Initial commit: bt411 -- standalone Windows BattleTech (Tesla 4.10 port)
Clean, self-contained extraction of the BattleTech-specific work from the
reverse-engineering workspace -- engine + game + content + build, with nothing
from Red Planet or the raw archive dumps. Builds green (Win32) and runs the
single-player drive->animate->target->fire->damage->destroy loop out of the box.
Layout:
engine/ MUNGA + MUNGA_L4 shared 2007 engine, carrying our BT render/loader
work (bgfload/L4D3D/L4VIDEO: BSL bit-slice decode, LOD/ground/shadow
models) + image codec; the minimal rp/ headers the audio HAL needs
game/ reconstructed BT logic + surviving-original BT source + fwd shims
+ WinMain launcher
content/ full runtime tree (BTL4.RES, VIDEO/, GAUGE/, AUDIO/, eggs, BTDPL.INI)
docs/ format specs + reconstruction ledgers
reference/ raw Ghidra pseudocode (recon source-of-truth) + decomp exporter
tools/ MP console emulator + map/resource scanners
One top-level CMake builds munga_engine lib + bt410_l4 game lib + btl4.exe.
All paths relativized (186 fwd shims + ~437 CMake abs paths -> repo-relative);
DXSDK is the one external, overridable via -DDXSDK. Verified: builds to a
byte-identical 2.27MB exe and runs combat (TARGET DESTROYED, 0 crashes) against
the bundled content.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,773 @@
|
||||
#include "munga.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "explode.h"
|
||||
#include "mover.h"
|
||||
#include "boxsolid.h"
|
||||
#include "collasst.h"
|
||||
#include "damage.h"
|
||||
#include "random.h"
|
||||
#include "app.h"
|
||||
#include "objstrm.h"
|
||||
#include "hostmgr.h"
|
||||
#include "notation.h"
|
||||
#include "namelist.h"
|
||||
|
||||
//#############################################################################
|
||||
//############################ Explosion ################################
|
||||
//#############################################################################
|
||||
|
||||
//#############################################################################
|
||||
// Shared Data Support
|
||||
//
|
||||
Derivation* Explosion::GetClassDerivations()
|
||||
{
|
||||
static Derivation classDerivations(Entity::GetClassDerivations(), "Explosion");
|
||||
return &classDerivations;
|
||||
}
|
||||
|
||||
Explosion::SharedData
|
||||
Explosion::DefaultData(
|
||||
Explosion::GetClassDerivations(),
|
||||
Explosion::GetMessageHandlers(),
|
||||
Explosion::GetAttributeIndex(),
|
||||
Explosion::StateCount,
|
||||
(Entity::MakeHandler)Explosion::Make
|
||||
);
|
||||
|
||||
void
|
||||
Explosion::ExplosionSimulation(Scalar)
|
||||
{
|
||||
Check(application);
|
||||
if ((Now() - creationTime) > explosionDuration)
|
||||
{
|
||||
CondemnToDeathRow();
|
||||
}
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void Explosion::SplashDamage
|
||||
( EntityID inflicting,
|
||||
Damage &damage,
|
||||
Scalar collisionRadius,
|
||||
Vector3D offset,
|
||||
Entity * excluded) // Excluded should really be a set of entities!
|
||||
{
|
||||
Check(this);
|
||||
Check(entityHit);
|
||||
if (excluded)
|
||||
{
|
||||
Check(excluded);
|
||||
}
|
||||
Check_Pointer(&damage);
|
||||
Verify(0 < collisionRadius);
|
||||
|
||||
|
||||
//
|
||||
// The list of volumes we intersect
|
||||
//
|
||||
BoxedSolidCollisionList collision_list;
|
||||
collision_list.Reset();
|
||||
|
||||
//
|
||||
// Create the collision assistant to check movers against
|
||||
//
|
||||
CollisionAssistant *collision_assistant;
|
||||
|
||||
collision_assistant = new CollisionAssistant(entityHit->GetInterestZoneID());
|
||||
Register_Object(collision_assistant);
|
||||
Check(collision_assistant);
|
||||
|
||||
BoxedSolidResource box;
|
||||
Check_Pointer(&box);
|
||||
box.solidType = BoxedSolid::YAxisCylinderType;
|
||||
box.materialType = BoxedSolid::ConcreteMaterial;
|
||||
const Vector3D min = Vector3D(-collisionRadius,-collisionRadius,-collisionRadius);
|
||||
const Vector3D max = Vector3D(collisionRadius,collisionRadius,collisionRadius);
|
||||
ExtentBox ext_box = ExtentBox(min,max);
|
||||
box.solidExtents = ext_box;
|
||||
box.sliceExtents = ext_box;
|
||||
|
||||
BoxedSolidResource local_box;
|
||||
local_box.Instance(box,localOrigin);
|
||||
|
||||
BoxedSolid *splash_volume = BoxedSolid::MakeBoxedSolid(&local_box, this, NULL);
|
||||
Register_Object(splash_volume);
|
||||
|
||||
//
|
||||
//---------------------------------
|
||||
// Test against the tangible movers
|
||||
//---------------------------------
|
||||
//
|
||||
Check(collision_assistant);
|
||||
CollisionAssistant::MovingEntityIterator iterator(collision_assistant);
|
||||
Entity *entity;
|
||||
Mover *mover;
|
||||
Check(splash_volume);
|
||||
while ((entity = iterator.ReadAndNext()) != NULL)
|
||||
{
|
||||
//
|
||||
//------------------------------------------------------------------
|
||||
// If we are checking against ourselves, skip it
|
||||
//------------------------------------------------------------------
|
||||
//
|
||||
Check(entity);
|
||||
if (entity == this)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
//--------------------------------------------------
|
||||
// If we have a mover class object, check against it
|
||||
//--------------------------------------------------
|
||||
//
|
||||
if (entity->IsDerivedFrom(*Mover::GetClassDerivations()))
|
||||
{
|
||||
mover = Cast_Object(Mover *,entity);
|
||||
Check(mover);
|
||||
|
||||
mover->CheckVolumeAgainstBoxedSolidChain(&collision_list, splash_volume);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
// Test against the static world
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
InterestManager *interest_mgr = application->GetInterestManager();
|
||||
Check(interest_mgr);
|
||||
InterestZone *zone = interest_mgr->GetInterestZone(interestZoneID);
|
||||
Check(zone);
|
||||
BoxedSolidTree* tree = zone->GetCollisionRoot();
|
||||
Check(tree);
|
||||
tree->FindBoundingBoxesContaining(
|
||||
splash_volume,
|
||||
collision_list
|
||||
);
|
||||
|
||||
Check_Fpu();
|
||||
Unregister_Object(collision_assistant);
|
||||
delete collision_assistant;
|
||||
Unregister_Object(splash_volume);
|
||||
delete splash_volume;
|
||||
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
// Make a sorted list of all the entities from the collision list,
|
||||
// sorted by their distance from the explosion's origin.
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
VChainOf<Entity*,Vector3D> radius_chain(NULL,False);
|
||||
VChainIteratorOf<Entity*,Vector3D> radius_chain_iterator(radius_chain);
|
||||
|
||||
Vector3D radius;
|
||||
Entity *target_entity;
|
||||
|
||||
|
||||
//
|
||||
|
||||
for(int i = 0;i < collision_list.GetCollisionCount(); i++)
|
||||
{
|
||||
BoxedSolidCollision bsc = collision_list[i];
|
||||
Check(&bsc);
|
||||
target_entity = (Entity*) ((bsc.GetTreeVolume())->GetOwningSimulation());
|
||||
Check(target_entity);
|
||||
Verify(target_entity->IsDerivedFrom(Entity::GetClassDerivations()));
|
||||
if ((target_entity != entityHit) && (target_entity != this) && (target_entity != excluded))
|
||||
{
|
||||
radius = Vector3D::Identity;
|
||||
radius.Subtract(target_entity->localOrigin.linearPosition,localOrigin.linearPosition);
|
||||
radius_chain.AddValue(target_entity, radius);
|
||||
}
|
||||
}
|
||||
|
||||
// While remaining_bursts > 0, advance through list, pick a number of bursts
|
||||
// to inflict, and call SendDamage to the current entity.
|
||||
|
||||
Damage some_damage = damage;
|
||||
int possible_targets = 0;
|
||||
int damageable_targets = 0;
|
||||
radius_chain_iterator.First();
|
||||
while ((target_entity = (Entity*) radius_chain_iterator.GetCurrent()) != NULL)
|
||||
{
|
||||
Check(target_entity);
|
||||
radius = radius_chain_iterator.GetValue();
|
||||
radius_chain_iterator.Next();
|
||||
possible_targets++;
|
||||
if (target_entity->damageZones)
|
||||
{
|
||||
|
||||
damageable_targets++;
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Set the damage data
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
some_damage.burstCount =damage.burstCount / (pow(radius.Length(), 1.2f));
|
||||
Min_Clamp(some_damage.burstCount,1);
|
||||
#if DEBUG_LEVEL > 0
|
||||
DEBUG_STREAM << "At radius " << radius.Length() << ", applied burstCount is " << some_damage.burstCount << std::endl << std::flush;
|
||||
DEBUG_STREAM << "Damage per burst is " << some_damage.damageAmount << std::endl << std::flush;
|
||||
#endif
|
||||
Vector3D force = Vector3D::Identity;
|
||||
force.Multiply(radius,localToWorld);
|
||||
some_damage.damageForce = force;
|
||||
Point3D origin_point = Point3D::Identity;
|
||||
origin_point.Add(localOrigin.linearPosition,offset);
|
||||
some_damage.impactPoint = origin_point;
|
||||
//some_damage.impactPoint.Add(origin_point,radius);
|
||||
|
||||
//
|
||||
//------------------------------------------
|
||||
// Send a damage message to the current target entity
|
||||
//------------------------------------------
|
||||
//
|
||||
|
||||
if (target_entity->GetEntityID() == inflicting)
|
||||
{
|
||||
DEBUG_STREAM << "Splash damage hurting inflicting entity." << std::endl << std::flush;
|
||||
}
|
||||
|
||||
if (excluded && target_entity->GetEntityID() == excluded->GetEntityID() )
|
||||
{
|
||||
DEBUG_STREAM << "Splash damage hurting excluded entity!" << std::endl << std::flush;
|
||||
}
|
||||
|
||||
Entity::TakeDamageMessage take_damage(
|
||||
Entity::TakeDamageMessageID,
|
||||
sizeof(Entity::TakeDamageMessage),
|
||||
inflicting,
|
||||
-1, // We can't know what damage zone we hit
|
||||
some_damage
|
||||
);
|
||||
target_entity->Dispatch(&take_damage);
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG_LEVEL >0
|
||||
DEBUG_STREAM << "There were " << possible_targets << "entities within range, only " << damageable_targets << " had damage zones" << std::endl << std::flush;
|
||||
#endif
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//#############################################################################
|
||||
// Construction and Destruction
|
||||
//
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Explosion::Explosion(
|
||||
Explosion::MakeMessage *creation_message,
|
||||
Explosion::SharedData &virtual_data
|
||||
):
|
||||
Entity(creation_message, virtual_data)
|
||||
{
|
||||
Check_Pointer(this);
|
||||
Check_Pointer(creation_message);
|
||||
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// zero out any rotation
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
localOrigin.angularPosition = Quaternion::Identity;
|
||||
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Get the explosion model resource
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ResourceDescription *resource_description;
|
||||
ModelResource *model_resource;
|
||||
|
||||
Check(application);
|
||||
Check(application->GetResourceFile());
|
||||
resource_description =
|
||||
application->GetResourceFile()->SearchList(
|
||||
resourceID,
|
||||
ResourceDescription::GameModelResourceType
|
||||
);
|
||||
Check(resource_description);
|
||||
resource_description->Lock();
|
||||
model_resource = (ModelResource*)resource_description->resourceAddress;
|
||||
Check_Pointer(model_resource);
|
||||
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Get the creating entity and entity hit by explosion
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Check(application->GetHostManager());
|
||||
entityHit =
|
||||
application->GetHostManager()->GetEntityPointer(
|
||||
creation_message->entityHitID
|
||||
);
|
||||
Check(entityHit);
|
||||
|
||||
if (creation_message->creatingEntityID != EntityID::Null)
|
||||
{
|
||||
creatingEntity =
|
||||
application->GetHostManager()->GetEntityPointer(
|
||||
creation_message->creatingEntityID
|
||||
);
|
||||
Check(creatingEntity);
|
||||
}
|
||||
else
|
||||
{
|
||||
creatingEntity = NULL;
|
||||
}
|
||||
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Calculate the localHitPosition in terms
|
||||
// local coordinate system of the entityHit
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
localHitPosition.MultiplyByInverse(
|
||||
localOrigin.linearPosition,
|
||||
entityHit->localToWorld
|
||||
);
|
||||
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Get the explosion duration
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
explosionDuration = model_resource->explosionDuration;
|
||||
|
||||
#if 0
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// If an explosion resource table is being used then
|
||||
// use it to set the resource
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
if (model_resource->resourceTableObjectID != NullObjectID)
|
||||
{
|
||||
//
|
||||
// If the explosion hit us, set the material to our craft,
|
||||
// If the explosion hit an opponent, set the material to other craft,
|
||||
// If the explosion hit something else then get the material...
|
||||
//
|
||||
Enumeration material_type;
|
||||
|
||||
Check(application);
|
||||
Entity *viewpoint_entity = application->GetViewpointEntity();
|
||||
Check(viewpoint_entity);
|
||||
Verify(creation_message->entityHitID != EntityID::Null);
|
||||
|
||||
// ECH 8/25/95 - Is this the best way to get our vehicle?
|
||||
if (
|
||||
creation_message->entityHitID ==
|
||||
viewpoint_entity->GetEntityID()
|
||||
)
|
||||
{
|
||||
material_type = BoxedSolid::OurCraftMaterial;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ECH 8/25/95 - Is this the best way to identify other vehicles?
|
||||
if (
|
||||
entityHit != NULL &&
|
||||
entityHit->GetPlayerLink() != NULL
|
||||
)
|
||||
{
|
||||
material_type = BoxedSolid::OtherCraftMaterial;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ECH 8/25/95 - How to get material? Just use this for now.
|
||||
material_type = BoxedSolid::ConcreteMaterial;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Get resource table pointer,
|
||||
// Then set the appropriate resource ID
|
||||
//
|
||||
Plug *plug;
|
||||
ExplosionResourceTable *resource_table;
|
||||
ResourceDescription::ResourceID new_resource_ID;
|
||||
|
||||
plug = PlugStreamManager::FindPlug(model_resource->resourceTableObjectID);
|
||||
resource_table = Cast_Object(ExplosionResourceTable*, plug);
|
||||
Check(resource_table);
|
||||
new_resource_ID = resource_table->FindResourceID(material_type);
|
||||
if (new_resource_ID != ResourceDescription::NullResourceID)
|
||||
{
|
||||
resourceID = new_resource_ID;
|
||||
}
|
||||
}
|
||||
#else
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// If an explosion resource table is being used then
|
||||
// use it to set the resource
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
if (model_resource->resourceTableObjectID != NullObjectID)
|
||||
{
|
||||
//
|
||||
// Get resource table pointer,
|
||||
// Then set the appropriate resource ID
|
||||
//
|
||||
Plug *plug;
|
||||
ExplosionResourceTable *resource_table;
|
||||
ResourceDescription::ResourceID new_resource_ID;
|
||||
|
||||
plug = PlugStreamManager::FindPlug(model_resource->resourceTableObjectID);
|
||||
resource_table = Cast_Object(ExplosionResourceTable*, plug);
|
||||
Check(resource_table);
|
||||
new_resource_ID = resource_table->FindResourceID(entityHit);
|
||||
if (new_resource_ID != ResourceDescription::NullResourceID)
|
||||
{
|
||||
resourceID = new_resource_ID;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Set performance and entity validity
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
resource_description->Unlock();
|
||||
SetPerformance(&Explosion::ExplosionSimulation);
|
||||
SetValidFlag();
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Explosion*
|
||||
Explosion::Make(Explosion::MakeMessage *creation_message)
|
||||
{
|
||||
Check(application);
|
||||
HostManager *host_mgr = application->GetHostManager();
|
||||
Check(host_mgr);
|
||||
Entity *entity = host_mgr->GetEntityPointer(creation_message->entityHitID);
|
||||
if (entity)
|
||||
{
|
||||
return new Explosion(creation_message);
|
||||
}
|
||||
Tell(
|
||||
"Warning: Explosion ignored - entity " << creation_message->entityHitID
|
||||
<< " couldn't be found!\n"
|
||||
);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Explosion::~Explosion()
|
||||
{
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Logical
|
||||
Explosion::TestInstance() const
|
||||
{
|
||||
return IsDerivedFrom(*GetClassDerivations());
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// CreateModelResource
|
||||
//
|
||||
ResourceDescription::ResourceID
|
||||
Explosion::CreateModelResource(
|
||||
ResourceFile *resource_file,
|
||||
const char *model_name,
|
||||
NotationFile *model_file,
|
||||
const ResourceDirectories*
|
||||
)
|
||||
{
|
||||
Check(resource_file);
|
||||
Check_Pointer(model_name);
|
||||
Check(model_file);
|
||||
|
||||
ModelResource local_model;
|
||||
if(
|
||||
!model_file->GetEntry(
|
||||
"gamedata",
|
||||
"ExplosionDuration",
|
||||
&local_model.explosionDuration
|
||||
)
|
||||
)
|
||||
{
|
||||
std::cerr<<model_file<<" missing ExplosionDuration"<<std::endl;
|
||||
return -1;
|
||||
}
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// If there exists the name of an explosion resource table then write
|
||||
// its object ID
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
const char *resource_table_name;
|
||||
|
||||
if(
|
||||
model_file->GetEntry(
|
||||
"gamedata",
|
||||
"ExplosionResourceTable",
|
||||
&resource_table_name
|
||||
)
|
||||
)
|
||||
{
|
||||
//
|
||||
// Get the object ID and set it in the model resource
|
||||
//
|
||||
local_model.resourceTableObjectID =
|
||||
PlugStreamManager::FindPlugName(resource_table_name);
|
||||
if (local_model.resourceTableObjectID == NullObjectID)
|
||||
{
|
||||
std::cout << "resource_table_name == " << resource_table_name << "\n";
|
||||
Fail("Explosion::CreateModelResource - ExplosionResourceTable not found");
|
||||
}
|
||||
Verify(local_model.resourceTableObjectID != NullObjectID);
|
||||
}
|
||||
else
|
||||
{
|
||||
local_model.resourceTableObjectID = NullObjectID;
|
||||
}
|
||||
|
||||
ResourceDescription *resource_description =
|
||||
resource_file->AddResource(
|
||||
model_name,
|
||||
ResourceDescription::GameModelResourceType,
|
||||
1,
|
||||
ResourceDescription::Preload,
|
||||
&local_model,
|
||||
sizeof(ModelResource)
|
||||
);
|
||||
Check(resource_description);
|
||||
return resource_description->resourceID;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Enumeration
|
||||
Explosion::GetInterestPriority(Entity *linked_entity)
|
||||
{
|
||||
Check(this);
|
||||
Check(linked_entity);
|
||||
|
||||
return
|
||||
(
|
||||
(linked_entity == creatingEntity) ?
|
||||
HighInterestPriority :
|
||||
LowInterestPriority
|
||||
);
|
||||
}
|
||||
|
||||
//#############################################################################
|
||||
//###################### ExplosionResourceTable #########################
|
||||
//#############################################################################
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
ExplosionResourceTable::ExplosionResourceTable(PlugStream *stream):
|
||||
Plug(stream),
|
||||
resourceIDSocket(NULL, True)
|
||||
{
|
||||
Check(stream);
|
||||
Check(&resourceIDSocket);
|
||||
|
||||
CollectionSize table_size;
|
||||
*stream >> table_size;
|
||||
|
||||
for (CollectionSize i = 0; i < table_size; i++)
|
||||
{
|
||||
Enumeration material_type;
|
||||
ResourceDescription::ResourceID resource_ID;
|
||||
ResourceIDPlug *resource_ID_Plug;
|
||||
|
||||
*stream >> material_type >> resource_ID;
|
||||
|
||||
resource_ID_Plug = new ResourceIDPlug(resource_ID);
|
||||
Register_Object(resource_ID_Plug);
|
||||
resourceIDSocket.AddValue(resource_ID_Plug, material_type);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
ExplosionResourceTable::~ExplosionResourceTable()
|
||||
{
|
||||
TableIteratorOf<ResourceIDPlug*, Enumeration>
|
||||
iterator(&resourceIDSocket);
|
||||
|
||||
Check(&iterator);
|
||||
iterator.DeletePlugs();
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
ExplosionResourceTable::BuildFromPage(
|
||||
ObjectStream *stream,
|
||||
NameList *name_list,
|
||||
ClassID class_ID,
|
||||
ObjectID object_ID
|
||||
)
|
||||
{
|
||||
Check(stream);
|
||||
Check(name_list);
|
||||
|
||||
Plug::BuildFromPage(stream, name_list, class_ID, object_ID);
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Write number of entries
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
CollectionSize table_size = 0;
|
||||
NameList::Entry *entry;
|
||||
|
||||
Check(name_list);
|
||||
entry = name_list->GetFirstEntry();
|
||||
while (entry != NULL)
|
||||
{
|
||||
Check(entry);
|
||||
if (entry->IsName("table_entry"))
|
||||
table_size++;
|
||||
entry = entry->GetNextEntry();
|
||||
}
|
||||
*stream << table_size;
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Write entries
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
#if DEBUG_LEVEL>0
|
||||
CollectionSize i = 0;
|
||||
#endif
|
||||
|
||||
Check(name_list);
|
||||
entry = name_list->GetFirstEntry();
|
||||
while (entry != NULL)
|
||||
{
|
||||
Check(entry);
|
||||
if (entry->IsName("table_entry"))
|
||||
{
|
||||
CString table_entry, token;
|
||||
Enumeration material_type;
|
||||
ResourceDescription *resource_description;
|
||||
ResourceDescription::ResourceID resource_ID;
|
||||
|
||||
Check_Pointer(entry->GetChar());
|
||||
table_entry = entry->GetChar();
|
||||
|
||||
//
|
||||
// Material
|
||||
//
|
||||
Check_Pointer(table_entry.GetNthToken(0));
|
||||
material_type = atol(table_entry.GetNthToken(0));
|
||||
|
||||
//
|
||||
// Resource
|
||||
//
|
||||
Check_Pointer(table_entry.GetNthToken(1));
|
||||
Check(stream->GetResourceFile());
|
||||
resource_description =
|
||||
stream->GetResourceFile()->FindResourceDescription(
|
||||
table_entry.GetNthToken(1),
|
||||
ResourceDescription::ModelListResourceType
|
||||
);
|
||||
Check(resource_description);
|
||||
resource_ID = resource_description->resourceID;
|
||||
|
||||
*stream << material_type << resource_ID;
|
||||
#if DEBUG_LEVEL>0
|
||||
i++;
|
||||
#endif
|
||||
}
|
||||
entry = entry->GetNextEntry();
|
||||
}
|
||||
#if DEBUG_LEVEL>0
|
||||
Verify(i == table_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
Logical
|
||||
ExplosionResourceTable::TestInstance() const
|
||||
{
|
||||
Plug::TestInstance();
|
||||
Check(&resourceIDSocket);
|
||||
return True;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
ResourceDescription::ResourceID
|
||||
ExplosionResourceTable::FindResourceID(Enumeration material_type)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
ResourceIDPlug *resource_ID_Plug;
|
||||
if ((resource_ID_Plug = resourceIDSocket.Find(material_type)) != NULL)
|
||||
{
|
||||
Check(resource_ID_Plug);
|
||||
return resource_ID_Plug->GetItem();
|
||||
}
|
||||
return ResourceDescription::NullResourceID;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
ResourceDescription::ResourceID
|
||||
ExplosionResourceTable::FindResourceID(Entity *entity_hit)
|
||||
{
|
||||
Check(this);
|
||||
Check(entity_hit);
|
||||
|
||||
//
|
||||
// If the explosion hit us, set the material to our craft,
|
||||
// If the explosion hit an opponent, set the material to other craft,
|
||||
// If the explosion hit something else then get the material...
|
||||
//
|
||||
Enumeration material_type;
|
||||
Entity *viewpoint_entity;
|
||||
|
||||
Check(application);
|
||||
viewpoint_entity = application->GetViewpointEntity();
|
||||
Check(viewpoint_entity);
|
||||
|
||||
// ECH 8/25/95 - Is this the best way to get our vehicle?
|
||||
if (entity_hit->GetEntityID() == viewpoint_entity->GetEntityID())
|
||||
{
|
||||
material_type = BoxedSolid::OurCraftMaterial;
|
||||
}
|
||||
// ECH 8/25/95 - Is this the best way to identify other vehicles?
|
||||
else if (entity_hit->GetPlayerLink() != NULL)
|
||||
{
|
||||
material_type = BoxedSolid::OtherCraftMaterial;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ECH 8/25/95 - How to get material? Just use this for now.
|
||||
material_type = BoxedSolid::ConcreteMaterial;
|
||||
}
|
||||
|
||||
//
|
||||
// Return the appropriate resource ID
|
||||
//
|
||||
return FindResourceID(material_type);
|
||||
}
|
||||
Reference in New Issue
Block a user