4.10 reconstruction: BTL4OPT.EXE links clean and BOOTS to the first staged brick

The reconstructed tree now produces a runnable binary with the authentic
1995 toolchain (BC4.52 / tlink32 / DPMI32):

- BTL4.CPP main TU reconstructed from the 4.11 Ghidra decomp (FUN_0040109c)
  + the 4.10 binary's own string pool + surviving RPL4TOOL.CPP house style;
  probe_main.cpp scaffold retired (BTL4.NOTES.md documents every decoded call)
- L4NET.CPP staged: L4NetworkManager ctor/dtor + 10 vtable-pulled virtuals
  (standalone-benign ones no-op, network ones Fail loudly) + NetNub client
  globals (Net_Common_Ptr=NULL routes L4File to its plain-DOS path)
- build410.sh: libs now built in the AUTHENTIC makefile member order
  (MUNGA.MAK / mungal4.mak / BT.MAK / BTL4.MAK). Order is load-bearing:
  tlink emits static-init records in module pull order, and alphabetical
  order booted into a null-vptr crash (IcomManager::ClassDerivations
  constructing before parent NetworkClient::ClassDerivations). Also fixed
  stage_link to the proven 32-bit lib set (SOSDBXC+SOSMBXC, no WATTCPLG)
- BOXTREE.HPP MemoryBlock unify, BTL4GRND notify stubs, remaining engine
  backfills (audio/gauge/resource/stream TUs) that closed the deep ledger

Smoke test (DOSBox-X + 32RTM, copy of the pod BT tree, our exe swapped in):
  BattleTech v4.10
  BTL4Application::BTL4Application
  l4net.cpp(22): L4NetworkManager -- l4net.cpp not yet reconstructed
Static init, main, -egg parse, BTL4.RES load (version 1.0.6 check passes),
ApplicationManager and the BTL4Application ctor chain all execute real
reconstructed code; boot halts at the first staged Fail() as designed.
Next brick: the real l4net.cpp body.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-07-19 19:05:53 -05:00
co-authored by Claude Fable 5
parent 60d812484e
commit 5b35eb973c
35 changed files with 17798 additions and 164 deletions
+20
View File
@@ -27,3 +27,23 @@ BTCameraDirector::SharedData
1,
(Entity::MakeHandler)BTCameraDirector::Make
);
BTCameraDirector::BTCameraDirector(
MakeMessage *creation_message,
SharedData &shared_data
):
CameraDirector(creation_message, shared_data)
{
Fail("BTCameraDirector -- btdirect.cpp not yet reconstructed");
}
BTCameraDirector::~BTCameraDirector()
{
}
BTCameraDirector*
BTCameraDirector::Make(CameraDirector::MakeMessage *)
{
Fail("BTCameraDirector::Make -- btdirect.cpp not yet reconstructed");
return NULL;
}
+20
View File
@@ -27,3 +27,23 @@ BTPlayer::SharedData
1,
(Entity::MakeHandler)BTPlayer::Make
);
BTPlayer::BTPlayer(
MakeMessage *creation_message,
SharedData &shared_data
):
Player(creation_message, shared_data)
{
Fail("BTPlayer -- btplayer.cpp not yet reconstructed");
}
BTPlayer::~BTPlayer()
{
}
BTPlayer*
BTPlayer::Make(MakeMessage *)
{
Fail("BTPlayer::Make -- btplayer.cpp not yet reconstructed");
return NULL;
}
+17
View File
@@ -37,3 +37,20 @@ Mech::SharedData
33,
(Entity::MakeHandler)Mech::Make
);
//
//#############################################################################
//#############################################################################
//
Mech*
Mech::Make(MakeMessage *)
{
Fail("Mech::Make -- mech.cpp not yet reconstructed");
return NULL;
}
void
Mech::SetMappingSubsystem(Subsystem *)
{
Fail("Mech::SetMappingSubsystem -- mech.cpp not yet reconstructed");
}
+58
View File
@@ -0,0 +1,58 @@
//===========================================================================//
// File: mechmppr.cpp //
// Project: BattleTech //
// Contents: Implementation details for the mech controls mapper //
//---------------------------------------------------------------------------//
// Copyright (C) 1995, Virtual World Entertainment, Inc. //
// All Rights reserved worldwide //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
//===========================================================================//
#include <bt.hpp>
#pragma hdrstop
#if !defined(MECHMPPR_HPP)
# include <mechmppr.hpp>
#endif
Derivation
MechControlsMapper::ClassDerivations(
Subsystem::ClassDerivations,
"MechControlsMapper"
);
MechControlsMapper::SharedData
MechControlsMapper::DefaultData(
MechControlsMapper::ClassDerivations,
Subsystem::MessageHandlers,
Subsystem::AttributeIndex,
1
);
MechControlsMapper::MechControlsMapper(
Mech *owner,
int subsystem_ID,
CString subsystem_name,
RegisteredClass::ClassID class_ID,
SharedData &shared_data
):
Subsystem(
(Entity *)owner,
subsystem_ID,
subsystem_name,
class_ID,
shared_data
)
{
Fail("MechControlsMapper -- mechmppr.cpp not yet reconstructed");
}
MechControlsMapper::~MechControlsMapper()
{
}
Logical
MechControlsMapper::TestInstance() const
{
return IsDerivedFrom(ClassDerivations);
}
+7
View File
@@ -27,3 +27,10 @@ Missile::SharedData
1,
(Entity::MakeHandler)Missile::Make
);
Missile*
Missile::Make(MakeMessage *)
{
Fail("Missile::Make -- missile.cpp not yet reconstructed");
return NULL;
}
+7
View File
@@ -27,3 +27,10 @@ Projectile::SharedData
1,
(Entity::MakeHandler)Projectile::Make
);
Projectile*
Projectile::Make(MakeMessage *)
{
Fail("Projectile::Make -- projtile.cpp not yet reconstructed");
return NULL;
}
+91
View File
@@ -0,0 +1,91 @@
//===========================================================================//
// File: btl4.cpp //
// Project: BattleTech Brick: BattleTech LBE Application //
// Contents: Application launcher (main) //
//---------------------------------------------------------------------------//
// Date Who Modification //
// -------- --- ---------------------------------------------------------- //
// //
//---------------------------------------------------------------------------//
// Copyright (C) 1995, Virtual World Entertainment, Inc. //
// All Rights reserved worldwide //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
//===========================================================================//
#include <btl4.hpp>
#pragma hdrstop
#if !defined(BTL4APP_HPP)
# include <btl4app.hpp>
#endif
#if !defined(APPMGR_HPP)
# include <appmgr.hpp>
#endif
#if !defined(BTL4VER_HPP)
# include <btl4ver.hpp>
#endif
//##########################################################################
//#################### BTL4Application Globals #######################
//##########################################################################
extern const char* const ProgName;
const char* const ProgName = "btl4";
static Byte
version[3] =
{MAJOR_DATA_VERSION, RELEASE_VERSION, MINOR_DATA_VERSION};
//
//#############################################################################
// main
//#############################################################################
//
int
main(int argc, char *argv[])
{
DEBUG_STREAM << "BattleTech v4.10" << endl;
if (!L4Application::ParseCommandLine(argc, argv, L4Application::ParseToken))
{
return 1;
}
StreamableResourceFile
resources("btl4.res", version);
ApplicationManager
*application_manager = NULL;
if (L4Application::GetMissionReviewMode() < 1)
{
application_manager =
new ApplicationManager(GetTicksPerSecond());
Application
*application = new BTL4Application(&resources);
application_manager->StartApplication(application);
}
else
{
//
//-------------------------------------------------------------------
// Mission review / live-camera launch (missionReviewMode >= 1):
// a MissionReviewApplicationManager with a SPOOLSIZE-byte packet
// spool plus BTL4PlaybackApplication -- those bricks are not yet
// reconstructed (see BTL4.NOTES.md for the decompiled structure).
//-------------------------------------------------------------------
//
Fail("btl4.cpp -- mission review/camera launch not yet reconstructed");
return 1;
}
application_manager->RunMissions();
delete application_manager;
return Exit_Code;
}
+65
View File
@@ -0,0 +1,65 @@
# BTL4.CPP — reconstruction notes
**Status: RECONSTRUCTED (normal launch path); review/camera branch staged with Fail().**
The 4.10 main TU. No original survives anywhere in the archive (OPT.MAK links
`btl4.obj` as a bare object next to the libs — it was never a lib member).
## Evidence base
1. **Ghidra decomp of the 4.11 binary**`C:\VWE\BT411\reference\decomp\all\part_000.c`,
`FUN_0040109c` (the 524-byte function the Borland startup calls = `main`).
The 4.10 and 4.11 binaries share the same string pool layout for this TU.
2. **String pool of the original 4.10 `BTL4OPT.EXE`** (ALPHA_1/REL410/BT), file
offset ~917884: `"btl4" "HEAPSIZE" "BattleTech v4.10" "btl4.res" "SPOOLSIZE"
"Spool size = "` — banner text and resource name byte-exact.
3. **Surviving 1995 launcher-style TU** `CODE/RP/RP_L4/RPL4TOOL.CPP` — house
style for `main(int, char*[])` and the `ProgName` global pattern.
4. **BT411's win32 launcher** `game/btl4main.cpp` (adapted from RP's RPL4.CPP)
independently reconstructs the same skeleton and pins `version[3] = {1,0,6}`
against the RESOURCE.cpp version check.
## Decoded decomp → source mapping
| decomp | source |
|---|---|
| `FUN_004dbb24(&cout, "BattleTech v4.10", 0); FUN_004d9c38(&cout)` | `DEBUG_STREAM << "BattleTech v4.10" << endl` |
| `FUN_0047b2ec(argc, argv, &LAB_0047af8c)` | `L4Application::ParseCommandLine(argc, argv, L4Application::ParseToken)` |
| `FUN_00407218(stack84, "btl4.res", &DAT_004e0070, 3)` | `StreamableResourceFile resources("btl4.res", version)` (match_level=3 is the declared default) |
| `DAT_004e0070` = 3 bytes | `version[3]` = `{MAJOR_DATA_VERSION, RELEASE_VERSION, MINOR_DATA_VERSION}` = {1,0,6} from BTL4VER.HPP |
| `DAT_004fd550 < 1` | `L4Application::GetMissionReviewMode() < 1` (inline static accessor) |
| `new(0x28) FUN_0044f29c(this, DAT_0052140c)` | `new ApplicationManager(GetTicksPerSecond())` (inline friend accessor, TIME.HPP:49) — DAT_0052140c is set to 28.0f by `SystemClock::SystemClock()` (L4TIME.CPP:93) when `L4TIMER=FAST` |
| `new(0xd4) FUN_004d34c4(this, &resources, 0x3EB, &DAT_0051e8d8)` | `new BTL4Application(&resources)` — 0x3EB/`DefaultData` are the declared default args (BTL4APP.HPP:34) |
| `FUN_0044f318(mgr, app)` | `application_manager->StartApplication(application)` |
| `FUN_0044f344(mgr)` | `application_manager->RunMissions()` |
| vcall slot 0 (mgr, 3) | `delete application_manager` |
| `return DAT_004efc98` | `return Exit_Code` (APP.HPP:542) |
## Review/camera branch (NOT yet reconstructed — staged Fail)
Decomp structure for `missionReviewMode >= 1` (mode 1 = camera, 2 = review per
emulator/CAMERA-REVIEW-NOTES.md):
```
spool_size = getenv("SPOOLSIZE") ? atoi(...) : 0x800000; // "Spool size = " printed
mgr = new(0x38) MissionReviewApplicationManager(ticksPerSecond,
(mode != 2) ? 2 : 1, spool_size);
spool_file = <mgr getter, FUN_0044fa14>;
if (spool_file)
mgr->StartApplication(new(0xd8) BTL4PlaybackApplication(&resources, spool_file));
if (mode == 1)
mgr->StartApplication(new(0xd8) <camera app, FUN_0047c3fc>(&resources, 1));
```
Class declarations survive: `BTL4PlaybackApplication` (CODE/BT/BT_L4/BTL4PB.HPP),
spooler bricks in CODE/RP/MUNGA_L4/L4SPLR.HPP (`MissionReviewApplicationManager`
referenced there). Their .CPP bodies are not staged, so the branch Fails loudly
instead of linking half a subsystem.
## Deliberate differences from the binary
- `HEAPSIZE` string sits in the pool between ProgName and the banner but is not
referenced from the decompiled main — it likely belongs to the runtime heap
init, not this TU. Not reproduced.
- `Register_Object`/`Start_Registering` debug bookkeeping is absent from the
optimized binary (DEBUG_LEVEL=0 compiles it out), so it is not written here.
+34
View File
@@ -0,0 +1,34 @@
//===========================================================================//
// File: btl4grnd.cpp //
// Project: BattleTech //
// Contents: Implementation details for the BT gauge renderer //
//---------------------------------------------------------------------------//
// Copyright (C) 1995, Virtual World Entertainment, Inc. //
// All Rights reserved worldwide //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
//===========================================================================//
#include <btl4.hpp>
#pragma hdrstop
#if !defined(BTL4GRND_HPP)
# include <btl4grnd.hpp>
#endif
BTL4GaugeRenderer::BTL4GaugeRenderer()
{
}
BTL4GaugeRenderer::~BTL4GaugeRenderer()
{
}
void
BTL4GaugeRenderer::NotifyOfNewInterestingEntity(Entity *)
{
}
void
BTL4GaugeRenderer::NotifyOfBecomingUninterestingEntity(Entity *)
{
}
+77
View File
@@ -40,3 +40,80 @@ MechRIOMapper::SharedData
Subsystem::AttributeIndex,
1
);
Derivation
L4MechControlsMapper::ClassDerivations(
MechControlsMapper::ClassDerivations,
"L4MechControlsMapper"
);
L4MechControlsMapper::SharedData
L4MechControlsMapper::DefaultData(
L4MechControlsMapper::ClassDerivations,
Subsystem::MessageHandlers,
Subsystem::AttributeIndex,
1
);
L4MechControlsMapper::L4MechControlsMapper(
Mech *owner,
int subsystem_ID,
CString subsystem_name,
RegisteredClass::ClassID class_ID,
SharedData &shared_data
):
MechControlsMapper(owner, subsystem_ID, subsystem_name, class_ID, shared_data)
{
}
L4MechControlsMapper::~L4MechControlsMapper()
{
}
Logical
L4MechControlsMapper::TestInstance() const
{
return IsDerivedFrom(ClassDerivations);
}
MechThrustmasterMapper::MechThrustmasterMapper(
Mech *owner,
int subsystem_ID,
CString subsystem_name,
RegisteredClass::ClassID class_ID,
SharedData &shared_data
):
L4MechControlsMapper(owner, subsystem_ID, subsystem_name, class_ID, shared_data)
{
}
MechThrustmasterMapper::~MechThrustmasterMapper()
{
}
Logical
MechThrustmasterMapper::TestInstance() const
{
return IsDerivedFrom(ClassDerivations);
}
MechRIOMapper::MechRIOMapper(
Mech *owner,
int subsystem_ID,
CString subsystem_name,
RegisteredClass::ClassID class_ID,
SharedData &shared_data
):
L4MechControlsMapper(owner, subsystem_ID, subsystem_name, class_ID, shared_data)
{
}
MechRIOMapper::~MechRIOMapper()
{
}
Logical
MechRIOMapper::TestInstance() const
{
return IsDerivedFrom(ClassDerivations);
}
+34
View File
@@ -0,0 +1,34 @@
//===========================================================================//
// File: btl4mssn.cpp //
// Project: BattleTech //
// Contents: Implementation details for the BT L4 mission //
//---------------------------------------------------------------------------//
// Copyright (C) 1995, Virtual World Entertainment, Inc. //
// All Rights reserved worldwide //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
//===========================================================================//
#include <btl4.hpp>
#pragma hdrstop
#if !defined(BTL4MSSN_HPP)
# include <btl4mssn.hpp>
#endif
BTL4Mission::BTL4Mission(
NotationFile *notation_file,
ResourceFile *resources
):
BTMission(notation_file, resources)
{
}
BTL4Mission::~BTL4Mission()
{
}
void
BTL4Mission::SetPlayerData(NotationFile *)
{
Fail("BTL4Mission::SetPlayerData -- btl4mssn.cpp not yet reconstructed");
}
+43
View File
@@ -0,0 +1,43 @@
//===========================================================================//
// File: btl4vid.cpp //
// Project: BattleTech //
// Contents: Implementation details for the BT video renderer //
//---------------------------------------------------------------------------//
// Copyright (C) 1995, Virtual World Entertainment, Inc. //
// All Rights reserved worldwide //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
//===========================================================================//
#include <btl4.hpp>
#pragma hdrstop
#if !defined(BTL4VID_HPP)
# include <btl4vid.hpp>
#endif
BTL4VideoRenderer::BTL4VideoRenderer(
RendererRate calibration_rate,
RendererComplexity calibration_complexity,
RendererPriority calibration_priority,
InterestType interest_type,
InterestDepth depth_calibration
):
DPLRenderer(
calibration_rate,
calibration_complexity,
calibration_priority,
interest_type,
depth_calibration
)
{
}
BTL4VideoRenderer::~BTL4VideoRenderer()
{
}
void
BTL4VideoRenderer::LoadMissionImplementation(Mission *)
{
Fail("BTL4VideoRenderer::LoadMissionImplementation -- btl4vid.cpp not yet reconstructed");
}
File diff suppressed because it is too large Load Diff
+540
View File
@@ -0,0 +1,540 @@
# if !defined(MUNGA_HPP)
# include <munga.hpp>
# endif
#pragma hdrstop
# if !defined(AUDREND_HPP)
# include <audrend.hpp>
# endif
# if !defined(AUDENT_HPP)
# include <audent.hpp>
# endif
# if !defined(JMOVER_HPP)
# include <jmover.hpp>
# endif
# if !defined(APP_HPP)
# include <app.hpp>
# endif
//#############################################################################
//########################### AudioRenderer #############################
//#############################################################################
//
//#############################################################################
// AudioRenderer
//#############################################################################
//
AudioRenderer::AudioRenderer(RendererRate render_rate):
Renderer(
render_rate,
MaxRendererComplexity,
DefaultRendererPriority,
AudioInterestType,
DefaultInterestDepth,
AudioRendererClassID
),
audioEventSocket(NULL, False)
{
audioHead = NULL;
#ifdef LAB_ONLY
sourceClippedCount = 0;
sourceStartCount = 0;
sourceSuspendCount = 0;
sourceResumeCount = 0;
doubleTriggerCount = 0;
resourceStealCount = 0;
resourceStealPriorityCount = 0;
resourceStealVolumeCount = 0;
stealShortDurationCount = 0;
#endif
}
//
//#############################################################################
// ~AudioRenderer
//#############################################################################
//
AudioRenderer::~AudioRenderer()
{
Unregister_Object(audioHead);
delete audioHead;
#ifdef LAB_ONLY
cout << "AudioRenderer::~AudioRenderer - sourceClippedCount="
<< sourceClippedCount << "\n";
cout << "AudioRenderer::~AudioRenderer - sourceStartCount="
<< sourceStartCount << "\n";
cout << "AudioRenderer::~AudioRenderer - sourceSuspendCount="
<< sourceSuspendCount << "\n";
cout << "AudioRenderer::~AudioRenderer - sourceResumeCount="
<< sourceResumeCount << "\n";
cout << "AudioRenderer::~AudioRenderer - doubleTriggerCount="
<< doubleTriggerCount << "\n";
cout << "AudioRenderer::~AudioRenderer - resourceStealCount="
<< resourceStealCount << "\n";
cout << "AudioRenderer::~AudioRenderer - resourceStealPriorityCount="
<< resourceStealPriorityCount << "\n";
cout << "AudioRenderer::~AudioRenderer - resourceStealVolumeCount="
<< resourceStealVolumeCount << "\n";
cout << "AudioRenderer::~AudioRenderer - stealShortDurationCount="
<< stealShortDurationCount << "\n";
#endif
}
//
//#############################################################################
// Initialize
//#############################################################################
//
void
AudioRenderer::Initialize()
{
audioHead = MakeAudioHead();
Register_Object(audioHead);
}
//
//#############################################################################
// TestInstance
//#############################################################################
//
Logical
AudioRenderer::TestInstance() const
{
Renderer::TestInstance();
if (audioHead != NULL)
{
Check(audioHead);
}
Check(&audioEventSocket);
return True;
}
//
//#############################################################################
// LinkToEntity
//#############################################################################
//
void
AudioRenderer::LinkToEntity(Entity *entity)
{
Check(this);
Check(entity);
//
//--------------------------------------------------------------------------
// Link the head to the entity
//--------------------------------------------------------------------------
//
Check(audioHead);
audioHead->LinkToEntity(entity);
//
//--------------------------------------------------------------------------
// Call inherited method
//--------------------------------------------------------------------------
//
Renderer::LinkToEntity(entity);
}
//
//#############################################################################
// ExecuteImplementation
//#############################################################################
//
void
AudioRenderer::ExecuteImplementation(
RendererComplexity,
RendererOrigin::InterestingEntityIterator*
)
{
Check(this);
Check(audioHead);
audioHead->Execute();
}
//
//#############################################################################
// PostAudioRequestMessage
//#############################################################################
//
void
AudioRenderer::PostAudioRequestMessage(
AudioSource *audio_source,
AudioSource::RequestMessage *message
)
{
Check(this);
Check(audio_source);
Check(message);
//
//--------------------------------------------------------------------------
// If audio source is clipped and the source is transient
// Then ignore
// Else set priority and volume
//--------------------------------------------------------------------------
//
AudioSourcePriority
audio_source_priority;
AudioControlValue
audio_source_volume_scale;
if (audio_source->IsAudioSourceClipped(GetAudioHead()))
{
//
// If it is a transient source then ignore request
//
if (audio_source->GetAudioRenderType() == TransientAudioRenderType)
{
#ifdef LAB_ONLY
sourceClippedCount++;
#endif
return;
}
audio_source_priority = audio_source->GetAudioSourcePriority();
audio_source_volume_scale = 0.0f;
}
else
{
audio_source_priority = audio_source->GetAudioSourcePriority();
// (task #50, AUDIO_FIDELITY F19) COLD-START PRIME: an idle source's own
// watcher socket only executes at Start attempts, so its authored
// AudioControlSmoothers (footstep volume: N=30/15, fill 0) warmed ONE
// sample per attempt -- and the transient drop gate below (vol < 0.3)
// rejected the first ~25 footfalls (~10-20 s of silent steps) before
// the average could cross the gate. On a Start request, pump the
// source's watchers a full smoother window so the volume chain is
// evaluated at its True steady state; the smoother keeps its authored
audio_source_volume_scale = audio_source->CalculateSourceVolumeScale();
}
//
//--------------------------------------------------------------------------
// If this a transient source and volume is lower than threshold
// Then return
//--------------------------------------------------------------------------
//
// DIAG (BT_AUDIO_NODROP): deliver low-volume transient starts anyway (at a
// floor volume) to isolate volume-feed problems from the rest of the chain.
if (getenv("BT_AUDIO_NODROP") &&
message->controlID == StartAudioControlID &&
audio_source->GetAudioRenderType() == TransientAudioRenderType &&
audio_source_volume_scale < LowAudioVolumeThreshold)
{
DEBUG_STREAM << "[spatial] NODROP forcing start src=" << (void*)audio_source
<< " vol=" << audio_source_volume_scale << "\n" << flush;
audio_source->ReceiveControl(VolumeAudioControlID, 0.7f);
audio_source_volume_scale = 0.7f;
}
if (
message->controlID == StartAudioControlID &&
audio_source->GetAudioRenderType() == TransientAudioRenderType &&
audio_source_volume_scale < LowAudioVolumeThreshold
)
{
#ifdef LAB_ONLY
sourceClippedCount++;
#endif
return;
}
//
//--------------------------------------------------------------------------
// Create audio weight based on priority and volume
// Add audio event
//--------------------------------------------------------------------------
//
AudioWeighting
audio_weight(audio_source_priority, audio_source_volume_scale);
AudioEvent
*audio_event;
audio_event = new AudioEvent(audio_source, message);
Register_Object(audio_event);
audioEventSocket.AddValue(audio_event, audio_weight);
}
//
//#############################################################################
// ProcessAudioRequestMessage
//#############################################################################
//
Logical
AudioRenderer::ProcessAudioRequestMessage()
{
//
// Process high priority, high volume event
//
AudioEventIterator
iterator(&audioEventSocket);
AudioEvent
*audio_event;
Logical stuff = False;
while ((audio_event = iterator.GetCurrent()) != NULL)
{
stuff = True;
Check(audio_event);
audio_event->Process();
//return True;
}
return stuff;
}
//
//#############################################################################
// FlushAudioMessages
//#############################################################################
//
void
AudioRenderer::FlushAudioMessages(AudioSource *audio_source)
{
Check(this);
Check(audio_source);
//
// Process matching events
//
AudioEventIterator
iterator(&audioEventSocket);
AudioEvent
*audio_event;
while ((audio_event = iterator.ReadAndNext()) != NULL)
{
Check(audio_event);
if (audio_event->targetReceiver.GetCurrent() == audio_source)
{
if (audio_event->messageToSend->controlID == StopAudioControlID)
{
audio_event->Process();
}
else
{
Unregister_Object(audio_event);
delete audio_event;
}
}
}
}
//
//#############################################################################
// MakeAudioHead
//#############################################################################
//
AudioHead*
AudioRenderer::MakeAudioHead()
{
return new AudioHead;
}
//
//#############################################################################
// StartEntityEffectImplementation
//#############################################################################
//
void
AudioRenderer::StartEntityEffectImplementation(
Entity *parent_entity,
DamageZone *damage_zone,
ResourceDescription::ResourceID resource_ID
)
{
SET_AUDIO_RENDERER();
Check(this);
Check(parent_entity);
Check(damage_zone);
Verify(resource_ID != ResourceDescription::NullResourceID);
//
//--------------------------------------------------------------------------
// Get the audio resource for this effect
//--------------------------------------------------------------------------
//
ResourceDescription *audio_resource_description;
Check(application);
Check(application->GetResourceFile());
audio_resource_description =
application->GetResourceFile()->SearchList(
resource_ID,
ResourceDescription::AudioStreamListResourceType
);
if (audio_resource_description == NULL)
{
CLEAR_AUDIO_RENDERER();
return;
}
Check(audio_resource_description);
//
//--------------------------------------------------------------------------
// Get the resource ID for the model resource for the audio effect entity
//--------------------------------------------------------------------------
//
ResourceDescription *model_resource_description;
Check(application);
Check(application->GetResourceFile());
Check(audio_resource_description);
model_resource_description =
application->GetResourceFile()->SearchList(
audio_resource_description->resourceID,
ResourceDescription::ModelListResourceType
);
if (model_resource_description == NULL)
{
CLEAR_AUDIO_RENDERER();
return;
}
Check(model_resource_description);
model_resource_description->Lock();
audio_resource_description->Lock();
//
//--------------------------------------------------------------------------
// Get the entity segment
//--------------------------------------------------------------------------
//
Entity *linked_entity;
AudioRepresentation audio_representation;
EntitySegment *parent_entity_segment;
linked_entity = GetLinkedEntity();
Check(linked_entity);
audio_representation =
(AudioRepresentation)parent_entity->GetAudioRepresentation(
linked_entity
);
parent_entity_segment = damage_zone->GetCurrentEffectSite(
(audio_representation == InternalAudioRepresentation) ?
DamageZone::InternalAudioEffectSite :
DamageZone::ExternalAudioEffectSite
);
Check(parent_entity_segment);
//
//--------------------------------------------------------------------------
// Create the audio effect entity with this resource
//--------------------------------------------------------------------------
//
JointedMover *jointed_mover;
Verify(parent_entity->IsDerivedFrom(JointedMover::ClassDerivations));
jointed_mover = Cast_Object(JointedMover*, parent_entity);
Check(jointed_mover);
AudioEntity::MakeMessage
make_message(
model_resource_description->resourceID,
jointed_mover,
parent_entity_segment
);
#if DEBUG_LEVEL>0
AudioEntity *audio_entity =
#endif
AudioEntity::Make(&make_message);
Register_Object(audio_entity);
model_resource_description->Unlock();
audio_resource_description->Unlock();
CLEAR_AUDIO_RENDERER();
}
//~~~~~~~~~~~~~~~~~~~~~~~~ AudioRenderer profile bits ~~~~~~~~~~~~~~~~~~~~~~~~~
#if defined(TRACE_AUDIO_RENDERER)
BitTrace Audio_Renderer("Audio Renderer");
#endif
#if defined(TRACE_AUDIO_RENDERER_CREATE_OBJECTS)
BitTrace Audio_Renderer_Create_Objects("Audio Renderer Create Objects");
#endif
#if defined(TRACE_AUDIO_RENDERER_DESTROY_OBJECTS)
BitTrace Audio_Renderer_Destroy_Objects("Audio Renderer Destroy Objects");
#endif
#if defined(TRACE_AUDIO_RENDERER_START_HANDLER)
BitTrace Audio_Renderer_Start_Handler("Audio Renderer Start Handler");
#endif
#if defined(TRACE_AUDIO_RENDERER_STOP_HANDLER)
BitTrace Audio_Renderer_Stop_Handler("Audio Renderer Stop Handler");
#endif
#if defined(TRACE_AUDIO_RENDERER_EXECUTE)
BitTrace Audio_Renderer_Execute("Audio Renderer Execute");
#endif
//#############################################################################
//############################## AudioEvent #############################
//#############################################################################
MemoryBlock
AudioEvent::AllocatedMemory(sizeof(Event), AUDIOEVENT_MEMORYBLOCK_ALLOCATION, AUDIOEVENT_MEMORYBLOCK_ALLOCATION, "AudioEvents");
//
//#############################################################################
//#############################################################################
//
AudioEvent::AudioEvent(
AudioSource *target,
AudioSource::RequestMessage *message
):
targetReceiver(this)
{
Check(target);
Check(message);
//
// Store the message
//
size_t long_size = (message->messageLength+3)>>2;
messageToSend = (AudioSource::RequestMessage*)new long[long_size];
Check_Pointer(messageToSend);
Register_Pointer(messageToSend);
Mem_Copy(
messageToSend,
message,
message->messageLength,
long_size*sizeof(long)
);
//
// Store the target receiver
//
targetReceiver.Add(target);
}
//
//#############################################################################
//#############################################################################
//
AudioEvent::~AudioEvent()
{
Unregister_Pointer(messageToSend);
delete messageToSend;
}
//
//#############################################################################
//#############################################################################
//
void
AudioEvent::ReleaseLinkHandler(
Socket*,
Plug*
)
{
Unregister_Object(this);
delete this;
}
+3 -3
View File
@@ -233,10 +233,10 @@ private:
);
~AudioEvent();
static MemoryBlock* GetAllocatedMemory();
static MemoryBlock AllocatedMemory;
void* operator new(size_t) { return GetAllocatedMemory()->New(); }
void operator delete(void *where) { GetAllocatedMemory()->Delete(where); }
void* operator new(size_t) { return AllocatedMemory.New(); }
void operator delete(void *where) { AllocatedMemory.Delete(where); }
void
Process();
+4 -6
View File
@@ -16,18 +16,16 @@ class BoundingBoxTree;
class BoundingBoxTreeNode SIGNATURED
{
public:
static MemoryBlock
AllocatedMemory;
friend class BoundingBoxTree;
//##########################################################################
// Memory Allocation
//
private:
static MemoryBlock* GetAllocatedMemory();
void* operator new(size_t) { return GetAllocatedMemory()->New(); }
void operator delete(void *where) { GetAllocatedMemory()->Delete(where); }
static MemoryBlock AllocatedMemory;
static MemoryBlock* GetAllocatedMemory() { return &AllocatedMemory; }
void* operator new(size_t) { return AllocatedMemory.New(); }
void operator delete(void *where) { AllocatedMemory.Delete(where); }
//##########################################################################
// Construction and Destruction
+450
View File
@@ -0,0 +1,450 @@
# if !defined(MUNGA_HPP)
# include <munga.hpp>
# endif
# if !defined(CSTR_HPP)
# include <cstr.hpp>
# endif
# if !defined(MEMSTRM_HPP)
# include <memstrm.hpp>
# endif
//namespace Munga
//{
rString StringRepresentation::operator+=(char chr)
{
Check(this);
size_t len = strlen(&firstByte);
*(&firstByte + len++) = chr;
*(&firstByte + len) = '\0';
return *this;
}
#if defined(USE_SIGNATURE)
int Is_Signature_Bad(const StringRepresentation *)
{
return False;
}
#endif
MemoryStream& MemoryStream_Read(MemoryStream *stream, StringRepresentation *str)
{
Check(stream);
Check(str);
pString ptr = *str;
for (*stream >> ptr[(size_t)0]; ptr[(size_t)0]; ++ptr)
*stream >> ptr[(size_t)0];
return *stream;
}
MemoryStream& MemoryStream_Write(MemoryStream *stream, const StringRepresentation &str)
{
Check(stream);
Check(&str);
return stream->WriteBytes((const char*)str, str.GetLength() + 1);
}
#define DELETE_FILL_CHAR ('0')
size_t CStringRepresentation::allocationIncrement = 8;
inline size_t CStringRepresentation::CalculateSize(size_t needed)
{
Verify(!Small_Enough(allocationIncrement));
size_t x = ((needed + allocationIncrement) / allocationIncrement) * allocationIncrement;
return x;
}
CStringRepresentation::CStringRepresentation()
{
stringLength = 0;
stringSize = 0;
stringText = NULL;
referenceCount = 0;
}
CStringRepresentation::CStringRepresentation(const CStringRepresentation &str)
{
Check(&str);
stringLength = str.stringLength;
stringSize = str.stringSize;
if (str.stringText == NULL)
stringText = NULL;
else
{
stringText = new char[stringSize];
Register_Pointer(stringText);
Mem_Copy(stringText, str.stringText, stringLength + 1, stringSize);
}
referenceCount = 0;
}
CStringRepresentation::CStringRepresentation(const char *cstr)
{
if ((cstr == NULL) || (cstr[0] == '\x00'))
{
stringLength = 0;
stringSize = 0;
stringText = NULL;
}
else
{
stringLength = strlen(cstr);
stringSize = CalculateSize(stringLength);
stringText = new char[stringSize];
Register_Pointer(stringText);
Mem_Copy(stringText, cstr, stringLength + 1, stringSize);
}
referenceCount = 0;
}
CStringRepresentation::~CStringRepresentation()
{
if (stringText != NULL)
{
#if DEBUG_LEVEL>0
memset(stringText, DELETE_FILL_CHAR, stringSize);
#endif
Unregister_Pointer(stringText);
delete[] stringText;
}
}
Logical CStringRepresentation::TestInstance() const
{
if (stringText == NULL)
{
Verify(stringSize == 0);
Verify(stringLength == 0);
}
else
{
Verify(stringSize > 0);
Verify(stringLength == strlen(stringText));
}
return True;
}
CStringRepresentation CStringRepresentation::operator = (const CStringRepresentation &str)
{
Check(this);
if (this == &str)
return *this;
if (stringText != NULL)
{
#if DEBUG_LEVEL>0
memset(stringText, DELETE_FILL_CHAR, stringSize);
#endif
Unregister_Pointer(stringText);
delete[] stringText;
}
Check(&str);
stringLength = str.stringLength;
stringSize = str.stringSize;
if (stringSize == 0)
stringText = NULL;
else
{
stringText = new char[stringSize];
Register_Pointer(stringText);
Mem_Copy(stringText, str.stringText, stringLength + 1, stringSize);
}
return *this;
}
CStringRepresentation CStringRepresentation::operator = (const char *cstr)
{
Check(this);
if (stringText != NULL)
{
#if DEBUG_LEVEL>0
memset(stringText, DELETE_FILL_CHAR, stringSize);
#endif
Unregister_Pointer(stringText);
delete[] stringText;
}
if ((cstr == NULL) || (cstr[0] == '\x00'))
{
stringLength = 0;
stringSize = 0;
stringText = NULL;
}
else
{
stringLength = strlen(cstr);
stringSize = CalculateSize(stringLength);
stringText = new char[stringSize];
Register_Pointer(stringText);
Mem_Copy(stringText, cstr, stringLength + 1, stringSize);
}
return *this;
}
CStringRepresentation operator + (const CStringRepresentation &str1, const CStringRepresentation &str2)
{
Check(&str1);
Check(&str2);
CStringRepresentation temp;
unsigned long totalLen = str1.stringLength + str2.stringLength;
if (totalLen == 0)
return temp;
temp.stringLength = 0;
temp.stringSize = CStringRepresentation::CalculateSize((size_t)totalLen);
temp.stringText = new char[temp.stringSize];
Register_Pointer(temp.stringText);
Verify(temp.stringSize >= 1);
temp.stringText[0] = '\000';
if (str1.stringText != NULL)
{
Mem_Copy(temp.stringText, str1.stringText, str1.stringLength, temp.stringSize);
temp.stringLength = str1.stringLength;
}
if (str2.stringText != NULL)
{
Verify(temp.stringLength < temp.stringSize);
Mem_Copy(&temp.stringText[temp.stringLength], str2.stringText, str2.stringLength + 1, temp.stringSize - temp.stringLength);
temp.stringLength += str2.stringLength;
}
Check(&temp);
return temp;
}
CStringRepresentation operator + (const CStringRepresentation &str, char ch)
{
Check(&str);
CStringRepresentation temp;
if (str.stringText == NULL)
{
temp.stringLength = 1;
temp.stringSize = CStringRepresentation::allocationIncrement;
temp.stringText = new char [temp.stringSize];
Register_Pointer(temp.stringText);
Verify(temp.stringSize >= 2);
temp.stringText[0] = ch;
temp.stringText[1] = '\000';
}
else
{
Verify(str.stringLength != UINT_MAX);
temp.stringLength = str.stringLength + 1;
if (temp.stringLength == str.stringSize)
temp.stringSize = str.stringSize + CStringRepresentation::allocationIncrement;
else
temp.stringSize = str.stringSize;
temp.stringText = new char[temp.stringSize];
Register_Pointer(temp.stringText);
Mem_Copy(temp.stringText, str.stringText, str.stringLength, temp.stringSize);
Verify(str.stringLength < temp.stringSize);
Verify(temp.stringLength < temp.stringSize);
temp.stringText[str.stringLength] = ch;
temp.stringText[temp.stringLength] = '\000';
}
Check(&temp);
return temp;
}
int CStringRepresentation::Compare(const CStringRepresentation &str) const
{
Check(this);
Check(&str);
// handle special cases where one string is empty
if (stringText == NULL)
{
if (str.stringText == NULL)
return 0;
else
return -1;
}
if (str.stringText == NULL)
return 1;
return strcmp(stringText, str.stringText);
}
CStringRepresentation CStringRepresentation::GetNthToken(size_t nth_token, char *delimiters) const
{
Check(this);
//
// Which delimters to use
//
char *delimter_string = " \t,";
if (delimiters != NULL)
delimter_string = delimiters;
Check_Pointer(delimter_string);
//
// Make temporary
//
CStringRepresentation temp(*this);
if (temp.stringText == NULL)
return temp;
//
// Parse string with strtok
//
size_t i;
char *ptr;
Check_Pointer(temp.stringText);
ptr = strtok(temp.stringText, delimter_string);
for (i = 0; i < nth_token; i++)
if ((ptr = strtok(NULL, delimter_string)) == NULL)
break;
if (ptr == NULL)
{
CStringRepresentation null_return;
return null_return;
}
CStringRepresentation token_return(ptr);
return token_return;
}
#if 0
void CStringRepresentation::ToUpper()
{
Check(this);
if (stringText != NULL)
strupr(stringText);
}
void CStringRepresentation::ToLower()
{
Check(this);
if (stringText != NULL)
strlwr(stringText);
}
#endif
MemoryStream& MemoryStream_Read(MemoryStream *stream, CStringRepresentation *str)
{
Check(stream);
Check(str);
size_t string_length;
char *ptr;
MemoryStream_Read(stream, &string_length);
ptr = new char[string_length + 1];
Register_Pointer(ptr);
stream->ReadBytes(ptr, string_length + 1);
*str = ptr;
Unregister_Pointer(ptr);
delete[] ptr;
Check(str);
return *stream;
}
MemoryStream& MemoryStream_Write(MemoryStream *stream, const CStringRepresentation &str)
{
Check(stream);
Check(&str);
MemoryStream_Write(stream, &str.stringLength);
return stream->WriteBytes(str.stringText, str.stringLength + 1);
}
void Convert_From_Ascii(const char *str, CStringRepresentation *value)
{
#if 0
Check_Pointer(str);
Check(value);
*value = str;
#else
if (str == NULL)
Fail("Convert_From_Ascii - str == NULL");
if (value == NULL)
Fail("Convert_From_Ascii - value == NULL");
*value = str;
#endif
}
CString CString::operator = (const CString &str)
{
Check(this);
Check(&str);
if (this == &str)
return *this;
Check(representation);
representation->DecrementReferenceCount();
representation = str.representation;
representation->IncrementReferenceCount();
return *this;
}
CString CString::operator = (const char *cstr)
{
Check(representation);
representation->DecrementReferenceCount();
representation = new CStringRepresentation(cstr);
Register_Object(representation);
representation->IncrementReferenceCount();
return *this;
}
MemoryStream& MemoryStream_Read(MemoryStream *stream, CString *str)
{
Check(str);
Check(str->representation);
str->representation->DecrementReferenceCount();
str->representation = new CStringRepresentation;
Register_Object(str->representation);
str->representation->IncrementReferenceCount();
Verify(str->representation->referenceCount == 1);
return MemoryStream_Read(stream, str->representation);
}
void Convert_From_Ascii(const char *str, CString *value)
{
Check(value);
Check(value->representation);
value->representation->DecrementReferenceCount();
value->representation = new CStringRepresentation;
Register_Object(value->representation);
value->representation->IncrementReferenceCount();
Verify(value->representation->referenceCount == 1);
Convert_From_Ascii(str, value->representation);
}
//}
#if defined(TEST_CLASS)
#include "cstr.tcp"
#endif
+625
View File
@@ -0,0 +1,625 @@
# if !defined(MUNGA_HPP)
# include <munga.hpp>
# endif
#pragma hdrstop
# if !defined(EXPTBL_HPP)
# include <exptbl.hpp>
# endif
# if !defined(NAMELIST_HPP)
# include <namelist.hpp>
# endif
# if !defined(REGISTRY_HPP)
# include <registry.hpp>
# endif
# if !defined(APP_HPP)
# include <app.hpp>
# endif
# if !defined(EXPLODE_HPP)
# include <explode.hpp>
# endif
# if !defined(DAMAGE_HPP)
# include <damage.hpp>
# endif
# if !defined(NOTATION_HPP)
# include <notation.hpp>
# endif
# if !defined(FILEUTIL_HPP)
# include <fileutil.hpp>
# endif
# if !defined(RENDERER_HPP)
# include <renderer.hpp>
# endif
//##############################################################################
//###################### Class ExplosionTableEntry ########################
//##############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ExplosionTableEntry::CreateExplosion(
const EntityID &entity_hit_ID,
const EntityID &creating_entity_ID,
const Point3D &explode_position
)
{
Check(this);
Origin explode_origin(Origin::Identity);
explode_origin = explode_position;
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Create the explosion MakeMessage
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Explosion::MakeMessage exp_message(
Explosion::MakeMessageID,
sizeof(Explosion::MakeMessage),
RegisteredClass::ExplosionClassID,
EntityID::Null,
explosionResourceID,
Explosion::DefaultFlags,
explode_origin,
entity_hit_ID,
creating_entity_ID
);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Calculate actual time based on time_delay
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Time when = Now();
when += timeDelay;
Check(application);
Registry *registry;
registry = application->GetRegistry();
Check_Pointer(registry);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Create a MakeEntityMessage
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Registry::MakeEntityMessage *registry_message;
registry_message = Registry::MakeEntityMessage::Make(&exp_message);
Register_Object(registry_message);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Post entity message to the registry
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
#if 0 // ECH 1/28/96
application->Post(
DefaultEventPriority,
registry,
registry_message,
when
);
#else
application->Post(
CreationEventPriority,
registry,
registry_message,
when
);
#endif
Unregister_Object(registry_message);
delete registry_message;
Check_Fpu();
}
//##############################################################################
// Construction/Destruction
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ExplosionTableEntry::ExplosionTableEntry(MemoryStream *exp_stream)
{
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Read in the data from the stream
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
*exp_stream >> damageLevel >> explosionResourceID >> graphicState;
*exp_stream >> timeDelay;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ExplosionTableEntry::~ExplosionTableEntry()
{
}
//##############################################################################
// Tool Support
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
ExplosionTableEntry::CreateStreamedExplosion(
ResourceFile *resource_file,
CString exp_file_name,
NotationFile *exp_file,
CString exp_page_name,
MemoryStream *explosion_stream
)
{
Check(exp_file);
//
//~~~~~~~~~~~~~~~~~~~~
// Get the DamageLevel
//~~~~~~~~~~~~~~~~~~~~
//
Scalar damage_level;
if (!exp_file->GetEntry(
exp_page_name,
"DamageLevel",
&damage_level
)
)
{
damage_level = -1.0f;
}
*explosion_stream << damage_level;
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Get the Explosion Model File
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char *explosion_model_file;
if (!exp_file->GetEntry(
exp_page_name,
"ExplosionModelFile",
&explosion_model_file
)
)
{
DEBUG_STREAM <<exp_file_name<<" : "<<exp_page_name<<" missing ExplosionModelFile!"<<endl << flush;
return False;
}
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Hunt for Model file in ResourceFile
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ResourceDescription *res;
res = resource_file->FindResourceDescription(
explosion_model_file,
ResourceDescription::ModelListResourceType
);
if (!res)
{
cout << exp_file_name << " cannot find " << explosion_model_file
<< " in resource file!\n";
return False;
}
//
//~~~~~~~~~~~~~~~~~~~~~~~~~
// Write out the resourceID
//~~~~~~~~~~~~~~~~~~~~~~~~~
//
*explosion_stream << res->resourceID;
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~
// Read in the Graphic State
//~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char *graphic_state_char;
Enumeration graphic_state;
if (exp_file->GetEntry(
exp_page_name,
"GraphicState",
&graphic_state_char
)
)
{
if (!strcmp(graphic_state_char, "Destroyed"))
{
graphic_state = DamageZone::DestroyedGraphicState;
}
else if (!strcmp(graphic_state_char, "Gone"))
{
graphic_state = DamageZone::GoneGraphicState;
}
}
else
{
graphic_state = DamageZone::ExistsGraphicState;
}
*explosion_stream << graphic_state;
//
//~~~~~~~~~~~~~~~~~~~~
// Get the TimeDelay
//~~~~~~~~~~~~~~~~~~~~
//
Scalar time_delay;
if (!exp_file->GetEntry(
exp_page_name,
"TimeDelay",
&time_delay
)
)
{
time_delay = 0.0f;
}
*explosion_stream << time_delay;
return True;
}
//##############################################################################
//######################## Class ExplosionTable ###########################
//##############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
ExplosionTable::CrossedDamageLevelThreshold(
Scalar old_value,
Scalar new_value
)
{
ExplosionTableIterator iterator(this);
ExplosionTableEntry *current_exp;
while ((current_exp = iterator.ReadAndNext()) != NULL)
{
if (
(old_value < current_exp->GetDamageLevel()) &&
(new_value >= current_exp->GetDamageLevel())
)
{
return True;
}
}
return False;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ExplosionTableEntry*
ExplosionTable::SelectDamageLevelEntry(Scalar damage_level)
{
ExplosionTableIterator iterator(this);
ExplosionTableEntry *current_exp;
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Choose ExplosionTableEntry by damage Level
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
while ((current_exp = iterator.ReadAndNext()) != NULL)
{
if (damage_level < current_exp->GetDamageLevel())
{
Check_Fpu();
return current_exp;
}
}
Check_Fpu();
return NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ExplosionTableEntry*
ExplosionTable::SelectGraphicStateEntry(Enumeration graphic_state)
{
ExplosionTableIterator iterator(this);
ExplosionTableEntry *current_entry;
while((current_entry = iterator.ReadAndNext() ) != NULL)
{
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Display Explosion if an Entry Exists
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
if (current_entry->GetGraphicState() == graphic_state)
{
Check_Fpu();
return current_entry;
}
}
Check_Fpu();
return NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ExplosionTable::CreateExplosion(
ExplosionTableEntry *explosion_entry,
const EntityID &entity_hit_ID,
const EntityID &creating_entity_ID,
Point3D explode_position
)
{
Check(this);
Check(explosion_entry);
explosion_entry->CreateExplosion(
entity_hit_ID,
creating_entity_ID,
explode_position
);
}
//##############################################################################
// Construction/Destruction
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ExplosionTable::ExplosionTable(MemoryStream *exp_stream):
TableOf<ExplosionTableEntry*, int>(NULL, True)
{
int entry_count;
*exp_stream >> entry_count;
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Create all of the ExplosionTableEntries
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ExplosionTableEntry *exp_entry;
for(int ii=0;ii<entry_count;++ii)
{
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Create a new ExplosionTableEntry
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
exp_entry = new ExplosionTableEntry(exp_stream);
Register_Object(exp_entry);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Add the entry the the ExplosionTable
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
AddValue(exp_entry, ii);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ExplosionTable::~ExplosionTable()
{
ExplosionTableIterator iterator(this);
iterator.DeletePlugs();
}
//##############################################################################
// Tool Support
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
ExplosionTable::CreateStreamedExplosionTable(
ResourceFile *resource_file,
CString model_name,
NotationFile *exp_file,
CString exp_filename,
MemoryStream *explosion_stream
)
{
Check(resource_file);
Check(exp_file);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Make a namelist of all Explosion Entries
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
NameList *exp_namelist = exp_file->MakePageList();
Register_Object(exp_namelist);
if (!exp_namelist->EntryCount())
{
DEBUG_STREAM << exp_file << " is empty or missing \n"<<endl << flush;
Unregister_Object(exp_namelist);
delete exp_namelist;
return False;
}
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Write the Number of Explosion Entries for this Entity
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int entry_count = exp_namelist->EntryCount();
*explosion_stream << entry_count;
NameList::Entry *exp_entry = exp_namelist->GetFirstEntry();
while(exp_entry)
{
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// While more pages Add ExplosionEntries to the stream
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ExplosionTableEntry::CreateStreamedExplosion(
resource_file,
exp_filename,
exp_file,
exp_entry->GetName(),
explosion_stream
);
exp_entry = exp_entry->GetNextEntry();
}
Unregister_Object(exp_namelist);
delete exp_namelist;
return True;
}
//##########################################################################
//###################### EntityEffectWatcher #########################
//##########################################################################
//##############################################################################
// Construction/Destruction
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
EntityEffectWatcher::EntityEffectWatcher(
Entity *entity_watched
)
{
entityWatched = entity_watched;
entityWatched->AddEffectWatcher(this);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Init array to hold previous damageLevel values
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Verify(entityWatched->damageZoneCount > 0);
oldDamageLevel = new Scalar[entityWatched->damageZoneCount];
Register_Pointer(oldDamageLevel);
for(int ii=0;ii<entityWatched->damageZoneCount;++ii)
{
oldDamageLevel[ii] = 0.0f;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
EntityEffectWatcher::~EntityEffectWatcher()
{
Unregister_Pointer(oldDamageLevel);
delete[] oldDamageLevel;
}
//##############################################################################
// Execute
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
EntityEffectWatcher::Execute()
{
Check(this);
Check(entityWatched);
Check_Pointer(entityWatched->damageZones);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Check the flags to see if any damageZones
// have been modified since the last Execute was called
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
DamageZone *current_zone;
ExplosionTable *exp_table;
ExplosionTableEntry *exp_entry(NULL);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Traverse damageZones looking for Changes
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
for (int ii=0;ii<entityWatched->damageZoneCount; ++ii)
{
current_zone = entityWatched->damageZones[ii];
Check(current_zone);
ResourceDescription::ResourceID exp_res;
exp_table = current_zone->GetExplosionTable();
Check(exp_table);
//
//~~~~~~~~~~~~~~~~~~~
// Check Damage Level
//~~~~~~~~~~~~~~~~~~~
//
if (current_zone->DamageLevelChanged())
{
exp_entry = exp_table->SelectDamageLevelEntry(current_zone->damageLevel);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// If delta was large enough signal an update
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
if (
exp_table->CrossedDamageLevelThreshold(
oldDamageLevel[ii],
current_zone->damageLevel
) &&
(entityWatched->GetInstance() == Entity::MasterInstance)
)
{
entityWatched->ForceUpdate(Entity::DamageZoneUpdateModelFlag);
}
oldDamageLevel[ii] = current_zone->damageLevel;
}
//
//~~~~~~~~~~~~~~~~~~~~
// Check Graphic State
//~~~~~~~~~~~~~~~~~~~~
//
if (current_zone->GraphicStateChanged())
{
exp_entry = exp_table->SelectGraphicStateEntry(
current_zone->GetGraphicState()
);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Always update for a graphic state change
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
if (entityWatched->GetInstance() == Entity::MasterInstance)
{
entityWatched->ForceUpdate(Entity::DamageZoneUpdateModelFlag);
}
}
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Notify RendererManager of Any Change
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
if (exp_entry)
{
Check(exp_entry);
exp_res = exp_entry->GetExplosionResourceID();
Check(application);
Check(application->GetRendererManager());
application->GetRendererManager()->StartEntityEffect(
entityWatched,
current_zone,
exp_res
);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Reset the DamageZone::changedFlags if
// I am a master and no update occurred OR
// if I am a replicant
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
if (
(
(entityWatched->GetInstance() == Entity::MasterInstance) &&
!entityWatched->DamageZoneUpdateModelFlagSet()
) ||
(
(entityWatched->GetInstance() == Entity::ReplicantInstance)
)
)
{
current_zone->ResetChangedFlags();
}
}
exp_entry = NULL;
}
Check_Fpu();
}
//##############################################################################
// Test Support
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
EntityEffectWatcher::TestInstance() const
{
Check(entityWatched);
return True;
}
+832
View File
@@ -0,0 +1,832 @@
# if !defined(MUNGA_HPP)
# include <munga.hpp>
# endif
#pragma hdrstop
#include <dir.h>
#include <direct.h>
# if !defined(FILEUTIL_HPP)
# include <fileutil.hpp>
# endif
# if !defined(NOTATION_HPP)
# include <notation.hpp>
# endif
char *WorkingDirectory = NULL;
//#############################################################################
const char *White_Space = " \t\n";
//#############################################################################
char
*SourceDirectory = NULL,
*ConfigDirectory = NULL,
*MaterialDirectory = NULL,
*TextureDirectory = NULL,
*AnimationDirectory = NULL,
*ProductionDirectory = NULL;
const char
*OutputDirectory = NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
SetSourceDirectory(const char *input_file)
{
Check_Pointer(input_file);
static const char
* const ARTTOOLS_FILENAME = ".arttoolsrc",
* const DIRECTORIES_PAGE = "directories",
* const CFG_DIR_ENTRY = "cfg_dir",
* const MTL_DIR_ENTRY = "mtl_dir",
* const TEX_DIR_ENTRY = "tex_dir",
* const KIN_DIR_ENTRY = "kin_dir",
* const PRD_DIR_ENTRY = "prd_dir";
NotationFile
*tools_info;
char
*cwd;
const char
*cp,
*contents;
//------------------------------------------------
// parse the source directory from the input file
//------------------------------------------------
if ((cp = strrchr(input_file, '/')) == NULL)
{
//---------------------------------------------------
// set source directory to current working directory
//---------------------------------------------------
cwd = getcwd(NULL, 256);
Verify( cwd );
SourceDirectory = new char[strlen(cwd) + 2];
Register_Pointer(SourceDirectory);
strcpy(SourceDirectory, cwd);
strcat(SourceDirectory, "/");
free(cwd);
}
else
{
//------------------------------------------------------
// set source directory to path specified in input file
//------------------------------------------------------
++cp;
SourceDirectory = new char[cp - input_file + 1];
Register_Pointer(SourceDirectory);
*SourceDirectory = '\0';
strncat(SourceDirectory, input_file, cp - input_file);
}
//-----------------------------------------------------------
// set other directories from tools config file (if present)
//-----------------------------------------------------------
tools_info = new NotationFile(SourceFile(ARTTOOLS_FILENAME));
Register_Object(tools_info);
if (tools_info->GetEntry(DIRECTORIES_PAGE, CFG_DIR_ENTRY, &contents))
{
ConfigDirectory = new char[strlen(contents) + 2];
Register_Pointer(ConfigDirectory);
strcpy(ConfigDirectory, contents);
cp = strchr(contents, '\0');
if (cp > contents && *--cp != '/')
{
strcat(ConfigDirectory, "/");
}
}
else
{
ConfigDirectory = SourceDirectory;
}
if (tools_info->GetEntry(DIRECTORIES_PAGE, MTL_DIR_ENTRY, &contents))
{
MaterialDirectory = new char[strlen(contents) + 2];
Register_Pointer(MaterialDirectory);
strcpy(MaterialDirectory, contents);
cp = strchr(contents, '\0');
if (cp > contents && *--cp != '/')
{
strcat(MaterialDirectory, "/");
}
}
else
{
MaterialDirectory = SourceDirectory;
}
if (tools_info->GetEntry(DIRECTORIES_PAGE, TEX_DIR_ENTRY, &contents))
{
TextureDirectory = new char[strlen(contents) + 2];
Register_Pointer(TextureDirectory);
strcpy(TextureDirectory, contents);
cp = strchr(contents, '\0');
if (cp > contents && *--cp != '/')
{
strcat(TextureDirectory, "/");
}
}
else
{
TextureDirectory = MaterialDirectory; // this one is different!
}
if (tools_info->GetEntry(DIRECTORIES_PAGE, KIN_DIR_ENTRY, &contents))
{
AnimationDirectory = new char[strlen(contents) + 2];
Register_Pointer(AnimationDirectory);
strcpy(AnimationDirectory, contents);
cp = strchr(contents, '\0');
if (cp > contents && *--cp != '/')
{
strcat(AnimationDirectory, "/");
}
}
else
{
AnimationDirectory = SourceDirectory;
}
if (tools_info->GetEntry(DIRECTORIES_PAGE, PRD_DIR_ENTRY, &contents))
{
ProductionDirectory = new char[strlen(contents) + 2];
Register_Pointer(ProductionDirectory);
strcpy(ProductionDirectory, contents);
cp = strchr(contents, '\0');
if (cp > contents && *--cp != '/')
{
strcat(ProductionDirectory, "/");
}
}
else
{
ProductionDirectory = SourceDirectory;
}
OutputDirectory = SourceDirectory;
Unregister_Object(tools_info);
delete tools_info;
return;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
SetOutputDirectory(const char *directory)
{
Check_Pointer(directory);
OutputDirectory = directory;
return;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char*
GetSourceDirectory()
{
return SourceDirectory;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char*
GetConfigDirectory()
{
return ConfigDirectory;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char*
GetMaterialDirectory()
{
return MaterialDirectory;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char*
GetTextureDirectory()
{
return TextureDirectory;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char*
GetAnimationDirectory()
{
return AnimationDirectory;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char*
GetProductionDirectory()
{
return ProductionDirectory;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char*
GetOutputDirectory()
{
return OutputDirectory;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ClearDirectories()
{
//do not clear output directory
if (ProductionDirectory && ProductionDirectory != SourceDirectory)
{
Unregister_Pointer(ProductionDirectory);
delete ProductionDirectory;
}
if (AnimationDirectory && AnimationDirectory != SourceDirectory)
{
Unregister_Pointer(AnimationDirectory);
delete AnimationDirectory;
}
if (TextureDirectory && TextureDirectory != MaterialDirectory) //different!
{
Unregister_Pointer(TextureDirectory);
delete TextureDirectory;
}
if (MaterialDirectory && MaterialDirectory != SourceDirectory)
{
Unregister_Pointer(MaterialDirectory);
delete MaterialDirectory;
}
if (ConfigDirectory && ConfigDirectory != SourceDirectory)
{
Unregister_Pointer(ConfigDirectory);
delete ConfigDirectory;
}
if (SourceDirectory)
{
Unregister_Pointer(SourceDirectory);
delete SourceDirectory;
}
return;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char*
DirectoryPlusFilename(
const char *directory,
const char *filename,
const char *extension
)
{
//do not check directory here
Check_Pointer(filename);
//do not check extension here
static char
buffer[512];
int
length;
if (!directory) { directory = "\0"; }
Check_Pointer(directory);
length = strlen(directory);
if (extension)
{
Check_Pointer(extension);
length += strlen(StripExtension(StripDirectory(filename)));
length += *extension == '.'?0:1;
length += strlen(extension);
}
else
{
length += strlen(StripDirectory(filename));
}
if (length >= ELEMENTS(buffer))
{
DEBUG_STREAM <<
": Program Error - buffer[] too small in DirectoryPlusFilename().\n" << flush;
Fail("Exiting");
}
strcpy(buffer, directory);
if (extension)
{
strcat(buffer, StripExtension(StripDirectory(filename)));
if (*extension != '.')
{
strcat(buffer, ".");
}
strcat(buffer, extension);
}
else
{
strcat(buffer, StripDirectory(filename));
}
return buffer;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char*
SourceFile(
const char *filename,
const char *extension
)
{
return DirectoryPlusFilename(SourceDirectory, filename, extension);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char*
ConfigFile(
const char *filename,
const char *extension
)
{
return DirectoryPlusFilename(ConfigDirectory, filename, extension);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char*
MaterialFile(
const char *filename,
const char *extension
)
{
return DirectoryPlusFilename(MaterialDirectory, filename, extension);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char*
TextureFile(
const char *filename,
const char *extension
)
{
return DirectoryPlusFilename(TextureDirectory, filename, extension);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char*
AnimationFile(
const char *filename,
const char *extension
)
{
return DirectoryPlusFilename(AnimationDirectory, filename, extension);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char*
OutputFile(
const char *filename,
const char *extension
)
{
return DirectoryPlusFilename(OutputDirectory, filename, extension);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char*
StripDirectory(const char *filename)
{
Check_Pointer(filename);
if (DirectoryIsSpecified(filename))
{
const char
*p;
//--------------------------------------
// parse the filename from the filepath
//--------------------------------------
p = strchr(filename, '\0');
Verify( p );
while (*p != '\\' && p != filename)
{
--p;
}
if (*p == '\\')
{
++p;
}
filename = p;
}
return filename;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char*
StripExtension(const char *filename)
{
Check_Pointer(filename);
static char
buffer[512];
char
*p;
if (strlen(filename) >= sizeof(buffer))
{
//DEBUG_STREAM << ProgName <<
// ": Program Error - buffer[] too small in StripExtension()." << endl;
DEBUG_STREAM <<
": Program Error - buffer[] too small in StripExtension()." << endl << flush;
Fail("Exiting");
}
strcpy(buffer, filename);
//------------------------------------
// remove the extension from filename
//------------------------------------
p = strchr(buffer, '\0');
Verify( p );
while (*p != '.' && p != buffer)
{
--p;
}
if (*p == '.')
{
*p = '\0';
}
return buffer;
}
//#############################################################################
char*
Ind(int level)
{
const int buf_len = 128;
static char buf[buf_len];
//---------------------------------------------------------
// Return string of spaces used to indent an output stream
//---------------------------------------------------------
buf[0] = '\0';
if (level > 63) level = 63; // floor((buf_len - 1)/number of spaces per indent)
for (; level > 0; --level)
{
strcat(buf, " ");
}
return buf;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical GetLine(istream &stream, char *buffer, int size_of_buffer)
{
static char temp_buffer[512];
//-------------------------------------------------------------
// read next line(s) from input stream automatically resolving
// lines with a continuation character '\' at the end
//-------------------------------------------------------------
if (stream.getline(buffer, size_of_buffer))
{
char *p;
int i;
while (True)
{
if ((i = strlen(buffer)) > (size_of_buffer - 2))
{
//DEBUG_STREAM << ProgName << ": ERROR - Input line too long." << endl << flush;
DEBUG_STREAM << ": ERROR - Input line too long." << endl << flush;
break;
}
p = buffer + i;
while (p-- > buffer && isspace(*p)); // find last non-blank character
if (p >= buffer && *p == '\\')
{
if (stream.getline(temp_buffer, sizeof(temp_buffer)))
{
*p = ' ';
++p;
strncat(p, temp_buffer, size_of_buffer - (p - buffer));
}
else
{
break;
}
}
else
{
break;
}
}
return True;
}
else
{
*buffer = '\0';
return False;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#if 0
char*
stripname(char filename[])
{
// Doesn't work
char
file2[200];
char
*filetosendback;
int
wordlength,
count,
countbackward,
length;
length = strlen(filename);
count = 0;
countbackward = length-1;
while (filename[countbackward-1] != '\\')
{
--countbackward;
}
wordlength = length - countbackward;
for (count = 0; count < wordlength; ++count)
{
file2[count] = filename[countbackward];
++countbackward;
}
file2[count] = '\0';
filetosendback = strdup(file2);
return filetosendback;
}
#endif
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Scalar
D2R(float degrees)
{
return degrees*(3.14159259f/180.0f);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
char*
MakeWorkingDirectory(
const char *file
)
{
char *directory;
const char *p;
int size;
p = file;
for (int i = (strlen(file) - 1 ); i >= 0; --i)
{
if ( (*p == '/') || (*p == '\\') )
{
size = strlen(file) - i + 1;
directory = new char[size];
strncpy(directory, file, size);
return directory;
}
++p;
}
//
// Else return local directory
//
#define BUFFER_SIZE (256)
char buffer[BUFFER_SIZE];
getcwd(buffer, BUFFER_SIZE);
#if 0
directory = strdup(buffer);
strcat(directory, "\\"); // ECH 1/29/96 - This is an overwrite
#else
Str_Cat(buffer, "\\", BUFFER_SIZE);
size = strlen(buffer) + 1;
directory = new char[size];
Str_Copy(directory, buffer, size);
#endif
//
// This is "\\" for DOS
//
return directory;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Logical
DirectoryIsSpecified(
const char *file
)
{
return strchr(file,'/') || strchr(file,':') || strchr(file,'\\');
#if 0
const char *p;
p = file;
for (int i = 0; i < strlen(file); ++i)
{
if ( (*p == '/') || (*p == '\\') )
{
return True;
}
++p;
}
return False;
#endif
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
char*
MakePathedFilename(
const char *directory,
const char *name
)
{
char *filename;
if (DirectoryIsSpecified(name))
{
filename = new char[ strlen(name) + 1];
strcpy(filename, name);
return filename;
}
if (directory == NULL)
{
filename = new char[strlen(name) + 1];
strcpy(filename, name);
}
else
{
filename = new char[strlen(directory) + strlen(name) + 1];
strcpy(filename, directory);
strcat(filename, name);
}
return filename;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void OpenOutput(ofstream &stream, const char *directory, const char *filename)
{
//do not check directory here
Check_Pointer(filename);
char
*file_to_open;
if (DirectoryIsSpecified(filename) || directory == NULL)
{
file_to_open = new char[strlen(filename) + 1];
Register_Pointer(file_to_open);
strcpy(file_to_open, filename);
}
else
{
Check_Pointer(directory);
file_to_open = new char[strlen(directory) + strlen(filename) + 1];
Register_Pointer(file_to_open);
strcpy(file_to_open, directory);
strcat(file_to_open, filename);
}
stream.open(file_to_open);
Unregister_Pointer(file_to_open);
delete file_to_open;
return;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void OpenInput(ifstream &stream, char *directory, const char *filename)
{
char tempfile[100];
if (DirectoryIsSpecified(filename))
{
strcpy(tempfile, filename);
}
else
{
if (directory != NULL)
{
strcpy(tempfile, directory);
strcat(tempfile, filename);
}
else
{
strcpy(tempfile, filename);
}
}
stream.open(tempfile);
return;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Logical
LabOnly(
NotationFile
*notation_file
)
{
if (notation_file->PageExists("LAB_ONLY"))
{
cout << "WARNING: LAB_ONLY" << endl;
return True;
}
else
{
return False;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
AddLabOnly(
NotationFile
*notation_file
)
{
if (!notation_file->PageExists("LAB_ONLY"))
{
notation_file->AppendEntry("LAB_ONLY", NULL, NULL);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Logical
DoesNotationFileExist(
NotationFile
*notation_file
)
{
Check(notation_file);
Check_Pointer(notation_file->GetFileName());
ifstream notation_file_stream(notation_file->GetFileName());
return (notation_file_stream) ? True : False;
}
//=============================================================================
+827
View File
@@ -0,0 +1,827 @@
# if !defined(MUNGA_HPP)
# include <munga.hpp>
# endif
#pragma hdrstop
# if !defined(GAUGE_HPP)
# include <gauge.hpp>
# endif
# if !defined(GAUGREND_HPP)
# include <gaugrend.hpp>
# endif
extern void
indent(int level); // in graph2d.cc
//#########################################################################
//############################# GaugeBase #################################
//#########################################################################
GaugeBase::GaugeBase(
ModeMask mode_mask,
GaugeRenderer *new_renderer,
unsigned int owner_ID,
const char *identification_string
) :
Node(Gauge::GaugeClassID),
alreadyActivatedFlag(False)
{
Check_Pointer(this);
modeMask = mode_mask;
ownerID = owner_ID;
renderer = new_renderer;
identificationString = identification_string;
stayInactive = True; // used by GaugeRenderer during activation
//---------------------------------------------------
// If renderer exists, add to object list
// (Not having a renderer allows for independent testing)
//---------------------------------------------------
if (renderer != NULL)
{
Check(renderer);
renderer->Add(this);
}
Check_Fpu();
}
GaugeBase::~GaugeBase()
{
Check(this);
Check_Fpu();
}
Logical
GaugeBase::TestInstance() const
{
return True;
}
void
GaugeBase::BecameActive()
{
Check(this);
//------------------------------------------------------
// Default method immediately inactivates the gaugeBase
//------------------------------------------------------
DEBUG_STREAM <<
"BecameActive() has not been defined for '" << identificationString <<
"'. About to call Inactivate()\n";
Inactivate();
Check_Fpu();
}
void
GaugeBase::BecameInactive()
{
Check(this);
Check_Fpu();
}
void
GaugeBase::Inactivate()
{
Check(this);
if (renderer != NULL)
{
Check(renderer);
renderer->Inactivate(this);
}
Check_Fpu();
}
Logical
GaugeBase::Update(GaugeRate /*rate_mask*/)
{
Check(this);
//------------------------------------------------------
// Default method immediately inactivates the gaugeBase
//------------------------------------------------------
DEBUG_STREAM <<
"Update() has not been defined for '" << identificationString <<
"'. About to call Inactivate()\n";
Inactivate();
Check_Fpu();
return False;
}
void
GaugeBase::UpdateProfile(Scalar /*frame_percentage*/)
{
Check(this);
Check_Fpu();
}
void
GaugeBase::ReportProfile()
{
Check(this);
Check_Fpu();
}
void
GaugeBase::LinkToEntity(Entity */*entity*/)
{
Check(this);
Check_Fpu();
}
void
GaugeBase::NotifyOfNewInterestingEntity(Entity */*entity*/)
{
Check(this);
Check_Fpu();
}
void
GaugeBase::NotifyOfBecomingUninterestingEntity(Entity */*entity*/)
{
Check(this);
Check_Fpu();
}
int
GaugeBase::DiscernTier()
{
Check(this);
Check_Fpu();
return 0;
}
//#########################################################################
//########################## GaugeBackground ##############################
//#########################################################################
GaugeBackground::GaugeBackground(
ModeMask mode_mask,
GaugeRenderer *new_renderer,
unsigned int owner_ID,
const char *identification_string
) :
GaugeBase(mode_mask, new_renderer, owner_ID, identification_string)
{
Check_Pointer(this);
Check_Fpu();
}
//#########################################################################
//######################## GraphicGaugeBackground #########################
//#########################################################################
GraphicGaugeBackground::GraphicGaugeBackground(
ModeMask mode_mask,
GaugeRenderer *renderer,
unsigned int owner_ID,
int graphics_port_number,
const char *identification_string
) :
localView(
renderer == NULL ?
NULL :
renderer->GetGraphicsPort(graphics_port_number)
),
GaugeBackground(mode_mask, renderer, owner_ID, identification_string)
{
Check_Fpu();
}
//#########################################################################
//########################## GaugeConnection ##############################
//#########################################################################
GaugeConnection::GaugeConnection(int parameter_id)
{
Check_Pointer(this);
parameterID = parameter_id;
Check_Fpu();
}
GaugeConnection::~GaugeConnection()
{
Check_Fpu();
}
Logical
GaugeConnection::TestInstance() const
{
Check_Pointer(this);
return True;
}
void GaugeConnection::Update()
{
Fail("GaugeConnection::Update should not be called!\n");
}
void
GaugeConnection::ShowInstance(char *indent)
{
Check(this);
cout << indent << "GaugeConnection:\n";
char
temp[80];
Str_Copy(temp,indent, 80);
Str_Cat(temp,"...", 80);
cout << temp << "parameterID=" << parameterID << "\n" << flush;
Check_Fpu();
}
//#########################################################################
//################################# Gauge #################################
//#########################################################################
//----------------------------------------------------------------------------
// GaugeRate masks are used to spread out workload in a priority-based
// manner. Each GaugeRate refers to the branch of a binary tree as shown:
//
// A = every frame
// /--------------^--------------\ :
// FIRST TIER: B C = 1/2
// /------^-------\ /------^-------\ :
// 2ND: D E F G = 1/4
// /--^---\ /--^---\ /--^---\ /--^---\ :
// H I J K L M N O = 1/8
// / \ / \ / \ / \ / \ / \ / \ / \ :
// P Q R S T U V W X Y Z Z0 Z1 Z2 Z3 Z4 = 1/16
//
// Each 'tier' down indicates an update rate half that of the one above it.
//
// Note that rates Z0..Z4 cannot be specified through the gauge renderer's
// interpreter. They are available to automatically generated gauges, though.
//----------------------------------------------------------------------------
GaugeRate
Gauge::rateTable[31] =
{
gaugeRate_A, // every frame
gaugeRate_B, // every other frame
gaugeRate_C,
gaugeRate_D, // every 4th frame
gaugeRate_E,
gaugeRate_F,
gaugeRate_G,
gaugeRate_H, // every 8th frame
gaugeRate_I,
gaugeRate_J,
gaugeRate_K,
gaugeRate_L,
gaugeRate_M,
gaugeRate_N,
gaugeRate_O,
gaugeRate_P, // every 16th frame
gaugeRate_Q,
gaugeRate_R,
gaugeRate_S,
gaugeRate_T,
gaugeRate_U,
gaugeRate_V,
gaugeRate_W,
gaugeRate_X,
gaugeRate_Y,
gaugeRate_Z,
gaugeRate_Z0,
gaugeRate_Z1,
gaugeRate_Z2,
gaugeRate_Z3,
gaugeRate_Z4
};
//-------------------------------------------------------------------
// Gauge::NextXXXTierGaugeRate()
// - These functions attempt to spead out workload by returning the
// next available 'GaugeRate' in a given 'tier'.
//
// The higher level tiers bump the lower level tier indices to
// attempt to avoid placing too much load on the same higher-order
// branch of the tree.
//-------------------------------------------------------------------
static int
first_index = -1,
second_index = -1,
third_index = -1,
fourth_index = -1;
GaugeRate
Gauge::NextFirstTierGaugeRate()
{
//----------------------------------------
// Generate first index
//----------------------------------------
first_index = (++first_index) & 1;
//----------------------------------------
// Bump other indices to avoid same branch
//----------------------------------------
second_index += 2;
third_index += 4;
fourth_index += 8;
//----------------------------------------
// Return rate mask
//----------------------------------------
return rateTable[first_index + 1];
}
GaugeRate
Gauge::NextSecondTierGaugeRate()
{
//----------------------------------------
// Generate first index
//----------------------------------------
second_index = (++second_index) & 3;
//----------------------------------------
// Bump other indices to avoid same branch
//----------------------------------------
third_index += 2;
fourth_index += 4;
//----------------------------------------
// Return rate mask
//----------------------------------------
return rateTable[second_index + 3];
}
GaugeRate
Gauge::NextThirdTierGaugeRate()
{
//----------------------------------------
// Generate first index
//----------------------------------------
third_index = (++third_index) & 7;
//----------------------------------------
// Bump other indices to avoid same branch
//----------------------------------------
fourth_index += 2;
//----------------------------------------
// Return rate mask
//----------------------------------------
return rateTable[third_index + 7];
}
GaugeRate
Gauge::NextFourthTierGaugeRate()
{
//----------------------------------------
// Generate first index
//----------------------------------------
fourth_index = (++fourth_index) & 15;
//----------------------------------------
// Return rate mask
//----------------------------------------
return rateTable[fourth_index + 15];
}
GaugeRate
Gauge::ConvertIndexToRate(int index)
{
Verify(index >= 0);
Verify(index < 32);
return rateTable[index];
}
Gauge::Gauge(
GaugeRate new_rate,
ModeMask mode_mask,
GaugeRenderer *renderer,
unsigned int owner_ID,
const char *identification_string
):
GaugeBase(mode_mask, renderer, owner_ID, identification_string),
instanceList(this)
{
Check_Pointer(this);
rate = new_rate;
oldRate = new_rate;
stayInactive = False;
profileFramePercentage = (Scalar) 0;
profileMaxFramePercentage = (Scalar) 0;
profileCycles = 0;
Check_Fpu();
}
Gauge::~Gauge()
{
Check(this);
RemoveAllConnections();
Check_Fpu();
}
Logical
Gauge::TestInstance() const
{
Check(&instanceList);
# if 0
//--------------------------------------------------------------------
// Check all owned GaugeConnections
//--------------------------------------------------------------------
ChainIteratorOf<GaugeConnection*>
i(instanceList);
GaugeConnection
*the_connection;
while ((the_connection=i.ReadAndNext()) != NULL)
{
Check(the_connection);
}
# endif
//--------------------------------------------------------------------
// Check the base object
//--------------------------------------------------------------------
return GaugeBase::TestInstance();
}
void
Gauge::ShowInstance(char *indent)
{
Check(this);
ChainIteratorOf<GaugeConnection*>
i(instanceList);
GaugeConnection
*the_connection;
cout << indent << "Gauge:\n";
char
temp[80];
Str_Copy(temp,indent, 80);
Str_Cat(temp,"...", 80);
cout << temp << "modeMask =" << modeMask << "\n";
cout << temp << "renderer =" << renderer << "\n";
cout << temp << "ownerID =" << ownerID << "\n";
cout << temp << "InstanceList -\n" << flush;
Str_Cat(temp,"...", 80);
while ((the_connection=i.ReadAndNext()) != NULL)
{
Check(the_connection);
the_connection->ShowInstance(temp);
}
Check_Fpu();
}
void
Gauge::AddConnection(GaugeConnection *connection)
{
Check(this);
Check(connection);
instanceList.Add(connection);
Check_Fpu();
}
void
Gauge::RemoveConnection(int parameter_ID)
{
Check(this);
ChainIteratorOf<GaugeConnection*>
i(instanceList);
GaugeConnection
*gauge_connection;
while ((gauge_connection=i.ReadAndNext()) != NULL)
{
Check(gauge_connection);
if (gauge_connection->parameterID == parameter_ID)
{
Unregister_Object(gauge_connection);
delete gauge_connection;
}
}
Check_Fpu();
}
void
Gauge::RemoveAllConnections()
{
Check(this);
ChainIteratorOf<GaugeConnection*>
i(instanceList);
GaugeConnection
*gauge_connection;
while ((gauge_connection=i.ReadAndNext()) != NULL)
{
Check(gauge_connection);
Unregister_Object(gauge_connection);
delete gauge_connection;
}
Check_Fpu();
}
void
Gauge::Disable(Logical disable_state)
{
Check(this);
if (disable_state)
{
rate = 0;
BecameInactive();
}
else
{
rate = oldRate;
BecameActive();
}
Check_Fpu();
}
Logical
Gauge::Update(GaugeRate rate_mask)
{
Check(this);
Logical
actually_ran = False;
//-----------------------------------------
// Update only if rate mask allows it
//-----------------------------------------
if (rate & rate_mask)
{
//-----------------------------------------
// Update parameters
//-----------------------------------------
ChainIteratorOf<GaugeConnection*>
i(instanceList);
GaugeConnection
*gauge_connection;
while ((gauge_connection=i.ReadAndNext()) != NULL)
{
Check(gauge_connection);
gauge_connection->Update();
}
//-----------------------------------------
// Execute gauge code
//-----------------------------------------
{
// BT DEV-GAUGES bring-up: run Execute() under SEH so a gauge whose
// game-state binding isn't reconstructed yet is DISABLED (rate=0)
// after its first fault instead of AV'ing every frame. Gated on
// BT_DEV_GAUGES; the pod build calls Execute() directly.
static int s_devGaugesUpd = -1;
if (s_devGaugesUpd < 0)
s_devGaugesUpd = (getenv("BT_DEV_GAUGES") != NULL ||
getenv("L4MFDSPLIT") != NULL) ? 1 : 0;
if (s_devGaugesUpd)
{
if (!GuardedExecute())
{
// LOUD KILL (2026-07-12): the silent version made a faulted
// gauge simply FREEZE on screen (user-hit: a weapon panel's
// dial + lamp died mid-session with no trace). Name the
// casualty so the log convicts the faulting Execute.
DEBUG_STREAM << "[gauge-fault] '"
<< (identificationString ? identificationString : "?")
<< "' Execute FAULTED -> gauge DISABLED (this="
<< (void *)this << ")\n" << flush;
Disable(True);
}
}
else
{
Execute();
}
}
actually_ran = True;
}
Check_Fpu();
return actually_ran;
}
void
Gauge::Execute()
{
Fail("Gauge::Execute not overridden");
}
//
// GuardedExecute -- BT DEV-GAUGES bring-up. Run Execute() under a structured
// exception handler so a gauge whose game-state data binding is not yet
// reconstructed is skipped instead of AV'ing the whole game. (A separate
// function because __try/__except may not share a frame with C++ objects that
// require unwinding, which Gauge::Update does.) Returns False on fault.
//
Logical
Gauge::GuardedExecute()
{
Execute();
return True;
}
struct TierLookup
{
GaugeRate rate;
int tier;
};
int
Gauge::DiscernTier()
{
Check(this);
TierLookup
*tier_pointer;
static TierLookup
tier_lookup[] =
{
{gaugeRate_A, 0 },
{gaugeRate_B, 1 },
{gaugeRate_C, 1 },
{gaugeRate_D, 2 },
{gaugeRate_E, 2 },
{gaugeRate_F, 2 },
{gaugeRate_G, 2 },
{gaugeRate_H, 3 },
{gaugeRate_I, 3 },
{gaugeRate_J, 3 },
{gaugeRate_K, 3 },
{gaugeRate_L, 3 },
{gaugeRate_M, 3 },
{gaugeRate_N, 3 },
{gaugeRate_O, 3 },
{gaugeRate_P, 4 },
{gaugeRate_Q, 4 },
{gaugeRate_R, 4 },
{gaugeRate_S, 4 },
{gaugeRate_T, 4 },
{gaugeRate_U, 4 },
{gaugeRate_V, 4 },
{gaugeRate_W, 4 },
{gaugeRate_X, 4 },
{gaugeRate_Y, 4 },
{gaugeRate_Z, 4 },
{gaugeRate_Z0,4 },
{gaugeRate_Z1,4 },
{gaugeRate_Z2,4 },
{gaugeRate_Z3,4 },
{gaugeRate_Z4,4 },
{0,0}
};
for (tier_pointer=tier_lookup; tier_pointer->rate != 0; ++tier_pointer)
{
if (tier_pointer->rate == rate)
{
Check_Fpu();
return tier_pointer->tier;
}
}
Check_Fpu();
return 0;
}
void
Gauge::UpdateProfile(Scalar frame_percentage)
{
Check(this);
//---------------------------------------------
// Keep worst case
//---------------------------------------------
if (profileMaxFramePercentage < frame_percentage)
{
profileMaxFramePercentage = frame_percentage;
}
//---------------------------------------------
// Keep running total
//---------------------------------------------
profileFramePercentage += frame_percentage;
//---------------------------------------------
// Prevent overflow
//---------------------------------------------
if (++profileCycles > 16384)
{
profileFramePercentage /= (Scalar) 2;
profileCycles >>= 1;
}
Check_Fpu();
}
void
Gauge::ReportProfile()
{
Check(this);
int
i;
DEBUG_STREAM << identificationString << flush;
for(i=strlen(identificationString); i<32; ++i)
{
DEBUG_STREAM << "." << flush;
}
if (profileCycles > 0)
{
Scalar
average = profileFramePercentage / (Scalar)profileCycles;
char
buffer[80];
sprintf(buffer, "%6d %6.4f %6.4f\n",
profileCycles,
average,
profileMaxFramePercentage
);
DEBUG_STREAM << buffer << flush;
}
else
{
DEBUG_STREAM << "never ran.\n" << flush;
}
//----------------------------------------
// Reset maximum percentage
//----------------------------------------
profileMaxFramePercentage = (Scalar) 0;
Check_Fpu();
}
//#########################################################################
//############################# GraphicGauge #############################
//#########################################################################
GraphicGauge::GraphicGauge(
GaugeRate new_rate,
ModeMask mode_mask,
GaugeRenderer *renderer,
unsigned int owner_ID,
int graphics_port_number,
const char *identification_string
) :
Gauge(new_rate, mode_mask, renderer, owner_ID, identification_string),
localView(
renderer == NULL ?
NULL :
renderer->GetGraphicsPort(graphics_port_number)
)
{
Check_Fpu();
}
GraphicGauge::~GraphicGauge()
{
Check(this);
Check_Fpu();
}
Logical
GraphicGauge::TestInstance() const
{
Check(&localView);
Check_Fpu();
return Gauge::TestInstance();
}
void
GraphicGauge::ShowInstance(char *indent)
{
Check(this);
cout << indent << "GraphicGauge:\n";
char
temp[80];
Str_Copy(temp,indent, 80);
Str_Cat(temp,"...", 80);
localView.ShowInstance(temp);
Gauge::ShowInstance(temp);
Check_Fpu();
}
#if defined(TEST_CLASS)
# include "gauge.tcp"
#endif
+744
View File
@@ -0,0 +1,744 @@
# if !defined(MUNGA_HPP)
# include <munga.hpp>
# endif
#pragma hdrstop
# if !defined(GAUGMAP_HPP)
# include <gaugmap.hpp>
# endif
# if !defined(POINT3D_HPP)
# include <point3d.hpp>
# endif
# if !defined(ENTITY_HPP)
# include <entity.hpp>
# endif
// #define LOCAL_TEST
#if defined(LOCAL_TEST)
# define Test_Tell(n) cout << n
#else
# define Test_Tell(n)
#endif
// 'FULL_EXTENT' is a value representing the total extent
// of the world in meters.
#define FULL_EXTENT 32767.0
#define HALF_EXTENT (FULL_EXTENT/2.0)
// 'LARGEST_RADIUS' defines a radius encompassing the largest existing entity
#define LARGEST_RADIUS 500.0 // HACK - this is a guess
//#############################################################################
// approximateDistance
// ...accurate to about 13%
// Graphics Gems, p.432, "A Fast Approximation To 3D Euclidean Distance"
//#############################################################################
Scalar
approximateDistance(Point3D *point1, Point3D *point2)
{
Check_Pointer(point1);
Check_Pointer(point2);
Scalar
max, mid, min, temp;
//-----------------------------------------------
// Get the three components in arbitrary order
//-----------------------------------------------
max = abs(point2->x - point1->x);
mid = abs(point2->y - point1->y);
min = abs(point2->z - point1->z);
//-----------------------------------------------
// Sort only the largest value to the top.
// We don't need to completely sort the values,
// as we weight the middle and smallest equally.
//-----------------------------------------------
if (max < mid)
{
temp=max; max=mid; mid=temp; // swap max, mid
}
if (max < min)
{
temp=max; max=min; min=temp; // swap max, min
}
//-----------------------------------------------
// return largest + 1/4 middle + 1/4 smallest
//-----------------------------------------------
Check_Fpu();
return max + ((mid+min)*.25);
}
//#############################################################################
// GaugeEntityList
//#############################################################################
//============================================================================
// Creator
//============================================================================
GaugeEntityList::GaugeEntityList() :
Node(GaugeEntityList::GaugeEntityListClassID),
instanceList(this)
{
Check_Fpu();
}
//============================================================================
// Destructor
//============================================================================
GaugeEntityList::~GaugeEntityList()
{
Check(this);
Clear(); // is this necessary, or are nodes automatically deleted?
Check_Fpu();
}
//============================================================================
// TestInstance
//============================================================================
Logical
GaugeEntityList::TestInstance() const
{
return Node::TestInstance();
}
//============================================================================
// Add
//============================================================================
void
GaugeEntityList::Add(Entity *entity)
{
Check(this);
Check(entity);
Check(&instanceList);
instanceList.Add(entity);
Check_Fpu();
}
//============================================================================
// Remove
//============================================================================
void
GaugeEntityList::Remove(Entity *search_entity)
{
Check(this);
Test_Tell(
"GaugeEntityList::Remove(" << search_entity <<
")\n"
);
Check(&instanceList);
ChainIteratorOf<Entity*>
i(instanceList);
Entity
*entity;
//-----------------------------------------------------
// Search the list for the given entity
//-----------------------------------------------------
while((entity=i.GetCurrent()) != NULL)
{
Check(entity);
//-----------------------------------------------------
// If we find it, remove it and exit
//-----------------------------------------------------
if (entity == search_entity)
{
Test_Tell("Found!\n");
i.Remove();
break;
}
else
{
i.Next();
}
}
Check_Fpu();
}
//============================================================================
// NumberOfItems
//============================================================================
int
GaugeEntityList::NumberOfItems()
{
Check(this);
ChainIteratorOf<Entity*>
i(instanceList);
Check_Fpu();
return i.GetSize();
}
//============================================================================
// Clear
//============================================================================
void
GaugeEntityList::Clear()
{
// Test_Tell("GaugeEntityList::Clear()\n");
Check(this);
ChainIteratorOf<Entity*>
i(instanceList);
//-----------------------------------------------------
// Remove all objects from the list
//-----------------------------------------------------
while(i.GetCurrent() != NULL)
{
Check(i.GetCurrent());
i.Remove();
}
Check_Fpu();
}
//============================================================================
// CopyEntities
//
// This method will create a reference in the destination list to
// all entities in the list
//============================================================================
int
GaugeEntityList::CopyEntities(
GaugeEntityList *destination,
Derivation *derivation_type
)
{
Test_Tell("GaugeEntityList::CopyEntities(" << destination << ")\n");
Check(this);
Check(destination);
ChainIteratorOf<Entity*>
i(instanceList);
Entity
*entity;
int
count(0);
//-----------------------------------------------------
// Return all items in the list
//-----------------------------------------------------
while ((entity=i.ReadAndNext()) != NULL)
{
Check(entity);
//-----------------------------------------------------
// Discard if wrong type
//-----------------------------------------------------
if (derivation_type != NULL)
{
if (! entity->IsDerivedFrom(*derivation_type))
{
continue;
}
}
//-----------------------------------------------------
// Add to the new list
//-----------------------------------------------------
destination->Add(entity);
++count;
}
Test_Tell("Found " << count << " items.\n");
Check_Fpu();
return count;
}
//============================================================================
// CopyEntitiesWithinBounds
//
// This method will create a reference in the destination list to
// all entities in the list that are within the given bounds (if supplied).
//============================================================================
int
GaugeEntityList::CopyEntitiesWithinBounds(
GaugeEntityList *destination,
Scalar min_x,
Scalar /*min_y*/,
Scalar min_z,
Scalar max_x,
Scalar /*max_y*/,
Scalar max_z,
Derivation *derivation_type
)
{
Test_Tell(
"GaugeEntityList::CopyEntitiesWithinBounds(" << destination <<
", " << min_x <<
"... , " << min_z <<
", " << max_x <<
"... , " << max_z <<
")\n"
);
Check(this);
Check(destination);
ChainIteratorOf<Entity*>
i(instanceList);
Entity
*entity;
Point3D
pos;
int
count(0);
//-----------------------------------------------------
// Check all items in the list
//-----------------------------------------------------
while ((entity=i.ReadAndNext()) != NULL)
{
Check(entity);
//-----------------------------------------------------
// Discard if wrong type
//-----------------------------------------------------
if (derivation_type != NULL)
{
if (! entity->IsDerivedFrom(*derivation_type))
{
continue;
}
}
//-----------------------------------------------------
// Get the item's position and radius
//-----------------------------------------------------
pos = entity->localOrigin.linearPosition;
//-----------------------------------------------------
// Add to the new list only if inside the bounds
//-----------------------------------------------------
Test_Tell(
"Testing (" << pos.x <<
", " << pos.y <<
", " << pos.z <<
")\n"
);
//if (pos.z >= min_z)
//{
// if (pos.z <= max_z)
// {
// if (pos.x >= min_x)
// {
// if (pos.x <= max_x)
{
Test_Tell("Accepted\n");
destination->Add(entity);
++count;
}
// }
// }
//}
}
Test_Tell("Found " << count << " items.\n");
Check_Fpu();
return count;
}
//#############################################################################
// GaugeEntityArray
//#############################################################################
//============================================================================
// Creator
//============================================================================
GaugeEntityArray::GaugeEntityArray()
{
minimumX= 0.0;
minimumY= 0.0;
minimumZ= 0.0;
maximumX= 0.0;
maximumY= 0.0;
maximumZ= 0.0;
Check_Fpu();
}
//============================================================================
// Destructor
//============================================================================
GaugeEntityArray::~GaugeEntityArray()
{
Check(this);
Clear();
Check_Fpu();
}
//============================================================================
// TestInstance
//============================================================================
Logical
GaugeEntityArray::TestInstance() const
{
return True;
}
//============================================================================
// Add
//============================================================================
void
GaugeEntityArray::Add(Entity *entity)
{
Test_Tell(
"GaugeEntityArray::Add(" << entity <<
")\n"
);
Check(this);
Check(entity);
//-----------------------------------------------------
// Add to the proper grid list
//-----------------------------------------------------
Point3D
pos(entity->localOrigin.linearPosition);
grid[ArrayOffset(pos.x)][ArrayOffset(pos.z)].Add(entity);
//-----------------------------------------------------
// Keep track of the total extents
//-----------------------------------------------------
if (pos.x < minimumX)
{
minimumX = pos.x;
}
if (pos.y < minimumY)
{
minimumY = pos.y;
}
if (pos.z < minimumZ)
{
minimumZ = pos.z;
}
if (pos.x > maximumX)
{
maximumX = pos.x;
}
if (pos.y > maximumY)
{
maximumY = pos.y;
}
if (pos.z > maximumZ)
{
maximumZ = pos.z;
}
Check_Fpu();
}
//============================================================================
// Remove
//============================================================================
void
GaugeEntityArray::Remove(Entity *entity)
{
Test_Tell(
"GaugeEntityArray::Remove(" << entity <<
")\n"
);
Check(this);
Check(entity);
Point3D
pos(entity->localOrigin.linearPosition);
//-----------------------------------------------------
// Remove from the proper grid list
//-----------------------------------------------------
grid[ArrayOffset(pos.x)][ArrayOffset(pos.z)].Remove(entity);
Check_Fpu();
}
//============================================================================
// Clear
//============================================================================
void
GaugeEntityArray::Clear()
{
Check(this);
int
x,
z;
//-----------------------------------------------------
// Clear all grid lists
//-----------------------------------------------------
for(z=0; z<gaugeMapArraySize; ++z)
{
for(x=0; x<gaugeMapArraySize; ++x)
{
grid[x][z].Clear();
}
}
//-----------------------------------------------------
// Set the bounds to zero
//-----------------------------------------------------
minimumX= 0.0;
minimumY= 0.0;
minimumZ= 0.0;
maximumX= 0.0;
maximumY= 0.0;
maximumZ= 0.0;
Check_Fpu();
}
//============================================================================
// PrintStatistics
//============================================================================
void
GaugeEntityArray::PrintStatistics()
{
Check(this);
int
x,
z,
n,
total(0);
//-----------------------------------------------------
// Count all grid lists
//-----------------------------------------------------
for(z=0; z<gaugeMapArraySize; ++z)
{
if (z < 10)
{
cout << " ";
}
cout << z << ":";
for(x=0; x<gaugeMapArraySize; ++x)
{
n = grid[x][z].NumberOfItems();
total += n;
if (n < 100)
{
cout << " ";
if (n < 10)
{
cout << " ";
}
}
cout << n << " ";
}
cout << "\n";
}
cout << "Total= " << total << "\n";
Check_Fpu();
}
//============================================================================
// CopyEntities
//
// This method will create a reference in the destination list to
// all GaugeImages in the array.
//============================================================================
int
GaugeEntityArray::CopyEntities(
GaugeEntityList *destination,
Derivation *derivation_type
)
{
Test_Tell(
"GaugeEntityArray::CopyEntities(" << destination << ")\n");
Check(this);
Check(destination);
int
x,
low_x,
high_x,
z,
high_z,
count(0);
//-----------------------------------------------------
// Generate the z search limits
//-----------------------------------------------------
z = 0;
high_z = gaugeMapArraySize - 1;
//-----------------------------------------------------
// Generate the x search limits
//-----------------------------------------------------
low_x = 0;
high_x = gaugeMapArraySize - 1;
//-------------------------------------------------------
// Search the grid for items
//-------------------------------------------------------
for( ; z<high_z; ++z)
{
for(x=low_x; x<high_x; ++x)
{
Test_Tell("Searching [" << x << "][" << z << "]\n");
count += grid[x][z].CopyEntities(destination, derivation_type);
}
}
Test_Tell("Search done, total found = " << count << " items.\n");
Check_Fpu();
return count;
}
//============================================================================
// CopyEntitiesWithinBounds
//
// This method will create a reference in the destination list to
// all GaugeImages in the array that are within the given bounds.
//============================================================================
int
GaugeEntityArray::CopyEntitiesWithinBounds(
GaugeEntityList *destination,
Scalar min_x,
Scalar min_y,
Scalar min_z,
Scalar max_x,
Scalar max_y,
Scalar max_z,
Derivation *derivation_type
)
{
Test_Tell(
"GaugeEntityArray::CopyEntitiesWithinBounds(" << destination <<
", " << min_x <<
", " << min_y <<
", " << min_z <<
", " << max_x <<
", " << max_y <<
", " << max_z <<
")\n"
);
Check(this);
Check(destination);
int
x,
low_x,
high_x,
z,
high_z,
count(0);
//-----------------------------------------------------
// Generate the z search limits
//-----------------------------------------------------
z = ArrayOffset(min_z - LARGEST_RADIUS);
high_z = ArrayOffset(max_z + LARGEST_RADIUS);
Test_Tell(
"Initial z =" << z <<
", high_z=" << high_z <<
"\n"
);
if (z < 0)
{
z = 0;
}
else if (z >= gaugeMapArraySize)
{
z = gaugeMapArraySize - 1;
}
if (high_z < 0)
{
high_z = 0;
}
else if (high_z >= gaugeMapArraySize)
{
high_z = gaugeMapArraySize - 1;
}
//-----------------------------------------------------
// Generate the x search limits
//-----------------------------------------------------
low_x = ArrayOffset(min_x - LARGEST_RADIUS);
high_x = ArrayOffset(max_x + LARGEST_RADIUS);
if (low_x < 0)
{
low_x = 0;
}
else if (low_x >= gaugeMapArraySize)
{
low_x = gaugeMapArraySize - 1;
}
if (high_x < 0)
{
high_x = 0;
}
else if (high_x >= gaugeMapArraySize)
{
high_x = gaugeMapArraySize - 1;
}
Test_Tell("Search x=(" << low_x << "..." << high_x << ")\n");
Test_Tell("Search z=(" << z << "..." << high_z << ")\n");
//-------------------------------------------------------
// Search the (limited) grid for items within the bounds
//-------------------------------------------------------
for( ; z<high_z; ++z)
{
for(x=low_x; x<high_x; ++x)
{
Test_Tell("Searching [" << x << "][" << z << "]\n");
count += grid[x][z].CopyEntitiesWithinBounds(
destination,
min_x,
min_y,
min_z,
max_x,
max_y,
max_z,
derivation_type
);
}
}
Test_Tell("Search done, total found = " << count << " items.\n");
Check_Fpu();
return count;
}
//============================================================================
// GetBounds
//============================================================================
void
GaugeEntityArray::GetBounds(
Scalar *min_x,
Scalar *min_y,
Scalar *min_z,
Scalar *max_x,
Scalar *max_y,
Scalar *max_z
)
{
*min_x = minimumX;
*min_y = minimumY;
*min_z = minimumZ;
*max_x = maximumX;
*max_y = maximumY;
*max_z = maximumZ;
Check_Fpu();
}
//============================================================================
// ArrayOffset - generate offset into array based on position value
//============================================================================
int
GaugeEntityArray::ArrayOffset(Scalar n)
{
int q;
q = (int)(gaugeMapArraySize*(n/HALF_EXTENT)+.5)+(gaugeMapArraySize>>1);
if (q < 0)
{
q = 0;
}
if (q >= gaugeMapArraySize)
{
q = (gaugeMapArraySize-1);
}
Check_Fpu();
return q;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+440 -44
View File
@@ -1,44 +1,440 @@
//===========================================================================//
// File: network.cpp //
// Project: MUNGA Brick: Network //
// Contents: Implementation details for network clients //
//---------------------------------------------------------------------------//
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc. //
// All Rights reserved worldwide //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
//===========================================================================//
#include <munga.hpp>
#pragma hdrstop
#if !defined(NETWORK_HPP)
# include <network.hpp>
#endif
//
//#############################################################################
//#############################################################################
//
Derivation
NetworkClient::ClassDerivations(
Receiver::ClassDerivations,
"NetworkClient"
);
NetworkClient::SharedData
NetworkClient::DefaultData(
NetworkClient::ClassDerivations,
Receiver::MessageHandlers
);
Derivation
NetworkManager::ClassDerivations(
NetworkClient::ClassDerivations,
"NetworkManager"
);
NetworkManager::SharedData
NetworkManager::DefaultData(
NetworkManager::ClassDerivations,
Receiver::MessageHandlers
);
# if !defined(MUNGA_HPP)
# include <munga.hpp>
# endif
#pragma hdrstop
# if !defined(HOSTMGR_HPP)
# include <hostmgr.hpp>
# endif
# if !defined(INTEREST_HPP)
# include <interest.hpp>
# endif
# if !defined(ICOM_HPP)
# include <icom.hpp>
# endif
# if !defined(APP_HPP)
# include <app.hpp>
# endif
# if !defined(NOTATION_HPP)
# include <notation.hpp>
# endif
# if !defined(NTTMGR_HPP)
# include <nttmgr.hpp>
# endif
#if defined(TRACE_ROUTE_PACKET)
static BitTrace Route_Packet("Route Packet");
# define SET_ROUTE_PACKET() Route_Packet.Set()
# define CLEAR_ROUTE_PACKET() Route_Packet.Clear()
#else
# define SET_ROUTE_PACKET()
# define CLEAR_ROUTE_PACKET()
#endif
const NetworkAddress NullNetworkAddress = 0x00000000;// 0.0.0.0 (in TCP land);
//#############################################################################
// Shared Data Support
//
NetworkClient::SharedData
NetworkClient::DefaultData(
NetworkClient::ClassDerivations,
NetworkClient::MessageHandlers
);
//
//#############################################################################
// Code for the network client class
//#############################################################################
//
Derivation
NetworkClient::ClassDerivations(Receiver::ClassDerivations, "NetworkClient");
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Constructor for the NetworkClient
//
NetworkClient::NetworkClient(
ClassID class_ID,
SharedData &virtual_data,
ClientID client_ID
):
Receiver(class_ID, virtual_data)
{
clientID = client_ID;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Destructor for the NetworkClient
//
NetworkClient::~NetworkClient()
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Destructor for the NetworkClient
//
Logical
NetworkClient::TestInstance() const
{
return IsDerivedFrom(ClassDerivations);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Receive packet for the NetworkClient
//
void
NetworkClient::ReceiveNetworkPacket(
NetworkPacket*,
Receiver::Message *packet_message
)
{
Dispatch(packet_message);
}
//
//#############################################################################
// Code for the network manager class
//#############################################################################
const Receiver::HandlerEntry
NetworkManager::MessageHandlerEntries[]=
{
MESSAGE_ENTRY(NetworkManager,ReceiveEggFile)
};
NetworkManager::MessageHandlerSet
NetworkManager::MessageHandlers(ELEMENTS(NetworkManager::MessageHandlerEntries), NetworkManager::MessageHandlerEntries, NetworkClient::MessageHandlers);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Shared Data Support
//
NetworkManager::SharedData
NetworkManager::DefaultData(
NetworkManager::ClassDerivations,
NetworkManager::MessageHandlers
);
Derivation
NetworkManager::ClassDerivations(NetworkClient::ClassDerivations, "NetworkManager");
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Constructor for the NetworkManager
//
NetworkManager::NetworkManager(SharedData &shared_data):
NetworkClient(NetworkManagerClassID, shared_data, NetworkManagerClientID)
{
// basic init goes here
gameID = 0;
eggTempBuffer = NULL;
networkEggNotationFile = NULL;
eggTempNext = 0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Creates a host for us. Any derived class must deal with reading the
// notation file to get the network nodes to connect to. This start is
// designed for STAND-ALONE MODE ONLY and should not be inherited for use by
//
void
NetworkManager::StartConnecting(Mission *)
{
Check(this);
//
//---------------------------------------------------------
// Make the local host, and get the application to adopt it
//---------------------------------------------------------
//
Host *local_host = new Host(1, GameMachineHostType, 1);
Register_Object(local_host);
Check(application);
Check(application->GetHostManager());
application->GetHostManager()->AdoptLocalHost(local_host);
//
//--------------------------------------------------------------------
// Now, since this host creator is for stand-alone mode, send the load
// mission message to the application
//--------------------------------------------------------------------
//
Check(application);
Application::Message
load_message(
Application::LoadMissionMessageID,
sizeof(Application::Message)
);
application->Post(DefaultEventPriority, application, &load_message);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// NetworkManager::EndMission This routine is called when a mission ends to
// allow the network management system to do stuff (like disconnecting network
// connections between pods and so on)
//
Logical
NetworkManager::Shutdown()
{
//
// If there is a notation file floating about, kill it!
//
if (networkEggNotationFile)
{
Unregister_Object(networkEggNotationFile);
delete networkEggNotationFile;
}
//
// Deregister local host
//
Host *local_host;
local_host = application->GetHostManager()->OrphanLocalHost();
Unregister_Object(local_host);
delete local_host;
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Destructor for the NetworkManager
//
NetworkManager::~NetworkManager()
{
// shutdown net goes here
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// NetworkManager::ReceiveEggFileMessageHandler
//
void
NetworkManager::ReceiveEggFileMessageHandler(
ReceiveEggFileMessage* EggMessage
)
{
//
// An egg sequence number of -1 means that the egg is posted locally, and
// should just call create mission
//
if (EggMessage->sequenceNumber == -1)
{
application->CreateMission(networkEggNotationFile);
return;
}
if (EggMessage->sequenceNumber == 0)
{
//
// Make a buffer
//
eggTempBuffer = new char[EggMessage->notationFileLength];
Register_Pointer(eggTempBuffer);
eggTempNext = 0;
}
//
// Write the egg data into the buffer
//
memcpy(
(eggTempBuffer+eggTempNext),
EggMessage->notationData,
EggMessage->thisMessageLength
);
eggTempNext += EggMessage->thisMessageLength;
//
// If we don't have all the data, return and wait for more
//
if(eggTempNext < EggMessage->notationFileLength)
{
return;
}
//
// We've got all the data, make the notation file
//
networkEggNotationFile = new NotationFile();
Register_Object(networkEggNotationFile);
networkEggNotationFile->ReadText(eggTempBuffer, eggTempNext);
networkEggNotationFile->WriteFile("last.egg");
//
// Now turn the notation file into a mission
//
application->CreateMission(networkEggNotationFile);
//
// Get rid of the ram buffer now that we're done with it
//
Unregister_Pointer(eggTempBuffer);
delete eggTempBuffer;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// NetworkManager::Send Handles sending a message to a specific network address
// which can NOT be us. Default behavior is to do nothing, as no network is
// hooked up if we get here
//
void
NetworkManager::Send(
Message *,
ClientID,
HostID
)
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// NetworkManager::Broadcast Handles broadcasting a message to everyone,
// including ourselves. !!!! Reliable broadcasting is currently used,
// implimented by sending a point-to-point message to every destination.
//
void
NetworkManager::Broadcast(
Message *message,
ClientID client_id
)
{
//
// Send this message back to ourselves
//
NetworkClient *client = GetNetworkClientPointer(client_id);
Check(client);
client->ReceiveNetworkPacket(NULL, message);
//
// Broadcast the message to everyone else on the network
//
ExclusiveBroadcast(message,client_id);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// NetworkManager::ExclusiveBroadcast Broadcasts a message to everyone on the
// network execpt us. Default behavior sends it to nobody, as there is really
// no network
//
void
NetworkManager::ExclusiveBroadcast(
Message *,
ClientID
)
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// NetworkManager::GetNetworkClientPointer Determine who the client of a
// message is and return a pointer to them.
//
NetworkClient*
NetworkManager::GetNetworkClientPointer(ClientID client_id)
{
switch (client_id)
{
case NetworkClient::NetworkManagerClientID:
return this;
case NetworkClient::EntityManagerClientID:
Check(application);
return application->GetEntityManager();
case NetworkClient::HostManagerClientID:
Check(application);
return application->GetHostManager();
case NetworkClient::InterestManagerClientID:
Check(application);
return application->GetInterestManager();
case NetworkClient::IcomManagerClientID:
Check(application);
return application->GetIntercomManager();
case NetworkClient::ApplicationClientID:
Check(application);
return application;
default:
DEBUG_STREAM << "------UNKNOWN NETWORK CLIENT ID " << client_id << endl << flush;
Fail("Unknown Client ID");
break;
}
return NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// NetworkManager::RoutePacket
//
Logical
NetworkManager::RoutePacket()
{
Check(this);
Byte
message_buffer[NETWORKMANAGER_BUFFER_SIZE];
NetworkPacket
*p;
//
// Return if check buffers doesn't have a packet for us
//
if (!CheckBuffers((NetworkPacket*)message_buffer))
{
return False;
}
//
// Process and route the packet properly
//
p = (NetworkPacket*)message_buffer;
if (p->gameID == gameID)
{
// cout<<"++++++++client "<<p->clientID<<" gameID "<<p->gameID<<" fromHost "<<p->fromHost<<"\n";
NetworkClient *client = GetNetworkClientPointer(p->clientID);
Check(client);
SET_ROUTE_PACKET();
client->ReceiveNetworkPacket(p, &p->messageData);
CLEAR_ROUTE_PACKET();
}
else
{
DEBUG_STREAM << "+++++++++ client " << p->clientID << " gameID " << p->gameID << " fromHost " << p->fromHost << endl << flush;
Fail("######### NOT A PACKET FOR THIS GAME!");
}
RemovePacket(p);
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// NetworkManager::ExecuteBackground Allows the network to perform tasks in
// the applications background. The method should return True if the manager
// is busy, False otherwise. For example, if the input and output buffers of
// the network driver are not empty then return True, otherwise return False.
//
Logical
NetworkManager::ExecuteBackground()
{
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// NetworkManager::CheckBuffers Checks to see if there is a message for us
// buffered up in the network interface card and returns a pointer to it.
//
Logical
NetworkManager::CheckBuffers(NetworkPacket*)
{
Fail("NetworkManager::CheckBuffers - should never reach here!");
return False;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// NetworkManager::RemovePacket If the network implimentation requires us to
// free up a packet buffer, this routine would do it.
//
void
NetworkManager::RemovePacket(NetworkPacket*)
{
Fail("NetworkManager::RemovePacket - should never reach here!");
}
File diff suppressed because it is too large Load Diff
+176
View File
@@ -0,0 +1,176 @@
# if !defined(MUNGA_HPP)
# include <munga.hpp>
# endif
#pragma hdrstop
# if !defined(RAY_HPP)
# include <ray.hpp>
# endif
# if !defined(PLANE_HPP)
# include <plane.hpp>
# endif
# if !defined(SPHERE_HPP)
# include <sphere.hpp>
# endif
//
//#############################################################################
//#############################################################################
//
void Ray::Project(Scalar length, Point3D *result)
{
Check(this);
Check(result);
Vector3D temp;
temp.Multiply(direction,length);
result->Add(origin,temp);
}
//
//#############################################################################
//#############################################################################
//
Scalar Ray::LengthToClosestPointTo(const Point3D &point)
{
Check(this);
Check(&point);
Vector3D temp;
temp.Subtract(point,origin);
return temp*direction;
}
//
//#############################################################################
//#############################################################################
//
Scalar Ray::DistanceTo(const Plane &plane, Scalar *product) const
{
Scalar t;
//
//------------------------------------------------------------------
// Compute the dot product of the ray and plane normal, and find the
// distance from the origin of the ray to the plane
//------------------------------------------------------------------
//
*product = plane.normal * direction;
t = plane.DistanceTo(origin);
//
//----------------------------------------------------------------------
// If the ray is not parallel to the plane, determine how far to proceed
// along the ray until we hit the plane
//----------------------------------------------------------------------
//
if (!Small_Enough(*product))
t /= -*product;
return t;
}
//
//#############################################################################
//#############################################################################
//
Scalar Ray::DistanceTo(const Sphere &sphere, Scalar *penetration) const
{
Scalar b, c;
Vector3D temp;
//
//-------------------------------------------------------------------------
// Set up to solve a quadratic equation for the intersection of the ray and
// sphere. The solution is based on finding the closest point on the line
// to the sphere, and then calculating the interval between the entry and
// exit points of the ray
//-------------------------------------------------------------------------
//
temp.Subtract(origin,sphere.center);
b = 2.0f * (direction * temp);
c = temp.LengthSquared() - sphere.radius*sphere.radius;
//
//--------------------------------------------------------------------------
// Compute the squared interval to use for the solution. If it is negative,
// then the ray misses the sphere
//--------------------------------------------------------------------------
//
*penetration = b*b - 4.0f*c;
if (*penetration<SMALL)
return 0.0f;
else
{
//-------------------------------------------------------------------------
// Otherwise, find the linear distance along the line of the entry point by
// subtracting half the interval between entry and exit points from the
// distance to the closest point on the sphere
//-------------------------------------------------------------------------
*penetration = Sqrt(*penetration);
return -0.5f*(b+*penetration);
}
}
//
//#############################################################################
//#############################################################################
//
Logical Ray::TestInstance() const
{
return True;
}
//
//#############################################################################
//#############################################################################
//
Scalar Find_Closest_Approach(const Point3D& origin1, const Vector3D& velocity1, Point3D *result1, const Point3D& origin2, const Vector3D& velocity2, Point3D *result2, Scalar *time, Logical *constant)
{
Vector3D a,b;
a.Subtract(origin1, origin2);
b.Subtract(velocity1, velocity2);
//
//--------------------------------------------------------------------
// If the velocities are identical, any point will do for the test, so
// simply return the difference between the starting points
//--------------------------------------------------------------------
//
Scalar d = b.LengthSquared();
if (Small_Enough(d))
{
*constant = True;
d = a.Length();
Check_Fpu();
return d;
}
//
//-------------------------------------------------------------------------
// The velocities are not parallel, so figure out when the closest approach
// is via the derivative
//-------------------------------------------------------------------------
//
*constant = False;
*time = (a * b) / -d;
Check_Fpu();
//
//------------------------------------------------------
// Now, plot the resultant points of both line equations
//------------------------------------------------------
//
Vector3D closest;
closest.AddScaled(a, b, *time);
result1->AddScaled(origin1, velocity1, *time);
result2->AddScaled(origin2, velocity2, *time);
d = closest.Length();
Check_Fpu();
return d;
}
#if defined(TEST_CLASS)
# include "ray.tcp"
#endif
+916
View File
@@ -0,0 +1,916 @@
# if !defined(MUNGA_HPP)
# include <munga.hpp>
# endif
#pragma hdrstop
# if !defined(RESOURCE_HPP)
# include <resource.hpp>
# endif
# if !defined(RESVER_HPP)
# include <resver.hpp>
# endif
ResourceDescription::ResourceDescription(
ResourceFile *file,
const char* name,
ResourceDescription::ResourceType type,
int priority,
LWord flags,
const void* address,
size_t size,
ResourceDescription::ResourceID index
)
{
Check(this);
Check_Pointer(name);
resourceFile = file;
resourceID = index;
resourceType = type;
Str_Copy(resourceName, name, sizeof(resourceName));
for (int i = strlen(resourceName) + 1; i<sizeof(resourceName); ++i)
{
resourceName[i] = '\0';
}
downloadPriority = priority;
resourceFlags = flags;
offsetInFile = 0;
resourceSize = size;
resourceAddress = NULL;
lockCount = 0;
if (address)
{
Check_Pointer(address);
resourceAddress = new char[resourceSize];
Register_Pointer(resourceAddress);
Mem_Copy(resourceAddress, address, resourceSize, resourceSize);
SetLoaded();
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ResourceDescription::~ResourceDescription()
{
Check(this);
// Verify(!IsLocked());
if (resourceAddress)
{
Unregister_Pointer(resourceAddress);
delete[] resourceAddress;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ResourceDescription::ReleaseUnlockedResource()
{
Check(this);
if (!IsLocked())
{
if (IsLoaded())
{
SetNotLoaded();
Verify(resourceAddress);
Unregister_Pointer(resourceAddress);
delete[] resourceAddress;
resourceAddress = NULL;
}
Verify(!resourceAddress);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ResourceDescription::LoadResource()
{
Check(this);
if (!IsLoaded())
{
Verify(!resourceAddress);
Check(resourceFile);
resourceFile->LoadResource(this);
Verify(resourceAddress);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
ResourceDescription::TestInstance() const
{
return True;
}
//#############################################################################
//########################## ResourceFile ###############################
//#############################################################################
//#############################################################################
// ResourceFile CONSTRUCTORS & DESTRUCTORS
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ResourceFile::ResourceFile():
labOnly(0),
resourceArray(NULL),
resourceArraySize(0),
maxResourceID(ResourceDescription::NullResourceID),
lastPreallocatedResourceID(ResourceDescription::NullResourceID)
{
versionArray[0] = RESOURCE_FORMAT_VERSION;
versionArray[1] = 0;
versionArray[2] = 0;
versionArray[3] = 0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ResourceFile::~ResourceFile()
{
if (resourceArray)
{
for (int i=maxResourceID; i>=0; i--)
{
if (resourceArray[i])
{
Unregister_Object(resourceArray[i]);
delete resourceArray[i];
}
}
Unregister_Pointer(resourceArray);
delete[] resourceArray;
}
versionArray[0] = RESOURCE_FORMAT_VERSION;
versionArray[1] = 0;
versionArray[2] = 0;
versionArray[3] = 0;
labOnly = 0;
resourceArraySize = 0;
maxResourceID = ResourceDescription::NullResourceID;
resourceArray = NULL;
}
//##############################################################################
// ResourceFile METHODS
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ResourceDescription*
ResourceFile::AddResource(
const char* name,
ResourceDescription::ResourceType type,
int priority,
LWord load_flag,
const void* address,
size_t size,
ResourceDescription::ResourceID index
)
{
Check(this);
Check_Pointer(name);
int i;
//
//-------------------------------------------------------------------------
// If we asked for the next available ID number, find out what it should be
//-------------------------------------------------------------------------
//
if (index == ResourceDescription::NullResourceID)
{
index = lastPreallocatedResourceID + 1;
if (resourceArray)
{
Check_Pointer(resourceArray);
for (; index<=resourceArraySize; ++index)
{
if (!resourceArray[index])
{
break;
}
}
}
}
//
//-------------------------------------------------------------
// Check to see if the resource index table needs to be created
//-------------------------------------------------------------
//
if (!resourceArray)
{
resourceArraySize = index + IndexBlockSize;
resourceArray = new ResourceDescription* [resourceArraySize];
Register_Pointer(resourceArray);
for (i=0; i<resourceArraySize; ++i)
{
resourceArray[i] = NULL;
}
}
//
//-----------------------------------------------------------
// Otherwise, check to see if we have to grow the index table
//-----------------------------------------------------------
//
if (index >= resourceArraySize)
{
//
//----------------------------------------
// Allocate a new table for the main index
//----------------------------------------
//
ResourceDescription **new_index =
new ResourceDescription* [index + IndexBlockSize];
Register_Pointer(new_index);
//
//------------------------------------
// Copy the old table into the new one
//------------------------------------
//
Check_Pointer(resourceArray);
for (i=0; i<resourceArraySize; ++i)
{
new_index[i] = resourceArray[i];
}
//
//---------------------
// Delete the old table
//---------------------
//
Unregister_Pointer(resourceArray);
delete[] resourceArray;
resourceArray = new_index;
resourceArraySize = index + IndexBlockSize;
//
//----------------------------------
// NULL the new entries in the table
//----------------------------------
//
while (i<resourceArraySize)
{
resourceArray[i++] = NULL;
}
}
//
//-----------------------------------------------
// Add the new resource in at the specified index
//-----------------------------------------------
//
Check_Pointer(resourceArray);
Verify(!resourceArray[index]);
if (index > maxResourceID)
{
maxResourceID = index;
}
resourceArray[index] =
new ResourceDescription(
this,
name,
type,
priority,
load_flag,
address,
size,
index
);
//
//----------------------------------------------------------------------
// The caller of this function is responsible for registering the memory
//----------------------------------------------------------------------
//
Register_Object(resourceArray[index]);
return resourceArray[index];
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ResourceDescription*
ResourceFile::AddResourceList(
const char* name,
ResourceDescription::ResourceType type,
int priority,
LWord load_flag,
const ResourceDescription::ResourceID* address,
int count,
ResourceDescription::ResourceID index
)
{
Check(this);
Check_Pointer(name);
Check_Pointer(address);
//
//--------------------------------------------------------
// prefix the directory table with the count of references
//--------------------------------------------------------
//
ResourceDescription::ResourceID *table =
new ResourceDescription::ResourceID[count+1];
Register_Pointer(table);
for (int i=0; i<count; ++i)
{
table[i+1] = address[i];
}
*table = count;
//
//-------------------------------------------------
// Go ahead and add the directory to the main index
//-------------------------------------------------
//
ResourceDescription *directory =
AddResource(
name,
type,
priority,
load_flag,
table,
(count+1) * sizeof(ResourceDescription::ResourceID),
index
);
Unregister_Pointer(table);
delete[] table;
return directory;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ResourceDescription*
ResourceFile::AddResourceMemoryStream(
const char* name,
ResourceDescription::ResourceType type,
int priority,
LWord load_flag,
MemoryStream* memory_stream,
ResourceDescription::ResourceID index
)
{
Check(this);
Check(memory_stream);
size_t size = memory_stream->GetBytesUsed();
memory_stream->Rewind();
return
AddResource(
name,
type,
priority,
load_flag,
memory_stream->GetPointer(),
size,
index
);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ResourceFile::DeleteResource(ResourceDescription *resource)
{
Check(this);
Check(resource);
Check_Pointer(resourceArray);
Verify(!resource->IsLocked());
//
//------------------------------------------------------------------------
// Delete pointer from resoureArray if it was there
//------------------------------------------------------------------------
//
if (resource->resourceID != ResourceDescription::NullResourceID )
{
resourceArray[resource->resourceID] = NULL;
//
//------------------------------------------------------------------------
// Find new maxResourceID
//------------------------------------------------------------------------
//
if (resource->resourceID == maxResourceID )
{
ResourceDescription::ResourceID i;
for (i = maxResourceID; i>=0; i--)
{
if(resourceArray[i] != NULL)
{
Check(resourceArray[i]);
break;
}
}
maxResourceID = i;
}
}
//
//------------------------------------------------------------------------
// The caller of this function is responsible for unregistering the memory
//------------------------------------------------------------------------
//
delete resource;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ResourceDescription*
ResourceFile::FindResourceDescription(ResourceDescription::ResourceID index)
{
Check(this);
if (index<0 || index>maxResourceID || !resourceArray)
{
return NULL;
}
Check_Pointer(resourceArray);
ResourceDescription *res = resourceArray[index];
return res;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ResourceDescription*
ResourceFile::FindResourceDescription(
const char* name,
ResourceDescription::ResourceType type,
ResourceDescription::ResourceID after
)
{
Check(this);
ResourceDescription *desc;
ResourceDescription::ResourceID i;
for (i=after+1; i<=maxResourceID; ++i)
{
desc = FindResourceDescription(i);
if (desc)
{
Check(desc);
if (
type == desc->resourceType &&
(!name || !strcmp(name, desc->resourceName))
)
{
break;
}
}
}
if (i > maxResourceID)
{
desc = NULL;
}
return desc;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ResourceDescription*
ResourceFile::SearchList(
ResourceDescription::ResourceID list_id,
ResourceDescription::ResourceType type
)
{
ResourceDescription *list_res = FindResourceDescription(list_id);
if (list_res)
{
Check(list_res);
list_res->Lock();
Verify(
list_res->resourceType <= ResourceDescription::MaxListResourceType
);
ResourceDescription::ResourceID *list =
(ResourceDescription::ResourceID*)list_res->resourceAddress;
Check_Pointer(list);
for (int i=1; i<=*list; ++i)
{
ResourceDescription *res = FindResourceDescription(list[i]);
Check(res);
if (res->resourceType == type)
{
list_res->Unlock();
return res;
}
}
list_res->Unlock();
}
return NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ResourceDescription*
ResourceFile::SearchList(
ResourceDescription::ResourceID list_id,
const char* name
)
{
Check_Pointer(name);
ResourceDescription *list_res = FindResourceDescription(list_id);
if (list_res)
{
Check(list_res);
list_res->Lock();
Verify(
list_res->resourceType <= ResourceDescription::MaxListResourceType
);
ResourceDescription::ResourceID *list =
(ResourceDescription::ResourceID*)list_res->resourceAddress;
Check_Pointer(list);
for (int i=1; i<=*list; ++i)
{
ResourceDescription *res = FindResourceDescription(list[i]);
Check(res);
if (!strcmp(name, res->resourceName))
{
list_res->Unlock();
return res;
}
}
list_res->Unlock();
}
return NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
ResourceFile::ReleaseUnlockedResources()
{
for (ResourceDescription::ResourceID i = maxResourceID; i>=0; i--)
{
if(resourceArray[i] != NULL)
{
ResourceDescription *res = resourceArray[i];
Check(res);
res->ReleaseUnlockedResource();
}
}
}
//#############################################################################
// ResourceFile Test Support
//
Logical
ResourceFile::TestInstance() const
{
return True;
}
//##############################################################################
//########################## StreamableResourceFile ######################
//##############################################################################
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
StreamableResourceFile::StreamableResourceFile()
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
StreamableResourceFile::StreamableResourceFile(const char* file_name)
{
Open(file_name);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
StreamableResourceFile::StreamableResourceFile(const char* file_name, Byte version_array[3], int match_level)
{
Open(file_name);
int i;
for (i=0; i<match_level; ++i)
if (version_array[i] != versionArray[i+1])
break;
if (i < match_level)
{
DEBUG_STREAM << "\n\nError - Resource file " << file_name << " v" << (int)versionArray[0] << '.' << (int)versionArray[1] << '.' << (int)versionArray[2] << '.' << (int)versionArray[3] << " is obsolete!\n\n" << flush;
Fail("Exiting");
}
#if 0
if (release_only && labOnly)
{
DEBUG_STREAM << "\n\n\nERROR!\n\n"
"This resource file was not properly released!\n\n";
Fail("Exiting");
}
#endif
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
StreamableResourceFile::~StreamableResourceFile()
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int
StreamableResourceFile::Open(const char *file_name)
{
Check(this);
Str_Copy(resourceFilename, file_name, sizeof(resourceFilename));
diskFile.Open(resourceFilename);
if (!diskFile.IsFileOpened())
{
return False;
}
//
//-----------------------
// Read in resource count
//-----------------------
//
maxResourceID = 0;
diskFile.ReadBytes(&versionArray, sizeof(versionArray));
if (versionArray[0] != RESOURCE_FORMAT_VERSION)
{
DEBUG_STREAM << "\n\nError - Resource file " << file_name << " v"
<< (int)versionArray[0] << '.' << (int)versionArray[1] << '.'
<< (int)versionArray[2] << '.' << (int)versionArray[3]
<< " is obsolete!\n\n" << flush;
Fail("Exiting");
}
diskFile >> labOnly >> maxResourceID;
//
//------------------------------------------------------------------
// Read in main index table first, and make room for expansion later
//------------------------------------------------------------------
//
size_t *offset_table = new size_t[maxResourceID];
Register_Pointer(offset_table);
diskFile.ReadBytes(offset_table, maxResourceID*sizeof(size_t));
resourceArraySize = maxResourceID + IndexBlockSize;
resourceArray = new ResourceDescription*[resourceArraySize];
Register_Pointer(resourceArray);
int i;
for (i=0; i<resourceArraySize; ++i)
{
resourceArray[i] = NULL;
}
--maxResourceID;
//
//---------------------------------------------------------------------
// Step through the index table, reading each description as we find it
//---------------------------------------------------------------------
//
for (i=0; i<=maxResourceID; ++i)
{
//
//--------------------------------------------
// Make sure we skip empty resources correctly
//--------------------------------------------
//
if (!offset_table[i])
{
resourceArray[i] = NULL;
continue;
}
//
//------------------------
// Read in the description
//------------------------
//
ResourcePhysicalFormat buffer;
diskFile.SetPointer(offset_table[i]);
diskFile >> buffer;
//
//-------------------------------------------------
// If the preload flag is set, read in the resource
//-------------------------------------------------
//
char *data = NULL;
if (buffer.resourceFlags == ResourceDescription::Preload && buffer.resourceLength > 0)
{
data = new char[buffer.resourceLength];
Register_Pointer(data);
diskFile.SetPointer(buffer.resourceOffset);
diskFile.ReadBytes(data, buffer.resourceLength);
}
if (buffer.resourceType > ResourceDescription::MaxListResourceType || !data)
{
resourceArray[i] = AddResource(
buffer.resourceName,
buffer.resourceType,
buffer.downloadPriority,
buffer.resourceFlags,
data,
buffer.resourceLength,
buffer.resourceID
);
}
else
{
resourceArray[i] = AddResourceList(
buffer.resourceName,
buffer.resourceType,
buffer.downloadPriority,
buffer.resourceFlags,
(int*)data + 1,
*(int*)data,
buffer.resourceID
);
}
resourceArray[i]->offsetInFile = buffer.resourceOffset;
if (data)
{
resourceArray[i]->Lock();
Unregister_Pointer(data);
delete[] data;
}
}
Unregister_Pointer(offset_table);
delete[] offset_table;
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
StreamableResourceFile::Save()
{
Check(this);
if (!resourceArray)
{
return False;
}
//
//-----------------------------------------------------------------------
// Make sure to load any unloaded resources before closing the input file
//-----------------------------------------------------------------------
//
ResourceDescription *desc;
ResourceDescription::ResourceID i;
for (i=0; i<=maxResourceID; ++i)
{
desc = resourceArray[i];
if (desc)
{
Check(desc);
desc->LoadResource();
}
}
//
//-------------------------------------------
// Close the current file, and open a new one
//-------------------------------------------
//
if (diskFile.IsFileOpened())
{
diskFile.Close();
}
diskFile.Open(resourceFilename, True);
Verify(diskFile.IsFileOpened());
//
//-------------------------------------
// Write out resource count and version
//-------------------------------------
//
++maxResourceID;
diskFile.WriteBytes(&versionArray, sizeof(versionArray));
diskFile << labOnly << maxResourceID;
//
//--------------------------------------------------------------------------
// Write out main index table first. This is just filling up space, and the
// offsets will have to be written back into this section later
//--------------------------------------------------------------------------
//
size_t *offset_table = new size_t[maxResourceID];
Register_Pointer(offset_table);
diskFile.WriteBytes(offset_table, maxResourceID*sizeof(size_t));
//
//-------------------------------------------------------------------------
// Step through the index table, writing out each description as we find it
//-------------------------------------------------------------------------
//
for (i=0; i<maxResourceID; ++i)
{
//
//--------------------------------------------
// Make sure we skip empty resources correctly
//--------------------------------------------
//
desc = resourceArray[i];
if (!desc)
{
offset_table[i] = 0;
continue;
}
Check(desc);
//
//-------------------
// Write out the data
//-------------------
//
ResourcePhysicalFormat buffer;
buffer.resourceOffset = diskFile.GetIndex();
diskFile.WriteBytes(desc->resourceAddress, desc->resourceSize);
//
//--------------------------
// Write out the description
//--------------------------
//
offset_table[i] = diskFile.GetIndex();
buffer.resourceID = desc->resourceID;
buffer.resourceType = desc->resourceType;
//#if sizeof(buffer.resourceName) < sizeof(desc->resourceName)
//# error ResourceDescription::resourceName is too big!
//#endif
memcpy(
buffer.resourceName,
desc->resourceName,
sizeof(desc->resourceName)
);
buffer.resourceLength = desc->resourceSize;
buffer.downloadPriority = desc->downloadPriority;
buffer.resourceFlags =
desc->resourceFlags & ~ResourceDescription::LoadedFlag;
diskFile << buffer;
}
diskFile.SetPointer(
sizeof(maxResourceID) + sizeof(versionArray) + sizeof(labOnly)
);
diskFile.WriteBytes(offset_table, maxResourceID*sizeof(long));
Unregister_Pointer(offset_table);
delete(offset_table);
--maxResourceID;
diskFile.Close();
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
StreamableResourceFile::SaveAs(const char* file_name)
{
Str_Copy(resourceFilename, file_name, sizeof(resourceFilename));
return Save();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
StreamableResourceFile::LoadResource(ResourceDescription *res)
{
ResourceFile::LoadResource(res);
Verify(!res->resourceAddress);
res->resourceAddress = new char[res->resourceSize];
Register_Pointer(res->resourceAddress);
diskFile.SetPointer(res->offsetInFile);
diskFile.ReadBytes(res->resourceAddress, res->resourceSize);
}
//#############################################################################
// StreamableResourceFile Test Support
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
StreamableResourceFile::TestInstance() const
{
return True;
}
#if defined(TEST_CLASS)
#include "resource.tcp"
#endif
+243
View File
@@ -0,0 +1,243 @@
# if !defined(MUNGA_HPP)
# include <munga.hpp>
# endif
#pragma hdrstop
# if !defined(SCNROLE_HPP)
# include <scnrole.hpp>
# endif
# if !defined(APP_HPP)
# include <app.hpp>
# endif
# if !defined(NOTATION_HPP)
# include <notation.hpp>
# endif
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ScenarioRole::ScenarioRole(const CString &role_name)
{
damageReceivedModifier = 0.0f;
damageInflictedModifier = 0.0f;
damageBias = 0.0f;
friendlyFirePenalty = 0.0f;
killBonus = 0.0f;
roleName = role_name;
returnFromDeath = 0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ScenarioRole::ScenarioRole(const CString &role_name, const CString &model_file)
{
Check_Pointer(&role_name);
Check_Pointer(&model_file);
roleName = role_name;
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Truncate the Role:: from roleName
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ResourceFile
*res = application->GetResourceFile();
ResourceDescription
*player_res_des;
player_res_des = res->FindResourceDescription(
model_file,
ResourceDescription::GameModelResourceType
);
if (player_res_des)
{
player_res_des->Lock();
ModelResource
*player_data = (ModelResource *)player_res_des->
resourceAddress;
killBonus = player_data->killBonus;
returnFromDeath = player_data->returnFromDeath;
damageReceivedModifier = player_data->damageReceivedModifier;
damageInflictedModifier = player_data->damageInflictedModifier;
damageBias = player_data->damageBias;
friendlyFirePenalty = player_data->friendlyFirePenalty;
player_res_des->Unlock();
}
else
{
Tell(role_name);
Warn(" does not exists in resource! ");
damageReceivedModifier = 0.0f;
damageInflictedModifier = 0.0f;
damageBias = 0.0f;
friendlyFirePenalty = 0.0f;
killBonus = 0.0f;
returnFromDeath = 0;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar
ScenarioRole::CalcDamageReceivedScore(const Scalar &damage_received)
{
Check(this);
// ]
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Calculate modified score for the player receiving damage
// damageReceived * damageReceivedModifier
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Check(this);
Check_Fpu();
return -(damage_received * GetDamageReceivedModifier());
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ScenarioRole::~ScenarioRole()
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ResourceDescription::ResourceID
ScenarioRole::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_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);
}
//----------------------------------------
// Read in the data from notation file
//----------------------------------------
//
// Get PointValue assigned to this ScoreZone
//
if(
!model_file->GetEntry(
"gamedata",
"KillBonus",
&local_model->killBonus
)
)
{
cerr << model_name << "Missing KillBonus" << endl;
Dump_And_Die:
if (!model)
{
Unregister_Pointer(local_model);
delete local_model;
}
return -1;
}
if(
!model_file->GetEntry(
"gamedata",
"DamageReceivedModifier",
&local_model->damageReceivedModifier
)
)
{
cerr << model_name << "Missing DamageReceivedModifier" << endl;
goto Dump_And_Die;
}
if(
!model_file->GetEntry(
"gamedata",
"DamageInflictedModifier",
&local_model->damageInflictedModifier
)
)
{
cerr << model_name << "Missing DamageInflictedModifier" << endl;
goto Dump_And_Die;
}
if(
!model_file->GetEntry(
"gamedata",
"ReturnFromDeath",
&local_model->returnFromDeath
)
)
{
cerr << model_name << "Missing ReturnFromDeath" << endl;
goto Dump_And_Die;
}
if(
!model_file->GetEntry(
"gamedata",
"DamageBias",
&local_model->damageBias
)
)
{
cerr << model_name << "Missing DamageBias" << endl;
goto Dump_And_Die;
}
if(
!model_file->GetEntry(
"gamedata",
"FriendlyFirePenalty",
&local_model->friendlyFirePenalty
)
)
{
cerr << model_name << "Missing FriendlyFirePenalty" << endl;
goto Dump_And_Die;
}
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_Fpu();
Check(new_res);
return new_res->resourceID;
}
else
{
Check_Fpu();
return 0;
}
}
+45
View File
@@ -0,0 +1,45 @@
//===========================================================================//
// File: stubs.cpp //
// Project: MUNGA //
// Contents: Optimized-build heap and exit stubs //
//---------------------------------------------------------------------------//
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc. //
// All Rights reserved worldwide //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
//===========================================================================//
#include <munga.hpp>
#pragma hdrstop
#include <stdlib.h>
void
Exit(int exit_code)
{
exit(exit_code);
}
UserHeap::UserHeap(const char *, size_t)
{
}
UserHeap::~UserHeap()
{
}
void*
UserHeap::Allocate(size_t size)
{
return new char[size];
}
void
UserHeap::Release(void *where)
{
delete[] (char *)where;
}
void
UserHeap::ReleaseAll()
{
}
+204
View File
@@ -0,0 +1,204 @@
# if !defined(MUNGA_HPP)
# include <munga.hpp>
# endif
#pragma hdrstop
# if !defined(CONTROLS_HPP)
# include <controls.hpp>
# endif
# if !defined(GAUGREND_HPP)
# include <gaugrend.hpp>
# endif
#if defined(__BCPLUSPLUS__)
//
//#############################################################################
//#############################################################################
//
#if DEBUG_LEVEL>0
int _matherr(struct exception *a)
{
switch (a->type)
{
case DOMAIN:
DEBUG_STREAM << "Domain" << flush;
break;
case SING:
DEBUG_STREAM << "Singularity" << flush;
break;
case UNDERFLOW:
DEBUG_STREAM << "Underflow" << flush;
break;
case OVERFLOW:
DEBUG_STREAM << "Overflow" << flush;
break;
case TLOSS:
DEBUG_STREAM << "Loss of Precision" << flush;
break;
}
DEBUG_STREAM << " error occurred in " << a->name << endl << flush;
DEBUG_STREAM << "arg1 = " << a->arg1 << endl << flush;
DEBUG_STREAM << "arg2 = " << a->arg2 << endl << flush;
DEBUG_STREAM << "retval = " << a->retval << endl << flush << flush;
return 0;
}
#else
int _matherr(struct exception *)
{
_fpreset();
return 1;
}
#endif
extern "C" void _pure_error_()
{
Fail("Pure virtual function called");
}
#endif
//
//#############################################################################
// Fpu_Ok
//
// returns True if fpu has no errors, False if errors found
//#############################################################################
//
int
Fpu_Ok()
{
unsigned int s =
_status87() &
(
SW_INVALID |
// SW_DENORMAL |
SW_ZERODIVIDE |
SW_OVERFLOW
// SW_UNDERFLOW |
//VERIFY: SW_STACKFAULT
);
if (s)
{
DEBUG_STREAM << "ERROR: FPU status=" << flush;
if (s & SW_INVALID)
{
DEBUG_STREAM << "invalid " << flush;
}
if (s & SW_DENORMAL)
{
DEBUG_STREAM << "denormalized " << flush;
}
if (s & SW_ZERODIVIDE)
{
DEBUG_STREAM << "zeroDivide " << flush;
}
if (s & SW_OVERFLOW)
{
DEBUG_STREAM << "overflow " << flush;
}
if (s & SW_UNDERFLOW)
{
DEBUG_STREAM << "underflow " << flush;
}
/*if (s & SW_STACKFAULT)
{
DEBUG_STREAM << "stackFault" << flush;
}*/
DEBUG_STREAM << "\n" << flush << flush;
return False;
}
else
{
return True;
}
}
//
//#############################################################################
//#############################################################################
//
static Logical AlreadyFailed=False;
void Verify_Failed(char *Message, char *File, int Line)
{
if (!AlreadyFailed)
{
AlreadyFailed = True;
DEBUG_STREAM << File << "(" << Line << "): Failed " << Message << "\n" << flush;
#if defined(USE_PROFILE_ANALYSIS)
Analysis_Named_Status();
#endif
DEBUG_STREAM << "Failing to debugger\n" << flush << flush;
SystemClock::timer.Shutdown();
ControlsManager::Shutdown();
GaugeRenderer::EmergencyShutdown();
*(int*)(0xFFFFFFFF) = 0;
}
}
//
//#############################################################################
//#############################################################################
//
void
Fail_To_Debugger(char *Message, char *File, int Line)
{
if (!AlreadyFailed)
{
AlreadyFailed = True;
DEBUG_STREAM << File << "(" << Line << "): " << Message << "\n" << flush;
#if defined(USE_PROFILE_ANALYSIS)
Analysis_Named_Status();
#endif
DEBUG_STREAM << "Failing to debugger\n" << flush << flush;
SystemClock::timer.Shutdown();
ControlsManager::Shutdown();
GaugeRenderer::EmergencyShutdown();
*(int*)(0xFFFFFFFF) = 0;
}
}
//
//#############################################################################
//#############################################################################
//
#if defined(USE_SIGNATURE)
Signature::Signature()
{
#if DEBUG_LEVEL>0
mark = magic;
#endif
}
Signature::~Signature()
{
#if DEBUG_LEVEL>0
mark = noMagic;
#endif
}
int
Is_Signature_Bad(const volatile Signature *p)
{
#if DEBUG_LEVEL>0
if (p->mark == Signature::magic)
{
return Signature::ok;
}
else if (p->mark == Signature::noMagic)
{
return Signature::destroyed;
}
else
{
return Signature::corrupted;
}
#else
return False;
#endif
}
#endif
+876 -73
View File
@@ -1,73 +1,876 @@
//===========================================================================//
// File: l4app.cpp //
// Project: MUNGA Brick: L4Application //
// Contents: Implementation details for L4Application //
//---------------------------------------------------------------------------//
// Date Who Modification //
// -------- --- ---------------------------------------------------------- //
// //
//---------------------------------------------------------------------------//
// Copyright (C) 1994, Virtual World Entertainment, Inc. //
// All Rights reserved worldwide. //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
//===========================================================================//
#include <mungal4.hpp>
#pragma hdrstop
#if !defined(L4APP_HPP)
# include <l4app.hpp>
#endif
//
//#############################################################################
//#############################################################################
//
const Receiver::HandlerEntry
L4Application::MessageHandlerEntries[]=
{
MESSAGE_ENTRY(L4Application, LightsOut),
MESSAGE_ENTRY(L4Application, RunMission),
MESSAGE_ENTRY(L4Application, StopMission),
MESSAGE_ENTRY(L4Application, KeyCommand)
};
L4Application::MessageHandlerSet
L4Application::MessageHandlers(
ELEMENTS(L4Application::MessageHandlerEntries),
L4Application::MessageHandlerEntries,
Application::MessageHandlers
);
//
//#############################################################################
//#############################################################################
//
Derivation
L4Application::ClassDerivations(
Application::ClassDerivations,
"L4Application"
);
L4Application::SharedData
L4Application::DefaultData(
L4Application::ClassDerivations,
L4Application::MessageHandlers
);
//
//#############################################################################
//#############################################################################
//
Logical
L4Application::seeSolids = False;
CString
L4Application::eggNotationFileName;
unsigned long
L4Application::networkCommonFlatAddress = 0;
int
L4Application::missionReviewMode = 0;
CString
L4Application::rioPlaybackFileName;
CString
L4Application::rioRecordingFileName;
# if !defined(MUNGAL4_HPP)
# include <mungal4.hpp>
# endif
#pragma hdrstop
# if !defined(CAMSHIP_HPP)
# include <camship.hpp>
# endif
# if !defined(APPMSG_HPP)
# include <appmsg.hpp>
# endif
# if !defined(L4APP_HPP)
# include <l4app.hpp>
# endif
# if !defined(L4CTRL_HPP)
# include <l4ctrl.hpp>
# endif
# if !defined(L4ICOM_HPP)
# include <l4icom.hpp>
# endif
# if !defined(L4VIDEO_HPP)
# include <l4video.hpp>
# endif
# if !defined(L4AUDRND_HPP)
# include <l4audrnd.hpp>
# endif
# if !defined(L4GREND_HPP)
# include <l4grend.hpp>
# endif
# if !defined(L4NET_HPP)
# include <l4net.hpp>
# endif
# if !defined(L4MPPR_HPP)
# include <l4mppr.hpp>
# endif
# if !defined(PLAYER_HPP)
# include <player.hpp>
# endif
# if !defined(MISSION_HPP)
# include <mission.hpp>
# endif
L4Application*&
l4_application = (L4Application*&)application;
const Receiver::HandlerEntry
L4Application::MessageHandlerEntries[]=
{
MESSAGE_ENTRY(L4Application, RunMission),
MESSAGE_ENTRY(L4Application, StopMission),
MESSAGE_ENTRY(L4Application, LightsOut),
MESSAGE_ENTRY(L4Application, KeyCommand)
};
L4Application::MessageHandlerSet
L4Application::MessageHandlers(ELEMENTS(L4Application::MessageHandlerEntries), L4Application::MessageHandlerEntries, Application::MessageHandlers);
//#############################################################################
// Virtual Data support
//
Derivation
L4Application::ClassDerivations(Application::ClassDerivations, "L4Application");
L4Application::SharedData
L4Application::DefaultData(
L4Application::ClassDerivations,
L4Application::MessageHandlers
);
//##########################################################################
//################## L4Application Static Data #######################
//##########################################################################
Logical L4Application::seeSolids = False;
CString L4Application::eggNotationFileName;
unsigned long L4Application::networkCommonFlatAddress;
int L4Application::missionReviewMode = 0;
CString L4Application::rioPlaybackFileName;
CString L4Application::rioRecordingFileName;
//
//#############################################################################
// ParseCommandLine
//#############################################################################
//
Logical
L4Application::ParseToken(
int *arguement,
int argc,
char *argv[]
)
{
Check_Pointer(argv);
if (!stricmp(argv[*arguement], "-egg"))
{
if ((*arguement+1) < argc && argv[*arguement+1][0] != '-')
{
eggNotationFileName = argv[++(*arguement)];
}
else
{
DEBUG_STREAM << "\nEgg file not specified after -egg\n" << flush << flush;
return False;
}
}
else if (!stricmp(argv[*arguement], "-net"))
{
if ((*arguement+1) < argc && argv[*arguement+1][0] != '-')
{
networkCommonFlatAddress = atol(argv[++(*arguement)]);
}
else
{
DEBUG_STREAM << "\nAddress not specified after -net\n" << flush;
return False;
}
}
else if (!stricmp(argv[*arguement], "-r"))
{
if ((*arguement+1) < argc && argv[*arguement+1][0] != '-')
{
rioRecordingFileName = argv[++(*arguement)];
CString playback = GetRIOPlaybackFileName();
if (playback && strlen(playback))
{
DEBUG_STREAM << "\nPlayback already specified!\n" << flush;
return False;
}
}
else
{
DEBUG_STREAM << "\nRecording file not specified after -r\n" << flush;
return False;
}
}
else if (!stricmp(argv[*arguement], "-p"))
{
if ((*arguement+1) < argc && argv[*arguement+1][0] != '-')
{
rioPlaybackFileName = argv[++(*arguement)];
CString recording = GetRIORecordingFileName();
if (recording && strlen(recording))
{
DEBUG_STREAM << "\nRecording already specified!\n" << flush;
return False;
}
}
else
{
DEBUG_STREAM << "\nPlayback file not specified after -egg\n" << flush;
return False;
}
}
else if (!stricmp(argv[*arguement], "-solids"))
{
seeSolids = True;
}
else if (
!stricmp(argv[*arguement], "-h") || !stricmp(argv[*arguement], "-help")
)
{
DEBUG_STREAM << "\n" << argv[0] <<
" -egg <filename> -net <memory_address> -solids -h -help\n";
return False;
}
return True;
}
//
//#############################################################################
// ParseCommandLine
//#############################################################################
//
Logical
L4Application::ParseCommandLine(
int argc,
char *argv[],
TokenParser parser
)
{
Check_Pointer(argv);
//
// Process options
//
seeSolids = False;
eggNotationFileName = "";
networkCommonFlatAddress = NULL;
missionReviewMode = 0;
if (argc > 1)
{
for (int i = 1; i < argc; ++i)
{
if (!stricmp(argv[i], "-mr"))
{
missionReviewMode = 1;
} else if (!(*parser)(&i, argc, argv))
{
return False;
}
}
}
return True;
}
//
//#############################################################################
// TestInstance
//#############################################################################
//
Logical
L4Application::TestInstance() const
{
if (!IsDerivedFrom(ClassDerivations))
{
return False;
}
return True;
}
//
//#############################################################################
// L4Application
//#############################################################################
//
L4Application::L4Application(
ResourceFile *resource_file,
ApplicationID application_ID,
ClassID class_ID,
SharedData &shared_data
):
Application(resource_file, application_ID, class_ID, shared_data)
{
divisionParameters = getenv("DPLARG");
}
//
//#############################################################################
// Initialize
//#############################################################################
//
void
L4Application::Initialize()
{
Check(this);
InitializeTillConsole();
//
// Create the console host and socket
//
L4NetworkManager *net_mgr = GetNetworkManager();
net_mgr->CreateConsoleHost();
}
//
//#############################################################################
// Initialize
//#############################################################################
//
void
L4Application::InitializeTillConsole()
{
Check(this);
Application::Initialize();
}
//
//#############################################################################
// MakeModeManager
//#############################################################################
//
ModeManager*
L4Application::MakeModeManager()
{
return new ModeManager((ModeMask)ModeManager::ModeAlwaysActive); // Normally called at top level!!
}
//
//#############################################################################
// MakeNetworkManager
//#############################################################################
//
NetworkManager*
L4Application::MakeNetworkManager()
{
return new L4NetworkManager;
}
//
//#############################################################################
// MakeControlsManager
//#############################################################################
//
ControlsManager*
L4Application::MakeControlsManager()
{
LBE4ControlsManager *manager = new LBE4ControlsManager();
Check(manager);
manager->keyboardGroup[LBE4ControlsManager::KeyboardPC].Add(ModeManager::ModeAlwaysActive, this, KeyCommandMessageID, this);
return manager;
}
//
//#############################################################################
// MakeIntercomManager
//#############################################################################
//
IcomManager*
L4Application::MakeIntercomManager()
{
L4IcomManager
*manager = new L4IcomManager();
Check(manager);
return manager;
}
//
//#############################################################################
// MakeVideoRenderer
//#############################################################################
//
VideoRenderer*
L4Application::MakeVideoRenderer()
{
if (divisionParameters)
{
return
new DPLRenderer(
DefaultRendererRate,
MaxRendererComplexity,
DefaultRendererPriority,
VisualInterestType,
1
);
}
return NULL;
}
//
//#############################################################################
// MakeAudioRenderer
//#############################################################################
//
AudioRenderer*
L4Application::MakeAudioRenderer()
{
/* char *blaster1, *blaster2;
blaster1 = getenv(FRONT_CARD_ENV_VAR);
blaster2 = getenv(REAR_CARD_ENV_VAR);
if (blaster1 != NULL && blaster2 != NULL)
{
return new L4AudioRenderer(DefaultRendererRate, False);
}
return NULL;*/
return new L4AudioRenderer(DefaultRendererRate, False);
}
//
//#############################################################################
// MakeGaugeRenderer
//#############################################################################
//
GaugeRenderer*
L4Application::MakeGaugeRenderer()
{
char *mode_string = getenv("L4GAUGE");
if (mode_string != NULL)
{
return new L4GaugeRenderer;
}
return NULL;
}
//
//#############################################################################
// Terminate
//#############################################################################
//
void
L4Application::Terminate()
{
Check(this);
//
//--------------------------------------------------------------------------
// Turn off illumination
//--------------------------------------------------------------------------
//
PilotIllumination(False);
//
// Call inherited method
//
Application::Terminate();
}
//
//#############################################################################
// ~L4Application
//#############################################################################
//
L4Application::~L4Application()
{
}
//
//#############################################################################
// MakeAndLinkViewpointEntity
//#############################################################################
//
Entity*
L4Application::MakeAndLinkViewpointEntity(Entity::MakeMessage* message)
{
Check(this);
Check(message);
Application::MakeAndLinkViewpointEntity(message);
//
//--------------------------------------------------------------------------
// Turn on lights for pilot
// (turned off by RunMissionMessageHandler)
//--------------------------------------------------------------------------
//
PilotIllumination(True);
//
//--------------------------------------------------------------------------
// Return viewpoint entity
//--------------------------------------------------------------------------
//
return GetViewpointEntity();
}
//
//#############################################################################
// MakeViewpointEntity
//#############################################################################
//
Entity*
L4Application::MakeViewpointEntity(Entity::MakeMessage *message)
{
Entity *viewing_entity;
viewing_entity = NULL;
switch(message->classToCreate)
{
case CameraShipClassID:
viewing_entity = CameraShip::Make((CameraShip::MakeMessage*)message);
Check(viewing_entity);
CameraShip *viewing_camera = Cast_Object(CameraShip*, viewing_entity);
Check(viewing_camera);
//
// Create controls mapping object
//
CameraControlsMapper
*camera_mapper;
Verify(GetControlsManager() != NULL);
CameraControlsMapper::SubsystemResource control_subsystem_resource;
Str_Copy(
control_subsystem_resource.subsystemName,
"ControlsMapper",
sizeof(control_subsystem_resource.subsystemName)
);
control_subsystem_resource.classID = TrivialSubsystemClassID;
control_subsystem_resource.subsystemModelSize =
sizeof(control_subsystem_resource);
LBE4ControlsManager* controls = GetControlsManager();
Check(controls);
switch (controls->primaryControlType)
{
case LBE4ControlsManager::PrimaryThrustMaster:
Tell("L4Application::MakeViewpointEntity, using ThrustMaster\n");
camera_mapper =
new CameraThrustmasterMapper(
viewing_camera,
CameraShip::ControlsMapperSubsystem,
&control_subsystem_resource
);
Register_Object(camera_mapper);
viewing_camera->SetMappingSubsystem(camera_mapper);
break;
case LBE4ControlsManager::PrimaryRIO:
Tell("L4Application::MakeViewpointEntity, using RIO\n");
camera_mapper =
new CameraRIOMapper(
viewing_camera,
CameraShip::ControlsMapperSubsystem,
&control_subsystem_resource
);
Register_Object(camera_mapper);
viewing_camera->SetMappingSubsystem(camera_mapper);
break;
default:
Fail("L4Application::MakeViewpointEntity, *** NO MAPPER! ***\n");
break;
}
//
//-------------------------------------------
// Create gauges for this entity
//-------------------------------------------
//
if (GetGaugeRenderer() != NULL)
{
L4GaugeRenderer *gauge_renderer = GetGaugeRenderer();
Check(gauge_renderer);
gauge_renderer->ConfigureForModel(
"Init",
viewing_entity
);
}
break;
}
return viewing_entity;
}
//
//#############################################################################
// RunMissionMessageHandler
//#############################################################################
//
void
L4Application::RunMissionMessageHandler(RunMissionMessage *message)
{
Check(this);
Verify(message->messageID == RunMissionMessageID);
//
//--------------------------------------------------------------------------
// If the application is already running then ignore this message
//--------------------------------------------------------------------------
//
switch (GetApplicationState())
{
case RunningMission:
break;
//
//-------------------------------------
// Start the playback if it is required
//-------------------------------------
//
case LaunchingMission:
{
LBE4ControlsManager *controls = GetControlsManager();
Check(controls);
if (controls->IsRecording())
{
controls->StartRecording();
}
else if (controls->IsPlayingBack())
{
controls->StartPlayback();
}
}
break;
case WaitingForLaunch:
PilotIllumination(False);
break;
default:
Fail("Application::RunMissionMessageHandler - Not ready to run!\n");
break;
}
//
//--------------------------------------------------------------------------
// Call previous handler
//--------------------------------------------------------------------------
//
Application::RunMissionMessageHandler(message);
}
//
//#############################################################################
// StopMissionMessageHandler
//#############################################################################
//
void
L4Application::StopMissionMessageHandler(StopMissionMessage *message)
{
Check(this);
Verify(message->messageID == StopMissionMessageID);
//
//--------------------------------------------------------------------------
// Call inherited handler
//--------------------------------------------------------------------------
//
Application::StopMissionMessageHandler(message);
//
//--------------------------------------------------------------------------
// Turn on illumination
//--------------------------------------------------------------------------
//
PilotIllumination(True);
//
//--------------------------------------------------------------------------
// Post a delayed message to ourselves to turn off the illumination
//--------------------------------------------------------------------------
//
Receiver::Message
lights_out_message(LightsOutMessageID, sizeof(Receiver::Message));
Time
event_time;
event_time = Now();
event_time += 30.0f;
Post(
LowEventPriority, // priority
this, // target
&lights_out_message, // message
event_time // when
);
}
//
//#############################################################################
// KeyCommandMessageHandler
//#############################################################################
//
void
L4Application::KeyCommandMessageHandler(
ReceiverDataMessageOf<ControlsKey> *message
)
{
Check(this);
Check(message);
switch (message->dataContents)
{
//--------------------------------------------
// FrameDump from Division card to Targa file
//--------------------------------------------
case PCK_ALT_F:
{
DPLRenderer *dpl_renderer = l4_application->GetVideoRenderer();
if (dpl_renderer)
{
Check(dpl_renderer);
dpl_renderer->DPLFrameDump(True); // True indicates antialiased
}
break;
}
//------------------------------------
// Report current free memory in card
//------------------------------------
case PCK_ALT_K:
{
//STUBBED: HEAP RB 1/20/07
/*DPLRenderer *dpl_renderer = l4_application->GetVideoRenderer();
if (dpl_renderer)
{
Check(dpl_renderer);
dpl_renderer->DPLReportFreeMemory(DEBUG_STREAM) << flush;
}
DEBUG_STREAM << UserHeap::MainStorage.GetTotalHeapLeft() << '('
<< UserHeap::MainStorage.GetBiggestHeapLeft()
<< " contiguous) bytes of MUNGA core left\n"
<< UserHeap::MainStorage.GetHeapUsed() << " bytes of heap used\n";
#if defined(USE_MEMORY_ANALYSIS)
DEBUG_STREAM << UserHeap::MainStorage.GetLowestTotalHeapLeft()
<< " bytes minimum available so far\n"
<< UserHeap::MainStorage.GetMostHeapUsed()
<< " bytes maximum used so far\n";
#endif
MemoryBlockBase::UsageReport();*/
break;
}
//------------------------------------
// Report current event queue
//------------------------------------
case 'E':
{
Check(application);
application->DumpEventQueue();
break;
}
//---------------------------------------
// Report performance statistics (Alt-?)
//---------------------------------------
case PCK_ALT_SLASH:
{
DPLRenderer *dpl_renderer = l4_application->GetVideoRenderer();
if (dpl_renderer)
{
Check(dpl_renderer);
dpl_renderer->DPLReportPerfStats(DEBUG_STREAM);
}
break;
}
//--------------------------
// Toggle Wireframe display
//--------------------------
case PCK_ALT_W:
{
DPLRenderer *dpl_renderer = l4_application->GetVideoRenderer();
if (dpl_renderer)
{
Check(dpl_renderer);
dpl_renderer->DPLToggleWireframe();
}
break;
}
//--------------------------
// Toggle "Predator-vision"
//--------------------------
case PCK_ALT_V:
{
DPLRenderer *dpl_renderer = l4_application->GetVideoRenderer();
if (dpl_renderer)
{
Check(dpl_renderer);
dpl_renderer->DPLTogglePVision();
}
break;
}
//--------------------------------------------------------------
// Toggle transparency dither pattern between random and static
//--------------------------------------------------------------
case PCK_ALT_R:
//-----------------------------
// Report position of eyepoint
//-----------------------------
case PCK_ALT_P:
DEBUG_STREAM << "Function net yet enabled.\n" << flush;
break;
//------------------------------
// Pass event on to Application
//------------------------------
default:
Application::KeyCommandMessageHandler(message);
break;
}
}
//
//#############################################################################
// LightsOutMessageHandler
//#############################################################################
//
#if DEBUG_LEVEL == 0
void
L4Application::LightsOutMessageHandler(Receiver::Message */*message*/)
{
#else
void
L4Application::LightsOutMessageHandler(Receiver::Message *message)
{
Check(this);
Verify(message->messageID == LightsOutMessageID);
#endif
//
//--------------------------------------------------------------------------
// Turn off illumination
//--------------------------------------------------------------------------
//
PilotIllumination(False);
}
//
//#############################################################################
// TeslaCoil
//#############################################################################
//
void
L4Application::TeslaCoil(Logical light_on)
{
Check(controlsManager);
if (light_on)
{
((LBE4ControlsManager *) controlsManager)->SetLamp(
LBE4ControlsManager::LampTesla1,
RIO::solid + RIO::state1Bright + RIO::state2Bright
);
((LBE4ControlsManager *) controlsManager)->SetLamp(
LBE4ControlsManager::LampTesla2,
RIO::solid + RIO::state1Bright + RIO::state2Bright
);
((LBE4ControlsManager *) controlsManager)->SetLamp(
LBE4ControlsManager::LampTesla3,
RIO::solid + RIO::state1Bright + RIO::state2Bright
);
}
else
{
((LBE4ControlsManager *) controlsManager)->SetLamp(LBE4ControlsManager::LampTesla1, RIO::solid + RIO::state1Off + RIO::state2Off);
((LBE4ControlsManager *) controlsManager)->SetLamp(LBE4ControlsManager::LampTesla2, RIO::solid + RIO::state1Off + RIO::state2Off);
((LBE4ControlsManager *) controlsManager)->SetLamp(LBE4ControlsManager::LampTesla3, RIO::solid + RIO::state1Off + RIO::state2Off);
}
}
//
//#############################################################################
// PilotIllumination
//#############################################################################
//
void
L4Application::PilotIllumination(Logical light_on)
{
Check(controlsManager);
TeslaCoil(light_on);
if (light_on)
{
//--------------------------------------------
// Turn on floor light
//--------------------------------------------
((LBE4ControlsManager *) controlsManager)->SetLamp(
LBE4ControlsManager::LampFloor,
RIO::solid + RIO::state1Bright + RIO::state2Bright
);
//--------------------------------------------
// Ramp all aux screens to white
//--------------------------------------------
L4GaugeRenderer *gauge_renderer = GetGaugeRenderer();
if (gauge_renderer != NULL)
{
Check(gauge_renderer);
gauge_renderer->FadeToWhite(1.5);
}
}
else
{
//--------------------------------------------
// Turn off floor light
//--------------------------------------------
((LBE4ControlsManager *) controlsManager)->SetLamp(
LBE4ControlsManager::LampFloor,
RIO::solid + RIO::state1Off + RIO::state2Off
);
//--------------------------------------------
// Ramp all aux screens to normal
//--------------------------------------------
L4GaugeRenderer *gauge_renderer = GetGaugeRenderer();
if (gauge_renderer != NULL)
{
Check(gauge_renderer);
gauge_renderer->FadeToNormal(1.5);
}
}
}
#ifdef TEST_CLASS
# include "l4app.tcp"
#endif
+119
View File
@@ -0,0 +1,119 @@
//===========================================================================//
// File: l4net.cpp //
// Project: MUNGA Brick: L4 Network //
// Contents: Implementation details for the L4 network manager //
//---------------------------------------------------------------------------//
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc. //
// All Rights reserved worldwide //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
//===========================================================================//
#include <mungal4.hpp>
#pragma hdrstop
#if !defined(L4NET_HPP)
# include <l4net.hpp>
#endif
L4NetworkManager::L4NetworkManager():
NetworkManager(NetworkManager::DefaultData),
messageBuffer(this)
{
Fail("L4NetworkManager -- l4net.cpp not yet reconstructed");
}
void
L4NetworkManager::CreateConsoleHost()
{
Fail("L4NetworkManager::CreateConsoleHost -- l4net.cpp not yet reconstructed");
}
L4NetworkManager__MessageBuffer::L4NetworkManager__MessageBuffer(L4NetworkManager *network_manager):
messageQueueSocket(NULL, 1)
{
networkManager = network_manager;
bufferSize = 0;
}
L4NetworkManager__MessageBuffer::~L4NetworkManager__MessageBuffer()
{
}
//
//#############################################################################
// Staged bodies: real l4net.cpp not yet reconstructed. Methods that a
// standalone (non-networked) boot may touch are benign no-ops; methods that
// imply real network traffic Fail loudly.
//#############################################################################
//
L4NetworkManager::~L4NetworkManager()
{
}
void
L4NetworkManager::Send(Message *, ClientID, HostID)
{
Fail("L4NetworkManager::Send -- l4net.cpp not yet reconstructed");
}
void
L4NetworkManager::ExclusiveBroadcast(Message *, ClientID)
{
Fail("L4NetworkManager::ExclusiveBroadcast -- l4net.cpp not yet reconstructed");
}
void
L4NetworkManager::StartConnecting(Mission *)
{
Fail("L4NetworkManager::StartConnecting -- l4net.cpp not yet reconstructed");
}
Logical
L4NetworkManager::Shutdown()
{
return 1;
}
Logical
L4NetworkManager::CheckBuffers(NetworkPacket *)
{
Fail("L4NetworkManager::CheckBuffers -- l4net.cpp not yet reconstructed");
return 0;
}
void
L4NetworkManager::RemovePacket(NetworkPacket *)
{
Fail("L4NetworkManager::RemovePacket -- l4net.cpp not yet reconstructed");
}
Logical
L4NetworkManager::ExecuteBackground()
{
return 0;
}
void
L4NetworkManager::Marker(char *)
{
}
void
L4NetworkManager::Mode(NetworkMode)
{
}
//
//#############################################################################
// NetNub client-side globals (real home: l4net.cpp). Net_Common_Ptr NULL =
// no NetNub TSR loaded; L4File then takes its plain-DOS path (L4FILE.CPP:32).
//#############################################################################
//
Netcom_Ptr
Net_Common_Ptr = NULL;
void
NetNub::SendCommand()
{
Fail("NetNub::SendCommand -- l4net.cpp not yet reconstructed");
}
+1 -1
View File
@@ -75,7 +75,7 @@ def main():
line = re.sub(r"(?<![:\w])GetMessageHandlers\(\)", "MessageHandlers", line)
line = re.sub(r"(?<![:\w])GetAttributeIndex\(\)", "AttributeIndex", line)
line = line.replace("PostQuitMessage(AbortExitCodeID);", 'Fail("Exiting");')
for bad in ("atlbase.h", "windows.h", "winsock"):
for bad in ("atlbase.h", "windows.h", "winsock", "windows.hpp", "<cstdlib>", "<cstring>", "<cstdio>"):
if bad in line and "#include" in line:
line = ""
break
+49 -37
View File
@@ -52,7 +52,7 @@ srcfor() { # srcfor <name.cpp> <BTdir> <RPdir> [S410dir]
l4vidper.cpp|l4tsdpl.cpp) return;; # not in mungal4.lib
filestub.cpp) return;; # stub.lib member (prebuilt obj)
esac
for d in "$2" "$4" "$3"; do # BT first, then source410, then RP
for d in "$4" "$2" "$3"; do # source410 overrides, then BT, then RP
[ -z "$d" ] && continue
for f in "$d"/*.CPP "$d"/*.cpp; do
[ -f "$f" ] || continue
@@ -92,30 +92,50 @@ stage_bt() {
echo "BT: $ok ok, $fail fail"
}
# Authentic 1995 lib member ORDER (MUNGA.MAK / mungal4.mak / BT.MAK / BTL4.MAK).
# Order is LOAD-BEARING: tlink emits static-init records in module pull order,
# and base-class statics (e.g. NetworkClient::ClassDerivations, network.obj)
# must construct before derived ones (IcomManager, icom.obj). Alphabetical
# order boots into a null-vptr crash in Derivation::Derivation.
ORDER_munga="heap cstr memblock memreg memstrm filestrm verify namelist notation fileutil color resource scalar rect2d random angle vector3d vector4d point3d unitvec rotation motion origin affnmtrx linmtrx matrix mtrxstk spline ray line sphere normal plane extntbox bndgbox boxtree boxlist boxsolid boxsort boxsphr boxcone boxramp boxiramp boxwedge boxdisks boxtile time vdata iterator link plug objstrm socket node slot chain sfeskt srtskt schain vchain tree table hash trace receiver event evtstat cmpnnt simulate subsystm joint network damage entity entityid nttmgr entity2 envirnmt mover segment jmover watcher host hostmgr console scnrole team exptbl caminst cammgr camship cammppr eyecandy player director dropzone explode terrain cultural doorfram door registry lattice intorgn collorgn interest collasst update reticle rndorgn renderer vidrend audio audent audtime audwgt audlvl audloc audcmp audsrc audmidi audseq audwthr audrend wrhous gaugmap gauge lamp gaugrend gaugalrm graph2d mode controls mission apptask app appmgr appmsg spooler icom maptool modtool animtool audtools tool"
ORDER_mungal4="l4trace l4file l4time netshare l4serial l4svga16 joystick pcspak l4host l4net l4dplmem l4vidrnd l4video startdpl sosmawe l4audhdw l4audio l4audlvl l4audwtr l4audres l4audrnd l4wrhous l4vb8 l4vb16 l4gauima l4grend l4gauge l4lamp l4plasma l4ctrl l4keybd l4mouse l4rio l4mppr l4app l4splr l4icom l4vidtul l4audtul l4gautul l4ctltul"
ORDER_bt="btmssn messmgr mechdmg dmgtable mech mech2 mech3 mech4 mechsub mechtech heat mechmppr powersub sensor gnrator gyro torso hud myomers mechweap emitter ppc projweap mislanch ammobin gauss projtile misthrst seeker missile btplayer btteam btdirect btreg btcnsl bttool"
ORDER_btl4="btl4mode btl4rdr btl4gaug btl4gau2 btl4gau3 btl4grnd btl4galm btl4vid btl4mppr btl4arnd btl4mssn btl4app btl4pb"
stage_libs() {
cd "$B/lib"
for lib in munga mungal4 bt btl4; do
rm -f $lib.lib
ls "$B/obj/$lib"/*.obj >/dev/null 2>&1 || continue
: > $lib.rsp
for o in "$B/obj/$lib"/*.obj; do
printf '+..\obj\%s\%s &
' "$lib" "$(basename "$o")" >> $lib.rsp
done
# prebuilt-1995 fallbacks for TUs with no compiled obj
if [ $lib = munga ] || [ $lib = mungal4 ]; then
for o in $(find $R/MUNGA/opt $R/MUNGA_L4 -iname "*.obj" 2>/dev/null); do
n=$(basename "${o%.*}" | tr 'A-Z' 'a-z')
if [ ! -f "$B/obj/munga/$n.obj" ] && [ ! -f "$B/obj/mungal4/$n.obj" ]; then
case "$lib/$o" in
munga/*/MUNGA/*) printf '+%s &
' "$(cygpath -w "$o" | sed 's|\|\\|g')" >> $lib.rsp;;
mungal4/*/MUNGA_L4/*) printf '+%s &
' "$(cygpath -w "$o" | sed 's|\|\\|g')" >> $lib.rsp;;
esac
eval "order=\$ORDER_$lib"
added=" "
# authentic makefile order first: compiled obj, else prebuilt-1995 obj
for n in $order; do
if [ -f "$B/obj/$lib/$n.obj" ]; then
printf '+..\obj\%s\%s.obj &
' "$lib" "$n" >> $lib.rsp
added="$added$n "
else
pre=$(find $R/MUNGA/opt $R/MUNGA_L4 -iname "$n.obj" 2>/dev/null | head -1)
if [ -n "$pre" ]; then
printf '+%s &
' "$(cygpath -w "$pre")" >> $lib.rsp
added="$added$n "
fi
done
fi
fi
done
# any extra compiled objs not in the 1995 list go last
for o in "$B/obj/$lib"/*.obj; do
n=$(basename "${o%.*}")
# btl4.obj (main) is linked bare, never a lib member (BTL4.MAK:70)
[ "$lib" = btl4 ] && [ "$n" = btl4 ] && continue
# l4tstall = the engine TEST main -- its own exe in 1995, never a lib member
[ "$n" = l4tstall ] && continue
case "$added" in *" $n "*) continue;; esac
printf '+..\obj\%s\%s.obj &
' "$lib" "$n" >> $lib.rsp
done
sed -i '$ s/ &$//' $lib.rsp
MSYS2_ARG_CONV_EXCL='*' tlib $lib.lib /P32 @$lib.rsp > $lib.tlib.log 2>&1
echo "$lib.lib: $(grep -c '^+' $lib.rsp) members ($(ls -la $lib.lib 2>/dev/null | awk '{print $5}') bytes)"
@@ -124,30 +144,22 @@ stage_libs() {
stage_link() {
cd "$B"
if [ ! -f obj/btl4/btl4.obj ] && [ -f probe_main.cpp ]; then
if [ -f obj/btl4/btl4.obj ]; then
MAIN=obj/btl4/btl4.obj
elif [ -f probe_main.cpp ]; then
bcc32 $FLAGS -I"$INC" -oprobe_main.obj probe_main.cpp > probe_main.log 2>&1 || { echo "probe main FAILED (probe_main.log)"; return 1; }
MAIN=probe_main.obj
else
MAIN=obj/btl4/btl4.obj
fi
cp -f "$T/CODE/BT/32STUB.EXE" 32stub.exe 2>/dev/null
# single-line sections; SOSDBXC+SOSMBXC = the 32-bit Borland SOS pair
# (SOSMW* is 16-bit); WATTCPLG is the 16-bit NetNub TSR side -- excluded
cat > link.rsp <<EOF2
$(cygpath -w $C/C0X32.OBJ)+
$MAIN,
btl4opt.exe,
btl4opt.map,
lib/munga.lib+
lib/mungal4.lib+
$(cygpath -w $R/MUNGA_L4/libDPL/LIBDPL.LIB)+
$(cygpath -w $R/MUNGA_L4/sos/SOSMWXCR.LIB)+
$(cygpath -w $R/MUNGA_L4/NetNub/lib/WATTCPLG.LIB)+
lib/bt.lib+
lib/btl4.lib+
$(cygpath -w $R/DPMI32.LIB)+
$(cygpath -w $R/CW32.LIB)
$(cygpath -w $C/C0X32.OBJ) $(cygpath -w "$B/$MAIN"), btl4opt.exe, btl4opt.map, lib\\munga.lib lib\\mungal4.lib $(cygpath -w $R/MUNGA_L4/libDPL/LIBDPL.LIB) $(cygpath -w $R/MUNGA_L4/sos/SOSDBXC.LIB) $(cygpath -w $R/MUNGA_L4/sos/SOSMBXC.LIB) lib\\bt.lib lib\\btl4.lib $(cygpath -w $R/DPMI32.LIB) $(cygpath -w $R/CW32.LIB)
EOF2
tlink32 -Tpe -ax -m -L"$(cygpath -w $TW/BORLAND/BC45/LIB)" @link.rsp > link.log 2>&1
grep -i "undefined" link.log | sed "s/^.*Error: //" | sort -u > UNRESOLVED.txt
echo "link exit: $? ; unresolved: $(wc -l < UNRESOLVED.txt) (build410/UNRESOLVED.txt)"
MSYS2_ARG_CONV_EXCL='*' tlink32 -Tpe -ax -m -L"$(cygpath -w $TW/BORLAND/BC45/LIB)" @link.rsp > link.log 2>&1
grep -i "unresolved" link.log | sed "s/^.*Error: //" | sort -u > UNRESOLVED.txt
echo "link exit: $? ; unresolved: $(wc -l < UNRESOLVED.txt) (build410/UNRESOLVED.txt); main=$MAIN"
ls -la btl4opt.exe 2>/dev/null
}
case "${1:-all}" in