Complete disaster-recovery snapshot: engine/game source, game data assets, VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive. Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false, no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
1246 lines
35 KiB
C++
1246 lines
35 KiB
C++
#include "MW4Headers.hpp"
|
|
|
|
#include "MWObject.hpp"
|
|
#include "Subsystem.hpp"
|
|
#include "Torso.hpp"
|
|
#include "MWDamageObject.hpp"
|
|
#include "HeatManager.hpp"
|
|
#include "gameinfo.hpp"
|
|
#include "MWApplication.hpp"
|
|
|
|
#include <MissionLang\Resource.h>
|
|
|
|
#include <Adept\Tool.hpp>
|
|
#include <Adept\EntityManager.hpp>
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
int MWObject__GameModel::ConvertStringToMoveType (const char *str)
|
|
{
|
|
if (!str)
|
|
return NONE_MOVETYPE;
|
|
if (!stricmp (str,"LEGMOVETYPE"))
|
|
return LEG_MOVETYPE;
|
|
if (!stricmp (str,"LEGJUMPMOVETYPE"))
|
|
return LEGJUMP_MOVETYPE;
|
|
if (!stricmp (str,"TRACKMOVETYPE"))
|
|
return TRACK_MOVETYPE;
|
|
if (!stricmp (str,"WHEELMOVETYPE"))
|
|
return WHEEL_MOVETYPE;
|
|
if (!stricmp (str,"FLYERMOVETYPE"))
|
|
return FLYER_MOVETYPE;
|
|
if (!stricmp (str,"HOVERMOVETYPE"))
|
|
return HOVER_MOVETYPE;
|
|
if (!stricmp (str,"HELIMOVETYPE"))
|
|
return HELI_MOVETYPE;
|
|
if (!stricmp (str,"DROPSHIPMOVETYPE"))
|
|
return DROPSHIP_MOVETYPE;
|
|
if (!stricmp (str,"WATERMOVETYPE"))
|
|
return WATER_MOVETYPE;
|
|
gosREPORT (false,"Unknown movement type in MWObject gamemodel");
|
|
return NONE_MOVETYPE;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject__CreateMessage::ConstructCreateMessage(Script *script)
|
|
{
|
|
Check_Object(script);
|
|
#if defined(_ARMOR)
|
|
int stack_level = Tool::Instance->GetStackLevel();
|
|
#endif
|
|
#ifdef LAB_ONLY
|
|
strcpy(MWGameInfo::g_ResourceFile, (char *)(script->instancePage->GetNotationFile()->GetFileName()));
|
|
strcpy(MWGameInfo::g_ResourceEntry, (char *)(script->instancePage->GetName()));
|
|
#endif
|
|
|
|
//
|
|
//--------------
|
|
// Set up stream
|
|
//--------------
|
|
//
|
|
MemoryStream *message_stream = script->messageStream;
|
|
Check_Object(message_stream);
|
|
message_stream->AllocateBytes(sizeof(MWObject__CreateMessage));
|
|
BaseClass::ConstructCreateMessage(script);
|
|
MWObject__CreateMessage *message =
|
|
Cast_Pointer(
|
|
MWObject__CreateMessage*,
|
|
message_stream->GetPointer()
|
|
);
|
|
message->messageLength = sizeof(*message);
|
|
|
|
//
|
|
//---------------------------------------------------------------
|
|
// Point at the notation file and make other files relative to it
|
|
//---------------------------------------------------------------
|
|
//
|
|
Page *instance_page = script->instancePage;
|
|
Check_Object(instance_page);
|
|
NotationFile *instance_file = instance_page->GetNotationFile();
|
|
Check_Object(instance_file);
|
|
Check_Object(Tool::Instance);
|
|
Tool::Instance->PushFilePath(instance_file);
|
|
Check_Object(Resource::ParentFileDependencies);
|
|
|
|
//
|
|
//--------------------------------------
|
|
// Make sure that no armature exists yet
|
|
//--------------------------------------
|
|
//
|
|
{
|
|
Verify(!message->armatureStreamResourceID);
|
|
NotationFile armatures_file;
|
|
if (instance_page->GetEntry("Armature", &armatures_file))
|
|
{
|
|
const char* armatures_filename = armatures_file.GetFileName();
|
|
|
|
//
|
|
//------------------------------------------------------------------
|
|
// Look for the armature stream resource to see if it is up to date
|
|
//------------------------------------------------------------------
|
|
//
|
|
Resource armature_resource(armatures_filename);
|
|
if (
|
|
armature_resource.DoesResourceExist() &&
|
|
armature_resource.IsResourceUpToDate()
|
|
)
|
|
{
|
|
WORD span;
|
|
armature_resource.LoadData();
|
|
armature_resource >> span;
|
|
Verify(span > 0);
|
|
*script->baseID += span;
|
|
message->armatureStreamResourceID = armature_resource.GetResourceID();
|
|
message->replicatorID += span;
|
|
if (!armature_resource.IsRegistered())
|
|
armature_resource.AddFileDependenciesTo(Resource::ParentFileDependencies);
|
|
}
|
|
|
|
//
|
|
//------------------------------------------------
|
|
// For each instance_page, an entity will be built
|
|
//------------------------------------------------
|
|
//
|
|
else
|
|
{
|
|
FileDependencies arm_deps(*armatures_file.GetFileDependencies());
|
|
FileDependencies *parent = Resource::ParentFileDependencies;
|
|
Resource::ParentFileDependencies = &arm_deps;
|
|
Tool::Instance->PushFilePath(&armatures_file);
|
|
DynamicMemoryStream armature_stream;
|
|
armature_stream << static_cast<WORD>(0);
|
|
ReplicatorID starting_id = *script->baseID;
|
|
NotationFile::PageIterator *instance_names = armatures_file.MakePageIterator();
|
|
Check_Object(instance_names);
|
|
Page *instance;
|
|
while ((instance = instance_names->ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(instance);
|
|
|
|
//
|
|
//-----------------------------------------
|
|
// Create the entity for this instance_page
|
|
//-----------------------------------------
|
|
//
|
|
bool on_root = false;
|
|
instance->GetEntry("AttachedToRoot", &on_root);
|
|
if (on_root)
|
|
{
|
|
Entity::CreateMessage *message =
|
|
Tool::Instance->ConstructCreateMessage(
|
|
&armature_stream,
|
|
instance,
|
|
script->baseID
|
|
);
|
|
Check_Object(message);
|
|
armature_stream.AdvancePointer(message->messageLength);
|
|
}
|
|
}
|
|
|
|
//
|
|
//-----------------------------------------
|
|
// Only save out the stream if there is one
|
|
//-----------------------------------------
|
|
//
|
|
if (armature_stream.GetBytesUsed() > sizeof(WORD))
|
|
{
|
|
armature_stream.Rewind();
|
|
Verify(*script->baseID != starting_id);
|
|
WORD span =
|
|
static_cast<WORD>(script->baseID->localID - starting_id.localID);
|
|
armature_stream << span;
|
|
armature_resource.Save(&armature_stream, &arm_deps);
|
|
Check_Object(&armature_resource);
|
|
message->armatureStreamResourceID = armature_resource.GetResourceID();
|
|
message->replicatorID += span;
|
|
}
|
|
else
|
|
message->armatureStreamResourceID = ResourceID::Null;
|
|
if (!armature_resource.IsRegistered())
|
|
parent->AddDependencies(&arm_deps);
|
|
Resource::ParentFileDependencies = parent;
|
|
|
|
//
|
|
//------------------------
|
|
// Clean up the tool stack
|
|
//------------------------
|
|
//
|
|
Check_Object(instance_names);
|
|
delete instance_names;
|
|
Tool::Instance->PopFilePath();
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
//------------------------------------------------------------
|
|
// Create messages for the subsystem stream only if it's there
|
|
//------------------------------------------------------------
|
|
//
|
|
{
|
|
NotationFile subsystems_file;
|
|
message->subsystemStreamResourceID = ResourceID::Null;
|
|
if (instance_page->GetEntry("Subsystems", &subsystems_file))
|
|
{
|
|
const char *subsystems_filename = subsystems_file.GetFileName();
|
|
Check_Pointer(subsystems_filename);
|
|
|
|
//
|
|
//------------------------------------------------------------------
|
|
// Look for the subsystem stream resource to see if it is up to date
|
|
//------------------------------------------------------------------
|
|
//
|
|
Resource subsystem_resource(subsystems_filename);
|
|
if (
|
|
subsystem_resource.DoesResourceExist() &&
|
|
subsystem_resource.IsResourceUpToDate()
|
|
)
|
|
{
|
|
subsystem_resource.LoadData();
|
|
WORD span;
|
|
subsystem_resource >> span;
|
|
Verify(span > 0);
|
|
*script->baseID += span;
|
|
message->subsystemStreamResourceID = subsystem_resource.GetResourceID();
|
|
message->replicatorID += span;
|
|
if (!subsystem_resource.IsRegistered())
|
|
subsystem_resource.AddFileDependenciesTo(Resource::ParentFileDependencies);
|
|
}
|
|
|
|
else
|
|
{
|
|
//
|
|
//---------------------------------------
|
|
// For each instance_page, an entity will be built
|
|
//---------------------------------------
|
|
//
|
|
FileDependencies sub_deps(*subsystems_file.GetFileDependencies());
|
|
FileDependencies *parent = Resource::ParentFileDependencies;
|
|
Resource::ParentFileDependencies = &sub_deps;
|
|
Tool::Instance->PushFilePath(&subsystems_file);
|
|
DynamicMemoryStream subsystem_stream(sizeof(WORD));
|
|
subsystem_stream << static_cast<WORD>(0);
|
|
ReplicatorID starting_id = *script->baseID;
|
|
NotationFile::PageIterator *instance_names = subsystems_file.MakePageIterator();
|
|
Check_Object(instance_names);
|
|
Page *instance;
|
|
while ((instance = instance_names->ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(instance);
|
|
|
|
//
|
|
//--------------------------------
|
|
// Create the entity for this instance_page
|
|
//--------------------------------
|
|
//
|
|
Entity::CreateMessage *message =
|
|
Tool::Instance->ConstructCreateMessage(
|
|
&subsystem_stream,
|
|
instance,
|
|
script->baseID
|
|
);
|
|
Check_Object(message);
|
|
subsystem_stream.AdvancePointer(message->messageLength);
|
|
}
|
|
|
|
//
|
|
//-----------------------------------------
|
|
// Only save out the stream if there is one
|
|
//-----------------------------------------
|
|
//
|
|
if (subsystem_stream.GetBytesUsed() > sizeof(WORD))
|
|
{
|
|
subsystem_stream.Rewind();
|
|
Verify(*script->baseID != starting_id);
|
|
WORD span =
|
|
static_cast<WORD>(script->baseID->localID - starting_id.localID);
|
|
subsystem_stream << span;
|
|
subsystem_resource.Save(&subsystem_stream, &sub_deps);
|
|
Check_Object(&subsystem_resource);
|
|
message->subsystemStreamResourceID = subsystem_resource.GetResourceID();
|
|
message->replicatorID += span;
|
|
}
|
|
else
|
|
message->subsystemStreamResourceID = ResourceID::Null;
|
|
if (!subsystem_resource.IsRegistered())
|
|
parent->AddDependencies(&sub_deps);
|
|
Resource::ParentFileDependencies = parent;
|
|
|
|
//
|
|
//------------------------
|
|
// Clean up the tool stack
|
|
//------------------------
|
|
//
|
|
Check_Object(instance_names);
|
|
delete instance_names;
|
|
Tool::Instance->PopFilePath();
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
//----------------------------------------------------------
|
|
// Create messages a damage object stream only if it's there
|
|
//----------------------------------------------------------
|
|
//
|
|
{
|
|
NotationFile damage_file;
|
|
message->damageStreamResourceID = ResourceID::Null;
|
|
if (instance_page->GetEntry("DamageObjects", &damage_file))
|
|
{
|
|
Check_Object(Tool::Instance);
|
|
const char* damage_filename = damage_file.GetFileName();
|
|
Check_Pointer(damage_filename);
|
|
|
|
//
|
|
//---------------------------------------------------------------
|
|
// Look for the damage stream resource to see if it is up to date
|
|
//---------------------------------------------------------------
|
|
//
|
|
Resource damage_resource(damage_filename);
|
|
if (
|
|
damage_resource.DoesResourceExist() &&
|
|
damage_resource.IsResourceUpToDate()
|
|
)
|
|
{
|
|
message->damageStreamResourceID = damage_resource.GetResourceID();
|
|
if (!damage_resource.IsRegistered())
|
|
damage_resource.AddFileDependenciesTo(Resource::ParentFileDependencies);
|
|
}
|
|
|
|
else
|
|
{
|
|
|
|
//
|
|
//---------------------------------------
|
|
// For each instance_page, an entity will be built
|
|
//---------------------------------------
|
|
//
|
|
FileDependencies damage_deps(*damage_file.GetFileDependencies());
|
|
FileDependencies *parent = Resource::ParentFileDependencies;
|
|
Resource::ParentFileDependencies = &damage_deps;
|
|
Tool::Instance->PushFilePath(&damage_file);
|
|
DynamicMemoryStream damage_stream;
|
|
NotationFile::PageIterator *damage_names = damage_file.MakePageIterator();
|
|
Check_Object(damage_names);
|
|
Page *damage_instance;
|
|
|
|
//
|
|
//---------------------------------------
|
|
// Create the damage Object for this instance_page
|
|
//---------------------------------------
|
|
//
|
|
while ((damage_instance = damage_names->ReadAndNext()) != NULL)
|
|
{
|
|
|
|
//
|
|
//-------------------------------------------------------
|
|
//Check to see if we are internal or just a damage object
|
|
//-------------------------------------------------------
|
|
//
|
|
int damage_zone;
|
|
if (!damage_instance->GetEntry("DamageZone", &damage_zone))
|
|
{
|
|
DamageObject::ConstructDamageObjectStream(
|
|
&damage_stream,
|
|
damage_instance
|
|
);
|
|
}
|
|
else
|
|
{
|
|
MWInternalDamageObject::ConstructMWInternalDamageObjectStream(
|
|
&damage_stream,
|
|
damage_instance
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
//-----------------------------------------
|
|
// Only save out the stream if there is one
|
|
//-----------------------------------------
|
|
//
|
|
if (damage_stream.GetBytesUsed())
|
|
{
|
|
damage_resource.Save(
|
|
&damage_stream,
|
|
&damage_deps
|
|
);
|
|
if (!damage_resource.IsRegistered())
|
|
parent->AddDependencies(&damage_deps);
|
|
Check_Object(&damage_resource);
|
|
message->damageStreamResourceID = damage_resource.GetResourceID();
|
|
}
|
|
else
|
|
message->damageStreamResourceID = ResourceID::Null;
|
|
Resource::ParentFileDependencies = parent;
|
|
|
|
//------------------------
|
|
// Clean up the tool stack
|
|
//------------------------
|
|
//
|
|
Check_Object(damage_names);
|
|
delete damage_names;
|
|
Tool::Instance->PopFilePath();
|
|
}
|
|
}
|
|
}
|
|
|
|
const char *skin_name;
|
|
message->skinPrefix = DefaultSkinPrefix;
|
|
if(instance_page->GetEntry("Skin", &skin_name))
|
|
message->skinPrefix = *skin_name;
|
|
|
|
message->teamDecal = 0;
|
|
instance_page->GetEntry("TeamDecal", &message->teamDecal);
|
|
|
|
message->pilotDecal = 0;
|
|
instance_page->GetEntry("PilotDecal", &message->pilotDecal);
|
|
|
|
message->nameIndex = -1;
|
|
instance_page->GetEntry("NameIndex", &message->nameIndex);
|
|
|
|
message->doesHaveInstanceName = false;
|
|
instance_page->GetEntry("DoesHaveInstanceName", &message->doesHaveInstanceName);
|
|
|
|
Tool::Instance->PopFilePath();
|
|
Verify(stack_level == Tool::Instance->GetStackLevel());
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject__GameModel::ConstructGameModel(Script *script)
|
|
{
|
|
Check_Object(script);
|
|
#if defined(_ARMOR)
|
|
int stack_level = Tool::Instance->GetStackLevel();
|
|
#endif
|
|
|
|
//
|
|
//--------------
|
|
// Set up stream
|
|
//--------------
|
|
//
|
|
MemoryStream *model_stream = script->modelStream;
|
|
Check_Object(model_stream);
|
|
model_stream->AllocateBytes(sizeof(MWObject__GameModel));
|
|
BaseClass::ConstructGameModel(script);
|
|
|
|
MWObject__GameModel *model =
|
|
Cast_Pointer(MWObject__GameModel*, model_stream->GetPointer());
|
|
|
|
|
|
NotationFile *model_file = script->modelFile;
|
|
Check_Object(model_file);
|
|
|
|
const char *temp_name = NULL;
|
|
Page *game_page = model_file->GetPage("GameData");
|
|
Check_Object(game_page);
|
|
game_page->GetEntry("AnimationScript", &temp_name);
|
|
|
|
model->animScriptName[0] = NULL;
|
|
|
|
if (temp_name != NULL)
|
|
{
|
|
Str_Copy(model->animScriptName, temp_name, sizeof(model->animScriptName));
|
|
}
|
|
|
|
const char *str = NULL;
|
|
game_page->GetEntry("MoveTypeFlag",&str);
|
|
model->moveTypeFlag = ConvertStringToMoveType (str);
|
|
|
|
//
|
|
//---------------------------------------------
|
|
//Create the array of Damage Effect ResourceIDs
|
|
//---------------------------------------------
|
|
//
|
|
model->idleEffectResourceID = ResourceID::Null;
|
|
NotationFile effects_file;
|
|
if(game_page->GetEntry("IdleEffectsFile", &effects_file))
|
|
{
|
|
const char *effects_file_name = effects_file.GetFileName();
|
|
Check_Pointer(effects_file_name);
|
|
|
|
//
|
|
//------------------------------------------------------------------
|
|
// Look for the subsystem stream resource to see if it is up to date
|
|
//------------------------------------------------------------------
|
|
//
|
|
Resource effects_resource(effects_file_name);
|
|
if (
|
|
effects_resource.DoesResourceExist() &&
|
|
effects_resource.IsResourceUpToDate()
|
|
)
|
|
{
|
|
model->idleEffectResourceID = effects_resource.GetResourceID();
|
|
if (!effects_resource.IsRegistered())
|
|
effects_resource.AddFileDependenciesTo(Resource::ParentFileDependencies);
|
|
}
|
|
|
|
else
|
|
{
|
|
//
|
|
//---------------------------------------
|
|
// For each page, an entity will be built
|
|
//---------------------------------------
|
|
//
|
|
FileDependencies effect_deps(*effects_file.GetFileDependencies());
|
|
FileDependencies *parent = Resource::ParentFileDependencies;
|
|
Resource::ParentFileDependencies = &effect_deps;
|
|
Tool::Instance->PushFilePath(&effects_file);
|
|
DynamicMemoryStream effects_stream;
|
|
NotationFile::PageIterator *instance_names = effects_file.MakePageIterator();
|
|
Check_Object(instance_names);
|
|
Page *instance;
|
|
while ((instance = instance_names->ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(instance);
|
|
|
|
//
|
|
//--------------------------------
|
|
// Create the entity for this page
|
|
//--------------------------------
|
|
//
|
|
|
|
//First get and create the effect resource and store the ID
|
|
const char* effect_file;
|
|
instance->GetEntry("EffectFile", &effect_file, true);
|
|
Resource effect_entry_resource;
|
|
Tool::Instance->ConstructDataList(&effect_entry_resource, effect_file);
|
|
Check_Object(&effect_entry_resource);
|
|
Verify(effect_entry_resource.DoesResourceExist());
|
|
effects_stream << effect_entry_resource.GetResourceID();
|
|
|
|
//Next read in the site name and store it
|
|
const char *site_name;
|
|
MString site_string;
|
|
instance->GetEntry("SiteName", &site_name);
|
|
Check_Pointer(site_name);
|
|
site_string = site_name;
|
|
effects_stream << site_string;
|
|
}
|
|
|
|
//
|
|
//-----------------------------------------
|
|
// Only save out the stream if there is one
|
|
//-----------------------------------------
|
|
//
|
|
if (effects_stream.GetBytesUsed() > 0)
|
|
{
|
|
effects_resource.Save(&effects_stream, &effect_deps);
|
|
if (!effects_resource.IsRegistered())
|
|
parent->AddDependencies(&effect_deps);
|
|
Check_Object(&effects_resource);
|
|
model->idleEffectResourceID = effects_resource.GetResourceID();
|
|
}
|
|
else
|
|
model->idleEffectResourceID = ResourceID::Null;
|
|
Resource::ParentFileDependencies = parent;
|
|
|
|
//
|
|
//------------------------
|
|
// Clean up the tool stack
|
|
//------------------------
|
|
//
|
|
Check_Object(instance_names);
|
|
delete instance_names;
|
|
Tool::Instance->PopFilePath();
|
|
}
|
|
}
|
|
|
|
Verify(stack_level == Tool::Instance->GetStackLevel());
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject__GameModel::ConstructOBBStream(Script *script)
|
|
{
|
|
Check_Object(script);
|
|
Check_Object(Resource::ParentFileDependencies);
|
|
|
|
//
|
|
//--------------
|
|
// Set up stream
|
|
//--------------
|
|
//
|
|
MemoryStream *model_stream = script->modelStream;
|
|
Check_Object(model_stream);
|
|
MWObject__GameModel *model =
|
|
Cast_Pointer(MWObject__GameModel*, model_stream->GetPointer());
|
|
|
|
//
|
|
//------------------------------
|
|
// See if there is an OBB stream
|
|
//------------------------------
|
|
//
|
|
NotationFile *model_file = script->modelFile;
|
|
Check_Object(model_file);
|
|
Page *game_page = model_file->GetPage("GameData");
|
|
Check_Object(game_page);
|
|
const char* obb_stream_name;
|
|
|
|
//
|
|
//---------------------------------------------------
|
|
// If there is a solid OBB, store it in the resources
|
|
//---------------------------------------------------
|
|
//
|
|
model->obbStreamResourceID = ResourceID::Null;
|
|
if (game_page->GetEntry("SolidOBB", &obb_stream_name))
|
|
{
|
|
Check_Pointer(obb_stream_name);
|
|
FileStream solid_stream(obb_stream_name);
|
|
MString file_name = model_file->GetFileName();
|
|
file_name += "{SolidOBB}";
|
|
Resource obb_res(file_name);
|
|
if (!obb_res.DoesResourceExist() || !obb_res.IsResourceUpToDate())
|
|
{
|
|
FileDependencies obb_dependencies;
|
|
obb_dependencies.AddDependency(&solid_stream);
|
|
obb_res.Save(&solid_stream, &obb_dependencies);
|
|
if (!obb_res.IsRegistered())
|
|
obb_res.AddFileDependenciesTo(Resource::ParentFileDependencies);
|
|
}
|
|
else if (!obb_res.IsRegistered())
|
|
obb_res.AddFileDependenciesTo(Resource::ParentFileDependencies);
|
|
|
|
model->obbStreamResourceID = obb_res.GetResourceID();
|
|
}
|
|
|
|
//
|
|
//----------------------------------------------------------
|
|
// If there is a hierarchical OBB, store it in the resources
|
|
//----------------------------------------------------------
|
|
//
|
|
model->hierarchicalOBBStreamResourceID = ResourceID::Null;
|
|
if (game_page->GetEntry("HierarchicalOBB", &obb_stream_name))
|
|
{
|
|
Check_Pointer(obb_stream_name);
|
|
FileStream solid_stream(obb_stream_name);
|
|
MString file_name = model_file->GetFileName();
|
|
file_name += "{HierarchicalOBB}";
|
|
Resource obb_res(file_name);
|
|
if (!obb_res.DoesResourceExist() || !obb_res.IsResourceUpToDate())
|
|
{
|
|
FileDependencies obb_dependencies;
|
|
obb_dependencies.AddDependency(&solid_stream);
|
|
obb_res.Save(&solid_stream, &obb_dependencies);
|
|
if (!obb_res.IsRegistered())
|
|
obb_res.AddFileDependenciesTo(Resource::ParentFileDependencies);
|
|
}
|
|
else if (!obb_res.IsRegistered())
|
|
obb_res.AddFileDependenciesTo(Resource::ParentFileDependencies);
|
|
|
|
model->hierarchicalOBBStreamResourceID = obb_res.GetResourceID();
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
MWObject__GameModel::ReadAndVerify(
|
|
MWObject__GameModel *model,
|
|
ModelAttributeEntry *attribute_entry,
|
|
const char *data,
|
|
char **error,
|
|
int error_buffer
|
|
)
|
|
{
|
|
Check_Object(attribute_entry);
|
|
|
|
bool result = false;
|
|
bool valid_data = (*data != '\0');
|
|
|
|
//
|
|
//----------------------------------------
|
|
//Read in the values from the data entered
|
|
//----------------------------------------
|
|
//
|
|
result =
|
|
BaseClass::ReadAndVerify(
|
|
model,
|
|
attribute_entry,
|
|
data,
|
|
error,
|
|
error_buffer
|
|
);
|
|
//
|
|
//---------------------------
|
|
//Verify all the model values
|
|
//---------------------------
|
|
//
|
|
switch(attribute_entry->attributeID)
|
|
{
|
|
|
|
case DestroyedEffectResourceAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
ResourceID value = ResourceID::Null;
|
|
attribute_entry->SetValue(model, (void *)&value);
|
|
result = true;
|
|
}
|
|
break;
|
|
}
|
|
case DeathEntityResourceAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
ResourceID value = ResourceID::Null;
|
|
attribute_entry->SetValue(model, (void *)&value);
|
|
result = true;
|
|
}
|
|
break;
|
|
}
|
|
case SecondaryDestroyedEffectResourceAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
ResourceID value = ResourceID::Null;
|
|
attribute_entry->SetValue(model, (void *)&value);
|
|
result = true;
|
|
}
|
|
break;
|
|
}
|
|
case SecondaryDeathEntityResourceAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
ResourceID value = ResourceID::Null;
|
|
attribute_entry->SetValue(model, (void *)&value);
|
|
result = true;
|
|
}
|
|
break;
|
|
}
|
|
case VehicleTonnageAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
Scalar value = 1.0f;
|
|
attribute_entry->SetValue(model, &value);
|
|
result = true;
|
|
}
|
|
if(model->vehicleTonnage < 0.0f)
|
|
{
|
|
_snprintf(
|
|
*error,
|
|
error_buffer,
|
|
"{[GameData]VehicleTonnage=%f}: value must be >= 0!",
|
|
model->vehicleTonnage
|
|
);
|
|
result = false;
|
|
}
|
|
break;
|
|
}
|
|
case MaxVehicleTonnageAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
Scalar value = 500.0f;
|
|
attribute_entry->SetValue(model, &value);
|
|
result = true;
|
|
}
|
|
if(model->maxVehicleTonnage < 0.0f)
|
|
{
|
|
_snprintf(
|
|
*error,
|
|
error_buffer,
|
|
"{[GameData]MaxVehicleTonnage=%f}: value must be >= 0!",
|
|
model->maxVehicleTonnage
|
|
);
|
|
result = false;
|
|
}
|
|
break;
|
|
}
|
|
case EyeSiteNameAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
char *value;
|
|
value = new char[MaxStringLength];
|
|
Register_Pointer(value);
|
|
Str_Copy(value, "site_eyepoint", MaxStringLength);
|
|
attribute_entry->SetValue(model, value);
|
|
result = true;
|
|
Unregister_Pointer(value);
|
|
delete value;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case PartDestructionEffectResourceAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
ResourceID value = ResourceID::Null;
|
|
attribute_entry->SetValue(model, (void *)&value);
|
|
result = true;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SplashDamageRadiusAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
Scalar value = 1.0f;
|
|
attribute_entry->SetValue(model, &value);
|
|
result = true;
|
|
}
|
|
if(model->splashDamageRadius < 0.0f)
|
|
{
|
|
_snprintf(
|
|
*error,
|
|
error_buffer,
|
|
"{[GameData]SplashDamageRadius=%f}: value must be > 0!",
|
|
model->splashDamageRadius
|
|
);
|
|
result = false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SplashDamageAmountAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
Scalar value = 1.0f;
|
|
attribute_entry->SetValue(model, &value);
|
|
result = true;
|
|
}
|
|
if(model->splashDamageAmount < 0.0f)
|
|
{
|
|
_snprintf(
|
|
*error,
|
|
error_buffer,
|
|
"{[GameData]SplashDamageAmount=%f}: value must be > 0!",
|
|
model->splashDamageAmount
|
|
);
|
|
result = false;
|
|
}
|
|
break;
|
|
}
|
|
case VehicleBattleValueAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
int value = 0;
|
|
attribute_entry->SetValue(model, &value);
|
|
result = true;
|
|
}
|
|
if(model->vehicleBattleValue < 0)
|
|
{
|
|
_snprintf(
|
|
*error,
|
|
error_buffer,
|
|
"{[GameData]VehicleBattleValue=%f}: value must be >= 0!",
|
|
model->vehicleBattleValue
|
|
);
|
|
result = false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case CoolantEffectResourceAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
ResourceID value = ResourceID::Null;
|
|
attribute_entry->SetValue(model, (void *)&value);
|
|
result = true;
|
|
}
|
|
break;
|
|
}
|
|
case OverHeatEffectResourceAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
ResourceID value = ResourceID::Null;
|
|
attribute_entry->SetValue(model, (void *)&value);
|
|
result = true;
|
|
}
|
|
break;
|
|
}
|
|
case EjectEffectResourceAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
ResourceID value = ResourceID::Null;
|
|
attribute_entry->SetValue(model, (void *)&value);
|
|
result = true;
|
|
}
|
|
break;
|
|
}
|
|
case SplashHeatAmountAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
Scalar value = 1.0f;
|
|
attribute_entry->SetValue(model, &value);
|
|
result = true;
|
|
}
|
|
if(model->splashHeatAmount < 0.0f)
|
|
{
|
|
_snprintf(
|
|
*error,
|
|
error_buffer,
|
|
"{[GameData]SplashHeatAmount=%f}: value must be >= 0!",
|
|
model->splashHeatAmount
|
|
);
|
|
result = false;
|
|
}
|
|
break;
|
|
}
|
|
case NameIndexAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
int value = IDS_NONAME;
|
|
attribute_entry->SetValue(model, &value);
|
|
result = true;
|
|
}
|
|
if(model->m_nameIndex < 0)
|
|
{
|
|
_snprintf(
|
|
*error,
|
|
error_buffer,
|
|
"{[GameData]NameIndex=%f}: value must be >= 0!",
|
|
model->m_nameIndex
|
|
);
|
|
result = false;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::SaveInstanceText(Page *instance_page)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(instance_page);
|
|
|
|
BaseClass::SaveInstanceText(instance_page);
|
|
|
|
//
|
|
//----------------------------
|
|
//Save all of the stream names
|
|
//----------------------------
|
|
//
|
|
if(armatureStreamResourceID != ResourceID::Null)
|
|
{
|
|
Resource armature_resource(armatureStreamResourceID);
|
|
Verify(armature_resource.DoesResourceExist());
|
|
instance_page->SetEntry("Armature", armature_resource.GetName());
|
|
}
|
|
if(subsystemStreamResourceID != ResourceID::Null)
|
|
{
|
|
Resource subsystem_resource(subsystemStreamResourceID);
|
|
Verify(subsystem_resource.DoesResourceExist());
|
|
instance_page->SetEntry("Subsystems", subsystem_resource.GetName());
|
|
}
|
|
if(!invulnerable && damageStreamResourceID != ResourceID::Null)
|
|
{
|
|
Resource damage_resource(damageStreamResourceID);
|
|
Verify(damage_resource.DoesResourceExist());
|
|
instance_page->SetEntry("DamageObjects", damage_resource.GetName());
|
|
}
|
|
|
|
if(m_heatManager)
|
|
instance_page->SetEntry("CurrentHeat", m_heatManager->GetHeat());
|
|
|
|
char szTemp[2];
|
|
szTemp[0] = m_skinPrefix;
|
|
szTemp[1] = 0;
|
|
instance_page->SetEntry("Skin", szTemp);
|
|
|
|
|
|
instance_page->SetEntry("TeamDecal", m_teamDecal);
|
|
instance_page->SetEntry("PilotDecal", m_teamDecal);
|
|
|
|
instance_page->SetEntry("DoesHaveInstanceName", m_doesHaveInstanceName);
|
|
|
|
if(m_doesHaveInstanceName)
|
|
instance_page->SetEntry("@LocalizedInstanceName", instanceName);
|
|
|
|
|
|
if(m_localizeIndex > -1)
|
|
// instance_page->SetEntry("NameIndex", m_localizeIndex);
|
|
// Wipe this value out so that NameTable doesn't replace a define with a hard number.
|
|
instance_page->SetEntry("NameIndex", -1);
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
ResourceID
|
|
MWObject__GameModel::CreateEffectTableResource(Stuff::NotationFile *effect_file, BYTE length)
|
|
{
|
|
Check_Object(Resource::ParentFileDependencies);
|
|
|
|
Resource table_resource(effect_file->GetFileName());
|
|
if (
|
|
table_resource.DoesResourceExist() &&
|
|
table_resource.IsResourceUpToDate()
|
|
)
|
|
{
|
|
if (!table_resource.IsRegistered())
|
|
table_resource.AddFileDependenciesTo(Resource::ParentFileDependencies);
|
|
return table_resource.GetResourceID();
|
|
}
|
|
|
|
DynamicMemoryStream effects_stream(sizeof(int) + length * sizeof(ResourceID));
|
|
|
|
//
|
|
//----------------------
|
|
//Create the stream here
|
|
//----------------------
|
|
//
|
|
effects_stream << length;
|
|
ResourceID *stream_array = Cast_Pointer(ResourceID *, effects_stream.GetPointer());
|
|
for(int i=0;i<length;i++)
|
|
{
|
|
stream_array[i] = ResourceID::Null;
|
|
}
|
|
|
|
Check_Object(effect_file);
|
|
Page *effect_page = effect_file->FindPage("EffectList");
|
|
if (effect_page)
|
|
{
|
|
ChainOf<Note*> *effects = effect_page->MakeNoteChain("Effect");
|
|
Check_Object(effects);
|
|
Page::NoteIterator effects_list(effects);
|
|
Note *effects_entry;
|
|
while ((effects_entry = effects_list.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(effects_entry);
|
|
const char *effect_data;
|
|
effects_entry->GetEntry(&effect_data);
|
|
Check_Pointer(effect_data);
|
|
|
|
MString entry_string;
|
|
MString effect_file_name;
|
|
|
|
entry_string = effect_data;
|
|
effect_file_name = entry_string.GetNthToken(0, ",");
|
|
|
|
Check_Object(Tool::Instance);
|
|
Check_Object(ResourceManager::Instance);
|
|
Resource effect_resource;
|
|
Tool::Instance->ConstructDataList(&effect_resource, effect_file_name);
|
|
Check_Object(&effect_resource);
|
|
Verify(effect_resource.DoesResourceExist());
|
|
MString material_name;
|
|
material_name = entry_string.GetNthToken(1, ",");
|
|
int material_num = MaterialTypeTextToAscii(material_name);
|
|
Verify(material_num < length);
|
|
stream_array[material_num] = effect_resource.GetResourceID();
|
|
}
|
|
|
|
if (effects_stream.GetBytesUsed() > 0)
|
|
{
|
|
table_resource.Save(
|
|
&effects_stream,
|
|
Resource::ParentFileDependencies
|
|
);
|
|
Check_Object(&table_resource);
|
|
|
|
delete effects;
|
|
return table_resource.GetResourceID();
|
|
}
|
|
|
|
delete effects;
|
|
}
|
|
return ResourceID::Null;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::CreateArmatureStream(MemoryStream *stream, NotationFile *notation_file)
|
|
{
|
|
Check_Pointer(stream);
|
|
Check_Pointer(notation_file);
|
|
|
|
Tool::Instance->PushFilePath(notation_file);
|
|
FileDependencies arm_deps(*notation_file->GetFileDependencies());
|
|
FileDependencies *parent = Resource::ParentFileDependencies;
|
|
Resource::ParentFileDependencies = &arm_deps;
|
|
*stream << static_cast<WORD>(0);
|
|
ReplicatorID starting_id = ReplicatorID::Null;
|
|
NotationFile::PageIterator *instance_names = notation_file->MakePageIterator();
|
|
Check_Object(instance_names);
|
|
Page *instance;
|
|
while ((instance = instance_names->ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(instance);
|
|
|
|
//
|
|
//-----------------------------------------
|
|
// Create the entity for this instance_page
|
|
//-----------------------------------------
|
|
//
|
|
bool on_root = false;
|
|
instance->GetEntry("AttachedToRoot", &on_root);
|
|
if (on_root)
|
|
{
|
|
Entity::CreateMessage *message =
|
|
Tool::Instance->ConstructCreateMessage(
|
|
stream,
|
|
instance,
|
|
&starting_id
|
|
);
|
|
Check_Object(message);
|
|
stream->AdvancePointer(message->messageLength);
|
|
}
|
|
}
|
|
|
|
if (stream->GetBytesUsed() > sizeof(WORD))
|
|
{
|
|
stream->Rewind();
|
|
WORD span =
|
|
static_cast<WORD>(starting_id.localID - 0);
|
|
*stream << span;
|
|
}
|
|
//
|
|
//------------------------
|
|
// Clean up the tool stack
|
|
//------------------------
|
|
//
|
|
Resource::ParentFileDependencies = parent;
|
|
|
|
Check_Object(instance_names);
|
|
delete instance_names;
|
|
Tool::Instance->PopFilePath();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::CreateDamageStream(MemoryStream *stream, NotationFile *notation_file)
|
|
{
|
|
Check_Pointer(stream);
|
|
Check_Pointer(notation_file);
|
|
|
|
FileDependencies damage_deps(*notation_file->GetFileDependencies());
|
|
FileDependencies *parent = Resource::ParentFileDependencies;
|
|
Resource::ParentFileDependencies = &damage_deps;
|
|
Tool::Instance->PushFilePath(notation_file);
|
|
NotationFile::PageIterator *damage_names = notation_file->MakePageIterator();
|
|
Check_Object(damage_names);
|
|
Page *damage_instance;
|
|
|
|
//
|
|
//---------------------------------------
|
|
// Create the damage Object for this instance_page
|
|
//---------------------------------------
|
|
//
|
|
while ((damage_instance = damage_names->ReadAndNext()) != NULL)
|
|
{
|
|
//
|
|
//-------------------------------------------------------
|
|
//Check to see if we are internal or just a damage object
|
|
//-------------------------------------------------------
|
|
//
|
|
int damage_zone;
|
|
if (!damage_instance->GetEntry("DamageZone", &damage_zone))
|
|
{
|
|
DamageObject::ConstructDamageObjectStream(stream, damage_instance);
|
|
}
|
|
else
|
|
{
|
|
MWInternalDamageObject::ConstructMWInternalDamageObjectStream(stream, damage_instance);
|
|
}
|
|
}
|
|
|
|
Resource::ParentFileDependencies = parent;
|
|
|
|
Check_Object(damage_names);
|
|
delete damage_names;
|
|
Tool::Instance->PopFilePath();
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MWObject::CreateSubsystemStream(MemoryStream *stream, NotationFile *notation_file)
|
|
{
|
|
Check_Pointer(stream);
|
|
Check_Pointer(notation_file);
|
|
|
|
FileDependencies sub_deps(*notation_file->GetFileDependencies());
|
|
FileDependencies *parent = Resource::ParentFileDependencies;
|
|
Resource::ParentFileDependencies = &sub_deps;
|
|
Tool::Instance->PushFilePath(notation_file);
|
|
*stream << static_cast<WORD>(0);
|
|
ReplicatorID starting_id = ReplicatorID::Null;
|
|
NotationFile::PageIterator *instance_names = notation_file->MakePageIterator();
|
|
Check_Object(instance_names);
|
|
Page *instance;
|
|
while ((instance = instance_names->ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(instance);
|
|
|
|
//
|
|
//-----------------------------------------
|
|
// Create the entity for this instance_page
|
|
//-----------------------------------------
|
|
//
|
|
Entity::CreateMessage *message =
|
|
Tool::Instance->ConstructCreateMessage(
|
|
stream,
|
|
instance,
|
|
&starting_id
|
|
);
|
|
Check_Object(message);
|
|
stream->AdvancePointer(message->messageLength);
|
|
}
|
|
|
|
//
|
|
//-----------------------------------------
|
|
// Only save out the stream if there is one
|
|
//-----------------------------------------
|
|
//
|
|
if (stream->GetBytesUsed() > sizeof(WORD))
|
|
{
|
|
stream->Rewind();
|
|
WORD span =
|
|
static_cast<WORD>(starting_id.localID - 0);
|
|
*stream << span;
|
|
}
|
|
Resource::ParentFileDependencies = parent;
|
|
|
|
Check_Object(instance_names);
|
|
delete instance_names;
|
|
Tool::Instance->PopFilePath();
|
|
} |