This avoids an issue where the skins array takes up a fixed, but large
amount of memory at runtime. On x86_64 linux, that array is roughly 80
megabytes in memory, most of which is unused when the game is unmodded.
Instead, we treat `skins` as a dynamically resizing array, and it is an
array-of-pointers into separate allocated `skin_t`.
This is based on Lactozilla's skin limit MR for SRB2, but I've rewritten
it because RR has diverged quite a bit.
This was verified to check every access of `skins` by using clangd's
find-all-references function. However, I have only tested plain skins,
not Lua addons, so that could afford some extra checking.
In cases where state/property set can cause instant deletion, definitely interrupts FindMobjFromTID iteration after one step and potentially uses after free
Also adds comment warnings to this effect near ways to find P_FindMobjFromTID, and updates P_ProcessSpecial even though we could probably stand to rip it out now
- If you've gotten every Spray Can, or you're on a custom course...
- Only one of these spawns per map
- Correctly save and load these
- Statistics menu counts base-game bonuses
- If there are gaps in the list, or new Spray Cans are added later, these base-game bonuses are converted into the new Spray Cans
- New graphics required so far:
- SBONA0 to SBONP0 - 16-frame prerendered circling sprite animation
- GOTBON - 8x8 representation of the SBON object
BEHAVIOR being optional is now handled from our side, because using getModule or loadModule on an invalid file is supposed to be an error condition for the VM.
This could be done with Get/SetLineProperty just fine, but added just for completion's sake -- the Hexen instruction set is now fully implemented, minus SoundSequence which is for a feature we straight up don't have.
- For Tutorials specifically
- void Dialogue_AutoDismiss(void)
- Dismisses the current dialogue (including from other threads).
- str CheckTutorialChallenge(void)
- Returns special values depending on state relevant to the Tutorial Challenge.
- Returns a blank string in netgames, or if none of the following are true.
- Returns "Active" if the skip is in progress.
- Returns "Failed" if the skip was just failed.
- Returns "Locked" if not available with this gamedata.
- Other tiny check functions
- bool PositionStart(void)
- Returns true if leveltime < starttime.
- bool FreePlay(void)
- Returns true if in Free Play.
If some dialogue needs to be never-missable, that's the mapper's responsibility - but now they won't get randomly interleaved if multiple are activated just by regular free driving, which was the worst kind of default
A first pass in attempts to fix crashes when ACS causes map changes.
Frustratingly still got a crash, but I think this is definitely the right foundation to work with.