mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2026-04-27 12:31:54 +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_BOTTOM",
|
||||||
//"S_ITEMCAPSULE_INSIDE",
|
//"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",
|
||||||
"S_MAGICIANBOXTOP",
|
"S_MAGICIANBOXTOP",
|
||||||
"S_MAGICIANBOXBOTTOM",
|
"S_MAGICIANBOXBOTTOM",
|
||||||
|
|
@ -5298,6 +5316,9 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
|
||||||
"MT_FLOATINGITEM",
|
"MT_FLOATINGITEM",
|
||||||
"MT_ITEMCAPSULE",
|
"MT_ITEMCAPSULE",
|
||||||
"MT_ITEMCAPSULE_PART",
|
"MT_ITEMCAPSULE_PART",
|
||||||
|
"MT_MONITOR",
|
||||||
|
"MT_MONITOR_PART",
|
||||||
|
"MT_MONITOR_SHARD",
|
||||||
"MT_MAGICIANBOX",
|
"MT_MAGICIANBOX",
|
||||||
|
|
||||||
"MT_SIGNSPARKLE",
|
"MT_SIGNSPARKLE",
|
||||||
|
|
|
||||||
102
src/info.c
102
src/info.c
|
|
@ -548,6 +548,9 @@ char sprnames[NUMSPRITES + 1][5] =
|
||||||
"MGBX", // Heavy Magician transform box
|
"MGBX", // Heavy Magician transform box
|
||||||
"MGBT", // Heavy Magician transform box top
|
"MGBT", // Heavy Magician transform box top
|
||||||
"MGBB", // Heavy Magician transform box bottom
|
"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
|
"WIPD", // Wipeout dust trail
|
||||||
"DRIF", // Drift Sparks
|
"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|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_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_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_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
|
{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
|
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
|
{ // MT_MAGICIANBOX
|
||||||
-1, // doomednum
|
-1, // doomednum
|
||||||
S_MAGICIANBOX, // spawnstate
|
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_MGBX, // Heavy Magician transform box
|
||||||
SPR_MGBT, // Heavy Magician transform box top
|
SPR_MGBT, // Heavy Magician transform box top
|
||||||
SPR_MGBB, // Heavy Magician transform box bottom
|
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_WIPD, // Wipeout dust trail
|
||||||
SPR_DRIF, // Drift Sparks
|
SPR_DRIF, // Drift Sparks
|
||||||
|
|
@ -4311,6 +4314,24 @@ typedef enum state
|
||||||
//S_ITEMCAPSULE_BOTTOM,
|
//S_ITEMCAPSULE_BOTTOM,
|
||||||
//S_ITEMCAPSULE_INSIDE,
|
//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,
|
||||||
S_MAGICIANBOX_TOP,
|
S_MAGICIANBOX_TOP,
|
||||||
S_MAGICIANBOX_BOTTOM,
|
S_MAGICIANBOX_BOTTOM,
|
||||||
|
|
@ -6362,6 +6383,9 @@ typedef enum mobj_type
|
||||||
MT_FLOATINGITEM,
|
MT_FLOATINGITEM,
|
||||||
MT_ITEMCAPSULE,
|
MT_ITEMCAPSULE,
|
||||||
MT_ITEMCAPSULE_PART,
|
MT_ITEMCAPSULE_PART,
|
||||||
|
MT_MONITOR,
|
||||||
|
MT_MONITOR_PART,
|
||||||
|
MT_MONITOR_SHARD,
|
||||||
MT_MAGICIANBOX,
|
MT_MAGICIANBOX,
|
||||||
|
|
||||||
MT_SIGNSPARKLE,
|
MT_SIGNSPARKLE,
|
||||||
|
|
|
||||||
135
src/k_battle.c
135
src/k_battle.c
|
|
@ -18,6 +18,7 @@
|
||||||
#include "r_sky.h" // skyflatnum
|
#include "r_sky.h" // skyflatnum
|
||||||
#include "k_grandprix.h" // K_CanChangeRules
|
#include "k_grandprix.h" // K_CanChangeRules
|
||||||
#include "p_spec.h"
|
#include "p_spec.h"
|
||||||
|
#include "k_objects.h"
|
||||||
|
|
||||||
// Battle overtime info
|
// Battle overtime info
|
||||||
struct battleovertime battleovertime;
|
struct battleovertime battleovertime;
|
||||||
|
|
@ -472,9 +473,7 @@ void K_RunPaperItemSpawners(void)
|
||||||
#define MAXITEM 64
|
#define MAXITEM 64
|
||||||
mobj_t *spotList[MAXITEM];
|
mobj_t *spotList[MAXITEM];
|
||||||
UINT8 spotMap[MAXITEM];
|
UINT8 spotMap[MAXITEM];
|
||||||
UINT8 spotCount = 0, spotBackup = 0;
|
UINT8 spotCount = 0, spotBackup = 0, spotAvailable = 0;
|
||||||
|
|
||||||
INT16 starti = 0;
|
|
||||||
|
|
||||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||||
{
|
{
|
||||||
|
|
@ -488,14 +487,26 @@ void K_RunPaperItemSpawners(void)
|
||||||
emeraldsSpawned |= mo->extravalue1;
|
emeraldsSpawned |= mo->extravalue1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mo->type == MT_MONITOR)
|
||||||
|
{
|
||||||
|
emeraldsSpawned |= Obj_MonitorGetEmerald(mo);
|
||||||
|
}
|
||||||
|
|
||||||
if (mo->type != MT_PAPERITEMSPOT)
|
if (mo->type != MT_PAPERITEMSPOT)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (spotCount >= MAXITEM)
|
if (spotCount >= MAXITEM)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (Obj_ItemSpotIsAvailable(mo))
|
||||||
|
{
|
||||||
|
// spotMap first only includes spots
|
||||||
|
// where a monitor doesn't exist
|
||||||
|
spotMap[spotAvailable] = spotCount;
|
||||||
|
spotAvailable++;
|
||||||
|
}
|
||||||
|
|
||||||
spotList[spotCount] = mo;
|
spotList[spotCount] = mo;
|
||||||
spotMap[spotCount] = spotCount;
|
|
||||||
spotCount++;
|
spotCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -513,7 +524,6 @@ void K_RunPaperItemSpawners(void)
|
||||||
if (!(emeraldsSpawned & emeraldFlag))
|
if (!(emeraldsSpawned & emeraldFlag))
|
||||||
{
|
{
|
||||||
firstUnspawnedEmerald = emeraldFlag;
|
firstUnspawnedEmerald = emeraldFlag;
|
||||||
starti = -1;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -521,77 +531,72 @@ void K_RunPaperItemSpawners(void)
|
||||||
|
|
||||||
//CONS_Printf("leveltime = %d ", leveltime);
|
//CONS_Printf("leveltime = %d ", leveltime);
|
||||||
|
|
||||||
spotBackup = spotCount;
|
if (spotAvailable > 0)
|
||||||
for (i = starti; i < pcount; i++)
|
|
||||||
{
|
{
|
||||||
UINT8 r = 0, key = 0;
|
const UINT8 r = spotMap[P_RandomKey(PR_ITEM_ROULETTE, spotAvailable)];
|
||||||
mobj_t *drop = NULL;
|
|
||||||
SINT8 flip = 1;
|
|
||||||
|
|
||||||
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
|
UINT8 r = 0, key = 0;
|
||||||
spotCount = spotBackup;
|
mobj_t *drop = NULL;
|
||||||
}
|
SINT8 flip = 1;
|
||||||
|
|
||||||
if (spotCount == 1)
|
if (spotCount == 0)
|
||||||
{
|
|
||||||
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))
|
|
||||||
{
|
{
|
||||||
drop = K_SpawnSphereBox(
|
// all are accessible again
|
||||||
spotList[r]->x, spotList[r]->y, spotList[r]->z + (128 * mapobjectscale * flip),
|
spotCount = spotBackup;
|
||||||
FixedAngle(P_RandomRange(PR_ITEM_ROULETTE, 0, 359) * FRACUNIT), flip,
|
|
||||||
10
|
|
||||||
);
|
|
||||||
K_FlipFromObject(drop, spotList[r]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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),
|
spotList[r]->x, spotList[r]->y, spotList[r]->z + (128 * mapobjectscale * flip),
|
||||||
FixedAngle(P_RandomRange(PR_ITEM_ROULETTE, 0, 359) * FRACUNIT), flip,
|
FixedAngle(P_RandomRange(PR_ITEM_ROULETTE, 0, 359) * FRACUNIT), flip,
|
||||||
0, 0
|
10
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
K_FlipFromObject(drop, spotList[r]);
|
K_FlipFromObject(drop, spotList[r]);
|
||||||
|
|
||||||
spotCount--;
|
spotCount--;
|
||||||
if (key != spotCount)
|
if (key != spotCount)
|
||||||
{
|
{
|
||||||
// So the core theory of what's going on is that we keep every
|
// 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
|
// available option at the front of the array, so we don't have
|
||||||
// to skip over any gaps or do recursion to avoid doubles.
|
// to skip over any gaps or do recursion to avoid doubles.
|
||||||
// But because spotCount can be reset in the case of a low
|
// But because spotCount can be reset in the case of a low
|
||||||
// quanitity of item spawnpoints in a map, we still need every
|
// quanitity of item spawnpoints in a map, we still need every
|
||||||
// entry in the array, even outside of the "visible" range.
|
// entry in the array, even outside of the "visible" range.
|
||||||
// A series of swaps allows us to adhere to both constraints.
|
// A series of swaps allows us to adhere to both constraints.
|
||||||
// -toast 22/03/22 (semipalindromic!)
|
// -toast 22/03/22 (semipalindromic!)
|
||||||
spotMap[key] = spotMap[spotCount];
|
spotMap[key] = spotMap[spotCount];
|
||||||
spotMap[spotCount] = r; // was set to spotMap[key] previously
|
spotMap[spotCount] = r; // was set to spotMap[key] previously
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//CONS_Printf("\n");
|
//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.
|
// from causing super crazy bumps.
|
||||||
fixed_t spd = K_GetKartSpeed(mobj->player, false, true);
|
fixed_t spd = K_GetKartSpeed(mobj->player, false, true);
|
||||||
|
|
||||||
|
fixed_t speedfactor = 8 * mapobjectscale;
|
||||||
|
|
||||||
weight = (mobj->player->kartweight) * FRACUNIT;
|
weight = (mobj->player->kartweight) * FRACUNIT;
|
||||||
|
|
||||||
if (mobj->player->speed > spd)
|
if (against && against->type == MT_MONITOR)
|
||||||
weight += FixedDiv((mobj->player->speed - spd), 8 * mapobjectscale);
|
{
|
||||||
|
speedfactor /= 5; // speed matters more
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (mobj->player->itemtype == KITEM_BUBBLESHIELD)
|
||||||
|
weight += 9*FRACUNIT;
|
||||||
|
}
|
||||||
|
|
||||||
if (mobj->player->itemtype == KITEM_BUBBLESHIELD)
|
if (mobj->player->speed > spd)
|
||||||
weight += 9*FRACUNIT;
|
weight += FixedDiv((mobj->player->speed - spd), speedfactor);
|
||||||
}
|
}
|
||||||
|
|
||||||
return weight;
|
return weight;
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,22 @@ void Obj_UFOPieceRemoved(mobj_t *piece);
|
||||||
mobj_t *Obj_CreateSpecialUFO(void);
|
mobj_t *Obj_CreateSpecialUFO(void);
|
||||||
UINT32 K_GetSpecialUFODistance(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
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -10,4 +10,6 @@ target_sources(SRB2SDL2 PRIVATE
|
||||||
duel-bomb.c
|
duel-bomb.c
|
||||||
broly.c
|
broly.c
|
||||||
ufo.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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case MT_MONITOR:
|
||||||
|
Obj_MonitorOnDeath(target);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -2007,6 +2011,17 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
||||||
laglength = 0; // handled elsewhere
|
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.
|
// Everything above here can't be forced.
|
||||||
if (!metalrecording)
|
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);
|
K_KartBouncing(tm.thing, thing);
|
||||||
return BMIT_CONTINUE;
|
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)
|
else if (thing->flags & MF_SOLID)
|
||||||
{
|
{
|
||||||
// see if it went over / under
|
// 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:
|
case MT_ITEM_DEBRIS:
|
||||||
gravityadd *= 6;
|
gravityadd *= 6;
|
||||||
break;
|
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:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -3077,6 +3092,17 @@ boolean P_SceneryZMovement(mobj_t *mo)
|
||||||
P_RemoveMobj(mo);
|
P_RemoveMobj(mo);
|
||||||
return false;
|
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:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -5723,6 +5749,21 @@ static void P_MobjSceneryThink(mobj_t *mobj)
|
||||||
P_AddOverlay(mobj);
|
P_AddOverlay(mobj);
|
||||||
if (mobj->target->hitlag) // move to the correct position, update to the correct properties, but DON'T STATE-ANIMATE
|
if (mobj->target->hitlag) // move to the correct position, update to the correct properties, but DON'T STATE-ANIMATE
|
||||||
return;
|
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;
|
break;
|
||||||
case MT_WATERDROP:
|
case MT_WATERDROP:
|
||||||
P_SceneryCheckWater(mobj);
|
P_SceneryCheckWater(mobj);
|
||||||
|
|
@ -6520,6 +6561,9 @@ static void P_MobjSceneryThink(mobj_t *mobj)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case MT_MONITOR_SHARD:
|
||||||
|
Obj_MonitorShardThink(mobj);
|
||||||
|
break;
|
||||||
case MT_VWREF:
|
case MT_VWREF:
|
||||||
case MT_VWREB:
|
case MT_VWREB:
|
||||||
{
|
{
|
||||||
|
|
@ -7382,6 +7426,12 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MT_EMERALD:
|
case MT_EMERALD:
|
||||||
|
{
|
||||||
|
if (mobj->threshold > 0)
|
||||||
|
mobj->threshold--;
|
||||||
|
}
|
||||||
|
/*FALLTHRU*/
|
||||||
|
case MT_MONITOR:
|
||||||
{
|
{
|
||||||
if (battleovertime.enabled >= 10*TICRATE)
|
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)
|
if (leveltime % 3 == 0)
|
||||||
{
|
{
|
||||||
mobj_t *sparkle = P_SpawnMobjFromMobj(
|
mobj_t *sparkle = P_SpawnMobjFromMobj(
|
||||||
|
|
@ -7407,9 +7465,6 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
||||||
sparkle->color = mobj->color;
|
sparkle->color = mobj->color;
|
||||||
sparkle->momz += 8 * mobj->scale * P_MobjFlip(mobj);
|
sparkle->momz += 8 * mobj->scale * P_MobjFlip(mobj);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mobj->threshold > 0)
|
|
||||||
mobj->threshold--;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MT_DRIFTEXPLODE:
|
case MT_DRIFTEXPLODE:
|
||||||
|
|
@ -9414,6 +9469,9 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
||||||
mobj->colorized = false;
|
mobj->colorized = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case MT_MONITOR_PART:
|
||||||
|
Obj_MonitorPartThink(mobj);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
// check mobj against possible water content, before movement code
|
// check mobj against possible water content, before movement code
|
||||||
P_MobjCheckWater(mobj);
|
P_MobjCheckWater(mobj);
|
||||||
|
|
@ -9519,6 +9577,7 @@ static boolean P_CanFlickerFuse(mobj_t *mobj)
|
||||||
case MT_SNAPPER_HEAD:
|
case MT_SNAPPER_HEAD:
|
||||||
case MT_SNAPPER_LEG:
|
case MT_SNAPPER_LEG:
|
||||||
case MT_MINECARTSEG:
|
case MT_MINECARTSEG:
|
||||||
|
case MT_MONITOR_PART:
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case MT_RANDOMITEM:
|
case MT_RANDOMITEM:
|
||||||
|
|
@ -10620,6 +10679,10 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case MT_MONITOR: {
|
||||||
|
Obj_MonitorSpawnParts(mobj);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case MT_KARMAHITBOX:
|
case MT_KARMAHITBOX:
|
||||||
{
|
{
|
||||||
const fixed_t rad = FixedMul(mobjinfo[MT_PLAYER].radius, mobj->scale);
|
const fixed_t rad = FixedMul(mobjinfo[MT_PLAYER].radius, mobj->scale);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue