Functional gameplay

- Capsules get spawned in the proper scenarios
- Level ends when all capsules are busted
- Time gets used on the leaderboard instead of score

Also split a handful of Battle code into k_battle.c. Lots of other code could probably get moved here later
This commit is contained in:
TehRealSalt 2019-09-15 20:19:48 -04:00
parent 2648e5d3de
commit 1ef09699d1
18 changed files with 515 additions and 341 deletions

View file

@ -490,6 +490,7 @@ OBJS:=$(i_main_o) \
$(OBJDIR)/st_stuff.o \
$(OBJDIR)/k_kart.o \
$(OBJDIR)/k_collide.o\
$(OBJDIR)/k_battle.o \
$(OBJDIR)/m_aatree.o \
$(OBJDIR)/m_anigif.o \
$(OBJDIR)/m_argv.o \

View file

@ -47,6 +47,7 @@
#include "lua_script.h"
#include "lua_hook.h"
#include "k_kart.h"
#include "k_battle.h"
#ifdef CLIENT_LOADINGSCREEN
// cl loading screen

View file

@ -47,6 +47,7 @@
#include "m_cond.h"
#include "m_anigif.h"
#include "k_kart.h" // SRB2kart
#include "k_battle.h"
#include "y_inter.h"
#ifdef NETGAME_DEVMODE

View file

@ -353,7 +353,10 @@ extern UINT16 emeralds;
#define EMERALD7 64
#define ALL7EMERALDS(v) ((v & (EMERALD1|EMERALD2|EMERALD3|EMERALD4|EMERALD5|EMERALD6|EMERALD7)) == (EMERALD1|EMERALD2|EMERALD3|EMERALD4|EMERALD5|EMERALD6|EMERALD7))
extern INT32 nummaprings, nummapboxes, numgotboxes; //keep track of spawned rings/coins/battle mode items
extern INT32 nummaprings; // keep track of spawned rings/coins
extern INT32 nummapboxes, numgotboxes; // keep track of spawned battle mode items
extern UINT8 maptargets, numtargets; // Keep track of spawend Battle Mode targets
extern boolean targetsspawned; // have targets been spawned already?
/** Time attack information, currently a very small structure.
*/

View file

@ -48,6 +48,7 @@
#include "m_cond.h" // condition sets
#include "md5.h" // demo checksums
#include "k_kart.h" // SRB2kart
#include "k_battle.h"
gameaction_t gameaction;
gamestate_t gamestate = GS_NULL;
@ -188,6 +189,11 @@ INT32 nummaprings = 0;
INT32 nummapboxes = 0;
INT32 numgotboxes = 0;
// Break the Capsules counters for Battle Mode!
UINT8 maptargets = 0; // targets in map
UINT8 numtargets = 0; // targets busted
boolean targetsspawned = false; // have targets been spawned already?
// Elminates unnecessary searching.
boolean CheckForBustableBlocks;
boolean CheckForBouncySector;

436
src/k_battle.c Normal file
View file

@ -0,0 +1,436 @@
/// \file k_battle.c
/// \brief SRB2Kart Battle Mode specific code
#include "k_battle.h"
#include "k_kart.h"
#include "doomtype.h"
#include "doomdata.h"
#include "g_game.h"
#include "p_mobj.h"
#include "p_local.h"
#include "p_setup.h"
#include "p_slopes.h" // P_GetZAt
#include "r_main.h"
#include "r_defs.h" // MAXFFLOORS
#include "info.h"
boolean K_IsPlayerWanted(player_t *player)
{
UINT8 i;
if (!(G_BattleGametype()))
return false;
for (i = 0; i < 4; i++)
{
if (battlewanted[i] == -1)
break;
if (player == &players[battlewanted[i]])
return true;
}
return false;
}
void K_CalculateBattleWanted(void)
{
UINT8 numingame = 0, numplaying = 0, numwanted = 0;
SINT8 bestbumperplayer = -1, bestbumper = -1;
SINT8 camppos[MAXPLAYERS]; // who is the biggest camper
UINT8 ties = 0, nextcamppos = 0;
boolean setbumper = false;
UINT8 i, j;
if (!G_BattleGametype())
{
for (i = 0; i < 4; i++)
battlewanted[i] = -1;
return;
}
wantedcalcdelay = wantedfrequency;
for (i = 0; i < MAXPLAYERS; i++)
camppos[i] = -1; // initialize
for (i = 0; i < MAXPLAYERS; i++)
{
UINT8 position = 1;
if (!playeringame[i] || players[i].spectator) // Not playing
continue;
if (players[i].exiting) // We're done, don't calculate.
return;
numplaying++;
if (players[i].kartstuff[k_bumper] <= 0) // Not alive, so don't do anything else
continue;
numingame++;
if (bestbumper == -1 || players[i].kartstuff[k_bumper] > bestbumper)
{
bestbumper = players[i].kartstuff[k_bumper];
bestbumperplayer = i;
}
else if (players[i].kartstuff[k_bumper] == bestbumper)
bestbumperplayer = -1; // Tie, no one has best bumper.
for (j = 0; j < MAXPLAYERS; j++)
{
if (!playeringame[j] || players[j].spectator)
continue;
if (players[j].kartstuff[k_bumper] <= 0)
continue;
if (j == i)
continue;
if (players[j].kartstuff[k_wanted] == players[i].kartstuff[k_wanted] && players[j].marescore > players[i].marescore)
position++;
else if (players[j].kartstuff[k_wanted] > players[i].kartstuff[k_wanted])
position++;
}
position--; // Make zero based
while (camppos[position] != -1) // Port priority!
position++;
camppos[position] = i;
}
if (numplaying <= 2 || (numingame <= 2 && bestbumper == 1)) // In 1v1s then there's no need for WANTED. In bigger netgames, don't show anyone as WANTED when they're equally matched.
numwanted = 0;
else
numwanted = min(4, 1 + ((numingame-2) / 4));
for (i = 0; i < 4; i++)
{
if (i+1 > numwanted) // Not enough players for this slot to be wanted!
battlewanted[i] = -1;
else if (bestbumperplayer != -1 && !setbumper) // If there's a player who has an untied bumper lead over everyone else, they are the first to be wanted.
{
battlewanted[i] = bestbumperplayer;
setbumper = true; // Don't set twice
}
else
{
// Don't accidentally set the same player, if the bestbumperplayer is also a huge camper.
while (bestbumperplayer != -1 && camppos[nextcamppos] != -1
&& bestbumperplayer == camppos[nextcamppos])
nextcamppos++;
// Do not add *any* more people if there's too many times that are tied with others.
// This could theoretically happen very easily if people don't hit each other for a while after the start of a match.
// (I will be sincerely impressed if more than 2 people tie after people start hitting each other though)
if (camppos[nextcamppos] == -1 // Out of entries
|| ties >= (numwanted-i)) // Already counted ties
{
battlewanted[i] = -1;
continue;
}
if (ties < (numwanted-i))
{
ties = 0; // Reset
for (j = 0; j < 2; j++)
{
if (camppos[nextcamppos+(j+1)] == -1) // Nothing beyond, cancel
break;
if (players[camppos[nextcamppos]].kartstuff[k_wanted] == players[camppos[nextcamppos+(j+1)]].kartstuff[k_wanted])
ties++;
}
}
if (ties < (numwanted-i)) // Is it still low enough after counting?
{
battlewanted[i] = camppos[nextcamppos];
nextcamppos++;
}
else
battlewanted[i] = -1;
}
}
}
void K_SpawnBattlePoints(player_t *source, player_t *victim, UINT8 amount)
{
statenum_t st;
mobj_t *pt;
if (!source || !source->mo)
return;
if (amount == 1)
st = S_BATTLEPOINT1A;
else if (amount == 2)
st = S_BATTLEPOINT2A;
else if (amount == 3)
st = S_BATTLEPOINT3A;
else
return; // NO STATE!
pt = P_SpawnMobj(source->mo->x, source->mo->y, source->mo->z, MT_BATTLEPOINT);
P_SetTarget(&pt->target, source->mo);
P_SetMobjState(pt, st);
if (victim && victim->skincolor)
pt->color = victim->skincolor;
else
pt->color = source->skincolor;
}
void K_CheckBumpers(void)
{
UINT8 i;
UINT8 numingame = 0;
SINT8 winnernum = -1;
INT32 winnerscoreadd = 0;
if (!multiplayer)
return;
if (!G_BattleGametype())
return;
if (gameaction == ga_completed)
return;
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator) // not even in-game
continue;
if (players[i].exiting) // we're already exiting! stop!
return;
numingame++;
winnerscoreadd += players[i].marescore;
if (players[i].kartstuff[k_bumper] <= 0) // if you don't have any bumpers, you're probably not a winner
continue;
else if (winnernum > -1) // TWO winners? that's dumb :V
return;
winnernum = i;
winnerscoreadd -= players[i].marescore;
}
if (numingame <= 1)
{
K_SpawnBattleCapsules();
return;
}
if (winnernum > -1 && playeringame[winnernum])
{
players[winnernum].marescore += winnerscoreadd;
CONS_Printf(M_GetText("%s recieved %d point%s for winning!\n"), player_names[winnernum], winnerscoreadd, (winnerscoreadd == 1 ? "" : "s"));
}
for (i = 0; i < MAXPLAYERS; i++) // This can't go in the earlier loop because winning adds points
K_KartUpdatePosition(&players[i]);
for (i = 0; i < MAXPLAYERS; i++) // and it can't be merged with this loop because it needs to be all updated before exiting... multi-loops suck...
P_DoPlayerExit(&players[i]);
}
void K_SpawnBattleCapsules(void)
{
mapthing_t *mt;
UINT8 n = 0;
size_t i;
if (targetsspawned)
return;
if (!G_BattleGametype())
return;
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && !players[i].spectator)
n++;
if (players[i].exiting)
return;
if (n > 1)
break;
}
if (n > 1)
return;
mt = mapthings;
for (i = 0; i < nummapthings; i++, mt++)
{
if (mt->type == mobjinfo[MT_BATTLECAPSULE].doomednum)
{
sector_t *mtsector, *sec;
fixed_t x, y, z;
fixed_t floorheights[MAXFFLOORS+1];
UINT8 numfloors = 1;
mobj_t *mobj = NULL;
boolean fly = true;
mt->mobj = NULL;
mtsector = R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS)->sector;
mt->z = (INT16)(
#ifdef ESLOPE
mtsector->f_slope ? P_GetZAt(mtsector->f_slope, mt->x << FRACBITS, mt->y << FRACBITS) :
#endif
mtsector->floorheight)>>FRACBITS;
x = mt->x << FRACBITS;
y = mt->y << FRACBITS;
sec = R_PointInSubsector(x, y)->sector;
if (mt->options & MTF_OBJECTFLIP)
{
z = (
#ifdef ESLOPE
sec->c_slope ? P_GetZAt(sec->c_slope, x, y) :
#endif
sec->ceilingheight) - mobjinfo[MT_BATTLECAPSULE].height;
floorheights[0] = z;
if (mt->options >> ZSHIFT)
z -= ((mt->options >> ZSHIFT) << FRACBITS);
}
else
{
z =
#ifdef ESLOPE
sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
#endif
sec->floorheight;
floorheights[0] = z;
if (mt->options >> ZSHIFT)
z += ((mt->options >> ZSHIFT) << FRACBITS);
}
if (sec->ffloors)
{
ffloor_t *rover;
for (rover = sec->ffloors; rover; rover = rover->next)
{
if ((rover->flags & FF_EXISTS) && (rover->flags & FF_BLOCKOTHERS))
{
if (mt->options & MTF_OBJECTFLIP)
{
floorheights[numfloors] = (
#ifdef ESLOPE
*rover->b_slope ? P_GetZAt(*rover->b_slope, x, y) :
#endif
*rover->bottomheight) - mobjinfo[MT_BATTLECAPSULE].height;
}
else
{
floorheights[numfloors] = (
#ifdef ESLOPE
*rover->t_slope ? P_GetZAt(*rover->t_slope, x, y) :
#endif
*rover->topheight);
}
numfloors++;
}
}
}
mt->z = (INT16)(z>>FRACBITS);
mobj = P_SpawnMobj(x, y, z, MT_BATTLECAPSULE);
mobj->spawnpoint = mt;
if (mt->options & MTF_OBJECTFLIP)
{
mobj->eflags |= MFE_VERTICALFLIP;
mobj->flags2 |= MF2_OBJECTFLIP;
}
for (i = 0; i < numfloors; i++)
{
if (z == floorheights[i])
{
fly = false;
break;
}
}
// Flying capsules
if (fly)
{
mobj->flags |= MF_NOGRAVITY;
mobj->extravalue1 = 1; // Set extravalue1 for later reference
}
// Moved from P_SpawnMobj due to order of operations mumbo jumbo
{
mobj_t *cur, *prev = mobj;
// Init hnext list
// Spherical top
cur = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_BATTLECAPSULE_PIECE);
P_SetMobjState(cur, S_BATTLECAPSULE_TOP);
P_SetTarget(&cur->target, mobj);
P_SetTarget(&cur->hprev, prev);
P_SetTarget(&prev->hnext, cur);
prev = cur;
// Tippity-top decorational button
cur = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_BATTLECAPSULE_PIECE);
P_SetMobjState(cur, S_BATTLECAPSULE_BUTTON);
P_SetTarget(&cur->target, mobj);
P_SetTarget(&cur->hprev, prev);
P_SetTarget(&prev->hnext, cur);
prev = cur;
// Supports on the bottom
for (i = 0; i < 4; i++)
{
cur = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_BATTLECAPSULE_PIECE);
cur->extravalue1 = i;
// TODO: use karma bomb wheels on grounded, moving capsules
if (mobj->extravalue1)
P_SetMobjState(cur, S_BATTLECAPSULE_SUPPORTFLY);
else
P_SetMobjState(cur, S_BATTLECAPSULE_SUPPORT);
P_SetTarget(&cur->target, mobj);
P_SetTarget(&cur->hprev, prev);
P_SetTarget(&prev->hnext, cur);
prev = cur;
}
// Side paneling
for (i = 0; i < 8; i++)
{
cur = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_BATTLECAPSULE_PIECE);
cur->extravalue1 = i;
if (i & 1)
P_SetMobjState(cur, S_BATTLECAPSULE_SIDE2);
else
P_SetMobjState(cur, S_BATTLECAPSULE_SIDE1);
P_SetTarget(&cur->target, mobj);
P_SetTarget(&cur->hprev, prev);
P_SetTarget(&prev->hnext, cur);
prev = cur;
}
}
mobj->angle = FixedAngle(mt->angle * FRACUNIT);
mt->mobj = mobj;
}
}
targetsspawned = true;
}

13
src/k_battle.h Normal file
View file

@ -0,0 +1,13 @@
#ifndef __K_BATTLE__
#define __K_BATTLE__
#include "doomtype.h"
#include "d_player.h"
boolean K_IsPlayerWanted(player_t *player);
void K_CalculateBattleWanted(void);
void K_SpawnBattlePoints(player_t *source, player_t *victim, UINT8 amount);
void K_CheckBumpers(void);
void K_SpawnBattleCapsules(void);
#endif

View file

@ -4,6 +4,8 @@
/// \brief SRB2kart general.
/// All of the SRB2kart-unique stuff.
#include "k_kart.h"
#include "k_battle.h"
#include "doomdef.h"
#include "hu_stuff.h"
#include "g_game.h"
@ -18,7 +20,6 @@
#include "z_zone.h"
#include "m_misc.h"
#include "m_cond.h"
#include "k_kart.h"
#include "f_finale.h"
#include "lua_hud.h" // For Lua hud checks
#include "lua_hook.h" // For MobjDamage and ShouldDamage
@ -621,21 +622,6 @@ boolean K_IsPlayerLosing(player_t *player)
return (player->kartstuff[k_position] > winningpos);
}
boolean K_IsPlayerWanted(player_t *player)
{
UINT8 i;
if (!(G_BattleGametype()))
return false;
for (i = 0; i < 4; i++)
{
if (battlewanted[i] == -1)
break;
if (player == &players[battlewanted[i]])
return true;
}
return false;
}
fixed_t K_GetKartGameSpeedScalar(SINT8 value)
{
// Easy = 81.25%
@ -2374,32 +2360,6 @@ void K_DoInstashield(player_t *player)
P_SetTarget(&layerb->target, player->mo);
}
void K_SpawnBattlePoints(player_t *source, player_t *victim, UINT8 amount)
{
statenum_t st;
mobj_t *pt;
if (!source || !source->mo)
return;
if (amount == 1)
st = S_BATTLEPOINT1A;
else if (amount == 2)
st = S_BATTLEPOINT2A;
else if (amount == 3)
st = S_BATTLEPOINT3A;
else
return; // NO STATE!
pt = P_SpawnMobj(source->mo->x, source->mo->y, source->mo->z, MT_BATTLEPOINT);
P_SetTarget(&pt->target, source->mo);
P_SetMobjState(pt, st);
if (victim && victim->skincolor)
pt->color = victim->skincolor;
else
pt->color = source->skincolor;
}
void K_SpinPlayer(player_t *player, mobj_t *source, INT32 type, mobj_t *inflictor, boolean trapitem)
{
UINT8 scoremultiply = 1;
@ -6639,181 +6599,6 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
}
}
void K_CalculateBattleWanted(void)
{
UINT8 numingame = 0, numplaying = 0, numwanted = 0;
SINT8 bestbumperplayer = -1, bestbumper = -1;
SINT8 camppos[MAXPLAYERS]; // who is the biggest camper
UINT8 ties = 0, nextcamppos = 0;
boolean setbumper = false;
UINT8 i, j;
if (!G_BattleGametype())
{
for (i = 0; i < 4; i++)
battlewanted[i] = -1;
return;
}
wantedcalcdelay = wantedfrequency;
for (i = 0; i < MAXPLAYERS; i++)
camppos[i] = -1; // initialize
for (i = 0; i < MAXPLAYERS; i++)
{
UINT8 position = 1;
if (!playeringame[i] || players[i].spectator) // Not playing
continue;
if (players[i].exiting) // We're done, don't calculate.
return;
numplaying++;
if (players[i].kartstuff[k_bumper] <= 0) // Not alive, so don't do anything else
continue;
numingame++;
if (bestbumper == -1 || players[i].kartstuff[k_bumper] > bestbumper)
{
bestbumper = players[i].kartstuff[k_bumper];
bestbumperplayer = i;
}
else if (players[i].kartstuff[k_bumper] == bestbumper)
bestbumperplayer = -1; // Tie, no one has best bumper.
for (j = 0; j < MAXPLAYERS; j++)
{
if (!playeringame[j] || players[j].spectator)
continue;
if (players[j].kartstuff[k_bumper] <= 0)
continue;
if (j == i)
continue;
if (players[j].kartstuff[k_wanted] == players[i].kartstuff[k_wanted] && players[j].marescore > players[i].marescore)
position++;
else if (players[j].kartstuff[k_wanted] > players[i].kartstuff[k_wanted])
position++;
}
position--; // Make zero based
while (camppos[position] != -1) // Port priority!
position++;
camppos[position] = i;
}
if (numplaying <= 2 || (numingame <= 2 && bestbumper == 1)) // In 1v1s then there's no need for WANTED. In bigger netgames, don't show anyone as WANTED when they're equally matched.
numwanted = 0;
else
numwanted = min(4, 1 + ((numingame-2) / 4));
for (i = 0; i < 4; i++)
{
if (i+1 > numwanted) // Not enough players for this slot to be wanted!
battlewanted[i] = -1;
else if (bestbumperplayer != -1 && !setbumper) // If there's a player who has an untied bumper lead over everyone else, they are the first to be wanted.
{
battlewanted[i] = bestbumperplayer;
setbumper = true; // Don't set twice
}
else
{
// Don't accidentally set the same player, if the bestbumperplayer is also a huge camper.
while (bestbumperplayer != -1 && camppos[nextcamppos] != -1
&& bestbumperplayer == camppos[nextcamppos])
nextcamppos++;
// Do not add *any* more people if there's too many times that are tied with others.
// This could theoretically happen very easily if people don't hit each other for a while after the start of a match.
// (I will be sincerely impressed if more than 2 people tie after people start hitting each other though)
if (camppos[nextcamppos] == -1 // Out of entries
|| ties >= (numwanted-i)) // Already counted ties
{
battlewanted[i] = -1;
continue;
}
if (ties < (numwanted-i))
{
ties = 0; // Reset
for (j = 0; j < 2; j++)
{
if (camppos[nextcamppos+(j+1)] == -1) // Nothing beyond, cancel
break;
if (players[camppos[nextcamppos]].kartstuff[k_wanted] == players[camppos[nextcamppos+(j+1)]].kartstuff[k_wanted])
ties++;
}
}
if (ties < (numwanted-i)) // Is it still low enough after counting?
{
battlewanted[i] = camppos[nextcamppos];
nextcamppos++;
}
else
battlewanted[i] = -1;
}
}
}
void K_CheckBumpers(void)
{
UINT8 i;
UINT8 numingame = 0;
SINT8 winnernum = -1;
INT32 winnerscoreadd = 0;
if (!multiplayer)
return;
if (!G_BattleGametype())
return;
if (gameaction == ga_completed)
return;
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator) // not even in-game
continue;
if (players[i].exiting) // we're already exiting! stop!
return;
numingame++;
winnerscoreadd += players[i].marescore;
if (players[i].kartstuff[k_bumper] <= 0) // if you don't have any bumpers, you're probably not a winner
continue;
else if (winnernum > -1) // TWO winners? that's dumb :V
return;
winnernum = i;
winnerscoreadd -= players[i].marescore;
}
if (numingame <= 1)
return;
if (winnernum > -1 && playeringame[winnernum])
{
players[winnernum].marescore += winnerscoreadd;
CONS_Printf(M_GetText("%s recieved %d point%s for winning!\n"), player_names[winnernum], winnerscoreadd, (winnerscoreadd == 1 ? "" : "s"));
}
for (i = 0; i < MAXPLAYERS; i++) // This can't go in the earlier loop because winning adds points
K_KartUpdatePosition(&players[i]);
for (i = 0; i < MAXPLAYERS; i++) // and it can't be merged with this loop because it needs to be all updated before exiting... multi-loops suck...
P_DoPlayerExit(&players[i]);
}
void K_CheckSpectateStatus(void)
{
UINT8 respawnlist[MAXPLAYERS];

View file

@ -21,7 +21,6 @@ UINT8 K_GetKartColorByName(const char *name);
void K_RegisterKartStuff(void);
boolean K_IsPlayerLosing(player_t *player);
boolean K_IsPlayerWanted(player_t *player);
fixed_t K_GetKartGameSpeedScalar(SINT8 value);
void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid);
void K_KartPainEnergyFling(player_t *player);
@ -33,7 +32,6 @@ void K_KartPlayerHUDUpdate(player_t *player);
void K_KartPlayerThink(player_t *player, ticcmd_t *cmd);
void K_KartPlayerAfterThink(player_t *player);
void K_DoInstashield(player_t *player);
void K_SpawnBattlePoints(player_t *source, player_t *victim, UINT8 amount);
void K_SpinPlayer(player_t *player, mobj_t *source, INT32 type, mobj_t *inflictor, boolean trapitem);
void K_SquishPlayer(player_t *player, mobj_t *source, mobj_t *inflictor);
void K_ExplodePlayer(player_t *player, mobj_t *source, mobj_t *inflictor);
@ -66,8 +64,6 @@ fixed_t K_GetKartAccel(player_t *player);
UINT16 K_GetKartFlashing(player_t *player);
fixed_t K_3dKartMovement(player_t *player, boolean onground, fixed_t forwardmove);
void K_MoveKartPlayer(player_t *player, boolean onground);
void K_CalculateBattleWanted(void);
void K_CheckBumpers(void);
void K_CheckSpectateStatus(void);
// sound stuff for lua

View file

@ -26,6 +26,7 @@
#include "hu_stuff.h" // HU_AddChatText
#include "console.h"
#include "k_kart.h" // SRB2Kart
#include "k_battle.h"
#include "d_netcmd.h" // IsPlayerAdmin
#include "lua_script.h"

View file

@ -27,6 +27,7 @@
#include "m_misc.h"
#include "v_video.h" // video flags for CEchos
#include "k_kart.h" // SRB2kart
#include "k_battle.h"
// CTF player names
#define CTFTEAMCODE(pl) pl->ctfteam ? (pl->ctfteam == 1 ? "\x85" : "\x84") : ""
@ -2528,7 +2529,9 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source)
{
mobj_t *cur;
numtargets++;
target->fuse = 16;
target->flags |= MF_NOCLIP|MF_NOCLIPTHING;
cur = target->hnext;
@ -2551,6 +2554,14 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source)
cur = cur->hnext;
}
// All targets busted!
if (numtargets >= maptargets)
{
UINT8 i;
for (i = 0; i < MAXPLAYERS; i++)
P_DoPlayerExit(&players[i]);
}
}
break;

View file

@ -36,6 +36,7 @@
#endif
#include "k_kart.h"
#include "k_battle.h"
// protos.
//static CV_PossibleValue_t viewheight_cons_t[] = {{16, "MIN"}, {56, "MAX"}, {0, NULL}};
@ -10210,73 +10211,6 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
}
}
break;
case MT_BATTLECAPSULE:
{
mobj_t *cur, *prev = mobj;
UINT8 i;
// Flying capsules
if (!(mobj->eflags & MFE_ONGROUND))
{
mobj->flags |= MF_NOGRAVITY;
mobj->extravalue1 = 1; // Set extravalue1 for later reference
}
// Init hnext list
// Spherical top
cur = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_BATTLECAPSULE_PIECE);
P_SetMobjState(cur, S_BATTLECAPSULE_TOP);
P_SetTarget(&cur->target, mobj);
P_SetTarget(&cur->hprev, prev);
P_SetTarget(&prev->hnext, cur);
prev = cur;
// Tippity-top decorational button
cur = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_BATTLECAPSULE_PIECE);
P_SetMobjState(cur, S_BATTLECAPSULE_BUTTON);
P_SetTarget(&cur->target, mobj);
P_SetTarget(&cur->hprev, prev);
P_SetTarget(&prev->hnext, cur);
prev = cur;
// Supports on the bottom
for (i = 0; i < 4; i++)
{
cur = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_BATTLECAPSULE_PIECE);
cur->extravalue1 = i;
// TODO: use karma bomb wheels on grounded, moving capsules
if (mobj->extravalue1)
P_SetMobjState(cur, S_BATTLECAPSULE_SUPPORTFLY);
else
P_SetMobjState(cur, S_BATTLECAPSULE_SUPPORT);
P_SetTarget(&cur->target, mobj);
P_SetTarget(&cur->hprev, prev);
P_SetTarget(&prev->hnext, cur);
prev = cur;
}
// Side paneling
for (i = 0; i < 8; i++)
{
cur = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_BATTLECAPSULE_PIECE);
cur->extravalue1 = i;
if (i & 1)
P_SetMobjState(cur, S_BATTLECAPSULE_SIDE2);
else
P_SetMobjState(cur, S_BATTLECAPSULE_SIDE1);
P_SetTarget(&cur->target, mobj);
P_SetTarget(&cur->hprev, prev);
P_SetTarget(&prev->hnext, cur);
prev = cur;
}
}
break;
default:
break;
}

View file

@ -3277,6 +3277,8 @@ static void P_NetArchiveMisc(void)
// SRB2kart
WRITEINT32(save_p, numgotboxes);
WRITEUINT8(save_p, numtargets);
WRITEUINT8(save_p, targetsspawned);
WRITEUINT8(save_p, gamespeed);
WRITEUINT8(save_p, franticitems);
@ -3386,6 +3388,8 @@ static inline boolean P_NetUnArchiveMisc(void)
// SRB2kart
numgotboxes = READINT32(save_p);
numtargets = READUINT8(save_p);
targetsspawned = (boolean)READUINT8(save_p);
gamespeed = READUINT8(save_p);
franticitems = (boolean)READUINT8(save_p);

View file

@ -84,6 +84,7 @@
// SRB2Kart
#include "k_kart.h"
#include "k_battle.h" // K_SpawnBattleCapsules
//
// Map MD5, calculated on level load.
@ -1021,6 +1022,12 @@ static void P_LoadThings(void)
if (mt->type == mobjinfo[MT_RANDOMITEM].doomednum)
nummapboxes++;
if (mt->type == mobjinfo[MT_BATTLECAPSULE].doomednum)
{
maptargets++;
continue; // These should not be spawned *yet*
}
mt->mobj = NULL;
P_SpawnMapThing(mt);
}
@ -1077,14 +1084,19 @@ static void P_LoadThings(void)
for (i = 0; i < nummapthings; i++, mt++)
{
if (mt->type == 300 || mt->type == 308 || mt->type == 309
|| mt->type == 1706 || (mt->type >= 600 && mt->type <= 609)
|| mt->type == 1705 || mt->type == 1713 || mt->type == 1800)
|| mt->type == 1706 || (mt->type >= 600 && mt->type <= 609)
|| mt->type == 1705 || mt->type == 1713 || mt->type == 1800)
{
sector_t *mtsector = R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS)->sector;
mt->mobj = NULL;
// Z for objects Tails 05-26-2002
mt->z = (INT16)(R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS)
->sector->floorheight>>FRACBITS);
// Z for objects
mt->z = (INT16)(
#ifdef ESLOPE
mtsector->f_slope ? P_GetZAt(mtsector->f_slope, mt->x << FRACBITS, mt->y << FRACBITS) :
#endif
mtsector->floorheight)>>FRACBITS;
P_SpawnHoopsAndRings (mt);
}
@ -2291,15 +2303,13 @@ static void P_LevelInitStuff(void)
memset(localaiming, 0, sizeof(localaiming));
// map object scale
mapobjectscale = mapheaderinfo[gamemap-1]->mobj_scale;
// special stage tokens, emeralds, and ring total
tokenbits = 0;
runemeraldmanager = false;
nummaprings = 0;
nummapboxes = 0;
numgotboxes = 0;
nummapboxes = numgotboxes = 0;
maptargets = numtargets = 0;
targetsspawned = false;
// emerald hunt
hunt1 = hunt2 = hunt3 = NULL;
@ -3140,44 +3150,7 @@ boolean P_SetupLevel(boolean skipprecip)
/*else if (modeattacking == ATTACKING_NIGHTS && !demo.playback)
P_LoadNightsGhosts();*/
if (G_TagGametype())
{
INT32 realnumplayers = 0;
INT32 playersactive[MAXPLAYERS];
//I just realized how problematic this code can be.
//D_NumPlayers() will not always cover the scope of the netgame.
//What if one player is node 0 and the other node 31?
//The solution? Make a temp array of all players that are currently playing and pick from them.
//Future todo? When a player leaves, shift all nodes down so D_NumPlayers() can be used as intended?
//Also, you'd never have to loop through all 32 players slots to find anything ever again.
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && !players[i].spectator)
{
playersactive[realnumplayers] = i; //stores the player's node in the array.
realnumplayers++;
}
}
if (realnumplayers) //this should also fix the dedicated crash bug. You only pick a player if one exists to be picked.
{
i = P_RandomKey(realnumplayers);
players[playersactive[i]].pflags |= PF_TAGIT; //choose our initial tagger before map starts.
// Taken and modified from G_DoReborn()
// Remove the player so he can respawn elsewhere.
// first dissasociate the corpse
if (players[playersactive[i]].mo)
P_RemoveMobj(players[playersactive[i]].mo);
G_SpawnPlayer(playersactive[i], false); //respawn the lucky player in his dedicated spawn location.
}
else
CONS_Printf(M_GetText("No player currently available to become IT. Awaiting available players.\n"));
}
else if (G_RaceGametype() && server)
if (G_RaceGametype() && server)
CV_StealthSetValue(&cv_numlaps,
((netgame || multiplayer) && cv_basenumlaps.value
&& (!(mapheaderinfo[gamemap - 1]->levelflags & LF_SECTIONRACE)
@ -3304,6 +3277,8 @@ boolean P_SetupLevel(boolean skipprecip)
if (!(netgame || multiplayer) && !majormods)
mapvisited[gamemap-1] |= MV_VISITED;
G_AddMapToBuffer(gamemap-1);
levelloading = false;
P_RunCachedActions();
@ -3341,7 +3316,8 @@ boolean P_SetupLevel(boolean skipprecip)
#endif
}
G_AddMapToBuffer(gamemap-1);
// NOW you can try to spawn in the Battle capsules, if there's not enough players for a match
K_SpawnBattleCapsules();
return true;
}

View file

@ -5668,6 +5668,9 @@ static void P_RunLevelLoadExecutors(void)
*/
void P_InitSpecials(void)
{
// Set the map object scale
mapobjectscale = mapheaderinfo[gamemap-1]->mobj_scale;
// Set the default gravity. Custom gravity overrides this setting.
gravity = (FRACUNIT*8)/10;

View file

@ -23,6 +23,7 @@
#include "lua_script.h"
#include "lua_hook.h"
#include "k_kart.h"
#include "k_battle.h"
// Object place
#include "m_cheat.h"

View file

@ -14,6 +14,8 @@
#ifndef __SOUNDS__
#define __SOUNDS__
#include "doomdef.h"
// Customisable sounds for Skins
typedef enum
{

View file

@ -433,7 +433,7 @@ void Y_IntermissionDrawer(void)
if (data.match.rankingsmode)
timeheader = "RANK";
else
timeheader = (intertype == int_race ? "TIME" : "SCORE");
timeheader = ((intertype == int_race || (intertype == int_match && targetsspawned)) ? "TIME" : "SCORE");
// draw the level name
V_DrawCenteredString(-4 + x + BASEVIDWIDTH/2, 12, 0, data.match.levelstring);
@ -519,7 +519,7 @@ void Y_IntermissionDrawer(void)
V_DrawRightAlignedThinString(x+152+gutter, y-1, (data.match.numplayers > NUMFORNEWCOLUMN ? V_6WIDTHSPACE : 0), "NO CONTEST.");
else
{
if (intertype == int_race)
if (intertype == int_race || (intertype == int_match && targetsspawned))
{
snprintf(strtime, sizeof strtime, "%i'%02i\"%02i", G_TicsToMinutes(data.match.val[i], true),
G_TicsToSeconds(data.match.val[i]), G_TicsToCentiseconds(data.match.val[i]));
@ -840,7 +840,7 @@ void Y_StartIntermission(void)
case int_match:
{
// Calculate who won
Y_CalculateMatchData(0, Y_CompareBattle);
Y_CalculateMatchData(0, targetsspawned ? Y_CompareRace : Y_CompareBattle);
if (cv_inttime.value > 0)
S_ChangeMusicInternal("racent", true); // loop it
break;