limit times a command can be used per map


(NovaPrime) #1

Is there a way (maybe in LUA or some other way) to limit the amount of times users can use a particular command each map?

I have a custom command that is being abused a bit, but I don’t want to get rid of it, instead make it only possible to use like 3-5 times per map.


(acQu) #2

Lua ? Yes.

How is your command used: “\customcmd” or is it sent along with the say command, like this say “!customcmd”. You can also have some variations, for example you can limit the command e.g. to be used only after like X seconds after the last command.


(Micha) #3

Lua should be possible. You should put more information about the command.


(NovaPrime) #4

the command is a custom command that revives the player. its hard coded in the game. Yes, it is a say command i.e. !revive.

So I wanted to limit the player from using the command X amount of times. But, limiting the time it can be used would be just as good, however unless it can be limited several minutes it would be useless. A command like !revive is not being spammed in that way. What I mean by spammed is that they can revive after each death, which I do not want. If I can limit to like 3 minutes between command…that might resolve it. Otherwise, I need a way to limit the player X amount of times per map.


(zbzero) #5

disable this sh!t command, OMG!!


(Mateos) #6

He’s asking how to limit its usage, not if it is sh!t or not, even if I agree with you ^^’

Medics may be only fragging then, if players can revive themselves? xD


(ETJump-Zero) #7

Just add a lastReviveTime variable for each client and check that it’s been atleast x seconds since last revive.


(NovaPrime) #8

Can you be a little more specific please? Where do I update what you are talking about? That a cvar option?


(stealth6) #9

I think you need to be a little more specific before we can. Are you coding a mod? Are you using a current mod? Which mod? Does this mod even support lua?

I don’t know any mods that have a cvar to limit the amount of times a command is used. Especially since it’s a !command. With lua I’m pretty sure that you could do this since there are admin mods that solely use lua and thus scan player text for !commands. Plus if you are running NoQuarter you can use lua to get a players level and check if he has permission to use the command.

Here you can find some information about lua scripting for ETpro
Here’s some information for NoQuarter - replace **** with the s-word
Here’s a topic about setting and getting a players level in Nitmod so I guess it’s possible there too.


(NovaPrime) #10

The mod is etpub nightly
No it is not a dedicated mod project (in case you start wondering)
The revive command was added by a friend, it simply mirrors the revive code, added to shrubbot

I think ET jump zero was assuming that I was trying to code this in, which I can, but I just need more details about his suggestion.


(ETJump-Zero) #11

[QUOTE=NovaPrime;408417]The mod is etpub nightly
No it is not a dedicated mod project (in case you start wondering)
The revive command was added by a friend, it simply mirrors the revive code, added to shrubbot

I think ET jump zero was assuming that I was trying to code this in, which I can, but I just need more details about his suggestion.[/QUOTE]You need to add a static variable (one for each client, in C -> static int lastReviveTime[64]) somewhere to keep track of clients last revive time and when client uses revive it checks if(currentTime - lastReviveTime < x milliseconds) and either blocks the commands or not. I’d expect LUA addon to have some sort of level.time function that returns the current server time in milliseconds.


(acQu) #12

You mean you can code it in in C, but still are not sure if Lua can do it ?

Well, here is how i would do it. First use this framework:

function et_ClientCommand( clientNum, command )

   if command ~= "say" then
      return 0
   end

   if et.trap_Argv(1) == "customcmd" then
      -- DO STUFF
   end
end

For retrieving leveltime in etpub use this:

local millisec = et.trap_Milliseconds()

Then proceed from there. I could have written the script already, but i was not sure if it would be wasted time. It is no biggie in Lua.

For using a buffer for every client i don’t know. I would probably allocate it dynamically, to save space and time.


(acQu) #13

You mean you can code it in C, but still are not sure if Lua can do it ?

Well, here is how i would do it. First use this framework:

function et_ClientCommand( clientNum, command )

   if command ~= "say" then
      return 0
   end

   if et.trap_Argv(1) == "customcmd" then
      -- DO STUFF
   end
end

For retrieving leveltime in etpub use this:

local millisec = et.trap_Milliseconds()

Then proceed from there. I could have written the script already, but i was/am not sure if it would be wasted time. It is no biggie in Lua.

For using a buffer for every client i don’t know. I would probably allocate it “just in time” and build the buffer sort of “dynamically”.


(ETJump-Zero) #14

[QUOTE=acQu;408429]You mean you can code it in C, but still are not sure if Lua can do it ?

Well, here is how i would do it. First use this framework:

function et_ClientCommand( clientNum, command )

   if command ~= "say" then
      return 0
   end

   if et.trap_Argv(1) == "customcmd" then
      -- DO STUFF
   end
end

For retrieving leveltime in etpub use this:

local millisec = et.trap_Milliseconds()

Then proceed from there. I could have written the script already, but i was/am not sure if it would be wasted time. It is no biggie in Lua.

For using a buffer for every client i don’t know. I would probably allocate it “just in time” and build the buffer sort of “dynamically”.[/QUOTE]
Why wouldn’t it be possible in LUA, all you need is to be able to create a few variables and get the level.time with et.trap_Milliseconds(). Also using a dynamic buffer would be plain stupid considering it’s just 64 integers. 64x8 bits of memory is nothing(if ET uses 128 MBs it’s 2/390625th of it, lol), and with dynamic buffer you’d have to allocate memory every time you add a new user. You’d also have to search for the correct user in the list instead of just indexing it in constant time.

Example in C (should be pretty straight forward to do this in LUA aswell.)

static int lastReviveTime[MAX_CLIENTS];

if(lastReviveTime[clientNum] - level.time < 30000) {
    return;
}

revive(target);
lastReviveTime[clientNum] = level.time;
        
     

(acQu) #15

[QUOTE=ETJump-Zero;408474]Why wouldn’t it be possible in LUA, all you need is to be able to create a few variables and get the level.time with et.trap_Milliseconds(). Also using a dynamic buffer would be plain stupid considering it’s just 64 integers. 64x8 bits of memory is nothing(if ET uses 128 MBs it’s 2/390625th of it, lol), and with dynamic buffer you’d have to allocate memory every time you add a new user. You’d also have to search for the correct user in the list instead of just indexing it in constant time.

Example in C (should be pretty straight forward to do this in LUA aswell.)

static int lastReviveTime[MAX_CLIENTS];

if(lastReviveTime[clientNum] - level.time < 30000) {
    return;
}

revive(target);
lastReviveTime[clientNum] = level.time;
        
     

[/QUOTE]

I didn’t say it was not possible in Lua. If you scroll up to 2nd post i say it is possible. I also say in last post how i would do it. So i do not know how you can misunderstand that.

@dynamic thingy: i would have done it an extreme lazy way (very ineffective you are right). But i would spare myself e.g. clientdisconnect stuff lol. But you are absolutely right if you would want to do it fast, memory is not really a concern. Again, that was just born out of my lazyness :slight_smile:

So yes, it is possible in Lua. Just ask if you want to have that script in Lua and maybe someone takes the time to write it :slight_smile:


(ETJump-Zero) #16

[QUOTE=acQu;408477]I didn’t say it was not possible in Lua. If you scroll up to 2nd post i say it is possible. I also say in last post how i would do it. So i do not know how you can misunderstand that.

@dynamic thingy: i would have done it an extreme lazy way (very ineffective you are right). But i would spare myself e.g. clientdisconnect stuff lol. But you are absolutely right if you would want to do it fast, memory is not really a concern. Again, that was just born out of my lazyness :slight_smile:

So yes, it is possible in Lua. Just ask if you want to have that script in Lua and maybe someone takes the time to write it :)[/QUOTE]I wouldn’t worry about client connects or disconnects considering they’d only have to wait a maximum of x seconds if a new client connected the very second another disconnects :] I wasn’t sure who you were talking to, also I guess the part I missed was the ?. I thought you said “(I’m) still not sure if LUA can do it”

Anyway, in this time I guess we could’ve written it already, heh.


(Micha) #17

revive_cmd = “!revive”

function et_ClientCommand(client, command)
local arg0 = string.lower(et.trap_Argv(0))
local argv1 = string.lower(et.trap_Argv(1))
if arg0 == “m” or arg0 == “pm” or arg0 == “msg” or arg0 == “say” or arg0 == “say_team” or arg0 == “say_buddy” or arg0 == “say_teamnl” then
if string.find(argv1, “^” … revive_cmd … “”) then
“This will check for !revive and you can do something now. You could put a counter for each player and add a blocker”
end
end
end


(NovaPrime) #18

On second thought. I think adding a delay to the revive action would solve all my problems. How can I add a 10 second delay to the revive in C?

code below…

qboolean ReviveEntity(gentity_t *ent, gentity_t *traceEnt, qboolean resuscitation);
qboolean G_shrubbot_revive(gentity_t *ent, int skiparg)
{
	int pids[MAX_CLIENTS];
	char name[MAX_NAME_LENGTH], err[MAX_STRING_CHARS];
	char *reason;
	gentity_t *vic;

	if(Q_SayArgc() < 2+skiparg) 
	{
		SP("^drevive usage: ^2!revive ^9[name|slot#] [reason]^7
");
		return qfalse;
	}

	Q_SayArgv(1+skiparg, name, sizeof(name));
	reason = Q_SayConcatArgs(2+skiparg);

	if(ClientNumbersFromString(name, pids) != 1) 
	{
		G_MatchOnePlayer(pids, err, sizeof(err));
		SP(va("revive: %s
", err));
		return qfalse;
	}
	vic = &g_entities[pids[0]];

	if(!(vic->client->sess.sessionTeam == TEAM_AXIS || vic->client->sess.sessionTeam == TEAM_ALLIES)) 
	{
		SP("^drevive: ^9player must be on a team^7
");
		return qfalse;
	}

	if(vic->health > 0 || vic->client->ps.pm_flags & PMF_LIMBO) {
		SP(va("^drevive: ^7%s ^9is not dead!^7
", vic->client->pers.netname));
		return qfalse;
	}

	ReviveEntity(ent? ent : NULL, vic, qfalse);
	AP(va("chat \"^drevive: ^*%s ^9was revived^7\"", vic->client->pers.netname));

	
	CPx(pids[0], va("cp \"%s ^9revived you^7%s%s\"", 
			(ent?ent->client->pers.netname:"^3SERVER CONSOLE"),
			(*reason) ? "^9 because:
" : "",
			(*reason) ? reason : ""));

	return qtrue;
}
 
void Weapon_Medic_Ext(gentity_t *ent, vec3_t viewpos, vec3_t tosspos, vec3_t velocity);
qboolean G_shrubbot_medpack(gentity_t *ent, int skiparg)
{
	vec3_t	launchspot;
	vec3_t	launchvel;
	int pids[MAX_CLIENTS];
	char name[MAX_NAME_LENGTH], err[MAX_STRING_CHARS];
	char *reason;
	gentity_t *vic;

	if(Q_SayArgc() < 2+skiparg) 
	{
		SP("^dmedpack usage: ^2!medpack ^9[name|slot#] [reason]^7
");
		return qfalse;
	}

	Q_SayArgv(1+skiparg, name, sizeof(name));
	reason = Q_SayConcatArgs(2+skiparg);

	if(ClientNumbersFromString(name, pids) != 1) 
	{
		G_MatchOnePlayer(pids, err, sizeof(err));
		SP(va("medpack: %s
", err));
		return qfalse;
	}
	vic = &g_entities[pids[0]];

	if(!(vic->client->sess.sessionTeam == TEAM_AXIS || vic->client->sess.sessionTeam == TEAM_ALLIES)) 
	{
		SP("^dmedpack: ^9player must be on a team^7
");
		return qfalse;
	}

	if(vic->health < 0 && !(vic->client->ps.pm_flags & PMF_LIMBO)) {
		SP(va("^dmedpack: ^7%s ^9need to be alive!^7
", vic->client->pers.netname));
		return qfalse;
	}


	if ( !ent )
		return qfalse;

	launchvel[0] = crandom();
	launchvel[1] = crandom();
	launchvel[2] = 0;
	VectorScale(launchvel, 100, launchvel);
	launchvel[2] = g_packDistance.integer;
//	VectorCopy(ent->r.currentOrigin, launchspot);		
//	Weapon_Medic_Ext(ent, launchspot, launchspot, launchvel);
	VectorCopy(vic->r.currentOrigin, launchspot);		
	Weapon_Medic_Ext(vic, launchspot, launchspot, launchvel);
	AP(va("chat \"", vic->client->pers.netname));

	
	CPx(pids[0], va("cp \"%s ^9has give you a medpack^7%s%s\"", 
			(ent?ent->client->pers.netname:"^3SERVER CONSOLE"),
			(*reason) ? "^9 because:
" : "",
			(*reason) ? reason : ""));
	
	return qtrue;
} 

(ETJump-Zero) #19

[QUOTE=NovaPrime;409156]On second thought. I think adding a delay to the revive action would solve all my problems. How can I add a 10 second delay to the revive in C?

code below…

qboolean ReviveEntity(gentity_t *ent, gentity_t *traceEnt, qboolean resuscitation);
qboolean G_shrubbot_revive(gentity_t *ent, int skiparg)
{
	int pids[MAX_CLIENTS];
	char name[MAX_NAME_LENGTH], err[MAX_STRING_CHARS];
	char *reason;
	gentity_t *vic;

	if(Q_SayArgc() < 2+skiparg) 
	{
		SP("^drevive usage: ^2!revive ^9[name|slot#] [reason]^7
");
		return qfalse;
	}

	Q_SayArgv(1+skiparg, name, sizeof(name));
	reason = Q_SayConcatArgs(2+skiparg);

	if(ClientNumbersFromString(name, pids) != 1) 
	{
		G_MatchOnePlayer(pids, err, sizeof(err));
		SP(va("revive: %s
", err));
		return qfalse;
	}
	vic = &g_entities[pids[0]];

	if(!(vic->client->sess.sessionTeam == TEAM_AXIS || vic->client->sess.sessionTeam == TEAM_ALLIES)) 
	{
		SP("^drevive: ^9player must be on a team^7
");
		return qfalse;
	}

	if(vic->health > 0 || vic->client->ps.pm_flags & PMF_LIMBO) {
		SP(va("^drevive: ^7%s ^9is not dead!^7
", vic->client->pers.netname));
		return qfalse;
	}

	ReviveEntity(ent? ent : NULL, vic, qfalse);
	AP(va("chat \"^drevive: ^*%s ^9was revived^7\"", vic->client->pers.netname));

	
	CPx(pids[0], va("cp \"%s ^9revived you^7%s%s\"", 
			(ent?ent->client->pers.netname:"^3SERVER CONSOLE"),
			(*reason) ? "^9 because:
" : "",
			(*reason) ? reason : ""));

	return qtrue;
}
 
void Weapon_Medic_Ext(gentity_t *ent, vec3_t viewpos, vec3_t tosspos, vec3_t velocity);
qboolean G_shrubbot_medpack(gentity_t *ent, int skiparg)
{
	vec3_t	launchspot;
	vec3_t	launchvel;
	int pids[MAX_CLIENTS];
	char name[MAX_NAME_LENGTH], err[MAX_STRING_CHARS];
	char *reason;
	gentity_t *vic;

	if(Q_SayArgc() < 2+skiparg) 
	{
		SP("^dmedpack usage: ^2!medpack ^9[name|slot#] [reason]^7
");
		return qfalse;
	}

	Q_SayArgv(1+skiparg, name, sizeof(name));
	reason = Q_SayConcatArgs(2+skiparg);

	if(ClientNumbersFromString(name, pids) != 1) 
	{
		G_MatchOnePlayer(pids, err, sizeof(err));
		SP(va("medpack: %s
", err));
		return qfalse;
	}
	vic = &g_entities[pids[0]];

	if(!(vic->client->sess.sessionTeam == TEAM_AXIS || vic->client->sess.sessionTeam == TEAM_ALLIES)) 
	{
		SP("^dmedpack: ^9player must be on a team^7
");
		return qfalse;
	}

	if(vic->health < 0 && !(vic->client->ps.pm_flags & PMF_LIMBO)) {
		SP(va("^dmedpack: ^7%s ^9need to be alive!^7
", vic->client->pers.netname));
		return qfalse;
	}


	if ( !ent )
		return qfalse;

	launchvel[0] = crandom();
	launchvel[1] = crandom();
	launchvel[2] = 0;
	VectorScale(launchvel, 100, launchvel);
	launchvel[2] = g_packDistance.integer;
//	VectorCopy(ent->r.currentOrigin, launchspot);		
//	Weapon_Medic_Ext(ent, launchspot, launchspot, launchvel);
	VectorCopy(vic->r.currentOrigin, launchspot);		
	Weapon_Medic_Ext(vic, launchspot, launchspot, launchvel);
	AP(va("chat \"", vic->client->pers.netname));

	
	CPx(pids[0], va("cp \"%s ^9has give you a medpack^7%s%s\"", 
			(ent?ent->client->pers.netname:"^3SERVER CONSOLE"),
			(*reason) ? "^9 because:
" : "",
			(*reason) ? reason : ""));
	
	return qtrue;
} 

[/QUOTE]
Already posted code in C to do that.


(NovaPrime) #20

Thanks Jump, I will get this added and try it. but I have a new problem that I got to get fixed first I guess.

The linux qagame binary does not want to load, not sure why. Says “Sys_LoadDll(qagame) failed dlopen() completely!”. I am running a CentOS 4.x server with glibc 2.3.4. Compiled on DebianEtch 4.0. No errors when compiling. The windows binary works like a charm. I did not have these linux binary problems until my friend added all the latest etpub and a few custom editions to my source. Possibly a tool/package I need to install on my compiler machine?

I will post a more detailed log of the server crash a bit later today.