diff --git a/src/deh_tables.c b/src/deh_tables.c index 7a730b6ce..1d8d4eaec 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -1194,6 +1194,9 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi // Spray Can "S_SPRAYCAN", + // Ancient Shrine + "S_ANCIENTSHRINE", + // Chaos Emeralds "S_CHAOSEMERALD1", "S_CHAOSEMERALD2", @@ -4803,6 +4806,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_BLUEFLAG", // Blue CTF Flag "MT_EMBLEM", "MT_SPRAYCAN", + "MT_ANCIENTSHRINE", "MT_EMERALD", "MT_EMERALDSPARK", "MT_EMERALDFLARE", diff --git a/src/info.c b/src/info.c index 0a311d369..1121a075f 100644 --- a/src/info.c +++ b/src/info.c @@ -143,6 +143,8 @@ char sprnames[NUMSPRITES + 1][5] = "NCHP", // NiGHTS chip "NSTR", // NiGHTS star "EMBM", // Emblem + "SPCN", // Spray Can + "MMSH", // Ancient Shrine "EMRC", // Chaos Emeralds "SEMR", // Super Emeralds "ESPK", @@ -635,7 +637,6 @@ char sprnames[NUMSPRITES + 1][5] = "POKE", // Pokey "AUDI", // Audience members "DECO", // Old 1.0 Kart Decoratives + New misc ones - "SPCN", // Spray Can replaces all the old D00Dkart objects "SNES", // Sprites for SNES remake maps "GBAS", // Sprites for GBA remake maps "SPRS", // Sapphire Coast Spring Shell @@ -1870,6 +1871,9 @@ state_t states[NUMSTATES] = // Spray Can {SPR_SPCN, FF_ANIMATE|FF_SEMIBRIGHT, -1, {NULL}, 15, 2, S_NULL}, // S_SPRAYCAN + // Ancient Shrine + {SPR_MMSH, 0, -1, {NULL}, 0, 0, S_NULL}, // S_ANCIENTSHRINE + // Chaos Emeralds {SPR_EMRC, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_CHAOSEMERALD2}, // S_CHAOSEMERALD1 {SPR_EMRC, FF_FULLBRIGHT|FF_ADD, 1, {NULL}, 0, 0, S_CHAOSEMERALD1}, // S_CHAOSEMERALD2 @@ -8309,6 +8313,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_ANCIENTSHRINE + 2256, // doomednum + S_ANCIENTSHRINE,// 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 + 48*FRACUNIT, // radius + 80*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_SCENERY|MF_NOGRAVITY|MF_SOLID|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + { // MT_EMERALD -1, // doomednum S_CHAOSEMERALD1, // spawnstate diff --git a/src/info.h b/src/info.h index 1a4054638..09e79d655 100644 --- a/src/info.h +++ b/src/info.h @@ -696,6 +696,8 @@ typedef enum sprite SPR_NCHP, // NiGHTS chip SPR_NSTR, // NiGHTS star SPR_EMBM, // Emblem + SPR_SPCN, // Spray Can + SPR_MMSH, // Ancient Shrine SPR_EMRC, // Chaos Emeralds SPR_SEMR, // Super Emeralds SPR_ESPK, @@ -1188,7 +1190,6 @@ typedef enum sprite SPR_POKE, // Pokey SPR_AUDI, // Audience members SPR_DECO, // Old 1.0 Kart Decoratives + New misc ones - SPR_SPCN, // Spray Can replaces all the old D00Dkart objects SPR_SNES, // Sprites for SNES remake maps SPR_GBAS, // Sprites for GBA remake maps SPR_SPRS, // Sapphire Coast Spring Shell @@ -2352,6 +2353,9 @@ typedef enum state // Spray Can S_SPRAYCAN, + // Ancient Shrine + S_ANCIENTSHRINE, + // Chaos Emeralds S_CHAOSEMERALD1, S_CHAOSEMERALD2, @@ -5996,6 +6000,7 @@ typedef enum mobj_type MT_BLUEFLAG, // Blue CTF Flag MT_EMBLEM, MT_SPRAYCAN, + MT_ANCIENTSHRINE, MT_EMERALD, MT_EMERALDSPARK, MT_EMERALDFLARE, diff --git a/src/k_follower.c b/src/k_follower.c index 3018566f4..2f679dbe3 100644 --- a/src/k_follower.c +++ b/src/k_follower.c @@ -710,25 +710,46 @@ void K_HandleFollower(player_t *player) } /*-------------------------------------------------- - void K_FollowerHornTaunt(player_t *taunter, player_t *victim) + void K_FollowerHornTaunt(player_t *taunter, player_t *victim, boolean mysticmelodyspecial) See header file for description. --------------------------------------------------*/ -void K_FollowerHornTaunt(player_t *taunter, player_t *victim) +void K_FollowerHornTaunt(player_t *taunter, player_t *victim, boolean mysticmelodyspecial) { + // Basic checks if ( - (cv_karthorns.value == 0) - || taunter == NULL + taunter == NULL || victim == NULL || taunter->followerskin < 0 || taunter->followerskin >= numfollowers + ) + { + return; + } + + const follower_t *fl = &followers[taunter->followerskin]; + + // Check mystic melody special status + if (mysticmelodyspecial == true) + { + /*mysticmelodyspecial = (fl->hornsound == sfx_melody) + + if (mysticmelodyspecial == true) + { + // Todo: The rest of the owl + }*/ + } + + // More expensive checks + if ( + (cv_karthorns.value == 0 && mysticmelodyspecial == false) || (P_IsDisplayPlayer(victim) == false && cv_karthorns.value != 2) || P_MobjWasRemoved(taunter->mo) == true || P_MobjWasRemoved(taunter->follower) == true ) + { return; - - const follower_t *fl = &followers[taunter->followerskin]; + } const boolean tasteful = (taunter->karthud[khud_taunthorns] == 0); diff --git a/src/k_follower.h b/src/k_follower.h index 9da3d4e73..af66b8113 100644 --- a/src/k_follower.h +++ b/src/k_follower.h @@ -227,19 +227,20 @@ void K_HandleFollower(player_t *player); void K_RemoveFollower(player_t *player); /*-------------------------------------------------- - void K_FollowerHornTaunt(player_t *taunter, player_t *victim) + void K_FollowerHornTaunt(player_t *taunter, player_t *victim, boolean mysticmelodyspecial) Plays horn and spawns object (MOSTLY non-netsynced) Input Arguments:- taunter - Source player with a follower victim - Player that hears and sees the honk + mysticmelodyspecial - Special Mystic Melody behaviour Return:- None --------------------------------------------------*/ -void K_FollowerHornTaunt(player_t *taunter, player_t *victim); +void K_FollowerHornTaunt(player_t *taunter, player_t *victim, boolean mysticmelodyspecial); #ifdef __cplusplus } // extern "C" diff --git a/src/k_kart.c b/src/k_kart.c index 4afe202ff..ec4435df2 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -2022,10 +2022,10 @@ static SINT8 K_GlanceAtPlayers(player_t *glancePlayer, boolean horn) { const fixed_t maxdistance = FixedMul(1280 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed)); const angle_t blindSpotSize = ANG10; // ANG5 - UINT8 i; SINT8 glanceDir = 0; SINT8 lastValidGlance = 0; - boolean podiumspecial = (K_PodiumSequence() == true && glancePlayer->nextwaypoint == NULL && glancePlayer->speed == 0); + const boolean podiumspecial = (K_PodiumSequence() == true && glancePlayer->nextwaypoint == NULL && glancePlayer->speed == 0); + boolean mysticmelodyspecial = false; if (podiumspecial) { @@ -2044,43 +2044,47 @@ static SINT8 K_GlanceAtPlayers(player_t *glancePlayer, boolean horn) // See if there's any players coming up behind us. // If so, your character will glance at 'em. - for (i = 0; i < MAXPLAYERS; i++) + mobj_t *victim = NULL, *victimnext = NULL; + + for (victim = trackercap; victim; victim = victimnext) { - player_t *p; + player_t *p = victim->player; angle_t back; angle_t diff; fixed_t distance; SINT8 dir = -1; - if (!playeringame[i]) + victimnext = victim->itnext; + + if (p != NULL) { - // Invalid player - continue; + if (p == glancePlayer) + { + // FOOL! Don't glance at yerself! + continue; + } + + if (p->spectator || p->hyudorotimer > 0) + { + // Not playing / invisible + continue; + } + + if (podiumspecial && p->position >= glancePlayer->position) + { + // On the podium, only look with envy, not condesencion + continue; + } } - - p = &players[i]; - - if (p == glancePlayer) + else if (victim->type != MT_ANCIENTSHRINE) { - // FOOL! Don't glance at yerself! - continue; - } - - if (!p->mo || P_MobjWasRemoved(p->mo)) - { - // Invalid mobj - continue; - } - - if (p->spectator || p->hyudorotimer > 0) - { - // Not playing / invisible + // Ancient Shrines are a special exception to glance logic. continue; } if (!podiumspecial) { - distance = R_PointToDist2(glancePlayer->mo->x, glancePlayer->mo->y, p->mo->x, p->mo->y); + distance = R_PointToDist2(glancePlayer->mo->x, glancePlayer->mo->y, victim->x, victim->y); if (distance > maxdistance) { @@ -2088,13 +2092,9 @@ static SINT8 K_GlanceAtPlayers(player_t *glancePlayer, boolean horn) continue; } } - else if (p->position >= glancePlayer->position) - { - continue; - } back = glancePlayer->mo->angle + ANGLE_180; - diff = R_PointToAngle2(glancePlayer->mo->x, glancePlayer->mo->y, p->mo->x, p->mo->y) - back; + diff = R_PointToAngle2(glancePlayer->mo->x, glancePlayer->mo->y, victim->x, victim->y) - back; if (diff > ANGLE_180) { @@ -2114,7 +2114,7 @@ static SINT8 K_GlanceAtPlayers(player_t *glancePlayer, boolean horn) continue; } - if (!podiumspecial && P_CheckSight(glancePlayer->mo, p->mo) == false) + if (!podiumspecial && P_CheckSight(glancePlayer->mo, victim) == false) { // Blocked by a wall, we can't glance at 'em! continue; @@ -2129,7 +2129,14 @@ static SINT8 K_GlanceAtPlayers(player_t *glancePlayer, boolean horn) if (horn == true) { - K_FollowerHornTaunt(glancePlayer, p); + if (p != NULL) + { + K_FollowerHornTaunt(glancePlayer, p, false); + } + else if (victim->type == MT_ANCIENTSHRINE) + { + mysticmelodyspecial = true; + } } } @@ -2137,7 +2144,7 @@ static SINT8 K_GlanceAtPlayers(player_t *glancePlayer, boolean horn) { const boolean tasteful = (glancePlayer->karthud[khud_taunthorns] == 0); - K_FollowerHornTaunt(glancePlayer, glancePlayer); + K_FollowerHornTaunt(glancePlayer, glancePlayer, mysticmelodyspecial); if (tasteful && glancePlayer->karthud[khud_taunthorns] < 2*TICRATE) glancePlayer->karthud[khud_taunthorns] = 2*TICRATE; diff --git a/src/p_mobj.c b/src/p_mobj.c index 504077f99..eb82c9815 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -5338,6 +5338,10 @@ static boolean P_IsTrackerType(INT32 type) case MT_JAWZ: return true; + // Players need to be able to glance at the Ancient Shrines + case MT_ANCIENTSHRINE: + return true; + // Primarily for minimap data, handle with care case MT_SPB: case MT_BATTLECAPSULE: @@ -5348,6 +5352,7 @@ static boolean P_IsTrackerType(INT32 type) case MT_PLAYER: return true; + // HUD tracking case MT_OVERTIME_CENTER: case MT_MONITOR: case MT_EMERALD: @@ -13060,6 +13065,22 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj) nummapspraycans++; break; } + case MT_ANCIENTSHRINE: + { + angle_t remainderangle = (mobj->angle % ANGLE_90); + + if (remainderangle) + { + // Always lock to 90 degree grid. + if (remainderangle > ANGLE_45) + mobj->angle += ANGLE_90; + mobj->angle -= remainderangle; + } + + P_SetScale(mobj, mobj->destscale = 2*mobj->scale); + + break; + } case MT_SKYBOX: { P_InitSkyboxPoint(mobj, mthing);