From 593641ce8275bd43a6eb6be397638e2c48b599b7 Mon Sep 17 00:00:00 2001 From: Misa Date: Thu, 29 Dec 2022 15:00:01 -0800 Subject: [PATCH] Always destroy and create new player in startgamemode This fixes a bug where players could flip in mid-air at the start of custom levels whose start points were in mid-air, because onground/onroof were not being reset. This could also be done when loading in to a save with a checkpoint in mid-air. All that's required is to exit the game while standing on a surface (or otherwise having a nonzero onground/onroof). This reminded me that there were other variables on the player entity persisting through that made loading in to a level not have a totally clean slate, such as walkingframe (which could affect sequencing individual TASes together into one TAS), so it's better to just destroy the player entity and recreate it. Except some attributes still have to be persisted for 2.2 and 2.0 glitchrunner mode. But it's better that this is done via a whitelist rather than a blacklist. The player duplicate removal code in hardreset is mostly redundant now (except for some very unlikely corner cases), but there's nothing wrong with having redundant code as long as it's not harmful. I had a paragraph here justifying why it could be removed but decided it was simpler to just keep it. --- desktop_version/src/Script.cpp | 45 ++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/desktop_version/src/Script.cpp b/desktop_version/src/Script.cpp index b6fe587f..4fe50db8 100644 --- a/desktop_version/src/Script.cpp +++ b/desktop_version/src/Script.cpp @@ -2400,6 +2400,34 @@ void scriptclass::startgamemode(const enum StartMode mode) VVV_exit(0); } + struct + { + bool initialized; + int size; + int cx; + int cy; + int w; + int h; + } + player_hitbox; + SDL_zero(player_hitbox); + + if (GlitchrunnerMode_less_than_or_equal(Glitchrunner2_2)) + { + /* Preserve player hitbox */ + const int player_idx = obj.getplayer(); + if (INBOUNDS_VEC(player_idx, obj.entities)) + { + const entclass* player = &obj.entities[player_idx]; + player_hitbox.initialized = true; + player_hitbox.size = player->size; + player_hitbox.cx = player->cx; + player_hitbox.cy = player->cy; + player_hitbox.w = player->w; + player_hitbox.h = player->h; + } + } + hardreset(); if (mode == Start_EDITOR) @@ -2663,10 +2691,23 @@ void scriptclass::startgamemode(const enum StartMode mode) obj.flags[73] = true; } - if (obj.entities.empty()) + obj.entities.clear(); + obj.createentity(game.savex, game.savey, 0, 0); + if (player_hitbox.initialized) { - obj.createentity(game.savex, game.savey, 0, 0); //In this game, constant, never destroyed + /* Restore player hitbox */ + const int player_idx = obj.getplayer(); + if (INBOUNDS_VEC(player_idx, obj.entities)) + { + entclass* player = &obj.entities[player_idx]; + player->size = player_hitbox.size; + player->cx = player_hitbox.cx; + player->cy = player_hitbox.cy; + player->w = player_hitbox.w; + player->h = player_hitbox.h; + } } + map.resetplayer(); map.gotoroom(game.saverx, game.savery); map.initmapdata();