mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2026-03-02 01:11:19 +00:00
UC_PRISONEGGCD
Gamedata minor version was updated again.
(God this was a weirdly big amount of work and it's not even polished.)
- Condition1 = PrisonEggCD [Level that has to be unlocked]
- Approximately every 30 Prison Eggs destroyed, you get a shot at a Prison Egg Drop.
- The only Prison Egg Drop implemented right now is an Alt Music CD.
- Your [Wild Prize] is guaranteed to be selected only from conditions associated with levels that are unlocked!
- Only spawns in Grand Prix Bonus Rounds, for netsync and game design.
- The number is fuzzed. If you start the level with 0 Prison Eggs to destroy, it selects a random number of Prisons in the level to bust.
- If you miss the pickup (such as into a deathpit), you'll get another shot in the immediate next Bonus Round you play.
Also:
- The number of Chao Keys you start your gamedata with is now part of the header file, not buried in the wiping function.
- Removed the ACTUAL last object definition vestiges of the Emerald Hunt gamemode.
This commit is contained in:
parent
71a95b3096
commit
f8de2cfc83
14 changed files with 427 additions and 56 deletions
|
|
@ -2643,6 +2643,22 @@ static void readcondition(UINT16 set, UINT32 id, char *word2)
|
|||
// Force at head of the list?
|
||||
x1 = (params[2] && (params[2][0] == 'Y' || params[2][0] == 'T')) ? 1 : 0;
|
||||
}
|
||||
else if (fastcmp(params[0], "PRISONEGGCD"))
|
||||
{
|
||||
ty = UC_PRISONEGGCD;
|
||||
re = NEXTMAP_INVALID;
|
||||
|
||||
if (params[1])
|
||||
{
|
||||
re = G_MapNumber(params[1]);
|
||||
|
||||
if (re >= nummapheaders)
|
||||
{
|
||||
deh_warning("Invalid level %s for condition ID %d", params[1], id+1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((offset=0) || fastcmp(params[0], "AND")
|
||||
|| (++offset && fastcmp(params[0], "COMMA")))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1218,10 +1218,8 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
|
|||
|
||||
"S_EMERALDFLARE1",
|
||||
|
||||
// Emerald hunt shards
|
||||
"S_SHRD1",
|
||||
"S_SHRD2",
|
||||
"S_SHRD3",
|
||||
// Prison Egg Drops
|
||||
"S_PRISONEGGDROP_CD",
|
||||
|
||||
// Bubble Source
|
||||
"S_BUBBLES1",
|
||||
|
|
@ -4841,8 +4839,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
|
|||
"MT_EMERALD",
|
||||
"MT_EMERALDSPARK",
|
||||
"MT_EMERALDFLARE",
|
||||
"MT_EMERHUNT", // Emerald Hunt
|
||||
"MT_EMERALDSPAWN", // Emerald spawner w/ delay
|
||||
"MT_PRISONEGGDROP",
|
||||
|
||||
// Springs and others
|
||||
"MT_FAN",
|
||||
|
|
|
|||
14
src/g_game.c
14
src/g_game.c
|
|
@ -4425,7 +4425,7 @@ void G_LoadGameSettings(void)
|
|||
}
|
||||
|
||||
#define GD_VERSIONCHECK 0xBA5ED123 // Change every major version, as usual
|
||||
#define GD_VERSIONMINOR 7 // Change every format update
|
||||
#define GD_VERSIONMINOR 8 // Change every format update
|
||||
|
||||
// You can't rearrange these without a special format update
|
||||
typedef enum
|
||||
|
|
@ -4583,6 +4583,13 @@ void G_LoadGameData(void)
|
|||
save.p += 4; // no direct equivalent to matchesplayed
|
||||
}
|
||||
|
||||
// Prison Egg Pickups
|
||||
if (versionMinor >= 8)
|
||||
{
|
||||
gamedata->thisprisoneggpickup = READUINT16(save.p);
|
||||
gamedata->prisoneggstothispickup = READUINT16(save.p);
|
||||
}
|
||||
|
||||
{
|
||||
// Quick & dirty hash for what mod this save file is for.
|
||||
UINT32 modID = READUINT32(save.p);
|
||||
|
|
@ -5090,6 +5097,7 @@ void G_SaveGameData(void)
|
|||
(4*GDGT_MAX)+
|
||||
4+1+2+2+
|
||||
4+
|
||||
2+2+
|
||||
4+
|
||||
(MAXEMBLEMS+(MAXUNLOCKABLES*2)+MAXCONDITIONSETS)+
|
||||
4+2);
|
||||
|
|
@ -5256,6 +5264,10 @@ void G_SaveGameData(void)
|
|||
WRITEUINT32(save.p, everflags); // 4
|
||||
}
|
||||
|
||||
// Prison Egg Pickups
|
||||
WRITEUINT16(save.p, gamedata->thisprisoneggpickup); // 2
|
||||
WRITEUINT16(save.p, gamedata->prisoneggstothispickup); // 2
|
||||
|
||||
WRITEUINT32(save.p, quickncasehash(timeattackfolder, 64)); // 4
|
||||
|
||||
// To save space, use one bit per collected/achieved/unlocked flag
|
||||
|
|
|
|||
53
src/info.c
53
src/info.c
|
|
@ -148,7 +148,9 @@ char sprnames[NUMSPRITES + 1][5] =
|
|||
"EMRC", // Chaos Emeralds
|
||||
"SEMR", // Super Emeralds
|
||||
"ESPK",
|
||||
"SHRD", // Emerald Hunt
|
||||
|
||||
// Prison Egg Drops
|
||||
"ALTM",
|
||||
|
||||
// Interactive Objects
|
||||
"BBLS", // water bubble source
|
||||
|
|
@ -1920,10 +1922,8 @@ state_t states[NUMSTATES] =
|
|||
|
||||
{SPR_LENS, FF_FULLBRIGHT|FF_ADD|FF_TRANS10|FF_ANIMATE|11, 8, {NULL}, 7, 1, S_GAINAX_MID2}, // S_EMERALDFLARE1
|
||||
|
||||
// Emerald hunt shards
|
||||
{SPR_SHRD, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SHRD1
|
||||
{SPR_SHRD, 1, -1, {NULL}, 0, 0, S_NULL}, // S_SHRD2
|
||||
{SPR_SHRD, 2, -1, {NULL}, 0, 0, S_NULL}, // S_SHRD3
|
||||
// Prison Egg Drops
|
||||
{SPR_ALTM, 0|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_PRISONEGGDROP_CD
|
||||
|
||||
// Bubble Source
|
||||
{SPR_BBLS, 0, 8, {A_BubbleSpawn}, 2048, 0, S_BUBBLES2}, // S_BUBBLES1
|
||||
|
|
@ -8482,9 +8482,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_EMERHUNT
|
||||
320, // doomednum
|
||||
S_SHRD1, // spawnstate
|
||||
{ // MT_PRISONEGGDROP
|
||||
-1, // doomednum
|
||||
S_INVISIBLE, // spawnstate
|
||||
1000, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
|
|
@ -8495,44 +8495,17 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
sfx_None, // painsound
|
||||
S_NULL, // meleestate
|
||||
S_NULL, // missilestate
|
||||
S_SPRK1, // deathstate
|
||||
S_NULL, // xdeathstate
|
||||
sfx_cgot, // deathsound
|
||||
8, // speed
|
||||
12*FRACUNIT, // radius
|
||||
42*FRACUNIT, // height
|
||||
0, // display offset
|
||||
4, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_SPECIAL|MF_NOGRAVITY, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_EMERALDSPAWN
|
||||
321, // doomednum
|
||||
S_INVISIBLE, // spawnstate
|
||||
1000, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
0, // 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
|
||||
sfx_s3k9c, // deathsound
|
||||
0, // speed
|
||||
8, // radius
|
||||
8, // height
|
||||
65*FRACUNIT, // radius
|
||||
130*FRACUNIT, // height
|
||||
0, // display offset
|
||||
10, // mass
|
||||
16, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOSECTOR, // flags
|
||||
MF_SPECIAL|MF_PICKUPFROMBELOW|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
|
|
|
|||
13
src/info.h
13
src/info.h
|
|
@ -703,7 +703,9 @@ typedef enum sprite
|
|||
SPR_EMRC, // Chaos Emeralds
|
||||
SPR_SEMR, // Super Emeralds
|
||||
SPR_ESPK,
|
||||
SPR_SHRD, // Emerald Hunt
|
||||
|
||||
// Prison Egg Drops
|
||||
SPR_ALTM,
|
||||
|
||||
// Interactive Objects
|
||||
SPR_BBLS, // water bubble source
|
||||
|
|
@ -2400,10 +2402,8 @@ typedef enum state
|
|||
|
||||
S_EMERALDFLARE1,
|
||||
|
||||
// Emerald hunt shards
|
||||
S_SHRD1,
|
||||
S_SHRD2,
|
||||
S_SHRD3,
|
||||
// Prison Egg Drops
|
||||
S_PRISONEGGDROP_CD,
|
||||
|
||||
// Bubble Source
|
||||
S_BUBBLES1,
|
||||
|
|
@ -6062,8 +6062,7 @@ typedef enum mobj_type
|
|||
MT_EMERALD,
|
||||
MT_EMERALDSPARK,
|
||||
MT_EMERALDFLARE,
|
||||
MT_EMERHUNT, // Emerald Hunt
|
||||
MT_EMERALDSPAWN, // Emerald spawner w/ delay
|
||||
MT_PRISONEGGDROP,
|
||||
|
||||
// Springs and others
|
||||
MT_FAN,
|
||||
|
|
|
|||
16
src/k_kart.c
16
src/k_kart.c
|
|
@ -267,6 +267,22 @@ void K_TimerInit(void)
|
|||
{
|
||||
K_SpawnDuelOnlyItems();
|
||||
}
|
||||
|
||||
if (
|
||||
battleprisons == true
|
||||
&& grandprixinfo.gp == true
|
||||
&& netgame == false
|
||||
&& gamedata->thisprisoneggpickup_cached != NULL
|
||||
&& gamedata->prisoneggstothispickup == 0
|
||||
&& maptargets > 1
|
||||
)
|
||||
{
|
||||
// This calculation is like this so...
|
||||
// - You can't get a Prison Egg Drop on the last broken target
|
||||
// - If it were 0 at minimum there'd be a slight bias towards the start of the round
|
||||
// - This is bad because it benefits CD farming like in Brawl :D
|
||||
gamedata->prisoneggstothispickup = 1 + M_RandomKey(maptargets - 1);
|
||||
}
|
||||
}
|
||||
|
||||
UINT32 K_GetPlayerDontDrawFlag(player_t *player)
|
||||
|
|
|
|||
191
src/m_cond.c
191
src/m_cond.c
|
|
@ -679,6 +679,14 @@ void M_ClearSecrets(void)
|
|||
gamedata->numspraycans = 0;
|
||||
gamedata->gotspraycans = 0;
|
||||
|
||||
Z_Free(gamedata->prisoneggpickups);
|
||||
gamedata->prisoneggpickups = NULL;
|
||||
gamedata->numprisoneggpickups = 0;
|
||||
gamedata->gettableprisoneggpickups = 0;
|
||||
gamedata->thisprisoneggpickup = MAXCONDITIONSETS;
|
||||
gamedata->thisprisoneggpickup_cached = NULL;
|
||||
gamedata->thisprisoneggpickupgrabbed = false;
|
||||
|
||||
UINT16 i, j;
|
||||
for (i = 0; i < nummapheaders; i++)
|
||||
{
|
||||
|
|
@ -713,7 +721,9 @@ void M_ClearSecrets(void)
|
|||
gamedata->pendingkeyrounds = 0;
|
||||
gamedata->pendingkeyroundoffset = 0;
|
||||
gamedata->keyspending = 0;
|
||||
gamedata->chaokeys = 3; // Start with 3 !!
|
||||
|
||||
gamedata->chaokeys = GDINIT_CHAOKEYS;
|
||||
gamedata->prisoneggstothispickup = GDINIT_PRISONSTOPRIZE;
|
||||
}
|
||||
|
||||
// For lack of a better idea on where to put this
|
||||
|
|
@ -835,6 +845,171 @@ static void M_AssignSpraycans(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void M_InitPrisonEggPickups(void)
|
||||
{
|
||||
// Init ordered list of skincolors
|
||||
UINT16 temppickups[MAXCONDITIONSETS];
|
||||
UINT16 listlen = 0;
|
||||
|
||||
UINT32 i, j;
|
||||
conditionset_t *c;
|
||||
condition_t *cn;
|
||||
|
||||
for (i = 0; i < MAXCONDITIONSETS; ++i)
|
||||
{
|
||||
// Optimisation - unlike Spray Cans, these are rebuilt every game launch/savedata wipe.
|
||||
// Therefore, we don't need to re-store the ones that have been achieved.
|
||||
if (gamedata->achieved[i])
|
||||
continue;
|
||||
|
||||
c = &conditionSets[i];
|
||||
if (!c->numconditions)
|
||||
continue;
|
||||
|
||||
for (j = 0; j < c->numconditions; ++j)
|
||||
{
|
||||
cn = &c->condition[j];
|
||||
if (cn->type != UC_PRISONEGGCD)
|
||||
continue;
|
||||
|
||||
temppickups[listlen] = i;
|
||||
listlen++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!listlen)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// This list doesn't need to be shuffled because it's always being randomly grabbed.
|
||||
// (Unlike Spray Cans, you don't know which CD you miss out on.)
|
||||
|
||||
gamedata->prisoneggpickups = Z_Realloc(
|
||||
gamedata->prisoneggpickups,
|
||||
sizeof(UINT16) * listlen,
|
||||
PU_STATIC,
|
||||
NULL);
|
||||
|
||||
while (gamedata->numprisoneggpickups < listlen)
|
||||
{
|
||||
gamedata->prisoneggpickups[gamedata->numprisoneggpickups]
|
||||
= temppickups[gamedata->numprisoneggpickups];
|
||||
gamedata->numprisoneggpickups++;
|
||||
}
|
||||
|
||||
M_UpdateNextPrisonEggPickup();
|
||||
}
|
||||
|
||||
void M_UpdateNextPrisonEggPickup(void)
|
||||
{
|
||||
UINT16 i = gamedata->gettableprisoneggpickups, j, swap;
|
||||
|
||||
conditionset_t *c;
|
||||
condition_t *cn;
|
||||
|
||||
boolean firstrun = true;
|
||||
|
||||
cacheprisoneggpickup:
|
||||
|
||||
// Check if the current roll is fine
|
||||
gamedata->thisprisoneggpickup_cached = NULL;
|
||||
if (gamedata->thisprisoneggpickup < MAXCONDITIONSETS)
|
||||
{
|
||||
//CONS_Printf("CACHE TEST: thisprisoneggpickup is set to %u\n", gamedata->thisprisoneggpickup);
|
||||
if (gamedata->achieved[gamedata->thisprisoneggpickup] == false)
|
||||
{
|
||||
c = &conditionSets[gamedata->thisprisoneggpickup];
|
||||
if (c->numconditions)
|
||||
{
|
||||
for (j = 0; j < c->numconditions; ++j)
|
||||
{
|
||||
cn = &c->condition[j];
|
||||
if (cn->type != UC_PRISONEGGCD)
|
||||
continue;
|
||||
|
||||
if (cn->requirement < nummapheaders && M_MapLocked(cn->requirement+1))
|
||||
continue;
|
||||
|
||||
// Good! Attach the cache.
|
||||
gamedata->thisprisoneggpickup_cached = cn;
|
||||
//CONS_Printf(" successfully set to cn!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gamedata->thisprisoneggpickup_cached == NULL)
|
||||
{
|
||||
gamedata->thisprisoneggpickup = MAXCONDITIONSETS;
|
||||
gamedata->thisprisoneggpickupgrabbed = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstrun && gamedata->numprisoneggpickups && gamedata->thisprisoneggpickup == MAXCONDITIONSETS)
|
||||
{
|
||||
for (; i < gamedata->numprisoneggpickups; i++)
|
||||
{
|
||||
if (gamedata->achieved[gamedata->prisoneggpickups[i]] == false)
|
||||
{
|
||||
c = &conditionSets[gamedata->prisoneggpickups[i]];
|
||||
if (c->numconditions)
|
||||
{
|
||||
for (j = 0; j < c->numconditions; ++j)
|
||||
{
|
||||
cn = &c->condition[j];
|
||||
if (cn->type != UC_PRISONEGGCD)
|
||||
continue;
|
||||
|
||||
// Locked associated map? Keep in the rear end dimension!
|
||||
if (cn->requirement < nummapheaders && M_MapLocked(cn->requirement+1))
|
||||
break; // not continue intentionally
|
||||
|
||||
// Okay, this should be available.
|
||||
// Bring to the front!
|
||||
swap = gamedata->prisoneggpickups[gamedata->gettableprisoneggpickups];
|
||||
gamedata->prisoneggpickups[gamedata->gettableprisoneggpickups] =
|
||||
gamedata->prisoneggpickups[i];
|
||||
gamedata->prisoneggpickups[i] = swap;
|
||||
|
||||
gamedata->gettableprisoneggpickups++;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (j < c->numconditions)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Fell all the way through?
|
||||
// Push this all the way to the back, and lop it off!
|
||||
|
||||
swap = gamedata->prisoneggpickups[gamedata->numprisoneggpickups];
|
||||
gamedata->prisoneggpickups[gamedata->numprisoneggpickups] =
|
||||
gamedata->prisoneggpickups[i];
|
||||
gamedata->prisoneggpickups[i] = swap;
|
||||
|
||||
gamedata->numprisoneggpickups--;
|
||||
i--; // We run the loop again for this entry
|
||||
}
|
||||
|
||||
if (gamedata->gettableprisoneggpickups)
|
||||
{
|
||||
gamedata->thisprisoneggpickup =
|
||||
gamedata->prisoneggpickups[
|
||||
M_RandomKey(gamedata->gettableprisoneggpickups)
|
||||
];
|
||||
|
||||
firstrun = false;
|
||||
goto cacheprisoneggpickup;
|
||||
}
|
||||
}
|
||||
|
||||
//CONS_Printf("thisprisoneggpickup = %u (MAXCONDITIONSETS is %u)\n", gamedata->thisprisoneggpickup, MAXCONDITIONSETS);
|
||||
}
|
||||
|
||||
static void M_PrecacheLevelLocks(void)
|
||||
{
|
||||
UINT16 i, j;
|
||||
|
|
@ -908,6 +1083,9 @@ void M_FinaliseGameData(void)
|
|||
// Place the spraycans, which CAN'T be done lazily.
|
||||
M_AssignSpraycans();
|
||||
|
||||
// You could probably do the Prison Egg Pickups lazily, but it'd be a lagspike mid-combat.
|
||||
M_InitPrisonEggPickups();
|
||||
|
||||
// Don't consider loaded until it's a success!
|
||||
// It used to do this much earlier, but this would cause the gamedata
|
||||
// to save over itself when it I_Errors from corruption, which can
|
||||
|
|
@ -1160,6 +1338,7 @@ boolean M_CheckCondition(condition_t *cn, player_t *player)
|
|||
return false;
|
||||
case UC_PASSWORD:
|
||||
return (cn->stringvar == NULL);
|
||||
|
||||
case UC_SPRAYCAN:
|
||||
{
|
||||
if (cn->requirement <= 0
|
||||
|
|
@ -1174,6 +1353,9 @@ boolean M_CheckCondition(condition_t *cn, player_t *player)
|
|||
return (gamedata->spraycans[can_id].map < nummapheaders);
|
||||
}
|
||||
|
||||
case UC_PRISONEGGCD:
|
||||
return ((gamedata->thisprisoneggpickupgrabbed == true) && (cn == gamedata->thisprisoneggpickup_cached));
|
||||
|
||||
// Just for string building
|
||||
case UC_AND:
|
||||
case UC_COMMA:
|
||||
|
|
@ -1748,6 +1930,7 @@ static const char *M_GetConditionString(condition_t *cn)
|
|||
return NULL;
|
||||
case UC_PASSWORD:
|
||||
return "enter a secret password";
|
||||
|
||||
case UC_SPRAYCAN:
|
||||
{
|
||||
if (cn->requirement <= 0
|
||||
|
|
@ -1771,6 +1954,10 @@ static const char *M_GetConditionString(condition_t *cn)
|
|||
return va("grab %d Spray Cans", can_id + 1);
|
||||
}
|
||||
|
||||
case UC_PRISONEGGCD:
|
||||
// :butterfly: "alternatively you could say 'grab a hot toooon' or 'smooth beeat'"
|
||||
return "BONUS ROUND: grab a prize from a Prison Egg";
|
||||
|
||||
case UC_AND:
|
||||
return "&";
|
||||
case UC_COMMA:
|
||||
|
|
@ -2161,6 +2348,8 @@ boolean M_UpdateUnlockablesAndExtraEmblems(boolean loud, boolean doall)
|
|||
{
|
||||
response = M_CheckUnlockConditions(NULL);
|
||||
|
||||
M_UpdateNextPrisonEggPickup();
|
||||
|
||||
if (gamedata->pendingkeyrounds == 0
|
||||
|| (gamedata->chaokeys >= GDMAX_CHAOKEYS))
|
||||
{
|
||||
|
|
|
|||
16
src/m_cond.h
16
src/m_cond.h
|
|
@ -63,6 +63,8 @@ typedef enum
|
|||
|
||||
UC_SPRAYCAN, // Grab a spraycan
|
||||
|
||||
UC_PRISONEGGCD, // Grab a CD from a Prison Egg
|
||||
|
||||
// Just for string building
|
||||
UC_AND,
|
||||
UC_COMMA,
|
||||
|
|
@ -246,6 +248,9 @@ typedef enum {
|
|||
|
||||
#define GDCONVERT_ROUNDSTOKEY 32
|
||||
|
||||
#define GDINIT_CHAOKEYS 3 // Start with 3 Chao Keys !!
|
||||
#define GDINIT_PRISONSTOPRIZE 30 // 30 Prison Eggs to your [Wild Prize] !!
|
||||
|
||||
typedef enum {
|
||||
GDGT_RACE,
|
||||
GDGT_BATTLE,
|
||||
|
|
@ -287,6 +292,15 @@ struct gamedata_t
|
|||
UINT16 gotspraycans;
|
||||
candata_t* spraycans;
|
||||
|
||||
// PRISON EGG PICKUPS
|
||||
UINT16 numprisoneggpickups;
|
||||
UINT16 gettableprisoneggpickups;
|
||||
UINT16 thisprisoneggpickup;
|
||||
condition_t *thisprisoneggpickup_cached;
|
||||
boolean thisprisoneggpickupgrabbed;
|
||||
UINT16 prisoneggstothispickup;
|
||||
UINT16* prisoneggpickups;
|
||||
|
||||
// CHALLENGE GRID
|
||||
UINT16 challengegridwidth;
|
||||
UINT16 *challengegrid;
|
||||
|
|
@ -375,6 +389,8 @@ boolean M_UpdateUnlockablesAndExtraEmblems(boolean loud, boolean doall);
|
|||
#define PENDING_CHAOKEYS (UINT16_MAX-1)
|
||||
UINT16 M_GetNextAchievedUnlock(boolean canskipchaokeys);
|
||||
|
||||
void M_UpdateNextPrisonEggPickup(void);
|
||||
|
||||
UINT16 M_CheckLevelEmblems(void);
|
||||
UINT16 M_CompletionEmblems(void);
|
||||
|
||||
|
|
|
|||
|
|
@ -980,7 +980,6 @@ static mobj_t *SearchMarioNode(msecnode_t *node)
|
|||
case MT_THOK:
|
||||
case MT_GHOST:
|
||||
case MT_OVERLAY:
|
||||
case MT_EMERALDSPAWN:
|
||||
case MT_ELEMENTAL_ORB:
|
||||
case MT_ATTRACT_ORB:
|
||||
case MT_FORCE_ORB:
|
||||
|
|
|
|||
|
|
@ -800,6 +800,49 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
return;
|
||||
}
|
||||
|
||||
case MT_PRISONEGGDROP:
|
||||
{
|
||||
if (demo.playback)
|
||||
{
|
||||
// Never collect emblems in replays.
|
||||
return;
|
||||
}
|
||||
|
||||
if (player->bot)
|
||||
{
|
||||
// Your nefarious opponent puppy can't grab these for you.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!P_IsLocalPlayer(player))
|
||||
{
|
||||
// Must be party.
|
||||
return;
|
||||
}
|
||||
|
||||
if (special->hitlag || special->scale < mapobjectscale/2)
|
||||
{
|
||||
// Don't get during the initial activation
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
grandprixinfo.gp == true // Bonus Round
|
||||
&& netgame == false // game design + makes it easier to implement
|
||||
&& gamedata->thisprisoneggpickup_cached != NULL
|
||||
)
|
||||
{
|
||||
gamedata->thisprisoneggpickupgrabbed = true;
|
||||
gamedata->prisoneggstothispickup = GDINIT_PRISONSTOPRIZE;
|
||||
|
||||
if (!M_UpdateUnlockablesAndExtraEmblems(true, true))
|
||||
S_StartSound(NULL, sfx_ncitem);
|
||||
gamedata->deferredsave = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MT_LSZ_BUNGEE:
|
||||
Obj_BungeeSpecial(special, player);
|
||||
return;
|
||||
|
|
@ -936,6 +979,11 @@ static void P_AddBrokenPrison(mobj_t *target, mobj_t *source)
|
|||
K_SpawnBattlePoints(source->player, NULL, 1);
|
||||
}
|
||||
|
||||
if (gamedata->prisoneggstothispickup)
|
||||
{
|
||||
gamedata->prisoneggstothispickup--;
|
||||
}
|
||||
|
||||
if (++numtargets >= maptargets)
|
||||
{
|
||||
P_DoAllPlayersExit(0, (grandprixinfo.gp == true));
|
||||
|
|
@ -948,6 +996,55 @@ static void P_AddBrokenPrison(mobj_t *target, mobj_t *source)
|
|||
extratimeintics += 10*TICRATE;
|
||||
secretextratime = TICRATE/2;
|
||||
}
|
||||
|
||||
if (
|
||||
grandprixinfo.gp == true // Bonus Round
|
||||
&& demo.playback == false // Not playback
|
||||
&& netgame == false // game design + makes it easier to implement
|
||||
&& gamedata->thisprisoneggpickup_cached != NULL
|
||||
&& gamedata->prisoneggstothispickup == 0
|
||||
&& gamedata->thisprisoneggpickupgrabbed == false
|
||||
)
|
||||
{
|
||||
// Will be 0 for the next level
|
||||
gamedata->prisoneggstothispickup = (maptargets - numtargets);
|
||||
|
||||
mobj_t *secretpickup = P_SpawnMobj(
|
||||
target->x, target->y,
|
||||
target->z + (
|
||||
target->height
|
||||
- FixedMul(mobjinfo[MT_PRISONEGGDROP].height, mapobjectscale)
|
||||
),
|
||||
MT_PRISONEGGDROP
|
||||
);
|
||||
|
||||
if (secretpickup)
|
||||
{
|
||||
secretpickup->hitlag = target->hitlag;
|
||||
|
||||
P_SetScale(secretpickup, mapobjectscale/TICRATE);
|
||||
// secretpickup->destscale = mapobjectscale; -- safe assumption it's already set?
|
||||
secretpickup->scalespeed = (2*mapobjectscale)/(3*TICRATE);
|
||||
|
||||
// NOT from the target - just in case it's just been placed on the ceiling as a gimmick
|
||||
K_FlipFromObject(secretpickup, source);
|
||||
|
||||
// Okay these have to use M_Random because replays...
|
||||
// The spawning of these won't be recorded back!
|
||||
const angle_t launchangle = FixedAngle(M_RandomRange(60, 80) * FRACUNIT);
|
||||
const fixed_t launchmomentum = 20 * mapobjectscale;
|
||||
|
||||
secretpickup->momz = P_MobjFlip(target) // THIS one uses target!
|
||||
* P_ReturnThrustY(secretpickup, launchangle, launchmomentum);
|
||||
|
||||
secretpickup->angle = FixedAngle(M_RandomKey(360) * FRACUNIT);
|
||||
|
||||
P_InstaThrust(
|
||||
secretpickup, secretpickup->angle,
|
||||
P_ReturnThrustX(secretpickup, launchangle, launchmomentum)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
51
src/p_mobj.c
51
src/p_mobj.c
|
|
@ -7638,6 +7638,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
break;
|
||||
}
|
||||
case MT_EMERALD:
|
||||
{
|
||||
Obj_EmeraldThink(mobj);
|
||||
|
||||
if (P_MobjWasRemoved(mobj))
|
||||
|
|
@ -7645,6 +7646,56 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MT_PRISONEGGDROP:
|
||||
{
|
||||
// If it gets any more complicated than this I'll make an objects/prisoneggdrop.c file, promise
|
||||
// ~toast 121023
|
||||
|
||||
statenum_t teststate = S_NULL;
|
||||
|
||||
if (mobj->flags2 & MF2_AMBUSH)
|
||||
{
|
||||
if (P_IsObjectOnGround(mobj))
|
||||
{
|
||||
if (P_CheckDeathPitCollide(mobj))
|
||||
{
|
||||
P_RemoveMobj(mobj);
|
||||
return false;
|
||||
}
|
||||
|
||||
mobj->momx = mobj->momy = 0;
|
||||
}
|
||||
|
||||
teststate = (mobj->state-states);
|
||||
}
|
||||
else if (!netgame)
|
||||
{
|
||||
if (gamedata->thisprisoneggpickup_cached->type == UC_PRISONEGGCD)
|
||||
{
|
||||
teststate = S_PRISONEGGDROP_CD;
|
||||
}
|
||||
|
||||
P_SetMobjState(mobj, teststate);
|
||||
|
||||
if (P_MobjWasRemoved(mobj))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
S_StartSound(NULL, sfx_cdsprk);
|
||||
|
||||
mobj->z += P_MobjFlip(mobj);
|
||||
mobj->flags2 |= MF2_AMBUSH;
|
||||
}
|
||||
|
||||
if (teststate == S_PRISONEGGDROP_CD)
|
||||
{
|
||||
mobj->angle += ANGLE_MAX/TICRATE;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case MT_EMERALDFLARE:
|
||||
Obj_EmeraldFlareThink(mobj);
|
||||
|
||||
|
|
|
|||
|
|
@ -2708,6 +2708,10 @@ boolean TypeIsNetSynced(mobjtype_t type)
|
|||
if (type == MT_HORNCODE)
|
||||
return false;
|
||||
|
||||
// MT_PRISONEGGDROP: Yeah these are completely local
|
||||
if (type == MT_PRISONEGGDROP)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1193,6 +1193,7 @@ sfxinfo_t S_sfx[NUMSFX] =
|
|||
|
||||
{"horn00", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, "/"}, // HORNCODE
|
||||
{"melody", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, "/"}, // Mystic Melody
|
||||
{"cdsprk", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, "/"}, // Prison Egg CD sparkling
|
||||
{"monch", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
{"etexpl", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Game crash"},
|
||||
|
||||
|
|
|
|||
|
|
@ -1263,6 +1263,7 @@ typedef enum
|
|||
|
||||
sfx_horn00,
|
||||
sfx_melody,
|
||||
sfx_cdsprk,
|
||||
sfx_monch,
|
||||
sfx_etexpl,
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue