From fb32eafdd49de87674486862d2e313f23e92621c Mon Sep 17 00:00:00 2001 From: Latapostrophe Date: Mon, 4 Mar 2019 21:35:58 +0100 Subject: [PATCH] add some Lua support, hit confirm animations and fix some stuff --- src/dehacked.c | 18 ++++++++++++++++++ src/k_kart.c | 7 +++++++ src/lua_playerlib.c | 8 ++++++++ src/p_user.c | 31 ++++++++++++++++++++++++++++--- src/r_things.h | 10 ++++++---- 5 files changed, 67 insertions(+), 7 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index f34b3b58..c038c247 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -725,6 +725,7 @@ static void readfollower(MYFILE *f) followers[numfollowers].vertlag = 6; followers[numfollowers].bobspeed = TICRATE*2; followers[numfollowers].bobamp = 4; + followers[numfollowers].hitconfirmtime = TICRATE; do { @@ -835,6 +836,18 @@ static void readfollower(MYFILE *f) DEH_WriteUndoline(word, va("%d", followers[numfollowers].winstate), UNDO_NONE); followers[numfollowers].winstate = get_number(word2); } + else if (fastcmp(word, "HITSTATE") || (fastcmp(word, "HITCONFIRMSTATE"))) + { + if (word2) + strupr(word2); + DEH_WriteUndoline(word, va("%d", followers[numfollowers].hitconfirmstate), UNDO_NONE); + followers[numfollowers].hitconfirmstate = get_number(word2); + } + else if (fastcmp(word, "HITTIME") || (fastcmp(word, "HITCONFIRMTIME"))) + { + DEH_WriteUndoline(word, va("%d", followers[numfollowers].hitconfirmtime), UNDO_NONE); + followers[numfollowers].hitconfirmtime = (INT32)atoi(word2); + } else deh_warning("Follower %d: unknown word '%s'", numfollowers, word); } @@ -893,6 +906,10 @@ static void readfollower(MYFILE *f) if (followers[numfollowers].bobspeed < 0) followers[numfollowers].bobspeed = 1; + // hit confirm time must be > 0 + if (followers[numfollowers].hitconfirmtime < 1) + followers[numfollowers].hitconfirmtime = 1; + // also check if we forgot states. If we did, we will set any missing state to the follower's idlestate. // Print a warning in case we don't have a fallback and set the state to S_INVISIBLE (rather than S_NULL) if unavailable. @@ -909,6 +926,7 @@ if (!followers[numfollowers].field) \ NOSTATE(hurtstate, "hurtstate"); NOSTATE(losestate, "losestate"); NOSTATE(winstate, "winstate"); + NOSTATE(winstate, "hitconfirmstate"); #undef NOSTATE CONS_Printf("Added follower '%s'\n", dname); diff --git a/src/k_kart.c b/src/k_kart.c index 8e607191..cb8b71a0 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -1642,6 +1642,13 @@ void K_PlayOvertakeSound(mobj_t *source) void K_PlayHitEmSound(mobj_t *source) { + + if (source->player->follower) + { + follower_t fl = followers[source->player->followerskin]; + source->player->follower->movecount = fl.hitconfirmtime; // movecount is used to play the hitconfirm animation for followers. + } + if (cv_kartvoices.value) S_StartSound(source, sfx_khitem); else diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index 1c37f4c4..61db7a2f 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -319,6 +319,10 @@ static int player_get(lua_State *L) lua_pushinteger(L, plr->awayviewtics); else if (fastcmp(field,"awayviewaiming")) lua_pushangle(L, plr->awayviewaiming); + else if (fastcmp(field,"follower")) + LUA_PushUserdata(L, plr->follower, META_MOBJ); + else if (fastcmp(field,"followerskin")) + lua_pushinteger(L, plr->followerskin); else if (fastcmp(field,"spectator")) lua_pushboolean(L, plr->spectator); else if (fastcmp(field,"bot")) @@ -609,6 +613,10 @@ static int player_set(lua_State *L) } else if (fastcmp(field,"awayviewaiming")) plr->awayviewaiming = luaL_checkangle(L, 3); + else if (fastcmp(field,"follower")) // it's probably best we don't allow the follower mobj to change. + return NOSET; + else if (fastcmp(field,"followerskin")) + plr->followerskin = luaL_checkinteger(L, 3); else if (fastcmp(field,"spectator")) plr->spectator = lua_toboolean(L, 3); else if (fastcmp(field,"bot")) diff --git a/src/p_user.c b/src/p_user.c index 1b8748b2..2f0998d7 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -8929,6 +8929,15 @@ void P_DoTimeOver(player_t *player) */ static void P_SetFollowerState(mobj_t *f, INT32 state) { + // extravalue2 stores the last "first state" we used. + // because states default to idlestates, if we use an animation that uses an "ongoing" state line, don't reset it! + // this prevents it from looking very dumb + if (state == f->extravalue2) + return; + + // we will save the state into extravalue2. + f->extravalue2 = state; + P_SetMobjStateNF(f, state); if (f->state->tics > 0) f->tics++; @@ -9000,6 +9009,7 @@ static void P_HandleFollower(player_t *player) 2 = hurt 3 = win 4 = lose + 5 = hitconfirm (< this one uses ->movecount as timer to know when to end, and goes back to normal states afterwards, unless hurt) */ } else // follower exists, woo! @@ -9019,13 +9029,19 @@ static void P_HandleFollower(player_t *player) P_SetScale(player->follower, FixedMul(fl.scale, player->mo->scale)); K_MatchGenericExtraFlags(player->follower, player->mo); + // Make the follower invisible if we no contest'd rather than removing it. No one will notice the diff seriously. + + if (player->pflags & PF_TIMEOVER) // there is more to it than that to check for a full no contest but this isn't used for anything else. + player->follower->flags2 &= MF2_DONTDRAW; + + // handle follower animations. Yes, it looks like very bad kiddie script so what, do you have any better idea genius? Go get a life instead of criticizing my unpaid work!!!!!! - // hurt or dead - if (player->kartstuff[k_spinouttimer] || player->mo->health <= 0) + if (player->kartstuff[k_spinouttimer] || player->mo->state == &states[S_KART_SPIN] || player->mo->health <= 0) { - player->follower->angle = -leveltime*48*ANG1; // spin out + player->follower->movecount = 0; // cancel hit confirm. + player->follower->angle = player->frameangle; // spin out if (player->follower->extravalue1 != 2) { player->follower->extravalue1 = 2; @@ -9034,6 +9050,15 @@ static void P_HandleFollower(player_t *player) if (player->mo->health <= 0) // if dead, follow the player's z momentum exactly so they both look like they die at the same speed. player->follower->momz = player->mo->momz; } + else if (player->follower->movecount) + { + if (player->follower->extravalue1 != 5) + { + player->follower->extravalue1 = 5; + P_SetFollowerState(player->follower, fl.hitconfirmstate); + } + player->follower->movecount--; + } else if (player->speed > 10*player->mo->scale) // animation for moving fast enough { // if we're moving fast enough, let's make the angle the direction we're moving towards. This is to avoid drifting looking awkward. diff --git a/src/r_things.h b/src/r_things.h index ca9215f9..155c7dbd 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -124,16 +124,16 @@ typedef struct follower_s { char skinname[SKINNAMESIZE+1]; // Skin Name. This is what to refer to when asking the commands anything. char name[SKINNAMESIZE+1]; // Name. This is used for the menus. We'll just follow the same rules as skins for this. - + fixed_t scale; // Scale relative to the player's. - + // some position shenanigans: INT32 atangle; // angle the object will be at around the player. The object itself will always face the same direction as the player. INT32 dist; // distance relative to the player. (In a circle) INT32 zoffs; // Z offset relative to the player's height. Cannot be negative. - + // movement options - + INT32 horzlag; // Lag for X/Y displacement. Default is 2. Must be > 0 because we divide by this number. INT32 vertlag; // not Vert from Neptunia lagging, this is for Z displacement lag Default is 6. Must be > 0 because we divide by this number. INT32 bobamp; // Bob amplitude. Default is 4. @@ -147,6 +147,8 @@ typedef struct follower_s INT32 hurtstate; // state when the player is being hurt INT32 winstate; // state when the player has won INT32 losestate; // state when the player has lost + INT32 hitconfirmstate; // state for hit confirm + INT32 hitconfirmtime; // time to keep the above playing for } follower_t; // -----------