mirror of
https://github.com/electronicarts/CnC_Renegade.git
synced 2025-12-15 23:21:40 -05:00
Initial commit of Command & Conquer Renegade source code.
This commit is contained in:
562
Code/Combat/scriptzone.cpp
Normal file
562
Code/Combat/scriptzone.cpp
Normal file
@@ -0,0 +1,562 @@
|
||||
/*
|
||||
** Command & Conquer Renegade(tm)
|
||||
** Copyright 2025 Electronic Arts Inc.
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/***********************************************************************************************
|
||||
*** Confidential - Westwood Studios ***
|
||||
***********************************************************************************************
|
||||
* *
|
||||
* Project Name : Commando *
|
||||
* *
|
||||
* $Archive:: /Commando/Code/Combat/scriptzone.cpp $*
|
||||
* *
|
||||
* $Author:: Byon_g $*
|
||||
* *
|
||||
* $Modtime:: 1/18/02 10:44a $*
|
||||
* *
|
||||
* $Revision:: 18 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#include "scriptzone.h"
|
||||
#include "gameobjmanager.h"
|
||||
#include "scripts.h"
|
||||
#include "colmath.h"
|
||||
#include "colmathinlines.h"
|
||||
#include "debug.h"
|
||||
#include "persistfactory.h"
|
||||
#include "combatchunkid.h"
|
||||
#include "wwhack.h"
|
||||
#include "simpledefinitionfactory.h"
|
||||
#include "combat.h"
|
||||
#include "smartgameobj.h"
|
||||
#include "playertype.h"
|
||||
#include "wwprofile.h"
|
||||
#include "pscene.h"
|
||||
#include "phys.h"
|
||||
#include "soldier.h"
|
||||
|
||||
/*
|
||||
** ScriptZoneGameObjDef
|
||||
*/
|
||||
DECLARE_FORCE_LINK( Zone )
|
||||
|
||||
/*
|
||||
** Namespaces
|
||||
*/
|
||||
using namespace ZoneConstants;
|
||||
|
||||
/*
|
||||
** Constants
|
||||
*/
|
||||
static const char * ZONE_TYPE_NAMES[TYPE_COUNT] =
|
||||
{
|
||||
"Default",
|
||||
"Capture The Flag",
|
||||
"Vehicle Construction",
|
||||
"Vehicle Repair",
|
||||
"Tiberium Field",
|
||||
"Beacon",
|
||||
"GDI Tiberium Field",
|
||||
"NOD Tiberium Field",
|
||||
};
|
||||
|
||||
/*
|
||||
** Editable and Save/Load system stuff
|
||||
*/
|
||||
SimplePersistFactoryClass<ScriptZoneGameObjDef, CHUNKID_GAME_OBJECT_DEF_SCRIPT_ZONE> _ScriptZoneGameObjDefPersistFactory;
|
||||
|
||||
DECLARE_DEFINITION_FACTORY(ScriptZoneGameObjDef, CLASSID_GAME_OBJECT_DEF_SCRIPT_ZONE, "Script Zone") _ScriptZoneGameObjDefDefFactory;
|
||||
|
||||
ScriptZoneGameObjDef::ScriptZoneGameObjDef( void ) :
|
||||
Color( 0, 0.7F, 0 ),
|
||||
CheckStarsOnly( true ),
|
||||
ZoneType( TYPE_DEFAULT ),
|
||||
IsEnvironmentZone( false )
|
||||
{
|
||||
EDITABLE_PARAM( ScriptZoneGameObjDef, ParameterClass::TYPE_COLOR, Color );
|
||||
EDITABLE_PARAM( ScriptZoneGameObjDef, ParameterClass::TYPE_BOOL, CheckStarsOnly );
|
||||
EDITABLE_PARAM( ScriptZoneGameObjDef, ParameterClass::TYPE_BOOL, IsEnvironmentZone );
|
||||
|
||||
//
|
||||
// Configure the zone type parameter
|
||||
//
|
||||
#ifdef PARAM_EDITING_ON
|
||||
EnumParameterClass *zone_type_param = new EnumParameterClass( (int*)&ZoneType );
|
||||
zone_type_param->Set_Name( "Zone Type" );
|
||||
for ( int index = 0; index < TYPE_COUNT; index++ ) {
|
||||
zone_type_param->Add_Value( ZONE_TYPE_NAMES[index], index );
|
||||
}
|
||||
GENERIC_EDITABLE_PARAM(ScriptZoneGameObjDef,zone_type_param);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
uint32 ScriptZoneGameObjDef::Get_Class_ID (void) const
|
||||
{
|
||||
return CLASSID_GAME_OBJECT_DEF_SCRIPT_ZONE;
|
||||
}
|
||||
|
||||
PersistClass * ScriptZoneGameObjDef::Create( void ) const
|
||||
{
|
||||
ScriptZoneGameObj * obj = new ScriptZoneGameObj;
|
||||
obj->Init( *this );
|
||||
return obj;
|
||||
}
|
||||
|
||||
enum {
|
||||
XXXCHUNKID_DEF_PARENT_OLD = 1111991132,
|
||||
CHUNKID_DEF_VARIABLES,
|
||||
CHUNKID_DEF_PARENT,
|
||||
|
||||
MICROCHUNKID_DEF_IS_CTF_ZONE = 1,
|
||||
MICROCHUNKID_DEF_ZONE_COLOR,
|
||||
MICROCHUNKID_DEF_CHECK_STARS_ONLY,
|
||||
MICROCHUNKID_DEF_ZONE_TYPE,
|
||||
MICROCHUNKID_DEF_IS_ENVIRONMENT_ZONE,
|
||||
|
||||
};
|
||||
|
||||
bool ScriptZoneGameObjDef::Save( ChunkSaveClass & csave )
|
||||
{
|
||||
csave.Begin_Chunk( CHUNKID_DEF_PARENT );
|
||||
ScriptableGameObjDef::Save( csave );
|
||||
csave.End_Chunk();
|
||||
|
||||
csave.Begin_Chunk( CHUNKID_DEF_VARIABLES );
|
||||
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_ZONE_COLOR, Color );
|
||||
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_CHECK_STARS_ONLY, CheckStarsOnly );
|
||||
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_ZONE_TYPE, ZoneType );
|
||||
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_DEF_IS_ENVIRONMENT_ZONE, IsEnvironmentZone );
|
||||
csave.End_Chunk();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScriptZoneGameObjDef::Load( ChunkLoadClass &cload )
|
||||
{
|
||||
while (cload.Open_Chunk()) {
|
||||
switch(cload.Cur_Chunk_ID()) {
|
||||
|
||||
case CHUNKID_DEF_PARENT:
|
||||
ScriptableGameObjDef::Load( cload );
|
||||
break;
|
||||
|
||||
case CHUNKID_DEF_VARIABLES:
|
||||
while (cload.Open_Micro_Chunk()) {
|
||||
switch(cload.Cur_Micro_Chunk_ID()) {
|
||||
READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_ZONE_COLOR, Color );
|
||||
READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_CHECK_STARS_ONLY, CheckStarsOnly );
|
||||
READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_ZONE_TYPE, ZoneType );
|
||||
READ_MICRO_CHUNK( cload, MICROCHUNKID_DEF_IS_ENVIRONMENT_ZONE, IsEnvironmentZone );
|
||||
|
||||
default:
|
||||
Debug_Say(( "Unrecognized ZoneDef Variable chunkID\n" ));
|
||||
break;
|
||||
|
||||
}
|
||||
cload.Close_Micro_Chunk();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
Debug_Say(( "Unrecognized ZoneDef chunkID\n" ));
|
||||
break;
|
||||
|
||||
}
|
||||
cload.Close_Chunk();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
const PersistFactoryClass & ScriptZoneGameObjDef::Get_Factory (void) const
|
||||
{
|
||||
return _ScriptZoneGameObjDefPersistFactory;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** ScriptZoneGameObj
|
||||
*/
|
||||
SimplePersistFactoryClass<ScriptZoneGameObj, CHUNKID_GAME_OBJECT_SCRIPT_ZONE> _ScriptZoneGameObjPersistFactory;
|
||||
|
||||
ScriptZoneGameObj::ScriptZoneGameObj( void ) :
|
||||
PlayerType( PLAYERTYPE_NEUTRAL )
|
||||
{
|
||||
}
|
||||
|
||||
ScriptZoneGameObj::~ScriptZoneGameObj( void )
|
||||
{
|
||||
GameObjReference * ref;
|
||||
while ( (ref = InsideList.Remove_Head() ) != NULL ) {
|
||||
*ref = NULL;
|
||||
delete ref;
|
||||
}
|
||||
}
|
||||
|
||||
const PersistFactoryClass & ScriptZoneGameObj::Get_Factory (void) const
|
||||
{
|
||||
return _ScriptZoneGameObjPersistFactory;
|
||||
}
|
||||
|
||||
/*
|
||||
**
|
||||
*/
|
||||
void ScriptZoneGameObj::Init( void )
|
||||
{
|
||||
Init( Get_Definition() );
|
||||
}
|
||||
|
||||
void ScriptZoneGameObj::Init( const ScriptZoneGameObjDef & definition )
|
||||
{
|
||||
ScriptableGameObj::Init( definition );
|
||||
}
|
||||
|
||||
const ScriptZoneGameObjDef & ScriptZoneGameObj::Get_Definition( void ) const
|
||||
{
|
||||
return (const ScriptZoneGameObjDef &)BaseGameObj::Get_Definition();
|
||||
}
|
||||
|
||||
/*
|
||||
** ScriptZoneGameObj Save and Load
|
||||
*/
|
||||
enum {
|
||||
CHUNKID_PARENT_OLD = 922991806,
|
||||
CHUNKID_VARIABLES,
|
||||
CHUNKID_INSIDE_LIST,
|
||||
CHUNKID_INSIDE_LIST_ENTRY,
|
||||
CHUNKID_PARENT,
|
||||
|
||||
MICROCHUNKID_BOUNDING_BOX = 1,
|
||||
MICROCHUNKID_PLAYER_TYPE,
|
||||
};
|
||||
|
||||
bool ScriptZoneGameObj::Save( ChunkSaveClass & csave )
|
||||
{
|
||||
csave.Begin_Chunk( CHUNKID_PARENT );
|
||||
ScriptableGameObj::Save( csave );
|
||||
csave.End_Chunk();
|
||||
|
||||
csave.Begin_Chunk( CHUNKID_VARIABLES );
|
||||
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_BOUNDING_BOX, BoundingBox );
|
||||
WRITE_MICRO_CHUNK( csave, MICROCHUNKID_PLAYER_TYPE, PlayerType );
|
||||
csave.End_Chunk();
|
||||
|
||||
csave.Begin_Chunk( CHUNKID_INSIDE_LIST );
|
||||
SLNode<GameObjReference> *pobjrefnode;
|
||||
for ( pobjrefnode = InsideList.Head(); pobjrefnode; pobjrefnode = pobjrefnode->Next() ) {
|
||||
GameObjReference *ref = pobjrefnode->Data();
|
||||
if ( *ref != NULL ) {
|
||||
csave.Begin_Chunk( CHUNKID_INSIDE_LIST_ENTRY );
|
||||
ref->Save( csave );
|
||||
csave.End_Chunk();
|
||||
}
|
||||
}
|
||||
|
||||
csave.End_Chunk();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool ScriptZoneGameObj::Load( ChunkLoadClass &cload )
|
||||
{
|
||||
while (cload.Open_Chunk()) {
|
||||
switch(cload.Cur_Chunk_ID()) {
|
||||
|
||||
case CHUNKID_PARENT:
|
||||
ScriptableGameObj::Load( cload );
|
||||
break;
|
||||
|
||||
case CHUNKID_VARIABLES:
|
||||
while (cload.Open_Micro_Chunk()) {
|
||||
switch(cload.Cur_Micro_Chunk_ID()) {
|
||||
READ_MICRO_CHUNK( cload, MICROCHUNKID_BOUNDING_BOX, BoundingBox );
|
||||
READ_MICRO_CHUNK( cload, MICROCHUNKID_PLAYER_TYPE, PlayerType );
|
||||
default:
|
||||
Debug_Say(( "Unrecognized ScriptZoneGameObj Variable chunkID\n" ));
|
||||
break;
|
||||
}
|
||||
cload.Close_Micro_Chunk();
|
||||
}
|
||||
break;
|
||||
|
||||
case CHUNKID_INSIDE_LIST:
|
||||
WWASSERT( InsideList.Get_Count()== 0 );
|
||||
while (cload.Open_Chunk()) {
|
||||
WWASSERT( cload.Cur_Chunk_ID() == CHUNKID_INSIDE_LIST_ENTRY );
|
||||
GameObjReference * ref = new GameObjReference;
|
||||
ref->Load( cload );
|
||||
InsideList.Add_Head( ref );
|
||||
cload.Close_Chunk();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
Debug_Say(( "Unrecognized ScriptZoneGameObj chunkID\n" ));
|
||||
break;
|
||||
|
||||
}
|
||||
cload.Close_Chunk();
|
||||
}
|
||||
|
||||
// Legacy Fix
|
||||
switch( PlayerType ) {
|
||||
case 2: PlayerType = PLAYERTYPE_NEUTRAL; break; // Remap TEAM2
|
||||
case 3: PlayerType = PLAYERTYPE_NEUTRAL; break; // Remap TEAM3
|
||||
case 4: PlayerType = PLAYERTYPE_NOD; break; // Remap NOD
|
||||
case 5: PlayerType = PLAYERTYPE_GDI; break; // Remap GDI
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
**
|
||||
*/
|
||||
void ScriptZoneGameObj::Think()
|
||||
{
|
||||
ScriptableGameObj::Think();
|
||||
|
||||
if ( Get_Observers().Count == 0 && Get_Definition().ZoneType != TYPE_CTF ) {
|
||||
return;
|
||||
}
|
||||
|
||||
WWPROFILE( "ScriptZone Think" );
|
||||
|
||||
// check current objects for exiting
|
||||
SLNode<GameObjReference> *pobjrefnode;
|
||||
for ( pobjrefnode = InsideList.Head(); pobjrefnode; ) {
|
||||
SmartGameObj * obj = (SmartGameObj*)pobjrefnode->Data()->Get_Ptr();
|
||||
|
||||
SLNode<GameObjReference> * next = pobjrefnode->Next();
|
||||
|
||||
if ( obj == NULL ) {
|
||||
Debug_Say(( "Object died inside me\n" ));
|
||||
GameObjReference * ref = pobjrefnode->Data();
|
||||
InsideList.Remove( ref );
|
||||
*ref = NULL;
|
||||
delete ref;
|
||||
} else if ( !Inside_Me( obj ) ) {
|
||||
|
||||
const GameObjObserverList & observer_list = Get_Observers();
|
||||
for( int index = 0; index < observer_list.Count(); index++ ) {
|
||||
observer_list[ index ]->Exited( this, (PhysicalGameObj*)obj );
|
||||
}
|
||||
|
||||
GameObjReference * ref = pobjrefnode->Data();
|
||||
InsideList.Remove( ref );
|
||||
*ref = NULL;
|
||||
delete ref;
|
||||
}
|
||||
|
||||
pobjrefnode = next;
|
||||
}
|
||||
|
||||
|
||||
// If only gathering stars...
|
||||
if (Get_Definition().CheckStarsOnly ) {
|
||||
|
||||
WWPROFILE( "Star Enter" );
|
||||
// check all stars for entering
|
||||
SLNode<SoldierGameObj> *objnode;
|
||||
for ( objnode = GameObjManager::Get_Star_Game_Obj_List()->Head(); objnode; objnode = objnode->Next()) {
|
||||
SoldierGameObj * obj = objnode->Data();
|
||||
if ( obj && Inside_Me( obj ) && !In_List( obj ) ) {
|
||||
Entered( obj );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
WWPROFILE( "All Enter" );
|
||||
// Collect the dynamic physics objects overlapping this zone
|
||||
NonRefPhysListClass objs_in_zone;
|
||||
PhysicsSceneClass::Get_Instance()->Collect_Objects( BoundingBox, false, true, &objs_in_zone );
|
||||
NonRefPhysListIterator it(&objs_in_zone);
|
||||
for (it.First(); !it.Is_Done(); it.Next()) {
|
||||
if ( it.Peek_Obj()->Get_Observer() != NULL ) {
|
||||
PhysicalGameObj * gameobj = ((CombatPhysObserverClass *)it.Peek_Obj()->Get_Observer())->As_PhysicalGameObj();
|
||||
if (gameobj != NULL) {
|
||||
SmartGameObj *obj = gameobj->As_SmartGameObj();
|
||||
if ( obj && Inside_Me( obj ) && !In_List( obj ) ) {
|
||||
Entered( obj );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
**
|
||||
*/
|
||||
void ScriptZoneGameObj::Entered( SmartGameObj * obj )
|
||||
{
|
||||
const GameObjObserverList & observer_list = Get_Observers();
|
||||
for( int index = 0; index < observer_list.Count(); index++ ) {
|
||||
observer_list[ index ]->Entered( this, obj );
|
||||
}
|
||||
|
||||
// Create a new reference and add it to our list
|
||||
GameObjReference * ref = new GameObjReference;
|
||||
*ref = obj;
|
||||
InsideList.Add_Head( ref );
|
||||
}
|
||||
|
||||
/*
|
||||
**
|
||||
*/
|
||||
bool ScriptZoneGameObj::In_List( SmartGameObj * obj )
|
||||
{
|
||||
WWASSERT( obj != NULL );
|
||||
SLNode<GameObjReference> *pobjrefnode;
|
||||
for ( pobjrefnode = InsideList.Head(); pobjrefnode; pobjrefnode = pobjrefnode->Next() ) {
|
||||
if ( obj == *pobjrefnode->Data() ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
**
|
||||
*/
|
||||
bool ScriptZoneGameObj::Inside_Me( const SmartGameObj * obj )
|
||||
{
|
||||
if ( obj && obj->Peek_Physical_Object() ) { // hack to hide zones
|
||||
Vector3 pos;
|
||||
obj->Get_Position(&pos);
|
||||
return (CollisionMath::Overlap_Test(BoundingBox,pos) == CollisionMath::INSIDE);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
**
|
||||
*/
|
||||
ScriptZoneGameObj *ScriptZoneGameObj::Find_Closest_Zone (const Vector3 &pos, ZoneConstants::ZoneType type)
|
||||
{
|
||||
SList<BaseGameObj> *list = GameObjManager::Get_Game_Obj_List ();
|
||||
float closest_dist2 = 999999.0F;
|
||||
ScriptZoneGameObj *closest_zone = NULL;
|
||||
|
||||
//
|
||||
// Loop over all the objects looking for zones
|
||||
//
|
||||
SLNode<BaseGameObj> *node = NULL;
|
||||
for (node = list->Head (); node != NULL; node = node->Next ()) {
|
||||
BaseGameObj *game_obj = node->Data ();
|
||||
|
||||
//
|
||||
// Is this a building on our team?
|
||||
//
|
||||
if (game_obj != NULL && game_obj->As_ScriptableGameObj () != NULL) {
|
||||
ScriptZoneGameObj *zone = game_obj->As_ScriptableGameObj ()->As_ScriptZoneGameObj ();
|
||||
if (zone != NULL) {
|
||||
|
||||
//
|
||||
// Is the type of zone we are looking for?
|
||||
//
|
||||
if (zone->Get_Definition ().Get_Type () == type) {
|
||||
float dist2 = (pos - zone->Get_Bounding_Box ().Center).Length2 ();
|
||||
|
||||
//
|
||||
// Is this the closest zone we've found yet?
|
||||
//
|
||||
if (dist2 < closest_dist2) {
|
||||
closest_dist2 = dist2;
|
||||
closest_zone = zone;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return closest_zone;
|
||||
}
|
||||
|
||||
/*
|
||||
**
|
||||
*/
|
||||
int ScriptZoneGameObj::Count_Team_Members_Inside( int player_type )
|
||||
{
|
||||
SLNode<GameObjReference> *pobjrefnode;
|
||||
int count = 0;
|
||||
for ( pobjrefnode = InsideList.Head(); pobjrefnode; pobjrefnode = pobjrefnode->Next() ) {
|
||||
SmartGameObj * obj = (SmartGameObj*)pobjrefnode->Data()->Get_Ptr();
|
||||
if ( obj->Get_Player_Type() == player_type ) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
**
|
||||
*/
|
||||
/*
|
||||
bool ScriptZoneGameObj::Exists_On_Client( void ) const
|
||||
{
|
||||
bool retval = false;
|
||||
|
||||
//
|
||||
// Allow the C&C mode zone's to exist on the client
|
||||
//
|
||||
switch (Get_Definition ().Get_Type ())
|
||||
{
|
||||
case TYPE_VEHICLE_CONSTRUCTION:
|
||||
case TYPE_VEHICLE_REPAIR:
|
||||
case TYPE_TIBERIUM_FIELD:
|
||||
case TYPE_BEACON:
|
||||
retval = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
if (Get_Definition().ZoneType == TYPE_CTF && obj->As_SoldierGameObj() != NULL) {
|
||||
CombatManager::Soldier_Enters_Pedestal(obj->As_SoldierGameObj(), Get_Player_Type());
|
||||
}
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user