//===========================================================================// // File: btl4galm.cpp // // Project: BattleTech Brick: Gauge Renderer Manager // // Contents: BTL4GaugeAlarmManager -- the BattleTech override of the MUNGA // // GaugeAlarmManager. It supplies the two per-item stream virtuals // // that the base class declares pure ("not overridden!"): it knows how // // to compile a named cockpit-gauge alarm definition into a memory // // stream (CreateGaugeAlarmStreamItem) and how to instantiate a live // // GaugeAlarm for a given subsystem/condition from that stream // // (ReadGaugeAlarmStreamItem). // //---------------------------------------------------------------------------// // Date Who Modification // // -------- --- ---------------------------------------------------------- // // 02/22/96 CPB Initial coding. // //---------------------------------------------------------------------------// // Copyright (C) 1996, Virtual World Entertainment, Inc. All rights reserved // // PROPRIETARY AND CONFIDENTIAL // //===========================================================================// // // RECONSTRUCTED -- IMPORTANT PROVENANCE NOTE // ------------------------------------------ // btl4galm.obj links after btl4grnd.obj and before btl4vid.obj (BTL4.MAK // BTL4_OBJS order). In the shipped optimised image (BTL4OPT.EXE) there is **no // distinct, separately-emitted BTL4GaugeAlarmManager override body**: // * the only GaugeAlarmManager code in the binary is the MUNGA base class in // gaugalrm.cpp (recovered/all/part_006.c, @00448928..@00448f48), including // the two "not overridden!" trap virtuals // CreateGaugeAlarmStreamItem @00448ab8 (asserts GAUGALRM.CPP:0x71) // ReadGaugeAlarmStreamItem @00448ad4 (asserts GAUGALRM.CPP:0x7e) // and the base driver helpers that CALL those virtuals // GaugeAlarmManager::CreateGaugeAlarmStream @00448af0 // GaugeAlarmManager::BuildAlarmsForModel @00448d00 // * no subclass vtable (one whose Create/Read slots point into BattleTech // code) appears in vtables.tsv, and no caller constructs a subclass // (the base ctors @00448ebd/@00448edc/@00448efb have no external callers). // The code region the linker reserved for btl4galm.obj (@004cc40c..@004cdac0) // actually holds a 3-D HUD-model builder (PNAME1..8.bgf), i.e. the compiler // folded BTL4GaugeAlarmManager's tiny overrides away / it was never instantiated // in this build configuration. // // This file is therefore reconstructed to MATCH THE SURVIVING BTL4GALM.HPP and // the base driver's calling contract (the argument order, the GaugeAlarm object // it expects, and the "undefined alarm type ... resource not built" diagnostic // the base prints when the virtual returns False). Bodies below are BEST-EFFORT // (low confidence): they describe what the override must do for the base driver // to function, not bytes lifted from this image. // // Base contract (recovered, high confidence): // GaugeAlarmManager::CreateGaugeAlarmStream @00448af0 // - opens the "gaugeAlarm" sub-resource of a model record (FUN_00404720, // "gaugeAlarm" @004eecc9), counts its entries, makes a MemoryStream // (0x18), and for each entry calls the virtual // this->CreateGaugeAlarmStreamItem(stream, entry_name, entry_data) // (entry_name @entry+8, entry_data @entry[1]); if it returns 0 it prints // "Model file '' has undefined alarm type '' - // resource not built." (strings @004eecd4/@004eece1/@004eecfe) // and aborts the build. On success it bakes the stream (FUN_00406f3c). // GaugeAlarmManager::BuildAlarmsForModel @00448d00 // - for each baked alarm record it makes a GaugeAlarm (FUN_004489e8, // 0x28 bytes; vtable PTR_FUN_004eed7c; ctor stores entity@+0xc, // subsystem@+0x10, condition@+0x14), adds it to the manager's alarm list // (this+4, list-insert vtbl+4), then calls the virtual // this->ReadGaugeAlarmStreamItem(alarm, entity, subsystem, condition, // stream) // once per record to configure it. // // Engine-internal helper map (from the base + the BattleTech alarm bricks): // FUN_004489e8 GaugeAlarm ctor FUN_00448a28 GaugeAlarm dtor // FUN_00448ebd GaugeAlarmManager base ctor (chains a ChainOf) // FUN_0040385c Verify(msg,file,line) // FUN_004dbb24 DebugStream << (char*) FUN_004db78c DebugStream << (int) // DAT_00524e20 DebugStream (warning channel) // MemoryStream write/read = (*stream + 0x20)(stream,&v,4) / (*stream+0x1c)(...) // #include #pragma hdrstop #if !defined(BTL4GALM_HPP) # include #endif #if !defined(APP_HPP) # include #endif // // Recognised cockpit gauge-alarm type names. (BattleTech's l4gauge.cfg // "gaugeAlarm" sections name one of these; the threshold / flash parameters // follow in alarm_data.) The exact spelling list could not be recovered from // this image -- it lived in the folded-away override -- so the set below is the // minimal set implied by the GaugeAlarm fields the cockpit gauges flash on // (heat / power / armour / ammo). BEST-EFFORT. // enum GaugeAlarmType { gaugeAlarmThreshold, // value crosses a fixed threshold gaugeAlarmRange, // value leaves a [low,high] band gaugeAlarmState, // subsystem operational-state change gaugeAlarmFlash, // timed flash while condition holds gaugeAlarmTypeCount, gaugeAlarmUndefined = -1 }; // // BTL4GaugeAlarmManager::CreateGaugeAlarmStreamItem // // Called by GaugeAlarmManager::CreateGaugeAlarmStream (@00448af0) once per // "gaugeAlarm" entry while a gauge model is being compiled. Recognise the // alarm type spelled in , parse its parameters out of , // and serialise (type, parameters) into . Returning False makes // the base print "Model file '...' has undefined alarm type '' - // resource not built." and abandon the model -- so an unknown name MUST yield // False (that diagnostic is the observable contract). // // BEST-EFFORT reconstruction (no distinct override body survived in BTL4OPT.EXE). // Logical BTL4GaugeAlarmManager::CreateGaugeAlarmStreamItem( MemoryStream *mem_stream, const char *alarm_name, const char *alarm_data ) { GaugeAlarmType type = gaugeAlarmUndefined; // // Map the type name -> enum. (Names best-effort; see note above.) // if (stricmp(alarm_name, "threshold") == 0) type = gaugeAlarmThreshold; else if (stricmp(alarm_name, "range") == 0) type = gaugeAlarmRange; else if (stricmp(alarm_name, "state") == 0) type = gaugeAlarmState; else if (stricmp(alarm_name, "flash") == 0) type = gaugeAlarmFlash; if (type == gaugeAlarmUndefined) { // // Unknown alarm type: tell the caller so it emits the // "undefined alarm type ... resource not built" warning. // return False; } // // Serialise the type tag followed by the type-specific parameters parsed // from the alarm_data text (thresholds, flash period, target colour, ...). // mem_stream->WriteBytes(&type, sizeof(type)); // (*mem_stream+0x20)(...,4) // ... write parsed numeric parameters from alarm_data ... return True; } // // BTL4GaugeAlarmManager::ReadGaugeAlarmStreamItem // // Called by GaugeAlarmManager::BuildAlarmsForModel (@00448d00) once per baked // alarm record, with a freshly-constructed GaugeAlarm (already carrying // the_entity/the_subsystem/the_condition from the GaugeAlarm ctor @004489e8). // Read the (type, parameters) back out of and configure // so that, every frame, it samples the named subsystem attribute and raises / // clears its flashing state when the recorded condition is met. // // BEST-EFFORT reconstruction (no distinct override body survived in BTL4OPT.EXE). // void BTL4GaugeAlarmManager::ReadGaugeAlarmStreamItem( GaugeAlarm *alarm, Entity *the_entity, Subsystem *the_subsystem, Enumeration the_condition, MemoryStream *mem_stream ) { GaugeAlarmType type; mem_stream->ReadBytes(&type, sizeof(type)); // (*mem_stream+0x1c)(...,4) // // Bind the alarm to its data source and trip parameters. The base // GaugeAlarm already stores entity/subsystem/condition; here we attach the // type-specific trip (threshold / band / state / flash period) read from // the stream so GaugeAlarm::Execute can flash the owning gauge. // switch (type) { case gaugeAlarmThreshold: // alarm->SetThreshold( read Scalar ); alarm->SetCondition(the_condition); break; case gaugeAlarmRange: // alarm->SetBand( read low, read high ); break; case gaugeAlarmState: // alarm->WatchState(the_subsystem); break; case gaugeAlarmFlash: // alarm->SetFlashPeriod( read Scalar ); break; default: Verify(False, "Bad gauge alarm type", "d:\\tesla\\bt\\bt_l4\\BTL4GALM.CPP", 0); break; } (void)the_entity; (void)the_subsystem; (void)the_condition; }