Only one caller passes a value other than `object_none` for
`is_bomb_objnum`. That one caller uses an equivalent predicate to the
one that `multi_send_fire` uses for deciding whether to use
`MULTI_FIRE_BOMB`. Therefore, if `is_bomb_objnum != object_none` is
true, the weapon is guaranteed to be a proximity bomb or smart mine, and
`multi_send_fire` can use `MULTI_FIRE_BOMB` without retesting the object
id.
Commit 81dd23b151 ("Only charge player for weapons that fire successfully")
added an early return when `objnum == object_none`, so if execution
reaches the call to `multi_send_fire`, then the object is guaranteed to
exist. Access the track_goal without rechecking whether the object
exists.
Instead of sliding the entire queue down one element at a time, move the
non-expired elements in one step, and wipe all the trailing elements
in a single pass.
The only values for any given player are true/false, so use a bitset
instead of a byte per player. Some implementations may use a uint64_t
internally, negating the space savings. Even so, this version is
an improvement for requiring the use of playernum_t as an index.
The function had one caller, which always passed `0`. Inline that.
Next, observe that `sent` is only ever modified `if (!(Game_mode &
GM_NETWORK))`. As a multiplayer function, `multi_send_robot_frame`
should never be called in single-player, so this test should always be
false. Delete it, and observe that `sent` is now `const`.
Remove unused return value of `multi_send_robot_frame`.
Instead of passing a truth value and letting
multi_send_robot_position_sub pick which of two priority values to use,
let the callers pass the priority directly. There were two callers.
One used a fixed truth value, and the other can easily use a ternary.
Instead of passing a bare `int` named `secret_flag`, define it as an
`enum class : uint8_t` to name the two special values.
Rework the passing of this value, to deal with some confusing
inconsistencies when reading the code.
Before this change:
In D1:
- Multiplayer will always go to the secret level, regardless of which
exit door the player used.
In D2:
- Flying through a D1 secret exit in multiplayer shows the on-HUD error
"Secret Level Teleporter disabled in multiplayer!", and does not exit
the level. This is at best confusing, and at worst dangerous, since
D1 secret exits are only available during the countdown, so the player
has little time to realize that the normal exit must be used instead.
- Like D1, multiplayer will request to go to the secret level regardless
of the exit used. Unlike D1, the caller ignores the flag and always
advances to the next regular level.
After this change:
- No observable differences for the player in-game. The questionable D2
secret exit handling for D1 is retained.
- The code makes clearer that secret exits do not work in D2
multiplayer, by way of `#if defined(DXX_BUILD_DESCENT_I)` guarding the
existence of the parameter and all updates to it.
All callers except one want the `lite` version of the request. Switch
from a boolean that is selected inside the function to a reference that
is defaulted to `lite`. Override that argument to the heavy version in
the one caller that needs it.
Using `netplayer_info` in `UDP_sequence_packet` defined many unused
fields. Replace this with per-message types that carry only the
required fields. Make these fields `const` where possible.
Instead of forcing one call, then conditionally doing 3 more, make the
loop run for 4 passes, and make the call after the conditional exit,
instead of before.
Some callers create an explosion with damage forced to zero. Others
create an explosion with damage non-zero. Only the non-zero case needs
to examine nearby objects. Split object_create_explosion_sub so that
the zero-damage case can skip that logic, and the arguments required to
implement it.
Remove the definition of FQ_CHECK_OBJS and all uses of it. Add a new
fvi_query member d_level_unique_object_state *LevelUniqueObjectState.
If object checking is enabled, pass &LevelUniqueObjectState in that
member. If object checking is disabled, pass nullptr in that member.
Change fvi_sub to use this member to decide whether to perform object
checking.
If FQ_CHECK_OBJS is used, a valid object is required. Copy the
icobjptridx_t from fvi_query into a local vcobjptridx_t to force a
validation, then use that validated copy for later work.
- Make all members constant, and pass an anonymous temporary fvi_query
to find_vector_intersection.
- Change `p0`/`p1` to `const vms_vector &`, since the positions are
mandatory. Callers can no longer pass `nullptr` or an uninitialized
value here.
- Change `thisobjnum` to `icobjptridx_t`. Calls to fvi_sub built an
objptridx at need, so moving it to the caller allows it to be
constructed once per find_vector_intersection call.
- Move `flags` and `rad` out of fvi_query, since calls to fvi_sub may
use other values than the ones in fvi_query. This prepares for
passing fvi_query to fvi_sub.
Ship wiggle is normally enabled for compatibility with the original
game. However, during development, it can become a nuisance, so add an
option to allow disabling it.
This started out as underline, but one of the special drawing modes uses
it to draw an underline-width block across the entire vertical height of
the character.