thirtyflightsofloving/3zb2/g_main.c
Knightmare66 eb97af1598 Added sources for Zaero mission pack and 3ZB2 bot DLLs.
Added GetFileList() to game function imports in misison pack DLL game.h.
2020-02-23 16:15:28 -05:00

638 lines
12 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "g_local.h"
#include "bot.h"
game_locals_t game;
level_locals_t level;
game_import_t gi;
game_export_t globals;
spawn_temp_t st;
int sm_meat_index;
int snd_fry;
int meansOfDeath;
edict_t *g_edicts;
cvar_t *deathmatch;
cvar_t *coop;
cvar_t *dmflags;
cvar_t *skill;
cvar_t *fraglimit;
cvar_t *timelimit;
cvar_t *filterban;
//ZOID
cvar_t *capturelimit;
//ZOID
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 *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;
//ponpoko
cvar_t *gamepath;
cvar_t *chedit;
cvar_t *vwep;
cvar_t *maplist;
cvar_t *botlist;
cvar_t *autospawn;
cvar_t *zigmode;
cvar_t *mega_gibs; // Knightmare- Octavian's modified gibs
float spawncycle;
float ctfjob_update;
//ponpoko
cvar_t *turn_rider; // Knightmare added
void SpawnEntities (char *mapname, char *entities, char *spawnpoint);
void ClientThink (edict_t *ent, usercmd_t *cmd);
qboolean ClientConnect (edict_t *ent, char *userinfo, qboolean loadgame);
void ClientUserinfoChanged (edict_t *ent, char *userinfo);
void ClientDisconnect (edict_t *ent);
void ClientBegin (edict_t *ent, qboolean loadgame);
void ClientCommand (edict_t *ent);
void RunEntity (edict_t *ent);
void WriteGame (char *filename);
void ReadGame (char *filename);
void WriteLevel (char *filename);
void ReadLevel (char *filename);
void InitGame (void);
void G_RunFrame (void);
void SetBotFlag1(edict_t *ent); //ƒ`<60>[ƒ€1ÌŠø
void SetBotFlag2(edict_t *ent); //ƒ`<60>[ƒ€2ÌŠø
//===================================================================
/*
=================
GetGameAPI
Returns a pointer to the structure with all entry points
and global variables
=================
*/
void ShutdownGame (void)
{
gi.dprintf ("==== ShutdownGame ====\n");
// Bot_LevelChange();
gi.FreeTags (TAG_LEVEL);
gi.FreeTags (TAG_GAME);
SetBotFlag1(NULL);
SetBotFlag2(NULL);
}
//void Dummy (void) {};
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);
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);
// vsprintf (text, error, argptr);
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);
// vsprintf (text, msg, argptr);
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;
if(!(ent->svflags & SVF_MONSTER))
ClientEndServerFrame (ent);
}
}
/*
=================
GetNextMap
get next map's file name
=================
*/
void Get_NextMap()
{
FILE *fp;
qboolean firstflag = false;
char Buff[MAX_QPATH];
char top[MAX_QPATH];
char nextmap[MAX_QPATH];
int i;
if(!maplist->string) return;
sprintf(Buff,".\\%s\\3ZBMAPS.LST",gamepath->string);
fp = fopen(Buff,"r");
if(fp == NULL) return;
//search section
while(1)
{
if(fgets( Buff, sizeof(Buff), fp ) == NULL) goto NONEXTMAP;
if(Buff[0] != '[') continue;
i = 0;
while(1)
{
if(Buff[i] == ']') Buff[i] = 0;
if(Buff[i] == 0) break;
if(++i >= sizeof(Buff))
{
Buff[i - 1] = 0;
break;
}
}
//compare map section name
if(Q_stricmp (&Buff[1], maplist->string) == 0) break;
}
//search current mapname
while(1)
{
if(fgets( Buff, sizeof(Buff), fp ) == NULL) goto NONEXTMAP;
if(Buff[0] == '[')
{
if( firstflag )
{
strcpy(nextmap,top);
goto SETNEXTMAP;
}
else goto NONEXTMAP;
}
if(Buff[0] == '\n') continue;
sscanf(Buff,"%s",nextmap);
if(!firstflag)
{
firstflag = true;
strcpy(top,nextmap);
}
if(Q_stricmp (level.mapname, nextmap) == 0) break;
}
//search nextmap
while(1)
{
if(fgets( Buff, sizeof(Buff), fp ) == NULL)
{
if( firstflag )
{
strcpy(nextmap,top);
goto SETNEXTMAP;
}
else goto NONEXTMAP;
}
if(Buff[0] == '[')
{
if( firstflag )
{
strcpy(nextmap,top);
goto SETNEXTMAP;
}
else goto NONEXTMAP;
}
if(Buff[0] == '\n') continue;
sscanf(Buff,"%s",nextmap);
break;
}
SETNEXTMAP:
strcpy(level.nextmap,nextmap);
NONEXTMAP:
fclose(fp);
}
/*
=================
EndDMLevel
The timelimit or fraglimit has been exceeded
=================
*/
void EndDMLevel (void)
{
edict_t *ent;
Get_NextMap();
// stay on same level flag
if ((int)dmflags->value & DF_SAME_LEVEL)
{
ent = G_Spawn ();
ent->classname = "target_changelevel";
ent->map = level.mapname;
}
else if (level.nextmap)
{ // go to a specific map
ent = G_Spawn ();
ent->classname = "target_changelevel";
ent->map = level.nextmap;
}
else
{ // search for a changeleve
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
ent = G_Spawn ();
ent->classname = "target_changelevel";
ent->map = level.mapname;
}
}
BeginIntermission (ent);
//PONKO
Bot_LevelChange();
//PONKO
}
/*
=================
CheckNeedPass
=================
*/
void CheckNeedPass (void)
{
int need;
// if password or spectator_password has changed, update needpass
// as needed
if (password->modified || spectator_password->modified)
{
password->modified = spectator_password->modified = false;
need = 0;
if (*password->string && Q_stricmp(password->string, "none"))
need |= 1;
if (*spectator_password->string && Q_stricmp(spectator_password->string, "none"))
need |= 2;
gi.cvar_set("needpass", va("%d", need));
}
}
/*
=================
CheckDMRules
=================
*/
void CheckDMRules (void)
{
int i;
gclient_t *cl;
if (level.intermissiontime)
return;
if (!deathmatch->value)
return;
if (timelimit->value)
{
if (level.time >= timelimit->value*60)
{
gi.bprintf (PRINT_HIGH, "Timelimit hit.\n");
EndDMLevel ();
return;
}
}
// Fix by Bouman- allow capturelimit without fraglimit set
if ( ctf->value && CTFCheckRules() ) {
EndDMLevel ();
return;
}
// end Bouman fix
if (fraglimit->value)
{
//ZOID
/* if (ctf->value) {
if (CTFCheckRules()) {
EndDMLevel ();
}
}*/
//ZOID
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;
}
SetBotFlag1(NULL);
SetBotFlag2(NULL);
//ZOID
CTFInit();
//ZOID
}
/*
================
G_RunFrame
Advances the world by 0.1 seconds
================
*/
void G_InitEdict (edict_t *e);
void G_RunFrame (void)
{
int i,j;
static int ofs;
static float next_fragadd = 0;
edict_t *ent;
vec3_t v,vv;
qboolean haveflag;
// gitem_t *item;
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;
}
//
// Bot Spawning
//
if(SpawnWaitingBots && !level.intermissiontime)
{
if(spawncycle < level.time)
{
Bot_SpawnCall();
spawncycle = level.time + FRAMETIME * 10 + 0.01 * SpawnWaitingBots;
}
}
else
{
if(spawncycle < level.time) spawncycle = level.time + FRAMETIME * 10;
}
//
// treat each object in turn
// even the world gets a chance to think
//
haveflag = false;
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);
}
}
//ctf job assign
if(ctf->value)
{
if(ctfjob_update < level.time)
{
//gi.bprintf(PRINT_HIGH,"Assigned!!!\n");
CTFJobAssign();
ctfjob_update = level.time + FRAMETIME * 2;
}
}
//////////Šø̃XƒRƒAƒ`ƒFƒbƒN
if(zigmode->value == 1)
{
if(next_fragadd < level.time)
{
if(i > 0 && i <= maxclients->value && g_edicts[i].client)
{
if(g_edicts[i].client->pers.inventory[ITEM_INDEX(zflag_item)])
{
zflag_ent = NULL;
haveflag = true;
gi.sound(ent, CHAN_VOICE, gi.soundindex("misc/secret.wav"), 1, ATTN_NORM, 0);
if (!((int)(dmflags->value) & (DF_MODELTEAMS | DF_SKINTEAMS)))
g_edicts[i].client->resp.score += 1;
else
{
//ŠøðŽ<C3B0>ÁÄéƃtƒ‰ƒbƒOð«·
for ( j = 1 ; j <= maxclients->value ; j++)
{
if(g_edicts[j].inuse)
{
if(OnSameTeam(&g_edicts[i],&g_edicts[j]))
g_edicts[j].client->resp.score += 1;
}
}
}
}
}
if(zflag_ent != NULL)
{
if(!zflag_ent->inuse)
{
// item = FindItem("Zig Flag");
SelectSpawnPoint (ent, v, vv);
// VectorCopy (v, ent->s.origin);
if(ZIGDrop_Flag(ent,zflag_item))
{
VectorCopy (v, zflag_ent->s.origin);
}
}
}
}
}
/////////////
if (i > 0 && i <= maxclients->value && !(ent->svflags & SVF_MONSTER))
{
ClientBeginServerFrame (ent);
continue;
}
G_RunEntity (ent);
}
if(next_fragadd < level.time)
{
if(zflag_ent == NULL && !haveflag && !ctf->value
&& zigmode->value == 1 && zigflag_spawn == 2)
{
SelectSpawnPoint (ent, v, vv);
//VectorCopy (v, ent->s.origin);
if(ZIGDrop_Flag(ent,zflag_item))
{
VectorCopy (v, zflag_ent->s.origin);
}
}
next_fragadd = level.time + FRAMETIME * 100;
}
// see if it is time to end a deathmatch
CheckDMRules ();
// see if needpass needs updated
CheckNeedPass ();
// build the playerstate_t structures for all players
ClientEndServerFrames ();
}