Author SHA1 Message Date
dicion c33465611f Add [automaticmode] Load File button to console lobby
options.ini [automaticmode] section:
  automaticmode=1
  automaticfile=c:\path\to\config.ini

Right-click was considered then dropped in favor of a dedicated button
at 467,510 (below Pick Cond., left of Reprint).

C++ (MW4Shell.cpp):
- SAutoFileSlot struct + g_aAutoSlots[16], g_bAutomaticMode, g_szAutomaticFile globals
- [automaticmode] ini read at StartUp
- CTCL_LoadAutoFile: checks file exists, reads [mission] page into existing
  g_nRookieXxx globals + [slot0]..[slot15] pages into g_aAutoSlots[]; returns 1 if loaded
- CTCL_GetAutoSlotName(out_str, k): pilot name for slot k
- CTCL_GetAutoSlotMech(out_str, k): mech display name for slot k
- CTCL_GetAutoSlotInt(k, field): Type/Team/Skin/Decal for slot k (fields 0-3)
- Register/unregister all 4 callbacks in StartUp/ShutDown

Script (ConLobby.script):
- o_load_file button at 467, 510
- Handler: CTCL_LoadAutoFile -> if loaded, sends MAIL_SET_ROOKIE_MISSION to
  ConLobbyMission (game options), clears all slots, then applies per-slot data
  in a loop (pilot names, mech by display-name lookup in allowed_mechs[], team,
  skin, decal). USE_ALLOWED_MECHS/non-ALLOWED_MECHS both handled via #if.

File not consumed (stays on disk); external app overwrites for next load.
Rebuild required: MW4.exe (Release + Profile).
2026-07-24 08:44:57 -05:00
dicion fccdc2dee4 CLAUDE.md: document 5813aeb6 through 0344418a work (2026-07-23)
- hsh/ BMP canonical renames (MFD + Mechs, commit 5813aeb6)
- RookieMission configurable defaults via options.ini (MW4Shell.cpp + ConLobbyMission.script, 5813aeb6)
- Mechlab turn rate label correction (StringResource.rc, 5813aeb6)
- BTFrstrm design docs: MechDependencyTree.docx + Special_Zones.docx (840bc96c)
- mech_loadouts.md: MechEditor data sources, field conversions, hsh naming reference (0344418a)
2026-07-23 22:18:43 -05:00
dicion 0344418aae mech_loadouts.md: document MechEditor data sources, conversions, hsh naming (2026-07-23) 2026-07-23 21:56:14 -05:00
dicion 520a860414 Update testing checklist through 2026-07-23 (RookieMission, turnrate label, hsh renames) 2026-07-23 21:47:08 -05:00
dicion 5813aeb6e9 Fix missing asset files with ones from 5.0.7D 2026-07-23 21:36:27 -05:00
dicion 840bc96cc1 Documentation! 2026-07-23 16:16:45 -05:00
dicion 72e1e59d8e CLAUDE.md: document eaa5fd3 through 5.1.0b-in-progress work
- MFD mode 4 right-device stagger fix (eaa5fd3): cycle diagram, files touched
- Linux→Windows rsync workflow: sync-to-windows.sh (55b9bfc5)
- ddraw.dll removed from repo; build-resources.ps1 moves it aside (0ceba9c7, 24825ff3)
- ConLobby V5.1.0b1 / Super6 6-mech rotation from Highlight (c768f7c4)
- CRIOMAIN.CPP Korean translation + RIO poll timeout scaling; CRLF hazard note;
  min/max undeclared in VC6 in this TU (16fca6c4, a712002f)
- 16 pilots + 1 cameraship: NetworkMaxPlayers formula, fall-through break warning (f76dc05f)
2026-07-19 19:55:46 -05:00
dicion b591bae273 add checklist of changes for testing! 2026-07-19 19:18:09 -05:00
dicion a712002fec CRIOMAIN.CPP: fix min/max undeclared identifier (VC6)
min() and max() are not in scope in this translation unit under VC6.
Replace with explicit ternary clamping expression; no new headers needed.
2026-07-19 19:00:08 -05:00
dicion f76dc05f46 Support 16 pilots + 1 cameraship in multiplayer
MW4Shell.cpp:
- CTCL_DefaultHostSetup (non-coop): replaced hardcoded
  Environment.NetworkMaxPlayers=16 with
  params->m_maxPlayers + (CTCL_GetTeslaCountAll() - CTCL_GetTeslaCount())
  so DirectPlay reserves one extra slot per installed cameraship.
  CTCL_GetTeslaCountAll() - CTCL_GetTeslaCount() = camera-only seat count.
- SetNetworkMissionParamater / PLAYER_LIMIT_PARAMETER: applied the same
  camera-slot formula when the host changes the player limit at runtime.
  Also restored the gos_NetServerCommands(gos_Commend_UpdateMaxPlayers)
  call (was accidentally dropped) and the missing break that caused
  fall-through into JOIN_IN_PROGRESS_PARAMETER.
- COOP branch: no change (capped at 9+bots; camera seats not needed there).

ConLobby.script:
- Raised the launch-guard cap from nTempPlayerCount > 16 to > 17,
  allowing the 17th connection (the cameraship) to not trigger the
  'Too many player/bots' error.
2026-07-19 18:54:38 -05:00
dicion 16fca6c4f1 CRIOMAIN.CPP: translate Korean comments to English, clean UTF-8
Translated all EUC-KR/CP949 Korean developer comments (~35 lines) to
English. File re-saved as UTF-8 (was CP949/EUC-KR on disk).

Also included: g_dwRIOPollTimeout formula that scales WaitForMultipleObjects
timeout by baud rate: clamp(ceil(480000/baud), 5, 50) ms.

Key translations:
- Developer markers (sanghoon/hyun)
- Packet receive loop comments
- ACK/NAK handling comments
- Thread/COM init comments
- Button table comments
- Joystick pedal/throttle diagram comments

Decorative diamond markers (◆) stripped from case labels and section
dividers. Unicode arrows (← →) in diagram comments replaced with ASCII.
2026-07-19 18:52:30 -05:00
c768f7c46b Bump console version to V5.1.0b1; merge Highlight Super6 changes
Version bumped to V5.1.0b1 to align with the 5.1.0b-in-progress branch name and
the goal of producing a tested release candidate.

Incorporated manually-tested script changes from Buddy 'Highlight' Taylor of
MechCorps (MCHL), who expanded the default mech pool from Fab4 to Super6:
- ROOKIEMECH defines extended to 6 entries (added Archer ID=1, Warhammer ID=62)
- 16-slot default mech assignments updated to cycle through all 6 Super6 mechs
- Right-click mech randomizer expanded from random(0,3) to random(0,5) to
  include Archer and Warhammer in the pool

Changelog entries for Cyd (06/24/26), MCHL (06/27/26), and RT (07/19/26)
added to the script header.

Co-authored-by: Claude Sonnet 4.6 (Anthropic) <noreply@anthropic.com>
Co-authored-by: GitHub Copilot <copilot@github.com>
2026-07-19 17:19:08 -05:00
dicion 24825ff396 more ddraw handling fixes for profiler. ugh. 2026-07-19 16:41:45 -05:00
dicion 0ceba9c778 ddraw.dll breaking mw4pro windowed mode 2026-07-19 16:28:51 -05:00
55b9bfc521 Add sync-to-windows.sh: rsync script for Linux→Windows build machine
Syncs all source, content, toolchain, and assets needed to build and test the game on the Windows machine at /vwe/firestorm. Excludes generated build outputs (bin dirs, *.mw4, *.dep), .git/LFS, _UNUSED, and the MW4 deploy dir.

Co-authored-by: Claude Sonnet 4.6 (Anthropic) <noreply@anthropic.com>
Co-authored-by: GitHub Copilot <copilot@github.com>
2026-07-19 15:40:24 -05:00
190 changed files with 1496 additions and 446 deletions
Binary file not shown.
Binary file not shown.
+360
View File
@@ -292,3 +292,363 @@ At the time this doc was written:
- non-playable mechs are explicitly marked `No`
- Templar and other mechs with rear or side mounts have facing visible in the CSV
- the file is intended to be a living audit artifact for future data cleanup and enablement work
---
## MechEditor Web App — Data Sources, Fields, and Conversions (documented 2026-07-23)
The MechEditor is a single-file Python HTTP server at `/home/rich/Repositories/MechEditor/mech_editor.py`.
It runs at `localhost:8765`, parses the firestorm content tree, and presents a full mech configuration editor in the browser.
This section documents every data field it reads, every conversion it performs, and every naming rule it enforces.
---
### Data Files Parsed Per Mech
All files live under `Gameleap/mw4/Content/Mechs/<MechDir>/`.
#### `.data` file (`parse_data()`)
| Field in file | Editor key | Notes |
|---|---|---|
| `VehicleTonnage` | `tonnage` | chassis base tonnage (float) |
| `MaxVehicleTonnage` | `max_tonnage` | max loadout tonnage (float) |
| `TechType` | `tech` | `$(Tech_IS)` ? `"IS"`, `$(Tech_Clan)` ? `"Clan"` |
| `MaxHeat` | `max_heat` | heat capacity (int) |
| `VehicleTradeValue` | `trade_value` | C-bills |
| `DragoonValue` | `dragoon` | used in Power Rating bar scaling |
| `MinMaxSpeed` | `min_max_speed` | base speed ceiling in **m/s** |
| `MaxSpeed` | `max_speed` | absolute speed ceiling in **m/s** (engine upgrades may not exceed this) |
| `FullStopTurnRate` | `full_stop_turn` | turn rate at zero speed, in **degrees/sec** |
| `TopSpeedTurnRate` | `top_speed_turn` | turn rate at top speed, in **degrees/sec** |
| `Acceleration` | `acceleration` | forward acceleration in **m/s²** |
| `Decceleration` | `decceleration` | forward braking in **m/s²****double-c spelling is canonical in the engine source** |
| `ReverseAccelerationMultiplier` | `rev_accel_mult` | multiplier applied to Acceleration for reverse |
| `ReverseDeccelerationMultiplier` | `rev_decel_mult` | multiplier applied to Decceleration for reverse — double-c canonical |
| `MinStandTransitionSpeed` | not surfaced | animation threshold only — see note below |
| `CanLoadJumpJets` | `can_jj` | Yes/No |
| `CanLoadECM` | `can_ecm` | Yes/No |
| `CanLoadBeagle` | `can_bap` | Yes/No |
| `CanLoadLightAmp` | `can_lightamp` | Yes/No |
| `CanLoadAMS` | `can_ams` | Yes/No |
| `CanLoadLAMS` | `can_lams` | Yes/No |
| `CanLoadIFF_Jammer` | `can_iff` | Yes/No |
**MinStandTransitionSpeed** is the speed (m/s) below which the mech switches from its walking animation to its idle/standing animation.
It is NOT a hard movement limit. It is purely an animation state machine threshold in `Mech.cpp`.
Code path: `animStateEngine?RequestState(StandState)` when `currentSpeedMPS <= minStandTransitionSpeed`.
Must be > 0 (validated in `Vehicle_Tool.cpp`). Argus = 12.631 m/s = 45.5 kph.
#### `.instance` file (`parse_instance()`)
| Field | Editor key | Notes |
|---|---|---|
| `PowerRating` | `PowerRating` | mechlab bar value, 0100 |
| `ArmorRating` | `ArmorRating` | mechlab bar value, 0100 |
| `SpeedRating` | `SpeedRating` | mechlab bar value, 0100 |
| `HeatRating` | `HeatRating` | mechlab bar value, 0100 |
| `DoesHaveLightAmp` | `has_lightamp` | 0 or 1, default 1 — whether LightAmp is currently installed |
#### `.subsystems` file (`parse_subsystems()`)
Provides: armor type + per-zone multipliers, installed heatsinks, jump jets, engine upgrades, weapons, electronics.
**Armor block:**
- `ArmorType=` ? armor type string (`Standard`, `FerroFiberus`, `Reactive`, `Reflective`, `Solarian`)
- Per-zone entries: `LeftArm=1.0`, `RightTorso=2.5`, etc. — multiplier for that zone
**Engine:**
- `EngineUpgrade` blocks counted ? `engine_upgrades` (05)
**Weapons** — each weapon block contains:
- `Model=` ? weapon subsystem resource path (name extracted)
- `InternalLocation=` ? zone name
- `Site=` ? mount port name (from armature)
- `GroupIndex=` ? weapon group number
- `WeaponFacing=` ? 0=Front, 1=Rear, 2=Side (absent = Front)
- `AmmoCount=` ? rounds for ammo-using weapons
- `EjectSite=` ? optional ejection site for ammo
**Electronics:** ECM, Beagle (BAP), AMS, LAMS, IFF_Jammer detected by subsystem model path.
#### `.damage` file (`parse_damage()`)
Per zone section `[ZoneInternal]`:
- `BaseArmorValue` ? starting armor (float)
- `MaxArmorValue` ? hard cap on armor pts for that zone
- `InternalHPValue` ? internal structure HP
- `OmniSlots`, `BeamSlots`, `MissileSlots`, `ProjectileSlots` ? weapon slot counts
Special zones:
- `SpecialAttachedToZone=` ? which body section this special zone is attached to
- `DamagePropagationZone=` ? where overflow damage propagates
#### `.engine` file (`parse_engine()`)
| Field | Editor key | Notes |
|---|---|---|
| `NumHeatSinks` | `NumHeatSinks` | free heatsinks from engine (not in subsystems) |
| `TonsPerUpgrade` | `TonsPerUpgrade` | tonnage cost per engine upgrade tier |
| `MPSPerUpgrade` | `MPSPerUpgrade` | m/s speed gain per upgrade tier |
#### `.torso` file (`parse_torso()`)
| Field | Notes |
|---|---|
| `TwistSpeed` | torso horizontal rotation speed — may be a macro reference |
| `PitchSpeed` | torso vertical rotation speed — may be a macro reference |
| `TwistRadius` | max horizontal twist angle — may be a macro reference |
| `PitchRadius` | max vertical pitch angle — may be a macro reference |
| `ArmRatioAngle` | ratio of arm tracking vs torso rotation — may be a macro reference |
All torso fields may reference macros from `Content/Defines/MechTorso.defines`.
The editor resolves them using a preloaded `TORSO_DEFINES` dict. Notable values:
```
NORMAL_RATIO = 40
SNAIL_TSPEED = 40
NORMAL_TSPEED = 60
FAST_TSPEED = 80
WIDE_TRADIUS = 160
NORMAL_PRADIUS = 40
```
---
### Calculated Ratings and Conversions
#### Speed (kph)
```
top_speed_kph = min(MinMaxSpeed + MPSPerUpgrade × engine_upgrades, MaxSpeed) × 3.6
```
- `MinMaxSpeed` and `MaxSpeed` from `.data` (m/s)
- `MPSPerUpgrade` from `.engine` (m/s per tier)
- `engine_upgrades` from `.subsystems` (05)
- Multiply by 3.6 to convert m/s ? kph
- Argus example: (20.28 + 1.11 × 10) × 3.6 = 113.5 kph
#### Speed Rating (bar)
```
speed_rating = (top_speed_mps / MaxSpeed) × 100 [capped at 100]
```
#### Turn Rate — degrees to radians
The `.data` file stores turn rates in **degrees/sec**. The mechlab UI label was changed to show rad/sec:
- `StringResource.rc`: `IDS_ML_CH_TURNRATE` ? `"Turn Rate (Top Speed Rad/Sec):"`
- Conversion: `radians = degrees × ?/180` where `?/180 ? 0.017453`
- Argus: FullStopTurn = 75° = **1.309 rad/sec**, TopSpeedTurn = 45° = **0.785 rad/sec**
#### Acceleration / Deceleration (m/s²)
Stored directly in `.data`. Reverse values are derived:
```
reverse_accel = Acceleration × ReverseAccelerationMultiplier
reverse_decel = Decceleration × ReverseDeccelerationMultiplier
```
**The double-c spelling (`Decceleration`, `ReverseDeccelerationMultiplier`) is canonical — it matches the engine source. Do not "fix" the spelling.**
#### Heat Rating (bar)
```
total_hs = NumHeatSinks (engine) + installed_heatsinks (subsystems)
effective_hs = total_hs × (2 if Double else 1)
heat_rating = (effective_hs / MaxHeat) × 100 [capped at 100]
```
#### Power Rating (bar)
```
total_damage = ? (DamageAmount × NumFire) for each installed weapon
power_rating = (total_damage / 80) × 100 [capped at 100]
```
- `DamageAmount` and `NumFire` come from `WeaponSubsystems/<weapon>.data` following `!include` chains
- Parsed by `load_weapon_damages()` at server startup, cached in `Handler.weapon_damages`
- Argus example with default load: ~36.2 total damage ? 45 rating (stored = 42)
#### Armor Rating (bar)
```
for each zone:
pts = multiplier × ARMOR_PTS_PER_TON[armor_type]
effective = min(pts, MaxArmorValue[zone])
armor_rating = (? effective / ? MaxArmorValue) × 100
```
Armor pts per ton by type (from `Adept/ResourceImagePool.cpp` and game design):
| Type | Pts/ton |
|---|---|
| Standard | 32 |
| FerroFiberus | 38 |
| Reactive | 30 |
| Reflective | 30 |
| Solarian | 60 |
Note: `FerroFiberus` is the canonical internal token (not player-visible). The player sees `DNL_FERROFIB = "Ferro Fibrous"` via string lookup.
---
### Active-in-Game Detection
Source: `Gameleap/mw4/Content/Tables/MechChassisTable.tbl`
Format:
```
DisplayKey=Mechs\DirName\FileName.data
//CommentedKey=Mechs\DirName\FileName.data <- inactive
```
- Active = entry exists AND is not prefixed with `//`
- Currently the only inactive mech: **Dasher** (commented out)
- The editor shows a green **ACTIVE IN GAME** or red **NOT IN GAME** banner at top of Stats tab
---
### hsh/ Image Naming Conventions
The `hsh/` directory under `Gameleap/mw4/` holds loose BMP files loaded at runtime (not packed into `.mw4`).
There are four relevant subdirectories, each with a different naming authority.
#### `hsh/hud/` — in-game HUD damage silhouette (own mech)
#### `hsh/MFD/` — MFD target display silhouette (target mech)
#### `hsh/radar/hud/` — radar damage overlay
**All three use identical stems** sourced from `huddamage.cpp` `texturename[]` array.
Load path:
- hud/MFD: `hsh\<texturename>.bmp` where texturename = `hud\<stem>` ? file = `hsh/hud/<stem>.bmp`
- radar: `hsh\radar\<texturename>.bmp` ? file = `hsh/radar/hud/<stem>.bmp`
Code: `render.cpp` `CRadar_Device::LoadRadarDamageTexture()` and `huddamage.cpp` `HUDDamage`.
#### `hsh/Mechs/` — mw4print scorecard portrait
Load path: `recscore.cpp` ? `GetLocString(model->m_nameIndex)` ? `DNL_*` string from `StringResource.rc` ? lowercased filename.
Different naming authority from the other three.
---
### Complete Canonical Name Table
Key: mech directory name (case-insensitive) ? canonical stem for `hsh/hud/`, `hsh/MFD/`, `hsh/radar/hud/`.
Entries in **bold** differ from the directory name.
| Directory | hud/MFD/radar stem | hsh/Mechs/ portrait filename |
|---|---|---|
| Annihilator | annihilator | annihilator.bmp |
| Archer | archer | archer.bmp |
| ArcticWolf | arcticwolf | arctic wolf.bmp |
| Ares | ares | ares.bmp |
| Argus | argus | argus.bmp |
| Assassin2 | assassin2 | **assassin ii.bmp** |
| Atlas | atlas | atlas.bmp |
| Avatar | avatar | avatar.bmp |
| Awesome | awesome | awesome.bmp |
| Battlemaster | battlemaster | battlemaster.bmp |
| Battlemaster2c | **battlemasteriic** | **battlemaster iic.bmp** |
| Behemoth | behemoth | behemoth.bmp |
| Behemoth2 | **behemothii** | **behemoth ii.bmp** |
| Blackhawk | blackhawk | black hawk.bmp |
| Blacknight | **blackknight** | black knight.bmp |
| Blacklanner | blacklanner | black lanner.bmp |
| Brigand | brigand | brigand.bmp |
| Bushwacker | bushwacker | bushwacker.bmp |
| Catapult | catapult | catapult.bmp |
| CauldronBorn | cauldronborn | **cauldronborn.bmp** (table key has hyphen; DNL does not) |
| Chimera | chimera | chimera.bmp |
| Commando | commando | commando.bmp |
| Cougar | cougar | cougar.bmp |
| Cyclops | cyclops | cyclops.bmp |
| Daishi | daishi | daishi.bmp |
| Deimos | deimos | deimos.bmp |
| Dragon | dragon | dragon.bmp |
| Fafnir | fafnir | fafnir.bmp |
| Flea | flea | flea.bmp |
| Gladiator | gladiator | gladiator.bmp |
| Grizzly | grizzly | grizzly.bmp |
| Hauptmann | hauptmann | hauptmann.bmp |
| Hellhound | hellhound | hellhound.bmp |
| Hellspawn | hellspawn | hellspawn.bmp |
| Highlander | highlander | highlander.bmp |
| Hollander | **hollanderii** | **hollander ii.bmp** |
| Hunchback | hunchback | hunchback.bmp |
| Kodiak | kodiak | kodiak.bmp |
| Loki | loki | loki.bmp |
| Longbow | longbow | longbow.bmp |
| Madcat | madcat | mad cat.bmp |
| Madcat_MKII | **madcat2** | mad cat mkii.bmp |
| Masakari | masakari | masakari.bmp |
| Mauler | mauler | mauler.bmp |
| Novacat | novacat | nova cat.bmp |
| Osiris | osiris | osiris.bmp |
| Owens | owens | owens.bmp |
| Puma | puma | puma.bmp |
| Raven | raven | raven.bmp |
| Rifleman | rifleman | rifleman.bmp |
| Ryoken | ryoken | ryoken.bmp |
| Shadowcat | shadowcat | shadow cat.bmp |
| Solitaire | solitaire | solitaire.bmp |
| Sunder | sunder | sunder.bmp |
| Templar | templar | templar.bmp |
| Thanatos | thanatos | thanatos.bmp |
| Thor | thor | thor.bmp |
| Uller | uller | uller.bmp |
| Urbanmech | urbanmech | urbanmech.bmp |
| Uziel | uziel | uziel.bmp |
| Victor | victor | victor.bmp |
| Vulture | vulture | vulture.bmp |
| Warhammer | warhammer | warhammer.bmp |
| Wolfhound | wolfhound | wolfhound.bmp |
| Zeus | zeus | zeus.bmp |
**Critical mismatches where directory name ? hud/MFD stem (files must use the stem, not the dir name):**
| Directory | Wrong name (dir-based) | Correct name (stem) |
|---|---|---|
| Battlemaster2c | battlemaster2c.bmp | **battlemasteriic.bmp** |
| Behemoth2 | behemoth2.bmp | **behemothii.bmp** |
| Blacknight | blacknight.bmp | **blackknight.bmp** |
| Hollander | hollander.bmp | **hollanderii.bmp** |
| Madcat_MKII | madcat_mkii.bmp | **madcat2.bmp** |
**Portrait mismatches for hsh/Mechs/ (table key ? DNL string):**
The `MechChassisTable.tbl` display key and `GetLocString()` DNL string differ for these mechs.
mw4print uses the DNL string. The table key is NOT the correct portrait filename for these 5 mechs.
| Directory | Table key (wrong for mw4print) | DNL string (correct portrait stem) |
|---|---|---|
| Assassin2 | AssassinII ? assassinii | `DNL_ASSASSIN2 "Assassin II"` ? **assassin ii.bmp** |
| Battlemaster2c | BattlemasterIIC ? battlemasteriic | `DNL_BATTLEMASTERIIC "Battlemaster IIc"` ? **battlemaster iic.bmp** |
| Behemoth2 | BehemothII ? behemothii | `DNL_BEHEMOTHII "Behemoth II"` ? **behemoth ii.bmp** |
| CauldronBorn | Cauldron-Born ? cauldron-born | `DNL_CAULDRONBORN "Cauldronborn"` ? **cauldronborn.bmp** |
| Hollander | HollanderII ? hollanderii | `DNL_HOLLANDERII "Hollander II"` ? **hollander ii.bmp** |
---
### MechEditor Implementation Notes
The editor encodes all of the above knowledge in two Python dicts:
**`MECH_HSH_STEMS`** (in `mech_editor.py`)
Maps lowercase dir name ? canonical stem for `hsh/hud/`, `hsh/MFD/`, `hsh/radar/hud/`.
Source: `huddamage.cpp` `texturename[]` array.
**`MECH_PORTRAIT_OVERRIDES`** (in `mech_editor.py`)
Maps lowercase dir name ? portrait stem for `hsh/Mechs/` where the DNL string differs from the chassis table key.
Source: `DNL_*` entries in `Gameleap/code/mw4/Code/scriptstrings/StringResource.rc`.
For all other mechs, the portrait stem is derived dynamically from `MechChassisTable.tbl` (display key, lowercased).
The Assets tab in the editor shows all four image types. When an image is missing, it displays:
```
Wants: hsh/<subdir>/<expected_filename>.bmp
```
so the user knows exactly what to rename or create.
+112
View File
@@ -795,6 +795,118 @@ keeping old-RIO (type 0) protocol behavior byte-identical:
alongside `mw4print.exe`.
- Version bumped to **2.0**, copyright year updated to **2026**.
## 📋 MFD mode 4: right device stagger fix (2026-07-18, eaa5fd3)
Root cause: `CMFD_Device::BeginScene()` cleared BOTH MFD device back-buffers at `sh_step==0`.
But in mode 4 the right MFD flip also fires at `sh_step==1` (= old `sh_step==0` after the
stagger increment), so it presented a just-cleared buffer — only the grid, no channel data.
Fix: `BeginScene()` now only clears/grids the LEFT device at `sh_step==0`. New `BeginSceneRight()`
(added to `render.cpp` / `render.hpp`, called from `WinMain.cpp`) clears/grids the RIGHT device at
`sh_step==1` — one frame AFTER the right flip — so channels 34 render into a fresh buffer before
the next flip. Mode 1 is unchanged.
Mode 4 cycle (with stagger):
- `sh_step 0`: radar + left `BeginScene` (clear + grid); no flip
- `sh_step 1`: flip right MFD (shows channels 34 from previous cycle) + right `BeginScene` (clear + grid)
- `sh_step 24`: channels 02 → left device
- `sh_step 56`: channels 34 → right device
- `sh_step 0` (next): flip radar + left MFD (shows channels 02 from previous cycle)
Files: `CoreTech/Libraries/GameOS/WinMain.cpp`, `render.cpp`, `render.hpp`.
## 📋 Linux→Windows development workflow (2026-07-19, 55b9bfc5)
`build-env/sync-to-windows.sh` — rsync script that pushes all source, content, toolchain, and
assets to the Windows build machine at `/vwe/firestorm`. Excludes generated build outputs
(`rel.bin/`, `dbg.bin/`, `*.mw4`, `*.dep`), `.git`/LFS objects, `_UNUSED/`, and the game deploy
dir (`MW4/`). Run from Linux before triggering a Windows build.
## 📋 ddraw.dll removed from repo; build script moves it aside (2026-07-19, 0ceba9c7, 24825ff3)
`Gameleap/mw4/ddraw.dll` (DDrawCompat) removed from git (was LFS-tracked); now lives as
`ddraw.dll.old` in the same dir for reference. `deploy-editor.ps1` installs DDrawCompat as
`ddraw.dll` at deploy time (the editor needs it for its windowed D3D7 viewport).
`build-resources.ps1` moves `ddraw.dll` aside (`.buildaside`) before running `MW4pro.exe`
because **DDrawCompat is fatal to MW4pro.exe in BOTH windowed and fullscreen modes**, then
restores it in `finally`. The same block also defensively covers dgVoodoo2 interceptors
(`D3D8/D3D9/D3DImm.dll`) in case they reappear.
## 📋 Branch `5.1.0b-in-progress`: multiplayer + RIO + source cleanup (2026-07-19)
### ConLobby V5.1.0b1 — Super6 mech rotation (c768f7c4)
Changes from Buddy 'Highlight' Taylor (MCHL), merged manually:
- Console version string bumped to **V5.1.0b1**.
- `ROOKIEMECH` defines expanded from 4 → **6 mechs**: added Archer (ID=1) and Warhammer (ID=62).
- 16-slot default assignments cycle through all 6 Super6 mechs.
- Right-click randomizer expanded from `random(0,3)``random(0,5)`.
### CRIOMAIN.CPP — Korean translation + RIO poll timeout scaling (16fca6c4, a712002f)
- Translated all EUC-KR/CP949 Korean developer comments (~35 lines) to English. File re-saved
as clean UTF-8. CRLF line endings preserved (`* -text` in `.gitattributes`).
⚠️ **Encoding hazard:** always read/write CRIOMAIN.CPP as binary (or with an explicit encoding
codec). Python text-mode `readlines()` silently strips `\r`, causing a 3000+-line git diff when
every line's `\r\n` becomes `\n`. If that happens, restore CRLF with `re.sub(b'(?<!\r)\n', b'\r\n', data)` in binary mode, then amend the commit.
- Added **`g_dwRIOPollTimeout`** global (default 50 ms). Computed in `SetupConnection` before the
receive loop using: `clamp(⌈480000/baud⌉, 5, 50)`. Preserves 50 ms at 9600 baud; floors at
5 ms for 115200 baud. Implemented with explicit ternary — **`min`/`max` are undeclared in this
translation unit under VC6** (not pulled in by CRIOMAIN's includes); use ternary or `__min`/`__max`.
### 16 pilots + 1 cameraship in multiplayer (f76dc05f)
`MW4Shell.cpp`:
- `CTCL_DefaultHostSetup` (non-coop): `Environment.NetworkMaxPlayers` set to
`params->m_maxPlayers + (CTCL_GetTeslaCountAll() - CTCL_GetTeslaCount())`.
The delta = camera-only seats (Tesla seats not assigned to pilots), reserving one extra
DirectPlay slot per cameraship so the 17th connection isn't rejected.
- `SetNetworkMissionParamater / PLAYER_LIMIT_PARAMETER`: same formula applied at runtime when
host changes the player limit. `gos_NetServerCommands(gos_Commend_UpdateMaxPlayers)` still called;
`break` must be present in this case (was accidentally dropped once — fall-through to
`JOIN_IN_PROGRESS_PARAMETER` corrupts `m_joinInProgress`).
- COOP branch unchanged (capped at 9+bots; no camera seat needed there).
`ConLobby.script`: launch guard `nTempPlayerCount > 16` raised to `> 17` so the cameraship
connection doesn't trigger "Too many player/bots".
### hsh/ BMP canonical renames (5813aeb6, 2026-07-23)
All `hsh/MFD/*.bmp` and `hsh/Mechs/*.bmp` filenames reconciled against the canonical stems
expected by game code. The engine loads MFD images via `huddamage.cpp` `texturename[]` array
(lowercase, no spaces) and Mechs portraits via `GetLocString` DNL strings (mixed-case with
spaces). Any mismatch = silently missing image at runtime.
Key renames:
- `hsh/MFD/assassinii.bmp``assassin2.bmp` (matches `texturename[]` canonical)
- `hsh/Mechs/battlemasteriic.bmp``battlemaster iic.bmp`
- `hsh/Mechs/mad cat mk.ii.bmp``mad cat mkii.bmp`
- `hsh/Mechs/behemoth ii.bmp` added (was absent)
Most other files in both directories are LFS pointer updates only (content unchanged).
### RookieMission configurable defaults via options.ini (5813aeb6, 2026-07-23)
CTCL (console) arcade mode has a "Rookie Mission" quick-launch that previously hardcoded all
game params. Now all 13 params are overridable from an `[RookieMission]` section in
`options.ini` (read by `CTCL_SetCDSP` at startup):
- `MW4Shell.cpp`: added 14 `g_` globals (`g_szRookieMission`, `g_nRookieGameType`, and 12
numeric params); registered as `gosScript_RegisterVariable` in `StartUp`/`ShutDown`;
`CTCL_SetCDSP` reads the `[RookieMission]` page via `NotationFile` and populates them.
Defaults: `"ScarabStronghold - Attrition"`, GameType=2 (Attrition), UnlimitedAmmo=1, all
others zero. `g_nRookieTimeLimit=-1` means "use the server's current time setting".
- `ConLobbyMission.script`: all hardcoded values in `MAIL_SET_ROOKIE_MISSION` handler replaced
with `$$g_szRookieMission$$` / `$$g_nRookieXxx$$` references.
- Requires rebuild: `MW4.exe` (Release + Profile).
### Mechlab turn rate label (5813aeb6, 2026-07-23)
`StringResource.rc` `IDS_ML_CH_TURNRATE`: "Turn Rate (Degrees/Sec.):" →
"Turn Rate (Top Speed Rad/Sec):" to match the actual `.data` field semantics
(`TopSpeedTurnRate` is in rad/s at top speed, not deg/s).
Requires rebuild: `ScriptStrings.dll`.
### BTFrstrm design documentation (840bc96c, 2026-07-23)
Two Word documents added to `BTFrstrm/`:
- `MechDependencyTree.docx` — dependency relationships between mech chassis/variants.
- `Special_Zones.docx` — documentation of special zone types used in maps/missions.
### mech_loadouts.md: MechEditor data model (0344418a, 2026-07-23)
`BTFrstrm/mech_loadouts.md` extended with a full reference section documenting the
MechEditor web app (`/home/rich/Repositories/MechEditor/mech_editor.py`, localhost:8765):
every `.data`/`.instance`/`.subsystems` field parsed, conversions performed (m/s ↔ kph,
rad/s ↔ deg/s), and `hsh/` naming rules for MFD/Mechs/HUD/Radar images. Canonical
reference for future mech data work.
## Next steps (proposed)
- [x] ~~Windowed 3D viewport on Win11~~ — DONE via DDrawCompat (see STEP 8 viewport section).
- [ ] (Optional) Curate remaining WIP content as features are exercised (editor loads dev `Content\`).
+2 -2
View File
@@ -9,7 +9,7 @@
#include "recscore.h"
#endif // !defined(CTCLS_EXPORTS) && !defined(CTCL_LAUNCHER)
#define MAX_TESLAS 31
#define MAX_TESLAS 16
#define MAX_CAMERAS 4
#define PORT_Launcher 1000
@@ -260,7 +260,7 @@ CInviteCOOP g_InviteCOOP;
// Mech4 only
int g_nMech4Comm = 0;
BOOL g_bIsServer = FALSE;
SPlayerInfo g_aPlayerInfos[35]; // 31 pilots + 1 CS + 3 spare
SPlayerInfo g_aPlayerInfos[20];
int g_nPlayerInfos;
int g_nServer;
int g_nTeslas;
+55 -42
View File
@@ -43,7 +43,7 @@ LONG g_LeftPedalLast = 0;
LONG g_RightPedalLast = 0;
BOOL g_StartGame = FALSE;
static int g_nOpenComState = 0; //
static int g_nOpenComState = 0; // hyun
DWORD g_dwLastAnalogUpdate = 0;
@@ -54,7 +54,7 @@ DWORD g_dwLastAnalogUpdate = 0;
#define RESTART_CHAR 0xFE
#define IDLE_CHAR 0xFF
//member 변수처럼 활용할것.
//Use it like a member variable.
static HANDLE g_hCom = INVALID_HANDLE_VALUE;
static OVERLAPPED wos;
static OVERLAPPED ros;
@@ -108,6 +108,7 @@ int g_nRIOPacketCountB = (sizeof(g_baRIOLengthsB) / sizeof(g_baRIOLengthsB[0]));
int g_nRIOType = 0; // 0: old(original) type, 1: new type
DWORD g_dwRIOBaud = 0; // [tbaud] 0: default by RIO type; else COM1 baud forced by -tbaud (high-speed replica of the original RIO board, protocol unchanged)
DWORD g_dwRIOPollTimeout = 50; // [tbaud] WaitForMultipleObjects timeout (ms); computed from baud rate before the receive loop starts
int g_nEjectButton = 61; // 61: original, 31: new type
BYTE* g_pbRIOLengths = NULL;
int g_nRIOPacketCount = 0;
@@ -318,7 +319,7 @@ void RequestVersion();
void RequestAnalogUpdate(BYTE bFreq = 3);
// start - for new RIO Board only...
//received packet은 각각 다른 스레드에서 처리하므로.. ciritical section이 필요하다..
//Received packets are handled in different threads.. a critical section is needed..
BYTE received_buffer[128][16];
int received_packet=0;//packets count in the received_buffer.
DWORD received_serial=0;
@@ -569,7 +570,7 @@ BOOL SetupConnection(HANDLE hCom)
return TRUE;
/*
원래 처리 루틴..
Original processing routine..
NPTTYINFO npTTYInfo=0 ;
BYTE bset1 = (BYTE) ((FLOWCTRL( npTTYInfo ) & FC_DTRDSR) != 0) ;
BYTE bset2 = (BYTE) ((FLOWCTRL( npTTYInfo ) & FC_RTSCTS) != 0) ;
@@ -603,7 +604,7 @@ BOOL SetupConnection(HANDLE hCom)
//처리되지 않는 항목들.. GetCommState의 기본값으로 처리한다.
//Unhandled items.. handled using GetCommState default values.
DWORD fDsrSensitivity:1; // DSR sensitivity
DWORD fTXContinueOnXoff:1; // XOFF continues Tx
DWORD fErrorChar: 1; // enable error replacement
@@ -647,7 +648,7 @@ HANDLE OpenConnection(int port)
g_hLampEvent = CreateEvent(0,FALSE,0,0);
g_hCommWatchThread = CreateThread((LPSECURITY_ATTRIBUTES)NULL, 0, (LPTHREAD_START_ROUTINE)CommWatchProc, NULL, CREATE_SUSPENDED, &g_dwThreadID);
if (g_hCommWatchThread) {
//Thread까지 정상적으로 생성되었다.
//Thread was created successfully.
//////////////////////////////////////////////
//All OK
//Exit Point <======
@@ -744,11 +745,11 @@ retry:
for(int i=0;i<(int)dwLength;i++){
int ch=(BYTE)lpszBlock[i];
//받은 문자만큼 루프를 돈다.
//현재.. 받고 있는 packet이 없고.. 어떤 control문자라도 올 수 있는 상태이다.
//Loop for the number of received characters.
//Currently.. no packet is being received.. can receive any control character.
if(packetbyteremain!=0){
//패킷에 해당하는 문자가 도착했다.. 나머지 문자들을 받는다.
//Character corresponding to a packet has arrived.. receive the remaining characters.
if (ch & 0x80) {
packetbyteremain=0;
chinpacket=0;
@@ -758,7 +759,7 @@ retry:
packetbytes[chinpacket] = ch;
chinpacket++;
if (packetbyteremain == 0) {
//하나의 패킷이 완성되었다. 도착했다.. 즉시 반응한다.
//A packet has been completed and arrived.. respond immediately.
chinpacket--; // exclude check byte
int packettype=packetbytes[0];
BYTE bCheckByte = 0;
@@ -837,21 +838,21 @@ retry:
packettype++;
packettype--;
#endif // _DEBUG
case rio_Ack2://◆◆◆◆◆◆◆◆◆◆
case rio_Ack2:
if (g_nRIOType != 0) {
BYTE id=packetbytes[1];
int popped_index=PopPacket(id);
ack_timeout=GetTickCount()+30;
if(popped_index==0){
//맨처음것... 정상적인 경우이다.
//This is the very first one... Normal case.
}else if(popped_index>0){
//맨처음것이 아닌것.
//이전것들이 정상적으로 보내지지 않았으므로 다시 보낸다...
ReSendPackets(popped_index);//잘못된 개수 만큼..
//Not the very first one.
//Previous ones were not sent successfully, resend...
ReSendPackets(popped_index);//By the number of incorrect ones..
}else{
//실패 했다는것은.. 없는 id가 왔다는 것인데..
//명백한 에러.. 그러나 특별히 대처할 방법은 없다.
//그냥 무시한다.
//Failure means an id that does not exist arrived..
//An obvious error.. but there is no particular way to handle it.
//Simply ignore it.
}
}
break;
@@ -870,9 +871,9 @@ retry:
// WriteTTYBlock(hWnd,"|",1);
chinpacket=0;
//packetbytes버퍼를 지운다.
//Clear the packetbytes buffer.
} else {
//아직 패킷 문자들이 다 도착하지 않았다.. 아무것도 하지 않는다.
//Packet characters have not all arrived yet.. do nothing.
;
}
}else{
@@ -889,7 +890,7 @@ retry:
}//for(int i=0;i<(int)dwLength;i++)
//상훈 뒤
//sanghoon end
if (!fReadStat){
if (GetLastError() == ERROR_IO_PENDING){
while(!GetOverlappedResult( g_hCom,&ros, &dwLength, TRUE )){
@@ -1000,12 +1001,24 @@ DWORD FAR PASCAL CommWatchProc( LPSTR lpData )
}
g_dwLastAnalogUpdate = GetTickCount() + 2800;
// [tbaud] Scale the poll timeout proportionally to baud rate so faster links
// poll more frequently. Formula: clamp(ceil(480000/baud), 5, 50)
// preserves the existing 50ms at 9600 baud, floors at 5ms for high speeds.
// effectiveBaud: use -tbaud override if set, else the RIO type's default.
{
DWORD effectiveBaud = (g_dwRIOBaud != 0) ? g_dwRIOBaud
: ((g_nRIOType == 0) ? 9600UL : 115200UL);
{
DWORD t = (480000UL + effectiveBaud - 1) / effectiveBaud;
g_dwRIOPollTimeout = (t < 5UL) ? 5UL : (t > 50UL ? 50UL : t);
}
}
while(1) {
DWORD dwEvtMask = 0;
WaitCommEvent( g_hCom, &dwEvtMask,&wcos );
DWORD ret=WaitForMultipleObjects(3,events,FALSE,50/*INFINITE*/);
DWORD ret=WaitForMultipleObjects(3,events,FALSE,g_dwRIOPollTimeout);
if(ret==WAIT_OBJECT_0){
//An Comm Event has arrived.
DWORD bytesread;
@@ -1022,10 +1035,10 @@ DWORD FAR PASCAL CommWatchProc( LPSTR lpData )
}
} else {*/
if (g_nRIOType != 0) {
///◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆위의 ReadCommBlock에서 ack를 받았을 경우 duetime을 update시킨다.
///◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆CheckSentBuffer...
///When ack is received from ReadCommBlock above, update duetime.
///CheckSentBuffer...
if(GetTickCount()>ack_timeout)
ReSendPackets(sent_packet);//sent_buffer에 있는 모든것들을 다시 보내본다.
ReSendPackets(sent_packet);//Resend everything in sent_buffer.
}
/*}*/
}else if(ret==WAIT_OBJECT_0+1){
@@ -1039,9 +1052,9 @@ DWORD FAR PASCAL CommWatchProc( LPSTR lpData )
//break;
}else if (ret==WAIT_TIMEOUT) {
if (g_nRIOType != 0) {
///◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆CheckSentBuffer...
///CheckSentBuffer...
if(GetTickCount()>ack_timeout)
ReSendPackets(sent_packet);//sent_buffer에 있는 모든것들을 다시 보내본다.
ReSendPackets(sent_packet);//Resend everything in sent_buffer.
}
if (packetbyteremain == 0) {
RequestAnalogUpdate();
@@ -1236,8 +1249,8 @@ bool SaveReceivedPacket(const BYTE*ba,int length)
bool GetSerialFromReceivedBuffer(char * ba)
{
//ButtonPressed/Released만 저장해 놓는다..
//모든 serial packet을 옮긴다.
//Store only ButtonPressed/Released..
//Transfer all serial packets.
if(received_packet>0){
if(received_buffer[0][2]==received_serial){
CopyMemory(ba,received_buffer[0],16);
@@ -1264,7 +1277,7 @@ bool QueuePacket(const BYTE *ba,int length)
int PopPacket(BYTE id)
{
//lamp.. id..
//lamp.. check by id..
//search the packet..
for(int i=0;i<sent_packet;i++){
if(sent_buffer[i][3]==id){
@@ -1427,7 +1440,7 @@ void CBUTTON_GROUP::SetTable(BOOL bFlag/* = true*/)
for (int b = 0; b < MAXBUTTON_TABLE; b++) {
s_aCtrlLamp[b] = s_aSaveLamp[b];// = s_aButtonTable[b].lamp;
// s_aButtonTable는 Old값이므로 초기치는 Off
// s_aButtonTable is the old value, so the initial value is Off
s_aButtonTable[b].lamp = LAMP_OFF;
}
@@ -1439,7 +1452,7 @@ void CBUTTON_GROUP::SetTable(BOOL bFlag/* = true*/)
}
else
{
// 모든 테이블을 원래 상태로
// Restore all tables to original state
for (int b = 0; b < MAXBUTTON_TABLE; b++) {
s_aCtrlLamp[b] = s_aSaveLamp[b];
}
@@ -1534,7 +1547,7 @@ void CBUTTON_GROUP::ResetTable(BOOL bFlag/* = true*/)
}
else
{
// 모든 테이블을 Off
// Turn off all tables
for (int b = 0; b < MAXBUTTON_TABLE; b++) {
switch(b)
{
@@ -2212,13 +2225,13 @@ void CRIOMAIN::UpdatePadal (DIJOYSTATE &js)
Down Up
======================
(+) (-)
<-- (+) (-) -->
======================
/^
g_LeftPedalStart: INT_MAX (+)
lP = (LONG)g_LeftPedalStart - g_LeftPedal;
lP 결과값은 무조건 음수
lP result value is always negative
*/
LONG lP = 0;
@@ -2362,9 +2375,9 @@ void CRIOMAIN::UpdateThrottle (DIJOYSTATE &js)
Up Down
======================
(-) (+)
<-- (-) (+) -->
======================
/^
g_ThrottleStart: INT_MIN (-)
*/
@@ -2447,11 +2460,11 @@ void CRIOMAIN::UpdateJoystick (DIJOYSTATE &js)
*/
//////////////////////////////////////////////////////////////////////////////////
/*
80 의 의미
Meaning of 80
RIO (LEFT :120 ~ RIGHT :-80) 까지의 수를 돌려준다고 가정하고
(LEFT의경우) RIGHT 의 최대값 80 이상인 값을 잘라버리고 나머지는
버릴경우 LEFT RIGHT가 동일한 속도로 움직일수 있다
Assuming RIO returns values in range (LEFT:120 ~ RIGHT:-80)
(In the LEFT case) clip values above the RIGHT maximum of 80, and the rest
if discarded, LEFT and RIGHT can move at the same speed
*/
//////////////////////////////////////////////////////////////////////////////////
LONG lJ;
+219 -11
View File
@@ -132,6 +132,10 @@ extern SCRIPTCALLBACK(CTCL_GetMissionState);
extern SCRIPTCALLBACK(CTCL_DoBreak);
extern SCRIPTCALLBACK(CTCL_IsGameLoaded);
extern SCRIPTCALLBACK(CTCL_DoReprint);
extern SCRIPTCALLBACK(CTCL_LoadAutoFile);
extern SCRIPTCALLBACK(CTCL_GetAutoSlotName);
extern SCRIPTCALLBACK(CTCL_GetAutoSlotMech);
extern SCRIPTCALLBACK(CTCL_GetAutoSlotInt);
extern SCRIPTCALLBACK(CTCL_CheckPlayMovie);
extern SCRIPTCALLBACK(CTCL_CheckCoinCounts);
extern SCRIPTCALLBACK(CTCL_CheckUseJPD);
@@ -158,6 +162,35 @@ int g_nWhyPaused = 0; // 0: not paused - invitation in menu-state, 1: briefing,
extern SCRIPTCALLBACK(CTCL_WhyPaused);
int g_nTimeList_Index = 3; // 3rd item in listbox...
int g_nTimeList_Value = 7; // 7 minutes
// [RookieMission] options.ini overrides ? defaults match the hardcoded script values
char g_szRookieMission[256] = "ScarabStronghold - Attrition";
char* g_pszRookieMission = g_szRookieMission; // pointer used for script registration
int g_nRookieGameType = 2; // Attrition index in game-type list
int g_nRookieVisibility = 0; // 0=clear
int g_nRookieWeather = 0; // 0=off
int g_nRookieTimeOfDay = 0; // 0=day
int g_nRookieTimeLimit = -1; // -1=use g_nTimeList_Value
int g_nRookieRadar = 0; // 0=novice
int g_nRookieHeat = 0; // 0=off
int g_nRookieFriendlyFire= 0;
int g_nRookieSplash = 0;
int g_nRookieUnlimitedAmmo = 1; // 1=on (be cautious)
int g_nRookieWeaponJam = 0;
int g_nRookieAdvanceMode = 0;
int g_nRookieArmorMode = 0;
// [automaticmode] options.ini ? Load File button
struct SAutoFileSlot {
char szName[64]; // pilot name
char szMech[64]; // mech display name (matched against mech[] array)
int nType; // 0=empty, 1=player, 2-9=bot difficulty level
int nTeam;
int nSkin;
int nDecal;
};
static SAutoFileSlot g_aAutoSlots[16];
static int g_nAutoSlotsCount = 0;
static int g_bAutomaticMode = 0;
static char g_szAutomaticFile[MAX_PATH] = "";
// MSL 5.06
int g_nMechVariant = 0;
int g_nMechLabOp = 0;
@@ -727,6 +760,36 @@ void MW4Shell::StartUp()
gosScript_RegisterCallback("CTCL_WhyPaused",&CTCL_WhyPaused,GOSVAR_INT,0,NULL);
gosScript_RegisterVariable("g_nTimeList_Index", &g_nTimeList_Index, GOSVAR_INT, 0, NULL);
gosScript_RegisterVariable("g_nTimeList_Value", &g_nTimeList_Value, GOSVAR_INT, 0, NULL);
// [RookieMission] ini-driven defaults
gosScript_RegisterVariable("g_szRookieMission", &g_pszRookieMission, GOSVAR_STRING, 0, NULL);
gosScript_RegisterVariable("g_nRookieGameType", &g_nRookieGameType, GOSVAR_INT, 0, NULL);
gosScript_RegisterVariable("g_nRookieVisibility", &g_nRookieVisibility, GOSVAR_INT, 0, NULL);
gosScript_RegisterVariable("g_nRookieWeather", &g_nRookieWeather, GOSVAR_INT, 0, NULL);
gosScript_RegisterVariable("g_nRookieTimeOfDay", &g_nRookieTimeOfDay, GOSVAR_INT, 0, NULL);
gosScript_RegisterVariable("g_nRookieTimeLimit", &g_nRookieTimeLimit, GOSVAR_INT, 0, NULL);
gosScript_RegisterVariable("g_nRookieRadar", &g_nRookieRadar, GOSVAR_INT, 0, NULL);
gosScript_RegisterVariable("g_nRookieHeat", &g_nRookieHeat, GOSVAR_INT, 0, NULL);
gosScript_RegisterVariable("g_nRookieFriendlyFire",&g_nRookieFriendlyFire, GOSVAR_INT, 0, NULL);
gosScript_RegisterVariable("g_nRookieSplash", &g_nRookieSplash, GOSVAR_INT, 0, NULL);
gosScript_RegisterVariable("g_nRookieUnlimitedAmmo",&g_nRookieUnlimitedAmmo,GOSVAR_INT, 0, NULL);
gosScript_RegisterVariable("g_nRookieWeaponJam", &g_nRookieWeaponJam, GOSVAR_INT, 0, NULL);
gosScript_RegisterVariable("g_nRookieAdvanceMode", &g_nRookieAdvanceMode, GOSVAR_INT, 0, NULL);
gosScript_RegisterVariable("g_nRookieArmorMode", &g_nRookieArmorMode, GOSVAR_INT, 0, NULL);
// [automaticmode] callbacks
gosScript_RegisterCallback("CTCL_LoadAutoFile", &CTCL_LoadAutoFile, GOSVAR_INT, 0, NULL);
gosScript_RegisterCallback("CTCL_GetAutoSlotName", &CTCL_GetAutoSlotName, GOSVAR_INT, 0, NULL);
gosScript_RegisterCallback("CTCL_GetAutoSlotMech", &CTCL_GetAutoSlotMech, GOSVAR_INT, 0, NULL);
gosScript_RegisterCallback("CTCL_GetAutoSlotInt", &CTCL_GetAutoSlotInt, GOSVAR_INT, 0, NULL);
{
NotationFile opts("options.ini", NotationFile::Standard, true);
Page *pAuto = opts.FindPage("automaticmode");
if (pAuto) {
pAuto->GetEntry("automaticmode", &g_bAutomaticMode);
const char *sz = NULL;
if (pAuto->GetEntry("automaticfile", &sz) && sz)
strncpy(g_szAutomaticFile, sz, sizeof(g_szAutomaticFile)-1);
}
}
// MSL 5.06
gosScript_RegisterVariable("g_nMechVariant", &g_nMechVariant, GOSVAR_INT, 0, NULL);
gosScript_RegisterVariable("g_nMechLabOp", &g_nMechLabOp, GOSVAR_INT, 0, NULL);
@@ -1108,6 +1171,26 @@ void MW4Shell::ShutDown()
// jcem - start
gosScript_UnregisterVariable("g_nTimeList_Value");
gosScript_UnregisterVariable("g_nTimeList_Index");
// [RookieMission] globals
gosScript_UnregisterVariable("g_szRookieMission");
gosScript_UnregisterVariable("g_nRookieGameType");
gosScript_UnregisterVariable("g_nRookieVisibility");
gosScript_UnregisterVariable("g_nRookieWeather");
gosScript_UnregisterVariable("g_nRookieTimeOfDay");
gosScript_UnregisterVariable("g_nRookieTimeLimit");
gosScript_UnregisterVariable("g_nRookieRadar");
gosScript_UnregisterVariable("g_nRookieHeat");
gosScript_UnregisterVariable("g_nRookieFriendlyFire");
gosScript_UnregisterVariable("g_nRookieSplash");
gosScript_UnregisterVariable("g_nRookieUnlimitedAmmo");
gosScript_UnregisterVariable("g_nRookieWeaponJam");
gosScript_UnregisterVariable("g_nRookieAdvanceMode");
gosScript_UnregisterVariable("g_nRookieArmorMode");
// [automaticmode] callbacks
gosScript_UnregisterCallback("CTCL_GetAutoSlotInt");
gosScript_UnregisterCallback("CTCL_GetAutoSlotMech");
gosScript_UnregisterCallback("CTCL_GetAutoSlotName");
gosScript_UnregisterCallback("CTCL_LoadAutoFile");
// MSL 5.06
gosScript_UnregisterVariable("g_nBlackMech");
gosScript_UnregisterVariable("g_nMechVariant");
@@ -1828,7 +1911,8 @@ int MW4Shell::SetNetworkMissionParamater(void * instance, int numParms, void **d
case PLAYER_LIMIT_PARAMETER:
params->m_playerLimit = INTPARM(1);
Min_Clamp(params->m_playerLimit, Network::GetInstance()->GetPlayerCount());
Environment.NetworkMaxPlayers = params->m_playerLimit;
// Add camera slots on top of the pilot limit so cameraships can still connect
Environment.NetworkMaxPlayers = params->m_playerLimit + (CTCL_GetTeslaCountAll() - CTCL_GetTeslaCount());
gos_NetServerCommands(gos_Commend_UpdateMaxPlayers,0);
break;
@@ -12731,6 +12815,132 @@ int __stdcall CTCL_SetCDSP(void* instance, int args, void* data[])
{
ASSERT(CTCL_IsConsole());
CTCL_DefaultHostSetup(1);
// Read [RookieMission] section from options.ini and populate script globals.
// Missing keys leave globals at their initialised defaults (backward-compatible).
{
NotationFile options_ini("options.ini", NotationFile::Standard, true);
Page *page = options_ini.FindPage("RookieMission");
if (page)
{
const char *sz = NULL;
if (page->GetEntry("MissionName", &sz) && sz)
{
strncpy(g_szRookieMission, sz, sizeof(g_szRookieMission) - 1);
g_szRookieMission[sizeof(g_szRookieMission) - 1] = '\0';
}
page->GetEntry("GameType", &g_nRookieGameType);
page->GetEntry("Visibility", &g_nRookieVisibility);
page->GetEntry("Weather", &g_nRookieWeather);
page->GetEntry("TimeOfDay", &g_nRookieTimeOfDay);
page->GetEntry("TimeLimit", &g_nRookieTimeLimit);
page->GetEntry("Radar", &g_nRookieRadar);
page->GetEntry("HeatOn", &g_nRookieHeat);
page->GetEntry("FriendlyFire", &g_nRookieFriendlyFire);
page->GetEntry("SplashDamage", &g_nRookieSplash);
page->GetEntry("UnlimitedAmmo", &g_nRookieUnlimitedAmmo);
page->GetEntry("WeaponJam", &g_nRookieWeaponJam);
page->GetEntry("AdvanceMode", &g_nRookieAdvanceMode);
page->GetEntry("ArmorMode", &g_nRookieArmorMode);
}
}
return 0;
}
// [automaticmode] Load File button ? reads automatic file into Rookie Mission globals + per-slot data.
// Returns 1 if the file was found and loaded, 0 otherwise. File is NOT consumed (stays on disk).
int __stdcall CTCL_LoadAutoFile(void* instance, int args, void* data[])
{
if (!g_bAutomaticMode || !g_szAutomaticFile[0])
return 0;
if (GetFileAttributes(g_szAutomaticFile) == 0xFFFFFFFF)
return 0;
NotationFile autofile(g_szAutomaticFile, NotationFile::Standard, true);
// Game options ? overwrite Rookie Mission globals so the existing
// MAIL_SET_ROOKIE_MISSION script flow picks them up automatically.
Page *pMission = autofile.FindPage("mission");
if (pMission) {
const char *sz = NULL;
if (pMission->GetEntry("MissionName", &sz) && sz) {
strncpy(g_szRookieMission, sz, sizeof(g_szRookieMission)-1);
g_szRookieMission[sizeof(g_szRookieMission)-1] = '\0';
}
pMission->GetEntry("GameType", &g_nRookieGameType);
pMission->GetEntry("Visibility", &g_nRookieVisibility);
pMission->GetEntry("Weather", &g_nRookieWeather);
pMission->GetEntry("TimeOfDay", &g_nRookieTimeOfDay);
pMission->GetEntry("TimeLimit", &g_nRookieTimeLimit);
pMission->GetEntry("Radar", &g_nRookieRadar);
pMission->GetEntry("HeatOn", &g_nRookieHeat);
pMission->GetEntry("FriendlyFire", &g_nRookieFriendlyFire);
pMission->GetEntry("SplashDamage", &g_nRookieSplash);
pMission->GetEntry("UnlimitedAmmo", &g_nRookieUnlimitedAmmo);
pMission->GetEntry("WeaponJam", &g_nRookieWeaponJam);
pMission->GetEntry("AdvanceMode", &g_nRookieAdvanceMode);
pMission->GetEntry("ArmorMode", &g_nRookieArmorMode);
}
// Per-slot data (up to 16 slots via [slot0]..[slot15] pages)
g_nAutoSlotsCount = 0;
memset(g_aAutoSlots, 0, sizeof(g_aAutoSlots));
char szPageName[16];
for (int i = 0; i < 16; i++) {
sprintf(szPageName, "slot%d", i);
Page *pSlot = autofile.FindPage(szPageName);
if (!pSlot) break;
g_nAutoSlotsCount = i + 1;
const char *sz = NULL;
if (pSlot->GetEntry("PilotName", &sz) && sz)
strncpy(g_aAutoSlots[i].szName, sz, sizeof(g_aAutoSlots[i].szName)-1);
sz = NULL;
if (pSlot->GetEntry("Mech", &sz) && sz)
strncpy(g_aAutoSlots[i].szMech, sz, sizeof(g_aAutoSlots[i].szMech)-1);
pSlot->GetEntry("Type", &g_aAutoSlots[i].nType);
pSlot->GetEntry("Team", &g_aAutoSlots[i].nTeam);
pSlot->GetEntry("Skin", &g_aAutoSlots[i].nSkin);
pSlot->GetEntry("Decal", &g_aAutoSlots[i].nDecal);
}
return 1;
}
// Returns pilot name string for slot k ? data[0]=string output buffer, data[1]=int k
int __stdcall CTCL_GetAutoSlotName(void* instance, int args, void* data[])
{
int k = INTPARM(1);
const char *sz = (k >= 0 && k < 16) ? g_aAutoSlots[k].szName : "";
if (STRPARM(0)) gos_Free(STRPARM(0));
STRPARM(0) = (char *)gos_Malloc(64);
strncpy(STRPARM(0), sz, 63);
STRPARM(0)[63] = '\0';
return 1;
}
// Returns mech display name for slot k ? data[0]=string output buffer, data[1]=int k
int __stdcall CTCL_GetAutoSlotMech(void* instance, int args, void* data[])
{
int k = INTPARM(1);
const char *sz = (k >= 0 && k < 16) ? g_aAutoSlots[k].szMech : "";
if (STRPARM(0)) gos_Free(STRPARM(0));
STRPARM(0) = (char *)gos_Malloc(64);
strncpy(STRPARM(0), sz, 63);
STRPARM(0)[63] = '\0';
return 1;
}
// Returns int field for slot k ? data[0]=int k, data[1]=int field (0=Type 1=Team 2=Skin 3=Decal)
int __stdcall CTCL_GetAutoSlotInt(void* instance, int args, void* data[])
{
int k = INTPARM(0);
int field = INTPARM(1);
if (k < 0 || k >= 16) return 0;
switch (field) {
case 0: return g_aAutoSlots[k].nType;
case 1: return g_aAutoSlots[k].nTeam;
case 2: return g_aAutoSlots[k].nSkin;
case 3: return g_aAutoSlots[k].nDecal;
}
return 0;
}
@@ -13307,19 +13517,17 @@ void CTCL_API CTCL_DefaultHostSetup(int nMode)
params->m_allowdecaltransfer = 0;
if (g_bCOOP) {
Environment.NetworkMaxPlayers = 16;
//if (CTCL_GetTeslaCount() < CTCL_GetTeslaCountAll()) {
// any cameraship installed... so 1 more player can join
//params->m_maxPlayers = 9;
//params->m_maxBots = 8;
//} else {
// Reserve extra DirectPlay slots for camera seats (tracked separately from pilots in CTCL)
// Original commented-out intent preserved and now implemented for non-COOP below
params->m_maxPlayers = 9;
params->m_maxBots = 8;
//}
} else {
params->m_maxPlayers = 31; // 31: max that fits in 5-bit bitstream (0-31)
Environment.NetworkMaxPlayers = 31;
params->m_maxBots = 31;
gos_NetServerCommands(gos_Commend_UpdateMaxPlayers, 0); // push the updated limit to the live DirectPlay session
params->m_maxPlayers = 16;
// Reserve extra DirectPlay slots for cameraships: they share the session but are tracked
// separately from pilot seats in CTCL (CTCL_GetTeslaCountAll - CTCL_GetTeslaCount = camera count).
// Without this, cameraship connection is rejected by DirectPlay because slot 17 doesn't exist.
Environment.NetworkMaxPlayers = params->m_maxPlayers + (CTCL_GetTeslaCountAll() - CTCL_GetTeslaCount());
params->m_maxBots = 16;
}
params->m_allow3rdPerson = 1;
if ((nMode != 0) && (nMode != 4)) {
+4 -4
View File
@@ -808,8 +808,8 @@ void NetMissionParameters::MWNetMissionParameters::SaveParameters(DynamicMemoryS
stream->WriteBits(&m_pureMapCycle,1);
stream->WriteBits(&m_maxPlayers, 5); // max 31 players
stream->WriteBits(&m_maxBots, 5); // max 31
stream->WriteBits(&m_maxPlayers, 5); // 16 players maximum
stream->WriteBits(&m_maxBots, 5); // 16 players maximum
stream->WriteBits(&m_mapID, 16); // 65535 maps available
stream->WriteBits(&m_mapClientCRC, 64);
@@ -927,8 +927,8 @@ void NetMissionParameters::MWNetMissionParameters::LoadParameters(MemoryStream *
stream->ReadBits(&m_useMapCycle,1);
stream->ReadBits(&m_pureMapCycle,1);
stream->ReadBits(&m_maxPlayers, 5); // max 31 players
stream->ReadBits(&m_maxBots, 5); // max 31
stream->ReadBits(&m_maxPlayers, 5); // 16 players max
stream->ReadBits(&m_maxBots, 5); // 16 players max
stream->ReadBits(&m_mapID, 16); // 65535 maps available
stream->ReadBits(&m_mapClientCRC, 64);
+1 -1
View File
@@ -150,7 +150,7 @@ extern int g_nMech4Comm;
// server & client only
extern BOOL g_bIsServer;
// console(All), server & client only(g_aPlayerInfos[0]), server only(g_aPlayerInfos[1..g_nBOTs]
extern SPlayerInfo g_aPlayerInfos[35]; // 31 pilots + 1 CS + 3 spare
extern SPlayerInfo g_aPlayerInfos[20];
extern int g_nPlayerInfos;
extern int g_nServer;
extern int g_nTeslas;
@@ -885,7 +885,7 @@ void __stdcall GetGameOSEnvironment(char* CommandLine)
Environment.allowMultipleApps = false;
Environment.AllowJoinInProgress = true;
Environment.NetworkGame = true;
Environment.NetworkMaxPlayers = 31; // max 31 (fits in 5-bit bitstream)
Environment.NetworkMaxPlayers = 16;
Environment.NetworkGUID[0] = 0x95;
Environment.NetworkGUID[1] = 0x78;
Environment.NetworkGUID[2] = 0xFF;
@@ -9,7 +9,7 @@
#include "recscore.h"
#endif // !defined(CTCLS_EXPORTS) && !defined(CTCL_LAUNCHER)
#define MAX_TESLAS 31
#define MAX_TESLAS 16
#define MAX_CAMERAS 4
#define PORT_Launcher 1000
@@ -263,7 +263,7 @@ CInviteCOOP g_InviteCOOP;
// Mech4 only
int g_nMech4Comm = 0;
BOOL g_bIsServer = FALSE;
SPlayerInfo g_aPlayerInfos[35]; // 31 pilots + 1 CS + 3 spare
SPlayerInfo g_aPlayerInfos[20];
int g_nPlayerInfos;
int g_nServer;
int g_nTeslas;
+2 -2
View File
@@ -9,7 +9,7 @@
#include "recscore.h"
#endif // !defined(CTCLS_EXPORTS) && !defined(CTCL_LAUNCHER)
#define MAX_TESLAS 31
#define MAX_TESLAS 16
#define MAX_CAMERAS 4
#define PORT_Launcher 1000
@@ -263,7 +263,7 @@ CInviteCOOP g_InviteCOOP;
// Mech4 only
int g_nMech4Comm = 0;
BOOL g_bIsServer = FALSE;
SPlayerInfo g_aPlayerInfos[35]; // 31 pilots + 1 CS + 3 spare
SPlayerInfo g_aPlayerInfos[20];
int g_nPlayerInfos;
int g_nServer;
int g_nTeslas;
@@ -806,7 +806,7 @@ STRINGTABLE DISCARDABLE
BEGIN
IDS_ML_CH_ACCELERATION "Acceleration (Meters/Sec.):"
IDS_ML_CH_DECELERATION "Deceleration (Meters/Sec.):"
IDS_ML_CH_TURNRATE "Turn Rate (Degrees/Sec.):"
IDS_ML_CH_TURNRATE "Turn Rate (Top Speed Rad/Sec):"
IDS_ML_CH_TWISTRANGE "Torso Twist Range (Degrees):"
IDS_ML_CH_TWISTSPEED "Torso Twist Speed (Degrees/Sec.):"
IDS_ML_CH_NEWMECH "NEW 'MECH"
@@ -86,7 +86,7 @@ void NetMissionParameters::AdeptNetMissionParameters::ResetParameters(void)
{
m_runDedicated = 0;
m_closedGame = 0;
m_playerLimit = 31; // max 31 (fits in 5-bit bitstream)
m_playerLimit = 16;
m_visibility = 0;
+2 -2
View File
@@ -9,7 +9,7 @@
#include "recscore.h"
#endif // !defined(CTCLS_EXPORTS) && !defined(CTCL_LAUNCHER)
#define MAX_TESLAS 31
#define MAX_TESLAS 16
#define MAX_CAMERAS 4
#define PORT_Launcher 1000
@@ -263,7 +263,7 @@ CInviteCOOP g_InviteCOOP;
// Mech4 only
int g_nMech4Comm = 0;
BOOL g_bIsServer = FALSE;
SPlayerInfo g_aPlayerInfos[35]; // 31 pilots + 1 CS + 3 spare
SPlayerInfo g_aPlayerInfos[20];
int g_nPlayerInfos;
int g_nServer;
int g_nTeslas;
+168 -55
View File
@@ -14,6 +14,9 @@
// 10/10/03 MSL Added Cameraship to RESET_AFTER_LAUNCH
// 10/17/05 MSL Added all remaining Mechs (55)
// 06/19/18 AVB Update tab stops
// 06/24/26 Cyd MechCorps is given access to this script and the loading method (-diskfirst). This includes the CS timer fix.
// 06/27/26 MCHL MechCorps Highlight: Change Fab4 to Super6.
// 07/19/26 RT Bumped console title to V5.1.0b1
//-------------------------------------------------------------------------
@@ -72,8 +75,8 @@
#define USE_O_MORE_PODS $$g_nMechPodNum$$ // 0 = use only 8
#if USE_O_MORE_PODS
#define MAX_ROSTER_COUNT 31 // max within 5-bit bitstream (0-31)
#define MAX_TEAMMATE_COUNT 15 // Was 4, then 8
#define MAX_ROSTER_COUNT 16 // Was 8
#define MAX_TEAMMATE_COUNT 8 // Was 4
#else
#define MAX_ROSTER_COUNT 8
#define MAX_TEAMMATE_COUNT 4 // Was 4
@@ -190,10 +193,13 @@
// MSL 5.06
// MSL ADD MECH
#define ROOKIEMECH1 38 // Loki
#define ROOKIEMECH2 40 // Madcat
#define ROOKIEMECH3 56 // Thor
#define ROOKIEMECH4 61 // Vulture
// MechCorps Highlight: expanded from Fab4 to Super6 (added Archer and Warhammer)
#define ROOKIEMECH1 1 // Archer
#define ROOKIEMECH2 38 // Loki
#define ROOKIEMECH3 40 // Madcat
#define ROOKIEMECH4 56 // Thor
#define ROOKIEMECH5 61 // Vulture
#define ROOKIEMECH6 62 // Warhammer
main
{
@@ -246,7 +252,7 @@ main
o_frame.type = 0
o_frame.location = 0, 0, 100
// MSL Version
o_frame.screen_name = "BattleTech Console V5.0.7Df" // localize$(IDS_MP_LOBBY_GAME_LOBBY)
o_frame.screen_name = "BattleTech Console V5.1.0b1" // localize$(IDS_MP_LOBBY_GAME_LOBBY)
initialize(o_frame)
int team_camo[16] // team_camo[selected team number] is skin number(0..36)...
@@ -364,7 +370,7 @@ main
cur_team_val = callback($$CTCL_GetTeamParams$$, cur_team_count[0])
int skin_id ///////VERY IMPORTANT FOR NEW SKIN INTERFACE
int skin_ids[32]
int skin_ids[17]
int update_skin = false
// MSL 5.05
int decal_id ///////VERY IMPORTANT FOR NEW DECAL INTERFACE
@@ -522,7 +528,7 @@ main
///---------holds faction name for scroll list
string faction_name[32]
string faction_name[17]
callback($$Shell_CallbackHandler$$, ShellInitMPScreen)
@@ -645,12 +651,12 @@ main
team_legal_to_join[8] = TRUE
int update_team = 0
int max_players = 31 // max within 5-bit bitstream
int max_players = 16
int player_num = 0
// int num_of_teams = 8
int mech_id
int name_color[32]
int name_color[17]
int lupe
for lupe = 0; lupe < nRosterCount;lupe++
@@ -675,33 +681,33 @@ main
player_num = -1
// ComboBox for the Player Type
object o_BotList[32]
object o_BotList_bu[32]
int m_naLastSelected[32]
object o_BotList[17]
object o_BotList_bu[17]
int m_naLastSelected[17]
for x = 0; x < nRosterCount; x++
{
m_naLastSelected[x] = 0
}
object o_Editbox[32]
object o_print_text[32]
object o_mech_variant[32]
object o_mech_variant_bu[32]
object o_Editbox[17]
object o_print_text[17]
object o_mech_variant[17]
object o_mech_variant_bu[17]
#if USE_O_MECH_VARIANT2
object o_mech_variant2[32]
object o_mech_variant2_bu[32]
object o_mech_variant2[17]
object o_mech_variant2_bu[17]
#endif // USE_O_MECH_VARIANT2
object o_mech_rand[32]
object o_skins[32]
object o_skins_bu[32]
object o_mech_rand[17]
object o_skins[17]
object o_skins_bu[17]
// MSL 5.05
object o_decal[32]
object o_decal_bu[32]
object o_team[32]
object o_team_bu[32]
object o_decal_box[32]
object o_skin_box[32]
object o_status[32]
int roster_posy[32]
object o_decal[18]
object o_decal_bu[18]
object o_team[18]
object o_team_bu[18]
object o_decal_box[18]
object o_skin_box[18]
object o_status[18]
int roster_posy[18]
int coolbaby
int stock_size = 0
@@ -1005,7 +1011,7 @@ main
o_decal[x].list_item[15] = "16"
o_decal[x].list_item[16] = "17"
for coolbaby = 17;coolbaby < o_decal[x].list_size;coolbaby++
for coolbaby = 17;coolbaby < o_decal[x].list_size+1;coolbaby++
o_decal[x].list_item[coolbaby] = conv$(coolbaby+1)
o_decal[x].nselected = 3
@@ -1072,7 +1078,7 @@ main
o_skins[x].list_item[14] = "15"
o_skins[x].list_item[15] = "16"
for coolbaby = 16;coolbaby < o_skins[x].list_size;coolbaby++
for coolbaby = 16;coolbaby < o_skins[x].list_size+1;coolbaby++
o_skins[x].list_item[coolbaby] = conv$(coolbaby+1)
o_skins[x].nselected = 3
@@ -1223,6 +1229,16 @@ main
o_all_random_mech.state = 0 // initially enabled
initialize(o_all_random_mech)
// [automaticmode] Load File button -- below Pick Cond., left of Reprint
object o_load_file = s_multistatepane
o_load_file.total_states = 3
o_load_file.textsize = 1
o_load_file.text = "Load File"
o_load_file.file = WPATH "button_reg_138x23m_3state.tga"
o_load_file.location = 467, 510, o_frame.location.z + 1
o_load_file.state = 0 // initially enabled
initialize(o_load_file)
// MSL Added default settings button
object o_default = s_multistatepane
o_default.total_states = 3
@@ -1658,6 +1674,94 @@ main
mail(MAIL_RESET_AFTER_LAUNCH, this) // reset
return
}
// [automaticmode] Load File button handler
if (sender == o_load_file)
{
play press, 1
if callback($$CTCL_LoadAutoFile$$)
{
// Apply mission + game options via existing Rookie Mission flow
mail(MAIL_SET_ROOKIE_MISSION, @ConLobbyMission@)
// Clear all slots
o_cam_list.nselected = 0
for (k = 0; k < nRosterCount; k++)
{
if (1 <= o_BotList[k].nselected)
{
if (o_BotList[k].nselected == 1) && (k < MAXTESLA_P)
{
o_Editbox[k].boxValue = ""
initialize(o_Editbox[k])
deactivate(o_Editbox[k])
}
o_BotList[k].nselected = 0
m_naLastSelected[k] = 0
if (ROSTER_top_of_list <= k) && (k < ROSTER_top_of_list + ROSTER_DISPLAY_COUNT)
mail(MAIL_PLAYER_TYPE_CHANGED, k, this)
}
}
// Apply per-slot data from file
string szAutoName
string szAutoMech
int nAutoType
int j
for (k = 0; k < nRosterCount; k++)
{
nAutoType = callback($$CTCL_GetAutoSlotInt$$, k, 0)
if nAutoType > 0
{
o_BotList[k].nselected = nAutoType
m_naLastSelected[k] = nAutoType
if (o_BotList[k].nselected > 0)
activate(o_BotList[k])
if (nAutoType == 1) && (k < MAXTESLA_P)
{
callback($$CTCL_GetAutoSlotName$$, szAutoName, k)
o_Editbox[k].boxValue = szAutoName
initialize(o_Editbox[k])
activate(o_Editbox[k])
}
callback($$CTCL_GetAutoSlotMech$$, szAutoMech, k)
if (!equal$(szAutoMech, ""))
{
#if USE_ALLOWED_MECHS
for (j = 0; j < MAX_ALLOWED_MECHS; j++)
{
if equal$(mech[allowed_mechs[j]], szAutoMech)
{
o_mech_variant[k].nselected = j
break
}
}
#else
for (j = 0; j < $$m_mechCount$$; j++)
{
if equal$(mech[j], szAutoMech)
{
o_mech_variant[k].nselected = j
break
}
}
#endif
}
if cur_team_val > 0
o_team[k].nselected = callback($$CTCL_GetAutoSlotInt$$, k, 1)
else
o_skins[k].nselected = callback($$CTCL_GetAutoSlotInt$$, k, 2)
o_decal[k].nselected = callback($$CTCL_GetAutoSlotInt$$, k, 3)
initialize(o_mech_variant[k])
if (ROSTER_top_of_list <= k) && (k < ROSTER_top_of_list + ROSTER_DISPLAY_COUNT)
{
activate(o_mech_variant[k])
mail(MAIL_PLAYER_TYPE_CHANGED, k, this)
}
else
deactivate(o_mech_variant[k])
}
}
}
return
}
if (sender == o_reprint)
{
play press,1
@@ -1761,38 +1865,39 @@ main
for (k = 0; k < nRosterCount; k++)
{
// MSL
// MechCorps Highlight: Super6 slot assignments (16 slots, 6-mech cycle; Vulture+Warhammer appear twice)
if k == 0
o_mech_variant[k].nselected = ROOKIEMECH1 // Loki
o_mech_variant[k].nselected = ROOKIEMECH1 // Archer
if k == 1
o_mech_variant[k].nselected = ROOKIEMECH2 // Madcat
o_mech_variant[k].nselected = ROOKIEMECH2 // Loki
if k == 2
o_mech_variant[k].nselected = ROOKIEMECH3 // Thor
o_mech_variant[k].nselected = ROOKIEMECH3 // Madcat
if k == 3
o_mech_variant[k].nselected = ROOKIEMECH4 // vulture
o_mech_variant[k].nselected = ROOKIEMECH4 // Thor
if k == 4
o_mech_variant[k].nselected = ROOKIEMECH1 // Loki
o_mech_variant[k].nselected = ROOKIEMECH5 // Vulture
if k == 5
o_mech_variant[k].nselected = ROOKIEMECH2 // Madcat
o_mech_variant[k].nselected = ROOKIEMECH6 // Warhammer
if k == 6
o_mech_variant[k].nselected = ROOKIEMECH3 // Thor
o_mech_variant[k].nselected = ROOKIEMECH1 // Archer
if k == 7
o_mech_variant[k].nselected = ROOKIEMECH4 // Vulture
o_mech_variant[k].nselected = ROOKIEMECH2 // Loki
if k == 8
o_mech_variant[k].nselected = ROOKIEMECH1 // Loki
o_mech_variant[k].nselected = ROOKIEMECH3 // Madcat
if k == 9
o_mech_variant[k].nselected = ROOKIEMECH2 // Madcat
o_mech_variant[k].nselected = ROOKIEMECH4 // Thor
if k == 10
o_mech_variant[k].nselected = ROOKIEMECH3 // Thor
o_mech_variant[k].nselected = ROOKIEMECH5 // Vulture
if k == 11
o_mech_variant[k].nselected = ROOKIEMECH4 // vulture
o_mech_variant[k].nselected = ROOKIEMECH6 // Warhammer
if k == 12
o_mech_variant[k].nselected = ROOKIEMECH1 // Loki
o_mech_variant[k].nselected = ROOKIEMECH1 // Archer
if k == 13
o_mech_variant[k].nselected = ROOKIEMECH2 // Madcat
o_mech_variant[k].nselected = ROOKIEMECH2 // Loki
if k == 14
o_mech_variant[k].nselected = ROOKIEMECH3 // Thor
o_mech_variant[k].nselected = ROOKIEMECH3 // Madcat
if k == 15
o_mech_variant[k].nselected = ROOKIEMECH4 // Vulture
o_mech_variant[k].nselected = ROOKIEMECH4 // Thor
#if USE_O_MECH_VARIANT2
if (USE_ALLOWED_MECHS)
last_count = stock_array[allowed_mechs[o_mech_variant[k].nselected]]
@@ -2714,7 +2819,8 @@ main
}
}
// MSL 5.06
if nLaunchState == 0 && (nTempPlayerCount > 31)
// RT 07/19/26: raised cap from 16 to 17 to allow 16 pilots + 1 cameraship
if nLaunchState == 0 && (nTempPlayerCount > 17)
{
o_error_string.text = "Too many player/bots"
nLaunchState = -7
@@ -4000,17 +4106,24 @@ mech_randomizer
else // right button
{
int pick_mech = 0
pick_mech = random(0, 3)
//pick_mech = random(0, 3) // Fab4
// MechCorps Highlight: Super6 - expand right-click random range to 6
pick_mech = random(0, 5)
// MSL
// MechCorps Highlight: Super6 - added Archer (0) and Warhammer (5) to right-click mech pool
if pick_mech = 0
last_mech = ROOKIEMECH1 // Loki
last_mech = ROOKIEMECH1 // Archer
if pick_mech = 1
last_mech = ROOKIEMECH2 // Madcat
last_mech = ROOKIEMECH2 // Loki
if pick_mech = 2
last_mech = ROOKIEMECH3 // Thor
last_mech = ROOKIEMECH3 // Madcat
if pick_mech = 3
last_mech = ROOKIEMECH4 // vulture
last_mech = ROOKIEMECH4 // Thor
if pick_mech = 4
last_mech = ROOKIEMECH5 // Vulture
if pick_mech = 5
last_mech = ROOKIEMECH6 // Warhammer
}
if (USE_ALLOWED_MECHS)
{
@@ -793,15 +793,15 @@ main
if (getmessage() == MAIL_SET_ROOKIE_MISSION) // set rookie, see conlobby.script
{
// caution: actually 0 is not correct but who care? ^^
if (o_game_options[0].nselected != 2)
if (o_game_options[0].nselected != $$g_nRookieGameType$$)
{
o_game_options[0].nselected = 2
o_game_options[0].nselected = $$g_nRookieGameType$$
mail(MAIL_SET_ROOKIE_MISSION, this)
}
// find mission:
for k = 0; k < o_game_options[1].list_size; k++
{
if equal$(o_game_options[1].list_item[k], ROOKIE_MISSION)
if equal$(o_game_options[1].list_item[k], $$g_szRookieMission$$)
{
// found mission
break
@@ -855,24 +855,26 @@ main
else
{
// visibility
o_game_options[2].nselected = 0 // Default
o_game_options[2].nselected = $$g_nRookieVisibility$$ // [RookieMission] ini
callback($$SetNetworkMissionParamater$$, visibility, o_game_options[2].nselected)
// weather
o_game_options[3].nselected = 0 // off
o_game_options[3].nselected = $$g_nRookieWeather$$ // [RookieMission] ini
callback($$SetNetworkMissionParamater$$, weather, o_game_options[3].nselected)
// time of day
o_game_options[4].nselected = 0
o_game_options[4].nselected = $$g_nRookieTimeOfDay$$ // [RookieMission] ini
callback($$SetNetworkMissionParamater$$, night_parameter, o_game_options[4].nselected)
callback($$Shell_CallbackHandler$$, ShellSetTime, o_game_options[4].nselected)
}
// time limit
// time limit - use ini override if set, else TIME_VALUE_DEFAULT
if $$g_nRookieTimeLimit$$ >= 0
temp_num = $$g_nRookieTimeLimit$$ // [RookieMission] ini
else
temp_num = TIME_VALUE_DEFAULT
for k = 0; k < o_game_options[5].list_size; k++
{
temp_num = makeint(o_game_options[5].list_item[k])
if (temp_num == TIME_VALUE_DEFAULT)
if (makeint(o_game_options[5].list_item[k]) == temp_num)
{
o_game_options[5].nselected = k
break
@@ -935,31 +937,31 @@ main
{
// radar
nTempParam = radar
nTempValue = 0 // Novice
nTempValue = $$g_nRookieRadar$$ // [RookieMission] ini (0=Novice)
o_game_options[6].nselected = nTempValue
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
// heat management
nTempParam = HEAT_PARAMETER
nTempValue = 0
nTempValue = $$g_nRookieHeat$$ // [RookieMission] ini
o_game_options[7].state = 0
callback($$SetNetworkMissionParamater$$,nTempParam, nTempValue)
// friendly fire
nTempParam = FRIENDLY_FIRE_PERCENTGE_PARAMETER
nTempValue = 0
nTempValue = $$g_nRookieFriendlyFire$$ // [RookieMission] ini
o_game_options[8].state = 0
callback($$SetNetworkMissionParamater$$,nTempParam, nTempValue)
// splash
nTempParam = SPLASH_ON_PARAMETER
nTempValue = 0
nTempValue = $$g_nRookieSplash$$ // [RookieMission] ini
o_game_options[9].state = 0
callback($$SetNetworkMissionParamater$$,nTempParam, nTempValue)
// unlimited ammo
nTempParam = UNLIMITED_AMMO_PARAMETER
nTempValue = 1 // be cautious
nTempValue = $$g_nRookieUnlimitedAmmo$$ // [RookieMission] ini
o_game_options[10].state = 0
callback($$SetNetworkMissionParamater$$,nTempParam, nTempValue)
@@ -975,7 +977,7 @@ main
// weapon jam
nTempParam = WEAPON_JAM_PARAMETER
nTempValue = 0
nTempValue = $$g_nRookieWeaponJam$$ // [RookieMission] ini
o_game_options[14].state = 0
callback($$SetNetworkMissionParamater$$,nTempParam, nTempValue)
@@ -987,13 +989,13 @@ main
// advance mode
nTempParam = ADVANCE_MODE_PARAMETER
nTempValue = 0
nTempValue = $$g_nRookieAdvanceMode$$ // [RookieMission] ini
o_game_options[15].state = 0
callback($$SetNetworkMissionParamater$$,nTempParam, nTempValue)
// armor mode
nTempParam = ARMOR_MODE_PARAMETER
nTempValue = 0
nTempValue = $$g_nRookieArmorMode$$ // [RookieMission] ini
o_game_options[16].state = 0
callback($$SetNetworkMissionParamater$$,nTempParam, nTempValue)
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More