mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Merge branch 'super-flicky' into 'master'
Battle: Super Flicky power-up, give power-up command, general functions for interfacing power-ups (also Lua) See merge request KartKrew/Kart!1301
This commit is contained in:
commit
f393b9782b
23 changed files with 1202 additions and 48 deletions
|
|
@ -146,6 +146,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
|
|||
k_serverstats.c
|
||||
k_zvote.c
|
||||
k_mapuser.c
|
||||
k_powerup.cpp
|
||||
)
|
||||
|
||||
if(SRB2_CONFIG_ENABLE_WEBM_MOVIES)
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@
|
|||
#include "k_vote.h"
|
||||
#include "k_zvote.h"
|
||||
#include "k_bot.h"
|
||||
#include "k_powerup.h"
|
||||
|
||||
#ifdef SRB2_CONFIG_ENABLE_WEBM_MOVIES
|
||||
#include "m_avrecorder.h"
|
||||
|
|
@ -442,6 +443,11 @@ static CV_PossibleValue_t kartdebugitem_cons_t[] =
|
|||
#define FOREACH( name, n ) { n, #name }
|
||||
KART_ITEM_ITERATOR,
|
||||
#undef FOREACH
|
||||
{POWERUP_SMONITOR, "SMonitor"},
|
||||
{POWERUP_BARRIER, "Barrier"},
|
||||
{POWERUP_BUMPER, "Bumper"},
|
||||
{POWERUP_BADGE, "Badge"},
|
||||
{POWERUP_SUPERFLICKY, "SuperFlicky"},
|
||||
{0}
|
||||
};
|
||||
consvar_t cv_kartdebugitem = CVAR_INIT ("debugitem", "None", CV_NETVAR|CV_CHEAT, kartdebugitem_cons_t, NULL);
|
||||
|
|
@ -2074,6 +2080,11 @@ void D_Cheat(INT32 playernum, INT32 cheat, ...)
|
|||
COPY(WRITEUINT8, unsigned int);
|
||||
break;
|
||||
|
||||
case CHEAT_GIVEPOWERUP:
|
||||
COPY(WRITEUINT8, unsigned int);
|
||||
COPY(WRITEUINT16, unsigned int);
|
||||
break;
|
||||
|
||||
case CHEAT_SCORE:
|
||||
COPY(WRITEUINT32, UINT32);
|
||||
break;
|
||||
|
|
@ -6133,6 +6144,20 @@ static void Got_Cheat(UINT8 **cp, INT32 playernum)
|
|||
break;
|
||||
}
|
||||
|
||||
case CHEAT_GIVEPOWERUP: {
|
||||
UINT8 powerup = READUINT8(*cp);
|
||||
UINT16 time = READUINT16(*cp);
|
||||
|
||||
// FIXME: we should have actual KITEM_ name array
|
||||
const char *powerupname = cv_kartdebugitem.PossibleValue[
|
||||
1 + NUMKARTITEMS + (powerup - FIRSTPOWERUP)].strvalue;
|
||||
|
||||
K_GivePowerUp(player, powerup, time);
|
||||
|
||||
CV_CheaterWarning(playernum, va("give powerup %s %d tics", powerupname, time));
|
||||
break;
|
||||
}
|
||||
|
||||
case CHEAT_SCORE: {
|
||||
UINT32 score = READUINT32(*cp);
|
||||
|
||||
|
|
@ -6440,7 +6465,18 @@ static void Command_KartGiveItem_f(void)
|
|||
}
|
||||
}
|
||||
|
||||
if (item < NUMKARTITEMS)
|
||||
if (item >= FIRSTPOWERUP)
|
||||
{
|
||||
INT32 amt;
|
||||
|
||||
if (ac > 2)
|
||||
amt = atoi(COM_Argv(2));
|
||||
else
|
||||
amt = BATTLE_POWERUP_TIME;
|
||||
|
||||
D_Cheat(consoleplayer, CHEAT_GIVEPOWERUP, item, amt);
|
||||
}
|
||||
else if (item < NUMKARTITEMS)
|
||||
{
|
||||
INT32 amt;
|
||||
|
||||
|
|
|
|||
|
|
@ -179,7 +179,16 @@ typedef enum
|
|||
KRITEM_DUALJAWZ,
|
||||
KRITEM_TRIPLEGACHABOM,
|
||||
|
||||
NUMKARTRESULTS
|
||||
NUMKARTRESULTS,
|
||||
|
||||
// Power-ups exist in the same enum as items so it's easy
|
||||
// for paper items to be reused for them.
|
||||
FIRSTPOWERUP,
|
||||
POWERUP_SMONITOR = FIRSTPOWERUP,
|
||||
POWERUP_BARRIER,
|
||||
POWERUP_BUMPER,
|
||||
POWERUP_BADGE,
|
||||
POWERUP_SUPERFLICKY,
|
||||
} kartitems_t;
|
||||
|
||||
typedef enum
|
||||
|
|
@ -451,6 +460,11 @@ typedef struct {
|
|||
boolean flip;
|
||||
} sonicloopvars_t;
|
||||
|
||||
// player_t struct for power-ups
|
||||
struct powerupvars_t {
|
||||
mobj_t *flickyController;
|
||||
};
|
||||
|
||||
// player_t struct for all alternative viewpoint variables
|
||||
struct altview_t
|
||||
{
|
||||
|
|
@ -768,6 +782,7 @@ struct player_t
|
|||
mobj_t *sliptideZipIndicator;
|
||||
mobj_t *whip;
|
||||
mobj_t *hand;
|
||||
mobj_t *flickyAttacker;
|
||||
|
||||
UINT8 instaShieldCooldown;
|
||||
UINT8 guardCooldown;
|
||||
|
|
@ -792,6 +807,7 @@ struct player_t
|
|||
|
||||
sonicloopvars_t loop;
|
||||
roundconditions_t roundconditions;
|
||||
powerupvars_t powerup;
|
||||
};
|
||||
|
||||
// WARNING FOR ANYONE ABOUT TO ADD SOMETHING TO THE PLAYER STRUCT, G_PlayerReborn WANTS YOU TO SUFFER
|
||||
|
|
|
|||
|
|
@ -4582,6 +4582,8 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
|
|||
"S_GACHABOM_EXPLOSION_4",
|
||||
"S_GACHABOM_WAITING",
|
||||
"S_GACHABOM_RETURNING",
|
||||
|
||||
"S_SUPER_FLICKY",
|
||||
};
|
||||
|
||||
// RegEx to generate this from info.h: ^\tMT_([^,]+), --> \t"MT_\1",
|
||||
|
|
@ -5708,6 +5710,9 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
|
|||
|
||||
"MT_LOOPENDPOINT",
|
||||
"MT_LOOPCENTERPOINT",
|
||||
|
||||
"MT_SUPER_FLICKY",
|
||||
"MT_SUPER_FLICKY_CONTROLLER",
|
||||
};
|
||||
|
||||
const char *const MOBJFLAG_LIST[] = {
|
||||
|
|
@ -6867,6 +6872,12 @@ struct int_const_s const INT_CONST[] = {
|
|||
{"KRITEM_DUALJAWZ",KRITEM_DUALJAWZ},
|
||||
{"KRITEM_TRIPLEGACHABOM",KRITEM_TRIPLEGACHABOM},
|
||||
{"NUMKARTRESULTS",NUMKARTRESULTS},
|
||||
{"FIRSTPOWERUP",FIRSTPOWERUP},
|
||||
{"POWERUP_SMONITOR",POWERUP_SMONITOR},
|
||||
{"POWERUP_BARRIER",POWERUP_BARRIER},
|
||||
{"POWERUP_BUMPER",POWERUP_BUMPER},
|
||||
{"POWERUP_BADGE",POWERUP_BADGE},
|
||||
{"POWERUP_SUPERFLICKY",POWERUP_SUPERFLICKY},
|
||||
|
||||
// kartshields_t
|
||||
{"KSHIELD_NONE",KSHIELD_NONE},
|
||||
|
|
|
|||
59
src/info.c
59
src/info.c
|
|
@ -649,6 +649,7 @@ char sprnames[NUMSPRITES + 1][5] =
|
|||
"ITMO",
|
||||
"ITMI",
|
||||
"ITMN",
|
||||
"PWRB",
|
||||
"WANT",
|
||||
|
||||
"PBOM", // player bomb
|
||||
|
|
@ -816,6 +817,8 @@ char sprnames[NUMSPRITES + 1][5] =
|
|||
"GBOM",
|
||||
"GCHX",
|
||||
|
||||
"3DFR",
|
||||
|
||||
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later
|
||||
"VIEW",
|
||||
};
|
||||
|
|
@ -5247,6 +5250,8 @@ state_t states[NUMSTATES] =
|
|||
{SPR_GCHX, 6|FF_PAPERSPRITE|FF_ANIMATE|FF_REVERSEANIM, 14, {NULL}, 6, 2, S_GACHABOM_WAITING}, // S_GACHABOM_EXPLOSION_4
|
||||
{SPR_GBOM, FF_INVERT, 8, {A_SetScale}, FRACUNIT, 0, S_GACHABOM_RETURNING}, // S_GACHABOM_WAITING
|
||||
{SPR_GBOM, FF_INVERT, -1, {A_SetScale}, FRACUNIT/2, 1, S_NULL}, // S_GACHABOM_RETURNING
|
||||
|
||||
{SPR_3DFR, 1|FF_ANIMATE, -1, {NULL}, 2, 5, S_NULL}, // S_SUPER_FLICKY
|
||||
};
|
||||
|
||||
mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
||||
|
|
@ -29806,6 +29811,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
MF_NOSECTOR|MF_NOBLOCKMAP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_SUPER_FLICKY
|
||||
-1, // doomednum
|
||||
S_SUPER_FLICKY, // spawnstate
|
||||
1000, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
0, // reactiontime
|
||||
sfx_None, // attacksound
|
||||
S_NULL, // painstate
|
||||
0, // painchance
|
||||
sfx_None, // painsound
|
||||
S_NULL, // meleestate
|
||||
S_NULL, // missilestate
|
||||
S_NULL, // deathstate
|
||||
S_NULL, // xdeathstate
|
||||
sfx_None, // deathsound
|
||||
0, // speed
|
||||
16*FRACUNIT, // radius
|
||||
32*FRACUNIT, // height
|
||||
0, // display offset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_SUPER_FLICKY_CONTROLLER
|
||||
-1, // doomednum
|
||||
S_INVISIBLE, // spawnstate
|
||||
1000, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
0, // reactiontime
|
||||
sfx_None, // attacksound
|
||||
S_NULL, // painstate
|
||||
0, // painchance
|
||||
sfx_None, // painsound
|
||||
S_NULL, // meleestate
|
||||
S_NULL, // missilestate
|
||||
S_NULL, // deathstate
|
||||
S_NULL, // xdeathstate
|
||||
sfx_None, // deathsound
|
||||
0, // speed
|
||||
16*FRACUNIT, // radius
|
||||
32*FRACUNIT, // height
|
||||
0, // display offset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOSECTOR|MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
};
|
||||
|
||||
skincolor_t skincolors[MAXSKINCOLORS] = {
|
||||
|
|
|
|||
|
|
@ -1200,6 +1200,7 @@ typedef enum sprite
|
|||
SPR_ITMO,
|
||||
SPR_ITMI,
|
||||
SPR_ITMN,
|
||||
SPR_PWRB,
|
||||
SPR_WANT,
|
||||
|
||||
SPR_PBOM, // player bomb
|
||||
|
|
@ -1367,6 +1368,8 @@ typedef enum sprite
|
|||
SPR_GBOM,
|
||||
SPR_GCHX,
|
||||
|
||||
SPR_3DFR,
|
||||
|
||||
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later
|
||||
SPR_VIEW,
|
||||
|
||||
|
|
@ -5678,6 +5681,8 @@ typedef enum state
|
|||
S_GACHABOM_WAITING,
|
||||
S_GACHABOM_RETURNING,
|
||||
|
||||
S_SUPER_FLICKY,
|
||||
|
||||
S_FIRSTFREESLOT,
|
||||
S_LASTFREESLOT = S_FIRSTFREESLOT + NUMSTATEFREESLOTS - 1,
|
||||
NUMSTATES
|
||||
|
|
@ -6823,6 +6828,9 @@ typedef enum mobj_type
|
|||
MT_LOOPENDPOINT,
|
||||
MT_LOOPCENTERPOINT,
|
||||
|
||||
MT_SUPER_FLICKY,
|
||||
MT_SUPER_FLICKY_CONTROLLER,
|
||||
|
||||
MT_FIRSTFREESLOT,
|
||||
MT_LASTFREESLOT = MT_FIRSTFREESLOT + NUMMOBJFREESLOTS - 1,
|
||||
NUMMOBJTYPES
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ extern "C" {
|
|||
|
||||
#define BATTLE_SPAWN_INTERVAL (4*TICRATE)
|
||||
#define BATTLE_DESPAWN_TIME (15*TICRATE)
|
||||
#define BATTLE_POWERUP_TIME (20*TICRATE)
|
||||
|
||||
extern struct battleovertime
|
||||
{
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include "k_objects.h"
|
||||
#include "k_roulette.h"
|
||||
#include "k_podium.h"
|
||||
#include "k_powerup.h"
|
||||
|
||||
angle_t K_GetCollideAngle(mobj_t *t1, mobj_t *t2)
|
||||
{
|
||||
|
|
@ -888,6 +889,8 @@ boolean K_InstaWhipCollide(mobj_t *shield, mobj_t *victim)
|
|||
P_PlayerRingBurst(victimPlayer, 5);
|
||||
P_DamageMobj(victim, shield, attacker, 1, DMG_STUMBLE); // There's a special exception in P_DamageMobj for type==MT_INSTAWHIP
|
||||
|
||||
K_DropPowerUps(victimPlayer);
|
||||
|
||||
angle_t thrangle = ANGLE_180 + R_PointToAngle2(victim->x, victim->y, shield->x, shield->y);
|
||||
P_Thrust(victim, thrangle, FRACUNIT*10);
|
||||
|
||||
|
|
@ -898,6 +901,19 @@ boolean K_InstaWhipCollide(mobj_t *shield, mobj_t *victim)
|
|||
}
|
||||
return false;
|
||||
}
|
||||
else if (victim->type == MT_SUPER_FLICKY)
|
||||
{
|
||||
if (Obj_IsSuperFlickyWhippable(victim))
|
||||
{
|
||||
K_AddHitLag(victim, victimHitlag, true);
|
||||
K_AddHitLag(attacker, attackerHitlag, false);
|
||||
shield->hitlag = attacker->hitlag;
|
||||
|
||||
Obj_WhipSuperFlicky(victim);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (victim->type == MT_ORBINAUT || victim->type == MT_JAWZ || victim->type == MT_GACHABOM
|
||||
|
|
|
|||
69
src/k_kart.c
69
src/k_kart.c
|
|
@ -6533,13 +6533,26 @@ SINT8 K_GetTotallyRandomResult(UINT8 useodds)
|
|||
return i;
|
||||
}
|
||||
|
||||
mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 flip, UINT8 type, UINT8 amount)
|
||||
mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 flip, UINT8 type, UINT16 amount)
|
||||
{
|
||||
mobj_t *drop = P_SpawnMobj(x, y, z, MT_FLOATINGITEM);
|
||||
mobj_t *backdrop = P_SpawnMobjFromMobj(drop, 0, 0, 0, MT_OVERLAY);
|
||||
|
||||
P_SetTarget(&backdrop->target, drop);
|
||||
P_SetMobjState(backdrop, S_ITEMBACKDROP);
|
||||
// FIXME: due to linkdraw sucking major ass, I was unable
|
||||
// to make a backdrop render behind dropped power-ups
|
||||
// (which use a smaller sprite than normal items). So
|
||||
// dropped power-ups have the backdrop baked into the
|
||||
// sprite for now.
|
||||
if (type < FIRSTPOWERUP)
|
||||
{
|
||||
mobj_t *backdrop = P_SpawnMobjFromMobj(drop, 0, 0, 0, MT_OVERLAY);
|
||||
|
||||
P_SetTarget(&backdrop->target, drop);
|
||||
P_SetMobjState(backdrop, S_ITEMBACKDROP);
|
||||
|
||||
backdrop->dispoffset = 1;
|
||||
P_SetTarget(&backdrop->tracer, drop);
|
||||
backdrop->flags2 |= MF2_LINKDRAW;
|
||||
}
|
||||
|
||||
P_SetScale(drop, drop->scale>>4);
|
||||
drop->destscale = (3*drop->destscale)/2;
|
||||
|
|
@ -6588,9 +6601,6 @@ mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8
|
|||
}
|
||||
|
||||
drop->flags |= MF_NOCLIPTHING;
|
||||
backdrop->dispoffset = 1;
|
||||
P_SetTarget(&backdrop->tracer, drop);
|
||||
backdrop->flags2 |= MF2_LINKDRAW;
|
||||
|
||||
if (gametyperules & GTR_CLOSERPLAYERS)
|
||||
{
|
||||
|
|
@ -6600,20 +6610,30 @@ mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8
|
|||
return drop;
|
||||
}
|
||||
|
||||
void K_DropPaperItem(player_t *player, UINT8 itemtype, UINT16 itemamount)
|
||||
{
|
||||
if (!player->mo || P_MobjWasRemoved(player->mo))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mobj_t *drop = K_CreatePaperItem(
|
||||
player->mo->x, player->mo->y, player->mo->z + player->mo->height/2,
|
||||
player->mo->angle + ANGLE_90, P_MobjFlip(player->mo),
|
||||
itemtype, itemamount
|
||||
);
|
||||
|
||||
K_FlipFromObject(drop, player->mo);
|
||||
}
|
||||
|
||||
// For getting EXTRA hit!
|
||||
void K_DropItems(player_t *player)
|
||||
{
|
||||
K_DropHnextList(player);
|
||||
|
||||
if (player->mo && !P_MobjWasRemoved(player->mo) && player->itemamount > 0)
|
||||
if (player->itemamount > 0)
|
||||
{
|
||||
mobj_t *drop = K_CreatePaperItem(
|
||||
player->mo->x, player->mo->y, player->mo->z + player->mo->height/2,
|
||||
player->mo->angle + ANGLE_90, P_MobjFlip(player->mo),
|
||||
player->itemtype, player->itemamount
|
||||
);
|
||||
|
||||
K_FlipFromObject(drop, player->mo);
|
||||
K_DropPaperItem(player, player->itemtype, player->itemamount);
|
||||
}
|
||||
|
||||
K_StripItems(player);
|
||||
|
|
@ -8288,6 +8308,12 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
if (player->hand && P_MobjWasRemoved(player->hand))
|
||||
P_SetTarget(&player->hand, NULL);
|
||||
|
||||
if (player->flickyAttacker && P_MobjWasRemoved(player->flickyAttacker))
|
||||
P_SetTarget(&player->flickyAttacker, NULL);
|
||||
|
||||
if (player->powerup.flickyController && P_MobjWasRemoved(player->powerup.flickyController))
|
||||
P_SetTarget(&player->powerup.flickyController, NULL);
|
||||
|
||||
if (player->spectator == false)
|
||||
{
|
||||
K_KartEbrakeVisuals(player);
|
||||
|
|
@ -12009,8 +12035,17 @@ void K_UpdateMobjItemOverlay(mobj_t *part, SINT8 itemType, UINT8 itemCount)
|
|||
part->frame = FF_FULLBRIGHT|FF_PAPERSPRITE;
|
||||
break;
|
||||
default:
|
||||
part->sprite = SPR_ITEM;
|
||||
part->frame = FF_FULLBRIGHT|FF_PAPERSPRITE|(itemType);
|
||||
if (itemType >= FIRSTPOWERUP)
|
||||
{
|
||||
part->sprite = SPR_PWRB;
|
||||
// Not a papersprite. See K_CreatePaperItem for why.
|
||||
part->frame = FF_FULLBRIGHT|(itemType - FIRSTPOWERUP);
|
||||
}
|
||||
else
|
||||
{
|
||||
part->sprite = SPR_ITEM;
|
||||
part->frame = FF_FULLBRIGHT|FF_PAPERSPRITE|(itemType);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -150,7 +150,8 @@ void K_SpawnDriftElectricSparks(player_t *player, int color, boolean shockwave);
|
|||
void K_KartUpdatePosition(player_t *player);
|
||||
void K_UpdateAllPlayerPositions(void);
|
||||
SINT8 K_GetTotallyRandomResult(UINT8 useodds);
|
||||
mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 flip, UINT8 type, UINT8 amount);
|
||||
mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 flip, UINT8 type, UINT16 amount);
|
||||
void K_DropPaperItem(player_t *player, UINT8 itemtype, UINT16 itemamount);
|
||||
void K_PopPlayerShield(player_t *player);
|
||||
void K_DropItems(player_t *player);
|
||||
void K_DropRocketSneaker(player_t *player);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
#ifndef k_objects_H
|
||||
#define k_objects_H
|
||||
|
||||
#include "doomdef.h"
|
||||
#include "m_fixed.h"
|
||||
#include "tables.h" // angle_t
|
||||
#include "taglist.h"
|
||||
|
||||
|
|
@ -144,6 +146,21 @@ void Obj_SpawnGachaBomRebound(mobj_t *source, mobj_t *target);
|
|||
/* Servant Hand */
|
||||
void Obj_ServantHandHandling(player_t *player);
|
||||
|
||||
/* Super Flicky Controller */
|
||||
void Obj_SpawnSuperFlickySwarm(player_t *owner, tic_t time);
|
||||
void Obj_SuperFlickyControllerThink(mobj_t *controller);
|
||||
void Obj_EndSuperFlickySwarm(mobj_t *controller);
|
||||
void Obj_ExtendSuperFlickySwarm(mobj_t *controller, tic_t time);
|
||||
tic_t Obj_SuperFlickySwarmTime(const mobj_t *controller);
|
||||
|
||||
/* Super Flicky */
|
||||
void Obj_SuperFlickyThink(mobj_t *flicky);
|
||||
void Obj_WhipSuperFlicky(mobj_t *flicky);
|
||||
void Obj_BlockSuperFlicky(mobj_t *flicky);
|
||||
void Obj_SuperFlickyPlayerCollide(mobj_t *flicky, mobj_t *player);
|
||||
void Obj_SuperFlickyLanding(mobj_t *flicky);
|
||||
boolean Obj_IsSuperFlickyWhippable(const mobj_t *flicky);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
|||
50
src/k_powerup.cpp
Normal file
50
src/k_powerup.cpp
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/// \brief Battle mode power-up code
|
||||
|
||||
#include "k_kart.h"
|
||||
#include "k_objects.h"
|
||||
#include "k_powerup.h"
|
||||
|
||||
tic_t K_PowerUpRemaining(const player_t* player, kartitems_t powerup)
|
||||
{
|
||||
switch (powerup)
|
||||
{
|
||||
case POWERUP_SUPERFLICKY:
|
||||
return Obj_SuperFlickySwarmTime(player->powerup.flickyController);
|
||||
|
||||
default:
|
||||
return 0u;
|
||||
}
|
||||
}
|
||||
|
||||
void K_GivePowerUp(player_t* player, kartitems_t powerup, tic_t time)
|
||||
{
|
||||
switch (powerup)
|
||||
{
|
||||
case POWERUP_SUPERFLICKY:
|
||||
if (K_PowerUpRemaining(player, POWERUP_SUPERFLICKY))
|
||||
{
|
||||
Obj_ExtendSuperFlickySwarm(player->powerup.flickyController, time);
|
||||
}
|
||||
else
|
||||
{
|
||||
Obj_SpawnSuperFlickySwarm(player, time);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void K_DropPowerUps(player_t* player)
|
||||
{
|
||||
if (K_PowerUpRemaining(player, POWERUP_SUPERFLICKY))
|
||||
{
|
||||
mobj_t* swarm = player->powerup.flickyController;
|
||||
|
||||
// Be sure to measure the remaining time before ending the power-up
|
||||
K_DropPaperItem(player, POWERUP_SUPERFLICKY, Obj_SuperFlickySwarmTime(swarm));
|
||||
|
||||
Obj_EndSuperFlickySwarm(swarm);
|
||||
}
|
||||
}
|
||||
19
src/k_powerup.h
Normal file
19
src/k_powerup.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef __K_POWERUP__
|
||||
#define __K_POWERUP__
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "d_player.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
tic_t K_PowerUpRemaining(const player_t *player, kartitems_t powerup);
|
||||
void K_GivePowerUp(player_t *player, kartitems_t powerup, tic_t timer);
|
||||
void K_DropPowerUps(player_t *player);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // __K_POWERUP__
|
||||
|
|
@ -36,6 +36,7 @@
|
|||
#include "p_spec.h" // P_StartQuake
|
||||
#include "i_system.h" // I_GetPreciseTime, I_GetPrecisePrecision
|
||||
#include "hu_stuff.h" // for the cecho
|
||||
#include "k_powerup.h"
|
||||
|
||||
#include "lua_script.h"
|
||||
#include "lua_libs.h"
|
||||
|
|
@ -3883,6 +3884,40 @@ static int lib_kAddHitLag(lua_State *L)
|
|||
}
|
||||
|
||||
|
||||
static int lib_kPowerUpRemaining(lua_State *L)
|
||||
{
|
||||
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
|
||||
kartitems_t powerup = luaL_checkinteger(L, 2);
|
||||
//HUDSAFE
|
||||
if (!player)
|
||||
return LUA_ErrInvalid(L, "player_t");
|
||||
lua_pushinteger(L, K_PowerUpRemaining(player, powerup));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lib_kGivePowerUp(lua_State *L)
|
||||
{
|
||||
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
|
||||
kartitems_t powerup = luaL_checkinteger(L, 2);
|
||||
tic_t time = (tic_t)luaL_checkinteger(L, 3);
|
||||
NOHUD
|
||||
if (!player)
|
||||
return LUA_ErrInvalid(L, "player_t");
|
||||
K_GivePowerUp(player, powerup, time);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lib_kDropPowerUps(lua_State *L)
|
||||
{
|
||||
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
|
||||
NOHUD
|
||||
if (!player)
|
||||
return LUA_ErrInvalid(L, "player_t");
|
||||
K_DropPowerUps(player);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int lib_kInitBossHealthBar(lua_State *L)
|
||||
{
|
||||
const char *enemyname = luaL_checkstring(L, 1);
|
||||
|
|
@ -4211,6 +4246,11 @@ static luaL_Reg lib[] = {
|
|||
{"K_GetCollideAngle",lib_kGetCollideAngle},
|
||||
{"K_AddHitLag",lib_kAddHitLag},
|
||||
|
||||
// k_powerup
|
||||
{"K_PowerUpRemaining",lib_kPowerUpRemaining},
|
||||
{"K_GivePowerUp",lib_kGivePowerUp},
|
||||
{"K_DropPowerUps",lib_kDropPowerUps},
|
||||
|
||||
// k_boss
|
||||
{"K_InitBossHealthBar", lib_kInitBossHealthBar},
|
||||
{"K_UpdateBossHealthBar", lib_kUpdateBossHealthBar},
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ typedef enum {
|
|||
CHEAT_SCORE,
|
||||
CHEAT_ANGLE,
|
||||
CHEAT_RESPAWNAT,
|
||||
CHEAT_GIVEPOWERUP,
|
||||
|
||||
NUMBER_OF_CHEATS
|
||||
} cheat_t;
|
||||
|
|
|
|||
|
|
@ -21,4 +21,5 @@ target_sources(SRB2SDL2 PRIVATE
|
|||
block.c
|
||||
gachabom-rebound.cpp
|
||||
servant-hand.c
|
||||
super-flicky.cpp
|
||||
)
|
||||
|
|
|
|||
769
src/objects/super-flicky.cpp
Normal file
769
src/objects/super-flicky.cpp
Normal file
|
|
@ -0,0 +1,769 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023 by James R.
|
||||
// Copyright (C) 2023 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \brief Super Flicky power-up, hunts other players
|
||||
|
||||
#include "../d_player.h"
|
||||
#include "../doomdef.h"
|
||||
#include "../g_game.h"
|
||||
#include "../k_battle.h"
|
||||
#include "../k_kart.h"
|
||||
#include "../k_objects.h"
|
||||
#include "../k_respawn.h"
|
||||
#include "../m_fixed.h"
|
||||
#include "../m_random.h"
|
||||
#include "../p_local.h"
|
||||
#include "../r_main.h"
|
||||
#include "../s_sound.h"
|
||||
#include "../tables.h"
|
||||
|
||||
#define flicky_controller(o) ((o)->target)
|
||||
#define flicky_chasing(o) ((o)->tracer)
|
||||
#define flicky_next(o) ((o)->hnext)
|
||||
#define flicky_next_target(o) ((o)->hprev)
|
||||
#define flicky_phase(o) ((o)->threshold)
|
||||
#define flicky_delay(o) ((o)->movecount)
|
||||
#define flicky_mode(o) ((o)->extravalue1)
|
||||
#define flicky_fly(o) ((o)->extravalue2)
|
||||
|
||||
#define controller_source(o) ((o)->target)
|
||||
#define controller_chasing(o) ((o)->tracer)
|
||||
#define controller_flicky(o) ((o)->hnext)
|
||||
#define controller_mode(o) ((o)->movecount)
|
||||
#define controller_zofs(o) ((o)->sprzoff)
|
||||
#define controller_expiry(o) ((o)->fuse)
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
constexpr tic_t kOrbitSpeed = 2*TICRATE;
|
||||
constexpr int kOrbitSpacing = ANGLE_90;
|
||||
|
||||
// Multiples of player radius
|
||||
constexpr fixed_t kOrbitRadiusInitial = 32*FRACUNIT;
|
||||
constexpr fixed_t kOrbitRadius = 2*FRACUNIT;
|
||||
|
||||
constexpr int kDescendHeight = 256;
|
||||
constexpr int kDescendSmoothing = 16;
|
||||
|
||||
constexpr int kSearchRadius = 1920;
|
||||
constexpr int kFlightRadius = 1280;
|
||||
constexpr int kPeckingRadius = 256;
|
||||
|
||||
constexpr int kFlightSpeed = 2;
|
||||
constexpr int kPeckingSpeed = 8;
|
||||
|
||||
constexpr fixed_t kRebound = 8*FRACUNIT/9;
|
||||
|
||||
constexpr tic_t kDelay = 8;
|
||||
constexpr tic_t kStunTime = 5*TICRATE;
|
||||
constexpr tic_t kBlockTime = 1*TICRATE;
|
||||
|
||||
constexpr int kRiseTime = 1*TICRATE;
|
||||
constexpr int kRiseSpeed = 4;
|
||||
|
||||
// TODO: skincolor must be updated to 2.2 palette
|
||||
constexpr skincolornum_t kSuperStart = SKINCOLOR_SUPERGOLD1;
|
||||
constexpr skincolornum_t kSuperEnd = SKINCOLOR_SUPERGOLD5;
|
||||
|
||||
// copied from objects/hyudoro.c
|
||||
void
|
||||
sine_bob
|
||||
( mobj_t * hyu,
|
||||
angle_t a,
|
||||
fixed_t sineofs)
|
||||
{
|
||||
const fixed_t kBobHeight = 4 * mapobjectscale;
|
||||
|
||||
// slightly modified from objects/hyudoro.c
|
||||
hyu->sprzoff = FixedMul(kBobHeight,
|
||||
sineofs + FINESINE(a >> ANGLETOFINESHIFT));
|
||||
}
|
||||
|
||||
void
|
||||
bob_in_place
|
||||
( mobj_t * hyu,
|
||||
INT32 phase,
|
||||
INT32 bob_speed)
|
||||
{
|
||||
sine_bob(hyu,
|
||||
((leveltime + phase) & (bob_speed - 1)) *
|
||||
(ANGLE_MAX / bob_speed), -(3*FRACUNIT/4));
|
||||
}
|
||||
|
||||
struct Flicky;
|
||||
|
||||
struct Controller : mobj_t
|
||||
{
|
||||
enum class Mode : int
|
||||
{
|
||||
kDescend,
|
||||
kOrbit,
|
||||
kEnRoute,
|
||||
kAttached,
|
||||
kReturning,
|
||||
};
|
||||
|
||||
mobj_t* source() const { return controller_source(this); }
|
||||
void source(mobj_t* n) { P_SetTarget(&controller_source(this), n); }
|
||||
|
||||
mobj_t* chasing() const { return controller_chasing(this); }
|
||||
void chasing(mobj_t* n) { P_SetTarget(&controller_chasing(this), n); }
|
||||
|
||||
Flicky* flicky() const;
|
||||
void flicky(Flicky* n);
|
||||
|
||||
Mode mode() const { return static_cast<Mode>(controller_mode(this)); }
|
||||
void mode(Mode n) { controller_mode(this) = static_cast<int>(n); }
|
||||
|
||||
fixed_t zofs() const { return controller_zofs(this); }
|
||||
void zofs(fixed_t n) { controller_zofs(this) = n; }
|
||||
|
||||
tic_t expiry() const { return controller_expiry(this); }
|
||||
void expiry(tic_t n) { controller_expiry(this) = n; }
|
||||
|
||||
static Controller* spawn(player_t* player, tic_t time)
|
||||
{
|
||||
Controller* x = static_cast<Controller*>(P_SpawnMobjFromMobjUnscaled(
|
||||
player->mo,
|
||||
0,
|
||||
0,
|
||||
kDescendHeight * mapobjectscale,
|
||||
MT_SUPER_FLICKY_CONTROLLER
|
||||
));
|
||||
|
||||
x->source(player->mo);
|
||||
x->mode(Mode::kDescend);
|
||||
x->zofs(0);
|
||||
x->expiry(leveltime + time);
|
||||
|
||||
P_SetTarget(&player->powerup.flickyController, x);
|
||||
|
||||
S_StartSound(x, sfx_s3k46);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
bool valid() { return !P_MobjWasRemoved(source()); }
|
||||
tic_t time_remaining() const { return expiry() - leveltime; }
|
||||
tic_t powerup_remaining() const { return ending() ? 0u : time_remaining() - kRiseTime; }
|
||||
bool ending() const { return time_remaining() <= kRiseTime; }
|
||||
|
||||
void descend()
|
||||
{
|
||||
fixed_t head = P_GetMobjHead(source());
|
||||
fixed_t tz = head;
|
||||
|
||||
if (mode() == Mode::kDescend)
|
||||
{
|
||||
tz = z - ((z - head) / kDescendSmoothing);
|
||||
|
||||
if ((tz - head) < mapobjectscale)
|
||||
{
|
||||
mode(Mode::kOrbit);
|
||||
tz = head;
|
||||
}
|
||||
}
|
||||
|
||||
z = tz + zofs();
|
||||
|
||||
if (ending())
|
||||
{
|
||||
zofs(zofs() + (kRiseSpeed * mapobjectscale * P_MobjFlip(this)));
|
||||
}
|
||||
}
|
||||
|
||||
void expand()
|
||||
{
|
||||
fixed_t n = FixedMul(kOrbitRadiusInitial, ((z - P_GetMobjHead(source())) / kDescendHeight));
|
||||
|
||||
radius = FixedMul(FixedMul(kOrbitRadius, source()->radius), FRACUNIT + n);
|
||||
}
|
||||
|
||||
void end()
|
||||
{
|
||||
// +1 in case flicky already thunk this tic
|
||||
expiry(leveltime + kRiseTime + 1);
|
||||
}
|
||||
|
||||
void search();
|
||||
};
|
||||
|
||||
struct Flicky : mobj_t
|
||||
{
|
||||
enum class Mode : int
|
||||
{
|
||||
kReserved,
|
||||
kHunting,
|
||||
kStunned,
|
||||
kWeak,
|
||||
};
|
||||
|
||||
enum class Fly : int
|
||||
{
|
||||
kNormal,
|
||||
kZoom,
|
||||
kSlow,
|
||||
};
|
||||
|
||||
Controller* controller() const { return static_cast<Controller*>(flicky_controller(this)); }
|
||||
void controller(Controller* n) { P_SetTarget(&flicky_controller(this), n); }
|
||||
|
||||
mobj_t* chasing() const { return flicky_chasing(this); }
|
||||
void chasing(mobj_t* n) { P_SetTarget(&flicky_chasing(this), n); }
|
||||
|
||||
Flicky* next() const { return static_cast<Flicky*>(flicky_next(this)); }
|
||||
void next(Flicky* n) { P_SetTarget(&flicky_next(this), n); }
|
||||
|
||||
mobj_t* next_target() const { return flicky_next_target(this); }
|
||||
void next_target(mobj_t* n) { P_SetTarget(&flicky_next_target(this), n); }
|
||||
|
||||
int phase() const { return flicky_phase(this); }
|
||||
void phase(int n) { flicky_phase(this) = n; }
|
||||
|
||||
int delay() const { return flicky_delay(this); }
|
||||
void delay(int n) { flicky_delay(this) = n; }
|
||||
|
||||
Mode mode() const { return static_cast<Mode>(flicky_mode(this)); }
|
||||
void mode(Mode n) { flicky_mode(this) = static_cast<int>(n); }
|
||||
|
||||
Fly fly() const { return static_cast<Fly>(flicky_fly(this)); }
|
||||
void fly(Fly n) { flicky_fly(this) = static_cast<int>(n); }
|
||||
|
||||
mobj_t* source() const { return controller()->source(); }
|
||||
|
||||
static void spawn(Controller* controller, int phase)
|
||||
{
|
||||
Flicky* x = static_cast<Flicky*>(P_SpawnMobjFromMobj(controller, 0, 0, 0, MT_SUPER_FLICKY));
|
||||
|
||||
x->controller(controller);
|
||||
x->phase(phase);
|
||||
x->delay(0);
|
||||
x->mode(Mode::kReserved);
|
||||
x->light_up(true);
|
||||
|
||||
x->next(controller->flicky());
|
||||
controller->flicky(x);
|
||||
}
|
||||
|
||||
static skincolornum_t super_color()
|
||||
{
|
||||
return static_cast<skincolornum_t>(kSuperStart + ((leveltime / 4) % ((kSuperEnd - kSuperStart) + 1)));
|
||||
}
|
||||
|
||||
bool valid() const { return !P_MobjWasRemoved(controller()) && controller()->valid(); }
|
||||
|
||||
bool stunned() const { return mode() == Mode::kStunned || mode() == Mode::kWeak; }
|
||||
|
||||
void light_up(bool n)
|
||||
{
|
||||
if (n)
|
||||
{
|
||||
renderflags |= RF_FULLBRIGHT;
|
||||
color = super_color();
|
||||
}
|
||||
else
|
||||
{
|
||||
renderflags &= ~(RF_FULLBRIGHT);
|
||||
color = source()->player ? source()->player->skincolor : source()->color;
|
||||
}
|
||||
}
|
||||
|
||||
void animate()
|
||||
{
|
||||
P_InstaScale(this, source()->scale * (chasing() ? 2 : 1));
|
||||
|
||||
if (color >= kSuperStart && color <= kSuperEnd)
|
||||
{
|
||||
color = super_color();
|
||||
}
|
||||
|
||||
bob_in_place(this, phase() * 8, 32);
|
||||
}
|
||||
|
||||
void refocus()
|
||||
{
|
||||
if (controller()->ending())
|
||||
{
|
||||
if (controller()->time_remaining() == kRiseTime)
|
||||
{
|
||||
light_up(false);
|
||||
rise();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (delay() > 0)
|
||||
{
|
||||
delay(delay() - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (chasing() != next_target())
|
||||
{
|
||||
chasing(next_target());
|
||||
mode(Mode::kHunting);
|
||||
|
||||
S_StartSound(this, sfx_fhurt2);
|
||||
}
|
||||
|
||||
if (stunned())
|
||||
{
|
||||
light_up(true);
|
||||
flags = info->flags;
|
||||
mode(Mode::kHunting);
|
||||
|
||||
S_StartSound(this, sfx_s3k9f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
angle_t orbit_angle() const { return controller()->angle + (phase() * kOrbitSpacing); }
|
||||
|
||||
vector3_t orbit_position() const
|
||||
{
|
||||
return {
|
||||
source()->x + FixedMul(FCOS(orbit_angle()), controller()->radius),
|
||||
source()->y + FixedMul(FSIN(orbit_angle()), controller()->radius),
|
||||
controller()->z
|
||||
};
|
||||
}
|
||||
|
||||
void orbit()
|
||||
{
|
||||
vector3_t pos = orbit_position();
|
||||
|
||||
P_MoveOrigin(this, pos.x, pos.y, pos.z);
|
||||
|
||||
momx = 0;
|
||||
momy = 0;
|
||||
momz = 0;
|
||||
|
||||
angle = orbit_angle() + ANGLE_90; // face direction of orbit
|
||||
}
|
||||
|
||||
|
||||
// copied from objects/spb.c
|
||||
void spawn_speed_lines(angle_t direction)
|
||||
{
|
||||
if (mode() != Mode::kHunting)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mobj_t *fast = P_SpawnMobjFromMobjUnscaled(
|
||||
this,
|
||||
P_RandomRange(PR_DECORATION, -24, 24) * mapobjectscale,
|
||||
P_RandomRange(PR_DECORATION, -24, 24) * mapobjectscale,
|
||||
(height / 2) + (P_RandomRange(PR_DECORATION, -24, 24) * mapobjectscale),
|
||||
MT_FASTLINE
|
||||
);
|
||||
|
||||
P_SetTarget(&fast->target, this);
|
||||
fast->angle = direction;
|
||||
|
||||
fast->color = source()->color;
|
||||
fast->colorized = true;
|
||||
fast->renderflags |= RF_ADD;
|
||||
|
||||
K_MatchGenericExtraFlags(fast, this);
|
||||
}
|
||||
|
||||
void chase()
|
||||
{
|
||||
if (controller()->ending())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
vector3_t pos = chasing() ? vector3_t{chasing()->x, chasing()->y, P_GetMobjFeet(chasing())} : orbit_position();
|
||||
angle_t th = R_PointToAngle2(x, y, pos.x, pos.y);
|
||||
|
||||
momz = (pos.z - z) / kDescendSmoothing;
|
||||
angle = K_MomentumAngleReal(this);
|
||||
|
||||
angle_t d = AngleDelta(th, angle);
|
||||
fixed_t dist = FixedHypot(x - pos.x, y - pos.y);
|
||||
|
||||
const Fly oldFly = fly();
|
||||
|
||||
if (d < ANGLE_11hh && dist < kPeckingRadius * mapobjectscale)
|
||||
{
|
||||
// Drastically speed up when about to intersect
|
||||
P_Thrust(this, th, kPeckingSpeed * mapobjectscale);
|
||||
fly(Fly::kZoom);
|
||||
}
|
||||
else
|
||||
{
|
||||
P_Thrust(this, th, kFlightSpeed * mapobjectscale);
|
||||
fly(Fly::kNormal);
|
||||
}
|
||||
|
||||
if (d > ANGLE_45 && dist > kFlightRadius * mapobjectscale)
|
||||
{
|
||||
// Cut momentum when too far outside of intended trajectory
|
||||
momx = FixedMul(momx, kRebound);
|
||||
momy = FixedMul(momy, kRebound);
|
||||
|
||||
spawn_speed_lines(th);
|
||||
|
||||
fly(Fly::kSlow);
|
||||
}
|
||||
else
|
||||
{
|
||||
spawn_speed_lines(angle);
|
||||
}
|
||||
|
||||
// Returning to owner
|
||||
if (!chasing())
|
||||
{
|
||||
if (AngleDelta(th, R_PointToAngle2(x + momx, y + momy, pos.x, pos.y)) > ANG1)
|
||||
{
|
||||
mode(Mode::kReserved);
|
||||
}
|
||||
else
|
||||
{
|
||||
P_InstaThrust(this, th, FixedHypot(momx, momy));
|
||||
}
|
||||
}
|
||||
|
||||
if (fly() != oldFly)
|
||||
{
|
||||
switch (fly())
|
||||
{
|
||||
case Fly::kNormal:
|
||||
break;
|
||||
|
||||
case Fly::kZoom:
|
||||
S_StartSound(this, sfx_fbird);
|
||||
break;
|
||||
|
||||
case Fly::kSlow:
|
||||
S_StartSound(this, sfx_fbost1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rise()
|
||||
{
|
||||
P_SetObjectMomZ(this, kRiseSpeed * FRACUNIT, false);
|
||||
}
|
||||
|
||||
void damage(mobj_t* mobj)
|
||||
{
|
||||
if (!mobj->player)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (mobj != chasing())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode() != Mode::kHunting)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (P_DamageMobj(mobj, this, source(), 1, DMG_NORMAL))
|
||||
{
|
||||
P_InstaThrust(mobj, K_MomentumAngleReal(this), FixedHypot(momx, momy));
|
||||
K_StumblePlayer(mobj->player);
|
||||
|
||||
mobj->player->spinouttimer = 1; // need invulnerability for one tic
|
||||
|
||||
P_SetTarget(&mobj->player->flickyAttacker, this);
|
||||
|
||||
controller()->mode(Controller::Mode::kAttached);
|
||||
}
|
||||
|
||||
S_StartSound(this, sfx_supflk);
|
||||
}
|
||||
|
||||
void reflect()
|
||||
{
|
||||
momx = -(momx);
|
||||
momy = -(momy);
|
||||
}
|
||||
|
||||
void nerf()
|
||||
{
|
||||
light_up(false);
|
||||
|
||||
flags &= ~(MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT);
|
||||
}
|
||||
|
||||
void whip()
|
||||
{
|
||||
reflect();
|
||||
P_SetObjectMomZ(this, 8*FRACUNIT, false);
|
||||
|
||||
nerf();
|
||||
|
||||
mode(Mode::kStunned);
|
||||
delay(kStunTime);
|
||||
|
||||
S_StartSound(this, sfx_fhurt1);
|
||||
}
|
||||
|
||||
void block()
|
||||
{
|
||||
reflect();
|
||||
|
||||
mode(Mode::kStunned);
|
||||
delay(kBlockTime);
|
||||
}
|
||||
|
||||
void land()
|
||||
{
|
||||
flags |= MF_NOGRAVITY;
|
||||
|
||||
mode(Mode::kWeak);
|
||||
}
|
||||
};
|
||||
|
||||
Flicky* Controller::flicky() const
|
||||
{
|
||||
return static_cast<Flicky*>(controller_flicky(this));
|
||||
}
|
||||
|
||||
void Controller::flicky(Flicky* n)
|
||||
{
|
||||
P_SetTarget(&controller_flicky(this), n);
|
||||
}
|
||||
|
||||
void Controller::search()
|
||||
{
|
||||
if (ending())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
fixed_t nearestDistance = INT32_MAX;
|
||||
mobj_t* nearestMobj = nullptr;
|
||||
|
||||
mobj_t* origin = chasing() ? chasing() : source();
|
||||
|
||||
for (int i = 0; i < MAXPLAYERS; ++i)
|
||||
{
|
||||
player_t* player = &players[i];
|
||||
mobj_t* mobj = player->mo;
|
||||
|
||||
if (!playeringame[i] || P_MobjWasRemoved(mobj))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Do not retarget existing target or owner.
|
||||
if (mobj == chasing() || mobj == source())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Target is already being hunted.
|
||||
if (player->flickyAttacker)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (player->respawn.state != RESPAWNST_NONE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
fixed_t dist = FixedHypot(origin->x - mobj->x, origin->y - mobj->y);
|
||||
|
||||
if (dist < kSearchRadius * mapobjectscale && dist < nearestDistance)
|
||||
{
|
||||
nearestDistance = dist;
|
||||
nearestMobj = mobj;
|
||||
}
|
||||
}
|
||||
|
||||
if (nearestMobj)
|
||||
{
|
||||
if (chasing() && flicky())
|
||||
{
|
||||
// Detach flicky from swarm. This one keeps its previous target.
|
||||
flicky(flicky()->next());
|
||||
}
|
||||
|
||||
chasing(nearestMobj);
|
||||
mode(Mode::kEnRoute);
|
||||
|
||||
// Update entire swarm
|
||||
for (Flicky* x = flicky(); x; x = x->next())
|
||||
{
|
||||
x->next_target(chasing());
|
||||
x->delay(x->phase() * kDelay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace
|
||||
|
||||
void Obj_SpawnSuperFlickySwarm(player_t* owner, tic_t time)
|
||||
{
|
||||
Controller* controller = Controller::spawn(owner, time);
|
||||
|
||||
Flicky::spawn(controller, 0);
|
||||
Flicky::spawn(controller, 1);
|
||||
Flicky::spawn(controller, 2);
|
||||
Flicky::spawn(controller, 3);
|
||||
}
|
||||
|
||||
void Obj_SuperFlickyThink(mobj_t* mobj)
|
||||
{
|
||||
Flicky* x = static_cast<Flicky*>(mobj);
|
||||
|
||||
if (!x->valid())
|
||||
{
|
||||
P_RemoveMobj(x);
|
||||
return;
|
||||
}
|
||||
|
||||
x->animate();
|
||||
x->refocus();
|
||||
|
||||
switch (x->mode())
|
||||
{
|
||||
case Flicky::Mode::kReserved:
|
||||
x->orbit();
|
||||
break;
|
||||
|
||||
case Flicky::Mode::kHunting:
|
||||
x->chase();
|
||||
break;
|
||||
|
||||
case Flicky::Mode::kStunned:
|
||||
break;
|
||||
|
||||
case Flicky::Mode::kWeak:
|
||||
x->chase();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Obj_SuperFlickyControllerThink(mobj_t* mobj)
|
||||
{
|
||||
Controller* x = static_cast<Controller*>(mobj);
|
||||
|
||||
if (!x->valid())
|
||||
{
|
||||
P_RemoveMobj(x);
|
||||
return;
|
||||
}
|
||||
|
||||
if (x->time_remaining() <= 1)
|
||||
{
|
||||
P_RemoveMobj(x);
|
||||
return;
|
||||
}
|
||||
|
||||
x->angle += ANGLE_MAX / kOrbitSpeed;
|
||||
|
||||
switch (x->mode())
|
||||
{
|
||||
case Controller::Mode::kDescend:
|
||||
x->descend();
|
||||
x->expand();
|
||||
break;
|
||||
|
||||
case Controller::Mode::kOrbit:
|
||||
x->descend();
|
||||
x->expand();
|
||||
x->search();
|
||||
break;
|
||||
|
||||
case Controller::Mode::kEnRoute:
|
||||
break;
|
||||
|
||||
case Controller::Mode::kAttached:
|
||||
x->search();
|
||||
break;
|
||||
|
||||
case Controller::Mode::kReturning:
|
||||
x->descend();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Obj_WhipSuperFlicky(mobj_t* t1)
|
||||
{
|
||||
Flicky* x = static_cast<Flicky*>(t1);
|
||||
|
||||
if (x->valid())
|
||||
{
|
||||
x->whip();
|
||||
}
|
||||
}
|
||||
|
||||
void Obj_BlockSuperFlicky(mobj_t* t1)
|
||||
{
|
||||
Flicky* x = static_cast<Flicky*>(t1);
|
||||
|
||||
if (x->valid())
|
||||
{
|
||||
x->block();
|
||||
}
|
||||
}
|
||||
|
||||
void Obj_SuperFlickyPlayerCollide(mobj_t* t1, mobj_t* t2)
|
||||
{
|
||||
Flicky* x = static_cast<Flicky*>(t1);
|
||||
|
||||
if (x->valid())
|
||||
{
|
||||
x->damage(t2);
|
||||
}
|
||||
}
|
||||
|
||||
void Obj_SuperFlickyLanding(mobj_t* mobj)
|
||||
{
|
||||
Flicky* x = static_cast<Flicky*>(mobj);
|
||||
|
||||
if (x->valid())
|
||||
{
|
||||
x->land();
|
||||
}
|
||||
}
|
||||
|
||||
void Obj_EndSuperFlickySwarm(mobj_t* mobj)
|
||||
{
|
||||
Controller* x = static_cast<Controller*>(mobj);
|
||||
|
||||
if (x->valid())
|
||||
{
|
||||
x->end();
|
||||
}
|
||||
}
|
||||
|
||||
void Obj_ExtendSuperFlickySwarm(mobj_t* mobj, tic_t time)
|
||||
{
|
||||
Controller* x = static_cast<Controller*>(mobj);
|
||||
|
||||
x->expiry(x->expiry() + time);
|
||||
}
|
||||
|
||||
tic_t Obj_SuperFlickySwarmTime(const mobj_t* mobj)
|
||||
{
|
||||
const Controller* x = static_cast<const Controller*>(mobj);
|
||||
|
||||
return x ? x->powerup_remaining() : 0u;
|
||||
}
|
||||
|
||||
boolean Obj_IsSuperFlickyWhippable(const mobj_t* mobj)
|
||||
{
|
||||
const Flicky* x = static_cast<const Flicky*>(mobj);
|
||||
|
||||
return !x->stunned();
|
||||
}
|
||||
|
|
@ -41,6 +41,7 @@
|
|||
#include "k_roulette.h"
|
||||
#include "k_boss.h"
|
||||
#include "acs/interface.h"
|
||||
#include "k_powerup.h"
|
||||
|
||||
// CTF player names
|
||||
#define CTFTEAMCODE(pl) pl->ctfteam ? (pl->ctfteam == 1 ? "\x85" : "\x84") : ""
|
||||
|
|
@ -332,14 +333,21 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
P_InstaThrust(player->mo, player->mo->angle, 20<<FRACBITS);
|
||||
return;
|
||||
case MT_FLOATINGITEM: // SRB2Kart
|
||||
if (!P_CanPickupItem(player, 3) || (player->itemamount && player->itemtype != special->threshold))
|
||||
return;
|
||||
|
||||
player->itemtype = special->threshold;
|
||||
if ((UINT16)(player->itemamount) + special->movecount > 255)
|
||||
player->itemamount = 255;
|
||||
if (special->threshold >= FIRSTPOWERUP)
|
||||
{
|
||||
K_GivePowerUp(player, special->threshold, special->movecount);
|
||||
}
|
||||
else
|
||||
player->itemamount += special->movecount;
|
||||
{
|
||||
if (!P_CanPickupItem(player, 3) || (player->itemamount && player->itemtype != special->threshold))
|
||||
return;
|
||||
|
||||
player->itemtype = special->threshold;
|
||||
if ((UINT16)(player->itemamount) + special->movecount > 255)
|
||||
player->itemamount = 255;
|
||||
else
|
||||
player->itemamount += special->movecount;
|
||||
}
|
||||
|
||||
S_StartSound(special, special->info->deathsound);
|
||||
|
||||
|
|
@ -648,6 +656,10 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
Obj_PlayerUsedRingShooter(special, player);
|
||||
return;
|
||||
|
||||
case MT_SUPER_FLICKY:
|
||||
Obj_SuperFlickyPlayerCollide(special, toucher);
|
||||
return;
|
||||
|
||||
default: // SOC or script pickup
|
||||
P_SetTarget(&special->target, toucher);
|
||||
break;
|
||||
|
|
@ -2322,8 +2334,16 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
if (clash)
|
||||
{
|
||||
player->spheres = max(player->spheres - 10, 0);
|
||||
|
||||
if (inflictor)
|
||||
{
|
||||
K_DoPowerClash(target, inflictor);
|
||||
|
||||
if (inflictor->type == MT_SUPER_FLICKY)
|
||||
{
|
||||
Obj_BlockSuperFlicky(inflictor);
|
||||
}
|
||||
}
|
||||
else if (source)
|
||||
K_DoPowerClash(target, source);
|
||||
}
|
||||
|
|
|
|||
47
src/p_mobj.c
47
src/p_mobj.c
|
|
@ -2464,6 +2464,12 @@ boolean P_ZMovement(mobj_t *mo)
|
|||
return false;
|
||||
}
|
||||
}
|
||||
else if (mo->type == MT_SUPER_FLICKY)
|
||||
{
|
||||
mom.z = -mom.z;
|
||||
|
||||
Obj_SuperFlickyLanding(mo);
|
||||
}
|
||||
else if (mo->type == MT_DRIFTCLIP)
|
||||
{
|
||||
mom.z = -mom.z/2;
|
||||
|
|
@ -6684,6 +6690,14 @@ static void P_MobjSceneryThink(mobj_t *mobj)
|
|||
case MT_INSTAWHIP_RECHARGE:
|
||||
Obj_InstaWhipRechargeThink(mobj);
|
||||
|
||||
if (P_MobjWasRemoved(mobj))
|
||||
{
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case MT_SUPER_FLICKY_CONTROLLER:
|
||||
Obj_SuperFlickyControllerThink(mobj);
|
||||
|
||||
if (P_MobjWasRemoved(mobj))
|
||||
{
|
||||
return;
|
||||
|
|
@ -7197,29 +7211,12 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
}
|
||||
}
|
||||
|
||||
switch (mobj->threshold)
|
||||
if (mobj->threshold == KITEM_SPB || mobj->threshold == KITEM_SHRINK)
|
||||
{
|
||||
case KITEM_ORBINAUT:
|
||||
mobj->sprite = SPR_ITMO;
|
||||
mobj->frame = FF_FULLBRIGHT|FF_PAPERSPRITE|K_GetOrbinautItemFrame(mobj->movecount);
|
||||
break;
|
||||
case KITEM_INVINCIBILITY:
|
||||
mobj->sprite = SPR_ITMI;
|
||||
mobj->frame = FF_FULLBRIGHT|FF_PAPERSPRITE|K_GetInvincibilityItemFrame();
|
||||
break;
|
||||
case KITEM_SAD:
|
||||
mobj->sprite = SPR_ITEM;
|
||||
mobj->frame = FF_FULLBRIGHT|FF_PAPERSPRITE;
|
||||
break;
|
||||
case KITEM_SPB:
|
||||
case KITEM_SHRINK:
|
||||
K_SetItemCooldown(mobj->threshold, 20*TICRATE);
|
||||
/* FALLTHRU */
|
||||
default:
|
||||
mobj->sprite = SPR_ITEM;
|
||||
mobj->frame = FF_FULLBRIGHT|FF_PAPERSPRITE|(mobj->threshold);
|
||||
break;
|
||||
K_SetItemCooldown(mobj->threshold, 20*TICRATE);
|
||||
}
|
||||
|
||||
K_UpdateMobjItemOverlay(mobj, mobj->threshold, mobj->movecount);
|
||||
break;
|
||||
}
|
||||
case MT_ITEMCAPSULE:
|
||||
|
|
@ -9533,6 +9530,14 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
case MT_GACHABOM_REBOUND:
|
||||
Obj_GachaBomReboundThink(mobj);
|
||||
|
||||
if (P_MobjWasRemoved(mobj))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case MT_SUPER_FLICKY:
|
||||
Obj_SuperFlickyThink(mobj);
|
||||
|
||||
if (P_MobjWasRemoved(mobj))
|
||||
{
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -79,6 +79,8 @@ typedef enum
|
|||
RINGSHOOTER = 0x0100,
|
||||
WHIP = 0x0200,
|
||||
HAND = 0x0400,
|
||||
FLICKYATTACKER = 0x0800,
|
||||
FLICKYCONTROLLER = 0x1000,
|
||||
} player_saveflags;
|
||||
|
||||
static inline void P_ArchivePlayer(savebuffer_t *save)
|
||||
|
|
@ -319,6 +321,12 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
|||
if (players[i].ringShooter)
|
||||
flags |= RINGSHOOTER;
|
||||
|
||||
if (players[i].flickyAttacker)
|
||||
flags |= FLICKYATTACKER;
|
||||
|
||||
if (players[i].powerup.flickyController)
|
||||
flags |= FLICKYCONTROLLER;
|
||||
|
||||
WRITEUINT16(save->p, flags);
|
||||
|
||||
if (flags & SKYBOXVIEW)
|
||||
|
|
@ -351,6 +359,12 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
|||
if (flags & RINGSHOOTER)
|
||||
WRITEUINT32(save->p, players[i].ringShooter->mobjnum);
|
||||
|
||||
if (flags & FLICKYATTACKER)
|
||||
WRITEUINT32(save->p, players[i].flickyAttacker->mobjnum);
|
||||
|
||||
if (flags & FLICKYCONTROLLER)
|
||||
WRITEUINT32(save->p, players[i].powerup.flickyController->mobjnum);
|
||||
|
||||
WRITEUINT32(save->p, (UINT32)players[i].followitem);
|
||||
|
||||
WRITEUINT32(save->p, players[i].charflags);
|
||||
|
|
@ -757,6 +771,12 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
|
|||
if (flags & RINGSHOOTER)
|
||||
players[i].ringShooter = (mobj_t *)(size_t)READUINT32(save->p);
|
||||
|
||||
if (flags & FLICKYATTACKER)
|
||||
players[i].flickyAttacker = (mobj_t *)(size_t)READUINT32(save->p);
|
||||
|
||||
if (flags & FLICKYCONTROLLER)
|
||||
players[i].powerup.flickyController = (mobj_t *)(size_t)READUINT32(save->p);
|
||||
|
||||
players[i].followitem = (mobjtype_t)READUINT32(save->p);
|
||||
|
||||
//SetPlayerSkinByNum(i, players[i].skin);
|
||||
|
|
@ -5264,6 +5284,20 @@ static void P_RelinkPointers(void)
|
|||
if (!P_SetTarget(&players[i].ringShooter, P_FindNewPosition(temp)))
|
||||
CONS_Debug(DBG_GAMELOGIC, "ringShooter not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].flickyAttacker)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].flickyAttacker;
|
||||
players[i].flickyAttacker = NULL;
|
||||
if (!P_SetTarget(&players[i].flickyAttacker, P_FindNewPosition(temp)))
|
||||
CONS_Debug(DBG_GAMELOGIC, "flickyAttacker not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].powerup.flickyController)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].powerup.flickyController;
|
||||
players[i].powerup.flickyController = NULL;
|
||||
if (!P_SetTarget(&players[i].powerup.flickyController, P_FindNewPosition(temp)))
|
||||
CONS_Debug(DBG_GAMELOGIC, "powerup.flickyController not found on player %d\n", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1189,6 +1189,13 @@ sfxinfo_t S_sfx[NUMSFX] =
|
|||
{"iwhp", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Instawhip attack
|
||||
{"gbrk", false, 255, 8, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Guard break!
|
||||
|
||||
// Super Flicky Power-Up
|
||||
{"supflk", false, 255, 32, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Woodpecking - SF_NOINTERRUPT
|
||||
{"fbost1", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Slowing down
|
||||
{"fbird", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Speeding up
|
||||
{"fhurt1", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Whipped
|
||||
{"fhurt2", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Hunting
|
||||
|
||||
// SRB2Kart - Engine sounds
|
||||
// Engine class A
|
||||
{"krta00", false, 48, 65, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
|
|
|
|||
|
|
@ -1258,6 +1258,12 @@ typedef enum
|
|||
sfx_iwhp,
|
||||
sfx_gbrk,
|
||||
|
||||
sfx_supflk,
|
||||
sfx_fbost1,
|
||||
sfx_fbird,
|
||||
sfx_fhurt1,
|
||||
sfx_fhurt2,
|
||||
|
||||
// Next up: UNIQUE ENGINE SOUNDS! Hoooooo boy...
|
||||
// Engine class A - Low Speed, Low Weight
|
||||
sfx_krta00,
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ TYPEDEF (botvars_t);
|
|||
TYPEDEF (roundconditions_t);
|
||||
TYPEDEF (skybox_t);
|
||||
TYPEDEF (itemroulette_t);
|
||||
TYPEDEF (powerupvars_t);
|
||||
TYPEDEF (altview_t);
|
||||
TYPEDEF (player_t);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue