/*
===========================================================================
Copyright (C) 1999 - 2005, Id Software, Inc.
Copyright (C) 2000 - 2013, Raven Software, Inc.
Copyright (C) 2001 - 2013, Activision, Inc.
Copyright (C) 2013 - 2015, OpenJK contributors
This file is part of the OpenJK source code.
OpenJK is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, see .
===========================================================================
*/
#ifndef __G_LOCAL_H__
#define __G_LOCAL_H__
// g_local.h -- local definitions for game module
// define GAME_INCLUDE so that g_public.h does not define the
// short, server-visible gclient_t and gentity_t structures,
// because we define the full size ones in this file
#define GAME_INCLUDE
#include "../../code/ui/gameinfo.h"
#include "g_shared.h"
#include "anims.h"
#include "dmstates.h"
#include "time.h"
//==================================================================
// the "gameversion" client command will print this plus compile date
#define GAMEVERSION "base"
#define BODY_QUEUE_SIZE 8
#define Q3_INFINITE 16777216
#define FRAMETIME 100 // msec
#define EVENT_VALID_MSEC 300
#define CARNAGE_REWARD_TIME 3000
#define INTERMISSION_DELAY_TIME 1000
#define START_TIME_LINK_ENTS FRAMETIME*1 // time-delay after map start at which all ents have been spawned, so can link them
#define START_TIME_FIND_LINKS FRAMETIME*2 // time-delay after map start at which you can find linked entities
#define START_TIME_MOVERS_SPAWNED FRAMETIME*2 // time-delay after map start at which all movers should be spawned
#define START_TIME_REMOVE_ENTS FRAMETIME*3 // time-delay after map start to remove temporary ents
#define START_TIME_NAV_CALC FRAMETIME*4 // time-delay after map start to connect waypoints and calc routes
#define START_TIME_FIND_WAYPOINT FRAMETIME*5 // time-delay after map start after which it's okay to try to find your best waypoint
// gentity->flags
#define FL_SHIELDED 0x00000001 // protected from all damage except lightsabers
#define FL_DMG_BY_HEAVY_WEAP_ONLY 0x00000002 // protected from all damage except heavy weap class missiles
#define FL_DMG_BY_SABER_ONLY 0x00000004 //protected from all damage except saber damage
#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_DONT_SHOOT 0x00002000 // Can target him, but not shoot him
#define FL_UNDYING 0x00004000 // Takes damage down to 1 point, but does not die
//#define FL_OVERCHARGED 0x00008000 // weapon shot is an overcharged version....probably a lame place to be putting this flag...
#define FL_LOCK_PLAYER_WEAPONS 0x00010000 // player can't switch weapons... ask james if there's a better spot for this
#define FL_DISINTEGRATED 0x00020000 // marks that the corpse has already been disintegrated
#define FL_FORCE_PULLABLE_ONLY 0x00040000 // cannot be force pushed
#define FL_NO_IMPACT_DMG 0x00080000 // Will not take impact damage
//Pointer safety utilities
#define VALID( a ) ( a != NULL )
#define VALIDATE( a ) ( assert( a ) )
#define VALIDATEV( a ) if ( a == NULL ) { assert(0); return; }
#define VALIDATEB( a ) if ( a == NULL ) { assert(0); return qfalse; }
#define VALIDATEP( a ) if ( a == NULL ) { assert(0); return NULL; }
#define VALIDSTRING( a ) ( ( a != NULL ) && ( a[0] != '\0' ) )
//Interest points
#define MAX_INTEREST_POINTS 64
typedef struct
{
vec3_t origin;
char *target;
} interestPoint_t;
//Combat points
#define MAX_COMBAT_POINTS 512
typedef struct
{
vec3_t origin;
int flags;
// char *NPC_targetname;
// team_t team;
qboolean occupied;
int waypoint;
int dangerTime;
} combatPoint_t;
// Alert events
#define MAX_ALERT_EVENTS 32
enum alertEventType_e
{
AET_SIGHT,
AET_SOUND,
};
enum alertEventLevel_e
{
AEL_MINOR, //Enemy responds to the sound, but only by looking
AEL_SUSPICIOUS, //Enemy looks at the sound, and will also investigate it
AEL_DISCOVERED, //Enemy knows the player is around, and will actively hunt
AEL_DANGER, //Enemy should try to find cover
AEL_DANGER_GREAT, //Enemy should run like hell!
};
// !!!!!!!!! LOADSAVE-affecting struct !!!!!!!!!!
class alertEvent_t
{
public:
vec3_t position; //Where the event is located
float radius; //Consideration radius
alertEventLevel_e level; //Priority level of the event
alertEventType_e type; //Event type (sound,sight)
gentity_t *owner; //Who made the sound
float light; //ambient light level at point
float addLight; //additional light- makes it more noticable, even in darkness
int ID; //unique... if get a ridiculous number, this will repeat, but should not be a problem as it's just comparing it to your lastAlertID
int timestamp; //when it was created
void sg_export(
ojk::SavedGameHelper& saved_game) const
{
saved_game.write(position);
saved_game.write(radius);
saved_game.write(level);
saved_game.write(type);
saved_game.write(owner);
saved_game.write(light);
saved_game.write(addLight);
saved_game.write(ID);
saved_game.write(timestamp);
}
void sg_import(
ojk::SavedGameHelper& saved_game)
{
saved_game.read(position);
saved_game.read(radius);
saved_game.read(level);
saved_game.read(type);
saved_game.read(owner);
saved_game.read(light);
saved_game.read(addLight);
saved_game.read(ID);
saved_game.read(timestamp);
}
}; // alertEvent_t
//
// this structure is cleared as each map is entered
//
#define MAX_SPAWN_VARS 64
#define MAX_SPAWN_VARS_CHARS 2048
typedef struct
{
char targetname[MAX_QPATH];
char target[MAX_QPATH];
char target2[MAX_QPATH];
char target3[MAX_QPATH];
char target4[MAX_QPATH];
int nodeID;
} waypointData_t;
#define WF_RAINING 0x00000001 //raining
#define WF_SNOWING 0x00000002 //snowing
// !!!!!!!!!! LOADSAVE-affecting structure !!!!!!!!!!
class level_locals_t
{
public:
gclient_t *clients; // [maxclients]
// 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 globalTime; // global time at level initialization
char mapname[MAX_QPATH]; // the server name (base1, etc)
qboolean locationLinked; // target_locations get linked
gentity_t *locationHead; // head of the location list
alertEvent_t alertEvents[ MAX_ALERT_EVENTS ];
int numAlertEvents;
int curAlertID;
AIGroupInfo_t groups[MAX_FRAME_GROUPS];
animFileSet_t knownAnimFileSets[MAX_ANIM_FILES];
int numKnownAnimFileSets;
int worldFlags;
int dmState; //actually, we do want save/load the dynamic music state
// =====================================
//
// NOTE!!!!!! The only things beyond this point in the structure should be the ones you do NOT wish to be
// affected by loading saved-games. Since loading a game first starts the map and then loads
// over things like entities etc then these fields are usually the ones setup by the map loader.
// If they ever get modified in-game let me know and I'll include them in the save. -Ste
//
#define LEVEL_LOCALS_T_SAVESTOP logFile // name of whichever field is next below this in the source
fileHandle_t logFile;
//Interest points- squadmates automatically look at these if standing around and close to them
interestPoint_t interestPoints[MAX_INTEREST_POINTS];
int numInterestPoints;
//Combat points- NPCs in bState BS_COMBAT_POINT will find their closest empty combat_point
combatPoint_t combatPoints[MAX_COMBAT_POINTS];
int numCombatPoints;
char spawntarget[MAX_QPATH]; // the targetname of the spawnpoint you want the player to start at
int dmDebounceTime;
int dmBeatTime;
void sg_export(
ojk::SavedGameHelper& saved_game) const
{
saved_game.write(clients);
saved_game.write(maxclients);
saved_game.write(framenum);
saved_game.write(time);
saved_game.write(previousTime);
saved_game.write(globalTime);
saved_game.write(mapname);
saved_game.write(locationLinked);
saved_game.write(locationHead);
saved_game.write<>(alertEvents);
saved_game.write(numAlertEvents);
saved_game.write(curAlertID);
saved_game.write<>(groups);
saved_game.write<>(knownAnimFileSets);
saved_game.write(numKnownAnimFileSets);
saved_game.write(worldFlags);
saved_game.write(dmState);
}
void sg_import(
ojk::SavedGameHelper& saved_game)
{
saved_game.read(clients);
saved_game.read(maxclients);
saved_game.read(framenum);
saved_game.read(time);
saved_game.read(previousTime);
saved_game.read(globalTime);
saved_game.read(mapname);
saved_game.read(locationLinked);
saved_game.read(locationHead);
saved_game.read<>(alertEvents);
saved_game.read(numAlertEvents);
saved_game.read(curAlertID);
saved_game.read<>(groups);
saved_game.read<>(knownAnimFileSets);
saved_game.read(numKnownAnimFileSets);
saved_game.read(worldFlags);
saved_game.read(dmState);
}
}; // level_locals_t
extern level_locals_t level;
extern game_export_t globals;
extern cvar_t *g_gravity;
extern cvar_t *g_speed;
extern cvar_t *g_cheats;
extern cvar_t *g_developer;
extern cvar_t *g_knockback;
extern cvar_t *g_inactivity;
extern cvar_t *g_debugMove;
extern cvar_t *g_subtitles;
extern cvar_t *g_removeDoors;
extern cvar_t *g_ICARUSDebug;
extern gentity_t *player;
//
// 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 );
qboolean G_SpawnVector4( const char *key, const char *defaultString, float *out );
qboolean G_SpawnAngleHack( const char *key, const char *defaultString, float *out );
void G_SpawnEntitiesFromString( const char *entities );
//
// g_cmds.c
//
void Cmd_Score_f (gentity_t *ent);
//
// g_items.c
//
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, qboolean copytarget );
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( const char *name );
int G_SoundIndex( const char *name );
/*
Ghoul2 Insert Start
*/
int G_SkinIndex( const char *name );
void G_SetBoltSurfaceRemoval( const int entNum, const int modelIndex, const int boltIndex, const int surfaceIndex = -1, float duration = 5000 );
/*
Ghoul2 Insert End
*/
int G_EffectIndex( const char *name );
void G_PlayEffect( const char *name, vec3_t origin );
void G_PlayEffect( const char *name, int clientNum );
void G_PlayEffect( const char *name, vec3_t origin, vec3_t fwd );
void G_PlayEffect( const char *name, vec3_t origin, vec3_t axis[3] );
void G_PlayEffect( const char *name, const int modelIndex, const int boltIndex, const int entNum);
void G_PlayEffect( int fxID, vec3_t origin, vec3_t fwd );
void G_PlayEffect( int fxID, vec3_t origin, vec3_t axis[3] );
void G_PlayEffect( int fxID, const int modelIndex, const int boltIndex, const int entNum);
void G_PlayEffect( int fxID, int entNum, vec3_t fwd );
void G_KillBox (gentity_t *ent);
gentity_t *G_Find (gentity_t *from, int fieldofs, const char *match);
int G_RadiusList ( vec3_t origin, float radius, gentity_t *ignore, qboolean takeDamage, gentity_t *ent_list[MAX_GENTITIES]);
gentity_t *G_PickTarget (char *targetname);
void G_UseTargets (gentity_t *ent, gentity_t *activator);
void G_UseTargets2 (gentity_t *ent, gentity_t *activator, const char *string);
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 soundIndex );
void G_FreeEntity( gentity_t *e );
void G_TouchTriggers (gentity_t *ent);
void G_TouchTeamClients (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_AddEvent( gentity_t *ent, int event, int eventParm );
void G_SetOrigin( gentity_t *ent, const vec3_t origin );
void G_SetAngles( gentity_t *ent, const vec3_t angles );
void G_DebugLine(vec3_t A, vec3_t B, int duration, int color, qboolean deleteornot);
//
// 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, int hitLoc=HL_NONE );
void G_RadiusDamage (vec3_t origin, gentity_t *attacker, float damage, float radius, gentity_t *ignore, int mod);
gentity_t *TossClientItems( gentity_t *self );
void ExplodeDeath_Wait( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath,int dFlags,int hitLoc );
void ExplodeDeath( gentity_t *self );
void GoExplodeDeath( gentity_t *self, gentity_t *other, gentity_t *activator);
void G_ApplyKnockback( gentity_t *targ, vec3_t newDir, float knockback );
void G_Throw( gentity_t *targ, vec3_t newDir, float push );
// 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 0x00000008 // do not affect velocity, just view angles
#define DAMAGE_NO_HIT_LOC 0x00000010 // do not modify damage by hit loc
#define DAMAGE_NO_PROTECTION 0x00000020 // armor, shields, invulnerability, and godmode have no effect
#define DAMAGE_EXTRA_KNOCKBACK 0x00000040 // add extra knockback to this damage
#define DAMAGE_DEATH_KNOCKBACK 0x00000080 // only does knockback on death of target
#define DAMAGE_IGNORE_TEAM 0x00000100 // damage is always done, regardless of teams
#define DAMAGE_NO_DAMAGE 0x00000200 // do no actual damage but react as if damage was taken
#define DAMAGE_DISMEMBER 0x00000400 // do dismemberment
#define DAMAGE_NO_KILL 0x00000800 // do damage, but don't kill them
#define DAMAGE_HEAVY_WEAP_CLASS 0x00001000 // doing heavy weapon type damage, certain objects may only take damage by missiles containing this flag
#define DAMAGE_CUSTOM_HUD 0x00002000 // really dumb, but....
//
// 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);
//
// g_mover.c
//
void G_RunMover( gentity_t *ent );
//
// g_misc.c
//
void TeleportPlayer( gentity_t *player, vec3_t origin, vec3_t angles );
//
// g_weapon.c
//
//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 WP_LoadWeaponParms (void);
void IT_LoadItemParms( void );
//
// g_client.c
//
team_t PickTeam( int ignoreClientNum );
void SetClientViewAngle( gentity_t *ent, vec3_t angle );
gentity_t *SelectSpawnPoint ( vec3_t avoidPoint, team_t team, vec3_t origin, vec3_t angles );
void respawn (gentity_t *ent);
void InitClientPersistant (gclient_t *client);
void InitClientResp (gclient_t *client);
qboolean ClientSpawn( gentity_t *ent, SavedGameJustLoaded_e eSavedGameJustLoaded );
void player_die (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod, int dFlags, int hitLoc);
void AddScore( gentity_t *ent, int score );
qboolean SpotWouldTelefrag( gentity_t *spot, team_t checkteam );
//
// g_svcmds.c
//
qboolean ConsoleCommand( void );
//
// g_weapon.c
//
void FireWeapon( gentity_t *ent, qboolean alt_fire );
//
// p_hud.c
//
void MoveClientToIntermission (gentity_t *client);
void G_SetStats (gentity_t *ent);
void DeathmatchScoreboardMessage (gentity_t *client);
//
// g_pweapon.c
//
//
// g_main.c
//
void G_RunThink (gentity_t *ent);
void QDECL G_Error( const char *fmt, ... );
void ClearAllInUse(void);
void SetInUse(gentity_t *ent);
void ClearInUse(gentity_t *ent);
qboolean PInUse(unsigned int entNum);
qboolean PInUse2(gentity_t *ent);
void WriteInUseBits(void);
void ReadInUseBits(void);
//
// g_nav.cpp
//
void Svcmd_Nav_f (void);
//
// g_squad.cpp
//
void Svcmd_Comm_f (void);
void Svcmd_Hail_f (void);
void Svcmd_Form_f (void);
//
// g_utils.cpp
//
void Svcmd_Use_f (void);
//
// g_weapons.cpp
//
//
// g_client.c
//
char *ClientConnect( int clientNum, qboolean firstTime, SavedGameJustLoaded_e eSavedGameJustLoaded );
void ClientUserinfoChanged( int clientNum );
void ClientDisconnect( int clientNum );
void ClientBegin( int clientNum, usercmd_t *cmd, SavedGameJustLoaded_e eSavedGameJustLoaded );
void ClientCommand( int clientNum );
//
// g_active.c
//
void ClientThink( int clientNum, usercmd_t *cmd );
void ClientEndFrame (gentity_t *ent);
//
// g_inventory.cpp
//
extern qboolean INV_GoodieKeyGive( gentity_t *target );
extern qboolean INV_GoodieKeyTake( gentity_t *target );
extern int INV_GoodieKeyCheck( gentity_t *target );
extern qboolean INV_SecurityKeyGive( gentity_t *target, const char *keyname );
extern void INV_SecurityKeyTake( gentity_t *target, char *keyname );
extern qboolean INV_SecurityKeyCheck( gentity_t *target, char *keyname );
//
// g_team.c
//
qboolean OnSameTeam( gentity_t *ent1, gentity_t *ent2 );
//
// 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 );
//
// NPC_senses.cpp
//
extern void AddSightEvent( gentity_t *owner, vec3_t position, float radius, alertEventLevel_e alertLevel, float addLight=0.0f );
extern void AddSoundEvent( gentity_t *owner, vec3_t position, float radius, alertEventLevel_e alertLevel, qboolean needLOS = qfalse );
extern qboolean G_CheckForDanger( gentity_t *self, int alertEvent );
extern int G_CheckAlertEvents( gentity_t *self, qboolean checkSight, qboolean checkSound, float maxSeeDist, float maxHearDist, int ignoreAlert = -1, qboolean mustHaveOwner = qfalse, int minAlertLevel = AEL_MINOR );
extern qboolean G_CheckForDanger( gentity_t *self, int alertEvent );
extern qboolean G_ClearLOS( gentity_t *self, const vec3_t start, const vec3_t end );
extern qboolean G_ClearLOS( gentity_t *self, gentity_t *ent, const vec3_t end );
extern qboolean G_ClearLOS( gentity_t *self, const vec3_t start, gentity_t *ent );
extern qboolean G_ClearLOS( gentity_t *self, gentity_t *ent );
extern qboolean G_ClearLOS( gentity_t *self, const vec3_t end );
//============================================================================
//Tags
// Reference tags
#define MAX_REFTAGS 128 // Probably more than we'll ever need
#define MAX_REFNAME 32
#define RTF_NONE 0
#define RTF_NAVGOAL 0x00000001
typedef struct reference_tag_s
{
char name[MAX_REFNAME];
vec3_t origin;
vec3_t angles;
int flags; //Just in case
int radius; //For nav goals
} reference_tag_t;
extern void TAG_Init( void );
extern reference_tag_t *TAG_Add( const char *name, const char *owner, vec3_t origin, vec3_t angles, int radius, int flags );
extern int TAG_GetOrigin( const char *owner, const char *name, vec3_t origin );
extern int TAG_GetAngles( const char *owner, const char *name, vec3_t angles );
extern int TAG_GetRadius( const char *owner, const char *name );
extern int TAG_GetFlags( const char *owner, const char *name );
void TAG_ShowTags( int flags );
// Reference tags END
typedef struct pscript_s
{
char *buffer;
long length;
} pscript_t;
typedef std::map < std::string, int, std::less > entlist_t;
typedef std::map < std::string, pscript_t*, std::less > bufferlist_t;
extern char *G_NewString( const char *string );
// some stuff for savegames...
//
void WriteLevel(qboolean qbAutosave);
void ReadLevel(qboolean qbAutosave, qboolean qbLoadTransition);
qboolean GameAllowedToSaveHere(void);
extern qboolean G_ActivateBehavior( gentity_t *ent, int bset );
//Timing information
void TIMER_Clear( void );
void TIMER_Clear( gentity_t *ent );
void TIMER_Save( void );
void TIMER_Load( void );
void TIMER_Set( gentity_t *ent, const char *identifier, int duration );
int TIMER_Get( gentity_t *ent, const char *identifier );
qboolean TIMER_Done( gentity_t *ent, const char *identifier );
qboolean TIMER_Start( gentity_t *self, const char *identifier, int duration );
qboolean TIMER_Done2( gentity_t *ent, const char *identifier, qboolean remove = qfalse );
qboolean TIMER_Exists( gentity_t *ent, const char *identifier );
void TIMER_Remove( gentity_t *ent, const char *identifier );
float NPC_GetHFOVPercentage( vec3_t spot, vec3_t from, vec3_t facing, float hFOV );
float NPC_GetVFOVPercentage( vec3_t spot, vec3_t from, vec3_t facing, float vFOV );
#endif//#ifndef __G_LOCAL_H__