diff --git a/game/reconstructed/btl4gau2.cpp b/game/reconstructed/btl4gau2.cpp index 6343d06..2efbc25 100644 --- a/game/reconstructed/btl4gau2.cpp +++ b/game/reconstructed/btl4gau2.cpp @@ -822,32 +822,227 @@ void //########################################################################### //########################################################################### +// forward: the tiled-blit helper is defined lower in this TU (FUN_004c2ec4). +static void DrawPortBackground(GraphicsView *view, L4Warehouse *warehouse, + int x, int y, const char *tile); + +// ---- FUN_004c79c8 : draw the three status-label cells (+ optional top erase box). +// Each cell blits its label .pcc, or blanks the cell. Absolute cell rectangles are +// the binary's exact coords (part_014.c:1127-1166). +static void + DrawStatusCells(GraphicsView *view, L4Warehouse *warehouse, + int topBox, const char *A, const char *B, const char *C) +{ + if (topBox) // :1131-1135 + { + view->SetColor(0); + view->MoveToAbsolute(0x97, 0x80); + view->DrawFilledRectangleToAbsolute(0x17d, 0x13b); + } + if (A == NULL) { view->SetColor(0); view->MoveToAbsolute(0x15a, 0x145); // :1136-1140 + view->DrawFilledRectangleToAbsolute(0x17f, 0x159); } + else { view->SetColor(0xff); DrawPortBackground(view, warehouse, 0x15a, 0x145, A); } + if (B == NULL) { view->SetColor(0); view->MoveToAbsolute(0x85, 0x58); // :1145-1149 + view->DrawFilledRectangleToAbsolute(0x17f, 0x7c); } + else { view->SetColor(0xff); DrawPortBackground(view, warehouse, 0x85, 0x58, B); } + if (C == NULL) { view->SetColor(0); view->MoveToAbsolute(0x2a, 0x34); // :1154-1160 + // raw uses an extra GraphicsView vtbl+0x4c(99,10) compound-blank; a plain + // fill at the same cell is the faithful-enough substitute (marked). + view->DrawFilledRectangleToAbsolute(0x9f, 0x2d); } + else { view->SetColor(0xff); DrawPortBackground(view, warehouse, 0x2a, 0x34, C); } +} + +// CFG shape (L4GAUGE.CFG:4595): mode, int screen(1..12), then 7 .pcc names +// (font + 6 labels). 9 params. +MethodDescription + PrepEngrScreen::methodDescription = + { + "prepEngr", + PrepEngrScreen::Make, + { + { ParameterDescription::typeModeMask, NULL }, // p[0] mode (ModeMFD*Eng*) + { ParameterDescription::typeInteger, NULL }, // p[1] screen number 1..12 + { ParameterDescription::typeString, NULL }, // p[2] font helv42.pcc -> statusImage[0] + { ParameterDescription::typeString, NULL }, // p[3] escnd.pcc -> statusImage[1] + { ParameterDescription::typeString, NULL }, // p[4] edmg.pcc -> statusImage[2] + { ParameterDescription::typeString, NULL }, // p[5] bteslev.pcc -> statusImage[3] + { ParameterDescription::typeString, NULL }, // p[6] bteunjm.pcc -> statusImage[4] + { ParameterDescription::typeString, NULL }, // p[7] espeed.pcc -> statusImage[5] + { ParameterDescription::typeString, NULL }, // p[8] btesrnge.pcc -> statusImage[6] + PARAMETER_DESCRIPTION_END + } + }; + // -// @004c7b30 -- Make. DAT_0051936c is the engineer-screen number; must be 1..12 -// or "PrepEngr: screen number out of range " is warned. Allocates (0x90) -// and constructs with seven status-image names (DAT_005193b0..00519548). +// @004c7b30 -- Make. Validate the screen number (p[1], 1..12) then construct. +// The GraphicGaugeBackground base ctor self-registers with the renderer, so the +// gauge's BecameActive fires whenever its Eng screen is selected. We `new` the +// object (real compiled size) rather than operator new(0x90) -- the 2007 base +// isn't byte-exact, and nothing reads this object at raw offsets. // -// @004c7bf0 -- ctor (vtable PTR_FUN_0051a06c). Derives from the non-graphic -// Gauge group (FUN_004440d4) -- it owns no GraphicsView, only a child-gauge -// chain at +0x24. Interns and BitMapCache-AddRefs the seven status pixmaps -// (this[0x1D..0x23]); stores mech (this[0x1B]) and screen number (this[0x1C]). +Logical + PrepEngrScreen::Make( + int display_port_index, + Vector2DOf /*position -- PrepEngr draws at absolute coords*/, + Entity *entity, + GaugeRenderer *gauge_renderer + ) +{ + ParameterDescription *p = methodDescription.parameterList; + + int screen = p[1].data.integer; + if (screen < 1 || screen > 12) // :1182 + { + DEBUG_STREAM << "PrepEngr: screen number out of range " << screen << "\n"; // :1183 + return False; + } + + new PrepEngrScreen( // FUN_00402298(0x90) in the binary + p[0].data.modeMask, // mode (ModeMFD*Eng*) + (L4GaugeRenderer *)gauge_renderer, + 0, // owner_ID (raw hard-wires 0) + display_port_index, // graphics_port_number + entity, // mech + screen, // screen number + p[2].data.string, p[3].data.string, p[4].data.string, + p[5].data.string, p[6].data.string, p[7].data.string, + p[8].data.string, + "PrepEngr"); + return True; +} + // -// @004c7d14 -- dtor: release + free the seven images, tear down the child chain -// (FUN_0044ae0c), Gauge-group dtor (FUN_00443f7c). +// @004c7bf0 -- ctor. GraphicGaugeBackground base (mode/renderer/0/port/"PrepEngr"); +// store screen + mech; copy the 7 image names and pre-load (AddRef) each from the +// bitmap cache. // -// @004c7e48 -- Execute. Walk the mech's critical-subsystem roster -// (mech+0x124 count, mech+0x128 array). For each subsystem that (a) is a -// Generator-derived weapon (IsDerivedFrom 0x50f4bc) and (b) belongs to the -// selected screen (subsys+0x1dc == screenNumber), draw its label and -- via -// NumericDisplay (FUN_004700bc/0047043 0) -- its temperature and a HeatSink -// read-out, then dispatch on ClassID to lay out the weapon's status bitmaps -// (FUN_004c79c8 = draw three labelled status cells): -// 0xBC3 Sensor -> one cell + ammo bitmap (this[0x23]) -// 0xBC6 -> two cells (this[0x22],this[0x20]) -// 0xBC8/0xBD4 Emitter/PPC -> three cells (this[0x1E..0x20]) -// 0xBCD/0xBD0 Proj/Missile -> one cell (this[0x21]) -// 0xBCE GaussRifle -> warn "Gauss rifle not yet supported", one cell +PrepEngrScreen::PrepEngrScreen( + ModeMask mode_mask, L4GaugeRenderer *renderer_in, unsigned int owner_ID, + int graphics_port_number, Entity *mech_in, int screen_number, + const char *img0, const char *img1, const char *img2, const char *img3, + const char *img4, const char *img5, const char *img6, + const char *identification_string +): + GraphicGaugeBackground(mode_mask, renderer_in, owner_ID, // FUN_004440d4 + graphics_port_number, identification_string) +{ + screenNumber = screen_number; // @0x6C (:1216) + mech = mech_in; // @0x70 (:1215) + + const char *src[7] = { img0, img1, img2, img3, img4, img5, img6 }; + L4Warehouse *warehouse = (L4Warehouse *)renderer_in->warehousePointer; // renderer+0x4c + for (int i = 0; i < 7; i++) // :1217-1238 + { + if (src[i] != NULL) { + statusImage[i] = new char[strlen(src[i]) + 1]; // nameCopy (FUN_004700ac) + strcpy(statusImage[i], src[i]); + warehouse->bitMapBin.Get(statusImage[i]); // FUN_00442aec pre-load/AddRef + } else { + statusImage[i] = NULL; + } + } +} + // +// @004c7d14 -- dtor. Release the 7 pre-loaded images + free their name copies; +// the localView + base dtor run implicitly (do NOT emit explicit base-dtor calls). +// +PrepEngrScreen::~PrepEngrScreen() +{ + L4Warehouse *warehouse = (L4Warehouse *)renderer->warehousePointer; + for (int i = 0; i < 7; i++) // :1254-1274 + { + if (statusImage[i] != NULL) { + warehouse->bitMapBin.Release(statusImage[i]); // FUN_00442c12 + delete[] statusImage[i]; + statusImage[i] = NULL; + } + } +} + +// +// @004c7e48 -- BecameActive. Find the subsystem assigned to this screen and paint +// its labels (roster + aux-screen read via the databinding-safe accessors + the +// PoweredSubsystem bridge, exactly like VehicleSubSystems::Make). NON-inactivating +// (a real paint; does not chain the base) -> the paint-on-activation contract. +// +void + PrepEngrScreen::BecameActive() +{ + if (mech == NULL) return; + L4Warehouse *warehouse = (L4Warehouse *)renderer->warehousePointer; + const char *font = statusImage[0]; // helv42.pcc + + int count = mech->GetSubsystemCount(); // mech+0x124 + for (int i = 1; i < count; i++) // skip slot 0 (controls mapper) + { + Subsystem *sub = mech->GetSubsystem(i); // mech+0x128[i] + if (sub == NULL) continue; + + int auxScreen = 0, placement = -1; char label64[64]; label64[0] = '\0'; + if (!BTGetSubsystemAuxScreen(sub, &auxScreen, &placement, label64)) // filter + sub+0x1dc + continue; // not a PoweredSubsystem-derived weapon + if (auxScreen != screenNumber) // :1309 + continue; + + // ---- numeric #1 : the screen number, 2 digits @(0xE9,0x176) (:1310-1313) + { + NumericDisplay num(warehouse, 0xe9, 0x176, font, 2, + NumericDisplay::unsignedFormat, 0, 0xff); // FUN_004700bc + num.Draw(&localView, (Scalar)screenNumber); // FUN_00470430 + } + + // ---- numeric #2 : linked heat-sink number, 1 digit @(0x15E,5) (:1315-1321) + // BEST-EFFORT (marked): the resolved sink's +0x1D4 index is a raw offset on + // a not-byte-exact object -> guarded (NULL link / read 0). + int hsNumber = 0; + void *hsLink = AttributePointerOf(sub, "HeatSink"); // FUN_0041bfc0 + void *hs = (hsLink != NULL) ? ResolveLink(hsLink) : NULL; // FUN_00417ab4 + if (hs != NULL) + hsNumber = *(int *)((char *)hs + 0x1d4); + { + NumericDisplay num(warehouse, 0x15e, 5, font, 1, + NumericDisplay::unsignedFormat, 0, 0xff); + num.Draw(&localView, (Scalar)hsNumber); + } + + // ---- subsystem label bitmap @(0x125,0x172) (:1322-1329). The binary draws + // the .pcc name at sub+0x224; the aux-screen bridge's label64 is the + // databinding-safe equivalent (BEST-EFFORT). + if (label64[0] != '\0') { + localView.SetColor(0xff); + DrawPortBackground(&localView, warehouse, 0x125, 0x172, label64); + } + + // ---- type-specific label cells (switch on ClassID, :1330-1357) + switch (sub->GetClassID()) // sub+4 + { + case 0xBC3: // Sensor + DrawStatusCells(&localView, warehouse, 1, NULL, NULL, NULL); + localView.SetColor(0xff); + DrawPortBackground(&localView, warehouse, 0xb8, 0x8c, statusImage[6]); // btesrnge + return; + case 0xBC6: // Myomers + DrawStatusCells(&localView, warehouse, 0, NULL, statusImage[5], statusImage[3]); + return; + case 0xBC8: // Emitter + case 0xBD4: // PPC + DrawStatusCells(&localView, warehouse, 0, statusImage[1], statusImage[2], statusImage[3]); + return; + case 0xBCD: // ProjectileWeapon + case 0xBD0: // MissileLauncher + DrawStatusCells(&localView, warehouse, 1, NULL, NULL, statusImage[4]); + return; + case 0xBCE: // GaussRifle -- not yet supported + DEBUG_STREAM << "PrepEngr: Gauss rifle not yet supported\n"; // :1353 + DrawStatusCells(&localView, warehouse, 1, NULL, NULL, statusImage[3]); + return; + default: + return; + } + } +} + //########################################################################### diff --git a/game/reconstructed/btl4gau2.hpp b/game/reconstructed/btl4gau2.hpp index 9235dfd..8bf1fa7 100644 --- a/game/reconstructed/btl4gau2.hpp +++ b/game/reconstructed/btl4gau2.hpp @@ -290,35 +290,39 @@ //####################################################################### - // PrepEngrScreen -- builds the per-weapon "engineering" status screen. - // @004c7b30 Make / @004c7bf0 ctor / @004c7d14 dtor. vtable PTR_FUN_0051a06c. - // Derives from the non-graphic Gauge group (FUN_004440d4) and interns seven - // status pixmaps (this[0x1D..0x23]). Make validates DAT_0051936c (engineer - // screen number, must be 1..12; warns "PrepEngr: screen number out of range"). - // Execute @004c7e48 walks the mech's critical-subsystem roster (mech+0x124 - // count / mech+0x128 array) and, for each weapon on the selected screen, - // renders its label & ammo via NumericDisplay, dispatching on subsystem - // ClassID (0xBC3 Sensor, 0xBC6, 0xBC8/0xBD4 Emitter/PPC, 0xBCD/0xBD0 - // Projectile/Missile, 0xBCE GaussRifle -- "Gauss rifle not yet supported"). + // PrepEngrScreen (config keyword "prepEngr") -- the per-engineering-screen + // STATIC LABEL overlay. @004c7b30 Make / @004c7bf0 ctor / @004c7d14 dtor / + // @004c7e48 BecameActive. vtable PTR_FUN_0051a06c. + // + // A GraphicGaugeBackground (paint-on-activation, NOT an Execute gauge -- the + // same base/vtable shape as the engine's BackgroundBitmap: only the dtor + + // BecameActive slots are overridden). Interns 7 status .pcc's (font + 6 + // labels) and, when its MFD-Eng screen (1..12) activates, paints the labels + // for the ONE subsystem whose auxScreenNumber == this screen, dispatched by + // the subsystem's ClassID. Was a MISLABELED stub (base Gauge, Execute, and + // mech/screenNumber SWAPPED) with no methodDescription -> "prepEngr" was + // parse-skipped (12 CFG calls never built). //####################################################################### class PrepEngrScreen : - public Gauge // non-graphic Gauge group (FUN_004440d4) + public GraphicGaugeBackground { public: + static MethodDescription methodDescription; // "prepEngr" static Logical Make(int, Vector2DOf, Entity *, GaugeRenderer *); // @004c7b30 PrepEngrScreen( // @004c7bf0 - GaugeRate, ModeMask, L4GaugeRenderer *, int screen_number, - Entity *mech, int graphics_port_number, - const char *img0, const char *img1, const char *img2, + ModeMask, L4GaugeRenderer *, unsigned int owner_ID, + int graphics_port_number, Entity *mech, int screen_number, + const char *img0/*font*/, const char *img1, const char *img2, const char *img3, const char *img4, const char *img5, - const char *img6, const char *identification_string); + const char *img6, const char *identification_string = "PrepEngr"); ~PrepEngrScreen(); // @004c7d14 - void Execute(); // @004c7e48 + void BecameActive(); // @004c7e48 (the paint slot -- NOT Execute) protected: - Entity *mech; // @0x6C this[0x1B] - int screenNumber; // @0x70 this[0x1C] - char *statusImage[7]; // @0x74 this[0x1D..0x23] - // child gauges chained in the base Gauge group at +0x24 + int screenNumber; // @0x6C this[0x1B] (FIX: was mech) + Entity *mech; // @0x70 this[0x1C] (FIX: was screenNumber) + char *statusImage[7]; // @0x74 this[0x1D..0x23] (interned .pcc names) + // sizeof == 0x90 (Make alloc); no offset locks (2007 GraphicGaugeBackground + // base not byte-identical; every read is via named members / safe accessors). }; diff --git a/game/reconstructed/btl4grnd.cpp b/game/reconstructed/btl4grnd.cpp index 87f96f5..3dfb806 100644 --- a/game/reconstructed/btl4grnd.cpp +++ b/game/reconstructed/btl4grnd.cpp @@ -148,6 +148,7 @@ MethodDescription &PilotList::methodDescription, // "pilotList" -- Comm KILLS/DEATHS pilot roster &GeneratorCluster::methodDescription, // "GeneratorCluster" -- the 4 generator engineering panels (buttons 9-12) &SectorDisplay::methodDescription, // "sectorDisplay" -- radar SECTOR X/Z read-out (Secondary overlay) + &PrepEngrScreen::methodDescription, // "prepEngr" -- per-Eng-screen static label overlay (12x) &BTL4ChainToPrevious }; diff --git a/scratchpad/prep_gauge.png b/scratchpad/prep_gauge.png new file mode 100644 index 0000000..0886c5a Binary files /dev/null and b/scratchpad/prep_gauge.png differ