Skip to content

Addition of the SF_KARTLESS flag to S_SKIN lumps in character WADs to prevent kart & related gibs from spawning upon death

Spring Thing requested to merge SpringEThing/RingRacers:new-skin-flags into master

Hey guys, a few things before we get started.

First of all, I've only ever programmed in a team in a work environment where merge requests are not a thing, we just have the right to merge into the master branch as employees. As such, I've never done a merge request before, so please tell me if any of this is incorrect or odd. I'm looking to merge commit de767fef in specifically if something gets lost in translation which as of writing this is the latest commit on the new-skin-flags branch.

Second of all, I accidentally authored my first commit with my real name and email, and from there I just kept doing it since I already flubbed it up and it was on-record as such. I'd prefer to go by my screen-name wherever possible, so just keep that in mind.

Anyway, all that said, here's what I did:

I added the SF_KARTLESS flag for S_SKIN lumps in character WADs. When the bit for this flag is set, upon a player dying, no kart husk will spawn and no kart gib particles will spew. The kart mobj WILL still spawn such that the logic of the kart husk can remain relatively untouched, it will just be invisible and intangible with respects to certain checks for the S_INVISIBLE state.

Below, you can see a clip of what happens when a skin with the SF_KARTLESS bit is set as of the commit listed above:

ringracers_GAXHkDn2cO

To get this to work as non-destructively as possible, I had to add a new state named S_KART_LEFTOVER_KARTLESS to statenum_t that acts the same as S_INVISIBLE in info.c but is distinct from that state. I did this because the destroy() method in destroyed-kart.cpp is conditioned to not run past the first frame in think() where that method can run by checking if the state of the kart is S_INVISIBLE or not, and so if I were to re-use S_INVISIBLE for this new SF_KARTLESS flag then it'd fail that condition (although I think the checks at the start of destroy() would result in a no-op anyway). My first thought to prevent the creation of a fairly pointless state like S_KART_LEFTOVER_KARTLESS was to add an extravalue3 to mobj_t, however that wasn't going to work because certain enums related to those variables are used in bitwise operations that cap out at 32 entires for the data type in which they are stored which the enums in question had already reached.

Lastly, the only important thing to bring up is that in order to prevent a kartless instance of the kart mobj from animating its particles as though it were NOT kartless on the condition that the player changes skin between the kartless instance spawning and being deleted, I had to have some way to cache the state of SF_KARTLESS upon the kartless instance spawning without using the aforementioned extravalue3. I did this by creating a new enum value for the mobjeflag_t enum called MFE_KARTLESS. You may already be thinking that the eflags variable of mobj_t is a UINT16 type and is not designed to do bitwise operations with values of that mobjeflag_t enum if there are more than 16 entries which this update would push the number of entires to 17, but I changed the data type of eflags to UINT32 for up to 32 flags and saw no adverse effects in-game from this as little testing as I did to prove this all the same.

So, TL;DR:

  1. S_SKIN lumps can set the SF_KARTLESS flag to prevent a kart husk from spawning upon death
  2. This required me to make a new state identical to S_VISIBLE but distinct from it all the same to maintain the integrity of certain existing if statements
  3. The particle update system of destroyed-kart.cpp required me to cache the SF_KARTLESS bit in advance through a new mobjeflag_t value that has been adjusted in eflags to accomodate >16 enum values for this enum with no adverse effects observed for this change.
Edited by Spring Thing

Merge request reports