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.
662 lines
15 KiB
C++
662 lines
15 KiB
C++
//===========================================================================//
|
|
// File: Vehicle_Tool.cpp //
|
|
//---------------------------------------------------------------------------//
|
|
// Date Who Modification //
|
|
// -------- --- ---------------------------------------------------------- //
|
|
// 09/09/98 JSE Inital base class based off of Shadowrun/Adept //
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1998, Fasa Interactive //
|
|
// All Rights reserved worldwide //
|
|
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
|
//===========================================================================//
|
|
|
|
#include "MW4Headers.hpp"
|
|
|
|
#include "Vehicle.hpp"
|
|
#include "Subsystem.hpp"
|
|
#include "Engine.hpp"
|
|
#include "Torso.hpp"
|
|
#include "MWDamageObject.hpp"
|
|
#include "MaterialEffectHolder.hpp"
|
|
|
|
#include <Adept\Tool.hpp>
|
|
#include <Adept\EntityManager.hpp>
|
|
#include <MLR\MLRLight.hpp>
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Vehicle__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(Vehicle__GameModel));
|
|
BaseClass::ConstructGameModel(script);
|
|
|
|
Verify(stack_level == Tool::Instance->GetStackLevel());
|
|
|
|
Vehicle__GameModel *model =
|
|
Cast_Pointer(Vehicle__GameModel*, model_stream->GetPointer());
|
|
|
|
//
|
|
//------------------------------
|
|
// Set up the model file pointer
|
|
//------------------------------
|
|
//
|
|
NotationFile *model_file = script->modelFile;
|
|
Check_Object(model_file);
|
|
model->trailEffectsTable = ResourceID::Null;
|
|
Page *game_page = model_file->GetPage("GameData");
|
|
Check_Object(game_page);
|
|
|
|
//
|
|
//-------------------------
|
|
// Create the effects table
|
|
//-------------------------
|
|
//
|
|
NotationFile effects_file;
|
|
if (game_page->GetEntry("TrailEffectsFile", &effects_file))
|
|
model->trailEffectsTable = CreateEffectTableResource(&effects_file, MaterialCount);
|
|
|
|
//
|
|
//-------------------------------------------------------------
|
|
// If there is no shadow entry, set the stream resource to NULL
|
|
//-------------------------------------------------------------
|
|
//
|
|
NotationFile shadow_file;
|
|
if (!game_page->GetEntry("Shadow", &shadow_file))
|
|
model->shadowStream = ResourceID::Null;
|
|
|
|
//
|
|
//------------------------------------
|
|
// Otherwise, rebuild the light stream
|
|
//------------------------------------
|
|
//
|
|
else
|
|
{
|
|
Tool::Instance->PushFilePath(&shadow_file);
|
|
DynamicMemoryStream shadow_stream;
|
|
|
|
//
|
|
//----------------------------------------------------
|
|
// Read each light in and write it out into the binary
|
|
//----------------------------------------------------
|
|
//
|
|
MidLevelRenderer::WriteMLRVersion(&shadow_stream);
|
|
NotationFile::PageIterator *pages = shadow_file.MakePageIterator();
|
|
Check_Object(pages);
|
|
Page *shadow_page;
|
|
while ((shadow_page = pages->ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(shadow_page);
|
|
MidLevelRenderer::MLRLight* shadow =
|
|
MidLevelRenderer::MLRLight::Make(shadow_page);
|
|
Check_Object(shadow);
|
|
shadow->Save(&shadow_stream);
|
|
delete shadow;
|
|
}
|
|
|
|
//
|
|
//-----------------------------------------
|
|
// Only save out the stream if there is one
|
|
//-----------------------------------------
|
|
//
|
|
if (shadow_stream.GetBytesUsed() > 0)
|
|
{
|
|
shadow_stream.Rewind();
|
|
Resource shadow_resource(shadow_file.GetFileName());
|
|
shadow_resource.Save(&shadow_stream, shadow_file.GetFileDependencies());
|
|
shadow_resource.AddFileDependenciesTo(Resource::ParentFileDependencies);
|
|
Check_Object(&shadow_resource);
|
|
model->shadowStream = shadow_resource.GetResourceID();
|
|
}
|
|
else
|
|
{
|
|
model->shadowStream = ResourceID::Null;
|
|
Resource::ParentFileDependencies->AddDependencies(shadow_file.GetFileDependencies());
|
|
}
|
|
|
|
//
|
|
//------------------------
|
|
// Clean up the tool stack
|
|
//------------------------
|
|
//
|
|
Check_Object(pages);
|
|
delete pages;
|
|
Tool::Instance->PopFilePath();
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
Vehicle__GameModel::ReadAndVerify(
|
|
Vehicle__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 FullStopTurnRateAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
Scalar value = 10.1f*Radians_Per_Degree;
|
|
attribute_entry->SetValue(model, &value);
|
|
result = true;
|
|
}
|
|
if(model->fullStopTurnRate < 10.0f*Radians_Per_Degree)
|
|
{
|
|
_snprintf(
|
|
*error,
|
|
error_buffer,
|
|
"{[GameData]FullStopTurnRate=%f}: value must be >= 10.0!",
|
|
model->fullStopTurnRate*Degrees_Per_Radian
|
|
);
|
|
result = false;
|
|
}
|
|
break;
|
|
}
|
|
case TopSpeedTurnRateAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
Scalar value = 10.1f*Radians_Per_Degree;
|
|
attribute_entry->SetValue(model, &value);
|
|
result = true;
|
|
}
|
|
if(model->topSpeedTurnRate < 10.0f*Radians_Per_Degree)
|
|
{
|
|
_snprintf(
|
|
*error,
|
|
error_buffer,
|
|
"{[GameData]TopSpeedTurnRate=%f}: value must be >= 10.0!",
|
|
model->topSpeedTurnRate
|
|
);
|
|
result = false;
|
|
}
|
|
break;
|
|
}
|
|
case MaxSpeedAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
Scalar value = 0.0f;
|
|
attribute_entry->SetValue(model, &value);
|
|
result = true;
|
|
}
|
|
if(model->maxSpeed < 0.0f)
|
|
{
|
|
_snprintf(
|
|
*error,
|
|
error_buffer,
|
|
"{[GameData]MaxSpeed=%f}: value must be >= 0!",
|
|
model->maxSpeed
|
|
);
|
|
result = false;
|
|
}
|
|
break;
|
|
}
|
|
case MinMaxSpeedAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
Scalar value = model->maxSpeed;
|
|
attribute_entry->SetValue(model, &value);
|
|
result = true;
|
|
}
|
|
if(model->minMaxSpeed < 0.0f)
|
|
{
|
|
_snprintf(
|
|
*error,
|
|
error_buffer,
|
|
"{[GameData]MinMaxSpeed=%f}: value must be >= 0!",
|
|
model->minMaxSpeed
|
|
);
|
|
result = false;
|
|
}
|
|
break;
|
|
}
|
|
case MinSpeedAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
Scalar value = 0.0f;
|
|
attribute_entry->SetValue(model, &value);
|
|
result = true;
|
|
}
|
|
if(model->minSpeed > model->maxSpeed)
|
|
{
|
|
_snprintf(
|
|
*error,
|
|
error_buffer,
|
|
"{[GameData]MinSpeed=%f}: value must be <= MaxSpeed %f!",
|
|
model->minSpeed,
|
|
model->maxSpeed
|
|
);
|
|
result = false;
|
|
}
|
|
break;
|
|
}
|
|
case MaxReverseSpeedAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
Scalar value = -1.0f;
|
|
attribute_entry->SetValue(model, &value);
|
|
result = true;
|
|
}
|
|
if(model->maxReverseSpeed > 0.0f)
|
|
{
|
|
_snprintf(
|
|
*error,
|
|
error_buffer,
|
|
"{[GameData]MaxReverseSpeed=%f}: value must be <= 0!",
|
|
model->maxReverseSpeed
|
|
);
|
|
result = false;
|
|
}
|
|
break;
|
|
}
|
|
case MinReverseSpeedAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
Scalar value = 0.0f;
|
|
attribute_entry->SetValue(model, &value);
|
|
result = true;
|
|
}
|
|
if(model->minReverseSpeed < model->maxReverseSpeed)
|
|
{
|
|
_snprintf(
|
|
*error,
|
|
error_buffer,
|
|
"{[GameData]MinReverseSpeed=%f}: value must be >= MaxReverseSpeed!",
|
|
model->minReverseSpeed
|
|
);
|
|
result = false;
|
|
}
|
|
break;
|
|
}
|
|
case AccelerationAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
Scalar value = 0.0f;
|
|
attribute_entry->SetValue(model, &value);
|
|
result = true;
|
|
}
|
|
if(model->acceleration < 0.0f)
|
|
{
|
|
_snprintf(
|
|
*error,
|
|
error_buffer,
|
|
"{[GameData]Acceleration=%f}: value must be >= 0!",
|
|
model->acceleration
|
|
);
|
|
result = false;
|
|
}
|
|
break;
|
|
}
|
|
case DeccelerationAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
Scalar value = 0.0f;
|
|
attribute_entry->SetValue(model, &value);
|
|
result = true;
|
|
}
|
|
if(model->decceleration < 0.0f)
|
|
{
|
|
_snprintf(
|
|
*error,
|
|
error_buffer,
|
|
"{[GameData]Decceleration=%f}: value must be >= 0!",
|
|
model->decceleration
|
|
);
|
|
result = false;
|
|
}
|
|
break;
|
|
}
|
|
case ReverseAccelerationMultiplierAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
Scalar value = 0.0f;
|
|
attribute_entry->SetValue(model, &value);
|
|
result = true;
|
|
}
|
|
if(model->reverseAccelerationMultiplier < 0.0f)
|
|
{
|
|
_snprintf(
|
|
*error,
|
|
error_buffer,
|
|
"{[GameData]ReverseAccelerationMultiplier=%f}: value must be >= 0!",
|
|
model->reverseAccelerationMultiplier
|
|
);
|
|
result = false;
|
|
}
|
|
break;
|
|
}
|
|
case ReverseDeccelerationMultiplierAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
Scalar value = 0.0f;
|
|
attribute_entry->SetValue(model, &value);
|
|
result = true;
|
|
}
|
|
if(model->reverseDeccelerationMultiplier < 0.0f)
|
|
{
|
|
_snprintf(
|
|
*error,
|
|
error_buffer,
|
|
"{[GameData]ReverseDeccelerationMultiplier=%f}: value must be >= 0!",
|
|
model->reverseDeccelerationMultiplier
|
|
);
|
|
result = false;
|
|
}
|
|
break;
|
|
}
|
|
case TargetLockTimeAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
Scalar value = 3.0f;
|
|
attribute_entry->SetValue(model, &value);
|
|
result = true;
|
|
}
|
|
if(model->targetLockTime < 0.0f)
|
|
{
|
|
_snprintf(
|
|
*error,
|
|
error_buffer,
|
|
"{[GameData]TargetLockTime=%f}: value must be >= 0!",
|
|
model->targetLockTime
|
|
);
|
|
result = false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case MinStandTransitionSpeedAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
Scalar value = 0.0f;
|
|
attribute_entry->SetValue(model, &value);
|
|
result = true;
|
|
}
|
|
if(model->minStandTransitionSpeed < 0.0f)
|
|
{
|
|
_snprintf(
|
|
*error,
|
|
error_buffer,
|
|
"{[GameData]MinStandTransitionSpeed=%f}: value must be > 0!",
|
|
model->minStandTransitionSpeed
|
|
);
|
|
result = false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
case MaxGimpSpeedAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
Scalar value = 0.0f;
|
|
attribute_entry->SetValue(model, &value);
|
|
result = true;
|
|
}
|
|
if(model->maxGimpSpeed < 0.0f)
|
|
{
|
|
_snprintf(
|
|
*error,
|
|
error_buffer,
|
|
"{[GameData]MaxGimpSpeed=%f}: value must be > 0!",
|
|
model->maxGimpSpeed
|
|
);
|
|
result = false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
|
|
case MaxSlopeAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
Scalar value = 55.0f;
|
|
attribute_entry->SetValue(model, &value);
|
|
result = true;
|
|
}
|
|
if (model->modelmaxSlope < 0)
|
|
{
|
|
_snprintf(
|
|
*error,
|
|
error_buffer,
|
|
"{[GameData]MaxSlope=%f}: value must be >= 0!",
|
|
model->modelmaxSlope
|
|
);
|
|
result = false;
|
|
}
|
|
else
|
|
{
|
|
model->modelmaxSlope = model->modelmaxSlope * Radians_Per_Degree;
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
|
|
case StartSlopeDecelerationAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
Scalar value = 40.0f;
|
|
attribute_entry->SetValue(model, &value);
|
|
result = true;
|
|
}
|
|
if (model->modelstartSlopeDeceleration < 0)
|
|
{
|
|
_snprintf(
|
|
*error,
|
|
error_buffer,
|
|
"{[GameData]StartSlopeDeceleration=%f}: value must be >= 0!",
|
|
model->modelstartSlopeDeceleration
|
|
);
|
|
result = false;
|
|
}
|
|
else
|
|
{
|
|
model->modelstartSlopeDeceleration = model->modelstartSlopeDeceleration * Radians_Per_Degree;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SlopeDecel1AttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
Scalar value = 20.0f;
|
|
attribute_entry->SetValue(model, &value);
|
|
result = true;
|
|
}
|
|
if(model->slopeDecel1 < 0.0f)
|
|
{
|
|
_snprintf(
|
|
*error,
|
|
error_buffer,
|
|
"{[GameData]SlopeDecel1=%f}: value must be > 0!",
|
|
model->slopeDecel1
|
|
);
|
|
result = false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SlopeDecel2AttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
Scalar value = 40.0f;
|
|
attribute_entry->SetValue(model, &value);
|
|
result = true;
|
|
}
|
|
if(model->slopeDecel2 < 0.0f)
|
|
{
|
|
_snprintf(
|
|
*error,
|
|
error_buffer,
|
|
"{[GameData]SlopeDecel2=%f}: value must be > 0!",
|
|
model->slopeDecel2
|
|
);
|
|
result = false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SlopeDecel3AttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
Scalar value = 60.0f;
|
|
attribute_entry->SetValue(model, &value);
|
|
result = true;
|
|
}
|
|
if(model->slopeDecel3 < 0.0f)
|
|
{
|
|
_snprintf(
|
|
*error,
|
|
error_buffer,
|
|
"{[GameData]SlopeDecel3=%f}: value must be > 0!",
|
|
model->slopeDecel3
|
|
);
|
|
result = false;
|
|
}
|
|
break;
|
|
}
|
|
case AttackTypeAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
int value = 0;
|
|
attribute_entry->SetValue(model, &value);
|
|
result = true;
|
|
}
|
|
if(model->m_attackType < 0)
|
|
{
|
|
_snprintf(
|
|
*error,
|
|
error_buffer,
|
|
"{[GameData]AttackType=%f}: value must be > 0!",
|
|
model->m_attackType
|
|
);
|
|
result = false;
|
|
}
|
|
break;
|
|
}
|
|
case TreadLengthAttributeID:
|
|
{
|
|
if(!valid_data)
|
|
{
|
|
// Default tread length is set to 6 meters
|
|
Scalar value = 6.0f;
|
|
attribute_entry->SetValue(model, &value);
|
|
result = true;
|
|
}
|
|
if(model->m_treadLength <= 0)
|
|
{
|
|
_snprintf(
|
|
*error,
|
|
error_buffer,
|
|
"{[GameData]TreadLength=%f}: value must be > 0!",
|
|
model->m_treadLength
|
|
);
|
|
result = false;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Vehicle::SaveInstanceText(Page *instance_page)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(instance_page);
|
|
|
|
BaseClass::SaveInstanceText(instance_page);
|
|
|
|
//
|
|
//-------------------------
|
|
// Save the Execution State
|
|
//-------------------------
|
|
//
|
|
int execution_state = executionState->GetState();
|
|
MString execution_state_text;
|
|
switch(execution_state)
|
|
{
|
|
case ExecutionStateEngine::FallingMotionState:
|
|
{
|
|
execution_state_text = "FallingMotionState";
|
|
break;
|
|
}
|
|
case ExecutionStateEngine::FlyingMotionState:
|
|
{
|
|
execution_state_text = "FlyingMotionState";
|
|
break;
|
|
}
|
|
case ExecutionStateEngine::DrivingMotionState:
|
|
{
|
|
execution_state_text = "DrivingMotionState";
|
|
break;
|
|
}
|
|
}
|
|
if (execution_state_text)
|
|
{
|
|
instance_page->SetEntry("ExecutionState", execution_state_text);
|
|
}
|
|
}
|