The Quake III Arena sources as originally released under the GPL license on August 20, 2005.

This commit is contained in:
Travis Bradshaw 2012-01-31 13:41:34 -06:00
commit dbe4ddb103
1409 changed files with 806066 additions and 0 deletions

140
code/game/Conscript Normal file
View file

@ -0,0 +1,140 @@
# game building
# builds the game for vanilla Q3 and TA
# there are slight differences between Q3 and TA build:
# -DMISSIONPACK
# the config is passed in the imported variable TARGET_DIR
# qvm building against native:
# only native has g_syscalls.c
# only qvm has ../game/bg_lib.c
# qvm uses a custom g_syscalls.asm with equ stubs
Import qw( BASE_CFLAGS TARGET_DIR INSTALL_DIR NO_VM NO_SO CC CXX LINK );
$env = new cons(
# the code has the very bad habit of doing things like #include "../ui/ui_shared.h"
# this seems to confuse the dependency analysis, explicit toplevel includes seem to fix
CPPPATH => '#cgame:#game:#q3_ui',
CC => $CC,
CXX => $CXX,
LINK => $LINK,
ENV => { PATH => $ENV{PATH}, HOME => $ENV{HOME} },
CFLAGS => $BASE_CFLAGS . '-fPIC',
LDFLAGS => '-shared -ldl -lm'
);
# for TA, use -DMISSIONPACK
%ta_env_hash = $env->copy(
CPPPATH => '#cgame:#game:#ui'
);
$ta_env_hash{CFLAGS} = '-DMISSIONPACK ' . $ta_env_hash{CFLAGS};
$ta_env = new cons(%ta_env_hash);
# qvm building
# we heavily customize the cons environment
$vm_env = new cons(
# the code has the very bad habit of doing things like #include "../ui/ui_shared.h"
# this seems to confuse the dependency analysis, explicit toplevel includes seem to fix
CPPPATH => '#cgame:#game:#q3_ui',
CC => 'q3lcc',
CCCOM => '%CC %CFLAGS %_IFLAGS -c %< -o %>',
SUFOBJ => '.asm',
LINK => 'q3asm',
CFLAGS => '-DQ3_VM -S -Wf-target=bytecode -Wf-g',
# need to know where to find the compiler tools
ENV => { PATH => $ENV{PATH} . ":./qvmtools", },
);
# TA qvm building
%vm_ta_env_hash = $vm_env->copy(
CPPPATH => '#cgame:#game:#ui'
);
$vm_ta_env_hash{CFLAGS} = '-DMISSIONPACK ' . $vm_ta_env_hash{CFLAGS};
$vm_ta_env = new cons(%vm_ta_env_hash);
# the file with vmMain function MUST be the first one of the list
@FILES = qw(
g_main.c
ai_chat.c
ai_cmd.c
ai_dmnet.c
ai_dmq3.c
ai_main.c
ai_team.c
ai_vcmd.c
bg_misc.c
bg_pmove.c
bg_slidemove.c
g_active.c
g_arenas.c
g_bot.c
g_client.c
g_cmds.c
g_combat.c
g_items.c
g_mem.c
g_misc.c
g_missile.c
g_mover.c
g_session.c
g_spawn.c
g_svcmds.c
g_target.c
g_team.c
g_trigger.c
g_utils.c
g_weapon.c
q_math.c
q_shared.c
);
$FILESREF = \@FILES;
# only in .so
# (VM uses a custom .asm with equ stubs)
@SO_FILES = qw(
g_syscalls.c
);
$SO_FILESREF = \@SO_FILES;
# only for VM
@VM_FILES = qw(
bg_lib.c
g_syscalls.asm
);
$VM_FILESREF = \@VM_FILES;
# FIXME CPU string?
# NOTE: $env $ta_env and $vm_env $vm_ta_env may not be necessary
# we could alter the $env and $ta_env based on $TARGET_DIR
# doing it this way to ensure homogeneity with cgame building
if ($TARGET_DIR eq 'Q3')
{
if ($NO_SO eq 0)
{
Program $env 'qagamei386.so', @$FILESREF, @$SO_FILESREF;
Install $env $INSTALL_DIR, 'qagamei386.so';
}
if ($NO_VM eq 0)
{
Depends $vm_env 'qagame.qvm', '#qvmtools/q3lcc';
Depends $vm_env 'qagame.qvm', '#qvmtools/q3asm';
Program $vm_env 'qagame.qvm', @$FILESREF, @$VM_FILESREF;
Install $vm_env $INSTALL_DIR . '/vm', 'qagame.qvm';
}
}
else
{
if ($NO_SO eq 0)
{
Program $ta_env 'qagamei386.so', @$FILESREF, @$SO_FILESREF;
Install $ta_env $INSTALL_DIR, 'qagamei386.so';
}
if ($NO_VM eq 0)
{
Depends $vm_env 'qagame.qvm', '#qvmtools/q3lcc';
Depends $vm_env 'qagame.qvm', '#qvmtools/q3asm';
Program $vm_ta_env 'qagame.qvm', @$FILESREF, @$VM_FILESREF;
Install $vm_ta_env $INSTALL_DIR . '/vm', 'qagame.qvm';
}
}

1226
code/game/ai_chat.c Normal file

File diff suppressed because it is too large Load diff

61
code/game/ai_chat.h Normal file
View file

@ -0,0 +1,61 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
/*****************************************************************************
* name: ai_chat.h
*
* desc: Quake3 bot AI
*
* $Archive: /source/code/botai/ai_chat.c $
*
*****************************************************************************/
//
int BotChat_EnterGame(bot_state_t *bs);
//
int BotChat_ExitGame(bot_state_t *bs);
//
int BotChat_StartLevel(bot_state_t *bs);
//
int BotChat_EndLevel(bot_state_t *bs);
//
int BotChat_HitTalking(bot_state_t *bs);
//
int BotChat_HitNoDeath(bot_state_t *bs);
//
int BotChat_HitNoKill(bot_state_t *bs);
//
int BotChat_Death(bot_state_t *bs);
//
int BotChat_Kill(bot_state_t *bs);
//
int BotChat_EnemySuicide(bot_state_t *bs);
//
int BotChat_Random(bot_state_t *bs);
// time the selected chat takes to type in
float BotChatTime(bot_state_t *bs);
// returns true if the bot can chat at the current position
int BotValidChatPosition(bot_state_t *bs);
// test the initial bot chats
void BotChatTest(bot_state_t *bs);

1992
code/game/ai_cmd.c Normal file

File diff suppressed because it is too large Load diff

37
code/game/ai_cmd.h Normal file
View file

@ -0,0 +1,37 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
/*****************************************************************************
* name: ai_cmd.h
*
* desc: Quake3 bot AI
*
* $Archive: /source/code/botai/ai_chat.c $
*
*****************************************************************************/
extern int notleader[MAX_CLIENTS];
int BotMatchMessage(bot_state_t *bs, char *message);
void BotPrintTeamGoal(bot_state_t *bs);

2610
code/game/ai_dmnet.c Normal file

File diff suppressed because it is too large Load diff

61
code/game/ai_dmnet.h Normal file
View file

@ -0,0 +1,61 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
/*****************************************************************************
* name: ai_dmnet.h
*
* desc: Quake3 bot AI
*
* $Archive: /source/code/botai/ai_chat.c $
*
*****************************************************************************/
#define MAX_NODESWITCHES 50
void AIEnter_Intermission(bot_state_t *bs, char *s);
void AIEnter_Observer(bot_state_t *bs, char *s);
void AIEnter_Respawn(bot_state_t *bs, char *s);
void AIEnter_Stand(bot_state_t *bs, char *s);
void AIEnter_Seek_ActivateEntity(bot_state_t *bs, char *s);
void AIEnter_Seek_NBG(bot_state_t *bs, char *s);
void AIEnter_Seek_LTG(bot_state_t *bs, char *s);
void AIEnter_Seek_Camp(bot_state_t *bs, char *s);
void AIEnter_Battle_Fight(bot_state_t *bs, char *s);
void AIEnter_Battle_Chase(bot_state_t *bs, char *s);
void AIEnter_Battle_Retreat(bot_state_t *bs, char *s);
void AIEnter_Battle_NBG(bot_state_t *bs, char *s);
int AINode_Intermission(bot_state_t *bs);
int AINode_Observer(bot_state_t *bs);
int AINode_Respawn(bot_state_t *bs);
int AINode_Stand(bot_state_t *bs);
int AINode_Seek_ActivateEntity(bot_state_t *bs);
int AINode_Seek_NBG(bot_state_t *bs);
int AINode_Seek_LTG(bot_state_t *bs);
int AINode_Battle_Fight(bot_state_t *bs);
int AINode_Battle_Chase(bot_state_t *bs);
int AINode_Battle_Retreat(bot_state_t *bs);
int AINode_Battle_NBG(bot_state_t *bs);
void BotResetNodeSwitches(void);
void BotDumpNodeSwitches(bot_state_t *bs);

5461
code/game/ai_dmq3.c Normal file

File diff suppressed because it is too large Load diff

206
code/game/ai_dmq3.h Normal file
View file

@ -0,0 +1,206 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
/*****************************************************************************
* name: ai_dmq3.h
*
* desc: Quake3 bot AI
*
* $Archive: /source/code/botai/ai_chat.c $
*
*****************************************************************************/
//setup the deathmatch AI
void BotSetupDeathmatchAI(void);
//shutdown the deathmatch AI
void BotShutdownDeathmatchAI(void);
//let the bot live within it's deathmatch AI net
void BotDeathmatchAI(bot_state_t *bs, float thinktime);
//free waypoints
void BotFreeWaypoints(bot_waypoint_t *wp);
//choose a weapon
void BotChooseWeapon(bot_state_t *bs);
//setup movement stuff
void BotSetupForMovement(bot_state_t *bs);
//update the inventory
void BotUpdateInventory(bot_state_t *bs);
//update the inventory during battle
void BotUpdateBattleInventory(bot_state_t *bs, int enemy);
//use holdable items during battle
void BotBattleUseItems(bot_state_t *bs);
//return true if the bot is dead
qboolean BotIsDead(bot_state_t *bs);
//returns true if the bot is in observer mode
qboolean BotIsObserver(bot_state_t *bs);
//returns true if the bot is in the intermission
qboolean BotIntermission(bot_state_t *bs);
//returns true if the bot is in lava or slime
qboolean BotInLavaOrSlime(bot_state_t *bs);
//returns true if the entity is dead
qboolean EntityIsDead(aas_entityinfo_t *entinfo);
//returns true if the entity is invisible
qboolean EntityIsInvisible(aas_entityinfo_t *entinfo);
//returns true if the entity is shooting
qboolean EntityIsShooting(aas_entityinfo_t *entinfo);
#ifdef MISSIONPACK
//returns true if this entity has the kamikaze
qboolean EntityHasKamikaze(aas_entityinfo_t *entinfo);
#endif
// set a user info key/value pair
void BotSetUserInfo(bot_state_t *bs, char *key, char *value);
// set the team status (offense, defense etc.)
void BotSetTeamStatus(bot_state_t *bs);
//returns the name of the client
char *ClientName(int client, char *name, int size);
//returns an simplyfied client name
char *EasyClientName(int client, char *name, int size);
//returns the skin used by the client
char *ClientSkin(int client, char *skin, int size);
// returns the appropriate synonym context for the current game type and situation
int BotSynonymContext(bot_state_t *bs);
// set last ordered task
int BotSetLastOrderedTask(bot_state_t *bs);
// selection of goals for teamplay
void BotTeamGoals(bot_state_t *bs, int retreat);
//returns the aggression of the bot in the range [0, 100]
float BotAggression(bot_state_t *bs);
//returns how bad the bot feels
float BotFeelingBad(bot_state_t *bs);
//returns true if the bot wants to retreat
int BotWantsToRetreat(bot_state_t *bs);
//returns true if the bot wants to chase
int BotWantsToChase(bot_state_t *bs);
//returns true if the bot wants to help
int BotWantsToHelp(bot_state_t *bs);
//returns true if the bot can and wants to rocketjump
int BotCanAndWantsToRocketJump(bot_state_t *bs);
// returns true if the bot has a persistant powerup and a weapon
int BotHasPersistantPowerupAndWeapon(bot_state_t *bs);
//returns true if the bot wants to and goes camping
int BotWantsToCamp(bot_state_t *bs);
//the bot will perform attack movements
bot_moveresult_t BotAttackMove(bot_state_t *bs, int tfl);
//returns true if the bot and the entity are in the same team
int BotSameTeam(bot_state_t *bs, int entnum);
//returns true if teamplay is on
int TeamPlayIsOn(void);
// returns the client number of the team mate flag carrier (-1 if none)
int BotTeamFlagCarrier(bot_state_t *bs);
//returns visible team mate flag carrier if available
int BotTeamFlagCarrierVisible(bot_state_t *bs);
//returns visible enemy flag carrier if available
int BotEnemyFlagCarrierVisible(bot_state_t *bs);
//get the number of visible teammates and enemies
void BotVisibleTeamMatesAndEnemies(bot_state_t *bs, int *teammates, int *enemies, float range);
//returns true if within the field of vision for the given angles
qboolean InFieldOfVision(vec3_t viewangles, float fov, vec3_t angles);
//returns true and sets the .enemy field when an enemy is found
int BotFindEnemy(bot_state_t *bs, int curenemy);
//returns a roam goal
void BotRoamGoal(bot_state_t *bs, vec3_t goal);
//returns entity visibility in the range [0, 1]
float BotEntityVisible(int viewer, vec3_t eye, vec3_t viewangles, float fov, int ent);
//the bot will aim at the current enemy
void BotAimAtEnemy(bot_state_t *bs);
//check if the bot should attack
void BotCheckAttack(bot_state_t *bs);
//AI when the bot is blocked
void BotAIBlocked(bot_state_t *bs, bot_moveresult_t *moveresult, int activate);
//AI to predict obstacles
int BotAIPredictObstacles(bot_state_t *bs, bot_goal_t *goal);
//enable or disable the areas the blocking entity is in
void BotEnableActivateGoalAreas(bot_activategoal_t *activategoal, int enable);
//pop an activate goal from the stack
int BotPopFromActivateGoalStack(bot_state_t *bs);
//clear the activate goal stack
void BotClearActivateGoalStack(bot_state_t *bs);
//returns the team the bot is in
int BotTeam(bot_state_t *bs);
//retuns the opposite team of the bot
int BotOppositeTeam(bot_state_t *bs);
//returns the flag the bot is carrying (CTFFLAG_?)
int BotCTFCarryingFlag(bot_state_t *bs);
//remember the last ordered task
void BotRememberLastOrderedTask(bot_state_t *bs);
//set ctf goals (defend base, get enemy flag) during seek
void BotCTFSeekGoals(bot_state_t *bs);
//set ctf goals (defend base, get enemy flag) during retreat
void BotCTFRetreatGoals(bot_state_t *bs);
//
#ifdef MISSIONPACK
int Bot1FCTFCarryingFlag(bot_state_t *bs);
int BotHarvesterCarryingCubes(bot_state_t *bs);
void Bot1FCTFSeekGoals(bot_state_t *bs);
void Bot1FCTFRetreatGoals(bot_state_t *bs);
void BotObeliskSeekGoals(bot_state_t *bs);
void BotObeliskRetreatGoals(bot_state_t *bs);
void BotGoHarvest(bot_state_t *bs);
void BotHarvesterSeekGoals(bot_state_t *bs);
void BotHarvesterRetreatGoals(bot_state_t *bs);
int BotTeamCubeCarrierVisible(bot_state_t *bs);
int BotEnemyCubeCarrierVisible(bot_state_t *bs);
#endif
//get a random alternate route goal towards the given base
int BotGetAlternateRouteGoal(bot_state_t *bs, int base);
//returns either the alternate route goal or the given goal
bot_goal_t *BotAlternateRoute(bot_state_t *bs, bot_goal_t *goal);
//create a new waypoint
bot_waypoint_t *BotCreateWayPoint(char *name, vec3_t origin, int areanum);
//find a waypoint with the given name
bot_waypoint_t *BotFindWayPoint(bot_waypoint_t *waypoints, char *name);
//strstr but case insensitive
char *stristr(char *str, char *charset);
//returns the number of the client with the given name
int ClientFromName(char *name);
int ClientOnSameTeamFromName(bot_state_t *bs, char *name);
//
int BotPointAreaNum(vec3_t origin);
//
void BotMapScripts(bot_state_t *bs);
//ctf flags
#define CTF_FLAG_NONE 0
#define CTF_FLAG_RED 1
#define CTF_FLAG_BLUE 2
//CTF skins
#define CTF_SKIN_REDTEAM "red"
#define CTF_SKIN_BLUETEAM "blue"
extern int gametype; //game type
extern int maxclients; //maximum number of clients
extern vmCvar_t bot_grapple;
extern vmCvar_t bot_rocketjump;
extern vmCvar_t bot_fastchat;
extern vmCvar_t bot_nochat;
extern vmCvar_t bot_testrchat;
extern vmCvar_t bot_challenge;
extern bot_goal_t ctf_redflag;
extern bot_goal_t ctf_blueflag;
#ifdef MISSIONPACK
extern bot_goal_t ctf_neutralflag;
extern bot_goal_t redobelisk;
extern bot_goal_t blueobelisk;
extern bot_goal_t neutralobelisk;
#endif

1695
code/game/ai_main.c Normal file

File diff suppressed because it is too large Load diff

299
code/game/ai_main.h Normal file
View file

@ -0,0 +1,299 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
/*****************************************************************************
* name: ai_main.h
*
* desc: Quake3 bot AI
*
* $Archive: /source/code/botai/ai_chat.c $
*
*****************************************************************************/
//#define DEBUG
#define CTF
#define MAX_ITEMS 256
//bot flags
#define BFL_STRAFERIGHT 1 //strafe to the right
#define BFL_ATTACKED 2 //bot has attacked last ai frame
#define BFL_ATTACKJUMPED 4 //bot jumped during attack last frame
#define BFL_AIMATENEMY 8 //bot aimed at the enemy this frame
#define BFL_AVOIDRIGHT 16 //avoid obstacles by going to the right
#define BFL_IDEALVIEWSET 32 //bot has ideal view angles set
#define BFL_FIGHTSUICIDAL 64 //bot is in a suicidal fight
//long term goal types
#define LTG_TEAMHELP 1 //help a team mate
#define LTG_TEAMACCOMPANY 2 //accompany a team mate
#define LTG_DEFENDKEYAREA 3 //defend a key area
#define LTG_GETFLAG 4 //get the enemy flag
#define LTG_RUSHBASE 5 //rush to the base
#define LTG_RETURNFLAG 6 //return the flag
#define LTG_CAMP 7 //camp somewhere
#define LTG_CAMPORDER 8 //ordered to camp somewhere
#define LTG_PATROL 9 //patrol
#define LTG_GETITEM 10 //get an item
#define LTG_KILL 11 //kill someone
#define LTG_HARVEST 12 //harvest skulls
#define LTG_ATTACKENEMYBASE 13 //attack the enemy base
#define LTG_MAKELOVE_UNDER 14
#define LTG_MAKELOVE_ONTOP 15
//some goal dedication times
#define TEAM_HELP_TIME 60 //1 minute teamplay help time
#define TEAM_ACCOMPANY_TIME 600 //10 minutes teamplay accompany time
#define TEAM_DEFENDKEYAREA_TIME 600 //10 minutes ctf defend base time
#define TEAM_CAMP_TIME 600 //10 minutes camping time
#define TEAM_PATROL_TIME 600 //10 minutes patrolling time
#define TEAM_LEAD_TIME 600 //10 minutes taking the lead
#define TEAM_GETITEM_TIME 60 //1 minute
#define TEAM_KILL_SOMEONE 180 //3 minute to kill someone
#define TEAM_ATTACKENEMYBASE_TIME 600 //10 minutes
#define TEAM_HARVEST_TIME 120 //2 minutes
#define CTF_GETFLAG_TIME 600 //10 minutes ctf get flag time
#define CTF_RUSHBASE_TIME 120 //2 minutes ctf rush base time
#define CTF_RETURNFLAG_TIME 180 //3 minutes to return the flag
#define CTF_ROAM_TIME 60 //1 minute ctf roam time
//patrol flags
#define PATROL_LOOP 1
#define PATROL_REVERSE 2
#define PATROL_BACK 4
//teamplay task preference
#define TEAMTP_DEFENDER 1
#define TEAMTP_ATTACKER 2
//CTF strategy
#define CTFS_AGRESSIVE 1
//copied from the aas file header
#define PRESENCE_NONE 1
#define PRESENCE_NORMAL 2
#define PRESENCE_CROUCH 4
//
#define MAX_PROXMINES 64
//check points
typedef struct bot_waypoint_s
{
int inuse;
char name[32];
bot_goal_t goal;
struct bot_waypoint_s *next, *prev;
} bot_waypoint_t;
#define MAX_ACTIVATESTACK 8
#define MAX_ACTIVATEAREAS 32
typedef struct bot_activategoal_s
{
int inuse;
bot_goal_t goal; //goal to activate (buttons etc.)
float time; //time to activate something
float start_time; //time starting to activate something
float justused_time; //time the goal was used
int shoot; //true if bot has to shoot to activate
int weapon; //weapon to be used for activation
vec3_t target; //target to shoot at to activate something
vec3_t origin; //origin of the blocking entity to activate
int areas[MAX_ACTIVATEAREAS]; //routing areas disabled by blocking entity
int numareas; //number of disabled routing areas
int areasdisabled; //true if the areas are disabled for the routing
struct bot_activategoal_s *next; //next activate goal on stack
} bot_activategoal_t;
//bot state
typedef struct bot_state_s
{
int inuse; //true if this state is used by a bot client
int botthink_residual; //residual for the bot thinks
int client; //client number of the bot
int entitynum; //entity number of the bot
playerState_t cur_ps; //current player state
int last_eFlags; //last ps flags
usercmd_t lastucmd; //usercmd from last frame
int entityeventTime[1024]; //last entity event time
//
bot_settings_t settings; //several bot settings
int (*ainode)(struct bot_state_s *bs); //current AI node
float thinktime; //time the bot thinks this frame
vec3_t origin; //origin of the bot
vec3_t velocity; //velocity of the bot
int presencetype; //presence type of the bot
vec3_t eye; //eye coordinates of the bot
int areanum; //the number of the area the bot is in
int inventory[MAX_ITEMS]; //string with items amounts the bot has
int tfl; //the travel flags the bot uses
int flags; //several flags
int respawn_wait; //wait until respawned
int lasthealth; //health value previous frame
int lastkilledplayer; //last killed player
int lastkilledby; //player that last killed this bot
int botdeathtype; //the death type of the bot
int enemydeathtype; //the death type of the enemy
int botsuicide; //true when the bot suicides
int enemysuicide; //true when the enemy of the bot suicides
int setupcount; //true when the bot has just been setup
int map_restart; //true when the map is being restarted
int entergamechat; //true when the bot used an enter game chat
int num_deaths; //number of time this bot died
int num_kills; //number of kills of this bot
int revenge_enemy; //the revenge enemy
int revenge_kills; //number of kills the enemy made
int lastframe_health; //health value the last frame
int lasthitcount; //number of hits last frame
int chatto; //chat to all or team
float walker; //walker charactertic
float ltime; //local bot time
float entergame_time; //time the bot entered the game
float ltg_time; //long term goal time
float nbg_time; //nearby goal time
float respawn_time; //time the bot takes to respawn
float respawnchat_time; //time the bot started a chat during respawn
float chase_time; //time the bot will chase the enemy
float enemyvisible_time; //time the enemy was last visible
float check_time; //time to check for nearby items
float stand_time; //time the bot is standing still
float lastchat_time; //time the bot last selected a chat
float kamikaze_time; //time to check for kamikaze usage
float invulnerability_time; //time to check for invulnerability usage
float standfindenemy_time; //time to find enemy while standing
float attackstrafe_time; //time the bot is strafing in one dir
float attackcrouch_time; //time the bot will stop crouching
float attackchase_time; //time the bot chases during actual attack
float attackjump_time; //time the bot jumped during attack
float enemysight_time; //time before reacting to enemy
float enemydeath_time; //time the enemy died
float enemyposition_time; //time the position and velocity of the enemy were stored
float defendaway_time; //time away while defending
float defendaway_range; //max travel time away from defend area
float rushbaseaway_time; //time away from rushing to the base
float attackaway_time; //time away from attacking the enemy base
float harvestaway_time; //time away from harvesting
float ctfroam_time; //time the bot is roaming in ctf
float killedenemy_time; //time the bot killed the enemy
float arrive_time; //time arrived (at companion)
float lastair_time; //last time the bot had air
float teleport_time; //last time the bot teleported
float camp_time; //last time camped
float camp_range; //camp range
float weaponchange_time; //time the bot started changing weapons
float firethrottlewait_time; //amount of time to wait
float firethrottleshoot_time; //amount of time to shoot
float notblocked_time; //last time the bot was not blocked
float blockedbyavoidspot_time; //time blocked by an avoid spot
float predictobstacles_time; //last time the bot predicted obstacles
int predictobstacles_goalareanum; //last goal areanum the bot predicted obstacles for
vec3_t aimtarget;
vec3_t enemyvelocity; //enemy velocity 0.5 secs ago during battle
vec3_t enemyorigin; //enemy origin 0.5 secs ago during battle
//
int kamikazebody; //kamikaze body
int proxmines[MAX_PROXMINES];
int numproxmines;
//
int character; //the bot character
int ms; //move state of the bot
int gs; //goal state of the bot
int cs; //chat state of the bot
int ws; //weapon state of the bot
//
int enemy; //enemy entity number
int lastenemyareanum; //last reachability area the enemy was in
vec3_t lastenemyorigin; //last origin of the enemy in the reachability area
int weaponnum; //current weapon number
vec3_t viewangles; //current view angles
vec3_t ideal_viewangles; //ideal view angles
vec3_t viewanglespeed;
//
int ltgtype; //long term goal type
// team goals
int teammate; //team mate involved in this team goal
int decisionmaker; //player who decided to go for this goal
int ordered; //true if ordered to do something
float order_time; //time ordered to do something
int owndecision_time; //time the bot made it's own decision
bot_goal_t teamgoal; //the team goal
bot_goal_t altroutegoal; //alternative route goal
float reachedaltroutegoal_time; //time the bot reached the alt route goal
float teammessage_time; //time to message team mates what the bot is doing
float teamgoal_time; //time to stop helping team mate
float teammatevisible_time; //last time the team mate was NOT visible
int teamtaskpreference; //team task preference
// last ordered team goal
int lastgoal_decisionmaker;
int lastgoal_ltgtype;
int lastgoal_teammate;
bot_goal_t lastgoal_teamgoal;
// for leading team mates
int lead_teammate; //team mate the bot is leading
bot_goal_t lead_teamgoal; //team goal while leading
float lead_time; //time leading someone
float leadvisible_time; //last time the team mate was visible
float leadmessage_time; //last time a messaged was sent to the team mate
float leadbackup_time; //time backing up towards team mate
//
char teamleader[32]; //netname of the team leader
float askteamleader_time; //time asked for team leader
float becometeamleader_time; //time the bot will become the team leader
float teamgiveorders_time; //time to give team orders
float lastflagcapture_time; //last time a flag was captured
int numteammates; //number of team mates
int redflagstatus; //0 = at base, 1 = not at base
int blueflagstatus; //0 = at base, 1 = not at base
int neutralflagstatus; //0 = at base, 1 = our team has flag, 2 = enemy team has flag, 3 = enemy team dropped the flag
int flagstatuschanged; //flag status changed
int forceorders; //true if forced to give orders
int flagcarrier; //team mate carrying the enemy flag
int ctfstrategy; //ctf strategy
char subteam[32]; //sub team name
float formation_dist; //formation team mate intervening space
char formation_teammate[16]; //netname of the team mate the bot uses for relative positioning
float formation_angle; //angle relative to the formation team mate
vec3_t formation_dir; //the direction the formation is moving in
vec3_t formation_origin; //origin the bot uses for relative positioning
bot_goal_t formation_goal; //formation goal
bot_activategoal_t *activatestack; //first activate goal on the stack
bot_activategoal_t activategoalheap[MAX_ACTIVATESTACK]; //activate goal heap
bot_waypoint_t *checkpoints; //check points
bot_waypoint_t *patrolpoints; //patrol points
bot_waypoint_t *curpatrolpoint; //current patrol point the bot is going for
int patrolflags; //patrol flags
} bot_state_t;
//resets the whole bot state
void BotResetState(bot_state_t *bs);
//returns the number of bots in the game
int NumBots(void);
//returns info about the entity
void BotEntityInfo(int entnum, aas_entityinfo_t *info);
extern float floattime;
#define FloatTime() floattime
// from the game source
void QDECL BotAI_Print(int type, char *fmt, ...);
void QDECL QDECL BotAI_BotInitialChat( bot_state_t *bs, char *type, ... );
void BotAI_Trace(bsp_trace_t *bsptrace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask);
int BotAI_GetClientState( int clientNum, playerState_t *state );
int BotAI_GetEntityState( int entityNum, entityState_t *state );
int BotAI_GetSnapshotEntity( int clientNum, int sequence, entityState_t *state );
int BotTeamLeader(bot_state_t *bs);

2080
code/game/ai_team.c Normal file

File diff suppressed because it is too large Load diff

39
code/game/ai_team.h Normal file
View file

@ -0,0 +1,39 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
/*****************************************************************************
* name: ai_team.h
*
* desc: Quake3 bot AI
*
* $Archive: /source/code/botai/ai_chat.c $
*
*****************************************************************************/
void BotTeamAI(bot_state_t *bs);
int BotGetTeamMateTaskPreference(bot_state_t *bs, int teammate);
void BotSetTeamMateTaskPreference(bot_state_t *bs, int teammate, int preference);
void BotVoiceChat(bot_state_t *bs, int toclient, char *voicechat);
void BotVoiceChatOnly(bot_state_t *bs, int toclient, char *voicechat);

550
code/game/ai_vcmd.c Normal file
View file

@ -0,0 +1,550 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
/*****************************************************************************
* name: ai_vcmd.c
*
* desc: Quake3 bot AI
*
* $Archive: /MissionPack/code/game/ai_vcmd.c $
*
*****************************************************************************/
#include "g_local.h"
#include "botlib.h"
#include "be_aas.h"
#include "be_ea.h"
#include "be_ai_char.h"
#include "be_ai_chat.h"
#include "be_ai_gen.h"
#include "be_ai_goal.h"
#include "be_ai_move.h"
#include "be_ai_weap.h"
//
#include "ai_main.h"
#include "ai_dmq3.h"
#include "ai_chat.h"
#include "ai_cmd.h"
#include "ai_dmnet.h"
#include "ai_team.h"
#include "ai_vcmd.h"
//
#include "chars.h" //characteristics
#include "inv.h" //indexes into the inventory
#include "syn.h" //synonyms
#include "match.h" //string matching types and vars
// for the voice chats
#include "../../ui/menudef.h"
typedef struct voiceCommand_s
{
char *cmd;
void (*func)(bot_state_t *bs, int client, int mode);
} voiceCommand_t;
/*
==================
BotVoiceChat_GetFlag
==================
*/
void BotVoiceChat_GetFlag(bot_state_t *bs, int client, int mode) {
//
if (gametype == GT_CTF) {
if (!ctf_redflag.areanum || !ctf_blueflag.areanum)
return;
}
#ifdef MISSIONPACK
else if (gametype == GT_1FCTF) {
if (!ctf_neutralflag.areanum || !ctf_redflag.areanum || !ctf_blueflag.areanum)
return;
}
#endif
else {
return;
}
//
bs->decisionmaker = client;
bs->ordered = qtrue;
bs->order_time = FloatTime();
//set the time to send a message to the team mates
bs->teammessage_time = FloatTime() + 2 * random();
//set the ltg type
bs->ltgtype = LTG_GETFLAG;
//set the team goal time
bs->teamgoal_time = FloatTime() + CTF_GETFLAG_TIME;
// get an alternate route in ctf
if (gametype == GT_CTF) {
//get an alternative route goal towards the enemy base
BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
}
//
BotSetTeamStatus(bs);
// remember last ordered task
BotRememberLastOrderedTask(bs);
#ifdef DEBUG
BotPrintTeamGoal(bs);
#endif //DEBUG
}
/*
==================
BotVoiceChat_Offense
==================
*/
void BotVoiceChat_Offense(bot_state_t *bs, int client, int mode) {
if ( gametype == GT_CTF
#ifdef MISSIONPACK
|| gametype == GT_1FCTF
#endif
) {
BotVoiceChat_GetFlag(bs, client, mode);
return;
}
#ifdef MISSIONPACK
if (gametype == GT_HARVESTER) {
//
bs->decisionmaker = client;
bs->ordered = qtrue;
bs->order_time = FloatTime();
//set the time to send a message to the team mates
bs->teammessage_time = FloatTime() + 2 * random();
//set the ltg type
bs->ltgtype = LTG_HARVEST;
//set the team goal time
bs->teamgoal_time = FloatTime() + TEAM_HARVEST_TIME;
bs->harvestaway_time = 0;
//
BotSetTeamStatus(bs);
// remember last ordered task
BotRememberLastOrderedTask(bs);
}
else
#endif
{
//
bs->decisionmaker = client;
bs->ordered = qtrue;
bs->order_time = FloatTime();
//set the time to send a message to the team mates
bs->teammessage_time = FloatTime() + 2 * random();
//set the ltg type
bs->ltgtype = LTG_ATTACKENEMYBASE;
//set the team goal time
bs->teamgoal_time = FloatTime() + TEAM_ATTACKENEMYBASE_TIME;
bs->attackaway_time = 0;
//
BotSetTeamStatus(bs);
// remember last ordered task
BotRememberLastOrderedTask(bs);
}
#ifdef DEBUG
BotPrintTeamGoal(bs);
#endif //DEBUG
}
/*
==================
BotVoiceChat_Defend
==================
*/
void BotVoiceChat_Defend(bot_state_t *bs, int client, int mode) {
#ifdef MISSIONPACK
if ( gametype == GT_OBELISK || gametype == GT_HARVESTER) {
//
switch(BotTeam(bs)) {
case TEAM_RED: memcpy(&bs->teamgoal, &redobelisk, sizeof(bot_goal_t)); break;
case TEAM_BLUE: memcpy(&bs->teamgoal, &blueobelisk, sizeof(bot_goal_t)); break;
default: return;
}
}
else
#endif
if (gametype == GT_CTF
#ifdef MISSIONPACK
|| gametype == GT_1FCTF
#endif
) {
//
switch(BotTeam(bs)) {
case TEAM_RED: memcpy(&bs->teamgoal, &ctf_redflag, sizeof(bot_goal_t)); break;
case TEAM_BLUE: memcpy(&bs->teamgoal, &ctf_blueflag, sizeof(bot_goal_t)); break;
default: return;
}
}
else {
return;
}
//
bs->decisionmaker = client;
bs->ordered = qtrue;
bs->order_time = FloatTime();
//set the time to send a message to the team mates
bs->teammessage_time = FloatTime() + 2 * random();
//set the ltg type
bs->ltgtype = LTG_DEFENDKEYAREA;
//get the team goal time
bs->teamgoal_time = FloatTime() + TEAM_DEFENDKEYAREA_TIME;
//away from defending
bs->defendaway_time = 0;
//
BotSetTeamStatus(bs);
// remember last ordered task
BotRememberLastOrderedTask(bs);
#ifdef DEBUG
BotPrintTeamGoal(bs);
#endif //DEBUG
}
/*
==================
BotVoiceChat_DefendFlag
==================
*/
void BotVoiceChat_DefendFlag(bot_state_t *bs, int client, int mode) {
BotVoiceChat_Defend(bs, client, mode);
}
/*
==================
BotVoiceChat_Patrol
==================
*/
void BotVoiceChat_Patrol(bot_state_t *bs, int client, int mode) {
//
bs->decisionmaker = client;
//
bs->ltgtype = 0;
bs->lead_time = 0;
bs->lastgoal_ltgtype = 0;
//
BotAI_BotInitialChat(bs, "dismissed", NULL);
trap_BotEnterChat(bs->cs, client, CHAT_TELL);
BotVoiceChatOnly(bs, -1, VOICECHAT_ONPATROL);
//
BotSetTeamStatus(bs);
#ifdef DEBUG
BotPrintTeamGoal(bs);
#endif //DEBUG
}
/*
==================
BotVoiceChat_Camp
==================
*/
void BotVoiceChat_Camp(bot_state_t *bs, int client, int mode) {
int areanum;
aas_entityinfo_t entinfo;
char netname[MAX_NETNAME];
//
bs->teamgoal.entitynum = -1;
BotEntityInfo(client, &entinfo);
//if info is valid (in PVS)
if (entinfo.valid) {
areanum = BotPointAreaNum(entinfo.origin);
if (areanum) { // && trap_AAS_AreaReachability(areanum)) {
//NOTE: just assume the bot knows where the person is
//if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, client)) {
bs->teamgoal.entitynum = client;
bs->teamgoal.areanum = areanum;
VectorCopy(entinfo.origin, bs->teamgoal.origin);
VectorSet(bs->teamgoal.mins, -8, -8, -8);
VectorSet(bs->teamgoal.maxs, 8, 8, 8);
//}
}
}
//if the other is not visible
if (bs->teamgoal.entitynum < 0) {
BotAI_BotInitialChat(bs, "whereareyou", EasyClientName(client, netname, sizeof(netname)), NULL);
trap_BotEnterChat(bs->cs, client, CHAT_TELL);
return;
}
//
bs->decisionmaker = client;
bs->ordered = qtrue;
bs->order_time = FloatTime();
//set the time to send a message to the team mates
bs->teammessage_time = FloatTime() + 2 * random();
//set the ltg type
bs->ltgtype = LTG_CAMPORDER;
//get the team goal time
bs->teamgoal_time = FloatTime() + TEAM_CAMP_TIME;
//the teammate that requested the camping
bs->teammate = client;
//not arrived yet
bs->arrive_time = 0;
//
BotSetTeamStatus(bs);
// remember last ordered task
BotRememberLastOrderedTask(bs);
#ifdef DEBUG
BotPrintTeamGoal(bs);
#endif //DEBUG
}
/*
==================
BotVoiceChat_FollowMe
==================
*/
void BotVoiceChat_FollowMe(bot_state_t *bs, int client, int mode) {
int areanum;
aas_entityinfo_t entinfo;
char netname[MAX_NETNAME];
bs->teamgoal.entitynum = -1;
BotEntityInfo(client, &entinfo);
//if info is valid (in PVS)
if (entinfo.valid) {
areanum = BotPointAreaNum(entinfo.origin);
if (areanum) { // && trap_AAS_AreaReachability(areanum)) {
bs->teamgoal.entitynum = client;
bs->teamgoal.areanum = areanum;
VectorCopy(entinfo.origin, bs->teamgoal.origin);
VectorSet(bs->teamgoal.mins, -8, -8, -8);
VectorSet(bs->teamgoal.maxs, 8, 8, 8);
}
}
//if the other is not visible
if (bs->teamgoal.entitynum < 0) {
BotAI_BotInitialChat(bs, "whereareyou", EasyClientName(client, netname, sizeof(netname)), NULL);
trap_BotEnterChat(bs->cs, client, CHAT_TELL);
return;
}
//
bs->decisionmaker = client;
bs->ordered = qtrue;
bs->order_time = FloatTime();
//the team mate
bs->teammate = client;
//last time the team mate was assumed visible
bs->teammatevisible_time = FloatTime();
//set the time to send a message to the team mates
bs->teammessage_time = FloatTime() + 2 * random();
//get the team goal time
bs->teamgoal_time = FloatTime() + TEAM_ACCOMPANY_TIME;
//set the ltg type
bs->ltgtype = LTG_TEAMACCOMPANY;
bs->formation_dist = 3.5 * 32; //3.5 meter
bs->arrive_time = 0;
//
BotSetTeamStatus(bs);
// remember last ordered task
BotRememberLastOrderedTask(bs);
#ifdef DEBUG
BotPrintTeamGoal(bs);
#endif //DEBUG
}
/*
==================
BotVoiceChat_FollowFlagCarrier
==================
*/
void BotVoiceChat_FollowFlagCarrier(bot_state_t *bs, int client, int mode) {
int carrier;
carrier = BotTeamFlagCarrier(bs);
if (carrier >= 0)
BotVoiceChat_FollowMe(bs, carrier, mode);
#ifdef DEBUG
BotPrintTeamGoal(bs);
#endif //DEBUG
}
/*
==================
BotVoiceChat_ReturnFlag
==================
*/
void BotVoiceChat_ReturnFlag(bot_state_t *bs, int client, int mode) {
//if not in CTF mode
if (
gametype != GT_CTF
#ifdef MISSIONPACK
&& gametype != GT_1FCTF
#endif
) {
return;
}
//
bs->decisionmaker = client;
bs->ordered = qtrue;
bs->order_time = FloatTime();
//set the time to send a message to the team mates
bs->teammessage_time = FloatTime() + 2 * random();
//set the ltg type
bs->ltgtype = LTG_RETURNFLAG;
//set the team goal time
bs->teamgoal_time = FloatTime() + CTF_RETURNFLAG_TIME;
bs->rushbaseaway_time = 0;
BotSetTeamStatus(bs);
#ifdef DEBUG
BotPrintTeamGoal(bs);
#endif //DEBUG
}
/*
==================
BotVoiceChat_StartLeader
==================
*/
void BotVoiceChat_StartLeader(bot_state_t *bs, int client, int mode) {
ClientName(client, bs->teamleader, sizeof(bs->teamleader));
}
/*
==================
BotVoiceChat_StopLeader
==================
*/
void BotVoiceChat_StopLeader(bot_state_t *bs, int client, int mode) {
char netname[MAX_MESSAGE_SIZE];
if (!Q_stricmp(bs->teamleader, ClientName(client, netname, sizeof(netname)))) {
bs->teamleader[0] = '\0';
notleader[client] = qtrue;
}
}
/*
==================
BotVoiceChat_WhoIsLeader
==================
*/
void BotVoiceChat_WhoIsLeader(bot_state_t *bs, int client, int mode) {
char netname[MAX_MESSAGE_SIZE];
if (!TeamPlayIsOn()) return;
ClientName(bs->client, netname, sizeof(netname));
//if this bot IS the team leader
if (!Q_stricmp(netname, bs->teamleader)) {
BotAI_BotInitialChat(bs, "iamteamleader", NULL);
trap_BotEnterChat(bs->cs, 0, CHAT_TEAM);
BotVoiceChatOnly(bs, -1, VOICECHAT_STARTLEADER);
}
}
/*
==================
BotVoiceChat_WantOnDefense
==================
*/
void BotVoiceChat_WantOnDefense(bot_state_t *bs, int client, int mode) {
char netname[MAX_NETNAME];
int preference;
preference = BotGetTeamMateTaskPreference(bs, client);
preference &= ~TEAMTP_ATTACKER;
preference |= TEAMTP_DEFENDER;
BotSetTeamMateTaskPreference(bs, client, preference);
//
EasyClientName(client, netname, sizeof(netname));
BotAI_BotInitialChat(bs, "keepinmind", netname, NULL);
trap_BotEnterChat(bs->cs, client, CHAT_TELL);
BotVoiceChatOnly(bs, client, VOICECHAT_YES);
trap_EA_Action(bs->client, ACTION_AFFIRMATIVE);
}
/*
==================
BotVoiceChat_WantOnOffense
==================
*/
void BotVoiceChat_WantOnOffense(bot_state_t *bs, int client, int mode) {
char netname[MAX_NETNAME];
int preference;
preference = BotGetTeamMateTaskPreference(bs, client);
preference &= ~TEAMTP_DEFENDER;
preference |= TEAMTP_ATTACKER;
BotSetTeamMateTaskPreference(bs, client, preference);
//
EasyClientName(client, netname, sizeof(netname));
BotAI_BotInitialChat(bs, "keepinmind", netname, NULL);
trap_BotEnterChat(bs->cs, client, CHAT_TELL);
BotVoiceChatOnly(bs, client, VOICECHAT_YES);
trap_EA_Action(bs->client, ACTION_AFFIRMATIVE);
}
void BotVoiceChat_Dummy(bot_state_t *bs, int client, int mode) {
}
voiceCommand_t voiceCommands[] = {
{VOICECHAT_GETFLAG, BotVoiceChat_GetFlag},
{VOICECHAT_OFFENSE, BotVoiceChat_Offense },
{VOICECHAT_DEFEND, BotVoiceChat_Defend },
{VOICECHAT_DEFENDFLAG, BotVoiceChat_DefendFlag },
{VOICECHAT_PATROL, BotVoiceChat_Patrol },
{VOICECHAT_CAMP, BotVoiceChat_Camp },
{VOICECHAT_FOLLOWME, BotVoiceChat_FollowMe },
{VOICECHAT_FOLLOWFLAGCARRIER, BotVoiceChat_FollowFlagCarrier },
{VOICECHAT_RETURNFLAG, BotVoiceChat_ReturnFlag },
{VOICECHAT_STARTLEADER, BotVoiceChat_StartLeader },
{VOICECHAT_STOPLEADER, BotVoiceChat_StopLeader },
{VOICECHAT_WHOISLEADER, BotVoiceChat_WhoIsLeader },
{VOICECHAT_WANTONDEFENSE, BotVoiceChat_WantOnDefense },
{VOICECHAT_WANTONOFFENSE, BotVoiceChat_WantOnOffense },
{NULL, BotVoiceChat_Dummy}
};
int BotVoiceChatCommand(bot_state_t *bs, int mode, char *voiceChat) {
int i, voiceOnly, clientNum, color;
char *ptr, buf[MAX_MESSAGE_SIZE], *cmd;
if (!TeamPlayIsOn()) {
return qfalse;
}
if ( mode == SAY_ALL ) {
return qfalse; // don't do anything with voice chats to everyone
}
Q_strncpyz(buf, voiceChat, sizeof(buf));
cmd = buf;
for (ptr = cmd; *cmd && *cmd > ' '; cmd++);
while (*cmd && *cmd <= ' ') *cmd++ = '\0';
voiceOnly = atoi(ptr);
for (ptr = cmd; *cmd && *cmd > ' '; cmd++);
while (*cmd && *cmd <= ' ') *cmd++ = '\0';
clientNum = atoi(ptr);
for (ptr = cmd; *cmd && *cmd > ' '; cmd++);
while (*cmd && *cmd <= ' ') *cmd++ = '\0';
color = atoi(ptr);
if (!BotSameTeam(bs, clientNum)) {
return qfalse;
}
for (i = 0; voiceCommands[i].cmd; i++) {
if (!Q_stricmp(cmd, voiceCommands[i].cmd)) {
voiceCommands[i].func(bs, clientNum, mode);
return qtrue;
}
}
return qfalse;
}

36
code/game/ai_vcmd.h Normal file
View file

@ -0,0 +1,36 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
/*****************************************************************************
* name: ai_vcmd.h
*
* desc: Quake3 bot AI
*
* $Archive: /source/code/botai/ai_vcmd.c $
*
*****************************************************************************/
int BotVoiceChatCommand(bot_state_t *bs, int mode, char *voicechat);
void BotVoiceChat_Defend(bot_state_t *bs, int client, int mode);

221
code/game/be_aas.h Normal file
View file

@ -0,0 +1,221 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
/*****************************************************************************
* name: be_aas.h
*
* desc: Area Awareness System, stuff exported to the AI
*
* $Archive: /source/code/botlib/be_aas.h $
*
*****************************************************************************/
#ifndef MAX_STRINGFIELD
#define MAX_STRINGFIELD 80
#endif
//travel flags
#define TFL_INVALID 0x00000001 //traveling temporary not possible
#define TFL_WALK 0x00000002 //walking
#define TFL_CROUCH 0x00000004 //crouching
#define TFL_BARRIERJUMP 0x00000008 //jumping onto a barrier
#define TFL_JUMP 0x00000010 //jumping
#define TFL_LADDER 0x00000020 //climbing a ladder
#define TFL_WALKOFFLEDGE 0x00000080 //walking of a ledge
#define TFL_SWIM 0x00000100 //swimming
#define TFL_WATERJUMP 0x00000200 //jumping out of the water
#define TFL_TELEPORT 0x00000400 //teleporting
#define TFL_ELEVATOR 0x00000800 //elevator
#define TFL_ROCKETJUMP 0x00001000 //rocket jumping
#define TFL_BFGJUMP 0x00002000 //bfg jumping
#define TFL_GRAPPLEHOOK 0x00004000 //grappling hook
#define TFL_DOUBLEJUMP 0x00008000 //double jump
#define TFL_RAMPJUMP 0x00010000 //ramp jump
#define TFL_STRAFEJUMP 0x00020000 //strafe jump
#define TFL_JUMPPAD 0x00040000 //jump pad
#define TFL_AIR 0x00080000 //travel through air
#define TFL_WATER 0x00100000 //travel through water
#define TFL_SLIME 0x00200000 //travel through slime
#define TFL_LAVA 0x00400000 //travel through lava
#define TFL_DONOTENTER 0x00800000 //travel through donotenter area
#define TFL_FUNCBOB 0x01000000 //func bobbing
#define TFL_FLIGHT 0x02000000 //flight
#define TFL_BRIDGE 0x04000000 //move over a bridge
//
#define TFL_NOTTEAM1 0x08000000 //not team 1
#define TFL_NOTTEAM2 0x10000000 //not team 2
//default travel flags
#define TFL_DEFAULT TFL_WALK|TFL_CROUCH|TFL_BARRIERJUMP|\
TFL_JUMP|TFL_LADDER|\
TFL_WALKOFFLEDGE|TFL_SWIM|TFL_WATERJUMP|\
TFL_TELEPORT|TFL_ELEVATOR|\
TFL_AIR|TFL_WATER|TFL_JUMPPAD|TFL_FUNCBOB
typedef enum
{
SOLID_NOT, // no interaction with other objects
SOLID_TRIGGER, // only touch when inside, after moving
SOLID_BBOX, // touch on edge
SOLID_BSP // bsp clip, touch on edge
} solid_t;
//a trace is returned when a box is swept through the AAS world
typedef struct aas_trace_s
{
qboolean startsolid; // if true, the initial point was in a solid area
float fraction; // time completed, 1.0 = didn't hit anything
vec3_t endpos; // final position
int ent; // entity blocking the trace
int lastarea; // last area the trace was in (zero if none)
int area; // area blocking the trace (zero if none)
int planenum; // number of the plane that was hit
} aas_trace_t;
/* Defined in botlib.h
//bsp_trace_t hit surface
typedef struct bsp_surface_s
{
char name[16];
int flags;
int value;
} bsp_surface_t;
//a trace is returned when a box is swept through the BSP world
typedef struct bsp_trace_s
{
qboolean allsolid; // if true, plane is not valid
qboolean startsolid; // if true, the initial point was in a solid area
float fraction; // time completed, 1.0 = didn't hit anything
vec3_t endpos; // final position
cplane_t plane; // surface normal at impact
float exp_dist; // expanded plane distance
int sidenum; // number of the brush side hit
bsp_surface_t surface; // hit surface
int contents; // contents on other side of surface hit
int ent; // number of entity hit
} bsp_trace_t;
//
*/
//entity info
typedef struct aas_entityinfo_s
{
int valid; // true if updated this frame
int type; // entity type
int flags; // entity flags
float ltime; // local time
float update_time; // time between last and current update
int number; // number of the entity
vec3_t origin; // origin of the entity
vec3_t angles; // angles of the model
vec3_t old_origin; // for lerping
vec3_t lastvisorigin; // last visible origin
vec3_t mins; // bounding box minimums
vec3_t maxs; // bounding box maximums
int groundent; // ground entity
int solid; // solid type
int modelindex; // model used
int modelindex2; // weapons, CTF flags, etc
int frame; // model frame number
int event; // impulse events -- muzzle flashes, footsteps, etc
int eventParm; // even parameter
int powerups; // bit flags
int weapon; // determines weapon and flash model, etc
int legsAnim; // mask off ANIM_TOGGLEBIT
int torsoAnim; // mask off ANIM_TOGGLEBIT
} aas_entityinfo_t;
// area info
typedef struct aas_areainfo_s
{
int contents;
int flags;
int presencetype;
int cluster;
vec3_t mins;
vec3_t maxs;
vec3_t center;
} aas_areainfo_t;
// client movement prediction stop events, stop as soon as:
#define SE_NONE 0
#define SE_HITGROUND 1 // the ground is hit
#define SE_LEAVEGROUND 2 // there's no ground
#define SE_ENTERWATER 4 // water is entered
#define SE_ENTERSLIME 8 // slime is entered
#define SE_ENTERLAVA 16 // lava is entered
#define SE_HITGROUNDDAMAGE 32 // the ground is hit with damage
#define SE_GAP 64 // there's a gap
#define SE_TOUCHJUMPPAD 128 // touching a jump pad area
#define SE_TOUCHTELEPORTER 256 // touching teleporter
#define SE_ENTERAREA 512 // the given stoparea is entered
#define SE_HITGROUNDAREA 1024 // a ground face in the area is hit
#define SE_HITBOUNDINGBOX 2048 // hit the specified bounding box
#define SE_TOUCHCLUSTERPORTAL 4096 // touching a cluster portal
typedef struct aas_clientmove_s
{
vec3_t endpos; //position at the end of movement prediction
int endarea; //area at end of movement prediction
vec3_t velocity; //velocity at the end of movement prediction
aas_trace_t trace; //last trace
int presencetype; //presence type at end of movement prediction
int stopevent; //event that made the prediction stop
int endcontents; //contents at the end of movement prediction
float time; //time predicted ahead
int frames; //number of frames predicted ahead
} aas_clientmove_t;
// alternate route goals
#define ALTROUTEGOAL_ALL 1
#define ALTROUTEGOAL_CLUSTERPORTALS 2
#define ALTROUTEGOAL_VIEWPORTALS 4
typedef struct aas_altroutegoal_s
{
vec3_t origin;
int areanum;
unsigned short starttraveltime;
unsigned short goaltraveltime;
unsigned short extratraveltime;
} aas_altroutegoal_t;
// route prediction stop events
#define RSE_NONE 0
#define RSE_NOROUTE 1 //no route to goal
#define RSE_USETRAVELTYPE 2 //stop as soon as on of the given travel types is used
#define RSE_ENTERCONTENTS 4 //stop when entering the given contents
#define RSE_ENTERAREA 8 //stop when entering the given area
typedef struct aas_predictroute_s
{
vec3_t endpos; //position at the end of movement prediction
int endarea; //area at end of movement prediction
int stopevent; //event that made the prediction stop
int endcontents; //contents at the end of movement prediction
int endtravelflags; //end travel flags
int numareas; //number of areas predicted ahead
int time; //time predicted ahead (in hundreth of a sec)
} aas_predictroute_t;

48
code/game/be_ai_char.h Normal file
View file

@ -0,0 +1,48 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
/*****************************************************************************
* name: be_ai_char.h
*
* desc: bot characters
*
* $Archive: /source/code/botlib/be_ai_char.h $
*
*****************************************************************************/
//loads a bot character from a file
int BotLoadCharacter(char *charfile, float skill);
//frees a bot character
void BotFreeCharacter(int character);
//returns a float characteristic
float Characteristic_Float(int character, int index);
//returns a bounded float characteristic
float Characteristic_BFloat(int character, int index, float min, float max);
//returns an integer characteristic
int Characteristic_Integer(int character, int index);
//returns a bounded integer characteristic
int Characteristic_BInteger(int character, int index, int min, int max);
//returns a string characteristic
void Characteristic_String(int character, int index, char *buf, int size);
//free cached bot characters
void BotShutdownCharacters(void);

113
code/game/be_ai_chat.h Normal file
View file

@ -0,0 +1,113 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
/*****************************************************************************
* name: be_ai_chat.h
*
* desc: char AI
*
* $Archive: /source/code/botlib/be_ai_chat.h $
*
*****************************************************************************/
#define MAX_MESSAGE_SIZE 256
#define MAX_CHATTYPE_NAME 32
#define MAX_MATCHVARIABLES 8
#define CHAT_GENDERLESS 0
#define CHAT_GENDERFEMALE 1
#define CHAT_GENDERMALE 2
#define CHAT_ALL 0
#define CHAT_TEAM 1
#define CHAT_TELL 2
//a console message
typedef struct bot_consolemessage_s
{
int handle;
float time; //message time
int type; //message type
char message[MAX_MESSAGE_SIZE]; //message
struct bot_consolemessage_s *prev, *next; //prev and next in list
} bot_consolemessage_t;
//match variable
typedef struct bot_matchvariable_s
{
char offset;
int length;
} bot_matchvariable_t;
//returned to AI when a match is found
typedef struct bot_match_s
{
char string[MAX_MESSAGE_SIZE];
int type;
int subtype;
bot_matchvariable_t variables[MAX_MATCHVARIABLES];
} bot_match_t;
//setup the chat AI
int BotSetupChatAI(void);
//shutdown the chat AI
void BotShutdownChatAI(void);
//returns the handle to a newly allocated chat state
int BotAllocChatState(void);
//frees the chatstate
void BotFreeChatState(int handle);
//adds a console message to the chat state
void BotQueueConsoleMessage(int chatstate, int type, char *message);
//removes the console message from the chat state
void BotRemoveConsoleMessage(int chatstate, int handle);
//returns the next console message from the state
int BotNextConsoleMessage(int chatstate, bot_consolemessage_t *cm);
//returns the number of console messages currently stored in the state
int BotNumConsoleMessages(int chatstate);
//selects a chat message of the given type
void BotInitialChat(int chatstate, char *type, int mcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7);
//returns the number of initial chat messages of the given type
int BotNumInitialChats(int chatstate, char *type);
//find and select a reply for the given message
int 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);
//returns the length of the currently selected chat message
int BotChatLength(int chatstate);
//enters the selected chat message
void BotEnterChat(int chatstate, int clientto, int sendto);
//get the chat message ready to be output
void BotGetChatMessage(int chatstate, char *buf, int size);
//checks if the first string contains the second one, returns index into first string or -1 if not found
int StringContains(char *str1, char *str2, int casesensitive);
//finds a match for the given string using the match templates
int BotFindMatch(char *str, bot_match_t *match, unsigned long int context);
//returns a variable from a match
void BotMatchVariable(bot_match_t *match, int variable, char *buf, int size);
//unify all the white spaces in the string
void UnifyWhiteSpaces(char *string);
//replace all the context related synonyms in the string
void BotReplaceSynonyms(char *string, unsigned long int context);
//loads a chat file for the chat state
int BotLoadChatFile(int chatstate, char *chatfile, char *chatname);
//store the gender of the bot in the chat state
void BotSetChatGender(int chatstate, int gender);
//store the bot name in the chat state
void BotSetChatName(int chatstate, char *name, int client);

33
code/game/be_ai_gen.h Normal file
View file

@ -0,0 +1,33 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
/*****************************************************************************
* name: be_ai_gen.h
*
* desc: genetic selection
*
* $Archive: /source/code/botlib/be_ai_gen.h $
*
*****************************************************************************/
int GeneticParentsAndChildSelection(int numranks, float *ranks, int *parent1, int *parent2, int *child);

118
code/game/be_ai_goal.h Normal file
View file

@ -0,0 +1,118 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
/*****************************************************************************
* name: be_ai_goal.h
*
* desc: goal AI
*
* $Archive: /source/code/botlib/be_ai_goal.h $
*
*****************************************************************************/
#define MAX_AVOIDGOALS 256
#define MAX_GOALSTACK 8
#define GFL_NONE 0
#define GFL_ITEM 1
#define GFL_ROAM 2
#define GFL_DROPPED 4
//a bot goal
typedef struct bot_goal_s
{
vec3_t origin; //origin of the goal
int areanum; //area number of the goal
vec3_t mins, maxs; //mins and maxs of the goal
int entitynum; //number of the goal entity
int number; //goal number
int flags; //goal flags
int iteminfo; //item information
} bot_goal_t;
//reset the whole goal state, but keep the item weights
void BotResetGoalState(int goalstate);
//reset avoid goals
void BotResetAvoidGoals(int goalstate);
//remove the goal with the given number from the avoid goals
void BotRemoveFromAvoidGoals(int goalstate, int number);
//push a goal onto the goal stack
void BotPushGoal(int goalstate, bot_goal_t *goal);
//pop a goal from the goal stack
void BotPopGoal(int goalstate);
//empty the bot's goal stack
void BotEmptyGoalStack(int goalstate);
//dump the avoid goals
void BotDumpAvoidGoals(int goalstate);
//dump the goal stack
void BotDumpGoalStack(int goalstate);
//get the name name of the goal with the given number
void BotGoalName(int number, char *name, int size);
//get the top goal from the stack
int BotGetTopGoal(int goalstate, bot_goal_t *goal);
//get the second goal on the stack
int BotGetSecondGoal(int goalstate, bot_goal_t *goal);
//choose the best long term goal item for the bot
int BotChooseLTGItem(int goalstate, vec3_t origin, int *inventory, int travelflags);
//choose the best nearby goal item for the bot
//the item may not be further away from the current bot position than maxtime
//also the travel time from the nearby goal towards the long term goal may not
//be larger than the travel time towards the long term goal from the current bot position
int BotChooseNBGItem(int goalstate, vec3_t origin, int *inventory, int travelflags,
bot_goal_t *ltg, float maxtime);
//returns true if the bot touches the goal
int BotTouchingGoal(vec3_t origin, bot_goal_t *goal);
//returns true if the goal should be visible but isn't
int BotItemGoalInVisButNotVisible(int viewer, vec3_t eye, vec3_t viewangles, bot_goal_t *goal);
//search for a goal for the given classname, the index can be used
//as a start point for the search when multiple goals are available with that same classname
int BotGetLevelItemGoal(int index, char *classname, bot_goal_t *goal);
//get the next camp spot in the map
int BotGetNextCampSpotGoal(int num, bot_goal_t *goal);
//get the map location with the given name
int BotGetMapLocationGoal(char *name, bot_goal_t *goal);
//returns the avoid goal time
float BotAvoidGoalTime(int goalstate, int number);
//set the avoid goal time
void BotSetAvoidGoalTime(int goalstate, int number, float avoidtime);
//initializes the items in the level
void BotInitLevelItems(void);
//regularly update dynamic entity items (dropped weapons, flags etc.)
void BotUpdateEntityItems(void);
//interbreed the goal fuzzy logic
void BotInterbreedGoalFuzzyLogic(int parent1, int parent2, int child);
//save the goal fuzzy logic to disk
void BotSaveGoalFuzzyLogic(int goalstate, char *filename);
//mutate the goal fuzzy logic
void BotMutateGoalFuzzyLogic(int goalstate, float range);
//loads item weights for the bot
int BotLoadItemWeights(int goalstate, char *filename);
//frees the item weights of the bot
void BotFreeItemWeights(int goalstate);
//returns the handle of a newly allocated goal state
int BotAllocGoalState(int client);
//free the given goal state
void BotFreeGoalState(int handle);
//setup the goal AI
int BotSetupGoalAI(void);
//shut down the goal AI
void BotShutdownGoalAI(void);

142
code/game/be_ai_move.h Normal file
View file

@ -0,0 +1,142 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
/*****************************************************************************
* name: be_ai_move.h
*
* desc: movement AI
*
* $Archive: /source/code/botlib/be_ai_move.h $
*
*****************************************************************************/
//movement types
#define MOVE_WALK 1
#define MOVE_CROUCH 2
#define MOVE_JUMP 4
#define MOVE_GRAPPLE 8
#define MOVE_ROCKETJUMP 16
#define MOVE_BFGJUMP 32
//move flags
#define MFL_BARRIERJUMP 1 //bot is performing a barrier jump
#define MFL_ONGROUND 2 //bot is in the ground
#define MFL_SWIMMING 4 //bot is swimming
#define MFL_AGAINSTLADDER 8 //bot is against a ladder
#define MFL_WATERJUMP 16 //bot is waterjumping
#define MFL_TELEPORTED 32 //bot is being teleported
#define MFL_GRAPPLEPULL 64 //bot is being pulled by the grapple
#define MFL_ACTIVEGRAPPLE 128 //bot is using the grapple hook
#define MFL_GRAPPLERESET 256 //bot has reset the grapple
#define MFL_WALK 512 //bot should walk slowly
// move result flags
#define MOVERESULT_MOVEMENTVIEW 1 //bot uses view for movement
#define MOVERESULT_SWIMVIEW 2 //bot uses view for swimming
#define MOVERESULT_WAITING 4 //bot is waiting for something
#define MOVERESULT_MOVEMENTVIEWSET 8 //bot has set the view in movement code
#define MOVERESULT_MOVEMENTWEAPON 16 //bot uses weapon for movement
#define MOVERESULT_ONTOPOFOBSTACLE 32 //bot is ontop of obstacle
#define MOVERESULT_ONTOPOF_FUNCBOB 64 //bot is ontop of a func_bobbing
#define MOVERESULT_ONTOPOF_ELEVATOR 128 //bot is ontop of an elevator (func_plat)
#define MOVERESULT_BLOCKEDBYAVOIDSPOT 256 //bot is blocked by an avoid spot
//
#define MAX_AVOIDREACH 1
#define MAX_AVOIDSPOTS 32
// avoid spot types
#define AVOID_CLEAR 0 //clear all avoid spots
#define AVOID_ALWAYS 1 //avoid always
#define AVOID_DONTBLOCK 2 //never totally block
// restult types
#define RESULTTYPE_ELEVATORUP 1 //elevator is up
#define RESULTTYPE_WAITFORFUNCBOBBING 2 //waiting for func bobbing to arrive
#define RESULTTYPE_BADGRAPPLEPATH 4 //grapple path is obstructed
#define RESULTTYPE_INSOLIDAREA 8 //stuck in solid area, this is bad
//structure used to initialize the movement state
//the or_moveflags MFL_ONGROUND, MFL_TELEPORTED and MFL_WATERJUMP come from the playerstate
typedef struct bot_initmove_s
{
vec3_t origin; //origin of the bot
vec3_t velocity; //velocity of the bot
vec3_t viewoffset; //view offset
int entitynum; //entity number of the bot
int client; //client number of the bot
float thinktime; //time the bot thinks
int presencetype; //presencetype of the bot
vec3_t viewangles; //view angles of the bot
int or_moveflags; //values ored to the movement flags
} bot_initmove_t;
//NOTE: the ideal_viewangles are only valid if MFL_MOVEMENTVIEW is set
typedef struct bot_moveresult_s
{
int failure; //true if movement failed all together
int type; //failure or blocked type
int blocked; //true if blocked by an entity
int blockentity; //entity blocking the bot
int traveltype; //last executed travel type
int flags; //result flags
int weapon; //weapon used for movement
vec3_t movedir; //movement direction
vec3_t ideal_viewangles; //ideal viewangles for the movement
} bot_moveresult_t;
// bk001204: from code/botlib/be_ai_move.c
// TTimo 04/12/2001 was moved here to avoid dup defines
typedef struct bot_avoidspot_s
{
vec3_t origin;
float radius;
int type;
} bot_avoidspot_t;
//resets the whole move state
void BotResetMoveState(int movestate);
//moves the bot to the given goal
void BotMoveToGoal(bot_moveresult_t *result, int movestate, bot_goal_t *goal, int travelflags);
//moves the bot in the specified direction using the specified type of movement
int BotMoveInDirection(int movestate, vec3_t dir, float speed, int type);
//reset avoid reachability
void BotResetAvoidReach(int movestate);
//resets the last avoid reachability
void BotResetLastAvoidReach(int movestate);
//returns a reachability area if the origin is in one
int BotReachabilityArea(vec3_t origin, int client);
//view target based on movement
int BotMovementViewTarget(int movestate, bot_goal_t *goal, int travelflags, float lookahead, vec3_t target);
//predict the position of a player based on movement towards a goal
int BotPredictVisiblePosition(vec3_t origin, int areanum, bot_goal_t *goal, int travelflags, vec3_t target);
//returns the handle of a newly allocated movestate
int BotAllocMoveState(void);
//frees the movestate with the given handle
void BotFreeMoveState(int handle);
//initialize movement state before performing any movement
void BotInitMoveState(int handle, bot_initmove_t *initmove);
//add a spot to avoid (if type == AVOID_CLEAR all spots are removed)
void BotAddAvoidSpot(int movestate, vec3_t origin, float radius, int type);
//must be called every map change
void BotSetBrushModelTypes(void);
//setup movement AI
int BotSetupMoveAI(void);
//shutdown movement AI
void BotShutdownMoveAI(void);

104
code/game/be_ai_weap.h Normal file
View file

@ -0,0 +1,104 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
/*****************************************************************************
* name: be_ai_weap.h
*
* desc: weapon AI
*
* $Archive: /source/code/botlib/be_ai_weap.h $
*
*****************************************************************************/
//projectile flags
#define PFL_WINDOWDAMAGE 1 //projectile damages through window
#define PFL_RETURN 2 //set when projectile returns to owner
//weapon flags
#define WFL_FIRERELEASED 1 //set when projectile is fired with key-up event
//damage types
#define DAMAGETYPE_IMPACT 1 //damage on impact
#define DAMAGETYPE_RADIAL 2 //radial damage
#define DAMAGETYPE_VISIBLE 4 //damage to all entities visible to the projectile
typedef struct projectileinfo_s
{
char name[MAX_STRINGFIELD];
char model[MAX_STRINGFIELD];
int flags;
float gravity;
int damage;
float radius;
int visdamage;
int damagetype;
int healthinc;
float push;
float detonation;
float bounce;
float bouncefric;
float bouncestop;
} projectileinfo_t;
typedef struct weaponinfo_s
{
int valid; //true if the weapon info is valid
int number; //number of the weapon
char name[MAX_STRINGFIELD];
char model[MAX_STRINGFIELD];
int level;
int weaponindex;
int flags;
char projectile[MAX_STRINGFIELD];
int numprojectiles;
float hspread;
float vspread;
float speed;
float acceleration;
vec3_t recoil;
vec3_t offset;
vec3_t angleoffset;
float extrazvelocity;
int ammoamount;
int ammoindex;
float activate;
float reload;
float spinup;
float spindown;
projectileinfo_t proj; //pointer to the used projectile
} weaponinfo_t;
//setup the weapon AI
int BotSetupWeaponAI(void);
//shut down the weapon AI
void BotShutdownWeaponAI(void);
//returns the best weapon to fight with
int BotChooseBestFightWeapon(int weaponstate, int *inventory);
//returns the information of the current weapon
void BotGetWeaponInfo(int weaponstate, int weapon, weaponinfo_t *weaponinfo);
//loads the weapon weights
int BotLoadWeaponWeights(int weaponstate, char *filename);
//returns a handle to a newly allocated weapon state
int BotAllocWeaponState(void);
//frees the weapon state
void BotFreeWeaponState(int weaponstate);
//resets the whole weapon state
void BotResetWeaponState(int weaponstate);

66
code/game/be_ea.h Normal file
View file

@ -0,0 +1,66 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
/*****************************************************************************
* name: be_ea.h
*
* desc: elementary actions
*
* $Archive: /source/code/botlib/be_ea.h $
*
*****************************************************************************/
//ClientCommand elementary actions
void EA_Say(int client, char *str);
void EA_SayTeam(int client, char *str);
void EA_Command(int client, char *command );
void EA_Action(int client, int action);
void EA_Crouch(int client);
void EA_Walk(int client);
void EA_MoveUp(int client);
void EA_MoveDown(int client);
void EA_MoveForward(int client);
void EA_MoveBack(int client);
void EA_MoveLeft(int client);
void EA_MoveRight(int client);
void EA_Attack(int client);
void EA_Respawn(int client);
void EA_Talk(int client);
void EA_Gesture(int client);
void EA_Use(int client);
//regular elementary actions
void EA_SelectWeapon(int client, int weapon);
void EA_Jump(int client);
void EA_DelayedJump(int client);
void EA_Move(int client, vec3_t dir, float speed);
void EA_View(int client, vec3_t viewangles);
//send regular input to the server
void EA_EndRegular(int client, float thinktime);
void EA_GetInput(int client, float thinktime, bot_input_t *input);
void EA_ResetInput(int client);
//setup and shutdown routines
int EA_Setup(void);
void EA_Shutdown(void);

1324
code/game/bg_lib.c Normal file

File diff suppressed because it is too large Load diff

91
code/game/bg_lib.h Normal file
View file

@ -0,0 +1,91 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// bg_lib.h -- standard C library replacement routines used by code
// compiled for the virtual machine
// This file is NOT included on native builds
typedef int size_t;
typedef char * va_list;
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_end(ap) ( ap = (va_list)0 )
#define CHAR_BIT 8 /* number of bits in a char */
#define SCHAR_MIN (-128) /* minimum signed char value */
#define SCHAR_MAX 127 /* maximum signed char value */
#define UCHAR_MAX 0xff /* maximum unsigned char value */
#define SHRT_MIN (-32768) /* minimum (signed) short value */
#define SHRT_MAX 32767 /* maximum (signed) short value */
#define USHRT_MAX 0xffff /* maximum unsigned short value */
#define INT_MIN (-2147483647 - 1) /* minimum (signed) int value */
#define INT_MAX 2147483647 /* maximum (signed) int value */
#define UINT_MAX 0xffffffff /* maximum unsigned int value */
#define LONG_MIN (-2147483647L - 1) /* minimum (signed) long value */
#define LONG_MAX 2147483647L /* maximum (signed) long value */
#define ULONG_MAX 0xffffffffUL /* maximum unsigned long value */
// Misc functions
typedef int cmp_t(const void *, const void *);
void qsort(void *a, size_t n, size_t es, cmp_t *cmp);
void srand( unsigned seed );
int rand( void );
// String functions
size_t strlen( const char *string );
char *strcat( char *strDestination, const char *strSource );
char *strcpy( char *strDestination, const char *strSource );
int strcmp( const char *string1, const char *string2 );
char *strchr( const char *string, int c );
char *strstr( const char *string, const char *strCharSet );
char *strncpy( char *strDest, const char *strSource, size_t count );
int tolower( int c );
int toupper( int c );
double atof( const char *string );
double _atof( const char **stringPtr );
int atoi( const char *string );
int _atoi( const char **stringPtr );
int vsprintf( char *buffer, const char *fmt, va_list argptr );
int sscanf( const char *buffer, const char *fmt, ... );
// Memory functions
void *memmove( void *dest, const void *src, size_t count );
void *memset( void *dest, int c, size_t count );
void *memcpy( void *dest, const void *src, size_t count );
// Math functions
double ceil( double x );
double floor( double x );
double sqrt( double x );
double sin( double x );
double cos( double x );
double atan2( double y, double x );
double tan( double x );
int abs( int n );
double fabs( double x );
double acos( double x );

83
code/game/bg_local.h Normal file
View file

@ -0,0 +1,83 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// bg_local.h -- local definitions for the bg (both games) files
#define MIN_WALK_NORMAL 0.7f // can't walk on very steep slopes
#define STEPSIZE 18
#define JUMP_VELOCITY 270
#define TIMER_LAND 130
#define TIMER_GESTURE (34*66+50)
#define OVERCLIP 1.001f
// all of the locals will be zeroed before each
// pmove, just to make damn sure we don't have
// any differences when running on client or server
typedef struct {
vec3_t forward, right, up;
float frametime;
int msec;
qboolean walking;
qboolean groundPlane;
trace_t groundTrace;
float impactSpeed;
vec3_t previous_origin;
vec3_t previous_velocity;
int previous_waterlevel;
} pml_t;
extern pmove_t *pm;
extern pml_t pml;
// movement parameters
extern float pm_stopspeed;
extern float pm_duckScale;
extern float pm_swimScale;
extern float pm_wadeScale;
extern float pm_accelerate;
extern float pm_airaccelerate;
extern float pm_wateraccelerate;
extern float pm_flyaccelerate;
extern float pm_friction;
extern float pm_waterfriction;
extern float pm_flightfriction;
extern int c_pmove;
void PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out, float overbounce );
void PM_AddTouchEnt( int entityNum );
void PM_AddEvent( int newEvent );
qboolean PM_SlideMove( qboolean gravity );
void PM_StepSlideMove( qboolean gravity );

1604
code/game/bg_misc.c Normal file

File diff suppressed because it is too large Load diff

2069
code/game/bg_pmove.c Normal file

File diff suppressed because it is too large Load diff

738
code/game/bg_public.h Normal file
View file

@ -0,0 +1,738 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// bg_public.h -- definitions shared by both the server game and client game modules
// because games can change separately from the main system version, we need a
// second version that must match between game and cgame
#define GAME_VERSION "baseq3-1"
#define DEFAULT_GRAVITY 800
#define GIB_HEALTH -40
#define ARMOR_PROTECTION 0.66
#define MAX_ITEMS 256
#define RANK_TIED_FLAG 0x4000
#define DEFAULT_SHOTGUN_SPREAD 700
#define DEFAULT_SHOTGUN_COUNT 11
#define ITEM_RADIUS 15 // item sizes are needed for client side pickup detection
#define LIGHTNING_RANGE 768
#define SCORE_NOT_PRESENT -9999 // for the CS_SCORES[12] when only one player is present
#define VOTE_TIME 30000 // 30 seconds before vote times out
#define MINS_Z -24
#define DEFAULT_VIEWHEIGHT 26
#define CROUCH_VIEWHEIGHT 12
#define DEAD_VIEWHEIGHT -16
//
// config strings are a general means of communicating variable length strings
// from the server to all connected clients.
//
// CS_SERVERINFO and CS_SYSTEMINFO are defined in q_shared.h
#define CS_MUSIC 2
#define CS_MESSAGE 3 // from the map worldspawn's message field
#define CS_MOTD 4 // g_motd string for server message of the day
#define CS_WARMUP 5 // server time when the match will be restarted
#define CS_SCORES1 6
#define CS_SCORES2 7
#define CS_VOTE_TIME 8
#define CS_VOTE_STRING 9
#define CS_VOTE_YES 10
#define CS_VOTE_NO 11
#define CS_TEAMVOTE_TIME 12
#define CS_TEAMVOTE_STRING 14
#define CS_TEAMVOTE_YES 16
#define CS_TEAMVOTE_NO 18
#define CS_GAME_VERSION 20
#define CS_LEVEL_START_TIME 21 // so the timer only shows the current level
#define CS_INTERMISSION 22 // when 1, fraglimit/timelimit has been hit and intermission will start in a second or two
#define CS_FLAGSTATUS 23 // string indicating flag status in CTF
#define CS_SHADERSTATE 24
#define CS_BOTINFO 25
#define CS_ITEMS 27 // string of 0's and 1's that tell which items are present
#define CS_MODELS 32
#define CS_SOUNDS (CS_MODELS+MAX_MODELS)
#define CS_PLAYERS (CS_SOUNDS+MAX_SOUNDS)
#define CS_LOCATIONS (CS_PLAYERS+MAX_CLIENTS)
#define CS_PARTICLES (CS_LOCATIONS+MAX_LOCATIONS)
#define CS_MAX (CS_PARTICLES+MAX_LOCATIONS)
#if (CS_MAX) > MAX_CONFIGSTRINGS
#error overflow: (CS_MAX) > MAX_CONFIGSTRINGS
#endif
typedef enum {
GT_FFA, // free for all
GT_TOURNAMENT, // one on one tournament
GT_SINGLE_PLAYER, // single player ffa
//-- team games go after this --
GT_TEAM, // team deathmatch
GT_CTF, // capture the flag
GT_1FCTF,
GT_OBELISK,
GT_HARVESTER,
GT_MAX_GAME_TYPE
} gametype_t;
typedef enum { GENDER_MALE, GENDER_FEMALE, GENDER_NEUTER } gender_t;
/*
===================================================================================
PMOVE MODULE
The pmove code takes a player_state_t and a usercmd_t and generates a new player_state_t
and some other output data. Used for local prediction on the client game and true
movement on the server game.
===================================================================================
*/
typedef enum {
PM_NORMAL, // can accelerate and turn
PM_NOCLIP, // noclip movement
PM_SPECTATOR, // still run into walls
PM_DEAD, // no acceleration or turning, but free falling
PM_FREEZE, // stuck in place with no control
PM_INTERMISSION, // no movement or status bar
PM_SPINTERMISSION // no movement or status bar
} pmtype_t;
typedef enum {
WEAPON_READY,
WEAPON_RAISING,
WEAPON_DROPPING,
WEAPON_FIRING
} weaponstate_t;
// pmove->pm_flags
#define PMF_DUCKED 1
#define PMF_JUMP_HELD 2
#define PMF_BACKWARDS_JUMP 8 // go into backwards land
#define PMF_BACKWARDS_RUN 16 // coast down to backwards run
#define PMF_TIME_LAND 32 // pm_time is time before rejump
#define PMF_TIME_KNOCKBACK 64 // pm_time is an air-accelerate only time
#define PMF_TIME_WATERJUMP 256 // pm_time is waterjump
#define PMF_RESPAWNED 512 // clear after attack and jump buttons come up
#define PMF_USE_ITEM_HELD 1024
#define PMF_GRAPPLE_PULL 2048 // pull towards grapple location
#define PMF_FOLLOW 4096 // spectate following another player
#define PMF_SCOREBOARD 8192 // spectate as a scoreboard
#define PMF_INVULEXPAND 16384 // invulnerability sphere set to full size
#define PMF_ALL_TIMES (PMF_TIME_WATERJUMP|PMF_TIME_LAND|PMF_TIME_KNOCKBACK)
#define MAXTOUCH 32
typedef struct {
// state (in / out)
playerState_t *ps;
// command (in)
usercmd_t cmd;
int tracemask; // collide against these types of surfaces
int debugLevel; // if set, diagnostic output will be printed
qboolean noFootsteps; // if the game is setup for no footsteps by the server
qboolean gauntletHit; // true if a gauntlet attack would actually hit something
int framecount;
// results (out)
int numtouch;
int touchents[MAXTOUCH];
vec3_t mins, maxs; // bounding box size
int watertype;
int waterlevel;
float xyspeed;
// for fixed msec Pmove
int pmove_fixed;
int pmove_msec;
// callbacks to test the world
// these will be different functions during game and cgame
void (*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 (*pointcontents)( const vec3_t point, int passEntityNum );
} pmove_t;
// if a full pmove isn't done on the client, you can just update the angles
void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd );
void Pmove (pmove_t *pmove);
//===================================================================================
// player_state->stats[] indexes
// NOTE: may not have more than 16
typedef enum {
STAT_HEALTH,
STAT_HOLDABLE_ITEM,
#ifdef MISSIONPACK
STAT_PERSISTANT_POWERUP,
#endif
STAT_WEAPONS, // 16 bit fields
STAT_ARMOR,
STAT_DEAD_YAW, // look this direction when dead (FIXME: get rid of?)
STAT_CLIENTS_READY, // bit mask of clients wishing to exit the intermission (FIXME: configstring?)
STAT_MAX_HEALTH // health / armor limit, changable by handicap
} statIndex_t;
// player_state->persistant[] indexes
// these fields are the only part of player_state that isn't
// cleared on respawn
// NOTE: may not have more than 16
typedef enum {
PERS_SCORE, // !!! MUST NOT CHANGE, SERVER AND GAME BOTH REFERENCE !!!
PERS_HITS, // total points damage inflicted so damage beeps can sound on change
PERS_RANK, // player rank or team rank
PERS_TEAM, // player team
PERS_SPAWN_COUNT, // incremented every respawn
PERS_PLAYEREVENTS, // 16 bits that can be flipped for events
PERS_ATTACKER, // clientnum of last damage inflicter
PERS_ATTACKEE_ARMOR, // health/armor of last person we attacked
PERS_KILLED, // count of the number of times you died
// player awards tracking
PERS_IMPRESSIVE_COUNT, // two railgun hits in a row
PERS_EXCELLENT_COUNT, // two successive kills in a short amount of time
PERS_DEFEND_COUNT, // defend awards
PERS_ASSIST_COUNT, // assist awards
PERS_GAUNTLET_FRAG_COUNT, // kills with the guantlet
PERS_CAPTURES // captures
} persEnum_t;
// entityState_t->eFlags
#define EF_DEAD 0x00000001 // don't draw a foe marker over players with EF_DEAD
#ifdef MISSIONPACK
#define EF_TICKING 0x00000002 // used to make players play the prox mine ticking sound
#endif
#define EF_TELEPORT_BIT 0x00000004 // toggled every time the origin abruptly changes
#define EF_AWARD_EXCELLENT 0x00000008 // draw an excellent sprite
#define EF_PLAYER_EVENT 0x00000010
#define EF_BOUNCE 0x00000010 // for missiles
#define EF_BOUNCE_HALF 0x00000020 // for missiles
#define EF_AWARD_GAUNTLET 0x00000040 // draw a gauntlet sprite
#define EF_NODRAW 0x00000080 // may have an event, but no model (unspawned items)
#define EF_FIRING 0x00000100 // for lightning gun
#define EF_KAMIKAZE 0x00000200
#define EF_MOVER_STOP 0x00000400 // will push otherwise
#define EF_AWARD_CAP 0x00000800 // draw the capture sprite
#define EF_TALK 0x00001000 // draw a talk balloon
#define EF_CONNECTION 0x00002000 // draw a connection trouble sprite
#define EF_VOTED 0x00004000 // already cast a vote
#define EF_AWARD_IMPRESSIVE 0x00008000 // draw an impressive sprite
#define EF_AWARD_DEFEND 0x00010000 // draw a defend sprite
#define EF_AWARD_ASSIST 0x00020000 // draw a assist sprite
#define EF_AWARD_DENIED 0x00040000 // denied
#define EF_TEAMVOTED 0x00080000 // already cast a team vote
// NOTE: may not have more than 16
typedef enum {
PW_NONE,
PW_QUAD,
PW_BATTLESUIT,
PW_HASTE,
PW_INVIS,
PW_REGEN,
PW_FLIGHT,
PW_REDFLAG,
PW_BLUEFLAG,
PW_NEUTRALFLAG,
PW_SCOUT,
PW_GUARD,
PW_DOUBLER,
PW_AMMOREGEN,
PW_INVULNERABILITY,
PW_NUM_POWERUPS
} powerup_t;
typedef enum {
HI_NONE,
HI_TELEPORTER,
HI_MEDKIT,
HI_KAMIKAZE,
HI_PORTAL,
HI_INVULNERABILITY,
HI_NUM_HOLDABLE
} holdable_t;
typedef enum {
WP_NONE,
WP_GAUNTLET,
WP_MACHINEGUN,
WP_SHOTGUN,
WP_GRENADE_LAUNCHER,
WP_ROCKET_LAUNCHER,
WP_LIGHTNING,
WP_RAILGUN,
WP_PLASMAGUN,
WP_BFG,
WP_GRAPPLING_HOOK,
#ifdef MISSIONPACK
WP_NAILGUN,
WP_PROX_LAUNCHER,
WP_CHAINGUN,
#endif
WP_NUM_WEAPONS
} weapon_t;
// reward sounds (stored in ps->persistant[PERS_PLAYEREVENTS])
#define PLAYEREVENT_DENIEDREWARD 0x0001
#define PLAYEREVENT_GAUNTLETREWARD 0x0002
#define PLAYEREVENT_HOLYSHIT 0x0004
// entityState_t->event values
// entity events are for effects that take place reletive
// to an existing entities origin. Very network efficient.
// two bits at the top of the entityState->event field
// will be incremented with each change in the event so
// that an identical event started twice in a row can
// be distinguished. And off the value with ~EV_EVENT_BITS
// to retrieve the actual event number
#define EV_EVENT_BIT1 0x00000100
#define EV_EVENT_BIT2 0x00000200
#define EV_EVENT_BITS (EV_EVENT_BIT1|EV_EVENT_BIT2)
#define EVENT_VALID_MSEC 300
typedef enum {
EV_NONE,
EV_FOOTSTEP,
EV_FOOTSTEP_METAL,
EV_FOOTSPLASH,
EV_FOOTWADE,
EV_SWIM,
EV_STEP_4,
EV_STEP_8,
EV_STEP_12,
EV_STEP_16,
EV_FALL_SHORT,
EV_FALL_MEDIUM,
EV_FALL_FAR,
EV_JUMP_PAD, // boing sound at origin, jump sound on player
EV_JUMP,
EV_WATER_TOUCH, // foot touches
EV_WATER_LEAVE, // foot leaves
EV_WATER_UNDER, // head touches
EV_WATER_CLEAR, // head leaves
EV_ITEM_PICKUP, // normal item pickups are predictable
EV_GLOBAL_ITEM_PICKUP, // powerup / team sounds are broadcast to everyone
EV_NOAMMO,
EV_CHANGE_WEAPON,
EV_FIRE_WEAPON,
EV_USE_ITEM0,
EV_USE_ITEM1,
EV_USE_ITEM2,
EV_USE_ITEM3,
EV_USE_ITEM4,
EV_USE_ITEM5,
EV_USE_ITEM6,
EV_USE_ITEM7,
EV_USE_ITEM8,
EV_USE_ITEM9,
EV_USE_ITEM10,
EV_USE_ITEM11,
EV_USE_ITEM12,
EV_USE_ITEM13,
EV_USE_ITEM14,
EV_USE_ITEM15,
EV_ITEM_RESPAWN,
EV_ITEM_POP,
EV_PLAYER_TELEPORT_IN,
EV_PLAYER_TELEPORT_OUT,
EV_GRENADE_BOUNCE, // eventParm will be the soundindex
EV_GENERAL_SOUND,
EV_GLOBAL_SOUND, // no attenuation
EV_GLOBAL_TEAM_SOUND,
EV_BULLET_HIT_FLESH,
EV_BULLET_HIT_WALL,
EV_MISSILE_HIT,
EV_MISSILE_MISS,
EV_MISSILE_MISS_METAL,
EV_RAILTRAIL,
EV_SHOTGUN,
EV_BULLET, // otherEntity is the shooter
EV_PAIN,
EV_DEATH1,
EV_DEATH2,
EV_DEATH3,
EV_OBITUARY,
EV_POWERUP_QUAD,
EV_POWERUP_BATTLESUIT,
EV_POWERUP_REGEN,
EV_GIB_PLAYER, // gib a previously living player
EV_SCOREPLUM, // score plum
//#ifdef MISSIONPACK
EV_PROXIMITY_MINE_STICK,
EV_PROXIMITY_MINE_TRIGGER,
EV_KAMIKAZE, // kamikaze explodes
EV_OBELISKEXPLODE, // obelisk explodes
EV_OBELISKPAIN, // obelisk is in pain
EV_INVUL_IMPACT, // invulnerability sphere impact
EV_JUICED, // invulnerability juiced effect
EV_LIGHTNINGBOLT, // lightning bolt bounced of invulnerability sphere
//#endif
EV_DEBUG_LINE,
EV_STOPLOOPINGSOUND,
EV_TAUNT,
EV_TAUNT_YES,
EV_TAUNT_NO,
EV_TAUNT_FOLLOWME,
EV_TAUNT_GETFLAG,
EV_TAUNT_GUARDBASE,
EV_TAUNT_PATROL
} entity_event_t;
typedef enum {
GTS_RED_CAPTURE,
GTS_BLUE_CAPTURE,
GTS_RED_RETURN,
GTS_BLUE_RETURN,
GTS_RED_TAKEN,
GTS_BLUE_TAKEN,
GTS_REDOBELISK_ATTACKED,
GTS_BLUEOBELISK_ATTACKED,
GTS_REDTEAM_SCORED,
GTS_BLUETEAM_SCORED,
GTS_REDTEAM_TOOK_LEAD,
GTS_BLUETEAM_TOOK_LEAD,
GTS_TEAMS_ARE_TIED,
GTS_KAMIKAZE
} global_team_sound_t;
// animations
typedef enum {
BOTH_DEATH1,
BOTH_DEAD1,
BOTH_DEATH2,
BOTH_DEAD2,
BOTH_DEATH3,
BOTH_DEAD3,
TORSO_GESTURE,
TORSO_ATTACK,
TORSO_ATTACK2,
TORSO_DROP,
TORSO_RAISE,
TORSO_STAND,
TORSO_STAND2,
LEGS_WALKCR,
LEGS_WALK,
LEGS_RUN,
LEGS_BACK,
LEGS_SWIM,
LEGS_JUMP,
LEGS_LAND,
LEGS_JUMPB,
LEGS_LANDB,
LEGS_IDLE,
LEGS_IDLECR,
LEGS_TURN,
TORSO_GETFLAG,
TORSO_GUARDBASE,
TORSO_PATROL,
TORSO_FOLLOWME,
TORSO_AFFIRMATIVE,
TORSO_NEGATIVE,
MAX_ANIMATIONS,
LEGS_BACKCR,
LEGS_BACKWALK,
FLAG_RUN,
FLAG_STAND,
FLAG_STAND2RUN,
MAX_TOTALANIMATIONS
} animNumber_t;
typedef struct animation_s {
int firstFrame;
int numFrames;
int loopFrames; // 0 to numFrames
int frameLerp; // msec between frames
int initialLerp; // msec to get to first frame
int reversed; // true if animation is reversed
int flipflop; // true if animation should flipflop back to base
} animation_t;
// flip the togglebit every time an animation
// changes so a restart of the same anim can be detected
#define ANIM_TOGGLEBIT 128
typedef enum {
TEAM_FREE,
TEAM_RED,
TEAM_BLUE,
TEAM_SPECTATOR,
TEAM_NUM_TEAMS
} team_t;
// Time between location updates
#define TEAM_LOCATION_UPDATE_TIME 1000
// How many players on the overlay
#define TEAM_MAXOVERLAY 32
//team task
typedef enum {
TEAMTASK_NONE,
TEAMTASK_OFFENSE,
TEAMTASK_DEFENSE,
TEAMTASK_PATROL,
TEAMTASK_FOLLOW,
TEAMTASK_RETRIEVE,
TEAMTASK_ESCORT,
TEAMTASK_CAMP
} teamtask_t;
// means of death
typedef enum {
MOD_UNKNOWN,
MOD_SHOTGUN,
MOD_GAUNTLET,
MOD_MACHINEGUN,
MOD_GRENADE,
MOD_GRENADE_SPLASH,
MOD_ROCKET,
MOD_ROCKET_SPLASH,
MOD_PLASMA,
MOD_PLASMA_SPLASH,
MOD_RAILGUN,
MOD_LIGHTNING,
MOD_BFG,
MOD_BFG_SPLASH,
MOD_WATER,
MOD_SLIME,
MOD_LAVA,
MOD_CRUSH,
MOD_TELEFRAG,
MOD_FALLING,
MOD_SUICIDE,
MOD_TARGET_LASER,
MOD_TRIGGER_HURT,
#ifdef MISSIONPACK
MOD_NAIL,
MOD_CHAINGUN,
MOD_PROXIMITY_MINE,
MOD_KAMIKAZE,
MOD_JUICED,
#endif
MOD_GRAPPLE
} meansOfDeath_t;
//---------------------------------------------------------
// gitem_t->type
typedef enum {
IT_BAD,
IT_WEAPON, // EFX: rotate + upscale + minlight
IT_AMMO, // EFX: rotate
IT_ARMOR, // EFX: rotate + minlight
IT_HEALTH, // EFX: static external sphere + rotating internal
IT_POWERUP, // instant on, timer based
// EFX: rotate + external ring that rotates
IT_HOLDABLE, // single use, holdable item
// EFX: rotate + bob
IT_PERSISTANT_POWERUP,
IT_TEAM
} itemType_t;
#define MAX_ITEM_MODELS 4
typedef struct gitem_s {
char *classname; // spawning name
char *pickup_sound;
char *world_model[MAX_ITEM_MODELS];
char *icon;
char *pickup_name; // for printing on pickup
int quantity; // for ammo how much, or duration of powerup
itemType_t giType; // IT_* flags
int giTag;
char *precaches; // string of all models and images this item will use
char *sounds; // string of all sounds this item will use
} gitem_t;
// included in both the game dll and the client
extern gitem_t bg_itemlist[];
extern int bg_numItems;
gitem_t *BG_FindItem( const char *pickupName );
gitem_t *BG_FindItemForWeapon( weapon_t weapon );
gitem_t *BG_FindItemForPowerup( powerup_t pw );
gitem_t *BG_FindItemForHoldable( holdable_t pw );
#define ITEM_INDEX(x) ((x)-bg_itemlist)
qboolean BG_CanItemBeGrabbed( int gametype, const entityState_t *ent, const playerState_t *ps );
// g_dmflags->integer flags
#define DF_NO_FALLING 8
#define DF_FIXED_FOV 16
#define DF_NO_FOOTSTEPS 32
// content masks
#define MASK_ALL (-1)
#define MASK_SOLID (CONTENTS_SOLID)
#define MASK_PLAYERSOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_BODY)
#define MASK_DEADSOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP)
#define MASK_WATER (CONTENTS_WATER|CONTENTS_LAVA|CONTENTS_SLIME)
#define MASK_OPAQUE (CONTENTS_SOLID|CONTENTS_SLIME|CONTENTS_LAVA)
#define MASK_SHOT (CONTENTS_SOLID|CONTENTS_BODY|CONTENTS_CORPSE)
//
// entityState_t->eType
//
typedef enum {
ET_GENERAL,
ET_PLAYER,
ET_ITEM,
ET_MISSILE,
ET_MOVER,
ET_BEAM,
ET_PORTAL,
ET_SPEAKER,
ET_PUSH_TRIGGER,
ET_TELEPORT_TRIGGER,
ET_INVISIBLE,
ET_GRAPPLE, // grapple hooked on wall
ET_TEAM,
ET_EVENTS // any of the EV_* events can be added freestanding
// by setting eType to ET_EVENTS + eventNum
// this avoids having to set eFlags and eventNum
} entityType_t;
void BG_EvaluateTrajectory( const trajectory_t *tr, int atTime, vec3_t result );
void BG_EvaluateTrajectoryDelta( const trajectory_t *tr, int atTime, vec3_t result );
void BG_AddPredictableEventToPlayerstate( int newEvent, int eventParm, playerState_t *ps );
void BG_TouchJumpPad( playerState_t *ps, entityState_t *jumppad );
void BG_PlayerStateToEntityState( playerState_t *ps, entityState_t *s, qboolean snap );
void BG_PlayerStateToEntityStateExtraPolate( playerState_t *ps, entityState_t *s, int time, qboolean snap );
qboolean BG_PlayerTouchesItem( playerState_t *ps, entityState_t *item, int atTime );
#define ARENAS_PER_TIER 4
#define MAX_ARENAS 1024
#define MAX_ARENAS_TEXT 8192
#define MAX_BOTS 1024
#define MAX_BOTS_TEXT 8192
// Kamikaze
// 1st shockwave times
#define KAMI_SHOCKWAVE_STARTTIME 0
#define KAMI_SHOCKWAVEFADE_STARTTIME 1500
#define KAMI_SHOCKWAVE_ENDTIME 2000
// explosion/implosion times
#define KAMI_EXPLODE_STARTTIME 250
#define KAMI_IMPLODE_STARTTIME 2000
#define KAMI_IMPLODE_ENDTIME 2250
// 2nd shockwave times
#define KAMI_SHOCKWAVE2_STARTTIME 2000
#define KAMI_SHOCKWAVE2FADE_STARTTIME 2500
#define KAMI_SHOCKWAVE2_ENDTIME 3000
// radius of the models without scaling
#define KAMI_SHOCKWAVEMODEL_RADIUS 88
#define KAMI_BOOMSPHEREMODEL_RADIUS 72
// maximum radius of the models during the effect
#define KAMI_SHOCKWAVE_MAXRADIUS 1320
#define KAMI_BOOMSPHERE_MAXRADIUS 720
#define KAMI_SHOCKWAVE2_MAXRADIUS 704

325
code/game/bg_slidemove.c Normal file
View file

@ -0,0 +1,325 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// bg_slidemove.c -- part of bg_pmove functionality
#include "q_shared.h"
#include "bg_public.h"
#include "bg_local.h"
/*
input: origin, velocity, bounds, groundPlane, trace function
output: origin, velocity, impacts, stairup boolean
*/
/*
==================
PM_SlideMove
Returns qtrue if the velocity was clipped in some way
==================
*/
#define MAX_CLIP_PLANES 5
qboolean PM_SlideMove( qboolean gravity ) {
int bumpcount, numbumps;
vec3_t dir;
float d;
int numplanes;
vec3_t planes[MAX_CLIP_PLANES];
vec3_t primal_velocity;
vec3_t clipVelocity;
int i, j, k;
trace_t trace;
vec3_t end;
float time_left;
float into;
vec3_t endVelocity;
vec3_t endClipVelocity;
numbumps = 4;
VectorCopy (pm->ps->velocity, primal_velocity);
if ( gravity ) {
VectorCopy( pm->ps->velocity, endVelocity );
endVelocity[2] -= pm->ps->gravity * pml.frametime;
pm->ps->velocity[2] = ( pm->ps->velocity[2] + endVelocity[2] ) * 0.5;
primal_velocity[2] = endVelocity[2];
if ( pml.groundPlane ) {
// slide along the ground plane
PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal,
pm->ps->velocity, OVERCLIP );
}
}
time_left = pml.frametime;
// never turn against the ground plane
if ( pml.groundPlane ) {
numplanes = 1;
VectorCopy( pml.groundTrace.plane.normal, planes[0] );
} else {
numplanes = 0;
}
// never turn against original velocity
VectorNormalize2( pm->ps->velocity, planes[numplanes] );
numplanes++;
for ( bumpcount=0 ; bumpcount < numbumps ; bumpcount++ ) {
// calculate position we are trying to move to
VectorMA( pm->ps->origin, time_left, pm->ps->velocity, end );
// see if we can make it there
pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemask);
if (trace.allsolid) {
// entity is completely trapped in another solid
pm->ps->velocity[2] = 0; // don't build up falling damage, but allow sideways acceleration
return qtrue;
}
if (trace.fraction > 0) {
// actually covered some distance
VectorCopy (trace.endpos, pm->ps->origin);
}
if (trace.fraction == 1) {
break; // moved the entire distance
}
// save entity for contact
PM_AddTouchEnt( trace.entityNum );
time_left -= time_left * trace.fraction;
if (numplanes >= MAX_CLIP_PLANES) {
// this shouldn't really happen
VectorClear( pm->ps->velocity );
return qtrue;
}
//
// if this is the same plane we hit before, nudge velocity
// out along it, which fixes some epsilon issues with
// non-axial planes
//
for ( i = 0 ; i < numplanes ; i++ ) {
if ( DotProduct( trace.plane.normal, planes[i] ) > 0.99 ) {
VectorAdd( trace.plane.normal, pm->ps->velocity, pm->ps->velocity );
break;
}
}
if ( i < numplanes ) {
continue;
}
VectorCopy (trace.plane.normal, planes[numplanes]);
numplanes++;
//
// modify velocity so it parallels all of the clip planes
//
// find a plane that it enters
for ( i = 0 ; i < numplanes ; i++ ) {
into = DotProduct( pm->ps->velocity, planes[i] );
if ( into >= 0.1 ) {
continue; // move doesn't interact with the plane
}
// see how hard we are hitting things
if ( -into > pml.impactSpeed ) {
pml.impactSpeed = -into;
}
// slide along the plane
PM_ClipVelocity (pm->ps->velocity, planes[i], clipVelocity, OVERCLIP );
// slide along the plane
PM_ClipVelocity (endVelocity, planes[i], endClipVelocity, OVERCLIP );
// see if there is a second plane that the new move enters
for ( j = 0 ; j < numplanes ; j++ ) {
if ( j == i ) {
continue;
}
if ( DotProduct( clipVelocity, planes[j] ) >= 0.1 ) {
continue; // move doesn't interact with the plane
}
// try clipping the move to the plane
PM_ClipVelocity( clipVelocity, planes[j], clipVelocity, OVERCLIP );
PM_ClipVelocity( endClipVelocity, planes[j], endClipVelocity, OVERCLIP );
// see if it goes back into the first clip plane
if ( DotProduct( clipVelocity, planes[i] ) >= 0 ) {
continue;
}
// slide the original velocity along the crease
CrossProduct (planes[i], planes[j], dir);
VectorNormalize( dir );
d = DotProduct( dir, pm->ps->velocity );
VectorScale( dir, d, clipVelocity );
CrossProduct (planes[i], planes[j], dir);
VectorNormalize( dir );
d = DotProduct( dir, endVelocity );
VectorScale( dir, d, endClipVelocity );
// see if there is a third plane the the new move enters
for ( k = 0 ; k < numplanes ; k++ ) {
if ( k == i || k == j ) {
continue;
}
if ( DotProduct( clipVelocity, planes[k] ) >= 0.1 ) {
continue; // move doesn't interact with the plane
}
// stop dead at a tripple plane interaction
VectorClear( pm->ps->velocity );
return qtrue;
}
}
// if we have fixed all interactions, try another move
VectorCopy( clipVelocity, pm->ps->velocity );
VectorCopy( endClipVelocity, endVelocity );
break;
}
}
if ( gravity ) {
VectorCopy( endVelocity, pm->ps->velocity );
}
// don't change velocity if in a timer (FIXME: is this correct?)
if ( pm->ps->pm_time ) {
VectorCopy( primal_velocity, pm->ps->velocity );
}
return ( bumpcount != 0 );
}
/*
==================
PM_StepSlideMove
==================
*/
void PM_StepSlideMove( qboolean gravity ) {
vec3_t start_o, start_v;
vec3_t down_o, down_v;
trace_t trace;
// float down_dist, up_dist;
// vec3_t delta, delta2;
vec3_t up, down;
float stepSize;
VectorCopy (pm->ps->origin, start_o);
VectorCopy (pm->ps->velocity, start_v);
if ( PM_SlideMove( gravity ) == 0 ) {
return; // we got exactly where we wanted to go first try
}
VectorCopy(start_o, down);
down[2] -= STEPSIZE;
pm->trace (&trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask);
VectorSet(up, 0, 0, 1);
// never step up when you still have up velocity
if ( pm->ps->velocity[2] > 0 && (trace.fraction == 1.0 ||
DotProduct(trace.plane.normal, up) < 0.7)) {
return;
}
VectorCopy (pm->ps->origin, down_o);
VectorCopy (pm->ps->velocity, down_v);
VectorCopy (start_o, up);
up[2] += STEPSIZE;
// test the player position if they were a stepheight higher
pm->trace (&trace, start_o, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask);
if ( trace.allsolid ) {
if ( pm->debugLevel ) {
Com_Printf("%i:bend can't step\n", c_pmove);
}
return; // can't step up
}
stepSize = trace.endpos[2] - start_o[2];
// try slidemove from this position
VectorCopy (trace.endpos, pm->ps->origin);
VectorCopy (start_v, pm->ps->velocity);
PM_SlideMove( gravity );
// push down the final amount
VectorCopy (pm->ps->origin, down);
down[2] -= stepSize;
pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask);
if ( !trace.allsolid ) {
VectorCopy (trace.endpos, pm->ps->origin);
}
if ( trace.fraction < 1.0 ) {
PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP );
}
#if 0
// if the down trace can trace back to the original position directly, don't step
pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, start_o, pm->ps->clientNum, pm->tracemask);
if ( trace.fraction == 1.0 ) {
// use the original move
VectorCopy (down_o, pm->ps->origin);
VectorCopy (down_v, pm->ps->velocity);
if ( pm->debugLevel ) {
Com_Printf("%i:bend\n", c_pmove);
}
} else
#endif
{
// use the step move
float delta;
delta = pm->ps->origin[2] - start_o[2];
if ( delta > 2 ) {
if ( delta < 7 ) {
PM_AddEvent( EV_STEP_4 );
} else if ( delta < 11 ) {
PM_AddEvent( EV_STEP_8 );
} else if ( delta < 15 ) {
PM_AddEvent( EV_STEP_12 );
} else {
PM_AddEvent( EV_STEP_16 );
}
}
if ( pm->debugLevel ) {
Com_Printf("%i:stepped\n", c_pmove);
}
}
}

516
code/game/botlib.h Normal file
View file

@ -0,0 +1,516 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
/*****************************************************************************
* name: botlib.h
*
* desc: bot AI library
*
* $Archive: /source/code/game/botai.h $
*
*****************************************************************************/
#define BOTLIB_API_VERSION 2
struct aas_clientmove_s;
struct aas_entityinfo_s;
struct aas_areainfo_s;
struct aas_altroutegoal_s;
struct aas_predictroute_s;
struct bot_consolemessage_s;
struct bot_match_s;
struct bot_goal_s;
struct bot_moveresult_s;
struct bot_initmove_s;
struct weaponinfo_s;
#define BOTFILESBASEFOLDER "botfiles"
//debug line colors
#define LINECOLOR_NONE -1
#define LINECOLOR_RED 1//0xf2f2f0f0L
#define LINECOLOR_GREEN 2//0xd0d1d2d3L
#define LINECOLOR_BLUE 3//0xf3f3f1f1L
#define LINECOLOR_YELLOW 4//0xdcdddedfL
#define LINECOLOR_ORANGE 5//0xe0e1e2e3L
//Print types
#define PRT_MESSAGE 1
#define PRT_WARNING 2
#define PRT_ERROR 3
#define PRT_FATAL 4
#define PRT_EXIT 5
//console message types
#define CMS_NORMAL 0
#define CMS_CHAT 1
//botlib error codes
#define BLERR_NOERROR 0 //no error
#define BLERR_LIBRARYNOTSETUP 1 //library not setup
#define BLERR_INVALIDENTITYNUMBER 2 //invalid entity number
#define BLERR_NOAASFILE 3 //no AAS file available
#define BLERR_CANNOTOPENAASFILE 4 //cannot open AAS file
#define BLERR_WRONGAASFILEID 5 //incorrect AAS file id
#define BLERR_WRONGAASFILEVERSION 6 //incorrect AAS file version
#define BLERR_CANNOTREADAASLUMP 7 //cannot read AAS file lump
#define BLERR_CANNOTLOADICHAT 8 //cannot load initial chats
#define BLERR_CANNOTLOADITEMWEIGHTS 9 //cannot load item weights
#define BLERR_CANNOTLOADITEMCONFIG 10 //cannot load item config
#define BLERR_CANNOTLOADWEAPONWEIGHTS 11 //cannot load weapon weights
#define BLERR_CANNOTLOADWEAPONCONFIG 12 //cannot load weapon config
//action flags
#define ACTION_ATTACK 0x0000001
#define ACTION_USE 0x0000002
#define ACTION_RESPAWN 0x0000008
#define ACTION_JUMP 0x0000010
#define ACTION_MOVEUP 0x0000020
#define ACTION_CROUCH 0x0000080
#define ACTION_MOVEDOWN 0x0000100
#define ACTION_MOVEFORWARD 0x0000200
#define ACTION_MOVEBACK 0x0000800
#define ACTION_MOVELEFT 0x0001000
#define ACTION_MOVERIGHT 0x0002000
#define ACTION_DELAYEDJUMP 0x0008000
#define ACTION_TALK 0x0010000
#define ACTION_GESTURE 0x0020000
#define ACTION_WALK 0x0080000
#define ACTION_AFFIRMATIVE 0x0100000
#define ACTION_NEGATIVE 0x0200000
#define ACTION_GETFLAG 0x0800000
#define ACTION_GUARDBASE 0x1000000
#define ACTION_PATROL 0x2000000
#define ACTION_FOLLOWME 0x8000000
//the bot input, will be converted to an usercmd_t
typedef struct bot_input_s
{
float thinktime; //time since last output (in seconds)
vec3_t dir; //movement direction
float speed; //speed in the range [0, 400]
vec3_t viewangles; //the view angles
int actionflags; //one of the ACTION_? flags
int weapon; //weapon to use
} bot_input_t;
#ifndef BSPTRACE
#define BSPTRACE
//bsp_trace_t hit surface
typedef struct bsp_surface_s
{
char name[16];
int flags;
int value;
} bsp_surface_t;
//remove the bsp_trace_s structure definition l8r on
//a trace is returned when a box is swept through the world
typedef struct bsp_trace_s
{
qboolean allsolid; // if true, plane is not valid
qboolean startsolid; // if true, the initial point was in a solid area
float fraction; // time completed, 1.0 = didn't hit anything
vec3_t endpos; // final position
cplane_t plane; // surface normal at impact
float exp_dist; // expanded plane distance
int sidenum; // number of the brush side hit
bsp_surface_t surface; // the hit point surface
int contents; // contents on other side of surface hit
int ent; // number of entity hit
} bsp_trace_t;
#endif // BSPTRACE
//entity state
typedef struct bot_entitystate_s
{
int type; // entity type
int flags; // entity flags
vec3_t origin; // origin of the entity
vec3_t angles; // angles of the model
vec3_t old_origin; // for lerping
vec3_t mins; // bounding box minimums
vec3_t maxs; // bounding box maximums
int groundent; // ground entity
int solid; // solid type
int modelindex; // model used
int modelindex2; // weapons, CTF flags, etc
int frame; // model frame number
int event; // impulse events -- muzzle flashes, footsteps, etc
int eventParm; // even parameter
int powerups; // bit flags
int weapon; // determines weapon and flash model, etc
int legsAnim; // mask off ANIM_TOGGLEBIT
int torsoAnim; // mask off ANIM_TOGGLEBIT
} bot_entitystate_t;
//bot AI library exported functions
typedef struct botlib_import_s
{
//print messages from the bot library
void (QDECL *Print)(int type, char *fmt, ...);
//trace a bbox through the world
void (*Trace)(bsp_trace_t *trace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask);
//trace a bbox against a specific entity
void (*EntityTrace)(bsp_trace_t *trace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int entnum, int contentmask);
//retrieve the contents at the given point
int (*PointContents)(vec3_t point);
//check if the point is in potential visible sight
int (*inPVS)(vec3_t p1, vec3_t p2);
//retrieve the BSP entity data lump
char *(*BSPEntityData)(void);
//
void (*BSPModelMinsMaxsOrigin)(int modelnum, vec3_t angles, vec3_t mins, vec3_t maxs, vec3_t origin);
//send a bot client command
void (*BotClientCommand)(int client, char *command);
//memory allocation
void *(*GetMemory)(int size); // allocate from Zone
void (*FreeMemory)(void *ptr); // free memory from Zone
int (*AvailableMemory)(void); // available Zone memory
void *(*HunkAlloc)(int size); // allocate from hunk
//file system access
int (*FS_FOpenFile)( const char *qpath, fileHandle_t *file, fsMode_t mode );
int (*FS_Read)( void *buffer, int len, fileHandle_t f );
int (*FS_Write)( const void *buffer, int len, fileHandle_t f );
void (*FS_FCloseFile)( fileHandle_t f );
int (*FS_Seek)( fileHandle_t f, long offset, int origin );
//debug visualisation stuff
int (*DebugLineCreate)(void);
void (*DebugLineDelete)(int line);
void (*DebugLineShow)(int line, vec3_t start, vec3_t end, int color);
//
int (*DebugPolygonCreate)(int color, int numPoints, vec3_t *points);
void (*DebugPolygonDelete)(int id);
} botlib_import_t;
typedef struct aas_export_s
{
//-----------------------------------
// be_aas_entity.h
//-----------------------------------
void (*AAS_EntityInfo)(int entnum, struct aas_entityinfo_s *info);
//-----------------------------------
// be_aas_main.h
//-----------------------------------
int (*AAS_Initialized)(void);
void (*AAS_PresenceTypeBoundingBox)(int presencetype, vec3_t mins, vec3_t maxs);
float (*AAS_Time)(void);
//--------------------------------------------
// be_aas_sample.c
//--------------------------------------------
int (*AAS_PointAreaNum)(vec3_t point);
int (*AAS_PointReachabilityAreaIndex)( vec3_t point );
int (*AAS_TraceAreas)(vec3_t start, vec3_t end, int *areas, vec3_t *points, int maxareas);
int (*AAS_BBoxAreas)(vec3_t absmins, vec3_t absmaxs, int *areas, int maxareas);
int (*AAS_AreaInfo)( int areanum, struct aas_areainfo_s *info );
//--------------------------------------------
// be_aas_bspq3.c
//--------------------------------------------
int (*AAS_PointContents)(vec3_t point);
int (*AAS_NextBSPEntity)(int ent);
int (*AAS_ValueForBSPEpairKey)(int ent, char *key, char *value, int size);
int (*AAS_VectorForBSPEpairKey)(int ent, char *key, vec3_t v);
int (*AAS_FloatForBSPEpairKey)(int ent, char *key, float *value);
int (*AAS_IntForBSPEpairKey)(int ent, char *key, int *value);
//--------------------------------------------
// be_aas_reach.c
//--------------------------------------------
int (*AAS_AreaReachability)(int areanum);
//--------------------------------------------
// be_aas_route.c
//--------------------------------------------
int (*AAS_AreaTravelTimeToGoalArea)(int areanum, vec3_t origin, int goalareanum, int travelflags);
int (*AAS_EnableRoutingArea)(int areanum, int enable);
int (*AAS_PredictRoute)(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);
//--------------------------------------------
// be_aas_altroute.c
//--------------------------------------------
int (*AAS_AlternativeRouteGoals)(vec3_t start, int startareanum, vec3_t goal, int goalareanum, int travelflags,
struct aas_altroutegoal_s *altroutegoals, int maxaltroutegoals,
int type);
//--------------------------------------------
// be_aas_move.c
//--------------------------------------------
int (*AAS_Swimming)(vec3_t origin);
int (*AAS_PredictClientMovement)(struct 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);
} aas_export_t;
typedef struct ea_export_s
{
//ClientCommand elementary actions
void (*EA_Command)(int client, char *command );
void (*EA_Say)(int client, char *str);
void (*EA_SayTeam)(int client, char *str);
//
void (*EA_Action)(int client, int action);
void (*EA_Gesture)(int client);
void (*EA_Talk)(int client);
void (*EA_Attack)(int client);
void (*EA_Use)(int client);
void (*EA_Respawn)(int client);
void (*EA_MoveUp)(int client);
void (*EA_MoveDown)(int client);
void (*EA_MoveForward)(int client);
void (*EA_MoveBack)(int client);
void (*EA_MoveLeft)(int client);
void (*EA_MoveRight)(int client);
void (*EA_Crouch)(int client);
void (*EA_SelectWeapon)(int client, int weapon);
void (*EA_Jump)(int client);
void (*EA_DelayedJump)(int client);
void (*EA_Move)(int client, vec3_t dir, float speed);
void (*EA_View)(int client, vec3_t viewangles);
//send regular input to the server
void (*EA_EndRegular)(int client, float thinktime);
void (*EA_GetInput)(int client, float thinktime, bot_input_t *input);
void (*EA_ResetInput)(int client);
} ea_export_t;
typedef struct ai_export_s
{
//-----------------------------------
// be_ai_char.h
//-----------------------------------
int (*BotLoadCharacter)(char *charfile, float skill);
void (*BotFreeCharacter)(int character);
float (*Characteristic_Float)(int character, int index);
float (*Characteristic_BFloat)(int character, int index, float min, float max);
int (*Characteristic_Integer)(int character, int index);
int (*Characteristic_BInteger)(int character, int index, int min, int max);
void (*Characteristic_String)(int character, int index, char *buf, int size);
//-----------------------------------
// be_ai_chat.h
//-----------------------------------
int (*BotAllocChatState)(void);
void (*BotFreeChatState)(int handle);
void (*BotQueueConsoleMessage)(int chatstate, int type, char *message);
void (*BotRemoveConsoleMessage)(int chatstate, int handle);
int (*BotNextConsoleMessage)(int chatstate, struct bot_consolemessage_s *cm);
int (*BotNumConsoleMessages)(int chatstate);
void (*BotInitialChat)(int chatstate, char *type, int mcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7);
int (*BotNumInitialChats)(int chatstate, char *type);
int (*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 (*BotChatLength)(int chatstate);
void (*BotEnterChat)(int chatstate, int client, int sendto);
void (*BotGetChatMessage)(int chatstate, char *buf, int size);
int (*StringContains)(char *str1, char *str2, int casesensitive);
int (*BotFindMatch)(char *str, struct bot_match_s *match, unsigned long int context);
void (*BotMatchVariable)(struct bot_match_s *match, int variable, char *buf, int size);
void (*UnifyWhiteSpaces)(char *string);
void (*BotReplaceSynonyms)(char *string, unsigned long int context);
int (*BotLoadChatFile)(int chatstate, char *chatfile, char *chatname);
void (*BotSetChatGender)(int chatstate, int gender);
void (*BotSetChatName)(int chatstate, char *name, int client);
//-----------------------------------
// be_ai_goal.h
//-----------------------------------
void (*BotResetGoalState)(int goalstate);
void (*BotResetAvoidGoals)(int goalstate);
void (*BotRemoveFromAvoidGoals)(int goalstate, int number);
void (*BotPushGoal)(int goalstate, struct bot_goal_s *goal);
void (*BotPopGoal)(int goalstate);
void (*BotEmptyGoalStack)(int goalstate);
void (*BotDumpAvoidGoals)(int goalstate);
void (*BotDumpGoalStack)(int goalstate);
void (*BotGoalName)(int number, char *name, int size);
int (*BotGetTopGoal)(int goalstate, struct bot_goal_s *goal);
int (*BotGetSecondGoal)(int goalstate, struct bot_goal_s *goal);
int (*BotChooseLTGItem)(int goalstate, vec3_t origin, int *inventory, int travelflags);
int (*BotChooseNBGItem)(int goalstate, vec3_t origin, int *inventory, int travelflags,
struct bot_goal_s *ltg, float maxtime);
int (*BotTouchingGoal)(vec3_t origin, struct bot_goal_s *goal);
int (*BotItemGoalInVisButNotVisible)(int viewer, vec3_t eye, vec3_t viewangles, struct bot_goal_s *goal);
int (*BotGetLevelItemGoal)(int index, char *classname, struct bot_goal_s *goal);
int (*BotGetNextCampSpotGoal)(int num, struct bot_goal_s *goal);
int (*BotGetMapLocationGoal)(char *name, struct bot_goal_s *goal);
float (*BotAvoidGoalTime)(int goalstate, int number);
void (*BotSetAvoidGoalTime)(int goalstate, int number, float avoidtime);
void (*BotInitLevelItems)(void);
void (*BotUpdateEntityItems)(void);
int (*BotLoadItemWeights)(int goalstate, char *filename);
void (*BotFreeItemWeights)(int goalstate);
void (*BotInterbreedGoalFuzzyLogic)(int parent1, int parent2, int child);
void (*BotSaveGoalFuzzyLogic)(int goalstate, char *filename);
void (*BotMutateGoalFuzzyLogic)(int goalstate, float range);
int (*BotAllocGoalState)(int client);
void (*BotFreeGoalState)(int handle);
//-----------------------------------
// be_ai_move.h
//-----------------------------------
void (*BotResetMoveState)(int movestate);
void (*BotMoveToGoal)(struct bot_moveresult_s *result, int movestate, struct bot_goal_s *goal, int travelflags);
int (*BotMoveInDirection)(int movestate, vec3_t dir, float speed, int type);
void (*BotResetAvoidReach)(int movestate);
void (*BotResetLastAvoidReach)(int movestate);
int (*BotReachabilityArea)(vec3_t origin, int testground);
int (*BotMovementViewTarget)(int movestate, struct bot_goal_s *goal, int travelflags, float lookahead, vec3_t target);
int (*BotPredictVisiblePosition)(vec3_t origin, int areanum, struct bot_goal_s *goal, int travelflags, vec3_t target);
int (*BotAllocMoveState)(void);
void (*BotFreeMoveState)(int handle);
void (*BotInitMoveState)(int handle, struct bot_initmove_s *initmove);
void (*BotAddAvoidSpot)(int movestate, vec3_t origin, float radius, int type);
//-----------------------------------
// be_ai_weap.h
//-----------------------------------
int (*BotChooseBestFightWeapon)(int weaponstate, int *inventory);
void (*BotGetWeaponInfo)(int weaponstate, int weapon, struct weaponinfo_s *weaponinfo);
int (*BotLoadWeaponWeights)(int weaponstate, char *filename);
int (*BotAllocWeaponState)(void);
void (*BotFreeWeaponState)(int weaponstate);
void (*BotResetWeaponState)(int weaponstate);
//-----------------------------------
// be_ai_gen.h
//-----------------------------------
int (*GeneticParentsAndChildSelection)(int numranks, float *ranks, int *parent1, int *parent2, int *child);
} ai_export_t;
//bot AI library imported functions
typedef struct botlib_export_s
{
//Area Awareness System functions
aas_export_t aas;
//Elementary Action functions
ea_export_t ea;
//AI functions
ai_export_t ai;
//setup the bot library, returns BLERR_
int (*BotLibSetup)(void);
//shutdown the bot library, returns BLERR_
int (*BotLibShutdown)(void);
//sets a library variable returns BLERR_
int (*BotLibVarSet)(char *var_name, char *value);
//gets a library variable returns BLERR_
int (*BotLibVarGet)(char *var_name, char *value, int size);
//sets a C-like define returns BLERR_
int (*PC_AddGlobalDefine)(char *string);
int (*PC_LoadSourceHandle)(const char *filename);
int (*PC_FreeSourceHandle)(int handle);
int (*PC_ReadTokenHandle)(int handle, pc_token_t *pc_token);
int (*PC_SourceFileAndLine)(int handle, char *filename, int *line);
//start a frame in the bot library
int (*BotLibStartFrame)(float time);
//load a new map in the bot library
int (*BotLibLoadMap)(const char *mapname);
//entity updates
int (*BotLibUpdateEntity)(int ent, bot_entitystate_t *state);
//just for testing
int (*Test)(int parm0, char *parm1, vec3_t parm2, vec3_t parm3);
} botlib_export_t;
//linking of bot library
botlib_export_t *GetBotLibAPI( int apiVersion, botlib_import_t *import );
/* Library variables:
name: default: module(s): description:
"basedir" "" l_utils.c base directory
"gamedir" "" l_utils.c game directory
"cddir" "" l_utils.c CD directory
"log" "0" l_log.c enable/disable creating a log file
"maxclients" "4" be_interface.c maximum number of clients
"maxentities" "1024" be_interface.c maximum number of entities
"bot_developer" "0" be_interface.c bot developer mode
"phys_friction" "6" be_aas_move.c ground friction
"phys_stopspeed" "100" be_aas_move.c stop speed
"phys_gravity" "800" be_aas_move.c gravity value
"phys_waterfriction" "1" be_aas_move.c water friction
"phys_watergravity" "400" be_aas_move.c gravity in water
"phys_maxvelocity" "320" be_aas_move.c maximum velocity
"phys_maxwalkvelocity" "320" be_aas_move.c maximum walk velocity
"phys_maxcrouchvelocity" "100" be_aas_move.c maximum crouch velocity
"phys_maxswimvelocity" "150" be_aas_move.c maximum swim velocity
"phys_walkaccelerate" "10" be_aas_move.c walk acceleration
"phys_airaccelerate" "1" be_aas_move.c air acceleration
"phys_swimaccelerate" "4" be_aas_move.c swim acceleration
"phys_maxstep" "18" be_aas_move.c maximum step height
"phys_maxsteepness" "0.7" be_aas_move.c maximum floor steepness
"phys_maxbarrier" "32" be_aas_move.c maximum barrier height
"phys_maxwaterjump" "19" be_aas_move.c maximum waterjump height
"phys_jumpvel" "270" be_aas_move.c jump z velocity
"phys_falldelta5" "40" be_aas_move.c
"phys_falldelta10" "60" be_aas_move.c
"rs_waterjump" "400" be_aas_move.c
"rs_teleport" "50" be_aas_move.c
"rs_barrierjump" "100" be_aas_move.c
"rs_startcrouch" "300" be_aas_move.c
"rs_startgrapple" "500" be_aas_move.c
"rs_startwalkoffledge" "70" be_aas_move.c
"rs_startjump" "300" be_aas_move.c
"rs_rocketjump" "500" be_aas_move.c
"rs_bfgjump" "500" be_aas_move.c
"rs_jumppad" "250" be_aas_move.c
"rs_aircontrolledjumppad" "300" be_aas_move.c
"rs_funcbob" "300" be_aas_move.c
"rs_startelevator" "50" be_aas_move.c
"rs_falldamage5" "300" be_aas_move.c
"rs_falldamage10" "500" be_aas_move.c
"rs_maxjumpfallheight" "450" be_aas_move.c
"max_aaslinks" "4096" be_aas_sample.c maximum links in the AAS
"max_routingcache" "4096" be_aas_route.c maximum routing cache size in KB
"forceclustering" "0" be_aas_main.c force recalculation of clusters
"forcereachability" "0" be_aas_main.c force recalculation of reachabilities
"forcewrite" "0" be_aas_main.c force writing of aas file
"aasoptimize" "0" be_aas_main.c enable aas optimization
"sv_mapChecksum" "0" be_aas_main.c BSP file checksum
"bot_visualizejumppads" "0" be_aas_reach.c visualize jump pads
"bot_reloadcharacters" "0" - reload bot character files
"ai_gametype" "0" be_ai_goal.c game type
"droppedweight" "1000" be_ai_goal.c additional dropped item weight
"weapindex_rocketlauncher" "5" be_ai_move.c rl weapon index for rocket jumping
"weapindex_bfg10k" "9" be_ai_move.c bfg weapon index for bfg jumping
"weapindex_grapple" "10" be_ai_move.c grapple weapon index for grappling
"entitytypemissile" "3" be_ai_move.c ET_MISSILE
"offhandgrapple" "0" be_ai_move.c enable off hand grapple hook
"cmd_grappleon" "grappleon" be_ai_move.c command to activate off hand grapple
"cmd_grappleoff" "grappleoff" be_ai_move.c command to deactivate off hand grapple
"itemconfig" "items.c" be_ai_goal.c item configuration file
"weaponconfig" "weapons.c" be_ai_weap.c weapon configuration file
"synfile" "syn.c" be_ai_chat.c file with synonyms
"rndfile" "rnd.c" be_ai_chat.c file with random strings
"matchfile" "match.c" be_ai_chat.c file with match strings
"nochat" "0" be_ai_chat.c disable chats
"max_messages" "1024" be_ai_chat.c console message heap size
"max_weaponinfo" "32" be_ai_weap.c maximum number of weapon info
"max_projectileinfo" "32" be_ai_weap.c maximum number of projectile info
"max_iteminfo" "256" be_ai_goal.c maximum number of item info
"max_levelitems" "256" be_ai_goal.c maximum number of level items
*/

134
code/game/chars.h Normal file
View file

@ -0,0 +1,134 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//========================================================
//========================================================
//name
#define CHARACTERISTIC_NAME 0 //string
//gender of the bot
#define CHARACTERISTIC_GENDER 1 //string ("male", "female", "it")
//attack skill
// > 0.0 && < 0.2 = don't move
// > 0.3 && < 1.0 = aim at enemy during retreat
// > 0.0 && < 0.4 = only move forward/backward
// >= 0.4 && < 1.0 = circle strafing
// > 0.7 && < 1.0 = random strafe direction change
#define CHARACTERISTIC_ATTACK_SKILL 2 //float [0, 1]
//weapon weight file
#define CHARACTERISTIC_WEAPONWEIGHTS 3 //string
//view angle difference to angle change factor
#define CHARACTERISTIC_VIEW_FACTOR 4 //float <0, 1]
//maximum view angle change
#define CHARACTERISTIC_VIEW_MAXCHANGE 5 //float [1, 360]
//reaction time in seconds
#define CHARACTERISTIC_REACTIONTIME 6 //float [0, 5]
//accuracy when aiming
#define CHARACTERISTIC_AIM_ACCURACY 7 //float [0, 1]
//weapon specific aim accuracy
#define CHARACTERISTIC_AIM_ACCURACY_MACHINEGUN 8 //float [0, 1]
#define CHARACTERISTIC_AIM_ACCURACY_SHOTGUN 9 //float [0, 1]
#define CHARACTERISTIC_AIM_ACCURACY_ROCKETLAUNCHER 10 //float [0, 1]
#define CHARACTERISTIC_AIM_ACCURACY_GRENADELAUNCHER 11 //float [0, 1]
#define CHARACTERISTIC_AIM_ACCURACY_LIGHTNING 12
#define CHARACTERISTIC_AIM_ACCURACY_PLASMAGUN 13 //float [0, 1]
#define CHARACTERISTIC_AIM_ACCURACY_RAILGUN 14
#define CHARACTERISTIC_AIM_ACCURACY_BFG10K 15 //float [0, 1]
//skill when aiming
// > 0.0 && < 0.9 = aim is affected by enemy movement
// > 0.4 && <= 0.8 = enemy linear leading
// > 0.8 && <= 1.0 = enemy exact movement leading
// > 0.5 && <= 1.0 = prediction shots when enemy is not visible
// > 0.6 && <= 1.0 = splash damage by shooting nearby geometry
#define CHARACTERISTIC_AIM_SKILL 16 //float [0, 1]
//weapon specific aim skill
#define CHARACTERISTIC_AIM_SKILL_ROCKETLAUNCHER 17 //float [0, 1]
#define CHARACTERISTIC_AIM_SKILL_GRENADELAUNCHER 18 //float [0, 1]
#define CHARACTERISTIC_AIM_SKILL_PLASMAGUN 19 //float [0, 1]
#define CHARACTERISTIC_AIM_SKILL_BFG10K 20 //float [0, 1]
//========================================================
//chat
//========================================================
//file with chats
#define CHARACTERISTIC_CHAT_FILE 21 //string
//name of the chat character
#define CHARACTERISTIC_CHAT_NAME 22 //string
//characters per minute type speed
#define CHARACTERISTIC_CHAT_CPM 23 //integer [1, 4000]
//tendency to insult/praise
#define CHARACTERISTIC_CHAT_INSULT 24 //float [0, 1]
//tendency to chat misc
#define CHARACTERISTIC_CHAT_MISC 25 //float [0, 1]
//tendency to chat at start or end of level
#define CHARACTERISTIC_CHAT_STARTENDLEVEL 26 //float [0, 1]
//tendency to chat entering or exiting the game
#define CHARACTERISTIC_CHAT_ENTEREXITGAME 27 //float [0, 1]
//tendency to chat when killed someone
#define CHARACTERISTIC_CHAT_KILL 28 //float [0, 1]
//tendency to chat when died
#define CHARACTERISTIC_CHAT_DEATH 29 //float [0, 1]
//tendency to chat when enemy suicides
#define CHARACTERISTIC_CHAT_ENEMYSUICIDE 30 //float [0, 1]
//tendency to chat when hit while talking
#define CHARACTERISTIC_CHAT_HITTALKING 31 //float [0, 1]
//tendency to chat when bot was hit but didn't dye
#define CHARACTERISTIC_CHAT_HITNODEATH 32 //float [0, 1]
//tendency to chat when bot hit the enemy but enemy didn't dye
#define CHARACTERISTIC_CHAT_HITNOKILL 33 //float [0, 1]
//tendency to randomly chat
#define CHARACTERISTIC_CHAT_RANDOM 34 //float [0, 1]
//tendency to reply
#define CHARACTERISTIC_CHAT_REPLY 35 //float [0, 1]
//========================================================
//movement
//========================================================
//tendency to crouch
#define CHARACTERISTIC_CROUCHER 36 //float [0, 1]
//tendency to jump
#define CHARACTERISTIC_JUMPER 37 //float [0, 1]
//tendency to walk
#define CHARACTERISTIC_WALKER 48 //float [0, 1]
//tendency to jump using a weapon
#define CHARACTERISTIC_WEAPONJUMPING 38 //float [0, 1]
//tendency to use the grapple hook when available
#define CHARACTERISTIC_GRAPPLE_USER 39 //float [0, 1] //use this!!
//========================================================
//goal
//========================================================
//item weight file
#define CHARACTERISTIC_ITEMWEIGHTS 40 //string
//the aggression of the bot
#define CHARACTERISTIC_AGGRESSION 41 //float [0, 1]
//the self preservation of the bot (rockets near walls etc.)
#define CHARACTERISTIC_SELFPRESERVATION 42 //float [0, 1]
//how likely the bot is to take revenge
#define CHARACTERISTIC_VENGEFULNESS 43 //float [0, 1] //use this!!
//tendency to camp
#define CHARACTERISTIC_CAMPER 44 //float [0, 1]
//========================================================
//========================================================
//tendency to get easy frags
#define CHARACTERISTIC_EASY_FRAGGER 45 //float [0, 1]
//how alert the bot is (view distance)
#define CHARACTERISTIC_ALERTNESS 46 //float [0, 1]
//how much the bot fires it's weapon
#define CHARACTERISTIC_FIRETHROTTLE 47 //float [0, 1]

1191
code/game/g_active.c Normal file

File diff suppressed because it is too large Load diff

376
code/game/g_arenas.c Normal file
View file

@ -0,0 +1,376 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
//
// g_arenas.c
//
#include "g_local.h"
gentity_t *podium1;
gentity_t *podium2;
gentity_t *podium3;
/*
==================
UpdateTournamentInfo
==================
*/
void UpdateTournamentInfo( void ) {
int i;
gentity_t *player;
int playerClientNum;
int n, accuracy, perfect, msglen;
int buflen;
#ifdef MISSIONPACK // bk001205
int score1, score2;
qboolean won;
#endif
char buf[32];
char msg[MAX_STRING_CHARS];
// find the real player
player = NULL;
for (i = 0; i < level.maxclients; i++ ) {
player = &g_entities[i];
if ( !player->inuse ) {
continue;
}
if ( !( player->r.svFlags & SVF_BOT ) ) {
break;
}
}
// this should never happen!
if ( !player || i == level.maxclients ) {
return;
}
playerClientNum = i;
CalculateRanks();
if ( level.clients[playerClientNum].sess.sessionTeam == TEAM_SPECTATOR ) {
#ifdef MISSIONPACK
Com_sprintf( msg, sizeof(msg), "postgame %i %i 0 0 0 0 0 0 0 0 0 0 0", level.numNonSpectatorClients, playerClientNum );
#else
Com_sprintf( msg, sizeof(msg), "postgame %i %i 0 0 0 0 0 0", level.numNonSpectatorClients, playerClientNum );
#endif
}
else {
if( player->client->accuracy_shots ) {
accuracy = player->client->accuracy_hits * 100 / player->client->accuracy_shots;
}
else {
accuracy = 0;
}
#ifdef MISSIONPACK
won = qfalse;
if (g_gametype.integer >= GT_CTF) {
score1 = level.teamScores[TEAM_RED];
score2 = level.teamScores[TEAM_BLUE];
if (level.clients[playerClientNum].sess.sessionTeam == TEAM_RED) {
won = (level.teamScores[TEAM_RED] > level.teamScores[TEAM_BLUE]);
} else {
won = (level.teamScores[TEAM_BLUE] > level.teamScores[TEAM_RED]);
}
} else {
if (&level.clients[playerClientNum] == &level.clients[ level.sortedClients[0] ]) {
won = qtrue;
score1 = level.clients[ level.sortedClients[0] ].ps.persistant[PERS_SCORE];
score2 = level.clients[ level.sortedClients[1] ].ps.persistant[PERS_SCORE];
} else {
score2 = level.clients[ level.sortedClients[0] ].ps.persistant[PERS_SCORE];
score1 = level.clients[ level.sortedClients[1] ].ps.persistant[PERS_SCORE];
}
}
if (won && player->client->ps.persistant[PERS_KILLED] == 0) {
perfect = 1;
} else {
perfect = 0;
}
Com_sprintf( msg, sizeof(msg), "postgame %i %i %i %i %i %i %i %i %i %i %i %i %i %i", level.numNonSpectatorClients, playerClientNum, accuracy,
player->client->ps.persistant[PERS_IMPRESSIVE_COUNT], player->client->ps.persistant[PERS_EXCELLENT_COUNT],player->client->ps.persistant[PERS_DEFEND_COUNT],
player->client->ps.persistant[PERS_ASSIST_COUNT], player->client->ps.persistant[PERS_GAUNTLET_FRAG_COUNT], player->client->ps.persistant[PERS_SCORE],
perfect, score1, score2, level.time, player->client->ps.persistant[PERS_CAPTURES] );
#else
perfect = ( level.clients[playerClientNum].ps.persistant[PERS_RANK] == 0 && player->client->ps.persistant[PERS_KILLED] == 0 ) ? 1 : 0;
Com_sprintf( msg, sizeof(msg), "postgame %i %i %i %i %i %i %i %i", level.numNonSpectatorClients, playerClientNum, accuracy,
player->client->ps.persistant[PERS_IMPRESSIVE_COUNT], player->client->ps.persistant[PERS_EXCELLENT_COUNT],
player->client->ps.persistant[PERS_GAUNTLET_FRAG_COUNT], player->client->ps.persistant[PERS_SCORE],
perfect );
#endif
}
msglen = strlen( msg );
for( i = 0; i < level.numNonSpectatorClients; i++ ) {
n = level.sortedClients[i];
Com_sprintf( buf, sizeof(buf), " %i %i %i", n, level.clients[n].ps.persistant[PERS_RANK], level.clients[n].ps.persistant[PERS_SCORE] );
buflen = strlen( buf );
if( msglen + buflen + 1 >= sizeof(msg) ) {
break;
}
strcat( msg, buf );
}
trap_SendConsoleCommand( EXEC_APPEND, msg );
}
static gentity_t *SpawnModelOnVictoryPad( gentity_t *pad, vec3_t offset, gentity_t *ent, int place ) {
gentity_t *body;
vec3_t vec;
vec3_t f, r, u;
body = G_Spawn();
if ( !body ) {
G_Printf( S_COLOR_RED "ERROR: out of gentities\n" );
return NULL;
}
body->classname = ent->client->pers.netname;
body->client = ent->client;
body->s = ent->s;
body->s.eType = ET_PLAYER; // could be ET_INVISIBLE
body->s.eFlags = 0; // clear EF_TALK, etc
body->s.powerups = 0; // clear powerups
body->s.loopSound = 0; // clear lava burning
body->s.number = body - g_entities;
body->timestamp = level.time;
body->physicsObject = qtrue;
body->physicsBounce = 0; // don't bounce
body->s.event = 0;
body->s.pos.trType = TR_STATIONARY;
body->s.groundEntityNum = ENTITYNUM_WORLD;
body->s.legsAnim = LEGS_IDLE;
body->s.torsoAnim = TORSO_STAND;
if( body->s.weapon == WP_NONE ) {
body->s.weapon = WP_MACHINEGUN;
}
if( body->s.weapon == WP_GAUNTLET) {
body->s.torsoAnim = TORSO_STAND2;
}
body->s.event = 0;
body->r.svFlags = ent->r.svFlags;
VectorCopy (ent->r.mins, body->r.mins);
VectorCopy (ent->r.maxs, body->r.maxs);
VectorCopy (ent->r.absmin, body->r.absmin);
VectorCopy (ent->r.absmax, body->r.absmax);
body->clipmask = CONTENTS_SOLID | CONTENTS_PLAYERCLIP;
body->r.contents = CONTENTS_BODY;
body->r.ownerNum = ent->r.ownerNum;
body->takedamage = qfalse;
VectorSubtract( level.intermission_origin, pad->r.currentOrigin, vec );
vectoangles( vec, body->s.apos.trBase );
body->s.apos.trBase[PITCH] = 0;
body->s.apos.trBase[ROLL] = 0;
AngleVectors( body->s.apos.trBase, f, r, u );
VectorMA( pad->r.currentOrigin, offset[0], f, vec );
VectorMA( vec, offset[1], r, vec );
VectorMA( vec, offset[2], u, vec );
G_SetOrigin( body, vec );
trap_LinkEntity (body);
body->count = place;
return body;
}
static void CelebrateStop( gentity_t *player ) {
int anim;
if( player->s.weapon == WP_GAUNTLET) {
anim = TORSO_STAND2;
}
else {
anim = TORSO_STAND;
}
player->s.torsoAnim = ( ( player->s.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
}
#define TIMER_GESTURE (34*66+50)
static void CelebrateStart( gentity_t *player ) {
player->s.torsoAnim = ( ( player->s.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | TORSO_GESTURE;
player->nextthink = level.time + TIMER_GESTURE;
player->think = CelebrateStop;
/*
player->client->ps.events[player->client->ps.eventSequence & (MAX_PS_EVENTS-1)] = EV_TAUNT;
player->client->ps.eventParms[player->client->ps.eventSequence & (MAX_PS_EVENTS-1)] = 0;
player->client->ps.eventSequence++;
*/
G_AddEvent(player, EV_TAUNT, 0);
}
static vec3_t offsetFirst = {0, 0, 74};
static vec3_t offsetSecond = {-10, 60, 54};
static vec3_t offsetThird = {-19, -60, 45};
static void PodiumPlacementThink( gentity_t *podium ) {
vec3_t vec;
vec3_t origin;
vec3_t f, r, u;
podium->nextthink = level.time + 100;
AngleVectors( level.intermission_angle, vec, NULL, NULL );
VectorMA( level.intermission_origin, trap_Cvar_VariableIntegerValue( "g_podiumDist" ), vec, origin );
origin[2] -= trap_Cvar_VariableIntegerValue( "g_podiumDrop" );
G_SetOrigin( podium, origin );
if( podium1 ) {
VectorSubtract( level.intermission_origin, podium->r.currentOrigin, vec );
vectoangles( vec, podium1->s.apos.trBase );
podium1->s.apos.trBase[PITCH] = 0;
podium1->s.apos.trBase[ROLL] = 0;
AngleVectors( podium1->s.apos.trBase, f, r, u );
VectorMA( podium->r.currentOrigin, offsetFirst[0], f, vec );
VectorMA( vec, offsetFirst[1], r, vec );
VectorMA( vec, offsetFirst[2], u, vec );
G_SetOrigin( podium1, vec );
}
if( podium2 ) {
VectorSubtract( level.intermission_origin, podium->r.currentOrigin, vec );
vectoangles( vec, podium2->s.apos.trBase );
podium2->s.apos.trBase[PITCH] = 0;
podium2->s.apos.trBase[ROLL] = 0;
AngleVectors( podium2->s.apos.trBase, f, r, u );
VectorMA( podium->r.currentOrigin, offsetSecond[0], f, vec );
VectorMA( vec, offsetSecond[1], r, vec );
VectorMA( vec, offsetSecond[2], u, vec );
G_SetOrigin( podium2, vec );
}
if( podium3 ) {
VectorSubtract( level.intermission_origin, podium->r.currentOrigin, vec );
vectoangles( vec, podium3->s.apos.trBase );
podium3->s.apos.trBase[PITCH] = 0;
podium3->s.apos.trBase[ROLL] = 0;
AngleVectors( podium3->s.apos.trBase, f, r, u );
VectorMA( podium->r.currentOrigin, offsetThird[0], f, vec );
VectorMA( vec, offsetThird[1], r, vec );
VectorMA( vec, offsetThird[2], u, vec );
G_SetOrigin( podium3, vec );
}
}
static gentity_t *SpawnPodium( void ) {
gentity_t *podium;
vec3_t vec;
vec3_t origin;
podium = G_Spawn();
if ( !podium ) {
return NULL;
}
podium->classname = "podium";
podium->s.eType = ET_GENERAL;
podium->s.number = podium - g_entities;
podium->clipmask = CONTENTS_SOLID;
podium->r.contents = CONTENTS_SOLID;
podium->s.modelindex = G_ModelIndex( SP_PODIUM_MODEL );
AngleVectors( level.intermission_angle, vec, NULL, NULL );
VectorMA( level.intermission_origin, trap_Cvar_VariableIntegerValue( "g_podiumDist" ), vec, origin );
origin[2] -= trap_Cvar_VariableIntegerValue( "g_podiumDrop" );
G_SetOrigin( podium, origin );
VectorSubtract( level.intermission_origin, podium->r.currentOrigin, vec );
podium->s.apos.trBase[YAW] = vectoyaw( vec );
trap_LinkEntity (podium);
podium->think = PodiumPlacementThink;
podium->nextthink = level.time + 100;
return podium;
}
/*
==================
SpawnModelsOnVictoryPads
==================
*/
void SpawnModelsOnVictoryPads( void ) {
gentity_t *player;
gentity_t *podium;
podium1 = NULL;
podium2 = NULL;
podium3 = NULL;
podium = SpawnPodium();
player = SpawnModelOnVictoryPad( podium, offsetFirst, &g_entities[level.sortedClients[0]],
level.clients[ level.sortedClients[0] ].ps.persistant[PERS_RANK] &~ RANK_TIED_FLAG );
if ( player ) {
player->nextthink = level.time + 2000;
player->think = CelebrateStart;
podium1 = player;
}
player = SpawnModelOnVictoryPad( podium, offsetSecond, &g_entities[level.sortedClients[1]],
level.clients[ level.sortedClients[1] ].ps.persistant[PERS_RANK] &~ RANK_TIED_FLAG );
if ( player ) {
podium2 = player;
}
if ( level.numNonSpectatorClients > 2 ) {
player = SpawnModelOnVictoryPad( podium, offsetThird, &g_entities[level.sortedClients[2]],
level.clients[ level.sortedClients[2] ].ps.persistant[PERS_RANK] &~ RANK_TIED_FLAG );
if ( player ) {
podium3 = player;
}
}
}
/*
===============
Svcmd_AbortPodium_f
===============
*/
void Svcmd_AbortPodium_f( void ) {
if( g_gametype.integer != GT_SINGLE_PLAYER ) {
return;
}
if( podium1 ) {
podium1->nextthink = level.time;
podium1->think = CelebrateStop;
}
}

1017
code/game/g_bot.c Normal file

File diff suppressed because it is too large Load diff

1344
code/game/g_client.c Normal file

File diff suppressed because it is too large Load diff

1701
code/game/g_cmds.c Normal file

File diff suppressed because it is too large Load diff

1195
code/game/g_combat.c Normal file

File diff suppressed because it is too large Load diff

1010
code/game/g_items.c Normal file

File diff suppressed because it is too large Load diff

971
code/game/g_local.h Normal file
View file

@ -0,0 +1,971 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// g_local.h -- local definitions for game module
#include "q_shared.h"
#include "bg_public.h"
#include "g_public.h"
//==================================================================
// the "gameversion" client command will print this plus compile date
#define GAMEVERSION "baseq3"
#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
float angle; // set in editor, -1 = up, -2 = down
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;
// the auto following clients don't follow a specific client
// number, but instead follow the first two active players
#define FOLLOW_ACTIVE1 -1
#define FOLLOW_ACTIVE2 -2
// 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 spectatorTime; // for determining next-in-line to play
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;
int num_entities; // current number, <= MAX_GENTITIES
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 );
void SetTeam( gentity_t *ent, char *s );
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);
void G_TouchSolids (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);
const char *BuildShaderStateConfig();
//
// 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_blaster (gentity_t *self, vec3_t start, vec3_t aimdir);
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
//
team_t TeamCount( int ignoreClientNum, int team );
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 );
void CopyToBodyQue( gentity_t *ent );
void respawn (gentity_t *ent);
void BeginIntermission (void);
void InitClientPersistant (gclient_t *client);
void InitClientResp (gclient_t *client);
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
//
// p_hud.c
//
void MoveClientToIntermission (gentity_t *client);
void G_SetStats (gentity_t *ent);
void DeathmatchScoreboardMessage (gentity_t *client);
//
// g_cmds.c
//
//
// g_pweapon.c
//
//
// g_main.c
//
void FindIntermissionPoint( void );
void SetLeader(int team, int client);
void CheckTeamLeader( int team );
void G_RunThink (gentity_t *ent);
void QDECL G_LogPrintf( const char *fmt, ... );
void SendScoreboardMessageToAllClients( void );
void QDECL G_Printf( const char *fmt, ... );
void QDECL G_Error( const char *fmt, ... );
//
// 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;
char team[MAX_FILEPATH];
} 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) ((int)&(((gentity_t *)0)->x))
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;
void trap_Printf( const char *fmt );
void trap_Error( const char *fmt );
int trap_Milliseconds( void );
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 );

1832
code/game/g_main.c Normal file

File diff suppressed because it is too large Load diff

61
code/game/g_mem.c Normal file
View file

@ -0,0 +1,61 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
//
// g_mem.c
//
#include "g_local.h"
#define POOLSIZE (256 * 1024)
static char memoryPool[POOLSIZE];
static int allocPoint;
void *G_Alloc( int size ) {
char *p;
if ( g_debugAlloc.integer ) {
G_Printf( "G_Alloc of %i bytes (%i left)\n", size, POOLSIZE - allocPoint - ( ( size + 31 ) & ~31 ) );
}
if ( allocPoint + size > POOLSIZE ) {
G_Error( "G_Alloc: failed on allocation of %i bytes\n", size ); // bk010103 - was %u, but is signed
return NULL;
}
p = &memoryPool[allocPoint];
allocPoint += ( size + 31 ) & ~31;
return p;
}
void G_InitMemory( void ) {
allocPoint = 0;
}
void Svcmd_GameMem_f( void ) {
G_Printf( "Game memory status: %i out of %i bytes allocated\n", allocPoint, POOLSIZE );
}

482
code/game/g_misc.c Normal file
View file

@ -0,0 +1,482 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// g_misc.c
#include "g_local.h"
/*QUAKED func_group (0 0 0) ?
Used to group brushes together just for editor convenience. They are turned into normal brushes by the utilities.
*/
/*QUAKED info_camp (0 0.5 0) (-4 -4 -4) (4 4 4)
Used as a positional target for calculations in the utilities (spotlights, etc), but removed during gameplay.
*/
void SP_info_camp( gentity_t *self ) {
G_SetOrigin( self, self->s.origin );
}
/*QUAKED info_null (0 0.5 0) (-4 -4 -4) (4 4 4)
Used as a positional target for calculations in the utilities (spotlights, etc), but removed during gameplay.
*/
void SP_info_null( gentity_t *self ) {
G_FreeEntity( self );
}
/*QUAKED info_notnull (0 0.5 0) (-4 -4 -4) (4 4 4)
Used as a positional target for in-game calculation, like jumppad targets.
target_position does the same thing
*/
void SP_info_notnull( gentity_t *self ){
G_SetOrigin( self, self->s.origin );
}
/*QUAKED light (0 1 0) (-8 -8 -8) (8 8 8) linear
Non-displayed light.
"light" overrides the default 300 intensity.
Linear checbox gives linear falloff instead of inverse square
Lights pointed at a target will be spotlights.
"radius" overrides the default 64 unit radius of a spotlight at the target point.
*/
void SP_light( gentity_t *self ) {
G_FreeEntity( self );
}
/*
=================================================================================
TELEPORTERS
=================================================================================
*/
void TeleportPlayer( gentity_t *player, vec3_t origin, vec3_t angles ) {
gentity_t *tent;
// use temp events at source and destination to prevent the effect
// from getting dropped by a second player event
if ( player->client->sess.sessionTeam != TEAM_SPECTATOR ) {
tent = G_TempEntity( player->client->ps.origin, EV_PLAYER_TELEPORT_OUT );
tent->s.clientNum = player->s.clientNum;
tent = G_TempEntity( origin, EV_PLAYER_TELEPORT_IN );
tent->s.clientNum = player->s.clientNum;
}
// unlink to make sure it can't possibly interfere with G_KillBox
trap_UnlinkEntity (player);
VectorCopy ( origin, player->client->ps.origin );
player->client->ps.origin[2] += 1;
// spit the player out
AngleVectors( angles, player->client->ps.velocity, NULL, NULL );
VectorScale( player->client->ps.velocity, 400, player->client->ps.velocity );
player->client->ps.pm_time = 160; // hold time
player->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
// toggle the teleport bit so the client knows to not lerp
player->client->ps.eFlags ^= EF_TELEPORT_BIT;
// set angles
SetClientViewAngle( player, angles );
// kill anything at the destination
if ( player->client->sess.sessionTeam != TEAM_SPECTATOR ) {
G_KillBox (player);
}
// save results of pmove
BG_PlayerStateToEntityState( &player->client->ps, &player->s, qtrue );
// use the precise origin for linking
VectorCopy( player->client->ps.origin, player->r.currentOrigin );
if ( player->client->sess.sessionTeam != TEAM_SPECTATOR ) {
trap_LinkEntity (player);
}
}
/*QUAKED misc_teleporter_dest (1 0 0) (-32 -32 -24) (32 32 -16)
Point teleporters at these.
Now that we don't have teleport destination pads, this is just
an info_notnull
*/
void SP_misc_teleporter_dest( gentity_t *ent ) {
}
//===========================================================
/*QUAKED misc_model (1 0 0) (-16 -16 -16) (16 16 16)
"model" arbitrary .md3 file to display
*/
void SP_misc_model( gentity_t *ent ) {
#if 0
ent->s.modelindex = G_ModelIndex( ent->model );
VectorSet (ent->mins, -16, -16, -16);
VectorSet (ent->maxs, 16, 16, 16);
trap_LinkEntity (ent);
G_SetOrigin( ent, ent->s.origin );
VectorCopy( ent->s.angles, ent->s.apos.trBase );
#else
G_FreeEntity( ent );
#endif
}
//===========================================================
void locateCamera( gentity_t *ent ) {
vec3_t dir;
gentity_t *target;
gentity_t *owner;
owner = G_PickTarget( ent->target );
if ( !owner ) {
G_Printf( "Couldn't find target for misc_partal_surface\n" );
G_FreeEntity( ent );
return;
}
ent->r.ownerNum = owner->s.number;
// frame holds the rotate speed
if ( owner->spawnflags & 1 ) {
ent->s.frame = 25;
} else if ( owner->spawnflags & 2 ) {
ent->s.frame = 75;
}
// swing camera ?
if ( owner->spawnflags & 4 ) {
// set to 0 for no rotation at all
ent->s.powerups = 0;
}
else {
ent->s.powerups = 1;
}
// clientNum holds the rotate offset
ent->s.clientNum = owner->s.clientNum;
VectorCopy( owner->s.origin, ent->s.origin2 );
// see if the portal_camera has a target
target = G_PickTarget( owner->target );
if ( target ) {
VectorSubtract( target->s.origin, owner->s.origin, dir );
VectorNormalize( dir );
} else {
G_SetMovedir( owner->s.angles, dir );
}
ent->s.eventParm = DirToByte( dir );
}
/*QUAKED misc_portal_surface (0 0 1) (-8 -8 -8) (8 8 8)
The portal surface nearest this entity will show a view from the targeted misc_portal_camera, or a mirror view if untargeted.
This must be within 64 world units of the surface!
*/
void SP_misc_portal_surface(gentity_t *ent) {
VectorClear( ent->r.mins );
VectorClear( ent->r.maxs );
trap_LinkEntity (ent);
ent->r.svFlags = SVF_PORTAL;
ent->s.eType = ET_PORTAL;
if ( !ent->target ) {
VectorCopy( ent->s.origin, ent->s.origin2 );
} else {
ent->think = locateCamera;
ent->nextthink = level.time + 100;
}
}
/*QUAKED misc_portal_camera (0 0 1) (-8 -8 -8) (8 8 8) slowrotate fastrotate noswing
The target for a misc_portal_director. You can set either angles or target another entity to determine the direction of view.
"roll" an angle modifier to orient the camera around the target vector;
*/
void SP_misc_portal_camera(gentity_t *ent) {
float roll;
VectorClear( ent->r.mins );
VectorClear( ent->r.maxs );
trap_LinkEntity (ent);
G_SpawnFloat( "roll", "0", &roll );
ent->s.clientNum = roll/360.0 * 256;
}
/*
======================================================================
SHOOTERS
======================================================================
*/
void Use_Shooter( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
vec3_t dir;
float deg;
vec3_t up, right;
// see if we have a target
if ( ent->enemy ) {
VectorSubtract( ent->enemy->r.currentOrigin, ent->s.origin, dir );
VectorNormalize( dir );
} else {
VectorCopy( ent->movedir, dir );
}
// randomize a bit
PerpendicularVector( up, dir );
CrossProduct( up, dir, right );
deg = crandom() * ent->random;
VectorMA( dir, deg, up, dir );
deg = crandom() * ent->random;
VectorMA( dir, deg, right, dir );
VectorNormalize( dir );
switch ( ent->s.weapon ) {
case WP_GRENADE_LAUNCHER:
fire_grenade( ent, ent->s.origin, dir );
break;
case WP_ROCKET_LAUNCHER:
fire_rocket( ent, ent->s.origin, dir );
break;
case WP_PLASMAGUN:
fire_plasma( ent, ent->s.origin, dir );
break;
}
G_AddEvent( ent, EV_FIRE_WEAPON, 0 );
}
static void InitShooter_Finish( gentity_t *ent ) {
ent->enemy = G_PickTarget( ent->target );
ent->think = 0;
ent->nextthink = 0;
}
void InitShooter( gentity_t *ent, int weapon ) {
ent->use = Use_Shooter;
ent->s.weapon = weapon;
RegisterItem( BG_FindItemForWeapon( weapon ) );
G_SetMovedir( ent->s.angles, ent->movedir );
if ( !ent->random ) {
ent->random = 1.0;
}
ent->random = sin( M_PI * ent->random / 180 );
// target might be a moving object, so we can't set movedir for it
if ( ent->target ) {
ent->think = InitShooter_Finish;
ent->nextthink = level.time + 500;
}
trap_LinkEntity( ent );
}
/*QUAKED shooter_rocket (1 0 0) (-16 -16 -16) (16 16 16)
Fires at either the target or the current direction.
"random" the number of degrees of deviance from the taget. (1.0 default)
*/
void SP_shooter_rocket( gentity_t *ent ) {
InitShooter( ent, WP_ROCKET_LAUNCHER );
}
/*QUAKED shooter_plasma (1 0 0) (-16 -16 -16) (16 16 16)
Fires at either the target or the current direction.
"random" is the number of degrees of deviance from the taget. (1.0 default)
*/
void SP_shooter_plasma( gentity_t *ent ) {
InitShooter( ent, WP_PLASMAGUN);
}
/*QUAKED shooter_grenade (1 0 0) (-16 -16 -16) (16 16 16)
Fires at either the target or the current direction.
"random" is the number of degrees of deviance from the taget. (1.0 default)
*/
void SP_shooter_grenade( gentity_t *ent ) {
InitShooter( ent, WP_GRENADE_LAUNCHER);
}
#ifdef MISSIONPACK
static void PortalDie (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod) {
G_FreeEntity( self );
//FIXME do something more interesting
}
void DropPortalDestination( gentity_t *player ) {
gentity_t *ent;
vec3_t snapped;
// create the portal destination
ent = G_Spawn();
ent->s.modelindex = G_ModelIndex( "models/powerups/teleporter/tele_exit.md3" );
VectorCopy( player->s.pos.trBase, snapped );
SnapVector( snapped );
G_SetOrigin( ent, snapped );
VectorCopy( player->r.mins, ent->r.mins );
VectorCopy( player->r.maxs, ent->r.maxs );
ent->classname = "hi_portal destination";
ent->s.pos.trType = TR_STATIONARY;
ent->r.contents = CONTENTS_CORPSE;
ent->takedamage = qtrue;
ent->health = 200;
ent->die = PortalDie;
VectorCopy( player->s.apos.trBase, ent->s.angles );
ent->think = G_FreeEntity;
ent->nextthink = level.time + 2 * 60 * 1000;
trap_LinkEntity( ent );
player->client->portalID = ++level.portalSequence;
ent->count = player->client->portalID;
// give the item back so they can drop the source now
player->client->ps.stats[STAT_HOLDABLE_ITEM] = BG_FindItem( "Portal" ) - bg_itemlist;
}
static void PortalTouch( gentity_t *self, gentity_t *other, trace_t *trace) {
gentity_t *destination;
// see if we will even let other try to use it
if( other->health <= 0 ) {
return;
}
if( !other->client ) {
return;
}
// if( other->client->ps.persistant[PERS_TEAM] != self->spawnflags ) {
// return;
// }
if ( other->client->ps.powerups[PW_NEUTRALFLAG] ) { // only happens in One Flag CTF
Drop_Item( other, BG_FindItemForPowerup( PW_NEUTRALFLAG ), 0 );
other->client->ps.powerups[PW_NEUTRALFLAG] = 0;
}
else if ( other->client->ps.powerups[PW_REDFLAG] ) { // only happens in standard CTF
Drop_Item( other, BG_FindItemForPowerup( PW_REDFLAG ), 0 );
other->client->ps.powerups[PW_REDFLAG] = 0;
}
else if ( other->client->ps.powerups[PW_BLUEFLAG] ) { // only happens in standard CTF
Drop_Item( other, BG_FindItemForPowerup( PW_BLUEFLAG ), 0 );
other->client->ps.powerups[PW_BLUEFLAG] = 0;
}
// find the destination
destination = NULL;
while( (destination = G_Find(destination, FOFS(classname), "hi_portal destination")) != NULL ) {
if( destination->count == self->count ) {
break;
}
}
// if there is not one, die!
if( !destination ) {
if( self->pos1[0] || self->pos1[1] || self->pos1[2] ) {
TeleportPlayer( other, self->pos1, self->s.angles );
}
G_Damage( other, other, other, NULL, NULL, 100000, DAMAGE_NO_PROTECTION, MOD_TELEFRAG );
return;
}
TeleportPlayer( other, destination->s.pos.trBase, destination->s.angles );
}
static void PortalEnable( gentity_t *self ) {
self->touch = PortalTouch;
self->think = G_FreeEntity;
self->nextthink = level.time + 2 * 60 * 1000;
}
void DropPortalSource( gentity_t *player ) {
gentity_t *ent;
gentity_t *destination;
vec3_t snapped;
// create the portal source
ent = G_Spawn();
ent->s.modelindex = G_ModelIndex( "models/powerups/teleporter/tele_enter.md3" );
VectorCopy( player->s.pos.trBase, snapped );
SnapVector( snapped );
G_SetOrigin( ent, snapped );
VectorCopy( player->r.mins, ent->r.mins );
VectorCopy( player->r.maxs, ent->r.maxs );
ent->classname = "hi_portal source";
ent->s.pos.trType = TR_STATIONARY;
ent->r.contents = CONTENTS_CORPSE | CONTENTS_TRIGGER;
ent->takedamage = qtrue;
ent->health = 200;
ent->die = PortalDie;
trap_LinkEntity( ent );
ent->count = player->client->portalID;
player->client->portalID = 0;
// ent->spawnflags = player->client->ps.persistant[PERS_TEAM];
ent->nextthink = level.time + 1000;
ent->think = PortalEnable;
// find the destination
destination = NULL;
while( (destination = G_Find(destination, FOFS(classname), "hi_portal destination")) != NULL ) {
if( destination->count == ent->count ) {
VectorCopy( destination->s.pos.trBase, ent->pos1 );
break;
}
}
}
#endif

808
code/game/g_missile.c Normal file
View file

@ -0,0 +1,808 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
#include "g_local.h"
#define MISSILE_PRESTEP_TIME 50
/*
================
G_BounceMissile
================
*/
void G_BounceMissile( gentity_t *ent, trace_t *trace ) {
vec3_t velocity;
float dot;
int hitTime;
// reflect the velocity on the trace plane
hitTime = level.previousTime + ( level.time - level.previousTime ) * trace->fraction;
BG_EvaluateTrajectoryDelta( &ent->s.pos, hitTime, velocity );
dot = DotProduct( velocity, trace->plane.normal );
VectorMA( velocity, -2*dot, trace->plane.normal, ent->s.pos.trDelta );
if ( ent->s.eFlags & EF_BOUNCE_HALF ) {
VectorScale( ent->s.pos.trDelta, 0.65, ent->s.pos.trDelta );
// check for stop
if ( trace->plane.normal[2] > 0.2 && VectorLength( ent->s.pos.trDelta ) < 40 ) {
G_SetOrigin( ent, trace->endpos );
return;
}
}
VectorAdd( ent->r.currentOrigin, trace->plane.normal, ent->r.currentOrigin);
VectorCopy( ent->r.currentOrigin, ent->s.pos.trBase );
ent->s.pos.trTime = level.time;
}
/*
================
G_ExplodeMissile
Explode a missile without an impact
================
*/
void G_ExplodeMissile( gentity_t *ent ) {
vec3_t dir;
vec3_t origin;
BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );
SnapVector( origin );
G_SetOrigin( ent, origin );
// we don't have a valid direction, so just point straight up
dir[0] = dir[1] = 0;
dir[2] = 1;
ent->s.eType = ET_GENERAL;
G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( dir ) );
ent->freeAfterEvent = qtrue;
// splash damage
if ( ent->splashDamage ) {
if( G_RadiusDamage( ent->r.currentOrigin, ent->parent, ent->splashDamage, ent->splashRadius, ent
, ent->splashMethodOfDeath ) ) {
g_entities[ent->r.ownerNum].client->accuracy_hits++;
}
}
trap_LinkEntity( ent );
}
#ifdef MISSIONPACK
/*
================
ProximityMine_Explode
================
*/
static void ProximityMine_Explode( gentity_t *mine ) {
G_ExplodeMissile( mine );
// if the prox mine has a trigger free it
if (mine->activator) {
G_FreeEntity(mine->activator);
mine->activator = NULL;
}
}
/*
================
ProximityMine_Die
================
*/
static void ProximityMine_Die( gentity_t *ent, gentity_t *inflictor, gentity_t *attacker, int damage, int mod ) {
ent->think = ProximityMine_Explode;
ent->nextthink = level.time + 1;
}
/*
================
ProximityMine_Trigger
================
*/
void ProximityMine_Trigger( gentity_t *trigger, gentity_t *other, trace_t *trace ) {
vec3_t v;
gentity_t *mine;
if( !other->client ) {
return;
}
// trigger is a cube, do a distance test now to act as if it's a sphere
VectorSubtract( trigger->s.pos.trBase, other->s.pos.trBase, v );
if( VectorLength( v ) > trigger->parent->splashRadius ) {
return;
}
if ( g_gametype.integer >= GT_TEAM ) {
// don't trigger same team mines
if (trigger->parent->s.generic1 == other->client->sess.sessionTeam) {
return;
}
}
// ok, now check for ability to damage so we don't get triggered thru walls, closed doors, etc...
if( !CanDamage( other, trigger->s.pos.trBase ) ) {
return;
}
// trigger the mine!
mine = trigger->parent;
mine->s.loopSound = 0;
G_AddEvent( mine, EV_PROXIMITY_MINE_TRIGGER, 0 );
mine->nextthink = level.time + 500;
G_FreeEntity( trigger );
}
/*
================
ProximityMine_Activate
================
*/
static void ProximityMine_Activate( gentity_t *ent ) {
gentity_t *trigger;
float r;
ent->think = ProximityMine_Explode;
ent->nextthink = level.time + g_proxMineTimeout.integer;
ent->takedamage = qtrue;
ent->health = 1;
ent->die = ProximityMine_Die;
ent->s.loopSound = G_SoundIndex( "sound/weapons/proxmine/wstbtick.wav" );
// build the proximity trigger
trigger = G_Spawn ();
trigger->classname = "proxmine_trigger";
r = ent->splashRadius;
VectorSet( trigger->r.mins, -r, -r, -r );
VectorSet( trigger->r.maxs, r, r, r );
G_SetOrigin( trigger, ent->s.pos.trBase );
trigger->parent = ent;
trigger->r.contents = CONTENTS_TRIGGER;
trigger->touch = ProximityMine_Trigger;
trap_LinkEntity (trigger);
// set pointer to trigger so the entity can be freed when the mine explodes
ent->activator = trigger;
}
/*
================
ProximityMine_ExplodeOnPlayer
================
*/
static void ProximityMine_ExplodeOnPlayer( gentity_t *mine ) {
gentity_t *player;
player = mine->enemy;
player->client->ps.eFlags &= ~EF_TICKING;
if ( player->client->invulnerabilityTime > level.time ) {
G_Damage( player, mine->parent, mine->parent, vec3_origin, mine->s.origin, 1000, DAMAGE_NO_KNOCKBACK, MOD_JUICED );
player->client->invulnerabilityTime = 0;
G_TempEntity( player->client->ps.origin, EV_JUICED );
}
else {
G_SetOrigin( mine, player->s.pos.trBase );
// make sure the explosion gets to the client
mine->r.svFlags &= ~SVF_NOCLIENT;
mine->splashMethodOfDeath = MOD_PROXIMITY_MINE;
G_ExplodeMissile( mine );
}
}
/*
================
ProximityMine_Player
================
*/
static void ProximityMine_Player( gentity_t *mine, gentity_t *player ) {
if( mine->s.eFlags & EF_NODRAW ) {
return;
}
G_AddEvent( mine, EV_PROXIMITY_MINE_STICK, 0 );
if( player->s.eFlags & EF_TICKING ) {
player->activator->splashDamage += mine->splashDamage;
player->activator->splashRadius *= 1.50;
mine->think = G_FreeEntity;
mine->nextthink = level.time;
return;
}
player->client->ps.eFlags |= EF_TICKING;
player->activator = mine;
mine->s.eFlags |= EF_NODRAW;
mine->r.svFlags |= SVF_NOCLIENT;
mine->s.pos.trType = TR_LINEAR;
VectorClear( mine->s.pos.trDelta );
mine->enemy = player;
mine->think = ProximityMine_ExplodeOnPlayer;
if ( player->client->invulnerabilityTime > level.time ) {
mine->nextthink = level.time + 2 * 1000;
}
else {
mine->nextthink = level.time + 10 * 1000;
}
}
#endif
/*
================
G_MissileImpact
================
*/
void G_MissileImpact( gentity_t *ent, trace_t *trace ) {
gentity_t *other;
qboolean hitClient = qfalse;
#ifdef MISSIONPACK
vec3_t forward, impactpoint, bouncedir;
int eFlags;
#endif
other = &g_entities[trace->entityNum];
// check for bounce
if ( !other->takedamage &&
( ent->s.eFlags & ( EF_BOUNCE | EF_BOUNCE_HALF ) ) ) {
G_BounceMissile( ent, trace );
G_AddEvent( ent, EV_GRENADE_BOUNCE, 0 );
return;
}
#ifdef MISSIONPACK
if ( other->takedamage ) {
if ( ent->s.weapon != WP_PROX_LAUNCHER ) {
if ( other->client && other->client->invulnerabilityTime > level.time ) {
//
VectorCopy( ent->s.pos.trDelta, forward );
VectorNormalize( forward );
if (G_InvulnerabilityEffect( other, forward, ent->s.pos.trBase, impactpoint, bouncedir )) {
VectorCopy( bouncedir, trace->plane.normal );
eFlags = ent->s.eFlags & EF_BOUNCE_HALF;
ent->s.eFlags &= ~EF_BOUNCE_HALF;
G_BounceMissile( ent, trace );
ent->s.eFlags |= eFlags;
}
ent->target_ent = other;
return;
}
}
}
#endif
// impact damage
if (other->takedamage) {
// FIXME: wrong damage direction?
if ( ent->damage ) {
vec3_t velocity;
if( LogAccuracyHit( other, &g_entities[ent->r.ownerNum] ) ) {
g_entities[ent->r.ownerNum].client->accuracy_hits++;
hitClient = qtrue;
}
BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, velocity );
if ( VectorLength( velocity ) == 0 ) {
velocity[2] = 1; // stepped on a grenade
}
G_Damage (other, ent, &g_entities[ent->r.ownerNum], velocity,
ent->s.origin, ent->damage,
0, ent->methodOfDeath);
}
}
#ifdef MISSIONPACK
if( ent->s.weapon == WP_PROX_LAUNCHER ) {
if( ent->s.pos.trType != TR_GRAVITY ) {
return;
}
// if it's a player, stick it on to them (flag them and remove this entity)
if( other->s.eType == ET_PLAYER && other->health > 0 ) {
ProximityMine_Player( ent, other );
return;
}
SnapVectorTowards( trace->endpos, ent->s.pos.trBase );
G_SetOrigin( ent, trace->endpos );
ent->s.pos.trType = TR_STATIONARY;
VectorClear( ent->s.pos.trDelta );
G_AddEvent( ent, EV_PROXIMITY_MINE_STICK, trace->surfaceFlags );
ent->think = ProximityMine_Activate;
ent->nextthink = level.time + 2000;
vectoangles( trace->plane.normal, ent->s.angles );
ent->s.angles[0] += 90;
// link the prox mine to the other entity
ent->enemy = other;
ent->die = ProximityMine_Die;
VectorCopy(trace->plane.normal, ent->movedir);
VectorSet(ent->r.mins, -4, -4, -4);
VectorSet(ent->r.maxs, 4, 4, 4);
trap_LinkEntity(ent);
return;
}
#endif
if (!strcmp(ent->classname, "hook")) {
gentity_t *nent;
vec3_t v;
nent = G_Spawn();
if ( other->takedamage && other->client ) {
G_AddEvent( nent, EV_MISSILE_HIT, DirToByte( trace->plane.normal ) );
nent->s.otherEntityNum = other->s.number;
ent->enemy = other;
v[0] = other->r.currentOrigin[0] + (other->r.mins[0] + other->r.maxs[0]) * 0.5;
v[1] = other->r.currentOrigin[1] + (other->r.mins[1] + other->r.maxs[1]) * 0.5;
v[2] = other->r.currentOrigin[2] + (other->r.mins[2] + other->r.maxs[2]) * 0.5;
SnapVectorTowards( v, ent->s.pos.trBase ); // save net bandwidth
} else {
VectorCopy(trace->endpos, v);
G_AddEvent( nent, EV_MISSILE_MISS, DirToByte( trace->plane.normal ) );
ent->enemy = NULL;
}
SnapVectorTowards( v, ent->s.pos.trBase ); // save net bandwidth
nent->freeAfterEvent = qtrue;
// change over to a normal entity right at the point of impact
nent->s.eType = ET_GENERAL;
ent->s.eType = ET_GRAPPLE;
G_SetOrigin( ent, v );
G_SetOrigin( nent, v );
ent->think = Weapon_HookThink;
ent->nextthink = level.time + FRAMETIME;
ent->parent->client->ps.pm_flags |= PMF_GRAPPLE_PULL;
VectorCopy( ent->r.currentOrigin, ent->parent->client->ps.grapplePoint);
trap_LinkEntity( ent );
trap_LinkEntity( nent );
return;
}
// is it cheaper in bandwidth to just remove this ent and create a new
// one, rather than changing the missile into the explosion?
if ( other->takedamage && other->client ) {
G_AddEvent( ent, EV_MISSILE_HIT, DirToByte( trace->plane.normal ) );
ent->s.otherEntityNum = other->s.number;
} else if( trace->surfaceFlags & SURF_METALSTEPS ) {
G_AddEvent( ent, EV_MISSILE_MISS_METAL, DirToByte( trace->plane.normal ) );
} else {
G_AddEvent( ent, EV_MISSILE_MISS, DirToByte( trace->plane.normal ) );
}
ent->freeAfterEvent = qtrue;
// change over to a normal entity right at the point of impact
ent->s.eType = ET_GENERAL;
SnapVectorTowards( trace->endpos, ent->s.pos.trBase ); // save net bandwidth
G_SetOrigin( ent, trace->endpos );
// splash damage (doesn't apply to person directly hit)
if ( ent->splashDamage ) {
if( G_RadiusDamage( trace->endpos, ent->parent, ent->splashDamage, ent->splashRadius,
other, ent->splashMethodOfDeath ) ) {
if( !hitClient ) {
g_entities[ent->r.ownerNum].client->accuracy_hits++;
}
}
}
trap_LinkEntity( ent );
}
/*
================
G_RunMissile
================
*/
void G_RunMissile( gentity_t *ent ) {
vec3_t origin;
trace_t tr;
int passent;
// get current position
BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );
// if this missile bounced off an invulnerability sphere
if ( ent->target_ent ) {
passent = ent->target_ent->s.number;
}
#ifdef MISSIONPACK
// prox mines that left the owner bbox will attach to anything, even the owner
else if (ent->s.weapon == WP_PROX_LAUNCHER && ent->count) {
passent = ENTITYNUM_NONE;
}
#endif
else {
// ignore interactions with the missile owner
passent = ent->r.ownerNum;
}
// trace a line from the previous position to the current position
trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask );
if ( tr.startsolid || tr.allsolid ) {
// make sure the tr.entityNum is set to the entity we're stuck in
trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, ent->r.currentOrigin, passent, ent->clipmask );
tr.fraction = 0;
}
else {
VectorCopy( tr.endpos, ent->r.currentOrigin );
}
trap_LinkEntity( ent );
if ( tr.fraction != 1 ) {
// never explode or bounce on sky
if ( tr.surfaceFlags & SURF_NOIMPACT ) {
// If grapple, reset owner
if (ent->parent && ent->parent->client && ent->parent->client->hook == ent) {
ent->parent->client->hook = NULL;
}
G_FreeEntity( ent );
return;
}
G_MissileImpact( ent, &tr );
if ( ent->s.eType != ET_MISSILE ) {
return; // exploded
}
}
#ifdef MISSIONPACK
// if the prox mine wasn't yet outside the player body
if (ent->s.weapon == WP_PROX_LAUNCHER && !ent->count) {
// check if the prox mine is outside the owner bbox
trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, ent->r.currentOrigin, ENTITYNUM_NONE, ent->clipmask );
if (!tr.startsolid || tr.entityNum != ent->r.ownerNum) {
ent->count = 1;
}
}
#endif
// check think function after bouncing
G_RunThink( ent );
}
//=============================================================================
/*
=================
fire_plasma
=================
*/
gentity_t *fire_plasma (gentity_t *self, vec3_t start, vec3_t dir) {
gentity_t *bolt;
VectorNormalize (dir);
bolt = G_Spawn();
bolt->classname = "plasma";
bolt->nextthink = level.time + 10000;
bolt->think = G_ExplodeMissile;
bolt->s.eType = ET_MISSILE;
bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
bolt->s.weapon = WP_PLASMAGUN;
bolt->r.ownerNum = self->s.number;
bolt->parent = self;
bolt->damage = 20;
bolt->splashDamage = 15;
bolt->splashRadius = 20;
bolt->methodOfDeath = MOD_PLASMA;
bolt->splashMethodOfDeath = MOD_PLASMA_SPLASH;
bolt->clipmask = MASK_SHOT;
bolt->target_ent = NULL;
bolt->s.pos.trType = TR_LINEAR;
bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
VectorCopy( start, bolt->s.pos.trBase );
VectorScale( dir, 2000, bolt->s.pos.trDelta );
SnapVector( bolt->s.pos.trDelta ); // save net bandwidth
VectorCopy (start, bolt->r.currentOrigin);
return bolt;
}
//=============================================================================
/*
=================
fire_grenade
=================
*/
gentity_t *fire_grenade (gentity_t *self, vec3_t start, vec3_t dir) {
gentity_t *bolt;
VectorNormalize (dir);
bolt = G_Spawn();
bolt->classname = "grenade";
bolt->nextthink = level.time + 2500;
bolt->think = G_ExplodeMissile;
bolt->s.eType = ET_MISSILE;
bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
bolt->s.weapon = WP_GRENADE_LAUNCHER;
bolt->s.eFlags = EF_BOUNCE_HALF;
bolt->r.ownerNum = self->s.number;
bolt->parent = self;
bolt->damage = 100;
bolt->splashDamage = 100;
bolt->splashRadius = 150;
bolt->methodOfDeath = MOD_GRENADE;
bolt->splashMethodOfDeath = MOD_GRENADE_SPLASH;
bolt->clipmask = MASK_SHOT;
bolt->target_ent = NULL;
bolt->s.pos.trType = TR_GRAVITY;
bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
VectorCopy( start, bolt->s.pos.trBase );
VectorScale( dir, 700, bolt->s.pos.trDelta );
SnapVector( bolt->s.pos.trDelta ); // save net bandwidth
VectorCopy (start, bolt->r.currentOrigin);
return bolt;
}
//=============================================================================
/*
=================
fire_bfg
=================
*/
gentity_t *fire_bfg (gentity_t *self, vec3_t start, vec3_t dir) {
gentity_t *bolt;
VectorNormalize (dir);
bolt = G_Spawn();
bolt->classname = "bfg";
bolt->nextthink = level.time + 10000;
bolt->think = G_ExplodeMissile;
bolt->s.eType = ET_MISSILE;
bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
bolt->s.weapon = WP_BFG;
bolt->r.ownerNum = self->s.number;
bolt->parent = self;
bolt->damage = 100;
bolt->splashDamage = 100;
bolt->splashRadius = 120;
bolt->methodOfDeath = MOD_BFG;
bolt->splashMethodOfDeath = MOD_BFG_SPLASH;
bolt->clipmask = MASK_SHOT;
bolt->target_ent = NULL;
bolt->s.pos.trType = TR_LINEAR;
bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
VectorCopy( start, bolt->s.pos.trBase );
VectorScale( dir, 2000, bolt->s.pos.trDelta );
SnapVector( bolt->s.pos.trDelta ); // save net bandwidth
VectorCopy (start, bolt->r.currentOrigin);
return bolt;
}
//=============================================================================
/*
=================
fire_rocket
=================
*/
gentity_t *fire_rocket (gentity_t *self, vec3_t start, vec3_t dir) {
gentity_t *bolt;
VectorNormalize (dir);
bolt = G_Spawn();
bolt->classname = "rocket";
bolt->nextthink = level.time + 15000;
bolt->think = G_ExplodeMissile;
bolt->s.eType = ET_MISSILE;
bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
bolt->s.weapon = WP_ROCKET_LAUNCHER;
bolt->r.ownerNum = self->s.number;
bolt->parent = self;
bolt->damage = 100;
bolt->splashDamage = 100;
bolt->splashRadius = 120;
bolt->methodOfDeath = MOD_ROCKET;
bolt->splashMethodOfDeath = MOD_ROCKET_SPLASH;
bolt->clipmask = MASK_SHOT;
bolt->target_ent = NULL;
bolt->s.pos.trType = TR_LINEAR;
bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
VectorCopy( start, bolt->s.pos.trBase );
VectorScale( dir, 900, bolt->s.pos.trDelta );
SnapVector( bolt->s.pos.trDelta ); // save net bandwidth
VectorCopy (start, bolt->r.currentOrigin);
return bolt;
}
/*
=================
fire_grapple
=================
*/
gentity_t *fire_grapple (gentity_t *self, vec3_t start, vec3_t dir) {
gentity_t *hook;
VectorNormalize (dir);
hook = G_Spawn();
hook->classname = "hook";
hook->nextthink = level.time + 10000;
hook->think = Weapon_HookFree;
hook->s.eType = ET_MISSILE;
hook->r.svFlags = SVF_USE_CURRENT_ORIGIN;
hook->s.weapon = WP_GRAPPLING_HOOK;
hook->r.ownerNum = self->s.number;
hook->methodOfDeath = MOD_GRAPPLE;
hook->clipmask = MASK_SHOT;
hook->parent = self;
hook->target_ent = NULL;
hook->s.pos.trType = TR_LINEAR;
hook->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
hook->s.otherEntityNum = self->s.number; // use to match beam in client
VectorCopy( start, hook->s.pos.trBase );
VectorScale( dir, 800, hook->s.pos.trDelta );
SnapVector( hook->s.pos.trDelta ); // save net bandwidth
VectorCopy (start, hook->r.currentOrigin);
self->client->hook = hook;
return hook;
}
#ifdef MISSIONPACK
/*
=================
fire_nail
=================
*/
#define NAILGUN_SPREAD 500
gentity_t *fire_nail( gentity_t *self, vec3_t start, vec3_t forward, vec3_t right, vec3_t up ) {
gentity_t *bolt;
vec3_t dir;
vec3_t end;
float r, u, scale;
bolt = G_Spawn();
bolt->classname = "nail";
bolt->nextthink = level.time + 10000;
bolt->think = G_ExplodeMissile;
bolt->s.eType = ET_MISSILE;
bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
bolt->s.weapon = WP_NAILGUN;
bolt->r.ownerNum = self->s.number;
bolt->parent = self;
bolt->damage = 20;
bolt->methodOfDeath = MOD_NAIL;
bolt->clipmask = MASK_SHOT;
bolt->target_ent = NULL;
bolt->s.pos.trType = TR_LINEAR;
bolt->s.pos.trTime = level.time;
VectorCopy( start, bolt->s.pos.trBase );
r = random() * M_PI * 2.0f;
u = sin(r) * crandom() * NAILGUN_SPREAD * 16;
r = cos(r) * crandom() * NAILGUN_SPREAD * 16;
VectorMA( start, 8192 * 16, forward, end);
VectorMA (end, r, right, end);
VectorMA (end, u, up, end);
VectorSubtract( end, start, dir );
VectorNormalize( dir );
scale = 555 + random() * 1800;
VectorScale( dir, scale, bolt->s.pos.trDelta );
SnapVector( bolt->s.pos.trDelta );
VectorCopy( start, bolt->r.currentOrigin );
return bolt;
}
/*
=================
fire_prox
=================
*/
gentity_t *fire_prox( gentity_t *self, vec3_t start, vec3_t dir ) {
gentity_t *bolt;
VectorNormalize (dir);
bolt = G_Spawn();
bolt->classname = "prox mine";
bolt->nextthink = level.time + 3000;
bolt->think = G_ExplodeMissile;
bolt->s.eType = ET_MISSILE;
bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN;
bolt->s.weapon = WP_PROX_LAUNCHER;
bolt->s.eFlags = 0;
bolt->r.ownerNum = self->s.number;
bolt->parent = self;
bolt->damage = 0;
bolt->splashDamage = 100;
bolt->splashRadius = 150;
bolt->methodOfDeath = MOD_PROXIMITY_MINE;
bolt->splashMethodOfDeath = MOD_PROXIMITY_MINE;
bolt->clipmask = MASK_SHOT;
bolt->target_ent = NULL;
// count is used to check if the prox mine left the player bbox
// if count == 1 then the prox mine left the player bbox and can attack to it
bolt->count = 0;
//FIXME: we prolly wanna abuse another field
bolt->s.generic1 = self->client->sess.sessionTeam;
bolt->s.pos.trType = TR_GRAVITY;
bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame
VectorCopy( start, bolt->s.pos.trBase );
VectorScale( dir, 700, bolt->s.pos.trDelta );
SnapVector( bolt->s.pos.trDelta ); // save net bandwidth
VectorCopy (start, bolt->r.currentOrigin);
return bolt;
}
#endif

1612
code/game/g_mover.c Normal file

File diff suppressed because it is too large Load diff

429
code/game/g_public.h Normal file
View file

@ -0,0 +1,429 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// g_public.h -- game module information visible to server
#define GAME_API_VERSION 8
// entity->svFlags
// the server does not know how to interpret most of the values
// in entityStates (level eType), so the game must explicitly flag
// special server behaviors
#define SVF_NOCLIENT 0x00000001 // don't send entity to clients, even if it has effects
// TTimo
// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=551
#define SVF_CLIENTMASK 0x00000002
#define SVF_BOT 0x00000008 // set if the entity is a bot
#define SVF_BROADCAST 0x00000020 // send to all connected clients
#define SVF_PORTAL 0x00000040 // merge a second pvs at origin2 into snapshots
#define SVF_USE_CURRENT_ORIGIN 0x00000080 // entity->r.currentOrigin instead of entity->s.origin
// for link position (missiles and movers)
#define SVF_SINGLECLIENT 0x00000100 // only send to a single client (entityShared_t->singleClient)
#define SVF_NOSERVERINFO 0x00000200 // don't send CS_SERVERINFO updates to this client
// so that it can be updated for ping tools without
// lagging clients
#define SVF_CAPSULE 0x00000400 // use capsule for collision detection instead of bbox
#define SVF_NOTSINGLECLIENT 0x00000800 // send entity to everyone but one client
// (entityShared_t->singleClient)
//===============================================================
typedef struct {
entityState_t s; // communicated by server to clients
qboolean linked; // qfalse if not in any good cluster
int linkcount;
int svFlags; // SVF_NOCLIENT, SVF_BROADCAST, etc
// only send to this client when SVF_SINGLECLIENT is set
// if SVF_CLIENTMASK is set, use bitmask for clients to send to (maxclients must be <= 32, up to the mod to enforce this)
int singleClient;
qboolean bmodel; // if false, assume an explicit mins / maxs bounding box
// only set by trap_SetBrushModel
vec3_t mins, maxs;
int contents; // CONTENTS_TRIGGER, CONTENTS_SOLID, CONTENTS_BODY, etc
// a non-solid entity should set to 0
vec3_t absmin, absmax; // derived from mins/maxs and origin + rotation
// currentOrigin will be used for all collision detection and world linking.
// it will not necessarily be the same as the trajectory evaluation for the current
// time, because each entity must be moved one at a time after time is advanced
// to avoid simultanious collision issues
vec3_t currentOrigin;
vec3_t currentAngles;
// when a trace call is made and passEntityNum != ENTITYNUM_NONE,
// an ent will be excluded from testing if:
// ent->s.number == passEntityNum (don't interact with self)
// ent->s.ownerNum = passEntityNum (don't interact with your own missiles)
// entity[ent->s.ownerNum].ownerNum = passEntityNum (don't interact with other missiles from owner)
int ownerNum;
} entityShared_t;
// the server looks at a sharedEntity, which is the start of the game's gentity_t structure
typedef struct {
entityState_t s; // communicated by server to clients
entityShared_t r; // shared by both the server system and game
} sharedEntity_t;
//===============================================================
//
// system traps provided by the main engine
//
typedef enum {
//============== general Quake services ==================
G_PRINT, // ( const char *string );
// print message on the local console
G_ERROR, // ( const char *string );
// abort the game
G_MILLISECONDS, // ( void );
// get current time for profiling reasons
// this should NOT be used for any game related tasks,
// because it is not journaled
// console variable interaction
G_CVAR_REGISTER, // ( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags );
G_CVAR_UPDATE, // ( vmCvar_t *vmCvar );
G_CVAR_SET, // ( const char *var_name, const char *value );
G_CVAR_VARIABLE_INTEGER_VALUE, // ( const char *var_name );
G_CVAR_VARIABLE_STRING_BUFFER, // ( const char *var_name, char *buffer, int bufsize );
G_ARGC, // ( void );
// ClientCommand and ServerCommand parameter access
G_ARGV, // ( int n, char *buffer, int bufferLength );
G_FS_FOPEN_FILE, // ( const char *qpath, fileHandle_t *file, fsMode_t mode );
G_FS_READ, // ( void *buffer, int len, fileHandle_t f );
G_FS_WRITE, // ( const void *buffer, int len, fileHandle_t f );
G_FS_FCLOSE_FILE, // ( fileHandle_t f );
G_SEND_CONSOLE_COMMAND, // ( const char *text );
// add commands to the console as if they were typed in
// for map changing, etc
//=========== server specific functionality =============
G_LOCATE_GAME_DATA, // ( gentity_t *gEnts, int numGEntities, int sizeofGEntity_t,
// playerState_t *clients, int sizeofGameClient );
// the game needs to let the server system know where and how big the gentities
// are, so it can look at them directly without going through an interface
G_DROP_CLIENT, // ( int clientNum, const char *reason );
// kick a client off the server with a message
G_SEND_SERVER_COMMAND, // ( int clientNum, const char *fmt, ... );
// reliably sends a command string to be interpreted by the given
// client. If clientNum is -1, it will be sent to all clients
G_SET_CONFIGSTRING, // ( int num, const char *string );
// config strings hold all the index strings, and various other information
// that is reliably communicated to all clients
// All of the current configstrings are sent to clients when
// they connect, and changes are sent to all connected clients.
// All confgstrings are cleared at each level start.
G_GET_CONFIGSTRING, // ( int num, char *buffer, int bufferSize );
G_GET_USERINFO, // ( int num, char *buffer, int bufferSize );
// userinfo strings are maintained by the server system, so they
// are persistant across level loads, while all other game visible
// data is completely reset
G_SET_USERINFO, // ( int num, const char *buffer );
G_GET_SERVERINFO, // ( char *buffer, int bufferSize );
// the serverinfo info string has all the cvars visible to server browsers
G_SET_BRUSH_MODEL, // ( gentity_t *ent, const char *name );
// sets mins and maxs based on the brushmodel name
G_TRACE, // ( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask );
// collision detection against all linked entities
G_POINT_CONTENTS, // ( const vec3_t point, int passEntityNum );
// point contents against all linked entities
G_IN_PVS, // ( const vec3_t p1, const vec3_t p2 );
G_IN_PVS_IGNORE_PORTALS, // ( const vec3_t p1, const vec3_t p2 );
G_ADJUST_AREA_PORTAL_STATE, // ( gentity_t *ent, qboolean open );
G_AREAS_CONNECTED, // ( int area1, int area2 );
G_LINKENTITY, // ( gentity_t *ent );
// an entity will never be sent to a client or used for collision
// if it is not passed to linkentity. If the size, position, or
// solidity changes, it must be relinked.
G_UNLINKENTITY, // ( gentity_t *ent );
// call before removing an interactive entity
G_ENTITIES_IN_BOX, // ( const vec3_t mins, const vec3_t maxs, gentity_t **list, int maxcount );
// EntitiesInBox will return brush models based on their bounding box,
// so exact determination must still be done with EntityContact
G_ENTITY_CONTACT, // ( const vec3_t mins, const vec3_t maxs, const gentity_t *ent );
// perform an exact check against inline brush models of non-square shape
// access for bots to get and free a server client (FIXME?)
G_BOT_ALLOCATE_CLIENT, // ( void );
G_BOT_FREE_CLIENT, // ( int clientNum );
G_GET_USERCMD, // ( int clientNum, usercmd_t *cmd )
G_GET_ENTITY_TOKEN, // qboolean ( char *buffer, int bufferSize )
// Retrieves the next string token from the entity spawn text, returning
// false when all tokens have been parsed.
// This should only be done at GAME_INIT time.
G_FS_GETFILELIST,
G_DEBUG_POLYGON_CREATE,
G_DEBUG_POLYGON_DELETE,
G_REAL_TIME,
G_SNAPVECTOR,
G_TRACECAPSULE, // ( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask );
G_ENTITY_CONTACTCAPSULE, // ( const vec3_t mins, const vec3_t maxs, const gentity_t *ent );
// 1.32
G_FS_SEEK,
BOTLIB_SETUP = 200, // ( void );
BOTLIB_SHUTDOWN, // ( void );
BOTLIB_LIBVAR_SET,
BOTLIB_LIBVAR_GET,
BOTLIB_PC_ADD_GLOBAL_DEFINE,
BOTLIB_START_FRAME,
BOTLIB_LOAD_MAP,
BOTLIB_UPDATENTITY,
BOTLIB_TEST,
BOTLIB_GET_SNAPSHOT_ENTITY, // ( int client, int ent );
BOTLIB_GET_CONSOLE_MESSAGE, // ( int client, char *message, int size );
BOTLIB_USER_COMMAND, // ( int client, usercmd_t *ucmd );
BOTLIB_AAS_ENABLE_ROUTING_AREA = 300,
BOTLIB_AAS_BBOX_AREAS,
BOTLIB_AAS_AREA_INFO,
BOTLIB_AAS_ENTITY_INFO,
BOTLIB_AAS_INITIALIZED,
BOTLIB_AAS_PRESENCE_TYPE_BOUNDING_BOX,
BOTLIB_AAS_TIME,
BOTLIB_AAS_POINT_AREA_NUM,
BOTLIB_AAS_TRACE_AREAS,
BOTLIB_AAS_POINT_CONTENTS,
BOTLIB_AAS_NEXT_BSP_ENTITY,
BOTLIB_AAS_VALUE_FOR_BSP_EPAIR_KEY,
BOTLIB_AAS_VECTOR_FOR_BSP_EPAIR_KEY,
BOTLIB_AAS_FLOAT_FOR_BSP_EPAIR_KEY,
BOTLIB_AAS_INT_FOR_BSP_EPAIR_KEY,
BOTLIB_AAS_AREA_REACHABILITY,
BOTLIB_AAS_AREA_TRAVEL_TIME_TO_GOAL_AREA,
BOTLIB_AAS_SWIMMING,
BOTLIB_AAS_PREDICT_CLIENT_MOVEMENT,
BOTLIB_EA_SAY = 400,
BOTLIB_EA_SAY_TEAM,
BOTLIB_EA_COMMAND,
BOTLIB_EA_ACTION,
BOTLIB_EA_GESTURE,
BOTLIB_EA_TALK,
BOTLIB_EA_ATTACK,
BOTLIB_EA_USE,
BOTLIB_EA_RESPAWN,
BOTLIB_EA_CROUCH,
BOTLIB_EA_MOVE_UP,
BOTLIB_EA_MOVE_DOWN,
BOTLIB_EA_MOVE_FORWARD,
BOTLIB_EA_MOVE_BACK,
BOTLIB_EA_MOVE_LEFT,
BOTLIB_EA_MOVE_RIGHT,
BOTLIB_EA_SELECT_WEAPON,
BOTLIB_EA_JUMP,
BOTLIB_EA_DELAYED_JUMP,
BOTLIB_EA_MOVE,
BOTLIB_EA_VIEW,
BOTLIB_EA_END_REGULAR,
BOTLIB_EA_GET_INPUT,
BOTLIB_EA_RESET_INPUT,
BOTLIB_AI_LOAD_CHARACTER = 500,
BOTLIB_AI_FREE_CHARACTER,
BOTLIB_AI_CHARACTERISTIC_FLOAT,
BOTLIB_AI_CHARACTERISTIC_BFLOAT,
BOTLIB_AI_CHARACTERISTIC_INTEGER,
BOTLIB_AI_CHARACTERISTIC_BINTEGER,
BOTLIB_AI_CHARACTERISTIC_STRING,
BOTLIB_AI_ALLOC_CHAT_STATE,
BOTLIB_AI_FREE_CHAT_STATE,
BOTLIB_AI_QUEUE_CONSOLE_MESSAGE,
BOTLIB_AI_REMOVE_CONSOLE_MESSAGE,
BOTLIB_AI_NEXT_CONSOLE_MESSAGE,
BOTLIB_AI_NUM_CONSOLE_MESSAGE,
BOTLIB_AI_INITIAL_CHAT,
BOTLIB_AI_REPLY_CHAT,
BOTLIB_AI_CHAT_LENGTH,
BOTLIB_AI_ENTER_CHAT,
BOTLIB_AI_STRING_CONTAINS,
BOTLIB_AI_FIND_MATCH,
BOTLIB_AI_MATCH_VARIABLE,
BOTLIB_AI_UNIFY_WHITE_SPACES,
BOTLIB_AI_REPLACE_SYNONYMS,
BOTLIB_AI_LOAD_CHAT_FILE,
BOTLIB_AI_SET_CHAT_GENDER,
BOTLIB_AI_SET_CHAT_NAME,
BOTLIB_AI_RESET_GOAL_STATE,
BOTLIB_AI_RESET_AVOID_GOALS,
BOTLIB_AI_PUSH_GOAL,
BOTLIB_AI_POP_GOAL,
BOTLIB_AI_EMPTY_GOAL_STACK,
BOTLIB_AI_DUMP_AVOID_GOALS,
BOTLIB_AI_DUMP_GOAL_STACK,
BOTLIB_AI_GOAL_NAME,
BOTLIB_AI_GET_TOP_GOAL,
BOTLIB_AI_GET_SECOND_GOAL,
BOTLIB_AI_CHOOSE_LTG_ITEM,
BOTLIB_AI_CHOOSE_NBG_ITEM,
BOTLIB_AI_TOUCHING_GOAL,
BOTLIB_AI_ITEM_GOAL_IN_VIS_BUT_NOT_VISIBLE,
BOTLIB_AI_GET_LEVEL_ITEM_GOAL,
BOTLIB_AI_AVOID_GOAL_TIME,
BOTLIB_AI_INIT_LEVEL_ITEMS,
BOTLIB_AI_UPDATE_ENTITY_ITEMS,
BOTLIB_AI_LOAD_ITEM_WEIGHTS,
BOTLIB_AI_FREE_ITEM_WEIGHTS,
BOTLIB_AI_SAVE_GOAL_FUZZY_LOGIC,
BOTLIB_AI_ALLOC_GOAL_STATE,
BOTLIB_AI_FREE_GOAL_STATE,
BOTLIB_AI_RESET_MOVE_STATE,
BOTLIB_AI_MOVE_TO_GOAL,
BOTLIB_AI_MOVE_IN_DIRECTION,
BOTLIB_AI_RESET_AVOID_REACH,
BOTLIB_AI_RESET_LAST_AVOID_REACH,
BOTLIB_AI_REACHABILITY_AREA,
BOTLIB_AI_MOVEMENT_VIEW_TARGET,
BOTLIB_AI_ALLOC_MOVE_STATE,
BOTLIB_AI_FREE_MOVE_STATE,
BOTLIB_AI_INIT_MOVE_STATE,
BOTLIB_AI_CHOOSE_BEST_FIGHT_WEAPON,
BOTLIB_AI_GET_WEAPON_INFO,
BOTLIB_AI_LOAD_WEAPON_WEIGHTS,
BOTLIB_AI_ALLOC_WEAPON_STATE,
BOTLIB_AI_FREE_WEAPON_STATE,
BOTLIB_AI_RESET_WEAPON_STATE,
BOTLIB_AI_GENETIC_PARENTS_AND_CHILD_SELECTION,
BOTLIB_AI_INTERBREED_GOAL_FUZZY_LOGIC,
BOTLIB_AI_MUTATE_GOAL_FUZZY_LOGIC,
BOTLIB_AI_GET_NEXT_CAMP_SPOT_GOAL,
BOTLIB_AI_GET_MAP_LOCATION_GOAL,
BOTLIB_AI_NUM_INITIAL_CHATS,
BOTLIB_AI_GET_CHAT_MESSAGE,
BOTLIB_AI_REMOVE_FROM_AVOID_GOALS,
BOTLIB_AI_PREDICT_VISIBLE_POSITION,
BOTLIB_AI_SET_AVOID_GOAL_TIME,
BOTLIB_AI_ADD_AVOID_SPOT,
BOTLIB_AAS_ALTERNATIVE_ROUTE_GOAL,
BOTLIB_AAS_PREDICT_ROUTE,
BOTLIB_AAS_POINT_REACHABILITY_AREA_INDEX,
BOTLIB_PC_LOAD_SOURCE,
BOTLIB_PC_FREE_SOURCE,
BOTLIB_PC_READ_TOKEN,
BOTLIB_PC_SOURCE_FILE_AND_LINE
} gameImport_t;
//
// functions exported by the game subsystem
//
typedef enum {
GAME_INIT, // ( int levelTime, int randomSeed, int restart );
// init and shutdown will be called every single level
// The game should call G_GET_ENTITY_TOKEN to parse through all the
// entity configuration text and spawn gentities.
GAME_SHUTDOWN, // (void);
GAME_CLIENT_CONNECT, // ( int clientNum, qboolean firstTime, qboolean isBot );
// return NULL if the client is allowed to connect, otherwise return
// a text string with the reason for denial
GAME_CLIENT_BEGIN, // ( int clientNum );
GAME_CLIENT_USERINFO_CHANGED, // ( int clientNum );
GAME_CLIENT_DISCONNECT, // ( int clientNum );
GAME_CLIENT_COMMAND, // ( int clientNum );
GAME_CLIENT_THINK, // ( int clientNum );
GAME_RUN_FRAME, // ( int levelTime );
GAME_CONSOLE_COMMAND, // ( void );
// ConsoleCommand will be called when a command has been issued
// that is not recognized as a builtin function.
// The game can issue trap_argc() / trap_argv() commands to get the command
// and parameters. Return qfalse if the game doesn't recognize it as a command.
BOTAI_START_FRAME // ( int time );
} gameExport_t;

1135
code/game/g_rankings.c Normal file

File diff suppressed because it is too large Load diff

396
code/game/g_rankings.h Normal file
View file

@ -0,0 +1,396 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// g_rankings.h -- score keys for global rankings
#ifndef _G_RANKINGS_H_
#define _G_RANKINGS_H_
/*
==============================================================================
Key digits:
10^9: report type
1 = normal
2 = developer-only
10^8: stat type
0 = match stat
1 = single player stat
2 = duel stat
10^7: data type
0 = string
1 = uint32
10^6: calculation
0 = use raw value
1 = add to total
2 = average
3 = max
4 = min
10^5
10^4: category
00 = general
01 = session
02 = weapon
03 = ammo
04 = health
05 = armor
06 = powerup
07 = holdable
08 = hazard
09 = reward
10 = teammate
11 = ctf
10^3:
10^2: sub-category
10^1:
10^0: ordinal
==============================================================================
*/
// general keys
#define QGR_KEY_MATCH_RATING 1112000001
#define QGR_KEY_PLAYED_WITH 1210000002
// session keys
#define QGR_KEY_HOSTNAME 1000010000
#define QGR_KEY_MAP 1000010001
#define QGR_KEY_MOD 1000010002
#define QGR_KEY_GAMETYPE 1010010003
#define QGR_KEY_FRAGLIMIT 1010010004
#define QGR_KEY_TIMELIMIT 1010010005
#define QGR_KEY_MAXCLIENTS 1010010006
#define QGR_KEY_MAXRATE 1010010007
#define QGR_KEY_MINPING 1010010008
#define QGR_KEY_MAXPING 1010010009
#define QGR_KEY_DEDICATED 1010010010
#define QGR_KEY_VERSION 1000010011
// weapon keys
#define QGR_KEY_FRAG 1211020000
#define QGR_KEY_SUICIDE 1111020001
#define QGR_KEY_SHOT_FIRED 1111020002
#define QGR_KEY_HIT_GIVEN 1111020003
#define QGR_KEY_HIT_TAKEN 1111020004
#define QGR_KEY_DAMAGE_GIVEN 1111020005
#define QGR_KEY_DAMAGE_TAKEN 1111020006
#define QGR_KEY_SPLASH_GIVEN 1111020007
#define QGR_KEY_SPLASH_TAKEN 1111020008
#define QGR_KEY_PICKUP_WEAPON 1111020009
#define QGR_KEY_TIME 1111020010
#define QGR_KEY_FRAG_GAUNTLET 1211020100
#define QGR_KEY_SUICIDE_GAUNTLET 1111020101
#define QGR_KEY_SHOT_FIRED_GAUNTLET 1111020102
#define QGR_KEY_HIT_GIVEN_GAUNTLET 1111020103
#define QGR_KEY_HIT_TAKEN_GAUNTLET 1111020104
#define QGR_KEY_DAMAGE_GIVEN_GAUNTLET 1111020105
#define QGR_KEY_DAMAGE_TAKEN_GAUNTLET 1111020106
#define QGR_KEY_SPLASH_GIVEN_GAUNTLET 1111020107
#define QGR_KEY_SPLASH_TAKEN_GAUNTLET 1111020108
#define QGR_KEY_PICKUP_GAUNTLET 1111020109
#define QGR_KEY_TIME_GAUNTLET 1111020110
#define QGR_KEY_FRAG_MACHINEGUN 1211020200
#define QGR_KEY_SUICIDE_MACHINEGUN 1111020201
#define QGR_KEY_SHOT_FIRED_MACHINEGUN 1111020202
#define QGR_KEY_HIT_GIVEN_MACHINEGUN 1111020203
#define QGR_KEY_HIT_TAKEN_MACHINEGUN 1111020204
#define QGR_KEY_DAMAGE_GIVEN_MACHINEGUN 1111020205
#define QGR_KEY_DAMAGE_TAKEN_MACHINEGUN 1111020206
#define QGR_KEY_SPLASH_GIVEN_MACHINEGUN 1111020207
#define QGR_KEY_SPLASH_TAKEN_MACHINEGUN 1111020208
#define QGR_KEY_PICKUP_MACHINEGUN 1111020209
#define QGR_KEY_TIME_MACHINEGUN 1111020210
#define QGR_KEY_FRAG_SHOTGUN 1211020300
#define QGR_KEY_SUICIDE_SHOTGUN 1111020301
#define QGR_KEY_SHOT_FIRED_SHOTGUN 1111020302
#define QGR_KEY_HIT_GIVEN_SHOTGUN 1111020303
#define QGR_KEY_HIT_TAKEN_SHOTGUN 1111020304
#define QGR_KEY_DAMAGE_GIVEN_SHOTGUN 1111020305
#define QGR_KEY_DAMAGE_TAKEN_SHOTGUN 1111020306
#define QGR_KEY_SPLASH_GIVEN_SHOTGUN 1111020307
#define QGR_KEY_SPLASH_TAKEN_SHOTGUN 1111020308
#define QGR_KEY_PICKUP_SHOTGUN 1111020309
#define QGR_KEY_TIME_SHOTGUN 1111020310
#define QGR_KEY_FRAG_GRENADE 1211020400
#define QGR_KEY_SUICIDE_GRENADE 1111020401
#define QGR_KEY_SHOT_FIRED_GRENADE 1111020402
#define QGR_KEY_HIT_GIVEN_GRENADE 1111020403
#define QGR_KEY_HIT_TAKEN_GRENADE 1111020404
#define QGR_KEY_DAMAGE_GIVEN_GRENADE 1111020405
#define QGR_KEY_DAMAGE_TAKEN_GRENADE 1111020406
#define QGR_KEY_SPLASH_GIVEN_GRENADE 1111020407
#define QGR_KEY_SPLASH_TAKEN_GRENADE 1111020408
#define QGR_KEY_PICKUP_GRENADE 1111020409
#define QGR_KEY_TIME_GRENADE 1111020410
#define QGR_KEY_FRAG_ROCKET 1211020500
#define QGR_KEY_SUICIDE_ROCKET 1111020501
#define QGR_KEY_SHOT_FIRED_ROCKET 1111020502
#define QGR_KEY_HIT_GIVEN_ROCKET 1111020503
#define QGR_KEY_HIT_TAKEN_ROCKET 1111020504
#define QGR_KEY_DAMAGE_GIVEN_ROCKET 1111020505
#define QGR_KEY_DAMAGE_TAKEN_ROCKET 1111020506
#define QGR_KEY_SPLASH_GIVEN_ROCKET 1111020507
#define QGR_KEY_SPLASH_TAKEN_ROCKET 1111020508
#define QGR_KEY_PICKUP_ROCKET 1111020509
#define QGR_KEY_TIME_ROCKET 1111020510
#define QGR_KEY_FRAG_PLASMA 1211020600
#define QGR_KEY_SUICIDE_PLASMA 1111020601
#define QGR_KEY_SHOT_FIRED_PLASMA 1111020602
#define QGR_KEY_HIT_GIVEN_PLASMA 1111020603
#define QGR_KEY_HIT_TAKEN_PLASMA 1111020604
#define QGR_KEY_DAMAGE_GIVEN_PLASMA 1111020605
#define QGR_KEY_DAMAGE_TAKEN_PLASMA 1111020606
#define QGR_KEY_SPLASH_GIVEN_PLASMA 1111020607
#define QGR_KEY_SPLASH_TAKEN_PLASMA 1111020608
#define QGR_KEY_PICKUP_PLASMA 1111020609
#define QGR_KEY_TIME_PLASMA 1111020610
#define QGR_KEY_FRAG_RAILGUN 1211020700
#define QGR_KEY_SUICIDE_RAILGUN 1111020701
#define QGR_KEY_SHOT_FIRED_RAILGUN 1111020702
#define QGR_KEY_HIT_GIVEN_RAILGUN 1111020703
#define QGR_KEY_HIT_TAKEN_RAILGUN 1111020704
#define QGR_KEY_DAMAGE_GIVEN_RAILGUN 1111020705
#define QGR_KEY_DAMAGE_TAKEN_RAILGUN 1111020706
#define QGR_KEY_SPLASH_GIVEN_RAILGUN 1111020707
#define QGR_KEY_SPLASH_TAKEN_RAILGUN 1111020708
#define QGR_KEY_PICKUP_RAILGUN 1111020709
#define QGR_KEY_TIME_RAILGUN 1111020710
#define QGR_KEY_FRAG_LIGHTNING 1211020800
#define QGR_KEY_SUICIDE_LIGHTNING 1111020801
#define QGR_KEY_SHOT_FIRED_LIGHTNING 1111020802
#define QGR_KEY_HIT_GIVEN_LIGHTNING 1111020803
#define QGR_KEY_HIT_TAKEN_LIGHTNING 1111020804
#define QGR_KEY_DAMAGE_GIVEN_LIGHTNING 1111020805
#define QGR_KEY_DAMAGE_TAKEN_LIGHTNING 1111020806
#define QGR_KEY_SPLASH_GIVEN_LIGHTNING 1111020807
#define QGR_KEY_SPLASH_TAKEN_LIGHTNING 1111020808
#define QGR_KEY_PICKUP_LIGHTNING 1111020809
#define QGR_KEY_TIME_LIGHTNING 1111020810
#define QGR_KEY_FRAG_BFG 1211020900
#define QGR_KEY_SUICIDE_BFG 1111020901
#define QGR_KEY_SHOT_FIRED_BFG 1111020902
#define QGR_KEY_HIT_GIVEN_BFG 1111020903
#define QGR_KEY_HIT_TAKEN_BFG 1111020904
#define QGR_KEY_DAMAGE_GIVEN_BFG 1111020905
#define QGR_KEY_DAMAGE_TAKEN_BFG 1111020906
#define QGR_KEY_SPLASH_GIVEN_BFG 1111020907
#define QGR_KEY_SPLASH_TAKEN_BFG 1111020908
#define QGR_KEY_PICKUP_BFG 1111020909
#define QGR_KEY_TIME_BFG 1111020910
#define QGR_KEY_FRAG_GRAPPLE 1211021000
#define QGR_KEY_SUICIDE_GRAPPLE 1111021001
#define QGR_KEY_SHOT_FIRED_GRAPPLE 1111021002
#define QGR_KEY_HIT_GIVEN_GRAPPLE 1111021003
#define QGR_KEY_HIT_TAKEN_GRAPPLE 1111021004
#define QGR_KEY_DAMAGE_GIVEN_GRAPPLE 1111021005
#define QGR_KEY_DAMAGE_TAKEN_GRAPPLE 1111021006
#define QGR_KEY_SPLASH_GIVEN_GRAPPLE 1111021007
#define QGR_KEY_SPLASH_TAKEN_GRAPPLE 1111021008
#define QGR_KEY_PICKUP_GRAPPLE 1111021009
#define QGR_KEY_TIME_GRAPPLE 1111021010
#define QGR_KEY_FRAG_UNKNOWN 1211021100
#define QGR_KEY_SUICIDE_UNKNOWN 1111021101
#define QGR_KEY_SHOT_FIRED_UNKNOWN 1111021102
#define QGR_KEY_HIT_GIVEN_UNKNOWN 1111021103
#define QGR_KEY_HIT_TAKEN_UNKNOWN 1111021104
#define QGR_KEY_DAMAGE_GIVEN_UNKNOWN 1111021105
#define QGR_KEY_DAMAGE_TAKEN_UNKNOWN 1111021106
#define QGR_KEY_SPLASH_GIVEN_UNKNOWN 1111021107
#define QGR_KEY_SPLASH_TAKEN_UNKNOWN 1111021108
#define QGR_KEY_PICKUP_UNKNOWN 1111021109
#define QGR_KEY_TIME_UNKNOWN 1111021110
#ifdef MISSIONPACK
// new to team arena
#define QGR_KEY_FRAG_NAILGIN 1211021200
#define QGR_KEY_SUICIDE_NAILGIN 1111021201
#define QGR_KEY_SHOT_FIRED_NAILGIN 1111021202
#define QGR_KEY_HIT_GIVEN_NAILGIN 1111021203
#define QGR_KEY_HIT_TAKEN_NAILGIN 1111021204
#define QGR_KEY_DAMAGE_GIVEN_NAILGIN 1111021205
#define QGR_KEY_DAMAGE_TAKEN_NAILGIN 1111021206
#define QGR_KEY_SPLASH_GIVEN_NAILGIN 1111021207
#define QGR_KEY_SPLASH_TAKEN_NAILGIN 1111021208
#define QGR_KEY_PICKUP_NAILGIN 1111021209
#define QGR_KEY_TIME_NAILGIN 1111021210
// new to team arena
#define QGR_KEY_FRAG_PROX_LAUNCHER 1211021300
#define QGR_KEY_SUICIDE_PROX_LAUNCHER 1111021301
#define QGR_KEY_SHOT_FIRED_PROX_LAUNCHER 1111021302
#define QGR_KEY_HIT_GIVEN_PROX_LAUNCHER 1111021303
#define QGR_KEY_HIT_TAKEN_PROX_LAUNCHER 1111021304
#define QGR_KEY_DAMAGE_GIVEN_PROX_LAUNCHER 1111021305
#define QGR_KEY_DAMAGE_TAKEN_PROX_LAUNCHER 1111021306
#define QGR_KEY_SPLASH_GIVEN_PROX_LAUNCHER 1111021307
#define QGR_KEY_SPLASH_TAKEN_PROX_LAUNCHER 1111021308
#define QGR_KEY_PICKUP_PROX_LAUNCHER 1111021309
#define QGR_KEY_TIME_PROX_LAUNCHER 1111021310
// new to team arena
#define QGR_KEY_FRAG_CHAINGUN 1211021400
#define QGR_KEY_SUICIDE_CHAINGUN 1111021401
#define QGR_KEY_SHOT_FIRED_CHAINGUN 1111021402
#define QGR_KEY_HIT_GIVEN_CHAINGUN 1111021403
#define QGR_KEY_HIT_TAKEN_CHAINGUN 1111021404
#define QGR_KEY_DAMAGE_GIVEN_CHAINGUN 1111021405
#define QGR_KEY_DAMAGE_TAKEN_CHAINGUN 1111021406
#define QGR_KEY_SPLASH_GIVEN_CHAINGUN 1111021407
#define QGR_KEY_SPLASH_TAKEN_CHAINGUN 1111021408
#define QGR_KEY_PICKUP_CHAINGUN 1111021409
#define QGR_KEY_TIME_CHAINGUN 1111021410
#endif /* MISSIONPACK */
// ammo keys
#define QGR_KEY_BOXES 1111030000
#define QGR_KEY_ROUNDS 1111030001
#define QGR_KEY_BOXES_BULLETS 1111030100
#define QGR_KEY_ROUNDS_BULLETS 1111030101
#define QGR_KEY_BOXES_SHELLS 1111030200
#define QGR_KEY_ROUNDS_SHELLS 1111030201
#define QGR_KEY_BOXES_GRENADES 1111030300
#define QGR_KEY_ROUNDS_GRENADES 1111030301
#define QGR_KEY_BOXES_ROCKETS 1111030400
#define QGR_KEY_ROUNDS_ROCKETS 1111030401
#define QGR_KEY_BOXES_CELLS 1111030500
#define QGR_KEY_ROUNDS_CELLS 1111030501
#define QGR_KEY_BOXES_SLUGS 1111030600
#define QGR_KEY_ROUNDS_SLUGS 1111030601
#define QGR_KEY_BOXES_LG_AMMO 1111030700
#define QGR_KEY_ROUNDS_LG_AMMO 1111030701
#define QGR_KEY_BOXES_BFG_AMMO 1111030800
#define QGR_KEY_ROUNDS_BFG_AMMO 1111030801
#ifdef MISSIONPACK
// new to team arena
#define QGR_KEY_BOXES_NAILGUN_AMMO 1111030900
#define QGR_KEY_ROUNDS_NAILGUN_AMMO 1111030901
// new to team arena
#define QGR_KEY_BOXES_PROX_LAUNCHER_AMMO 1111031000
#define QGR_KEY_ROUNDS_PROX_LAUNCHER_AMMO 1111031001
// new to team arena
#define QGR_KEY_BOXES_CHAINGUN_AMMO 1111031100
#define QGR_KEY_ROUNDS_CHAINGUN_AMMO 1111031101
#endif /* MISSIONPACK */
// health keys
#define QGR_KEY_HEALTH 1111040000
#define QGR_KEY_HEALTH_TOTAL 1111040001
#define QGR_KEY_HEALTH_5 1111040100
#define QGR_KEY_HEALTH_25 1111040200
#define QGR_KEY_HEALTH_50 1111040300
#define QGR_KEY_HEALTH_MEGA 1111040400
// armor keys
#define QGR_KEY_ARMOR 1111050000
#define QGR_KEY_ARMOR_TOTAL 1111050001
#define QGR_KEY_ARMOR_SHARD 1111050100
#define QGR_KEY_ARMOR_YELLOW 1111050200
#define QGR_KEY_ARMOR_RED 1111050300
// powerup keys
#define QGR_KEY_POWERUP 1111060000
#define QGR_KEY_QUAD 1111060100
#define QGR_KEY_SUIT 1111060200
#define QGR_KEY_HASTE 1111060300
#define QGR_KEY_INVIS 1111060400
#define QGR_KEY_REGEN 1111060500
#define QGR_KEY_FLIGHT 1111060600
#ifdef MISSIONPACK
// persistant powerup keys
// new to team arena
#define QGR_KEY_SCOUT 1111160800
#define QGR_KEY_GUARD 1111160801
#define QGR_KEY_DOUBLER 1111160802
#define QGR_KEY_AMMOREGEN 1111160803
#endif //MISSIONPACK
// holdable item keys
#define QGR_KEY_MEDKIT 1111070000
#define QGR_KEY_MEDKIT_USE 1111070001
#define QGR_KEY_TELEPORTER 1111070100
#define QGR_KEY_TELEPORTER_USE 1111070101
#ifdef MISSIONPACK
// new to team arena
#define QGR_KEY_KAMIKAZE 1111070200
#define QGR_KEY_KAMIKAZE_USE 1111070201
// new to team arena
#define QGR_KEY_PORTAL 1111070300
#define QGR_KEY_PORTAL_USE 1111070301
// new to team arena
#define QGR_KEY_INVULNERABILITY 1111070400
#define QGR_KEY_INVULNERABILITY_USE 1111070401
#endif /* MISSIONPACK */
// hazard keys
#define QGR_KEY_HAZARD_DEATH 1111080000
#define QGR_KEY_WATER 1111080100
#define QGR_KEY_SLIME 1111080200
#define QGR_KEY_LAVA 1111080300
#define QGR_KEY_CRUSH 1111080400
#define QGR_KEY_TELEFRAG 1111080500
#define QGR_KEY_FALLING 1111080600
#define QGR_KEY_SUICIDE_CMD 1111080700
#define QGR_KEY_TRIGGER_HURT 1111080800
#define QGR_KEY_HAZARD_MISC 1111080900
// reward keys
#define QGR_KEY_IMPRESSIVE 1111090000
#define QGR_KEY_EXCELLENT 1111090100
// teammate keys
#define QGR_KEY_TEAMMATE_FRAG 1211100000
#define QGR_KEY_TEAMMATE_HIT_GIVEN 1111100001
#define QGR_KEY_TEAMMATE_HIT_TAKEN 1111100002
#define QGR_KEY_TEAMMATE_DAMAGE_GIVEN 1111100003
#define QGR_KEY_TEAMMATE_DAMAGE_TAKEN 1111100004
#define QGR_KEY_TEAMMATE_SPLASH_GIVEN 1111100005
#define QGR_KEY_TEAMMATE_SPLASH_TAKEN 1111100006
#define QGR_KEY_TEAM_NAME 1100100007
// ctf keys
#define QGR_KEY_FLAG_PICKUP 1111110000
#define QGR_KEY_FLAG_CAPTURE 1111110001
#endif // _G_RANKINGS_H_

193
code/game/g_session.c Normal file
View file

@ -0,0 +1,193 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
#include "g_local.h"
/*
=======================================================================
SESSION DATA
Session data is the only data that stays persistant across level loads
and tournament restarts.
=======================================================================
*/
/*
================
G_WriteClientSessionData
Called on game shutdown
================
*/
void G_WriteClientSessionData( gclient_t *client ) {
const char *s;
const char *var;
s = va("%i %i %i %i %i %i %i",
client->sess.sessionTeam,
client->sess.spectatorTime,
client->sess.spectatorState,
client->sess.spectatorClient,
client->sess.wins,
client->sess.losses,
client->sess.teamLeader
);
var = va( "session%i", client - level.clients );
trap_Cvar_Set( var, s );
}
/*
================
G_ReadSessionData
Called on a reconnect
================
*/
void G_ReadSessionData( gclient_t *client ) {
char s[MAX_STRING_CHARS];
const char *var;
// bk001205 - format
int teamLeader;
int spectatorState;
int sessionTeam;
var = va( "session%i", client - level.clients );
trap_Cvar_VariableStringBuffer( var, s, sizeof(s) );
sscanf( s, "%i %i %i %i %i %i %i",
&sessionTeam, // bk010221 - format
&client->sess.spectatorTime,
&spectatorState, // bk010221 - format
&client->sess.spectatorClient,
&client->sess.wins,
&client->sess.losses,
&teamLeader // bk010221 - format
);
// bk001205 - format issues
client->sess.sessionTeam = (team_t)sessionTeam;
client->sess.spectatorState = (spectatorState_t)spectatorState;
client->sess.teamLeader = (qboolean)teamLeader;
}
/*
================
G_InitSessionData
Called on a first-time connect
================
*/
void G_InitSessionData( gclient_t *client, char *userinfo ) {
clientSession_t *sess;
const char *value;
sess = &client->sess;
// initial team determination
if ( g_gametype.integer >= GT_TEAM ) {
if ( g_teamAutoJoin.integer ) {
sess->sessionTeam = PickTeam( -1 );
BroadcastTeamChange( client, -1 );
} else {
// always spawn as spectator in team games
sess->sessionTeam = TEAM_SPECTATOR;
}
} else {
value = Info_ValueForKey( userinfo, "team" );
if ( value[0] == 's' ) {
// a willing spectator, not a waiting-in-line
sess->sessionTeam = TEAM_SPECTATOR;
} else {
switch ( g_gametype.integer ) {
default:
case GT_FFA:
case GT_SINGLE_PLAYER:
if ( g_maxGameClients.integer > 0 &&
level.numNonSpectatorClients >= g_maxGameClients.integer ) {
sess->sessionTeam = TEAM_SPECTATOR;
} else {
sess->sessionTeam = TEAM_FREE;
}
break;
case GT_TOURNAMENT:
// if the game is full, go into a waiting mode
if ( level.numNonSpectatorClients >= 2 ) {
sess->sessionTeam = TEAM_SPECTATOR;
} else {
sess->sessionTeam = TEAM_FREE;
}
break;
}
}
}
sess->spectatorState = SPECTATOR_FREE;
sess->spectatorTime = level.time;
G_WriteClientSessionData( client );
}
/*
==================
G_InitWorldSession
==================
*/
void G_InitWorldSession( void ) {
char s[MAX_STRING_CHARS];
int gt;
trap_Cvar_VariableStringBuffer( "session", s, sizeof(s) );
gt = atoi( s );
// if the gametype changed since the last session, don't use any
// client sessions
if ( g_gametype.integer != gt ) {
level.newSession = qtrue;
G_Printf( "Gametype changed, clearing session data.\n" );
}
}
/*
==================
G_WriteSessionData
==================
*/
void G_WriteSessionData( void ) {
int i;
trap_Cvar_Set( "session", va("%i", g_gametype.integer) );
for ( i = 0 ; i < level.maxclients ; i++ ) {
if ( level.clients[i].pers.connected == CON_CONNECTED ) {
G_WriteClientSessionData( &level.clients[i] );
}
}
}

643
code/game/g_spawn.c Normal file
View file

@ -0,0 +1,643 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
#include "g_local.h"
qboolean G_SpawnString( const char *key, const char *defaultString, char **out ) {
int i;
if ( !level.spawning ) {
*out = (char *)defaultString;
// G_Error( "G_SpawnString() called while not spawning" );
}
for ( i = 0 ; i < level.numSpawnVars ; i++ ) {
if ( !Q_stricmp( key, level.spawnVars[i][0] ) ) {
*out = level.spawnVars[i][1];
return qtrue;
}
}
*out = (char *)defaultString;
return qfalse;
}
qboolean G_SpawnFloat( const char *key, const char *defaultString, float *out ) {
char *s;
qboolean present;
present = G_SpawnString( key, defaultString, &s );
*out = atof( s );
return present;
}
qboolean G_SpawnInt( const char *key, const char *defaultString, int *out ) {
char *s;
qboolean present;
present = G_SpawnString( key, defaultString, &s );
*out = atoi( s );
return present;
}
qboolean G_SpawnVector( const char *key, const char *defaultString, float *out ) {
char *s;
qboolean present;
present = G_SpawnString( key, defaultString, &s );
sscanf( s, "%f %f %f", &out[0], &out[1], &out[2] );
return present;
}
//
// fields are needed for spawning from the entity string
//
typedef enum {
F_INT,
F_FLOAT,
F_LSTRING, // string on disk, pointer in memory, TAG_LEVEL
F_GSTRING, // string on disk, pointer in memory, TAG_GAME
F_VECTOR,
F_ANGLEHACK,
F_ENTITY, // index on disk, pointer in memory
F_ITEM, // index on disk, pointer in memory
F_CLIENT, // index on disk, pointer in memory
F_IGNORE
} fieldtype_t;
typedef struct
{
char *name;
int ofs;
fieldtype_t type;
int flags;
} field_t;
field_t fields[] = {
{"classname", FOFS(classname), F_LSTRING},
{"origin", FOFS(s.origin), F_VECTOR},
{"model", FOFS(model), F_LSTRING},
{"model2", FOFS(model2), F_LSTRING},
{"spawnflags", FOFS(spawnflags), F_INT},
{"speed", FOFS(speed), F_FLOAT},
{"target", FOFS(target), F_LSTRING},
{"targetname", FOFS(targetname), F_LSTRING},
{"message", FOFS(message), F_LSTRING},
{"team", FOFS(team), F_LSTRING},
{"wait", FOFS(wait), F_FLOAT},
{"random", FOFS(random), F_FLOAT},
{"count", FOFS(count), F_INT},
{"health", FOFS(health), F_INT},
{"light", 0, F_IGNORE},
{"dmg", FOFS(damage), F_INT},
{"angles", FOFS(s.angles), F_VECTOR},
{"angle", FOFS(s.angles), F_ANGLEHACK},
{"targetShaderName", FOFS(targetShaderName), F_LSTRING},
{"targetShaderNewName", FOFS(targetShaderNewName), F_LSTRING},
{NULL}
};
typedef struct {
char *name;
void (*spawn)(gentity_t *ent);
} spawn_t;
void SP_info_player_start (gentity_t *ent);
void SP_info_player_deathmatch (gentity_t *ent);
void SP_info_player_intermission (gentity_t *ent);
void SP_info_firstplace(gentity_t *ent);
void SP_info_secondplace(gentity_t *ent);
void SP_info_thirdplace(gentity_t *ent);
void SP_info_podium(gentity_t *ent);
void SP_func_plat (gentity_t *ent);
void SP_func_static (gentity_t *ent);
void SP_func_rotating (gentity_t *ent);
void SP_func_bobbing (gentity_t *ent);
void SP_func_pendulum( gentity_t *ent );
void SP_func_button (gentity_t *ent);
void SP_func_door (gentity_t *ent);
void SP_func_train (gentity_t *ent);
void SP_func_timer (gentity_t *self);
void SP_trigger_always (gentity_t *ent);
void SP_trigger_multiple (gentity_t *ent);
void SP_trigger_push (gentity_t *ent);
void SP_trigger_teleport (gentity_t *ent);
void SP_trigger_hurt (gentity_t *ent);
void SP_target_remove_powerups( gentity_t *ent );
void SP_target_give (gentity_t *ent);
void SP_target_delay (gentity_t *ent);
void SP_target_speaker (gentity_t *ent);
void SP_target_print (gentity_t *ent);
void SP_target_laser (gentity_t *self);
void SP_target_character (gentity_t *ent);
void SP_target_score( gentity_t *ent );
void SP_target_teleporter( gentity_t *ent );
void SP_target_relay (gentity_t *ent);
void SP_target_kill (gentity_t *ent);
void SP_target_position (gentity_t *ent);
void SP_target_location (gentity_t *ent);
void SP_target_push (gentity_t *ent);
void SP_light (gentity_t *self);
void SP_info_null (gentity_t *self);
void SP_info_notnull (gentity_t *self);
void SP_info_camp (gentity_t *self);
void SP_path_corner (gentity_t *self);
void SP_misc_teleporter_dest (gentity_t *self);
void SP_misc_model(gentity_t *ent);
void SP_misc_portal_camera(gentity_t *ent);
void SP_misc_portal_surface(gentity_t *ent);
void SP_shooter_rocket( gentity_t *ent );
void SP_shooter_plasma( gentity_t *ent );
void SP_shooter_grenade( gentity_t *ent );
void SP_team_CTF_redplayer( gentity_t *ent );
void SP_team_CTF_blueplayer( gentity_t *ent );
void SP_team_CTF_redspawn( gentity_t *ent );
void SP_team_CTF_bluespawn( gentity_t *ent );
#ifdef MISSIONPACK
void SP_team_blueobelisk( gentity_t *ent );
void SP_team_redobelisk( gentity_t *ent );
void SP_team_neutralobelisk( gentity_t *ent );
#endif
void SP_item_botroam( gentity_t *ent ) {};
spawn_t spawns[] = {
// info entities don't do anything at all, but provide positional
// information for things controlled by other processes
{"info_player_start", SP_info_player_start},
{"info_player_deathmatch", SP_info_player_deathmatch},
{"info_player_intermission", SP_info_player_intermission},
{"info_null", SP_info_null},
{"info_notnull", SP_info_notnull}, // use target_position instead
{"info_camp", SP_info_camp},
{"func_plat", SP_func_plat},
{"func_button", SP_func_button},
{"func_door", SP_func_door},
{"func_static", SP_func_static},
{"func_rotating", SP_func_rotating},
{"func_bobbing", SP_func_bobbing},
{"func_pendulum", SP_func_pendulum},
{"func_train", SP_func_train},
{"func_group", SP_info_null},
{"func_timer", SP_func_timer}, // rename trigger_timer?
// Triggers are brush objects that cause an effect when contacted
// by a living player, usually involving firing targets.
// While almost everything could be done with
// a single trigger class and different targets, triggered effects
// could not be client side predicted (push and teleport).
{"trigger_always", SP_trigger_always},
{"trigger_multiple", SP_trigger_multiple},
{"trigger_push", SP_trigger_push},
{"trigger_teleport", SP_trigger_teleport},
{"trigger_hurt", SP_trigger_hurt},
// targets perform no action by themselves, but must be triggered
// by another entity
{"target_give", SP_target_give},
{"target_remove_powerups", SP_target_remove_powerups},
{"target_delay", SP_target_delay},
{"target_speaker", SP_target_speaker},
{"target_print", SP_target_print},
{"target_laser", SP_target_laser},
{"target_score", SP_target_score},
{"target_teleporter", SP_target_teleporter},
{"target_relay", SP_target_relay},
{"target_kill", SP_target_kill},
{"target_position", SP_target_position},
{"target_location", SP_target_location},
{"target_push", SP_target_push},
{"light", SP_light},
{"path_corner", SP_path_corner},
{"misc_teleporter_dest", SP_misc_teleporter_dest},
{"misc_model", SP_misc_model},
{"misc_portal_surface", SP_misc_portal_surface},
{"misc_portal_camera", SP_misc_portal_camera},
{"shooter_rocket", SP_shooter_rocket},
{"shooter_grenade", SP_shooter_grenade},
{"shooter_plasma", SP_shooter_plasma},
{"team_CTF_redplayer", SP_team_CTF_redplayer},
{"team_CTF_blueplayer", SP_team_CTF_blueplayer},
{"team_CTF_redspawn", SP_team_CTF_redspawn},
{"team_CTF_bluespawn", SP_team_CTF_bluespawn},
#ifdef MISSIONPACK
{"team_redobelisk", SP_team_redobelisk},
{"team_blueobelisk", SP_team_blueobelisk},
{"team_neutralobelisk", SP_team_neutralobelisk},
#endif
{"item_botroam", SP_item_botroam},
{0, 0}
};
/*
===============
G_CallSpawn
Finds the spawn function for the entity and calls it,
returning qfalse if not found
===============
*/
qboolean G_CallSpawn( gentity_t *ent ) {
spawn_t *s;
gitem_t *item;
if ( !ent->classname ) {
G_Printf ("G_CallSpawn: NULL classname\n");
return qfalse;
}
// check item spawn functions
for ( item=bg_itemlist+1 ; item->classname ; item++ ) {
if ( !strcmp(item->classname, ent->classname) ) {
G_SpawnItem( ent, item );
return qtrue;
}
}
// check normal spawn functions
for ( s=spawns ; s->name ; s++ ) {
if ( !strcmp(s->name, ent->classname) ) {
// found it
s->spawn(ent);
return qtrue;
}
}
G_Printf ("%s doesn't have a spawn function\n", ent->classname);
return qfalse;
}
/*
=============
G_NewString
Builds a copy of the string, translating \n to real linefeeds
so message texts can be multi-line
=============
*/
char *G_NewString( const char *string ) {
char *newb, *new_p;
int i,l;
l = strlen(string) + 1;
newb = G_Alloc( l );
new_p = newb;
// turn \n into a real linefeed
for ( i=0 ; i< l ; i++ ) {
if (string[i] == '\\' && i < l-1) {
i++;
if (string[i] == 'n') {
*new_p++ = '\n';
} else {
*new_p++ = '\\';
}
} else {
*new_p++ = string[i];
}
}
return newb;
}
/*
===============
G_ParseField
Takes a key/value pair and sets the binary values
in a gentity
===============
*/
void G_ParseField( const char *key, const char *value, gentity_t *ent ) {
field_t *f;
byte *b;
float v;
vec3_t vec;
for ( f=fields ; f->name ; f++ ) {
if ( !Q_stricmp(f->name, key) ) {
// found it
b = (byte *)ent;
switch( f->type ) {
case F_LSTRING:
*(char **)(b+f->ofs) = G_NewString (value);
break;
case F_VECTOR:
sscanf (value, "%f %f %f", &vec[0], &vec[1], &vec[2]);
((float *)(b+f->ofs))[0] = vec[0];
((float *)(b+f->ofs))[1] = vec[1];
((float *)(b+f->ofs))[2] = vec[2];
break;
case F_INT:
*(int *)(b+f->ofs) = atoi(value);
break;
case F_FLOAT:
*(float *)(b+f->ofs) = atof(value);
break;
case F_ANGLEHACK:
v = atof(value);
((float *)(b+f->ofs))[0] = 0;
((float *)(b+f->ofs))[1] = v;
((float *)(b+f->ofs))[2] = 0;
break;
default:
case F_IGNORE:
break;
}
return;
}
}
}
/*
===================
G_SpawnGEntityFromSpawnVars
Spawn an entity and fill in all of the level fields from
level.spawnVars[], then call the class specfic spawn function
===================
*/
void G_SpawnGEntityFromSpawnVars( void ) {
int i;
gentity_t *ent;
char *s, *value, *gametypeName;
static char *gametypeNames[] = {"ffa", "tournament", "single", "team", "ctf", "oneflag", "obelisk", "harvester", "teamtournament"};
// get the next free entity
ent = G_Spawn();
for ( i = 0 ; i < level.numSpawnVars ; i++ ) {
G_ParseField( level.spawnVars[i][0], level.spawnVars[i][1], ent );
}
// check for "notsingle" flag
if ( g_gametype.integer == GT_SINGLE_PLAYER ) {
G_SpawnInt( "notsingle", "0", &i );
if ( i ) {
G_FreeEntity( ent );
return;
}
}
// check for "notteam" flag (GT_FFA, GT_TOURNAMENT, GT_SINGLE_PLAYER)
if ( g_gametype.integer >= GT_TEAM ) {
G_SpawnInt( "notteam", "0", &i );
if ( i ) {
G_FreeEntity( ent );
return;
}
} else {
G_SpawnInt( "notfree", "0", &i );
if ( i ) {
G_FreeEntity( ent );
return;
}
}
#ifdef MISSIONPACK
G_SpawnInt( "notta", "0", &i );
if ( i ) {
G_FreeEntity( ent );
return;
}
#else
G_SpawnInt( "notq3a", "0", &i );
if ( i ) {
G_FreeEntity( ent );
return;
}
#endif
if( G_SpawnString( "gametype", NULL, &value ) ) {
if( g_gametype.integer >= GT_FFA && g_gametype.integer < GT_MAX_GAME_TYPE ) {
gametypeName = gametypeNames[g_gametype.integer];
s = strstr( value, gametypeName );
if( !s ) {
G_FreeEntity( ent );
return;
}
}
}
// move editor origin to pos
VectorCopy( ent->s.origin, ent->s.pos.trBase );
VectorCopy( ent->s.origin, ent->r.currentOrigin );
// if we didn't get a classname, don't bother spawning anything
if ( !G_CallSpawn( ent ) ) {
G_FreeEntity( ent );
}
}
/*
====================
G_AddSpawnVarToken
====================
*/
char *G_AddSpawnVarToken( const char *string ) {
int l;
char *dest;
l = strlen( string );
if ( level.numSpawnVarChars + l + 1 > MAX_SPAWN_VARS_CHARS ) {
G_Error( "G_AddSpawnVarToken: MAX_SPAWN_CHARS" );
}
dest = level.spawnVarChars + level.numSpawnVarChars;
memcpy( dest, string, l+1 );
level.numSpawnVarChars += l + 1;
return dest;
}
/*
====================
G_ParseSpawnVars
Parses a brace bounded set of key / value pairs out of the
level's entity strings into level.spawnVars[]
This does not actually spawn an entity.
====================
*/
qboolean G_ParseSpawnVars( void ) {
char keyname[MAX_TOKEN_CHARS];
char com_token[MAX_TOKEN_CHARS];
level.numSpawnVars = 0;
level.numSpawnVarChars = 0;
// parse the opening brace
if ( !trap_GetEntityToken( com_token, sizeof( com_token ) ) ) {
// end of spawn string
return qfalse;
}
if ( com_token[0] != '{' ) {
G_Error( "G_ParseSpawnVars: found %s when expecting {",com_token );
}
// go through all the key / value pairs
while ( 1 ) {
// parse key
if ( !trap_GetEntityToken( keyname, sizeof( keyname ) ) ) {
G_Error( "G_ParseSpawnVars: EOF without closing brace" );
}
if ( keyname[0] == '}' ) {
break;
}
// parse value
if ( !trap_GetEntityToken( com_token, sizeof( com_token ) ) ) {
G_Error( "G_ParseSpawnVars: EOF without closing brace" );
}
if ( com_token[0] == '}' ) {
G_Error( "G_ParseSpawnVars: closing brace without data" );
}
if ( level.numSpawnVars == MAX_SPAWN_VARS ) {
G_Error( "G_ParseSpawnVars: MAX_SPAWN_VARS" );
}
level.spawnVars[ level.numSpawnVars ][0] = G_AddSpawnVarToken( keyname );
level.spawnVars[ level.numSpawnVars ][1] = G_AddSpawnVarToken( com_token );
level.numSpawnVars++;
}
return qtrue;
}
/*QUAKED worldspawn (0 0 0) ?
Every map should have exactly one worldspawn.
"music" music wav file
"gravity" 800 is default gravity
"message" Text to print during connection process
*/
void SP_worldspawn( void ) {
char *s;
G_SpawnString( "classname", "", &s );
if ( Q_stricmp( s, "worldspawn" ) ) {
G_Error( "SP_worldspawn: The first entity isn't 'worldspawn'" );
}
// make some data visible to connecting client
trap_SetConfigstring( CS_GAME_VERSION, GAME_VERSION );
trap_SetConfigstring( CS_LEVEL_START_TIME, va("%i", level.startTime ) );
G_SpawnString( "music", "", &s );
trap_SetConfigstring( CS_MUSIC, s );
G_SpawnString( "message", "", &s );
trap_SetConfigstring( CS_MESSAGE, s ); // map specific message
trap_SetConfigstring( CS_MOTD, g_motd.string ); // message of the day
G_SpawnString( "gravity", "800", &s );
trap_Cvar_Set( "g_gravity", s );
G_SpawnString( "enableDust", "0", &s );
trap_Cvar_Set( "g_enableDust", s );
G_SpawnString( "enableBreath", "0", &s );
trap_Cvar_Set( "g_enableBreath", s );
g_entities[ENTITYNUM_WORLD].s.number = ENTITYNUM_WORLD;
g_entities[ENTITYNUM_WORLD].classname = "worldspawn";
// see if we want a warmup time
trap_SetConfigstring( CS_WARMUP, "" );
if ( g_restarted.integer ) {
trap_Cvar_Set( "g_restarted", "0" );
level.warmupTime = 0;
} else if ( g_doWarmup.integer ) { // Turn it on
level.warmupTime = -1;
trap_SetConfigstring( CS_WARMUP, va("%i", level.warmupTime) );
G_LogPrintf( "Warmup:\n" );
}
}
/*
==============
G_SpawnEntitiesFromString
Parses textual entity definitions out of an entstring and spawns gentities.
==============
*/
void G_SpawnEntitiesFromString( void ) {
// allow calls to G_Spawn*()
level.spawning = qtrue;
level.numSpawnVars = 0;
// the worldspawn is not an actual entity, but it still
// has a "spawn" function to perform any global setup
// needed by a level (setting configstrings or cvars, etc)
if ( !G_ParseSpawnVars() ) {
G_Error( "SpawnEntities: no entities" );
}
SP_worldspawn();
// parse ents
while( G_ParseSpawnVars() ) {
G_SpawnGEntityFromSpawnVars();
}
level.spawning = qfalse; // any future calls to G_Spawn*() will be errors
}

508
code/game/g_svcmds.c Normal file
View file

@ -0,0 +1,508 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// this file holds commands that can be executed by the server console, but not remote clients
#include "g_local.h"
/*
==============================================================================
PACKET FILTERING
You can add or remove addresses from the filter list with:
addip <ip>
removeip <ip>
The ip address is specified in dot format, and you can use '*' to match any value
so you can specify an entire class C network with "addip 192.246.40.*"
Removeip will only remove an address specified exactly the same way. You cannot addip a subnet, then removeip a single host.
listip
Prints the current list of filters.
g_filterban <0 or 1>
If 1 (the default), then ip addresses matching the current list will be prohibited from entering the game. This is the default setting.
If 0, then only addresses matching the list will be allowed. This lets you easily set up a private game, or a game that only allows players from your local network.
TTimo NOTE: for persistence, bans are stored in g_banIPs cvar MAX_CVAR_VALUE_STRING
The size of the cvar string buffer is limiting the banning to around 20 masks
this could be improved by putting some g_banIPs2 g_banIps3 etc. maybe
still, you should rely on PB for banning instead
==============================================================================
*/
typedef struct ipFilter_s
{
unsigned mask;
unsigned compare;
} ipFilter_t;
#define MAX_IPFILTERS 1024
static ipFilter_t ipFilters[MAX_IPFILTERS];
static int numIPFilters;
/*
=================
StringToFilter
=================
*/
static qboolean StringToFilter (char *s, ipFilter_t *f)
{
char num[128];
int i, j;
byte b[4];
byte m[4];
for (i=0 ; i<4 ; i++)
{
b[i] = 0;
m[i] = 0;
}
for (i=0 ; i<4 ; i++)
{
if (*s < '0' || *s > '9')
{
if (*s == '*') // 'match any'
{
// b[i] and m[i] to 0
s++;
if (!*s)
break;
s++;
continue;
}
G_Printf( "Bad filter address: %s\n", s );
return qfalse;
}
j = 0;
while (*s >= '0' && *s <= '9')
{
num[j++] = *s++;
}
num[j] = 0;
b[i] = atoi(num);
m[i] = 255;
if (!*s)
break;
s++;
}
f->mask = *(unsigned *)m;
f->compare = *(unsigned *)b;
return qtrue;
}
/*
=================
UpdateIPBans
=================
*/
static void UpdateIPBans (void)
{
byte b[4];
byte m[4];
int i,j;
char iplist_final[MAX_CVAR_VALUE_STRING];
char ip[64];
*iplist_final = 0;
for (i = 0 ; i < numIPFilters ; i++)
{
if (ipFilters[i].compare == 0xffffffff)
continue;
*(unsigned *)b = ipFilters[i].compare;
*(unsigned *)m = ipFilters[i].mask;
*ip = 0;
for (j = 0 ; j < 4 ; j++)
{
if (m[j]!=255)
Q_strcat(ip, sizeof(ip), "*");
else
Q_strcat(ip, sizeof(ip), va("%i", b[j]));
Q_strcat(ip, sizeof(ip), (j<3) ? "." : " ");
}
if (strlen(iplist_final)+strlen(ip) < MAX_CVAR_VALUE_STRING)
{
Q_strcat( iplist_final, sizeof(iplist_final), ip);
}
else
{
Com_Printf("g_banIPs overflowed at MAX_CVAR_VALUE_STRING\n");
break;
}
}
trap_Cvar_Set( "g_banIPs", iplist_final );
}
/*
=================
G_FilterPacket
=================
*/
qboolean G_FilterPacket (char *from)
{
int i;
unsigned in;
byte m[4];
char *p;
i = 0;
p = from;
while (*p && i < 4) {
m[i] = 0;
while (*p >= '0' && *p <= '9') {
m[i] = m[i]*10 + (*p - '0');
p++;
}
if (!*p || *p == ':')
break;
i++, p++;
}
in = *(unsigned *)m;
for (i=0 ; i<numIPFilters ; i++)
if ( (in & ipFilters[i].mask) == ipFilters[i].compare)
return g_filterBan.integer != 0;
return g_filterBan.integer == 0;
}
/*
=================
AddIP
=================
*/
static void AddIP( char *str )
{
int i;
for (i = 0 ; i < numIPFilters ; i++)
if (ipFilters[i].compare == 0xffffffff)
break; // free spot
if (i == numIPFilters)
{
if (numIPFilters == MAX_IPFILTERS)
{
G_Printf ("IP filter list is full\n");
return;
}
numIPFilters++;
}
if (!StringToFilter (str, &ipFilters[i]))
ipFilters[i].compare = 0xffffffffu;
UpdateIPBans();
}
/*
=================
G_ProcessIPBans
=================
*/
void G_ProcessIPBans(void)
{
char *s, *t;
char str[MAX_CVAR_VALUE_STRING];
Q_strncpyz( str, g_banIPs.string, sizeof(str) );
for (t = s = g_banIPs.string; *t; /* */ ) {
s = strchr(s, ' ');
if (!s)
break;
while (*s == ' ')
*s++ = 0;
if (*t)
AddIP( t );
t = s;
}
}
/*
=================
Svcmd_AddIP_f
=================
*/
void Svcmd_AddIP_f (void)
{
char str[MAX_TOKEN_CHARS];
if ( trap_Argc() < 2 ) {
G_Printf("Usage: addip <ip-mask>\n");
return;
}
trap_Argv( 1, str, sizeof( str ) );
AddIP( str );
}
/*
=================
Svcmd_RemoveIP_f
=================
*/
void Svcmd_RemoveIP_f (void)
{
ipFilter_t f;
int i;
char str[MAX_TOKEN_CHARS];
if ( trap_Argc() < 2 ) {
G_Printf("Usage: sv removeip <ip-mask>\n");
return;
}
trap_Argv( 1, str, sizeof( str ) );
if (!StringToFilter (str, &f))
return;
for (i=0 ; i<numIPFilters ; i++) {
if (ipFilters[i].mask == f.mask &&
ipFilters[i].compare == f.compare) {
ipFilters[i].compare = 0xffffffffu;
G_Printf ("Removed.\n");
UpdateIPBans();
return;
}
}
G_Printf ( "Didn't find %s.\n", str );
}
/*
===================
Svcmd_EntityList_f
===================
*/
void Svcmd_EntityList_f (void) {
int e;
gentity_t *check;
check = g_entities+1;
for (e = 1; e < level.num_entities ; e++, check++) {
if ( !check->inuse ) {
continue;
}
G_Printf("%3i:", e);
switch ( check->s.eType ) {
case ET_GENERAL:
G_Printf("ET_GENERAL ");
break;
case ET_PLAYER:
G_Printf("ET_PLAYER ");
break;
case ET_ITEM:
G_Printf("ET_ITEM ");
break;
case ET_MISSILE:
G_Printf("ET_MISSILE ");
break;
case ET_MOVER:
G_Printf("ET_MOVER ");
break;
case ET_BEAM:
G_Printf("ET_BEAM ");
break;
case ET_PORTAL:
G_Printf("ET_PORTAL ");
break;
case ET_SPEAKER:
G_Printf("ET_SPEAKER ");
break;
case ET_PUSH_TRIGGER:
G_Printf("ET_PUSH_TRIGGER ");
break;
case ET_TELEPORT_TRIGGER:
G_Printf("ET_TELEPORT_TRIGGER ");
break;
case ET_INVISIBLE:
G_Printf("ET_INVISIBLE ");
break;
case ET_GRAPPLE:
G_Printf("ET_GRAPPLE ");
break;
default:
G_Printf("%3i ", check->s.eType);
break;
}
if ( check->classname ) {
G_Printf("%s", check->classname);
}
G_Printf("\n");
}
}
gclient_t *ClientForString( const char *s ) {
gclient_t *cl;
int i;
int idnum;
// numeric values are just slot numbers
if ( s[0] >= '0' && s[0] <= '9' ) {
idnum = atoi( s );
if ( idnum < 0 || idnum >= level.maxclients ) {
Com_Printf( "Bad client slot: %i\n", idnum );
return NULL;
}
cl = &level.clients[idnum];
if ( cl->pers.connected == CON_DISCONNECTED ) {
G_Printf( "Client %i is not connected\n", idnum );
return NULL;
}
return cl;
}
// check for a name match
for ( i=0 ; i < level.maxclients ; i++ ) {
cl = &level.clients[i];
if ( cl->pers.connected == CON_DISCONNECTED ) {
continue;
}
if ( !Q_stricmp( cl->pers.netname, s ) ) {
return cl;
}
}
G_Printf( "User %s is not on the server\n", s );
return NULL;
}
/*
===================
Svcmd_ForceTeam_f
forceteam <player> <team>
===================
*/
void Svcmd_ForceTeam_f( void ) {
gclient_t *cl;
char str[MAX_TOKEN_CHARS];
// find the player
trap_Argv( 1, str, sizeof( str ) );
cl = ClientForString( str );
if ( !cl ) {
return;
}
// set the team
trap_Argv( 2, str, sizeof( str ) );
SetTeam( &g_entities[cl - level.clients], str );
}
char *ConcatArgs( int start );
/*
=================
ConsoleCommand
=================
*/
qboolean ConsoleCommand( void ) {
char cmd[MAX_TOKEN_CHARS];
trap_Argv( 0, cmd, sizeof( cmd ) );
if ( Q_stricmp (cmd, "entitylist") == 0 ) {
Svcmd_EntityList_f();
return qtrue;
}
if ( Q_stricmp (cmd, "forceteam") == 0 ) {
Svcmd_ForceTeam_f();
return qtrue;
}
if (Q_stricmp (cmd, "game_memory") == 0) {
Svcmd_GameMem_f();
return qtrue;
}
if (Q_stricmp (cmd, "addbot") == 0) {
Svcmd_AddBot_f();
return qtrue;
}
if (Q_stricmp (cmd, "botlist") == 0) {
Svcmd_BotList_f();
return qtrue;
}
if (Q_stricmp (cmd, "abort_podium") == 0) {
Svcmd_AbortPodium_f();
return qtrue;
}
if (Q_stricmp (cmd, "addip") == 0) {
Svcmd_AddIP_f();
return qtrue;
}
if (Q_stricmp (cmd, "removeip") == 0) {
Svcmd_RemoveIP_f();
return qtrue;
}
if (Q_stricmp (cmd, "listip") == 0) {
trap_SendConsoleCommand( EXEC_NOW, "g_banIPs\n" );
return qtrue;
}
if (g_dedicated.integer) {
if (Q_stricmp (cmd, "say") == 0) {
trap_SendServerCommand( -1, va("print \"server: %s\"", ConcatArgs(1) ) );
return qtrue;
}
// everything else will also be printed as a say command
trap_SendServerCommand( -1, va("print \"server: %s\"", ConcatArgs(0) ) );
return qtrue;
}
return qfalse;
}

225
code/game/g_syscalls.asm Normal file
View file

@ -0,0 +1,225 @@
code
equ trap_Printf -1
equ trap_Error -2
equ trap_Milliseconds -3
equ trap_Cvar_Register -4
equ trap_Cvar_Update -5
equ trap_Cvar_Set -6
equ trap_Cvar_VariableIntegerValue -7
equ trap_Cvar_VariableStringBuffer -8
equ trap_Argc -9
equ trap_Argv -10
equ trap_FS_FOpenFile -11
equ trap_FS_Read -12
equ trap_FS_Write -13
equ trap_FS_FCloseFile -14
equ trap_SendConsoleCommand -15
equ trap_LocateGameData -16
equ trap_DropClient -17
equ trap_SendServerCommand -18
equ trap_SetConfigstring -19
equ trap_GetConfigstring -20
equ trap_GetUserinfo -21
equ trap_SetUserinfo -22
equ trap_GetServerinfo -23
equ trap_SetBrushModel -24
equ trap_Trace -25
equ trap_PointContents -26
equ trap_InPVS -27
equ trap_InPVSIgnorePortals -28
equ trap_AdjustAreaPortalState -29
equ trap_AreasConnected -30
equ trap_LinkEntity -31
equ trap_UnlinkEntity -32
equ trap_EntitiesInBox -33
equ trap_EntityContact -34
equ trap_BotAllocateClient -35
equ trap_BotFreeClient -36
equ trap_GetUsercmd -37
equ trap_GetEntityToken -38
equ trap_FS_GetFileList -39
equ trap_DebugPolygonCreate -40
equ trap_DebugPolygonDelete -41
equ trap_RealTime -42
equ trap_SnapVector -43
equ trap_TraceCapsule -44
equ trap_EntityContactCapsule -45
equ trap_FS_Seek -46
equ memset -101
equ memcpy -102
equ strncpy -103
equ sin -104
equ cos -105
equ atan2 -106
equ sqrt -107
equ floor -111
equ ceil -112
equ testPrintInt -113
equ testPrintFloat -114
equ trap_BotLibSetup -201
equ trap_BotLibShutdown -202
equ trap_BotLibVarSet -203
equ trap_BotLibVarGet -204
equ trap_BotLibDefine -205
equ trap_BotLibStartFrame -206
equ trap_BotLibLoadMap -207
equ trap_BotLibUpdateEntity -208
equ trap_BotLibTest -209
equ trap_BotGetSnapshotEntity -210
equ trap_BotGetServerCommand -211
equ trap_BotUserCommand -212
equ trap_AAS_EnableRoutingArea -301
equ trap_AAS_BBoxAreas -302
equ trap_AAS_AreaInfo -303
equ trap_AAS_EntityInfo -304
equ trap_AAS_Initialized -305
equ trap_AAS_PresenceTypeBoundingBox -306
equ trap_AAS_Time -307
equ trap_AAS_PointAreaNum -308
equ trap_AAS_TraceAreas -309
equ trap_AAS_PointContents -310
equ trap_AAS_NextBSPEntity -311
equ trap_AAS_ValueForBSPEpairKey -312
equ trap_AAS_VectorForBSPEpairKey -313
equ trap_AAS_FloatForBSPEpairKey -314
equ trap_AAS_IntForBSPEpairKey -315
equ trap_AAS_AreaReachability -316
equ trap_AAS_AreaTravelTimeToGoalArea -317
equ trap_AAS_Swimming -318
equ trap_AAS_PredictClientMovement -319
equ trap_EA_Say -401
equ trap_EA_SayTeam -402
equ trap_EA_Command -403
equ trap_EA_Action -404
equ trap_EA_Gesture -405
equ trap_EA_Talk -406
equ trap_EA_Attack -407
equ trap_EA_Use -408
equ trap_EA_Respawn -409
equ trap_EA_Crouch -410
equ trap_EA_MoveUp -411
equ trap_EA_MoveDown -412
equ trap_EA_MoveForward -413
equ trap_EA_MoveBack -414
equ trap_EA_MoveLeft -415
equ trap_EA_MoveRight -416
equ trap_EA_SelectWeapon -417
equ trap_EA_Jump -418
equ trap_EA_DelayedJump -419
equ trap_EA_Move -420
equ trap_EA_View -421
equ trap_EA_EndRegular -422
equ trap_EA_GetInput -423
equ trap_EA_ResetInput -424
equ trap_BotLoadCharacter -501
equ trap_BotFreeCharacter -502
equ trap_Characteristic_Float -503
equ trap_Characteristic_BFloat -504
equ trap_Characteristic_Integer -505
equ trap_Characteristic_BInteger -506
equ trap_Characteristic_String -507
equ trap_BotAllocChatState -508
equ trap_BotFreeChatState -509
equ trap_BotQueueConsoleMessage -510
equ trap_BotRemoveConsoleMessage -511
equ trap_BotNextConsoleMessage -512
equ trap_BotNumConsoleMessages -513
equ trap_BotInitialChat -514
equ trap_BotReplyChat -515
equ trap_BotChatLength -516
equ trap_BotEnterChat -517
equ trap_StringContains -518
equ trap_BotFindMatch -519
equ trap_BotMatchVariable -520
equ trap_UnifyWhiteSpaces -521
equ trap_BotReplaceSynonyms -522
equ trap_BotLoadChatFile -523
equ trap_BotSetChatGender -524
equ trap_BotSetChatName -525
equ trap_BotResetGoalState -526
equ trap_BotResetAvoidGoals -527
equ trap_BotPushGoal -528
equ trap_BotPopGoal -529
equ trap_BotEmptyGoalStack -530
equ trap_BotDumpAvoidGoals -531
equ trap_BotDumpGoalStack -532
equ trap_BotGoalName -533
equ trap_BotGetTopGoal -534
equ trap_BotGetSecondGoal -535
equ trap_BotChooseLTGItem -536
equ trap_BotChooseNBGItem -537
equ trap_BotTouchingGoal -538
equ trap_BotItemGoalInVisButNotVisible -539
equ trap_BotGetLevelItemGoal -540
equ trap_BotAvoidGoalTime -541
equ trap_BotInitLevelItems -542
equ trap_BotUpdateEntityItems -543
equ trap_BotLoadItemWeights -544
equ trap_BotFreeItemWeights -546
equ trap_BotSaveGoalFuzzyLogic -546
equ trap_BotAllocGoalState -547
equ trap_BotFreeGoalState -548
equ trap_BotResetMoveState -549
equ trap_BotMoveToGoal -550
equ trap_BotMoveInDirection -551
equ trap_BotResetAvoidReach -552
equ trap_BotResetLastAvoidReach -553
equ trap_BotReachabilityArea -554
equ trap_BotMovementViewTarget -555
equ trap_BotAllocMoveState -556
equ trap_BotFreeMoveState -557
equ trap_BotInitMoveState -558
equ trap_BotChooseBestFightWeapon -559
equ trap_BotGetWeaponInfo -560
equ trap_BotLoadWeaponWeights -561
equ trap_BotAllocWeaponState -562
equ trap_BotFreeWeaponState -563
equ trap_BotResetWeaponState -564
equ trap_GeneticParentsAndChildSelection -565
equ trap_BotInterbreedGoalFuzzyLogic -566
equ trap_BotMutateGoalFuzzyLogic -567
equ trap_BotGetNextCampSpotGoal -568
equ trap_BotGetMapLocationGoal -569
equ trap_BotNumInitialChats -570
equ trap_BotGetChatMessage -571
equ trap_BotRemoveFromAvoidGoals -572
equ trap_BotPredictVisiblePosition -573
equ trap_BotSetAvoidGoalTime -574
equ trap_BotAddAvoidSpot -575
equ trap_AAS_AlternativeRouteGoals -576
equ trap_AAS_PredictRoute -577
equ trap_AAS_PointReachabilityAreaIndex -578
equ trap_BotLibLoadSource -579
equ trap_BotLibFreeSource -580
equ trap_BotLibReadToken -581
equ trap_BotLibSourceFileAndLine -582

790
code/game/g_syscalls.c Normal file
View file

@ -0,0 +1,790 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
#include "g_local.h"
// this file is only included when building a dll
// g_syscalls.asm is included instead when building a qvm
#ifdef Q3_VM
#error "Do not use in VM build"
#endif
static int (QDECL *syscall)( int arg, ... ) = (int (QDECL *)( int, ...))-1;
void dllEntry( int (QDECL *syscallptr)( int arg,... ) ) {
syscall = syscallptr;
}
int PASSFLOAT( float x ) {
float floatTemp;
floatTemp = x;
return *(int *)&floatTemp;
}
void trap_Printf( const char *fmt ) {
syscall( G_PRINT, fmt );
}
void trap_Error( const char *fmt ) {
syscall( G_ERROR, fmt );
}
int trap_Milliseconds( void ) {
return syscall( G_MILLISECONDS );
}
int trap_Argc( void ) {
return syscall( G_ARGC );
}
void trap_Argv( int n, char *buffer, int bufferLength ) {
syscall( G_ARGV, n, buffer, bufferLength );
}
int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode ) {
return syscall( G_FS_FOPEN_FILE, qpath, f, mode );
}
void trap_FS_Read( void *buffer, int len, fileHandle_t f ) {
syscall( G_FS_READ, buffer, len, f );
}
void trap_FS_Write( const void *buffer, int len, fileHandle_t f ) {
syscall( G_FS_WRITE, buffer, len, f );
}
void trap_FS_FCloseFile( fileHandle_t f ) {
syscall( G_FS_FCLOSE_FILE, f );
}
int trap_FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize ) {
return syscall( G_FS_GETFILELIST, path, extension, listbuf, bufsize );
}
int trap_FS_Seek( fileHandle_t f, long offset, int origin ) {
return syscall( G_FS_SEEK, f, offset, origin );
}
void trap_SendConsoleCommand( int exec_when, const char *text ) {
syscall( G_SEND_CONSOLE_COMMAND, exec_when, text );
}
void trap_Cvar_Register( vmCvar_t *cvar, const char *var_name, const char *value, int flags ) {
syscall( G_CVAR_REGISTER, cvar, var_name, value, flags );
}
void trap_Cvar_Update( vmCvar_t *cvar ) {
syscall( G_CVAR_UPDATE, cvar );
}
void trap_Cvar_Set( const char *var_name, const char *value ) {
syscall( G_CVAR_SET, var_name, value );
}
int trap_Cvar_VariableIntegerValue( const char *var_name ) {
return syscall( G_CVAR_VARIABLE_INTEGER_VALUE, var_name );
}
void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize ) {
syscall( G_CVAR_VARIABLE_STRING_BUFFER, var_name, buffer, bufsize );
}
void trap_LocateGameData( gentity_t *gEnts, int numGEntities, int sizeofGEntity_t,
playerState_t *clients, int sizeofGClient ) {
syscall( G_LOCATE_GAME_DATA, gEnts, numGEntities, sizeofGEntity_t, clients, sizeofGClient );
}
void trap_DropClient( int clientNum, const char *reason ) {
syscall( G_DROP_CLIENT, clientNum, reason );
}
void trap_SendServerCommand( int clientNum, const char *text ) {
syscall( G_SEND_SERVER_COMMAND, clientNum, text );
}
void trap_SetConfigstring( int num, const char *string ) {
syscall( G_SET_CONFIGSTRING, num, string );
}
void trap_GetConfigstring( int num, char *buffer, int bufferSize ) {
syscall( G_GET_CONFIGSTRING, num, buffer, bufferSize );
}
void trap_GetUserinfo( int num, char *buffer, int bufferSize ) {
syscall( G_GET_USERINFO, num, buffer, bufferSize );
}
void trap_SetUserinfo( int num, const char *buffer ) {
syscall( G_SET_USERINFO, num, buffer );
}
void trap_GetServerinfo( char *buffer, int bufferSize ) {
syscall( G_GET_SERVERINFO, buffer, bufferSize );
}
void trap_SetBrushModel( gentity_t *ent, const char *name ) {
syscall( G_SET_BRUSH_MODEL, ent, 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 ) {
syscall( G_TRACE, results, start, mins, maxs, end, passEntityNum, contentmask );
}
void trap_TraceCapsule( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask ) {
syscall( G_TRACECAPSULE, results, start, mins, maxs, end, passEntityNum, contentmask );
}
int trap_PointContents( const vec3_t point, int passEntityNum ) {
return syscall( G_POINT_CONTENTS, point, passEntityNum );
}
qboolean trap_InPVS( const vec3_t p1, const vec3_t p2 ) {
return syscall( G_IN_PVS, p1, p2 );
}
qboolean trap_InPVSIgnorePortals( const vec3_t p1, const vec3_t p2 ) {
return syscall( G_IN_PVS_IGNORE_PORTALS, p1, p2 );
}
void trap_AdjustAreaPortalState( gentity_t *ent, qboolean open ) {
syscall( G_ADJUST_AREA_PORTAL_STATE, ent, open );
}
qboolean trap_AreasConnected( int area1, int area2 ) {
return syscall( G_AREAS_CONNECTED, area1, area2 );
}
void trap_LinkEntity( gentity_t *ent ) {
syscall( G_LINKENTITY, ent );
}
void trap_UnlinkEntity( gentity_t *ent ) {
syscall( G_UNLINKENTITY, ent );
}
int trap_EntitiesInBox( const vec3_t mins, const vec3_t maxs, int *list, int maxcount ) {
return syscall( G_ENTITIES_IN_BOX, mins, maxs, list, maxcount );
}
qboolean trap_EntityContact( const vec3_t mins, const vec3_t maxs, const gentity_t *ent ) {
return syscall( G_ENTITY_CONTACT, mins, maxs, ent );
}
qboolean trap_EntityContactCapsule( const vec3_t mins, const vec3_t maxs, const gentity_t *ent ) {
return syscall( G_ENTITY_CONTACTCAPSULE, mins, maxs, ent );
}
int trap_BotAllocateClient( void ) {
return syscall( G_BOT_ALLOCATE_CLIENT );
}
void trap_BotFreeClient( int clientNum ) {
syscall( G_BOT_FREE_CLIENT, clientNum );
}
void trap_GetUsercmd( int clientNum, usercmd_t *cmd ) {
syscall( G_GET_USERCMD, clientNum, cmd );
}
qboolean trap_GetEntityToken( char *buffer, int bufferSize ) {
return syscall( G_GET_ENTITY_TOKEN, buffer, bufferSize );
}
int trap_DebugPolygonCreate(int color, int numPoints, vec3_t *points) {
return syscall( G_DEBUG_POLYGON_CREATE, color, numPoints, points );
}
void trap_DebugPolygonDelete(int id) {
syscall( G_DEBUG_POLYGON_DELETE, id );
}
int trap_RealTime( qtime_t *qtime ) {
return syscall( G_REAL_TIME, qtime );
}
void trap_SnapVector( float *v ) {
syscall( G_SNAPVECTOR, v );
return;
}
// BotLib traps start here
int trap_BotLibSetup( void ) {
return syscall( BOTLIB_SETUP );
}
int trap_BotLibShutdown( void ) {
return syscall( BOTLIB_SHUTDOWN );
}
int trap_BotLibVarSet(char *var_name, char *value) {
return syscall( BOTLIB_LIBVAR_SET, var_name, value );
}
int trap_BotLibVarGet(char *var_name, char *value, int size) {
return syscall( BOTLIB_LIBVAR_GET, var_name, value, size );
}
int trap_BotLibDefine(char *string) {
return syscall( BOTLIB_PC_ADD_GLOBAL_DEFINE, string );
}
int trap_BotLibStartFrame(float time) {
return syscall( BOTLIB_START_FRAME, PASSFLOAT( time ) );
}
int trap_BotLibLoadMap(const char *mapname) {
return syscall( BOTLIB_LOAD_MAP, mapname );
}
int trap_BotLibUpdateEntity(int ent, void /* struct bot_updateentity_s */ *bue) {
return syscall( BOTLIB_UPDATENTITY, ent, bue );
}
int trap_BotLibTest(int parm0, char *parm1, vec3_t parm2, vec3_t parm3) {
return syscall( BOTLIB_TEST, parm0, parm1, parm2, parm3 );
}
int trap_BotGetSnapshotEntity( int clientNum, int sequence ) {
return syscall( BOTLIB_GET_SNAPSHOT_ENTITY, clientNum, sequence );
}
int trap_BotGetServerCommand(int clientNum, char *message, int size) {
return syscall( BOTLIB_GET_CONSOLE_MESSAGE, clientNum, message, size );
}
void trap_BotUserCommand(int clientNum, usercmd_t *ucmd) {
syscall( BOTLIB_USER_COMMAND, clientNum, ucmd );
}
void trap_AAS_EntityInfo(int entnum, void /* struct aas_entityinfo_s */ *info) {
syscall( BOTLIB_AAS_ENTITY_INFO, entnum, info );
}
int trap_AAS_Initialized(void) {
return syscall( BOTLIB_AAS_INITIALIZED );
}
void trap_AAS_PresenceTypeBoundingBox(int presencetype, vec3_t mins, vec3_t maxs) {
syscall( BOTLIB_AAS_PRESENCE_TYPE_BOUNDING_BOX, presencetype, mins, maxs );
}
float trap_AAS_Time(void) {
int temp;
temp = syscall( BOTLIB_AAS_TIME );
return (*(float*)&temp);
}
int trap_AAS_PointAreaNum(vec3_t point) {
return syscall( BOTLIB_AAS_POINT_AREA_NUM, point );
}
int trap_AAS_PointReachabilityAreaIndex(vec3_t point) {
return syscall( BOTLIB_AAS_POINT_REACHABILITY_AREA_INDEX, point );
}
int trap_AAS_TraceAreas(vec3_t start, vec3_t end, int *areas, vec3_t *points, int maxareas) {
return syscall( BOTLIB_AAS_TRACE_AREAS, start, end, areas, points, maxareas );
}
int trap_AAS_BBoxAreas(vec3_t absmins, vec3_t absmaxs, int *areas, int maxareas) {
return syscall( BOTLIB_AAS_BBOX_AREAS, absmins, absmaxs, areas, maxareas );
}
int trap_AAS_AreaInfo( int areanum, void /* struct aas_areainfo_s */ *info ) {
return syscall( BOTLIB_AAS_AREA_INFO, areanum, info );
}
int trap_AAS_PointContents(vec3_t point) {
return syscall( BOTLIB_AAS_POINT_CONTENTS, point );
}
int trap_AAS_NextBSPEntity(int ent) {
return syscall( BOTLIB_AAS_NEXT_BSP_ENTITY, ent );
}
int trap_AAS_ValueForBSPEpairKey(int ent, char *key, char *value, int size) {
return syscall( BOTLIB_AAS_VALUE_FOR_BSP_EPAIR_KEY, ent, key, value, size );
}
int trap_AAS_VectorForBSPEpairKey(int ent, char *key, vec3_t v) {
return syscall( BOTLIB_AAS_VECTOR_FOR_BSP_EPAIR_KEY, ent, key, v );
}
int trap_AAS_FloatForBSPEpairKey(int ent, char *key, float *value) {
return syscall( BOTLIB_AAS_FLOAT_FOR_BSP_EPAIR_KEY, ent, key, value );
}
int trap_AAS_IntForBSPEpairKey(int ent, char *key, int *value) {
return syscall( BOTLIB_AAS_INT_FOR_BSP_EPAIR_KEY, ent, key, value );
}
int trap_AAS_AreaReachability(int areanum) {
return syscall( BOTLIB_AAS_AREA_REACHABILITY, areanum );
}
int trap_AAS_AreaTravelTimeToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags) {
return syscall( BOTLIB_AAS_AREA_TRAVEL_TIME_TO_GOAL_AREA, areanum, origin, goalareanum, travelflags );
}
int trap_AAS_EnableRoutingArea( int areanum, int enable ) {
return syscall( BOTLIB_AAS_ENABLE_ROUTING_AREA, areanum, 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) {
return syscall( BOTLIB_AAS_PREDICT_ROUTE, route, areanum, origin, goalareanum, travelflags, maxareas, maxtime, stopevent, stopcontents, stoptfl, 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) {
return syscall( BOTLIB_AAS_ALTERNATIVE_ROUTE_GOAL, start, startareanum, goal, goalareanum, travelflags, altroutegoals, maxaltroutegoals, type );
}
int trap_AAS_Swimming(vec3_t origin) {
return syscall( BOTLIB_AAS_SWIMMING, origin );
}
int trap_AAS_PredictClientMovement(void /* struct 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) {
return syscall( BOTLIB_AAS_PREDICT_CLIENT_MOVEMENT, move, entnum, origin, presencetype, onground, velocity, cmdmove, cmdframes, maxframes, PASSFLOAT(frametime), stopevent, stopareanum, visualize );
}
void trap_EA_Say(int client, char *str) {
syscall( BOTLIB_EA_SAY, client, str );
}
void trap_EA_SayTeam(int client, char *str) {
syscall( BOTLIB_EA_SAY_TEAM, client, str );
}
void trap_EA_Command(int client, char *command) {
syscall( BOTLIB_EA_COMMAND, client, command );
}
void trap_EA_Action(int client, int action) {
syscall( BOTLIB_EA_ACTION, client, action );
}
void trap_EA_Gesture(int client) {
syscall( BOTLIB_EA_GESTURE, client );
}
void trap_EA_Talk(int client) {
syscall( BOTLIB_EA_TALK, client );
}
void trap_EA_Attack(int client) {
syscall( BOTLIB_EA_ATTACK, client );
}
void trap_EA_Use(int client) {
syscall( BOTLIB_EA_USE, client );
}
void trap_EA_Respawn(int client) {
syscall( BOTLIB_EA_RESPAWN, client );
}
void trap_EA_Crouch(int client) {
syscall( BOTLIB_EA_CROUCH, client );
}
void trap_EA_MoveUp(int client) {
syscall( BOTLIB_EA_MOVE_UP, client );
}
void trap_EA_MoveDown(int client) {
syscall( BOTLIB_EA_MOVE_DOWN, client );
}
void trap_EA_MoveForward(int client) {
syscall( BOTLIB_EA_MOVE_FORWARD, client );
}
void trap_EA_MoveBack(int client) {
syscall( BOTLIB_EA_MOVE_BACK, client );
}
void trap_EA_MoveLeft(int client) {
syscall( BOTLIB_EA_MOVE_LEFT, client );
}
void trap_EA_MoveRight(int client) {
syscall( BOTLIB_EA_MOVE_RIGHT, client );
}
void trap_EA_SelectWeapon(int client, int weapon) {
syscall( BOTLIB_EA_SELECT_WEAPON, client, weapon );
}
void trap_EA_Jump(int client) {
syscall( BOTLIB_EA_JUMP, client );
}
void trap_EA_DelayedJump(int client) {
syscall( BOTLIB_EA_DELAYED_JUMP, client );
}
void trap_EA_Move(int client, vec3_t dir, float speed) {
syscall( BOTLIB_EA_MOVE, client, dir, PASSFLOAT(speed) );
}
void trap_EA_View(int client, vec3_t viewangles) {
syscall( BOTLIB_EA_VIEW, client, viewangles );
}
void trap_EA_EndRegular(int client, float thinktime) {
syscall( BOTLIB_EA_END_REGULAR, client, PASSFLOAT(thinktime) );
}
void trap_EA_GetInput(int client, float thinktime, void /* struct bot_input_s */ *input) {
syscall( BOTLIB_EA_GET_INPUT, client, PASSFLOAT(thinktime), input );
}
void trap_EA_ResetInput(int client) {
syscall( BOTLIB_EA_RESET_INPUT, client );
}
int trap_BotLoadCharacter(char *charfile, float skill) {
return syscall( BOTLIB_AI_LOAD_CHARACTER, charfile, PASSFLOAT(skill));
}
void trap_BotFreeCharacter(int character) {
syscall( BOTLIB_AI_FREE_CHARACTER, character );
}
float trap_Characteristic_Float(int character, int index) {
int temp;
temp = syscall( BOTLIB_AI_CHARACTERISTIC_FLOAT, character, index );
return (*(float*)&temp);
}
float trap_Characteristic_BFloat(int character, int index, float min, float max) {
int temp;
temp = syscall( BOTLIB_AI_CHARACTERISTIC_BFLOAT, character, index, PASSFLOAT(min), PASSFLOAT(max) );
return (*(float*)&temp);
}
int trap_Characteristic_Integer(int character, int index) {
return syscall( BOTLIB_AI_CHARACTERISTIC_INTEGER, character, index );
}
int trap_Characteristic_BInteger(int character, int index, int min, int max) {
return syscall( BOTLIB_AI_CHARACTERISTIC_BINTEGER, character, index, min, max );
}
void trap_Characteristic_String(int character, int index, char *buf, int size) {
syscall( BOTLIB_AI_CHARACTERISTIC_STRING, character, index, buf, size );
}
int trap_BotAllocChatState(void) {
return syscall( BOTLIB_AI_ALLOC_CHAT_STATE );
}
void trap_BotFreeChatState(int handle) {
syscall( BOTLIB_AI_FREE_CHAT_STATE, handle );
}
void trap_BotQueueConsoleMessage(int chatstate, int type, char *message) {
syscall( BOTLIB_AI_QUEUE_CONSOLE_MESSAGE, chatstate, type, message );
}
void trap_BotRemoveConsoleMessage(int chatstate, int handle) {
syscall( BOTLIB_AI_REMOVE_CONSOLE_MESSAGE, chatstate, handle );
}
int trap_BotNextConsoleMessage(int chatstate, void /* struct bot_consolemessage_s */ *cm) {
return syscall( BOTLIB_AI_NEXT_CONSOLE_MESSAGE, chatstate, cm );
}
int trap_BotNumConsoleMessages(int chatstate) {
return syscall( BOTLIB_AI_NUM_CONSOLE_MESSAGE, 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 ) {
syscall( BOTLIB_AI_INITIAL_CHAT, chatstate, type, mcontext, var0, var1, var2, var3, var4, var5, var6, var7 );
}
int trap_BotNumInitialChats(int chatstate, char *type) {
return syscall( BOTLIB_AI_NUM_INITIAL_CHATS, chatstate, 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 ) {
return syscall( BOTLIB_AI_REPLY_CHAT, chatstate, message, mcontext, vcontext, var0, var1, var2, var3, var4, var5, var6, var7 );
}
int trap_BotChatLength(int chatstate) {
return syscall( BOTLIB_AI_CHAT_LENGTH, chatstate );
}
void trap_BotEnterChat(int chatstate, int client, int sendto) {
syscall( BOTLIB_AI_ENTER_CHAT, chatstate, client, sendto );
}
void trap_BotGetChatMessage(int chatstate, char *buf, int size) {
syscall( BOTLIB_AI_GET_CHAT_MESSAGE, chatstate, buf, size);
}
int trap_StringContains(char *str1, char *str2, int casesensitive) {
return syscall( BOTLIB_AI_STRING_CONTAINS, str1, str2, casesensitive );
}
int trap_BotFindMatch(char *str, void /* struct bot_match_s */ *match, unsigned long int context) {
return syscall( BOTLIB_AI_FIND_MATCH, str, match, context );
}
void trap_BotMatchVariable(void /* struct bot_match_s */ *match, int variable, char *buf, int size) {
syscall( BOTLIB_AI_MATCH_VARIABLE, match, variable, buf, size );
}
void trap_UnifyWhiteSpaces(char *string) {
syscall( BOTLIB_AI_UNIFY_WHITE_SPACES, string );
}
void trap_BotReplaceSynonyms(char *string, unsigned long int context) {
syscall( BOTLIB_AI_REPLACE_SYNONYMS, string, context );
}
int trap_BotLoadChatFile(int chatstate, char *chatfile, char *chatname) {
return syscall( BOTLIB_AI_LOAD_CHAT_FILE, chatstate, chatfile, chatname );
}
void trap_BotSetChatGender(int chatstate, int gender) {
syscall( BOTLIB_AI_SET_CHAT_GENDER, chatstate, gender );
}
void trap_BotSetChatName(int chatstate, char *name, int client) {
syscall( BOTLIB_AI_SET_CHAT_NAME, chatstate, name, client );
}
void trap_BotResetGoalState(int goalstate) {
syscall( BOTLIB_AI_RESET_GOAL_STATE, goalstate );
}
void trap_BotResetAvoidGoals(int goalstate) {
syscall( BOTLIB_AI_RESET_AVOID_GOALS, goalstate );
}
void trap_BotRemoveFromAvoidGoals(int goalstate, int number) {
syscall( BOTLIB_AI_REMOVE_FROM_AVOID_GOALS, goalstate, number);
}
void trap_BotPushGoal(int goalstate, void /* struct bot_goal_s */ *goal) {
syscall( BOTLIB_AI_PUSH_GOAL, goalstate, goal );
}
void trap_BotPopGoal(int goalstate) {
syscall( BOTLIB_AI_POP_GOAL, goalstate );
}
void trap_BotEmptyGoalStack(int goalstate) {
syscall( BOTLIB_AI_EMPTY_GOAL_STACK, goalstate );
}
void trap_BotDumpAvoidGoals(int goalstate) {
syscall( BOTLIB_AI_DUMP_AVOID_GOALS, goalstate );
}
void trap_BotDumpGoalStack(int goalstate) {
syscall( BOTLIB_AI_DUMP_GOAL_STACK, goalstate );
}
void trap_BotGoalName(int number, char *name, int size) {
syscall( BOTLIB_AI_GOAL_NAME, number, name, size );
}
int trap_BotGetTopGoal(int goalstate, void /* struct bot_goal_s */ *goal) {
return syscall( BOTLIB_AI_GET_TOP_GOAL, goalstate, goal );
}
int trap_BotGetSecondGoal(int goalstate, void /* struct bot_goal_s */ *goal) {
return syscall( BOTLIB_AI_GET_SECOND_GOAL, goalstate, goal );
}
int trap_BotChooseLTGItem(int goalstate, vec3_t origin, int *inventory, int travelflags) {
return syscall( BOTLIB_AI_CHOOSE_LTG_ITEM, goalstate, origin, inventory, travelflags );
}
int trap_BotChooseNBGItem(int goalstate, vec3_t origin, int *inventory, int travelflags, void /* struct bot_goal_s */ *ltg, float maxtime) {
return syscall( BOTLIB_AI_CHOOSE_NBG_ITEM, goalstate, origin, inventory, travelflags, ltg, PASSFLOAT(maxtime) );
}
int trap_BotTouchingGoal(vec3_t origin, void /* struct bot_goal_s */ *goal) {
return syscall( BOTLIB_AI_TOUCHING_GOAL, origin, goal );
}
int trap_BotItemGoalInVisButNotVisible(int viewer, vec3_t eye, vec3_t viewangles, void /* struct bot_goal_s */ *goal) {
return syscall( BOTLIB_AI_ITEM_GOAL_IN_VIS_BUT_NOT_VISIBLE, viewer, eye, viewangles, goal );
}
int trap_BotGetLevelItemGoal(int index, char *classname, void /* struct bot_goal_s */ *goal) {
return syscall( BOTLIB_AI_GET_LEVEL_ITEM_GOAL, index, classname, goal );
}
int trap_BotGetNextCampSpotGoal(int num, void /* struct bot_goal_s */ *goal) {
return syscall( BOTLIB_AI_GET_NEXT_CAMP_SPOT_GOAL, num, goal );
}
int trap_BotGetMapLocationGoal(char *name, void /* struct bot_goal_s */ *goal) {
return syscall( BOTLIB_AI_GET_MAP_LOCATION_GOAL, name, goal );
}
float trap_BotAvoidGoalTime(int goalstate, int number) {
int temp;
temp = syscall( BOTLIB_AI_AVOID_GOAL_TIME, goalstate, number );
return (*(float*)&temp);
}
void trap_BotSetAvoidGoalTime(int goalstate, int number, float avoidtime) {
syscall( BOTLIB_AI_SET_AVOID_GOAL_TIME, goalstate, number, PASSFLOAT(avoidtime));
}
void trap_BotInitLevelItems(void) {
syscall( BOTLIB_AI_INIT_LEVEL_ITEMS );
}
void trap_BotUpdateEntityItems(void) {
syscall( BOTLIB_AI_UPDATE_ENTITY_ITEMS );
}
int trap_BotLoadItemWeights(int goalstate, char *filename) {
return syscall( BOTLIB_AI_LOAD_ITEM_WEIGHTS, goalstate, filename );
}
void trap_BotFreeItemWeights(int goalstate) {
syscall( BOTLIB_AI_FREE_ITEM_WEIGHTS, goalstate );
}
void trap_BotInterbreedGoalFuzzyLogic(int parent1, int parent2, int child) {
syscall( BOTLIB_AI_INTERBREED_GOAL_FUZZY_LOGIC, parent1, parent2, child );
}
void trap_BotSaveGoalFuzzyLogic(int goalstate, char *filename) {
syscall( BOTLIB_AI_SAVE_GOAL_FUZZY_LOGIC, goalstate, filename );
}
void trap_BotMutateGoalFuzzyLogic(int goalstate, float range) {
syscall( BOTLIB_AI_MUTATE_GOAL_FUZZY_LOGIC, goalstate, range );
}
int trap_BotAllocGoalState(int state) {
return syscall( BOTLIB_AI_ALLOC_GOAL_STATE, state );
}
void trap_BotFreeGoalState(int handle) {
syscall( BOTLIB_AI_FREE_GOAL_STATE, handle );
}
void trap_BotResetMoveState(int movestate) {
syscall( BOTLIB_AI_RESET_MOVE_STATE, movestate );
}
void trap_BotAddAvoidSpot(int movestate, vec3_t origin, float radius, int type) {
syscall( BOTLIB_AI_ADD_AVOID_SPOT, movestate, origin, PASSFLOAT(radius), type);
}
void trap_BotMoveToGoal(void /* struct bot_moveresult_s */ *result, int movestate, void /* struct bot_goal_s */ *goal, int travelflags) {
syscall( BOTLIB_AI_MOVE_TO_GOAL, result, movestate, goal, travelflags );
}
int trap_BotMoveInDirection(int movestate, vec3_t dir, float speed, int type) {
return syscall( BOTLIB_AI_MOVE_IN_DIRECTION, movestate, dir, PASSFLOAT(speed), type );
}
void trap_BotResetAvoidReach(int movestate) {
syscall( BOTLIB_AI_RESET_AVOID_REACH, movestate );
}
void trap_BotResetLastAvoidReach(int movestate) {
syscall( BOTLIB_AI_RESET_LAST_AVOID_REACH,movestate );
}
int trap_BotReachabilityArea(vec3_t origin, int testground) {
return syscall( BOTLIB_AI_REACHABILITY_AREA, origin, testground );
}
int trap_BotMovementViewTarget(int movestate, void /* struct bot_goal_s */ *goal, int travelflags, float lookahead, vec3_t target) {
return syscall( BOTLIB_AI_MOVEMENT_VIEW_TARGET, movestate, goal, travelflags, PASSFLOAT(lookahead), target );
}
int trap_BotPredictVisiblePosition(vec3_t origin, int areanum, void /* struct bot_goal_s */ *goal, int travelflags, vec3_t target) {
return syscall( BOTLIB_AI_PREDICT_VISIBLE_POSITION, origin, areanum, goal, travelflags, target );
}
int trap_BotAllocMoveState(void) {
return syscall( BOTLIB_AI_ALLOC_MOVE_STATE );
}
void trap_BotFreeMoveState(int handle) {
syscall( BOTLIB_AI_FREE_MOVE_STATE, handle );
}
void trap_BotInitMoveState(int handle, void /* struct bot_initmove_s */ *initmove) {
syscall( BOTLIB_AI_INIT_MOVE_STATE, handle, initmove );
}
int trap_BotChooseBestFightWeapon(int weaponstate, int *inventory) {
return syscall( BOTLIB_AI_CHOOSE_BEST_FIGHT_WEAPON, weaponstate, inventory );
}
void trap_BotGetWeaponInfo(int weaponstate, int weapon, void /* struct weaponinfo_s */ *weaponinfo) {
syscall( BOTLIB_AI_GET_WEAPON_INFO, weaponstate, weapon, weaponinfo );
}
int trap_BotLoadWeaponWeights(int weaponstate, char *filename) {
return syscall( BOTLIB_AI_LOAD_WEAPON_WEIGHTS, weaponstate, filename );
}
int trap_BotAllocWeaponState(void) {
return syscall( BOTLIB_AI_ALLOC_WEAPON_STATE );
}
void trap_BotFreeWeaponState(int weaponstate) {
syscall( BOTLIB_AI_FREE_WEAPON_STATE, weaponstate );
}
void trap_BotResetWeaponState(int weaponstate) {
syscall( BOTLIB_AI_RESET_WEAPON_STATE, weaponstate );
}
int trap_GeneticParentsAndChildSelection(int numranks, float *ranks, int *parent1, int *parent2, int *child) {
return syscall( BOTLIB_AI_GENETIC_PARENTS_AND_CHILD_SELECTION, numranks, ranks, parent1, parent2, child );
}
int trap_PC_LoadSource( const char *filename ) {
return syscall( BOTLIB_PC_LOAD_SOURCE, filename );
}
int trap_PC_FreeSource( int handle ) {
return syscall( BOTLIB_PC_FREE_SOURCE, handle );
}
int trap_PC_ReadToken( int handle, pc_token_t *pc_token ) {
return syscall( BOTLIB_PC_READ_TOKEN, handle, pc_token );
}
int trap_PC_SourceFileAndLine( int handle, char *filename, int *line ) {
return syscall( BOTLIB_PC_SOURCE_FILE_AND_LINE, handle, filename, line );
}

467
code/game/g_target.c Normal file
View file

@ -0,0 +1,467 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
#include "g_local.h"
//==========================================================
/*QUAKED target_give (1 0 0) (-8 -8 -8) (8 8 8)
Gives the activator all the items pointed to.
*/
void Use_Target_Give( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
gentity_t *t;
trace_t trace;
if ( !activator->client ) {
return;
}
if ( !ent->target ) {
return;
}
memset( &trace, 0, sizeof( trace ) );
t = NULL;
while ( (t = G_Find (t, FOFS(targetname), ent->target)) != NULL ) {
if ( !t->item ) {
continue;
}
Touch_Item( t, activator, &trace );
// make sure it isn't going to respawn or show any events
t->nextthink = 0;
trap_UnlinkEntity( t );
}
}
void SP_target_give( gentity_t *ent ) {
ent->use = Use_Target_Give;
}
//==========================================================
/*QUAKED target_remove_powerups (1 0 0) (-8 -8 -8) (8 8 8)
takes away all the activators powerups.
Used to drop flight powerups into death puts.
*/
void Use_target_remove_powerups( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
if( !activator->client ) {
return;
}
if( activator->client->ps.powerups[PW_REDFLAG] ) {
Team_ReturnFlag( TEAM_RED );
} else if( activator->client->ps.powerups[PW_BLUEFLAG] ) {
Team_ReturnFlag( TEAM_BLUE );
} else if( activator->client->ps.powerups[PW_NEUTRALFLAG] ) {
Team_ReturnFlag( TEAM_FREE );
}
memset( activator->client->ps.powerups, 0, sizeof( activator->client->ps.powerups ) );
}
void SP_target_remove_powerups( gentity_t *ent ) {
ent->use = Use_target_remove_powerups;
}
//==========================================================
/*QUAKED target_delay (1 0 0) (-8 -8 -8) (8 8 8)
"wait" seconds to pause before firing targets.
"random" delay variance, total delay = delay +/- random seconds
*/
void Think_Target_Delay( gentity_t *ent ) {
G_UseTargets( ent, ent->activator );
}
void Use_Target_Delay( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
ent->nextthink = level.time + ( ent->wait + ent->random * crandom() ) * 1000;
ent->think = Think_Target_Delay;
ent->activator = activator;
}
void SP_target_delay( gentity_t *ent ) {
// check delay for backwards compatability
if ( !G_SpawnFloat( "delay", "0", &ent->wait ) ) {
G_SpawnFloat( "wait", "1", &ent->wait );
}
if ( !ent->wait ) {
ent->wait = 1;
}
ent->use = Use_Target_Delay;
}
//==========================================================
/*QUAKED target_score (1 0 0) (-8 -8 -8) (8 8 8)
"count" number of points to add, default 1
The activator is given this many points.
*/
void Use_Target_Score (gentity_t *ent, gentity_t *other, gentity_t *activator) {
AddScore( activator, ent->r.currentOrigin, ent->count );
}
void SP_target_score( gentity_t *ent ) {
if ( !ent->count ) {
ent->count = 1;
}
ent->use = Use_Target_Score;
}
//==========================================================
/*QUAKED target_print (1 0 0) (-8 -8 -8) (8 8 8) redteam blueteam private
"message" text to print
If "private", only the activator gets the message. If no checks, all clients get the message.
*/
void Use_Target_Print (gentity_t *ent, gentity_t *other, gentity_t *activator) {
if ( activator->client && ( ent->spawnflags & 4 ) ) {
trap_SendServerCommand( activator-g_entities, va("cp \"%s\"", ent->message ));
return;
}
if ( ent->spawnflags & 3 ) {
if ( ent->spawnflags & 1 ) {
G_TeamCommand( TEAM_RED, va("cp \"%s\"", ent->message) );
}
if ( ent->spawnflags & 2 ) {
G_TeamCommand( TEAM_BLUE, va("cp \"%s\"", ent->message) );
}
return;
}
trap_SendServerCommand( -1, va("cp \"%s\"", ent->message ));
}
void SP_target_print( gentity_t *ent ) {
ent->use = Use_Target_Print;
}
//==========================================================
/*QUAKED target_speaker (1 0 0) (-8 -8 -8) (8 8 8) looped-on looped-off global activator
"noise" wav file to play
A global sound will play full volume throughout the level.
Activator sounds will play on the player that activated the target.
Global and activator sounds can't be combined with looping.
Normal sounds play each time the target is used.
Looped sounds will be toggled by use functions.
Multiple identical looping sounds will just increase volume without any speed cost.
"wait" : Seconds between auto triggerings, 0 = don't auto trigger
"random" wait variance, default is 0
*/
void Use_Target_Speaker (gentity_t *ent, gentity_t *other, gentity_t *activator) {
if (ent->spawnflags & 3) { // looping sound toggles
if (ent->s.loopSound)
ent->s.loopSound = 0; // turn it off
else
ent->s.loopSound = ent->noise_index; // start it
}else { // normal sound
if ( ent->spawnflags & 8 ) {
G_AddEvent( activator, EV_GENERAL_SOUND, ent->noise_index );
} else if (ent->spawnflags & 4) {
G_AddEvent( ent, EV_GLOBAL_SOUND, ent->noise_index );
} else {
G_AddEvent( ent, EV_GENERAL_SOUND, ent->noise_index );
}
}
}
void SP_target_speaker( gentity_t *ent ) {
char buffer[MAX_QPATH];
char *s;
G_SpawnFloat( "wait", "0", &ent->wait );
G_SpawnFloat( "random", "0", &ent->random );
if ( !G_SpawnString( "noise", "NOSOUND", &s ) ) {
G_Error( "target_speaker without a noise key at %s", vtos( ent->s.origin ) );
}
// force all client reletive sounds to be "activator" speakers that
// play on the entity that activates it
if ( s[0] == '*' ) {
ent->spawnflags |= 8;
}
if (!strstr( s, ".wav" )) {
Com_sprintf (buffer, sizeof(buffer), "%s.wav", s );
} else {
Q_strncpyz( buffer, s, sizeof(buffer) );
}
ent->noise_index = G_SoundIndex(buffer);
// a repeating speaker can be done completely client side
ent->s.eType = ET_SPEAKER;
ent->s.eventParm = ent->noise_index;
ent->s.frame = ent->wait * 10;
ent->s.clientNum = ent->random * 10;
// check for prestarted looping sound
if ( ent->spawnflags & 1 ) {
ent->s.loopSound = ent->noise_index;
}
ent->use = Use_Target_Speaker;
if (ent->spawnflags & 4) {
ent->r.svFlags |= SVF_BROADCAST;
}
VectorCopy( ent->s.origin, ent->s.pos.trBase );
// must link the entity so we get areas and clusters so
// the server can determine who to send updates to
trap_LinkEntity( ent );
}
//==========================================================
/*QUAKED target_laser (0 .5 .8) (-8 -8 -8) (8 8 8) START_ON
When triggered, fires a laser. You can either set a target or a direction.
*/
void target_laser_think (gentity_t *self) {
vec3_t end;
trace_t tr;
vec3_t point;
// if pointed at another entity, set movedir to point at it
if ( self->enemy ) {
VectorMA (self->enemy->s.origin, 0.5, self->enemy->r.mins, point);
VectorMA (point, 0.5, self->enemy->r.maxs, point);
VectorSubtract (point, self->s.origin, self->movedir);
VectorNormalize (self->movedir);
}
// fire forward and see what we hit
VectorMA (self->s.origin, 2048, self->movedir, end);
trap_Trace( &tr, self->s.origin, NULL, NULL, end, self->s.number, CONTENTS_SOLID|CONTENTS_BODY|CONTENTS_CORPSE);
if ( tr.entityNum ) {
// hurt it if we can
G_Damage ( &g_entities[tr.entityNum], self, self->activator, self->movedir,
tr.endpos, self->damage, DAMAGE_NO_KNOCKBACK, MOD_TARGET_LASER);
}
VectorCopy (tr.endpos, self->s.origin2);
trap_LinkEntity( self );
self->nextthink = level.time + FRAMETIME;
}
void target_laser_on (gentity_t *self)
{
if (!self->activator)
self->activator = self;
target_laser_think (self);
}
void target_laser_off (gentity_t *self)
{
trap_UnlinkEntity( self );
self->nextthink = 0;
}
void target_laser_use (gentity_t *self, gentity_t *other, gentity_t *activator)
{
self->activator = activator;
if ( self->nextthink > 0 )
target_laser_off (self);
else
target_laser_on (self);
}
void target_laser_start (gentity_t *self)
{
gentity_t *ent;
self->s.eType = ET_BEAM;
if (self->target) {
ent = G_Find (NULL, FOFS(targetname), self->target);
if (!ent) {
G_Printf ("%s at %s: %s is a bad target\n", self->classname, vtos(self->s.origin), self->target);
}
self->enemy = ent;
} else {
G_SetMovedir (self->s.angles, self->movedir);
}
self->use = target_laser_use;
self->think = target_laser_think;
if ( !self->damage ) {
self->damage = 1;
}
if (self->spawnflags & 1)
target_laser_on (self);
else
target_laser_off (self);
}
void SP_target_laser (gentity_t *self)
{
// let everything else get spawned before we start firing
self->think = target_laser_start;
self->nextthink = level.time + FRAMETIME;
}
//==========================================================
void target_teleporter_use( gentity_t *self, gentity_t *other, gentity_t *activator ) {
gentity_t *dest;
if (!activator->client)
return;
dest = G_PickTarget( self->target );
if (!dest) {
G_Printf ("Couldn't find teleporter destination\n");
return;
}
TeleportPlayer( activator, dest->s.origin, dest->s.angles );
}
/*QUAKED target_teleporter (1 0 0) (-8 -8 -8) (8 8 8)
The activator will be teleported away.
*/
void SP_target_teleporter( gentity_t *self ) {
if (!self->targetname)
G_Printf("untargeted %s at %s\n", self->classname, vtos(self->s.origin));
self->use = target_teleporter_use;
}
//==========================================================
/*QUAKED target_relay (.5 .5 .5) (-8 -8 -8) (8 8 8) RED_ONLY BLUE_ONLY RANDOM
This doesn't perform any actions except fire its targets.
The activator can be forced to be from a certain team.
if RANDOM is checked, only one of the targets will be fired, not all of them
*/
void target_relay_use (gentity_t *self, gentity_t *other, gentity_t *activator) {
if ( ( self->spawnflags & 1 ) && activator->client
&& activator->client->sess.sessionTeam != TEAM_RED ) {
return;
}
if ( ( self->spawnflags & 2 ) && activator->client
&& activator->client->sess.sessionTeam != TEAM_BLUE ) {
return;
}
if ( self->spawnflags & 4 ) {
gentity_t *ent;
ent = G_PickTarget( self->target );
if ( ent && ent->use ) {
ent->use( ent, self, activator );
}
return;
}
G_UseTargets (self, activator);
}
void SP_target_relay (gentity_t *self) {
self->use = target_relay_use;
}
//==========================================================
/*QUAKED target_kill (.5 .5 .5) (-8 -8 -8) (8 8 8)
Kills the activator.
*/
void target_kill_use( gentity_t *self, gentity_t *other, gentity_t *activator ) {
G_Damage ( activator, NULL, NULL, NULL, NULL, 100000, DAMAGE_NO_PROTECTION, MOD_TELEFRAG);
}
void SP_target_kill( gentity_t *self ) {
self->use = target_kill_use;
}
/*QUAKED target_position (0 0.5 0) (-4 -4 -4) (4 4 4)
Used as a positional target for in-game calculation, like jumppad targets.
*/
void SP_target_position( gentity_t *self ){
G_SetOrigin( self, self->s.origin );
}
static void target_location_linkup(gentity_t *ent)
{
int i;
int n;
if (level.locationLinked)
return;
level.locationLinked = qtrue;
level.locationHead = NULL;
trap_SetConfigstring( CS_LOCATIONS, "unknown" );
for (i = 0, ent = g_entities, n = 1;
i < level.num_entities;
i++, ent++) {
if (ent->classname && !Q_stricmp(ent->classname, "target_location")) {
// lets overload some variables!
ent->health = n; // use for location marking
trap_SetConfigstring( CS_LOCATIONS + n, ent->message );
n++;
ent->nextTrain = level.locationHead;
level.locationHead = ent;
}
}
// All linked together now
}
/*QUAKED target_location (0 0.5 0) (-8 -8 -8) (8 8 8)
Set "message" to the name of this location.
Set "count" to 0-7 for color.
0:white 1:red 2:green 3:yellow 4:blue 5:cyan 6:magenta 7:white
Closest target_location in sight used for the location, if none
in site, closest in distance
*/
void SP_target_location( gentity_t *self ){
self->think = target_location_linkup;
self->nextthink = level.time + 200; // Let them all spawn first
G_SetOrigin( self, self->s.origin );
}

1483
code/game/g_team.c Normal file

File diff suppressed because it is too large Load diff

88
code/game/g_team.h Normal file
View file

@ -0,0 +1,88 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
#ifdef MISSIONPACK
#define CTF_CAPTURE_BONUS 100 // what you get for capture
#define CTF_TEAM_BONUS 25 // what your team gets for capture
#define CTF_RECOVERY_BONUS 10 // what you get for recovery
#define CTF_FLAG_BONUS 10 // what you get for picking up enemy flag
#define CTF_FRAG_CARRIER_BONUS 20 // what you get for fragging enemy flag carrier
#define CTF_FLAG_RETURN_TIME 40000 // seconds until auto return
#define CTF_CARRIER_DANGER_PROTECT_BONUS 5 // bonus for fraggin someone who has recently hurt your flag carrier
#define CTF_CARRIER_PROTECT_BONUS 2 // bonus for fraggin someone while either you or your target are near your flag carrier
#define CTF_FLAG_DEFENSE_BONUS 10 // bonus for fraggin someone while either you or your target are near your flag
#define CTF_RETURN_FLAG_ASSIST_BONUS 10 // awarded for returning a flag that causes a capture to happen almost immediately
#define CTF_FRAG_CARRIER_ASSIST_BONUS 10 // award for fragging a flag carrier if a capture happens almost immediately
#else
#define CTF_CAPTURE_BONUS 5 // what you get for capture
#define CTF_TEAM_BONUS 0 // what your team gets for capture
#define CTF_RECOVERY_BONUS 1 // what you get for recovery
#define CTF_FLAG_BONUS 0 // what you get for picking up enemy flag
#define CTF_FRAG_CARRIER_BONUS 2 // what you get for fragging enemy flag carrier
#define CTF_FLAG_RETURN_TIME 40000 // seconds until auto return
#define CTF_CARRIER_DANGER_PROTECT_BONUS 2 // bonus for fraggin someone who has recently hurt your flag carrier
#define CTF_CARRIER_PROTECT_BONUS 1 // bonus for fraggin someone while either you or your target are near your flag carrier
#define CTF_FLAG_DEFENSE_BONUS 1 // bonus for fraggin someone while either you or your target are near your flag
#define CTF_RETURN_FLAG_ASSIST_BONUS 1 // awarded for returning a flag that causes a capture to happen almost immediately
#define CTF_FRAG_CARRIER_ASSIST_BONUS 2 // award for fragging a flag carrier if a capture happens almost immediately
#endif
#define CTF_TARGET_PROTECT_RADIUS 1000 // the radius around an object being defended where a target will be worth extra frags
#define CTF_ATTACKER_PROTECT_RADIUS 1000 // the radius around an object being defended where an attacker will get extra frags when making kills
#define CTF_CARRIER_DANGER_PROTECT_TIMEOUT 8000
#define CTF_FRAG_CARRIER_ASSIST_TIMEOUT 10000
#define CTF_RETURN_FLAG_ASSIST_TIMEOUT 10000
#define CTF_GRAPPLE_SPEED 750 // speed of grapple in flight
#define CTF_GRAPPLE_PULL_SPEED 750 // speed player is pulled at
#define OVERLOAD_ATTACK_BASE_SOUND_TIME 20000
// Prototypes
int OtherTeam(int team);
const char *TeamName(int team);
const char *OtherTeamName(int team);
const char *TeamColorString(int team);
void AddTeamScore(vec3_t origin, int team, int score);
void Team_DroppedFlagThink(gentity_t *ent);
void Team_FragBonuses(gentity_t *targ, gentity_t *inflictor, gentity_t *attacker);
void Team_CheckHurtCarrier(gentity_t *targ, gentity_t *attacker);
void Team_InitGame(void);
void Team_ReturnFlag(int team);
void Team_FreeEntity(gentity_t *ent);
gentity_t *SelectCTFSpawnPoint ( team_t team, int teamstate, vec3_t origin, vec3_t angles );
gentity_t *Team_GetLocation(gentity_t *ent);
qboolean Team_GetLocationMsg(gentity_t *ent, char *loc, int loclen);
void TeamplayInfoMessage( gentity_t *ent );
void CheckTeamStatus(void);
int Pickup_Team( gentity_t *ent, gentity_t *other );

465
code/game/g_trigger.c Normal file
View file

@ -0,0 +1,465 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
#include "g_local.h"
void InitTrigger( gentity_t *self ) {
if (!VectorCompare (self->s.angles, vec3_origin))
G_SetMovedir (self->s.angles, self->movedir);
trap_SetBrushModel( self, self->model );
self->r.contents = CONTENTS_TRIGGER; // replaces the -1 from trap_SetBrushModel
self->r.svFlags = SVF_NOCLIENT;
}
// the wait time has passed, so set back up for another activation
void multi_wait( gentity_t *ent ) {
ent->nextthink = 0;
}
// the trigger was just activated
// ent->activator should be set to the activator so it can be held through a delay
// so wait for the delay time before firing
void multi_trigger( gentity_t *ent, gentity_t *activator ) {
ent->activator = activator;
if ( ent->nextthink ) {
return; // can't retrigger until the wait is over
}
if ( activator->client ) {
if ( ( ent->spawnflags & 1 ) &&
activator->client->sess.sessionTeam != TEAM_RED ) {
return;
}
if ( ( ent->spawnflags & 2 ) &&
activator->client->sess.sessionTeam != TEAM_BLUE ) {
return;
}
}
G_UseTargets (ent, ent->activator);
if ( ent->wait > 0 ) {
ent->think = multi_wait;
ent->nextthink = level.time + ( ent->wait + ent->random * crandom() ) * 1000;
} else {
// we can't just remove (self) here, because this is a touch function
// called while looping through area links...
ent->touch = 0;
ent->nextthink = level.time + FRAMETIME;
ent->think = G_FreeEntity;
}
}
void Use_Multi( gentity_t *ent, gentity_t *other, gentity_t *activator ) {
multi_trigger( ent, activator );
}
void Touch_Multi( gentity_t *self, gentity_t *other, trace_t *trace ) {
if( !other->client ) {
return;
}
multi_trigger( self, other );
}
/*QUAKED trigger_multiple (.5 .5 .5) ?
"wait" : Seconds between triggerings, 0.5 default, -1 = one time only.
"random" wait variance, default is 0
Variable sized repeatable trigger. Must be targeted at one or more entities.
so, the basic time between firing is a random time between
(wait - random) and (wait + random)
*/
void SP_trigger_multiple( gentity_t *ent ) {
G_SpawnFloat( "wait", "0.5", &ent->wait );
G_SpawnFloat( "random", "0", &ent->random );
if ( ent->random >= ent->wait && ent->wait >= 0 ) {
ent->random = ent->wait - FRAMETIME;
G_Printf( "trigger_multiple has random >= wait\n" );
}
ent->touch = Touch_Multi;
ent->use = Use_Multi;
InitTrigger( ent );
trap_LinkEntity (ent);
}
/*
==============================================================================
trigger_always
==============================================================================
*/
void trigger_always_think( gentity_t *ent ) {
G_UseTargets(ent, ent);
G_FreeEntity( ent );
}
/*QUAKED trigger_always (.5 .5 .5) (-8 -8 -8) (8 8 8)
This trigger will always fire. It is activated by the world.
*/
void SP_trigger_always (gentity_t *ent) {
// we must have some delay to make sure our use targets are present
ent->nextthink = level.time + 300;
ent->think = trigger_always_think;
}
/*
==============================================================================
trigger_push
==============================================================================
*/
void trigger_push_touch (gentity_t *self, gentity_t *other, trace_t *trace ) {
if ( !other->client ) {
return;
}
BG_TouchJumpPad( &other->client->ps, &self->s );
}
/*
=================
AimAtTarget
Calculate origin2 so the target apogee will be hit
=================
*/
void AimAtTarget( gentity_t *self ) {
gentity_t *ent;
vec3_t origin;
float height, gravity, time, forward;
float dist;
VectorAdd( self->r.absmin, self->r.absmax, origin );
VectorScale ( origin, 0.5, origin );
ent = G_PickTarget( self->target );
if ( !ent ) {
G_FreeEntity( self );
return;
}
height = ent->s.origin[2] - origin[2];
gravity = g_gravity.value;
time = sqrt( height / ( .5 * gravity ) );
if ( !time ) {
G_FreeEntity( self );
return;
}
// set s.origin2 to the push velocity
VectorSubtract ( ent->s.origin, origin, self->s.origin2 );
self->s.origin2[2] = 0;
dist = VectorNormalize( self->s.origin2);
forward = dist / time;
VectorScale( self->s.origin2, forward, self->s.origin2 );
self->s.origin2[2] = time * gravity;
}
/*QUAKED trigger_push (.5 .5 .5) ?
Must point at a target_position, which will be the apex of the leap.
This will be client side predicted, unlike target_push
*/
void SP_trigger_push( gentity_t *self ) {
InitTrigger (self);
// unlike other triggers, we need to send this one to the client
self->r.svFlags &= ~SVF_NOCLIENT;
// make sure the client precaches this sound
G_SoundIndex("sound/world/jumppad.wav");
self->s.eType = ET_PUSH_TRIGGER;
self->touch = trigger_push_touch;
self->think = AimAtTarget;
self->nextthink = level.time + FRAMETIME;
trap_LinkEntity (self);
}
void Use_target_push( gentity_t *self, gentity_t *other, gentity_t *activator ) {
if ( !activator->client ) {
return;
}
if ( activator->client->ps.pm_type != PM_NORMAL ) {
return;
}
if ( activator->client->ps.powerups[PW_FLIGHT] ) {
return;
}
VectorCopy (self->s.origin2, activator->client->ps.velocity);
// play fly sound every 1.5 seconds
if ( activator->fly_sound_debounce_time < level.time ) {
activator->fly_sound_debounce_time = level.time + 1500;
G_Sound( activator, CHAN_AUTO, self->noise_index );
}
}
/*QUAKED target_push (.5 .5 .5) (-8 -8 -8) (8 8 8) bouncepad
Pushes the activator in the direction.of angle, or towards a target apex.
"speed" defaults to 1000
if "bouncepad", play bounce noise instead of windfly
*/
void SP_target_push( gentity_t *self ) {
if (!self->speed) {
self->speed = 1000;
}
G_SetMovedir (self->s.angles, self->s.origin2);
VectorScale (self->s.origin2, self->speed, self->s.origin2);
if ( self->spawnflags & 1 ) {
self->noise_index = G_SoundIndex("sound/world/jumppad.wav");
} else {
self->noise_index = G_SoundIndex("sound/misc/windfly.wav");
}
if ( self->target ) {
VectorCopy( self->s.origin, self->r.absmin );
VectorCopy( self->s.origin, self->r.absmax );
self->think = AimAtTarget;
self->nextthink = level.time + FRAMETIME;
}
self->use = Use_target_push;
}
/*
==============================================================================
trigger_teleport
==============================================================================
*/
void trigger_teleporter_touch (gentity_t *self, gentity_t *other, trace_t *trace ) {
gentity_t *dest;
if ( !other->client ) {
return;
}
if ( other->client->ps.pm_type == PM_DEAD ) {
return;
}
// Spectators only?
if ( ( self->spawnflags & 1 ) &&
other->client->sess.sessionTeam != TEAM_SPECTATOR ) {
return;
}
dest = G_PickTarget( self->target );
if (!dest) {
G_Printf ("Couldn't find teleporter destination\n");
return;
}
TeleportPlayer( other, dest->s.origin, dest->s.angles );
}
/*QUAKED trigger_teleport (.5 .5 .5) ? SPECTATOR
Allows client side prediction of teleportation events.
Must point at a target_position, which will be the teleport destination.
If spectator is set, only spectators can use this teleport
Spectator teleporters are not normally placed in the editor, but are created
automatically near doors to allow spectators to move through them
*/
void SP_trigger_teleport( gentity_t *self ) {
InitTrigger (self);
// unlike other triggers, we need to send this one to the client
// unless is a spectator trigger
if ( self->spawnflags & 1 ) {
self->r.svFlags |= SVF_NOCLIENT;
} else {
self->r.svFlags &= ~SVF_NOCLIENT;
}
// make sure the client precaches this sound
G_SoundIndex("sound/world/jumppad.wav");
self->s.eType = ET_TELEPORT_TRIGGER;
self->touch = trigger_teleporter_touch;
trap_LinkEntity (self);
}
/*
==============================================================================
trigger_hurt
==============================================================================
*/
/*QUAKED trigger_hurt (.5 .5 .5) ? START_OFF - SILENT NO_PROTECTION SLOW
Any entity that touches this will be hurt.
It does dmg points of damage each server frame
Targeting the trigger will toggle its on / off state.
SILENT supresses playing the sound
SLOW changes the damage rate to once per second
NO_PROTECTION *nothing* stops the damage
"dmg" default 5 (whole numbers only)
*/
void hurt_use( gentity_t *self, gentity_t *other, gentity_t *activator ) {
if ( self->r.linked ) {
trap_UnlinkEntity( self );
} else {
trap_LinkEntity( self );
}
}
void hurt_touch( gentity_t *self, gentity_t *other, trace_t *trace ) {
int dflags;
if ( !other->takedamage ) {
return;
}
if ( self->timestamp > level.time ) {
return;
}
if ( self->spawnflags & 16 ) {
self->timestamp = level.time + 1000;
} else {
self->timestamp = level.time + FRAMETIME;
}
// play sound
if ( !(self->spawnflags & 4) ) {
G_Sound( other, CHAN_AUTO, self->noise_index );
}
if (self->spawnflags & 8)
dflags = DAMAGE_NO_PROTECTION;
else
dflags = 0;
G_Damage (other, self, self, NULL, NULL, self->damage, dflags, MOD_TRIGGER_HURT);
}
void SP_trigger_hurt( gentity_t *self ) {
InitTrigger (self);
self->noise_index = G_SoundIndex( "sound/world/electro.wav" );
self->touch = hurt_touch;
if ( !self->damage ) {
self->damage = 5;
}
self->r.contents = CONTENTS_TRIGGER;
if ( self->spawnflags & 2 ) {
self->use = hurt_use;
}
// link in to the world if starting active
if ( ! (self->spawnflags & 1) ) {
trap_LinkEntity (self);
}
}
/*
==============================================================================
timer
==============================================================================
*/
/*QUAKED func_timer (0.3 0.1 0.6) (-8 -8 -8) (8 8 8) START_ON
This should be renamed trigger_timer...
Repeatedly fires its targets.
Can be turned on or off by using.
"wait" base time between triggering all targets, default is 1
"random" wait variance, default is 0
so, the basic time between firing is a random time between
(wait - random) and (wait + random)
*/
void func_timer_think( gentity_t *self ) {
G_UseTargets (self, self->activator);
// set time before next firing
self->nextthink = level.time + 1000 * ( self->wait + crandom() * self->random );
}
void func_timer_use( gentity_t *self, gentity_t *other, gentity_t *activator ) {
self->activator = activator;
// if on, turn it off
if ( self->nextthink ) {
self->nextthink = 0;
return;
}
// turn it on
func_timer_think (self);
}
void SP_func_timer( gentity_t *self ) {
G_SpawnFloat( "random", "1", &self->random);
G_SpawnFloat( "wait", "1", &self->wait );
self->use = func_timer_use;
self->think = func_timer_think;
if ( self->random >= self->wait ) {
self->random = self->wait - FRAMETIME;
G_Printf( "func_timer at %s has random >= wait\n", vtos( self->s.origin ) );
}
if ( self->spawnflags & 1 ) {
self->nextthink = level.time + FRAMETIME;
self->activator = self;
}
self->r.svFlags = SVF_NOCLIENT;
}

666
code/game/g_utils.c Normal file
View file

@ -0,0 +1,666 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// g_utils.c -- misc utility functions for game module
#include "g_local.h"
typedef struct {
char oldShader[MAX_QPATH];
char newShader[MAX_QPATH];
float timeOffset;
} shaderRemap_t;
#define MAX_SHADER_REMAPS 128
int remapCount = 0;
shaderRemap_t remappedShaders[MAX_SHADER_REMAPS];
void AddRemap(const char *oldShader, const char *newShader, float timeOffset) {
int i;
for (i = 0; i < remapCount; i++) {
if (Q_stricmp(oldShader, remappedShaders[i].oldShader) == 0) {
// found it, just update this one
strcpy(remappedShaders[i].newShader,newShader);
remappedShaders[i].timeOffset = timeOffset;
return;
}
}
if (remapCount < MAX_SHADER_REMAPS) {
strcpy(remappedShaders[remapCount].newShader,newShader);
strcpy(remappedShaders[remapCount].oldShader,oldShader);
remappedShaders[remapCount].timeOffset = timeOffset;
remapCount++;
}
}
const char *BuildShaderStateConfig() {
static char buff[MAX_STRING_CHARS*4];
char out[(MAX_QPATH * 2) + 5];
int i;
memset(buff, 0, MAX_STRING_CHARS);
for (i = 0; i < remapCount; i++) {
Com_sprintf(out, (MAX_QPATH * 2) + 5, "%s=%s:%5.2f@", remappedShaders[i].oldShader, remappedShaders[i].newShader, remappedShaders[i].timeOffset);
Q_strcat( buff, sizeof( buff ), out);
}
return buff;
}
/*
=========================================================================
model / sound configstring indexes
=========================================================================
*/
/*
================
G_FindConfigstringIndex
================
*/
int G_FindConfigstringIndex( char *name, int start, int max, qboolean create ) {
int i;
char s[MAX_STRING_CHARS];
if ( !name || !name[0] ) {
return 0;
}
for ( i=1 ; i<max ; i++ ) {
trap_GetConfigstring( start + i, s, sizeof( s ) );
if ( !s[0] ) {
break;
}
if ( !strcmp( s, name ) ) {
return i;
}
}
if ( !create ) {
return 0;
}
if ( i == max ) {
G_Error( "G_FindConfigstringIndex: overflow" );
}
trap_SetConfigstring( start + i, name );
return i;
}
int G_ModelIndex( char *name ) {
return G_FindConfigstringIndex (name, CS_MODELS, MAX_MODELS, qtrue);
}
int G_SoundIndex( char *name ) {
return G_FindConfigstringIndex (name, CS_SOUNDS, MAX_SOUNDS, qtrue);
}
//=====================================================================
/*
================
G_TeamCommand
Broadcasts a command to only a specific team
================
*/
void G_TeamCommand( team_t team, char *cmd ) {
int i;
for ( i = 0 ; i < level.maxclients ; i++ ) {
if ( level.clients[i].pers.connected == CON_CONNECTED ) {
if ( level.clients[i].sess.sessionTeam == team ) {
trap_SendServerCommand( i, va("%s", cmd ));
}
}
}
}
/*
=============
G_Find
Searches all active entities for the next one that holds
the matching string at fieldofs (use the FOFS() macro) in the structure.
Searches beginning at the entity after from, or the beginning if NULL
NULL will be returned if the end of the list is reached.
=============
*/
gentity_t *G_Find (gentity_t *from, int fieldofs, const char *match)
{
char *s;
if (!from)
from = g_entities;
else
from++;
for ( ; from < &g_entities[level.num_entities] ; from++)
{
if (!from->inuse)
continue;
s = *(char **) ((byte *)from + fieldofs);
if (!s)
continue;
if (!Q_stricmp (s, match))
return from;
}
return NULL;
}
/*
=============
G_PickTarget
Selects a random entity from among the targets
=============
*/
#define MAXCHOICES 32
gentity_t *G_PickTarget (char *targetname)
{
gentity_t *ent = NULL;
int num_choices = 0;
gentity_t *choice[MAXCHOICES];
if (!targetname)
{
G_Printf("G_PickTarget called with NULL targetname\n");
return NULL;
}
while(1)
{
ent = G_Find (ent, FOFS(targetname), targetname);
if (!ent)
break;
choice[num_choices++] = ent;
if (num_choices == MAXCHOICES)
break;
}
if (!num_choices)
{
G_Printf("G_PickTarget: target %s not found\n", targetname);
return NULL;
}
return choice[rand() % num_choices];
}
/*
==============================
G_UseTargets
"activator" should be set to the entity that initiated the firing.
Search for (string)targetname in all entities that
match (string)self.target and call their .use function
==============================
*/
void G_UseTargets( gentity_t *ent, gentity_t *activator ) {
gentity_t *t;
if ( !ent ) {
return;
}
if (ent->targetShaderName && ent->targetShaderNewName) {
float f = level.time * 0.001;
AddRemap(ent->targetShaderName, ent->targetShaderNewName, f);
trap_SetConfigstring(CS_SHADERSTATE, BuildShaderStateConfig());
}
if ( !ent->target ) {
return;
}
t = NULL;
while ( (t = G_Find (t, FOFS(targetname), ent->target)) != NULL ) {
if ( t == ent ) {
G_Printf ("WARNING: Entity used itself.\n");
} else {
if ( t->use ) {
t->use (t, ent, activator);
}
}
if ( !ent->inuse ) {
G_Printf("entity was removed while using targets\n");
return;
}
}
}
/*
=============
TempVector
This is just a convenience function
for making temporary vectors for function calls
=============
*/
float *tv( float x, float y, float z ) {
static int index;
static vec3_t vecs[8];
float *v;
// use an array so that multiple tempvectors won't collide
// for a while
v = vecs[index];
index = (index + 1)&7;
v[0] = x;
v[1] = y;
v[2] = z;
return v;
}
/*
=============
VectorToString
This is just a convenience function
for printing vectors
=============
*/
char *vtos( const vec3_t v ) {
static int index;
static char str[8][32];
char *s;
// use an array so that multiple vtos won't collide
s = str[index];
index = (index + 1)&7;
Com_sprintf (s, 32, "(%i %i %i)", (int)v[0], (int)v[1], (int)v[2]);
return s;
}
/*
===============
G_SetMovedir
The editor only specifies a single value for angles (yaw),
but we have special constants to generate an up or down direction.
Angles will be cleared, because it is being used to represent a direction
instead of an orientation.
===============
*/
void G_SetMovedir( vec3_t angles, vec3_t movedir ) {
static vec3_t VEC_UP = {0, -1, 0};
static vec3_t MOVEDIR_UP = {0, 0, 1};
static vec3_t VEC_DOWN = {0, -2, 0};
static vec3_t MOVEDIR_DOWN = {0, 0, -1};
if ( VectorCompare (angles, VEC_UP) ) {
VectorCopy (MOVEDIR_UP, movedir);
} else if ( VectorCompare (angles, VEC_DOWN) ) {
VectorCopy (MOVEDIR_DOWN, movedir);
} else {
AngleVectors (angles, movedir, NULL, NULL);
}
VectorClear( angles );
}
float vectoyaw( const vec3_t vec ) {
float yaw;
if (vec[YAW] == 0 && vec[PITCH] == 0) {
yaw = 0;
} else {
if (vec[PITCH]) {
yaw = ( atan2( vec[YAW], vec[PITCH]) * 180 / M_PI );
} else if (vec[YAW] > 0) {
yaw = 90;
} else {
yaw = 270;
}
if (yaw < 0) {
yaw += 360;
}
}
return yaw;
}
void G_InitGentity( gentity_t *e ) {
e->inuse = qtrue;
e->classname = "noclass";
e->s.number = e - g_entities;
e->r.ownerNum = ENTITYNUM_NONE;
}
/*
=================
G_Spawn
Either finds a free entity, or allocates a new one.
The slots from 0 to MAX_CLIENTS-1 are always reserved for clients, and will
never be used by anything else.
Try to avoid reusing an entity that was recently freed, because it
can cause the client to think the entity morphed into something else
instead of being removed and recreated, which can cause interpolated
angles and bad trails.
=================
*/
gentity_t *G_Spawn( void ) {
int i, force;
gentity_t *e;
e = NULL; // shut up warning
i = 0; // shut up warning
for ( force = 0 ; force < 2 ; force++ ) {
// if we go through all entities and can't find one to free,
// override the normal minimum times before use
e = &g_entities[MAX_CLIENTS];
for ( i = MAX_CLIENTS ; i<level.num_entities ; i++, e++) {
if ( e->inuse ) {
continue;
}
// the first couple seconds of server time can involve a lot of
// freeing and allocating, so relax the replacement policy
if ( !force && e->freetime > level.startTime + 2000 && level.time - e->freetime < 1000 ) {
continue;
}
// reuse this slot
G_InitGentity( e );
return e;
}
if ( i != MAX_GENTITIES ) {
break;
}
}
if ( i == ENTITYNUM_MAX_NORMAL ) {
for (i = 0; i < MAX_GENTITIES; i++) {
G_Printf("%4i: %s\n", i, g_entities[i].classname);
}
G_Error( "G_Spawn: no free entities" );
}
// open up a new slot
level.num_entities++;
// let the server system know that there are more entities
trap_LocateGameData( level.gentities, level.num_entities, sizeof( gentity_t ),
&level.clients[0].ps, sizeof( level.clients[0] ) );
G_InitGentity( e );
return e;
}
/*
=================
G_EntitiesFree
=================
*/
qboolean G_EntitiesFree( void ) {
int i;
gentity_t *e;
e = &g_entities[MAX_CLIENTS];
for ( i = MAX_CLIENTS; i < level.num_entities; i++, e++) {
if ( e->inuse ) {
continue;
}
// slot available
return qtrue;
}
return qfalse;
}
/*
=================
G_FreeEntity
Marks the entity as free
=================
*/
void G_FreeEntity( gentity_t *ed ) {
trap_UnlinkEntity (ed); // unlink from world
if ( ed->neverFree ) {
return;
}
memset (ed, 0, sizeof(*ed));
ed->classname = "freed";
ed->freetime = level.time;
ed->inuse = qfalse;
}
/*
=================
G_TempEntity
Spawns an event entity that will be auto-removed
The origin will be snapped to save net bandwidth, so care
must be taken if the origin is right on a surface (snap towards start vector first)
=================
*/
gentity_t *G_TempEntity( vec3_t origin, int event ) {
gentity_t *e;
vec3_t snapped;
e = G_Spawn();
e->s.eType = ET_EVENTS + event;
e->classname = "tempEntity";
e->eventTime = level.time;
e->freeAfterEvent = qtrue;
VectorCopy( origin, snapped );
SnapVector( snapped ); // save network bandwidth
G_SetOrigin( e, snapped );
// find cluster for PVS
trap_LinkEntity( e );
return e;
}
/*
==============================================================================
Kill box
==============================================================================
*/
/*
=================
G_KillBox
Kills all entities that would touch the proposed new positioning
of ent. Ent should be unlinked before calling this!
=================
*/
void G_KillBox (gentity_t *ent) {
int i, num;
int touch[MAX_GENTITIES];
gentity_t *hit;
vec3_t mins, maxs;
VectorAdd( ent->client->ps.origin, ent->r.mins, mins );
VectorAdd( ent->client->ps.origin, ent->r.maxs, maxs );
num = trap_EntitiesInBox( mins, maxs, touch, MAX_GENTITIES );
for (i=0 ; i<num ; i++) {
hit = &g_entities[touch[i]];
if ( !hit->client ) {
continue;
}
// nail it
G_Damage ( hit, ent, ent, NULL, NULL,
100000, DAMAGE_NO_PROTECTION, MOD_TELEFRAG);
}
}
//==============================================================================
/*
===============
G_AddPredictableEvent
Use for non-pmove events that would also be predicted on the
client side: jumppads and item pickups
Adds an event+parm and twiddles the event counter
===============
*/
void G_AddPredictableEvent( gentity_t *ent, int event, int eventParm ) {
if ( !ent->client ) {
return;
}
BG_AddPredictableEventToPlayerstate( event, eventParm, &ent->client->ps );
}
/*
===============
G_AddEvent
Adds an event+parm and twiddles the event counter
===============
*/
void G_AddEvent( gentity_t *ent, int event, int eventParm ) {
int bits;
if ( !event ) {
G_Printf( "G_AddEvent: zero event added for entity %i\n", ent->s.number );
return;
}
// clients need to add the event in playerState_t instead of entityState_t
if ( ent->client ) {
bits = ent->client->ps.externalEvent & EV_EVENT_BITS;
bits = ( bits + EV_EVENT_BIT1 ) & EV_EVENT_BITS;
ent->client->ps.externalEvent = event | bits;
ent->client->ps.externalEventParm = eventParm;
ent->client->ps.externalEventTime = level.time;
} else {
bits = ent->s.event & EV_EVENT_BITS;
bits = ( bits + EV_EVENT_BIT1 ) & EV_EVENT_BITS;
ent->s.event = event | bits;
ent->s.eventParm = eventParm;
}
ent->eventTime = level.time;
}
/*
=============
G_Sound
=============
*/
void G_Sound( gentity_t *ent, int channel, int soundIndex ) {
gentity_t *te;
te = G_TempEntity( ent->r.currentOrigin, EV_GENERAL_SOUND );
te->s.eventParm = soundIndex;
}
//==============================================================================
/*
================
G_SetOrigin
Sets the pos trajectory for a fixed position
================
*/
void G_SetOrigin( gentity_t *ent, vec3_t origin ) {
VectorCopy( origin, ent->s.pos.trBase );
ent->s.pos.trType = TR_STATIONARY;
ent->s.pos.trTime = 0;
ent->s.pos.trDuration = 0;
VectorClear( ent->s.pos.trDelta );
VectorCopy( origin, ent->r.currentOrigin );
}
/*
================
DebugLine
debug polygons only work when running a local game
with r_debugSurface set to 2
================
*/
int DebugLine(vec3_t start, vec3_t end, int color) {
vec3_t points[4], dir, cross, up = {0, 0, 1};
float dot;
VectorCopy(start, points[0]);
VectorCopy(start, points[1]);
//points[1][2] -= 2;
VectorCopy(end, points[2]);
//points[2][2] -= 2;
VectorCopy(end, points[3]);
VectorSubtract(end, start, dir);
VectorNormalize(dir);
dot = DotProduct(dir, up);
if (dot > 0.99 || dot < -0.99) VectorSet(cross, 1, 0, 0);
else CrossProduct(dir, up, cross);
VectorNormalize(cross);
VectorMA(points[0], 2, cross, points[0]);
VectorMA(points[1], -2, cross, points[1]);
VectorMA(points[2], -2, cross, points[2]);
VectorMA(points[3], 2, cross, points[3]);
return trap_DebugPolygonCreate(color, 4, points);
}

1145
code/game/g_weapon.c Normal file

File diff suppressed because it is too large Load diff

85
code/game/game.bat Normal file
View file

@ -0,0 +1,85 @@
rem make sure we have a safe environement
set LIBRARY=
set INCLUDE=
mkdir vm
cd vm
set cc=lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\ui %1
%cc% ../g_main.c
@if errorlevel 1 goto quit
%cc% ../g_syscalls.c
@if errorlevel 1 goto quit
%cc% ../bg_misc.c
@if errorlevel 1 goto quit
%cc% ../bg_lib.c
@if errorlevel 1 goto quit
%cc% ../bg_pmove.c
@if errorlevel 1 goto quit
%cc% ../bg_slidemove.c
@if errorlevel 1 goto quit
%cc% ../q_math.c
@if errorlevel 1 goto quit
%cc% ../q_shared.c
@if errorlevel 1 goto quit
%cc% ../ai_dmnet.c
@if errorlevel 1 goto quit
%cc% ../ai_dmq3.c
@if errorlevel 1 goto quit
%cc% ../ai_main.c
@if errorlevel 1 goto quit
%cc% ../ai_chat.c
@if errorlevel 1 goto quit
%cc% ../ai_cmd.c
@if errorlevel 1 goto quit
%cc% ../ai_team.c
@if errorlevel 1 goto quit
%cc% ../g_active.c
@if errorlevel 1 goto quit
%cc% ../g_arenas.c
@if errorlevel 1 goto quit
%cc% ../g_bot.c
@if errorlevel 1 goto quit
%cc% ../g_client.c
@if errorlevel 1 goto quit
%cc% ../g_cmds.c
@if errorlevel 1 goto quit
%cc% ../g_combat.c
@if errorlevel 1 goto quit
%cc% ../g_items.c
@if errorlevel 1 goto quit
%cc% ../g_mem.c
@if errorlevel 1 goto quit
%cc% ../g_misc.c
@if errorlevel 1 goto quit
%cc% ../g_missile.c
@if errorlevel 1 goto quit
%cc% ../g_mover.c
@if errorlevel 1 goto quit
%cc% ../g_session.c
@if errorlevel 1 goto quit
%cc% ../g_spawn.c
@if errorlevel 1 goto quit
%cc% ../g_svcmds.c
@if errorlevel 1 goto quit
%cc% ../g_target.c
@if errorlevel 1 goto quit
%cc% ../g_team.c
@if errorlevel 1 goto quit
%cc% ../g_trigger.c
@if errorlevel 1 goto quit
%cc% ../g_utils.c
@if errorlevel 1 goto quit
%cc% ../g_weapon.c
@if errorlevel 1 goto quit
%cc% ../ai_vcmd.c
@if errorlevel 1 goto quit
q3asm -f ../game
:quit
cd ..

3
code/game/game.def Normal file
View file

@ -0,0 +1,3 @@
EXPORTS
dllEntry
vmMain

35
code/game/game.q3asm Normal file
View file

@ -0,0 +1,35 @@
-o "\quake3\baseq3\vm\qagame"
g_main
..\g_syscalls
bg_misc
bg_lib
bg_pmove
bg_slidemove
q_math
q_shared
ai_dmnet
ai_dmq3
ai_team
ai_main
ai_chat
ai_cmd
ai_vcmd
g_active
g_arenas
g_bot
g_client
g_cmds
g_combat
g_items
g_mem
g_misc
g_missile
g_mover
g_session
g_spawn
g_svcmds
g_target
g_team
g_trigger
g_utils
g_weapon

48
code/game/game.sh Normal file
View file

@ -0,0 +1,48 @@
#!/bin/sh
mkdir -p vm
cd vm
CC="q3lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I../../cgame -I../../game -I../../q3_ui"
$CC ../g_main.c
$CC ../g_syscalls.c
$CC ../bg_misc.c
$CC ../bg_lib.c
$CC ../bg_pmove.c
$CC ../bg_slidemove.c
$CC ../q_math.c
$CC ../q_shared.c
$CC ../ai_vcmd.c
$CC ../ai_dmnet.c
$CC ../ai_dmq3.c
$CC ../ai_main.c
$CC ../ai_chat.c
$CC ../ai_cmd.c
$CC ../ai_team.c
$CC ../g_active.c
$CC ../g_arenas.c
$CC ../g_bot.c
$CC ../g_client.c
$CC ../g_cmds.c
$CC ../g_combat.c
$CC ../g_items.c
$CC ../g_mem.c
$CC ../g_misc.c
$CC ../g_missile.c
$CC ../g_mover.c
$CC ../g_session.c
$CC ../g_spawn.c
$CC ../g_svcmds.c
$CC ../g_target.c
$CC ../g_team.c
$CC ../g_trigger.c
$CC ../g_utils.c
$CC ../g_weapon.c
q3asm -f ../game
cd ..

2132
code/game/game.vcproj Normal file

File diff suppressed because it is too large Load diff

86
code/game/game_ta.bat Normal file
View file

@ -0,0 +1,86 @@
rem make sure we have a safe environement
set LIBRARY=
set INCLUDE=
mkdir vm
cd vm
set cc=lcc -DQ3_VM -DMISSIONPACK -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\ui %1
%cc% ../g_main.c
@if errorlevel 1 goto quit
%cc% ../g_syscalls.c
@if errorlevel 1 goto quit
%cc% ../bg_misc.c
@if errorlevel 1 goto quit
%cc% ../bg_lib.c
@if errorlevel 1 goto quit
%cc% ../bg_pmove.c
@if errorlevel 1 goto quit
%cc% ../bg_slidemove.c
@if errorlevel 1 goto quit
%cc% ../q_math.c
@if errorlevel 1 goto quit
%cc% ../q_shared.c
@if errorlevel 1 goto quit
%cc% ../ai_dmnet.c
@if errorlevel 1 goto quit
%cc% ../ai_dmq3.c
@if errorlevel 1 goto quit
%cc% ../ai_main.c
@if errorlevel 1 goto quit
%cc% ../ai_chat.c
@if errorlevel 1 goto quit
%cc% ../ai_cmd.c
@if errorlevel 1 goto quit
%cc% ../ai_team.c
@if errorlevel 1 goto quit
%cc% ../g_active.c
@if errorlevel 1 goto quit
%cc% ../g_arenas.c
@if errorlevel 1 goto quit
%cc% ../g_bot.c
@if errorlevel 1 goto quit
%cc% ../g_client.c
@if errorlevel 1 goto quit
%cc% ../g_cmds.c
@if errorlevel 1 goto quit
%cc% ../g_combat.c
@if errorlevel 1 goto quit
%cc% ../g_items.c
@if errorlevel 1 goto quit
%cc% ../g_mem.c
@if errorlevel 1 goto quit
%cc% ../g_misc.c
@if errorlevel 1 goto quit
%cc% ../g_missile.c
@if errorlevel 1 goto quit
%cc% ../g_mover.c
@if errorlevel 1 goto quit
%cc% ../g_session.c
@if errorlevel 1 goto quit
%cc% ../g_spawn.c
@if errorlevel 1 goto quit
%cc% ../g_svcmds.c
@if errorlevel 1 goto quit
%cc% ../g_target.c
@if errorlevel 1 goto quit
%cc% ../g_team.c
@if errorlevel 1 goto quit
%cc% ../g_trigger.c
@if errorlevel 1 goto quit
%cc% ../g_utils.c
@if errorlevel 1 goto quit
%cc% ../g_weapon.c
@if errorlevel 1 goto quit
%cc% ../ai_vcmd.c
@if errorlevel 1 goto quit
q3asm -f ../game_ta
:quit
cd ..

35
code/game/game_ta.q3asm Normal file
View file

@ -0,0 +1,35 @@
-o "\quake3\missionpack\vm\qagame"
g_main
..\g_syscalls
bg_misc
bg_lib
bg_pmove
bg_slidemove
q_math
q_shared
ai_dmnet
ai_dmq3
ai_team
ai_main
ai_chat
ai_cmd
g_active
g_arenas
g_bot
g_client
g_cmds
g_combat
g_items
g_mem
g_misc
g_missile
g_mover
g_session
g_spawn
g_svcmds
g_target
g_team
g_trigger
g_utils
g_weapon
ai_vcmd

48
code/game/game_ta.sh Normal file
View file

@ -0,0 +1,48 @@
#!/bin/sh
mkdir -p vm
cd vm
CC="q3lcc -DQ3_VM -DMISSIONPACK -S -Wf-target=bytecode -Wf-g -I../../cgame -I../../game -I../../ui"
$CC ../g_main.c
$CC ../g_syscalls.c
$CC ../bg_misc.c
$CC ../bg_lib.c
$CC ../bg_pmove.c
$CC ../bg_slidemove.c
$CC ../q_math.c
$CC ../q_shared.c
$CC ../ai_vcmd.c
$CC ../ai_dmnet.c
$CC ../ai_dmq3.c
$CC ../ai_main.c
$CC ../ai_chat.c
$CC ../ai_cmd.c
$CC ../ai_team.c
$CC ../g_active.c
$CC ../g_arenas.c
$CC ../g_bot.c
$CC ../g_client.c
$CC ../g_cmds.c
$CC ../g_combat.c
$CC ../g_items.c
$CC ../g_mem.c
$CC ../g_misc.c
$CC ../g_missile.c
$CC ../g_mover.c
$CC ../g_session.c
$CC ../g_spawn.c
$CC ../g_svcmds.c
$CC ../g_target.c
$CC ../g_team.c
$CC ../g_trigger.c
$CC ../g_utils.c
$CC ../g_weapon.c
q3asm -f ../game_ta
cd ..

166
code/game/inv.h Normal file
View file

@ -0,0 +1,166 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#define INVENTORY_NONE 0
//armor
#define INVENTORY_ARMOR 1
//weapons
#define INVENTORY_GAUNTLET 4
#define INVENTORY_SHOTGUN 5
#define INVENTORY_MACHINEGUN 6
#define INVENTORY_GRENADELAUNCHER 7
#define INVENTORY_ROCKETLAUNCHER 8
#define INVENTORY_LIGHTNING 9
#define INVENTORY_RAILGUN 10
#define INVENTORY_PLASMAGUN 11
#define INVENTORY_BFG10K 13
#define INVENTORY_GRAPPLINGHOOK 14
#define INVENTORY_NAILGUN 15
#define INVENTORY_PROXLAUNCHER 16
#define INVENTORY_CHAINGUN 17
//ammo
#define INVENTORY_SHELLS 18
#define INVENTORY_BULLETS 19
#define INVENTORY_GRENADES 20
#define INVENTORY_CELLS 21
#define INVENTORY_LIGHTNINGAMMO 22
#define INVENTORY_ROCKETS 23
#define INVENTORY_SLUGS 24
#define INVENTORY_BFGAMMO 25
#define INVENTORY_NAILS 26
#define INVENTORY_MINES 27
#define INVENTORY_BELT 28
//powerups
#define INVENTORY_HEALTH 29
#define INVENTORY_TELEPORTER 30
#define INVENTORY_MEDKIT 31
#define INVENTORY_KAMIKAZE 32
#define INVENTORY_PORTAL 33
#define INVENTORY_INVULNERABILITY 34
#define INVENTORY_QUAD 35
#define INVENTORY_ENVIRONMENTSUIT 36
#define INVENTORY_HASTE 37
#define INVENTORY_INVISIBILITY 38
#define INVENTORY_REGEN 39
#define INVENTORY_FLIGHT 40
#define INVENTORY_SCOUT 41
#define INVENTORY_GUARD 42
#define INVENTORY_DOUBLER 43
#define INVENTORY_AMMOREGEN 44
#define INVENTORY_REDFLAG 45
#define INVENTORY_BLUEFLAG 46
#define INVENTORY_NEUTRALFLAG 47
#define INVENTORY_REDCUBE 48
#define INVENTORY_BLUECUBE 49
//enemy stuff
#define ENEMY_HORIZONTAL_DIST 200
#define ENEMY_HEIGHT 201
#define NUM_VISIBLE_ENEMIES 202
#define NUM_VISIBLE_TEAMMATES 203
// if running the mission pack
#ifdef MISSIONPACK
//#error "running mission pack"
#endif
//item numbers (make sure they are in sync with bg_itemlist in bg_misc.c)
#define MODELINDEX_ARMORSHARD 1
#define MODELINDEX_ARMORCOMBAT 2
#define MODELINDEX_ARMORBODY 3
#define MODELINDEX_HEALTHSMALL 4
#define MODELINDEX_HEALTH 5
#define MODELINDEX_HEALTHLARGE 6
#define MODELINDEX_HEALTHMEGA 7
#define MODELINDEX_GAUNTLET 8
#define MODELINDEX_SHOTGUN 9
#define MODELINDEX_MACHINEGUN 10
#define MODELINDEX_GRENADELAUNCHER 11
#define MODELINDEX_ROCKETLAUNCHER 12
#define MODELINDEX_LIGHTNING 13
#define MODELINDEX_RAILGUN 14
#define MODELINDEX_PLASMAGUN 15
#define MODELINDEX_BFG10K 16
#define MODELINDEX_GRAPPLINGHOOK 17
#define MODELINDEX_SHELLS 18
#define MODELINDEX_BULLETS 19
#define MODELINDEX_GRENADES 20
#define MODELINDEX_CELLS 21
#define MODELINDEX_LIGHTNINGAMMO 22
#define MODELINDEX_ROCKETS 23
#define MODELINDEX_SLUGS 24
#define MODELINDEX_BFGAMMO 25
#define MODELINDEX_TELEPORTER 26
#define MODELINDEX_MEDKIT 27
#define MODELINDEX_QUAD 28
#define MODELINDEX_ENVIRONMENTSUIT 29
#define MODELINDEX_HASTE 30
#define MODELINDEX_INVISIBILITY 31
#define MODELINDEX_REGEN 32
#define MODELINDEX_FLIGHT 33
#define MODELINDEX_REDFLAG 34
#define MODELINDEX_BLUEFLAG 35
// mission pack only defines
#define MODELINDEX_KAMIKAZE 36
#define MODELINDEX_PORTAL 37
#define MODELINDEX_INVULNERABILITY 38
#define MODELINDEX_NAILS 39
#define MODELINDEX_MINES 40
#define MODELINDEX_BELT 41
#define MODELINDEX_SCOUT 42
#define MODELINDEX_GUARD 43
#define MODELINDEX_DOUBLER 44
#define MODELINDEX_AMMOREGEN 45
#define MODELINDEX_NEUTRALFLAG 46
#define MODELINDEX_REDCUBE 47
#define MODELINDEX_BLUECUBE 48
#define MODELINDEX_NAILGUN 49
#define MODELINDEX_PROXLAUNCHER 50
#define MODELINDEX_CHAINGUN 51
//
#define WEAPONINDEX_GAUNTLET 1
#define WEAPONINDEX_MACHINEGUN 2
#define WEAPONINDEX_SHOTGUN 3
#define WEAPONINDEX_GRENADE_LAUNCHER 4
#define WEAPONINDEX_ROCKET_LAUNCHER 5
#define WEAPONINDEX_LIGHTNING 6
#define WEAPONINDEX_RAILGUN 7
#define WEAPONINDEX_PLASMAGUN 8
#define WEAPONINDEX_BFG 9
#define WEAPONINDEX_GRAPPLING_HOOK 10
#define WEAPONINDEX_NAILGUN 11
#define WEAPONINDEX_PROXLAUNCHER 12
#define WEAPONINDEX_CHAINGUN 13

134
code/game/match.h Normal file
View file

@ -0,0 +1,134 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// make sure this is the same character as we use in chats in g_cmd.c
#define EC "\x19"
//match template contexts
#define MTCONTEXT_MISC 2
#define MTCONTEXT_INITIALTEAMCHAT 4
#define MTCONTEXT_TIME 8
#define MTCONTEXT_TEAMMATE 16
#define MTCONTEXT_ADDRESSEE 32
#define MTCONTEXT_PATROLKEYAREA 64
#define MTCONTEXT_REPLYCHAT 128
#define MTCONTEXT_CTF 256
//message types
#define MSG_NEWLEADER 1 //new leader
#define MSG_ENTERGAME 2 //enter game message
#define MSG_HELP 3 //help someone
#define MSG_ACCOMPANY 4 //accompany someone
#define MSG_DEFENDKEYAREA 5 //defend a key area
#define MSG_RUSHBASE 6 //everyone rush to base
#define MSG_GETFLAG 7 //get the enemy flag
#define MSG_STARTTEAMLEADERSHIP 8 //someone wants to become the team leader
#define MSG_STOPTEAMLEADERSHIP 9 //someone wants to stop being the team leader
#define MSG_WHOISTEAMLAEDER 10 //who is the team leader
#define MSG_WAIT 11 //wait for someone
#define MSG_WHATAREYOUDOING 12 //what are you doing?
#define MSG_JOINSUBTEAM 13 //join a sub-team
#define MSG_LEAVESUBTEAM 14 //leave a sub-team
#define MSG_CREATENEWFORMATION 15 //create a new formation
#define MSG_FORMATIONPOSITION 16 //tell someone his/her position in a formation
#define MSG_FORMATIONSPACE 17 //set the formation intervening space
#define MSG_DOFORMATION 18 //form a known formation
#define MSG_DISMISS 19 //dismiss commanded team mates
#define MSG_CAMP 20 //camp somewhere
#define MSG_CHECKPOINT 21 //remember a check point
#define MSG_PATROL 22 //patrol between certain keypoints
#define MSG_LEADTHEWAY 23 //lead the way
#define MSG_GETITEM 24 //get an item
#define MSG_KILL 25 //kill someone
#define MSG_WHEREAREYOU 26 //where is someone
#define MSG_RETURNFLAG 27 //return the flag
#define MSG_WHATISMYCOMMAND 28 //ask the team leader what to do
#define MSG_WHICHTEAM 29 //ask which team a bot is in
#define MSG_TASKPREFERENCE 30 //tell your teamplay task preference
#define MSG_ATTACKENEMYBASE 31 //attack the enemy base
#define MSG_HARVEST 32 //go harvest
#define MSG_SUICIDE 33 //order to suicide
//
#define MSG_ME 100
#define MSG_EVERYONE 101
#define MSG_MULTIPLENAMES 102
#define MSG_NAME 103
#define MSG_PATROLKEYAREA 104
#define MSG_MINUTES 105
#define MSG_SECONDS 106
#define MSG_FOREVER 107
#define MSG_FORALONGTIME 108
#define MSG_FORAWHILE 109
//
#define MSG_CHATALL 200
#define MSG_CHATTEAM 201
#define MSG_CHATTELL 202
//
#define MSG_CTF 300 //ctf message
//command sub types
#define ST_SOMEWHERE 0
#define ST_NEARITEM 1
#define ST_ADDRESSED 2
#define ST_METER 4
#define ST_FEET 8
#define ST_TIME 16
#define ST_HERE 32
#define ST_THERE 64
#define ST_I 128
#define ST_MORE 256
#define ST_BACK 512
#define ST_REVERSE 1024
#define ST_SOMEONE 2048
#define ST_GOTFLAG 4096
#define ST_CAPTUREDFLAG 8192
#define ST_RETURNEDFLAG 16384
#define ST_TEAM 32768
#define ST_1FCTFGOTFLAG 65535
//ctf task preferences
#define ST_DEFENDER 1
#define ST_ATTACKER 2
#define ST_ROAMER 4
//word replacement variables
#define THE_ENEMY 7
#define THE_TEAM 7
//team message variables
#define NETNAME 0
#define PLACE 1
#define FLAG 1
#define MESSAGE 2
#define ADDRESSEE 2
#define ITEM 3
#define TEAMMATE 4
#define TEAMNAME 4
#define ENEMY 4
#define KEYAREA 5
#define FORMATION 5
#define POSITION 5
#define NUMBER 5
#define TIME 6
#define NAME 6
#define MORE 6

1308
code/game/q_math.c Normal file

File diff suppressed because it is too large Load diff

1258
code/game/q_shared.c Normal file

File diff suppressed because it is too large Load diff

1432
code/game/q_shared.h Normal file

File diff suppressed because it is too large Load diff

80
code/game/surfaceflags.h Normal file
View file

@ -0,0 +1,80 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// This file must be identical in the quake and utils directories
// contents flags are seperate bits
// a given brush can contribute multiple content bits
// these definitions also need to be in q_shared.h!
#define CONTENTS_SOLID 1 // an eye is never valid in a solid
#define CONTENTS_LAVA 8
#define CONTENTS_SLIME 16
#define CONTENTS_WATER 32
#define CONTENTS_FOG 64
#define CONTENTS_NOTTEAM1 0x0080
#define CONTENTS_NOTTEAM2 0x0100
#define CONTENTS_NOBOTCLIP 0x0200
#define CONTENTS_AREAPORTAL 0x8000
#define CONTENTS_PLAYERCLIP 0x10000
#define CONTENTS_MONSTERCLIP 0x20000
//bot specific contents types
#define CONTENTS_TELEPORTER 0x40000
#define CONTENTS_JUMPPAD 0x80000
#define CONTENTS_CLUSTERPORTAL 0x100000
#define CONTENTS_DONOTENTER 0x200000
#define CONTENTS_BOTCLIP 0x400000
#define CONTENTS_MOVER 0x800000
#define CONTENTS_ORIGIN 0x1000000 // removed before bsping an entity
#define CONTENTS_BODY 0x2000000 // should never be on a brush, only in game
#define CONTENTS_CORPSE 0x4000000
#define CONTENTS_DETAIL 0x8000000 // brushes not used for the bsp
#define CONTENTS_STRUCTURAL 0x10000000 // brushes used for the bsp
#define CONTENTS_TRANSLUCENT 0x20000000 // don't consume surface fragments inside
#define CONTENTS_TRIGGER 0x40000000
#define CONTENTS_NODROP 0x80000000 // don't leave bodies or items (death fog, lava)
#define SURF_NODAMAGE 0x1 // never give falling damage
#define SURF_SLICK 0x2 // effects game physics
#define SURF_SKY 0x4 // lighting from environment map
#define SURF_LADDER 0x8
#define SURF_NOIMPACT 0x10 // don't make missile explosions
#define SURF_NOMARKS 0x20 // don't leave missile marks
#define SURF_FLESH 0x40 // make flesh sounds and effects
#define SURF_NODRAW 0x80 // don't generate a drawsurface at all
#define SURF_HINT 0x100 // make a primary bsp splitter
#define SURF_SKIP 0x200 // completely ignore, allowing non-closed brushes
#define SURF_NOLIGHTMAP 0x400 // surface doesn't need a lightmap
#define SURF_POINTLIGHT 0x800 // generate lighting info at vertexes
#define SURF_METALSTEPS 0x1000 // clanking footsteps
#define SURF_NOSTEPS 0x2000 // no footstep sounds
#define SURF_NONSOLID 0x4000 // don't collide against curves with this set
#define SURF_LIGHTFILTER 0x8000 // act as a light filter during q3map -light
#define SURF_ALPHASHADOW 0x10000 // do per-pixel light shadow casting in q3map
#define SURF_NODLIGHT 0x20000 // don't dlight even if solid (solid lava, skies)
#define SURF_DUST 0x40000 // leave a dust trail when walking on this surface

34
code/game/syn.h Normal file
View file

@ -0,0 +1,34 @@
/*
===========================================================================
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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#define CONTEXT_ALL 0xFFFFFFFF
#define CONTEXT_NORMAL 1
#define CONTEXT_NEARBYITEM 2
#define CONTEXT_CTFREDTEAM 4
#define CONTEXT_CTFBLUETEAM 8
#define CONTEXT_REPLY 16
#define CONTEXT_OBELISKREDTEAM 32
#define CONTEXT_OBELISKBLUETEAM 64
#define CONTEXT_HARVESTERREDTEAM 128
#define CONTEXT_HARVESTERBLUETEAM 256
#define CONTEXT_NAMES 1024