Devirtualization is an optimization in the generated assembly: when a
class C is polymorphic but also final, ``((C *)ptr)->func()`` can be
turned from an indirect into a static call.
scripts/Y2K.cpp:467:5: warning: deleting object of polymorphic class type
"LevelScript_0000" which has non-virtual destructor might cause undefined
behavior [-Wdelete-non-virtual-dtor]
467 | delete ((LevelScript_0000 *)ptr);
$GIT/scripts/LEVEL15.cpp: In function ‘void aMatCenPuzzleInit()’:
$GIT/scripts/LEVEL15.cpp:833:38: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
833 | #define MagicMatCenSwitchSequence (*((int *)(&User_vars[17])))
$GIT/scripts/LEVEL15.cpp:834:25: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
834 | #define MatCenStateA (*((int *)(&User_vars[0])))
...
$GIT/scripts/Level6.cpp: In function ‘void aPriestKeyEnter(int)’:
$GIT/scripts/Level6.cpp:910:47: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
910 | #define Var_ThereIsPlayerInPriestKeyPuzzle (*((int *)(&User_vars[7])))
Turn ``User_var`` into an array of std::variant, the latter of which can hold
either float or int. Savegames do not carry the necessary type information
which variant (float/int) is in use; instead, this is statically decided by
the level DLL logic on a per-index basis. This approach is retained for now.
A lot of ``Var_something = 0`` is used despite Var_something being
logically used as float, so we need to override op= to keep the
variant type as-is.
Due to ``#include "DallasFuncs.cpp"``, DF is recompiled 52 times.
Rework it to build just once. The compile time goes down for me
from 1m45.3s to 1m38.8s on my 1135G7 CPU running make -j8.
It is possible to cause the death of the CollectorNomad2 object (rush
to it before it possibly leaves again into the sidepackets the ship
won't fit through). The transition happens here:
```
f0 KillObject (objp=0x3d4d3e0 <Objects+384000>, killer=0x3cef7e0 <Objects>, damage=3) at /home/jengelh/D3/Descent3/damage.cpp:1036
f1 ApplyDamageToGeneric (hit_obj=0x3d4d3e0 <Objects+384000>, killer=0x3cef7e0 <Objects>, damage_type=6, damage=3, server_says=0, weapon_id=255) at /home/jengelh/D3/Descent3/damage.cpp:1401
f2 collide_generic_and_player (robotobj=0x3d4d3e0 <Objects+384000>, playerobj=0x3cef7e0 <Objects>, collision_point=0x7f877f40a830, collision_normal=0x7f877f40a858, f_reverse_normal=true, hit_info=0x7f877f40a810) at /home/jengelh/D3/physics/collide.cpp:2127
f3 collide_two_objects (A=0x3cef7e0 <Objects>, B=0x3d4d3e0 <Objects+384000>, collision_point=0x7f877f40a830, collision_normal=0x7f877f40a858, hit_info=0x7f877f40a810) at /home/jengelh/D3/physics/collide.cpp:2505
f4 do_physics_sim (obj=0x3cef7e0 <Objects>) at /home/jengelh/D3/physics/physics.cpp:1515
f5 ObjDoFrame (obj=0x3cef7e0 <Objects>) at /home/jengelh/D3/Descent3/object.cpp:2824
f6 ObjDoFrameAll () at /home/jengelh/D3/Descent3/object.cpp:2988
f7 GameFrame () at /home/jengelh/D3/Descent3/GameLoop.cpp:2980
f8 GameSequencer () at /home/jengelh/D3/Descent3/gamesequence.cpp:1221
f9 PlayGame () at /home/jengelh/D3/Descent3/game.cpp:834
f10 MainLoop () at /home/jengelh/D3/Descent3/descent.cpp:550
f11 Descent3 () at /home/jengelh/D3/Descent3/descent.cpp:508
f12 oeD3LnxApp::run (this=0x7f877f00db50) at /home/jengelh/D3/Descent3/sdlmain.cpp:151
<frame 2> (gdb) p robotobj
$1 = {
type = 2 '\002' (OBJ_ROBOT), dummy_type = 255 '\377', id = 276,
flags = 2135072, name = 0x5020000aff30 "CollectorNomad2",
handle = 2432, next = 178, prev = -1,
control_type = 1 '\001' (CT_AI), movement_type = 2 '\002' (MC_ROLLING),
render_type = 1 '\001' (LRT_GOURAUD), lighting_render_type = 1 '\001', roomnum = 58,
pos = {x = 2350.21484, y = -263.523956, z = 1868.59888},
orient = {
rvec = {x = 0.882905424, y = 1.63964216e-14, z = -0.469550878},
uvec = {x = -1.25793295e-14, y = 1, z = 1.12662192e-14},
fvec = {x = 0.469550878, y = -4.04037088e-15, z = 0.882905424}
},...}
```
Thus, KillObject sets obj->control_type=CT_DYING. In the same game
tick, Level6.cpp then calls aAIGoalFollowPathSimple which triggers
the assertion.
```
Int3 in $GIT/Descent3/osiris_predefs.cpp at line 571.(Descent 3 Debug Break)
f0 osipf_AIGoalFollowPathSimple (objhandle=2432, path_id=21, guid=7, flags=1052928, slot=3) at $GIT/Descent3/osiris_predefs.cpp:571
f1 AI_GoalFollowPathSimple (objhandle=2432, path_id=21, guid=7, flags=1052928, slot=3) at $GIT/scripts/osiris_import.h:170
f2 aAIGoalFollowPathSimple (objhandle=2432, pathid=21, flags=1052928, goalid=7, priority=3) at $GIT/scripts/DallasFuncs.cpp:3649
f3 LevelScript_0000::CallEvent (this=0x5020000ba430, event=256, data=0x7f963e71d930) at $GIT/scripts/Level6.cpp:2465
f4 CallInstanceEvent (id=0, ptr=0x5020000ba430, event=256, data=0x7f963e71d930) at $GIT/scripts/Level6.cpp:2209
f5 Osiris_CallLevelEvent (event=256, data=0x7f963e71d930) at $GIT/Descent3/OsirisLoadandBind.cpp:2000
f6 GameFrame () at $GIT/Descent3/GameLoop.cpp:3020
f7 GameSequencer () at $GIT/Descent3/gamesequence.cpp:1221
f8 PlayGame () at $GIT/Descent3/game.cpp:834
f9 MainLoop () at $GIT/Descent3/descent.cpp:550
f10 Descent3 () at $GIT/Descent3/descent.cpp:508
f11 oeD3LnxApp::run (this=0x7f963e80db50) at $GIT/Descent3/sdlmain.cpp:151
```
The vast majority of this is fixing up `char *` that should be `const char *`
but a handful of other fixes, like potential buffer overflows that GCC
noticed, etc, were applied as well.
This removes `-Wno-write-strings` from CMakeLists.txt, as it is no longer
necessary, as there is no longer a flood of compiler warning spam when
building.
This does not fix all compiler warnings; there are still a handful, and they
are legitimate, but they can be dealt with in a future commit.
Most of the warnings were caused by uninitialized values. Some were in plug-ins that didn't have a break in a switch, causing the memory to be deleted twice.