mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-12-21 07:22:33 +00:00
Merge branch 'top-final'
This commit is contained in:
commit
f3668fbd7c
23 changed files with 1288 additions and 118 deletions
|
|
@ -362,7 +362,6 @@ consvar_t cv_joyscale[MAXSPLITSCREENPLAYERS] = { //Alam: Dummy for save
|
|||
#endif
|
||||
|
||||
// SRB2kart
|
||||
consvar_t cv_superring = CVAR_INIT ("superring", "On", CV_NETVAR, CV_OnOff, NULL);
|
||||
consvar_t cv_sneaker = CVAR_INIT ("sneaker", "On", CV_NETVAR, CV_OnOff, NULL);
|
||||
consvar_t cv_rocketsneaker = CVAR_INIT ("rocketsneaker", "On", CV_NETVAR, CV_OnOff, NULL);
|
||||
consvar_t cv_invincibility = CVAR_INIT ("invincibility", "On", CV_NETVAR, CV_OnOff, NULL);
|
||||
|
|
@ -372,7 +371,6 @@ consvar_t cv_orbinaut = CVAR_INIT ("orbinaut", "On", CV_NETVAR, CV_OnOff,
|
|||
consvar_t cv_jawz = CVAR_INIT ("jawz", "On", CV_NETVAR, CV_OnOff, NULL);
|
||||
consvar_t cv_mine = CVAR_INIT ("mine", "On", CV_NETVAR, CV_OnOff, NULL);
|
||||
consvar_t cv_landmine = CVAR_INIT ("landmine", "On", CV_NETVAR, CV_OnOff, NULL);
|
||||
consvar_t cv_droptarget = CVAR_INIT ("droptarget", "On", CV_NETVAR, CV_OnOff, NULL);
|
||||
consvar_t cv_ballhog = CVAR_INIT ("ballhog", "On", CV_NETVAR, CV_OnOff, NULL);
|
||||
consvar_t cv_selfpropelledbomb = CVAR_INIT ("selfpropelledbomb", "On", CV_NETVAR, CV_OnOff, NULL);
|
||||
consvar_t cv_grow = CVAR_INIT ("grow", "On", CV_NETVAR, CV_OnOff, NULL);
|
||||
|
|
@ -382,7 +380,10 @@ consvar_t cv_bubbleshield = CVAR_INIT ("bubbleshield", "On", CV_NETVAR, CV_O
|
|||
consvar_t cv_flameshield = CVAR_INIT ("flameshield", "On", CV_NETVAR, CV_OnOff, NULL);
|
||||
consvar_t cv_hyudoro = CVAR_INIT ("hyudoro", "On", CV_NETVAR, CV_OnOff, NULL);
|
||||
consvar_t cv_pogospring = CVAR_INIT ("pogospring", "On", CV_NETVAR, CV_OnOff, NULL);
|
||||
consvar_t cv_superring = CVAR_INIT ("superring", "On", CV_NETVAR, CV_OnOff, NULL);
|
||||
consvar_t cv_kitchensink = CVAR_INIT ("kitchensink", "On", CV_NETVAR, CV_OnOff, NULL);
|
||||
consvar_t cv_droptarget = CVAR_INIT ("droptarget", "On", CV_NETVAR, CV_OnOff, NULL);
|
||||
consvar_t cv_gardentop = CVAR_INIT ("gardentop", "On", CV_NETVAR, CV_OnOff, NULL);
|
||||
|
||||
consvar_t cv_dualsneaker = CVAR_INIT ("dualsneaker", "On", CV_NETVAR, CV_OnOff, NULL);
|
||||
consvar_t cv_triplesneaker = CVAR_INIT ("triplesneaker", "On", CV_NETVAR, CV_OnOff, NULL);
|
||||
|
|
|
|||
|
|
@ -72,14 +72,38 @@ extern consvar_t cv_pause;
|
|||
extern consvar_t cv_restrictskinchange, cv_allowteamchange, cv_maxplayers, cv_respawntime;
|
||||
|
||||
// SRB2kart items
|
||||
extern consvar_t cv_superring, cv_sneaker, cv_rocketsneaker, cv_invincibility, cv_banana;
|
||||
extern consvar_t cv_eggmanmonitor, cv_orbinaut, cv_jawz, cv_mine, cv_landmine, cv_droptarget;
|
||||
extern consvar_t cv_ballhog, cv_selfpropelledbomb, cv_grow, cv_shrink;
|
||||
extern consvar_t cv_lightningshield, cv_bubbleshield, cv_flameshield;
|
||||
extern consvar_t cv_hyudoro, cv_pogospring, cv_kitchensink;
|
||||
extern consvar_t
|
||||
cv_sneaker,
|
||||
cv_rocketsneaker,
|
||||
cv_invincibility,
|
||||
cv_banana,
|
||||
cv_eggmanmonitor,
|
||||
cv_orbinaut,
|
||||
cv_jawz,
|
||||
cv_mine,
|
||||
cv_landmine,
|
||||
cv_ballhog,
|
||||
cv_selfpropelledbomb,
|
||||
cv_grow,
|
||||
cv_shrink,
|
||||
cv_lightningshield,
|
||||
cv_bubbleshield,
|
||||
cv_flameshield,
|
||||
cv_hyudoro,
|
||||
cv_pogospring,
|
||||
cv_superring,
|
||||
cv_kitchensink,
|
||||
cv_droptarget,
|
||||
cv_gardentop;
|
||||
|
||||
extern consvar_t cv_dualsneaker, cv_triplesneaker, cv_triplebanana, cv_decabanana;
|
||||
extern consvar_t cv_tripleorbinaut, cv_quadorbinaut, cv_dualjawz;
|
||||
extern consvar_t
|
||||
cv_dualsneaker,
|
||||
cv_triplesneaker,
|
||||
cv_triplebanana,
|
||||
cv_decabanana,
|
||||
cv_tripleorbinaut,
|
||||
cv_quadorbinaut,
|
||||
cv_dualjawz;
|
||||
|
||||
extern consvar_t cv_kartminimap;
|
||||
extern consvar_t cv_kartcheck;
|
||||
|
|
|
|||
|
|
@ -159,7 +159,8 @@ Run this macro, then #undef FOREACH afterward
|
|||
FOREACH (POGOSPRING, 18),\
|
||||
FOREACH (SUPERRING, 19),\
|
||||
FOREACH (KITCHENSINK, 20),\
|
||||
FOREACH (DROPTARGET, 21)
|
||||
FOREACH (DROPTARGET, 21),\
|
||||
FOREACH (GARDENTOP, 22)
|
||||
|
||||
typedef enum
|
||||
{
|
||||
|
|
@ -187,6 +188,7 @@ typedef enum
|
|||
KSHIELD_LIGHTNING = 1,
|
||||
KSHIELD_BUBBLE = 2,
|
||||
KSHIELD_FLAME = 3,
|
||||
KSHIELD_TOP = 4,
|
||||
NUMKARTSHIELDS
|
||||
} kartshields_t;
|
||||
|
||||
|
|
@ -288,6 +290,8 @@ typedef enum
|
|||
#define ITEMSCALE_GROW 1
|
||||
#define ITEMSCALE_SHRINK 2
|
||||
|
||||
#define GARDENTOP_MAXGRINDTIME (45)
|
||||
|
||||
// player_t struct for all respawn variables
|
||||
typedef struct respawnvars_s
|
||||
{
|
||||
|
|
@ -598,6 +602,8 @@ typedef struct player_s
|
|||
UINT8 kickstartaccel;
|
||||
|
||||
UINT8 stairjank;
|
||||
UINT8 topdriftheld;
|
||||
UINT8 topinfirst;
|
||||
|
||||
UINT8 shrinkLaserDelay;
|
||||
|
||||
|
|
|
|||
|
|
@ -3740,6 +3740,14 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
|
|||
"S_FLAMESHIELDLINE3",
|
||||
"S_FLAMESHIELDFLASH",
|
||||
|
||||
// Marble Garden Zone Spinning Top
|
||||
"S_GARDENTOP_FLOATING",
|
||||
"S_GARDENTOP_SINKING1",
|
||||
"S_GARDENTOP_SINKING2",
|
||||
"S_GARDENTOP_SINKING3",
|
||||
"S_GARDENTOP_DEAD",
|
||||
"S_GARDENTOPSPARK",
|
||||
|
||||
// Caked-Up Booty-Sheet Ghost
|
||||
"S_HYUDORO",
|
||||
|
||||
|
|
@ -5346,6 +5354,8 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
|
|||
"MT_FLAMESHIELDUNDERLAY",
|
||||
"MT_FLAMESHIELDPAPER",
|
||||
"MT_BUBBLESHIELDTRAP",
|
||||
"MT_GARDENTOP",
|
||||
"MT_GARDENTOPSPARK",
|
||||
|
||||
"MT_HYUDORO",
|
||||
"MT_HYUDORO_CENTER",
|
||||
|
|
@ -6668,6 +6678,7 @@ struct int_const_s const INT_CONST[] = {
|
|||
{"KSHIELD_LIGHTNING",KSHIELD_LIGHTNING},
|
||||
{"KSHIELD_BUBBLE",KSHIELD_BUBBLE},
|
||||
{"KSHIELD_FLAME",KSHIELD_FLAME},
|
||||
{"KSHIELD_TOP",KSHIELD_TOP},
|
||||
{"NUMKARTSHIELDS",NUMKARTSHIELDS},
|
||||
|
||||
// kartspinoutflags_t
|
||||
|
|
|
|||
61
src/info.c
61
src/info.c
|
|
@ -4320,6 +4320,13 @@ state_t states[NUMSTATES] =
|
|||
{SPR_FLML, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_ANIMATE|14, 7, {NULL}, 6, 1, S_NULL}, // S_FLAMESHIELDLINE3
|
||||
{SPR_FLMF, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_FLAMESHIELDFLASH
|
||||
|
||||
{SPR_GTOP, FF_ANIMATE, -1, {NULL}, 5, 1, S_NULL}, // S_GARDENTOP_FLOATING
|
||||
{SPR_GTOP, 0, 1, {NULL}, 5, 1, S_GARDENTOP_SINKING2}, // S_GARDENTOP_SINKING1
|
||||
{SPR_GTOP, 2, 1, {NULL}, 5, 1, S_GARDENTOP_SINKING3}, // S_GARDENTOP_SINKING2
|
||||
{SPR_GTOP, 4, 1, {NULL}, 5, 1, S_GARDENTOP_SINKING1}, // S_GARDENTOP_SINKING3
|
||||
{SPR_GTOP, FF_ANIMATE, 100, {A_Scream}, 5, 1, S_NULL}, // S_GARDENTOP_DEAD
|
||||
{SPR_BDRF, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 5, 2, S_NULL}, // S_GARDENTOPSPARK
|
||||
|
||||
{SPR_HYUU, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_HYUDORO
|
||||
|
||||
{SPR_GRWP, FF_FULLBRIGHT|FF_ANIMATE, 13, {NULL}, 7, 1, S_NULL}, // S_GROW_PARTICLE
|
||||
|
|
@ -24065,6 +24072,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_GARDENTOP
|
||||
-1, // doomednum
|
||||
S_GARDENTOP_FLOATING, // spawnstate
|
||||
8, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
4, // reactiontime
|
||||
sfx_s3k8b, // attacksound
|
||||
S_NULL, // painstate
|
||||
0, // painchance
|
||||
sfx_None, // painsound
|
||||
S_NULL, // meleestate
|
||||
S_NULL, // missilestate
|
||||
S_GARDENTOP_DEAD, // deathstate
|
||||
S_NULL, // xdeathstate
|
||||
sfx_s3k7a, // deathsound
|
||||
40*FRACUNIT, // speed
|
||||
30*FRACUNIT, // radius
|
||||
68*FRACUNIT, // height
|
||||
-1, // display offset
|
||||
100, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOCLIPTHING|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_GARDENTOPSPARK
|
||||
-1, // doomednum
|
||||
S_GARDENTOPSPARK, // 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
|
||||
8, // speed
|
||||
8*FRACUNIT, // radius
|
||||
8*FRACUNIT, // height
|
||||
1, // display offset
|
||||
100, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_DONTENCOREMAP|MF_NOSQUISH, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_HYUDORO
|
||||
-1, // doomednum
|
||||
S_HYUDORO, // spawnstate
|
||||
|
|
|
|||
10
src/info.h
10
src/info.h
|
|
@ -4750,6 +4750,14 @@ typedef enum state
|
|||
S_FLAMESHIELDLINE3,
|
||||
S_FLAMESHIELDFLASH,
|
||||
|
||||
// Marble Garden Zone Spinning Top
|
||||
S_GARDENTOP_FLOATING,
|
||||
S_GARDENTOP_SINKING1,
|
||||
S_GARDENTOP_SINKING2,
|
||||
S_GARDENTOP_SINKING3,
|
||||
S_GARDENTOP_DEAD,
|
||||
S_GARDENTOPSPARK,
|
||||
|
||||
// Caked-Up Booty-Sheet Ghost
|
||||
S_HYUDORO,
|
||||
|
||||
|
|
@ -6392,6 +6400,8 @@ typedef enum mobj_type
|
|||
MT_FLAMESHIELDUNDERLAY,
|
||||
MT_FLAMESHIELDPAPER,
|
||||
MT_BUBBLESHIELDTRAP,
|
||||
MT_GARDENTOP,
|
||||
MT_GARDENTOPSPARK,
|
||||
|
||||
MT_HYUDORO,
|
||||
MT_HYUDORO_CENTER,
|
||||
|
|
|
|||
|
|
@ -66,17 +66,22 @@ boolean K_BananaBallhogCollide(mobj_t *t1, mobj_t *t2)
|
|||
if (t1->type == MT_BANANA && t1->health > 1)
|
||||
S_StartSound(t2, sfx_bsnipe);
|
||||
|
||||
damageitem = true;
|
||||
|
||||
if (t2->player->flamedash && t2->player->itemtype == KITEM_FLAMESHIELD)
|
||||
{
|
||||
// Melt item
|
||||
S_StartSound(t2, sfx_s3k43);
|
||||
}
|
||||
else if (K_IsRidingFloatingTop(t2->player))
|
||||
{
|
||||
// Float over silly banana
|
||||
damageitem = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
P_DamageMobj(t2, t1, t1->target, 1, DMG_NORMAL|DMG_WOMBO);
|
||||
}
|
||||
|
||||
damageitem = true;
|
||||
}
|
||||
else if (t2->type == MT_BANANA || t2->type == MT_BANANA_SHIELD
|
||||
|| t2->type == MT_ORBINAUT || t2->type == MT_ORBINAUT_SHIELD
|
||||
|
|
@ -774,11 +779,13 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2)
|
|||
// Clash instead of damage if both parties have any of these conditions
|
||||
t1Condition = (K_IsBigger(t1, t2) == true)
|
||||
|| (t1->player->invincibilitytimer > 0)
|
||||
|| (t1->player->flamedash > 0 && t1->player->itemtype == KITEM_FLAMESHIELD);
|
||||
|| (t1->player->flamedash > 0 && t1->player->itemtype == KITEM_FLAMESHIELD)
|
||||
|| (t1->player->curshield == KSHIELD_TOP && !K_IsHoldingDownTop(t1->player));
|
||||
|
||||
t2Condition = (K_IsBigger(t2, t1) == true)
|
||||
|| (t2->player->invincibilitytimer > 0)
|
||||
|| (t2->player->flamedash > 0 && t2->player->itemtype == KITEM_FLAMESHIELD);
|
||||
|| (t2->player->flamedash > 0 && t2->player->itemtype == KITEM_FLAMESHIELD)
|
||||
|| (t2->player->curshield == KSHIELD_TOP && !K_IsHoldingDownTop(t2->player));
|
||||
|
||||
if (t1Condition == true && t2Condition == true)
|
||||
{
|
||||
|
|
|
|||
29
src/k_hud.c
29
src/k_hud.c
|
|
@ -111,7 +111,7 @@ static patch_t *kp_itemtimer[2];
|
|||
static patch_t *kp_itemmulsticker[2];
|
||||
static patch_t *kp_itemx;
|
||||
|
||||
static patch_t *kp_superring[2];
|
||||
static patch_t *kp_sadface[2];
|
||||
static patch_t *kp_sneaker[2];
|
||||
static patch_t *kp_rocketsneaker[2];
|
||||
static patch_t *kp_invincibility[13];
|
||||
|
|
@ -121,7 +121,6 @@ static patch_t *kp_orbinaut[5];
|
|||
static patch_t *kp_jawz[2];
|
||||
static patch_t *kp_mine[2];
|
||||
static patch_t *kp_landmine[2];
|
||||
static patch_t *kp_droptarget[2];
|
||||
static patch_t *kp_ballhog[2];
|
||||
static patch_t *kp_selfpropelledbomb[2];
|
||||
static patch_t *kp_grow[2];
|
||||
|
|
@ -131,8 +130,10 @@ static patch_t *kp_bubbleshield[2];
|
|||
static patch_t *kp_flameshield[2];
|
||||
static patch_t *kp_hyudoro[2];
|
||||
static patch_t *kp_pogospring[2];
|
||||
static patch_t *kp_superring[2];
|
||||
static patch_t *kp_kitchensink[2];
|
||||
static patch_t *kp_sadface[2];
|
||||
static patch_t *kp_droptarget[2];
|
||||
static patch_t *kp_gardentop[2];
|
||||
|
||||
static patch_t *kp_check[6];
|
||||
|
||||
|
|
@ -390,7 +391,7 @@ void K_LoadKartHUDGraphics(void)
|
|||
HU_UpdatePatch(&kp_itemmulsticker[0], "K_ITMUL");
|
||||
HU_UpdatePatch(&kp_itemx, "K_ITX");
|
||||
|
||||
HU_UpdatePatch(&kp_superring[0], "K_ITRING");
|
||||
HU_UpdatePatch(&kp_sadface[0], "K_ITSAD");
|
||||
HU_UpdatePatch(&kp_sneaker[0], "K_ITSHOE");
|
||||
HU_UpdatePatch(&kp_rocketsneaker[0], "K_ITRSHE");
|
||||
|
||||
|
|
@ -411,7 +412,6 @@ void K_LoadKartHUDGraphics(void)
|
|||
HU_UpdatePatch(&kp_jawz[0], "K_ITJAWZ");
|
||||
HU_UpdatePatch(&kp_mine[0], "K_ITMINE");
|
||||
HU_UpdatePatch(&kp_landmine[0], "K_ITLNDM");
|
||||
HU_UpdatePatch(&kp_droptarget[0], "K_ITDTRG");
|
||||
HU_UpdatePatch(&kp_ballhog[0], "K_ITBHOG");
|
||||
HU_UpdatePatch(&kp_selfpropelledbomb[0], "K_ITSPB");
|
||||
HU_UpdatePatch(&kp_grow[0], "K_ITGROW");
|
||||
|
|
@ -421,8 +421,10 @@ void K_LoadKartHUDGraphics(void)
|
|||
HU_UpdatePatch(&kp_flameshield[0], "K_ITFLMS");
|
||||
HU_UpdatePatch(&kp_hyudoro[0], "K_ITHYUD");
|
||||
HU_UpdatePatch(&kp_pogospring[0], "K_ITPOGO");
|
||||
HU_UpdatePatch(&kp_superring[0], "K_ITRING");
|
||||
HU_UpdatePatch(&kp_kitchensink[0], "K_ITSINK");
|
||||
HU_UpdatePatch(&kp_sadface[0], "K_ITSAD");
|
||||
HU_UpdatePatch(&kp_droptarget[0], "K_ITDTRG");
|
||||
HU_UpdatePatch(&kp_gardentop[0], "K_ITGTOP");
|
||||
|
||||
sprintf(buffer, "FSMFGxxx");
|
||||
for (i = 0; i < 104; i++)
|
||||
|
|
@ -447,7 +449,7 @@ void K_LoadKartHUDGraphics(void)
|
|||
HU_UpdatePatch(&kp_itemtimer[1], "K_ISIMER");
|
||||
HU_UpdatePatch(&kp_itemmulsticker[1], "K_ISMUL");
|
||||
|
||||
HU_UpdatePatch(&kp_superring[1], "K_ISRING");
|
||||
HU_UpdatePatch(&kp_sadface[1], "K_ISSAD");
|
||||
HU_UpdatePatch(&kp_sneaker[1], "K_ISSHOE");
|
||||
HU_UpdatePatch(&kp_rocketsneaker[1], "K_ISRSHE");
|
||||
sprintf(buffer, "K_ISINVx");
|
||||
|
|
@ -462,7 +464,6 @@ void K_LoadKartHUDGraphics(void)
|
|||
HU_UpdatePatch(&kp_jawz[1], "K_ISJAWZ");
|
||||
HU_UpdatePatch(&kp_mine[1], "K_ISMINE");
|
||||
HU_UpdatePatch(&kp_landmine[1], "K_ISLNDM");
|
||||
HU_UpdatePatch(&kp_droptarget[1], "K_ISDTRG");
|
||||
HU_UpdatePatch(&kp_ballhog[1], "K_ISBHOG");
|
||||
HU_UpdatePatch(&kp_selfpropelledbomb[1], "K_ISSPB");
|
||||
HU_UpdatePatch(&kp_grow[1], "K_ISGROW");
|
||||
|
|
@ -472,8 +473,10 @@ void K_LoadKartHUDGraphics(void)
|
|||
HU_UpdatePatch(&kp_flameshield[1], "K_ISFLMS");
|
||||
HU_UpdatePatch(&kp_hyudoro[1], "K_ISHYUD");
|
||||
HU_UpdatePatch(&kp_pogospring[1], "K_ISPOGO");
|
||||
HU_UpdatePatch(&kp_superring[1], "K_ISRING");
|
||||
HU_UpdatePatch(&kp_kitchensink[1], "K_ISSINK");
|
||||
HU_UpdatePatch(&kp_sadface[1], "K_ISSAD");
|
||||
HU_UpdatePatch(&kp_droptarget[1], "K_ISDTRG");
|
||||
HU_UpdatePatch(&kp_gardentop[1], "K_ISGTOP");
|
||||
|
||||
sprintf(buffer, "FSMFSxxx");
|
||||
for (i = 0; i < 104; i++)
|
||||
|
|
@ -662,8 +665,6 @@ const char *K_GetItemPatch(UINT8 item, boolean tiny)
|
|||
return (tiny ? "K_ISMINE" : "K_ITMINE");
|
||||
case KITEM_LANDMINE:
|
||||
return (tiny ? "K_ISLNDM" : "K_ITLNDM");
|
||||
case KITEM_DROPTARGET:
|
||||
return (tiny ? "K_ISDTRG" : "K_ITDTRG");
|
||||
case KITEM_BALLHOG:
|
||||
return (tiny ? "K_ISBHOG" : "K_ITBHOG");
|
||||
case KITEM_SPB:
|
||||
|
|
@ -686,6 +687,10 @@ const char *K_GetItemPatch(UINT8 item, boolean tiny)
|
|||
return (tiny ? "K_ISRING" : "K_ITRING");
|
||||
case KITEM_KITCHENSINK:
|
||||
return (tiny ? "K_ISSINK" : "K_ITSINK");
|
||||
case KITEM_DROPTARGET:
|
||||
return (tiny ? "K_ISDTRG" : "K_ITDTRG");
|
||||
case KITEM_GARDENTOP:
|
||||
return (tiny ? "K_ISGTOP" : "K_ITGTOP");
|
||||
case KRITEM_TRIPLEORBINAUT:
|
||||
return (tiny ? "K_ISORBN" : "K_ITORB3");
|
||||
case KRITEM_QUADORBINAUT:
|
||||
|
|
@ -721,6 +726,7 @@ static patch_t *K_GetCachedItemPatch(INT32 item, UINT8 offset)
|
|||
kp_superring,
|
||||
kp_kitchensink,
|
||||
kp_droptarget,
|
||||
kp_gardentop,
|
||||
};
|
||||
|
||||
if (item == KITEM_SAD || (item > KITEM_NONE && item < NUMKARTITEMS))
|
||||
|
|
@ -4456,6 +4462,7 @@ static void K_drawDistributionDebugger(void)
|
|||
kp_superring[1],
|
||||
kp_kitchensink[1],
|
||||
kp_droptarget[1],
|
||||
kp_gardentop[1],
|
||||
|
||||
kp_sneaker[1],
|
||||
kp_sneaker[1],
|
||||
|
|
|
|||
461
src/k_kart.c
461
src/k_kart.c
|
|
@ -218,7 +218,6 @@ void K_RegisterKartStuff(void)
|
|||
CV_RegisterVar(&cv_jawz);
|
||||
CV_RegisterVar(&cv_mine);
|
||||
CV_RegisterVar(&cv_landmine);
|
||||
CV_RegisterVar(&cv_droptarget);
|
||||
CV_RegisterVar(&cv_ballhog);
|
||||
CV_RegisterVar(&cv_selfpropelledbomb);
|
||||
CV_RegisterVar(&cv_grow);
|
||||
|
|
@ -230,6 +229,8 @@ void K_RegisterKartStuff(void)
|
|||
CV_RegisterVar(&cv_pogospring);
|
||||
CV_RegisterVar(&cv_superring);
|
||||
CV_RegisterVar(&cv_kitchensink);
|
||||
CV_RegisterVar(&cv_droptarget);
|
||||
CV_RegisterVar(&cv_gardentop);
|
||||
|
||||
CV_RegisterVar(&cv_dualsneaker);
|
||||
CV_RegisterVar(&cv_triplesneaker);
|
||||
|
|
@ -336,6 +337,7 @@ consvar_t *KartItemCVars[NUMKARTRESULTS-1] =
|
|||
&cv_superring,
|
||||
&cv_kitchensink,
|
||||
&cv_droptarget,
|
||||
&cv_gardentop,
|
||||
&cv_dualsneaker,
|
||||
&cv_triplesneaker,
|
||||
&cv_triplebanana,
|
||||
|
|
@ -350,68 +352,70 @@ consvar_t *KartItemCVars[NUMKARTRESULTS-1] =
|
|||
// Less ugly 2D arrays
|
||||
static UINT8 K_KartItemOddsRace[NUMKARTRESULTS-1][8] =
|
||||
{
|
||||
//P-Odds 0 1 2 3 4 5 6 7
|
||||
/*Sneaker*/ { 0, 0, 2, 4, 6, 0, 0, 0 }, // Sneaker
|
||||
/*Rocket Sneaker*/ { 0, 0, 0, 0, 0, 2, 4, 6 }, // Rocket Sneaker
|
||||
/*Invincibility*/ { 0, 0, 0, 0, 3, 4, 5, 7 }, // Invincibility
|
||||
/*Banana*/ { 2, 3, 1, 0, 0, 0, 0, 0 }, // Banana
|
||||
/*Eggman Monitor*/ { 1, 2, 0, 0, 0, 0, 0, 0 }, // Eggman Monitor
|
||||
/*Orbinaut*/ { 5, 5, 2, 2, 0, 0, 0, 0 }, // Orbinaut
|
||||
/*Jawz*/ { 0, 4, 2, 1, 0, 0, 0, 0 }, // Jawz
|
||||
/*Mine*/ { 0, 3, 3, 1, 0, 0, 0, 0 }, // Mine
|
||||
/*Land Mine*/ { 3, 0, 0, 0, 0, 0, 0, 0 }, // Land Mine
|
||||
/*Ballhog*/ { 0, 0, 2, 2, 0, 0, 0, 0 }, // Ballhog
|
||||
/*Self-Propelled Bomb*/ { 0, 0, 0, 0, 0, 0, 0, 0 }, // Self-Propelled Bomb
|
||||
/*Grow*/ { 0, 0, 0, 1, 2, 3, 0, 0 }, // Grow
|
||||
/*Shrink*/ { 0, 0, 0, 0, 0, 1, 3, 2 }, // Shrink
|
||||
/*Lightning Shield*/ { 1, 0, 0, 0, 0, 0, 0, 0 }, // Lightning Shield
|
||||
/*Bubble Shield*/ { 0, 1, 2, 1, 0, 0, 0, 0 }, // Bubble Shield
|
||||
/*Flame Shield*/ { 0, 0, 0, 0, 0, 1, 3, 5 }, // Flame Shield
|
||||
/*Hyudoro*/ { 3, 0, 0, 0, 0, 0, 0, 0 }, // Hyudoro
|
||||
/*Pogo Spring*/ { 0, 0, 0, 0, 0, 0, 0, 0 }, // Pogo Spring
|
||||
/*Super Ring*/ { 2, 1, 1, 0, 0, 0, 0, 0 }, // Super Ring
|
||||
/*Kitchen Sink*/ { 0, 0, 0, 0, 0, 0, 0, 0 }, // Kitchen Sink
|
||||
/*Drop Target*/ { 3, 0, 0, 0, 0, 0, 0, 0 }, // Drop Target
|
||||
/*Sneaker x2*/ { 0, 0, 2, 2, 2, 0, 0, 0 }, // Sneaker x2
|
||||
/*Sneaker x3*/ { 0, 0, 0, 1, 6, 9, 5, 0 }, // Sneaker x3
|
||||
/*Banana x3*/ { 0, 1, 1, 0, 0, 0, 0, 0 }, // Banana x3
|
||||
/*Banana x10*/ { 0, 0, 0, 1, 0, 0, 0, 0 }, // Banana x10
|
||||
/*Orbinaut x3*/ { 0, 0, 1, 0, 0, 0, 0, 0 }, // Orbinaut x3
|
||||
/*Orbinaut x4*/ { 0, 0, 0, 2, 0, 0, 0, 0 }, // Orbinaut x4
|
||||
/*Jawz x2*/ { 0, 0, 1, 2, 1, 0, 0, 0 } // Jawz x2
|
||||
//B C D E F G H I
|
||||
{ 0, 0, 2, 3, 4, 0, 0, 0 }, // Sneaker
|
||||
{ 0, 0, 0, 0, 0, 3, 4, 5 }, // Rocket Sneaker
|
||||
{ 0, 0, 0, 0, 2, 5, 5, 7 }, // Invincibility
|
||||
{ 2, 3, 1, 0, 0, 0, 0, 0 }, // Banana
|
||||
{ 1, 2, 0, 0, 0, 0, 0, 0 }, // Eggman Monitor
|
||||
{ 5, 5, 2, 2, 0, 0, 0, 0 }, // Orbinaut
|
||||
{ 0, 4, 2, 1, 0, 0, 0, 0 }, // Jawz
|
||||
{ 0, 3, 3, 1, 0, 0, 0, 0 }, // Mine
|
||||
{ 3, 0, 0, 0, 0, 0, 0, 0 }, // Land Mine
|
||||
{ 0, 0, 2, 2, 0, 0, 0, 0 }, // Ballhog
|
||||
{ 0, 0, 0, 0, 0, 2, 4, 0 }, // Self-Propelled Bomb
|
||||
{ 0, 0, 0, 0, 2, 5, 0, 0 }, // Grow
|
||||
{ 0, 0, 0, 0, 0, 2, 4, 2 }, // Shrink
|
||||
{ 1, 0, 0, 0, 0, 0, 0, 0 }, // Lightning Shield
|
||||
{ 0, 1, 2, 1, 0, 0, 0, 0 }, // Bubble Shield
|
||||
{ 0, 0, 0, 0, 0, 1, 3, 5 }, // Flame Shield
|
||||
{ 3, 0, 0, 0, 0, 0, 0, 0 }, // Hyudoro
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0 }, // Pogo Spring
|
||||
{ 2, 1, 1, 0, 0, 0, 0, 0 }, // Super Ring
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0 }, // Kitchen Sink
|
||||
{ 3, 0, 0, 0, 0, 0, 0, 0 }, // Drop Target
|
||||
{ 0, 0, 0, 3, 5, 0, 0, 0 }, // Garden Top
|
||||
{ 0, 0, 2, 2, 2, 0, 0, 0 }, // Sneaker x2
|
||||
{ 0, 0, 0, 0, 4, 4, 4, 0 }, // Sneaker x3
|
||||
{ 0, 1, 1, 0, 0, 0, 0, 0 }, // Banana x3
|
||||
{ 0, 0, 0, 1, 0, 0, 0, 0 }, // Banana x10
|
||||
{ 0, 0, 1, 0, 0, 0, 0, 0 }, // Orbinaut x3
|
||||
{ 0, 0, 0, 2, 0, 0, 0, 0 }, // Orbinaut x4
|
||||
{ 0, 0, 1, 2, 1, 0, 0, 0 } // Jawz x2
|
||||
};
|
||||
|
||||
static UINT8 K_KartItemOddsBattle[NUMKARTRESULTS][2] =
|
||||
{
|
||||
//P-Odds 0 1
|
||||
/*Sneaker*/ { 2, 1 }, // Sneaker
|
||||
/*Rocket Sneaker*/ { 0, 0 }, // Rocket Sneaker
|
||||
/*Invincibility*/ { 4, 1 }, // Invincibility
|
||||
/*Banana*/ { 0, 0 }, // Banana
|
||||
/*Eggman Monitor*/ { 1, 0 }, // Eggman Monitor
|
||||
/*Orbinaut*/ { 8, 0 }, // Orbinaut
|
||||
/*Jawz*/ { 8, 1 }, // Jawz
|
||||
/*Mine*/ { 6, 1 }, // Mine
|
||||
/*Land Mine*/ { 2, 0 }, // Land Mine
|
||||
/*Ballhog*/ { 2, 1 }, // Ballhog
|
||||
/*Self-Propelled Bomb*/ { 0, 0 }, // Self-Propelled Bomb
|
||||
/*Grow*/ { 2, 1 }, // Grow
|
||||
/*Shrink*/ { 0, 0 }, // Shrink
|
||||
/*Lightning Shield*/ { 4, 0 }, // Lightning Shield
|
||||
/*Bubble Shield*/ { 1, 0 }, // Bubble Shield
|
||||
/*Flame Shield*/ { 1, 0 }, // Flame Shield
|
||||
/*Hyudoro*/ { 2, 0 }, // Hyudoro
|
||||
/*Pogo Spring*/ { 3, 0 }, // Pogo Spring
|
||||
/*Super Ring*/ { 0, 0 }, // Super Ring
|
||||
/*Kitchen Sink*/ { 0, 0 }, // Kitchen Sink
|
||||
/*Drop Target*/ { 2, 0 }, // Drop Target
|
||||
/*Sneaker x2*/ { 0, 0 }, // Sneaker x2
|
||||
/*Sneaker x3*/ { 0, 1 }, // Sneaker x3
|
||||
/*Banana x3*/ { 0, 0 }, // Banana x3
|
||||
/*Banana x10*/ { 1, 1 }, // Banana x10
|
||||
/*Orbinaut x3*/ { 2, 0 }, // Orbinaut x3
|
||||
/*Orbinaut x4*/ { 1, 1 }, // Orbinaut x4
|
||||
/*Jawz x2*/ { 5, 1 } // Jawz x2
|
||||
//K L
|
||||
{ 2, 1 }, // Sneaker
|
||||
{ 0, 0 }, // Rocket Sneaker
|
||||
{ 4, 1 }, // Invincibility
|
||||
{ 0, 0 }, // Banana
|
||||
{ 1, 0 }, // Eggman Monitor
|
||||
{ 8, 0 }, // Orbinaut
|
||||
{ 8, 1 }, // Jawz
|
||||
{ 6, 1 }, // Mine
|
||||
{ 2, 0 }, // Land Mine
|
||||
{ 2, 1 }, // Ballhog
|
||||
{ 0, 0 }, // Self-Propelled Bomb
|
||||
{ 2, 1 }, // Grow
|
||||
{ 0, 0 }, // Shrink
|
||||
{ 4, 0 }, // Lightning Shield
|
||||
{ 1, 0 }, // Bubble Shield
|
||||
{ 1, 0 }, // Flame Shield
|
||||
{ 2, 0 }, // Hyudoro
|
||||
{ 3, 0 }, // Pogo Spring
|
||||
{ 0, 0 }, // Super Ring
|
||||
{ 0, 0 }, // Kitchen Sink
|
||||
{ 2, 0 }, // Drop Target
|
||||
{ 4, 0 }, // Garden Top
|
||||
{ 0, 0 }, // Sneaker x2
|
||||
{ 0, 1 }, // Sneaker x3
|
||||
{ 0, 0 }, // Banana x3
|
||||
{ 1, 1 }, // Banana x10
|
||||
{ 2, 0 }, // Orbinaut x3
|
||||
{ 1, 1 }, // Orbinaut x4
|
||||
{ 5, 1 } // Jawz x2
|
||||
};
|
||||
|
||||
#define DISTVAR (2048) // Magic number distance for use with item roulette tiers
|
||||
|
|
@ -442,6 +446,7 @@ INT32 K_GetShieldFromItem(INT32 item)
|
|||
case KITEM_LIGHTNINGSHIELD: return KSHIELD_LIGHTNING;
|
||||
case KITEM_BUBBLESHIELD: return KSHIELD_BUBBLE;
|
||||
case KITEM_FLAMESHIELD: return KSHIELD_FLAME;
|
||||
case KITEM_GARDENTOP: return KSHIELD_TOP;
|
||||
default: return KSHIELD_NONE;
|
||||
}
|
||||
}
|
||||
|
|
@ -715,10 +720,20 @@ INT32 K_KartGetItemOdds(
|
|||
if (players[i].exiting)
|
||||
pexiting++;
|
||||
|
||||
if (shieldtype != KSHIELD_NONE && shieldtype == K_GetShieldFromItem(players[i].itemtype))
|
||||
switch (shieldtype)
|
||||
{
|
||||
// Don't allow more than one of each shield type at a time
|
||||
return 0;
|
||||
case KSHIELD_NONE:
|
||||
/* Marble Garden Top is not REALLY
|
||||
a Sonic 3 shield */
|
||||
case KSHIELD_TOP:
|
||||
break;
|
||||
|
||||
default:
|
||||
if (shieldtype == K_GetShieldFromItem(players[i].itemtype))
|
||||
{
|
||||
// Don't allow more than one of each shield type at a time
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (players[i].position == 1)
|
||||
|
|
@ -1359,7 +1374,13 @@ static fixed_t K_PlayerWeight(mobj_t *mobj, mobj_t *against)
|
|||
if (!mobj->player)
|
||||
return weight;
|
||||
|
||||
if (against && !P_MobjWasRemoved(against) && against->player
|
||||
if (against && (against->type == MT_GARDENTOP || (against->player && against->player->curshield == KSHIELD_TOP)))
|
||||
{
|
||||
/* Players bumping into a Top get zero weight -- the
|
||||
Top rider is immovable. */
|
||||
weight = 0;
|
||||
}
|
||||
else if (against && !P_MobjWasRemoved(against) && against->player
|
||||
&& ((!P_PlayerInPain(against->player) && P_PlayerInPain(mobj->player)) // You're hurt
|
||||
|| (against->player->itemtype == KITEM_BUBBLESHIELD && mobj->player->itemtype != KITEM_BUBBLESHIELD))) // They have a Bubble Shield
|
||||
{
|
||||
|
|
@ -1947,6 +1968,18 @@ static void K_DrawDraftCombiring(player_t *player, player_t *victim, fixed_t cur
|
|||
#undef CHAOTIXBANDLEN
|
||||
}
|
||||
|
||||
static boolean K_HasInfiniteTether(player_t *player)
|
||||
{
|
||||
switch (player->curshield)
|
||||
{
|
||||
case KSHIELD_LIGHTNING:
|
||||
case KSHIELD_TOP:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** \brief Updates the player's drafting values once per frame
|
||||
|
||||
\param player player object passed from K_KartPlayerThink
|
||||
|
|
@ -1961,7 +1994,7 @@ static void K_UpdateDraft(player_t *player)
|
|||
UINT8 leniency;
|
||||
UINT8 i;
|
||||
|
||||
if (player->itemtype == KITEM_LIGHTNINGSHIELD)
|
||||
if (K_HasInfiniteTether(player))
|
||||
{
|
||||
// Lightning Shield gets infinite draft distance as its (other) passive effect.
|
||||
draftdistance = 0;
|
||||
|
|
@ -2399,7 +2432,7 @@ void K_SpawnDriftBoostClipSpark(mobj_t *clip)
|
|||
spark->momy = clip->momx/2;
|
||||
}
|
||||
|
||||
void K_SpawnNormalSpeedLines(player_t *player)
|
||||
static void K_SpawnGenericSpeedLines(player_t *player, boolean top)
|
||||
{
|
||||
mobj_t *fast = P_SpawnMobj(player->mo->x + (P_RandomRange(PR_DECORATION,-36,36) * player->mo->scale),
|
||||
player->mo->y + (P_RandomRange(PR_DECORATION,-36,36) * player->mo->scale),
|
||||
|
|
@ -2407,20 +2440,40 @@ void K_SpawnNormalSpeedLines(player_t *player)
|
|||
MT_FASTLINE);
|
||||
|
||||
P_SetTarget(&fast->target, player->mo);
|
||||
P_InitAngle(fast, K_MomentumAngle(player->mo));
|
||||
fast->momx = 3*player->mo->momx/4;
|
||||
fast->momy = 3*player->mo->momy/4;
|
||||
fast->momz = 3*P_GetMobjZMovement(player->mo)/4;
|
||||
|
||||
K_MatchGenericExtraFlags(fast, player->mo);
|
||||
fast->z += player->mo->sprzoff;
|
||||
|
||||
if (player->tripwireLeniency)
|
||||
if (top)
|
||||
{
|
||||
fast->destscale = fast->destscale * 2;
|
||||
P_SetScale(fast, 3*fast->scale/2);
|
||||
P_InitAngle(fast, player->mo->angle);
|
||||
P_SetScale(fast, (fast->destscale =
|
||||
3 * fast->destscale / 2));
|
||||
|
||||
fast->spritexscale = 3*FRACUNIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
P_InitAngle(fast, K_MomentumAngle(player->mo));
|
||||
|
||||
if (player->tripwireLeniency)
|
||||
{
|
||||
fast->destscale = fast->destscale * 2;
|
||||
P_SetScale(fast, 3*fast->scale/2);
|
||||
}
|
||||
}
|
||||
|
||||
if (player->eggmanexplode)
|
||||
K_MatchGenericExtraFlags(fast, player->mo);
|
||||
|
||||
if (top)
|
||||
{
|
||||
fast->color = SKINCOLOR_SUNSLAM;
|
||||
fast->colorized = true;
|
||||
fast->renderflags |= RF_ADD;
|
||||
}
|
||||
else if (player->eggmanexplode)
|
||||
{
|
||||
// Make it red when you have the eggman speed boost
|
||||
fast->color = SKINCOLOR_RED;
|
||||
|
|
@ -2448,6 +2501,16 @@ void K_SpawnNormalSpeedLines(player_t *player)
|
|||
}
|
||||
}
|
||||
|
||||
void K_SpawnNormalSpeedLines(player_t *player)
|
||||
{
|
||||
K_SpawnGenericSpeedLines(player, false);
|
||||
}
|
||||
|
||||
void K_SpawnGardenTopSpeedLines(player_t *player)
|
||||
{
|
||||
K_SpawnGenericSpeedLines(player, true);
|
||||
}
|
||||
|
||||
void K_SpawnInvincibilitySpeedLines(mobj_t *mo)
|
||||
{
|
||||
mobj_t *fast = P_SpawnMobjFromMobj(mo,
|
||||
|
|
@ -2546,14 +2609,21 @@ static void K_SpawnGrowShrinkParticles(mobj_t *mo, INT32 timer)
|
|||
|
||||
void K_SpawnBumpEffect(mobj_t *mo)
|
||||
{
|
||||
mobj_t *top = mo->player ? K_GetGardenTop(mo->player) : NULL;
|
||||
|
||||
mobj_t *fx = P_SpawnMobj(mo->x, mo->y, mo->z, MT_BUMP);
|
||||
|
||||
if (mo->eflags & MFE_VERTICALFLIP)
|
||||
fx->eflags |= MFE_VERTICALFLIP;
|
||||
else
|
||||
fx->eflags &= ~MFE_VERTICALFLIP;
|
||||
|
||||
fx->scale = mo->scale;
|
||||
|
||||
S_StartSound(mo, sfx_s3k49);
|
||||
if (top)
|
||||
S_StartSound(mo, top->info->attacksound);
|
||||
else
|
||||
S_StartSound(mo, sfx_s3k49);
|
||||
}
|
||||
|
||||
static SINT8 K_GlanceAtPlayers(player_t *glancePlayer)
|
||||
|
|
@ -2708,6 +2778,10 @@ void K_KartMoveAnimation(player_t *player)
|
|||
drift = intsign(player->aizdriftturn);
|
||||
turndir = 0;
|
||||
}
|
||||
else if (player->curshield == KSHIELD_TOP)
|
||||
{
|
||||
drift = -turndir;
|
||||
}
|
||||
else if (turndir == 0 && drift == 0)
|
||||
{
|
||||
// Only try glancing if you're driving straight.
|
||||
|
|
@ -3211,6 +3285,8 @@ boolean K_ApplyOffroad(player_t *player)
|
|||
{
|
||||
if (player->invincibilitytimer || player->hyudorotimer || player->sneakertimer)
|
||||
return false;
|
||||
if (K_IsRidingFloatingTop(player))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -3218,6 +3294,8 @@ boolean K_SlopeResistance(player_t *player)
|
|||
{
|
||||
if (player->invincibilitytimer || player->sneakertimer || player->tiregrease || player->flamedash)
|
||||
return true;
|
||||
if (player->curshield == KSHIELD_TOP)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -3281,6 +3359,11 @@ boolean K_WaterRun(mobj_t *mobj)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (mobj->player->curshield == KSHIELD_TOP)
|
||||
{
|
||||
return K_IsHoldingDownTop(mobj->player) == false;
|
||||
}
|
||||
|
||||
if (mobj->player->invincibilitytimer
|
||||
|| mobj->player->sneakertimer
|
||||
|| mobj->player->tiregrease
|
||||
|
|
@ -3311,6 +3394,16 @@ boolean K_WaterSkip(mobj_t *mobj)
|
|||
switch (mobj->type)
|
||||
{
|
||||
case MT_PLAYER:
|
||||
{
|
||||
if (mobj->player != NULL && mobj->player->curshield == KSHIELD_TOP)
|
||||
{
|
||||
// Don't allow
|
||||
return false;
|
||||
}
|
||||
// Allow
|
||||
break;
|
||||
}
|
||||
|
||||
case MT_ORBINAUT:
|
||||
case MT_JAWZ:
|
||||
case MT_BALLHOG:
|
||||
|
|
@ -3486,6 +3579,46 @@ void K_SpawnWaterRunParticles(mobj_t *mobj)
|
|||
}
|
||||
}
|
||||
|
||||
boolean K_IsRidingFloatingTop(player_t *player)
|
||||
{
|
||||
if (player->curshield != KSHIELD_TOP)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return !Obj_GardenTopPlayerIsGrinding(player);
|
||||
}
|
||||
|
||||
boolean K_IsHoldingDownTop(player_t *player)
|
||||
{
|
||||
if (player->curshield != KSHIELD_TOP)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((K_GetKartButtons(player) & BT_DRIFT) != BT_DRIFT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
mobj_t *K_GetGardenTop(player_t *player)
|
||||
{
|
||||
if (player->curshield != KSHIELD_TOP)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (player->mo == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return player->mo->hnext;
|
||||
}
|
||||
|
||||
static fixed_t K_FlameShieldDashVar(INT32 val)
|
||||
{
|
||||
// 1 second = 75% + 50% top speed
|
||||
|
|
@ -3648,7 +3781,7 @@ static void K_GetKartBoostPower(player_t *player)
|
|||
draftspeed *= 2;
|
||||
}
|
||||
|
||||
if (player->itemtype == KITEM_LIGHTNINGSHIELD)
|
||||
if (K_HasInfiniteTether(player))
|
||||
{
|
||||
// infinite tether
|
||||
draftspeed *= 2;
|
||||
|
|
@ -3770,6 +3903,10 @@ fixed_t K_GetKartAccel(player_t *player)
|
|||
if (gametype == GT_BATTLE && player->bumpers <= 0)
|
||||
k_accel *= 2;
|
||||
|
||||
// Marble Garden Top gets 800% accel
|
||||
if (player->curshield == KSHIELD_TOP)
|
||||
k_accel *= 8;
|
||||
|
||||
return FixedMul(k_accel, (FRACUNIT + player->accelboost) / 4);
|
||||
}
|
||||
|
||||
|
|
@ -3859,17 +3996,35 @@ SINT8 K_GetForwardMove(player_t *player)
|
|||
forwardmove = MAXPLMOVE;
|
||||
}
|
||||
|
||||
if (player->curshield == KSHIELD_TOP)
|
||||
{
|
||||
if (forwardmove < 0 ||
|
||||
(K_GetKartButtons(player) & BT_DRIFT))
|
||||
{
|
||||
forwardmove = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
forwardmove = MAXPLMOVE;
|
||||
}
|
||||
}
|
||||
|
||||
return forwardmove;
|
||||
}
|
||||
|
||||
fixed_t K_GetNewSpeed(player_t *player)
|
||||
{
|
||||
const fixed_t accelmax = 4000;
|
||||
const fixed_t p_speed = K_GetKartSpeed(player, true, true);
|
||||
fixed_t p_speed = K_GetKartSpeed(player, true, true);
|
||||
fixed_t p_accel = K_GetKartAccel(player);
|
||||
|
||||
fixed_t newspeed, oldspeed, finalspeed;
|
||||
|
||||
if (player->curshield == KSHIELD_TOP)
|
||||
{
|
||||
p_speed = 11 * p_speed / 10;
|
||||
}
|
||||
|
||||
if (K_PlayerUsesBotMovement(player) == true && player->botvars.rubberband > 0)
|
||||
{
|
||||
// Acceleration is tied to top speed...
|
||||
|
|
@ -4896,6 +5051,19 @@ fixed_t K_ItemScaleForPlayer(player_t *player)
|
|||
}
|
||||
}
|
||||
|
||||
fixed_t K_DefaultPlayerRadius(player_t *player)
|
||||
{
|
||||
mobj_t *top = K_GetGardenTop(player);
|
||||
|
||||
if (top)
|
||||
{
|
||||
return top->radius;
|
||||
}
|
||||
|
||||
return FixedMul(player->mo->scale,
|
||||
player->mo->info->radius);
|
||||
}
|
||||
|
||||
static mobj_t *K_SpawnKartMissile(mobj_t *source, mobjtype_t type, angle_t an, INT32 flags2, fixed_t speed, SINT8 dir)
|
||||
{
|
||||
mobj_t *th;
|
||||
|
|
@ -5010,6 +5178,9 @@ static mobj_t *K_SpawnKartMissile(mobj_t *source, mobjtype_t type, angle_t an, I
|
|||
th->destscale = th->destscale << 1;
|
||||
th->scalespeed = abs(th->destscale - th->scale) / (2*TICRATE);
|
||||
break;
|
||||
case MT_GARDENTOP:
|
||||
th->movefactor = finalspeed;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -5670,8 +5841,11 @@ void K_DriftDustHandling(mobj_t *spawner)
|
|||
dust->destscale = spawner->scale * 3;
|
||||
dust->scalespeed = spawner->scale/12;
|
||||
|
||||
if (leveltime % 6 == 0)
|
||||
S_StartSound(spawner, sfx_screec);
|
||||
if (!spawner->player || !K_GetGardenTop(spawner->player))
|
||||
{
|
||||
if (leveltime % 6 == 0)
|
||||
S_StartSound(spawner, sfx_screec);
|
||||
}
|
||||
|
||||
K_MatchGenericExtraFlags(dust, spawner);
|
||||
|
||||
|
|
@ -5831,7 +6005,7 @@ mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t mapthing,
|
|||
|
||||
if (missile) // Shootables
|
||||
{
|
||||
if (dir < 0 && mapthing != MT_SPB)
|
||||
if (dir < 0 && mapthing != MT_SPB && mapthing != MT_GARDENTOP)
|
||||
{
|
||||
// Shoot backward
|
||||
mo = K_SpawnKartMissile(player->mo, mapthing, (player->mo->angle + ANGLE_180) + angleOffset, 0, PROJSPEED, dir);
|
||||
|
|
@ -6442,7 +6616,7 @@ void K_DropHnextList(player_t *player, boolean keepshields)
|
|||
flip = P_MobjFlip(player->mo);
|
||||
ponground = P_IsObjectOnGround(player->mo);
|
||||
|
||||
if (shield != KSHIELD_NONE && !keepshields)
|
||||
if (shield != KSHIELD_NONE && shield != KSHIELD_TOP && !keepshields)
|
||||
{
|
||||
if (shield == KSHIELD_LIGHTNING)
|
||||
{
|
||||
|
|
@ -6494,6 +6668,9 @@ void K_DropHnextList(player_t *player, boolean keepshields)
|
|||
orbit = false;
|
||||
type = MT_EGGMANITEM;
|
||||
break;
|
||||
case MT_GARDENTOP:
|
||||
Obj_GardenTopDestroy(player);
|
||||
return;
|
||||
// intentionally do nothing
|
||||
case MT_ROCKETSNEAKER:
|
||||
case MT_SINK_SHIELD:
|
||||
|
|
@ -7800,6 +7977,33 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
{
|
||||
const boolean onground = P_IsObjectOnGround(player->mo);
|
||||
|
||||
/* reset sprite offsets :) */
|
||||
player->mo->sprxoff = 0;
|
||||
player->mo->spryoff = 0;
|
||||
player->mo->sprzoff = 0;
|
||||
player->mo->spritexoffset = 0;
|
||||
player->mo->spriteyoffset = 0;
|
||||
|
||||
if (player->curshield == KSHIELD_TOP)
|
||||
{
|
||||
mobj_t *top = K_GetGardenTop(player);
|
||||
|
||||
if (top)
|
||||
{
|
||||
/* FIXME: I cannot figure out how offset the
|
||||
player correctly in real time to pivot around
|
||||
the BOTTOM of the Top. This hack plus the one
|
||||
in R_PlayerSpriteRotation. */
|
||||
player->mo->spritexoffset += FixedMul(
|
||||
FixedDiv(top->height, top->scale),
|
||||
FINESINE(top->rollangle >> ANGLETOFINESHIFT));
|
||||
|
||||
player->mo->sprzoff += top->sprzoff + (
|
||||
P_GetMobjHead(top) -
|
||||
P_GetMobjFeet(player->mo));
|
||||
}
|
||||
}
|
||||
|
||||
K_UpdateOffroad(player);
|
||||
K_UpdateDraft(player);
|
||||
K_UpdateEngineSounds(player); // Thanks, VAda!
|
||||
|
|
@ -8244,8 +8448,20 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
|
||||
if (cmd->buttons & BT_DRIFT)
|
||||
{
|
||||
if (player->curshield == KSHIELD_TOP)
|
||||
{
|
||||
if (player->topdriftheld <= GARDENTOP_MAXGRINDTIME)
|
||||
player->topdriftheld++;
|
||||
|
||||
// Squish :)
|
||||
player->mo->spritexscale = 6*FRACUNIT/4;
|
||||
player->mo->spriteyscale = 2*FRACUNIT/4;
|
||||
|
||||
if (leveltime & 1)
|
||||
K_SpawnGardenTopSpeedLines(player);
|
||||
}
|
||||
// Only allow drifting while NOT trying to do an spindash input.
|
||||
if ((K_GetKartButtons(player) & BT_EBRAKEMASK) != BT_EBRAKEMASK)
|
||||
else if ((K_GetKartButtons(player) & BT_EBRAKEMASK) != BT_EBRAKEMASK)
|
||||
{
|
||||
player->pflags |= PF_DRIFTINPUT;
|
||||
}
|
||||
|
|
@ -8382,7 +8598,7 @@ void K_KartResetPlayerColor(player_t *player)
|
|||
|
||||
finalise:
|
||||
|
||||
if (player->curshield)
|
||||
if (player->curshield && player->curshield != KSHIELD_TOP)
|
||||
{
|
||||
fullbright = true;
|
||||
}
|
||||
|
|
@ -9027,13 +9243,25 @@ INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue)
|
|||
if ((currentSpeed <= 0) // Not moving
|
||||
&& ((K_GetKartButtons(player) & BT_EBRAKEMASK) != BT_EBRAKEMASK) // Not e-braking
|
||||
&& (player->respawn.state == RESPAWNST_NONE) // Not respawning
|
||||
&& (player->curshield != KSHIELD_TOP) // Not riding a Top
|
||||
&& (P_IsObjectOnGround(player->mo) == true)) // On the ground
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
p_maxspeed = K_GetKartSpeed(player, false, true);
|
||||
p_speed = min(currentSpeed, (p_maxspeed * 2));
|
||||
|
||||
if (player->curshield == KSHIELD_TOP)
|
||||
{
|
||||
// Do not downscale turning speed with faster
|
||||
// movement speed; behaves as if turning in place.
|
||||
p_speed = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
p_speed = min(currentSpeed, (p_maxspeed * 2));
|
||||
}
|
||||
|
||||
weightadjust = FixedDiv((p_maxspeed * 3) - p_speed, (p_maxspeed * 3) + (player->kartweight * FRACUNIT));
|
||||
|
||||
if (K_PlayerUsesBotMovement(player))
|
||||
|
|
@ -9060,7 +9288,9 @@ INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue)
|
|||
turnfixed = FixedMul(turnfixed, FRACUNIT + player->handleboost);
|
||||
}
|
||||
|
||||
if (player->mo->eflags & MFE_UNDERWATER)
|
||||
if (player->curshield == KSHIELD_TOP)
|
||||
;
|
||||
else if (player->mo->eflags & MFE_UNDERWATER)
|
||||
{
|
||||
fixed_t div = min(FRACUNIT + K_GetUnderwaterStrafeMul(player), 2*FRACUNIT);
|
||||
turnfixed = FixedDiv(turnfixed, div);
|
||||
|
|
@ -9448,6 +9678,7 @@ void K_KartUpdatePosition(player_t *player)
|
|||
fixed_t position = 1;
|
||||
fixed_t oldposition = player->position;
|
||||
fixed_t i;
|
||||
INT32 realplayers = 0;
|
||||
|
||||
if (player->spectator || !player->mo)
|
||||
{
|
||||
|
|
@ -9462,6 +9693,8 @@ void K_KartUpdatePosition(player_t *player)
|
|||
if (!playeringame[i] || players[i].spectator || !players[i].mo)
|
||||
continue;
|
||||
|
||||
realplayers++;
|
||||
|
||||
if (gametyperules & GTR_CIRCUIT)
|
||||
{
|
||||
if (player->exiting) // End of match standings
|
||||
|
|
@ -9525,6 +9758,33 @@ void K_KartUpdatePosition(player_t *player)
|
|||
if (oldposition != position) // Changed places?
|
||||
player->positiondelay = 10; // Position number growth
|
||||
|
||||
/* except in FREE PLAY */
|
||||
if (player->curshield == KSHIELD_TOP &&
|
||||
(gametyperules & GTR_CIRCUIT) &&
|
||||
realplayers > 1)
|
||||
{
|
||||
/* grace period so you don't fall off INSTANTLY */
|
||||
if (position == 1 && player->topinfirst < 2*TICRATE)
|
||||
{
|
||||
player->topinfirst++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (position == 1)
|
||||
{
|
||||
Obj_GardenTopThrow(player);
|
||||
}
|
||||
else
|
||||
{
|
||||
player->topinfirst = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
player->topinfirst = 0;
|
||||
}
|
||||
|
||||
player->position = position;
|
||||
}
|
||||
|
||||
|
|
@ -9676,6 +9936,7 @@ 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);
|
||||
p->mo->hprev->sprzoff = p->mo->sprzoff;
|
||||
}
|
||||
|
||||
if (!p->spindash)
|
||||
|
|
@ -10043,6 +10304,11 @@ void K_AdjustPlayerFriction(player_t *player)
|
|||
player->mo->friction += ((FRACUNIT - prevfriction) / greasetics) * player->tiregrease;
|
||||
}
|
||||
|
||||
if (player->curshield == KSHIELD_TOP)
|
||||
{
|
||||
player->mo->friction += 1024;
|
||||
}
|
||||
|
||||
/*
|
||||
if (K_PlayerEBrake(player) == true)
|
||||
{
|
||||
|
|
@ -10693,6 +10959,37 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
}
|
||||
}
|
||||
break;
|
||||
case KITEM_GARDENTOP:
|
||||
if (ATTACK_IS_DOWN && NO_HYUDORO)
|
||||
{
|
||||
if (player->curshield != KSHIELD_TOP)
|
||||
{
|
||||
player->topinfirst = 0;
|
||||
Obj_GardenTopDeploy(player->mo);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (player->throwdir == -1)
|
||||
{
|
||||
mobj_t *top = Obj_GardenTopDestroy(player);
|
||||
|
||||
// Fly off the Top at high speed
|
||||
P_Thrust(player->mo, K_MomentumAngle(player->mo), 80 * mapobjectscale);
|
||||
P_SetObjectMomZ(player->mo, player->mo->info->height / 8, true);
|
||||
|
||||
top->momx = player->mo->momx;
|
||||
top->momy = player->mo->momy;
|
||||
top->momz = player->mo->momz;
|
||||
}
|
||||
else
|
||||
{
|
||||
Obj_GardenTopThrow(player);
|
||||
S_StartSound(player->mo, sfx_tossed); // play only when actually thrown :^,J
|
||||
K_PlayAttackTaunt(player->mo);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case KITEM_BUBBLESHIELD:
|
||||
if (player->curshield != KSHIELD_BUBBLE)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ void K_SpawnDashDustRelease(player_t *player);
|
|||
void K_SpawnDriftBoostClip(player_t *player);
|
||||
void K_SpawnDriftBoostClipSpark(mobj_t *clip);
|
||||
void K_SpawnNormalSpeedLines(player_t *player);
|
||||
void K_SpawnGardenTopSpeedLines(player_t *player);
|
||||
void K_SpawnInvincibilitySpeedLines(mobj_t *mo);
|
||||
void K_SpawnBumpEffect(mobj_t *mo);
|
||||
void K_KartMoveAnimation(player_t *player);
|
||||
|
|
@ -146,6 +147,9 @@ boolean K_MovingHorizontally(mobj_t *mobj);
|
|||
boolean K_WaterRun(mobj_t *mobj);
|
||||
boolean K_WaterSkip(mobj_t *mobj);
|
||||
void K_SpawnWaterRunParticles(mobj_t *mobj);
|
||||
boolean K_IsRidingFloatingTop(player_t *player);
|
||||
boolean K_IsHoldingDownTop(player_t *player);
|
||||
mobj_t *K_GetGardenTop(player_t *player);
|
||||
void K_ApplyTripWire(player_t *player, tripwirestate_t state);
|
||||
INT16 K_GetSpindashChargeTime(player_t *player);
|
||||
fixed_t K_GetSpindashChargeSpeed(player_t *player);
|
||||
|
|
@ -172,6 +176,7 @@ UINT8 K_GetOrbinautItemFrame(UINT8 count);
|
|||
boolean K_IsSPBInGame(void);
|
||||
void K_KartEbrakeVisuals(player_t *p);
|
||||
void K_HandleDirectionalInfluence(player_t *player);
|
||||
fixed_t K_DefaultPlayerRadius(player_t *player);
|
||||
|
||||
// sound stuff for lua
|
||||
void K_PlayAttackTaunt(mobj_t *source);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,14 @@ void Obj_HyudoroThink(mobj_t *actor);
|
|||
void Obj_HyudoroCenterThink(mobj_t *actor);
|
||||
void Obj_HyudoroCollide(mobj_t *special, mobj_t *toucher);
|
||||
|
||||
/* Garden Top */
|
||||
void Obj_GardenTopDeploy(mobj_t *rider);
|
||||
mobj_t *Obj_GardenTopThrow(player_t *player);
|
||||
mobj_t *Obj_GardenTopDestroy(player_t *player);
|
||||
void Obj_GardenTopThink(mobj_t *top);
|
||||
void Obj_GardenTopSparkThink(mobj_t *spark);
|
||||
boolean Obj_GardenTopPlayerIsGrinding(player_t *player);
|
||||
|
||||
/* Shrink */
|
||||
void Obj_PohbeeThinker(mobj_t *pohbee);
|
||||
void Obj_PohbeeRemoved(mobj_t *pohbee);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
hyudoro.c
|
||||
gardentop.c
|
||||
shrink.c
|
||||
item-debris.c
|
||||
spb.c
|
||||
|
|
|
|||
614
src/objects/gardentop.c
Normal file
614
src/objects/gardentop.c
Normal file
|
|
@ -0,0 +1,614 @@
|
|||
#include "../doomdef.h"
|
||||
#include "../doomstat.h"
|
||||
#include "../info.h"
|
||||
#include "../k_kart.h"
|
||||
#include "../k_objects.h"
|
||||
#include "../m_random.h"
|
||||
#include "../p_local.h"
|
||||
#include "../r_local.h"
|
||||
#include "../s_sound.h"
|
||||
|
||||
// TODO: separate from this file
|
||||
static fixed_t K_FlipZOffset(mobj_t *us, mobj_t *them)
|
||||
{
|
||||
fixed_t z = 0;
|
||||
|
||||
if (them->eflags & MFE_VERTICALFLIP)
|
||||
z += them->height;
|
||||
|
||||
if (us->eflags & MFE_VERTICALFLIP)
|
||||
z -= us->height;
|
||||
|
||||
return z;
|
||||
}
|
||||
|
||||
#define SPARKCOLOR SKINCOLOR_ROBIN
|
||||
|
||||
enum {
|
||||
TOP_ANCHORED,
|
||||
TOP_LOOSE,
|
||||
};
|
||||
|
||||
#define topsfx_floating sfx_s3k7d
|
||||
#define topsfx_grinding sfx_s3k79
|
||||
#define topsfx_lift sfx_s3ka0
|
||||
|
||||
#define rider_top(o) ((o)->hnext)
|
||||
|
||||
#define top_mode(o) ((o)->extravalue1)
|
||||
#define top_float(o) ((o)->lastlook)
|
||||
#define top_sound(o) ((o)->extravalue2)
|
||||
#define top_soundtic(o) ((o)->movecount)
|
||||
|
||||
/* TOP_ANCHORED */
|
||||
#define top_rider(o) ((o)->tracer)
|
||||
|
||||
/* TOP_LOOSE */
|
||||
#define top_waveangle(o) ((o)->movedir)
|
||||
/* wavepause will take mobjinfo reactiontime automatically */
|
||||
#define top_wavepause(o) ((o)->reactiontime)
|
||||
|
||||
#define spark_top(o) ((o)->target)
|
||||
#define spark_angle(o) ((o)->movedir)
|
||||
|
||||
static inline player_t *
|
||||
get_rider_player (mobj_t *rider)
|
||||
{
|
||||
return rider ? rider->player : NULL;
|
||||
}
|
||||
|
||||
static inline player_t *
|
||||
get_top_rider_player (mobj_t *top)
|
||||
{
|
||||
return get_rider_player(top_rider(top));
|
||||
}
|
||||
|
||||
static inline boolean
|
||||
is_top_grind_input (mobj_t *top)
|
||||
{
|
||||
player_t *player = get_top_rider_player(top);
|
||||
|
||||
return player && K_IsHoldingDownTop(player);
|
||||
}
|
||||
|
||||
static inline boolean
|
||||
is_top_grinding (mobj_t *top)
|
||||
{
|
||||
if (top_float(top) > 0)
|
||||
return false;
|
||||
|
||||
if (!P_IsObjectOnGround(top))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline fixed_t
|
||||
grind_spark_base_scale (player_t *player)
|
||||
{
|
||||
return FRACUNIT/2 +
|
||||
player->topdriftheld * FRACUNIT
|
||||
/ GARDENTOP_MAXGRINDTIME;
|
||||
}
|
||||
|
||||
static inline INT32
|
||||
get_player_steer_tilt
|
||||
( player_t * player,
|
||||
INT32 stages)
|
||||
{
|
||||
return player->steering
|
||||
* stages
|
||||
|
||||
// 1 degree for a full turn
|
||||
/ KART_FULLTURN
|
||||
* ANG1
|
||||
|
||||
// stages is for fractions of a full turn, divide to
|
||||
// get a fraction of a degree
|
||||
/ stages
|
||||
|
||||
// angle is inverted in reverse gravity
|
||||
* P_MobjFlip(player->mo);
|
||||
}
|
||||
|
||||
static inline fixed_t
|
||||
goofy_shake (fixed_t n)
|
||||
{
|
||||
return P_RandomRange(PR_DECORATION, -1, 1) * n;
|
||||
}
|
||||
|
||||
static inline void
|
||||
init_top
|
||||
( mobj_t * top,
|
||||
INT32 mode)
|
||||
{
|
||||
top_mode(top) = mode;
|
||||
top_float(top) = 0;
|
||||
top_sound(top) = sfx_None;
|
||||
top_waveangle(top) = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
spawn_spark
|
||||
( mobj_t * top,
|
||||
angle_t angle)
|
||||
{
|
||||
mobj_t *spark = P_SpawnMobjFromMobj(
|
||||
top, 0, 0, 0, MT_GARDENTOPSPARK);
|
||||
|
||||
P_SetTarget(&spark_top(spark), top);
|
||||
|
||||
spark_angle(spark) = angle;
|
||||
|
||||
spark->color = SPARKCOLOR;
|
||||
spark->spriteyscale = 3*FRACUNIT/4;
|
||||
}
|
||||
|
||||
static void
|
||||
spawn_spark_circle
|
||||
( mobj_t * top,
|
||||
UINT8 n)
|
||||
{
|
||||
const angle_t a = ANGLE_MAX / n;
|
||||
|
||||
UINT8 i;
|
||||
|
||||
for (i = 0; i < n; ++i)
|
||||
{
|
||||
spawn_spark(top, i * a);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
spawn_grind_spark (mobj_t *top)
|
||||
{
|
||||
mobj_t *rider = top_rider(top);
|
||||
mobj_t *spark;
|
||||
|
||||
player_t *player = NULL;
|
||||
|
||||
fixed_t x = 0;
|
||||
fixed_t y = 0;
|
||||
|
||||
angle_t angle = top->angle;
|
||||
|
||||
if (rider)
|
||||
{
|
||||
const fixed_t speed = -20 * top->scale;
|
||||
|
||||
angle = K_MomentumAngle(rider);
|
||||
|
||||
x = P_ReturnThrustX(rider, angle, speed);
|
||||
y = P_ReturnThrustY(rider, angle, speed);
|
||||
|
||||
player = get_rider_player(rider);
|
||||
}
|
||||
|
||||
spark = P_SpawnMobjFromMobj(
|
||||
top, x, y, 0, MT_DRIFTSPARK);
|
||||
|
||||
spark->momx = x;
|
||||
spark->momy = y;
|
||||
|
||||
P_SetMobjState(spark, S_DRIFTSPARK_A1);
|
||||
|
||||
spark->angle = angle;
|
||||
spark->color = SPARKCOLOR;
|
||||
|
||||
if (player)
|
||||
{
|
||||
spark->destscale = FixedMul(spark->destscale,
|
||||
grind_spark_base_scale(player));
|
||||
|
||||
P_SetScale(spark, spark->destscale);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
loop_sfx
|
||||
( mobj_t * top,
|
||||
sfxenum_t sfx)
|
||||
{
|
||||
switch (sfx)
|
||||
{
|
||||
case topsfx_floating:
|
||||
if (S_SoundPlaying(top, sfx))
|
||||
{
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case topsfx_grinding:
|
||||
if ((sfxenum_t)top_sound(top) != sfx)
|
||||
{
|
||||
top_soundtic(top) = leveltime;
|
||||
}
|
||||
|
||||
/* FIXME: could this sound just be looped
|
||||
normally? :face_holding_back_tears: */
|
||||
if ((leveltime - top_soundtic(top)) % 28 > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
S_StartSound(top, sfx);
|
||||
}
|
||||
|
||||
static void
|
||||
modulate (mobj_t *top)
|
||||
{
|
||||
const fixed_t max_hover = top->height / 4;
|
||||
const fixed_t hover_step = max_hover / 4;
|
||||
|
||||
sfxenum_t ambience = sfx_None;
|
||||
|
||||
if (is_top_grind_input(top))
|
||||
{
|
||||
if (top_float(top) == max_hover)
|
||||
{
|
||||
P_SetMobjState(top, S_GARDENTOP_SINKING1);
|
||||
}
|
||||
|
||||
if (top_float(top) > 0)
|
||||
{
|
||||
top_float(top) = max(0,
|
||||
top_float(top) - hover_step);
|
||||
}
|
||||
else if (P_IsObjectOnGround(top))
|
||||
{
|
||||
spawn_grind_spark(top);
|
||||
ambience = topsfx_grinding;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (top_float(top) == 0)
|
||||
{
|
||||
P_SetMobjState(top, S_GARDENTOP_FLOATING);
|
||||
|
||||
S_StopSoundByID(top, topsfx_grinding);
|
||||
S_StartSound(top, topsfx_lift);
|
||||
}
|
||||
|
||||
if (top_float(top) < max_hover)
|
||||
{
|
||||
top_float(top) = min(max_hover,
|
||||
top_float(top) + hover_step);
|
||||
}
|
||||
else
|
||||
{
|
||||
ambience = topsfx_floating;
|
||||
}
|
||||
}
|
||||
|
||||
top->sprzoff = top_float(top) * P_MobjFlip(top);
|
||||
|
||||
if (ambience)
|
||||
{
|
||||
loop_sfx(top, ambience);
|
||||
}
|
||||
|
||||
top_sound(top) = ambience;
|
||||
}
|
||||
|
||||
static void
|
||||
tilt (mobj_t *top)
|
||||
{
|
||||
player_t *player = get_top_rider_player(top);
|
||||
|
||||
INT32 tilt = top->rollangle;
|
||||
|
||||
if (is_top_grind_input(top))
|
||||
{
|
||||
const angle_t tiltmax = ANGLE_22h;
|
||||
|
||||
tilt += get_player_steer_tilt(player, 4);
|
||||
|
||||
if (abs(tilt) > tiltmax)
|
||||
{
|
||||
tilt = intsign(tilt) * tiltmax;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const angle_t decay = ANG1 * 2;
|
||||
|
||||
if (abs(tilt) > decay)
|
||||
{
|
||||
tilt -= intsign(tilt) * decay;
|
||||
}
|
||||
else
|
||||
{
|
||||
tilt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
top->rollangle = tilt;
|
||||
|
||||
/* Vibrate left and right if you're about to lose it. */
|
||||
if (player && player->topinfirst)
|
||||
{
|
||||
top->spritexoffset = P_LerpFlip(32*FRACUNIT, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
top->spritexoffset = 0;
|
||||
}
|
||||
|
||||
/* Go ABSOLUTELY NUTS if the player is tumbling... */
|
||||
if (player && player->tumbleBounces > 0)
|
||||
{
|
||||
const fixed_t yofs = 48 * FRACUNIT;
|
||||
const fixed_t ofs3d = 24 * top->scale;
|
||||
|
||||
/* spriteyoffset scales, e.g. with K_Squish */
|
||||
top->spriteyoffset = FixedDiv(
|
||||
goofy_shake(yofs), top->spriteyscale);
|
||||
|
||||
top->sprxoff = goofy_shake(ofs3d);
|
||||
top->spryoff = goofy_shake(ofs3d);
|
||||
}
|
||||
else
|
||||
{
|
||||
top->spriteyoffset = 0;
|
||||
top->sprxoff = 0;
|
||||
top->spryoff = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
anchor_top (mobj_t *top)
|
||||
{
|
||||
mobj_t *rider = top_rider(top);
|
||||
player_t *player = get_rider_player(rider);
|
||||
|
||||
if (player && player->curshield != KSHIELD_TOP)
|
||||
{
|
||||
P_RemoveMobj(top);
|
||||
return;
|
||||
}
|
||||
|
||||
tilt(top);
|
||||
|
||||
P_MoveOrigin(top, rider->x, rider->y,
|
||||
rider->z + K_FlipZOffset(top, rider));
|
||||
|
||||
K_GenericExtraFlagsNoZAdjust(top, rider);
|
||||
|
||||
/* Copying the Z momentum lets the Top squash and stretch
|
||||
as it falls with the player. Don't copy the X/Y
|
||||
momentum because then it would always get slightly
|
||||
ahead of the player. */
|
||||
top->momx = 0;
|
||||
top->momy = 0;
|
||||
top->momz = rider->momz;
|
||||
|
||||
/* The Z momentum can put the Top slightly ahead of the
|
||||
player in that axis too. It looks cool if the Top
|
||||
falls below you but not if it bounces up. */
|
||||
if (top->momz * P_MobjFlip(top) > 0)
|
||||
{
|
||||
top->momz = 0;
|
||||
}
|
||||
|
||||
/* match rider's slope tilt */
|
||||
top->pitch = rider->pitch;
|
||||
top->roll = rider->roll;
|
||||
}
|
||||
|
||||
static void
|
||||
loose_think (mobj_t *top)
|
||||
{
|
||||
const fixed_t thrustamount = top->movefactor;
|
||||
const angle_t momangle = K_MomentumAngle(top);
|
||||
|
||||
angle_t ang = top->angle;
|
||||
|
||||
mobj_t *ghost = P_SpawnGhostMobj(top);
|
||||
ghost->colorized = true; // already has color!
|
||||
|
||||
if (AngleDelta(ang, momangle) > ANGLE_90)
|
||||
{
|
||||
top->angle = momangle;
|
||||
}
|
||||
|
||||
if (top_wavepause(top))
|
||||
{
|
||||
top_wavepause(top)--;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* oscillate between +90 and -90 degrees */
|
||||
ang += AbsAngle(top_waveangle(top)) - ANGLE_90;
|
||||
}
|
||||
|
||||
P_InstaThrust(top, top->angle, thrustamount);
|
||||
P_Thrust(top, ang, thrustamount);
|
||||
|
||||
//top_waveangle(top) = (angle_t)top_waveangle(top) + ANG10;
|
||||
top_waveangle(top) += ANG10;
|
||||
|
||||
/* intangibility grace period */
|
||||
if (top->threshold > 0)
|
||||
{
|
||||
top->threshold--;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
anchor_spark (mobj_t *spark)
|
||||
{
|
||||
mobj_t *top = spark_top(spark);
|
||||
mobj_t *rider = top_rider(top);
|
||||
player_t *player = get_rider_player(rider);
|
||||
|
||||
const angle_t angle = top->angle + spark_angle(spark);
|
||||
const fixed_t x = P_ReturnThrustX(top, angle, spark->scale);
|
||||
const fixed_t y = P_ReturnThrustY(top, angle, spark->scale);
|
||||
|
||||
/* FIXME: THIS FUNCTION FUCKING SUCKS */
|
||||
K_FlipFromObject(spark, top);
|
||||
|
||||
P_MoveOrigin(spark, top->x + x, top->y + y,
|
||||
top->z + K_FlipZOffset(spark, top));
|
||||
|
||||
spark->angle = angle;
|
||||
|
||||
if (player)
|
||||
{
|
||||
const fixed_t topspeed =
|
||||
K_GetKartSpeed(player, false, false);
|
||||
|
||||
const fixed_t speed = FixedHypot(
|
||||
rider->momx, rider->momy);
|
||||
|
||||
P_SetScale(spark, FixedMul(top->scale, FRACUNIT/2 +
|
||||
FixedDiv(speed / 2, topspeed)));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Obj_GardenTopDeploy (mobj_t *rider)
|
||||
{
|
||||
player_t *player = rider->player;
|
||||
|
||||
mobj_t *top = P_SpawnMobjFromMobj(
|
||||
rider, 0, 0, 0, MT_GARDENTOP);
|
||||
|
||||
init_top(top, TOP_ANCHORED);
|
||||
|
||||
top->flags |= MF_NOCLIPHEIGHT;
|
||||
|
||||
/* only the player's shadow needs to be rendered */
|
||||
top->shadowscale = 0;
|
||||
|
||||
P_SetTarget(&top_rider(top), rider);
|
||||
P_SetTarget(&rider_top(rider), top);
|
||||
|
||||
if (player)
|
||||
{
|
||||
player->curshield = KSHIELD_TOP;
|
||||
rider->radius = K_DefaultPlayerRadius(player);
|
||||
}
|
||||
|
||||
spawn_spark_circle(top, 6);
|
||||
}
|
||||
|
||||
mobj_t *
|
||||
Obj_GardenTopThrow (player_t *player)
|
||||
{
|
||||
mobj_t *top = K_GetGardenTop(player);
|
||||
|
||||
if (top)
|
||||
{
|
||||
const fixed_t oldfloat = top_float(top);
|
||||
const fixed_t height = top->height;
|
||||
|
||||
K_UpdateHnextList(player, true);
|
||||
|
||||
/* Sucks that another one needs to be spawned but
|
||||
this way, the throwing function can be used. */
|
||||
top = K_ThrowKartItem(
|
||||
player, true, MT_GARDENTOP, 1, 0, 0);
|
||||
|
||||
init_top(top, TOP_LOOSE);
|
||||
|
||||
top_float(top) = oldfloat;
|
||||
top_waveangle(top) = 0;
|
||||
|
||||
/* prevents it from hitting us on its way out */
|
||||
top->threshold = 20;
|
||||
|
||||
/* ensure it's tangible */
|
||||
top->flags &= ~(MF_NOCLIPTHING);
|
||||
|
||||
/* Put player PHYSICALLY on top. While riding the
|
||||
Top, player collision was used and the player
|
||||
technically remained on the ground. Now they
|
||||
should fall off. */
|
||||
P_SetOrigin(player->mo, player->mo->x, player->mo->y,
|
||||
player->mo->z + height * P_MobjFlip(player->mo));
|
||||
|
||||
if (player->itemamount > 0)
|
||||
player->itemamount--;
|
||||
|
||||
if (player->itemamount <= 0)
|
||||
player->itemtype = KITEM_NONE;
|
||||
|
||||
player->curshield = KSHIELD_NONE;
|
||||
|
||||
player->mo->radius = K_DefaultPlayerRadius(player);
|
||||
}
|
||||
|
||||
return top;
|
||||
}
|
||||
|
||||
mobj_t *
|
||||
Obj_GardenTopDestroy (player_t *player)
|
||||
{
|
||||
mobj_t *top = Obj_GardenTopThrow(player);
|
||||
|
||||
if (top)
|
||||
{
|
||||
/* kill kill kill die die die */
|
||||
P_KillMobj(top, NULL, NULL, DMG_NORMAL);
|
||||
}
|
||||
|
||||
return top;
|
||||
}
|
||||
|
||||
void
|
||||
Obj_GardenTopThink (mobj_t *top)
|
||||
{
|
||||
modulate(top);
|
||||
|
||||
switch (top_mode(top))
|
||||
{
|
||||
case TOP_ANCHORED:
|
||||
if (top_rider(top))
|
||||
{
|
||||
anchor_top(top);
|
||||
}
|
||||
break;
|
||||
|
||||
case TOP_LOOSE:
|
||||
loose_think(top);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Obj_GardenTopSparkThink (mobj_t *spark)
|
||||
{
|
||||
mobj_t *top = spark_top(spark);
|
||||
|
||||
if (!top)
|
||||
{
|
||||
P_RemoveMobj(spark);
|
||||
return;
|
||||
}
|
||||
|
||||
anchor_spark(spark);
|
||||
|
||||
if (is_top_grinding(top))
|
||||
{
|
||||
spark->renderflags ^= RF_DONTDRAW;
|
||||
}
|
||||
else
|
||||
{
|
||||
spark->renderflags |= RF_DONTDRAW;
|
||||
}
|
||||
}
|
||||
|
||||
boolean
|
||||
Obj_GardenTopPlayerIsGrinding (player_t *player)
|
||||
{
|
||||
mobj_t *top = K_GetGardenTop(player);
|
||||
|
||||
return top ? is_top_grinding(top) : false;
|
||||
}
|
||||
|
|
@ -143,6 +143,7 @@ void Obj_OrbinautThink(mobj_t *th)
|
|||
boolean Obj_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2)
|
||||
{
|
||||
boolean damageitem = false;
|
||||
boolean tumbleitem = false;
|
||||
boolean sprung = false;
|
||||
|
||||
if ((orbinaut_selfdelay(t1) > 0 && t2->hitlag > 0)
|
||||
|
|
@ -173,6 +174,11 @@ boolean Obj_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (t1->type == MT_GARDENTOP)
|
||||
{
|
||||
tumbleitem = true;
|
||||
}
|
||||
|
||||
if (t2->player)
|
||||
{
|
||||
if ((t2->player->flashing > 0 && t2->hitlag == 0)
|
||||
|
|
@ -190,7 +196,8 @@ boolean Obj_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2)
|
|||
else
|
||||
{
|
||||
// Player Damage
|
||||
P_DamageMobj(t2, t1, t1->target, 1, DMG_WIPEOUT|DMG_WOMBO);
|
||||
P_DamageMobj(t2, t1, t1->target, 1, DMG_WOMBO |
|
||||
(tumbleitem ? DMG_TUMBLE : DMG_WIPEOUT));
|
||||
K_KartBouncing(t2, t1);
|
||||
S_StartSound(t2, sfx_s3k7b);
|
||||
}
|
||||
|
|
@ -233,6 +240,11 @@ boolean Obj_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2)
|
|||
damageitem = true;
|
||||
}
|
||||
|
||||
if (t1->type == MT_GARDENTOP)
|
||||
{
|
||||
damageitem = false;
|
||||
}
|
||||
|
||||
if (damageitem)
|
||||
{
|
||||
// This Item Damage
|
||||
|
|
|
|||
|
|
@ -2014,6 +2014,12 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
player->emeralds = 0;
|
||||
K_CheckEmeralds(source->player);
|
||||
}
|
||||
|
||||
/* Drop "shield" immediately on contact. */
|
||||
if (source->player->curshield == KSHIELD_TOP)
|
||||
{
|
||||
Obj_GardenTopDestroy(source->player);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
15
src/p_map.c
15
src/p_map.c
|
|
@ -866,6 +866,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
|||
&& (tmthing->type == MT_ORBINAUT || tmthing->type == MT_JAWZ
|
||||
|| tmthing->type == MT_BANANA || tmthing->type == MT_EGGMANITEM || tmthing->type == MT_BALLHOG
|
||||
|| tmthing->type == MT_SSMINE || tmthing->type == MT_LANDMINE || tmthing->type == MT_SINK
|
||||
|| tmthing->type == MT_GARDENTOP
|
||||
|| (tmthing->type == MT_PLAYER && thing->target != tmthing)))
|
||||
{
|
||||
// see if it went over / under
|
||||
|
|
@ -881,6 +882,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
|||
&& (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ
|
||||
|| thing->type == MT_BANANA || thing->type == MT_EGGMANITEM || thing->type == MT_BALLHOG
|
||||
|| thing->type == MT_SSMINE || tmthing->type == MT_LANDMINE || thing->type == MT_SINK
|
||||
|| thing->type == MT_GARDENTOP
|
||||
|| (thing->type == MT_PLAYER && tmthing->target != thing)))
|
||||
{
|
||||
// see if it went over / under
|
||||
|
|
@ -901,6 +903,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
|||
&& (tmthing->type == MT_ORBINAUT || tmthing->type == MT_JAWZ
|
||||
|| tmthing->type == MT_BANANA || tmthing->type == MT_EGGMANITEM || tmthing->type == MT_BALLHOG
|
||||
|| tmthing->type == MT_SSMINE || tmthing->type == MT_LANDMINE || tmthing->type == MT_SINK
|
||||
|| tmthing->type == MT_GARDENTOP
|
||||
|| (tmthing->type == MT_PLAYER)))
|
||||
{
|
||||
// see if it went over / under
|
||||
|
|
@ -915,6 +918,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
|||
&& (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ
|
||||
|| thing->type == MT_BANANA || thing->type == MT_EGGMANITEM || thing->type == MT_BALLHOG
|
||||
|| thing->type == MT_SSMINE || tmthing->type == MT_LANDMINE || thing->type == MT_SINK
|
||||
|| thing->type == MT_GARDENTOP
|
||||
|| (thing->type == MT_PLAYER)))
|
||||
{
|
||||
// see if it went over / under
|
||||
|
|
@ -932,7 +936,8 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
|||
return BMIT_CONTINUE;
|
||||
|
||||
if (tmthing->type == MT_ORBINAUT || tmthing->type == MT_JAWZ
|
||||
|| tmthing->type == MT_ORBINAUT_SHIELD || tmthing->type == MT_JAWZ_SHIELD)
|
||||
|| tmthing->type == MT_ORBINAUT_SHIELD || tmthing->type == MT_JAWZ_SHIELD
|
||||
|| tmthing->type == MT_GARDENTOP)
|
||||
{
|
||||
// see if it went over / under
|
||||
if (tmthing->z > thing->z + thing->height)
|
||||
|
|
@ -943,7 +948,8 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
|||
return Obj_OrbinautJawzCollide(tmthing, thing) ? BMIT_CONTINUE : BMIT_ABORT;
|
||||
}
|
||||
else if (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ
|
||||
|| thing->type == MT_ORBINAUT_SHIELD || thing->type == MT_JAWZ_SHIELD)
|
||||
|| thing->type == MT_ORBINAUT_SHIELD || thing->type == MT_JAWZ_SHIELD
|
||||
|| thing->type == MT_GARDENTOP)
|
||||
{
|
||||
// see if it went over / under
|
||||
if (tmthing->z > thing->z + thing->height)
|
||||
|
|
@ -2842,6 +2848,11 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
|
|||
thing->terrain = NULL;
|
||||
}
|
||||
|
||||
if (thing->player && K_IsRidingFloatingTop(thing->player))
|
||||
{
|
||||
stairjank = false;
|
||||
}
|
||||
|
||||
/* FIXME: slope step down (even up) has some false
|
||||
positives, so just ignore them entirely. */
|
||||
if (stairjank && !oldslope && !thing->standingslope &&
|
||||
|
|
|
|||
43
src/p_mobj.c
43
src/p_mobj.c
|
|
@ -1133,7 +1133,11 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
|
|||
gravityadd = FixedMul(TUMBLEGRAVITY, gravityadd);
|
||||
}
|
||||
|
||||
if (mo->player->fastfall != 0)
|
||||
if (K_IsHoldingDownTop(mo->player))
|
||||
{
|
||||
gravityadd = (5*gravityadd)/2;
|
||||
}
|
||||
else if (mo->player->fastfall != 0)
|
||||
{
|
||||
// Fast falling
|
||||
gravityadd *= 4;
|
||||
|
|
@ -1734,6 +1738,7 @@ void P_XYMovement(mobj_t *mo)
|
|||
switch (mo->type)
|
||||
{
|
||||
case MT_ORBINAUT: // Orbinaut speed decreasing
|
||||
case MT_GARDENTOP:
|
||||
if (mo->health > 1)
|
||||
{
|
||||
S_StartSound(mo, mo->info->attacksound);
|
||||
|
|
@ -6444,6 +6449,7 @@ static boolean P_MobjDeadThink(mobj_t *mobj)
|
|||
return false;
|
||||
}
|
||||
/* FALLTHRU */
|
||||
case MT_GARDENTOP:
|
||||
case MT_ORBINAUT_SHIELD:
|
||||
case MT_BANANA_SHIELD:
|
||||
case MT_EGGMANITEM_SHIELD:
|
||||
|
|
@ -7152,7 +7158,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
}
|
||||
}
|
||||
break;
|
||||
case MT_TRIPWIREBOOST:
|
||||
case MT_TRIPWIREBOOST: {
|
||||
mobj_t *top;
|
||||
fixed_t newHeight;
|
||||
fixed_t newScale;
|
||||
|
||||
if (!mobj->target || !mobj->target->health
|
||||
|| !mobj->target->player || !mobj->target->player->tripwireLeniency)
|
||||
{
|
||||
|
|
@ -7160,10 +7170,21 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
return false;
|
||||
}
|
||||
|
||||
newHeight = mobj->target->height;
|
||||
newScale = mobj->target->scale;
|
||||
|
||||
top = K_GetGardenTop(mobj->target->player);
|
||||
|
||||
if (top)
|
||||
{
|
||||
newHeight += 5 * top->height / 4;
|
||||
newScale = FixedMul(newScale, FixedDiv(newHeight / 2, mobj->target->height));
|
||||
}
|
||||
|
||||
mobj->angle = K_MomentumAngle(mobj->target);
|
||||
P_MoveOrigin(mobj, mobj->target->x, mobj->target->y, mobj->target->z + (mobj->target->height >> 1));
|
||||
mobj->destscale = mobj->target->scale;
|
||||
P_SetScale(mobj, mobj->target->scale);
|
||||
P_MoveOrigin(mobj, mobj->target->x, mobj->target->y, mobj->target->z + (newHeight / 2));
|
||||
mobj->destscale = newScale;
|
||||
P_SetScale(mobj, newScale);
|
||||
|
||||
if (mobj->extravalue1)
|
||||
{
|
||||
|
|
@ -7235,6 +7256,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MT_BOOSTFLAME:
|
||||
if (!mobj->target || !mobj->target->health)
|
||||
{
|
||||
|
|
@ -7806,6 +7828,16 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
}
|
||||
break;
|
||||
}
|
||||
case MT_GARDENTOP:
|
||||
{
|
||||
Obj_GardenTopThink(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_GARDENTOPSPARK:
|
||||
{
|
||||
Obj_GardenTopSparkThink(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_HYUDORO:
|
||||
{
|
||||
Obj_HyudoroThink(mobj);
|
||||
|
|
@ -9851,6 +9883,7 @@ static void P_DefaultMobjShadowScale(mobj_t *thing)
|
|||
case MT_BUBBLESHIELD:
|
||||
case MT_BUBBLESHIELDTRAP:
|
||||
case MT_FLAMESHIELD:
|
||||
case MT_GARDENTOP:
|
||||
thing->shadowscale = FRACUNIT;
|
||||
break;
|
||||
case MT_RING:
|
||||
|
|
|
|||
|
|
@ -378,6 +378,8 @@ static void P_NetArchivePlayers(void)
|
|||
WRITEUINT8(save_p, players[i].kickstartaccel);
|
||||
|
||||
WRITEUINT8(save_p, players[i].stairjank);
|
||||
WRITEUINT8(save_p, players[i].topdriftheld);
|
||||
WRITEUINT8(save_p, players[i].topinfirst);
|
||||
|
||||
WRITEUINT8(save_p, players[i].shrinkLaserDelay);
|
||||
|
||||
|
|
@ -674,6 +676,8 @@ static void P_NetUnArchivePlayers(void)
|
|||
players[i].kickstartaccel = READUINT8(save_p);
|
||||
|
||||
players[i].stairjank = READUINT8(save_p);
|
||||
players[i].topdriftheld = READUINT8(save_p);
|
||||
players[i].topinfirst = READUINT8(save_p);
|
||||
|
||||
players[i].shrinkLaserDelay = READUINT8(save_p);
|
||||
|
||||
|
|
|
|||
|
|
@ -4416,7 +4416,7 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers
|
|||
switch (special)
|
||||
{
|
||||
case 1: // Damage (Generic)
|
||||
if (roversector || P_MobjReadyToTrigger(player->mo, sector))
|
||||
if (!K_IsRidingFloatingTop(player) && (roversector || P_MobjReadyToTrigger(player->mo, sector)))
|
||||
P_DamageMobj(player->mo, NULL, NULL, 1, DMG_NORMAL);
|
||||
break;
|
||||
case 2: // Damage (Water) // SRB2kart - These three damage types are now offroad sectors
|
||||
|
|
@ -4424,7 +4424,7 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers
|
|||
case 4: // Damage (Electrical)
|
||||
break;
|
||||
case 5: // Spikes
|
||||
if (roversector || P_MobjReadyToTrigger(player->mo, sector))
|
||||
if (!K_IsRidingFloatingTop(player) && (roversector || P_MobjReadyToTrigger(player->mo, sector)))
|
||||
P_DamageMobj(player->mo, NULL, NULL, 1, DMG_NORMAL);
|
||||
break;
|
||||
case 6: // Death Pit (Camera Mod)
|
||||
|
|
|
|||
|
|
@ -44,6 +44,14 @@ INT32 P_AltFlip(INT32 n, tic_t tics)
|
|||
return leveltime % (2 * tics) < tics ? n : -(n);
|
||||
}
|
||||
|
||||
// Please read p_tick.h
|
||||
INT32 P_LerpFlip(INT32 n, tic_t tics)
|
||||
{
|
||||
const tic_t w = 2 * tics;
|
||||
|
||||
return P_AltFlip(((leveltime % w) - tics) * n, w);
|
||||
}
|
||||
|
||||
//
|
||||
// THINKERS
|
||||
// All thinkers should be allocated by Z_Calloc
|
||||
|
|
|
|||
|
|
@ -35,4 +35,12 @@ mobj_t *P_SetTarget(mobj_t **mo, mobj_t *target); // killough 11/98
|
|||
INT32 P_AltFlip(INT32 value, tic_t tics);
|
||||
#define P_RandomFlip(value) P_AltFlip(value, 1)
|
||||
|
||||
// Multiply value back and forth between -(tics) and +(tics).
|
||||
// Example output P_ModulateFlip(2, 2):
|
||||
// Tic: 0 1 2 3 4 5 6 7 8
|
||||
// Val: -4 -2 0 2 4 2 0 -2 -4
|
||||
// A half cycle (one direction) takes 2 * tics.
|
||||
// A full cycle takes 4 * tics.
|
||||
INT32 P_LerpFlip(INT32 value, tic_t tics);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
28
src/p_user.c
28
src/p_user.c
|
|
@ -1801,7 +1801,7 @@ static void P_3dMovement(player_t *player)
|
|||
// Get the old momentum; this will be needed at the end of the function! -SH
|
||||
oldMagnitude = R_PointToDist2(player->mo->momx - player->cmomx, player->mo->momy - player->cmomy, 0, 0);
|
||||
|
||||
if (player->stairjank > 8 && leveltime & 3)
|
||||
if ((player->stairjank > 8 && leveltime & 3) || K_IsRidingFloatingTop(player))
|
||||
{
|
||||
movepushangle = K_MomentumAngle(player->mo);
|
||||
}
|
||||
|
|
@ -1884,6 +1884,7 @@ static void P_3dMovement(player_t *player)
|
|||
if (player->mo->movefactor != FRACUNIT) // Friction-scaled acceleration...
|
||||
movepushforward = FixedMul(movepushforward, player->mo->movefactor);
|
||||
|
||||
if (player->curshield != KSHIELD_TOP)
|
||||
{
|
||||
INT32 a = K_GetUnderwaterTurnAdjust(player);
|
||||
INT32 adj = 0;
|
||||
|
|
@ -1967,6 +1968,24 @@ static void P_3dMovement(player_t *player)
|
|||
player->mo->momx += totalthrust.x;
|
||||
player->mo->momy += totalthrust.y;
|
||||
|
||||
// Releasing a drift while on the Top translates all your
|
||||
// momentum (and even then some) into whichever direction
|
||||
// you're facing
|
||||
if (onground && player->curshield == KSHIELD_TOP && (K_GetKartButtons(player) & BT_DRIFT) != BT_DRIFT && (player->oldcmd.buttons & BT_DRIFT))
|
||||
{
|
||||
const fixed_t gmin = FRACUNIT/4;
|
||||
const fixed_t gmax = 5*FRACUNIT/2;
|
||||
|
||||
const fixed_t grindfactor = (gmax - gmin) / GARDENTOP_MAXGRINDTIME;
|
||||
const fixed_t grindscale = gmin + (player->topdriftheld * grindfactor);
|
||||
|
||||
const fixed_t speed = R_PointToDist2(0, 0, player->mo->momx, player->mo->momy);
|
||||
|
||||
P_InstaThrust(player->mo, player->mo->angle, FixedMul(speed, grindscale));
|
||||
|
||||
player->topdriftheld = 0;/* reset after release */
|
||||
}
|
||||
|
||||
if (!onground)
|
||||
{
|
||||
const fixed_t airspeedcap = (50*mapobjectscale);
|
||||
|
|
@ -3169,6 +3188,13 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
|
|||
}
|
||||
}
|
||||
|
||||
/* The Top is Big Large so zoom out */
|
||||
if (player->curshield == KSHIELD_TOP)
|
||||
{
|
||||
camdist += 40 * mapobjectscale;
|
||||
camheight += 40 * mapobjectscale;
|
||||
}
|
||||
|
||||
if (!resetcalled && (leveltime >= introtime && timeover != 2)
|
||||
&& (t_cam_rotate[num] != -42))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@ static angle_t R_PlayerSpriteRotation(player_t *player, player_t *viewPlayer)
|
|||
|
||||
angle_t rollAngle = 0;
|
||||
|
||||
mobj_t *top = K_GetGardenTop(player);
|
||||
|
||||
if (player->mo->eflags & MFE_UNDERWATER)
|
||||
{
|
||||
rollAngle -= player->underwatertilt;
|
||||
|
|
@ -61,6 +63,14 @@ static angle_t R_PlayerSpriteRotation(player_t *player, player_t *viewPlayer)
|
|||
(17 / player->stairjank));
|
||||
}
|
||||
|
||||
if (top)
|
||||
{
|
||||
/* FIXME: why does it not look right at more acute
|
||||
angles without this? There's a related hack to
|
||||
spritexoffset in K_KartPlayerThink. */
|
||||
rollAngle += 3 * (INT32)top->rollangle / 2;
|
||||
}
|
||||
|
||||
return rollAngle;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue