Merge remote-tracking branch 'origin/master' into postrace-director

This commit is contained in:
AJ Martinez 2025-06-01 15:21:01 -04:00
commit 9d3c0f0c68
30 changed files with 418 additions and 171 deletions

View file

@ -3589,13 +3589,15 @@ bool CallFunc_SetThingProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, A
INT32 value = 0;
tag = argV[0];
mobj = P_FindMobjFromTID(tag, mobj, info->mo);
mobj_t *next = P_FindMobjFromTID(tag, mobj, info->mo);
property = argV[1];
value = argV[2];
while (mobj != NULL)
while ((mobj = next) != NULL)
{
// First in case of deletion. (Can't check for value == S_NULL because of A_ calls, etc)
next = P_FindMobjFromTID(tag, mobj, info->mo);
#define PROP_READONLY(x, y) \
case x: \
@ -3830,8 +3832,6 @@ bool CallFunc_SetThingProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, A
}
}
mobj = P_FindMobjFromTID(tag, mobj, info->mo);
#undef PROP_FLAGS
#undef PROP_SCALE
#undef PROP_MOBJ

View file

@ -149,6 +149,7 @@ public:
Vector& operator=(const Vector& rhs)
{
clear();
for (auto itr = rhs.begin(); itr != rhs.end(); itr++)
{
push_back(*itr);

View file

@ -281,7 +281,7 @@ shouldsign_t ShouldSignChallenge(uint8_t *message)
if ((max(now, then) - min(now, then)) > 60*15)
return SIGN_BADTIME;
// ____ _____ ___ ____ _
// ____ _____ ___ ____ _
// / ___|_ _/ _ \| _ \| |
// \___ \ | || | | | |_) | |
// ___) || || |_| | __/|_|
@ -2436,6 +2436,11 @@ static void CL_ConnectToServer(void)
joinedIP[0] = '\0'; // And empty this for good measure regardless of whether or not we actually used it.
// Enable sound input/microphone in netgames, activating the microphone device.
if (netgame)
{
S_SoundInputSetEnabled(true);
}
}
static void Command_connect(void)
@ -2502,6 +2507,8 @@ static void Command_connect(void)
{
CONS_Alert(CONS_ERROR, M_GetText("There is no server identification with this network driver\n"));
D_CloseConnection();
S_SoundInputSetEnabled(false);
return;
}
}
@ -3659,6 +3666,7 @@ void D_QuitNetGame(void)
K_ClearClientPowerLevels();
G_ObliterateParties();
K_ResetMidVote();
S_SoundInputSetEnabled(false);
DEBFILE("===========================================================================\n"
" Log finish\n"
@ -7376,9 +7384,6 @@ void NetVoiceUpdate(void)
return;
}
// This necessarily runs every frame, not every tic
S_SoundInputSetEnabled(true);
UINT32 bytes_dequed = 0;
do
{

View file

@ -297,6 +297,7 @@ actionpointer_t actionpointers[] =
{{A_MakeSSCandle}, "A_MAKESSCANDLE"},
{{A_HologramRandomTranslucency}, "A_HOLOGRAMRANDOMTRANSLUCENCY"},
{{A_SSChainShatter}, "A_SSCHAINSHATTER"},
{{A_GenericBumper}, "A_GENERICBUMPER"},
{{NULL}, "NONE"},

View file

@ -2368,6 +2368,8 @@ void G_BeginRecording(void)
WRITEUINT8(demobuf.p, player->skin);
WRITEUINT8(demobuf.p, player->lastfakeskin);
WRITEUINT8(demobuf.p, player->team);
// Color
demobuf.p += copy_fixed_buf(demobuf.p, skincolors[player->skincolor].name, g_buffer_sizes.color_name);
@ -3500,6 +3502,8 @@ void G_DoPlayDemoEx(const char *defdemoname, lumpnum_t deflumpnum)
demo.currentskinid[p] = 0;
lastfakeskin[p] = READUINT8(demobuf.p);
players[p].team = READUINT8(demobuf.p);
// Color
demobuf.p += copy_fixed_buf(color, demobuf.p, g_buffer_sizes.color_name);
for (i = 0; i < numskincolors; i++)
@ -3783,6 +3787,8 @@ void G_AddGhost(savebuffer_t *buffer, const char *defdemoname)
ghskin = &skins[skinlist[i].mapping];
p++; // lastfakeskin
p++; // team
// Color
p += copy_fixed_buf(color, p, ghostsizes.color_name);

View file

@ -1556,7 +1556,7 @@ boolean G_CouldView(INT32 playernum)
return false;
// SRB2Kart: we have no team-based modes, YET...
if (G_GametypeHasTeams())
if (G_GametypeHasTeams() && !demo.playback)
{
if (players[consoleplayer].spectator == false && player->team != players[consoleplayer].team)
return false;
@ -2352,8 +2352,6 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
bot = players[player].bot;
botdifficulty = players[player].botvars.difficulty;
cangrabitems = players[player].cangrabitems;
botdiffincrease = players[player].botvars.diffincrease;
botrival = players[player].botvars.rival;
@ -2439,13 +2437,6 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
tallyactive = false;
cangrabitems = 0;
if (gametyperules & GTR_SPHERES
|| gametyperules & GTR_CATCHER
|| G_TimeAttackStart()
|| gametype == GT_TUTORIAL
|| !M_NotFreePlay()
|| K_GetNumWaypoints() == 0)
cangrabitems = EARLY_ITEM_FLICKER;
}
else
{
@ -2501,6 +2492,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
{
tally = players[player].tally;
}
cangrabitems = players[player].cangrabitems;
}
spectatorReentry = (betweenmaps ? 0 : players[player].spectatorReentry);
@ -5426,6 +5419,8 @@ void G_InitNew(UINT8 pencoremode, INT32 map, boolean resetplayer, boolean skippr
players[i].xtralife = 0;
players[i].totalring = 0;
players[i].score = 0;
if (roundqueue.position == 0) // Don't unassign teams in tournament play
players[i].team = TEAM_UNASSIGNED;
}
if (resetplayer || !(gametyperules & GTR_CHECKPOINTS && map == gamemap))

View file

@ -3640,7 +3640,7 @@ state_t states[NUMSTATES] =
{SPR_S_SP, FF_ANIMATE|FF_SEMIBRIGHT, -1, {NULL}, 3, 2, S_NULL}, // S_SLSTMACE
// MT_SEALEDSTAR_BUMPER
{SPR_SBMP, 0|FF_FULLBRIGHT, -1, {NULL}, 2, 8, S_SEALEDSTAR_BUMPER}, // S_SEALEDSTAR_BUMPER
{SPR_SBMP, 0|FF_FULLBRIGHT, -1, {A_GenericBumper}, 0, 56, S_SEALEDSTAR_BUMPER}, // S_SEALEDSTAR_BUMPER
{SPR_SBMP, 1|FF_ANIMATE|FF_FULLBRIGHT, 8, {NULL}, 1, 2, S_SEALEDSTAR_BUMPER}, // S_SEALEDSTAR_BUMPERHIT
// MT_SSCHAIN_SPAWNER
@ -22233,7 +22233,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // mass
0, // damage
sfx_None, // activesound
MF_SPECIAL|MF_NOGRAVITY, // flags
MF_NOGRAVITY|MF_SOLID, // flags
S_NULL // raisestate
},
{ // MT_SSCHAIN_SPAWNER

View file

@ -289,6 +289,7 @@ enum actionnum
A_MAKESSCANDLE,
A_HOLOGRAMRANDOMTRANSLUCENCY,
A_SSCHAINSHATTER,
A_GENERICBUMPER,
NUMACTIONS
};
@ -557,6 +558,7 @@ void A_BlendEyePuyoHack();
void A_MakeSSCandle();
void A_HologramRandomTranslucency();
void A_SSChainShatter();
void A_GenericBumper();
extern boolean actionsoverridden[NUMACTIONS];

View file

@ -75,7 +75,7 @@ boolean K_BananaBallhogCollide(mobj_t *t1, mobj_t *t2)
if (t1->type == MT_BALLHOGBOOM && t2->type == MT_BALLHOGBOOM)
return true; // Ballhogs don't collide with eachother
if (K_TryPickMeUp(t1, t2))
if (K_TryPickMeUp(t1, t2, false))
return true;
if (t2->player)
@ -178,7 +178,7 @@ boolean K_EggItemCollide(mobj_t *t1, mobj_t *t2)
if (t1->health <= 0 || t2->health <= 0)
return true;
if (K_TryPickMeUp(t1, t2))
if (K_TryPickMeUp(t1, t2, false))
return true;
if (!P_CanPickupItem(t2->player, PICKUP_EGGBOX))
@ -434,7 +434,7 @@ boolean K_LandMineCollide(mobj_t *t1, mobj_t *t2)
if (t1->health <= 0 || t2->health <= 0)
return true;
if (K_TryPickMeUp(t1, t2))
if (K_TryPickMeUp(t1, t2, false))
return true;
if (t2->player)
@ -544,7 +544,7 @@ boolean K_DropTargetCollide(mobj_t *t1, mobj_t *t2)
if (t2->player && (t2->player->hyudorotimer || t2->player->justbumped))
return true;
if (K_TryPickMeUp(t1, t2))
if (K_TryPickMeUp(t1, t2, false))
return true;
if (draggeddroptarget && P_MobjWasRemoved(draggeddroptarget))
@ -777,6 +777,12 @@ static inline BlockItReturn_t PIT_LightningShieldAttack(mobj_t *thing)
return BMIT_CONTINUE;
}
// see if it went over / under
if (lightningSource->z - lightningDist > thing->z + thing->height)
return BMIT_CONTINUE; // overhead
if (lightningSource->z + lightningSource->height + lightningDist < thing->z)
return BMIT_CONTINUE; // underneath
#if 0
if (P_CheckSight(lightningSource, thing) == false)
{
@ -1036,7 +1042,14 @@ boolean K_InstaWhipCollide(mobj_t *shield, mobj_t *victim)
}
else if (victim->type == MT_DROPTARGET || victim->type == MT_DROPTARGET_SHIELD)
{
K_DropTargetCollide(victim, shield);
if (K_TryPickMeUp(attacker, victim, true))
{
shield->hitlag = attacker->hitlag; // players hitlag is handled in K_TryPickMeUp, and we need to set for the shield too
}
else
{
K_DropTargetCollide(victim, shield);
}
return true;
}
else
@ -1053,8 +1066,13 @@ boolean K_InstaWhipCollide(mobj_t *shield, mobj_t *victim)
shield->extravalue1 = 1;
}
if (P_DamageMobj(victim, shield, attacker, 1, DMG_NORMAL))
if (K_TryPickMeUp(attacker, victim, true))
{
shield->hitlag = attacker->hitlag; // players hitlag is handled in K_TryPickMeUp, and we need to set for the shield too
}
else
{
P_DamageMobj(victim, shield, attacker, 1, DMG_NORMAL);
K_AddHitLag(attacker, attackerHitlag, false);
shield->hitlag = attacker->hitlag;
}
@ -1068,7 +1086,7 @@ boolean K_KitchenSinkCollide(mobj_t *t1, mobj_t *t2)
if (((t1->target == t2) || (!(t2->flags & (MF_ENEMY|MF_BOSS)) && (t1->target == t2->target))) && (t1->threshold > 0 || (t2->type != MT_PLAYER && t2->threshold > 0)))
return true;
if (K_TryPickMeUp(t1, t2))
if (K_TryPickMeUp(t1, t2, false))
return true;
if (t2->player)

View file

@ -240,7 +240,7 @@ static patch_t *kp_duel_you;
static patch_t *kp_duel_sticker;
static patch_t *kp_duel_under;
static patch_t *kp_duel_over;
static patch_t *kp_duel_margin[6];
static patch_t *kp_duel_margin[24];
patch_t *kp_autoroulette;
patch_t *kp_autoring;
@ -1074,9 +1074,13 @@ void K_LoadKartHUDGraphics(void)
HU_UpdatePatch(&kp_duel_under, "DUEL_B");
HU_UpdatePatch(&kp_duel_over, "DUEL_B2");
HU_UpdatePatch(&kp_duel_you, "DUEL_YOU");
for (i = 0; i < 6; i++)
sprintf(buffer, "DUELMBxx");
for (i = 0; i < MARGINLEVELS; i++)
{
HU_UpdatePatch(&kp_duel_margin[i], "DUELMB0%d", i);
buffer[6] = '0'+(i/10);
buffer[7] = '0'+(i%10);
HU_UpdatePatch(&kp_duel_margin[i], "%s", buffer);
}
}
@ -3250,6 +3254,8 @@ INT32 K_GetTransFlagFromFixed(fixed_t value)
}
static tic_t duel_lastleveltime = 0;
static INT32 duel_marginanim = 0;
static INT32 duel_lastmargin = 0;
static INT32 youheight = 0;
static void K_drawKartDuelScores(void)
@ -3289,8 +3295,6 @@ static void K_drawKartDuelScores(void)
INT32 youfill = skincolors[stplyr->skincolor].ramp[ri];
INT32 foefill = skincolors[foe->skincolor].ramp[ri];
INT32 margin = std::min(overtimecheckpoints, (UINT8)5); // Absolutely what the fuck kind of cast.
V_DrawScaledPatch(basex, basey, flags, kp_duel_sticker);
INT32 scoredelta = stplyr->duelscore - foe->duelscore;
@ -3322,7 +3326,6 @@ static void K_drawKartDuelScores(void)
else if (targetyouheight < youheight)
youheight -= slide;
}
duel_lastleveltime = leveltime;
INT32 foeheight = 2*barheight-youheight; // barheight is a single tied bar, so total height of the full gauge is 2x barheight
@ -3397,7 +3400,138 @@ static void K_drawKartDuelScores(void)
V_DrawMappedPatch(drawx+xoff, drawy+yoff, flags|flipflag, faceprefix[workingskin][FACE_RANK], colormap);
}
V_DrawScaledPatch(basex, basey, flags, kp_duel_margin[margin]);
// Dogshit. Should have just figured out how to do log base 5 in C++.
// However, I think this works anyway.
// I did my best to comment this but the algorithm is honestly just bad and hard to
// reason about. Please don't try to maintain this, just yell at me if it needs any
// adjustments. -Tyron 2025-05-29
// DESIGN INTENT: Create realistic-looking Puyo garbage stacks, while using the
// leading garbage symbol as an indicator of the current Margin Boost value.
INT32 rawmargin = overtimecheckpoints; // The actual Margin Boost value.
INT32 boostspersymbol = 3; // How many boosts should it take to see a new symbol?
// rawmargin = (leveltime/10)%(3*boostspersymbol);
if (duel_lastleveltime != leveltime) // Trigger the "slide" animation when rawmargin changes.
{
duel_marginanim = std::min(duel_marginanim + 1, 100); // not magic just arbitrary
if (duel_lastmargin != rawmargin)
{
duel_marginanim = 0;
duel_lastmargin = rawmargin;
}
}
duel_lastleveltime = leveltime;
// CONS_Printf("=== RAWMARGIN %d\n", rawmargin);
if (rawmargin == 0)
return;
rawmargin--; // Start at 0, idiot
// We're invoking the RNG to get a slightly chaotic symbol distribution,
// but we're a HUD hook, so we need to keep the results of the call consistent.
P_SetRandSeed(PR_NUISANCE, 69 + rawmargin);
INT32 highsymbol = rawmargin/boostspersymbol + 1; // Highest symbol that should appear.
INT32 symbolsperupgrade = 5; // What is each symbol worth relative to each other? Like, 5 Stars = 1 Moon, etc.
// Okay, so we would LOVE to do this in a way that isn't a big clusterfuck, like just
// doing rawmargin^3 and then subtracting powers of 5 out of that. Unfortunately, UINT64
// is too small for the values that feel intuitively right here, so we have to do some of
// the math on a limited set of symbols, then shift up. This is the concept of "symbol
// headroom" that's in use here.
//
// (Note that Puyo~n uses a super inconsistent symbol table, probably to avoid this problem,
// but we're assholes and want things to feel logically consistent I guess?
// I dunno. I sort of feel like I should have just directly used the Puyo~n garbage table and
// avoided most of this, LOL)
INT32 symbolheadroom = 5; // Maximum # symbols we can "step down".
INT32 frac = rawmargin % boostspersymbol; // Used in intermediate calculations.
INT32 minsymbol = std::max(1, highsymbol - symbolheadroom); // The lowest symbol that should appear.
INT32 symbolheadroominuse = highsymbol - minsymbol; // The # of symbols we are stepping down.
INT32 minscore = std::pow(symbolsperupgrade, symbolheadroominuse+1);
INT32 maxscore = std::pow(symbolsperupgrade, symbolheadroominuse+2) - 1;
// CONS_Printf("min %d max %d\n", minscore, maxscore);
// We show the player successive combos with the same leading symbol, but we
// waht them to feel intuitively like they're increasing each time.
// Maxscore and minscore have been mapped to the correct power-of-N, so any
// point we pick between them will lead with the correct symbol once we adjust
// for symbol headroom. Pick a point that's appropriate for how "far" into the
// current symbol we are.
fixed_t lobound = FRACUNIT * frac / boostspersymbol;
fixed_t hibound = FRACUNIT * (frac+1) / boostspersymbol;
fixed_t roll = P_RandomRange(PR_NUISANCE, lobound, hibound);
INT32 margin = Easing_Linear(roll, minscore, maxscore); // The score we're trying to draw a garbage stack for.
INT32 margindigits[5];
memset(margindigits, -1, sizeof(margindigits));
INT32 nummargindigits = 0;
// CONS_Printf("margin %d min %d max %d roll %d shiu %d ms %d\n", margin, minscore, maxscore, roll, symbolheadroominuse, minsymbol);
if (rawmargin/boostspersymbol >= (MARGINLEVELS-1))
{
// Capped out. Show 5 Chaos.
nummargindigits = 5;
for(UINT8 i = 0; i < nummargindigits; i++)
{
margindigits[i] = MARGINLEVELS-1;
}
}
else
{
// Subtract powers of N from our chosen score to create a decent-enough-looking
// garbage stack, then queue up the right patches to be drawn, shifting all the math
// up by "minsymbol"—remember, once maxsymbol goes above symbolheadroom, we are doing
// a low-precision version of the math that ignores low enough symbols.
while (margin > 0)
{
INT32 significant_margin = 0;
for (UINT8 i = symbolheadroominuse+1; i >= 0; i--)
{
INT32 test = std::pow(symbolsperupgrade, i);
// CONS_Printf("testing %d (%d)\n", i, test);
if (margin >= test)
{
significant_margin = i;
break;
}
}
INT32 index = significant_margin;
margindigits[nummargindigits] = index + minsymbol - 1;
// CONS_Printf("digit %d %d\n", nummargindigits, margindigits[nummargindigits]);
nummargindigits++;
// CONS_Printf("margin was %d ", margin);
margin -= std::pow(symbolsperupgrade, index);
// CONS_Printf("is %d\n", margin);
if (nummargindigits >= 3 + frac)
break;
}
}
INT32 marginspacing = std::min(6, duel_marginanim);
INT32 marginx = ((nummargindigits-1) * marginspacing)/2;
for (INT32 i = nummargindigits - 1; i >= 0; i--)
{
// CONS_Printf("draw %d - %d\n", i, margindigits[i]);
V_DrawScaledPatch(basex + marginx, basey, flags, kp_duel_margin[margindigits[i]]);
marginx -= marginspacing;
}
}
static INT32 easedallyscore = 0;
@ -3480,6 +3614,9 @@ static void K_drawKartTeamScores(void)
UINT16 enemyscore = g_teamscores[enemies];
UINT16 totalscore = allyscore + enemyscore;
if (totalscore == 0)
return;
using srb2::Draw;
srb2::Draw::Font scorefont = Draw::Font::kTimer;
@ -3535,7 +3672,7 @@ static void K_drawKartTeamScores(void)
{
INT32 delta = abs(easedallyscore - allyscore); // how wrong is display score?
if (scorechangecooldown == 0)
if (scorechangecooldown == 0 && delta)
{
if (allyscore > easedallyscore)
{
@ -3702,6 +3839,11 @@ static void K_drawKartTeamScores(void)
*/
}
static boolean K_DrawingLaps()
{
return (numlaps != 1 && !K_InRaceDuel() && (UINT16)stplyr->exp != UINT16_MAX);
}
static boolean K_drawKartLaps(void)
{
INT32 splitflags = V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_SPLITSCREEN;
@ -4141,7 +4283,16 @@ static void K_drawKartAccessibilityIcons(boolean gametypeinfoshown, INT32 fx)
}
else
{
fx = LAPS_X+44;
fx = LAPS_X + 33;
if ((gametyperules & (GTR_BUMPERS|GTR_CIRCUIT)) == GTR_BUMPERS)
fx -= 14;
if (K_DrawingLaps())
{
fx += 30;
}
fy = LAPS_Y;
if (R_GetViewNumber() & 1) // If we are not P1 or P3...
{
@ -7113,35 +7264,39 @@ static void K_DrawMessageFeed(void)
text.font(Draw::Font::kMenu);
UINT8 x = BASEVIDWIDTH/2;
UINT8 y = 10;
UINT32 vw = vid.width / vid.dupx;
UINT32 vh = vid.height / vid.dupy;
UINT32 x = vw / 2;
UINT32 y = 10;
SINT8 shift = 0;
if (r_splitscreen >= 2)
{
text.font(Draw::Font::kThin);
shift = -2;
x = BASEVIDWIDTH/4;
x = vw/4;
y = 5;
if (i % 2)
x += BASEVIDWIDTH/2;
x += vw / 2;
if (i >= 2)
y += BASEVIDHEIGHT / 2;
y += vh / 2;
}
else if (r_splitscreen >= 1)
{
y = 5;
if (i >= 1)
y += BASEVIDHEIGHT / 2;
y += vh / 2;
}
UINT16 sw = text.width();
K_DrawSticker(x - sw/2, y, sw, 0, true);
Draw(x, y+shift).align(Draw::Align::kCenter).text(text);
K_DrawSticker(x - sw/2, y, sw, V_SNAPTOTOP|V_SNAPTOLEFT, true);
Draw(x, y+shift).align(Draw::Align::kCenter).flags(V_SNAPTOTOP|V_SNAPTOLEFT).text(text);
}
}

View file

@ -25,6 +25,8 @@ extern "C" {
#define POS_DELAY_TIME 10
#define MARGINLEVELS 24
extern INT32 MINI_X, MINI_Y;
struct trackingResult_t

View file

@ -143,6 +143,8 @@ struct TargetTracking
return false;
default:
if (K_IsPickMeUpItem(mobj->type))
return false;
return true;
}
}
@ -277,28 +279,17 @@ private:
{{6, 2, {kp_spraycantarget_far[1]}, V_ADD}}, // 4P
}},
};
case MT_JAWZ:
case MT_JAWZ_SHIELD:
case MT_ORBINAUT:
case MT_ORBINAUT_SHIELD:
case MT_DROPTARGET:
case MT_DROPTARGET_SHIELD:
case MT_LANDMINE:
case MT_BANANA:
case MT_BANANA_SHIELD:
case MT_GACHABOM:
case MT_EGGMANITEM:
case MT_EGGMANITEM_SHIELD:
case MT_BUBBLESHIELDTRAP:
return {
{ // Near
{2, TICRATE/2, {kp_pickmeup}, 0}, // 1P
{{2, TICRATE/2, {kp_pickmeup}, 0}}, // 4P
},
};
default:
if (K_IsPickMeUpItem(mobj->type))
{
return {
{ // Near
{2, TICRATE/2, {kp_pickmeup}, 0}, // 1P
{{2, TICRATE/2, {kp_pickmeup}, 0}}, // 4P
},
};
}
return {
{ // Near
{8, 2, {kp_capsuletarget_near[0]}}, // 1P
@ -902,32 +893,17 @@ void K_drawTargetHUD(const vector3_t* origin, player_t* player)
if (tracking)
{
fixed_t itemOffset = 36*mobj->scale;
switch (mobj->type)
if (K_IsPickMeUpItem(mobj->type))
{
case MT_JAWZ:
case MT_JAWZ_SHIELD:
case MT_ORBINAUT:
case MT_ORBINAUT_SHIELD:
case MT_DROPTARGET:
case MT_DROPTARGET_SHIELD:
case MT_LANDMINE:
case MT_BANANA:
case MT_BANANA_SHIELD:
case MT_GACHABOM:
case MT_BUBBLESHIELDTRAP:
case MT_EGGMANITEM:
case MT_EGGMANITEM_SHIELD:
if (stplyr->mo->eflags & MFE_VERTICALFLIP)
{
pos.z -= itemOffset;
}
else
{
pos.z += itemOffset;
}
break;
default:
break;
if (stplyr->mo->eflags & MFE_VERTICALFLIP)
{
pos.z -= itemOffset;
}
else
{
pos.z += itemOffset;
}
}
K_ObjectTracking(&tr.result, &pos, false);

View file

@ -497,7 +497,7 @@ fixed_t K_GetKartGameSpeedScalar(SINT8 value)
value = 3;
fixed_t base = ((13 + (3*value)) << FRACBITS) / 16;
fixed_t duel = overtimecheckpoints*(1<<FRACBITS)/16;
fixed_t duel = overtimecheckpoints*(1<<FRACBITS)/32;
return base + duel;
}
@ -9781,6 +9781,21 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
player->invincibilitytimer--;
}
// The precise ordering of start-of-level made me want to cut my head off,
// so let's try this instead. Whatever!
if (leveltime <= starttime || player->gradingpointnum == 0)
{
if ((gametyperules & GTR_SPHERES)
|| (gametyperules & GTR_CATCHER)
|| G_TimeAttackStart()
|| (gametype == GT_TUTORIAL)
|| !M_NotFreePlay()
|| (K_GetNumWaypoints() == 0))
player->cangrabitems = EARLY_ITEM_FLICKER;
else
player->cangrabitems = 0;
}
if (player->cangrabitems && player->cangrabitems <= EARLY_ITEM_FLICKER)
player->cangrabitems++;
@ -11455,6 +11470,14 @@ INT16 K_GetKartTurnValue(const player_t *player, INT16 turnvalue)
turnfixed = FixedMul(turnfixed, 2*FRACUNIT); // Base increase to turning
}
/*
if (overtimecheckpoints)
{
fixed_t assistpercent = FRACUNIT * overtimecheckpoints / 32;
turnfixed += FixedMul(Easing_Linear(assistpercent, 0, FRACUNIT/2), turnfixed);
}
*/
if (player->drift != 0 && P_IsObjectOnGround(player->mo))
{
if (G_CompatLevel(0x000A))
@ -15772,6 +15795,29 @@ void K_BotHitPenalty(player_t *player)
}
}
boolean K_IsPickMeUpItem(mobjtype_t type)
{
switch (type)
{
case MT_JAWZ:
case MT_JAWZ_SHIELD:
case MT_ORBINAUT:
case MT_ORBINAUT_SHIELD:
case MT_DROPTARGET:
case MT_DROPTARGET_SHIELD:
case MT_LANDMINE:
case MT_BANANA:
case MT_BANANA_SHIELD:
case MT_GACHABOM:
case MT_EGGMANITEM:
case MT_EGGMANITEM_SHIELD:
case MT_BUBBLESHIELDTRAP:
return true;
default:
return false;
}
}
static boolean K_PickUp(player_t *player, mobj_t *picked)
{
SINT8 type = -1;
@ -15862,7 +15908,7 @@ static boolean K_PickUp(player_t *player, mobj_t *picked)
}
// ACHTUNG this destroys items when returning true, make sure to bail out
boolean K_TryPickMeUp(mobj_t *m1, mobj_t *m2)
boolean K_TryPickMeUp(mobj_t *m1, mobj_t *m2, boolean allowHostile)
{
if (!m1 || P_MobjWasRemoved(m1))
return false;
@ -15897,7 +15943,7 @@ boolean K_TryPickMeUp(mobj_t *m1, mobj_t *m2)
if (inflictor->target->player && G_SameTeam(inflictor->target->player, victim->player))
allied = true;
if (!allied)
if (!allied && !allowHostile)
return false;
// CONS_Printf("target check passed\n");

View file

@ -325,7 +325,9 @@ boolean K_LegacyRingboost(player_t *player);
void K_BotHitPenalty(player_t *player);
boolean K_TryPickMeUp(mobj_t *m1, mobj_t *m2);
boolean K_IsPickMeUpItem(mobjtype_t type);
boolean K_TryPickMeUp(mobj_t *m1, mobj_t *m2, boolean allowHostile);
fixed_t K_TeamComebackMultiplier(player_t *player);

View file

@ -411,7 +411,6 @@ void Obj_SSGobletMobjThink(mobj_t* mo);
void Obj_SSLampMapThingSpawn(mobj_t* mo, mapthing_t* mt);
void Obj_SSWindowMapThingSpawn(mobj_t* mo, mapthing_t* mt);
void Obj_SLSTMaceMobjThink(mobj_t* mo);
void Obj_SSBumperTouchSpecial(mobj_t* special, mobj_t* toucher);
void Obj_SSBumperMobjSpawn(mobj_t* mo);
void Obj_SSChainMobjThink(mobj_t* mo);
void Obj_SSGachaTargetMobjSpawn(mobj_t* mo);

View file

@ -92,6 +92,8 @@ typedef enum
PR_ITEM_SPAWNER = PROLDDEMO, // Battle mode item spawners
PR_TEAMS, // Teamplay shuffling
PR_NUISANCE, // Margin Boost HUD
PRNUMSYNCED,
PR_INTERPHUDRANDOM = PRNUMSYNCED, // Interpolation-accomodating HUD randomisation

View file

@ -72,6 +72,24 @@ static boolean input_routine(INT32)
return false;
}
static void init_routine(void)
{
if (!netgame)
{
S_SoundInputSetEnabled(true);
}
}
static boolean quit_routine(void)
{
if (!netgame)
{
S_SoundInputSetEnabled(false);
}
return true;
}
menu_t OPTIONS_VoiceDef = {
sizeof (OPTIONS_Voice) / sizeof (menuitem_t),
&OPTIONS_MainDef,
@ -85,7 +103,7 @@ menu_t OPTIONS_VoiceDef = {
draw_routine,
M_DrawOptionsCogs,
tick_routine,
NULL,
NULL,
init_routine,
quit_routine,
input_routine,
};

View file

@ -60,6 +60,7 @@ struct Visual : Mobj
}
move_origin(shield()->pos());
scale(5 * shield()->follow()->scale() / 4);
renderflags = (renderflags & ~RF_DONTDRAW) |
(shield()->state()->num() == S_INVISIBLE ? 0 : RF_DONTDRAW);

View file

@ -55,6 +55,7 @@ struct Visual : Mobj
}
move_origin(shield()->pos());
scale(5 * shield()->follow()->scale() / 4);
dispoffset = state()->num() == S_THNB1 ? -1 : 1;
return true;

View file

@ -190,7 +190,7 @@ boolean Obj_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2)
return true;
}
if (K_TryPickMeUp(t1, t2))
if (K_TryPickMeUp(t1, t2, false))
return true;
if (t1->type == MT_GARDENTOP)

View file

@ -542,58 +542,6 @@ void Obj_SLSTMaceMobjThink(mobj_t* mo)
}
}
#define BUMPER_STRENGTH (56)
void Obj_SSBumperTouchSpecial(mobj_t* special, mobj_t* toucher)
{
angle_t hang;
angle_t vang;
fixed_t str;
int i;
hang = R_PointToAngle2(special->x, special->y, toucher->x, toucher->y);
vang = 0;
if (P_IsObjectOnGround(toucher) == false)
{
vang = R_PointToAngle2(
FixedHypot(special->x, special->y), special->z + (special->height >> 1),
FixedHypot(toucher->x, toucher->y), toucher->z + (toucher->height >> 1)
);
}
str = (BUMPER_STRENGTH * special->scale) >> 1;
toucher->momx = FixedMul(FixedMul(str, FCOS(hang)), abs(FCOS(vang)));
toucher->momy = FixedMul(FixedMul(str, FSIN(hang)), abs(FCOS(vang)));
toucher->momz = FixedMul(str, FSIN(vang));
if (toucher->player)
{
if (toucher->player->tiregrease == 0)
{
for (i = 0; i < 2; i++)
{
mobj_t *grease = P_SpawnMobjFromMobj(toucher, 0, 0, 0, MT_TIREGREASE);
P_SetTarget(&grease->target, toucher);
grease->angle = toucher->angle;
grease->extravalue1 = i;
}
}
if (toucher->player->tiregrease < 2*TICRATE) // greasetics
{
toucher->player->tiregrease = 2*TICRATE;
}
}
if (special->state != &states[special->info->seestate])
{
S_StartSound(special, special->info->deathsound);
P_SetMobjState(special, special->info->seestate);
}
}
void Obj_SSBumperMobjSpawn(mobj_t* mo)
{
mo->shadowscale = FRACUNIT;

View file

@ -321,6 +321,7 @@ void A_BlendEyePuyoHack(mobj_t *actor);
void A_MakeSSCandle(mobj_t *actor);
void A_HologramRandomTranslucency(mobj_t *actor);
void A_SSChainShatter(mobj_t *actor);
void A_GenericBumper(mobj_t *actor);
//for p_enemy.c
@ -12668,3 +12669,54 @@ void A_SSChainShatter(mobj_t* actor)
actor->fuse = 1;
}
// var1 = If -1, triggered by collision event
// var2 = Strength value
//
// mobjinfo dependencies:
// - deathsound - bumper noise
// - seestate - bumper flashing state
//
void A_GenericBumper(mobj_t* actor)
{
if (var1 != -1)
return;
mobj_t *other = actor->target;
if (!other)
return;
// This code was ported from Lua
// Original was Balloon Park's bumpers?
INT32 hang = R_PointToAngle2(
actor->x, actor->y,
other->x, other->y
);
INT32 vang = 0;
if (!P_IsObjectOnGround(other))
{
vang = R_PointToAngle2(
FixedHypot(actor->x, actor->y), actor->z + (actor->height / 2),
FixedHypot(other->x, other->y), other->z + (other->height / 2)
);
}
INT32 baseStrength = abs(astate->var2);
fixed_t strength = (baseStrength * actor->scale) / 2;
other->momx = FixedMul(FixedMul(strength, FCOS(hang)), abs(FCOS(vang)));
other->momy = FixedMul(FixedMul(strength, FSIN(hang)), abs(FCOS(vang)));
other->momz = FixedMul(strength, FSIN(vang));
if (other->player)
K_SetTireGrease(other->player, max(other->player->tiregrease, 2*TICRATE));
if (actor->state != &states[actor->info->seestate])
{
S_StartSound(actor, actor->info->deathsound);
P_SetMobjState(actor, actor->info->seestate);
}
}

View file

@ -667,7 +667,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
if (!player->mo || player->spectator)
return;
if (K_TryPickMeUp(special, toucher))
if (K_TryPickMeUp(special, toucher, false))
return;
// attach to player!
@ -1083,10 +1083,6 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
Obj_TrickBalloonTouchSpecial(special, toucher);
return;
case MT_SEALEDSTAR_BUMPER:
Obj_SSBumperTouchSpecial(special, toucher);
return;
case MT_PULLUPHOOK:
Obj_PulleyHookTouch(special, toucher);
return;

View file

@ -612,6 +612,9 @@ void P_InitTIDHash(void);
void P_AddThingTID(mobj_t *mo);
void P_RemoveThingTID(mobj_t *mo);
void P_SetThingTID(mobj_t *mo, mtag_t tid);
// This function cannot be safely called after *i is removed!
// Please call at start of loops if *i is to be mutated
mobj_t *P_FindMobjFromTID(mtag_t tid, mobj_t *i, mobj_t *activator);
void P_DeleteMobjStringArgs(mobj_t *mobj);

View file

@ -1552,7 +1552,19 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
if (!K_PuntCollide(thing, g_tm.thing))
{
K_KartSolidBounce(g_tm.thing, thing);
state_t *st = &states[thing->info->spawnstate];
if (st->action.acp1 == A_GenericBumper)
{
P_SetTarget(&thing->target, g_tm.thing);
var1 = -1;
var2 = 0;
astate = st;
st->action.acp1(thing);
}
else
K_KartSolidBounce(g_tm.thing, thing);
}
return BMIT_CONTINUE;
}

View file

@ -15417,6 +15417,8 @@ void P_SetThingTID(mobj_t *mo, mtag_t tid)
//
// P_FindMobjFromTID
// Mobj tag search function.
// This function cannot be safely called after *i is removed!
// Please call at start of loops if *i is to be mutated
//
mobj_t *P_FindMobjFromTID(mtag_t tid, mobj_t *i, mobj_t *activator)
{

View file

@ -3275,8 +3275,13 @@ boolean P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, cha
return false;
}
while ((targetThing = P_FindMobjFromTID(args[1], targetThing, mo)) != NULL)
mobj_t *next = P_FindMobjFromTID(args[1], targetThing, mo);
while ((targetThing = next) != NULL)
{
// First in case of deletion. (Can't check for state == S_NULL because of A_ calls, etc)
next = P_FindMobjFromTID(args[1], targetThing, mo);
if (targetThing->player != NULL)
{
continue;

View file

@ -3763,7 +3763,6 @@ boolean P_SpectatorJoinGame(player_t *player)
}
player->spectator = false;
player->pflags &= ~PF_WANTSTOJOIN;
player->spectatewait = 0;
player->team = TEAM_UNASSIGNED; // We will auto-assign later.
player->playerstate = PST_REBORN;
player->enteredGame = true;
@ -3778,6 +3777,10 @@ boolean P_SpectatorJoinGame(player_t *player)
// a surprise tool that will help us later...
text = va("\x82*%s entered the game.", player_names[player-players]);
if (P_IsMachineLocalPlayer(player) && player->spectatewait > TICRATE)
S_StartSound(NULL, sfx_s3ka9);
player->spectatewait = 0;
HU_AddChatText(text, false);
return true; // no more player->mo, cannot continue.
}

View file

@ -198,7 +198,6 @@ static void (*music_fade_callback)();
static SDL_AudioDeviceID g_device_id;
static SDL_AudioDeviceID g_input_device_id;
static boolean g_input_device_paused;
void* I_GetSfx(sfxinfo_t* sfx)
{
@ -999,14 +998,14 @@ void I_UpdateAudioRecorder(void)
boolean I_SoundInputIsEnabled(void)
{
return g_input_device_id != 0 && !g_input_device_paused;
return g_input_device_id != 0;
}
boolean I_SoundInputSetEnabled(boolean enabled)
{
if (g_input_device_id == 0 && enabled)
{
if (SDL_GetNumAudioDevices(true) == 0)
if (!sound_started || SDL_GetNumAudioDevices(true) == 0)
{
return false;
}
@ -1023,21 +1022,17 @@ boolean I_SoundInputSetEnabled(boolean enabled)
CONS_Alert(CONS_WARNING, "Failed to open input audio device: %s\n", SDL_GetError());
return false;
}
g_input_device_paused = true;
}
if (enabled && g_input_device_paused)
{
SDL_PauseAudioDevice(g_input_device_id, SDL_FALSE);
g_input_device_paused = false;
}
else if (!enabled && !g_input_device_paused)
else if (g_input_device_id != 0 && !enabled)
{
SDL_PauseAudioDevice(g_input_device_id, SDL_TRUE);
SDL_ClearQueuedAudio(g_input_device_id);
g_input_device_paused = true;
SDL_CloseAudioDevice(g_input_device_id);
g_input_device_id = 0;
}
return !g_input_device_paused;
return enabled;
}
UINT32 I_SoundInputDequeueSamples(void *data, UINT32 len)

View file

@ -2544,9 +2544,10 @@ void Y_StartIntermission(void)
}
K_CashInPowerLevels();
SV_BumpMatchStats();
}
SV_BumpMatchStats();
if (!timer)
{
Y_EndIntermission();