mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-12-28 18:52:31 +00:00
Merge branch 'monitors' into 'master'
Monitors See merge request KartKrew/Kart!845
This commit is contained in:
commit
ac250d45f1
12 changed files with 1081 additions and 72 deletions
|
|
@ -3283,6 +3283,24 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
|
|||
//"S_ITEMCAPSULE_BOTTOM",
|
||||
//"S_ITEMCAPSULE_INSIDE",
|
||||
|
||||
"S_MONITOR_DAMAGE",
|
||||
"S_MONITOR_DEATH",
|
||||
"S_MONITOR_SCREEN1A",
|
||||
"S_MONITOR_SCREEN1B",
|
||||
"S_MONITOR_SCREEN2A",
|
||||
"S_MONITOR_SCREEN2B",
|
||||
"S_MONITOR_SCREEN3A",
|
||||
"S_MONITOR_SCREEN3B",
|
||||
"S_MONITOR_SCREEN4A",
|
||||
"S_MONITOR_SCREEN4B",
|
||||
"S_MONITOR_STAND",
|
||||
"S_MONITOR_CRACKA",
|
||||
"S_MONITOR_CRACKB",
|
||||
|
||||
"S_MONITOR_BIG_SHARD",
|
||||
"S_MONITOR_SMALL_SHARD",
|
||||
"S_MONITOR_TWINKLE",
|
||||
|
||||
"S_MAGICIANBOX",
|
||||
"S_MAGICIANBOXTOP",
|
||||
"S_MAGICIANBOXBOTTOM",
|
||||
|
|
@ -5298,6 +5316,9 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
|
|||
"MT_FLOATINGITEM",
|
||||
"MT_ITEMCAPSULE",
|
||||
"MT_ITEMCAPSULE_PART",
|
||||
"MT_MONITOR",
|
||||
"MT_MONITOR_PART",
|
||||
"MT_MONITOR_SHARD",
|
||||
"MT_MAGICIANBOX",
|
||||
|
||||
"MT_SIGNSPARKLE",
|
||||
|
|
|
|||
102
src/info.c
102
src/info.c
|
|
@ -548,6 +548,9 @@ char sprnames[NUMSPRITES + 1][5] =
|
|||
"MGBX", // Heavy Magician transform box
|
||||
"MGBT", // Heavy Magician transform box top
|
||||
"MGBB", // Heavy Magician transform box bottom
|
||||
"MSHD", // Item Monitor Big Shard
|
||||
"IMDB", // Item Monitor Small Shard (Debris)
|
||||
"MTWK", // Item Monitor Glass Twinkle
|
||||
|
||||
"WIPD", // Wipeout dust trail
|
||||
"DRIF", // Drift Sparks
|
||||
|
|
@ -3902,6 +3905,24 @@ state_t states[NUMSTATES] =
|
|||
//{SPR_ICAP, FF_FLOORSPRITE|4, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMCAPSULE_BOTTOM
|
||||
//{SPR_ICAP, FF_FLOORSPRITE|5, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMCAPSULE_INSIDE
|
||||
|
||||
{SPR_NULL, 0, 1, {NULL}, 6, 1, S_SPAWNSTATE}, // S_MONITOR_DAMAGE
|
||||
{SPR_NULL, 0, 1, {NULL}, 0, 0, S_NULL}, // S_MONITOR_DEATH
|
||||
{SPR_IMON, FF_PAPERSPRITE|1, 1, {NULL}, 3, 1, S_MONITOR_SCREEN1B}, // S_MONITOR_SCREEN1A
|
||||
{SPR_IMON, FF_PAPERSPRITE|0, 1, {NULL}, 3, 1, S_MONITOR_SCREEN2A}, // S_MONITOR_SCREEN1B
|
||||
{SPR_IMON, FF_PAPERSPRITE|2, 1, {NULL}, 3, 1, S_MONITOR_SCREEN2B}, // S_MONITOR_SCREEN2A
|
||||
{SPR_IMON, FF_PAPERSPRITE|0, 1, {NULL}, 3, 1, S_MONITOR_SCREEN3A}, // S_MONITOR_SCREEN2B
|
||||
{SPR_IMON, FF_PAPERSPRITE|3, 1, {NULL}, 3, 1, S_MONITOR_SCREEN3B}, // S_MONITOR_SCREEN3A
|
||||
{SPR_IMON, FF_PAPERSPRITE|0, 1, {NULL}, 3, 1, S_MONITOR_SCREEN4A}, // S_MONITOR_SCREEN3B
|
||||
{SPR_IMON, FF_PAPERSPRITE|4, 1, {NULL}, 3, 1, S_MONITOR_SCREEN4B}, // S_MONITOR_SCREEN4A
|
||||
{SPR_IMON, FF_PAPERSPRITE|0, 1, {NULL}, 3, 1, S_MONITOR_SCREEN1A}, // S_MONITOR_SCREEN4B
|
||||
{SPR_IMON, FF_PAPERSPRITE|5, -1, {NULL}, 3, 1, S_NULL}, // S_MONITOR_STAND
|
||||
{SPR_NULL, FF_PAPERSPRITE|FF_TRANS50|FF_ADD|6, -1, {NULL}, 3, 35, S_NULL}, // S_MONITOR_CRACKA
|
||||
{SPR_NULL, FF_PAPERSPRITE|FF_TRANS50|FF_SUBTRACT|10, -1, {NULL}, 3, 35, S_NULL}, // S_MONITOR_CRACKB
|
||||
|
||||
{SPR_MSHD, FF_FULLBRIGHT|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_MONITOR_BIG_SHARD
|
||||
{SPR_IMDB, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_MONITOR_SMALL_SHARD
|
||||
{SPR_MTWK, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_MONITOR_TWINKLE
|
||||
|
||||
{SPR_MGBX, FF_PAPERSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_MAGICIANBOX
|
||||
{SPR_MGBT, FF_FLOORSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_MAGICIANBOX_TOP
|
||||
{SPR_MGBB, FF_FLOORSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_MAGICIANBOX_BOTTOM
|
||||
|
|
@ -22422,6 +22443,87 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_MONITOR
|
||||
-1, // doomednum
|
||||
S_INVISIBLE, // spawnstate
|
||||
FRACUNIT, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
0, // reactiontime
|
||||
sfx_None, // attacksound
|
||||
S_MONITOR_DAMAGE, // painstate
|
||||
0, // painchance
|
||||
sfx_None, // painsound
|
||||
S_NULL, // meleestate
|
||||
S_NULL, // missilestate
|
||||
S_MONITOR_DEATH, // deathstate
|
||||
S_NULL, // xdeathstate
|
||||
sfx_None, // deathsound
|
||||
0, // speed
|
||||
32*FRACUNIT, // radius
|
||||
112*FRACUNIT, // height
|
||||
0, // display offset
|
||||
100, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_SOLID|MF_SHOOTABLE|MF_SLIDEME|MF_DONTENCOREMAP|MF_NOHITLAGFORME, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_MONITOR_PART
|
||||
-1, // doomednum
|
||||
S_INVISIBLE, // spawnstate
|
||||
1, // 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
|
||||
32*FRACUNIT, // radius
|
||||
112*FRACUNIT, // height
|
||||
0, // display offset
|
||||
100, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOGRAVITY|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPTHING|MF_NOCLIPHEIGHT|MF_NOSQUISH, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_MONITOR_SHARD
|
||||
-1, // doomednum
|
||||
S_MONITOR_BIG_SHARD, // spawnstate
|
||||
1, // 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
|
||||
32*FRACUNIT, // radius
|
||||
32*FRACUNIT, // height
|
||||
0, // display offset
|
||||
100, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_SCENERY|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPTHING|MF_NOSQUISH, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_MAGICIANBOX
|
||||
-1, // doomednum
|
||||
S_MAGICIANBOX, // spawnstate
|
||||
|
|
|
|||
24
src/info.h
24
src/info.h
|
|
@ -1099,6 +1099,9 @@ typedef enum sprite
|
|||
SPR_MGBX, // Heavy Magician transform box
|
||||
SPR_MGBT, // Heavy Magician transform box top
|
||||
SPR_MGBB, // Heavy Magician transform box bottom
|
||||
SPR_MSHD, // Item Monitor Big Shard
|
||||
SPR_IMDB, // Item Monitor Small Shard (Debris)
|
||||
SPR_MTWK, // Item Monitor Glass Twinkle
|
||||
|
||||
SPR_WIPD, // Wipeout dust trail
|
||||
SPR_DRIF, // Drift Sparks
|
||||
|
|
@ -4311,6 +4314,24 @@ typedef enum state
|
|||
//S_ITEMCAPSULE_BOTTOM,
|
||||
//S_ITEMCAPSULE_INSIDE,
|
||||
|
||||
S_MONITOR_DAMAGE,
|
||||
S_MONITOR_DEATH,
|
||||
S_MONITOR_SCREEN1A,
|
||||
S_MONITOR_SCREEN1B,
|
||||
S_MONITOR_SCREEN2A,
|
||||
S_MONITOR_SCREEN2B,
|
||||
S_MONITOR_SCREEN3A,
|
||||
S_MONITOR_SCREEN3B,
|
||||
S_MONITOR_SCREEN4A,
|
||||
S_MONITOR_SCREEN4B,
|
||||
S_MONITOR_STAND,
|
||||
S_MONITOR_CRACKA,
|
||||
S_MONITOR_CRACKB,
|
||||
|
||||
S_MONITOR_BIG_SHARD,
|
||||
S_MONITOR_SMALL_SHARD,
|
||||
S_MONITOR_TWINKLE,
|
||||
|
||||
S_MAGICIANBOX,
|
||||
S_MAGICIANBOX_TOP,
|
||||
S_MAGICIANBOX_BOTTOM,
|
||||
|
|
@ -6362,6 +6383,9 @@ typedef enum mobj_type
|
|||
MT_FLOATINGITEM,
|
||||
MT_ITEMCAPSULE,
|
||||
MT_ITEMCAPSULE_PART,
|
||||
MT_MONITOR,
|
||||
MT_MONITOR_PART,
|
||||
MT_MONITOR_SHARD,
|
||||
MT_MAGICIANBOX,
|
||||
|
||||
MT_SIGNSPARKLE,
|
||||
|
|
|
|||
135
src/k_battle.c
135
src/k_battle.c
|
|
@ -18,6 +18,7 @@
|
|||
#include "r_sky.h" // skyflatnum
|
||||
#include "k_grandprix.h" // K_CanChangeRules
|
||||
#include "p_spec.h"
|
||||
#include "k_objects.h"
|
||||
|
||||
// Battle overtime info
|
||||
struct battleovertime battleovertime;
|
||||
|
|
@ -472,9 +473,7 @@ void K_RunPaperItemSpawners(void)
|
|||
#define MAXITEM 64
|
||||
mobj_t *spotList[MAXITEM];
|
||||
UINT8 spotMap[MAXITEM];
|
||||
UINT8 spotCount = 0, spotBackup = 0;
|
||||
|
||||
INT16 starti = 0;
|
||||
UINT8 spotCount = 0, spotBackup = 0, spotAvailable = 0;
|
||||
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
|
|
@ -488,14 +487,26 @@ void K_RunPaperItemSpawners(void)
|
|||
emeraldsSpawned |= mo->extravalue1;
|
||||
}
|
||||
|
||||
if (mo->type == MT_MONITOR)
|
||||
{
|
||||
emeraldsSpawned |= Obj_MonitorGetEmerald(mo);
|
||||
}
|
||||
|
||||
if (mo->type != MT_PAPERITEMSPOT)
|
||||
continue;
|
||||
|
||||
if (spotCount >= MAXITEM)
|
||||
continue;
|
||||
|
||||
if (Obj_ItemSpotIsAvailable(mo))
|
||||
{
|
||||
// spotMap first only includes spots
|
||||
// where a monitor doesn't exist
|
||||
spotMap[spotAvailable] = spotCount;
|
||||
spotAvailable++;
|
||||
}
|
||||
|
||||
spotList[spotCount] = mo;
|
||||
spotMap[spotCount] = spotCount;
|
||||
spotCount++;
|
||||
}
|
||||
|
||||
|
|
@ -513,7 +524,6 @@ void K_RunPaperItemSpawners(void)
|
|||
if (!(emeraldsSpawned & emeraldFlag))
|
||||
{
|
||||
firstUnspawnedEmerald = emeraldFlag;
|
||||
starti = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -521,77 +531,72 @@ void K_RunPaperItemSpawners(void)
|
|||
|
||||
//CONS_Printf("leveltime = %d ", leveltime);
|
||||
|
||||
spotBackup = spotCount;
|
||||
for (i = starti; i < pcount; i++)
|
||||
if (spotAvailable > 0)
|
||||
{
|
||||
UINT8 r = 0, key = 0;
|
||||
mobj_t *drop = NULL;
|
||||
SINT8 flip = 1;
|
||||
const UINT8 r = spotMap[P_RandomKey(PR_ITEM_ROULETTE, spotAvailable)];
|
||||
|
||||
if (spotCount == 0)
|
||||
Obj_ItemSpotAssignMonitor(spotList[r], Obj_SpawnMonitor(
|
||||
spotList[r], 1 + pcount, firstUnspawnedEmerald));
|
||||
}
|
||||
|
||||
for (i = 0; i < spotCount; ++i)
|
||||
{
|
||||
// now spotMap includes every spot
|
||||
spotMap[i] = i;
|
||||
}
|
||||
|
||||
if ((gametyperules & GTR_SPHERES) && IsOnInterval(2 * interval))
|
||||
{
|
||||
spotBackup = spotCount;
|
||||
for (i = 0; i < pcount; i++)
|
||||
{
|
||||
// all are accessible again
|
||||
spotCount = spotBackup;
|
||||
}
|
||||
UINT8 r = 0, key = 0;
|
||||
mobj_t *drop = NULL;
|
||||
SINT8 flip = 1;
|
||||
|
||||
if (spotCount == 1)
|
||||
{
|
||||
key = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
key = P_RandomKey(PR_ITEM_ROULETTE, spotCount);
|
||||
}
|
||||
|
||||
r = spotMap[key];
|
||||
|
||||
//CONS_Printf("[%d %d %d] ", i, key, r);
|
||||
|
||||
flip = P_MobjFlip(spotList[r]);
|
||||
|
||||
// When -1, we're spawning a Chaos Emerald.
|
||||
if (i == -1)
|
||||
{
|
||||
drop = K_SpawnChaosEmerald(
|
||||
spotList[r]->x, spotList[r]->y, spotList[r]->z + (128 * mapobjectscale * flip),
|
||||
FixedAngle(P_RandomRange(PR_ITEM_ROULETTE, 0, 359) * FRACUNIT), flip,
|
||||
firstUnspawnedEmerald
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((gametyperules & GTR_SPHERES) && IsOnInterval(2 * interval))
|
||||
if (spotCount == 0)
|
||||
{
|
||||
drop = K_SpawnSphereBox(
|
||||
spotList[r]->x, spotList[r]->y, spotList[r]->z + (128 * mapobjectscale * flip),
|
||||
FixedAngle(P_RandomRange(PR_ITEM_ROULETTE, 0, 359) * FRACUNIT), flip,
|
||||
10
|
||||
);
|
||||
K_FlipFromObject(drop, spotList[r]);
|
||||
// all are accessible again
|
||||
spotCount = spotBackup;
|
||||
}
|
||||
|
||||
drop = K_CreatePaperItem(
|
||||
if (spotCount == 1)
|
||||
{
|
||||
key = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
key = P_RandomKey(PR_ITEM_ROULETTE, spotCount);
|
||||
}
|
||||
|
||||
r = spotMap[key];
|
||||
|
||||
//CONS_Printf("[%d %d %d] ", i, key, r);
|
||||
|
||||
flip = P_MobjFlip(spotList[r]);
|
||||
|
||||
drop = K_SpawnSphereBox(
|
||||
spotList[r]->x, spotList[r]->y, spotList[r]->z + (128 * mapobjectscale * flip),
|
||||
FixedAngle(P_RandomRange(PR_ITEM_ROULETTE, 0, 359) * FRACUNIT), flip,
|
||||
0, 0
|
||||
FixedAngle(P_RandomRange(PR_ITEM_ROULETTE, 0, 359) * FRACUNIT), flip,
|
||||
10
|
||||
);
|
||||
}
|
||||
|
||||
K_FlipFromObject(drop, spotList[r]);
|
||||
K_FlipFromObject(drop, spotList[r]);
|
||||
|
||||
spotCount--;
|
||||
if (key != spotCount)
|
||||
{
|
||||
// So the core theory of what's going on is that we keep every
|
||||
// available option at the front of the array, so we don't have
|
||||
// to skip over any gaps or do recursion to avoid doubles.
|
||||
// But because spotCount can be reset in the case of a low
|
||||
// quanitity of item spawnpoints in a map, we still need every
|
||||
// entry in the array, even outside of the "visible" range.
|
||||
// A series of swaps allows us to adhere to both constraints.
|
||||
// -toast 22/03/22 (semipalindromic!)
|
||||
spotMap[key] = spotMap[spotCount];
|
||||
spotMap[spotCount] = r; // was set to spotMap[key] previously
|
||||
spotCount--;
|
||||
if (key != spotCount)
|
||||
{
|
||||
// So the core theory of what's going on is that we keep every
|
||||
// available option at the front of the array, so we don't have
|
||||
// to skip over any gaps or do recursion to avoid doubles.
|
||||
// But because spotCount can be reset in the case of a low
|
||||
// quanitity of item spawnpoints in a map, we still need every
|
||||
// entry in the array, even outside of the "visible" range.
|
||||
// A series of swaps allows us to adhere to both constraints.
|
||||
// -toast 22/03/22 (semipalindromic!)
|
||||
spotMap[key] = spotMap[spotCount];
|
||||
spotMap[spotCount] = r; // was set to spotMap[key] previously
|
||||
}
|
||||
}
|
||||
}
|
||||
//CONS_Printf("\n");
|
||||
|
|
|
|||
17
src/k_kart.c
17
src/k_kart.c
|
|
@ -624,13 +624,22 @@ static fixed_t K_PlayerWeight(mobj_t *mobj, mobj_t *against)
|
|||
// from causing super crazy bumps.
|
||||
fixed_t spd = K_GetKartSpeed(mobj->player, false, true);
|
||||
|
||||
fixed_t speedfactor = 8 * mapobjectscale;
|
||||
|
||||
weight = (mobj->player->kartweight) * FRACUNIT;
|
||||
|
||||
if (mobj->player->speed > spd)
|
||||
weight += FixedDiv((mobj->player->speed - spd), 8 * mapobjectscale);
|
||||
if (against && against->type == MT_MONITOR)
|
||||
{
|
||||
speedfactor /= 5; // speed matters more
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mobj->player->itemtype == KITEM_BUBBLESHIELD)
|
||||
weight += 9*FRACUNIT;
|
||||
}
|
||||
|
||||
if (mobj->player->itemtype == KITEM_BUBBLESHIELD)
|
||||
weight += 9*FRACUNIT;
|
||||
if (mobj->player->speed > spd)
|
||||
weight += FixedDiv((mobj->player->speed - spd), speedfactor);
|
||||
}
|
||||
|
||||
return weight;
|
||||
|
|
|
|||
|
|
@ -73,6 +73,22 @@ void Obj_UFOPieceRemoved(mobj_t *piece);
|
|||
mobj_t *Obj_CreateSpecialUFO(void);
|
||||
UINT32 K_GetSpecialUFODistance(void);
|
||||
|
||||
/* Monitors */
|
||||
mobj_t *Obj_SpawnMonitor(mobj_t *origin, UINT8 numItemTypes, UINT8 emerald);
|
||||
void Obj_MonitorSpawnParts(mobj_t *monitor);
|
||||
void Obj_MonitorPartThink(mobj_t *part);
|
||||
fixed_t Obj_MonitorGetDamage(mobj_t *monitor, mobj_t *inflictor, UINT8 damagetype);
|
||||
void Obj_MonitorOnDamage(mobj_t *monitor, mobj_t *inflictor, INT32 damage);
|
||||
void Obj_MonitorOnDeath(mobj_t *monitor);
|
||||
void Obj_MonitorShardThink(mobj_t *shard);
|
||||
UINT32 Obj_MonitorGetEmerald(const mobj_t *monitor);
|
||||
void Obj_MonitorSetItemSpot(mobj_t *monitor, mobj_t *spot);
|
||||
|
||||
/* Item Spot */
|
||||
boolean Obj_ItemSpotIsAvailable(const mobj_t *spot);
|
||||
void Obj_ItemSpotAssignMonitor(mobj_t *spot, mobj_t *monitor);
|
||||
void Obj_ItemSpotUpdate(mobj_t *spot);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -10,4 +10,6 @@ target_sources(SRB2SDL2 PRIVATE
|
|||
duel-bomb.c
|
||||
broly.c
|
||||
ufo.c
|
||||
monitor.c
|
||||
item-spot.c
|
||||
)
|
||||
|
|
|
|||
35
src/objects/item-spot.c
Normal file
35
src/objects/item-spot.c
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#include "../doomdef.h"
|
||||
#include "../m_fixed.h"
|
||||
#include "../k_objects.h"
|
||||
#include "../k_battle.h"
|
||||
#include "../p_tick.h"
|
||||
#include "../p_local.h"
|
||||
|
||||
#define spot_monitor(o) ((o)->target)
|
||||
#define spot_cool(o) ((o)->threshold)
|
||||
|
||||
boolean
|
||||
Obj_ItemSpotIsAvailable (const mobj_t *spot)
|
||||
{
|
||||
return P_MobjWasRemoved(spot_monitor(spot)) &&
|
||||
(leveltime - spot_cool(spot)) > BATTLE_SPAWN_INTERVAL;
|
||||
}
|
||||
|
||||
void
|
||||
Obj_ItemSpotAssignMonitor
|
||||
( mobj_t * spot,
|
||||
mobj_t * monitor)
|
||||
{
|
||||
P_SetTarget(&spot_monitor(spot), monitor);
|
||||
Obj_MonitorSetItemSpot(monitor, spot);
|
||||
}
|
||||
|
||||
void
|
||||
Obj_ItemSpotUpdate (mobj_t *spot)
|
||||
{
|
||||
if (P_MobjWasRemoved(spot_monitor(spot)) ||
|
||||
spot_monitor(spot)->health <= 0)
|
||||
{
|
||||
spot_cool(spot) = leveltime;
|
||||
}
|
||||
}
|
||||
705
src/objects/monitor.c
Normal file
705
src/objects/monitor.c
Normal file
|
|
@ -0,0 +1,705 @@
|
|||
#include "../doomdef.h"
|
||||
#include "../doomstat.h"
|
||||
#include "../info.h"
|
||||
#include "../k_objects.h"
|
||||
#include "../p_local.h"
|
||||
#include "../r_state.h"
|
||||
#include "../k_kart.h"
|
||||
#include "../k_battle.h"
|
||||
#include "../m_random.h"
|
||||
#include "../r_main.h"
|
||||
|
||||
#define FINE90 (FINEANGLES/4)
|
||||
#define FINE180 (FINEANGLES/2)
|
||||
#define TRUETAN(n) FINETANGENT(FINE90 + (n)) // bruh
|
||||
|
||||
#define HEALTHFACTOR (FRACUNIT/4) // Always takes at most, 4 hits.
|
||||
|
||||
#define MONITOR_PART_DEFINE(dispoffset, nsides, ...) \
|
||||
{dispoffset, nsides, (statenum_t[]){__VA_ARGS__, 0}}
|
||||
|
||||
static const struct monitor_part_config {
|
||||
INT32 dispoffset;
|
||||
UINT8 nsides;
|
||||
statenum_t * states;
|
||||
} monitor_parts[] = {
|
||||
MONITOR_PART_DEFINE (0, 3,
|
||||
S_MONITOR_SCREEN1A,
|
||||
S_ITEMICON,
|
||||
S_MONITOR_CRACKB,
|
||||
S_MONITOR_CRACKA),
|
||||
|
||||
MONITOR_PART_DEFINE (-5, 5, S_MONITOR_STAND),
|
||||
};
|
||||
|
||||
#define monitor_spot(o) ((o)->target)
|
||||
#define monitor_rngseed(o) ((o)->movedir)
|
||||
#define monitor_itemcount(o) ((o)->movecount)
|
||||
#define monitor_spawntic(o) ((o)->reactiontime)
|
||||
#define monitor_emerald(o) ((o)->extravalue1)
|
||||
#define monitor_damage(o) ((o)->extravalue2)
|
||||
#define monitor_rammingspeed(o) ((o)->movefactor)
|
||||
|
||||
static inline UINT8
|
||||
get_monitor_itemcount (const mobj_t *monitor)
|
||||
{
|
||||
// protects against divide by zero
|
||||
return max(monitor_itemcount(monitor), 1);
|
||||
}
|
||||
|
||||
#define part_monitor(o) ((o)->target)
|
||||
#define part_type(o) ((o)->extravalue1)
|
||||
#define part_index(o) ((o)->extravalue2)
|
||||
#define part_theta(o) ((o)->movedir)
|
||||
|
||||
#define shard_can_roll(o) ((o)->extravalue1)
|
||||
|
||||
static const sprcache_t * get_state_sprcache (statenum_t);
|
||||
|
||||
static const sprcache_t *
|
||||
get_sprcache
|
||||
( spritenum_t sprite,
|
||||
UINT8 frame)
|
||||
{
|
||||
const spritedef_t *sprdef = &sprites[sprite];
|
||||
|
||||
if (frame < sprdef->numframes)
|
||||
{
|
||||
size_t lump = sprdef->spriteframes[frame].lumpid[0];
|
||||
|
||||
return &spritecachedinfo[lump];
|
||||
}
|
||||
else
|
||||
{
|
||||
return get_state_sprcache(S_UNKNOWN);
|
||||
}
|
||||
}
|
||||
|
||||
static const sprcache_t *
|
||||
get_state_sprcache (statenum_t statenum)
|
||||
{
|
||||
return get_sprcache(states[statenum].sprite,
|
||||
states[statenum].frame & FF_FRAMEMASK);
|
||||
}
|
||||
|
||||
static inline fixed_t
|
||||
get_inradius
|
||||
( fixed_t length,
|
||||
INT32 nsides)
|
||||
{
|
||||
return FixedDiv(length, 2 * TRUETAN(FINE180 / nsides));
|
||||
}
|
||||
|
||||
static inline void
|
||||
center_item_sprite
|
||||
( mobj_t * part,
|
||||
fixed_t scale)
|
||||
{
|
||||
part->spriteyoffset = 25*FRACUNIT;
|
||||
part->spritexscale = scale;
|
||||
part->spriteyscale = scale;
|
||||
}
|
||||
|
||||
static mobj_t *
|
||||
spawn_part
|
||||
( mobj_t * monitor,
|
||||
statenum_t state)
|
||||
{
|
||||
mobj_t *part = P_SpawnMobjFromMobj(
|
||||
monitor, 0, 0, 0, MT_MONITOR_PART);
|
||||
|
||||
P_SetMobjState(part, state);
|
||||
P_SetTarget(&part_monitor(part), monitor);
|
||||
|
||||
part_type(part) = state;
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case S_ITEMICON:
|
||||
// The first frame of the monitor is TV static so
|
||||
// this should be invisible on the first frame.
|
||||
part->renderflags |= RF_DONTDRAW;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return part;
|
||||
}
|
||||
|
||||
static void
|
||||
spawn_part_side
|
||||
( mobj_t * monitor,
|
||||
fixed_t rad,
|
||||
fixed_t ang,
|
||||
const struct monitor_part_config * p,
|
||||
size_t side)
|
||||
{
|
||||
INT32 i = 0;
|
||||
|
||||
while (p->states[i])
|
||||
{
|
||||
mobj_t *part = spawn_part(monitor, p->states[i]);
|
||||
|
||||
part->radius = rad;
|
||||
part_theta(part) = ang;
|
||||
|
||||
// add one point for each layer (back to front order)
|
||||
part->dispoffset = p->dispoffset + i;
|
||||
|
||||
part_index(part) = side;
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
spawn_monitor_parts
|
||||
( mobj_t * monitor,
|
||||
const struct monitor_part_config *p)
|
||||
{
|
||||
const sprcache_t *info = get_state_sprcache(p->states[0]);
|
||||
const fixed_t width = FixedMul(monitor->scale, info->width);
|
||||
const fixed_t rad = get_inradius(width, p->nsides);
|
||||
const fixed_t angle_factor = ANGLE_MAX / p->nsides;
|
||||
|
||||
INT32 i;
|
||||
angle_t ang = 0;
|
||||
|
||||
for (i = 0; i < p->nsides; ++i)
|
||||
{
|
||||
spawn_part_side(monitor, rad, ang, p, i);
|
||||
ang += angle_factor;
|
||||
}
|
||||
}
|
||||
|
||||
static inline boolean
|
||||
can_shard_state_roll (statenum_t state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case S_MONITOR_BIG_SHARD:
|
||||
case S_MONITOR_SMALL_SHARD:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
spawn_shard
|
||||
( mobj_t * part,
|
||||
statenum_t state)
|
||||
{
|
||||
mobj_t *monitor = part_monitor(part);
|
||||
|
||||
// These divisions and multiplications are done on the
|
||||
// offsets to give bigger increments of randomness.
|
||||
|
||||
const fixed_t half = FixedDiv(
|
||||
monitor->height, monitor->scale) / 2;
|
||||
|
||||
const UINT16 rad = (monitor->radius / monitor->scale) / 4;
|
||||
const UINT16 tall = (half / FRACUNIT) / 4;
|
||||
|
||||
mobj_t *p = P_SpawnMobjFromMobj(monitor,
|
||||
P_RandomRange(PR_ITEM_DEBRIS, -(rad), rad) * 8 * FRACUNIT,
|
||||
P_RandomRange(PR_ITEM_DEBRIS, -(rad), rad) * 8 * FRACUNIT,
|
||||
(half / 4) + P_RandomKey(PR_ITEM_DEBRIS, tall + 1) * 4 * FRACUNIT,
|
||||
MT_MONITOR_SHARD);
|
||||
|
||||
angle_t th = (part->angle + ANGLE_90);
|
||||
|
||||
th -= P_RandomKey(PR_ITEM_DEBRIS, ANGLE_45) - ANGLE_22h;
|
||||
|
||||
p->hitlag = 0;
|
||||
|
||||
P_Thrust(p, th, 6 * p->scale + monitor_rammingspeed(monitor));
|
||||
p->momz = P_RandomRange(PR_ITEM_DEBRIS, 3, 10) * p->scale;
|
||||
|
||||
P_SetMobjState(p, state);
|
||||
|
||||
shard_can_roll(p) = can_shard_state_roll(state);
|
||||
|
||||
if (shard_can_roll(p))
|
||||
{
|
||||
p->rollangle = P_Random(PR_ITEM_DEBRIS);
|
||||
}
|
||||
|
||||
if (P_RandomChance(PR_ITEM_DEBRIS, FRACUNIT/2))
|
||||
{
|
||||
p->renderflags |= RF_DONTDRAW;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
spawn_debris (mobj_t *part)
|
||||
{
|
||||
const mobj_t *monitor = part_monitor(part);
|
||||
|
||||
fixed_t i;
|
||||
|
||||
for (i = monitor->health;
|
||||
i <= FRACUNIT; i += HEALTHFACTOR/2)
|
||||
{
|
||||
spawn_shard(part, S_MONITOR_BIG_SHARD);
|
||||
spawn_shard(part, S_MONITOR_SMALL_SHARD);
|
||||
spawn_shard(part, S_MONITOR_TWINKLE);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
spawn_monitor_explosion (mobj_t *monitor)
|
||||
{
|
||||
mobj_t *smoldering = P_SpawnMobjFromMobj(monitor, 0, 0, 0, MT_SMOLDERING);
|
||||
|
||||
UINT8 i;
|
||||
|
||||
// Note that a Broly Ki is purposefully not spawned. This
|
||||
// is to reduce visual clutter since these monitors would
|
||||
// probably get popped a lot.
|
||||
|
||||
K_MineFlashScreen(monitor);
|
||||
|
||||
P_SetScale(smoldering, (smoldering->destscale /= 3));
|
||||
smoldering->tics = TICRATE*3;
|
||||
|
||||
for (i = 0; i < 8; ++i)
|
||||
{
|
||||
mobj_t *x = P_SpawnMobjFromMobj(monitor, 0, 0, 0, MT_BOOMEXPLODE);
|
||||
x->hitlag = 0;
|
||||
x->color = SKINCOLOR_WHITE;
|
||||
x->momx = P_RandomRange(PR_EXPLOSION, -5, 5) * monitor->scale,
|
||||
x->momy = P_RandomRange(PR_EXPLOSION, -5, 5) * monitor->scale,
|
||||
x->momz = P_RandomRange(PR_EXPLOSION, 0, 6) * monitor->scale * P_MobjFlip(monitor);
|
||||
P_SetScale(x, (x->destscale *= 3));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
kill_monitor_part (mobj_t *part)
|
||||
{
|
||||
const statenum_t statenum = part_type(part);
|
||||
|
||||
switch (statenum)
|
||||
{
|
||||
case S_ITEMICON:
|
||||
P_RemoveMobj(part);
|
||||
return;
|
||||
|
||||
case S_MONITOR_STAND:
|
||||
part->momx = 0;
|
||||
part->momy = 0;
|
||||
break;
|
||||
|
||||
case S_MONITOR_SCREEN1A:
|
||||
spawn_debris(part);
|
||||
P_SetMobjState(part, S_MONITOR_SCREEN1B);
|
||||
/*FALLTHRU*/
|
||||
|
||||
default:
|
||||
/* To be clear, momx/y do not need to set because
|
||||
those fields are set every tic to offset each
|
||||
part. */
|
||||
part->momz = (part->height / 8) * P_MobjFlip(part);
|
||||
}
|
||||
|
||||
part->fuse = TICRATE;
|
||||
part->flags &= ~(MF_NOGRAVITY);
|
||||
}
|
||||
|
||||
static inline UINT32
|
||||
restore_item_rng (UINT32 seed)
|
||||
{
|
||||
const UINT32 oldseed = P_GetRandSeed(PR_ITEM_ROULETTE);
|
||||
|
||||
P_SetRandSeedNet(PR_ITEM_ROULETTE,
|
||||
P_GetInitSeed(PR_ITEM_ROULETTE), seed);
|
||||
|
||||
return oldseed;
|
||||
}
|
||||
|
||||
static inline SINT8
|
||||
get_item_result (void)
|
||||
{
|
||||
return K_GetTotallyRandomResult(0);
|
||||
}
|
||||
|
||||
static SINT8
|
||||
get_cycle_result
|
||||
( const mobj_t * monitor,
|
||||
size_t cycle)
|
||||
{
|
||||
const size_t rem = cycle %
|
||||
get_monitor_itemcount(monitor);
|
||||
|
||||
SINT8 result;
|
||||
size_t i;
|
||||
|
||||
const UINT32 oldseed = restore_item_rng(
|
||||
monitor_rngseed(monitor));
|
||||
|
||||
for (i = 0; i <= rem; ++i)
|
||||
{
|
||||
result = get_item_result();
|
||||
}
|
||||
|
||||
restore_item_rng(oldseed);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline tic_t
|
||||
get_age (const mobj_t *monitor)
|
||||
{
|
||||
return (leveltime - monitor_spawntic(monitor));
|
||||
}
|
||||
|
||||
static inline boolean
|
||||
is_flickering (const mobj_t *part)
|
||||
{
|
||||
const mobj_t *monitor = part_monitor(part);
|
||||
|
||||
return monitor->fuse > 0 && monitor->fuse <= TICRATE;
|
||||
}
|
||||
|
||||
static void
|
||||
flicker
|
||||
( mobj_t * part,
|
||||
UINT8 interval)
|
||||
{
|
||||
const tic_t age = get_age(part_monitor(part));
|
||||
|
||||
if (age % interval)
|
||||
{
|
||||
part->renderflags |= RF_DONTDRAW;
|
||||
}
|
||||
else
|
||||
{
|
||||
part->renderflags &= ~(RF_DONTDRAW);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
project_icon (mobj_t *part)
|
||||
{
|
||||
const mobj_t *monitor = part_monitor(part);
|
||||
const tic_t age = get_age(monitor);
|
||||
|
||||
// Item displayed on monitor cycles every N tics
|
||||
if (age % 64 == 0)
|
||||
{
|
||||
const SINT8 result = get_cycle_result(monitor,
|
||||
part_index(part) + (age / 64));
|
||||
|
||||
K_UpdateMobjItemOverlay(part,
|
||||
K_ItemResultToType(result),
|
||||
K_ItemResultToAmount(result));
|
||||
|
||||
center_item_sprite(part, 5*FRACUNIT/4);
|
||||
}
|
||||
|
||||
flicker(part, is_flickering(part) ? 4 : 2);
|
||||
}
|
||||
|
||||
static void
|
||||
translate (mobj_t *part)
|
||||
{
|
||||
const angle_t ang = part_theta(part) +
|
||||
part_monitor(part)->angle;
|
||||
|
||||
part->angle = (ang - ANGLE_90);
|
||||
|
||||
// Because of MF_NOCLIPTHING, no friction is applied.
|
||||
// This object is teleported back to the monitor every
|
||||
// tic so its position is in total only ever translated
|
||||
// by this much.
|
||||
part->momx = P_ReturnThrustX(NULL, ang, part->radius);
|
||||
part->momy = P_ReturnThrustY(NULL, ang, part->radius);
|
||||
}
|
||||
|
||||
static inline fixed_t
|
||||
get_damage_multiplier (const mobj_t *monitor)
|
||||
{
|
||||
return FixedDiv(monitor_damage(monitor), HEALTHFACTOR);
|
||||
}
|
||||
|
||||
static inline boolean
|
||||
has_state
|
||||
( const mobj_t * mobj,
|
||||
statenum_t state)
|
||||
{
|
||||
return mobj->hitlag == 0 &&
|
||||
(size_t)(mobj->state - states) == (size_t)state;
|
||||
}
|
||||
|
||||
static mobj_t *
|
||||
adjust_monitor_drop
|
||||
( mobj_t * monitor,
|
||||
mobj_t * drop)
|
||||
{
|
||||
P_InstaThrust(drop, drop->angle, 4*mapobjectscale);
|
||||
|
||||
drop->momz *= 8;
|
||||
|
||||
K_FlipFromObject(drop, monitor);
|
||||
|
||||
return drop;
|
||||
}
|
||||
|
||||
void
|
||||
Obj_MonitorSpawnParts (mobj_t *monitor)
|
||||
{
|
||||
const size_t nparts =
|
||||
sizeof monitor_parts / sizeof *monitor_parts;
|
||||
|
||||
size_t i;
|
||||
|
||||
P_SetScale(monitor, (monitor->destscale *= 2));
|
||||
|
||||
monitor_itemcount(monitor) = 0;
|
||||
monitor_rngseed(monitor) = P_GetRandSeed(PR_ITEM_ROULETTE);
|
||||
monitor_spawntic(monitor) = leveltime;
|
||||
monitor_emerald(monitor) = 0;
|
||||
|
||||
for (i = 0; i < nparts; ++i)
|
||||
{
|
||||
spawn_monitor_parts(monitor, &monitor_parts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
mobj_t *
|
||||
Obj_SpawnMonitor
|
||||
( mobj_t * origin,
|
||||
UINT8 numItemTypes,
|
||||
UINT8 emerald)
|
||||
{
|
||||
mobj_t *monitor = P_SpawnMobj(origin->x, origin->y,
|
||||
origin->z, MT_MONITOR);
|
||||
|
||||
monitor->angle = P_Random(PR_DECORATION);
|
||||
|
||||
monitor_itemcount(monitor) = numItemTypes;
|
||||
monitor_emerald(monitor) = emerald;
|
||||
|
||||
monitor->color = K_GetChaosEmeraldColor(emerald);
|
||||
|
||||
return monitor;
|
||||
}
|
||||
|
||||
void
|
||||
Obj_MonitorPartThink (mobj_t *part)
|
||||
{
|
||||
const statenum_t statenum = part_type(part);
|
||||
|
||||
mobj_t *monitor = part_monitor(part);
|
||||
|
||||
if (part->fuse > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (P_MobjWasRemoved(monitor))
|
||||
{
|
||||
P_RemoveMobj(part);
|
||||
return;
|
||||
}
|
||||
|
||||
if (has_state(monitor, monitor->info->deathstate))
|
||||
{
|
||||
kill_monitor_part(part);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_flickering(part))
|
||||
{
|
||||
flicker(part, 2);
|
||||
}
|
||||
|
||||
if (monitor->hitlag)
|
||||
{
|
||||
const fixed_t shake = FixedMul(
|
||||
2 * get_damage_multiplier(monitor),
|
||||
monitor->radius / 8);
|
||||
|
||||
part->sprxoff = P_AltFlip(shake, 2);
|
||||
part->spryoff = P_AltFlip(shake, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
part->sprxoff = 0;
|
||||
part->spryoff = 0;
|
||||
}
|
||||
|
||||
switch (statenum)
|
||||
{
|
||||
case S_MONITOR_SCREEN1A:
|
||||
if (has_state(monitor, monitor->info->painstate))
|
||||
{
|
||||
spawn_debris(part);
|
||||
}
|
||||
break;
|
||||
|
||||
case S_MONITOR_CRACKA:
|
||||
case S_MONITOR_CRACKB:
|
||||
if (monitor->health < monitor->info->spawnhealth)
|
||||
{
|
||||
part->sprite = SPR_IMON; // initially SPR_NULL
|
||||
part->frame = part->state->frame +
|
||||
(monitor->health / HEALTHFACTOR);
|
||||
}
|
||||
break;
|
||||
|
||||
case S_ITEMICON:
|
||||
project_icon(part);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
P_MoveOrigin(part, monitor->x, monitor->y, monitor->z);
|
||||
|
||||
translate(part);
|
||||
}
|
||||
|
||||
fixed_t
|
||||
Obj_MonitorGetDamage
|
||||
( mobj_t * monitor,
|
||||
mobj_t * inflictor,
|
||||
UINT8 damagetype)
|
||||
{
|
||||
fixed_t damage;
|
||||
|
||||
switch (damagetype & DMG_TYPEMASK)
|
||||
{
|
||||
case DMG_VOLTAGE:
|
||||
if (monitor->health < HEALTHFACTOR)
|
||||
{
|
||||
return HEALTHFACTOR;
|
||||
}
|
||||
else
|
||||
{
|
||||
// always reduce to final damage state
|
||||
return (monitor->health - HEALTHFACTOR) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (inflictor == NULL)
|
||||
{
|
||||
return HEALTHFACTOR;
|
||||
}
|
||||
|
||||
if (inflictor->player)
|
||||
{
|
||||
const fixed_t weight =
|
||||
K_GetMobjWeight(inflictor, monitor);
|
||||
|
||||
// HEALTHFACTOR is the minimum damage that can be
|
||||
// dealt but player's weight (and speed) can buff the hit.
|
||||
damage = HEALTHFACTOR +
|
||||
(FixedMul(weight, HEALTHFACTOR) / 9);
|
||||
|
||||
if (inflictor->scale > mapobjectscale)
|
||||
{
|
||||
damage = P_ScaleFromMap(damage, inflictor->scale);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
damage = FRACUNIT; // kill instantly
|
||||
}
|
||||
|
||||
return damage;
|
||||
}
|
||||
|
||||
void
|
||||
Obj_MonitorOnDamage
|
||||
( mobj_t * monitor,
|
||||
mobj_t * inflictor,
|
||||
INT32 damage)
|
||||
{
|
||||
monitor->fuse = BATTLE_DESPAWN_TIME;
|
||||
monitor_damage(monitor) = damage;
|
||||
monitor_rammingspeed(monitor) = inflictor
|
||||
? FixedDiv(FixedHypot(inflictor->momx, inflictor->momy), 4 * inflictor->radius) : 0;
|
||||
monitor->hitlag =
|
||||
6 * get_damage_multiplier(monitor) / FRACUNIT;
|
||||
}
|
||||
|
||||
void
|
||||
Obj_MonitorOnDeath (mobj_t *monitor)
|
||||
{
|
||||
const UINT8 itemcount = get_monitor_itemcount(monitor);
|
||||
const angle_t ang = ANGLE_MAX / itemcount;
|
||||
const SINT8 flip = P_MobjFlip(monitor);
|
||||
|
||||
INT32 i;
|
||||
|
||||
UINT32 sharedseed = restore_item_rng(
|
||||
monitor_rngseed(monitor));
|
||||
|
||||
for (i = 0; i < itemcount; ++i)
|
||||
{
|
||||
const SINT8 result = get_item_result();
|
||||
const UINT32 localseed = restore_item_rng(sharedseed);
|
||||
|
||||
adjust_monitor_drop(monitor,
|
||||
K_CreatePaperItem(
|
||||
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
|
||||
// copy of the seed afterward
|
||||
sharedseed = restore_item_rng(localseed);
|
||||
}
|
||||
|
||||
restore_item_rng(sharedseed);
|
||||
|
||||
if (monitor_emerald(monitor) != 0)
|
||||
{
|
||||
adjust_monitor_drop(monitor,
|
||||
K_SpawnChaosEmerald(monitor->x, monitor->y, monitor->z + (128 * mapobjectscale * flip),
|
||||
ang, flip, monitor_emerald(monitor)));
|
||||
}
|
||||
|
||||
spawn_monitor_explosion(monitor);
|
||||
|
||||
// There is hitlag from being damaged, so remove
|
||||
// tangibility RIGHT NOW.
|
||||
monitor->flags &= ~(MF_SOLID);
|
||||
|
||||
if (!P_MobjWasRemoved(monitor_spot(monitor)))
|
||||
{
|
||||
Obj_ItemSpotUpdate(monitor_spot(monitor));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Obj_MonitorShardThink (mobj_t *shard)
|
||||
{
|
||||
if (shard_can_roll(shard))
|
||||
{
|
||||
shard->rollangle += ANGLE_45;
|
||||
}
|
||||
|
||||
shard->renderflags ^= RF_DONTDRAW;
|
||||
}
|
||||
|
||||
UINT32
|
||||
Obj_MonitorGetEmerald (const mobj_t *monitor)
|
||||
{
|
||||
return monitor_emerald(monitor);
|
||||
}
|
||||
|
||||
void
|
||||
Obj_MonitorSetItemSpot
|
||||
( mobj_t * monitor,
|
||||
mobj_t * spot)
|
||||
{
|
||||
P_SetTarget(&monitor_spot(monitor), spot);
|
||||
}
|
||||
|
|
@ -1666,6 +1666,10 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
|
|||
break;
|
||||
}
|
||||
|
||||
case MT_MONITOR:
|
||||
Obj_MonitorOnDeath(target);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -2007,6 +2011,17 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
laglength = 0; // handled elsewhere
|
||||
}
|
||||
|
||||
switch (target->type)
|
||||
{
|
||||
case MT_MONITOR:
|
||||
damage = Obj_MonitorGetDamage(target, inflictor, damagetype);
|
||||
Obj_MonitorOnDamage(target, inflictor, damage);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Everything above here can't be forced.
|
||||
if (!metalrecording)
|
||||
{
|
||||
|
|
|
|||
12
src/p_map.c
12
src/p_map.c
|
|
@ -1537,6 +1537,18 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
|||
K_KartBouncing(tm.thing, thing);
|
||||
return BMIT_CONTINUE;
|
||||
}
|
||||
else if (thing->type == MT_MONITOR)
|
||||
{
|
||||
// see if it went over / under
|
||||
if (tm.thing->z > thing->z + thing->height)
|
||||
return BMIT_CONTINUE; // overhead
|
||||
if (tm.thing->z + tm.thing->height < thing->z)
|
||||
return BMIT_CONTINUE; // underneath
|
||||
|
||||
P_DamageMobj(thing, tm.thing, tm.thing, 1, DMG_NORMAL);
|
||||
K_KartBouncing(tm.thing, thing);
|
||||
return BMIT_CONTINUE;
|
||||
}
|
||||
else if (thing->flags & MF_SOLID)
|
||||
{
|
||||
// see if it went over / under
|
||||
|
|
|
|||
69
src/p_mobj.c
69
src/p_mobj.c
|
|
@ -1225,6 +1225,21 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
|
|||
case MT_ITEM_DEBRIS:
|
||||
gravityadd *= 6;
|
||||
break;
|
||||
case MT_FLOATINGITEM: {
|
||||
// Basically this accelerates gravity after
|
||||
// the object reached its peak vertical
|
||||
// momentum. It's a gradual acceleration up
|
||||
// to 2x normal gravity. It's not instant to
|
||||
// give it some 'weight'.
|
||||
const fixed_t z = P_MobjFlip(mo) * mo->momz;
|
||||
if (z < 0)
|
||||
{
|
||||
const fixed_t d = (z - (mo->height / 2));
|
||||
const fixed_t f = 2 * abs(FixedDiv(d, mo->height));
|
||||
gravityadd = FixedMul(gravityadd, FRACUNIT + min(f, 2*FRACUNIT));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -3077,6 +3092,17 @@ boolean P_SceneryZMovement(mobj_t *mo)
|
|||
P_RemoveMobj(mo);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case MT_MONITOR_SHARD:
|
||||
// Hits the ground
|
||||
if ((mo->eflags & MFE_VERTICALFLIP)
|
||||
? (mo->ceilingz <= (mo->z + mo->height))
|
||||
: (mo->z <= mo->floorz))
|
||||
{
|
||||
P_RemoveMobj(mo);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -5723,6 +5749,21 @@ static void P_MobjSceneryThink(mobj_t *mobj)
|
|||
P_AddOverlay(mobj);
|
||||
if (mobj->target->hitlag) // move to the correct position, update to the correct properties, but DON'T STATE-ANIMATE
|
||||
return;
|
||||
switch (mobj->target->type)
|
||||
{
|
||||
case MT_FLOATINGITEM:
|
||||
// Spawn trail for item drop as it flies upward.
|
||||
// Done here so it applies to backdrop too.
|
||||
if (mobj->target->momz * P_MobjFlip(mobj->target) > 0)
|
||||
{
|
||||
P_SpawnGhostMobj(mobj);
|
||||
P_SpawnGhostMobj(mobj->target);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case MT_WATERDROP:
|
||||
P_SceneryCheckWater(mobj);
|
||||
|
|
@ -6520,6 +6561,9 @@ static void P_MobjSceneryThink(mobj_t *mobj)
|
|||
return;
|
||||
}
|
||||
break;
|
||||
case MT_MONITOR_SHARD:
|
||||
Obj_MonitorShardThink(mobj);
|
||||
break;
|
||||
case MT_VWREF:
|
||||
case MT_VWREB:
|
||||
{
|
||||
|
|
@ -7382,6 +7426,12 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
break;
|
||||
}
|
||||
case MT_EMERALD:
|
||||
{
|
||||
if (mobj->threshold > 0)
|
||||
mobj->threshold--;
|
||||
}
|
||||
/*FALLTHRU*/
|
||||
case MT_MONITOR:
|
||||
{
|
||||
if (battleovertime.enabled >= 10*TICRATE)
|
||||
{
|
||||
|
|
@ -7394,6 +7444,14 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
}
|
||||
}
|
||||
|
||||
// Don't spawn sparkles on a monitor with no
|
||||
// emerald inside
|
||||
if (mobj->type == MT_MONITOR &&
|
||||
Obj_MonitorGetEmerald(mobj) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (leveltime % 3 == 0)
|
||||
{
|
||||
mobj_t *sparkle = P_SpawnMobjFromMobj(
|
||||
|
|
@ -7407,9 +7465,6 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
sparkle->color = mobj->color;
|
||||
sparkle->momz += 8 * mobj->scale * P_MobjFlip(mobj);
|
||||
}
|
||||
|
||||
if (mobj->threshold > 0)
|
||||
mobj->threshold--;
|
||||
}
|
||||
break;
|
||||
case MT_DRIFTEXPLODE:
|
||||
|
|
@ -9414,6 +9469,9 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
mobj->colorized = false;
|
||||
}
|
||||
break;
|
||||
case MT_MONITOR_PART:
|
||||
Obj_MonitorPartThink(mobj);
|
||||
break;
|
||||
default:
|
||||
// check mobj against possible water content, before movement code
|
||||
P_MobjCheckWater(mobj);
|
||||
|
|
@ -9519,6 +9577,7 @@ static boolean P_CanFlickerFuse(mobj_t *mobj)
|
|||
case MT_SNAPPER_HEAD:
|
||||
case MT_SNAPPER_LEG:
|
||||
case MT_MINECARTSEG:
|
||||
case MT_MONITOR_PART:
|
||||
return true;
|
||||
|
||||
case MT_RANDOMITEM:
|
||||
|
|
@ -10620,6 +10679,10 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
|
|||
|
||||
break;
|
||||
}
|
||||
case MT_MONITOR: {
|
||||
Obj_MonitorSpawnParts(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_KARMAHITBOX:
|
||||
{
|
||||
const fixed_t rad = FixedMul(mobjinfo[MT_PLAYER].radius, mobj->scale);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue