Files
BT411/engine/MUNGA/CULTURAL.cpp
T
arcattackandClaude Fable 5 6f6a39b8c9 Issue #3 (b)+(c): weapon damage reaches cultural icons -> full trkdead explosion + authored burn fire
(b) The 'tiny explosion' on the ram kill is AUTHORED: crunch res 31 = 'stephit'
(one video object, effect 1008 = ddam5 damage smoke) -- a step/ram squash is
small by design.  The FULL explosion res 32 = 'trkdead' = psfx 15 dtrkboom
(fiery omni burst) + psfx 16 dtrkburn (the burning-wreck fire), reached by
WEAPON kills -- which the 1995 binary dispatches [T1]:
  - MechWeapon::SendDamageMessage @004b9728 (part_013.c:6765) gates only
    "target NOT derived from Mech@0x50bdb4 OR aimed zone set": a non-Mech
    boresight target takes the zone=-1 damage UNCONDITIONALLY;
  - Missile contact @004be078 dispatches at the struck solid's OWNER entity
    with no class test at all.
Port wiring: Mech::WorldStructurePick returns the struck solid's owning entity
(BoxedSolid::GetOwningSimulation; TERRAIN.cpp:107/246 build every static solid
with its Terrain/CulturalIcon/Door entity as owner); the mech4 pick block
designates IT instead of the gBTTerrainEntity sentinel (sentinel = fallback);
the projectile contact path grew the non-mech damage-zoned else-branch
(@004be078 mirror, direct Dispatch).  Plain terrain ignores the damage
(ENTITY.cpp:885 zone==-1 guard); an icon's handler maps -1 -> 0 and dies.
Truck armor is WeaponDamagePoints=1 (TRK.DMG): one laser = one dead truck.

(c) The burning fire is dtrkburn.pfx, authored INTO the death package (every
icon family carries 1016: trkdead/bigdead/meddead/msldead/twrdead).  There is
NO looping BurningState fire in the binary: the damage-zone effect watcher
ctor @0042a984 has exactly one call site (the Mech ctor, part_012.c:10405), so
icon ExplosionTables are inert, and CulturalIcon has no Performance.
Documented as authentic -- nothing invented.

Verified live (BT_SHOT pixel capture): 26 laser kills, [cult] TakeDamage
type=3 -> DYING res=32 -> DPLIndependantEffect 1015+1016 at the icon origin;
frames show the orange dtrkboom fireball, dtrkburn flames on the fresh wreck,
and the rubble aftermath; ram harness re-run still fires crunch res 31.
Diags: BT_FIRE_AT_ICON (designate nearest ahead icon; live-icon census in
CULTURAL.cpp), BT_FX_TEST="1015,1016".

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 12:02:15 -05:00

1129 lines
26 KiB
C++

#include "munga.h"
#pragma hdrstop
#include "cultural.h"
#include "terrain.h"
#include "fileutil.h"
#include "boxtree.h"
#include "boxsolid.h"
#include "scnrole.h"
#include "mission.h"
#include "explode.h"
#include "app.h"
#include "interest.h"
#include "hostmgr.h"
#include "nttmgr.h"
#include "namelist.h"
#include "console.h"
//##########################################################################
//##################### Class CulturalIcon ##########################
//##########################################################################
//#############################################################################
// Shared Data Support
//
Derivation* CulturalIcon::GetClassDerivations()
{ static Derivation classDerivations(UnscalableTerrain::GetClassDerivations(), "CulturalIcon");
return &classDerivations;
}
CulturalIcon::SharedData
CulturalIcon::DefaultData(
CulturalIcon::GetClassDerivations(),
CulturalIcon::GetMessageHandlers(),
CulturalIcon::GetAttributeIndex(),
CulturalIcon::StateCount,
(UnscalableTerrain::MakeHandler)CulturalIcon::Make
);
//#############################################################################
// Message Support
//
const Receiver::HandlerEntry
CulturalIcon::MessageHandlerEntries[]=
{
MESSAGE_ENTRY(CulturalIcon, TakeDamage),
MESSAGE_ENTRY(CulturalIcon, SetBurningState)
};
CulturalIcon::MessageHandlerSet& CulturalIcon::GetMessageHandlers()
{
static CulturalIcon::MessageHandlerSet messageHandlers(ELEMENTS(CulturalIcon::MessageHandlerEntries), CulturalIcon::MessageHandlerEntries, UnscalableTerrain::GetMessageHandlers());
return messageHandlers;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CulturalIcon::SetBurningStateMessageHandler(Message * /*burning_message*/)
{
SetSimulationState(CulturalIcon::BurningState);
ForceUpdate(DefaultUpdateModelFlag);
AlwaysExecute();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CulturalIcon::TakeDamageMessageHandler(TakeDamageMessage *damage_message)
{
Check(damage_message);
// BT_CULT_LOG (issue #3): does damage ever reach a cultural icon?
if (getenv("BT_CULT_LOG"))
{
DEBUG_STREAM << "[cult] TakeDamage entity=" << (long)GetEntityID()
<< " type=" << (int)damage_message->damageData.damageType
<< " amount=" << (float)damage_message->damageData.damageAmount
<< " zone=" << damage_message->damageZone
<< " state=" << GetSimulationState()
<< "\n" << std::flush;
}
if (damage_message->damageZone == -1 )
{
damage_message->damageZone = 0;
}
if (GetSimulationState() == CulturalIcon::DefaultState)
{
//
//~~~~~~~~~~~~~~~~~~
// Update Replicants
//~~~~~~~~~~~~~~~~~~
//
if (GetInstance() != ReplicantInstance)
{
ForceUpdate(DamageZoneUpdateModelFlag | DefaultUpdateModelFlag);
AlwaysExecute();
}
//
//~~~~~~~~~~~~~~~~~~~~~
// Call Derived Classes
//~~~~~~~~~~~~~~~~~~~~~
//
UnscalableTerrain::TakeDamageMessageHandler(damage_message);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Update Collision Volumes if we died
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
for(int ii=0;ii<damageZoneCount;++ii)
{
if(damageZones[ii]->GetDamageZoneState() == DamageZone::BurningState)
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Create the explosion
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Origin explode_origin = localOrigin;
ResourceDescription::ResourceID explosion_ID;
if ((damage_message->damageData.damageType == Damage::CollisionDamageType )&&
(crunchExplosionResourceID != -1))
{
explosion_ID = crunchExplosionResourceID;
}
else
{
explosion_ID = explosionResourceID;
}
Explosion::MakeMessage exp_message(
Explosion::MakeMessageID,
sizeof(Explosion::MakeMessage),
RegisteredClass::ExplosionClassID,
EntityID::Null,
explosion_ID,
Explosion::DefaultFlags,
explode_origin,
GetEntityID(),
GetEntityID()
);
#if (DEBUG_LEVEL > 0)
Explosion *new_exp =
#endif
Explosion::Make(&exp_message);
Register_Object(new_exp);
// BT_CULT_LOG (issue #3): the death transition fired
if (getenv("BT_CULT_LOG"))
{
DEBUG_STREAM << "[cult] DYING entity=" << (long)GetEntityID()
<< " explosion res=" << explosion_ID
<< " delay=" << (float)timeDelay
<< " -> WaitingToBurn\n" << std::flush;
}
Message dummy_message(SetBurningStateMessageID, sizeof(Message));
Check(application);
Time now = Now();
now += timeDelay;
application->Post(CreationEventPriority, this, &dummy_message, now);
SetSimulationState(WaitingToBurn);
UpdateCollisionVolumes();
break;
}
}
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CulturalIcon::UpdateCollisionVolumes()
{
Check(this);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Get the Tree for these Collision Volumes
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
InterestManager *interest_mgr =
application->GetInterestManager();
Check(interest_mgr);
InterestZone *zone =
interest_mgr->GetInterestZone(interestZoneID);
Check(zone);
BoxedSolidTree* tree = zone->GetCollisionRoot();
Check(tree);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Update Volumes based on RemoveVolume Flag
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoxedSolid *box = collisionVolumes;
while (box)
{
BoxedSolid *next_box = box->GetNextSolid();
if (RemoveCollisionVolumeOnDeath())
{
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Delete the Collision Volume
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
tree->Remove(box);
Unregister_Object(box);
delete box;
}
else
{
//
//~~~~~~~~~~~~~~~~~~~~~~
// Move Collision Volume
//~~~~~~~~~~~~~~~~~~~~~~
//
box->minY += destroyedYTranslation;
box->maxY += destroyedYTranslation;
}
box = next_box;
}
collisionVolumes = NULL;
Check_Fpu();
}
//#############################################################################
// Attribute Support
//
const CulturalIcon::IndexEntry
CulturalIcon::AttributePointers[]=
{
ATTRIBUTE_ENTRY(CulturalIcon, TeamName, teamName)
};
CulturalIcon::AttributeIndexSet& CulturalIcon::GetAttributeIndex()
{
static CulturalIcon::AttributeIndexSet attributeIndex(ELEMENTS(CulturalIcon::AttributePointers),
CulturalIcon::AttributePointers,
UnscalableTerrain::GetAttributeIndex()
);
return attributeIndex;
}
//#############################################################################
// Construction and Destruction
//
//
// Live-icon census (issue #3 diag): lets the BT_FIRE_AT_ICON harness designate
// a real map icon deterministically (headless weapon-vs-icon verification).
// Registration bookkeeping only -- no behavior change; entries are removed in
// the dtor (interest streaming can delete icons on zone transitions).
//
Entity *gBTCultIcons[256];
int gBTCultIconCount = 0;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CulturalIcon::CulturalIcon(
MakeMessage *creation_message,
SharedData &shared_data
) :
UnscalableTerrain(creation_message, shared_data)
{
if (gBTCultIconCount < 256)
{
gBTCultIcons[gBTCultIconCount++] = this;
}
Str_Copy(teamName, "Defualt", sizeof(teamName));
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Read in the ModelResource Information
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ResourceDescription *res =
application->GetResourceFile()->SearchList(
resourceID,
ResourceDescription::GameModelResourceType
);
Check(res);
res->Lock();
ModelResource* model_resource = (ModelResource*)res->resourceAddress;
Check_Pointer(model_resource);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Determine if we move or Destroy the
// Collision volume in Death of the map entity
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
if (model_resource->sinkCollisionVolume)
{
destroyedYTranslation = model_resource->destroyedYTranslation;
}
else
{
destroyedYTranslation = 0.0f;
SetRemoveCollisionVolumeFlag();
}
timeDelay = model_resource->timeDelay;
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Is Stopping Collision Volume ?
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
if (model_resource->stoppingCollisionVolume)
{
SetStoppingCollisionVolumeFlag();
}
explosionResourceID = model_resource->explosionResourceID;
crunchExplosionResourceID = model_resource->crunchExplosionResourceID;
res->Unlock();
//DEBUG_STREAM << model_resource->crunchExplosionResourceID << std::endl << std::flush;
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Read in DamageZone Information from the Resource
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ResourceDescription *dmg_res =
application->GetResourceFile()->SearchList(
resourceID,
ResourceDescription::DamageZoneStreamResourceType
);
Check(dmg_res);
dmg_res->Lock();
DynamicMemoryStream damage_stream (
dmg_res->resourceAddress,
dmg_res->resourceSize
);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~
// skip over DamageZoneCount
//~~~~~~~~~~~~~~~~~~~~~~~~~~
//
damage_stream.AdvancePointer(sizeof(damageZoneCount));
//
//~~~~~~~~~~~~~~~~~~~~~~~
// Create the DamageZones
//~~~~~~~~~~~~~~~~~~~~~~~
//
for(int ii=0;ii<damageZoneCount;++ii)
{
damageZones[ii] = new DamageZone(
this,
ii,
&damage_stream
);
Register_Object(damageZones[ii]);
}
SetValidFlag();
dmg_res->Unlock();
// BT_CULT_LOG: per-icon creation census (issue #3 -- truck destruction)
if (getenv("BT_CULT_LOG"))
{
DEBUG_STREAM << "[cult] made icon entity=" << (long)GetEntityID()
<< " res=" << resourceID
<< " zones=" << damageZoneCount
<< " explode=" << explosionResourceID
<< " crunch=" << crunchExplosionResourceID
<< " removeOnDeath=" << (int)RemoveCollisionVolumeOnDeath()
<< " stopping=" << (int)IsStoppingCollisionVolume()
<< " pos=(" << localOrigin.linearPosition.x
<< "," << localOrigin.linearPosition.y
<< "," << localOrigin.linearPosition.z << ")"
<< "\n" << std::flush;
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CulturalIcon::ReadUpdateRecord(Simulation::UpdateRecord *message)
{
Check(this);
Check_Pointer(message);
UnscalableTerrain::ReadUpdateRecord(message);
if (simulationState.GetOldState() != GetSimulationState() && (GetSimulationState() == BurningState))
{
UpdateCollisionVolumes();
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
CulturalIcon::CreateMakeMessage(
MakeMessage *creation_message,
NotationFile *model_file,
const ResourceDirectories *directories
)
{
Check(creation_message);
Check(model_file);
if (!UnscalableTerrain::CreateMakeMessage(creation_message, model_file, directories))
{
return False;
}
creation_message->messageLength = sizeof(MakeMessage);
creation_message->classToCreate = CulturalIconClassID;
creation_message->instanceFlags = MasterInstance|DynamicFlag|MapFlag|TrappedFlag;
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CulturalIcon*
CulturalIcon::Make(MakeMessage *creation_message)
{
Check_Fpu();
return new CulturalIcon(creation_message);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CulturalIcon::~CulturalIcon()
{
// live-icon census removal (swap-with-last; see the registration above)
for (int ii = 0; ii < gBTCultIconCount; ++ii)
{
if (gBTCultIcons[ii] == this)
{
gBTCultIcons[ii] = gBTCultIcons[--gBTCultIconCount];
break;
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
CulturalIcon::CreateModelResource(
#if DEBUG_LEVEL>0
ResourceFile *resource_file,
const char *model_name,
NotationFile *model_file,
const ResourceDirectories *directories,
ModelResource* model
#else
ResourceFile *resource_file,
const char *model_name,
NotationFile *model_file,
const ResourceDirectories *,
ModelResource* model
#endif
)
{
Check(resource_file);
Check_Pointer(model_name);
Check(model_file);
Check_Pointer(directories);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Allocate memory for the resource
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ModelResource *local_model = model;
if (!local_model)
{
local_model = new ModelResource;
Register_Pointer(local_model);
}
if (
!model_file->GetEntry(
"gamedata",
"DestroyedYTranslation",
&local_model->destroyedYTranslation
)
)
{
local_model->sinkCollisionVolume = False;
local_model->destroyedYTranslation = 0.0f;
}
else
{
local_model->sinkCollisionVolume = True;
}
if (!model_file->GetLogicalEntry(
"gamedata",
"StoppingCollisionVolume",
&local_model->stoppingCollisionVolume
)
)
{
local_model->stoppingCollisionVolume = False;
}
if (
!model_file->GetEntry(
"gamedata",
"TimeDelay",
&local_model->timeDelay
)
)
{
DEBUG_STREAM << model_name << " TimeDelay is missing " << std::endl << std::flush;
PostQuitMessage(AbortExitCodeID);
}
//
//----------------------------------------------------------------------
// Read in the Model Filename of the Explosion renderable, then find its
// resource ID in the resource file
//----------------------------------------------------------------------
//
const char *explosion = "Unspecified";
if (
!model_file->GetEntry(
"gamedata",
"ExplosionModelFile",
&explosion
)
)
{
std::cout << model_name << " missing ExplosionModelFile!\n";
Check_Fpu();
return False;
}
ResourceDescription *res = NULL;
if (strcmp(explosion,"Unspecified"))
{
res = resource_file->FindResourceDescription(
explosion,
ResourceDescription::ModelListResourceType
);
}
if (!res)
{
std::cout << model_name << " cannot find " << explosion
<< " in resource file!\n";
Check_Fpu();
return False;
}
if (res)
{
local_model->explosionResourceID = res->resourceID;
}
const char *crunch_explosion = "Unspecified";
model_file->GetEntry(
"gamedata",
"CrunchExplosionModelFile",
&crunch_explosion
);
local_model->crunchExplosionResourceID = -1;
if (strcmp(crunch_explosion,"Unspecified"))
{
//res = NULL;
res = resource_file->FindResourceDescription(
crunch_explosion,
ResourceDescription::ModelListResourceType
);
if (!res)
{
std::cout << model_name << " cannot find " << crunch_explosion
<< " in resource file!\n";
Check_Fpu();
return False;
}
else
{
local_model->crunchExplosionResourceID = res->resourceID;
}
}
//DEBUG_STREAM << ":" << local_model->crunchExplosionResourceID << std::endl << std::flush;
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Write the model to the resource
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
if (!model)
{
ResourceDescription *new_res =
resource_file->AddResource(
model_name,
ResourceDescription::GameModelResourceType,
1,
ResourceDescription::Preload,
local_model,
sizeof(*local_model)
);
Unregister_Pointer(local_model);
delete local_model;
Check(new_res);
Check_Fpu();
return new_res->resourceID;
}
else
{
Check_Fpu();
return 0;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
CulturalIcon::CreateDamageZoneStream(
ResourceFile *resource_file,
const char *model_name,
NotationFile *model_file,
const ResourceDirectories *directories
)
{
Check(resource_file);
Check_Pointer(model_name);
Check(model_file);
Check_Pointer(directories);
//
//-------------------
// Find the .dmg file
//-------------------
//
const char* dmg_file_cname;
if (
!model_file->GetEntry(
"gamedata",
"DamageZones",
&dmg_file_cname
)
)
{
std::cerr << model_name << " is missing .dmg file specification!\n";
return -1;
}
CString dmg_filename =
MakePathedFilename(directories->modelDirectory, dmg_file_cname);
NotationFile *dmg_file = new NotationFile(dmg_filename);
Register_Object(dmg_file);
int page_count = dmg_file->PageCount();
if (!page_count)
{
std::cerr << dmg_filename << " is empty or missing!\n";
Unregister_Object(dmg_file);
delete dmg_file;
return -1;
}
DynamicMemoryStream damage_stream;
damage_stream << page_count;
NameList *dmg_namelist = dmg_file->MakePageList();
Register_Object(dmg_namelist);
NameList::Entry *dmg_entry = dmg_namelist->GetFirstEntry();
CString dmg_page_name;
while(dmg_entry)
{
dmg_page_name = dmg_entry->GetName();
DamageZone::CreateStreamedDamageZone(
model_file,
model_name,
NULL,
dmg_page_name,
&damage_stream,
dmg_file,
directories
);
dmg_entry = dmg_entry->GetNextEntry();
}
//
//~~~~~~~~~~~~~~~~~~~~~~~
// Add Stream to Resource
//~~~~~~~~~~~~~~~~~~~~~~~
//
ResourceDescription *new_res =
resource_file->AddResourceMemoryStream(
model_name,
ResourceDescription::DamageZoneStreamResourceType,
1,
ResourceDescription::Preload,
&damage_stream
);
Check(new_res);
Unregister_Object(dmg_file);
delete dmg_file;
Unregister_Object(dmg_namelist);
delete dmg_namelist;
return new_res->resourceID;
}
//##########################################################################
//#################### Class Landmark ##########################
//##########################################################################
//#############################################################################
// Shared Data Support
//
Derivation* Landmark::GetClassDerivations()
{ static Derivation classDerivations(CulturalIcon::GetClassDerivations(), "Landmark");
return &classDerivations;
}
Landmark::SharedData
Landmark::DefaultData(
Landmark::GetClassDerivations(),
Landmark::MessageHandlers,
Landmark::GetAttributeIndex(),
Landmark::StateCount,
(Landmark::MakeHandler)Landmark::Make
);
//#############################################################################
// Message Support
//
const Receiver::HandlerEntry
Landmark::MessageHandlerEntries[]=
{
MESSAGE_ENTRY(Landmark, TakeDamage)
};
Landmark::MessageHandlerSet
Landmark::MessageHandlers(
ELEMENTS(Landmark::MessageHandlerEntries),
Landmark::MessageHandlerEntries,
CulturalIcon::GetMessageHandlers()
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Landmark::TakeDamageMessageHandler(TakeDamageMessage *damage_message)
{
Check(damage_message);
if (owningTeam == NULL)
{
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Initialize the owning team pointer
// with the Teams entity Group
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Check(application);
EntityManager *entity_manager = application->GetEntityManager();
Check(entity_manager);
EntityGroup *team_group = entity_manager->UseGroup("Teams");
if (team_group)
{
ChainIteratorOf<Node*> team_iterator(team_group->groupMembers);
Team *current_team;
while((current_team = (Team*) team_iterator.ReadAndNext() ) != NULL)
{
if (!strcmp(current_team->teamName, teamName))
{
owningTeam = current_team;
break;
}
}
}
}
if (owningTeam == NULL)
{
DEBUG_STREAM << "TEAM : '" << teamName << "' was never found! " << std::endl << std::flush;
exit (-1);
}
if (GetSimulationState() != BurningState)
{
CulturalIcon::TakeDamageMessageHandler(damage_message);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Calculate the Score Loss based
// on the Scenario Data
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Check(scenarioRole);
#if 0
Logical landmark_destroyed = GetSimulationState() == BurningState;
Scalar score_loss = scenarioRole->CalcDamageReceivedScore(
damage_message->damageData.damageAmount
);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Tell the Console about the Damage
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Check(application);
HostManager *host_manager = application->GetHostManager();
Check(host_manager);
Host *console_host = host_manager->GetConsoleHost();
if (console_host)
{
Check(console_host);
ConsoleLandmarkDamagedMessage landmark_damaged_message(
damage_message->inflictingEntity.GetHostID(),
landmarkID,
damage_message->damageData.damageAmount,
landmark_destroyed,
score_loss
);
application->SendMessage(
console_host->GetHostID(),
NetworkClient::ConsoleClientID,
&landmark_damaged_message
);
}
#endif
}
}
Logical
CulturalIcon::TestInstance() const
{
return IsDerivedFrom(*GetClassDerivations());
}
//#############################################################################
// Construction and Destruction
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Landmark::Landmark(
MakeMessage *creation_message,
SharedData &shared_data
) :
CulturalIcon ( creation_message, shared_data)
{
scenarioRole = NULL;
owningTeam = NULL;
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Initialize the owning team pointer
// with the Teams entity Group
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Check(application);
EntityManager *entity_manager = application->GetEntityManager();
Check(entity_manager);
EntityGroup *team_group = entity_manager->UseGroup("Teams");
if (team_group)
{
ChainIteratorOf<Node*> team_iterator(team_group->groupMembers);
Team *current_team;
while((current_team = (Team*) team_iterator.ReadAndNext() ) != NULL)
{
if (!strcmp(current_team->teamName, creation_message->teamName))
{
owningTeam = current_team;
break;
}
}
}
//
// If the team is null, that's ok. It will either show up over the network
// or be a free for all
//
Str_Copy(teamName, creation_message->teamName, sizeof(teamName));
Check(application->GetCurrentMission());
scenarioRole =
application->GetCurrentMission()->GetScenarioRole(creation_message->roleName);
if (!scenarioRole)
{
scenarioRole = new ScenarioRole("Role::MapAssigned",creation_message->roleName);
Register_Object(scenarioRole);
application->GetCurrentMission()->AddScenarioRole(scenarioRole);
}
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Add this landmark to the Landmark Entity Group
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
EntityGroup *landmark_group = entity_manager->UseGroup("Landmarks");
Check(landmark_group);
landmark_group->Add(this);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Landmark::~Landmark()
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
Landmark::CreateMakeMessage(
MakeMessage *creation_message,
NotationFile *model_file,
const ResourceDirectories *directories
)
{
Check(creation_message);
Check(model_file);
if (!CulturalIcon::CreateMakeMessage(creation_message, model_file, directories))
{
return False;
}
creation_message->messageLength = sizeof(MakeMessage);
creation_message->classToCreate = LandmarkClassID;
char *p;
//
//----------------------------
// landmarkID allocated
// by map stream creation
//----------------------------
//
//
//~~~~~~~~~~~~~~~
// Get the teamName
//~~~~~~~~~~~~~~~
//
if ((p = strtok(NULL, ",")) == NULL)
{
std::cerr << "teamName missing!\n";
return False;
}
Str_Copy(creation_message->teamName,p, sizeof(creation_message->teamName));
//
//~~~~~~~~~~~~~~~~~
// Get the roleName
//~~~~~~~~~~~~~~~~~
//
if ((p = strtok(NULL, ",")) == NULL)
{
std::cerr << "roleName missing!\n";
return False;
}
Str_Copy(creation_message->roleName,p, sizeof(creation_message->roleName));
//
//~~~~~~~~~~~~~~~~~~~~~~
// Get the Landmark Name
//~~~~~~~~~~~~~~~~~~~~~~
//
if ((p = strtok(NULL, ",")) == NULL)
{
std::cerr << "Landmark Name missing!\n";
return False;
}
Str_Copy(creation_message->landmarkName,p, sizeof(creation_message->landmarkName));
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Landmark*
Landmark::Make(MakeMessage *creation_message)
{
Check_Fpu();
return new Landmark(creation_message);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
Landmark::CreateModelResource(
ResourceFile *resource_file,
const char *model_name,
NotationFile *model_file,
const ResourceDirectories *directories,
ModelResource* model
)
{
Check(resource_file);
Check_Pointer(model_name);
Check(model_file);
Check_Pointer(directories);
CulturalIcon::CreateModelResource(resource_file, model_name, model_file, directories, model);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Allocate memory for the resource
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ModelResource *local_model = model;
if (!local_model)
{
local_model = new ModelResource;
Register_Pointer(local_model);
}
#if 0
const char *role_model_file;
if (!model_file->GetEntry(
"gamedata",
"RoleModelFile",
&role_model_file
)
)
{
std::cerr<<model_name<<" missing RoleModelFile ! \n"<<std::endl;
Dump_And_Die:
if (local_model)
{
Unregister_Pointer(local_model);
delete local_model;
}
return -1;
}
else
{
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Hunt for Model file in ResourceFile
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ResourceDescription *res;
res = resource_file->FindResourceDescription(
role_model_file,
ResourceDescription::ModelListResourceType
);
if (!res)
{
std::cout << model_name << " cannot find " << role_model_file
<< " in resource file!\n";
goto Dump_And_Die;
}
local_model->roleResourceID = res->resourceID;
}
#endif
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Write the model to the resource
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
if (!model)
{
ResourceDescription *new_res =
resource_file->AddResource(
model_name,
ResourceDescription::GameModelResourceType,
1,
ResourceDescription::Preload,
local_model,
sizeof(*local_model)
);
Unregister_Pointer(local_model);
delete local_model;
Check(new_res);
Check_Fpu();
return new_res->resourceID;
}
else
{
Check_Fpu();
return 0;
}
}
Logical
Landmark::TestInstance() const
{
return IsDerivedFrom(*GetClassDerivations());
}