mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
New Ballhog design
Taking the old charge idea, but instead of missiles, it's bananas that explode on the floor and can only be lobbed forward. Charging creates more projectiles in a circle pattern around it.
This commit is contained in:
parent
c0bc1cc245
commit
03874c3374
17 changed files with 642 additions and 161 deletions
|
|
@ -70,6 +70,7 @@
|
|||
#include "sanitize.h"
|
||||
#include "r_fps.h"
|
||||
#include "filesrch.h" // refreshdirmenu
|
||||
#include "k_objects.h"
|
||||
|
||||
// cl loading screen
|
||||
#include "v_video.h"
|
||||
|
|
@ -2510,6 +2511,7 @@ void CL_ClearPlayer(INT32 playernum)
|
|||
P_SetTarget(&players[playernum].whip, NULL);
|
||||
P_SetTarget(&players[playernum].hand, NULL);
|
||||
P_SetTarget(&players[playernum].hoverhyudoro, NULL);
|
||||
P_SetTarget(&players[playernum].ballhogreticule, NULL);
|
||||
P_SetTarget(&players[playernum].ringShooter, NULL);
|
||||
|
||||
// TODO: Any better handling in store?
|
||||
|
|
|
|||
|
|
@ -787,6 +787,7 @@ struct player_t
|
|||
|
||||
UINT16 ballhogcharge; // Ballhog charge up -- the higher this value, the more projectiles
|
||||
boolean ballhogtap; // Ballhog released during charge: used to allow semirapid tapfire
|
||||
mobj_t *ballhogreticule; // First ballhog reticule estimation object
|
||||
|
||||
UINT16 hyudorotimer; // Duration of the Hyudoro offroad effect itself
|
||||
SINT8 stealingtimer; // if >0 you are stealing, if <0 you are being stolen from
|
||||
|
|
|
|||
|
|
@ -1922,6 +1922,7 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
|
|||
"S_BALLHOGBOOM14",
|
||||
"S_BALLHOGBOOM15",
|
||||
"S_BALLHOGBOOM16",
|
||||
"S_BALLHOG_RETICULE",
|
||||
|
||||
// Self-Propelled Bomb - just an explosion for now...
|
||||
"S_SPB1",
|
||||
|
|
@ -3585,6 +3586,8 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
|
|||
|
||||
"MT_BALLHOG", // Ballhog
|
||||
"MT_BALLHOGBOOM",
|
||||
"MT_BALLHOG_RETICULE",
|
||||
"MT_BALLHOG_RETICULE_TEST",
|
||||
|
||||
"MT_SPB", // Self-Propelled Bomb
|
||||
"MT_SPBEXPLOSION",
|
||||
|
|
|
|||
|
|
@ -2429,6 +2429,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
hoverhyudoro = players[player].hoverhyudoro;
|
||||
skyboxviewpoint = players[player].skybox.viewpoint;
|
||||
skyboxcenterpoint = players[player].skybox.centerpoint;
|
||||
|
||||
K_UpdateBallhogReticules(&players[player], 0, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
63
src/info.c
63
src/info.c
|
|
@ -2458,6 +2458,7 @@ state_t states[NUMSTATES] =
|
|||
{SPR_BHBM, FF_FULLBRIGHT|13, 1, {NULL}, 0, 0, S_BALLHOGBOOM15}, // S_BALLHOGBOOM14
|
||||
{SPR_BHBM, FF_FULLBRIGHT|14, 1, {NULL}, 0, 0, S_BALLHOGBOOM16}, // S_BALLHOGBOOM15
|
||||
{SPR_BHBM, FF_FULLBRIGHT|15, 1, {NULL}, 0, 0, S_NULL}, // S_BALLHOGBOOM16
|
||||
{SPR_SPBM, FF_FULLBRIGHT|0, -1, {NULL}, 0, 0, S_NULL}, // S_BALLHOG_RETICULE
|
||||
|
||||
{SPR_SPBM, 0, 1, {NULL}, 0, 0, S_SPB2}, // S_SPB1
|
||||
{SPR_SPBM, 1, 1, {NULL}, 0, 0, S_SPB3}, // S_SPB2
|
||||
|
|
@ -15129,9 +15130,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
{ // MT_BALLHOG
|
||||
-1, // doomednum
|
||||
S_BALLHOG1, // spawnstate
|
||||
140, // spawnhealth
|
||||
1, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
sfx_tossed, // seesound
|
||||
8, // reactiontime
|
||||
sfx_None, // attacksound
|
||||
S_NULL, // painstate
|
||||
|
|
@ -15142,7 +15143,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
S_BALLHOG_DEAD, // deathstate
|
||||
S_NULL, // xdeathstate
|
||||
sfx_hogbom, // deathsound
|
||||
40*FRACUNIT, // speed
|
||||
0, // speed
|
||||
26*FRACUNIT, // radius
|
||||
64*FRACUNIT, // height
|
||||
0, // display offset
|
||||
|
|
@ -15176,7 +15177,61 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
100, // mass
|
||||
1, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_DONTENCOREMAP, // flags
|
||||
MF_NOGRAVITY|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_BALLHOG_RETICULE
|
||||
-1, // doomednum
|
||||
S_BALLHOG_RETICULE, // 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
|
||||
26*FRACUNIT, // radius
|
||||
64*FRACUNIT, // height
|
||||
1, // display offset
|
||||
100, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_SCENERY|MF_NOGRAVITY|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_BALLHOG_RETICULE_TEST
|
||||
-1, // doomednum
|
||||
S_INVISIBLE, // spawnstate
|
||||
1000, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
8, // reactiontime
|
||||
sfx_None, // attacksound
|
||||
S_NULL, // painstate
|
||||
0, // painchance
|
||||
sfx_None, // painsound
|
||||
S_NULL, // meleestate
|
||||
S_NULL, // missilestate
|
||||
S_NULL, // deathstate
|
||||
S_NULL, // xdeathstate
|
||||
sfx_None, // deathsound
|
||||
0, // speed
|
||||
26*FRACUNIT, // radius
|
||||
64*FRACUNIT, // height
|
||||
0, // display offset
|
||||
100, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOTHINK|MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_DONTENCOREMAP|MF_DONTPUNT, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -2949,6 +2949,7 @@ typedef enum state
|
|||
S_BALLHOGBOOM14,
|
||||
S_BALLHOGBOOM15,
|
||||
S_BALLHOGBOOM16,
|
||||
S_BALLHOG_RETICULE,
|
||||
|
||||
// Self-Propelled Bomb
|
||||
S_SPB1,
|
||||
|
|
@ -4639,6 +4640,8 @@ typedef enum mobj_type
|
|||
|
||||
MT_BALLHOG, // Ballhog
|
||||
MT_BALLHOGBOOM,
|
||||
MT_BALLHOG_RETICULE,
|
||||
MT_BALLHOG_RETICULE_TEST,
|
||||
|
||||
MT_SPB, // SPB stuff
|
||||
MT_SPBEXPLOSION,
|
||||
|
|
|
|||
170
src/k_kart.c
170
src/k_kart.c
|
|
@ -556,7 +556,7 @@ UINT8 K_ItemResultToAmount(SINT8 getitem, const itemroulette_t *roulette)
|
|||
return 4;
|
||||
|
||||
case KITEM_BALLHOG: // Not a special result, but has a special amount
|
||||
return 5;
|
||||
return 7;
|
||||
|
||||
case KITEM_SUPERRING:
|
||||
if (roulette && roulette->popcorn)
|
||||
|
|
@ -3157,7 +3157,6 @@ boolean K_WaterSkip(mobj_t *mobj)
|
|||
|
||||
case MT_ORBINAUT:
|
||||
case MT_JAWZ:
|
||||
case MT_BALLHOG:
|
||||
{
|
||||
// Allow
|
||||
break;
|
||||
|
|
@ -5501,7 +5500,7 @@ fixed_t K_DefaultPlayerRadius(player_t *player)
|
|||
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)
|
||||
static mobj_t *K_SpawnKartMissile(mobj_t *source, mobjtype_t type, angle_t an, INT32 flags2, fixed_t speed, fixed_t dir)
|
||||
{
|
||||
mobj_t *th;
|
||||
fixed_t x, y, z;
|
||||
|
|
@ -5555,7 +5554,7 @@ static mobj_t *K_SpawnKartMissile(mobj_t *source, mobjtype_t type, angle_t an, I
|
|||
finalscale = source->scale;
|
||||
}
|
||||
|
||||
if (dir == -1)
|
||||
if (dir < 0)
|
||||
{
|
||||
fixed_t nerf = FRACUNIT;
|
||||
|
||||
|
|
@ -5569,10 +5568,6 @@ static mobj_t *K_SpawnKartMissile(mobj_t *source, mobjtype_t type, angle_t an, I
|
|||
nerf = FRACUNIT/4;
|
||||
break;
|
||||
|
||||
case MT_BALLHOG:
|
||||
nerf = FRACUNIT/8;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -5631,11 +5626,6 @@ static mobj_t *K_SpawnKartMissile(mobj_t *source, mobjtype_t type, angle_t an, I
|
|||
S_StartSound(th, sfx_s3kbfl);
|
||||
S_StartSound(th, sfx_cdfm35);
|
||||
break;
|
||||
case MT_BALLHOG:
|
||||
// Contra spread shot scale up
|
||||
th->destscale = th->destscale << 1;
|
||||
th->scalespeed = abs(th->destscale - th->scale) / (2*TICRATE);
|
||||
break;
|
||||
case MT_GARDENTOP:
|
||||
th->movefactor = finalspeed;
|
||||
break;
|
||||
|
|
@ -6488,10 +6478,10 @@ static mobj_t *K_FindLastTrailMobj(player_t *player)
|
|||
return trail;
|
||||
}
|
||||
|
||||
mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t mapthing, INT32 defaultDir, INT32 altthrow, angle_t angleOffset)
|
||||
mobj_t *K_ThrowKartItemEx(player_t *player, boolean missile, mobjtype_t mapthing, INT32 defaultDir, INT32 altthrow, angle_t angleOffset, fixed_t tossX, fixed_t tossY)
|
||||
{
|
||||
mobj_t *mo;
|
||||
INT32 dir;
|
||||
fixed_t dir = FRACUNIT;
|
||||
fixed_t PROJSPEED;
|
||||
angle_t newangle;
|
||||
fixed_t newx, newy, newz;
|
||||
|
|
@ -6504,36 +6494,29 @@ mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t mapthing,
|
|||
{
|
||||
if (altthrow == 2) // Kitchen sink throwing
|
||||
{
|
||||
#if 0
|
||||
if (player->throwdir == 1)
|
||||
dir = 3;
|
||||
dir = 2 * FRACUNIT;
|
||||
else if (player->throwdir == -1)
|
||||
dir = 1;
|
||||
dir = FRACUNIT / 2;
|
||||
else
|
||||
dir = 2;
|
||||
#else
|
||||
if (player->throwdir == 1)
|
||||
dir = 2;
|
||||
else
|
||||
dir = 1;
|
||||
#endif
|
||||
dir = FRACUNIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (player->throwdir == 1)
|
||||
dir = 2;
|
||||
dir = 2 * FRACUNIT;
|
||||
else if (player->throwdir == -1)
|
||||
dir = -1;
|
||||
dir = -FRACUNIT;
|
||||
else
|
||||
dir = 1;
|
||||
dir = FRACUNIT;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (player->throwdir != 0)
|
||||
dir = player->throwdir;
|
||||
dir = player->throwdir * FRACUNIT;
|
||||
else
|
||||
dir = defaultDir;
|
||||
dir = defaultDir * FRACUNIT;
|
||||
}
|
||||
|
||||
if (mapthing == MT_GACHABOM && dir > 0)
|
||||
|
|
@ -6604,16 +6587,34 @@ mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t mapthing,
|
|||
|
||||
S_StartSound(player->mo, mo->info->seesound);
|
||||
|
||||
{
|
||||
angle_t fa = player->mo->angle>>ANGLETOFINESHIFT;
|
||||
fixed_t HEIGHT = ((20 + (dir*10)) * FRACUNIT) + (FixedDiv(player->mo->momz, mapobjectscale)*P_MobjFlip(player->mo)); // Also intentionally not player scale
|
||||
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->momx = player->mo->momx + FixedMul(FINECOSINE(fa), PROJSPEED*dir);
|
||||
mo->momy = player->mo->momy + FixedMul(FINESINE(fa), PROJSPEED*dir);
|
||||
|
||||
angle_t fa = (player->mo->angle >> ANGLETOFINESHIFT);
|
||||
mo->momx = player->mo->momx + FixedMul(FINECOSINE(fa), FixedMul(PROJSPEED, dir));
|
||||
mo->momy = player->mo->momy + FixedMul( FINESINE(fa), FixedMul(PROJSPEED, dir));
|
||||
|
||||
if (tossX != 0 || tossY != 0)
|
||||
{
|
||||
fixed_t g = 5 * DEFAULT_GRAVITY / 2; // P_GetMobjGravity does not work here??
|
||||
if (dir > FRACUNIT)
|
||||
{
|
||||
g = FixedMul(g, dir);
|
||||
}
|
||||
|
||||
mo->extravalue2 = dir;
|
||||
if (g > 0)
|
||||
{
|
||||
const INT32 air_time = (FixedDiv(mo->momz * P_MobjFlip(mo), g) * 2) / FRACUNIT;
|
||||
|
||||
if (air_time > 0)
|
||||
{
|
||||
mo->momx += FixedMul(tossX, finalscale) / air_time;
|
||||
mo->momy += FixedMul(tossY, finalscale) / air_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mo->eflags & MFE_UNDERWATER)
|
||||
mo->momz = (117 * mo->momz) / 200;
|
||||
|
|
@ -6621,15 +6622,22 @@ mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t mapthing,
|
|||
P_SetScale(mo, finalscale);
|
||||
mo->destscale = finalscale;
|
||||
|
||||
if (mapthing == MT_BANANA)
|
||||
switch (mapthing)
|
||||
{
|
||||
case MT_BANANA:
|
||||
mo->angle = FixedAngle(P_RandomRange(PR_DECORATION, -180, 180) << FRACBITS);
|
||||
mo->rollangle = FixedAngle(P_RandomRange(PR_DECORATION, -180, 180) << FRACBITS);
|
||||
}
|
||||
|
||||
if (mapthing == MT_GACHABOM)
|
||||
{
|
||||
break;
|
||||
case MT_GACHABOM:
|
||||
Obj_GachaBomThrown(mo, mo->radius, dir);
|
||||
break;
|
||||
case MT_BALLHOG:
|
||||
// Contra spread shot scale up
|
||||
mo->destscale = mo->destscale << 1;
|
||||
mo->scalespeed = abs(mo->destscale - mo->scale) / (2*TICRATE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// this is the small graphic effect that plops in you when you throw an item:
|
||||
|
|
@ -6728,7 +6736,7 @@ mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t mapthing,
|
|||
}
|
||||
|
||||
// Missiles set as traps inflict a nocollide stumble
|
||||
if (dir < 0 && (mapthing == MT_ORBINAUT || mapthing == MT_ORBINAUT_SHIELD || mapthing == MT_JAWZ || mapthing == MT_JAWZ_SHIELD || mapthing == MT_BALLHOG || mapthing == MT_GACHABOM))
|
||||
if (dir < 0 && (mapthing == MT_ORBINAUT || mapthing == MT_ORBINAUT_SHIELD || mapthing == MT_JAWZ || mapthing == MT_JAWZ_SHIELD || mapthing == MT_GACHABOM))
|
||||
{
|
||||
mo->cvmem = 1;
|
||||
}
|
||||
|
|
@ -6736,6 +6744,11 @@ mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t mapthing,
|
|||
return mo;
|
||||
}
|
||||
|
||||
mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t mapthing, INT32 defaultDir, INT32 altthrow, angle_t angleOffset)
|
||||
{
|
||||
return K_ThrowKartItemEx(player, missile, mapthing, defaultDir, altthrow, angleOffset, 0, 0);
|
||||
}
|
||||
|
||||
void K_PuntMine(mobj_t *origMine, mobj_t *punter)
|
||||
{
|
||||
angle_t fa = K_MomentumAngle(punter);
|
||||
|
|
@ -13424,7 +13437,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
case KITEM_BALLHOG:
|
||||
if (!HOLDING_ITEM && NO_HYUDORO)
|
||||
{
|
||||
INT32 ballhogmax = (player->itemamount) * BALLHOGINCREMENT;
|
||||
INT32 ballhogmax = player->itemamount * BALLHOGINCREMENT;
|
||||
|
||||
// This construct looks a little goofy, but we're basically just
|
||||
// trying to prevent rapid taps from restarting a charge, while
|
||||
|
|
@ -13437,10 +13450,13 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
if (player->ballhogcharge == 0)
|
||||
player->ballhogtap = false;
|
||||
|
||||
boolean realcharge = (cmd->buttons & BT_ATTACK) && (player->itemflags & IF_HOLDREADY) && (player->ballhogcharge < ballhogmax);
|
||||
boolean realcharge = (cmd->buttons & BT_ATTACK) && (player->itemflags & IF_HOLDREADY) /*&& (player->ballhogcharge < ballhogmax)*/;
|
||||
if ((realcharge && !player->ballhogtap) || (player->ballhogtap && player->ballhogcharge < BALLHOGINCREMENT))
|
||||
{
|
||||
if (player->ballhogcharge < ballhogmax)
|
||||
{
|
||||
player->ballhogcharge++;
|
||||
|
||||
if (player->ballhogcharge % BALLHOGINCREMENT == 0)
|
||||
{
|
||||
sfxenum_t hogsound[] =
|
||||
|
|
@ -13456,6 +13472,27 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
S_StartSound(player->mo, hogsound[chargesound-1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (player->ballhogcharge > 0)
|
||||
{
|
||||
INT32 numhogs = K_HogChargeToHogCount(player->ballhogcharge, player->itemamount);
|
||||
if (numhogs > 0) // no tapfire scams
|
||||
{
|
||||
K_SetItemOut(player); // need this to set itemscale
|
||||
|
||||
player->itemamount -= numhogs;
|
||||
K_PlayAttackTaunt(player->mo);
|
||||
K_DoBallhogAttack(player, numhogs);
|
||||
|
||||
K_UnsetItemOut(player);
|
||||
}
|
||||
|
||||
player->ballhogcharge = 0;
|
||||
player->itemflags &= ~IF_HOLDREADY;
|
||||
player->botvars.itemconfirm = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cmd->buttons & BT_ATTACK)
|
||||
|
|
@ -13466,45 +13503,6 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
{
|
||||
player->itemflags |= IF_HOLDREADY;
|
||||
}
|
||||
|
||||
if (player->ballhogcharge > 0)
|
||||
{
|
||||
INT32 numhogs = min((player->ballhogcharge / BALLHOGINCREMENT), player->itemamount);
|
||||
|
||||
K_SetItemOut(player); // need this to set itemscale
|
||||
|
||||
if (numhogs <= 0)
|
||||
{
|
||||
// no tapfire scams
|
||||
}
|
||||
else if (numhogs == 1)
|
||||
{
|
||||
player->itemamount--;
|
||||
K_ThrowKartItem(player, true, MT_BALLHOG, 1, 0, 0);
|
||||
K_PlayAttackTaunt(player->mo);
|
||||
}
|
||||
else
|
||||
{
|
||||
angle_t cone = 0x01800000 * (numhogs-1);
|
||||
angle_t offsetAmt = (cone * 2) / (numhogs-1);
|
||||
angle_t angleOffset = cone;
|
||||
INT32 i;
|
||||
|
||||
player->itemamount -= numhogs;
|
||||
|
||||
for (i = 0; i < numhogs; i++)
|
||||
{
|
||||
K_ThrowKartItem(player, true, MT_BALLHOG, 1, 0, angleOffset);
|
||||
angleOffset -= offsetAmt;
|
||||
}
|
||||
|
||||
K_PlayAttackTaunt(player->mo);
|
||||
}
|
||||
|
||||
K_UnsetItemOut(player);
|
||||
player->ballhogcharge = 0;
|
||||
player->itemflags &= ~IF_HOLDREADY;
|
||||
player->botvars.itemconfirm = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -14379,6 +14377,12 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
|
||||
Obj_PlayerBulbThink(player);
|
||||
|
||||
UINT8 hog_count = 0;
|
||||
if (player->itemtype == KITEM_BALLHOG)
|
||||
{
|
||||
hog_count = K_HogChargeToHogCount(player->ballhogcharge, player->itemamount);
|
||||
}
|
||||
K_UpdateBallhogReticules(player, hog_count, false);
|
||||
}
|
||||
|
||||
void K_CheckSpectateStatus(boolean considermapreset)
|
||||
|
|
|
|||
|
|
@ -177,6 +177,7 @@ void K_SpawnDraftDust(mobj_t *mo);
|
|||
void K_SpawnMagicianParticles(mobj_t *mo, int spread);
|
||||
void K_DriftDustHandling(mobj_t *spawner);
|
||||
void K_Squish(mobj_t *mo);
|
||||
mobj_t *K_ThrowKartItemEx(player_t *player, boolean missile, mobjtype_t mapthing, INT32 defaultDir, INT32 altthrow, angle_t angleOffset, fixed_t tossX, fixed_t tossY);
|
||||
mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t mapthing, INT32 defaultDir, INT32 altthrow, angle_t angleOffset);
|
||||
void K_PuntMine(mobj_t *mine, mobj_t *punter);
|
||||
void K_DoSneaker(player_t *player, INT32 type);
|
||||
|
|
|
|||
|
|
@ -64,8 +64,8 @@ mobj_t *Obj_MantaRingCreate(mobj_t *spb, mobj_t *owner, mobj_t *chase);
|
|||
/* Orbinaut */
|
||||
void Obj_OrbinautThink(mobj_t *th);
|
||||
boolean Obj_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2);
|
||||
void Obj_OrbinautThrown(mobj_t *th, fixed_t finalSpeed, SINT8 dir);
|
||||
void Obj_GachaBomThrown(mobj_t *th, fixed_t finalSpeed, SINT8 dir);
|
||||
void Obj_OrbinautThrown(mobj_t *th, fixed_t finalSpeed, fixed_t dir);
|
||||
void Obj_GachaBomThrown(mobj_t *th, fixed_t finalSpeed, fixed_t dir);
|
||||
void Obj_OrbinautJawzMoveHeld(player_t *player);
|
||||
boolean Obj_GachaBomWasTossed(mobj_t *th);
|
||||
void Obj_OrbinautDrop(mobj_t *th);
|
||||
|
|
@ -73,7 +73,7 @@ boolean Obj_OrbinautCanRunOnWater(mobj_t *th);
|
|||
|
||||
/* Jawz */
|
||||
void Obj_JawzThink(mobj_t *th);
|
||||
void Obj_JawzThrown(mobj_t *th, fixed_t finalSpeed, SINT8 dir);
|
||||
void Obj_JawzThrown(mobj_t *th, fixed_t finalSpeed, fixed_t dir);
|
||||
|
||||
/* Duel Bomb */
|
||||
void Obj_DuelBombThink(mobj_t *bomb);
|
||||
|
|
@ -439,6 +439,11 @@ void Obj_DestroyedKartParticleLanding(mobj_t *part);
|
|||
void Obj_PulleyThink(mobj_t *root);
|
||||
void Obj_PulleyHookTouch(mobj_t *special, mobj_t *toucher);
|
||||
|
||||
/* Ballhog */
|
||||
UINT8 K_HogChargeToHogCount(INT32 charge, UINT8 cap);
|
||||
void K_UpdateBallhogReticules(player_t *player, UINT8 num_hogs, boolean on_release);
|
||||
void K_DoBallhogAttack(player_t *player, UINT8 num_hogs);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ target_sources(SRB2SDL2 PRIVATE
|
|||
destroyed-kart.cpp
|
||||
pulley.cpp
|
||||
amps.c
|
||||
ballhog.cpp
|
||||
)
|
||||
|
||||
add_subdirectory(versus)
|
||||
|
|
|
|||
383
src/objects/ballhog.cpp
Normal file
383
src/objects/ballhog.cpp
Normal file
|
|
@ -0,0 +1,383 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2024 by Sally "TehRealSalt" Cochenour
|
||||
// Copyright (C) 2024 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file ballhog.cpp
|
||||
/// \brief Ballhog item code.
|
||||
|
||||
#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_main.h"
|
||||
#include "../s_sound.h"
|
||||
#include "../g_game.h"
|
||||
#include "../z_zone.h"
|
||||
#include "../k_collide.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct hog_angles
|
||||
{
|
||||
fixed_t x, y;
|
||||
hog_angles(fixed_t nx, fixed_t ny) : x(nx), y(ny) {}
|
||||
};
|
||||
|
||||
std::vector<struct hog_angles> g_hogangles;
|
||||
|
||||
};
|
||||
|
||||
static void CalculateHogAngles(UINT8 n)
|
||||
{
|
||||
const UINT8 total_hogs = n;
|
||||
|
||||
// This algorithm should probably be replaced to
|
||||
// maximize more space covered, but the desired effect
|
||||
// is achieved for 1 to 5, which is the vast majority of uses.
|
||||
g_hogangles.clear();
|
||||
|
||||
if (total_hogs == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (total_hogs == 1 || total_hogs > 4)
|
||||
{
|
||||
// Add a point to the exact middle.
|
||||
g_hogangles.emplace_back(0, 0);
|
||||
n--;
|
||||
}
|
||||
|
||||
if (total_hogs > 1)
|
||||
{
|
||||
const fixed_t base_radius = mobjinfo[MT_BALLHOG].radius * 3 / 2;
|
||||
fixed_t radius = base_radius;
|
||||
UINT8 max_points = 6;
|
||||
angle_t circle_offset = 0;
|
||||
|
||||
if (total_hogs < 5)
|
||||
{
|
||||
// Reduce size to get more space covered.
|
||||
radius /= 2;
|
||||
max_points = 4;
|
||||
}
|
||||
|
||||
while (n > 0)
|
||||
{
|
||||
const UINT8 add_points = std::min<UINT8>(n, max_points);
|
||||
|
||||
angle_t angle = circle_offset;
|
||||
const angle_t angle_offset = ANGLE_MAX / add_points;
|
||||
|
||||
for (UINT8 c = 0; c < add_points; c++)
|
||||
{
|
||||
g_hogangles.emplace_back(
|
||||
FixedMul(FINECOSINE( angle >> ANGLETOFINESHIFT ), radius),
|
||||
FixedMul( FINESINE( angle >> ANGLETOFINESHIFT ), radius)
|
||||
);
|
||||
angle += angle_offset;
|
||||
n--;
|
||||
}
|
||||
|
||||
radius += base_radius;
|
||||
circle_offset += ANGLE_MAX / max_points;
|
||||
max_points += (max_points / 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UINT8 K_HogChargeToHogCount(INT32 charge, UINT8 cap)
|
||||
{
|
||||
return std::clamp<UINT8>((charge / BALLHOGINCREMENT), 0, cap);
|
||||
}
|
||||
|
||||
static boolean HogReticuleEmulate(mobj_t *mobj)
|
||||
{
|
||||
fixed_t x, y, z;
|
||||
|
||||
//I_Assert(mobj != NULL);
|
||||
//I_Assert(P_MobjWasRemoved(mobj) == false);
|
||||
|
||||
x = mobj->x, y = mobj->y, z = mobj->z;
|
||||
|
||||
//if (mobj->momx || mobj->momy)
|
||||
{
|
||||
if (P_XYMovement(mobj) == false)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (P_MobjWasRemoved(mobj) == true)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//if (mobj->momz)
|
||||
{
|
||||
if (P_ZMovement(mobj) == false)
|
||||
{
|
||||
return true; // mobj was removed
|
||||
}
|
||||
|
||||
//P_CheckPosition(mobj, mobj->x, mobj->y, NULL);
|
||||
}
|
||||
|
||||
return (P_MobjWasRemoved(mobj) == true || (x == mobj->x && y == mobj->y && z == mobj->z));
|
||||
}
|
||||
|
||||
static void HogReticuleTest(player_t *player, vector3_t *ret)
|
||||
{
|
||||
// Emulate the movement of a tossed ballhog
|
||||
// until it hits something.
|
||||
|
||||
fixed_t dir = FRACUNIT;
|
||||
if (player->throwdir == 1)
|
||||
{
|
||||
dir = 2*FRACUNIT;
|
||||
}
|
||||
else if (player->throwdir == -1)
|
||||
{
|
||||
dir = FRACUNIT/2;
|
||||
}
|
||||
|
||||
// Use pre-determined speed for tossing
|
||||
fixed_t proj_speed = FixedMul(82 * FRACUNIT, K_GetKartGameSpeedScalar(gamespeed));
|
||||
|
||||
// Scale to map scale
|
||||
// Intentionally NOT player scale, that doesn't work.
|
||||
proj_speed = FixedMul(proj_speed, mapobjectscale);
|
||||
|
||||
fixed_t finalscale = ITEMSCALE_NORMAL;
|
||||
if (player->mo->scale >= FixedMul(GROW_PHYSICS_SCALE, mapobjectscale))
|
||||
{
|
||||
finalscale = ITEMSCALE_GROW;
|
||||
}
|
||||
else if (player->mo->scale <= FixedMul(SHRINK_PHYSICS_SCALE, mapobjectscale))
|
||||
{
|
||||
finalscale = ITEMSCALE_SHRINK;
|
||||
}
|
||||
|
||||
// Shoot forward
|
||||
//P_MoveOrigin(mo, player->mo->x, player->mo->y, player->mo->z + (player->mo->height / 2));
|
||||
// FINE! YOU WIN! I'll make an object every time I need to test this...
|
||||
mobj_t *mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z + (player->mo->height / 2), MT_BALLHOG_RETICULE_TEST);
|
||||
mo->fuse = 2; // if something goes wrong, destroy this
|
||||
|
||||
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)
|
||||
{
|
||||
mo->z -= player->mo->height;
|
||||
mo->eflags |= MFE_VERTICALFLIP;
|
||||
mo->flags2 |= (player->mo->flags2 & MF2_OBJECTFLIP);
|
||||
}
|
||||
|
||||
//P_SetTarget(&mo->target, player->mo);
|
||||
|
||||
mo->extravalue2 = dir;
|
||||
|
||||
fixed_t proj_speed_z = ((20 * FRACUNIT) + (10 * dir)) + (FixedDiv(player->mo->momz, mapobjectscale) * P_MobjFlip(player->mo)); // Also intentionally not player scale
|
||||
P_SetObjectMomZ(mo, proj_speed_z, false);
|
||||
|
||||
angle_t fa = (player->mo->angle >> ANGLETOFINESHIFT);
|
||||
mo->momx = player->mo->momx + FixedMul(FINECOSINE(fa), FixedMul(proj_speed, dir));
|
||||
mo->momy = player->mo->momy + FixedMul( FINESINE(fa), FixedMul(proj_speed, dir));
|
||||
|
||||
if (mo->eflags & MFE_UNDERWATER)
|
||||
{
|
||||
mo->momz = (117 * mo->momz) / 200;
|
||||
}
|
||||
|
||||
P_SetScale(mo, finalscale);
|
||||
mo->destscale = finalscale;
|
||||
|
||||
// Contra spread shot scale up
|
||||
//mo->destscale = mo->destscale << 1;
|
||||
//mo->scalespeed = abs(mo->destscale - mo->scale) / (2*TICRATE);
|
||||
|
||||
ret->x = mo->x;
|
||||
ret->y = mo->y;
|
||||
ret->z = mo->z;
|
||||
|
||||
constexpr INT32 max_iteration = 256;
|
||||
for (INT32 i = 0; i < max_iteration; i++)
|
||||
{
|
||||
if (HogReticuleEmulate(mo) == true)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
ret->x = mo->x;
|
||||
ret->y = mo->y;
|
||||
ret->z = mo->z;
|
||||
}
|
||||
|
||||
P_RemoveMobj(mo);
|
||||
}
|
||||
|
||||
void K_UpdateBallhogReticules(player_t *player, UINT8 num_hogs, boolean on_release)
|
||||
{
|
||||
if (player == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (player->mo == nullptr || P_MobjWasRemoved(player->mo) == true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr tic_t kBallhogReticuleTime = TICRATE / 2;
|
||||
|
||||
const UINT8 start_hogs = num_hogs;
|
||||
CalculateHogAngles(num_hogs);
|
||||
|
||||
// Calculate center positon
|
||||
vector3_t center = {0, 0, 0};
|
||||
HogReticuleTest(player, ¢er); // Originally this was called for everything, but it's more optimized to only run 1 prediction.
|
||||
|
||||
// Update existing reticules.
|
||||
mobj_t *reticule = player->ballhogreticule;
|
||||
while (reticule != nullptr && P_MobjWasRemoved(reticule) == false)
|
||||
{
|
||||
mobj_t *next = reticule->hnext;
|
||||
boolean removed = false;
|
||||
|
||||
if (num_hogs > 0)
|
||||
{
|
||||
const UINT8 old_hogs = reticule->extravalue1;
|
||||
|
||||
UINT8 angle_index = num_hogs - 1;
|
||||
fixed_t x_offset = g_hogangles[angle_index].x;
|
||||
fixed_t y_offset = g_hogangles[angle_index].y;
|
||||
|
||||
if (on_release == true)
|
||||
{
|
||||
reticule->extravalue1 = start_hogs;
|
||||
P_MoveOrigin(
|
||||
reticule,
|
||||
center.x + x_offset,
|
||||
center.y + y_offset,
|
||||
center.z
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (start_hogs != old_hogs)
|
||||
{
|
||||
// Reset to the middle
|
||||
P_SetOrigin(reticule, center.x, center.y, center.z);
|
||||
reticule->extravalue1 = start_hogs;
|
||||
}
|
||||
|
||||
// Move to new position
|
||||
P_MoveOrigin(
|
||||
reticule,
|
||||
reticule->x + (((center.x + x_offset) - reticule->x) / (BALLHOGINCREMENT / 2)),
|
||||
reticule->y + (((center.y + y_offset) - reticule->y) / (BALLHOGINCREMENT / 2)),
|
||||
reticule->z + ((center.z - reticule->z) / (BALLHOGINCREMENT / 2))
|
||||
);
|
||||
}
|
||||
|
||||
reticule->tics = kBallhogReticuleTime;
|
||||
num_hogs--;
|
||||
}
|
||||
#if 0
|
||||
else
|
||||
{
|
||||
// Too many reticules exist, so remove the remainder.
|
||||
P_RemoveMobj(reticule);
|
||||
removed = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (next == nullptr || P_MobjWasRemoved(next) == true)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (removed == true)
|
||||
{
|
||||
P_SetTarget(&next->hprev, nullptr);
|
||||
}
|
||||
reticule = next;
|
||||
}
|
||||
|
||||
// Not enough reticules exist, so make new ones.
|
||||
while (num_hogs > 0)
|
||||
{
|
||||
mobj_t *new_reticule = P_SpawnMobjFromMobj((reticule != nullptr) ? reticule : player->mo, 0, 0, 0, MT_BALLHOG_RETICULE);
|
||||
if (new_reticule == nullptr)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (reticule != nullptr)
|
||||
{
|
||||
P_SetTarget(&reticule->hnext, new_reticule);
|
||||
P_SetTarget(&new_reticule->hprev, reticule);
|
||||
}
|
||||
else
|
||||
{
|
||||
P_SetTarget(&player->ballhogreticule, new_reticule);
|
||||
P_SetTarget(&new_reticule->hprev, player->mo);
|
||||
}
|
||||
|
||||
// Start in center
|
||||
new_reticule->extravalue1 = start_hogs;
|
||||
new_reticule->tics = kBallhogReticuleTime;
|
||||
|
||||
if (on_release == true)
|
||||
{
|
||||
UINT8 angle_index = num_hogs - 1;
|
||||
fixed_t x_offset = g_hogangles[angle_index].x;
|
||||
fixed_t y_offset = g_hogangles[angle_index].y;
|
||||
|
||||
P_SetOrigin(new_reticule, center.x + x_offset, center.y + y_offset, center.z);
|
||||
}
|
||||
else
|
||||
{
|
||||
P_SetOrigin(new_reticule, center.x, center.y, center.z);
|
||||
}
|
||||
|
||||
reticule = new_reticule;
|
||||
num_hogs--;
|
||||
}
|
||||
}
|
||||
|
||||
void K_DoBallhogAttack(player_t *player, UINT8 num_hogs)
|
||||
{
|
||||
// Update reticules instantly, then untie them to us.
|
||||
K_UpdateBallhogReticules(player, num_hogs, true);
|
||||
P_SetTarget(&player->ballhogreticule, nullptr);
|
||||
|
||||
CalculateHogAngles(num_hogs);
|
||||
|
||||
while (num_hogs > 0)
|
||||
{
|
||||
UINT8 angle_index = num_hogs - 1;
|
||||
|
||||
fixed_t x_offset = g_hogangles[angle_index].x;
|
||||
fixed_t y_offset = g_hogangles[angle_index].y;
|
||||
|
||||
K_ThrowKartItemEx(
|
||||
player,
|
||||
false, MT_BALLHOG, 1, 2,
|
||||
0,
|
||||
x_offset, y_offset
|
||||
);
|
||||
|
||||
num_hogs--;
|
||||
}
|
||||
}
|
||||
|
|
@ -253,7 +253,7 @@ void Obj_JawzThink(mobj_t *th)
|
|||
}
|
||||
}
|
||||
|
||||
void Obj_JawzThrown(mobj_t *th, fixed_t finalSpeed, SINT8 dir)
|
||||
void Obj_JawzThrown(mobj_t *th, fixed_t finalSpeed, fixed_t dir)
|
||||
{
|
||||
INT32 lastTarg = -1;
|
||||
player_t *owner = NULL;
|
||||
|
|
@ -270,7 +270,7 @@ void Obj_JawzThrown(mobj_t *th, fixed_t finalSpeed, SINT8 dir)
|
|||
jawz_retcolor(th) = SKINCOLOR_KETCHUP;
|
||||
}
|
||||
|
||||
if (dir == -1)
|
||||
if (dir < 0)
|
||||
{
|
||||
// Thrown backwards, init self-chase
|
||||
P_SetTarget(&jawz_chase(th), jawz_owner(th));
|
||||
|
|
|
|||
|
|
@ -323,7 +323,7 @@ boolean Obj_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2)
|
|||
return true;
|
||||
}
|
||||
|
||||
void Obj_OrbinautThrown(mobj_t *th, fixed_t finalSpeed, SINT8 dir)
|
||||
void Obj_OrbinautThrown(mobj_t *th, fixed_t finalSpeed, fixed_t dir)
|
||||
{
|
||||
orbinaut_flags(th) = 0;
|
||||
|
||||
|
|
@ -335,7 +335,7 @@ void Obj_OrbinautThrown(mobj_t *th, fixed_t finalSpeed, SINT8 dir)
|
|||
const mobj_t *owner = orbinaut_owner(th);
|
||||
const ffloor_t *rover = P_IsObjectFlipped(owner) ? owner->ceilingrover : owner->floorrover;
|
||||
|
||||
if (dir != -1 && rover && (rover->fofflags & FOF_SWIMMABLE))
|
||||
if (dir >= 0 && rover && (rover->fofflags & FOF_SWIMMABLE))
|
||||
{
|
||||
// The owner can run on water, so we should too!
|
||||
orbinaut_flags(th) |= ORBI_WATERSKI;
|
||||
|
|
@ -351,7 +351,7 @@ void Obj_OrbinautThrown(mobj_t *th, fixed_t finalSpeed, SINT8 dir)
|
|||
|
||||
orbinaut_flags(th) |= ORBI_TRAIL;
|
||||
|
||||
if (dir == -1)
|
||||
if (dir < 0)
|
||||
{
|
||||
// Thrown backwards, init orbiting in place
|
||||
orbinaut_turn(th) = ORBINAUT_MAXTURN / ORBINAUT_TURNLERP;
|
||||
|
|
@ -362,21 +362,19 @@ void Obj_OrbinautThrown(mobj_t *th, fixed_t finalSpeed, SINT8 dir)
|
|||
}
|
||||
}
|
||||
|
||||
void Obj_GachaBomThrown(mobj_t *th, fixed_t finalSpeed, SINT8 dir)
|
||||
void Obj_GachaBomThrown(mobj_t *th, fixed_t finalSpeed, fixed_t dir)
|
||||
{
|
||||
Obj_OrbinautThrown(th, finalSpeed, dir);
|
||||
|
||||
orbinaut_flags(th) &= ~(ORBI_TRAIL);
|
||||
|
||||
switch (dir)
|
||||
if (dir < 0)
|
||||
{
|
||||
case -1:
|
||||
orbinaut_flags(th) |= ORBI_SPIN;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
}
|
||||
else if (dir > 0)
|
||||
{
|
||||
orbinaut_flags(th) |= ORBI_TOSSED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
83
src/p_mobj.c
83
src/p_mobj.c
|
|
@ -594,18 +594,19 @@ void P_ExplodeMissile(mobj_t *mo)
|
|||
|
||||
mo->momx = mo->momy = mo->momz = 0;
|
||||
|
||||
if (mo->flags & MF_NOCLIPTHING)
|
||||
if (mo->flags2 & MF2_BOSSDEAD)
|
||||
return;
|
||||
|
||||
mo->flags &= ~MF_MISSILE;
|
||||
|
||||
mo->flags |= MF_NOGRAVITY; // Dead missiles don't need to sink anymore.
|
||||
mo->flags |= MF_NOCLIPTHING; // Dummy flag to indicate that this was already called.
|
||||
mo->flags2 |= MF2_BOSSDEAD; // Dummy flag to indicate that this was already called.
|
||||
|
||||
if (mo->info->deathsound && !(mo->flags2 & MF2_DEBRIS))
|
||||
S_StartSound(mo, mo->info->deathsound);
|
||||
|
||||
P_SetMobjState(mo, mo->info->deathstate);
|
||||
mo->health = 0;
|
||||
}
|
||||
|
||||
// P_InsideANonSolidFFloor
|
||||
|
|
@ -1059,6 +1060,8 @@ static boolean P_UseUnderwaterGravity(mobj_t *mo)
|
|||
switch (mo->type)
|
||||
{
|
||||
case MT_BANANA:
|
||||
case MT_BALLHOG:
|
||||
case MT_BALLHOG_RETICULE_TEST:
|
||||
return false;
|
||||
|
||||
case MT_GACHABOM:
|
||||
|
|
@ -1247,6 +1250,8 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
|
|||
gravityadd = (5*gravityadd)/2;
|
||||
break;
|
||||
case MT_BANANA:
|
||||
case MT_BALLHOG:
|
||||
case MT_BALLHOG_RETICULE_TEST:
|
||||
case MT_EGGMANITEM:
|
||||
case MT_SSMINE:
|
||||
case MT_LANDMINE:
|
||||
|
|
@ -1255,9 +1260,9 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
|
|||
case MT_EMERALD:
|
||||
if (mo->health > 0)
|
||||
{
|
||||
if (mo->extravalue2 > 0)
|
||||
if (mo->extravalue2 > FRACUNIT)
|
||||
{
|
||||
gravityadd *= mo->extravalue2;
|
||||
gravityadd = FixedMul(gravityadd, mo->extravalue2);
|
||||
}
|
||||
|
||||
gravityadd = (5*gravityadd)/2;
|
||||
|
|
@ -1600,7 +1605,7 @@ static boolean P_CheckSkyHit(mobj_t *mo)
|
|||
//
|
||||
// P_XYMovement
|
||||
//
|
||||
void P_XYMovement(mobj_t *mo)
|
||||
boolean P_XYMovement(mobj_t *mo)
|
||||
{
|
||||
player_t *player;
|
||||
fixed_t xmove, ymove;
|
||||
|
|
@ -1626,7 +1631,7 @@ void P_XYMovement(mobj_t *mo)
|
|||
// set in 'search new direction' state?
|
||||
P_SetMobjState(mo, mo->info->spawnstate);
|
||||
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1676,21 +1681,6 @@ void P_XYMovement(mobj_t *mo)
|
|||
if (CheckForBustableBlocks && ((mo->flags & MF_PUSHABLE) || ((mo->info->flags & MF_PUSHABLE) && mo->fuse)))
|
||||
P_PushableCheckBustables(mo);
|
||||
|
||||
//{ SRB2kart - Ballhogs
|
||||
if (mo->type == MT_BALLHOG)
|
||||
{
|
||||
if (mo->health)
|
||||
{
|
||||
mo->health--;
|
||||
if (mo->health == 0)
|
||||
{
|
||||
mo->scalespeed = mo->scale/12;
|
||||
mo->destscale = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
//}
|
||||
|
||||
if (!P_TryMove(mo, mo->x + xmove, mo->y + ymove, true, &result)
|
||||
&& !(P_MobjWasRemoved(mo) || mo->eflags & MFE_SPRUNG))
|
||||
{
|
||||
|
|
@ -1700,13 +1690,18 @@ void P_XYMovement(mobj_t *mo)
|
|||
if (LUA_HookMobjMoveBlocked(mo, g_tm.hitthing, result.line))
|
||||
{
|
||||
if (P_MobjWasRemoved(mo))
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
else if (P_MobjWasRemoved(mo))
|
||||
return;
|
||||
return false;
|
||||
|
||||
P_PushSpecialLine(result.line, mo);
|
||||
|
||||
if (mo->type == MT_BALLHOG_RETICULE_TEST)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mo->flags & MF_MISSILE)
|
||||
{
|
||||
// explode a missile
|
||||
|
|
@ -1718,7 +1713,7 @@ void P_XYMovement(mobj_t *mo)
|
|||
// Check frontsector as well.
|
||||
|
||||
P_RemoveMobj(mo);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// draw damage on wall
|
||||
|
|
@ -1745,7 +1740,7 @@ void P_XYMovement(mobj_t *mo)
|
|||
// --------------------------------------------------------- SPLAT TEST
|
||||
|
||||
P_ExplodeMissile(mo);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1807,14 +1802,14 @@ void P_XYMovement(mobj_t *mo)
|
|||
{
|
||||
P_SlideMove(mo, &result);
|
||||
if (P_MobjWasRemoved(mo))
|
||||
return;
|
||||
return false;
|
||||
xmove = ymove = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
P_BounceMove(mo, &result);
|
||||
if (P_MobjWasRemoved(mo))
|
||||
return;
|
||||
return false;
|
||||
xmove = ymove = 0;
|
||||
S_StartSound(mo, mo->info->activesound);
|
||||
|
||||
|
|
@ -1822,9 +1817,7 @@ void P_XYMovement(mobj_t *mo)
|
|||
// Ballhog dies on contact with walls
|
||||
if (mo->type == MT_BALLHOG)
|
||||
{
|
||||
S_StartSound(mo, mo->info->deathsound);
|
||||
P_KillMobj(mo, NULL, NULL, DMG_NORMAL);
|
||||
return;
|
||||
P_ExplodeMissile(mo);
|
||||
}
|
||||
// Bump sparks
|
||||
else if (mo->type == MT_ORBINAUT || mo->type == MT_GACHABOM)
|
||||
|
|
@ -1886,7 +1879,7 @@ void P_XYMovement(mobj_t *mo)
|
|||
moved = true;
|
||||
|
||||
if (P_MobjWasRemoved(mo)) // MF_SPECIAL touched a player! O_o;;
|
||||
return;
|
||||
return false;
|
||||
|
||||
if (moved == true)
|
||||
{
|
||||
|
|
@ -1963,29 +1956,30 @@ void P_XYMovement(mobj_t *mo)
|
|||
P_CheckGravity(mo, false);
|
||||
|
||||
if (mo->flags & MF_NOCLIPHEIGHT)
|
||||
return; // no frictions for objects that can pass through floors
|
||||
return moved; // no frictions for objects that can pass through floors
|
||||
|
||||
if (mo->flags & MF_MISSILE || mo->flags2 & MF2_SKULLFLY)
|
||||
return; // no friction for missiles ever
|
||||
return moved; // no friction for missiles ever
|
||||
|
||||
if ((mo->type == MT_BIGTUMBLEWEED || mo->type == MT_LITTLETUMBLEWEED)
|
||||
&& (mo->standingslope && abs(mo->standingslope->zdelta) > FRACUNIT>>8)) // Special exception for tumbleweeds on slopes
|
||||
return;
|
||||
return moved;
|
||||
|
||||
//{ SRB2kart stuff
|
||||
if (mo->type == MT_FLINGRING || mo->type == MT_BALLHOG || mo->type == MT_BUBBLESHIELDTRAP)
|
||||
return;
|
||||
if (mo->type == MT_FLINGRING || mo->type == MT_BALLHOG || mo->type == MT_BALLHOG_RETICULE_TEST || mo->type == MT_BUBBLESHIELDTRAP)
|
||||
return moved;
|
||||
|
||||
if (player && (player->spinouttimer && !player->wipeoutslow)
|
||||
&& player->speed <= FixedDiv(20*mapobjectscale, player->offroad + FRACUNIT))
|
||||
return;
|
||||
return moved;
|
||||
//}
|
||||
|
||||
if (((!(mo->eflags & MFE_VERTICALFLIP) && (mo->momz > 0 || mo->z > mo->floorz)) || (mo->eflags & MFE_VERTICALFLIP && (mo->momz < 0 || mo->z+mo->height < mo->ceilingz)))
|
||||
&& !(player && player->carry == CR_SLIDING))
|
||||
return; // no friction when airborne
|
||||
return moved; // no friction when airborne
|
||||
|
||||
P_XYFriction(mo, oldx, oldy);
|
||||
return moved;
|
||||
}
|
||||
|
||||
void P_RingXYMovement(mobj_t *mo)
|
||||
|
|
@ -2328,6 +2322,19 @@ boolean P_ZMovement(mobj_t *mo)
|
|||
return false;
|
||||
}
|
||||
break;
|
||||
case MT_BALLHOG:
|
||||
if (mo->z <= mo->floorz || mo->z + mo->height >= mo->ceilingz)
|
||||
{
|
||||
P_ExplodeMissile(mo);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case MT_BALLHOG_RETICULE_TEST:
|
||||
if (mo->z <= mo->floorz || mo->z + mo->height >= mo->ceilingz)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// SRB2kart stuff that should die in pits
|
||||
// Shouldn't stop moving along the Z if there's no speed though!
|
||||
|
|
|
|||
|
|
@ -578,7 +578,7 @@ void P_NullPrecipThinker(precipmobj_t *mobj);
|
|||
void P_FreePrecipMobj(precipmobj_t *mobj);
|
||||
void P_SetScale(mobj_t *mobj, fixed_t newscale);
|
||||
void P_InstaScale(mobj_t *mobj, fixed_t newscale);
|
||||
void P_XYMovement(mobj_t *mo);
|
||||
boolean P_XYMovement(mobj_t *mo);
|
||||
void P_RingXYMovement(mobj_t *mo);
|
||||
void P_SceneryXYMovement(mobj_t *mo);
|
||||
boolean P_ZMovement(mobj_t *mo);
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ typedef enum
|
|||
FLICKYCONTROLLER = 0x1000,
|
||||
TRICKINDICATOR = 0x2000,
|
||||
BARRIER = 0x4000,
|
||||
BALLHOGRETICULE = 0x8000, // uh oh, we're full now...
|
||||
} player_saveflags;
|
||||
|
||||
static inline void P_ArchivePlayer(savebuffer_t *save)
|
||||
|
|
@ -325,6 +326,9 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
|||
if (players[i].hoverhyudoro)
|
||||
flags |= HOVERHYUDORO;
|
||||
|
||||
if (players[i].ballhogreticule)
|
||||
flags |= BALLHOGRETICULE;
|
||||
|
||||
if (players[i].stumbleIndicator)
|
||||
flags |= STUMBLE;
|
||||
|
||||
|
|
@ -369,6 +373,9 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
|||
if (flags & HOVERHYUDORO)
|
||||
WRITEUINT32(save->p, players[i].hoverhyudoro->mobjnum);
|
||||
|
||||
if (flags & BALLHOGRETICULE)
|
||||
WRITEUINT32(save->p, players[i].ballhogreticule->mobjnum);
|
||||
|
||||
if (flags & STUMBLE)
|
||||
WRITEUINT32(save->p, players[i].stumbleIndicator->mobjnum);
|
||||
|
||||
|
|
@ -989,6 +996,9 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
|
|||
if (flags & HOVERHYUDORO)
|
||||
players[i].hoverhyudoro = (mobj_t *)(size_t)READUINT32(save->p);
|
||||
|
||||
if (flags & BALLHOGRETICULE)
|
||||
players[i].ballhogreticule = (mobj_t *)(size_t)READUINT32(save->p);
|
||||
|
||||
if (flags & STUMBLE)
|
||||
players[i].stumbleIndicator = (mobj_t *)(size_t)READUINT32(save->p);
|
||||
|
||||
|
|
@ -5971,6 +5981,11 @@ static void P_RelinkPointers(void)
|
|||
if (!RelinkMobj(&players[i].hoverhyudoro))
|
||||
CONS_Debug(DBG_GAMELOGIC, "hoverhyudoro not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].ballhogreticule)
|
||||
{
|
||||
if (!RelinkMobj(&players[i].ballhogreticule))
|
||||
CONS_Debug(DBG_GAMELOGIC, "ballhogreticule not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].stumbleIndicator)
|
||||
{
|
||||
if (!RelinkMobj(&players[i].stumbleIndicator))
|
||||
|
|
|
|||
|
|
@ -4244,6 +4244,7 @@ void P_PlayerThink(player_t *player)
|
|||
PlayerPointerErase(player->hand);
|
||||
PlayerPointerErase(player->ringShooter);
|
||||
PlayerPointerErase(player->hoverhyudoro);
|
||||
PlayerPointerErase(player->ballhogreticule);
|
||||
PlayerPointerErase(player->flickyAttacker);
|
||||
PlayerPointerErase(player->powerup.flickyController);
|
||||
PlayerPointerErase(player->powerup.barrier);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue