From 13a77581c44c8862eb44f98679bc17deafec514f Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 28 Sep 2022 00:44:50 -0400 Subject: [PATCH] Hyudoro behaves properly without owner set When it's placed by the level, it's given to whoever has the best position at time of stealing. Since this is meant for duels, this means always the other player. This behavior is also used as a default whenever its owner gets unset for whatever reason. If there is literally NO ONE (1P), then rotate in place violently. --- src/objects/hyudoro.c | 116 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 112 insertions(+), 4 deletions(-) diff --git a/src/objects/hyudoro.c b/src/objects/hyudoro.c index c1a2e60a8..3c804cdfc 100644 --- a/src/objects/hyudoro.c +++ b/src/objects/hyudoro.c @@ -1,3 +1,15 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2022 by James R. +// Copyright (C) 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 hyudoro.c +/// \brief Hyudoro item code. + #include "../doomdef.h" #include "../doomstat.h" #include "../info.h" @@ -7,6 +19,7 @@ #include "../p_local.h" #include "../r_main.h" #include "../s_sound.h" +#include "../g_game.h" enum { HYU_PATROL, @@ -39,11 +52,14 @@ K_ChangePlayerItem #define hyudoro_hover_stack(o) ((o)->threshold) #define hyudoro_next(o) ((o)->tracer) #define hyudoro_stackpos(o) ((o)->reactiontime) +#define hyudoro_delivered(o) (hyudoro_itemtype(o) == KITEM_NONE) // cannot be combined #define hyudoro_center(o) ((o)->target) #define hyudoro_target(o) ((o)->target) +#define hyudoro_stolefrom(o) ((o)->hnext) + #define hyudoro_center_max_radius(o) ((o)->threshold) #define hyudoro_center_master(o) ((o)->target) @@ -173,6 +189,82 @@ spawn_hyudoro_shadow (mobj_t *hyu) P_SetTarget(&shadow->tracer, hyu); } +static mobj_t * +find_duel_target (mobj_t *ignore) +{ + mobj_t *ret = NULL; + UINT8 bestPosition = UINT8_MAX; + UINT8 i; + + for (i = 0; i < MAXPLAYERS; i++) + { + player_t *player = NULL; + + if (playeringame[i] == false) + { + continue; + } + + player = &players[i]; + if (player->spectator || player->exiting) + { + continue; + } + + if (!player->mo || P_MobjWasRemoved(player->mo)) + { + continue; + } + + if (ignore != NULL && player->mo == ignore) + { + continue; + } + + if (player->position < bestPosition) + { + ret = player->mo; + bestPosition = player->position; + + if (bestPosition <= 1) + { + // Can't get any lower + break; + } + } + } + + return ret; +} + +static void +do_confused (mobj_t *hyu) +{ + // Hyudoro is confused. + // Spin around, try to find a new target. + const INT32 bob_speed = 32; + + if (hyudoro_delivered(hyu)) + { + // Already delivered, not confused + return; + } + + // Try to find new target + P_SetTarget(&hyudoro_target(hyu), + find_duel_target(hyudoro_stolefrom(hyu))); + + // Spin in circles + hyu->angle += ANGLE_45; + + // Bob very fast + sine_bob(hyu, + (leveltime & (bob_speed - 1)) * + (ANGLE_MAX / bob_speed), -(3*FRACUNIT/4)); + + hyu->sprzoff += hyu->height; +} + static void move_to_player (mobj_t *hyu) { @@ -181,8 +273,11 @@ move_to_player (mobj_t *hyu) angle_t angle; fixed_t speed; - if (!target) + if (!target || P_MobjWasRemoved(target)) + { + do_confused(hyu); return; + } angle = R_PointToAngle2( hyu->x, hyu->y, target->x, target->y); @@ -232,6 +327,9 @@ deliver_item (mobj_t *hyu) hyu->destscale = target->scale / 4; hyu->scalespeed = abs(hyu->scale - hyu->destscale) / hyu->tics; + + // sets as already delivered + hyudoro_itemtype(hyu) = KITEM_NONE; } static void @@ -287,11 +385,14 @@ hyudoro_patrol_hit_player mobj_t *center = hyudoro_center(hyu); + mobj_t *master = NULL; + if (!player) return false; // Cannot hit its master - if (toucher == get_hyudoro_master(hyu)) + master = get_hyudoro_master(hyu); + if (toucher == master) return false; // Don't punish a punished player @@ -313,8 +414,15 @@ hyudoro_patrol_hit_player player->hyudorotimer = hyudorotime; player->stealingtimer = hyudorotime; - P_SetTarget(&hyudoro_target(hyu), - hyudoro_center_master(center)); + P_SetTarget(&hyudoro_stolefrom(hyu), toucher); + + if (master == NULL || P_MobjWasRemoved(master)) + { + // if master is NULL, it is probably a DUEL + master = find_duel_target(toucher); + } + + P_SetTarget(&hyudoro_target(hyu), master); if (center) P_RemoveMobj(center);