421 lines
9.5 KiB
C++
421 lines
9.5 KiB
C++
// Copyright (C) 1997 by Ritual Entertainment, Inc.
|
|
// All rights reserved.
|
|
//
|
|
// This source is may not be distributed and/or modified without
|
|
// expressly written permission by Ritual Entertainment, Inc.
|
|
//
|
|
// DESCRIPTION:
|
|
// Base class for worldspawn objects. This should be subclassed whenever
|
|
// a DLL has new game behaviour that needs to be initialized before any other
|
|
// entities are created, or before any entity thinks each frame. Also controls
|
|
// spawning of clients.
|
|
//
|
|
|
|
#include "g_local.h"
|
|
#include "entity.h"
|
|
#include "scriptmaster.h"
|
|
#include "worldspawn.h"
|
|
#include "surface.h"
|
|
#include "console.h"
|
|
#include "deadbody.h"
|
|
#include "gravpath.h"
|
|
#include "earthquake.h"
|
|
//###
|
|
#include "spritegun.h" // added for spritegun
|
|
#include "checkpoints.h"
|
|
//###
|
|
|
|
extern void CreateMissionComputer( void );
|
|
|
|
WorldPtr world;
|
|
|
|
//### added some options to the worldspawn
|
|
/*****************************************************************************/
|
|
/*SINED worldspawn (0 0 0) ? CINEMATIC x BIKESONLY BODIESFADE
|
|
|
|
Only used for the world.
|
|
"sky" environment map name
|
|
"skyaxis" vector axis for rotating sky
|
|
"skyrotate" speed of rotation in degrees/second
|
|
"soundtrack" the music file to use
|
|
"cdtrack" music cd track number
|
|
"gravity" 800 is default gravity
|
|
"message" text to print at user logon
|
|
"skipthread" thread that is activated to skip this level (if cinematic)
|
|
|
|
"watercolor" specifies the view blend color while in water.
|
|
"wateralpha" specifies the alpha of the view blend while in water.
|
|
"lavacolor" specifies the view blend color while in lava.
|
|
"lavaalpha" specifies the alpha of the view blend while in lava.
|
|
"lightcolor" specifies the view blend color while in light.
|
|
"lightalpha" specifies the alpha of the view blend while in light.
|
|
|
|
"lavadamage" sets the amount of damage laval should do per waterheight level. Default is 10.
|
|
|
|
"cpsounds" sets the script file to get the hoverbike checkpoint sounds from. Default is "global/default_cp_sounds.scr"
|
|
|
|
BIKESONLY all players spawn in hoverbikes and can't get off. If the bike dies, they die.
|
|
BODIESFADE makes dead player bodies fade shortly after dying. Good for big open maps.
|
|
/*****************************************************************************/
|
|
|
|
#define CINEMATIC 1
|
|
//###
|
|
#define BIKESONLY 4
|
|
#define BODIESFADE 8
|
|
//###
|
|
|
|
CLASS_DECLARATION( Entity, World, "worldspawn" );
|
|
|
|
ResponseDef World::Responses[] =
|
|
{
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
World::World()
|
|
{
|
|
const char *text;
|
|
str mapname;
|
|
int i;
|
|
Vector water_color;
|
|
Vector lightvolume_color;
|
|
Vector lava_color;
|
|
Event *ev; //### added for spritegun
|
|
|
|
world = this;
|
|
|
|
setMoveType( MOVETYPE_NONE );
|
|
setSolidType( SOLID_BSP );
|
|
|
|
// world model is always index 1
|
|
edict->s.modelindex = 1;
|
|
model = "*1";
|
|
|
|
// Anything that modifies configstrings, or spawns things is ignored when loading savegames
|
|
if ( LoadingSavegame )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// inform the client that this is deathmatch, and we should
|
|
// draw deathmatch stats. This goes around what the CS_STATUSBAR
|
|
// used to be used for since we moved all HUDS to the client.
|
|
if ( deathmatch->value )
|
|
{
|
|
gi.configstring( CS_STATUSBAR, "DEATHMATCH" );
|
|
}
|
|
else
|
|
{
|
|
gi.configstring( CS_STATUSBAR, "SINGLE_PLAYER" );
|
|
}
|
|
|
|
//
|
|
// see if the level has a soundtrack associated withit
|
|
//
|
|
text = G_GetSpawnArg( "soundtrack" );
|
|
if ( text )
|
|
{
|
|
gi.configstring( CS_SOUNDTRACK, text );
|
|
}
|
|
|
|
text = G_GetSpawnArg( "sky" );
|
|
if ( text )
|
|
{
|
|
gi.configstring( CS_SKY, text );
|
|
}
|
|
else
|
|
{
|
|
gi.configstring( CS_SKY, "sky_" );
|
|
}
|
|
|
|
text = G_GetSpawnArg( "skyrotate" );
|
|
gi.configstring( CS_SKYROTATE, text ? text : "0" );
|
|
|
|
text = G_GetSpawnArg( "skyaxis" );
|
|
gi.configstring( CS_SKYAXIS, text ? text : "0 0 0" );
|
|
|
|
text = G_GetSpawnArg( "cdtrack" );
|
|
gi.configstring( CS_CDTRACK, text ? text : "0" );
|
|
|
|
gi.configstring (CS_MAXCLIENTS, va("%i", (int)(maxclients->value) ) );
|
|
|
|
text = G_GetSpawnArg( "gravity" );
|
|
if ( !text )
|
|
{
|
|
gi.cvar_set( "sv_gravity", "800" );
|
|
}
|
|
else
|
|
{
|
|
gi.cvar_set( "sv_gravity", text );
|
|
}
|
|
|
|
// get skipthread
|
|
skipthread = G_GetStringArg( "skipthread" );
|
|
|
|
// the world takes blast marks and sparks by default
|
|
flags |= FL_BLASTMARK;
|
|
flags |= FL_SPARKS;
|
|
|
|
// Reserve some space for dead bodies
|
|
InitializeBodyQueue();
|
|
|
|
//
|
|
// see if this is a cinematic level
|
|
//
|
|
if ( spawnflags & CINEMATIC )
|
|
{
|
|
level.cinematic = true;
|
|
}
|
|
else
|
|
{
|
|
level.cinematic = false;
|
|
}
|
|
|
|
level.nextmap = G_GetStringArg( "nextmap" );
|
|
|
|
// make some data visible to the server
|
|
text = G_GetSpawnArg( "message" );
|
|
if ( text )
|
|
{
|
|
gi.configstring( CS_NAME, text );
|
|
level.level_name = text;
|
|
}
|
|
else
|
|
{
|
|
level.level_name = level.mapname;
|
|
}
|
|
|
|
// Set up script
|
|
text = G_GetSpawnArg( "script" );
|
|
if ( !text )
|
|
{
|
|
// No script specified. Try using the mapname as the script name
|
|
mapname = "maps/";
|
|
mapname += level.mapname;
|
|
for( i = mapname.length() - 1; i >= 0; i-- )
|
|
{
|
|
if ( mapname[ i ] == '.' )
|
|
{
|
|
mapname[ i ] = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
mapname += ".scr";
|
|
|
|
text = &mapname[ 5 ];
|
|
|
|
// If there isn't a script with the same name as the map, then don't try to load script
|
|
if ( gi.LoadFile( mapname.c_str(), NULL, 0 ) == -1 )
|
|
{
|
|
text = NULL;
|
|
}
|
|
}
|
|
|
|
if ( text )
|
|
{
|
|
gi.dprintf( "Adding script: '%s'\n", text );
|
|
mapname = va( "maps/%s", text );
|
|
|
|
// just set the script, we will start it in G_Spawn
|
|
ScriptLib.SetGameScript( mapname.c_str() );
|
|
}
|
|
|
|
//###
|
|
// read in sprite file after everything's spawned
|
|
ev = new Event("spg_load");
|
|
Spritecontrol.PostEvent(ev, 0.1);
|
|
|
|
// setup checkpoints sounds
|
|
level.cp_sounds_script = G_GetStringArg("cpsounds", "global/default_cp_sounds.scr");
|
|
|
|
//set this here for when there's no checkpoints
|
|
gi.configstring(CS_CHECKPOINTS, "NONE");
|
|
|
|
// init the checkpoint counter
|
|
level.cp_anyorder = false;
|
|
level.cp_num = 0;
|
|
|
|
if(spawnflags & BIKESONLY)
|
|
{
|
|
level.bikesonly = true;
|
|
}
|
|
else
|
|
{
|
|
level.bikesonly = false;
|
|
}
|
|
|
|
if(spawnflags & BODIESFADE)
|
|
{
|
|
level.bodiesfade = true;
|
|
}
|
|
else
|
|
{
|
|
level.bodiesfade = false;
|
|
}
|
|
|
|
level.lavadamage = G_GetIntArg("lavadamage", 10);
|
|
|
|
// remove any time limit offset
|
|
reset_timeofs = 0;
|
|
//###
|
|
|
|
// Set the color for the blends.
|
|
water_color = G_GetVectorArg("watercolor",Vector(0,0,1));
|
|
level.water_alpha = G_GetFloatArg("wateralpha",0.1);
|
|
|
|
lightvolume_color = G_GetVectorArg("lightcolor",Vector(1,1,1));
|
|
level.lightvolume_alpha = G_GetFloatArg("lightalpha",0.5);
|
|
|
|
lava_color = G_GetVectorArg("lavacolor",Vector(1.0,0.3,0));
|
|
level.lava_alpha = G_GetFloatArg("lavaalpha",0.6);
|
|
|
|
level.water_color = water_color;
|
|
level.lightvolume_color = lightvolume_color;
|
|
level.lava_color = lava_color;
|
|
|
|
//
|
|
// reset the earthquake
|
|
//
|
|
level.earthquake = 0;
|
|
}
|
|
|
|
TargetList * World::GetTargetList( str &targetname )
|
|
{
|
|
TargetList * targetlist;
|
|
int i;
|
|
|
|
for( i = 1; i <= targetList.NumObjects(); i++ )
|
|
{
|
|
targetlist = targetList.ObjectAt( i );
|
|
if ( targetname == targetlist->targetname)
|
|
return targetlist;
|
|
}
|
|
targetlist = new TargetList( targetname );
|
|
targetList.AddObject( targetlist );
|
|
return targetlist;
|
|
}
|
|
|
|
void World::AddTargetEntity( str &targetname, Entity * ent )
|
|
{
|
|
TargetList * targetlist;
|
|
|
|
targetlist = GetTargetList( targetname );
|
|
targetlist->AddEntity( ent );
|
|
}
|
|
|
|
void World::RemoveTargetEntity( str &targetname, Entity * ent )
|
|
{
|
|
TargetList * targetlist;
|
|
|
|
targetlist = GetTargetList( targetname );
|
|
targetlist->RemoveEntity( ent );
|
|
}
|
|
|
|
Entity * World::GetNextEntity( str &targetname, Entity * ent )
|
|
{
|
|
TargetList * targetlist;
|
|
|
|
targetlist = GetTargetList( targetname );
|
|
return targetlist->GetNextEntity( ent );
|
|
}
|
|
|
|
//### added so I can trigger stuff easily from code
|
|
void World::ActivateTarget(str &targetname)
|
|
{
|
|
TargetList * targetlist;
|
|
Event *event;
|
|
Entity *ent;
|
|
int i, num;
|
|
|
|
targetlist = GetTargetList( targetname );
|
|
num = targetlist->list.NumObjects();
|
|
for ( i = 1; i <= num; i++ )
|
|
{
|
|
ent = targetlist->list.ObjectAt( i );
|
|
|
|
assert( ent );
|
|
|
|
event = new Event( EV_Activate );
|
|
event->AddEntity( world );
|
|
ent->ProcessEvent( event );
|
|
}
|
|
}
|
|
//###
|
|
|
|
World::~World()
|
|
{
|
|
FreeTargetList();
|
|
}
|
|
|
|
void World::FreeTargetList
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
int i;
|
|
int num;
|
|
|
|
num = targetList.NumObjects();
|
|
for( i = 1; i <= num; i++ )
|
|
{
|
|
delete targetList.ObjectAt( i );
|
|
}
|
|
|
|
targetList.FreeObjectList();
|
|
}
|
|
|
|
//
|
|
// List stuff for targets
|
|
//
|
|
|
|
CLASS_DECLARATION( Class, TargetList, NULL );
|
|
|
|
ResponseDef TargetList::Responses[] =
|
|
{
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
TargetList::TargetList()
|
|
{
|
|
}
|
|
|
|
TargetList::TargetList( str &tname )
|
|
{
|
|
targetname = tname;
|
|
}
|
|
|
|
TargetList::~TargetList()
|
|
{
|
|
}
|
|
|
|
void TargetList::AddEntity( Entity * ent )
|
|
{
|
|
if ( !list.ObjectInList( ent ) )
|
|
{
|
|
list.AddObject( ent );
|
|
}
|
|
}
|
|
|
|
void TargetList::RemoveEntity( Entity * ent )
|
|
{
|
|
if ( list.ObjectInList( ent ) )
|
|
{
|
|
list.RemoveObject( ent );
|
|
}
|
|
}
|
|
|
|
Entity * TargetList::GetNextEntity( Entity * ent )
|
|
{
|
|
int index;
|
|
|
|
index = 0;
|
|
if ( ent )
|
|
index = list.IndexOfObject( ent );
|
|
index++;
|
|
if ( index > list.NumObjects() )
|
|
return NULL;
|
|
else
|
|
return list.ObjectAt( index );
|
|
}
|
|
|