Every caller passes `1`, so remove the parameter and always use `1`.
For backward compatibility with the previous network protocol, continue
to send a `1` in the network message.
- Write a more specific message on failure
- Defer writing a success message until `spit_powerup` succeeds
- Defer the sound too
- Rewrite the success message to tell how much ammo remains
Commit 8c8b7419b6 defined Shift-F5 and Shift-F6 to adjust the VR
handling. However, Shift-F5 and Shift-F6 already had a meaning: drop
primary weapon / drop secondary weapon. The ordering of the logic
causes the new VR handling to suppress the old drop handling, thus
preventing players from dropping weapons. Disable the VR meaning for
these keys so that drop-weapon works again, since F1 documents those
keys as drop-weapon.
Fixes: 8c8b7419b6 ("Improved conditionals for stereo vs non-stereo modes.")
v29_trigger and v30_trigger define a field `time`. v29_trigger never
initializes it. v30_trigger initializes it from the uninitialized
v29_trigger in legacy mode, and from a file field otherwise. No program
logic ever reads this member, so remove it.
Commit 7f2df64649 converted `mission_menu` to inherit from `listbox`,
but introduced an off-by-one bug in the handling of subdirectories.
`listbox` must be told how many strings it is given. Subdirectories
have one extra string, to represent the `listbox_go_up` element. The
count passed to `listbox` incorrectly failed to adjust for the generated
go-up element, causing listbox not to show the last string in the list.
Change the logic to adjust the count to include the extra element.
Fixes: 7f2df64649 ("Make mission_menu inherit from listbox")
Reported-by: AlumiuN <https://github.com/dxx-rebirth/dxx-rebirth/issues/629>
The contents of the output buffer are undefined if PHYSFSX_getRealPath
fails, so mark the function as [[nodiscard]] and modify all callers to
check that the function succeeded.
Rework the error paths to return path-specific status codes so that the
caller can report exactly which step caused an HMP file to be rejected.
On error, print this reason numerically and, if the reason was a PhysFS
error, also print the PhysFS error code numerically and symbolically.
openable_door_on_near_path should return 0 for no door and any non-zero
value for door-found. Commit 9fdf6005df changed the logic to return 0
for no door, and the side number value for door-found. This is wrong,
since WLEFT has integer value 0, so the caller will interpret a return
of door-found, side=WLEFT as no-door-found.
Fixes: 9fdf6005df ("Convert ai_static::GOALSIDE to sidenum_t")
If two or more events are delivered in the same loop, the previous
implementation would count joystick motion multiple times. Fix this by
moving the joystick interpretation to occur once, after all the events
have been processed.
Lists of these objects are unrolled by a template parameter pack
regardless of whether they are type compatible, so keeping the types
compatible does not improve code size. Store more precise types in the
structure, and avoid needing to store the constant values into a
structure at runtime.
- Use std::integral_constant instead of a static function that returns
the value
- Remove unused protocol_family
- Replace the enum with a typedef for the one type that the enum was
used to define
If exactly one object will always be needed, use an overload that
returns the object id. Otherwise, use an overload that only returns
whether at least one object was created. This simplifies callers that
always request exactly one object.
If at least two robots would be dropped, and a drop failed, then
object_create_robot_egg would report failure to the caller. Callers
that check the return code treat any failure as total failure, but that
is not guaranteed to be true. If the game successfully dropped one
robot and failed when dropping a second, then the caller would receive a
status of failure.
Fix this by returning a status of whether at least one object was
created.
- Change D1X to use D2X rules regarding Vulcan cannon pickup. The D1X
rules were confusing at best, and seem outright wrong in some ways.
- When a Vulcan cannon was picked up, it was treated as containing not
less than VULCAN_WEAPON_AMMO_AMOUNT rounds, regardless of what it
actually contained. D2X respected the actual contained count, even
when running in D1X emulation mode.
- In D1X single player, if the Vulcan cannon was not picked up, then
it could be treated as Vulcan ammo. If at least 1 unit of
ammunition was added to the player, the entire powerup would be
consumed, regardless of how much ammunition remained.
- In D2X single player, if the Vulcan cannon was not picked up, then
ammunition would be taken from it, but the powerup would only be
consumed if all its ammunition was taken.
- In D1X multiplayer, a player who already had a Vulcan cannon could
not get anything from touching a new cannon, and the cannon would
not be changed.
- In D2X multiplayer, a player who already had a Vulcan cannon could
take ammunition from the cannon, but the cannon could not be drained
below VULCAN_AMMO_AMOUNT. If the cannon had VULCAN_AMMO_AMOUNT or
less, then the player could not take ammunition. If the cannon had
more, the player could drain it to that level.
- Replace all that with a simplified version of the D2X rules:
- If the player does not have the cannon, the cannon is picked up
and removed from the mine. The player takes as much of its
ammunition as possible. If the cannon was well stocked, and the
player was nearly full, some ammunition will be lost. This is
unfortunate, but the game has always had this rule, and changing
it would require dropping one or more Vulcan Ammo packs to
represent the untaken ammunition.
- If the player already had that cannon, then the player takes as
much ammunition as the cannon has, while not exceeding the
ammunition cap. Other players, if any, are updated about how much
ammunition remains in the cannon. The cannon remains in the mine.
- Backport to D1X the network message for updating the contained
ammunition in a vulcan cannon. zico added the basic feature in
7684ce92, but only applied it to D2X. With the change to let D1X
multiplayer take ammunition from the cannon, D1X now needs the same
feature.
- Remove the special case to delete an empty cannon. Instead, let the
cannon remain in the mine without ammunition. This allows a player in
single player mode to leave behind a backup cannon, which could be
useful if the player is killed and wishes to rearm before returning to
the death site. Similarly, under the new rule that players in
multiplayer can drain the cannon down to 0 ammunition, this removal
allows the cannon to remain behind for someone else to take, rather
than allowing it to be deleted by a player who already had an instance
of it.
Instead of creating the powerup from a player, then overwriting the
location and velocity of the powerup, and fixing up its segment, create
the powerup directly where it should be, with the intended velocity.
Add periodic calls to send_endlevel_packet in kmatrix if
Control_center_destroyed is false.
Needed because after finishing the last level, kmatrix is called from a
different place where Control_center_destroyed is already false.
It looks like this issue was introduced in Rebirth 0.56 with the
split off of the ipx code (febe5d1). That commit removes the call to
multi_endlevel_poll2 from kmatrix_view, which did the same periodic
sends. (Maybe because in D1 Control_center_destroyed was always true
in kmatrix so it was not needed there.)
Reported-by: snytek <#520>
Fixes: febe5d1 ("Abstracting networking protocols")
clang-13 fails to sufficiently inline this construct, causing it to emit
an unnecessary call to check_null_pointer_conversion on a path where
m_ptr is already guaranteed to be non-nullptr. That call in turn
causes a linker error, since no other site using valptridx<wall> needs
check_null_pointer_conversion instantiated. Rather than provide the
instantiation, rework the logic to avoid the need for the dead call.
Instead of creating the powerup from a player, then overwriting the
location and velocity of the powerup, and fixing up its segment, create
the powerup directly where it should be, with the intended velocity.
Iterating over it returns each side number in turn. This allows
converting many loops of the form:
```
for (int i = 0; i < MAX_SIDES_PER_SEGMENT; ++i)
```
to the compact form:
```
for (const auto i : MAX_SIDES_PER_SEGMENT)
```
The compact form brings the usual benefit of range-based for: delegating
iteration to the compiler prevents the loop body from skipping a step,
and makes clear in the code that this is the case.
Some flags merit a type other than int8_t. Begin moving flags out to
distinct variables with their own type.
Add static_assert checks that the ABI relevant structures do not change.
A level can have a secret exit without having a mission entry describing
where to go when the secret exit is used. Switch from an assertion
failure in that case to a log message.
This triggers a diagnostic from -Wuseless-cast. It appears to be
unnecessary, after tracing down typedefs. It might need to be restored
if some platform uses a definition that is neither the same type nor
implicitly convertible.
clang treats names introduced by structured bindings specially, and
refuses to capture them for a lambda, even when it should be capturing
an rvalue reference. gcc accepts this capture.
Switch to initializing a lambda local variable from the structured
binding in the outer scope, which works with both compilers.
Reported-by: Kreeblah <https://github.com/dxx-rebirth/dxx-rebirth/issues/609>
This eliminates the only place that zip<>'s template parameter list is
written out in the source, which will allow later commits to change the
template parameter list.
Remove the workaround added for issue #289 [1]. That issue covered a
miscompilation by early versions of gcc-4.9. gcc-4.9.x is no longer
supported, so the workaround is no longer needed.
[1]: https://github.com/dxx-rebirth/dxx-rebirth/issues/289
Change it from the level number on which the path was created to a
true/false flag. The previous logic only tested whether the number was
equal to the current level number.
This also fixes a bug where the action was not available on the first
secret level, since that level is `-1`, and the value was set to `-1` to
indicate that it should be enabled.
cockpit_decode_alpha::deccpt has static scope and is retained to support
the data in WinBoxOverlay. Change WinBoxOverlay into a structure that
stores deccpt (and rename it to the more descriptive
`decoded_full_cockpit_image`) to keep the pieces together.
Switch from formatting the strings each time they are drawn to format
them once and save them in scores_menu. Change the drawing logic to
draw from those saved strings. Change the reset logic to reinitialize
those strings instead of recreating the entire menu.
Most callers do not need it, and it is only vaguely related to the
purpose of measuring a particular string. For those callers that need
it, lift it out.
Some targets only ever use GUI warn functions. On those targets:
- initialize `warn_func` to `msgbox_warning` at compile time
- remove the runtime initialize of warn_func in main
On targets which do not call `clear_warn_func`, preprocess out its
declaration and definition.
Taken together, these changes allow some targets not to define
`warn_printf`.
On x86_64-w64-mingw32, `uint_fast32_t` is `unsigned int`. Use the
appropriate format macro for it, instead of writing `lu` and expecting
that `uint_fast32_t` will be `unsigned long`.
gcc-7 warns if a structured binding defines a variable, and then does
not use it. Suppress the warning, since the binding is needed in the
non-editor build.
1024 is excessive. 128 leaves 25 bytes unused on Trainee (the longest
difficulty string, tied with Hotshot) at time 0:00:00. A player who
reached double-digit hours for both time on level and time in game would
need 2 bytes more. A player who rescued 100 hostages would need another
2 bytes.
The existing code checks that w.m_ptr is not nullptr before using it.
clang's flow analysis is unable to prove that w.m_ptr does not become
nullptr after it was first checked, even though `w` is const. This
causes clang to include calls to null_pointer_exception::report, which
is not instantiated for wall. That in turn causes a link error.
Rewrite the code to let clang see that the value tested is the value
used, and that no nullptr dereference can happen here.
Push the computation up, so that invocations that differ only in the
length of their expression strings will resolve to the same template.
Rework unchecked_partial_range not to take expression strings if they
will not be used.
- Inline add_computed_color into gr_find_closest_color, and then only
one function will need access to Computed_colors.
- Allow the recent-choice bubble-up logic to apply to all elements
- If all entries are in use, always overwrite the last element in
Computed_colors instead of picking one randomly.
gr_find_closest_color did not need it. Remove it. For the others,
resetting the count is sufficient. There is no need to reset the
individual elements.
Add a helper to deduce the enum type of a value, and use an appropriate
std::underlying_type<T> expression for that enum type. This avoids the
need to repeat the type of the enum at the site of each cast, and moves
the casts into the helper to make the callers easier to read.
- Use std::iota to initialize the translation array
- Switch from conditionally using either a linear count or the array to
always using the array. In non-random mode, the array is initialized
and never shuffled, so it should produce the same effect as using the
linear count, but avoids a branch in the loop.
- Switch to using std::shuffle driven by std::minstd_rand, rather than
an inline swap loop using d_rand() to pick indices.
- Reorder the shuffle logic to have exactly one invocation in each game,
so that the shuffle call itself can be eligible for inlining.
- Use std::uniform_int_distribution to decide whether to reshuffle in
Descent 2. Maintain the original logic that reshuffling happens 25%
of the time.
clang-12 warns when the format string checking logic indexes off the end
of a very short format string to PHYSFSX_printf. In each case, the call
had no variadic arguments, so it can be switched to PHYSFSX_puts_literal
to make the code simpler and eliminate the warning.
A robot that is rendered may be woken later, subject to some conditions.
Move the easily checked conditions into the renderer, so that robots
which will not be woken are never recorded.
Checking the glow special case should be cheaper than computing and
checking the normal, so check the glow case first. Also, when the glow
values are defined, cache the result of reading from it to avoid
repeating the indexing logic farther down.
Commit d0d7545ec1 ("Unload robot movies on exit") intended to shorten
the lifetime of the loaded data, but failed to save the unique_ptr, so
the lifetime was shortened more than intended. Save the unique_ptr so
that the movies remain loaded.
Also, add a [[nodiscard]] annotation so that the compiler can warn if
this mistake is repeated.
Reported-by: Q3BFG10K <https://github.com/dxx-rebirth/dxx-rebirth/issues/599>
Fixes: d0d7545ec1 ("Unload robot movies on exit")
The previous commit removed an incorrect double scaling of the player's
weapon sounds, which will make all such sounds louder. Players with
their FX volume set to maximum will now have twice as loud a sound.
Halve the intensity in the source to return to the volume such players
would have had before. Players with an FX volume less than maximum will
still get a somewhat louder sound than before.
The SDL_mixer library has already been instructed, via Mix_Volume, to
scale the volume of sounds on all channels, by an amount based on
digi_volume. There is no need to manipulate the effective distance of a
particular sound to further scale it by digi_volume. Even if this
second scale was needed, it was done incorrectly, because it was only
applied when the sound was started, but not re-applied when the sound's
volume was updated due to positional changes. As a result, any sound
which was updated would switch to an unscaled version. Sounds which
were never updated, such as those attached to the viewer object, would
retain their original scaled volume.
Update the implementation of digi_mixer_set_channel_volume to call
Mix_SetDistance in the same way as digi_mixer_start_sound, for
readability and consistency.
Some callers need to update an existing sound_object. Other callers
need a temporary copy of the data for external use. Rearrange the code
so that the latter type of caller can obtain the data without a pointer
indirection.
gcc treats the intervening lines since the last `if` as sufficient to
recognize this as not misleading. clang does not. Change the indent to
calm clang.