Ancient Shrine implementation beginning

- Players will glance at Ancient Shrines near/behind them.
- Look back at these Shrines to activate your follower's horn!
    - Currently, this even works if horns are turned off, as a sort of tutorial.
    - TODO: A special horn will be able to activate them...
This commit is contained in:
toaster 2023-10-05 23:07:35 +01:00
parent 0b1be76442
commit e96bae393c
7 changed files with 133 additions and 43 deletions

View file

@ -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",

View file

@ -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

View file

@ -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,

View file

@ -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);

View file

@ -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"

View file

@ -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;

View file

@ -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);