From c6e7fe2d298bc4841c25d519838f14fc60db9a1e Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 29 Apr 2022 22:02:22 -0700 Subject: [PATCH] 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: