mirror of
https://github.com/blendogames/thirtyflightsofloving.git
synced 2024-11-14 16:40:57 +00:00
95295401a4
Added weapon balancing and tech control cvars to 3ZB2 DLL. Added Vampire and Ammogen techs to 3ZB2 game DLL. Fixed func_door_secret movement bug (when built with origin brush) in Zaero DLL. Fixed armor stacking bug in default Lazarus, missionpack, and Zaero DLLs. Removed unused tech cvars in default Lazarus DLL. Changed parsing of TE_BLASTER_COLORED tempent.
649 lines
12 KiB
C
649 lines
12 KiB
C
|
||
#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 (void)
|
||
{
|
||
FILE *fp;
|
||
qboolean firstflag = false;
|
||
char Buff[MAX_QPATH];
|
||
char top[MAX_QPATH];
|
||
char nextmap[MAX_QPATH];
|
||
int i;
|
||
|
||
if (!maplist->string) return;
|
||
|
||
Com_sprintf (Buff, sizeof(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 )
|
||
{
|
||
Com_strcpy (nextmap, sizeof(nextmap),top);
|
||
goto SETNEXTMAP;
|
||
}
|
||
else goto NONEXTMAP;
|
||
}
|
||
|
||
if (Buff[0] == '\n') continue;
|
||
|
||
// sscanf(Buff, "%s", nextmap);
|
||
if (sscanf(Buff, "%s", nextmap) == EOF) {
|
||
gi.dprintf ("Get_NextMap: invalid mapname '%s'.\n", Buff);
|
||
}
|
||
|
||
if (!firstflag)
|
||
{
|
||
firstflag = true;
|
||
Com_strcpy (top, sizeof(top), nextmap);
|
||
}
|
||
|
||
if (Q_stricmp (level.mapname, nextmap) == 0) break;
|
||
}
|
||
|
||
// search nextmap
|
||
while (1)
|
||
{
|
||
if (fgets( Buff, sizeof(Buff), fp ) == NULL)
|
||
{
|
||
if ( firstflag )
|
||
{
|
||
Com_strcpy (nextmap, sizeof(nextmap) ,top);
|
||
goto SETNEXTMAP;
|
||
}
|
||
else goto NONEXTMAP;
|
||
}
|
||
|
||
if (Buff[0] == '[')
|
||
{
|
||
if ( firstflag )
|
||
{
|
||
Com_strcpy (nextmap, sizeof(nextmap), top);
|
||
goto SETNEXTMAP;
|
||
}
|
||
else goto NONEXTMAP;
|
||
}
|
||
|
||
if (Buff[0] == '\n') continue;
|
||
|
||
// sscanf(Buff, "%s", nextmap);
|
||
if (sscanf(Buff, "%s" ,nextmap) == EOF) {
|
||
gi.dprintf ("Get_NextMap: invalid nextmap '%s'.\n", Buff);
|
||
}
|
||
break;
|
||
}
|
||
SETNEXTMAP:
|
||
|
||
Com_strcpy (level.nextmap, sizeof(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;
|
||
}
|
||
|
||
#if 0
|
||
if ( use_techs->value || (ctf->value && !((int)dmflags->value & DF_CTF_NO_TECH)) )
|
||
CheckNumTechs ();
|
||
#endif
|
||
|
||
//
|
||
// 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 ();
|
||
}
|
||
|