Commit Graph
4820 Commits
Author SHA1 Message Date
e7095999df delete four out-of-line declarations that repeat the class body
Each of these says again, outside the class, what the class already declares:

    template <int N>
    void TestTableTemplate<N>::SetRefresh();

SetRefresh and Init are declared as members a few dozen lines above, so these
add nothing. A member named out of line has to be a definition; MSVC lets the
declaration through, clang does not.

None of the three templates ever defines these members generically. Every
instantiation supplies its own, as an explicit specialization next to the
screen that uses it, and those are untouched:

    template<> void DropDownTemplate<DROPDOWNNR_APPEARANCE>::SetRefresh()
                                            { gfIMPPrejudice_Redraw = TRUE; }

The mpSelf lines that follow each of these look similar but are definitions of
a static data member, so they stay.

Verification:

    grep -rn 'Template<N>::' --include=*.h Laptop/    # only mpSelf definitions
    ninja -C build parse         # out-of-line class gone: 28 -> 24 sites
    ninja -C build -k 0          # Release, four applications, green
    ninja -C build-debug -k 0    # Debug, four applications, green

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 19:29:55 -03:00
1bf28bc07a ask whether strstr found the tag, not whether it is positive
strstr returns a pointer into the string or NULL, and these four tests compare
that pointer to 0 with >. Ordering a pointer against a null pointer constant
is not something C++ defines; MSVC allows it, clang rejects it.

The intent is plainly "did this attribute name contain the tag", and the
result is the same either way, since the only pointer these can produce that
is not greater than zero is the null one. != NULL says it directly, and reads
like the strcmp(name, "...") == 0 tests it sits between.

strstr rather than strcmp is deliberate here: the attributes it looks for are
numbered, usAttachment1 through usAttachment4 and usResult1 upwards, so an
exact comparison would not match them. That is unchanged.

Verification:

    grep -rn 'strstr([^)]*)[ \t]*[><]' --include=*.cpp --include=*.h .   # nothing
    ninja -C build parse         # pointer-ordering class gone: 32 -> 28 sites
    ninja -C build -k 0          # Release, four applications, green
    ninja -C build-debug -k 0    # Debug, four applications, green

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 19:29:55 -03:00
1d6ff6be3c let CIniReader take its strings as pointers to const
STR8 is char*, so const STR8 is char* const: a const pointer to a mutable
string, which is not what any of these sixty parameters wanted. What they
wanted is const CHAR8*, a pointer to a string they will not write to, and
that is what all of them do.

Under the MSVC compatibility rules clang-cl applies, a string literal still
converts to char*, so most calls survive this mistake untouched. An expression
of type const char* does not, and Intro.cpp has thirteen of them:

    inireader.ReadString("INTRO_BEGINNING", "INTRO_REBEL_CRDT",
                         no_defaults ? "" : "INTRO\\Rebel_cr");

The conditional is a const char*, not a literal, so it has nowhere to bind and
the call does not compile. The other two arguments are literals and are
accepted, which is why only the third one was ever reported.

The invariant: in these two files, every parameter spelled const STR8 becomes
const CHAR8*, and nothing else changes. No body assigns to one of them, so
none needed rewriting; STR8 input_buffer in the five-argument ReadString is
genuinely an output and keeps its type. Three commented-out lines still say
const STR8 and were left as they are.

Verification:

    grep -n 'const[ \t]*STR8' Utils/INIReader.h Utils/INIReader.cpp
        # three hits, all on lines beginning with //

    git show HEAD -U0 | grep '^[+-][^+-]' |
      sed -E 's/const[ \t]+(STR8|CHAR8\*)/const/g; s/^[+-]//' |
      sort | uniq -c | awk '$1 % 2'          # no output

    ninja -C build parse         # ReadString class gone: 45 -> 32 sites
    ninja -C build -k 0          # Release, four applications, green
    ninja -C build-debug -k 0    # Debug, four applications, green

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 19:29:55 -03:00
c99f939fe6 stop pasting a directive name onto the comma after it
DIRECTIVE_TEXT builds four enumerator names from one directive name:

    #define DIRECTIVE_TEXT(id)  RCDT_##id##, RCDT_##id##_EFFECT, ...

The last ## on the first name has nothing to paste onto but the comma that
follows, and RCDT_GATHER_SUPPLIES, is not a token. The other three pastes are
well formed; only this one runs off the end of the name.

MSVC concatenates the text and re-lexes it, so it recovers the identifier and
the comma and produces the right enumerators; clang diagnoses it. Removing the
stray ## gives the same ten enumerations, and MISSION_TEXT just below already
spells it this way.

Verification:

    grep -rn '##[A-Za-z_]*##[,)]' --include=*.h --include=*.cpp .   # nothing
    ninja -C build parse         # token-paste class gone: 55 -> 45 sites
    ninja -C build -k 0          # Release, four applications, green
    ninja -C build-debug -k 0    # Debug, four applications, green

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 19:29:55 -03:00
3db2d60a4d drop the extern "C" wrapper whose other half is commented out
DEBUG.H once wrapped its declarations in extern "C", and DEBUG.cpp wrapped the
matching definitions to agree. At some point the header's pair was commented
out, both the opening brace and the closing one:

    /*
    #ifdef __cplusplus
    extern "C" {
    #endif
    */

That had to happen, because the block would otherwise have swallowed
<stdexcept>, <list> and namespace sgp further down the header. The wrapper in
DEBUG.cpp was left behind, so seven variables are declared with C++ linkage in
the header and defined with C linkage in the source. That is ill-formed. MSVC
takes the linkage of the first declaration it sees, which is the header's, so
the mangled names still agree and the tree still links; clang refuses.

The header is the only place these seven are declared, so removing the
wrapper leaves everything with the C++ linkage it already had. Nothing here
needs to be callable from C.

A second such wrapper remains further down the file, inside #ifdef SGP_DEBUG.
Nothing in the build defines SGP_DEBUG and nothing it contains is declared in
a header, so it is neither compiled nor mismatched, and it is left alone.

Verification:

    ninja -C build parse         # language-linkage class gone: 60 -> 55 sites
    ninja -C build -k 0          # Release, four applications, green
    ninja -C build-debug -k 0    # Debug, four applications, green

The seven diagnostics sit on five lines, three of them sharing a single
declaration, and the parse target counts one site per line.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 19:29:55 -03:00
e56a372871 give the XML tag map and the writer buffer a name
Both of these bound a non-const reference to a temporary, which MSVC accepts
and clang does not, and which leaves the reference dangling once the full
expression ends.

PropertyContainer::initFromXMLFile and writeToXMLFile take their tag map by
non-const reference because the accessors on it insert default tag names as
they are asked for, so it cannot be const and it cannot be a temporary. All
eight call sites passed a freshly built one; they now declare it. Each keeps
its own object, so a map filled in by one call cannot leak into the next, the
same as when each call built its own temporary.

XMLWriter::writeToFile bound std::string& to what stringstream::str() returns
by value. Declared as a value it is initialised straight from the return with
no copy, and const because only c_str() and length() are asked of it.

Verification:

    grep -rn 'PropertyContainer::TagMap()' .   # nothing
    ninja -C build parse         # no i18n or XMLWriter sites remain
    ninja -C build -k 0          # Release, four applications, green
    ninja -C build-debug -k 0    # Debug, four applications, green

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 19:29:55 -03:00
b5ea70aa44 declare the postal service iterators as values, not as references
PostalService.h names every type twice, once plainly and once as a reference:
RefToDestinationStruct is DestinationStruct&, RefToShipmentList is
ShipmentList&. That scheme was extended to the iterators, and there it does
not work. Every one of the seventeen uses looks like this:

    RefToShipmentListIterator sli = _Shipments.begin();

begin() returns a value, so this binds a non-const reference to a temporary.
MSVC allows it as an extension; the temporary still dies at the end of the
full expression, which leaves sli referring to a dead object for the whole
rest of the function. It works only because nothing has reused the stack slot
yet. clang rejects it outright.

Iterators are already handles into their container, so a reference to one buys
nothing: the plain typedef says exactly what these seventeen variables want to
be. DESTINATION and SHIPMENT now take theirs by value, which changes nothing
for either, as both only dereference the iterator they are given.

Two of the reference typedefs, RefToDestinationDeliveryInfoTableIterator and
RefToDeliveryCallbackDataListIterator, had no uses at all. They are removed
rather than left behind, since their only possible use is the pattern this
commit removes.

Verification:

    grep -rn 'RefTo[A-Za-z]*Iterator' --include=*.cpp --include=*.h .   # nothing
    ninja -C build parse         # bind-to-temporary class gone: 91 -> 60 sites
    ninja -C build -k 0          # Release, four applications, green
    ninja -C build-debug -k 0    # Debug, four applications, green

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 19:29:55 -03:00
70b11ee120 make narrowing conversions in braced initialisers explicit
A braced initialiser does not allow a narrowing conversion unless the value
is a constant expression the compiler can prove fits. Every site here holds a
runtime value: WORLD_COLS is the global guiWorldCols, the laptop screen
coordinates are built from iScreenWidthOffset, the sector limits come from the
externalised options. MSVC accepts all of it silently; clang rejects it, and
it is ill-formed.

Nothing about the generated code changes. MSVC was already performing these
conversions; the casts only say so out loud, at the 73 places where it was
happening implicitly.

The invariant: each site is wrapped in a static_cast to the element type the
initialiser already had, and nothing else is touched. No type is widened, no
expression is reassociated, no value is clamped or checked. static_cast rather
than a C-style cast so that a later reader can grep for the narrowings, and so
that none of these can quietly become a reinterpret_cast if a type changes.

Verification:

    # every changed line differs only by inserted casts and their parentheses
    git show HEAD -U0 | grep '^[+-][^+-]' |
      sed -E 's/static_cast<[A-Za-z0-9_]+>//g; s/[()]//g; s/^[+-]//' |
      sort | uniq -c | awk '$1 % 2'          # no output

    git show HEAD -U0 | grep -c '^+[^+]'     # 38 lines, 73 casts

    ninja -C build parse                     # narrowing class gone: 129 -> 91 sites
    ninja -C build -k 0                      # Release, four applications, green
    ninja -C build-debug -k 0                # Debug, four applications, green

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 19:29:55 -03:00
5e2982c509 take popup option names by const reference, not by pointer
POPUP_OPTION copies the name it is given -- `this->name = *newName` into a
std::wstring member -- but its constructor took a std::wstring*, so 64 call
sites spelled the argument `&std::wstring( pStr )`. Taking the address of a
temporary is ill-formed, and clang refuses it outright:

    error: taking the address of a temporary object of type 'std::wstring'

It happens to work under MSVC because the temporary outlives the call, dying
at the end of the full expression rather than before the copy. Nothing was
corrupt; the code was just spelling "pass me a string" in a way the language
does not allow.

A const reference says what these functions actually want, so the call sites
lose the &, and the two places that allocated a string purely to have an
address to pass -- POPUP_SUB_POPUP_OPTION's default constructor, which carried
a "TODO: possible memmory leak!" saying as much, and a "Dummy generator"
option -- stop leaking one.

Converted: POPUP_OPTION's constructor and setName, POPUP::addOption and
addSubMenuOption, and both POPUP_SUB_POPUP_OPTION constructors. The popupDef
family in popup_definition.* keeps its std::wstring* because it owns what it
is handed and stores the pointer; that is a different design and a different
change. The three calls it makes into the converted API now dereference.

Verification:
    grep -rn '&std::wstring' --include=*.cpp --include=*.h .   # nothing
    ninja -C build parse             # no popup_* or SkillMenu sites remain
    ninja -C build -k 0              # Release, four applications, green
    ninja -C build-debug -k 0        # Debug, four applications, green

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 19:29:55 -03:00
83b637aa73 libsmacker: allow overlapping copies in the 0x40 palette opcode
The color-shift opcode copies a run of palette entries from the previous
frame's palette to the current one. libsmacker rejected the copy when the
source and destination ranges overlapped, aborting the whole palette decode
and leaving the palette half-updated -- so every frame from the first such
opcode on rendered with a mix of the new and stale palette.

The overlap check is bogus: the copy reads from oldPalette, a snapshot taken
at the top of the function, and writes into s->palette, a separate buffer, so
overlapping ranges are harmless (and it is a memmove regardless). ffmpeg and
the original SMACKW32.DLL have no such check.

Several of the videos that ship with the game (Rebel_cr, Omerta, Prague) use
these overlapping copies, and showed washed-out colours with the previous
frame's palette bleeding through. Drop the overlap clause, keep the real
256-entry bounds checks.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 19:01:37 -03:00
Marco Antonio J. Costaandmajcosta 4ff2853b70 play smacker video with libsmacker instead of SMACKW32.DLL
Drops the last piece of the proprietary Smacker SDK: SMACKW32.LIB, its
header sgp/SMACK.H, and with them the SMACKW32.DLL the game needed at
runtime. Bink is untouched and still needs binkw32.

The two libraries divide the work differently, so Cinematics.cpp changes
more than the call names. SMACKW32.DLL played a file: it kept the playback
clock (SmackWait), blitted converted 16bpp pixels into a surface we handed
it (SmackToBuffer) and pushed the audio to DirectSound itself. libsmacker
only decodes, so this module now:

- keeps the clock. Frames are advanced against GetTickCount() from the
  moment the flic starts, skipping frames if the game fell behind, which
  is what SmackWait/SmackDoFrame did internally.
- blits itself. Frames come out 8bpp palettised, so the palette is
  converted with Get16BPPColor() and the frame is written into the frame
  buffer, clipped to the screen. The Y-scaling flags are not handled;
  none of the videos shipping with the game set them.
- plays the audio itself, through the SoundPlayFromBuffer() added earlier.
  libsmacker hands out audio a frame at a time, so the whole track is
  decoded up front, with the video track disabled to keep that pass cheap,
  and given a WAV header so the sound module can take it.

libsmacker reads from memory, which lets the file be read straight out of
the VFS. That removes the dance where the .smk was first copied to a real
file under Temp/ because SmackOpen() could only open a path.

SmkInitialize() loses its window and screen size arguments, which only
existed for SmackBufferOpen(). SmkOpenFlic(), SmkSetBlitPosition() and
SmkGetFreeFlic() are no longer declared in the header; nothing outside the
module called them. SMKFLIC is now opaque, Intro.cpp only holds pointers.

The unused SMACK.H include in Cinematics Bink.cpp goes away as well.

Tested by running the Sirtech splash screen (SPLASHSCREEN.SMK, 640x480,
15 fps, one 44.1kHz 16 bit stereo track) under Wine: picture, palette,
placement and playback speed are right.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

refactor
2026-07-23 19:01:37 -03:00
13c4be7382 soundman: allow playing a sound file held in memory
Smacker video carries its audio as PCM that the video decoder produces
itself, so there is no file for the sound module to open. Add
SoundPlayFromBuffer(), which streams from a caller-owned memory buffer.

It deliberately does not go through the sample cache: a full length intro
video decodes to close to 20 MB of PCM, which does not fit in the cache's
memory budget and would evict everything else on the way to failing. The
channel bookkeeping already has a notion of a stream with no cache slot
behind it (uiSample == -1), which is what streamed files use, so the buffer
simply stays the caller's property for as long as the sound plays.

To share the parameter handling, everything SoundStartStream() did after
opening the stream moves unchanged into SoundStartOpenedStream().

No caller yet.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 19:01:37 -03:00
de78480c9c vendor libsmacker 1.2
libsmacker is an open reimplementation of the parts of smackw32.dll needed
to get frames and audio out of an .smk file. Vendoring it here is the first
step to dropping the proprietary SMACKW32.LIB/SMACKW32.DLL dependency.

Nothing links against it yet.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 19:01:37 -03:00
9c1403b4ec do not hand clang the MSVC-only forward declaration in VFS
vfs_debug.h forward declares std::exception under #ifdef _MSC_VER. clang-cl
defines _MSC_VER too, and rejects the declaration:

    vfs_debug.h(34,15): error: forward declaration of class cannot have a
                               nested name specifier

so any tool built on clang stops at the first file that reaches sgp/DEBUG.H,
which is nearly all of them. Guarding on __clang__ as well leaves the MSVC
build byte for byte identical and lets include-what-you-use parse the tree.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 09:14:21 -03:00
aad39ac3bd declare gFullBaseTileValues extern like every other global here
tiledef.h is included by 1900 objects, and each one was compiling a tentative
definition of gFullBaseTileValues rather than a declaration of it. The array
is defined once in TileDat.cpp, and every other global in the same block is
already declared extern; this one was missed.

MSVC accepts it and merges the tentative definitions, so nothing was visibly
broken. A conforming front end rejects it outright:

    tiledef.h(180,12): error: definition of variable with array type needs
                              an explicit size or an initializer

which is what turned it up.

Verification: ninja -C build -k 0, all four applications link.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 09:14:21 -03:00
Marco Antonio J. Costaandmajcosta 3d3e1bbfc6 refactor Translate()
it returns true but no consumers use it. its return type is void, then
2026-07-21 18:39:50 -03:00
Marco Antonio J. Costaandmajcosta 738225d2a2 move ImportStrings to i18n 2026-07-21 18:39:50 -03:00
Marco Antonio J. Costaandmajcosta 4be9b106f4 give more local functions internal linkage 2026-07-21 18:39:50 -03:00
Marco Antonio J. Costaandmajcosta af4eeb09f4 make local-only functions static 2026-07-21 18:39:50 -03:00
Marco Antonio J. Costaandmajcosta 15821498a3 text declarations go into text.h 2026-07-21 18:39:50 -03:00
Marco Antonio J. Costaandmajcosta 54bdce6c46 cleanup: dead code removal 2026-07-21 18:39:50 -03:00
Marco Antonio J. Costaandmajcosta 433de0e67b use exhaustive switch instead of if statements 2026-07-21 18:39:50 -03:00
Marco Antonio J. Costaandmajcosta 30e5d8f91c i18n: we already have one Language enum, no need for two 2026-07-21 18:39:50 -03:00
Marco Antonio J. Costaandmajcosta 506ea842b8 i18n: pull some TUs that do not belong in Utils 2026-07-21 18:39:50 -03:00
Marco Antonio J. Costaandmajcosta 9adc1ad998 node20 is deprecated, clear the warnings
bump action versions and change the MSVC action to a composite one that doesn't use node at all

also remove msbuild which we don't need
2026-07-21 14:45:04 -03:00
Marco Antonio J. Costaandmajcosta 8d1877d26d read language from Language.ini file
to avoid having to ship a whole ja2.ini for languages that
currently don't

command-line /language:german still works, but INI file is
prioritized

format:

```
[Language]
LANGUAGE = ITALIAN
```
2026-07-21 14:42:52 -03:00
Marco Antonio J. Costaandmajcosta d03989051a remove Languages from CI
no need anymore
2026-07-21 11:23:08 -03:00
Marco Antonio J. Costaandmajcosta 5da2ee8bf6 better initialization of language defaults 2026-07-21 09:46:41 -03:00
Marco Antonio J. Costaandmajcosta aa0aac2bfe remove unused includes 2026-07-21 09:46:41 -03:00
ee098125e6 Strip dead per-language .slf entries from gGameLibaries
InitializeFileDatabase, the only reader of gGameLibaries[], is called
nowhere in the tree — VFS replaced this legacy loader. Delete the
7 #ifdef GERMAN/POLISH/DUTCH/ITALIAN/RUSSIAN/FRENCH/CHINESE entries
outright rather than runtime-selecting them.

NPC.h: two commented-out #if defined(CRIPPLED_VERSION)||defined(RUSSIAN)
triplets. AimMembers.cpp: two commented-out #ifdef POLISH character-remap
switch blocks. All already-dead. Verify grep for language macros outside
i18n/ now returns only unrelated hits (filename literal, dev-tool CLI flag,
stray comment, historical prose) — no #ifdef guards left.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 09:46:41 -03:00
Marco Antonio J. Costaandmajcosta bada3ef31a cleanup: remove last remnants of language preprocessor definitions
good riddance
2026-07-21 09:46:41 -03:00
Marco Antonio J. Costaandmajcosta 00a805cc39 remove lying, outdated or superfluous comments
no more guards, no more cpp files included
2026-07-21 09:46:41 -03:00
fd2c74727e Make LANGUAGE switchable in runtime (#653)
squashed into a single commit because doing it in steps that all
compiled involved a lot of boilerplate that is pointless to commit to
the repository. GH still has the PR for reference.

g_lang, MAX_MESSAGES_ON_MAP_BOTTOM, and GetLanguagePrefix() were
compile-time constants selected by the ENGLISH/GERMAN/... build
define. They're now runtime, defaulting to the same per-exe value the
define used to pick, and overridable at startup from [Ja2 Settings]
LANGUAGE in Ja2.ini.

-

XMLTacticalMessages is filled at runtime from NewTacticalMessages.xml,
never from compiled-in per-language data: all 8 per-language definitions
were the identical all-zero { L"" }. Delete them and define one shared
buffer in Utils/XML_Language.cpp (the loader) instead of pointer-rebinding
it like the static tables — this drops 9 dead 800KB zero-buffers (8
namespaced copies in LanguageStrings.cpp plus the standalone one) and
leaves no bind-ordering hazard for the XML load path.

-

ExportStrings.cpp privately recompiled one language's full text table
by #including the raw _<LANG>Text.cpp inside namespace Loc, keyed off
the exe-level ENGLISH/GERMAN/... compile macro (whichever the build
happened to select). That's redundant with the pointer globals every
other subsystem already uses (Text.h / LanguageStrings.cpp).

Drop the private copy; the unqualified table names in Loc::ExportStrings
now resolve to the global pointer externs, which BindLanguageStrings has
already rebound to the runtime g_lang by the time this runs (EXPORT_STRINGS
ini flag, checked after GetRuntimeSettings in sgp.cpp). gs_Lang (used only
by Loc::Translate for the Polish/Russian byte remap on raw .edt exports) is
now derived from g_lang via ToLocLanguage, so the export always matches
whatever language is actually active instead of a compile-time pick.

-

Editor/popupmenu.cpp and Strategic/Scheduling.cpp kept their own
call-site extern of gszScheduleActions as CHAR16[NUM_SCHEDULE_ACTIONS][20]
after the real definition changed into a rebindable pointer
(CHAR16 (*)[20], LanguageStrings.cpp). MSVC decays the outer array
dimension when mangling globals, so both declarations produce the same
symbol (?gszScheduleActions@@3PAY0BE@_WA) and the mismatch linked
silently -- but the array-typed TUs then indexed the 4-byte pointer
slot itself as string data, so the editor schedule popup and the map
schedule message text read garbage.

-

add text.def to be single-source of truth on symbol names and use it
 .much simpler, less error prone if adding more strings

-

add pseudo interface for language state. MAX_SAGES_ON_BOTTOM must always
 change in lockstep with g_lang. this isn't foolproof but better

---------

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-07-21 05:33:03 -03:00
steph-pgandAsdow ba64ed53c6 Items can now be taken from non colapsed POWs 2026-07-02 19:16:55 +03:00
Asdow c61f57bd9b Whitespace adjustment 2026-06-22 00:21:31 +03:00
Asdow 4d5593ebcb Fix render misalignment at 960x540 resolution
Should also work for any custom resolution that suffers from the same issue
2026-06-22 00:21:31 +03:00
Asdow 601fabf401 Fix tile rendering misalignment at 1440x900 and 1600x900 resolutions
Shamelessly stolen from Stracciatella code
2026-06-22 00:21:31 +03:00
steph-pgandAsdow eb8ecb31f0 fix POWs in LOS keeps you in turnbased mode 2026-06-20 20:03:16 +03:00
Asdow 2801af552e Set moved item old entry to not existing 2026-06-20 17:11:37 +03:00
Asdow ef30192b29 Leave merc equipment to current sector in UB 2026-06-20 08:49:56 +03:00
Asdow 392ba66df3 Enable dismissing mercs in UB before game start
Jerry Melo complains about too many mercs if player has hired over 6 mercs and refuses to fly. This allows player to dismiss mercs until the pilot is happy.
2026-06-20 08:49:56 +03:00
Asdow d4dd5f07df Disable contract renewal in UB 2026-06-20 08:49:56 +03:00
db29feed11 Don't strip robot's installed components on mapscreen drop-all
The mapscreen "drop everything" hotkey (Shift+W) looped over every
inventory slot from HELMETPOS to NUM_INV_SLOTS and dumped each one.
Madlab's robot stores its installed gear in those same slots - ammo (14),
targeting (15), chassis/armour (16) and utility (17). Dropping these left
the robot defenceless, and the player cannot re-install the components
through normal inventory, so the loss was permanent.

Skip the robot's component slots in the drop loop; only its general cargo
slot (ROBOT_INVENTORY_SLOT) may still be emptied. Regular mercs are
unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 23:06:33 +03:00
Asdow 1fc5f939bf Use new RandomGridNoUnloadedSector() for autoresolve
* Load required mapinfo for checking suitable gridnos
* Modify SOLDIERTYPE::DropSectorEquipment( ) to take an external gridno when placing items into an unloaded sector
2026-06-15 22:01:07 +03:00
Asdow 9e0105caec Add function for choosing random gridno in an unloaded sector 2026-06-15 22:01:07 +03:00
Asdow 0cc7fb4e39 Add function for loading world height data 2026-06-15 22:01:07 +03:00
Asdow db15679ec1 Add missing Iter->Exists() checks 2026-06-12 15:52:24 +03:00
Asdow 6a8a22aba2 Move iter->exists() check to first 2026-06-12 15:52:24 +03:00
Asdow 9b654ff3f1 Fix typo 2026-06-12 15:51:03 +03:00
Asdow a67f4b8a8f Formatting 2026-06-12 15:51:03 +03:00