When activating switches in the room with 6 matcens,
this happens after a short while:
```
Assertion failure at TERRAIN_REGION (Descent3/terrain.h:218), triggered 1 time:
'x != -1 && "invalid/unset room number (-1)!"'
f0 TERRAIN_REGION (x=-1) at Descent3/terrain.h:222
f1 AIPathAllocPath (obj=0x3d304b0 <Objects+150000>, ai_info=0x520000444080, goal_ptr=0x520000444250, start_room=0x3d304cc <Objects+150028>, start_pos=0x3d304d0 <Objects+150032>, end_room=0x7fb115dbe830, end_pos=0x52000044427c, rad=0, flags=0, handle=28822, ignore_obj=-1) at Descent3/aipath.cpp:1066
f2 GoalDoFrame (obj=0x3d304b0 <Objects+150000>) at Descent3/AIGoal.cpp:823
f3 AIDoFrame (obj=0x3d304b0 <Objects+150000>) at Descent3/AImain.cpp:6214
f4 ObjDoFrame (obj=0x3d304b0 <Objects+150000>) at Descent3/object.cpp:2674
f5 ObjDoFrameAll () at Descent3/object.cpp:2988
f6 GameFrame () at Descent3/GameLoop.cpp:2981
f7 GameSequencer () at Descent3/gamesequence.cpp:1221
f8 PlayGame () at Descent3/game.cpp:834
f9 MainLoop () at Descent3/descent.cpp:550
f10 Descent3 () at Descent3/descent.cpp:508
f11 oeD3LnxApp::run (this=0x7fb115a0db50) at Descent3/sdlmain.cpp:151
(gdb) up
start_room=0x3d304cc <Objects+150028>, start_pos=0x3d304d0 <Objects+150032>, end_room=0x7fb115dbe830, end_pos=0x52000044427c, rad=0, flags=0,
handle=28822, ignore_obj=-1) at Descent3/aipath.cpp:1066
1066 } else if (BOA_Array[BOA_INDEX(*start_room)][BOA_INDEX(*end_room)] & BOAF_TOO_SMALL_FOR_ROBOT) {
(gdb) p *start_room
$2 = 171
(gdb) p *end_room
$3 = -1
```
The return type of ``BOA_GetNextPath`` is int; but inside the
function, ``false`` is returned, which does not fit the scheme.
Judging from callsites, ``BOA_NO_PATH`` is expected instead.
In some functions related to AI pathfinding, add handling or
assertions for invalid room numbers.
Descent3/multi_dll_mgr.cpp:974:43: warning: deleting "void*" is
undefined [-Wdelete-incomplete]
(``delete`` requires that types are _complete_, so as to find the
right destructor to call; ``void`` is incomplete by definition.)
Commit d185ab9514 broke the
pointer-moving logic. When the allweapons cheat is executed or when
e.g. the afterburner is picked up, ASAN terminates the program with:
```
==8330==ERROR: AddressSanitizer: heap-use-after-free on address 0x50f00007ab60
at pc 0x7f23334f6843 bp 0x7ffe724d2b10 sp 0x7ffe724d22d0
READ of size 3 at 0x50f00007ab60 thread T0
f0 strdup
f1 Inventory::AddCounterMeasure(int, int, int, int, char const*) Descent3/Inventory.cpp:575
f2 Inventory::Add(int, int, object*, int, int, int, char const*) Descent3/Inventory.cpp:520
f3 DemoCheats(int) Descent3/GameCheat.cpp:606
f4 ProcessKeys() Descent3/GameLoop.cpp:2420
f5 GameFrame() Descent3/GameLoop.cpp:2956
f6 GameSequencer() Descent3/gamesequence.cpp:1212
f7 PlayGame() Descent3/game.cpp:826
f8 MainLoop() Descent3/descent.cpp:554
f9 Descent3() Descent3/descent.cpp:507
f10 oeD3LnxApp::run() Descent3/sdlmain.cpp:142
f11 main Descent3/sdlmain.cpp:323
0x50f00007ab60 is located 0 bytes inside of 175-byte region [0x50f00007ab60,0x50f00007ac0f)
freed by thread T0 here:
f1 mng_LoadNetGenericPage(CFILE*, bool) manage/generic.cpp:2216
f2 mng_LoadNetPages(int) manage/manage.cpp:1281
f3 mng_LoadTableFiles(int) manage/manage.cpp:648
f4 InitD3Systems2(bool) Descent3/init.cpp:1891
f5 Descent3() Descent3/descent.cpp:503
f6 oeD3LnxApp::run() Descent3/sdlmain.cpp:142
f7 main Descent3/sdlmain.cpp:323
previously allocated by thread T0 here:
f0 malloc
f1 mem_rmalloc<char> mem/mem.h:138
f2 mng_ReadNewGenericPage(CFILE*, mngs_generic_page*) manage/generic.cpp:1145
f3 mng_LoadNetGenericPage(CFILE*, bool) manage/generic.cpp:2196
f4 mng_LoadNetPages(int) manage/manage.cpp:1281
f5 mng_LoadTableFiles(int) manage/manage.cpp:648
f6 InitD3Systems2(bool) Descent3/init.cpp:1891
f7 Descent3() Descent3/descent.cpp:503
f8 oeD3LnxApp::run() Descent3/sdlmain.cpp:142
f9 main Descent3/sdlmain.cpp:323
```
The pointer value of mngs_generic_page::description was copied to
object_info::description (by function
``mng_AssignGenericPageToObjInfo``) and then the page was freed in
``mng_LoadNetGenericPage``, leaving object_info::description non-NULL
and dangling.
Fixes: d185ab9514
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);