From d7be3d3aca6750b9ded5368a80784550747ce611 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 27 Sep 2022 22:43:45 -0400 Subject: [PATCH 01/13] Add Duel objects - Banana, Eggman Items, Proxi Mine, Land Mine, Hyudoro, and Drop Targets are now placeable in maps. - By default, will only appear when in 1v1s. (Extra flag can be checked to enable spawning in all modes.) - Most of these objects will need tweaks to account for being placeable now. --- extras/conf/D3R-Config.cfg | 55 +++++++++++++++++++++++++++++++++++++- src/doomstat.h | 1 + src/g_game.c | 1 + src/info.c | 12 ++++----- src/k_kart.c | 3 +++ src/p_mobj.c | 15 +++++++++++ src/p_saveg.c | 2 ++ 7 files changed, 82 insertions(+), 7 deletions(-) diff --git a/extras/conf/D3R-Config.cfg b/extras/conf/D3R-Config.cfg index 0482dc439..7db8d8d99 100644 --- a/extras/conf/D3R-Config.cfg +++ b/extras/conf/D3R-Config.cfg @@ -139,7 +139,7 @@ skins // Gametypes gametypes { - -1 = "Single Player"; + -1 = "Grand Prix"; 0 = "Race"; 1 = "Battle"; } @@ -5113,6 +5113,7 @@ thingtypes height = 92; } } + waypoints { color = 4; // Red @@ -5161,6 +5162,58 @@ thingtypes fixedrotation = 1; } } + + duel + { + color = 4; // Red + arrow = 1; + title = "Duel-Only"; + sprite = "SPBMA2A8"; + width = 16; + height = 32; + flags1text = "[1] Spawn in all modes"; + + 2050 + { + title = "Duel Bomb"; + } + + 2051 + { + title = "Banana"; + sprite = "BANAA2A8"; + } + + 2052 + { + title = "Eggman Item"; + sprite = "FITMA0"; + } + + 2053 + { + title = "Proximity Mine"; + sprite = "SSMNA0"; + } + + 2054 + { + title = "Land Mine"; + sprite = "LNDMA0"; + } + + 2055 + { + title = "Hyudoro"; + sprite = "HYUUA2A8"; + } + + 2056 + { + title = "Drop Target"; + sprite = "DTRGA0"; + } + } } //Default things filters diff --git a/src/doomstat.h b/src/doomstat.h index dc6370ece..dc94ed0e6 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -669,6 +669,7 @@ extern boolean thwompsactive; extern UINT8 lastLowestLap; extern SINT8 spbplace; extern boolean rainbowstartavailable; +extern boolean inDuel; extern tic_t bombflashtimer; // Used to avoid causing seizures if multiple mines explode close to you :) extern boolean legitimateexit; diff --git a/src/g_game.c b/src/g_game.c index 181aa0697..3e6d3108d 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -312,6 +312,7 @@ boolean thwompsactive; // Thwomps activate on lap 2 UINT8 lastLowestLap; // Last lowest lap, for activating race lap executors SINT8 spbplace; // SPB exists, give the person behind better items boolean rainbowstartavailable; // Boolean, keeps track of if the rainbow start was gotten +boolean inDuel; // Boolean, keeps track of if it is a 1v1 // Client-sided, unsynched variables (NEVER use in anything that needs to be synced with other players) tic_t bombflashtimer = 0; // Cooldown before another FlashPal can be intialized by a bomb exploding near a displayplayer. Avoids seizures. diff --git a/src/info.c b/src/info.c index a5fe03bf2..1d95ad000 100644 --- a/src/info.c +++ b/src/info.c @@ -23310,7 +23310,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_EGGMANITEM - -1, // doomednum + 2052, // doomednum S_EGGMANITEM1, // spawnstate 2, // spawnhealth S_NULL, // seestate @@ -23364,7 +23364,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_BANANA - -1, // doomednum + 2051, // doomednum S_BANANA, // spawnstate 2, // spawnhealth S_NULL, // seestate @@ -23553,7 +23553,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_SSMINE - -1, // doomednum + 2053, // doomednum S_SSMINE_AIR1, // spawnstate 1, // spawnhealth S_NULL, // seestate @@ -23688,7 +23688,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_LANDMINE - -1, // doomednum + 2054, // doomednum S_LANDMINE, // spawnstate 2, // spawnhealth S_NULL, // seestate @@ -23715,7 +23715,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_DROPTARGET - -1, // doomednum + 2056, // doomednum S_DROPTARGET, // spawnstate 3, // spawnhealth S_NULL, // seestate @@ -24066,7 +24066,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_HYUDORO - -1, // doomednum + 2055, // doomednum S_HYUDORO, // spawnstate 1000, // spawnhealth S_NULL, // seestate diff --git a/src/k_kart.c b/src/k_kart.c index 5aa1aaeba..0b391d94d 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -78,6 +78,9 @@ void K_TimerInit(void) numPlayers++; } + // 1v1 activates DUEL rules! + inDuel = (numPlayers == 2); + if (numPlayers >= 2) { rainbowstartavailable = true; diff --git a/src/p_mobj.c b/src/p_mobj.c index 9b08f0e75..4006d399d 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11548,6 +11548,21 @@ static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i) return false; } break; + //case MT_DUELBOMB: + case MT_BANANA: + case MT_EGGMANITEM: + case MT_SSMINE: + case MT_LANDMINE: + case MT_HYUDORO: + case MT_DROPTARGET: + { + // Duel objects. + // Normally only spawn when placed by the map in Duels, + // but can be forced to always spawn with the Extra flag. + if (inDuel == false && !(mthing->options & MTF_EXTRA)) + return false; + } + break; default: break; } diff --git a/src/p_saveg.c b/src/p_saveg.c index 233056f21..d050da4b1 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -4576,6 +4576,7 @@ static void P_NetArchiveMisc(boolean resending) WRITEUINT8(save_p, lastLowestLap); WRITESINT8(save_p, spbplace); WRITEUINT8(save_p, rainbowstartavailable); + WRITEUINT8(save_p, inDuel); WRITEUINT32(save_p, introtime); WRITEUINT32(save_p, starttime); @@ -4733,6 +4734,7 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading) lastLowestLap = READUINT8(save_p); spbplace = READSINT8(save_p); rainbowstartavailable = (boolean)READUINT8(save_p); + inDuel = (boolean)READUINT8(save_p); introtime = READUINT32(save_p); starttime = READUINT32(save_p); From aa7c7df27cd197dd869d1477157be737ac4adff1 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 27 Sep 2022 22:55:35 -0400 Subject: [PATCH 02/13] Give Landmines a default color --- src/p_mobj.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/p_mobj.c b/src/p_mobj.c index 4006d399d..cf8856301 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6843,6 +6843,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj) case MT_LANDMINE: mobj->friction = ORIG_FRICTION/4; + if (mobj->target && mobj->target->player) + mobj->color = mobj->target->player->skincolor; + else + mobj->color = SKINCOLOR_SAPPHIRE; + if (mobj->momx || mobj->momy || mobj->momz) { mobj_t *ghost = P_SpawnGhostMobj(mobj); From c22d652add2c6aafa486c40750d6cae94d84cf97 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 27 Sep 2022 23:04:38 -0400 Subject: [PATCH 03/13] Give map-placed bananas a random angle --- src/p_mobj.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/p_mobj.c b/src/p_mobj.c index cf8856301..ef97d82b6 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -12734,6 +12734,14 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean // Increment no. of capsules on the map counter maptargets++; + break; + } + case MT_BANANA: + { + // Give Duel bananas a random angle + mobj->angle = FixedMul(P_RandomFixed(PR_DECORATION), ANGLE_MAX); + *doangle = false; + break; } default: break; From 456c824abfbff0fae911a05dbdbbb47f38354d90 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 27 Sep 2022 23:29:06 -0400 Subject: [PATCH 04/13] Init Hyudoro center properly --- src/info.c | 4 ++-- src/k_objects.h | 1 + src/objects/hyudoro.c | 19 +++++++++++++------ src/p_mobj.c | 7 ++++++- 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/info.c b/src/info.c index 1d95ad000..dd93bf376 100644 --- a/src/info.c +++ b/src/info.c @@ -24066,7 +24066,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_HYUDORO - 2055, // doomednum + -1, // doomednum S_HYUDORO, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -24093,7 +24093,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_HYUDORO_CENTER - -1, // doomednum + 2055, // doomednum S_INVISIBLE, // spawnstate 1000, // spawnhealth S_NULL, // seestate diff --git a/src/k_objects.h b/src/k_objects.h index 7679db658..7351465d6 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -3,6 +3,7 @@ #define k_objects_H /* Hyudoro */ +void Obj_InitHyudoroCenter(mobj_t *center, mobj_t *master); void Obj_HyudoroDeploy(mobj_t *master); void Obj_HyudoroThink(mobj_t *actor); void Obj_HyudoroCenterThink(mobj_t *actor); diff --git a/src/objects/hyudoro.c b/src/objects/hyudoro.c index 0a362aa89..c1a2e60a8 100644 --- a/src/objects/hyudoro.c +++ b/src/objects/hyudoro.c @@ -388,11 +388,8 @@ hyudoro_hover_await_stack (mobj_t *hyu) } void -Obj_HyudoroDeploy (mobj_t *master) +Obj_InitHyudoroCenter (mobj_t * center, 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); @@ -405,20 +402,30 @@ Obj_HyudoroDeploy (mobj_t *master) center->radius = hyu->radius; - P_InitAngle(hyu, master->angle); + P_InitAngle(hyu, center->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) + if (master && !P_MobjWasRemoved(master) && master->player) { hyu->renderflags |= RF_DONTDRAW & ~(K_GetPlayerDontDrawFlag(master->player)); } spawn_hyudoro_shadow(hyu); // this sucks btw +} + +void +Obj_HyudoroDeploy (mobj_t *master) +{ + mobj_t *center = P_SpawnMobjFromMobj( + master, 0, 0, 0, MT_HYUDORO_CENTER); + + center->angle = master->angle; + Obj_InitHyudoroCenter(center, master); S_StartSound(master, sfx_s3k92); // scary ghost noise } diff --git a/src/p_mobj.c b/src/p_mobj.c index ef97d82b6..ad280040c 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11558,7 +11558,7 @@ static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i) case MT_EGGMANITEM: case MT_SSMINE: case MT_LANDMINE: - case MT_HYUDORO: + case MT_HYUDORO_CENTER: case MT_DROPTARGET: { // Duel objects. @@ -12743,6 +12743,11 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean *doangle = false; break; } + case MT_HYUDORO_CENTER: + { + Obj_InitHyudoroCenter(mobj, NULL); + break; + } default: break; } From 13a77581c44c8862eb44f98679bc17deafec514f Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 28 Sep 2022 00:44:50 -0400 Subject: [PATCH 05/13] 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); From f9c4f66931808a96b05d203eaf0905d51837f484 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 28 Sep 2022 01:47:56 -0400 Subject: [PATCH 06/13] Add duel bomb objects Basically a landmine, but strafes back and forth. Currently uses SPB sprites, IDK if we'll end up replacing it later. --- extras/conf/D3R-Config.cfg | 51 ++++++++------------ src/deh_tables.c | 2 + src/info.c | 27 +++++++++++ src/info.h | 2 + src/k_botsearch.c | 1 + src/k_kart.c | 1 + src/k_objects.h | 6 +++ src/objects/Sourcefile | 1 + src/objects/duel-bomb.c | 98 ++++++++++++++++++++++++++++++++++++++ src/p_inter.c | 5 ++ src/p_mobj.c | 32 ++++++++++--- 11 files changed, 188 insertions(+), 38 deletions(-) create mode 100644 src/objects/duel-bomb.c diff --git a/extras/conf/D3R-Config.cfg b/extras/conf/D3R-Config.cfg index 7db8d8d99..862fb0cf3 100644 --- a/extras/conf/D3R-Config.cfg +++ b/extras/conf/D3R-Config.cfg @@ -5167,51 +5167,64 @@ thingtypes { color = 4; // Red arrow = 1; - title = "Duel-Only"; + title = "Duel Objects"; sprite = "SPBMA2A8"; - width = 16; - height = 32; + width = 24; + height = 48; flags1text = "[1] Spawn in all modes"; 2050 { title = "Duel Bomb"; + flags8text = "[8] Flip strafe"; } 2051 { title = "Banana"; sprite = "BANAA2A8"; + width = 16; + height = 32; } 2052 { title = "Eggman Item"; sprite = "FITMA0"; + width = 24; + height = 32; } 2053 { title = "Proximity Mine"; sprite = "SSMNA0"; + width = 16; + height = 24; } 2054 { title = "Land Mine"; - sprite = "LNDMA0"; + sprite = "LNDMALAR"; + width = 24; + height = 32; } 2055 { title = "Hyudoro"; sprite = "HYUUA2A8"; + width = 32; + height = 24; } 2056 { title = "Drop Target"; - sprite = "DTRGA0"; + sprite = "DTRGALAR"; + width = 45; + height = 32; } } } @@ -5236,24 +5249,6 @@ thingsfilters } filter2 - { - name = "Enemies"; - category = "enemies"; - type = -1; - - } - - - filter3 - { - name = "NiGHTS Track"; - category = "nightstrk"; - type = -1; - - } - - - filter4 { name = "Normal Gravity"; category = ""; @@ -5266,8 +5261,7 @@ thingsfilters } - - filter5 + filter3 { name = "Reverse Gravity"; category = ""; @@ -5279,11 +5273,4 @@ thingsfilters } } - - filter6 - { - name = "Boss Waypoints"; - category = ""; - type = 292; - } } diff --git a/src/deh_tables.c b/src/deh_tables.c index a0084ec85..a0d4e55bd 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -5362,6 +5362,8 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_SINK_SHIELD", "MT_SINKTRAIL", + "MT_DUELBOMB", // Duel mode bombs + "MT_BATTLEBUMPER", // Battle Mode bumper "MT_BATTLEBUMPER_DEBRIS", "MT_BATTLEBUMPER_BLAST", diff --git a/src/info.c b/src/info.c index dd93bf376..b05a20abc 100644 --- a/src/info.c +++ b/src/info.c @@ -24362,6 +24362,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_DUELBOMB + 2050, // doomednum + S_SPB1, // 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 + 64*FRACUNIT, // speed + 24*FRACUNIT, // radius + 48*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_SPECIAL|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags + S_NULL // raisestate + }, + { // MT_BATTLEBUMPER -1, // doomednum S_BATTLEBUMPER1,// spawnstate diff --git a/src/info.h b/src/info.h index 29e2695bf..e40ea51ee 100644 --- a/src/info.h +++ b/src/info.h @@ -6408,6 +6408,8 @@ typedef enum mobj_type MT_SINK_SHIELD, MT_SINKTRAIL, + MT_DUELBOMB, // Duel mode bombs + MT_BATTLEBUMPER, // Battle Mode bumpers MT_BATTLEBUMPER_DEBRIS, MT_BATTLEBUMPER_BLAST, diff --git a/src/k_botsearch.c b/src/k_botsearch.c index 5b6f1ccca..48c5745fd 100644 --- a/src/k_botsearch.c +++ b/src/k_botsearch.c @@ -422,6 +422,7 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing) case MT_BALLHOG: case MT_SPB: case MT_BUBBLESHIELDTRAP: + case MT_DUELBOMB: K_AddDodgeObject(thing, side, 20); break; case MT_SHRINK_GUN: diff --git a/src/k_kart.c b/src/k_kart.c index 0b391d94d..44f7501fb 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -1419,6 +1419,7 @@ fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against) break; case MT_ORBINAUT: case MT_ORBINAUT_SHIELD: + case MT_DUELBOMB: if (against->player) weight = K_PlayerWeight(against, NULL); break; diff --git a/src/k_objects.h b/src/k_objects.h index 7351465d6..be287c0f4 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -40,4 +40,10 @@ void Obj_OrbinautJawzMoveHeld(player_t *player); void Obj_JawzThink(mobj_t *th); void Obj_JawzThrown(mobj_t *th, fixed_t finalSpeed, SINT8 dir); +/* Duel Bomb */ +void Obj_DuelBombThink(mobj_t *bomb); +void Obj_DuelBombReverse(mobj_t *bomb); +void Obj_DuelBombTouch(mobj_t *bomb, mobj_t *toucher); +void Obj_DuelBombInit(mobj_t *bomb); + #endif/*k_objects_H*/ diff --git a/src/objects/Sourcefile b/src/objects/Sourcefile index 339175b0c..d768232c5 100644 --- a/src/objects/Sourcefile +++ b/src/objects/Sourcefile @@ -5,3 +5,4 @@ spb.c manta-ring.c orbinaut.c jawz.c +duel-bomb.c diff --git a/src/objects/duel-bomb.c b/src/objects/duel-bomb.c new file mode 100644 index 000000000..ace75f3b2 --- /dev/null +++ b/src/objects/duel-bomb.c @@ -0,0 +1,98 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2022 by Sally "TehRealSalt" Cochenour +// 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 duel-bomb.c +/// \brief Duel mode bombs. + +#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" +#include "../g_game.h" +#include "../z_zone.h" +#include "../k_waypoint.h" +#include "../k_respawn.h" +#include "../k_collide.h" + +#define bomb_dir(o) ((o)->movedir) + +static fixed_t GetBombSpeed(mobj_t *bomb) +{ + return FixedMul(bomb->info->speed, bomb->scale); +} + +static void UpdateBombMovement(mobj_t *bomb) +{ + const fixed_t spd = GetBombSpeed(bomb); + bomb->momx = FixedMul(spd, FINECOSINE(bomb_dir(bomb) >> ANGLETOFINESHIFT)); + bomb->momy = FixedMul(spd, FINESINE(bomb_dir(bomb) >> ANGLETOFINESHIFT)); +} + +void Obj_DuelBombThink(mobj_t *bomb) +{ + boolean grounded = P_IsObjectOnGround(bomb); + + if (grounded == true) + { + UpdateBombMovement(bomb); + } +} + +void Obj_DuelBombReverse(mobj_t *bomb) +{ + bomb_dir(bomb) += ANGLE_180; + UpdateBombMovement(bomb); +} + +void Obj_DuelBombTouch(mobj_t *bomb, mobj_t *toucher) +{ + player_t *player = toucher->player; + mobj_t *boom = NULL; + + if (bomb->health <= 0 || toucher->health <= 0) + { + return; + } + + if (player->flashing > 0 || player->hyudorotimer > 0 || P_PlayerInPain(player)) + { + // No interaction + return; + } + + // Create explosion + boom = P_SpawnMobjFromMobj(bomb, 0, 0, 0, MT_BOOMEXPLODE); + boom->momz = 5 * boom->scale; + boom->color = SKINCOLOR_KETCHUP; + S_StartSound(boom, bomb->info->attacksound); + + // Kill bomb + P_KillMobj(bomb, toucher, toucher, DMG_NORMAL); + + if (player->invincibilitytimer > 0 + || K_IsBigger(toucher, bomb) == true + || player->flamedash > 0) + { + // Kill without damaging. + return; + } + + P_DamageMobj(toucher, bomb, bomb, 1, DMG_TUMBLE); +} + +void Obj_DuelBombInit(mobj_t *bomb) +{ + bomb_dir(bomb) = bomb->angle + ANGLE_90; + UpdateBombMovement(bomb); +} diff --git a/src/p_inter.c b/src/p_inter.c index 19f03c664..bbfa804be 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -356,6 +356,11 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) Obj_SPBTouch(special, toucher); return; } + case MT_DUELBOMB: + { + Obj_DuelBombTouch(special, toucher); + return; + } case MT_EMERALD: if (!P_CanPickupItem(player, 0)) return; diff --git a/src/p_mobj.c b/src/p_mobj.c index ad280040c..5b9ea4c75 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1720,7 +1720,8 @@ void P_XYMovement(mobj_t *mo) //{ SRB2kart - Orbinaut, Ballhog // Bump sparks - if (mo->type == MT_ORBINAUT || mo->type == MT_BALLHOG) + if (mo->type == MT_ORBINAUT || mo->type == MT_BALLHOG + || mo->type == MT_DUELBOMB) { mobj_t *fx; fx = P_SpawnMobj(mo->x, mo->y, mo->z, MT_BUMP); @@ -1754,13 +1755,17 @@ void P_XYMovement(mobj_t *mo) } break; + case MT_BUBBLESHIELDTRAP: + S_StartSound(mo, sfx_s3k44); // Bubble bounce + break; + + case MT_DUELBOMB: + Obj_DuelBombReverse(mo); + break; + default: break; } - - // Bubble bounce - if (mo->type == MT_BUBBLESHIELDTRAP) - S_StartSound(mo, sfx_s3k44); } } } @@ -2190,6 +2195,7 @@ boolean P_ZMovement(mobj_t *mo) case MT_LANDMINE: case MT_DROPTARGET: case MT_BUBBLESHIELDTRAP: + case MT_DUELBOMB: // Remove stuff from death pits. if (P_CheckDeathPitCollide(mo)) { @@ -6906,6 +6912,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj) case MT_SPBEXPLOSION: mobj->health--; break; + case MT_DUELBOMB: + { + Obj_DuelBombThink(mobj); + break; + } case MT_EMERALD: { if (battleovertime.enabled >= 10*TICRATE) @@ -9708,6 +9719,7 @@ static void P_DefaultMobjShadowScale(mobj_t *thing) case MT_SINK: case MT_ROCKETSNEAKER: case MT_SPB: + case MT_DUELBOMB: thing->shadowscale = 3*FRACUNIT/2; break; case MT_BANANA_SHIELD: @@ -10317,6 +10329,9 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) // Remove before release CONS_Alert(CONS_WARNING, "Boss waypoints are deprecated. Did you forget to remove the old checkpoints, too?\n"); break; + case MT_DUELBOMB: + Obj_DuelBombInit(mobj); + break; default: break; } @@ -11553,7 +11568,7 @@ static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i) return false; } break; - //case MT_DUELBOMB: + case MT_DUELBOMB: case MT_BANANA: case MT_EGGMANITEM: case MT_SSMINE: @@ -12787,6 +12802,11 @@ static void P_SetAmbush(mobj_t *mobj) mobj->type != MT_NIGHTSBUMPER && mobj->type != MT_STARPOST) mobj->flags2 |= MF2_AMBUSH; + + if (mobj->type == MT_DUELBOMB) + { + Obj_DuelBombReverse(mobj); + } } static void P_SetObjectSpecial(mobj_t *mobj) From 1744da37915ac5a202ae981e5e1fc1b5aa4b8d63 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 28 Sep 2022 01:56:58 -0400 Subject: [PATCH 07/13] Don't respawn items boxes in duels --- src/p_inter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_inter.c b/src/p_inter.c index bbfa804be..d9950aa89 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1017,7 +1017,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget { target->fuse = 2; } - else + else if (inDuel == false) { UINT8 i; From 0fb60afb97e1b9f4c88bc0b9a742e874889858a3 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 28 Sep 2022 02:11:45 -0400 Subject: [PATCH 08/13] Make Duel Hyudoro invisible by default --- src/objects/hyudoro.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/objects/hyudoro.c b/src/objects/hyudoro.c index 3c804cdfc..07147deca 100644 --- a/src/objects/hyudoro.c +++ b/src/objects/hyudoro.c @@ -517,10 +517,10 @@ Obj_InitHyudoroCenter (mobj_t * center, mobj_t * master) hyudoro_mode(hyu) = HYU_PATROL; // Set splitscreen player visibility + hyu->renderflags |= RF_DONTDRAW; if (master && !P_MobjWasRemoved(master) && master->player) { - hyu->renderflags |= RF_DONTDRAW & - ~(K_GetPlayerDontDrawFlag(master->player)); + hyu->renderflags &= ~(K_GetPlayerDontDrawFlag(master->player)); } spawn_hyudoro_shadow(hyu); // this sucks btw From 70a231f11595c9f605956bc2fe5192416c368132 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 28 Sep 2022 02:37:01 -0400 Subject: [PATCH 09/13] Add Pogo Spring as a duel item --- extras/conf/D3R-Config.cfg | 15 ++++++++++++--- src/info.c | 2 +- src/p_mobj.c | 7 +++++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/extras/conf/D3R-Config.cfg b/extras/conf/D3R-Config.cfg index 862fb0cf3..dac4b0135 100644 --- a/extras/conf/D3R-Config.cfg +++ b/extras/conf/D3R-Config.cfg @@ -5166,16 +5166,17 @@ thingtypes duel { color = 4; // Red - arrow = 1; + arrow = 0; title = "Duel Objects"; sprite = "SPBMA2A8"; - width = 24; - height = 48; flags1text = "[1] Spawn in all modes"; 2050 { title = "Duel Bomb"; + width = 24; + height = 48; + arrow = 1; flags8text = "[8] Flip strafe"; } @@ -5226,6 +5227,14 @@ thingtypes width = 45; height = 32; } + + 2057 + { + title = "Pogo Spring"; + sprite = "POGSA0"; + width = 48; + height = 32; + } } } diff --git a/src/info.c b/src/info.c index b05a20abc..7bdffe11d 100644 --- a/src/info.c +++ b/src/info.c @@ -8308,7 +8308,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = }, { // MT_POGOSPRING - -1, // doomednum + 2057, // doomednum S_POGOSPRING1, // spawnstate 1000, // spawnhealth S_POGOSPRING2B, // seestate diff --git a/src/p_mobj.c b/src/p_mobj.c index 5b9ea4c75..6e699cbf5 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11575,6 +11575,7 @@ static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i) case MT_LANDMINE: case MT_HYUDORO_CENTER: case MT_DROPTARGET: + case MT_POGOSPRING: { // Duel objects. // Normally only spawn when placed by the map in Duels, @@ -12763,6 +12764,12 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean Obj_InitHyudoroCenter(mobj, NULL); break; } + case MT_POGOSPRING: + { + // Start as tumble version. + mobj->reactiontime++; + break; + } default: break; } From 4549ec5334b8bd7db8e22f91413704979c2914f7 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 28 Sep 2022 03:07:46 -0400 Subject: [PATCH 10/13] Fix duel bomb direction not working --- src/p_mobj.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 6e699cbf5..c7dcac8ff 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1703,7 +1703,13 @@ void P_XYMovement(mobj_t *mo) if (walltransferred == false) { - if (mo->flags & MF_SLIDEME) + if (mo->type == MT_DUELBOMB) + { + P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_BUMP); + Obj_DuelBombReverse(mo); + xmove = ymove = 0; + } + else if (mo->flags & MF_SLIDEME) { P_SlideMove(mo); if (P_MobjWasRemoved(mo)) @@ -1759,10 +1765,6 @@ void P_XYMovement(mobj_t *mo) S_StartSound(mo, sfx_s3k44); // Bubble bounce break; - case MT_DUELBOMB: - Obj_DuelBombReverse(mo); - break; - default: break; } @@ -10329,9 +10331,6 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) // Remove before release CONS_Alert(CONS_WARNING, "Boss waypoints are deprecated. Did you forget to remove the old checkpoints, too?\n"); break; - case MT_DUELBOMB: - Obj_DuelBombInit(mobj); - break; default: break; } @@ -12752,6 +12751,14 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean maptargets++; break; } + case MT_DUELBOMB: + { + // Duel Bomb needs init to match real map thing's angle + mobj->angle = FixedAngle(mthing->angle << FRACBITS); + Obj_DuelBombInit(mobj); + *doangle = false; + break; + } case MT_BANANA: { // Give Duel bananas a random angle From 4404d0c0980bc9002c108a9fbf774b50a798bff3 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 1 Oct 2022 22:23:52 -0400 Subject: [PATCH 11/13] Make hyu bob a static func --- src/objects/hyudoro.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/objects/hyudoro.c b/src/objects/hyudoro.c index 07147deca..21a5b8cc0 100644 --- a/src/objects/hyudoro.c +++ b/src/objects/hyudoro.c @@ -117,6 +117,16 @@ sine_bob sineofs + FINESINE(a >> ANGLETOFINESHIFT)); } +static void +bob_in_place +( mobj_t * hyu, + INT32 bob_speed) +{ + sine_bob(hyu, + (leveltime & (bob_speed - 1)) * + (ANGLE_MAX / bob_speed), -(3*FRACUNIT/4)); +} + static void project_hyudoro (mobj_t *hyu) { @@ -143,8 +153,6 @@ project_hyudoro (mobj_t *hyu) 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 @@ -170,9 +178,7 @@ project_hyudoro_hover (mobj_t *hyu) hyu->pitch = target->pitch; hyu->roll = target->roll; - sine_bob(hyu, - (leveltime & (bob_speed - 1)) * - (ANGLE_MAX / bob_speed), -(3*FRACUNIT/4)); + bob_in_place(hyu, 64); } static void @@ -242,7 +248,6 @@ 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)) { @@ -258,9 +263,7 @@ do_confused (mobj_t *hyu) hyu->angle += ANGLE_45; // Bob very fast - sine_bob(hyu, - (leveltime & (bob_speed - 1)) * - (ANGLE_MAX / bob_speed), -(3*FRACUNIT/4)); + bob_in_place(hyu, 32); hyu->sprzoff += hyu->height; } From bf6439731ccc41f4fc7b60e3afe75db63a0b7bc3 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 1 Oct 2022 22:28:33 -0400 Subject: [PATCH 12/13] Fix Duel Bomb tumble not scaling --- src/objects/duel-bomb.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/objects/duel-bomb.c b/src/objects/duel-bomb.c index ace75f3b2..173efb933 100644 --- a/src/objects/duel-bomb.c +++ b/src/objects/duel-bomb.c @@ -77,18 +77,17 @@ void Obj_DuelBombTouch(mobj_t *bomb, mobj_t *toucher) boom->color = SKINCOLOR_KETCHUP; S_StartSound(boom, bomb->info->attacksound); - // Kill bomb - P_KillMobj(bomb, toucher, toucher, DMG_NORMAL); - if (player->invincibilitytimer > 0 || K_IsBigger(toucher, bomb) == true || player->flamedash > 0) { // Kill without damaging. + P_KillMobj(bomb, toucher, toucher, DMG_NORMAL); return; } P_DamageMobj(toucher, bomb, bomb, 1, DMG_TUMBLE); + P_KillMobj(bomb, toucher, toucher, DMG_NORMAL); } void Obj_DuelBombInit(mobj_t *bomb) From 7b7cbbbf26c39a68a551af7a852c2884bec25aaa Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 1 Oct 2022 22:58:58 -0400 Subject: [PATCH 13/13] Fix oddities with duel items not always spawning --- src/k_kart.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ src/k_kart.h | 3 +++ src/p_mobj.c | 28 ++++++++++++---------------- 3 files changed, 64 insertions(+), 16 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 66432ad54..645aee529 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -49,10 +49,53 @@ // battlewanted is an array of the WANTED player nums, -1 for no player in that slot // mapreset is set when enough players fill an empty server +boolean K_IsDuelItem(mobjtype_t type) +{ + switch (type) + { + case MT_DUELBOMB: + case MT_BANANA: + case MT_EGGMANITEM: + case MT_SSMINE: + case MT_LANDMINE: + case MT_HYUDORO_CENTER: + case MT_DROPTARGET: + case MT_POGOSPRING: + return true; + + default: + return false; + } +} + +boolean K_DuelItemAlwaysSpawns(mapthing_t *mt) +{ + return (mt->options & MTF_EXTRA); +} + +static void K_SpawnDuelOnlyItems(void) +{ + mapthing_t *mt = NULL; + size_t i; + + mt = mapthings; + for (i = 0; i < nummapthings; i++, mt++) + { + mobjtype_t type = P_GetMobjtype(mt->type); + + if (K_IsDuelItem(type) == true + && K_DuelItemAlwaysSpawns(mt) == false) + { + P_SpawnMapThing(mt); + } + } +} + void K_TimerReset(void) { starttime = introtime = 3; numbulbs = 1; + inDuel = false; } void K_TimerInit(void) @@ -109,6 +152,12 @@ void K_TimerInit(void) // NOW you can try to spawn in the Battle capsules, if there's not enough players for a match K_BattleInit(); + + if (inDuel == true) + { + K_SpawnDuelOnlyItems(); + } + //CONS_Printf("numbulbs set to %d (%d players, %d spectators) on tic %d\n", numbulbs, numPlayers, numspec, leveltime); } diff --git a/src/k_kart.h b/src/k_kart.h index 7973a236c..a5d2b0185 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -38,6 +38,9 @@ angle_t K_ReflectAngle(angle_t angle, angle_t against, fixed_t maxspeed, fixed_t void K_RegisterKartStuff(void); +boolean K_IsDuelItem(mobjtype_t type); +boolean K_DuelItemAlwaysSpawns(mapthing_t *mt); + void K_TimerReset(void); void K_TimerInit(void); UINT32 K_GetPlayerDontDrawFlag(player_t *player); diff --git a/src/p_mobj.c b/src/p_mobj.c index c3e8795b6..12a484218 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11755,30 +11755,26 @@ static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i) return false; } break; - case MT_DUELBOMB: - case MT_BANANA: - case MT_EGGMANITEM: - case MT_SSMINE: - case MT_LANDMINE: - case MT_HYUDORO_CENTER: - case MT_DROPTARGET: - case MT_POGOSPRING: - { - // Duel objects. - // Normally only spawn when placed by the map in Duels, - // but can be forced to always spawn with the Extra flag. - if (inDuel == false && !(mthing->options & MTF_EXTRA)) - return false; - } - break; default: break; } + if (inDuel == false) + { + if (K_IsDuelItem(i) == true + && K_DuelItemAlwaysSpawns(mthing) == false) + { + // Only spawns in Duels. + return false; + } + } + // No bosses outside of a combat situation. // (just in case we want boss arenas to do double duty as battle maps) if (!bossinfo.boss && (mobjinfo[i].flags & MF_BOSS)) + { return false; + } if (metalrecording) // Metal Sonic can't use these things. {