ioq3/code/game/g_local.h

954 lines
34 KiB
C
Raw Normal View History

2005-08-26 17:39:27 +00:00
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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.
Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
2005-08-26 17:39:27 +00:00
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// g_local.h -- local definitions for game module
#include "../qcommon/q_shared.h"
2005-08-26 17:39:27 +00:00
#include "bg_public.h"
#include "g_public.h"
//==================================================================
// the "gameversion" client command will print this plus compile date
#define GAMEVERSION BASEGAME
2005-08-26 17:39:27 +00:00
#define BODY_QUEUE_SIZE 8
#define INFINITE 1000000
#define FRAMETIME 100 // msec
#define CARNAGE_REWARD_TIME 3000
#define REWARD_SPRITE_TIME 2000
#define INTERMISSION_DELAY_TIME 1000
#define SP_INTERMISSION_DELAY_TIME 5000
// gentity->flags
#define FL_GODMODE 0x00000010
#define FL_NOTARGET 0x00000020
#define FL_TEAMSLAVE 0x00000400 // not the first on the team
#define FL_NO_KNOCKBACK 0x00000800
#define FL_DROPPED_ITEM 0x00001000
#define FL_NO_BOTS 0x00002000 // spawn point not for bot use
#define FL_NO_HUMANS 0x00004000 // spawn point just for bots
#define FL_FORCE_GESTURE 0x00008000 // force gesture on client
// movers are things like doors, plats, buttons, etc
typedef enum {
MOVER_POS1,
MOVER_POS2,
MOVER_1TO2,
MOVER_2TO1
} moverState_t;
#define SP_PODIUM_MODEL "models/mapobjects/podium/podium4.md3"
//============================================================================
typedef struct gentity_s gentity_t;
typedef struct gclient_s gclient_t;
struct gentity_s {
entityState_t s; // communicated by server to clients
entityShared_t r; // shared by both the server system and game
// DO NOT MODIFY ANYTHING ABOVE THIS, THE SERVER
// EXPECTS THE FIELDS IN THAT ORDER!
//================================
struct gclient_s *client; // NULL if not a client
qboolean inuse;
char *classname; // set in QuakeEd
int spawnflags; // set in QuakeEd
qboolean neverFree; // if true, FreeEntity will only unlink
// bodyque uses this
int flags; // FL_* variables
char *model;
char *model2;
int freetime; // level.time when the object was freed
int eventTime; // events will be cleared EVENT_VALID_MSEC after set
qboolean freeAfterEvent;
qboolean unlinkAfterEvent;
qboolean physicsObject; // if true, it can be pushed by movers and fall off edges
// all game items are physicsObjects,
float physicsBounce; // 1.0 = continuous bounce, 0.0 = no bounce
int clipmask; // brushes with this content value will be collided against
// when moving. items and corpses do not collide against
// players, for instance
// movers
moverState_t moverState;
int soundPos1;
int sound1to2;
int sound2to1;
int soundPos2;
int soundLoop;
gentity_t *parent;
gentity_t *nextTrain;
gentity_t *prevTrain;
vec3_t pos1, pos2;
char *message;
int timestamp; // body queue sinking, etc
char *target;
char *targetname;
char *team;
char *targetShaderName;
char *targetShaderNewName;
gentity_t *target_ent;
float speed;
vec3_t movedir;
int nextthink;
void (*think)(gentity_t *self);
void (*reached)(gentity_t *self); // movers call this when hitting endpoint
void (*blocked)(gentity_t *self, gentity_t *other);
void (*touch)(gentity_t *self, gentity_t *other, trace_t *trace);
void (*use)(gentity_t *self, gentity_t *other, gentity_t *activator);
void (*pain)(gentity_t *self, gentity_t *attacker, int damage);
void (*die)(gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod);
int pain_debounce_time;
int fly_sound_debounce_time; // wind tunnel
int last_move_time;
int health;
qboolean takedamage;
int damage;
int splashDamage; // quad will increase this without increasing radius
int splashRadius;
int methodOfDeath;
int splashMethodOfDeath;
int count;
gentity_t *chain;
gentity_t *enemy;
gentity_t *activator;
gentity_t *teamchain; // next entity in team
gentity_t *teammaster; // master of the team
#ifdef MISSIONPACK
int kamikazeTime;
int kamikazeShockTime;
#endif
int watertype;
int waterlevel;
int noise_index;
// timing variables
float wait;
float random;
gitem_t *item; // for bonus items
};
typedef enum {
CON_DISCONNECTED,
CON_CONNECTING,
CON_CONNECTED
} clientConnected_t;
typedef enum {
SPECTATOR_NOT,
SPECTATOR_FREE,
SPECTATOR_FOLLOW,
SPECTATOR_SCOREBOARD
} spectatorState_t;
typedef enum {
TEAM_BEGIN, // Beginning a team game, spawn at base
TEAM_ACTIVE // Now actively playing
} playerTeamStateState_t;
typedef struct {
playerTeamStateState_t state;
int location;
int captures;
int basedefense;
int carrierdefense;
int flagrecovery;
int fragcarrier;
int assists;
float lasthurtcarrier;
float lastreturnedflag;
float flagsince;
float lastfraggedcarrier;
} playerTeamState_t;
// client data that stays across multiple levels or tournament restarts
// this is achieved by writing all the data to cvar strings at game shutdown
// time and reading them back at connection time. Anything added here
// MUST be dealt with in G_InitSessionData() / G_ReadSessionData() / G_WriteSessionData()
typedef struct {
team_t sessionTeam;
int spectatorNum; // for determining next-in-line to play
2005-08-26 17:39:27 +00:00
spectatorState_t spectatorState;
int spectatorClient; // for chasecam and follow mode
int wins, losses; // tournament stats
qboolean teamLeader; // true when this client is a team leader
} clientSession_t;
//
#define MAX_NETNAME 36
#define MAX_VOTE_COUNT 3
// client data that stays across multiple respawns, but is cleared
// on each level change or team change at ClientBegin()
typedef struct {
clientConnected_t connected;
usercmd_t cmd; // we would lose angles if not persistant
qboolean localClient; // true if "ip" info key is "localhost"
qboolean initialSpawn; // the first spawn should be at a cool location
qboolean predictItemPickup; // based on cg_predictItems userinfo
qboolean pmoveFixed; //
char netname[MAX_NETNAME];
int maxHealth; // for handicapping
int enterTime; // level.time the client entered the game
playerTeamState_t teamState; // status in teamplay games
int voteCount; // to prevent people from constantly calling votes
int teamVoteCount; // to prevent people from constantly calling votes
qboolean teamInfo; // send team overlay updates?
} clientPersistant_t;
// this structure is cleared on each ClientSpawn(),
// except for 'client->pers' and 'client->sess'
struct gclient_s {
// ps MUST be the first element, because the server expects it
playerState_t ps; // communicated by server to clients
// the rest of the structure is private to game
clientPersistant_t pers;
clientSession_t sess;
qboolean readyToExit; // wishes to leave the intermission
qboolean noclip;
int lastCmdTime; // level.time of last usercmd_t, for EF_CONNECTION
// we can't just use pers.lastCommand.time, because
// of the g_sycronousclients case
int buttons;
int oldbuttons;
int latched_buttons;
vec3_t oldOrigin;
// sum up damage over an entire frame, so
// shotgun blasts give a single big kick
int damage_armor; // damage absorbed by armor
int damage_blood; // damage taken out of health
int damage_knockback; // impact damage
vec3_t damage_from; // origin for vector calculation
qboolean damage_fromWorld; // if true, don't use the damage_from vector
int accurateCount; // for "impressive" reward sound
int accuracy_shots; // total number of shots
int accuracy_hits; // total number of hits
//
int lastkilled_client; // last client that this client killed
int lasthurt_client; // last client that damaged this client
int lasthurt_mod; // type of damage the client did
// timers
int respawnTime; // can respawn when time > this, force after g_forcerespwan
int inactivityTime; // kick players when time > this
qboolean inactivityWarning; // qtrue if the five seoond warning has been given
int rewardTime; // clear the EF_AWARD_IMPRESSIVE, etc when time > this
int airOutTime;
int lastKillTime; // for multiple kill rewards
qboolean fireHeld; // used for hook
gentity_t *hook; // grapple hook if out
int switchTeamTime; // time the player switched teams
// timeResidual is used to handle events that happen every second
// like health / armor countdowns and regeneration
int timeResidual;
#ifdef MISSIONPACK
gentity_t *persistantPowerup;
int portalID;
int ammoTimes[WP_NUM_WEAPONS];
int invulnerabilityTime;
#endif
char *areabits;
};
//
// this structure is cleared as each map is entered
//
#define MAX_SPAWN_VARS 64
#define MAX_SPAWN_VARS_CHARS 4096
typedef struct {
struct gclient_s *clients; // [maxclients]
struct gentity_s *gentities;
int gentitySize;
2011-05-11 14:33:12 +00:00
int num_entities; // MAX_CLIENTS <= num_entities <= ENTITYNUM_MAX_NORMAL
2005-08-26 17:39:27 +00:00
int warmupTime; // restart match at this time
fileHandle_t logFile;
// store latched cvars here that we want to get at often
int maxclients;
int framenum;
int time; // in msec
int previousTime; // so movers can back up when blocked
int startTime; // level.time the map was started
int teamScores[TEAM_NUM_TEAMS];
int lastTeamLocationTime; // last time of client team location update
qboolean newSession; // don't use any old session data, because
// we changed gametype
qboolean restarted; // waiting for a map_restart to fire
int numConnectedClients;
int numNonSpectatorClients; // includes connecting clients
int numPlayingClients; // connected, non-spectators
int sortedClients[MAX_CLIENTS]; // sorted by score
int follow1, follow2; // clientNums for auto-follow spectators
int snd_fry; // sound index for standing in lava
int warmupModificationCount; // for detecting if g_warmup is changed
// voting state
char voteString[MAX_STRING_CHARS];
char voteDisplayString[MAX_STRING_CHARS];
int voteTime; // level.time vote was called
int voteExecuteTime; // time the vote is executed
int voteYes;
int voteNo;
int numVotingClients; // set by CalculateRanks
// team voting state
char teamVoteString[2][MAX_STRING_CHARS];
int teamVoteTime[2]; // level.time vote was called
int teamVoteYes[2];
int teamVoteNo[2];
int numteamVotingClients[2];// set by CalculateRanks
// spawn variables
qboolean spawning; // the G_Spawn*() functions are valid
int numSpawnVars;
char *spawnVars[MAX_SPAWN_VARS][2]; // key / value pairs
int numSpawnVarChars;
char spawnVarChars[MAX_SPAWN_VARS_CHARS];
// intermission state
int intermissionQueued; // intermission was qualified, but
// wait INTERMISSION_DELAY_TIME before
// actually going there so the last
// frag can be watched. Disable future
// kills during this delay
int intermissiontime; // time the intermission was started
char *changemap;
qboolean readyToExit; // at least one client wants to exit
int exitTime;
vec3_t intermission_origin; // also used for spectator spawns
vec3_t intermission_angle;
qboolean locationLinked; // target_locations get linked
gentity_t *locationHead; // head of the location list
int bodyQueIndex; // dead bodies
gentity_t *bodyQue[BODY_QUEUE_SIZE];
#ifdef MISSIONPACK
int portalSequence;
#endif
} level_locals_t;
//
// g_spawn.c
//
qboolean G_SpawnString( const char *key, const char *defaultString, char **out );
// spawn string returns a temporary reference, you must CopyString() if you want to keep it
qboolean G_SpawnFloat( const char *key, const char *defaultString, float *out );
qboolean G_SpawnInt( const char *key, const char *defaultString, int *out );
qboolean G_SpawnVector( const char *key, const char *defaultString, float *out );
void G_SpawnEntitiesFromString( void );
char *G_NewString( const char *string );
//
// g_cmds.c
//
void Cmd_Score_f (gentity_t *ent);
void StopFollowing( gentity_t *ent );
void BroadcastTeamChange( gclient_t *client, int oldTeam );
Fix g_teamAutoJoin and g_teamForceBalance There are various issues caused by not knowing the initial team for the local client and bots when they connect. This is can be reproduced by starting a team game from the main menu. When g_teamAutoJoin is enabled, bots and local client join a random team at connect and then execute their team command a few frames later. This may result in the player being killed if they specify a different team. In Team Arena's Harvester mode this causes harvester skulls to be spawned at the beginning of the game. When g_teamForceBalance is enabled, the local client and bots may not be able to join their desired team. This may result in them being spectators. If g_teamAutoJoin is also enabled they may be left on the opposite (red/blue) team they were meant to join. There is a hack for including bot's team in their player info string (used by cgame for which team skin to use) before the bot joins their desired team. Bots aren't guaranteed to join their desired team (as may happen when both g_teamAutoJoin and g_teamForceBalance are enabled) so clients may see them as being on the wrong team! ---- Add teampref userinfo option for team preference. If teampref is set it will be used for attempting to join the team immediately at connect. Bots now join team at connect using teampref userinfo. So remove the hack for setting bot's team in player info string before the bot joins the team. To avoid the client sending teampref userinfo to all network servers, the local client uses a g_localTeamPref cvar. The g_localTeamPref cvar is cleared after it's used so it doesn't get used when starting another server later. Another reason not to use a teampref userinfo cvar is there isn't a reliable way to clear it in CGame/UI which are likely loaded from baseq3 pk3. Make it so g_teamAutoJoin doesn't affect clients who specify teampref. If teampref is invalid, the client will join a random team like g_teamAutoJoin. Don't apply g_teamForceBalance to the local client or bots. Otherwise they may be left as spectators when starting team game from menu. The start server menus use team command and g_localTeamPref to set the human player's team. This way it's compatible with vanilla Q3 game VMs and the new setting team at connect feature.
2017-06-23 02:56:00 +00:00
void SetTeam( gentity_t *ent, const char *s );
2005-08-26 17:39:27 +00:00
void Cmd_FollowCycle_f( gentity_t *ent, int dir );
//
// g_items.c
//
void G_CheckTeamItems( void );
void G_RunItem( gentity_t *ent );
void RespawnItem( gentity_t *ent );
void UseHoldableItem( gentity_t *ent );
void PrecacheItem (gitem_t *it);
gentity_t *Drop_Item( gentity_t *ent, gitem_t *item, float angle );
gentity_t *LaunchItem( gitem_t *item, vec3_t origin, vec3_t velocity );
void SetRespawn (gentity_t *ent, float delay);
void G_SpawnItem (gentity_t *ent, gitem_t *item);
void FinishSpawningItem( gentity_t *ent );
void Think_Weapon (gentity_t *ent);
int ArmorIndex (gentity_t *ent);
void Add_Ammo (gentity_t *ent, int weapon, int count);
void Touch_Item (gentity_t *ent, gentity_t *other, trace_t *trace);
void ClearRegisteredItems( void );
void RegisterItem( gitem_t *item );
void SaveRegisteredItems( void );
//
// g_utils.c
//
int G_ModelIndex( char *name );
int G_SoundIndex( char *name );
void G_TeamCommand( team_t team, char *cmd );
void G_KillBox (gentity_t *ent);
gentity_t *G_Find (gentity_t *from, int fieldofs, const char *match);
gentity_t *G_PickTarget (char *targetname);
void G_UseTargets (gentity_t *ent, gentity_t *activator);
void G_SetMovedir ( vec3_t angles, vec3_t movedir);
void G_InitGentity( gentity_t *e );
gentity_t *G_Spawn (void);
gentity_t *G_TempEntity( vec3_t origin, int event );
void G_Sound( gentity_t *ent, int channel, int soundIndex );
void G_FreeEntity( gentity_t *e );
qboolean G_EntitiesFree( void );
void G_TouchTriggers (gentity_t *ent);
float *tv (float x, float y, float z);
char *vtos( const vec3_t v );
float vectoyaw( const vec3_t vec );
void G_AddPredictableEvent( gentity_t *ent, int event, int eventParm );
void G_AddEvent( gentity_t *ent, int event, int eventParm );
void G_SetOrigin( gentity_t *ent, vec3_t origin );
void AddRemap(const char *oldShader, const char *newShader, float timeOffset);
2005-09-02 20:13:47 +00:00
const char *BuildShaderStateConfig( void );
2005-08-26 17:39:27 +00:00
//
// g_combat.c
//
qboolean CanDamage (gentity_t *targ, vec3_t origin);
void G_Damage (gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, vec3_t dir, vec3_t point, int damage, int dflags, int mod);
qboolean G_RadiusDamage (vec3_t origin, gentity_t *attacker, float damage, float radius, gentity_t *ignore, int mod);
int G_InvulnerabilityEffect( gentity_t *targ, vec3_t dir, vec3_t point, vec3_t impactpoint, vec3_t bouncedir );
void body_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath );
void TossClientItems( gentity_t *self );
#ifdef MISSIONPACK
void TossClientPersistantPowerups( gentity_t *self );
#endif
void TossClientCubes( gentity_t *self );
// damage flags
#define DAMAGE_RADIUS 0x00000001 // damage was indirect
#define DAMAGE_NO_ARMOR 0x00000002 // armour does not protect from this damage
#define DAMAGE_NO_KNOCKBACK 0x00000004 // do not affect velocity, just view angles
#define DAMAGE_NO_PROTECTION 0x00000008 // armor, shields, invulnerability, and godmode have no effect
#ifdef MISSIONPACK
#define DAMAGE_NO_TEAM_PROTECTION 0x00000010 // armor, shields, invulnerability, and godmode have no effect
#endif
//
// g_missile.c
//
void G_RunMissile( gentity_t *ent );
gentity_t *fire_plasma (gentity_t *self, vec3_t start, vec3_t aimdir);
gentity_t *fire_grenade (gentity_t *self, vec3_t start, vec3_t aimdir);
gentity_t *fire_rocket (gentity_t *self, vec3_t start, vec3_t dir);
gentity_t *fire_bfg (gentity_t *self, vec3_t start, vec3_t dir);
gentity_t *fire_grapple (gentity_t *self, vec3_t start, vec3_t dir);
#ifdef MISSIONPACK
gentity_t *fire_nail( gentity_t *self, vec3_t start, vec3_t forward, vec3_t right, vec3_t up );
gentity_t *fire_prox( gentity_t *self, vec3_t start, vec3_t aimdir );
#endif
//
// g_mover.c
//
void G_RunMover( gentity_t *ent );
void Touch_DoorTrigger( gentity_t *ent, gentity_t *other, trace_t *trace );
//
// g_trigger.c
//
void trigger_teleporter_touch (gentity_t *self, gentity_t *other, trace_t *trace );
//
// g_misc.c
//
void TeleportPlayer( gentity_t *player, vec3_t origin, vec3_t angles );
#ifdef MISSIONPACK
void DropPortalSource( gentity_t *ent );
void DropPortalDestination( gentity_t *ent );
#endif
//
// g_weapon.c
//
qboolean LogAccuracyHit( gentity_t *target, gentity_t *attacker );
void CalcMuzzlePoint ( gentity_t *ent, vec3_t forward, vec3_t right, vec3_t up, vec3_t muzzlePoint );
void SnapVectorTowards( vec3_t v, vec3_t to );
qboolean CheckGauntletAttack( gentity_t *ent );
void Weapon_HookFree (gentity_t *ent);
void Weapon_HookThink (gentity_t *ent);
//
// g_client.c
//
int TeamCount( int ignoreClientNum, team_t team );
2005-08-26 17:39:27 +00:00
int TeamLeader( int team );
team_t PickTeam( int ignoreClientNum );
void SetClientViewAngle( gentity_t *ent, vec3_t angle );
gentity_t *SelectSpawnPoint (vec3_t avoidPoint, vec3_t origin, vec3_t angles, qboolean isbot);
2005-08-26 17:39:27 +00:00
void CopyToBodyQue( gentity_t *ent );
Batch of bug fixes for gamecode. Patch compiled and log message written by Tobias Kuehnhammer (#5144) ################################################################################ This Patch fixes: ################################################################################ - The "fraglimit warning" was not played at all, if on the blue team. - The "where" console command was broken. - Obelisk explosion wasn't drawn if no Rocketlauncher was loaded. - Impact marks sometimes didn't draw at all. - IMPORTANT BUGFIX: No killing for cheaters with Lightning gun and Gauntlet. - If two doors are close to each other a spectator couldn't fly through them. - More robust, efficient and logical respawning routine. NOTE: The game.qvm will get notable smaller and will use LESS MEMORY! - Drowning sounds are fixed. Now they are played as intended. (as the id comment in the source code shows). - Some AI bugs (OVERFLOW!) in the bot movement code. - Several "Team Arena" Overload and Harvester bugs. - Stops bots from attacking a team mate (player) who only changed teams. - Some voice chats and CTF commands fixed. - "Team_ReturnFlag" was called twice, which did wired things sometimes. NOTE: (G_RunItem checks CONTENTS_NODROP already!) - A bugfix for Gauntlet animation. - Incorrect CTF scoring. - A bunch of corrected comments and print lines ("\n"). - Some regularity of expression and some small trivial bugs. ################################################################################ Details: ################################################################################ ******************************************************************************** BUG: in gamemode GT_TEAM the fraglimit warning will not be played if joining the blue team! -------------------------------------------------------------------------------- Solution: In "CG_CheckLocalSounds": if cgs.scores2 > highScore, highScore should be cgs.scores2. ******************************************************************************** BUG: the "where" console command doesn't work as expected (it's always 0 0 0) but not in id Quake 3 Arena. It seems that now Ioquake3 is affected! -------------------------------------------------------------------------------- Solution: In Function "Cmd_Where_f" ent->s.origin should be ent->r.currentOrigin. ******************************************************************************** BUG: in gamemode GT_OBELISK obelisk explosion won't be drawn if there is no Rocketlauncher loaded. (The "maps without Rocketlauncher" bug) -------------------------------------------------------------------------------- Solution: in "cg_main.c": cgs.media.rocketExplosionShader should be registered if gamemode is GT_OBELISK. ******************************************************************************** BUG: Impact marks sometimes doesn't draw at all. Not easy to reproduce if you don't play (io)Quake3 every day and know the places where it happens! ;) But anyway... Test: start q3dm12 go to "Long Jump Canyon" (where the small platform teleporter for the BFG is) place yourself at the point where the railgun spawns, look in the direction where the red suspended armor is. Now shoot at the sloped wall on the out/leftside of the door you see. (the sloped wall should be nearly in the center of your screen now). If you choose the correct brush face and shoot up and down at this brush face, the impact marks sometimes aren't visible. There are hundreds of custom maps where this can happen! -------------------------------------------------------------------------------- Solution: I replaced the function "SnapVectorTowards" with the one from "Wolfenstein - Enemy Territory (GPL Source Code)" ******************************************************************************** BUG: Normally "NOCLIP" cheaters are logically not allowed to fire a gun. Unfortunatly the Gauntlet (and Lightning gun) was forgotten and not restricted to that. All weapons except those two were handled correct. -------------------------------------------------------------------------------- Solution: Make Gauntlet and Lightning gun not firing for someone who cheats with "NOCLIP" (like all other weapons). ******************************************************************************** NOTE: A few bugfixes are not mine and are reported here: http://www.quake3world.com/forum/viewtopic.php?f=16&t=9179. Thanks to Quake3world, for all those years and the good guys there! ******************************************************************************** BUG: During making a mod I found a very strange bug, which mainly occurs if someone tries to implement a lot of singleplayer monsters which should walk slowly (like the "Crash" bot). So if someone wants to make slow down bots or monsters when they are walking towards a goal and alter the function "BotMoveInGoalArea" then the bots/monsters do stupid things. Otherwise and this is the default (also buggy) behavior they start running although they shouldn't (as seen with the "Crash" bot and will not be fixed here). -------------------------------------------------------------------------------- Solution: Fix overflow in bot user command. BUGFIX from "Hunt" mod by J. Hoffman. ******************************************************************************** BUG: in function "BotMoveToGoal" the special elevator case doesn't make sense. -------------------------------------------------------------------------------- Solution: in "be_ai_move.c": ((result->flags & MOVERESULT_ONTOPOF_FUNCBOB) || (result->flags & MOVERESULT_ONTOPOF_FUNCBOB)) should be ((result->flags & MOVERESULT_ONTOPOF_ELEVATOR) || (result->flags & MOVERESULT_ONTOPOF_FUNCBOB)). ******************************************************************************** BUG: in function "BotWantsToRetreat" and "BotWantsToChase" this is wrong: "(bs->enemy != redobelisk.entitynum || bs->enemy != blueobelisk.entitynum)" -------------------------------------------------------------------------------- Solution: "... redobelisk.entitynum) && (bs->enemy != blueobelisk.." is correct. ******************************************************************************** BUG: in gamemode GT_OBELISK there are too many node switches for bots (test: mpq3tourney6 with many bots). If that happens, game becomes unplayable. I don't know if this is the best solution but here it is: -------------------------------------------------------------------------------- Solution: In function "AINode_Battle_Fight" right after: if (!BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy)) { I added this: #ifdef MISSIONPACK if (bs->enemy == redobelisk.entitynum || bs->enemy == blueobelisk.entitynum) { AIEnter_Battle_Chase(bs, "battle fight: obelisk out of sight"); return qfalse; } #endif ******************************************************************************** BUG: in gamemode >= GT_TEAM, after team change, bots will (sometimes) not stop shooting at you, although you are on their team now. It seems that the configstrings are f***** up or not reliable in this case! -------------------------------------------------------------------------------- Solution: In function "BotTeam" and "BotSameTeam" get the real team values. ******************************************************************************** BUG: Some of the bots voice commands are wrong. They are commanded to attack the enemy base but they say "Okay, I will defend!" -------------------------------------------------------------------------------- Solution: Corrected some voice commands in "BotCTFOrders_FlagNotAtBase" and "Bot1FCTFOrders_EnemyDroppedFlag" ******************************************************************************** BUG: Spectators couldn't fly through doors if they are very close to each other. You can test it with some regular id maps (q3dm14, q3dm12) but there are also many custom maps where this can happen! This is annoying because in the worst case you can't move at all and are caught inside a door. -------------------------------------------------------------------------------- Solution: There is a solution in a mod called "Hunt" by J. Hoffman. Bugfix is included in this patch! ******************************************************************************** BUG: During making a mod I found it very hard to implement some of my ideas (something like "Limbo" or "Meeting") because of the way the player spawn effect, intermission and spawning on victory pads is handled. I reworked it a bit and simplified it so that the effect is handled when a client respawns (as the name says) and not when a client begins. I think this will help more mod makers everytime they want to make changes to spawning of players, bots on victory pads or monsters... and want to avoid spectators with Machineguns which can kill and score... :() NOTE: I also renamed the poorly named function "respawn" to "ClientRespawn". If someone searches the code base for "respawn" it was really hard to find the correct place for what was meant. "respawn" is used so often, that you really get headache ... now with "ClientRespawn" it's easier! IMPORTANT: The whole respawning, moving to intermission point and everything related to that is now done in a more reliable way without changing the default behavior. (How critical the whole spwaning mess was did you see by yourself (ioquake3 rev. 2076). With this patch it's safer. Trust me, I spent hours of fixing silly problems... -------------------------------------------------------------------------------- Solution: Simplified "ClientBegin" and moved the teleport event to "ClientSpawn". ******************************************************************************** BUG: If a player is dying or hurted under water the hurt/dying sounds AND the drowning sounds are played together. This is silly. Moreover it's no good idea to let the server play client sounds! There was a solution in a mod called "Q3A++" by Dan 'Neurobasher' Gomes which fixes the problem. -------------------------------------------------------------------------------- Solution: Created a "CG_WaterLevel" function to play the appropriate sounds. ******************************************************************************** ################################################################################
2011-08-01 11:39:33 +00:00
void ClientRespawn(gentity_t *ent);
2005-08-26 17:39:27 +00:00
void BeginIntermission (void);
void InitBodyQue (void);
void ClientSpawn( gentity_t *ent );
void player_die (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod);
void AddScore( gentity_t *ent, vec3_t origin, int score );
void CalculateRanks( void );
qboolean SpotWouldTelefrag( gentity_t *spot );
//
// g_svcmds.c
//
qboolean ConsoleCommand( void );
void G_ProcessIPBans(void);
qboolean G_FilterPacket (char *from);
//
// g_weapon.c
//
void FireWeapon( gentity_t *ent );
#ifdef MISSIONPACK
void G_StartKamikaze( gentity_t *ent );
#endif
//
// g_cmds.c
//
void DeathmatchScoreboardMessage( gentity_t *ent );
2005-08-26 17:39:27 +00:00
//
// g_main.c
//
void MoveClientToIntermission( gentity_t *ent );
2005-08-26 17:39:27 +00:00
void FindIntermissionPoint( void );
void SetLeader(int team, int client);
void CheckTeamLeader( int team );
void G_RunThink (gentity_t *ent);
void AddTournamentQueue(gclient_t *client);
void QDECL G_LogPrintf( const char *fmt, ... ) __attribute__ ((format (printf, 1, 2)));
2005-08-26 17:39:27 +00:00
void SendScoreboardMessageToAllClients( void );
void QDECL G_Printf( const char *fmt, ... ) __attribute__ ((format (printf, 1, 2)));
2011-07-27 00:02:45 +00:00
void QDECL G_Error( const char *fmt, ... ) __attribute__ ((noreturn, format (printf, 1, 2)));
2005-08-26 17:39:27 +00:00
//
// g_client.c
//
char *ClientConnect( int clientNum, qboolean firstTime, qboolean isBot );
void ClientUserinfoChanged( int clientNum );
void ClientDisconnect( int clientNum );
void ClientBegin( int clientNum );
void ClientCommand( int clientNum );
//
// g_active.c
//
void ClientThink( int clientNum );
void ClientEndFrame( gentity_t *ent );
void G_RunClient( gentity_t *ent );
//
// g_team.c
//
qboolean OnSameTeam( gentity_t *ent1, gentity_t *ent2 );
void Team_CheckDroppedItem( gentity_t *dropped );
qboolean CheckObeliskAttack( gentity_t *obelisk, gentity_t *attacker );
//
// g_mem.c
//
void *G_Alloc( int size );
void G_InitMemory( void );
void Svcmd_GameMem_f( void );
//
// g_session.c
//
void G_ReadSessionData( gclient_t *client );
void G_InitSessionData( gclient_t *client, char *userinfo );
void G_InitWorldSession( void );
void G_WriteSessionData( void );
//
// g_arenas.c
//
void UpdateTournamentInfo( void );
void SpawnModelsOnVictoryPads( void );
void Svcmd_AbortPodium_f( void );
//
// g_bot.c
//
void G_InitBots( qboolean restart );
char *G_GetBotInfoByNumber( int num );
char *G_GetBotInfoByName( const char *name );
void G_CheckBotSpawn( void );
void G_RemoveQueuedBotBegin( int clientNum );
qboolean G_BotConnect( int clientNum, qboolean restart );
void Svcmd_AddBot_f( void );
void Svcmd_BotList_f( void );
void BotInterbreedEndMatch( void );
// ai_main.c
#define MAX_FILEPATH 144
//bot settings
typedef struct bot_settings_s
{
char characterfile[MAX_FILEPATH];
float skill;
} bot_settings_t;
int BotAISetup( int restart );
int BotAIShutdown( int restart );
int BotAILoadMap( int restart );
int BotAISetupClient(int client, struct bot_settings_s *settings, qboolean restart);
int BotAIShutdownClient( int client, qboolean restart );
int BotAIStartFrame( int time );
void BotTestAAS(vec3_t origin);
#include "g_team.h" // teamplay specific stuff
extern level_locals_t level;
extern gentity_t g_entities[MAX_GENTITIES];
#define FOFS(x) ((size_t)&(((gentity_t *)0)->x))
2005-08-26 17:39:27 +00:00
extern vmCvar_t g_gametype;
extern vmCvar_t g_dedicated;
extern vmCvar_t g_cheats;
extern vmCvar_t g_maxclients; // allow this many total, including spectators
extern vmCvar_t g_maxGameClients; // allow this many active
extern vmCvar_t g_restarted;
extern vmCvar_t g_dmflags;
extern vmCvar_t g_fraglimit;
extern vmCvar_t g_timelimit;
extern vmCvar_t g_capturelimit;
extern vmCvar_t g_friendlyFire;
extern vmCvar_t g_password;
extern vmCvar_t g_needpass;
extern vmCvar_t g_gravity;
extern vmCvar_t g_speed;
extern vmCvar_t g_knockback;
extern vmCvar_t g_quadfactor;
extern vmCvar_t g_forcerespawn;
extern vmCvar_t g_inactivity;
extern vmCvar_t g_debugMove;
extern vmCvar_t g_debugAlloc;
extern vmCvar_t g_debugDamage;
extern vmCvar_t g_weaponRespawn;
extern vmCvar_t g_weaponTeamRespawn;
extern vmCvar_t g_synchronousClients;
extern vmCvar_t g_motd;
extern vmCvar_t g_warmup;
extern vmCvar_t g_doWarmup;
extern vmCvar_t g_blood;
extern vmCvar_t g_allowVote;
extern vmCvar_t g_teamAutoJoin;
extern vmCvar_t g_teamForceBalance;
extern vmCvar_t g_banIPs;
extern vmCvar_t g_filterBan;
extern vmCvar_t g_obeliskHealth;
extern vmCvar_t g_obeliskRegenPeriod;
extern vmCvar_t g_obeliskRegenAmount;
extern vmCvar_t g_obeliskRespawnDelay;
extern vmCvar_t g_cubeTimeout;
extern vmCvar_t g_redteam;
extern vmCvar_t g_blueteam;
extern vmCvar_t g_smoothClients;
extern vmCvar_t pmove_fixed;
extern vmCvar_t pmove_msec;
extern vmCvar_t g_rankings;
extern vmCvar_t g_enableDust;
extern vmCvar_t g_enableBreath;
extern vmCvar_t g_singlePlayer;
extern vmCvar_t g_proxMineTimeout;
Fix g_teamAutoJoin and g_teamForceBalance There are various issues caused by not knowing the initial team for the local client and bots when they connect. This is can be reproduced by starting a team game from the main menu. When g_teamAutoJoin is enabled, bots and local client join a random team at connect and then execute their team command a few frames later. This may result in the player being killed if they specify a different team. In Team Arena's Harvester mode this causes harvester skulls to be spawned at the beginning of the game. When g_teamForceBalance is enabled, the local client and bots may not be able to join their desired team. This may result in them being spectators. If g_teamAutoJoin is also enabled they may be left on the opposite (red/blue) team they were meant to join. There is a hack for including bot's team in their player info string (used by cgame for which team skin to use) before the bot joins their desired team. Bots aren't guaranteed to join their desired team (as may happen when both g_teamAutoJoin and g_teamForceBalance are enabled) so clients may see them as being on the wrong team! ---- Add teampref userinfo option for team preference. If teampref is set it will be used for attempting to join the team immediately at connect. Bots now join team at connect using teampref userinfo. So remove the hack for setting bot's team in player info string before the bot joins the team. To avoid the client sending teampref userinfo to all network servers, the local client uses a g_localTeamPref cvar. The g_localTeamPref cvar is cleared after it's used so it doesn't get used when starting another server later. Another reason not to use a teampref userinfo cvar is there isn't a reliable way to clear it in CGame/UI which are likely loaded from baseq3 pk3. Make it so g_teamAutoJoin doesn't affect clients who specify teampref. If teampref is invalid, the client will join a random team like g_teamAutoJoin. Don't apply g_teamForceBalance to the local client or bots. Otherwise they may be left as spectators when starting team game from menu. The start server menus use team command and g_localTeamPref to set the human player's team. This way it's compatible with vanilla Q3 game VMs and the new setting team at connect feature.
2017-06-23 02:56:00 +00:00
extern vmCvar_t g_localTeamPref;
2005-08-26 17:39:27 +00:00
void trap_Print( const char *text );
void trap_Error( const char *text ) __attribute__((noreturn));
2005-08-26 17:39:27 +00:00
int trap_Milliseconds( void );
int trap_RealTime( qtime_t *qtime );
2005-08-26 17:39:27 +00:00
int trap_Argc( void );
void trap_Argv( int n, char *buffer, int bufferLength );
void trap_Args( char *buffer, int bufferLength );
int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode );
void trap_FS_Read( void *buffer, int len, fileHandle_t f );
void trap_FS_Write( const void *buffer, int len, fileHandle_t f );
void trap_FS_FCloseFile( fileHandle_t f );
int trap_FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize );
int trap_FS_Seek( fileHandle_t f, long offset, int origin ); // fsOrigin_t
void trap_SendConsoleCommand( int exec_when, const char *text );
void trap_Cvar_Register( vmCvar_t *cvar, const char *var_name, const char *value, int flags );
void trap_Cvar_Update( vmCvar_t *cvar );
void trap_Cvar_Set( const char *var_name, const char *value );
int trap_Cvar_VariableIntegerValue( const char *var_name );
float trap_Cvar_VariableValue( const char *var_name );
void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );
void trap_LocateGameData( gentity_t *gEnts, int numGEntities, int sizeofGEntity_t, playerState_t *gameClients, int sizeofGameClient );
void trap_DropClient( int clientNum, const char *reason );
void trap_SendServerCommand( int clientNum, const char *text );
void trap_SetConfigstring( int num, const char *string );
void trap_GetConfigstring( int num, char *buffer, int bufferSize );
void trap_GetUserinfo( int num, char *buffer, int bufferSize );
void trap_SetUserinfo( int num, const char *buffer );
void trap_GetServerinfo( char *buffer, int bufferSize );
void trap_SetBrushModel( gentity_t *ent, const char *name );
void trap_Trace( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask );
int trap_PointContents( const vec3_t point, int passEntityNum );
qboolean trap_InPVS( const vec3_t p1, const vec3_t p2 );
qboolean trap_InPVSIgnorePortals( const vec3_t p1, const vec3_t p2 );
void trap_AdjustAreaPortalState( gentity_t *ent, qboolean open );
qboolean trap_AreasConnected( int area1, int area2 );
void trap_LinkEntity( gentity_t *ent );
void trap_UnlinkEntity( gentity_t *ent );
int trap_EntitiesInBox( const vec3_t mins, const vec3_t maxs, int *entityList, int maxcount );
qboolean trap_EntityContact( const vec3_t mins, const vec3_t maxs, const gentity_t *ent );
int trap_BotAllocateClient( void );
void trap_BotFreeClient( int clientNum );
void trap_GetUsercmd( int clientNum, usercmd_t *cmd );
qboolean trap_GetEntityToken( char *buffer, int bufferSize );
int trap_DebugPolygonCreate(int color, int numPoints, vec3_t *points);
void trap_DebugPolygonDelete(int id);
int trap_BotLibSetup( void );
int trap_BotLibShutdown( void );
int trap_BotLibVarSet(char *var_name, char *value);
int trap_BotLibVarGet(char *var_name, char *value, int size);
int trap_BotLibDefine(char *string);
int trap_BotLibStartFrame(float time);
int trap_BotLibLoadMap(const char *mapname);
int trap_BotLibUpdateEntity(int ent, void /* struct bot_updateentity_s */ *bue);
int trap_BotLibTest(int parm0, char *parm1, vec3_t parm2, vec3_t parm3);
int trap_BotGetSnapshotEntity( int clientNum, int sequence );
int trap_BotGetServerCommand(int clientNum, char *message, int size);
void trap_BotUserCommand(int client, usercmd_t *ucmd);
int trap_AAS_BBoxAreas(vec3_t absmins, vec3_t absmaxs, int *areas, int maxareas);
int trap_AAS_AreaInfo( int areanum, void /* struct aas_areainfo_s */ *info );
void trap_AAS_EntityInfo(int entnum, void /* struct aas_entityinfo_s */ *info);
int trap_AAS_Initialized(void);
void trap_AAS_PresenceTypeBoundingBox(int presencetype, vec3_t mins, vec3_t maxs);
float trap_AAS_Time(void);
int trap_AAS_PointAreaNum(vec3_t point);
int trap_AAS_PointReachabilityAreaIndex(vec3_t point);
int trap_AAS_TraceAreas(vec3_t start, vec3_t end, int *areas, vec3_t *points, int maxareas);
int trap_AAS_PointContents(vec3_t point);
int trap_AAS_NextBSPEntity(int ent);
int trap_AAS_ValueForBSPEpairKey(int ent, char *key, char *value, int size);
int trap_AAS_VectorForBSPEpairKey(int ent, char *key, vec3_t v);
int trap_AAS_FloatForBSPEpairKey(int ent, char *key, float *value);
int trap_AAS_IntForBSPEpairKey(int ent, char *key, int *value);
int trap_AAS_AreaReachability(int areanum);
int trap_AAS_AreaTravelTimeToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags);
int trap_AAS_EnableRoutingArea( int areanum, int enable );
int trap_AAS_PredictRoute(void /*struct aas_predictroute_s*/ *route, int areanum, vec3_t origin,
int goalareanum, int travelflags, int maxareas, int maxtime,
int stopevent, int stopcontents, int stoptfl, int stopareanum);
int trap_AAS_AlternativeRouteGoals(vec3_t start, int startareanum, vec3_t goal, int goalareanum, int travelflags,
void /*struct aas_altroutegoal_s*/ *altroutegoals, int maxaltroutegoals,
int type);
int trap_AAS_Swimming(vec3_t origin);
int trap_AAS_PredictClientMovement(void /* aas_clientmove_s */ *move, int entnum, vec3_t origin, int presencetype, int onground, vec3_t velocity, vec3_t cmdmove, int cmdframes, int maxframes, float frametime, int stopevent, int stopareanum, int visualize);
void trap_EA_Say(int client, char *str);
void trap_EA_SayTeam(int client, char *str);
void trap_EA_Command(int client, char *command);
void trap_EA_Action(int client, int action);
void trap_EA_Gesture(int client);
void trap_EA_Talk(int client);
void trap_EA_Attack(int client);
void trap_EA_Use(int client);
void trap_EA_Respawn(int client);
void trap_EA_Crouch(int client);
void trap_EA_MoveUp(int client);
void trap_EA_MoveDown(int client);
void trap_EA_MoveForward(int client);
void trap_EA_MoveBack(int client);
void trap_EA_MoveLeft(int client);
void trap_EA_MoveRight(int client);
void trap_EA_SelectWeapon(int client, int weapon);
void trap_EA_Jump(int client);
void trap_EA_DelayedJump(int client);
void trap_EA_Move(int client, vec3_t dir, float speed);
void trap_EA_View(int client, vec3_t viewangles);
void trap_EA_EndRegular(int client, float thinktime);
void trap_EA_GetInput(int client, float thinktime, void /* struct bot_input_s */ *input);
void trap_EA_ResetInput(int client);
int trap_BotLoadCharacter(char *charfile, float skill);
void trap_BotFreeCharacter(int character);
float trap_Characteristic_Float(int character, int index);
float trap_Characteristic_BFloat(int character, int index, float min, float max);
int trap_Characteristic_Integer(int character, int index);
int trap_Characteristic_BInteger(int character, int index, int min, int max);
void trap_Characteristic_String(int character, int index, char *buf, int size);
int trap_BotAllocChatState(void);
void trap_BotFreeChatState(int handle);
void trap_BotQueueConsoleMessage(int chatstate, int type, char *message);
void trap_BotRemoveConsoleMessage(int chatstate, int handle);
int trap_BotNextConsoleMessage(int chatstate, void /* struct bot_consolemessage_s */ *cm);
int trap_BotNumConsoleMessages(int chatstate);
void trap_BotInitialChat(int chatstate, char *type, int mcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7 );
int trap_BotNumInitialChats(int chatstate, char *type);
int trap_BotReplyChat(int chatstate, char *message, int mcontext, int vcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7 );
int trap_BotChatLength(int chatstate);
void trap_BotEnterChat(int chatstate, int client, int sendto);
void trap_BotGetChatMessage(int chatstate, char *buf, int size);
int trap_StringContains(char *str1, char *str2, int casesensitive);
int trap_BotFindMatch(char *str, void /* struct bot_match_s */ *match, unsigned long int context);
void trap_BotMatchVariable(void /* struct bot_match_s */ *match, int variable, char *buf, int size);
void trap_UnifyWhiteSpaces(char *string);
void trap_BotReplaceSynonyms(char *string, unsigned long int context);
int trap_BotLoadChatFile(int chatstate, char *chatfile, char *chatname);
void trap_BotSetChatGender(int chatstate, int gender);
void trap_BotSetChatName(int chatstate, char *name, int client);
void trap_BotResetGoalState(int goalstate);
void trap_BotRemoveFromAvoidGoals(int goalstate, int number);
void trap_BotResetAvoidGoals(int goalstate);
void trap_BotPushGoal(int goalstate, void /* struct bot_goal_s */ *goal);
void trap_BotPopGoal(int goalstate);
void trap_BotEmptyGoalStack(int goalstate);
void trap_BotDumpAvoidGoals(int goalstate);
void trap_BotDumpGoalStack(int goalstate);
void trap_BotGoalName(int number, char *name, int size);
int trap_BotGetTopGoal(int goalstate, void /* struct bot_goal_s */ *goal);
int trap_BotGetSecondGoal(int goalstate, void /* struct bot_goal_s */ *goal);
int trap_BotChooseLTGItem(int goalstate, vec3_t origin, int *inventory, int travelflags);
int trap_BotChooseNBGItem(int goalstate, vec3_t origin, int *inventory, int travelflags, void /* struct bot_goal_s */ *ltg, float maxtime);
int trap_BotTouchingGoal(vec3_t origin, void /* struct bot_goal_s */ *goal);
int trap_BotItemGoalInVisButNotVisible(int viewer, vec3_t eye, vec3_t viewangles, void /* struct bot_goal_s */ *goal);
int trap_BotGetNextCampSpotGoal(int num, void /* struct bot_goal_s */ *goal);
int trap_BotGetMapLocationGoal(char *name, void /* struct bot_goal_s */ *goal);
int trap_BotGetLevelItemGoal(int index, char *classname, void /* struct bot_goal_s */ *goal);
float trap_BotAvoidGoalTime(int goalstate, int number);
void trap_BotSetAvoidGoalTime(int goalstate, int number, float avoidtime);
void trap_BotInitLevelItems(void);
void trap_BotUpdateEntityItems(void);
int trap_BotLoadItemWeights(int goalstate, char *filename);
void trap_BotFreeItemWeights(int goalstate);
void trap_BotInterbreedGoalFuzzyLogic(int parent1, int parent2, int child);
void trap_BotSaveGoalFuzzyLogic(int goalstate, char *filename);
void trap_BotMutateGoalFuzzyLogic(int goalstate, float range);
int trap_BotAllocGoalState(int state);
void trap_BotFreeGoalState(int handle);
void trap_BotResetMoveState(int movestate);
void trap_BotMoveToGoal(void /* struct bot_moveresult_s */ *result, int movestate, void /* struct bot_goal_s */ *goal, int travelflags);
int trap_BotMoveInDirection(int movestate, vec3_t dir, float speed, int type);
void trap_BotResetAvoidReach(int movestate);
void trap_BotResetLastAvoidReach(int movestate);
int trap_BotReachabilityArea(vec3_t origin, int testground);
int trap_BotMovementViewTarget(int movestate, void /* struct bot_goal_s */ *goal, int travelflags, float lookahead, vec3_t target);
int trap_BotPredictVisiblePosition(vec3_t origin, int areanum, void /* struct bot_goal_s */ *goal, int travelflags, vec3_t target);
int trap_BotAllocMoveState(void);
void trap_BotFreeMoveState(int handle);
void trap_BotInitMoveState(int handle, void /* struct bot_initmove_s */ *initmove);
void trap_BotAddAvoidSpot(int movestate, vec3_t origin, float radius, int type);
int trap_BotChooseBestFightWeapon(int weaponstate, int *inventory);
void trap_BotGetWeaponInfo(int weaponstate, int weapon, void /* struct weaponinfo_s */ *weaponinfo);
int trap_BotLoadWeaponWeights(int weaponstate, char *filename);
int trap_BotAllocWeaponState(void);
void trap_BotFreeWeaponState(int weaponstate);
void trap_BotResetWeaponState(int weaponstate);
int trap_GeneticParentsAndChildSelection(int numranks, float *ranks, int *parent1, int *parent2, int *child);
void trap_SnapVector( float *v );