914 lines
23 KiB
C++
914 lines
23 KiB
C++
|
/*
|
||
|
** 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 ;
|
||
|
}
|