If the file is accessible via PhysFS, the next branch, based on
PHYSFS_openRead, will find it and use it. If it is not accessible via
PhysFS, then attempting to resolve its path would fail. Thus, this
attempt is redundant regardless of whether the file is reachable by
PhysFS. Remove it.
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.
If the type is not None, an earlier statement will have already
returned. Thus, the type can be assumed to be None if these test
statements are reached.
Previously, if the filename had no dots, then mix_play_file would refuse
to play it at all. This was excessive, as only the check for hmp needs
a filename with a dot in it. Change the logic so that a dot-less file
still is assumed not to be an hmp, but instead of returning, will fall
through and try the other load types.
Return the type for compatibility, but set the music type immediately.
Change callers to return without using a switch to set the music type
based on the returned value. This allows the callers to exit early on a
successful load.
Remove the `switch` in the caller, since now every path that can set
`current_music_type` will either (a) set it to None because the load
failed or (b) set it to non-None and return before reaching the
`switch`.
Return the type for compatibility, but set the music type immediately.
Change callers to return without using a switch to set the music type
based on the returned value. This allows the callers to exit early on a
successful load.
- Centralize the default value for the hook function.
- Move some static functions to the anonymous namespace.
- Define functions for setting the mixer parameters to ADLMIDI mode and
SDL_mixer mode, so that these modes can be set from more places.
AlumiuN reports that mingw32-w64-gcc-8.1.0 incorrectly reports
`ascending` as unused-but-set. This is clearly not true. Reorder the
code to avoid saving `ascending`, and instead use the result of
`detail::get_xrange_ascending` directly. This also improves the error
message in the DXX_ALWAYS_ERROR_FUNCTION path.
Reported-by: AlumiuN <https://github.com/dxx-rebirth/dxx-rebirth/issues/626>
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.
- 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.
clang chokes on use of a `constexpr bool` that is initialized separately
from its definition. gcc allows this. Move the value computation into
a constexpr helper function, so that the variable can be defined and
initialized in the same statement.
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.
clang warns that an implicit copy constructor is deprecated in the
presence of an explicitly defaulted copy-assignment operator.
Add an explicitly defaulted default constructor too, since the
explicitly defaulted copy constructor suppresses generation of an
implicit default constructor, and the default constructor is needed.
Commit 4d6affd74d ("Fix SDL-only briefing crash") added a hack to
prevent a crash when the briefing window is automatically resized.
However, a logic error in that hack causes some subcanvases that were
not wrong to be truncated. Change the logic to fix those subcanvases,
such as the one used for rendering a background in the High Scores
window. The new logic still avoids the crash in in SDL-only mode.
Fixes: 4d6affd74d ("Fix SDL-only briefing crash")
On some systems, such as the Apple M1 (ARM-based Macs),
dylibbundler is in $PATH, but not in a directory found by the limited
path that SCons uses for Command() invocations. This causes the SConf
test to succeed (because it uses the full $PATH), but the Command() to
fail (because it uses a reduced path). Fix this by using the user's
$PATH, if defined, for this Command() invocation.
Along the way, rework tool_bundle.py to use SCons' Node() objects in
place of direct path manipulation. This lets SCons produce better error
messages in some cases.
Reported-by: Kreeblah <https://github.com/dxx-rebirth/dxx-rebirth/pull/610>
If std::common_type<range::index_type>... finds a common index_type
among all the zipped ranges, pass that common type through as
zip<...>::index_type. Otherwise, set zip<...>::index_type to void.
This allows enumerate(zip(...))) to report a better index_type.
Trim the bitmap's current width and height to be not more than its
parent. Otherwise, an automatic screen resize, such as triggered when
playing the robot briefings in Descent 2, will give the window a new
smaller bm_data, but continue to use the old dimensions. This then
causes load_briefing_screen -> gr_bitmap_scale_to -> scale_line to write
off the end of the smaller bm_data, causing memory corruption and
eventually a crash.
enum game_mode_flags must be visible in common code, which does not
define DXX_BUILD_DESCENT_II. To avoid One Definition Rule errors,
game_mode_flags must have the same definition in all files.
Fortunately, the DXX_BUILD_DESCENT_II definition is a superset of the
common definition, so the preprocessor guards can be replaced with
advisory comments.
Fixes: 2b718da343 ("Use enum class for Game_mode, Newdemo_game_mode")
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.
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`.
When partial_range is used on a container that defines index_type,
define that same index_type on the partial_range. This allows other
callers, such as enumerate(), to maintain the correct index type.
All the affected symbols are templates, so duplicate instantiations will
not cause duplicate definition errors. Removing the anonymous namespace
wrapper will allow equivalent definitions from different source files to
be folded together, reducing the size of the executable.
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.
- UO -> index_begin_type
- o -> index_begin
- UL -> index_end_type
- l -> index_end
- I -> range_exception
The original names were picked because `l` was the length of the
subrange. Rename these to more closely follow STL's begin/end
nomenclature.
`I` was used variously for an iterator type and for the exception type
thrown on error. Rename the latter to be descriptive.
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 limiter to let it return early when the result is predictable.
The first caller checks only whether the returned value is above a
threshold. Once the value goes above that threshold, its precise
value will not matter, so stop counting and return early.
- Add comments explaining some of the logic.
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.
In gcc-7, expressions on the false path of `if constexpr` are deleted
before they are considered "used", so a variable that is only used on a
deleted path is reported as an unused variable. Add an alternate path
that casts the variable to void so that it is always used.