Descent 2: Vertigo level 10 has invalid data in its control center
triggers. Sanitize invalid data at load to avoid problems in
memory-poisoning builds.
`oldsegnum` is `const`, so the address computed from it cannot change.
Lift the computation of `auto &children` out of the loop.
Reduce the scope of `biggest_val`, since it does not need to outlive the
loop.
Introduce a helper to obtain both the magnitude of a vector and the
corresponding normalized vector. Use it to capture both values as const
when possible.
gcc-11.3.0 issues a -Wmaybe-uninitialized warning for `exit_side`.
Reorder the code to eliminate this warning. Also, fix a potential
out-of-bounds read if `matt_find_connect_side` returned `side_none`.
Before, this would lead to a read of `Side_opposite[side_none]` before
the test that `entry_side` is not `side_none`. Now, if
`matt_find_connect_side` returns `side_none`, the read of
`Side_opposite` is skipped and logic goes directly to finding a proper
exit side.
gcc-11.3.0 with -Og may issue a -Wmaybe-uninitialized warning for `w1`
because it fails to prove that every path sets the variable. Reorder
the logic to use a local lambda to ensure that every path assigns a
value.
`Multi_is_guided` is only enabled in one place. One code path set up
Guided_missile[] for the local player, and a different path handled
network players. Remove `Multi_is_guided` and rearrange such that a
single site handles both local and network players.
When the host exits the game, guests switch the game window to be
non-visible, and raise a dialog box stating `Host has left the game!`.
Prior to this change, the guests would then busy loop until the dialog
was dismissed. With this change, the game will sleep for each idle
event, minimizing CPU use during the period waiting for the player to
acknowledge the dialog box.
Using `sav_objnum` caused the player to be restored into the object slot
of the pre-load level, in the object table of the post-load level. This
was harmless when the slots were the same, and wrong when they were not.
It became noticeably wrong when more player data was moved into the
object. After those changes, the player's data was stored into the
correct post-load slot, but the ship was assigned to the pre-load slot.
Remove the incorrect slot switch, and add an assert that the object
being overwritten is a player ghost. With the incorrect switch present,
this assert will catch most (but not all)[1] cases of the incorrect
restore. With the incorrect switch removed, this assert succeeds.
[1] In the unlikely case that the post-load slot was a player start, but
for a different player, the assert could succeed despite the slot
mismatch bug. In the common case, the post-load slot would not be a
start of a different player; it would either be the correct player slot,
in which case `sav_objnum` was harmless, or it would be some other
object, such as a robot.
If the guest is slow to respond, the host would enter a busy loop
polling for the guests to be ready. Mitigate the CPU load by sleeping
for 50ms when guests are not yet ready.
Remove the multi_do_fire branches that check the message type. Delegate
those checks to the caller, so that multi_do_fire can work with the
common initial sequence of the three messages.
Descent 2 secret levels allow a player to rescue hostages that are not
counted in `total_hostages`, so a player can exit with more hostages
saved than were in the mine. Change the scoring logic not to penalize a
player for saving these unaccounted hostages.
In non-memory-poison builds, the zero initialization of the new object
will suffice to cover this. In memory-poison builds, the new object
will be reset to a poison value, so the member must be given a
reasonable value here.
Convert the RAIIsocket to a simple SOCKET before passing it to FD_SET.
Otherwise, the build fails with:
```
similar/main/net_udp.cpp: In function 'int {anonymous}::udp_general_packet_ready(dcx::{anonymous}::RAIIsocket&)':
similar/main/net_udp.cpp:969:2: error: use of deleted function 'bool dcx::{anonymous}::RAIIsocket::operator==(T) const [with T = long long unsigned int]'
969 | FD_SET(sock, &set);
| ^~~~~~
similar/main/net_udp.cpp:493:29: note: declared here
493 | template <typename T> bool operator==(T) const = delete;
| ^~~~~~~~
```
The kill messages have different lengths and conditional processing
based on whether the message is MULTI_KILL_CLIENT or MULTI_KILL_HOST.
Split the two into separate functions to simplify the implementation of
each.
Compiler error messages are generally better when reporting a misuse
that fails a requires() versus reporting a misuse that fails a
std::enable_if. In some cases, this also makes the code clearer, and
avoids the need for dummy template parameters as a place to invoke
std::enable_if.
The caller has the player object, and can provide the orientation matrix
from it. Use that instead of letting multi_send_fire recompute the
object in order to get the matrix.
When the player fires a generic secondary, the choice of proximity bomb
versus super-mine is never read. When the player specifically drops a
bomb, only that choice needs to be read. Pass the chosen weapon as an
argument, and avoid computing the choice on the path where it is never
read.
Two paths are always local. One path is always remote. Split the
handler function to remove the locality test and rely on the caller's
knowledge of whether the affected player is local.