Merge branch 'battle-ufo' into 'splitscreen-timer'

Battle: Power-up UFO

See merge request KartKrew/Kart!1308
This commit is contained in:
Oni 2023-06-30 06:08:37 +00:00
commit 0c94ce41eb
21 changed files with 531 additions and 22 deletions

View file

@ -190,6 +190,7 @@ typedef enum
POWERUP_BADGE,
POWERUP_SUPERFLICKY,
ENDOFPOWERUPS,
LASTPOWERUP = ENDOFPOWERUPS - 1,
NUMPOWERUPS = ENDOFPOWERUPS - FIRSTPOWERUP,
} kartitems_t;

View file

@ -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

View file

@ -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
};

View file

@ -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,

View file

@ -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)

View file

@ -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;

View file

@ -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;

View file

@ -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;
}

View file

@ -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

View file

@ -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);

View file

@ -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);

View file

@ -74,6 +74,8 @@ typedef enum
PR_MOVINGTARGET, // Randomised moving targets
PR_BATTLEUFO, // Battle UFO spawning
PR_BOTS, // Bot spawning
PRNUMCLASS

View file

@ -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
View 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);
}
}

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}

View file

@ -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);

View file

@ -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;

View file

@ -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.