58 Commits
Author SHA1 Message Date
a0331e78d2 Compiled Build 5.1.0b_RC1 Files
Deployed game tree copied back from the Windows build machine, containing the
compiled 5.1.0b_RC1 binaries and every asset the deploy produces. 846 files:
21 added, 825 modified.

Freshly built binaries: MW4.exe, Launcher.exe, autoconfig.exe, ctcls.dll,
MissionLang.dll, ScriptStrings.dll, Language.dll and the rest of the runtime DLL
set, carrying everything merged this cycle -- the 16-pilots-plus-cameraship launch
fix, the MFD mode 4 split-display support and its stutter fix, -tmon, -tcoop, -fps,
-tbaud, the Load File console lobby feature, configurable Rookie Mission, and the
English Language.dll build.

New in the deployment:
- set-appcompat.bat / set-appcompat.ps1 -- the one-click AppCompat shim installer,
  now shipped by deploy-mw4.ps1 so any copy of an install can repair its own
  registration (the layer is keyed on the exe's full path).
- libmysql.dll -- required by mw4print 2.0's MySQL export, late-bound at runtime.
- Four hsh art files restored from 5.0.7D: MFD/assassin2.bmp, Mechs/battlemaster
  iic.bmp, Mechs/behemoth ii.bmp, Mechs/mad cat mkii.bmp.
- banner.txt, dbstruct.txt -- mw4print banner text and the exported DB structure
  reference.

dgVoodoo2 is included as MW4/dgvoodoo2_files/ -- deliberately in a subfolder and
NOT alongside the executable. Nothing loads from there, so the files are available
for a pod owner to install on Windows 10/11 without being active by default. This
keeps XP pods safe: they use native DirectDraw, and having dgVoodoo2 loose in the
game folder would break them. Do not move these files up a level in the repo.

Runtime leftovers from testing on the build machine are included as well
(DDrawCompat logs, DebugLog.txt, mw4-help.txt, two screenshots), consistent with
this repo's stated purpose as a full disaster-recovery mirror in which nothing is
excluded on purpose.

All binaries and art are stored via Git LFS per .gitattributes; verified that
MW4.exe, libmysql.dll, the dgVoodoo2 DLLs and the screenshots staged as LFS
pointers rather than raw blobs.

Co-authored-by: Claude Opus 5 (Anthropic) <noreply@anthropic.com>
Co-authored-by: GitHub Copilot <copilot@github.com>
2026-07-25 19:52:43 -05:00
1b931d5fb8 Correct dgVoodoo2 guidance: never ship it, XP pods must not have it
Two corrections from the project owner.

1. dgVoodoo2 must NEVER be added to the repo or the deploy script.

The pod fleet is mixed. XP pods use native DirectDraw and need nothing extra --
installing dgVoodoo2 on them BREAKS them. Only Windows 10/11 pods need it, and
only for the MFD modes. It is therefore an installed-per-machine, OS-dependent
prerequisite that the pod owner sets up, not a build artifact.

This reverses the recommendation added in the previous commit, which suggested
versioning the working dgVoodoo.conf and having deploy-mw4.ps1 place it. That
advice was wrong: it would have pushed a Win10-only dependency onto every XP
machine. dgVoodoo.conf and dgVoodooCpl.exe were removed in 0ceba9c7 deliberately
and must stay out.

- CLAUDE.md STEP 10: the "TODO: commit it" note is replaced with the reasoning,
  flagged so nobody re-adds the files later thinking it was an oversight.
- CLAUDE.md Next steps: that TODO is removed. The borderless-windowed item now
  notes it is the only route that removes the dgVoodoo2 prerequisite WITHOUT
  breaking the XP pods, since it needs no external DLL on either OS.
- Release notes gain an explicit warning callout: dgVoodoo2 is not part of the
  build and must not be installed on XP pods, with the advice to configure it per
  machine rather than inside the game folder that gets copied around. Without this
  an owner with a mixed fleet could reasonably have copied a working Win10 install
  onto an XP pod and broken it.

2. Version numbering is intentional, not a mismatch.

V5.1.0b<n> denotes beta build n; these are handed out as release candidates for
testing. The "b" is dropped and it becomes 5.1.0 when the release is final. So the
console string V5.1.0b1 alongside a release named V5.1.0b_RC1 is expected, and the
earlier suggestion to reconcile them is withdrawn.

Both release-notes formats regenerated; the XP warning renders as a warning
callout in the HTML. Both remain plain ASCII with CRLF.

Co-authored-by: Claude Opus 5 (Anthropic) <noreply@anthropic.com>
Co-authored-by: GitHub Copilot <copilot@github.com>
2026-07-25 19:47:26 -05:00
10dab8f2d5 Add V5.1.0b_RC1 end-user release notes (markdown + HTML)
Release notes covering the 58 commits since dbcf4052 (-tbaud), written for pod
owners rather than developers: what changed, what the defaults are if they touch
nothing, and how to switch on anything new.

Two formats. The HTML is generated from the markdown so the two cannot drift, and
carries the same inline styling as BTFrstrm/autoconfig-file-spec.html -- no external
files, opens in any browser, prints cleanly. Both are plain ASCII with CRLF so they
open correctly in Notepad on a pod.

Structure leads with the two things that will otherwise generate support traffic:
running set-appcompat.bat after install (the AppCompat layer is keyed on the install
path, and its absence produces the misleading "Another application is preventing use
of full screen mode"), and the dgVoodoo2 scaling mode, which fails silently when set
wrong. Every command line switch is listed with an explicit "if you leave it off"
column.

Facts checked against the source while writing, and corrected:

- [RookieMission] key names. The first draft documented RookieMission=, RookieGameType=
  and so on -- the internal variable names. The game actually reads MissionName,
  GameType, TimeLimit, Visibility, Weather, TimeOfDay, Radar, HeatOn, FriendlyFire,
  SplashDamage, UnlimitedAmmo, WeaponJam, AdvanceMode, ArmorMode. Anyone following the
  draft would have edited options.ini and seen no effect with nothing to explain why.
  The section now carries the full annotated block verbatim from options.ini, and all
  14 documented keys are machine-verified against MW4Shell.cpp.

- [automaticmode] needs TWO keys, not one. automaticmode=1 shows the Load File button;
  automaticfile=<path> tells it what to load. Without the second, CTCL_LoadAutoFile
  returns immediately -- the button appears and silently does nothing. Both are now
  documented in a table, with the path rules (bare filename resolves next to MW4.exe,
  or give a full path).

- dgVoodoo2 is required on Windows 10/11 for EVERY MFD mode, including the original
  spanned display (-tmfds 1 and 3), not only the new split mode (-tmfds 4). The first
  draft implied it was specific to the new feature, which would have led owners running
  the span to skip it.

- The mw4print MySQL export is flagged as included but not yet tested against a live
  server. Everything else in the notes is confirmed working by the project owner.
  libmysql.dll ships in the deployment (Gameleap/mw4, kept by the deploy's root *.dll
  rule and not on the skip list), so there is nothing for owners to download.

Also repaired 23 em dashes that had been written as literal '?' characters, including
in headings -- a side effect of the workspace saving new files as CP949, which cannot
represent them. Both files are now pure ASCII.

Co-authored-by: Claude Opus 5 (Anthropic) <noreply@anthropic.com>
Co-authored-by: GitHub Copilot <copilot@github.com>
2026-07-25 19:22:54 -05:00
2f4ed244ea Fix -fps logger measuring its own overhead; buffer output, fix percentiles
First real run of -fps (222 seconds, 4-monitor bench, in-mission) showed a
rock-solid 60.0 fps average but a worst frame of ~24ms in 82% of seconds, with a
median of 24.4ms and a minimum of 23.2ms. That regularity was the tell: 60Hz vsync
intervals are 16.7 / 33.3 / 50.0 ms, so 24ms is not a multiple of anything and had
no business recurring once per second with that consistency.

Cause: the logger was measuring itself. The per-second line was written straight to
the file with WriteFile on the render thread, and the frame duration is recorded
BEFORE the line is emitted -- so the write's cost landed in the *next* frame's
measurement, which belongs to the next second's bucket. Result: exactly one
inflated frame per second, indefinitely. Holding the handle open (as the first
version did) was not enough; a single WriteFile is still several milliseconds when
something like antivirus is in the path.

Three fixes:

1. Buffered output. Lines accumulate in a 128 KB static buffer (~2000 rows, about
   33 minutes at one row per second) and are flushed only when the buffer fills or
   at exit via atexit(). A normal measurement session now performs no file writes
   at all while running. Trade-off, deliberately accepted: a hard crash loses the
   un-flushed tail. gos-displays.txt remains the crash-survivable log; gos-fps.txt
   is a measurement instrument and must not perturb what it measures.

2. Meaningful percentiles. A "1% low" over 60 samples per second computes
   nFrames/100 = 0, which was clamped to 1 -- so the column was literally
   1000/worst_frame, i.e. the worst-frame column restated in different units.
   Verified against the log: worst 24.1ms -> 41.5 fps, exactly the "1% low" printed.
   Per-second is now a 5% low (worst 3 of 60), which is a number that actually
   differs from the worst frame. True whole-session 1% and 0.1% lows are computed
   at exit from a 0.5ms-bucket frame time histogram (2000 buckets, 0-1000ms) and
   printed in a new session summary along with total frames, elapsed time, average,
   and total hitches. The histogram gives exact-enough percentiles over an entire
   session without retaining every frame time.

3. Carry-over. A single frame longer than one second (a level load: the log shows
   4338ms and 4799ms frames) left the accumulator above the 1000ms threshold, so
   the next few frames each emitted their own bogus one-frame row -- visible in the
   log as rows reporting "1 frame, 1339 fps". The excess is now discarded.

Also adds #include <stdlib.h> to WinMain.cpp for atexit(); it was not reachable
through pch.hpp. GOS_FpsAtExit is declared __cdecl: GameOS builds with /Gz, which
makes __stdcall the default calling convention, but atexit() takes a __cdecl
callback -- without it VC6 rejects the call with C2664.

What the run did establish, and still stands: 60 frames per second sustained for
~150 seconds with no rhythmic multi-hitch pattern, so the mode 4 split-MFD stutter
fix (0a657b59) is holding. Genuine dropped frames (>40ms) occurred in 18% of
seconds, including clusters of 80-90ms; those are real and unaffected by this fix.
Re-measure after this change to see the true baseline.

CLAUDE.md STEP 10 updated: the previous claim that holding the handle open kept the
logger from perturbing the measurement was wrong, and is replaced with what was
actually observed.

Co-authored-by: Claude Opus 5 (Anthropic) <noreply@anthropic.com>
Co-authored-by: GitHub Copilot <copilot@github.com>
2026-07-25 18:43:42 -05:00
9c67dddd83 Display diagnostics + -fps/-tcoop; native multi-monitor MFD ruled out
Four-monitor MFD bring-up on the new bench (MR_new: AMD FirePro W4100, 4 outputs,
Win10). Adds permanent display diagnostics, a Release-capable frame pacing logger,
a self-locating AppCompat shim installer, and settles -- empirically -- whether
dgVoodoo2 can be dropped for the multi-monitor MFD modes. It cannot.

WHY THIS WAS HARD
-----------------
CHSH_Device::InitFirst/InitSecond discarded EVERY HRESULT (SetCooperativeLevel,
SetDisplayMode, CreateSurface, GetAttachedSurface, QueryInterface, CreateDevice)
and returned true unconditionally. A panel that failed to open produced no error,
no crash and no log entry -- the monitor just stayed on the desktop. SPEW is
compiled out of shipping builds, so none of it was visible. Restoring that
visibility is what unblocked everything else.

DIAGNOSTICS ADDED (keep these)
------------------------------
* VideoCard.cpp -- LogDisplayDevices() writes gos-displays.txt next to the exe:
  NumDevices/NumHWDevices/NumMonitors, every DirectDraw device with its
  hw_rasterization flag, the role assignment (FullScreenDevice / g_nNonDualHead /
  g_nDualHead / g_nDualHead2 / g_nMFD1 / g_nMFD2), per-slot -tmon APPLIED/REJECTED
  (previously silent), and whether mode 4's "BOTH mfd1 and mfd2" requirement is met.
* render.cpp -- HSH_LogInit()/HSH_CheckHR()/HSH_HRName() log every DirectDraw call
  in the panel init path with its HRESULT decoded by name (27 DDERR_* codes, all
  verified present and collision-free against build-env/dx7asdk/include/ddraw.h).
  Each line is opened/appended/closed individually so the log survives a crash.
* WinMain.cpp -- GOS_LogFrameRate() writes gos-fps.txt: per second, frame count,
  average fps, 1% low (mean of the worst 1% of frames), worst frame in ms, and a
  count of frames exceeding 2x average ("hitches"). Average fps alone cannot
  distinguish 60fps from 60fps-with-a-dropped-frame-every-second; the 1% low can.
  The engine's own FrameRate readout is #ifdef LAB_ONLY (MWMission.cpp) so it only
  exists in MW4pro.exe; this works in Release, which is what runs on the pods.

NEW SWITCHES (both documented in -help)
---------------------------------------
* -fps    Enable the frame pacing report. Off by default: the gate is the first
          statement in GOS_LogFrameRate, so an unflagged run does no arithmetic
          and does not even create the file. The file handle is held open for the
          process lifetime -- opening/closing it every second would put a syscall
          of unpredictable latency on the render thread, i.e. the measurement tool
          perturbing what it measures.
* -tcoop <0-5>  Selects the SetCooperativeLevel form used by the radar/MFD panels.
          0 = legacy (unchanged shipped behaviour, remains the default).
          Exists so every candidate fix could be compared on real hardware without
          a rebuild between attempts.

CRASH-SAFETY FIX
----------------
hsh_initialized was set unconditionally after panel init, so a failed panel left
null surfaces and a null IDirect3DDevice7 behind and the per-frame path called
straight through them. Now:
  - all four InitSecond overrides (CMR/CRadar/CMFD/CMFDRight) bail on base failure,
  - CMFD_Device::InitFirst reports its real result instead of always returning true,
  - hsh_initialized is only set when the panels genuinely came up.
A display failure now leaves the game running without MFDs instead of bombing to
desktop. Crash signature for the record: `call [ecx+0x44]` with ECX=0 is
IDirectDrawSurface7::GetDC on a never-created surface (vtable offset confirmed
against the DX7 header), reported as "Attempt to read from address 0x00000044".

APPCOMPAT SHIM INSTALLER (new)
------------------------------
build-env/set-appcompat.ps1 + set-appcompat.bat. Self-locating via $PSScriptRoot:
applies DWM8And16BitMitigation to the MW4 executables sitting next to it, wherever
that install lives. HKCU always, HKLM too when elevated (the HKLM value format
differs -- it carries a leading "$" marker -- so the two must not be interchanged).
Verifies by reading back; detects the HIGHDPIAWARE-only entry that SUPPRESSES the
automatic shim; supports -Remove and -WhatIfOnly. deploy-mw4.ps1 now ships both
files into every deployment.

This matters because the layer is keyed on the executable's FULL PATH -- any copy
of an install to another folder or machine silently loses it, and the resulting
error is actively misleading (see below).

WHAT WE LEARNED
---------------
* The AppCompat shim SYNTHESISES 16-bit display modes. Proved directly: the crash
  dump shows "16 bit modes :" EMPTY without it and fully populated with it. MW4
  renders at bitdepth=16 and modern GPUs expose no 16-bit modes at all.
* Without the shim, GameOS reports "Another application is preventing use of full
  screen mode" (GOS_DXRASTERIZER_NOFULLSCREEN, DXRasterizer.cpp ~1125). That is a
  catch-all fired after every SetDisplayMode attempt fails -- it even scans for
  NetMeeting -- and it sends you looking for a conflicting program that does not
  exist. The real cause is the missing shim.
* Exclusive fullscreen DOES work on Win10 with the system ddraw.dll and dgVoodoo2
  physically removed, once the shim is applied to that exe path.
* Windowed mode works natively with no shim at all: the windowed path sets
  Environment.bitDepth = DesktopBpp (32), so there is no mode switch. Verified for
  the console/shell; a full mission windowed is still untested.
* Native DirectDraw enumerates all four W4100 outputs, so dgVoodoo2 was never
  needed for device enumeration.
* The engine is 4:3 ONLY. ImageHlp.cpp ~464 asserts the complete supported set:
  640x480, 512x384, 800x600, 960x720, 1024x768, 1280x1024 (5:4), 1600x1200. No
  16:9 mode and no aspect correction anywhere in the codebase. On a 16:9 monitor
  the scaler must adapt: plain stretch distorts geometry, keep-aspect pillarboxes.
* -2dt is not a recognised switch anywhere in the codebase, despite appearing in
  production ctcl.ini launch lines. Completely inert.
* NumHWDevices (5) can exceed NumDevices (4): it counts D3D device-enumeration
  callbacks, and an adapter exposing both a HAL and a T&L HAL yields two. Benign.

WHAT WE TRIED AND WHY IT FAILED
-------------------------------
The panel cooperative-level call was genuinely wrong -- a latent 2002 bug. Every
panel asked to be BOTH the process focus window AND its own device window, on the
one shared hWindow, after the main device had already taken exclusive mode on it.
The main device (DXRasterizer.cpp ~1027) already uses the correct two-call idiom
(SETFOCUSWINDOW alone, then EXCLUSIVE|FULLSCREEN) -- tagged //sanghoon, the same
author. The panels never were.

Results on real hardware, no dgVoodoo2, shim applied, -tmfds 4:

  -tcoop 0  SETFOCUSWINDOW|CREATEDEVICEWINDOW|ALLOWREBOOT|EXCLUSIVE|FULLSCREEN
            -> DDERR_EXCLUSIVEMODEALREADYSET
  -tcoop 1  CREATEDEVICEWINDOW|EXCLUSIVE|FULLSCREEN (no focus claim)
            -> DDERR_INVALIDPARAMS (CREATEDEVICEWINDOW needs a focus window)
  -tcoop 2  SETFOCUSWINDOW, then CREATEDEVICEWINDOW|EXCLUSIVE|FULLSCREEN
            -> DDERR_INVALIDPARAMS
  -tcoop 3  SETFOCUSWINDOW, then EXCLUSIVE|FULLSCREEN
            -> first panel collides, but that collision STEALS exclusive mode from
               the main display, after which panels 2 and 3 fully initialise (the
               radar reached CreateDevice(HAL) = DD_OK -- a secondary panel running
               entirely on native DirectDraw). Side effect: the desktop was left at
               1920x1080 16bpp. Not viable.
  -tcoop 4  EXCLUSIVE|FULLSCREEN only          -> EXCLUSIVEMODEALREADYSET, all panels
  -tcoop 5  ALLOWREBOOT|EXCLUSIVE|FULLSCREEN   -> EXCLUSIVEMODEALREADYSET, all panels

CONCLUSION: on modern Windows only ONE DirectDraw object per process may hold
exclusive fullscreen. The main display takes it; every secondary panel is refused.
XP allowed multiple. dgVoodoo2 allows it because it is a full reimplementation of
ddraw and is not bound by that rule -- it is not papering over a bug we can fix.

=> dgVoodoo2 CANNOT be removed for -tmfds 1/3/4 by correcting these flags. The
default stays -tcoop 0. The switch is retained because it is how this was settled
and it will re-settle it on different hardware.

The only native path is a borderless windowed panel design (DDSCL_NORMAL + clipper
per monitor, no exclusive mode anywhere). Assessment and staged plan are recorded
in CLAUDE.md STEP 10; not started.

WORKING 4-MONITOR CONFIG (with dgVoodoo2)
-----------------------------------------
dgVoodoo2 Scaling mode MUST be "Stretched, Keep Aspect Ratio". Plain "Stretched"
fails silently: main and radar go fullscreen black, both MFD monitors keep showing
the desktop, and every DirectDraw call still returns DD_OK -- the devices are alive
but dgVoodoo2 never drives those outputs. Diagnosed with a temporary per-panel
colour-flash test (since removed), which also established that device index maps
1:1 to physical monitor on this bench, so -tmon 1,2,3,4 equals auto-detection.
Confirmed working end to end: all three secondary panels present, full mission
played.

KNOWN GAP: the working dgVoodoo.conf is still not versioned in the repo (removed
in 0ceba9c7), so a fresh deploy will reproduce the silent MFD failure.

Behaviour with no new switches supplied is unchanged from the previous build
except on failure paths, which now degrade gracefully instead of crashing.

Co-authored-by: Claude Opus 5 (Anthropic) <noreply@anthropic.com>
Co-authored-by: GitHub Copilot <copilot@github.com>
2026-07-25 18:22:31 -05:00
f402e5becc Add OPTIONS-INI.md reference
options.ini had no documentation. This documents every section and key, compiled
by reading the actual read sites rather than by describing the shipped file, so
that settings which look active but are not are identified as such.

Covers [graphics options], [sound options], [special commands], [server],
[joystick], [Cameraship Params], [Battle Tech Misc], [RookieMission] and
[battle tech print], plus how the file is loaded, which parts the game writes
back, and the per-role options-game/cam/mr variants.

Notable findings, all verified against source:

- The entire [network options] section is DEAD. None of connectiontype,
  connectionspeed, packetsize, defaultconnection, playericon or teamicon is read
  by any code; the connection type actually used comes from the multiplayer
  connection wizard. These are stock MW4 leftovers.

- Several [Battle Tech Misc] keys have names that do not describe what they do,
  and the real meanings are now recorded: RuleBook sets g_nMechVariant, DawnWar
  sets g_nMechLabOp, BiggieSizeIt sets g_nMechPodNum (the console lobby's larger
  roster flag), and CanYouHearTheFootSteps sets g_nBlackMech.

- The shipped options.ini misspells two keys. It contains secmissionreplay and
  secmissionreport, but the code reads SecsMissionReplay and SecsMissionReport.
  The shipped values are therefore ignored and the compiled defaults apply.

- Three keys are read and then immediately overridden, so editing them does
  nothing: videodriverindex (device forced to 0), huddamagemode and
  hudtargetdamagemode (both forced false). Their GetEntry calls are commented out.

- [special commands] killgame is a self-clearing kill switch: if true at startup
  the game rewrites it to false, saves options.ini and exits immediately.

- maxplayers/maxbots are serialised to clients as 5-bit fields, so 31 is the
  maximum usable value; cross-referenced to RAISING-PLAYER-CAP.md.

Also records why a typo produces no diagnostic: GetEntry returns false and the
compiled default is kept silently. Page and key lookup were confirmed to be
case-insensitive (NotationFile::FindPage lowercases; Page::FindNote uses
_stricmp), so the capitalisation differences between the shipped file and the
code are harmless -- the misspellings above are not.

Co-authored-by: Claude Opus 5 (Anthropic) <noreply@anthropic.com>
Co-authored-by: GitHub Copilot <copilot@github.com>
2026-07-25 08:54:28 -05:00
308fe041d4 Make -help a complete command line reference
MW4.exe accepts 76 command line switches. Only 27 of them appeared in the old
-help output, that output went to the debug log rather than to the user, and it
did not stop the game from launching afterwards -- so in practice the switches
were undocumented.

-help now writes a full, categorised reference to mw4-help.txt next to the
executable, opens it in Notepad, and returns from WinMain without starting the
game. If Notepad cannot be launched, a message box reports where the file was
written. The check runs immediately after the command line is lower-cased at the
top of WinMain, before any subsystem is initialised.

A file plus a viewer was chosen over a message box because MW4 is a GUI-subsystem
application with no console, and 76 switches with real descriptions do not fit
legibly in a dialog.

The reference documents every switch actually parsed, grouped as: display and
video, audio and plasma display, pod hardware and arcade (CTCL), zoom and field
of view, multiplayer and network, logging and diagnostics, development and test
builds, and other. Each entry records the accepted value range where the parser
enforces one -- for example -tbaud 9600-921600, -armorlevel 0-4, -tmfds 0-4,
-zmfovb 0.01-0.5, and the -zmtime special case where 0 means instant.

Two switches are listed under "recognised but inactive" so their behaviour is not
misrepresented: -join, whose consuming line is commented out, and -noabzug, which
is only parsed inside a disabled code path. The LAB-only switches are marked as
accepted and ignored in Release builds.

The old partial SPEWALWAYS list in GetGameOSEnvironment was removed so there is a
single maintained reference rather than two that can drift apart. A comment there
points at the new one.

Also adds an explicit #include <stdio.h>; this translation unit previously had no
direct stdio use and relied on transitive inclusion.

Co-authored-by: Claude Opus 5 (Anthropic) <noreply@anthropic.com>
Co-authored-by: GitHub Copilot <copilot@github.com>
2026-07-25 08:54:10 -05:00
0009f868eb RAISING-PLAYER-CAP.md: sharpen the drop-zone wording
The previous correction overstated the case by implying the code reading was
wrong outright. It was not. The engine really does place surplus 'Mechs on
already-occupied spawn points -- two 'Mechs dropped on the same spot -- exactly
as reading the code suggests.

The only wrong part was the predicted consequence. The original draft said those
players "silently fail to spawn". They do spawn; the collision system then pushes
the stacked 'Mechs apart within a second or two, costing some minor contact
damage, and play continues normally.

Reworded Layer 7 and the known-traps entry to separate the two claims: the
spawn-point reuse is real and code-predictable, the failure-to-spawn conclusion
was not.

Co-authored-by: Claude Opus 5 (Anthropic) <noreply@anthropic.com>
Co-authored-by: GitHub Copilot <copilot@github.com>
2026-07-24 23:50:12 -05:00
33c28cf816 RAISING-PLAYER-CAP.md: correct the drop-zone analysis
The original draft claimed that players beyond a map's available drop zones
"silently fail to spawn", and called per-map drop-zone authoring the true gating
task for raising the player cap. That was inferred from reading the code and is
wrong.

Corrected from real pod testing: when there are more 'Mechs than drop zones, the
surplus 'Mechs spawn on top of each other. They clip and collide briefly, take
some minor damage, then separate and play normally. It resolves itself within
seconds.

So a drop-zone shortfall is a quality-of-experience issue, not a functional
failure. It does not block raising the cap and should not gate the schedule.
Adding start points to busy maps is still worth doing eventually -- overlapping
spawns are untidy and hand out free chip damage -- but it can happen at any point
and never needs to be complete.

Updated accordingly: the TL;DR table, Layer 7, the implementation order (drop
zones moved from step 5 to last and marked optional), the verification checklist,
and the known-traps list.

The biggest remaining non-code task is now the lobby pod-grid and scoreboard
layout rework.

Co-authored-by: Claude Opus 5 (Anthropic) <noreply@anthropic.com>
Co-authored-by: GitHub Copilot <copilot@github.com>
2026-07-24 23:49:01 -05:00
a41dfb4aa8 Add RAISING-PLAYER-CAP.md reference
Captures the full audit of every player-count limit in the codebase, done while
tracking down the "16 pilots + 1 cameraship" launch failure. Research only --
nothing in it is implemented.

Key finding: the practical ceiling without a wire-format change is 31, not 32.
m_maxPlayers and m_maxBots are serialized as 5-bit fields in
NetMissionParameters, so 32 truncates to 0. This supersedes the "32" figure in
the existing CLAUDE.md plan sections.

Documents, with file references:
- what is NOT a limit (Adept::Maximum_Players is 255, connectionID is a BYTE,
  DirectPlay imposes nothing, and there is no 32-bit player bitmask)
- the 5-bit serialization ceiling and what widening it would cost
- the compiled defaults in CTCL_DefaultHostSetup that actually gate connections
- the CTCL roster arrays, including that g_aPlayerInfos[20] has NO bounds check
  in CTCL_AddPlayer and that ctcl.h is duplicated across ~6 directories
- MAX_LANCEMATES 16 for bots
- the lobby script constants and the pod-grid UI work
- scoreboard/radar/review layout work
- per-map drop zones, which is the real gating task and produces silent spawn
  failures when short
- the O(n^2) replication cost, reframed as verify-don't-assume on modern hardware

Also records the failure signatures to expect, so a future attempt recognises
them quickly: silent launch hang from a count mismatch, silent non-spawn from
missing drop zones, and 5-bit truncation looking like "max players became zero".

Co-authored-by: Claude Opus 5 (Anthropic) <noreply@anthropic.com>
Co-authored-by: GitHub Copilot <copilot@github.com>
2026-07-24 23:40:14 -05:00
9ba2d594b1 Add -tmon switch to hard-assign display devices
Display roles are auto-detected in FindVideoCards(): the main view takes the
first hardware-rasterizing device that is not a 1280x480-capable span, the radar
takes the next, and mode 4's two MFD panels take the two after that. That works
until DirectDraw enumerates the adapters in an unexpected order, at which point
the wrong content appears on the wrong monitor with no way to correct it.

Adds an override that keeps auto-detection as the default:

    -tmon <main>,<radar>,<mfd1>,<mfd2>

Values are 1-based, so the normal case is "-tmon 1,2,3,4". A value of 0 leaves
that slot auto-detected, so "-tmon 2,1,0,0" swaps only main and radar. Separators
may be ',' '/' or ':'. mfd1/mfd2 are only meaningful with -tmfds 4. Omitting the
switch entirely preserves existing behaviour exactly.

Implementation:

- Parsed in MW4Application's WinMain alongside -tmfds. That runs before GameOS
  calls FindVideoCards(), so the values are in place for device selection.
- Stored in g_naMonitorOverride[4] (VideoCard.cpp), extern'd in MW4Application.cpp.
- ApplyMonitorOverride() validates the index against NumDevices, so a stale -tmon
  on a machine with fewer monitors falls back to auto-detection rather than
  breaking startup.
- Ordering matters and is deliberate: main and radar are applied BEFORE the mode 4
  MFD search so that search still skips whichever devices the operator picked;
  mfd1/mfd2 are applied after it. Partial overrides therefore compose correctly.

Role map: main = Environment.FullScreenDevice, radar = g_nNonDualHead,
mfd1 = g_nMFD1, mfd2 = g_nMFD2. The mode 1 span (g_nDualHead) is intentionally
not overridable -- it is detected by 1280x480 mode support, which only the span
card advertises, so that detection is reliable.

Also adds a SPEW line logging the final role -> device map and device count.
Note this is only visible in Profile/LAB builds; SPEW compiles out in Release
(gos2X/Gos.h), so in Release the order is determined by observation.

Verified: compiles clean, console launches. Multi-monitor testing pending.

Co-authored-by: Claude Opus 5 (Anthropic) <noreply@anthropic.com>
Co-authored-by: GitHub Copilot <copilot@github.com>
2026-07-24 23:39:59 -05:00
0a657b5998 Fix constant rhythmic stutter in MFD mode 4 (split dual 640x480)
-tmfds 4 splits the 1280x480 MFD span into two independent 640x480 monitors so
the span hardware is no longer required. It rendered correctly but stuttered
rhythmically and constantly, making the game unplayable. -tmfds 1 on the same
binary was flawless.

Root cause: a cross-DirectDraw-object texture read, twice every 7-frame cycle.

CHSH_Device::InitFirst with no pOtherHSHD peer creates its OWN IDirectDraw7 (via
wDirectDrawCreateEx on that monitor's device GUID) and InitSecond creates its OWN
primary flip chain and IDirect3DDevice7. CMFDRight_Device::InitFirst passes no
peer, so the right MFD is an entirely separate DirectDraw object.

EndChannel then did, for channels 3-4:

    target->pD3DDevice->SetTexture(0, pDDSTarget);

where target->pD3DDevice belonged to the RIGHT device but pDDSTarget was the LEFT
device's render-target texture. The old code comment asserted "both devices are
on the same GPU so VRAM textures are mutually accessible" -- that premise is
wrong. In DirectDraw 7 a surface belongs to the IDirectDraw7 that created it, not
to the physical GPU, so it is not a valid texture on another object's D3D device.

The MFDs still displayed, which means the runtime was emulating the access with a
VRAM -> system-memory readback and re-upload of the 1024x512 16-bit render target.
That forces a full GPU pipeline stall, and it happened on channels 3 and 4 (that
is, sh_step 5 and 6) -- twice per 7-frame cycle, on the same GPU drawing the main
view. Hence a fixed-period hitch in the whole game, forever.

This also explains why the earlier stagger work (eaa5fd3, BeginSceneRight) did not
help: it only moved a Flip from sh_step 0 to 1, and the flips already used
DDFLIP_DONOTWAIT|DDFLIP_NOVSYNC and never blocked. The flips were never the
problem.

Fix: give the right device everything it draws with, and render channels 3-4
entirely on it.

- New HSH_CreateMFDTextures() builds the mech image atlas and the MFD sprite atlas
  on a caller-supplied IDirectDraw7. Both devices now call it, so each owns a
  complete independent texture set. CMFD_Device::InitSecond was refactored onto it.

- CMFDRight_Device gained its own pDDSMechTexture / pDDSDamageTexture /
  pDDSTargetTexture plus a Release() override, and its InitSecond now sets up
  tw/th and the material/render state exactly like the left device.

- New CMFD_Device::SwapRightState() exchanges this object's DATA members with the
  right device's. BeginChannel swaps in when channel >= 3 in mode 4; EndChannel
  swaps back. This routes all existing drawing to the correct monitor without
  touching the ~233 mfd_device.* call sites in hudchat/huddamage/hudweapon/
  GUIRadarManager. The vtable pointer is deliberately never swapped, so virtual
  dispatch is unaffected; CHSHFont has no virtual functions so its array is
  swapped bytewise to avoid ctor/dtor side effects on a temporary.

- EndChannel's composite is now a single path for all modes. Mode 4 composites
  full 640 width at x=0 (each device is a standalone panel); modes 1-3 keep the
  half-width (ch/3)*w packing into one backbuffer.

Side effects: startup builds the 65-bitmap mech atlas twice (once per device), and
VRAM use rises by a few MB. Modes 0-3 are behaviourally unchanged.

Known cosmetic leftover, deliberately not changed: huddamage.cpp lines ~1319 and
~1901 call LoadTargetTexture outside the channel-3 block, so those loads land on
the left device and go unused. The in-channel call at ~2209 runs every frame in
that branch and correctly populates the right device's copy, so behaviour is
correct -- it is just a redundant load on target change.

Requires rebuild: MW4.exe (GameOS changes recompile the engine library).
Verified: compiles clean, console launches. Two-monitor testing pending.

Co-authored-by: Claude Opus 5 (Anthropic) <noreply@anthropic.com>
Co-authored-by: GitHub Copilot <copilot@github.com>
2026-07-24 23:39:42 -05:00
29aee4f71b Fix 16 pilots + 1 cameraship failing to launch
A full 16-'Mech roster plus a cameraship silently refused to launch: the console
sat in nLaunchState 3 ("loading") forever with no crash and no error. 15 mechs +
camera worked, and 16 mechs with no camera worked.

Two independent bugs, both counting the cameraship against the 16 'Mech slots.

1. Session capacity (broke all-human rosters)

   CTCL_DefaultHostSetup derived the camera reserve from
   CTCL_GetTeslaCountAll() - CTCL_GetTeslaCount(). Those counters read the CTCL
   tesla table, which is only populated when CTCL_IsConsoleOrCOOP() is true --
   i.e. only on the console. But the machine that creates the network session is
   the cameraship pod (CTCL_DoMission sets g_nServer = nCameraship, and that pod
   runs CTCL_DoCreateGame -> CTCL_DefaultHostSetup(0) -> Mech4CreateGame ->
   gos_CreateGame(..., Environment.NetworkMaxPlayers, ...)).

   On that pod both counters return 0, so the reserve collapsed to +0 and the
   session was created with dwMaxPlayers = 16. The 17th connection was refused,
   CTCL_CheckServerReady never saw nCount == g_nTeslas + 1, and the launch hung.

   Fixed by reserving with a constant, MW4_CAMERASHIP_RESERVE (4, matching
   MAX_CAMERAS), which is valid on every machine regardless of the tesla table.

2. Bot admission (broke any roster containing bots)

   MW4Shell::AddBot rejects when (player_count + bot_count) >= m_maxPlayers.
   player_count is the DirectPlay player count, which includes the cameraship
   connection, so with m_maxPlayers = 16 the last bot was silently refused.
   g_nBOTs then never matched the connected lancemates and the same readiness
   check spun forever.

   Fixed by subtracting cameraship participants from player_count under CTCL,
   via a new CTCL_CountCameraShipsInGame() helper (non-bot entries with
   m_nMechIndex == 0). Cameraships hold a network slot but pilot no 'Mech, so
   they must not consume a 'Mech slot.

Also applies the constant reserve in the PLAYER_LIMIT_PARAMETER path, guarded by
!CTCL_IsNone() so a standalone non-pod host keeps its exact configured limit.

This supersedes commit f76dc05f, which had the right formula but evaluated it on
the console rather than on the pod that actually creates the session.

Note for later: m_maxPlayers is serialized in only 5 bits (MWApplication.cpp),
so 31 is the hard ceiling for any future player-cap work. See
RAISING-PLAYER-CAP.md.

Requires rebuild: MW4.exe (Release + Profile). No script or resource changes.
Verified: compiles clean, console launches. Pod testing pending.

Co-authored-by: Claude Opus 5 (Anthropic) <noreply@anthropic.com>
Co-authored-by: GitHub Copilot <copilot@github.com>
2026-07-24 23:39:16 -05:00
dicion 515adc2413 mw4print: persist banner text via banner.txt
- Add banner.txt load/save helpers in banner settings dialog

- Load banner from banner.txt first, with options.ini BannerText fallback

- Fix options.ini path join to include missing path separator
2026-07-24 21:56:24 -05:00
dicion ff650f7bec Load File: finalize first-click deterministic apply, add NoReturn, and align docs
- Stabilize Load File first-click behavior across mission/map/options/slots.

- Fix map sequencing by rebuilding game-type scenario list before mission lookup.

- Resolve mission-name miss to map index 0 fallback for selected game type.

- Fix decal handling: map INI decal IDs to dropdown indices, clamp invalid indices, display actual decal IDs in UI labels, and avoid redraw-time decal overwrite.

- Fix option apply timing and UI visibility issues, including Weapon Jam refresh.

- Add NoReturn support end-to-end: parse/store in MW4Shell auto globals, expose script variable, and apply to respawn/no-return mission params and UI checkbox.

- Update autoconfig spec to reflect actual parser/default/fallback behavior and add NoReturn examples.
2026-07-24 21:42:54 -05:00
dicion e5561181bb Fix MAIL_LOAD_AUTO_MISSION crash: defer initialize(this) to sender==this self-mail
'gui_objects have no parent' crash at line 907: initialize(this) cannot be
called from sender==@conlobby@ context (external mail). Fix:

1. Replace initialize(this)+mail(-9998,parent) in MAIL_LOAD_AUTO_MISSION
   with mail(MAIL_LOAD_AUTO_MISSION_DONE=-8888, this) -- a self-mail.

2. Add MAIL_LOAD_AUTO_MISSION_DONE handler in sender==this block, which
   safely calls initialize(this)+mail(-9998,parent) from the correct context.

Also repaired a corrupt duplicate MAIL_PREVIOUS_MISSION_PARAMS block
that was left orphaned by an earlier edit (the original body of
MAIL_LOAD_AUTO_MISSION had been inserted there when the handler was
moved from sender==this to sender==@conlobby@).

No rebuild required (script-only).
2026-07-24 11:09:50 -05:00
dicion 06de4534da BTFrstrm: add Load File test ini files (FFA Coliseum + 4-team KotH CentralPark) 2026-07-24 11:01:11 -05:00
dicion 23284b18b0 Fix MAIL_LOAD_AUTO_MISSION: move handler to sender==@conlobby@ block
Handler was inside 'if (sender == this)' but MAIL_LOAD_AUTO_MISSION is sent
from ConLobby (sender != this), so it never fired. All game params (FriendlyFire,
SplashDamage, UnlimitedAmmo, WeaponJam, AdvanceMode, ArmorMode, etc.) were
silently ignored on every Load File click.

Fix: move the ~70-line handler to the 'if (sender == @conlobby@)' block,
alongside MAIL_SET_ROOKIE_MISSION and MAIL_PREVIOUS_MISSION — where all
ConLobby-originated mails are handled. No rebuild required (script only).
2026-07-24 10:56:57 -05:00
dicion 62dc0952b1 BTFrstrm: add Load File test configs (FFA Coliseum, Team KoH CentralPark) 2026-07-24 10:46:24 -05:00
dicion 9a9f2d0df2 autoconfig-file-spec.html: add TeamAllowed/TeamCount to example; fix caveat #3 2026-07-24 10:37:37 -05:00
dicion cd2fe73c88 Fix Load File: separate Auto globals; fix team/FFA double-press
Issue 1 — double press to fix team/FFA display:
  cur_team_val is updated by ConLobbyMission's -9998 signal which was async.
  Fix: call SetNetworkMissionParamater(team_allowed, ...) directly in ConLobby
  before the slot loop, then re-read cur_team_val via CTCL_GetTeamParams.
  This is synchronous so the slot display is correct on the first click.
  New file keys: TeamAllowed=0/1, TeamCount=2 (default 2 teams).

Issue 2 — Default button broken after Load File click:
  CTCL_LoadAutoFile was overwriting g_nRookieGameType/g_szRookieMission etc.
  so the Default button loaded the last auto-file params instead of defaults.
  Fix: 14 new dedicated g_nAutoXxx/g_szAutoMission globals. CTCL_LoadAutoFile
  populates ONLY these. Rookie Mission globals are never touched.
  New MAIL_LOAD_AUTO_MISSION (-6666) sent to ConLobbyMission applies the Auto
  globals (mirrors MAIL_SET_ROOKIE_MISSION_PARAMS but uses g_nAutoXxx).
  ConLobby reads game type/mission from Auto globals directly into the
  ConLobbyMission dropdowns (@ConLobbyMission@o_game_options[N].nselected).

Files changed:
  MW4Shell.cpp: 16 new globals, StartUp/ShutDown registration, CTCL_LoadAutoFile
  ConLobby.script: MAIL_LOAD_AUTO_MISSION define, updated handler
  ConLobbyMission.script: MAIL_LOAD_AUTO_MISSION define + handler
  autoconfig-file-spec.html: document TeamAllowed + TeamCount fields
Rebuild required: MW4.exe (Release + Profile).
2026-07-24 10:35:11 -05:00
dicion 3f2d79a038 BTFrstrm: add weapon location spreadsheets (Special1/2 and rear-facing) 2026-07-24 10:18:06 -05:00
dicion c3d82d78c9 Load File: hide button when automaticmode!=1; fix team/skin double-click
1. Expose g_bAutomaticMode as gosScript variable so ConLobby can check
   it at init time. o_load_file.state is set to 3 (disabled/hidden) if
   automaticmode != 1 in options.ini. Button is fully visible and active
   only when the feature is intentionally enabled.
   Rebuild required: MW4.exe (Release + Profile).

2. Remove cur_team_val conditional for team/skin slot assignment.
   Previously, only one of o_team[k] or o_skins[k] was set depending on
   cur_team_val at click time, but MAIL_SET_ROOKIE_MISSION propagates the
   new game type asynchronously -- cur_team_val would not reflect the
   file's GameType until the next frame, requiring a second click.
   Fix: always set both o_team[k] and o_skins[k] unconditionally. The
   mission launch code uses whichever is relevant for the active mode;
   the other is harmlessly ignored. No rebuild (script-only).
2026-07-24 10:08:21 -05:00
dicion 17ca966473 Fix Load File mech lookup: use stock_array to get chassis name
mech[j] in the flat sorted array hits variant entries (e.g. 'Assassin2 A'
sorts before 'AssassinII' alphabetically, pushing all subsequent chassis
indices off by 1 or more). The script's stock_array[] maps each chassis
index -> its actual position in the flat mech[] array, bypassing variant
entries.

Fix: mech[allowed_mechs[j]] -> mech[stock_array[allowed_mechs[j]]]

Only stock (chassis) names are supported in Mech= field. Operators can
adjust variants manually after Load File is clicked. No rebuild required
(script-only change).
2026-07-24 10:02:13 -05:00
dicion 7852269dc7 Fix Load File crash: VALUEPARM for literal field arg in CTCL_GetAutoSlotInt
Script calls callback(CTCL_GetAutoSlotInt, k, 0/1/2/3) where 0-3 are
integer literals. The script engine passes literals as (void*)N directly
(not as pointers), so INTPARM(1) = *((int*)data[1]) dereferences NULL
when field=0, producing the 'Attempt to read from NULL' STOP.

Fix: VALUEPARM(1) = (int)data[1] reads the value without dereferencing.
k (data[0]) remains INTPARM because it is a script variable (passed as
a pointer to the variable's storage, not a literal).

Also add exists(@ConLobbyMission@) guard before MAIL_SET_ROOKIE_MISSION
for defensive safety if the sub-script is not running.

Rebuild required: MW4.exe (Release + Profile).
2026-07-24 09:31:51 -05:00
dicion 76121f1c68 BTFrstrm: add autoconfig-file-spec.html (Load File format reference) 2026-07-24 09:13:37 -05:00
dicion c33465611f Add [automaticmode] Load File button to console lobby
options.ini [automaticmode] section:
  automaticmode=1
  automaticfile=c:\path\to\config.ini

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

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

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

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

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

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

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

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

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

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

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

Co-authored-by: Claude Sonnet 4.6 (Anthropic) <noreply@anthropic.com>
Co-authored-by: GitHub Copilot <copilot@github.com>
2026-07-19 15:40:24 -05:00
106bb5b59f Document mech_loadouts audit data
Update mech_loadouts.csv with derived playability, hardpoint, facing, and loadout annotations, and add mech_loadouts.md as the catch-up reference for future updates.

Co-authored-by: Claude Sonnet 4.6 (Anthropic) <noreply@anthropic.com>
Co-authored-by: GitHub Copilot <copilot@github.com>
2026-07-19 14:36:37 -05:00
e45a67a8fe mfdsplit: mech loadouts, time list, build fixes, Korean→English, mw4print v2.0
Battlemaster stock loadouts (Content\Mechs\Battlemaster\battlemaster.subsystems):
- Replace lone MediumPulseLaser with full IS stock: PPC (Special2, group 1),
  6×ML (3 RT + 3 LT, group 1), 2×MG (LA, 200 rds, group 1), SRM6 (Special1,
  15 rds, group 2).

Battlemaster Clan 2C (battlemaster2c.subsystems):
- Replace ClanMediumPulseLaser with: ER PPC (RA, group 1), 6×ER ML (3 RT + 3
  LT, group 1), 2×Clan Gauss (LA, 16 rds each, group 1), Clan SSRM6 (Special1,
  15 rds, group 2).

Behemoth / Behemoth2 (.subsystems):
- Move Gauss rifles from weapon group 3 → group 1 (3 occurrences each).

Resource builder (build-resources.ps1):
- Always run with -window (windowed + DDrawCompat). Fullscreen native DDraw
  fails on VMs with the generic Microsoft display adapter.
- Remove dgVoodoo2 D3D interceptors (D3D8/D3D9/D3DImm.dll) from Gameleap\mw4:
  they silently break the builder (process exits 0 without packing anything).
  Script also defensively moves any such files aside via $dgvMoved block.
- Remove dgVoodoo.conf and dgVoodooCpl.exe (abandoned experiment, no longer used).
- Expected: 'Hardware Error: not compatible with MechWarrior 4' dialog at end
  of build on VMs -- click OK, packages are built correctly regardless.

CLAUDE.md: updated with mfdsplit branch notes covering all 2026-07-18 work.

Co-authored-by: Claude Sonnet 4.6 (Anthropic) <noreply@anthropic.com>
Co-authored-by: GitHub Copilot <copilot@github.com>
2026-07-18 16:22:03 -05:00
456e197822 Fix ConLobbyMission time list (18 entries) and build-resources ddraw handling
ConLobbyMission.script:
- Expand MP time-limit dropdown from 9 to 18 entries (1-15, 20, 25, 30 min)
  with max_displayed=10 so the list scrolls cleanly.
- Fix bare else-if syntax (missing braces) that caused null-reference crash
  on console lobby load when this was merged from main.
- Fix i==5 vs i==6 max_displayed assignment for time vs radar dropdowns.

build-resources.ps1:
- DDrawCompat's ddraw.dll is fatal to MW4pro.exe in FULLSCREEN but works
  in WINDOWED mode. Don't move it aside; instead run the builder with
  -window when ddraw.dll is present. This fixes builds on VMs with generic
  display adapters (no hardware DirectDraw) and avoids the EnterWindowMode
  CreateSurface crash on Win10/11 without a functioning DWM shim.
- Also temporarily set options.ini bitdepth=32 when running without any
  ddraw interceptor (bare-metal fallback), restored in finally block.
- Remove stale comment about ddraw being fatal; update interceptor detection
  to correctly identify DDrawCompat vs dgVoodoo2 via dgVoodoo.conf presence.

Co-authored-by: Claude Sonnet 4.6 (Anthropic) <noreply@anthropic.com>
Co-authored-by: GitHub Copilot <copilot@github.com>
2026-07-18 15:39:42 -05:00
a45be8044c mw4print: bump to version 2.0, update copyright year to 2026
Co-authored-by: Claude Sonnet 4.6 (Anthropic) <noreply@anthropic.com>
Co-authored-by: GitHub Copilot <copilot@github.com>
2026-07-18 14:42:11 -05:00
9f3a50443a mw4print: bump version to 2.0, update copyright year to 2026
Co-authored-by: Claude Sonnet 4.6 (Anthropic) <noreply@anthropic.com>
Co-authored-by: GitHub Copilot <copilot@github.com>
2026-07-18 14:39:15 -05:00
dicion 47000d6cf2 text version of db structure for reference 2026-07-18 14:10:51 -05:00
dicion 195db56b1e mw4print: add db_schema.sql documenting MySQL export structure 2026-07-18 14:10:04 -05:00
dicion b98cb87ef3 mw4print: MySQL export, configurable banner text
MySQL database export (dbexport.h / dbexport.cpp):
- New files dbexport.h / dbexport.cpp implement late-bound MySQL export.
  libmysql.dll is loaded at runtime via LoadLibrary/GetProcAddress so no
  MySQL SDK is required at compile time; the app runs normally if the DLL
  is absent.
- After each print job, match data is exported to a MySQL server before
  PrintDlg() is called: one row in 'match', one row per player in
  'player_result', one row per attacker/victim pair in 'pvp'.  An optional
  'event' table records every individual SRecScore entry (off by default).
  Tables are created automatically (CREATE TABLE IF NOT EXISTS) on first
  connect.
- Config stored in mw4print.ini (app directory), section [MySQLExport]:
  Enabled, Host, Port, Database, Username, Password, ExportEvents.
- Config loaded at startup (OnCreate); DB_LoadConfig() / DB_SaveConfig().
- Connection timeout set to 5 seconds so the app does not hang if the
  server is unreachable.
- libmysql.dll (MySQL Connector/C 32-bit) added to Gameleap/mw4/ so the
  deploy script copies it to MW4/ alongside mw4print.exe.

Database Settings dialog (File > Database Settings... / Ctrl+D):
- MFC dialog: enable checkbox, Host/Port/Database/Username/Password fields,
  Export Events checkbox, Test Connection button with live status label,
  OK/Cancel.  OK persists settings to mw4print.ini immediately.

Configurable banner text (File > Banner Setting...):
- The 'WWW.MECHJOCK.COM' URL string printed at the bottom of every score
  sheet is now configurable.  Stored as BannerText= in options.ini under
  [battle tech print] (same section/file as the other print layout params).
  File > Banner Setting... opens a dialog to edit it; OK saves to options.ini
  and takes effect on the next print job with no restart needed.
  Default value is the original MECHJOCK string if the key is absent.
2026-07-18 14:05:31 -05:00
dicion 92aaedfcbb Add Korean translation diff HTML for documentation
korean_diff.html: side-by-side GitHub-style diff of all 171 source files
changed in the Korean->English translation commit (af416960). Shows the
original EUC-KR/CP949 Korean text on the left and the English replacement
on the right, including the UTF-8 encoding cleanup changes.

Generated from: git diff HEAD~1..HEAD (af416960) for documentation/
review purposes. Not a build input.
2026-07-18 13:17:33 -05:00
dicion af416960fa Translate Korean comments/strings to English; fix UTF-8 encoding across source tree
Korean translation (84 source files, 876 lines):
- Translated all EUC-KR/CP949 Korean developer comments to English across
  84 source files in Gameleap/code/. Zero Korean bytes remain outside the
  intentional font-table headers (D3FFontEdit2/fontedit all.h etc.).
- Comment markers: //상훈 앞/뒤 -> //sanghoon begin/end (Sang-hun's code
  region markers); //상훈짱 begin/end, //상훈.. variants; // 鉉 -> // hyun
  (second developer's markers); // 鉉 - start/end patterns.
- Functional string translations in recscore.cpp (mw4 + mw4print copies):
  body-part return values (왼발/오른발/etc. -> Left Leg/Right Leg/etc.),
  kill-announcer format strings (~30 entries), and the nonmfc.h assert dialog.
- GosView profiler: 킪 -> us (microseconds) in timing display strings.
- Network/socket code (ctcl.cpp, mugsocs.h, ctime.cpp across Launcher/
  MW4Application/MW4GameEd2/AnimScript): state-machine comments, socket
  ID comments, login/session management comments.
- render.hpp CHSH_Device member comments; GUIRadarManager.cpp drawing
  routine comments; hudchat/hudcomp2/huddamage/hudmap/hudweapon/hudtarg
  HUD component comments.
- DXRasterizer.cpp: cleaned residual U+FFFD replacement characters left
  from a prior partial encoding conversion.

UTF-8 encoding cleanup (76+ files):
- Latin-1 single bytes converted to proper UTF-8 multi-byte sequences:
  © (0xA9) in 3dsmax4/Maxscrpt Autodesk/Wainwright copyright headers,
  ® (0xAE) in gosHelp/Remote.cpp, · (0xB7) bullet points in ai command.hpp,
  Û (0xDB) in SafeChain_Test.cpp tool header,
  ß (0xDF) in AnimationSuite version strings (8 files).
- Font lookup tables (D3FFontEdit2/, fontedit/ *.h) intentionally left
  as-is: raw byte values are C array data, not text.

Language DLL:
- Replaced Gameleap/mw4/Language.dll (original Korean binary) and
  MW4/Language.dll with freshly built English version from
  Language - Win32 English config (Language.dsp). Fixes Korean button
  labels in the GameOS exception/crash dialog (??? ??... / ?? / ???
  were showing instead of More Details.../Continue/Exit).
2026-07-18 13:10:31 -05:00
dicion eaa5fd3bbe fix mode 4: stagger right MFD BeginScene to step 1 to match flip timing
Root cause of the broken MFD2 display: CMFD_Device::BeginScene() cleared
the right device back buffer at old sh_step==0, but with the stagger the
right device flip also fired in that same frame (new sh_step==1 = old
sh_step==0 after increment). The flip presented a just-cleared buffer
with only the grid, no channel data.

Fix: split BeginScene for mode 4 - left device (step 0) vs right device
(step 1). Add BeginSceneRight() called from WinMain at old sh_step==1.
The right device flip at new sh_step==1 (= old sh_step==0) now shows
channels 3-4 rendered at steps 5-6 of the previous cycle - correct.

Cycle for mode 4 with stagger:
  old sh_step 0: radar+left BeginScene, no flip
  new sh_step 1: flip right MFD (shows prev cycle channels 3-4)
  old sh_step 1: right BeginScene (clear+grid)
  old sh_step 2-4: channels 0-2 -> left device
  old sh_step 5-6: channels 3-4 -> right device
  new sh_step 0: flip radar+left MFD (shows prev cycle channels 0-2)
2026-07-17 21:43:22 -05:00
dicion ab24aace11 stagger mfd device flips to try and prevent studder. 2026-07-17 21:43:21 -05:00
dicion ef82366132 remove dgvoodoo2 dlls from the deploy script. 2026-07-17 21:43:21 -05:00
dicion 6f630c777e fix errors 2026-07-17 21:43:20 -05:00
dicion 87e25677b5 dgvoodoo support files for building MW4 with dgvoodoo2 instead of DDrawCompat. This is a workaround for the fact that DDrawCompat is not compatible with Windows 11, and dgvoodoo2 is a more modern alternative. 2026-07-17 21:43:20 -05:00
dicion 7e6b457745 added ability to use dgvoodoo ddraw for VM resource builds. 2026-07-17 21:43:19 -05:00
dicion e5c4993436 Added tmdfs mode 4 for 2x 640x480 monitors 2026-07-17 21:43:18 -05:00
1227 changed files with 15943 additions and 1934 deletions
+13
View File
@@ -0,0 +1,13 @@
{
// Legacy source files use CP949 (Korean Windows encoding, superset of EUC-KR).
// VS Code defaults to UTF-8, which silently corrupts the Korean comment bytes
// on save. Setting encoding to cp949 here preserves them exactly.
"files.encoding": "cp949",
// Let VS Code try to detect encoding per-file, falling back to cp949 above.
"files.autoGuessEncoding": true,
// Preserve the original Windows CRLF line endings (Git's * -text in
// .gitattributes also prevents conversion, but this keeps VS Code consistent).
"files.eol": "\r\n"
}
Binary file not shown.
Binary file not shown.
+585
View File
@@ -0,0 +1,585 @@
<!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 &ldquo;Load File&rdquo; button &nbsp;|&nbsp;
Commit: <code>c3346561</code> (branch <code>5.1.0b-in-progress</code>) &nbsp;|&nbsp;
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> &mdash; 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>) &mdash;
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> &mdash; 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&rsquo;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 &mdash; both accepted.</li>
<li><strong>Section headers:</strong> <code>[sectionname]</code> &mdash; <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, parser defaults are used. For <code>[mission]</code> this means built-in auto defaults (not current UI values). For <code>[slotX]</code> fields, omitted numeric values default to <code>0</code> and omitted strings default to empty.</li>
<li><strong>Missing section:</strong> If <code>[mission]</code> is absent, Load File still applies mission defaults. If <code>[slot0]</code> is absent, all slots are cleared and remain empty.</li>
</ul>
<hr>
<h2>4. Section: <code>[mission]</code></h2>
<p>Sets all game lobby parameters. This section is <span class="optional">optional</span>, but if omitted, Load File applies built-in mission defaults (it does not preserve current UI values).</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">NoReturn</span>=<span class="value">0</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 &nbsp;<code>MissionName</code> &mdash; 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>,
map selection falls back to index <code>0</code> (first available map for that game type).
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 &nbsp;<code>GameType</code> &mdash; 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 &mdash; 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 &mdash; <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 &nbsp;<code>Visibility</code> &mdash; 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 &nbsp;<code>Weather</code> &mdash; 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 &nbsp;<code>TimeOfDay</code> &mdash; 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 &nbsp;<code>TimeLimit</code> &mdash; 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&rsquo;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 &nbsp;<code>Radar</code> &mdash; 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 &nbsp;<code>HeatOn</code> &mdash; integer</h3>
<table>
<tr><th>Value</th><th>Description</th></tr>
<tr><td><code>0</code></td><td>Off &mdash; heat never builds, weapons never overheat <span class="default-tag">DEFAULT</span></td></tr>
<tr><td><code>1</code></td><td>On &mdash; standard heat management enabled</td></tr>
</table>
<h3>4.9 &nbsp;<code>FriendlyFire</code> &mdash; integer</h3>
<table>
<tr><th>Value</th><th>Description</th></tr>
<tr><td><code>0</code></td><td>Off &mdash; friendly fire disabled <span class="default-tag">DEFAULT</span></td></tr>
<tr><td><code>1</code></td><td>On &mdash; 100% damage to teammates</td></tr>
</table>
<h3>4.10 &nbsp;<code>SplashDamage</code> &mdash; 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 &mdash; area/splash damage from missiles and explosions</td></tr>
</table>
<h3>4.11 &nbsp;<code>UnlimitedAmmo</code> &mdash; integer</h3>
<table>
<tr><th>Value</th><th>Description</th></tr>
<tr><td><code>0</code></td><td>Off &mdash; ammo is finite</td></tr>
<tr><td><code>1</code></td><td>On &mdash; unlimited ammo <span class="default-tag">DEFAULT (console/arcade)</span></td></tr>
</table>
<h3>4.12 &nbsp;<code>NoReturn</code> &mdash; integer</h3>
<table>
<tr><th>Value</th><th>Description</th></tr>
<tr><td><code>0</code></td><td>Off &mdash; pilots can respawn <span class="default-tag">DEFAULT</span></td></tr>
<tr><td><code>1</code></td><td>On &mdash; no respawn ("No Return")</td></tr>
</table>
<p><strong>Implementation note:</strong> this maps to <code>RESPAWN_LIMIT_PARAMETER</code> (on/off), with <code>RESPAWN_LIMIT_NUMBER_PARAMETER</code> forced to <code>0</code>, matching current lobby behavior.</p>
<h3>4.13 &nbsp;<code>WeaponJam</code> &mdash; 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 &mdash; weapons can randomly jam</td></tr>
</table>
<h3>4.14 &nbsp;<code>AdvanceMode</code> &mdash; 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 &nbsp;<code>ArmorMode</code> &mdash; 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.16 &nbsp;<code>TeamAllowed</code> &mdash; 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.17 &nbsp;<code>TeamCount</code> &mdash; integer <span class="optional">(optional, only when TeamAllowed=1)</span></h3>
<p>Number of teams. Valid range: 2&ndash;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&ndash;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 &nbsp;<code>Type</code> &mdash; 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 &mdash; slot skipped, left empty in lobby</td></tr>
<tr><td><code>1</code></td><td>Player slot &mdash; 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 &nbsp;<code>PilotName</code> &mdash; 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&ndash;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 &nbsp;<code>Mech</code> &mdash; 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 &nbsp;<code>Team</code> &mdash; integer</h3>
<p>
<strong>Only applied in team game modes</strong> (game types marked &ldquo;Team&rdquo; 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 &nbsp;<code>Skin</code> &mdash; 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>&ndash;<code>15</code></td><td>Additional camo patterns</td></tr>
</table>
<h3>5.6 &nbsp;<code>Decal</code> &mdash; integer (faction emblem, 0&ndash;63)</h3>
<p>
Applied in <strong>both team and FFA modes.</strong>
Valid range: <code>0</code>&ndash;<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> &le; 63 chars (truncated silently);
<code>MissionName</code> &le; 255 chars;
<code>automaticfile</code> path &le; 259 chars (<code>MAX_PATH&nbsp;&minus;&nbsp;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> &mdash; <code>CTCL_LoadAutoFile</code>,
<code>CTCL_GetAutoSlotName/Mech/Int</code> &nbsp;|&nbsp;
<code>ConLobby.script</code> &mdash; <code>o_load_file</code> handler &nbsp;|&nbsp;
<code>ConLobbyMission.script</code> &mdash; <code>MAIL_LOAD_AUTO_MISSION</code> &nbsp;|&nbsp;
Commit cd2fe73c &nbsp;|&nbsp; 2026-07-24
</p>
</body>
</html>
+111
View File
@@ -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}")
+88
View File
@@ -0,0 +1,88 @@
Mech,In_game_playable,Tech,Chassis_Tonnage,Max_Loadout_Tonnage,Armor_Type,Internal_Type,Heatsinks,Heatsink_Type,JumpJets_Installed,CanLoad_JJ,CanLoad_ECM,CanLoad_BAP,CanLoad_AMS,OmniSlots,Equipment,Armor_LeftArm,Armor_RightArm,Armor_LeftLeg,Armor_RightLeg,Armor_LeftFrontTorso,Armor_RightFrontTorso,Armor_CenterFrontTorso,Armor_CenterRearTorso,Armor_Head,Total_Armor_Multiplier,Weapon_Count,Weapons_Summary,Weapons_With_Locations,Default_Installed_Locations,Available_Slot_Capacity_By_Zone,Available_Hardpoints,notes
Annihilator,Yes,IS,23.000000,100.000000,Reflective,EndoSteel,17,Single,0,No,Yes,Yes,Yes,43,,1.8,1.8,1.8,1.8,1.85,1.85,2.0,0.8,0.3,14,10,"4x ClanERSmallLaser, 2x ClanMachineGun, 4x ClanUltraAC5",ClanERSmallLaser@LeftTorso(Front) G1 | ClanERSmallLaser@CenterTorso(Front) G1 | ClanERSmallLaser@CenterTorso(Front) G1 | ClanERSmallLaser@RightTorso(Front) G1 | ClanMachineGun@LeftTorso(Front) G1 | ClanMachineGun@RightTorso(Front) G1 | ClanUltraAC5@LeftArm(Front) G1 | ClanUltraAC5@LeftArm(Front) G1 | ClanUltraAC5@RightArm(Front) G1 | ClanUltraAC5@RightArm(Front) G1,LeftTorsox2 | CenterTorsox2 | RightTorsox2 | LeftArmx2 | RightArmx2,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1),LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Front) | Head(Unknown),
Archer,Yes,IS,17.000000,70.000000,Standard,Standard,20,Single,1,Yes,Yes,Yes,Yes,43,,1.1,1.1,1.2,1.2,1.4,1.4,1.5,0.5,0.3,9.7,9,"4x MediumPulseLaser, 2x SSRM2, 2x LRM15, NarcBeacon",MediumPulseLaser@LeftArm(Front) G1 | MediumPulseLaser@CenterTorso(Front) G1 | MediumPulseLaser@CenterTorso(Front) G1 | MediumPulseLaser@RightArm(Front) G1 | SSRM2@LeftArm(Front) G2 | SSRM2@RightArm(Front) G2 | LRM15@LeftTorso(Side) G2 | LRM15@RightTorso(Side) G2 | NarcBeacon@LeftTorso(Front) G3,LeftArmx2 | CenterTorsox2 | RightArmx2 | LeftTorsox2 | RightTorsox1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1),LeftArm(Front) | RightArm(Front) | LeftTorso(Front+Side) | RightTorso(Side) | CenterTorso(Front) | Head(Unknown),
ArcticWolf,Yes,Clan,9.500000,40.000000,FerroFiberus,EndoSteel,8,Single,1,Yes,Yes,Yes,Yes,43,,0.7,0.7,0.95,0.95,0.85,0.85,1.0,0.2,0.3,6.5,6,"2x ClanSmallPulseLaser, 4x ClanSSRM4",ClanSmallPulseLaser@RightTorso(Front) G1 | ClanSmallPulseLaser@RightTorso(Front) G1 | ClanSSRM4@leftarm(Front) G2 | ClanSSRM4@special1(Front) G2 | ClanSSRM4@special2(Front) G2 | ClanSSRM4@rightarm(Front) G2,RightTorsox2 | leftarmx1 | special1x1 | special2x1 | rightarmx1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O8) | RightTorso(M0/P0/B0/O8) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O4) | Special2(M0/P0/B0/O4),LeftArm(Unknown) | RightArm(Unknown) | LeftTorso(Unknown) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown) | Special1(Unknown) | Special2(Unknown),
Ares,Yes,Clan,15.500000,60.000000,FerroFiberus,Standard,15,Single,0,Yes,Yes,Yes,Yes,46,,0.9,0.9,1.15,1.15,1.1,1.1,1.45,0.9,0.25,8.9,9,"2x ClanERSmallLaser, 3x ClanERMediumLaser, ClanERLargeLaser, 3x ClanLRM10",ClanERSmallLaser@Special1(Front) G1 | ClanERSmallLaser@Special1(Front) G1 | ClanERMediumLaser@LeftArm(Front) G1 | ClanERMediumLaser@RightArm(Front) G1 | ClanERMediumLaser@RightArm(Front) G1 | ClanERLargeLaser@LeftArm(Front) G1 | ClanLRM10@Special2(Side) G2 | ClanLRM10@Special2(Side) G2 | ClanLRM10@Special2(Side) G2,Special1x2 | LeftArmx2 | RightArmx2 | Special2x3,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O2) | Special2(M0/P0/B0/O3),LeftArm(Front) | RightArm(Front) | LeftTorso(Unknown) | RightTorso(Unknown) | Head(Unknown) | Special1(Front) | Special2(Side),
Argus,Yes,IS,14.500000,60.000000,Standard,Standard,13,Single,0,No,Yes,Yes,Yes,43,,0.7,0.7,1.15,1.15,0.85,0.85,1.45,0.9,0.3,8.05,9,"3x MediumLaser, PPC, 4x MachineGun, LRM10",MediumLaser@Lefttorso(Front) G1 | MediumLaser@Righttorso(Front) G1 | MediumLaser@RightArm(Front) G1 | PPC@RightArm(Front) G1 | MachineGun@LeftTorso(Front) G1 | MachineGun@CenterTorso(Front) G1 | MachineGun@CenterTorso(Front) G1 | MachineGun@RightTorso(Front) G1 | LRM10@LeftArm(Front) G2,Lefttorsox1 | Righttorsox1 | RightArmx2 | LeftTorsox1 | CenterTorsox2 | RightTorsox1 | LeftArmx1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1),LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Front) | Head(Unknown),
Assassin2,Yes,IS,12.000000,45.000000,FerroFiberus,EndoSteel,6,Single,0,Yes,Yes,Yes,Yes,40,,0.85,0.85,0.85,0.85,0.9,0.9,1.05,0.45,0.25,6.95,7,"2x SmallLaser, 2x MediumLaser, 2x SRM4, LRM5",SmallLaser@LeftArm(Front) G1 | SmallLaser@RightArm(Front) G1 | MediumLaser@LeftArm(Front) G1 | MediumLaser@RightArm(Front) G1 | SRM4@LeftTorso(Front) G2 | SRM4@RightTorso(Front) G2 | LRM5@Special1(Side) G2,LeftArmx2 | RightArmx2 | LeftTorsox1 | RightTorsox1 | Special1x1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O10) | Special1(M0/P0/B0/O2),LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | Special1(Side),
Atlas,Yes,IS,28.000000,100.000000,Standard,Standard,17,Single,0,No,Yes,Yes,Yes,43,,1.95,1.95,2.15,2.15,2.45,2.45,2.2,1.1,0.3,16.7,9,"4x MediumLaser, AC20, 2x SSRM2, SRM6, LRM20",MediumLaser@LeftArm(Front) G1 | MediumLaser@Head(Front) G1 | MediumLaser@CenterTorso(Front) G1 | MediumLaser@RightArm(Front) G1 | AC20@Special1(Front) G1 | SSRM2@LeftTorso(Front) G2 | SSRM2@RightTorso(Front) G2 | SRM6@Special2(Front) G2 | LRM20@LeftTorso(Side) G2,LeftArmx1 | Headx1 | CenterTorsox1 | RightArmx1 | Special1x1 | LeftTorsox2 | RightTorsox1 | Special2x1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O10) | RightTorso(M0/P0/B0/O8) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O4) | Special2(M0/P0/B0/O2),LeftArm(Front) | RightArm(Front) | LeftTorso(Front+Side) | RightTorso(Front) | CenterTorso(Front) | Head(Front) | Special1(Front) | Special2(Front),
Avatar,Yes,IS,17.000000,70.000000,Reactive,EndoSteel,12,Single,0,Yes,Yes,Yes,Yes,43,,1.3,1.3,1.5,1.5,1.6,1.6,1.75,0.5,0.3,11.35,10,"4x MachineGun, 2x LargeLaser, 2x LRM5, 2x LRM10",MachineGun@LeftArm(Front) G1 | MachineGun@Special1(Front) G1 | MachineGun@Special1(Front) G1 | MachineGun@RightArm(Front) G1 | LargeLaser@LeftArm(Front) G1 | LargeLaser@RightArm(Front) G1 | LRM5@LeftTorso(Side) G2 | LRM5@RightTorso(Side) G2 | LRM10@LeftTorso(Side) G2 | LRM10@RightTorso(Side) G2,LeftArmx2 | Special1x2 | RightArmx2 | LeftTorsox2 | RightTorsox2,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O2),LeftArm(Front) | RightArm(Front) | LeftTorso(Side) | RightTorso(Side) | Head(Unknown) | Special1(Front),
Awesome,Yes,IS,23.000000,80.000000,Standard,Standard,28,Single,0,No,Yes,Yes,Yes,43,,1.45,1.45,1.55,1.55,1.65,1.65,1.75,1.25,0.3,12.6,6,"SmallPulseLaser, 3x ERPPC, UltraAC5, LRM5",SmallPulseLaser@Head(Front) G1 | ERPPC@Lefttorso(Front) G1 | ERPPC@righttorso(Front) G1 | ERPPC@RightArm(Front) G1 | UltraAC5@LeftArm(Front) G1 | LRM5@CenterTorso(Side) G2,Headx1 | Lefttorsox1 | righttorsox1 | RightArmx1 | LeftArmx1 | CenterTorsox1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1),LeftArm(Front) | RightArm(Front) | LeftTorso(Unknown) | RightTorso(Unknown) | CenterTorso(Side) | Head(Front),
Battlemaster,Yes,IS,20.500000,85.000000,Standard,EndoSteel,25,Single,0,No,Yes,Yes,Yes,43,,1.45,1.45,1.6,1.6,1.8,1.8,2.05,0.95,0.3,13,10,"PPC, 6x MediumLaser, 2x MachineGun, SRM6",PPC@Special2(Front) G1 | MediumLaser@RightTorso(Front) G1 | MediumLaser@RightTorso(Front) G1 | MediumLaser@RightTorso(Rear) G1 | MediumLaser@LeftTorso(Front) G1 | MediumLaser@LeftTorso(Front) G1 | MediumLaser@LeftTorso(Rear) G1 | MachineGun@LeftArm(Front) G1 | MachineGun@LeftArm(Front) G1 | SRM6@Special1(Front) G2,Special2x1 | RightTorsox3 | LeftTorsox3 | LeftArmx2 | Special1x1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O4) | LeftTorso(M0/P0/B0/O9) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O3) | Special2(M0/P0/B0/O4),LeftArm(Front) | RightArm(Unknown) | LeftTorso(Front+Rear) | RightTorso(Front+Rear) | CenterTorso(Unknown) | Head(Unknown) | Special1(Front) | Special2(Front),
Battlemaster2c,Yes,Clan,15.500000,85.000000,Standard,EndoSteel,25,Single,0,No,Yes,Yes,Yes,39,,1.45,1.45,1.6,1.6,1.8,1.8,2.05,0.95,0.3,13,10,"ClanERPPC, 6x ClanERMediumLaser, 2x ClanGaussRifle, ClanSSRM6",ClanERPPC@RightArm(Front) G1 | ClanERMediumLaser@RightTorso(Front) G1 | ClanERMediumLaser@RightTorso(Front) G1 | ClanERMediumLaser@RightTorso(Rear) G1 | ClanERMediumLaser@LeftTorso(Front) G1 | ClanERMediumLaser@LeftTorso(Front) G1 | ClanERMediumLaser@LeftTorso(Rear) G1 | ClanGaussRifle@LeftArm(Front) G1 | ClanGaussRifle@LeftArm(Front) G1 | ClanSSRM6@Special1(Front) G2,RightArmx1 | RightTorsox3 | LeftTorsox3 | LeftArmx2 | Special1x1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O4) | LeftTorso(M0/P0/B0/O9) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O3),LeftArm(Front) | RightArm(Front) | LeftTorso(Front+Rear) | RightTorso(Front+Rear) | CenterTorso(Unknown) | Head(Unknown) | Special1(Front),
Behemoth,Yes,Clan,22.000000,100.000000,Standard,Standard,21,Single,1,Yes,Yes,Yes,Yes,43,,1.95,1.95,2.15,2.15,2.45,2.45,2.2,1.1,0.3,16.7,7,"4x ClanLargePulseLaser, 2x ClanGaussRifle, LargeLaser",ClanLargePulseLaser@LeftTorso(Front) G1 | ClanLargePulseLaser@LeftTorso(Front) G1 | ClanLargePulseLaser@RightTorso(Front) G1 | ClanLargePulseLaser@RightTorso(Front) G1 | ClanGaussRifle@LeftArm(Front) G1 | ClanGaussRifle@RightArm(Front) G1 | LargeLaser@Special1(Front) G1,LeftTorsox2 | RightTorsox2 | LeftArmx1 | RightArmx1 | Special1x1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O2),LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | Head(Unknown) | Special1(Front),
Behemoth2,Yes,Clan,22.000000,100.000000,Standard,Standard,21,Single,1,Yes,Yes,Yes,Yes,43,,1.95,1.95,2.15,2.15,2.45,2.45,2.2,1.1,0.3,16.7,7,"4x ClanLargePulseLaser, 2x ClanGaussRifle, LargeLaser",ClanLargePulseLaser@LeftTorso(Front) G1 | ClanLargePulseLaser@LeftTorso(Front) G1 | ClanLargePulseLaser@RightTorso(Front) G1 | ClanLargePulseLaser@RightTorso(Front) G1 | ClanGaussRifle@LeftArm(Front) G1 | ClanGaussRifle@RightArm(Front) G1 | LargeLaser@Special1(Front) G1,LeftTorsox2 | RightTorsox2 | LeftArmx1 | RightArmx1 | Special1x1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O2),LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | Head(Unknown) | Special1(Front),
Blackhawk,Yes,Clan,10.000000,50.000000,FerroFiberus,EndoSteel,12,Single,0,Yes,Yes,Yes,Yes,43,,0.9,0.9,0.95,0.95,1.05,1.05,1.2,0.55,0.25,7.8,4,"2x ClanMediumPulseLaser, 2x ClanERPPC",ClanMediumPulseLaser@LeftTorso(Front) G1 | ClanMediumPulseLaser@RightTorso(Front) G1 | ClanERPPC@LeftArm(Front) G1 | ClanERPPC@RightArm(Front) G1,LeftTorsox1 | RightTorsox1 | LeftArmx1 | RightArmx1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O10) | RightTorso(M0/P0/B0/O10) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O2) | Special2(M0/P0/B0/O2),LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown) | Special1(Unknown) | Special2(Unknown),
Blackheart,No,Clan,14.000000,70.000000,FerroFiberus,Standard,0,,0,No,Yes,No,No,6,,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.9,0,,,,LeftArm(M0/P3/B0/O0) | RightArm(M0/P3/B0/O0) | LeftTorso(M0/P0/B1/O2) | RightTorso(M0/P0/B1/O2) | CenterTorso(M0/P0/B0/O2),LeftArm(Unknown) | RightArm(Unknown) | LeftTorso(Unknown) | RightTorso(Unknown) | CenterTorso(Unknown),"not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud"
Blacklanner,Yes,Clan,12.500000,55.000000,FerroFiberus,EndoSteel,10,Single,0,No,Yes,Yes,Yes,40,ECM,0.9,0.9,1.0,1.0,1.05,1.05,1.15,0.75,0.25,8.05,5,"2x ClanERMediumLaser, ClanERLargeLaser, ClanSRM6, ClanLRM10",ClanERMediumLaser@LeftArm(Front) G1 | ClanERMediumLaser@LeftArm(Front) G1 | ClanERLargeLaser@RightArm(Front) G1 | ClanSRM6@Special2(Side) G2 | ClanLRM10@Special1(Side) G2,LeftArmx2 | RightArmx1 | Special2x1 | Special1x1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | Special1(M0/P0/B0/O12) | Special2(M0/P0/B0/O12),LeftArm(Front) | RightArm(Front) | Special1(Side) | Special2(Side),
Blacknight,Yes,IS,16.000000,75.000000,Standard,Standard,22,Single,0,Yes,Yes,Yes,Yes,43,,1.2,1.2,1.4,1.4,1.55,1.55,1.8,0.8,0.3,11.2,8,"SmallLaser, 4x MediumLaser, 2x LargeLaser, PPC",SmallLaser@Head(Front) G1 | MediumLaser@LeftArm(Front) G1 | MediumLaser@LeftTorso(Front) G1 | MediumLaser@RightTorso(Front) G1 | MediumLaser@RightArm(Front) G1 | LargeLaser@LeftTorso(Front) G1 | LargeLaser@RightTorso(Front) G1 | PPC@RightArm(Front) G1,Headx1 | LeftArmx1 | LeftTorsox2 | RightTorsox2 | RightArmx2,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1),LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Front),
Bowman,No,Clan,16.000000,70.000000,FerroFiberus,Standard,0,,0,No,Yes,Yes,No,5,,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.9,0,,,,LeftArm(M0/P2/B2/O2) | RightArm(M4/P0/B0/O0) | Special1(M4/P0/B0/O0) | Special2(M0/P0/B0/O3),LeftArm(Unknown) | RightArm(Unknown) | Special1(Unknown) | Special2(Unknown),"not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud"
Brigand,Yes,IS,7.000000,25.000000,FerroFiberus,Standard,10,Single,0,Yes,Yes,Yes,Yes,40,,0.45,0.45,0.45,0.45,0.55,0.55,0.55,0.4,0.25,4.1,4,"2x MediumPulseLaser, 2x MediumLaser",MediumPulseLaser@LeftArm(Front) G1 | MediumPulseLaser@RightArm(Front) G1 | MediumLaser@Special2(Front) G1 | MediumLaser@Special1(Front) G1,LeftArmx1 | RightArmx1 | Special2x1 | Special1x1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | Special1(M0/P0/B0/O12) | Special2(M0/P0/B0/O12),LeftArm(Front) | RightArm(Front) | Special1(Front) | Special2(Front),
Bushwacker,Yes,IS,15.500000,55.000000,FerroFiberus,Standard,11,Single,0,No,Yes,Yes,Yes,43,,0.9,0.9,1.1,1.1,1.15,1.15,1.35,0.5,0.25,8.4,8,"2x MediumLaser, ERLargeLaser, 2x MachineGun, AC10, 2x LRM5",MediumLaser@CenterTorso(Front) G1 | MediumLaser@CenterTorso(Front) G1 | ERLargeLaser@RightArm(Front) G1 | MachineGun@LeftTorso(Front) G1 | MachineGun@RightTorso(Front) G1 | AC10@LeftArm(Front) G1 | LRM5@Special1(Side) G2 | LRM5@Special1(Side) G2,CenterTorsox2 | RightArmx1 | LeftTorsox1 | RightTorsox1 | LeftArmx1 | Special1x2,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O8) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O4),LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Front) | Head(Unknown) | Special1(Side),
Canis,No,Clan,15.000000,80.000000,FerroFiberus,EndoSteel,0,,0,Yes,No,No,No,,,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.9,0,,,,LeftArm(M0/P0/B5/O0) | RightArm(M0/P0/B5/O0) | Special1(M0/P3/B0/O0) | Special2(M0/P3/B0/O0),LeftArm(Unknown) | RightArm(Unknown) | Special1(Unknown) | Special2(Unknown),"not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud"
Catapult,Yes,IS,15.000000,65.000000,Reactive,Standard,10,Single,1,Yes,Yes,Yes,Yes,43,BAP,1.45,1.45,1.35,1.35,1.45,1.45,1.5,0.65,0.3,10.95,4,"2x LargeLaser, 2x LRM20",LargeLaser@LeftTorso(Front) G1 | LargeLaser@RightTorso(Front) G1 | LRM20@LeftArm(Side) G2 | LRM20@RightArm(Side) G2,LeftTorsox1 | RightTorsox1 | LeftArmx1 | RightArmx1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1),LeftArm(Side) | RightArm(Side) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown),
CauldronBorn,Yes,Clan,13.500000,65.000000,FerroFiberus,EndoSteel,13,Single,0,Yes,Yes,Yes,Yes,43,,0.85,0.85,0.95,0.95,1.15,1.15,1.55,0.85,0.25,8.55,6,"ClanERMediumLaser, ClanUltraAC5, ClanGaussRifle, ClanSSRM2, 2x ClanLRM10",ClanERMediumLaser@LeftTorso(Front) G1 | ClanUltraAC5@LeftArm(Front) G1 | ClanGaussRifle@RightArm(Front) G1 | ClanSSRM2@RightTorso(Front) G2 | ClanLRM10@Special1(Side) G2 | ClanLRM10@Special2(Side) G2,LeftTorsox1 | LeftArmx1 | RightArmx1 | RightTorsox1 | Special1x1 | Special2x1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O8) | RightTorso(M0/P0/B0/O8) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O4) | Special2(M0/P0/B0/O4),LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown) | Special1(Side) | Special2(Side),
Chimera,Yes,IS,9.500000,40.000000,Standard,EndoSteel,14,Single,1,Yes,Yes,Yes,Yes,43,BAP,0.95,0.95,1.0,1.0,1.0,1.0,1.1,0.5,0.3,7.8,7,"2x MediumPulseLaser, ERLargeLaser, 4x LRM5",MediumPulseLaser@LeftArm(Front) G1 | MediumPulseLaser@LeftArm(Front) G1 | ERLargeLaser@RightArm(Front) G1 | LRM5@RightTorso(Side) G2 | LRM5@RightTorso(Side) G2 | LRM5@RightTorso(Side) G2 | LRM5@RightTorso(Side) G2,LeftArmx2 | RightArmx1 | RightTorsox4,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1),LeftArm(Front) | RightArm(Front) | LeftTorso(Unknown) | RightTorso(Side) | CenterTorso(Unknown) | Head(Unknown),
Commando,Yes,IS,7.000000,25.000000,Standard,Standard,8,Single,0,Yes,Yes,Yes,Yes,43,,0.6,0.6,0.8,0.8,0.75,0.75,0.8,0.45,0.3,5.85,3,"2x MediumLaser, SRM6",MediumLaser@LeftArm(Front) G1 | MediumLaser@RightArm(Front) G1 | SRM6@CenterTorso(Front) G2,LeftArmx1 | RightArmx1 | CenterTorsox1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1),LeftArm(Front) | RightArm(Front) | LeftTorso(Unknown) | RightTorso(Unknown) | CenterTorso(Front) | Head(Unknown),
Cougar,Yes,Clan,8.500000,35.000000,FerroFiberus,EndoSteel,10,Single,1,Yes,Yes,Yes,Yes,43,BAP,0.7,0.7,0.7,0.7,0.75,0.75,0.8,0.45,0.25,5.8,5,"2x ClanMediumPulseLaser, ClanMachineGun, 2x ClanLRM10",ClanMediumPulseLaser@LeftArm(Front) G1 | ClanMediumPulseLaser@RightArm(Front) G1 | ClanMachineGun@RightTorso(Front) G1 | ClanLRM10@LeftTorso(Side) G2 | ClanLRM10@RightTorso(Side) G2,LeftArmx1 | RightArmx1 | RightTorsox2 | LeftTorsox1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1),LeftArm(Front) | RightArm(Front) | LeftTorso(Side) | RightTorso(Front+Side) | CenterTorso(Unknown) | Head(Unknown),
Crab,No,IS,10.500000,50.000000,FerroFiberus,Standard,0,,0,No,No,Yes,No,1,,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.9,0,,,,LeftArm(M0/P0/B4/O0) | RightArm(M0/P0/B4/O0) | CenterTorso(M0/P0/B2/O0) | Special1(M0/P0/B1/O1),LeftArm(Unknown) | RightArm(Unknown) | CenterTorso(Unknown) | Special1(Unknown),"not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud"
Cyclops,Yes,IS,19.000000,90.000000,FerroFiberus,Standard,16,Single,0,No,Yes,Yes,Yes,45,BAP,1.4,1.4,1.4,1.4,1.55,1.55,1.45,0.8,0.25,11.2,8,"3x MediumPulseLaser, 2x MediumLaser, GaussRifle, SRM4, LRM10",MediumPulseLaser@LeftArm(Front) G1 | MediumPulseLaser@Special1(Front) G1 | MediumPulseLaser@RightArm(Front) G1 | MediumLaser@LeftArm(Front) G1 | MediumLaser@RightArm(Front) G1 | GaussRifle@RightTorso(Front) G1 | SRM4@CenterTorso(Front) G2 | LRM10@LeftTorso(Side) G2,LeftArmx2 | Special1x1 | RightArmx2 | RightTorsox1 | CenterTorsox1 | LeftTorsox1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O2),LeftArm(Front) | RightArm(Front) | LeftTorso(Side) | RightTorso(Front) | CenterTorso(Front) | Head(Unknown) | Special1(Front),
Daishi,Yes,Clan,25.000000,100.000000,Standard,Standard,21,Single,0,No,Yes,Yes,Yes,43,,1.75,1.75,1.9,1.9,2.0,2.0,2.2,1.5,0.3,15.3,6,"3x ClanLargePulseLaser, ClanGaussRifle, 2x ClanSSRM6",ClanLargePulseLaser@RightArm(Front) G1 | ClanLargePulseLaser@RightArm(Front) G1 | ClanLargePulseLaser@RightArm(Front) G1 | ClanGaussRifle@LeftArm(Front) G1 | ClanSSRM6@special1(Front) G2 | ClanSSRM6@special1(Front) G2,RightArmx3 | LeftArmx1 | special1x2,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O8) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O4),LeftArm(Front) | RightArm(Front) | LeftTorso(Unknown) | RightTorso(Unknown) | CenterTorso(Unknown) | Head(Unknown) | Special1(Unknown),
Deimos,Yes,Clan,18.000000,85.000000,Reactive,EndoSteel,17,Single,0,No,Yes,Yes,Yes,43,,1.55,1.55,1.65,1.65,1.75,1.75,2.05,0.7,0.3,12.95,10,"2x ClanERMediumLaser, 6x ClanUltraAC2, 2x ClanLRM15",ClanERMediumLaser@LeftTorso(Front) G1 | ClanERMediumLaser@RightTorso(Front) G1 | ClanUltraAC2@LeftArm(Front) G1 | ClanUltraAC2@LeftArm(Front) G1 | ClanUltraAC2@LeftArm(Front) G1 | ClanUltraAC2@RightArm(Front) G1 | ClanUltraAC2@RightArm(Front) G1 | ClanUltraAC2@RightArm(Front) G1 | ClanLRM15@Special1(Side) G2 | ClanLRM15@Special2(Side) G2,LeftTorsox1 | RightTorsox1 | LeftArmx3 | RightArmx3 | Special1x1 | Special2x1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O9) | RightTorso(M0/P0/B0/O9) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O3) | Special2(M0/P0/B0/O3),LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown) | Special1(Side) | Special2(Side),
Dragon,Yes,Clan,17.000000,60.000000,Standard,Standard,13,Single,0,Yes,Yes,Yes,Yes,43,,1.15,1.15,1.4,1.4,1.25,1.25,1.55,0.9,0.3,10.35,5,"3x MediumLaser, ERPPC, LRM10",MediumLaser@LeftArm(Front) G1 | MediumLaser@LeftTorso(Front) G1 | MediumLaser@RightTorso(Front) G1 | ERPPC@RightArm(Front) G1 | LRM10@CenterTorso(Side) G2,LeftArmx1 | LeftTorsox1 | RightTorsox1 | RightArmx1 | CenterTorsox1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1),LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Side) | Head(Unknown),
Duangung,No,IS,7.000000,25.000000,FerroFiberus,Standard,0,,0,Yes,No,No,No,,,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.9,0,,,,LeftArm(M0/P0/B2/O0) | RightArm(M0/P0/B2/O0) | CenterTorso(M2/P0/B0/O0) | Special1(M0/P0/B1/O0) | Special2(M0/P0/B1/O0),LeftArm(Unknown) | RightArm(Unknown) | CenterTorso(Unknown) | Special1(Unknown) | Special2(Unknown),"not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud"
Fafnir,Yes,IS,21.000000,100.000000,FerroFiberus,Standard,7,Single,0,No,Yes,No,No,43,,1.8,1.8,1.9,1.9,2.0,2.0,2.2,1.0,0.3,14.9,7,"2x ClanGaussRifle, 2x LargeLaser, 3x MediumLaser",ClanGaussRifle@RightTorso(Front) G1 | ClanGaussRifle@LeftTorso(Front) G1 | LargeLaser@RightArm(Front) G1 | LargeLaser@LeftArm(Front) G1 | MediumLaser@RightTorso(Front) G1 | MediumLaser@CenterTorso(Front) G1 | MediumLaser@LeftTorso(Front) G1,RightTorsox2 | LeftTorsox2 | RightArmx1 | LeftArmx1 | CenterTorsox1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1),LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Front) | Head(Unknown),
Flea,Yes,IS,7.000000,20.000000,Standard,Standard,2,Single,0,No,Yes,Yes,Yes,43,,0.4,0.4,0.4,0.4,0.5,0.5,0.65,0.3,0.3,3.85,6,"2x SmallLaser, 2x MediumLaser, 2x MachineGun",SmallLaser@LeftTorso(Rear) G1 | SmallLaser@RightTorso(Rear) G1 | MediumLaser@LeftArm(Front) G1 | MediumLaser@RightArm(Front) G1 | MachineGun@LeftArm(Front) G1 | MachineGun@RightArm(Front) G1,LeftTorsox1 | RightTorsox1 | LeftArmx2 | RightArmx2,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1),LeftArm(Front) | RightArm(Front) | LeftTorso(Rear) | RightTorso(Rear) | CenterTorso(Unknown) | Head(Unknown),
Gargoyle,No,Clan,15.000000,80.000000,FerroFiberus,EndoSteel,0,,0,No,Yes,No,No,6,,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.9,0,,,,LeftArm(M1/P0/B0/O3) | RightArm(M1/P0/B0/O3) | LeftTorso(M0/P2/B2/O0) | RightTorso(M0/P2/B2/O0),LeftArm(Unknown) | RightArm(Unknown) | LeftTorso(Unknown) | RightTorso(Unknown),"not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud"
Gesu,No,Clan,9.750000,45.000000,FerroFiberus,EndoSteel,0,,0,No,No,Yes,No,,,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.9,0,,,,LeftArm(M0/P2/B0/O0) | RightArm(M0/P2/B0/O0) | LeftTorso(M0/P0/B2/O0) | RightTorso(M0/P0/B2/O0) | Special1(M2/P0/B0/O0) | Special2(M2/P0/B0/O0),LeftArm(Unknown) | RightArm(Unknown) | LeftTorso(Unknown) | RightTorso(Unknown) | Special1(Unknown) | Special2(Unknown),"not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud"
Gladiator,Yes,Clan,24.000000,95.000000,FerroFiberus,Standard,19,Single,1,Yes,Yes,Yes,Yes,43,,1.4,1.4,1.65,1.65,1.75,1.75,2.0,0.95,0.25,12.8,12,"5x ClanSmallPulseLaser, ClanERSmallLaser, 3x ClanMediumPulseLaser, ClanLargePulseLaser, 2x SRM6",ClanSmallPulseLaser@RightTorso(Front) G1 | ClanSmallPulseLaser@RightTorso(Front) G1 | ClanSmallPulseLaser@RightArm(Front) G1 | ClanSmallPulseLaser@RightArm(Front) G1 | ClanSmallPulseLaser@RightArm(Front) G1 | ClanERSmallLaser@LeftTorso(Front) G1 | ClanMediumPulseLaser@RightArm(Front) G1 | ClanMediumPulseLaser@RightArm(Front) G1 | ClanMediumPulseLaser@RightArm(Front) G1 | ClanLargePulseLaser@LeftArm(Front) G1 | SRM6@LeftArm(Front) G2 | SRM6@LeftArm(Front) G2,RightTorsox2 | RightArmx6 | LeftTorsox1 | LeftArmx3,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1),LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown),
Grizzly,Yes,Clan,16.000000,70.000000,FerroFiberus,Standard,11,Single,1,Yes,Yes,Yes,Yes,40,,1.2,1.2,1.1,1.1,1.4,1.4,1.5,0.5,0.25,9.65,6,"2x ClanSmallPulseLaser, ClanMediumPulseLaser, ClanLargePulseLaser, ClanGaussRifle, CLANLRM10",ClanSmallPulseLaser@LeftArm(Front) G1 | ClanSmallPulseLaser@LeftArm(Front) G1 | ClanMediumPulseLaser@RightTorso(Front) G1 | ClanLargePulseLaser@LeftArm(Front) G1 | ClanGaussRifle@RightArm(Front) G1 | CLANLRM10@LeftTorso(Side) G2,LeftArmx3 | RightTorsox1 | RightArmx1 | LeftTorsox1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12),LeftArm(Front) | RightArm(Front) | LeftTorso(Side) | RightTorso(Front),
Hauptmann,Yes,Clan,21.000000,95.000000,Standard,Standard,20,Single,0,Yes,Yes,Yes,Yes,43,ECM,1.7,1.7,1.8,1.8,1.9,1.9,2.1,1.1,0.3,14.3,8,"ClanERSmallLaser, 2x ClanMediumPulseLaser, 2x ClanLargePulseLaser, ClanUltraAC20, 2x ClanSSRM2",ClanERSmallLaser@Head(Front) G1 | ClanMediumPulseLaser@LeftArm(Front) G1 | ClanMediumPulseLaser@RightArm(Front) G1 | ClanLargePulseLaser@LeftArm(Front) G1 | ClanLargePulseLaser@RightArm(Front) G1 | ClanUltraAC20@Special1(Front) G1 | ClanSSRM2@LeftTorso(Front) G2 | ClanSSRM2@RightTorso(Front) G2,Headx1 | LeftArmx2 | RightArmx2 | Special1x1 | LeftTorsox1 | RightTorsox1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O8) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O4),LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Front) | Special1(Front),
Hellhound,Yes,Clan,10.500000,50.000000,FerroFiberus,EndoSteel,12,Single,1,Yes,Yes,Yes,Yes,43,,0.9,0.9,0.95,0.95,1.05,1.05,1.2,0.55,0.25,7.8,6,"3x ClanMediumPulseLaser, ClanUltraAC2, ClanUltraAC5, ClanLRM10",ClanMediumPulseLaser@LeftArm(Front) G1 | ClanMediumPulseLaser@LeftArm(Front) G1 | ClanMediumPulseLaser@RightArm(Front) G1 | ClanUltraAC2@RightTorso(Front) G1 | ClanUltraAC5@RightTorso(Front) G1 | ClanLRM10@LeftTorso(Side) G2,LeftArmx2 | RightArmx1 | RightTorsox2 | LeftTorsox1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1),LeftArm(Front) | RightArm(Front) | LeftTorso(Side) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown),
Hellspawn,Yes,IS,10.000000,45.000000,Standard,Standard,9,Single,1,Yes,Yes,Yes,Yes,43,ECM,0.5,0.5,0.8,0.8,0.85,0.85,1.15,0.5,0.3,6.25,6,"2x MediumPulseLaser, LargePulseLaser, 2x SSRM2, LRM10",MediumPulseLaser@LeftArm(Front) G1 | MediumPulseLaser@LeftArm(Front) G1 | LargePulseLaser@LeftArm(Front) G1 | SSRM2@RightArm(Front) G2 | SSRM2@Special1(Front) G2 | LRM10@LeftTorso(Front) G2,LeftArmx3 | RightArmx1 | Special1x1 | LeftTorsox1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O8) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O4),LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Unknown) | CenterTorso(Unknown) | Head(Unknown) | Special1(Front),
Highlander,Yes,IS,21.500000,90.000000,Standard,Standard,17,Single,1,Yes,Yes,Yes,Yes,43,,1.75,1.45,1.7,1.7,1.8,1.8,2.0,0.85,0.3,13.35,7,"4x MediumPulseLaser, GaussRifle, 2x SRM6",MediumPulseLaser@RightTorso(Front) G1 | MediumPulseLaser@RightTorso(Front) G1 | MediumPulseLaser@RightArm(Front) G1 | MediumPulseLaser@RightArm(Front) G1 | GaussRifle@LeftArm(Front) G1 | SRM6@LeftTorso(Front) G2 | SRM6@LeftTorso(Front) G2,RightTorsox2 | RightArmx2 | LeftArmx1 | LeftTorsox2,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1),LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown),
Hollander,Yes,IS,10.000000,45.000000,FerroFiberus,EndoSteel,12,Single,0,No,Yes,Yes,Yes,42,,0.85,0.85,0.85,0.85,0.9,0.9,1.05,0.45,0.25,6.95,6,"2x SmallPulseLaser, 3x MediumPulseLaser, GaussRifle",SmallPulseLaser@Special2(Front) G1 | SmallPulseLaser@Special2(Front) G1 | MediumPulseLaser@LeftArm(Front) G1 | MediumPulseLaser@LeftTorso(Front) G1 | MediumPulseLaser@RightArm(Front) G1 | GaussRifle@Special1(Front) G1,Special2x2 | LeftArmx1 | LeftTorsox1 | RightArmx1 | Special1x1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | Special1(M0/P0/B0/O12) | Special2(M0/P0/B0/O2),LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | Special1(Front) | Special2(Front),
Hunchback,Yes,IS,13.500000,50.000000,Standard,Standard,10,Single,0,Yes,Yes,Yes,Yes,43,ECM,1.0,1.0,1.1,1.1,1.2,1.2,1.5,0.5,0.3,8.9,6,"SmallLaser, 4x MediumLaser, AC10",SmallLaser@Head(Front) G1 | MediumLaser@LeftArm(Front) G1 | MediumLaser@LeftArm(Front) G1 | MediumLaser@RightArm(Front) G1 | MediumLaser@RightArm(Front) G1 | AC10@Special1(Front) G1,Headx1 | LeftArmx2 | RightArmx2 | Special1x1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O8) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O4),LeftArm(Front) | RightArm(Front) | LeftTorso(Unknown) | RightTorso(Unknown) | CenterTorso(Unknown) | Head(Front) | Special1(Front),
Kodiak,Yes,IS,22.000000,100.000000,Standard,EndoSteel,20,Single,1,Yes,Yes,Yes,Yes,43,,1.5,1.5,1.9,1.9,1.5,1.5,2,1.1,0.3,13.2,7,"4x ClanERMediumLaser, ClanUltraAC20, 2x ClanSSRM6",ClanERMediumLaser@leftArm(Front) G1 | ClanERMediumLaser@leftArm(Front) G1 | ClanERMediumLaser@rightarm(Front) G1 | ClanERMediumLaser@rightarm(Front) G1 | ClanUltraAC20@RightTorso(Front) G1 | ClanSSRM6@LeftTorso(Front) G2 | ClanSSRM6@LeftTorso(Front) G2,leftArmx2 | rightarmx2 | RightTorsox1 | LeftTorsox2,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1),LeftArm(Unknown) | RightArm(Unknown) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown),
Loki,Yes,Clan,17.500000,65.000000,Standard,Standard,13,Single,0,No,Yes,Yes,Yes,43,ECM,1.3,1.3,1.4,1.4,1.5,1.5,1.55,0.6,0.3,10.85,7,"2x ClanERMediumLaser, 2x ClanMachineGun, 2x ClanUltraAC5, ClanSSRM6",ClanERMediumLaser@LeftArm(Front) G1 | ClanERMediumLaser@RightArm(Front) G1 | ClanMachineGun@LeftTorso(Front) G1 | ClanMachineGun@RightTorso(Front) G1 | ClanUltraAC5@LeftArm(Front) G1 | ClanUltraAC5@RightArm(Front) G1 | ClanSSRM6@Special1(Front) G2,LeftArmx2 | RightArmx2 | LeftTorsox1 | RightTorsox1 | Special1x1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O10) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O2),LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown) | Special1(Front),
Longbow,Yes,IS,20.500000,85.000000,Standard,Standard,11,Single,0,No,Yes,Yes,Yes,43,,1.6,1.6,1.65,1.65,1.2,1.2,1.85,1.0,0.3,12.05,6,"2x MediumLaser, 2x LRM5, 2x LRM20",MediumLaser@LeftTorso(Front) G1 | MediumLaser@RightTorso(Front) G1 | LRM5@LeftTorso(Front) G2 | LRM5@RightTorso(Front) G2 | LRM20@LeftArm(Front) G2 | LRM20@RightArm(Front) G2,LeftTorsox2 | RightTorsox2 | LeftArmx1 | RightArmx1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1),LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown),
MadCat_MkII,Yes,Clan,18.500000,90.000000,Reflective,EndoSteel,17,Single,1,Yes,Yes,Yes,Yes,43,,1.8,1.8,1.8,1.8,1.85,1.85,2.0,0.8,0.3,14,12,"4x ClanERSmallLaser, 2x ClanMachineGun, 4x ClanUltraAC5, 2x ClanLRM15",ClanERSmallLaser@LeftTorso(Front) G1 | ClanERSmallLaser@CenterTorso(Front) G1 | ClanERSmallLaser@CenterTorso(Front) G1 | ClanERSmallLaser@RightTorso(Front) G1 | ClanMachineGun@LeftTorso(Front) G1 | ClanMachineGun@RightTorso(Front) G1 | ClanUltraAC5@LeftArm(Front) G1 | ClanUltraAC5@LeftArm(Front) G1 | ClanUltraAC5@RightArm(Front) G1 | ClanUltraAC5@RightArm(Front) G1 | ClanLRM15@Special2(Side) G2 | ClanLRM15@Special1(Side) G2,LeftTorsox2 | CenterTorsox2 | RightTorsox2 | LeftArmx2 | RightArmx2 | Special2x1 | Special1x1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O8) | RightTorso(M0/P0/B0/O8) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O4) | Special2(M0/P0/B0/O4),LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Front) | Head(Unknown) | Special1(Side) | Special2(Side),
Madcat,Yes,Clan,16.500000,75.000000,FerroFiberus,EndoSteel,17,Single,0,Yes,Yes,Yes,Yes,43,,1.1,1.1,1.2,1.2,1.4,1.4,1.5,0.5,0.25,9.65,8,"2x ClanMediumPulseLaser, 2x ClanERLargeLaser, 2x ClanMachineGun, 2x ClanLRM10",ClanMediumPulseLaser@LeftArm(Front) G1 | ClanMediumPulseLaser@RightArm(Front) G1 | ClanERLargeLaser@LeftArm(Front) G1 | ClanERLargeLaser@RightArm(Front) G1 | ClanMachineGun@LeftTorso(Front) G1 | ClanMachineGun@RightTorso(Front) G1 | ClanLRM10@Special1(Side) G2 | ClanLRM10@Special2(Side) G2,LeftArmx2 | RightArmx2 | LeftTorsox1 | RightTorsox1 | Special1x1 | Special2x1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O9) | RightTorso(M0/P0/B0/O9) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O3) | Special2(M0/P0/B0/O3),LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown) | Special1(Side) | Special2(Side),
Masakari,Yes,Clan,18.000000,85.000000,FerroFiberus,Standard,15,Single,0,Yes,Yes,Yes,Yes,43,,1.25,1.25,1.4,1.4,1.45,1.45,1.8,0.85,0.25,11.1,7,"2x ClanERMediumLaser, 2x ClanUltraAC2, ClanGaussRifle, 2x ClanLRM10",ClanERMediumLaser@RightTorso(Front) G1 | ClanERMediumLaser@RightTorso(Front) G1 | ClanUltraAC2@RightArm(Front) G1 | ClanUltraAC2@RightArm(Front) G1 | ClanGaussRifle@LeftArm(Front) G1 | ClanLRM10@LeftTorso(Side) G2 | ClanLRM10@LeftTorso(Side) G2,RightTorsox2 | RightArmx2 | LeftArmx1 | LeftTorsox2,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1),LeftArm(Front) | RightArm(Front) | LeftTorso(Side) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown),
Mauler,Yes,IS,26.000000,90.000000,FerroFiberus,Standard,11,Single,0,No,Yes,Yes,Yes,43,,1.4,1.4,1.4,1.4,1.55,1.55,1.45,0.8,0.25,11.2,10,"2x GaussRifle, 2x SSRM4, 6x LRM5",GaussRifle@LeftArm(Front) G1 | GaussRifle@RightArm(Front) G1 | SSRM4@LeftTorso(Front) G2 | SSRM4@RightTorso(Front) G2 | LRM5@LeftTorso(Side) G2 | LRM5@LeftTorso(Side) G2 | LRM5@LeftTorso(Side) G2 | LRM5@RightTorso(Side) G2 | LRM5@RightTorso(Side) G2 | LRM5@RightTorso(Side) G2,LeftArmx1 | RightArmx1 | LeftTorsox4 | RightTorsox4,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1),LeftArm(Front) | RightArm(Front) | LeftTorso(Front+Side) | RightTorso(Front+Side) | CenterTorso(Unknown) | Head(Unknown),
Novacat,Yes,Clan,16.000000,70.000000,Reactive,EndoSteel,17,Single,1,Yes,Yes,Yes,Yes,43,ECM,1.55,1.55,1.45,1.45,1.5,1.5,1.7,0.75,0.3,11.75,7,"5x ClanMediumPulseLaser, 2x ClanERLargeLaser",ClanMediumPulseLaser@LeftArm(Front) G1 | ClanMediumPulseLaser@LeftArm(Front) G1 | ClanMediumPulseLaser@LeftArm(Front) G1 | ClanMediumPulseLaser@LeftTorso(Front) G1 | ClanMediumPulseLaser@RightTorso(Front) G1 | ClanERLargeLaser@RightArm(Front) G1 | ClanERLargeLaser@RightArm(Front) G1,LeftArmx3 | LeftTorsox1 | RightTorsox1 | RightArmx2,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1),LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown),
Osiris,Yes,IS,9.500000,30.000000,FerroFiberus,EndoSteel,11,Single,1,Yes,Yes,Yes,Yes,43,,0.6,0.6,0.6,0.6,0.65,0.65,0.75,0.3,0.25,5,5,"SmallPulseLaser, 2x MediumPulseLaser, SSRM2, NarcBeacon",SmallPulseLaser@special2(Front) G1 | MediumPulseLaser@special1(Front) G1 | MediumPulseLaser@RightArm(Front) G1 | SSRM2@LeftArm(Front) G2 | NarcBeacon@LeftArm(Front) G3,special2x1 | special1x1 | RightArmx1 | LeftArmx2,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O1) | Special2(M0/P0/B0/O1),LeftArm(Front) | RightArm(Front) | LeftTorso(Unknown) | RightTorso(Unknown) | Head(Unknown) | Special1(Unknown) | Special2(Unknown),
Owens,Yes,IS,9.750000,35.000000,Standard,Standard,5,Single,0,No,Yes,Yes,Yes,39,ECM,0.9,0.9,0.8,0.8,0.8,0.8,1.05,0.35,0.3,6.7,5,"2x SmallLaser, MediumLaser, 2x SRM6",SmallLaser@CenterTorso(Front) G1 | SmallLaser@CenterTorso(Front) G1 | MediumLaser@Head(Front) G1 | SRM6@LeftArm(Front) G2 | SRM6@RightArm(Front) G2,CenterTorsox2 | Headx1 | LeftArmx1 | RightArmx1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O8) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1),LeftArm(Front) | RightArm(Front) | LeftTorso(Unknown) | RightTorso(Unknown) | CenterTorso(Front) | Head(Front),
Puma,Yes,Clan,7.500000,35.000000,FerroFiberus,EndoSteel,10,Single,1,Yes,Yes,Yes,Yes,43,,0.8,0.8,0.6,0.6,0.6,0.6,0.85,0.45,0.25,5.55,4,"2x ClanSmallPulseLaser, 2x ClanLRM20",ClanSmallPulseLaser@LeftTorso(Front) G1 | ClanSmallPulseLaser@RightTorso(Front) G1 | ClanLRM20@LeftArm(Front) G2 | ClanLRM20@RightArm(Front) G2,LeftTorsox1 | RightTorsox1 | LeftArmx1 | RightArmx1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1),LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown),
Raven,Yes,IS,10.250000,35.000000,FerroFiberus,Standard,7,Single,0,No,Yes,Yes,Yes,43,"BAP, ECM",0.6,0.65,0.65,0.65,0.7,0.7,0.75,0.25,0.25,5.2,5,"2x MediumLaser, SRM6, LRM5, NarcBeacon",MediumLaser@RightArm(Front) G1 | MediumLaser@RightArm(Front) G1 | SRM6@RightTorso(Front) G2 | LRM5@RightTorso(Side) G2 | NarcBeacon@LeftArm(Front) G3,RightArmx2 | RightTorsox2 | LeftArmx1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1),LeftArm(Front) | RightArm(Front) | LeftTorso(Unknown) | RightTorso(Front+Side) | CenterTorso(Unknown) | Head(Unknown),
Rifleman,Yes,IS,12.500000,60.000000,FerroFiberus,EndoSteel,17,Single,0,Yes,Yes,Yes,Yes,43,,0.9,0.9,1.0,1.0,1.5,1.5,1.3,0.7,0.25,9.05,6,"2x MediumLaser, 2x LargeLaser, 2x PPC",MediumLaser@Special1(Front) G1 | MediumLaser@Special1(Front) G1 | LargeLaser@LeftArm(Front) G1 | LargeLaser@RightArm(Front) G1 | PPC@LeftArm(Front) G1 | PPC@RightArm(Front) G1,Special1x2 | LeftArmx2 | RightArmx2,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O2),LeftArm(Front) | RightArm(Front) | LeftTorso(Unknown) | RightTorso(Unknown) | Head(Unknown) | Special1(Front),
Ryoken,Yes,IS,12.500000,55.000000,FerroFiberus,EndoSteel,10,Single,1,Yes,Yes,Yes,Yes,43,ECM,0.9,0.9,1.0,1.0,1.05,1.05,1.15,0.75,0.25,8.05,6,"4x ClanMediumPulseLaser, 2x ClanSSRM6",ClanMediumPulseLaser@LeftArm(Front) G1 | ClanMediumPulseLaser@LeftArm(Front) G1 | ClanMediumPulseLaser@RightArm(Front) G1 | ClanMediumPulseLaser@RightArm(Front) G1 | ClanSSRM6@LeftTorso(Front) G2 | ClanSSRM6@RightTorso(Front) G2,LeftArmx2 | RightArmx2 | LeftTorsox1 | RightTorsox1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1),LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown),
Shadowcat,Yes,Clan,9.750000,45.000000,FerroFiberus,EndoSteel,10,Single,1,Yes,Yes,Yes,Yes,43,BAP,0.85,0.85,0.85,0.85,0.9,0.9,1.05,0.45,0.25,6.95,5,"2x ClanMediumPulseLaser, ClanGaussRifle, 2x ClanSSRM4",ClanMediumPulseLaser@RightTorso(Front) G1 | ClanMediumPulseLaser@RightArm(Front) G1 | ClanGaussRifle@LeftArm(Front) G1 | ClanSSRM4@LeftTorso(Front) G2 | ClanSSRM4@RightTorso(Front) G2,RightTorsox2 | RightArmx1 | LeftArmx1 | LeftTorsox1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1),LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown),
Solitaire,Yes,Clan,7.000000,25.000000,FerroFiberus,EndoSteel,10,Single,0,Yes,Yes,Yes,Yes,46,,0.6,0.6,0.6,0.6,0.55,0.55,0.8,0.4,0.25,4.95,4,"ClanERSmallLaser, 2x ClanERMediumLaser, ClanERLargeLaser",ClanERSmallLaser@LeftTorso(Front) G1 | ClanERMediumLaser@LeftTorso(Front) G1 | ClanERMediumLaser@CenterTorso(Front) G1 | ClanERLargeLaser@Special1(Front) G1,LeftTorsox2 | CenterTorsox1 | Special1x1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O3),LeftArm(Unknown) | RightArm(Unknown) | LeftTorso(Front) | RightTorso(Unknown) | CenterTorso(Front) | Head(Unknown) | Special1(Front),
Sunder,Yes,IS,17.500000,90.000000,Standard,Standard,17,Single,0,Yes,Yes,Yes,Yes,43,,1.35,1.35,1.55,1.55,1.65,1.65,2.0,1.0,0.3,12.4,10,"6x MediumLaser, PPC, 2x MachineGun, SRM6",MediumLaser@LeftTorso(Front) G1 | MediumLaser@LeftTorso(Front) G1 | MediumLaser@LeftTorso(Rear) G1 | MediumLaser@RightTorso(Rear) G1 | MediumLaser@RightTorso(Front) G1 | MediumLaser@RightTorso(Front) G1 | PPC@LeftArm(Front) G1 | MachineGun@RightArm(Front) G1 | MachineGun@RightArm(Front) G1 | SRM6@CenterTorso(Front) G2,LeftTorsox3 | RightTorsox3 | LeftArmx1 | RightArmx2 | CenterTorsox1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1),LeftArm(Front) | RightArm(Front) | LeftTorso(Front+Rear) | RightTorso(Front+Rear) | CenterTorso(Front) | Head(Unknown),
Templar,Yes,IS,20.500000,85.000000,Standard,EndoSteel,25,Single,1,Yes,Yes,Yes,Yes,43,,1.45,1.45,1.6,1.6,1.8,1.8,2.05,0.95,0.3,13,11,"6x MediumPulseLaser, PPC, 2x MachineGun, AC20, SRM4",MediumPulseLaser@LeftArm(Front) G1 | MediumPulseLaser@LeftTorso(Front) G1 | MediumPulseLaser@RightTorso(Front) G1 | MediumPulseLaser@RightArm(Front) G1 | MediumPulseLaser@LeftTorso(Rear) G1 | MediumPulseLaser@RightTorso(Rear) G1 | PPC@LeftArm(Front) G1 | MachineGun@LeftTorso(Front) G1 | MachineGun@RightTorso(Front) G1 | AC20@RightArm(Front) G1 | SRM4@RightTorso(Front) G2,LeftArmx2 | LeftTorsox3 | RightTorsox4 | RightArmx2,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1),LeftArm(Front) | RightArm(Front) | LeftTorso(Front+Rear) | RightTorso(Front+Rear) | CenterTorso(Unknown) | Head(Unknown),
Thanatos,Yes,IS,18.000000,75.000000,FerroFiberus,EndoSteel,20,Single,1,Yes,Yes,Yes,Yes,43,,0.9,0.9,1.3,1.3,1.2,1.2,1.6,0.85,0.25,9.5,7,"MediumPulseLaser, 2x MediumLaser, 2x LargePulseLaser, 2x LRM10",MediumPulseLaser@LeftTorso(Front) G1 | MediumLaser@LeftArm(Front) G1 | MediumLaser@RightTorso(Front) G1 | LargePulseLaser@LeftArm(Front) G1 | LargePulseLaser@RightTorso(Front) G1 | LRM10@RightArm(Front) G2 | LRM10@RightArm(Front) G2,LeftTorsox1 | LeftArmx2 | RightTorsox2 | RightArmx2,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1),LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown),
Thor,Yes,Clan,19.000000,70.000000,FerroFiberus,Standard,20,Single,1,Yes,Yes,Yes,Yes,43,,1.1,1.1,1.2,1.2,1.4,1.4,1.5,0.5,0.25,9.65,7,"2x ClanMediumPulseLaser, ClanERPPC, 2x ClanMachineGun, ClanUltraAC10, CLANLRM10",ClanMediumPulseLaser@LeftTorso(Front) G1 | ClanMediumPulseLaser@RightTorso(Front) G1 | ClanERPPC@RightArm(Front) G1 | ClanMachineGun@LeftTorso(Front) G1 | ClanMachineGun@RightTorso(Front) G1 | ClanUltraAC10@LeftArm(Front) G1 | CLANLRM10@Special1(Side) G2,LeftTorsox2 | RightTorsox2 | RightArmx1 | LeftArmx1 | Special1x1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O10) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O2),LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown) | Special1(Side),
Uller,Yes,Clan,8.000000,30.000000,FerroFiberus,EndoSteel,8,Single,0,Yes,Yes,Yes,Yes,43,ECM,0.45,0.45,0.5,0.5,0.6,0.6,0.65,0.45,0.25,4.45,4,"ClanERSmallLaser, ClanERMediumLaser, ClanUltraAC5, ClanSRM6",ClanERSmallLaser@LeftArm(Front) G1 | ClanERMediumLaser@RightArm(Front) G1 | ClanUltraAC5@RightArm(Front) G1 | ClanSRM6@LeftArm(Front) G2,LeftArmx2 | RightArmx2,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1),LeftArm(Front) | RightArm(Front) | LeftTorso(Unknown) | RightTorso(Unknown) | CenterTorso(Unknown) | Head(Unknown),
Uziel,Yes,IS,11.500000,50.000000,Standard,EndoSteel,10,Single,1,Yes,Yes,Yes,Yes,45,,1.2,1.2,1.05,1.05,1.15,1.15,1.0,0.45,0.3,8.55,7,"2x SmallPulseLaser, PPC, 2x MachineGun, UltraAC5, LRM10",SmallPulseLaser@LeftTorso(Front) G1 | SmallPulseLaser@RightTorso(Front) G1 | PPC@LeftArm(Front) G1 | MachineGun@LeftTorso(Front) G1 | MachineGun@RightTorso(Front) G1 | UltraAC5@RightArm(Front) G1 | LRM10@Special1(Side) G2,LeftTorsox2 | RightTorsox2 | LeftArmx1 | RightArmx1 | Special1x1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O4),LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | Head(Unknown) | Special1(Side),
Victor,Yes,IS,17.000000,80.000000,Standard,EndoSteel,10,Single,1,Yes,Yes,Yes,Yes,43,ECM,1.3,1.3,1.3,1.3,1.25,1.25,1.65,1.1,0.3,10.75,7,"2x MediumLaser, 2x MachineGun, AC20, 2x SRM4",MediumLaser@LeftArm(Front) G1 | MediumLaser@LeftArm(Front) G1 | MachineGun@LeftTorso(Front) G1 | MachineGun@RightTorso(Front) G1 | AC20@RightArm(Front) G1 | SRM4@LeftTorso(Front) G2 | SRM4@RightTorso(Front) G2,LeftArmx2 | LeftTorsox2 | RightTorsox2 | RightArmx1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1),LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown),
Vulture,Yes,Clan,16.000000,60.000000,Reactive,EndoSteel,12,Single,0,No,Yes,Yes,Yes,43,BAP,1.3,1.3,1.5,1.5,1.6,1.6,1.75,0.5,0.3,11.35,10,"4x ClanMachineGun, 2x ClanLargePulseLaser, 2x ClanLRM5, 2x ClanLRM10",ClanMachineGun@LeftArm(Front) G1 | ClanMachineGun@Special1(Front) G1 | ClanMachineGun@Special1(Front) G1 | ClanMachineGun@RightArm(Front) G1 | ClanLargePulseLaser@LeftArm(Front) G1 | ClanLargePulseLaser@RightArm(Front) G1 | ClanLRM5@LeftTorso(Side) G2 | ClanLRM5@RightTorso(Side) G2 | ClanLRM10@LeftTorso(Side) G2 | ClanLRM10@RightTorso(Side) G2,LeftArmx2 | Special1x2 | RightArmx2 | LeftTorsox2 | RightTorsox2,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O2),LeftArm(Front) | RightArm(Front) | LeftTorso(Side) | RightTorso(Side) | Head(Unknown) | Special1(Front),
Warhammer,Yes,IS,15.000000,70.000000,Standard,Standard,17,Single,0,Yes,Yes,Yes,Yes,43,,1.55,1.55,1.45,1.45,1.5,1.5,1.7,0.75,0.3,11.75,5,"2x MediumLaser, 2x ERPPC, SRM6",MediumLaser@RightTorso(Front) G1 | MediumLaser@LeftTorso(Front) G1 | ERPPC@RightArm(Front) G1 | ERPPC@LeftArm(Front) G1 | SRM6@special2(Front) G2,RightTorsox1 | LeftTorsox1 | RightArmx1 | LeftArmx1 | special2x1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | Special2(M0/P0/B0/O2),LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | Special2(Unknown),
Wolfhound,Yes,Clan,10.250000,35.000000,FerroFiberus,EndoSteel,14,Single,0,Yes,Yes,Yes,Yes,43,ECM,0.5,0.5,0.7,0.7,0.75,0.75,0.95,0.5,0.25,5.6,5,"3x ClanMediumPulseLaser, ClanERMediumLaser, ClanERLargeLaser",ClanMediumPulseLaser@LeftTorso(Front) G1 | ClanMediumPulseLaser@CenterTorso(Front) G1 | ClanMediumPulseLaser@RightTorso(Front) G1 | ClanERMediumLaser@CenterTorso(Rear) G1 | ClanERLargeLaser@RightArm(Front) G1,LeftTorsox1 | CenterTorsox2 | RightTorsox1 | RightArmx1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1),LeftArm(Unknown) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Front+Rear) | Head(Unknown),
Zeus,Yes,IS,22.000000,80.000000,FerroFiberus,Standard,22,Single,0,Yes,Yes,Yes,Yes,43,,1.1,1.1,1.25,1.25,1.45,1.45,1.55,0.8,0.25,10.2,7,"4x MediumPulseLaser, ERLargeLaser, ERPPC, LRM15",MediumPulseLaser@LeftTorso(Front) G1 | MediumPulseLaser@RightTorso(Front) G1 | MediumPulseLaser@RightArm(Front) G1 | MediumPulseLaser@RightTorso(Rear) G1 | ERLargeLaser@CenterTorso(Front) G1 | ERPPC@LeftArm(Front) G1 | LRM15@RightArm(Front) G2,LeftTorsox1 | RightTorsox2 | RightArmx2 | CenterTorsox1 | LeftArmx1,LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1),LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front+Rear) | CenterTorso(Front) | Head(Unknown),
jenner2c,No,Clan,10.000000,35.000000,FerroFiberus,Standard,0,,0,Yes,Yes,No,No,,,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.9,0,,,,LeftArm(M2/P0/B2/O0) | RightArm(M2/P0/B2/O0) | Special1(M3/P0/B0/O0),LeftArm(Unknown) | RightArm(Unknown) | Special1(Unknown),"not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud"
koto,No,IS,7.000000,25.000000,FerroFiberus,EndoSteel,0,,0,No,Yes,No,No,,,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.9,0,,,,LeftArm(M0/P1/B1/O0) | RightArm(M0/P1/B1/O0) | CenterTorso(M0/P0/B2/O0) | Special1(M0/P0/B3/O0),LeftArm(Unknown) | RightArm(Unknown) | CenterTorso(Unknown) | Special1(Unknown),"not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud"
locust2c,No,Clan,7.000000,25.000000,FerroFiberus,EndoSteel,0,,0,No,Yes,No,No,4,,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.9,0,,,,LeftArm(M0/P0/B1/O2) | RightArm(M0/P0/B1/O2) | Special1(M0/P0/B3/O0),LeftArm(Unknown) | RightArm(Unknown) | Special1(Unknown),"not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud"
marauder2,No,IS,22.000000,100.000000,FerroFiberus,EndoSteel,0,,0,Yes,No,Yes,No,6,,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.9,0,,,,LeftArm(M0/P0/B4/O1) | RightArm(M0/P0/B4/O1) | LeftTorso(M0/P0/B1/O1) | RightTorso(M0/P0/B1/O1) | Special1(M0/P7/B0/O0) | Special2(M0/P0/B0/O2),LeftArm(Unknown) | RightArm(Unknown) | LeftTorso(Unknown) | RightTorso(Unknown) | Special1(Unknown) | Special2(Unknown),"not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud"
pitbull,No,Clan,15.000000,70.000000,FerroFiberus,EndoSteel,0,,0,Yes,No,No,No,,,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.9,0,,,,LeftArm(M0/P2/B2/O0) | RightArm(M0/P2/B2/O0) | LeftTorso(M0/P0/B2/O0) | RightTorso(M0/P0/B2/O0) | Special1(M0/P4/B0/O0),LeftArm(Unknown) | RightArm(Unknown) | LeftTorso(Unknown) | RightTorso(Unknown) | Special1(Unknown),"not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud"
privateer,No,IS,12.500000,55.000000,FerroFiberus,Standard,0,,0,No,No,Yes,No,2,,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.9,0,,,,LeftArm(M0/P1/B0/O1) | RightArm(M0/P1/B0/O1) | LeftTorso(M0/P2/B2/O0) | RightTorso(M0/P0/B1/O0) | Special1(M4/P0/B0/O0),LeftArm(Unknown) | RightArm(Unknown) | LeftTorso(Unknown) | RightTorso(Unknown) | Special1(Unknown),"not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud"
razorback,No,IS,9.000000,30.000000,FerroFiberus,EndoSteel,0,,0,No,Yes,No,No,,,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.9,0,,,,LeftArm(M2/P0/B2/O0) | RightArm(M0/P0/B3/O0) | Special1(M0/P2/B0/O0) | Special2(M0/P2/B0/O0),LeftArm(Unknown) | RightArm(Unknown) | Special1(Unknown) | Special2(Unknown),"not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud"
reaper,No,Clan,16.500000,75.000000,FerroFiberus,EndoSteel,0,,0,Yes,Yes,No,No,,,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.9,0,,,,LeftArm(M0/P0/B3/O0) | RightArm(M0/P0/B3/O0) | LeftTorso(M0/P0/B2/O0) | RightTorso(M0/P0/B2/O0) | CenterTorso(M0/P6/B0/O0),LeftArm(Unknown) | RightArm(Unknown) | LeftTorso(Unknown) | RightTorso(Unknown) | CenterTorso(Unknown),"not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud"
reaver,No,Clan,10.000000,40.000000,FerroFiberus,EndoSteel,0,,0,Yes,No,Yes,No,,,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.9,0,,,,LeftArm(M0/P0/B3/O0) | RightArm(M0/P0/B3/O0) | LeftTorso(M0/P0/B1/O0) | RightTorso(M0/P0/B1/O0),LeftArm(Unknown) | RightArm(Unknown) | LeftTorso(Unknown) | RightTorso(Unknown),"not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud"
shadowhawk,No,IS,12.500000,55.000000,FerroFiberus,Standard,0,,0,Yes,Yes,No,No,,,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.9,0,,,,LeftArm(M0/P1/B2/O0) | RightArm(M0/P0/B3/O0) | LeftTorso(M0/P0/B1/O0) | RightTorso(M0/P0/B1/O0) | Special1(M0/P2/B0/O0) | Special2(M2/P0/B0/O0),LeftArm(Unknown) | RightArm(Unknown) | LeftTorso(Unknown) | RightTorso(Unknown) | Special1(Unknown) | Special2(Unknown),"not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud"
strider,No,IS,11.000000,40.000000,FerroFiberus,Standard,0,,0,No,No,Yes,No,4,,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.9,0,,,,LeftArm(M2/P0/B0/O0) | RightArm(M2/P0/B0/O0) | LeftTorso(M0/P0/B0/O2) | RightTorso(M0/P0/B0/O2) | CenterTorso(M0/P0/B2/O0),LeftArm(Unknown) | RightArm(Unknown) | LeftTorso(Unknown) | RightTorso(Unknown) | CenterTorso(Unknown),"not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud"
urbanmech,Yes,IS,5.000000,30.000000,Standard,Standard,8,Single,0,Yes,Yes,No,No,50,,0.45,0.45,0.5,0.5,0.6,0.6,0.65,0.45,0.25,4.45,2,"SmallLaser, AC20",SmallLaser@LeftArm(Front) G1 | AC20@RightArm(Front) G1,LeftArmx1 | RightArmx1,LeftArm(M0/P0/B0/O12) | RightArm(M0/P0/B0/O12) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2),LeftArm(Front) | RightArm(Front) | LeftTorso(Unknown) | RightTorso(Unknown) | CenterTorso(Unknown),
urbanmech_iic,No,Clan,5.000000,30.000000,FerroFiberus,Standard,0,,0,Yes,Yes,No,No,,,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.9,0,,,,LeftArm(M0/P2/B2/O0) | RightArm(M0/P0/B4/O0) | LeftTorso(M0/P1/B0/O0) | RightTorso(M0/P1/B0/O0),LeftArm(Unknown) | RightArm(Unknown) | LeftTorso(Unknown) | RightTorso(Unknown),"not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud"
ursus,No,Clan,10.500000,50.000000,FerroFiberus,Standard,0,,0,No,Yes,No,No,3,,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.9,0,,,,LeftArm(M0/P0/B0/O3) | RightArm(M0/P0/B4/O0) | CenterTorso(M2/P0/B0/O0) | Special1(M0/P0/B1/O0) | Special2(M0/P0/B1/O0),LeftArm(Unknown) | RightArm(Unknown) | CenterTorso(Unknown) | Special1(Unknown) | Special2(Unknown),"not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud"
vulture2,No,Clan,16.500000,75.000000,FerroFiberus,EndoSteel,0,,0,No,Yes,No,No,5,,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.9,0,,,,LeftArm(M0/P3/B0/O0) | RightArm(M0/P0/B0/O3) | LeftTorso(M2/P0/B2/O0) | RightTorso(M2/P0/B2/O0) | Special1(M0/P0/B0/O2) | Special2(M0/P0/B2/O0),LeftArm(Unknown) | RightArm(Unknown) | LeftTorso(Unknown) | RightTorso(Unknown) | Special1(Unknown) | Special2(Unknown),"not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud"
vulturec,No,Clan,14.000000,60.000000,FerroFiberus,Standard,0,,0,No,Yes,No,No,3,,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.9,0,,,,LeftArm(M0/P3/B0/O0) | RightArm(M0/P3/B0/O0) | LeftTorso(M2/P0/B0/O0) | RightTorso(M2/P0/B0/O0) | CenterTorso(M0/P0/B0/O1) | Special1(M0/P0/B0/O1) | Special2(M0/P0/B0/O1),LeftArm(Unknown) | RightArm(Unknown) | LeftTorso(Unknown) | RightTorso(Unknown) | CenterTorso(Unknown) | Special1(Unknown) | Special2(Unknown),"not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud"
1 Mech In_game_playable Tech Chassis_Tonnage Max_Loadout_Tonnage Armor_Type Internal_Type Heatsinks Heatsink_Type JumpJets_Installed CanLoad_JJ CanLoad_ECM CanLoad_BAP CanLoad_AMS OmniSlots Equipment Armor_LeftArm Armor_RightArm Armor_LeftLeg Armor_RightLeg Armor_LeftFrontTorso Armor_RightFrontTorso Armor_CenterFrontTorso Armor_CenterRearTorso Armor_Head Total_Armor_Multiplier Weapon_Count Weapons_Summary Weapons_With_Locations Default_Installed_Locations Available_Slot_Capacity_By_Zone Available_Hardpoints notes
2 Annihilator Yes IS 23.000000 100.000000 Reflective EndoSteel 17 Single 0 No Yes Yes Yes 43 1.8 1.8 1.8 1.8 1.85 1.85 2.0 0.8 0.3 14 10 4x ClanERSmallLaser, 2x ClanMachineGun, 4x ClanUltraAC5 ClanERSmallLaser@LeftTorso(Front) G1 | ClanERSmallLaser@CenterTorso(Front) G1 | ClanERSmallLaser@CenterTorso(Front) G1 | ClanERSmallLaser@RightTorso(Front) G1 | ClanMachineGun@LeftTorso(Front) G1 | ClanMachineGun@RightTorso(Front) G1 | ClanUltraAC5@LeftArm(Front) G1 | ClanUltraAC5@LeftArm(Front) G1 | ClanUltraAC5@RightArm(Front) G1 | ClanUltraAC5@RightArm(Front) G1 LeftTorsox2 | CenterTorsox2 | RightTorsox2 | LeftArmx2 | RightArmx2 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Front) | Head(Unknown)
3 Archer Yes IS 17.000000 70.000000 Standard Standard 20 Single 1 Yes Yes Yes Yes 43 1.1 1.1 1.2 1.2 1.4 1.4 1.5 0.5 0.3 9.7 9 4x MediumPulseLaser, 2x SSRM2, 2x LRM15, NarcBeacon MediumPulseLaser@LeftArm(Front) G1 | MediumPulseLaser@CenterTorso(Front) G1 | MediumPulseLaser@CenterTorso(Front) G1 | MediumPulseLaser@RightArm(Front) G1 | SSRM2@LeftArm(Front) G2 | SSRM2@RightArm(Front) G2 | LRM15@LeftTorso(Side) G2 | LRM15@RightTorso(Side) G2 | NarcBeacon@LeftTorso(Front) G3 LeftArmx2 | CenterTorsox2 | RightArmx2 | LeftTorsox2 | RightTorsox1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) LeftArm(Front) | RightArm(Front) | LeftTorso(Front+Side) | RightTorso(Side) | CenterTorso(Front) | Head(Unknown)
4 ArcticWolf Yes Clan 9.500000 40.000000 FerroFiberus EndoSteel 8 Single 1 Yes Yes Yes Yes 43 0.7 0.7 0.95 0.95 0.85 0.85 1.0 0.2 0.3 6.5 6 2x ClanSmallPulseLaser, 4x ClanSSRM4 ClanSmallPulseLaser@RightTorso(Front) G1 | ClanSmallPulseLaser@RightTorso(Front) G1 | ClanSSRM4@leftarm(Front) G2 | ClanSSRM4@special1(Front) G2 | ClanSSRM4@special2(Front) G2 | ClanSSRM4@rightarm(Front) G2 RightTorsox2 | leftarmx1 | special1x1 | special2x1 | rightarmx1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O8) | RightTorso(M0/P0/B0/O8) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O4) | Special2(M0/P0/B0/O4) LeftArm(Unknown) | RightArm(Unknown) | LeftTorso(Unknown) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown) | Special1(Unknown) | Special2(Unknown)
5 Ares Yes Clan 15.500000 60.000000 FerroFiberus Standard 15 Single 0 Yes Yes Yes Yes 46 0.9 0.9 1.15 1.15 1.1 1.1 1.45 0.9 0.25 8.9 9 2x ClanERSmallLaser, 3x ClanERMediumLaser, ClanERLargeLaser, 3x ClanLRM10 ClanERSmallLaser@Special1(Front) G1 | ClanERSmallLaser@Special1(Front) G1 | ClanERMediumLaser@LeftArm(Front) G1 | ClanERMediumLaser@RightArm(Front) G1 | ClanERMediumLaser@RightArm(Front) G1 | ClanERLargeLaser@LeftArm(Front) G1 | ClanLRM10@Special2(Side) G2 | ClanLRM10@Special2(Side) G2 | ClanLRM10@Special2(Side) G2 Special1x2 | LeftArmx2 | RightArmx2 | Special2x3 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O2) | Special2(M0/P0/B0/O3) LeftArm(Front) | RightArm(Front) | LeftTorso(Unknown) | RightTorso(Unknown) | Head(Unknown) | Special1(Front) | Special2(Side)
6 Argus Yes IS 14.500000 60.000000 Standard Standard 13 Single 0 No Yes Yes Yes 43 0.7 0.7 1.15 1.15 0.85 0.85 1.45 0.9 0.3 8.05 9 3x MediumLaser, PPC, 4x MachineGun, LRM10 MediumLaser@Lefttorso(Front) G1 | MediumLaser@Righttorso(Front) G1 | MediumLaser@RightArm(Front) G1 | PPC@RightArm(Front) G1 | MachineGun@LeftTorso(Front) G1 | MachineGun@CenterTorso(Front) G1 | MachineGun@CenterTorso(Front) G1 | MachineGun@RightTorso(Front) G1 | LRM10@LeftArm(Front) G2 Lefttorsox1 | Righttorsox1 | RightArmx2 | LeftTorsox1 | CenterTorsox2 | RightTorsox1 | LeftArmx1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Front) | Head(Unknown)
7 Assassin2 Yes IS 12.000000 45.000000 FerroFiberus EndoSteel 6 Single 0 Yes Yes Yes Yes 40 0.85 0.85 0.85 0.85 0.9 0.9 1.05 0.45 0.25 6.95 7 2x SmallLaser, 2x MediumLaser, 2x SRM4, LRM5 SmallLaser@LeftArm(Front) G1 | SmallLaser@RightArm(Front) G1 | MediumLaser@LeftArm(Front) G1 | MediumLaser@RightArm(Front) G1 | SRM4@LeftTorso(Front) G2 | SRM4@RightTorso(Front) G2 | LRM5@Special1(Side) G2 LeftArmx2 | RightArmx2 | LeftTorsox1 | RightTorsox1 | Special1x1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O10) | Special1(M0/P0/B0/O2) LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | Special1(Side)
8 Atlas Yes IS 28.000000 100.000000 Standard Standard 17 Single 0 No Yes Yes Yes 43 1.95 1.95 2.15 2.15 2.45 2.45 2.2 1.1 0.3 16.7 9 4x MediumLaser, AC20, 2x SSRM2, SRM6, LRM20 MediumLaser@LeftArm(Front) G1 | MediumLaser@Head(Front) G1 | MediumLaser@CenterTorso(Front) G1 | MediumLaser@RightArm(Front) G1 | AC20@Special1(Front) G1 | SSRM2@LeftTorso(Front) G2 | SSRM2@RightTorso(Front) G2 | SRM6@Special2(Front) G2 | LRM20@LeftTorso(Side) G2 LeftArmx1 | Headx1 | CenterTorsox1 | RightArmx1 | Special1x1 | LeftTorsox2 | RightTorsox1 | Special2x1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O10) | RightTorso(M0/P0/B0/O8) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O4) | Special2(M0/P0/B0/O2) LeftArm(Front) | RightArm(Front) | LeftTorso(Front+Side) | RightTorso(Front) | CenterTorso(Front) | Head(Front) | Special1(Front) | Special2(Front)
9 Avatar Yes IS 17.000000 70.000000 Reactive EndoSteel 12 Single 0 Yes Yes Yes Yes 43 1.3 1.3 1.5 1.5 1.6 1.6 1.75 0.5 0.3 11.35 10 4x MachineGun, 2x LargeLaser, 2x LRM5, 2x LRM10 MachineGun@LeftArm(Front) G1 | MachineGun@Special1(Front) G1 | MachineGun@Special1(Front) G1 | MachineGun@RightArm(Front) G1 | LargeLaser@LeftArm(Front) G1 | LargeLaser@RightArm(Front) G1 | LRM5@LeftTorso(Side) G2 | LRM5@RightTorso(Side) G2 | LRM10@LeftTorso(Side) G2 | LRM10@RightTorso(Side) G2 LeftArmx2 | Special1x2 | RightArmx2 | LeftTorsox2 | RightTorsox2 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O2) LeftArm(Front) | RightArm(Front) | LeftTorso(Side) | RightTorso(Side) | Head(Unknown) | Special1(Front)
10 Awesome Yes IS 23.000000 80.000000 Standard Standard 28 Single 0 No Yes Yes Yes 43 1.45 1.45 1.55 1.55 1.65 1.65 1.75 1.25 0.3 12.6 6 SmallPulseLaser, 3x ERPPC, UltraAC5, LRM5 SmallPulseLaser@Head(Front) G1 | ERPPC@Lefttorso(Front) G1 | ERPPC@righttorso(Front) G1 | ERPPC@RightArm(Front) G1 | UltraAC5@LeftArm(Front) G1 | LRM5@CenterTorso(Side) G2 Headx1 | Lefttorsox1 | righttorsox1 | RightArmx1 | LeftArmx1 | CenterTorsox1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) LeftArm(Front) | RightArm(Front) | LeftTorso(Unknown) | RightTorso(Unknown) | CenterTorso(Side) | Head(Front)
11 Battlemaster Yes IS 20.500000 85.000000 Standard EndoSteel 25 Single 0 No Yes Yes Yes 43 1.45 1.45 1.6 1.6 1.8 1.8 2.05 0.95 0.3 13 10 PPC, 6x MediumLaser, 2x MachineGun, SRM6 PPC@Special2(Front) G1 | MediumLaser@RightTorso(Front) G1 | MediumLaser@RightTorso(Front) G1 | MediumLaser@RightTorso(Rear) G1 | MediumLaser@LeftTorso(Front) G1 | MediumLaser@LeftTorso(Front) G1 | MediumLaser@LeftTorso(Rear) G1 | MachineGun@LeftArm(Front) G1 | MachineGun@LeftArm(Front) G1 | SRM6@Special1(Front) G2 Special2x1 | RightTorsox3 | LeftTorsox3 | LeftArmx2 | Special1x1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O4) | LeftTorso(M0/P0/B0/O9) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O3) | Special2(M0/P0/B0/O4) LeftArm(Front) | RightArm(Unknown) | LeftTorso(Front+Rear) | RightTorso(Front+Rear) | CenterTorso(Unknown) | Head(Unknown) | Special1(Front) | Special2(Front)
12 Battlemaster2c Yes Clan 15.500000 85.000000 Standard EndoSteel 25 Single 0 No Yes Yes Yes 39 1.45 1.45 1.6 1.6 1.8 1.8 2.05 0.95 0.3 13 10 ClanERPPC, 6x ClanERMediumLaser, 2x ClanGaussRifle, ClanSSRM6 ClanERPPC@RightArm(Front) G1 | ClanERMediumLaser@RightTorso(Front) G1 | ClanERMediumLaser@RightTorso(Front) G1 | ClanERMediumLaser@RightTorso(Rear) G1 | ClanERMediumLaser@LeftTorso(Front) G1 | ClanERMediumLaser@LeftTorso(Front) G1 | ClanERMediumLaser@LeftTorso(Rear) G1 | ClanGaussRifle@LeftArm(Front) G1 | ClanGaussRifle@LeftArm(Front) G1 | ClanSSRM6@Special1(Front) G2 RightArmx1 | RightTorsox3 | LeftTorsox3 | LeftArmx2 | Special1x1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O4) | LeftTorso(M0/P0/B0/O9) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O3) LeftArm(Front) | RightArm(Front) | LeftTorso(Front+Rear) | RightTorso(Front+Rear) | CenterTorso(Unknown) | Head(Unknown) | Special1(Front)
13 Behemoth Yes Clan 22.000000 100.000000 Standard Standard 21 Single 1 Yes Yes Yes Yes 43 1.95 1.95 2.15 2.15 2.45 2.45 2.2 1.1 0.3 16.7 7 4x ClanLargePulseLaser, 2x ClanGaussRifle, LargeLaser ClanLargePulseLaser@LeftTorso(Front) G1 | ClanLargePulseLaser@LeftTorso(Front) G1 | ClanLargePulseLaser@RightTorso(Front) G1 | ClanLargePulseLaser@RightTorso(Front) G1 | ClanGaussRifle@LeftArm(Front) G1 | ClanGaussRifle@RightArm(Front) G1 | LargeLaser@Special1(Front) G1 LeftTorsox2 | RightTorsox2 | LeftArmx1 | RightArmx1 | Special1x1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O2) LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | Head(Unknown) | Special1(Front)
14 Behemoth2 Yes Clan 22.000000 100.000000 Standard Standard 21 Single 1 Yes Yes Yes Yes 43 1.95 1.95 2.15 2.15 2.45 2.45 2.2 1.1 0.3 16.7 7 4x ClanLargePulseLaser, 2x ClanGaussRifle, LargeLaser ClanLargePulseLaser@LeftTorso(Front) G1 | ClanLargePulseLaser@LeftTorso(Front) G1 | ClanLargePulseLaser@RightTorso(Front) G1 | ClanLargePulseLaser@RightTorso(Front) G1 | ClanGaussRifle@LeftArm(Front) G1 | ClanGaussRifle@RightArm(Front) G1 | LargeLaser@Special1(Front) G1 LeftTorsox2 | RightTorsox2 | LeftArmx1 | RightArmx1 | Special1x1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O2) LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | Head(Unknown) | Special1(Front)
15 Blackhawk Yes Clan 10.000000 50.000000 FerroFiberus EndoSteel 12 Single 0 Yes Yes Yes Yes 43 0.9 0.9 0.95 0.95 1.05 1.05 1.2 0.55 0.25 7.8 4 2x ClanMediumPulseLaser, 2x ClanERPPC ClanMediumPulseLaser@LeftTorso(Front) G1 | ClanMediumPulseLaser@RightTorso(Front) G1 | ClanERPPC@LeftArm(Front) G1 | ClanERPPC@RightArm(Front) G1 LeftTorsox1 | RightTorsox1 | LeftArmx1 | RightArmx1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O10) | RightTorso(M0/P0/B0/O10) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O2) | Special2(M0/P0/B0/O2) LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown) | Special1(Unknown) | Special2(Unknown)
16 Blackheart No Clan 14.000000 70.000000 FerroFiberus Standard 0 0 No Yes No No 6 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.9 0 LeftArm(M0/P3/B0/O0) | RightArm(M0/P3/B0/O0) | LeftTorso(M0/P0/B1/O2) | RightTorso(M0/P0/B1/O2) | CenterTorso(M0/P0/B0/O2) LeftArm(Unknown) | RightArm(Unknown) | LeftTorso(Unknown) | RightTorso(Unknown) | CenterTorso(Unknown) not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud
17 Blacklanner Yes Clan 12.500000 55.000000 FerroFiberus EndoSteel 10 Single 0 No Yes Yes Yes 40 ECM 0.9 0.9 1.0 1.0 1.05 1.05 1.15 0.75 0.25 8.05 5 2x ClanERMediumLaser, ClanERLargeLaser, ClanSRM6, ClanLRM10 ClanERMediumLaser@LeftArm(Front) G1 | ClanERMediumLaser@LeftArm(Front) G1 | ClanERLargeLaser@RightArm(Front) G1 | ClanSRM6@Special2(Side) G2 | ClanLRM10@Special1(Side) G2 LeftArmx2 | RightArmx1 | Special2x1 | Special1x1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | Special1(M0/P0/B0/O12) | Special2(M0/P0/B0/O12) LeftArm(Front) | RightArm(Front) | Special1(Side) | Special2(Side)
18 Blacknight Yes IS 16.000000 75.000000 Standard Standard 22 Single 0 Yes Yes Yes Yes 43 1.2 1.2 1.4 1.4 1.55 1.55 1.8 0.8 0.3 11.2 8 SmallLaser, 4x MediumLaser, 2x LargeLaser, PPC SmallLaser@Head(Front) G1 | MediumLaser@LeftArm(Front) G1 | MediumLaser@LeftTorso(Front) G1 | MediumLaser@RightTorso(Front) G1 | MediumLaser@RightArm(Front) G1 | LargeLaser@LeftTorso(Front) G1 | LargeLaser@RightTorso(Front) G1 | PPC@RightArm(Front) G1 Headx1 | LeftArmx1 | LeftTorsox2 | RightTorsox2 | RightArmx2 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Front)
19 Bowman No Clan 16.000000 70.000000 FerroFiberus Standard 0 0 No Yes Yes No 5 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.9 0 LeftArm(M0/P2/B2/O2) | RightArm(M4/P0/B0/O0) | Special1(M4/P0/B0/O0) | Special2(M0/P0/B0/O3) LeftArm(Unknown) | RightArm(Unknown) | Special1(Unknown) | Special2(Unknown) not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud
20 Brigand Yes IS 7.000000 25.000000 FerroFiberus Standard 10 Single 0 Yes Yes Yes Yes 40 0.45 0.45 0.45 0.45 0.55 0.55 0.55 0.4 0.25 4.1 4 2x MediumPulseLaser, 2x MediumLaser MediumPulseLaser@LeftArm(Front) G1 | MediumPulseLaser@RightArm(Front) G1 | MediumLaser@Special2(Front) G1 | MediumLaser@Special1(Front) G1 LeftArmx1 | RightArmx1 | Special2x1 | Special1x1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | Special1(M0/P0/B0/O12) | Special2(M0/P0/B0/O12) LeftArm(Front) | RightArm(Front) | Special1(Front) | Special2(Front)
21 Bushwacker Yes IS 15.500000 55.000000 FerroFiberus Standard 11 Single 0 No Yes Yes Yes 43 0.9 0.9 1.1 1.1 1.15 1.15 1.35 0.5 0.25 8.4 8 2x MediumLaser, ERLargeLaser, 2x MachineGun, AC10, 2x LRM5 MediumLaser@CenterTorso(Front) G1 | MediumLaser@CenterTorso(Front) G1 | ERLargeLaser@RightArm(Front) G1 | MachineGun@LeftTorso(Front) G1 | MachineGun@RightTorso(Front) G1 | AC10@LeftArm(Front) G1 | LRM5@Special1(Side) G2 | LRM5@Special1(Side) G2 CenterTorsox2 | RightArmx1 | LeftTorsox1 | RightTorsox1 | LeftArmx1 | Special1x2 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O8) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O4) LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Front) | Head(Unknown) | Special1(Side)
22 Canis No Clan 15.000000 80.000000 FerroFiberus EndoSteel 0 0 Yes No No No 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.9 0 LeftArm(M0/P0/B5/O0) | RightArm(M0/P0/B5/O0) | Special1(M0/P3/B0/O0) | Special2(M0/P3/B0/O0) LeftArm(Unknown) | RightArm(Unknown) | Special1(Unknown) | Special2(Unknown) not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud
23 Catapult Yes IS 15.000000 65.000000 Reactive Standard 10 Single 1 Yes Yes Yes Yes 43 BAP 1.45 1.45 1.35 1.35 1.45 1.45 1.5 0.65 0.3 10.95 4 2x LargeLaser, 2x LRM20 LargeLaser@LeftTorso(Front) G1 | LargeLaser@RightTorso(Front) G1 | LRM20@LeftArm(Side) G2 | LRM20@RightArm(Side) G2 LeftTorsox1 | RightTorsox1 | LeftArmx1 | RightArmx1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) LeftArm(Side) | RightArm(Side) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown)
24 CauldronBorn Yes Clan 13.500000 65.000000 FerroFiberus EndoSteel 13 Single 0 Yes Yes Yes Yes 43 0.85 0.85 0.95 0.95 1.15 1.15 1.55 0.85 0.25 8.55 6 ClanERMediumLaser, ClanUltraAC5, ClanGaussRifle, ClanSSRM2, 2x ClanLRM10 ClanERMediumLaser@LeftTorso(Front) G1 | ClanUltraAC5@LeftArm(Front) G1 | ClanGaussRifle@RightArm(Front) G1 | ClanSSRM2@RightTorso(Front) G2 | ClanLRM10@Special1(Side) G2 | ClanLRM10@Special2(Side) G2 LeftTorsox1 | LeftArmx1 | RightArmx1 | RightTorsox1 | Special1x1 | Special2x1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O8) | RightTorso(M0/P0/B0/O8) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O4) | Special2(M0/P0/B0/O4) LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown) | Special1(Side) | Special2(Side)
25 Chimera Yes IS 9.500000 40.000000 Standard EndoSteel 14 Single 1 Yes Yes Yes Yes 43 BAP 0.95 0.95 1.0 1.0 1.0 1.0 1.1 0.5 0.3 7.8 7 2x MediumPulseLaser, ERLargeLaser, 4x LRM5 MediumPulseLaser@LeftArm(Front) G1 | MediumPulseLaser@LeftArm(Front) G1 | ERLargeLaser@RightArm(Front) G1 | LRM5@RightTorso(Side) G2 | LRM5@RightTorso(Side) G2 | LRM5@RightTorso(Side) G2 | LRM5@RightTorso(Side) G2 LeftArmx2 | RightArmx1 | RightTorsox4 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) LeftArm(Front) | RightArm(Front) | LeftTorso(Unknown) | RightTorso(Side) | CenterTorso(Unknown) | Head(Unknown)
26 Commando Yes IS 7.000000 25.000000 Standard Standard 8 Single 0 Yes Yes Yes Yes 43 0.6 0.6 0.8 0.8 0.75 0.75 0.8 0.45 0.3 5.85 3 2x MediumLaser, SRM6 MediumLaser@LeftArm(Front) G1 | MediumLaser@RightArm(Front) G1 | SRM6@CenterTorso(Front) G2 LeftArmx1 | RightArmx1 | CenterTorsox1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) LeftArm(Front) | RightArm(Front) | LeftTorso(Unknown) | RightTorso(Unknown) | CenterTorso(Front) | Head(Unknown)
27 Cougar Yes Clan 8.500000 35.000000 FerroFiberus EndoSteel 10 Single 1 Yes Yes Yes Yes 43 BAP 0.7 0.7 0.7 0.7 0.75 0.75 0.8 0.45 0.25 5.8 5 2x ClanMediumPulseLaser, ClanMachineGun, 2x ClanLRM10 ClanMediumPulseLaser@LeftArm(Front) G1 | ClanMediumPulseLaser@RightArm(Front) G1 | ClanMachineGun@RightTorso(Front) G1 | ClanLRM10@LeftTorso(Side) G2 | ClanLRM10@RightTorso(Side) G2 LeftArmx1 | RightArmx1 | RightTorsox2 | LeftTorsox1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) LeftArm(Front) | RightArm(Front) | LeftTorso(Side) | RightTorso(Front+Side) | CenterTorso(Unknown) | Head(Unknown)
28 Crab No IS 10.500000 50.000000 FerroFiberus Standard 0 0 No No Yes No 1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.9 0 LeftArm(M0/P0/B4/O0) | RightArm(M0/P0/B4/O0) | CenterTorso(M0/P0/B2/O0) | Special1(M0/P0/B1/O1) LeftArm(Unknown) | RightArm(Unknown) | CenterTorso(Unknown) | Special1(Unknown) not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud
29 Cyclops Yes IS 19.000000 90.000000 FerroFiberus Standard 16 Single 0 No Yes Yes Yes 45 BAP 1.4 1.4 1.4 1.4 1.55 1.55 1.45 0.8 0.25 11.2 8 3x MediumPulseLaser, 2x MediumLaser, GaussRifle, SRM4, LRM10 MediumPulseLaser@LeftArm(Front) G1 | MediumPulseLaser@Special1(Front) G1 | MediumPulseLaser@RightArm(Front) G1 | MediumLaser@LeftArm(Front) G1 | MediumLaser@RightArm(Front) G1 | GaussRifle@RightTorso(Front) G1 | SRM4@CenterTorso(Front) G2 | LRM10@LeftTorso(Side) G2 LeftArmx2 | Special1x1 | RightArmx2 | RightTorsox1 | CenterTorsox1 | LeftTorsox1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O2) LeftArm(Front) | RightArm(Front) | LeftTorso(Side) | RightTorso(Front) | CenterTorso(Front) | Head(Unknown) | Special1(Front)
30 Daishi Yes Clan 25.000000 100.000000 Standard Standard 21 Single 0 No Yes Yes Yes 43 1.75 1.75 1.9 1.9 2.0 2.0 2.2 1.5 0.3 15.3 6 3x ClanLargePulseLaser, ClanGaussRifle, 2x ClanSSRM6 ClanLargePulseLaser@RightArm(Front) G1 | ClanLargePulseLaser@RightArm(Front) G1 | ClanLargePulseLaser@RightArm(Front) G1 | ClanGaussRifle@LeftArm(Front) G1 | ClanSSRM6@special1(Front) G2 | ClanSSRM6@special1(Front) G2 RightArmx3 | LeftArmx1 | special1x2 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O8) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O4) LeftArm(Front) | RightArm(Front) | LeftTorso(Unknown) | RightTorso(Unknown) | CenterTorso(Unknown) | Head(Unknown) | Special1(Unknown)
31 Deimos Yes Clan 18.000000 85.000000 Reactive EndoSteel 17 Single 0 No Yes Yes Yes 43 1.55 1.55 1.65 1.65 1.75 1.75 2.05 0.7 0.3 12.95 10 2x ClanERMediumLaser, 6x ClanUltraAC2, 2x ClanLRM15 ClanERMediumLaser@LeftTorso(Front) G1 | ClanERMediumLaser@RightTorso(Front) G1 | ClanUltraAC2@LeftArm(Front) G1 | ClanUltraAC2@LeftArm(Front) G1 | ClanUltraAC2@LeftArm(Front) G1 | ClanUltraAC2@RightArm(Front) G1 | ClanUltraAC2@RightArm(Front) G1 | ClanUltraAC2@RightArm(Front) G1 | ClanLRM15@Special1(Side) G2 | ClanLRM15@Special2(Side) G2 LeftTorsox1 | RightTorsox1 | LeftArmx3 | RightArmx3 | Special1x1 | Special2x1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O9) | RightTorso(M0/P0/B0/O9) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O3) | Special2(M0/P0/B0/O3) LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown) | Special1(Side) | Special2(Side)
32 Dragon Yes Clan 17.000000 60.000000 Standard Standard 13 Single 0 Yes Yes Yes Yes 43 1.15 1.15 1.4 1.4 1.25 1.25 1.55 0.9 0.3 10.35 5 3x MediumLaser, ERPPC, LRM10 MediumLaser@LeftArm(Front) G1 | MediumLaser@LeftTorso(Front) G1 | MediumLaser@RightTorso(Front) G1 | ERPPC@RightArm(Front) G1 | LRM10@CenterTorso(Side) G2 LeftArmx1 | LeftTorsox1 | RightTorsox1 | RightArmx1 | CenterTorsox1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Side) | Head(Unknown)
33 Duangung No IS 7.000000 25.000000 FerroFiberus Standard 0 0 Yes No No No 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.9 0 LeftArm(M0/P0/B2/O0) | RightArm(M0/P0/B2/O0) | CenterTorso(M2/P0/B0/O0) | Special1(M0/P0/B1/O0) | Special2(M0/P0/B1/O0) LeftArm(Unknown) | RightArm(Unknown) | CenterTorso(Unknown) | Special1(Unknown) | Special2(Unknown) not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud
34 Fafnir Yes IS 21.000000 100.000000 FerroFiberus Standard 7 Single 0 No Yes No No 43 1.8 1.8 1.9 1.9 2.0 2.0 2.2 1.0 0.3 14.9 7 2x ClanGaussRifle, 2x LargeLaser, 3x MediumLaser ClanGaussRifle@RightTorso(Front) G1 | ClanGaussRifle@LeftTorso(Front) G1 | LargeLaser@RightArm(Front) G1 | LargeLaser@LeftArm(Front) G1 | MediumLaser@RightTorso(Front) G1 | MediumLaser@CenterTorso(Front) G1 | MediumLaser@LeftTorso(Front) G1 RightTorsox2 | LeftTorsox2 | RightArmx1 | LeftArmx1 | CenterTorsox1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Front) | Head(Unknown)
35 Flea Yes IS 7.000000 20.000000 Standard Standard 2 Single 0 No Yes Yes Yes 43 0.4 0.4 0.4 0.4 0.5 0.5 0.65 0.3 0.3 3.85 6 2x SmallLaser, 2x MediumLaser, 2x MachineGun SmallLaser@LeftTorso(Rear) G1 | SmallLaser@RightTorso(Rear) G1 | MediumLaser@LeftArm(Front) G1 | MediumLaser@RightArm(Front) G1 | MachineGun@LeftArm(Front) G1 | MachineGun@RightArm(Front) G1 LeftTorsox1 | RightTorsox1 | LeftArmx2 | RightArmx2 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) LeftArm(Front) | RightArm(Front) | LeftTorso(Rear) | RightTorso(Rear) | CenterTorso(Unknown) | Head(Unknown)
36 Gargoyle No Clan 15.000000 80.000000 FerroFiberus EndoSteel 0 0 No Yes No No 6 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.9 0 LeftArm(M1/P0/B0/O3) | RightArm(M1/P0/B0/O3) | LeftTorso(M0/P2/B2/O0) | RightTorso(M0/P2/B2/O0) LeftArm(Unknown) | RightArm(Unknown) | LeftTorso(Unknown) | RightTorso(Unknown) not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud
37 Gesu No Clan 9.750000 45.000000 FerroFiberus EndoSteel 0 0 No No Yes No 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.9 0 LeftArm(M0/P2/B0/O0) | RightArm(M0/P2/B0/O0) | LeftTorso(M0/P0/B2/O0) | RightTorso(M0/P0/B2/O0) | Special1(M2/P0/B0/O0) | Special2(M2/P0/B0/O0) LeftArm(Unknown) | RightArm(Unknown) | LeftTorso(Unknown) | RightTorso(Unknown) | Special1(Unknown) | Special2(Unknown) not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud
38 Gladiator Yes Clan 24.000000 95.000000 FerroFiberus Standard 19 Single 1 Yes Yes Yes Yes 43 1.4 1.4 1.65 1.65 1.75 1.75 2.0 0.95 0.25 12.8 12 5x ClanSmallPulseLaser, ClanERSmallLaser, 3x ClanMediumPulseLaser, ClanLargePulseLaser, 2x SRM6 ClanSmallPulseLaser@RightTorso(Front) G1 | ClanSmallPulseLaser@RightTorso(Front) G1 | ClanSmallPulseLaser@RightArm(Front) G1 | ClanSmallPulseLaser@RightArm(Front) G1 | ClanSmallPulseLaser@RightArm(Front) G1 | ClanERSmallLaser@LeftTorso(Front) G1 | ClanMediumPulseLaser@RightArm(Front) G1 | ClanMediumPulseLaser@RightArm(Front) G1 | ClanMediumPulseLaser@RightArm(Front) G1 | ClanLargePulseLaser@LeftArm(Front) G1 | SRM6@LeftArm(Front) G2 | SRM6@LeftArm(Front) G2 RightTorsox2 | RightArmx6 | LeftTorsox1 | LeftArmx3 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown)
39 Grizzly Yes Clan 16.000000 70.000000 FerroFiberus Standard 11 Single 1 Yes Yes Yes Yes 40 1.2 1.2 1.1 1.1 1.4 1.4 1.5 0.5 0.25 9.65 6 2x ClanSmallPulseLaser, ClanMediumPulseLaser, ClanLargePulseLaser, ClanGaussRifle, CLANLRM10 ClanSmallPulseLaser@LeftArm(Front) G1 | ClanSmallPulseLaser@LeftArm(Front) G1 | ClanMediumPulseLaser@RightTorso(Front) G1 | ClanLargePulseLaser@LeftArm(Front) G1 | ClanGaussRifle@RightArm(Front) G1 | CLANLRM10@LeftTorso(Side) G2 LeftArmx3 | RightTorsox1 | RightArmx1 | LeftTorsox1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) LeftArm(Front) | RightArm(Front) | LeftTorso(Side) | RightTorso(Front)
40 Hauptmann Yes Clan 21.000000 95.000000 Standard Standard 20 Single 0 Yes Yes Yes Yes 43 ECM 1.7 1.7 1.8 1.8 1.9 1.9 2.1 1.1 0.3 14.3 8 ClanERSmallLaser, 2x ClanMediumPulseLaser, 2x ClanLargePulseLaser, ClanUltraAC20, 2x ClanSSRM2 ClanERSmallLaser@Head(Front) G1 | ClanMediumPulseLaser@LeftArm(Front) G1 | ClanMediumPulseLaser@RightArm(Front) G1 | ClanLargePulseLaser@LeftArm(Front) G1 | ClanLargePulseLaser@RightArm(Front) G1 | ClanUltraAC20@Special1(Front) G1 | ClanSSRM2@LeftTorso(Front) G2 | ClanSSRM2@RightTorso(Front) G2 Headx1 | LeftArmx2 | RightArmx2 | Special1x1 | LeftTorsox1 | RightTorsox1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O8) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O4) LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Front) | Special1(Front)
41 Hellhound Yes Clan 10.500000 50.000000 FerroFiberus EndoSteel 12 Single 1 Yes Yes Yes Yes 43 0.9 0.9 0.95 0.95 1.05 1.05 1.2 0.55 0.25 7.8 6 3x ClanMediumPulseLaser, ClanUltraAC2, ClanUltraAC5, ClanLRM10 ClanMediumPulseLaser@LeftArm(Front) G1 | ClanMediumPulseLaser@LeftArm(Front) G1 | ClanMediumPulseLaser@RightArm(Front) G1 | ClanUltraAC2@RightTorso(Front) G1 | ClanUltraAC5@RightTorso(Front) G1 | ClanLRM10@LeftTorso(Side) G2 LeftArmx2 | RightArmx1 | RightTorsox2 | LeftTorsox1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) LeftArm(Front) | RightArm(Front) | LeftTorso(Side) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown)
42 Hellspawn Yes IS 10.000000 45.000000 Standard Standard 9 Single 1 Yes Yes Yes Yes 43 ECM 0.5 0.5 0.8 0.8 0.85 0.85 1.15 0.5 0.3 6.25 6 2x MediumPulseLaser, LargePulseLaser, 2x SSRM2, LRM10 MediumPulseLaser@LeftArm(Front) G1 | MediumPulseLaser@LeftArm(Front) G1 | LargePulseLaser@LeftArm(Front) G1 | SSRM2@RightArm(Front) G2 | SSRM2@Special1(Front) G2 | LRM10@LeftTorso(Front) G2 LeftArmx3 | RightArmx1 | Special1x1 | LeftTorsox1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O8) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O4) LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Unknown) | CenterTorso(Unknown) | Head(Unknown) | Special1(Front)
43 Highlander Yes IS 21.500000 90.000000 Standard Standard 17 Single 1 Yes Yes Yes Yes 43 1.75 1.45 1.7 1.7 1.8 1.8 2.0 0.85 0.3 13.35 7 4x MediumPulseLaser, GaussRifle, 2x SRM6 MediumPulseLaser@RightTorso(Front) G1 | MediumPulseLaser@RightTorso(Front) G1 | MediumPulseLaser@RightArm(Front) G1 | MediumPulseLaser@RightArm(Front) G1 | GaussRifle@LeftArm(Front) G1 | SRM6@LeftTorso(Front) G2 | SRM6@LeftTorso(Front) G2 RightTorsox2 | RightArmx2 | LeftArmx1 | LeftTorsox2 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown)
44 Hollander Yes IS 10.000000 45.000000 FerroFiberus EndoSteel 12 Single 0 No Yes Yes Yes 42 0.85 0.85 0.85 0.85 0.9 0.9 1.05 0.45 0.25 6.95 6 2x SmallPulseLaser, 3x MediumPulseLaser, GaussRifle SmallPulseLaser@Special2(Front) G1 | SmallPulseLaser@Special2(Front) G1 | MediumPulseLaser@LeftArm(Front) G1 | MediumPulseLaser@LeftTorso(Front) G1 | MediumPulseLaser@RightArm(Front) G1 | GaussRifle@Special1(Front) G1 Special2x2 | LeftArmx1 | LeftTorsox1 | RightArmx1 | Special1x1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | Special1(M0/P0/B0/O12) | Special2(M0/P0/B0/O2) LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | Special1(Front) | Special2(Front)
45 Hunchback Yes IS 13.500000 50.000000 Standard Standard 10 Single 0 Yes Yes Yes Yes 43 ECM 1.0 1.0 1.1 1.1 1.2 1.2 1.5 0.5 0.3 8.9 6 SmallLaser, 4x MediumLaser, AC10 SmallLaser@Head(Front) G1 | MediumLaser@LeftArm(Front) G1 | MediumLaser@LeftArm(Front) G1 | MediumLaser@RightArm(Front) G1 | MediumLaser@RightArm(Front) G1 | AC10@Special1(Front) G1 Headx1 | LeftArmx2 | RightArmx2 | Special1x1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O8) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O4) LeftArm(Front) | RightArm(Front) | LeftTorso(Unknown) | RightTorso(Unknown) | CenterTorso(Unknown) | Head(Front) | Special1(Front)
46 Kodiak Yes IS 22.000000 100.000000 Standard EndoSteel 20 Single 1 Yes Yes Yes Yes 43 1.5 1.5 1.9 1.9 1.5 1.5 2 1.1 0.3 13.2 7 4x ClanERMediumLaser, ClanUltraAC20, 2x ClanSSRM6 ClanERMediumLaser@leftArm(Front) G1 | ClanERMediumLaser@leftArm(Front) G1 | ClanERMediumLaser@rightarm(Front) G1 | ClanERMediumLaser@rightarm(Front) G1 | ClanUltraAC20@RightTorso(Front) G1 | ClanSSRM6@LeftTorso(Front) G2 | ClanSSRM6@LeftTorso(Front) G2 leftArmx2 | rightarmx2 | RightTorsox1 | LeftTorsox2 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) LeftArm(Unknown) | RightArm(Unknown) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown)
47 Loki Yes Clan 17.500000 65.000000 Standard Standard 13 Single 0 No Yes Yes Yes 43 ECM 1.3 1.3 1.4 1.4 1.5 1.5 1.55 0.6 0.3 10.85 7 2x ClanERMediumLaser, 2x ClanMachineGun, 2x ClanUltraAC5, ClanSSRM6 ClanERMediumLaser@LeftArm(Front) G1 | ClanERMediumLaser@RightArm(Front) G1 | ClanMachineGun@LeftTorso(Front) G1 | ClanMachineGun@RightTorso(Front) G1 | ClanUltraAC5@LeftArm(Front) G1 | ClanUltraAC5@RightArm(Front) G1 | ClanSSRM6@Special1(Front) G2 LeftArmx2 | RightArmx2 | LeftTorsox1 | RightTorsox1 | Special1x1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O10) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O2) LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown) | Special1(Front)
48 Longbow Yes IS 20.500000 85.000000 Standard Standard 11 Single 0 No Yes Yes Yes 43 1.6 1.6 1.65 1.65 1.2 1.2 1.85 1.0 0.3 12.05 6 2x MediumLaser, 2x LRM5, 2x LRM20 MediumLaser@LeftTorso(Front) G1 | MediumLaser@RightTorso(Front) G1 | LRM5@LeftTorso(Front) G2 | LRM5@RightTorso(Front) G2 | LRM20@LeftArm(Front) G2 | LRM20@RightArm(Front) G2 LeftTorsox2 | RightTorsox2 | LeftArmx1 | RightArmx1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown)
49 MadCat_MkII Yes Clan 18.500000 90.000000 Reflective EndoSteel 17 Single 1 Yes Yes Yes Yes 43 1.8 1.8 1.8 1.8 1.85 1.85 2.0 0.8 0.3 14 12 4x ClanERSmallLaser, 2x ClanMachineGun, 4x ClanUltraAC5, 2x ClanLRM15 ClanERSmallLaser@LeftTorso(Front) G1 | ClanERSmallLaser@CenterTorso(Front) G1 | ClanERSmallLaser@CenterTorso(Front) G1 | ClanERSmallLaser@RightTorso(Front) G1 | ClanMachineGun@LeftTorso(Front) G1 | ClanMachineGun@RightTorso(Front) G1 | ClanUltraAC5@LeftArm(Front) G1 | ClanUltraAC5@LeftArm(Front) G1 | ClanUltraAC5@RightArm(Front) G1 | ClanUltraAC5@RightArm(Front) G1 | ClanLRM15@Special2(Side) G2 | ClanLRM15@Special1(Side) G2 LeftTorsox2 | CenterTorsox2 | RightTorsox2 | LeftArmx2 | RightArmx2 | Special2x1 | Special1x1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O8) | RightTorso(M0/P0/B0/O8) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O4) | Special2(M0/P0/B0/O4) LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Front) | Head(Unknown) | Special1(Side) | Special2(Side)
50 Madcat Yes Clan 16.500000 75.000000 FerroFiberus EndoSteel 17 Single 0 Yes Yes Yes Yes 43 1.1 1.1 1.2 1.2 1.4 1.4 1.5 0.5 0.25 9.65 8 2x ClanMediumPulseLaser, 2x ClanERLargeLaser, 2x ClanMachineGun, 2x ClanLRM10 ClanMediumPulseLaser@LeftArm(Front) G1 | ClanMediumPulseLaser@RightArm(Front) G1 | ClanERLargeLaser@LeftArm(Front) G1 | ClanERLargeLaser@RightArm(Front) G1 | ClanMachineGun@LeftTorso(Front) G1 | ClanMachineGun@RightTorso(Front) G1 | ClanLRM10@Special1(Side) G2 | ClanLRM10@Special2(Side) G2 LeftArmx2 | RightArmx2 | LeftTorsox1 | RightTorsox1 | Special1x1 | Special2x1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O9) | RightTorso(M0/P0/B0/O9) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O3) | Special2(M0/P0/B0/O3) LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown) | Special1(Side) | Special2(Side)
51 Masakari Yes Clan 18.000000 85.000000 FerroFiberus Standard 15 Single 0 Yes Yes Yes Yes 43 1.25 1.25 1.4 1.4 1.45 1.45 1.8 0.85 0.25 11.1 7 2x ClanERMediumLaser, 2x ClanUltraAC2, ClanGaussRifle, 2x ClanLRM10 ClanERMediumLaser@RightTorso(Front) G1 | ClanERMediumLaser@RightTorso(Front) G1 | ClanUltraAC2@RightArm(Front) G1 | ClanUltraAC2@RightArm(Front) G1 | ClanGaussRifle@LeftArm(Front) G1 | ClanLRM10@LeftTorso(Side) G2 | ClanLRM10@LeftTorso(Side) G2 RightTorsox2 | RightArmx2 | LeftArmx1 | LeftTorsox2 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) LeftArm(Front) | RightArm(Front) | LeftTorso(Side) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown)
52 Mauler Yes IS 26.000000 90.000000 FerroFiberus Standard 11 Single 0 No Yes Yes Yes 43 1.4 1.4 1.4 1.4 1.55 1.55 1.45 0.8 0.25 11.2 10 2x GaussRifle, 2x SSRM4, 6x LRM5 GaussRifle@LeftArm(Front) G1 | GaussRifle@RightArm(Front) G1 | SSRM4@LeftTorso(Front) G2 | SSRM4@RightTorso(Front) G2 | LRM5@LeftTorso(Side) G2 | LRM5@LeftTorso(Side) G2 | LRM5@LeftTorso(Side) G2 | LRM5@RightTorso(Side) G2 | LRM5@RightTorso(Side) G2 | LRM5@RightTorso(Side) G2 LeftArmx1 | RightArmx1 | LeftTorsox4 | RightTorsox4 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) LeftArm(Front) | RightArm(Front) | LeftTorso(Front+Side) | RightTorso(Front+Side) | CenterTorso(Unknown) | Head(Unknown)
53 Novacat Yes Clan 16.000000 70.000000 Reactive EndoSteel 17 Single 1 Yes Yes Yes Yes 43 ECM 1.55 1.55 1.45 1.45 1.5 1.5 1.7 0.75 0.3 11.75 7 5x ClanMediumPulseLaser, 2x ClanERLargeLaser ClanMediumPulseLaser@LeftArm(Front) G1 | ClanMediumPulseLaser@LeftArm(Front) G1 | ClanMediumPulseLaser@LeftArm(Front) G1 | ClanMediumPulseLaser@LeftTorso(Front) G1 | ClanMediumPulseLaser@RightTorso(Front) G1 | ClanERLargeLaser@RightArm(Front) G1 | ClanERLargeLaser@RightArm(Front) G1 LeftArmx3 | LeftTorsox1 | RightTorsox1 | RightArmx2 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown)
54 Osiris Yes IS 9.500000 30.000000 FerroFiberus EndoSteel 11 Single 1 Yes Yes Yes Yes 43 0.6 0.6 0.6 0.6 0.65 0.65 0.75 0.3 0.25 5 5 SmallPulseLaser, 2x MediumPulseLaser, SSRM2, NarcBeacon SmallPulseLaser@special2(Front) G1 | MediumPulseLaser@special1(Front) G1 | MediumPulseLaser@RightArm(Front) G1 | SSRM2@LeftArm(Front) G2 | NarcBeacon@LeftArm(Front) G3 special2x1 | special1x1 | RightArmx1 | LeftArmx2 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O1) | Special2(M0/P0/B0/O1) LeftArm(Front) | RightArm(Front) | LeftTorso(Unknown) | RightTorso(Unknown) | Head(Unknown) | Special1(Unknown) | Special2(Unknown)
55 Owens Yes IS 9.750000 35.000000 Standard Standard 5 Single 0 No Yes Yes Yes 39 ECM 0.9 0.9 0.8 0.8 0.8 0.8 1.05 0.35 0.3 6.7 5 2x SmallLaser, MediumLaser, 2x SRM6 SmallLaser@CenterTorso(Front) G1 | SmallLaser@CenterTorso(Front) G1 | MediumLaser@Head(Front) G1 | SRM6@LeftArm(Front) G2 | SRM6@RightArm(Front) G2 CenterTorsox2 | Headx1 | LeftArmx1 | RightArmx1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O8) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) LeftArm(Front) | RightArm(Front) | LeftTorso(Unknown) | RightTorso(Unknown) | CenterTorso(Front) | Head(Front)
56 Puma Yes Clan 7.500000 35.000000 FerroFiberus EndoSteel 10 Single 1 Yes Yes Yes Yes 43 0.8 0.8 0.6 0.6 0.6 0.6 0.85 0.45 0.25 5.55 4 2x ClanSmallPulseLaser, 2x ClanLRM20 ClanSmallPulseLaser@LeftTorso(Front) G1 | ClanSmallPulseLaser@RightTorso(Front) G1 | ClanLRM20@LeftArm(Front) G2 | ClanLRM20@RightArm(Front) G2 LeftTorsox1 | RightTorsox1 | LeftArmx1 | RightArmx1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown)
57 Raven Yes IS 10.250000 35.000000 FerroFiberus Standard 7 Single 0 No Yes Yes Yes 43 BAP, ECM 0.6 0.65 0.65 0.65 0.7 0.7 0.75 0.25 0.25 5.2 5 2x MediumLaser, SRM6, LRM5, NarcBeacon MediumLaser@RightArm(Front) G1 | MediumLaser@RightArm(Front) G1 | SRM6@RightTorso(Front) G2 | LRM5@RightTorso(Side) G2 | NarcBeacon@LeftArm(Front) G3 RightArmx2 | RightTorsox2 | LeftArmx1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) LeftArm(Front) | RightArm(Front) | LeftTorso(Unknown) | RightTorso(Front+Side) | CenterTorso(Unknown) | Head(Unknown)
58 Rifleman Yes IS 12.500000 60.000000 FerroFiberus EndoSteel 17 Single 0 Yes Yes Yes Yes 43 0.9 0.9 1.0 1.0 1.5 1.5 1.3 0.7 0.25 9.05 6 2x MediumLaser, 2x LargeLaser, 2x PPC MediumLaser@Special1(Front) G1 | MediumLaser@Special1(Front) G1 | LargeLaser@LeftArm(Front) G1 | LargeLaser@RightArm(Front) G1 | PPC@LeftArm(Front) G1 | PPC@RightArm(Front) G1 Special1x2 | LeftArmx2 | RightArmx2 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O2) LeftArm(Front) | RightArm(Front) | LeftTorso(Unknown) | RightTorso(Unknown) | Head(Unknown) | Special1(Front)
59 Ryoken Yes IS 12.500000 55.000000 FerroFiberus EndoSteel 10 Single 1 Yes Yes Yes Yes 43 ECM 0.9 0.9 1.0 1.0 1.05 1.05 1.15 0.75 0.25 8.05 6 4x ClanMediumPulseLaser, 2x ClanSSRM6 ClanMediumPulseLaser@LeftArm(Front) G1 | ClanMediumPulseLaser@LeftArm(Front) G1 | ClanMediumPulseLaser@RightArm(Front) G1 | ClanMediumPulseLaser@RightArm(Front) G1 | ClanSSRM6@LeftTorso(Front) G2 | ClanSSRM6@RightTorso(Front) G2 LeftArmx2 | RightArmx2 | LeftTorsox1 | RightTorsox1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown)
60 Shadowcat Yes Clan 9.750000 45.000000 FerroFiberus EndoSteel 10 Single 1 Yes Yes Yes Yes 43 BAP 0.85 0.85 0.85 0.85 0.9 0.9 1.05 0.45 0.25 6.95 5 2x ClanMediumPulseLaser, ClanGaussRifle, 2x ClanSSRM4 ClanMediumPulseLaser@RightTorso(Front) G1 | ClanMediumPulseLaser@RightArm(Front) G1 | ClanGaussRifle@LeftArm(Front) G1 | ClanSSRM4@LeftTorso(Front) G2 | ClanSSRM4@RightTorso(Front) G2 RightTorsox2 | RightArmx1 | LeftArmx1 | LeftTorsox1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown)
61 Solitaire Yes Clan 7.000000 25.000000 FerroFiberus EndoSteel 10 Single 0 Yes Yes Yes Yes 46 0.6 0.6 0.6 0.6 0.55 0.55 0.8 0.4 0.25 4.95 4 ClanERSmallLaser, 2x ClanERMediumLaser, ClanERLargeLaser ClanERSmallLaser@LeftTorso(Front) G1 | ClanERMediumLaser@LeftTorso(Front) G1 | ClanERMediumLaser@CenterTorso(Front) G1 | ClanERLargeLaser@Special1(Front) G1 LeftTorsox2 | CenterTorsox1 | Special1x1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O3) LeftArm(Unknown) | RightArm(Unknown) | LeftTorso(Front) | RightTorso(Unknown) | CenterTorso(Front) | Head(Unknown) | Special1(Front)
62 Sunder Yes IS 17.500000 90.000000 Standard Standard 17 Single 0 Yes Yes Yes Yes 43 1.35 1.35 1.55 1.55 1.65 1.65 2.0 1.0 0.3 12.4 10 6x MediumLaser, PPC, 2x MachineGun, SRM6 MediumLaser@LeftTorso(Front) G1 | MediumLaser@LeftTorso(Front) G1 | MediumLaser@LeftTorso(Rear) G1 | MediumLaser@RightTorso(Rear) G1 | MediumLaser@RightTorso(Front) G1 | MediumLaser@RightTorso(Front) G1 | PPC@LeftArm(Front) G1 | MachineGun@RightArm(Front) G1 | MachineGun@RightArm(Front) G1 | SRM6@CenterTorso(Front) G2 LeftTorsox3 | RightTorsox3 | LeftArmx1 | RightArmx2 | CenterTorsox1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) LeftArm(Front) | RightArm(Front) | LeftTorso(Front+Rear) | RightTorso(Front+Rear) | CenterTorso(Front) | Head(Unknown)
63 Templar Yes IS 20.500000 85.000000 Standard EndoSteel 25 Single 1 Yes Yes Yes Yes 43 1.45 1.45 1.6 1.6 1.8 1.8 2.05 0.95 0.3 13 11 6x MediumPulseLaser, PPC, 2x MachineGun, AC20, SRM4 MediumPulseLaser@LeftArm(Front) G1 | MediumPulseLaser@LeftTorso(Front) G1 | MediumPulseLaser@RightTorso(Front) G1 | MediumPulseLaser@RightArm(Front) G1 | MediumPulseLaser@LeftTorso(Rear) G1 | MediumPulseLaser@RightTorso(Rear) G1 | PPC@LeftArm(Front) G1 | MachineGun@LeftTorso(Front) G1 | MachineGun@RightTorso(Front) G1 | AC20@RightArm(Front) G1 | SRM4@RightTorso(Front) G2 LeftArmx2 | LeftTorsox3 | RightTorsox4 | RightArmx2 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) LeftArm(Front) | RightArm(Front) | LeftTorso(Front+Rear) | RightTorso(Front+Rear) | CenterTorso(Unknown) | Head(Unknown)
64 Thanatos Yes IS 18.000000 75.000000 FerroFiberus EndoSteel 20 Single 1 Yes Yes Yes Yes 43 0.9 0.9 1.3 1.3 1.2 1.2 1.6 0.85 0.25 9.5 7 MediumPulseLaser, 2x MediumLaser, 2x LargePulseLaser, 2x LRM10 MediumPulseLaser@LeftTorso(Front) G1 | MediumLaser@LeftArm(Front) G1 | MediumLaser@RightTorso(Front) G1 | LargePulseLaser@LeftArm(Front) G1 | LargePulseLaser@RightTorso(Front) G1 | LRM10@RightArm(Front) G2 | LRM10@RightArm(Front) G2 LeftTorsox1 | LeftArmx2 | RightTorsox2 | RightArmx2 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown)
65 Thor Yes Clan 19.000000 70.000000 FerroFiberus Standard 20 Single 1 Yes Yes Yes Yes 43 1.1 1.1 1.2 1.2 1.4 1.4 1.5 0.5 0.25 9.65 7 2x ClanMediumPulseLaser, ClanERPPC, 2x ClanMachineGun, ClanUltraAC10, CLANLRM10 ClanMediumPulseLaser@LeftTorso(Front) G1 | ClanMediumPulseLaser@RightTorso(Front) G1 | ClanERPPC@RightArm(Front) G1 | ClanMachineGun@LeftTorso(Front) G1 | ClanMachineGun@RightTorso(Front) G1 | ClanUltraAC10@LeftArm(Front) G1 | CLANLRM10@Special1(Side) G2 LeftTorsox2 | RightTorsox2 | RightArmx1 | LeftArmx1 | Special1x1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O10) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O2) LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown) | Special1(Side)
66 Uller Yes Clan 8.000000 30.000000 FerroFiberus EndoSteel 8 Single 0 Yes Yes Yes Yes 43 ECM 0.45 0.45 0.5 0.5 0.6 0.6 0.65 0.45 0.25 4.45 4 ClanERSmallLaser, ClanERMediumLaser, ClanUltraAC5, ClanSRM6 ClanERSmallLaser@LeftArm(Front) G1 | ClanERMediumLaser@RightArm(Front) G1 | ClanUltraAC5@RightArm(Front) G1 | ClanSRM6@LeftArm(Front) G2 LeftArmx2 | RightArmx2 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) LeftArm(Front) | RightArm(Front) | LeftTorso(Unknown) | RightTorso(Unknown) | CenterTorso(Unknown) | Head(Unknown)
67 Uziel Yes IS 11.500000 50.000000 Standard EndoSteel 10 Single 1 Yes Yes Yes Yes 45 1.2 1.2 1.05 1.05 1.15 1.15 1.0 0.45 0.3 8.55 7 2x SmallPulseLaser, PPC, 2x MachineGun, UltraAC5, LRM10 SmallPulseLaser@LeftTorso(Front) G1 | SmallPulseLaser@RightTorso(Front) G1 | PPC@LeftArm(Front) G1 | MachineGun@LeftTorso(Front) G1 | MachineGun@RightTorso(Front) G1 | UltraAC5@RightArm(Front) G1 | LRM10@Special1(Side) G2 LeftTorsox2 | RightTorsox2 | LeftArmx1 | RightArmx1 | Special1x1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O4) LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | Head(Unknown) | Special1(Side)
68 Victor Yes IS 17.000000 80.000000 Standard EndoSteel 10 Single 1 Yes Yes Yes Yes 43 ECM 1.3 1.3 1.3 1.3 1.25 1.25 1.65 1.1 0.3 10.75 7 2x MediumLaser, 2x MachineGun, AC20, 2x SRM4 MediumLaser@LeftArm(Front) G1 | MediumLaser@LeftArm(Front) G1 | MachineGun@LeftTorso(Front) G1 | MachineGun@RightTorso(Front) G1 | AC20@RightArm(Front) G1 | SRM4@LeftTorso(Front) G2 | SRM4@RightTorso(Front) G2 LeftArmx2 | LeftTorsox2 | RightTorsox2 | RightArmx1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Unknown) | Head(Unknown)
69 Vulture Yes Clan 16.000000 60.000000 Reactive EndoSteel 12 Single 0 No Yes Yes Yes 43 BAP 1.3 1.3 1.5 1.5 1.6 1.6 1.75 0.5 0.3 11.35 10 4x ClanMachineGun, 2x ClanLargePulseLaser, 2x ClanLRM5, 2x ClanLRM10 ClanMachineGun@LeftArm(Front) G1 | ClanMachineGun@Special1(Front) G1 | ClanMachineGun@Special1(Front) G1 | ClanMachineGun@RightArm(Front) G1 | ClanLargePulseLaser@LeftArm(Front) G1 | ClanLargePulseLaser@RightArm(Front) G1 | ClanLRM5@LeftTorso(Side) G2 | ClanLRM5@RightTorso(Side) G2 | ClanLRM10@LeftTorso(Side) G2 | ClanLRM10@RightTorso(Side) G2 LeftArmx2 | Special1x2 | RightArmx2 | LeftTorsox2 | RightTorsox2 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | Head(M0/P0/B0/O1) | Special1(M0/P0/B0/O2) LeftArm(Front) | RightArm(Front) | LeftTorso(Side) | RightTorso(Side) | Head(Unknown) | Special1(Front)
70 Warhammer Yes IS 15.000000 70.000000 Standard Standard 17 Single 0 Yes Yes Yes Yes 43 1.55 1.55 1.45 1.45 1.5 1.5 1.7 0.75 0.3 11.75 5 2x MediumLaser, 2x ERPPC, SRM6 MediumLaser@RightTorso(Front) G1 | MediumLaser@LeftTorso(Front) G1 | ERPPC@RightArm(Front) G1 | ERPPC@LeftArm(Front) G1 | SRM6@special2(Front) G2 RightTorsox1 | LeftTorsox1 | RightArmx1 | LeftArmx1 | special2x1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | Special2(M0/P0/B0/O2) LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | Special2(Unknown)
71 Wolfhound Yes Clan 10.250000 35.000000 FerroFiberus EndoSteel 14 Single 0 Yes Yes Yes Yes 43 ECM 0.5 0.5 0.7 0.7 0.75 0.75 0.95 0.5 0.25 5.6 5 3x ClanMediumPulseLaser, ClanERMediumLaser, ClanERLargeLaser ClanMediumPulseLaser@LeftTorso(Front) G1 | ClanMediumPulseLaser@CenterTorso(Front) G1 | ClanMediumPulseLaser@RightTorso(Front) G1 | ClanERMediumLaser@CenterTorso(Rear) G1 | ClanERLargeLaser@RightArm(Front) G1 LeftTorsox1 | CenterTorsox2 | RightTorsox1 | RightArmx1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) LeftArm(Unknown) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front) | CenterTorso(Front+Rear) | Head(Unknown)
72 Zeus Yes IS 22.000000 80.000000 FerroFiberus Standard 22 Single 0 Yes Yes Yes Yes 43 1.1 1.1 1.25 1.25 1.45 1.45 1.55 0.8 0.25 10.2 7 4x MediumPulseLaser, ERLargeLaser, ERPPC, LRM15 MediumPulseLaser@LeftTorso(Front) G1 | MediumPulseLaser@RightTorso(Front) G1 | MediumPulseLaser@RightArm(Front) G1 | MediumPulseLaser@RightTorso(Rear) G1 | ERLargeLaser@CenterTorso(Front) G1 | ERPPC@LeftArm(Front) G1 | LRM15@RightArm(Front) G2 LeftTorsox1 | RightTorsox2 | RightArmx2 | CenterTorsox1 | LeftArmx1 LeftArm(M0/P0/B0/O8) | RightArm(M0/P0/B0/O8) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) | Head(M0/P0/B0/O1) LeftArm(Front) | RightArm(Front) | LeftTorso(Front) | RightTorso(Front+Rear) | CenterTorso(Front) | Head(Unknown)
73 jenner2c No Clan 10.000000 35.000000 FerroFiberus Standard 0 0 Yes Yes No No 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.9 0 LeftArm(M2/P0/B2/O0) | RightArm(M2/P0/B2/O0) | Special1(M3/P0/B0/O0) LeftArm(Unknown) | RightArm(Unknown) | Special1(Unknown) not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud
74 koto No IS 7.000000 25.000000 FerroFiberus EndoSteel 0 0 No Yes No No 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.9 0 LeftArm(M0/P1/B1/O0) | RightArm(M0/P1/B1/O0) | CenterTorso(M0/P0/B2/O0) | Special1(M0/P0/B3/O0) LeftArm(Unknown) | RightArm(Unknown) | CenterTorso(Unknown) | Special1(Unknown) not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud
75 locust2c No Clan 7.000000 25.000000 FerroFiberus EndoSteel 0 0 No Yes No No 4 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.9 0 LeftArm(M0/P0/B1/O2) | RightArm(M0/P0/B1/O2) | Special1(M0/P0/B3/O0) LeftArm(Unknown) | RightArm(Unknown) | Special1(Unknown) not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud
76 marauder2 No IS 22.000000 100.000000 FerroFiberus EndoSteel 0 0 Yes No Yes No 6 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.9 0 LeftArm(M0/P0/B4/O1) | RightArm(M0/P0/B4/O1) | LeftTorso(M0/P0/B1/O1) | RightTorso(M0/P0/B1/O1) | Special1(M0/P7/B0/O0) | Special2(M0/P0/B0/O2) LeftArm(Unknown) | RightArm(Unknown) | LeftTorso(Unknown) | RightTorso(Unknown) | Special1(Unknown) | Special2(Unknown) not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud
77 pitbull No Clan 15.000000 70.000000 FerroFiberus EndoSteel 0 0 Yes No No No 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.9 0 LeftArm(M0/P2/B2/O0) | RightArm(M0/P2/B2/O0) | LeftTorso(M0/P0/B2/O0) | RightTorso(M0/P0/B2/O0) | Special1(M0/P4/B0/O0) LeftArm(Unknown) | RightArm(Unknown) | LeftTorso(Unknown) | RightTorso(Unknown) | Special1(Unknown) not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud
78 privateer No IS 12.500000 55.000000 FerroFiberus Standard 0 0 No No Yes No 2 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.9 0 LeftArm(M0/P1/B0/O1) | RightArm(M0/P1/B0/O1) | LeftTorso(M0/P2/B2/O0) | RightTorso(M0/P0/B1/O0) | Special1(M4/P0/B0/O0) LeftArm(Unknown) | RightArm(Unknown) | LeftTorso(Unknown) | RightTorso(Unknown) | Special1(Unknown) not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud
79 razorback No IS 9.000000 30.000000 FerroFiberus EndoSteel 0 0 No Yes No No 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.9 0 LeftArm(M2/P0/B2/O0) | RightArm(M0/P0/B3/O0) | Special1(M0/P2/B0/O0) | Special2(M0/P2/B0/O0) LeftArm(Unknown) | RightArm(Unknown) | Special1(Unknown) | Special2(Unknown) not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud
80 reaper No Clan 16.500000 75.000000 FerroFiberus EndoSteel 0 0 Yes Yes No No 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.9 0 LeftArm(M0/P0/B3/O0) | RightArm(M0/P0/B3/O0) | LeftTorso(M0/P0/B2/O0) | RightTorso(M0/P0/B2/O0) | CenterTorso(M0/P6/B0/O0) LeftArm(Unknown) | RightArm(Unknown) | LeftTorso(Unknown) | RightTorso(Unknown) | CenterTorso(Unknown) not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud
81 reaver No Clan 10.000000 40.000000 FerroFiberus EndoSteel 0 0 Yes No Yes No 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.9 0 LeftArm(M0/P0/B3/O0) | RightArm(M0/P0/B3/O0) | LeftTorso(M0/P0/B1/O0) | RightTorso(M0/P0/B1/O0) LeftArm(Unknown) | RightArm(Unknown) | LeftTorso(Unknown) | RightTorso(Unknown) not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud
82 shadowhawk No IS 12.500000 55.000000 FerroFiberus Standard 0 0 Yes Yes No No 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.9 0 LeftArm(M0/P1/B2/O0) | RightArm(M0/P0/B3/O0) | LeftTorso(M0/P0/B1/O0) | RightTorso(M0/P0/B1/O0) | Special1(M0/P2/B0/O0) | Special2(M2/P0/B0/O0) LeftArm(Unknown) | RightArm(Unknown) | LeftTorso(Unknown) | RightTorso(Unknown) | Special1(Unknown) | Special2(Unknown) not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud
83 strider No IS 11.000000 40.000000 FerroFiberus Standard 0 0 No No Yes No 4 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.9 0 LeftArm(M2/P0/B0/O0) | RightArm(M2/P0/B0/O0) | LeftTorso(M0/P0/B0/O2) | RightTorso(M0/P0/B0/O2) | CenterTorso(M0/P0/B2/O0) LeftArm(Unknown) | RightArm(Unknown) | LeftTorso(Unknown) | RightTorso(Unknown) | CenterTorso(Unknown) not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud
84 urbanmech Yes IS 5.000000 30.000000 Standard Standard 8 Single 0 Yes Yes No No 50 0.45 0.45 0.5 0.5 0.6 0.6 0.65 0.45 0.25 4.45 2 SmallLaser, AC20 SmallLaser@LeftArm(Front) G1 | AC20@RightArm(Front) G1 LeftArmx1 | RightArmx1 LeftArm(M0/P0/B0/O12) | RightArm(M0/P0/B0/O12) | LeftTorso(M0/P0/B0/O12) | RightTorso(M0/P0/B0/O12) | CenterTorso(M0/P0/B0/O2) LeftArm(Front) | RightArm(Front) | LeftTorso(Unknown) | RightTorso(Unknown) | CenterTorso(Unknown)
85 urbanmech_iic No Clan 5.000000 30.000000 FerroFiberus Standard 0 0 Yes Yes No No 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.9 0 LeftArm(M0/P2/B2/O0) | RightArm(M0/P0/B4/O0) | LeftTorso(M0/P1/B0/O0) | RightTorso(M0/P1/B0/O0) LeftArm(Unknown) | RightArm(Unknown) | LeftTorso(Unknown) | RightTorso(Unknown) not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud
86 ursus No Clan 10.500000 50.000000 FerroFiberus Standard 0 0 No Yes No No 3 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.9 0 LeftArm(M0/P0/B0/O3) | RightArm(M0/P0/B4/O0) | CenterTorso(M2/P0/B0/O0) | Special1(M0/P0/B1/O0) | Special2(M0/P0/B1/O0) LeftArm(Unknown) | RightArm(Unknown) | CenterTorso(Unknown) | Special1(Unknown) | Special2(Unknown) not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud
87 vulture2 No Clan 16.500000 75.000000 FerroFiberus EndoSteel 0 0 No Yes No No 5 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.9 0 LeftArm(M0/P3/B0/O0) | RightArm(M0/P0/B0/O3) | LeftTorso(M2/P0/B2/O0) | RightTorso(M2/P0/B2/O0) | Special1(M0/P0/B0/O2) | Special2(M0/P0/B2/O0) LeftArm(Unknown) | RightArm(Unknown) | LeftTorso(Unknown) | RightTorso(Unknown) | Special1(Unknown) | Special2(Unknown) not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud
88 vulturec No Clan 14.000000 60.000000 FerroFiberus Standard 0 0 No Yes No No 3 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.9 0 LeftArm(M0/P3/B0/O0) | RightArm(M0/P3/B0/O0) | LeftTorso(M2/P0/B0/O0) | RightTorso(M2/P0/B0/O0) | CenterTorso(M0/P0/B0/O1) | Special1(M0/P0/B0/O1) | Special2(M0/P0/B0/O1) LeftArm(Unknown) | RightArm(Unknown) | LeftTorso(Unknown) | RightTorso(Unknown) | CenterTorso(Unknown) | Special1(Unknown) | Special2(Unknown) not registered in active mech tables; missing M_* mech ID defines; core mech files exist; not fully packaged (core.build, props.build, textures.build); missing display/name string IDs (IDS/DNL); no loose hsh bmp in Mechs/MFD/hud
+654
View File
@@ -0,0 +1,654 @@
# mech_loadouts.csv Catch-Up Notes
This document is for future AI agents or maintainers who need to understand how [mech_loadouts.csv](mech_loadouts.csv) was built, where each column comes from, and what files must be updated together when mech data changes.
## Purpose
`mech_loadouts.csv` is a flattened mech audit sheet built from the FireStorm content tree. It combines:
- mech identity and stat data
- current in-game playability status
- installed/default weapon loadouts
- weapon facing and grouping metadata
- zone hardpoint capacity
- notes about missing registration, packaging, or asset support
The CSV is not a primary source of truth. It is a synthesized report built from the mech content files and several registration tables.
## Current CSV Column Layout
The important derived columns are:
- `In_game_playable`
- `Weapons_With_Locations`
- `Default_Installed_Locations`
- `Available_Slot_Capacity_By_Zone`
- `Available_Hardpoints`
- `notes`
The existing stat columns before those are mostly direct mech data fields and were not re-derived during the audit.
## What Each Derived Column Means
### `In_game_playable`
`Yes` if the mech is currently in the active playable roster, `No` otherwise.
This was determined by comparing the mech folder set against the active registration chain:
- `Gameleap/code/mw4/Code/MW4/MechLabHeaders.h`
- `Gameleap/mw4/Content/ShellScripts/MechLabHeaders.h`
- `Gameleap/mw4/Content/Tables/MechChassisTable.tbl`
- `Gameleap/mw4/Content/Tables/MechTable.tbl`
- `Gameleap/mw4/Content/core.build`
- plus supporting string and packaging manifests
Practical rule:
- folder presence alone does not make a mech playable
- playable mechs must have the ID/table/build registrations aligned
### `Weapons_With_Locations`
This column lists each installed weapon in the mech¡¯s default subsystem file, with:
- the weapon name
- the `InternalLocation`
- the `WeaponFacing`
- the weapon group
Current format:
- `WeaponName@Location(Facing) G#`
Examples:
- `MediumPulseLaser@LeftTorso(Rear) G1`
- `SRM4@RightTorso(Front) G2`
- `ClanLRM10@LeftTorso(Side) G2`
Derived from the mech¡¯s `.subsystems` file by reading weapon subsystem blocks.
Important notes:
- `WeaponFacing=0` => `Front`
- `WeaponFacing=1` => `Rear`
- `WeaponFacing=2` => `Side`
- if `WeaponFacing` is absent, it defaults to `Front`
### `Default_Installed_Locations`
A compact count summary of where the mech¡¯s default weapons are installed, based on `InternalLocation` in the `.subsystems` file.
Example:
- `LeftArmx2 | LeftTorsox3 | RightTorsox4 | RightArmx2`
This is about installed weapons, not slot capacity.
### `Available_Slot_Capacity_By_Zone`
A compact summary of zone capacities from the mech¡¯s `.damage` file.
Current format:
- `Zone(M# / P# / B# / O#)`
Where:
- `M` = MissileSlots
- `P` = ProjectileSlots
- `B` = BeamSlots
- `O` = OmniSlots
Example:
- `LeftTorso(M0/P2/B2/O0)`
This reflects what the mech can support in that zone, not what is currently installed.
### `Available_Hardpoints`
A list of zones that have at least one positive slot count in the `.damage` file.
Current format:
- `LeftArm(Front)`
- `LeftTorso(Front+Rear)`
- `RightTorso(Side)`
This column is a directional summary of where weapons can be mounted.
Important:
- this is derived from slot capacity plus facing information from weapon loadouts
- it is not a literal mechanical port map
- if a zone has multiple facing types in the mech¡¯s default loadout, it can show a combined label such as `Front+Rear` or `Front+Side`
## Core Data Sources
### 1. Mech registration and playability
Primary files:
- `Gameleap/code/mw4/Code/MW4/MechLabHeaders.h`
- `Gameleap/mw4/Content/ShellScripts/MechLabHeaders.h`
- `Gameleap/mw4/Content/Tables/MechChassisTable.tbl`
- `Gameleap/mw4/Content/Tables/MechTable.tbl`
- `Gameleap/mw4/Content/core.build`
What they control:
- which mechs are actually in the active roster
- which IDs exist in code and script space
- which mech resources are packed into the runtime build
If a mech folder exists but it is not listed in these files, it is usually not playable.
### 2. Default weapon loadout and weapon-facing metadata
Primary file:
- `Gameleap/mw4/Content/Mechs/<MechName>/<mech>.subsystems`
Each weapon block typically contains:
- `Model=` weapon subsystem resource
- `InternalLocation=` where the weapon is mounted
- `Site=` mount port name
- `GroupIndex=` weapon group number
- `WeaponFacing=` optional facing metadata
- `AmmoCount=` for ammo-using weapons
The `.subsystems` file is the source for:
- `Weapons_With_Locations`
- `Default_Installed_Locations`
- facing annotations in the hardpoint summaries
### 3. Slot capacity / hardpoint support
Primary file:
- `Gameleap/mw4/Content/Mechs/<MechName>/<mech>.damage`
Each section such as `[LeftArmInternal]` or `[RightTorsoInternal]` may contain:
- `MissileSlots=`
- `ProjectileSlots=`
- `BeamSlots=`
- `OmniSlots=`
These are used to derive:
- `Available_Slot_Capacity_By_Zone`
- `Available_Hardpoints`
### 4. Weapon slot type rules in code
Relevant code:
- `Gameleap/code/mw4/Code/MW4/MWDamageObject.cpp`
- `Gameleap/code/mw4/Code/MW4/MWDamageObject.hpp`
- `Gameleap/code/mw4/Code/MW4/MechLab.cpp`
- `Gameleap/code/mw4/Code/MW4/Subsystem_Tool.cpp`
- `Gameleap/code/mw4/Code/MW4/Weapon_Tool.cpp`
- `Gameleap/code/mw4/Code/MW4/Weapon.hpp`
- `Gameleap/code/mw4/Code/MW4/Weapon.cpp`
- `Gameleap/code/mw4/Code/MW4/hudweapon.cpp`
What the code does:
- reads slot counts from `.damage`
- reads `InternalLocation` and `WeaponFacing` from `.subsystems`
- maps weapon slot type and size from the weapon model
- assigns weapons to valid locations during mechlab editing
## Facing Semantics
Weapon facing is stored per weapon instance, not as a separate hardpoint label.
Values seen in the data/code:
- `0` = front
- `1` = rear
- `2` = side
Code references:
- `Gameleap/code/mw4/Code/MW4/Weapon_Tool.cpp`
- `Gameleap/code/mw4/Code/MW4/Weapon.hpp`
- `Gameleap/code/mw4/Code/MW4/Weapon.cpp`
- `Gameleap/code/mw4/Code/MW4/hudweapon.cpp`
- `Gameleap/code/mw4/Code/MW4/MechLab.cpp`
Important nuance:
- a zone name like `LeftTorso` does not tell you the facing by itself
- the facing comes from the weapon block¡¯s `WeaponFacing`
- the same zone can contain multiple weapons with different facings
## Group Index Meaning
The `G1`, `G2`, etc. suffix in `Weapons_With_Locations` is the weapon group number from `GroupIndex` in the subsystem file.
This is not a location or facing field.
Meaning:
- `G1` = weapon group 1
- `G2` = weapon group 2
- and so on
## How The Spreadsheet Was Built
The CSV was assembled by cross-referencing:
- mech folder contents under `Gameleap/mw4/Content/Mechs/`
- `.subsystems` weapon blocks
- `.damage` internal zone capacities
- active roster tables and IDs
- string registration files
- build manifests
- loose UI art assets under `Gameleap/mw4/hsh/`
The output is a derived audit sheet, not a direct export from a single source file.
## Known Pitfalls
### 1. Folder presence does not mean playable
Some mech folders exist but are not in the active roster tables or headers. These need ID/table/build integration before they are usable in-game.
### 2. File names are not always canonical
Some mechs use alternate base filenames inside their folder. Do not assume `FolderName/FolderName.damage` or `FolderName/FolderName.subsystems` always exist.
Prefer:
- parse the `.instance` file when present
- otherwise detect the first matching `.subsystems` / `.damage` file by extension and content
### 3. `Available_Hardpoints` is a summary, not a literal port map
It summarizes zones with capacity and facing hints, but it does not enumerate every exact port or site name.
### 4. Rear-facing weapons are per-instance
If a mech has one rear-mounted weapon in a torso zone, that does not mean all weapons in that zone are rear-facing.
## Update Checklist For Future Changes
If a mech is added or changed, check these in order:
1. update or verify the mech `.data`, `.instance`, `.subsystems`, and `.damage` files
2. ensure the mech is added to the active ID header(s)
3. update `MechChassisTable.tbl` and `MechTable.tbl`
4. update `core.build` and any related build manifests
5. add any needed string IDs or script references
6. confirm the mech has the expected loose or packed art assets
7. rebuild the CSV derived columns if the data changed
## Useful File Map
### Mech data
- `Gameleap/mw4/Content/Mechs/<MechName>/`
### Roster and IDs
- `Gameleap/code/mw4/Code/MW4/MechLabHeaders.h`
- `Gameleap/mw4/Content/ShellScripts/MechLabHeaders.h`
- `Gameleap/mw4/Content/Tables/MechChassisTable.tbl`
- `Gameleap/mw4/Content/Tables/MechTable.tbl`
### Slot/hardpoint logic
- `Gameleap/code/mw4/Code/MW4/MWDamageObject.cpp`
- `Gameleap/code/mw4/Code/MW4/MechLab.cpp`
- `Gameleap/code/mw4/Code/MW4/Subsystem_Tool.cpp`
### Facing logic
- `Gameleap/code/mw4/Code/MW4/Weapon.cpp`
- `Gameleap/code/mw4/Code/MW4/Weapon.hpp`
- `Gameleap/code/mw4/Code/MW4/Weapon_Tool.cpp`
- `Gameleap/code/mw4/Code/MW4/hudweapon.cpp`
### Build manifests
- `Gameleap/mw4/Content/core.build`
- `Gameleap/mw4/Content/props.build`
- `Gameleap/mw4/Content/textures.build`
## Current State Summary
At the time this doc was written:
- `mech_loadouts.csv` includes playability, default loadout, facing, hardpoint, and notes columns
- non-playable mechs are explicitly marked `No`
- Templar and other mechs with rear or side mounts have facing visible in the CSV
- the file is intended to be a living audit artifact for future data cleanup and enablement work
---
## MechEditor Web App — Data Sources, Fields, and Conversions (documented 2026-07-23)
The MechEditor is a single-file Python HTTP server at `/home/rich/Repositories/MechEditor/mech_editor.py`.
It runs at `localhost:8765`, parses the firestorm content tree, and presents a full mech configuration editor in the browser.
This section documents every data field it reads, every conversion it performs, and every naming rule it enforces.
---
### Data Files Parsed Per Mech
All files live under `Gameleap/mw4/Content/Mechs/<MechDir>/`.
#### `.data` file (`parse_data()`)
| Field in file | Editor key | Notes |
|---|---|---|
| `VehicleTonnage` | `tonnage` | chassis base tonnage (float) |
| `MaxVehicleTonnage` | `max_tonnage` | max loadout tonnage (float) |
| `TechType` | `tech` | `$(Tech_IS)` ? `"IS"`, `$(Tech_Clan)` ? `"Clan"` |
| `MaxHeat` | `max_heat` | heat capacity (int) |
| `VehicleTradeValue` | `trade_value` | C-bills |
| `DragoonValue` | `dragoon` | used in Power Rating bar scaling |
| `MinMaxSpeed` | `min_max_speed` | base speed ceiling in **m/s** |
| `MaxSpeed` | `max_speed` | absolute speed ceiling in **m/s** (engine upgrades may not exceed this) |
| `FullStopTurnRate` | `full_stop_turn` | turn rate at zero speed, in **degrees/sec** |
| `TopSpeedTurnRate` | `top_speed_turn` | turn rate at top speed, in **degrees/sec** |
| `Acceleration` | `acceleration` | forward acceleration in **m/s²** |
| `Decceleration` | `decceleration` | forward braking in **m/s²****double-c spelling is canonical in the engine source** |
| `ReverseAccelerationMultiplier` | `rev_accel_mult` | multiplier applied to Acceleration for reverse |
| `ReverseDeccelerationMultiplier` | `rev_decel_mult` | multiplier applied to Decceleration for reverse — double-c canonical |
| `MinStandTransitionSpeed` | not surfaced | animation threshold only — see note below |
| `CanLoadJumpJets` | `can_jj` | Yes/No |
| `CanLoadECM` | `can_ecm` | Yes/No |
| `CanLoadBeagle` | `can_bap` | Yes/No |
| `CanLoadLightAmp` | `can_lightamp` | Yes/No |
| `CanLoadAMS` | `can_ams` | Yes/No |
| `CanLoadLAMS` | `can_lams` | Yes/No |
| `CanLoadIFF_Jammer` | `can_iff` | Yes/No |
**MinStandTransitionSpeed** is the speed (m/s) below which the mech switches from its walking animation to its idle/standing animation.
It is NOT a hard movement limit. It is purely an animation state machine threshold in `Mech.cpp`.
Code path: `animStateEngine?RequestState(StandState)` when `currentSpeedMPS <= minStandTransitionSpeed`.
Must be > 0 (validated in `Vehicle_Tool.cpp`). Argus = 12.631 m/s = 45.5 kph.
#### `.instance` file (`parse_instance()`)
| Field | Editor key | Notes |
|---|---|---|
| `PowerRating` | `PowerRating` | mechlab bar value, 0100 |
| `ArmorRating` | `ArmorRating` | mechlab bar value, 0100 |
| `SpeedRating` | `SpeedRating` | mechlab bar value, 0100 |
| `HeatRating` | `HeatRating` | mechlab bar value, 0100 |
| `DoesHaveLightAmp` | `has_lightamp` | 0 or 1, default 1 — whether LightAmp is currently installed |
#### `.subsystems` file (`parse_subsystems()`)
Provides: armor type + per-zone multipliers, installed heatsinks, jump jets, engine upgrades, weapons, electronics.
**Armor block:**
- `ArmorType=` ? armor type string (`Standard`, `FerroFiberus`, `Reactive`, `Reflective`, `Solarian`)
- Per-zone entries: `LeftArm=1.0`, `RightTorso=2.5`, etc. — multiplier for that zone
**Engine:**
- `EngineUpgrade` blocks counted ? `engine_upgrades` (05)
**Weapons** — each weapon block contains:
- `Model=` ? weapon subsystem resource path (name extracted)
- `InternalLocation=` ? zone name
- `Site=` ? mount port name (from armature)
- `GroupIndex=` ? weapon group number
- `WeaponFacing=` ? 0=Front, 1=Rear, 2=Side (absent = Front)
- `AmmoCount=` ? rounds for ammo-using weapons
- `EjectSite=` ? optional ejection site for ammo
**Electronics:** ECM, Beagle (BAP), AMS, LAMS, IFF_Jammer detected by subsystem model path.
#### `.damage` file (`parse_damage()`)
Per zone section `[ZoneInternal]`:
- `BaseArmorValue` ? starting armor (float)
- `MaxArmorValue` ? hard cap on armor pts for that zone
- `InternalHPValue` ? internal structure HP
- `OmniSlots`, `BeamSlots`, `MissileSlots`, `ProjectileSlots` ? weapon slot counts
Special zones:
- `SpecialAttachedToZone=` ? which body section this special zone is attached to
- `DamagePropagationZone=` ? where overflow damage propagates
#### `.engine` file (`parse_engine()`)
| Field | Editor key | Notes |
|---|---|---|
| `NumHeatSinks` | `NumHeatSinks` | free heatsinks from engine (not in subsystems) |
| `TonsPerUpgrade` | `TonsPerUpgrade` | tonnage cost per engine upgrade tier |
| `MPSPerUpgrade` | `MPSPerUpgrade` | m/s speed gain per upgrade tier |
#### `.torso` file (`parse_torso()`)
| Field | Notes |
|---|---|
| `TwistSpeed` | torso horizontal rotation speed — may be a macro reference |
| `PitchSpeed` | torso vertical rotation speed — may be a macro reference |
| `TwistRadius` | max horizontal twist angle — may be a macro reference |
| `PitchRadius` | max vertical pitch angle — may be a macro reference |
| `ArmRatioAngle` | ratio of arm tracking vs torso rotation — may be a macro reference |
All torso fields may reference macros from `Content/Defines/MechTorso.defines`.
The editor resolves them using a preloaded `TORSO_DEFINES` dict. Notable values:
```
NORMAL_RATIO = 40
SNAIL_TSPEED = 40
NORMAL_TSPEED = 60
FAST_TSPEED = 80
WIDE_TRADIUS = 160
NORMAL_PRADIUS = 40
```
---
### Calculated Ratings and Conversions
#### Speed (kph)
```
top_speed_kph = min(MinMaxSpeed + MPSPerUpgrade × engine_upgrades, MaxSpeed) × 3.6
```
- `MinMaxSpeed` and `MaxSpeed` from `.data` (m/s)
- `MPSPerUpgrade` from `.engine` (m/s per tier)
- `engine_upgrades` from `.subsystems` (05)
- Multiply by 3.6 to convert m/s ? kph
- Argus example: (20.28 + 1.11 × 10) × 3.6 = 113.5 kph
#### Speed Rating (bar)
```
speed_rating = (top_speed_mps / MaxSpeed) × 100 [capped at 100]
```
#### Turn Rate — degrees to radians
The `.data` file stores turn rates in **degrees/sec**. The mechlab UI label was changed to show rad/sec:
- `StringResource.rc`: `IDS_ML_CH_TURNRATE` ? `"Turn Rate (Top Speed Rad/Sec):"`
- Conversion: `radians = degrees × ?/180` where `?/180 ? 0.017453`
- Argus: FullStopTurn = 75° = **1.309 rad/sec**, TopSpeedTurn = 45° = **0.785 rad/sec**
#### Acceleration / Deceleration (m/s²)
Stored directly in `.data`. Reverse values are derived:
```
reverse_accel = Acceleration × ReverseAccelerationMultiplier
reverse_decel = Decceleration × ReverseDeccelerationMultiplier
```
**The double-c spelling (`Decceleration`, `ReverseDeccelerationMultiplier`) is canonical — it matches the engine source. Do not "fix" the spelling.**
#### Heat Rating (bar)
```
total_hs = NumHeatSinks (engine) + installed_heatsinks (subsystems)
effective_hs = total_hs × (2 if Double else 1)
heat_rating = (effective_hs / MaxHeat) × 100 [capped at 100]
```
#### Power Rating (bar)
```
total_damage = ? (DamageAmount × NumFire) for each installed weapon
power_rating = (total_damage / 80) × 100 [capped at 100]
```
- `DamageAmount` and `NumFire` come from `WeaponSubsystems/<weapon>.data` following `!include` chains
- Parsed by `load_weapon_damages()` at server startup, cached in `Handler.weapon_damages`
- Argus example with default load: ~36.2 total damage ? 45 rating (stored = 42)
#### Armor Rating (bar)
```
for each zone:
pts = multiplier × ARMOR_PTS_PER_TON[armor_type]
effective = min(pts, MaxArmorValue[zone])
armor_rating = (? effective / ? MaxArmorValue) × 100
```
Armor pts per ton by type (from `Adept/ResourceImagePool.cpp` and game design):
| Type | Pts/ton |
|---|---|
| Standard | 32 |
| FerroFiberus | 38 |
| Reactive | 30 |
| Reflective | 30 |
| Solarian | 60 |
Note: `FerroFiberus` is the canonical internal token (not player-visible). The player sees `DNL_FERROFIB = "Ferro Fibrous"` via string lookup.
---
### Active-in-Game Detection
Source: `Gameleap/mw4/Content/Tables/MechChassisTable.tbl`
Format:
```
DisplayKey=Mechs\DirName\FileName.data
//CommentedKey=Mechs\DirName\FileName.data <- inactive
```
- Active = entry exists AND is not prefixed with `//`
- Currently the only inactive mech: **Dasher** (commented out)
- The editor shows a green **ACTIVE IN GAME** or red **NOT IN GAME** banner at top of Stats tab
---
### hsh/ Image Naming Conventions
The `hsh/` directory under `Gameleap/mw4/` holds loose BMP files loaded at runtime (not packed into `.mw4`).
There are four relevant subdirectories, each with a different naming authority.
#### `hsh/hud/` — in-game HUD damage silhouette (own mech)
#### `hsh/MFD/` — MFD target display silhouette (target mech)
#### `hsh/radar/hud/` — radar damage overlay
**All three use identical stems** sourced from `huddamage.cpp` `texturename[]` array.
Load path:
- hud/MFD: `hsh\<texturename>.bmp` where texturename = `hud\<stem>` ? file = `hsh/hud/<stem>.bmp`
- radar: `hsh\radar\<texturename>.bmp` ? file = `hsh/radar/hud/<stem>.bmp`
Code: `render.cpp` `CRadar_Device::LoadRadarDamageTexture()` and `huddamage.cpp` `HUDDamage`.
#### `hsh/Mechs/` — mw4print scorecard portrait
Load path: `recscore.cpp` ? `GetLocString(model->m_nameIndex)` ? `DNL_*` string from `StringResource.rc` ? lowercased filename.
Different naming authority from the other three.
---
### Complete Canonical Name Table
Key: mech directory name (case-insensitive) ? canonical stem for `hsh/hud/`, `hsh/MFD/`, `hsh/radar/hud/`.
Entries in **bold** differ from the directory name.
| Directory | hud/MFD/radar stem | hsh/Mechs/ portrait filename |
|---|---|---|
| Annihilator | annihilator | annihilator.bmp |
| Archer | archer | archer.bmp |
| ArcticWolf | arcticwolf | arctic wolf.bmp |
| Ares | ares | ares.bmp |
| Argus | argus | argus.bmp |
| Assassin2 | assassin2 | **assassin ii.bmp** |
| Atlas | atlas | atlas.bmp |
| Avatar | avatar | avatar.bmp |
| Awesome | awesome | awesome.bmp |
| Battlemaster | battlemaster | battlemaster.bmp |
| Battlemaster2c | **battlemasteriic** | **battlemaster iic.bmp** |
| Behemoth | behemoth | behemoth.bmp |
| Behemoth2 | **behemothii** | **behemoth ii.bmp** |
| Blackhawk | blackhawk | black hawk.bmp |
| Blacknight | **blackknight** | black knight.bmp |
| Blacklanner | blacklanner | black lanner.bmp |
| Brigand | brigand | brigand.bmp |
| Bushwacker | bushwacker | bushwacker.bmp |
| Catapult | catapult | catapult.bmp |
| CauldronBorn | cauldronborn | **cauldronborn.bmp** (table key has hyphen; DNL does not) |
| Chimera | chimera | chimera.bmp |
| Commando | commando | commando.bmp |
| Cougar | cougar | cougar.bmp |
| Cyclops | cyclops | cyclops.bmp |
| Daishi | daishi | daishi.bmp |
| Deimos | deimos | deimos.bmp |
| Dragon | dragon | dragon.bmp |
| Fafnir | fafnir | fafnir.bmp |
| Flea | flea | flea.bmp |
| Gladiator | gladiator | gladiator.bmp |
| Grizzly | grizzly | grizzly.bmp |
| Hauptmann | hauptmann | hauptmann.bmp |
| Hellhound | hellhound | hellhound.bmp |
| Hellspawn | hellspawn | hellspawn.bmp |
| Highlander | highlander | highlander.bmp |
| Hollander | **hollanderii** | **hollander ii.bmp** |
| Hunchback | hunchback | hunchback.bmp |
| Kodiak | kodiak | kodiak.bmp |
| Loki | loki | loki.bmp |
| Longbow | longbow | longbow.bmp |
| Madcat | madcat | mad cat.bmp |
| Madcat_MKII | **madcat2** | mad cat mkii.bmp |
| Masakari | masakari | masakari.bmp |
| Mauler | mauler | mauler.bmp |
| Novacat | novacat | nova cat.bmp |
| Osiris | osiris | osiris.bmp |
| Owens | owens | owens.bmp |
| Puma | puma | puma.bmp |
| Raven | raven | raven.bmp |
| Rifleman | rifleman | rifleman.bmp |
| Ryoken | ryoken | ryoken.bmp |
| Shadowcat | shadowcat | shadow cat.bmp |
| Solitaire | solitaire | solitaire.bmp |
| Sunder | sunder | sunder.bmp |
| Templar | templar | templar.bmp |
| Thanatos | thanatos | thanatos.bmp |
| Thor | thor | thor.bmp |
| Uller | uller | uller.bmp |
| Urbanmech | urbanmech | urbanmech.bmp |
| Uziel | uziel | uziel.bmp |
| Victor | victor | victor.bmp |
| Vulture | vulture | vulture.bmp |
| Warhammer | warhammer | warhammer.bmp |
| Wolfhound | wolfhound | wolfhound.bmp |
| Zeus | zeus | zeus.bmp |
**Critical mismatches where directory name ? hud/MFD stem (files must use the stem, not the dir name):**
| Directory | Wrong name (dir-based) | Correct name (stem) |
|---|---|---|
| Battlemaster2c | battlemaster2c.bmp | **battlemasteriic.bmp** |
| Behemoth2 | behemoth2.bmp | **behemothii.bmp** |
| Blacknight | blacknight.bmp | **blackknight.bmp** |
| Hollander | hollander.bmp | **hollanderii.bmp** |
| Madcat_MKII | madcat_mkii.bmp | **madcat2.bmp** |
**Portrait mismatches for hsh/Mechs/ (table key ? DNL string):**
The `MechChassisTable.tbl` display key and `GetLocString()` DNL string differ for these mechs.
mw4print uses the DNL string. The table key is NOT the correct portrait filename for these 5 mechs.
| Directory | Table key (wrong for mw4print) | DNL string (correct portrait stem) |
|---|---|---|
| Assassin2 | AssassinII ? assassinii | `DNL_ASSASSIN2 "Assassin II"` ? **assassin ii.bmp** |
| Battlemaster2c | BattlemasterIIC ? battlemasteriic | `DNL_BATTLEMASTERIIC "Battlemaster IIc"` ? **battlemaster iic.bmp** |
| Behemoth2 | BehemothII ? behemothii | `DNL_BEHEMOTHII "Behemoth II"` ? **behemoth ii.bmp** |
| CauldronBorn | Cauldron-Born ? cauldron-born | `DNL_CAULDRONBORN "Cauldronborn"` ? **cauldronborn.bmp** |
| Hollander | HollanderII ? hollanderii | `DNL_HOLLANDERII "Hollander II"` ? **hollander ii.bmp** |
---
### MechEditor Implementation Notes
The editor encodes all of the above knowledge in two Python dicts:
**`MECH_HSH_STEMS`** (in `mech_editor.py`)
Maps lowercase dir name ? canonical stem for `hsh/hud/`, `hsh/MFD/`, `hsh/radar/hud/`.
Source: `huddamage.cpp` `texturename[]` array.
**`MECH_PORTRAIT_OVERRIDES`** (in `mech_editor.py`)
Maps lowercase dir name ? portrait stem for `hsh/Mechs/` where the DNL string differs from the chassis table key.
Source: `DNL_*` entries in `Gameleap/code/mw4/Code/scriptstrings/StringResource.rc`.
For all other mechs, the portrait stem is derived dynamically from `MechChassisTable.tbl` (display key, lowercased).
The Assets tab in the editor shows all four image types. When an image is missing, it displays:
```
Wants: hsh/<subdir>/<expected_filename>.bmp
```
so the user knows exactly what to rename or create.
+64
View File
@@ -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
1 Chassis InternalLocation Model Site AmmoCount GroupIndex WeaponFacing
2 Archer LeftTorso LRM15 site_ldmissile 24 2 2
3 Archer RightTorso LRM15 site_rdmissile 24 2 2
4 Ares Special2 ClanLRM10 site_lmissileport 24 2 2
5 Ares Special2 ClanLRM10 site_missileport 24 2 2
6 Ares Special2 ClanLRM10 site_rmissileport 24 2 2
7 AssassinII Special1 LRM5 site_missileport 24 2 2
8 Atlas LeftTorso LRM20 site_lmissileport 12 2 2
9 Avatar LeftTorso LRM5 site_lmissileport 24 2 2
10 Avatar RightTorso LRM5 site_rmissileport 24 2 2
11 Avatar LeftTorso LRM10 site_lmissileport 24 2 2
12 Avatar RightTorso LRM10 site_rmissileport 24 2 2
13 Awesome CenterTorso LRM5 site_ctorsoport 24 2 2
14 Battlemaster RightTorso MediumLaser site_rdtorsoport 1 1
15 Battlemaster LeftTorso MediumLaser site_ldtorsoport 1 1
16 BattlemasterIIC RightTorso ClanERMediumLaser site_rdtorsoport 1 1
17 BattlemasterIIC LeftTorso ClanERMediumLaser site_ldtorsoport 1 1
18 Black Lanner Special2 ClanSRM6 site_rmissileport 15 2 2
19 Black Lanner Special1 ClanLRM10 site_lmissileport 24 2 2
20 Bushwacker Special1 LRM5 site_missileport 24 2 2
21 Bushwacker Special1 LRM5 site_missileport 24 2 2
22 Catapult LeftArm LRM20 site_lmissileport 12 2 2
23 Catapult RightArm LRM20 site_rmissileport 12 2 2
24 Cauldron-Born Special1 ClanLRM10 site_rmissileport 24 2 2
25 Cauldron-Born Special2 ClanLRM10 site_lmissileport 24 2 2
26 Chimera RightTorso LRM5 site_missileport 24 2 2
27 Chimera RightTorso LRM5 site_missileport 24 2 2
28 Chimera RightTorso LRM5 site_missileport 24 2 2
29 Chimera RightTorso LRM5 site_missileport 24 2 2
30 Cyclops LeftTorso LRM10 site_lmissile 24 2 2
31 Cougar LeftTorso ClanLRM10 site_lmissileport 12 2 2
32 Cougar RightTorso ClanLRM10 site_rmissileport 12 2 2
33 Deimos Special1 ClanLRM15 site_lmissileport 16 2 2
34 Deimos Special2 ClanLRM15 site_rmissileport 16 2 2
35 Dragon CenterTorso LRM10 site_missleport 24 2 2
36 Flea LeftTorso SmallLaser site_ltorsoport 1 1
37 Flea RightTorso SmallLaser site_rtorsoport 1 1
38 Grizzly LeftTorso CLANLRM10 site_missleport 24 2 2
39 Hellhound LeftTorso ClanLRM10 site_missileport 12 2 2
40 Mad Cat Special1 ClanLRM10 site_lmissileport 24 2 2
41 Mad Cat Special2 ClanLRM10 site_rmissileport 24 2 2
42 Mad Cat MKII Special2 ClanLRM15 site_lmissileport 16 2 2
43 Mad Cat MKII Special1 ClanLRM15 site_rmissileport 16 2 2
44 Masakari LeftTorso ClanLRM10 site_lmissleport 24 2 2
45 Masakari LeftTorso ClanLRM10 site_ltorsoport 24 2 2
46 Mauler LeftTorso LRM5 site_lmissileport 24 2 2
47 Mauler LeftTorso LRM5 site_lmissileport 24 2 2
48 Mauler LeftTorso LRM5 site_lmissileport 24 2 2
49 Mauler RightTorso LRM5 site_rmissileport 24 2 2
50 Mauler RightTorso LRM5 site_rmissileport 24 2 2
51 Mauler RightTorso LRM5 site_rmissileport 24 2 2
52 Raven RightTorso LRM5 site_rtorsoport 24 2 2
53 Sunder LeftTorso MediumLaser site_ldtorsoport 1 1
54 Sunder RightTorso MediumLaser site_rdtorsoport 1 1
55 Templar LeftTorso MediumPulseLaser site_ldrtorsoport 1 1
56 Templar RightTorso MediumPulseLaser site_rdrtorsoport 1 1
57 Thor Special1 CLANLRM10 site_missileport 24 2 2
58 Uziel Special1 LRM10 site_missileport 24 2 2
59 Vulture LeftTorso ClanLRM5 site_lmissileport 24 2 2
60 Vulture RightTorso ClanLRM5 site_rmissileport 24 2 2
61 Vulture LeftTorso ClanLRM10 site_lmissileport 24 2 2
62 Vulture RightTorso ClanLRM10 site_rmissileport 24 2 2
63 Wolfhound CenterTorso ClanERMediumLaser site_reartorsoport 1 1
64 Zeus RightTorso MediumPulseLaser site_reartorsoport 1 1
+45
View File
@@ -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,
1 Chassis InternalLocation Model Site AmmoCount GroupIndex WeaponFacing
2 Ares Special1 ClanERSmallLaser site_lgunport 1
3 Ares Special1 ClanERSmallLaser site_rgunport 1
4 Ares Special2 ClanLRM10 site_lmissileport 24 2 2
5 Ares Special2 ClanLRM10 site_missileport 24 2 2
6 Ares Special2 ClanLRM10 site_rmissileport 24 2 2
7 AssassinII Special1 LRM5 site_missileport 24 2 2
8 Atlas Special1 AC20 site_rtorsoport 10 1
9 Atlas Special2 SRM6 site_llmissile 15 2
10 Avatar Special1 MachineGun site_ltorsoport 200 1
11 Avatar Special1 MachineGun site_rtorsoport 200 1
12 Battlemaster Special2 PPC site_rdgunport 1
13 Battlemaster Special1 SRM6 site_missile 15 2
14 BattlemasterIIC Special1 ClanSSRM6 site_missile 15 2
15 Behemoth Special1 LargeLaser site_ctorsoport 1
16 BehemothII Special1 LargeLaser site_ctorsoport 1
17 Black Lanner Special2 ClanSRM6 site_rmissileport 15 2 2
18 Black Lanner Special1 ClanLRM10 site_lmissileport 24 2 2
19 Brigand Special2 MediumLaser site_ltorsoport 1
20 Brigand Special1 MediumLaser site_rtorsoport 1
21 Bushwacker Special1 LRM5 site_missileport 24 2 2
22 Bushwacker Special1 LRM5 site_missileport 24 2 2
23 Cauldron-Born Special1 ClanLRM10 site_rmissileport 24 2 2
24 Cauldron-Born Special2 ClanLRM10 site_lmissileport 24 2 2
25 Cyclops Special1 MediumPulseLaser site_gunport 1
26 Deimos Special1 ClanLRM15 site_lmissileport 16 2 2
27 Deimos Special2 ClanLRM15 site_rmissileport 16 2 2
28 Hauptmann Special1 ClanUltraAC20 site_rutorsoport 16 1
29 Hellspawn Special1 SSRM2 site_rmissileport 50 2
30 HollanderII Special2 SmallPulseLaser site_cltorsoport 1
31 HollanderII Special2 SmallPulseLaser site_crtorsoport 1
32 HollanderII Special1 GaussRifle site_rtorsoport 16 1
33 Hunchback Special1 AC10 site_rutorsoport 20 1
34 Loki Special1 ClanSSRM6 site_missileport 15 2
35 Mad Cat Special1 ClanLRM10 site_lmissileport 24 2 2
36 Mad Cat Special2 ClanLRM10 site_rmissileport 24 2 2
37 Mad Cat MKII Special2 ClanLRM15 site_lmissileport 16 2 2
38 Mad Cat MKII Special1 ClanLRM15 site_rmissileport 16 2 2
39 Rifleman Special1 MediumLaser site_ltorsoport 1
40 Rifleman Special1 MediumLaser site_rtorsoport 1
41 Solitaire Special1 ClanERLargeLaser site_rtorsoport 1
42 Thor Special1 CLANLRM10 site_missileport 24 2 2
43 Uziel Special1 LRM10 site_missileport 24 2 2
44 Vulture Special1 ClanMachineGun site_ltorsoport 200 1
45 Vulture Special1 ClanMachineGun site_rtorsoport 200 1
+145
View File
@@ -0,0 +1,145 @@
[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
NoReturn=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
+146
View File
@@ -0,0 +1,146 @@
[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
NoReturn=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
+377
View File
@@ -734,7 +734,384 @@ keeping old-RIO (type 0) protocol behavior byte-identical:
call it via `-Command "& '...driver.ps1' game-start '-tbaud 115200'"``-File` binding call it via `-Command "& '...driver.ps1' game-start '-tbaud 115200'"``-File` binding
rejects dash-leading positional args, and `Start-Process -ArgumentList` doesn't re-quote. rejects dash-leading positional args, and `Start-Process -ArgumentList` doesn't re-quote.
## 📋 Branch `mfdsplit`: mech loadouts, time list, build fixes (2026-07-18)
### Mech loadout changes
- **Battlemaster IS** (`Content\Mechs\Battlemaster\battlemaster.subsystems`): replaced lone
MediumPulseLaser default with full stock IS loadout — PPC (Special2), 6×ML (3 RT, 3 LT),
2×MG (LA, 200 rds), SRM6 (Special1, 15 rds), all GroupIndex=1 except SRM6 (group 2).
- **Battlemaster Clan 2C** (`battlemaster2c.subsystems`): ER PPC (RA), 6×ER ML (3 RT, 3 LT),
2×Clan Gauss (LA, 16 rds each), Clan SSRM6 (Special1, 15 rds).
- **Behemoth / Behemoth2** (`.subsystems`): moved Gauss rifles from weapon group 3 → group 1
(3 occurrences each; gauss rifles now in group 1 alongside other main weapons).
### MP time-limit list fix (ConLobbyMission.script)
- Expanded from 9 → 18 entries (115, 20, 25, 30 min); `max_displayed=10` so dropdown scrolls.
- Fixed bare `else if` (missing braces) that caused a null-reference crash in the console lobby
when the commit was merged from `main`. This was the root cause of the `aa500be7` regression.
- Fixed `i==5` vs `i==6` max_displayed assignment for time vs radar dropdowns.
### Resource builder fix (build-resources.ps1) — VM / generic adapter support
- Builder now always runs with `-window` (windowed mode + DDrawCompat). Fullscreen native DDraw
fails on VMs with generic Microsoft display adapters (no hardware DDraw); windowed DDrawCompat
works on all tested configs including VMs.
- dgVoodoo2 D3D DLL interceptors (`D3D8.dll`, `D3D9.dll`, `D3DImm.dll`) in the working dir
silently break the builder (it exits 0 without building anything). These files were left over
from the abandoned dgVoodoo2 experiment (commit `87e25677`) — removed from repo (`git rm`).
The build script also moves any such files aside defensively via the `$dgvMoved` block.
- Removed all dead code for fullscreen fallback, bitdepth patching, ddraw move-aside logic.
- `dgVoodoo.conf` / `dgVoodooCpl.exe` also removed from `Gameleap\mw4\` (no longer in use).
- Expected behaviour on VM: a "Hardware Error: not compatible with MechWarrior 4" dialog appears
at the end of the build — this is a GameOS hardware-capability warning, NOT a fatal error.
Click OK; the .mw4 packages are built correctly regardless.
### Source tree Korean → English translation + UTF-8 cleanup (2026-07-18)
- Translated all EUC-KR/CP949 Korean developer comments to English across **84 source files**
(~876 lines). Zero Korean bytes remain outside intentional font-table headers (D3FFontEdit2/
fontedit `all.h` etc.). Files are now clean UTF-8 (no BOM), safe for any modern editor.
- Notable functional translations: `recscore.cpp` body-part return values and kill-announcer
format strings (gameplay-visible on Korean Windows; now English on all systems); `nonmfc.h`
assert dialog; GosView profiler `킪``us` (microseconds).
- Latin-1 chars converted to proper UTF-8: © in 3dsmax4/Maxscrpt headers (82 files), ® in
`gosHelp/Remote.cpp`, · bullet points in `ai command.hpp`, Û/ß in AnimationSuite headers.
- Font table `*.h` files (`D3FFontEdit2/`, `fontedit/`) intentionally left as-is (raw byte
values in C array data, not text).
- `korean_diff.html` (side-by-side GitHub-style diff, ~873 KB) committed as documentation.
### Language DLL: English version from source
- `Gameleap\mw4\Language.dll` and `MW4\Language.dll` replaced with the freshly compiled English
build from `Language - Win32 English` config (`Language.dsp`). Fixes Korean button labels in
the GameOS exception/crash dialog (`??? ??...` / `??` / `???` → More Details / Continue / Exit).
The old binary was the original Korean build from the 2009 dev machine.
### mw4print v2.0 additions
- **MySQL export** (`dbexport.h`/`dbexport.cpp`): late-bound runtime load of `libmysql.dll`
(no compile-time MySQL SDK needed). Exports match data (match, player_result, pvp, optional
event tables) to an external MySQL server after each print job. Schema in `db_schema.sql`.
Config via `mw4print.ini [MySQLExport]`; UI via File → Database Settings (Ctrl+D).
- **Configurable banner text**: File → Banner Setting... edits the bottom-of-sheet URL string
(was hardcoded `WWW.MECHJOCK.COM`). Persisted to `options.ini [battle tech print] BannerText=`.
- **libmysql.dll** (MySQL Connector/C 32-bit) added to `Gameleap\mw4\` so deploy copies it
alongside `mw4print.exe`.
- Version bumped to **2.0**, copyright year updated to **2026**.
## 📋 MFD mode 4: right device stagger fix (2026-07-18, eaa5fd3)
Root cause: `CMFD_Device::BeginScene()` cleared BOTH MFD device back-buffers at `sh_step==0`.
But in mode 4 the right MFD flip also fires at `sh_step==1` (= old `sh_step==0` after the
stagger increment), so it presented a just-cleared buffer — only the grid, no channel data.
Fix: `BeginScene()` now only clears/grids the LEFT device at `sh_step==0`. New `BeginSceneRight()`
(added to `render.cpp` / `render.hpp`, called from `WinMain.cpp`) clears/grids the RIGHT device at
`sh_step==1` — one frame AFTER the right flip — so channels 34 render into a fresh buffer before
the next flip. Mode 1 is unchanged.
Mode 4 cycle (with stagger):
- `sh_step 0`: radar + left `BeginScene` (clear + grid); no flip
- `sh_step 1`: flip right MFD (shows channels 34 from previous cycle) + right `BeginScene` (clear + grid)
- `sh_step 24`: channels 02 → left device
- `sh_step 56`: channels 34 → right device
- `sh_step 0` (next): flip radar + left MFD (shows channels 02 from previous cycle)
Files: `CoreTech/Libraries/GameOS/WinMain.cpp`, `render.cpp`, `render.hpp`.
## 📋 Linux→Windows development workflow (2026-07-19, 55b9bfc5)
`build-env/sync-to-windows.sh` — rsync script that pushes all source, content, toolchain, and
assets to the Windows build machine at `/vwe/firestorm`. Excludes generated build outputs
(`rel.bin/`, `dbg.bin/`, `*.mw4`, `*.dep`), `.git`/LFS objects, `_UNUSED/`, and the game deploy
dir (`MW4/`). Run from Linux before triggering a Windows build.
## 📋 ddraw.dll removed from repo; build script moves it aside (2026-07-19, 0ceba9c7, 24825ff3)
`Gameleap/mw4/ddraw.dll` (DDrawCompat) removed from git (was LFS-tracked); now lives as
`ddraw.dll.old` in the same dir for reference. `deploy-editor.ps1` installs DDrawCompat as
`ddraw.dll` at deploy time (the editor needs it for its windowed D3D7 viewport).
`build-resources.ps1` moves `ddraw.dll` aside (`.buildaside`) before running `MW4pro.exe`
because **DDrawCompat is fatal to MW4pro.exe in BOTH windowed and fullscreen modes**, then
restores it in `finally`. The same block also defensively covers dgVoodoo2 interceptors
(`D3D8/D3D9/D3DImm.dll`) in case they reappear.
## 📋 Branch `5.1.0b-in-progress`: multiplayer + RIO + source cleanup (2026-07-19)
### ConLobby V5.1.0b1 — Super6 mech rotation (c768f7c4)
Changes from Buddy 'Highlight' Taylor (MCHL), merged manually:
- Console version string bumped to **V5.1.0b1**.
- `ROOKIEMECH` defines expanded from 4 → **6 mechs**: added Archer (ID=1) and Warhammer (ID=62).
- 16-slot default assignments cycle through all 6 Super6 mechs.
- Right-click randomizer expanded from `random(0,3)``random(0,5)`.
### CRIOMAIN.CPP — Korean translation + RIO poll timeout scaling (16fca6c4, a712002f)
- Translated all EUC-KR/CP949 Korean developer comments (~35 lines) to English. File re-saved
as clean UTF-8. CRLF line endings preserved (`* -text` in `.gitattributes`).
⚠️ **Encoding hazard:** always read/write CRIOMAIN.CPP as binary (or with an explicit encoding
codec). Python text-mode `readlines()` silently strips `\r`, causing a 3000+-line git diff when
every line's `\r\n` becomes `\n`. If that happens, restore CRLF with `re.sub(b'(?<!\r)\n', b'\r\n', data)` in binary mode, then amend the commit.
- Added **`g_dwRIOPollTimeout`** global (default 50 ms). Computed in `SetupConnection` before the
receive loop using: `clamp(⌈480000/baud⌉, 5, 50)`. Preserves 50 ms at 9600 baud; floors at
5 ms for 115200 baud. Implemented with explicit ternary — **`min`/`max` are undeclared in this
translation unit under VC6** (not pulled in by CRIOMAIN's includes); use ternary or `__min`/`__max`.
### 16 pilots + 1 cameraship in multiplayer (f76dc05f)
`MW4Shell.cpp`:
- `CTCL_DefaultHostSetup` (non-coop): `Environment.NetworkMaxPlayers` set to
`params->m_maxPlayers + (CTCL_GetTeslaCountAll() - CTCL_GetTeslaCount())`.
The delta = camera-only seats (Tesla seats not assigned to pilots), reserving one extra
DirectPlay slot per cameraship so the 17th connection isn't rejected.
- `SetNetworkMissionParamater / PLAYER_LIMIT_PARAMETER`: same formula applied at runtime when
host changes the player limit. `gos_NetServerCommands(gos_Commend_UpdateMaxPlayers)` still called;
`break` must be present in this case (was accidentally dropped once — fall-through to
`JOIN_IN_PROGRESS_PARAMETER` corrupts `m_joinInProgress`).
- COOP branch unchanged (capped at 9+bots; no camera seat needed there).
`ConLobby.script`: launch guard `nTempPlayerCount > 16` raised to `> 17` so the cameraship
connection doesn't trigger "Too many player/bots".
### hsh/ BMP canonical renames (5813aeb6, 2026-07-23)
All `hsh/MFD/*.bmp` and `hsh/Mechs/*.bmp` filenames reconciled against the canonical stems
expected by game code. The engine loads MFD images via `huddamage.cpp` `texturename[]` array
(lowercase, no spaces) and Mechs portraits via `GetLocString` DNL strings (mixed-case with
spaces). Any mismatch = silently missing image at runtime.
Key renames:
- `hsh/MFD/assassinii.bmp``assassin2.bmp` (matches `texturename[]` canonical)
- `hsh/Mechs/battlemasteriic.bmp``battlemaster iic.bmp`
- `hsh/Mechs/mad cat mk.ii.bmp``mad cat mkii.bmp`
- `hsh/Mechs/behemoth ii.bmp` added (was absent)
Most other files in both directories are LFS pointer updates only (content unchanged).
### RookieMission configurable defaults via options.ini (5813aeb6, 2026-07-23)
CTCL (console) arcade mode has a "Rookie Mission" quick-launch that previously hardcoded all
game params. Now all 13 params are overridable from an `[RookieMission]` section in
`options.ini` (read by `CTCL_SetCDSP` at startup):
- `MW4Shell.cpp`: added 14 `g_` globals (`g_szRookieMission`, `g_nRookieGameType`, and 12
numeric params); registered as `gosScript_RegisterVariable` in `StartUp`/`ShutDown`;
`CTCL_SetCDSP` reads the `[RookieMission]` page via `NotationFile` and populates them.
Defaults: `"ScarabStronghold - Attrition"`, GameType=2 (Attrition), UnlimitedAmmo=1, all
others zero. `g_nRookieTimeLimit=-1` means "use the server's current time setting".
- `ConLobbyMission.script`: all hardcoded values in `MAIL_SET_ROOKIE_MISSION` handler replaced
with `$$g_szRookieMission$$` / `$$g_nRookieXxx$$` references.
- Requires rebuild: `MW4.exe` (Release + Profile).
### Mechlab turn rate label (5813aeb6, 2026-07-23)
`StringResource.rc` `IDS_ML_CH_TURNRATE`: "Turn Rate (Degrees/Sec.):" →
"Turn Rate (Top Speed Rad/Sec):" to match the actual `.data` field semantics
(`TopSpeedTurnRate` is in rad/s at top speed, not deg/s).
Requires rebuild: `ScriptStrings.dll`.
### BTFrstrm design documentation (840bc96c, 2026-07-23)
Two Word documents added to `BTFrstrm/`:
- `MechDependencyTree.docx` — dependency relationships between mech chassis/variants.
- `Special_Zones.docx` — documentation of special zone types used in maps/missions.
### mech_loadouts.md: MechEditor data model (0344418a, 2026-07-23)
`BTFrstrm/mech_loadouts.md` extended with a full reference section documenting the
MechEditor web app (`/home/rich/Repositories/MechEditor/mech_editor.py`, localhost:8765):
every `.data`/`.instance`/`.subsystems` field parsed, conversions performed (m/s ↔ kph,
rad/s ↔ deg/s), and `hsh/` naming rules for MFD/Mechs/HUD/Radar images. Canonical
reference for future mech data work.
### Load File autoconfig stabilization + docs update (2026-07-24)
End-to-end Load File flow for the console lobby was stabilized and verified with a
full-delta regression INI (all mission options + all 16 slots changed away from rookie
defaults), then round-tripped back via the Default button.
Key fixes in `ConLobby.script` / `ConLobbyMission.script`:
- Eliminated first-click vs second-click drift by moving auto-load to a dedicated
deterministic mission path and preventing redraw-time decal mutation.
- Corrected decal handling: map INI decal IDs to lobby dropdown indices, clamp invalid
indices, and show actual decal IDs in labels.
- Corrected mission+map sequencing: game type now rebuilds map list first; mission name
then resolves against that list (with fallback to map index 0).
- Fixed option-state application so first click applies all options (visibility/weather/
time/radar/heat/friendly fire/splash/unlimited/jam/advance/armor) without needing a
second click.
- Fixed Weapon Jam checkbox visibility refresh when set via Load File (UI now re-inits
correctly when heat/advanced states are applied).
New supported autoconfig key:
- Added `NoReturn=0|1` under `[mission]`:
- parser + script variable in `MW4Shell.cpp` (`g_nAutoNoReturn`),
- application in `ConLobbyMission.script` (`RESPAWN_LIMIT_PARAMETER`),
- docs + sample INIs updated.
Docs updates:
- `BTFrstrm/autoconfig-file-spec.html` corrected for real behavior:
- missing mission keys/section apply defaults (not current UI values),
- missing `MissionName` now falls back to first map for that game type,
- added `NoReturn` semantics and examples.
## 📋 STEP 10: Four-monitor MFD bring-up, display diagnostics, and the native-DirectDraw
## exclusive-mode wall (2026-07-25)
A long, dense session on the new 4-monitor bench (`MR_new`: AMD FirePro W4100, 4 outputs,
Win10). Everything below is empirical — measured on real hardware, not inferred.
### The root problem that made all of this hard
`CHSH_Device::InitFirst` / `InitSecond` (`CoreTech\Libraries\GameOS\render.cpp`) **discarded
every single `HRESULT`** (`SetCooperativeLevel`, `SetDisplayMode`, `CreateSurface`,
`GetAttachedSurface`, `QueryInterface`, `CreateDevice`) and **returned `true`
unconditionally**. A panel that failed to open produced no error, no crash and no log entry —
the monitor simply stayed on the desktop. SPEW is compiled out of shipping builds, so there
was no way to see any of it. **Fixing that visibility was what unblocked the whole session.**
### ✅ Diagnostics added (KEEP THESE — they are why everything below was findable)
- **`gos-displays.txt`** (written next to the exe by `VideoCard.cpp` `LogDisplayDevices()`):
`NumDevices`/`NumHWDevices`/`NumMonitors`, every DirectDraw device + `hw_rasterization`,
the role assignment (`FullScreenDevice`/`g_nNonDualHead`/`g_nDualHead`/`g_nDualHead2`/
`g_nMFD1`/`g_nMFD2`), `-tmon` APPLIED/REJECTED per slot, and the decisive
"mode 4 requires BOTH mfd1 and mfd2" line.
- **Per-call HRESULT logging** in `InitFirst`/`InitSecond` via `HSH_LogInit()` / `HSH_CheckHR()`
/ `HSH_HRName()` (27 `DDERR_*` codes decoded by name). Appends to the same file; each line is
written and flushed individually so **the log survives a crash**.
- **`gos-fps.txt`** — new **`-fps`** switch (`WinMain.cpp` `GOS_LogFrameRate`, hooked onto the
existing `frameRate` global). Per-second: frames, avg fps, **5% low**, worst frame in ms,
and a count of frames over 2x average ("hitches"), plus a **session summary** at exit with
true whole-session 1% / 0.1% lows (computed from a 0.5 ms-bucket histogram). Works in
**Release** — the engine's own `AddDebugData("FrameRate")` is `#ifdef LAB_ONLY`
(`MWMission.cpp`) so it only exists in `MW4pro.exe`. Off unless `-fps` is given (a global
read + branch when absent, no file created).
- ⚠️ **Lesson from the first real run: the instrument was measuring itself.** The original
version wrote one line per second straight to the file. The frame time is recorded
*before* the line is emitted, so the `WriteFile` cost landed in the **next** frame —
producing exactly one inflated frame every second (median worst-frame 24.4 ms against a
16.7 ms vsync interval, in 82% of seconds). Output is now buffered in memory and flushed
only when full or at exit (`atexit`), so a normal session performs no writes while
running. Trade-off: a hard crash loses the un-flushed tail — `gos-displays.txt` is the
crash-survivable log, this one is a measurement instrument.
- Also fixed: a "1% low" over 60 samples/sec degenerates to `nFrames/100 = 0` → clamped to
1 → literally the worst frame restated, so the column was redundant. Per-second is now a
5% low (worst 3-of-60); true 1% / 0.1% lows are in the session summary. And a single
frame longer than a second (a level load) no longer spills into following buckets and
emits a run of bogus one-frame rows.
### ✅ Crash-safety fix (independent of everything else, worth keeping)
`hsh_initialized` was set **unconditionally** after panel init. A failed panel therefore left
null surfaces and a null `IDirect3DDevice7` behind, and the per-frame path called straight
through them. Now: all four `InitSecond` overrides (`CMR`/`CRadar`/`CMFD`/`CMFDRight`) bail on
base failure, `CMFD_Device::InitFirst` reports the real result instead of always `true`, and
`hsh_initialized` is only set when the panels genuinely came up → **the game runs without MFDs
instead of dying**.
- **Crash signature to recognise:** `call [ecx+0x44]` with `ECX=0` = `IDirectDrawSurface7::GetDC`
on a never-created surface (verified against `build-env\dx7asdk\include\ddraw.h` vtable order).
Reported as `EXCEPTION : Attempt to read from address 0x00000044`.
### ✅ AppCompat shim — the single most important operational fact
**`DWM8And16BitMitigation` is keyed on the executable's FULL PATH.** A copy of the game at a
new path silently loses it. MW4 renders at `bitdepth=16` and **modern GPUs expose ZERO 16-bit
display modes** — the shim *synthesises* them (proved directly: crash dump shows
`16 bit modes :` EMPTY without the shim, populated with it).
- **Without the shim the error message actively misleads.** GameOS raises
`GOS_DXRASTERIZER_NOFULLSCREEN` — *"Another application is preventing use of full screen
mode"* (`DXRasterizer.cpp:~1125`). That is a **catch-all** fired after every `SetDisplayMode`
attempt fails; it even scans for NetMeeting. It sends you hunting for a conflicting program
that does not exist. The real cause is the missing shim / absent 16-bit modes.
- **NEW: `build-env\set-appcompat.ps1` + `set-appcompat.bat`** — self-locating (`$PSScriptRoot`)
one-click installer. Applies the layer to `MW4.exe`/`MW4pro.exe`/`MW4Ed2.exe` sitting next to
it, wherever that install lives; HKCU always, HKLM too if elevated (note the HKLM value format
differs — it carries a leading `$` marker). Verifies by reading back; detects the
`HIGHDPIAWARE`-only entry that *suppresses* the auto-shim (the original STEP 5 bug).
`-Remove` / `-WhatIfOnly` supported. **`deploy-mw4.ps1` now ships both into every deployment.**
### ✅ Exclusive fullscreen DOES work on Win10 without dgVoodoo2
Confirmed on the W4100 with system `ddraw.dll` and dgVoodoo2 physically removed: `MW4.exe`
alt-enters to exclusive fullscreen correctly **once the shim is applied to that exe path**.
Windowed mode also works natively with no shim at all (windowed sets
`Environment.bitDepth = DesktopBpp` = 32, so there is no mode switch). Console/shell confirmed
windowed; a **full mission windowed is still untested**.
### ❌ Native multi-monitor MFD is BLOCKED — and no flag combination fixes it
The panels' cooperative-level call was genuinely wrong (a latent 2002 bug): every panel asked to
be **both** the process focus window **and** its own device window, on the one shared `hWindow`,
*after* the main device had already taken exclusive mode on it. The main device
(`DXRasterizer.cpp:~1027`) already uses the correct two-call idiom
(`SETFOCUSWINDOW` alone, then `EXCLUSIVE|FULLSCREEN`) — tagged `//sanghoon`, same author. The
panels never were.
A new **`-tcoop <0-5>`** switch was added to test every plausible form on real hardware without a
rebuild between attempts. Results (no dgVoodoo2, shim applied, `-tmfds 4`):
| `-tcoop` | Flags | Result |
|---|---|---|
| 0 | `SETFOCUSWINDOW\|CREATEDEVICEWINDOW\|ALLOWREBOOT\|EXCLUSIVE\|FULLSCREEN` (legacy) | `DDERR_EXCLUSIVEMODEALREADYSET` |
| 1 | `CREATEDEVICEWINDOW\|EXCLUSIVE\|FULLSCREEN` (no focus claim) | `DDERR_INVALIDPARAMS` |
| 2 | `SETFOCUSWINDOW`, then `CREATEDEVICEWINDOW\|…` | `DDERR_INVALIDPARAMS` |
| 3 | `SETFOCUSWINDOW`, then `EXCLUSIVE\|FULLSCREEN` | 1st panel collides; **that collision steals exclusive from the main display**, after which panels 2+3 fully init (radar reached `CreateDevice(HAL) = DD_OK`). Side effect: desktop left at 1920x1080 **16bpp**. Not viable. |
| 4 | `EXCLUSIVE\|FULLSCREEN` only | `DDERR_EXCLUSIVEMODEALREADYSET` on **all** panels |
| 5 | `ALLOWREBOOT\|EXCLUSIVE\|FULLSCREEN` | `DDERR_EXCLUSIVEMODEALREADYSET` on **all** panels |
**CONCLUSION: on modern Windows only ONE DirectDraw object per process may hold exclusive
fullscreen.** The main display takes it; every secondary panel is refused. XP allowed multiple;
**dgVoodoo2 allows it because it is a full reimplementation of ddraw, not bound by that rule.**
=> **dgVoodoo2 cannot be removed for `-tmfds 1/3/4` by fixing flags.** Default stays `-tcoop 0`.
(`-tcoop` is retained: it is how this was settled and will re-settle it on different hardware.)
### ✅ Working 4-monitor config (WITH dgVoodoo2)
- **dgVoodoo2 Scaling mode MUST be "Stretched, Keep Aspect Ratio".** Plain "Stretched" fails
*silently*: main + radar go fullscreen black, both MFD monitors keep showing the desktop, and
**every DirectDraw call still returns `DD_OK`** — the devices are alive but dgVoodoo2 never
drives those outputs. Diagnosed with a temporary per-panel colour-flash test (since removed).
- Device index → physical monitor is **1:1** on this bench (colour test confirmed): main=0,
radar=1, mfd-left=2, mfd-right=3, so `-tmon 1,2,3,4` is identical to auto-detection.
- **Confirmed working end-to-end: all three secondary panels present, full mission played.**
- ⚠️ **dgVoodoo2 is deliberately NOT in the repo and must NOT be — it breaks Windows XP
deployments.** The pod fleet is mixed: XP pods need native DirectDraw and nothing else, while
Win10/11 pods need dgVoodoo2 for any MFD mode. Shipping it in the build (or having
`deploy-mw4.ps1` place it) would push a Win10-only dependency onto XP machines and break them.
It stays an **installed-per-machine, OS-dependent prerequisite** set up by the pod owner on
Win10/11 only. `dgVoodoo.conf`/`dgVoodooCpl.exe` were removed in `0ceba9c7` for this reason —
do not "fix" that by re-adding them. The required setting (Scaling mode
`Stretched, Keep Aspect Ratio`, on the **General** tab) is documented in the pod-owner release
notes instead.
### 📐 Engine is 4:3 ONLY (relevant to every display decision)
`ImageHlp.cpp:~464` asserts the complete supported resolution set: **640x480, 512x384, 800x600,
960x720, 1024x768, 1280x1024 (5:4), 1600x1200**. There is no 16:9 mode and **no aspect
correction anywhere** in the codebase (the only `aspect` hits are texture-dimension caps and
CameraShip). On a 16:9 monitor a 4:3 image must be adapted by the scaler: plain stretch =
distorted (circles → ovals, reticle wrong); keep-aspect = correct geometry + pillarbox bars.
Native widescreen would require re-authoring every 2D/shell layout (all fixed 640x480 pixel
coordinates) — a content project, not a code tweak.
### 📐 Assessment: moving to borderless windowed (discussed, NOT started)
The only native path to multi-monitor, since it removes exclusive mode from the picture entirely.
Smaller than it sounds because the mechanisms already exist:
- The windowed present is already `wBlt(FrontBufferSurface, &Window, BackBufferSurface, …)`
a blit to an arbitrary screen rect. `Blt` stretches when the dest rect differs in size, so
aspect-preserving borderless output is **rect maths, not new machinery**.
- Clipper wrappers (`wCreateClipper`/`wSetClipper`/`wSetHWnd`) already exist in `DirectDraw.cpp`,
unused by the fullscreen path.
- **None of the drawing code changes** — panels already render into `pDDSTarget` and composite;
`DrawQuad`/`DrawTexture`/fonts/`SwapRightState` don't care whether the present is Flip or Blt.
- Work is confined to `render.cpp`, `DXRasterizer.cpp`, `WinMain.cpp` (+ a little `Windows.cpp`):
panel init → `DDSCL_NORMAL` + clipper + offscreen render surface (~150 lines); ~4 panel `Flip`
sites → `Blt`; break the `HSH_EnterFullScreen2()``EnterFullScreenMode()` coupling
(`DXRasterizer.cpp:~1132` is its ONLY call site, which is also why windowed mode currently
creates no panels at all); **new: explicit frame pacing** (windowed Blt has no vsync — this is
the same root cause as the known mechlab fast-spin bug).
- **Gains:** no dgVoodoo2, no shim, no 16-bit dependency, no exclusive-mode contention, aspect
under our control, and panels stay at their monitor's native mode so "this panel won't accept
640x480" becomes impossible.
- **Risk that decides it:** windowed D3D7 device creation is per-GPU (the *editor* hit
`DDERR_INVALIDOBJECT` on Win11 and needed DDrawCompat; the *game* succeeded natively on the
W4100). Version lockstep means one build must serve every pod.
- **Recommended staging:** (1) `-borderless` for the MAIN display only, default off; (2) convert
**one** panel (radar) — the small, make-or-break test of `DDSCL_NORMAL` + clipper +
D3D-on-offscreen on the target GPU; (3) all three panels; (4) retire dgVoodoo2 + shim. Keep
exclusive fullscreen switch-selectable indefinitely.
### Incidental findings
- **`-2dt` is not a recognised switch anywhere in the codebase**, despite appearing in production
`ctcl.ini` launch lines. Completely inert. (2D targets are already the default; `-3dt` is what
switches to the 3D model.)
- `NumHWDevices` (5) can exceed `NumDevices` (4) — it counts D3D device-enumeration callbacks, and
an adapter exposing both a HAL and a T&L HAL yields two. Benign; `InitSecond` hardcodes
`IID_IDirect3DHALDevice`.
- New switches are documented in `-help` (`-fps` under LOGGING AND DIAGNOSTICS, `-tcoop` under
DISPLAY AND VIDEO).
## Next steps (proposed) ## Next steps (proposed)
- [ ] (Decision pending) Borderless-windowed migration — see the staged assessment in STEP 10.
Step 2 (one panel) is the cheap, decisive experiment. Note this is the only route that would
remove the dgVoodoo2 prerequisite **without** breaking the XP pods, since it needs no external
DLL on either OS.
- [ ] Test a **full mission windowed** (only the console/shell has been verified windowed).
- [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\`).
- [ ] (Optional) Build Debug/Armor configs (need `dbg.bin`/`arm.bin` output dirs). - [ ] (Optional) Build Debug/Armor configs (need `dbg.bin`/`arm.bin` output dirs).
@@ -104,7 +104,7 @@ char *TimeToString( double secs )
else else
if( secs*1000000.f >= 1.0f ) if( secs*1000000.f >= 1.0f )
{ {
sprintf(TimeStr,"%.2f µS", secs*1000000.f); sprintf(TimeStr,"%.2f us", secs*1000000.f);
} }
else else
{ {
@@ -24,9 +24,9 @@ const char *DivStrings[] =
"1nS / div", // 10^-9 "1nS / div", // 10^-9
"10nS / div", // 10^-8 "10nS / div", // 10^-8
"100nS / div", "100nS / div",
"1µS / div", "1us / div",
"10µS / div", "10us / div",
"100µS / div", "100us / div",
"1mS / div", "1mS / div",
"10mS / div", "10mS / div",
"100mS / div", "100mS / div",
@@ -104,7 +104,7 @@ char *TimeToString( double secs )
else else
if( secs*1000000.f >= 1.0f ) if( secs*1000000.f >= 1.0f )
{ {
sprintf(TimeStr,"%.2f µS", secs*1000000.f); sprintf(TimeStr,"%.2f us", secs*1000000.f);
} }
else else
{ {
@@ -24,9 +24,9 @@ const char *DivStrings[] =
"1nS / div", // 10^-9 "1nS / div", // 10^-9
"10nS / div", // 10^-8 "10nS / div", // 10^-8
"100nS / div", "100nS / div",
"1µS / div", "1us / div",
"10µS / div", "10us / div",
"100µS / div", "100us / div",
"1mS / div", "1mS / div",
"10mS / div", "10mS / div",
"100mS / div", "100mS / div",
@@ -1032,19 +1032,19 @@ void __stdcall gos_SetViewport( DWORD LeftX, DWORD TopY, DWORD Width, DWORD Heig
// You can only clear the backbuffer or Z buffer on the FIRST setup viewport (outside the Begin/End Scene // You can only clear the backbuffer or Z buffer on the FIRST setup viewport (outside the Begin/End Scene
// //
//상훈 앞 //sanghoon begin
void __cdecl ClearTargetCameraBackBuffer() void __cdecl ClearTargetCameraBackBuffer()
{ {
D3DRECT rc={0,10,120,112}; D3DRECT rc={0,10,120,112};
wClear(d3dDevice7,1,&rc,D3DCLEAR_TARGET,0xFF00FFFF,0,0); wClear(d3dDevice7,1,&rc,D3DCLEAR_TARGET,0xFF00FFFF,0,0);
return ; return ;
} }
//상훈 뒤 //sanghoon end
void __stdcall gos_SetupViewport( bool FillZ, float ZBuffer, bool FillBG, DWORD BGColor, float top, float left, float bottom, float right, bool ClearStencil, DWORD StencilValue ) void __stdcall gos_SetupViewport( bool FillZ, float ZBuffer, bool FillBG, DWORD BGColor, float top, float left, float bottom, float right, bool ClearStencil, DWORD StencilValue )
{ {
//상훈짱... //sanghoon
//원래의 법칙에 어긋나는 행동이기 때문에 ASSERT를 무시한다. //This violates the normal rules, so we suppress the ASSERT.
//gosASSERT( !InsideBeginScene || !(FillZ || FillBG) ); //gosASSERT( !InsideBeginScene || !(FillZ || FillBG) );
// //
// Work out size of viewport // Work out size of viewport
@@ -47,11 +47,11 @@ extern DWORD gDisableJoystick;
bool DisablePolling=0; bool DisablePolling=0;
void CMRestoreEffects( int stick ); void CMRestoreEffects( int stick );
// 鉉 - start // hyun begin
int g_bUseOrgJoy = TRUE; int g_bUseOrgJoy = TRUE;
void (__stdcall *g_pfnRIO_Joy)(DIJOYSTATE& js) = NULL; // Check out Test .. void (__stdcall *g_pfnRIO_Joy)(DIJOYSTATE& js) = NULL; // Check out Test ..
bool g_bNoWeaponRangeCheck = false; bool g_bNoWeaponRangeCheck = false;
// 鉉 - end // hyun end
// //
// //
// Initialize the DirectInput devices // Initialize the DirectInput devices
@@ -479,7 +479,7 @@ extern DWORD EnableDisplayInfo;
if( EnableDisplayInfo==0 ) { if( EnableDisplayInfo==0 ) {
disp: disp:
sprintf(DisplayInfoText, "COIN: %d 코인이래요", g_nCoinCount); sprintf(DisplayInfoText, "COIN: %d coins", g_nCoinCount);
EnableDisplayInfo = 1; EnableDisplayInfo = 1;
} else if (EnableDisplayInfo==2) { } else if (EnableDisplayInfo==2) {
if( timeGetTime() < EndDisplayInfoTime+50 ) { if( timeGetTime() < EndDisplayInfoTime+50 ) {
@@ -100,11 +100,11 @@ IDirectDraw7* DDobject = NULL; // Primiary DirectDraw object (for persistant
IDirectDraw7* CurrentDDobject = NULL; // DirectDraw object for rendering (can be the same as DDObject) IDirectDraw7* CurrentDDobject = NULL; // DirectDraw object for rendering (can be the same as DDObject)
IDirectDrawSurface7* ZBufferSurface = NULL; // ZBuffer surface IDirectDrawSurface7* ZBufferSurface = NULL; // ZBuffer surface
IDirectDrawSurface7* RefZBufferSurface = NULL; // Referemce rasterizer ZBuffer surface IDirectDrawSurface7* RefZBufferSurface = NULL; // Referemce rasterizer ZBuffer surface
// //sanghoon marker
IDirectDrawSurface7* SH_TargetBufferSurface = NULL; IDirectDrawSurface7* SH_TargetBufferSurface = NULL;
IDirectDrawSurface7* SH_SwirlTexture= NULL; IDirectDrawSurface7* SH_SwirlTexture= NULL;
IDirectDrawSurface7* SH_GameEndTexture= NULL; IDirectDrawSurface7* SH_GameEndTexture= NULL;
// //sanghoon marker
DDSURFACEDESC2 BackBufferddsd; DDSURFACEDESC2 BackBufferddsd;
// //
@@ -167,7 +167,7 @@ float GammaSetting=0.0;
bool UseGammaCorrection=0; bool UseGammaCorrection=0;
float UserGamma=1.0f; float UserGamma=1.0f;
//¯-begin //sanghoon begin
bool use_shgui = false; bool use_shgui = false;
bool hsh_initialized=false; bool hsh_initialized=false;
bool hsh_mrdev_initialized=false; bool hsh_mrdev_initialized=false;
@@ -176,7 +176,7 @@ bool hsh_mrdev_initialized=false;
#include "coord.cpp" #include "coord.cpp"
//#include "hsh_dxras.cpp" //#include "hsh_dxras.cpp"
#include "render.hpp" #include "render.hpp"
//¯-end //sanghoon end
// //
// Value range 0-10,000, default 750 (See DirectX docs) // Value range 0-10,000, default 750 (See DirectX docs)
@@ -1021,11 +1021,11 @@ void EnterFullScreenMode()
// //
#ifdef LAB_ONLY #ifdef LAB_ONLY
//¯ //sanghoon
wSetCooperativeLevel( CurrentDDobject, hWindow, DDSCL_SETFOCUSWINDOW ); wSetCooperativeLevel( CurrentDDobject, hWindow, DDSCL_SETFOCUSWINDOW );
wSetCooperativeLevel( CurrentDDobject, hWindow, DDSCL_ALLOWREBOOT | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN ); wSetCooperativeLevel( CurrentDDobject, hWindow, DDSCL_ALLOWREBOOT | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN );
#else #else
//¯ //sanghoon
wSetCooperativeLevel( CurrentDDobject, hWindow, DDSCL_SETFOCUSWINDOW ); wSetCooperativeLevel( CurrentDDobject, hWindow, DDSCL_SETFOCUSWINDOW );
wSetCooperativeLevel( CurrentDDobject, hWindow, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN ); wSetCooperativeLevel( CurrentDDobject, hWindow, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN );
#endif #endif
@@ -1127,11 +1127,11 @@ void EnterFullScreenMode()
} }
} }
//¯-begin //sanghoon begin
if(use_shgui){ if(use_shgui){
HSH_EnterFullScreen2(); HSH_EnterFullScreen2();
} }
//¯-end //sanghoon end
// //
// Changed modes, create all the surfaces // Changed modes, create all the surfaces
@@ -1164,7 +1164,7 @@ void EnterFullScreenMode()
// Debugging information // Debugging information
// //
SPEW(( GROUP_DIRECTDRAW, "EnterFullScreenMode() Finished" )); SPEW(( GROUP_DIRECTDRAW, "EnterFullScreenMode() Finished" ));
// //sanghoon
} }
@@ -1289,7 +1289,7 @@ void DisplayBackBuffer()
else else
{ {
#if 0 #if 0
// //sanghoon marker
extern bool sh_game_started; extern bool sh_game_started;
static FILE* fp=0; static FILE* fp=0;
static recorded_count=0; static recorded_count=0;
@@ -1352,11 +1352,11 @@ extern bool sh_game_started;
pp=(double*)malloc(800*600*2); pp=(double*)malloc(800*600*2);
} }
} }
// //sanghoon marker
#endif #endif
wFlip( FrontBufferSurface,NULL,DDFLIP_DONOTWAIT );//|DDFLIP_INTERVAL2 ); wFlip( FrontBufferSurface,NULL,DDFLIP_DONOTWAIT );//|DDFLIP_INTERVAL2 );
// ħ.. //sanghoon marker..
// //sanghoon
//wFlip( FrontBufferSurface,NULL,DDFLIP_WAIT ); //wFlip( FrontBufferSurface,NULL,DDFLIP_WAIT );
} }
} }
@@ -1403,11 +1403,11 @@ extern bool sh_game_started;
// //
void DirectDrawRelease() void DirectDrawRelease()
{ {
//¯-begin //sanghoon begin
if(use_shgui){ if(use_shgui){
HSH_DirectDrawRelease2(); HSH_DirectDrawRelease2();
} }
//¯-end //sanghoon end
SPEW(( GROUP_DIRECTDRAW, "DirectDrawRelease()" )); SPEW(( GROUP_DIRECTDRAW, "DirectDrawRelease()" ));
SafeFPU(); SafeFPU();
@@ -1496,7 +1496,7 @@ void DirectDrawRelease()
wRelease( ZBufferSurface ); wRelease( ZBufferSurface );
ZBufferSurface=0; ZBufferSurface=0;
} }
// //sanghoon marker
//DirectDrawRelease //DirectDrawRelease
if( SH_TargetBufferSurface) if( SH_TargetBufferSurface)
{ {
@@ -1513,7 +1513,7 @@ void DirectDrawRelease()
wRelease( SH_GameEndTexture ); wRelease( SH_GameEndTexture );
SH_GameEndTexture=0; SH_GameEndTexture=0;
} }
// //sanghoon marker
if( GammaControlInterface ) if( GammaControlInterface )
{ {
wRelease( GammaControlInterface ); wRelease( GammaControlInterface );
@@ -1593,20 +1593,20 @@ void DirectDrawCreateDDObject()
// //
// Create the NULL (primary) DirectDraw object // Create the NULL (primary) DirectDraw object
// //
// //sanghoon marker
/* /*
wDirectDrawCreateEx( &DeviceArray[0].DeviceGUID, (void**)&DDobject, IID_IDirectDraw7, NULL ); wDirectDrawCreateEx( &DeviceArray[0].DeviceGUID, (void**)&DDobject, IID_IDirectDraw7, NULL );
// wDirectDrawCreateEx( &DeviceArray[Environment.FullScreenDevice].DeviceGUID, (void**)&DDobject, IID_IDirectDraw7, NULL ); // wDirectDrawCreateEx( &DeviceArray[Environment.FullScreenDevice].DeviceGUID, (void**)&DDobject, IID_IDirectDraw7, NULL );
wSetCooperativeLevel( DDobject, hWindow, DDSCL_NORMAL ); wSetCooperativeLevel( DDobject, hWindow, DDSCL_NORMAL );
CurrentDDobject=DDobject; CurrentDDobject=DDobject;
*/ */
// ҽ.. //sanghoon ..
//wDirectDrawCreateEx(&DeviceArray[0].DeviceGUID, (void**)&DDobject, IID_IDirectDraw7, NULL ); //wDirectDrawCreateEx(&DeviceArray[0].DeviceGUID, (void**)&DDobject, IID_IDirectDraw7, NULL );
wDirectDrawCreateEx(NULL, (void**)&DDobject, IID_IDirectDraw7, NULL ); wDirectDrawCreateEx(NULL, (void**)&DDobject, IID_IDirectDraw7, NULL );
wSetCooperativeLevel( DDobject, hWindow, DDSCL_NORMAL ); wSetCooperativeLevel( DDobject, hWindow, DDSCL_NORMAL );
CurrentDDobject=DDobject; CurrentDDobject=DDobject;
// //sanghoon marker
// //
// //
// //
@@ -1630,11 +1630,11 @@ bool SetupMode( bool FullScreen, DWORD Renderer )
BackBufferSurface=0; BackBufferSurface=0;
ClipperObject=0; ClipperObject=0;
ZBufferSurface=0; ZBufferSurface=0;
// //sanghoon marker
SH_TargetBufferSurface = 0; SH_TargetBufferSurface = 0;
SH_SwirlTexture=0; SH_SwirlTexture=0;
SH_GameEndTexture=0; SH_GameEndTexture=0;
// //sanghoon marker
Maind3dDevice7=0; Maind3dDevice7=0;
d3dDevice7=0; d3dDevice7=0;
DDSURFACEDESC2 ddsd; DDSURFACEDESC2 ddsd;
@@ -1993,7 +1993,7 @@ bool SetupMode( bool FullScreen, DWORD Renderer )
} }
wAddAttachedSurface( BackBufferSurface, ZBufferSurface ); wAddAttachedSurface( BackBufferSurface, ZBufferSurface );
// //sanghoon marker
{ {
DDSURFACEDESC2 rdesc; DDSURFACEDESC2 rdesc;
memset(&rdesc,0,sizeof(ddsd)); memset(&rdesc,0,sizeof(ddsd));
@@ -2019,7 +2019,7 @@ bool SetupMode( bool FullScreen, DWORD Renderer )
if(SUCCEEDED(wCreateSurface( CurrentDDobject, &rdesc, &SH_SwirlTexture, NULL ))){ if(SUCCEEDED(wCreateSurface( CurrentDDobject, &rdesc, &SH_SwirlTexture, NULL ))){
; ;
//ȭؽ . //Draw texture content to screen. .
} }
rdesc.dwFlags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT|DDSD_TEXTURESTAGE; rdesc.dwFlags = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT|DDSD_TEXTURESTAGE;
@@ -2031,11 +2031,11 @@ bool SetupMode( bool FullScreen, DWORD Renderer )
if(SUCCEEDED(wCreateSurface( CurrentDDobject, &rdesc, &SH_GameEndTexture, NULL ))){ if(SUCCEEDED(wCreateSurface( CurrentDDobject, &rdesc, &SH_GameEndTexture, NULL ))){
; ;
//ȭؽ . //Draw texture content to screen. .
} }
} }
// //sanghoon marker
// //
// Get the Z buffer pixel format (nVidia may always match front bit depth) // Get the Z buffer pixel format (nVidia may always match front bit depth)
// //
@@ -2258,7 +2258,7 @@ Failed:
wRelease( ZBufferSurface ); wRelease( ZBufferSurface );
ZBufferSurface=0; ZBufferSurface=0;
} }
// //sanghoon
//SetupMode //SetupMode
if( SH_TargetBufferSurface) if( SH_TargetBufferSurface)
{ {
@@ -2275,7 +2275,7 @@ Failed:
wRelease( SH_SwirlTexture ); wRelease( SH_SwirlTexture );
SH_SwirlTexture=0; SH_SwirlTexture=0;
} }
// //sanghoon
if( ClipperObject ) if( ClipperObject )
{ {
if( FrontBufferSurface ) if( FrontBufferSurface )
@@ -2578,7 +2578,7 @@ void DirectDrawCreateAllBuffers()
wRelease( ZBufferSurface ); wRelease( ZBufferSurface );
ZBufferSurface=0; ZBufferSurface=0;
} }
// //sanghoon marker
//DirectDrawCreateAllBuffers //DirectDrawCreateAllBuffers
if( SH_TargetBufferSurface) if( SH_TargetBufferSurface)
{ {
@@ -2595,7 +2595,7 @@ void DirectDrawCreateAllBuffers()
wRelease( SH_SwirlTexture ); wRelease( SH_SwirlTexture );
SH_SwirlTexture=0; SH_SwirlTexture=0;
} }
// //sanghoon marker
if( ClipperObject ) if( ClipperObject )
{ {
if( FrontBufferSurface ) if( FrontBufferSurface )
@@ -161,7 +161,7 @@ HRESULT wEndScene( IDirect3DDevice7* d3dDevice7 )
//Original //Original
//if( FAILED(result) ) //if( FAILED(result) )
//상훈 //sanghoon
if( FAILED(result) && result!=DDERR_SURFACELOST) if( FAILED(result) && result!=DDERR_SURFACELOST)
PAUSE(( "FAILED (0x%x - %s) - EndScene()",result,ErrorNumberToMessage(result))); PAUSE(( "FAILED (0x%x - %s) - EndScene()",result,ErrorNumberToMessage(result)));
@@ -46,6 +46,12 @@ videoDevices BufferedDevices[8];
int g_nDualHead = -1; // jcem int g_nDualHead = -1; // jcem
int g_nDualHead2 = -1; // jcem int g_nDualHead2 = -1; // jcem
int g_nNonDualHead = -1; // jcem int g_nNonDualHead = -1; // jcem
int g_nMFD1 = -1; // mode 4: left 640x480 MFD monitor
int g_nMFD2 = -1; // mode 4: right 640x480 MFD monitor
// [tmon] Operator override for display-device selection, in Main/Radar/MFD1/MFD2 order.
// -1 = leave that slot to auto-detection. Populated by the -tmon command-line switch,
// which is parsed in MW4Application's WinMain - that runs before FindVideoCards().
int g_naMonitorOverride[4] = { -1, -1, -1, -1 };
// MSL 5.03 Mechview // MSL 5.03 Mechview
int g_nMechViewType; // jcem : 0 - no mechview, 1 - on radar screen, 2 - on main screen int g_nMechViewType; // jcem : 0 - no mechview, 1 - on radar screen, 2 - on main screen
@@ -275,6 +281,129 @@ HRESULT CALLBACK EnumModesCallback2( LPDDSURFACEDESC2 lpDDSurfaceDesc, LPVOID lp
// //
// //
// Called once at startup, enumerate and get caps of all 3D video cards // Called once at startup, enumerate and get caps of all 3D video cards
//
// [tmon] Apply a hard-assigned display device, but only if the operator supplied one
// and it names a device that actually exists. Anything else is ignored, so a stale
// -tmon left on the command line of a machine with fewer monitors simply falls back
// to auto-detection instead of breaking startup. Rejections are reported in
// gos-displays.txt - silently doing nothing is worse than useless when the operator
// is trying to work out why a monitor did not light up.
//
static void ApplyMonitorOverride(int slot, int* pTarget)
{
int dev = g_naMonitorOverride[slot];
if ((dev >= 0) && (dev < (int)NumDevices))
*pTarget = dev;
}
//
// [displaylog] Append one printf-style line to the display report.
//
static void EmitDisplayLine( HANDLE hFile, const char* fmt, ... )
{
char szLine[512];
DWORD dwWritten=0;
va_list ap;
va_start( ap, fmt );
vsprintf( szLine, fmt, ap );
va_end( ap );
WriteFile( hFile, szLine, (DWORD)strlen(szLine), &dwWritten, NULL );
}
//
// [displaylog] Write gos-displays.txt next to the executable, describing every
// DirectDraw device GameOS found and which display role each one was assigned.
//
// This exists because there is no other way to see it: the SPEW macros are compiled
// out of shipping builds, and a monitor that simply never lights up gives no clue
// whether the device was missing, lacked hardware caps, or was assigned elsewhere.
//
static void LogDisplayDevices()
{
char szDir[MAX_PATH];
char szPath[MAX_PATH];
szDir[0]='\0';
GetModuleFileNameA( NULL, szDir, sizeof(szDir) );
char* pSlash=strrchr( szDir, '\\' );
if( pSlash )
*(pSlash+1)='\0';
else
szDir[0]='\0';
sprintf( szPath, "%sgos-displays.txt", szDir );
HANDLE hFile=CreateFileA( szPath, GENERIC_WRITE, FILE_SHARE_READ, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
if( hFile==INVALID_HANDLE_VALUE )
return;
EmitDisplayLine( hFile, "GameOS display device enumeration\r\n" );
EmitDisplayLine( hFile, "=================================\r\n\r\n" );
EmitDisplayLine( hFile, "NumDevices = %d (DeviceArray holds at most 8)\r\n", (int)NumDevices );
EmitDisplayLine( hFile, "NumHWDevices = %d\r\n", (int)NumHWDevices );
EmitDisplayLine( hFile, "NumMonitors = %d\r\n\r\n", (int)NumMonitors );
for( DWORD t0=0; t0<NumDevices; t0++ )
{
EmitDisplayLine( hFile, " [%d] %-40s hw_rasterization=%s\r\n",
(int)t0,
DeviceArray[t0].DDid.szDescription,
(DeviceArray[t0].D3DCaps.dwDevCaps & D3DDEVCAPS_HWRASTERIZATION) ? "yes" : "NO" );
}
EmitDisplayLine( hFile, "\r\nAssigned roles (-1 means not found):\r\n" );
EmitDisplayLine( hFile, " main (FullScreenDevice) = %d\r\n", Environment.FullScreenDevice );
EmitDisplayLine( hFile, " radar (g_nNonDualHead) = %d\r\n", g_nNonDualHead );
EmitDisplayLine( hFile, " span (g_nDualHead) = %d\r\n", g_nDualHead );
EmitDisplayLine( hFile, " span2 (g_nDualHead2) = %d\r\n", g_nDualHead2 );
EmitDisplayLine( hFile, " mfd1 (g_nMFD1) = %d\r\n", g_nMFD1 );
EmitDisplayLine( hFile, " mfd2 (g_nMFD2) = %d\r\n", g_nMFD2 );
// Report what -tmon asked for and whether each slot could be honoured.
{
static const char* apszRole[4] = { "main", "radar", "mfd1", "mfd2" };
bool bAny=false;
for( int s=0; s<4; s++ )
if( g_naMonitorOverride[s] >= 0 )
bAny=true;
if( bAny )
{
EmitDisplayLine( hFile, "\r\n-tmon override:\r\n" );
for( int s2=0; s2<4; s2++ )
{
int dev=g_naMonitorOverride[s2];
if( dev < 0 )
EmitDisplayLine( hFile, " %-5s : auto\r\n", apszRole[s2] );
else if( dev < (int)NumDevices )
EmitDisplayLine( hFile, " %-5s : device %d APPLIED\r\n", apszRole[s2], dev );
else
EmitDisplayLine( hFile, " %-5s : device %d *** REJECTED - only %d device(s) exist ***\r\n",
apszRole[s2], dev, (int)NumDevices );
}
}
else
{
EmitDisplayLine( hFile, "\r\n-tmon override: not supplied (all roles auto-detected)\r\n" );
}
}
// The decisive line: whether the MFD subsystem will initialise at all.
EmitDisplayLine( hFile, "\r\nMFD mode (-tmfds) = %d\r\n", g_nTypeOfMFDs );
if( g_nTypeOfMFDs == 4 )
{
bool bOK = (g_nMFD1 != -1) && (g_nMFD2 != -1);
EmitDisplayLine( hFile, "mode 4 requires BOTH mfd1 and mfd2: %s\r\n", bOK ? "OK" : "*** FAILED ***" );
if( !bOK )
EmitDisplayLine( hFile,
" -> IsMultimonitorAvaliable() returns false, so HSH_EnterFullScreen2()\r\n"
" falls back to the single-secondary-monitor path and the two MFD\r\n"
" displays are never opened. Four hardware-rasterizing DirectDraw\r\n"
" devices are needed: main, radar, mfd1, mfd2.\r\n" );
}
CloseHandle( hFile );
}
// //
// //
void FindVideoCards() void FindVideoCards()
@@ -380,6 +509,31 @@ void FindVideoCards()
} }
} }
} }
// [tmon] Hard-assigned Main/Radar overrides. Applied BEFORE the mode 4 MFD search
// below so that search still skips whichever devices the operator picked.
ApplyMonitorOverride(0, &Environment.FullScreenDevice);
ApplyMonitorOverride(1, &g_nNonDualHead);
// Mode 4 (split dual 640x480): find two extra D3D devices beyond
// FullScreenDevice and g_nNonDualHead. These need no special resolution.
{
int found = 0;
for (int t0 = 0; t0 < NumDevices && found < 2; t0++) {
if (t0 == Environment.FullScreenDevice) continue;
if (t0 == g_nNonDualHead) continue;
if (DeviceArray[t0].D3DCaps.dwDevCaps & D3DDEVCAPS_HWRASTERIZATION) {
if (found == 0) g_nMFD1 = t0;
else g_nMFD2 = t0;
found++;
}
}
}
// [tmon] Hard-assigned MFD overrides (only meaningful with -tmfds 4).
ApplyMonitorOverride(2, &g_nMFD1);
ApplyMonitorOverride(3, &g_nMFD2);
// [displaylog] Write gos-displays.txt with the full enumeration and the role
// assignment. SPEW is compiled out of shipping builds, so a file is the only way
// the operator can see why a display did or did not get picked up.
LogDisplayDevices();
// jcem // jcem
// //
// Check any known video cards have up to date drivers (Only on Windows9x) // Check any known video cards have up to date drivers (Only on Windows9x)
@@ -20,6 +20,7 @@
#include "MemoryManager.hpp" #include "MemoryManager.hpp"
#include "DirectX.hpp" #include "DirectX.hpp"
#include "FileIO.hpp" #include "FileIO.hpp"
#include <stdlib.h> // [fpslog] atexit() for the frame pacing summary
#include "ControlManager.hpp" #include "ControlManager.hpp"
#include "LocalizationManager.hpp" #include "LocalizationManager.hpp"
#include "Time.hpp" #include "Time.hpp"
@@ -834,13 +835,264 @@ __int64 ProfileRenderEnd( __int64 RenderTime )
} }
//상훈짱 begin //sanghoon begin
#include "render.hpp" #include "render.hpp"
HRESULT App_Render( LPDIRECT3DDEVICE7 pd3dDevice,LPDIRECTDRAWSURFACE7 pddsTexture); HRESULT App_Render( LPDIRECT3DDEVICE7 pd3dDevice,LPDIRECTDRAWSURFACE7 pddsTexture);
//상훈짱 end //sanghoon end
//
// [fpslog] Frame pacing report, written to gos-fps.txt next to the executable.
//
// Off unless the -fps switch is given, so a normal pod run does no extra work at all.
// Set from MW4Application's command-line parser.
//
int g_nFpsLog = 0;
// The engine's own FrameRate readout is inside #ifdef LAB_ONLY, so it exists only in
// MW4pro.exe. This works in Release builds, which is what actually runs on the pods.
//
// Average FPS on its own hides stutter: 60 fps average is indistinguishable from 60 fps
// with a dropped frame every second. So this also reports the slowest frames, which is
// where rhythmic hitching shows up.
//
// IMPORTANT - why the output is buffered:
// The first version wrote one line per second straight to the file. That put a WriteFile
// on the render thread every second, and its cost landed in the NEXT frame's measurement
// (the frame time is recorded before the line is emitted). The result was exactly one
// inflated frame per second, forever - the tool was reporting its own overhead as the
// game's worst frame. Everything is now accumulated in memory and flushed only when the
// buffer fills or at exit, so a normal session performs no writes at all while running.
// Trade-off: a hard crash loses the un-flushed tail. gos-displays.txt is the
// crash-survivable log; this one is a measurement instrument.
//
static char s_szFpsBuf[131072]; // ~2000 lines, about 33 minutes at 1 line/sec
static int s_nFpsBufUsed = 0;
static HANDLE s_hFpsFile = INVALID_HANDLE_VALUE;
static int s_bFpsAtExit = 0;
// Whole-session frame time histogram in 0.5 ms buckets (0 - 1000 ms). Lets the true
// session-wide percentiles be computed at exit without retaining every frame time.
#define FPS_HIST_BUCKETS 2000
static DWORD s_adwFpsHist[FPS_HIST_BUCKETS];
static DWORD s_dwFpsFrames = 0;
static double s_dFpsTotalMS = 0.0;
static DWORD s_dwFpsHitches = 0;
static void GOS_FpsFlush( void )
{
DWORD dwWritten=0;
if( s_nFpsBufUsed<=0 )
return;
if( s_hFpsFile==INVALID_HANDLE_VALUE )
{
char szDir[MAX_PATH];
char szPath[MAX_PATH];
szDir[0]='\0';
GetModuleFileNameA( NULL, szDir, sizeof(szDir) );
char* pSlash=strrchr( szDir, '\\' );
if( pSlash )
*(pSlash+1)='\0';
else
szDir[0]='\0';
sprintf( szPath, "%sgos-fps.txt", szDir );
// FILE_SHARE_READ so the file can be read while the game is still running.
s_hFpsFile=CreateFileA( szPath, GENERIC_WRITE, FILE_SHARE_READ, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
if( s_hFpsFile==INVALID_HANDLE_VALUE )
{
s_nFpsBufUsed=0; // drop it rather than retry every second
return;
}
}
WriteFile( s_hFpsFile, s_szFpsBuf, (DWORD)s_nFpsBufUsed, &dwWritten, NULL );
s_nFpsBufUsed=0;
}
// Mean frame time (ms) of the slowest dwCount frames of the whole session.
static double GOS_FpsSlowestMean( DWORD dwCount )
{
double dSum=0.0;
DWORD dwSeen=0;
int b;
if( dwCount<1 )
dwCount=1;
for( b=FPS_HIST_BUCKETS-1; b>=0 && dwSeen<dwCount; b-- )
{
DWORD dwTake=s_adwFpsHist[b];
if( !dwTake )
continue;
if( dwTake>dwCount-dwSeen )
dwTake=dwCount-dwSeen;
dSum += (((double)b+0.5)/2.0)*(double)dwTake;
dwSeen += dwTake;
}
return dwSeen ? (dSum/(double)dwSeen) : 0.0;
}
static void GOS_FpsAppend( const char* pszLine )
{
int nLen=(int)strlen(pszLine);
if( nLen<=0 )
return;
if( s_nFpsBufUsed+nLen > (int)sizeof(s_szFpsBuf) )
GOS_FpsFlush(); // buffer full: one write, rarely
if( s_nFpsBufUsed+nLen > (int)sizeof(s_szFpsBuf) )
return; // still no room: give up quietly
memcpy( s_szFpsBuf+s_nFpsBufUsed, pszLine, nLen );
s_nFpsBufUsed += nLen;
}
// NOTE: must be __cdecl. GameOS builds with /Gz (__stdcall by default), but atexit()
// takes a __cdecl callback, so without this the compiler rejects it with C2664.
static void __cdecl GOS_FpsAtExit( void )
{
char szLine[256];
if( s_dwFpsFrames )
{
// True session-wide percentiles, which a per-second bucket cannot give:
// 1% of 60 frames is 0, so a "1% low" computed per second degenerates into
// "the single worst frame". Over a whole session it is meaningful.
double dAvgMS = s_dFpsTotalMS/(double)s_dwFpsFrames;
double dOnePct = GOS_FpsSlowestMean( s_dwFpsFrames/100 );
double dTenthPct= GOS_FpsSlowestMean( s_dwFpsFrames/1000 );
GOS_FpsAppend( "\r\n" );
GOS_FpsAppend( "session summary\r\n" );
GOS_FpsAppend( "---------------\r\n" );
sprintf( szLine, " frames : %lu\r\n", (unsigned long)s_dwFpsFrames );
GOS_FpsAppend( szLine );
sprintf( szLine, " elapsed : %.1f s\r\n", s_dFpsTotalMS/1000.0 );
GOS_FpsAppend( szLine );
sprintf( szLine, " average : %.1f fps (%.2f ms)\r\n",
(dAvgMS>0.0)?1000.0/dAvgMS:0.0, dAvgMS );
GOS_FpsAppend( szLine );
sprintf( szLine, " 1%% low : %.1f fps (%.2f ms)\r\n",
(dOnePct>0.0)?1000.0/dOnePct:0.0, dOnePct );
GOS_FpsAppend( szLine );
sprintf( szLine, " 0.1%% low : %.1f fps (%.2f ms)\r\n",
(dTenthPct>0.0)?1000.0/dTenthPct:0.0, dTenthPct );
GOS_FpsAppend( szLine );
sprintf( szLine, " frames over 2x avg: %lu\r\n", (unsigned long)s_dwFpsHitches );
GOS_FpsAppend( szLine );
}
GOS_FpsFlush();
if( s_hFpsFile!=INVALID_HANDLE_VALUE )
{
CloseHandle( s_hFpsFile );
s_hFpsFile=INVALID_HANDLE_VALUE;
}
}
static void GOS_LogFrameRate( float fFrameRate )
{
enum { MAX_WORST = 64 };
static float s_afWorst[MAX_WORST]; // longest frames this second, descending ms
static int s_nWorst = 0;
static float s_fAccumMS= 0.0f;
static float s_fSumMS = 0.0f;
static float s_fMaxMS = 0.0f;
static int s_nFrames = 0;
static int s_nSecond = 0;
char szLine[256];
if( !g_nFpsLog ) // [fpslog] -fps not given: do nothing
return;
if( fFrameRate<=0.0f )
return;
if( !s_bFpsAtExit )
{
s_bFpsAtExit=1;
atexit( GOS_FpsAtExit ); // flush the buffer + write the summary
}
float fMS = 1000.0f/fFrameRate;
s_nFrames++;
s_fSumMS += fMS;
s_fAccumMS += fMS;
if( fMS>s_fMaxMS )
s_fMaxMS = fMS;
// Whole-session histogram (0.5 ms buckets, saturating at the top bucket).
int nBucket=(int)(fMS*2.0f);
if( nBucket<0 )
nBucket=0;
if( nBucket>=FPS_HIST_BUCKETS )
nBucket=FPS_HIST_BUCKETS-1;
s_adwFpsHist[nBucket]++;
s_dwFpsFrames++;
s_dFpsTotalMS += fMS;
// Maintain the longest frames of this second, sorted longest-first.
if( s_nWorst<MAX_WORST )
s_afWorst[s_nWorst++] = fMS;
else if( fMS>s_afWorst[MAX_WORST-1] )
s_afWorst[MAX_WORST-1] = fMS;
for( int i=s_nWorst-1; i>0 && s_afWorst[i]>s_afWorst[i-1]; i-- ) {
float fTmp=s_afWorst[i]; s_afWorst[i]=s_afWorst[i-1]; s_afWorst[i-1]=fTmp;
}
if( s_fAccumMS<1000.0f )
return;
float fAvgMS = s_fSumMS/(float)s_nFrames;
float fAvgFPS = 1000.0f/fAvgMS;
// 5% low, not 1%: at 60 samples a "1% low" is a single frame, which is just the
// worst-frame column restated. Worst 3-of-60 is a number that actually differs.
int nLow = s_nFrames/20;
if( nLow<3 )
nLow = 3;
if( nLow>s_nWorst )
nLow = s_nWorst;
float fLowSum=0.0f;
for( int j=0; j<nLow; j++ )
fLowSum += s_afWorst[j];
float fLowFPS = (fLowSum>0.0f) ? (1000.0f/(fLowSum/(float)nLow)) : 0.0f;
// Frames that took more than twice the average - i.e. visible hitches.
int nHitch=0;
for( int k=0; k<s_nWorst; k++ )
if( s_afWorst[k]>fAvgMS*2.0f )
nHitch++;
s_dwFpsHitches += nHitch;
if( s_nSecond==0 )
GOS_FpsAppend( " sec frames avg fps 5% low worst frame hitches\r\n"
" --- ------ ------- ------ ----------- -------\r\n" );
sprintf( szLine, "%5d %6d %8.1f %8.1f %8.1f ms %s%d\r\n",
s_nSecond, s_nFrames, fAvgFPS, fLowFPS, s_fMaxMS,
nHitch ? "<-- " : "", nHitch );
GOS_FpsAppend( szLine );
s_nSecond++;
s_nFrames = 0;
s_nWorst = 0;
s_fSumMS = 0.0f;
s_fMaxMS = 0.0f;
// A single frame longer than a second (a level load) must not spill into the next
// buckets and emit a run of bogus one-frame rows, which is what used to happen.
s_fAccumMS-= 1000.0f;
if( s_fAccumMS<0.0f || s_fAccumMS>=1000.0f )
s_fAccumMS = 0.0f;
}
// //
// Update the display (call all the 'Update Renderers' routines // Update the display (call all the 'Update Renderers' routines
// //
@@ -885,6 +1137,7 @@ void gos_UpdateDisplay( bool Everything )
frameRate=(float)frequency/(float)thisframe; // Calculate frame rate based on clock frequency frameRate=(float)frequency/(float)thisframe; // Calculate frame rate based on clock frequency
StartOfRenderTime=GetCycles(); StartOfRenderTime=GetCycles();
GOS_LogFrameRate( frameRate ); // [fpslog] per-second pacing report
// //
// Don't trigger watchdog timer // Don't trigger watchdog timer
// //
@@ -915,8 +1168,8 @@ void gos_UpdateDisplay( bool Everything )
ProfileTime( TimeClearViewPort, gos_SetupViewport( 0, 0, 1, 0x303050 , 0.0, 0.0, 1.0, 1.0 ) ); ProfileTime( TimeClearViewPort, gos_SetupViewport( 0, 0, 1, 0x303050 , 0.0, 0.0, 1.0, 1.0 ) );
TimeInClearViewPort+=TimeClearViewPort; TimeInClearViewPort+=TimeClearViewPort;
} }
//상훈짱 begin //sanghoon begin
//backbuffer에 Background Image를 그린다... //Draw background image to backbuffer...
if(hsh_initialized){ if(hsh_initialized){
// 0 - no MFDs, 1 - orginal(5+1=dual & single), 2 - B&W(3 + 1=1 dual), 3 - color(3 + 1=2 dual) // 0 - no MFDs, 1 - orginal(5+1=dual & single), 2 - B&W(3 + 1=1 dual), 3 - color(3 + 1=2 dual)
@@ -940,13 +1193,25 @@ void gos_UpdateDisplay( bool Everything )
radar_device.BeginScene(); radar_device.BeginScene();
} }
break; break;
case 4:
// Step 0: clear + grid for radar and LEFT MFD.
// Step 1: clear + grid for RIGHT MFD (staggered so the right
// flip at new sh_step==1 shows channels 3-4 from the previous
// cycle, not a freshly-cleared buffer).
if(sh_step==0){
radar_device.BeginScene();
mfd_device.BeginScene(); // left device only
} else if(sh_step==1) {
mfd_device.BeginSceneRight(); // right device clear + grid
}
break;
} }
}else if(hsh_mrdev_initialized){ }else if(hsh_mrdev_initialized){
mr_device.BeginScene(); mr_device.BeginScene();
} }
//HSH_RenderAux1SmallMech(); //HSH_RenderAux1SmallMech();
//상훈짱 end //sanghoon end
if (g_pfnCTCL_AfterBeginScene) { if (g_pfnCTCL_AfterBeginScene) {
(*g_pfnCTCL_AfterBeginScene)(); (*g_pfnCTCL_AfterBeginScene)();
} }
@@ -1043,7 +1308,7 @@ void gos_UpdateDisplay( bool Everything )
LOG_BLOCK("Gos::UpdateDebugger()"); LOG_BLOCK("Gos::UpdateDebugger()");
ProfileTime( TimeDebugger, UpdateDebugger() ); ProfileTime( TimeDebugger, UpdateDebugger() );
} }
//상훈.. //sanghoon
#if 1 #if 1
extern LPDIRECT3DDEVICE7 d3dDevice7; extern LPDIRECT3DDEVICE7 d3dDevice7;
static bool preload_GameEndScreem=true;; static bool preload_GameEndScreem=true;;
@@ -1077,8 +1342,8 @@ void gos_UpdateDisplay( bool Everything )
// //
// Flip or Blit the current image onto the display // Flip or Blit the current image onto the display
// //
//상훈 앞 //sanghoon begin
//Flip을 한다. //Perform the Flip.
if(hsh_initialized){ if(hsh_initialized){
// 0 - no MFDs, 1 - orginal(5+1=dual & single), 2 - B&W(3 + 1=1 dual), 3 - color(3 + 1=2 dual) // 0 - no MFDs, 1 - orginal(5+1=dual & single), 2 - B&W(3 + 1=1 dual), 3 - color(3 + 1=2 dual)
switch(g_nTypeOfMFDs) { switch(g_nTypeOfMFDs) {
@@ -1106,13 +1371,32 @@ void gos_UpdateDisplay( bool Everything )
break; break;
case 3: case 3:
break; break;
case 4:
// 7-step cadence. Radar + left MFD flip on step 0 (same as mode 1).
// Right MFD flip is staggered to step 1 so that three back-to-back
// DGVoodoo2 Present() calls don't all land in the same frame and
// cause rhythmic stutter on the main display.
// Right device finishes rendering at step 6 (channel 4), so
// flipping at step 1 is still correct timing.
sh_step++;
sh_step%=7;
if(sh_step==0) {
radar_device.EndScene();
radar_device.pDDSFront->Flip(0,DDFLIP_DONOTWAIT|DDFLIP_NOVSYNC);
mfd_device.EndScene();
mfd_device.pDDSFront->Flip(0,DDFLIP_DONOTWAIT|DDFLIP_NOVSYNC);
} else if(sh_step==1) {
if (mfd_device_right.pDDSFront)
mfd_device_right.pDDSFront->Flip(0,DDFLIP_DONOTWAIT|DDFLIP_NOVSYNC);
}
break;
} }
}else if(hsh_mrdev_initialized){ }else if(hsh_mrdev_initialized){
mr_device.EndScene(); mr_device.EndScene();
mr_device.pDDSFront->Flip(0,DDFLIP_DONOTWAIT|DDFLIP_NOVSYNC); mr_device.pDDSFront->Flip(0,DDFLIP_DONOTWAIT|DDFLIP_NOVSYNC);
} }
//상훈 뒤 //sanghoon end
{ {
LOG_BLOCK("Gos::DisplayBackBuffer()"); LOG_BLOCK("Gos::DisplayBackBuffer()");
ProfileTime( TimeDisplay, DisplayBackBuffer() ); ProfileTime( TimeDisplay, DisplayBackBuffer() );
@@ -44,9 +44,9 @@ extern DWORD gNumLockMode;
extern DWORD gCapLockMode; extern DWORD gCapLockMode;
extern DWORD gScrollLockMode; extern DWORD gScrollLockMode;
// úè - start // hyun begin
void (__stdcall *g_pfnRIO_ButtonEvent)(BYTE* by) = NULL; void (__stdcall *g_pfnRIO_ButtonEvent)(BYTE* by) = NULL;
// úè - end // hyun end
// //
// //
@@ -106,14 +106,14 @@ LRESULT CALLBACK GameOSWinProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
switch( uMsg ) switch( uMsg )
{ {
// úè // hyun
case WM_USER + 100: case WM_USER + 100:
{ {
// úè - start // hyun begin
if (g_pfnRIO_ButtonEvent) { if (g_pfnRIO_ButtonEvent) {
(*g_pfnRIO_ButtonEvent)((BYTE*)&lParam); (*g_pfnRIO_ButtonEvent)((BYTE*)&lParam);
} }
// úè - end // hyun end
} }
break; break;
// //
File diff suppressed because it is too large Load Diff
@@ -1,4 +1,4 @@
//D3DCOLOR_XXXX정위한다.(d3d8types.h에 정의되어 있으므로. 정의되어있지 않을것이다. //D3DCOLOR_XXXX macros are defined in d3d8types.h and will not be redefined here.
#ifndef D3DCOLOR_ARGB #ifndef D3DCOLOR_ARGB
#define D3DCOLOR_ARGB(a,r,g,b) (D3DCOLOR)((((a)&0xff)<<24)|(((r)&0xff)<<16)|(((g)&0xff)<<8)|((b)&0xff))) #define D3DCOLOR_ARGB(a,r,g,b) (D3DCOLOR)((((a)&0xff)<<24)|(((r)&0xff)<<16)|(((g)&0xff)<<8)|((b)&0xff)))
@@ -44,10 +44,10 @@ enum AUX1STATE
#define AUX1_TEAM_MESSAGE 2 #define AUX1_TEAM_MESSAGE 2
#define AUX1_FREE_MESSAGE 3 #define AUX1_FREE_MESSAGE 3
//각 디바이스마다.., 각 폰트 종류(typeface,크기,굴기,기울기)가 달라질때 마다 하나씩 생성시켜 사용하면 된다. //Create one instance per device per font type (typeface, size, bold, italic).
class CHSHFont class CHSHFont
{ {
//일시적으로 사용되고.. 각 instance마다 사용되어질 필요가 없으므로 static으로 하였다. //Used temporarily; no need per instance, so declared static.
static D3DTLVERTEX m_pVB[300]; static D3DTLVERTEX m_pVB[300];
LPDIRECT3DDEVICE7 m_pd3dDevice; LPDIRECT3DDEVICE7 m_pd3dDevice;
@@ -59,7 +59,7 @@ class CHSHFont
DWORD m_dwSavedStateBlock; DWORD m_dwSavedStateBlock;
DWORD m_dwDrawTextStateBlock; DWORD m_dwDrawTextStateBlock;
DWORD m_dwMaxWidth;//문자 하나중 가장 큰것.. DWORD m_dwMaxWidth;//Width of the widest single character..
public: public:
CHSHFont(); CHSHFont();
~CHSHFont(); ~CHSHFont();
@@ -80,10 +80,10 @@ public:
CHSH_Device* m_pOtherHSHD; CHSH_Device* m_pOtherHSHD;
public: public:
LPDIRECTDRAW7 pDD; LPDIRECTDRAW7 pDD;
LPDIRECTDRAWSURFACE7 pDDSFront; //Flip을 하기위해서 필요.. LPDIRECTDRAWSURFACE7 pDDSFront; //Required for Flip..
LPDIRECTDRAWSURFACE7 pDDSBack; //Drawing하기 위해서 필요. LPDIRECTDRAWSURFACE7 pDDSBack; //Required for Drawing.
LPDIRECTDRAWSURFACE7 pDDSTarget; //실제 그리는 텍스쳐 이다. LPDIRECTDRAWSURFACE7 pDDSTarget; //The actual rendering texture.
LPDIRECTDRAWSURFACE7 pDDSTexture; //실제 그리는 텍스쳐 이다. LPDIRECTDRAWSURFACE7 pDDSTexture; //The actual rendering texture.
LPDIRECT3DDEVICE7 pD3DDevice; LPDIRECT3DDEVICE7 pD3DDevice;
CHSHFont pFont[4]; CHSHFont pFont[4];
SIZE size_back; SIZE size_back;
@@ -141,7 +141,7 @@ public:
bool InitFirst(); bool InitFirst();
bool InitSecond(); bool InitSecond();
LPDIRECTDRAWSURFACE7 pDDSBackground; //one attatched image sruface LPDIRECTDRAWSURFACE7 pDDSBackground; //one attatched image sruface
LPDIRECTDRAWSURFACE7 pDDSRadarDamageTexture;//메크 데미지 텍스쳐.. LPDIRECTDRAWSURFACE7 pDDSRadarDamageTexture;//Mech damage texture..
// MSL 5.03 Mechview // MSL 5.03 Mechview
LPDIRECTDRAWSURFACE7 pDDSMechViewBkgnd; LPDIRECTDRAWSURFACE7 pDDSMechViewBkgnd;
LPDIRECTDRAWSURFACE7 pDDSMechViewBeagle; LPDIRECTDRAWSURFACE7 pDDSMechViewBeagle;
@@ -151,7 +151,7 @@ public:
LPDIRECTDRAWSURFACE7 pDDSMechViewLightamp; LPDIRECTDRAWSURFACE7 pDDSMechViewLightamp;
LPDIRECTDRAWSURFACE7 m_pDDSMechView; //m x n - tiled 3D MechView images LPDIRECTDRAWSURFACE7 m_pDDSMechView; //m x n - tiled 3D MechView images
virtual bool BeginScene(); //texture를 ratate시켜서 출력하기 위한 루틴이 포함된다.. background이미지를.. 미리 출력한다... virtual bool BeginScene(); //Rotates and outputs texture; pre-renders background image...
virtual bool EndScene(); virtual bool EndScene();
virtual bool Release(); virtual bool Release();
bool LoadRadarDamageTexture(const char *mechtexturename); bool LoadRadarDamageTexture(const char *mechtexturename);
@@ -159,25 +159,33 @@ public:
bool MapDrawn; bool MapDrawn;
}; };
// Mode 4 (split dual 640x480): the right-hand MFD lives on its own DirectDraw object,
// so CMFD_Device keeps a typed pointer to it.
class CMFDRight_Device;
class CMFD_Device:public CHSH_Device class CMFD_Device:public CHSH_Device
{ {
public: public:
//CHSHFont SmallFont; //CHSHFont SmallFont;
LPDIRECTDRAWSURFACE7 pDDSMechTexture;//3D메크 이미지 저장하기 위한 텍스쳐... LPDIRECTDRAWSURFACE7 pDDSMechTexture;//Texture for storing 3D mech image...
LPDIRECTDRAWSURFACE7 pDDSDamageTexture;//메크 데미지 텍스쳐.. LPDIRECTDRAWSURFACE7 pDDSDamageTexture;//Mech damage texture..
// MSL 5.03 Target Damage Display // MSL 5.03 Target Damage Display
LPDIRECTDRAWSURFACE7 pDDSTargetTexture;//메크 데미지 텍스쳐.. LPDIRECTDRAWSURFACE7 pDDSTargetTexture;//Target damage texture..
DWORD ch; //current channel.... DWORD ch; //current channel....
CMFDRight_Device* m_pRightDevice; // mode 4: right 640x480 device (NULL in modes 1-3)
bool m_bSwappedToRight; // mode 4: true while our members point at the right device
public: public:
CMFD_Device(); CMFD_Device();
~CMFD_Device(); ~CMFD_Device();
bool InitFirst(); bool InitFirst();
bool InitSecond(); bool InitSecond();
bool BeginChannel(DWORD channel);// 0~4번의 채널을 정할 수 있게된다. bool BeginChannel(DWORD channel);// Select channel 0-4.
bool EndChannel(); bool EndChannel();
virtual bool BeginScene(); //normal한 beginscene/endscene를 한다. void SwapRightState(); // mode 4: exchange data members with the right device
virtual bool EndScene(); //flip을 한다. virtual bool BeginScene(); //Performs normal BeginScene/EndScene.
bool BeginSceneRight(); // mode 4: clear+grid on right device at sh_step==1
virtual bool EndScene(); //Performs the Flip.
virtual bool Release(); virtual bool Release();
bool LoadDamageTexture(const char *mechtexturename); bool LoadDamageTexture(const char *mechtexturename);
// MSL 5.03 Target Damage Display // MSL 5.03 Target Damage Display
@@ -189,6 +197,27 @@ public:
bool DrawMFDDefaultBackAux1(int state); bool DrawMFDDefaultBackAux1(int state);
}; };
// Mode 4 (split dual 640x480): right-side MFD device on its own 640x480 monitor.
// It owns a SEPARATE IDirectDraw7 and IDirect3DDevice7 (a DirectDraw device is bound to
// one monitor), therefore it must also own a complete, independent copy of the MFD
// texture set: a surface belongs to the IDirectDraw7 that created it, not to the GPU,
// so surfaces can NOT be shared between the two devices even on the same card.
class CMFDRight_Device : public CHSH_Device
{
public:
LPDIRECTDRAWSURFACE7 pDDSMechTexture;
LPDIRECTDRAWSURFACE7 pDDSDamageTexture;
LPDIRECTDRAWSURFACE7 pDDSTargetTexture;
public:
CMFDRight_Device()
: pDDSMechTexture(0), pDDSDamageTexture(0), pDDSTargetTexture(0) {}
bool InitFirst();
bool InitSecond();
virtual bool BeginScene() { return true; }
virtual bool EndScene() { return true; }
virtual bool Release();
};
class CMR_Device:public CHSH_Device class CMR_Device:public CHSH_Device
{ {
public: public:
@@ -199,10 +228,10 @@ public:
bool InitFirst(); bool InitFirst();
bool InitSecond(); bool InitSecond();
LPDIRECTDRAWSURFACE7 pDDSBackground; //one attatched image sruface LPDIRECTDRAWSURFACE7 pDDSBackground; //one attatched image sruface
LPDIRECTDRAWSURFACE7 pDDSMapTexture; //스크롤되는 맵 이미지를 위한 텍스쳐.. LPDIRECTDRAWSURFACE7 pDDSMapTexture; //Texture for scrollable map image..
LPDIRECTDRAWSURFACE7 pDDSMRTargetTexture;//메크 데미지 텍스쳐.. LPDIRECTDRAWSURFACE7 pDDSMRTargetTexture;//Mission Review target texture..
bool LoadMRTargetTexture(const char *mechtexturename); bool LoadMRTargetTexture(const char *mechtexturename);
virtual bool BeginScene(); //texture를 ratate시켜서 출력하기 위한 루틴이 포함된다.. background이미지를.. 미리 출력한다... virtual bool BeginScene(); //Rotates and outputs texture; pre-renders background image...
virtual bool EndScene(); virtual bool EndScene();
virtual bool Release(); virtual bool Release();
}; };
@@ -212,6 +241,7 @@ void HSH_DirectDrawRelease2();
extern CRadar_Device radar_device; extern CRadar_Device radar_device;
extern CMFD_Device mfd_device; extern CMFD_Device mfd_device;
extern CMFDRight_Device mfd_device_right;
extern CMR_Device mr_device; extern CMR_Device mr_device;
extern bool use_shgui; extern bool use_shgui;
extern int sh_step; extern int sh_step;
@@ -71,7 +71,7 @@ INTERNET_STATUS_STATE_CHANGE
INTERNET_STATE_DISCONNECTED_BY_USER INTERNET_STATE_DISCONNECTED_BY_USER
Disconnected by user request. Disconnected by user request.
INTERNET_STATE_IDLE INTERNET_STATE_IDLE
No network requests are being made by the Win32® Internet functions. No network requests are being made by the Win32® Internet functions.
INTERNET_STATE_BUSY INTERNET_STATE_BUSY
Network requests are being made by the Win32 Internet functions. Network requests are being made by the Win32 Internet functions.
INTERNET_STATUS_USER_INPUT_REQUIRED INTERNET_STATUS_USER_INPUT_REQUIRED
+1 -1
View File
@@ -1077,7 +1077,7 @@ int CStrArray::GetTotalLength() const
int nTotalLength; int nTotalLength;
int i, nSize = GetSize(); int i, nSize = GetSize();
nTotalLength = nSize; // nSize개의 '\0' nTotalLength = nSize; // nSize null terminators '\0'
for(i = 0; i < nSize; i++) { for(i = 0; i < nSize; i++) {
nTotalLength += strlen(GetAt(i)); nTotalLength += strlen(GetAt(i));
} }
+22 -22
View File
@@ -514,7 +514,7 @@ void CSOC_Server::OnSendFile()
BYTE bCode; BYTE bCode;
if (Disassemble("B", &bCode)) { if (Disassemble("B", &bCode)) {
ASSERT((bCode == 0) || (bCode == 3)); ASSERT((bCode == 0) || (bCode == 3));
// 받아가시오 from Game to console... // Receiving from Game to console...
SYSTEMTIME* pSysTime; SYSTEMTIME* pSysTime;
WORD wSysTimeSize; WORD wSysTimeSize;
GUID* pGUID; GUID* pGUID;
@@ -530,7 +530,7 @@ void CSOC_Server::OnSendFile()
pSF = g_pCTCLManager->m_SFM_Recv.Find(*pGUID, nType); pSF = g_pCTCLManager->m_SFM_Recv.Find(*pGUID, nType);
if (pSF) { if (pSF) {
if (bCode == 3) { if (bCode == 3) {
// 미션리뷰 서버가 mission review 받았다는 것을 받았느냐? // Did we receive confirmation the mission review server got the mission review?
pSF->m_bProcessed = true; pSF->m_bProcessed = true;
g_pCTCLManager->m_SFM_Recv.Cut(pSF); g_pCTCLManager->m_SFM_Recv.Cut(pSF);
g_pCTCLManager->m_SFM_Done.AddTail(pSF); g_pCTCLManager->m_SFM_Done.AddTail(pSF);
@@ -907,7 +907,7 @@ void CSOC_Client::OnSendFile()
BYTE bCode; BYTE bCode;
if (Disassemble("B", &bCode)) { if (Disassemble("B", &bCode)) {
ASSERT((bCode == 1) || (bCode == 2)); ASSERT((bCode == 1) || (bCode == 2));
// 받았오 from console to Game... // Received from console to Game...
SYSTEMTIME* pSysTime; SYSTEMTIME* pSysTime;
WORD wSysTimeSize; WORD wSysTimeSize;
GUID* pGUID; GUID* pGUID;
@@ -1425,21 +1425,21 @@ void CCTCLManager::Run()
#endif // !defined(CTCL_LAUNCHER) #endif // !defined(CTCL_LAUNCHER)
} else { } else {
/* /*
. Code executed for both client and server.
* *Possible states:
/ .. Before server/client role is determined: waiting for commands
(// .) (Commands such as exit/start-server/start-client may arrive.)
Running as server, waiting for server mech configuration data
(CreateSession가 .) (State after CreateSession has been called.)
Bot들에 Running as server, waiting for Bot information
( .) (Client joining happens automatically between client and server.)
Launch를 Running as server, waiting for Launch
==> . ==>Client has no waiting state as data is transferred immediately on startup.
==> . ==>Define each state and implement the appropriate handling for each.
switch(state){ switch(state){
} }
*/ */
@@ -1521,8 +1521,8 @@ void CCTCLManager::DoMech4Comm()
} }
break; break;
case 1: case 1:
//서버/클라이언트로서 실행준비하도록 명령을 전달한다. //Send command to prepare for execution as server/client.
//또한 서버를 실행하는데 필요한 모든 파라미터도 함께 전달한다. //Also transmit all parameters required to run the server.
for(i = 0; i < g_nPlayerInfos; i++) { for(i = 0; i < g_nPlayerInfos; i++) {
SPlayerInfo& pi = g_aPlayerInfos[i]; SPlayerInfo& pi = g_aPlayerInfos[i];
if (!pi.m_bBot) { if (!pi.m_bBot) {
@@ -1549,12 +1549,12 @@ void CCTCLManager::DoMech4Comm()
} }
} }
if (i == g_nPlayerInfos) { if (i == g_nPlayerInfos) {
// Bot들에 대한 정보를 모두 한데 묶어서 보낸다. // Bundle and send all Bot information together.
CPacket pak(&SVR.GetGameSOC()); CPacket pak(&SVR.GetGameSOC());
pak.Assemble("B", C_BOTS); pak.Assemble("B", C_BOTS);
for(i = 0; i < g_nPlayerInfos; i++) { for(i = 0; i < g_nPlayerInfos; i++) {
if (i != g_nServer) { // 원래 Bot만 지금은 서버를 제외한 전부... if (i != g_nServer) { // Originally bots only; now everyone except the server...
SPlayerInfo& pi = g_aPlayerInfos[i]; SPlayerInfo& pi = g_aPlayerInfos[i];
pak.Assemble("BnsDWwsnn", pi.m_bBot, pi.m_nLevelOrTesla, pi.m_szName, pi.m_nMechIndex, pi.m_fileID, pi.m_recordID, pi.m_szMech, pi.m_nTeamOrSkin, pi.m_nDecal); pak.Assemble("BnsDWwsnn", pi.m_bBot, pi.m_nLevelOrTesla, pi.m_szName, pi.m_nMechIndex, pi.m_fileID, pi.m_recordID, pi.m_szMech, pi.m_nTeamOrSkin, pi.m_nDecal);
} }
@@ -1565,10 +1565,10 @@ void CCTCLManager::DoMech4Comm()
} }
break; break;
case 4: case 4:
// 게임이 성공적으로 만들어지면 서버와 클라이언트들의 Mech에 대한 정보들을 Set한다... // Once the game is successfully created, set Mech info for server and all clients...
if (SOCGame.m_nGameReturn == _EGR_OkCreateSession) { if (SOCGame.m_nGameReturn == _EGR_OkCreateSession) {
for(i = 0; i < g_nPlayerInfos; i++) { for(i = 0; i < g_nPlayerInfos; i++) {
if (i != g_nServer) { // 서버는 이미 SetMech에 진입한 상태... if (i != g_nServer) { // Server has already entered SetMech...
SPlayerInfo& pi = g_aPlayerInfos[i]; SPlayerInfo& pi = g_aPlayerInfos[i];
if (!pi.m_bBot) { if (!pi.m_bBot) {
CTeslaInfo& ti = m_aTIs.GetAt(pi.m_nLevelOrTesla); CTeslaInfo& ti = m_aTIs.GetAt(pi.m_nLevelOrTesla);
@@ -1581,8 +1581,8 @@ void CCTCLManager::DoMech4Comm()
} }
break; break;
case 6: case 6:
//모든 클라이언드들이 서버에 참여하기를 기다린다.<==이 응답은 서버로 부터 얻을 수 있다. //Wait for all clients to join the server. <==This response comes from the server.
//참여가 모두 끝났으면, 서버로 하여금 게임을 Launch시키도록 한다. //Once all clients have joined, instruct the server to Launch the game.
if (SOCGame.m_nGameReturn == _EGR_OkLaunchReady) { if (SOCGame.m_nGameReturn == _EGR_OkLaunchReady) {
g_nMech4Comm = 9; g_nMech4Comm = 9;
} }
+1 -1
View File
@@ -42,7 +42,7 @@ public:
const char* m_pcsz; const char* m_pcsz;
int m_nLauncherConnection; // 0: no connection, +1: connection, -1: connecting int m_nLauncherConnection; // 0: no connection, +1: connection, -1: connecting
int m_nConnection2; // m_bCameraShip값에 따라 게임 혹은 카메라 쉽과의 접속을 의미, 0: no connection, +1: connection, -1: connecting int m_nConnection2; // Connection to game or camera ship per m_bCameraShip, 0: no connection, +1: connected, -1: connecting
int m_nApplType; int m_nApplType;
int m_nApplState; int m_nApplState;
int m_nGameState; int m_nGameState;
+4 -4
View File
@@ -44,7 +44,7 @@ int GetDayEnd(int nYear, int nMonth)
long GetTotalSeconds(int nYear, int nMonth, int nDay) long GetTotalSeconds(int nYear, int nMonth, int nDay)
{ {
// nYear, nMonth, nDay날의 0시 0분 0초를 0으로 한 초단위 수... // Seconds elapsed since 00:00:00 on the date nYear/nMonth/nDay...
ASSERT(nYear >= 1970); ASSERT(nYear >= 1970);
ASSERT((1 <= nMonth) && (nMonth <= 12)); ASSERT((1 <= nMonth) && (nMonth <= 12));
ASSERT(1 <= nDay); ASSERT(1 <= nDay);
@@ -57,13 +57,13 @@ long GetTotalSeconds(int nYear, int nMonth, int nDay)
if (IsLeapYear(nStart)) { if (IsLeapYear(nStart)) {
nDays++; nDays++;
} }
lTotal += nDays * 24 * 60 * 60; // 24시간 60분 60초 lTotal += nDays * 24 * 60 * 60; // 24 hours * 60 min * 60 sec
} }
for(nStart = 1; nStart < nMonth; nStart++) { for(nStart = 1; nStart < nMonth; nStart++) {
int nDayEnd = GetDayEnd(nYear, nStart); int nDayEnd = GetDayEnd(nYear, nStart);
lTotal += nDayEnd * 24 * 60 * 60; // 24시간 60분 60초 lTotal += nDayEnd * 24 * 60 * 60; // 24 hours * 60 min * 60 sec
} }
lTotal += (nDay - 1) * 24 * 60 * 60; // 24시간 60분 60초 lTotal += (nDay - 1) * 24 * 60 * 60; // 24 hours * 60 min * 60 sec
return lTotal; return lTotal;
} }
+1 -1
View File
@@ -16,7 +16,7 @@ class CTimeDate
public: public:
union { union {
struct { struct {
// Bit Field는 앞쪽에 지정된 것이 LowBit이다. // Bit Fields declared first are at the low-bit end.
DWORD m_xDay: 5; // 2^0, 2^5-1 DWORD m_xDay: 5; // 2^0, 2^5-1
DWORD m_xMonth: 4; // 2^5, 2^4-1 DWORD m_xMonth: 4; // 2^5, 2^4-1
DWORD m_xYear: TIMEDATE_YEAR_BITS; // from 1900-2155 // 2^9, 2^8-1 DWORD m_xYear: TIMEDATE_YEAR_BITS; // from 1900-2155 // 2^9, 2^8-1
+2 -2
View File
@@ -1375,7 +1375,7 @@ void CSockAddr::SetTarget(const char* pcszAddr)
{ {
if (pcszAddr) { if (pcszAddr) {
sin_addr.s_addr = inet_addr(pcszAddr); sin_addr.s_addr = inet_addr(pcszAddr);
if (sin_addr.s_addr == INADDR_ANY) { // 0.0.0.0이기 때문에 HOST/Network Addr무관 if (sin_addr.s_addr == INADDR_ANY) { // 0.0.0.0, HOST/Network Addr irrelevant
hostent* pHN = gethostbyname(pcszAddr); hostent* pHN = gethostbyname(pcszAddr);
if (pHN) { if (pHN) {
sin_addr.s_addr = *(u_long*)pHN->h_addr; sin_addr.s_addr = *(u_long*)pHN->h_addr;
@@ -3667,7 +3667,7 @@ CSOCListen* CSOCManager::DoListen(int nPort, PFN_CreateSOCClient pfnCSC, DWORD d
pSOCListen = new CSOCListen(nPort); pSOCListen = new CSOCListen(nPort);
pSOCListen->SetCSCParam(pfnCSC, dwCSCParam1, dwCSCParam2); pSOCListen->SetCSCParam(pfnCSC, dwCSCParam1, dwCSCParam2);
if (!DoListen(pSOCListen, nPort)) { if (!DoListen(pSOCListen, nPort)) {
// 같은 포트를 2번 Listen 하는 경우?... // Case of Listen on the same port twice?...
pSOCListen = NULL; pSOCListen = NULL;
} }
+25 -25
View File
@@ -41,7 +41,7 @@ extern char SERVERID[];
#endif // !MAX_PACKET #endif // !MAX_PACKET
#ifndef MAX_FTPBUF #ifndef MAX_FTPBUF
#define MAX_FTPBUF 1024 #define MAX_FTPBUF 1024
// MAX_FTPBUF는 MAX_PACKET보다 반드시 작아야 한다? // MAX_FTPBUF must be smaller than MAX_PACKET?
// 9+size==sizeof(bCmd) + sizeof(FTID) + sizeof(size) + size // 9+size==sizeof(bCmd) + sizeof(FTID) + sizeof(size) + size
#endif // !MAX_FTPBUF #endif // !MAX_FTPBUF
@@ -251,7 +251,7 @@ private:
#define ESTRF_USER_START 100 #define ESTRF_USER_START 100
#define ESTRF_PASSWORDCHANGED 110 // 로그인하고 있는 동안에 패스워드가 바뀜 #define ESTRF_PASSWORDCHANGED 110 // Password changed while logged in
void Randomize(); void Randomize();
@@ -268,7 +268,7 @@ union UPacketValue
class CDAPacket : public SOCBase_Class class CDAPacket : public SOCBase_Class
{ {
// Packet의 앞 부분을 처리하고 난 뒷 부분의 가변 파라미터... // Variable parameters in the tail portion after processing the packet header...
public: public:
BYTE m_bCmd; BYTE m_bCmd;
BYTE m_bReserved; BYTE m_bReserved;
@@ -361,8 +361,8 @@ public:
#define C_ROOM_MAKE 232 #define C_ROOM_MAKE 232
// s - name, s - password // s - name, s - password
#define C_ROOM_JOIN 233 #define C_ROOM_JOIN 233
// d - number(Room을 떠나는 것은 -1), s - password // d - number (leaving a Room = -1), s - password
#define S_ROOM_JOIN 233 // C_ROOM_MAKE/C_ROOM_JOIN의 결과... #define S_ROOM_JOIN 233 // Result of C_ROOM_MAKE/C_ROOM_JOIN...
// b - code(CSCODE_OK or error code), d - number // b - code(CSCODE_OK or error code), d - number
#define C_ROOM_UPDS 234 // CSCODE_... + @ #define C_ROOM_UPDS 234 // CSCODE_... + @
@@ -384,13 +384,13 @@ public:
#define S_FTP 254 //... see ftp.txt #define S_FTP 254 //... see ftp.txt
#define X_KEEPALIVE 255 // no parameters, should be ignored... #define X_KEEPALIVE 255 // no parameters, should be ignored...
#define TX_SYSTEM 0 // 시스템 메시지... #define TX_SYSTEM 0 // System message...
#define TX_NORMAL 1 // 일반 채팅 텍스트 #define TX_NORMAL 1 // Regular chat text
#define TX_WARNING 2 // 경고 #define TX_WARNING 2 // Warning
#define TX_ERROR 3 // 오류 #define TX_ERROR 3 // Error
#define TX_FATAL 4 // 치명적인 오류 #define TX_FATAL 4 // Fatal error
#define TX_INFO 5 // 사용자 정보 등의 Information Result... #define TX_INFO 5 // Information result (e.g. user info)...
#define TX_SAY 6 // 귓속말 #define TX_SAY 6 // Whisper
#define TX_LOCAL 7 // local echo.... #define TX_LOCAL 7 // local echo....
#define TX_UNKNOWN 0xffff // unknown... #define TX_UNKNOWN 0xffff // unknown...
@@ -493,7 +493,7 @@ CPacket
protected: protected:
CSOC* m_pSOC; CSOC* m_pSOC;
private: private:
// 이 안의 블럭은 반드시 연속해야 한다... // The block within must be contiguous...
WORD m_wLen; WORD m_wLen;
BYTE m_ba[MAX_PACKET]; BYTE m_ba[MAX_PACKET];
// //
@@ -587,7 +587,7 @@ end of variable PACKET_MAP definitions...
class CFileTransfer : public TDBLNK(CFileTransfer*) class CFileTransfer : public TDBLNK(CFileTransfer*)
{ {
public: public:
// 서버로 부터 받은 정보... - 혹은 클라이언트에게 전해줄 정보... // Information received from server... - or information to relay to client...
BOOL m_bClientSite; BOOL m_bClientSite;
DWORD m_dwFTID; DWORD m_dwFTID;
DWORD m_dwGUARD; DWORD m_dwGUARD;
@@ -680,18 +680,18 @@ protected:
// time out to Drop... // time out to Drop...
DWORD m_dwKARcvTimeOut; DWORD m_dwKARcvTimeOut;
#ifdef WIN32 #ifdef WIN32
// 보통 Login과정에 쓰이는 윈도우 핸들 // Window handle typically used during Login process
HWND m_hWndOwner; HWND m_hWndOwner;
#endif // WIN32 #endif // WIN32
// 보통 글로벌 변수로 쓰이는 소켓포인터에 대한 자동 NULL Assign을 위하여 // For auto NULL assignment of socket pointer typically used as a global variable
PSOC* m_ppSOC; PSOC* m_ppSOC;
// 소켓을 구분하기 위하여 사용자 프로그램에서 쓰이는 아이디 // ID used in user program to identify a socket
// 주로 서버의 경우에는 클라이언트가 접속할 때마다 고유 아이디를 부여하여 사용 // Mainly for servers: assigns a unique ID each time a client connects
// 하나의 Client가 다수의 서버에 접속할 때(주로 Star형) 각각의 접속을 구분할 때 사용 // Used to distinguish each connection when a client connects to multiple servers (Star topology)
// 클라이언트가 하나의 서버에만 접속하는 경우 클라이언트가 서버에 접속 중인지 혹은 접속했는지를 판단할 때 // When a client connects to only one server: used to check if client is connecting or already connected
// CSOCManager::FindSOC(CSOC_SERVER_ID==default)->GetConnectionState()를 사용. // Use CSOCManager::FindSOC(CSOC_SERVER_ID==default)->GetConnectionState().
// limits.h를 include해야함. // Must include limits.h.
// CSOC생성시의 기본값: CSOCServer == CSOC_SERVER_ID(=INT_MIN), CSOCClient == CSOC_CLIENT_ID(=0), CSOCListen == CSOC_LISTEN_ID(=-1) // Default values at CSOC creation: CSOCServer==CSOC_SERVER_ID(INT_MIN), CSOCClient==CSOC_CLIENT_ID(0), CSOCListen==CSOC_LISTEN_ID(-1)
union { union {
int m_nID; int m_nID;
UINT m_uID; UINT m_uID;
@@ -725,8 +725,8 @@ protected:
DWORD m_xGracefulRemote: 1; DWORD m_xGracefulRemote: 1;
DWORD m_xAbortyLocal: 1; DWORD m_xAbortyLocal: 1;
DWORD m_xAbortyRemote: 1; DWORD m_xAbortyRemote: 1;
DWORD m_xLoginStarted: 1; // 사용자가 직접 값을 Setting해야 한다. DWORD m_xLoginStarted: 1; // Must be set directly by the caller.
DWORD m_xLoginOK: 1; // 사용자가 직접 값을 Setting해야 한다. DWORD m_xLoginOK: 1; // Must be set directly by the caller.
} m_DW; } m_DW;
DWORD m_dwVarFlags; DWORD m_dwVarFlags;
}; };
+1 -1
View File
@@ -6,7 +6,7 @@ inline BOOL AssertDialog(const char* pcszExpr, const char* pcszfile, int nLine)
{ {
char szBuf[MAX_PATH * 2]; char szBuf[MAX_PATH * 2];
sprintf(szBuf, "\"%s\" 파일의 %d줄에서 ASSERT!!!\n\n디버깅을 하시겠습니까?", pcszfile, nLine); sprintf(szBuf, "ASSERT!!! in \"%s\" at line %d\n\nDo you want to debug?", pcszfile, nLine);
#ifdef WIN32 #ifdef WIN32
return ::MessageBox(NULL, szBuf, pcszExpr, MB_YESNO) == IDYES; return ::MessageBox(NULL, szBuf, pcszExpr, MB_YESNO) == IDYES;
+1 -1
View File
@@ -6,7 +6,7 @@ inline BOOL AssertDialog(const char* pcszExpr, const char* pcszfile, int nLine)
{ {
char szBuf[MAX_PATH * 2]; char szBuf[MAX_PATH * 2];
sprintf(szBuf, "\"%s\" 파일의 %d줄에서 ASSERT!!!\n\n디버깅을 하시겠습니까?", pcszfile, nLine); sprintf(szBuf, "ASSERT!!! in \"%s\" at line %d\n\nDo you want to debug?", pcszfile, nLine);
#ifdef WIN32 #ifdef WIN32
return ::MessageBox(NULL, szBuf, pcszExpr, MB_YESNO) == IDYES; return ::MessageBox(NULL, szBuf, pcszExpr, MB_YESNO) == IDYES;
@@ -76,18 +76,18 @@ typedef struct
typedef struct typedef struct
{ {
//· code for changing sort order or priority levels //· code for changing sort order or priority levels
//· new sort order //· new sort order
//· new priority level //· new priority level
//· priority set to remove //· priority set to remove
//· priority set to add //· priority set to add
} AdjustCommandData; } AdjustCommandData;
typedef struct typedef struct
{ {
//· command area from which to remove command //· command area from which to remove command
//· command id of command to remove //· command id of command to remove
//· other info to pick what command to remove //· other info to pick what command to remove
} RemoveCommandData; } RemoveCommandData;
union CommandUnion union CommandUnion
@@ -104,8 +104,8 @@ void CRIOMAIN::UpdateJoystickY (DIJOYSTATE &js)
lJ = JoystickY_Center - g_JoystickY; lJ = JoystickY_Center - g_JoystickY;
// 고감도 // High sensitivity
// Dead Zone 에서 벗어난 시점을 0으로 계산한다 // Calculate from the moment of exiting the Dead Zone as 0
if (lJ > 0) { if (lJ > 0) {
lJ -= DEADZONE_JOYSTICK; lJ -= DEADZONE_JOYSTICK;
} else if (lJ < 0) { } else if (lJ < 0) {
+55 -42
View File
@@ -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;
+87 -87
View File
@@ -19,16 +19,16 @@
#include <MLR\MLRTexture.hpp> #include <MLR\MLRTexture.hpp>
#include "MWObject.hpp" #include "MWObject.hpp"
//상훈짱 begin //sanghoon begin
#include <windows.h> #include <windows.h>
#include <ddraw.h> #include <ddraw.h>
#include <d3d.h> #include <d3d.h>
#include <GameOS\render.hpp> #include <GameOS\render.hpp>
#define RADAR_SCALE 2.8f #define RADAR_SCALE 2.8f
//상훈짱 end //sanghoon end
int m_gCool; // int m_gCool; // hyun: coolant
namespace MW4AI namespace MW4AI
{ {
@@ -121,22 +121,22 @@ GUIRadarManager::GUIRadarManager() :
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// //
//상훈 //sanghoon
extern bool sh_game_started; extern bool sh_game_started;
GUIRadarManager::~GUIRadarManager() GUIRadarManager::~GUIRadarManager()
{ {
//상훈 앞 //sanghoon begin
sh_game_started=false; sh_game_started=false;
//상훈 뒤 //sanghoon end
delete m_RangeText; delete m_RangeText;
} }
void DrawMapBoundary() void DrawMapBoundary()
{ {
//DrawImplementation에서 추출해왔음.. //Extracted from DrawImplementation..
//미션이 시작한 후 한번만 그리게된다.(맵상의 작전 영역은 변하지 않으므로..) //Drawn only once after mission start (operation area on map does not change..)
Scalar multx,multz; Scalar multx,multz;
multx = 200.0f/(MW4AI::MaxX - MW4AI::MinX); multx = 200.0f/(MW4AI::MaxX - MW4AI::MinX);
@@ -148,7 +148,7 @@ void DrawMapBoundary()
int numpts = ptlist.GetLength (); int numpts = ptlist.GetLength ();
HDC hdcBackImage; HDC hdcBackImage;
radar_device.pDDSBackground->GetDC( &hdcBackImage);//백버퍼 준비용.. 이미지.. radar_device.pDDSBackground->GetDC( &hdcBackImage);//Image for back buffer preparation..
HPEN hpenold=(HPEN)SelectObject(hdcBackImage,CreatePen(PS_SOLID,1,RGB(255,0,0))); HPEN hpenold=(HPEN)SelectObject(hdcBackImage,CreatePen(PS_SOLID,1,RGB(255,0,0)));
for (int i=0;i<numpts;i++){ for (int i=0;i<numpts;i++){
@@ -184,7 +184,7 @@ void DrawMapBoundary()
void GUIRadarManager::Reset (void) void GUIRadarManager::Reset (void)
{ {
//상훈 //sanghoon
MWApplication *m_App; MWApplication *m_App;
m_App = MWApplication::GetInstance (); m_App = MWApplication::GetInstance ();
@@ -192,19 +192,19 @@ void GUIRadarManager::Reset (void)
bool networking = MWApplication::GetInstance()->networkingFlag; bool networking = MWApplication::GetInstance()->networkingFlag;
if (!networking) if (!networking)
m_RadarMode = 0; m_RadarMode = 0;
//상훈 //sanghoon
if(hsh_initialized) if(hsh_initialized)
DrawMapBoundary(); DrawMapBoundary();
} }
//상훈 앞 //sanghoon begin
/* /*
char * radar_text[]={ char * radar_text[]={
"JUMP\nJET","SHUT\nDOWN","OVER\nRIDE","FLUSH","CROUCH","", "JUMP\nJET","SHUT\nDOWN","OVER\nRIDE","FLUSH","CROUCH","",
"RANGE","RADAR\nMODE","LIGHT\nAMP","SEARCH\nLIGHT","AUTO\nCENTER" "RANGE","RADAR\nMODE","LIGHT\nAMP","SEARCH\nLIGHT","AUTO\nCENTER"
}; };
*/ */
//상훈 뒤 //sanghoon end
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// //
@@ -246,7 +246,7 @@ if(!hsh_initialized){
Check_Pointer(vehicle); Check_Pointer(vehicle);
Check_Pointer(vehicle->GetSensor()); Check_Pointer(vehicle->GetSensor());
/* /*
//상훈 앞 맵 //sanghoon begin: map
Scalar multx,multz; Scalar multx,multz;
multx = 200.0f/(MW4AI::MaxX - MW4AI::MinX); multx = 200.0f/(MW4AI::MaxX - MW4AI::MinX);
@@ -655,7 +655,7 @@ if(!hsh_initialized){
int i; int i;
// Secondary Maps // Secondary Maps
//맵과 맵 경계선을 그린다. (게임중에 변하지 않으므로 한번만 그린다.) //Draw map and boundary. (Drawn once since it does not change during game.)
if(!radar_device.MapDrawn){ if(!radar_device.MapDrawn){
extern char AssetsDirectory1[MAX_PATH]; extern char AssetsDirectory1[MAX_PATH];
@@ -724,8 +724,8 @@ if(!hsh_initialized){
Check_Pointer(vehicle->GetSensor()); Check_Pointer(vehicle->GetSensor());
///////////////////// MAP 시작 ////////////////////// ///////////////////// MAP BEGIN //////////////////////
/////Torso Sweep그리기.. 시작 /////Torso Sweep draw.. begin
Scalar multx,multz; Scalar multx,multz;
multx = 200.0f/(MW4AI::MaxX - MW4AI::MinX); multx = 200.0f/(MW4AI::MaxX - MW4AI::MinX);
@@ -759,16 +759,16 @@ if(!hsh_initialized){
radar_device.DrawQuad(-pos.x+240-1,-pos.y+508-1,-pos.x+240+2,-pos.y+508+2,0xFF0000C0); radar_device.DrawQuad(-pos.x+240-1,-pos.y+508-1,-pos.x+240+2,-pos.y+508+2,0xFF0000C0);
} }
/////Torso Sweep그리기.. 끝 /////Torso Sweep draw.. end
//맵상에 오브젝트들 그리기. //Draw objects on map.
{ {
radar_device.pD3DDevice->SetTexture(0,radar_device.pDDSTexture); radar_device.pD3DDevice->SetTexture(0,radar_device.pDDSTexture);
MWObject *hsh_current_object; MWObject *hsh_current_object;
for(i=0;i<vehicle->GetSensor()->numberOfContacts;i++){ for(i=0;i<vehicle->GetSensor()->numberOfContacts;i++){
hsh_current_object=vehicle->GetSensor()->GetSensorData()[i]->object.GetCurrent(); hsh_current_object=vehicle->GetSensor()->GetSensorData()[i]->object.GetCurrent();
if (hsh_current_object != NULL){ if (hsh_current_object != NULL){
bool draw_contact = true;//해당 오브젝트를 그릴것인지..에대한 플래그.. bool draw_contact = true;//Flag: whether to draw this object..
// MSL 5.02 Bot on Map // MSL 5.02 Bot on Map
if (hsh_current_object->GetAI()==NULL && (MWApplication::GetInstance()->networkingFlag == false))draw_contact = false; if (hsh_current_object->GetAI()==NULL && (MWApplication::GetInstance()->networkingFlag == false))draw_contact = false;
@@ -833,10 +833,10 @@ if(!hsh_initialized){
} }
} }
///////////////////// MAP ////////////////////// ///////////////////// MAP END //////////////////////
///////////////////// RADAR 시작 ////////////////////// ///////////////////// RADAR BEGIN //////////////////////
radar_device.pD3DDevice->SetTexture(0,0); radar_device.pD3DDevice->SetTexture(0,0);
@@ -855,7 +855,7 @@ if(!hsh_initialized){
world_to_vehicle.Invert(vehicle_to_world); world_to_vehicle.Invert(vehicle_to_world);
// 경계선 그리기.. // Draw boundary line..
Mission *miss; Mission *miss;
miss = Mission::GetInstance (); miss = Mission::GetInstance ();
@@ -900,7 +900,7 @@ if(!hsh_initialized){
} }
//Torso View그리기.. //Draw Torso View..
//HSH_RenderRadarTorsoView(-m_TorsoTwist); //HSH_RenderRadarTorsoView(-m_TorsoTwist);
radar_device.pD3DDevice->SetTexture(0,radar_device.pDDSTexture); radar_device.pD3DDevice->SetTexture(0,radar_device.pDDSTexture);
radar_device.pD3DDevice->SetRenderState( D3DRENDERSTATE_ALPHABLENDENABLE, TRUE ); radar_device.pD3DDevice->SetRenderState( D3DRENDERSTATE_ALPHABLENDENABLE, TRUE );
@@ -914,7 +914,7 @@ if(!hsh_initialized){
radar_device.pD3DDevice->SetTextureStageState(0,D3DTSS_MAGFILTER, D3DTFG_POINT ); radar_device.pD3DDevice->SetTextureStageState(0,D3DTSS_MAGFILTER, D3DTFG_POINT );
radar_device.pD3DDevice->SetTextureStageState(0,D3DTSS_MINFILTER, D3DTFG_POINT ); radar_device.pD3DDevice->SetTextureStageState(0,D3DTSS_MINFILTER, D3DTFG_POINT );
//Radar범위 그리기. //Draw Radar range.
char text[10]; char text[10];
if (radarRange != radarRangeOrg) if (radarRange != radarRangeOrg)
sprintf (text,"NoLmt"); sprintf (text,"NoLmt");
@@ -923,11 +923,11 @@ if(!hsh_initialized){
//HSH_DrawRadarNumber(345,386,text,1); //HSH_DrawRadarNumber(345,386,text,1);
radar_device.pFont[1].DrawText(80,350,0xFFFFFFFF,text,TEXTALIGN_ORG); radar_device.pFont[1].DrawText(80,350,0xFFFFFFFF,text,TEXTALIGN_ORG);
//ActiveMode그리기.. //Draw ActiveMode..
char* modechar=(vehicle->GetSensor ()->GetSensorMode () == Sensor::ActiveMode)?"Active":"Passive"; char* modechar=(vehicle->GetSensor ()->GetSensorMode () == Sensor::ActiveMode)?"Active":"Passive";
radar_device.pFont[1].DrawText(395,350,0xFFFFFF,modechar,TEXTALIGN_ORG); radar_device.pFont[1].DrawText(395,350,0xFFFFFF,modechar,TEXTALIGN_ORG);
//빌딩 그리기 //Draw buildings.
MWObject *current_object; MWObject *current_object;
for(i=0;i<vehicle->GetSensor()->numberOfBuildingContacts;i++) for(i=0;i<vehicle->GetSensor()->numberOfBuildingContacts;i++)
{ {
@@ -993,7 +993,7 @@ if(!hsh_initialized){
} }
} }
//Object그리기. //Draw Objects.
for(i=0;i<vehicle->GetSensor()->numberOfContacts;i++){ for(i=0;i<vehicle->GetSensor()->numberOfContacts;i++){
current_object=vehicle->GetSensor()->GetSensorData()[i]->object.GetCurrent(); current_object=vehicle->GetSensor()->GetSensorData()[i]->object.GetCurrent();
if (current_object != NULL){ if (current_object != NULL){
@@ -1081,7 +1081,7 @@ if(!hsh_initialized){
} }
} }
//Navigation Point그리기. //Draw Navigation Points.
j=0; j=0;
ChainIteratorOf<NavPoint *> iter (NavPoint::s_RevealedNavPoints); ChainIteratorOf<NavPoint *> iter (NavPoint::s_RevealedNavPoints);
NavPoint *nav; NavPoint *nav;
@@ -1136,7 +1136,7 @@ if(!hsh_initialized){
radar_device.DrawTexture(posx2,posy2,0xFFFFFFFF,(60+id*12),0,(60+id*12)+12,12); radar_device.DrawTexture(posx2,posy2,0xFFFFFFFF,(60+id*12),0,(60+id*12)+12,12);
} }
///////////////////// RADAR ////////////////////// ///////////////////// RADAR END //////////////////////
} }
} }
@@ -1586,23 +1586,23 @@ if(!hsh_initialized){
DWORD color = MakeColor (64,64,64,255); DWORD color = MakeColor (64,64,64,255);
//막대 게이지의 백그라운드.. 기준.. //Bar gauge background baseline..
m_Textures[1]->Draw (loc,size,color,HUDTexture::NO_FLIP,true); m_Textures[1]->Draw (loc,size,color,HUDTexture::NO_FLIP,true);
color = MakeColor (255,255,255,255); color = MakeColor (255,255,255,255);
loc.y += size.y - targetyval; loc.y += size.y - targetyval;
size.y = (Scalar) targetyval; size.y = (Scalar) targetyval;
m_Textures[0]->TopLeft (m_Textures[0]->Left (),(Scalar) (m_BaseBottom - targetyval)); m_Textures[0]->TopLeft (m_Textures[0]->Left (),(Scalar) (m_BaseBottom - targetyval));
m_Textures[0]->BlendMode (gos_BlendDecal); m_Textures[0]->BlendMode (gos_BlendDecal);
//삼색 막대 게이지 그리기..(clipping size를 조절함으로써.. 값을 조절하는 효과를 나타낸다.) //Draw tri-color bar gauge.. (value adjusted by modifying clip size..)
m_Textures[0]->Draw (loc,size,color,HUDTexture::NO_FLIP); m_Textures[0]->Draw (loc,size,color,HUDTexture::NO_FLIP);
color = MakeColor (0,125,0,250); color = MakeColor (0,125,0,250);
size = Size (); size = Size ();
loc = Location (); loc = Location ();
//막대 게이지의 프레임. //Bar gauge frame.
DrawFrame ((int) (loc.x-2),(int) (loc.y-2),(int) (loc.x+size.x),(int) (loc.y+size.y),color); DrawFrame ((int) (loc.x-2),(int) (loc.y-2),(int) (loc.x+size.x),(int) (loc.y+size.y),color);
//온도 텍스트의 프레임.. //Temperature text frame..
DrawFrame (261,542,303,560,color); DrawFrame (261,542,303,560,color);
m_HeatText->TopLeft (261,542); m_HeatText->TopLeft (261,542);
m_HeatText->BottomRight (303,560); m_HeatText->BottomRight (303,560);
@@ -1611,23 +1611,23 @@ if(!hsh_initialized){
DWORD textw,texth; DWORD textw,texth;
m_HeatText->DrawSize (textw,texth); m_HeatText->DrawSize (textw,texth);
//온도를 정해진 색으로 출력한다.(게이지는 텍스쳐이므로 색을 지정할 필요가 없다.) //Display temperature in its designated color. (Gauge is a texture, no color spec needed.)
m_HeatText->Draw (Point3D (282.0f - (textw/2.0f),551.0f - (texth/2.0f),0.9f)); m_HeatText->Draw (Point3D (282.0f - (textw/2.0f),551.0f - (texth/2.0f),0.9f));
DrawLine (304,549,310,549,color); DrawLine (304,549,310,549,color);
DrawLine (309,(int) heaty,309,549,color); DrawLine (309,(int) heaty,309,549,color);
DrawLine ((int) (loc.x-2),(int) (heaty),309,(int) (heaty),color); DrawLine ((int) (loc.x-2),(int) (heaty),309,(int) (heaty),color);
}else if(sh_step==1){ }else if(sh_step==1){
//radar manager는 shutdown 시에 호출되지 않으므로.. 여기서 추가적으로 state를 업데이트 시켜준다. //radar manager is not called on shutdown.. state updated additionally here.
MechWarrior4::VehicleInterface* p = MechWarrior4::VehicleInterface::GetInstance(); MechWarrior4::VehicleInterface* p = MechWarrior4::VehicleInterface::GetInstance();
p->GetGUIRadarStates(radar_device.recent_state); p->GetGUIRadarStates(radar_device.recent_state);
int targetyval = (int) ((m_Heat * 23)/100.0f); int targetyval = (int) ((m_Heat * 23)/100.0f);
Clamp (targetyval,0,22); Clamp (targetyval,0,22);
//heat의 범위는??? 0~100??? //What is the range of heat??? 0~100???
//target은 그리지 않고 현재 온도만 그린다. //Draw current temperature only, without the target.
float sizey=256; float sizey=256;
//삼색 막대 게이지 그리기..(clipping size를 조절함으로써.. 값을 조절하는 효과를 나타낸다.) //Draw tri-color bar gauge.. (value adjusted by modifying clip size..)
{ {
radar_device.pD3DDevice->SetTexture(0,radar_device.pDDSTexture); radar_device.pD3DDevice->SetTexture(0,radar_device.pDDSTexture);
//backbground image //backbground image
@@ -1642,7 +1642,7 @@ if(!hsh_initialized){
radar_device.pD3DDevice->SetTexture(0,0); radar_device.pD3DDevice->SetTexture(0,0);
radar_device.DrawFrame(54-1,630-188-3,80+1,630+3,0xFFFFFFFF); radar_device.DrawFrame(54-1,630-188-3,80+1,630+3,0xFFFFFFFF);
} }
//텍스트 //Text
{ {
char buf[16]; char buf[16];
// MSL 5.02 Heat Scale Header // MSL 5.02 Heat Scale Header
@@ -1664,7 +1664,7 @@ HUDJump::HUDJump ()
m_TargetJump = -1.0f; m_TargetJump = -1.0f;
Location (Point3D (467,539,0.9f)); Location (Point3D (467,539,0.9f));
Size (Point3D (7,49,0.9f)); Size (Point3D (7,49,0.9f));
//j라고 하는 작은 글자... <==실제로는 잘 보이지 않는다. //Small 'j' character... <==actually barely visible.
AddTexture ("hud\\hud4",0,98,200,106,207); AddTexture ("hud\\hud4",0,98,200,106,207);
} }
@@ -1703,14 +1703,14 @@ if(!hsh_initialized){
size = Size (); size = Size ();
loc = Location (); loc = Location ();
DWORD color = MakeColor (255,255,255,250); // 원래 255,255,255,250이었음 DWORD color = MakeColor (255,255,255,250); // was originally 255,255,255,250
//j라고 하는 작은 글자... //Small 'j' character...
m_Textures[0]->Draw (Point3D (loc.x+2,loc.y - m_Textures[0]->Size().y-2.0f,0.9f),m_Textures[0]->Size (),color); m_Textures[0]->Draw (Point3D (loc.x+2,loc.y - m_Textures[0]->Size().y-2.0f,0.9f),m_Textures[0]->Size (),color);
int targetyval = (int) (m_Jump * size.y); int targetyval = (int) (m_Jump * size.y);
color = MakeColor (0,125,0,250); color = MakeColor (0,125,0,250);
//녹색 게이지.. //Green gauge..
my_DrawRect ((int) (loc.x),(int) (loc.y+size.y-targetyval),(int) (loc.x+size.x),(int) (loc.y+size.y),color); my_DrawRect ((int) (loc.x),(int) (loc.y+size.y-targetyval),(int) (loc.x+size.x),(int) (loc.y+size.y),color);
if ((m_Jump != 0) && (m_Alpha != 0)) if ((m_Jump != 0) && (m_Alpha != 0))
{ {
@@ -1718,11 +1718,11 @@ if(!hsh_initialized){
my_DrawRect ((int) (loc.x),(int) (loc.y+size.y-targetyval),(int) (loc.x+size.x),(int) (loc.y+size.y),color); my_DrawRect ((int) (loc.x),(int) (loc.y+size.y-targetyval),(int) (loc.x+size.x),(int) (loc.y+size.y),color);
} }
//게이지 맨위의 흰선.. //White line at the top of gauge..
color = MakeColor (255,255,255,200); color = MakeColor (255,255,255,200);
DrawLine ((int) (loc.x),(int) (loc.y+size.y-targetyval),(int) (loc.x+size.x),(int) (loc.y+size.y-targetyval),color); DrawLine ((int) (loc.x),(int) (loc.y+size.y-targetyval),(int) (loc.x+size.x),(int) (loc.y+size.y-targetyval),color);
//테두리 그리기.. //Draw border..
color = MakeColor (0,125,0,250); color = MakeColor (0,125,0,250);
DrawFrame ((int) loc.x,(int) (loc.y),(int) (loc.x+size.x),(int) (loc.y+size.y),color); DrawFrame ((int) loc.x,(int) (loc.y),(int) (loc.x+size.x),(int) (loc.y+size.y),color);
}else if(sh_step==1){ }else if(sh_step==1){
@@ -1736,7 +1736,7 @@ if(!hsh_initialized){
} }
} }
//전반적으로 jumpjet과 거의 같다. //Overall almost identical to jumpjet.
HUDCoolant::HUDCoolant () HUDCoolant::HUDCoolant ()
{ {
m_Alpha = 255; m_Alpha = 255;
@@ -1745,7 +1745,7 @@ HUDCoolant::HUDCoolant ()
m_Cool = 100; m_Cool = 100;
Location (Point3D (332,539,0.9f)); Location (Point3D (332,539,0.9f));
Size (Point3D (7,49,0.9f)); Size (Point3D (7,49,0.9f));
//C라고 하는 작은 글자.. //Small 'C' character..
AddTexture ("hud\\hud4",0,88,200,96,207); AddTexture ("hud\\hud4",0,88,200,96,207);
} }
@@ -1782,7 +1782,7 @@ if(!hsh_initialized){
loc = Location (); loc = Location ();
DWORD color = MakeColor (0,125,0,250); DWORD color = MakeColor (0,125,0,250);
//C라고 하는 작은 글자.. //Small 'C' character..
m_Textures[0]->Draw (Point3D (loc.x+2,loc.y - m_Textures[0]->Size().y-2.0f,0.9f),m_Textures[0]->Size (),color); m_Textures[0]->Draw (Point3D (loc.x+2,loc.y - m_Textures[0]->Size().y-2.0f,0.9f),m_Textures[0]->Size (),color);
m_gCool = m_Cool; m_gCool = m_Cool;
@@ -1790,19 +1790,19 @@ if(!hsh_initialized){
Clamp (targetyval,0,(int) size.y); Clamp (targetyval,0,(int) size.y);
color = MakeColor (0,100,255,250); color = MakeColor (0,100,255,250);
//게이지 그리기.. //Draw gauge..
my_DrawRect ((int) (loc.x),(int) (loc.y+size.y-targetyval),(int) (loc.x+size.x),(int) (loc.y+size.y),color); my_DrawRect ((int) (loc.x),(int) (loc.y+size.y-targetyval),(int) (loc.x+size.x),(int) (loc.y+size.y),color);
if ((m_Cool != 0) && (m_Alpha != 0)) if ((m_Cool != 0) && (m_Alpha != 0))
{ {
//flush했을때.. 흰색으로 깜박이는 효과 그리기... //When flushed.. draw white blinking effect...
color = MakeColor (255,255,255,m_Alpha); color = MakeColor (255,255,255,m_Alpha);
my_DrawRect ((int) (loc.x),(int) (loc.y+size.y-targetyval),(int) (loc.x+size.x),(int) (loc.y+size.y),color); my_DrawRect ((int) (loc.x),(int) (loc.y+size.y-targetyval),(int) (loc.x+size.x),(int) (loc.y+size.y),color);
} }
color = MakeColor (255,255,255,200); color = MakeColor (255,255,255,200);
//게이지 위쪽의 흰선.. //White line above gauge..
DrawLine ((int) (loc.x),(int) (loc.y+size.y-targetyval),(int) (loc.x+size.x),(int) (loc.y+size.y-targetyval),color); DrawLine ((int) (loc.x),(int) (loc.y+size.y-targetyval),(int) (loc.x+size.x),(int) (loc.y+size.y-targetyval),color);
//게이지를 둘러싸는 프레임.. //Frame surrounding gauge..
color = MakeColor (0,125,0,250); color = MakeColor (0,125,0,250);
DrawFrame ((int) loc.x,(int) (loc.y),(int) (loc.x+size.x),(int) (loc.y+size.y),color); DrawFrame ((int) loc.x,(int) (loc.y),(int) (loc.x+size.x),(int) (loc.y+size.y),color);
}else if(sh_step==1){ }else if(sh_step==1){
@@ -1817,7 +1817,7 @@ if(!hsh_initialized){
} }
//속도를 나타내는... HUD Component //HUD Component displaying speed...
namespace NHUDSPEED namespace NHUDSPEED
{ {
// const int for_speed_box[12] = {0,4,8,12,16,20,24,28,32,36,40,44}; // const int for_speed_box[12] = {0,4,8,12,16,20,24,28,32,36,40,44};
@@ -1928,25 +1928,25 @@ if(!hsh_initialized){
speedy = loc.y + 56 - fred; speedy = loc.y + 56 - fred;
DWORD color = MakeColor (255,255,255,255); DWORD color = MakeColor (255,255,255,255);
//게이지 백그라운드 눈금.. //Gauge background tick marks..
m_Textures[1]->Draw (loc,size,color,HUDTexture::NO_FLIP,true); m_Textures[1]->Draw (loc,size,color,HUDTexture::NO_FLIP,true);
loc.y += top; loc.y += top;
size.y = (Scalar) bottom - top; size.y = (Scalar) bottom - top;
//삼색 막대 게이지 그리기..(clipping size를 조절함으로써.. 값을 조절하는 효과를 나타낸다.) //Draw tri-color bar gauge.. (value adjusted by modifying clip size..)
m_Textures[0]->TopLeft (m_Textures[0]->Left (),(Scalar) (top)); m_Textures[0]->TopLeft (m_Textures[0]->Left (),(Scalar) (top));
m_Textures[0]->BottomRight (m_Textures[0]->Right (),(Scalar) (bottom)); m_Textures[0]->BottomRight (m_Textures[0]->Right (),(Scalar) (bottom));
m_Textures[0]->BlendMode (gos_BlendDecal); m_Textures[0]->BlendMode (gos_BlendDecal);
//colored 게이지..녹색으로 되어 있다. //Colored gauge.. currently green.
m_Textures[0]->Draw (loc,size,color,HUDTexture::NO_FLIP,true); m_Textures[0]->Draw (loc,size,color,HUDTexture::NO_FLIP,true);
color = MakeColor (0,125,0,250); color = MakeColor (0,125,0,250);
size = Size (); size = Size ();
loc = Location (); loc = Location ();
//게이지를 둘러싸는.. 프레임 그리기.. //Draw frame surrounding gauge..
DrawFrame ((int) (loc.x-2),(int) (loc.y-2),(int) (loc.x+size.x),(int) (loc.y+size.y),color); DrawFrame ((int) (loc.x-2),(int) (loc.y-2),(int) (loc.x+size.x),(int) (loc.y+size.y),color);
//속도 표시하는 프레임... //Speed display frame...
DrawFrame (506,537,548,555,color); DrawFrame (506,537,548,555,color);
m_SpeedText->TopLeft (506,537); m_SpeedText->TopLeft (506,537);
m_SpeedText->BottomRight (548,555); m_SpeedText->BottomRight (548,555);
@@ -1958,15 +1958,15 @@ if(!hsh_initialized){
DWORD textw,texth; DWORD textw,texth;
m_SpeedText->DrawSize (textw,texth); m_SpeedText->DrawSize (textw,texth);
//속도 표시하는 텍스트.. 앞/뒤 방향에 따라서 색이 녹식/파란색.....으로 된다. //Speed text.. color is green/blue depending on forward/backward direction.....
m_SpeedText->Draw (Point3D (527.0f - (textw/2.0f),546.0f - (texth/2.0f),0.9f)); m_SpeedText->Draw (Point3D (527.0f - (textw/2.0f),546.0f - (texth/2.0f),0.9f));
//속도프레임-게이지 프레임 연결하는 3 segment라인.. //3-segment line connecting speed frame to gauge frame..
DrawLine (498,549,506,549,color); DrawLine (498,549,506,549,color);
DrawLine (498,(int) speedy,498,549,color); DrawLine (498,(int) speedy,498,549,color);
DrawLine ((int) (loc.x+size.x+2),(int) (speedy),498,(int) (speedy),color); DrawLine ((int) (loc.x+size.x+2),(int) (speedy),498,(int) (speedy),color);
}else if(sh_step==1){ }else if(sh_step==1){
//적절하지는 않지만.. 미션 시간을 speed에서 같이 그린다. //Not ideal, but draw mission time alongside speed display.
//미션 시간 그리기...hudtimer.cpp에 DrawImplementation에서 따온것임.. //Draw mission timer... taken from DrawImplementation in hudtimer.cpp..
{ {
MWMission *mwmiss = Cast_Object (MWMission *,Mission::GetInstance ()); MWMission *mwmiss = Cast_Object (MWMission *,Mission::GetInstance ());
Verify (mwmiss); Verify (mwmiss);
@@ -1983,7 +1983,7 @@ if(!hsh_initialized){
} }
float offset; float offset;
//126,62.. 188의 속도.. 2:1로 나누면.. //126,62.. speed 188.. divided 2:1..
//backbground image //backbground image
radar_device.pD3DDevice->SetTexture(0,radar_device.pDDSTexture); radar_device.pD3DDevice->SetTexture(0,radar_device.pDDSTexture);
@@ -2094,8 +2094,8 @@ HUDNav::HUDNav()
navPointName = new HUDText (); navPointName = new HUDText ();
navPointRange = new HUDNumberText (); navPointRange = new HUDNumberText ();
playerAngle = new HUDNumberText (); playerAngle = new HUDNumberText ();
navPointRange->SetSize (HUDText::MEDIUM_SIZE); // 원래 SMALL_SIZE였음 navPointRange->SetSize (HUDText::MEDIUM_SIZE); // was originally SMALL_SIZE
playerAngle->SetSize (HUDText::MEDIUM_SIZE); // 원래 SMALL_SIZE였음 playerAngle->SetSize (HUDText::MEDIUM_SIZE); // was originally SMALL_SIZE
m_NavAlphaTime = 0; m_NavAlphaTime = 0;
@@ -2203,14 +2203,14 @@ if(!hsh_initialized){
m_Textures[10]->TopLeft ((Scalar) (m_BaseLeft + offset),m_Textures[10]->Top ()); m_Textures[10]->TopLeft ((Scalar) (m_BaseLeft + offset),m_Textures[10]->Top ());
size = m_Textures[10]->Size (); size = m_Textures[10]->Size ();
m_Textures[10]->Draw (loc,size,color,HUDTexture::NO_FLIP,true); m_Textures[10]->Draw (loc,size,color,HUDTexture::NO_FLIP,true);
//2번 aux의 줄자..의 대부분...(이걸로 표시되지 않을때.. 다음걸로 표시한다.) //Main portion of aux2 ruler... (if not displayable here, use next one.)
#if 1 #if 1
loc.x += size.x; loc.x += size.x;
loc.x-=1; loc.x-=1;
m_Textures[13]->BottomRight ((Scalar) m_BaseLeft+offset,m_Textures[13]->Bottom ()); m_Textures[13]->BottomRight ((Scalar) m_BaseLeft+offset,m_Textures[13]->Bottom ());
size = m_Textures[13]->Size (); size = m_Textures[13]->Size ();
m_Textures[13]->Draw (loc,size,color,HUDTexture::NO_FLIP,true); m_Textures[13]->Draw (loc,size,color,HUDTexture::NO_FLIP,true);
//2번 aux의 줄자의 짦은 부분.... //Short tick marks of aux2 ruler....
#endif #endif
int heading = m_PlayerFacing; int heading = m_PlayerFacing;
@@ -2223,7 +2223,7 @@ if(!hsh_initialized){
bool draw = false; bool draw = false;
if (dir < 0) if (dir < 0)
dir += 360; dir += 360;
else if (dir > 360)//상훈 고침.. 원래는 --> "else if (dir > 360)" 였음.. else if (dir > 360)//sanghoon fix: original was --> "else if (dir > 360)"..
dir -= 360; dir -= 360;
switch (dir) switch (dir)
{ {
@@ -2265,11 +2265,11 @@ if(!hsh_initialized){
navText[textid]->DrawSize (dx,dy); navText[textid]->DrawSize (dx,dy);
textloc.x -= dx/2; textloc.x -= dx/2;
navText[textid]->Draw (textloc); navText[textid]->Draw (textloc);
//2번 aux방위각 표시.. 340 350 N 10 20... //Aux2 bearing display.. 340 350 N 10 20...
} }
} }
//2번 aux mech의 방향각도 표시... //Aux2 mech heading angle display...
color = Color (); color = Color ();
DrawFrame (400-13,10,400+13,22,color); DrawFrame (400-13,10,400+13,22,color);
DWORD dx,dy; DWORD dx,dy;
@@ -2288,7 +2288,7 @@ if(!hsh_initialized){
size = m_Textures[11]->Size (); size = m_Textures[11]->Size ();
color = Color (); color = Color ();
m_Textures[11]->Draw (Point3D (400.0f,44.0f,0.9f),size,color); m_Textures[11]->Draw (Point3D (400.0f,44.0f,0.9f),size,color);
//2번 aux 중심표시.. 역삼각형..(매우작음) //Aux2 center indicator.. inverted triangle.. (very small)
if (m_NavPointRange != -1) if (m_NavPointRange != -1)
{ {
@@ -2299,9 +2299,9 @@ if(!hsh_initialized){
textloc.y = 0; textloc.y = 0;
textloc.z = 0; textloc.z = 0;
// Draw navpoint bug or arrows // Draw navpoint bug or arrows
//2번 aux navigation //Aux2 navigation
//navpoint bug:... 목표를 나타내는 동그라미를 발한다.(ruler안에 표시가능할때) //navpoint: draw circle indicating objective (when displayable in ruler)
//arrow ruler안에 표시가 불가능할때.. 방향만 좌/우 화살표로서 표시한다. //When unable to display in arrow ruler.. show direction with left/right arrow only.
DWORD color = (m_NavAlpha << 24) + 0x00AF00; DWORD color = (m_NavAlpha << 24) + 0x00AF00;
size = Size (); size = Size ();
@@ -2346,7 +2346,7 @@ if(!hsh_initialized){
textloc.y += 5; textloc.y += 5;
textloc.z = 0.9f; textloc.z = 0.9f;
} }
//지점 타켓의 이름을 그린다. //Draw the name of the point target.
DWORD dx,dy; DWORD dx,dy;
navPointName->TopLeft (textloc.x-50.0f,textloc.y-2.0f); navPointName->TopLeft (textloc.x-50.0f,textloc.y-2.0f);
navPointName->BottomRight (textloc.x+50.0f,textloc.y+20.0f); navPointName->BottomRight (textloc.x+50.0f,textloc.y+20.0f);
@@ -2357,7 +2357,7 @@ if(!hsh_initialized){
navPointName->Draw (textloc); navPointName->Draw (textloc);
textloc.x += dx/2; textloc.x += dx/2;
//지점 타켓의 거리를 그린다. //Draw distance to point target.
textloc.y += 12.0f; textloc.y += 12.0f;
navPointName->TopLeft (textloc.x-50.0f,textloc.y-2.0f); navPointName->TopLeft (textloc.x-50.0f,textloc.y-2.0f);
navPointName->BottomRight (textloc.x+50.0f,textloc.y+20.0f); navPointName->BottomRight (textloc.x+50.0f,textloc.y+20.0f);
@@ -2503,7 +2503,7 @@ if(!hsh_initialized){
if(VehGetShutdownState()!=1) if(VehGetShutdownState()!=1)
{ {
mfd_device.DrawTexture(120,140,0xFFFFFFFF,testoffset+1,256,testoffset+402+1,256+18); mfd_device.DrawTexture(120,140,0xFFFFFFFF,testoffset+1,256,testoffset+402+1,256+18);
//눈금위의 방위각 그리기 //Draw bearing above tick marks
int heading = m_PlayerFacing; int heading = m_PlayerFacing;
int ii=0; int ii=0;
for (int i=heading-20;i<=heading+20;i++,ii++){ for (int i=heading-20;i<=heading+20;i++,ii++){
@@ -2521,7 +2521,7 @@ if(!hsh_initialized){
} }
mfd_device.pD3DDevice->SetTexture(0,0); mfd_device.pD3DDevice->SetTexture(0,0);
//현재 방위각 그리기 //Draw current bearing
{ {
char text[8]; char text[8];
wsprintf(text,"%d",(int)m_PlayerFacing); wsprintf(text,"%d",(int)m_PlayerFacing);
@@ -2530,19 +2530,19 @@ if(!hsh_initialized){
} }
mfd_device.pD3DDevice->SetTexture(0,mfd_device.pDDSTexture); mfd_device.pD3DDevice->SetTexture(0,mfd_device.pDDSTexture);
//중심표시 역삼각형(매우작음) 그리기 //Draw center-indicator inverted triangle (very small)
mfd_device.DrawTexture(320-5,140,0xFFFFFFFF,59,30+256,70,39+256); mfd_device.DrawTexture(320-5,140,0xFFFFFFFF,59,30+256,70,39+256);
//목표 그리기. //Draw objective.
if (m_NavPointRange != -1){//목표 지점이 있을때. if (m_NavPointRange != -1){//when a target waypoint exists.
int hsh_textpos=0; int hsh_textpos=0;
//목표 표시 그리기. //Draw objective indicator.
if ((m_NavPointFacing > -20) && (m_NavPointFacing < 20)){ if ((m_NavPointFacing > -20) && (m_NavPointFacing < 20)){
//방위각 내에 있을때.. 버그를 그린다. //When inside bearing range.. draw indicator.
mfd_device.DrawTexture((int)(320-9-m_NavPointFacing*10),140+4,0xFFFFFFFF,87,28+256,106,47+256); mfd_device.DrawTexture((int)(320-9-m_NavPointFacing*10),140+4,0xFFFFFFFF,87,28+256,106,47+256);
hsh_textpos=(int)(320-m_NavPointFacing*10); hsh_textpos=(int)(320-m_NavPointFacing*10);
}else{ }else{
//방위각 밖에 있을때.. 화살표를 그린다. //When outside bearing range.. draw arrow.
if (m_NavPointFacing <= -10){ if (m_NavPointFacing <= -10){
mfd_device.DrawTexture(520+4,140,0xFFFFFFFF,3,54+256,39,81+256); mfd_device.DrawTexture(520+4,140,0xFFFFFFFF,3,54+256,39,81+256);
hsh_textpos=520; hsh_textpos=520;
@@ -2552,12 +2552,12 @@ if(!hsh_initialized){
} }
} }
//목표 이름과 거리(텍스트) 그리기. //Draw objective name and distance (text).
mfd_device.pFont[0].DrawText(hsh_textpos,140+26,0xFFFFFFFF,m_NavPointName,TEXTALIGN_CENTER); mfd_device.pFont[0].DrawText(hsh_textpos,140+26,0xFFFFFFFF,m_NavPointName,TEXTALIGN_CENTER);
mfd_device.pFont[0].DrawText(hsh_textpos,140+46,0xFFFFFFFF,m_NavPointRangeText,TEXTALIGN_CENTER); mfd_device.pFont[0].DrawText(hsh_textpos,140+46,0xFFFFFFFF,m_NavPointRangeText,TEXTALIGN_CENTER);
} }
} }
//반드시.. scroe정보 그리는 루틴을 추가할것.. //Must add routine to draw score info here..
{ {
char score[32]={0}; char score[32]={0};
char kills[32]={0}; char kills[32]={0};
@@ -51,9 +51,9 @@ namespace MechWarrior4
Stuff::Scalar m_TorsoTwist; Stuff::Scalar m_TorsoTwist;
int m_RadarMode; int m_RadarMode;
stlport::vector<ShotEntry> m_ShotList; stlport::vector<ShotEntry> m_ShotList;
//상훈 앞 //sanghoon begin
int hsh_fdraw; int hsh_fdraw;
//상훈 뒤 //sanghoon end
bool OnShotList (ObjectID who); bool OnShotList (ObjectID who);
void ClipLine (Scalar& xpt1,Scalar& ypt1,Scalar& xpt2,Scalar& ypt2,Scalar cx,Scalar cy,Scalar rad); void ClipLine (Scalar& xpt1,Scalar& ypt1,Scalar& xpt2,Scalar& ypt2,Scalar cx,Scalar cy,Scalar rad);
+6 -6
View File
@@ -121,7 +121,7 @@
void InitComFuncs (void); void InitComFuncs (void);
void KillComFuncs (void); void KillComFuncs (void);
// úè - start // hyun begin
typedef long LONG; typedef long LONG;
typedef struct DIJOYSTATE { typedef struct DIJOYSTATE {
LONG lX; LONG lX;
@@ -141,7 +141,7 @@ extern void (__stdcall *g_pfnRIO_ButtonEvent)(BYTE* by);
extern void __stdcall RIO_Joy(DIJOYSTATE& js); extern void __stdcall RIO_Joy(DIJOYSTATE& js);
extern void __stdcall RIO_ButEvent(BYTE* by); extern void __stdcall RIO_ButEvent(BYTE* by);
// úè - end // hyun end
namespace MW4AI namespace MW4AI
{ {
@@ -200,13 +200,13 @@ Stuff::Scalar MechWarrior4::DECRYPT (Stuff::Scalar value)
void void
MechWarrior4::InitializeClasses(Stuff::NotationFile *startup_ini) MechWarrior4::InitializeClasses(Stuff::NotationFile *startup_ini)
{ {
// úè - start // hyun begin
if (g_bUseOrgJoy) if (g_bUseOrgJoy)
g_pfnRIO_Joy = NULL; g_pfnRIO_Joy = NULL;
else else
g_pfnRIO_Joy = RIO_Joy; g_pfnRIO_Joy = RIO_Joy;
g_pfnRIO_ButtonEvent = RIO_ButEvent; g_pfnRIO_ButtonEvent = RIO_ButEvent;
// úè - end // hyun end
Verify(!g_LibraryHeap); Verify(!g_LibraryHeap);
g_LibraryHeap = gos_CreateMemoryHeap("MechWarrior4(All)"); g_LibraryHeap = gos_CreateMemoryHeap("MechWarrior4(All)");
@@ -753,8 +753,8 @@ void
gos_DestroyMemoryHeap(g_LibraryHeap); gos_DestroyMemoryHeap(g_LibraryHeap);
g_LibraryHeap = NULL; g_LibraryHeap = NULL;
// úè - start // hyun begin
g_pfnRIO_ButtonEvent = NULL; g_pfnRIO_ButtonEvent = NULL;
g_pfnRIO_Joy = NULL; g_pfnRIO_Joy = NULL;
// úè - end // hyun end
} }
+342 -11
View File
@@ -57,6 +57,19 @@
#include "mechspecs.cpp" #include "mechspecs.cpp"
// [16 pilots + 1 cameraship fix]
//
// A cameraship seat occupies a network (DirectPlay) slot but pilots no 'Mech, so slots must
// be reserved for cameraships on top of the pilot cap, and cameraships must NOT be counted
// against the 'Mech cap.
//
// The reserve has to be a CONSTANT rather than being derived from
// (CTCL_GetTeslaCountAll() - CTCL_GetTeslaCount()): the CTCL tesla table is only populated
// when CTCL_IsConsoleOrCOOP() is true (see ctcl.cpp), so on a pod - including the cameraship
// pod, which is the machine that actually creates the network session in CTCL_DoCreateGame()
// - both counters return 0 and the reserve collapsed to +0.
#define MW4_CAMERASHIP_RESERVE 4 // must be >= MAX_CAMERAS in ctcl.cpp
// MSL 5.03 Mechview // MSL 5.03 Mechview
void __stdcall CTCL_AfterBeginScene(); void __stdcall CTCL_AfterBeginScene();
void __stdcall CTCL_UpdateMechView(); void __stdcall CTCL_UpdateMechView();
@@ -132,6 +145,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 +175,54 @@ 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_nAutoNoReturn = 0;
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 +792,55 @@ 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_nAutoNoReturn", &g_nAutoNoReturn, 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 +1222,45 @@ 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_nAutoNoReturn");
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 +1981,13 @@ 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());
// [16 pilots + 1 cameraship fix] Add camera slots on top of the pilot limit so
// cameraships can still connect. Uses the constant reserve for the same reason as
// CTCL_DefaultHostSetup: the CTCL tesla counters are console-only and read 0 on a pod.
// Only applied under CTCL - a standalone (non-pod) host must keep its exact limit.
Environment.NetworkMaxPlayers = params->m_playerLimit; Environment.NetworkMaxPlayers = params->m_playerLimit;
if (!CTCL_IsNone())
Environment.NetworkMaxPlayers += MW4_CAMERASHIP_RESERVE;
gos_NetServerCommands(gos_Commend_UpdateMaxPlayers,0); gos_NetServerCommands(gos_Commend_UpdateMaxPlayers,0);
break; break;
@@ -8930,6 +9089,24 @@ int MW4Shell::LoadDefaultOptions()
return 1; return 1;
} }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// [16 pilots + 1 cameraship fix]
// Number of cameraship participants in the current roster. Only meaningful on the server
// pod, which is the only machine that holds the full g_aPlayerInfos roster (filled by
// CSOC_Client::OnBOTS) and the only machine that calls AddBot in CTCL mode.
// A cameraship entry is a non-bot player with no 'Mech (m_nMechIndex == 0).
static int CTCL_CountCameraShipsInGame()
{
int count = 0;
for (int i = 0; i < g_nPlayerInfos; i++)
{
const SPlayerInfo& PI = g_aPlayerInfos[i];
if (!PI.m_bBot && (PI.m_nMechIndex == 0))
count++;
}
return count;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// //
int _stdcall MW4Shell::AddBot(void *instance, int numParams, void* data[]) int _stdcall MW4Shell::AddBot(void *instance, int numParams, void* data[])
@@ -8946,6 +9123,16 @@ int _stdcall MW4Shell::AddBot(void *instance, int numParams, void* data[])
bot_count++; bot_count++;
} }
player_count = Network::GetInstance()->GetPlayerCount(); player_count = Network::GetInstance()->GetPlayerCount();
// [16 pilots + 1 cameraship fix] Cameraships hold a network slot but no 'Mech slot.
// Counting them here capped pilots+cameras+bots at m_maxPlayers (16), so a full 16-'Mech
// roster plus a cameraship silently lost its last bot; g_nBOTs then never matched the
// connected lancemates and CTCL_CheckServerReady() spun forever without ever launching.
if (CTCL_IsConsoleX())
{
player_count -= CTCL_CountCameraShipsInGame();
if (player_count < 0)
player_count = 0;
}
NetMissionParameters::MWNetMissionParameters *params = app->GetLocalNetParams(); NetMissionParameters::MWNetMissionParameters *params = app->GetLocalNetParams();
if (params->m_runDedicated) if (params->m_runDedicated)
{ {
@@ -12731,6 +12918,144 @@ 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_nAutoNoReturn = 0; 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("NoReturn", &g_nAutoNoReturn);
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;
} }
@@ -12980,10 +13305,10 @@ void CTCL_API CTCL_SetMissionParams()
//} //}
NetMissionParameters::MWNetMissionParameters* lparams = app->GetLocalNetParams(); NetMissionParameters::MWNetMissionParameters* lparams = app->GetLocalNetParams();
lparams->m_killLimit = 0; // no kill limit - 목표치 lparams->m_killLimit = 0; // no kill limit - target value
lparams->m_killLimitNumber = 0; lparams->m_killLimitNumber = 0;
lparams->m_respawnLimit = 0; // 생명제한을 둘 것인가? lparams->m_respawnLimit = 0; // apply a respawn limit?
lparams->m_respawnLimitNumber = 0; // 생명수 lparams->m_respawnLimitNumber = 0; // number of lives
//params->m_isNight = params.m_isNight; //params->m_isNight = params.m_isNight;
lparams->m_onlyStockMech = FALSE; lparams->m_onlyStockMech = FALSE;
lparams->m_playMissionReview = 0; // params.m_playMissionReview; lparams->m_playMissionReview = 0; // params.m_playMissionReview;
@@ -13250,7 +13575,7 @@ void CTCL_API CTCL_CheckServerReady()
int i, nOK, nCount = Network::GetInstance()->GetPlayerCount(); int i, nOK, nCount = Network::GetInstance()->GetPlayerCount();
BOOL bOK = FALSE; BOOL bOK = FALSE;
if (nCount == (g_nTeslas + 1)) { // 모든 클라이언트가 접속이 되어 있을 때... if (nCount == (g_nTeslas + 1)) { // when all clients are connected...
for(nOK = 0, i = 0; i < Maximum_Players; ++i) { for(nOK = 0, i = 0; i < Maximum_Players; ++i) {
if (i != Connection::Server->GetID()) { if (i != Connection::Server->GetID()) {
const MechWarrior4::ServedConnectionData& scd = app->servedConnectionData[i]; const MechWarrior4::ServedConnectionData& scd = app->servedConnectionData[i];
@@ -13307,17 +13632,19 @@ 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 = 16; params->m_maxPlayers = 16;
Environment.NetworkMaxPlayers = 16; // [16 pilots + 1 cameraship fix] Reserve network slots for cameraship seats on top of the
// pilot cap. This runs on the cameraship pod too (via CTCL_DoCreateGame -> nMode 0), which
// is the machine that creates the session with dwMaxPlayers = Environment.NetworkMaxPlayers.
// Do NOT derive the reserve from the CTCL tesla counters here: that table is console-only,
// so on the pod they both return 0, the reserve became +0, the session was created with
// 16 slots, and the 17th connection was refused - the mission then never finished loading.
Environment.NetworkMaxPlayers = params->m_maxPlayers + MW4_CAMERASHIP_RESERVE;
params->m_maxBots = 16; params->m_maxBots = 16;
} }
params->m_allow3rdPerson = 1; params->m_allow3rdPerson = 1;
@@ -14820,6 +15147,10 @@ void __stdcall CTCL_UpdateMechView()
mfd_device.BeginScene(); mfd_device.BeginScene();
sh_step = 4; sh_step = 4;
break; break;
case 4:
// Same 7-step cadence as mode 1.
sh_step = 6;
break;
} }
} }
else else
+14 -14
View File
@@ -230,13 +230,13 @@ extern int g_nTeamOrderMode;
extern bool g_bCOOP; // COin OPeration extern bool g_bCOOP; // COin OPeration
// jcem - end // jcem - end
// 鉉 - start // hyun begin
extern void __stdcall RIO_StartStop (BOOL bStart); extern void __stdcall RIO_StartStop (BOOL bStart);
void COOP_InputMode(bool bRestore); void COOP_InputMode(bool bRestore);
extern int g_bNoPlasma; extern int g_bNoPlasma;
extern void __stdcall PLASMA_Do(int nMode); extern void __stdcall PLASMA_Do(int nMode);
extern void GeneralReset(); extern void GeneralReset();
// 鉉 - end // hyun end
extern bool __stdcall gos_NetDoneStartGame(); extern bool __stdcall gos_NetDoneStartGame();
extern bool __stdcall PrepareDefaultServerAdvertisers(void); extern bool __stdcall PrepareDefaultServerAdvertisers(void);
@@ -1938,9 +1938,9 @@ public:
void EndPos (DWORD& x,DWORD& y); void EndPos (DWORD& x,DWORD& y);
bool Empty (void) bool Empty (void)
{ return (m_Text[0] == 0); } { return (m_Text[0] == 0); }
//상훈 앞 //sanghoon begin
const char *hsh_get_m_Text(){return &m_Text[0];} const char *hsh_get_m_Text(){return &m_Text[0];}
//상훈 뒤 //sanghoon end
}; };
TextBox::TextBox (const char* pcszFontName, int nFontSize/* = -11*/, bool oldmode/* = false*/) TextBox::TextBox (const char* pcszFontName, int nFontSize/* = -11*/, bool oldmode/* = false*/)
@@ -3571,9 +3571,9 @@ void
} }
Environment.DoGameLogic = &MWApplication::DoGameLogic; Environment.DoGameLogic = &MWApplication::DoGameLogic;
} }
// 鉉 - start // hyun begin
RIO_StartStop (TRUE); RIO_StartStop (TRUE);
// 鉉 - end // hyun end
g_MRF.Started(); // jcem g_MRF.Started(); // jcem
g_RSF.Started(); // jcem g_RSF.Started(); // jcem
@@ -3696,9 +3696,9 @@ void
g_RSF.Stopping(); // jcem g_RSF.Stopping(); // jcem
ClearTOC(); ClearTOC();
// 鉉 - start // hyun begin
RIO_StartStop (FALSE); RIO_StartStop (FALSE);
// 鉉 - end // hyun end
if (CTCL_IsConsoleX()) { if (CTCL_IsConsoleX()) {
CTCL_SetGameState(_EGS_Closing); CTCL_SetGameState(_EGS_Closing);
} }
@@ -3870,9 +3870,9 @@ sh_game_started = false;
g_RSF.Stopping(); // jcem g_RSF.Stopping(); // jcem
ClearTOC(); ClearTOC();
// 鉉 - start // hyun begin
RIO_StartStop (FALSE); RIO_StartStop (FALSE);
// 鉉 - end // hyun end
if (CTCL_IsConsoleX()) { if (CTCL_IsConsoleX()) {
CTCL_SetGameState(_EGS_Closing); CTCL_SetGameState(_EGS_Closing);
} }
@@ -18435,7 +18435,7 @@ int __stdcall CTCL_StartCOOP(void* instance, int args, void* data[])
// $$COOP: see void CSOC_Client::OnReadyStartGame() // $$COOP: see void CSOC_Client::OnReadyStartGame()
// C_ReadyStartGame // C_ReadyStartGame
g_nTeslas = 0; // 싱글 게임 g_nTeslas = 0; // single player game
g_nBOTs = 7; g_nBOTs = 7;
g_nPlayerInfos = 1 + g_nBOTs + g_nTeslas; g_nPlayerInfos = 1 + g_nBOTs + g_nTeslas;
g_bIsServer = TRUE; g_bIsServer = TRUE;
@@ -18523,13 +18523,13 @@ int __stdcall CTCL_StartCOOP(void* instance, int args, void* data[])
// MSL ADD MECH // MSL ADD MECH
PI.m_nMechIndex = -1; PI.m_nMechIndex = -1;
//* //*
// 각 메크에 대한 정보는 MechIndex를 참조함 // See MechIndex for each mech's info
PI.m_fileID = 0; PI.m_fileID = 0;
PI.m_recordID = 0; PI.m_recordID = 0;
strcpy(PI.m_szMech, s_paMechNames[11]); // Madcat strcpy(PI.m_szMech, s_paMechNames[11]); // Madcat
strcpy(PI.m_szMech, "$Yellow"); strcpy(PI.m_szMech, "$Yellow");
//*/ //*/
PI.m_nTeamOrSkin = 1; // 빨강 PI.m_nTeamOrSkin = 1; // red
PI.m_nDecal = 1; // nDecal; PI.m_nDecal = 1; // nDecal;
PI.m_dwAddr = 0; // dwAddr; PI.m_dwAddr = 0; // dwAddr;
g_nPrintOut = FALSE; g_nPrintOut = FALSE;
@@ -18576,7 +18576,7 @@ int __stdcall CTCL_StartCOOP(void* instance, int args, void* data[])
strcpy(PI.m_szName, s_pNames[aLBN[2][i - 1]]); strcpy(PI.m_szName, s_pNames[aLBN[2][i - 1]]);
PI.m_nMechIndex = -1; PI.m_nMechIndex = -1;
//* //*
//각 메크에 대한 정보는 MechIndex를 참조함 //See MechIndex for each mech's info
PI.m_fileID = 0; PI.m_fileID = 0;
PI.m_recordID = 0; PI.m_recordID = 0;
/*if (i == 1) /*if (i == 1)
+7 -7
View File
@@ -1,8 +1,8 @@
#include "MW4Headers.hpp" #include "MW4Headers.hpp"
//상훈 앞 //sanghoon begin
#include "MWVideoRenderer.hpp" #include "MWVideoRenderer.hpp"
//상훈 뒤 //sanghoon end
#include "MWGUIManager.hpp" #include "MWGUIManager.hpp"
#include "GUIWeaponManager.hpp" #include "GUIWeaponManager.hpp"
#include "GUIRadarManager.hpp" #include "GUIRadarManager.hpp"
@@ -1554,7 +1554,7 @@ void MWGUIManager::RenderComponents (void)
(*iter)->Draw (); (*iter)->Draw ();
} }
}else{ }else{
//상훈... 셧다운 중일때.. //sanghoon: while shutting down..
for (iter = m_Components.begin ();iter != m_Components.end ();iter++) for (iter = m_Components.begin ();iter != m_Components.end ();iter++)
{ {
//Main hudZoom,//hudReticle,hudObjective,hudTorsoBar,hudHelp,hudScore //Main hudZoom,//hudReticle,hudObjective,hudTorsoBar,hudHelp,hudScore
@@ -1597,11 +1597,11 @@ void MWGUIManager::RenderComponents (void)
} }
else else
{ {
//상훈-앞 //sanghoon begin
extern CamerashipParams g_CamerashipParams; extern CamerashipParams g_CamerashipParams;
if (CTCL_IsConsoleX() || g_CamerashipParams.m_bAllowChatDisplay) if (CTCL_IsConsoleX() || g_CamerashipParams.m_bAllowChatDisplay)
hudChat->Draw (true); hudChat->Draw (true);
//상훈-뒤 //sanghoon end
hudScore->Draw (true); hudScore->Draw (true);
hudCamera->Draw(true); hudCamera->Draw(true);
} }
@@ -1612,7 +1612,7 @@ void MWGUIManager::RenderComponents (void)
gos_PopRenderStates (); gos_PopRenderStates ();
//상훈 앞 //sanghoon begin
MWApplication* app = MWApplication::GetInstance(); MWApplication* app = MWApplication::GetInstance();
if (app->networkingFlag) if (app->networkingFlag)
{ {
@@ -1648,7 +1648,7 @@ void MWGUIManager::RenderComponents (void)
} }
} }
} }
//상훈 뒤 //sanghoon end
} }
void MWGUIManager::ShowHelpArrow (bool value) void MWGUIManager::ShowHelpArrow (bool value)
+1 -1
View File
@@ -590,7 +590,7 @@ namespace MechWarrior4
return (m_EndMissionTimer.Running()); return (m_EndMissionTimer.Running());
} }
//상훈 //sanghoon
Stuff::Scalar GetMissionDuration () Stuff::Scalar GetMissionDuration ()
{ {
if (!m_EndMissionTimer.Running ()) if (!m_EndMissionTimer.Running ())
+1 -1
View File
@@ -3954,7 +3954,7 @@ void
g_HUDPPCLevel = 10; g_HUDPPCLevel = 10;
} }
//상훈 //sanghoon
//extern bool sh_isdeathmode; //extern bool sh_isdeathmode;
//Are we ejecting? //Are we ejecting?
if (m_NeedEject) if (m_NeedEject)
+94 -94
View File
@@ -13,7 +13,7 @@
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL // // This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
//===========================================================================// //===========================================================================//
// 鉉 - start // hyun begin
#include "MW4.hpp" #include "MW4.hpp"
#include "Vehicle.hpp" #include "Vehicle.hpp"
#include "MechAnimationState.hpp" #include "MechAnimationState.hpp"
@@ -22,7 +22,7 @@
#include "SpringOf.hpp" #include "SpringOf.hpp"
#include "MechLabHeaders.h" #include "MechLabHeaders.h"
#include <Stuff\Spline.hpp> #include <Stuff\Spline.hpp>
// 鉉 - end // hyun end
#include "MW4Headers.hpp" #include "MW4Headers.hpp"
@@ -65,9 +65,9 @@
#include "EyePointManager.hpp" #include "EyePointManager.hpp"
#include "mw4shell.hpp" #include "mw4shell.hpp"
#include "NavPoint.hpp" #include "NavPoint.hpp"
//상훈 앞 //sanghoon begin
#include "MWVideoRenderer.hpp" #include "MWVideoRenderer.hpp"
//상훈 뒤 //sanghoon end
#include <Adept\CollisionGrid.hpp> #include <Adept\CollisionGrid.hpp>
#include <Adept\Controls.hpp> #include <Adept\Controls.hpp>
@@ -101,7 +101,7 @@ bool _stdcall WriteImageAfterGrab(BYTE* Image, const char* pcszFilePrefix);
#include <mbstring.h> #include <mbstring.h>
#define __mbsrchr(s,c) (char*)_mbsrchr((const unsigned char*)(s),(c)) #define __mbsrchr(s,c) (char*)_mbsrchr((const unsigned char*)(s),(c))
// 鉉 - start // hyun begin
#include <windows.h> #include <windows.h>
#include "ctcls.h" #include "ctcls.h"
@@ -208,7 +208,7 @@ float g_fNeedFlushLevel = 0.66;
float g_fTimeMsgSender = 1.5f; float g_fTimeMsgSender = 1.5f;
float g_fTimeScoringAtEnd = 10.0f; float g_fTimeScoringAtEnd = 10.0f;
Mech* FindNextMechToFollowByScore(Mech* pCur); // jcem Mech* FindNextMechToFollowByScore(Mech* pCur); // jcem
// 鉉 - end // hyun end
CamerashipParams g_CamerashipParams; CamerashipParams g_CamerashipParams;
@@ -2285,7 +2285,7 @@ void
if (MWGUIManager::GetInstance () && IsObserving(true)) if (MWGUIManager::GetInstance () && IsObserving(true))
{ {
Check_Object(MWGUIManager::GetInstance()); Check_Object(MWGUIManager::GetInstance());
//상훈 //sanghoon
if (!CTCL_IsConsoleX() && !g_CamerashipParams.m_bAllowChatDisplay) { if (!CTCL_IsConsoleX() && !g_CamerashipParams.m_bAllowChatDisplay) {
HUDChat *chat; HUDChat *chat;
chat = Cast_Object (HUDChat *,MWGUIManager::GetInstance ()->Component (MWGUIManager::HUD_CHAT)); chat = Cast_Object (HUDChat *,MWGUIManager::GetInstance ()->Component (MWGUIManager::HUD_CHAT));
@@ -3781,11 +3781,11 @@ void VehicleInterface::ApplyControls(Time till)
} }
else if (controlPacket.lookCommand == AnalogControlSave::LookBack) else if (controlPacket.lookCommand == AnalogControlSave::LookBack)
{ {
//상훈 //sanghoon
ShowHUDIfOn(true); ShowHUDIfOn(true);
//MWGUIManager::GetInstance()->HideHudComponent (HUD_TARGETARROW); //MWGUIManager::GetInstance()->HideHudComponent (HUD_TARGETARROW);
//ShowHUDIfOn(false); //ShowHUDIfOn(false);
//상훈 //sanghoon
// MSL 5.04 Rear Firing Weapons // MSL 5.04 Rear Firing Weapons
// ShowStatic(cameraView == InMechCameraView); // ShowStatic(cameraView == InMechCameraView);
ShowStatic(true); ShowStatic(true);
@@ -4968,7 +4968,7 @@ void
Scalar fT = gos_GetElapsedTime(); Scalar fT = gos_GetElapsedTime();
if ((fT - g_fLastScoringTimeCechk) >= CAMERASHIP_SCORING_CHECK) { if ((fT - g_fLastScoringTimeCechk) >= CAMERASHIP_SCORING_CHECK) {
g_fLastScoringTimeCechk = fT; g_fLastScoringTimeCechk = fT;
//상훈 //sanghoon
if (Application::GetInstance()->networkingFlag) if (Application::GetInstance()->networkingFlag)
{ {
bool bNearEnd = false; bool bNearEnd = false;
@@ -5378,7 +5378,7 @@ again:
if ((m_curView == STATE_DEATH_SEQUENCE_START) || (m_curView == STATE_DEATH_SEQUENCE_TRANS)) { if ((m_curView == STATE_DEATH_SEQUENCE_START) || (m_curView == STATE_DEATH_SEQUENCE_TRANS)) {
bool bStateEnded = false; bool bStateEnded = false;
if (m_pMechDying != pMech) { if (m_pMechDying != pMech) {
// 죽는 도중에 타겟이 바뀐 경우 // Case where target changes while dying
ClearFixedPoint(); ClearFixedPoint();
m_fTimeStateEnd = fMT + g_CamerashipParams.m_fTimeStandard; m_fTimeStateEnd = fMT + g_CamerashipParams.m_fTimeStandard;
m_pMechDying = m_pEnemy = NULL; m_pMechDying = m_pEnemy = NULL;
@@ -5419,7 +5419,7 @@ again:
} }
if ((m_pEnemy != m_pMechDying) && m_pEnemy->IsDestroyed()) { if ((m_pEnemy != m_pMechDying) && m_pEnemy->IsDestroyed()) {
if (m_curView == STATE_DEATH_SEQUENCE_START) { if (m_curView == STATE_DEATH_SEQUENCE_START) {
// 죽음을 보여주는 도중에 상대방이 죽은 경우... // Case where opponent dies while death animation is playing...
// move to trans... // move to trans...
bStateEnded = true; bStateEnded = true;
} }
@@ -7495,7 +7495,7 @@ void
// MSL 5.02 Zoom // MSL 5.02 Zoom
// m_reticuleCamera->SetPerspective(near_clip_zoom, far_clip_main + (100.0f * (horizontal_fov_main - horizontal_fov_zoom)), horizontal_fov_zoom, (height_to_width_zoom)); // m_reticuleCamera->SetPerspective(near_clip_zoom, far_clip_main + (100.0f * (horizontal_fov_main - horizontal_fov_zoom)), horizontal_fov_zoom, (height_to_width_zoom));
m_reticuleCamera->SetPerspective(near_clip_zoom, far_clip_main + (100.0f * (horizontal_fov_main - horizontal_fov_zoom)), horizontal_fov_zoom, (height_to_width_zoom*1.75)); m_reticuleCamera->SetPerspective(near_clip_zoom, far_clip_main + (100.0f * (horizontal_fov_main - horizontal_fov_zoom)), horizontal_fov_zoom, (height_to_width_zoom*1.75));
//상훈 //sanghoon
// float height=(1-g_fZoomMarginLR*2)*800 * height_to_width_zoom/600; // float height=(1-g_fZoomMarginLR*2)*800 * height_to_width_zoom/600;
// float tb_margin=(1-height)/2; // float tb_margin=(1-height)/2;
// m_reticuleCamera->SetViewport(1-g_fZoomMarginLR,1-tb_margin, g_fZoomMarginLR, tb_margin); // m_reticuleCamera->SetViewport(1-g_fZoomMarginLR,1-tb_margin, g_fZoomMarginLR, tb_margin);
@@ -8121,7 +8121,7 @@ void VehicleInterface::ChainFireGroup (Stuff::Time till,ChainIteratorOf<Weapon *
} }
// //
// 鉉 - start // hyun begin
groupWeaponIterator->ReadAndNext(); groupWeaponIterator->ReadAndNext();
@@ -8135,7 +8135,7 @@ void VehicleInterface::ChainFireGroup (Stuff::Time till,ChainIteratorOf<Weapon *
BOOL bWeaponGroup3 = (group3FireRequest > 0) && GetWeaponGroupID (*weapon, 3); BOOL bWeaponGroup3 = (group3FireRequest > 0) && GetWeaponGroupID (*weapon, 3);
// //
// 鉉 - end // hyun end
// //
num_weapons ++; num_weapons ++;
@@ -8369,7 +8369,7 @@ void
} }
} }
*/ */
// fireRequest > 0 (Enter Key : None Used) : // fireRequest > 0 (Enter Key : None Used) : hyun
if(fireRequest > 0) if(fireRequest > 0)
{ {
switch(weaponMode) switch(weaponMode)
@@ -8521,12 +8521,12 @@ void VehicleInterface::OverrideAutoCenterToTorsoMessageHandler(Adept::ReceiverDa
Verify(message->messageID == OverrideAutoCenterToTorsoMessageID); Verify(message->messageID == OverrideAutoCenterToTorsoMessageID);
if (GetShutdownState()) { if (GetShutdownState()) {
g_pRIOMain->SetLampState (28, LAMP_OFF); // g_pRIOMain->SetLampState (28, LAMP_OFF); // hyun
return; return;
} }
if(message->dataContents > 0) if(message->dataContents > 0)
{ {
g_pRIOMain->SetLampState (28, LAMP_BRIGHT); // g_pRIOMain->SetLampState (28, LAMP_BRIGHT); // hyun
if (perminateTorsoMode == CenterLegsToTorso) if (perminateTorsoMode == CenterLegsToTorso)
{ {
@@ -8539,7 +8539,7 @@ void VehicleInterface::OverrideAutoCenterToTorsoMessageHandler(Adept::ReceiverDa
} }
else else
{ {
g_pRIOMain->SetLampState (28, LAMP_DEFAULT); // g_pRIOMain->SetLampState (28, LAMP_DEFAULT); // hyun
} }
} }
@@ -8658,11 +8658,11 @@ void
} }
} }
g_pRIOMain->SetLampState (17, LAMP_BRIGHT);// g_pRIOMain->SetLampState (17, LAMP_BRIGHT);// hyun
} }
else else
{ {
g_pRIOMain->SetLampState (17, LAMP_DEFAULT);// g_pRIOMain->SetLampState (17, LAMP_DEFAULT);// hyun
} }
} }
@@ -8749,17 +8749,17 @@ void
Verify(message->messageID == CrouchCommandMessageID); Verify(message->messageID == CrouchCommandMessageID);
if (GetShutdownState()) { if (GetShutdownState()) {
g_pRIOMain->SetLampState (20, LAMP_OFF);// g_pRIOMain->SetLampState (20, LAMP_OFF);// hyun
return; return;
} }
if(message->dataContents > 0) if(message->dataContents > 0)
{ {
g_pRIOMain->SetLampState (20, LAMP_BRIGHT);// g_pRIOMain->SetLampState (20, LAMP_BRIGHT);// hyun
// if (executionState->GetState () == ExecutionStateEngine::AutoPilotState) // if (executionState->GetState () == ExecutionStateEngine::AutoPilotState)
executionState->RequestState(ExecutionStateEngine::AlwaysExecuteState); executionState->RequestState(ExecutionStateEngine::AlwaysExecuteState);
QueCommand(VehicleCommand::CrouchCommand); QueCommand(VehicleCommand::CrouchCommand);
} else { } else {
g_pRIOMain->SetLampState (20, LAMP_DEFAULT);// g_pRIOMain->SetLampState (20, LAMP_DEFAULT);// hyun
} }
} }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -8786,10 +8786,10 @@ void
if (GetShutdownState()) { if (GetShutdownState()) {
if (g_bJumpZoom) if (g_bJumpZoom)
g_pRIOMain->SetLampState (16, LAMP_OFF);// g_pRIOMain->SetLampState (16, LAMP_OFF);// hyun
g_pRIOMain->SetLampState (50, LAMP_OFF); g_pRIOMain->SetLampState (50, LAMP_OFF);
g_pRIOMain->SetLampState (33, LAMP_OFF);// g_pRIOMain->SetLampState (33, LAMP_OFF);// hyun
g_pRIOMain->SetLampState (34, LAMP_OFF);// g_pRIOMain->SetLampState (34, LAMP_OFF);// hyun
return; return;
} }
@@ -8797,7 +8797,7 @@ void
{ {
if (GetJumpJetState() > 0) { if (GetJumpJetState() > 0) {
if (g_bJumpZoom) if (g_bJumpZoom)
g_pRIOMain->SetLampState (16, LAMP_BRIGHT);// g_pRIOMain->SetLampState (16, LAMP_BRIGHT);// hyun
g_pRIOMain->SetLampState (33, LAMP_BRIGHT); g_pRIOMain->SetLampState (33, LAMP_BRIGHT);
g_pRIOMain->SetLampState (34, LAMP_BRIGHT); g_pRIOMain->SetLampState (34, LAMP_BRIGHT);
} }
@@ -8811,10 +8811,10 @@ void
if (!GetShutdownState()) if (!GetShutdownState())
if (GetJumpJetState() > 0) { if (GetJumpJetState() > 0) {
if (g_bJumpZoom) if (g_bJumpZoom)
g_pRIOMain->SetLampState (16, LAMP_DEFAULT);// g_pRIOMain->SetLampState (16, LAMP_DEFAULT);// hyun
g_pRIOMain->SetLampState (50, LAMP_DEFAULT); g_pRIOMain->SetLampState (50, LAMP_DEFAULT);
g_pRIOMain->SetLampState (33, LAMP_DEFAULT);// g_pRIOMain->SetLampState (33, LAMP_DEFAULT);// hyun
g_pRIOMain->SetLampState (34, LAMP_DEFAULT);// g_pRIOMain->SetLampState (34, LAMP_DEFAULT);// hyun
} }
} }
@@ -9284,12 +9284,12 @@ void
} }
if (!GetShutdownState()) if (!GetShutdownState())
g_pRIOMain->SetLampState (7, LAMP_BRIGHT);// g_pRIOMain->SetLampState (7, LAMP_BRIGHT);// hyun
} }
else else
{ {
if (!GetShutdownState()) if (!GetShutdownState())
g_pRIOMain->SetLampState (7, LAMP_DEFAULT);// g_pRIOMain->SetLampState (7, LAMP_DEFAULT);// hyun
} }
*/ */
} }
@@ -9341,7 +9341,7 @@ void
if(message->dataContents > 0) if(message->dataContents > 0)
{ {
//SetWeaponMode(GroupFireMode); //hyun SetWeaponMode(GroupFireMode);
// selectedWeaponGroup = 1; // selectedWeaponGroup = 1;
group1FireRequest ++; group1FireRequest ++;
// fireRequest ++; // fireRequest ++;
@@ -9379,7 +9379,7 @@ void
if(message->dataContents > 0) if(message->dataContents > 0)
{ {
//SetWeaponMode(GroupFireMode); //hyun SetWeaponMode(GroupFireMode);
// selectedWeaponGroup = 2; // selectedWeaponGroup = 2;
group2FireRequest ++; group2FireRequest ++;
// fireRequest ++; // fireRequest ++;
@@ -9415,7 +9415,7 @@ void
if(message->dataContents > 0) if(message->dataContents > 0)
{ {
//SetWeaponMode(GroupFireMode); //hyun SetWeaponMode(GroupFireMode);
// selectedWeaponGroup = 3; // selectedWeaponGroup = 3;
// fireRequest ++; // fireRequest ++;
group3FireRequest ++; group3FireRequest ++;
@@ -9468,7 +9468,7 @@ void
if(message->dataContents > 0) if(message->dataContents > 0)
{ {
//SetWeaponMode(GroupFireMode); //hyun SetWeaponMode(GroupFireMode);
// selectedWeaponGroup = 4; // selectedWeaponGroup = 4;
// fireRequest ++; // fireRequest ++;
// group4FireRequest ++; // group4FireRequest ++;
@@ -9508,7 +9508,7 @@ void
if(message->dataContents > 0) if(message->dataContents > 0)
{ {
//SetWeaponMode(GroupFireMode); //hyun SetWeaponMode(GroupFireMode);
// selectedWeaponGroup = 5; // selectedWeaponGroup = 5;
// fireRequest ++; // fireRequest ++;
// group5FireRequest ++; // group5FireRequest ++;
@@ -9554,7 +9554,7 @@ void
if(message->dataContents > 0) if(message->dataContents > 0)
{ {
//SetWeaponMode(GroupFireMode); //hyun SetWeaponMode(GroupFireMode);
//group6FireRequest ++; //group6FireRequest ++;
} }
else else
@@ -10344,19 +10344,19 @@ void
Verify(message->messageID == ToggleSearchLightMessageID); Verify(message->messageID == ToggleSearchLightMessageID);
if (GetShutdownState()) { if (GetShutdownState()) {
g_pRIOMain->SetLampState (27, LAMP_OFF);// g_pRIOMain->SetLampState (27, LAMP_OFF);// hyun
return; return;
} }
if(message->dataContents > 0) if(message->dataContents > 0)
{ {
if (g_SearchLight == TRUE) if (g_SearchLight == TRUE)
g_pRIOMain->SetLampState (27, LAMP_BRIGHT);// g_pRIOMain->SetLampState (27, LAMP_BRIGHT);// hyun
QueCommand(VehicleCommand::ToggleSearchLightCommand); QueCommand(VehicleCommand::ToggleSearchLightCommand);
} }
else else
{ {
if (g_SearchLight == TRUE) if (g_SearchLight == TRUE)
g_pRIOMain->SetLampState (27, LAMP_DEFAULT);// g_pRIOMain->SetLampState (27, LAMP_DEFAULT);// hyun
} }
} }
@@ -10546,7 +10546,7 @@ void
{ {
//if (!GetShutdownState()) //if (!GetShutdownState())
//if (g_bCool == TRUE) { //if (g_bCool == TRUE) {
// g_pRIOMain->SetLampState (19, LAMP_BRIGHT);// // g_pRIOMain->SetLampState (19, LAMP_BRIGHT);// hyun
//} //}
isCooling ++; isCooling ++;
@@ -10560,7 +10560,7 @@ void
{ {
//if (!GetShutdownState()) //if (!GetShutdownState())
//if (g_bCool == TRUE) { //if (g_bCool == TRUE) {
// g_pRIOMain->SetLampState (19, LAMP_DEFAULT);// // g_pRIOMain->SetLampState (19, LAMP_DEFAULT);// hyun
//} //}
isCooling --; isCooling --;
@@ -10734,7 +10734,7 @@ void
if (GetShutdownState()) if (GetShutdownState())
{ {
g_pRIOMain->SetLampState (26, LAMP_OFF);// g_pRIOMain->SetLampState (26, LAMP_OFF);// hyun
g_pRIOMain->SetLampState (48, LAMP_OFF); // Light Amp Lamp MFD g_pRIOMain->SetLampState (48, LAMP_OFF); // Light Amp Lamp MFD
return; return;
} }
@@ -10759,7 +10759,7 @@ void
MWGUIManager::GetInstance()->ShowLightAmplification(); MWGUIManager::GetInstance()->ShowLightAmplification();
Mission::GetInstance()->SetLightAmpMissionLights(); Mission::GetInstance()->SetLightAmpMissionLights();
ShowZoomIfOn (false); ShowZoomIfOn (false);
g_pRIOMain->SetLampState (26, LAMP_BRIGHT);// g_pRIOMain->SetLampState (26, LAMP_BRIGHT);// hyun
if (!g_bJumpZoom) if (!g_bJumpZoom)
{ {
if (g_pRIOMain->GetLampState (16) == LAMP_BRIGHT) if (g_pRIOMain->GetLampState (16) == LAMP_BRIGHT)
@@ -10773,12 +10773,12 @@ void
{ {
if(vehicle->DoesHaveLightAmp()) if(vehicle->DoesHaveLightAmp())
{ {
g_pRIOMain->SetLampState (26, LAMP_DEFAULT);// g_pRIOMain->SetLampState (26, LAMP_DEFAULT);// hyun
g_pRIOMain->SetLampState (48, LAMP_DEFAULT); // Light Amp Lamp MFD g_pRIOMain->SetLampState (48, LAMP_DEFAULT); // Light Amp Lamp MFD
} }
else else
{ {
g_pRIOMain->SetLampState (26, LAMP_OFF);// g_pRIOMain->SetLampState (26, LAMP_OFF);// hyun
g_pRIOMain->SetLampState (48, LAMP_OFF); // Light Amp Lamp MFD g_pRIOMain->SetLampState (48, LAMP_OFF); // Light Amp Lamp MFD
} }
} }
@@ -10864,12 +10864,12 @@ void
Verify(message->messageID == NextNavPointMessageID); Verify(message->messageID == NextNavPointMessageID);
if (GetShutdownState()) { if (GetShutdownState()) {
g_pRIOMain->SetLampState (38, LAMP_OFF);// g_pRIOMain->SetLampState (38, LAMP_OFF);// hyun
return; return;
} }
if(message->dataContents > 0) if(message->dataContents > 0)
{ {
g_pRIOMain->SetLampState (38, LAMP_BRIGHT);// g_pRIOMain->SetLampState (38, LAMP_BRIGHT);// hyun
m_selectedNavPoint.Remove(); m_selectedNavPoint.Remove();
NavPoint *nav_point; NavPoint *nav_point;
if((nav_point = NavPoint::GetNextNavPoint()) != NULL) if((nav_point = NavPoint::GetNextNavPoint()) != NULL)
@@ -10890,7 +10890,7 @@ void
} }
else else
{ {
g_pRIOMain->SetLampState (38, LAMP_DEFAULT);// g_pRIOMain->SetLampState (38, LAMP_DEFAULT);// hyun
} }
} }
@@ -10915,12 +10915,12 @@ void
Verify(message->messageID == PreviousNavPointMessageID); Verify(message->messageID == PreviousNavPointMessageID);
if (GetShutdownState()) { if (GetShutdownState()) {
g_pRIOMain->SetLampState (37, LAMP_OFF);// g_pRIOMain->SetLampState (37, LAMP_OFF);// hyun
return; return;
} }
if(message->dataContents > 0) if(message->dataContents > 0)
{ {
g_pRIOMain->SetLampState (37, LAMP_BRIGHT);// g_pRIOMain->SetLampState (37, LAMP_BRIGHT);// hyun
m_selectedNavPoint.Remove(); m_selectedNavPoint.Remove();
NavPoint *nav_point; NavPoint *nav_point;
if((nav_point = NavPoint::GetPreviousNavPoint()) != NULL) if((nav_point = NavPoint::GetPreviousNavPoint()) != NULL)
@@ -10936,7 +10936,7 @@ void
} }
else else
{ {
g_pRIOMain->SetLampState (37, LAMP_DEFAULT);// g_pRIOMain->SetLampState (37, LAMP_DEFAULT);// hyun
} }
} }
@@ -10961,12 +10961,12 @@ void
Verify(message->messageID == NextEnemyMessageID); Verify(message->messageID == NextEnemyMessageID);
if (GetShutdownState()) { if (GetShutdownState()) {
g_pRIOMain->SetLampState (10, LAMP_OFF);// g_pRIOMain->SetLampState (10, LAMP_OFF);// hyun
return; return;
} }
if(message->dataContents > 0) if(message->dataContents > 0)
{ {
g_pRIOMain->SetLampState (10, LAMP_BRIGHT);// g_pRIOMain->SetLampState (10, LAMP_BRIGHT);// hyun
Entity *next_enemy = NULL; Entity *next_enemy = NULL;
Sensor *sensor = vehicle->GetSensor(); Sensor *sensor = vehicle->GetSensor();
if(sensor) if(sensor)
@@ -10978,7 +10978,7 @@ void
} }
else else
{ {
g_pRIOMain->SetLampState (10, LAMP_DEFAULT);// g_pRIOMain->SetLampState (10, LAMP_DEFAULT);// hyun
} }
} }
@@ -11003,12 +11003,12 @@ void
Verify(message->messageID == PreviousEnemyMessageID); Verify(message->messageID == PreviousEnemyMessageID);
if (GetShutdownState()) { if (GetShutdownState()) {
g_pRIOMain->SetLampState (9, LAMP_OFF);// g_pRIOMain->SetLampState (9, LAMP_OFF);// hyun
return; return;
} }
if(message->dataContents > 0) if(message->dataContents > 0)
{ {
g_pRIOMain->SetLampState (9, LAMP_BRIGHT);// g_pRIOMain->SetLampState (9, LAMP_BRIGHT);// hyun
Entity *next_enemy = NULL; Entity *next_enemy = NULL;
Sensor *sensor = vehicle->GetSensor(); Sensor *sensor = vehicle->GetSensor();
if(sensor) if(sensor)
@@ -11020,7 +11020,7 @@ void
} }
else else
{ {
g_pRIOMain->SetLampState (9, LAMP_DEFAULT);// g_pRIOMain->SetLampState (9, LAMP_DEFAULT);// hyun
} }
} }
@@ -11045,12 +11045,12 @@ void
Verify(message->messageID == NearestEnemyMessageID); Verify(message->messageID == NearestEnemyMessageID);
if (GetShutdownState()) { if (GetShutdownState()) {
g_pRIOMain->SetLampState (11, LAMP_OFF);// g_pRIOMain->SetLampState (11, LAMP_OFF);// hyun
return; return;
} }
if(message->dataContents > 0) if(message->dataContents > 0)
{ {
g_pRIOMain->SetLampState (11, LAMP_BRIGHT);// g_pRIOMain->SetLampState (11, LAMP_BRIGHT);// hyun
m_interfaceTarget.Remove(); m_interfaceTarget.Remove();
m_targetCamera->SetScene(NULL); m_targetCamera->SetScene(NULL);
Entity *entity = NULL; Entity *entity = NULL;
@@ -11065,7 +11065,7 @@ void
} }
else else
{ {
g_pRIOMain->SetLampState (11, LAMP_DEFAULT);// g_pRIOMain->SetLampState (11, LAMP_DEFAULT);// hyun
} }
} }
@@ -11232,12 +11232,12 @@ void
if (GetShutdownState()) if (GetShutdownState())
{ {
g_pRIOMain->SetLampState (8, LAMP_OFF);// g_pRIOMain->SetLampState (8, LAMP_OFF);// hyun
return; return;
} }
if(message->dataContents > 0) if(message->dataContents > 0)
{ {
g_pRIOMain->SetLampState (8, LAMP_BRIGHT);// g_pRIOMain->SetLampState (8, LAMP_BRIGHT);// hyun
Entity *target_entity; Entity *target_entity;
target_entity = targetQueryEntity.GetCurrent(); target_entity = targetQueryEntity.GetCurrent();
@@ -11260,7 +11260,7 @@ void
} }
else else
{ {
g_pRIOMain->SetLampState (8, LAMP_DEFAULT);// g_pRIOMain->SetLampState (8, LAMP_DEFAULT);// hyun
} }
} }
@@ -11285,12 +11285,12 @@ void
Verify(message->messageID == NextFriendlyMessageID); Verify(message->messageID == NextFriendlyMessageID);
if (GetShutdownState()) { if (GetShutdownState()) {
g_pRIOMain->SetLampState (14, LAMP_OFF);// g_pRIOMain->SetLampState (14, LAMP_OFF);// hyun
return; return;
} }
if(message->dataContents > 0) if(message->dataContents > 0)
{ {
g_pRIOMain->SetLampState (14, LAMP_BRIGHT);// g_pRIOMain->SetLampState (14, LAMP_BRIGHT);// hyun
Entity *next_friendly = NULL; Entity *next_friendly = NULL;
Sensor *sensor = vehicle->GetSensor(); Sensor *sensor = vehicle->GetSensor();
if(sensor) if(sensor)
@@ -11303,7 +11303,7 @@ void
} }
else else
{ {
g_pRIOMain->SetLampState (14, LAMP_DEFAULT);// g_pRIOMain->SetLampState (14, LAMP_DEFAULT);// hyun
} }
} }
@@ -11328,12 +11328,12 @@ void
Verify(message->messageID == PreviousFriendlyMessageID); Verify(message->messageID == PreviousFriendlyMessageID);
if (GetShutdownState()) { if (GetShutdownState()) {
g_pRIOMain->SetLampState (13, LAMP_OFF);// g_pRIOMain->SetLampState (13, LAMP_OFF);// hyun
return; return;
} }
if(message->dataContents > 0) if(message->dataContents > 0)
{ {
g_pRIOMain->SetLampState (13, LAMP_BRIGHT);// g_pRIOMain->SetLampState (13, LAMP_BRIGHT);// hyun
Entity *next_friendly = NULL; Entity *next_friendly = NULL;
Sensor *sensor = vehicle->GetSensor(); Sensor *sensor = vehicle->GetSensor();
if(sensor) if(sensor)
@@ -11346,7 +11346,7 @@ void
} }
else else
{ {
g_pRIOMain->SetLampState (13, LAMP_DEFAULT);// g_pRIOMain->SetLampState (13, LAMP_DEFAULT);// hyun
} }
} }
@@ -11371,12 +11371,12 @@ void
Verify(message->messageID == NearestFriendlyMessageID); Verify(message->messageID == NearestFriendlyMessageID);
if (GetShutdownState()) { if (GetShutdownState()) {
g_pRIOMain->SetLampState (15, LAMP_OFF);// g_pRIOMain->SetLampState (15, LAMP_OFF);// hyun
return; return;
} }
if(message->dataContents > 0) if(message->dataContents > 0)
{ {
g_pRIOMain->SetLampState (15, LAMP_BRIGHT);// g_pRIOMain->SetLampState (15, LAMP_BRIGHT);// hyun
Entity *entity = NULL; Entity *entity = NULL;
Sensor *sensor = vehicle->GetSensor(); Sensor *sensor = vehicle->GetSensor();
if(sensor) if(sensor)
@@ -11388,7 +11388,7 @@ void
} }
else else
{ {
g_pRIOMain->SetLampState (15, LAMP_DEFAULT);// g_pRIOMain->SetLampState (15, LAMP_DEFAULT);// hyun
} }
} }
@@ -11478,7 +11478,7 @@ void VehicleInterface::OverrideShutdownMessageHandler(Adept::ReceiverDataMessage
if(message->dataContents > 0) if(message->dataContents > 0)
{ {
//if (!GetShutdownState()) //if (!GetShutdownState())
// g_pRIOMain->SetLampState (18, LAMP_BRIGHT);// // g_pRIOMain->SetLampState (18, LAMP_BRIGHT);// hyun
HeatManager *heat; HeatManager *heat;
if (vehicle->IsDerivedFrom (Mech::DefaultData)) if (vehicle->IsDerivedFrom (Mech::DefaultData))
{ {
@@ -11492,7 +11492,7 @@ void VehicleInterface::OverrideShutdownMessageHandler(Adept::ReceiverDataMessage
} }
else { else {
//if (!GetShutdownState()) //if (!GetShutdownState())
// g_pRIOMain->SetLampState (18, LAMP_DEFAULT);// // g_pRIOMain->SetLampState (18, LAMP_DEFAULT);// hyun
} }
} }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -11541,7 +11541,7 @@ void VehicleInterface::RightMFDMessageHandler (Adept::ReceiverDataMessageOf<int>
if(message->dataContents > 0) if(message->dataContents > 0)
{ {
g_pRIOMain->SetLampState (52, LAMP_BRIGHT);// g_pRIOMain->SetLampState (52, LAMP_BRIGHT);// hyun
if(MWGUIManager::GetInstance()) if(MWGUIManager::GetInstance())
{ {
Check_Object(MWGUIManager::GetInstance()); Check_Object(MWGUIManager::GetInstance());
@@ -11552,7 +11552,7 @@ void VehicleInterface::RightMFDMessageHandler (Adept::ReceiverDataMessageOf<int>
} }
else else
{ {
g_pRIOMain->SetLampState (52, LAMP_DEFAULT);// g_pRIOMain->SetLampState (52, LAMP_DEFAULT);// hyun
} }
} }
@@ -11584,12 +11584,12 @@ void VehicleInterface::LeftMFDMessageHandler (Adept::ReceiverDataMessageOf<int>
Verify(message->messageID == LeftMFDMessageID); Verify(message->messageID == LeftMFDMessageID);
if (GetShutdownState()) { if (GetShutdownState()) {
g_pRIOMain->SetLampState (12, LAMP_OFF);// g_pRIOMain->SetLampState (12, LAMP_OFF);// hyun
return; return;
} }
if(message->dataContents > 0) if(message->dataContents > 0)
{ {
g_pRIOMain->SetLampState (12, LAMP_BRIGHT);// g_pRIOMain->SetLampState (12, LAMP_BRIGHT);// hyun
if(MWGUIManager::GetInstance()) if(MWGUIManager::GetInstance())
{ {
Check_Object(MWGUIManager::GetInstance()); Check_Object(MWGUIManager::GetInstance());
@@ -11610,7 +11610,7 @@ void VehicleInterface::LeftMFDMessageHandler (Adept::ReceiverDataMessageOf<int>
} }
else else
{ {
g_pRIOMain->SetLampState (12, LAMP_DEFAULT);// g_pRIOMain->SetLampState (12, LAMP_DEFAULT);// hyun
} }
} }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -11632,12 +11632,12 @@ void VehicleInterface::ToggleRadarPassiveMessageHandler (Adept::ReceiverDataMess
Verify(message->messageID == ToggleRadarPassiveMessageID); Verify(message->messageID == ToggleRadarPassiveMessageID);
if (GetShutdownState()) { if (GetShutdownState()) {
g_pRIOMain->SetLampState (25, LAMP_OFF);// g_pRIOMain->SetLampState (25, LAMP_OFF);// hyun
return; return;
} }
if(message->dataContents > 0) if(message->dataContents > 0)
{ {
g_pRIOMain->SetLampState (25, LAMP_BRIGHT);// g_pRIOMain->SetLampState (25, LAMP_BRIGHT);// hyun
if(!vehicle->vehicleShutDown) if(!vehicle->vehicleShutDown)
{ {
if(MWGUIManager::GetInstance()) if(MWGUIManager::GetInstance())
@@ -11676,7 +11676,7 @@ void VehicleInterface::ToggleRadarPassiveMessageHandler (Adept::ReceiverDataMess
} }
else else
{ {
g_pRIOMain->SetLampState (25, LAMP_DEFAULT);// g_pRIOMain->SetLampState (25, LAMP_DEFAULT);// hyun
} }
} }
@@ -11702,12 +11702,12 @@ void
Verify(message->messageID == ToggleRadarRangeMessageID); Verify(message->messageID == ToggleRadarRangeMessageID);
if (GetShutdownState()) { if (GetShutdownState()) {
g_pRIOMain->SetLampState (24, LAMP_OFF);// g_pRIOMain->SetLampState (24, LAMP_OFF);// hyun
return; return;
} }
if(message->dataContents > 0) if(message->dataContents > 0)
{ {
g_pRIOMain->SetLampState (24, LAMP_BRIGHT);// g_pRIOMain->SetLampState (24, LAMP_BRIGHT);// hyun
if(!vehicle->vehicleShutDown) if(!vehicle->vehicleShutDown)
{ {
if(MWGUIManager::GetInstance()) if(MWGUIManager::GetInstance())
@@ -11739,7 +11739,7 @@ void
} }
else else
{ {
g_pRIOMain->SetLampState (24, LAMP_DEFAULT);// g_pRIOMain->SetLampState (24, LAMP_DEFAULT);// hyun
} }
} }
@@ -13533,13 +13533,13 @@ void VehicleInterface::ShowObjectivesMessageHandler(Adept::ReceiverDataMessageOf
{ {
if(message->dataContents > 0) if(message->dataContents > 0)
{ {
g_pRIOMain->SetLampState (36, LAMP_BRIGHT);// g_pRIOMain->SetLampState (36, LAMP_BRIGHT);// hyun
g_bObjMode = !g_bObjMode; g_bObjMode = !g_bObjMode;
// ObjectiveRenderer::Instance->ToggleObjective (); // ObjectiveRenderer::Instance->ToggleObjective ();
} }
else else
{ {
g_pRIOMain->SetLampState (36, LAMP_DEFAULT);// g_pRIOMain->SetLampState (36, LAMP_DEFAULT);// hyun
} }
} }
else else
@@ -13568,12 +13568,12 @@ void VehicleInterface::MuteMessageHandler(Adept::ReceiverDataMessageOf<int> *mes
if(message->dataContents > 0) if(message->dataContents > 0)
{ {
g_pRIOMain->SetLampState (55, LAMP_BRIGHT);// g_pRIOMain->SetLampState (55, LAMP_BRIGHT);// hyun
g_bMuteMode = !g_bMuteMode; g_bMuteMode = !g_bMuteMode;
} }
else else
{ {
g_pRIOMain->SetLampState (55, LAMP_DEFAULT);// g_pRIOMain->SetLampState (55, LAMP_DEFAULT);// hyun
} }
} }
@@ -13689,7 +13689,7 @@ void
if (GetShutdownState()) { if (GetShutdownState()) {
if (!g_bJumpZoom) if (!g_bJumpZoom)
g_pRIOMain->SetLampState (16, LAMP_OFF);// g_pRIOMain->SetLampState (16, LAMP_OFF);// hyun
g_pRIOMain->SetLampState (51, LAMP_OFF); g_pRIOMain->SetLampState (51, LAMP_OFF);
return; return;
} }
@@ -14489,7 +14489,7 @@ void VehicleInterface::ShowZoom (void)
Check_Object(m_reticuleCamera); Check_Object(m_reticuleCamera);
m_reticuleCamera->GetPerspective(near_clip, far_clip, horizontal_fov, height_to_width); m_reticuleCamera->GetPerspective(near_clip, far_clip, horizontal_fov, height_to_width);
//m_reticuleCamera->SetPerspective(near_clip, far_clip, s_zoomFOV[0], height_to_width); //m_reticuleCamera->SetPerspective(near_clip, far_clip, s_zoomFOV[0], height_to_width);
//상훈 //sanghoon
// jcem - begin // jcem - begin
float fZoom; float fZoom;
gosASSERT(g_fZoomFOVA >= g_fZoomFOVB); gosASSERT(g_fZoomFOVA >= g_fZoomFOVB);
+1 -1
View File
@@ -42,7 +42,7 @@ public:
const char* m_pcsz; const char* m_pcsz;
int m_nLauncherConnection; // 0: no connection, +1: connection, -1: connecting int m_nLauncherConnection; // 0: no connection, +1: connection, -1: connecting
int m_nConnection2; // m_bCameraShip값에 따라 게임 혹은 카메라 쉽과의 접속을 의미, 0: no connection, +1: connection, -1: connecting int m_nConnection2; // Connection to game or camera ship per m_bCameraShip, 0: no connection, +1: connected, -1: connecting
int m_nApplType; int m_nApplType;
int m_nApplState; int m_nApplState;
int m_nGameState; int m_nGameState;
+37 -37
View File
@@ -1,5 +1,5 @@
#include "MW4Headers.hpp" #include "MW4Headers.hpp"
//상훈 앞 //sanghoon begin
#include "MWMission.hpp" #include "MWMission.hpp"
#include "VehicleInterface.hpp" #include "VehicleInterface.hpp"
#include "Vehicle.hpp" #include "Vehicle.hpp"
@@ -21,7 +21,7 @@
#include "mech.hpp" #include "mech.hpp"
#include "mechlabheaders.h" #include "mechlabheaders.h"
#include "bucket.hpp" #include "bucket.hpp"
//상훈 뒤 //sanghoon end
#include "hudcomp.hpp" #include "hudcomp.hpp"
#include "HUDChat.hpp" #include "HUDChat.hpp"
#include "hudcomm.hpp" #include "hudcomm.hpp"
@@ -30,7 +30,7 @@
#include "mwapplication.hpp" #include "mwapplication.hpp"
#include "..\missionlang\resource.h" #include "..\missionlang\resource.h"
//상훈짱 begin //sanghoon begin
#include <windows.h> #include <windows.h>
#include <ddraw.h> #include <ddraw.h>
#include <d3d.h> #include <d3d.h>
@@ -43,7 +43,7 @@
extern Scalar g_fLastStartTime; extern Scalar g_fLastStartTime;
extern Adept::ReplicatorID g_LastTarget; extern Adept::ReplicatorID g_LastTarget;
//상훈짱 end //sanghoon end
extern "C" char* _stdcall CharPrevA(const char* lpszStart, const char* lpszCurrent); extern "C" char* _stdcall CharPrevA(const char* lpszStart, const char* lpszCurrent);
#define CharPrev CharPrevA #define CharPrev CharPrevA
@@ -164,7 +164,7 @@ void HUDChat::Reset (void)
// KillData (); // KillData ();
comm = Cast_Object (HUDComm *, MWGUIManager::GetInstance ()->Component (MWGUIManager::HUD_COMM)); comm = Cast_Object (HUDComm *, MWGUIManager::GetInstance ()->Component (MWGUIManager::HUD_COMM));
//mr_device의 맵 데이타를 로드한다. //Load map data for mr_device.
if(hsh_mrdev_initialized){ if(hsh_mrdev_initialized){
extern char AssetsDirectory1[MAX_PATH]; extern char AssetsDirectory1[MAX_PATH];
const Map__GameModel *model = Map::GetInstance ()->GetGameModel (); const Map__GameModel *model = Map::GetInstance ()->GetGameModel ();
@@ -228,12 +228,12 @@ static const float sm1_offset[][2]={
{ 0*2, 0*2}, //special2 { 0*2, 0*2}, //special2
}; };
//number: 0,1,2,3 lancemate의 순서.. //number: 0,1,2,3 lancemate order..
//part: 해당 lancemate mech의 part //part: mech part of the lancemate
//color:해당 part의 color //color: color for this part
void RenderAux1SmallMech(int num,int part,int color) void RenderAux1SmallMech(int num,int part,int color)
{ {
//각각의 offset에 따라서 그린다. //Draw according to each offset.
if(sm1_texture[part][2]!=0){ if(sm1_texture[part][2]!=0){
mfd_device.DrawTexture( mfd_device.DrawTexture(
sm1_offset[part][0]+190+num*160, sm1_offset[part][0]+190+num*160,
@@ -598,15 +598,15 @@ void HUDChat::DrawImplementation(void)
#endif #endif
if(draw_mr){ if(draw_mr){
//미션 리뷰 내용을 그린다. //Draw mission review content.
//_______________________________________________________________________________________________________ //_______________________________________________________________________________________________________
// //
// Mech상태 및 메시지 // Mech status and messages
//_______________________________________________________________________________________________________ //_______________________________________________________________________________________________________
if(!mr_device.map_loaded){ if(!mr_device.map_loaded){
comm = Cast_Object (HUDComm *, MWGUIManager::GetInstance ()->Component (MWGUIManager::HUD_COMM)); comm = Cast_Object (HUDComm *, MWGUIManager::GetInstance ()->Component (MWGUIManager::HUD_COMM));
//mr_device의 맵 데이타를 로드한다. //Load map data for mr_device.
extern char AssetsDirectory1[MAX_PATH]; extern char AssetsDirectory1[MAX_PATH];
const Map__GameModel *model = Map::GetInstance ()->GetGameModel (); const Map__GameModel *model = Map::GetInstance ()->GetGameModel ();
char temp[256]; char temp[256];
@@ -629,7 +629,7 @@ void HUDChat::DrawImplementation(void)
int mech_count=0; int mech_count=0;
PMechInfo pMechInfos = &g_aMechInfos[0]; PMechInfo pMechInfos = &g_aMechInfos[0];
{ {
//현재 다른 메크들의 이름 /Kill/Death를 그린다. //Draw the name/Kill/Death stats of other mechs.
mech_count=MWApplication::GetInstance()->GetMechInfos(2, g_aMechInfos, g_TeamOrderOthers); mech_count=MWApplication::GetInstance()->GetMechInfos(2, g_aMechInfos, g_TeamOrderOthers);
g_TeamOrderCount=mech_count; g_TeamOrderCount=mech_count;
if (mech_count > 8) // jcem if (mech_count > 8) // jcem
@@ -657,7 +657,7 @@ void HUDChat::DrawImplementation(void)
mr_device.pD3DDevice->SetTexture(0,mr_device.pDDSTexture); mr_device.pD3DDevice->SetTexture(0,mr_device.pDDSTexture);
//메크의 Damage 상태를 그린다. //Draw mech Damage status.
for (j=0;j<11;j++){ for (j=0;j<11;j++){
if (j==7 || j==9 || j==10) if (j==7 || j==9 || j==10)
continue; continue;
@@ -669,7 +669,7 @@ void HUDChat::DrawImplementation(void)
} }
} }
//메크의 Callsign/Score/Kills/Deaths를 그린다. //Draw mech Callsign/Score/Kills/Deaths.
int nScore = 0, nKills = 0, nDeaths = 0; int nScore = 0, nKills = 0, nDeaths = 0;
callsign=pMechInfos->m_pcszName; callsign=pMechInfos->m_pcszName;
if (hud) { if (hud) {
@@ -695,7 +695,7 @@ void HUDChat::DrawImplementation(void)
pMechInfos++; pMechInfos++;
} }
//채팅장의 내용을 그린다. //Draw the contents of the chat window.
stlport::list<ChatData>::iterator iter; stlport::list<ChatData>::iterator iter;
int cy=300+30;//chat_y int cy=300+30;//chat_y
for (iter = m_Messages.begin ();iter != m_Messages.end ();iter++){ for (iter = m_Messages.begin ();iter != m_Messages.end ();iter++){
@@ -733,8 +733,8 @@ void HUDChat::DrawImplementation(void)
int i; int i;
// Secondary Maps // Secondary Maps
//맵과 맵 경계선을 그린다. (게임중에 변하지 않으므로 한번만 그린다.) //Draw map and boundary. (Drawn once since it does not change during game.)
//DrawMapBoundary();//다른 버전 구현할 것... //DrawMapBoundary();//Implement alternate version...
mr_device.pD3DDevice->SetRenderState(D3DRENDERSTATE_CLIPPING ,TRUE); mr_device.pD3DDevice->SetRenderState(D3DRENDERSTATE_CLIPPING ,TRUE);
mr_device.pD3DDevice->SetTexture(0,mr_device.pDDSMapTexture); mr_device.pD3DDevice->SetTexture(0,mr_device.pDDSMapTexture);
mr_device.pD3DDevice->SetRenderState( D3DRENDERSTATE_ALPHABLENDENABLE, TRUE ); mr_device.pD3DDevice->SetRenderState( D3DRENDERSTATE_ALPHABLENDENABLE, TRUE );
@@ -748,7 +748,7 @@ void HUDChat::DrawImplementation(void)
//MechWarrior4::VehicleInterface* p = MechWarrior4::VehicleInterface::GetInstance(); //MechWarrior4::VehicleInterface* p = MechWarrior4::VehicleInterface::GetInstance();
//미션 리뷰에서는 현재 메크가 중심에 표시되므로 맵이 스크롤 되어 표시된다. //In mission review, current mech is shown at center so the map scrolls.
float MR_MSF=4.0f;//Mission Review - Map Scale Factor float MR_MSF=4.0f;//Mission Review - Map Scale Factor
const float ViewSize=300.0f;//Mission Review - Map Size const float ViewSize=300.0f;//Mission Review - Map Size
const float ViewLMargin=10; const float ViewLMargin=10;
@@ -758,9 +758,9 @@ void HUDChat::DrawImplementation(void)
D3DVIEWPORT7 viewport={ViewLMargin,ViewTMargin,ViewSize,ViewSize,0.0f,1.0f}; D3DVIEWPORT7 viewport={ViewLMargin,ViewTMargin,ViewSize,ViewSize,0.0f,1.0f};
mr_device.pD3DDevice->SetViewport(&viewport); mr_device.pD3DDevice->SetViewport(&viewport);
///////////////////// MAP 시작 ////////////////////// ///////////////////// MAP BEGIN //////////////////////
//Focus Mech를 설정하는 루틴을 넣어야한다. //Need to add routine to set Focus Mech.
Scalar multx,multz; Scalar multx,multz;
@@ -787,10 +787,10 @@ void HUDChat::DrawImplementation(void)
mr_device.pD3DDevice->SetTexture(0,mr_device.pDDSTexture); mr_device.pD3DDevice->SetTexture(0,mr_device.pDDSTexture);
//맵상에 메크들들 그리기.텍스트 먼저.. //Draw mechs on map. Text first..
for(i=0,pMechInfos = &g_aMechInfos[0];i<mech_count;i++,pMechInfos++){ for(i=0,pMechInfos = &g_aMechInfos[0];i<mech_count;i++,pMechInfos++){
Mech* pMech = pMechInfos->m_pMech; Mech* pMech = pMechInfos->m_pMech;
//메크의 위치를 구할 것.. //TODO: get mech position..
Stuff::Point3D pos; Stuff::Point3D pos;
@@ -827,10 +827,10 @@ void HUDChat::DrawImplementation(void)
color,callsign,TEXTALIGN_HCENTER|TEXTALIGN_TOP); color,callsign,TEXTALIGN_HCENTER|TEXTALIGN_TOP);
} }
//아이콘 그리기. //Draw icon.
for(i=0,pMechInfos = &g_aMechInfos[0];i<mech_count;i++,pMechInfos++){ for(i=0,pMechInfos = &g_aMechInfos[0];i<mech_count;i++,pMechInfos++){
Mech* pMech = pMechInfos->m_pMech; Mech* pMech = pMechInfos->m_pMech;
//메크의 위치를 구할 것.. //TODO: get mech position..
Stuff::Point3D pos; Stuff::Point3D pos;
@@ -886,7 +886,7 @@ void HUDChat::DrawImplementation(void)
mr_device.pD3DDevice->SetViewport(&viewport2); mr_device.pD3DDevice->SetViewport(&viewport2);
///////////////////// MAP ////////////////////// ///////////////////// MAP END //////////////////////
//_______________________________________________________________________________________________________ //_______________________________________________________________________________________________________
// //
@@ -894,7 +894,7 @@ void HUDChat::DrawImplementation(void)
//_______________________________________________________________________________________________________ //_______________________________________________________________________________________________________
//미션 시간 그리기...hudtimer.cpp에 DrawImplementation에서 따온것임.. //Draw mission timer... taken from DrawImplementation in hudtimer.cpp..
MWMission *mwmiss = Cast_Object (MWMission *,Mission::GetInstance ()); MWMission *mwmiss = Cast_Object (MWMission *,Mission::GetInstance ());
Verify (mwmiss); Verify (mwmiss);
Stuff::Scalar cur_time=mwmiss->GetMissionTime();//-mwmiss->GetMissionTime(); Stuff::Scalar cur_time=mwmiss->GetMissionTime();//-mwmiss->GetMissionTime();
@@ -923,7 +923,7 @@ void HUDChat::DrawImplementation(void)
if(g_nTeamOrderMode==TEAM_MODE){ if(g_nTeamOrderMode==TEAM_MODE){
int i,j; int i,j;
int size=3; int size=3;
//메크들의 상태를 그린다. //Draw mech status.
PMechInfo pMechInfos = &g_aMechInfos[1]; PMechInfo pMechInfos = &g_aMechInfos[1];
size=MWApplication::GetInstance()->GetMechInfos(0, g_aMechInfos, g_TeamOrderOthers); size=MWApplication::GetInstance()->GetMechInfos(0, g_aMechInfos, g_TeamOrderOthers);
size--; size--;
@@ -970,7 +970,7 @@ void HUDChat::DrawImplementation(void)
pMechInfos++; pMechInfos++;
} }
mfd_device.DrawMFDBackText(mfd_text_comm1); mfd_device.DrawMFDBackText(mfd_text_comm1);
//채팅장의 내용을 그린다. //Draw the contents of the chat window.
stlport::list<ChatData>::iterator iter; stlport::list<ChatData>::iterator iter;
int cy=240;//chat_y int cy=240;//chat_y
for (iter = m_Messages.begin ();iter != m_Messages.end ();iter++){ for (iter = m_Messages.begin ();iter != m_Messages.end ();iter++){
@@ -996,7 +996,7 @@ void HUDChat::DrawImplementation(void)
} }
}else if(g_nTeamOrderMode==FREEFORALL_MODE){ }else if(g_nTeamOrderMode==FREEFORALL_MODE){
//현재 다른 메크들의 이름 /Kill/Death를 그린다. //Draw the name/Kill/Death stats of other mechs.
int size=0; int size=0;
PMechInfo pMechInfos = &g_aMechInfos[1]; PMechInfo pMechInfos = &g_aMechInfos[1];
size=MWApplication::GetInstance()->GetMechInfos(2, g_aMechInfos, g_TeamOrderOthers); size=MWApplication::GetInstance()->GetMechInfos(2, g_aMechInfos, g_TeamOrderOthers);
@@ -1006,10 +1006,10 @@ void HUDChat::DrawImplementation(void)
size = 7; size = 7;
int i; int i;
//번호를 먼저 지운다. //Clear the numbers first.
// MSL 5.03 Comm MFD // MSL 5.03 Comm MFD
for(i=0;i<7;i++)mfd_text_comm3[i][0]=0; for(i=0;i<7;i++)mfd_text_comm3[i][0]=0;
//번호를 채워 넣는다. //Fill in the numbers.
// MSL 5.03 Comm MFD // MSL 5.03 Comm MFD
for(i=0;i<size;i++)itoa(i+1,mfd_text_comm3[i],10); for(i=0;i<size;i++)itoa(i+1,mfd_text_comm3[i],10);
@@ -1064,8 +1064,8 @@ void HUDChat::DrawImplementation(void)
if(size.cx<160){ if(size.cx<160){
mfd_device.pFont[1].DrawText((float)p2->x,(float)p2->y,0xFFFFFFFF,callsign,TEXTALIGN_ORG); mfd_device.pFont[1].DrawText((float)p2->x,(float)p2->y,0xFFFFFFFF,callsign,TEXTALIGN_ORG);
}else{ }else{
//최소크기 폰트도.. 넘어선다... //Even the minimum font size is exceeded...
//2line으로 만든다. //Split into 2 lines.
char callsign2[128]; char callsign2[128];
strcpy(callsign2,callsign); strcpy(callsign2,callsign);
int len2=strlen(callsign)/2; int len2=strlen(callsign)/2;
@@ -1120,7 +1120,7 @@ void HUDChat::DrawImplementation(void)
pMechInfos++; pMechInfos++;
} }
//채팅장의 내용을 그린다. //Draw the contents of the chat window.
stlport::list<ChatData>::iterator iter; stlport::list<ChatData>::iterator iter;
int cy=180;//chat_y int cy=180;//chat_y
for (iter = m_Messages.begin ();iter != m_Messages.end ();iter++){ for (iter = m_Messages.begin ();iter != m_Messages.end ();iter++){
@@ -1145,7 +1145,7 @@ void HUDChat::DrawImplementation(void)
iter = m_Messages.erase (iter); iter = m_Messages.erase (iter);
} }
/* /*
//MWMission.cpp에서 가져온것인 //Taken from MWMission.cpp
MWMission *mwmiss = Cast_Object (MWMission *,Mission::GetInstance ()); MWMission *mwmiss = Cast_Object (MWMission *,Mission::GetInstance ());
int death=0,kill=0;//,score int death=0,kill=0;//,score
@@ -1167,7 +1167,7 @@ void HUDChat::DrawImplementation(void)
}else if(g_nTeamOrderMode==TEAM_MESSAGE2){ }else if(g_nTeamOrderMode==TEAM_MESSAGE2){
;//do nothing ;//do nothing
} }
//상훈 뒤 //sanghoon end
mfd_device.EndChannel(); mfd_device.EndChannel();
} else { } else {
}//hsh_initialized }//hsh_initialized
+4 -4
View File
@@ -1,5 +1,5 @@
#include "MW4Headers.hpp" #include "MW4Headers.hpp"
//상훈 앞 //sanghoon begin
#include "MWMission.hpp" #include "MWMission.hpp"
#include "VehicleInterface.hpp" #include "VehicleInterface.hpp"
#include "Narc.hpp" #include "Narc.hpp"
@@ -13,7 +13,7 @@
#include "mwguimanager.hpp" #include "mwguimanager.hpp"
#include "MWPlayer.hpp" #include "MWPlayer.hpp"
#include <Adept\Mission.hpp> #include <Adept\Mission.hpp>
//상훈 뒤 //sanghoon end
#include "hudcomp.hpp" #include "hudcomp.hpp"
#include "HUDComm.hpp" #include "HUDComm.hpp"
@@ -25,14 +25,14 @@
#include "..\missionlang\resource.h" #include "..\missionlang\resource.h"
#include "mechlabheaders.h" #include "mechlabheaders.h"
//상훈짱 begin //sanghoon begin
#include <windows.h> #include <windows.h>
#include <ddraw.h> #include <ddraw.h>
#include <d3d.h> #include <d3d.h>
#include <GameOS\render.hpp> #include <GameOS\render.hpp>
//상훈짱 end //sanghoon end
using namespace MechWarrior4; using namespace MechWarrior4;
+3 -3
View File
@@ -333,7 +333,7 @@ inline DWORD DarkerColor (DWORD color)
{ m_Justification = value; } { m_Justification = value; }
void Wrap (bool value) void Wrap (bool value)
{ m_Wrap = value; } { m_Wrap = value; }
//상훈 //sanghoon
void SetAsAlt(){ void SetAsAlt(){
m_Font=altFontHandle; m_Font=altFontHandle;
} }
@@ -381,9 +381,9 @@ inline DWORD DarkerColor (DWORD color)
virtual void EndPos (DWORD& x,DWORD& y, bool bAdjust = true); virtual void EndPos (DWORD& x,DWORD& y, bool bAdjust = true);
bool Empty (void) bool Empty (void)
{ return (m_Text[0] == 0); } { return (m_Text[0] == 0); }
//상훈 앞 //sanghoon begin
char *hsh_get_m_Text(){return m_Text;} char *hsh_get_m_Text(){return m_Text;}
//상훈 뒤 //sanghoon end
}; };
class HUDNumberText : public HUDText class HUDNumberText : public HUDText
+10 -10
View File
@@ -95,7 +95,7 @@ void HUDTargetArrow::SetZoomWindow(Stuff::Scalar left,Stuff::Scalar top,Stuff::S
void HUDTargetArrow::DrawImplementation(void) void HUDTargetArrow::DrawImplementation(void)
{ {
//상훈-깜박임 처리는 어디서 하는지 찾아 볼것. //sanghoon - need to find where blink handling is done.
Point3D loc,size; Point3D loc,size;
DWORD color; DWORD color;
int textx,texty,ty2; int textx,texty,ty2;
@@ -208,7 +208,7 @@ void HUDTargetArrow::DrawImplementation(void)
{ {
size = m_Textures[5]->Size (); size = m_Textures[5]->Size ();
m_Textures[5]->Draw (Point3D (m_TargetX,m_TargetY,0.9f),size,color); m_Textures[5]->Draw (Point3D (m_TargetX,m_TargetY,0.9f),size,color);
//꺽쇠 네개가 하나로 합쳐진 텍스쳐... //Texture of four angle brackets merged into one...
} }
else else
{ {
@@ -278,7 +278,7 @@ void HUDTorsoBar::DrawImplementation(void)
Scalar currentxval,currentyval; Scalar currentxval,currentyval;
Point3D size,loc,texsize; Point3D size,loc,texsize;
//x축을 나타내는 그래프를 그리는 루틴... //Routine to draw the graph representing the x-axis...
//_________________________________________________________________________ //_________________________________________________________________________
size = TwistSize (); size = TwistSize ();
texsize = m_Textures[0]->Size (); texsize = m_Textures[0]->Size ();
@@ -289,7 +289,7 @@ void HUDTorsoBar::DrawImplementation(void)
if (currentxval > 0) if (currentxval > 0)
loc.x += 1.0f; loc.x += 1.0f;
DWORD color = DarkerColor (Color ()); DWORD color = DarkerColor (Color ());
//가로 ruler를 그린다.(화살표는 들어있지 않음) //Draw horizontal ruler. (arrows not included)
m_Textures[5]->Draw (loc,m_Textures[5]->Size (),color,HUDTexture::NO_FLIP,true); m_Textures[5]->Draw (loc,m_Textures[5]->Size (),color,HUDTexture::NO_FLIP,true);
color = Color (); color = Color ();
if (currentxval != 0) if (currentxval != 0)
@@ -315,19 +315,19 @@ void HUDTorsoBar::DrawImplementation(void)
ty= (DWORD) (loc.y+size.y+10); ty= (DWORD) (loc.y+size.y+10);
if ((currentxval > 5) || (currentxval < -5)) if ((currentxval > 5) || (currentxval < -5))
{ {
//과도한 twist시에 방향표시해줌.. //Shows direction indicator when torso twist is excessive..
m_TwistText->Draw (Point3D ((Scalar) tx,(Scalar) ty,0.9f)); m_TwistText->Draw (Point3D ((Scalar) tx,(Scalar) ty,0.9f));
} }
//상체표시 사각형.. //Upper body indicator rectangle..
// Changed Torso Bar from Green to Yellow // Changed Torso Bar from Green to Yellow
// MSL 5.00 // MSL 5.00
color = MakeColor (255,255,0,250); color = MakeColor (255,255,0,250);
my_DrawRect (min,(int) loc.y,max,(int) (loc.y+size.y),color); my_DrawRect (min,(int) loc.y,max,(int) (loc.y+size.y),color);
color = DarkerColor (Color ()); color = DarkerColor (Color ());
//위쪽, 상체 방향표시 화살표.. //Top arrow indicating upper body direction..
m_Textures[2]->Draw (Point3D (loc.x-currentxval,loc.y-1,0.9f),texsize,color); m_Textures[2]->Draw (Point3D (loc.x-currentxval,loc.y-1,0.9f),texsize,color);
//아래쪽. 중심표시 화살표.. //Bottom arrow indicating center position..
m_Textures[3]->Draw (Point3D (loc.x-1,loc.y+size.y+1,0.9f),texsize,color); m_Textures[3]->Draw (Point3D (loc.x-1,loc.y+size.y+1,0.9f),texsize,color);
// DrawLine ((int) (loc.x-currentxval),(int) (loc.y-1),(int) (loc.x-currentxval),(int) (loc.y+size.y),color); // DrawLine ((int) (loc.x-currentxval),(int) (loc.y-1),(int) (loc.x-currentxval),(int) (loc.y+size.y),color);
} }
@@ -339,7 +339,7 @@ void HUDTorsoBar::DrawImplementation(void)
// DrawLine ((int) (loc.x),(int) (loc.y-1),(int) (loc.x),(int) (loc.y+size.y),color); // DrawLine ((int) (loc.x),(int) (loc.y-1),(int) (loc.x),(int) (loc.y+size.y),color);
} }
//y축을 나타내는 그래프를 그리는 루틴...<==여기는 과도한 상하를 나타내는 텍스트가 없다. //Routine to draw graph for y-axis... <== no excessive up/down text here.
//_________________________________________________________________________ //_________________________________________________________________________
size = PitchSize (); size = PitchSize ();
currentyval = (m_TorsoPitch*size.y)/100.0f; // 33 is the width of the bar currentyval = (m_TorsoPitch*size.y)/100.0f; // 33 is the width of the bar
@@ -382,7 +382,7 @@ void HUDTorsoBar::DrawImplementation(void)
m_Textures[1]->Draw (Point3D (loc.x+size.x,loc.y,0.9f),texsize,color); m_Textures[1]->Draw (Point3D (loc.x+size.x,loc.y,0.9f),texsize,color);
// DrawLine ((int) (loc.x-1),(int) (loc.y),(int) (loc.x+size.x+2),(int) (loc.y),color); // DrawLine ((int) (loc.x-1),(int) (loc.y),(int) (loc.x+size.x+2),(int) (loc.y),color);
} }
//.. DrawImplementation. //End.. DrawImplementation.
} }
+34 -34
View File
@@ -9,7 +9,7 @@
#include "mwapplication.hpp" #include "mwapplication.hpp"
#include "..\missionlang\resource.h" #include "..\missionlang\resource.h"
//상훈짱 begin //sanghoon begin
#include <windows.h> #include <windows.h>
#include <ddraw.h> #include <ddraw.h>
#include <d3d.h> #include <d3d.h>
@@ -34,7 +34,7 @@ bool g_bNextTargetMode = false;
bool g_bCrossTargetMode = false; bool g_bCrossTargetMode = false;
// MSL 5.03 Secondary Damage Display // MSL 5.03 Secondary Damage Display
int g_nAuxilMode = 0; int g_nAuxilMode = 0;
//상훈짱 end //sanghoon end
using namespace MechWarrior4; using namespace MechWarrior4;
namespace HUDDAMAGE namespace HUDDAMAGE
@@ -330,9 +330,9 @@ HUDDamage::HUDDamage()
Color (MakeColor (0,175,0,150)); Color (MakeColor (0,175,0,150));
m_DamageFlashTime = 0; m_DamageFlashTime = 0;
m_HitFlashTime = 0; m_HitFlashTime = 0;
//상훈 앞 //sanghoon begin
VehicleInterface::GetInstance()->hudDamageMode=false; VehicleInterface::GetInstance()->hudDamageMode=false;
//상훈 뒤 //sanghoon end
m_ArmorMode = VehicleInterface::GetInstance()->hudDamageMode; m_ArmorMode = VehicleInterface::GetInstance()->hudDamageMode;
for (i=0;i<MAX_HUD_DAMAGE_ZONE+1;i++) for (i=0;i<MAX_HUD_DAMAGE_ZONE+1;i++)
{ {
@@ -410,7 +410,7 @@ void HUDDamage::Reset (void)
} }
else else
{ {
//상훈 //sanghoon
mfd_device.LoadDamageTexture(texturename[m_MechID]); mfd_device.LoadDamageTexture(texturename[m_MechID]);
radar_device.LoadRadarDamageTexture(texturename[m_MechID]); radar_device.LoadRadarDamageTexture(texturename[m_MechID]);
} }
@@ -464,7 +464,7 @@ void HUDDamage::ArmorValue (Scalar values[MAX_HUD_DAMAGE_ZONE+1],bool firstpass)
m_ArmorValues[i] = values[i]; m_ArmorValues[i] = values[i];
} }
} }
//상훈 앞 //sanghoon begin
//nst DWORD SH_DamageColor[6]={0xFFFFFFFF,0xFFCCCCCC,0xFF999999,0xFF666666,0xFF333333,0xFF000000}; //nst DWORD SH_DamageColor[6]={0xFFFFFFFF,0xFFCCCCCC,0xFF999999,0xFF666666,0xFF333333,0xFF000000};
const DWORD SH_DamageColor[6]={0xFFFFFFFF,0xFFDDDDDD,0xFFBBBBBB,0xFF999999,0xFF777777,0xFF333333}; const DWORD SH_DamageColor[6]={0xFFFFFFFF,0xFFDDDDDD,0xFFBBBBBB,0xFF999999,0xFF777777,0xFF333333};
@@ -566,7 +566,7 @@ static RECT damage_back_frames[4]={
{504,245,566,382}, {504,245,566,382},
{573,245,634,382}, {573,245,634,382},
}; };
//상훈 뒤 //sanghoon end
void HUDDamage::DrawImplementation(void) void HUDDamage::DrawImplementation(void)
{ {
@@ -632,7 +632,7 @@ void HUDDamage::DrawImplementation(void)
color = Color (); color = Color ();
for (i=0;i<10;i++) for (i=0;i<10;i++)
{ {
//글자를 그리는 곳인가?? //Is this where text is drawn??
m_Textures[20+i]->Draw (Point3D ((Scalar) bartable[i]+1.0f,(Scalar) y,0.9f),size,MakeColor (255,255,255,255),HUDTexture::NO_FLIP,true); m_Textures[20+i]->Draw (Point3D ((Scalar) bartable[i]+1.0f,(Scalar) y,0.9f),size,MakeColor (255,255,255,255),HUDTexture::NO_FLIP,true);
if (!(m_HitFlashCount[trans_array[i]] & 0x01)) if (!(m_HitFlashCount[trans_array[i]] & 0x01))
{ {
@@ -752,7 +752,7 @@ void HUDDamage::DrawImplementation(void)
fred = 0; fred = 0;
for (i=0;i<11;i++) for (i=0;i<11;i++)
{//13이라는 숫자가 의미하는 것은 무엇일까? {//What does the number 13 mean here?
#if 0 #if 0
if (i != fred) if (i != fred)
{ {
@@ -872,7 +872,7 @@ void HUDDamage::DrawImplementation(void)
mfd_device.pD3DDevice->SetRenderState( D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA ); mfd_device.pD3DDevice->SetRenderState( D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA );
mfd_device.pD3DDevice->SetRenderState( D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA ); mfd_device.pD3DDevice->SetRenderState( D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA );
//원래것은..13,14,14,14,14,14,14,14,16,14의 간격을 두고 있다. //The original spacing is 13,14,14,14,14,14,14,14,16,14.
const hsh_bartable[11] = {26+61*0,26+61*1,26+61*2,26+61*3,26+61*4,26+61*5,26+61*6,26+61*7,522,591,540}; const hsh_bartable[11] = {26+61*0,26+61*1,26+61*2,26+61*3,26+61*4,26+61*5,26+61*6,26+61*7,522,591,540};
DWORD color=0xFFFFFFFF; DWORD color=0xFFFFFFFF;
@@ -907,7 +907,7 @@ void HUDDamage::DrawImplementation(void)
radar_device.pDDSTarget->Blt(&rc,NULL,NULL,DDBLT_COLORFILL ,&fx); radar_device.pDDSTarget->Blt(&rc,NULL,NULL,DDBLT_COLORFILL ,&fx);
for (i=0;i<11;i++) for (i=0;i<11;i++)
{//13이라는 숫자가 의미하는 것은 무엇일까? {//What does the number 13 mean here?
int dv=m_DamageValues[i]; int dv=m_DamageValues[i];
DWORD color=0xFF000000; DWORD color=0xFF000000;
if(0<=dv && dv<=5) if(0<=dv && dv<=5)
@@ -948,7 +948,7 @@ void HUDDamage::DrawImplementation(void)
{ {
if (m_ArmorValues[trans_array[i]] != -1) if (m_ArmorValues[trans_array[i]] != -1)
{ {
hsh_x=hsh_bartable[i];//7에서는 예외이다. hsh_x=hsh_bartable[i];//Exception at index 7.
int tr=trans_array[i]; int tr=trans_array[i];
DWORD color=(m_HitFlashCount[tr] & 0x01)? 0xFFFFFFFF : SH_DamageColor[m_DamageValues[tr]]; DWORD color=(m_HitFlashCount[tr] & 0x01)? 0xFFFFFFFF : SH_DamageColor[m_DamageValues[tr]];
@@ -999,7 +999,7 @@ void HUDDamage::DrawImplementation(void)
mfd_device.LoadDamageTexture(texturename[m_MechID]); mfd_device.LoadDamageTexture(texturename[m_MechID]);
for (i=0;i<13;i++) for (i=0;i<13;i++)
{//13이라는 숫자가 의미하는 것은 무엇일까? {//What does the number 13 mean here?
int dv=m_DamageValues[i]; int dv=m_DamageValues[i];
DWORD color=0xFF000000; DWORD color=0xFF000000;
if(0<=dv && dv<=5)color=SH_DamageColor[dv]; if(0<=dv && dv<=5)color=SH_DamageColor[dv];
@@ -1249,7 +1249,7 @@ HUDTargetDamage::HUDTargetDamage() :
m_TargetName->Justification (HUDText::LEFT_ALIGN); m_TargetName->Justification (HUDText::LEFT_ALIGN);
m_TargetRangeText = new HUDNumberText (); m_TargetRangeText = new HUDNumberText ();
m_TargetRangeText->Justification (HUDText::LEFT_ALIGN); m_TargetRangeText->Justification (HUDText::LEFT_ALIGN);
//상훈 //sanghoon
// m_TargetRangeText->SetSize(HUDText::LARGE_SIZE); // m_TargetRangeText->SetSize(HUDText::LARGE_SIZE);
m_TargetRangeText->SetSize(HUDText::MEDIUM_SIZE); m_TargetRangeText->SetSize(HUDText::MEDIUM_SIZE);
m_TargetAlignment = 0; m_TargetAlignment = 0;
@@ -1269,9 +1269,9 @@ HUDTargetDamage::HUDTargetDamage() :
m_TargetMechID = 0; m_TargetMechID = 0;
m_Weapons.clear (); m_Weapons.clear ();
//상훈 앞 //sanghoon begin
VehicleInterface::GetInstance()->hudTargetDamageMode=false; VehicleInterface::GetInstance()->hudTargetDamageMode=false;
//상훈 뒤 //sanghoon end
m_ArmorMode = VehicleInterface::GetInstance()->hudTargetDamageMode; m_ArmorMode = VehicleInterface::GetInstance()->hudTargetDamageMode;
m_LastMechMode = false; m_LastMechMode = false;
} }
@@ -1315,7 +1315,7 @@ void HUDTargetDamage::Reset (void)
} }
else else
{ {
//상훈 //sanghoon
mfd_device.LoadTargetTexture(texturename[m_TargetMechID]); mfd_device.LoadTargetTexture(texturename[m_TargetMechID]);
} }
@@ -1764,7 +1764,7 @@ if(!hsh_initialized){
if (m_TargetTonnage == -1) if (m_TargetTonnage == -1)
{ {
//타켓이 메크가 아닐때.. //When target is not a mech..
Verify (!m_ArmorMode); // only mechs show armor mode Verify (!m_ArmorMode); // only mechs show armor mode
if (m_TargetVehicle.GetCurrent()->IsDerivedFrom (MWObject::DefaultData)) if (m_TargetVehicle.GetCurrent()->IsDerivedFrom (MWObject::DefaultData))
{ {
@@ -1805,7 +1805,7 @@ if(!hsh_initialized){
} }
else else
{ {
//타켓이 메크일때.. //When target is a mech..
Verify (m_TargetVehicle.GetCurrent ()->IsDerivedFrom (Mech::DefaultData)); Verify (m_TargetVehicle.GetCurrent ()->IsDerivedFrom (Mech::DefaultData));
Mech *mech = Cast_Object(Mech *, m_TargetVehicle.GetCurrent()); Mech *mech = Cast_Object(Mech *, m_TargetVehicle.GetCurrent());
Check_Object (mech); Check_Object (mech);
@@ -1826,7 +1826,7 @@ if(!hsh_initialized){
if (m_ArmorMode) if (m_ArmorMode)
{ {
//타켓이 메크이고 아머 모드일때 //When target is a mech and in armor mode
int x,y; int x,y;
size = m_Textures[20]->Size (); size = m_Textures[20]->Size ();
@@ -1897,7 +1897,7 @@ if(!hsh_initialized){
} }
else else
{ {
//상훈 //sanghoon
mfd_device.LoadTargetTexture(texturename[m_TargetMechID]); mfd_device.LoadTargetTexture(texturename[m_TargetMechID]);
} }
@@ -1910,7 +1910,7 @@ if(!hsh_initialized){
fred = 0; fred = 0;
for (i=0;i<11;i++) for (i=0;i<11;i++)
{//13이라는 숫자가 의미하는 것은 무엇일까? {//What does the number 13 mean here?
#if 0 #if 0
if (i != fred) if (i != fred)
{ {
@@ -1983,7 +1983,7 @@ else
if (m_TargetVehicle.GetCurrent ()) if (m_TargetVehicle.GetCurrent ())
{ {
//3D target 또는 2D Target을 그린다. //Draw 3D target or 2D target.
if (!m_ArmorMode) if (!m_ArmorMode)
{ {
if(g_f3dtarget) if(g_f3dtarget)
@@ -2006,19 +2006,19 @@ else
int mechindex=GetMechIndex(model->mechID); int mechindex=GetMechIndex(model->mechID);
if(mechindex>=0) if(mechindex>=0)
{ {
//지원되는 mech만 그린다. //Draw only supported mechs.
// MSL 5.02 Target MFD Image // MSL 5.02 Target MFD Image
int x=(mechindex%8)*128; int x=(mechindex%8)*128;
int y=(mechindex/8)*128; int y=(mechindex/8)*128;
// int x=(mechindex%4)*128; // int x=(mechindex%4)*128;
// int y=(mechindex/4)*128; // int y=(mechindex/4)*128;
//Target을 2D로 그린다. //Draw target in 2D.
mfd_device.pD3DDevice->SetTexture(0,mfd_device.pDDSMechTexture); mfd_device.pD3DDevice->SetTexture(0,mfd_device.pDDSMechTexture);
mfd_device.pD3DDevice->SetRenderState( D3DRENDERSTATE_ALPHABLENDENABLE, FALSE); mfd_device.pD3DDevice->SetRenderState( D3DRENDERSTATE_ALPHABLENDENABLE, FALSE);
mfd_device.pD3DDevice->SetTextureStageState(0,D3DTSS_MAGFILTER,D3DTFG_LINEAR); mfd_device.pD3DDevice->SetTextureStageState(0,D3DTSS_MAGFILTER,D3DTFG_LINEAR);
mfd_device.pD3DDevice->SetTextureStageState(0,D3DTSS_MINFILTER,D3DTFG_LINEAR); mfd_device.pD3DDevice->SetTextureStageState(0,D3DTSS_MINFILTER,D3DTFG_LINEAR);
//메크의 종류별로 좌표를 계산하는.. 루틴을 작성하여 집어 넣을것... //Need to write routine to calculate coordinates per mech type...
// MSL 5.02 Target MFD Image // MSL 5.02 Target MFD Image
mfd_device.tw=1024,mfd_device.th=1024; mfd_device.tw=1024,mfd_device.th=1024;
// MSL 5.02 Target MFD Image Resize // MSL 5.02 Target MFD Image Resize
@@ -2060,7 +2060,7 @@ else
radar_device.pDDSTarget->Blt(&rc,NULL,NULL,DDBLT_COLORFILL ,&fx); radar_device.pDDSTarget->Blt(&rc,NULL,NULL,DDBLT_COLORFILL ,&fx);
for (int i=0;i<11;i++) for (int i=0;i<11;i++)
{//13이라는 숫자가 의미하는 것은 무엇일까? {//What does the number 13 mean here?
int dv=m_DamageValues[i]; int dv=m_DamageValues[i];
DWORD color=0xFF000000; DWORD color=0xFF000000;
if(0<=dv && dv<=5) if(0<=dv && dv<=5)
@@ -2103,7 +2103,7 @@ else
if (m_ShowData) if (m_ShowData)
{ {
//좌측 하단의 target의 무기의 상태를 표시하는 루틴.. //Routine to display weapon status of target in lower-left..
if (!m_ArmorMode) if (!m_ArmorMode)
{ {
stlport::vector<WeaponData>::iterator iter; stlport::vector<WeaponData>::iterator iter;
@@ -2134,7 +2134,7 @@ else
if (m_TargetTonnage == -1) if (m_TargetTonnage == -1)
{ {
//타켓이 메크가 아닐때.. //When target is not a mech..
Verify (!m_ArmorMode); // only mechs show armor mode Verify (!m_ArmorMode); // only mechs show armor mode
if (m_TargetVehicle.GetCurrent()->IsDerivedFrom (MWObject::DefaultData)) if (m_TargetVehicle.GetCurrent()->IsDerivedFrom (MWObject::DefaultData))
{ {
@@ -2145,7 +2145,7 @@ else
m_ArmorValues[0] = (veh->m_HitPoints / veh->m_MaxHitPoints); m_ArmorValues[0] = (veh->m_HitPoints / veh->m_MaxHitPoints);
if (m_ArmorValues[0] != -1) if (m_ArmorValues[0] != -1)
{ {
//데미지 막대 그래프를 그린다. 높이와 색상 동시에 표현된다. //Draw damage bar graph. Height and color are expressed simultaneously.
int level; int level;
level = (int) ((m_ArmorValues[0]*(MAX_HUD_DAMAGE_LEVEL))+0.5f); level = (int) ((m_ArmorValues[0]*(MAX_HUD_DAMAGE_LEVEL))+0.5f);
level = MAX_HUD_DAMAGE_LEVEL - level; level = MAX_HUD_DAMAGE_LEVEL - level;
@@ -2160,7 +2160,7 @@ else
}//When the target is not a mech. }//When the target is not a mech.
else else
{ {
//타켓이 메크일때.. //When target is a mech..
Verify (m_TargetVehicle.GetCurrent ()->IsDerivedFrom (Mech::DefaultData)); Verify (m_TargetVehicle.GetCurrent ()->IsDerivedFrom (Mech::DefaultData));
Mech *mech = Cast_Object(Mech *, m_TargetVehicle.GetCurrent()); Mech *mech = Cast_Object(Mech *, m_TargetVehicle.GetCurrent());
Check_Object (mech); Check_Object (mech);
@@ -2178,7 +2178,7 @@ else
if (m_ArmorMode) if (m_ArmorMode)
{ {
//타켓이 메크이고 아머 모드일때 //When target is a mech and in armor mode
for (i=0;i<MAX_HUD_DAMAGE_ZONE;i++) for (i=0;i<MAX_HUD_DAMAGE_ZONE;i++)
{ {
int tr=trans_array[i]; int tr=trans_array[i];
@@ -2208,12 +2208,12 @@ else
// MSL 5.03 Target Damage Display // MSL 5.03 Target Damage Display
mfd_device.LoadTargetTexture(texturename[m_TargetMechID]); mfd_device.LoadTargetTexture(texturename[m_TargetMechID]);
//타켓이 메크이고 아머 모드가 아닐때.. //When target is a mech and NOT in armor mode..
if(mfd_device.pDDSTargetTexture==0) if(mfd_device.pDDSTargetTexture==0)
mfd_device.LoadTargetTexture(texturename[m_TargetMechID]); mfd_device.LoadTargetTexture(texturename[m_TargetMechID]);
for (i=0;i<11;i++) for (i=0;i<11;i++)
{//13이라는 숫자가 의미하는 것은 무엇일까? {//What does the number 13 mean here?
int dv=m_DamageValues[i]; int dv=m_DamageValues[i];
DWORD color=0xFF000000; DWORD color=0xFF000000;
if(0<=dv && dv<=5)color=SH_DamageColor[dv]; if(0<=dv && dv<=5)color=SH_DamageColor[dv];
+6 -6
View File
@@ -77,11 +77,11 @@ namespace MechWarrior4
int m_TargetMechID; int m_TargetMechID;
bool m_ShowData; bool m_ShowData;
bool m_LastMechMode; bool m_LastMechMode;
//상훈 앞 //sanghoon begin
public: public:
char hsh_targetname[64]; char hsh_targetname[64];
char hsh_targetrange[64]; char hsh_targetrange[64];
//상훈 뒤 //sanghoon end
public: public:
HUDTargetDamage(); HUDTargetDamage();
@@ -97,10 +97,10 @@ namespace MechWarrior4
void TargetName (char *name) void TargetName (char *name)
{ {
m_TargetName->UpdateText (name); m_TargetName->UpdateText (name);
//상훈 앞 //sanghoon begin
strncpy(hsh_targetname,name,sizeof(hsh_targetname)); strncpy(hsh_targetname,name,sizeof(hsh_targetname));
hsh_targetname[sizeof(hsh_targetname)-1]=0; hsh_targetname[sizeof(hsh_targetname)-1]=0;
//상훈 뒤 //sanghoon end
} }
void TargetRange (Stuff::Scalar value) void TargetRange (Stuff::Scalar value)
{ {
@@ -108,10 +108,10 @@ namespace MechWarrior4
int temp = (int) value; int temp = (int) value;
sprintf (text,"%dm",temp); sprintf (text,"%dm",temp);
m_TargetRangeText->UpdateText (text); m_TargetRangeText->UpdateText (text);
//상훈 앞 //sanghoon begin
strncpy(hsh_targetrange,text,sizeof(hsh_targetrange)); strncpy(hsh_targetrange,text,sizeof(hsh_targetrange));
hsh_targetrange[sizeof(hsh_targetrange)-1]=0; hsh_targetrange[sizeof(hsh_targetrange)-1]=0;
//상훈 뒤 //sanghoon end
} }
void TargetTonnage (Stuff::Scalar value); void TargetTonnage (Stuff::Scalar value);
void TargetAlignment (int value) void TargetAlignment (int value)
+8 -8
View File
@@ -8,14 +8,14 @@
#include "mwapplication.hpp" #include "mwapplication.hpp"
// MSL 5.02 Nav Points // MSL 5.02 Nav Points
#include "navpoint.hpp" #include "navpoint.hpp"
//상훈짱 begin //sanghoon begin
#include <windows.h> #include <windows.h>
#include <ddraw.h> #include <ddraw.h>
#include <d3d.h> #include <d3d.h>
#include <GameOS\render.hpp> #include <GameOS\render.hpp>
extern char AssetsDirectory1[MAX_PATH]; extern char AssetsDirectory1[MAX_PATH];
//상훈짱 end //sanghoon end
const Stuff::Time SHOT_TIME = 2.0; const Stuff::Time SHOT_TIME = 2.0;
@@ -37,7 +37,7 @@ HUDMap::HUDMap():
AddTexture ("hud\\map",0,28,28,228,228); AddTexture ("hud\\map",0,28,28,228,228);
else{ else{
AddTexture (model->m_HudMap,0,0,0,255,255); AddTexture (model->m_HudMap,0,0,0,255,255);
//상훈 앞 //sanghoon begin
radar_device.MapDrawn=false; radar_device.MapDrawn=false;
/* /*
if(hsh_initialized){ if(hsh_initialized){
@@ -49,7 +49,7 @@ HUDMap::HUDMap():
radar_device.MapDrawn=true; radar_device.MapDrawn=true;
} }
*/ */
//상훈 뒤 //sanghoon end
} }
Location (Point3D (301,399,0.9f)); Location (Point3D (301,399,0.9f));
@@ -154,7 +154,7 @@ void HUDMap::DrawImplementation(void)
Point3D loc,size; Point3D loc,size;
int i; int i;
//맵을 그린다. //Draw the map.
Vehicle *vehicle = m_Vehicle.GetCurrent(); Vehicle *vehicle = m_Vehicle.GetCurrent();
loc = Location (); loc = Location ();
@@ -163,7 +163,7 @@ void HUDMap::DrawImplementation(void)
// loc.y -= (size.y/2.0f); // loc.y -= (size.y/2.0f);
m_Textures[0]->Draw (loc,size,MakeColor (255,255,255,255),HUDTexture::NO_FLIP,true); m_Textures[0]->Draw (loc,size,MakeColor (255,255,255,255),HUDTexture::NO_FLIP,true);
//Torso Sweep(파이모양 시야각 표시도형)을 표시한다. //Display Torso Sweep (pie-shaped field-of-view indicator).
if (NULL == vehicle) if (NULL == vehicle)
return; return;
@@ -214,7 +214,7 @@ void HUDMap::DrawImplementation(void)
//Draw Radar Blips //Draw Radar Blips
//레이다의 오브젝트들을 표시한다. //Display radar objects.
MWObject *current_object; MWObject *current_object;
for(i=0;i<vehicle->GetSensor()->numberOfContacts;i++) for(i=0;i<vehicle->GetSensor()->numberOfContacts;i++)
@@ -332,7 +332,7 @@ void HUDMap::DrawImplementation(void)
color = MakeColor (255,255,255,250); color = MakeColor (255,255,255,250);
m_Textures[id+20]->Draw (Point3D (object_display_pos.x,object_display_pos.y,0.9f),size,color,HUDTexture::NO_FLIP,true); m_Textures[id+20]->Draw (Point3D (object_display_pos.x,object_display_pos.y,0.9f),size,color,HUDTexture::NO_FLIP,true);
} }
//작전 범위(Boundary) 표시 다각형(주황빨강) //Operation boundary display polygon (orange-red)
size = Size (); size = Size ();
loc = Location (); loc = Location ();
Mission *miss; Mission *miss;
+2 -2
View File
@@ -34,9 +34,9 @@ namespace MechWarrior4
void DrawImplementation(void); void DrawImplementation(void);
void ConvertMapCoords (float& x,float& y); void ConvertMapCoords (float& x,float& y);
void ConvertMapCoords (Point3D& pt); void ConvertMapCoords (Point3D& pt);
//상훈 앞 //sanghoon begin
bool hsh_fdraw; bool hsh_fdraw;
//상훈 뒤 //sanghoon end
public: public:
HUDMap(); HUDMap();
+5 -5
View File
@@ -90,7 +90,7 @@ get_score:
HUDScore::HUDScore() HUDScore::HUDScore()
{ {
m_AnimTime = 0; m_AnimTime = 0;
//상훈 //sanghoon
Location (Point3D (0,0,0.9f)); Location (Point3D (0,0,0.9f));
// Location (Point3D (200,100,0.9f)); // Location (Point3D (200,100,0.9f));
Size (Point3D (310,300,0.9f)); Size (Point3D (310,300,0.9f));
@@ -128,7 +128,7 @@ HUDScore::HUDScore()
m_PingHeader = new HUDText (); m_PingHeader = new HUDText ();
m_PingHeader ->SetAsAlt(); m_PingHeader ->SetAsAlt();
//상훈 //sanghoon
/* /*
m_PingHeader->Justification (HUDText::LEFT_ALIGN); m_PingHeader->Justification (HUDText::LEFT_ALIGN);
m_PingHeader->UpdateText (app->GetLocString (IDS_PINGHEADER)); m_PingHeader->UpdateText (app->GetLocString (IDS_PINGHEADER));
@@ -444,7 +444,7 @@ void HUDScore::DrawImplementation(void)
m_TimeLeftText->UpdateText (text); m_TimeLeftText->UpdateText (text);
} }
//상훈 //sanghoon
count+=1; count+=1;
loc = Location (); loc = Location ();
loc.y=600-count*LINE_HEIGHT; loc.y=600-count*LINE_HEIGHT;
@@ -455,7 +455,7 @@ void HUDScore::DrawImplementation(void)
DWORD bcolor = BrighterColor (Color ()); DWORD bcolor = BrighterColor (Color ());
//상훈.. //sanghoon
{ {
Stuff::Point3D loc2(800-size.x,600-LINE_HEIGHT-1,0.9f); Stuff::Point3D loc2(800-size.x,600-LINE_HEIGHT-1,0.9f);
LDrawRect (loc2,0,0,size.x,LINE_HEIGHT,MakeColor (0,150,0,128)); LDrawRect (loc2,0,0,size.x,LINE_HEIGHT,MakeColor (0,150,0,128));
@@ -481,7 +481,7 @@ void HUDScore::DrawImplementation(void)
m_PlayerTitle->Draw (Point3D (loc.x+10,yvalue,0.9f)); m_PlayerTitle->Draw (Point3D (loc.x+10,yvalue,0.9f));
DWORD h; DWORD h;
//상훈 //sanghoon
//m_PingHeader->DrawSize (pingwidth,h); //m_PingHeader->DrawSize (pingwidth,h);
//pingx = loc.x + size.x - pingwidth - 10; //pingx = loc.x + size.x - pingwidth - 10;
pingx = loc.x + size.x ; pingx = loc.x + size.x ;
+2 -2
View File
@@ -367,10 +367,10 @@ void HUDReticle::DrawImplementation(void)
m_Textures[36]->Draw (loc,size,m_LeftCenterColor); m_Textures[36]->Draw (loc,size,m_LeftCenterColor);
m_Textures[37]->Draw (loc,size,m_RightCenterColor); m_Textures[37]->Draw (loc,size,m_RightCenterColor);
for (i=0;i<3;i++)//상훈 원래 6이었음 for (i=0;i<3;i++)//sanghoon: originally 6
{ {
size = m_Textures[20+i]->Size (); size = m_Textures[20+i]->Size ();
//CanHit Hudweapon에서 set한다... //CanHit is set in Hudweapon...
if (m_Weapons->CanHit (i)) if (m_Weapons->CanHit (i))
color = MakeColor (0,255,0,255); color = MakeColor (0,255,0,255);
else { else {
+13 -13
View File
@@ -15,14 +15,14 @@ static float RECOVER_FROM_JAMMING_TIME = 5.0f;
// MSL 5.03 Ammo Bay Fire // MSL 5.03 Ammo Bay Fire
static float TIME_AMMO_BAY_FIRE = 7.0f; static float TIME_AMMO_BAY_FIRE = 7.0f;
//상훈짱 begin //sanghoon begin
#include <windows.h> #include <windows.h>
#include <ddraw.h> #include <ddraw.h>
#include <d3d.h> #include <d3d.h>
#include <GameOS\render.hpp> #include <GameOS\render.hpp>
extern bool g_bNoWeaponRangeCheck; extern bool g_bNoWeaponRangeCheck;
//상훈짱 end //sanghoon end
static void MakeStringCaps(char* buffer) static void MakeStringCaps(char* buffer)
{ {
@@ -555,7 +555,7 @@ if(mfd_device.BeginChannel(4))
int rh=25;//row_height int rh=25;//row_height
//16개의 row를 가질수 있는것으로 가정한다.(row포함) //Assumes up to 16 rows (including header row).
// background boxes // background boxes
mfd_device.DrawQuad(0+lm,0+tm,96+lm,(totalcount+1)*rh+10+tm,0xFF404040); mfd_device.DrawQuad(0+lm,0+tm,96+lm,(totalcount+1)*rh+10+tm,0xFF404040);
@@ -609,13 +609,13 @@ if(mfd_device.BeginChannel(4))
DWORD hsh_color1=0,hsh_color2=0; DWORD hsh_color1=0,hsh_color2=0;
//무기 발사가능 상태: 각각의 색상에 대해 정확히 정의 할것. //Weapon fire-ready status: define exact color for each state.
//정상(타겟안에 있음)(발사가능) 0xFFFFFFFF //Normal (target in range)(can fire) 0xFFFFFFFF
//정상(타겟밖에 있음)(발사가능) 0xFFFFFFFF //Normal (target out of range)(can fire) 0xFFFFFFFF
//로딩중(발사 불가) 0xFFA0A0A0 //Reloading (cannot fire) 0xFFA0A0A0
//탄알이 떨어짐(발사불가) 0xFF808080 //Out of ammo (cannot fire) 0xFF808080
//고장남(발사불가) 0xFF606060 //Destroyed (cannot fire) 0xFF606060
DWORD nameheight=30; DWORD nameheight=30;
int top=5+(weapony+1)*rh; int top=5+(weapony+1)*rh;
int bottom = top+rh; int bottom = top+rh;
@@ -694,7 +694,7 @@ if(mfd_device.BeginChannel(4))
char *weapon_string[3]={"1","2","3"}; char *weapon_string[3]={"1","2","3"};
//해당 무기의 그룹의 상태를 표시한다. //Display the status of the weapon group.
for(int i=0;i<3;i++){ for(int i=0;i<3;i++){
DWORD weapon_color=weapon_flag[i]?normal_color:nogroup_color; DWORD weapon_color=weapon_flag[i]?normal_color:nogroup_color;
// MSL 5.00 Added Ammocount check, if = 0 then weapon name same as ammo nogroup_color // MSL 5.00 Added Ammocount check, if = 0 then weapon name same as ammo nogroup_color
@@ -707,7 +707,7 @@ if(mfd_device.BeginChannel(4))
Point3D numsize = m_Textures[20]->Size (); Point3D numsize = m_Textures[20]->Size ();
//무기 이름을 표시한다. //Display weapon name.
// MSL 5.00 Added Ammocount check, if = 0 then weapon name same as ammo out_color // MSL 5.00 Added Ammocount check, if = 0 then weapon name same as ammo out_color
switch (weapon->m_status) switch (weapon->m_status)
{ {
@@ -786,7 +786,7 @@ if(mfd_device.BeginChannel(4))
} }
} }
//현재 엔터키로 발사되는 선택된 무기에 대해서 프레임을 표시한다. //Display frame for the selected weapon currently fired with Enter.
if (weapon->m_weapon == m_SingleFire.GetCurrent ()){ if (weapon->m_weapon == m_SingleFire.GetCurrent ()){
mfd_device.DrawFrame(155+lm,top+1+tm,545+lm,bottom-1+tm,0xFFFFFFFF); mfd_device.DrawFrame(155+lm,top+1+tm,545+lm,bottom-1+tm,0xFFFFFFFF);
} }
@@ -795,7 +795,7 @@ if(mfd_device.BeginChannel(4))
if ((ammocount > -1) && (weapon->m_status != 2)){ if ((ammocount > -1) && (weapon->m_status != 2)){
mfd_device.pFont[0].DrawText(615-5+lm,center+tm,ammocount_color,text,TEXTALIGN_VCENTER|TEXTALIGN_RIGHT); mfd_device.pFont[0].DrawText(615-5+lm,center+tm,ammocount_color,text,TEXTALIGN_VCENTER|TEXTALIGN_RIGHT);
}else if (ammocount == -1){ }else if (ammocount == -1){
//무기수가 제한이 없는 무기의 종류에는 '-'를 표시한다. //Display '-' for weapon types with unlimited ammo.
mfd_device.pFont[0].DrawText(615-5+lm,center+tm,ammocount_color,"-",TEXTALIGN_VCENTER|TEXTALIGN_RIGHT); mfd_device.pFont[0].DrawText(615-5+lm,center+tm,ammocount_color,"-",TEXTALIGN_VCENTER|TEXTALIGN_RIGHT);
} }
weapony ++; weapony ++;
+46 -46
View File
@@ -1008,27 +1008,27 @@ const char* ArmorZoneStr(int nArmorZone)
case Adept::DamageObject::NullArmorZone: case Adept::DamageObject::NullArmorZone:
return "()"; return "()";
case Adept::DamageObject::LeftLegArmorZone: case Adept::DamageObject::LeftLegArmorZone:
return "왼발"; return "Left Leg";
case Adept::DamageObject::RightLegArmorZone: case Adept::DamageObject::RightLegArmorZone:
return "오른발"; return "Right Leg";
case Adept::DamageObject::LeftArmArmorZone: case Adept::DamageObject::LeftArmArmorZone:
return "왼팔"; return "Left Arm";
case Adept::DamageObject::RightArmArmorZone: case Adept::DamageObject::RightArmArmorZone:
return "오른팔"; return "Right Arm";
case Adept::DamageObject::RightTorsoArmorZone: case Adept::DamageObject::RightTorsoArmorZone:
return "우측"; return "Right Torso";
case Adept::DamageObject::LeftTorsoArmorZone: case Adept::DamageObject::LeftTorsoArmorZone:
return "좌측"; return "Left Torso";
case Adept::DamageObject::CenterTorsoArmorZone: case Adept::DamageObject::CenterTorsoArmorZone:
return "전면"; return "Front";
case Adept::DamageObject::CenterRearTorsoArmorZone: case Adept::DamageObject::CenterRearTorsoArmorZone:
return "후면"; return "Rear";
case Adept::DamageObject::HeadArmorZone: case Adept::DamageObject::HeadArmorZone:
return "머리"; return "Head";
case Adept::DamageObject::SpecialArmorZone1: case Adept::DamageObject::SpecialArmorZone1:
return "보조장치1"; return "Aux Device 1";
case Adept::DamageObject::SpecialArmorZone2: case Adept::DamageObject::SpecialArmorZone2:
return "보조장치2"; return "Aux Device 2";
case Adept::DamageObject::DefaultArmorZone: case Adept::DamageObject::DefaultArmorZone:
return "Default"; return "Default";
} }
@@ -1990,83 +1990,83 @@ public:
static SMSGFMT s_aKill[20][2] = { static SMSGFMT s_aKill[20][2] = {
{ {
{ "%s's %s destroys %s's %s!", 0 }, // ok! { "%s's %s destroys %s's %s!", 0 }, // ok!
{ "%s %s, %s의 %s을(를) 파괴하다!", 0 }, // ok! { "%s's %s destroyed %s's %s!", 0 }, // ok!
}, },
{ {
{ "%s's %s explodes in a fire-ball, thanks to %s.", 1 }, // ok! { "%s's %s explodes in a fire-ball, thanks to %s.", 1 }, // ok!
{ "%s %s, 각 기관부의 화염으로 폭발! %s의 절묘한 공격성공!", 1 }, // ok! { "%s's %s explodes in flames! %s lands a perfect hit!", 1 }, // ok!
}, },
{ {
{ "%s delivers the last blow as %s's %s explodes in flames!", 2 }, // ok! { "%s delivers the last blow as %s's %s explodes in flames!", 2 }, // ok!
{ "%s %s %s!", 2 - 100}, // ok! { "%s took a hit to %s's %s!", 2 - 100}, // ok!
}, },
{ {
{ "Smoking wreckage is all that's left of %s's %s after %s delivers the fatal blow!", 1 }, { "Smoking wreckage is all that's left of %s's %s after %s delivers the fatal blow!", 1 },
{ "%s의 무자비한 공격으로 %s의 %s 불타는 잔해만 남길 것이다.", 2 }, // ok! { "%s's merciless assault leaves only burning wreckage of %s's %s.", 2 }, // ok!
}, },
{ {
{ "Glorious victory goes to %s as the wreckage from %s's %s lies burning on the battlefield!", 2 }, { "Glorious victory goes to %s as the wreckage from %s's %s lies burning on the battlefield!", 2 },
{ "전황은 급속도로 진전, %s의 생존가능성은 0%%!", 8 }, // ok! { "The battle escalates rapidly - %s's survival probability is 0%%!", 8 }, // ok!
}, },
{ {
{ "%s's %s is put out of it's misery by a devastating shot from %s.", 1 }, { "%s's %s is put out of it's misery by a devastating shot from %s.", 1 },
{ "%s의 압도적인 화력 앞에 %s 처참히 무너지고 있다.", 4 }, // ok! { "Under %s's overwhelming firepower, %s crumbles miserably.", 4 }, // ok!
}, },
{ {
{ "%s racks up another kill marker from reducing %s's %s to rubble!", 2 }, { "%s racks up another kill marker from reducing %s's %s to rubble!", 2 },
{ "%s %s의 %s을(를) 때려 눕히고, 새로운 킬마크를 얻었다.", 2 }, // ok! { "%s knocked out %s's %s and earned a new kill mark.", 2 }, // ok!
}, },
{ {
{ "Fresh paint is applied to %s's %s to mark the destruction of %s's %s!", 0 }, // ok! { "Fresh paint is applied to %s's %s to mark the destruction of %s's %s!", 0 }, // ok!
{ "%s는 %s를 격추한 킬마크를 %s에 추가했다.", 0 - 100 }, { "%s added a kill mark on %s for shooting down %s.", 0 - 100 },
}, },
{ {
{ "The burning wreckage of %s's %s is a reminder to all of the prowess of %s's battle skills!", 1 }, { "The burning wreckage of %s's %s is a reminder to all of the prowess of %s's battle skills!", 1 },
{ "%s의 잔해는 %s이(가) 가져갈 승리의 기념품이 될것이다.", 7 }, // ok! { "The wreckage of %s will be %s's trophy of victory.", 7 }, // ok!
}, },
{ {
{ "The thunderous explosion of %s's %s is music to the ears of %s!", 1 }, { "The thunderous explosion of %s's %s is music to the ears of %s!", 1 },
{ "%s의 귀에 들려오는 죽음의 전주곡. 지휘자는 %s.", 7 }, // ok! { "A death prelude echoes in %s's ears. The conductor: %s.", 7 }, // ok!
}, },
{ {
{ "%s's %s is destroyed by %s's %s.", 3 }, { "%s's %s is destroyed by %s's %s.", 3 },
{ "%s' %s, %s %s에게 파괴되었다.", 3 }, // ok! { "%s's %s was destroyed by %s's %s.", 3 }, // ok!
}, },
{ {
{ "%s brings the four horseman of the apocalypse down upon %s.", 4 }, { "%s brings the four horseman of the apocalypse down upon %s.", 4 },
{ "%s(이)가 휘두르는 심판의 추가 %s에게 작렬했다.", 4 }, // ok! { "The pendulum of judgment swung by %s strikes %s.", 4 }, // ok!
}, },
{ {
{ "%s's life flashes as %s reduces the %s to a burning wreck.", 5 }, { "%s's life flashes as %s reduces the %s to a burning wreck.", 5 },
{ "%s의 마지막 생명줄에, %s !", 7 - 100 }, // ok! { "On %s's last lifeline, %s!", 7 - 100 }, // ok!
}, },
{ {
{ "%s is deafened by the resounding roar of the exploding %s, thanks to %s.", 1 }, { "%s is deafened by the resounding roar of the exploding %s, thanks to %s.", 1 },
{ "%s 기체의 폭발소리와 함께, 저 하늘로 날아갔다. %s에게 영광을!", 7 }, // ok! { "%s's mech explodes skyward. Glory to %s!", 7 }, // ok!
}, },
{ {
{ "A kill marker is placed on %s's %s to mark the victory over %s.", 6 }, { "A kill marker is placed on %s's %s to mark the victory over %s.", 6 },
{ "%s의 %s에 새로운 킬마크를 추가해야 할 듯, 희생자는 %s", 6 }, // ok! { "A new kill mark should be added to %s's %s, victim: %s", 6 }, // ok!
}, },
{ {
{ "%s is delivered unto the inferno with regards from %s.", 7 }, { "%s is delivered unto the inferno with regards from %s.", 7 },
{ "%s, %s의 호위하에 지옥으로 향했다. %s에게 명복을!", 9 }, // ok! { "%s headed to hell under %s's escort. Rest in peace, %s!", 9 }, // ok!
}, },
{ {
{ "Another kill marker is given up by %s, as %s celebrates victory.", 7 }, { "Another kill marker is given up by %s, as %s celebrates victory.", 7 },
{ "%s, %s의 새로운 킬 마크가 되었다. 영원한 안식을…", 7 - 100 }, { "%s became %s's new kill mark. Rest in peace...", 7 - 100 },
}, },
{ {
{ "Best wishes in the afterlife are presented to %s from %s.", 7 }, { "Best wishes in the afterlife are presented to %s from %s.", 7 },
{ "%s에게 남은 것은 오직 %s에 대한 복수뿐!", 7 }, // ok! { "All that remains for %s is revenge against %s!", 7 }, // ok!
}, },
{ {
{ "Tragedy strikes %s as %s guns the %s down.", 5 }, { "Tragedy strikes %s as %s guns the %s down.", 5 },
{ "%s 모든 화력을 동원해 %s %s을(를) 파괴했다.", 2 }, // ok! { "%s brought all firepower to bear and destroyed %s's %s.", 2 }, // ok!
}, },
{ {
{ "%s earns the revenge of %s after the tragic destruction of the %s.", 2 }, { "%s earns the revenge of %s after the tragic destruction of the %s.", 2 },
{ "%s의 비극적인 최후! %s 절망하는 %s을(를) 지켜볼 뿐이다.", 9 }, // ok! { "A tragic end for %s! %s can only watch %s in despair.", 9 }, // ok!
}, },
}; };
@@ -2077,11 +2077,11 @@ static SMSGFMT s_aKill[20][2] = {
static SMSGFMT s_aSuicide[2][2] = { static SMSGFMT s_aSuicide[2][2] = {
{ {
{ "%s leaves the battlefield in disgrace after causing the destruction of the %s.", 0 }, { "%s leaves the battlefield in disgrace after causing the destruction of the %s.", 0 },
{ "%s 자폭! %s 불명예스럽게 전장을 떠났다!", 2 }, { "%s self-destructed! %s left the battlefield in disgrace!", 2 },
}, },
{ {
{ "%s will not grace the halls of the honored mechwarriors after self-destructing the %s.", 0 }, { "%s will not grace the halls of the honored mechwarriors after self-destructing the %s.", 0 },
{ "%s 자폭! 비겁자여, 진실로 승리를 원하는가?", 3 }, { "%s self-destructed! Coward, do you truly desire victory?", 3 },
}, },
}; };
@@ -2106,43 +2106,43 @@ static SMSGFMT s_aSuicide[2][2] = {
static SMSGFMT s_aShot[10][2] = { static SMSGFMT s_aShot[10][2] = {
{ {
{ "%s's %s fires the %s and damages the %s of %s's %s.", 0 }, { "%s's %s fires the %s and damages the %s of %s's %s.", 0 },
{ "%s %s의 %s에 %s으로 공격했다", 1 }, // ok! { "%s attacked %s's %s with %s", 1 }, // ok!
}, },
{ {
{ "%s fires the %s's %s and decimates the %s of %s's %s.", 2 }, { "%s fires the %s's %s and decimates the %s of %s's %s.", 2 },
{ "%s이(가) 탑승한 %s, %s %s이(가) 탑승한 %s %s에 피해를 입혔다.", 2 }, { "%s piloting %s damaged %s's %s on %s's %s.", 2 },
}, },
{ {
{ "%s's %s takes a devastating hit in the %s from %s.", 3 }, { "%s's %s takes a devastating hit in the %s from %s.", 3 },
{ "%s %s, %s의 압도적인 공격에 %s에 피해를 입었다.", 4 }, // ok! { "%s's %s took damage to the %s under %s's overwhelming attack.", 4 }, // ok!
}, },
{ {
{ "%s's %s suffers a direct hit to it's %s from %s's %s.", 5 }, { "%s's %s suffers a direct hit to it's %s from %s's %s.", 5 },
{ "%s %s은(는) %s %s에 직접적인 피해를 받았다. 피해 %s!", 6 -100}, { "%s's %s took direct damage from %s's %s. Damage: %s!", 6 -100},
}, },
{ {
{ "%s damages %s's %s.", 7 }, { "%s damages %s's %s.", 7 },
{ "%s, %s %s에 피해를 입혔다..", 7 }, // ok! { "%s dealt damage to %s's %s..", 7 }, // ok!
}, },
{ {
{ "Dense black smoke pours from %s's %s as a result of %s's targeted hit.", 8 }, { "Dense black smoke pours from %s's %s as a result of %s's targeted hit.", 8 },
{ "%s의 절묘한 공격으로 %s %s에서 검은 연기가 퍼지고 있다.", 7 }, // ok! { "Black smoke billows from %s's %s from %s's precise attack.", 7 }, // ok!
}, },
{ {
{ "Fire boils from the damaged %s of %s's %s after %s hits it with a %s.", 9 }, { "Fire boils from the damaged %s of %s's %s after %s hits it with a %s.", 9 },
{ "%s %s을(를) 발사하여, %s이(가) 탑승한 %s %s에 피해를 발생시켰다.", 10 }, // ok! { "%s fired %s, dealing damage to the %s of %s's %s.", 10 }, // ok!
}, },
{ {
{ "Smoke and fire are trailing from %s's %s, all results of the %s blast inflicted by %s.", 11 }, { "Smoke and fire are trailing from %s's %s, all results of the %s blast inflicted by %s.", 11 },
{ "%s의 %s 공격에, 불과 연기가 %s의 기체를 뒤덮고 있다.", 15 }, // ok! { "Fire and smoke engulf %s's mech from %s's %s attack.", 15 }, // ok!
}, },
{ {
{ "%s targets and fires the %s; %s cries in dismay as the %s's %s is damaged.", 10 }, { "%s targets and fires the %s; %s cries in dismay as the %s's %s is damaged.", 10 },
{ "%s %s을(를) 조준하여 %s이(가) 탑승한 %s %s에 맞춘 후 방아쇠를 당겼다.", 10 }, // ok! { "%s aimed %s and pulled the trigger, hitting the %s of %s's %s.", 10 }, // ok!
}, },
{ {
{ "%s takes a severe wound to the %s as %s aims for the %s again.", 13 }, { "%s takes a severe wound to the %s as %s aims for the %s again.", 13 },
{ "%s 다시 %s %s을(를) 조준하여 사격했다. %s, %s에 심각한 피해를 입은 듯.", 14 -100}, { "%s aimed again at %s's %s and fired. %s seems to have taken serious damage to %s.", 14 -100},
}, },
}; };
@@ -2150,19 +2150,19 @@ static SMSGFMT s_aShot[10][2] = {
static SMSGFMT s_aCTF[1][2] = { static SMSGFMT s_aCTF[1][2] = {
{ {
{ "%s captured flag.", 0 }, { "%s captured flag.", 0 },
{ "%s, 깃발 획득!.", 0 }, { "%s captured the flag!", 0 },
}, },
}; };
static SMSGFMT s_aFBK[1][2] = { static SMSGFMT s_aFBK[1][2] = {
{ {
{ "%s destroyed friendly building.", 0 }, { "%s destroyed friendly building.", 0 },
{ "%s, 깃발 획득!.", 0 }, { "%s captured the flag!", 0 },
}, },
}; };
static SMSGFMT s_aEBK[1][2] = { static SMSGFMT s_aEBK[1][2] = {
{ {
{ "%s destroyed enemy building.", 0 }, { "%s destroyed enemy building.", 0 },
{ "%s, 깃발 획득!.", 0 }, { "%s captured the flag!", 0 },
}, },
}; };
const SMSGFMT* pcFMT; const SMSGFMT* pcFMT;
@@ -1077,7 +1077,7 @@ int CStrArray::GetTotalLength() const
int nTotalLength; int nTotalLength;
int i, nSize = GetSize(); int i, nSize = GetSize();
nTotalLength = nSize; // nSize개의 '\0' nTotalLength = nSize; // nSize null terminators '\0'
for(i = 0; i < nSize; i++) { for(i = 0; i < nSize; i++) {
nTotalLength += strlen(GetAt(i)); nTotalLength += strlen(GetAt(i));
} }
@@ -2,7 +2,7 @@
#include<Windows.h> #include<Windows.h>
// //
//Do not use .\EulaTest\\1.0 as the key for your game; use your game name and version instead //Do not use ....\EulaTest\\1.0 as the key for your game; use your game name and version instead...
// PLEASE NOTE: do not place backslashes on beginning or end of regkey. // PLEASE NOTE: do not place backslashes on beginning or end of regkey.
// //
@@ -11,7 +11,7 @@
typedef DWORD (*EBUPROC) (LPCTSTR lpRegKeyLocation, LPCTSTR lpEULAFileName, LPCSTR lpWarrantyFileName, BOOL fCheckForFirstRun); typedef DWORD (*EBUPROC) (LPCTSTR lpRegKeyLocation, LPCTSTR lpEULAFileName, LPCSTR lpWarrantyFileName, BOOL fCheckForFirstRun);
// //
//The game applications .RC file should define strings for the EULA and WARRANTY pathnames //The game application's .RC file should define strings for the EULA and WARRANTY pathnames...
// //
@@ -28,13 +28,13 @@ bool FirstRunEula(const char *eula_filename,const char *warranty_filename)
if (NULL == hMod) if (NULL == hMod)
hMod = LoadLibrary("EBUEula.dll"); hMod = LoadLibrary("EBUEula.dll");
if (NULL == hMod) // cant attach to DLL if (NULL == hMod) // can't attach to DLL
{ {
STOP(("Cannot Load EBUEula.dll")); STOP(("Cannot Load EBUEula.dll"));
} }
pfnEBUEula = (EBUPROC) GetProcAddress(hMod, "EBUEula"); pfnEBUEula = (EBUPROC) GetProcAddress(hMod, "EBUEula");
if (NULL == pfnEBUEula) // cant find entry point if (NULL == pfnEBUEula) // can't find entry point
{ {
FreeLibrary(hMod); FreeLibrary(hMod);
STOP(("Cannot Find Entry Point to EBUEula.dll")); STOP(("Cannot Find Entry Point to EBUEula.dll"));
@@ -43,9 +43,9 @@ bool FirstRunEula(const char *eula_filename,const char *warranty_filename)
// //
//This call enables both EULA and warranty accepting/viewing/printing. If your //This call enables both EULA and warranty accepting/viewing/printing. If your
//game doesnt ship with a WARRANTY file, specifiy NULL instead of szWarranty //game doesn't ship with a WARRANTY file, specifiy NULL instead of szWarranty...
//The code below, for instance, works with both OEM and retail builds //The code below, for instance, works with both OEM and retail builds...
// //
const char *pszWarrantyParam = 0xFFFFFFFF != GetFileAttributes(warranty_filename) ? warranty_filename : NULL; const char *pszWarrantyParam = 0xFFFFFFFF != GetFileAttributes(warranty_filename) ? warranty_filename : NULL;
@@ -16,6 +16,7 @@
#include "MW4AppHeaders.hpp" #include "MW4AppHeaders.hpp"
#include "MW4Application.hpp" #include "MW4Application.hpp"
#include <windows.h> #include <windows.h>
#include <stdio.h> // [help] FILE/fopen/fprintf used by MW4_ShowCommandLineHelp
#include <MW4DedicatedUI\DedicatedUI.hpp> #include <MW4DedicatedUI\DedicatedUI.hpp>
#include <GameOS\GameOS.hpp> #include <GameOS\GameOS.hpp>
#include <GameOS\Platform.hpp> #include <GameOS\Platform.hpp>
@@ -85,9 +86,18 @@ extern Time g_PlasmaClearTime;
extern Time g_TOC_ADT; extern Time g_TOC_ADT;
extern Time g_AUX_ADT; extern Time g_AUX_ADT;
extern bool g_UseMSRSP; extern bool g_UseMSRSP;
extern int g_nTypeOfMFDs; // 0 - no MFDs, 1 - orginal(5+1=dual & single), 2 - B&W(3 + 1=1 dual), 3 - color(3 + 1=2 dual) extern int g_nTypeOfMFDs; // 0 - no MFDs, 1 - orginal(5+1=dual & single), 2 - B&W(3 + 1=1 dual), 3 - color(3 + 1=2 dual), 4 - split dual 640x480
// [tmon] Display-device override in Main/Radar/MFD1/MFD2 order; -1 = auto-detect.
// Defined in CoreTech GameOS VideoCard.cpp and consumed by FindVideoCards().
extern int g_naMonitorOverride[4];
extern int g_nRIOType; extern int g_nRIOType;
extern DWORD g_dwRIOBaud; // [tbaud] extern DWORD g_dwRIOBaud; // [tbaud]
// [fpslog] Non-zero enables the per-second frame pacing report (gos-fps.txt).
// Defined in CoreTech GameOS WinMain.cpp.
extern int g_nFpsLog;
// [panelcoop] SetCooperativeLevel form used by the radar/MFD panels; 0 = legacy.
// Defined in CoreTech GameOS render.cpp.
extern int g_nHshCoopMode;
extern LONG g_ThrottleDir; extern LONG g_ThrottleDir;
extern bool g_bCanSuicideAllways; extern bool g_bCanSuicideAllways;
extern bool g_f3dtarget; extern bool g_f3dtarget;
@@ -190,10 +200,10 @@ int bloatSizeTable[8] = {
extern bool(__cdecl *NoCDMessageFunction)(void); extern bool(__cdecl *NoCDMessageFunction)(void);
extern bool gNoDialogs; extern bool gNoDialogs;
//상훈.. begin //sanghoon begin
extern bool use_shgui; extern bool use_shgui;
extern int SCREENS; extern int SCREENS;
//상훈.. end //sanghoon end
bool gRunEula=true; bool gRunEula=true;
bool gNoCD=false; bool gNoCD=false;
@@ -290,13 +300,13 @@ void _stdcall InitializeGameEngine()
// bool needflip=Environment.fullScreen && IsFirstRun(); // bool needflip=Environment.fullScreen && IsFirstRun();
//상훈 앞 //sanghoon begin
bool needflip=false; bool needflip=false;
//상훈 뒤 //sanghoon end
if(needflip){ if(needflip){
//상훈 앞 //sanghoon begin
//MessageBeep(MB_ICONEXCLAMATION); //MessageBeep(MB_ICONEXCLAMATION);
//상훈 뒤 //sanghoon end
EnterWindowMode(); EnterWindowMode();
} }
@@ -336,7 +346,7 @@ void _stdcall InitializeGameEngine()
{ {
//Original //Original
//page->GetEntry("videodriverindex",&Environment.FullScreenDevice); //page->GetEntry("videodriverindex",&Environment.FullScreenDevice);
//상훈 //sanghoon
Environment.FullScreenDevice=0; Environment.FullScreenDevice=0;
page->GetEntry("antialias",&Environment.AntiAlias); page->GetEntry("antialias",&Environment.AntiAlias);
page->GetEntry("bitdepth",&Environment.bitDepth); page->GetEntry("bitdepth",&Environment.bitDepth);
@@ -355,7 +365,7 @@ void _stdcall InitializeGameEngine()
//Original //Original
//page->GetEntry("HudDamageMode",&VehicleInterface::hudDamageMode); //page->GetEntry("HudDamageMode",&VehicleInterface::hudDamageMode);
//page->GetEntry("HudTargetDamageMode",&VehicleInterface::hudTargetDamageMode); //page->GetEntry("HudTargetDamageMode",&VehicleInterface::hudTargetDamageMode);
//상훈 //sanghoon
VehicleInterface::hudDamageMode=false; VehicleInterface::hudDamageMode=false;
VehicleInterface::hudTargetDamageMode=false; VehicleInterface::hudTargetDamageMode=false;
} }
@@ -816,6 +826,242 @@ GetEnvironmentVariableA(
LPSTR lpBuffer, LPSTR lpBuffer,
DWORD nSize DWORD nSize
); );
// [help] ---------------------------------------------------------------------
// Complete command-line reference, shown by "MW4.exe -help".
//
// MW4 is a GUI-subsystem application, so there is no console to print to when it
// is launched normally. -help therefore writes the full reference to
// mw4-help.txt next to the executable, opens it in Notepad, and exits without
// starting the game. If Notepad cannot be launched, a message box reports where
// the file was written.
//
// KEEP THIS IN SYNC when adding or changing a command-line switch.
static const char* const g_apszCommandLineHelp[] =
{
"BattleTech: FireStorm - MW4.exe command line reference",
"======================================================",
"",
"Usage: MW4.exe [options]",
"",
"Options may appear in any order and are case-insensitive. An option that takes",
"a value must be followed by a single space and then the value, for example:",
"",
" MW4.exe -tmfds 4 -tmon 1,2,3,4 -tbaud 115200",
"",
"Values outside the documented range are ignored and the default is kept.",
"",
"",
"DISPLAY AND VIDEO",
"-----------------",
" -window Run in a window instead of fullscreen.",
" -fullscreen Force fullscreen. Overrides -window.",
" -tmfds <0-4> MFD output mode:",
" 0 = no MFDs",
" 1 = original 1280x480 span (5 channels + radar)",
" 2 = black and white (3 channels + 1 dual)",
" 3 = colour (3 channels + 2 dual)",
" 4 = split dual 640x480 - drives two independent",
" MFD monitors, so no span hardware is needed",
" -tmon <m>,<r>,<f1>,<f2> Hard-assign display devices in the order",
" main, radar, MFD1, MFD2. Values are 1-based; a",
" value of 0 leaves that slot auto-detected.",
" Separators may be ',' '/' or ':'.",
" MFD1 and MFD2 only apply with -tmfds 4.",
" Example: -tmon 1,2,4,3 swaps the two MFD panels.",
" -tcoop <0-5> How the radar/MFD panels claim their displays.",
" 0 = legacy single call (as shipped; works on XP",
" and under dgVoodoo2, fails on Windows 10).",
" 1 = drop SETFOCUSWINDOW, let DirectDraw create",
" the device window.",
" 2 = SETFOCUSWINDOW first, then CREATEDEVICEWINDOW.",
" 3 = SETFOCUSWINDOW first, then EXCLUSIVE only,",
" matching what the main display already does.",
" 4 = EXCLUSIVE|FULLSCREEN only. The main display",
" has already set the focus window, so the",
" panels never contend for it.",
" 5 = as 4, plus ALLOWREBOOT.",
" Results are reported in gos-displays.txt.",
" -mechview <1|2> Show the rotating mech view. 1 = on the radar",
" -mv <1|2> screen, 2 = on the main screen. Default: off.",
" -3dt Draw the MFD target as a live 3D model instead of",
" the pre-rendered 2D bitmaps.",
" -capdev <0-7> Select which device screen captures come from:",
" 0 main, 1 radar, 2 mission review, 3 hudchat,",
" 4 nav, 5 weapon, 6 target, 7 armor",
"",
"",
"AUDIO AND PLASMA DISPLAY",
"------------------------",
" -nosound Disable all sound output.",
" -noplasma Disable the COM2 plasma score display.",
" -pctime <seconds> Plasma display clear time. Minimum 3.",
"",
"",
"POD HARDWARE AND ARCADE (CTCL)",
"------------------------------",
" -ctcltype <1-3> CTCL role for this machine:",
" -ctcl <1-3> 1 = console, 2 = game pod, 3 = cameraship.",
" Default when absent: console.",
" -dragon Disable CTCL entirely and run standalone.",
" -coop Co-operative arcade mode. Implies 1 coin per game",
" and the game-pod role.",
" -#coop <coins> Co-op with an explicit coin count. A negative",
" value selects the cameraship role instead.",
" -trio <0|1> RIO cockpit board protocol. 0 = original board,",
" 1 = newer protocol (different framing and acks).",
" -tbaud <9600-921600> Force the COM1 baud rate for the RIO board. Use",
" for replica boards with a high-speed UART. The",
" wire protocol is unchanged; only the rate differs.",
" -useorgjoy Use the original joystick axis mapping.",
" -ojoy Same as -useorgjoy.",
" -usetockeys Enable TOC keys. They are disabled by default.",
" -tocadt <seconds> TOC auto-detect timeout. Minimum 5.",
" -auxadt <seconds> AUX auto-detect timeout. Minimum 3.",
" -usecam Force camera mode. Implied by the cameraship role.",
" -suicide Allow self-destruct at any time.",
" -jpd Enable JPD input handling.",
"",
"",
"ZOOM AND FIELD OF VIEW",
"----------------------",
" -zmfova <0.01-0.5> Zoom field-of-view, stage A.",
" -zmfovb <0.01-0.5> Zoom field-of-view, stage B. A and B are swapped",
" automatically so that A is the wider of the two.",
" -zmmrgn <0.01-0.49> Zoom left/right margin, as a fraction of width.",
" -zmtime <0, or 0.05-3.0> Zoom transition time in seconds. 0 = instant.",
"",
"",
"MULTIPLAYER AND NETWORK",
"-----------------------",
" -serve Automatically host a server game on startup.",
" -lobby Indicates the game was started from a lobby.",
" -game <file> Load the named game/mission file.",
" -gamename <name> Name advertised for the hosted game.",
" -playername <name> Player name to use.",
" -password <password> Password for the hosted or joined game.",
" -advertiseport <port> Port used to advertise the server.",
" -ipx Use IPX in the server browser.",
" -nodplay Disable DirectPlay networking.",
" -directplayprotocol Force use of the DirectPlay protocol.",
" -secure Enable secure networking for the game session.",
" -set_internet Configure network settings for internet play.",
" -set_lan Configure network settings for LAN play.",
" -win32dedicated Run as a Win32 dedicated server. Disables sound",
" and rendering and uses the dedicated server UI.",
" -allowmultiple Allow more than one instance of the game to run.",
" -oldmpui Use the older multiplayer user interface.",
"",
"",
"LOGGING AND DIAGNOSTICS",
"-----------------------",
" -zlogstyle <value> ZLog output style.",
" -zlogflush <value> ZLog flush behaviour.",
" -zlogbuffer <size> ZLog buffer size.",
" -zlogname <filename> ZLog output file name.",
" -olog Write the legacy .log match report instead of the",
" newer .rpt format.",
" -fps Write a per-second frame pacing report to",
" gos-fps.txt next to the executable: average fps,",
" 1% low, worst frame in ms, and a count of frames",
" taking over twice the average (hitches). Useful",
" for confirming smooth pacing on the MFD modes.",
" Off unless this switch is given.",
" -gamestats Save game statistics.",
" -help Show this reference and exit without starting.",
"",
"",
"DEVELOPMENT AND TEST BUILDS",
"---------------------------",
"The following are only active in LAB (Debug, Armor and Profile) builds. In a",
"Release build they are accepted and ignored.",
"",
" -build Rebuild the resource packages at startup.",
" -norun Do not run the game after building.",
" -demo Demo mode.",
" -rekey Re-key resources.",
" -bloat Enable bloat diagnostics.",
" -reportnotresourced Report assets that are not in a resource package.",
" -armorlevel <0-4> Assertion/armor checking level.",
" -leak <n> Memory trace level.",
" -diskfirst Prefer loose files on disk over packaged data.",
" -testclasses Run internal class self-tests.",
" -aistats Enable AI statistics collection.",
" -bspmap Save BSP map differences.",
" -showscripterrors Display script errors as they occur.",
" -mrtest Mission review test mode.",
" -prtest Print report test mode.",
" -nowrc Disable weapon range checking.",
" -regs Debug builds only: enable script regions.",
" -spew Debug builds only: enable script spews.",
"",
"",
"OTHER",
"-----",
" -nocd Skip the CD check. (The CD check is already",
" disabled unconditionally in this build.)",
" -noeula Skip the end user licence agreement screen.",
" -noautoconfig Skip automatic video and sound configuration.",
"",
"",
"RECOGNISED BUT INACTIVE",
"-----------------------",
" -join Parsed for compatibility but has no effect; the",
" code that consumed it is commented out.",
" -noabzug Parsed only in a disabled code path.",
"",
"",
"RELATED CONFIGURATION",
"---------------------",
"Most persistent settings live in options.ini next to MW4.exe rather than on the",
"command line. See OPTIONS-INI.md in the source repository for a full reference.",
"Arcade pod assignments live in c:\\ctcl.ini.",
NULL
};
static void MW4_ShowCommandLineHelp()
{
char szDir[MAX_PATH];
char szPath[MAX_PATH];
// Write next to the executable rather than the working directory, so the file
// is easy to find no matter how the game was launched.
szDir[0] = '\0';
GetModuleFileNameA(NULL, szDir, sizeof(szDir));
char* pSlash = strrchr(szDir, '\\');
if (pSlash)
*(pSlash + 1) = '\0';
else
szDir[0] = '\0';
sprintf(szPath, "%smw4-help.txt", szDir);
FILE* f = fopen(szPath, "wt");
if (!f)
{
MessageBoxA(NULL,
"Could not write mw4-help.txt next to MW4.exe.\n"
"Check that the folder is writable.",
"MW4 command line help", MB_OK | MB_ICONWARNING);
return;
}
for (int i = 0; g_apszCommandLineHelp[i] != NULL; i++)
fprintf(f, "%s\n", g_apszCommandLineHelp[i]);
fclose(f);
// Open it for the user. WinExec is used rather than ShellExecute to avoid a
// dependency on shellapi.h in this translation unit.
char szCmd[MAX_PATH + 32];
sprintf(szCmd, "notepad.exe \"%s\"", szPath);
if (WinExec(szCmd, SW_SHOWNORMAL) < 32)
{
char szMsg[MAX_PATH + 128];
sprintf(szMsg,
"The MW4.exe command line reference was written to:\n\n%s",
szPath);
MessageBoxA(NULL, szMsg, "MW4 command line help", MB_OK | MB_ICONINFORMATION);
}
}
void __stdcall GetGameOSEnvironment(char* CommandLine) void __stdcall GetGameOSEnvironment(char* CommandLine)
{ {
#ifdef _DEBUG #ifdef _DEBUG
@@ -1088,9 +1334,9 @@ DWORD __stdcall gos_EnableSetting( gosSetting Setting, DWORD Value );
Environment.soundDisable = (strstr(all_lower, "-nosound") != NULL); Environment.soundDisable = (strstr(all_lower, "-nosound") != NULL);
Environment.fullScreen = (strstr(all_lower, "-window") == NULL); Environment.fullScreen = (strstr(all_lower, "-window") == NULL);
//상훈짱.. begin //sanghoon begin
use_shgui=Environment.fullScreen?1:0; use_shgui=Environment.fullScreen?1:0;
//상훈짱.. end //sanghoon end
gNoAutoConfig= (strstr(all_lower, "-noautoconfig") != NULL); gNoAutoConfig= (strstr(all_lower, "-noautoconfig") != NULL);
@@ -1176,49 +1422,10 @@ DWORD __stdcall gos_EnableSetting( gosSetting Setting, DWORD Value );
#endif #endif
} }
if (strstr(all_lower, "-help")) // [help] -help is handled at the top of WinMain (see MW4_ShowCommandLineHelp),
{ // which runs before this and exits the process. The old partial list that used
SPEWALWAYS((NULL, "Command line options:\n")); // to live here was incomplete and only reached the debug log, so it was removed
SPEWALWAYS((NULL, "-allowmultiple")); // in favour of a single maintained reference.
SPEWALWAYS((NULL, "-lobby"));
SPEWALWAYS((NULL, "-game <file>"));
SPEWALWAYS((NULL, "-gamename <name>"));
SPEWALWAYS((NULL, "-playername <name>"));
SPEWALWAYS((NULL, "-serve"));
SPEWALWAYS((NULL, "-join"));
SPEWALWAYS((NULL, "-nosound"));
SPEWALWAYS((NULL, "-window"));
SPEWALWAYS((NULL, "-zlogstyle <value>"));
SPEWALWAYS((NULL, "-zlogflush <value>"));
SPEWALWAYS((NULL, "-zlogbuffer <size>"));
SPEWALWAYS((NULL, "-zlogname <filename>"));
SPEWALWAYS((NULL, "-secure"));
SPEWALWAYS((NULL, "-ipx"));
#ifdef LAB_ONLY
SPEWALWAYS((NULL, "-nodplay"));
SPEWALWAYS((NULL, "-dontuseipx"));
SPEWALWAYS((NULL, "-dontusetcp"));
SPEWALWAYS((NULL, "-dontusegamespy"));
SPEWALWAYS((NULL, "-dontusegun"));
SPEWALWAYS((NULL, "-aistats"));
SPEWALWAYS((NULL, "-oldmpui"));
SPEWALWAYS((NULL, "-testclasses"));
SPEWALWAYS((NULL, "-build"));
SPEWALWAYS((NULL, "-norun"));
SPEWALWAYS((NULL, "-demo"));
SPEWALWAYS((NULL, "-rekey"));
SPEWALWAYS((NULL, "-bloat"));
SPEWALWAYS((NULL, "-reportnotresourced"));
SPEWALWAYS((NULL, "-armorlevel <n>"));
SPEWALWAYS((NULL, "-leak <n>"));
SPEWALWAYS((NULL, "-diskfirst"));
#endif
}
if (MWApplication::AutoLaunchServerGame || MWApplication::Win32DedicatedServer) if (MWApplication::AutoLaunchServerGame || MWApplication::Win32DedicatedServer)
@@ -1294,6 +1501,14 @@ int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int n
for (p=all_lower; i>0; ++p,--i) for (p=all_lower; i>0; ++p,--i)
*p=(char)tolower(*p); *p=(char)tolower(*p);
// [help] Handle -help before anything is initialised: write the full command
// line reference next to the exe, open it, and exit without starting the game.
if (strstr(all_lower, "-help"))
{
MW4_ShowCommandLineHelp();
return 0;
}
char *token; char *token;
// jcem - begin // jcem - begin
token = strstr(all_lower, "-ctcltype "); token = strstr(all_lower, "-ctcltype ");
@@ -1440,9 +1655,37 @@ int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int n
if (token && token[7]) if (token && token[7])
{ {
int n = atoi(&token[7]); int n = atoi(&token[7]);
if ((0 <= n) && (n <= 3)) // 0 - no MFDs, 1 - orginal(5+1=dual & single), 2 - B&W(3 + 1=1 dual), 3 - color(3 + 1=2 dual) if ((0 <= n) && (n <= 4)) // 0 - no MFDs, 1 - orginal(5+1=dual & single), 2 - B&W(3 + 1=1 dual), 3 - color(3 + 1=2 dual), 4 - split dual 640x480
g_nTypeOfMFDs = n; g_nTypeOfMFDs = n;
} }
// [tmon] Hard-assign the display devices when DirectDraw enumerates them in an
// unexpected order. Syntax: -tmon <main>,<radar>,<mfd1>,<mfd2>
// Values are 1-based (the normal case is "-tmon 1,2,3,4"); a value of 0 leaves that
// slot to auto-detection, so "-tmon 2,1,0,0" only swaps main and radar. Separators
// may be ',' '/' or ':'. mfd1/mfd2 are only used by -tmfds 4.
token = strstr(all_lower, "-tmon ");
if (token)
{
const char* p = &token[6];
int slot = 0;
while (slot < 4)
{
while (*p == ' ')
p++;
if ((*p < '0') || ('9' < *p))
break;
int v = atoi(p);
while (('0' <= *p) && (*p <= '9'))
p++;
// 0 = leave auto-detected, otherwise convert 1-based to a 0-based device index
g_naMonitorOverride[slot] = (0 < v) ? (v - 1) : -1;
slot++;
if ((*p == ',') || (*p == '/') || (*p == ':'))
p++;
else
break;
}
}
token = strstr(all_lower, "-trio "); token = strstr(all_lower, "-trio ");
if (token && token[6]) if (token && token[6])
{ {
@@ -1457,6 +1700,17 @@ int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int n
if ((9600 <= n) && (n <= 921600)) if ((9600 <= n) && (n <= 921600))
g_dwRIOBaud = (DWORD)n; g_dwRIOBaud = (DWORD)n;
} }
// [panelcoop] Cooperative-level form for the radar/MFD panels. 0 = legacy combined
// call (what shipped); 1-3 are forms compatible with strict modern DirectDraw.
token = strstr(all_lower, "-tcoop ");
if (token && token[7])
{
int n = atoi(&token[7]);
if ((0 <= n) && (n <= 5))
g_nHshCoopMode = n;
}
// [fpslog] Enable the per-second frame pacing report written to gos-fps.txt.
g_nFpsLog = (strstr(all_lower, "-fps") != NULL) ? 1 : 0;
g_bCanSuicideAllways = (strstr(all_lower, "-suicide") != NULL); g_bCanSuicideAllways = (strstr(all_lower, "-suicide") != NULL);
g_f3dtarget = (strstr(all_lower, "-3dt") != NULL); g_f3dtarget = (strstr(all_lower, "-3dt") != NULL);
g_bOldLOG = (strstr(all_lower, "-olog") != NULL); g_bOldLOG = (strstr(all_lower, "-olog") != NULL);
+22 -22
View File
@@ -517,7 +517,7 @@ void CSOC_Server::OnSendFile()
BYTE bCode; BYTE bCode;
if (Disassemble("B", &bCode)) { if (Disassemble("B", &bCode)) {
ASSERT((bCode == 0) || (bCode == 3)); ASSERT((bCode == 0) || (bCode == 3));
// 받아가시오 from Game to console... // Receiving from Game to console...
SYSTEMTIME* pSysTime; SYSTEMTIME* pSysTime;
WORD wSysTimeSize; WORD wSysTimeSize;
GUID* pGUID; GUID* pGUID;
@@ -533,7 +533,7 @@ void CSOC_Server::OnSendFile()
pSF = g_pCTCLManager->m_SFM_Recv.Find(*pGUID, nType); pSF = g_pCTCLManager->m_SFM_Recv.Find(*pGUID, nType);
if (pSF) { if (pSF) {
if (bCode == 3) { if (bCode == 3) {
// 미션리뷰 서버가 mission review 받았다는 것을 받았느냐? // Did we receive confirmation the mission review server got the mission review?
pSF->m_bProcessed = true; pSF->m_bProcessed = true;
g_pCTCLManager->m_SFM_Recv.Cut(pSF); g_pCTCLManager->m_SFM_Recv.Cut(pSF);
g_pCTCLManager->m_SFM_Done.AddTail(pSF); g_pCTCLManager->m_SFM_Done.AddTail(pSF);
@@ -910,7 +910,7 @@ void CSOC_Client::OnSendFile()
BYTE bCode; BYTE bCode;
if (Disassemble("B", &bCode)) { if (Disassemble("B", &bCode)) {
ASSERT((bCode == 1) || (bCode == 2)); ASSERT((bCode == 1) || (bCode == 2));
// 받았오 from console to Game... // Received from console to Game...
SYSTEMTIME* pSysTime; SYSTEMTIME* pSysTime;
WORD wSysTimeSize; WORD wSysTimeSize;
GUID* pGUID; GUID* pGUID;
@@ -1437,21 +1437,21 @@ void CCTCLManager::Run()
#endif // !defined(CTCL_LAUNCHER) #endif // !defined(CTCL_LAUNCHER)
} else { } else {
/* /*
. Code executed for both client and server.
* *Possible states:
/ .. Before server/client role is determined: waiting for commands
(// .) (Commands such as exit/start-server/start-client may arrive.)
Running as server, waiting for server mech configuration data
(CreateSession가 .) (State after CreateSession has been called.)
Bot들에 Running as server, waiting for Bot information
( .) (Client joining happens automatically between client and server.)
Launch를 Running as server, waiting for Launch
==> . ==>Client has no waiting state as data is transferred immediately on startup.
==> . ==>Define each state and implement the appropriate handling for each.
switch(state){ switch(state){
} }
*/ */
@@ -1533,8 +1533,8 @@ void CCTCLManager::DoMech4Comm()
} }
break; break;
case 1: case 1:
//서버/클라이언트로서 실행준비하도록 명령을 전달한다. //Send command to prepare for execution as server/client.
//또한 서버를 실행하는데 필요한 모든 파라미터도 함께 전달한다. //Also transmit all parameters required to run the server.
for(i = 0; i < g_nPlayerInfos; i++) { for(i = 0; i < g_nPlayerInfos; i++) {
SPlayerInfo& pi = g_aPlayerInfos[i]; SPlayerInfo& pi = g_aPlayerInfos[i];
if (!pi.m_bBot) { if (!pi.m_bBot) {
@@ -1561,12 +1561,12 @@ void CCTCLManager::DoMech4Comm()
} }
} }
if (i == g_nPlayerInfos) { if (i == g_nPlayerInfos) {
// Bot들에 대한 정보를 모두 한데 묶어서 보낸다. // Bundle and send all Bot information together.
CPacket pak(&SVR.GetGameSOC()); CPacket pak(&SVR.GetGameSOC());
pak.Assemble("B", C_BOTS); pak.Assemble("B", C_BOTS);
for(i = 0; i < g_nPlayerInfos; i++) { for(i = 0; i < g_nPlayerInfos; i++) {
if (i != g_nServer) { // 원래 Bot만 지금은 서버를 제외한 전부... if (i != g_nServer) { // Originally bots only; now everyone except the server...
SPlayerInfo& pi = g_aPlayerInfos[i]; SPlayerInfo& pi = g_aPlayerInfos[i];
pak.Assemble("BnsDWwsnn", pi.m_bBot, pi.m_nLevelOrTesla, pi.m_szName, pi.m_nMechIndex, pi.m_fileID, pi.m_recordID, pi.m_szMech, pi.m_nTeamOrSkin, pi.m_nDecal); pak.Assemble("BnsDWwsnn", pi.m_bBot, pi.m_nLevelOrTesla, pi.m_szName, pi.m_nMechIndex, pi.m_fileID, pi.m_recordID, pi.m_szMech, pi.m_nTeamOrSkin, pi.m_nDecal);
} }
@@ -1577,10 +1577,10 @@ void CCTCLManager::DoMech4Comm()
} }
break; break;
case 4: case 4:
// 게임이 성공적으로 만들어지면 서버와 클라이언트들의 Mech에 대한 정보들을 Set한다... // Once the game is successfully created, set Mech info for server and all clients...
if (SOCGame.m_nGameReturn == _EGR_OkCreateSession) { if (SOCGame.m_nGameReturn == _EGR_OkCreateSession) {
for(i = 0; i < g_nPlayerInfos; i++) { for(i = 0; i < g_nPlayerInfos; i++) {
if (i != g_nServer) { // 서버는 이미 SetMech에 진입한 상태... if (i != g_nServer) { // Server has already entered SetMech...
SPlayerInfo& pi = g_aPlayerInfos[i]; SPlayerInfo& pi = g_aPlayerInfos[i];
if (!pi.m_bBot) { if (!pi.m_bBot) {
CTeslaInfo& ti = m_aTIs.GetAt(pi.m_nLevelOrTesla); CTeslaInfo& ti = m_aTIs.GetAt(pi.m_nLevelOrTesla);
@@ -1593,8 +1593,8 @@ void CCTCLManager::DoMech4Comm()
} }
break; break;
case 6: case 6:
//모든 클라이언드들이 서버에 참여하기를 기다린다.<==이 응답은 서버로 부터 얻을 수 있다. //Wait for all clients to join the server. <==This response comes from the server.
//참여가 모두 끝났으면, 서버로 하여금 게임을 Launch시키도록 한다. //Once all clients have joined, instruct the server to Launch the game.
if (SOCGame.m_nGameReturn == _EGR_OkLaunchReady) { if (SOCGame.m_nGameReturn == _EGR_OkLaunchReady) {
g_nMech4Comm = 9; g_nMech4Comm = 9;
} }
+1 -1
View File
@@ -42,7 +42,7 @@ public:
const char* m_pcsz; const char* m_pcsz;
int m_nLauncherConnection; // 0: no connection, +1: connection, -1: connecting int m_nLauncherConnection; // 0: no connection, +1: connection, -1: connecting
int m_nConnection2; // m_bCameraShip값에 따라 게임 혹은 카메라 쉽과의 접속을 의미, 0: no connection, +1: connection, -1: connecting int m_nConnection2; // Connection to game or camera ship per m_bCameraShip, 0: no connection, +1: connected, -1: connecting
int m_nApplType; int m_nApplType;
int m_nApplState; int m_nApplState;
int m_nGameState; int m_nGameState;
@@ -44,7 +44,7 @@ int GetDayEnd(int nYear, int nMonth)
long GetTotalSeconds(int nYear, int nMonth, int nDay) long GetTotalSeconds(int nYear, int nMonth, int nDay)
{ {
// nYear, nMonth, nDay날의 0시 0분 0초를 0으로 한 초단위 수... // Seconds elapsed since 00:00:00 on the date nYear/nMonth/nDay...
ASSERT(nYear >= 1970); ASSERT(nYear >= 1970);
ASSERT((1 <= nMonth) && (nMonth <= 12)); ASSERT((1 <= nMonth) && (nMonth <= 12));
ASSERT(1 <= nDay); ASSERT(1 <= nDay);
@@ -57,13 +57,13 @@ long GetTotalSeconds(int nYear, int nMonth, int nDay)
if (IsLeapYear(nStart)) { if (IsLeapYear(nStart)) {
nDays++; nDays++;
} }
lTotal += nDays * 24 * 60 * 60; // 24시간 60분 60초 lTotal += nDays * 24 * 60 * 60; // 24 hours * 60 min * 60 sec
} }
for(nStart = 1; nStart < nMonth; nStart++) { for(nStart = 1; nStart < nMonth; nStart++) {
int nDayEnd = GetDayEnd(nYear, nStart); int nDayEnd = GetDayEnd(nYear, nStart);
lTotal += nDayEnd * 24 * 60 * 60; // 24시간 60분 60초 lTotal += nDayEnd * 24 * 60 * 60; // 24 hours * 60 min * 60 sec
} }
lTotal += (nDay - 1) * 24 * 60 * 60; // 24시간 60분 60초 lTotal += (nDay - 1) * 24 * 60 * 60; // 24 hours * 60 min * 60 sec
return lTotal; return lTotal;
} }
@@ -16,7 +16,7 @@ class CTimeDate
public: public:
union { union {
struct { struct {
// Bit Field는 앞쪽에 지정된 것이 LowBit이다. // Bit Fields declared first are at the low-bit end.
DWORD m_xDay: 5; // 2^0, 2^5-1 DWORD m_xDay: 5; // 2^0, 2^5-1
DWORD m_xMonth: 4; // 2^5, 2^4-1 DWORD m_xMonth: 4; // 2^5, 2^4-1
DWORD m_xYear: TIMEDATE_YEAR_BITS; // from 1900-2155 // 2^9, 2^8-1 DWORD m_xYear: TIMEDATE_YEAR_BITS; // from 1900-2155 // 2^9, 2^8-1
@@ -1375,7 +1375,7 @@ void CSockAddr::SetTarget(const char* pcszAddr)
{ {
if (pcszAddr) { if (pcszAddr) {
sin_addr.s_addr = inet_addr(pcszAddr); sin_addr.s_addr = inet_addr(pcszAddr);
if (sin_addr.s_addr == INADDR_ANY) { // 0.0.0.0이기 때문에 HOST/Network Addr무관 if (sin_addr.s_addr == INADDR_ANY) { // 0.0.0.0, HOST/Network Addr irrelevant
hostent* pHN = gethostbyname(pcszAddr); hostent* pHN = gethostbyname(pcszAddr);
if (pHN) { if (pHN) {
sin_addr.s_addr = *(u_long*)pHN->h_addr; sin_addr.s_addr = *(u_long*)pHN->h_addr;
@@ -3667,7 +3667,7 @@ CSOCListen* CSOCManager::DoListen(int nPort, PFN_CreateSOCClient pfnCSC, DWORD d
pSOCListen = new CSOCListen(nPort); pSOCListen = new CSOCListen(nPort);
pSOCListen->SetCSCParam(pfnCSC, dwCSCParam1, dwCSCParam2); pSOCListen->SetCSCParam(pfnCSC, dwCSCParam1, dwCSCParam2);
if (!DoListen(pSOCListen, nPort)) { if (!DoListen(pSOCListen, nPort)) {
// 같은 포트를 2번 Listen 하는 경우?... // Case of Listen on the same port twice?...
pSOCListen = NULL; pSOCListen = NULL;
} }
+25 -25
View File
@@ -41,7 +41,7 @@ extern char SERVERID[];
#endif // !MAX_PACKET #endif // !MAX_PACKET
#ifndef MAX_FTPBUF #ifndef MAX_FTPBUF
#define MAX_FTPBUF 1024 #define MAX_FTPBUF 1024
// MAX_FTPBUF는 MAX_PACKET보다 반드시 작아야 한다? // MAX_FTPBUF must be smaller than MAX_PACKET?
// 9+size==sizeof(bCmd) + sizeof(FTID) + sizeof(size) + size // 9+size==sizeof(bCmd) + sizeof(FTID) + sizeof(size) + size
#endif // !MAX_FTPBUF #endif // !MAX_FTPBUF
@@ -251,7 +251,7 @@ private:
#define ESTRF_USER_START 100 #define ESTRF_USER_START 100
#define ESTRF_PASSWORDCHANGED 110 // 로그인하고 있는 동안에 패스워드가 바뀜 #define ESTRF_PASSWORDCHANGED 110 // Password changed while logged in
void Randomize(); void Randomize();
@@ -268,7 +268,7 @@ union UPacketValue
class CDAPacket : public SOCBase_Class class CDAPacket : public SOCBase_Class
{ {
// Packet의 앞 부분을 처리하고 난 뒷 부분의 가변 파라미터... // Variable parameters in the tail portion after processing the packet header...
public: public:
BYTE m_bCmd; BYTE m_bCmd;
BYTE m_bReserved; BYTE m_bReserved;
@@ -361,8 +361,8 @@ public:
#define C_ROOM_MAKE 232 #define C_ROOM_MAKE 232
// s - name, s - password // s - name, s - password
#define C_ROOM_JOIN 233 #define C_ROOM_JOIN 233
// d - number(Room을 떠나는 것은 -1), s - password // d - number (leaving a Room = -1), s - password
#define S_ROOM_JOIN 233 // C_ROOM_MAKE/C_ROOM_JOIN의 결과... #define S_ROOM_JOIN 233 // Result of C_ROOM_MAKE/C_ROOM_JOIN...
// b - code(CSCODE_OK or error code), d - number // b - code(CSCODE_OK or error code), d - number
#define C_ROOM_UPDS 234 // CSCODE_... + @ #define C_ROOM_UPDS 234 // CSCODE_... + @
@@ -384,13 +384,13 @@ public:
#define S_FTP 254 //... see ftp.txt #define S_FTP 254 //... see ftp.txt
#define X_KEEPALIVE 255 // no parameters, should be ignored... #define X_KEEPALIVE 255 // no parameters, should be ignored...
#define TX_SYSTEM 0 // 시스템 메시지... #define TX_SYSTEM 0 // System message...
#define TX_NORMAL 1 // 일반 채팅 텍스트 #define TX_NORMAL 1 // Regular chat text
#define TX_WARNING 2 // 경고 #define TX_WARNING 2 // Warning
#define TX_ERROR 3 // 오류 #define TX_ERROR 3 // Error
#define TX_FATAL 4 // 치명적인 오류 #define TX_FATAL 4 // Fatal error
#define TX_INFO 5 // 사용자 정보 등의 Information Result... #define TX_INFO 5 // Information result (e.g. user info)...
#define TX_SAY 6 // 귓속말 #define TX_SAY 6 // Whisper
#define TX_LOCAL 7 // local echo.... #define TX_LOCAL 7 // local echo....
#define TX_UNKNOWN 0xffff // unknown... #define TX_UNKNOWN 0xffff // unknown...
@@ -493,7 +493,7 @@ CPacket
protected: protected:
CSOC* m_pSOC; CSOC* m_pSOC;
private: private:
// 이 안의 블럭은 반드시 연속해야 한다... // The block within must be contiguous...
WORD m_wLen; WORD m_wLen;
BYTE m_ba[MAX_PACKET]; BYTE m_ba[MAX_PACKET];
// //
@@ -587,7 +587,7 @@ end of variable PACKET_MAP definitions...
class CFileTransfer : public TDBLNK(CFileTransfer*) class CFileTransfer : public TDBLNK(CFileTransfer*)
{ {
public: public:
// 서버로 부터 받은 정보... - 혹은 클라이언트에게 전해줄 정보... // Information received from server... - or information to relay to client...
BOOL m_bClientSite; BOOL m_bClientSite;
DWORD m_dwFTID; DWORD m_dwFTID;
DWORD m_dwGUARD; DWORD m_dwGUARD;
@@ -680,18 +680,18 @@ protected:
// time out to Drop... // time out to Drop...
DWORD m_dwKARcvTimeOut; DWORD m_dwKARcvTimeOut;
#ifdef WIN32 #ifdef WIN32
// 보통 Login과정에 쓰이는 윈도우 핸들 // Window handle typically used during Login process
HWND m_hWndOwner; HWND m_hWndOwner;
#endif // WIN32 #endif // WIN32
// 보통 글로벌 변수로 쓰이는 소켓포인터에 대한 자동 NULL Assign을 위하여 // For auto NULL assignment of socket pointer typically used as a global variable
PSOC* m_ppSOC; PSOC* m_ppSOC;
// 소켓을 구분하기 위하여 사용자 프로그램에서 쓰이는 아이디 // ID used in user program to identify a socket
// 주로 서버의 경우에는 클라이언트가 접속할 때마다 고유 아이디를 부여하여 사용 // Mainly for servers: assigns a unique ID each time a client connects
// 하나의 Client가 다수의 서버에 접속할 때(주로 Star형) 각각의 접속을 구분할 때 사용 // Used to distinguish each connection when a client connects to multiple servers (Star topology)
// 클라이언트가 하나의 서버에만 접속하는 경우 클라이언트가 서버에 접속 중인지 혹은 접속했는지를 판단할 때 // When a client connects to only one server: used to check if client is connecting or already connected
// CSOCManager::FindSOC(CSOC_SERVER_ID==default)->GetConnectionState()를 사용. // Use CSOCManager::FindSOC(CSOC_SERVER_ID==default)->GetConnectionState().
// limits.h를 include해야함. // Must include limits.h.
// CSOC생성시의 기본값: CSOCServer == CSOC_SERVER_ID(=INT_MIN), CSOCClient == CSOC_CLIENT_ID(=0), CSOCListen == CSOC_LISTEN_ID(=-1) // Default values at CSOC creation: CSOCServer==CSOC_SERVER_ID(INT_MIN), CSOCClient==CSOC_CLIENT_ID(0), CSOCListen==CSOC_LISTEN_ID(-1)
union { union {
int m_nID; int m_nID;
UINT m_uID; UINT m_uID;
@@ -725,8 +725,8 @@ protected:
DWORD m_xGracefulRemote: 1; DWORD m_xGracefulRemote: 1;
DWORD m_xAbortyLocal: 1; DWORD m_xAbortyLocal: 1;
DWORD m_xAbortyRemote: 1; DWORD m_xAbortyRemote: 1;
DWORD m_xLoginStarted: 1; // 사용자가 직접 값을 Setting해야 한다. DWORD m_xLoginStarted: 1; // Must be set directly by the caller.
DWORD m_xLoginOK: 1; // 사용자가 직접 값을 Setting해야 한다. DWORD m_xLoginOK: 1; // Must be set directly by the caller.
} m_DW; } m_DW;
DWORD m_dwVarFlags; DWORD m_dwVarFlags;
}; };
@@ -6,7 +6,7 @@ inline BOOL AssertDialog(const char* pcszExpr, const char* pcszfile, int nLine)
{ {
char szBuf[MAX_PATH * 2]; char szBuf[MAX_PATH * 2];
sprintf(szBuf, "\"%s\" 파일의 %d줄에서 ASSERT!!!\n\n디버깅을 하시겠습니까?", pcszfile, nLine); sprintf(szBuf, "ASSERT!!! in \"%s\" at line %d\n\nDo you want to debug?", pcszfile, nLine);
#ifdef WIN32 #ifdef WIN32
return ::MessageBox(NULL, szBuf, pcszExpr, MB_YESNO) == IDYES; return ::MessageBox(NULL, szBuf, pcszExpr, MB_YESNO) == IDYES;
+1 -1
View File
@@ -1077,7 +1077,7 @@ int CStrArray::GetTotalLength() const
int nTotalLength; int nTotalLength;
int i, nSize = GetSize(); int i, nSize = GetSize();
nTotalLength = nSize; // nSize개의 '\0' nTotalLength = nSize; // nSize null terminators '\0'
for(i = 0; i < nSize; i++) { for(i = 0; i < nSize; i++) {
nTotalLength += strlen(GetAt(i)); nTotalLength += strlen(GetAt(i));
} }
@@ -3092,13 +3092,13 @@ bool FirstRunEula(const char *eula_filename,const char *warranty_filename)
if (NULL == hMod) if (NULL == hMod)
hMod = LoadLibrary("EBUEula.dll"); hMod = LoadLibrary("EBUEula.dll");
if (NULL == hMod) // cant attach to DLL if (NULL == hMod) // can't attach to DLL
{ {
STOP(("Cannot Load EBUEula.dll")); STOP(("Cannot Load EBUEula.dll"));
} }
pfnEBUEula = (EBUPROC) GetProcAddress(hMod, "EBUEula"); pfnEBUEula = (EBUPROC) GetProcAddress(hMod, "EBUEula");
if (NULL == pfnEBUEula) // cant find entry point if (NULL == pfnEBUEula) // can't find entry point
{ {
FreeLibrary(hMod); FreeLibrary(hMod);
STOP(("Cannot Find Entry Point to EBUEula.dll")); STOP(("Cannot Find Entry Point to EBUEula.dll"));
@@ -3107,9 +3107,9 @@ bool FirstRunEula(const char *eula_filename,const char *warranty_filename)
// //
//This call enables both EULA and warranty accepting/viewing/printing. If your //This call enables both EULA and warranty accepting/viewing/printing. If your
//game doesnt ship with a WARRANTY file, specifiy NULL instead of szWarranty //game doesn't ship with a WARRANTY file, specifiy NULL instead of szWarranty...
//The code below, for instance, works with both OEM and retail builds //The code below, for instance, works with both OEM and retail builds...
// //
const char *pszWarrantyParam = 0xFFFFFFFF != GetFileAttributes(warranty_filename) ? warranty_filename : NULL; const char *pszWarrantyParam = 0xFFFFFFFF != GetFileAttributes(warranty_filename) ? warranty_filename : NULL;
+22 -22
View File
@@ -517,7 +517,7 @@ void CSOC_Server::OnSendFile()
BYTE bCode; BYTE bCode;
if (Disassemble("B", &bCode)) { if (Disassemble("B", &bCode)) {
ASSERT((bCode == 0) || (bCode == 3)); ASSERT((bCode == 0) || (bCode == 3));
// 받아가시오 from Game to console... // Receiving from Game to console...
SYSTEMTIME* pSysTime; SYSTEMTIME* pSysTime;
WORD wSysTimeSize; WORD wSysTimeSize;
GUID* pGUID; GUID* pGUID;
@@ -533,7 +533,7 @@ void CSOC_Server::OnSendFile()
pSF = g_pCTCLManager->m_SFM_Recv.Find(*pGUID, nType); pSF = g_pCTCLManager->m_SFM_Recv.Find(*pGUID, nType);
if (pSF) { if (pSF) {
if (bCode == 3) { if (bCode == 3) {
// 미션리뷰 서버가 mission review 받았다는 것을 받았느냐? // Did we receive confirmation the mission review server got the mission review?
pSF->m_bProcessed = true; pSF->m_bProcessed = true;
g_pCTCLManager->m_SFM_Recv.Cut(pSF); g_pCTCLManager->m_SFM_Recv.Cut(pSF);
g_pCTCLManager->m_SFM_Done.AddTail(pSF); g_pCTCLManager->m_SFM_Done.AddTail(pSF);
@@ -910,7 +910,7 @@ void CSOC_Client::OnSendFile()
BYTE bCode; BYTE bCode;
if (Disassemble("B", &bCode)) { if (Disassemble("B", &bCode)) {
ASSERT((bCode == 1) || (bCode == 2)); ASSERT((bCode == 1) || (bCode == 2));
// 받았오 from console to Game... // Received from console to Game...
SYSTEMTIME* pSysTime; SYSTEMTIME* pSysTime;
WORD wSysTimeSize; WORD wSysTimeSize;
GUID* pGUID; GUID* pGUID;
@@ -1438,21 +1438,21 @@ void CCTCLManager::Run()
#endif // !defined(CTCL_LAUNCHER) #endif // !defined(CTCL_LAUNCHER)
} else { } else {
/* /*
. Code executed for both client and server.
* *Possible states:
/ .. Before server/client role is determined: waiting for commands
(// .) (Commands such as exit/start-server/start-client may arrive.)
Running as server, waiting for server mech configuration data
(CreateSession가 .) (State after CreateSession has been called.)
Bot들에 Running as server, waiting for Bot information
( .) (Client joining happens automatically between client and server.)
Launch를 Running as server, waiting for Launch
==> . ==>Client has no waiting state as data is transferred immediately on startup.
==> . ==>Define each state and implement the appropriate handling for each.
switch(state){ switch(state){
} }
*/ */
@@ -1534,8 +1534,8 @@ void CCTCLManager::DoMech4Comm()
} }
break; break;
case 1: case 1:
//서버/클라이언트로서 실행준비하도록 명령을 전달한다. //Send command to prepare for execution as server/client.
//또한 서버를 실행하는데 필요한 모든 파라미터도 함께 전달한다. //Also transmit all parameters required to run the server.
for(i = 0; i < g_nPlayerInfos; i++) { for(i = 0; i < g_nPlayerInfos; i++) {
SPlayerInfo& pi = g_aPlayerInfos[i]; SPlayerInfo& pi = g_aPlayerInfos[i];
if (!pi.m_bBot) { if (!pi.m_bBot) {
@@ -1562,12 +1562,12 @@ void CCTCLManager::DoMech4Comm()
} }
} }
if (i == g_nPlayerInfos) { if (i == g_nPlayerInfos) {
// Bot들에 대한 정보를 모두 한데 묶어서 보낸다. // Bundle and send all Bot information together.
CPacket pak(&SVR.GetGameSOC()); CPacket pak(&SVR.GetGameSOC());
pak.Assemble("B", C_BOTS); pak.Assemble("B", C_BOTS);
for(i = 0; i < g_nPlayerInfos; i++) { for(i = 0; i < g_nPlayerInfos; i++) {
if (i != g_nServer) { // 원래 Bot만 지금은 서버를 제외한 전부... if (i != g_nServer) { // Originally bots only; now everyone except the server...
SPlayerInfo& pi = g_aPlayerInfos[i]; SPlayerInfo& pi = g_aPlayerInfos[i];
pak.Assemble("BnsDWwsnn", pi.m_bBot, pi.m_nLevelOrTesla, pi.m_szName, pi.m_nMechIndex, pi.m_fileID, pi.m_recordID, pi.m_szMech, pi.m_nTeamOrSkin, pi.m_nDecal); pak.Assemble("BnsDWwsnn", pi.m_bBot, pi.m_nLevelOrTesla, pi.m_szName, pi.m_nMechIndex, pi.m_fileID, pi.m_recordID, pi.m_szMech, pi.m_nTeamOrSkin, pi.m_nDecal);
} }
@@ -1578,10 +1578,10 @@ void CCTCLManager::DoMech4Comm()
} }
break; break;
case 4: case 4:
// 게임이 성공적으로 만들어지면 서버와 클라이언트들의 Mech에 대한 정보들을 Set한다... // Once the game is successfully created, set Mech info for server and all clients...
if (SOCGame.m_nGameReturn == _EGR_OkCreateSession) { if (SOCGame.m_nGameReturn == _EGR_OkCreateSession) {
for(i = 0; i < g_nPlayerInfos; i++) { for(i = 0; i < g_nPlayerInfos; i++) {
if (i != g_nServer) { // 서버는 이미 SetMech에 진입한 상태... if (i != g_nServer) { // Server has already entered SetMech...
SPlayerInfo& pi = g_aPlayerInfos[i]; SPlayerInfo& pi = g_aPlayerInfos[i];
if (!pi.m_bBot) { if (!pi.m_bBot) {
CTeslaInfo& ti = m_aTIs.GetAt(pi.m_nLevelOrTesla); CTeslaInfo& ti = m_aTIs.GetAt(pi.m_nLevelOrTesla);
@@ -1594,8 +1594,8 @@ void CCTCLManager::DoMech4Comm()
} }
break; break;
case 6: case 6:
//모든 클라이언드들이 서버에 참여하기를 기다린다.<==이 응답은 서버로 부터 얻을 수 있다. //Wait for all clients to join the server. <==This response comes from the server.
//참여가 모두 끝났으면, 서버로 하여금 게임을 Launch시키도록 한다. //Once all clients have joined, instruct the server to Launch the game.
if (SOCGame.m_nGameReturn == _EGR_OkLaunchReady) { if (SOCGame.m_nGameReturn == _EGR_OkLaunchReady) {
g_nMech4Comm = 9; g_nMech4Comm = 9;
} }
+1 -1
View File
@@ -42,7 +42,7 @@ public:
const char* m_pcsz; const char* m_pcsz;
int m_nLauncherConnection; // 0: no connection, +1: connection, -1: connecting int m_nLauncherConnection; // 0: no connection, +1: connection, -1: connecting
int m_nConnection2; // m_bCameraShip값에 따라 게임 혹은 카메라 쉽과의 접속을 의미, 0: no connection, +1: connection, -1: connecting int m_nConnection2; // Connection to game or camera ship per m_bCameraShip, 0: no connection, +1: connected, -1: connecting
int m_nApplType; int m_nApplType;
int m_nApplState; int m_nApplState;
int m_nGameState; int m_nGameState;
+4 -4
View File
@@ -44,7 +44,7 @@ int GetDayEnd(int nYear, int nMonth)
long GetTotalSeconds(int nYear, int nMonth, int nDay) long GetTotalSeconds(int nYear, int nMonth, int nDay)
{ {
// nYear, nMonth, nDay날의 0시 0분 0초를 0으로 한 초단위 수... // Seconds elapsed since 00:00:00 on the date nYear/nMonth/nDay...
ASSERT(nYear >= 1970); ASSERT(nYear >= 1970);
ASSERT((1 <= nMonth) && (nMonth <= 12)); ASSERT((1 <= nMonth) && (nMonth <= 12));
ASSERT(1 <= nDay); ASSERT(1 <= nDay);
@@ -57,13 +57,13 @@ long GetTotalSeconds(int nYear, int nMonth, int nDay)
if (IsLeapYear(nStart)) { if (IsLeapYear(nStart)) {
nDays++; nDays++;
} }
lTotal += nDays * 24 * 60 * 60; // 24시간 60분 60초 lTotal += nDays * 24 * 60 * 60; // 24 hours * 60 min * 60 sec
} }
for(nStart = 1; nStart < nMonth; nStart++) { for(nStart = 1; nStart < nMonth; nStart++) {
int nDayEnd = GetDayEnd(nYear, nStart); int nDayEnd = GetDayEnd(nYear, nStart);
lTotal += nDayEnd * 24 * 60 * 60; // 24시간 60분 60초 lTotal += nDayEnd * 24 * 60 * 60; // 24 hours * 60 min * 60 sec
} }
lTotal += (nDay - 1) * 24 * 60 * 60; // 24시간 60분 60초 lTotal += (nDay - 1) * 24 * 60 * 60; // 24 hours * 60 min * 60 sec
return lTotal; return lTotal;
} }
+1 -1
View File
@@ -16,7 +16,7 @@ class CTimeDate
public: public:
union { union {
struct { struct {
// Bit Field는 앞쪽에 지정된 것이 LowBit이다. // Bit Fields declared first are at the low-bit end.
DWORD m_xDay: 5; // 2^0, 2^5-1 DWORD m_xDay: 5; // 2^0, 2^5-1
DWORD m_xMonth: 4; // 2^5, 2^4-1 DWORD m_xMonth: 4; // 2^5, 2^4-1
DWORD m_xYear: TIMEDATE_YEAR_BITS; // from 1900-2155 // 2^9, 2^8-1 DWORD m_xYear: TIMEDATE_YEAR_BITS; // from 1900-2155 // 2^9, 2^8-1
@@ -1375,7 +1375,7 @@ void CSockAddr::SetTarget(const char* pcszAddr)
{ {
if (pcszAddr) { if (pcszAddr) {
sin_addr.s_addr = inet_addr(pcszAddr); sin_addr.s_addr = inet_addr(pcszAddr);
if (sin_addr.s_addr == INADDR_ANY) { // 0.0.0.0이기 때문에 HOST/Network Addr무관 if (sin_addr.s_addr == INADDR_ANY) { // 0.0.0.0, HOST/Network Addr irrelevant
hostent* pHN = gethostbyname(pcszAddr); hostent* pHN = gethostbyname(pcszAddr);
if (pHN) { if (pHN) {
sin_addr.s_addr = *(u_long*)pHN->h_addr; sin_addr.s_addr = *(u_long*)pHN->h_addr;
@@ -3667,7 +3667,7 @@ CSOCListen* CSOCManager::DoListen(int nPort, PFN_CreateSOCClient pfnCSC, DWORD d
pSOCListen = new CSOCListen(nPort); pSOCListen = new CSOCListen(nPort);
pSOCListen->SetCSCParam(pfnCSC, dwCSCParam1, dwCSCParam2); pSOCListen->SetCSCParam(pfnCSC, dwCSCParam1, dwCSCParam2);
if (!DoListen(pSOCListen, nPort)) { if (!DoListen(pSOCListen, nPort)) {
// 같은 포트를 2번 Listen 하는 경우?... // Case of Listen on the same port twice?...
pSOCListen = NULL; pSOCListen = NULL;
} }
+25 -25
View File
@@ -41,7 +41,7 @@ extern char SERVERID[];
#endif // !MAX_PACKET #endif // !MAX_PACKET
#ifndef MAX_FTPBUF #ifndef MAX_FTPBUF
#define MAX_FTPBUF 1024 #define MAX_FTPBUF 1024
// MAX_FTPBUF는 MAX_PACKET보다 반드시 작아야 한다? // MAX_FTPBUF must be smaller than MAX_PACKET?
// 9+size==sizeof(bCmd) + sizeof(FTID) + sizeof(size) + size // 9+size==sizeof(bCmd) + sizeof(FTID) + sizeof(size) + size
#endif // !MAX_FTPBUF #endif // !MAX_FTPBUF
@@ -251,7 +251,7 @@ private:
#define ESTRF_USER_START 100 #define ESTRF_USER_START 100
#define ESTRF_PASSWORDCHANGED 110 // 로그인하고 있는 동안에 패스워드가 바뀜 #define ESTRF_PASSWORDCHANGED 110 // Password changed while logged in
void Randomize(); void Randomize();
@@ -268,7 +268,7 @@ union UPacketValue
class CDAPacket : public SOCBase_Class class CDAPacket : public SOCBase_Class
{ {
// Packet의 앞 부분을 처리하고 난 뒷 부분의 가변 파라미터... // Variable parameters in the tail portion after processing the packet header...
public: public:
BYTE m_bCmd; BYTE m_bCmd;
BYTE m_bReserved; BYTE m_bReserved;
@@ -361,8 +361,8 @@ public:
#define C_ROOM_MAKE 232 #define C_ROOM_MAKE 232
// s - name, s - password // s - name, s - password
#define C_ROOM_JOIN 233 #define C_ROOM_JOIN 233
// d - number(Room을 떠나는 것은 -1), s - password // d - number (leaving a Room = -1), s - password
#define S_ROOM_JOIN 233 // C_ROOM_MAKE/C_ROOM_JOIN의 결과... #define S_ROOM_JOIN 233 // Result of C_ROOM_MAKE/C_ROOM_JOIN...
// b - code(CSCODE_OK or error code), d - number // b - code(CSCODE_OK or error code), d - number
#define C_ROOM_UPDS 234 // CSCODE_... + @ #define C_ROOM_UPDS 234 // CSCODE_... + @
@@ -384,13 +384,13 @@ public:
#define S_FTP 254 //... see ftp.txt #define S_FTP 254 //... see ftp.txt
#define X_KEEPALIVE 255 // no parameters, should be ignored... #define X_KEEPALIVE 255 // no parameters, should be ignored...
#define TX_SYSTEM 0 // 시스템 메시지... #define TX_SYSTEM 0 // System message...
#define TX_NORMAL 1 // 일반 채팅 텍스트 #define TX_NORMAL 1 // Regular chat text
#define TX_WARNING 2 // 경고 #define TX_WARNING 2 // Warning
#define TX_ERROR 3 // 오류 #define TX_ERROR 3 // Error
#define TX_FATAL 4 // 치명적인 오류 #define TX_FATAL 4 // Fatal error
#define TX_INFO 5 // 사용자 정보 등의 Information Result... #define TX_INFO 5 // Information result (e.g. user info)...
#define TX_SAY 6 // 귓속말 #define TX_SAY 6 // Whisper
#define TX_LOCAL 7 // local echo.... #define TX_LOCAL 7 // local echo....
#define TX_UNKNOWN 0xffff // unknown... #define TX_UNKNOWN 0xffff // unknown...
@@ -493,7 +493,7 @@ CPacket
protected: protected:
CSOC* m_pSOC; CSOC* m_pSOC;
private: private:
// 이 안의 블럭은 반드시 연속해야 한다... // The block within must be contiguous...
WORD m_wLen; WORD m_wLen;
BYTE m_ba[MAX_PACKET]; BYTE m_ba[MAX_PACKET];
// //
@@ -587,7 +587,7 @@ end of variable PACKET_MAP definitions...
class CFileTransfer : public TDBLNK(CFileTransfer*) class CFileTransfer : public TDBLNK(CFileTransfer*)
{ {
public: public:
// 서버로 부터 받은 정보... - 혹은 클라이언트에게 전해줄 정보... // Information received from server... - or information to relay to client...
BOOL m_bClientSite; BOOL m_bClientSite;
DWORD m_dwFTID; DWORD m_dwFTID;
DWORD m_dwGUARD; DWORD m_dwGUARD;
@@ -680,18 +680,18 @@ protected:
// time out to Drop... // time out to Drop...
DWORD m_dwKARcvTimeOut; DWORD m_dwKARcvTimeOut;
#ifdef WIN32 #ifdef WIN32
// 보통 Login과정에 쓰이는 윈도우 핸들 // Window handle typically used during Login process
HWND m_hWndOwner; HWND m_hWndOwner;
#endif // WIN32 #endif // WIN32
// 보통 글로벌 변수로 쓰이는 소켓포인터에 대한 자동 NULL Assign을 위하여 // For auto NULL assignment of socket pointer typically used as a global variable
PSOC* m_ppSOC; PSOC* m_ppSOC;
// 소켓을 구분하기 위하여 사용자 프로그램에서 쓰이는 아이디 // ID used in user program to identify a socket
// 주로 서버의 경우에는 클라이언트가 접속할 때마다 고유 아이디를 부여하여 사용 // Mainly for servers: assigns a unique ID each time a client connects
// 하나의 Client가 다수의 서버에 접속할 때(주로 Star형) 각각의 접속을 구분할 때 사용 // Used to distinguish each connection when a client connects to multiple servers (Star topology)
// 클라이언트가 하나의 서버에만 접속하는 경우 클라이언트가 서버에 접속 중인지 혹은 접속했는지를 판단할 때 // When a client connects to only one server: used to check if client is connecting or already connected
// CSOCManager::FindSOC(CSOC_SERVER_ID==default)->GetConnectionState()를 사용. // Use CSOCManager::FindSOC(CSOC_SERVER_ID==default)->GetConnectionState().
// limits.h를 include해야함. // Must include limits.h.
// CSOC생성시의 기본값: CSOCServer == CSOC_SERVER_ID(=INT_MIN), CSOCClient == CSOC_CLIENT_ID(=0), CSOCListen == CSOC_LISTEN_ID(=-1) // Default values at CSOC creation: CSOCServer==CSOC_SERVER_ID(INT_MIN), CSOCClient==CSOC_CLIENT_ID(0), CSOCListen==CSOC_LISTEN_ID(-1)
union { union {
int m_nID; int m_nID;
UINT m_uID; UINT m_uID;
@@ -725,8 +725,8 @@ protected:
DWORD m_xGracefulRemote: 1; DWORD m_xGracefulRemote: 1;
DWORD m_xAbortyLocal: 1; DWORD m_xAbortyLocal: 1;
DWORD m_xAbortyRemote: 1; DWORD m_xAbortyRemote: 1;
DWORD m_xLoginStarted: 1; // 사용자가 직접 값을 Setting해야 한다. DWORD m_xLoginStarted: 1; // Must be set directly by the caller.
DWORD m_xLoginOK: 1; // 사용자가 직접 값을 Setting해야 한다. DWORD m_xLoginOK: 1; // Must be set directly by the caller.
} m_DW; } m_DW;
DWORD m_dwVarFlags; DWORD m_dwVarFlags;
}; };
+1 -1
View File
@@ -6,7 +6,7 @@ inline BOOL AssertDialog(const char* pcszExpr, const char* pcszfile, int nLine)
{ {
char szBuf[MAX_PATH * 2]; char szBuf[MAX_PATH * 2];
sprintf(szBuf, "\"%s\" 파일의 %d줄에서 ASSERT!!!\n\n디버깅을 하시겠습니까?", pcszfile, nLine); sprintf(szBuf, "ASSERT!!! in \"%s\" at line %d\n\nDo you want to debug?", pcszfile, nLine);
#ifdef WIN32 #ifdef WIN32
return ::MessageBox(NULL, szBuf, pcszExpr, MB_YESNO) == IDYES; return ::MessageBox(NULL, szBuf, pcszExpr, MB_YESNO) == IDYES;
@@ -11,6 +11,7 @@
#include "mw4dummy.h" #include "mw4dummy.h"
#include "recscore.h" #include "recscore.h"
#include "dbexport.h"
typedef unsigned long UINT4; typedef unsigned long UINT4;
typedef unsigned char* POINTER; typedef unsigned char* POINTER;
#include "logreport.h" #include "logreport.h"
@@ -23,6 +24,7 @@ static char THIS_FILE[] = __FILE__;
#include "mw4dummy.cpp" #include "mw4dummy.cpp"
#include "recscore.cpp" #include "recscore.cpp"
#include "dbexport.cpp"
#include "logreport.cpp" #include "logreport.cpp"
#define IDT_TIMER 1000 #define IDT_TIMER 1000
@@ -37,6 +39,12 @@ BEGIN_MESSAGE_MAP(CChildView,CWnd )
ON_COMMAND(ID_FILE_OPEN, OnFileOpen) ON_COMMAND(ID_FILE_OPEN, OnFileOpen)
ON_COMMAND(ID_FILE_LOGREPORT, OnFileLogReport) ON_COMMAND(ID_FILE_LOGREPORT, OnFileLogReport)
ON_COMMAND(ID_FILE_LOG2DATES, OnFileLog2Dates) ON_COMMAND(ID_FILE_LOG2DATES, OnFileLog2Dates)
ON_COMMAND(ID_FILE_DBSETTINGS, OnFileDbSettings)
ON_COMMAND(ID_FILE_BANNERSETTING, OnFileBannerSetting)
END_MESSAGE_MAP()
BEGIN_MESSAGE_MAP(CDlgDBSettings, CDialog)
ON_BN_CLICKED(IDC_DB_TEST, OnTestConnection)
END_MESSAGE_MAP() END_MESSAGE_MAP()
BEGIN_MESSAGE_MAP(CDlgGet2Dates, CDialog) BEGIN_MESSAGE_MAP(CDlgGet2Dates, CDialog)
@@ -300,6 +308,8 @@ int CChildView::OnCreate(LPCREATESTRUCT lpCreateStruct)
if (CWnd ::OnCreate(lpCreateStruct) == -1) if (CWnd ::OnCreate(lpCreateStruct) == -1)
return -1; return -1;
DB_LoadConfig();
m_uTimer = SetTimer(IDT_TIMER, 1 * 1000, NULL); m_uTimer = SetTimer(IDT_TIMER, 1 * 1000, NULL);
if (!m_uTimer) if (!m_uTimer)
return -1; return -1;
@@ -343,6 +353,151 @@ void CChildView::OnTimer(UINT nIDEvent)
CWnd ::OnTimer(nIDEvent); CWnd ::OnTimer(nIDEvent);
} }
void CChildView::OnFileBannerSetting()
{
CDlgBannerSetting dlg(this);
dlg.DoModal();
}
static void LoadBannerTextFile()
{
char szPath[MAX_PATH];
sprintf(szPath, "%s\\banner.txt", AssetsDirectory1);
FILE* f = fopen(szPath, "rt");
if (f) {
char szBuf[sizeof(g_szPrintBanner)];
if (fgets(szBuf, sizeof(szBuf), f)) {
size_t n = strlen(szBuf);
while (n && (szBuf[n - 1] == '\r' || szBuf[n - 1] == '\n')) {
szBuf[--n] = '\0';
}
strncpy(g_szPrintBanner, szBuf, sizeof(g_szPrintBanner) - 1);
g_szPrintBanner[sizeof(g_szPrintBanner) - 1] = '\0';
}
fclose(f);
}
}
static void SaveBannerTextFile()
{
char szPath[MAX_PATH];
sprintf(szPath, "%s\\banner.txt", AssetsDirectory1);
FILE* f = fopen(szPath, "wt");
if (f) {
fputs(g_szPrintBanner, f);
fputc('\n', f);
fclose(f);
}
}
/////////////////////////////////////////////////////////////////////////////
// CDlgBannerSetting
CDlgBannerSetting::CDlgBannerSetting(CWnd* pParent)
: CDialog(CDlgBannerSetting::IDD, pParent)
{
}
BEGIN_MESSAGE_MAP(CDlgBannerSetting, CDialog)
END_MESSAGE_MAP()
void CDlgBannerSetting::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
BOOL CDlgBannerSetting::OnInitDialog()
{
CDialog::OnInitDialog();
LoadBannerTextFile();
SetDlgItemText(IDC_BANNER_TEXT, g_szPrintBanner);
return TRUE;
}
void CDlgBannerSetting::OnOK()
{
GetDlgItemText(IDC_BANNER_TEXT, g_szPrintBanner, sizeof(g_szPrintBanner));
SaveBannerTextFile();
CDialog::OnOK();
}
void CChildView::OnFileDbSettings()
{
CDlgDBSettings dlg(this);
dlg.DoModal();
}
/////////////////////////////////////////////////////////////////////////////
// CDlgDBSettings
CDlgDBSettings::CDlgDBSettings(CWnd* pParent)
: CDialog(CDlgDBSettings::IDD, pParent)
{
}
void CDlgDBSettings::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
BOOL CDlgDBSettings::OnInitDialog()
{
CDialog::OnInitDialog();
CheckDlgButton(IDC_DB_ENABLED, g_dbConfig.bEnabled ? BST_CHECKED : BST_UNCHECKED);
CheckDlgButton(IDC_DB_EXPORTEVENTS, g_dbConfig.bExportEvents ? BST_CHECKED : BST_UNCHECKED);
SetDlgItemText(IDC_DB_HOST, g_dbConfig.szHost);
SetDlgItemInt (IDC_DB_PORT, g_dbConfig.nPort, FALSE);
SetDlgItemText(IDC_DB_DATABASE, g_dbConfig.szDatabase);
SetDlgItemText(IDC_DB_USERNAME, g_dbConfig.szUsername);
SetDlgItemText(IDC_DB_PASSWORD, g_dbConfig.szPassword);
SetDlgItemText(IDC_DB_STATUS, "");
return TRUE;
}
void CDlgDBSettings::OnOK()
{
g_dbConfig.bEnabled = IsDlgButtonChecked(IDC_DB_ENABLED) == BST_CHECKED;
g_dbConfig.bExportEvents = IsDlgButtonChecked(IDC_DB_EXPORTEVENTS) == BST_CHECKED;
GetDlgItemText(IDC_DB_HOST, g_dbConfig.szHost, sizeof(g_dbConfig.szHost));
g_dbConfig.nPort = (int)GetDlgItemInt(IDC_DB_PORT, NULL, FALSE);
GetDlgItemText(IDC_DB_DATABASE, g_dbConfig.szDatabase, sizeof(g_dbConfig.szDatabase));
GetDlgItemText(IDC_DB_USERNAME, g_dbConfig.szUsername, sizeof(g_dbConfig.szUsername));
GetDlgItemText(IDC_DB_PASSWORD, g_dbConfig.szPassword, sizeof(g_dbConfig.szPassword));
DB_SaveConfig();
CDialog::OnOK();
}
void CDlgDBSettings::OnTestConnection()
{
// Read fields into a temporary config so we test what's in the UI,
// not necessarily what was last saved.
SDBConfig saved = g_dbConfig;
GetDlgItemText(IDC_DB_HOST, g_dbConfig.szHost, sizeof(g_dbConfig.szHost));
g_dbConfig.nPort = (int)GetDlgItemInt(IDC_DB_PORT, NULL, FALSE);
GetDlgItemText(IDC_DB_DATABASE, g_dbConfig.szDatabase, sizeof(g_dbConfig.szDatabase));
GetDlgItemText(IDC_DB_USERNAME, g_dbConfig.szUsername, sizeof(g_dbConfig.szUsername));
GetDlgItemText(IDC_DB_PASSWORD, g_dbConfig.szPassword, sizeof(g_dbConfig.szPassword));
SetDlgItemText(IDC_DB_STATUS, "Testing...");
UpdateWindow();
char szError[512] = "";
bool bOK = DB_TestConnection(szError, sizeof(szError));
SetDlgItemText(IDC_DB_STATUS, bOK ? "OK - Connected successfully." : szError);
g_dbConfig = saved; // restore; OnOK() will save the final values
}
void CChildView::OnFileOpen() void CChildView::OnFileOpen()
{ {
// TODO: Add your command handler code here // TODO: Add your command handler code here
@@ -9,11 +9,41 @@
#pragma once #pragma once
#endif // _MSC_VER > 1000 #endif // _MSC_VER > 1000
class CDlgBannerSetting : public CDialog
{
public:
CDlgBannerSetting(CWnd* pParent = NULL);
enum { IDD = IDD_BANNER_SETTING };
protected:
virtual void DoDataExchange(CDataExchange* pDX);
virtual BOOL OnInitDialog();
virtual void OnOK();
DECLARE_MESSAGE_MAP()
};
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// CChildView window // CChildView window
class MW4PRINT_COPYDATASTRUCT; class MW4PRINT_COPYDATASTRUCT;
/////////////////////////////////////////////////////////////////////////////
// CDlgDBSettings dialog
class CDlgDBSettings : public CDialog
{
public:
CDlgDBSettings(CWnd* pParent = NULL);
enum { IDD = IDD_DB_SETTINGS };
protected:
virtual void DoDataExchange(CDataExchange* pDX);
virtual BOOL OnInitDialog();
virtual void OnOK();
afx_msg void OnTestConnection();
DECLARE_MESSAGE_MAP()
};
class CMyPrintInfo : public TDBLNK(CMyPrintInfo*) class CMyPrintInfo : public TDBLNK(CMyPrintInfo*)
{ {
public: public:
@@ -131,6 +161,8 @@ protected:
afx_msg void OnFileOpen(); afx_msg void OnFileOpen();
afx_msg void OnFileLogReport(); afx_msg void OnFileLogReport();
afx_msg void OnFileLog2Dates(); afx_msg void OnFileLog2Dates();
afx_msg void OnFileDbSettings();
afx_msg void OnFileBannerSetting();
DECLARE_MESSAGE_MAP() DECLARE_MESSAGE_MAP()
}; };
+1 -1
View File
@@ -1077,7 +1077,7 @@ int CStrArray::GetTotalLength() const
int nTotalLength; int nTotalLength;
int i, nSize = GetSize(); int i, nSize = GetSize();
nTotalLength = nSize; // nSize개의 '\0' nTotalLength = nSize; // nSize null terminators '\0'
for(i = 0; i < nSize; i++) { for(i = 0; i < nSize; i++) {
nTotalLength += strlen(GetAt(i)); nTotalLength += strlen(GetAt(i));
} }
+2 -2
View File
@@ -80,7 +80,7 @@ void CSpcFileDialog::SetCustomFilter(const char* pcszName/* = NULL*/, const char
m_ofn.lpstrCustomFilter = p; m_ofn.lpstrCustomFilter = p;
if (!pcszName) { if (!pcszName) {
pcszName = "사용자 정의 파일"; pcszName = "User-defined file";
} }
strcpy(p, pcszName); strcpy(p, pcszName);
p = &p[strlen(pcszName)]; p = &p[strlen(pcszName)];
@@ -111,7 +111,7 @@ BOOL CSpcFileDialog::DoMessage(HWND hParent, UINT uMsg, WPARAM wParam, LPARAM lP
switch(uMsg) { switch(uMsg) {
case WM_INITDIALOG: case WM_INITDIALOG:
if (m_dwStyle) { if (m_dwStyle) {
//0x480 // 파일 이름 Edit //0x480 // File Name Edit
HWND hReadOnly = ::GetDlgItem(hParent, 0x0410); // Read Only HWND hReadOnly = ::GetDlgItem(hParent, 0x0410); // Read Only
if (hReadOnly) { if (hReadOnly) {
if (m_dwStyle == (DWORD)(-1)) { if (m_dwStyle == (DWORD)(-1)) {
+2 -2
View File
@@ -21,8 +21,8 @@ public:
CSpcFileDialog(BOOL bOpenFileDialog, LPCTSTR lpszDefExt = NULL, LPCTSTR lpszFileName = NULL, DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, LPCTSTR lpszFilter = NULL, CWnd* pParentWnd = NULL); CSpcFileDialog(BOOL bOpenFileDialog, LPCTSTR lpszDefExt = NULL, LPCTSTR lpszFileName = NULL, DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, LPCTSTR lpszFilter = NULL, CWnd* pParentWnd = NULL);
void SetTitle(const char* pcszTitle); void SetTitle(const char* pcszTitle);
void SetWorkingDir(const char* pcszWorkingDir); void SetWorkingDir(const char* pcszWorkingDir);
void SetFilterIndex(int nFilterIndex); // 1 기준한 값, 0은 사용자 필터 void SetFilterIndex(int nFilterIndex); // 1-based index, 0 = user-defined filter
int GetFilterIndex() const; // 1 기준한 값, 0은 사용자 필터 int GetFilterIndex() const; // 1-based index, 0 = user-defined filter
void SetCustomFilter(const char* pcszName = NULL, const char* pcszExt = NULL); void SetCustomFilter(const char* pcszName = NULL, const char* pcszExt = NULL);
void EnableHook(const char* pcszWindowText, DWORD dwStyle = (DWORD)(-1)); void EnableHook(const char* pcszWindowText, DWORD dwStyle = (DWORD)(-1));
@@ -0,0 +1,135 @@
-- mw4print MySQL database schema
-- Tables are created automatically by mw4print on first export.
-- This file documents the structure for reference.
--
-- Prerequisites: create the database first, then configure mw4print.ini:
--
-- [MySQLExport]
-- Enabled=1
-- Host=192.168.1.100
-- Port=3306
-- Database=firestorm_stats
-- Username=mw4
-- Password=yourpassword
-- ExportEvents=0
--
-- Run this script manually if you want to pre-create the tables,
-- or just let mw4print create them on first connect.
CREATE TABLE IF NOT EXISTS `match` (
`match_id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`match_time` DATETIME NOT NULL,
`server_name` VARCHAR(256) NOT NULL DEFAULT '',
`server_ip` VARCHAR(64) NOT NULL DEFAULT '',
`map_name` VARCHAR(128) NOT NULL DEFAULT '',
`scenario_name` VARCHAR(128) NOT NULL DEFAULT '',
`game_type` INT NOT NULL DEFAULT 0,
`game_type_name` VARCHAR(64) NOT NULL DEFAULT '',
`is_team_game` TINYINT(1) NOT NULL DEFAULT 0,
`player_count` INT NOT NULL DEFAULT 0,
`team_count` INT NOT NULL DEFAULT 0,
`team_scores` VARCHAR(64) NOT NULL DEFAULT '', -- comma-separated team totals: t0,t1,...,t7
`game_length` INT NOT NULL DEFAULT 0,
`kill_limit` INT NOT NULL DEFAULT 0, -- 0 = no limit
`respawn_limit` INT NOT NULL DEFAULT 0, -- 0 = no limit
`friendly_fire` INT NOT NULL DEFAULT 0, -- percentage
`heat_on` TINYINT(1) NOT NULL DEFAULT 0,
`armor_mode` TINYINT(1) NOT NULL DEFAULT 0,
`unlimited_ammo` TINYINT(1) NOT NULL DEFAULT 0,
`is_night` TINYINT(1) NOT NULL DEFAULT 0,
`min_tonnage` INT NOT NULL DEFAULT 0,
`max_tonnage` INT NOT NULL DEFAULT 0,
PRIMARY KEY (`match_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- game_type values (from GameTypes.h):
-- 0 StockDestruction 1 StockTeamDestruction
-- 2 StockAttrition 3 StockTeamAttrition
-- 4 StockCaptureTheFlag 5 StockKingOfTheHill
-- 6 StockTeamKingOfTheHill 7 StockTerritories
-- 8 StockStealTheBacon 9 StockCaptureBase
-- 10 StockDestroyObjective 11 StockEscort
-- 12 StockMasterTrial 13 StockSiegeAssault
-- 14 StockCampaign 15 CustomDestruction
-- 16 CustomTeamDestruction 17 CustomAttrition
-- 18 CustomTeamAttrition 19 CustomCaptureTheFlag
-- 20 CustomKingOfTheHill 21 CustomTeamKingOfTheHill
-- 22 CustomTerritories 23 CustomStealTheBacon
-- 24 CustomCaptureBase 25 CustomDestroyObjective
-- 26 CustomEscort 27 CustomMasterTrial
-- 28 CustomSiegeAssault 29 CustomCampaign
CREATE TABLE IF NOT EXISTS `player_result` (
`result_id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`match_id` INT UNSIGNED NOT NULL,
`player_name` VARCHAR(64) NOT NULL DEFAULT '',
`mech_name` VARCHAR(64) NOT NULL DEFAULT '',
`team` INT NOT NULL DEFAULT 0, -- 0-7; meaningless in FFA (team_count=0)
`score` INT NOT NULL DEFAULT 0,
`kills` INT NOT NULL DEFAULT 0,
`deaths` INT NOT NULL DEFAULT 0,
`is_bot` TINYINT(1) NOT NULL DEFAULT 0,
`pilot_decal` INT NOT NULL DEFAULT 0, -- decal index 0-63
PRIMARY KEY (`result_id`),
KEY `match_id` (`match_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `pvp` (
`pvp_id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`match_id` INT UNSIGNED NOT NULL,
`attacker` VARCHAR(64) NOT NULL DEFAULT '', -- player_name of attacker
`victim` VARCHAR(64) NOT NULL DEFAULT '', -- player_name of victim
`kills` INT NOT NULL DEFAULT 0, -- times attacker killed victim
`score` INT NOT NULL DEFAULT 0, -- score attacker earned from victim
PRIMARY KEY (`pvp_id`),
KEY `match_id` (`match_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- Optional: populated only when ExportEvents=1 in mw4print.ini.
-- Can generate thousands of rows per match; off by default.
CREATE TABLE IF NOT EXISTS `event` (
`event_id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`match_id` INT UNSIGNED NOT NULL,
`event_type` INT NOT NULL DEFAULT 0, -- CBucketManager::Bucket_Type (see below)
`actor` VARCHAR(64) NOT NULL DEFAULT '',
`target` VARCHAR(64) NOT NULL DEFAULT '',
`weapon` INT NOT NULL DEFAULT 0,
`body_zone` INT NOT NULL DEFAULT 0, -- DamageObject zone (see below)
`param` INT NOT NULL DEFAULT 0, -- context-dependent value
PRIMARY KEY (`event_id`),
KEY `match_id` (`match_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- event_type values (CBucketManager::Bucket_Type):
-- 0 KILL_LINK 1 DEATH_LINK
-- 2 KILLS 3 FRIENDLY_KILLS
-- 4 ENEMY_KILLS 5 KILLS_BY_TONNAGE
-- 6 FRIENDLY_KILLS_BY_TONNAGE 7 ENEMY_KILLS_BY_TONNAGE
-- 8 DEATHS 9 SUICIDES
-- 10 DAMAGE_INFLICT 11 FRIENDLY_DAMAGE_INFLICT
-- 12 ENEMY_DAMAGE_INFLICT 13 DAMAGE_RECEIVE
-- 14 FRIENDLY_DAMAGE_RECEIVE 15 ENEMY_DAMAGE_RECEIVE
-- 16 COMPONENT_KILLS 17 COMPONENT_DEATHS
-- 18 FRIENDLY_COMPONENT_KILLS 19 FRIENDLY_COMPONENT_DEATHS
-- 20 ENEMY_COMPONENT_KILLS 21 ENEMY_COMPONENT_DEATHS
-- 22 DFA 23 SHOTS_HIT
-- 24 SHOTS_FIRED 25 HEAD_SHOTS
-- 26 ARM_SHOTS 27 LEG_SHOTS
-- 28 TORSO_SHOTS 29 KILLS_PC
-- 30 KILLS_AI 31 BLANK
-- 32 SHUTDOWN_TIMER 33 OBJECTIVE
-- 34 OBJECTIVE_CONTESTED 35 OBJECTIVE_UNCONTESTED
-- 36 FLAGS_TAKEN 37 FLAGS_DROPPED
-- 38 FLAGS_CAPTURED 39 FLAG_HOLD_TIME
-- 40 TIME 41 ALIVE_PLAYERS
-- 42 DEAD_PLAYERS 43 CUSTOM
-- 44 ENEMY_TURRET_KILLS 45 FRIENDLY_TURRET_KILLS
-- 46 ENEMY_BUILDING_KILLS 47 FRIENDLY_BUILDING_KILLS
-- body_zone values (DamageObject::DamageZone):
-- 0 LeftLeg 1 RightLeg 2 LeftArm 3 RightArm
-- 4 RightTorso 5 LeftTorso 6 CenterTorso 7 Head
-- 8 SpecialZone1 9 SpecialZone2
@@ -0,0 +1,486 @@
// dbexport.cpp - MySQL export implementation for mw4print
//
// Included directly from ChildView.cpp (same pattern as recscore.cpp).
//
#include "dbexport.h"
// ---- Config default values -----------------------------------------------
SDBConfig g_dbConfig = {
false, // bEnabled
"localhost", // szHost
3306, // nPort
"firestorm_stats", // szDatabase
"mw4", // szUsername
"", // szPassword
false // bExportEvents
};
// ---- MySQL late binding --------------------------------------------------
//
// We load libmysql.dll at runtime so the exe does not hard-link against it.
// All function pointers are NULL until DB_LoadMySQL() succeeds.
static HMODULE g_hMySQL = NULL;
typedef void* MYSQLH; // opaque MYSQL* handle
typedef unsigned long MYULONG;
typedef unsigned __int64 MYULLONG;
// MYSQL_OPT_CONNECT_TIMEOUT = 0
#define MY_OPT_CONNECT_TIMEOUT 0
typedef MYSQLH (__cdecl *PFN_mysql_init) (MYSQLH);
typedef MYSQLH (__cdecl *PFN_mysql_real_connect) (MYSQLH, const char*, const char*, const char*, const char*, unsigned int, const char*, unsigned long);
typedef void (__cdecl *PFN_mysql_options) (MYSQLH, int, const char*);
typedef int (__cdecl *PFN_mysql_real_query) (MYSQLH, const char*, unsigned long);
typedef MYULLONG (__cdecl *PFN_mysql_insert_id) (MYSQLH);
typedef void (__cdecl *PFN_mysql_close) (MYSQLH);
typedef const char* (__cdecl *PFN_mysql_error) (MYSQLH);
typedef MYULONG (__cdecl *PFN_mysql_escape_string) (char*, const char*, MYULONG);
static PFN_mysql_init pfn_init = NULL;
static PFN_mysql_real_connect pfn_real_connect = NULL;
static PFN_mysql_options pfn_options = NULL;
static PFN_mysql_real_query pfn_real_query = NULL;
static PFN_mysql_insert_id pfn_insert_id = NULL;
static PFN_mysql_close pfn_close = NULL;
static PFN_mysql_error pfn_error = NULL;
static PFN_mysql_escape_string pfn_escape_string = NULL;
static bool DB_LoadMySQL()
{
if (g_hMySQL)
return true;
// Try app directory first, then system path.
char szPath[MAX_PATH];
sprintf(szPath, "%s\\libmysql.dll", AssetsDirectory1);
g_hMySQL = LoadLibrary(szPath);
if (!g_hMySQL)
g_hMySQL = LoadLibrary("libmysql.dll");
if (!g_hMySQL)
return false;
#define GETPROC(name, pfn) pfn = (PFN_##name)GetProcAddress(g_hMySQL, #name); if (!pfn) { FreeLibrary(g_hMySQL); g_hMySQL=NULL; return false; }
GETPROC(mysql_init, pfn_init)
GETPROC(mysql_real_connect, pfn_real_connect)
GETPROC(mysql_options, pfn_options)
GETPROC(mysql_real_query, pfn_real_query)
GETPROC(mysql_insert_id, pfn_insert_id)
GETPROC(mysql_close, pfn_close)
GETPROC(mysql_error, pfn_error)
GETPROC(mysql_escape_string, pfn_escape_string)
#undef GETPROC
return true;
}
// ---- Helpers -------------------------------------------------------------
// Open a connection using current config. Returns handle on success, NULL
// on failure. Caller must call pfn_close on the returned handle.
static MYSQLH DB_Connect(char* pszError, int nErrBufSize)
{
if (!DB_LoadMySQL()) {
if (pszError)
strncpy(pszError, "libmysql.dll not found. Install MySQL Connector/C and place libmysql.dll next to mw4print.exe.", nErrBufSize - 1);
return NULL;
}
MYSQLH h = pfn_init(NULL);
if (!h) {
if (pszError)
strncpy(pszError, "mysql_init failed (out of memory?)", nErrBufSize - 1);
return NULL;
}
// Short connect timeout so the app doesn't hang if server is unreachable.
int nTimeout = 5;
pfn_options(h, MY_OPT_CONNECT_TIMEOUT, (const char*)&nTimeout);
MYSQLH conn = pfn_real_connect(h,
g_dbConfig.szHost,
g_dbConfig.szUsername,
g_dbConfig.szPassword,
g_dbConfig.szDatabase,
(unsigned int)g_dbConfig.nPort,
NULL, 0);
if (!conn) {
if (pszError) {
strncpy(pszError, pfn_error(h), nErrBufSize - 1);
pszError[nErrBufSize - 1] = '\0';
}
pfn_close(h);
return NULL;
}
return h;
}
// Execute a query string; return true on success.
static bool DB_Exec(MYSQLH h, const char* pszSQL)
{
return pfn_real_query(h, pszSQL, (unsigned long)strlen(pszSQL)) == 0;
}
// Escape a string for use inside SQL single-quoted literals.
// Writes into pszOut (must be at least 2*len+1 bytes).
static void DB_Escape(char* pszOut, const char* pszIn)
{
if (pfn_escape_string)
pfn_escape_string(pszOut, pszIn, (MYULONG)strlen(pszIn));
else {
// Fallback: manual escape of ' and backslash
char* dst = pszOut;
for (const char* src = pszIn; *src; ++src) {
if (*src == '\'' || *src == '\\')
*dst++ = '\\';
*dst++ = *src;
}
*dst = '\0';
}
}
// ---- CREATE TABLE statements (run on first connect) ----------------------
static const char* s_szCreateMatch =
"CREATE TABLE IF NOT EXISTS `match` ("
" `match_id` INT UNSIGNED NOT NULL AUTO_INCREMENT,"
" `match_time` DATETIME NOT NULL,"
" `server_name` VARCHAR(256) NOT NULL DEFAULT '',"
" `server_ip` VARCHAR(64) NOT NULL DEFAULT '',"
" `map_name` VARCHAR(128) NOT NULL DEFAULT '',"
" `scenario_name` VARCHAR(128) NOT NULL DEFAULT '',"
" `game_type` INT NOT NULL DEFAULT 0,"
" `game_type_name` VARCHAR(64) NOT NULL DEFAULT '',"
" `is_team_game` TINYINT(1) NOT NULL DEFAULT 0,"
" `player_count` INT NOT NULL DEFAULT 0,"
" `team_count` INT NOT NULL DEFAULT 0,"
" `team_scores` VARCHAR(64) NOT NULL DEFAULT '',"
" `game_length` INT NOT NULL DEFAULT 0,"
" `kill_limit` INT NOT NULL DEFAULT 0,"
" `respawn_limit` INT NOT NULL DEFAULT 0,"
" `friendly_fire` INT NOT NULL DEFAULT 0,"
" `heat_on` TINYINT(1) NOT NULL DEFAULT 0,"
" `armor_mode` TINYINT(1) NOT NULL DEFAULT 0,"
" `unlimited_ammo` TINYINT(1) NOT NULL DEFAULT 0,"
" `is_night` TINYINT(1) NOT NULL DEFAULT 0,"
" `min_tonnage` INT NOT NULL DEFAULT 0,"
" `max_tonnage` INT NOT NULL DEFAULT 0,"
" PRIMARY KEY (`match_id`)"
") ENGINE=InnoDB DEFAULT CHARSET=utf8";
static const char* s_szCreatePlayerResult =
"CREATE TABLE IF NOT EXISTS `player_result` ("
" `result_id` INT UNSIGNED NOT NULL AUTO_INCREMENT,"
" `match_id` INT UNSIGNED NOT NULL,"
" `player_name` VARCHAR(64) NOT NULL DEFAULT '',"
" `mech_name` VARCHAR(64) NOT NULL DEFAULT '',"
" `team` INT NOT NULL DEFAULT 0,"
" `score` INT NOT NULL DEFAULT 0,"
" `kills` INT NOT NULL DEFAULT 0,"
" `deaths` INT NOT NULL DEFAULT 0,"
" `is_bot` TINYINT(1) NOT NULL DEFAULT 0,"
" `pilot_decal` INT NOT NULL DEFAULT 0,"
" PRIMARY KEY (`result_id`),"
" KEY `match_id` (`match_id`)"
") ENGINE=InnoDB DEFAULT CHARSET=utf8";
static const char* s_szCreatePVP =
"CREATE TABLE IF NOT EXISTS `pvp` ("
" `pvp_id` INT UNSIGNED NOT NULL AUTO_INCREMENT,"
" `match_id` INT UNSIGNED NOT NULL,"
" `attacker` VARCHAR(64) NOT NULL DEFAULT '',"
" `victim` VARCHAR(64) NOT NULL DEFAULT '',"
" `kills` INT NOT NULL DEFAULT 0,"
" `score` INT NOT NULL DEFAULT 0,"
" PRIMARY KEY (`pvp_id`),"
" KEY `match_id` (`match_id`)"
") ENGINE=InnoDB DEFAULT CHARSET=utf8";
static const char* s_szCreateEvent =
"CREATE TABLE IF NOT EXISTS `event` ("
" `event_id` INT UNSIGNED NOT NULL AUTO_INCREMENT,"
" `match_id` INT UNSIGNED NOT NULL,"
" `event_type` INT NOT NULL DEFAULT 0,"
" `actor` VARCHAR(64) NOT NULL DEFAULT '',"
" `target` VARCHAR(64) NOT NULL DEFAULT '',"
" `weapon` INT NOT NULL DEFAULT 0,"
" `body_zone` INT NOT NULL DEFAULT 0,"
" `param` INT NOT NULL DEFAULT 0,"
" PRIMARY KEY (`event_id`),"
" KEY `match_id` (`match_id`)"
") ENGINE=InnoDB DEFAULT CHARSET=utf8";
// Map CBucketManager::Bucket_Type int to a game_type name string.
static const char* GameTypeName(int n)
{
switch (n) {
case 0: return "StockDestruction";
case 1: return "StockTeamDestruction";
case 2: return "StockAttrition";
case 3: return "StockTeamAttrition";
case 4: return "StockCaptureTheFlag";
case 5: return "StockKingOfTheHill";
case 6: return "StockTeamKingOfTheHill";
case 7: return "StockTerritories";
case 8: return "StockStealTheBacon";
case 9: return "StockCaptureBase";
case 10: return "StockDestroyObjective";
case 11: return "StockEscort";
case 12: return "StockMasterTrial";
case 13: return "StockSiegeAssault";
case 14: return "StockCampaign";
case 15: return "CustomDestruction";
case 16: return "CustomTeamDestruction";
case 17: return "CustomAttrition";
case 18: return "CustomTeamAttrition";
case 19: return "CustomCaptureTheFlag";
case 20: return "CustomKingOfTheHill";
case 21: return "CustomTeamKingOfTheHill";
case 22: return "CustomTerritories";
case 23: return "CustomStealTheBacon";
case 24: return "CustomCaptureBase";
case 25: return "CustomDestroyObjective";
case 26: return "CustomEscort";
case 27: return "CustomMasterTrial";
case 28: return "CustomSiegeAssault";
case 29: return "CustomCampaign";
default: return "Unknown";
}
}
// Resolve a ReplicatorID to a player name by scanning aRSOs[].
static const char* ResolvePlayerName(
const ReplicatorID& id,
PCRecScoreObject aRSOs[],
int nPlayers)
{
for (int i = 0; i < nPlayers; i++) {
if (aRSOs[i]->m_who == id)
return aRSOs[i]->GetName();
}
return "";
}
// ---- Config I/O ----------------------------------------------------------
static void DB_GetINIPath(char* pszOut)
{
sprintf(pszOut, "%s\\mw4print.ini", AssetsDirectory1);
}
void DB_LoadConfig()
{
char szINI[MAX_PATH];
DB_GetINIPath(szINI);
const char* sec = "MySQLExport";
g_dbConfig.bEnabled = !!GetPrivateProfileInt(sec, "Enabled", 0, szINI);
GetPrivateProfileString(sec, "Host", "localhost", g_dbConfig.szHost, sizeof(g_dbConfig.szHost), szINI);
g_dbConfig.nPort = GetPrivateProfileInt(sec, "Port", 3306, szINI);
GetPrivateProfileString(sec, "Database", "firestorm_stats", g_dbConfig.szDatabase, sizeof(g_dbConfig.szDatabase), szINI);
GetPrivateProfileString(sec, "Username", "mw4", g_dbConfig.szUsername, sizeof(g_dbConfig.szUsername), szINI);
GetPrivateProfileString(sec, "Password", "", g_dbConfig.szPassword, sizeof(g_dbConfig.szPassword), szINI);
g_dbConfig.bExportEvents = !!GetPrivateProfileInt(sec, "ExportEvents", 0, szINI);
}
void DB_SaveConfig()
{
char szINI[MAX_PATH];
DB_GetINIPath(szINI);
const char* sec = "MySQLExport";
char szBuf[32];
WritePrivateProfileString(sec, "Enabled", g_dbConfig.bEnabled ? "1" : "0", szINI);
WritePrivateProfileString(sec, "Host", g_dbConfig.szHost, szINI);
_itoa(g_dbConfig.nPort, szBuf, 10);
WritePrivateProfileString(sec, "Port", szBuf, szINI);
WritePrivateProfileString(sec, "Database", g_dbConfig.szDatabase, szINI);
WritePrivateProfileString(sec, "Username", g_dbConfig.szUsername, szINI);
WritePrivateProfileString(sec, "Password", g_dbConfig.szPassword, szINI);
WritePrivateProfileString(sec, "ExportEvents", g_dbConfig.bExportEvents ? "1" : "0", szINI);
}
// ---- Test connection -----------------------------------------------------
bool DB_TestConnection(char* pszError, int nErrBufSize)
{
if (pszError && nErrBufSize > 0)
pszError[0] = '\0';
MYSQLH h = DB_Connect(pszError, nErrBufSize);
if (!h)
return false;
bool bOK = DB_Exec(h, "SELECT 1");
if (!bOK && pszError) {
strncpy(pszError, pfn_error(h), nErrBufSize - 1);
pszError[nErrBufSize - 1] = '\0';
}
pfn_close(h);
return bOK;
}
// ---- Main export ---------------------------------------------------------
bool DB_ExportMatch(
const CRecScoreFull& rsf,
PCRecScoreObject aRSOs[],
int nPlayers,
const int naTeams[8],
int nTeamCount,
const MWNetMissionParameters& params)
{
char szError[512];
MYSQLH h = DB_Connect(szError, sizeof(szError));
if (!h)
return false;
char szSQL[4096];
char szEsc[512];
bool bOK = true;
// Ensure tables exist (silent if already present).
DB_Exec(h, s_szCreateMatch);
DB_Exec(h, s_szCreatePlayerResult);
DB_Exec(h, s_szCreatePVP);
if (g_dbConfig.bExportEvents)
DB_Exec(h, s_szCreateEvent);
// ---- Insert match row ------------------------------------------------
// Build team_scores as comma-separated string e.g. "100,80,0,0,0,0,0,0"
char szTeamScores[64];
sprintf(szTeamScores, "%d,%d,%d,%d,%d,%d,%d,%d",
rsf.m_naTeamScores[0], rsf.m_naTeamScores[1],
rsf.m_naTeamScores[2], rsf.m_naTeamScores[3],
rsf.m_naTeamScores[4], rsf.m_naTeamScores[5],
rsf.m_naTeamScores[6], rsf.m_naTeamScores[7]);
char szServerNameE[512], szServerIPE[512], szMapE[256], szScenarioE[256], szGameTypeNameE[128];
DB_Escape(szServerNameE, params.m_serverName);
DB_Escape(szServerIPE, params.m_serverIP);
DB_Escape(szMapE, params.m_mapName);
DB_Escape(szScenarioE, params.m_scenarioName);
DB_Escape(szGameTypeNameE, GameTypeName(params.m_ruleType));
sprintf(szSQL,
"INSERT INTO `match` "
"(match_time, server_name, server_ip, map_name, scenario_name, "
" game_type, game_type_name, is_team_game, player_count, team_count, "
" team_scores, game_length, kill_limit, respawn_limit, friendly_fire, "
" heat_on, armor_mode, unlimited_ammo, is_night, min_tonnage, max_tonnage) "
"VALUES ("
"'%04d-%02d-%02d %02d:%02d:%02d'," // match_time
"'%s','%s','%s','%s'," // server_name, server_ip, map_name, scenario_name
"%d,'%s',%d,%d,%d," // game_type, game_type_name, is_team_game, player_count, team_count
"'%s'," // team_scores
"%d,%d,%d,%d," // game_length, kill_limit, respawn_limit, friendly_fire
"%d,%d,%d,%d,%d,%d" // heat_on, armor_mode, unlimited_ammo, is_night, min_tonnage, max_tonnage
")",
rsf.m_SysTime.wYear, rsf.m_SysTime.wMonth, rsf.m_SysTime.wDay,
rsf.m_SysTime.wHour, rsf.m_SysTime.wMinute, rsf.m_SysTime.wSecond,
szServerNameE, szServerIPE, szMapE, szScenarioE,
params.m_ruleType, szGameTypeNameE,
rsf.m_bTeamGame ? 1 : 0, nPlayers, nTeamCount,
szTeamScores,
params.m_gameLength,
params.m_killLimit ? params.m_killLimitNumber : 0,
params.m_respawnLimit ? params.m_respawnLimitNumber : 0,
params.m_friendlyFirePercentage,
params.m_heatOn ? 1 : 0,
params.m_armormodeOn ? 1 : 0,
params.m_unlimitedAmmo ? 1 : 0,
params.m_isNight ? 1 : 0,
params.m_minimumTonnage,
params.m_maximumTonnage);
bOK = DB_Exec(h, szSQL);
if (!bOK) {
pfn_close(h);
return false;
}
MYULLONG nMatchID = pfn_insert_id(h);
// ---- Insert player_result rows ---------------------------------------
for (int i = 0; i < nPlayers && bOK; i++) {
const CRecScoreObject& rso = *aRSOs[i];
char szNameE[128], szMechE[128];
DB_Escape(szNameE, rso.GetName());
DB_Escape(szMechE, rso.GetMech());
sprintf(szSQL,
"INSERT INTO `player_result` "
"(match_id, player_name, mech_name, team, score, kills, deaths, is_bot, pilot_decal) "
"VALUES (%I64u,'%s','%s',%d,%d,%d,%d,%d,%d)",
nMatchID,
szNameE, szMechE,
rso.m_nPilotTeam,
rso.m_nScore,
rso.m_nKills,
rso.m_nDeaths,
rso.m_bBOT ? 1 : 0,
rso.m_nPilotDecal);
bOK = DB_Exec(h, szSQL);
}
// ---- Insert pvp rows -------------------------------------------------
for (int p = 0; p < rsf.m_nPVPs && bOK; p++) {
const CRecScoreFull::SPVP_Rec& pvp = rsf.m_pPVPs[p];
const char* pszAttacker = ResolvePlayerName(pvp.m_Inf, aRSOs, nPlayers);
const char* pszVictim = ResolvePlayerName(pvp.m_Rcv, aRSOs, nPlayers);
char szAttE[128], szVicE[128];
DB_Escape(szAttE, pszAttacker);
DB_Escape(szVicE, pszVictim);
sprintf(szSQL,
"INSERT INTO `pvp` (match_id, attacker, victim, kills, score) "
"VALUES (%I64u,'%s','%s',%d,%d)",
nMatchID, szAttE, szVicE, pvp.m_nKills, pvp.m_nScore);
bOK = DB_Exec(h, szSQL);
}
// ---- Insert event rows (optional) ------------------------------------
if (bOK && g_dbConfig.bExportEvents) {
// Walk the CRecScorePack linked list.
const CRecScorePack* pPack = rsf.m_pScorePackStart;
while (pPack && bOK) {
for (int e = 0; e < pPack->m_nCount && bOK; e++) {
const SRecScore& rs = pPack->m_a[e];
const char* pszActor = ResolvePlayerName(rs.m_who, aRSOs, nPlayers);
const char* pszTarget = ResolvePlayerName(rs.m_whom, aRSOs, nPlayers);
char szActE[128], szTgtE[128];
DB_Escape(szActE, pszActor);
DB_Escape(szTgtE, pszTarget);
sprintf(szSQL,
"INSERT INTO `event` (match_id, event_type, actor, target, weapon, body_zone, param) "
"VALUES (%I64u,%d,'%s','%s',%d,%d,%d)",
nMatchID,
rs.m_nType,
szActE, szTgtE,
rs.m_nBy,
rs.m_Where.m_xWhere,
rs.m_nParam);
bOK = DB_Exec(h, szSQL);
}
pPack = pPack->m_pNext;
}
}
pfn_close(h);
return bOK;
}
@@ -0,0 +1,59 @@
// dbexport.h - MySQL export interface for mw4print
//
// Connects to an external MySQL server and writes match results after each
// print job. MySQL is loaded at runtime via late binding (libmysql.dll) so
// no MySQL SDK is required at compile time.
//
// Config is stored in mw4print.ini next to the exe:
// [MySQLExport]
// Enabled=0
// Host=192.168.1.100
// Port=3306
// Database=firestorm_stats
// Username=mw4
// Password=
// ExportEvents=0 (1 = also export per-event SRecScore rows)
//
#ifndef __DBEXPORT_H__
#define __DBEXPORT_H__
// ---- Config struct -------------------------------------------------------
struct SDBConfig
{
bool bEnabled;
char szHost[256];
int nPort;
char szDatabase[64];
char szUsername[64];
char szPassword[64];
bool bExportEvents; // export individual SRecScore events (can be many rows)
};
extern SDBConfig g_dbConfig;
// ---- Public API ----------------------------------------------------------
// Load / save config from mw4print.ini in the app directory.
void DB_LoadConfig();
void DB_SaveConfig();
// Try to open a connection using current g_dbConfig, run a trivial query,
// then disconnect. Returns true on success; on failure fills pszError
// (up to nErrBufSize bytes) with the MySQL error string.
bool DB_TestConnection(char* pszError, int nErrBufSize);
// Export one completed match to the database. Called from
// CRecScoreFull::DoPrint() just before PrintDlg().
// Returns true on success.
bool DB_ExportMatch(
const CRecScoreFull& rsf,
PCRecScoreObject aRSOs[],
int nPlayers,
const int naTeams[8],
int nTeamCount,
const MWNetMissionParameters& params
);
#endif // __DBEXPORT_H__
+49 -7
View File
@@ -93,6 +93,9 @@ BEGIN
MENUITEM "&Log report...\t^L", ID_FILE_LOGREPORT MENUITEM "&Log report...\t^L", ID_FILE_LOGREPORT
MENUITEM "Log report(&Block)...\t^B", ID_FILE_LOG2DATES MENUITEM "Log report(&Block)...\t^B", ID_FILE_LOG2DATES
MENUITEM SEPARATOR MENUITEM SEPARATOR
MENUITEM "&Database Settings...\t^D", ID_FILE_DBSETTINGS
MENUITEM "Ban&ner Setting...", ID_FILE_BANNERSETTING
MENUITEM SEPARATOR
MENUITEM "E&xit", ID_APP_EXIT MENUITEM "E&xit", ID_APP_EXIT
END END
POPUP "&Help" POPUP "&Help"
@@ -110,6 +113,7 @@ END
IDR_MAINFRAME ACCELERATORS PRELOAD MOVEABLE PURE IDR_MAINFRAME ACCELERATORS PRELOAD MOVEABLE PURE
BEGIN BEGIN
"B", ID_FILE_LOG2DATES, VIRTKEY, CONTROL, NOINVERT "B", ID_FILE_LOG2DATES, VIRTKEY, CONTROL, NOINVERT
"D", ID_FILE_DBSETTINGS, VIRTKEY, CONTROL, NOINVERT
"L", ID_FILE_LOGREPORT, VIRTKEY, CONTROL, NOINVERT "L", ID_FILE_LOGREPORT, VIRTKEY, CONTROL, NOINVERT
"O", ID_FILE_OPEN, VIRTKEY, CONTROL, NOINVERT "O", ID_FILE_OPEN, VIRTKEY, CONTROL, NOINVERT
END END
@@ -126,12 +130,50 @@ CAPTION "About mw4print"
FONT 8, "MS Sans Serif" FONT 8, "MS Sans Serif"
BEGIN BEGIN
ICON IDR_MAINFRAME,IDC_STATIC,11,17,20,20 ICON IDR_MAINFRAME,IDC_STATIC,11,17,20,20
LTEXT "mw4print Version 1.0",IDC_STATIC,40,10,119,8, LTEXT "mw4print Version 2.0",IDC_STATIC,40,10,119,8,
SS_NOPREFIX SS_NOPREFIX
LTEXT "Copyright (C) 2002",IDC_STATIC,40,25,119,8 LTEXT "Copyright (C) 2026",IDC_STATIC,40,25,119,8
DEFPUSHBUTTON "OK",IDOK,178,7,50,14,WS_GROUP DEFPUSHBUTTON "OK",IDOK,178,7,50,14,WS_GROUP
END END
IDD_BANNER_SETTING DIALOG DISCARDABLE 0, 0, 300, 65
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Banner Setting"
FONT 8, "MS Sans Serif"
BEGIN
LTEXT "Banner text:",IDC_STATIC,7,9,50,8
EDITTEXT IDC_BANNER_TEXT,60,7,233,14,ES_AUTOHSCROLL
DEFPUSHBUTTON "OK",IDOK,189,43,50,14
PUSHBUTTON "Cancel",IDCANCEL,244,43,50,14
LTEXT "(Printed at the bottom of every score sheet. Leave blank to hide.)",
IDC_STATIC,7,28,286,16
END
IDD_DB_SETTINGS DIALOG DISCARDABLE 0, 0, 300, 175
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Database Export Settings"
FONT 8, "MS Sans Serif"
BEGIN
CONTROL "Enable MySQL export",IDC_DB_ENABLED,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,7,7,200,12
LTEXT "Host:",IDC_STATIC,7,26,30,8
EDITTEXT IDC_DB_HOST,55,24,170,14,ES_AUTOHSCROLL
LTEXT "Port:",IDC_STATIC,7,46,30,8
EDITTEXT IDC_DB_PORT,55,44,50,14,ES_AUTOHSCROLL | ES_NUMBER
LTEXT "Database:",IDC_STATIC,7,66,40,8
EDITTEXT IDC_DB_DATABASE,55,64,170,14,ES_AUTOHSCROLL
LTEXT "Username:",IDC_STATIC,7,86,40,8
EDITTEXT IDC_DB_USERNAME,55,84,170,14,ES_AUTOHSCROLL
LTEXT "Password:",IDC_STATIC,7,106,40,8
EDITTEXT IDC_DB_PASSWORD,55,104,170,14,ES_AUTOHSCROLL | ES_PASSWORD
CONTROL "Export individual events (many rows)",IDC_DB_EXPORTEVENTS,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,123,200,12
PUSHBUTTON "Test Connection",IDC_DB_TEST,226,104,68,14
LTEXT "",IDC_DB_STATUS,7,141,286,18,SS_NOPREFIX
DEFPUSHBUTTON "OK",IDOK,189,155,50,14
PUSHBUTTON "Cancel",IDCANCEL,244,155,50,14
END
IDD_GET_2DATES DIALOG DISCARDABLE 0, 0, 187, 75 IDD_GET_2DATES DIALOG DISCARDABLE 0, 0, 187, 75
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Date selection" CAPTION "Date selection"
@@ -157,8 +199,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,1 FILEVERSION 2,0,0,0
PRODUCTVERSION 1,0,0,1 PRODUCTVERSION 2,0,0,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@@ -175,13 +217,13 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "\0" VALUE "CompanyName", "\0"
VALUE "FileDescription", "mw4print MFC Application\0" VALUE "FileDescription", "mw4print MFC Application\0"
VALUE "FileVersion", "1, 0, 0, 1\0" VALUE "FileVersion", "2, 0, 0, 0\0"
VALUE "InternalName", "mw4print\0" VALUE "InternalName", "mw4print\0"
VALUE "LegalCopyright", "Copyright (C) 2002\0" VALUE "LegalCopyright", "Copyright (C) 2026\0"
VALUE "LegalTrademarks", "\0" VALUE "LegalTrademarks", "\0"
VALUE "OriginalFilename", "mw4print.EXE\0" VALUE "OriginalFilename", "mw4print.EXE\0"
VALUE "ProductName", "mw4print Application\0" VALUE "ProductName", "mw4print Application\0"
VALUE "ProductVersion", "1, 0, 0, 1\0" VALUE "ProductVersion", "2, 0, 0, 0\0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"
+91 -49
View File
@@ -268,6 +268,11 @@ static RECT s_rcTextMargin; // check!!! - margin 2 panes on bottom relative to t
// so g_aFonts[FNTI_INFO_TEXT/FNTI_INFO_TEXT_BOLD].m_nTextHeight should less then s_nTextHeight // so g_aFonts[FNTI_INFO_TEXT/FNTI_INFO_TEXT_BOLD].m_nTextHeight should less then s_nTextHeight
static int s_nTextHeight; // check!!! - text line height static int s_nTextHeight; // check!!! - text line height
// Configurable banner text printed at the bottom of each sheet.
// Primary source: banner.txt next to mw4print.exe (first line only).
// Legacy fallback: [battle tech print] BannerText= in options.ini.
char g_szPrintBanner[256] = "Join the worlds greatest Battletech community at WWW.MECHJOCK.COM today!";
void _stdcall GetFileName4GUID(char szBuf[256], const char* pcszDrv, const char* pcszPath, const char* pcszExt, const GUID& guid = *(const GUID*)NULL); void _stdcall GetFileName4GUID(char szBuf[256], const char* pcszDrv, const char* pcszPath, const char* pcszExt, const GUID& guid = *(const GUID*)NULL);
void WriteMString(MemoryStream& mf, const MString& ms) void WriteMString(MemoryStream& mf, const MString& ms)
@@ -1008,27 +1013,27 @@ const char* ArmorZoneStr(int nArmorZone)
case Adept::DamageObject::NullArmorZone: case Adept::DamageObject::NullArmorZone:
return "()"; return "()";
case Adept::DamageObject::LeftLegArmorZone: case Adept::DamageObject::LeftLegArmorZone:
return "왼발"; return "Left Leg";
case Adept::DamageObject::RightLegArmorZone: case Adept::DamageObject::RightLegArmorZone:
return "오른발"; return "Right Leg";
case Adept::DamageObject::LeftArmArmorZone: case Adept::DamageObject::LeftArmArmorZone:
return "왼팔"; return "Left Arm";
case Adept::DamageObject::RightArmArmorZone: case Adept::DamageObject::RightArmArmorZone:
return "오른팔"; return "Right Arm";
case Adept::DamageObject::RightTorsoArmorZone: case Adept::DamageObject::RightTorsoArmorZone:
return "우측"; return "Right Torso";
case Adept::DamageObject::LeftTorsoArmorZone: case Adept::DamageObject::LeftTorsoArmorZone:
return "좌측"; return "Left Torso";
case Adept::DamageObject::CenterTorsoArmorZone: case Adept::DamageObject::CenterTorsoArmorZone:
return "전면"; return "Front";
case Adept::DamageObject::CenterRearTorsoArmorZone: case Adept::DamageObject::CenterRearTorsoArmorZone:
return "후면"; return "Rear";
case Adept::DamageObject::HeadArmorZone: case Adept::DamageObject::HeadArmorZone:
return "머리"; return "Head";
case Adept::DamageObject::SpecialArmorZone1: case Adept::DamageObject::SpecialArmorZone1:
return "보조장치1"; return "Aux Device 1";
case Adept::DamageObject::SpecialArmorZone2: case Adept::DamageObject::SpecialArmorZone2:
return "보조장치2"; return "Aux Device 2";
case Adept::DamageObject::DefaultArmorZone: case Adept::DamageObject::DefaultArmorZone:
return "Default"; return "Default";
} }
@@ -1996,83 +2001,83 @@ public:
static SMSGFMT s_aKill[20][2] = { static SMSGFMT s_aKill[20][2] = {
{ {
{ "%s's %s destroys %s's %s!", 0 }, // ok! { "%s's %s destroys %s's %s!", 0 }, // ok!
{ "%s %s, %s의 %s을(를) 파괴하다!", 0 }, // ok! { "%s's %s destroyed %s's %s!", 0 }, // ok!
}, },
{ {
{ "%s's %s explodes in a fire-ball, thanks to %s.", 1 }, // ok! { "%s's %s explodes in a fire-ball, thanks to %s.", 1 }, // ok!
{ "%s %s, 각 기관부의 화염으로 폭발! %s의 절묘한 공격성공!", 1 }, // ok! { "%s's %s explodes in flames! %s lands a perfect hit!", 1 }, // ok!
}, },
{ {
{ "%s delivers the last blow as %s's %s explodes in flames!", 2 }, // ok! { "%s delivers the last blow as %s's %s explodes in flames!", 2 }, // ok!
{ "%s %s %s!", 2 - 100}, // ok! { "%s took a hit to %s's %s!", 2 - 100}, // ok!
}, },
{ {
{ "Smoking wreckage is all that's left of %s's %s after %s delivers the fatal blow!", 1 }, { "Smoking wreckage is all that's left of %s's %s after %s delivers the fatal blow!", 1 },
{ "%s의 무자비한 공격으로 %s의 %s 불타는 잔해만 남길 것이다.", 2 }, // ok! { "%s's merciless assault leaves only burning wreckage of %s's %s.", 2 }, // ok!
}, },
{ {
{ "Glorious victory goes to %s as the wreckage from %s's %s lies burning on the battlefield!", 2 }, { "Glorious victory goes to %s as the wreckage from %s's %s lies burning on the battlefield!", 2 },
{ "전황은 급속도로 진전, %s의 생존가능성은 0%%!", 8 }, // ok! { "The battle escalates rapidly - %s's survival probability is 0%%!", 8 }, // ok!
}, },
{ {
{ "%s's %s is put out of it's misery by a devastating shot from %s.", 1 }, { "%s's %s is put out of it's misery by a devastating shot from %s.", 1 },
{ "%s의 압도적인 화력 앞에 %s 처참히 무너지고 있다.", 4 }, // ok! { "Under %s's overwhelming firepower, %s crumbles miserably.", 4 }, // ok!
}, },
{ {
{ "%s racks up another kill marker from reducing %s's %s to rubble!", 2 }, { "%s racks up another kill marker from reducing %s's %s to rubble!", 2 },
{ "%s %s의 %s을(를) 때려 눕히고, 새로운 킬마크를 얻었다.", 2 }, // ok! { "%s knocked out %s's %s and earned a new kill mark.", 2 }, // ok!
}, },
{ {
{ "Fresh paint is applied to %s's %s to mark the destruction of %s's %s!", 0 }, // ok! { "Fresh paint is applied to %s's %s to mark the destruction of %s's %s!", 0 }, // ok!
{ "%s는 %s를 격추한 킬마크를 %s에 추가했다.", 0 - 100 }, { "%s added a kill mark on %s for shooting down %s.", 0 - 100 },
}, },
{ {
{ "The burning wreckage of %s's %s is a reminder to all of the prowess of %s's battle skills!", 1 }, { "The burning wreckage of %s's %s is a reminder to all of the prowess of %s's battle skills!", 1 },
{ "%s의 잔해는 %s이(가) 가져갈 승리의 기념품이 될것이다.", 7 }, // ok! { "The wreckage of %s will be %s's trophy of victory.", 7 }, // ok!
}, },
{ {
{ "The thunderous explosion of %s's %s is music to the ears of %s!", 1 }, { "The thunderous explosion of %s's %s is music to the ears of %s!", 1 },
{ "%s의 귀에 들려오는 죽음의 전주곡. 지휘자는 %s.", 7 }, // ok! { "A death prelude echoes in %s's ears. The conductor: %s.", 7 }, // ok!
}, },
{ {
{ "%s's %s is destroyed by %s's %s.", 3 }, { "%s's %s is destroyed by %s's %s.", 3 },
{ "%s' %s, %s %s에게 파괴되었다.", 3 }, // ok! { "%s's %s was destroyed by %s's %s.", 3 }, // ok!
}, },
{ {
{ "%s brings the four horsemen of the apocalypse down upon %s.", 4 }, { "%s brings the four horsemen of the apocalypse down upon %s.", 4 },
{ "%s(이)가 휘두르는 심판의 추가 %s에게 작렬했다.", 4 }, // ok! { "The pendulum of judgment swung by %s strikes %s.", 4 }, // ok!
}, },
{ {
{ "%s's life flashes as %s reduces the %s to a burning wreck.", 5 }, { "%s's life flashes as %s reduces the %s to a burning wreck.", 5 },
{ "%s의 마지막 생명줄에, %s !", 7 - 100 }, // ok! { "On %s's last lifeline, %s!", 7 - 100 }, // ok!
}, },
{ {
{ "%s is deafened by the resounding roar of the exploding %s, thanks to %s.", 1 }, { "%s is deafened by the resounding roar of the exploding %s, thanks to %s.", 1 },
{ "%s 기체의 폭발소리와 함께, 저 하늘로 날아갔다. %s에게 영광을!", 7 }, // ok! { "%s's mech explodes skyward. Glory to %s!", 7 }, // ok!
}, },
{ {
{ "A kill marker is placed on %s's %s to mark the victory over %s.", 6 }, { "A kill marker is placed on %s's %s to mark the victory over %s.", 6 },
{ "%s의 %s에 새로운 킬마크를 추가해야 할 듯, 희생자는 %s", 6 }, // ok! { "A new kill mark should be added to %s's %s, victim: %s", 6 }, // ok!
}, },
{ {
{ "%s is delivered unto the inferno with regards from %s.", 7 }, { "%s is delivered unto the inferno with regards from %s.", 7 },
{ "%s, %s의 호위하에 지옥으로 향했다. %s에게 명복을!", 9 }, // ok! { "%s headed to hell under %s's escort. Rest in peace, %s!", 9 }, // ok!
}, },
{ {
{ "Another kill marker is given up by %s, as %s celebrates victory.", 7 }, { "Another kill marker is given up by %s, as %s celebrates victory.", 7 },
{ "%s, %s의 새로운 킬 마크가 되었다. 영원한 안식을…", 7 - 100 }, { "%s became %s's new kill mark. Rest in peace...", 7 - 100 },
}, },
{ {
{ "Best wishes in the afterlife are presented to %s from %s.", 7 }, { "Best wishes in the afterlife are presented to %s from %s.", 7 },
{ "%s에게 남은 것은 오직 %s에 대한 복수뿐!", 7 }, // ok! { "All that remains for %s is revenge against %s!", 7 }, // ok!
}, },
{ {
{ "Tragedy strikes %s as %s guns the %s down.", 5 }, { "Tragedy strikes %s as %s guns the %s down.", 5 },
{ "%s 모든 화력을 동원해 %s %s을(를) 파괴했다.", 2 }, // ok! { "%s brought all firepower to bear and destroyed %s's %s.", 2 }, // ok!
}, },
{ {
{ "%s earns the revenge of %s after the tragic destruction of the %s.", 2 }, { "%s earns the revenge of %s after the tragic destruction of the %s.", 2 },
{ "%s의 비극적인 최후! %s 절망하는 %s을(를) 지켜볼 뿐이다.", 9 }, // ok! { "A tragic end for %s! %s can only watch %s in despair.", 9 }, // ok!
}, },
}; };
@@ -2083,11 +2088,11 @@ static SMSGFMT s_aKill[20][2] = {
static SMSGFMT s_aSuicide[2][2] = { static SMSGFMT s_aSuicide[2][2] = {
{ {
{ "%s leaves the battlefield in disgrace after causing the destruction of the %s.", 0 }, { "%s leaves the battlefield in disgrace after causing the destruction of the %s.", 0 },
{ "%s 자폭! %s 불명예스럽게 전장을 떠났다!", 2 }, { "%s self-destructed! %s left the battlefield in disgrace!", 2 },
}, },
{ {
{ "%s will not grace the halls of the honored mechwarriors after self-destructing the %s.", 0 }, { "%s will not grace the halls of the honored mechwarriors after self-destructing the %s.", 0 },
{ "%s 자폭! 비겁자여, 진실로 승리를 원하는가?", 3 }, { "%s self-destructed! Coward, do you truly desire victory?", 3 },
}, },
}; };
@@ -2112,43 +2117,43 @@ static SMSGFMT s_aSuicide[2][2] = {
static SMSGFMT s_aShot[10][2] = { static SMSGFMT s_aShot[10][2] = {
{ {
{ "%s's %s fires the %s and damages the %s of %s's %s.", 0 }, { "%s's %s fires the %s and damages the %s of %s's %s.", 0 },
{ "%s %s의 %s에 %s으로 공격했다", 1 }, // ok! { "%s attacked %s's %s with %s", 1 }, // ok!
}, },
{ {
{ "%s fires the %s's %s and decimates the %s of %s's %s.", 2 }, { "%s fires the %s's %s and decimates the %s of %s's %s.", 2 },
{ "%s이(가) 탑승한 %s, %s %s이(가) 탑승한 %s %s에 피해를 입혔다.", 2 }, { "%s piloting %s damaged %s's %s on %s's %s.", 2 },
}, },
{ {
{ "%s's %s takes a devastating hit in the %s from %s.", 3 }, { "%s's %s takes a devastating hit in the %s from %s.", 3 },
{ "%s %s, %s의 압도적인 공격에 %s에 피해를 입었다.", 4 }, // ok! { "%s's %s took damage to the %s under %s's overwhelming attack.", 4 }, // ok!
}, },
{ {
{ "%s's %s suffers a direct hit to it's %s from %s's %s.", 5 }, { "%s's %s suffers a direct hit to it's %s from %s's %s.", 5 },
{ "%s %s은(는) %s %s에 직접적인 피해를 받았다. 피해 %s!", 6 -100}, { "%s's %s took direct damage from %s's %s. Damage: %s!", 6 -100},
}, },
{ {
{ "%s damages %s's %s.", 7 }, { "%s damages %s's %s.", 7 },
{ "%s, %s %s에 피해를 입혔다..", 7 }, // ok! { "%s dealt damage to %s's %s..", 7 }, // ok!
}, },
{ {
{ "Dense black smoke pours from %s's %s as a result of %s's targeted hit.", 8 }, { "Dense black smoke pours from %s's %s as a result of %s's targeted hit.", 8 },
{ "%s의 절묘한 공격으로 %s %s에서 검은 연기가 퍼지고 있다.", 7 }, // ok! { "Black smoke billows from %s's %s from %s's precise attack.", 7 }, // ok!
}, },
{ {
{ "Fire boils from the damaged %s of %s's %s after %s hits it with a %s.", 9 }, { "Fire boils from the damaged %s of %s's %s after %s hits it with a %s.", 9 },
{ "%s %s을(를) 발사하여, %s이(가) 탑승한 %s %s에 피해를 발생시켰다.", 10 }, // ok! { "%s fired %s, dealing damage to the %s of %s's %s.", 10 }, // ok!
}, },
{ {
{ "Smoke and fire are trailing from %s's %s, all results of the %s blast inflicted by %s.", 11 }, { "Smoke and fire are trailing from %s's %s, all results of the %s blast inflicted by %s.", 11 },
{ "%s의 %s 공격에, 불과 연기가 %s의 기체를 뒤덮고 있다.", 15 }, // ok! { "Fire and smoke engulf %s's mech from %s's %s attack.", 15 }, // ok!
}, },
{ {
{ "%s targets and fires the %s; %s cries in dismay as the %s's %s is damaged.", 10 }, { "%s targets and fires the %s; %s cries in dismay as the %s's %s is damaged.", 10 },
{ "%s %s을(를) 조준하여 %s이(가) 탑승한 %s %s에 맞춘 후 방아쇠를 당겼다.", 10 }, // ok! { "%s aimed %s and pulled the trigger, hitting the %s of %s's %s.", 10 }, // ok!
}, },
{ {
{ "%s takes a severe wound to the %s as %s aims for the %s again.", 13 }, { "%s takes a severe wound to the %s as %s aims for the %s again.", 13 },
{ "%s 다시 %s %s을(를) 조준하여 사격했다. %s, %s에 심각한 피해를 입은 듯.", 14 -100}, { "%s aimed again at %s's %s and fired. %s seems to have taken serious damage to %s.", 14 -100},
}, },
}; };
@@ -2156,19 +2161,19 @@ static SMSGFMT s_aShot[10][2] = {
static SMSGFMT s_aCTF[1][2] = { static SMSGFMT s_aCTF[1][2] = {
{ {
{ "%s captured flag.", 0 }, { "%s captured flag.", 0 },
{ "%s, 깃발 획득!.", 0 }, { "%s captured the flag!", 0 },
}, },
}; };
static SMSGFMT s_aFBK[1][2] = { static SMSGFMT s_aFBK[1][2] = {
{ {
{ "%s destroyed friendly building.", 0 }, { "%s destroyed friendly building.", 0 },
{ "%s, 깃발 획득!.", 0 }, { "%s captured the flag!", 0 },
}, },
}; };
static SMSGFMT s_aEBK[1][2] = { static SMSGFMT s_aEBK[1][2] = {
{ {
{ "%s destroyed enemy building.", 0 }, { "%s destroyed enemy building.", 0 },
{ "%s, 깃발 획득!.", 0 }, { "%s captured the flag!", 0 },
}, },
}; };
const SMSGFMT* pcFMT; const SMSGFMT* pcFMT;
@@ -2602,6 +2607,15 @@ int CRecScoreFull::DoPrint() const
MemoryStream stream(m_pMissionParam, m_nMissionParamSize, 0); MemoryStream stream(m_pMissionParam, m_nMissionParamSize, 0);
params.LoadParameters(&stream); params.LoadParameters(&stream);
#ifdef MW4PRINT
// ---- Database export (before printing) ----
// Export match data to the external MySQL database if configured.
if (g_dbConfig.bEnabled) {
DB_ExportMatch(*this, aRSOs, nPlayers, naTeams, nTeamCount, params);
}
// -------------------------------------------
#endif // MW4PRINT
static int s_nIndex = -1; // for job name - not important!! static int s_nIndex = -1; // for job name - not important!!
if (++s_nIndex >= 10) if (++s_nIndex >= 10)
s_nIndex = 0; s_nIndex = 0;
@@ -2925,8 +2939,7 @@ void CRecScoreFull::DoPrint(HDC hDC, const RECT& rcDraw, const POINT& DPI, int n
Rectangle(hDC, rcMH.left, rcURL.top, rcMH.right, rcURL.bottom); Rectangle(hDC, rcMH.left, rcURL.top, rcMH.right, rcURL.bottom);
static const char s_szURL[] = "Join the worlds greatest Battletech community at WWW.MECHJOCK.COM today!"; DrawText(hDC, g_szPrintBanner, strlen(g_szPrintBanner), &rcURL, DT_CENTER | DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER);
DrawText(hDC, s_szURL, strlen(s_szURL), &rcURL, DT_CENTER | DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER);
SelectObject(hDC, hFontOld); SelectObject(hDC, hFontOld);
// end URL Text // end URL Text
@@ -3478,7 +3491,7 @@ bool CRecScoreFull::LoadPR(const char* pcszFile)
void CRecScoreFull::LoadPrintParams() const void CRecScoreFull::LoadPrintParams() const
{ {
MString strOI(&AssetsDirectory1[0]); MString strOI(&AssetsDirectory1[0]);
strOI += "options.ini"; strOI += "\\options.ini";
LoadPrintParam(strOI, "CellMarginLR", s_nCellMarginLR, U_point(200), U_point(10), U_point(500)); LoadPrintParam(strOI, "CellMarginLR", s_nCellMarginLR, U_point(200), U_point(10), U_point(500));
LoadPrintParam(strOI, "CellMarginTV", s_nCellMarginTV, U_point(200), U_point(10), U_point(500)); LoadPrintParam(strOI, "CellMarginTV", s_nCellMarginTV, U_point(200), U_point(10), U_point(500));
@@ -3498,6 +3511,35 @@ void CRecScoreFull::LoadPrintParams() const
LoadPrintParam(strOI, "TextMarginR", s_rcTextMargin.right, U_point(300), 0, U_cm(100)); LoadPrintParam(strOI, "TextMarginR", s_rcTextMargin.right, U_point(300), 0, U_cm(100));
LoadPrintParam(strOI, "TextMarginB", s_rcTextMargin.bottom, U_point(300), 0, U_cm(100)); LoadPrintParam(strOI, "TextMarginB", s_rcTextMargin.bottom, U_point(300), 0, U_cm(100));
LoadPrintParam(strOI, "TextHeight", s_nTextHeight, U_point(1100), U_point(600), U_point(1500)); LoadPrintParam(strOI, "TextHeight", s_nTextHeight, U_point(1100), U_point(600), U_point(1500));
// Configurable banner/URL text printed at the bottom of each sheet.
// Prefer banner.txt for persistence (game may sanitize unknown options.ini keys).
bool bLoadedBanner = false;
{
char szBannerPath[MAX_PATH];
sprintf(szBannerPath, "%s\\banner.txt", AssetsDirectory1);
FILE* fBanner = fopen(szBannerPath, "rt");
if (fBanner) {
char szBuf[sizeof(g_szPrintBanner)];
if (fgets(szBuf, sizeof(szBuf), fBanner)) {
size_t n = strlen(szBuf);
while (n && (szBuf[n - 1] == '\r' || szBuf[n - 1] == '\n')) {
szBuf[--n] = '\0';
}
if (szBuf[0]) {
strncpy(g_szPrintBanner, szBuf, sizeof(g_szPrintBanner) - 1);
g_szPrintBanner[sizeof(g_szPrintBanner) - 1] = '\0';
bLoadedBanner = true;
}
}
fclose(fBanner);
}
}
if (!bLoadedBanner) {
GetPrivateProfileString("battle tech print", "BannerText",
"Join the worlds greatest Battletech community at WWW.MECHJOCK.COM today!",
g_szPrintBanner, sizeof(g_szPrintBanner), strOI);
}
LoadPrintParam(strOI, "ImageTitleHeight", g_aFonts[FNTI_IMAGE_TITLE].m_nTextHeight, U_point(1500), U_point(900), U_point(2000)); LoadPrintParam(strOI, "ImageTitleHeight", g_aFonts[FNTI_IMAGE_TITLE].m_nTextHeight, U_point(1500), U_point(900), U_point(2000));
LoadPrintParam(strOI, "TableTextHeight", g_aFonts[FNTI_TABLE_TEXT].m_nTextHeight, U_point(900), U_point(600), U_point(1200)); LoadPrintParam(strOI, "TableTextHeight", g_aFonts[FNTI_TABLE_TEXT].m_nTextHeight, U_point(900), U_point(600), U_point(1200));
LoadPrintParam(strOI, "MHTextHeight", g_aFonts[FNTI_MISSION_HIGHLIGHTS].m_nTextHeight, U_point(1200), U_point(800), U_point(1600)); LoadPrintParam(strOI, "MHTextHeight", g_aFonts[FNTI_MISSION_HIGHLIGHTS].m_nTextHeight, U_point(1200), U_point(800), U_point(1600));
+19 -3
View File
@@ -10,15 +10,31 @@
#define IDC_DNT_END 1001 #define IDC_DNT_END 1001
#define ID_FILE_LOGREPORT 32771 #define ID_FILE_LOGREPORT 32771
#define ID_FILE_LOG2DATES 32772 #define ID_FILE_LOG2DATES 32772
#define ID_FILE_DBSETTINGS 32773
#define ID_FILE_BANNERSETTING 32774
#define IDD_DB_SETTINGS 131
#define IDD_BANNER_SETTING 132
#define IDC_DB_ENABLED 1002
#define IDC_DB_HOST 1003
#define IDC_DB_PORT 1004
#define IDC_DB_DATABASE 1005
#define IDC_DB_USERNAME 1006
#define IDC_DB_PASSWORD 1007
#define IDC_DB_TEST 1008
#define IDC_DB_STATUS 1009
#define IDC_DB_EXPORTEVENTS 1010
#define IDC_BANNER_TEXT 1011
// Next default values for new objects // Next default values for new objects
// //
#ifdef APSTUDIO_INVOKED #ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS #ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_3D_CONTROLS 1 #define _APS_3D_CONTROLS 1
#define _APS_NEXT_RESOURCE_VALUE 131 #define _APS_NEXT_RESOURCE_VALUE 133
#define _APS_NEXT_COMMAND_VALUE 32772 #define _APS_NEXT_COMMAND_VALUE 32775
#define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_CONTROL_VALUE 1012
#define _APS_NEXT_SYMED_VALUE 101 #define _APS_NEXT_SYMED_VALUE 101
#endif #endif
#endif #endif
@@ -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"
@@ -28,7 +28,7 @@
// forward declaration // forward declaration
class FPInterface; class FPInterface;
//ッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッ //----------------------------------------------------------------------
// A data channel is a homogeneous collection of objects of a user defined // A data channel is a homogeneous collection of objects of a user defined
// type (data objects). Data channels are uniquely identified by a Class_ID. // type (data objects). Data channels are uniquely identified by a Class_ID.
// //
@@ -52,7 +52,7 @@ class IDataChannel : public InterfaceServer
#define DATACHANNEL_INTERFACE Interface_ID(0x38a718a8, 0x14685b4b) #define DATACHANNEL_INTERFACE Interface_ID(0x38a718a8, 0x14685b4b)
#define GetDataChannelInterface(obj) ((IDataChannel*)obj->GetInterface(DATACHANNEL_INTERFACE)) #define GetDataChannelInterface(obj) ((IDataChannel*)obj->GetInterface(DATACHANNEL_INTERFACE))
//ッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッ //----------------------------------------------------------------------
// Face-data channel interface // Face-data channel interface
// //
// This is an abstraction of a collection of data objects that is // This is an abstraction of a collection of data objects that is
@@ -149,7 +149,7 @@ class IFaceDataChannel : public IDataChannel
#define FACEDATACHANNEL_INTERFACE Interface_ID(0x181358d5, 0x3cab1bc9) #define FACEDATACHANNEL_INTERFACE Interface_ID(0x181358d5, 0x3cab1bc9)
#define GetFaceDataChannelInterface(obj) ((IFaceDataChannel*)obj->GetInterface(FACEDATACHANNEL_INTERFACE)) #define GetFaceDataChannelInterface(obj) ((IFaceDataChannel*)obj->GetInterface(FACEDATACHANNEL_INTERFACE))
//ッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッ //----------------------------------------------------------------------
// Interface class that allows to execute a callback method (Proc) for all // Interface class that allows to execute a callback method (Proc) for all
// face-data channels of an object. // face-data channels of an object.
// //
@@ -21,7 +21,7 @@
// GUID that identifies this ifc (interface) // GUID that identifies this ifc (interface)
#define FACEDATAMGR_INTERFACE Interface_ID(0x1b454148, 0x6a066927) #define FACEDATAMGR_INTERFACE Interface_ID(0x1b454148, 0x6a066927)
//ッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッ //----------------------------------------------------------------------
// Interface for managing face-data channels. // Interface for managing face-data channels.
// Objects that want to have face-data channels should implement this ifc // Objects that want to have face-data channels should implement this ifc
// //
@@ -20,7 +20,7 @@
#include <map> #include <map>
#include "export.h" #include "export.h"
//ッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッ //----------------------------------------------------------------------
// Face-data management implementation // Face-data management implementation
//________________________________________________________________________ //________________________________________________________________________
class IFaceDataMgrImpl : public IFaceDataMgr class IFaceDataMgrImpl : public IFaceDataMgr
@@ -20,7 +20,7 @@
// GUID that identifies this ifc (interface) // GUID that identifies this ifc (interface)
#define PIPELINECLIENT_INTERFACE Interface_ID(0x62383d51, 0x2d0f7d6a) #define PIPELINECLIENT_INTERFACE Interface_ID(0x62383d51, 0x2d0f7d6a)
//ッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッッ //----------------------------------------------------------------------
// This interface should be implemented by objects that flow up the // This interface should be implemented by objects that flow up the
// geometry pipeline and have data members that belong to the pipeline // geometry pipeline and have data members that belong to the pipeline
// channels (geometry, topology, texmap, etc) // channels (geometry, topology, texmap, etc)
@@ -1,7 +1,7 @@
/* /*
* BitMaps.h - MAX bitmap access classes * BitMaps.h - MAX bitmap access classes
* *
* Copyright © John Wainwright 1996 * Copyright © John Wainwright 1996
* *
*/ */
@@ -1,7 +1,7 @@
/* /*
* HashTable.h - HashTable class for MAXScript * HashTable.h - HashTable class for MAXScript
* *
* Copyright © John Wainwright 1996 * Copyright © John Wainwright 1996
* *
*/ */
@@ -4,7 +4,7 @@
* IVisualMSMgr - core interface to the VisualMS manager * IVisualMSMgr - core interface to the VisualMS manager
* IVisualMSForm - interface to an existing form * IVisualMSForm - interface to an existing form
* *
* Copyright © Autodesk, Inc, 2000. John Wainwright. * Copyright © Autodesk, Inc, 2000. John Wainwright.
* *
*/ */
@@ -1,7 +1,7 @@
/* /*
* MAXKeys.h - MAX controller keyframe access classes * MAXKeys.h - MAX controller keyframe access classes
* *
* Copyright © John Wainwright 1996 * Copyright © John Wainwright 1996
* *
*/ */
@@ -1,7 +1,7 @@
/* /*
* MAXMaterials.h - MAX material & map wrapper classes * MAXMaterials.h - MAX material & map wrapper classes
* *
* Copyright © John Wainwright 1996 * Copyright © John Wainwright 1996
* *
*/ */

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