Files
TeslaRel410/restoration/source410/BT_L4/BTL4MSSN.CPP
T
CydandClaude Fable 5 10e1a70055 BT410 Phase 5.3.30: the pilot name resolves -- and the magenta boxes diagnosed
The name art was never missing.  The egg carries it as notation pages of hex
rows ([BitMap::Small::Aeolus]); the engine BitMap has a ctor that reads
exactly that format; and the AUTHENTIC Mission ctor already loads them into
smallNameBitmapChain (MISSION.CPP:525 -- implemented, called, working).  The
break was ours: btl4gau3's LookupPlayerNameBitmap was a bring-up stub
returning NULL.  It now uses the authentic API (GetCurrentMission()->
GetSmallNameBitmap(playerBitmapIndex)) and resolves live -- traced index=1
to a real BitMap, with the fallback-box branch provably never firing.
Coverage 91% -> 92%.

DIAGNOSIS CORRECTED for the stray magenta blocks over the top-left title:
they are NOT a missing-name placeholder.  They are the REAL name bitmap
drawn at the wrong slot coordinates -- PilotList lays its 8 roster slots
out from the PE-recovered DAT_0051af88 (x,y,mode) table, and ours puts them
top-left instead of the shipped exe's centre row.  Recovering that table is
the next cockpit thread; the egg-hex -> live-BitMap pipeline is verified end
to end, so what remains there is layout, not art or lookup.

(A duplicate loader written before finding the authentic one was removed --
CODE/RP/MUNGA/MISSION.CPP already does this job.)

Gauge fight 11/11, smoke and novice clean, zero faults.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 09:47:19 -05:00

369 lines
10 KiB
C++

//===========================================================================//
// File: btl4mssn.cpp //
// Project: BattleTech Brick: //
// Contents: Implementation for the L4 (game-level) mission //
//---------------------------------------------------------------------------//
// Date Who Modification //
// -------- --- ---------------------------------------------------------- //
// 04/07/95 ECH Initial coding. //
// 09/12/95 JM Derived from L4Mission //
//---------------------------------------------------------------------------//
// 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
#if !defined(BTL4APP_HPP)
# include <btl4app.hpp>
#endif
#if !defined(L4GREND_HPP)
# include <l4grend.hpp>
#endif
#if !defined(L4HOST_HPP)
# include <l4host.hpp>
#endif
#if !defined(HOSTMGR_HPP)
# include <hostmgr.hpp>
#endif
#if !defined(NOTATION_HPP)
# include <notation.hpp>
#endif
#if !defined(SCNROLE_HPP)
# include <scnrole.hpp>
#endif
//##########################################################################
//########################### BTL4Mission ############################
//##########################################################################
//
//#############################################################################
//#############################################################################
//
BTL4Mission::BTL4Mission(
NotationFile *notation_file,
ResourceFile *resources
):
BTMission(notation_file, resources)
{
Check_Fpu();
}
//
//#############################################################################
//#############################################################################
//
BTL4Mission::~BTL4Mission()
{
Check(this);
Check_Fpu();
}
//
//#############################################################################
// SetPlayerData Pulls this host's player page out of the notation file and
// populates the mission's player description: model, dropzone, color, badge,
// patch, experience level, advanced-damage flag, scenario role (+ its damage
// modifiers), and the plasma-display badge bitmap.
//#############################################################################
//
void
BTL4Mission::SetPlayerData(NotationFile *notation_file)
{
Check(this);
//
//--------------------------------------------------------------
// Figure out which page we should be using to create the player
//--------------------------------------------------------------
//
Check(application);
HostManager *host_manager = application->GetHostManager();
Check(host_manager);
L4Host *host = (L4Host*)host_manager->GetLocalHost();
Check(host);
CString
player_node = host->GetSymbolicName();
//
//----------------------------------------------------------
// Copy the game model and dropzone strings into the mission
//----------------------------------------------------------
//
gameModel = NULL;
const char *player_model = NULL;
notation_file->GetEntry(player_node, "vehicle", &player_model);
if (!player_model)
{
DEBUG_STREAM << "Error: vehicle not specified!\n";
Fail("Exiting");
}
Check_Pointer(player_model);
gameModel = strdup(player_model);
Register_Pointer(gameModel);
dropZoneName = NULL;
const char *drop_zone = NULL;
notation_file->GetEntry(player_node, "dropzone", &drop_zone);
if (!drop_zone)
{
DEBUG_STREAM << "Error: dropzone not specified!\n";
Fail("Exiting");
}
Check_Pointer(drop_zone);
dropZoneName = strdup(drop_zone);
Register_Pointer(dropZoneName);
dropZoneHost = False;
notation_file->GetEntry(player_node, "loadzones", &dropZoneHost);
//
//----------------------------------------------------------
// Color
//----------------------------------------------------------
//
colorName = NULL;
const char *color_name = NULL;
notation_file->GetEntry(player_node, "color", &color_name);
if (!color_name)
{
DEBUG_STREAM << "Error: color not specified!\n";
Fail("Exiting");
}
Check_Pointer(color_name);
colorName = strdup(color_name);
Register_Pointer(colorName);
//
//----------------------------------------------------------
// Patch
//----------------------------------------------------------
//
const char *patch_name = NULL;
notation_file->GetEntry(player_node, "patch", &patch_name);
if (!patch_name)
{
DEBUG_STREAM << "Error: patch not specified!\n";
Fail("Exiting");
}
Check_Pointer(patch_name);
patchName = patch_name;
//
//----------------------------------------------------------
// Badge
//----------------------------------------------------------
//
badgeName = NULL;
const char *badge_name = NULL;
notation_file->GetEntry(player_node, "badge", &badge_name);
if (!badge_name)
{
DEBUG_STREAM << "Error: badge not specified!\n";
Fail("Exiting");
}
Check_Pointer(badge_name);
badgeName = strdup(badge_name);
Register_Pointer(badgeName);
//
//----------------------------------------------------------
// Team name. NOTE: the shipped binary reads the "badge" key here
// as well and defaults to "DEFAULT" when the page omits it.
//----------------------------------------------------------
//
const char *team_name = NULL;
if (!notation_file->GetEntry(player_node, "badge", &team_name))
{
teamName = "DEFAULT";
}
else
{
Check_Pointer(team_name);
teamName = team_name;
}
//
//----------------------------------------------------------
// Experience level. Absence is tolerated only for the "camera"
// page; "Unspecified" leaves the default.
//----------------------------------------------------------
//
const char *experience = "Unspecified";
if (!notation_file->GetEntry(player_node, "experience", &experience))
{
if (strcmp(gameModel, "camera") != 0)
{
DEBUG_STREAM << player_node << " page missing expereince!" << endl;
Fail("Exiting");
}
}
if (strcmp("Unspecified", experience) != 0)
{
if (strcmp(experience, "novice") == 0)
{
experienceLevel = BTMission::NoviceMode;
}
else if (strcmp(experience, "standard") == 0)
{
experienceLevel = BTMission::StandardMode;
}
else if (strcmp(experience, "veteran") == 0)
{
experienceLevel = BTMission::VeteranMode;
}
else if (strcmp(experience, "expert") == 0)
{
experienceLevel = BTMission::ExpertMode;
}
else
{
DEBUG_STREAM << player_node
<< " has an unknown experience field of "
<< experience;
Fail("Exiting");
}
}
//
//----------------------------------------------------------
// Advanced damage flag
//----------------------------------------------------------
//
Logical advanced_damage = False;
if (notation_file->GetEntry(player_node, "advancedDamage", &advanced_damage))
{
advancedDamageOn = advanced_damage ? True : False;
}
//
//----------------------------------------------------------
// Scenario role -- every player page must name a role, and the role
// page must name a model. The ScenarioRole is looked up (and created
// on first use) in the mission's role dictionary, then its per-page
// score modifiers applied.
//----------------------------------------------------------
//
const char *role_node = NULL;
if (!notation_file->GetEntry(player_node, "role", &role_node))
{
DEBUG_STREAM << "Each Player page must have a role field !" << endl;
Fail("Exiting");
}
else
{
Check_Pointer(role_node);
roleName = role_node;
const char *role_model = NULL;
if (!notation_file->GetEntry(role_node, "model", &role_model))
{
DEBUG_STREAM << role_node << " page or model field missing !" << endl;
Fail("Exiting");
}
else
{
ScenarioRole *role = GetScenarioRole(roleName);
if (role == NULL)
{
role = new ScenarioRole(roleName, CString(role_model));
Register_Object(role);
AddScenarioRole(role);
}
//
// Optional per-page score modifiers.
//
Scalar value;
if (notation_file->GetEntry(role_node, "dmgInflctdMdfr", &value))
{
role->SetDamageInflictedModifier(value);
}
if (notation_file->GetEntry(role_node, "dmgRcvdMdfr", &value))
{
role->SetDamageReceivedModifier(value);
}
if (notation_file->GetEntry(role_node, "dmgBias", &value))
{
role->SetDamageBias(value);
}
if (notation_file->GetEntry(role_node, "friendlyFire", &value))
{
role->SetFriendlyFirePenalty(value);
}
int return_from_death;
if (notation_file->GetEntry(role_node, "return", &return_from_death))
{
role->SetReturnFromDeath(return_from_death);
}
if (notation_file->GetEntry(role_node, "killBonus", &value))
{
role->SetKillBonus(value);
}
}
}
//
//~~~~~~~~~~~~~~~~~~~~~~
// Get playerBitmapIndex and, if present, blit the badge bitmap onto
// the external (plasma) display.
//~~~~~~~~~~~~~~~~~~~~~~
//
if (!notation_file->GetEntry(player_node, "bitmapindex", &playerBitmapIndex))
{
DEBUG_STREAM << "No Bitmap for player" << player_node;
DEBUG_STREAM << flush;
}
else
{
BitMap *bitmap = GetLargeNameBitmap(playerBitmapIndex);
if (bitmap != NULL)
{
Check(application);
L4GaugeRenderer
*gauge_renderer =
(L4GaugeRenderer*)application->GetGaugeRenderer();
if (gauge_renderer != NULL)
{
Check(gauge_renderer);
GraphicsDisplay *graphics_display =
gauge_renderer->GetExternalDisplay();
if (graphics_display != NULL)
{
graphics_display->DrawBitMapOpaque(
1, // foreground color
0, // background color
0xFF, // bitmask
GraphicsDisplay::Replace, // operation
0, // rotation
0, 0, // position
bitmap,
0, // sx1
0, // sy1
bitmap->Data.Size.x - 1, // sx2
bitmap->Data.Size.y - 1 // sy2
);
graphics_display->Update(True);
graphics_display->WaitForUpdate();
}
}
}
}
Check_Fpu();
}