This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/Combat/staticnetworkobject.cpp

914 lines
23 KiB
C++
Raw Permalink Normal View History

/*
** 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/staticnetworkobject.cpp $*
* *
* $Author:: Steve_t $*
* *
* $Modtime:: 1/15/02 1:02p $*
* *
* $Revision:: 15 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "staticnetworkobject.h"
#include "staticanimphys.h"
#include "doors.h"
#include "elevator.h"
#include "bitpackids.h"
#include "combat.h"
#include "damageablestaticphys.h"
#include "explosion.h"
#include "vistable.h"
#include "networkobjectmgr.h"
#include "apppackettypes.h"
////////////////////////////////////////////////////////////////
// Forward declarations
////////////////////////////////////////////////////////////////
DynamicVectorClass<StaticNetworkObjectClass *> StaticNetworkObjectClass::StaticNetworkObjectList;
////////////////////////////////////////////////////////////////
//
// StaticNetworkObjectClass
//
////////////////////////////////////////////////////////////////
StaticNetworkObjectClass::StaticNetworkObjectClass (void) :
PhysObj (NULL),
AnimationMode (0),
LoopStart (0),
LoopEnd (0),
CurrFrame (0),
TargetFrame (0)
{
//
// Add ourselves to the master list
//
StaticNetworkObjectList.Add (this);
//
// Make sure we don't try to create the object on the client
//
//TSS2001d Clear_Object_Dirty_Bits ();
Set_Object_Dirty_Bit (BIT_RARE, true);
Set_App_Packet_Type(APPPACKETTYPE_STATIC);
}
////////////////////////////////////////////////////////////////
//
// ~StaticNetworkObjectClass
//
////////////////////////////////////////////////////////////////
StaticNetworkObjectClass::~StaticNetworkObjectClass (void)
{
REF_PTR_RELEASE (PhysObj);
//
// Remove ourselves from the master list
//
int index = StaticNetworkObjectList.ID (this);
if (index != -1) {
StaticNetworkObjectList.Delete (index);
}
return ;
}
////////////////////////////////////////////////////////////////
//
// Get_World_Position
//
////////////////////////////////////////////////////////////////
bool
StaticNetworkObjectClass::Get_World_Position (Vector3 &pos) const
{
bool retval = false;
//
// Return the physic object's position
//
if (PhysObj != NULL) {
PhysObj->Get_Position (&pos);
retval = true;
}
return retval;
}
////////////////////////////////////////////////////////////////
//
// Get_Vis_ID - return the vis ID for this object
//
////////////////////////////////////////////////////////////////
int
StaticNetworkObjectClass::Get_Vis_ID (void)
{
if (PhysObj != NULL) {
return PhysObj->Get_Vis_Object_ID ();
}
return -1;
}
////////////////////////////////////////////////////////////////
//
// Initialize
//
////////////////////////////////////////////////////////////////
void
StaticNetworkObjectClass::Initialize (StaticAnimPhysClass *phys_obj)
{
REF_PTR_SET (PhysObj, phys_obj);
//
// Update the network ID
//
int network_id = 0;
if (PhysObj != NULL) {
network_id = PhysObj->Get_ID ();
//
// Copy the object's state
//
AnimCollisionManagerClass &anim_mgr = PhysObj->Get_Animation_Manager ();
AnimationMode = anim_mgr.Get_Animation_Mode ();
CurrFrame = anim_mgr.Get_Current_Frame ();
TargetFrame = anim_mgr.Get_Target_Frame ();
LoopStart = anim_mgr.Get_Loop_Start ();
LoopEnd = anim_mgr.Get_Loop_End ();
}
//WWASSERT(network_id >= NETID_STATIC_OBJECT_MIN && network_id <= NETID_STATIC_OBJECT_MAX);
Set_Network_ID (network_id);
return ;
}
////////////////////////////////////////////////////////////////
//
// Network_Think
//
////////////////////////////////////////////////////////////////
void
StaticNetworkObjectClass::Network_Think (void)
{
NetworkObjectClass::Network_Think ();
if (PhysObj != NULL) {
AnimCollisionManagerClass &anim_mgr = PhysObj->Get_Animation_Manager ();
//
// Set the dirty bit if the state has changed
//
if ( AnimationMode != anim_mgr.Get_Animation_Mode () ||
TargetFrame != anim_mgr.Get_Target_Frame () ||
LoopStart != anim_mgr.Get_Loop_Start () ||
LoopEnd != anim_mgr.Get_Loop_End ())
{
AnimationMode = anim_mgr.Get_Animation_Mode ();
CurrFrame = anim_mgr.Get_Current_Frame ();
TargetFrame = anim_mgr.Get_Target_Frame ();
LoopStart = anim_mgr.Get_Loop_Start ();
LoopEnd = anim_mgr.Get_Loop_End ();
Set_Object_Dirty_Bit (BIT_RARE, true);
}
}
return ;
}
/*
////////////////////////////////////////////////////////////////////////////
//
// Compute_Object_Priority - TSS092201
//
/////////////////////////////////////////////////////////////////////////////
float
StaticNetworkObjectClass::Compute_Object_Priority (int client_id, const Vector3 &client_pos)
{
float priority = 1.0F;
if (Get_Object_Dirty_Bit (client_id, BIT_RARE) == false) {
priority = NetworkObjectClass::Compute_Object_Priority (client_id, client_pos);
}
//
// Priority value is cached, update the cached value.
//
Set_Cached_Priority(priority);
return priority;
}
*/
////////////////////////////////////////////////////////////////
//
// Generate_Static_Network_Objects
//
////////////////////////////////////////////////////////////////
void
StaticNetworkObjectClass::Generate_Static_Network_Objects (void)
{
RefPhysListIterator iterator = COMBAT_SCENE->Get_Static_Anim_Object_Iterator ();
//
// Loop over all the static anim objects in the world
//
for (iterator.First (); iterator.Is_Done () == false; iterator.Next ()) {
StaticAnimPhysClass *phys_obj = (StaticAnimPhysClass *)iterator.Peek_Obj ();
if (phys_obj != NULL) {
//
// Make a new network object for this phys obj
//
StaticNetworkObjectClass *network_obj = NULL;
if (phys_obj->As_ElevatorPhysClass () != NULL) {
network_obj = new ElevatorNetworkObjectClass;
} else if (phys_obj->As_DoorPhysClass () != NULL) {
network_obj = new DoorNetworkObjectClass;
} else if (phys_obj->As_DamageableStaticPhysClass () != NULL) {
network_obj = new DSAPONetworkObjectClass;
} else {
network_obj = new StaticNetworkObjectClass;
}
//
// Initialize the network object
//
network_obj->Initialize (phys_obj);
}
}
return ;
}
////////////////////////////////////////////////////////////////
//
// Free_Static_Network_Objects
//
////////////////////////////////////////////////////////////////
void
StaticNetworkObjectClass::Free_Static_Network_Objects (void)
{
DynamicVectorClass<StaticNetworkObjectClass *> temp_list = StaticNetworkObjectList;
//
// Loop over and free all the entries
//
for (int index = temp_list.Count () - 1; index >= 0; index --) {
StaticNetworkObjectClass *object = temp_list[index];
if (object != NULL) {
delete object;
}
}
//
// Make sure the list has been completely cleared
//
WWASSERT (StaticNetworkObjectList.Count () == 0);
return ;
}
////////////////////////////////////////////////////////////////
//
// Import_Rare
//
////////////////////////////////////////////////////////////////
void
StaticNetworkObjectClass::Import_Rare (BitStreamClass &packet)
{
NetworkObjectClass::Import_Rare (packet);
//
// Read the data
//
packet.Get (AnimationMode);
packet.Get (LoopStart);
packet.Get (LoopEnd);
packet.Get (CurrFrame);
packet.Get (TargetFrame);
if (PhysObj != NULL) {
AnimCollisionManagerClass &anim_mgr = PhysObj->Get_Animation_Manager ();
//
// Set the data
//
anim_mgr.Set_Target_Frame (TargetFrame);
anim_mgr.Set_Current_Frame (CurrFrame);
anim_mgr.Set_Loop_Start (LoopStart);
anim_mgr.Set_Loop_End (LoopEnd);
anim_mgr.Set_Animation_Mode ((AnimCollisionManagerClass::AnimModeType)AnimationMode);
}
return ;
}
////////////////////////////////////////////////////////////////
//
// Export_Rare
//
////////////////////////////////////////////////////////////////
void
StaticNetworkObjectClass::Export_Rare (BitStreamClass &packet)
{
NetworkObjectClass::Export_Rare (packet);
//
// Export information about the animation
//
packet.Add (AnimationMode);
packet.Add (LoopStart);
packet.Add (LoopEnd);
packet.Add (CurrFrame);
packet.Add (TargetFrame);
return ;
}
////////////////////////////////////////////////////////////////
//
// DoorNetworkObjectClass
//
////////////////////////////////////////////////////////////////
DoorNetworkObjectClass::DoorNetworkObjectClass (void) :
DoorState (0)
{
Set_App_Packet_Type(APPPACKETTYPE_DOOR);
}
////////////////////////////////////////////////////////////////
//
// Initialize
//
////////////////////////////////////////////////////////////////
void
DoorNetworkObjectClass::Initialize (StaticAnimPhysClass *phys_obj)
{
StaticNetworkObjectClass::Initialize (phys_obj);
//
// Get a pointer to the door
//
if (PhysObj != NULL) {
DoorPhysClass *door = PhysObj->As_DoorPhysClass ();
if (door != NULL) {
//
// Copy the object's state
//
DoorState = door->State;
Set_Object_Dirty_Bit (BIT_RARE, true);
}
}
return ;
}
////////////////////////////////////////////////////////////////
//
// Network_Think
//
////////////////////////////////////////////////////////////////
void
DoorNetworkObjectClass::Network_Think (void)
{
NetworkObjectClass::Network_Think ();
//
// Get a pointer to the door
//
if (PhysObj != NULL) {
DoorPhysClass *door = PhysObj->As_DoorPhysClass ();
if (door != NULL) {
//
// Set the dirty bit if the state has changed
//
if (DoorState != door->State) {
DoorState = door->State;
if (DoorState == STATE_OPENING_DOOR || DoorState == STATE_CLOSING_DOOR || DoorState == STATE_ACCESS_DENIED) {
Set_Object_Dirty_Bit (BIT_RARE, true);
}
}
}
}
return ;
}
////////////////////////////////////////////////////////////////
//
// Import_Rare
//
////////////////////////////////////////////////////////////////
void
DoorNetworkObjectClass::Import_Rare (BitStreamClass &packet)
{
//
// Note: As a network optimization, we don't call the base
// class. Doors are now state based and don't need to
// transmit frame numbers.
//
//
// Read the new state
//
packet.Get (DoorState, BITPACK_DOOR_STATE);
//
// Get a pointer to the door
//
if (PhysObj != NULL) {
DoorPhysClass *door = PhysObj->As_DoorPhysClass ();
if (door != NULL) {
//
// Set the new state
//
bool success = door->Set_State (DoorState);
if (!success) {
WWDEBUG_SAY(("DoorNetworkObjectClass::Import_Rare -- Door state changed failed to apply\n"));
}
}
}
return ;
}
////////////////////////////////////////////////////////////////
//
// Export_Rare
//
////////////////////////////////////////////////////////////////
void
DoorNetworkObjectClass::Export_Rare (BitStreamClass &packet)
{
//
// Note: As a network optimization, we don't call the base
// class. Doors are now state based and don't need to
// transmit frame numbers.
//
//
// Send the state
//
packet.Add (DoorState, BITPACK_DOOR_STATE);
return ;
}
////////////////////////////////////////////////////////////////
//
// Get_Description
//
////////////////////////////////////////////////////////////////
void
DoorNetworkObjectClass::Get_Description (StringClass & description)
{
StringClass line;
StringClass state_string;
switch (DoorState) {
case STATE_CLOSED_DOOR: state_string = "STATE_CLOSED_DOOR"; break;
case STATE_OPENED_DOOR: state_string = "STATE_OPENED_DOOR"; break;
case STATE_OPENING_DOOR: state_string = "STATE_OPENING_DOOR"; break;
case STATE_CLOSING_DOOR: state_string = "STATE_CLOSING_DOOR"; break;
case STATE_ACCESS_DENIED: state_string = "STATE_ACCESS_DENIED"; break;
default: DIE;
}
line.Format("DoorState: %d (%s)\n", DoorState, state_string);
description += line;
if (PhysObj != NULL) {
DoorPhysClass *door = PhysObj->As_DoorPhysClass ();
if (door != NULL) {
line.Format("Timer: %-5.2f\n", door->Timer);
description += line;
line.Format("CheckTimer: %-5.2f\n", door->CheckTimer);
description += line;
line.Format("State: %d\n", door->State);
description += line;
line.Format("ORP: %d\n", door->OpenRequestPending);
description += line;
line.Format("LockState: %d\n", door->LockState);
description += line;
}
}
}
////////////////////////////////////////////////////////////////
//
// ElevatorNetworkObjectClass
//
////////////////////////////////////////////////////////////////
ElevatorNetworkObjectClass::ElevatorNetworkObjectClass (void) :
State (0),
DoorStateTop (0),
DoorStateBottom (0)
{
Set_App_Packet_Type(APPPACKETTYPE_ELEVATOR);
}
////////////////////////////////////////////////////////////////
//
// Initialize
//
////////////////////////////////////////////////////////////////
void
ElevatorNetworkObjectClass::Initialize (StaticAnimPhysClass *phys_obj)
{
//bug NetworkObjectClass::Network_Think ();
StaticNetworkObjectClass::Initialize (phys_obj);
//
// Get a pointer to the elevator
//
if (PhysObj != NULL) {
ElevatorPhysClass *elevator = PhysObj->As_ElevatorPhysClass ();
if (elevator != NULL) {
//
// Copy the object's state
//
State = elevator->State;
DoorStateTop = elevator->DoorStates[ElevatorPhysClass::TOP];
DoorStateBottom = elevator->DoorStates[ElevatorPhysClass::BOTTOM];
}
}
return ;
}
////////////////////////////////////////////////////////////////
//
// Network_Think
//
////////////////////////////////////////////////////////////////
void
ElevatorNetworkObjectClass::Network_Think (void)
{
NetworkObjectClass::Network_Think ();
//StaticNetworkObjectClass::Network_Think ();
//
// Get a pointer to the elevator
//
if (PhysObj != NULL) {
ElevatorPhysClass *elevator = PhysObj->As_ElevatorPhysClass ();
if (elevator != NULL) {
//
// Set the dirty bit if the state has changed
//
if ( State != elevator->State ||
DoorStateTop != elevator->DoorStates[ElevatorPhysClass::TOP] ||
DoorStateBottom != elevator->DoorStates[ElevatorPhysClass::BOTTOM])
{
State = elevator->State;
DoorStateTop = elevator->DoorStates[ElevatorPhysClass::TOP];
DoorStateBottom = elevator->DoorStates[ElevatorPhysClass::BOTTOM];
Set_Object_Dirty_Bit (BIT_RARE, true);
}
}
}
return ;
}
////////////////////////////////////////////////////////////////
//
// Import_Rare
//
////////////////////////////////////////////////////////////////
void
ElevatorNetworkObjectClass::Import_Rare (BitStreamClass &packet)
{
//
// Note: As a network optimization, we don't call the base
// class. Doors are now state based and don't need to
// transmit frame numbers.
//
//StaticNetworkObjectClass::Import_Rare (packet);
//
// Read the new state data
//
packet.Get (State);
packet.Get (DoorStateTop);
packet.Get (DoorStateBottom);
//
// Get a pointer to the elevator
//
if (PhysObj != NULL) {
ElevatorPhysClass *elevator = PhysObj->As_ElevatorPhysClass ();
if (elevator != NULL) {
//
// Switch to the new states
//
elevator->Set_State (State);
elevator->Set_Door_State (ElevatorPhysClass::TOP, DoorStateTop);
elevator->Set_Door_State (ElevatorPhysClass::BOTTOM, DoorStateBottom);
}
}
return ;
}
////////////////////////////////////////////////////////////////
//
// Export_Rare
//
////////////////////////////////////////////////////////////////
void
ElevatorNetworkObjectClass::Export_Rare (BitStreamClass &packet)
{
//
// Note: As a network optimization, we don't call the base
// class. Doors are now state based and don't need to
// transmit frame numbers.
//
//StaticNetworkObjectClass::Export_Rare (packet);
//
// Transmit the state information
//
packet.Add (State);
packet.Add (DoorStateTop);
packet.Add (DoorStateBottom);
return ;
}
////////////////////////////////////////////////////////////////
//
// Get_Description
//
////////////////////////////////////////////////////////////////
void
ElevatorNetworkObjectClass::Get_Description (StringClass & description)
{
StringClass line;
StringClass state_string;
//
// State
//
switch (State) {
case ElevatorPhysClass::STATE_DOWN: state_string = "STATE_DOWN"; break;
case ElevatorPhysClass::STATE_MOVING_UP: state_string = "STATE_MOVING_UP"; break;
case ElevatorPhysClass::STATE_UP: state_string = "STATE_UP"; break;
case ElevatorPhysClass::STATE_MOVING_DOWN: state_string = "STATE_MOVING_DOWN"; break;
default: DIE;
}
line.Format("State: %d (%s)\n", State, state_string);
description += line;
//
// DoorStateTop
//
switch (DoorStateTop) {
case ElevatorPhysClass::DOOR_STATE_NORMAL: state_string = "DOOR_STATE_NORMAL"; break;
case ElevatorPhysClass::DOOR_STATE_UNLOCKED: state_string = "DOOR_STATE_UNLOCKED"; break;
case ElevatorPhysClass::DOOR_STATE_ACCESS_DENIED: state_string = "DOOR_STATE_ACCESS_DENIED"; break;
default: DIE;
}
line.Format("DoorStateTop: %d (%s)\n", DoorStateTop, state_string);
description += line;
//
// DoorStateBottom
//
switch (DoorStateBottom) {
case ElevatorPhysClass::DOOR_STATE_NORMAL: state_string = "DOOR_STATE_NORMAL"; break;
case ElevatorPhysClass::DOOR_STATE_UNLOCKED: state_string = "DOOR_STATE_UNLOCKED"; break;
case ElevatorPhysClass::DOOR_STATE_ACCESS_DENIED: state_string = "DOOR_STATE_ACCESS_DENIED"; break;
default: DIE;
}
line.Format("DoorStateBottom: %d (%s)\n", DoorStateBottom, state_string);
description += line;
if (PhysObj != NULL) {
ElevatorPhysClass *elevator = PhysObj->As_ElevatorPhysClass ();
if (elevator != NULL) {
line.Format("State: %d\n", elevator->State);
description += line;
line.Format("DoorStates[0]: %d\n", elevator->DoorStates[0]);
description += line;
line.Format("DoorStates[1]: %d\n", elevator->DoorStates[1]);
description += line;
line.Format("CheckTimer: %-5.2f\n", elevator->CheckTimer);
description += line;
line.Format("PrevFrame: %-5.2f\n", elevator->PrevFrame);
description += line;
line.Format("IsCallTimerSet: %d\n", elevator->IsCallTimerSet);
description += line;
line.Format("CallTimer: %-5.2f\n", elevator->CallTimer);
description += line;
line.Format("TriggerRequest: %d\n", elevator->TriggerRequest);
description += line;
}
}
}
////////////////////////////////////////////////////////////////
//
// DSAPONetworkObjectClass
//
////////////////////////////////////////////////////////////////
DSAPONetworkObjectClass::DSAPONetworkObjectClass (void) :
Health (0)
{
Set_App_Packet_Type(APPPACKETTYPE_DSAPO);
}
////////////////////////////////////////////////////////////////
//
// Initialize
//
////////////////////////////////////////////////////////////////
void
DSAPONetworkObjectClass::Initialize (StaticAnimPhysClass *phys_obj)
{
StaticNetworkObjectClass::Initialize (phys_obj);
//
// Get a pointer to the object
//
if (PhysObj != NULL) {
DamageableStaticPhysClass *phys_obj = PhysObj->As_DamageableStaticPhysClass ();
if (phys_obj != NULL) {
//
// Copy the object's state
//
Health = phys_obj->DefenseObject.Get_Health ();
}
}
return ;
}
////////////////////////////////////////////////////////////////
//
// Network_Think
//
////////////////////////////////////////////////////////////////
void
DSAPONetworkObjectClass::Network_Think (void)
{
StaticNetworkObjectClass::Network_Think ();
//
// Get a pointer to the object
//
if (PhysObj != NULL) {
DamageableStaticPhysClass *phys_obj = PhysObj->As_DamageableStaticPhysClass ();
if (phys_obj != NULL) {
//
// Set the dirty bit if the state has changed
//
if (Health > 0 && phys_obj->DefenseObject.Get_Health () <= 0) {
Health = phys_obj->DefenseObject.Get_Health ();
Set_Object_Dirty_Bit (BIT_RARE, true);
}
}
}
return ;
}
////////////////////////////////////////////////////////////////
//
// Import_Rare
//
////////////////////////////////////////////////////////////////
void
DSAPONetworkObjectClass::Import_Rare (BitStreamClass &packet)
{
DamageableStaticPhysClass *phys_obj = PhysObj->As_DamageableStaticPhysClass ();
if (phys_obj == NULL) {
return ;
}
//
// Get the health BEFORE we import the data
//
float old_health = phys_obj->DefenseObject.Get_Health();
//
// Import the data
//
StaticNetworkObjectClass::Import_Rare (packet);
phys_obj->DefenseObject.Import (packet);
//
// Did the health drop below 0?
//
if ((old_health > 0) && (phys_obj->DefenseObject.Get_Health () <= 0)) {
//
// Anim data should already been sent
//
phys_obj->Get_Animation_Manager().Set_Animation_Mode (AnimCollisionManagerClass::ANIMATE_TARGET);
//
// Play the explosion
//
const DamageableStaticPhysDefClass *definition = phys_obj->Get_DamageableStaticPhysDef ();
if (definition->KilledExplosion != 0) {
ExplosionManager::Create_Explosion_At (definition->KilledExplosion, phys_obj->Get_Transform (), NULL);
}
}
return ;
}
////////////////////////////////////////////////////////////////
//
// Export_Rare
//
////////////////////////////////////////////////////////////////
void
DSAPONetworkObjectClass::Export_Rare (BitStreamClass &packet)
{
DamageableStaticPhysClass *phys_obj = PhysObj->As_DamageableStaticPhysClass ();
if (phys_obj == NULL) {
return ;
}
//
// Just export the defense object's settings
//
StaticNetworkObjectClass::Export_Rare (packet);
phys_obj->DefenseObject.Export (packet);
return ;
}