Descent 1 mangles colors during `g3_init_polygon_model`, so this must
not be called on polygons not designed for mangling. Rearrange the
logic to allow Descent 1 to verify that polygon models are well-formed
without using the functions that mangle the colors.
Fixes: 42a2e3ab0b ("Avoid crash loading polymodels with invalid subcalls")
Reported-by: derhass <https://github.com/dxx-rebirth/dxx-rebirth/issues/416>
Windows std::ptrdiff_t is `int` instead of `long` as it should be.
Expand the values out to `long` (which is the same size as `int` on
Win32!) before printing them. This fixes format string warnings.
Reported-by: Ninjared <https://forum.dxx-rebirth.com/showthread.php?tid=857&pid=12555#pid12555>
Fixes: 42a2e3ab0b ("Avoid crash loading polymodels with invalid subcalls")
The highest-level tracking code assumed filenames would always fit in a
char[9]. This was true on DOS, but has not been true in Rebirth for
many years. Builds without fortification caused silent memory
corruption in this case.
Refuse to create highest-level entries if they would cause corruption.
Log a diagnostic telling the user that this happened.
Fix original bug that buddy was limited to 5 hints per program run, not
5 per boss as it probably should have been.
Due to savegame format limitations, this still is not right. Reloading
the game should restore Buddy_gave_hint_count to its value at save time,
but will not.
Bitmaps based on grs_main_bitmap own their data. Bitmaps based on
grs_bitmap do not. Adjust prototypes to prevent initializing a
grs_main_bitmap with data it will not own.
Release builds should never have an object in CT_SLEW state. If they
do, they abort the program. This is an extreme reaction. Change the
logic to report the problem, then coerce the type to CT_NONE and try to
resume operation.
Processing sharepath in SConf is incorrect, because targets can share a
build directory (and therefore an SConf run), but not share a sharepath.
Move sharepath handling out of SConf. Move DXX_USE_SHAREPATH handling
from CGameArg to GameArg, since one game can be built with a sharepath
while the other is built without.
clang warns for using an uninitialized array during the
member-initialization-list, before the union constructor would have done
nothing. clang permits using the still-uninitialized array in the
constructor body, after the union constructor has done nothing.
The same code is generated both before and after this commit, but the
old code produces a warning and the new code is silent.
```
similar/main/physics.cpp:282:5: error: field 'a' is uninitialized when used here [-Werror,-Wuninitialized]
e(a.begin())
```
gcc-4.9 rejects defining a class with a reference member and no
constructor, even though the use of the class uses a
brace-initialization expression to set the reference at construction
time.
Fixes: fa654324ad ("Pass context to wall.cpp:cwframe, cw_removal_predicate")
PHYSFS_init is not guaranteed to succeed. Using PHYSFS functions after
PHYSFS_init fails is likely to fail badly. On Windows, failure may take
the form of a crash in ntdll. Avoid this by exiting gracefully.
Commit 88b5e616a9 ("Replace calls to
window_set_visible in DoPlayerDead() with stop/start_time()") switched
from hiding the game window to only stopping time, and that only if
hiding the window would have stopped time. In multiplayer, this allows
time to continue running. This introduced a crash if the player dies
during the mine countdown. When the player dies, the game checks if the
reactor has been destroyed. If so, the game immediately advances to the
next level. That advance will try to draw the game window if it is
visible. When the window is drawn, if time is not stopped, then game
logic runs. Some of that logic is not prepared to deal with the
inconsistent state present when a new level is only partially loaded.
That inconsistent state then causes a crash. Call stack:
#11 slew_frame () at similar/main/slew.cpp:152
#12 in d2x::object_move_one () at similar/main/object.cpp:1758
#13 in d2x::object_move_all () at similar/main/object.cpp:1956
#14 in d2x::GameProcessFrame () at similar/main/game.cpp:1848
#15 d2x::game_handler () at similar/main/game.cpp:1615
#16 in dcx::window_send_event () at common/include/window.h:116
#17 dcx::event_process () at common/arch/sdl/event.cpp:176
#18 in newmenu_do2 () at similar/main/newmenu.cpp:498
#19 in newmenu_do2<dcx::unused_newmenu_userdata_t> () at common/main/newmenu.h:184
#20 newmenu_do<dcx::unused_newmenu_userdata_t const> () at common/main/newmenu.h:190
#21 newmenu_do<1ul, dcx::unused_newmenu_userdata_t const> () at common/main/newmenu.h:196
#22 net_udp_wait_for_requests () at similar/main/net_udp.cpp:4563
#23 net_udp_level_sync () at similar/main/net_udp.cpp:4607
#24 in multi_level_sync () at similar/main/multi.cpp:3458
#25 in d2x::StartNewLevelSub () at similar/main/gameseq.cpp:1803
#26 in d2x::StartNewLevel () at similar/main/gameseq.cpp:2018
#27 in d2x::AdvanceLevel () at similar/main/gameseq.cpp:1648
#28 in d2x::DoPlayerDead () at similar/main/gameseq.cpp:1721
The root cause of this is the layering violation:
- Killing the player can have the side effect of advancing the level
- Advancing the level can have the side effect of calling multiplayer code while the level data is in an inconsistent state
- Calling multiplayer code can cause the event system to redraw the game
- Redrawing the game can cause game logic to run
Hack around this by restoring the logic that hides the game window, so
that the window is not redrawn and the game logic is not run. This does
not fix the layering problem, but prevents crashing affected users. To
avoid undoing the feature from the breaking commit, hide the window only
when advancing to a new level, rather than unconditionally. A player
advancing to a new level already lacks the move-at-cold-start capability
even on successfully escaping the mine, so no functionality is lost with
this change. Players who are dead and do not advance to a new level
retain that capability.
Fixes: 88b5e616a9 ("Replace calls to window_set_visible in DoPlayerDead() with stop/start_time()")
Reported-by: Ninjared <https://forum.dxx-rebirth.com/showthread.php?tid=1097>
- Raise the player limit to 8.
- Remove the logic that forces player counts up/down when switching
between cooperative and deathmatch game modes.
- Add heuristics to add start positions for the extra players, since
standard maps will not have the required number of starts.