Compare commits
25
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
06de4534da | ||
|
|
23284b18b0 | ||
|
|
62dc0952b1 | ||
|
|
9a9f2d0df2 | ||
|
|
cd2fe73c88 | ||
|
|
3f2d79a038 | ||
|
|
c3d82d78c9 | ||
|
|
17ca966473 | ||
|
|
7852269dc7 | ||
|
|
76121f1c68 | ||
|
|
c33465611f | ||
|
|
fccdc2dee4 | ||
|
|
0344418aae | ||
|
|
520a860414 | ||
|
|
5813aeb6e9 | ||
|
|
840bc96cc1 | ||
|
|
72e1e59d8e | ||
|
|
b591bae273 | ||
|
|
a712002fec | ||
|
|
f76dc05f46 | ||
|
|
16fca6c4f1 | ||
|
|
c768f7c46b | ||
|
|
24825ff396 | ||
|
|
0ceba9c778 | ||
|
|
55b9bfc521 |
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,575 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Automatic Config File Specification ? Firestorm Console Load File</title>
|
||||||
|
<style>
|
||||||
|
body { font-family: Calibri, Arial, sans-serif; font-size: 11pt; margin: 60px 72px; color: #1a1a1a; max-width: 900px; }
|
||||||
|
h1 { font-size: 20pt; color: #1F3864; border-bottom: 3px solid #1F3864; padding-bottom: 8px; margin-top: 0; }
|
||||||
|
h2 { font-size: 14pt; color: #1F3864; border-bottom: 1px solid #BDD7EE; padding-bottom: 4px; margin-top: 28px; }
|
||||||
|
h3 { font-size: 12pt; color: #2E4D7B; margin-top: 20px; margin-bottom: 4px; }
|
||||||
|
h4 { font-size: 11pt; color: #2E4D7B; margin-top: 16px; margin-bottom: 2px; font-style: italic; }
|
||||||
|
.meta { color: #555; font-size: 10pt; margin-bottom: 28px; }
|
||||||
|
code, .code { font-family: Consolas, "Courier New", monospace; font-size: 10pt; background: #F4F7FB; padding: 1px 4px; border-radius: 2px; color: #1a1a1a; }
|
||||||
|
pre { font-family: Consolas, "Courier New", monospace; font-size: 10pt; background: #F4F7FB; border: 1px solid #BDD7EE; border-left: 4px solid #2E4D7B; padding: 12px 16px; border-radius: 0 4px 4px 0; overflow-x: auto; line-height: 1.5; }
|
||||||
|
pre .section { color: #7B2D8B; font-weight: bold; }
|
||||||
|
pre .key { color: #1F6A8F; }
|
||||||
|
pre .value { color: #2D6A2D; }
|
||||||
|
pre .comment { color: #888; font-style: italic; }
|
||||||
|
table { border-collapse: collapse; width: 100%; margin: 10px 0 18px 0; font-size: 10.5pt; }
|
||||||
|
th { background: #1F3864; color: white; padding: 7px 12px; text-align: left; font-weight: bold; font-size: 10pt; }
|
||||||
|
tr:nth-child(even) td { background: #EFF4FB; }
|
||||||
|
td { padding: 5px 12px; border-bottom: 1px solid #D0D9E8; vertical-align: top; }
|
||||||
|
td code { background: #E8EFF9; }
|
||||||
|
.warn { background: #FFF3CD; border: 1px solid #FFEAA0; border-left: 4px solid #F0B429; padding: 10px 14px; border-radius: 0 4px 4px 0; margin: 14px 0; font-size: 10.5pt; }
|
||||||
|
.warn strong { color: #7A4F00; }
|
||||||
|
.note { background: #E7F3FD; border: 1px solid #B8D9F5; border-left: 4px solid #1F3864; padding: 10px 14px; border-radius: 0 4px 4px 0; margin: 14px 0; font-size: 10.5pt; }
|
||||||
|
.optional { color: #666; font-size: 9.5pt; font-style: italic; }
|
||||||
|
ul, ol { margin: 6px 0 10px 0; padding-left: 24px; }
|
||||||
|
li { margin-bottom: 4px; }
|
||||||
|
hr { border: none; border-top: 1px solid #D0D9E8; margin: 30px 0; }
|
||||||
|
.key-block { background: #F0F4FA; border: 1px solid #C5D5E8; padding: 8px 12px; border-radius: 4px; margin: 8px 0 12px 0; }
|
||||||
|
.key-block .kname { font-family: Consolas, monospace; font-size: 10.5pt; font-weight: bold; color: #1F6A8F; }
|
||||||
|
.key-block .ktype { color: #888; font-size: 9.5pt; margin-left: 8px; }
|
||||||
|
.default-tag { background: #D4EDDA; color: #155724; font-size: 9pt; padding: 1px 6px; border-radius: 3px; margin-left: 6px; font-weight: bold; }
|
||||||
|
.ignored-tag { background: #F8D7DA; color: #721C24; font-size: 9pt; padding: 1px 6px; border-radius: 3px; margin-left: 6px; }
|
||||||
|
.mech-table td:first-child { font-family: Consolas, monospace; font-size: 10pt; white-space: nowrap; }
|
||||||
|
@media print { body { margin: 40px; } h2 { page-break-before: auto; } }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h1>Automatic Config File Format Specification</h1>
|
||||||
|
<div class="meta">
|
||||||
|
Feature: Console Lobby “Load File” button |
|
||||||
|
Commit: <code>c3346561</code> (branch <code>5.1.0b-in-progress</code>) |
|
||||||
|
Date: 2026-07-24, updated 2026-07-24 (commit <code>cd2fe73c</code>)
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>1. Overview</h2>
|
||||||
|
<p>
|
||||||
|
The system operates with <strong>two separate files</strong>:
|
||||||
|
</p>
|
||||||
|
<ol>
|
||||||
|
<li>
|
||||||
|
<strong><code>options.ini</code></strong> — machine-level one-time configuration, read once at game startup.
|
||||||
|
Contains the path to the config file. Never changed by the game.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>The config file</strong> (path specified in <code>options.ini</code>) —
|
||||||
|
written by the external application before each match.
|
||||||
|
Read by the game when the operator clicks <strong>Load File</strong> in the console lobby.
|
||||||
|
<strong>Not consumed</strong> — the game leaves it on disk. Overwrite it to set the next match.
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
<p>
|
||||||
|
When <strong>Load File</strong> is clicked, the game:
|
||||||
|
</p>
|
||||||
|
<ol>
|
||||||
|
<li>Checks that <code>automaticmode=1</code> and the file path is configured.</li>
|
||||||
|
<li>Checks that the config file exists on disk (<code>GetFileAttributes</code>). If not, does nothing.</li>
|
||||||
|
<li>Reads the file, applies game options, clears all current lobby slots, then fills slots from the file.</li>
|
||||||
|
<li>Leaves the file on disk unchanged.</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h2>2. <code>options.ini</code> Setup (One-Time, Per Machine)</h2>
|
||||||
|
<p>Add the following section to the game’s <code>options.ini</code> in the game working directory.</p>
|
||||||
|
|
||||||
|
<pre><span class="section">[automaticmode]</span>
|
||||||
|
<span class="key">automaticmode</span>=<span class="value">1</span>
|
||||||
|
<span class="key">automaticfile</span>=<span class="value">c:\mw4files\nextmatch.ini</span></pre>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr><th>Key</th><th>Type</th><th>Description</th></tr>
|
||||||
|
<tr><td><code>automaticmode</code></td><td>integer</td><td><code>1</code> = enabled. <code>0</code> = disabled; Load File button does nothing.</td></tr>
|
||||||
|
<tr><td><code>automaticfile</code></td><td>string</td><td>Full absolute Windows path to the config file. Max 259 characters. Can be any local drive letter.</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="note">
|
||||||
|
<strong>Read at startup only.</strong> Changing <code>options.ini</code> requires a game restart.
|
||||||
|
If the <code>[automaticmode]</code> section is absent, or <code>automaticmode=0</code>, or
|
||||||
|
<code>automaticfile</code> is empty, Load File always does nothing regardless of what config file exists.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h2>3. Config File Format Rules</h2>
|
||||||
|
<p>The config file uses <strong>standard Windows INI format</strong>, parsed by <code>NotationFile::Standard</code>.</p>
|
||||||
|
<ul>
|
||||||
|
<li><strong>Encoding:</strong> ANSI / ASCII only. No Unicode, no UTF-8 BOM.</li>
|
||||||
|
<li><strong>Line endings:</strong> CRLF or LF — both accepted.</li>
|
||||||
|
<li><strong>Section headers:</strong> <code>[sectionname]</code> — <strong>case-sensitive, must be all lowercase exactly as shown.</strong></li>
|
||||||
|
<li><strong>Key names:</strong> Case-sensitive. Must match exactly as documented below.</li>
|
||||||
|
<li><strong>String values:</strong> Everything after <code>=</code> to end of line. Do <strong>not</strong> wrap in quotes. Example: <code>MissionName=ScarabStronghold - Attrition</code></li>
|
||||||
|
<li><strong>Integer values:</strong> Raw decimal integer only. No quotes, no sign unless negative. Example: <code>GameType=2</code></li>
|
||||||
|
<li><strong>Do not use comments</strong> (<code>//</code> or <code>;</code>). Parser behavior is not guaranteed. Keep the file clean.</li>
|
||||||
|
<li><strong>Missing key:</strong> If a key is absent from its section, the corresponding lobby value stays at its current setting. No error is raised.</li>
|
||||||
|
<li><strong>Missing section:</strong> If <code>[mission]</code> is absent, no game options are changed. If <code>[slot0]</code> is absent, no slots are changed.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h2>4. Section: <code>[mission]</code></h2>
|
||||||
|
<p>Sets all game lobby parameters. This section is <span class="optional">optional</span> — omit it to leave game options unchanged and only configure slots.</p>
|
||||||
|
|
||||||
|
<pre><span class="section">[mission]</span>
|
||||||
|
<span class="key">MissionName</span>=<span class="value">ScarabStronghold - Attrition</span>
|
||||||
|
<span class="key">GameType</span>=<span class="value">2</span>
|
||||||
|
<span class="key">TeamAllowed</span>=<span class="value">0</span>
|
||||||
|
<span class="key">Visibility</span>=<span class="value">0</span>
|
||||||
|
<span class="key">Weather</span>=<span class="value">0</span>
|
||||||
|
<span class="key">TimeOfDay</span>=<span class="value">0</span>
|
||||||
|
<span class="key">TimeLimit</span>=<span class="value">7</span>
|
||||||
|
<span class="key">Radar</span>=<span class="value">0</span>
|
||||||
|
<span class="key">HeatOn</span>=<span class="value">0</span>
|
||||||
|
<span class="key">FriendlyFire</span>=<span class="value">0</span>
|
||||||
|
<span class="key">SplashDamage</span>=<span class="value">0</span>
|
||||||
|
<span class="key">UnlimitedAmmo</span>=<span class="value">1</span>
|
||||||
|
<span class="key">WeaponJam</span>=<span class="value">0</span>
|
||||||
|
<span class="key">AdvanceMode</span>=<span class="value">0</span>
|
||||||
|
<span class="key">ArmorMode</span>=<span class="value">0</span></pre>
|
||||||
|
|
||||||
|
<h3>4.1 <code>MissionName</code> — string, max 255 characters</h3>
|
||||||
|
<p>
|
||||||
|
The scenario name, <strong>exactly as it appears in the mission list dropdown in the console lobby.</strong>
|
||||||
|
Match is exact string equality, case-sensitive. Trailing/leading spaces are stripped by the parser.
|
||||||
|
</p>
|
||||||
|
<div class="warn">
|
||||||
|
<strong>If the name is not found</strong> in the list for the selected <code>GameType</code>,
|
||||||
|
mission selection silently fails — the dropdown stays at its previous value.
|
||||||
|
No error is logged. All other parameters (Visibility, Weather, etc.) are still applied.
|
||||||
|
The available mission names depend on what scenario files are installed on the machine;
|
||||||
|
there is no static guaranteed list.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>4.2 <code>GameType</code> — integer (dropdown index, 0-based)</h3>
|
||||||
|
<div class="warn">
|
||||||
|
<strong>This is the position in the game type dropdown, NOT the internal game type ID number.</strong>
|
||||||
|
The dropdown is built dynamically at lobby startup — only game types that have at least
|
||||||
|
one installed scenario are shown. If a game type has no installed maps it is skipped and all
|
||||||
|
subsequent indices shift down by one.
|
||||||
|
</div>
|
||||||
|
<p>For a <strong>standard full installation</strong> with all game types present, the order is fixed:</p>
|
||||||
|
<table>
|
||||||
|
<tr><th>Index</th><th>Display Name</th><th>Mode</th></tr>
|
||||||
|
<tr><td><code>0</code></td><td>Destruction</td><td>FFA</td></tr>
|
||||||
|
<tr><td><code>1</code></td><td>Team Destruction</td><td>Team</td></tr>
|
||||||
|
<tr><td><code>2</code></td><td>Attrition</td><td>FFA — <strong>default</strong> <span class="default-tag">DEFAULT</span></td></tr>
|
||||||
|
<tr><td><code>3</code></td><td>Team Attrition</td><td>Team</td></tr>
|
||||||
|
<tr><td><code>4</code></td><td>Capture the Flag</td><td>FFA</td></tr>
|
||||||
|
<tr><td><code>5</code></td><td>King of the Hill</td><td>FFA</td></tr>
|
||||||
|
<tr><td><code>6</code></td><td>Team King of the Hill</td><td>Team</td></tr>
|
||||||
|
<tr><td><code>7</code></td><td>Steal the Bacon</td><td>FFA</td></tr>
|
||||||
|
<tr><td><code>8</code></td><td>Master Trial</td><td>Special</td></tr>
|
||||||
|
<tr><td><code>9</code></td><td>Siege Assault</td><td>Special</td></tr>
|
||||||
|
<tr><td><code>10+</code></td><td>Custom map variants</td><td>Varies (if custom content installed)</td></tr>
|
||||||
|
</table>
|
||||||
|
<p><strong>Team vs. FFA is important:</strong> it determines whether the <code>Team</code> or <code>Skin</code> field is applied to each slot. See Section 5 for details.</p>
|
||||||
|
|
||||||
|
<h3>4.3 <code>Visibility</code> — integer</h3>
|
||||||
|
<table>
|
||||||
|
<tr><th>Value</th><th>Display Name</th><th>Description</th></tr>
|
||||||
|
<tr><td><code>0</code></td><td>Default</td><td>Same as Clear <span class="default-tag">DEFAULT</span></td></tr>
|
||||||
|
<tr><td><code>1</code></td><td>Clear</td><td>Full visibility range</td></tr>
|
||||||
|
<tr><td><code>2</code></td><td>Light Fog</td><td>Reduced visibility range</td></tr>
|
||||||
|
<tr><td><code>3</code></td><td>Heavy Fog</td><td>Heavily reduced visibility range</td></tr>
|
||||||
|
<tr><td><code>4</code></td><td>Pea Soup Fog</td><td>Near-zero visibility range</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h3>4.4 <code>Weather</code> — integer</h3>
|
||||||
|
<table>
|
||||||
|
<tr><th>Value</th><th>Display</th></tr>
|
||||||
|
<tr><td><code>0</code></td><td>Off <span class="default-tag">DEFAULT</span></td></tr>
|
||||||
|
<tr><td><code>1</code></td><td>On (rain or snow depending on map)</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h3>4.5 <code>TimeOfDay</code> — integer</h3>
|
||||||
|
<table>
|
||||||
|
<tr><th>Value</th><th>Display</th></tr>
|
||||||
|
<tr><td><code>0</code></td><td>Day <span class="default-tag">DEFAULT</span></td></tr>
|
||||||
|
<tr><td><code>1</code></td><td>Night</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h3>4.6 <code>TimeLimit</code> — integer (<strong>actual minutes</strong>, not a list index)</h3>
|
||||||
|
<p>
|
||||||
|
Specify the desired match length in <strong>real minutes</strong>.
|
||||||
|
Valid values that appear in the lobby dropdown:
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<code>1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 20, 25, 30</code>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Other integers are accepted and applied to the network parameter but will not match a dropdown item
|
||||||
|
(the visual display may show the nearest value).
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Special value <code>-1</code>: use the server’s current default time (7 minutes unless changed separately).
|
||||||
|
</p>
|
||||||
|
<p>Default if key absent: server current default (equivalent to <code>-1</code>).</p>
|
||||||
|
|
||||||
|
<h3>4.7 <code>Radar</code> — integer</h3>
|
||||||
|
<table>
|
||||||
|
<tr><th>Value</th><th>Display</th><th>Description</th></tr>
|
||||||
|
<tr><td><code>0</code></td><td>Novice</td><td>All mechs visible, no range limit <span class="default-tag">DEFAULT</span></td></tr>
|
||||||
|
<tr><td><code>1</code></td><td>Normal</td><td>Standard radar with range cutoff</td></tr>
|
||||||
|
<tr><td><code>2</code></td><td>Team Only</td><td>Only your own team visible on radar</td></tr>
|
||||||
|
<tr><td><code>3</code></td><td>No Radar</td><td>Radar completely disabled for all players</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h3>4.8 <code>HeatOn</code> — integer</h3>
|
||||||
|
<table>
|
||||||
|
<tr><th>Value</th><th>Description</th></tr>
|
||||||
|
<tr><td><code>0</code></td><td>Off — heat never builds, weapons never overheat <span class="default-tag">DEFAULT</span></td></tr>
|
||||||
|
<tr><td><code>1</code></td><td>On — standard heat management enabled</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h3>4.9 <code>FriendlyFire</code> — integer</h3>
|
||||||
|
<table>
|
||||||
|
<tr><th>Value</th><th>Description</th></tr>
|
||||||
|
<tr><td><code>0</code></td><td>Off — friendly fire disabled <span class="default-tag">DEFAULT</span></td></tr>
|
||||||
|
<tr><td><code>1</code></td><td>On — 100% damage to teammates</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h3>4.10 <code>SplashDamage</code> — integer</h3>
|
||||||
|
<table>
|
||||||
|
<tr><th>Value</th><th>Description</th></tr>
|
||||||
|
<tr><td><code>0</code></td><td>Off <span class="default-tag">DEFAULT</span></td></tr>
|
||||||
|
<tr><td><code>1</code></td><td>On — area/splash damage from missiles and explosions</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h3>4.11 <code>UnlimitedAmmo</code> — integer</h3>
|
||||||
|
<table>
|
||||||
|
<tr><th>Value</th><th>Description</th></tr>
|
||||||
|
<tr><td><code>0</code></td><td>Off — ammo is finite</td></tr>
|
||||||
|
<tr><td><code>1</code></td><td>On — unlimited ammo <span class="default-tag">DEFAULT (console/arcade)</span></td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h3>4.12 <code>WeaponJam</code> — integer</h3>
|
||||||
|
<table>
|
||||||
|
<tr><th>Value</th><th>Description</th></tr>
|
||||||
|
<tr><td><code>0</code></td><td>Off <span class="default-tag">DEFAULT</span></td></tr>
|
||||||
|
<tr><td><code>1</code></td><td>On — weapons can randomly jam</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h3>4.13 <code>AdvanceMode</code> — integer</h3>
|
||||||
|
<table>
|
||||||
|
<tr><th>Value</th><th>Description</th></tr>
|
||||||
|
<tr><td><code>0</code></td><td>Off <span class="default-tag">DEFAULT</span></td></tr>
|
||||||
|
<tr><td><code>1</code></td><td>On</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h3>4.14 <code>ArmorMode</code> — integer</h3>
|
||||||
|
<table>
|
||||||
|
<tr><th>Value</th><th>Description</th></tr>
|
||||||
|
<tr><td><code>0</code></td><td>Off <span class="default-tag">DEFAULT</span></td></tr>
|
||||||
|
<tr><td><code>1</code></td><td>On</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h3>4.15 <code>TeamAllowed</code> — integer <span class="optional">(required for correct team/FFA slot display on first click)</span></h3>
|
||||||
|
<p>Must match the <code>GameType</code> selected. Controls whether <code>Team</code> or <code>Skin</code> is applied to slots, and whether team dropdowns are shown.</p>
|
||||||
|
<table>
|
||||||
|
<tr><th>Value</th><th>Description</th></tr>
|
||||||
|
<tr><td><code>0</code></td><td>FFA mode ? slot <code>Skin</code> field is used <span class="default-tag">DEFAULT</span></td></tr>
|
||||||
|
<tr><td><code>1</code></td><td>Team game ? slot <code>Team</code> field is used</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h3>4.16 <code>TeamCount</code> — integer <span class="optional">(optional, only when TeamAllowed=1)</span></h3>
|
||||||
|
<p>Number of teams. Valid range: 2–8. Default: <code>2</code>.</p>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h2>5. Sections: <code>[slot0]</code> through <code>[slot15]</code></h2>
|
||||||
|
|
||||||
|
<p>One section per roster slot, numbered starting from <strong>zero</strong>.</p>
|
||||||
|
|
||||||
|
<div class="warn">
|
||||||
|
<strong>Slots must be contiguous starting from <code>[slot0]</code>.</strong>
|
||||||
|
The parser stops at the first missing slot number. If <code>[slot2]</code> is absent,
|
||||||
|
<code>[slot3]</code> through <code>[slot15]</code> are never read, even if present in the file.
|
||||||
|
Do not skip numbers.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>Maximum: <strong>16 slots</strong> (indices 0–15). All slots are cleared before applying file data, so slots not defined in the file will be empty in the lobby after Load File is clicked.</p>
|
||||||
|
|
||||||
|
<pre><span class="section">[slot0]</span>
|
||||||
|
<span class="key">Type</span>=<span class="value">1</span>
|
||||||
|
<span class="key">PilotName</span>=<span class="value">Alpha One</span>
|
||||||
|
<span class="key">Mech</span>=<span class="value">Atlas</span>
|
||||||
|
<span class="key">Team</span>=<span class="value">0</span>
|
||||||
|
<span class="key">Skin</span>=<span class="value">0</span>
|
||||||
|
<span class="key">Decal</span>=<span class="value">3</span></pre>
|
||||||
|
|
||||||
|
<h3>5.1 <code>Type</code> — integer, required</h3>
|
||||||
|
<p>Determines what occupies this slot. All other fields are ignored when <code>Type=0</code>.</p>
|
||||||
|
<table>
|
||||||
|
<tr><th>Value</th><th>Description</th></tr>
|
||||||
|
<tr><td><code>0</code></td><td>Empty — slot skipped, left empty in lobby</td></tr>
|
||||||
|
<tr><td><code>1</code></td><td>Player slot — a human pilot can connect to this seat</td></tr>
|
||||||
|
<tr><td><code>2</code></td><td>Bot, difficulty level 1 (easiest)</td></tr>
|
||||||
|
<tr><td><code>3</code></td><td>Bot, difficulty level 2</td></tr>
|
||||||
|
<tr><td><code>4</code></td><td>Bot, difficulty level 3</td></tr>
|
||||||
|
<tr><td><code>5</code></td><td>Bot, difficulty level 4</td></tr>
|
||||||
|
<tr><td><code>6</code></td><td>Bot, difficulty level 5</td></tr>
|
||||||
|
<tr><td><code>7</code></td><td>Bot, difficulty level 6</td></tr>
|
||||||
|
<tr><td><code>8</code></td><td>Bot, difficulty level 7</td></tr>
|
||||||
|
<tr><td><code>9</code></td><td>Bot, difficulty level 8 (hardest)</td></tr>
|
||||||
|
</table>
|
||||||
|
<p>If <code>Type</code> key is absent, it defaults to <code>0</code> (empty) due to zero-initialization.</p>
|
||||||
|
|
||||||
|
<h3>5.2 <code>PilotName</code> — string, max 63 characters</h3>
|
||||||
|
<p>Only meaningful when <code>Type=1</code> (player slot). Sets the callsign shown in the lobby pilot editbox. The connecting player can override this after they connect.</p>
|
||||||
|
<p>For bots (<code>Type=2–9</code>), this field is read from the file but ignored by the script.</p>
|
||||||
|
<p>Set to empty value or omit key to leave the name blank: <code>PilotName=</code></p>
|
||||||
|
<p>Strings longer than 63 characters are silently truncated.</p>
|
||||||
|
|
||||||
|
<h3>5.3 <code>Mech</code> — string (chassis name, exact and case-sensitive)</h3>
|
||||||
|
<p>Must match <strong>exactly</strong> one of the chassis names from <code>MechTable.tbl</code>. The lookup is case-sensitive exact string comparison. If the name is not found, the mech dropdown for that slot stays at its previous value. No error is raised.</p>
|
||||||
|
|
||||||
|
<div class="warn">
|
||||||
|
<strong>These are the table key strings, not display labels.</strong>
|
||||||
|
Pay close attention to capitalization, spacing, and special characters (hyphens, Roman numerals).
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class="mech-table">
|
||||||
|
<tr><th>Exact <code>Mech=</code> value</th><th>Notes</th></tr>
|
||||||
|
<tr><td>Annihilator</td><td></td></tr>
|
||||||
|
<tr><td>Archer</td><td></td></tr>
|
||||||
|
<tr><td>Arctic Wolf</td><td>space between words</td></tr>
|
||||||
|
<tr><td>Ares</td><td></td></tr>
|
||||||
|
<tr><td>Argus</td><td></td></tr>
|
||||||
|
<tr><td>AssassinII</td><td>no spaces; capital I</td></tr>
|
||||||
|
<tr><td>Atlas</td><td></td></tr>
|
||||||
|
<tr><td>Avatar</td><td></td></tr>
|
||||||
|
<tr><td>Awesome</td><td></td></tr>
|
||||||
|
<tr><td>Battlemaster</td><td></td></tr>
|
||||||
|
<tr><td>BattlemasterIIC</td><td>no spaces</td></tr>
|
||||||
|
<tr><td>Behemoth</td><td></td></tr>
|
||||||
|
<tr><td>BehemothII</td><td>no space; capital I</td></tr>
|
||||||
|
<tr><td>Black Hawk</td><td>space between words</td></tr>
|
||||||
|
<tr><td>Black Knight</td><td>space between words</td></tr>
|
||||||
|
<tr><td>Black Lanner</td><td>space between words</td></tr>
|
||||||
|
<tr><td>Brigand</td><td></td></tr>
|
||||||
|
<tr><td>Bushwacker</td><td></td></tr>
|
||||||
|
<tr><td>Catapult</td><td></td></tr>
|
||||||
|
<tr><td>Cauldron-Born</td><td>hyphen between words</td></tr>
|
||||||
|
<tr><td>Chimera</td><td></td></tr>
|
||||||
|
<tr><td>Commando</td><td></td></tr>
|
||||||
|
<tr><td>Cougar</td><td></td></tr>
|
||||||
|
<tr><td>Cyclops</td><td></td></tr>
|
||||||
|
<tr><td>Daishi</td><td></td></tr>
|
||||||
|
<tr><td>Deimos</td><td></td></tr>
|
||||||
|
<tr><td>Dragon</td><td></td></tr>
|
||||||
|
<tr><td>Fafnir</td><td></td></tr>
|
||||||
|
<tr><td>Flea</td><td></td></tr>
|
||||||
|
<tr><td>Gladiator</td><td></td></tr>
|
||||||
|
<tr><td>Grizzly</td><td></td></tr>
|
||||||
|
<tr><td>Hauptmann</td><td></td></tr>
|
||||||
|
<tr><td>Hellhound</td><td></td></tr>
|
||||||
|
<tr><td>Hellspawn</td><td></td></tr>
|
||||||
|
<tr><td>Highlander</td><td></td></tr>
|
||||||
|
<tr><td>HollanderII</td><td>no space; capital I</td></tr>
|
||||||
|
<tr><td>Hunchback</td><td></td></tr>
|
||||||
|
<tr><td>Kodiak</td><td></td></tr>
|
||||||
|
<tr><td>Loki</td><td></td></tr>
|
||||||
|
<tr><td>Longbow</td><td></td></tr>
|
||||||
|
<tr><td>Mad Cat</td><td>space between words</td></tr>
|
||||||
|
<tr><td>Mad Cat MKII</td><td>space + "MKII" all caps, no period</td></tr>
|
||||||
|
<tr><td>Masakari</td><td></td></tr>
|
||||||
|
<tr><td>Mauler</td><td></td></tr>
|
||||||
|
<tr><td>Nova Cat</td><td>space between words</td></tr>
|
||||||
|
<tr><td>Osiris</td><td></td></tr>
|
||||||
|
<tr><td>Owens</td><td></td></tr>
|
||||||
|
<tr><td>Puma</td><td></td></tr>
|
||||||
|
<tr><td>Raven</td><td></td></tr>
|
||||||
|
<tr><td>Rifleman</td><td></td></tr>
|
||||||
|
<tr><td>Ryoken</td><td></td></tr>
|
||||||
|
<tr><td>Shadow Cat</td><td>space between words</td></tr>
|
||||||
|
<tr><td>Solitaire</td><td></td></tr>
|
||||||
|
<tr><td>Sunder</td><td></td></tr>
|
||||||
|
<tr><td>Templar</td><td></td></tr>
|
||||||
|
<tr><td>Thanatos</td><td></td></tr>
|
||||||
|
<tr><td>Thor</td><td></td></tr>
|
||||||
|
<tr><td>Uller</td><td></td></tr>
|
||||||
|
<tr><td>Urbanmech</td><td></td></tr>
|
||||||
|
<tr><td>Uziel</td><td></td></tr>
|
||||||
|
<tr><td>Victor</td><td></td></tr>
|
||||||
|
<tr><td>Vulture</td><td></td></tr>
|
||||||
|
<tr><td>Warhammer</td><td></td></tr>
|
||||||
|
<tr><td>Wolfhound</td><td></td></tr>
|
||||||
|
<tr><td>Zeus</td><td></td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h3>5.4 <code>Team</code> — integer</h3>
|
||||||
|
<p>
|
||||||
|
<strong>Only applied in team game modes</strong> (game types marked “Team” in Section 4.2 table).
|
||||||
|
<strong class="ignored-tag">IGNORED in FFA modes.</strong>
|
||||||
|
</p>
|
||||||
|
<table>
|
||||||
|
<tr><th>Value</th><th>Team</th><th>Default Color</th></tr>
|
||||||
|
<tr><td><code>0</code></td><td>Team 1</td><td>Blue</td></tr>
|
||||||
|
<tr><td><code>1</code></td><td>Team 2</td><td>Red</td></tr>
|
||||||
|
<tr><td><code>2</code></td><td>Team 3</td><td>Yellow</td></tr>
|
||||||
|
<tr><td><code>3</code></td><td>Team 4</td><td>Green</td></tr>
|
||||||
|
<tr><td><code>4</code></td><td>Team 5</td><td>Purple</td></tr>
|
||||||
|
<tr><td><code>5</code></td><td>Team 6</td><td>Light Blue</td></tr>
|
||||||
|
<tr><td><code>6</code></td><td>Team 7</td><td>Orange</td></tr>
|
||||||
|
<tr><td><code>7</code></td><td>Team 8</td><td>Charcoal</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h3>5.5 <code>Skin</code> — integer (FFA camo, dropdown index 0-based)</h3>
|
||||||
|
<p>
|
||||||
|
<strong>Only applied in FFA game modes.</strong>
|
||||||
|
<strong class="ignored-tag">IGNORED in team modes.</strong>
|
||||||
|
</p>
|
||||||
|
<table>
|
||||||
|
<tr><th>Value</th><th>Camo Color/Pattern</th></tr>
|
||||||
|
<tr><td><code>0</code></td><td>Blue</td></tr>
|
||||||
|
<tr><td><code>1</code></td><td>Red</td></tr>
|
||||||
|
<tr><td><code>2</code></td><td>Yellow</td></tr>
|
||||||
|
<tr><td><code>3</code></td><td>Green</td></tr>
|
||||||
|
<tr><td><code>4</code></td><td>Purple</td></tr>
|
||||||
|
<tr><td><code>5</code></td><td>Light Blue</td></tr>
|
||||||
|
<tr><td><code>6</code></td><td>Orange</td></tr>
|
||||||
|
<tr><td><code>7</code></td><td>Charcoal</td></tr>
|
||||||
|
<tr><td><code>8</code>–<code>15</code></td><td>Additional camo patterns</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h3>5.6 <code>Decal</code> — integer (faction emblem, 0–63)</h3>
|
||||||
|
<p>
|
||||||
|
Applied in <strong>both team and FFA modes.</strong>
|
||||||
|
Valid range: <code>0</code>–<code>63</code>. All values in range are accepted. Common values:
|
||||||
|
</p>
|
||||||
|
<table>
|
||||||
|
<tr><th>Value</th><th>Faction</th></tr>
|
||||||
|
<tr><td><code>0</code></td><td>None</td></tr>
|
||||||
|
<tr><td><code>2</code></td><td>Davion</td></tr>
|
||||||
|
<tr><td><code>3</code></td><td>Steiner</td></tr>
|
||||||
|
<tr><td><code>4</code></td><td>Kurita</td></tr>
|
||||||
|
<tr><td><code>5</code></td><td>Liao</td></tr>
|
||||||
|
<tr><td><code>6</code></td><td>Marik</td></tr>
|
||||||
|
<tr><td><code>9</code></td><td>ComStar</td></tr>
|
||||||
|
<tr><td><code>10</code></td><td>Star League</td></tr>
|
||||||
|
<tr><td><code>11</code></td><td>Wolf Clan</td></tr>
|
||||||
|
<tr><td><code>12</code></td><td>Jade Falcon</td></tr>
|
||||||
|
<tr><td><code>16</code></td><td>Ghost Bear</td></tr>
|
||||||
|
<tr><td><code>20</code></td><td>Hell Horses</td></tr>
|
||||||
|
<tr><td><code>21</code></td><td>Coyote</td></tr>
|
||||||
|
<tr><td><code>22</code></td><td>Blood Spirit</td></tr>
|
||||||
|
<tr><td><code>24</code></td><td>Ice Hellion</td></tr>
|
||||||
|
<tr><td><code>27</code></td><td>Goliath Scorpion</td></tr>
|
||||||
|
<tr><td><code>46</code></td><td>BKG</td></tr>
|
||||||
|
<tr><td><code>47</code></td><td>FSA</td></tr>
|
||||||
|
<tr><td><code>48</code></td><td>331st</td></tr>
|
||||||
|
<tr><td><code>49</code></td><td>DDC</td></tr>
|
||||||
|
<tr><td><code>50</code></td><td>VGL</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h2>6. Complete Example File</h2>
|
||||||
|
|
||||||
|
<pre><span class="section">[mission]</span>
|
||||||
|
<span class="key">MissionName</span>=<span class="value">ScarabStronghold - Attrition</span>
|
||||||
|
<span class="key">GameType</span>=<span class="value">2</span>
|
||||||
|
<span class="key">Visibility</span>=<span class="value">0</span>
|
||||||
|
<span class="key">Weather</span>=<span class="value">0</span>
|
||||||
|
<span class="key">TimeOfDay</span>=<span class="value">0</span>
|
||||||
|
<span class="key">TimeLimit</span>=<span class="value">7</span>
|
||||||
|
<span class="key">Radar</span>=<span class="value">0</span>
|
||||||
|
<span class="key">HeatOn</span>=<span class="value">0</span>
|
||||||
|
<span class="key">FriendlyFire</span>=<span class="value">0</span>
|
||||||
|
<span class="key">SplashDamage</span>=<span class="value">0</span>
|
||||||
|
<span class="key">UnlimitedAmmo</span>=<span class="value">1</span>
|
||||||
|
<span class="key">WeaponJam</span>=<span class="value">0</span>
|
||||||
|
<span class="key">AdvanceMode</span>=<span class="value">0</span>
|
||||||
|
<span class="key">ArmorMode</span>=<span class="value">0</span>
|
||||||
|
|
||||||
|
<span class="section">[slot0]</span>
|
||||||
|
<span class="key">Type</span>=<span class="value">1</span>
|
||||||
|
<span class="key">PilotName</span>=<span class="value">Blackjack</span>
|
||||||
|
<span class="key">Mech</span>=<span class="value">Atlas</span>
|
||||||
|
<span class="key">Team</span>=<span class="value">0</span>
|
||||||
|
<span class="key">Skin</span>=<span class="value">0</span>
|
||||||
|
<span class="key">Decal</span>=<span class="value">3</span>
|
||||||
|
|
||||||
|
<span class="section">[slot1]</span>
|
||||||
|
<span class="key">Type</span>=<span class="value">1</span>
|
||||||
|
<span class="key">PilotName</span>=<span class="value">Viper</span>
|
||||||
|
<span class="key">Mech</span>=<span class="value">Mad Cat</span>
|
||||||
|
<span class="key">Team</span>=<span class="value">0</span>
|
||||||
|
<span class="key">Skin</span>=<span class="value">1</span>
|
||||||
|
<span class="key">Decal</span>=<span class="value">4</span>
|
||||||
|
|
||||||
|
<span class="section">[slot2]</span>
|
||||||
|
<span class="key">Type</span>=<span class="value">2</span>
|
||||||
|
<span class="key">PilotName</span>=
|
||||||
|
<span class="key">Mech</span>=<span class="value">Thor</span>
|
||||||
|
<span class="key">Team</span>=<span class="value">1</span>
|
||||||
|
<span class="key">Skin</span>=<span class="value">1</span>
|
||||||
|
<span class="key">Decal</span>=<span class="value">4</span>
|
||||||
|
|
||||||
|
<span class="section">[slot3]</span>
|
||||||
|
<span class="key">Type</span>=<span class="value">2</span>
|
||||||
|
<span class="key">PilotName</span>=
|
||||||
|
<span class="key">Mech</span>=<span class="value">Warhammer</span>
|
||||||
|
<span class="key">Team</span>=<span class="value">1</span>
|
||||||
|
<span class="key">Skin</span>=<span class="value">1</span>
|
||||||
|
<span class="key">Decal</span>=<span class="value">4</span></pre>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h2>7. Known Constraints and Caveats</h2>
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li>
|
||||||
|
<strong>Slots must be numbered contiguously from <code>[slot0]</code>.</strong>
|
||||||
|
The parser uses a loop that breaks on the first missing section. Defining <code>[slot0]</code>
|
||||||
|
and <code>[slot2]</code> without <code>[slot1]</code> means only slot 0 is processed.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>All current slots are cleared before file slots are applied.</strong>
|
||||||
|
Any slot not defined in the file (or defined with <code>Type=0</code>) will be empty in the lobby.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Team vs. FFA display is correct on the first click</strong> provided <code>TeamAllowed=</code> is set correctly in the file.
|
||||||
|
The game updates <code>team_allowed</code> synchronously from this field before processing slots.
|
||||||
|
If <code>TeamAllowed</code> is absent, it defaults to <code>0</code> (FFA) regardless of <code>GameType</code>.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong><code>MissionName</code> and <code>Mech</code> matches are case-sensitive.</strong>
|
||||||
|
<code>atlas</code> will not match <code>Atlas</code>.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>The file is never deleted by the game.</strong>
|
||||||
|
Write it before the match, overwrite it before the next match. No locking is performed.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong><code>options.ini</code> is read only at game startup.</strong>
|
||||||
|
Changing the <code>automaticfile</code> path or enabling/disabling the feature requires a restart.
|
||||||
|
The config file itself is re-read fresh on every Load File button click.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Buffer limits:</strong> <code>PilotName</code> ≤ 63 chars (truncated silently);
|
||||||
|
<code>MissionName</code> ≤ 255 chars;
|
||||||
|
<code>automaticfile</code> path ≤ 259 chars (<code>MAX_PATH − 1</code>).
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Mech names are sourced from <code>MechTable.tbl</code>.</strong>
|
||||||
|
If the game installation has custom mechs added or some mechs removed, the valid name list
|
||||||
|
changes accordingly. The table above reflects the standard Firestorm build.
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<p style="font-size:9pt; color:#888; text-align:center; margin-top:30px;">
|
||||||
|
Generated from source: <code>MW4Shell.cpp</code> — <code>CTCL_LoadAutoFile</code>,
|
||||||
|
<code>CTCL_GetAutoSlotName/Mech/Int</code> |
|
||||||
|
<code>ConLobby.script</code> — <code>o_load_file</code> handler |
|
||||||
|
<code>ConLobbyMission.script</code> — <code>MAIL_LOAD_AUTO_MISSION</code> |
|
||||||
|
Commit cd2fe73c | 2026-07-24
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Generate special_weapon_locations.csv and rear_facing_weapons.csv from stock mech subsystems."""
|
||||||
|
import csv
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
BASE = Path("Gameleap/mw4/Content")
|
||||||
|
MECH_TABLE = BASE / "Tables" / "MechTable.tbl"
|
||||||
|
OUT_DIR = Path("BTFrstrm")
|
||||||
|
|
||||||
|
def parse_ini(path):
|
||||||
|
sections, cur_sec, cur_dict = [], None, {}
|
||||||
|
with open(path, 'r', encoding='latin-1', errors='replace') as f:
|
||||||
|
for raw in f:
|
||||||
|
line = raw.strip()
|
||||||
|
if line.startswith('[') and line.endswith(']'):
|
||||||
|
if cur_sec is not None:
|
||||||
|
sections.append((cur_sec, cur_dict))
|
||||||
|
cur_sec, cur_dict = line[1:-1], {}
|
||||||
|
elif '=' in line and cur_sec is not None:
|
||||||
|
k, _, v = line.partition('=')
|
||||||
|
cur_dict[k.strip()] = v.strip()
|
||||||
|
if cur_sec is not None:
|
||||||
|
sections.append((cur_sec, cur_dict))
|
||||||
|
return sections
|
||||||
|
|
||||||
|
def find_dir_ci(parent, name):
|
||||||
|
"""Case-insensitive directory lookup for Linux."""
|
||||||
|
exact = parent / name
|
||||||
|
if exact.exists():
|
||||||
|
return exact
|
||||||
|
name_lower = name.lower()
|
||||||
|
for child in parent.iterdir():
|
||||||
|
if child.is_dir() and child.name.lower() == name_lower:
|
||||||
|
return child
|
||||||
|
return None
|
||||||
|
|
||||||
|
def weapon_model(model_path):
|
||||||
|
return Path(model_path.replace('\\', '/')).stem
|
||||||
|
|
||||||
|
# Read chassis list from MechTable.tbl
|
||||||
|
chassis_list = []
|
||||||
|
with open(MECH_TABLE, 'r', encoding='latin-1') as f:
|
||||||
|
for raw in f:
|
||||||
|
line = raw.strip()
|
||||||
|
if not line or line.startswith('//') or line.startswith('[') or '=' not in line:
|
||||||
|
continue
|
||||||
|
name, _, rel = line.partition('=')
|
||||||
|
# rel is like "Mechs\Atlas\Atlas.instance"
|
||||||
|
parts = rel.strip().replace('\\', '/').split('/')
|
||||||
|
chassis_list.append((name.strip(), parts)) # parts = ['Mechs', 'Atlas', 'Atlas.instance']
|
||||||
|
|
||||||
|
print(f"Found {len(chassis_list)} chassis in MechTable.tbl")
|
||||||
|
|
||||||
|
HDR = ['Chassis', 'InternalLocation', 'Model', 'Site', 'AmmoCount', 'GroupIndex', 'WeaponFacing']
|
||||||
|
special_rows, rear_rows, missing = [], [], []
|
||||||
|
|
||||||
|
mechs_dir = BASE / "Mechs"
|
||||||
|
|
||||||
|
for chassis_name, path_parts in chassis_list:
|
||||||
|
# path_parts[1] is the mech directory name (e.g. 'Atlas', 'MadCat_MkII', 'Urbanmech')
|
||||||
|
if len(path_parts) < 2:
|
||||||
|
missing.append(chassis_name)
|
||||||
|
continue
|
||||||
|
|
||||||
|
mech_dir = find_dir_ci(mechs_dir, path_parts[1])
|
||||||
|
if not mech_dir:
|
||||||
|
missing.append(f"{chassis_name} (dir not found: {path_parts[1]})")
|
||||||
|
continue
|
||||||
|
|
||||||
|
subs = [f for f in mech_dir.glob('*.subsystems') if f.suffix == '.subsystems']
|
||||||
|
if not subs:
|
||||||
|
missing.append(f"{chassis_name} (no .subsystems in {mech_dir.name})")
|
||||||
|
continue
|
||||||
|
|
||||||
|
subsys_file = subs[0]
|
||||||
|
sections = parse_ini(subsys_file)
|
||||||
|
|
||||||
|
for sec_name, fields in sections:
|
||||||
|
if 'WeaponSubsystem' not in fields.get('Model', ''):
|
||||||
|
continue
|
||||||
|
|
||||||
|
loc = fields.get('InternalLocation', '')
|
||||||
|
model = weapon_model(fields.get('Model', ''))
|
||||||
|
site = fields.get('Site', '')
|
||||||
|
ammo = fields.get('AmmoCount', '')
|
||||||
|
group = fields.get('GroupIndex', '')
|
||||||
|
facing = fields.get('WeaponFacing', '')
|
||||||
|
|
||||||
|
if loc in ('Special1', 'Special2'):
|
||||||
|
special_rows.append([chassis_name, loc, model, site, ammo, group, facing])
|
||||||
|
|
||||||
|
if facing and facing != '0':
|
||||||
|
rear_rows.append([chassis_name, loc, model, site, ammo, group, facing])
|
||||||
|
|
||||||
|
# Write CSVs
|
||||||
|
out1 = OUT_DIR / 'special_weapon_locations.csv'
|
||||||
|
with open(out1, 'w', newline='') as f:
|
||||||
|
w = csv.writer(f)
|
||||||
|
w.writerow(HDR)
|
||||||
|
w.writerows(special_rows)
|
||||||
|
|
||||||
|
out2 = OUT_DIR / 'rear_facing_weapons.csv'
|
||||||
|
with open(out2, 'w', newline='') as f:
|
||||||
|
w = csv.writer(f)
|
||||||
|
w.writerow(HDR)
|
||||||
|
w.writerows(rear_rows)
|
||||||
|
|
||||||
|
print(f"Spreadsheet 1 ? Special1/2 weapon locations: {len(special_rows)} rows -> {out1}")
|
||||||
|
print(f"Spreadsheet 2 ? Non-forward WeaponFacing: {len(rear_rows)} rows -> {out2}")
|
||||||
|
if missing:
|
||||||
|
print(f"\nSkipped: {missing}")
|
||||||
@@ -292,3 +292,363 @@ At the time this doc was written:
|
|||||||
- non-playable mechs are explicitly marked `No`
|
- non-playable mechs are explicitly marked `No`
|
||||||
- Templar and other mechs with rear or side mounts have facing visible in the CSV
|
- 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
|
- 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, 0–100 |
|
||||||
|
| `ArmorRating` | `ArmorRating` | mechlab bar value, 0–100 |
|
||||||
|
| `SpeedRating` | `SpeedRating` | mechlab bar value, 0–100 |
|
||||||
|
| `HeatRating` | `HeatRating` | mechlab bar value, 0–100 |
|
||||||
|
| `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` (0–5)
|
||||||
|
|
||||||
|
**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` (0–5)
|
||||||
|
- 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.
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
Chassis,InternalLocation,Model,Site,AmmoCount,GroupIndex,WeaponFacing
|
||||||
|
Archer,LeftTorso,LRM15,site_ldmissile,24,2,2
|
||||||
|
Archer,RightTorso,LRM15,site_rdmissile,24,2,2
|
||||||
|
Ares,Special2,ClanLRM10,site_lmissileport,24,2,2
|
||||||
|
Ares,Special2,ClanLRM10,site_missileport,24,2,2
|
||||||
|
Ares,Special2,ClanLRM10,site_rmissileport,24,2,2
|
||||||
|
AssassinII,Special1,LRM5,site_missileport,24,2,2
|
||||||
|
Atlas,LeftTorso,LRM20,site_lmissileport,12,2,2
|
||||||
|
Avatar,LeftTorso,LRM5,site_lmissileport,24,2,2
|
||||||
|
Avatar,RightTorso,LRM5,site_rmissileport,24,2,2
|
||||||
|
Avatar,LeftTorso,LRM10,site_lmissileport,24,2,2
|
||||||
|
Avatar,RightTorso,LRM10,site_rmissileport,24,2,2
|
||||||
|
Awesome,CenterTorso,LRM5,site_ctorsoport,24,2,2
|
||||||
|
Battlemaster,RightTorso,MediumLaser,site_rdtorsoport,,1,1
|
||||||
|
Battlemaster,LeftTorso,MediumLaser,site_ldtorsoport,,1,1
|
||||||
|
BattlemasterIIC,RightTorso,ClanERMediumLaser,site_rdtorsoport,,1,1
|
||||||
|
BattlemasterIIC,LeftTorso,ClanERMediumLaser,site_ldtorsoport,,1,1
|
||||||
|
Black Lanner,Special2,ClanSRM6,site_rmissileport,15,2,2
|
||||||
|
Black Lanner,Special1,ClanLRM10,site_lmissileport,24,2,2
|
||||||
|
Bushwacker,Special1,LRM5,site_missileport,24,2,2
|
||||||
|
Bushwacker,Special1,LRM5,site_missileport,24,2,2
|
||||||
|
Catapult,LeftArm,LRM20,site_lmissileport,12,2,2
|
||||||
|
Catapult,RightArm,LRM20,site_rmissileport,12,2,2
|
||||||
|
Cauldron-Born,Special1,ClanLRM10,site_rmissileport,24,2,2
|
||||||
|
Cauldron-Born,Special2,ClanLRM10,site_lmissileport,24,2,2
|
||||||
|
Chimera,RightTorso,LRM5,site_missileport,24,2,2
|
||||||
|
Chimera,RightTorso,LRM5,site_missileport,24,2,2
|
||||||
|
Chimera,RightTorso,LRM5,site_missileport,24,2,2
|
||||||
|
Chimera,RightTorso,LRM5,site_missileport,24,2,2
|
||||||
|
Cyclops,LeftTorso,LRM10,site_lmissile,24,2,2
|
||||||
|
Cougar,LeftTorso,ClanLRM10,site_lmissileport,12,2,2
|
||||||
|
Cougar,RightTorso,ClanLRM10,site_rmissileport,12,2,2
|
||||||
|
Deimos,Special1,ClanLRM15,site_lmissileport,16,2,2
|
||||||
|
Deimos,Special2,ClanLRM15,site_rmissileport,16,2,2
|
||||||
|
Dragon,CenterTorso,LRM10,site_missleport,24,2,2
|
||||||
|
Flea,LeftTorso,SmallLaser,site_ltorsoport,,1,1
|
||||||
|
Flea,RightTorso,SmallLaser,site_rtorsoport,,1,1
|
||||||
|
Grizzly,LeftTorso,CLANLRM10,site_missleport,24,2,2
|
||||||
|
Hellhound,LeftTorso,ClanLRM10,site_missileport,12,2,2
|
||||||
|
Mad Cat,Special1,ClanLRM10,site_lmissileport,24,2,2
|
||||||
|
Mad Cat,Special2,ClanLRM10,site_rmissileport,24,2,2
|
||||||
|
Mad Cat MKII,Special2,ClanLRM15,site_lmissileport,16,2,2
|
||||||
|
Mad Cat MKII,Special1,ClanLRM15,site_rmissileport,16,2,2
|
||||||
|
Masakari,LeftTorso,ClanLRM10,site_lmissleport,24,2,2
|
||||||
|
Masakari,LeftTorso,ClanLRM10,site_ltorsoport,24,2,2
|
||||||
|
Mauler,LeftTorso,LRM5,site_lmissileport,24,2,2
|
||||||
|
Mauler,LeftTorso,LRM5,site_lmissileport,24,2,2
|
||||||
|
Mauler,LeftTorso,LRM5,site_lmissileport,24,2,2
|
||||||
|
Mauler,RightTorso,LRM5,site_rmissileport,24,2,2
|
||||||
|
Mauler,RightTorso,LRM5,site_rmissileport,24,2,2
|
||||||
|
Mauler,RightTorso,LRM5,site_rmissileport,24,2,2
|
||||||
|
Raven,RightTorso,LRM5,site_rtorsoport,24,2,2
|
||||||
|
Sunder,LeftTorso,MediumLaser,site_ldtorsoport,,1,1
|
||||||
|
Sunder,RightTorso,MediumLaser,site_rdtorsoport,,1,1
|
||||||
|
Templar,LeftTorso,MediumPulseLaser,site_ldrtorsoport,,1,1
|
||||||
|
Templar,RightTorso,MediumPulseLaser,site_rdrtorsoport,,1,1
|
||||||
|
Thor,Special1,CLANLRM10,site_missileport,24,2,2
|
||||||
|
Uziel,Special1,LRM10,site_missileport,24,2,2
|
||||||
|
Vulture,LeftTorso,ClanLRM5,site_lmissileport,24,2,2
|
||||||
|
Vulture,RightTorso,ClanLRM5,site_rmissileport,24,2,2
|
||||||
|
Vulture,LeftTorso,ClanLRM10,site_lmissileport,24,2,2
|
||||||
|
Vulture,RightTorso,ClanLRM10,site_rmissileport,24,2,2
|
||||||
|
Wolfhound,CenterTorso,ClanERMediumLaser,site_reartorsoport,,1,1
|
||||||
|
Zeus,RightTorso,MediumPulseLaser,site_reartorsoport,,1,1
|
||||||
|
@@ -0,0 +1,45 @@
|
|||||||
|
Chassis,InternalLocation,Model,Site,AmmoCount,GroupIndex,WeaponFacing
|
||||||
|
Ares,Special1,ClanERSmallLaser,site_lgunport,,1,
|
||||||
|
Ares,Special1,ClanERSmallLaser,site_rgunport,,1,
|
||||||
|
Ares,Special2,ClanLRM10,site_lmissileport,24,2,2
|
||||||
|
Ares,Special2,ClanLRM10,site_missileport,24,2,2
|
||||||
|
Ares,Special2,ClanLRM10,site_rmissileport,24,2,2
|
||||||
|
AssassinII,Special1,LRM5,site_missileport,24,2,2
|
||||||
|
Atlas,Special1,AC20,site_rtorsoport,10,1,
|
||||||
|
Atlas,Special2,SRM6,site_llmissile,15,2,
|
||||||
|
Avatar,Special1,MachineGun,site_ltorsoport,200,1,
|
||||||
|
Avatar,Special1,MachineGun,site_rtorsoport,200,1,
|
||||||
|
Battlemaster,Special2,PPC,site_rdgunport,,1,
|
||||||
|
Battlemaster,Special1,SRM6,site_missile,15,2,
|
||||||
|
BattlemasterIIC,Special1,ClanSSRM6,site_missile,15,2,
|
||||||
|
Behemoth,Special1,LargeLaser,site_ctorsoport,,1,
|
||||||
|
BehemothII,Special1,LargeLaser,site_ctorsoport,,1,
|
||||||
|
Black Lanner,Special2,ClanSRM6,site_rmissileport,15,2,2
|
||||||
|
Black Lanner,Special1,ClanLRM10,site_lmissileport,24,2,2
|
||||||
|
Brigand,Special2,MediumLaser,site_ltorsoport,,1,
|
||||||
|
Brigand,Special1,MediumLaser,site_rtorsoport,,1,
|
||||||
|
Bushwacker,Special1,LRM5,site_missileport,24,2,2
|
||||||
|
Bushwacker,Special1,LRM5,site_missileport,24,2,2
|
||||||
|
Cauldron-Born,Special1,ClanLRM10,site_rmissileport,24,2,2
|
||||||
|
Cauldron-Born,Special2,ClanLRM10,site_lmissileport,24,2,2
|
||||||
|
Cyclops,Special1,MediumPulseLaser,site_gunport,,1,
|
||||||
|
Deimos,Special1,ClanLRM15,site_lmissileport,16,2,2
|
||||||
|
Deimos,Special2,ClanLRM15,site_rmissileport,16,2,2
|
||||||
|
Hauptmann,Special1,ClanUltraAC20,site_rutorsoport,16,1,
|
||||||
|
Hellspawn,Special1,SSRM2,site_rmissileport,50,2,
|
||||||
|
HollanderII,Special2,SmallPulseLaser,site_cltorsoport,,1,
|
||||||
|
HollanderII,Special2,SmallPulseLaser,site_crtorsoport,,1,
|
||||||
|
HollanderII,Special1,GaussRifle,site_rtorsoport,16,1,
|
||||||
|
Hunchback,Special1,AC10,site_rutorsoport,20,1,
|
||||||
|
Loki,Special1,ClanSSRM6,site_missileport,15,2,
|
||||||
|
Mad Cat,Special1,ClanLRM10,site_lmissileport,24,2,2
|
||||||
|
Mad Cat,Special2,ClanLRM10,site_rmissileport,24,2,2
|
||||||
|
Mad Cat MKII,Special2,ClanLRM15,site_lmissileport,16,2,2
|
||||||
|
Mad Cat MKII,Special1,ClanLRM15,site_rmissileport,16,2,2
|
||||||
|
Rifleman,Special1,MediumLaser,site_ltorsoport,,1,
|
||||||
|
Rifleman,Special1,MediumLaser,site_rtorsoport,,1,
|
||||||
|
Solitaire,Special1,ClanERLargeLaser,site_rtorsoport,,1,
|
||||||
|
Thor,Special1,CLANLRM10,site_missileport,24,2,2
|
||||||
|
Uziel,Special1,LRM10,site_missileport,24,2,2
|
||||||
|
Vulture,Special1,ClanMachineGun,site_ltorsoport,200,1,
|
||||||
|
Vulture,Special1,ClanMachineGun,site_rtorsoport,200,1,
|
||||||
|
@@ -0,0 +1,144 @@
|
|||||||
|
[mission]
|
||||||
|
MissionName=Coliseum - Attrition
|
||||||
|
GameType=2
|
||||||
|
TeamAllowed=0
|
||||||
|
Visibility=1
|
||||||
|
Weather=0
|
||||||
|
TimeOfDay=0
|
||||||
|
TimeLimit=15
|
||||||
|
Radar=0
|
||||||
|
HeatOn=0
|
||||||
|
FriendlyFire=1
|
||||||
|
SplashDamage=1
|
||||||
|
UnlimitedAmmo=0
|
||||||
|
WeaponJam=1
|
||||||
|
AdvanceMode=1
|
||||||
|
ArmorMode=1
|
||||||
|
|
||||||
|
[slot0]
|
||||||
|
Type=1
|
||||||
|
PilotName=Viper
|
||||||
|
Mech=Atlas
|
||||||
|
Team=0
|
||||||
|
Skin=0
|
||||||
|
Decal=3
|
||||||
|
|
||||||
|
[slot1]
|
||||||
|
Type=1
|
||||||
|
PilotName=Blackjack
|
||||||
|
Mech=Mad Cat
|
||||||
|
Team=0
|
||||||
|
Skin=1
|
||||||
|
Decal=4
|
||||||
|
|
||||||
|
[slot2]
|
||||||
|
Type=1
|
||||||
|
PilotName=Ghost
|
||||||
|
Mech=Warhammer
|
||||||
|
Team=0
|
||||||
|
Skin=2
|
||||||
|
Decal=2
|
||||||
|
|
||||||
|
[slot3]
|
||||||
|
Type=1
|
||||||
|
PilotName=Maverick
|
||||||
|
Mech=Thor
|
||||||
|
Team=0
|
||||||
|
Skin=3
|
||||||
|
Decal=5
|
||||||
|
|
||||||
|
[slot4]
|
||||||
|
Type=1
|
||||||
|
PilotName=Reaper
|
||||||
|
Mech=Loki
|
||||||
|
Team=0
|
||||||
|
Skin=4
|
||||||
|
Decal=6
|
||||||
|
|
||||||
|
[slot5]
|
||||||
|
Type=1
|
||||||
|
PilotName=Phoenix
|
||||||
|
Mech=Daishi
|
||||||
|
Team=0
|
||||||
|
Skin=5
|
||||||
|
Decal=9
|
||||||
|
|
||||||
|
[slot6]
|
||||||
|
Type=1
|
||||||
|
PilotName=Hammer
|
||||||
|
Mech=Shadow Cat
|
||||||
|
Team=0
|
||||||
|
Skin=6
|
||||||
|
Decal=10
|
||||||
|
|
||||||
|
[slot7]
|
||||||
|
Type=1
|
||||||
|
PilotName=Blade
|
||||||
|
Mech=Battlemaster
|
||||||
|
Team=0
|
||||||
|
Skin=7
|
||||||
|
Decal=11
|
||||||
|
|
||||||
|
[slot8]
|
||||||
|
Type=1
|
||||||
|
PilotName=Ironside
|
||||||
|
Mech=Cauldron-Born
|
||||||
|
Team=0
|
||||||
|
Skin=8
|
||||||
|
Decal=12
|
||||||
|
|
||||||
|
[slot9]
|
||||||
|
Type=1
|
||||||
|
PilotName=Tempest
|
||||||
|
Mech=Vulture
|
||||||
|
Team=0
|
||||||
|
Skin=9
|
||||||
|
Decal=3
|
||||||
|
|
||||||
|
[slot10]
|
||||||
|
Type=1
|
||||||
|
PilotName=Saber
|
||||||
|
Mech=Black Hawk
|
||||||
|
Team=0
|
||||||
|
Skin=10
|
||||||
|
Decal=16
|
||||||
|
|
||||||
|
[slot11]
|
||||||
|
Type=1
|
||||||
|
PilotName=Ajax
|
||||||
|
Mech=Archer
|
||||||
|
Team=0
|
||||||
|
Skin=11
|
||||||
|
Decal=49
|
||||||
|
|
||||||
|
[slot12]
|
||||||
|
Type=1
|
||||||
|
PilotName=Thunder
|
||||||
|
Mech=Kodiak
|
||||||
|
Team=0
|
||||||
|
Skin=12
|
||||||
|
Decal=2
|
||||||
|
|
||||||
|
[slot13]
|
||||||
|
Type=1
|
||||||
|
PilotName=Raven
|
||||||
|
Mech=Uziel
|
||||||
|
Team=0
|
||||||
|
Skin=13
|
||||||
|
Decal=50
|
||||||
|
|
||||||
|
[slot14]
|
||||||
|
Type=1
|
||||||
|
PilotName=Wraith
|
||||||
|
Mech=Grizzly
|
||||||
|
Team=0
|
||||||
|
Skin=14
|
||||||
|
Decal=48
|
||||||
|
|
||||||
|
[slot15]
|
||||||
|
Type=1
|
||||||
|
PilotName=Goliath
|
||||||
|
Mech=Annihilator
|
||||||
|
Team=0
|
||||||
|
Skin=15
|
||||||
|
Decal=5
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
[mission]
|
||||||
|
MissionName=CentralPark - Team KotH
|
||||||
|
GameType=6
|
||||||
|
TeamAllowed=1
|
||||||
|
TeamCount=4
|
||||||
|
Visibility=1
|
||||||
|
Weather=0
|
||||||
|
TimeOfDay=0
|
||||||
|
TimeLimit=15
|
||||||
|
Radar=0
|
||||||
|
HeatOn=0
|
||||||
|
FriendlyFire=1
|
||||||
|
SplashDamage=1
|
||||||
|
UnlimitedAmmo=0
|
||||||
|
WeaponJam=1
|
||||||
|
AdvanceMode=1
|
||||||
|
ArmorMode=1
|
||||||
|
|
||||||
|
[slot0]
|
||||||
|
Type=1
|
||||||
|
PilotName=Viper
|
||||||
|
Mech=Atlas
|
||||||
|
Team=0
|
||||||
|
Skin=0
|
||||||
|
Decal=3
|
||||||
|
|
||||||
|
[slot1]
|
||||||
|
Type=1
|
||||||
|
PilotName=Blackjack
|
||||||
|
Mech=Mad Cat
|
||||||
|
Team=0
|
||||||
|
Skin=0
|
||||||
|
Decal=3
|
||||||
|
|
||||||
|
[slot2]
|
||||||
|
Type=1
|
||||||
|
PilotName=Ghost
|
||||||
|
Mech=Warhammer
|
||||||
|
Team=0
|
||||||
|
Skin=0
|
||||||
|
Decal=3
|
||||||
|
|
||||||
|
[slot3]
|
||||||
|
Type=1
|
||||||
|
PilotName=Maverick
|
||||||
|
Mech=Thor
|
||||||
|
Team=0
|
||||||
|
Skin=0
|
||||||
|
Decal=3
|
||||||
|
|
||||||
|
[slot4]
|
||||||
|
Type=1
|
||||||
|
PilotName=Reaper
|
||||||
|
Mech=Loki
|
||||||
|
Team=1
|
||||||
|
Skin=1
|
||||||
|
Decal=4
|
||||||
|
|
||||||
|
[slot5]
|
||||||
|
Type=1
|
||||||
|
PilotName=Phoenix
|
||||||
|
Mech=Daishi
|
||||||
|
Team=1
|
||||||
|
Skin=1
|
||||||
|
Decal=4
|
||||||
|
|
||||||
|
[slot6]
|
||||||
|
Type=1
|
||||||
|
PilotName=Hammer
|
||||||
|
Mech=Shadow Cat
|
||||||
|
Team=1
|
||||||
|
Skin=1
|
||||||
|
Decal=4
|
||||||
|
|
||||||
|
[slot7]
|
||||||
|
Type=1
|
||||||
|
PilotName=Blade
|
||||||
|
Mech=Battlemaster
|
||||||
|
Team=1
|
||||||
|
Skin=1
|
||||||
|
Decal=4
|
||||||
|
|
||||||
|
[slot8]
|
||||||
|
Type=1
|
||||||
|
PilotName=Ironside
|
||||||
|
Mech=Cauldron-Born
|
||||||
|
Team=2
|
||||||
|
Skin=2
|
||||||
|
Decal=2
|
||||||
|
|
||||||
|
[slot9]
|
||||||
|
Type=1
|
||||||
|
PilotName=Tempest
|
||||||
|
Mech=Vulture
|
||||||
|
Team=2
|
||||||
|
Skin=2
|
||||||
|
Decal=2
|
||||||
|
|
||||||
|
[slot10]
|
||||||
|
Type=1
|
||||||
|
PilotName=Saber
|
||||||
|
Mech=Black Hawk
|
||||||
|
Team=2
|
||||||
|
Skin=2
|
||||||
|
Decal=2
|
||||||
|
|
||||||
|
[slot11]
|
||||||
|
Type=1
|
||||||
|
PilotName=Ajax
|
||||||
|
Mech=Archer
|
||||||
|
Team=2
|
||||||
|
Skin=2
|
||||||
|
Decal=2
|
||||||
|
|
||||||
|
[slot12]
|
||||||
|
Type=1
|
||||||
|
PilotName=Thunder
|
||||||
|
Mech=Kodiak
|
||||||
|
Team=3
|
||||||
|
Skin=3
|
||||||
|
Decal=5
|
||||||
|
|
||||||
|
[slot13]
|
||||||
|
Type=1
|
||||||
|
PilotName=Raven
|
||||||
|
Mech=Uziel
|
||||||
|
Team=3
|
||||||
|
Skin=3
|
||||||
|
Decal=5
|
||||||
|
|
||||||
|
[slot14]
|
||||||
|
Type=1
|
||||||
|
PilotName=Wraith
|
||||||
|
Mech=Grizzly
|
||||||
|
Team=3
|
||||||
|
Skin=3
|
||||||
|
Decal=5
|
||||||
|
|
||||||
|
[slot15]
|
||||||
|
Type=1
|
||||||
|
PilotName=Goliath
|
||||||
|
Mech=Annihilator
|
||||||
|
Team=3
|
||||||
|
Skin=3
|
||||||
|
Decal=5
|
||||||
@@ -795,6 +795,118 @@ keeping old-RIO (type 0) protocol behavior byte-identical:
|
|||||||
alongside `mw4print.exe`.
|
alongside `mw4print.exe`.
|
||||||
- Version bumped to **2.0**, copyright year updated to **2026**.
|
- 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 3–4 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 3–4 from previous cycle) + right `BeginScene` (clear + grid)
|
||||||
|
- `sh_step 2–4`: channels 0–2 → left device
|
||||||
|
- `sh_step 5–6`: channels 3–4 → right device
|
||||||
|
- `sh_step 0` (next): flip radar + left MFD (shows channels 0–2 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)
|
## Next steps (proposed)
|
||||||
- [x] ~~Windowed 3D viewport on Win11~~ — DONE via DDrawCompat (see STEP 8 viewport section).
|
- [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\`).
|
- [ ] (Optional) Curate remaining WIP content as features are exercised (editor loads dev `Content\`).
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#include "recscore.h"
|
#include "recscore.h"
|
||||||
#endif // !defined(CTCLS_EXPORTS) && !defined(CTCL_LAUNCHER)
|
#endif // !defined(CTCLS_EXPORTS) && !defined(CTCL_LAUNCHER)
|
||||||
|
|
||||||
#define MAX_TESLAS 31
|
#define MAX_TESLAS 16
|
||||||
#define MAX_CAMERAS 4
|
#define MAX_CAMERAS 4
|
||||||
|
|
||||||
#define PORT_Launcher 1000
|
#define PORT_Launcher 1000
|
||||||
@@ -260,7 +260,7 @@ CInviteCOOP g_InviteCOOP;
|
|||||||
// Mech4 only
|
// Mech4 only
|
||||||
int g_nMech4Comm = 0;
|
int g_nMech4Comm = 0;
|
||||||
BOOL g_bIsServer = FALSE;
|
BOOL g_bIsServer = FALSE;
|
||||||
SPlayerInfo g_aPlayerInfos[35]; // 31 pilots + 1 CS + 3 spare
|
SPlayerInfo g_aPlayerInfos[20];
|
||||||
int g_nPlayerInfos;
|
int g_nPlayerInfos;
|
||||||
int g_nServer;
|
int g_nServer;
|
||||||
int g_nTeslas;
|
int g_nTeslas;
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ LONG g_LeftPedalLast = 0;
|
|||||||
LONG g_RightPedalLast = 0;
|
LONG g_RightPedalLast = 0;
|
||||||
BOOL g_StartGame = FALSE;
|
BOOL g_StartGame = FALSE;
|
||||||
|
|
||||||
static int g_nOpenComState = 0; // 鉉
|
static int g_nOpenComState = 0; // hyun
|
||||||
|
|
||||||
DWORD g_dwLastAnalogUpdate = 0;
|
DWORD g_dwLastAnalogUpdate = 0;
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ DWORD g_dwLastAnalogUpdate = 0;
|
|||||||
#define RESTART_CHAR 0xFE
|
#define RESTART_CHAR 0xFE
|
||||||
#define IDLE_CHAR 0xFF
|
#define IDLE_CHAR 0xFF
|
||||||
|
|
||||||
//member 변수처럼 활용할것.
|
//Use it like a member variable.
|
||||||
static HANDLE g_hCom = INVALID_HANDLE_VALUE;
|
static HANDLE g_hCom = INVALID_HANDLE_VALUE;
|
||||||
static OVERLAPPED wos;
|
static OVERLAPPED wos;
|
||||||
static OVERLAPPED ros;
|
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
|
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_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
|
int g_nEjectButton = 61; // 61: original, 31: new type
|
||||||
BYTE* g_pbRIOLengths = NULL;
|
BYTE* g_pbRIOLengths = NULL;
|
||||||
int g_nRIOPacketCount = 0;
|
int g_nRIOPacketCount = 0;
|
||||||
@@ -318,7 +319,7 @@ void RequestVersion();
|
|||||||
void RequestAnalogUpdate(BYTE bFreq = 3);
|
void RequestAnalogUpdate(BYTE bFreq = 3);
|
||||||
|
|
||||||
// start - for new RIO Board only...
|
// 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];
|
BYTE received_buffer[128][16];
|
||||||
int received_packet=0;//packets count in the received_buffer.
|
int received_packet=0;//packets count in the received_buffer.
|
||||||
DWORD received_serial=0;
|
DWORD received_serial=0;
|
||||||
@@ -569,7 +570,7 @@ BOOL SetupConnection(HANDLE hCom)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
원래 처리 루틴..
|
Original processing routine..
|
||||||
NPTTYINFO npTTYInfo=0 ;
|
NPTTYINFO npTTYInfo=0 ;
|
||||||
BYTE bset1 = (BYTE) ((FLOWCTRL( npTTYInfo ) & FC_DTRDSR) != 0) ;
|
BYTE bset1 = (BYTE) ((FLOWCTRL( npTTYInfo ) & FC_DTRDSR) != 0) ;
|
||||||
BYTE bset2 = (BYTE) ((FLOWCTRL( npTTYInfo ) & FC_RTSCTS) != 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 fDsrSensitivity:1; // DSR sensitivity
|
||||||
DWORD fTXContinueOnXoff:1; // XOFF continues Tx
|
DWORD fTXContinueOnXoff:1; // XOFF continues Tx
|
||||||
DWORD fErrorChar: 1; // enable error replacement
|
DWORD fErrorChar: 1; // enable error replacement
|
||||||
@@ -647,7 +648,7 @@ HANDLE OpenConnection(int port)
|
|||||||
g_hLampEvent = CreateEvent(0,FALSE,0,0);
|
g_hLampEvent = CreateEvent(0,FALSE,0,0);
|
||||||
g_hCommWatchThread = CreateThread((LPSECURITY_ATTRIBUTES)NULL, 0, (LPTHREAD_START_ROUTINE)CommWatchProc, NULL, CREATE_SUSPENDED, &g_dwThreadID);
|
g_hCommWatchThread = CreateThread((LPSECURITY_ATTRIBUTES)NULL, 0, (LPTHREAD_START_ROUTINE)CommWatchProc, NULL, CREATE_SUSPENDED, &g_dwThreadID);
|
||||||
if (g_hCommWatchThread) {
|
if (g_hCommWatchThread) {
|
||||||
//Thread까지 정상적으로 생성되었다.
|
//Thread was created successfully.
|
||||||
//////////////////////////////////////////////
|
//////////////////////////////////////////////
|
||||||
//All OK
|
//All OK
|
||||||
//Exit Point <======
|
//Exit Point <======
|
||||||
@@ -744,11 +745,11 @@ retry:
|
|||||||
for(int i=0;i<(int)dwLength;i++){
|
for(int i=0;i<(int)dwLength;i++){
|
||||||
int ch=(BYTE)lpszBlock[i];
|
int ch=(BYTE)lpszBlock[i];
|
||||||
|
|
||||||
//받은 문자만큼 루프를 돈다.
|
//Loop for the number of received characters.
|
||||||
//현재.. 받고 있는 packet이 없고.. 어떤 control문자라도 올 수 있는 상태이다.
|
//Currently.. no packet is being received.. can receive any control character.
|
||||||
|
|
||||||
if(packetbyteremain!=0){
|
if(packetbyteremain!=0){
|
||||||
//패킷에 해당하는 문자가 도착했다.. 나머지 문자들을 받는다.
|
//Character corresponding to a packet has arrived.. receive the remaining characters.
|
||||||
if (ch & 0x80) {
|
if (ch & 0x80) {
|
||||||
packetbyteremain=0;
|
packetbyteremain=0;
|
||||||
chinpacket=0;
|
chinpacket=0;
|
||||||
@@ -758,7 +759,7 @@ retry:
|
|||||||
packetbytes[chinpacket] = ch;
|
packetbytes[chinpacket] = ch;
|
||||||
chinpacket++;
|
chinpacket++;
|
||||||
if (packetbyteremain == 0) {
|
if (packetbyteremain == 0) {
|
||||||
//하나의 패킷이 완성되었다. 도착했다.. 즉시 반응한다.
|
//A packet has been completed and arrived.. respond immediately.
|
||||||
chinpacket--; // exclude check byte
|
chinpacket--; // exclude check byte
|
||||||
int packettype=packetbytes[0];
|
int packettype=packetbytes[0];
|
||||||
BYTE bCheckByte = 0;
|
BYTE bCheckByte = 0;
|
||||||
@@ -837,21 +838,21 @@ retry:
|
|||||||
packettype++;
|
packettype++;
|
||||||
packettype--;
|
packettype--;
|
||||||
#endif // _DEBUG
|
#endif // _DEBUG
|
||||||
case rio_Ack2://◆◆◆◆◆◆◆◆◆◆
|
case rio_Ack2:
|
||||||
if (g_nRIOType != 0) {
|
if (g_nRIOType != 0) {
|
||||||
BYTE id=packetbytes[1];
|
BYTE id=packetbytes[1];
|
||||||
int popped_index=PopPacket(id);
|
int popped_index=PopPacket(id);
|
||||||
ack_timeout=GetTickCount()+30;
|
ack_timeout=GetTickCount()+30;
|
||||||
if(popped_index==0){
|
if(popped_index==0){
|
||||||
//맨처음것... 정상적인 경우이다.
|
//This is the very first one... Normal case.
|
||||||
}else if(popped_index>0){
|
}else if(popped_index>0){
|
||||||
//맨처음것이 아닌것.
|
//Not the very first one.
|
||||||
//이전것들이 정상적으로 보내지지 않았으므로 다시 보낸다...
|
//Previous ones were not sent successfully, resend...
|
||||||
ReSendPackets(popped_index);//잘못된 개수 만큼..
|
ReSendPackets(popped_index);//By the number of incorrect ones..
|
||||||
}else{
|
}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;
|
break;
|
||||||
@@ -870,9 +871,9 @@ retry:
|
|||||||
// WriteTTYBlock(hWnd,"|",1);
|
// WriteTTYBlock(hWnd,"|",1);
|
||||||
chinpacket=0;
|
chinpacket=0;
|
||||||
|
|
||||||
//packetbytes버퍼를 지운다.
|
//Clear the packetbytes buffer.
|
||||||
} else {
|
} else {
|
||||||
//아직 패킷 문자들이 다 도착하지 않았다.. 아무것도 하지 않는다.
|
//Packet characters have not all arrived yet.. do nothing.
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
@@ -889,7 +890,7 @@ retry:
|
|||||||
}//for(int i=0;i<(int)dwLength;i++)
|
}//for(int i=0;i<(int)dwLength;i++)
|
||||||
|
|
||||||
|
|
||||||
//상훈 뒤
|
//sanghoon end
|
||||||
if (!fReadStat){
|
if (!fReadStat){
|
||||||
if (GetLastError() == ERROR_IO_PENDING){
|
if (GetLastError() == ERROR_IO_PENDING){
|
||||||
while(!GetOverlappedResult( g_hCom,&ros, &dwLength, TRUE )){
|
while(!GetOverlappedResult( g_hCom,&ros, &dwLength, TRUE )){
|
||||||
@@ -1000,12 +1001,24 @@ DWORD FAR PASCAL CommWatchProc( LPSTR lpData )
|
|||||||
}
|
}
|
||||||
|
|
||||||
g_dwLastAnalogUpdate = GetTickCount() + 2800;
|
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) {
|
while(1) {
|
||||||
DWORD dwEvtMask = 0;
|
DWORD dwEvtMask = 0;
|
||||||
|
|
||||||
WaitCommEvent( g_hCom, &dwEvtMask,&wcos );
|
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){
|
if(ret==WAIT_OBJECT_0){
|
||||||
//An Comm Event has arrived.
|
//An Comm Event has arrived.
|
||||||
DWORD bytesread;
|
DWORD bytesread;
|
||||||
@@ -1022,10 +1035,10 @@ DWORD FAR PASCAL CommWatchProc( LPSTR lpData )
|
|||||||
}
|
}
|
||||||
} else {*/
|
} else {*/
|
||||||
if (g_nRIOType != 0) {
|
if (g_nRIOType != 0) {
|
||||||
///◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆위의 ReadCommBlock에서 ack를 받았을 경우 duetime을 update시킨다.
|
///When ack is received from ReadCommBlock above, update duetime.
|
||||||
///◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆CheckSentBuffer...
|
///CheckSentBuffer...
|
||||||
if(GetTickCount()>ack_timeout)
|
if(GetTickCount()>ack_timeout)
|
||||||
ReSendPackets(sent_packet);//sent_buffer에 있는 모든것들을 다시 보내본다.
|
ReSendPackets(sent_packet);//Resend everything in sent_buffer.
|
||||||
}
|
}
|
||||||
/*}*/
|
/*}*/
|
||||||
}else if(ret==WAIT_OBJECT_0+1){
|
}else if(ret==WAIT_OBJECT_0+1){
|
||||||
@@ -1039,9 +1052,9 @@ DWORD FAR PASCAL CommWatchProc( LPSTR lpData )
|
|||||||
//break;
|
//break;
|
||||||
}else if (ret==WAIT_TIMEOUT) {
|
}else if (ret==WAIT_TIMEOUT) {
|
||||||
if (g_nRIOType != 0) {
|
if (g_nRIOType != 0) {
|
||||||
///◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆CheckSentBuffer...
|
///CheckSentBuffer...
|
||||||
if(GetTickCount()>ack_timeout)
|
if(GetTickCount()>ack_timeout)
|
||||||
ReSendPackets(sent_packet);//sent_buffer에 있는 모든것들을 다시 보내본다.
|
ReSendPackets(sent_packet);//Resend everything in sent_buffer.
|
||||||
}
|
}
|
||||||
if (packetbyteremain == 0) {
|
if (packetbyteremain == 0) {
|
||||||
RequestAnalogUpdate();
|
RequestAnalogUpdate();
|
||||||
@@ -1236,8 +1249,8 @@ bool SaveReceivedPacket(const BYTE*ba,int length)
|
|||||||
|
|
||||||
bool GetSerialFromReceivedBuffer(char * ba)
|
bool GetSerialFromReceivedBuffer(char * ba)
|
||||||
{
|
{
|
||||||
//ButtonPressed/Released만 저장해 놓는다..
|
//Store only ButtonPressed/Released..
|
||||||
//모든 serial packet을 옮긴다.
|
//Transfer all serial packets.
|
||||||
if(received_packet>0){
|
if(received_packet>0){
|
||||||
if(received_buffer[0][2]==received_serial){
|
if(received_buffer[0][2]==received_serial){
|
||||||
CopyMemory(ba,received_buffer[0],16);
|
CopyMemory(ba,received_buffer[0],16);
|
||||||
@@ -1264,7 +1277,7 @@ bool QueuePacket(const BYTE *ba,int length)
|
|||||||
|
|
||||||
int PopPacket(BYTE id)
|
int PopPacket(BYTE id)
|
||||||
{
|
{
|
||||||
//lamp는.. id가..
|
//lamp.. check by id..
|
||||||
//search the packet..
|
//search the packet..
|
||||||
for(int i=0;i<sent_packet;i++){
|
for(int i=0;i<sent_packet;i++){
|
||||||
if(sent_buffer[i][3]==id){
|
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++) {
|
for (int b = 0; b < MAXBUTTON_TABLE; b++) {
|
||||||
s_aCtrlLamp[b] = s_aSaveLamp[b];// = s_aButtonTable[b].lamp;
|
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;
|
s_aButtonTable[b].lamp = LAMP_OFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1439,7 +1452,7 @@ void CBUTTON_GROUP::SetTable(BOOL bFlag/* = true*/)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 모든 테이블을 원래 상태로
|
// Restore all tables to original state
|
||||||
for (int b = 0; b < MAXBUTTON_TABLE; b++) {
|
for (int b = 0; b < MAXBUTTON_TABLE; b++) {
|
||||||
s_aCtrlLamp[b] = s_aSaveLamp[b];
|
s_aCtrlLamp[b] = s_aSaveLamp[b];
|
||||||
}
|
}
|
||||||
@@ -1534,7 +1547,7 @@ void CBUTTON_GROUP::ResetTable(BOOL bFlag/* = true*/)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 모든 테이블을 Off
|
// Turn off all tables
|
||||||
for (int b = 0; b < MAXBUTTON_TABLE; b++) {
|
for (int b = 0; b < MAXBUTTON_TABLE; b++) {
|
||||||
switch(b)
|
switch(b)
|
||||||
{
|
{
|
||||||
@@ -2212,13 +2225,13 @@ void CRIOMAIN::UpdatePadal (DIJOYSTATE &js)
|
|||||||
|
|
||||||
Down Up
|
Down Up
|
||||||
======================
|
======================
|
||||||
← (+) (-) →
|
<-- (+) (-) -->
|
||||||
======================
|
======================
|
||||||
↗
|
/^
|
||||||
g_LeftPedalStart: INT_MAX (+)
|
g_LeftPedalStart: INT_MAX (+)
|
||||||
|
|
||||||
lP = (LONG)g_LeftPedalStart - g_LeftPedal;
|
lP = (LONG)g_LeftPedalStart - g_LeftPedal;
|
||||||
lP 결과값은 무조건 음수
|
lP result value is always negative
|
||||||
*/
|
*/
|
||||||
|
|
||||||
LONG lP = 0;
|
LONG lP = 0;
|
||||||
@@ -2362,9 +2375,9 @@ void CRIOMAIN::UpdateThrottle (DIJOYSTATE &js)
|
|||||||
|
|
||||||
Up Down
|
Up Down
|
||||||
======================
|
======================
|
||||||
← (-) (+) →
|
<-- (-) (+) -->
|
||||||
======================
|
======================
|
||||||
↗
|
/^
|
||||||
g_ThrottleStart: INT_MIN (-)
|
g_ThrottleStart: INT_MIN (-)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -2447,11 +2460,11 @@ void CRIOMAIN::UpdateJoystick (DIJOYSTATE &js)
|
|||||||
*/
|
*/
|
||||||
//////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
/*
|
/*
|
||||||
80 의 의미
|
Meaning of 80
|
||||||
|
|
||||||
RIO (LEFT :120 ~ RIGHT :-80) 까지의 수를 돌려준다고 가정하고
|
Assuming RIO returns values in range (LEFT:120 ~ RIGHT:-80)
|
||||||
(LEFT의경우) RIGHT 의 최대값 80 이상인 값을 잘라버리고 나머지는
|
(In the LEFT case) clip values above the RIGHT maximum of 80, and the rest
|
||||||
버릴경우 LEFT 와 RIGHT가 동일한 속도로 움직일수 있다
|
if discarded, LEFT and RIGHT can move at the same speed
|
||||||
*/
|
*/
|
||||||
//////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
LONG lJ;
|
LONG lJ;
|
||||||
|
|||||||
@@ -132,6 +132,10 @@ extern SCRIPTCALLBACK(CTCL_GetMissionState);
|
|||||||
extern SCRIPTCALLBACK(CTCL_DoBreak);
|
extern SCRIPTCALLBACK(CTCL_DoBreak);
|
||||||
extern SCRIPTCALLBACK(CTCL_IsGameLoaded);
|
extern SCRIPTCALLBACK(CTCL_IsGameLoaded);
|
||||||
extern SCRIPTCALLBACK(CTCL_DoReprint);
|
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_CheckPlayMovie);
|
||||||
extern SCRIPTCALLBACK(CTCL_CheckCoinCounts);
|
extern SCRIPTCALLBACK(CTCL_CheckCoinCounts);
|
||||||
extern SCRIPTCALLBACK(CTCL_CheckUseJPD);
|
extern SCRIPTCALLBACK(CTCL_CheckUseJPD);
|
||||||
@@ -158,6 +162,53 @@ int g_nWhyPaused = 0; // 0: not paused - invitation in menu-state, 1: briefing,
|
|||||||
extern SCRIPTCALLBACK(CTCL_WhyPaused);
|
extern SCRIPTCALLBACK(CTCL_WhyPaused);
|
||||||
int g_nTimeList_Index = 3; // 3rd item in listbox...
|
int g_nTimeList_Index = 3; // 3rd item in listbox...
|
||||||
int g_nTimeList_Value = 7; // 7 minutes
|
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] = "";
|
||||||
|
// [automaticmode] game option globals ? separate from Rookie Mission defaults to preserve Default button behavior
|
||||||
|
static char g_szAutoMission[256] = "";
|
||||||
|
static char* g_pszAutoMission = g_szAutoMission;
|
||||||
|
static int g_nAutoGameType = 2; // Attrition
|
||||||
|
static int g_nAutoVisibility = 0;
|
||||||
|
static int g_nAutoWeather = 0;
|
||||||
|
static int g_nAutoTimeOfDay = 0;
|
||||||
|
static int g_nAutoTimeLimit = -1; // -1 = server default
|
||||||
|
static int g_nAutoRadar = 0;
|
||||||
|
static int g_nAutoHeat = 0;
|
||||||
|
static int g_nAutoFriendlyFire = 0;
|
||||||
|
static int g_nAutoSplash = 0;
|
||||||
|
static int g_nAutoUnlimitedAmmo = 1;
|
||||||
|
static int g_nAutoWeaponJam = 0;
|
||||||
|
static int g_nAutoAdvanceMode = 0;
|
||||||
|
static int g_nAutoArmorMode = 0;
|
||||||
|
static int g_nAutoTeamAllowed = 0; // 0=FFA 1=team game; set via TeamAllowed= in [mission]
|
||||||
|
static int g_nAutoTeamCount = 2; // number of teams when TeamAllowed=1
|
||||||
// MSL 5.06
|
// MSL 5.06
|
||||||
int g_nMechVariant = 0;
|
int g_nMechVariant = 0;
|
||||||
int g_nMechLabOp = 0;
|
int g_nMechLabOp = 0;
|
||||||
@@ -727,6 +778,54 @@ void MW4Shell::StartUp()
|
|||||||
gosScript_RegisterCallback("CTCL_WhyPaused",&CTCL_WhyPaused,GOSVAR_INT,0,NULL);
|
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_Index", &g_nTimeList_Index, GOSVAR_INT, 0, NULL);
|
||||||
gosScript_RegisterVariable("g_nTimeList_Value", &g_nTimeList_Value, 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 + g_bAutomaticMode variable for script visibility
|
||||||
|
gosScript_RegisterVariable("g_bAutomaticMode", &g_bAutomaticMode, GOSVAR_INT, 0, NULL);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// [automaticmode] game option variables (separate from Rookie globals)
|
||||||
|
gosScript_RegisterVariable("g_szAutoMission", &g_pszAutoMission, GOSVAR_STRING, 0, NULL);
|
||||||
|
gosScript_RegisterVariable("g_nAutoGameType", &g_nAutoGameType, GOSVAR_INT, 0, NULL);
|
||||||
|
gosScript_RegisterVariable("g_nAutoVisibility", &g_nAutoVisibility, GOSVAR_INT, 0, NULL);
|
||||||
|
gosScript_RegisterVariable("g_nAutoWeather", &g_nAutoWeather, GOSVAR_INT, 0, NULL);
|
||||||
|
gosScript_RegisterVariable("g_nAutoTimeOfDay", &g_nAutoTimeOfDay, GOSVAR_INT, 0, NULL);
|
||||||
|
gosScript_RegisterVariable("g_nAutoTimeLimit", &g_nAutoTimeLimit, GOSVAR_INT, 0, NULL);
|
||||||
|
gosScript_RegisterVariable("g_nAutoRadar", &g_nAutoRadar, GOSVAR_INT, 0, NULL);
|
||||||
|
gosScript_RegisterVariable("g_nAutoHeat", &g_nAutoHeat, GOSVAR_INT, 0, NULL);
|
||||||
|
gosScript_RegisterVariable("g_nAutoFriendlyFire", &g_nAutoFriendlyFire, GOSVAR_INT, 0, NULL);
|
||||||
|
gosScript_RegisterVariable("g_nAutoSplash", &g_nAutoSplash, GOSVAR_INT, 0, NULL);
|
||||||
|
gosScript_RegisterVariable("g_nAutoUnlimitedAmmo",&g_nAutoUnlimitedAmmo, GOSVAR_INT, 0, NULL);
|
||||||
|
gosScript_RegisterVariable("g_nAutoWeaponJam", &g_nAutoWeaponJam, GOSVAR_INT, 0, NULL);
|
||||||
|
gosScript_RegisterVariable("g_nAutoAdvanceMode", &g_nAutoAdvanceMode, GOSVAR_INT, 0, NULL);
|
||||||
|
gosScript_RegisterVariable("g_nAutoArmorMode", &g_nAutoArmorMode, GOSVAR_INT, 0, NULL);
|
||||||
|
gosScript_RegisterVariable("g_nAutoTeamAllowed", &g_nAutoTeamAllowed, GOSVAR_INT, 0, NULL);
|
||||||
|
gosScript_RegisterVariable("g_nAutoTeamCount", &g_nAutoTeamCount, GOSVAR_INT, 0, NULL);
|
||||||
// MSL 5.06
|
// MSL 5.06
|
||||||
gosScript_RegisterVariable("g_nMechVariant", &g_nMechVariant, GOSVAR_INT, 0, NULL);
|
gosScript_RegisterVariable("g_nMechVariant", &g_nMechVariant, GOSVAR_INT, 0, NULL);
|
||||||
gosScript_RegisterVariable("g_nMechLabOp", &g_nMechLabOp, GOSVAR_INT, 0, NULL);
|
gosScript_RegisterVariable("g_nMechLabOp", &g_nMechLabOp, GOSVAR_INT, 0, NULL);
|
||||||
@@ -1108,6 +1207,44 @@ void MW4Shell::ShutDown()
|
|||||||
// jcem - start
|
// jcem - start
|
||||||
gosScript_UnregisterVariable("g_nTimeList_Value");
|
gosScript_UnregisterVariable("g_nTimeList_Value");
|
||||||
gosScript_UnregisterVariable("g_nTimeList_Index");
|
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 + variable
|
||||||
|
gosScript_UnregisterCallback("CTCL_GetAutoSlotInt");
|
||||||
|
gosScript_UnregisterCallback("CTCL_GetAutoSlotMech");
|
||||||
|
gosScript_UnregisterCallback("CTCL_GetAutoSlotName");
|
||||||
|
gosScript_UnregisterCallback("CTCL_LoadAutoFile");
|
||||||
|
gosScript_UnregisterVariable("g_bAutomaticMode");
|
||||||
|
// [automaticmode] game option variables
|
||||||
|
gosScript_UnregisterVariable("g_nAutoTeamCount");
|
||||||
|
gosScript_UnregisterVariable("g_nAutoTeamAllowed");
|
||||||
|
gosScript_UnregisterVariable("g_nAutoArmorMode");
|
||||||
|
gosScript_UnregisterVariable("g_nAutoAdvanceMode");
|
||||||
|
gosScript_UnregisterVariable("g_nAutoWeaponJam");
|
||||||
|
gosScript_UnregisterVariable("g_nAutoUnlimitedAmmo");
|
||||||
|
gosScript_UnregisterVariable("g_nAutoSplash");
|
||||||
|
gosScript_UnregisterVariable("g_nAutoFriendlyFire");
|
||||||
|
gosScript_UnregisterVariable("g_nAutoHeat");
|
||||||
|
gosScript_UnregisterVariable("g_nAutoRadar");
|
||||||
|
gosScript_UnregisterVariable("g_nAutoTimeLimit");
|
||||||
|
gosScript_UnregisterVariable("g_nAutoTimeOfDay");
|
||||||
|
gosScript_UnregisterVariable("g_nAutoWeather");
|
||||||
|
gosScript_UnregisterVariable("g_nAutoVisibility");
|
||||||
|
gosScript_UnregisterVariable("g_nAutoGameType");
|
||||||
|
gosScript_UnregisterVariable("g_szAutoMission");
|
||||||
// MSL 5.06
|
// MSL 5.06
|
||||||
gosScript_UnregisterVariable("g_nBlackMech");
|
gosScript_UnregisterVariable("g_nBlackMech");
|
||||||
gosScript_UnregisterVariable("g_nMechVariant");
|
gosScript_UnregisterVariable("g_nMechVariant");
|
||||||
@@ -1828,7 +1965,8 @@ int MW4Shell::SetNetworkMissionParamater(void * instance, int numParms, void **d
|
|||||||
case PLAYER_LIMIT_PARAMETER:
|
case PLAYER_LIMIT_PARAMETER:
|
||||||
params->m_playerLimit = INTPARM(1);
|
params->m_playerLimit = INTPARM(1);
|
||||||
Min_Clamp(params->m_playerLimit, Network::GetInstance()->GetPlayerCount());
|
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);
|
gos_NetServerCommands(gos_Commend_UpdateMaxPlayers,0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -12731,6 +12869,143 @@ int __stdcall CTCL_SetCDSP(void* instance, int args, void* data[])
|
|||||||
{
|
{
|
||||||
ASSERT(CTCL_IsConsole());
|
ASSERT(CTCL_IsConsole());
|
||||||
CTCL_DefaultHostSetup(1);
|
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 ? stored in dedicated Auto globals, NOT Rookie Mission globals,
|
||||||
|
// so the Default button continues to use the original [RookieMission] defaults.
|
||||||
|
g_szAutoMission[0] = '\0';
|
||||||
|
g_nAutoGameType = 2; g_nAutoVisibility = 0; g_nAutoWeather = 0;
|
||||||
|
g_nAutoTimeOfDay = 0; g_nAutoTimeLimit = -1; g_nAutoRadar = 0;
|
||||||
|
g_nAutoHeat = 0; g_nAutoFriendlyFire = 0; g_nAutoSplash = 0;
|
||||||
|
g_nAutoUnlimitedAmmo = 1; g_nAutoWeaponJam = 0; g_nAutoAdvanceMode = 0;
|
||||||
|
g_nAutoArmorMode = 0; g_nAutoTeamAllowed = 0; g_nAutoTeamCount = 2;
|
||||||
|
|
||||||
|
Page *pMission = autofile.FindPage("mission");
|
||||||
|
if (pMission) {
|
||||||
|
const char *sz = NULL;
|
||||||
|
if (pMission->GetEntry("MissionName", &sz) && sz) {
|
||||||
|
strncpy(g_szAutoMission, sz, sizeof(g_szAutoMission)-1);
|
||||||
|
g_szAutoMission[sizeof(g_szAutoMission)-1] = '\0';
|
||||||
|
}
|
||||||
|
pMission->GetEntry("GameType", &g_nAutoGameType);
|
||||||
|
pMission->GetEntry("Visibility", &g_nAutoVisibility);
|
||||||
|
pMission->GetEntry("Weather", &g_nAutoWeather);
|
||||||
|
pMission->GetEntry("TimeOfDay", &g_nAutoTimeOfDay);
|
||||||
|
pMission->GetEntry("TimeLimit", &g_nAutoTimeLimit);
|
||||||
|
pMission->GetEntry("Radar", &g_nAutoRadar);
|
||||||
|
pMission->GetEntry("HeatOn", &g_nAutoHeat);
|
||||||
|
pMission->GetEntry("FriendlyFire", &g_nAutoFriendlyFire);
|
||||||
|
pMission->GetEntry("SplashDamage", &g_nAutoSplash);
|
||||||
|
pMission->GetEntry("UnlimitedAmmo", &g_nAutoUnlimitedAmmo);
|
||||||
|
pMission->GetEntry("WeaponJam", &g_nAutoWeaponJam);
|
||||||
|
pMission->GetEntry("AdvanceMode", &g_nAutoAdvanceMode);
|
||||||
|
pMission->GetEntry("ArmorMode", &g_nAutoArmorMode);
|
||||||
|
pMission->GetEntry("TeamAllowed", &g_nAutoTeamAllowed);
|
||||||
|
pMission->GetEntry("TeamCount", &g_nAutoTeamCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
// field is passed as a script literal (0/1/2/3), so use VALUEPARM not INTPARM (literals are passed
|
||||||
|
// as (void*)N directly, not as pointers; INTPARM would dereference NULL for field=0 and crash).
|
||||||
|
int __stdcall CTCL_GetAutoSlotInt(void* instance, int args, void* data[])
|
||||||
|
{
|
||||||
|
int k = INTPARM(0);
|
||||||
|
int field = VALUEPARM(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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -13307,19 +13582,17 @@ void CTCL_API CTCL_DefaultHostSetup(int nMode)
|
|||||||
params->m_allowdecaltransfer = 0;
|
params->m_allowdecaltransfer = 0;
|
||||||
if (g_bCOOP) {
|
if (g_bCOOP) {
|
||||||
Environment.NetworkMaxPlayers = 16;
|
Environment.NetworkMaxPlayers = 16;
|
||||||
//if (CTCL_GetTeslaCount() < CTCL_GetTeslaCountAll()) {
|
// Reserve extra DirectPlay slots for camera seats (tracked separately from pilots in CTCL)
|
||||||
// any cameraship installed... so 1 more player can join
|
// Original commented-out intent preserved and now implemented for non-COOP below
|
||||||
//params->m_maxPlayers = 9;
|
|
||||||
//params->m_maxBots = 8;
|
|
||||||
//} else {
|
|
||||||
params->m_maxPlayers = 9;
|
params->m_maxPlayers = 9;
|
||||||
params->m_maxBots = 8;
|
params->m_maxBots = 8;
|
||||||
//}
|
|
||||||
} else {
|
} else {
|
||||||
params->m_maxPlayers = 31; // 31: max that fits in 5-bit bitstream (0-31)
|
params->m_maxPlayers = 16;
|
||||||
Environment.NetworkMaxPlayers = 31;
|
// Reserve extra DirectPlay slots for cameraships: they share the session but are tracked
|
||||||
params->m_maxBots = 31;
|
// separately from pilot seats in CTCL (CTCL_GetTeslaCountAll - CTCL_GetTeslaCount = camera count).
|
||||||
gos_NetServerCommands(gos_Commend_UpdateMaxPlayers, 0); // push the updated limit to the live DirectPlay session
|
// 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;
|
params->m_allow3rdPerson = 1;
|
||||||
if ((nMode != 0) && (nMode != 4)) {
|
if ((nMode != 0) && (nMode != 4)) {
|
||||||
|
|||||||
@@ -808,8 +808,8 @@ void NetMissionParameters::MWNetMissionParameters::SaveParameters(DynamicMemoryS
|
|||||||
stream->WriteBits(&m_pureMapCycle,1);
|
stream->WriteBits(&m_pureMapCycle,1);
|
||||||
|
|
||||||
|
|
||||||
stream->WriteBits(&m_maxPlayers, 5); // max 31 players
|
stream->WriteBits(&m_maxPlayers, 5); // 16 players maximum
|
||||||
stream->WriteBits(&m_maxBots, 5); // max 31
|
stream->WriteBits(&m_maxBots, 5); // 16 players maximum
|
||||||
stream->WriteBits(&m_mapID, 16); // 65535 maps available
|
stream->WriteBits(&m_mapID, 16); // 65535 maps available
|
||||||
stream->WriteBits(&m_mapClientCRC, 64);
|
stream->WriteBits(&m_mapClientCRC, 64);
|
||||||
|
|
||||||
@@ -927,8 +927,8 @@ void NetMissionParameters::MWNetMissionParameters::LoadParameters(MemoryStream *
|
|||||||
stream->ReadBits(&m_useMapCycle,1);
|
stream->ReadBits(&m_useMapCycle,1);
|
||||||
stream->ReadBits(&m_pureMapCycle,1);
|
stream->ReadBits(&m_pureMapCycle,1);
|
||||||
|
|
||||||
stream->ReadBits(&m_maxPlayers, 5); // max 31 players
|
stream->ReadBits(&m_maxPlayers, 5); // 16 players max
|
||||||
stream->ReadBits(&m_maxBots, 5); // max 31
|
stream->ReadBits(&m_maxBots, 5); // 16 players max
|
||||||
stream->ReadBits(&m_mapID, 16); // 65535 maps available
|
stream->ReadBits(&m_mapID, 16); // 65535 maps available
|
||||||
stream->ReadBits(&m_mapClientCRC, 64);
|
stream->ReadBits(&m_mapClientCRC, 64);
|
||||||
|
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ extern int g_nMech4Comm;
|
|||||||
// server & client only
|
// server & client only
|
||||||
extern BOOL g_bIsServer;
|
extern BOOL g_bIsServer;
|
||||||
// console(All), server & client only(g_aPlayerInfos[0]), server only(g_aPlayerInfos[1..g_nBOTs]
|
// 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_nPlayerInfos;
|
||||||
extern int g_nServer;
|
extern int g_nServer;
|
||||||
extern int g_nTeslas;
|
extern int g_nTeslas;
|
||||||
|
|||||||
@@ -885,7 +885,7 @@ void __stdcall GetGameOSEnvironment(char* CommandLine)
|
|||||||
Environment.allowMultipleApps = false;
|
Environment.allowMultipleApps = false;
|
||||||
Environment.AllowJoinInProgress = true;
|
Environment.AllowJoinInProgress = true;
|
||||||
Environment.NetworkGame = true;
|
Environment.NetworkGame = true;
|
||||||
Environment.NetworkMaxPlayers = 31; // max 31 (fits in 5-bit bitstream)
|
Environment.NetworkMaxPlayers = 16;
|
||||||
Environment.NetworkGUID[0] = 0x95;
|
Environment.NetworkGUID[0] = 0x95;
|
||||||
Environment.NetworkGUID[1] = 0x78;
|
Environment.NetworkGUID[1] = 0x78;
|
||||||
Environment.NetworkGUID[2] = 0xFF;
|
Environment.NetworkGUID[2] = 0xFF;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#include "recscore.h"
|
#include "recscore.h"
|
||||||
#endif // !defined(CTCLS_EXPORTS) && !defined(CTCL_LAUNCHER)
|
#endif // !defined(CTCLS_EXPORTS) && !defined(CTCL_LAUNCHER)
|
||||||
|
|
||||||
#define MAX_TESLAS 31
|
#define MAX_TESLAS 16
|
||||||
#define MAX_CAMERAS 4
|
#define MAX_CAMERAS 4
|
||||||
|
|
||||||
#define PORT_Launcher 1000
|
#define PORT_Launcher 1000
|
||||||
@@ -263,7 +263,7 @@ CInviteCOOP g_InviteCOOP;
|
|||||||
// Mech4 only
|
// Mech4 only
|
||||||
int g_nMech4Comm = 0;
|
int g_nMech4Comm = 0;
|
||||||
BOOL g_bIsServer = FALSE;
|
BOOL g_bIsServer = FALSE;
|
||||||
SPlayerInfo g_aPlayerInfos[35]; // 31 pilots + 1 CS + 3 spare
|
SPlayerInfo g_aPlayerInfos[20];
|
||||||
int g_nPlayerInfos;
|
int g_nPlayerInfos;
|
||||||
int g_nServer;
|
int g_nServer;
|
||||||
int g_nTeslas;
|
int g_nTeslas;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#include "recscore.h"
|
#include "recscore.h"
|
||||||
#endif // !defined(CTCLS_EXPORTS) && !defined(CTCL_LAUNCHER)
|
#endif // !defined(CTCLS_EXPORTS) && !defined(CTCL_LAUNCHER)
|
||||||
|
|
||||||
#define MAX_TESLAS 31
|
#define MAX_TESLAS 16
|
||||||
#define MAX_CAMERAS 4
|
#define MAX_CAMERAS 4
|
||||||
|
|
||||||
#define PORT_Launcher 1000
|
#define PORT_Launcher 1000
|
||||||
@@ -263,7 +263,7 @@ CInviteCOOP g_InviteCOOP;
|
|||||||
// Mech4 only
|
// Mech4 only
|
||||||
int g_nMech4Comm = 0;
|
int g_nMech4Comm = 0;
|
||||||
BOOL g_bIsServer = FALSE;
|
BOOL g_bIsServer = FALSE;
|
||||||
SPlayerInfo g_aPlayerInfos[35]; // 31 pilots + 1 CS + 3 spare
|
SPlayerInfo g_aPlayerInfos[20];
|
||||||
int g_nPlayerInfos;
|
int g_nPlayerInfos;
|
||||||
int g_nServer;
|
int g_nServer;
|
||||||
int g_nTeslas;
|
int g_nTeslas;
|
||||||
|
|||||||
@@ -806,7 +806,7 @@ STRINGTABLE DISCARDABLE
|
|||||||
BEGIN
|
BEGIN
|
||||||
IDS_ML_CH_ACCELERATION "Acceleration (Meters/Sec.):"
|
IDS_ML_CH_ACCELERATION "Acceleration (Meters/Sec.):"
|
||||||
IDS_ML_CH_DECELERATION "Deceleration (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_TWISTRANGE "Torso Twist Range (Degrees):"
|
||||||
IDS_ML_CH_TWISTSPEED "Torso Twist Speed (Degrees/Sec.):"
|
IDS_ML_CH_TWISTSPEED "Torso Twist Speed (Degrees/Sec.):"
|
||||||
IDS_ML_CH_NEWMECH "NEW 'MECH"
|
IDS_ML_CH_NEWMECH "NEW 'MECH"
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ void NetMissionParameters::AdeptNetMissionParameters::ResetParameters(void)
|
|||||||
{
|
{
|
||||||
m_runDedicated = 0;
|
m_runDedicated = 0;
|
||||||
m_closedGame = 0;
|
m_closedGame = 0;
|
||||||
m_playerLimit = 31; // max 31 (fits in 5-bit bitstream)
|
m_playerLimit = 16;
|
||||||
|
|
||||||
m_visibility = 0;
|
m_visibility = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#include "recscore.h"
|
#include "recscore.h"
|
||||||
#endif // !defined(CTCLS_EXPORTS) && !defined(CTCL_LAUNCHER)
|
#endif // !defined(CTCLS_EXPORTS) && !defined(CTCL_LAUNCHER)
|
||||||
|
|
||||||
#define MAX_TESLAS 31
|
#define MAX_TESLAS 16
|
||||||
#define MAX_CAMERAS 4
|
#define MAX_CAMERAS 4
|
||||||
|
|
||||||
#define PORT_Launcher 1000
|
#define PORT_Launcher 1000
|
||||||
@@ -263,7 +263,7 @@ CInviteCOOP g_InviteCOOP;
|
|||||||
// Mech4 only
|
// Mech4 only
|
||||||
int g_nMech4Comm = 0;
|
int g_nMech4Comm = 0;
|
||||||
BOOL g_bIsServer = FALSE;
|
BOOL g_bIsServer = FALSE;
|
||||||
SPlayerInfo g_aPlayerInfos[35]; // 31 pilots + 1 CS + 3 spare
|
SPlayerInfo g_aPlayerInfos[20];
|
||||||
int g_nPlayerInfos;
|
int g_nPlayerInfos;
|
||||||
int g_nServer;
|
int g_nServer;
|
||||||
int g_nTeslas;
|
int g_nTeslas;
|
||||||
|
|||||||
@@ -14,6 +14,9 @@
|
|||||||
// 10/10/03 MSL Added Cameraship to RESET_AFTER_LAUNCH
|
// 10/10/03 MSL Added Cameraship to RESET_AFTER_LAUNCH
|
||||||
// 10/17/05 MSL Added all remaining Mechs (55)
|
// 10/17/05 MSL Added all remaining Mechs (55)
|
||||||
// 06/19/18 AVB Update tab stops
|
// 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
|
#define USE_O_MORE_PODS $$g_nMechPodNum$$ // 0 = use only 8
|
||||||
|
|
||||||
#if USE_O_MORE_PODS
|
#if USE_O_MORE_PODS
|
||||||
#define MAX_ROSTER_COUNT 31 // max within 5-bit bitstream (0-31)
|
#define MAX_ROSTER_COUNT 16 // Was 8
|
||||||
#define MAX_TEAMMATE_COUNT 15 // Was 4, then 8
|
#define MAX_TEAMMATE_COUNT 8 // Was 4
|
||||||
#else
|
#else
|
||||||
#define MAX_ROSTER_COUNT 8
|
#define MAX_ROSTER_COUNT 8
|
||||||
#define MAX_TEAMMATE_COUNT 4 // Was 4
|
#define MAX_TEAMMATE_COUNT 4 // Was 4
|
||||||
@@ -187,13 +190,17 @@
|
|||||||
#define MAIL_PREVIOUS_MISSION -2222
|
#define MAIL_PREVIOUS_MISSION -2222
|
||||||
#define MAIL_RECORD_MISSION -4444
|
#define MAIL_RECORD_MISSION -4444
|
||||||
#define MAIL_PREVIOUS_MISSION_PARAMS -5555
|
#define MAIL_PREVIOUS_MISSION_PARAMS -5555
|
||||||
|
#define MAIL_LOAD_AUTO_MISSION -6666 // [automaticmode] sync with Multiplayer/ConLobbyMission.script
|
||||||
|
|
||||||
// MSL 5.06
|
// MSL 5.06
|
||||||
// MSL ADD MECH
|
// MSL ADD MECH
|
||||||
#define ROOKIEMECH1 38 // Loki
|
// MechCorps Highlight: expanded from Fab4 to Super6 (added Archer and Warhammer)
|
||||||
#define ROOKIEMECH2 40 // Madcat
|
#define ROOKIEMECH1 1 // Archer
|
||||||
#define ROOKIEMECH3 56 // Thor
|
#define ROOKIEMECH2 38 // Loki
|
||||||
#define ROOKIEMECH4 61 // Vulture
|
#define ROOKIEMECH3 40 // Madcat
|
||||||
|
#define ROOKIEMECH4 56 // Thor
|
||||||
|
#define ROOKIEMECH5 61 // Vulture
|
||||||
|
#define ROOKIEMECH6 62 // Warhammer
|
||||||
|
|
||||||
main
|
main
|
||||||
{
|
{
|
||||||
@@ -246,7 +253,7 @@ main
|
|||||||
o_frame.type = 0
|
o_frame.type = 0
|
||||||
o_frame.location = 0, 0, 100
|
o_frame.location = 0, 0, 100
|
||||||
// MSL Version
|
// 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)
|
initialize(o_frame)
|
||||||
|
|
||||||
int team_camo[16] // team_camo[selected team number] is skin number(0..36)...
|
int team_camo[16] // team_camo[selected team number] is skin number(0..36)...
|
||||||
@@ -364,7 +371,7 @@ main
|
|||||||
cur_team_val = callback($$CTCL_GetTeamParams$$, cur_team_count[0])
|
cur_team_val = callback($$CTCL_GetTeamParams$$, cur_team_count[0])
|
||||||
|
|
||||||
int skin_id ///////VERY IMPORTANT FOR NEW SKIN INTERFACE
|
int skin_id ///////VERY IMPORTANT FOR NEW SKIN INTERFACE
|
||||||
int skin_ids[32]
|
int skin_ids[17]
|
||||||
int update_skin = false
|
int update_skin = false
|
||||||
// MSL 5.05
|
// MSL 5.05
|
||||||
int decal_id ///////VERY IMPORTANT FOR NEW DECAL INTERFACE
|
int decal_id ///////VERY IMPORTANT FOR NEW DECAL INTERFACE
|
||||||
@@ -522,7 +529,7 @@ main
|
|||||||
|
|
||||||
|
|
||||||
///---------holds faction name for scroll list
|
///---------holds faction name for scroll list
|
||||||
string faction_name[32]
|
string faction_name[17]
|
||||||
|
|
||||||
callback($$Shell_CallbackHandler$$, ShellInitMPScreen)
|
callback($$Shell_CallbackHandler$$, ShellInitMPScreen)
|
||||||
|
|
||||||
@@ -645,12 +652,12 @@ main
|
|||||||
team_legal_to_join[8] = TRUE
|
team_legal_to_join[8] = TRUE
|
||||||
int update_team = 0
|
int update_team = 0
|
||||||
|
|
||||||
int max_players = 31 // max within 5-bit bitstream
|
int max_players = 16
|
||||||
|
|
||||||
int player_num = 0
|
int player_num = 0
|
||||||
// int num_of_teams = 8
|
// int num_of_teams = 8
|
||||||
int mech_id
|
int mech_id
|
||||||
int name_color[32]
|
int name_color[17]
|
||||||
int lupe
|
int lupe
|
||||||
|
|
||||||
for lupe = 0; lupe < nRosterCount;lupe++
|
for lupe = 0; lupe < nRosterCount;lupe++
|
||||||
@@ -675,33 +682,33 @@ main
|
|||||||
player_num = -1
|
player_num = -1
|
||||||
|
|
||||||
// ComboBox for the Player Type
|
// ComboBox for the Player Type
|
||||||
object o_BotList[32]
|
object o_BotList[17]
|
||||||
object o_BotList_bu[32]
|
object o_BotList_bu[17]
|
||||||
int m_naLastSelected[32]
|
int m_naLastSelected[17]
|
||||||
for x = 0; x < nRosterCount; x++
|
for x = 0; x < nRosterCount; x++
|
||||||
{
|
{
|
||||||
m_naLastSelected[x] = 0
|
m_naLastSelected[x] = 0
|
||||||
}
|
}
|
||||||
object o_Editbox[32]
|
object o_Editbox[17]
|
||||||
object o_print_text[32]
|
object o_print_text[17]
|
||||||
object o_mech_variant[32]
|
object o_mech_variant[17]
|
||||||
object o_mech_variant_bu[32]
|
object o_mech_variant_bu[17]
|
||||||
#if USE_O_MECH_VARIANT2
|
#if USE_O_MECH_VARIANT2
|
||||||
object o_mech_variant2[32]
|
object o_mech_variant2[17]
|
||||||
object o_mech_variant2_bu[32]
|
object o_mech_variant2_bu[17]
|
||||||
#endif // USE_O_MECH_VARIANT2
|
#endif // USE_O_MECH_VARIANT2
|
||||||
object o_mech_rand[32]
|
object o_mech_rand[17]
|
||||||
object o_skins[32]
|
object o_skins[17]
|
||||||
object o_skins_bu[32]
|
object o_skins_bu[17]
|
||||||
// MSL 5.05
|
// MSL 5.05
|
||||||
object o_decal[32]
|
object o_decal[18]
|
||||||
object o_decal_bu[32]
|
object o_decal_bu[18]
|
||||||
object o_team[32]
|
object o_team[18]
|
||||||
object o_team_bu[32]
|
object o_team_bu[18]
|
||||||
object o_decal_box[32]
|
object o_decal_box[18]
|
||||||
object o_skin_box[32]
|
object o_skin_box[18]
|
||||||
object o_status[32]
|
object o_status[18]
|
||||||
int roster_posy[32]
|
int roster_posy[18]
|
||||||
int coolbaby
|
int coolbaby
|
||||||
|
|
||||||
int stock_size = 0
|
int stock_size = 0
|
||||||
@@ -1005,7 +1012,7 @@ main
|
|||||||
o_decal[x].list_item[15] = "16"
|
o_decal[x].list_item[15] = "16"
|
||||||
o_decal[x].list_item[16] = "17"
|
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].list_item[coolbaby] = conv$(coolbaby+1)
|
||||||
|
|
||||||
o_decal[x].nselected = 3
|
o_decal[x].nselected = 3
|
||||||
@@ -1072,7 +1079,7 @@ main
|
|||||||
o_skins[x].list_item[14] = "15"
|
o_skins[x].list_item[14] = "15"
|
||||||
o_skins[x].list_item[15] = "16"
|
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].list_item[coolbaby] = conv$(coolbaby+1)
|
||||||
|
|
||||||
o_skins[x].nselected = 3
|
o_skins[x].nselected = 3
|
||||||
@@ -1223,6 +1230,18 @@ main
|
|||||||
o_all_random_mech.state = 0 // initially enabled
|
o_all_random_mech.state = 0 // initially enabled
|
||||||
initialize(o_all_random_mech)
|
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)
|
||||||
|
if ($$g_bAutomaticMode$$ != 1)
|
||||||
|
o_load_file.state = 3 // hide when automaticmode is not active
|
||||||
|
|
||||||
// MSL Added default settings button
|
// MSL Added default settings button
|
||||||
object o_default = s_multistatepane
|
object o_default = s_multistatepane
|
||||||
o_default.total_states = 3
|
o_default.total_states = 3
|
||||||
@@ -1658,6 +1677,119 @@ main
|
|||||||
mail(MAIL_RESET_AFTER_LAUNCH, this) // reset
|
mail(MAIL_RESET_AFTER_LAUNCH, this) // reset
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// [automaticmode] Load File button handler
|
||||||
|
if (sender == o_load_file)
|
||||||
|
{
|
||||||
|
play press, 1
|
||||||
|
if callback($$CTCL_LoadAutoFile$$)
|
||||||
|
{
|
||||||
|
// Apply game options using dedicated Auto globals.
|
||||||
|
// Rookie Mission globals are NOT touched so the Default button keeps working.
|
||||||
|
int m
|
||||||
|
if exists(@ConLobbyMission@)
|
||||||
|
{
|
||||||
|
@ConLobbyMission@o_game_options[0].nselected = $$g_nAutoGameType$$
|
||||||
|
for (m = 0; m < @ConLobbyMission@o_game_options[1].list_size; m++)
|
||||||
|
{
|
||||||
|
if equal$(@ConLobbyMission@o_game_options[1].list_item[m], $$g_szAutoMission$$)
|
||||||
|
{
|
||||||
|
@ConLobbyMission@o_game_options[1].nselected = m
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mail(MAIL_LOAD_AUTO_MISSION, @ConLobbyMission@)
|
||||||
|
}
|
||||||
|
// Update team state synchronously so slot display is correct on the first click.
|
||||||
|
// MAIL_LOAD_AUTO_MISSION is async; setting team_allowed directly here lets
|
||||||
|
// CTCL_GetTeamParams return the correct cur_team_val before the slot loop runs.
|
||||||
|
callback($$SetNetworkMissionParamater$$, team_allowed, $$g_nAutoTeamAllowed$$)
|
||||||
|
if $$g_nAutoTeamAllowed$$
|
||||||
|
callback($$SetNetworkMissionParamater$$, num_of_teams, $$g_nAutoTeamCount$$)
|
||||||
|
cur_team_val = callback($$CTCL_GetTeamParams$$, cur_team_count[0])
|
||||||
|
// 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
|
||||||
|
// stock_array[j] = index in mech[] where chassis j lives (skips variant entries).
|
||||||
|
// mech[allowed_mechs[j]] would hit variant names; stock_array corrects this.
|
||||||
|
for (j = 0; j < MAX_ALLOWED_MECHS; j++)
|
||||||
|
{
|
||||||
|
if equal$(mech[stock_array[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
|
||||||
|
}
|
||||||
|
// Always set both team and skin unconditionally.
|
||||||
|
// The game type may not have propagated to cur_team_val yet
|
||||||
|
// (MAIL_SET_ROOKIE_MISSION is async); setting both is safe --
|
||||||
|
// the launch code uses whichever is correct for the active mode.
|
||||||
|
o_team[k].nselected = callback($$CTCL_GetAutoSlotInt$$, k, 1)
|
||||||
|
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)
|
if (sender == o_reprint)
|
||||||
{
|
{
|
||||||
play press,1
|
play press,1
|
||||||
@@ -1761,38 +1893,39 @@ main
|
|||||||
for (k = 0; k < nRosterCount; k++)
|
for (k = 0; k < nRosterCount; k++)
|
||||||
{
|
{
|
||||||
// MSL
|
// MSL
|
||||||
|
// MechCorps Highlight: Super6 slot assignments (16 slots, 6-mech cycle; Vulture+Warhammer appear twice)
|
||||||
if k == 0
|
if k == 0
|
||||||
o_mech_variant[k].nselected = ROOKIEMECH1 // Loki
|
o_mech_variant[k].nselected = ROOKIEMECH1 // Archer
|
||||||
if k == 1
|
if k == 1
|
||||||
o_mech_variant[k].nselected = ROOKIEMECH2 // Madcat
|
o_mech_variant[k].nselected = ROOKIEMECH2 // Loki
|
||||||
if k == 2
|
if k == 2
|
||||||
o_mech_variant[k].nselected = ROOKIEMECH3 // Thor
|
o_mech_variant[k].nselected = ROOKIEMECH3 // Madcat
|
||||||
if k == 3
|
if k == 3
|
||||||
o_mech_variant[k].nselected = ROOKIEMECH4 // vulture
|
o_mech_variant[k].nselected = ROOKIEMECH4 // Thor
|
||||||
if k == 4
|
if k == 4
|
||||||
o_mech_variant[k].nselected = ROOKIEMECH1 // Loki
|
o_mech_variant[k].nselected = ROOKIEMECH5 // Vulture
|
||||||
if k == 5
|
if k == 5
|
||||||
o_mech_variant[k].nselected = ROOKIEMECH2 // Madcat
|
o_mech_variant[k].nselected = ROOKIEMECH6 // Warhammer
|
||||||
if k == 6
|
if k == 6
|
||||||
o_mech_variant[k].nselected = ROOKIEMECH3 // Thor
|
o_mech_variant[k].nselected = ROOKIEMECH1 // Archer
|
||||||
if k == 7
|
if k == 7
|
||||||
o_mech_variant[k].nselected = ROOKIEMECH4 // Vulture
|
o_mech_variant[k].nselected = ROOKIEMECH2 // Loki
|
||||||
if k == 8
|
if k == 8
|
||||||
o_mech_variant[k].nselected = ROOKIEMECH1 // Loki
|
o_mech_variant[k].nselected = ROOKIEMECH3 // Madcat
|
||||||
if k == 9
|
if k == 9
|
||||||
o_mech_variant[k].nselected = ROOKIEMECH2 // Madcat
|
o_mech_variant[k].nselected = ROOKIEMECH4 // Thor
|
||||||
if k == 10
|
if k == 10
|
||||||
o_mech_variant[k].nselected = ROOKIEMECH3 // Thor
|
o_mech_variant[k].nselected = ROOKIEMECH5 // Vulture
|
||||||
if k == 11
|
if k == 11
|
||||||
o_mech_variant[k].nselected = ROOKIEMECH4 // vulture
|
o_mech_variant[k].nselected = ROOKIEMECH6 // Warhammer
|
||||||
if k == 12
|
if k == 12
|
||||||
o_mech_variant[k].nselected = ROOKIEMECH1 // Loki
|
o_mech_variant[k].nselected = ROOKIEMECH1 // Archer
|
||||||
if k == 13
|
if k == 13
|
||||||
o_mech_variant[k].nselected = ROOKIEMECH2 // Madcat
|
o_mech_variant[k].nselected = ROOKIEMECH2 // Loki
|
||||||
if k == 14
|
if k == 14
|
||||||
o_mech_variant[k].nselected = ROOKIEMECH3 // Thor
|
o_mech_variant[k].nselected = ROOKIEMECH3 // Madcat
|
||||||
if k == 15
|
if k == 15
|
||||||
o_mech_variant[k].nselected = ROOKIEMECH4 // Vulture
|
o_mech_variant[k].nselected = ROOKIEMECH4 // Thor
|
||||||
#if USE_O_MECH_VARIANT2
|
#if USE_O_MECH_VARIANT2
|
||||||
if (USE_ALLOWED_MECHS)
|
if (USE_ALLOWED_MECHS)
|
||||||
last_count = stock_array[allowed_mechs[o_mech_variant[k].nselected]]
|
last_count = stock_array[allowed_mechs[o_mech_variant[k].nselected]]
|
||||||
@@ -2714,7 +2847,8 @@ main
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// MSL 5.06
|
// 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"
|
o_error_string.text = "Too many player/bots"
|
||||||
nLaunchState = -7
|
nLaunchState = -7
|
||||||
@@ -4000,17 +4134,24 @@ mech_randomizer
|
|||||||
else // right button
|
else // right button
|
||||||
{
|
{
|
||||||
int pick_mech = 0
|
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
|
// MSL
|
||||||
|
// MechCorps Highlight: Super6 - added Archer (0) and Warhammer (5) to right-click mech pool
|
||||||
if pick_mech = 0
|
if pick_mech = 0
|
||||||
last_mech = ROOKIEMECH1 // Loki
|
last_mech = ROOKIEMECH1 // Archer
|
||||||
if pick_mech = 1
|
if pick_mech = 1
|
||||||
last_mech = ROOKIEMECH2 // Madcat
|
last_mech = ROOKIEMECH2 // Loki
|
||||||
if pick_mech = 2
|
if pick_mech = 2
|
||||||
last_mech = ROOKIEMECH3 // Thor
|
last_mech = ROOKIEMECH3 // Madcat
|
||||||
if pick_mech = 3
|
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)
|
if (USE_ALLOWED_MECHS)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -52,6 +52,7 @@
|
|||||||
#define MAIL_PREVIOUS_MISSION -2222
|
#define MAIL_PREVIOUS_MISSION -2222
|
||||||
#define MAIL_RECORD_MISSION -4444
|
#define MAIL_RECORD_MISSION -4444
|
||||||
#define MAIL_PREVIOUS_MISSION_PARAMS -5555
|
#define MAIL_PREVIOUS_MISSION_PARAMS -5555
|
||||||
|
#define MAIL_LOAD_AUTO_MISSION -6666 // [automaticmode] sync with ConLobby.script
|
||||||
|
|
||||||
#define ROOKIE_MISSION "ScarabStronghold - Attrition"
|
#define ROOKIE_MISSION "ScarabStronghold - Attrition"
|
||||||
|
|
||||||
@@ -793,15 +794,15 @@ main
|
|||||||
if (getmessage() == MAIL_SET_ROOKIE_MISSION) // set rookie, see conlobby.script
|
if (getmessage() == MAIL_SET_ROOKIE_MISSION) // set rookie, see conlobby.script
|
||||||
{
|
{
|
||||||
// caution: actually 0 is not correct but who care? ^^
|
// 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)
|
mail(MAIL_SET_ROOKIE_MISSION, this)
|
||||||
}
|
}
|
||||||
// find mission:
|
// find mission:
|
||||||
for k = 0; k < o_game_options[1].list_size; k++
|
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
|
// found mission
|
||||||
break
|
break
|
||||||
@@ -830,6 +831,82 @@ main
|
|||||||
mail(MAIL_PREVIOUS_MISSION_PARAMS, this)
|
mail(MAIL_PREVIOUS_MISSION_PARAMS, this)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// [automaticmode] Load File button: apply Auto globals, separate from Rookie Mission defaults
|
||||||
|
if (getmessage() == MAIL_LOAD_AUTO_MISSION)
|
||||||
|
{
|
||||||
|
callback($$SetNetworkMissionParamater$$, game_type, selection_to_standard[$$g_nAutoGameType$$])
|
||||||
|
// visibility
|
||||||
|
o_game_options[2].nselected = $$g_nAutoVisibility$$
|
||||||
|
callback($$SetNetworkMissionParamater$$, visibility, o_game_options[2].nselected)
|
||||||
|
// weather
|
||||||
|
o_game_options[3].nselected = $$g_nAutoWeather$$
|
||||||
|
callback($$SetNetworkMissionParamater$$, weather, o_game_options[3].nselected)
|
||||||
|
// time of day
|
||||||
|
o_game_options[4].nselected = $$g_nAutoTimeOfDay$$
|
||||||
|
callback($$SetNetworkMissionParamater$$, night_parameter, o_game_options[4].nselected)
|
||||||
|
callback($$Shell_CallbackHandler$$, ShellSetTime, o_game_options[4].nselected)
|
||||||
|
// time limit
|
||||||
|
int nAutoTL = $$g_nAutoTimeLimit$$
|
||||||
|
int temp_num
|
||||||
|
if nAutoTL >= 0
|
||||||
|
temp_num = nAutoTL
|
||||||
|
else
|
||||||
|
temp_num = TIME_VALUE_DEFAULT
|
||||||
|
int m
|
||||||
|
for (m = 0; m < o_game_options[5].list_size; m++)
|
||||||
|
{
|
||||||
|
if (makeint(o_game_options[5].list_item[m]) == temp_num)
|
||||||
|
{
|
||||||
|
o_game_options[5].nselected = m
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
callback($$SetNetworkMissionParamater$$, time_limit, temp_num)
|
||||||
|
// radar
|
||||||
|
int nTempParam = radar
|
||||||
|
int nTempValue = $$g_nAutoRadar$$
|
||||||
|
o_game_options[6].nselected = nTempValue
|
||||||
|
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
|
||||||
|
// heat
|
||||||
|
nTempParam = HEAT_PARAMETER
|
||||||
|
nTempValue = $$g_nAutoHeat$$
|
||||||
|
o_game_options[7].state = 0
|
||||||
|
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
|
||||||
|
// friendly fire
|
||||||
|
nTempParam = FRIENDLY_FIRE_PERCENTGE_PARAMETER
|
||||||
|
nTempValue = $$g_nAutoFriendlyFire$$
|
||||||
|
o_game_options[8].state = 0
|
||||||
|
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
|
||||||
|
// splash
|
||||||
|
nTempParam = SPLASH_ON_PARAMETER
|
||||||
|
nTempValue = $$g_nAutoSplash$$
|
||||||
|
o_game_options[9].state = 0
|
||||||
|
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
|
||||||
|
// unlimited ammo
|
||||||
|
nTempParam = UNLIMITED_AMMO_PARAMETER
|
||||||
|
nTempValue = $$g_nAutoUnlimitedAmmo$$
|
||||||
|
o_game_options[10].state = 0
|
||||||
|
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
|
||||||
|
// weapon jam
|
||||||
|
nTempParam = WEAPON_JAM_PARAMETER
|
||||||
|
nTempValue = $$g_nAutoWeaponJam$$
|
||||||
|
o_game_options[14].state = 0
|
||||||
|
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
|
||||||
|
// advance mode
|
||||||
|
nTempParam = ADVANCE_MODE_PARAMETER
|
||||||
|
nTempValue = $$g_nAutoAdvanceMode$$
|
||||||
|
o_game_options[15].state = 0
|
||||||
|
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
|
||||||
|
// armor mode
|
||||||
|
nTempParam = ARMOR_MODE_PARAMETER
|
||||||
|
nTempValue = $$g_nAutoArmorMode$$
|
||||||
|
o_game_options[16].state = 0
|
||||||
|
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
|
||||||
|
initialize(this)
|
||||||
|
// notify ConLobby: game type/params changed (updates cur_game_type, cur_team_val display)
|
||||||
|
mail(-9998, parent)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (sender == this)
|
if (sender == this)
|
||||||
{
|
{
|
||||||
@@ -855,24 +932,26 @@ main
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// visibility
|
// 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)
|
callback($$SetNetworkMissionParamater$$, visibility, o_game_options[2].nselected)
|
||||||
|
|
||||||
// weather
|
// 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)
|
callback($$SetNetworkMissionParamater$$, weather, o_game_options[3].nselected)
|
||||||
|
|
||||||
// time of day
|
// 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($$SetNetworkMissionParamater$$, night_parameter, o_game_options[4].nselected)
|
||||||
callback($$Shell_CallbackHandler$$, ShellSetTime, o_game_options[4].nselected)
|
callback($$Shell_CallbackHandler$$, ShellSetTime, o_game_options[4].nselected)
|
||||||
}
|
}
|
||||||
|
// time limit - use ini override if set, else TIME_VALUE_DEFAULT
|
||||||
// time limit
|
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++
|
for k = 0; k < o_game_options[5].list_size; k++
|
||||||
{
|
{
|
||||||
temp_num = makeint(o_game_options[5].list_item[k])
|
if (makeint(o_game_options[5].list_item[k]) == temp_num)
|
||||||
if (temp_num == TIME_VALUE_DEFAULT)
|
|
||||||
{
|
{
|
||||||
o_game_options[5].nselected = k
|
o_game_options[5].nselected = k
|
||||||
break
|
break
|
||||||
@@ -935,31 +1014,31 @@ main
|
|||||||
{
|
{
|
||||||
// radar
|
// radar
|
||||||
nTempParam = radar
|
nTempParam = radar
|
||||||
nTempValue = 0 // Novice
|
nTempValue = $$g_nRookieRadar$$ // [RookieMission] ini (0=Novice)
|
||||||
o_game_options[6].nselected = nTempValue
|
o_game_options[6].nselected = nTempValue
|
||||||
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
|
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
|
||||||
|
|
||||||
// heat management
|
// heat management
|
||||||
nTempParam = HEAT_PARAMETER
|
nTempParam = HEAT_PARAMETER
|
||||||
nTempValue = 0
|
nTempValue = $$g_nRookieHeat$$ // [RookieMission] ini
|
||||||
o_game_options[7].state = 0
|
o_game_options[7].state = 0
|
||||||
callback($$SetNetworkMissionParamater$$,nTempParam, nTempValue)
|
callback($$SetNetworkMissionParamater$$,nTempParam, nTempValue)
|
||||||
|
|
||||||
// friendly fire
|
// friendly fire
|
||||||
nTempParam = FRIENDLY_FIRE_PERCENTGE_PARAMETER
|
nTempParam = FRIENDLY_FIRE_PERCENTGE_PARAMETER
|
||||||
nTempValue = 0
|
nTempValue = $$g_nRookieFriendlyFire$$ // [RookieMission] ini
|
||||||
o_game_options[8].state = 0
|
o_game_options[8].state = 0
|
||||||
callback($$SetNetworkMissionParamater$$,nTempParam, nTempValue)
|
callback($$SetNetworkMissionParamater$$,nTempParam, nTempValue)
|
||||||
|
|
||||||
// splash
|
// splash
|
||||||
nTempParam = SPLASH_ON_PARAMETER
|
nTempParam = SPLASH_ON_PARAMETER
|
||||||
nTempValue = 0
|
nTempValue = $$g_nRookieSplash$$ // [RookieMission] ini
|
||||||
o_game_options[9].state = 0
|
o_game_options[9].state = 0
|
||||||
callback($$SetNetworkMissionParamater$$,nTempParam, nTempValue)
|
callback($$SetNetworkMissionParamater$$,nTempParam, nTempValue)
|
||||||
|
|
||||||
// unlimited ammo
|
// unlimited ammo
|
||||||
nTempParam = UNLIMITED_AMMO_PARAMETER
|
nTempParam = UNLIMITED_AMMO_PARAMETER
|
||||||
nTempValue = 1 // be cautious
|
nTempValue = $$g_nRookieUnlimitedAmmo$$ // [RookieMission] ini
|
||||||
o_game_options[10].state = 0
|
o_game_options[10].state = 0
|
||||||
callback($$SetNetworkMissionParamater$$,nTempParam, nTempValue)
|
callback($$SetNetworkMissionParamater$$,nTempParam, nTempValue)
|
||||||
|
|
||||||
@@ -975,7 +1054,7 @@ main
|
|||||||
|
|
||||||
// weapon jam
|
// weapon jam
|
||||||
nTempParam = WEAPON_JAM_PARAMETER
|
nTempParam = WEAPON_JAM_PARAMETER
|
||||||
nTempValue = 0
|
nTempValue = $$g_nRookieWeaponJam$$ // [RookieMission] ini
|
||||||
o_game_options[14].state = 0
|
o_game_options[14].state = 0
|
||||||
callback($$SetNetworkMissionParamater$$,nTempParam, nTempValue)
|
callback($$SetNetworkMissionParamater$$,nTempParam, nTempValue)
|
||||||
|
|
||||||
@@ -987,13 +1066,13 @@ main
|
|||||||
|
|
||||||
// advance mode
|
// advance mode
|
||||||
nTempParam = ADVANCE_MODE_PARAMETER
|
nTempParam = ADVANCE_MODE_PARAMETER
|
||||||
nTempValue = 0
|
nTempValue = $$g_nRookieAdvanceMode$$ // [RookieMission] ini
|
||||||
o_game_options[15].state = 0
|
o_game_options[15].state = 0
|
||||||
callback($$SetNetworkMissionParamater$$,nTempParam, nTempValue)
|
callback($$SetNetworkMissionParamater$$,nTempParam, nTempValue)
|
||||||
|
|
||||||
// armor mode
|
// armor mode
|
||||||
nTempParam = ARMOR_MODE_PARAMETER
|
nTempParam = ARMOR_MODE_PARAMETER
|
||||||
nTempValue = 0
|
nTempValue = $$g_nRookieArmorMode$$ // [RookieMission] ini
|
||||||
o_game_options[16].state = 0
|
o_game_options[16].state = 0
|
||||||
callback($$SetNetworkMissionParamater$$,nTempParam, nTempValue)
|
callback($$SetNetworkMissionParamater$$,nTempParam, nTempValue)
|
||||||
|
|
||||||
@@ -1005,6 +1084,81 @@ main
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (getmessage() == MAIL_PREVIOUS_MISSION_PARAMS)
|
if (getmessage() == MAIL_PREVIOUS_MISSION_PARAMS)
|
||||||
|
{
|
||||||
|
callback($$SetNetworkMissionParamater$$, game_type, selection_to_standard[$$g_nAutoGameType$$])
|
||||||
|
// visibility
|
||||||
|
o_game_options[2].nselected = $$g_nAutoVisibility$$
|
||||||
|
callback($$SetNetworkMissionParamater$$, visibility, o_game_options[2].nselected)
|
||||||
|
// weather
|
||||||
|
o_game_options[3].nselected = $$g_nAutoWeather$$
|
||||||
|
callback($$SetNetworkMissionParamater$$, weather, o_game_options[3].nselected)
|
||||||
|
// time of day
|
||||||
|
o_game_options[4].nselected = $$g_nAutoTimeOfDay$$
|
||||||
|
callback($$SetNetworkMissionParamater$$, night_parameter, o_game_options[4].nselected)
|
||||||
|
callback($$Shell_CallbackHandler$$, ShellSetTime, o_game_options[4].nselected)
|
||||||
|
// time limit
|
||||||
|
int nAutoTL = $$g_nAutoTimeLimit$$
|
||||||
|
int temp_num
|
||||||
|
if nAutoTL >= 0
|
||||||
|
temp_num = nAutoTL
|
||||||
|
else
|
||||||
|
temp_num = TIME_VALUE_DEFAULT
|
||||||
|
int m
|
||||||
|
for (m = 0; m < o_game_options[5].list_size; m++)
|
||||||
|
{
|
||||||
|
if (makeint(o_game_options[5].list_item[m]) == temp_num)
|
||||||
|
{
|
||||||
|
o_game_options[5].nselected = m
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
callback($$SetNetworkMissionParamater$$, time_limit, temp_num)
|
||||||
|
// radar
|
||||||
|
int nTempParam = radar
|
||||||
|
int nTempValue = $$g_nAutoRadar$$
|
||||||
|
o_game_options[6].nselected = nTempValue
|
||||||
|
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
|
||||||
|
// heat
|
||||||
|
nTempParam = HEAT_PARAMETER
|
||||||
|
nTempValue = $$g_nAutoHeat$$
|
||||||
|
o_game_options[7].state = 0
|
||||||
|
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
|
||||||
|
// friendly fire
|
||||||
|
nTempParam = FRIENDLY_FIRE_PERCENTGE_PARAMETER
|
||||||
|
nTempValue = $$g_nAutoFriendlyFire$$
|
||||||
|
o_game_options[8].state = 0
|
||||||
|
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
|
||||||
|
// splash
|
||||||
|
nTempParam = SPLASH_ON_PARAMETER
|
||||||
|
nTempValue = $$g_nAutoSplash$$
|
||||||
|
o_game_options[9].state = 0
|
||||||
|
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
|
||||||
|
// unlimited ammo
|
||||||
|
nTempParam = UNLIMITED_AMMO_PARAMETER
|
||||||
|
nTempValue = $$g_nAutoUnlimitedAmmo$$
|
||||||
|
o_game_options[10].state = 0
|
||||||
|
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
|
||||||
|
// weapon jam
|
||||||
|
nTempParam = WEAPON_JAM_PARAMETER
|
||||||
|
nTempValue = $$g_nAutoWeaponJam$$
|
||||||
|
o_game_options[14].state = 0
|
||||||
|
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
|
||||||
|
// advance mode
|
||||||
|
nTempParam = ADVANCE_MODE_PARAMETER
|
||||||
|
nTempValue = $$g_nAutoAdvanceMode$$
|
||||||
|
o_game_options[15].state = 0
|
||||||
|
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
|
||||||
|
// armor mode
|
||||||
|
nTempParam = ARMOR_MODE_PARAMETER
|
||||||
|
nTempValue = $$g_nAutoArmorMode$$
|
||||||
|
o_game_options[16].state = 0
|
||||||
|
callback($$SetNetworkMissionParamater$$, nTempParam, nTempValue)
|
||||||
|
initialize(this)
|
||||||
|
// notify ConLobby: game type/params changed (updates cur_game_type, cur_team_val display)
|
||||||
|
mail(-9998, parent)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (getmessage() == MAIL_PREVIOUS_MISSION_PARAMS)
|
||||||
{
|
{
|
||||||
// visibility
|
// visibility
|
||||||
o_game_options[2].nselected = game_options_2
|
o_game_options[2].nselected = game_options_2
|
||||||
|
|||||||
BIN
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
Reference in New Issue
Block a user