Merge remote-tracking branch 'origin/master' into parties

This commit is contained in:
James R 2020-03-22 18:28:07 -07:00
commit abcba53781
35 changed files with 2002 additions and 1211 deletions

View file

@ -495,6 +495,8 @@ OBJS:=$(i_main_o) \
$(OBJDIR)/y_inter.o \
$(OBJDIR)/st_stuff.o \
$(OBJDIR)/k_kart.o \
$(OBJDIR)/k_collide.o\
$(OBJDIR)/k_battle.o \
$(OBJDIR)/k_pwrlv.o \
$(OBJDIR)/k_waypoint.o\
$(OBJDIR)/k_pathfind.o\

View file

@ -47,6 +47,7 @@
#include "lua_script.h"
#include "lua_hook.h"
#include "k_kart.h"
#include "k_battle.h"
#include "k_pwrlv.h"
#ifdef CLIENT_LOADINGSCREEN
@ -3516,7 +3517,7 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum)
splitscreenplayer = (UINT8)READUINT8(*p);
CONS_Debug(DBG_NETPLAY, "addplayer: %d %d %d\n", node, newplayernum, splitscreenplayer);
// Clear player before joining, lest some things get set incorrectly
CL_ClearPlayer(newplayernum);
@ -3767,7 +3768,11 @@ void SV_StartSinglePlayerServer(void)
server = true;
netgame = false;
multiplayer = false;
gametype = GT_RACE; //srb2kart
if (modeattacking == ATTACKING_CAPSULES)
gametype = GT_MATCH; //srb2kart
else
gametype = GT_RACE; //srb2kart
// no more tic the game with this settings!
SV_StopServer();

View file

@ -468,7 +468,7 @@ static void D_Display(void)
break;
}
topleft = screens[0] + viewwindowy*vid.width + viewwindowx;
}

View file

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

View file

@ -2473,10 +2473,10 @@ static void readunlockable(MYFILE *f, INT32 num)
unlockables[num].type = SECRET_PANDORA;
else if (fastcmp(word2, "CREDITS"))
unlockables[num].type = SECRET_CREDITS;
else if (fastcmp(word2, "RECORDATTACK"))
unlockables[num].type = SECRET_RECORDATTACK;
else if (fastcmp(word2, "NIGHTSMODE"))
unlockables[num].type = SECRET_NIGHTSMODE;
else if (fastcmp(word2, "TIMEATTACK"))
unlockables[num].type = SECRET_TIMEATTACK;
else if (fastcmp(word2, "BREAKTHECAPSULES"))
unlockables[num].type = SECRET_BREAKTHECAPSULES;
else if (fastcmp(word2, "HEADER"))
unlockables[num].type = SECRET_HEADER;
else if (fastcmp(word2, "LEVELSELECT"))
@ -7219,6 +7219,13 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_OVERTIMEORB",
"S_OVERTIMEBEAM",
"S_BATTLECAPSULE_SIDE1",
"S_BATTLECAPSULE_SIDE2",
"S_BATTLECAPSULE_TOP",
"S_BATTLECAPSULE_BUTTON",
"S_BATTLECAPSULE_SUPPORT",
"S_BATTLECAPSULE_SUPPORTFLY",
#ifdef SEENAMES
"S_NAMECHECK",
#endif
@ -8018,6 +8025,9 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_OVERTIMEORB",
"MT_OVERTIMEBEAM",
"MT_BATTLECAPSULE",
"MT_BATTLECAPSULE_PIECE",
#ifdef SEENAMES
"MT_NAMECHECK",
#endif

View file

@ -1,6 +1,6 @@
/* ______ ___ ___
* /\ _ \ /\_ \ /\_ \
* \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
/* ______ ___ ___
* /\ _ \ /\_ \ /\_ \
* \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
* \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
* \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
* \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
@ -22,9 +22,9 @@
#include "allegro.h"
/* ______ ___ ___
* /\ _ \ /\_ \ /\_ \
* \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
/* ______ ___ ___
* /\ _ \ /\_ \ /\_ \
* \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
* \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
* \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
* \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
@ -57,7 +57,7 @@
#define FILE_CREATE(filename, handle) handle = open(filename, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)
#define FILE_CLOSE(handle) close(handle)
#define FILE_READ(handle, buf, size, sz) sz = read(handle, buf, size)
#define FILE_WRITE(handle, buf, size, sz) sz = write(handle, buf, size)
#define FILE_WRITE(handle, buf, size, sz) sz = write(handle, buf, size)
#define FILE_SEARCH_STRUCT struct ffblk
#define FILE_FINDFIRST(filename, attrib, dta) findfirst(filename, dta, attrib)
#define FILE_FINDNEXT(dta) findnext(dta)
@ -73,11 +73,11 @@
#define ENABLE() asm volatile ("sti")
__INLINE__ void enter_critical(void)
__INLINE__ void enter_critical(void)
{
if (windows_version >= 3) {
__dpmi_regs r;
r.x.ax = 0x1681;
r.x.ax = 0x1681;
__dpmi_int(0x2F, &r);
}
@ -85,11 +85,11 @@ __INLINE__ void enter_critical(void)
}
__INLINE__ void exit_critical(void)
__INLINE__ void exit_critical(void)
{
if (windows_version >= 3) {
__dpmi_regs r;
r.x.ax = 0x1682;
r.x.ax = 0x1682;
__dpmi_int(0x2F, &r);
}
@ -176,9 +176,9 @@ extern int _fm_port;
extern int _mpu_port;
extern int _mpu_irq;
extern int _sb_freq;
extern int _sb_port;
extern int _sb_dma;
extern int _sb_irq;
extern int _sb_port;
extern int _sb_dma;
extern int _sb_irq;
int _sb_read_dsp_version(void);
int _sb_reset_dsp(int data);
@ -238,8 +238,8 @@ extern volatile int _retrace_hpp_value;
/* caches and tables for svga bank switching */
extern int _last_bank_1, _last_bank_2;
extern int *_gfx_bank;
extern int _last_bank_1, _last_bank_2;
extern int *_gfx_bank;
/* bank switching routines */
@ -282,7 +282,7 @@ extern int _crtc;
__INLINE__ int _read_vga_register(int port, int index)
{
if (port==0x3C0)
inportb(_crtc+6);
inportb(_crtc+6);
outportb(port, index);
return inportb(port+1);
@ -292,7 +292,7 @@ __INLINE__ int _read_vga_register(int port, int index)
/* _write_vga_register:
* Writes a byte to a VGA register.
*/
__INLINE__ void _write_vga_register(int port, int index, int v)
__INLINE__ void _write_vga_register(int port, int index, int v)
{
if (port==0x3C0) {
inportb(_crtc+6);
@ -345,7 +345,7 @@ __INLINE__ void _vsync_out_v(void)
__INLINE__ void _vsync_in(void)
{
if (_timer_use_retrace) {
int t = retrace_count;
int t = retrace_count;
do {
} while (t == retrace_count);
@ -555,7 +555,7 @@ typedef struct POLYGON_SEGMENT
/* an active polygon edge */
typedef struct POLYGON_EDGE
typedef struct POLYGON_EDGE
{
int top; /* top y position */
int bottom; /* bottom y position */
@ -673,7 +673,7 @@ void _poly_scanline_ptex_mask_lit32d(unsigned long addr, int w, POLYGON_SEGMENT
/* sound lib stuff */
extern int _digi_volume;
extern int _midi_volume;
extern int _flip_pan;
extern int _flip_pan;
extern int _sound_hq;
extern int (*_midi_init)(void);

View file

@ -82,7 +82,7 @@ extern boolean metalrecording;
#define ATTACKING_NONE 0
#define ATTACKING_RECORD 1
//#define ATTACKING_NIGHTS 2
#define ATTACKING_CAPSULES 2
extern UINT8 modeattacking;
// menu demo things
@ -385,7 +385,7 @@ 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
/** Time attack information, currently a very small structure.
*/
@ -518,15 +518,6 @@ extern INT16 votelevels[5][2];
extern SINT8 votes[MAXPLAYERS];
extern SINT8 pickedvote;
/** Battle overtime information
*/
extern struct battleovertime
{
UINT16 enabled; ///< Has this been initalized yet?
fixed_t radius, minradius; ///< Radius of kill field
fixed_t x, y, z; ///< Position to center on
} battleovertime;
extern tic_t hidetime;
extern UINT32 timesBeaten; // # of times the game has been beaten.

View file

@ -204,7 +204,7 @@ static void F_DoWipe(fademask_t *fademask, lighttable_t *fadecolormap, boolean r
// ---
// Sal: I kinda destroyed some of this code by introducing Genesis-style fades.
// A colormap can be provided in F_RunWipe, which the white/black values will be
// remapped to the appropriate entry in the fade colormap.
// remapped to the appropriate entry in the fade colormap.
{
// wipe screen, start, end
UINT8 *w = wipe_scr;
@ -434,7 +434,7 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu, const char *colormap, boolean r
reverse = false;
}
paldiv = FixedDiv(257<<FRACBITS, pallen<<FRACBITS);
paldiv = FixedDiv(257<<FRACBITS, pallen<<FRACBITS);
// Init the wipe
WipeInAction = true;

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"
#include "k_pwrlv.h"
gameaction_t gameaction;
@ -199,10 +200,6 @@ UINT32 bluescore, redscore; // CTF and Team Match team scores
// ring count... for PERFECT!
INT32 nummaprings = 0;
// box respawning in battle mode
INT32 nummapboxes = 0;
INT32 numgotboxes = 0;
// Elminates unnecessary searching.
boolean CheckForBustableBlocks;
boolean CheckForBouncySector;
@ -276,9 +273,6 @@ 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
struct battleovertime battleovertime;
// Server-sided, synched variables
SINT8 battlewanted[4]; // WANTED players in battle, worth x2 points
tic_t wantedcalcdelay; // Time before it recalculates WANTED
@ -2639,7 +2633,7 @@ void G_PlayerReborn(INT32 player)
itemtype = 0;
itemamount = 0;
growshrinktimer = 0;
bumper = (G_BattleGametype() ? cv_kartbumpers.value : 0);
bumper = (G_BattleGametype() ? K_StartingBumperCount() : 0);
rings = (G_BattleGametype() ? 0 : 5);
comebackpoints = 0;
wanted = 0;
@ -2864,9 +2858,13 @@ void G_SpawnPlayer(INT32 playernum, boolean starpost)
return;
}
// -- Record Attack --
if (modeattacking || battlecapsules)
spawnpoint = playerstarts[0];
// -- CTF --
// Order: CTF->DM->Coop
if (gametype == GT_CTF && players[playernum].ctfteam)
else if (gametype == GT_CTF && players[playernum].ctfteam)
{
if (!(spawnpoint = G_FindCTFStart(playernum)) // find a CTF start
&& !(spawnpoint = G_FindMatchStart(playernum))) // find a DM start
@ -4805,8 +4803,8 @@ char *G_BuildMapTitle(INT32 mapnum)
#define DEMOHEADER "\xF0" "KartReplay" "\x0F"
#define DF_GHOST 0x01 // This demo contains ghost data too!
#define DF_RECORDATTACK 0x02 // This demo is from record attack and contains its final completion time!
#define DF_NIGHTSATTACK 0x04 // This demo is from NiGHTS attack and contains its time left, score, and mares!
#define DF_TIMEATTACK 0x02 // This demo is from Time Attack and contains its final completion time & best lap!
#define DF_BREAKTHECAPSULES 0x04 // This demo is from Break the Capsules and contains its final completion time!
#define DF_ATTACKMASK 0x06 // This demo is from ??? attack and contains ???
#define DF_ATTACKSHIFT 1
#define DF_ENCORE 0x40
@ -4844,7 +4842,6 @@ static ticcmd_t oldcmd[MAXPLAYERS];
// Not used for Metal Sonic
#define GZT_SPRITE 0x10 // Animation frame
#define GZT_EXTRA 0x20
#define GZT_NIGHTS 0x40 // NiGHTS Mode stuff!
// GZT_EXTRA flags
#define EZT_THOK 0x01 // Spawned a thok object
@ -5350,13 +5347,6 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum)
if (!(demoflags & DF_GHOST))
return; // No ghost data to write.
if (ghost->player && ghost->player->pflags & PF_NIGHTSMODE && ghost->tracer)
{
// We're talking about the NiGHTS thing, not the normal platforming thing!
ziptic |= GZT_NIGHTS;
ghost = ghost->tracer;
}
ziptic_p = demo_p++; // the ziptic, written at the end of this function
#define MAXMOM (0x7FFF<<8)
@ -5573,12 +5563,6 @@ void G_ConsGhostTic(INT32 playernum)
demo_p++;
if (ziptic & GZT_SPRITE)
demo_p++;
if(ziptic & GZT_NIGHTS) {
if (!testmo || !testmo->player || !(testmo->player->pflags & PF_NIGHTSMODE) || !testmo->tracer)
nightsfail = true;
else
testmo = testmo->tracer;
}
if (ziptic & GZT_EXTRA)
{ // But wait, there's more!
@ -6409,6 +6393,10 @@ void G_BeginRecording(void)
WRITEUINT32(demo_p,UINT32_MAX); // time
WRITEUINT32(demo_p,UINT32_MAX); // lap
break;
case ATTACKING_CAPSULES: // 2
demotime_p = demo_p;
WRITEUINT32(demo_p,UINT32_MAX); // time
break;
default: // 3
break;
}
@ -6551,13 +6539,18 @@ void G_SetDemoTime(UINT32 ptime, UINT32 plap)
{
if (!demo.recording || !demotime_p)
return;
if (demoflags & DF_RECORDATTACK)
if (demoflags & DF_TIMEATTACK)
{
WRITEUINT32(demotime_p, ptime);
WRITEUINT32(demotime_p, plap);
demotime_p = NULL;
}
else if (demoflags & DF_BREAKTHECAPSULES)
{
WRITEUINT32(demotime_p, ptime);
(void)plap;
demotime_p = NULL;
}
}
static void G_LoadDemoExtraFiles(UINT8 **pp)
@ -6733,6 +6726,7 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
UINT8 c;
UINT16 s ATTRUNUSED;
UINT8 aflags = 0;
boolean uselaps = false;
// load the new file
FIL_DefaultExtension(newname, ".lmp");
@ -6759,20 +6753,17 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
p++; // gametype
G_SkipDemoExtraFiles(&p);
aflags = flags & (DF_RECORDATTACK|DF_NIGHTSATTACK);
aflags = flags & (DF_TIMEATTACK|DF_BREAKTHECAPSULES);
I_Assert(aflags);
if (flags & DF_RECORDATTACK)
{
newtime = READUINT32(p);
if (flags & DF_TIMEATTACK)
uselaps = true; // get around uninitalized error
newtime = READUINT32(p);
if (uselaps)
newlap = READUINT32(p);
}
/*else if (flags & DF_NIGHTSATTACK)
{
newtime = READUINT32(p);
newscore = READUINT32(p);
}*/
else // appease compiler
return 0;
else
newlap = UINT32_MAX;
Z_Free(buffer);
@ -6824,28 +6815,32 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
Z_Free(buffer);
return UINT8_MAX;
}
if (flags & DF_RECORDATTACK)
{
oldtime = READUINT32(p);
oldtime = READUINT32(p);
if (uselaps)
oldlap = READUINT32(p);
}
/*else if (flags & DF_NIGHTSATTACK)
{
oldtime = READUINT32(p);
oldscore = READUINT32(p);
}*/
else // appease compiler
return UINT8_MAX;
else
oldlap = 0;
Z_Free(buffer);
c = 0;
if (newtime < oldtime
|| (newtime == oldtime && (newlap < oldlap)))
c |= 1; // Better time
if (newlap < oldlap
|| (newlap == oldlap && newtime < oldtime))
c |= 1<<1; // Better lap time
if (uselaps)
{
if (newtime < oldtime
|| (newtime == oldtime && (newlap < oldlap)))
c |= 1; // Better time
if (newlap < oldlap
|| (newlap == oldlap && newtime < oldtime))
c |= 1<<1; // Better lap time
}
else
{
if (newtime < oldtime)
c |= 1; // Better time
}
return c;
}
@ -7220,19 +7215,18 @@ void G_DoPlayDemo(char *defdemoname)
switch (modeattacking)
{
case ATTACKING_NONE: // 0
break;
case ATTACKING_RECORD: // 1
hu_demotime = READUINT32(demo_p);
hu_demolap = READUINT32(demo_p);
break;
/*case ATTACKING_NIGHTS: // 2
hu_demotime = READUINT32(demo_p);
hu_demoscore = READUINT32(demo_p);
break;*/
default: // 3
modeattacking = ATTACKING_NONE;
break;
case ATTACKING_NONE: // 0
break;
case ATTACKING_RECORD: // 1
hu_demotime = READUINT32(demo_p);
hu_demolap = READUINT32(demo_p);
break;
case ATTACKING_CAPSULES: // 2
hu_demotime = READUINT32(demo_p);
break;
default: // 3
modeattacking = ATTACKING_NONE;
break;
}
// Random seed
@ -7527,16 +7521,16 @@ void G_AddGhost(char *defdemoname)
switch ((flags & DF_ATTACKMASK)>>DF_ATTACKSHIFT)
{
case ATTACKING_NONE: // 0
break;
case ATTACKING_RECORD: // 1
p += 8; // demo time, lap
break;
/*case ATTACKING_NIGHTS: // 2
p += 8; // demo time left, score
break;*/
default: // 3
break;
case ATTACKING_NONE: // 0
break;
case ATTACKING_RECORD: // 1
p += 8; // demo time, lap
break;
case ATTACKING_CAPSULES: // 2
p += 4; // demo time
break;
default: // 3
break;
}
p += 4; // random seed
@ -7728,6 +7722,9 @@ void G_UpdateStaffGhostName(lumpnum_t l)
case ATTACKING_RECORD: // 1
p += 8; // demo time, lap
break;
case ATTACKING_CAPSULES: // 2
p += 4; // demo time
break;
default: // 3
break;
}
@ -8059,7 +8056,7 @@ void G_SaveDemo(void)
free(demobuffer);
demo.recording = false;
if (modeattacking != ATTACKING_RECORD)
if (!modeattacking)
{
if (demo.savemode == DSM_SAVED)
CONS_Printf(M_GetText("Demo %s recorded\n"), demoname);

View file

@ -3460,6 +3460,13 @@ state_t states[NUMSTATES] =
{SPR_OTFG, 2|FF_FULLBRIGHT|FF_PAPERSPRITE, 1, {NULL}, 0, 0, S_NULL}, // S_OVERTIMEORB
{SPR_OTFG, 1|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_NULL}, // S_OVERTIMEBEAM
{SPR_CAPS, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_BATTLECAPSULE_SIDE1
{SPR_CAPS, FF_PAPERSPRITE|1, -1, {NULL}, 0, 0, S_NULL}, // S_BATTLECAPSULE_SIDE2
{SPR_CAPS, 2, -1, {NULL}, 0, 0, S_NULL}, // S_BATTLECAPSULE_TOP
{SPR_CAPS, 3, -1, {NULL}, 0, 0, S_NULL}, // S_BATTLECAPSULE_BUTTON
{SPR_CAPS, 4, -1, {NULL}, 0, 0, S_NULL}, // S_BATTLECAPSULE_SUPPORT
{SPR_CAPS, FF_ANIMATE|5, -1, {NULL}, 3, 1, S_NULL}, // S_BATTLECAPSULE_SUPPORTFLY
#ifdef SEENAMES
{SPR_NULL, 0, 1, {NULL}, 0, 0, S_NULL}, // S_NAMECHECK
#endif
@ -20441,6 +20448,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_BATTLECAPSULE
2333, // doomednum
S_INVISIBLE, // spawnstate
1, // 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_INVISIBLE, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
28<<FRACBITS, // radius
112<<FRACBITS, // height
0, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_SOLID|MF_SHOOTABLE|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
{ // MT_BATTLECAPSULE_PIECE
-1, // doomednum
S_INVISIBLE, // 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
8<<FRACBITS, // height
0, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_SCENERY|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOBLOCKMAP|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
// ============================================================================================================================//
#ifdef SEENAMES

View file

@ -4126,6 +4126,13 @@ typedef enum state
S_OVERTIMEORB,
S_OVERTIMEBEAM,
S_BATTLECAPSULE_SIDE1,
S_BATTLECAPSULE_SIDE2,
S_BATTLECAPSULE_TOP,
S_BATTLECAPSULE_BUTTON,
S_BATTLECAPSULE_SUPPORT,
S_BATTLECAPSULE_SUPPORTFLY,
#ifdef SEENAMES
S_NAMECHECK,
#endif
@ -4942,6 +4949,9 @@ typedef enum mobj_type
MT_OVERTIMEORB,
MT_OVERTIMEBEAM,
MT_BATTLECAPSULE,
MT_BATTLECAPSULE_PIECE,
#ifdef SEENAMES
MT_NAMECHECK,
#endif

764
src/k_battle.c Normal file
View file

@ -0,0 +1,764 @@
/// \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"
#include "s_sound.h"
#include "m_random.h"
#include "r_sky.h" // skyflatnum
// Battle overtime info
struct battleovertime battleovertime;
// Capsules mode enabled for this map?
boolean battlecapsules = false;
// box respawning in battle mode
INT32 nummapboxes = 0;
INT32 numgotboxes = 0;
// Capsule counters
UINT8 maptargets = 0; // Capsules in map
UINT8 numtargets = 0; // Capsules busted
INT32 K_StartingBumperCount(void)
{
if (battlecapsules)
return 1; // always 1 hit in Break the Capsules
return cv_kartbumpers.value;
}
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;
boolean nobumpers = false;
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
{
nobumpers = true;
continue;
}
else if (winnernum != -1) // TWO winners? that's dumb :V
return;
winnernum = i;
winnerscoreadd -= players[i].marescore;
}
if (numingame <= 1)
{
if (!battlecapsules)
{
// Reset map to turn on battle capsules
D_MapChange(gamemap, gametype, encoremode, true, 0, false, false);
}
else
{
if (nobumpers)
{
for (i = 0; i < MAXPLAYERS; i++)
{
players[i].pflags |= PF_TIMEOVER;
//players[i].lives = 0;
P_DoPlayerExit(&players[i]);
}
}
}
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]);
}
#define MAXPLANESPERSECTOR (MAXFFLOORS+1)*2
static void K_SpawnOvertimeParticles(fixed_t x, fixed_t y, fixed_t scale, mobjtype_t type, boolean ceiling)
{
UINT8 i;
fixed_t flatz[MAXPLANESPERSECTOR];
boolean flip[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
for (i = 0; i < MAXPLANESPERSECTOR; i++)
flip[i] = false;
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) - FixedMul(mobjinfo[type].height, scale);
#else
flatz[numflats] = (sec->ceilingheight) - FixedMul(mobjinfo[type].height, scale);
#endif
flip[numflats] = true;
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) - FixedMul(mobjinfo[type].height, scale);
#else
flatz[numflats] = (*rover->bottomheight) - FixedMul(mobjinfo[type].height, scale);
#endif
flip[numflats] = true;
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]))
{
const fixed_t sbz = skyboxmo[0]->z;
fixed_t checkz = sec->floorheight;
while (checkz < sec->ceilingheight)
{
P_TeleportMove(skyboxmo[0], skyboxmo[0]->x, skyboxmo[0]->y, checkz);
if (P_CheckSight(skyboxmo[0], mo))
{
P_RemoveMobj(mo);
break;
}
else
checkz += 32*mapobjectscale;
}
P_TeleportMove(skyboxmo[0], skyboxmo[0]->x, skyboxmo[0]->y, sbz);
if (P_MobjWasRemoved(mo))
continue;
}
P_SetScale(mo, scale);
if (flip[i])
{
mo->flags2 |= MF2_OBJECTFLIP;
mo->eflags |= MFE_VERTICALFLIP;
}
switch(type)
{
case MT_OVERTIMEFOG:
mo->destscale = 8*mo->scale;
mo->momz = P_RandomRange(1,8)*mo->scale;
break;
case MT_OVERTIMEORB:
//mo->destscale = mo->scale/4;
mo->frame += ((leveltime/4) % 8);
/*if (battleovertime.enabled < 10*TICRATE)
mo->flags2 |= MF2_SHADOW;*/
mo->angle = R_PointToAngle2(mo->x, mo->y, battleovertime.x, battleovertime.y) + ANGLE_90;
mo->z += P_RandomRange(0,48) * mo->scale;
break;
default:
break;
}
}
}
#undef MAXPLANESPERSECTOR
void K_RunBattleOvertime(void)
{
UINT16 i, j;
if (battleovertime.enabled < 10*TICRATE)
{
battleovertime.enabled++;
if (battleovertime.enabled == TICRATE)
S_StartSound(NULL, sfx_bhurry);
if (battleovertime.enabled == 10*TICRATE)
S_StartSound(NULL, sfx_kc40);
}
else
{
if (battleovertime.radius > battleovertime.minradius)
battleovertime.radius -= mapobjectscale;
else
battleovertime.radius = battleovertime.minradius;
}
if (leveltime & 1)
{
UINT8 transparency = tr_trans50;
if (!splitscreen && players[displayplayers[0]].mo)
{
INT32 dist = P_AproxDistance(battleovertime.x-players[displayplayers[0]].mo->x, battleovertime.y-players[displayplayers[0]].mo->y);
transparency = max(0, NUMTRANSMAPS - ((256 + (dist>>FRACBITS)) / 256));
}
if (transparency < NUMTRANSMAPS)
{
mobj_t *beam = P_SpawnMobj(battleovertime.x, battleovertime.y, battleovertime.z + (mobjinfo[MT_RANDOMITEM].height/2), MT_OVERTIMEBEAM);
P_SetScale(beam, beam->scale*2);
if (transparency > 0)
beam->frame |= transparency<<FF_TRANSSHIFT;
}
}
// 16 orbs at the normal minimum size of 512
{
const fixed_t pi = (22<<FRACBITS) / 7; // loose approximation, this doesn't need to be incredibly precise
fixed_t scale = mapobjectscale + (battleovertime.radius/2048);
fixed_t sprwidth = 32*scale;
fixed_t circumference = FixedMul(pi, battleovertime.radius<<1);
UINT16 orbs = circumference / sprwidth;
angle_t angoff = ANGLE_MAX / orbs;
for (i = 0; i < orbs; i++)
{
angle_t ang = (i * angoff) + FixedAngle((leveltime/2)<<FRACBITS);
fixed_t x = battleovertime.x + P_ReturnThrustX(NULL, ang, battleovertime.radius - FixedMul(mobjinfo[MT_OVERTIMEORB].radius, scale));
fixed_t y = battleovertime.y + P_ReturnThrustY(NULL, ang, battleovertime.radius - FixedMul(mobjinfo[MT_OVERTIMEORB].radius, scale));
K_SpawnOvertimeParticles(x, y, scale, MT_OVERTIMEORB, false);
}
}
if (battleovertime.enabled < 10*TICRATE)
return;
/*if (!S_IdPlaying(sfx_s3kd4s)) // global ambience
S_StartSoundAtVolume(NULL, sfx_s3kd4s, min(255, ((4096*mapobjectscale) - battleovertime.radius)>>FRACBITS / 2));*/
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);
fixed_t closestdist = battleovertime.radius + (8*mobjinfo[MT_OVERTIMEFOG].radius);
j++;
if (P_AproxDistance(x-battleovertime.x, y-battleovertime.y) < closestdist)
continue;
K_SpawnOvertimeParticles(x, y, 4*mapobjectscale, MT_OVERTIMEFOG, false);
break;
}
}
}
static void K_SetupMovingCapsule(mapthing_t *mt, mobj_t *mobj)
{
UINT8 sequence = mt->extrainfo-1;
fixed_t speed = (FRACUNIT >> 3) * mt->angle;
boolean backandforth = (mt->options & MTF_AMBUSH);
boolean reverse = (mt->options & MTF_OBJECTSPECIAL);
mobj_t *mo2;
mobj_t *target = NULL;
thinker_t *th;
// Find the inital target
for (th = thinkercap.next; th != &thinkercap; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
continue;
mo2 = (mobj_t *)th;
if (mo2->type != MT_TUBEWAYPOINT)
continue;
if (mo2->threshold == sequence)
{
if (reverse) // Use the highest waypoint number as first
{
if (mo2->health != 0)
{
if (target == NULL)
target = mo2;
else if (mo2->health > target->health)
target = mo2;
}
}
else // Use the lowest waypoint number as first
{
if (mo2->health == 0)
target = mo2;
}
}
}
if (!target)
{
CONS_Alert(CONS_WARNING, "No target waypoint found for moving capsule (seq: #%d)\n", sequence);
return;
}
P_SetTarget(&mobj->target, target);
mobj->lastlook = sequence;
mobj->movecount = target->health;
mobj->movefactor = speed;
if (backandforth) {
mobj->flags2 |= MF2_AMBUSH;
} else {
mobj->flags2 &= ~MF2_AMBUSH;
}
if (reverse) {
mobj->cvmem = -1;
} else {
mobj->cvmem = 1;
}
}
void K_SpawnBattleCapsules(void)
{
mapthing_t *mt;
size_t i;
if (battlecapsules)
return;
if (!G_BattleGametype())
return;
if (modeattacking != ATTACKING_CAPSULES)
{
UINT8 n = 0;
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;
UINT8 j;
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 (j = 0; j < numfloors; j++)
{
if (z == floorheights[j])
{
fly = false;
break;
}
}
// Flying capsules
if (fly)
{
mobj->flags |= MF_NOGRAVITY;
mobj->extravalue1 = 1; // Set extravalue1 for later reference
}
// Moving capsules!
if (mt->extrainfo && mt->angle)
K_SetupMovingCapsule(mt, mobj);
// 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 (j = 0; j < 4; j++)
{
cur = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_BATTLECAPSULE_PIECE);
cur->extravalue1 = j;
if (mobj->extravalue1) // Flying capsule, moving or not
P_SetMobjState(cur, S_BATTLECAPSULE_SUPPORTFLY);
else if (mobj->target && !P_MobjWasRemoved(mobj->target)) // Grounded, moving capsule
P_SetMobjState(cur, S_KARMAWHEEL);
else
P_SetMobjState(cur, S_BATTLECAPSULE_SUPPORT); // Grounded, stationary capsule
P_SetTarget(&cur->target, mobj);
P_SetTarget(&cur->hprev, prev);
P_SetTarget(&prev->hnext, cur);
prev = cur;
}
// Side paneling
for (j = 0; j < 8; j++)
{
cur = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_BATTLECAPSULE_PIECE);
cur->extravalue1 = j;
if (j & 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;
}
}
mt->mobj = mobj;
}
}
battlecapsules = true;
}

26
src/k_battle.h Normal file
View file

@ -0,0 +1,26 @@
#ifndef __K_BATTLE__
#define __K_BATTLE__
#include "doomtype.h"
#include "d_player.h"
extern struct battleovertime
{
UINT16 enabled; ///< Has this been initalized yet?
fixed_t radius, minradius; ///< Radius of kill field
fixed_t x, y, z; ///< Position to center on
} battleovertime;
extern boolean battlecapsules;
extern INT32 nummapboxes, numgotboxes; // keep track of spawned battle mode items
extern UINT8 maptargets, numtargets;
INT32 K_StartingBumperCount(void);
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_RunBattleOvertime(void);
void K_SpawnBattleCapsules(void);
#endif

319
src/k_collide.c Normal file
View file

@ -0,0 +1,319 @@
/// \file k_collide.c
/// \brief SRB2Kart item collision hooks
#include "k_collide.h"
#include "doomtype.h"
#include "p_mobj.h"
#include "k_kart.h"
#include "p_local.h"
#include "s_sound.h"
#include "r_main.h" // R_PointToAngle2, R_PointToDist2
#include "hu_stuff.h" // Sink snipe print
#include "doomdef.h" // Sink snipe print
#include "g_game.h" // Sink snipe print
boolean K_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2)
{
boolean damageitem = false;
if (((t1->target == t2) || (t1->target == t2->target)) && (t1->threshold > 0 || (t2->type != MT_PLAYER && t2->threshold > 0)))
return true;
if (t1->health <= 0 || t2->health <= 0)
return true;
if ((t1->type == MT_ORBINAUT_SHIELD || t1->type == MT_JAWZ_SHIELD) && t1->lastlook
&& (t2->type == MT_ORBINAUT_SHIELD || t2->type == MT_JAWZ_SHIELD) && t2->lastlook
&& (t1->target == t2->target)) // Don't hit each other if you have the same target
return true;
if (t2->player)
{
if (t2->player->powers[pw_flashing]
&& !(t1->type == MT_ORBINAUT || t1->type == MT_JAWZ || t1->type == MT_JAWZ_DUD))
return true;
if (t2->player->kartstuff[k_hyudorotimer])
return true; // no interaction
// Player Damage
P_DamageMobj(t2, t1, t1->target, 1);
K_KartBouncing(t2, t1, false, false);
S_StartSound(t2, sfx_s3k7b);
damageitem = true;
}
else if (t2->type == MT_ORBINAUT || t2->type == MT_JAWZ || t2->type == MT_JAWZ_DUD
|| t2->type == MT_ORBINAUT_SHIELD || t2->type == MT_JAWZ_SHIELD
|| t2->type == MT_BANANA || t2->type == MT_BANANA_SHIELD
|| t2->type == MT_BALLHOG)
{
// Other Item Damage
if (t2->eflags & MFE_VERTICALFLIP)
t2->z -= t2->height;
else
t2->z += t2->height;
S_StartSound(t2, t2->info->deathsound);
P_KillMobj(t2, t1, t1);
P_SetObjectMomZ(t2, 8*FRACUNIT, false);
P_InstaThrust(t2, R_PointToAngle2(t1->x, t1->y, t2->x, t2->y)+ANGLE_90, 16*FRACUNIT);
P_SpawnMobj(t2->x/2 + t1->x/2, t2->y/2 + t1->y/2, t2->z/2 + t1->z/2, MT_ITEMCLASH);
damageitem = true;
}
else if (t2->type == MT_SSMINE_SHIELD || t2->type == MT_SSMINE)
{
damageitem = true;
// Bomb death
P_KillMobj(t2, t1, t1);
}
else if (t2->flags & MF_SPRING && (t1->type != MT_ORBINAUT_SHIELD && t1->type != MT_JAWZ_SHIELD))
{
// Let thrown items hit springs!
P_DoSpring(t2, t1);
}
else if (t2->flags & MF_SHOOTABLE)
{
// Shootable damage
P_DamageMobj(t2, t2, t1->target, 1);
damageitem = true;
}
if (damageitem)
{
// This Item Damage
if (t1->eflags & MFE_VERTICALFLIP)
t1->z -= t1->height;
else
t1->z += t1->height;
S_StartSound(t1, t1->info->deathsound);
P_KillMobj(t1, t2, t2);
P_SetObjectMomZ(t1, 8*FRACUNIT, false);
P_InstaThrust(t1, R_PointToAngle2(t2->x, t2->y, t1->x, t1->y)+ANGLE_90, 16*FRACUNIT);
}
return true;
}
boolean K_BananaBallhogCollide(mobj_t *t1, mobj_t *t2)
{
boolean damageitem = false;
if (((t1->target == t2) || (t1->target == t2->target)) && (t1->threshold > 0 || (t2->type != MT_PLAYER && t2->threshold > 0)))
return true;
if (t1->health <= 0 || t2->health <= 0)
return true;
if (((t1->type == MT_BANANA_SHIELD) && (t2->type == MT_BANANA_SHIELD))
&& (t1->target == t2->target)) // Don't hit each other if you have the same target
return true;
if (t1->type == MT_BALLHOG && t2->type == MT_BALLHOG)
return true; // Ballhogs don't collide with eachother
if (t2->player)
{
if (t2->player->powers[pw_flashing])
return true;
// Banana snipe!
if (t1->type == MT_BANANA && t1->health > 1)
S_StartSound(t2, sfx_bsnipe);
// Player Damage
K_SpinPlayer(t2->player, t1->target, 0, t1, (t1->type == MT_BANANA || t1->type == MT_BANANA_SHIELD));
damageitem = true;
}
else if (t2->type == MT_BANANA || t2->type == MT_BANANA_SHIELD
|| t2->type == MT_ORBINAUT || t2->type == MT_ORBINAUT_SHIELD
|| t2->type == MT_JAWZ || t2->type == MT_JAWZ_DUD || t2->type == MT_JAWZ_SHIELD
|| t2->type == MT_BALLHOG)
{
// Other Item Damage
if (t2->eflags & MFE_VERTICALFLIP)
t2->z -= t2->height;
else
t2->z += t2->height;
S_StartSound(t2, t2->info->deathsound);
P_KillMobj(t2, t1, t1);
P_SetObjectMomZ(t2, 8*FRACUNIT, false);
P_InstaThrust(t2, R_PointToAngle2(t1->x, t1->y, t2->x, t2->y)+ANGLE_90, 16*FRACUNIT);
P_SpawnMobj(t2->x/2 + t1->x/2, t2->y/2 + t1->y/2, t2->z/2 + t1->z/2, MT_ITEMCLASH);
damageitem = true;
}
else if (t2->flags & MF_SHOOTABLE)
{
// Shootable damage
P_DamageMobj(t2, t2, t1->target, 1);
damageitem = true;
}
if (damageitem)
{
// This Item Damage
if (t1->eflags & MFE_VERTICALFLIP)
t1->z -= t1->height;
else
t1->z += t1->height;
S_StartSound(t1, t1->info->deathsound);
P_KillMobj(t1, t2, t2);
P_SetObjectMomZ(t1, 8*FRACUNIT, false);
P_InstaThrust(t1, R_PointToAngle2(t2->x, t2->y, t1->x, t1->y)+ANGLE_90, 16*FRACUNIT);
}
return true;
}
boolean K_EggItemCollide(mobj_t *t1, mobj_t *t2)
{
// Push fakes out of other item boxes
if (t2->type == MT_RANDOMITEM || t2->type == MT_EGGMANITEM)
P_InstaThrust(t1, R_PointToAngle2(t2->x, t2->y, t1->x, t1->y), t2->radius/4);
// Player collision is handled by TouchSpecial
return true;
}
boolean K_MineCollide(mobj_t *t1, mobj_t *t2)
{
if (((t1->target == t2) || (t1->target == t2->target)) && (t1->threshold > 0 || (t2->type != MT_PLAYER && t2->threshold > 0)))
return true;
if (t1->health <= 0 || t2->health <= 0)
return true;
if (t2->player)
{
if (t2->player->powers[pw_flashing])
return true;
// Bomb punting
if ((t1->state >= &states[S_SSMINE1] && t1->state <= &states[S_SSMINE4])
|| (t1->state >= &states[S_SSMINE_DEPLOY8] && t1->state <= &states[S_SSMINE_DEPLOY13]))
P_KillMobj(t1, t2, t2);
else
K_PuntMine(t1, t2);
}
else if (t2->type == MT_ORBINAUT || t2->type == MT_JAWZ || t2->type == MT_JAWZ_DUD
|| t2->type == MT_ORBINAUT_SHIELD || t2->type == MT_JAWZ_SHIELD)
{
// Bomb death
P_KillMobj(t1, t2, t2);
// Other Item Damage
if (t2->eflags & MFE_VERTICALFLIP)
t2->z -= t2->height;
else
t2->z += t2->height;
S_StartSound(t2, t2->info->deathsound);
P_KillMobj(t2, t1, t1);
P_SetObjectMomZ(t2, 8*FRACUNIT, false);
P_InstaThrust(t2, R_PointToAngle2(t1->x, t1->y, t2->x, t2->y)+ANGLE_90, 16*FRACUNIT);
}
else if (t2->flags & MF_SHOOTABLE)
{
// Bomb death
P_KillMobj(t1, t2, t2);
// Shootable damage
P_DamageMobj(t2, t2, t1->target, 1);
}
return true;
}
boolean K_MineExplosionCollide(mobj_t *t1, mobj_t *t2)
{
if (t2->player)
{
if (t2->player->powers[pw_flashing])
return true;
if (t1->state == &states[S_MINEEXPLOSION1])
K_ExplodePlayer(t2->player, t1->target, t1);
else
K_SpinPlayer(t2->player, t1->target, 0, t1, false);
}
else if (t2->flags & MF_SHOOTABLE)
{
// Shootable damage
P_DamageMobj(t2, t2, t1->target, 1);
}
return true;
}
boolean K_KitchenSinkCollide(mobj_t *t1, mobj_t *t2)
{
if (((t1->target == t2) || (t1->target == t2->target)) && (t1->threshold > 0 || (t2->type != MT_PLAYER && t2->threshold > 0)))
return true;
if (t2->player)
{
if (t2->player->powers[pw_flashing])
return true;
S_StartSound(NULL, sfx_bsnipe); // let all players hear it.
HU_SetCEchoFlags(0);
HU_SetCEchoDuration(5);
HU_DoCEcho(va("%s\\was hit by a kitchen sink.\\\\\\\\", player_names[t2->player-players]));
I_OutputMsg("%s was hit by a kitchen sink.\n", player_names[t2->player-players]);
P_DamageMobj(t2, t1, t1->target, 10000);
P_KillMobj(t1, t2, t2);
}
else if (t2->flags & MF_SHOOTABLE)
{
// Shootable damage
P_KillMobj(t2, t2, t1->target);
// This item damage
P_KillMobj(t1, t2, t2);
}
return true;
}
boolean K_FallingRockCollide(mobj_t *t1, mobj_t *t2)
{
if (t2->player || t2->type == MT_FALLINGROCK)
K_KartBouncing(t2, t1, false, false);
return true;
}
boolean K_SMKIceBlockCollide(mobj_t *t1, mobj_t *t2)
{
if (!(t2->flags & MF_SOLID || t2->flags & MF_SHOOTABLE || t2->flags & MF_BOUNCE))
return true;
if (!(t2->health))
return true;
if (t2->type == MT_BANANA || t2->type == MT_BANANA_SHIELD
|| t2->type == MT_EGGMANITEM || t2->type == MT_EGGMANITEM_SHIELD
|| t2->type == MT_SSMINE || t2->type == MT_SSMINE_SHIELD
|| t2->type == MT_ORBINAUT_SHIELD || t2->type == MT_JAWZ_SHIELD)
return false;
if (t1->health)
P_KillMobj(t1, t2, t2);
/*if (t2->player && (t2->player->kartstuff[k_invincibilitytimer] > 0
|| t2->player->kartstuff[k_growshrinktimer] > 0))
return true;*/
K_KartBouncing(t2, t1, false, true);
return false;
}

16
src/k_collide.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef __K_COLLIDE__
#define __K_COLLIDE__
#include "doomtype.h"
#include "p_mobj.h"
boolean K_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2);
boolean K_BananaBallhogCollide(mobj_t *t1, mobj_t *t2);
boolean K_EggItemCollide(mobj_t *t1, mobj_t *t2);
boolean K_MineCollide(mobj_t *t1, mobj_t *t2);
boolean K_MineExplosionCollide(mobj_t *t1, mobj_t *t2);
boolean K_KitchenSinkCollide(mobj_t *t1, mobj_t *t2);
boolean K_FallingRockCollide(mobj_t *t1, mobj_t *t2);
boolean K_SMKIceBlockCollide(mobj_t *t1, mobj_t *t2);
#endif

View file

@ -5,6 +5,7 @@
/// All of the SRB2kart-unique stuff.
#include "k_kart.h"
#include "k_battle.h"
#include "k_pwrlv.h"
#include "doomdef.h"
#include "hu_stuff.h"
@ -604,6 +605,9 @@ boolean K_IsPlayerLosing(player_t *player)
INT32 winningpos = 1;
UINT8 i, pcount = 0;
if (battlecapsules && player->kartstuff[k_bumper] <= 0)
return true; // DNF in break the capsules
if (player->kartstuff[k_position] == 1)
return false;
@ -625,21 +629,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%
@ -1179,8 +1168,8 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd)
}
else
{
if (modeattacking || cv_orbinaut.value) // Waited patiently? You get an orbinaut!
K_KartGetItemResult(player, KITEM_ORBINAUT);
if (modeattacking || cv_tripleorbinaut.value) // Waited patiently? You get Orbinaut x3!
K_KartGetItemResult(player, KRITEM_TRIPLEORBINAUT);
else // Default to sad if nothing's enabled...
K_KartGetItemResult(player, KITEM_SAD);
player->karthud[khud_itemblinkmode] = 0;
@ -2630,32 +2619,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;
@ -3076,7 +3039,7 @@ void K_StealBumper(player_t *player, player_t *victim, boolean force)
if (!force)
{
if (victim->kartstuff[k_bumper] <= 0) // || player->kartstuff[k_bumper] >= cv_kartbumpers.value+2
if (victim->kartstuff[k_bumper] <= 0) // || player->kartstuff[k_bumper] >= K_StartingBumperCount()+2
return;
if (player->kartstuff[k_squishedtimer] > 0 || player->kartstuff[k_spinouttimer] > 0)
@ -7665,181 +7628,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];
@ -7953,6 +7741,8 @@ static patch_t *kp_lapstickernarrow;
static patch_t *kp_splitlapflag;
static patch_t *kp_bumpersticker;
static patch_t *kp_bumperstickerwide;
static patch_t *kp_capsulesticker;
static patch_t *kp_capsulestickerwide;
static patch_t *kp_karmasticker;
static patch_t *kp_splitkarmabomb;
static patch_t *kp_timeoutsticker;
@ -7983,6 +7773,7 @@ static patch_t *kp_speedometerlabel[4];
static patch_t *kp_rankbumper;
static patch_t *kp_tinybumper[2];
static patch_t *kp_ranknobumpers;
static patch_t *kp_rankcapsule;
static patch_t *kp_battlewin;
static patch_t *kp_battlecool;
@ -8055,6 +7846,8 @@ void K_LoadKartHUDGraphics(void)
kp_splitlapflag = W_CachePatchName("K_SPTLAP", PU_HUDGFX);
kp_bumpersticker = W_CachePatchName("K_STBALN", PU_HUDGFX);
kp_bumperstickerwide = W_CachePatchName("K_STBALW", PU_HUDGFX);
kp_capsulesticker = W_CachePatchName("K_STCAPN", PU_HUDGFX);
kp_capsulestickerwide = W_CachePatchName("K_STCAPW", PU_HUDGFX);
kp_karmasticker = W_CachePatchName("K_STKARM", PU_HUDGFX);
kp_splitkarmabomb = W_CachePatchName("K_SPTKRM", PU_HUDGFX);
kp_timeoutsticker = W_CachePatchName("K_STTOUT", PU_HUDGFX);
@ -8181,6 +7974,7 @@ void K_LoadKartHUDGraphics(void)
kp_tinybumper[0] = W_CachePatchName("K_BLNA", PU_HUDGFX);
kp_tinybumper[1] = W_CachePatchName("K_BLNB", PU_HUDGFX);
kp_ranknobumpers = W_CachePatchName("K_NOBLNS", PU_HUDGFX);
kp_rankcapsule = W_CachePatchName("K_CAPICO", PU_HUDGFX);
// Battle graphics
kp_battlewin = W_CachePatchName("K_BWIN", PU_HUDGFX);
@ -9524,8 +9318,8 @@ static void K_drawKartLapsAndRings(void)
if (cv_numlaps.value >= 10)
{
UINT8 ln[2];
ln[0] = ((abs(stplyr->laps) / 10) % 10);
ln[1] = (abs(stplyr->laps) % 10);
ln[0] = ((stplyr->laps / 10) % 10);
ln[1] = (stplyr->laps % 10);
V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|splitflags, pingnum[ln[0]]);
V_DrawScaledPatch(fx+17, fy, V_HUDTRANS|splitflags, pingnum[ln[1]]);
@ -9705,52 +9499,95 @@ static void K_drawKartBumpersOrKarma(void)
V_DrawScaledPatch(fx-2 + (flipflag ? (SHORT(kp_ringstickersplit[1]->width) - 3) : 0), fy, V_HUDTRANS|splitflags|flipflag, kp_ringstickersplit[0]);
V_DrawScaledPatch(fx+22, fy, V_HUDTRANS|splitflags, frameslash);
if (stplyr->kartstuff[k_bumper] <= 0)
if (battlecapsules)
{
V_DrawMappedPatch(fx+1, fy-2, V_HUDTRANS|splitflags, kp_splitkarmabomb, colormap);
V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|splitflags, kp_facenum[(stplyr->kartstuff[k_comebackpoints]) % 10]);
V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|splitflags, kp_facenum[2]);
}
else
{
V_DrawMappedPatch(fx+1, fy-2, V_HUDTRANS|splitflags, kp_rankbumper, colormap);
V_DrawMappedPatch(fx+1, fy-2, V_HUDTRANS|splitflags, kp_rankcapsule, NULL);
if (stplyr->kartstuff[k_bumper] > 9 || cv_kartbumpers.value > 9)
if (numtargets > 9 || maptargets > 9)
{
UINT8 ln[2];
ln[0] = ((abs(stplyr->kartstuff[k_bumper]) / 10) % 10);
ln[1] = (abs(stplyr->kartstuff[k_bumper]) % 10);
ln[0] = ((numtargets / 10) % 10);
ln[1] = (numtargets % 10);
V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|splitflags, pingnum[ln[0]]);
V_DrawScaledPatch(fx+17, fy, V_HUDTRANS|splitflags, pingnum[ln[1]]);
ln[0] = ((abs(cv_kartbumpers.value) / 10) % 10);
ln[1] = (abs(cv_kartbumpers.value) % 10);
ln[0] = ((maptargets / 10) % 10);
ln[1] = (maptargets % 10);
V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|splitflags, pingnum[ln[0]]);
V_DrawScaledPatch(fx+31, fy, V_HUDTRANS|splitflags, pingnum[ln[1]]);
}
else
{
V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|splitflags, kp_facenum[(stplyr->kartstuff[k_bumper]) % 10]);
V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|splitflags, kp_facenum[(cv_kartbumpers.value) % 10]);
V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|splitflags, kp_facenum[numtargets % 10]);
V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|splitflags, kp_facenum[maptargets % 10]);
}
}
else
{
if (stplyr->kartstuff[k_bumper] <= 0)
{
V_DrawMappedPatch(fx+1, fy-2, V_HUDTRANS|splitflags, kp_splitkarmabomb, colormap);
V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|splitflags, kp_facenum[(stplyr->kartstuff[k_comebackpoints]) % 10]);
V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|splitflags, kp_facenum[2]);
}
else
{
INT32 maxbumper = K_StartingBumperCount();
V_DrawMappedPatch(fx+1, fy-2, V_HUDTRANS|splitflags, kp_rankbumper, colormap);
if (stplyr->kartstuff[k_bumper] > 9 || maxbumper > 9)
{
UINT8 ln[2];
ln[0] = ((abs(stplyr->kartstuff[k_bumper]) / 10) % 10);
ln[1] = (abs(stplyr->kartstuff[k_bumper]) % 10);
V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|splitflags, pingnum[ln[0]]);
V_DrawScaledPatch(fx+17, fy, V_HUDTRANS|splitflags, pingnum[ln[1]]);
ln[0] = ((abs(maxbumper) / 10) % 10);
ln[1] = (abs(maxbumper) % 10);
V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|splitflags, pingnum[ln[0]]);
V_DrawScaledPatch(fx+31, fy, V_HUDTRANS|splitflags, pingnum[ln[1]]);
}
else
{
V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|splitflags, kp_facenum[(stplyr->kartstuff[k_bumper]) % 10]);
V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|splitflags, kp_facenum[(maxbumper) % 10]);
}
}
}
}
else
{
if (stplyr->kartstuff[k_bumper] <= 0)
if (battlecapsules)
{
V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|splitflags, kp_karmasticker, colormap);
V_DrawKartString(LAPS_X+47, LAPS_Y+3, V_HUDTRANS|splitflags, va("%d/2", stplyr->kartstuff[k_comebackpoints]));
if (numtargets > 9 && maptargets > 9)
V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|splitflags, kp_capsulestickerwide, NULL);
else
V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|splitflags, kp_capsulesticker, NULL);
V_DrawKartString(LAPS_X+47, LAPS_Y+3, V_HUDTRANS|splitflags, va("%d/%d", numtargets, maptargets));
}
else
{
if (stplyr->kartstuff[k_bumper] > 9 && cv_kartbumpers.value > 9)
V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|splitflags, kp_bumperstickerwide, colormap);
if (stplyr->kartstuff[k_bumper] <= 0)
{
V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|splitflags, kp_karmasticker, colormap);
V_DrawKartString(LAPS_X+47, LAPS_Y+3, V_HUDTRANS|splitflags, va("%d/2", stplyr->kartstuff[k_comebackpoints]));
}
else
V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|splitflags, kp_bumpersticker, colormap);
V_DrawKartString(LAPS_X+47, LAPS_Y+3, V_HUDTRANS|splitflags, va("%d/%d", stplyr->kartstuff[k_bumper], cv_kartbumpers.value));
{
INT32 maxbumper = K_StartingBumperCount();
if (stplyr->kartstuff[k_bumper] > 9 && maxbumper > 9)
V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|splitflags, kp_bumperstickerwide, colormap);
else
V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|splitflags, kp_bumpersticker, colormap);
V_DrawKartString(LAPS_X+47, LAPS_Y+3, V_HUDTRANS|splitflags, va("%d/%d", stplyr->kartstuff[k_bumper], maxbumper));
}
}
}
}
@ -10308,10 +10145,14 @@ static void K_drawBattleFullscreen(void)
V_DrawFadeScreen(0xFF00, 16);
if (stplyr->exiting < 6*TICRATE && !stplyr->spectator)
{
if (stplyr->kartstuff[k_position] == 1)
V_DrawFixedPatch(x<<FRACBITS, y<<FRACBITS, scale, splitflags, kp_battlewin, NULL);
else
V_DrawFixedPatch(x<<FRACBITS, y<<FRACBITS, scale, splitflags, (K_IsPlayerLosing(stplyr) ? kp_battlelose : kp_battlecool), NULL);
patch_t *p = kp_battlecool;
if (K_IsPlayerLosing(stplyr))
p = kp_battlelose;
else if (stplyr->kartstuff[k_position] == 1)
p = kp_battlewin;
V_DrawFixedPatch(x<<FRACBITS, y<<FRACBITS, scale, splitflags, p, NULL);
}
else
K_drawKartFinish();

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);
@ -34,7 +33,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);
@ -68,8 +66,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

@ -19,7 +19,7 @@ UINT16 clientpowerlevels[MAXPLAYERS][PWRLV_NUMTYPES];
// Which players spec-scummed, and their power level before scumming.
// On race finish, everyone is considered to have "won" against these people.
INT16 nospectategrief[MAXPLAYERS];
INT16 nospectategrief[MAXPLAYERS];
// Game setting scrambles based on server Power Level
SINT8 speedscramble = -1;

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

@ -172,7 +172,8 @@ unlockable_t unlockables[MAXUNLOCKABLES] =
/* 05 */ {"Encore Mode", "", 4, 5, SECRET_ENCORE, 0, false, false, 0},
/* 06 */ {"Hell Attack", "", 6, 6, SECRET_HELLATTACK, 0, false, false, 0},
/* 07 */ {"Record Attack", "", -1, -1, SECRET_RECORDATTACK, 0, true, true, 0},
/* 07 */ {"Time Attack", "", -1, -1, SECRET_TIMEATTACK, 0, true, true, 0},
/* 08 */ {"Break the Capsules", "", -1, -1, SECRET_BREAKTHECAPSULES, 0, true, true, 0},
};
// Default number of emblems and extra emblems

View file

@ -118,8 +118,8 @@ typedef struct
#define SECRET_ITEMFINDER -5 // Enables Item Finder/Emblem Radar
#define SECRET_EMBLEMHINTS -4 // Enables Emblem Hints
#define SECRET_PANDORA -3 // Enables Pandora's Box
#define SECRET_RECORDATTACK -2 // Enables Record Attack on the main menu
#define SECRET_NIGHTSMODE -1 // Enables NiGHTS Mode on the main menu
#define SECRET_TIMEATTACK -2 // Enables Time Attack on the main menu
#define SECRET_BREAKTHECAPSULES -1 // Enables Break the Capsules on the main menu
#define SECRET_HEADER 0 // Does nothing on its own, just serves as a header for the menu
#define SECRET_LEVELSELECT 1 // Selectable level select
#define SECRET_WARP 2 // Selectable warp

View file

@ -138,8 +138,8 @@ typedef enum
{
LLM_CREATESERVER,
LLM_LEVELSELECT,
LLM_RECORDATTACK,
LLM_NIGHTSATTACK
LLM_TIMEATTACK,
LLM_BREAKTHECAPSULES
} levellist_mode_t;
levellist_mode_t levellistmode = LLM_CREATESERVER;
@ -205,9 +205,7 @@ static char *M_GetConditionString(condition_t cond);
menu_t SR_MainDef, SR_UnlockChecklistDef;
// Misc. Main Menu
#if 0 // Bring this back when we have actual single-player
static void M_SinglePlayerMenu(INT32 choice);
#endif
static void M_Options(INT32 choice);
static void M_Manual(INT32 choice);
static void M_SelectableClearMenus(INT32 choice);
@ -230,7 +228,7 @@ menu_t MISC_ScrambleTeamDef, MISC_ChangeTeamDef, MISC_ChangeSpectateDef;
//static void M_LoadGame(INT32 choice);
static void M_TimeAttack(INT32 choice);
static boolean M_QuitTimeAttackMenu(void);
//static void M_NightsAttack(INT32 choice);
static void M_BreakTheCapsules(INT32 choice);
static void M_Statistics(INT32 choice);
static void M_HandleStaffReplay(INT32 choice);
static void M_ReplayTimeAttack(INT32 choice);
@ -482,11 +480,10 @@ static consvar_t cv_dummystaff = {"dummystaff", "0", CV_HIDEN|CV_CALL, dummystaf
static menuitem_t MainMenu[] =
{
{IT_SUBMENU|IT_STRING, NULL, "Extras", &SR_MainDef, 76},
//{IT_CALL |IT_STRING, NULL, "1 Player", M_SinglePlayerMenu, 84},
#ifdef TESTERS
{IT_GRAYEDOUT, NULL, "Time Attack", NULL, 84},
{IT_GRAYEDOUT, NULL, "1 Player", NULL, 84},
#else
{IT_CALL |IT_STRING, NULL, "Time Attack", M_TimeAttack, 84},
{IT_CALL |IT_STRING, NULL, "1 Player", M_SinglePlayerMenu, 84},
#endif
{IT_SUBMENU|IT_STRING, NULL, "Multiplayer", &MP_MainDef, 92},
{IT_CALL |IT_STRING, NULL, "Options", M_Options, 100},
@ -806,18 +803,16 @@ static menuitem_t SR_EmblemHintMenu[] =
// Single Player Main
static menuitem_t SP_MainMenu[] =
{
//{IT_CALL | IT_STRING, NULL, "Start Game", M_LoadGame, 92},
{IT_SECRET, NULL, "Record Attack", M_TimeAttack, 100},
//{IT_SECRET, NULL, "NiGHTS Mode", M_NightsAttack, 108},
{IT_CALL | IT_STRING | IT_CALL_NOTMODIFIED, NULL, "Statistics", M_Statistics, 108},
//{IT_CALL | IT_STRING, NULL, "Grand Prix", M_LoadGame, 92},
{IT_SECRET, NULL, "Time Attack", M_TimeAttack, 100},
{IT_SECRET, NULL, "Break the Capsules", M_BreakTheCapsules, 108},
};
enum
{
//sploadgame,
sprecordattack,
//spnightsmode,
spstatistics
//spgrandprix,
sptimeattack,
spbreakthecapsules
};
// Single Player Load Game
@ -1879,52 +1874,6 @@ static menu_t SP_GhostDef =
NULL
};
/*static menu_t SP_NightsAttackDef =
{
"M_NIGHTS",
sizeof (SP_NightsAttackMenu)/sizeof (menuitem_t),
&MainDef, // Doesn't matter.
SP_NightsAttackMenu,
M_DrawNightsAttackMenu,
32, 40,
0,
NULL
};
static menu_t SP_NightsReplayDef =
{
"M_NIGHTS",
sizeof(SP_NightsReplayMenu)/sizeof(menuitem_t),
&SP_NightsAttackDef,
SP_NightsReplayMenu,
M_DrawNightsAttackMenu,
32, 120,
0,
NULL
};
static menu_t SP_NightsGuestReplayDef =
{
"M_NIGHTS",
sizeof(SP_NightsGuestReplayMenu)/sizeof(menuitem_t),
&SP_NightsAttackDef,
SP_NightsGuestReplayMenu,
M_DrawNightsAttackMenu,
32, 120,
0,
NULL
};
static menu_t SP_NightsGhostDef =
{
"M_NIGHTS",
sizeof(SP_NightsGhostMenu)/sizeof(menuitem_t),
&SP_NightsAttackDef,
SP_NightsGhostMenu,
M_DrawNightsAttackMenu,
32, 120,
0,
NULL
};*/
/*menu_t SP_PlayerDef =
{
"M_PICKP",
@ -2163,7 +2112,7 @@ static void Nextmap_OnChange(void)
CV_StealthSetValue(&cv_dummystaff, 0);
active = false;
active = 0;
SP_TimeAttackMenu[taguest].status = IT_DISABLED;
SP_TimeAttackMenu[tareplay].status = IT_DISABLED;
//SP_TimeAttackMenu[taghost].status = IT_DISABLED;
@ -2184,11 +2133,15 @@ static void Nextmap_OnChange(void)
SP_GuestReplayMenu[0].status = IT_WHITESTRING|IT_CALL;
active |= 3;
}
if (FIL_FileExists(va("%s-%s-lap-best.lmp", gpath, cv_chooseskin.string))) {
SP_ReplayMenu[1].status = IT_WHITESTRING|IT_CALL;
SP_GuestReplayMenu[1].status = IT_WHITESTRING|IT_CALL;
active |= 3;
if (levellistmode != LLM_BREAKTHECAPSULES) {
if (FIL_FileExists(va("%s-%s-lap-best.lmp", gpath, cv_chooseskin.string))) {
SP_ReplayMenu[1].status = IT_WHITESTRING|IT_CALL;
SP_GuestReplayMenu[1].status = IT_WHITESTRING|IT_CALL;
active |= 3;
}
}
if (FIL_FileExists(va("%s-%s-last.lmp", gpath, cv_chooseskin.string))) {
SP_ReplayMenu[2].status = IT_WHITESTRING|IT_CALL;
SP_GuestReplayMenu[2].status = IT_WHITESTRING|IT_CALL;
@ -4263,11 +4216,13 @@ boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt)
return false; // not unlocked
return true;*/
case LLM_RECORDATTACK:
case LLM_TIMEATTACK:
case LLM_BREAKTHECAPSULES:
/*if (!(mapheaderinfo[mapnum]->menuflags & LF2_RECORDATTACK))
return false;*/
if (!(mapheaderinfo[mapnum]->typeoflevel & TOL_RACE))
if ((levellistmode == LLM_TIMEATTACK && !(mapheaderinfo[mapnum]->typeoflevel & TOL_RACE))
|| (levellistmode == LLM_BREAKTHECAPSULES && !(mapheaderinfo[mapnum]->typeoflevel & TOL_MATCH)))
return false;
if (M_MapLocked(mapnum+1))
@ -4286,20 +4241,6 @@ boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt)
return false;*/
return true;
/*case LLM_NIGHTSATTACK:
if (!(mapheaderinfo[mapnum]->menuflags & LF2_NIGHTSATTACK))
return false;
if (M_MapLocked(mapnum+1))
return false; // not unlocked
if (mapheaderinfo[mapnum]->menuflags & LF2_NOVISITNEEDED)
return true;
if (!mapvisited[mapnum])
return false;
return true;*/
default:
return false;
}
@ -6627,18 +6568,16 @@ static void M_Credits(INT32 choice)
// SINGLE PLAYER MENU
// ==================
#if 0 // Bring this back when we have actual single-player
static void M_SinglePlayerMenu(INT32 choice)
{
(void)choice;
SP_MainMenu[sprecordattack].status =
(M_SecretUnlocked(SECRET_RECORDATTACK)) ? IT_CALL|IT_STRING : IT_SECRET;
/*SP_MainMenu[spnightsmode].status =
(M_SecretUnlocked(SECRET_NIGHTSMODE)) ? IT_CALL|IT_STRING : IT_SECRET;*/
SP_MainMenu[sptimeattack].status =
(M_SecretUnlocked(SECRET_TIMEATTACK)) ? IT_CALL|IT_STRING : IT_SECRET;
SP_MainMenu[spbreakthecapsules].status =
(M_SecretUnlocked(SECRET_BREAKTHECAPSULES)) ? IT_CALL|IT_STRING : IT_SECRET;
M_SetupNextMenu(&SP_MainDef);
}
#endif
/*static void M_LoadGameLevelSelect(INT32 choice)
{
@ -7624,8 +7563,11 @@ void M_DrawTimeAttackMenu(void)
V_DrawFill((BASEVIDWIDTH - dupadjust)>>1, 78, dupadjust, 36, 159);
V_DrawRightAlignedString(149, 80, highlightflags, "BEST LAP:");
K_drawKartTimestamp(lap, 19, 86, 0, 2);
if (levellistmode != LLM_BREAKTHECAPSULES)
{
V_DrawRightAlignedString(149, 80, highlightflags, "BEST LAP:");
K_drawKartTimestamp(lap, 19, 86, 0, 2);
}
V_DrawRightAlignedString(292, 80, highlightflags, "BEST TIME:");
K_drawKartTimestamp(time, 162, 86, cv_nextmap.value, 1);
@ -7714,11 +7656,43 @@ static void M_TimeAttack(INT32 choice)
memset(skins_cons_t, 0, sizeof (skins_cons_t));
levellistmode = LLM_RECORDATTACK; // Don't be dependent on cv_newgametype
levellistmode = LLM_TIMEATTACK; // Don't be dependent on cv_newgametype
if (M_CountLevelsToShowInList() == 0)
{
M_StartMessage(M_GetText("No record-attackable levels found.\n"),NULL,MM_NOTHING);
M_StartMessage(M_GetText("No levels found for Time Attack.\n"),NULL,MM_NOTHING);
return;
}
M_PatchSkinNameTable();
M_PrepareLevelSelect();
M_SetupNextMenu(&SP_TimeAttackDef);
G_SetGamestate(GS_TIMEATTACK);
if (cv_nextmap.value)
Nextmap_OnChange();
else
CV_AddValue(&cv_nextmap, 1);
itemOn = tastart; // "Start" is selected.
S_ChangeMusicInternal("racent", true);
}
// Same as above, but sets a different levellistmode. Should probably be merged...
static void M_BreakTheCapsules(INT32 choice)
{
(void)choice;
memset(skins_cons_t, 0, sizeof (skins_cons_t));
levellistmode = LLM_BREAKTHECAPSULES; // Don't be dependent on cv_newgametype
if (M_CountLevelsToShowInList() == 0)
{
M_StartMessage(M_GetText("No levels found for Break the Capsules.\n"),NULL,MM_NOTHING);
return;
}
@ -7852,13 +7826,13 @@ static boolean M_QuitTimeAttackMenu(void)
}*/
// Going to Nights Attack menu...
/*static void M_NightsAttack(INT32 choice)
/*static void M_BreakTheCapsules(INT32 choice)
{
(void)choice;
memset(skins_cons_t, 0, sizeof (skins_cons_t));
levellistmode = LLM_NIGHTSATTACK; // Don't be dependent on cv_newgametype
levellistmode = LLM_BREAKTHECAPSULES; // Don't be dependent on cv_newgametype
if (M_CountLevelsToShowInList() == 0)
{
@ -7886,7 +7860,7 @@ static boolean M_QuitTimeAttackMenu(void)
(void)choice;
emeralds = 0;
M_ClearMenus(true);
modeattacking = ATTACKING_NIGHTS;
modeattacking = ATTACKING_CAPSULES;
I_mkdir(va("%s"PATHSEP"replay", srb2home), 0755);
I_mkdir(va("%s"PATHSEP"replay"PATHSEP"%s", srb2home, timeattackfolder), 0755);
@ -7910,7 +7884,7 @@ static void M_ChooseTimeAttack(INT32 choice)
(void)choice;
emeralds = 0;
M_ClearMenus(true);
modeattacking = ATTACKING_RECORD;
modeattacking = (levellistmode == LLM_BREAKTHECAPSULES ? ATTACKING_CAPSULES : ATTACKING_RECORD);
I_mkdir(va("%s"PATHSEP"replay", srb2home), 0755);
I_mkdir(va("%s"PATHSEP"replay"PATHSEP"%s", srb2home, timeattackfolder), 0755);
@ -7960,7 +7934,7 @@ static void M_HandleStaffReplay(INT32 choice)
if (l == LUMPERROR)
break;
M_ClearMenus(true);
modeattacking = ATTACKING_RECORD;
modeattacking = (levellistmode == LLM_BREAKTHECAPSULES ? ATTACKING_CAPSULES : ATTACKING_RECORD);
demo.loadfiles = false; demo.ignorefiles = true; // Just assume that record attack replays have the files needed
G_DoPlayDemo(va("%sS%02u",G_BuildMapName(cv_nextmap.value),cv_dummystaff.value));
break;
@ -7981,7 +7955,7 @@ static void M_ReplayTimeAttack(INT32 choice)
{
const char *which;
M_ClearMenus(true);
modeattacking = ATTACKING_RECORD; // set modeattacking before G_DoPlayDemo so the map loader knows
modeattacking = (levellistmode == LLM_BREAKTHECAPSULES ? ATTACKING_CAPSULES : ATTACKING_RECORD); // set modeattacking before G_DoPlayDemo so the map loader knows
demo.loadfiles = false; demo.ignorefiles = true; // Just assume that record attack replays have the files needed
if (currentMenu == &SP_ReplayDef)
@ -8128,10 +8102,8 @@ static void M_ModeAttackRetry(INT32 choice)
{
(void)choice;
G_CheckDemoStatus(); // Cancel recording
if (modeattacking == ATTACKING_RECORD)
if (modeattacking)
M_ChooseTimeAttack(0);
/*else if (modeattacking == ATTACKING_NIGHTS)
M_ChooseNightsAttack(0);*/
}
static void M_ModeAttackEndGame(INT32 choice)
@ -8143,16 +8115,10 @@ static void M_ModeAttackEndGame(INT32 choice)
Command_ExitGame_f();
M_StartControlPanel();
switch(modeattacking)
{
default:
case ATTACKING_RECORD:
if (modeattacking)
currentMenu = &SP_TimeAttackDef;
break;
/*case ATTACKING_NIGHTS:
currentMenu = &SP_NightsAttackDef;
break;*/
}
itemOn = currentMenu->lastOn;
G_SetGamestate(GS_TIMEATTACK);
modeattacking = ATTACKING_NONE;

View file

@ -25,6 +25,7 @@
#include "lua_hook.h"
#include "k_kart.h" // SRB2kart
#include "k_waypoint.h"
#include "k_battle.h"
#ifdef HW3SOUND
#include "hardware/hw3sound.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"
#include "k_pwrlv.h"
// CTF player names
@ -1785,7 +1786,7 @@ void P_CheckTimeLimit(void)
if (!(multiplayer || netgame))
return;
if (G_RaceGametype())
if (G_RaceGametype() || battlecapsules)
return;
if (leveltime < (timelimitintics + starttime))
@ -2516,6 +2517,45 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source)
S_StartSound(target, sfx_s3k80);
}
break;
case MT_BATTLECAPSULE:
{
mobj_t *cur;
numtargets++;
target->fuse = 16;
target->flags |= MF_NOCLIP|MF_NOCLIPTHING;
cur = target->hnext;
while (cur && !P_MobjWasRemoved(cur))
{
// Shoot every piece outward
if (!(cur->x == target->x && cur->y == target->y))
{
P_InstaThrust(cur,
R_PointToAngle2(target->x, target->y, cur->x, cur->y),
R_PointToDist2(target->x, target->y, cur->x, cur->y) / 12
);
}
cur->momz = 8 * target->scale * P_MobjFlip(target);
cur->flags &= ~MF_NOGRAVITY;
cur->tics = TICRATE;
cur->frame &= ~FF_ANIMATE; // Stop animating the propellers
cur = cur->hnext;
}
// All targets busted!
if (numtargets >= maptargets)
{
UINT8 i;
for (i = 0; i < MAXPLAYERS; i++)
P_DoPlayerExit(&players[i]);
}
}
break;
default:
break;

View file

@ -227,7 +227,6 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state);
boolean P_SetMobjState(mobj_t *mobj, statenum_t state);
//void P_RunShields(void);
void P_RunOverlays(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

@ -25,6 +25,7 @@
#include "s_sound.h"
#include "w_wad.h"
#include "k_kart.h" // SRB2kart 011617
#include "k_collide.h"
#include "hu_stuff.h" // SRB2kart
#include "i_system.h" // SRB2kart
@ -819,7 +820,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
// SRB2kart 011617 - Colission[sic] code for kart items //{
if (thing->type == MT_SMK_ICEBLOCK)
if (tmthing->type == MT_SMK_ICEBLOCK)
{
// see if it went over / under
if (tmthing->z > thing->z + thing->height)
@ -827,31 +828,20 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (tmthing->z + tmthing->height < thing->z)
return true; // underneath
if (!(tmthing->flags & MF_SOLID || tmthing->flags & MF_SHOOTABLE || tmthing->flags & MF_BOUNCE))
return true;
return K_SMKIceBlockCollide(tmthing, thing);
}
else if (thing->type == MT_SMK_ICEBLOCK)
{
// see if it went over / under
if (tmthing->z > thing->z + thing->height)
return true; // overhead
if (tmthing->z + tmthing->height < thing->z)
return true; // underneath
if (!(tmthing->health))
return true;
if (tmthing->type == MT_BANANA || tmthing->type == MT_BANANA_SHIELD
|| tmthing->type == MT_EGGMANITEM || tmthing->type == MT_EGGMANITEM_SHIELD
|| tmthing->type == MT_SSMINE || tmthing->type == MT_SSMINE_SHIELD
|| tmthing->type == MT_ORBINAUT_SHIELD || tmthing->type == MT_JAWZ_SHIELD)
return false;
if (thing->health)
P_KillMobj(thing, tmthing, tmthing);
/*if (tmthing->player && (tmthing->player->kartstuff[k_invincibilitytimer] > 0
|| tmthing->player->kartstuff[k_growshrinktimer] > 0))
return true;*/
K_KartBouncing(tmthing, thing, false, true);
return false;
return K_SMKIceBlockCollide(thing, tmthing);
}
// Push fakes out of other items
if (tmthing->type == MT_EGGMANITEM && (thing->type == MT_RANDOMITEM || thing->type == MT_EGGMANITEM))
if (tmthing->type == MT_EGGMANITEM)
{
// see if it went over / under
if (tmthing->z > thing->z + thing->height)
@ -859,10 +849,10 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (tmthing->z + tmthing->height < thing->z)
return true; // underneath
P_InstaThrust(tmthing, R_PointToAngle2(thing->x, thing->y, tmthing->x, tmthing->y), thing->radius/4);
K_EggItemCollide(tmthing, thing);
return true;
}
else if (thing->type == MT_EGGMANITEM && (tmthing->type == MT_RANDOMITEM || tmthing->type == MT_EGGMANITEM))
else if (thing->type == MT_EGGMANITEM)
{
// see if it went over / under
if (tmthing->z > thing->z + thing->height)
@ -870,7 +860,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (tmthing->z + tmthing->height < thing->z)
return true; // underneath
P_InstaThrust(thing, R_PointToAngle2(tmthing->x, tmthing->y, thing->x, thing->y), tmthing->radius/4);
K_EggItemCollide(thing, tmthing);
return true;
}
@ -886,97 +876,10 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (tmthing->z + tmthing->height < thing->z)
return true; // underneath
if (((tmthing->target == thing) || (tmthing->target == thing->target)) && (tmthing->threshold > 0 || (thing->type != MT_PLAYER && thing->threshold > 0)))
return true;
if (tmthing->health <= 0 || thing->health <= 0)
return true;
if ((tmthing->type == MT_ORBINAUT_SHIELD || tmthing->type == MT_JAWZ_SHIELD) && tmthing->lastlook
&& (thing->type == MT_ORBINAUT_SHIELD || thing->type == MT_JAWZ_SHIELD) && thing->lastlook
&& (tmthing->target == thing->target)) // Don't hit each other if you have the same target
return true;
if (thing->player && thing->player->powers[pw_flashing]
&& !(tmthing->type == MT_ORBINAUT || tmthing->type == MT_JAWZ || tmthing->type == MT_JAWZ_DUD))
return true;
if (thing->player && thing->player->kartstuff[k_hyudorotimer])
return true; // no interaction
if (thing->type == MT_PLAYER)
{
// Player Damage
P_DamageMobj(thing, tmthing, tmthing->target, 1);
K_KartBouncing(thing, tmthing, false, false);
S_StartSound(thing, sfx_s3k7b);
// This Item Damage
if (tmthing->eflags & MFE_VERTICALFLIP)
tmthing->z -= tmthing->height;
else
tmthing->z += tmthing->height;
S_StartSound(tmthing, tmthing->info->deathsound);
P_KillMobj(tmthing, thing, thing);
P_SetObjectMomZ(tmthing, 12*FRACUNIT, false);
P_InstaThrust(tmthing, R_PointToAngle2(thing->x, thing->y, tmthing->x, tmthing->y)+ANGLE_90, 16*FRACUNIT);
}
else if (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ || thing->type == MT_JAWZ_DUD
|| thing->type == MT_ORBINAUT_SHIELD || thing->type == MT_JAWZ_SHIELD
|| thing->type == MT_BANANA || thing->type == MT_BANANA_SHIELD
|| thing->type == MT_BALLHOG)
{
// Other Item Damage
if (thing->eflags & MFE_VERTICALFLIP)
thing->z -= thing->height;
else
thing->z += thing->height;
S_StartSound(thing, thing->info->deathsound);
P_KillMobj(thing, tmthing, tmthing);
P_SetObjectMomZ(thing, 12*FRACUNIT, false);
P_InstaThrust(thing, R_PointToAngle2(tmthing->x, tmthing->y, thing->x, thing->y)+ANGLE_90, 16*FRACUNIT);
P_SpawnMobj(thing->x/2 + tmthing->x/2, thing->y/2 + tmthing->y/2, thing->z/2 + tmthing->z/2, MT_ITEMCLASH);
// This Item Damage
if (tmthing->eflags & MFE_VERTICALFLIP)
tmthing->z -= tmthing->height;
else
tmthing->z += tmthing->height;
S_StartSound(tmthing, tmthing->info->deathsound);
P_KillMobj(tmthing, thing, thing);
P_SetObjectMomZ(tmthing, 12*FRACUNIT, false);
P_InstaThrust(tmthing, R_PointToAngle2(thing->x, thing->y, tmthing->x, tmthing->y)+ANGLE_90, 16*FRACUNIT);
}
else if (thing->type == MT_SSMINE_SHIELD || thing->type == MT_SSMINE)
{
// This Item Damage
if (tmthing->eflags & MFE_VERTICALFLIP)
tmthing->z -= tmthing->height;
else
tmthing->z += tmthing->height;
S_StartSound(tmthing, tmthing->info->deathsound);
P_KillMobj(tmthing, thing, thing);
P_SetObjectMomZ(tmthing, 12*FRACUNIT, false);
P_InstaThrust(tmthing, R_PointToAngle2(thing->x, thing->y, tmthing->x, tmthing->y)+ANGLE_90, 16*FRACUNIT);
// Bomb death
P_KillMobj(thing, tmthing, tmthing);
}
else if (thing->flags & MF_SPRING && (tmthing->type == MT_JAWZ || tmthing->type == MT_JAWZ_DUD || tmthing->type == MT_ORBINAUT))
P_DoSpring(thing, tmthing);
return true;
return K_OrbinautJawzCollide(tmthing, thing);
}
else if (tmthing->flags & MF_SPRING && (thing->type == MT_JAWZ || thing->type == MT_JAWZ_DUD || thing->type == MT_ORBINAUT))
else if (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ || thing->type == MT_JAWZ_DUD
|| thing->type == MT_ORBINAUT_SHIELD || thing->type == MT_JAWZ_SHIELD)
{
// see if it went over / under
if (tmthing->z > thing->z + thing->height)
@ -984,14 +887,10 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (tmthing->z + tmthing->height < thing->z)
return true; // underneath
if (thing->health <= 0)
return true;
P_DoSpring(tmthing, thing);
return true;
return K_OrbinautJawzCollide(thing, tmthing);
}
else if (tmthing->type == MT_SINK)
if (tmthing->type == MT_BANANA || tmthing->type == MT_BANANA_SHIELD || tmthing->type == MT_BALLHOG)
{
// see if it went over / under
if (tmthing->z > thing->z + thing->height)
@ -999,34 +898,9 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (tmthing->z + tmthing->height < thing->z)
return true; // underneath
if (((tmthing->target == thing) || (tmthing->target == thing->target)) && (tmthing->threshold > 0 || (thing->type != MT_PLAYER && thing->threshold > 0)))
return true;
if (thing->player && thing->player->powers[pw_flashing])
return true;
if (thing->type == MT_PLAYER)
{
mobj_t *explosion;
S_StartSound(NULL, sfx_bsnipe); // let all players hear it.
HU_SetCEchoFlags(0);
HU_SetCEchoDuration(5);
HU_DoCEcho(va("%s\\was hit by a kitchen sink.\\\\\\\\", player_names[thing->player-players]));
I_OutputMsg("%s was hit by a kitchen sink.\n", player_names[thing->player-players]);
explosion = P_SpawnMobj(thing->x, thing->y, thing->z, MT_SPBEXPLOSION);
explosion->extravalue1 = 1; // Tell K_ExplodePlayer to use extra knockback
if (tmthing->target && !P_MobjWasRemoved(tmthing->target))
P_SetTarget(&explosion->target, tmthing->target);
P_KillMobj(tmthing, thing, thing);
}
return true;
return K_BananaBallhogCollide(tmthing, thing);
}
else if (tmthing->type == MT_MINEEXPLOSION)
else if (thing->type == MT_BANANA || thing->type == MT_BANANA_SHIELD || thing->type == MT_BALLHOG)
{
// see if it went over / under
if (tmthing->z > thing->z + thing->height)
@ -1034,24 +908,10 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (tmthing->z + tmthing->height < thing->z)
return true; // underneath
if (!(thing->type == MT_PLAYER))
return true;
if (thing->player && thing->player->powers[pw_flashing])
return true;
if (thing->type == MT_PLAYER && thing->player)
{
if (tmthing->state == &states[S_MINEEXPLOSION1])
K_ExplodePlayer(thing->player, tmthing->target, tmthing);
else
K_SpinPlayer(thing->player, tmthing->target, 0, tmthing, false);
}
return true; // This doesn't collide with anything, but we want it to effect the player anyway.
return K_BananaBallhogCollide(thing, tmthing);
}
else if (tmthing->type == MT_BANANA_SHIELD || tmthing->type == MT_BANANA
|| tmthing->type == MT_BALLHOG)
if (tmthing->type == MT_SSMINE || tmthing->type == MT_SSMINE_SHIELD)
{
// see if it went over / under
if (tmthing->z > thing->z + thing->height)
@ -1059,78 +919,9 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (tmthing->z + tmthing->height < thing->z)
return true; // underneath
if (((tmthing->target == thing) || (tmthing->target == thing->target)) && (tmthing->threshold > 0 || (thing->type != MT_PLAYER && thing->threshold > 0)))
return true;
if (tmthing->health <= 0 || thing->health <= 0)
return true;
if (((tmthing->type == MT_BANANA_SHIELD) && (thing->type == MT_BANANA_SHIELD))
&& (tmthing->target == thing->target)) // Don't hit each other if you have the same target
return true;
if (tmthing->type == MT_BALLHOG && thing->type == MT_BALLHOG)
return true; // Ballhogs don't collide with eachother
if (thing->player && thing->player->powers[pw_flashing])
return true;
if (thing->type == MT_PLAYER)
{
// Banana snipe!
if (tmthing->type == MT_BANANA && tmthing->health > 1)
S_StartSound(thing, sfx_bsnipe);
// Player Damage
K_SpinPlayer(thing->player, tmthing->target, 0, tmthing, (tmthing->type == MT_BANANA || tmthing->type == MT_BANANA_SHIELD));
// This Item Damage
if (tmthing->eflags & MFE_VERTICALFLIP)
tmthing->z -= tmthing->height;
else
tmthing->z += tmthing->height;
S_StartSound(tmthing, tmthing->info->deathsound);
P_KillMobj(tmthing, thing, thing);
P_SetObjectMomZ(tmthing, 12*FRACUNIT, false);
P_InstaThrust(tmthing, R_PointToAngle2(thing->x, thing->y, tmthing->x, tmthing->y)+ANGLE_90, 16*FRACUNIT);
}
else if (thing->type == MT_BANANA || thing->type == MT_BANANA_SHIELD
|| thing->type == MT_ORBINAUT || thing->type == MT_ORBINAUT_SHIELD
|| thing->type == MT_JAWZ || thing->type == MT_JAWZ_DUD || thing->type == MT_JAWZ_SHIELD
|| thing->type == MT_BALLHOG)
{
// Other Item Damage
if (thing->eflags & MFE_VERTICALFLIP)
thing->z -= thing->height;
else
thing->z += thing->height;
S_StartSound(thing, thing->info->deathsound);
P_KillMobj(thing, tmthing, tmthing);
P_SetObjectMomZ(thing, 12*FRACUNIT, false);
P_InstaThrust(thing, R_PointToAngle2(tmthing->x, tmthing->y, thing->x, thing->y)+ANGLE_90, 16*FRACUNIT);
P_SpawnMobj(thing->x/2 + tmthing->x/2, thing->y/2 + tmthing->y/2, thing->z/2 + tmthing->z/2, MT_ITEMCLASH);
// This Item Damage
if (tmthing->eflags & MFE_VERTICALFLIP)
tmthing->z -= tmthing->height;
else
tmthing->z += tmthing->height;
S_StartSound(tmthing, tmthing->info->deathsound);
P_KillMobj(tmthing, thing, thing);
P_SetObjectMomZ(tmthing, 12*FRACUNIT, false);
P_InstaThrust(tmthing, R_PointToAngle2(thing->x, thing->y, tmthing->x, tmthing->y)+ANGLE_90, 16*FRACUNIT);
}
return true;
return K_MineCollide(tmthing, thing);
}
else if (tmthing->type == MT_SSMINE_SHIELD || tmthing->type == MT_SSMINE)
else if (thing->type == MT_SSMINE || thing->type == MT_SSMINE_SHIELD)
{
// see if it went over / under
if (tmthing->z > thing->z + thing->height)
@ -1138,52 +929,10 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (tmthing->z + tmthing->height < thing->z)
return true; // underneath
if (((tmthing->target == thing) || (tmthing->target == thing->target)) && (tmthing->threshold > 0 || (thing->type != MT_PLAYER && thing->threshold > 0)))
return true;
if (tmthing->health <= 0 || thing->health <= 0)
return true;
if (thing->player && thing->player->powers[pw_flashing])
return true;
if (thing->type == MT_PLAYER)
{
// Bomb punting
if ((tmthing->state >= &states[S_SSMINE1] && tmthing->state <= &states[S_SSMINE4])
|| (tmthing->state >= &states[S_SSMINE_DEPLOY8] && tmthing->state <= &states[S_SSMINE_DEPLOY13]))
P_KillMobj(tmthing, thing, thing);
else
K_PuntMine(tmthing, thing);
}
else if (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ || thing->type == MT_JAWZ_DUD
|| thing->type == MT_ORBINAUT_SHIELD || thing->type == MT_JAWZ_SHIELD)
{
P_KillMobj(tmthing, thing, thing);
// Other Item Damage
if (thing->eflags & MFE_VERTICALFLIP)
thing->z -= thing->height;
else
thing->z += thing->height;
S_StartSound(thing, thing->info->deathsound);
P_KillMobj(thing, tmthing, tmthing);
P_SetObjectMomZ(thing, 12*FRACUNIT, false);
P_InstaThrust(thing, R_PointToAngle2(tmthing->x, tmthing->y, thing->x, thing->y)+ANGLE_90, 16*FRACUNIT);
}
return true;
return K_MineCollide(thing, tmthing);
}
else if (tmthing->type == MT_PLAYER &&
(thing->type == MT_ORBINAUT_SHIELD || thing->type == MT_ORBINAUT
|| thing->type == MT_JAWZ_SHIELD || thing->type == MT_JAWZ || thing->type == MT_JAWZ_DUD
|| thing->type == MT_BANANA_SHIELD || thing->type == MT_BANANA
|| thing->type == MT_SSMINE_SHIELD || thing->type == MT_SSMINE
|| thing->type == MT_MINEEXPLOSION
|| thing->type == MT_SINK || thing->type == MT_BALLHOG
))
if (tmthing->type == MT_MINEEXPLOSION)
{
// see if it went over / under
if (tmthing->z > thing->z + thing->height)
@ -1191,130 +940,63 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (tmthing->z + tmthing->height < thing->z)
return true; // underneath
if (tmthing->player && tmthing->player->powers[pw_flashing]
&& !(thing->type == MT_ORBINAUT || thing->type == MT_JAWZ || thing->type == MT_JAWZ_DUD))
return true;
return K_MineExplosionCollide(tmthing, thing);
}
else if (thing->type == MT_MINEEXPLOSION)
{
// see if it went over / under
if (tmthing->z > thing->z + thing->height)
return true; // overhead
if (tmthing->z + tmthing->height < thing->z)
return true; // underneath
if (tmthing->player && tmthing->player->kartstuff[k_hyudorotimer]) // I thought about doing this for just the objects below but figured it should apply to everything.
return true; // no interaction
return K_MineExplosionCollide(thing, tmthing);
}
if (thing->type == MT_ORBINAUT_SHIELD || thing->type == MT_JAWZ_SHIELD
|| thing->type == MT_ORBINAUT || thing->type == MT_JAWZ || thing->type == MT_JAWZ_DUD)
{
if ((thing->target == tmthing) && (thing->threshold > 0))
return true;
if (tmthing->type == MT_SINK)
{
// see if it went over / under
if (tmthing->z > thing->z + thing->height)
return true; // overhead
if (tmthing->z + tmthing->height < thing->z)
return true; // underneath
if (tmthing->health <= 0 || thing->health <= 0)
return true;
return K_KitchenSinkCollide(tmthing, thing);
}
else if (thing->type == MT_SINK)
{
// see if it went over / under
if (tmthing->z > thing->z + thing->height)
return true; // overhead
if (tmthing->z + tmthing->height < thing->z)
return true; // underneath
// Player Damage
P_DamageMobj(tmthing, thing, thing->target, 1);
K_KartBouncing(tmthing, thing, false, false);
S_StartSound(tmthing, sfx_s3k7b);
return K_KitchenSinkCollide(thing, tmthing);
}
// Other Item Damage
if (thing->eflags & MFE_VERTICALFLIP)
thing->z -= thing->height;
else
thing->z += thing->height;
if (tmthing->type == MT_FALLINGROCK)
{
// see if it went over / under
if (tmthing->z > thing->z + thing->height)
return true; // overhead
if (tmthing->z + tmthing->height < thing->z)
return true; // underneath
S_StartSound(thing, thing->info->deathsound);
P_KillMobj(thing, tmthing, tmthing);
return K_FallingRockCollide(tmthing, thing);
}
else if (thing->type == MT_FALLINGROCK)
{
// see if it went over / under
if (tmthing->z > thing->z + thing->height)
return true; // overhead
if (tmthing->z + tmthing->height < thing->z)
return true; // underneath
P_SetObjectMomZ(thing, 12*FRACUNIT, false);
P_InstaThrust(thing, R_PointToAngle2(tmthing->x, tmthing->y, thing->x, thing->y)+ANGLE_90, 16*FRACUNIT);
}
else if (thing->type == MT_BANANA_SHIELD || thing->type == MT_BANANA
|| thing->type == MT_BALLHOG)
{
if ((thing->target == tmthing) && (thing->threshold > 0))
return true;
if (tmthing->health <= 0 || thing->health <= 0)
return true;
// Banana snipe!
if (thing->type == MT_BANANA && thing->health > 1)
S_StartSound(tmthing, sfx_bsnipe);
// Player Damage
K_SpinPlayer(tmthing->player, thing->target, 0, thing, (thing->type == MT_BANANA || thing->type == MT_BANANA_SHIELD));
// Other Item Damage
if (thing->eflags & MFE_VERTICALFLIP)
thing->z -= thing->height;
else
thing->z += thing->height;
S_StartSound(thing, thing->info->deathsound);
P_KillMobj(thing, tmthing, tmthing);
P_SetObjectMomZ(thing, 12*FRACUNIT, false);
P_InstaThrust(thing, R_PointToAngle2(tmthing->x, tmthing->y, thing->x, thing->y)+ANGLE_90, 16*FRACUNIT);
}
else if (thing->type == MT_SSMINE_SHIELD || thing->type == MT_SSMINE)
{
if ((thing->target == tmthing) && (thing->threshold > 0))
return true;
if (tmthing->health <= 0 || thing->health <= 0)
return true;
// Bomb punting
if ((thing->state >= &states[S_SSMINE1] && thing->state <= &states[S_SSMINE4])
|| (thing->state >= &states[S_SSMINE_DEPLOY8] && thing->state <= &states[S_SSMINE_DEPLOY13]))
P_KillMobj(thing, tmthing, tmthing);
else
K_PuntMine(thing, tmthing);
}
else if (thing->type == MT_MINEEXPLOSION && tmthing->player)
{
// Player Damage
if (thing->state == &states[S_MINEEXPLOSION1])
K_ExplodePlayer(tmthing->player, thing->target, thing);
else
K_SpinPlayer(tmthing->player, thing->target, 0, thing, false);
return true;
}
else if (thing->type == MT_SINK)
{
mobj_t *explosion;
if ((thing->target == tmthing) && (thing->threshold > 0))
return true;
S_StartSound(NULL, sfx_bsnipe); // let all players hear it.
HU_SetCEchoFlags(0);
HU_SetCEchoDuration(5);
HU_DoCEcho(va("%s\\was hit by a kitchen sink.\\\\\\\\", player_names[tmthing->player-players]));
I_OutputMsg("%s was hit by a kitchen sink.\n", player_names[tmthing->player-players]);
explosion = P_SpawnMobj(tmthing->x, tmthing->y, tmthing->z, MT_SPBEXPLOSION);
explosion->extravalue1 = 1; // Tell K_ExplodePlayer to use extra knockback
if (thing->target && !P_MobjWasRemoved(thing->target))
P_SetTarget(&explosion->target, thing->target);
P_KillMobj(thing, tmthing, tmthing);
}
return true;
return K_FallingRockCollide(thing, tmthing);
}
//}
if ((thing->type == MT_FALLINGROCK && (tmthing->player || tmthing->type == MT_FALLINGROCK))
|| (tmthing->type == MT_FALLINGROCK && (thing->player || thing->type == MT_FALLINGROCK)))
{
// see if it went over / under
if (tmthing->z > thing->z + thing->height)
return true; // overhead
if (tmthing->z + tmthing->height < thing->z)
return true; // underneath
K_KartBouncing(thing, tmthing, false, false);
}
if ((thing->type == MT_SPRINGSHELL || thing->type == MT_YELLOWSHELL) && thing->health > 0
&& (tmthing->player || (tmthing->flags & MF_PUSHABLE)) && tmthing->health > 0)
{

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}};
@ -3614,12 +3615,15 @@ boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled
dummy.y = thiscam->y;
dummy.z = thiscam->z;
dummy.height = thiscam->height;
if (player->pflags & PF_TIMEOVER)
if ((player->pflags & PF_TIMEOVER) && G_RaceGametype())
player->karthud[khud_timeovercam] = (2*TICRATE)+1;
if (!resetcalled && !(player->pflags & PF_NOCLIP || leveltime < introtime) && !P_CheckSight(&dummy, player->mo)) // TODO: "P_CheckCameraSight" instead.
P_ResetCamera(player, thiscam);
else
P_SlideCameraMove(thiscam);
if (resetcalled) // Okay this means the camera is fully reset.
return true;
}
@ -6268,216 +6272,6 @@ static void P_RemoveOverlay(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, fixed_t scale, mobjtype_t type, boolean ceiling)
{
UINT8 i;
fixed_t flatz[MAXPLANESPERSECTOR];
boolean flip[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
for (i = 0; i < MAXPLANESPERSECTOR; i++)
flip[i] = false;
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) - FixedMul(mobjinfo[type].height, scale);
#else
flatz[numflats] = (sec->ceilingheight) - FixedMul(mobjinfo[type].height, scale);
#endif
flip[numflats] = true;
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) - FixedMul(mobjinfo[type].height, scale);
#else
flatz[numflats] = (*rover->bottomheight) - FixedMul(mobjinfo[type].height, scale);
#endif
flip[numflats] = true;
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]))
{
const fixed_t sbz = skyboxmo[0]->z;
fixed_t checkz = sec->floorheight;
while (checkz < sec->ceilingheight)
{
P_TeleportMove(skyboxmo[0], skyboxmo[0]->x, skyboxmo[0]->y, checkz);
if (P_CheckSight(skyboxmo[0], mo))
{
P_RemoveMobj(mo);
break;
}
else
checkz += 32*mapobjectscale;
}
P_TeleportMove(skyboxmo[0], skyboxmo[0]->x, skyboxmo[0]->y, sbz);
if (P_MobjWasRemoved(mo))
continue;
}
P_SetScale(mo, scale);
if (flip[i])
{
mo->flags2 |= MF2_OBJECTFLIP;
mo->eflags |= MFE_VERTICALFLIP;
}
switch(type)
{
case MT_OVERTIMEFOG:
mo->destscale = 8*mo->scale;
mo->momz = P_RandomRange(1,8)*mo->scale;
break;
case MT_OVERTIMEORB:
//mo->destscale = mo->scale/4;
mo->frame += ((leveltime/4) % 8);
/*if (battleovertime.enabled < 10*TICRATE)
mo->flags2 |= MF2_SHADOW;*/
mo->angle = R_PointToAngle2(mo->x, mo->y, battleovertime.x, battleovertime.y) + ANGLE_90;
mo->z += P_RandomRange(0,48) * mo->scale;
break;
default:
break;
}
}
}
#undef MAXPLANESPERSECTOR
void P_RunBattleOvertime(void)
{
UINT16 i, j;
if (battleovertime.enabled < 10*TICRATE)
{
battleovertime.enabled++;
if (battleovertime.enabled == TICRATE)
S_StartSound(NULL, sfx_bhurry);
if (battleovertime.enabled == 10*TICRATE)
S_StartSound(NULL, sfx_kc40);
}
else
{
if (battleovertime.radius > battleovertime.minradius)
battleovertime.radius -= mapobjectscale;
else
battleovertime.radius = battleovertime.minradius;
}
if (leveltime & 1)
{
UINT8 transparency = tr_trans50;
if (!r_splitscreen && players[displayplayers[0]].mo)
{
INT32 dist = P_AproxDistance(battleovertime.x-players[displayplayers[0]].mo->x, battleovertime.y-players[displayplayers[0]].mo->y);
transparency = max(0, NUMTRANSMAPS - ((256 + (dist>>FRACBITS)) / 256));
}
if (transparency < NUMTRANSMAPS)
{
mobj_t *beam = P_SpawnMobj(battleovertime.x, battleovertime.y, battleovertime.z + (mobjinfo[MT_RANDOMITEM].height/2), MT_OVERTIMEBEAM);
P_SetScale(beam, beam->scale*2);
if (transparency > 0)
beam->frame |= transparency<<FF_TRANSSHIFT;
}
}
// 16 orbs at the normal minimum size of 512
{
const fixed_t pi = (22<<FRACBITS) / 7; // loose approximation, this doesn't need to be incredibly precise
fixed_t scale = mapobjectscale + (battleovertime.radius/2048);
fixed_t sprwidth = 32*scale;
fixed_t circumference = FixedMul(pi, battleovertime.radius<<1);
UINT16 orbs = circumference / sprwidth;
angle_t angoff = ANGLE_MAX / orbs;
for (i = 0; i < orbs; i++)
{
angle_t ang = (i * angoff) + FixedAngle((leveltime/2)<<FRACBITS);
fixed_t x = battleovertime.x + P_ReturnThrustX(NULL, ang, battleovertime.radius - FixedMul(mobjinfo[MT_OVERTIMEORB].radius, scale));
fixed_t y = battleovertime.y + P_ReturnThrustY(NULL, ang, battleovertime.radius - FixedMul(mobjinfo[MT_OVERTIMEORB].radius, scale));
P_SpawnOvertimeParticles(x, y, scale, MT_OVERTIMEORB, false);
}
}
if (battleovertime.enabled < 10*TICRATE)
return;
/*if (!S_IdPlaying(sfx_s3kd4s)) // global ambience
S_StartSoundAtVolume(NULL, sfx_s3kd4s, min(255, ((4096*mapobjectscale) - battleovertime.radius)>>FRACBITS / 2));*/
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);
fixed_t closestdist = battleovertime.radius + (8*mobjinfo[MT_OVERTIMEFOG].radius);
j++;
if (P_AproxDistance(x-battleovertime.x, y-battleovertime.y) < closestdist)
continue;
P_SpawnOvertimeParticles(x, y, 4*mapobjectscale, MT_OVERTIMEFOG, false);
break;
}
}
}
void A_BossDeath(mobj_t *mo);
// AI for the Koopa boss.
static void P_KoopaThinker(mobj_t *koopa)
@ -7124,6 +6918,18 @@ void P_MobjThinker(mobj_t *mobj)
P_SetMobjStateNF(smok, smok->info->painstate); // same function, diff sprite
}
break;
case MT_BATTLECAPSULE_PIECE:
if (mobj->extravalue2)
mobj->frame |= FF_VERTICALFLIP;
else
mobj->frame &= ~FF_VERTICALFLIP;
if (mobj->flags2 & MF2_OBJECTFLIP)
mobj->eflags |= MFE_VERTICALFLIP;
if (mobj->tics > 0)
mobj->flags2 ^= MF2_DONTDRAW;
break;
//}
case MT_WATERDROP:
P_SceneryCheckWater(mobj);
@ -7571,6 +7377,27 @@ void P_MobjThinker(mobj_t *mobj)
return;
}
break;
case MT_BATTLECAPSULE:
if (!(mobj->fuse & 1))
{
const SINT8 amt = 96;
mobj_t *dust;
UINT8 i;
for (i = 0; i < 2; i++)
{
fixed_t xoffset = P_RandomRange(-amt, amt) * mobj->scale;
fixed_t yoffset = P_RandomRange(-amt, amt) * mobj->scale;
fixed_t zoffset = P_RandomRange(-(amt >> 1), (amt >> 1)) * mobj->scale;
dust = P_SpawnMobj(mobj->x + xoffset, mobj->y + yoffset,
mobj->z + (mobj->height >> 1) + zoffset, MT_EXPLODE);
}
if (dust && !P_MobjWasRemoved(dust)) // Only do for 1 explosion
S_StartSound(dust, sfx_s3k3d);
}
break;
//}
default:
break;
@ -9392,6 +9219,229 @@ void P_MobjThinker(mobj_t *mobj)
trail->color = mobj->color;
}
break;
case MT_BATTLECAPSULE:
{
SINT8 realflip = P_MobjFlip(mobj);
SINT8 flip = realflip; // Flying capsules needs flipped sprites, but not flipped gravity
fixed_t bottom;
mobj_t *cur;
if (mobj->extravalue1)
{
const INT32 speed = 6*TICRATE; // longer is slower
const fixed_t pi = 22*FRACUNIT/7; // Inaccurate, but is close enough for our usage
fixed_t sine = FINESINE((((2*pi*speed) * leveltime) >> ANGLETOFINESHIFT) & FINEMASK) * flip;
// Flying capsules are flipped upside-down, like S3K
flip = -flip;
// ALL CAPSULE MOVEMENT NEEDS TO HAPPEN AFTER THIS & ADD TO MOMENTUM FOR BOBBING TO BE ACCURATE
mobj->momz = sine/2;
}
// Moving capsules
if (mobj->target && !P_MobjWasRemoved(mobj->target))
{
fixed_t speed = mobj->movefactor;
UINT8 sequence = mobj->lastlook;
UINT8 num = mobj->movecount;
boolean backandforth = (mobj->flags2 & MF2_AMBUSH);
SINT8 direction = mobj->cvmem;
mobj_t *next = NULL;
thinker_t *th;
fixed_t dist, momx, momy, momz;
dist = P_AproxDistance(mobj->target->x - mobj->x, mobj->target->y - mobj->y);
if (mobj->extravalue1)
dist = P_AproxDistance(dist, mobj->target->z - mobj->z);
if (dist < 1)
dist = 1;
if (speed <= dist)
{
momx = FixedMul(FixedDiv(mobj->target->x - mobj->x, dist), speed);
momy = FixedMul(FixedDiv(mobj->target->y - mobj->y, dist), speed);
if (mobj->extravalue1)
momz = mobj->momz + FixedMul(FixedDiv(mobj->target->z - mobj->z, dist), speed);
mobj->momx = momx;
mobj->momy = momy;
if (mobj->extravalue1)
mobj->momz = momz;
}
else
{
mobj_t *mo2;
speed -= dist;
P_UnsetThingPosition(mobj);
mobj->x = mobj->target->x;
mobj->y = mobj->target->y;
mobj->z = mobj->target->z;
P_SetThingPosition(mobj);
mobj->floorz = mobj->subsector->sector->floorheight;
mobj->ceilingz = mobj->subsector->sector->ceilingheight;
// Onto the next waypoint!
for (th = thinkercap.next; th != &thinkercap; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
continue;
mo2 = (mobj_t *)th;
if (mo2->type != MT_TUBEWAYPOINT)
continue;
if (mo2->threshold == sequence)
{
if (mo2->health == num + direction)
{
next = mo2;
break;
}
}
}
// Are we at the end of the waypoint chain?
// If so, search again for the first/previous waypoint (depending on settings)
if (next == NULL)
{
if (backandforth)
{
mobj->cvmem = -mobj->cvmem;
direction = mobj->cvmem;
}
for (th = thinkercap.next; th != &thinkercap; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
continue;
mo2 = (mobj_t *)th;
if (mo2->type != MT_TUBEWAYPOINT)
continue;
if (mo2->threshold == sequence)
{
if (backandforth)
{
if (mo2->health == num + direction)
{
next = mo2;
break;
}
}
else
{
if (direction < 0)
{
if (next == NULL || mo2->health > next->health)
next = mo2;
}
else
{
if (next == NULL || mo2->health < next->health)
next = mo2;
}
}
}
}
}
if (next && !P_MobjWasRemoved(next))
{
P_SetTarget(&mobj->target, next);
mobj->movecount = next->health;
dist = P_AproxDistance(mobj->target->x - mobj->x, mobj->target->y - mobj->y);
if (mobj->extravalue1)
dist = P_AproxDistance(dist, mobj->target->z - mobj->z);
if (dist < 1)
dist = 1;
momx = FixedMul(FixedDiv(mobj->target->x - mobj->x, dist), speed);
momy = FixedMul(FixedDiv(mobj->target->y - mobj->y, dist), speed);
if (mobj->extravalue1)
momz = mobj->momz + FixedMul(FixedDiv(mobj->target->z - mobj->z, dist), speed);
mobj->momx = momx;
mobj->momy = momy;
if (mobj->extravalue1)
mobj->momz = momz;
}
else
{
CONS_Alert(CONS_WARNING, "Moving capsule could not find next waypoint! (seq: %d)\n", sequence);
P_SetTarget(&mobj->target, NULL);
}
}
}
if (flip == -1)
bottom = mobj->z + mobj->height;
else
bottom = mobj->z;
cur = mobj->hnext;
// Move each piece to the proper position
while (cur && !P_MobjWasRemoved(cur))
{
fixed_t newx = mobj->x;
fixed_t newy = mobj->y;
fixed_t newz = bottom;
statenum_t state = (statenum_t)(cur->state-states);
cur->scale = mobj->scale;
cur->destscale = mobj->destscale;
cur->scalespeed = mobj->scalespeed;
cur->extravalue2 = mobj->extravalue1;
cur->flags2 = (cur->flags2 & ~MF2_OBJECTFLIP)|(mobj->flags2 & MF2_OBJECTFLIP);
if (state == S_BATTLECAPSULE_TOP)
newz += (80 * mobj->scale * flip);
else if (state == S_BATTLECAPSULE_BUTTON)
newz += (108 * mobj->scale * flip);
else if (state == S_BATTLECAPSULE_SUPPORT
|| state == S_BATTLECAPSULE_SUPPORTFLY
|| state == S_KARMAWHEEL)
{
fixed_t offx = mobj->radius;
fixed_t offy = mobj->radius;
if (cur->extravalue1 & 1)
offx = -offx;
if (cur->extravalue1 > 1)
offy = -offy;
newx += offx;
newy += offy;
}
else if (state == S_BATTLECAPSULE_SIDE1
|| state == S_BATTLECAPSULE_SIDE2)
{
fixed_t offset = 48 * mobj->scale;
angle_t angle = (ANGLE_45 * cur->extravalue1);
newx += FixedMul(offset, FINECOSINE(angle >> ANGLETOFINESHIFT));
newy += FixedMul(offset, FINESINE(angle >> ANGLETOFINESHIFT));
newz += (12 * mobj->scale * flip);
cur->angle = angle + ANGLE_90;
}
P_TeleportMove(cur, newx, newy, newz);
cur = cur->hnext;
}
}
case MT_RANDOMITEM:
if (G_BattleGametype() && mobj->threshold == 70)
{
@ -11276,7 +11326,7 @@ void P_SpawnPlayer(INT32 playernum)
|| (p->jointime <= 1 && pcount <= 1))
{
if (leveltime < 1 || (p->jointime <= 1 && pcount <= 1)) // Start of the map?
p->kartstuff[k_bumper] = cv_kartbumpers.value; // Reset those bumpers!
p->kartstuff[k_bumper] = K_StartingBumperCount(); // Reset those bumpers!
if (p->kartstuff[k_bumper])
{

View file

@ -35,6 +35,7 @@
#endif
// SRB2Kart
#include "k_battle.h"
#include "k_pwrlv.h"
savedata_t savedata;
@ -3320,6 +3321,8 @@ static void P_NetArchiveMisc(void)
// SRB2kart
WRITEINT32(save_p, numgotboxes);
WRITEUINT8(save_p, numtargets);
WRITEUINT8(save_p, battlecapsules);
WRITEUINT8(save_p, gamespeed);
WRITEUINT8(save_p, franticitems);
@ -3443,6 +3446,8 @@ static inline boolean P_NetUnArchiveMisc(void)
// SRB2kart
numgotboxes = READINT32(save_p);
numtargets = READUINT8(save_p);
battlecapsules = (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
#include "k_pwrlv.h"
#include "k_waypoint.h"
@ -1026,6 +1027,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);
}
@ -1082,14 +1089,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);
}
@ -2297,15 +2309,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;
battlecapsules = false;
// emerald hunt
hunt1 = hunt2 = hunt3 = NULL;
@ -2634,15 +2644,18 @@ static void P_LoadRecordGhosts(void)
}
// Best Lap ghost
if (cv_ghost_bestlap.value)
if (modeattacking != ATTACKING_CAPSULES)
{
for (i = 0; i < numskins; ++i)
if (cv_ghost_bestlap.value)
{
if (cv_ghost_bestlap.value == 1 && players[consoleplayer].skin != i)
continue;
for (i = 0; i < numskins; ++i)
{
if (cv_ghost_bestlap.value == 1 && players[consoleplayer].skin != i)
continue;
if (FIL_FileExists(va("%s-%s-lap-best.lmp", gpath, skins[i].name)))
G_AddGhost(va("%s-%s-lap-best.lmp", gpath, skins[i].name));
if (FIL_FileExists(va("%s-%s-lap-best.lmp", gpath, skins[i].name)))
G_AddGhost(va("%s-%s-lap-best.lmp", gpath, skins[i].name));
}
}
}
@ -3175,49 +3188,10 @@ boolean P_SetupLevel(boolean skipprecip)
}
}
if (modeattacking == ATTACKING_RECORD && !demo.playback)
if (modeattacking && !demo.playback)
P_LoadRecordGhosts();
/*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)
@ -3347,6 +3321,8 @@ boolean P_SetupLevel(boolean skipprecip)
if (!(netgame || multiplayer) && !majormods)
mapvisited[gamemap-1] |= MV_VISITED;
G_AddMapToBuffer(gamemap-1);
levelloading = false;
P_RunCachedActions();
@ -3384,7 +3360,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

@ -1983,7 +1983,7 @@ void P_SwitchWeather(UINT8 newWeather)
return; // Nothing to do.
purge = true;
}
else
else
{
if (precipprops[curWeather].type != MT_NULL)
{
@ -2024,7 +2024,7 @@ void P_SwitchWeather(UINT8 newWeather)
precipmobj->flags = mobjinfo[swap].flags;
st = mobjinfo[swap].spawnstate;
if (randomstates > 0)
{
UINT8 mrand = M_RandomByte();
@ -5699,6 +5699,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"
#include "k_waypoint.h"
// Object place
@ -636,14 +637,15 @@ 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++)
if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo))
P_PlayerAfterThink(&players[i]);
if (G_BattleGametype() && battleovertime.enabled)
K_RunBattleOvertime();
#ifdef HAVE_BLUA
LUAh_ThinkFrame();
#endif
@ -793,14 +795,15 @@ 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++)
if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo))
P_PlayerAfterThink(&players[i]);
if (G_BattleGametype() && battleovertime.enabled)
K_RunBattleOvertime();
#ifdef HAVE_BLUA
LUAh_ThinkFrame();
#endif

View file

@ -1158,10 +1158,10 @@ boolean P_EndingMusic(player_t *player)
sprintf(buffer, "k*fail"); // F-Zero death results theme
else
{
if (bestlocalpos == 1)
sprintf(buffer, "k*win");
else if (K_IsPlayerLosing(bestlocalplayer))
if (K_IsPlayerLosing(bestlocalplayer))
sprintf(buffer, "k*lose");
else if (bestlocalpos == 1)
sprintf(buffer, "k*win");
else
sprintf(buffer, "k*ok");
}
@ -6969,9 +6969,10 @@ static void P_DeathThink(player_t *player)
if (player->bot) // don't allow bots to do any of the below, B_CheckRespawn does all they need for respawning already
goto notrealplayer;
if (player->pflags & PF_TIMEOVER)
if ((player->pflags & PF_TIMEOVER) && G_RaceGametype())
{
player->karthud[khud_timeovercam]++;
if (player->mo)
{
player->mo->flags |= (MF_NOGRAVITY|MF_NOCLIP);
@ -7186,7 +7187,7 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
|| (leveltime < introtime)); // Kart intro cam
#endif
if (player->pflags & PF_TIMEOVER) // 1 for momentum keep, 2 for turnaround
if ((player->pflags & PF_TIMEOVER) && G_RaceGametype()) // 1 for momentum keep, 2 for turnaround
timeover = (player->karthud[khud_timeovercam] > 2*TICRATE ? 2 : 1);
else
timeover = 0;

View file

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

View file

@ -1272,7 +1272,7 @@ static void ST_drawNiGHTSHUD(void) // SRB2kart - unused.
#endif
)
{
if (modeattacking == ATTACKING_NIGHTS)
if (modeattacking == ATTACKING_CAPSULES)
{
INT32 maretime = max(stplyr->realtime - stplyr->marebegunat, 0);
fixed_t cornerx = vid.width, cornery = vid.height-SCZ(20);

View file

@ -39,6 +39,7 @@
#include "m_random.h" // M_RandomKey
#include "g_input.h" // PLAYER1INPUTDOWN
#include "k_kart.h" // colortranslations
#include "k_battle.h"
#include "k_pwrlv.h"
#include "console.h" // cons_menuhighlight
#include "lua_hook.h" // IntermissionThinker hook
@ -168,7 +169,7 @@ static void Y_UnloadVoteData(void);
//
// SRB2Kart - Y_CalculateMatchData and ancillary functions
//
static void Y_CompareRace(INT32 i)
static void Y_CompareTime(INT32 i)
{
UINT32 val = ((players[i].pflags & PF_TIMEOVER || players[i].realtime == UINT32_MAX)
? (UINT32_MAX-1) : players[i].realtime);
@ -180,7 +181,7 @@ static void Y_CompareRace(INT32 i)
data.match.num[data.match.numplayers] = i;
}
static void Y_CompareBattle(INT32 i)
static void Y_CompareScore(INT32 i)
{
UINT32 val = ((players[i].pflags & PF_TIMEOVER)
? (UINT32_MAX-1) : players[i].marescore);
@ -440,7 +441,7 @@ void Y_IntermissionDrawer(void)
if (data.match.rankingsmode)
timeheader = "PWR.LV";
else
timeheader = (intertype == int_race ? "TIME" : "SCORE");
timeheader = ((intertype == int_race || (intertype == int_match && battlecapsules)) ? "TIME" : "SCORE");
// draw the level name
V_DrawCenteredString(-4 + x + BASEVIDWIDTH/2, 12, 0, data.match.levelstring);
@ -559,7 +560,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 && battlecapsules))
{
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]));
@ -745,7 +746,7 @@ void Y_Ticker(void)
remove = 10;
// Remove 10 points at a time
data.match.increase[data.match.num[q]] -= remove;
data.match.increase[data.match.num[q]] -= remove;
// Still not zero, no kaching yet
if (data.match.increase[data.match.num[q]] != 0)
@ -795,11 +796,26 @@ static void Y_UpdateRecordReplays(void)
if (!mainrecords[gamemap-1])
G_AllocMainRecordData(gamemap-1);
if ((mainrecords[gamemap-1]->time == 0) || (players[consoleplayer].realtime < mainrecords[gamemap-1]->time))
mainrecords[gamemap-1]->time = players[consoleplayer].realtime;
if (players[consoleplayer].pflags & PF_TIMEOVER)
{
players[consoleplayer].realtime = UINT32_MAX;
}
if ((mainrecords[gamemap-1]->lap == 0) || (bestlap < mainrecords[gamemap-1]->lap))
mainrecords[gamemap-1]->lap = bestlap;
if (((mainrecords[gamemap-1]->time == 0) || (players[consoleplayer].realtime < mainrecords[gamemap-1]->time))
&& (players[consoleplayer].realtime < UINT32_MAX)) // DNF
{
mainrecords[gamemap-1]->time = players[consoleplayer].realtime;
}
if (modeattacking == ATTACKING_RECORD)
{
if ((mainrecords[gamemap-1]->lap == 0) || (bestlap < mainrecords[gamemap-1]->lap))
mainrecords[gamemap-1]->lap = bestlap;
}
else
{
mainrecords[gamemap-1]->lap = 0;
}
// Save demo!
bestdemo[255] = '\0';
@ -830,13 +846,16 @@ static void Y_UpdateRecordReplays(void)
CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW RECORD TIME!"), M_GetText("Saved replay as"), bestdemo);
}
snprintf(bestdemo, 255, "%s-%s-lap-best.lmp", gpath, cv_chooseskin.string);
if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & (1<<1))
{ // Better lap time, save this demo.
if (FIL_FileExists(bestdemo))
remove(bestdemo);
FIL_WriteFile(bestdemo, buf, len);
CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW RECORD LAP!"), M_GetText("Saved replay as"), bestdemo);
if (modeattacking == ATTACKING_RECORD)
{
snprintf(bestdemo, 255, "%s-%s-lap-best.lmp", gpath, cv_chooseskin.string);
if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & (1<<1))
{ // Better lap time, save this demo.
if (FIL_FileExists(bestdemo))
remove(bestdemo);
FIL_WriteFile(bestdemo, buf, len);
CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW RECORD LAP!"), M_GetText("Saved replay as"), bestdemo);
}
}
//CONS_Printf("%s '%s'\n", M_GetText("Saved replay as"), lastdemo);
@ -1036,12 +1055,20 @@ void Y_StartIntermission(void)
{
timer = 0;
/* // srb2kart: time attack tally is UGLY rn
if (modeattacking)
intertype = int_timeattack;
else
*/
intertype = int_race;
if (!majormods && !multiplayer && !demo.playback) // move this once we have a proper time attack screen
{
// Update visitation flags
mapvisited[gamemap-1] |= MV_BEATEN;
if (ALL7EMERALDS(emeralds))
mapvisited[gamemap-1] |= MV_ALLEMERALDS;
/*if (ultimatemode)
mapvisited[gamemap-1] |= MV_ULTIMATE;
if (data.coop.gotperfbonus)
mapvisited[gamemap-1] |= MV_PERFECT;*/
if (modeattacking)
Y_UpdateRecordReplays();
}
}
else
{
@ -1056,13 +1083,13 @@ void Y_StartIntermission(void)
if (!timer)
timer = 1;
}
if (gametype == GT_MATCH)
intertype = int_match;
else //if (gametype == GT_RACE)
intertype = int_race;
}
if (gametype == GT_MATCH)
intertype = int_match;
else //if (gametype == GT_RACE)
intertype = int_race;
// We couldn't display the intermission even if we wanted to.
// But we still need to give the players their score bonuses, dummy.
//if (dedicated) return;
@ -1076,30 +1103,24 @@ void Y_StartIntermission(void)
case int_match:
{
// Calculate who won
Y_CalculateMatchData(0, Y_CompareBattle);
if (battlecapsules)
{
Y_CalculateMatchData(0, Y_CompareTime);
}
else
{
Y_CalculateMatchData(0, Y_CompareScore);
}
if (cv_inttime.value > 0)
S_ChangeMusicInternal("racent", true); // loop it
break;
}
case int_race: // (time-only race)
{
if (!majormods && !multiplayer && !demo.playback) // remove this once we have a proper time attack screen
{
// Update visitation flags
mapvisited[gamemap-1] |= MV_BEATEN;
if (ALL7EMERALDS(emeralds))
mapvisited[gamemap-1] |= MV_ALLEMERALDS;
/*if (ultimatemode)
mapvisited[gamemap-1] |= MV_ULTIMATE;
if (data.coop.gotperfbonus)
mapvisited[gamemap-1] |= MV_PERFECT;*/
if (modeattacking == ATTACKING_RECORD)
Y_UpdateRecordReplays();
}
// Calculate who won
Y_CalculateMatchData(0, Y_CompareRace);
Y_CalculateMatchData(0, Y_CompareTime);
break;
}