/* * Copyright(c) 1997-2001 Id Software, Inc. * Copyright(c) 2002 The Quakeforge Project. * Copyright(c) 2006 Quetoo. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or(at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "g_local.h" #include "m_player.h" void SelectNextItem(edict_t *ent, int itflags){ gclient_t *cl; int i, index; gitem_t *it; cl = ent->client; if(cl->chase_target){ ChaseNext(ent); return; } // scan for the next valid one for(i = 1; i <= MAX_ITEMS; i++){ index =(cl->pers.selected_item + i) % MAX_ITEMS; if(!cl->pers.inventory[index]) continue; it = &itemlist[index]; if(!it->use) continue; if(!(it->flags & itflags)) continue; cl->pers.selected_item = index; return; } cl->pers.selected_item = -1; } void SelectPrevItem(edict_t *ent, int itflags){ gclient_t *cl; int i, index; gitem_t *it; cl = ent->client; if(cl->chase_target){ ChasePrev(ent); return; } // scan for the next valid one for(i = 1; i <= MAX_ITEMS; i++){ index =(cl->pers.selected_item + MAX_ITEMS - i) % MAX_ITEMS; if(!cl->pers.inventory[index]) continue; it = &itemlist[index]; if(!it->use) continue; if(!(it->flags & itflags)) continue; cl->pers.selected_item = index; return; } cl->pers.selected_item = -1; } void ValidateSelectedItem(edict_t *ent){ gclient_t *cl; cl = ent->client; if(cl->pers.inventory[cl->pers.selected_item]) return; // valid SelectNextItem(ent, -1); } /* Cmd_Give_f Give items to a client */ void Cmd_Give_f(edict_t *ent){ char *name; gitem_t *it; int index; int i; qboolean give_all; edict_t *it_ent; if(!sv_cheats->value){ gi.cprintf(ent, PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n"); return; } name = gi.args(); if(Q_stricmp(name, "all") == 0) give_all = true; else give_all = false; if(give_all || Q_stricmp(gi.argv(1), "health") == 0){ if(gi.argc() == 3) ent->health = atoi(gi.argv(2)); else ent->health = ent->max_health; if(!give_all) return; } if(give_all || Q_stricmp(name, "weapons") == 0){ for(i = 0; i < game.num_items; i++){ it = itemlist + i; if(!it->pickup) continue; if(!(it->flags & IT_WEAPON)) continue; ent->client->pers.inventory[i] += 1; } if(!give_all) return; } if(give_all || Q_stricmp(name, "ammo") == 0){ for(i = 0; i < game.num_items; i++){ it = itemlist + i; if(!it->pickup) continue; if(!(it->flags & IT_AMMO)) continue; Add_Ammo(ent, it, 1000); } if(!give_all) return; } if(give_all || Q_stricmp(name, "armor") == 0){ gitem_armor_t *info; it = FindItem("Jacket Armor"); ent->client->pers.inventory[ITEM_INDEX(it)] = 0; it = FindItem("Combat Armor"); ent->client->pers.inventory[ITEM_INDEX(it)] = 0; it = FindItem("Body Armor"); info =(gitem_armor_t *)it->info; ent->client->pers.inventory[ITEM_INDEX(it)] = info->max_count; if(!give_all) return; } if(give_all || Q_stricmp(name, "Power Shield") == 0){ it = FindItem("Power Shield"); it_ent = G_Spawn(); it_ent->classname = it->classname; SpawnItem(it_ent, it); Touch_Item(it_ent, ent, NULL, NULL); if(it_ent->inuse) G_FreeEdict(it_ent); if(!give_all) return; } if(give_all){ for(i = 0; i < game.num_items; i++){ it = itemlist + i; if(!it->pickup) continue; if(it->flags &(IT_ARMOR | IT_WEAPON | IT_AMMO)) continue; ent->client->pers.inventory[i] = 1; } return; } it = FindItem(name); if(!it){ name = gi.argv(1); it = FindItem(name); if(!it){ gi.cprintf(ent, PRINT_HIGH, "unknown item\n"); return; } } if(!it->pickup){ gi.cprintf(ent, PRINT_HIGH, "non-pickup item\n"); return; } index = ITEM_INDEX(it); if(it->flags & IT_AMMO){ if(gi.argc() == 3) ent->client->pers.inventory[index] = atoi(gi.argv(2)); else ent->client->pers.inventory[index] += it->quantity; } else { it_ent = G_Spawn(); it_ent->classname = it->classname; SpawnItem(it_ent, it); Touch_Item(it_ent, ent, NULL, NULL); if(it_ent->inuse) G_FreeEdict(it_ent); } } /* Cmd_God_f Sets client to godmode argv(0) god */ void Cmd_God_f(edict_t *ent){ char *msg; if(!sv_cheats->value){ gi.cprintf(ent, PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n"); return; } ent->flags ^= FL_GODMODE; if(!(ent->flags & FL_GODMODE)) msg = "godmode OFF\n"; else msg = "godmode ON\n"; gi.cprintf(ent, PRINT_HIGH, msg); } /* Cmd_Notarget_f Sets client to notarget argv(0) notarget */ void Cmd_Notarget_f(edict_t *ent){ char *msg; if(!sv_cheats->value){ gi.cprintf(ent, PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n"); return; } ent->flags ^= FL_NOTARGET; if(!(ent->flags & FL_NOTARGET)) msg = "notarget OFF\n"; else msg = "notarget ON\n"; gi.cprintf(ent, PRINT_HIGH, msg); } /* Cmd_Noclip_f argv(0) noclip */ void Cmd_Noclip_f(edict_t *ent){ char *msg; if(!sv_cheats->value){ gi.cprintf(ent, PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n"); return; } if(ent->movetype == MOVETYPE_NOCLIP){ ent->movetype = MOVETYPE_WALK; msg = "noclip OFF\n"; } else { ent->movetype = MOVETYPE_NOCLIP; msg = "noclip ON\n"; } gi.cprintf(ent, PRINT_HIGH, msg); } /* Cmd_Use_f Use an inventory item */ void Cmd_Use_f(edict_t *ent){ int index; gitem_t *it; char *s; s = gi.args(); it = FindItem(s); if(!it){ gi.cprintf(ent, PRINT_HIGH, "unknown item: %s\n", s); return; } if(!it->use){ gi.cprintf(ent, PRINT_HIGH, "Item is not usable.\n"); return; } index = ITEM_INDEX(it); if(!ent->client->pers.inventory[index]){ gi.cprintf(ent, PRINT_HIGH, "Out of item: %s\n", s); return; } it->use(ent, it); } /* Cmd_Drop_f Drop an inventory item */ void Cmd_Drop_f(edict_t *ent){ int index; gitem_t *it; char *s; s = gi.args(); it = FindItem(s); if(!it){ gi.cprintf(ent, PRINT_HIGH, "unknown item: %s\n", s); return; } if(!it->drop){ gi.cprintf(ent, PRINT_HIGH, "Item is not dropable.\n"); return; } index = ITEM_INDEX(it); if(!ent->client->pers.inventory[index]){ gi.cprintf(ent, PRINT_HIGH, "Out of item: %s\n", s); return; } it->drop(ent, it); } /* Cmd_Inven_f */ void Cmd_Inven_f(edict_t *ent){ int i; gclient_t *cl; cl = ent->client; cl->showscores = false; if(cl->showinventory){ cl->showinventory = false; return; } cl->showinventory = true; gi.WriteByte(svc_inventory); for(i = 0; i < MAX_ITEMS; i++){ gi.WriteShort(cl->pers.inventory[i]); } gi.unicast(ent, true); } /* Cmd_InvUse_f */ void Cmd_InvUse_f(edict_t *ent){ gitem_t *it; ValidateSelectedItem(ent); if(ent->client->pers.selected_item == -1){ gi.cprintf(ent, PRINT_HIGH, "No item to use.\n"); return; } it = &itemlist[ent->client->pers.selected_item]; if(!it->use){ gi.cprintf(ent, PRINT_HIGH, "Item is not usable.\n"); return; } it->use(ent, it); } /* Cmd_WeapPrev_f */ void Cmd_WeapPrev_f(edict_t *ent){ gclient_t *cl; int i, index; gitem_t *it; int selected_weapon; cl = ent->client; if(!cl->pers.weapon) return; selected_weapon = ITEM_INDEX(cl->pers.weapon); // scan for the next valid one for(i = 1; i <= MAX_ITEMS; i++){ index =(selected_weapon + i) % MAX_ITEMS; if(!cl->pers.inventory[index]) continue; it = &itemlist[index]; if(!it->use) continue; if(!(it->flags & IT_WEAPON)) continue; it->use(ent, it); if(cl->pers.weapon == it) return; // successful } } /* Cmd_WeapNext_f */ void Cmd_WeapNext_f(edict_t *ent){ gclient_t *cl; int i, index; gitem_t *it; int selected_weapon; cl = ent->client; if(!cl->pers.weapon) return; selected_weapon = ITEM_INDEX(cl->pers.weapon); // scan for the next valid one for(i = 1; i <= MAX_ITEMS; i++){ index =(selected_weapon + MAX_ITEMS - i) % MAX_ITEMS; if(!cl->pers.inventory[index]) continue; it = &itemlist[index]; if(!it->use) continue; if(!(it->flags & IT_WEAPON)) continue; it->use(ent, it); if(cl->pers.weapon == it) return; // successful } } /* Cmd_WeapLast_f */ void Cmd_WeapLast_f(edict_t *ent){ gclient_t *cl; int index; gitem_t *it; cl = ent->client; if(!cl->pers.weapon || !cl->pers.lastweapon) return; index = ITEM_INDEX(cl->pers.lastweapon); if(!cl->pers.inventory[index]) return; it = &itemlist[index]; if(!it->use) return; if(!(it->flags & IT_WEAPON)) return; it->use(ent, it); } /* Cmd_InvDrop_f */ void Cmd_InvDrop_f(edict_t *ent){ gitem_t *it; ValidateSelectedItem(ent); if(ent->client->pers.selected_item == -1){ gi.cprintf(ent, PRINT_HIGH, "No item to drop.\n"); return; } it = &itemlist[ent->client->pers.selected_item]; if(!it->drop){ gi.cprintf(ent, PRINT_HIGH, "Item is not dropable.\n"); return; } it->drop(ent, it); } /* Cmd_Kill_f */ void Cmd_Kill_f(edict_t *ent){ if((level.time - ent->client->respawn_time) < 5) return; ent->flags &= ~FL_GODMODE; ent->health = 0; meansOfDeath = MOD_SUICIDE; player_die(ent, ent, ent, 100000, vec3_origin); } /* Cmd_PutAway_f */ void Cmd_PutAway_f(edict_t *ent){ ent->client->showscores = false; ent->client->showinventory = false; } int PlayerSort(void const *a, void const *b){ int anum, bnum; anum = *(int *)a; bnum = *(int *)b; anum = game.clients[anum].ps.stats[STAT_FRAGS]; bnum = game.clients[bnum].ps.stats[STAT_FRAGS]; if(anum < bnum) return -1; if(anum > bnum) return 1; return 0; } /* Cmd_Players_f */ void Cmd_Players_f(edict_t *ent){ int i; int count; char small[64]; char large[1280]; int index[256]; count = 0; for(i = 0; i < maxclients->value; i++) if(g_edicts[i + 1].inuse){ index[count] = i; count++; } // sort by frags qsort(index, count, sizeof(index[0]), PlayerSort); // print information large[0] = 0; for(i = 0; i < count; i++){ Com_sprintf(small, sizeof(small), "%3i %s\n", game.clients[index[i]].ps.stats[STAT_FRAGS], game.clients[index[i]].pers.netname); if(strlen(small) + strlen(large) > sizeof(large) - 100){ // can't print all of them in one packet strcat(large, "...\n"); break; } strcat(large, small); } gi.cprintf(ent, PRINT_HIGH, "%s\n%i players\n", large, count); } /* Cmd_Wave_f */ void Cmd_Wave_f(edict_t *ent){ int i; i = atoi(gi.argv(1)); // can't wave when ducked if(ent->client->ps.pmove.pm_flags & PMF_DUCKED) return; if(ent->client->anim_priority > ANIM_WAVE) return; ent->client->anim_priority = ANIM_WAVE; switch(i){ case 0: gi.cprintf(ent, PRINT_HIGH, "flipoff\n"); ent->s.frame = FRAME_flip01 - 1; ent->client->anim_end = FRAME_flip12; break; case 1: gi.cprintf(ent, PRINT_HIGH, "salute\n"); ent->s.frame = FRAME_salute01 - 1; ent->client->anim_end = FRAME_salute11; break; case 2: gi.cprintf(ent, PRINT_HIGH, "taunt\n"); ent->s.frame = FRAME_taunt01 - 1; ent->client->anim_end = FRAME_taunt17; break; case 3: gi.cprintf(ent, PRINT_HIGH, "wave\n"); ent->s.frame = FRAME_wave01 - 1; ent->client->anim_end = FRAME_wave11; break; case 4: default: gi.cprintf(ent, PRINT_HIGH, "point\n"); ent->s.frame = FRAME_point01 - 1; ent->client->anim_end = FRAME_point12; break; } } /* Cmd_Say_f */ void Cmd_Say_f(edict_t *ent, qboolean team, qboolean arg0){ int i, j; edict_t *other; char *p, msg[150], text[2048]; gclient_t *cl; if(gi.argc() < 2 && !arg0) return; if(!teams->value) //say_team is same as say without teams team = false; if(team) Com_sprintf(text, sizeof(text), "(%s): ", ent->client->pers.netname); else Com_sprintf(text, sizeof(text), "%s: ", ent->client->pers.netname); memset(msg, 0, sizeof(msg)); if(arg0){ strcat(msg, gi.argv(0)); strcat(msg, " "); strcat(msg, gi.args()); } else { p = gi.args(); if(*p == '"'){ p++; p[strlen(p) - 1] = 0; } strcat(msg, p); } // don't let text be too long for malicious reasons if(strlen(msg) > 149) msg[149] = 0; strcat(text, msg); strcat(text, "\n"); if(flood_msgs->value && !team){ // flood protection, does not pertain to teams cl = ent->client; if(level.time < cl->flood_locktill){ gi.cprintf(ent, PRINT_HIGH, "You can't talk for %d more seconds\n", (int)(cl->flood_locktill - level.time)); return; } i = cl->flood_whenhead - flood_msgs->value + 1; if(i < 0) i =(sizeof(cl->flood_when) / sizeof(cl->flood_when[0])) + i; if(cl->flood_when[i] && level.time - cl->flood_when[i] < flood_persecond->value){ cl->flood_locktill = level.time + flood_waitdelay->value; gi.cprintf(ent, PRINT_CHAT, "Flood protection: You can't talk for %d seconds.\n", (int)flood_waitdelay->value); return; } cl->flood_whenhead = (cl->flood_whenhead + 1) % (sizeof(cl->flood_when) / sizeof(cl->flood_when[0])); cl->flood_when[cl->flood_whenhead] = level.time; } if(dedicated->value) gi.cprintf(NULL, PRINT_CHAT, "%s", text); for(j = 1; j <= maxclients->value; j++){ other = &g_edicts[j]; if(!other->inuse) continue; if(!other->client) continue; if(team){ if(!OnSameTeam(ent, other)) continue; } gi.cprintf(other, PRINT_CHAT, "%s", text); } if(chatlog != NULL){ //write chatlog fprintf(chatlog, text); fflush(chatlog); } #ifdef HAVE_MYSQL if(mysql != NULL){ //insert to db mysql_real_escape_string(mysql, text, msg, sizeof(msg)); snprintf(sql, sizeof(sql) - 1, "insert into chat values('%s', '%s')", ent->client->pers.netname, text); sql[sizeof(sql) - 1] = 0; mysql_query(mysql, sql); } #endif } void Cmd_PlayerList_f(edict_t *ent){ int i; char st[80]; char text[1400]; edict_t *e2; // connect time, ping, score, name *text = 0; for(i = 0, e2 = g_edicts + 1; i < maxclients->value; i++, e2++){ if(!e2->inuse) continue; Com_sprintf(st, sizeof(st), "%02d:%02d %4d %3d %s%s\n", (level.framenum - e2->client->resp.enterframe) / 600, ((level.framenum - e2->client->resp.enterframe) % 600) / 10, e2->client->ping, e2->client->resp.score, e2->client->pers.netname, e2->client->resp.spectator ? "(spectator)" : ""); if(strlen(text) + strlen(st) > sizeof(text) - 50){ sprintf(text + strlen(text), "And more...\n"); gi.cprintf(ent, PRINT_HIGH, "%s", text); return; } strcat(text, st); } gi.cprintf(ent, PRINT_HIGH, "%s", text); } qboolean vote_active = false; float vote_time = 0; char *vote_cmds[] = { "map", "fraglimit", "timelimit", "gameplay", "hook", "kick", "reset", "teams", NULL }; char vote_cmd[64]; int votes[3]; /* Vote_Help Inspects the vote command and issues help if applicable. Returns true if the command received help and may therefore be ignored, false otherwise. */ qboolean Vote_Help(edict_t *ent){ int i, j, len; char msg[1024]; memset(msg, 0, sizeof(msg)); i = 0; if(gi.argc() == 1){ //no command specified, list them strcat(msg, "\nAvailable vote commands:\n\n"); while(vote_cmds[i]){ strcat(msg, " "); strcat(msg, vote_cmds[i]); strcat(msg, "\n"); i++; } gi.cprintf(ent, PRINT_HIGH, msg); return true; } i = 0; while(vote_cmds[i]){ //verify that command is supported if(!Q_stricmp(gi.argv(1), vote_cmds[i])) break; i++; } if(!vote_cmds[i]){ //inform client if it is not gi.cprintf(ent, PRINT_HIGH, "Voting on \"%s\" is not supported\n", gi.argv(1)); return true; } if(!Q_stricmp(gi.argv(1), "reset")) return false; //takes no args, this is okay //command-specific help for some commands if(gi.argc() == 2 && !Q_stricmp(gi.argv(1), "map")){ //list available maps if(!maplist.count){ //no maps in maplist gi.cprintf(ent, PRINT_HIGH, "Map voting is not available\n"); return true; } strcat(msg, "\nAvailable maps:\n\n"); j = 0; for(i = 0; i < maplist.count; i++){ len = strlen(maplist.maps[i]) + 3; if(j + len > sizeof(msg)) //don't overrun msg break; strcat(msg, " "); strcat(msg, maplist.maps[i]); j += len; } gi.cprintf(ent, PRINT_HIGH, msg); return true; } if(gi.argc() == 2 && !Q_stricmp(gi.argv(1), "gameplay")){ //list gameplay modes gi.cprintf(ent, PRINT_HIGH, "\nAvailable gameplay modes:\n\n" " 0 DEATHMATCH\n 1 INSTAGIB\n 2 ROCKET ARENA\n"); return true; } if(gi.argc() == 2){ //general catch for invalid commands gi.cprintf(ent, PRINT_HIGH, "Usage: vote \n"); return true; } return false; } /* Cmd_Vote_f */ void Cmd_Vote_f(edict_t *ent){ char *c, vote[64]; int i; if(!sv_allow_vote->value){ gi.cprintf(ent, PRINT_HIGH, "Voting is not allowed"); return; } strncpy(vote, gi.args(), sizeof(vote) - 1); vote[sizeof(vote) - 1] = 0; if(vote_active){ //check for vote from client if(ent->client->pers.vote){ gi.cprintf(ent, PRINT_HIGH, "You've already voted\n"); return; } if(Q_stricmp(vote, "yes") == 0) ent->client->pers.vote = VOTE_YES; else if(Q_stricmp(vote, "no") == 0) ent->client->pers.vote = VOTE_NO; else { //only yes and no are valid during a vote gi.cprintf(ent, PRINT_HIGH, "A vote \"%s\" is already in progress\n", vote_cmd); return; } votes[ent->client->pers.vote]++; gi.bprintf(PRINT_HIGH, "Voting results \"%s\":\n %d Yes %d No\n", vote_cmd, votes[VOTE_YES], votes[VOTE_NO]); return; } if(Vote_Help(ent)) //vote command got help, ignore it return; if(!Q_stricmp(gi.argv(1), "map")){ //ensure map is in maplist for(i = 0; i < maplist.count; i++){ c = strtok(maplist.maps[i], " "); if(!Q_stricmp(gi.argv(2), c)) break; //found it } if(i == maplist.count){ //inform client if it is not gi.cprintf(ent, PRINT_HIGH, "Map \"%s\" is not available\n", gi.argv(2)); return; } } strncpy(vote_cmd, vote, sizeof(vote_cmd) - 1); vote_cmd[sizeof(vote_cmd) - 1] = 0; vote_time = level.time; vote_active = true; ent->client->pers.vote = VOTE_YES; //client has implicity voted votes[VOTE_YES] = 1; gi.configstring(CS_VOTE, vote_cmd); //send to layout gi.bprintf(PRINT_HIGH, "%s has called a vote:\n" " %s\n" "To vote, type \"vote yes\" or \"vote no\" at the console\n", ent->client->pers.netname, vote_cmd); } /* AddClientToTeam */ void AddClientToTeam(edict_t *ent, team_t *team){ strcpy(ent->client->pers.skin, team->skin); ent->client->pers.team = team; ent->client->pers.spectator = false; ent->client->resp.score = 0; } /* Cmd_Team_f */ void Cmd_Team_f(edict_t *ent){ if(gi.argc() != 2){ gi.cprintf(ent, PRINT_HIGH, "Usage: team <%s|%s|Spectators>\n", good.name, evil.name); return; } if(!Q_stricmp(good.name, gi.argv(1))) //resolve team AddClientToTeam(ent, &good); else if(!Q_stricmp(evil.name, gi.argv(1))) AddClientToTeam(ent, &evil); else if(!Q_stricmp("Spectators", gi.argv(1))) ent->client->pers.team = NULL; else { gi.cprintf(ent, PRINT_HIGH, "Team \"%s\" does not exist\n", gi.argv(1)); return; } PutClientInServer(ent); //respawn as team member or spectator if(ent->client->pers.team) //broadcast what happened gi.bprintf(PRINT_HIGH, "%s has joined %s\n", ent->client->pers.netname, ent->client->pers.team->name); else gi.bprintf(PRINT_HIGH, "%s likes to watch\n", ent->client->pers.netname); } /* Cmd_Teamname_f */ void Cmd_Teamname_f(edict_t *ent){ int cs; if(gi.argc() != 2){ gi.cprintf(ent, PRINT_HIGH, "Usage: teamname \n"); return; } if(!ent->client->pers.team){ gi.cprintf(ent, PRINT_HIGH, "You're not on a team\n"); return; } if(level.time - ent->client->pers.team->nametime < TEAM_CHANGE_TIME) return; //prevent change spamming strncpy(ent->client->pers.team->name, gi.argv(1), 15); ent->client->pers.team->name[15] = 0; ent->client->pers.team->nametime = level.time; cs = ent->client->pers.team == &good ? CS_TEAMGOOD : CS_TEAMEVIL; gi.configstring(cs, ent->client->pers.team->name); } /* Cmd_Teamskin_f */ void Cmd_Teamskin_f(edict_t *ent){ int i; gclient_t *cl; if(gi.argc() != 2){ gi.cprintf(ent, PRINT_HIGH, "Usage: teamskin \n"); return; } if(!ent->client->pers.team){ gi.cprintf(ent, PRINT_HIGH, "You're not on a team\n"); return; } if(level.time - ent->client->pers.team->skintime < TEAM_CHANGE_TIME) return; //prevent change spamming strncpy(ent->client->pers.team->skin, gi.argv(1), 15); ent->client->pers.team->skin[15] = 0; ent->client->pers.team->skintime = level.time; for(i = 0; i < maxclients->value; i++){ //update skins cl = game.clients + i; if(!cl->pers.team || cl->pers.team != ent->client->pers.team) continue; strncpy(ent->client->pers.skin, ent->client->pers.team->skin, 16); ent->client->pers.skin[15] = 0; gi.configstring(CS_PLAYERSKINS + i, va("%s\\%s", cl->pers.netname, cl->pers.skin)); } } /* ClientCommand */ void ClientCommand(edict_t *ent){ char *cmd; if(!ent->client) return; // not fully in game yet cmd = gi.argv(0); if(Q_stricmp(cmd, "players") == 0){ Cmd_Players_f(ent); return; } if(Q_stricmp(cmd, "say") == 0){ Cmd_Say_f(ent, false, false); return; } if(Q_stricmp(cmd, "say_team") == 0){ Cmd_Say_f(ent, true, false); return; } if(Q_stricmp(cmd, "score") == 0){ Cmd_Score_f(ent); return; } if(Q_stricmp(cmd, "help") == 0){ Cmd_Score_f(ent); return; } if(Q_stricmp(cmd, "team") == 0){ Cmd_Team_f(ent); return; } if(Q_stricmp(cmd, "teamname") == 0){ Cmd_Teamname_f(ent); return; } if(Q_stricmp(cmd, "teamskin") == 0){ Cmd_Teamskin_f(ent); return; } if(level.intermissiontime) return; if(Q_stricmp(cmd, "use") == 0) Cmd_Use_f(ent); else if(Q_stricmp(cmd, "drop") == 0) Cmd_Drop_f(ent); else if(Q_stricmp(cmd, "give") == 0) Cmd_Give_f(ent); else if(Q_stricmp(cmd, "god") == 0) Cmd_God_f(ent); else if(Q_stricmp(cmd, "notarget") == 0) Cmd_Notarget_f(ent); else if(Q_stricmp(cmd, "noclip") == 0) Cmd_Noclip_f(ent); else if(Q_stricmp(cmd, "inven") == 0) Cmd_Inven_f(ent); else if(Q_stricmp(cmd, "invnext") == 0) SelectNextItem(ent, -1); else if(Q_stricmp(cmd, "invprev") == 0) SelectPrevItem(ent, -1); else if(Q_stricmp(cmd, "invnextw") == 0) SelectNextItem(ent, IT_WEAPON); else if(Q_stricmp(cmd, "invprevw") == 0) SelectPrevItem(ent, IT_WEAPON); else if(Q_stricmp(cmd, "invnextp") == 0) SelectNextItem(ent, IT_POWERUP); else if(Q_stricmp(cmd, "invprevp") == 0) SelectPrevItem(ent, IT_POWERUP); else if(Q_stricmp(cmd, "invuse") == 0) Cmd_InvUse_f(ent); else if(Q_stricmp(cmd, "invdrop") == 0) Cmd_InvDrop_f(ent); else if(Q_stricmp(cmd, "weapprev") == 0) Cmd_WeapPrev_f(ent); else if(Q_stricmp(cmd, "weapnext") == 0) Cmd_WeapNext_f(ent); else if(Q_stricmp(cmd, "weaplast") == 0) Cmd_WeapLast_f(ent); else if(Q_stricmp(cmd, "kill") == 0) Cmd_Kill_f(ent); else if(Q_stricmp(cmd, "putaway") == 0) Cmd_PutAway_f(ent); else if(Q_stricmp(cmd, "wave") == 0) Cmd_Wave_f(ent); else if(Q_stricmp(cmd, "playerlist") == 0) Cmd_PlayerList_f(ent); else if(Q_stricmp(cmd, "vote") == 0) Cmd_Vote_f(ent); else if(Q_stricmp(cmd, "hook") == 0) Cmd_HookFire_f(ent); else if(Q_stricmp(cmd, "unhook") == 0) Cmd_HookReset_f(ent); else // anything that doesn't match a command will be a chat Cmd_Say_f(ent, false, true); }