mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Merge branch 'jartha/stone-shoe' into 'master'
Stone Shoe See merge request kart-krew-dev/ring-racers-internal!2627
This commit is contained in:
commit
4d89627f13
17 changed files with 654 additions and 24 deletions
|
|
@ -686,6 +686,7 @@ consvar_t cv_items[] = {
|
|||
UnsavedNetVar("droptarget", "On").on_off(),
|
||||
UnsavedNetVar("gardentop", "On").on_off(),
|
||||
UnsavedNetVar("gachabom", "On").on_off(),
|
||||
UnsavedNetVar("stoneshoe", "On").on_off(),
|
||||
UnsavedNetVar("dualsneaker", "On").on_off(),
|
||||
UnsavedNetVar("triplesneaker", "On").on_off(),
|
||||
UnsavedNetVar("triplebanana", "On").on_off(),
|
||||
|
|
|
|||
|
|
@ -193,7 +193,8 @@ Run this macro, then #undef FOREACH afterward
|
|||
FOREACH (KITCHENSINK, 20),\
|
||||
FOREACH (DROPTARGET, 21),\
|
||||
FOREACH (GARDENTOP, 22),\
|
||||
FOREACH (GACHABOM, 23)
|
||||
FOREACH (GACHABOM, 23),\
|
||||
FOREACH (STONESHOE, 24)
|
||||
|
||||
typedef enum
|
||||
{
|
||||
|
|
@ -214,6 +215,8 @@ typedef enum
|
|||
|
||||
NUMKARTRESULTS,
|
||||
|
||||
KDROP_STONESHOETRAP,
|
||||
|
||||
// Power-ups exist in the same enum as items so it's easy
|
||||
// for paper items to be reused for them.
|
||||
FIRSTPOWERUP,
|
||||
|
|
@ -771,6 +774,7 @@ struct player_t
|
|||
fixed_t accelboost; // Boost value smoothing for acceleration
|
||||
fixed_t handleboost; // Boost value smoothing for handling
|
||||
angle_t boostangle; // angle set when not spun out OR boosted to determine what direction you should keep going at if you're spun out and boosted.
|
||||
fixed_t stonedrag;
|
||||
|
||||
fixed_t draftpower; // (0 to FRACUNIT) - Drafting power, doubles your top speed & acceleration at max
|
||||
UINT16 draftleeway; // Leniency timer before removing draft power
|
||||
|
|
@ -1047,6 +1051,7 @@ struct player_t
|
|||
mobj_t *whip;
|
||||
mobj_t *hand;
|
||||
mobj_t *flickyAttacker;
|
||||
mobj_t *stoneShoe;
|
||||
|
||||
SINT8 pitblame; // Index of last player that hit you, resets after being in control for a bit. If you deathpit, credit the old attacker!
|
||||
|
||||
|
|
|
|||
|
|
@ -3109,6 +3109,8 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
|
|||
|
||||
// Flybot767 (stun)
|
||||
"S_FLYBOT767",
|
||||
|
||||
"S_STON",
|
||||
};
|
||||
|
||||
// RegEx to generate this from info.h: ^\tMT_([^,]+), --> \t"MT_\1",
|
||||
|
|
@ -4009,6 +4011,9 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
|
|||
"MT_AMPS",
|
||||
|
||||
"MT_FLYBOT767",
|
||||
|
||||
"MT_STONESHOE",
|
||||
"MT_STONESHOE_CHAIN",
|
||||
};
|
||||
|
||||
const char *const MOBJFLAG_LIST[] = {
|
||||
|
|
@ -5194,6 +5199,7 @@ struct int_const_s const INT_CONST[] = {
|
|||
{"KRITEM_DUALJAWZ",KRITEM_DUALJAWZ},
|
||||
{"KRITEM_TRIPLEGACHABOM",KRITEM_TRIPLEGACHABOM},
|
||||
{"NUMKARTRESULTS",NUMKARTRESULTS},
|
||||
{"KDROP_STONESHOETRAP",KDROP_STONESHOETRAP},
|
||||
{"FIRSTPOWERUP",FIRSTPOWERUP},
|
||||
{"POWERUP_SMONITOR",POWERUP_SMONITOR},
|
||||
{"POWERUP_BARRIER",POWERUP_BARRIER},
|
||||
|
|
|
|||
58
src/info.c
58
src/info.c
|
|
@ -792,6 +792,8 @@ char sprnames[NUMSPRITES + 1][5] =
|
|||
// Flybot767 (stun)
|
||||
"STUN",
|
||||
|
||||
"STON",
|
||||
|
||||
// Pulley
|
||||
"HCCH",
|
||||
"HCHK",
|
||||
|
|
@ -3680,6 +3682,8 @@ state_t states[NUMSTATES] =
|
|||
|
||||
// Flybot767 (stun)
|
||||
{SPR_STUN, FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 4, 4, S_NULL}, // S_FLYBOT767
|
||||
|
||||
{SPR_STON, 0, -1, {NULL}, 0, 0, S_STON}, // S_STON
|
||||
};
|
||||
|
||||
mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
||||
|
|
@ -13336,7 +13340,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
S_ITEMICON, // spawnstate
|
||||
1, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
sfx_tossed, // seesound
|
||||
0, // reactiontime
|
||||
sfx_None, // attacksound
|
||||
S_NULL, // painstate
|
||||
|
|
@ -22529,6 +22533,58 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIP|MF_NOCLIPTHING, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
{ // MT_STONESHOE
|
||||
-1, // doomednum
|
||||
S_STON, // 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_pop, // deathsound
|
||||
4*FRACUNIT, // speed
|
||||
64*FRACUNIT, // radius
|
||||
64*FRACUNIT, // height
|
||||
0, // dispoffset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_SOLID|MF_NOSQUISH|MF_NOHITLAGFORME|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
{ // MT_STONESHOE_CHAIN
|
||||
-1, // doomednum
|
||||
S_SHRINK_CHAIN, // 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
|
||||
32*FRACUNIT, // radius
|
||||
64*FRACUNIT, // height
|
||||
0, // display offset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_SPECIAL|MF_SCENERY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_PICKUPFROMBELOW|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1329,6 +1329,8 @@ typedef enum sprite
|
|||
// Flybot767 (stun)
|
||||
SPR_STUN,
|
||||
|
||||
SPR_STON,
|
||||
|
||||
// Pulley
|
||||
SPR_HCCH,
|
||||
SPR_HCHK,
|
||||
|
|
@ -4167,6 +4169,8 @@ typedef enum state
|
|||
// Flybot767 (stun)
|
||||
S_FLYBOT767,
|
||||
|
||||
S_STON,
|
||||
|
||||
S_FIRSTFREESLOT,
|
||||
S_LASTFREESLOT = S_FIRSTFREESLOT + NUMSTATEFREESLOTS - 1,
|
||||
NUMSTATES
|
||||
|
|
@ -5090,6 +5094,9 @@ typedef enum mobj_type
|
|||
|
||||
MT_FLYBOT767,
|
||||
|
||||
MT_STONESHOE,
|
||||
MT_STONESHOE_CHAIN,
|
||||
|
||||
MT_FIRSTFREESLOT,
|
||||
MT_LASTFREESLOT = MT_FIRSTFREESLOT + NUMMOBJFREESLOTS - 1,
|
||||
NUMMOBJTYPES
|
||||
|
|
|
|||
|
|
@ -171,6 +171,7 @@ static patch_t *kp_kitchensink[3];
|
|||
static patch_t *kp_droptarget[3];
|
||||
static patch_t *kp_gardentop[3];
|
||||
static patch_t *kp_gachabom[3];
|
||||
static patch_t *kp_stoneshoe[3];
|
||||
static patch_t *kp_bar[2];
|
||||
static patch_t *kp_doublebar[2];
|
||||
static patch_t *kp_triplebar[2];
|
||||
|
|
@ -639,6 +640,7 @@ void K_LoadKartHUDGraphics(void)
|
|||
HU_UpdatePatch(&kp_droptarget[0], "K_ITDTRG");
|
||||
HU_UpdatePatch(&kp_gardentop[0], "K_ITGTOP");
|
||||
HU_UpdatePatch(&kp_gachabom[0], "K_ITGBOM");
|
||||
HU_UpdatePatch(&kp_stoneshoe[0], "K_ITSTON");
|
||||
HU_UpdatePatch(&kp_bar[0], "K_RBBAR");
|
||||
HU_UpdatePatch(&kp_doublebar[0], "K_RBBAR2");
|
||||
HU_UpdatePatch(&kp_triplebar[0], "K_RBBAR3");
|
||||
|
|
@ -699,6 +701,7 @@ void K_LoadKartHUDGraphics(void)
|
|||
HU_UpdatePatch(&kp_droptarget[1], "K_ISDTRG");
|
||||
HU_UpdatePatch(&kp_gardentop[1], "K_ISGTOP");
|
||||
HU_UpdatePatch(&kp_gachabom[1], "K_ISGBOM");
|
||||
HU_UpdatePatch(&kp_stoneshoe[1], "K_ISSTON");
|
||||
HU_UpdatePatch(&kp_bar[1], "K_SBBAR");
|
||||
HU_UpdatePatch(&kp_doublebar[1], "K_SBBAR2");
|
||||
HU_UpdatePatch(&kp_triplebar[1], "K_SBBAR3");
|
||||
|
|
@ -757,6 +760,7 @@ void K_LoadKartHUDGraphics(void)
|
|||
HU_UpdatePatch(&kp_droptarget[2], "ISPYDTRG");
|
||||
HU_UpdatePatch(&kp_gardentop[2], "ISPYGTOP");
|
||||
HU_UpdatePatch(&kp_gachabom[2], "ISPYGBOM");
|
||||
HU_UpdatePatch(&kp_stoneshoe[2], "ISPYSTON");
|
||||
|
||||
// CHECK indicators
|
||||
sprintf(buffer, "K_CHECKx");
|
||||
|
|
@ -1177,6 +1181,7 @@ static patch_t *K_GetCachedItemPatch(INT32 item, UINT8 offset)
|
|||
kp_droptarget,
|
||||
kp_gardentop,
|
||||
kp_gachabom,
|
||||
kp_stoneshoe,
|
||||
};
|
||||
|
||||
if (item == KITEM_SAD || (item > KITEM_NONE && item < NUMKARTITEMS))
|
||||
|
|
|
|||
|
|
@ -389,6 +389,14 @@ bool is_object_tracking_target(const mobj_t* mobj)
|
|||
return !(mobj->renderflags & (RF_TRANSMASK | RF_DONTDRAW)) && // the spraycan wasn't collected yet
|
||||
P_CheckSight(stplyr->mo, const_cast<mobj_t*>(mobj));
|
||||
|
||||
case MT_FLOATINGITEM:
|
||||
if (mobj->threshold != KDROP_STONESHOETRAP)
|
||||
return false;
|
||||
|
||||
if (cv_debugpickmeup.value)
|
||||
return false;
|
||||
|
||||
// FALLTHRU
|
||||
default:
|
||||
if (K_IsPickMeUpItem(mobj->type))
|
||||
return (mobj->target && !P_MobjWasRemoved(mobj->target) && (
|
||||
|
|
|
|||
97
src/k_kart.c
97
src/k_kart.c
|
|
@ -808,6 +808,7 @@ fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against)
|
|||
case MT_ORBINAUT_SHIELD:
|
||||
case MT_GACHABOM:
|
||||
case MT_DUELBOMB:
|
||||
case MT_STONESHOE:
|
||||
if (against->player)
|
||||
weight = K_PlayerWeight(against, NULL);
|
||||
break;
|
||||
|
|
@ -933,6 +934,8 @@ static boolean K_JustBumpedException(mobj_t *mobj)
|
|||
}
|
||||
break;
|
||||
}
|
||||
case MT_STONESHOE:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -3527,6 +3530,9 @@ static void K_GetKartBoostPower(player_t *player)
|
|||
if (player->bananadrag > TICRATE)
|
||||
boostpower = (4*boostpower)/5;
|
||||
|
||||
if (player->stonedrag)
|
||||
boostpower = (4*boostpower)/5;
|
||||
|
||||
// Note: Handling will ONLY stack when sliptiding!
|
||||
// > (NB 2023-03-06: This was previously unintentionally applied while drifting as well.)
|
||||
// > (This only affected drifts where you were under the effect of multiple handling boosts.)
|
||||
|
|
@ -4669,7 +4675,7 @@ void K_RemoveGrowShrink(player_t *player)
|
|||
static boolean K_IsScaledItem(mobj_t *mobj)
|
||||
{
|
||||
return mobj && !P_MobjWasRemoved(mobj) &&
|
||||
(mobj->type == MT_ORBINAUT || mobj->type == MT_JAWZ || mobj->type == MT_GACHABOM
|
||||
(mobj->type == MT_ORBINAUT || mobj->type == MT_JAWZ || mobj->type == MT_GACHABOM || mobj->type == MT_STONESHOE
|
||||
|| mobj->type == MT_BANANA || mobj->type == MT_EGGMANITEM || mobj->type == MT_BALLHOG
|
||||
|| mobj->type == MT_SSMINE || mobj->type == MT_LANDMINE || mobj->type == MT_SINK
|
||||
|| mobj->type == MT_GARDENTOP || mobj->type == MT_DROPTARGET || mobj->type == MT_PLAYER);
|
||||
|
|
@ -6888,8 +6894,13 @@ mobj_t *K_ThrowKartItemEx(player_t *player, boolean missile, mobjtype_t mapthing
|
|||
if (dir > 0)
|
||||
{
|
||||
// Shoot forward
|
||||
mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z + player->mo->height/2, mapthing);
|
||||
mo->angle = player->mo->angle;
|
||||
if (mapthing == MT_FLOATINGITEM)
|
||||
mo = K_CreatePaperItem(player->mo->x, player->mo->y, player->mo->z + player->mo->height/2, player->mo->angle, 0, 1, 0);
|
||||
else
|
||||
{
|
||||
mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z + player->mo->height/2, mapthing);
|
||||
mo->angle = player->mo->angle;
|
||||
}
|
||||
|
||||
// These are really weird so let's make it a very specific case to make SURE it works...
|
||||
if (player->mo->eflags & MFE_VERTICALFLIP)
|
||||
|
|
@ -6907,7 +6918,7 @@ mobj_t *K_ThrowKartItemEx(player_t *player, boolean missile, mobjtype_t mapthing
|
|||
mo->extravalue2 = dir;
|
||||
|
||||
fixed_t HEIGHT = ((20 * FRACUNIT) + (dir * 10)) + (FixedDiv(player->mo->momz, mapobjectscale) * P_MobjFlip(player->mo)); // Also intentionally not player scale
|
||||
P_SetObjectMomZ(mo, HEIGHT, false);
|
||||
mo->momz = FixedMul(HEIGHT, mapobjectscale) * P_MobjFlip(mo);
|
||||
|
||||
angle_t fa = (player->mo->angle >> ANGLETOFINESHIFT);
|
||||
mo->momx = player->mo->momx + FixedMul(FINECOSINE(fa), FixedMul(PROJSPEED, dir));
|
||||
|
|
@ -6936,8 +6947,11 @@ mobj_t *K_ThrowKartItemEx(player_t *player, boolean missile, mobjtype_t mapthing
|
|||
if (mo->eflags & MFE_UNDERWATER)
|
||||
mo->momz = (117 * mo->momz) / 200;
|
||||
|
||||
P_SetScale(mo, finalscale);
|
||||
mo->destscale = finalscale;
|
||||
if (mapthing != MT_FLOATINGITEM)
|
||||
{
|
||||
P_SetScale(mo, finalscale);
|
||||
mo->destscale = finalscale;
|
||||
}
|
||||
|
||||
switch (mapthing)
|
||||
{
|
||||
|
|
@ -6984,6 +6998,13 @@ mobj_t *K_ThrowKartItemEx(player_t *player, boolean missile, mobjtype_t mapthing
|
|||
newy = player->mo->y + player->mo->momy;
|
||||
newz = player->mo->z;
|
||||
}
|
||||
else if (mapthing == MT_FLOATINGITEM) // Stone Shoe
|
||||
{
|
||||
newangle = player->mo->angle;
|
||||
newx = player->mo->x + player->mo->momx - FixedMul(2 * player->mo->radius + 40 * mapobjectscale, FCOS(newangle));
|
||||
newy = player->mo->y + player->mo->momy - FixedMul(2 * player->mo->radius + 40 * mapobjectscale, FSIN(newangle));
|
||||
newz = player->mo->z;
|
||||
}
|
||||
else if (lasttrail)
|
||||
{
|
||||
newangle = lasttrail->angle;
|
||||
|
|
@ -7003,14 +7024,23 @@ mobj_t *K_ThrowKartItemEx(player_t *player, boolean missile, mobjtype_t mapthing
|
|||
newz = player->mo->z;
|
||||
}
|
||||
|
||||
mo = P_SpawnMobj(newx, newy, newz, mapthing); // this will never return null because collision isn't processed here
|
||||
if (mapthing == MT_FLOATINGITEM)
|
||||
mo = K_CreatePaperItem(newx, newy, newz, newangle, 0, 1, 0);
|
||||
else
|
||||
{
|
||||
mo = P_SpawnMobj(newx, newy, newz, mapthing); // this will never return null because collision isn't processed here
|
||||
mo->angle = newangle;
|
||||
}
|
||||
K_FlipFromObject(mo, player->mo);
|
||||
|
||||
mo->threshold = 10;
|
||||
P_SetTarget(&mo->target, player->mo);
|
||||
|
||||
P_SetScale(mo, finalscale);
|
||||
mo->destscale = finalscale;
|
||||
if (mapthing != MT_FLOATINGITEM)
|
||||
{
|
||||
P_SetScale(mo, finalscale);
|
||||
mo->destscale = finalscale;
|
||||
}
|
||||
|
||||
if (P_IsObjectOnGround(player->mo))
|
||||
{
|
||||
|
|
@ -7039,8 +7069,6 @@ mobj_t *K_ThrowKartItemEx(player_t *player, boolean missile, mobjtype_t mapthing
|
|||
if (player->mo->eflags & MFE_VERTICALFLIP)
|
||||
mo->eflags |= MFE_VERTICALFLIP;
|
||||
|
||||
mo->angle = newangle;
|
||||
|
||||
if (mapthing == MT_SSMINE)
|
||||
mo->extravalue1 = 49; // Pads the start-up length from 21 frames to a full 2 seconds
|
||||
else if (mapthing == MT_BUBBLESHIELDTRAP)
|
||||
|
|
@ -10506,6 +10534,8 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
// S_StartSound(NULL, sfx_s26d);
|
||||
P_DamageMobj(player->mo, NULL, NULL, 1, DMG_INSTAKILL);
|
||||
}
|
||||
|
||||
player->stonedrag = 0;
|
||||
}
|
||||
|
||||
void K_KartResetPlayerColor(player_t *player)
|
||||
|
|
@ -14607,6 +14637,37 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
player->botvars.itemconfirm = 0;
|
||||
}
|
||||
break;
|
||||
case KITEM_STONESHOE:
|
||||
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
|
||||
{
|
||||
if (player->throwdir == -1)
|
||||
{
|
||||
// Do not spawn a shoe if you're already dragging one
|
||||
if (!P_MobjWasRemoved(player->stoneShoe))
|
||||
break;
|
||||
P_SetTarget(&player->stoneShoe, Obj_SpawnStoneShoe(player - players, player->mo));
|
||||
K_AddHitLag(player->mo, 8, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
K_SetItemOut(player); // need this to set itemscale
|
||||
|
||||
mobj_t *drop = K_ThrowKartItem(player, false, MT_FLOATINGITEM, -1, 0, 0);
|
||||
drop->threshold = KDROP_STONESHOETRAP;
|
||||
drop->movecount = 1;
|
||||
drop->extravalue2 = player - players;
|
||||
drop->radius = 32 * drop->scale;
|
||||
drop->flags |= MF_SHOOTABLE; // let it whip/lightning shield
|
||||
|
||||
K_UnsetItemOut(player);
|
||||
}
|
||||
|
||||
player->itemamount--;
|
||||
K_PlayAttackTaunt(player->mo);
|
||||
K_UpdateHnextList(player, false);
|
||||
player->botvars.itemconfirm = 0;
|
||||
}
|
||||
break;
|
||||
case KITEM_SAD:
|
||||
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO
|
||||
&& !player->sadtimer)
|
||||
|
|
@ -15448,6 +15509,10 @@ void K_UpdateMobjItemOverlay(mobj_t *part, SINT8 itemType, UINT8 itemCount)
|
|||
part->sprite = SPR_ITEM;
|
||||
part->frame = FF_FULLBRIGHT|FF_PAPERSPRITE;
|
||||
break;
|
||||
case KDROP_STONESHOETRAP:
|
||||
part->sprite = SPR_STON;
|
||||
part->frame = FF_FULLBRIGHT|FF_PAPERSPRITE|4;
|
||||
break;
|
||||
default:
|
||||
if (itemType >= FIRSTPOWERUP)
|
||||
{
|
||||
|
|
@ -15887,6 +15952,7 @@ boolean K_IsPickMeUpItem(mobjtype_t type)
|
|||
case MT_BUBBLESHIELDTRAP:
|
||||
case MT_SSMINE:
|
||||
case MT_SSMINE_SHIELD:
|
||||
case MT_FLOATINGITEM: // Stone Shoe
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
|
@ -15930,6 +15996,9 @@ static boolean K_PickUp(player_t *player, mobj_t *picked)
|
|||
case MT_GACHABOM:
|
||||
type = KITEM_GACHABOM;
|
||||
break;
|
||||
case MT_STONESHOE:
|
||||
type = KITEM_STONESHOE;
|
||||
break;
|
||||
case MT_BUBBLESHIELDTRAP:
|
||||
type = KITEM_BUBBLESHIELD;
|
||||
break;
|
||||
|
|
@ -15940,6 +16009,12 @@ static boolean K_PickUp(player_t *player, mobj_t *picked)
|
|||
case MT_SSMINE_SHIELD:
|
||||
type = KITEM_MINE;
|
||||
break;
|
||||
case MT_FLOATINGITEM:
|
||||
if (picked->threshold == KDROP_STONESHOETRAP)
|
||||
type = KITEM_STONESHOE;
|
||||
else
|
||||
type = KITEM_SAD;
|
||||
break;
|
||||
default:
|
||||
type = KITEM_SAD;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -460,6 +460,13 @@ boolean Obj_TickLightningShieldVisual(mobj_t *mobj);
|
|||
void Obj_SpawnFlameShieldVisuals(mobj_t *source);
|
||||
boolean Obj_TickFlameShieldVisual(mobj_t *mobj);
|
||||
|
||||
/* Stone Shoe */
|
||||
mobj_t *Obj_SpawnStoneShoe(INT32 owner, mobj_t *victim);
|
||||
boolean Obj_TickStoneShoe(mobj_t *shoe);
|
||||
boolean Obj_TickStoneShoeChain(mobj_t *chain);
|
||||
player_t *Obj_StoneShoeOwnerPlayer(mobj_t *shoe);
|
||||
void Obj_CollideStoneShoe(mobj_t *mover, mobj_t *mobj);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@ static UINT32 K_DynamicItemOddsRace[NUMKARTRESULTS-1][2] =
|
|||
{1, 3}, // droptarget
|
||||
{43, 5}, // gardentop
|
||||
{0, 0}, // gachabom
|
||||
{1, 3}, // stoneshoe
|
||||
{45, 6}, // dualsneaker
|
||||
{55, 8}, // triplesneaker
|
||||
{25, 2}, // triplebanana
|
||||
|
|
@ -138,6 +139,7 @@ static UINT32 K_DynamicItemOddsBattle[NUMKARTRESULTS-1][2] =
|
|||
{0, 0}, // droptarget
|
||||
{0, 0}, // gardentop
|
||||
{10, 5}, // gachabom
|
||||
{0, 0}, // stoneshoe
|
||||
{0, 0}, // dualsneaker
|
||||
{20, 1}, // triplesneaker
|
||||
{0, 0}, // triplebanana
|
||||
|
|
@ -173,6 +175,7 @@ static UINT32 K_DynamicItemOddsSpecial[NUMKARTRESULTS-1][2] =
|
|||
{0, 0}, // droptarget
|
||||
{0, 0}, // gardentop
|
||||
{0, 0}, // gachabom
|
||||
{0, 0}, // stoneshoe
|
||||
{35, 2}, // dualsneaker
|
||||
{0, 0}, // triplesneaker
|
||||
{0, 0}, // triplebanana
|
||||
|
|
@ -208,6 +211,7 @@ static UINT8 K_KartLegacyBattleOdds[NUMKARTRESULTS-1][2] =
|
|||
{ 0, 0 }, // Drop Target
|
||||
{ 0, 0 }, // Garden Top
|
||||
{ 5, 0 }, // Gachabom
|
||||
{ 0, 1 }, // Stone Shoe
|
||||
{ 0, 0 }, // Sneaker x2
|
||||
{ 0, 1 }, // Sneaker x3
|
||||
{ 0, 0 }, // Banana x3
|
||||
|
|
@ -368,6 +372,7 @@ botItemPriority_e K_GetBotItemPriority(kartitems_t result)
|
|||
case KITEM_DROPTARGET:
|
||||
case KITEM_EGGMAN:
|
||||
case KITEM_GACHABOM:
|
||||
case KITEM_STONESHOE:
|
||||
case KITEM_KITCHENSINK:
|
||||
{
|
||||
// Used when in 1st place and relatively far from players.
|
||||
|
|
@ -1044,6 +1049,7 @@ static boolean K_IsItemFirstOnly(kartitems_t item)
|
|||
case KITEM_LIGHTNINGSHIELD:
|
||||
case KITEM_HYUDORO:
|
||||
case KITEM_DROPTARGET:
|
||||
case KITEM_STONESHOE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ target_sources(SRB2SDL2 PRIVATE
|
|||
flybot767.c
|
||||
lightning-shield.cpp
|
||||
flame-shield.cpp
|
||||
stone-shoe.cpp
|
||||
)
|
||||
|
||||
add_subdirectory(versus)
|
||||
|
|
|
|||
362
src/objects/stone-shoe.cpp
Normal file
362
src/objects/stone-shoe.cpp
Normal file
|
|
@ -0,0 +1,362 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2025 by James Robert Roman
|
||||
// Copyright (C) 2025 by Kart Krew
|
||||
//
|
||||
// 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 <cstdlib>
|
||||
|
||||
#include "objects.hpp"
|
||||
|
||||
#include "../g_game.h"
|
||||
#include "../k_kart.h"
|
||||
#include "../m_easing.h"
|
||||
#include "../m_fixed.h"
|
||||
#include "../p_spec.h"
|
||||
#include "../r_main.h"
|
||||
#include "../tables.h"
|
||||
|
||||
using namespace srb2::objects;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct Player : Mobj
|
||||
{
|
||||
bool valid() const { return player != nullptr; }
|
||||
};
|
||||
|
||||
struct Shoe;
|
||||
|
||||
struct Chain : Mobj
|
||||
{
|
||||
void hnext() = delete;
|
||||
Chain* next() const { return Mobj::hnext<Chain>(); }
|
||||
void next(Chain* n) { Mobj::hnext(n); }
|
||||
|
||||
void target() = delete;
|
||||
Shoe* shoe() const { return Mobj::target<Shoe>(); }
|
||||
void shoe(Shoe* n) { Mobj::target(n); }
|
||||
|
||||
bool valid() const;
|
||||
|
||||
bool try_damage(Player* pmo);
|
||||
|
||||
bool tick()
|
||||
{
|
||||
if (!valid())
|
||||
{
|
||||
remove();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct Shoe : Mobj
|
||||
{
|
||||
void target() = delete;
|
||||
Player* follow() const { return Mobj::target<Player>(); }
|
||||
void follow(Player* n) { Mobj::target(n); }
|
||||
|
||||
void movedir() = delete;
|
||||
INT32 dir() const { return Mobj::movedir; }
|
||||
void dir(INT32 n) { Mobj::movedir = n; }
|
||||
|
||||
void hnext() = delete;
|
||||
Chain* chain() const { return Mobj::hnext<Chain>(); }
|
||||
void chain(Chain* n) { Mobj::hnext(n); }
|
||||
|
||||
void extravalue1() = delete;
|
||||
INT32 chainLength() const { return mobj_t::extravalue1; }
|
||||
void chainLength(INT32 n) { mobj_t::extravalue1 = n; }
|
||||
|
||||
void extravalue2() = delete;
|
||||
INT32 owner() const { return mobj_t::extravalue2; }
|
||||
void owner(INT32 n) { mobj_t::extravalue2 = n; }
|
||||
|
||||
void threshold() = delete;
|
||||
bool bouncing() const { return mobj_t::threshold; }
|
||||
void bouncing(bool n) { mobj_t::threshold = n; }
|
||||
|
||||
bool valid() const { return Mobj::valid(follow()) && follow()->valid() && Mobj::valid(chain()); }
|
||||
|
||||
Fixed minDist() const { return 200 * mapobjectscale; }
|
||||
Fixed maxDist() const { return 800 * mapobjectscale; }
|
||||
|
||||
angle_t followAngle() const { return R_PointToAngle2(x, y, follow()->x, follow()->y); }
|
||||
Fixed followDistance() const { return FixedHypot(x - follow()->x, y - follow()->y); }
|
||||
|
||||
static Vec2<Fixed> followVector(angle_t a) { return Vec2<Fixed> {FCOS(a), FSIN(a)}; }
|
||||
Vec2<Fixed> followVector() const { return followVector(followAngle()); }
|
||||
|
||||
player_t* ownerPlayer() const
|
||||
{
|
||||
if (owner() < 0 || owner() >= MAXPLAYERS)
|
||||
return nullptr;
|
||||
return &players[owner()];
|
||||
}
|
||||
|
||||
static Shoe* spawn
|
||||
( INT32 owner,
|
||||
Player* victim)
|
||||
{
|
||||
Vec2<Fixed> P = followVector(victim->angle) * Fixed {-40 * mapobjectscale};
|
||||
Shoe* shoe = victim->spawn_from<Shoe>({P, 0}, MT_STONESHOE);
|
||||
|
||||
shoe->follow(victim);
|
||||
shoe->owner(owner);
|
||||
shoe->dir(0);
|
||||
shoe->fuse = 15 * TICRATE;
|
||||
|
||||
INT32 numLinks = 8;
|
||||
Chain* link = nullptr;
|
||||
|
||||
for (INT32 i = 0; i < numLinks; ++i)
|
||||
{
|
||||
Chain* node = shoe->spawn_from<Chain>(MT_STONESHOE_CHAIN);
|
||||
node->next(link);
|
||||
node->shoe(shoe);
|
||||
link = node;
|
||||
}
|
||||
|
||||
shoe->chain(link);
|
||||
shoe->chainLength(numLinks);
|
||||
|
||||
shoe->voice(sfx_s3k5d);
|
||||
|
||||
return shoe;
|
||||
}
|
||||
|
||||
bool tick()
|
||||
{
|
||||
if (!valid())
|
||||
{
|
||||
remove();
|
||||
return false;
|
||||
}
|
||||
|
||||
move();
|
||||
move_chain();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool try_damage
|
||||
( Player* pmo,
|
||||
Mobj* inflictor)
|
||||
{
|
||||
if (pmo == follow())
|
||||
return false;
|
||||
|
||||
if (!valid())
|
||||
return false;
|
||||
|
||||
mobj_t* source = nullptr;
|
||||
|
||||
if (ownerPlayer())
|
||||
source = ownerPlayer()->mo;
|
||||
|
||||
bool hit = false;
|
||||
|
||||
if (bouncing())
|
||||
hit = P_DamageMobj(pmo, inflictor, source, 1, DMG_TUMBLE);
|
||||
else if (FixedHypot(momx, momy) > 16 * mapobjectscale)
|
||||
hit = P_DamageMobj(pmo, inflictor, source, 1, DMG_NORMAL);
|
||||
|
||||
if (hit && ownerPlayer() && follow()->player && pmo->player)
|
||||
{
|
||||
// Give Amps to both the originator of the Shoe and the person dragging it.
|
||||
K_SpawnAmps(ownerPlayer(), K_PvPAmpReward(10, ownerPlayer(), pmo->player), pmo);
|
||||
K_SpawnAmps(follow()->player, K_PvPAmpReward(10, follow()->player, pmo->player), pmo);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
void animate()
|
||||
{
|
||||
INT32 speed = 20; // TODO
|
||||
tic_t t = leveltime / speed;
|
||||
INT32 th = ANGLE_180 / speed * 2;
|
||||
UINT32 ff = 0;
|
||||
|
||||
if (t % 8 > 3)
|
||||
{
|
||||
ff = FF_VERTICALFLIP;
|
||||
angle = ANGLE_180 + dir();
|
||||
}
|
||||
else
|
||||
angle = dir();
|
||||
|
||||
frame = (t % 4) | ff;
|
||||
dir(dir() + th);
|
||||
rollangle -= th;
|
||||
|
||||
old_angle = angle;
|
||||
}
|
||||
|
||||
void move()
|
||||
{
|
||||
Fixed dist = followDistance();
|
||||
angle_t a = followAngle();
|
||||
bool close = true;
|
||||
|
||||
Fixed dz = z - follow()->z;
|
||||
|
||||
if (dz < -maxDist())
|
||||
z = follow()->z - maxDist();
|
||||
else if (dz > maxDist())
|
||||
z = follow()->z + maxDist();
|
||||
|
||||
if (dist > minDist())
|
||||
{
|
||||
if (dist > maxDist())
|
||||
{
|
||||
move_origin({
|
||||
follow()->x - maxDist() * Fixed {FCOS(a)},
|
||||
follow()->y - maxDist() * Fixed {FSIN(a)},
|
||||
z,
|
||||
});
|
||||
|
||||
close = false;
|
||||
|
||||
if (P_IsObjectOnGround(this))
|
||||
{
|
||||
momz = 32 * mapobjectscale;
|
||||
bouncing(true);
|
||||
voice(sfx_s3k5f);
|
||||
P_StartQuakeFromMobj(5, 40 * scale(), 512 * scale(), this);
|
||||
}
|
||||
}
|
||||
|
||||
thrust(a, 8 * mapobjectscale);
|
||||
|
||||
Fixed maxSpeed = 32 * mapobjectscale;
|
||||
Fixed speed = FixedHypot(momx, momy);
|
||||
|
||||
if (speed > maxSpeed)
|
||||
instathrust(a, maxSpeed);
|
||||
|
||||
if (P_IsObjectOnGround(this) && leveltime % 5 == 0)
|
||||
voice(sfx_s3k6f);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!P_IsObjectOnGround(this))
|
||||
bouncing(false);
|
||||
}
|
||||
|
||||
if (close)
|
||||
friction -= 200;
|
||||
else
|
||||
friction += 500;
|
||||
|
||||
if (dist > maxDist())
|
||||
animate();
|
||||
else
|
||||
{
|
||||
frame = 1;
|
||||
rollangle = 0;
|
||||
angle = a;
|
||||
}
|
||||
|
||||
follow()->player->stonedrag = dist > minDist();
|
||||
|
||||
sprzoff(30 * scale());
|
||||
}
|
||||
|
||||
void move_chain()
|
||||
{
|
||||
const Fixed shoeSpriteRadius = 48 * scale();
|
||||
const Fixed chainSpriteRadius = 26 * chain()->scale();
|
||||
|
||||
Fixed fd = std::max<Fixed>(followDistance() - shoeSpriteRadius - follow()->radius - chainSpriteRadius * 2, 0);
|
||||
Fixed fdz = follow()->z - z;
|
||||
Fixed nd = fd / std::max(chainLength(), 1);
|
||||
Fixed ndz = fdz / std::max(chainLength(), 1);
|
||||
|
||||
Vec2<Fixed> v = followVector();
|
||||
Vec2<Fixed> p = pos2d() + v * nd / 2 + v * Fixed {shoeSpriteRadius + chainSpriteRadius};
|
||||
Fixed pz = z + ndz / 2;
|
||||
|
||||
Chain* node = chain();
|
||||
|
||||
while (Mobj::valid(node))
|
||||
{
|
||||
node->move_origin({p, pz});
|
||||
node->sprzoff(sprzoff());
|
||||
|
||||
// Let chain flicker like shoe does
|
||||
node->renderflags = renderflags;
|
||||
|
||||
p += v * nd;
|
||||
pz += ndz;
|
||||
|
||||
node = node->next();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
bool Chain::valid() const
|
||||
{
|
||||
return Mobj::valid(shoe());
|
||||
}
|
||||
|
||||
bool Chain::try_damage(Player* pmo)
|
||||
{
|
||||
if (!Mobj::valid(shoe()))
|
||||
return false;
|
||||
|
||||
return shoe()->try_damage(pmo, this);
|
||||
}
|
||||
|
||||
}; // namespace
|
||||
|
||||
mobj_t *Obj_SpawnStoneShoe(INT32 owner, mobj_t *victim)
|
||||
{
|
||||
return Shoe::spawn(owner, static_cast<Player*>(victim));
|
||||
}
|
||||
|
||||
boolean Obj_TickStoneShoe(mobj_t *shoe)
|
||||
{
|
||||
return static_cast<Shoe*>(shoe)->tick();
|
||||
}
|
||||
|
||||
boolean Obj_TickStoneShoeChain(mobj_t *chain)
|
||||
{
|
||||
return static_cast<Chain*>(chain)->tick();
|
||||
}
|
||||
|
||||
player_t *Obj_StoneShoeOwnerPlayer(mobj_t *shoe)
|
||||
{
|
||||
return static_cast<Shoe*>(shoe)->ownerPlayer();
|
||||
}
|
||||
|
||||
void Obj_CollideStoneShoe(mobj_t *mover, mobj_t *mobj)
|
||||
{
|
||||
switch (mobj->type)
|
||||
{
|
||||
case MT_STONESHOE: {
|
||||
Shoe* shoe = static_cast<Shoe*>(mobj);
|
||||
|
||||
if (!shoe->try_damage(static_cast<Player*>(mover), shoe))
|
||||
K_KartSolidBounce(mover, shoe);
|
||||
break;
|
||||
}
|
||||
|
||||
case MT_STONESHOE_CHAIN:
|
||||
static_cast<Chain*>(mobj)->try_damage(static_cast<Player*>(mover));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -425,14 +425,41 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
if (special->scale < special->destscale/2)
|
||||
return;
|
||||
|
||||
if (!P_CanPickupItem(player, PICKUP_PAPERITEM) || (player->itemamount && player->itemtype != special->threshold))
|
||||
if (!P_CanPickupItem(player, PICKUP_PAPERITEM))
|
||||
return;
|
||||
|
||||
player->itemtype = special->threshold;
|
||||
if ((UINT16)(player->itemamount) + special->movecount > 255)
|
||||
player->itemamount = 255;
|
||||
if (special->threshold == KDROP_STONESHOETRAP)
|
||||
{
|
||||
if (K_TryPickMeUp(special, toucher, false))
|
||||
return;
|
||||
|
||||
if (!P_MobjWasRemoved(player->stoneShoe))
|
||||
{
|
||||
player->pflags |= PF_CASTSHADOW;
|
||||
return;
|
||||
}
|
||||
|
||||
P_SetTarget(&player->stoneShoe, Obj_SpawnStoneShoe(special->extravalue2, toucher));
|
||||
K_AddHitLag(toucher, 8, false);
|
||||
|
||||
player_t *owner = Obj_StoneShoeOwnerPlayer(special);
|
||||
if (owner)
|
||||
{
|
||||
K_SpawnAmps(player, K_PvPAmpReward(20, owner, player), toucher);
|
||||
K_SpawnAmps(owner, K_PvPAmpReward(20, owner, player), toucher);
|
||||
}
|
||||
}
|
||||
else
|
||||
player->itemamount += special->movecount;
|
||||
{
|
||||
if (player->itemamount && player->itemtype != special->threshold)
|
||||
return;
|
||||
|
||||
player->itemtype = special->threshold;
|
||||
if ((UINT16)(player->itemamount) + special->movecount > 255)
|
||||
player->itemamount = 255;
|
||||
else
|
||||
player->itemamount += special->movecount;
|
||||
}
|
||||
}
|
||||
|
||||
S_StartSound(special, special->info->deathsound);
|
||||
|
|
@ -1087,6 +1114,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
Obj_PulleyHookTouch(special, toucher);
|
||||
return;
|
||||
|
||||
case MT_STONESHOE_CHAIN:
|
||||
Obj_CollideStoneShoe(toucher, special);
|
||||
return;
|
||||
|
||||
default: // SOC or script pickup
|
||||
P_SetTarget(&special->target, toucher);
|
||||
break;
|
||||
|
|
@ -3202,7 +3233,9 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
|
||||
if (source && source != player->mo && source->player)
|
||||
{
|
||||
K_SpawnAmps(source->player, K_PvPAmpReward((type == DMG_WHUMBLE) ? 30 : 20, source->player, player), target);
|
||||
// Stone Shoe handles amps on its own
|
||||
if (inflictor->type != MT_STONESHOE && inflictor->type != MT_STONESHOE_CHAIN)
|
||||
K_SpawnAmps(source->player, K_PvPAmpReward((type == DMG_WHUMBLE) ? 30 : 20, source->player, player), target);
|
||||
K_BotHitPenalty(player);
|
||||
|
||||
if (G_SameTeam(source->player, player))
|
||||
|
|
|
|||
11
src/p_map.c
11
src/p_map.c
|
|
@ -1531,6 +1531,17 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
|||
K_KartBouncing(g_tm.thing, thing);
|
||||
return BMIT_CONTINUE;
|
||||
}
|
||||
else if (thing->type == MT_STONESHOE)
|
||||
{
|
||||
// see if it went over / under
|
||||
if (g_tm.thing->z > thing->z + thing->height)
|
||||
return BMIT_CONTINUE; // overhead
|
||||
if (g_tm.thing->z + g_tm.thing->height < thing->z)
|
||||
return BMIT_CONTINUE; // underneath
|
||||
|
||||
Obj_CollideStoneShoe(g_tm.thing, thing);
|
||||
return BMIT_CONTINUE;
|
||||
}
|
||||
else if ((thing->flags & MF_SHOOTABLE) && K_PlayerCanPunt(g_tm.thing->player))
|
||||
{
|
||||
// see if it went over / under
|
||||
|
|
|
|||
29
src/p_mobj.c
29
src/p_mobj.c
|
|
@ -1274,6 +1274,12 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
|
|||
gravityadd *= 6;
|
||||
break;
|
||||
case MT_FLOATINGITEM: {
|
||||
if (mo->threshold == KDROP_STONESHOETRAP)
|
||||
{
|
||||
gravityadd = (5*gravityadd)/2;
|
||||
break;
|
||||
}
|
||||
|
||||
// Basically this accelerates gravity after
|
||||
// the object reached its peak vertical
|
||||
// momentum. It's a gradual acceleration up
|
||||
|
|
@ -1296,6 +1302,9 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
|
|||
if (!mo->fuse)
|
||||
gravityadd *= 2;
|
||||
break;
|
||||
case MT_STONESHOE:
|
||||
gravityadd *= 4;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -6704,6 +6713,11 @@ static void P_MobjSceneryThink(mobj_t *mobj)
|
|||
}
|
||||
break;
|
||||
}
|
||||
case MT_STONESHOE_CHAIN:
|
||||
{
|
||||
Obj_TickStoneShoeChain(mobj);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
if (mobj->fuse)
|
||||
{ // Scenery object fuse! Very basic!
|
||||
|
|
@ -10228,6 +10242,9 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
break;
|
||||
}
|
||||
|
||||
case MT_STONESHOE:
|
||||
return Obj_TickStoneShoe(mobj);
|
||||
|
||||
default:
|
||||
// check mobj against possible water content, before movement code
|
||||
P_MobjCheckWater(mobj);
|
||||
|
|
@ -10297,6 +10314,12 @@ static boolean P_CanFlickerFuse(mobj_t *mobj)
|
|||
return true;
|
||||
}
|
||||
break;
|
||||
case MT_STONESHOE:
|
||||
if (mobj->fuse <= 3 * TICRATE)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
|
@ -11096,6 +11119,12 @@ static void P_DefaultMobjShadowScale(mobj_t *thing)
|
|||
thing->shadowscale = FRACUNIT;
|
||||
thing->whiteshadow = false;
|
||||
break;
|
||||
case MT_STONESHOE:
|
||||
thing->shadowscale = 2*FRACUNIT/3;
|
||||
break;
|
||||
case MT_STONESHOE_CHAIN:
|
||||
thing->shadowscale = FRACUNIT/5;
|
||||
break;
|
||||
default:
|
||||
if (thing->flags & (MF_ENEMY|MF_BOSS))
|
||||
thing->shadowscale = FRACUNIT;
|
||||
|
|
|
|||
|
|
@ -91,7 +91,8 @@ typedef enum
|
|||
FLICKYCONTROLLER = 0x1000,
|
||||
TRICKINDICATOR = 0x2000,
|
||||
BARRIER = 0x4000,
|
||||
BALLHOGRETICULE = 0x8000, // uh oh, we're full now...
|
||||
BALLHOGRETICULE = 0x8000,
|
||||
STONESHOE = 0x10000,
|
||||
} player_saveflags;
|
||||
|
||||
static inline void P_ArchivePlayer(savebuffer_t *save)
|
||||
|
|
@ -204,7 +205,7 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
|||
TracyCZone(__zone, true);
|
||||
|
||||
INT32 i, j;
|
||||
UINT16 flags;
|
||||
UINT32 flags;
|
||||
size_t q;
|
||||
|
||||
WRITEUINT32(save->p, ARCHIVEBLOCK_PLAYERS);
|
||||
|
|
@ -364,7 +365,10 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
|||
if (players[i].powerup.barrier)
|
||||
flags |= BARRIER;
|
||||
|
||||
WRITEUINT16(save->p, flags);
|
||||
if (players[i].stoneShoe)
|
||||
flags |= STONESHOE;
|
||||
|
||||
WRITEUINT32(save->p, flags);
|
||||
|
||||
if (flags & SKYBOXVIEW)
|
||||
WRITEUINT32(save->p, players[i].skybox.viewpoint->mobjnum);
|
||||
|
|
@ -411,6 +415,9 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
|||
if (flags & BARRIER)
|
||||
WRITEUINT32(save->p, players[i].powerup.barrier->mobjnum);
|
||||
|
||||
if (flags & STONESHOE)
|
||||
WRITEUINT32(save->p, players[i].stoneShoe->mobjnum);
|
||||
|
||||
WRITEUINT32(save->p, (UINT32)players[i].followitem);
|
||||
|
||||
WRITEUINT32(save->p, players[i].charflags);
|
||||
|
|
@ -499,6 +506,7 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
|||
WRITEFIXED(save->p, players[i].accelboost);
|
||||
WRITEFIXED(save->p, players[i].handleboost);
|
||||
WRITEANGLE(save->p, players[i].boostangle);
|
||||
WRITEFIXED(save->p, players[i].stonedrag);
|
||||
|
||||
WRITEFIXED(save->p, players[i].draftpower);
|
||||
WRITEUINT16(save->p, players[i].draftleeway);
|
||||
|
|
@ -897,7 +905,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
|
|||
TracyCZone(__zone, true);
|
||||
|
||||
INT32 i, j;
|
||||
UINT16 flags;
|
||||
UINT32 flags;
|
||||
size_t q;
|
||||
|
||||
if (READUINT32(save->p) != ARCHIVEBLOCK_PLAYERS)
|
||||
|
|
@ -1011,7 +1019,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
|
|||
|
||||
players[i].splitscreenindex = READUINT8(save->p);
|
||||
|
||||
flags = READUINT16(save->p);
|
||||
flags = READUINT32(save->p);
|
||||
|
||||
if (flags & SKYBOXVIEW)
|
||||
players[i].skybox.viewpoint = (mobj_t *)(size_t)READUINT32(save->p);
|
||||
|
|
@ -1058,6 +1066,9 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
|
|||
if (flags & BARRIER)
|
||||
players[i].powerup.barrier = (mobj_t *)(size_t)READUINT32(save->p);
|
||||
|
||||
if (flags & STONESHOE)
|
||||
players[i].stoneShoe = (mobj_t *)(size_t)READUINT32(save->p);
|
||||
|
||||
players[i].followitem = (mobjtype_t)READUINT32(save->p);
|
||||
|
||||
//SetPlayerSkinByNum(i, players[i].skin);
|
||||
|
|
@ -1147,6 +1158,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
|
|||
players[i].accelboost = READFIXED(save->p);
|
||||
players[i].handleboost = READFIXED(save->p);
|
||||
players[i].boostangle = READANGLE(save->p);
|
||||
players[i].stonedrag = READFIXED(save->p);
|
||||
|
||||
players[i].draftpower = READFIXED(save->p);
|
||||
players[i].draftleeway = READUINT16(save->p);
|
||||
|
|
@ -6218,6 +6230,11 @@ static void P_RelinkPointers(void)
|
|||
if (!RelinkMobj(&players[i].powerup.barrier))
|
||||
CONS_Debug(DBG_GAMELOGIC, "powerup.barrier not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].stoneShoe)
|
||||
{
|
||||
if (!RelinkMobj(&players[i].stoneShoe))
|
||||
CONS_Debug(DBG_GAMELOGIC, "stoneShoe not found on player %d\n", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4241,6 +4241,7 @@ void P_PlayerThink(player_t *player)
|
|||
PlayerPointerErase(player->hoverhyudoro);
|
||||
PlayerPointerErase(player->ballhogreticule);
|
||||
PlayerPointerErase(player->flickyAttacker);
|
||||
PlayerPointerErase(player->stoneShoe);
|
||||
PlayerPointerErase(player->powerup.flickyController);
|
||||
PlayerPointerErase(player->powerup.barrier);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue