/* Copyright (C) 1997-2001 Id Software, Inc. 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 "g_gametypes.h" #include "g_callvotes.h" //================== //G_Teleport // //Teleports client to specified position //If client is not spectator teleporting is only done if position is free and teleport effects are drawn. //================== qboolean G_Teleport (edict_t *ent, vec3_t origin, vec3_t angles) { int i; edict_t *event; if( !ent->r.inuse || !ent->r.client ) return qfalse; if( ent->r.client->ps.pmove.pm_type != PM_SPECTATOR ) { trace_t tr; trap_Trace( &tr, origin, ent->r.mins, ent->r.maxs, origin, ent, MASK_PLAYERSOLID ); if( tr.fraction != 1.0f || tr.startsolid ) return qfalse; event = G_SpawnEvent( EV_PLAYER_TELEPORT_OUT, 0, ent->s.origin ); event->r.svflags = SVF_NOOLDORIGIN; event->s.ownerNum = ENTNUM( ent ); } VectorCopy( origin, ent->s.origin ); VectorCopy( origin, ent->s.old_origin ); G_AddEvent( ent, EV_TELEPORT, 0, qtrue ); VectorClear( ent->velocity ); ent->r.client->ps.pmove.pm_time = 1; ent->r.client->ps.pmove.pm_flags |= PMF_TIME_TELEPORT; if( ent->r.client->ps.pmove.pm_type != PM_SPECTATOR ) { event = G_SpawnEvent( EV_PLAYER_TELEPORT_IN, 0, ent->s.origin ); event->r.svflags = SVF_NOOLDORIGIN; event->s.ownerNum = ENTNUM( ent ); } // set angles VectorCopy( angles, ent->s.angles ); VectorCopy( angles, ent->r.client->ps.viewangles ); VectorCopy( angles, ent->r.client->v_angle ); // set the delta angle for( i = 0 ; i < 3 ; i++ ) ent->r.client->ps.pmove.delta_angles[i] = ANGLE2SHORT(ent->s.angles[i]) - ent->r.client->pers.cmd_angles[i]; return qtrue; } char *ClientTeam (edict_t *ent) { char *p; static char value[512]; value[0] = 0; if (!ent->r.client) return value; Q_strncpyz(value, Info_ValueForKey (ent->r.client->pers.userinfo, "skin"), sizeof(value)); p = strchr(value, '/'); if (!p) return value; return ++p; } qboolean OnSameTeam( edict_t *ent1, edict_t *ent2 ) { return ( ent1->s.team == ent2->s.team ); } void SelectNextItem( edict_t *ent, int itflags ) { gclient_t *cl; int tag, first; cl = ent->r.client; if( cl->chase.active ) { ChaseNext(ent); } if( cl->selected_item < 0 ) cl->selected_item = 0; tag = cl->selected_item; tag++; if( tag >= game.numItems || tag <= 0 ) tag = 1; first = tag; while( tag != first ) { if( game.items[tag] ) { if( (game.items[tag]->flags & ITFLAG_USABLE) && (game.items[tag]->type & itflags) && cl->inventory[tag] ) { cl->selected_item = tag; return; } } tag++; if( tag >= game.numItems ) tag = 1; } cl->selected_item = -1; } void SelectPrevItem( edict_t *ent, int itflags ) { gclient_t *cl; int tag, first; cl = ent->r.client; if( cl->chase.active ) { ChasePrev(ent); } tag = cl->selected_item; tag--; if( tag <= 0 || tag >= game.numItems ) tag = game.numItems - 1; first = tag; while( tag != first ) { if( game.items[tag] ) { if( (game.items[tag]->flags & ITFLAG_USABLE) && (game.items[tag]->type & itflags ) && cl->inventory[tag] ) { cl->selected_item = tag; return; } } tag--; if( tag <= 0 ) tag = game.numItems - 1; } cl->selected_item = -1; } void ValidateSelectedItem( edict_t *ent ) { gclient_t *cl; cl = ent->r.client; if( cl->selected_item >=0 ) if( cl->inventory[cl->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 i; qboolean give_all; if( !sv_cheats->integer ) { G_PrintMsg( ent, "Cheats are not enabled on this server.\n" ); return; } name = trap_Cmd_Args (); if( !Q_stricmp(name, "all") ) give_all = qtrue; else give_all = qfalse; if( give_all || !Q_stricmp(trap_Cmd_Argv(1), "health") ) { if( trap_Cmd_Argc() == 3 ) ent->health = atoi( trap_Cmd_Argv(2) ); else ent->health = ent->max_health; if( !give_all ) return; } if( give_all || !Q_stricmp(name, "weapons") ) { for( i = 0; i < game.numItems; i++ ) { it = game.items[i]; if( !it ) continue; if( !(it->flags & ITFLAG_PICKABLE) ) continue; if( !(it->type & IT_WEAPON) ) continue; ent->r.client->inventory[i] += 1; } if( !give_all ) return; } if( give_all || !Q_stricmp(name, "ammo") ) { for( i = 0; i < game.numItems; i++ ) { it = game.items[i]; if( !it ) continue; if( !(it->flags & ITFLAG_PICKABLE) ) continue; if( !(it->type & IT_AMMO) ) continue; Add_Ammo( ent, it, 1000, qtrue ); } if( !give_all ) return; } if( give_all || !Q_stricmp(name, "armor") ) { gitem_armor_t *info; info = (gitem_armor_t *)game.items[ARMOR_RA]->info; ent->r.client->armor = info->max_count; ent->r.client->armortag = ARMOR_RA; if( !give_all ) return; } if( give_all ) { for( i = 0; i < game.numItems; i++ ) { it = game.items[i]; if( !it ) continue; if( !(it->flags & ITFLAG_PICKABLE) ) continue; if( it->type & (IT_ARMOR|IT_WEAPON|IT_AMMO|IT_FLAG) ) continue; ent->r.client->inventory[i] = 1; } return; } it = GS_FindItemByName( name ); if( !it ) { name = trap_Cmd_Argv(1); it = GS_FindItemByName( name ); if( !it ) { G_PrintMsg( ent, "unknown item\n" ); return; } } if( !(it->flags & ITFLAG_PICKABLE) || (it->type & IT_FLAG) ) { G_PrintMsg( ent, "non-pickup (givable) item\n" ); return; } if( it->type & IT_AMMO ) { if( trap_Cmd_Argc() == 3 ) ent->r.client->inventory[it->tag] = atoi( trap_Cmd_Argv(2) ); else ent->r.client->inventory[it->tag] += it->quantity; } else { if( it->tag && (it->tag > 0) && (it->tag < game.numItems) ) { if( game.items[it->tag] != NULL ) ent->r.client->inventory[it->tag]++; } else G_PrintMsg( ent, "non-pickup (givable) item\n" ); } } //================== //Cmd_God_f //Sets client to godmode //argv(0) god //================== void Cmd_God_f (edict_t *ent) { char *msg; if (!sv_cheats->integer) { G_PrintMsg (ent, "Cheats are not enabled on this server.\n"); return; } ent->flags ^= FL_GODMODE; if (!(ent->flags & FL_GODMODE) ) msg = "godmode OFF\n"; else msg = "godmode ON\n"; G_PrintMsg( ent, msg ); } //================== //Cmd_Notarget_f //Sets client to notarget //argv(0) notarget //================== void Cmd_Notarget_f( edict_t *ent ) { char *msg; if (!sv_cheats->integer) { G_PrintMsg( ent, "Cheats are not enabled on this server.\n" ); return; } ent->flags ^= FL_NOTARGET; if (!(ent->flags & FL_NOTARGET) ) msg = "notarget OFF\n"; else msg = "notarget ON\n"; G_PrintMsg( ent, msg ); } //================== //Cmd_Noclip_f // //argv(0) noclip //================== void Cmd_Noclip_f (edict_t *ent) { char *msg; if (!sv_cheats->integer) { G_PrintMsg( ent, "Cheats are not enabled on this server.\n" ); return; } if (ent->movetype == MOVETYPE_NOCLIP) { ent->movetype = MOVETYPE_WALK; msg = "noclip OFF\n"; } else { ent->movetype = MOVETYPE_NOCLIP; msg = "noclip ON\n"; } G_PrintMsg( ent, msg ); } //================== //Cmd_Use_f //Use an inventory item //================== void Cmd_Use_f( edict_t *ent ) { gitem_t *it; char *s; s = trap_Cmd_Args(); it = GS_FindItemByName(s); if( !it ) { G_PrintMsg( ent, "unknown item: %s\n", s ); return; } if( !(it->flags & ITFLAG_USABLE) ) { G_PrintMsg( ent, "Item is not usable.\n" ); return; } if( !ent->r.client->inventory[it->tag] ) { return; } G_UseItem( ent, it ); } //================== //Cmd_Drop_f //Drop an inventory item //================== void Cmd_Drop_f( edict_t *ent ) { gitem_t *it; char *s; s = trap_Cmd_Args(); // "weapon" acts as a shortcut for current weapon if( !Q_stricmp( trap_Cmd_Argv(1), "weapon") ) { if( !ent->s.weapon ) { G_PrintMsg( ent, "No weapon to drop\n", s ); return; } it = game.items[ent->s.weapon]; } else if( !Q_stricmp( trap_Cmd_Argv(1), "flag") ) { if( ent->s.team == TEAM_BLUE ) it = G_Gametype_CTF_FlagItem( TEAM_RED ); else if( ent->s.team == TEAM_RED ) it = G_Gametype_CTF_FlagItem( TEAM_BLUE ); else it = GS_FindItemByName(s); } else { it = GS_FindItemByName(s); } if( !it ) { G_PrintMsg( ent, "unknown item: %s\n", s ); return; } if( !(it->flags & ITFLAG_DROPABLE) ) { G_PrintMsg( ent, "Item is not dropable.\n" ); return; } if( !ent->r.client->inventory[it->tag] ) { G_PrintMsg( ent, "Out of item: %s\n", s ); return; } //splitmodels (drop) if( ent->pmAnim.anim_priority[UPPER] <= ANIM_WAVE ) G_AddEvent( ent, EV_DROP, 0, qtrue ); G_DropItem( ent, it ); } //================= //Cmd_Inven_f //================= void Cmd_Inven_f (edict_t *ent) { int i; char s[1024]; int row[MAX_ITEMS * 2], rowsize, rep; gclient_t *cl; cl = ent->r.client; cl->showscores = qfalse; if (cl->showinventory) { cl->showinventory = qfalse; return; } cl->showinventory = qtrue; // RLE compression for (i=1,rowsize=0,row[0] = 0 ; iinventory[i]; if (cl->inventory[i]) continue; for (i++, rep = 1; !cl->inventory[i] && (i < game.numItems); i++, rep++); row[rowsize++] = rep; i--; } // item 0 is never used Q_strncpyz (s, "inv \"", sizeof(s)); for (i=0 ; ir.client; ValidateSelectedItem(ent); if( cl->selected_item == -1 ) { G_PrintMsg( ent, "No item to use.\n" ); return; } it = game.items[cl->selected_item]; if( !(it->flags & ITFLAG_USABLE) ) { G_PrintMsg( ent, "Item is not usable.\n" ); return; } G_UseItem( ent, it ); } //================= //Cmd_ChasePrev_f //================= void Cmd_ChasePrev_f( edict_t *ent ) { if( ent->r.client->chase.active ) { ChasePrev(ent); } else { Cmd_ChaseCam_f(ent); } } //================= //Cmd_ChaseNext_f //================= void Cmd_ChaseNext_f( edict_t *ent ) { if( ent->r.client->chase.active ) { ChaseNext(ent); } else { Cmd_ChaseCam_f(ent); } } //================= //Cmd_InvDrop_f //================= void Cmd_InvDrop_f( edict_t *ent ) { gclient_t *cl; gitem_t *it; cl = ent->r.client; ValidateSelectedItem(ent); if( cl->selected_item == -1 ) { G_PrintMsg( ent, "No item to drop.\n" ); return; } it = game.items[cl->selected_item]; if( !(it->flags & ITFLAG_DROPABLE) ) { G_PrintMsg( ent, "Item is not dropable.\n" ); return; } //splitmodels (Inventory drop) if( ent->pmAnim.anim_priority[UPPER] <= ANIM_WAVE ) G_AddEvent( ent, EV_DROP, 0, qtrue ); G_DropItem( ent, it ); } extern void Killed (edict_t *targ, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point, int mod); //================= //Cmd_Kill_f //================= void Cmd_Kill_f (edict_t *ent) { if (ent->r.solid == SOLID_NOT) return; if((level.timemsec - ent->r.client->respawn_timestamp) < 5000) // can suicide after 5 seconds return; ent->flags &= ~FL_GODMODE; ent->health = 0; meansOfDeath = MOD_SUICIDE; //player_die (ent, ent, ent, 100000, vec3_origin); // wsw : pb : fix /kill command Killed(ent, ent, ent, 100000, vec3_origin, MOD_SUICIDE ); } //================= //Cmd_PutAway_f //================= void Cmd_PutAway_f (edict_t *ent) { ent->r.client->showinventory = qfalse; ent->r.client->showscores = qfalse; } //================== //Cmd_Score_f //================== void Cmd_Score_f (edict_t *ent) { ent->r.client->showinventory = qfalse; ent->r.client->showscores = !ent->r.client->showscores; } //================== //Cmd_Position_f //================== void Cmd_Position_f (edict_t *ent) { char *action; if( match.state != MATCH_STATE_WARMUP && ent->r.client->ps.pmove.pm_type != PM_SPECTATOR ) { G_PrintMsg( ent, "Position command is only available in warmup and in spectator mode.\n" ); return; } // flood protect if( ent->r.client->teamchange.position_lastcmd + 500 > game.realtime ) return; ent->r.client->teamchange.position_lastcmd = game.realtime; action = trap_Cmd_Argv(1); if( !Q_stricmp(action, "save") ) { ent->r.client->teamchange.position_saved = qtrue; VectorCopy( ent->s.origin, ent->r.client->teamchange.position_origin ); VectorCopy( ent->s.angles, ent->r.client->teamchange.position_angles ); G_PrintMsg( ent, "Position saved.\n" ); } else if( !Q_stricmp(action, "load") ) { if( !ent->r.client->teamchange.position_saved ) { G_PrintMsg( ent, "No position saved.\n" ); } else { if( ent->r.client->chase.active ) G_SpectatorMode( ent ); if( G_Teleport( ent, ent->r.client->teamchange.position_origin, ent->r.client->teamchange.position_angles ) ) G_PrintMsg( ent, "Position loaded.\n" ); else G_PrintMsg( ent, "Position not available.\n" ); } } else if( !Q_stricmp(action, "set") && trap_Cmd_Argc() == 7 ) { vec3_t origin, angles; int i, argnumber = 2; for( i = 0; i < 3; i++ ) origin[i] = atof(trap_Cmd_Argv(argnumber++)); for( i = 0; i < 2; i++ ) angles[i] = atof(trap_Cmd_Argv(argnumber++)); angles[2] = 0; if( ent->r.client->chase.active ) G_SpectatorMode( ent ); if( G_Teleport( ent, origin, angles ) ) G_PrintMsg( ent, "Position not available.\n" ); else G_PrintMsg( ent, "Position set.\n" ); } else { char msg[MAX_STRING_CHARS]; msg[0] = 0; Q_strncatz( msg, "Usage:\nposition save - Save current position\n", sizeof(msg) ); Q_strncatz( msg, "position load - Teleport to saved position\n", sizeof(msg) ); Q_strncatz( msg, "position set - Teleport to specified position\n", sizeof(msg) ); Q_strncatz( msg, va("Current position: %.4f %.4f %.4f %.4f %.4f\n", ent->s.origin[0], ent->s.origin[1], ent->s.origin[2], ent->s.angles[0], ent->s.angles[1]), sizeof(msg) ); G_PrintMsg( ent, msg ); } } //================= //Cmd_Players_f //================= void Cmd_Players_f (edict_t *ent) { int i; int count = 0; char line[64]; char msg[1024]; // print information msg[0] = 0; #ifdef BATTLEYE if (sv_battleye->integer) Q_strncatz (msg, "num BE name\n", sizeof(msg)); else Q_strncatz (msg, "num name\n", sizeof(msg)); #else Q_strncatz (msg, "num name\n", sizeof(msg)); #endif Q_strncatz (msg, "--- ---------------\n", sizeof(msg)); for (i = 0 ; i < game.maxclients ; i++) { if (game.clients[i].pers.connected) { #ifdef BATTLEYE if (sv_battleye->integer) Q_snprintfz (line, sizeof(line), "%3i %3s %s\n", i, game.clients[i].pers.battleye?"on":"off", game.clients[i].pers.netname); else Q_snprintfz (line, sizeof(line), "%3i %s\n", i, game.clients[i].pers.netname); #else Q_snprintfz (line, sizeof(line), "%3i %s\n", i, game.clients[i].pers.netname); #endif if (strlen (line) + strlen(msg) > sizeof(msg) - 100 ) { // can't print all of them in one packet Q_strncatz (msg, "...\n", sizeof(msg)); break; } Q_strncatz (msg, line, sizeof(msg)); count++; } } Q_strncatz (msg, "--- ---------------\n", sizeof(msg)); Q_strncatz (msg, va("%3i players\n", count), sizeof(msg)); G_PrintMsg (ent, msg); } //================= //Cmd_Wave_f - SPLITMODELS //================= void Cmd_Wave_f (edict_t *ent) { int i; i = atoi (trap_Cmd_Argv(1)); if (ent->pmAnim.anim_priority[UPPER] > ANIM_WAVE) return; ent->pmAnim.anim_priority[UPPER] = ANIM_WAVE; switch (i) { case 0: default: G_AddEvent (ent, EV_GESTURE, 0, qtrue); break; } } qboolean CheckFlood(edict_t *ent) { int i; gclient_t *cl; if (flood_msgs->integer) { cl = ent->r.client; if (game.realtime < cl->flood_locktill) { G_PrintMsg (ent, "You can't talk for %d more seconds\n", (int)(cl->flood_locktill - game.realtime)); return qtrue; } i = cl->flood_whenhead - flood_msgs->integer + 1; if (i < 0) i = (sizeof(cl->flood_when)/sizeof(cl->flood_when[0])) + i; if (cl->flood_when[i] && game.realtime - cl->flood_when[i] < flood_persecond->integer) { cl->flood_locktill = game.realtime + flood_waitdelay->value; G_PrintMsg (ent, "Flood protection: You can't talk for %d seconds.\n", flood_waitdelay->integer); return qtrue; } cl->flood_whenhead = (cl->flood_whenhead + 1) % (sizeof(cl->flood_when)/sizeof(cl->flood_when[0])); cl->flood_when[cl->flood_whenhead] = game.realtime; } return qfalse; } //================== //Cmd_Say_f //================== void Cmd_Say_f( edict_t *ent, qboolean arg0 ) { char *p; char text[2048]; if( CheckFlood(ent) ) return; if( ent->r.client && ent->r.client->pers.muted & 1 ) return; if( trap_Cmd_Argc() < 2 && !arg0 ) return; Q_snprintfz( text, sizeof(text), "%s%s: ", ent->r.client->pers.netname, S_COLOR_GREEN ); if( arg0 ) { Q_strncatz( text, trap_Cmd_Argv(0), sizeof(text) ); Q_strncatz( text, " ", sizeof(text) ); Q_strncatz( text, trap_Cmd_Args(), sizeof(text) ); } else { p = trap_Cmd_Args(); if( *p == '"' ) { p++; p[strlen(p)-1] = 0; } Q_strncatz( text, p, sizeof(text) ); } // don't let text be too long for malicious reasons if( strlen(text) > 150 ) text[150] = 0; Q_strncatz( text, "\n", sizeof(text) ); G_ChatMsg( NULL, "%s", text ); } // wsw : jal : gamecommandscompletion[start] //================== //Cmd_SayCmd_f //================== void Cmd_SayCmd_f( edict_t *ent ) { Cmd_Say_f( ent, qfalse ); } //================== //Cmd_SayTeam_f //================== void Cmd_SayTeam_f( edict_t *ent ) { G_Say_Team( ent, trap_Cmd_Args(), qtrue ); } #ifdef VSAYS typedef struct { char *name; int id; char *message; }g_vsays_t; static g_vsays_t g_vsays[] = { { "needhealth", VSAY_NEEDHEALTH, "Need health!" }, { "needweapon", VSAY_NEEDWEAPON, "Need weapon!" }, { "needarmor", VSAY_NEEDARMOR, "Need armor!" }, { "affirmative", VSAY_AFFIRMATIVE, "Affirmative!" }, { "negative", VSAY_NEGATIVE, "Negative!" }, { "yes", VSAY_YES, "Yes!" }, { "no", VSAY_NO, "No!" }, { "ondefense", VSAY_ONDEFENSE, "I'm on defense!" }, { "onoffense", VSAY_ONOFFENSE, "I'm on offense!" }, { "oops", VSAY_OOPS, "Oops!" }, { "sorry", VSAY_SORRY, "Sorry!" }, { "thanks", VSAY_THANKS, "Thanks!" }, { "noproblem", VSAY_NOPROBLEM, "No problem!" }, { "yeehaa", VSAY_YEEHAA, "Yeehaa!" }, { "goodgame", VSAY_GOODGAME, "Good game!" }, { "defend", VSAY_DEFEND, "Defend!" }, { "attack", VSAY_ATTACK, "Attack!" }, { "needbackup", VSAY_NEEDBACKUP, "Need backup!" }, { "booo", VSAY_BOOO, "Booo!" }, { "needdefense", VSAY_NEEDDEFENSE, "Need defense!" }, { "needoffense", VSAY_NEEDOFFENSE, "Need offense!" }, { "needhelp", VSAY_NEEDHELP, "Need help!" }, { "roger", VSAY_ROGER, "Roger!" }, { "armorfree", VSAY_ARMORFREE, "Armor free!" }, { "areasecured", VSAY_AREASECURED, "Area secured!" }, { "shutup", VSAY_SHUTUP, "Shut up!" }, { "boomstick", VSAY_BOOMSTICK, "Need a weapon!" }, { "gotopowerup", VSAY_GOTOPOWERUP, "Go to main powerup!" }, { "gotoquad", VSAY_GOTOQUAD, "Go to quad!" }, { "ok", VSAY_OK, "Ok!" }, { NULL, 0 } }; void G_BOTvsay_f( edict_t *ent, char *msg, qboolean team ) { edict_t *event = NULL; g_vsays_t *vsay; char *text = NULL; if( !(ent->r.svflags & SVF_FAKECLIENT) ) { // ignore flood checks on bots return; } if( ent->r.client && ent->r.client->pers.muted & 2 ) return; for( vsay = g_vsays; vsay->name; vsay++ ) { if( !Q_stricmp(msg, vsay->name) ) { event = G_SpawnEvent( EV_VSAY, vsay->id, NULL ); text = vsay->message; break; } } if( event && text ) { event->r.svflags |= SVF_BROADCAST; // force sending even when not in PVS event->s.ownerNum = ent->s.number; if( team ) { event->s.team = ent->s.team; event->r.svflags |= SVF_ONLYTEAM; // send only to clients with the same ->s.team value } if( team ) G_Say_Team( ent, va("(v) %s", text), qfalse ); else G_ChatMsg( NULL, "%s%s: (v) %s\n", ent->r.client->pers.netname, S_COLOR_GREEN, text ); } } //================== //G_vsay_f //================== void G_vsay_f( edict_t *ent, qboolean team ) { edict_t *event = NULL; g_vsays_t *vsay; char *text = NULL; char *msg = trap_Cmd_Argv(1); if( ent->r.client && ent->r.client->pers.muted & 2 ) return; if( !(ent->r.svflags & SVF_FAKECLIENT) ) { // ignore flood checks on bots if( ent->r.client->last_vsay > game.realtime - 500 ) return; // ignore silently vsays in that come in rapid succession ent->r.client->last_vsay = game.realtime; if( CheckFlood(ent) ) return; } for( vsay = g_vsays; vsay->name; vsay++ ) { if( !Q_stricmp(msg, vsay->name) ) { event = G_SpawnEvent( EV_VSAY, vsay->id, NULL ); text = vsay->message; break; } } if( event && text ) { event->r.svflags |= SVF_BROADCAST; // force sending even when not in PVS event->s.ownerNum = ent->s.number; if( team ) { event->s.team = ent->s.team; event->r.svflags |= SVF_ONLYTEAM; // send only to clients with the same ->s.team value } if( trap_Cmd_Argc() > 2 ) { char saystring[256]; int i; saystring[0] = 0; for( i = 2; i < trap_Cmd_Argc(); i++ ) { Q_strncatz( saystring, trap_Cmd_Argv(i), sizeof(saystring) ); Q_strncatz( saystring, " ", sizeof(saystring) ); } if( team ) G_Say_Team( ent, va("(v) %s", saystring), qfalse ); else G_ChatMsg( NULL, "%s%s: (v) %s\n", ent->r.client->pers.netname, S_COLOR_GREEN, saystring ); } else { if( team ) G_Say_Team( ent, va("(v) %s", text), qfalse ); else G_ChatMsg( NULL, "%s%s: (v) %s\n", ent->r.client->pers.netname, S_COLOR_GREEN, text ); } return; } // unknown token, print help { char string[MAX_STRING_CHARS]; // print information string[0] = 0; if( msg && strlen(msg) > 0 ) Q_strncatz( string, va( "%sUnknown vsay token%s \"%s\"\n", S_COLOR_YELLOW, S_COLOR_WHITE, msg ), sizeof(string) ); Q_strncatz( string, va( "%svsays:%s\n",S_COLOR_YELLOW, S_COLOR_WHITE ), sizeof(string) ); for( vsay = g_vsays; vsay->name; vsay++ ) { if( strlen(vsay->name) + strlen(string) < sizeof(string) - 6 ) { Q_strncatz( string, va("%s ", vsay->name), sizeof(string) ); } } Q_strncatz( string, "\n", sizeof(string) ); G_PrintMsg( ent, string ); } } //================== //G_vsay_Cmd //================== void G_vsay_Cmd( edict_t *ent ) { G_vsay_f( ent, qfalse ); } //================== //G_Teams_vsay_Cmd //================== void G_Teams_vsay_Cmd( edict_t *ent ) { G_vsay_f( ent, qtrue ); } #endif // VSAYS //================== //Cmd_InvNext_f //================== void Cmd_InvNext_f( edict_t *ent ) { SelectNextItem( ent, -1 ); } //================== //Cmd_InvPrev_f //================== void Cmd_InvPrev_f( edict_t *ent ) { SelectPrevItem( ent, -1 ); } //================== //Cmd_InvNextWeap_f //================== void Cmd_InvNextWeap_f( edict_t *ent ) { SelectNextItem( ent, IT_WEAPON ); } //================== //Cmd_InvPrevWeap_f //================== void Cmd_InvPrevWeap_f( edict_t *ent ) { SelectPrevItem( ent, IT_WEAPON ); } //==================== //Cmd_Timeout_f //==================== static void Cmd_Timeout_f( edict_t *ent ) { int num; if( ent->s.team == TEAM_SPECTATOR || match.state != MATCH_STATE_PLAYTIME ) return; if( GS_Gametype_IsTeamBased( game.gametype ) ) num = ent->s.team; else num = ENTNUM(ent)-1; if( gtimeout.active && (gtimeout.endtime - gtimeout.time) >= 2*TIMEIN_TIME ) { G_PrintMsg( ent, "Timeout already in progress\n" ); return; } if( g_maxtimeouts->integer != -1 && gtimeout.used[num] >= g_maxtimeouts->integer ) { if( g_maxtimeouts->integer == 0 ) G_PrintMsg( ent, "Timeouts are not allowed on this server\n" ); else if( GS_Gametype_IsTeamBased( game.gametype ) ) G_PrintMsg( ent, "Your team doesn't have any timeouts left\n" ); else G_PrintMsg( ent, "You don't have any timeouts left\n" ); return; } G_PrintMsg( NULL, "%s%s called a timeout\n", ent->r.client->pers.netname, S_COLOR_WHITE ); if( !gtimeout.active ) G_AnnouncerSound( NULL, trap_SoundIndex(va(S_ANNOUNCER_TIMEOUT_TIMEOUT_1_to_2, (rand()&1)+1)), GS_MAX_TEAMS, qtrue ); gtimeout.used[num]++; gtimeout.active = qtrue; gtimeout.caller = num; gtimeout.endtime = gtimeout.time + TIMEOUT_TIME + FRAMETIME; } //==================== //Cmd_Timeout_f //==================== static void Cmd_Timein_f( edict_t *ent ) { int num; if( ent->s.team == TEAM_SPECTATOR ) return; if( !gtimeout.active ) { G_PrintMsg( ent, "No timeout in progress.\n" ); return; } if( gtimeout.endtime - gtimeout.time <= 2 * TIMEIN_TIME ) { G_PrintMsg( ent, "The timeout is about to end already.\n" ); return; } if( GS_Gametype_IsTeamBased( game.gametype ) ) num = ent->s.team; else num = ENTNUM(ent)-1; if( gtimeout.caller != num) { if( GS_Gametype_IsTeamBased( game.gametype ) ) G_PrintMsg( ent, "Your team didn't call this timeout.\n" ); else G_PrintMsg( ent, "You didn't call this timeout.\n" ); return; } gtimeout.endtime = gtimeout.time + TIMEIN_TIME + FRAMETIME; G_AnnouncerSound( NULL, trap_SoundIndex(va(S_ANNOUNCER_TIMEOUT_TIMEIN_1_to_2, (rand()&1)+1)), GS_MAX_TEAMS, qtrue ); G_PrintMsg( NULL, "%s%s called a timein\n", ent->r.client->pers.netname, S_COLOR_WHITE ); } //================= //Cmd_ShowAccuracies_f //================= void Cmd_ShowAccuracies_f(edict_t *ent) { gitem_t *it; int i; int weakhit,weakshot; int hit,shot; float p; gclient_t *client; // when chasing generate from target client = ent->r.client; if( client->chase.active && game.edicts[client->chase.target].r.client ) client = game.edicts[client->chase.target].r.client; G_PrintMsg (ent, "%2s%s", " ", " Weak Strong\n"); G_PrintMsg (ent, "%2s%s", " ", " hit/shot percent"); G_PrintMsg (ent, " hit/shot percent\n"); //G_PrintMsg (ent, "-------------------------\n"); for( i = WEAP_GUNBLADE; i < WEAP_TOTAL; i++ ) { it = GS_FindItemByTag( i ); if( it->weakammo_tag != AMMO_NONE ) { weakhit = client->resp.accuracy_hits[it->weakammo_tag-AMMO_CELLS]; weakshot = client->resp.accuracy_shots[it->weakammo_tag-AMMO_CELLS]; } else { weakhit = 0; weakshot = 0; } if( it->ammo_tag != AMMO_NONE ) { hit = client->resp.accuracy_hits[it->ammo_tag-AMMO_CELLS]; shot = client->resp.accuracy_shots[it->ammo_tag-AMMO_CELLS]; } else { hit = 0; shot = 0; } if(weakshot>0 || shot>0) // only continue with registered shots { if(weakshot!=0) p=(100.0f*weakhit)/((float)weakshot); else p=0.0f; G_PrintMsg (ent, "%s%2s%s: %s%3i%s/%s%3i %s%2.1f", // weak it->color,it->short_name,S_COLOR_WHITE, S_COLOR_GREEN, weakhit, S_COLOR_WHITE, S_COLOR_CYAN, weakshot, S_COLOR_YELLOW, p); if(shot!=0) p=(100.0f*hit)/((float)shot); else p=0.0f; G_PrintMsg (ent, " %s%3i%s/%s%3i %s%2.1f\n", // strong S_COLOR_GREEN, hit, S_COLOR_WHITE, S_COLOR_CYAN, shot, S_COLOR_YELLOW, p); } } } //=========================================================== // client commands //=========================================================== typedef struct { int index; char name[MAX_QPATH]; void (*func)(edict_t *ent); }g_gamecommands_t; g_gamecommands_t g_Commands[MAX_GAMECOMMANDS]; void Cmd_ShowPLinks_f( edict_t *ent ); //MbotGame //================== //G_AddCommand //================== void G_AddCommand( char *name, void *callback ) { int i; //see if we already had it in game side for( i = 0; i < MAX_GAMECOMMANDS; i++ ) { if( g_Commands[i].index == -1 ) continue; if( !Q_stricmp( g_Commands[i].name, name) ) { //update func if different if( g_Commands[i].func != callback ) g_Commands[i].func = callback; return; } } // we didn't have it. Find a free one and add it for( i = 0; i < MAX_GAMECOMMANDS; i++ ) { if( g_Commands[i].index == -1 ) { g_Commands[i].index = i; g_Commands[i].func = callback; Q_strncpyz( g_Commands[i].name, name, sizeof(g_Commands[i].name) ); trap_ConfigString( CS_GAMECOMMANDS + i, name ); return; } } G_Error( "G_AddCommand: Couldn't find a free g_Commands spot for the new command. (increase MAX_GAMECOMMANDS)\n" ); } //================== //G_InitGameCommands //================== void G_InitGameCommands( void ) { int i; for( i = 0; i < MAX_GAMECOMMANDS; i++ ) { g_Commands[i].index = -1; g_Commands[i].func = NULL; g_Commands[i].name[0] = 0; } G_AddCommand( "position", Cmd_Position_f ); G_AddCommand( "players", Cmd_Players_f ); G_AddCommand( "stats", Cmd_ShowAccuracies_f ); G_AddCommand( "say", Cmd_SayCmd_f ); G_AddCommand( "say_team", Cmd_SayTeam_f ); G_AddCommand( "score", Cmd_Score_f ); G_AddCommand( "drop", Cmd_Drop_f ); G_AddCommand( "give", Cmd_Give_f ); G_AddCommand( "god", Cmd_God_f ); // G_AddCommand( "notarget", Cmd_Notarget_f ); // useless. We have no monsters G_AddCommand( "noclip", Cmd_Noclip_f ); G_AddCommand( "inven", Cmd_Inven_f ); G_AddCommand( "invnext", Cmd_InvNext_f ); G_AddCommand( "invprev", Cmd_InvPrev_f ); G_AddCommand( "invnextw", Cmd_InvNextWeap_f ); G_AddCommand( "invprevw", Cmd_InvPrevWeap_f ); G_AddCommand( "invuse", Cmd_InvUse_f ); G_AddCommand( "invdrop", Cmd_InvDrop_f ); G_AddCommand( "svuse", Cmd_Use_f ); G_AddCommand( "chaseprev", Cmd_ChasePrev_f ); G_AddCommand( "chasenext", Cmd_ChaseNext_f ); G_AddCommand( "kill", Cmd_Kill_f ); G_AddCommand( "putaway", Cmd_PutAway_f ); G_AddCommand( "wave", Cmd_Wave_f ); G_AddCommand( "chase", Cmd_ChaseCam_f ); G_AddCommand( "spec", Cmd_Spec_f ); G_AddCommand( "enterqueue", G_Teams_JoinChallengersQueue ); G_AddCommand( "leavequeue", G_Teams_LeaveChallengersQueue ); G_AddCommand( "camswitch", Cmd_SwitchChaseCamMode_f ); G_AddCommand( "timeout", Cmd_Timeout_f ); G_AddCommand( "timein", Cmd_Timein_f ); // callvotes commands G_AddCommand( "callvote", G_CallVote_Cmd ); G_AddCommand( "vote", G_CallVotes_CmdVote ); // teams commands G_AddCommand( "ready", G_Match_Ready ); G_AddCommand( "unready", G_Match_NotReady ); G_AddCommand( "notready", G_Match_NotReady ); G_AddCommand( "join", G_Teams_Join_Cmd ); #ifdef VSAYS G_AddCommand( "vsay", G_vsay_Cmd ); G_AddCommand( "vsay_team", G_Teams_vsay_Cmd ); #endif G_AddCommand( "lock", G_Teams_Lock_f ); G_AddCommand( "unlock", G_Teams_UnLock_f ); G_AddCommand( "invite", G_Teams_Invite_f ); // bot commands G_AddCommand( "showplinks", Cmd_ShowPLinks_f ); //MbotGame } //================= //ClientCommand //================= void ClientCommand (edict_t *ent) { char *cmd; int i; if (!ent->r.client) return; // not fully in game yet cmd = trap_Cmd_Argv(0); for( i = 0; i < MAX_GAMECOMMANDS; i++ ) { if( g_Commands[i].index == -1 ) continue; if( !Q_stricmp( g_Commands[i].name, cmd) ) { if( g_Commands[i].func ) g_Commands[i].func(ent); return; } } // unknown as a command. Say it as chat Cmd_Say_f (ent, qtrue); } // wsw : jal : gamecommandscompletion[end]