Initial import of Red Planet v4.10 Win32 source

Imports the current Win32 source for the pod-racing game 'Red Planet',
built on the MUNGA engine and its L4 (Win32/DirectX) platform layer:

- MUNGA / MUNGA_L4: cross-platform engine core and Win32 backend
- RP / RP_L4: Red Planet game logic and Win32 application
- DivLoader, Setup1: asset loader and installer project
- lib, MUNGA_L4/openal, MUNGA_L4/sos: third-party audio dependencies

Removed stale Subversion metadata and added .gitignore/.gitattributes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-06-30 07:59:51 -05:00
co-authored by Claude Opus 4.8
commit 4abbf8879f
551 changed files with 254956 additions and 0 deletions
+577
View File
@@ -0,0 +1,577 @@
#include "rp.h"
#pragma hdrstop
#include "scorzone.h"
#include "..\munga\fileutil.h"
#include "..\munga\nttmgr.h"
#include "..\munga\app.h"
#include "..\munga\hostmgr.h"
#include "..\munga\notation.h"
//#############################################################################
//############################### ScoreZone #############################
//#############################################################################
//#############################################################################
// Shared Data Support
//
Derivation* ScoreZone::GetClassDerivations()
{
static Derivation classDerivations(Entity::GetClassDerivations(), "ScoreZone");
return &classDerivations;
}
ScoreZone::SharedData
ScoreZone::DefaultData(
ScoreZone::GetClassDerivations(),
ScoreZone::MessageHandlers,
ScoreZone::GetAttributeIndex(),
ScoreZone::StateCount,
(Entity::MakeHandler)ScoreZone::Make
);
//#############################################################################
// Attribute Support
//
const ScoreZone::IndexEntry
ScoreZone::AttributePointers[]=
{
ATTRIBUTE_ENTRY(ScoreZone, ScoreZoneType, scoreZoneType),
ATTRIBUTE_ENTRY(ScoreZone, PointValue, pointValue)
};
ScoreZone::AttributeIndexSet& ScoreZone::GetAttributeIndex()
{
static ScoreZone::AttributeIndexSet attributeIndex(ELEMENTS(ScoreZone::AttributePointers),
ScoreZone::AttributePointers,
Entity::GetAttributeIndex()
);
return attributeIndex;
}
//#############################################################################
// Message Support
//
const Receiver::HandlerEntry
ScoreZone::MessageHandlerEntries[]=
{
MESSAGE_ENTRY(ScoreZone, ProcessScoreZoneRequest)
};
Receiver::MessageHandlerSet
ScoreZone::MessageHandlers(
ELEMENTS(ScoreZone::MessageHandlerEntries),
ScoreZone::MessageHandlerEntries,
Entity::GetMessageHandlers()
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ScoreZone::ProcessScoreZoneRequestMessageHandler(
ProcessScoreZoneRequestMessage *message
)
{
Check(this);
Check_Pointer(message);
//
//----------------------------------------
// Make sure that the score zone is active
//----------------------------------------
//
EntityGroup *score_zone_group;
if (GetSimulationState() == Active)
{
//
//-----------------------------------------------------------
// If Sequential, hunt for ourselves in the sequential group
//-----------------------------------------------------------
//
Check(application);
EntityManager *entity_mgr = application->GetEntityManager();
Check(entity_mgr);
if (
scoreZoneType == LocalSequential
|| scoreZoneType == GlobalSequential
)
{
int new_zone = sequenceNumber + 1;
score_zone_group = entity_mgr->FindGroup("SequentialScoreZones");
Check(score_zone_group);
ChainIteratorOf<Node*> iterator(score_zone_group->groupMembers);
ScoreZone
*score_zone,
*first_score_zone = NULL;
//
//------------------------------------------------------------------
// Store the first score zone in case we run off the end of the list
//------------------------------------------------------------------
//
while ((score_zone = (ScoreZone*)iterator.ReadAndNext()) != NULL)
{
Check(score_zone);
if (score_zone->sequenceNumber == 1)
{
first_score_zone = score_zone;
}
if (score_zone->sequenceNumber == new_zone)
{
break;
}
}
if (!score_zone)
{
score_zone = first_score_zone;
}
if (score_zone->GetSimulationState() == InActive)
{
score_zone->SetSimulationState(Active);
score_zone_group = entity_mgr->FindGroup("ActiveScoreZones");
Check(score_zone_group);
score_zone_group->Add(score_zone);
}
}
//
//----------------------------------------------------------------
// Set the zone as inactive, remove ourselves from the active list
//----------------------------------------------------------------
//
SetSimulationState(InActive);
score_zone_group = entity_mgr->FindGroup("ActiveScoreZones");
Check(score_zone_group);
ChainIteratorOf<Node*> iterator(score_zone_group->groupMembers);
ScoreZone *score_zone;
while ((score_zone = (ScoreZone*)iterator.GetCurrent()) != NULL)
{
if (score_zone == this)
{
iterator.Remove();
break;
}
iterator.Next();
}
//
//-----------------------------------
// Send the points back to the player
//-----------------------------------
//
ReplyMessage
reply(
message->replyMessageID,
sizeof(ReplyMessage),
pointValue
);
Check(application);
HostManager *host = application->GetHostManager();
Check(host);
Entity *entity = host->GetEntityPointer(message->requestingEntity);
Check(entity);
entity->Dispatch(&reply);
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ScoreZone::Dispatch(Receiver::Message *message)
{
Check(this);
Check(message);
ProcessScoreZoneRequestMessage *score_zone_message =
(ProcessScoreZoneRequestMessage*) message;
if (score_zone_message->messageID == ProcessScoreZoneRequestMessageID)
{
if (!extentBox.Contains(score_zone_message->linearPosition))
{
Check_Fpu();
return;
}
}
Entity::Dispatch(score_zone_message);
Check_Fpu();
}
//#############################################################################
// Construction and Destruction
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ScoreZone::ScoreZone(
ScoreZone::MakeMessage *creation_message,
ScoreZone::SharedData &virtual_data
):
Entity(creation_message, virtual_data)
{
Check_Pointer(this);
Check_Pointer(creation_message);
SetValidFlag();
//-------------------------------------------------
// Find the drop zone resource in the resource file
//-------------------------------------------------
ResourceFile
*res_file = application->GetResourceFile();
Check(res_file);
ResourceDescription *res =
res_file->SearchList(
resourceID,
ResourceDescription::GameModelResourceType
);
Check(res);
res->Lock();
//
// Get ScoreZone Info
//
sequenceNumber = creation_message->sequenceNumber;
ModelResource
*score_res = (ModelResource*)res->resourceAddress;
scoreZoneType = score_res->scoreZoneType;
pointValue = score_res->pointValue;
extentBox = score_res->extentBox;
extentBox.minX += localOrigin.linearPosition.x;
extentBox.minY += localOrigin.linearPosition.y;
extentBox.minZ += localOrigin.linearPosition.z;
extentBox.maxX += localOrigin.linearPosition.x;
extentBox.maxY += localOrigin.linearPosition.y;
extentBox.maxZ += localOrigin.linearPosition.z;
SetSimulationState(InActive);
res->Unlock();
//---------------------------------------------------------------------
// Make the sequential score zone list. Only make the first sequential
// score zone active
//---------------------------------------------------------------------
EntityManager *entity_manager = application->GetEntityManager();
Check(entity_manager);
EntityGroup *score_zones;
if (scoreZoneType == LocalSequential || scoreZoneType == GlobalSequential)
{
score_zones = entity_manager->UseGroup("SequentialScoreZones");
Check(score_zones);
score_zones->Add(this);
if (sequenceNumber == 1)
{
goto Active_Zone;
}
}
//
//------------------------------------------------
// If it isn't a sequential, always make it active
//------------------------------------------------
//
else
{
Active_Zone:
score_zones = entity_manager->UseGroup("ActiveScoreZones");
Check(score_zones);
SetSimulationState(Active);
score_zones->Add(this);
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ScoreZone*
ScoreZone::Make(ScoreZone::MakeMessage *creation_message)
{
return new ScoreZone(creation_message);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
ScoreZone::CreateMakeMessage(
MakeMessage *creation_message,
NotationFile *model_file,
const ResourceDirectories *directories
)
{
Check(creation_message);
Check(model_file);
if (!Entity::CreateMakeMessage(creation_message, model_file, directories))
{
Check_Fpu();
return False;
}
creation_message->classToCreate = RegisteredClass::ScoreZoneClassID;
creation_message->messageLength = sizeof(*creation_message);
creation_message->instanceFlags =
IndependantInstance|DynamicFlag|MapFlag|TrappedFlag;
char *p;
creation_message->sequenceNumber = -1;
if ((p = strtok(NULL, " ")) != NULL)
{
creation_message->sequenceNumber = atoi(p);
}
Check_Fpu();
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ScoreZone::~ScoreZone()
{
Check(this);
if (scoreZoneType == LocalSequential || scoreZoneType == GlobalSequential)
{
Check(application);
EntityManager *entity_mgr = application->GetEntityManager();
Check(entity_mgr);
EntityGroup *score_zone_group =
entity_mgr->FindGroup("SequentialScoreZones");
if (score_zone_group)
{
ChainIteratorOf<Node*> iterator(score_zone_group->groupMembers);
ScoreZone *score_zone = (ScoreZone*)iterator.GetCurrent();
if (score_zone == this)
{
iterator.Remove();
if (!iterator.GetCurrent())
{
entity_mgr->RemoveGroup(score_zone_group);
}
}
}
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ResourceDescription::ResourceID
ScoreZone::CreateModelResource(
ResourceFile *resource_file,
const char* model_name,
NotationFile * model_file,
const ResourceDirectories *directories,
ModelResource *model
)
{
Check(resource_file);
Check_Pointer(model_name);
Check_Pointer(directories);
//
// If we were not provided a buffer to write the model data into, we must
// create it ourselves. Then make sure that the model stuff is read in
//
ModelResource *local_model = model;
if (!local_model)
{
local_model = new ModelResource;
Register_Pointer(local_model);
}
//
// Get PointValue assigned to this ScoreZone
//
if(
!model_file->GetEntry(
"gamedata",
"PointValue",
&local_model->pointValue
)
)
{
std::cerr << model_name << "Missing PointValue" << std::endl;
Dump_And_Die:
if (!model)
{
Unregister_Pointer(local_model);
delete local_model;
}
Check_Fpu();
return -1;
}
//
// Get The ScoreZone Type
//
const char* score_zone_type;
if(
!model_file->GetEntry(
"gamedata",
"ScoreZoneType",
&score_zone_type
)
)
{
std::cerr << model_name << "Missing ScoreZoneType" << std::endl;
goto Dump_And_Die;
}
else
{
if(strcmp(score_zone_type,"GlobalOneTime") == 0)
{
local_model->scoreZoneType = GlobalOneTime;
}
else
if(strcmp(score_zone_type,"LocalOneTime") == 0)
{
local_model->scoreZoneType = LocalOneTime;
}
else
if(strcmp(score_zone_type,"GlobalSequential") == 0)
{
local_model->scoreZoneType = GlobalSequential;
}
else
if(strcmp(score_zone_type,"LocalSequential") == 0)
{
local_model->scoreZoneType = LocalSequential;
}
}
//
// Read In the Extent Box from the solid file determined by the
// collision data
//
const char* sld_entry;
if(
!model_file->GetEntry(
"gamedata",
"Extents",
&sld_entry
)
)
{
std::cerr << model_name << "Missing .sld Specifications " << std::endl;
goto Dump_And_Die;
}
else
{
char *sld_filename =
MakePathedFilename(directories->collisionDirectory, sld_entry);
Register_Pointer(sld_filename);
NotationFile *sld_file = new NotationFile(sld_filename);
Register_Object(sld_file);
if(sld_file->PageCount() == 0)
{
std::cerr <<sld_filename<<" is has no Pages"<<std::endl;
Unregister_Pointer(sld_filename);
delete sld_filename;
Unregister_Object(sld_file);
delete sld_file;
goto Dump_And_Die;
}
NameList *sld_namelist = sld_file->MakeEntryList("volume 0","extm");
Register_Object(sld_namelist);
if (sld_namelist->EntryCount() == 0)
{
Dump_And_Die_2:
Unregister_Pointer(sld_filename);
delete sld_filename;
Unregister_Object(sld_file);
delete sld_file;
Unregister_Object(sld_namelist);
delete sld_namelist;
goto Dump_And_Die;
}
NameList::Entry *extent_entry = sld_namelist->GetFirstEntry();
while(extent_entry)
{
Scalar value = extent_entry->GetAtof();
if (strcmp(extent_entry->GetName(),"extminX") == 0)
{
local_model->extentBox.minX = value;
}
else
if (strcmp(extent_entry->GetName(),"extminY") == 0)
{
local_model->extentBox.minY = value;
}
else
if (strcmp(extent_entry->GetName(),"extminZ") == 0)
{
local_model->extentBox.minZ = value;
}
else
if (strcmp(extent_entry->GetName(),"extmaxX") == 0)
{
local_model->extentBox.maxX = value;
}
else
if (strcmp(extent_entry->GetName(),"extmaxY") == 0)
{
local_model->extentBox.maxY = value;
}
else
if (strcmp(extent_entry->GetName(),"extmaxZ") == 0)
{
local_model->extentBox.maxZ = value;
}
else
{
std::cerr << sld_filename << "Improper Extent Format" << std::endl;
goto Dump_And_Die_2;
}
extent_entry = extent_entry->GetNextEntry();
}
Unregister_Pointer(sld_filename);
delete sld_filename;
Unregister_Object(sld_file);
delete sld_file;
Unregister_Object(sld_namelist);
delete sld_namelist;
}
//
//---------------------------
// Write out the new 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
ScoreZone::TestInstance() const
{
return IsDerivedFrom(*GetClassDerivations());
}