thirtyflightsofloving/missionpack/g_main.c
Knightmare66 0d4e872ce9 Added LMCTF / LM Escape plasma rifle to missionpack DLL.
Added plasma guards (monster_soldier_plasma_re and monster_soldier_plasma_sp) from LM Escape to missionpack DLL.
Added Zaero items/weapons to missionpack DLL.
Added support for Zaero doors  to missionpack DLL.
Fixed crash caused by killtargeting sentien (laser edict not freed) in missionpack DLL.
Fixed bug with broken Rogue turrets in missionpack DLL.
Fixed crash in g_combat.c->M_ReactToDamage() caused by attacker with NULL classname in missionpack DLL.
2020-08-09 02:45:19 -04:00

578 lines
12 KiB
C

#include "./g_local.h"
game_locals_t game;
level_locals_t level;
game_import_t gi;
game_export_t globals;
spawn_temp_t st;
//int _stdcall LibMain (int a, int b, int c) {}
int sm_meat_index;
int snd_fry;
int meansOfDeath;
edict_t *g_edicts;
cvar_t *deathmatch;
cvar_t *coop;
cvar_t *dmflags;
cvar_t *zdmflags; // Zaero added
cvar_t *skill;
cvar_t *fraglimit;
cvar_t *timelimit;
cvar_t *password;
cvar_t *spectator_password;
cvar_t *maxclients;
cvar_t *maxspectators;
cvar_t *maxentities;
cvar_t *g_select_empty;
cvar_t *dedicated;
cvar_t *filterban;
cvar_t *sv_maxvelocity;
cvar_t *sv_gravity;
cvar_t *sv_rollspeed;
cvar_t *sv_rollangle;
cvar_t *gun_x;
cvar_t *gun_y;
cvar_t *gun_z;
cvar_t *run_pitch;
cvar_t *run_roll;
cvar_t *bob_up;
cvar_t *bob_pitch;
cvar_t *bob_roll;
cvar_t *sv_cheats;
cvar_t *flood_msgs;
cvar_t *flood_persecond;
cvar_t *flood_waitdelay;
cvar_t *sv_maplist;
cvar_t *actorchicken;
cvar_t *actorjump;
cvar_t *actorscram;
cvar_t *alert_sounds;
cvar_t *allow_download;
cvar_t *allow_fog; // Set to 0 for no fog
// set to 0 to bypass target_changelevel clear inventory flag
// because some user maps have this erroneously set
cvar_t *allow_clear_inventory;
cvar_t *bounce_bounce;
cvar_t *bounce_minv;
cvar_t *cd_loopcount;
cvar_t *cl_gun;
cvar_t *cl_thirdperson; // Knightmare added
cvar_t *corpse_fade;
cvar_t *corpse_fadetime;
cvar_t *crosshair;
cvar_t *crossh;
cvar_t *developer;
cvar_t *fmod_nomusic;
cvar_t *footstep_sounds;
cvar_t *fov;
cvar_t *gl_clear;
cvar_t *gl_driver;
cvar_t *gl_driver_fog;
cvar_t *hand;
cvar_t *jetpack_weenie;
cvar_t *joy_pitchsensitivity;
cvar_t *joy_yawsensitivity;
cvar_t *jump_kick;
cvar_t *lazarus_cd_loop;
cvar_t *lazarus_cl_gun;
cvar_t *lazarus_crosshair;
cvar_t *lazarus_gl_clear;
cvar_t *lazarus_joyp;
cvar_t *lazarus_joyy;
cvar_t *lazarus_pitch;
cvar_t *lazarus_yaw;
cvar_t *lights;
cvar_t *lightsmin;
cvar_t *m_pitch;
cvar_t *m_yaw;
cvar_t *monsterjump;
cvar_t *packet_fmod_playback;
cvar_t *readout;
cvar_t *rocket_strafe;
cvar_t *rotate_distance;
cvar_t *s_primary;
cvar_t *shift_distance;
cvar_t *sv_maxgibs;
cvar_t *turn_rider;
cvar_t *vid_ref;
cvar_t *zoomrate;
cvar_t *zoomsnap;
cvar_t *tpp;
cvar_t *sv_stopspeed; //PGM (this was a define in g_phys.c)
cvar_t *sv_step_fraction; // Knightmare- this was a define in p_view.c
//ROGUE cvars
cvar_t *g_showlogic;
cvar_t *gamerules;
cvar_t *huntercam;
cvar_t *strong_mines;
cvar_t *randomrespawn;
//ROGUE
void SpawnEntities (char *mapname, char *entities, char *spawnpoint);
void ClientThink (edict_t *ent, usercmd_t *cmd);
qboolean ClientConnect (edict_t *ent, char *userinfo);
void ClientUserinfoChanged (edict_t *ent, char *userinfo);
void ClientDisconnect (edict_t *ent);
void ClientBegin (edict_t *ent);
void ClientCommand (edict_t *ent);
void RunEntity (edict_t *ent);
void WriteGame (char *filename, qboolean autosave);
void ReadGame (char *filename);
void WriteLevel (char *filename);
void ReadLevel (char *filename);
void InitGame (void);
void G_RunFrame (void);
//===================================================================
void ShutdownGame (void)
{
gi.dprintf ("==== ShutdownGame ====\n");
if(!deathmatch->value && !coop->value)
{
#ifndef KMQUAKE2_ENGINE_MOD // engine has zoom autosensitivity
gi.cvar_forceset("m_pitch", va("%f",lazarus_pitch->value));
#endif
//gi.cvar_forceset("cd_loopcount", va("%d",lazarus_cd_loop->value));
//gi.cvar_forceset("gl_clear", va("%d", lazarus_gl_clear->value));
}
// Lazarus: Turn off fog if it's on
if (!dedicated->value) {
// Fog_Off (true);
Fog_Off_Global ();
}
// and shut down FMOD
FMOD_Shutdown();
gi.FreeTags (TAG_LEVEL);
gi.FreeTags (TAG_GAME);
}
game_import_t RealFunc;
int max_modelindex;
int max_soundindex;
int Debug_Modelindex (char *name)
{
int modelnum;
modelnum = RealFunc.modelindex(name);
if(modelnum > max_modelindex)
{
gi.dprintf("Model %03d %s\n",modelnum,name);
max_modelindex = modelnum;
}
return modelnum;
}
int Debug_Soundindex (char *name)
{
int soundnum;
soundnum = RealFunc.soundindex(name);
if(soundnum > max_soundindex)
{
gi.dprintf("Sound %03d %s\n",soundnum,name);
max_soundindex = soundnum;
}
return soundnum;
}
/*
=================
GetGameAPI
Returns a pointer to the structure with all entry points
and global variables
=================
*/
game_export_t *GetGameAPI (game_import_t *import)
{
gi = *import;
globals.apiversion = GAME_API_VERSION;
globals.Init = InitGame;
globals.Shutdown = ShutdownGame;
globals.SpawnEntities = SpawnEntities;
globals.WriteGame = WriteGame;
globals.ReadGame = ReadGame;
globals.WriteLevel = WriteLevel;
globals.ReadLevel = ReadLevel;
globals.ClientThink = ClientThink;
globals.ClientConnect = ClientConnect;
globals.ClientUserinfoChanged = ClientUserinfoChanged;
globals.ClientDisconnect = ClientDisconnect;
globals.ClientBegin = ClientBegin;
globals.ClientCommand = ClientCommand;
globals.RunFrame = G_RunFrame;
globals.ServerCommand = ServerCommand;
globals.edict_size = sizeof(edict_t);
gl_driver = gi.cvar ("gl_driver", "", 0);
vid_ref = gi.cvar ("vid_ref", "", 0);
gl_driver_fog = gi.cvar ("gl_driver_fog", "opengl32", CVAR_NOSET | CVAR_ARCHIVE);
Fog_Init();
developer = gi.cvar("developer", "0", CVAR_SERVERINFO);
readout = gi.cvar("readout", "0", CVAR_SERVERINFO);
if(readout->value)
{
max_modelindex = 0;
max_soundindex = 0;
RealFunc.modelindex = gi.modelindex;
gi.modelindex = Debug_Modelindex;
RealFunc.soundindex = gi.soundindex;
gi.soundindex = Debug_Soundindex;
}
return &globals;
}
#ifndef GAME_HARD_LINKED
// this is only here so the functions in q_shared.c and q_shwin.c can link
void Sys_Error (char *error, ...)
{
va_list argptr;
char text[1024];
va_start (argptr, error);
Q_vsnprintf (text, sizeof(text), error, argptr);
va_end (argptr);
gi.error (ERR_FATAL, "%s", text);
}
void Com_Printf (char *msg, ...)
{
va_list argptr;
char text[1024];
va_start (argptr, msg);
Q_vsnprintf (text, sizeof(text), msg, argptr);
va_end (argptr);
gi.dprintf ("%s", text);
}
#endif
//======================================================================
/*
=================
ClientEndServerFrames
=================
*/
void ClientEndServerFrames (void)
{
int i;
edict_t *ent;
// calc the player views now that all pushing
// and damage has been added
for (i=0 ; i<maxclients->value ; i++)
{
ent = g_edicts + 1 + i;
if (!ent->inuse || !ent->client)
continue;
ClientEndServerFrame (ent);
}
// reflection stuff -- modified from psychospaz' original code
if (level.num_reflectors)
{
ent = &g_edicts[0];
for (i=0 ; i<globals.num_edicts ; i++, ent++) // pointers, not as slow as you think
{
if (!ent->inuse)
continue;
if (!ent->s.modelindex)
continue;
// if (ent->s.effects & EF_ROTATE)
// continue;
if (ent->flags & FL_REFLECT)
continue;
if (!ent->client && (ent->svflags & SVF_NOCLIENT))
continue;
if (ent->client && !ent->client->chaseactive && (ent->svflags & SVF_NOCLIENT) )
continue;
if ( (ent->svflags & SVF_MONSTER) && (ent->solid != SOLID_BBOX) )
continue;
if ( (ent->solid == SOLID_BSP) && (ent->movetype != MOVETYPE_PUSHABLE))
continue;
if (ent->client && (ent->client->resp.spectator || (ent->health <= 0) || (ent->deadflag == DEAD_DEAD)) )
continue;
if (ent->moreflags & FL2_DO_NOT_REFLECT) // Knightmare- don't reflect flagged entities
continue;
AddReflection(ent);
}
}
}
/*
=================
CreateTargetChangeLevel
Returns the created target changelevel
=================
*/
edict_t *CreateTargetChangeLevel(char *map)
{
edict_t *ent;
ent = G_Spawn ();
ent->classname = "target_changelevel";
Com_sprintf(level.nextmap, sizeof(level.nextmap), "%s", map);
ent->map = level.nextmap;
ent->spawnflags2 = 0; // Zaero added
return ent;
}
/*
=================
EndDMLevel
The timelimit or fraglimit has been exceeded
=================
*/
void EndDMLevel (void)
{
edict_t *ent;
char *s, *t, *f;
static const char *seps = " ,\n\r";
// stay on same level flag
if ((int)dmflags->value & DF_SAME_LEVEL)
{
BeginIntermission (CreateTargetChangeLevel (level.mapname) );
return;
}
// see if it's in the map list
if (*sv_maplist->string) {
s = strdup(sv_maplist->string);
f = NULL;
t = strtok(s, seps);
while (t != NULL) {
if (Q_stricmp(t, level.mapname) == 0) {
// it's in the list, go to the next one
t = strtok(NULL, seps);
if (t == NULL) { // end of list, go to first one
if (f == NULL) // there isn't a first one, same level
BeginIntermission (CreateTargetChangeLevel (level.mapname) );
else
BeginIntermission (CreateTargetChangeLevel (f) );
} else
BeginIntermission (CreateTargetChangeLevel (t) );
free(s);
return;
}
if (!f)
f = t;
t = strtok(NULL, seps);
}
free(s);
}
if (level.nextmap[0]) // go to a specific map
BeginIntermission (CreateTargetChangeLevel (level.nextmap) );
else { // search for a changelevel
ent = G_Find (NULL, FOFS(classname), "target_changelevel");
if (!ent)
{ // the map designer didn't include a changelevel,
// so create a fake ent that goes back to the same level
BeginIntermission (CreateTargetChangeLevel (level.mapname) );
return;
}
BeginIntermission (ent);
}
}
/*
=================
CheckDMRules
=================
*/
void CheckDMRules (void)
{
int i;
gclient_t *cl;
if (level.intermissiontime)
return;
if (!deathmatch->value)
return;
//=======
//ROGUE
if (gamerules && gamerules->value && DMGame.CheckDMRules)
{
if(DMGame.CheckDMRules())
return;
}
//ROGUE
//=======
if (timelimit->value)
{
if (level.time >= timelimit->value*60)
{
gi.bprintf (PRINT_HIGH, "Timelimit hit.\n");
EndDMLevel ();
return;
}
}
if (fraglimit->value)
{
for (i=0 ; i<maxclients->value ; i++)
{
cl = game.clients + i;
if (!g_edicts[i+1].inuse)
continue;
if (cl->resp.score >= fraglimit->value)
{
gi.bprintf (PRINT_HIGH, "Fraglimit hit.\n");
EndDMLevel ();
return;
}
}
}
}
/*
=============
ExitLevel
=============
*/
void ExitLevel (void)
{
int i;
edict_t *ent;
char command [256];
Com_sprintf (command, sizeof(command), "gamemap \"%s\"\n", level.changemap);
gi.AddCommandString (command);
level.changemap = NULL;
level.exitintermission = 0;
level.intermissiontime = 0;
ClientEndServerFrames ();
// clear some things before going to next level
for (i=0 ; i<maxclients->value ; i++)
{
ent = g_edicts + 1 + i;
if (!ent->inuse)
continue;
if (ent->health > ent->client->pers.max_health)
ent->health = ent->client->pers.max_health;
}
// mxd added
gibsthisframe = 0;
lastgibframe = 0;
}
/*
================
G_RunFrame
Advances the world by 0.1 seconds
================
*/
void G_RunFrame (void)
{
int i;
edict_t *ent;
// added stasis generator support
if(level.freeze)
{
level.freezeframes++;
if(level.freezeframes >= sk_stasis_time->value*10) // was 300
level.freeze = false;
}
else
level.framenum++;
level.time = level.framenum*FRAMETIME;
// choose a client for monsters to target this frame
AI_SetSightClient ();
// exit intermissions
if (level.exitintermission)
{
ExitLevel ();
return;
}
//
// treat each object in turn
// even the world gets a chance to think
//
ent = &g_edicts[0];
for (i=0 ; i<globals.num_edicts ; i++, ent++)
{
if (!ent->inuse)
continue;
level.current_entity = ent;
VectorCopy (ent->s.origin, ent->s.old_origin);
// if the ground entity moved, make sure we are still on it
if ((ent->groundentity) && (ent->groundentity->linkcount != ent->groundentity_linkcount))
{
ent->groundentity = NULL;
if ( !(ent->flags & (FL_SWIM|FL_FLY)) && (ent->svflags & SVF_MONSTER) )
{
M_CheckGround (ent);
}
}
if (i > 0 && i <= maxclients->value)
{
ClientBeginServerFrame (ent);
continue;
}
G_RunEntity (ent);
}
// FMOD stuff:
if ( (level.num_3D_sounds > 0) && (game.maxclients == 1))
FMOD_UpdateListenerPos();
// see if it is time to end a deathmatch
CheckDMRules ();
// build the playerstate_t structures for all players
ClientEndServerFrames ();
}