System for netsyncing unlocks, inspired by but with nowhere near as many moving parts as (STJr/SRB2!1756).
* `gamedata->unlocked[MAXUNLOCKABLES]` is duplicated to `netUnlocked[MAXUNLOCKABLES]` (or all `true` in `dedicated`
* New `local` boolean for M_SecretUnlocked
* Removed last vestiges of SRB2 special stage token code because it occupied the spot in the netsave we wanted to use.
* Correct typing of multiple `m_cond` functions that returned `boolean` constants as `UINT8`s.
Completely clientside, unlike SECRET_SKIN. Followers have no gameplay function, and it saves us having to write even more to our demos/netsaves. Replaces SECRET_WARP.
Also:
- Now don't apply skins or followers from profiles if the skin is locked - instead, get the closest skin in stats. (Same function as from demos!)
- If you're looking at a profile and the skin or follower are locked, make them solid colour (TC_BLINK).
- Don't show the ring cursor before you've selected a profile.
A small piece of (STJr/SRB2!1756).
Due to how RR currently handles time attack records and how it WILL handle unlocks, it's not currently feasible to split everything such that you can have two independent gamedata_t... but what's done so far is certainly more sane and less dependent on global variables
Other minor refactors:
- M_UpdateUnlockablesAndExtraEmblems and M_SilentUpdateUnlockablesAndEmblems are now one function with a boolean for loudness
- Unlock prints are currently living in the console, since the cecho stuff was a little broken
Mammoth commit, sorry. I only realised halfway through writing it that SECRET_SKIN was only partially merged.
Ports from 2.2:
- Merge SECRET_SKIN (STJr/SRB2!1474)
- Default skin is now handled by checking all skins for unlock status, and I_Erroring if none are available
- Don't show skin names on game startup, to keep our secrets hidden
- Unlockables now have string variables zallocated.
- For skin names rather than numbers.
- Correctly clean up memory when freeing unlockables and emblems.
Bespoke code:
- For temporary testing. `unlocks.pk3`
- Using this for rapid testing gameboot SOC instead of patch.pk3 because of the intent to turn that into scripts.pk3
- Don't not save gamedata in DEVELOP builds, even if you've used cheats!
- `player->availabilities` is now an array of UINT8
- (MAXSKINS + 7)/8 entries, or 32 bytes.
- Included with XD_ADDPLAYER instead of XD_NAMEANDCOLOR.
- Simplifies a lot of logic with respect to demos, skin changes mid-game, etc.
- Seriously, there's a lot of random places in the code that just iterate over MAXSPLITSCREENPLAYERS and g_localplayers to update availabilities in real time in a way that's not particularly netsafe...
- Lines up with the plan for handling unlocks when returning to menus.
- Was included with XD_ADDBOT, but that actually overruns the netxcmd buffer at first mapload with 7 bots. We might need to consider expanding the size of the netxcmd buffer...
- In demos, can be interpreted as both relative to the original replay and the current skin list depending on boolean context provided to R_SkinUsable.
- Used for SF_IRONMAN (and will crash if all other skins are inaccessible).
- Grand Prix bot randomisation uses the host's unlocks.
- Don't show locked characters on the fancy new character select.
- DXD_JOINDATA for demos
- Replaces the dual-purpose behaviour of DXD_PLAYSTATE
- Contains availabilities
- Handles bot material in a different way
- Forceskin restrictions
- Won't run in demos, because it's assumed recorded DXD_SKIN will handle all the conversions the original match had
- Won't run if K_CanChangeRules says no
- Correctly set `mapvisited` on level visit, even in [fake gasp] MULTIPLAYER/NETGAMES!! 🥹
- Added updating unlockables and extra emblems on `mapvisited` update.
- Currently fails to produce the cecho, but that'll be stripped out entirely in a future commit so I'm not bothered.
Tremendous whoopsie: turns out there's no code that actually saves it outside of netsync. This is now fixed.
Also now allows you to roll Eggman as your first skin, and doesn't cause immediate characterswaps for midgame joiners.
Notable new features:
- Guaranteed native compatibility with SF_IRONMAN even with differing # of skins
- Bots (todo: can still desync midway through round)
Implementation details:
- Demo code (skins):
- Instead of writing a skin name string, and the player's kartspeed, kartweight, and charflags for each player in the initial player-interpreting loop...
- Write a skinlist of EVERY skin's name string, kartspeed, kartweight, and flags next to the file list, to be read into `demo.skinlist`.
- If the skin name isn't loaded, find the skin with (in order)
- SF_IRONMAN if your skin had SF_IRONMAN, since that's more important to signal
- the closest stats otherwise (as per previous implementation)
- Just as tolerant to stats AND the number of base skins changing between versions (the bonuschars aegis situation)
- Not tolerant to restat, but we can add a DXD or EZT later if we want to natively support that kind of mod
- In the initial loop and DXD_SKIN, just write an index that can be used for `demo.skinlist`, and store it in `demo.currentskinid[p]`
- The player's skin is now encoded as EZT_IRONMAN for ghosts (and just in case RNG sync fails for unrelated reasons)
- In the SF_IRONMAN code when demo.playback is true
- everywhere where `skins[player->skin]` is referenced instead uses an index into `demo.skinlist`
- SetRandomFakePlayerSkin uses the `demo.skinlist` to build a table to ensure exact random call parity
- Also means it no longer double rejection-samples.
- `player->fakeskin` and `lastfakeskin` are always == their original recording values, a skin id which can be used into `demo.skinlist`
- Demo code (playstate, initial player setup loop):
- Add bot flag (`DXD_PST_ISBOT`, `DEMO_BOT`)
- Add in-between-level botvars (difficulty, diffincrease, rival)
- Don't rely on `PF_WANTSTOJOIN` to activate
Additional bugfixes:
- Followerskin set to -1 in CL_ClearPlayer so a bad follower isn't recorded on player join without name and color change arriving immediately
- Accomodate new joiners in demo code even if they're not on DXD_PST_SPECTATING for one reason or another
- Demo extra file list saving is now its own function for code cleanliness
- Actually only modify players relevant to the demo at the end of G_DoPlayDemo, not all 16 by supplying and overwriting garbage values (POSSIBLE MEMORY CORRUPTION FIX, mobj_t pointer was previously dereferenced)
* Instead of doing constant G_MapNumbers when finding the relationship between maps and cups...
* Add a cache of level IDs to cups, to go with the strings.
* Add a cache of the cup pointer to maps, so we don't have to search through all cups to find our map. (done in P_InitMapData)
* Pre-emptive work: G_IsSpecialStage and P_GetNextEmerald now reference cup data instead of a hardcoded ID set.
* Remove a bunch of old stuff from mapheaderinfo_t/associated, and reorder what stays
* Countdowntimer? 💥
* Startrings? 💥
* sstimer/ssspheres? 💥
* forcecharacter? 💥 (distinct from forceskin)
* interscreen? 💥
* sstage_start/end and smpstage_start/end? 💥💥💥💥
* You've been blocked
* G_MapNumber now returns a special NEXTMAP_INVALID if not found, for more consistent reference.
* Incorporate a good chunk of the `edit-headers` branch. Can't clear maps individually because of the new restrictions on sequential mapheaders, but we can add a "disable in vote screen, not even for map hell/archive" flag to a map at some future juncture for equivalent functionality...
"cheats" is a proper cvar now. Enabling it allows for cheats to be used any time, even in multiplayer, and disables gamedata saving. Turning it off undoes as many cheat commands as reasonably possible. Based a little bit off of some vanilla work I also did.
Many cheat commands are still SP-only, but can reasonably be allowed in netgames now if a net command is created for them.
* Allow colorisation types to not completely crowd each other out.
* For example, it's possible for invincibility + grow to flicker Invincibility, Eggman mark, and grow colours if the conditions for each type of flash are true on different frames!
Also removes a few remaining instances of player->bot being checked to affect gameplay where it shouldn't from vanilla, but it's code that is rarely used / completely unused anyway.
* Adjust several loading strings, and left-align their rendering.
* Don't call HU_LoadGraphics() again (startup cached ALL FONTS twice).
* Adjust when some functions are called during loading to more effectively compartmentalise sections of loading that depend on each other.
* LOADED_ISTARTUPGRAPHICS now comes after SCR_Startup, as we can explicitly guarantee the palette has been loaded after that function.
* Make sure everything closely related to configurations (gamedata, console stuff, etc) which is not directly dependent on anything else is loaded under LOADED_CONFIG - "Load settings" (formerly LOADED_MINIT).
* The `-warp` command line parameter is now checked alongside LOADED_DCHECKNETGAME.
* Don't attempt to draw the loading bar before LOADED_ISTARTUPGRAPHICS, as the palette is not loaded, which means you're wasting cycles on a white screen.
* Fix the screen being stuck black at the very start of start record attack.
* Bump up the demoversion to 7, because I want all previous v2 demos to be guaranteed kaput (it was previously 4, but 7 is a nice number).
* Fix a ton MORE shitcausing misalignments in the replay system, this time specifically focused on getting ghosts functional.
* Plug a few holes in the "best lap" record implementation that allowed for stupidly easy records due to the way v2's finish lines work.
* Make a few follower-related things sane, to prevent spurious console prints that were getting in the way of my test prints.
* Fixed a bug where you'd see :nick: on the current character selection screen if you didn't have many skins loaded.
* Fixed a bug where character skins loaded in PK3s would attempt to load every single lump of the PK3, even if it wasn't in the same subfolder as the original S_SKIN, as a sprite into the player struct. Could stand to be ported to vanilla.
Requires new chars.kart, which was created using the help of the indev 2.2-based Kartmaker update which will be available shortly.