Merge branch 'master' of https://git.do.srb2.org/KartKrew/Kart into other-progression

This commit is contained in:
toaster 2023-11-18 18:00:05 +00:00
commit a55803b690
48 changed files with 1010 additions and 118 deletions

View file

@ -117,6 +117,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
lua_blockmaplib.c
lua_hudlib.c
lua_hudlib_drawlist.c
lua_profile.cpp
k_kart.c
k_respawn.c
k_collide.cpp

View file

@ -460,7 +460,14 @@ consvar_t cv_usemouse = Player("use_mouse", "Off").values({{0, "Off"}, {1, "On"}
consvar_t cv_vhseffect = Player("vhspause", "On").on_off();
// synchronize page flipping with screen refresh
consvar_t cv_vidwait = GraphicsDriver("vid_wait", "Off").on_off();
extern "C++"
{
namespace srb2::cvarhandler
{
void on_set_vid_wait();
}
}
consvar_t cv_vidwait = GraphicsDriver("vid_wait", "Off").on_off().onchange(srb2::cvarhandler::on_set_vid_wait);
// if true, all sounds are loaded at game startup
consvar_t precachesound = Player("precachesound", "Off").on_off();
@ -855,6 +862,9 @@ consvar_t cv_devmode_screen = PlayerCheat("devmode_screen", "1").min_max(1, 4).d
consvar_t cv_drawpickups = PlayerCheat("drawpickups", "Yes").yes_no().description("Hide rings, spheres, item capsules, prison capsules (visual only)");
consvar_t cv_drawinput = PlayerCheat("drawinput", "No").yes_no().description("Draw turn inputs outside of Record Attack (turn solver debugging)");
void lua_profile_OnChange(void);
consvar_t cv_lua_profile = PlayerCheat("lua_profile", "0").values(CV_Unsigned).onchange(lua_profile_OnChange).description("Show hook timings over an average of N tics");
void CV_palette_OnChange(void);
consvar_t cv_palette = PlayerCheat("palette", "").onchange_noinit(CV_palette_OnChange).description("Force palette to a different lump");
consvar_t cv_palettenum = PlayerCheat("palettenum", "0").values(CV_Unsigned).onchange_noinit(CV_palette_OnChange).description("Use a different sub-palette by default");

View file

@ -2565,6 +2565,7 @@ void CL_ClearPlayer(INT32 playernum)
// TODO: Any better handling in store?
P_SetTarget(&players[playernum].flickyAttacker, NULL);
P_SetTarget(&players[playernum].powerup.flickyController, NULL);
P_SetTarget(&players[playernum].powerup.barrier, NULL);
// These are camera items and possibly belong to multiple players.
P_SetTarget(&players[playernum].skybox.viewpoint, NULL);
@ -6146,6 +6147,7 @@ boolean TryRunTics(tic_t realtics)
DEBFILE(va("============ Running tic %d (local %d)\n", gametic, localgametic));
ps_prevtictime = ps_tictime;
ps_tictime = I_GetPreciseTime();
dontRun = ExtraDataTicker();

View file

@ -96,6 +96,10 @@
#include "lua_script.h"
#include "lua_profile.h"
extern "C" consvar_t cv_lua_profile;
/* Manually defined asset hashes
* Last updated 2019 / 01 / 18 - Kart v1.0.2 - Main assets
* Last updated 2020 / 08 / 30 - Kart v1.3 - patch.kart
@ -765,6 +769,11 @@ static bool D_Display(void)
M_DrawPerfStats();
}
if (cv_lua_profile.value > 0)
{
LUA_RenderTimers();
}
ps_swaptime = I_GetPreciseTime();
I_FinishUpdate(); // page flip or blit buffer
ps_swaptime = I_GetPreciseTime() - ps_swaptime;

View file

@ -70,6 +70,7 @@
#include "k_powerup.h"
#include "k_roulette.h"
#include "k_bans.h"
#include "k_director.h"
#ifdef SRB2_CONFIG_ENABLE_WEBM_MOVIES
#include "m_avrecorder.h"
@ -1461,6 +1462,33 @@ void D_SendPlayerConfig(UINT8 n)
WeaponPref_Send(n);
}
static camera_t *LocalMutableCamera(INT32 playernum)
{
if (demo.playback)
{
// TODO: could have splitscreen support
if (!camera[0].freecam)
{
return NULL;
}
return &camera[0];
}
if (G_IsPartyLocal(playernum))
{
UINT8 viewnum = G_PartyPosition(playernum);
camera_t *cam = &camera[viewnum];
if (cam->freecam || (players[playernum].spectator && !K_DirectorIsAvailable(viewnum)))
{
return cam;
}
}
return NULL;
}
void D_Cheat(INT32 playernum, INT32 cheat, ...)
{
va_list ap;
@ -1468,12 +1496,62 @@ void D_Cheat(INT32 playernum, INT32 cheat, ...)
UINT8 buf[64];
UINT8 *p = buf;
camera_t *cam;
if ((cam = LocalMutableCamera(playernum)))
{
switch (cheat)
{
case CHEAT_RELATIVE_TELEPORT:
va_start(ap, cheat);
cam->x += va_arg(ap, fixed_t);
cam->y += va_arg(ap, fixed_t);
cam->z += va_arg(ap, fixed_t);
va_end(ap);
return;
case CHEAT_TELEPORT:
va_start(ap, cheat);
cam->x = va_arg(ap, fixed_t);
cam->y = va_arg(ap, fixed_t);
cam->z = va_arg(ap, fixed_t);
va_end(ap);
return;
case CHEAT_ANGLE:
va_start(ap, cheat);
cam->angle = va_arg(ap, angle_t);
va_end(ap);
return;
default:
break;
}
}
if (!CV_CheatsEnabled())
{
CONS_Printf("This cannot be used without cheats enabled.\n");
return;
}
if (demo.playback && cheat == CHEAT_DEVMODE)
{
// There is no networking in demos, but devmode is
// too useful to be inaccessible!
// TODO: maybe allow everything, even though it would
// desync replays? May be useful for debugging.
va_start(ap, cheat);
cht_debug = va_arg(ap, UINT32);
va_end(ap);
return;
}
// sanity check
if (demo.playback)
{
return;
}
WRITEUINT8(p, playernum);
WRITEUINT8(p, cheat);

View file

@ -212,6 +212,8 @@ typedef enum
NUMPOWERUPS = ENDOFPOWERUPS - FIRSTPOWERUP,
} kartitems_t;
#define POWERUP_BIT(x) (1 << ((x) - FIRSTPOWERUP))
typedef enum
{
KSHIELD_NONE = 0,
@ -546,6 +548,7 @@ struct powerupvars_t {
UINT16 barrierTimer;
UINT16 rhythmBadgeTimer;
mobj_t *flickyController;
mobj_t *barrier;
};
// player_t struct for all alternative viewpoint variables

View file

@ -4787,6 +4787,10 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
"S_BLENDEYE_PUYO_SHOCK",
"S_BLENDEYE_PUYO_DIE",
"S_BLENDEYE_PUYO_DUST",
"S_MEGABARRIER1",
"S_MEGABARRIER2",
"S_MEGABARRIER3",
};
// RegEx to generate this from info.h: ^\tMT_([^,]+), --> \t"MT_\1",
@ -5994,6 +5998,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
"MT_BLENDEYE_PUYO",
"MT_BLENDEYE_PUYO_DUST",
"MT_BLENDEYE_PUYO_DUST_COFFEE",
"MT_MEGABARRIER",
};
const char *const MOBJFLAG_LIST[] = {
@ -6653,6 +6658,7 @@ struct int_const_s const INT_CONST[] = {
{"RF_SHADOWEFFECTS",RF_SHADOWEFFECTS},
{"RF_DROPSHADOW",RF_DROPSHADOW},
{"RF_ABSOLUTELIGHTLEVEL",RF_ABSOLUTELIGHTLEVEL},
{"RF_REDUCEVFX",RF_REDUCEVFX},
{"RF_DONTDRAW",RF_DONTDRAW},
{"RF_DONTDRAWP1",RF_DONTDRAWP1},
{"RF_DONTDRAWP2",RF_DONTDRAWP2},

View file

@ -2262,6 +2262,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
P_SetTarget(&players[player].awayview.mobj, NULL);
P_SetTarget(&players[player].flickyAttacker, NULL);
P_SetTarget(&players[player].powerup.flickyController, NULL);
P_SetTarget(&players[player].powerup.barrier, NULL);
// The following pointers are safe to set directly, because the end goal should be refcount consistency before and after remanifestation.
ringShooter = players[player].ringShooter;
@ -5627,6 +5628,10 @@ void G_SaveGameData(void)
// Also save profiles here.
PR_SaveProfiles();
#ifdef DEVELOP
CONS_Alert(CONS_NOTICE, M_GetText("Gamedata saved.\n"));
#endif
}
#define VERSIONSIZE 16

View file

@ -3383,7 +3383,7 @@ static void HWR_SplitSprite(gl_vissprite_t *spr)
}
if (R_ThingIsSemiBright(spr->mobj))
lightlevel = 128 + (lightlevel>>1);
lightlevel = 192 + (lightlevel>>1);
for (i = 0; i < sector->numlights; i++)
{
@ -3398,7 +3398,7 @@ static void HWR_SplitSprite(gl_vissprite_t *spr)
lightlevel = *list[i].lightlevel > 255 ? 255 : *list[i].lightlevel;
if (R_ThingIsSemiBright(spr->mobj))
lightlevel = 128 + (lightlevel>>1);
lightlevel = 192 + (lightlevel>>1);
}
if (!R_ThingIsFullBright(spr->mobj) && !(spr->mobj->renderflags & RF_NOCOLORMAPS))

View file

@ -966,6 +966,8 @@ char sprnames[NUMSPRITES + 1][5] =
"PUYD",
"PUYE",
"MGSH", // Mega Barrier
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later
"VIEW",
};
@ -2025,23 +2027,23 @@ state_t states[NUMSTATES] =
{SPR_TFLM, FF_FULLBRIGHT|5, 2, {NULL}, 0, 0, S_TEAM_SPINFIRE1}, // S_TEAM_SPINFIRE6
// Floor Spike
{SPR_USPK, 0,-1, {A_SpikeRetract}, 1, 0, S_SPIKE2}, // S_SPIKE1 -- Fully extended
{SPR_USPK, 1, 2, {A_Pain}, 0, 0, S_SPIKE3}, // S_SPIKE2
{SPR_USPK, 2, 2, {NULL}, 0, 0, S_SPIKE4}, // S_SPIKE3
{SPR_USPK, 3,-1, {A_SpikeRetract}, 0, 0, S_SPIKE5}, // S_SPIKE4 -- Fully retracted
{SPR_USPK, 2, 2, {A_Pain}, 0, 0, S_SPIKE6}, // S_SPIKE5
{SPR_USPK, 1, 2, {NULL}, 0, 0, S_SPIKE1}, // S_SPIKE6
{SPR_USPK, 4,-1, {NULL}, 0, 0, S_NULL}, // S_SPIKED1 -- Busted spike particles
{SPR_USPK, 5,-1, {NULL}, 0, 0, S_NULL}, // S_SPIKED2
{SPR_USPK, FF_SEMIBRIGHT|0,-1, {A_SpikeRetract}, 1, 0, S_SPIKE2}, // S_SPIKE1 -- Fully extended
{SPR_USPK, FF_SEMIBRIGHT|1, 2, {A_Pain}, 0, 0, S_SPIKE3}, // S_SPIKE2
{SPR_USPK, FF_SEMIBRIGHT|0, 2, {NULL}, 0, 0, S_SPIKE4}, // S_SPIKE3
{SPR_USPK, FF_SEMIBRIGHT|3,-1, {A_SpikeRetract}, 0, 0, S_SPIKE5}, // S_SPIKE4 -- Fully retracted
{SPR_USPK, FF_SEMIBRIGHT|2, 2, {A_Pain}, 0, 0, S_SPIKE6}, // S_SPIKE5
{SPR_USPK, FF_SEMIBRIGHT|1, 2, {NULL}, 0, 0, S_SPIKE1}, // S_SPIKE6
{SPR_USPK, FF_SEMIBRIGHT|4,-1, {NULL}, 0, 0, S_NULL}, // S_SPIKED1 -- Busted spike particles
{SPR_USPK, FF_SEMIBRIGHT|5,-1, {NULL}, 0, 0, S_NULL}, // S_SPIKED2
// Wall Spike
{SPR_WSPK, 0|FF_PAPERSPRITE,-1, {A_SpikeRetract}, 1, 0, S_WALLSPIKE2}, // S_WALLSPIKE1 -- Fully extended
{SPR_WSPK, 1|FF_PAPERSPRITE, 2, {A_Pain}, 0, 0, S_WALLSPIKE3}, // S_WALLSPIKE2
{SPR_WSPK, 2|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_WALLSPIKE4}, // S_WALLSPIKE3
{SPR_WSPK, 3|FF_PAPERSPRITE,-1, {A_SpikeRetract}, 0, 0, S_WALLSPIKE5}, // S_WALLSPIKE4 -- Fully retracted
{SPR_WSPK, 2|FF_PAPERSPRITE, 2, {A_Pain}, 0, 0, S_WALLSPIKE6}, // S_WALLSPIKE5
{SPR_WSPK, 1|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_WALLSPIKE1}, // S_WALLSPIKE6
{SPR_WSPB, 0|FF_PAPERSPRITE,-1, {NULL}, 0, 0, S_NULL}, // S_WALLSPIKEBASE -- Base
{SPR_WSPK, 0|FF_SEMIBRIGHT|FF_PAPERSPRITE,-1, {A_SpikeRetract}, 1, 0, S_WALLSPIKE2}, // S_WALLSPIKE1 -- Fully extended
{SPR_WSPK, 1|FF_SEMIBRIGHT|FF_PAPERSPRITE, 2, {A_Pain}, 0, 0, S_WALLSPIKE3}, // S_WALLSPIKE2
{SPR_WSPK, 2|FF_SEMIBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_WALLSPIKE4}, // S_WALLSPIKE3
{SPR_WSPK, 3|FF_SEMIBRIGHT|FF_PAPERSPRITE,-1, {A_SpikeRetract}, 0, 0, S_WALLSPIKE5}, // S_WALLSPIKE4 -- Fully retracted
{SPR_WSPK, 2|FF_SEMIBRIGHT|FF_PAPERSPRITE, 2, {A_Pain}, 0, 0, S_WALLSPIKE6}, // S_WALLSPIKE5
{SPR_WSPK, 1|FF_SEMIBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_WALLSPIKE1}, // S_WALLSPIKE6
{SPR_WSPB, 0|FF_SEMIBRIGHT|FF_PAPERSPRITE,-1, {NULL}, 0, 0, S_NULL}, // S_WALLSPIKEBASE -- Base
{SPR_WSPK, 4,-1, {NULL}, 0, 0, S_NULL}, // S_WALLSPIKED1 -- Busted spike particles
{SPR_WSPK, 5,-1, {NULL}, 0, 0, S_NULL}, // S_WALLSPIKED2
@ -5613,6 +5615,10 @@ state_t states[NUMSTATES] =
{SPR_PUYA, 3, -1, {A_BlendEyePuyoHack}, 0, 0, S_NULL}, // S_BLENDEYE_PUYO_SHOCK,
{SPR_PUYA, 4|FF_ANIMATE, 5, {A_BlendEyePuyoHack}, 2, 2, S_NULL}, // S_BLENDEYE_PUYO_DIE,
{SPR_PUYA, 5, 2, {A_BlendEyePuyoHack}, 0, 0, S_BLENDEYE_PUYO_DIE}, // S_BLENDEYE_PUYO_DUST,
{SPR_MGSH, 2|FF_PAPERSPRITE|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_MEGABARRIER1,
{SPR_MGSH, 1|FF_PAPERSPRITE|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_MEGABARRIER2,
{SPR_MGSH, 0|FF_PAPERSPRITE|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_MEGABARRIER3,
};
mobjinfo_t mobjinfo[NUMMOBJTYPES] =
@ -5802,7 +5808,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
1000, // mass
0, // damage
sfx_None, // activesound
MF_SOLID|MF_DONTENCOREMAP|MF_APPLYTERRAIN|MF_SLOPE, // flags
MF_SOLID|MF_DONTENCOREMAP|MF_APPLYTERRAIN|MF_SLOPE|MF_SHOOTABLE, // flags
S_NULL // raisestate
},
@ -9365,7 +9371,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
4, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_SCENERY|MF_NOCLIPHEIGHT|MF_NOHITLAGFORME, // flags
MF_NOBLOCKMAP|MF_SCENERY|MF_NOCLIPHEIGHT|MF_NOHITLAGFORME|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -9392,7 +9398,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
4, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SCENERY|MF_NOCLIPHEIGHT|MF_PAPERCOLLISION|MF_NOHITLAGFORME, // flags
MF_NOBLOCKMAP|MF_NOGRAVITY|MF_SCENERY|MF_NOCLIPHEIGHT|MF_PAPERCOLLISION|MF_NOHITLAGFORME|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -24786,7 +24792,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_None, // deathsound
8, // speed
28*FRACUNIT, // radius
56*FRACUNIT, // height
0*FRACUNIT, // height
1, // display offset
16, // mass
0, // damage
@ -24840,7 +24846,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_None, // deathsound
8, // speed
28*FRACUNIT, // radius
56*FRACUNIT, // height
0*FRACUNIT, // height
1, // display offset
16, // mass
0, // damage
@ -24867,7 +24873,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_None, // deathsound
0, // speed
8<<FRACBITS, // radius
16<<FRACBITS, // height
0<<FRACBITS, // height
-1, // display offset
100, // mass
0, // damage
@ -24894,7 +24900,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_None, // deathsound
0, // speed
8<<FRACBITS, // radius
16<<FRACBITS, // height
0<<FRACBITS, // height
1, // display offset
100, // mass
0, // damage
@ -31738,6 +31744,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
MF_SCENERY|MF_NOCLIPTHING|MF_NOCLIPHEIGHT|MF_NOGRAVITY, // flags
S_NULL // raisestate
},
{ // MT_MEGABARRIER
-1, // doomednum
S_MEGABARRIER1, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
0, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
0, // radius
0, // height
0, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_SCENERY|MF_NOSQUISH, // flags
S_NULL // raisestate
}
};

View file

@ -1520,6 +1520,8 @@ typedef enum sprite
SPR_PUYD,
SPR_PUYE,
SPR_MGSH, // Mega Barrier
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later
SPR_VIEW,
@ -6038,6 +6040,10 @@ typedef enum state
S_BLENDEYE_PUYO_DIE,
S_BLENDEYE_PUYO_DUST,
S_MEGABARRIER1,
S_MEGABARRIER2,
S_MEGABARRIER3,
S_FIRSTFREESLOT,
S_LASTFREESLOT = S_FIRSTFREESLOT + NUMSTATEFREESLOTS - 1,
NUMSTATES
@ -7264,6 +7270,8 @@ typedef enum mobj_type
MT_BLENDEYE_PUYO_DUST,
MT_BLENDEYE_PUYO_DUST_COFFEE,
MT_MEGABARRIER,
MT_FIRSTFREESLOT,
MT_LASTFREESLOT = MT_FIRSTFREESLOT + NUMMOBJFREESLOTS - 1,
NUMMOBJTYPES

View file

@ -126,7 +126,7 @@ static void K_SpawnSingleHitLagSpark(
spark->colorized = true;
}
K_ReduceVFX(spark, NULL);
K_ReduceVFXForEveryone(spark);
}
}

View file

@ -320,7 +320,7 @@ UINT32 K_GetPlayerDontDrawFlag(player_t *player)
return flag;
}
void K_ReduceVFX(mobj_t *mo, player_t *owner)
void K_ReduceVFXForEveryone(mobj_t *mo)
{
if (cv_reducevfx.value == 0)
{
@ -329,11 +329,6 @@ void K_ReduceVFX(mobj_t *mo, player_t *owner)
}
mo->renderflags |= RF_DONTDRAW;
if (owner != NULL)
{
mo->renderflags &= ~K_GetPlayerDontDrawFlag(owner);
}
}
// Angle reflection used by springs & speed pads
@ -735,6 +730,11 @@ fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against)
static void K_SpawnBumpForObjs(mobj_t *mobj1, mobj_t *mobj2)
{
if (mobj1->type == MT_KART_LEFTOVER && mobj1->health == 0)
{
return;
}
mobj_t *fx = P_SpawnMobj(
mobj1->x/2 + mobj2->x/2,
mobj1->y/2 + mobj2->y/2,
@ -1739,7 +1739,8 @@ spawn_brake_dust
P_SetScale(spark, (spark->destscale =
FixedMul(scale, spark->scale)));
K_ReduceVFX(spark, master->player);
P_SetTarget(&spark->owner, master);
spark->renderflags |= RF_REDUCEVFX;
}
static void K_SpawnBrakeVisuals(player_t *player)
@ -1816,7 +1817,8 @@ void K_SpawnDriftBoostClip(player_t *player)
P_RandomFlip(P_RandomRange(PR_DECORATION, FRACUNIT/2, FRACUNIT)),
FixedMul(scale, player->speed));
K_ReduceVFX(clip, player);
P_SetTarget(&clip->owner, player->mo);
clip->renderflags |= RF_REDUCEVFX;
}
void K_SpawnDriftBoostClipSpark(mobj_t *clip)
@ -1873,7 +1875,8 @@ static void K_SpawnGenericSpeedLines(player_t *player, boolean top)
}
K_MatchGenericExtraFlags(fast, player->mo);
K_ReduceVFX(fast, player);
P_SetTarget(&fast->owner, player->mo);
fast->renderflags |= RF_REDUCEVFX;
if (top)
{
@ -1952,7 +1955,8 @@ void K_SpawnInvincibilitySpeedLines(mobj_t *mo)
fast->momz = 3*P_GetMobjZMovement(mo)/4;
K_MatchGenericExtraFlags(fast, mo);
K_ReduceVFX(fast, mo->player);
P_SetTarget(&fast->owner, mo);
fast->renderflags |= RF_REDUCEVFX;
fast->color = mo->color;
fast->colorized = true;
@ -3066,7 +3070,8 @@ void K_SpawnWaterRunParticles(mobj_t *mobj)
water->momz = mobj->momz;
P_SetScale(water, trailScale);
P_SetMobjState(water, curUnderlayFrame);
K_ReduceVFX(water, mobj->player);
P_SetTarget(&water->owner, mobj);
water->renderflags |= RF_REDUCEVFX;
// overlay
water = P_SpawnMobj(x1, y1,
@ -3078,7 +3083,8 @@ void K_SpawnWaterRunParticles(mobj_t *mobj)
water->momz = mobj->momz;
P_SetScale(water, trailScale);
P_SetMobjState(water, curOverlayFrame);
K_ReduceVFX(water, mobj->player);
P_SetTarget(&water->owner, mobj);
water->renderflags |= RF_REDUCEVFX;
// Right
// Underlay
@ -3091,7 +3097,8 @@ void K_SpawnWaterRunParticles(mobj_t *mobj)
water->momz = mobj->momz;
P_SetScale(water, trailScale);
P_SetMobjState(water, curUnderlayFrame);
K_ReduceVFX(water, mobj->player);
P_SetTarget(&water->owner, mobj);
water->renderflags |= RF_REDUCEVFX;
// Overlay
water = P_SpawnMobj(x2, y2,
@ -3103,7 +3110,8 @@ void K_SpawnWaterRunParticles(mobj_t *mobj)
water->momz = mobj->momz;
P_SetScale(water, trailScale);
P_SetMobjState(water, curOverlayFrame);
K_ReduceVFX(water, mobj->player);
P_SetTarget(&water->owner, mobj);
water->renderflags |= RF_REDUCEVFX;
if (!S_SoundPlaying(mobj, sfx_s3kdbs))
{
@ -4105,6 +4113,7 @@ void K_InitStumbleIndicator(player_t *player)
P_SetTarget(&player->stumbleIndicator, new);
P_SetTarget(&new->target, player->mo);
new->renderflags |= RF_DONTDRAW;
}
void K_InitWavedashIndicator(player_t *player)
@ -4130,6 +4139,7 @@ void K_InitWavedashIndicator(player_t *player)
P_SetTarget(&player->wavedashIndicator, new);
P_SetTarget(&new->target, player->mo);
new->renderflags |= RF_DONTDRAW;
}
void K_InitTrickIndicator(player_t *player)
@ -5218,7 +5228,8 @@ static void K_SpawnDriftElectricity(player_t *player)
spark->momz = mo->momz;
spark->color = color;
K_GenericExtraFlagsNoZAdjust(spark, mo);
K_ReduceVFX(spark, player);
P_SetTarget(&spark->owner, mo);
spark->renderflags |= RF_REDUCEVFX;
spark->spritexscale += scalefactor/3;
spark->spriteyscale += scalefactor/8;
@ -5289,7 +5300,8 @@ void K_SpawnDriftElectricSparks(player_t *player, int color, boolean shockwave)
sparkangle += ANGLE_90;
K_ReduceVFX(spark, player);
P_SetTarget(&spark->owner, mo);
spark->renderflags |= RF_REDUCEVFX;
}
}
}
@ -5440,7 +5452,8 @@ static void K_SpawnDriftSparks(player_t *player)
spark->tics += trail;
K_MatchGenericExtraFlags(spark, player->mo);
K_ReduceVFX(spark, player);
P_SetTarget(&spark->owner, player->mo);
spark->renderflags |= RF_REDUCEVFX;
}
if (player->driftcharge >= dsthree)
@ -10152,6 +10165,13 @@ static void K_KartDrift(player_t *player, boolean onground)
}
}
if (player->airtime > 2) // Arbitrary number. Small discontinuities due to Super Jank shouldn't thrash your handling properties.
{
player->aizdriftstrat = 0;
keepsliptide = false;
}
if ((player->aizdriftstrat && !player->drift)
|| (keepsliptide))
{
@ -10630,7 +10650,8 @@ void K_KartEbrakeVisuals(player_t *p)
wave = P_SpawnMobj(p->mo->x, p->mo->y, p->mo->floorz, MT_SOFTLANDING);
P_InstaScale(wave, p->mo->scale);
P_SetTarget(&wave->target, p->mo);
K_ReduceVFX(wave, p);
P_SetTarget(&wave->owner, p->mo);
wave->renderflags |= RF_REDUCEVFX;
}
// sound
@ -10663,7 +10684,8 @@ void K_KartEbrakeVisuals(player_t *p)
p->mo->hprev->angle = p->mo->angle;
p->mo->hprev->fuse = TICRATE/2; // When we leave spindash for any reason, make sure this bubble goes away soon after.
K_FlipFromObject(p->mo->hprev, p->mo);
K_ReduceVFX(p->mo->hprev, p);
P_SetTarget(&p->mo->hprev->owner, p->mo);
p->mo->hprev->renderflags |= RF_REDUCEVFX;
p->mo->hprev->sprzoff = p->mo->sprzoff;
p->mo->hprev->colorized = false;
@ -10681,7 +10703,8 @@ void K_KartEbrakeVisuals(player_t *p)
spdl->colorized = true;
spdl->color = SKINCOLOR_WHITE;
K_MatchGenericExtraFlags(spdl, p->mo);
K_ReduceVFX(spdl, p);
P_SetTarget(&spdl->owner, p->mo);
spdl->renderflags |= RF_REDUCEVFX;
P_SetScale(spdl, p->mo->scale);
// squish the player a little bit.
@ -10800,8 +10823,6 @@ static void K_KartSpindashDust(mobj_t *parent)
dust->momx = FixedMul(hmomentum, FINECOSINE(ang >> ANGLETOFINESHIFT));
dust->momy = FixedMul(hmomentum, FINESINE(ang >> ANGLETOFINESHIFT));
dust->momz = vmomentum * flip;
//K_ReduceVFX(dust, parent->player);
}
}
@ -10829,7 +10850,8 @@ static void K_KartSpindashWind(mobj_t *parent)
wind->momz = 3 * P_GetMobjZMovement(parent) / 4;
K_MatchGenericExtraFlags(wind, parent);
K_ReduceVFX(wind, parent->player);
P_SetTarget(&wind->owner, parent);
wind->renderflags |= RF_REDUCEVFX;
}
// Time after which you get a thrust for releasing spindash
@ -13078,7 +13100,8 @@ void K_SetTireGrease(player_t *player, tic_t tics)
P_SetTarget(&grease->target, player->mo);
grease->angle = K_MomentumAngle(player->mo);
grease->extravalue1 = i;
K_ReduceVFX(grease, player);
P_SetTarget(&grease->owner, player->mo);
grease->renderflags |= RF_REDUCEVFX;
}
}

View file

@ -67,7 +67,7 @@ void K_TimerReset(void);
void K_TimerInit(void);
UINT32 K_GetPlayerDontDrawFlag(player_t *player);
void K_ReduceVFX(mobj_t *mo, player_t *owner);
void K_ReduceVFXForEveryone(mobj_t *mo);
boolean K_IsPlayerLosing(player_t *player);
fixed_t K_GetKartGameSpeedScalar(SINT8 value);

View file

@ -2089,6 +2089,8 @@ static void M_DrawProfileCard(INT32 x, INT32 y, boolean greyedout, profile_t *p)
void M_DrawCharacterSelect(void)
{
const UINT8 pid = 0;
UINT8 i, j, k;
UINT8 priority = 0;
INT16 quadx, quady;
@ -2101,6 +2103,19 @@ void M_DrawCharacterSelect(void)
priority = setup_animcounter % setup_numplayers;
}
{
const int kLeft = 80;
const int kTop = 6;
const int kButtonWidth = 16;
INT32 x = basex + kLeft;
K_drawButton((x += 18) * FRACUNIT, (kTop - 3) * FRACUNIT, 0, kp_button_r, M_MenuButtonPressed(pid, MBT_R));
V_DrawThinString((x += kButtonWidth), kTop, 0, "Info");
K_drawButton((x += 58) * FRACUNIT, (kTop - 1) * FRACUNIT, 0, kp_button_c[1], M_MenuButtonPressed(pid, MBT_C));
V_DrawThinString((x += kButtonWidth), kTop, 0, "Default");
}
// We have to loop twice -- first time to draw the drop shadows, a second time to draw the icons.
if (forceskin == false)
{

View file

@ -249,6 +249,7 @@ void Obj_getPlayerOffRideroid(mobj_t *mo); // used in p_map.c to get off of em w
/* LSZ Bungee */
void Obj_BungeeSpecial(mobj_t *mo, player_t *p); // used when the player touches the bungee, to be used in p_inter.c
void Obj_playerBungeeThink(player_t *p); // player interaction with the bungee. The bungee is to be stored in p->mo->tracer.
void Obj_EndBungee(player_t *p);
/* LSZ Balls */
void Obj_EggBallSpawnerThink(mobj_t *mo);
@ -293,6 +294,9 @@ void Obj_BallSwitchThink(mobj_t *mobj);
void Obj_BallSwitchTouched(mobj_t *mobj, mobj_t *toucher);
void Obj_BallSwitchDamaged(mobj_t *mobj, mobj_t *inflictor, mobj_t *source);
/* Barrier Power-Up */
void Obj_SpawnMegaBarrier(player_t *player);
boolean Obj_MegaBarrierThink(mobj_t *mobj);
#ifdef __cplusplus
} // extern "C"

View file

@ -27,17 +27,19 @@ tic_t K_PowerUpRemaining(const player_t* player, kartitems_t powerup)
}
}
boolean K_AnyPowerUpRemaining(const player_t* player)
UINT32 K_AnyPowerUpRemaining(const player_t* player)
{
UINT32 mask = 0;
for (int k = FIRSTPOWERUP; k < ENDOFPOWERUPS; ++k)
{
if (K_PowerUpRemaining(player, static_cast<kartitems_t>(k)))
{
return true;
mask |= POWERUP_BIT(k);
}
}
return false;
return mask;
}
void K_GivePowerUp(player_t* player, kartitems_t powerup, tic_t time)
@ -56,6 +58,7 @@ void K_GivePowerUp(player_t* player, kartitems_t powerup, tic_t time)
case POWERUP_BARRIER:
player->powerup.barrierTimer += time;
Obj_SpawnMegaBarrier(player);
break;
case POWERUP_BUMPER:

View file

@ -9,7 +9,7 @@ extern "C" {
#endif
tic_t K_PowerUpRemaining(const player_t *player, kartitems_t powerup);
boolean K_AnyPowerUpRemaining(const player_t *player);
UINT32 K_AnyPowerUpRemaining(const player_t *player); // returns POWERUP_BIT mask
void K_GivePowerUp(player_t *player, kartitems_t powerup, tic_t timer);
void K_DropPowerUps(player_t *player);

View file

@ -628,7 +628,8 @@ void K_ProcessTerrainEffect(mobj_t *mo)
spark->fuse = 9;
spark->cusval = K_StairJankFlip(ANGLE_90);
P_SetTarget(&spark->target, mo);
K_ReduceVFX(spark, player);
P_SetTarget(&spark->owner, mo);
spark->renderflags |= RF_REDUCEVFX;
}
player->stairjank = 17;

View file

@ -22,7 +22,9 @@
#include "lua_libs.h"
#include "lua_hook.h"
#include "lua_hud.h" // hud_running errors
#include "lua_profile.h"
#include "command.h"
#include "m_perfstats.h"
#include "d_netcmd.h" // for cv_perfstats
#include "i_system.h" // I_GetPreciseTime
@ -365,6 +367,16 @@ static boolean prepare_string_hook
return false;
}
static boolean prepare_hud_hook
(
Hook_State * hook,
int hook_type
){
return init_hook_type(hook, 0,
hook_type, 0, NULL,
hudHookIds[hook_type].numHooks);
}
static void init_hook_call
(
Hook_State * hook,
@ -392,9 +404,52 @@ static void get_hook_from_table(Hook_State *hook, int n)
lua_getref(gL, hookRefs[hook->id]);
}
static int pcall(Hook_State *hook)
{
return lua_pcall(gL, hook->values, hook->results, EINDEX);
}
static const char *hook_name(Hook_State *hook)
{
if (hud_running)
{
return hudHookNames[hook->hook_type];
}
else if (hook->string)
{
return stringHookNames[hook->hook_type];
}
else if (hook->mobj_type > 0)
{
return mobjHookNames[hook->hook_type];
}
else
{
return hookNames[hook->hook_type];
}
}
static int pcall_timed_or_untimed(Hook_State *hook)
{
extern consvar_t cv_lua_profile;
if (!hud_running && cv_lua_profile.value > 0)
{
lua_timer_t *timer = LUA_BeginFunctionTimer(gL, -1 - hook->values, hook_name(hook));
int k = pcall(hook);
LUA_EndFunctionTimer(timer);
return k;
}
else
{
return pcall(hook);
}
}
static int call_single_hook_no_copy(Hook_State *hook)
{
if (lua_pcall(gL, hook->values, hook->results, EINDEX) == 0)
if (pcall_timed_or_untimed(hook) == 0)
{
if (hook->results > 0)
{
@ -625,13 +680,9 @@ int LUA_HookTiccmd(player_t *player, ticcmd_t *cmd, int hook_type)
void LUA_HookHUD(huddrawlist_h list, int hook_type)
{
const hook_t * map = &hudHookIds[hook_type];
Hook_State hook;
if (map->numHooks > 0)
if (prepare_hud_hook(&hook, hook_type))
{
start_hook_stack();
begin_hook_values(&hook);
LUA_SetHudHook(hook_type, list);
hud_running = true; // local hook
@ -640,7 +691,7 @@ void LUA_HookHUD(huddrawlist_h list, int hook_type)
V_ClearClipRect();
init_hook_call(&hook, 0, res_none);
call_mapped(&hook, map);
call_mapped(&hook, &hudHookIds[hook_type]);
hud_running = false;
}

View file

@ -109,6 +109,7 @@ enum mobj_e {
mobj_stringargs,
mobj_reappear,
mobj_punt_ref,
mobj_owner,
};
static const char *const mobj_opt[] = {
@ -198,6 +199,7 @@ static const char *const mobj_opt[] = {
"stringargs",
"reappear",
"punt_ref",
"owner",
NULL};
#define UNIMPLEMENTED luaL_error(L, LUA_QL("mobj_t") " field " LUA_QS " is not implemented for Lua and cannot be accessed.", mobj_opt[field])
@ -508,6 +510,14 @@ static int mobj_get(lua_State *L)
}
LUA_PushUserdata(L, mo->punt_ref, META_MOBJ);
break;
case mobj_owner:
if (mo->owner && P_MobjWasRemoved(mo->owner))
{ // don't put invalid mobj back into Lua.
P_SetTarget(&mo->owner, NULL);
return 0;
}
LUA_PushUserdata(L, mo->owner, META_MOBJ);
break;
default: // extra custom variables in Lua memory
lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS);
I_Assert(lua_istable(L, -1));
@ -910,6 +920,15 @@ static int mobj_set(lua_State *L)
P_SetTarget(&mo->punt_ref, punt_ref);
}
break;
case mobj_owner:
if (lua_isnil(L, 3))
P_SetTarget(&mo->owner, NULL);
else
{
mobj_t *owner = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
P_SetTarget(&mo->owner, owner);
}
break;
default:
lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS);
I_Assert(lua_istable(L, -1));

242
src/lua_profile.cpp Normal file
View file

@ -0,0 +1,242 @@
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2023 by James Robert Roman
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
#include <algorithm>
#include <cstddef>
#include <unordered_map>
#include <string>
#include <string_view>
#include <vector>
#include <fmt/format.h>
extern "C" {
#include "blua/lua.h"
};
#include "v_draw.hpp"
#include "command.h"
#include "doomtype.h"
#include "i_system.h"
#include "lua_profile.h"
#include "m_perfstats.h"
extern "C" consvar_t cv_lua_profile;
namespace
{
precise_t g_time_reference;
int g_tics_counted;
double g_running_tic_time;
double g_avg_tic_time;
bool g_invalid;
}; // namespace
struct lua_timer_t
{
struct Stat
{
double calls = 0;
double time = 0.0;
};
Stat running, avg;
};
namespace
{
std::unordered_map<std::string, lua_timer_t> g_tic_timers;
}; // namespace
lua_timer_t* LUA_BeginFunctionTimer(lua_State* L, int fn_idx, const char* name)
{
lua_Debug ar;
lua_pushvalue(L, fn_idx);
lua_getinfo(L, ">S", &ar);
auto label = [&]
{
using sv = std::string_view;
sv view{ar.source};
switch (view.front())
{
case '@': // file
if (std::size_t p = view.rfind('/'); p != sv::npos) // lump or base
{
return view.substr(p + 1);
}
break;
case '=': // ??
view.remove_prefix(1);
break;
}
return view;
};
auto [it, ins] = g_tic_timers.try_emplace(fmt::format("{}:{} ({})", label(), ar.linedefined, name));
auto& [key, timer] = *it;
g_time_reference = I_GetPreciseTime();
return &timer;
}
void LUA_EndFunctionTimer(lua_timer_t* timer)
{
precise_t t = I_GetPreciseTime() - g_time_reference;
double precision = I_GetPrecisePrecision();
timer->running.time += t / precision;
timer->running.calls += 1.0;
}
void LUA_ResetTicTimers(void)
{
if (cv_lua_profile.value <= 0)
{
return;
}
if (g_tics_counted < cv_lua_profile.value)
{
g_tics_counted++;
double precision = I_GetPrecisePrecision();
g_running_tic_time += ps_prevtictime / precision;
}
else
{
double counted = g_tics_counted;
for (auto& [key, timer] : g_tic_timers)
{
timer.avg = {timer.running.calls / counted, timer.running.time / counted};
timer.running = {};
}
g_avg_tic_time = g_running_tic_time / counted;
g_running_tic_time = 0.0;
g_tics_counted = 1;
g_invalid = false;
}
}
void LUA_RenderTimers(void)
{
using srb2::Draw;
constexpr int kRowHeight = 4;
Draw row = Draw(0, kRowHeight).font(Draw::Font::kConsole).align(Draw::Align::kLeft).scale(0.5).flags(V_MONOSPACE);
row.y(-kRowHeight).text("-- AVERAGES PER TIC (over {} tics) --", cv_lua_profile.value);
if (g_invalid)
{
row.flags(V_GRAYMAP).text(" <Data pending>");
return;
}
std::vector<decltype(g_tic_timers)::iterator> view;
view.reserve(g_tic_timers.size());
auto color_flag = [](double t)
{
if (t < 10.0)
{
return V_GRAYMAP;
}
else if (t >= 100.0)
{
return V_YELLOWMAP;
}
else
{
return 0;
}
};
{
double cum = 0.0;
for (auto it = g_tic_timers.begin(); it != g_tic_timers.end(); ++it)
{
auto& [key, timer] = *it;
cum += timer.avg.time;
if (timer.avg.time > 0.0)
{
view.push_back(it);
}
}
Draw tally = row.flags(color_flag(cum * 1'000'000.0));
tally.text("{:8.2f} us - TOTAL", cum * 1'000'000.0);
tally.y(kRowHeight).text("{:8.2f} ms", cum * 1000.0);
tally.y(kRowHeight * 2).text(
"{:8.2f}% overhead ({:.2f} / {:.2f}) <-- not counting rendering time",
(cum / g_avg_tic_time) * 100.0,
cum * TICRATE,
g_avg_tic_time * TICRATE
);
row = row.y(kRowHeight * 4);
}
std::sort(
view.rbegin(),
view.rend(),
[](auto a, auto b)
{
auto& [k1, t1] = *a;
auto& [k2, t2] = *b;
return t1.avg.time < t2.avg.time;
}
);
for (auto it : view)
{
auto& [key, timer] = *it;
double t = timer.avg.time * 1'000'000.0;
row.flags(color_flag(t)).text(
"{:>8.2f} us {:>8.2f} calls - {}",
t,
timer.avg.calls,
key
);
row = row.y(kRowHeight);
}
}
extern "C" void lua_profile_OnChange(void)
{
g_invalid = true;
if (cv_lua_profile.value == 0)
{
g_tic_timers = {};
}
}

34
src/lua_profile.h Normal file
View file

@ -0,0 +1,34 @@
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2023 by James Robert Roman
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
#ifndef lua_profile_h
#define lua_profile_h
#include "blua/lua.h"
#include "doomtype.h"
#include "typedef.h"
#ifdef __cplusplus
extern "C" {
#endif
struct lua_timer_t;
void LUA_ResetTicTimers(void);
lua_timer_t *LUA_BeginFunctionTimer(lua_State *L, int fn_idx, const char *name);
void LUA_EndFunctionTimer(lua_timer_t *timer);
void LUA_RenderTimers(void);
#ifdef __cplusplus
} // extern "C"
#endif
#endif/*lua_profile_h*/

View file

@ -80,13 +80,17 @@ static UINT8 cheatf_warp(void)
}
}
// Goofy, but this call needs to be before M_ClearMenus because that path
// calls G_LoadLevel, which will trigger a gamedata save. Garbage factory
if (success)
G_SetUsedCheats();
M_ClearMenus(true);
const char *text;
if (success)
{
G_SetUsedCheats();
S_StartSound(0, sfx_kc42);
text = M_GetText(
@ -281,6 +285,9 @@ boolean cht_Interpret(const char *password)
{ CONS_Printf(M_GetText("OBJECTPLACE must be enabled.\n")); return; }
#define REQUIRE_INLEVEL if (gamestate != GS_LEVEL || demo.playback)\
{ CONS_Printf(M_GetText("You must be in a level (and not a replay) to use this.\n")); return; }
#define REQUIRE_INLEVEL_OR_REPLAY if (gamestate != GS_LEVEL)\
{ CONS_Printf(M_GetText("You must be in a level to use this.\n")); return; }
#define REQUIRE_SINGLEPLAYER if (netgame)\
@ -357,7 +364,7 @@ void Command_RTeleport_f(void)
float z = atof(COM_Argv(3));
REQUIRE_CHEATS;
REQUIRE_INLEVEL;
REQUIRE_INLEVEL_OR_REPLAY;
if (COM_Argc() != 4)
{
@ -376,7 +383,7 @@ void Command_Teleport_f(void)
float z = atof(COM_Argv(3));
REQUIRE_CHEATS;
REQUIRE_INLEVEL;
REQUIRE_INLEVEL_OR_REPLAY;
if (COM_Argc() != 4)
{
@ -611,7 +618,7 @@ void Command_Goto_f(void)
const waypoint_t *wayp = K_GetWaypointFromID(id);
REQUIRE_CHEATS;
REQUIRE_INLEVEL;
REQUIRE_INLEVEL_OR_REPLAY;
if (COM_Argc() != 2)
{
@ -635,7 +642,7 @@ void Command_Angle_f(void)
const angle_t angle = FixedAngle(FLOAT_TO_FIXED(anglef));
REQUIRE_CHEATS;
REQUIRE_INLEVEL;
REQUIRE_INLEVEL_OR_REPLAY;
D_Cheat(consoleplayer, CHEAT_ANGLE, angle);
}
@ -657,7 +664,7 @@ void Command_RespawnAt_f(void)
void Command_GotoSkybox_f(void)
{
REQUIRE_CHEATS;
REQUIRE_INLEVEL;
REQUIRE_INLEVEL_OR_REPLAY;
mobj_t *skybox = players[consoleplayer].skybox.viewpoint;

View file

@ -46,6 +46,7 @@ struct perfstatrow {
static precise_t ps_frametime = 0;
precise_t ps_tictime = 0;
precise_t ps_prevtictime = 0;
precise_t ps_playerthink_time = 0;
precise_t ps_botticcmd_time = 0;

View file

@ -30,6 +30,7 @@ typedef enum
} ps_types_t;
extern precise_t ps_tictime;
extern precise_t ps_prevtictime;
extern precise_t ps_playerthink_time;
extern precise_t ps_botticcmd_time;

View file

@ -19,6 +19,8 @@ menuitem_t OPTIONS_Video[] =
{IT_STRING | IT_CVAR, "Fullscreen", "Set whether you want to use fullscreen or windowed mode.",
NULL, {.cvar = &cv_fullscreen}, 0, 0},
#endif
{IT_STRING | IT_CVAR, "Vertical Sync", "Works with your screen to reduce image tearing and judder.",
NULL, {.cvar = &cv_vidwait}, 0, 0},
{IT_NOTHING|IT_SPACE, NULL, "Kanade best waifu! I promise!",
NULL, {NULL}, 0, 0},
@ -27,13 +29,13 @@ menuitem_t OPTIONS_Video[] =
{IT_STRING | IT_CVAR | IT_CV_SLIDER, "Gamma", "Adjusts the overall brightness of the game.",
NULL, {.cvar = &cv_globalgamma}, 0, 0},
{IT_STRING | IT_CVAR, "FPS Cap", "Handles the refresh rate of the game (does not affect gamelogic).",
{IT_STRING | IT_CVAR, "FPS Cap", "Handles the frame rate of the game (35 to match game logic)",
NULL, {.cvar = &cv_fpscap}, 0, 0},
{IT_STRING | IT_CVAR, "Enable Skyboxes", "Turning this off will improve performance at the detriment of visuals for many maps.",
NULL, {.cvar = &cv_skybox}, 0, 0},
{IT_STRING | IT_CVAR, "Draw Distance", "How far objects can be drawn. Lower values may improve performance at the cost of visibility.",
{IT_STRING | IT_CVAR, "Draw Distance", "How far objects can be drawn. A tradeoff between performance & visibility.",
NULL, {.cvar = &cv_drawdist}, 0, 0},
{IT_STRING | IT_CVAR, "Weather Draw Distance", "Affects how far weather visuals can be drawn. Lower values improve performance.",

View file

@ -57,6 +57,13 @@ void Music_Init(void)
tune.priority = 21;
}
{
Tune& tune = g_tunes.insert("finish_silence");
tune.song = "";
tune.priority = 30;
}
{
Tune& tune = g_tunes.insert("finish");

View file

@ -40,6 +40,7 @@ target_sources(SRB2SDL2 PRIVATE
shadow.cpp
ball-switch.cpp
charge.c
mega-barrier.cpp
)
add_subdirectory(versus)

View file

@ -5,11 +5,6 @@
#include "../k_kart.h"
#include "../k_powerup.h"
static INT16 guard_upscale (player_t *player)
{
return K_PowerUpRemaining(player, POWERUP_BARRIER) ? 40 : player->spheres;
}
void Obj_BlockRingThink (mobj_t *ring)
{
if (P_MobjWasRemoved(ring->target) || !ring->target->player)
@ -28,7 +23,7 @@ void Obj_BlockRingThink (mobj_t *ring)
ring->color = mo->color;
fixed_t baseScale = mo->scale / 2;
baseScale += (mo->scale / 30) * guard_upscale(player);
baseScale += (mo->scale / 30) * player->spheres;
P_SetScale(ring, baseScale);
// Twirl
@ -41,7 +36,7 @@ void Obj_BlockRingThink (mobj_t *ring)
else
ring->renderflags |= RF_DONTDRAW;
if (!K_PlayerGuard(player))
if (K_PowerUpRemaining(player, POWERUP_BARRIER) || !K_PlayerGuard(player))
ring->renderflags |= RF_DONTDRAW;
}
}
@ -61,7 +56,7 @@ void Obj_BlockBodyThink (mobj_t *body)
body->flags &= ~(MF_NOCLIPTHING);
fixed_t baseScale = mo->scale / 2;
baseScale += (mo->scale / 30) * guard_upscale(player);
baseScale += (mo->scale / 30) * player->spheres;
P_SetScale(body, baseScale);
P_MoveOrigin(body, mo->x, mo->y, mo->z + mo->height/2);
@ -76,7 +71,7 @@ void Obj_BlockBodyThink (mobj_t *body)
else
body->renderflags |= RF_DONTDRAW;
if (!K_PlayerGuard(player))
if (K_PowerUpRemaining(player, POWERUP_BARRIER) || !K_PlayerGuard(player))
body->renderflags |= RF_DONTDRAW;
}
}

View file

@ -51,7 +51,7 @@ Obj_SpawnBrolyKi
x->tics = (duration + BUFFER_TICS);
K_ReduceVFX(x, NULL);
K_ReduceVFXForEveryone(x);
S_StartSound(x, sfx_cdfm74);

View file

@ -85,19 +85,13 @@ void Obj_playerBungeeThink(player_t *p)
if ((p->mo->eflags & MFE_VERTICALFLIP && p->mo->z < bungee->z)
|| (!(p->mo->eflags & MFE_VERTICALFLIP) && p->mo->z > bungee->z ))
{
p->mo->flags &= ~MF_NOGRAVITY;
p->mo->flags &= ~MF_NOCLIPTHING;
p->pflags &= ~PF_NOFASTFALL;
p->bungee = BUNGEE_NONE;
P_InstaThrust(p->mo, bungee->angle, p->mo->momz/8);
p->mo->momz = (p->mo->momz*3)/4;
p->springstars = TICRATE; // these are used as a buffer not to latch to vines again.
p->springcolor = SKINCOLOR_EMERALD;
P_RemoveMobj(bungee);
P_SetTarget(&p->mo->tracer, NULL);
Obj_EndBungee(p);
return;
}
}
@ -117,3 +111,26 @@ void Obj_playerBungeeThink(player_t *p)
seg->fuse = 2;
}
}
void Obj_EndBungee(player_t *p)
{
if (p->bungee == BUNGEE_NONE)
{
return;
}
p->pflags &= ~PF_NOFASTFALL;
p->bungee = BUNGEE_NONE;
if (!P_MobjWasRemoved(p->mo))
{
p->mo->flags &= ~MF_NOGRAVITY;
p->mo->flags &= ~MF_NOCLIPTHING;
if (!P_MobjWasRemoved(p->mo->tracer))
{
P_RemoveMobj(p->mo->tracer);
}
P_SetTarget(&p->mo->tracer, NULL);
}
}

View file

@ -0,0 +1,160 @@
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2023 by James Robert Roman
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
#include <cstddef>
#include "../doomdef.h"
#include "../d_player.h"
#include "../g_game.h"
#include "../info.h"
#include "../k_kart.h"
#include "../k_objects.h"
#include "../k_powerup.h"
#include "../m_fixed.h"
#include "../p_local.h"
#include "../p_mobj.h"
#include "../r_defs.h"
#define barrier_player(o) ((o)->extravalue1)
namespace
{
struct Barrier;
// TODO: header
struct Mobj : mobj_t
{
struct PosArg
{
fixed_t x, y, z;
PosArg(fixed_t x_, fixed_t y_, fixed_t z_) : x(x_), y(y_), z(z_) {}
PosArg(const mobj_t* mobj) : x(mobj->x), y(mobj->y), z(mobj->z) {}
};
static bool valid(const Mobj* mobj) { return !P_MobjWasRemoved(mobj); }
PosArg center() const { return {x, y, z + (height / 2)}; }
template <typename T>
T* spawn_offset(mobjtype_t type) { return static_cast<T*>(P_SpawnMobjFromMobj(this, 0, 0, 0, type)); }
void state(statenum_t state) { P_SetMobjState(this, state); }
statenum_t statenum() const { return static_cast<statenum_t>(mobj_t::state - states); }
fixed_t scale() const { return mobj_t::scale; }
void scale(fixed_t n)
{
mobj_t::scale = n;
mobj_t::destscale = n;
}
void move_origin(const PosArg& p) { P_MoveOrigin(this, p.x, p.y, p.z); }
void remove() { P_RemoveMobj(this); }
};
struct Player : player_t
{
struct Powerups : powerupvars_t
{
Barrier* barrier() const { return reinterpret_cast<Barrier*>(powerupvars_t::barrier); }
void barrier(Barrier* n) { P_SetTarget(&this->powerupvars_t::barrier, reinterpret_cast<mobj_t*>(n)); }
};
static bool valid(std::size_t i) { return i < MAXPLAYERS && playeringame[i]; }
static Player* at(std::size_t i) { return static_cast<Player*>(&players[i]); }
std::size_t num() const { return this - Player::at(0); }
Mobj* mobj() const { return static_cast<Mobj*>(mo); }
Powerups& powerups() { return static_cast<Powerups&>(player_t::powerup); }
const Powerups& powerups() const { return static_cast<const Powerups&>(player_t::powerup); }
};
struct Barrier : Mobj
{
static constexpr angle_t kSpinSpeed = ANGLE_22h;
static constexpr angle_t kSpinGap = 20*ANG1;
static Barrier* spawn(Player* player, statenum_t state, int idx)
{
Barrier* child = player->mobj()->spawn_offset<Barrier>(MT_MEGABARRIER);
child->angle = player->mobj()->angle + (idx * kSpinGap);
child->player(player);
child->renderflags |= RF_DONTDRAW;
child->state(state);
return child;
}
static void spawn_chain(Player* player)
{
player->powerups().barrier(spawn(player, S_MEGABARRIER1, 0));
spawn(player, S_MEGABARRIER2, 1);
spawn(player, S_MEGABARRIER2, 2);
spawn(player, S_MEGABARRIER2, 3);
spawn(player, S_MEGABARRIER2, 4);
spawn(player, S_MEGABARRIER3, 5);
}
int playernum() const { return barrier_player(this); }
Player* player() const { return Player::at(playernum()); }
void player(player_t* n) { barrier_player(this) = n - players; }
bool valid() const { return Mobj::valid(this) && Player::valid(playernum()) && Mobj::valid(player()->mobj()); }
bool think()
{
if (!valid() || !K_PowerUpRemaining(player(), POWERUP_BARRIER))
{
remove();
return false;
}
Mobj* source = player()->mobj();
color = source->color;
scale(8 * source->scale() / 9);
move_origin(source->center());
angle += kSpinSpeed;
eflags = (eflags & ~MFE_VERTICALFLIP) | (source->eflags & MFE_VERTICALFLIP);
if (K_PlayerGuard(player()))
{
renderflags &= ~RF_DONTDRAW;
renderflags ^= RF_ADD | RF_TRANS90;
}
else
{
renderflags |= RF_DONTDRAW;
}
return true;
}
};
}; // namespace
void Obj_SpawnMegaBarrier(player_t* p)
{
Player* player = static_cast<Player*>(p);
if (!Mobj::valid(player->powerups().barrier()))
{
Barrier::spawn_chain(player);
}
}
boolean Obj_MegaBarrierThink(mobj_t* mobj)
{
return static_cast<Barrier*>(mobj)->think();
}

View file

@ -1,3 +1,4 @@
#include "../doomtype.h"
#include "../info.h"
#include "../g_game.h"
#include "../m_fixed.h"
@ -85,6 +86,15 @@ struct Aura : mobj_t
P_InstaScale(this, 11 * origin()->scale / 10);
translate();
if (K_AnyPowerUpRemaining(&players[seek()]) & ~POWERUP_BIT(POWERUP_BARRIER))
{
renderflags &= ~RF_DONTDRAW;
}
else
{
renderflags |= RF_DONTDRAW;
}
}
void translate()

View file

@ -112,7 +112,8 @@ static void SpawnEmeraldSpeedLines(mobj_t *mo)
fast->momz = 3*P_GetMobjZMovement(mo)/4;
K_MatchGenericExtraFlags(fast, mo);
K_ReduceVFX(fast, mo->player);
P_SetTarget(&fast->owner, mo);
fast->renderflags |= RF_REDUCEVFX;
fast->color = mo->color;
fast->colorized = true;

View file

@ -3828,7 +3828,8 @@ void A_AttractChase(mobj_t *actor)
P_SetTarget(&sparkle->target, actor->target);
sparkle->angle = (actor->target->angle + (offset>>1)) + (offset * actor->target->player->sparkleanim);
actor->target->player->sparkleanim = (actor->target->player->sparkleanim+1) % 20;
K_ReduceVFX(sparkle, actor->target->player);
P_SetTarget(&sparkle->owner, actor->target);
sparkle->renderflags |= RF_REDUCEVFX;
P_KillMobj(actor, actor->target, actor->target, DMG_NORMAL);
return;

View file

@ -1545,7 +1545,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
|| target->type == MT_DROPTARGET || target->type == MT_DROPTARGET_SHIELD
|| target->type == MT_EGGMANITEM || target->type == MT_EGGMANITEM_SHIELD
|| target->type == MT_BALLHOG || target->type == MT_SPB
|| target->type == MT_GACHABOM)) // kart dead items
|| target->type == MT_GACHABOM || target->type == MT_KART_LEFTOVER)) // kart dead items
target->flags |= MF_NOGRAVITY; // Don't drop Tails 03-08-2000
else
target->flags &= ~MF_NOGRAVITY; // lose it if you for whatever reason have it, I'm looking at you shields
@ -1876,8 +1876,6 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
if (target->player->pflags & PF_NOCONTEST)
P_SetTarget(&target->tracer, kart);
kart->fuse = 5*TICRATE;
}
if (source && !P_MobjWasRemoved(source))
@ -1889,18 +1887,22 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
}
else
{
flingAngle = target->angle + ANGLE_180;
flingAngle = target->angle;
if (P_RandomByte(PR_ITEM_RINGS) & 1)
{
flingAngle -= ANGLE_45;
flingAngle -= ANGLE_45/2;
}
else
{
flingAngle += ANGLE_45;
flingAngle += ANGLE_45/2;
}
}
// On -20 ring deaths, you're guaranteed to be hitting the ground from Tumble,
// so make sure that this draws at the correct angle.
target->rollangle = 0;
P_InstaThrust(target, flingAngle, 14 * target->scale);
P_SetObjectMomZ(target, 14*FRACUNIT, false);
@ -1923,6 +1925,16 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
}
break;
case MT_KART_LEFTOVER:
if (!P_MobjWasRemoved(inflictor))
{
K_KartSolidBounce(target, inflictor);
target->momz = 20 * inflictor->scale * P_MobjFlip(inflictor);
}
target->z += P_MobjFlip(target);
target->tics = 175;
return;
case MT_METALSONIC_RACE:
target->fuse = TICRATE*3;
target->momx = target->momy = target->momz = 0;
@ -3126,6 +3138,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
player->glanceDir = 0;
player->preventfailsafe = TICRATE*3;
player->pflags &= ~PF_GAINAX;
Obj_EndBungee(player);
if (player->spectator == false && !(player->charflags & SF_IRONMAN))
{

View file

@ -962,6 +962,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|| tm.thing->type == MT_SSMINE || tm.thing->type == MT_LANDMINE || tm.thing->type == MT_SINK
|| tm.thing->type == MT_GARDENTOP
|| tm.thing->type == MT_DROPTARGET
|| tm.thing->type == MT_KART_LEFTOVER
|| (tm.thing->type == MT_PLAYER && thing->target != tm.thing)))
{
// see if it went over / under
@ -979,6 +980,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|| thing->type == MT_SSMINE || thing->type == MT_LANDMINE || thing->type == MT_SINK
|| thing->type == MT_GARDENTOP
|| thing->type == MT_DROPTARGET
|| thing->type == MT_KART_LEFTOVER
|| (thing->type == MT_PLAYER && tm.thing->target != thing)))
{
// see if it went over / under
@ -1002,6 +1004,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|| tm.thing->type == MT_GARDENTOP
|| tm.thing->type == MT_MONITOR
|| tm.thing->type == MT_BATTLECAPSULE
|| tm.thing->type == MT_KART_LEFTOVER
|| (tm.thing->type == MT_PLAYER)))
{
// see if it went over / under
@ -1019,6 +1022,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|| thing->type == MT_GARDENTOP
|| thing->type == MT_MONITOR
|| thing->type == MT_BATTLECAPSULE
|| thing->type == MT_KART_LEFTOVER
|| (thing->type == MT_PLAYER)))
{
// see if it went over / under
@ -1572,7 +1576,14 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
if (tm.thing->z + tm.thing->height < thing->z)
return BMIT_CONTINUE; // underneath
K_KartBouncing(tm.thing, thing);
if (K_PlayerCanPunt(tm.thing->player))
{
P_DamageMobj(thing, tm.thing, tm.thing, 1, DMG_NORMAL);
}
else
{
K_KartBouncing(tm.thing, thing);
}
return BMIT_CONTINUE;
}
else if (thing->type == MT_MONITOR)
@ -3137,7 +3148,8 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff, Try
spark->fuse = 9;
spark->cusval = K_StairJankFlip(ANGLE_90);
P_SetTarget(&spark->target, thing);
K_ReduceVFX(spark, thing->player);
P_SetTarget(&spark->owner, thing);
spark->renderflags |= RF_REDUCEVFX;
}
thing->player->stairjank = 17;

View file

@ -2592,6 +2592,8 @@ boolean P_ZMovement(mobj_t *mo)
tireAngle += (aOffset * 2);
}
}
mom.z = 0;
}
else if (mo->type == MT_KART_TIRE)
{
@ -6807,6 +6809,14 @@ static void P_MobjSceneryThink(mobj_t *mobj)
mobj->angle += ANG2;
break;
}
case MT_MEGABARRIER:
{
if (!Obj_MegaBarrierThink(mobj))
{
return;
}
break;
}
case MT_VWREF:
case MT_VWREB:
{
@ -6953,6 +6963,7 @@ static boolean P_MobjDeadThink(mobj_t *mobj)
//case MT_DROPTARGET:
case MT_SPB:
case MT_GACHABOM:
case MT_KART_LEFTOVER:
if (P_IsObjectOnGround(mobj))
{
P_RemoveMobj(mobj);
@ -8025,7 +8036,8 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
}
}
K_ReduceVFX(mobj, mobj->target->player);
P_SetTarget(&mobj->owner, mobj->target);
mobj->renderflags |= RF_REDUCEVFX;
break;
}
case MT_BOOSTFLAME:
@ -8114,7 +8126,8 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
S_StartSound(mobj, sfx_cdfm17);
K_MatchGenericExtraFlags(mobj, mobj->target);
K_ReduceVFX(mobj, mobj->target->player);
P_SetTarget(&mobj->owner, mobj->target);
mobj->renderflags |= RF_REDUCEVFX;
if (leveltime & 1)
mobj->renderflags |= RF_DONTDRAW;
}
@ -8319,7 +8332,8 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
mobj->renderflags = (mobj->renderflags & ~RF_TRANSMASK)|(trans << RF_TRANSSHIFT);
}
K_ReduceVFX(mobj, mobj->target->player);
P_SetTarget(&mobj->owner, mobj->target);
mobj->renderflags |= RF_REDUCEVFX;
break;
case MT_MAGICIANBOX:
{
@ -8796,9 +8810,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
}
}
P_MoveOrigin(mobj, mobj->target->x, mobj->target->y, mobj->target->z + mobj->target->height/2);
P_MoveOrigin(mobj, mobj->target->x, mobj->target->y, mobj->target->z + (mobj->eflags & MFE_VERTICALFLIP ? 1 : 1) * mobj->target->height/2);
mobj->angle = K_MomentumAngle(mobj->target);
K_FlipFromObject(mobj, mobj->target);
if (underlayst != S_NULL)
{
mobj_t *underlay = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_FLAMESHIELDUNDERLAY);
@ -10258,7 +10274,6 @@ static boolean P_CanFlickerFuse(mobj_t *mobj)
case MT_FALLINGROCK:
case MT_FLOATINGITEM:
case MT_POGOSPRING:
case MT_KART_LEFTOVER:
case MT_EMERALD:
case MT_BLENDEYE_PUYO:
if (mobj->fuse <= TICRATE)
@ -10435,6 +10450,8 @@ void P_MobjThinker(mobj_t *mobj)
P_SetTarget(&mobj->itnext, NULL);
if (mobj->punt_ref && P_MobjWasRemoved(mobj->punt_ref))
P_SetTarget(&mobj->punt_ref, NULL);
if (mobj->owner && P_MobjWasRemoved(mobj->owner))
P_SetTarget(&mobj->owner, NULL);
if (mobj->flags & MF_NOTHINK)
return;
@ -11990,6 +12007,7 @@ void P_RemoveMobj(mobj_t *mobj)
P_SetTarget(&mobj->itnext, NULL);
P_SetTarget(&mobj->punt_ref, NULL);
P_SetTarget(&mobj->owner, NULL);
P_RemoveThingTID(mobj);
P_DeleteMobjStringArgs(mobj);
@ -12639,13 +12657,13 @@ void P_SpawnPlayer(INT32 playernum)
}
}
boolean director = p->spectator && pcount > 0;
if (G_IsPartyLocal(playernum))
{
// Spectating when there is literally any other
// player in the level enables director cam.
K_ToggleDirector(G_PartyPosition(playernum), director);
// Spectating always enables director cam. If there
// is no one to view, this will do nothing. If
// someone enters the game later, it will
// automatically switch to that player.
K_ToggleDirector(G_PartyPosition(playernum), p->spectator);
// Spectators can switch to freecam. This should be
// disabled when they enter the race, or when the level

View file

@ -445,6 +445,8 @@ struct mobj_t
// If punt_ref, set punt_ref->reappear, treat as if this->reappear
mobj_t *punt_ref;
mobj_t *owner;
// WARNING: New fields must be added separately to savegame and Lua.
};

View file

@ -82,6 +82,7 @@ typedef enum
FLICKYATTACKER = 0x0800,
FLICKYCONTROLLER = 0x1000,
TRICKINDICATOR = 0x2000,
BARRIER = 0x4000,
} player_saveflags;
static inline void P_ArchivePlayer(savebuffer_t *save)
@ -332,6 +333,9 @@ static void P_NetArchivePlayers(savebuffer_t *save)
if (players[i].powerup.flickyController)
flags |= FLICKYCONTROLLER;
if (players[i].powerup.barrier)
flags |= BARRIER;
WRITEUINT16(save->p, flags);
if (flags & SKYBOXVIEW)
@ -373,6 +377,9 @@ static void P_NetArchivePlayers(savebuffer_t *save)
if (flags & FLICKYCONTROLLER)
WRITEUINT32(save->p, players[i].powerup.flickyController->mobjnum);
if (flags & BARRIER)
WRITEUINT32(save->p, players[i].powerup.barrier->mobjnum);
WRITEUINT32(save->p, (UINT32)players[i].followitem);
WRITEUINT32(save->p, players[i].charflags);
@ -911,6 +918,9 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
if (flags & FLICKYCONTROLLER)
players[i].powerup.flickyController = (mobj_t *)(size_t)READUINT32(save->p);
if (flags & BARRIER)
players[i].powerup.barrier = (mobj_t *)(size_t)READUINT32(save->p);
players[i].followitem = (mobjtype_t)READUINT32(save->p);
//SetPlayerSkinByNum(i, players[i].skin);
@ -2698,6 +2708,7 @@ typedef enum
MD3_LIGHTLEVEL = 1,
MD3_REAPPEAR = 1<<1,
MD3_PUNT_REF = 1<<2,
MD3_OWNER = 1<<3,
} mobj_diff3_t;
typedef enum
@ -3022,6 +3033,8 @@ static void SaveMobjThinker(savebuffer_t *save, const thinker_t *th, const UINT8
diff3 |= MD3_REAPPEAR;
if (mobj->punt_ref)
diff3 |= MD3_PUNT_REF;
if (mobj->owner)
diff3 |= MD3_OWNER;
if (diff3 != 0)
diff2 |= MD2_MORE;
@ -3310,6 +3323,10 @@ static void SaveMobjThinker(savebuffer_t *save, const thinker_t *th, const UINT8
{
WRITEUINT32(save->p, mobj->punt_ref->mobjnum);
}
if (diff3 & MD3_OWNER)
{
WRITEUINT32(save->p, mobj->owner->mobjnum);
}
WRITEUINT32(save->p, mobj->mobjnum);
}
@ -4564,6 +4581,10 @@ static thinker_t* LoadMobjThinker(savebuffer_t *save, actionf_p1 thinker)
{
mobj->punt_ref = (mobj_t *)(size_t)READUINT32(save->p);
}
if (diff3 & MD3_OWNER)
{
mobj->owner = (mobj_t *)(size_t)READUINT32(save->p);
}
// set sprev, snext, bprev, bnext, subsector
P_SetThingPosition(mobj);
@ -5611,6 +5632,13 @@ static void P_RelinkPointers(void)
if (!P_SetTarget(&mobj->punt_ref, P_FindNewPosition(temp)))
CONS_Debug(DBG_GAMELOGIC, "punt_ref not found on %d\n", mobj->type);
}
if (mobj->owner)
{
temp = (UINT32)(size_t)mobj->owner;
mobj->owner = NULL;
if (!P_SetTarget(&mobj->owner, P_FindNewPosition(temp)))
CONS_Debug(DBG_GAMELOGIC, "owner not found on %d\n", mobj->type);
}
}
for (i = 0; i < MAXPLAYERS; i++)
@ -5743,6 +5771,13 @@ static void P_RelinkPointers(void)
if (!P_SetTarget(&players[i].powerup.flickyController, P_FindNewPosition(temp)))
CONS_Debug(DBG_GAMELOGIC, "powerup.flickyController not found on player %d\n", i);
}
if (players[i].powerup.barrier)
{
temp = (UINT32)(size_t)players[i].powerup.barrier;
players[i].powerup.barrier = NULL;
if (!P_SetTarget(&players[i].powerup.barrier, P_FindNewPosition(temp)))
CONS_Debug(DBG_GAMELOGIC, "powerup.barrier not found on player %d\n", i);
}
}
}

View file

@ -46,6 +46,8 @@
#include "music.h"
#include "k_dialogue.h"
#include "lua_profile.h"
#ifdef PARANOIA
#include "deh_tables.h" // MOBJTYPE_LIST
#endif
@ -844,6 +846,8 @@ void P_Ticker(boolean run)
G_ReadDemoTiccmd(&players[i].cmd, i);
}
LUA_ResetTicTimers();
ps_lua_mobjhooks = 0;
ps_checkposition_calls = 0;

View file

@ -66,6 +66,7 @@
#include "k_profiles.h"
#include "music.h"
#include "k_tally.h"
#include "k_objects.h"
#ifdef HWRENDER
#include "hardware/hw_light.h"
@ -481,6 +482,7 @@ void P_ResetPlayer(player_t *player)
player->trickpanel = TRICKSTATE_NONE;
player->glanceDir = 0;
player->fastfall = 0;
Obj_EndBungee(player);
if (player->mo != NULL && P_MobjWasRemoved(player->mo) == false)
{
@ -1166,7 +1168,8 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj)
ghost->old_roll = mobj->old_roll2;
ghost->old_scale = mobj->old_scale2;
K_ReduceVFX(ghost, mobj->player);
P_SetTarget(&ghost->owner, mobj);
ghost->renderflags |= RF_REDUCEVFX;
ghost->reappear = mobj->reappear;
P_SetTarget(&ghost->punt_ref, mobj->punt_ref);
@ -1284,7 +1287,7 @@ void P_DoPlayerExit(player_t *player, pflags_t flags)
if (P_IsLocalPlayer(player) && !specialout && musiccountdown == 0)
{
Music_StopAll();
Music_Play("finish_silence");
musiccountdown = MUSIC_COUNTDOWN_MAX;
}
@ -3787,7 +3790,7 @@ void P_DoTimeOver(player_t *player)
if (P_IsLocalPlayer(player) && musiccountdown == 0)
{
Music_StopAll();
Music_Play("finish_silence");
musiccountdown = MUSIC_COUNTDOWN_MAX;
}
@ -4069,6 +4072,7 @@ void P_PlayerThink(player_t *player)
PlayerPointerErase(player->hoverhyudoro);
PlayerPointerErase(player->flickyAttacker);
PlayerPointerErase(player->powerup.flickyController);
PlayerPointerErase(player->powerup.barrier);
#undef PlayerPointerErase
}

View file

@ -973,6 +973,7 @@ typedef enum
RF_DROPSHADOW = (RF_SHADOWDRAW | RF_SHADOWEFFECTS | RF_FULLDARK),
RF_ABSOLUTELIGHTLEVEL = 0x00010000, // mobj_t.lightlevel is absolute instead of relative
RF_REDUCEVFX = 0x00020000, // only mobj_t.owner can see this object
RF_DONTDRAW = 0x00F00000, // --Don't generate a vissprite
RF_DONTDRAWP1 = 0x00100000, // No P1

View file

@ -3775,6 +3775,9 @@ boolean R_ThingVisible (mobj_t *thing)
|| (viewssnum == 3 && (thing->renderflags & RF_DONTDRAWP4)))
return false;
if ((thing->renderflags & RF_REDUCEVFX) && cv_reducevfx.value && thing->owner != players[displayplayers[viewssnum]].mo)
return false;
return true;
}

View file

@ -1810,3 +1810,38 @@ UINT32 I_GetRefreshRate(void)
// trouble querying mode over and over again.
return refresh_rate;
}
namespace srb2::cvarhandler
{
void on_set_vid_wait();
}
void srb2::cvarhandler::on_set_vid_wait()
{
int interval = 0;
if (cv_vidwait.value > 0)
{
interval = 1;
}
switch (rendermode)
{
case render_soft:
if (sdlglcontext == nullptr || SDL_GL_GetCurrentContext() != sdlglcontext)
{
return;
}
SDL_GL_SetSwapInterval(interval);
break;
#ifdef HWRENDER
case render_opengl:
if (g_legacy_gl_context == nullptr || SDL_GL_GetCurrentContext() != g_legacy_gl_context)
{
return;
}
SDL_GL_SetSwapInterval(interval);
#endif
default:
break;
}
}

View file

@ -452,10 +452,10 @@ void ST_drawDebugInfo(void)
{
INT32 height = 192;
const UINT8 screen = cv_devmode_screen.value - 1;
const UINT8 screen = min(r_splitscreen, cv_devmode_screen.value - 1);
// devmode_screen = 1..4
stplyr = &players[displayplayers[min(r_splitscreen, screen)]];
stplyr = &players[displayplayers[screen]];
if (!stplyr->mo)
return;
@ -472,11 +472,23 @@ void ST_drawDebugInfo(void)
if (cht_debug & DBG_BASIC)
{
const fixed_t d = AngleFixed(stplyr->mo->angle);
V_DrawRightAlignedString(320, height - 24, V_MONOSPACE, va("X: %6d", stplyr->mo->x>>FRACBITS));
V_DrawRightAlignedString(320, height - 16, V_MONOSPACE, va("Y: %6d", stplyr->mo->y>>FRACBITS));
V_DrawRightAlignedString(320, height - 8, V_MONOSPACE, va("Z: %6d", stplyr->mo->z>>FRACBITS));
V_DrawRightAlignedString(320, height, V_MONOSPACE, va("A: %6d", FixedInt(d)));
camera_t *cam = &camera[screen];
if (stplyr->spectator || cam->freecam)
{
const fixed_t d = AngleFixed(cam->angle);
V_DrawRightAlignedString(320, height - 24, V_MONOSPACE, va("X: %6d", cam->x>>FRACBITS));
V_DrawRightAlignedString(320, height - 16, V_MONOSPACE, va("Y: %6d", cam->y>>FRACBITS));
V_DrawRightAlignedString(320, height - 8, V_MONOSPACE, va("Z: %6d", cam->z>>FRACBITS));
V_DrawRightAlignedString(320, height, V_MONOSPACE, va("A: %6d", FixedInt(d)));
}
else
{
const fixed_t d = AngleFixed(stplyr->mo->angle);
V_DrawRightAlignedString(320, height - 24, V_MONOSPACE, va("X: %6d", stplyr->mo->x>>FRACBITS));
V_DrawRightAlignedString(320, height - 16, V_MONOSPACE, va("Y: %6d", stplyr->mo->y>>FRACBITS));
V_DrawRightAlignedString(320, height - 8, V_MONOSPACE, va("Z: %6d", stplyr->mo->z>>FRACBITS));
V_DrawRightAlignedString(320, height, V_MONOSPACE, va("A: %6d", FixedInt(d)));
}
height -= 40;
}

View file

@ -247,6 +247,9 @@ TYPEDEF (mapUserProperties_t);
// lua_hudlib_drawlist.h
typedef struct huddrawlist_s *huddrawlist_h;
// lua_profile.h
TYPEDEF (lua_timer_t);
// m_aatree.h
TYPEDEF (aatree_t);