From 505e2db2c42a406021e52472cbd983ce92ef3b60 Mon Sep 17 00:00:00 2001 From: James R Date: Thu, 17 Mar 2022 20:31:46 -0700 Subject: [PATCH 01/42] Add Hyudoro states --- src/deh_tables.c | 6 +++++ src/info.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++ src/info.h | 7 ++++++ 3 files changed, 70 insertions(+) diff --git a/src/deh_tables.c b/src/deh_tables.c index 8bdae717d..7266303da 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -3973,6 +3973,9 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_FLAMESHIELDLINE3", "S_FLAMESHIELDFLASH", + // Caked-Up Booty-Sheet Ghost + "S_HYUDORO", + // The legend "S_SINK", "S_SINK_SHIELD", @@ -5544,6 +5547,9 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_FLAMESHIELDPAPER", "MT_BUBBLESHIELDTRAP", + "MT_HYUDORO", + "MT_HYUDORO_CENTER", + "MT_SINK", // Kitchen Sink Stuff "MT_SINK_SHIELD", "MT_SINKTRAIL", diff --git a/src/info.c b/src/info.c index 9ebc1bf4c..00463602f 100644 --- a/src/info.c +++ b/src/info.c @@ -569,6 +569,7 @@ char sprnames[NUMSPRITES + 1][5] = "FLMP", // Flame Shield paper sprites "FLML", // Flame Shield speed lines "FLMF", // Flame Shield flash + "HYUU", // Hyudoro "SINK", // Kitchen Sink "SITR", // Kitchen Sink Trail "KBLN", // Battle Mode Bumper @@ -4529,6 +4530,8 @@ state_t states[NUMSTATES] = {SPR_FLML, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_ANIMATE|14, 7, {NULL}, 6, 1, S_NULL}, // S_FLAMESHIELDLINE3 {SPR_FLMF, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_FLAMESHIELDFLASH + {SPR_HYUU, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_HYUDORO + {SPR_SINK, 0, 1, {A_SmokeTrailer}, MT_SINKTRAIL, 0, S_SINK}, // S_SINK {SPR_SINK, 0|FF_TRANS80|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_SINK_SHIELD}, // S_SINK_SHIELD {SPR_SITR, 0, 1, {NULL}, 0, 0, S_SINKTRAIL2}, // S_SINKTRAIL1 @@ -24521,6 +24524,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_HYUDORO + -1, // doomednum + S_HYUDORO, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 64*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + + { // MT_HYUDORO_CENTER + -1, // doomednum + S_INVISIBLE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 64*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + { // MT_SINK -1, // doomednum S_SINK, // spawnstate diff --git a/src/info.h b/src/info.h index 71da066b8..a7e869bd9 100644 --- a/src/info.h +++ b/src/info.h @@ -1117,6 +1117,7 @@ typedef enum sprite SPR_FLMP, // Flame Shield paper sprites SPR_FLML, // Flame Shield speed lines SPR_FLMF, // Flame Shield flash + SPR_HYUU, // Hyudoro SPR_SINK, // Kitchen Sink SPR_SITR, // Kitchen Sink Trail SPR_KBLN, // Battle Mode Bumper @@ -4953,6 +4954,9 @@ typedef enum state S_FLAMESHIELDLINE3, S_FLAMESHIELDFLASH, + // Caked-Up Booty-Sheet Ghost + S_HYUDORO, + // The legend S_SINK, S_SINK_SHIELD, @@ -6561,6 +6565,9 @@ typedef enum mobj_type MT_FLAMESHIELDPAPER, MT_BUBBLESHIELDTRAP, + MT_HYUDORO, + MT_HYUDORO_CENTER, + MT_SINK, // Kitchen Sink Stuff MT_SINK_SHIELD, MT_SINKTRAIL, From cd9777f0cbf6142694edb99960c8611c3b1fd12a Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 22 Mar 2022 17:46:36 -0700 Subject: [PATCH 02/42] MT_GHOST: dont flicker tracer's DONTDRAW flags --- src/p_mobj.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 3a4cd1751..0dc5ec131 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -9207,14 +9207,19 @@ void P_MobjThinker(mobj_t *mobj) { if (mobj->extravalue2 >= 2) { + UINT32 dontdraw = RF_DONTDRAW; + + if (mobj->tracer) + dontdraw &= ~(mobj->tracer->renderflags); + if (mobj->extravalue2 == 2) // I don't know why the normal logic doesn't work for this. - mobj->renderflags ^= RF_DONTDRAW; + mobj->renderflags ^= dontdraw; else { if (mobj->fuse == mobj->extravalue2) - mobj->renderflags &= ~RF_DONTDRAW; + mobj->renderflags &= ~(dontdraw); else - mobj->renderflags |= RF_DONTDRAW; + mobj->renderflags |= dontdraw; } } } From 61399981a2d7c87eab71f1ee8a3ebd4f5185399b Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 22 Mar 2022 17:47:29 -0700 Subject: [PATCH 03/42] MT_SHADOW + SPR_NONE, teleports to tracer and renders only a shadow --- src/deh_tables.c | 3 ++- src/info.c | 29 +++++++++++++++++++++++++++++ src/info.h | 4 +++- src/p_mobj.c | 9 +++++++++ 4 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/deh_tables.c b/src/deh_tables.c index 7266303da..b7aaf262d 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -369,8 +369,8 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_XDEATHSTATE", "S_RAISESTATE", - // Thok "S_THOK", + "S_SHADOW", // SRB2kart Frames "S_KART_STILL", @@ -4705,6 +4705,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_UNKNOWN", "MT_THOK", // Thok! mobj + "MT_SHADOW", // Linkdraw Shadow (for invisible objects) "MT_PLAYER", "MT_KART_LEFTOVER", "MT_KART_TIRE", diff --git a/src/info.c b/src/info.c index 00463602f..8680bc9c7 100644 --- a/src/info.c +++ b/src/info.c @@ -28,6 +28,7 @@ char sprnames[NUMSPRITES + 1][5] = { "NULL", // invisible object + "NONE", // invisible but still rendered "UNKN", "THOK", // Thok! mobj @@ -850,6 +851,7 @@ state_t states[NUMSTATES] = {SPR_UNKN, FF_FULLBRIGHT, -1, {A_InfoState}, 6, 0, S_NULL}, // S_RAISESTATE {SPR_THOK, FF_TRANS50, 8, {NULL}, 0, 0, S_NULL}, // S_THOK + {SPR_NONE, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SHADOW // Player {SPR_PLAY, SPR2_STIN, 1, {NULL}, 0, 0, S_KART_STILL}, // S_KART_STILL @@ -5364,6 +5366,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_SHADOW + -1, // doomednum + S_SHADOW, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 8, // speed + 32*FRACUNIT, // radius + 64*FRACUNIT, // height + -1, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + { // MT_PLAYER -1, // doomednum S_KART_STILL, // spawnstate diff --git a/src/info.h b/src/info.h index a7e869bd9..e3257fdeb 100644 --- a/src/info.h +++ b/src/info.h @@ -576,6 +576,7 @@ extern boolean actionsoverridden[NUMACTIONS]; typedef enum sprite { SPR_NULL, // invisible object + SPR_NONE, // invisible but still rendered SPR_UNKN, SPR_THOK, // Thok! mobj @@ -1351,8 +1352,8 @@ typedef enum state S_XDEATHSTATE, S_RAISESTATE, - // Thok S_THOK, + S_SHADOW, S_KART_STILL, S_KART_STILL_L, @@ -5723,6 +5724,7 @@ typedef enum mobj_type MT_UNKNOWN, MT_THOK, // Thok! mobj + MT_SHADOW, // Linkdraw Shadow (for invisible objects) MT_PLAYER, MT_KART_LEFTOVER, MT_KART_TIRE, diff --git a/src/p_mobj.c b/src/p_mobj.c index 0dc5ec131..05d802b02 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -5307,6 +5307,15 @@ static void P_MobjSceneryThink(mobj_t *mobj) switch (mobj->type) { + case MT_SHADOW: + if (mobj->tracer) + { + P_MoveOrigin(mobj, + mobj->tracer->x, + mobj->tracer->y, + mobj->tracer->z); + } + break; case MT_BOSSJUNK: mobj->renderflags ^= RF_DONTDRAW; break; From 910ebe9d0fafb041c71b19b3b8abe6c63dd583e7 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 29 Apr 2022 22:01:51 -0700 Subject: [PATCH 04/42] Add objects subdirectory For game object-specific code --- src/CMakeLists.txt | 1 + src/Makefile | 1 + 2 files changed, 2 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1355c85ee..53eeb5248 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -302,6 +302,7 @@ target_compile_definitions(SRB2SDL2 PRIVATE -DCMAKECONFIG) #) add_subdirectory(sdl) +add_subdirectory(objects) if(${CMAKE_SYSTEM} MATCHES Windows) add_subdirectory(win32) diff --git a/src/Makefile b/src/Makefile index 9659a4994..ffec6a4cf 100644 --- a/src/Makefile +++ b/src/Makefile @@ -208,6 +208,7 @@ objdir:=$(makedir)/objs sources+=\ $(call List,Sourcefile)\ $(call List,blua/Sourcefile)\ + $(call List,objects/Sourcefile)\ depends:=$(basename $(filter %.c %.s,$(sources))) objects:=$(basename $(filter %.c %.s %.nas,$(sources))) From c6e7fe2d298bc4841c25d519838f14fc60db9a1e Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 29 Apr 2022 22:02:22 -0700 Subject: [PATCH 05/42] Hyudoro object code --- src/d_player.h | 1 + src/info.c | 6 +- src/k_kart.c | 7 +- src/objects/Sourcefile | 1 + src/objects/hyudoro.c | 402 +++++++++++++++++++++++++++++++++++++++++ src/p_inter.c | 5 + src/p_mobj.c | 16 +- 7 files changed, 432 insertions(+), 6 deletions(-) create mode 100644 src/objects/Sourcefile create mode 100644 src/objects/hyudoro.c diff --git a/src/d_player.h b/src/d_player.h index 55c2857d5..c72944268 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -465,6 +465,7 @@ typedef struct player_s UINT16 hyudorotimer; // Duration of the Hyudoro offroad effect itself SINT8 stealingtimer; // if >0 you are stealing, if <0 you are being stolen from + mobj_t *hoverhyudoro; // First hyudoro hovering next to player UINT16 sneakertimer; // Duration of a Sneaker Boost (from Sneakers or level boosters) UINT8 numsneakers; // Number of stacked sneaker effects diff --git a/src/info.c b/src/info.c index 8680bc9c7..136ef3cb8 100644 --- a/src/info.c +++ b/src/info.c @@ -24570,13 +24570,13 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 64*FRACUNIT, // radius - 32*FRACUNIT, // height + 32*FRACUNIT, // radius + 24*FRACUNIT, // height 0, // display offset 0, // mass 0, // damage sfx_None, // activesound - MF_NOGRAVITY|MF_DONTENCOREMAP, // flags + MF_SPECIAL|MF_NOCLIP|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, diff --git a/src/k_kart.c b/src/k_kart.c index 412f3bdc3..8ac2ccc22 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -36,6 +36,7 @@ #include "k_hud.h" #include "k_terrain.h" #include "k_director.h" +#include "k_objects.h" // SOME IMPORTANT VARIABLES DEFINED IN DOOMDEF.H: // gamespeed is cc (0 for easy, 1 for normal, 2 for hard) @@ -5178,6 +5179,7 @@ static void K_FlameDashLeftoverSmoke(mobj_t *src) } } +#if 0 static void K_DoHyudoroSteal(player_t *player) { INT32 i, numplayers = 0; @@ -5255,6 +5257,7 @@ static void K_DoHyudoroSteal(player_t *player) S_StartSound(NULL, sfx_s3k92); } } +#endif void K_DoSneaker(player_t *player, INT32 type) { @@ -9563,7 +9566,9 @@ void K_MoveKartPlayer(player_t *player, boolean onground) if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) { player->itemamount--; - K_DoHyudoroSteal(player); // yes. yes they do. + //K_DoHyudoroSteal(player); // yes. yes they do. + Obj_HyudoroDeploy(player->mo); + K_PlayAttackTaunt(player->mo); } break; case KITEM_POGOSPRING: diff --git a/src/objects/Sourcefile b/src/objects/Sourcefile new file mode 100644 index 000000000..f7e4f2491 --- /dev/null +++ b/src/objects/Sourcefile @@ -0,0 +1 @@ +hyudoro.c diff --git a/src/objects/hyudoro.c b/src/objects/hyudoro.c new file mode 100644 index 000000000..35c3680df --- /dev/null +++ b/src/objects/hyudoro.c @@ -0,0 +1,402 @@ +#include "../doomdef.h" +#include "../doomstat.h" +#include "../info.h" +#include "../k_kart.h" +#include "../k_objects.h" +#include "../m_random.h" +#include "../p_local.h" +#include "../r_main.h" +#include "../s_sound.h" + +enum { + HYU_PATROL, + HYU_RETURN, + HYU_HOVER, +}; + +// TODO: make these general functions + +static fixed_t +K_GetSpeed (mobj_t *mobj) +{ + return FixedHypot(mobj->momx, mobj->momy); +} + +static void +K_ChangePlayerItem +( player_t * player, + INT32 itemtype, + INT32 itemamount) +{ + player->itemtype = itemtype; + player->itemamount = itemamount; + K_UnsetItemOut(player); +} + +#define hyudoro_mode(o) ((o)->extravalue1) +#define hyudoro_itemtype(o) ((o)->movefactor) +#define hyudoro_itemcount(o) ((o)->movecount) +#define hyudoro_hover_stack(o) ((o)->threshold) +#define hyudoro_next(o) ((o)->tracer) +#define hyudoro_stackpos(o) ((o)->reactiontime) + +// cannot be combined +#define hyudoro_center(o) ((o)->target) +#define hyudoro_target(o) ((o)->target) + +#define hyudoro_center_max_radius(o) ((o)->threshold) +#define hyudoro_center_master(o) ((o)->target) + +static angle_t +trace_angle (mobj_t *hyu) +{ + mobj_t *center = hyu->target; + + if (hyu->x != center->x || hyu->y != center->y) + { + return R_PointToAngle2( + center->x, center->y, hyu->x, hyu->y); + } + else + return hyu->angle; +} + +static angle_t +get_look_angle (mobj_t *thing) +{ + player_t *player = thing->player; + + return player ? player->angleturn : thing->angle; +} + +static boolean +is_hyudoro (mobj_t *thing) +{ + return thing && thing->type == MT_HYUDORO; +} + +static mobj_t * +get_hyudoro_master (mobj_t *hyu) +{ + mobj_t *center = hyudoro_center(hyu); + + return center ? hyudoro_center_master(center) : NULL; +} + +static void +sine_bob +( mobj_t * hyu, + angle_t a, + fixed_t sineofs) +{ + hyu->sprzoff = FixedMul(hyu->height, + sineofs + FINESINE(a >> ANGLETOFINESHIFT)); +} + +static void +project_hyudoro (mobj_t *hyu) +{ + mobj_t *center = hyudoro_center(hyu); + + angle_t angleStep = FixedMul(5 * ANG1, + FixedDiv(hyudoro_center_max_radius(center), + center->radius)); + + angle_t angle = trace_angle(hyu) + angleStep; + + fixed_t d = center->radius; + + fixed_t x = P_ReturnThrustX(center, angle, d); + fixed_t y = P_ReturnThrustY(center, angle, d); + + hyu->momx = (center->x + x) - hyu->x; + hyu->momy = (center->y + y) - hyu->y; + hyu->angle = angle + ANGLE_90; + + sine_bob(hyu, angle, FRACUNIT); +} + +static void +project_hyudoro_hover (mobj_t *hyu) +{ + const INT32 bob_speed = 64; + + mobj_t *target = hyudoro_target(hyu); + + // Turns a bit toward its target + angle_t ang = get_look_angle(target) + ANGLE_67h; + fixed_t rad = (target->radius * 2) + hyu->radius; + + fixed_t zofs = hyudoro_stackpos(hyu) * + ((target->height / 2) + (hyu->height * 2)); + + P_MoveOrigin(hyu, + target->x - P_ReturnThrustX(hyu, ang, rad), + target->y - P_ReturnThrustY(hyu, ang, rad), + target->z + (zofs * P_MobjFlip(target))); + + // Cancel momentum from HYU_RETURN. + // (And anything else! I don't trust this game!!) + hyu->momx = 0; + hyu->momy = 0; + + hyu->angle = ang; + + // copies sprite tilting + hyu->pitch = target->pitch; + hyu->roll = target->roll; + + sine_bob(hyu, + (leveltime & (bob_speed - 1)) * + (ANGLE_MAX / bob_speed), -(3*FRACUNIT/4)); +} + +static void +spawn_hyudoro_shadow (mobj_t *hyu) +{ + mobj_t *shadow = P_SpawnMobjFromMobj( + hyu, 0, 0, 0, MT_SHADOW); + + shadow->whiteshadow = true; + + shadow->shadowscale = hyu->shadowscale; + hyu->shadowscale = 0; + + P_SetTarget(&shadow->tracer, hyu); +} + +static void +move_to_player (mobj_t *hyu) +{ + mobj_t *target = hyudoro_target(hyu); + + angle_t angle; + + if (!target) + return; + + angle = R_PointToAngle2( + hyu->x, hyu->y, target->x, target->y); + + P_InstaThrust(hyu, angle, (hyu->radius / 2) + + max(hyu->radius, K_GetSpeed(target))); + + hyu->z = target->z; // stay level with target + hyu->angle = angle; +} + +static void +deliver_item (mobj_t *hyu) +{ + mobj_t *target = hyudoro_target(hyu); + player_t *player = target->player; + + P_SetTarget(&hyudoro_target(hyu), NULL); + + K_ChangePlayerItem(player, + hyudoro_itemtype(hyu), + hyudoro_itemcount(hyu)); + + S_StartSound(target, sfx_itpick); + + // Stop moving here + hyu->momx = 0; + hyu->momy = 0; + + hyu->tics = 4; + + hyu->destscale = target->scale / 4; + hyu->scalespeed = + abs(hyu->scale - hyu->destscale) / hyu->tics; +} + +static void +append_hyudoro +( mobj_t ** head, + mobj_t * hyu) +{ + INT32 lastpos = 0; + + while (is_hyudoro(*head)) + { + lastpos = hyudoro_stackpos(*head); + head = &hyudoro_next(*head); + } + + hyudoro_stackpos(hyu) = lastpos + 1; + *head = hyu; +} + +static boolean +hyudoro_patrol_hit_player +( mobj_t * hyu, + mobj_t * toucher) +{ + player_t *player = toucher->player; + + mobj_t *center = hyudoro_center(hyu); + + if (!player) + return false; + + // Cannot hit its master + if (toucher == get_hyudoro_master(hyu)) + return false; + + // Don't punish a punished player + if (player->hyudorotimer) + return false; + + // NO ITEM? + if (!player->itemamount) + return false; + + K_AddHitLag(toucher, TICRATE/2, true); + + player->hyudorotimer = hyudorotime; + player->stealingtimer = hyudorotime; + + hyudoro_mode(hyu) = HYU_RETURN; + hyudoro_itemtype(hyu) = player->itemtype; + hyudoro_itemcount(hyu) = player->itemamount; + + K_ChangePlayerItem(player, KITEM_NONE, 0); + + P_SetTarget(&hyudoro_target(hyu), + hyudoro_center_master(center)); + + if (center) + P_RemoveMobj(center); + + hyu->renderflags &= ~(RF_DONTDRAW); + + return true; +} + +static boolean +hyudoro_return_hit_player +( mobj_t * hyu, + mobj_t * toucher) +{ + player_t *player = toucher->player; + + if (toucher != hyudoro_target(hyu)) + return false; + + // If the player already has an item, just hover beside + // them until they use/lose it. + if (player->itemamount || player->itemroulette) + { + hyudoro_mode(hyu) = HYU_HOVER; + append_hyudoro(&player->hoverhyudoro, hyu); + } + else + { + deliver_item(hyu); + } + + return true; +} + +void +Obj_HyudoroDeploy (mobj_t *master) +{ + mobj_t *center = P_SpawnMobjFromMobj( + master, 0, 0, 0, MT_HYUDORO_CENTER); + + mobj_t *hyu = P_SpawnMobjFromMobj( + center, 0, 0, 0, MT_HYUDORO); + + // This allows a Lua override + if (!hyudoro_center_max_radius(center)) + { + hyudoro_center_max_radius(center) = + 128 * center->scale; + } + + center->radius = hyu->radius; + + P_InitAngle(hyu, master->angle); + P_SetTarget(&hyudoro_center(hyu), center); + P_SetTarget(&hyudoro_center_master(center), master); + + hyudoro_mode(hyu) = HYU_PATROL; + + // Set splitscreen player visibility + if (master->player) + { + hyu->renderflags |= RF_DONTDRAW & + ~(K_GetPlayerDontDrawFlag(master->player)); + } + + spawn_hyudoro_shadow(hyu); // this sucks btw + + S_StartSound(master, sfx_s3k92); // scary ghost noise +} + +void +Obj_HyudoroThink (mobj_t *hyu) +{ + // Might get set from clipping slopes + hyu->momz = 0; + + switch (hyudoro_mode(hyu)) + { + case HYU_PATROL: + if (hyudoro_center(hyu)) + project_hyudoro(hyu); + + if (leveltime & 1) + { + mobj_t *ghost = P_SpawnGhostMobj(hyu); + + // Flickers every frame + ghost->extravalue1 = 1; + ghost->extravalue2 = 2; + + // copy per-splitscreen-player visibility + ghost->renderflags = + (hyu->renderflags & RF_DONTDRAW); + + ghost->tics = 8; + + P_SetTarget(&ghost->tracer, hyu); + } + break; + + case HYU_RETURN: + move_to_player(hyu); + break; + + case HYU_HOVER: + if (hyudoro_target(hyu)) + project_hyudoro_hover(hyu); + break; + } +} + +void +Obj_HyudoroCenterThink (mobj_t *center) +{ + fixed_t max_radius = hyudoro_center_max_radius(center); + + if (center->radius < max_radius) + center->radius += max_radius / 64; +} + +void +Obj_HyudoroCollide +( mobj_t * hyu, + mobj_t * toucher) +{ + switch (hyudoro_mode(hyu)) + { + case HYU_PATROL: + hyudoro_patrol_hit_player(hyu, toucher); + break; + + case HYU_RETURN: + hyudoro_return_hit_player(hyu, toucher); + break; + } +} diff --git a/src/p_inter.c b/src/p_inter.c index aceb8336c..d73828916 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -37,6 +37,7 @@ #include "k_boss.h" #include "k_respawn.h" #include "p_spec.h" +#include "k_objects.h" // CTF player names #define CTFTEAMCODE(pl) pl->ctfteam ? (pl->ctfteam == 1 ? "\x85" : "\x84") : "" @@ -483,6 +484,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) S_StartSound(toucher, sfx_s1b2); return; + case MT_HYUDORO: + Obj_HyudoroCollide(special, toucher); + return; + case MT_RING: case MT_FLINGRING: if (special->extravalue1) diff --git a/src/p_mobj.c b/src/p_mobj.c index 05d802b02..f23047371 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -42,6 +42,7 @@ #include "k_respawn.h" #include "k_bot.h" #include "k_terrain.h" +#include "k_objects.h" static CV_PossibleValue_t CV_BobSpeed[] = {{0, "MIN"}, {4*FRACUNIT, "MAX"}, {0, NULL}}; consvar_t cv_movebob = CVAR_INIT ("movebob", "1.0", CV_FLOAT|CV_SAVE, CV_BobSpeed, NULL); @@ -6559,8 +6560,8 @@ static boolean P_MobjRegularThink(mobj_t *mobj) } else if (P_IsObjectOnGround(mobj)) { - mobj->momx = 1; - mobj->momy = 0; + //mobj->momx = 1; + //mobj->momy = 0; mobj->flags &= ~MF_NOCLIPTHING; mobj->flags |= MF_NOGRAVITY; } @@ -7717,6 +7718,16 @@ static boolean P_MobjRegularThink(mobj_t *mobj) } break; } + case MT_HYUDORO: + { + Obj_HyudoroThink(mobj); + break; + } + case MT_HYUDORO_CENTER: + { + Obj_HyudoroCenterThink(mobj); + break; + } case MT_ROCKETSNEAKER: if (!mobj->target || !mobj->target->health) { @@ -9671,6 +9682,7 @@ static void P_DefaultMobjShadowScale(mobj_t *thing) case MT_SSMINE_SHIELD: case MT_LANDMINE: case MT_BALLHOG: + case MT_HYUDORO: case MT_SINK: case MT_ROCKETSNEAKER: case MT_SPB: From 39ff9ce383e010492f736a287d96d949a40b1286 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 29 Apr 2022 23:43:25 -0700 Subject: [PATCH 06/42] Remove orphaned MT_SHADOW --- src/p_mobj.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/p_mobj.c b/src/p_mobj.c index f23047371..8d727c308 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -5316,6 +5316,11 @@ static void P_MobjSceneryThink(mobj_t *mobj) mobj->tracer->y, mobj->tracer->z); } + else + { + P_RemoveMobj(mobj); + return; + } break; case MT_BOSSJUNK: mobj->renderflags ^= RF_DONTDRAW; From 3e8d50a44ae5d3d5d6d1c00ffb5cad1968619bf4 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 30 Apr 2022 00:25:42 -0700 Subject: [PATCH 07/42] Fix/finish hyudoro return delivery - Fix item detection, matches paper sprite pickups - Stacked hyudoros deliver item once player is not holding --- src/objects/hyudoro.c | 101 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 90 insertions(+), 11 deletions(-) diff --git a/src/objects/hyudoro.c b/src/objects/hyudoro.c index 35c3680df..b4778c8c5 100644 --- a/src/objects/hyudoro.c +++ b/src/objects/hyudoro.c @@ -83,6 +83,14 @@ get_hyudoro_master (mobj_t *hyu) return center ? hyudoro_center_master(center) : NULL; } +static player_t * +get_hyudoro_target_player (mobj_t *hyu) +{ + mobj_t *target = hyudoro_target(hyu); + + return target ? target->player : NULL; +} + static void sine_bob ( mobj_t * hyu, @@ -193,9 +201,12 @@ deliver_item (mobj_t *hyu) P_SetTarget(&hyudoro_target(hyu), NULL); - K_ChangePlayerItem(player, - hyudoro_itemtype(hyu), - hyudoro_itemcount(hyu)); + if (player) + { + K_ChangePlayerItem(player, + hyudoro_itemtype(hyu), + player->itemamount + hyudoro_itemcount(hyu)); + } S_StartSound(target, sfx_itpick); @@ -227,6 +238,33 @@ append_hyudoro *head = hyu; } +static void +pop_hyudoro (mobj_t **head) +{ + mobj_t *hyu = *head; + + INT32 lastpos; + INT32 thispos; + + if (is_hyudoro(hyu)) + { + lastpos = hyudoro_stackpos(hyu); + hyu = hyudoro_next(hyu); + + while (is_hyudoro(hyu)) + { + thispos = hyudoro_stackpos(hyu); + + hyudoro_stackpos(hyu) = lastpos; + lastpos = thispos; + + hyu = hyudoro_next(hyu); + } + } + + *head = hyu; +} + static boolean hyudoro_patrol_hit_player ( mobj_t * hyu, @@ -273,31 +311,69 @@ hyudoro_patrol_hit_player return true; } +static boolean +award_immediately (mobj_t *hyu) +{ + player_t *player = get_hyudoro_target_player(hyu); + + if (player) + { + if (player->itemamount && + player->itemtype != hyudoro_itemtype(hyu)) + { + return false; + } + + // Same as picking up paper items; get stacks + // immediately + if (!P_CanPickupItem(player, 3)) + return false; + } + + deliver_item(hyu); + + return true; +} + static boolean hyudoro_return_hit_player ( mobj_t * hyu, mobj_t * toucher) { - player_t *player = toucher->player; - if (toucher != hyudoro_target(hyu)) return false; // If the player already has an item, just hover beside // them until they use/lose it. - if (player->itemamount || player->itemroulette) + if (!award_immediately(hyu)) { hyudoro_mode(hyu) = HYU_HOVER; - append_hyudoro(&player->hoverhyudoro, hyu); - } - else - { - deliver_item(hyu); + append_hyudoro(&toucher->player->hoverhyudoro, hyu); } return true; } +static boolean +hyudoro_hover_await_stack (mobj_t *hyu) +{ + player_t *player = get_hyudoro_target_player(hyu); + + if (!player) + return false; + + // First in stack goes first + if (hyu == player->hoverhyudoro) + return false; + + if (!award_immediately(hyu)) + return false; + + pop_hyudoro(&player->hoverhyudoro); + + return true; +} + void Obj_HyudoroDeploy (mobj_t *master) { @@ -370,7 +446,10 @@ Obj_HyudoroThink (mobj_t *hyu) case HYU_HOVER: if (hyudoro_target(hyu)) + { project_hyudoro_hover(hyu); + hyudoro_hover_await_stack(hyu); + } break; } } From 8fd251b54c7feee6cff375d899ec221b05bf7fdf Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 1 May 2022 13:36:01 -0700 Subject: [PATCH 08/42] Revert wrongly committed code --- src/p_mobj.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 8d727c308..54ea94703 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6565,8 +6565,8 @@ static boolean P_MobjRegularThink(mobj_t *mobj) } else if (P_IsObjectOnGround(mobj)) { - //mobj->momx = 1; - //mobj->momy = 0; + mobj->momx = 1; + mobj->momy = 0; mobj->flags &= ~MF_NOCLIPTHING; mobj->flags |= MF_NOGRAVITY; } From 2196ccef62136e517a3f2c8bb04c02d4f0b33ef1 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 1 May 2022 13:36:17 -0700 Subject: [PATCH 09/42] Add k_objects.h --- src/k_objects.h | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/k_objects.h diff --git a/src/k_objects.h b/src/k_objects.h new file mode 100644 index 000000000..45f9df78c --- /dev/null +++ b/src/k_objects.h @@ -0,0 +1,11 @@ +/* object-specific code */ +#ifndef k_objects_H +#define k_objects_H + +/* Hyudoro */ +void Obj_HyudoroDeploy(mobj_t *master); +void Obj_HyudoroThink(mobj_t *actor); +void Obj_HyudoroCenterThink(mobj_t *actor); +void Obj_HyudoroCollide(mobj_t *special, mobj_t *toucher); + +#endif/*k_objects_H*/ From 38ab22f02272ccb498920302edfeed96ac218ec5 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 1 May 2022 14:04:25 -0700 Subject: [PATCH 10/42] Netsave player.hoverhyudoro --- src/p_saveg.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/p_saveg.c b/src/p_saveg.c index 18cef0e94..f6acde09e 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -62,6 +62,7 @@ typedef enum FOLLOWER = 0x04, SKYBOXVIEW = 0x08, SKYBOXCENTER = 0x10, + HOVERHYUDORO = 0x20, } player_saveflags; static inline void P_ArchivePlayer(void) @@ -195,6 +196,9 @@ static void P_NetArchivePlayers(void) if (players[i].skybox.centerpoint) flags |= SKYBOXCENTER; + if (players[i].hoverhyudoro) + flags |= HOVERHYUDORO; + WRITEUINT16(save_p, flags); if (flags & SKYBOXVIEW) @@ -209,6 +213,9 @@ static void P_NetArchivePlayers(void) if (flags & FOLLOWITEM) WRITEUINT32(save_p, players[i].followmobj->mobjnum); + if (flags & HOVERHYUDORO) + WRITEUINT32(save_p, players[i].hoverhyudoro->mobjnum); + WRITEUINT32(save_p, (UINT32)players[i].followitem); WRITEUINT32(save_p, players[i].charflags); @@ -474,6 +481,9 @@ static void P_NetUnArchivePlayers(void) if (flags & FOLLOWITEM) players[i].followmobj = (mobj_t *)(size_t)READUINT32(save_p); + if (flags & HOVERHYUDORO) + players[i].hoverhyudoro = (mobj_t *)(size_t)READUINT32(save_p); + players[i].followitem = (mobjtype_t)READUINT32(save_p); //SetPlayerSkinByNum(i, players[i].skin); @@ -4213,6 +4223,13 @@ static void P_RelinkPointers(void) CONS_Debug(DBG_GAMELOGIC, "respawn.wp not found on %d\n", mobj->type); } } + if (mobj->player->hoverhyudoro) + { + temp = (UINT32)(size_t)mobj->player->hoverhyudoro; + mobj->player->hoverhyudoro = NULL; + if (!P_SetTarget(&mobj->player->hoverhyudoro, P_FindNewPosition(temp))) + CONS_Debug(DBG_GAMELOGIC, "hoverhyudoro not found on %d\n", mobj->type); + } } } } From 64b8da086f1fe4a52761f9ed45355230b34bed81 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 1 May 2022 14:39:19 -0700 Subject: [PATCH 11/42] Readjust race item odds for Hyudoro --- src/k_kart.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 8ac2ccc22..1f0c0047b 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -352,21 +352,21 @@ static INT32 K_KartItemOddsRace[NUMKARTRESULTS-1][8] = //P-Odds 0 1 2 3 4 5 6 7 /*Sneaker*/ { 0, 0, 2, 4, 6, 0, 0, 0 }, // Sneaker /*Rocket Sneaker*/ { 0, 0, 0, 0, 0, 2, 4, 6 }, // Rocket Sneaker - /*Invincibility*/ { 0, 0, 0, 0, 2, 4, 6, 9 }, // Invincibility - /*Banana*/ { 4, 3, 1, 0, 0, 0, 0, 0 }, // Banana + /*Invincibility*/ { 0, 0, 0, 0, 3, 4, 6, 9 }, // Invincibility + /*Banana*/ { 2, 3, 1, 0, 0, 0, 0, 0 }, // Banana /*Eggman Monitor*/ { 1, 2, 0, 0, 0, 0, 0, 0 }, // Eggman Monitor /*Orbinaut*/ { 5, 4, 2, 2, 0, 0, 0, 0 }, // Orbinaut /*Jawz*/ { 0, 3, 2, 1, 1, 0, 0, 0 }, // Jawz /*Mine*/ { 0, 2, 3, 1, 0, 0, 0, 0 }, // Mine /*Land Mine*/ { 3, 0, 0, 0, 0, 0, 0, 0 }, // Land Mine - /*Ballhog*/ { 0, 0, 2, 1, 0, 0, 0, 0 }, // Ballhog + /*Ballhog*/ { 0, 0, 2, 2, 0, 0, 0, 0 }, // Ballhog /*Self-Propelled Bomb*/ { 0, 0, 0, 0, 0, 2, 4, 0 }, // Self-Propelled Bomb /*Grow*/ { 0, 0, 0, 1, 2, 3, 0, 0 }, // Grow /*Shrink*/ { 0, 0, 0, 0, 0, 0, 2, 0 }, // Shrink /*Thunder Shield*/ { 1, 2, 0, 0, 0, 0, 0, 0 }, // Thunder Shield /*Bubble Shield*/ { 0, 1, 2, 1, 0, 0, 0, 0 }, // Bubble Shield /*Flame Shield*/ { 0, 0, 0, 0, 0, 1, 3, 5 }, // Flame Shield - /*Hyudoro*/ { 0, 0, 0, 1, 1, 0, 0, 0 }, // Hyudoro + /*Hyudoro*/ { 2, 0, 0, 0, 0, 0, 0, 0 }, // Hyudoro /*Pogo Spring*/ { 0, 0, 0, 0, 0, 0, 0, 0 }, // Pogo Spring /*Super Ring*/ { 2, 1, 1, 0, 0, 0, 0, 0 }, // Super Ring /*Kitchen Sink*/ { 0, 0, 0, 0, 0, 0, 0, 0 }, // Kitchen Sink From 2de756d0772f076b00765e3cf21d90b314102953 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 1 May 2022 18:31:17 -0700 Subject: [PATCH 12/42] Fix typo --- src/objects/hyudoro.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objects/hyudoro.c b/src/objects/hyudoro.c index b4778c8c5..e8fc14de3 100644 --- a/src/objects/hyudoro.c +++ b/src/objects/hyudoro.c @@ -363,7 +363,7 @@ hyudoro_hover_await_stack (mobj_t *hyu) return false; // First in stack goes first - if (hyu == player->hoverhyudoro) + if (hyu != player->hoverhyudoro) return false; if (!award_immediately(hyu)) From 543928b5bbc14b027cc0c920db946cbbf22b6293 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 22 May 2022 21:04:52 -0400 Subject: [PATCH 13/42] Adjust Hyuu frequency --- src/k_kart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index b2fa1b627..08bd77101 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -367,11 +367,11 @@ static INT32 K_KartItemOddsRace[NUMKARTRESULTS-1][8] = /*Lightning Shield*/ { 1, 2, 0, 0, 0, 0, 0, 0 }, // Lightning Shield /*Bubble Shield*/ { 0, 1, 2, 1, 0, 0, 0, 0 }, // Bubble Shield /*Flame Shield*/ { 0, 0, 0, 0, 0, 1, 3, 5 }, // Flame Shield - /*Hyudoro*/ { 2, 0, 0, 0, 0, 0, 0, 0 }, // Hyudoro + /*Hyudoro*/ { 3, 0, 0, 0, 0, 0, 0, 0 }, // Hyudoro /*Pogo Spring*/ { 0, 0, 0, 0, 0, 0, 0, 0 }, // Pogo Spring /*Super Ring*/ { 2, 1, 1, 0, 0, 0, 0, 0 }, // Super Ring /*Kitchen Sink*/ { 0, 0, 0, 0, 0, 0, 0, 0 }, // Kitchen Sink - /*Drop Target*/ { 4, 0, 0, 0, 0, 0, 0, 0 }, // Drop Target + /*Drop Target*/ { 3, 0, 0, 0, 0, 0, 0, 0 }, // Drop Target /*Sneaker x2*/ { 0, 0, 2, 2, 1, 0, 0, 0 }, // Sneaker x2 /*Sneaker x3*/ { 0, 0, 0, 2, 6,10, 5, 0 }, // Sneaker x3 /*Banana x3*/ { 0, 1, 1, 0, 0, 0, 0, 0 }, // Banana x3 From c8718b25ffd38b947b1bb404021c3b3fb3d2d121 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 22 May 2022 21:14:02 -0400 Subject: [PATCH 14/42] REMOVE hyubgone + all of the other bullshit we did to try and make it show up less --- src/doomstat.h | 1 - src/g_game.c | 1 - src/k_kart.c | 11 +---------- src/lua_script.c | 5 ----- src/p_saveg.c | 2 -- src/p_setup.c | 1 - src/p_tick.c | 2 -- 7 files changed, 1 insertion(+), 22 deletions(-) diff --git a/src/doomstat.h b/src/doomstat.h index 163bfee96..8c2671c96 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -685,7 +685,6 @@ extern boolean comeback; extern SINT8 battlewanted[4]; extern tic_t wantedcalcdelay; extern tic_t indirectitemcooldown; -extern tic_t hyubgone; extern tic_t mapreset; extern boolean thwompsactive; extern UINT8 lastLowestLap; diff --git a/src/g_game.c b/src/g_game.c index 21467e592..6eae4df17 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -314,7 +314,6 @@ SINT8 pickedvote; // What vote the host rolls SINT8 battlewanted[4]; // WANTED players in battle, worth x2 points tic_t wantedcalcdelay; // Time before it recalculates WANTED tic_t indirectitemcooldown; // Cooldown before any more Shrink, SPB, or any other item that works indirectly is awarded -tic_t hyubgone; // Cooldown before hyudoro is allowed to be rerolled tic_t mapreset; // Map reset delay when enough players have joined an empty game boolean thwompsactive; // Thwomps activate on lap 2 UINT8 lastLowestLap; // Last lowest lap, for activating race lap executors diff --git a/src/k_kart.c b/src/k_kart.c index 08bd77101..a1f9ac788 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -458,9 +458,6 @@ static void K_KartGetItemResult(player_t *player, SINT8 getitem) if (getitem == KITEM_SPB || getitem == KITEM_SHRINK) // Indirect items indirectitemcooldown = 20*TICRATE; - if (getitem == KITEM_HYUDORO) // Hyudoro cooldown - hyubgone = 5*TICRATE; - player->botvars.itemdelay = TICRATE; player->botvars.itemconfirm = 0; @@ -682,6 +679,7 @@ INT32 K_KartGetItemOdds( case KITEM_LANDMINE: case KITEM_DROPTARGET: case KITEM_BALLHOG: + case KITEM_HYUDORO: case KRITEM_TRIPLESNEAKER: case KRITEM_TRIPLEORBINAUT: case KRITEM_QUADORBINAUT: @@ -742,13 +740,6 @@ INT32 K_KartGetItemOdds( if (spbplace != -1) newodds = 0; break; - case KITEM_HYUDORO: - cooldownOnStart = true; - notNearEnd = true; - - if (hyubgone > 0) - newodds = 0; - break; default: break; } diff --git a/src/lua_script.c b/src/lua_script.c index 3f919439f..8aea589db 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -378,9 +378,6 @@ int LUA_PushGlobals(lua_State *L, const char *word) } else if (fastcmp(word,"indirectitemcooldown")) { lua_pushinteger(L, indirectitemcooldown); return 1; - } else if (fastcmp(word,"hyubgone")) { - lua_pushinteger(L, hyubgone); - return 1; } else if (fastcmp(word,"thwompsactive")) { lua_pushboolean(L, thwompsactive); return 1; @@ -468,8 +465,6 @@ int LUA_WriteGlobals(lua_State *L, const char *word) exitcountdown = (tic_t)luaL_checkinteger(L, 2); else if (fastcmp(word,"indirectitemcooldown")) indirectitemcooldown = (tic_t)luaL_checkinteger(L, 2); - else if (fastcmp(word,"hyubgone")) - hyubgone = (tic_t)luaL_checkinteger(L, 2); else return 0; diff --git a/src/p_saveg.c b/src/p_saveg.c index 8b4604c8a..3cb65e7a7 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -4505,7 +4505,6 @@ static void P_NetArchiveMisc(boolean resending) WRITEUINT32(save_p, wantedcalcdelay); WRITEUINT32(save_p, indirectitemcooldown); - WRITEUINT32(save_p, hyubgone); WRITEUINT32(save_p, mapreset); for (i = 0; i < MAXPLAYERS; i++) @@ -4655,7 +4654,6 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading) wantedcalcdelay = READUINT32(save_p); indirectitemcooldown = READUINT32(save_p); - hyubgone = READUINT32(save_p); mapreset = READUINT32(save_p); for (i = 0; i < MAXPLAYERS; i++) diff --git a/src/p_setup.c b/src/p_setup.c index c1da43eef..2f23d6c1f 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -4405,7 +4405,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) wantedcalcdelay = wantedfrequency*2; indirectitemcooldown = 0; - hyubgone = 0; mapreset = 0; for (i = 0; i < MAXPLAYERS; i++) diff --git a/src/p_tick.c b/src/p_tick.c index c7dae9030..843461db6 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -685,8 +685,6 @@ void P_Ticker(boolean run) if (indirectitemcooldown > 0) indirectitemcooldown--; - if (hyubgone > 0) - hyubgone--; K_BossInfoTicker(); From 0ce466e7efacd1e97971ae1fb2bee9f6e6390a9d Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 22 May 2022 21:34:24 -0400 Subject: [PATCH 15/42] Some asserts in hyu code Instead of letting it crash due to a NULL subsector later, let it crash earlier so I can see what is happening... --- src/objects/hyudoro.c | 54 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/src/objects/hyudoro.c b/src/objects/hyudoro.c index e8fc14de3..b5ece9157 100644 --- a/src/objects/hyudoro.c +++ b/src/objects/hyudoro.c @@ -37,21 +37,55 @@ K_ChangePlayerItem #define hyudoro_itemtype(o) ((o)->movefactor) #define hyudoro_itemcount(o) ((o)->movecount) #define hyudoro_hover_stack(o) ((o)->threshold) -#define hyudoro_next(o) ((o)->tracer) + +static mobj_t * +hyudoro_next (mobj_t *o) +{ + I_Assert(o != NULL && P_MobjWasRemoved(o) == false); + I_Assert(o->tracer != NULL && P_MobjWasRemoved(o->tracer) == false); + + return o->tracer; +} + #define hyudoro_stackpos(o) ((o)->reactiontime) -// cannot be combined -#define hyudoro_center(o) ((o)->target) -#define hyudoro_target(o) ((o)->target) +// these next two functions cannot be combined +static mobj_t * +hyudoro_center (mobj_t *o) +{ + I_Assert(o != NULL && P_MobjWasRemoved(o) == false); + I_Assert(o->target != NULL && P_MobjWasRemoved(o->target) == false); + + return o->target; +} + +static mobj_t * +hyudoro_target (mobj_t *o) +{ + I_Assert(o != NULL && P_MobjWasRemoved(o) == false); + I_Assert(o->target != NULL && P_MobjWasRemoved(o->target) == false); + + return o->target; +} #define hyudoro_center_max_radius(o) ((o)->threshold) -#define hyudoro_center_master(o) ((o)->target) + +static mobj_t * +hyudoro_center_master (mobj_t *o) +{ + I_Assert(o != NULL && P_MobjWasRemoved(o) == false); + I_Assert(o->target != NULL && P_MobjWasRemoved(o->target) == false); + + return o->target; +} static angle_t trace_angle (mobj_t *hyu) { mobj_t *center = hyu->target; + I_Assert(center != NULL && P_MobjWasRemoved(center) == false); + if (hyu->x != center->x || hyu->y != center->y) { return R_PointToAngle2( @@ -66,13 +100,15 @@ get_look_angle (mobj_t *thing) { player_t *player = thing->player; + I_Assert(player != NULL); + return player ? player->angleturn : thing->angle; } static boolean is_hyudoro (mobj_t *thing) { - return thing && thing->type == MT_HYUDORO; + return thing != NULL && P_MobjWasRemoved(thing) == false && thing->type == MT_HYUDORO; } static mobj_t * @@ -80,6 +116,8 @@ get_hyudoro_master (mobj_t *hyu) { mobj_t *center = hyudoro_center(hyu); + I_Assert(center != NULL && P_MobjWasRemoved(center) == false); + return center ? hyudoro_center_master(center) : NULL; } @@ -97,6 +135,8 @@ sine_bob angle_t a, fixed_t sineofs) { + I_Assert(hyu != NULL && P_MobjWasRemoved(hyu) == false); + hyu->sprzoff = FixedMul(hyu->height, sineofs + FINESINE(a >> ANGLETOFINESHIFT)); } @@ -180,7 +220,7 @@ move_to_player (mobj_t *hyu) angle_t angle; - if (!target) + if (target == NULL || P_MobjWasRemoved(target) == true) return; angle = R_PointToAngle2( From 5ef78cbc16b795a90ce04fe032e2650af8d817f7 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 22 May 2022 21:41:40 -0400 Subject: [PATCH 16/42] EVEN MORE (also removed the define replacements since didn't work) --- src/objects/hyudoro.c | 69 +++++++++++++++++++------------------------ src/p_mobj.c | 2 ++ 2 files changed, 32 insertions(+), 39 deletions(-) diff --git a/src/objects/hyudoro.c b/src/objects/hyudoro.c index b5ece9157..d72a597c4 100644 --- a/src/objects/hyudoro.c +++ b/src/objects/hyudoro.c @@ -37,47 +37,15 @@ K_ChangePlayerItem #define hyudoro_itemtype(o) ((o)->movefactor) #define hyudoro_itemcount(o) ((o)->movecount) #define hyudoro_hover_stack(o) ((o)->threshold) - -static mobj_t * -hyudoro_next (mobj_t *o) -{ - I_Assert(o != NULL && P_MobjWasRemoved(o) == false); - I_Assert(o->tracer != NULL && P_MobjWasRemoved(o->tracer) == false); - - return o->tracer; -} - +#define hyudoro_next(o) ((o)->tracer) #define hyudoro_stackpos(o) ((o)->reactiontime) -// these next two functions cannot be combined -static mobj_t * -hyudoro_center (mobj_t *o) -{ - I_Assert(o != NULL && P_MobjWasRemoved(o) == false); - I_Assert(o->target != NULL && P_MobjWasRemoved(o->target) == false); - - return o->target; -} - -static mobj_t * -hyudoro_target (mobj_t *o) -{ - I_Assert(o != NULL && P_MobjWasRemoved(o) == false); - I_Assert(o->target != NULL && P_MobjWasRemoved(o->target) == false); - - return o->target; -} +// cannot be combined +#define hyudoro_center(o) ((o)->target) +#define hyudoro_target(o) ((o)->target) #define hyudoro_center_max_radius(o) ((o)->threshold) - -static mobj_t * -hyudoro_center_master (mobj_t *o) -{ - I_Assert(o != NULL && P_MobjWasRemoved(o) == false); - I_Assert(o->target != NULL && P_MobjWasRemoved(o->target) == false); - - return o->target; -} +#define hyudoro_center_master(o) ((o)->target) static angle_t trace_angle (mobj_t *hyu) @@ -126,6 +94,8 @@ get_hyudoro_target_player (mobj_t *hyu) { mobj_t *target = hyudoro_target(hyu); + I_Assert(target != NULL && P_MobjWasRemoved(target) == false); + return target ? target->player : NULL; } @@ -220,6 +190,8 @@ move_to_player (mobj_t *hyu) angle_t angle; + I_Assert(hyu != NULL && P_MobjWasRemoved(hyu) == false); + if (target == NULL || P_MobjWasRemoved(target) == true) return; @@ -239,6 +211,10 @@ deliver_item (mobj_t *hyu) mobj_t *target = hyudoro_target(hyu); player_t *player = target->player; + I_Assert(hyu != NULL && P_MobjWasRemoved(hyu) == false); + I_Assert(target != NULL && P_MobjWasRemoved(target) == false); + I_Assert(player != NULL); + P_SetTarget(&hyudoro_target(hyu), NULL); if (player) @@ -268,6 +244,8 @@ append_hyudoro { INT32 lastpos = 0; + I_Assert(hyu != NULL && P_MobjWasRemoved(hyu) == false); + while (is_hyudoro(*head)) { lastpos = hyudoro_stackpos(*head); @@ -314,7 +292,11 @@ hyudoro_patrol_hit_player mobj_t *center = hyudoro_center(hyu); - if (!player) + I_Assert(hyu != NULL && P_MobjWasRemoved(hyu) == false); + I_Assert(toucher != NULL && P_MobjWasRemoved(toucher) == false); + I_Assert(center != NULL && P_MobjWasRemoved(center) == false); + + if (player == NULL) return false; // Cannot hit its master @@ -356,6 +338,8 @@ award_immediately (mobj_t *hyu) { player_t *player = get_hyudoro_target_player(hyu); + I_Assert(hyu != NULL && P_MobjWasRemoved(hyu) == false); + if (player) { if (player->itemamount && @@ -380,6 +364,9 @@ hyudoro_return_hit_player ( mobj_t * hyu, mobj_t * toucher) { + I_Assert(hyu != NULL && P_MobjWasRemoved(hyu) == false); + I_Assert(toucher != NULL && P_MobjWasRemoved(toucher) == false); + if (toucher != hyudoro_target(hyu)) return false; @@ -399,7 +386,9 @@ hyudoro_hover_await_stack (mobj_t *hyu) { player_t *player = get_hyudoro_target_player(hyu); - if (!player) + I_Assert(hyu != NULL && P_MobjWasRemoved(hyu) == false); + + if (player == NULL) return false; // First in stack goes first @@ -453,6 +442,8 @@ Obj_HyudoroDeploy (mobj_t *master) void Obj_HyudoroThink (mobj_t *hyu) { + I_Assert(hyu != NULL && P_MobjWasRemoved(hyu) == false); + // Might get set from clipping slopes hyu->momz = 0; diff --git a/src/p_mobj.c b/src/p_mobj.c index 009241c62..64d0f616c 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -13464,6 +13464,8 @@ mobj_t *P_SpawnMobjFromMobj(mobj_t *mobj, fixed_t xofs, fixed_t yofs, fixed_t zo { mobj_t *newmobj; + I_Assert(mobj != NULL && P_MobjWasRemoved(mobj) == false); + xofs = FixedMul(xofs, mobj->scale); yofs = FixedMul(yofs, mobj->scale); zofs = FixedMul(zofs, mobj->scale); From 098304bd996fdae56cd9862b60c5eb54ceb41008 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 22 May 2022 22:00:54 -0400 Subject: [PATCH 17/42] Allow hyu thru tripwire --- src/k_kart.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/k_kart.c b/src/k_kart.c index a1f9ac788..7a1d23bf6 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -2908,6 +2908,7 @@ boolean K_TripwirePassConditions(player_t *player) player->sneakertimer || player->growshrinktimer > 0 || player->flamedash || + player->hyudorotimer || player->speed > 2 * K_GetKartSpeed(player, false) ) return true; From 61d61dcf25ecfb8860e868482cad298555a2b63e Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 22 May 2022 22:02:21 -0400 Subject: [PATCH 18/42] Revert "EVEN MORE" This reverts commit 5ef78cbc16b795a90ce04fe032e2650af8d817f7. --- src/objects/hyudoro.c | 69 ++++++++++++++++++++++++------------------- src/p_mobj.c | 2 -- 2 files changed, 39 insertions(+), 32 deletions(-) diff --git a/src/objects/hyudoro.c b/src/objects/hyudoro.c index d72a597c4..b5ece9157 100644 --- a/src/objects/hyudoro.c +++ b/src/objects/hyudoro.c @@ -37,15 +37,47 @@ K_ChangePlayerItem #define hyudoro_itemtype(o) ((o)->movefactor) #define hyudoro_itemcount(o) ((o)->movecount) #define hyudoro_hover_stack(o) ((o)->threshold) -#define hyudoro_next(o) ((o)->tracer) + +static mobj_t * +hyudoro_next (mobj_t *o) +{ + I_Assert(o != NULL && P_MobjWasRemoved(o) == false); + I_Assert(o->tracer != NULL && P_MobjWasRemoved(o->tracer) == false); + + return o->tracer; +} + #define hyudoro_stackpos(o) ((o)->reactiontime) -// cannot be combined -#define hyudoro_center(o) ((o)->target) -#define hyudoro_target(o) ((o)->target) +// these next two functions cannot be combined +static mobj_t * +hyudoro_center (mobj_t *o) +{ + I_Assert(o != NULL && P_MobjWasRemoved(o) == false); + I_Assert(o->target != NULL && P_MobjWasRemoved(o->target) == false); + + return o->target; +} + +static mobj_t * +hyudoro_target (mobj_t *o) +{ + I_Assert(o != NULL && P_MobjWasRemoved(o) == false); + I_Assert(o->target != NULL && P_MobjWasRemoved(o->target) == false); + + return o->target; +} #define hyudoro_center_max_radius(o) ((o)->threshold) -#define hyudoro_center_master(o) ((o)->target) + +static mobj_t * +hyudoro_center_master (mobj_t *o) +{ + I_Assert(o != NULL && P_MobjWasRemoved(o) == false); + I_Assert(o->target != NULL && P_MobjWasRemoved(o->target) == false); + + return o->target; +} static angle_t trace_angle (mobj_t *hyu) @@ -94,8 +126,6 @@ get_hyudoro_target_player (mobj_t *hyu) { mobj_t *target = hyudoro_target(hyu); - I_Assert(target != NULL && P_MobjWasRemoved(target) == false); - return target ? target->player : NULL; } @@ -190,8 +220,6 @@ move_to_player (mobj_t *hyu) angle_t angle; - I_Assert(hyu != NULL && P_MobjWasRemoved(hyu) == false); - if (target == NULL || P_MobjWasRemoved(target) == true) return; @@ -211,10 +239,6 @@ deliver_item (mobj_t *hyu) mobj_t *target = hyudoro_target(hyu); player_t *player = target->player; - I_Assert(hyu != NULL && P_MobjWasRemoved(hyu) == false); - I_Assert(target != NULL && P_MobjWasRemoved(target) == false); - I_Assert(player != NULL); - P_SetTarget(&hyudoro_target(hyu), NULL); if (player) @@ -244,8 +268,6 @@ append_hyudoro { INT32 lastpos = 0; - I_Assert(hyu != NULL && P_MobjWasRemoved(hyu) == false); - while (is_hyudoro(*head)) { lastpos = hyudoro_stackpos(*head); @@ -292,11 +314,7 @@ hyudoro_patrol_hit_player mobj_t *center = hyudoro_center(hyu); - I_Assert(hyu != NULL && P_MobjWasRemoved(hyu) == false); - I_Assert(toucher != NULL && P_MobjWasRemoved(toucher) == false); - I_Assert(center != NULL && P_MobjWasRemoved(center) == false); - - if (player == NULL) + if (!player) return false; // Cannot hit its master @@ -338,8 +356,6 @@ award_immediately (mobj_t *hyu) { player_t *player = get_hyudoro_target_player(hyu); - I_Assert(hyu != NULL && P_MobjWasRemoved(hyu) == false); - if (player) { if (player->itemamount && @@ -364,9 +380,6 @@ hyudoro_return_hit_player ( mobj_t * hyu, mobj_t * toucher) { - I_Assert(hyu != NULL && P_MobjWasRemoved(hyu) == false); - I_Assert(toucher != NULL && P_MobjWasRemoved(toucher) == false); - if (toucher != hyudoro_target(hyu)) return false; @@ -386,9 +399,7 @@ hyudoro_hover_await_stack (mobj_t *hyu) { player_t *player = get_hyudoro_target_player(hyu); - I_Assert(hyu != NULL && P_MobjWasRemoved(hyu) == false); - - if (player == NULL) + if (!player) return false; // First in stack goes first @@ -442,8 +453,6 @@ Obj_HyudoroDeploy (mobj_t *master) void Obj_HyudoroThink (mobj_t *hyu) { - I_Assert(hyu != NULL && P_MobjWasRemoved(hyu) == false); - // Might get set from clipping slopes hyu->momz = 0; diff --git a/src/p_mobj.c b/src/p_mobj.c index 64d0f616c..009241c62 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -13464,8 +13464,6 @@ mobj_t *P_SpawnMobjFromMobj(mobj_t *mobj, fixed_t xofs, fixed_t yofs, fixed_t zo { mobj_t *newmobj; - I_Assert(mobj != NULL && P_MobjWasRemoved(mobj) == false); - xofs = FixedMul(xofs, mobj->scale); yofs = FixedMul(yofs, mobj->scale); zofs = FixedMul(zofs, mobj->scale); From 800dcc6302f303e33a318f9e74c21515ffad1243 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 22 May 2022 22:02:31 -0400 Subject: [PATCH 19/42] Revert "Some asserts in hyu code" This reverts commit 0ce466e7efacd1e97971ae1fb2bee9f6e6390a9d. --- src/objects/hyudoro.c | 54 ++++++------------------------------------- 1 file changed, 7 insertions(+), 47 deletions(-) diff --git a/src/objects/hyudoro.c b/src/objects/hyudoro.c index b5ece9157..e8fc14de3 100644 --- a/src/objects/hyudoro.c +++ b/src/objects/hyudoro.c @@ -37,55 +37,21 @@ K_ChangePlayerItem #define hyudoro_itemtype(o) ((o)->movefactor) #define hyudoro_itemcount(o) ((o)->movecount) #define hyudoro_hover_stack(o) ((o)->threshold) - -static mobj_t * -hyudoro_next (mobj_t *o) -{ - I_Assert(o != NULL && P_MobjWasRemoved(o) == false); - I_Assert(o->tracer != NULL && P_MobjWasRemoved(o->tracer) == false); - - return o->tracer; -} - +#define hyudoro_next(o) ((o)->tracer) #define hyudoro_stackpos(o) ((o)->reactiontime) -// these next two functions cannot be combined -static mobj_t * -hyudoro_center (mobj_t *o) -{ - I_Assert(o != NULL && P_MobjWasRemoved(o) == false); - I_Assert(o->target != NULL && P_MobjWasRemoved(o->target) == false); - - return o->target; -} - -static mobj_t * -hyudoro_target (mobj_t *o) -{ - I_Assert(o != NULL && P_MobjWasRemoved(o) == false); - I_Assert(o->target != NULL && P_MobjWasRemoved(o->target) == false); - - return o->target; -} +// cannot be combined +#define hyudoro_center(o) ((o)->target) +#define hyudoro_target(o) ((o)->target) #define hyudoro_center_max_radius(o) ((o)->threshold) - -static mobj_t * -hyudoro_center_master (mobj_t *o) -{ - I_Assert(o != NULL && P_MobjWasRemoved(o) == false); - I_Assert(o->target != NULL && P_MobjWasRemoved(o->target) == false); - - return o->target; -} +#define hyudoro_center_master(o) ((o)->target) static angle_t trace_angle (mobj_t *hyu) { mobj_t *center = hyu->target; - I_Assert(center != NULL && P_MobjWasRemoved(center) == false); - if (hyu->x != center->x || hyu->y != center->y) { return R_PointToAngle2( @@ -100,15 +66,13 @@ get_look_angle (mobj_t *thing) { player_t *player = thing->player; - I_Assert(player != NULL); - return player ? player->angleturn : thing->angle; } static boolean is_hyudoro (mobj_t *thing) { - return thing != NULL && P_MobjWasRemoved(thing) == false && thing->type == MT_HYUDORO; + return thing && thing->type == MT_HYUDORO; } static mobj_t * @@ -116,8 +80,6 @@ get_hyudoro_master (mobj_t *hyu) { mobj_t *center = hyudoro_center(hyu); - I_Assert(center != NULL && P_MobjWasRemoved(center) == false); - return center ? hyudoro_center_master(center) : NULL; } @@ -135,8 +97,6 @@ sine_bob angle_t a, fixed_t sineofs) { - I_Assert(hyu != NULL && P_MobjWasRemoved(hyu) == false); - hyu->sprzoff = FixedMul(hyu->height, sineofs + FINESINE(a >> ANGLETOFINESHIFT)); } @@ -220,7 +180,7 @@ move_to_player (mobj_t *hyu) angle_t angle; - if (target == NULL || P_MobjWasRemoved(target) == true) + if (!target) return; angle = R_PointToAngle2( From a12c88c5e213519422dcef33be3f81dabfe0dec6 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 22 May 2022 19:19:41 -0700 Subject: [PATCH 20/42] Strip items after stealing with Hyudoro --- src/objects/hyudoro.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/objects/hyudoro.c b/src/objects/hyudoro.c index e8fc14de3..af0241fe3 100644 --- a/src/objects/hyudoro.c +++ b/src/objects/hyudoro.c @@ -291,14 +291,14 @@ hyudoro_patrol_hit_player K_AddHitLag(toucher, TICRATE/2, true); - player->hyudorotimer = hyudorotime; - player->stealingtimer = hyudorotime; - hyudoro_mode(hyu) = HYU_RETURN; hyudoro_itemtype(hyu) = player->itemtype; hyudoro_itemcount(hyu) = player->itemamount; - K_ChangePlayerItem(player, KITEM_NONE, 0); + K_StripItems(player); + + player->hyudorotimer = hyudorotime; + player->stealingtimer = hyudorotime; P_SetTarget(&hyudoro_target(hyu), hyudoro_center_master(center)); From b5334e6b42ae6b4092dc0c68e58431d2c8e13972 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 23 May 2022 00:23:46 -0400 Subject: [PATCH 21/42] Move follower code to its own file --- src/Sourcefile | 1 + src/d_netcmd.c | 17 +- src/deh_soc.c | 57 +++--- src/doomdef.h | 2 +- src/g_demo.c | 5 +- src/k_follower.c | 462 +++++++++++++++++++++++++++++++++++++++++++++++ src/k_follower.h | 133 ++++++++++++++ src/k_kart.c | 3 +- src/m_menu.c | 3 +- src/p_user.c | 291 +---------------------------- src/r_data.h | 3 - src/r_draw.c | 1 - src/r_skins.c | 99 ---------- src/r_skins.h | 47 ----- 14 files changed, 649 insertions(+), 475 deletions(-) create mode 100644 src/k_follower.c create mode 100644 src/k_follower.h diff --git a/src/Sourcefile b/src/Sourcefile index 9c7960081..c1e29e119 100644 --- a/src/Sourcefile +++ b/src/Sourcefile @@ -118,3 +118,4 @@ k_hud.c k_terrain.c k_brightmap.c k_director.c +k_follower.c diff --git a/src/d_netcmd.c b/src/d_netcmd.c index c9a030ab8..8d66a27bc 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -58,6 +58,7 @@ #include "k_respawn.h" #include "k_grandprix.h" #include "k_boss.h" +#include "k_follower.h" #include "doomstat.h" #include "deh_tables.h" @@ -1452,7 +1453,7 @@ static void SendNameAndColor(UINT8 n) // Update follower for local games: if (cv_follower[n].value >= -1 && cv_follower[n].value != player->followerskin) - SetFollower(playernum, cv_follower[n].value); + K_SetFollowerByNum(playernum, cv_follower[n].value); player->followercolor = cv_followercolor[n].value; @@ -1632,11 +1633,13 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum) SetPlayerSkinByNum(playernum, skin); // set follower colour: - // Don't bother doing garbage and kicking if we receive None, this is both silly and a waste of time, this will be handled properly in P_HandleFollower. + // Don't bother doing garbage and kicking if we receive None, + // this is both silly and a waste of time, + // this will be handled properly in K_HandleFollower. p->followercolor = followercolor; // set follower - SetFollower(playernum, follower); + K_SetFollowerByNum(playernum, follower); #ifdef HAVE_DISCORDRPC if (playernum == consoleplayer) @@ -5316,7 +5319,7 @@ static void Follower_OnChange(void) return; } - num = R_FollowerAvailable(str); + num = K_FollowerAvailable(str); if (num == -1) // that's an error. CONS_Alert(CONS_WARNING, M_GetText("Follower '%s' not found\n"), str); @@ -5370,7 +5373,7 @@ static void Follower2_OnChange(void) return; } - num = R_FollowerAvailable(str); + num = K_FollowerAvailable(str); if (num == -1) // that's an error. CONS_Alert(CONS_WARNING, M_GetText("Follower '%s' not found\n"), str); @@ -5421,7 +5424,7 @@ static void Follower3_OnChange(void) return; } - num = R_FollowerAvailable(str); + num = K_FollowerAvailable(str); if (num == -1) // that's an error. CONS_Alert(CONS_WARNING, M_GetText("Follower '%s' not found\n"), str); @@ -5472,7 +5475,7 @@ static void Follower4_OnChange(void) return; } - num = R_FollowerAvailable(str); + num = K_FollowerAvailable(str); if (num == -1) // that's an error. CONS_Alert(CONS_WARNING, M_GetText("Follower '%s' not found\n"), str); diff --git a/src/deh_soc.c b/src/deh_soc.c index 973daadf1..6fe6ca36b 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -49,6 +49,7 @@ // SRB2Kart #include "filesrch.h" // refreshdirmenu +#include "k_follower.h" // Loops through every constant and operation in word and performs its calculations, returning the final value. fixed_t get_number(const char *word) @@ -3819,15 +3820,15 @@ void readfollower(MYFILE *f) // Ready the default variables for followers. We will overwrite them as we go! We won't set the name or states RIGHT HERE as this is handled down instead. followers[numfollowers].scale = FRACUNIT; - followers[numfollowers].bubblescale = 0; // No bubble by default - followers[numfollowers].atangle = 230; - followers[numfollowers].dist = 32; // changed from 16 to 32 to better account for ogl models - followers[numfollowers].height = 16; - followers[numfollowers].zoffs = 32; - followers[numfollowers].horzlag = 2; - followers[numfollowers].vertlag = 6; + followers[numfollowers].bubblescale = 0; // No bubble by default + followers[numfollowers].atangle = FixedAngle(230 * FRACUNIT); + followers[numfollowers].dist = 32*FRACUNIT; // changed from 16 to 32 to better account for ogl models + followers[numfollowers].height = 16*FRACUNIT; + followers[numfollowers].zoffs = 32*FRACUNIT; + followers[numfollowers].horzlag = 2*FRACUNIT; + followers[numfollowers].vertlag = 6*FRACUNIT; followers[numfollowers].bobspeed = TICRATE*2; - followers[numfollowers].bobamp = 4; + followers[numfollowers].bobamp = 4*FRACUNIT; followers[numfollowers].hitconfirmtime = TICRATE; followers[numfollowers].defaultcolor = SKINCOLOR_GREEN; @@ -3865,48 +3866,47 @@ void readfollower(MYFILE *f) } else if (fastcmp(word, "DEFAULTCOLOR")) { - followers[numfollowers].defaultcolor = (UINT16)get_number(word2); + followers[numfollowers].defaultcolor = get_number(word2); } - else if (fastcmp(word, "SCALE")) { - followers[numfollowers].scale = get_number(word2); + followers[numfollowers].scale = (fixed_t)get_number(word2); } else if (fastcmp(word, "BUBBLESCALE")) { - followers[numfollowers].bubblescale = get_number(word2); + followers[numfollowers].bubblescale = (fixed_t)get_number(word2); } else if (fastcmp(word, "ATANGLE")) { - followers[numfollowers].atangle = (INT32)atoi(word2); + followers[numfollowers].atangle = (angle_t)(get_number(word2) * ANG1); } else if (fastcmp(word, "HORZLAG")) { - followers[numfollowers].horzlag = (INT32)atoi(word2); + followers[numfollowers].horzlag = (fixed_t)get_number(word2); } else if (fastcmp(word, "VERTLAG")) { - followers[numfollowers].vertlag = (INT32)atoi(word2); + followers[numfollowers].vertlag = (fixed_t)get_number(word2); } else if (fastcmp(word, "BOBSPEED")) { - followers[numfollowers].bobspeed = (INT32)atoi(word2); + followers[numfollowers].bobspeed = (tic_t)get_number(word2); } else if (fastcmp(word, "BOBAMP")) { - followers[numfollowers].bobamp = (INT32)atoi(word2); + followers[numfollowers].bobamp = (fixed_t)get_number(word2); } else if (fastcmp(word, "ZOFFSET") || (fastcmp(word, "ZOFFS"))) { - followers[numfollowers].zoffs = (INT32)atoi(word2); + followers[numfollowers].zoffs = (fixed_t)get_number(word2); } else if (fastcmp(word, "DISTANCE") || (fastcmp(word, "DIST"))) { - followers[numfollowers].dist = (INT32)atoi(word2); + followers[numfollowers].dist = (fixed_t)get_number(word2); } else if (fastcmp(word, "HEIGHT")) { - followers[numfollowers].height = (INT32)atoi(word2); + followers[numfollowers].height = (fixed_t)get_number(word2); } else if (fastcmp(word, "IDLESTATE")) { @@ -3947,16 +3947,19 @@ void readfollower(MYFILE *f) } else if (fastcmp(word, "HITTIME") || (fastcmp(word, "HITCONFIRMTIME"))) { - followers[numfollowers].hitconfirmtime = (INT32)atoi(word2); + followers[numfollowers].hitconfirmtime = (tic_t)get_number(word2); } else + { deh_warning("Follower %d: unknown word '%s'", numfollowers, word); + } } } while (!myfeof(f)); // finish when the line is empty - if (!nameset) // well this is problematic. + if (!nameset) { - strcpy(followers[numfollowers].name, va("Follower%d", numfollowers)); // this is lazy, so what + // well this is problematic. + strcpy(followers[numfollowers].name, va("Follower%d", numfollowers)); // this is lazy, so what } // set skin name (this is just the follower's name in lowercases): @@ -3966,7 +3969,7 @@ void readfollower(MYFILE *f) // lower testname for skin checks... strlwr(testname); - res = R_FollowerAvailable(testname); + res = K_FollowerAvailable(testname); if (res > -1) // yikes, someone else has stolen our name already { INT32 startlen = strlen(testname); @@ -3990,7 +3993,7 @@ void readfollower(MYFILE *f) // fallbacks for variables // Print a warning if the variable is on a weird value and set it back to the minimum available if that's the case. #define FALLBACK(field, field2, threshold, set) \ -if (followers[numfollowers].field < threshold) \ +if ((signed)followers[numfollowers].field < threshold) \ { \ followers[numfollowers].field = set; \ deh_warning("Follower '%s': Value for '%s' is too low! Minimum should be %d. Value was overwritten to %d.", dname, field2, set, set); \ @@ -4008,7 +4011,7 @@ if (followers[numfollowers].field < threshold) \ FALLBACK(bubblescale, "BUBBLESCALE", 0, 0); // No negative scale // Special case for color I suppose - if (followers[numfollowers].defaultcolor > numskincolors-1) + if (followers[numfollowers].defaultcolor > (unsigned)(numskincolors-1)) { followers[numfollowers].defaultcolor = SKINCOLOR_GREEN; deh_warning("Follower \'%s\': Value for 'color' should be between 1 and %d.\n", dname, numskincolors-1); @@ -4036,7 +4039,7 @@ if (!followers[numfollowers].field) \ #undef NOSTATE CONS_Printf("Added follower '%s'\n", dname); - numfollowers++; // add 1 follower + numfollowers++; // add 1 follower Z_Free(s); } diff --git a/src/doomdef.h b/src/doomdef.h index 0b7745be2..f36e780e6 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -206,7 +206,7 @@ extern char logfilename[1024]; #define MAXPLAYERNAME 21 #define MAXSPLITSCREENPLAYERS 4 // Max number of players on a single computer -#define MAXSKINS 128 +#define MAXSKINS UINT8_MAX #define COLORRAMPSIZE 16 #define MAXCOLORNAME 32 diff --git a/src/g_demo.c b/src/g_demo.c index ddf471684..fcc19e224 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -51,6 +51,7 @@ #include "k_respawn.h" #include "k_bot.h" #include "k_color.h" +#include "k_follower.h" static CV_PossibleValue_t recordmultiplayerdemos_cons_t[] = {{0, "Disabled"}, {1, "Manual Save"}, {2, "Auto Save"}, {0, NULL}}; consvar_t cv_recordmultiplayerdemos = CVAR_INIT ("netdemo_record", "Manual Save", CV_SAVE, recordmultiplayerdemos_cons_t, NULL); @@ -300,7 +301,7 @@ void G_ReadDemoExtraData(void) // Set our follower M_Memcpy(name, demo_p, 16); demo_p += 16; - SetPlayerFollower(p, name); + K_SetFollowerByName(p, name); // Follower's color M_Memcpy(name, demo_p, 16); @@ -3057,7 +3058,7 @@ void G_DoPlayDemo(char *defdemoname) // Follower M_Memcpy(follower, demo_p, 16); demo_p += 16; - SetPlayerFollower(p, follower); + K_SetFollowerByName(p, follower); // Follower colour M_Memcpy(color, demo_p, 16); diff --git a/src/k_follower.c b/src/k_follower.c new file mode 100644 index 000000000..42b956e9a --- /dev/null +++ b/src/k_follower.c @@ -0,0 +1,462 @@ + +#include "k_follower.h" + +#include "k_kart.h" + +#include "doomtype.h" +#include "doomdef.h" +#include "g_game.h" +#include "g_demo.h" +#include "r_skins.h" +#include "p_local.h" +#include "p_mobj.h" + +INT32 numfollowers = 0; +follower_t followers[MAXSKINS]; + +CV_PossibleValue_t Followercolor_cons_t[MAXSKINCOLORS+3]; // +3 to account for "Match", "Opposite" & NULL + +/*-------------------------------------------------- + INT32 K_FollowerAvailable(const char *name) + + See header file for description. +--------------------------------------------------*/ +INT32 K_FollowerAvailable(const char *name) +{ + INT32 i; + + for (i = 0; i < numfollowers; i++) + { + if (stricmp(followers[i].skinname, name) == 0) + return i; + } + + return -1; +} + +/*-------------------------------------------------- + boolean K_SetFollowerByName(INT32 playernum, const char *skinname) + + See header file for description. +--------------------------------------------------*/ +boolean K_SetFollowerByName(INT32 playernum, const char *skinname) +{ + INT32 i; + player_t *player = &players[playernum]; + + if (stricmp("None", skinname) == 0) + { + K_SetFollowerByNum(playernum, -1); // reminder that -1 is nothing + return true; + } + + for (i = 0; i < numfollowers; i++) + { + // search in the skin list + if (stricmp(followers[i].skinname, skinname) == 0) + { + K_SetFollowerByNum(playernum, i); + return true; + } + } + + if (P_IsLocalPlayer(player)) + { + CONS_Alert(CONS_WARNING, M_GetText("Follower '%s' not found.\n"), skinname); + } + else if (server || IsPlayerAdmin(consoleplayer)) + { + CONS_Alert(CONS_WARNING, M_GetText("Player %d (%s) follower '%s' not found\n"), playernum, player_names[playernum], skinname); + } + + K_SetFollowerByNum(playernum, -1); // reminder that -1 is nothing + return false; +} + +/*-------------------------------------------------- + void K_SetFollowerByNum(INT32 playernum, INT32 skinnum) + + See header file for description. +--------------------------------------------------*/ +void K_SetFollowerByNum(INT32 playernum, INT32 skinnum) +{ + player_t *player = &players[playernum]; + mobj_t *bub; + mobj_t *tmp; + + player->followerready = true; // we are ready to perform follower related actions in the player thinker, now. + + if (skinnum >= -1 && skinnum <= numfollowers) // Make sure it exists! + { + /* + We don't spawn the follower here since it'll be easier to handle all of it in the Player thinker itself. + However, we will despawn it right here if there's any to make it easy for the player thinker to replace it or delete it. + */ + + if (player->follower && skinnum != player->followerskin) // this is also called when we change colour so don't respawn the follower unless we changed skins + { + // Remove follower's possible hnext list (bubble) + bub = player->follower->hnext; + + while (bub && !P_MobjWasRemoved(bub)) + { + tmp = bub->hnext; + P_RemoveMobj(bub); + bub = tmp; + } + + P_RemoveMobj(player->follower); + P_SetTarget(&player->follower, NULL); + } + + player->followerskin = skinnum; + + // for replays: We have changed our follower mid-game; let the game know so it can do the same in the replay! + demo_extradata[playernum] |= DXD_FOLLOWER; + return; + } + + if (P_IsLocalPlayer(player)) + { + CONS_Alert(CONS_WARNING, M_GetText("Follower %d not found\n"), skinnum); + } + else if (server || IsPlayerAdmin(consoleplayer)) + { + CONS_Alert(CONS_WARNING, "Player %d (%s) follower %d not found\n", playernum, player_names[playernum], skinnum); + } + + K_SetFollowerByNum(playernum, -1); // Not found, then set -1 (nothing) as our follower. +} + + +/*-------------------------------------------------- + static void K_SetFollowerState(mobj_t *f, statenum_t state) + + Sets a follower object's state. + This is done as a separate function to prevent running follower actions. + + Input Arguments:- + f - The follower's mobj_t. + state - The state to set. + + Return:- + None +--------------------------------------------------*/ +static void K_SetFollowerState(mobj_t *f, statenum_t state) +{ + if (f == NULL || P_MobjWasRemoved(f) == true) + { + // safety net + return; + } + + // No, do NOT set the follower to S_NULL. Set it to S_INVISIBLE. + if (state == S_NULL) + { + state = S_INVISIBLE; + f->threshold = 1; // Threshold = 1 means stop doing anything related to setting states, so that we don't get out of S_INVISIBLE + } + + // 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 == (statenum_t)f->extravalue2) + { + return; + } + + // we will save the state into extravalue2. + f->extravalue2 = state; + + P_SetMobjStateNF(f, state); + if (f->state->tics > 0) + { + f->tics++; + } +} + +/*-------------------------------------------------- + void K_HandleFollower(player_t *player) + + See header file for description. +--------------------------------------------------*/ +void K_HandleFollower(player_t *player) +{ + follower_t fl; + angle_t an; + fixed_t zoffs; + fixed_t sx, sy, sz, deltaz; + UINT16 color; + + fixed_t bubble; // bubble scale (0 if no bubble) + mobj_t *bmobj; // temp bubble mobj + + if (player->followerready == false) + { + // we aren't ready to perform anything follower related yet. + return; + } + + // How about making sure our follower exists and is added before trying to spawn it n' all? + if (player->followerskin > numfollowers-1 || player->followerskin < -1) + { + //CONS_Printf("Follower skin invlaid. Setting to -1.\n"); + player->followerskin = -1; + return; + } + + // don't do anything if we can't have a follower to begin with. + // (It gets removed under those conditions) + if (player->spectator) + { + return; + } + + if (player->followerskin < 0) + { + return; + } + + // Before we do anything, let's be sure of where we're supposed to be + fl = followers[player->followerskin]; + + an = player->mo->angle + fl.atangle; + zoffs = fl.zoffs; + bubble = fl.bubblescale; // 0 if no bubble to spawn. + + // do you like angle maths? I certainly don't... + sx = player->mo->x + FixedMul(FixedMul(player->mo->scale, fl.dist), FINECOSINE((an) >> ANGLETOFINESHIFT)); + sy = player->mo->y + FixedMul(FixedMul(player->mo->scale, fl.dist), FINESINE((an) >> ANGLETOFINESHIFT)); + + // interp info helps with stretchy fix + deltaz = (player->mo->z - player->mo->old_z); + + // for the z coordinate, don't be a doof like Steel and forget that MFE_VERTICALFLIP exists :P + sz = player->mo->z + FixedMul(player->mo->scale, zoffs) * P_MobjFlip(player->mo); + if (player->mo->eflags & MFE_VERTICALFLIP) + { + sz += FixedMul(fl.height, player->mo->scale); + } + + // finally, add a cool floating effect to the z height. + // not stolen from k_kart I swear!! + { + const fixed_t pi = (22<> ANGLETOFINESHIFT) & FINEMASK)); + sz += FixedMul(player->mo->scale, sine) * P_MobjFlip(player->mo); + } + + // Set follower colour + switch (player->followercolor) + { + case FOLLOWERCOLOR_MATCH: // "Match" + color = player->skincolor; + break; + + case FOLLOWERCOLOR_OPPOSITE: // "Opposite" + color = skincolors[player->skincolor].invcolor; + break; + + default: + color = player->followercolor; + if (color == 0 || color > MAXSKINCOLORS+2) // Make sure this isn't garbage + { + color = player->skincolor; // "Match" as fallback. + } + break; + } + + if (player->follower == NULL) // follower doesn't exist / isn't valid + { + //CONS_Printf("Spawning follower...\n"); + + // so let's spawn one! + P_SetTarget(&player->follower, P_SpawnMobj(sx, sy, sz, MT_FOLLOWER)); + K_SetFollowerState(player->follower, fl.idlestate); + P_SetTarget(&player->follower->target, player->mo); // we need that to know when we need to disappear + P_InitAngle(player->follower, player->mo->angle); + + // This is safe to only spawn it here, the follower is removed then respawned when switched. + if (bubble) + { + bmobj = P_SpawnMobj(player->follower->x, player->follower->y, player->follower->z, MT_FOLLOWERBUBBLE_FRONT); + P_SetTarget(&player->follower->hnext, bmobj); + P_SetTarget(&bmobj->target, player->follower); // Used to know if we have to despawn at some point. + + bmobj = P_SpawnMobj(player->follower->x, player->follower->y, player->follower->z, MT_FOLLOWERBUBBLE_BACK); + P_SetTarget(&player->follower->hnext->hnext, bmobj); // this seems absolutely stupid, I know, but this will make updating the momentums/flags of these a bit easier. + P_SetTarget(&bmobj->target, player->follower); // Ditto + } + + player->follower->extravalue1 = 0; // extravalue1 is used to know what "state set" to use. + /* + 0 = idle + 1 = forwards + 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! + { + // Safety net (2) + + if (P_MobjWasRemoved(player->follower)) + { + P_SetTarget(&player->follower, NULL); // Remove this and respawn one, don't crash the game if Lua decides to P_RemoveMobj this thing. + return; + } + + // first of all, handle states following the same model as above: + if (player->follower->tics == 1) + { + K_SetFollowerState(player->follower, player->follower->state->nextstate); + } + + // move the follower next to us (yes, this is really basic maths but it looks pretty damn clean in practice)! + // 02/09/2021: cast lag to int32 otherwise funny things happen since it was changed to uint32 in the struct + player->follower->momx = FixedDiv(sx - player->follower->x, fl.horzlag); + player->follower->momy = FixedDiv(sy - player->follower->y, fl.horzlag); + player->follower->z += FixedDiv(deltaz, fl.vertlag); + player->follower->momz = FixedDiv(sz - player->follower->z, fl.vertlag); + player->follower->angle = player->mo->angle; + + if (player->mo->colorized) + { + player->follower->color = player->mo->color; + } + else + { + player->follower->color = color; + } + + player->follower->colorized = player->mo->colorized; + + P_SetScale(player->follower, FixedMul(fl.scale, player->mo->scale)); + K_GenericExtraFlagsNoZAdjust(player->follower, player->mo); // Not K_MatchGenericExtraFlag because the Z adjust it has only works properly if master & mo have the same Z height. + + // Match how the player is being drawn + player->follower->renderflags = player->mo->renderflags; + + // Make the follower invisible if we no contest'd rather than removing it. No one will notice the diff seriously. + if (player->pflags & PF_NOCONTEST) + { + player->follower->renderflags |= RF_DONTDRAW; + } + + // if we're moving let's make the angle the direction we're moving towards. This is to avoid drifting / reverse looking awkward. + player->follower->angle = K_MomentumAngle(player->follower); + + // Finally, if the follower has bubbles, move them, set their scale, etc.... + // This is what I meant earlier by it being easier, now we can just use this weird lil loop to get the job done! + + bmobj = player->follower->hnext; // will be NULL if there's no bubble + + while (bmobj != NULL && P_MobjWasRemoved(bmobj) == false) + { + // match follower's momentums and (e)flags(2). + bmobj->momx = player->follower->momx; + bmobj->momy = player->follower->momy; + bmobj->z += FixedDiv(deltaz, fl.vertlag); + bmobj->momz = player->follower->momz; + + P_SetScale(bmobj, FixedMul(bubble, player->mo->scale)); + K_GenericExtraFlagsNoZAdjust(bmobj, player->follower); + bmobj->renderflags = player->mo->renderflags; + + if (player->follower->threshold) + { + // threshold means the follower was "despawned" with S_NULL (is actually just set to S_INVISIBLE) + P_SetMobjState(bmobj, S_INVISIBLE); // sooooo... let's do the same! + } + + // switch to other bubble layer or exit + bmobj = bmobj->hnext; + } + + if (player->follower->threshold) + { + // Threshold means the follower was "despanwed" with S_NULL. + return; + } + + // However with how the code is factored, this is just a special case of S_INVISBLE to avoid having to add other player variables. + + // handle follower animations. Could probably be better... + // hurt or dead + if (P_PlayerInPain(player) == true || player->mo->state == &states[S_KART_SPINOUT] || player->mo->health <= 0) + { + // cancel hit confirm. + player->follower->movecount = 0; + + // spin out + player->follower->angle = player->drawangle; + + if (player->follower->extravalue1 != 2) + { + player->follower->extravalue1 = 2; + K_SetFollowerState(player->follower, fl.hurtstate); + } + + 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; + K_SetFollowerState(player->follower, fl.hitconfirmstate); + } + + player->follower->movecount--; + } + else if (player->speed > 10*player->mo->scale) // animation for moving fast enough + { + if (player->follower->extravalue1 != 1) + { + player->follower->extravalue1 = 1; + K_SetFollowerState(player->follower, fl.followstate); + } + } + else + { + // animations when nearly still. This includes winning and losing. + if (player->follower->extravalue1 != 0) + { + if (player->exiting) + { + // win/ loss animations + if (K_IsPlayerLosing(player)) + { + // L + if (player->follower->extravalue1 != 4) + { + player->follower->extravalue1 = 4; + K_SetFollowerState(player->follower, fl.losestate); + } + } + else + { + // W + if (player->follower->extravalue1 != 3) + { + player->follower->extravalue1 = 3; + K_SetFollowerState(player->follower, fl.winstate); + } + } + } + else + { + // normal standstill + player->follower->extravalue1 = 0; + K_SetFollowerState(player->follower, fl.idlestate); + } + } + } + } +} diff --git a/src/k_follower.h b/src/k_follower.h new file mode 100644 index 000000000..807d9ac57 --- /dev/null +++ b/src/k_follower.h @@ -0,0 +1,133 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2018-2022 by "Lat'" +// Copyright (C) 2018-2022 by Kart Krew +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file k_follower.h +/// \brief Code relating to the follower system + +#ifndef __K_FOLLOWER__ +#define __K_FOLLOWER__ + +#include "doomdef.h" +#include "doomstat.h" +#include "r_skins.h" + +#define FOLLOWERCOLOR_MATCH UINT16_MAX +#define FOLLOWERCOLOR_OPPOSITE (UINT16_MAX-1) + +extern CV_PossibleValue_t Followercolor_cons_t[]; // follower colours table, not a duplicate because of the "Match" option. + +// +// We'll define these here because they're really just a mobj that'll follow some rules behind a player +// +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. + + skincolornum_t defaultcolor; // default color for menus. + + fixed_t scale; // Scale relative to the player's. + fixed_t bubblescale; // Bubble scale relative to the player scale. If not set, no bubble will spawn (default) + + // some position shenanigans: + angle_t atangle; // angle the object will be at around the player. The object itself will always face the same direction as the player. + fixed_t dist; // distance relative to the player. (In a circle) + fixed_t height; // height of the follower, this is mostly important for Z flipping. + fixed_t zoffs; // Z offset relative to the player's height. Cannot be negative. + + // movement options + + fixed_t horzlag; // Lag for X/Y displacement. Default is 2. Must be > 0 because we divide by this number. + fixed_t vertlag; // Z displacement lag. Default is 6. Must be > 0 because we divide by this number. + fixed_t bobamp; // Bob amplitude. Default is 4. + tic_t bobspeed; // Arbitrary modifier for bobbing speed. Default is TICRATE*2 (70) + + // from there on out, everything is STATES to allow customization + // these are only set once when the action is performed and are then free to animate however they want. + + statenum_t idlestate; // state when the player is at a standstill + statenum_t followstate; // state when the player is moving + statenum_t hurtstate; // state when the player is being hurt + statenum_t winstate; // state when the player has won + statenum_t losestate; // state when the player has lost + statenum_t hitconfirmstate; // state for hit confirm + tic_t hitconfirmtime; // time to keep the above playing for +} follower_t; + +extern INT32 numfollowers; +extern follower_t followers[MAXSKINS]; + +/*-------------------------------------------------- + INT32 K_FollowerAvailable(const char *name) + + Check if a follower with the specified name + exists or not. + + Input Arguments:- + name - The skin name of the follower to check for. + + Return:- + The follower numerical ID of the follower, + or -1 if it doesn't exist. +--------------------------------------------------*/ + +INT32 K_FollowerAvailable(const char *name); + + +/*-------------------------------------------------- + boolean K_SetFollowerByName(INT32 playernum, const char *skinname) + + Updates a player's follower type via a named value. + Calls "K_SetFollowerByNum" internally. + + Input Arguments:- + playernum - The player ID to update + skinname - The follower's skin name + + Return:- + true if it was a valid name for a follower, + otherwise false. +--------------------------------------------------*/ + +boolean K_SetFollowerByName(INT32 playernum, const char *skinname); + + +/*-------------------------------------------------- + void K_SetFollowerByNum(INT32 playernum, INT32 skinnum) + + Updates a player's follower type via a numerical ID. + + Input Arguments:- + playernum - The player ID to update. + skinnum - The follower's skin ID + + Return:- + None +--------------------------------------------------*/ + +void K_SetFollowerByNum(INT32 playernum, INT32 skinnum); + + +/*-------------------------------------------------- + void K_HandleFollower(player_t *player) + + Updates a player's follower pointer, and does + its positioning and animations. + + Input Arguments:- + player - The player who we want to update the follower of. + + Return:- + None +--------------------------------------------------*/ + +void K_HandleFollower(player_t *player); + + +#endif // __K_FOLLOWER__ diff --git a/src/k_kart.c b/src/k_kart.c index 81374d9c6..e5fe76af1 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -37,6 +37,7 @@ #include "k_terrain.h" #include "k_director.h" #include "k_collide.h" +#include "k_follower.h" // SOME IMPORTANT VARIABLES DEFINED IN DOOMDEF.H: // gamespeed is cc (0 for easy, 1 for normal, 2 for hard) @@ -2806,7 +2807,7 @@ void K_PlayHitEmSound(mobj_t *source, mobj_t *victim) 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. + source->player->follower->movecount = fl.hitconfirmtime; // movecount is used to play the hitconfirm animation for followers. } if (cv_kartvoices.value) diff --git a/src/m_menu.c b/src/m_menu.c index 8255e5f35..d9d229cf2 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -65,6 +65,7 @@ #include "d_player.h" // KITEM_ constants #include "k_color.h" #include "k_grandprix.h" +#include "k_follower.h" #include "r_fps.h" #include "i_joy.h" // for joystick menu controls @@ -9667,7 +9668,7 @@ static void M_DrawSetupMultiPlayerMenu(void) follower_t fl = followers[setupm_fakefollower]; // shortcut for our sanity // smooth floating, totally not stolen from rocket sneakers. const fixed_t pi = (22<>ANGLETOFINESHIFT) & FINEMASK); + fixed_t sine = FixedMul(fl.bobamp, FINESINE((((8 * pi * (fl.bobspeed)) * followertimer)>>ANGLETOFINESHIFT) & FINEMASK)); UINT8 *colormap = R_GetTranslationColormap(-1, setupm_fakecolor->color, 0); V_DrawFixedPatch((mx+65)*FRACUNIT, (my+131-fl.zoffs)*FRACUNIT+sine, fl.scale, flags, patch, colormap); diff --git a/src/p_user.c b/src/p_user.c index dbf716925..648077340 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -56,6 +56,7 @@ #include "k_boss.h" #include "k_terrain.h" // K_SpawnSplashForMobj #include "k_color.h" +#include "k_follower.h" #ifdef HW3SOUND #include "hardware/hw3sound.h" @@ -3961,289 +3962,6 @@ static void P_ParabolicMove(mobj_t *mo, fixed_t x, fixed_t y, fixed_t z, fixed_t #endif -/* set follower state with our weird hacks - the reason we do this is to avoid followers ever using actions (majormods, yikes!) - without having to touch p_mobj.c. - so we give it 1more tic and change the state when tic == 1 instead of 0 - cool beans? - cool beans. -*/ -static void P_SetFollowerState(mobj_t *f, INT32 state) -{ - - if (!f || P_MobjWasRemoved(f)) - return; // safety net - - // No, do NOT set the follower to S_NULL. Set it to S_INVISIBLE. - if (state == S_NULL) - { - state = S_INVISIBLE; - f->threshold = 1; // Threshold = 1 means stop doing anything related to setting states, so that we don't get out of S_INVISIBLE - } - - // 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++; -} - -// -//P_HandleFollower -// -//Handle the follower's spawning and moving along with the player. Do note that some of the stuff like the removal if a player doesn't exist anymore is handled in MT_FOLLOWER's thinker. -static void P_HandleFollower(player_t *player) -{ - follower_t fl; - angle_t an; - fixed_t zoffs; - fixed_t sx, sy, sz, deltaz; - UINT16 color; - - fixed_t bubble; // bubble scale (0 if no bubble) - mobj_t *bmobj; // temp bubble mobj - - - if (!player->followerready) - return; // we aren't ready to perform anything follower related yet. - - // How about making sure our follower exists and is added before trying to spawn it n' all? - if (player->followerskin > numfollowers-1 || player->followerskin < -1) - { - //CONS_Printf("Follower skin invlaid. Setting to -1.\n"); - player->followerskin = -1; - return; - } - - // don't do anything if we can't have a follower to begin with. (It gets removed under those conditions) - if (player->spectator) - return; - if (player->followerskin < 0) - return; - // Before we do anything, let's be sure of where we're supposed to be - fl = followers[player->followerskin]; - - an = player->mo->angle + (fl.atangle)*ANG1; // it's aproximative but it really doesn't matter in the grand scheme of things... - zoffs = (fl.zoffs)*FRACUNIT; - bubble = fl.bubblescale; // 0 if no bubble to spawn. - - // do you like angle maths? I certainly don't... - sx = player->mo->x + FixedMul((player->mo->scale*fl.dist), FINECOSINE((an)>>ANGLETOFINESHIFT)); - sy = player->mo->y + FixedMul((player->mo->scale*fl.dist), FINESINE((an)>>ANGLETOFINESHIFT)); - - // interp info helps with stretchy fix - deltaz = (player->mo->z - player->mo->old_z); - - // for the z coordinate, don't be a doof like Steel and forget that MFE_VERTICALFLIP exists :P - sz = player->mo->z + FixedMul(player->mo->scale, zoffs)*P_MobjFlip(player->mo); - if (player->mo->eflags & MFE_VERTICALFLIP) - sz += fl.height*player->mo->scale; - - // finally, add a cool floating effect to the z height. - // not stolen from k_kart I swear!! - { - const fixed_t pi = (22<>ANGLETOFINESHIFT) & FINEMASK); - sz += FixedMul(player->mo->scale, sine)*P_MobjFlip(player->mo); - } - - // Set follower colour - switch (player->followercolor) - { - case FOLLOWERCOLOR_MATCH: // "Match" - color = player->skincolor; - break; - case FOLLOWERCOLOR_OPPOSITE: // "Opposite" - color = skincolors[player->skincolor].invcolor; - break; - default: - - color = player->followercolor; - if (!color || color > MAXSKINCOLORS+2) // Make sure this isn't garbage - color = player->skincolor; // "Match" as fallback. - - break; - } - - - - if (!player->follower) // follower doesn't exist / isn't valid - { - //CONS_Printf("Spawning follower...\n"); - // so let's spawn one! - P_SetTarget(&player->follower, P_SpawnMobj(sx, sy, sz, MT_FOLLOWER)); - P_SetFollowerState(player->follower, fl.idlestate); - P_SetTarget(&player->follower->target, player->mo); // we need that to know when we need to disappear - P_InitAngle(player->follower, player->mo->angle); - - // This is safe to only spawn it here, the follower is removed then respawned when switched. - if (bubble) - { - bmobj = P_SpawnMobj(player->follower->x, player->follower->y, player->follower->z, MT_FOLLOWERBUBBLE_FRONT); - P_SetTarget(&player->follower->hnext, bmobj); - P_SetTarget(&bmobj->target, player->follower); // Used to know if we have to despawn at some point. - - bmobj = P_SpawnMobj(player->follower->x, player->follower->y, player->follower->z, MT_FOLLOWERBUBBLE_BACK); - P_SetTarget(&player->follower->hnext->hnext, bmobj); // this seems absolutely stupid, I know, but this will make updating the momentums/flags of these a bit easier. - P_SetTarget(&bmobj->target, player->follower); // Ditto - } - - player->follower->extravalue1 = 0; // extravalue1 is used to know what "state set" to use. - /* - 0 = idle - 1 = forwards - 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! - { - - // Safety net (2) - - if (P_MobjWasRemoved(player->follower)) - { - P_SetTarget(&player->follower, NULL); // Remove this and respawn one, don't crash the game if Lua decides to P_RemoveMobj this thing. - return; - } - - // first of all, handle states following the same model as above: - if (player->follower->tics == 1) - P_SetFollowerState(player->follower, player->follower->state->nextstate); - - // move the follower next to us (yes, this is really basic maths but it looks pretty damn clean in practice)! - // 02/09/2021: cast lag to int32 otherwise funny things happen since it was changed to uint32 in the struct - player->follower->momx = (sx - player->follower->x)/ (INT32)fl.horzlag; - player->follower->momy = (sy - player->follower->y)/ (INT32)fl.horzlag; - player->follower->z += (deltaz/ (INT32)fl.vertlag); - player->follower->momz = (sz - player->follower->z)/ (INT32)fl.vertlag; - player->follower->angle = player->mo->angle; - - if (player->mo->colorized) - player->follower->color = player->mo->color; - else - player->follower->color = color; - - player->follower->colorized = player->mo->colorized; - - P_SetScale(player->follower, FixedMul(fl.scale, player->mo->scale)); - K_GenericExtraFlagsNoZAdjust(player->follower, player->mo); // Not K_MatchGenericExtraFlag because the Z adjust it has only works properly if master & mo have the same Z height. - - // Match how the player is being drawn - player->follower->renderflags = player->mo->renderflags; - - // Make the follower invisible if we no contest'd rather than removing it. No one will notice the diff seriously. - if (player->pflags & PF_NOCONTEST) - player->follower->renderflags |= RF_DONTDRAW; - - // if we're moving let's make the angle the direction we're moving towards. This is to avoid drifting / reverse looking awkward. - player->follower->angle = K_MomentumAngle(player->follower); - - // Finally, if the follower has bubbles, move them, set their scale, etc.... - // This is what I meant earlier by it being easier, now we can just use this weird lil loop to get the job done! - - bmobj = player->follower->hnext; // will be NULL if there's no bubble - - while (bmobj && !P_MobjWasRemoved(bmobj)) - { - // match follower's momentums and (e)flags(2). - bmobj->momx = player->follower->momx; - bmobj->momy = player->follower->momy; - bmobj->z += (deltaz/ (INT32)fl.vertlag); - bmobj->momz = player->follower->momz; - - P_SetScale(bmobj, FixedMul(bubble, player->mo->scale)); - K_GenericExtraFlagsNoZAdjust(bmobj, player->follower); - bmobj->renderflags = player->mo->renderflags; - - if (player->follower->threshold) // threshold means the follower was "despawned" with S_NULL (is actually just set to S_INVISIBLE) - P_SetMobjState(bmobj, S_INVISIBLE); // sooooo... let's do the same! - - bmobj = bmobj->hnext; // switch to other bubble layer or exit - } - - - if (player->follower->threshold) - return; // Threshold means the follower was "despanwed" with S_NULL. - - // However with how the code is factored, this is just a special case of S_INVISBLE to avoid having to add other player variables. - - - // handle follower animations. Could probably be better... - // hurt or dead - if (player->spinouttimer || player->mo->state == &states[S_KART_SPINOUT] || player->mo->health <= 0) - { - player->follower->movecount = 0; // cancel hit confirm. - player->follower->angle = player->drawangle; // spin out - if (player->follower->extravalue1 != 2) - { - player->follower->extravalue1 = 2; - P_SetFollowerState(player->follower, fl.hurtstate); - } - 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 (player->follower->extravalue1 != 1) - { - player->follower->extravalue1 = 1; - P_SetFollowerState(player->follower, fl.followstate); - } - } - else // animations when nearly still. This includes winning and losing. - { - if (player->follower->extravalue1 != 0) - { - - if (player->exiting) // win/ loss animations - { - if (K_IsPlayerLosing(player)) // L - { - if (player->follower->extravalue1 != 4) - { - player->follower->extravalue1 = 4; - P_SetFollowerState(player->follower, fl.losestate); - } - } - else // W - { - if (player->follower->extravalue1 != 3) - { - player->follower->extravalue1 = 3; - P_SetFollowerState(player->follower, fl.winstate); - } - } - } - else // normal standstill - { - player->follower->extravalue1 = 0; - P_SetFollowerState(player->follower, fl.idlestate); - } - } - } - } -} - /* gaysed script from me, based on Golden's sprite slope roll */ // holy SHIT @@ -4370,9 +4088,6 @@ void P_PlayerThink(player_t *player) player->awayviewtics = 0; // reset to zero } - // Run followes here. We need them to run even when we're dead to follow through what we're doing. - P_HandleFollower(player); - if (player->flashcount) player->flashcount--; @@ -4767,6 +4482,10 @@ void P_PlayerAfterThink(player_t *player) } #endif + // Run followers in AfterThink, after the players have moved, + // so a lag value of 1 is exactly attached to the player. + K_HandleFollower(player); + #ifdef SECTORSPECIALSAFTERTHINK if (player->onconveyor != 1 || !P_IsObjectOnGround(player->mo)) player->onconveyor = 0; diff --git a/src/r_data.h b/src/r_data.h index 1228f2420..3c8908a59 100644 --- a/src/r_data.h +++ b/src/r_data.h @@ -40,9 +40,6 @@ extern INT16 color8to16[256]; // remap color index to highcolor extern INT16 *hicolormaps; // remap high colors to high colors.. extern CV_PossibleValue_t Color_cons_t[]; -extern CV_PossibleValue_t Followercolor_cons_t[]; // follower colours table, not a duplicate because of the "Match" option. -#define FOLLOWERCOLOR_MATCH UINT16_MAX -#define FOLLOWERCOLOR_OPPOSITE (UINT16_MAX-1) // I/O, setting up the stuff. void R_InitTextureData(void); diff --git a/src/r_draw.c b/src/r_draw.c index d9f892423..7488ab5aa 100644 --- a/src/r_draw.c +++ b/src/r_draw.c @@ -194,7 +194,6 @@ static INT32 CacheIndexToSkin(INT32 ttc) } CV_PossibleValue_t Color_cons_t[MAXSKINCOLORS+1]; -CV_PossibleValue_t Followercolor_cons_t[MAXSKINCOLORS+3]; // +3 to account for "Match", "Opposite" & NULL #define TRANSTAB_AMTMUL10 (255.0f / 10.0f) diff --git a/src/r_skins.c b/src/r_skins.c index ba7ed0811..d4b10125e 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -34,8 +34,6 @@ INT32 numskins = 0; skin_t skins[MAXSKINS]; -INT32 numfollowers = 0; - // FIXTHIS: don't work because it must be inistilised before the config load //#define SKINVALUES #ifdef SKINVALUES @@ -44,9 +42,6 @@ CV_PossibleValue_t skin_cons_t[MAXSKINS+1]; CV_PossibleValue_t Forceskin_cons_t[MAXSKINS+2]; -// SRB2Kart followers -follower_t followers[MAXSKINS]; - // // P_GetSkinSprite2 // For non-super players, tries each sprite2's immediate predecessor until it finds one with a number of frames or ends up at standing. @@ -860,97 +855,3 @@ next_token: } #undef SYMBOLCONVERT - -// SRB2Kart: Followers! -// TODO: put this stuff in its own file? - -// same thing as R_SkinAvailable, but for followers -INT32 R_FollowerAvailable(const char *name) -{ - INT32 i; - - for (i = 0; i < numfollowers; i++) - { - if (stricmp(followers[i].skinname,name)==0) - return i; - } - return -1; -} - -// same thing as SetPlayerSkin, but for followers -boolean SetPlayerFollower(INT32 playernum, const char *skinname) -{ - INT32 i; - player_t *player = &players[playernum]; - - if (stricmp("None", skinname) == 0) - { - SetFollower(playernum, -1); // reminder that -1 is nothing - return true; - } - for (i = 0; i < numfollowers; i++) - { - // search in the skin list - if (stricmp(followers[i].skinname, skinname) == 0) - { - SetFollower(playernum, i); - return true; - } - } - - if (P_IsLocalPlayer(player)) - CONS_Alert(CONS_WARNING, M_GetText("Follower '%s' not found.\n"), skinname); - else if(server || IsPlayerAdmin(consoleplayer)) - CONS_Alert(CONS_WARNING, M_GetText("Player %d (%s) follower '%s' not found\n"), playernum, player_names[playernum], skinname); - - SetFollower(playernum, -1); // reminder that -1 is nothing - return false; -} - -// SetPlayerSkinByNum, for followers -void SetFollower(INT32 playernum, INT32 skinnum) -{ - player_t *player = &players[playernum]; - mobj_t *bub; - mobj_t *tmp; - - player->followerready = true; // we are ready to perform follower related actions in the player thinker, now. - - if (skinnum >= -1 && skinnum <= numfollowers) // Make sure it exists! - { - /* - We don't spawn the follower here since it'll be easier to handle all of it in the Player thinker itself. - However, we will despawn it right here if there's any to make it easy for the player thinker to replace it or delete it. - */ - - if (player->follower && skinnum != player->followerskin) // this is also called when we change colour so don't respawn the follower unless we changed skins - { - // Remove follower's possible hnext list (bubble) - bub = player->follower->hnext; - - while (bub && !P_MobjWasRemoved(bub)) - { - tmp = bub->hnext; - P_RemoveMobj(bub); - bub = tmp; - } - - P_RemoveMobj(player->follower); - P_SetTarget(&player->follower, NULL); - } - - player->followerskin = skinnum; - - // for replays: We have changed our follower mid-game; let the game know so it can do the same in the replay! - demo_extradata[playernum] |= DXD_FOLLOWER; - - return; - } - - if (P_IsLocalPlayer(player)) - CONS_Alert(CONS_WARNING, M_GetText("Follower %d not found\n"), skinnum); - else if(server || IsPlayerAdmin(consoleplayer)) - CONS_Alert(CONS_WARNING, "Player %d (%s) follower %d not found\n", playernum, player_names[playernum], skinnum); - - SetFollower(playernum, -1); // Not found, then set -1 (nothing) as our follower. -} diff --git a/src/r_skins.h b/src/r_skins.h index 2d29af188..cffd54da8 100644 --- a/src/r_skins.h +++ b/src/r_skins.h @@ -90,51 +90,4 @@ void R_AddSkins(UINT16 wadnum); UINT8 P_GetSkinSprite2(skin_t *skin, UINT8 spr2, player_t *player); -// SRB2Kart Followers - -// -// We'll define these here because they're really just a mobj that'll follow some rules behind a player -// -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. - - UINT16 defaultcolor; // default color for menus. - - fixed_t scale; // Scale relative to the player's. - fixed_t bubblescale; // Bubble scale relative to the player scale. If not set, no bubble will spawn (default) - - // 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 height; // height of the follower, this is mostly important for Z flipping. - INT32 zoffs; // Z offset relative to the player's height. Cannot be negative. - - // movement options - - UINT32 horzlag; // Lag for X/Y displacement. Default is 2. Must be > 0 because we divide by this number. - UINT32 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. - INT32 bobspeed; // Arbitrary modifier for bobbing speed, default is TICRATE*2 (70). - - // from there on out, everything is STATES to allow customization - // these are only set once when the action is performed and are then free to animate however they want. - - INT32 idlestate; // state when the player is at a standstill - INT32 followstate; // state when the player is moving - 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 - UINT32 hitconfirmtime; // time to keep the above playing for -} follower_t; - -extern INT32 numfollowers; -extern follower_t followers[MAXSKINS]; // again, use the same rules as skins, no reason not to. - -INT32 R_FollowerAvailable(const char *name); -boolean SetPlayerFollower(INT32 playernum,const char *skinname); -void SetFollower(INT32 playernum,INT32 skinnum); - #endif //__R_SKINS__ From cda0441abb315cc57b479a98a96a4222aa2ea2e1 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 23 May 2022 00:36:03 -0400 Subject: [PATCH 22/42] Follower angle lag + lookback - ANGLELAG lets you set how fast the followers swivel around. Default is 8*FRACUNIT, old behavior can be returned with FRACUNIT. - Followers reverse their angle when you hold the lookback button. - All lag values can't go below FRACUNIT instead of 1. --- src/deh_soc.c | 10 ++++++++-- src/k_follower.c | 24 +++++++++++++++++++++++- src/k_follower.h | 2 ++ 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index 6fe6ca36b..ba2845901 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -3827,6 +3827,7 @@ void readfollower(MYFILE *f) followers[numfollowers].zoffs = 32*FRACUNIT; followers[numfollowers].horzlag = 2*FRACUNIT; followers[numfollowers].vertlag = 6*FRACUNIT; + followers[numfollowers].anglelag = 8*FRACUNIT; followers[numfollowers].bobspeed = TICRATE*2; followers[numfollowers].bobamp = 4*FRACUNIT; followers[numfollowers].hitconfirmtime = TICRATE; @@ -3888,6 +3889,10 @@ void readfollower(MYFILE *f) { followers[numfollowers].vertlag = (fixed_t)get_number(word2); } + else if (fastcmp(word, "ANGLELAG")) + { + followers[numfollowers].vertlag = (fixed_t)get_number(word2); + } else if (fastcmp(word, "BOBSPEED")) { followers[numfollowers].bobspeed = (tic_t)get_number(word2); @@ -4002,8 +4007,9 @@ if ((signed)followers[numfollowers].field < threshold) \ FALLBACK(dist, "DIST", 0, 0); FALLBACK(height, "HEIGHT", 1, 1); FALLBACK(zoffs, "ZOFFS", 0, 0); - FALLBACK(horzlag, "HORZLAG", 1, 1); - FALLBACK(vertlag, "VERTLAG", 1, 1); + FALLBACK(horzlag, "HORZLAG", FRACUNIT, FRACUNIT); + FALLBACK(vertlag, "VERTLAG", FRACUNIT, FRACUNIT); + FALLBACK(anglelag, "ANGLELAG", FRACUNIT, FRACUNIT); FALLBACK(bobamp, "BOBAMP", 0, 0); FALLBACK(bobspeed, "BOBSPEED", 0, 0); FALLBACK(hitconfirmtime, "HITCONFIRMTIME", 1, 1); diff --git a/src/k_follower.c b/src/k_follower.c index 42b956e9a..6973e0fcd 100644 --- a/src/k_follower.c +++ b/src/k_follower.c @@ -191,6 +191,8 @@ void K_HandleFollower(player_t *player) fixed_t bubble; // bubble scale (0 if no bubble) mobj_t *bmobj; // temp bubble mobj + angle_t destAngle, angleDiff; + if (player->followerready == false) { // we aren't ready to perform anything follower related yet. @@ -346,7 +348,27 @@ void K_HandleFollower(player_t *player) } // if we're moving let's make the angle the direction we're moving towards. This is to avoid drifting / reverse looking awkward. - player->follower->angle = K_MomentumAngle(player->follower); + destAngle = K_MomentumAngle(player->follower); + + // Sal: Turn the follower around when looking backwards. + if ( player->cmd.buttons & BT_LOOKBACK ) + { + destAngle += ANGLE_180; + } + + // Sal: Smoothly rotate angle to the destination value. + angleDiff = destAngle - player->follower->angle; + + if (angleDiff > ANGLE_180) + { + angleDiff = InvAngle(FixedDiv(InvAngle(angleDiff), fl.anglelag)); + } + else + { + angleDiff = FixedDiv(angleDiff, fl.anglelag); + } + + player->follower->angle += angleDiff; // Finally, if the follower has bubbles, move them, set their scale, etc.... // This is what I meant earlier by it being easier, now we can just use this weird lil loop to get the job done! diff --git a/src/k_follower.h b/src/k_follower.h index 807d9ac57..b5c740a22 100644 --- a/src/k_follower.h +++ b/src/k_follower.h @@ -45,6 +45,8 @@ typedef struct follower_s fixed_t horzlag; // Lag for X/Y displacement. Default is 2. Must be > 0 because we divide by this number. fixed_t vertlag; // Z displacement lag. Default is 6. Must be > 0 because we divide by this number. + fixed_t anglelag; // Angle rotation lag. Default is 8. Must be > 0 because we divide by this number. + fixed_t bobamp; // Bob amplitude. Default is 4. tic_t bobspeed; // Arbitrary modifier for bobbing speed. Default is TICRATE*2 (70) From f8ad0a28e78c657b7e5498ecff6aa4d821edc644 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 23 May 2022 00:40:37 -0400 Subject: [PATCH 23/42] Fix anglelag typo --- src/deh_soc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index ba2845901..4249b5f80 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -3891,7 +3891,7 @@ void readfollower(MYFILE *f) } else if (fastcmp(word, "ANGLELAG")) { - followers[numfollowers].vertlag = (fixed_t)get_number(word2); + followers[numfollowers].anglelag = (fixed_t)get_number(word2); } else if (fastcmp(word, "BOBSPEED")) { From d67c6586437793baea286cde8db6878cd0e6dd6f Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 23 May 2022 01:09:58 -0400 Subject: [PATCH 24/42] Fix angle lag not working (Why was angle being set again above this...) --- src/k_follower.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/k_follower.c b/src/k_follower.c index 6973e0fcd..7bd1b2194 100644 --- a/src/k_follower.c +++ b/src/k_follower.c @@ -191,7 +191,8 @@ void K_HandleFollower(player_t *player) fixed_t bubble; // bubble scale (0 if no bubble) mobj_t *bmobj; // temp bubble mobj - angle_t destAngle, angleDiff; + angle_t destAngle; + INT32 angleDiff; if (player->followerready == false) { @@ -322,7 +323,6 @@ void K_HandleFollower(player_t *player) player->follower->momy = FixedDiv(sy - player->follower->y, fl.horzlag); player->follower->z += FixedDiv(deltaz, fl.vertlag); player->follower->momz = FixedDiv(sz - player->follower->z, fl.vertlag); - player->follower->angle = player->mo->angle; if (player->mo->colorized) { @@ -357,18 +357,12 @@ void K_HandleFollower(player_t *player) } // Sal: Smoothly rotate angle to the destination value. - angleDiff = destAngle - player->follower->angle; + angleDiff = AngleDeltaSigned(destAngle, player->follower->angle); - if (angleDiff > ANGLE_180) + if (angleDiff != 0) { - angleDiff = InvAngle(FixedDiv(InvAngle(angleDiff), fl.anglelag)); + player->follower->angle += FixedDiv(angleDiff, fl.anglelag); } - else - { - angleDiff = FixedDiv(angleDiff, fl.anglelag); - } - - player->follower->angle += angleDiff; // Finally, if the follower has bubbles, move them, set their scale, etc.... // This is what I meant earlier by it being easier, now we can just use this weird lil loop to get the job done! From fcff62fc9e5e42dbb092d62b503d1d53f9a7196e Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 23 May 2022 02:45:32 -0400 Subject: [PATCH 25/42] Lag of FRACUNIT matches your position exactly --- src/k_follower.c | 6 +++--- src/p_user.c | 12 ++++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/k_follower.c b/src/k_follower.c index 7bd1b2194..25e0c5814 100644 --- a/src/k_follower.c +++ b/src/k_follower.c @@ -228,14 +228,14 @@ void K_HandleFollower(player_t *player) bubble = fl.bubblescale; // 0 if no bubble to spawn. // do you like angle maths? I certainly don't... - sx = player->mo->x + FixedMul(FixedMul(player->mo->scale, fl.dist), FINECOSINE((an) >> ANGLETOFINESHIFT)); - sy = player->mo->y + FixedMul(FixedMul(player->mo->scale, fl.dist), FINESINE((an) >> ANGLETOFINESHIFT)); + sx = player->mo->x + player->mo->momx + FixedMul(FixedMul(player->mo->scale, fl.dist), FINECOSINE((an) >> ANGLETOFINESHIFT)); + sy = player->mo->y + player->mo->momy + FixedMul(FixedMul(player->mo->scale, fl.dist), FINESINE((an) >> ANGLETOFINESHIFT)); // interp info helps with stretchy fix deltaz = (player->mo->z - player->mo->old_z); // for the z coordinate, don't be a doof like Steel and forget that MFE_VERTICALFLIP exists :P - sz = player->mo->z + FixedMul(player->mo->scale, zoffs) * P_MobjFlip(player->mo); + sz = player->mo->z + player->mo->momz + FixedMul(player->mo->scale, zoffs) * P_MobjFlip(player->mo); if (player->mo->eflags & MFE_VERTICALFLIP) { sz += FixedMul(fl.height, player->mo->scale); diff --git a/src/p_user.c b/src/p_user.c index 648077340..ffef501e9 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4482,10 +4482,6 @@ void P_PlayerAfterThink(player_t *player) } #endif - // Run followers in AfterThink, after the players have moved, - // so a lag value of 1 is exactly attached to the player. - K_HandleFollower(player); - #ifdef SECTORSPECIALSAFTERTHINK if (player->onconveyor != 1 || !P_IsObjectOnGround(player->mo)) player->onconveyor = 0; @@ -4506,11 +4502,15 @@ void P_PlayerAfterThink(player_t *player) if (player->playerstate == PST_DEAD) { + // Followers need handled while dead. + K_HandleFollower(player); + if (player->followmobj) { P_RemoveMobj(player->followmobj); P_SetTarget(&player->followmobj, NULL); } + return; } @@ -4583,6 +4583,10 @@ void P_PlayerAfterThink(player_t *player) } } } + + // Run followers in AfterThink, after the players have moved, + // so a lag value of 1 is exactly attached to the player. + K_HandleFollower(player); } void P_SetPlayerAngle(player_t *player, angle_t angle) From 6574f822a46fb63bca339300779ad0aa1de544b3 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 23 May 2022 02:57:20 -0400 Subject: [PATCH 26/42] Fix bobspeed + menu z offset --- src/k_follower.c | 2 +- src/m_menu.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/k_follower.c b/src/k_follower.c index 25e0c5814..6b9b20c08 100644 --- a/src/k_follower.c +++ b/src/k_follower.c @@ -245,7 +245,7 @@ void K_HandleFollower(player_t *player) // not stolen from k_kart I swear!! { const fixed_t pi = (22<> ANGLETOFINESHIFT) & FINEMASK)); + fixed_t sine = FixedMul(fl.bobamp, FINESINE(((FixedMul(8 * pi, fl.bobspeed) * leveltime) >> ANGLETOFINESHIFT) & FINEMASK)); sz += FixedMul(player->mo->scale, sine) * P_MobjFlip(player->mo); } diff --git a/src/m_menu.c b/src/m_menu.c index d9d229cf2..e1a6a90c4 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -9668,10 +9668,10 @@ static void M_DrawSetupMultiPlayerMenu(void) follower_t fl = followers[setupm_fakefollower]; // shortcut for our sanity // smooth floating, totally not stolen from rocket sneakers. const fixed_t pi = (22<>ANGLETOFINESHIFT) & FINEMASK)); + fixed_t sine = FixedMul(fl.bobamp, FINESINE((((8 * pi * fl.bobspeed) * followertimer)>>ANGLETOFINESHIFT) & FINEMASK)); UINT8 *colormap = R_GetTranslationColormap(-1, setupm_fakecolor->color, 0); - V_DrawFixedPatch((mx+65)*FRACUNIT, (my+131-fl.zoffs)*FRACUNIT+sine, fl.scale, flags, patch, colormap); + V_DrawFixedPatch((mx+65)*FRACUNIT, ((my+131)*FRACUNIT)-fl.zoffs+sine, fl.scale, flags, patch, colormap); Z_Free(colormap); } } From ab9d474e9bceef7ad5f4a706eca4d27f51c3e8e7 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 23 May 2022 02:57:46 -0400 Subject: [PATCH 27/42] Fix follower color on menu (not that it even uses the real color, buuut...) --- src/m_menu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_menu.c b/src/m_menu.c index e1a6a90c4..24af0052e 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -9670,7 +9670,7 @@ static void M_DrawSetupMultiPlayerMenu(void) const fixed_t pi = (22<>ANGLETOFINESHIFT) & FINEMASK)); - UINT8 *colormap = R_GetTranslationColormap(-1, setupm_fakecolor->color, 0); + UINT8 *colormap = R_GetTranslationColormap(TC_DEFAULT, setupm_fakecolor->color, GTC_MENUCACHE); V_DrawFixedPatch((mx+65)*FRACUNIT, ((my+131)*FRACUNIT)-fl.zoffs+sine, fl.scale, flags, patch, colormap); Z_Free(colormap); } From 69023a96ee15d90aec0ffafc873844c30a40b2a1 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 23 May 2022 02:59:52 -0400 Subject: [PATCH 28/42] More bobspeed fix --- src/m_menu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_menu.c b/src/m_menu.c index 24af0052e..f3d08a6dc 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -9668,7 +9668,7 @@ static void M_DrawSetupMultiPlayerMenu(void) follower_t fl = followers[setupm_fakefollower]; // shortcut for our sanity // smooth floating, totally not stolen from rocket sneakers. const fixed_t pi = (22<>ANGLETOFINESHIFT) & FINEMASK)); + fixed_t sine = FixedMul(fl.bobamp, FINESINE(((FixedMul(8 * pi, fl.bobspeed) * followertimer)>>ANGLETOFINESHIFT) & FINEMASK)); UINT8 *colormap = R_GetTranslationColormap(TC_DEFAULT, setupm_fakecolor->color, GTC_MENUCACHE); V_DrawFixedPatch((mx+65)*FRACUNIT, ((my+131)*FRACUNIT)-fl.zoffs+sine, fl.scale, flags, patch, colormap); From d1d9a5bd109dd0b7d8508c8e617138cb2da9f25b Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 23 May 2022 03:03:16 -0400 Subject: [PATCH 29/42] Fix follower menu crash --- src/m_menu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_menu.c b/src/m_menu.c index f3d08a6dc..63c5c2f7b 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -9670,7 +9670,7 @@ static void M_DrawSetupMultiPlayerMenu(void) const fixed_t pi = (22<>ANGLETOFINESHIFT) & FINEMASK)); - UINT8 *colormap = R_GetTranslationColormap(TC_DEFAULT, setupm_fakecolor->color, GTC_MENUCACHE); + UINT8 *colormap = R_GetTranslationColormap(TC_DEFAULT, setupm_fakecolor->color, 0); // why does GTC_MENUCACHE not work here...? V_DrawFixedPatch((mx+65)*FRACUNIT, ((my+131)*FRACUNIT)-fl.zoffs+sine, fl.scale, flags, patch, colormap); Z_Free(colormap); } From 0e60a3ef2634cc3c56cdaaa64fab8108f24c9d18 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 23 May 2022 04:10:20 -0400 Subject: [PATCH 30/42] Increase default horzlag to 3 This value is closer to how the old value felt before the tracking was improved. --- src/deh_soc.c | 2 +- src/k_follower.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index 4249b5f80..d6661933a 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -3825,7 +3825,7 @@ void readfollower(MYFILE *f) followers[numfollowers].dist = 32*FRACUNIT; // changed from 16 to 32 to better account for ogl models followers[numfollowers].height = 16*FRACUNIT; followers[numfollowers].zoffs = 32*FRACUNIT; - followers[numfollowers].horzlag = 2*FRACUNIT; + followers[numfollowers].horzlag = 3*FRACUNIT; followers[numfollowers].vertlag = 6*FRACUNIT; followers[numfollowers].anglelag = 8*FRACUNIT; followers[numfollowers].bobspeed = TICRATE*2; diff --git a/src/k_follower.h b/src/k_follower.h index b5c740a22..b39eae9e6 100644 --- a/src/k_follower.h +++ b/src/k_follower.h @@ -43,7 +43,7 @@ typedef struct follower_s // movement options - fixed_t horzlag; // Lag for X/Y displacement. Default is 2. Must be > 0 because we divide by this number. + fixed_t horzlag; // Lag for X/Y displacement. Default is 3. Must be > 0 because we divide by this number. fixed_t vertlag; // Z displacement lag. Default is 6. Must be > 0 because we divide by this number. fixed_t anglelag; // Angle rotation lag. Default is 8. Must be > 0 because we divide by this number. From d8b7967a228a9a055bda6562a99b01aadbeb3543 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 23 May 2022 13:38:53 -0400 Subject: [PATCH 31/42] Make all instances of this sine use M_TAU_FIXED --- src/k_battle.c | 3 +-- src/k_follower.c | 3 +-- src/k_kart.c | 4 +--- src/m_fixed.h | 2 ++ src/m_menu.c | 4 ++-- src/p_mobj.c | 3 +-- 6 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/k_battle.c b/src/k_battle.c index e64fc5a9a..14ecfabf5 100644 --- a/src/k_battle.c +++ b/src/k_battle.c @@ -672,12 +672,11 @@ void K_RunBattleOvertime(void) if (battleovertime.radius > 0) { - const fixed_t pi = (22 * FRACUNIT) / 7; // loose approximation, this doesn't need to be incredibly precise const INT32 orbs = 32; const angle_t angoff = ANGLE_MAX / orbs; const UINT8 spriteSpacing = 128; - fixed_t circumference = FixedMul(pi, battleovertime.radius * 2); + fixed_t circumference = FixedMul(M_PI_FIXED, battleovertime.radius * 2); fixed_t scale = max(circumference / spriteSpacing / orbs, mapobjectscale); fixed_t size = FixedMul(mobjinfo[MT_OVERTIME_PARTICLE].radius, scale); diff --git a/src/k_follower.c b/src/k_follower.c index 6b9b20c08..4d7556dd4 100644 --- a/src/k_follower.c +++ b/src/k_follower.c @@ -244,8 +244,7 @@ void K_HandleFollower(player_t *player) // finally, add a cool floating effect to the z height. // not stolen from k_kart I swear!! { - const fixed_t pi = (22<> ANGLETOFINESHIFT) & FINEMASK)); + fixed_t sine = FixedMul(fl.bobamp, FINESINE(((FixedMul(4 * M_TAU_FIXED, fl.bobspeed) * leveltime) >> ANGLETOFINESHIFT) & FINEMASK)); sz += FixedMul(player->mo->scale, sine) * P_MobjFlip(player->mo); } diff --git a/src/k_kart.c b/src/k_kart.c index e5fe76af1..42adaf268 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -6631,12 +6631,10 @@ static void K_MoveHeldObjects(player_t *player) targy = player->mo->y + P_ReturnThrustY(cur, cur->angle + angoffset, cur->extravalue1); { // bobbing, copy pasted from my kimokawaiii entry - const fixed_t pi = (22<mo->scale, 8 * FINESINE((((2*pi*(4*TICRATE)) * leveltime)>>ANGLETOFINESHIFT) & FINEMASK)); + fixed_t sine = FixedMul(player->mo->scale, 8 * FINESINE((((M_TAU_FIXED * (4*TICRATE)) * leveltime) >> ANGLETOFINESHIFT) & FINEMASK)); targz = (player->mo->z + (player->mo->height/2)) + sine; if (player->mo->eflags & MFE_VERTICALFLIP) targz += (player->mo->height/2 - 32*player->mo->scale)*6; - } if (cur->tracer) diff --git a/src/m_fixed.h b/src/m_fixed.h index 49108ab93..9f3bb2910 100644 --- a/src/m_fixed.h +++ b/src/m_fixed.h @@ -37,6 +37,8 @@ #define M_TAU_FIXED 411769 #endif +#define M_PI_FIXED (M_TAU_FIXED >> 1) + typedef INT32 fixed_t; /*! diff --git a/src/m_menu.c b/src/m_menu.c index 63c5c2f7b..fcb2d6321 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -9666,9 +9666,9 @@ static void M_DrawSetupMultiPlayerMenu(void) // Fake the follower's in game appearance by now also applying some of its variables! coolio, eh? follower_t fl = followers[setupm_fakefollower]; // shortcut for our sanity + // smooth floating, totally not stolen from rocket sneakers. - const fixed_t pi = (22<>ANGLETOFINESHIFT) & FINEMASK)); + fixed_t sine = FixedMul(fl.bobamp, FINESINE(((FixedMul(4 * M_TAU_FIXED, fl.bobspeed) * followertimer)>>ANGLETOFINESHIFT) & FINEMASK)); UINT8 *colormap = R_GetTranslationColormap(TC_DEFAULT, setupm_fakecolor->color, 0); // why does GTC_MENUCACHE not work here...? V_DrawFixedPatch((mx+65)*FRACUNIT, ((my+131)*FRACUNIT)-fl.zoffs+sine, fl.scale, flags, patch, colormap); diff --git a/src/p_mobj.c b/src/p_mobj.c index 433ff4931..e00d7ef2f 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8597,8 +8597,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) if (mobj->extravalue1) { const INT32 speed = 6*TICRATE; // longer is slower - const fixed_t pi = 22*FRACUNIT/7; // Inaccurate, but is close enough for our usage - fixed_t sine = FINESINE((((2*pi*speed) * leveltime) >> ANGLETOFINESHIFT) & FINEMASK) * flip; + fixed_t sine = FINESINE((((M_TAU_FIXED * speed) * leveltime) >> ANGLETOFINESHIFT) & FINEMASK) * flip; // Flying capsules are flipped upside-down, like S3K flip = -flip; From 6e3c4dbc346d336c7d1e65e7371f0eca51bb439c Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 23 May 2022 13:40:51 -0400 Subject: [PATCH 32/42] > numfollowers-1 -> >= numfollowers --- src/d_netcmd.c | 2 +- src/k_follower.c | 2 +- src/m_menu.c | 18 +++++++++--------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 8d66a27bc..21d28ddc6 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1422,7 +1422,7 @@ static void SendNameAndColor(UINT8 n) CV_StealthSet(&cv_followercolor[n], "Match"); // set it to "Match". I don't care about your stupidity! // so like, this is sent before we even use anything like cvars or w/e so it's possible that follower is set to a pretty yikes value, so let's fix that before we send garbage that could crash the game: - if (cv_follower[n].value > numfollowers-1 || cv_follower[n].value < -1) + if (cv_follower[n].value >= numfollowers || cv_follower[n].value < -1) CV_StealthSet(&cv_follower[n], "-1"); if (!strcmp(cv_playername[n].string, player_names[playernum]) diff --git a/src/k_follower.c b/src/k_follower.c index 4d7556dd4..532adbe24 100644 --- a/src/k_follower.c +++ b/src/k_follower.c @@ -201,7 +201,7 @@ void K_HandleFollower(player_t *player) } // How about making sure our follower exists and is added before trying to spawn it n' all? - if (player->followerskin > numfollowers-1 || player->followerskin < -1) + if (player->followerskin >= numfollowers || player->followerskin < -1) { //CONS_Printf("Follower skin invlaid. Setting to -1.\n"); player->followerskin = -1; diff --git a/src/m_menu.c b/src/m_menu.c index fcb2d6321..5d3aae841 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -9683,7 +9683,7 @@ static void M_DrawSetupMultiPlayerMenu(void) static void M_GetFollowerState(void) { - if (setupm_fakefollower <= -1 || setupm_fakefollower > numfollowers-1) // yikes, there's none! + if (setupm_fakefollower <= -1 || setupm_fakefollower >= numfollowers) // yikes, there's none! return; // ^ we don't actually need to set anything since it won't be displayed anyway. @@ -9831,13 +9831,13 @@ static void M_HandleSetupMultiPlayer(INT32 choice) // check followers: if (setupm_fakefollower < -1) { - setupm_fakefollower = numfollowers-1; - M_GetFollowerState(); // update follower state + setupm_fakefollower = numfollowers; + M_GetFollowerState(); // update follower state } - if (setupm_fakefollower > numfollowers-1) + if (setupm_fakefollower >= numfollowers) { setupm_fakefollower = -1; - M_GetFollowerState(); // update follower state + M_GetFollowerState(); // update follower state } // check color @@ -9879,7 +9879,7 @@ static void M_SetupMultiPlayer(INT32 choice) setupm_fakefollower = atoi(setupm_cvfollower->string); // update fake follower value // yikes, we don't want none of that... - if (setupm_fakefollower > numfollowers-1) + if (setupm_fakefollower >= numfollowers) setupm_fakefollower = -1; M_GetFollowerState(); // update follower state @@ -9922,7 +9922,7 @@ static void M_SetupMultiPlayer2(INT32 choice) setupm_fakefollower = atoi(setupm_cvfollower->string); // update fake follower value // yikes, we don't want none of that... - if (setupm_fakefollower > numfollowers-1) + if (setupm_fakefollower >= numfollowers) setupm_fakefollower = -1; M_GetFollowerState(); // update follower state @@ -9965,7 +9965,7 @@ static void M_SetupMultiPlayer3(INT32 choice) setupm_fakefollower = atoi(setupm_cvfollower->string); // update fake follower value // yikes, we don't want none of that... - if (setupm_fakefollower > numfollowers-1) + if (setupm_fakefollower >= numfollowers) setupm_fakefollower = -1; M_GetFollowerState(); // update follower state @@ -10008,7 +10008,7 @@ static void M_SetupMultiPlayer4(INT32 choice) setupm_fakefollower = atoi(setupm_cvfollower->string); // update fake follower value // yikes, we don't want none of that... - if (setupm_fakefollower > numfollowers-1) + if (setupm_fakefollower >= numfollowers) setupm_fakefollower = -1; M_GetFollowerState(); // update follower state From 0e31d2e9a65884bbf544b2cc9f38d3c2e0175ddb Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 23 May 2022 20:12:31 +0100 Subject: [PATCH 33/42] * Tricks now have a minimum stick tilt of 1/4th of the data range to activate. * This tilt is a *difference* between the axes, so a slight diagonal shouldn't intefere. --- src/k_kart.c | 124 ++++++++++++++++++++++++--------------------------- 1 file changed, 59 insertions(+), 65 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 81374d9c6..791678574 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -10215,78 +10215,72 @@ void K_MoveKartPlayer(player_t *player, boolean onground) else if (!(player->pflags & PF_TRICKDELAY)) // don't allow tricking at the same frame you tumble obv { + INT16 aimingcompare = abs(cmd->throwdir) - abs(cmd->turning); - // "COOL" timing n shit. - if (cmd->turning || player->throwdir) + // Uses cmd->turning over steering intentionally. +#define TRICKTHRESHOLD (KART_FULLTURN/4) + if (aimingcompare < -TRICKTHRESHOLD) // side trick { + if (cmd->turning > 0) + { + P_InstaThrust(player->mo, player->mo->angle + lr, max(basespeed, speed*5/2)); + player->trickpanel = 2; + } + else + { + P_InstaThrust(player->mo, player->mo->angle - lr, max(basespeed, speed*5/2)); + player->trickpanel = 3; + } + } + else if (aimingcompare > TRICKTHRESHOLD) // forward/back trick + { + if (cmd->throwdir > 0) // back trick + { + if (player->mo->momz * P_MobjFlip(player->mo) > 0) + { + player->mo->momz = 0; + } + + P_InstaThrust(player->mo, player->mo->angle, max(basespeed, speed*3)); + player->trickpanel = 2; + } + else if (cmd->throwdir < 0) + { + boolean relative = true; + + player->mo->momx /= 3; + player->mo->momy /= 3; + + if (player->mo->momz * P_MobjFlip(player->mo) <= 0) + { + relative = false; + } + + // Calculate speed boost decay: + // Base speed boost duration is 35 tics. + // At most, lose 3/4th of your boost. + player->trickboostdecay = min(TICRATE*3/4, abs(momz/FRACUNIT)); + //CONS_Printf("decay: %d\n", player->trickboostdecay); + + P_SetObjectMomZ(player->mo, 48*FRACUNIT, relative); + player->trickpanel = 4; + } + } +#undef TRICKTHRESHOLD + + // Finalise everything. + if (player->trickpanel != 1) // just changed from 1? + { + player->mo->hitlag = TRICKLAG; + player->mo->eflags &= ~MFE_DAMAGEHITLAG; + + K_trickPanelTimingVisual(player, momz); + if (abs(momz) < FRACUNIT*99) // Let's use that as baseline for PERFECT trick. { player->karthud[khud_trickcool] = TICRATE; } } - - // Uses cmd->turning over steering intentionally. - if (cmd->turning > 0) - { - P_InstaThrust(player->mo, player->mo->angle + lr, max(basespeed, speed*5/2)); - player->trickpanel = 2; - - player->mo->hitlag = TRICKLAG; - player->mo->eflags &= ~MFE_DAMAGEHITLAG; - - K_trickPanelTimingVisual(player, momz); - } - else if (cmd->turning < 0) - { - P_InstaThrust(player->mo, player->mo->angle - lr, max(basespeed, speed*5/2)); - player->trickpanel = 3; - - player->mo->hitlag = TRICKLAG; - player->mo->eflags &= ~MFE_DAMAGEHITLAG; - - K_trickPanelTimingVisual(player, momz); - } - else if (cmd->throwdir > 0) - { - if (player->mo->momz * P_MobjFlip(player->mo) > 0) - { - player->mo->momz = 0; - } - - P_InstaThrust(player->mo, player->mo->angle, max(basespeed, speed*3)); - player->trickpanel = 2; - - player->mo->hitlag = TRICKLAG; - player->mo->eflags &= ~MFE_DAMAGEHITLAG; - - K_trickPanelTimingVisual(player, momz); - } - else if (cmd->throwdir < 0) - { - boolean relative = true; - - player->mo->momx /= 3; - player->mo->momy /= 3; - - if (player->mo->momz * P_MobjFlip(player->mo) <= 0) - { - relative = false; - } - - // Calculate speed boost decay: - // Base speed boost duration is 35 tics. - // At most, lose 3/4th of your boost. - player->trickboostdecay = min(TICRATE*3/4, abs(momz/FRACUNIT)); - //CONS_Printf("decay: %d\n", player->trickboostdecay); - - P_SetObjectMomZ(player->mo, 48*FRACUNIT, relative); - player->trickpanel = 4; - - player->mo->hitlag = TRICKLAG; - player->mo->eflags &= ~MFE_DAMAGEHITLAG; - - K_trickPanelTimingVisual(player, momz); - } } } else if (player->trickpanel == 4 && P_IsObjectOnGround(player->mo)) // Upwards trick landed! From 4b70a64b3f53a4159cef79aa4ed7aafe6bc8ff70 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 23 May 2022 15:51:00 -0400 Subject: [PATCH 34/42] Ground follower mode --- src/deh_soc.c | 26 ++++++++++-- src/k_botitem.c | 2 +- src/k_follower.c | 108 +++++++++++++++++++++++++++++++++++++++++++---- src/k_follower.h | 8 ++++ src/k_kart.c | 4 +- src/k_kart.h | 1 + 6 files changed, 134 insertions(+), 15 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index d6661933a..adb44c61e 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -3819,6 +3819,7 @@ void readfollower(MYFILE *f) s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL); // Ready the default variables for followers. We will overwrite them as we go! We won't set the name or states RIGHT HERE as this is handled down instead. + followers[numfollowers].mode = FOLLOWERMODE_FLOAT; followers[numfollowers].scale = FRACUNIT; followers[numfollowers].bubblescale = 0; // No bubble by default followers[numfollowers].atangle = FixedAngle(230 * FRACUNIT); @@ -3865,6 +3866,18 @@ void readfollower(MYFILE *f) strcpy(followers[numfollowers].name, word2); nameset = true; } + else if (fastcmp(word, "MODE")) + { + if (word2) + strupr(word2); + + if (fastcmp(word2, "FLOAT") || fastcmp(word2, "DEFAULT")) + followers[numfollowers].mode = FOLLOWERMODE_FLOAT; + else if (fastcmp(word2, "GROUND")) + followers[numfollowers].mode = FOLLOWERMODE_GROUND; + else + deh_warning("Follower %d: unknown follower mode '%s'", numfollowers, word2); + } else if (fastcmp(word, "DEFAULTCOLOR")) { followers[numfollowers].defaultcolor = get_number(word2); @@ -3997,11 +4010,18 @@ void readfollower(MYFILE *f) // fallbacks for variables // Print a warning if the variable is on a weird value and set it back to the minimum available if that's the case. + + if (followers[numfollowers].mode < FOLLOWERMODE_FLOAT || followers[numfollowers].mode >= FOLLOWERMODE__MAX) + { + followers[numfollowers].mode = FOLLOWERMODE_FLOAT; + deh_warning("Follower '%s': Value for 'mode' should be between %d and %d.", dname, FOLLOWERMODE_FLOAT, FOLLOWERMODE__MAX-1); + } + #define FALLBACK(field, field2, threshold, set) \ if ((signed)followers[numfollowers].field < threshold) \ { \ followers[numfollowers].field = set; \ - deh_warning("Follower '%s': Value for '%s' is too low! Minimum should be %d. Value was overwritten to %d.", dname, field2, set, set); \ + deh_warning("Follower '%s': Value for '%s' is too low! Minimum should be %d. Value was overwritten to %d.", dname, field2, threshold, set); \ } \ FALLBACK(dist, "DIST", 0, 0); @@ -4016,6 +4036,8 @@ if ((signed)followers[numfollowers].field < threshold) \ FALLBACK(scale, "SCALE", 1, 1); // No null/negative scale FALLBACK(bubblescale, "BUBBLESCALE", 0, 0); // No negative scale +#undef FALLBACK + // Special case for color I suppose if (followers[numfollowers].defaultcolor > (unsigned)(numskincolors-1)) { @@ -4023,8 +4045,6 @@ if ((signed)followers[numfollowers].field < threshold) \ deh_warning("Follower \'%s\': Value for 'color' should be between 1 and %d.\n", dname, numskincolors-1); } -#undef FALLBACK - // 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. diff --git a/src/k_botitem.c b/src/k_botitem.c index 465c45adb..48ed6283c 100644 --- a/src/k_botitem.c +++ b/src/k_botitem.c @@ -1308,7 +1308,7 @@ void K_BotItemUsage(player_t *player, ticcmd_t *cmd, INT16 turnamt) K_BotItemGenericOrbitShield(player, cmd); } else if (player->position != 1) // Hold onto orbiting items when in 1st :) - /* FALL-THRU */ + /* FALLTHRU */ case KITEM_BALLHOG: { K_BotItemOrbinaut(player, cmd); diff --git a/src/k_follower.c b/src/k_follower.c index 532adbe24..76a2d9dd7 100644 --- a/src/k_follower.c +++ b/src/k_follower.c @@ -7,6 +7,7 @@ #include "doomdef.h" #include "g_game.h" #include "g_demo.h" +#include "r_main.h" #include "r_skins.h" #include "p_local.h" #include "p_mobj.h" @@ -185,7 +186,9 @@ void K_HandleFollower(player_t *player) follower_t fl; angle_t an; fixed_t zoffs; + fixed_t ourheight; fixed_t sx, sy, sz, deltaz; + fixed_t fh = INT32_MIN, ch = INT32_MAX; UINT16 color; fixed_t bubble; // bubble scale (0 if no bubble) @@ -235,17 +238,39 @@ void K_HandleFollower(player_t *player) deltaz = (player->mo->z - player->mo->old_z); // for the z coordinate, don't be a doof like Steel and forget that MFE_VERTICALFLIP exists :P - sz = player->mo->z + player->mo->momz + FixedMul(player->mo->scale, zoffs) * P_MobjFlip(player->mo); + sz = player->mo->z + player->mo->momz + FixedMul(player->mo->scale, zoffs * P_MobjFlip(player->mo)); + ourheight = FixedMul(fl.height, player->mo->scale); if (player->mo->eflags & MFE_VERTICALFLIP) { - sz += FixedMul(fl.height, player->mo->scale); + sz += ourheight; } - // finally, add a cool floating effect to the z height. - // not stolen from k_kart I swear!! + fh = player->mo->floorz; + ch = player->mo->ceilingz - ourheight; + + switch (fl.mode) { - fixed_t sine = FixedMul(fl.bobamp, FINESINE(((FixedMul(4 * M_TAU_FIXED, fl.bobspeed) * leveltime) >> ANGLETOFINESHIFT) & FINEMASK)); - sz += FixedMul(player->mo->scale, sine) * P_MobjFlip(player->mo); + case FOLLOWERMODE_GROUND: + { + if (player->mo->eflags & MFE_VERTICALFLIP) + { + sz = ch; + } + else + { + sz = fh; + } + break; + } + case FOLLOWERMODE_FLOAT: + default: + { + // finally, add a cool floating effect to the z height. + // not stolen from k_kart I swear!! + fixed_t sine = FixedMul(fl.bobamp, FINESINE(((FixedMul(4 * M_TAU_FIXED, fl.bobspeed) * leveltime) >> ANGLETOFINESHIFT) & FINEMASK)); + sz += FixedMul(player->mo->scale, sine) * P_MobjFlip(player->mo); + break; + } } // Set follower colour @@ -317,11 +342,39 @@ void K_HandleFollower(player_t *player) } // move the follower next to us (yes, this is really basic maths but it looks pretty damn clean in practice)! - // 02/09/2021: cast lag to int32 otherwise funny things happen since it was changed to uint32 in the struct player->follower->momx = FixedDiv(sx - player->follower->x, fl.horzlag); player->follower->momy = FixedDiv(sy - player->follower->y, fl.horzlag); + player->follower->z += FixedDiv(deltaz, fl.vertlag); - player->follower->momz = FixedDiv(sz - player->follower->z, fl.vertlag); + + if (fl.mode == FOLLOWERMODE_GROUND) + { + sector_t *sec = R_PointInSubsector(sx, sy)->sector; + + fh = min(fh, P_GetFloorZ(player->follower, sec, sx, sy, NULL)); + ch = max(ch, P_GetCeilingZ(player->follower, sec, sx, sy, NULL) - ourheight); + + if (P_IsObjectOnGround(player->mo) == false) + { + // In the air, match their momentum. + player->follower->momz = player->mo->momz; + } + else + { + fixed_t fg = P_GetMobjGravity(player->mo); + fixed_t fz = P_GetMobjZMovement(player->follower); + + player->follower->momz = fz; + + // Player is on the ground ... try to get the follower + // back to the ground also if it is above it. + player->follower->momz += FixedDiv(fg * 6, fl.vertlag); // Scaled against the default value of vertlag + } + } + else + { + player->follower->momz = FixedDiv(sz - player->follower->z, fl.vertlag); + } if (player->mo->colorized) { @@ -347,7 +400,15 @@ void K_HandleFollower(player_t *player) } // if we're moving let's make the angle the direction we're moving towards. This is to avoid drifting / reverse looking awkward. - destAngle = K_MomentumAngle(player->follower); + if (FixedHypot(player->follower->momx, player->follower->momy) >= player->mo->scale) + { + destAngle = R_PointToAngle2(0, 0, player->follower->momx, player->follower->momy); + } + else + { + // Face the player's angle when standing still. + destAngle = player->mo->angle; + } // Sal: Turn the follower around when looking backwards. if ( player->cmd.buttons & BT_LOOKBACK ) @@ -363,6 +424,35 @@ void K_HandleFollower(player_t *player) player->follower->angle += FixedDiv(angleDiff, fl.anglelag); } + // Ground follower slope rotation + if (fl.mode == FOLLOWERMODE_GROUND) + { + if (player->follower->z <= fh) + { + player->follower->z = fh; + if (player->follower->momz < 0) + { + player->follower->momz = 0; + } + } + else if (player->follower->z >= ch) + { + player->follower->z = ch; + if (player->follower->momz > 0) + { + player->follower->momz = 0; + } + } + + K_CalculateBananaSlope( + player->follower, + player->follower->x, player->follower->y, player->follower->z, + player->follower->radius, ourheight, + (player->mo->eflags & MFE_VERTICALFLIP), + false + ); + } + // Finally, if the follower has bubbles, move them, set their scale, etc.... // This is what I meant earlier by it being easier, now we can just use this weird lil loop to get the job done! diff --git a/src/k_follower.h b/src/k_follower.h index b39eae9e6..27e070814 100644 --- a/src/k_follower.h +++ b/src/k_follower.h @@ -22,6 +22,13 @@ extern CV_PossibleValue_t Followercolor_cons_t[]; // follower colours table, not a duplicate because of the "Match" option. +typedef enum +{ + FOLLOWERMODE_FLOAT, // Default behavior, floats in the position you set it to. + FOLLOWERMODE_GROUND, // Snaps to the ground & rotates with slopes. + FOLLOWERMODE__MAX +} followermode_t; + // // We'll define these here because they're really just a mobj that'll follow some rules behind a player // @@ -31,6 +38,7 @@ typedef struct follower_s char name[SKINNAMESIZE+1]; // Name. This is used for the menus. We'll just follow the same rules as skins for this. skincolornum_t defaultcolor; // default color for menus. + followermode_t mode; // Follower behavior modifier. fixed_t scale; // Scale relative to the player's. fixed_t bubblescale; // Bubble scale relative to the player scale. If not set, no bubble will spawn (default) diff --git a/src/k_kart.c b/src/k_kart.c index 42adaf268..200e6b734 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3347,7 +3347,7 @@ fixed_t K_3dKartMovement(player_t *player) angle_t K_MomentumAngle(mobj_t *mo) { - if (mo->momx || mo->momy) + if (FixedHypot(mo->momx, mo->momy) >= mo->scale) { return R_PointToAngle2(0, 0, mo->momx, mo->momy); } @@ -6244,7 +6244,7 @@ static fixed_t K_BananaSlopeZ(pslope_t *slope, fixed_t x, fixed_t y, fixed_t z, return P_GetZAt(slope, testx, testy, z); } -static void K_CalculateBananaSlope(mobj_t *mobj, fixed_t x, fixed_t y, fixed_t z, fixed_t radius, fixed_t height, boolean flip, boolean player) +void K_CalculateBananaSlope(mobj_t *mobj, fixed_t x, fixed_t y, fixed_t z, fixed_t radius, fixed_t height, boolean flip, boolean player) { fixed_t newz; sector_t *sec; diff --git a/src/k_kart.h b/src/k_kart.h index 20c8cd33f..1e45e0637 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -94,6 +94,7 @@ void K_KillBananaChain(mobj_t *banana, mobj_t *inflictor, mobj_t *source); void K_UpdateHnextList(player_t *player, boolean clean); void K_DropHnextList(player_t *player, boolean keepshields); void K_RepairOrbitChain(mobj_t *orbit); +void K_CalculateBananaSlope(mobj_t *mobj, fixed_t x, fixed_t y, fixed_t z, fixed_t radius, fixed_t height, boolean flip, boolean player); player_t *K_FindJawzTarget(mobj_t *actor, player_t *source); INT32 K_GetKartRingPower(player_t *player, boolean boosted); void K_UpdateDistanceFromFinishLine(player_t *const player); From 17d007d418fd7b4955413b40ab72224b8340f747 Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 23 May 2022 22:04:14 +0100 Subject: [PATCH 35/42] * Restore player colour and colorization correctly when the Eggman Mark concludes its effect. * 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! --- src/d_netcmd.c | 3 +-- src/k_kart.c | 65 ++++++++++++++++++++++++++++++++++++-------------- src/k_kart.h | 1 + src/p_inter.c | 3 +-- src/p_user.c | 6 ++--- src/r_skins.c | 12 ++++------ 6 files changed, 57 insertions(+), 33 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index c9a030ab8..84412fd3c 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1447,8 +1447,7 @@ static void SendNameAndColor(UINT8 n) player->skincolor = cv_playercolor[n].value; - if (player->mo && !player->dye) - player->mo->color = player->skincolor; + K_KartResetPlayerColor(player); // Update follower for local games: if (cv_follower[n].value >= -1 && cv_follower[n].value != player->followerskin) diff --git a/src/k_kart.c b/src/k_kart.c index 81374d9c6..9c75d7003 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3548,8 +3548,7 @@ static void K_RemoveGrowShrink(player_t *player) else if (player->growshrinktimer < 0) // Play Grow noise S_StartSound(player->mo, sfx_kc5a); - if (player->invincibilitytimer == 0) - player->mo->color = player->skincolor; + K_KartResetPlayerColor(player); player->mo->scalespeed = mapobjectscale/TICRATE; player->mo->destscale = mapobjectscale; @@ -7571,6 +7570,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->eggmanexplode <= 0) { mobj_t *eggsexplode; + + K_KartResetPlayerColor(player); + //player->flashing = 0; eggsexplode = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_SPBEXPLOSION); if (player->eggmanblame >= 0 @@ -7650,37 +7652,45 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) K_HandleDelayedHitByEm(player); } -void K_KartPlayerAfterThink(player_t *player) +void K_KartResetPlayerColor(player_t *player) { + boolean forcereset = false; boolean fullbright = false; - if (player->playerstate == PST_DEAD || (player->respawn.state == RESPAWNST_MOVE)) // Ensure these are set correctly here + if (!player->mo || P_MobjWasRemoved(player->mo)) // Can't do anything + return; + + if (player->mo->health <= 0 || player->playerstate == PST_DEAD || (player->respawn.state == RESPAWNST_MOVE)) // Override everything { player->mo->colorized = (player->dye != 0); player->mo->color = player->dye ? player->dye : player->skincolor; + goto finalise; } - else if (player->eggmanexplode) // You're gonna diiiiie + + if (player->eggmanexplode) // You're gonna diiiiie { const INT32 flashtime = 4<<(player->eggmanexplode/TICRATE); if (player->eggmanexplode == 1 || (player->eggmanexplode % (flashtime/2) != 0)) { - player->mo->colorized = (player->dye != 0); - player->mo->color = player->dye ? player->dye : player->skincolor; + forcereset = true; } else if (player->eggmanexplode % flashtime == 0) { player->mo->colorized = true; player->mo->color = SKINCOLOR_BLACK; fullbright = true; + goto finalise; } else { player->mo->colorized = true; player->mo->color = SKINCOLOR_CRIMSON; fullbright = true; + goto finalise; } } - else if (player->invincibilitytimer) + + if (player->invincibilitytimer) // You're gonna kiiiiill { const tic_t defaultTime = itemtime+(2*TICRATE); tic_t flicker = 2; @@ -7691,45 +7701,57 @@ void K_KartPlayerAfterThink(player_t *player) { player->mo->color = K_RainbowColor(leveltime / 2); player->mo->colorized = true; + forcereset = false; } else { - player->mo->color = player->skincolor; - player->mo->colorized = false; - flicker += (defaultTime - player->invincibilitytimer) / TICRATE / 2; + forcereset = true; } if (leveltime % flicker == 0) { player->mo->color = SKINCOLOR_INVINCFLASH; player->mo->colorized = true; + forcereset = false; + } + + if (!forcereset) + { + goto finalise; } } - else if (player->growshrinktimer) // Ditto, for grow/shrink + + if (player->growshrinktimer) // Ditto, for grow/shrink { if (player->growshrinktimer % 5 == 0) { player->mo->colorized = true; player->mo->color = (player->growshrinktimer < 0 ? SKINCOLOR_CREAMSICLE : SKINCOLOR_PERIWINKLE); fullbright = true; + goto finalise; } - else - { - player->mo->colorized = (player->dye != 0); - player->mo->color = player->dye ? player->dye : player->skincolor; - } + + forcereset = true; } - else if (player->ringboost && (leveltime & 1)) // ring boosting + + if (player->ringboost && (leveltime & 1)) // ring boosting { player->mo->colorized = true; fullbright = true; + goto finalise; } else { player->mo->colorized = (player->dye != 0); + if (forcereset) + { + player->mo->color = player->dye ? player->dye : player->skincolor; + } } +finalise: + if (player->curshield) { fullbright = true; @@ -7744,6 +7766,11 @@ void K_KartPlayerAfterThink(player_t *player) if (!(player->mo->state->frame & FF_FULLBRIGHT)) player->mo->frame &= ~FF_FULLBRIGHT; } +} + +void K_KartPlayerAfterThink(player_t *player) +{ + K_KartResetPlayerColor(player); // Move held objects (Bananas, Orbinaut, etc) K_MoveHeldObjects(player); @@ -8859,6 +8886,8 @@ void K_StripOther(player_t *player) { player->eggmanexplode = 0; player->eggmanblame = -1; + + K_KartResetPlayerColor(player); } } diff --git a/src/k_kart.h b/src/k_kart.h index 20c8cd33f..de1a8ca47 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -61,6 +61,7 @@ void K_SpawnInvincibilitySpeedLines(mobj_t *mo); void K_SpawnBumpEffect(mobj_t *mo); void K_KartMoveAnimation(player_t *player); void K_KartPlayerHUDUpdate(player_t *player); +void K_KartResetPlayerColor(player_t *player); void K_KartPlayerThink(player_t *player, ticcmd_t *cmd); void K_KartPlayerAfterThink(player_t *player); angle_t K_MomentumAngle(mobj_t *mo); diff --git a/src/p_inter.c b/src/p_inter.c index 8a4d6754c..806a34994 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1767,8 +1767,7 @@ static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, player->carry = CR_NONE; - player->mo->color = player->skincolor; - player->mo->colorized = false; + K_KartResetPlayerColor(player); P_ResetPlayer(player); diff --git a/src/p_user.c b/src/p_user.c index dbf716925..81f903830 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1691,8 +1691,7 @@ static void P_CheckInvincibilityTimer(player_t *player) // Resume normal music stuff. if (player->invincibilitytimer == 1) { - player->mo->color = player->skincolor; - player->mo->colorized = false; + //K_KartResetPlayerColor(player); -- this gets called every tic anyways G_GhostAddColor((INT32) (player - players), GHC_NORMAL); P_RestoreMusic(player); @@ -2679,8 +2678,7 @@ static void P_DeathThink(player_t *player) if (!player->mo) return; - player->mo->colorized = false; - player->mo->color = player->skincolor; + //K_KartResetPlayerColor(player); -- called at death, don't think we need to re-establish P_CalcHeight(player); } diff --git a/src/r_skins.c b/src/r_skins.c index ba7ed0811..b95a63089 100644 --- a/src/r_skins.c +++ b/src/r_skins.c @@ -27,6 +27,9 @@ #include "p_local.h" #include "dehacked.h" // get_number (for thok) #include "m_cond.h" +#if 0 +#include "k_kart.h" // K_KartResetPlayerColor +#endif #ifdef HWRENDER #include "hardware/hw_md2.h" #endif @@ -285,7 +288,7 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum) { player_t *player = &players[playernum]; skin_t *skin = &skins[skinnum]; - UINT16 newcolor = 0; + //UINT16 newcolor = 0; //UINT8 i; if (skinnum >= 0 && skinnum < numskins && R_SkinUsable(playernum, skinnum)) // Make sure it exists! @@ -311,6 +314,7 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum) } player->skincolor = newcolor = skin->prefcolor; + K_KartResetPlayerColor(player); } #endif @@ -323,12 +327,6 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum) if (player->mo) { player->mo->skin = skin; - - if (newcolor) - { - player->mo->color = newcolor; - } - P_SetScale(player->mo, player->mo->scale); P_SetPlayerMobjState(player->mo, player->mo->state-states); // Prevent visual errors when switching between skins with differing number of frames } From d053d5f8ba7c4166155d11ef784dfec029539a01 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 23 May 2022 17:37:29 -0400 Subject: [PATCH 36/42] Fix blockmap WILD inconsistency when it's not PIT_CheckThing An optimized error check was put into P_BlockThingsIterator for tmthing, but this meant that anything that was not using or even setting this variable (the supermajority of them) would exit after finding 1 thing in each block. To keep this error check & keep it optimized, the PIT_ functions were expanded to three options instead of two: BMIT_CONTINUE lets the search continue. If used as the last mobj, it will return true when the iterator finishes. BMIT_ABORT ends the search and forces the iterator to return false. BMIT_STOP ends the search and forces the iterator to return true. --- src/k_botsearch.c | 52 +++---- src/k_collide.c | 52 +++---- src/k_kart.c | 24 +-- src/p_enemy.c | 22 +-- src/p_local.h | 2 +- src/p_map.c | 383 +++++++++++++++++++++++----------------------- src/p_maputl.c | 62 +++++--- src/p_maputl.h | 11 +- src/p_spec.c | 10 +- 9 files changed, 324 insertions(+), 294 deletions(-) diff --git a/src/k_botsearch.c b/src/k_botsearch.c index 07935d79c..b62b55852 100644 --- a/src/k_botsearch.c +++ b/src/k_botsearch.c @@ -51,7 +51,7 @@ struct globalsmuggle } globalsmuggle; /*-------------------------------------------------- - static boolean K_FindEggboxes(mobj_t *thing) + static BlockItReturn_t K_FindEggboxes(mobj_t *thing) Blockmap search function. Increments the random items and egg boxes counters. @@ -60,27 +60,27 @@ struct globalsmuggle thing - Object passed in from iteration. Return:- - true continues searching, false ends the search early. + BlockItReturn_t enum, see its definition for more information. --------------------------------------------------*/ -static boolean K_FindEggboxes(mobj_t *thing) +static BlockItReturn_t K_FindEggboxes(mobj_t *thing) { fixed_t dist; if (thing->type != MT_RANDOMITEM && thing->type != MT_EGGMANITEM) { - return true; + return BMIT_CONTINUE; } if (!thing->health) { - return true; + return BMIT_CONTINUE; } dist = P_AproxDistance(thing->x - globalsmuggle.eggboxx, thing->y - globalsmuggle.eggboxy); if (dist > globalsmuggle.distancetocheck) { - return true; + return BMIT_CONTINUE; } if (thing->type == MT_RANDOMITEM) @@ -92,7 +92,7 @@ static boolean K_FindEggboxes(mobj_t *thing) globalsmuggle.eggboxes++; } - return true; + return BMIT_CONTINUE; } /*-------------------------------------------------- @@ -347,7 +347,7 @@ static boolean K_PlayerAttackSteer(mobj_t *thing, UINT8 side, UINT8 weight, bool } /*-------------------------------------------------- - static boolean K_FindObjectsForNudging(mobj_t *thing) + static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing) Blockmap search function. Finds objects around the bot to steer towards/away from. @@ -356,9 +356,9 @@ static boolean K_PlayerAttackSteer(mobj_t *thing, UINT8 side, UINT8 weight, bool thing - Object passed in from iteration. Return:- - true continues searching, false ends the search early. + BlockItReturn_t enum, see its definition for more information. --------------------------------------------------*/ -static boolean K_FindObjectsForNudging(mobj_t *thing) +static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing) { INT16 anglediff; fixed_t fulldist; @@ -367,29 +367,29 @@ static boolean K_FindObjectsForNudging(mobj_t *thing) if (!globalsmuggle.botmo || P_MobjWasRemoved(globalsmuggle.botmo) || !globalsmuggle.botmo->player) { - return false; + return BMIT_ABORT; } if (thing->health <= 0) { - return true; + return BMIT_CONTINUE; } if (globalsmuggle.botmo == thing) { - return true; + return BMIT_CONTINUE; } fulldist = R_PointToDist2(globalsmuggle.botmo->x, globalsmuggle.botmo->y, thing->x, thing->y) - thing->radius; if (fulldist > globalsmuggle.distancetocheck) { - return true; + return BMIT_CONTINUE; } if (P_CheckSight(globalsmuggle.botmo, thing) == false) { - return true; + return BMIT_CONTINUE; } predictangle = R_PointToAngle2(globalsmuggle.botmo->x, globalsmuggle.botmo->y, globalsmuggle.predict->x, globalsmuggle.predict->y); @@ -607,7 +607,7 @@ static boolean K_FindObjectsForNudging(mobj_t *thing) break; } - return true; + return BMIT_CONTINUE; } /*-------------------------------------------------- @@ -776,7 +776,7 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player) } /*-------------------------------------------------- - static boolean K_FindPlayersToBully(mobj_t *thing) + static BlockItReturn_t K_FindPlayersToBully(mobj_t *thing) Blockmap search function. Finds players around the bot to bump. @@ -785,9 +785,9 @@ void K_NudgePredictionTowardsObjects(botprediction_t *predict, player_t *player) thing - Object passed in from iteration. Return:- - true continues searching, false ends the search early. + BlockItReturn_t enum, see its definition for more information. --------------------------------------------------*/ -static boolean K_FindPlayersToBully(mobj_t *thing) +static BlockItReturn_t K_FindPlayersToBully(mobj_t *thing) { INT16 anglediff; fixed_t fulldist; @@ -796,34 +796,34 @@ static boolean K_FindPlayersToBully(mobj_t *thing) if (!globalsmuggle.botmo || P_MobjWasRemoved(globalsmuggle.botmo) || !globalsmuggle.botmo->player) { - return false; + return BMIT_ABORT; } if (thing->health <= 0) { - return true; + return BMIT_CONTINUE; } if (!thing->player) { - return true; + return BMIT_CONTINUE; } if (globalsmuggle.botmo == thing) { - return true; + return BMIT_CONTINUE; } fulldist = R_PointToDist2(globalsmuggle.botmo->x, globalsmuggle.botmo->y, thing->x, thing->y) - thing->radius; if (fulldist > globalsmuggle.distancetocheck) { - return true; + return BMIT_CONTINUE; } if (P_CheckSight(globalsmuggle.botmo, thing) == false) { - return true; + return BMIT_CONTINUE; } ourangle = globalsmuggle.botmo->angle; @@ -860,7 +860,7 @@ static boolean K_FindPlayersToBully(mobj_t *thing) globalsmuggle.annoymo = thing; } - return true; + return BMIT_CONTINUE; } /*-------------------------------------------------- diff --git a/src/k_collide.c b/src/k_collide.c index 92c4bd7fd..306c01dd8 100644 --- a/src/k_collide.c +++ b/src/k_collide.c @@ -323,26 +323,26 @@ static inline boolean PIT_SSMineChecks(mobj_t *thing) return false; } -static inline boolean PIT_SSMineSearch(mobj_t *thing) +static inline BlockItReturn_t PIT_SSMineSearch(mobj_t *thing) { if (grenade == NULL || P_MobjWasRemoved(grenade)) - return false; // There's the possibility these can chain react onto themselves after they've already died if there are enough all in one spot + return BMIT_ABORT; // There's the possibility these can chain react onto themselves after they've already died if there are enough all in one spot if (grenade->flags2 & MF2_DEBRIS) // don't explode twice - return false; + return BMIT_ABORT; if (thing->type != MT_PLAYER) // Don't explode for anything but an actual player. - return true; + return BMIT_CONTINUE; if (thing == grenade->target && grenade->threshold != 0) // Don't blow up at your owner instantly. - return true; + return BMIT_CONTINUE; if (PIT_SSMineChecks(thing) == true) - return true; + return BMIT_CONTINUE; // Explode! P_SetMobjState(grenade, grenade->info->deathstate); - return false; + return BMIT_ABORT; } void K_DoMineSearch(mobj_t *actor, fixed_t size) @@ -364,21 +364,21 @@ void K_DoMineSearch(mobj_t *actor, fixed_t size) P_BlockThingsIterator(bx, by, PIT_SSMineSearch); } -static inline boolean PIT_SSMineExplode(mobj_t *thing) +static inline BlockItReturn_t PIT_SSMineExplode(mobj_t *thing) { if (grenade == NULL || P_MobjWasRemoved(grenade)) - return false; // There's the possibility these can chain react onto themselves after they've already died if there are enough all in one spot + return BMIT_ABORT; // There's the possibility these can chain react onto themselves after they've already died if there are enough all in one spot #if 0 if (grenade->flags2 & MF2_DEBRIS) // don't explode twice - return false; + return BMIT_ABORT; #endif if (PIT_SSMineChecks(thing) == true) - return true; + return BMIT_CONTINUE; P_DamageMobj(thing, grenade, grenade->target, 1, (explodespin ? DMG_NORMAL : DMG_EXPLODE)); - return true; + return BMIT_CONTINUE; } void K_MineExplodeAttack(mobj_t *actor, fixed_t size, boolean spin) @@ -667,60 +667,54 @@ boolean K_DropTargetCollide(mobj_t *t1, mobj_t *t2) static mobj_t *lightningSource; static fixed_t lightningDist; -static inline boolean PIT_LightningShieldAttack(mobj_t *thing) +static inline BlockItReturn_t PIT_LightningShieldAttack(mobj_t *thing) { if (lightningSource == NULL || P_MobjWasRemoved(lightningSource)) { // Invalid? - return false; + return BMIT_ABORT; } if (thing == lightningSource) { // Don't explode yourself!! - return true; + return BMIT_CONTINUE; } if (thing->health <= 0) { // Dead - return true; + return BMIT_CONTINUE; } if (!(thing->flags & MF_SHOOTABLE) || (thing->flags & MF_SCENERY)) { // Not shootable - return true; + return BMIT_CONTINUE; } if (thing->player && thing->player->spectator) { // Spectator - return true; - } - - if ((lightningSource->eflags & MFE_VERTICALFLIP) - ? (thing->z > lightningSource->z + lightningSource->height) - : (thing->z + thing->height < lightningSource->z)) - { - // Underneath - return true; + return BMIT_CONTINUE; } if (P_AproxDistance(thing->x - lightningSource->x, thing->y - lightningSource->y) > lightningDist + thing->radius) { // Too far away - return true; + return BMIT_CONTINUE; } +#if 0 if (P_CheckSight(lightningSource, thing) == false) { // Not in sight - return true; + return BMIT_CONTINUE; } +#endif P_DamageMobj(thing, lightningSource, lightningSource, 1, DMG_NORMAL|DMG_CANTHURTSELF|DMG_WOMBO); - return true; + return BMIT_CONTINUE; } void K_LightningShieldAttack(mobj_t *actor, fixed_t size) diff --git a/src/k_kart.c b/src/k_kart.c index 81374d9c6..183d16a5f 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -7062,57 +7062,57 @@ static mobj_t *attractmo; static fixed_t attractdist; static fixed_t attractzdist; -static inline boolean PIT_AttractingRings(mobj_t *thing) +static inline BlockItReturn_t PIT_AttractingRings(mobj_t *thing) { if (attractmo == NULL || P_MobjWasRemoved(attractmo) || attractmo->player == NULL) { - return false; + return BMIT_ABORT; } if (thing == NULL || P_MobjWasRemoved(thing)) { - return true; // invalid + return BMIT_CONTINUE; // invalid } if (thing == attractmo) { - return true; // invalid + return BMIT_CONTINUE; // invalid } if (!(thing->type == MT_RING || thing->type == MT_FLINGRING)) { - return true; // not a ring + return BMIT_CONTINUE; // not a ring } if (thing->health <= 0) { - return true; // dead + return BMIT_CONTINUE; // dead } if (thing->extravalue1) { - return true; // in special ring animation + return BMIT_CONTINUE; // in special ring animation } if (thing->tracer != NULL && P_MobjWasRemoved(thing->tracer) == false) { - return true; // already attracted + return BMIT_CONTINUE; // already attracted } // see if it went over / under if (attractmo->z - attractzdist > thing->z + thing->height) { - return true; // overhead + return BMIT_CONTINUE; // overhead } if (attractmo->z + attractmo->height + attractzdist < thing->z) { - return true; // underneath + return BMIT_CONTINUE; // underneath } if (P_AproxDistance(attractmo->x - thing->x, attractmo->y - thing->y) > attractdist + thing->radius) { - return true; // Too far away + return BMIT_CONTINUE; // Too far away } if (RINGTOTAL(attractmo->player) >= 20 || (attractmo->player->pflags & PF_RINGLOCK)) @@ -7139,7 +7139,7 @@ static inline boolean PIT_AttractingRings(mobj_t *thing) P_SetTarget(&thing->tracer, attractmo); } - return true; // find other rings + return BMIT_CONTINUE; // find other rings } /** Looks for rings near a player in the blockmap. diff --git a/src/p_enemy.c b/src/p_enemy.c index 65f00e116..cf28c31d6 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -4573,26 +4573,26 @@ void A_ShootBullet(mobj_t *actor) static mobj_t *minus; -static boolean PIT_MinusCarry(mobj_t *thing) +static BlockItReturn_t PIT_MinusCarry(mobj_t *thing) { if (minus->tracer) - return true; + return BMIT_CONTINUE; if (minus->type == thing->type) - return true; + return BMIT_CONTINUE; if (!(thing->flags & (MF_PUSHABLE|MF_ENEMY))) - return true; + return BMIT_CONTINUE; if (P_AproxDistance(minus->x - thing->x, minus->y - thing->y) >= minus->radius*3) - return true; + return BMIT_CONTINUE; if (abs(thing->z - minus->z) > minus->height) - return true; + return BMIT_CONTINUE; P_SetTarget(&minus->tracer, thing); - return true; + return BMIT_CONTINUE; } // Function: A_MinusDigging @@ -12145,13 +12145,13 @@ static mobj_t *barrel; static fixed_t exploderadius; static fixed_t explodethrust; -static boolean PIT_TNTExplode(mobj_t *nearby) +static BlockItReturn_t PIT_TNTExplode(mobj_t *nearby) { fixed_t dx, dy, dz; fixed_t dm; if (nearby == barrel) - return true; + return BMIT_CONTINUE; dx = nearby->x - barrel->x; dy = nearby->y - barrel->y; @@ -12159,7 +12159,7 @@ static boolean PIT_TNTExplode(mobj_t *nearby) dm = P_AproxDistance(P_AproxDistance(dx, dy), dz); if (dm >= exploderadius || !P_CheckSight(barrel, nearby)) // out of range or not visible - return true; + return BMIT_CONTINUE; if (barrel->type == nearby->type) // nearby is also a barrel { @@ -12200,7 +12200,7 @@ static boolean PIT_TNTExplode(mobj_t *nearby) } } - return true; + return BMIT_CONTINUE; } // Function: A_TNTExplode diff --git a/src/p_local.h b/src/p_local.h index 4940daf81..82b1d445c 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -435,7 +435,7 @@ void P_RadiusAttack(mobj_t *spot, mobj_t *source, fixed_t damagedist, UINT8 dama fixed_t P_FloorzAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height); fixed_t P_CeilingzAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height); -boolean PIT_PushableMoved(mobj_t *thing); +BlockItReturn_t PIT_PushableMoved(mobj_t *thing); boolean P_DoSpring(mobj_t *spring, mobj_t *object); diff --git a/src/p_map.c b/src/p_map.c index f75968169..a64f9d761 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -523,17 +523,20 @@ static void P_DoFanAndGasJet(mobj_t *spring, mobj_t *object) // // PIT_CheckThing // -static boolean PIT_CheckThing(mobj_t *thing) +static BlockItReturn_t PIT_CheckThing(mobj_t *thing) { fixed_t blockdist; + if (tmthing == NULL || P_MobjWasRemoved(tmthing) == true) + return BMIT_STOP; // func just popped our tmthing, cannot continue. + // don't clip against self if (thing == tmthing) - return true; + return BMIT_CONTINUE; // Ignore... things. if (!tmthing || !thing || P_MobjWasRemoved(thing)) - return true; + return BMIT_CONTINUE; I_Assert(!P_MobjWasRemoved(tmthing)); I_Assert(!P_MobjWasRemoved(thing)); @@ -541,19 +544,19 @@ static boolean PIT_CheckThing(mobj_t *thing) // Ignore spectators if ((tmthing->player && tmthing->player->spectator) || (thing->player && thing->player->spectator)) - return true; + return BMIT_CONTINUE; // Ignore the collision if BOTH things are in hitlag. if (thing->hitlag > 0 && tmthing->hitlag > 0) - return true; + return BMIT_CONTINUE; if ((thing->flags & MF_NOCLIPTHING) || !(thing->flags & (MF_SOLID|MF_SPECIAL|MF_PAIN|MF_SHOOTABLE|MF_SPRING))) - return true; + return BMIT_CONTINUE; blockdist = thing->radius + tmthing->radius; if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist) - return true; // didn't hit it + return BMIT_CONTINUE; // didn't hit it if (thing->flags & MF_PAPERCOLLISION) // CAUTION! Very easy to get stuck inside MF_SOLID objects. Giving the player MF_PAPERCOLLISION is a bad idea unless you know what you're doing. { @@ -580,23 +583,23 @@ static boolean PIT_CheckThing(mobj_t *thing) fixed_t tmcosradius = FixedMul(tmthing->radius, FINECOSINE(tmthing->angle>>ANGLETOFINESHIFT)); fixed_t tmsinradius = FixedMul(tmthing->radius, FINESINE(tmthing->angle>>ANGLETOFINESHIFT)); if (abs(thing->x - tmx) >= (abs(tmcosradius) + abs(cosradius)) || abs(thing->y - tmy) >= (abs(tmsinradius) + abs(sinradius))) - return true; // didn't hit it + return BMIT_CONTINUE; // didn't hit it check1 = P_PointOnLineSide(tmx - tmcosradius, tmy - tmsinradius, &junk); check2 = P_PointOnLineSide(tmx + tmcosradius, tmy + tmsinradius, &junk); check3 = P_PointOnLineSide(tmx + tmthing->momx - tmcosradius, tmy + tmthing->momy - tmsinradius, &junk); check4 = P_PointOnLineSide(tmx + tmthing->momx + tmcosradius, tmy + tmthing->momy + tmsinradius, &junk); if ((check1 == check2) && (check2 == check3) && (check3 == check4)) - return true; // the line doesn't cross between collider's start or end + return BMIT_CONTINUE; // the line doesn't cross between collider's start or end } else { if (abs(thing->x - tmx) >= (tmthing->radius + abs(cosradius)) || abs(thing->y - tmy) >= (tmthing->radius + abs(sinradius))) - return true; // didn't hit it + return BMIT_CONTINUE; // didn't hit it if ((P_PointOnLineSide(tmx - tmthing->radius, tmy - tmthing->radius, &junk) == P_PointOnLineSide(tmx + tmthing->radius, tmy + tmthing->radius, &junk)) && (P_PointOnLineSide(tmx + tmthing->radius, tmy - tmthing->radius, &junk) == P_PointOnLineSide(tmx - tmthing->radius, tmy + tmthing->radius, &junk))) - return true; // the line doesn't cross between either pair of opposite corners + return BMIT_CONTINUE; // the line doesn't cross between either pair of opposite corners } } else if (tmthing->flags & MF_PAPERCOLLISION) @@ -609,7 +612,7 @@ static boolean PIT_CheckThing(mobj_t *thing) tmsinradius = FixedMul(tmthing->radius, FINESINE(tmthing->angle>>ANGLETOFINESHIFT)); if (abs(thing->x - tmx) >= (thing->radius + abs(tmcosradius)) || abs(thing->y - tmy) >= (thing->radius + abs(tmsinradius))) - return true; // didn't hit it + return BMIT_CONTINUE; // didn't hit it v1.x = tmx - tmcosradius; v1.y = tmy - tmsinradius; @@ -626,34 +629,34 @@ static boolean PIT_CheckThing(mobj_t *thing) == P_PointOnLineSide(thing->x + thing->radius, thing->y + thing->radius, &junk)) && (P_PointOnLineSide(thing->x + thing->radius, thing->y - thing->radius, &junk) == P_PointOnLineSide(thing->x - thing->radius, thing->y + thing->radius, &junk))) - return true; // the line doesn't cross between either pair of opposite corners + return BMIT_CONTINUE; // the line doesn't cross between either pair of opposite corners } { UINT8 shouldCollide = LUAh_MobjCollide(thing, tmthing); // checks hook for thing's type if (P_MobjWasRemoved(tmthing) || P_MobjWasRemoved(thing)) - return true; // one of them was removed??? + return BMIT_CONTINUE; // one of them was removed??? if (shouldCollide == 1) - return false; // force collide + return BMIT_ABORT; // force collide else if (shouldCollide == 2) - return true; // force no collide + return BMIT_CONTINUE; // force no collide shouldCollide = LUAh_MobjMoveCollide(tmthing, thing); // checks hook for tmthing's type if (P_MobjWasRemoved(tmthing) || P_MobjWasRemoved(thing)) - return true; // one of them was removed??? + return BMIT_CONTINUE; // one of them was removed??? if (shouldCollide == 1) - return false; // force collide + return BMIT_ABORT; // force collide else if (shouldCollide == 2) - return true; // force no collide + return BMIT_CONTINUE; // force no collide } // When solid spikes move, assume they just popped up and teleport things on top of them to hurt. if (tmthing->type == MT_SPIKE && tmthing->flags & MF_SOLID) { if (thing->z > tmthing->z + tmthing->height) - return true; // overhead + return BMIT_CONTINUE; // overhead if (thing->z + thing->height < tmthing->z) - return true; // underneath + return BMIT_CONTINUE; // underneath if (tmthing->eflags & MFE_VERTICALFLIP) P_SetOrigin(thing, thing->x, thing->y, tmthing->z - thing->height - FixedMul(FRACUNIT, tmthing->scale)); @@ -661,16 +664,16 @@ static boolean PIT_CheckThing(mobj_t *thing) P_SetOrigin(thing, thing->x, thing->y, tmthing->z + tmthing->height + FixedMul(FRACUNIT, tmthing->scale)); if (thing->flags & MF_SHOOTABLE) P_DamageMobj(thing, tmthing, tmthing, 1, 0); - return true; + return BMIT_CONTINUE; } if (thing->flags & MF_PAIN) { // Player touches painful thing sitting on the floor // see if it went over / under if (thing->z > tmthing->z + tmthing->height) - return true; // overhead + return BMIT_CONTINUE; // overhead if (thing->z + thing->height < tmthing->z) - return true; // underneath + return BMIT_CONTINUE; // underneath if (tmthing->flags & MF_SHOOTABLE && thing->health > 0) { UINT32 damagetype = (thing->info->mass & 0xFF); @@ -678,15 +681,15 @@ static boolean PIT_CheckThing(mobj_t *thing) if (P_DamageMobj(tmthing, thing, thing, 1, damagetype) && (damagetype = (thing->info->mass>>8))) S_StartSound(thing, damagetype); } - return true; + return BMIT_CONTINUE; } else if (tmthing->flags & MF_PAIN && thing->player) { // Painful thing splats player in the face // see if it went over / under if (tmthing->z > thing->z + thing->height) - return true; // overhead + return BMIT_CONTINUE; // overhead if (tmthing->z + tmthing->height < thing->z) - return true; // underneath + return BMIT_CONTINUE; // underneath if (thing->flags & MF_SHOOTABLE && tmthing->health > 0) { UINT32 damagetype = (tmthing->info->mass & 0xFF); @@ -694,7 +697,7 @@ static boolean PIT_CheckThing(mobj_t *thing) if (P_DamageMobj(thing, tmthing, tmthing, 1, damagetype) && (damagetype = (tmthing->info->mass>>8))) S_StartSound(tmthing, damagetype); } - return true; + return BMIT_CONTINUE; } // check for skulls slamming into things @@ -702,13 +705,13 @@ static boolean PIT_CheckThing(mobj_t *thing) { // see if it went over / under if (tmthing->z > thing->z + thing->height) - return true; // overhead + return BMIT_CONTINUE; // overhead if (tmthing->z + tmthing->height < thing->z) - return true; // underneath + return BMIT_CONTINUE; // underneath tmthing->flags2 &= ~MF2_SKULLFLY; tmthing->momx = tmthing->momy = tmthing->momz = 0; - return false; // stop moving + return BMIT_ABORT; // stop moving } // SRB2kart 011617 - Colission[sic] code for kart items //{ @@ -717,46 +720,46 @@ static boolean PIT_CheckThing(mobj_t *thing) { // see if it went over / under if (tmthing->z > thing->z + thing->height) - return true; // overhead + return BMIT_CONTINUE; // overhead if (tmthing->z + tmthing->height < thing->z) - return true; // underneath + return BMIT_CONTINUE; // underneath - return K_SMKIceBlockCollide(tmthing, thing); + return K_SMKIceBlockCollide(tmthing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } else if (thing->type == MT_SMK_ICEBLOCK) { // see if it went over / under if (tmthing->z > thing->z + thing->height) - return true; // overhead + return BMIT_CONTINUE; // overhead if (tmthing->z + tmthing->height < thing->z) - return true; // underneath + return BMIT_CONTINUE; // underneath - return K_SMKIceBlockCollide(thing, tmthing); + return K_SMKIceBlockCollide(thing, tmthing) ? BMIT_CONTINUE : BMIT_ABORT; } if (tmthing->type == MT_EGGMANITEM || tmthing->type == MT_EGGMANITEM_SHIELD) { // see if it went over / under if (tmthing->z > thing->z + thing->height) - return true; // overhead + return BMIT_CONTINUE; // overhead if (tmthing->z + tmthing->height < thing->z) - return true; // underneath + return BMIT_CONTINUE; // underneath - return K_EggItemCollide(tmthing, thing); + return K_EggItemCollide(tmthing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } else if (thing->type == MT_EGGMANITEM || thing->type == MT_EGGMANITEM_SHIELD) { // see if it went over / under if (tmthing->z > thing->z + thing->height) - return true; // overhead + return BMIT_CONTINUE; // overhead if (tmthing->z + tmthing->height < thing->z) - return true; // underneath + return BMIT_CONTINUE; // underneath - return K_EggItemCollide(thing, tmthing); + return K_EggItemCollide(thing, tmthing) ? BMIT_CONTINUE : BMIT_ABORT; } if (tmthing->type == MT_RANDOMITEM) - return true; + return BMIT_CONTINUE; // Bubble Shield reflect if (((thing->type == MT_BUBBLESHIELD && thing->target->player && thing->target->player->bubbleblowup) @@ -768,11 +771,11 @@ static boolean PIT_CheckThing(mobj_t *thing) { // see if it went over / under if (tmthing->z > thing->z + thing->height) - return true; // overhead + return BMIT_CONTINUE; // overhead if (tmthing->z + tmthing->height < thing->z) - return true; // underneath + return BMIT_CONTINUE; // underneath - return K_BubbleShieldCollide(thing, tmthing); + return K_BubbleShieldCollide(thing, tmthing) ? BMIT_CONTINUE : BMIT_ABORT; } else if (((tmthing->type == MT_BUBBLESHIELD && tmthing->target->player && tmthing->target->player->bubbleblowup) || (tmthing->player && tmthing->player->bubbleblowup)) @@ -783,16 +786,16 @@ static boolean PIT_CheckThing(mobj_t *thing) { // see if it went over / under if (tmthing->z > thing->z + thing->height) - return true; // overhead + return BMIT_CONTINUE; // overhead if (tmthing->z + tmthing->height < thing->z) - return true; // underneath + return BMIT_CONTINUE; // underneath - return K_BubbleShieldCollide(tmthing, thing); + return K_BubbleShieldCollide(tmthing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } // double make sure bubbles won't collide with anything else if (thing->type == MT_BUBBLESHIELD || tmthing->type == MT_BUBBLESHIELD) - return true; + return BMIT_CONTINUE; // Droptarget reflect if ((thing->type == MT_DROPTARGET || thing->type == MT_DROPTARGET_SHIELD) @@ -803,11 +806,11 @@ static boolean PIT_CheckThing(mobj_t *thing) { // see if it went over / under if (tmthing->z > thing->z + thing->height) - return true; // overhead + return BMIT_CONTINUE; // overhead if (tmthing->z + tmthing->height < thing->z) - return true; // underneath + return BMIT_CONTINUE; // underneath - return K_DropTargetCollide(thing, tmthing); + return K_DropTargetCollide(thing, tmthing) ? BMIT_CONTINUE : BMIT_ABORT; } else if ((tmthing->type == MT_DROPTARGET || tmthing->type == MT_DROPTARGET_SHIELD) && (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ || thing->type == MT_JAWZ_DUD @@ -817,144 +820,144 @@ static boolean PIT_CheckThing(mobj_t *thing) { // see if it went over / under if (tmthing->z > thing->z + thing->height) - return true; // overhead + return BMIT_CONTINUE; // overhead if (tmthing->z + tmthing->height < thing->z) - return true; // underneath + return BMIT_CONTINUE; // underneath - return K_DropTargetCollide(tmthing, thing); + return K_DropTargetCollide(tmthing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } // double make sure drop targets won't collide with anything else if (thing->type == MT_DROPTARGET || tmthing->type == MT_DROPTARGET || thing->type == MT_DROPTARGET_SHIELD || tmthing->type == MT_DROPTARGET_SHIELD) - return true; + return BMIT_CONTINUE; if (tmthing->type == MT_ORBINAUT || tmthing->type == MT_JAWZ || tmthing->type == MT_JAWZ_DUD || tmthing->type == MT_ORBINAUT_SHIELD || tmthing->type == MT_JAWZ_SHIELD) { // see if it went over / under if (tmthing->z > thing->z + thing->height) - return true; // overhead + return BMIT_CONTINUE; // overhead if (tmthing->z + tmthing->height < thing->z) - return true; // underneath + return BMIT_CONTINUE; // underneath - return K_OrbinautJawzCollide(tmthing, thing); + return K_OrbinautJawzCollide(tmthing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } else if (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ || thing->type == MT_JAWZ_DUD || thing->type == MT_ORBINAUT_SHIELD || thing->type == MT_JAWZ_SHIELD) { // see if it went over / under if (tmthing->z > thing->z + thing->height) - return true; // overhead + return BMIT_CONTINUE; // overhead if (tmthing->z + tmthing->height < thing->z) - return true; // underneath + return BMIT_CONTINUE; // underneath - return K_OrbinautJawzCollide(thing, tmthing); + return K_OrbinautJawzCollide(thing, tmthing) ? BMIT_CONTINUE : BMIT_ABORT; } if (tmthing->type == MT_BANANA || tmthing->type == MT_BANANA_SHIELD || tmthing->type == MT_BALLHOG) { // see if it went over / under if (tmthing->z > thing->z + thing->height) - return true; // overhead + return BMIT_CONTINUE; // overhead if (tmthing->z + tmthing->height < thing->z) - return true; // underneath + return BMIT_CONTINUE; // underneath - return K_BananaBallhogCollide(tmthing, thing); + return K_BananaBallhogCollide(tmthing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } else if (thing->type == MT_BANANA || thing->type == MT_BANANA_SHIELD || thing->type == MT_BALLHOG) { // see if it went over / under if (tmthing->z > thing->z + thing->height) - return true; // overhead + return BMIT_CONTINUE; // overhead if (tmthing->z + tmthing->height < thing->z) - return true; // underneath + return BMIT_CONTINUE; // underneath - return K_BananaBallhogCollide(thing, tmthing); + return K_BananaBallhogCollide(thing, tmthing) ? BMIT_CONTINUE : BMIT_ABORT; } if (tmthing->type == MT_SSMINE || tmthing->type == MT_SSMINE_SHIELD) { // see if it went over / under if (tmthing->z > thing->z + thing->height) - return true; // overhead + return BMIT_CONTINUE; // overhead if (tmthing->z + tmthing->height < thing->z) - return true; // underneath + return BMIT_CONTINUE; // underneath - return K_MineCollide(tmthing, thing); + return K_MineCollide(tmthing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } else if (thing->type == MT_SSMINE || thing->type == MT_SSMINE_SHIELD) { // see if it went over / under if (tmthing->z > thing->z + thing->height) - return true; // overhead + return BMIT_CONTINUE; // overhead if (tmthing->z + tmthing->height < thing->z) - return true; // underneath + return BMIT_CONTINUE; // underneath - return K_MineCollide(thing, tmthing); + return K_MineCollide(thing, tmthing) ? BMIT_CONTINUE : BMIT_ABORT; } if (tmthing->type == MT_LANDMINE) { // see if it went over / under if (tmthing->z > thing->z + thing->height) - return true; // overhead + return BMIT_CONTINUE; // overhead if (tmthing->z + tmthing->height < thing->z) - return true; // underneath + return BMIT_CONTINUE; // underneath - return K_LandMineCollide(tmthing, thing); + return K_LandMineCollide(tmthing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } else if (thing->type == MT_LANDMINE) { // see if it went over / under if (tmthing->z > thing->z + thing->height) - return true; // overhead + return BMIT_CONTINUE; // overhead if (tmthing->z + tmthing->height < thing->z) - return true; // underneath + return BMIT_CONTINUE; // underneath - return K_LandMineCollide(thing, tmthing); + return K_LandMineCollide(thing, tmthing) ? BMIT_CONTINUE : BMIT_ABORT; } if (tmthing->type == MT_SINK) { // see if it went over / under if (tmthing->z > thing->z + thing->height) - return true; // overhead + return BMIT_CONTINUE; // overhead if (tmthing->z + tmthing->height < thing->z) - return true; // underneath + return BMIT_CONTINUE; // underneath - return K_KitchenSinkCollide(tmthing, thing); + return K_KitchenSinkCollide(tmthing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } else if (thing->type == MT_SINK) { // see if it went over / under if (tmthing->z > thing->z + thing->height) - return true; // overhead + return BMIT_CONTINUE; // overhead if (tmthing->z + tmthing->height < thing->z) - return true; // underneath + return BMIT_CONTINUE; // underneath - return K_KitchenSinkCollide(thing, tmthing); + return K_KitchenSinkCollide(thing, tmthing) ? BMIT_CONTINUE : BMIT_ABORT; } if (tmthing->type == MT_FALLINGROCK) { // see if it went over / under if (tmthing->z > thing->z + thing->height) - return true; // overhead + return BMIT_CONTINUE; // overhead if (tmthing->z + tmthing->height < thing->z) - return true; // underneath + return BMIT_CONTINUE; // underneath - return K_FallingRockCollide(tmthing, thing); + return K_FallingRockCollide(tmthing, thing) ? BMIT_CONTINUE : BMIT_ABORT; } else if (thing->type == MT_FALLINGROCK) { // see if it went over / under if (tmthing->z > thing->z + thing->height) - return true; // overhead + return BMIT_CONTINUE; // overhead if (tmthing->z + tmthing->height < thing->z) - return true; // underneath + return BMIT_CONTINUE; // underneath - return K_FallingRockCollide(thing, tmthing); + return K_FallingRockCollide(thing, tmthing) ? BMIT_CONTINUE : BMIT_ABORT; } //} @@ -972,10 +975,10 @@ static boolean PIT_CheckThing(mobj_t *thing) if (tmznext <= thzh) { P_DoSpring(thing, tmthing); - // return true; + // return BMIT_CONTINUE; } //else if (tmz > thzh - sprarea && tmz < thzh) // Don't damage people springing up / down - return true; + return BMIT_CONTINUE; } // missiles can hit other things @@ -985,35 +988,35 @@ static boolean PIT_CheckThing(mobj_t *thing) // see if it went over / under if (tmthing->z > thing->z + thing->height) - return true; // overhead + return BMIT_CONTINUE; // overhead if (tmthing->z + tmthing->height < thing->z) - return true; // underneath + return BMIT_CONTINUE; // underneath if (tmthing->target && tmthing->target->type == thing->type) { // Don't hit same species as originator. if (thing == tmthing->target) - return true; + return BMIT_CONTINUE; if (thing->type != MT_PLAYER) { // Explode, but do no damage. // Let players missile other players. - return false; + return BMIT_ABORT; } } if (!(thing->flags & MF_SHOOTABLE)) { // didn't do any damage - return !(thing->flags & MF_SOLID); + return (thing->flags & MF_SOLID) ? BMIT_ABORT : BMIT_CONTINUE; } // damage / explode P_DamageMobj(thing, tmthing, tmthing->target, 1, damagetype); // don't traverse any more - return false; + return BMIT_ABORT; } if (thing->flags & MF_PUSHABLE && (tmthing->player || tmthing->flags & MF_PUSHABLE) @@ -1080,13 +1083,13 @@ static boolean PIT_CheckThing(mobj_t *thing) if (thing->flags & MF_SPECIAL && tmthing->player) { P_TouchSpecialThing(thing, tmthing, true); // can remove thing - return true; + return BMIT_CONTINUE; } // check again for special pickup if (tmthing->flags & MF_SPECIAL && thing->player) { P_TouchSpecialThing(tmthing, thing, true); // can remove thing - return true; + return BMIT_CONTINUE; } // Sprite Spikes! @@ -1142,7 +1145,7 @@ static boolean PIT_CheckThing(mobj_t *thing) if (playerangle > ANGLE_180) playerangle = InvAngle(playerangle); if (playerangle < ANGLE_90) - return true; // Yes, this is intentionally outside the z-height check. No standing on spikes whilst moving away from them. + return BMIT_CONTINUE; // Yes, this is intentionally outside the z-height check. No standing on spikes whilst moving away from them. } bottomz = thing->z; @@ -1176,15 +1179,15 @@ static boolean PIT_CheckThing(mobj_t *thing) if (thing->type == MT_FAN || thing->type == MT_STEAM) { P_DoFanAndGasJet(thing, tmthing); - return true; + return BMIT_CONTINUE; } else if (thing->flags & MF_SPRING) { if ( thing->z <= tmthing->z + tmthing->height && tmthing->z <= thing->z + thing->height) if (P_DoSpring(thing, tmthing)) - return false; - return true; + return BMIT_ABORT; + return BMIT_CONTINUE; } } @@ -1193,7 +1196,7 @@ static boolean PIT_CheckThing(mobj_t *thing) { if ((thing->z + thing->height >= tmthing->z) && (tmthing->z + tmthing->height >= thing->z)) - return false; + return BMIT_ABORT; } if (thing->player) @@ -1205,7 +1208,7 @@ static boolean PIT_CheckThing(mobj_t *thing) if (tmthing->player) // Is the moving/interacting object the player? { if (!tmthing->health) - return true; + return BMIT_CONTINUE; if (thing->type == MT_FAN || thing->type == MT_STEAM) P_DoFanAndGasJet(thing, tmthing); @@ -1214,27 +1217,27 @@ static boolean PIT_CheckThing(mobj_t *thing) if ( thing->z <= tmthing->z + tmthing->height && tmthing->z <= thing->z + thing->height) if (P_DoSpring(thing, tmthing)) - return false; - return true; + return BMIT_ABORT; + return BMIT_CONTINUE; } else if (thing->player) // bounce when players collide { // see if it went over / under if (tmthing->z > thing->z + thing->height) - return true; // overhead + return BMIT_CONTINUE; // overhead if (tmthing->z + tmthing->height < thing->z) - return true; // underneath + return BMIT_CONTINUE; // underneath if (thing->player->hyudorotimer || tmthing->player->hyudorotimer) { - return true; + return BMIT_CONTINUE; } if ((gametyperules & GTR_BUMPERS) && ((thing->player->bumpers && !tmthing->player->bumpers) || (tmthing->player->bumpers && !thing->player->bumpers))) { - return true; + return BMIT_CONTINUE; } // The bump has to happen last @@ -1252,18 +1255,18 @@ static boolean PIT_CheckThing(mobj_t *thing) K_PvPTouchDamage(tmthing, thing); } - return true; + return BMIT_CONTINUE; } else if (thing->type == MT_BLUEROBRA_HEAD || thing->type == MT_BLUEROBRA_JOINT) { // see if it went over / under if (tmthing->z > thing->z + thing->height) - return true; // overhead + return BMIT_CONTINUE; // overhead if (tmthing->z + tmthing->height < thing->z) - return true; // underneath + return BMIT_CONTINUE; // underneath if (!thing->health) - return true; // dead + return BMIT_CONTINUE; // dead if (tmthing->player->invincibilitytimer > 0 || tmthing->player->growshrinktimer > 0) @@ -1272,42 +1275,42 @@ static boolean PIT_CheckThing(mobj_t *thing) P_KillMobj(thing->target, tmthing, tmthing, DMG_NORMAL); else P_KillMobj(thing, tmthing, tmthing, DMG_NORMAL); - return true; + return BMIT_CONTINUE; } else { K_KartSolidBounce(tmthing, thing); - return true; + return BMIT_CONTINUE; } } else if (thing->type == MT_SMK_PIPE) { // see if it went over / under if (tmthing->z > thing->z + thing->height) - return true; // overhead + return BMIT_CONTINUE; // overhead if (tmthing->z + tmthing->height < thing->z) - return true; // underneath + return BMIT_CONTINUE; // underneath if (!thing->health) - return true; // dead + return BMIT_CONTINUE; // dead if (tmthing->player->invincibilitytimer > 0 || tmthing->player->growshrinktimer > 0) { P_KillMobj(thing, tmthing, tmthing, DMG_NORMAL); - return true; // kill + return BMIT_CONTINUE; // kill } K_KartSolidBounce(tmthing, thing); - return true; + return BMIT_CONTINUE; } else if (thing->type == MT_SMK_THWOMP) { if (!thing->health) - return true; // dead + return BMIT_CONTINUE; // dead if (!thwompsactive) - return true; // not active yet + return BMIT_CONTINUE; // not active yet if ((tmthing->z < thing->z) && (thing->z >= thing->movefactor-(256<z > thing->z + thing->height) - return true; // overhead + return BMIT_CONTINUE; // overhead if (tmthing->z + tmthing->height < thing->z) - return true; // underneath + return BMIT_CONTINUE; // underneath // kill if (tmthing->player->invincibilitytimer > 0 || tmthing->player->growshrinktimer > 0) { P_KillMobj(thing, tmthing, tmthing, DMG_NORMAL); - return true; + return BMIT_CONTINUE; } // no interaction if (tmthing->player->flashing > 0 || tmthing->player->hyudorotimer > 0 || tmthing->player->spinouttimer > 0) - return true; + return BMIT_CONTINUE; // collide if (tmthing->z < thing->z && thing->momz < 0) @@ -1344,29 +1347,29 @@ static boolean PIT_CheckThing(mobj_t *thing) } } - return true; + return BMIT_CONTINUE; } else if (thing->type == MT_KART_LEFTOVER) { // see if it went over / under if (tmthing->z > thing->z + thing->height) - return true; // overhead + return BMIT_CONTINUE; // overhead if (tmthing->z + tmthing->height < thing->z) - return true; // underneath + return BMIT_CONTINUE; // underneath K_KartBouncing(tmthing, thing); - return true; + return BMIT_CONTINUE; } else if (thing->flags & MF_SOLID) { // see if it went over / under if (tmthing->z > thing->z + thing->height) - return true; // overhead + return BMIT_CONTINUE; // overhead if (tmthing->z + tmthing->height < thing->z) - return true; // underneath + return BMIT_CONTINUE; // underneath K_KartSolidBounce(tmthing, thing); - return true; + return BMIT_CONTINUE; } } @@ -1393,7 +1396,7 @@ static boolean PIT_CheckThing(mobj_t *thing) tmfloorslope = NULL; tmfloorpic = -1; } - return true; + return BMIT_CONTINUE; } topz = thing->z - thing->scale; // FixedMul(FRACUNIT, thing->scale), but thing->scale == FRACUNIT in base scale anyways @@ -1406,7 +1409,7 @@ static boolean PIT_CheckThing(mobj_t *thing) && tmthing->z + tmthing->height < tmthing->ceilingz) { if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->info->flags & MF_MONITOR)) // Gold monitor hack... - return false; + return BMIT_ABORT; tmfloorz = tmceilingz = topz; // block while in air tmceilingrover = NULL; @@ -1437,7 +1440,7 @@ static boolean PIT_CheckThing(mobj_t *thing) tmceilingslope = NULL; tmceilingpic = -1; } - return true; + return BMIT_CONTINUE; } topz = thing->z + thing->height + thing->scale; // FixedMul(FRACUNIT, thing->scale), but thing->scale == FRACUNIT in base scale anyways @@ -1450,7 +1453,7 @@ static boolean PIT_CheckThing(mobj_t *thing) && tmthing->z > tmthing->floorz) { if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->info->flags & MF_MONITOR)) // Gold monitor hack... - return false; + return BMIT_ABORT; tmfloorz = tmceilingz = topz; // block while in air tmfloorrover = NULL; @@ -1470,24 +1473,24 @@ static boolean PIT_CheckThing(mobj_t *thing) } // not solid not blocked - return true; + return BMIT_CONTINUE; } // PIT_CheckCameraLine // Adjusts tmfloorz and tmceilingz as lines are contacted - FOR CAMERA ONLY -static boolean PIT_CheckCameraLine(line_t *ld) +static BlockItReturn_t PIT_CheckCameraLine(line_t *ld) { if (ld->polyobj && !(ld->polyobj->flags & POF_SOLID)) - return true; + return BMIT_CONTINUE; if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT] || tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) { - return true; + return BMIT_CONTINUE; } if (P_BoxOnLineSide(tmbbox, ld) != -1) - return true; + return BMIT_CONTINUE; // A line has been hit @@ -1505,8 +1508,8 @@ static boolean PIT_CheckCameraLine(line_t *ld) if (!ld->backsector) // one sided line { if (P_PointOnLineSide(mapcampointer->x, mapcampointer->y, ld)) - return true; // don't hit the back side - return false; + return BMIT_CONTINUE; // don't hit the back side + return BMIT_ABORT; } // set openrange, opentop, openbottom @@ -1530,7 +1533,7 @@ static boolean PIT_CheckCameraLine(line_t *ld) if (lowfloor < tmdropoffz) tmdropoffz = lowfloor; - return true; + return BMIT_CONTINUE; } boolean P_IsLineBlocking(const line_t *ld, const mobj_t *thing) @@ -1559,19 +1562,19 @@ boolean P_IsLineTripWire(const line_t *ld) // PIT_CheckLine // Adjusts tmfloorz and tmceilingz as lines are contacted // -static boolean PIT_CheckLine(line_t *ld) +static BlockItReturn_t PIT_CheckLine(line_t *ld) { const fixed_t thingtop = tmthing->z + tmthing->height; if (ld->polyobj && !(ld->polyobj->flags & POF_SOLID)) - return true; + return BMIT_CONTINUE; if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT] || tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) - return true; + return BMIT_CONTINUE; if (P_BoxOnLineSide(tmbbox, ld) != -1) - return true; + return BMIT_CONTINUE; if (tmthing->flags & MF_PAPERCOLLISION) // Caution! Turning whilst up against a wall will get you stuck. You probably shouldn't give the player this flag. { @@ -1580,7 +1583,7 @@ static boolean PIT_CheckLine(line_t *ld) sinradius = FixedMul(tmthing->radius, FINESINE(tmthing->angle>>ANGLETOFINESHIFT)); if (P_PointOnLineSide(tmx - cosradius, tmy - sinradius, ld) == P_PointOnLineSide(tmx + cosradius, tmy + sinradius, ld)) - return true; // the line doesn't cross between collider's start or end + return BMIT_CONTINUE; // the line doesn't cross between collider's start or end #ifdef PAPER_COLLISIONCORRECTION { fixed_t dist; @@ -1616,22 +1619,22 @@ static boolean PIT_CheckLine(line_t *ld) { UINT8 shouldCollide = LUAh_MobjLineCollide(tmthing, blockingline); // checks hook for thing's type if (P_MobjWasRemoved(tmthing)) - return true; // one of them was removed??? + return BMIT_CONTINUE; // one of them was removed??? if (shouldCollide == 1) - return false; // force collide + return BMIT_ABORT; // force collide else if (shouldCollide == 2) - return true; // force no collide + return BMIT_CONTINUE; // force no collide } if (!ld->backsector) // one sided line { if (P_PointOnLineSide(tmthing->x, tmthing->y, ld)) - return true; // don't hit the back side - return false; + return BMIT_CONTINUE; // don't hit the back side + return BMIT_ABORT; } if (P_IsLineBlocking(ld, tmthing)) - return false; + return BMIT_ABORT; // set openrange, opentop, openbottom P_LineOpening(ld, tmthing); @@ -1676,7 +1679,7 @@ static boolean PIT_CheckLine(line_t *ld) add_spechit(ld); } - return true; + return BMIT_CONTINUE; } // ========================================================================= @@ -2322,32 +2325,32 @@ boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam) static mobj_t *stand; static fixed_t standx, standy; -boolean PIT_PushableMoved(mobj_t *thing) +BlockItReturn_t PIT_PushableMoved(mobj_t *thing) { fixed_t blockdist; if (!(thing->flags & MF_SOLID) || (thing->flags & MF_NOGRAVITY)) - return true; // Don't move something non-solid! + return BMIT_CONTINUE; // Don't move something non-solid! // Only pushables are supported... in 2.0. Now players can be moved too! if (!(thing->flags & MF_PUSHABLE || thing->player)) - return true; + return BMIT_CONTINUE; if (thing == stand) - return true; + return BMIT_CONTINUE; blockdist = stand->radius + thing->radius; if (abs(thing->x - stand->x) >= blockdist || abs(thing->y - stand->y) >= blockdist) - return true; // didn't hit it + return BMIT_CONTINUE; // didn't hit it if ((!(stand->eflags & MFE_VERTICALFLIP) && thing->z != stand->z + stand->height + FixedMul(FRACUNIT, stand->scale)) || ((stand->eflags & MFE_VERTICALFLIP) && thing->z + thing->height != stand->z - FixedMul(FRACUNIT, stand->scale))) - return true; // Not standing on top + return BMIT_CONTINUE; // Not standing on top if (!stand->momx && !stand->momy) - return true; + return BMIT_CONTINUE; // Move this guy! if (thing->player) @@ -2396,7 +2399,7 @@ boolean PIT_PushableMoved(mobj_t *thing) thing->momy = stand->momy; thing->momz = stand->momz; } - return true; + return BMIT_CONTINUE; } static boolean P_WaterRunning(mobj_t *thing) @@ -3952,18 +3955,18 @@ static boolean bombsightcheck; // "bombsource" is the creature // that caused the explosion at "bombspot". // -static boolean PIT_RadiusAttack(mobj_t *thing) +static BlockItReturn_t PIT_RadiusAttack(mobj_t *thing) { fixed_t dx, dy, dz, dist; if (thing == bombspot) // ignore the bomb itself (Deton fix) - return true; + return BMIT_CONTINUE; if ((bombdamagetype & DMG_CANTHURTSELF) && bombsource && thing->type == bombsource->type) // ignore the type of guys who dropped the bomb (Jetty-Syn Bomber or Skim can bomb eachother, but not themselves.) - return true; + return BMIT_CONTINUE; if ((thing->flags & (MF_MONITOR|MF_SHOOTABLE)) != MF_SHOOTABLE) - return true; + return BMIT_CONTINUE; dx = abs(thing->x - bombspot->x); dy = abs(thing->y - bombspot->y); @@ -3976,20 +3979,20 @@ static boolean PIT_RadiusAttack(mobj_t *thing) dist = 0; if (dist >= bombdamage) - return true; // out of range + return BMIT_CONTINUE; // out of range if (thing->floorz > bombspot->z && bombspot->ceilingz < thing->z) - return true; + return BMIT_CONTINUE; if (thing->ceilingz < bombspot->z && bombspot->floorz > thing->z) - return true; + return BMIT_CONTINUE; if (!bombsightcheck || P_CheckSight(thing, bombspot)) { // must be in direct path P_DamageMobj(thing, bombspot, bombsource, 1, bombdamagetype); // Tails 01-11-2001 } - return true; + return BMIT_CONTINUE; } // @@ -4623,19 +4626,19 @@ void P_DelPrecipSeclist(mprecipsecnode_t *node) // at this location, so don't bother with checking impassable or // blocking lines. -static inline boolean PIT_GetSectors(line_t *ld) +static inline BlockItReturn_t PIT_GetSectors(line_t *ld) { if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT] || tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) - return true; + return BMIT_CONTINUE; if (P_BoxOnLineSide(tmbbox, ld) != -1) - return true; + return BMIT_CONTINUE; if (ld->polyobj) // line belongs to a polyobject, don't add it - return true; + return BMIT_CONTINUE; // This line crosses through the object. @@ -4654,23 +4657,23 @@ static inline boolean PIT_GetSectors(line_t *ld) if (ld->backsector) sector_list = P_AddSecnode(ld->backsector, tmthing, sector_list); - return true; + return BMIT_CONTINUE; } // Tails 08-25-2002 -static inline boolean PIT_GetPrecipSectors(line_t *ld) +static inline BlockItReturn_t PIT_GetPrecipSectors(line_t *ld) { if (preciptmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || preciptmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT] || preciptmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || preciptmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) - return true; + return BMIT_CONTINUE; if (P_BoxOnLineSide(preciptmbbox, ld) != -1) - return true; + return BMIT_CONTINUE; if (ld->polyobj) // line belongs to a polyobject, don't add it - return true; + return BMIT_CONTINUE; // This line crosses through the object. @@ -4689,7 +4692,7 @@ static inline boolean PIT_GetPrecipSectors(line_t *ld) if (ld->backsector) precipsector_list = P_AddPrecipSecnode(ld->backsector, tmprecipthing, precipsector_list); - return true; + return BMIT_CONTINUE; } // P_CreateSecNodeList alters/creates the sector_list that shows what sectors diff --git a/src/p_maputl.c b/src/p_maputl.c index 555928a3a..37a24267c 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -1096,7 +1096,7 @@ void P_SetPrecipitationThingPosition(precipmobj_t *thing) // to P_BlockLinesIterator, then make one or more calls // to it. // -boolean P_BlockLinesIterator(INT32 x, INT32 y, boolean (*func)(line_t *)) +boolean P_BlockLinesIterator(INT32 x, INT32 y, BlockItReturn_t (*func)(line_t *)) { INT32 offset; const INT32 *list; // Big blockmap @@ -1122,11 +1122,22 @@ boolean P_BlockLinesIterator(INT32 x, INT32 y, boolean (*func)(line_t *)) for (i = 0; i < po->numLines; ++i) { + BlockItReturn_t ret = BMIT_CONTINUE; + if (po->lines[i]->validcount == validcount) // line has been checked continue; + po->lines[i]->validcount = validcount; - if (!func(po->lines[i])) + ret = func(po->lines[i]); + + if (ret == BMIT_ABORT) + { return false; + } + else if (ret == BMIT_STOP) + { + return true; + } } } plink = (polymaplink_t *)(plink->link.next); @@ -1137,15 +1148,24 @@ boolean P_BlockLinesIterator(INT32 x, INT32 y, boolean (*func)(line_t *)) // First index is really empty, so +1 it. for (list = blockmaplump + offset + 1; *list != -1; list++) { + BlockItReturn_t ret = BMIT_CONTINUE; + ld = &lines[*list]; if (ld->validcount == validcount) continue; // Line has already been checked. ld->validcount = validcount; + ret = func(ld); - if (!func(ld)) + if (ret == BMIT_ABORT) + { return false; + } + else if (ret == BMIT_STOP) + { + return true; + } } return true; // Everything was checked. } @@ -1154,7 +1174,7 @@ boolean P_BlockLinesIterator(INT32 x, INT32 y, boolean (*func)(line_t *)) // // P_BlockThingsIterator // -boolean P_BlockThingsIterator(INT32 x, INT32 y, boolean (*func)(mobj_t *)) +boolean P_BlockThingsIterator(INT32 x, INT32 y, BlockItReturn_t (*func)(mobj_t *)) { mobj_t *mobj, *bnext = NULL; @@ -1164,19 +1184,25 @@ boolean P_BlockThingsIterator(INT32 x, INT32 y, boolean (*func)(mobj_t *)) // Check interaction with the objects in the blockmap. for (mobj = blocklinks[y*bmapwidth + x]; mobj; mobj = bnext) { + BlockItReturn_t ret = BMIT_CONTINUE; + P_SetTarget(&bnext, mobj->bnext); // We want to note our reference to bnext here incase it is MF_NOTHINK and gets removed! - if (!func(mobj)) + ret = func(mobj); + + if (ret == BMIT_ABORT) { P_SetTarget(&bnext, NULL); - return false; + return false; // failure } - if (P_MobjWasRemoved(tmthing) // func just popped our tmthing, cannot continue. - || (bnext && P_MobjWasRemoved(bnext))) // func just broke blockmap chain, cannot continue. + + if ((ret == BMIT_STOP) + || (bnext && P_MobjWasRemoved(bnext))) // func just broke blockmap chain, cannot continue. { P_SetTarget(&bnext, NULL); - return true; + return true; // success } } + return true; } @@ -1220,7 +1246,7 @@ static void P_CheckIntercepts(void) // are on opposite sides of the trace. // Returns true if earlyout and a solid line hit. // -static boolean PIT_AddLineIntercepts(line_t *ld) +static BlockItReturn_t PIT_AddLineIntercepts(line_t *ld) { INT32 s1, s2; fixed_t frac; @@ -1243,18 +1269,18 @@ static boolean PIT_AddLineIntercepts(line_t *ld) } if (s1 == s2) - return true; // Line isn't crossed. + return BMIT_CONTINUE; // Line isn't crossed. // Hit the line. P_MakeDivline(ld, &dl); frac = P_InterceptVector(&trace, &dl); if (frac < 0) - return true; // Behind source. + return BMIT_CONTINUE; // Behind source. // Try to take an early out of the check. if (earlyout && frac < FRACUNIT && !ld->backsector) - return false; // stop checking + return BMIT_ABORT; // stop checking P_CheckIntercepts(); @@ -1263,13 +1289,13 @@ static boolean PIT_AddLineIntercepts(line_t *ld) intercept_p->d.line = ld; intercept_p++; - return true; // continue + return BMIT_CONTINUE; // continue } // // PIT_AddThingIntercepts // -static boolean PIT_AddThingIntercepts(mobj_t *thing) +static BlockItReturn_t PIT_AddThingIntercepts(mobj_t *thing) { fixed_t px1, py1, px2, py2, frac; INT32 s1, s2; @@ -1300,7 +1326,7 @@ static boolean PIT_AddThingIntercepts(mobj_t *thing) s2 = P_PointOnDivlineSide(px2, py2, &trace); if (s1 == s2) - return true; // Line isn't crossed. + return BMIT_CONTINUE; // Line isn't crossed. dl.x = px1; dl.y = py1; @@ -1310,7 +1336,7 @@ static boolean PIT_AddThingIntercepts(mobj_t *thing) frac = P_InterceptVector(&trace, &dl); if (frac < 0) - return true; // Behind source. + return BMIT_CONTINUE; // Behind source. P_CheckIntercepts(); @@ -1319,7 +1345,7 @@ static boolean PIT_AddThingIntercepts(mobj_t *thing) intercept_p->d.thing = thing; intercept_p++; - return true; // Keep going. + return BMIT_CONTINUE; // Keep going. } // diff --git a/src/p_maputl.h b/src/p_maputl.h index 43a7fb507..c17ad5d33 100644 --- a/src/p_maputl.h +++ b/src/p_maputl.h @@ -67,8 +67,15 @@ extern INT32 opentoppic, openbottompic; void P_LineOpening(line_t *plinedef, mobj_t *mobj); -boolean P_BlockLinesIterator(INT32 x, INT32 y, boolean(*func)(line_t *)); -boolean P_BlockThingsIterator(INT32 x, INT32 y, boolean(*func)(mobj_t *)); +typedef enum +{ + BMIT_CONTINUE, // Continue blockmap search + BMIT_STOP, // End blockmap search with success + BMIT_ABORT // End blockmap search with failure +} BlockItReturn_t; + +boolean P_BlockLinesIterator(INT32 x, INT32 y, BlockItReturn_t(*func)(line_t *)); +boolean P_BlockThingsIterator(INT32 x, INT32 y, BlockItReturn_t(*func)(mobj_t *)); #define PT_ADDLINES 1 #define PT_ADDTHINGS 2 diff --git a/src/p_spec.c b/src/p_spec.c index b6079e6cf..56e7ae455 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -8390,13 +8390,13 @@ static pusher_t *tmpusher; // pusher structure for blockmap searches * ::tmpusher won't need to be used. * \sa T_Pusher */ -static inline boolean PIT_PushThing(mobj_t *thing) +static inline BlockItReturn_t PIT_PushThing(mobj_t *thing) { if (thing->eflags & MFE_PUSHED) - return false; + return BMIT_ABORT; if (!tmpusher->source) - return false; + return BMIT_ABORT; // Allow this to affect pushable objects at some point? if (thing->player && !(thing->flags & (MF_NOGRAVITY | MF_NOCLIP))) @@ -8416,7 +8416,7 @@ static inline boolean PIT_PushThing(mobj_t *thing) { // Make sure the Z is in range if (thing->z < sz - tmpusher->radius || thing->z > sz + tmpusher->radius) - return false; + return BMIT_ABORT; dist = P_AproxDistance(P_AproxDistance(thing->x - sx, thing->y - sy), thing->z - sz); @@ -8482,7 +8482,7 @@ static inline boolean PIT_PushThing(mobj_t *thing) if (tmpusher->exclusive) thing->eflags |= MFE_PUSHED; - return true; + return BMIT_CONTINUE; } /** Applies a pusher to all affected objects. From 3bc5fac4307d1cf9ac148cbc205df68d17199d88 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Mon, 23 May 2022 16:47:27 -0500 Subject: [PATCH 37/42] Adjust steering lock after successful DI --- src/d_player.h | 2 +- src/k_kart.c | 13 +++++++++++-- src/lua_playerlib.c | 4 ++-- src/p_saveg.c | 2 +- src/p_user.c | 2 +- 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 606415a71..e7e7d348e 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -402,7 +402,7 @@ typedef struct player_s UINT8 justbumped; // Prevent players from endlessly bumping into each other UINT8 tumbleBounces; UINT16 tumbleHeight; // In *mobjscaled* fracunits, or mfu, not raw fu - boolean justDI; // Directional Influence ended, true until letting go of turn + UINT8 justDI; // Turn-lockout timer to briefly prevent unintended turning after DI, resets when actionable or no input boolean flipDI; // Bananas flip the DI direction. Was a bug, but it made bananas much more interesting. SINT8 drift; // (-5 to 5) - Drifting Left or Right, plus a bigger counter = sharper turn diff --git a/src/k_kart.c b/src/k_kart.c index 81374d9c6..1ffa01d18 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -7561,6 +7561,15 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) if (player->instashield) player->instashield--; + if (player->justDI) + { + player->justDI--; + + // return turning if player is fully actionable, no matter when! + if (!player->spinouttimer && player->mo->state != &states[S_KART_SPINOUT]) + player->justDI = 0; + } + if (player->eggmanexplode) { if (player->spectator || (gametype == GT_BATTLE && !player->bumpers)) @@ -8296,7 +8305,7 @@ INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue) return 0; } - if (player->justDI == true) + if (player->justDI > 0) { // No turning until you let go after DI-ing. return 0; @@ -10496,7 +10505,7 @@ void K_HandleDirectionalInfluence(player_t *player) } // DI attempted!! - player->justDI = true; + player->justDI = MAXHITLAGTICS; cmd = &player->cmd; diff --git a/src/lua_playerlib.c b/src/lua_playerlib.c index b4a971d99..4b2bad33d 100644 --- a/src/lua_playerlib.c +++ b/src/lua_playerlib.c @@ -239,7 +239,7 @@ static int player_get(lua_State *L) else if (fastcmp(field,"tumbleHeight")) lua_pushinteger(L, plr->tumbleHeight); else if (fastcmp(field,"justDI")) - lua_pushboolean(L, plr->justDI); + lua_pushinteger(L, plr->justDI); else if (fastcmp(field,"flipDI")) lua_pushboolean(L, plr->flipDI); else if (fastcmp(field,"drift")) @@ -593,7 +593,7 @@ static int player_set(lua_State *L) else if (fastcmp(field,"tumbleHeight")) plr->tumbleHeight = luaL_checkinteger(L, 3); else if (fastcmp(field,"justDI")) - plr->justDI = luaL_checkboolean(L, 3); + plr->justDI = luaL_checkinteger(L, 3); else if (fastcmp(field,"flipDI")) plr->flipDI = luaL_checkboolean(L, 3); else if (fastcmp(field,"drift")) diff --git a/src/p_saveg.c b/src/p_saveg.c index f6819eb9c..e92458710 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -521,7 +521,7 @@ static void P_NetUnArchivePlayers(void) players[i].tumbleBounces = READUINT8(save_p); players[i].tumbleHeight = READUINT16(save_p); - players[i].justDI = (boolean)READUINT8(save_p); + players[i].justDI = READUINT8(save_p); players[i].flipDI = (boolean)READUINT8(save_p); players[i].drift = READSINT8(save_p); diff --git a/src/p_user.c b/src/p_user.c index dbf716925..927dbf018 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2142,7 +2142,7 @@ void P_MovePlayer(player_t *player) if (cmd->turning == 0) { - player->justDI = false; + player->justDI = 0; } // Kart frames From 849dd2926ff50e2c2b314f5b0f8cdc4360ce999c Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Mon, 23 May 2022 16:57:48 -0500 Subject: [PATCH 38/42] Futureproof loss-of-control check --- src/k_kart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index 1ffa01d18..1ee01a9c8 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -7566,7 +7566,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) player->justDI--; // return turning if player is fully actionable, no matter when! - if (!player->spinouttimer && player->mo->state != &states[S_KART_SPINOUT]) + if (!P_PlayerInPain(player)) player->justDI = 0; } From b9ee6d1f4e974fe7f51b2b23bf5db42b7feb76b5 Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 23 May 2022 23:57:18 +0100 Subject: [PATCH 39/42] * Show version/DEVELOP info on the title screen, not the top-level menu (necessary in advance of new-menus). * Add TESTER/HOSTTESTER information to `version` command and title screen DEVELOP info. --- src/d_netcmd.c | 6 +++++- src/f_finale.c | 32 ++++++++++++++++++++++++++++++++ src/m_menu.c | 20 -------------------- 3 files changed, 37 insertions(+), 21 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index c9a030ab8..d7e3a5149 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -4364,7 +4364,11 @@ static void Command_Version_f(void) #endif // DEVELOP build -#ifdef DEVELOP +#if defined(TESTERS) + CONS_Printf("\x88" "TESTERS " "\x80"); +#elif defined(HOSTTESTERS) + CONS_Printf("\x82" "HOSTTESTERS " "\x80"); +#elif defined(DEVELOP) CONS_Printf("\x87" "DEVELOP " "\x80"); #endif diff --git a/src/f_finale.c b/src/f_finale.c index c6596e378..52f2556f4 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -1998,6 +1998,38 @@ void F_TitleScreenDrawer(void) V_DrawFixedPatch(0, 0, FRACUNIT, 0, kts_bumper, NULL); V_DrawFixedPatch(0, 0, FRACUNIT, 0, kts_copyright, NULL); + + // An adapted thing from old menus - most games have version info on the title screen now... + { + INT32 texty = vid.height - 10*vid.dupy; +#define addtext(f, str) {\ + V_DrawThinString(vid.dupx, texty, V_NOSCALESTART|f, str);\ + texty -= 10*vid.dupy;\ +} + if (customversionstring[0] != '\0') + { + addtext(V_ALLOWLOWERCASE, customversionstring); + addtext(0, "Mod version:"); + } + else + { +// Development -- show revision / branch info +#if defined(TESTERS) + addtext(V_ALLOWLOWERCASE|V_SKYMAP, "Tester client"); + addtext(V_ALLOWLOWERCASE|V_TRANSLUCENT, va("%s", compdate)); +#elif defined(HOSTTESTERS) + addtext(V_ALLOWLOWERCASE|V_REDMAP, "Netgame host for testers"); + addtext(V_ALLOWLOWERCASE|V_TRANSLUCENT, va("%s", compdate)); +#elif defined(DEVELOP) + addtext(V_ALLOWLOWERCASE|V_TRANSLUCENT, comprevision); + addtext(V_ALLOWLOWERCASE|V_TRANSLUCENT, compbranch); +#else // Regular build + addtext(V_ALLOWLOWERCASE|V_TRANSLUCENT, va("%s", VERSIONSTRING)); +#endif + } +#undef addtext + } + break; } diff --git a/src/m_menu.c b/src/m_menu.c index 8255e5f35..9a446f8c3 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -3119,26 +3119,6 @@ void M_Drawer(void) M_GetGametypeColor(); currentMenu->drawroutine(); // call current menu Draw routine } - - // Draw version down in corner - // ... but only in the MAIN MENU. I'm a picky bastard. - if (currentMenu == &MainDef) - { - if (customversionstring[0] != '\0') - { - V_DrawThinString(vid.dupx, vid.height - 20*vid.dupy, V_NOSCALESTART|V_TRANSLUCENT, "Mod version:"); - V_DrawThinString(vid.dupx, vid.height - 10*vid.dupy, V_NOSCALESTART|V_TRANSLUCENT|V_ALLOWLOWERCASE, customversionstring); - } - else - { -#ifdef DEVELOP // Development -- show revision / branch info - V_DrawThinString(vid.dupx, vid.height - 20*vid.dupy, V_NOSCALESTART|V_TRANSLUCENT|V_ALLOWLOWERCASE, compbranch); - V_DrawThinString(vid.dupx, vid.height - 10*vid.dupy, V_NOSCALESTART|V_TRANSLUCENT|V_ALLOWLOWERCASE, comprevision); -#else // Regular build - V_DrawThinString(vid.dupx, vid.height - 10*vid.dupy, V_NOSCALESTART|V_TRANSLUCENT|V_ALLOWLOWERCASE, va("%s", VERSIONSTRING)); -#endif - } - } } // focus lost notification goes on top of everything, even the former everything From 052e72c4096eceae6a65f9053e50ce17728b79bb Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 23 May 2022 19:20:21 -0400 Subject: [PATCH 40/42] PIT_CheckThing valid checks more consistent --- src/p_map.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/p_map.c b/src/p_map.c index a64f9d761..473ded5fe 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -530,17 +530,14 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) if (tmthing == NULL || P_MobjWasRemoved(tmthing) == true) return BMIT_STOP; // func just popped our tmthing, cannot continue. + // Ignore... things. + if (thing == NULL || P_MobjWasRemoved(thing) == true) + return BMIT_CONTINUE; + // don't clip against self if (thing == tmthing) return BMIT_CONTINUE; - // Ignore... things. - if (!tmthing || !thing || P_MobjWasRemoved(thing)) - return BMIT_CONTINUE; - - I_Assert(!P_MobjWasRemoved(tmthing)); - I_Assert(!P_MobjWasRemoved(thing)); - // Ignore spectators if ((tmthing->player && tmthing->player->spectator) || (thing->player && thing->player->spectator)) From 0d82b075b0e1b799b22c81b45a7fa967e1efa494 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 24 May 2022 18:09:40 +0100 Subject: [PATCH 41/42] Fix Grow on Trick Panels sending you to ridiculous heights. --- src/k_kart.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index ef94b4721..ade502c07 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -5615,7 +5615,6 @@ static void K_DoShrink(player_t *user) void K_DoPogoSpring(mobj_t *mo, fixed_t vertispeed, UINT8 sound) { - const fixed_t vscale = mapobjectscale + (mo->scale - mapobjectscale); fixed_t thrust = 0; if (mo->player && mo->player->spectator) @@ -5656,7 +5655,7 @@ void K_DoPogoSpring(mobj_t *mo, fixed_t vertispeed, UINT8 sound) //CONS_Printf("Got boost: %d%\n", mo->player->trickboostpower*100 / FRACUNIT); } - mo->momz = FixedMul(thrust, vscale); + mo->momz = FixedMul(thrust, mapobjectscale); if (mo->eflags & MFE_UNDERWATER) { From bf6d257cfb3acaf8173ff6c5787526ebc13fb95f Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 24 May 2022 18:41:13 +0100 Subject: [PATCH 42/42] Prevent rings from suddenly growing in size when a Grow player interacts with them, to match how using rings while grown or shrunk have them at mapobjectscale. --- src/p_enemy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_enemy.c b/src/p_enemy.c index 65f00e116..341c24164 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -4018,7 +4018,7 @@ void A_AttractChase(mobj_t *actor) { fixed_t dist = (4*actor->target->scale) * (16 - actor->extravalue1); - P_SetScale(actor, (actor->destscale = actor->target->scale - ((actor->target->scale/14) * actor->extravalue1))); + P_SetScale(actor, (actor->destscale = mapobjectscale - ((mapobjectscale/14) * actor->extravalue1))); actor->z = actor->target->z; K_MatchGenericExtraFlags(actor, actor->target); P_MoveOrigin(actor,