Battle Mode overtime

After the time limit is up, spawn a shrinking kill-field. This is one hefty initial commit!
This commit is contained in:
TehRealSalt 2018-12-06 13:46:38 -05:00
parent 7f335e9c46
commit dfa0522326
15 changed files with 343 additions and 62 deletions

View file

@ -4326,9 +4326,9 @@ void D_GameTypeChanged(INT32 lastgametype)
case GT_TEAMMATCH:
if (!cv_timelimit.changed && !cv_pointlimit.changed) // user hasn't changed limits
{
// default settings for match: no timelimit, no pointlimit
// default settings for match: 3 mins, no pointlimit
CV_SetValue(&cv_pointlimit, 0);
CV_SetValue(&cv_timelimit, 0);
CV_SetValue(&cv_timelimit, 3);
}
if (!cv_itemrespawntime.changed)
CV_Set(&cv_itemrespawntime, cv_itemrespawntime.defaultvalue); // respawn normally

View file

@ -346,6 +346,7 @@ typedef enum
k_comebackpoints, // Number of times you've bombed or gave an item to someone; once it's 3 it gets set back to 0 and you're given a bumper
k_comebackmode, // 0 = bomb, 1 = item
k_wanted, // Timer for determining WANTED status, lowers when hitting people, prevents the game turning into Camp Lazlo
k_killfield, // How long have you been in the kill field, stay in too long and lose a bumper
k_yougotem, // "You Got Em" gfx when hitting someone as a karma player via a method that gets you back in the game instantly
// v1.0.2 vars

View file

@ -7099,6 +7099,9 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_KARMAFIREWORK4",
"S_KARMAFIREWORKTRAIL",
"S_OVERTIMEFOG",
"S_OVERTIMEORB",
#ifdef SEENAMES
"S_NAMECHECK",
#endif
@ -7886,6 +7889,9 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_KARMAFIREWORK",
"MT_OVERTIMEFOG",
"MT_OVERTIMEORB",
#ifdef SEENAMES
"MT_NAMECHECK",
#endif
@ -8278,6 +8284,7 @@ static const char *const KARTSTUFF_LIST[] = {
"COMEBACKPOINTS",
"COMEBACKMODE",
"WANTED",
"KILLFIELD",
"YOUGOTEM",
"ITEMBLINK",

View file

@ -471,6 +471,17 @@ extern INT16 votelevels[5][2];
extern SINT8 votes[MAXPLAYERS];
extern SINT8 pickedvote;
/** Battle overtime information
*/
typedef struct
{
boolean enabled; ///< Has this been initalized yet?
UINT16 radius; ///< Radius of kill field
fixed_t x, y, z; ///< Position to center on (z is only used for visuals)
} battleovertime_t;
extern battleovertime_t *battleovertime;
extern tic_t hidetime;
extern UINT32 timesBeaten; // # of times the game has been beaten.

View file

@ -260,6 +260,9 @@ INT16 votelevels[5][2]; // Levels that were rolled by the host
SINT8 votes[MAXPLAYERS]; // Each player's vote
SINT8 pickedvote; // What vote the host rolls
// Battle overtime system
battleovertime_t *battleovertime = {NULL};
// Server-sided, synched variables
SINT8 battlewanted[4]; // WANTED players in battle, worth x2 points
tic_t wantedcalcdelay; // Time before it recalculates WANTED

View file

@ -69,7 +69,7 @@ char sprnames[NUMSPRITES + 1][5] =
"CNDL","DOCH","DUCK","GTRE","CHES","CHIM","DRGN","LZMN","PGSS","ZTCH",
"MKMA","MKMP","RTCH","BOWL","BOWH","BRRL","BRRR","HRSE","TOAH","BFRT",
"OFRT","RFRT","PFRT","ASPK","HBST","HBSO","HBSF","WBLZ","WBLN","FWRK",
"XMS4","XMS5","VIEW"
"OTFG","XMS4","XMS5","VIEW"
};
// Doesn't work with g++, needs actionf_p1 (don't modify this comment)
@ -3394,6 +3394,9 @@ state_t states[NUMSTATES] =
{SPR_FWRK, 3|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_KARMAFIREWORK1}, // S_KARMAFIREWORK4
{SPR_FWRK, 4|FF_FULLBRIGHT, TICRATE, {NULL}, 0, 0, S_NULL}, // S_KARMAFIREWORKTRAIL
{SPR_OTFG, FF_FULLBRIGHT|FF_TRANS50, 8, {NULL}, 0, 0, S_NULL}, // S_OVERTIMEFOG
{SPR_OTFG, 1|FF_FULLBRIGHT, 8, {NULL}, 0, 0, S_NULL}, // S_OVERTIMEORB
#ifdef SEENAMES
{SPR_NULL, 0, 1, {NULL}, 0, 0, S_NULL}, // S_NAMECHECK
#endif
@ -20052,6 +20055,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_OVERTIMEFOG
-1, // doomednum
S_OVERTIMEFOG, // 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
8<<FRACBITS, // radius
16<<FRACBITS, // height
-1, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags
S_NULL // raisestate
},
{ // MT_OVERTIMEORB
-1, // doomednum
S_OVERTIMEORB, // 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
8<<FRACBITS, // radius
16<<FRACBITS, // height
-1, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags
S_NULL // raisestate
},
// ============================================================================================================================//
#ifdef SEENAMES

View file

@ -776,6 +776,8 @@ typedef enum sprite
SPR_FWRK,
SPR_OTFG,
// Xmas-specific sprites that don't fit aboxe
SPR_XMS4,
SPR_XMS5,
@ -4052,6 +4054,9 @@ typedef enum state
S_KARMAFIREWORK4,
S_KARMAFIREWORKTRAIL,
S_OVERTIMEFOG,
S_OVERTIMEORB,
#ifdef SEENAMES
S_NAMECHECK,
#endif
@ -4856,6 +4861,9 @@ typedef enum mobj_type
MT_KARMAFIREWORK,
MT_OVERTIMEFOG,
MT_OVERTIMEORB,
#ifdef SEENAMES
MT_NAMECHECK,
#endif

View file

@ -4223,6 +4223,25 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
player->mo->color = player->skincolor;
}
}
else if (player->kartstuff[k_killfield]) // You're gonna REALLY diiiiie
{
const INT32 flashtime = 4<<(4-(player->kartstuff[k_killfield]/TICRATE));
if (player->kartstuff[k_killfield] == 1 || (player->kartstuff[k_killfield] % (flashtime/2) != 0))
{
player->mo->colorized = false;
player->mo->color = player->skincolor;
}
else if (player->kartstuff[k_killfield] % flashtime == 0)
{
player->mo->colorized = true;
player->mo->color = SKINCOLOR_BYZANTIUM;
}
else
{
player->mo->colorized = true;
player->mo->color = SKINCOLOR_RUBY;
}
}
else
{
player->mo->colorized = false;
@ -4370,8 +4389,28 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
if (player->kartstuff[k_tauntvoices])
player->kartstuff[k_tauntvoices]--;
if (G_BattleGametype() && player->kartstuff[k_bumper] > 0)
if (G_BattleGametype() && player->kartstuff[k_bumper] > 0
&& !player->kartstuff[k_spinouttimer] && !player->kartstuff[k_squishedtimer]
&& !player->kartstuff[k_respawn] && !player->powers[pw_flashing])
{
player->kartstuff[k_wanted]++;
if (battleovertime->enabled)
{
if (P_AproxDistance(player->mo->x - battleovertime->x, player->mo->y - battleovertime->y) > (battleovertime->radius<<FRACBITS))
{
player->kartstuff[k_killfield]++;
if (player->kartstuff[k_killfield] > 4*TICRATE)
{
K_SpinPlayer(player, NULL, 0, NULL, false);
//player->kartstuff[k_killfield] = 1;
}
}
else if (player->kartstuff[k_killfield] > 0)
player->kartstuff[k_killfield]--;
}
}
else if (player->kartstuff[k_killfield] > 0)
player->kartstuff[k_killfield]--;
if (P_IsObjectOnGround(player->mo))
player->kartstuff[k_waterskip] = 0;

View file

@ -8234,7 +8234,7 @@ void A_ItemPop(mobj_t *actor)
remains->flags = actor->flags; // Transfer flags
remains->flags2 = actor->flags2; // Transfer flags2
remains->fuse = actor->fuse; // Transfer respawn timer
remains->threshold = (actor->threshold == 69 ? 69 : 68);
remains->threshold = (actor->threshold == 70 ? 70 : (actor->threshold == 69 ? 69 : 68));
remains->skin = NULL;
remains->spawnpoint = actor->spawnpoint;
@ -8248,7 +8248,7 @@ void A_ItemPop(mobj_t *actor)
remains->flags2 &= ~MF2_AMBUSH;
if (G_BattleGametype() && actor->threshold != 69)
if (G_BattleGametype() && (actor->threshold != 69 && actor->threshold != 70))
numgotboxes++;
P_RemoveMobj(actor);

View file

@ -1755,7 +1755,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
*/
void P_CheckTimeLimit(void)
{
INT32 i, k;
INT32 i;
if (!cv_timelimit.value)
return;
@ -1791,66 +1791,62 @@ void P_CheckTimeLimit(void)
}
//Optional tie-breaker for Match/CTF
else*/ if (cv_overtime.value)
else*/
#define TESTOVERTIMEINFREEPLAY
if (cv_overtime.value)
{
INT32 playerarray[MAXPLAYERS];
INT32 tempplayer = 0;
INT32 spectators = 0;
INT32 playercount = 0;
//Figure out if we have enough participating players to care.
#ifndef TESTOVERTIMEINFREEPLAY
boolean foundone = false; // Overtime is used for closing off down to a specific item.
for (i = 0; i < MAXPLAYERS; i++)
{
if (players[i].exiting)
return;
if (playeringame[i] && players[i].spectator)
spectators++;
}
if ((D_NumPlayers() - spectators) > 1)
{
// Play the starpost sfx after the first second of overtime.
if (gamestate == GS_LEVEL && (leveltime == (timelimitintics + TICRATE)))
S_StartSound(NULL, sfx_strpst);
// Normal Match
if (!G_GametypeHasTeams())
if (!playeringame[i] || players[i].spectator)
continue;
if (foundone)
{
//Store the nodes of participating players in an array.
for (i = 0; i < MAXPLAYERS; i++)
#endif
// Initiate the kill zone
if (!battleovertime->enabled)
{
if (playeringame[i] && !players[i].spectator)
{
playerarray[playercount] = i;
playercount++;
}
}
UINT8 b = 0;
thinker_t *th;
mobj_t *item = NULL;
//Sort 'em.
for (i = 1; i < playercount; i++)
{
for (k = i; k < playercount; k++)
// Find us an item box to center on.
for (th = thinkercap.next; th != &thinkercap; th = th->next)
{
if (players[playerarray[i-1]].marescore < players[playerarray[k]].marescore)
{
tempplayer = playerarray[i-1];
playerarray[i-1] = playerarray[k];
playerarray[k] = tempplayer;
}
}
}
mobj_t *thismo;
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
continue;
thismo = (mobj_t *)th;
//End the round if the top players aren't tied.
if (players[playerarray[0]].marescore == players[playerarray[1]].marescore)
return;
if (thismo->type != MT_RANDOMITEM)
continue;
if (thismo->threshold == 69) // Disappears
continue;
b++;
if (item == NULL || (b < nummapboxes && P_RandomChance(((nummapboxes-b)*FRACUNIT)/nummapboxes))) // This is to throw off the RNG some
item = thismo;
if (b >= nummapboxes) // end early if we've found them all already
break;
}
if (item == NULL) // no item found?!
return;
item->threshold = 70; // Set constant respawn
battleovertime->x = item->x;
battleovertime->y = item->y;
battleovertime->z = item->z;
battleovertime->radius = 4096;
battleovertime->enabled = true;
}
return;
#ifndef TESTOVERTIMEINFREEPLAY
}
else
{
//In team match and CTF, determining a tie is much simpler. =P
if (redscore == bluescore)
return;
}
foundone = true;
}
#endif
}
for (i = 0; i < MAXPLAYERS; i++)
@ -1861,9 +1857,6 @@ void P_CheckTimeLimit(void)
return;
P_DoPlayerExit(&players[i]);
}
/*if (server)
SendNetXCmd(XD_EXITLEVEL, NULL, 0);*/
}
/** Checks if a player's score is over the pointlimit and the round should end.

View file

@ -233,6 +233,7 @@ boolean P_SetMobjState(mobj_t *mobj, statenum_t state);
//void P_RunShields(void);
void P_RunOverlays(void);
void P_RunShadows(void);
void P_RunBattleOvertime(void);
void P_MobjThinker(mobj_t *mobj);
boolean P_RailThinker(mobj_t *mobj);
void P_PushableThinker(mobj_t *mobj);

View file

@ -6409,6 +6409,140 @@ static void P_RemoveShadow(mobj_t *thing)
}
}
// SAL'S KART BATTLE MODE OVERTIME HANDLER
#define MAXPLANESPERSECTOR (MAXFFLOORS+1)*2
static void P_SpawnOvertimeParticles(fixed_t x, fixed_t y, mobjtype_t type, boolean ceiling)
{
UINT8 i;
fixed_t flatz[MAXPLANESPERSECTOR];
UINT8 numflats = 0;
mobj_t *mo;
subsector_t *ss = R_IsPointInSubsector(x, y);
sector_t *sec;
if (!ss)
return;
sec = ss->sector;
// convoluted stuff JUST to get all of the planes we need to draw orbs on :V
if (sec->floorpic != skyflatnum)
{
#ifdef ESLOPE
flatz[numflats] = (sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : sec->floorheight);
#else
flatz[numflats] = (sec->floorheight);
#endif
numflats++;
}
if (sec->ceilingpic != skyflatnum && ceiling)
{
#ifdef ESLOPE
flatz[numflats] = (sec->c_slope ? P_GetZAt(sec->c_slope, x, y) : sec->ceilingheight) - mobjinfo[MT_THOK].height;
#else
flatz[numflats] = (sec->ceilingheight) - mobjinfo[MT_THOK].height;
#endif
numflats++;
}
if (sec->ffloors)
{
ffloor_t *rover;
for (rover = sec->ffloors; rover; rover = rover->next)
{
if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BLOCKPLAYER))
continue;
if (*rover->toppic != skyflatnum)
{
#ifdef ESLOPE
flatz[numflats] = (*rover->t_slope ? P_GetZAt(*rover->t_slope, x, y) : *rover->topheight);
#else
flatz[numflats] = (*rover->topheight);
#endif
numflats++;
}
if (*rover->bottompic != skyflatnum && ceiling)
{
#ifdef ESLOPE
flatz[numflats] = (*rover->b_slope ? P_GetZAt(*rover->b_slope, x, y) : *rover->bottomheight) - mobjinfo[MT_THOK].height;
#else
flatz[numflats] = (*rover->bottomheight) - mobjinfo[MT_THOK].height;
#endif
numflats++;
}
}
}
if (numflats <= 0) // no flats
return;
for (i = 0; i < numflats; i++)
{
mo = P_SpawnMobj(x, y, flatz[i], type);
// Lastly, if this can see the skybox mobj, then... we just wasted our time :V
if (skyboxmo[0] && !P_MobjWasRemoved(skyboxmo[0]) && P_CheckSight(skyboxmo[0], mo))
{
P_RemoveMobj(mo);
continue;
}
switch(type)
{
case MT_OVERTIMEFOG:
P_SetScale(mo, 2*mo->scale);
mo->destscale = 8*mo->scale;
mo->momz = P_RandomRange(1,8)*mo->scale;
break;
case MT_OVERTIMEORB:
P_SetScale(mo, 2*mo->scale);
mo->destscale = mo->scale/4;
if ((leveltime/2) & 1)
mo->frame++;
break;
default:
break;
}
}
}
#undef MAXPLANESPERSECTOR
void P_RunBattleOvertime(void)
{
UINT8 i, j;
if (battleovertime->radius > 512)
battleovertime->radius--;
else
battleovertime->radius = 512;
if (leveltime & 1)
{
for (i = 0; i < 16; i++) // 16 base orbs
{
angle_t ang = FixedAngle(((45*i) * (FRACUNIT>>1)) + ((leveltime % 360)<<FRACBITS));
fixed_t x = battleovertime->x + P_ReturnThrustX(NULL, ang, battleovertime->radius<<FRACBITS);
fixed_t y = battleovertime->y + P_ReturnThrustY(NULL, ang, battleovertime->radius<<FRACBITS);
P_SpawnOvertimeParticles(x, y, MT_OVERTIMEORB, true);
}
}
for (i = 0; i < 16; i++)
{
j = 0;
while (j < 32) // max attempts
{
fixed_t x = battleovertime->x + ((P_RandomRange(-64,64) * 128)<<FRACBITS);
fixed_t y = battleovertime->y + ((P_RandomRange(-64,64) * 128)<<FRACBITS);
j++;
if (P_AproxDistance(x-battleovertime->x, y-battleovertime->y) <= (battleovertime->radius<<FRACBITS))
continue;
P_SpawnOvertimeParticles(x, y, MT_OVERTIMEFOG, false);
break;
}
}
}
void A_BossDeath(mobj_t *mo);
// AI for the Koopa boss.
static void P_KoopaThinker(mobj_t *koopa)
@ -9372,10 +9506,13 @@ for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) s
P_RemoveMobj(mobj); // make sure they disappear
return;
case MT_RANDOMITEM:
if (G_BattleGametype())
if (G_BattleGametype() && (mobj->threshold != 70))
{
if (mobj->threshold != 69)
{
mobj->fuse = cv_itemrespawntime.value*TICRATE + 2;
break;
}
}
else
{
@ -9390,6 +9527,8 @@ for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) s
// Transfer flags2 (strongbox, objectflip)
newmobj->flags2 = mobj->flags2 & ~MF2_DONTDRAW;
if (mobj->threshold == 70)
newmobj->threshold = 70;
}
P_RemoveMobj(mobj); // make sure they disappear
return;

View file

@ -961,8 +961,8 @@ typedef enum
MD2_EXTVAL2 = 1<<6,
MD2_HNEXT = 1<<7,
MD2_HPREV = 1<<8,
MD2_COLORIZED = 1<<9,
MD2_WAYPOINTCAP = 1<<10
MD2_COLORIZED = 1<<9,
MD2_WAYPOINTCAP = 1<<10
#ifdef ESLOPE
, MD2_SLOPE = 1<<11
#endif
@ -3298,6 +3298,13 @@ static void P_NetArchiveMisc(void)
for (i = 0; i < 4; i++)
WRITESINT8(save_p, battlewanted[i]);
// battleovertime_t
WRITEUINT8(save_p, battleovertime->enabled);
WRITEUINT16(save_p, battleovertime->radius);
WRITEFIXED(save_p, battleovertime->x);
WRITEFIXED(save_p, battleovertime->y);
WRITEFIXED(save_p, battleovertime->z);
WRITEUINT32(save_p, wantedcalcdelay);
WRITEUINT32(save_p, indirectitemcooldown);
WRITEUINT32(save_p, mapreset);
@ -3405,6 +3412,13 @@ static inline boolean P_NetUnArchiveMisc(void)
for (i = 0; i < 4; i++)
battlewanted[i] = READSINT8(save_p);
// battleovertime_t
battleovertime->enabled = (boolean)READUINT8(save_p);
battleovertime->radius = READUINT16(save_p);
battleovertime->x = READFIXED(save_p);
battleovertime->y = READFIXED(save_p);
battleovertime->z = READFIXED(save_p);
wantedcalcdelay = READUINT32(save_p);
indirectitemcooldown = READUINT32(save_p);
mapreset = READUINT32(save_p);

View file

@ -2373,6 +2373,10 @@ static void P_LevelInitStuff(void)
for (i = 0; i < 4; i++)
battlewanted[i] = -1;
if (!battleovertime)
battleovertime = Z_Malloc(sizeof(battleovertime_t), PU_STATIC, NULL);
memset(battleovertime, 0, sizeof(battleovertime_t));
}
//

View file

@ -621,6 +621,8 @@ void P_Ticker(boolean run)
if (run)
{
P_RunThinkers();
if (G_BattleGametype() && battleovertime->enabled)
P_RunBattleOvertime();
// Run any "after all the other thinkers" stuff
for (i = 0; i < MAXPLAYERS; i++)
@ -760,6 +762,8 @@ void P_PreTicker(INT32 frames)
}
P_RunThinkers();
if (G_BattleGametype() && battleovertime->enabled)
P_RunBattleOvertime();
// Run any "after all the other thinkers" stuff
for (i = 0; i < MAXPLAYERS; i++)