mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Merge branch 'battle-ufo' into 'splitscreen-timer'
Battle: Power-up UFO See merge request KartKrew/Kart!1308
This commit is contained in:
commit
0c94ce41eb
21 changed files with 531 additions and 22 deletions
|
|
@ -190,6 +190,7 @@ typedef enum
|
|||
POWERUP_BADGE,
|
||||
POWERUP_SUPERFLICKY,
|
||||
ENDOFPOWERUPS,
|
||||
LASTPOWERUP = ENDOFPOWERUPS - 1,
|
||||
NUMPOWERUPS = ENDOFPOWERUPS - FIRSTPOWERUP,
|
||||
} kartitems_t;
|
||||
|
||||
|
|
|
|||
|
|
@ -4587,6 +4587,12 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
|
|||
|
||||
"S_SUPER_FLICKY",
|
||||
|
||||
"S_BATTLEUFO",
|
||||
"S_BATTLEUFO_LEG",
|
||||
"S_BATTLEUFO_DIE",
|
||||
"S_BATTLEUFO_BEAM1",
|
||||
"S_BATTLEUFO_BEAM2",
|
||||
|
||||
"S_POWERUP_AURA",
|
||||
};
|
||||
|
||||
|
|
@ -5353,7 +5359,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
|
|||
"MT_MONITOR_PART",
|
||||
"MT_MONITOR_SHARD",
|
||||
"MT_MAGICIANBOX",
|
||||
|
||||
|
||||
"MT_SLIPTIDEZIP",
|
||||
|
||||
"MT_INSTAWHIP",
|
||||
|
|
@ -5536,7 +5542,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
|
|||
|
||||
"MT_POWERCLASH", // Invinc/Grow no damage clash VFX
|
||||
"MT_GUARDBREAK", // Guard break
|
||||
|
||||
|
||||
"MT_PLAYERARROW",
|
||||
"MT_PLAYERWANTED",
|
||||
|
||||
|
|
@ -5720,6 +5726,11 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
|
|||
"MT_SUPER_FLICKY",
|
||||
"MT_SUPER_FLICKY_CONTROLLER",
|
||||
|
||||
"MT_BATTLEUFO_SPAWNER",
|
||||
"MT_BATTLEUFO",
|
||||
"MT_BATTLEUFO_LEG",
|
||||
"MT_BATTLEUFO_BEAM",
|
||||
|
||||
"MT_POWERUP_AURA",
|
||||
};
|
||||
|
||||
|
|
@ -6164,7 +6175,7 @@ const char *COLOR_ENUMS[] = {
|
|||
"POSNUM_BEST4",
|
||||
"POSNUM_BEST5",
|
||||
"POSNUM_BEST6",
|
||||
|
||||
|
||||
"INTERMISSION",
|
||||
};
|
||||
|
||||
|
|
@ -6885,6 +6896,7 @@ struct int_const_s const INT_CONST[] = {
|
|||
{"POWERUP_BADGE",POWERUP_BADGE},
|
||||
{"POWERUP_SUPERFLICKY",POWERUP_SUPERFLICKY},
|
||||
{"ENDOFPOWERUPS",ENDOFPOWERUPS},
|
||||
{"LASTPOWERUP",LASTPOWERUP},
|
||||
{"NUMPOWERUPS",NUMPOWERUPS},
|
||||
|
||||
// kartshields_t
|
||||
|
|
|
|||
121
src/info.c
121
src/info.c
|
|
@ -822,6 +822,8 @@ char sprnames[NUMSPRITES + 1][5] =
|
|||
|
||||
"3DFR",
|
||||
|
||||
"BUFO", // Battle/Power-UP UFO
|
||||
|
||||
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later
|
||||
"VIEW",
|
||||
};
|
||||
|
|
@ -5258,6 +5260,13 @@ state_t states[NUMSTATES] =
|
|||
|
||||
{SPR_3DFR, 1|FF_ANIMATE, -1, {NULL}, 2, 5, S_NULL}, // S_SUPER_FLICKY
|
||||
|
||||
// Battle/Power-UP UFO
|
||||
{SPR_BUFO, 0, -1, {A_SetScale}, 3*FRACUNIT/2 , 0, S_NULL}, // S_BATTLEUFO
|
||||
{SPR_BUFO, 1, -1, {A_SetScale}, 2*FRACUNIT/2, 0, S_NULL}, // S_BATTLEUFO_LEG
|
||||
{SPR_BUFO, 0, 4, {A_BossScream}, 0, MT_EXPLODE, S_BATTLEUFO_DIE}, // S_BATTLEUFO_DIE
|
||||
{SPR_DEZL, 1|FF_ANIMATE|FF_FULLBRIGHT, 15, {NULL}, 2, 5, S_BATTLEUFO_BEAM2}, // S_BATTLEUFO_BEAM1
|
||||
{SPR_DEZL, 3|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_BATTLEUFO_BEAM2
|
||||
|
||||
{SPR_RBOW, FF_PAPERSPRITE|FF_ADD|FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 14, 2, S_NULL}, // S_POWERUP_AURA
|
||||
};
|
||||
|
||||
|
|
@ -22874,7 +22883,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
|
||||
{ // MT_SIGNSPARKLE
|
||||
-1, // doomednum
|
||||
S_SIGNSPARK1, // spawnstate
|
||||
|
|
@ -29900,6 +29909,114 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_BATTLEUFO_SPAWNER
|
||||
3786, // 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
|
||||
55*FRACUNIT, // radius
|
||||
95*FRACUNIT, // height
|
||||
0, // display offset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_SCENERY, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_BATTLEUFO
|
||||
-1, // doomednum
|
||||
S_BATTLEUFO, // spawnstate
|
||||
1, // 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_BATTLEUFO_DIE, // deathstate
|
||||
S_NULL, // xdeathstate
|
||||
sfx_cdfm19, // deathsound
|
||||
0, // speed
|
||||
60*FRACUNIT, // radius
|
||||
104*FRACUNIT, // height
|
||||
0, // display offset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOGRAVITY|MF_SOLID|MF_SHOOTABLE|MF_DONTENCOREMAP|MF_RUNSPAWNFUNC, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_BATTLEUFO_LEG
|
||||
-1, // doomednum
|
||||
S_BATTLEUFO_LEG, // 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
|
||||
-4*FRACUNIT, // speed
|
||||
64*FRACUNIT, // radius
|
||||
55*FRACUNIT, // height
|
||||
0, // display offset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP|MF_RUNSPAWNFUNC, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_BATTLEUFO_BEAM
|
||||
-1, // doomednum
|
||||
S_BATTLEUFO_BEAM1, // 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
|
||||
-(FRACUNIT/2), // speed
|
||||
64*FRACUNIT, // radius
|
||||
55*FRACUNIT, // height
|
||||
0, // display offset
|
||||
0, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOGRAVITY|MF_NOCLIP|MF_DONTENCOREMAP, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_POWERUP_AURA
|
||||
-1, // doomednum
|
||||
S_POWERUP_AURA, // spawnstate
|
||||
|
|
@ -30110,7 +30227,7 @@ skincolor_t skincolors[MAXSKINCOLORS] = {
|
|||
{"Position Best 4", {255, 255, 122, 122, 123, 123, 141, 141, 142, 142, 143, 143, 138, 139, 254, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_BEST4
|
||||
{"Position Best 5", {152, 152, 153, 153, 154, 154, 155, 155, 156, 156, 157, 158, 159, 253, 254, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_BEST5
|
||||
{"Position Best 6", {181, 181, 182, 182, 183, 183, 184, 184, 185, 185, 186, 186, 187, 187, 29, 30}, SKINCOLOR_NONE, 0, 0, false}, // SKINCOLOR_POSNUM_BEST6
|
||||
|
||||
|
||||
{"Intermission", {0,80,80,81,81,81,84,85,86,87,246,248,251,26,28,31}, SKINCOLOR_NONE, 0, 0, false} // SKINCOLOR_INTERMISSION
|
||||
};
|
||||
|
||||
|
|
|
|||
13
src/info.h
13
src/info.h
|
|
@ -1373,6 +1373,8 @@ typedef enum sprite
|
|||
|
||||
SPR_3DFR,
|
||||
|
||||
SPR_BUFO, // Battle/Power-UP UFO
|
||||
|
||||
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later
|
||||
SPR_VIEW,
|
||||
|
||||
|
|
@ -5688,6 +5690,12 @@ typedef enum state
|
|||
|
||||
S_SUPER_FLICKY,
|
||||
|
||||
S_BATTLEUFO,
|
||||
S_BATTLEUFO_LEG,
|
||||
S_BATTLEUFO_DIE,
|
||||
S_BATTLEUFO_BEAM1,
|
||||
S_BATTLEUFO_BEAM2,
|
||||
|
||||
S_POWERUP_AURA,
|
||||
|
||||
S_FIRSTFREESLOT,
|
||||
|
|
@ -6840,6 +6848,11 @@ typedef enum mobj_type
|
|||
MT_SUPER_FLICKY,
|
||||
MT_SUPER_FLICKY_CONTROLLER,
|
||||
|
||||
MT_BATTLEUFO_SPAWNER,
|
||||
MT_BATTLEUFO,
|
||||
MT_BATTLEUFO_LEG,
|
||||
MT_BATTLEUFO_BEAM,
|
||||
|
||||
MT_POWERUP_AURA,
|
||||
|
||||
MT_FIRSTFREESLOT,
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
// Battle overtime info
|
||||
struct battleovertime battleovertime;
|
||||
struct battleufo g_battleufo;
|
||||
|
||||
// Capsules mode enabled for this map?
|
||||
boolean battleprisons = false;
|
||||
|
|
@ -349,6 +350,11 @@ void K_RunPaperItemSpawners(void)
|
|||
return;
|
||||
}
|
||||
|
||||
if (leveltime == g_battleufo.due)
|
||||
{
|
||||
Obj_SpawnBattleUFOFromSpawner();
|
||||
}
|
||||
|
||||
if (!IsOnInterval(interval))
|
||||
{
|
||||
return;
|
||||
|
|
@ -411,7 +417,7 @@ void K_RunPaperItemSpawners(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
K_CreatePaperItem(
|
||||
K_FlingPaperItem(
|
||||
battleovertime.x, battleovertime.y, battleovertime.z + (128 * mapobjectscale * flip),
|
||||
FixedAngle(P_RandomRange(PR_ITEM_ROULETTE, 0, 359) * FRACUNIT), flip,
|
||||
0, 0
|
||||
|
|
@ -796,6 +802,9 @@ void K_BattleInit(boolean singleplayercontext)
|
|||
K_SpawnPlayerBattleBumpers(players+i);
|
||||
}
|
||||
}
|
||||
|
||||
g_battleufo.due = starttime;
|
||||
g_battleufo.previousId = Obj_GetFirstBattleUFOSpawnerID();
|
||||
}
|
||||
|
||||
UINT8 K_Bumpers(player_t *player)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ extern "C" {
|
|||
#define BATTLE_SPAWN_INTERVAL (4*TICRATE)
|
||||
#define BATTLE_DESPAWN_TIME (15*TICRATE)
|
||||
#define BATTLE_POWERUP_TIME (20*TICRATE)
|
||||
#define BATTLE_UFO_TIME (25*TICRATE)
|
||||
|
||||
extern struct battleovertime
|
||||
{
|
||||
|
|
@ -19,6 +20,12 @@ extern struct battleovertime
|
|||
fixed_t x, y, z; ///< Position to center on
|
||||
} battleovertime;
|
||||
|
||||
extern struct battleufo
|
||||
{
|
||||
INT32 previousId;
|
||||
tic_t due;
|
||||
} g_battleufo;
|
||||
|
||||
extern boolean battleprisons;
|
||||
extern INT32 nummapboxes, numgotboxes; // keep track of spawned battle mode items
|
||||
extern UINT8 maptargets, numtargets;
|
||||
|
|
|
|||
|
|
@ -920,11 +920,12 @@ boolean K_InstaWhipCollide(mobj_t *shield, mobj_t *victim)
|
|||
|| victim->type == MT_BANANA || victim->type == MT_EGGMANITEM || victim->type == MT_BALLHOG
|
||||
|| victim->type == MT_SSMINE || victim->type == MT_LANDMINE || victim->type == MT_SINK
|
||||
|| victim->type == MT_GARDENTOP || victim->type == MT_DROPTARGET || victim->type == MT_BATTLECAPSULE
|
||||
|| victim->type == MT_MONITOR || victim->type == MT_SPECIAL_UFO)
|
||||
|| victim->type == MT_MONITOR || victim->type == MT_SPECIAL_UFO || victim->type == MT_BATTLEUFO)
|
||||
{
|
||||
// Monitor hack. We can hit monitors once per instawhip, no multihit shredding!
|
||||
// Damage values in Obj_MonitorGetDamage.
|
||||
if (victim->type == MT_MONITOR)
|
||||
// Apply to UFO also -- steelt 29062023
|
||||
if (victim->type == MT_MONITOR || victim->type == MT_BATTLEUFO)
|
||||
{
|
||||
if (shield->extravalue1 == 1)
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ static patch_t *kp_wouldyoustillcatchmeifiwereaworm;
|
|||
static patch_t *kp_catcherminimap;
|
||||
static patch_t *kp_emeraldminimap[2];
|
||||
static patch_t *kp_capsuleminimap[3];
|
||||
static patch_t *kp_battleufominimap;
|
||||
|
||||
static patch_t *kp_ringsticker[2];
|
||||
static patch_t *kp_ringstickersplit[4];
|
||||
|
|
@ -372,6 +373,8 @@ void K_LoadKartHUDGraphics(void)
|
|||
HU_UpdatePatch(&kp_capsuleminimap[1], "MINICAP2");
|
||||
HU_UpdatePatch(&kp_capsuleminimap[2], "MINICAP3");
|
||||
|
||||
HU_UpdatePatch(&kp_battleufominimap, "MINIBUFO");
|
||||
|
||||
// Rings & Lives
|
||||
HU_UpdatePatch(&kp_ringsticker[0], "RNGBACKA");
|
||||
HU_UpdatePatch(&kp_ringsticker[1], "RNGBACKB");
|
||||
|
|
@ -4012,6 +4015,9 @@ static void K_drawKartMinimap(void)
|
|||
if (battleprisons)
|
||||
workingPic = kp_capsuleminimap[2];
|
||||
break;
|
||||
case MT_BATTLEUFO:
|
||||
workingPic = kp_battleufominimap;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
24
src/k_kart.c
24
src/k_kart.c
|
|
@ -6613,13 +6613,6 @@ mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8
|
|||
drop->destscale = (3*drop->destscale)/2;
|
||||
|
||||
drop->angle = angle;
|
||||
P_Thrust(drop,
|
||||
FixedAngle(P_RandomFixed(PR_ITEM_ROULETTE) * 180) + angle,
|
||||
16*mapobjectscale);
|
||||
|
||||
drop->momz = flip * 3 * mapobjectscale;
|
||||
if (drop->eflags & MFE_UNDERWATER)
|
||||
drop->momz = (117 * drop->momz) / 200;
|
||||
|
||||
if (type == 0)
|
||||
{
|
||||
|
|
@ -6665,6 +6658,21 @@ mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8
|
|||
return drop;
|
||||
}
|
||||
|
||||
mobj_t *K_FlingPaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8 flip, UINT8 type, UINT16 amount)
|
||||
{
|
||||
mobj_t *drop = K_CreatePaperItem(x, y, z, angle, flip, type, amount);
|
||||
|
||||
P_Thrust(drop,
|
||||
FixedAngle(P_RandomFixed(PR_ITEM_ROULETTE) * 180) + angle,
|
||||
16*mapobjectscale);
|
||||
|
||||
drop->momz = flip * 3 * mapobjectscale;
|
||||
if (drop->eflags & MFE_UNDERWATER)
|
||||
drop->momz = (117 * drop->momz) / 200;
|
||||
|
||||
return drop;
|
||||
}
|
||||
|
||||
void K_DropPaperItem(player_t *player, UINT8 itemtype, UINT16 itemamount)
|
||||
{
|
||||
if (!player->mo || P_MobjWasRemoved(player->mo))
|
||||
|
|
@ -6672,7 +6680,7 @@ void K_DropPaperItem(player_t *player, UINT8 itemtype, UINT16 itemamount)
|
|||
return;
|
||||
}
|
||||
|
||||
mobj_t *drop = K_CreatePaperItem(
|
||||
mobj_t *drop = K_FlingPaperItem(
|
||||
player->mo->x, player->mo->y, player->mo->z + player->mo->height/2,
|
||||
player->mo->angle + ANGLE_90, P_MobjFlip(player->mo),
|
||||
itemtype, itemamount
|
||||
|
|
|
|||
|
|
@ -152,6 +152,7 @@ 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, UINT16 amount);
|
||||
mobj_t *K_FlingPaperItem(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);
|
||||
|
|
|
|||
|
|
@ -161,6 +161,18 @@ void Obj_SuperFlickyPlayerCollide(mobj_t *flicky, mobj_t *player);
|
|||
void Obj_SuperFlickyLanding(mobj_t *flicky);
|
||||
boolean Obj_IsSuperFlickyWhippable(const mobj_t *flicky);
|
||||
|
||||
/* Battle/Power-UP UFO */
|
||||
void Obj_BattleUFOLegThink(mobj_t *leg);
|
||||
void Obj_BattleUFOThink(mobj_t *ufo);
|
||||
void Obj_SpawnBattleUFOLegs(mobj_t *ufo);
|
||||
void Obj_BattleUFODeath(mobj_t *ufo);
|
||||
void Obj_LinkBattleUFOSpawner(mobj_t *spawner);
|
||||
void Obj_UnlinkBattleUFOSpawner(mobj_t *spawner);
|
||||
void Obj_SpawnBattleUFOFromSpawner(void);
|
||||
INT32 Obj_GetFirstBattleUFOSpawnerID(void);
|
||||
void Obj_ResetUFOSpawners(void);
|
||||
void Obj_BattleUFOBeamThink(mobj_t *beam);
|
||||
|
||||
/* Power-Up Aura */
|
||||
void Obj_SpawnPowerUpAura(player_t* player);
|
||||
void Obj_PowerUpAuraThink(mobj_t* mobj);
|
||||
|
|
|
|||
|
|
@ -74,6 +74,8 @@ typedef enum
|
|||
|
||||
PR_MOVINGTARGET, // Randomised moving targets
|
||||
|
||||
PR_BATTLEUFO, // Battle UFO spawning
|
||||
|
||||
PR_BOTS, // Bot spawning
|
||||
|
||||
PRNUMCLASS
|
||||
|
|
|
|||
|
|
@ -22,5 +22,6 @@ target_sources(SRB2SDL2 PRIVATE
|
|||
gachabom-rebound.cpp
|
||||
servant-hand.c
|
||||
super-flicky.cpp
|
||||
battle-ufo.cpp
|
||||
powerup-aura.cpp
|
||||
)
|
||||
|
|
|
|||
241
src/objects/battle-ufo.cpp
Normal file
241
src/objects/battle-ufo.cpp
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <set>
|
||||
|
||||
#include "../doomdef.h"
|
||||
#include "../m_random.h"
|
||||
#include "../p_local.h"
|
||||
#include "../k_battle.h"
|
||||
#include "../k_objects.h"
|
||||
#include "../k_kart.h"
|
||||
|
||||
#define BATTLEUFO_LEG_ZOFFS (3*FRACUNIT) // Spawn height offset from the body
|
||||
#define BATTLEUFO_LEGS (3) // Number of UFO legs to spawn
|
||||
#define BATTLEUFO_BOB_AMP (4) // UFO bob strength
|
||||
#define BATTLEUFO_BOB_SPEED (TICRATE*2) // UFO bob speed
|
||||
|
||||
#define spawner_id(o) ((o)->args[0])
|
||||
|
||||
#define ufo_spawner(o) ((o)->target)
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct Spawner : mobj_t
|
||||
{
|
||||
INT32 id() const { return spawner_id(this); }
|
||||
};
|
||||
|
||||
struct UFO : mobj_t
|
||||
{
|
||||
Spawner* spawner() const { return static_cast<Spawner*>(ufo_spawner(this)); }
|
||||
void spawner(Spawner* n) { P_SetTarget(&ufo_spawner(this), n); }
|
||||
void spawn_beam()
|
||||
{
|
||||
mobj_t *x;
|
||||
|
||||
x = P_SpawnMobjFromMobj(this, 0, 0, FixedDiv(this->height / 4, this->scale), MT_BATTLEUFO_BEAM);
|
||||
x->renderflags |= RF_FLOORSPRITE|RF_NOSPLATBILLBOARD|RF_SLOPESPLAT|RF_NOSPLATROLLANGLE;
|
||||
x->colorized = true;
|
||||
x->color = SKINCOLOR_SAPPHIRE;
|
||||
}
|
||||
};
|
||||
|
||||
struct SpawnerCompare
|
||||
{
|
||||
bool operator()(const Spawner* a, const Spawner* b) const
|
||||
{
|
||||
return a->id() < b->id();
|
||||
}
|
||||
};
|
||||
|
||||
class SpawnerList
|
||||
{
|
||||
private:
|
||||
std::set<Spawner*, SpawnerCompare> set_;
|
||||
|
||||
public:
|
||||
void insert(Spawner* spawner)
|
||||
{
|
||||
auto [it, inserted] = set_.insert(spawner);
|
||||
|
||||
if (inserted)
|
||||
{
|
||||
mobj_t* dummy = nullptr;
|
||||
P_SetTarget(&dummy, spawner);
|
||||
}
|
||||
}
|
||||
|
||||
void erase(Spawner* spawner)
|
||||
{
|
||||
if (set_.erase(spawner))
|
||||
{
|
||||
mobj_t* dummy = spawner;
|
||||
P_SetTarget(&dummy, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
Spawner* next(INT32 order) const
|
||||
{
|
||||
auto it = std::upper_bound(
|
||||
set_.begin(),
|
||||
set_.end(),
|
||||
order,
|
||||
[](INT32 a, const Spawner* b) { return a < b->id(); }
|
||||
);
|
||||
|
||||
return it != set_.end() ? *it : *set_.begin();
|
||||
}
|
||||
|
||||
INT32 random_id() const
|
||||
{
|
||||
if (set_.empty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto it = set_.begin();
|
||||
|
||||
std::advance(it, P_RandomKey(PR_BATTLEUFO, set_.size()));
|
||||
|
||||
return (*std::prev(it == set_.begin() ? set_.end() : it))->id();
|
||||
}
|
||||
|
||||
void spawn_ufo() const
|
||||
{
|
||||
if (set_.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Spawner* spawner = next(g_battleufo.previousId);
|
||||
UFO* ufo = static_cast<UFO*>(P_SpawnMobjFromMobj(spawner, 0, 0, 250*FRACUNIT, MT_BATTLEUFO));
|
||||
|
||||
ufo->spawner(spawner);
|
||||
}
|
||||
};
|
||||
|
||||
SpawnerList g_spawners;
|
||||
|
||||
}; // namespace
|
||||
|
||||
void Obj_BattleUFOThink(mobj_t *mobj)
|
||||
{
|
||||
UFO* ufo = static_cast<UFO*>(mobj);
|
||||
|
||||
// Copied and slightly modified from k_kart.c
|
||||
fixed_t sine = FixedMul(ufo->scale, BATTLEUFO_BOB_AMP * FINESINE((((M_TAU_FIXED * BATTLEUFO_BOB_SPEED) * leveltime) >> ANGLETOFINESHIFT) & FINEMASK));
|
||||
fixed_t targz = FixedMul(ufo->scale, sine) * P_MobjFlip(ufo);
|
||||
ufo->momz = targz;
|
||||
|
||||
if ((leveltime/2) & 1)
|
||||
{
|
||||
ufo->spawn_beam();
|
||||
}
|
||||
}
|
||||
|
||||
void Obj_BattleUFODeath(mobj_t *mobj)
|
||||
{
|
||||
UFO* ufo = static_cast<UFO*>(mobj);
|
||||
const SINT8 flip = P_MobjFlip(ufo);
|
||||
|
||||
ufo->momz = -(8*mapobjectscale)/2;
|
||||
|
||||
K_CreatePaperItem(
|
||||
ufo->x,
|
||||
ufo->y,
|
||||
ufo->z + (flip),
|
||||
0,
|
||||
flip,
|
||||
P_RandomRange(PR_BATTLEUFO, FIRSTPOWERUP, LASTPOWERUP),
|
||||
BATTLE_POWERUP_TIME
|
||||
);
|
||||
|
||||
if (ufo->spawner())
|
||||
{
|
||||
g_battleufo.previousId = ufo->spawner()->id();
|
||||
g_battleufo.due = leveltime + BATTLE_UFO_TIME;
|
||||
}
|
||||
}
|
||||
|
||||
void Obj_SpawnBattleUFOLegs(mobj_t *ufo)
|
||||
{
|
||||
INT32 i;
|
||||
angle_t ang = 0;
|
||||
const fixed_t angle_factor = ANGLE_MAX / BATTLEUFO_LEGS;
|
||||
|
||||
for (i = 0; i < BATTLEUFO_LEGS; i++)
|
||||
{
|
||||
mobj_t *leg = P_SpawnMobjFromMobj(ufo, 0, 0, BATTLEUFO_LEG_ZOFFS, MT_BATTLEUFO_LEG);
|
||||
P_SetTarget(&leg->target, ufo);
|
||||
ang += angle_factor;
|
||||
leg->angle = ang;
|
||||
}
|
||||
}
|
||||
|
||||
void Obj_BattleUFOLegThink(mobj_t *leg)
|
||||
{
|
||||
if (!leg->target || P_MobjWasRemoved(leg->target))
|
||||
{
|
||||
P_RemoveMobj(leg);
|
||||
return;
|
||||
}
|
||||
|
||||
// Rotate around the UFO
|
||||
if (leg->target->health > 0)
|
||||
{
|
||||
leg->angle += FixedAngle(leg->info->speed);
|
||||
|
||||
const angle_t fa = leg->angle>>ANGLETOFINESHIFT;
|
||||
const fixed_t radius = FixedMul(14*leg->info->speed, leg->target->scale);
|
||||
fixed_t x = leg->target->x + FixedMul(FINECOSINE(fa),radius);
|
||||
fixed_t y = leg->target->y + FixedMul(FINESINE(fa),radius);
|
||||
|
||||
// TODO: Take gravflip into account
|
||||
P_MoveOrigin(leg, x, y, leg->z);
|
||||
}
|
||||
|
||||
leg->momz = leg->target->momz;
|
||||
leg->fuse = leg->target->fuse;
|
||||
|
||||
if (leg->target->hitlag)
|
||||
{
|
||||
leg->hitlag = leg->target->hitlag;
|
||||
leg->eflags |= (leg->target->eflags & MFE_DAMAGEHITLAG);
|
||||
}
|
||||
}
|
||||
|
||||
void Obj_LinkBattleUFOSpawner(mobj_t *spawner)
|
||||
{
|
||||
g_spawners.insert(static_cast<Spawner*>(spawner));
|
||||
}
|
||||
|
||||
void Obj_UnlinkBattleUFOSpawner(mobj_t *spawner)
|
||||
{
|
||||
g_spawners.erase(static_cast<Spawner*>(spawner));
|
||||
}
|
||||
|
||||
void Obj_SpawnBattleUFOFromSpawner(void)
|
||||
{
|
||||
g_spawners.spawn_ufo();
|
||||
}
|
||||
|
||||
INT32 Obj_GetFirstBattleUFOSpawnerID(void)
|
||||
{
|
||||
return g_spawners.random_id();
|
||||
}
|
||||
|
||||
void Obj_ResetUFOSpawners(void)
|
||||
{
|
||||
g_spawners = {};
|
||||
}
|
||||
|
||||
void Obj_BattleUFOBeamThink(mobj_t *beam)
|
||||
{
|
||||
P_SetObjectMomZ(beam, beam->info->speed, true);
|
||||
|
||||
if (P_IsObjectOnGround(beam))
|
||||
{
|
||||
P_RemoveMobj(beam);
|
||||
}
|
||||
}
|
||||
|
|
@ -668,13 +668,13 @@ Obj_MonitorOnDeath (mobj_t *monitor)
|
|||
const UINT32 localseed = restore_item_rng(sharedseed);
|
||||
|
||||
adjust_monitor_drop(monitor,
|
||||
K_CreatePaperItem(
|
||||
K_FlingPaperItem(
|
||||
monitor->x, monitor->y, monitor->z + (128 * mapobjectscale * flip),
|
||||
i * ang, flip,
|
||||
K_ItemResultToType(result),
|
||||
K_ItemResultToAmount(result)));
|
||||
|
||||
// K_CreatePaperItem may advance RNG, so update our
|
||||
// K_FlingPaperItem may advance RNG, so update our
|
||||
// copy of the seed afterward
|
||||
sharedseed = restore_item_rng(localseed);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -799,7 +799,7 @@ void P_CheckTimeLimit(void)
|
|||
{
|
||||
if (((timelimitintics + starttime - leveltime) % TICRATE) == 0)
|
||||
S_StartSound(NULL, sfx_s3ka7);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -1725,7 +1725,9 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
|
|||
case MT_MONITOR:
|
||||
Obj_MonitorOnDeath(target);
|
||||
break;
|
||||
|
||||
case MT_BATTLEUFO:
|
||||
Obj_BattleUFODeath(target);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
21
src/p_map.c
21
src/p_map.c
|
|
@ -753,6 +753,27 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
|||
return BMIT_CONTINUE;
|
||||
}
|
||||
|
||||
if (thing->type == MT_BATTLEUFO)
|
||||
{
|
||||
if (tm.thing->type != MT_PLAYER)
|
||||
{
|
||||
return BMIT_CONTINUE; // not a player
|
||||
}
|
||||
|
||||
if (thing->health <= 0)
|
||||
{
|
||||
return BMIT_CONTINUE; // dead
|
||||
}
|
||||
|
||||
if (tm.thing->z > thing->z + thing->height)
|
||||
{
|
||||
return BMIT_CONTINUE; // overhead
|
||||
}
|
||||
|
||||
P_SetObjectMomZ(tm.thing, FRACUNIT, true);
|
||||
return BMIT_CONTINUE;
|
||||
}
|
||||
|
||||
if (thing->type == MT_SPB)
|
||||
{
|
||||
if (tm.thing->type != MT_PLAYER
|
||||
|
|
|
|||
45
src/p_mobj.c
45
src/p_mobj.c
|
|
@ -5331,6 +5331,7 @@ static boolean P_IsTrackerType(INT32 type)
|
|||
case MT_OVERTIME_CENTER:
|
||||
case MT_MONITOR:
|
||||
case MT_EMERALD:
|
||||
case MT_BATTLEUFO:
|
||||
return true;
|
||||
|
||||
default:
|
||||
|
|
@ -6951,6 +6952,14 @@ static boolean P_MobjDeadThink(mobj_t *mobj)
|
|||
Obj_UFOPieceDead(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_BATTLEUFO:
|
||||
{
|
||||
if (P_IsObjectOnGround(mobj) && mobj->fuse == 0)
|
||||
{
|
||||
mobj->fuse = TICRATE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -8069,7 +8078,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
// cusval: responsible for disappear FX (should only happen once)
|
||||
|
||||
// S_MAGICANBOX: sides, starting angle is set in the spawner (SetRandomFakePlayerSkin)
|
||||
// S_MAGICIANBOX_TOP, S_MAGICIANBOX_BOTTOM: splats with their own offset sprite sets
|
||||
// S_MAGICIANBOX_TOP, S_MAGICIANBOX_BOTTOM: splats with their own offset sprite sets
|
||||
|
||||
mobj->extravalue2--;
|
||||
|
||||
|
|
@ -8436,6 +8445,21 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
Obj_ItemDebrisThink(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_BATTLEUFO:
|
||||
{
|
||||
Obj_BattleUFOThink(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_BATTLEUFO_LEG:
|
||||
{
|
||||
Obj_BattleUFOLegThink(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_BATTLEUFO_BEAM:
|
||||
{
|
||||
Obj_BattleUFOBeamThink(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_ROCKETSNEAKER:
|
||||
if (!mobj->target || !mobj->target->health)
|
||||
{
|
||||
|
|
@ -9657,6 +9681,8 @@ static boolean P_CanFlickerFuse(mobj_t *mobj)
|
|||
case MT_SNAPPER_LEG:
|
||||
case MT_MINECARTSEG:
|
||||
case MT_MONITOR_PART:
|
||||
case MT_BATTLEUFO:
|
||||
case MT_BATTLEUFO_LEG:
|
||||
return true;
|
||||
|
||||
case MT_RANDOMITEM:
|
||||
|
|
@ -10311,6 +10337,8 @@ static void P_DefaultMobjShadowScale(mobj_t *thing)
|
|||
case MT_KART_LEFTOVER:
|
||||
case MT_BATTLECAPSULE:
|
||||
case MT_SPECIAL_UFO:
|
||||
case MT_CDUFO:
|
||||
case MT_BATTLEUFO:
|
||||
thing->shadowscale = FRACUNIT;
|
||||
break;
|
||||
case MT_SMALLMACE:
|
||||
|
|
@ -10920,6 +10948,9 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
|
|||
case MT_SPHEREBOX:
|
||||
Obj_RandomItemSpawn(mobj);
|
||||
break;
|
||||
case MT_BATTLEUFO:
|
||||
Obj_SpawnBattleUFOLegs(mobj);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -11162,6 +11193,11 @@ void P_RemoveMobj(mobj_t *mobj)
|
|||
Obj_RingShooterDelete(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_BATTLEUFO_SPAWNER:
|
||||
{
|
||||
Obj_UnlinkBattleUFOSpawner(mobj);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
|
|
@ -12268,7 +12304,7 @@ static mobjtype_t P_GetMobjtypeSubstitute(mapthing_t *mthing, mobjtype_t i)
|
|||
|
||||
if ((i == MT_RANDOMITEM) && (gametyperules & (GTR_PAPERITEMS|GTR_CIRCUIT)) == (GTR_PAPERITEMS|GTR_CIRCUIT))
|
||||
return MT_PAPERITEMSPOT;
|
||||
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
|
@ -13429,6 +13465,11 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj)
|
|||
Obj_InitLoopCenter(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_BATTLEUFO_SPAWNER:
|
||||
{
|
||||
Obj_LinkBattleUFOSpawner(mobj);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5738,6 +5738,10 @@ static void P_NetArchiveMisc(savebuffer_t *save, boolean resending)
|
|||
WRITEFIXED(save->p, battleovertime.y);
|
||||
WRITEFIXED(save->p, battleovertime.z);
|
||||
|
||||
// battleufo_t
|
||||
WRITEINT32(save->p, g_battleufo.previousId);
|
||||
WRITEUINT32(save->p, g_battleufo.due);
|
||||
|
||||
WRITEUINT32(save->p, wantedcalcdelay);
|
||||
for (i = 0; i < NUMKARTITEMS-1; i++)
|
||||
WRITEUINT32(save->p, itemCooldowns[i]);
|
||||
|
|
@ -5908,6 +5912,10 @@ static boolean P_NetUnArchiveMisc(savebuffer_t *save, boolean reloading)
|
|||
battleovertime.y = READFIXED(save->p);
|
||||
battleovertime.z = READFIXED(save->p);
|
||||
|
||||
// battleufo_t
|
||||
g_battleufo.previousId = READINT32(save->p);
|
||||
g_battleufo.due = READUINT32(save->p);
|
||||
|
||||
wantedcalcdelay = READUINT32(save->p);
|
||||
for (i = 0; i < NUMKARTITEMS-1; i++)
|
||||
itemCooldowns[i] = READUINT32(save->p);
|
||||
|
|
|
|||
|
|
@ -7145,6 +7145,9 @@ static void P_ConvertBinaryThingTypes(void)
|
|||
case 2018: // MT_PETSMOKER
|
||||
mapthings[i].args[0] = !!(mapthings[i].options & MTF_OBJECTSPECIAL);
|
||||
break;
|
||||
case 3786: // MT_BATTLEUFO_SPAWNER
|
||||
mapthings[i].args[0] = mapthings[i].angle;
|
||||
break;
|
||||
case FLOOR_SLOPE_THING:
|
||||
case CEILING_SLOPE_THING:
|
||||
mapthings[i].args[0] = mapthings[i].extrainfo;
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
#include "k_director.h"
|
||||
#include "k_specialstage.h"
|
||||
#include "acs/interface.h"
|
||||
#include "k_objects.h"
|
||||
|
||||
#ifdef PARANOIA
|
||||
#include "deh_tables.h" // MOBJTYPE_LIST
|
||||
|
|
@ -230,6 +231,8 @@ void P_InitThinkers(void)
|
|||
{
|
||||
skyboxcenterpnts[i] = skyboxviewpnts[i] = NULL;
|
||||
}
|
||||
|
||||
Obj_ResetUFOSpawners();
|
||||
}
|
||||
|
||||
// Adds a new thinker at the end of the list.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue