diff --git a/src/Makefile b/src/Makefile index 18e0ddde5..d8c6fca11 100644 --- a/src/Makefile +++ b/src/Makefile @@ -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 \ diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 4d61194c4..33a1dfe61 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -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 diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 11c4547de..073b3fa3f 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -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 diff --git a/src/doomstat.h b/src/doomstat.h index 1f855da27..716b3fe85 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -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. */ diff --git a/src/g_game.c b/src/g_game.c index e406e29d1..50aa7b904 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -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; diff --git a/src/k_battle.c b/src/k_battle.c new file mode 100644 index 000000000..dafabf670 --- /dev/null +++ b/src/k_battle.c @@ -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; +} diff --git a/src/k_battle.h b/src/k_battle.h new file mode 100644 index 000000000..04c413d68 --- /dev/null +++ b/src/k_battle.h @@ -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 diff --git a/src/k_kart.c b/src/k_kart.c index c56c7c982..f9926d570 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -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]; diff --git a/src/k_kart.h b/src/k_kart.h index b91e8c8a1..7c09e92de 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -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 diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 38af4d2e9..f468f3b88 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -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" diff --git a/src/p_inter.c b/src/p_inter.c index 0b45d3878..240b7062f 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -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; diff --git a/src/p_mobj.c b/src/p_mobj.c index 4def2c713..d70c71e0f 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -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; } diff --git a/src/p_saveg.c b/src/p_saveg.c index 7d2e9a307..a79f90559 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -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); diff --git a/src/p_setup.c b/src/p_setup.c index d1ef91705..81bbcdd68 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -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; } diff --git a/src/p_spec.c b/src/p_spec.c index ec5de3224..1479d54b8 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -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; diff --git a/src/p_tick.c b/src/p_tick.c index 2502c7213..297bf31e6 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -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" diff --git a/src/sounds.h b/src/sounds.h index bb46ea9d8..a05c7babd 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -14,6 +14,8 @@ #ifndef __SOUNDS__ #define __SOUNDS__ +#include "doomdef.h" + // Customisable sounds for Skins typedef enum { diff --git a/src/y_inter.c b/src/y_inter.c index c270f04ab..855aae6a2 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -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;