Descent 2 has a hack, present as far back as I can trace, that
suppresses starting sounds during level load. The original reason was
not recorded, but this hack has the useful side effect that it avoids
using uninitialized data when set_sound_sources tries to use a Viewer
that has not been reset for the objects of the new level.
Descent 1 lacks this hack, so an invalid Viewer is used, which may
trigger a valptridx trap if the undefined data has an invalid segment
number, and could cause memory corruption in builds which do not
validate the segment index. The valptridx trap:
```
terminate called after throwing an instance of 'valptridx<dcx::segment>::index_range_exception'
what(): similar/main/digiobj.cpp:389: invalid index used in array subscript: base=(nil) size=9000 index=65021
```
The backtrace leading to the trap:
```
d1x::digi_link_sound_common (viewer=..., so=..., pos=..., forever=<optimized out>, max_volume=<optimized out>, max_distance=..., soundnum=42, segnum=...) at similar/main/digiobj.cpp:389
0x00005555555a4e2d in d1x::digi_link_sound_to_pos2 (vcobjptr=..., max_distance=..., max_volume=32768, forever=1, pos=..., sidenum=4, segnum=..., org_soundnum=121) at similar/main/digiobj.cpp:483
d1x::digi_link_sound_to_pos (soundnum=soundnum@entry=121, segnum=..., sidenum=sidenum@entry=4, pos=..., forever=forever@entry=1, max_volume=32768) at similar/main/digiobj.cpp:490
0x00005555555c140d in d1x::set_sound_sources (vcsegptridx=..., vcvertptr=...) at similar/main/gameseq.cpp:817
d1x::LoadLevel (level_num=<optimized out>, page_in_textures=1) at similar/main/gameseq.cpp:1022
0x00005555555c2654 in d1x::StartNewLevelSub (level_num=-1, page_in_textures=<optimized out>) at similar/main/gameseq.cpp:1865
```
Backport this hack into Descent 1. Ultimately, the hack should go away
and data should be loaded in an order that does not access undefined
memory.
Reported-by: Spacecpp <https://github.com/dxx-rebirth/dxx-rebirth/issues/463>
clang-9 reports:
```
similar/main/mglobal.cpp:210:44: error: 'report_error_uses_exception' is a protected member of 'valptridx_specialized_type_parameters<unsigned char, 90, valptridx_untyped_utilities::report_error_style::exception, valptridx_untyped_utilities::report_error_style::exception>'
template <typename T, bool = valptridx<T>::report_error_uses_exception::value>
^
similar/main/mglobal.cpp:229:16: note: in instantiation of default argument for 'instantiation_guard<dcx::active_door>' required here
template class instantiation_guard<dcx::active_door>::type::index_range_exception;
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
common/include/fwd-valptridx.h:42:2: note: constrained by protected inheritance here
protected valptridx_specialized_types<managed_type>::type
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
common/include/cpp-valptridx.h:175:8: note: member is declared here
using report_error_uses_exception = std::integral_constant<bool,
```
Add a `using` statement to switch `report_error_uses_exception` to
`public` access. Nothing else uses it, and there is no design purpose
served by keeping it `protected`.
Each axis can act as two buttons in both ways.
For example, a player might map slide left and slide right to J1 -A1 and J1 +A1 as button presses instead of the slide L/R axis.
This is mostly to fix XBox 360 Controller Left and Right triggers. But it can work on every axis if the player wishes to bind them.
If the level was not the most recently played, a save is forced so that
it can be marked as most recently played. However, the logic to force
the save also forced an update of the highest-level field, even if that
reduced it.
- Rename the parameter to clarify its meaning.
- Add comments explaining the logic to force the save.
- Only update the highest-level field when the update would increase the saved value
The subcanvas is positioned based on the dimensions of the containing
window, so it must be repositioned if the outer window is resized.
Reported-by: vLKp <https://github.com/dxx-rebirth/dxx-rebirth/issues/394>
Fixes: f491059ed7 ("Enable building with SDL2")
exit_segnum is set during load_endlevel_data, which currently runs too
early for this to depend on the exit used, and thus to be player-unique.
That data should be loaded at need, when the level ends, rather than
during level setup. This can be addressed later, when support for
multiple exits is improved.
transition_segnum is a function of how the player exited the mine, since
there could be multiple exit tunnels, although current code appears not
to handle that well in other places. Therefore, it needs to be
per-player data, not part of the level data, where it would not depend
on the player exiting.
This could be a shared variable instead, since it cannot be directly
influenced by gameplay. However, it is influenced by the game mode, and
keeping shared variables that are mode-specific would be more complexity
for very little savings.
As documented in zico's commit 38fabd7c49, robot smart mines have a
different ID number than player smart mines. Rename the test functions
to clarify that they only recognize player smart mines, but not robot
smart mines.
git grep -l is_proximity_bomb_or_smart_mine | xargs sed -i -e 's/is_proximity_bomb_or_smart_mine/is_proximity_bomb_or_player_smart_mine/g'
`flags` only needs to be 1 bit wide, so switch from `int` to `uint8_t`.
Shrinking to a single bit would not save more space, but would
complicate the code.
The number of hostages in a game is a function of the the game's levels,
not any particular player. Move it to d_game_unique_state and rename it
to total_hostages.
The number of hostages on a level is a function of the level, not any
particular player. Move it to d_level_unique_object_state and rename it
to total_hostages.
The number of robots accumulated in a game is a function of the the
game's levels, not any particular player. Move it to
d_game_unique_state and rename it to accumulated_robots.
The number of robots accumulated on a level is a function of the level,
not any particular player. Move it to d_level_unique_object_state and
rename it to accumulated_robots.
This removes the need to walk all objects when creating a new one, since
each object can have a private generation counter, unaware of other
objects. For compatibility with demos, mix in the object's index when
writing the signature value.
This was requested by a user in early 2018. However, the proposed
prototype was susceptible to various forms of desynchronization, and was
unsuitable for merging. No further revisions were proposed, and the
feature languished. This commit enables the guidebot in cooperative
games and addresses the known synchronization problems, as well as some
other bugs that were uncovered during light testing. This is classified
as an experimental feature because it has not been heavily tested in
complicated games.
Requested-by: cfeuersaenger <https://github.com/dxx-rebirth/dxx-rebirth/issues/364>
In multiplayer, the host sends a destroy message for both sides of the
wall. `do_exploding_wall_frame` processes both, but
`num_exploding_walls` is only decreased by 1, causing an assertion
failure at the end. Remove the assertion, since the wall does not
explode instantly on join, despite being marked as WALL_EXPLODING.
Remove use of object_guidebot_cannot_reach and instead track the
reachability of the object as a separate flag. This allows the game to
remember when an object was found, but unreachable. Previously, it
would store only that some unreachable object was found. Now, it stores
the index of the unreachable object. This extra information is not used
yet.
Reported-by: Dainslaif <https://github.com/dxx-rebirth/dxx-rebirth/issues/421>
Fixes: c3cead4319 ("Move Escort_goal_index to d_unique_buddy_state")
gcc-9 warns on taking the address of an unaligned member in a packed
structure. This structure does not need to be packed. Remove
__attribute__((packed)) and fix the code to implement I/O correctly
without packing.
gcc-9 rejects `std::enable_if<false,
std::integral_constant<std::integral_constant, 1> 0>::type` before it
notices that the whole expression is eliminated due to SFINAE. Use
`std::common_type` to coerce the inner integral_constant to an
appropriate integer type, which allows the expression to be well-formed
enough to reach the SFINAE check from enable_if, then be silently
removed from the overload resolution set.
Utility xrange, inspired by the Python2 feature of the same name,
provides an object that returns successive values from [start, end). It
is useful when the end index is known in advance, and is particularly
helpful when that index is expensive to recompute.
gcc-7 needs an additional cf_assert to inform it that e.idx is
constrained. Without this, it assumes e.idx could have any positive
value, then issues a fatal warning when INT_MAX does not fit in the
provided buffer.
common/arch/sdl/joy.cpp: In function 'void dcx::joy_init()':
common/arch/sdl/joy.cpp:281:6: error: '%u' directive output may be truncated writing between 1 and 10 bytes into a region of size between 0 and 4 [-Werror=format-truncation=]
common/arch/sdl/joy.cpp:281:6: note: directive argument in the range [1, 2147483647]
common/arch/sdl/joy.cpp:333:13: note: 'snprintf' output between 6 and 24 bytes into a destination of size 8
Commit 47a6f744d split out redundant code, but accidentally stored
temporaries in a `signed short` instead of a `fix` as they should have
been. This truncated some values, causing odd results whenever
quaternions were used. Fix the problem by storing the intermediate
results in a `fix`.
Fixes: 47a6f744d8 ("Factor out vms_quaternion_from_matrix division")
Reported-by: Ninjared <https://forum.dxx-rebirth.com/showthread.php?tid=1113>
Remove the fallback to Boost.Begin. C++14 is now the minimum supported
standard, and any conforming C++14 compiler should have a working C++11
std::begin.
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>
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.