"Drop Target" item initial commit.

Most of the way there, but still a bit left to do.
This commit is contained in:
toaster 2022-03-21 17:34:36 +00:00
parent 306d1cd3ae
commit 52d2472ed7
15 changed files with 574 additions and 122 deletions

View file

@ -348,6 +348,7 @@ consvar_t cv_orbinaut = CVAR_INIT ("orbinaut", "On", CV_NETVAR|CV_CHEAT, C
consvar_t cv_jawz = CVAR_INIT ("jawz", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_mine = CVAR_INIT ("mine", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_landmine = CVAR_INIT ("landmine", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_droptarget = CVAR_INIT ("droptarget", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_ballhog = CVAR_INIT ("ballhog", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_selfpropelledbomb = CVAR_INIT ("selfpropelledbomb", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_grow = CVAR_INIT ("grow", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);

View file

@ -61,7 +61,7 @@ extern consvar_t cv_restrictskinchange, cv_allowteamchange, cv_ingamecap, cv_res
// SRB2kart items
extern consvar_t cv_superring, cv_sneaker, cv_rocketsneaker, cv_invincibility, cv_banana;
extern consvar_t cv_eggmanmonitor, cv_orbinaut, cv_jawz, cv_mine, cv_landmine;
extern consvar_t cv_eggmanmonitor, cv_orbinaut, cv_jawz, cv_mine, cv_landmine, cv_droptarget;
extern consvar_t cv_ballhog, cv_selfpropelledbomb, cv_grow, cv_shrink;
extern consvar_t cv_thundershield, cv_bubbleshield, cv_flameshield;
extern consvar_t cv_hyudoro, cv_pogospring, cv_kitchensink;

View file

@ -141,17 +141,18 @@ Run this macro, then #undef FOREACH afterward
FOREACH (JAWZ, 7),\
FOREACH (MINE, 8),\
FOREACH (LANDMINE, 9),\
FOREACH (BALLHOG, 10),\
FOREACH (SPB, 11),\
FOREACH (GROW, 12),\
FOREACH (SHRINK, 13),\
FOREACH (THUNDERSHIELD, 14),\
FOREACH (BUBBLESHIELD, 15),\
FOREACH (FLAMESHIELD, 16),\
FOREACH (HYUDORO, 17),\
FOREACH (POGOSPRING, 18),\
FOREACH (SUPERRING, 19),\
FOREACH (KITCHENSINK, 20)
FOREACH (DROPTARGET, 10),\
FOREACH (BALLHOG, 11),\
FOREACH (SPB, 12),\
FOREACH (GROW, 13),\
FOREACH (SHRINK, 14),\
FOREACH (THUNDERSHIELD, 15),\
FOREACH (BUBBLESHIELD, 16),\
FOREACH (FLAMESHIELD, 17),\
FOREACH (HYUDORO, 18),\
FOREACH (POGOSPRING, 19),\
FOREACH (SUPERRING, 20),\
FOREACH (KITCHENSINK, 21)
typedef enum
{

View file

@ -3811,6 +3811,10 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
"S_LANDMINE",
"S_LANDMINE_EXPLODE",
// Drop Target
"S_DROPTARGET",
"S_DROPTARGET_SPIN",
// Ballhog
"S_BALLHOG1",
"S_BALLHOG2",
@ -5521,6 +5525,9 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
"MT_LANDMINE", // Land Mine
"MT_DROPTARGET", // Drop Target
"MT_DROPTARGET_SHIELD",
"MT_BALLHOG", // Ballhog
"MT_BALLHOGBOOM",

View file

@ -557,6 +557,7 @@ char sprnames[NUMSPRITES + 1][5] =
"SSMN", // SS Mine
"KRBM", // SS Mine BOOM
"LNDM", // Land Mine
"DTRG", // Drop Target
"BHOG", // Ballhog
"BHBM", // Ballhog BOOM
"SPBM", // Self-Propelled Bomb
@ -4375,6 +4376,9 @@ state_t states[NUMSTATES] =
{SPR_LNDM, 0, -1, {NULL}, 0, 0, S_LANDMINE}, // S_LANDMINE
{SPR_NULL, 0, 1, {A_LandMineExplode}, 0, 0, S_NULL}, // S_LANDMINE_EXPLODE
{SPR_DTRG, 0, -1, {NULL}, 0, 0, S_NULL}, // S_DROPTARGET
{SPR_DTRG, 1, -1, {NULL}, 0, 0, S_NULL}, // S_DROPTARGET_SPIN
{SPR_BHOG, 0, 3, {A_PlaySound}, sfx_s1bd, 1, S_BALLHOG2}, // S_BALLHOG1
{SPR_BHOG, FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_BALLHOG3}, // S_BALLHOG2
{SPR_BHOG, FF_FULLBRIGHT|2, 2, {NULL}, 0, 0, S_BALLHOG4}, // S_BALLHOG3
@ -24193,6 +24197,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_DROPTARGET
-1, // doomednum
S_DROPTARGET, // spawnstate
3, // spawnhealth
S_NULL, // seestate
sfx_tossed, // seesound
0, // reactiontime
sfx_None, // attacksound
S_DROPTARGET_SPIN, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_DROPTARGET_SPIN, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
128*FRACUNIT, // speed
45*FRACUNIT, // radius
32*FRACUNIT, // height
0, // display offset
100, // mass
1, // damage
sfx_s3k96, // activesound
MF_SPECIAL|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
{ // MT_DROPTARGET_SHIELD
-1, // doomednum
S_DROPTARGET, // spawnstate
3, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
0, // reactiontime
sfx_None, // attacksound
S_DROPTARGET_SPIN, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_DROPTARGET_SPIN, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
45*FRACUNIT, // radius
32*FRACUNIT, // height
0, // display offset
100, // mass
1, // damage
sfx_None, // activesound
MF_SPECIAL|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
{ // MT_BALLHOG
-1, // doomednum
S_BALLHOG1, // spawnstate

View file

@ -1101,6 +1101,7 @@ typedef enum sprite
SPR_SSMN, // SS Mine
SPR_KRBM, // SS Mine BOOM
SPR_LNDM, // Land Mine
SPR_DTRG, // Drop Target
SPR_BHOG, // Ballhog
SPR_BHBM, // Ballhog BOOM
SPR_SPBM, // Self-Propelled Bomb
@ -4789,6 +4790,10 @@ typedef enum state
S_LANDMINE,
S_LANDMINE_EXPLODE,
// Drop Target
S_DROPTARGET,
S_DROPTARGET_SPIN,
// Ballhog
S_BALLHOG1,
S_BALLHOG2,
@ -6536,6 +6541,9 @@ typedef enum mobj_type
MT_LANDMINE, // Land Mine
MT_DROPTARGET, // Drop Target
MT_DROPTARGET_SHIELD,
MT_BALLHOG, // Ballhog
MT_BALLHOGBOOM,

View file

@ -882,6 +882,64 @@ static void K_BotItemOrbinaut(player_t *player, ticcmd_t *cmd)
}
}
/*--------------------------------------------------
static void K_BotItemDropTarget(player_t *player, ticcmd_t *cmd)
Item usage for Drop Target throwing.
Input Arguments:-
player - Bot to do this for.
cmd - Bot's ticcmd to edit.
Return:-
None
--------------------------------------------------*/
static void K_BotItemDropTarget(player_t *player, ticcmd_t *cmd)
{
const fixed_t topspeed = K_GetKartSpeed(player, false);
fixed_t radius = FixedMul(1280 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed));
SINT8 throwdir = -1;
boolean tryLookback = false;
UINT8 snipeMul = 2;
player_t *target = NULL;
if (player->speed > topspeed)
{
radius = FixedMul(radius, FixedDiv(player->speed, topspeed));
snipeMul = 3; // Confirm faster when you'll throw it with a bunch of extra speed!!
}
player->botvars.itemconfirm++;
target = K_PlayerInCone(player, radius, 15, false);
if (target != NULL)
{
K_ItemConfirmForTarget(player, target, player->botvars.difficulty * snipeMul);
throwdir = 1;
}
else
{
target = K_PlayerInCone(player, radius, 15, true);
if (target != NULL)
{
K_ItemConfirmForTarget(player, target, player->botvars.difficulty);
throwdir = -1;
tryLookback = true;
}
}
if (tryLookback == true && throwdir == -1)
{
cmd->buttons |= BT_LOOKBACK;
}
if (player->botvars.itemconfirm > 25*TICRATE)
{
K_BotGenericPressItem(player, cmd, throwdir);
}
}
/*--------------------------------------------------
static void K_BotItemJawz(player_t *player, ticcmd_t *cmd)
@ -1287,6 +1345,16 @@ void K_BotItemUsage(player_t *player, ticcmd_t *cmd, INT16 turnamt)
case KITEM_LANDMINE:
K_BotItemLandmine(player, cmd, turnamt);
break;
case KITEM_DROPTARGET:
if (!(player->pflags & PF_ITEMOUT))
{
K_BotItemGenericTrapShield(player, cmd, turnamt, false);
}
else
{
K_BotItemDropTarget(player, cmd);
}
break;
case KITEM_THUNDERSHIELD:
K_BotItemThunder(player, cmd);
break;

View file

@ -418,6 +418,8 @@ static boolean K_FindObjectsForNudging(mobj_t *thing)
case MT_SSMINE:
case MT_SSMINE_SHIELD:
case MT_LANDMINE:
case MT_DROPTARGET:
case MT_DROPTARGET_SHIELD:
case MT_BALLHOG:
case MT_SPB:
case MT_BUBBLESHIELDTRAP:

View file

@ -411,6 +411,180 @@ boolean K_LandMineCollide(mobj_t *t1, mobj_t *t2)
return true;
}
boolean K_DropTargetCollide(mobj_t *t1, mobj_t *t2)
{
mobj_t *draggeddroptarget = (t1->type == MT_DROPTARGET_SHIELD) ? t1->target : NULL;
if ((t1->threshold > 0 && (t2->hitlag > 0 || !draggeddroptarget)) || (t2->threshold > 0 && t1->hitlag > 0))
return true;
if (((t1->target == t2) || (t1->target == t2->target)) && (t1->threshold > 0 || (t2->type != MT_PLAYER && t2->threshold > 0)))
return true;
if (t1->health <= 0 || t2->health <= 0)
return true;
if (t2->player && (t2->player->hyudorotimer || t2->player->justbumped))
return true;
// Intensify bumps if already spinning...
P_Thrust(t1, R_PointToAngle2(t1->x, t1->y, t2->x, t2->y),
(t1->reactiontime && !draggeddroptarget) ? 35*FRACUNIT : 20*FRACUNIT);
if (draggeddroptarget)
{
// "Pass through" the shock of the impact, part 1.
t1->momx = t1->target->momx;
t1->momy = t1->target->momy;
t1->momz = t1->target->momz;
}
{
angle_t t2angle = R_PointToAngle2(t2->momx, t2->momy, 0, 0);
angle_t t2deflect;
fixed_t t1speed, t2speed;
K_KartBouncing(t1, t2);
t1speed = FixedHypot(t1->momx, t1->momy);
t2speed = FixedHypot(t2->momx, t2->momy);
t2deflect = t2angle - R_PointToAngle2(0, 0, t2->momx, t2->momy);
if (t2deflect > ANGLE_180)
t2deflect = InvAngle(t2deflect);
if (t2deflect < ANG10)
P_InstaThrust(t2, t2angle, t2speed);
P_InitAngle(t1, R_PointToAngle2(0, 0, t1->momx, t1->momy));
t1->reactiontime = 7*(t1speed+t2speed)/FRACUNIT;
if (t1->reactiontime < 10)
t1->reactiontime = 10;
t1->threshold = 10;
}
t1->renderflags &= ~RF_FULLDARK; // brightest on the bump
if (draggeddroptarget)
{
// "Pass through" the shock of the impact, part 2.
draggeddroptarget->momx = t1->momx;
draggeddroptarget->momy = t1->momy;
draggeddroptarget->momz = t1->momz;
// Have the drop target travel between them.
t1->momx = (t1->momx + t2->momx)/2;
t1->momy = (t1->momy + t2->momy)/2;
t1->momz = (t1->momz + t2->momz)/2;
K_AddHitLag(t1->target, 6, false);
}
K_AddHitLag(t1, 6, true);
K_AddHitLag(t2, 6, false);
{
mobj_t *ghost = P_SpawnGhostMobj(t1);
UINT8 i;
P_SetScale(ghost, 3*ghost->destscale/2);
ghost->destscale = 15*ghost->destscale/2;
ghost->fuse = 10;
ghost->scalespeed = (ghost->destscale - ghost->scale)/ghost->fuse;
for (i = 0; i < 2; i++)
{
mobj_t *blast = P_SpawnMobjFromMobj(t1, 0, 0, FixedDiv(t1->height, t1->scale), MT_BATTLEBUMPER_BLAST);
P_SetScale(blast, 5*blast->scale/2);
blast->angle = R_PointToAngle2(0, 0, t1->momx, t1->momy) + ANGLE_45;
if (i & 1)
{
blast->angle += ANGLE_90;
}
P_InitAngle(blast, blast->angle);
blast->destscale *= 10;
}
}
t1->flags |= MF_SHOOTABLE;
// The following sets t1->target to t2, so draggeddroptarget keeps it persisting...
P_DamageMobj(t1, t2, (t2->target ? t2->target : t2), 1, DMG_NORMAL);
t1->color = (t1->health > 1)
? SKINCOLOR_GOLD
: SKINCOLOR_CRIMSON;
t1->flags &= ~MF_SHOOTABLE;
t1->spritexscale = 3*FRACUNIT;
t1->spriteyscale = 3*FRACUNIT/2;
if (!t2->player)
{
t2->angle += ANGLE_180;
if (t2->type == MT_JAWZ)
P_SetTarget(&t2->tracer, t2->target); // Back to the source!
t2->threshold = 10;
}
if (draggeddroptarget && draggeddroptarget->player)
{
// The following removes t1, be warned
// (its newly assigned properties are moved across)
K_DropHnextList(draggeddroptarget->player, true);
// Do NOT modify or reference t1 after this line
// I mean it! Do not even absentmindedly try it
}
return true;
}
boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2)
{
if (t2->type == MT_PLAYER)
{
// Counter desyncs
/*mobj_t *oldthing = thing;
mobj_t *oldtmthing = tmthing;
P_Thrust(tmthing, R_PointToAngle2(thing->x, thing->y, tmthing->x, tmthing->y), 4*thing->scale);
thing = oldthing;
P_SetTarget(&tmthing, oldtmthing);*/
if (P_PlayerInPain(t2->player)
|| t2->player->flashing || t2->player->hyudorotimer
|| t2->player->justbumped || t2->scale > t1->scale + (mapobjectscale/8))
return true;
// Player Damage
P_DamageMobj(t2, ((t1->type == MT_BUBBLESHIELD) ? t1->target : t1), t1, 1, DMG_NORMAL|DMG_WOMBO);
S_StartSound(t1, sfx_s3k44);
}
else
{
if (!t2->threshold)
{
if (!t2->momx && !t2->momy)
{
t2->momz += (24*t2->scale) * P_MobjFlip(t2);
}
else
{
t2->momx = -4*t2->momx;
t2->momy = -4*t2->momy;
t2->momz = -4*t2->momz;
t2->angle += ANGLE_180;
}
if (t2->type == MT_JAWZ)
P_SetTarget(&t2->tracer, t2->target); // Back to the source!
t2->threshold = 10;
S_StartSound(t1, sfx_s3k44);
}
}
// no interaction
return true;
}
boolean K_KitchenSinkCollide(mobj_t *t1, mobj_t *t2)
{
if ((t1->threshold > 0 && t2->hitlag > 0) || (t2->threshold > 0 && t1->hitlag > 0))
@ -463,6 +637,7 @@ boolean K_SMKIceBlockCollide(mobj_t *t1, mobj_t *t2)
if (t2->type == MT_BANANA || t2->type == MT_BANANA_SHIELD
|| t2->type == MT_EGGMANITEM || t2->type == MT_EGGMANITEM_SHIELD
|| t2->type == MT_SSMINE || t2->type == MT_SSMINE_SHIELD
|| t2->type == MT_DROPTARGET_SHIELD
|| t2->type == MT_ORBINAUT_SHIELD || t2->type == MT_JAWZ_SHIELD)
return false;

View file

@ -10,6 +10,8 @@ boolean K_EggItemCollide(mobj_t *t1, mobj_t *t2);
boolean K_MineCollide(mobj_t *t1, mobj_t *t2);
boolean K_MineExplosionCollide(mobj_t *t1, mobj_t *t2);
boolean K_LandMineCollide(mobj_t *t1, mobj_t *t2);
boolean K_DropTargetCollide(mobj_t *t1, mobj_t *t2);
boolean K_BubbleShieldCollide(mobj_t *t1, mobj_t *t2);
boolean K_KitchenSinkCollide(mobj_t *t1, mobj_t *t2);
boolean K_FallingRockCollide(mobj_t *t1, mobj_t *t2);
boolean K_SMKIceBlockCollide(mobj_t *t1, mobj_t *t2);

View file

@ -118,6 +118,7 @@ static patch_t *kp_orbinaut[5];
static patch_t *kp_jawz[2];
static patch_t *kp_mine[2];
static patch_t *kp_landmine[2];
static patch_t *kp_droptarget[2];
static patch_t *kp_ballhog[2];
static patch_t *kp_selfpropelledbomb[2];
static patch_t *kp_grow[2];
@ -403,6 +404,7 @@ void K_LoadKartHUDGraphics(void)
kp_jawz[0] = W_CachePatchName("K_ITJAWZ", PU_HUDGFX);
kp_mine[0] = W_CachePatchName("K_ITMINE", PU_HUDGFX);
kp_landmine[0] = W_CachePatchName("K_ITLNDM", PU_HUDGFX);
kp_droptarget[0] = W_CachePatchName("K_ITDTRG", PU_HUDGFX);
kp_ballhog[0] = W_CachePatchName("K_ITBHOG", PU_HUDGFX);
kp_selfpropelledbomb[0] = W_CachePatchName("K_ITSPB", PU_HUDGFX);
kp_grow[0] = W_CachePatchName("K_ITGROW", PU_HUDGFX);
@ -453,6 +455,7 @@ void K_LoadKartHUDGraphics(void)
kp_jawz[1] = W_CachePatchName("K_ISJAWZ", PU_HUDGFX);
kp_mine[1] = W_CachePatchName("K_ISMINE", PU_HUDGFX);
kp_landmine[1] = W_CachePatchName("K_ISLNDM", PU_HUDGFX);
kp_droptarget[1] = W_CachePatchName("K_ISDTRG", PU_HUDGFX);
kp_ballhog[1] = W_CachePatchName("K_ISBHOG", PU_HUDGFX);
kp_selfpropelledbomb[1] = W_CachePatchName("K_ISSPB", PU_HUDGFX);
kp_grow[1] = W_CachePatchName("K_ISGROW", PU_HUDGFX);
@ -1082,7 +1085,7 @@ static void K_drawKartItem(void)
if (stplyr->skincolor)
localcolor = stplyr->skincolor;
switch((stplyr->itemroulette % (15*3)) / 3)
switch((stplyr->itemroulette % (16*3)) / 3)
{
// Each case is handled in threes, to give three frames of in-game time to see the item on the roulette
case 0: // Sneaker
@ -1149,6 +1152,10 @@ static void K_drawKartItem(void)
localpatch = kp_landmine[offset];
//localcolor = SKINCOLOR_JET;
break;
case 16: // Land Mine
localpatch = kp_droptarget[offset];
//localcolor = SKINCOLOR_LIME;
break;
/*case 15: // Pogo Spring
localpatch = kp_pogospring[offset];
localcolor = SKINCOLOR_TANGERINE;
@ -1237,6 +1244,9 @@ static void K_drawKartItem(void)
case KITEM_LANDMINE:
localpatch = kp_landmine[offset];
break;
case KITEM_DROPTARGET:
localpatch = kp_droptarget[offset];
break;
case KITEM_BALLHOG:
localpatch = kp_ballhog[offset];
break;
@ -4135,6 +4145,7 @@ static void K_drawDistributionDebugger(void)
kp_jawz[1],
kp_mine[1],
kp_landmine[1],
kp_droptarget[1],
kp_ballhog[1],
kp_selfpropelledbomb[1],
kp_grow[1],

View file

@ -211,6 +211,7 @@ void K_RegisterKartStuff(void)
CV_RegisterVar(&cv_jawz);
CV_RegisterVar(&cv_mine);
CV_RegisterVar(&cv_landmine);
CV_RegisterVar(&cv_droptarget);
CV_RegisterVar(&cv_ballhog);
CV_RegisterVar(&cv_selfpropelledbomb);
CV_RegisterVar(&cv_grow);
@ -314,6 +315,7 @@ consvar_t *KartItemCVars[NUMKARTRESULTS-1] =
&cv_jawz,
&cv_mine,
&cv_landmine,
&cv_droptarget,
&cv_ballhog,
&cv_selfpropelledbomb,
&cv_grow,
@ -343,12 +345,13 @@ static INT32 K_KartItemOddsRace[NUMKARTRESULTS-1][8] =
/*Sneaker*/ { 0, 0, 2, 4, 6, 0, 0, 0 }, // Sneaker
/*Rocket Sneaker*/ { 0, 0, 0, 0, 0, 2, 4, 6 }, // Rocket Sneaker
/*Invincibility*/ { 0, 0, 0, 0, 2, 4, 6, 9 }, // Invincibility
/*Banana*/ { 5, 3, 1, 0, 0, 0, 0, 0 }, // Banana
/*Banana*/ { 4, 3, 1, 0, 0, 0, 0, 0 }, // Banana
/*Eggman Monitor*/ { 1, 2, 0, 0, 0, 0, 0, 0 }, // Eggman Monitor
/*Orbinaut*/ { 7, 4, 2, 2, 0, 0, 0, 0 }, // Orbinaut
/*Orbinaut*/ { 5, 4, 2, 2, 0, 0, 0, 0 }, // Orbinaut
/*Jawz*/ { 0, 3, 2, 1, 1, 0, 0, 0 }, // Jawz
/*Mine*/ { 0, 2, 3, 1, 0, 0, 0, 0 }, // Mine
/*Land Mine*/ { 4, 0, 0, 0, 0, 0, 0, 0 }, // Land Mine
/*Land Mine*/ { 3, 0, 0, 0, 0, 0, 0, 0 }, // Land Mine
/*Drop Target*/ { 4, 0, 0, 0, 0, 0, 0, 0 }, // Drop Target
/*Ballhog*/ { 0, 0, 2, 1, 0, 0, 0, 0 }, // Ballhog
/*Self-Propelled Bomb*/ { 0, 0, 0, 0, 0, 2, 4, 0 }, // Self-Propelled Bomb
/*Grow*/ { 0, 0, 0, 1, 2, 3, 0, 0 }, // Grow
@ -381,6 +384,7 @@ static INT32 K_KartItemOddsBattle[NUMKARTRESULTS][2] =
/*Jawz*/ { 8, 1 }, // Jawz
/*Mine*/ { 6, 1 }, // Mine
/*Land Mine*/ { 0, 0 }, // Land Mine
/*Drop Target*/ { 0, 0 }, // Drop Target
/*Ballhog*/ { 2, 1 }, // Ballhog
/*Self-Propelled Bomb*/ { 0, 0 }, // Self-Propelled Bomb
/*Grow*/ { 2, 1 }, // Grow
@ -667,6 +671,7 @@ INT32 K_KartGetItemOdds(
case KITEM_ROCKETSNEAKER:
case KITEM_JAWZ:
case KITEM_LANDMINE:
case KITEM_DROPTARGET:
case KITEM_BALLHOG:
case KRITEM_TRIPLESNEAKER:
case KRITEM_TRIPLEORBINAUT:
@ -1217,6 +1222,10 @@ fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against)
else
weight += 3*FRACUNIT;
break;
case MT_DROPTARGET:
case MT_DROPTARGET_SHIELD:
if (against->player)
weight = K_PlayerWeight(against, NULL);
default:
break;
}
@ -1250,6 +1259,12 @@ static void K_SpawnBumpForObjs(mobj_t *mobj1, mobj_t *mobj2)
{
S_StartSound(mobj1, sfx_s3k44);
}
else if (mobj1->type == MT_DROPTARGET || mobj1->type == MT_DROPTARGET_SHIELD) // no need to check the other way around
{
S_StartSound(mobj2, sfx_s258);
fx->colorized = true;
fx->color = mobj1->color;
}
else
{
S_StartSound(mobj1, sfx_s3k49);
@ -1365,6 +1380,7 @@ boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2)
|| (mobj2->player && mobj2->player->respawn.state != RESPAWNST_NONE))
return false;
if (mobj1->type != MT_DROPTARGET && mobj1->type != MT_DROPTARGET_SHIELD)
{ // Don't bump if you're flashing
INT32 flash;
@ -4839,6 +4855,12 @@ mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t mapthing,
// Shoot forward
mo = K_SpawnKartMissile(player->mo, mapthing, player->mo->angle, 0, PROJSPEED);
}
if (mapthing == MT_DROPTARGET && mo)
{
mo->reactiontime = TICRATE/2;
P_SetMobjState(mo, mo->info->painstate);
}
}
}
else
@ -4868,7 +4890,7 @@ mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t mapthing,
if (mo)
{
angle_t fa = player->mo->angle>>ANGLETOFINESHIFT;
fixed_t HEIGHT = ((20 + (dir*10)) * FRACUNIT) + (player->mo->momz*P_MobjFlip(player->mo)); // Also intentionally not player scale
fixed_t HEIGHT = ((20 + (dir*10)) * FRACUNIT) + (FixedDiv(player->mo->momz, mapobjectscale)*P_MobjFlip(player->mo)); // Also intentionally not player scale
P_SetObjectMomZ(mo, HEIGHT, false);
mo->momx = player->mo->momx + FixedMul(FINECOSINE(fa), PROJSPEED*dir);
@ -5334,7 +5356,8 @@ static void K_DoShrink(player_t *user)
if (mobj->type == MT_BANANA_SHIELD || mobj->type == MT_JAWZ_SHIELD ||
mobj->type == MT_SSMINE_SHIELD || mobj->type == MT_EGGMANITEM_SHIELD ||
mobj->type == MT_SINK_SHIELD || mobj->type == MT_ORBINAUT_SHIELD)
mobj->type == MT_SINK_SHIELD || mobj->type == MT_ORBINAUT_SHIELD ||
mobj->type == MT_DROPTARGET_SHIELD)
{
if (mobj->target && mobj->target->player)
{
@ -5537,6 +5560,9 @@ void K_DropHnextList(player_t *player, boolean keepshields)
{
nextwork = work->hnext;
if (!work->health)
continue; // taking care of itself
switch (work->type)
{
// Kart orbit items
@ -5558,6 +5584,11 @@ void K_DropHnextList(player_t *player, boolean keepshields)
dropall = false;
type = MT_SSMINE;
break;
case MT_DROPTARGET_SHIELD:
orbit = false;
dropall = false;
type = MT_DROPTARGET;
break;
case MT_EGGMANITEM_SHIELD:
orbit = false;
type = MT_EGGMANITEM;
@ -5580,14 +5611,24 @@ void K_DropHnextList(player_t *player, boolean keepshields)
P_SetScale(dropwork, work->scale);
dropwork->destscale = work->destscale;
dropwork->scalespeed = work->scalespeed;
dropwork->spritexscale = work->spritexscale;
dropwork->spriteyscale = work->spriteyscale;
dropwork->flags |= MF_NOCLIPTHING;
dropwork->flags2 = work->flags2;
dropwork->eflags = work->eflags;
dropwork->renderflags = work->renderflags;
dropwork->color = work->color;
dropwork->colorized = work->colorized;
dropwork->whiteshadow = work->whiteshadow;
dropwork->floorz = work->floorz;
dropwork->ceilingz = work->ceilingz;
dropwork->health = work->health; // will never be set to 0 as long as above guard exists
dropwork->hitlag = work->hitlag;
// Copy interp data
dropwork->old_angle = work->old_angle;
dropwork->old_x = work->old_x;
@ -5644,14 +5685,22 @@ void K_DropHnextList(player_t *player, boolean keepshields)
}
else
{
dropwork->color = work->color;
dropwork->angle -= ANGLE_90;
}
}
else // plop on the ground
{
dropwork->flags &= ~MF_NOCLIPTHING;
dropwork->threshold = 10;
dropwork->flags &= ~MF_NOCLIPTHING;
if (type == MT_DROPTARGET && dropwork->hitlag)
{
dropwork->momx = work->momx;
dropwork->momy = work->momy;
dropwork->momz = work->momz;
dropwork->reactiontime = work->reactiontime;
P_SetMobjState(dropwork, mobjinfo[type].painstate);
}
}
P_RemoveMobj(work);
@ -6163,10 +6212,12 @@ static void K_MoveHeldObjects(player_t *player)
break;
case MT_BANANA_SHIELD: // Kart trailing items
case MT_SSMINE_SHIELD:
case MT_DROPTARGET_SHIELD:
case MT_EGGMANITEM_SHIELD:
case MT_SINK_SHIELD:
{
mobj_t *cur = player->mo->hnext;
mobj_t *curnext;
mobj_t *targ = player->mo;
if (P_IsObjectOnGround(player->mo) && player->speed > 0)
@ -6179,11 +6230,17 @@ static void K_MoveHeldObjects(player_t *player)
fixed_t targx, targy, targz;
fixed_t speed, dist;
curnext = cur->hnext;
if (cur->type == MT_EGGMANITEM_SHIELD)
{
// Decided that this should use their "canon" color.
cur->color = SKINCOLOR_BLACK;
}
else if (cur->type == MT_DROPTARGET_SHIELD)
{
cur->renderflags = (cur->renderflags|RF_FULLBRIGHT) ^ RF_FULLDARK; // the difference between semi and fullbright
}
cur->flags &= ~MF_NOCLIPTHING;
@ -6192,7 +6249,7 @@ static void K_MoveHeldObjects(player_t *player)
if (!cur->health)
{
cur = cur->hnext;
cur = curnext;
continue;
}
@ -6210,7 +6267,10 @@ static void K_MoveHeldObjects(player_t *player)
dist = cur->extravalue1/2;
if (!targ || P_MobjWasRemoved(targ))
{
cur = curnext;
continue;
}
// Shrink your items if the player shrunk too.
P_SetScale(cur, (cur->destscale = FixedMul(FixedDiv(cur->extravalue1, radius), finalscale)));
@ -6241,7 +6301,14 @@ static void K_MoveHeldObjects(player_t *player)
P_SetObjectMomZ(cur, FixedMul(targz - cur->z, 7*FRACUNIT/8) - gravity, false);
if (R_PointToDist2(cur->x, cur->y, targx, targy) > 768*FRACUNIT)
{
P_MoveOrigin(cur, targx, targy, cur->z);
if (P_MobjWasRemoved(cur))
{
cur = curnext;
continue;
}
}
if (P_IsObjectOnGround(cur))
{
@ -6249,7 +6316,7 @@ static void K_MoveHeldObjects(player_t *player)
cur->radius, cur->height, (cur->eflags & MFE_VERTICALFLIP), false);
}
cur = cur->hnext;
cur = curnext;
}
}
break;
@ -9182,6 +9249,33 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
K_PlayAttackTaunt(player->mo);
}
break;
case KITEM_DROPTARGET:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
{
mobj_t *mo;
K_SetItemOut(player);
S_StartSound(player->mo, sfx_s254);
mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_DROPTARGET_SHIELD);
if (mo)
{
mo->flags |= MF_NOCLIPTHING;
mo->threshold = 10;
mo->movecount = 1;
mo->movedir = 1;
mo->cusval = player->itemscale;
P_SetTarget(&mo->target, player->mo);
P_SetTarget(&player->mo->hnext, mo);
}
}
else if (ATTACK_IS_DOWN && (player->pflags & PF_ITEMOUT))
{
K_ThrowKartItem(player, (player->throwdir > 0), MT_DROPTARGET, -1, 0);
K_PlayAttackTaunt(player->mo);
player->itemamount--;
player->pflags &= ~PF_ITEMOUT;
K_UpdateHnextList(player, true);
}
break;
case KITEM_BALLHOG:
if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
{

View file

@ -935,6 +935,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
&& !(target->type == MT_ORBINAUT || target->type == MT_ORBINAUT_SHIELD
|| target->type == MT_JAWZ || target->type == MT_JAWZ_DUD || target->type == MT_JAWZ_SHIELD
|| target->type == MT_BANANA || target->type == MT_BANANA_SHIELD
|| target->type == MT_DROPTARGET || target->type == MT_DROPTARGET_SHIELD
|| target->type == MT_EGGMANITEM || target->type == MT_EGGMANITEM_SHIELD
|| target->type == MT_BALLHOG || target->type == MT_SPB)) // kart dead items
target->flags |= MF_NOGRAVITY; // Don't drop Tails 03-08-2000
@ -974,6 +975,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
{
if ((target->type == MT_BANANA_SHIELD && target->target->player->itemtype == KITEM_BANANA) // trail items
|| (target->type == MT_SSMINE_SHIELD && target->target->player->itemtype == KITEM_MINE)
|| (target->type == MT_DROPTARGET_SHIELD && target->target->player->itemtype == KITEM_DROPTARGET)
|| (target->type == MT_SINK_SHIELD && target->target->player->itemtype == KITEM_KITCHENSINK))
{
if (target->movedir != 0 && target->movedir < (UINT16)target->target->player->itemamount)
@ -1489,6 +1491,11 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
}
break;
case MT_DROPTARGET:
case MT_DROPTARGET_SHIELD:
target->fuse = 1;
break;
default:
break;
}
@ -1827,6 +1834,10 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
{
laglength = 2;
}
else if (target->type == MT_DROPTARGET || target->type == MT_DROPTARGET_SHIELD)
{
laglength = 0; // handled elsewhere
}
// Everything above here can't be forced.
if (!metalrecording)
@ -1899,7 +1910,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
// Check if the player is allowed to be damaged!
// If not, then spawn the instashield effect instead.
if (!force)
if (!force && !(inflictor && inflictor->type == MT_SPBEXPLOSION && inflictor->extravalue1 == 1))
{
if (gametyperules & GTR_BUMPERS)
{

View file

@ -768,50 +768,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (tmthing->z + tmthing->height < thing->z)
return true; // underneath
if (tmthing->type == MT_PLAYER)
{
// Counter desyncs
/*mobj_t *oldthing = thing;
mobj_t *oldtmthing = tmthing;
P_Thrust(tmthing, R_PointToAngle2(thing->x, thing->y, tmthing->x, tmthing->y), 4*thing->scale);
thing = oldthing;
P_SetTarget(&tmthing, oldtmthing);*/
if (P_PlayerInPain(tmthing->player)
|| tmthing->player->flashing || tmthing->player->hyudorotimer
|| tmthing->player->justbumped || tmthing->scale > thing->scale + (mapobjectscale/8))
return true;
// Player Damage
P_DamageMobj(tmthing, ((thing->type == MT_BUBBLESHIELD) ? thing->target : thing), thing, 1, DMG_NORMAL|DMG_WOMBO);
S_StartSound(thing, sfx_s3k44);
}
else
{
if (!tmthing->threshold)
{
if (!tmthing->momx && !tmthing->momy)
{
tmthing->momz += (24*tmthing->scale) * P_MobjFlip(tmthing);
}
else
{
tmthing->momx = -tmthing->momx;
tmthing->momy = -tmthing->momy;
tmthing->momz = -tmthing->momz;
tmthing->angle += ANGLE_180;
}
if (tmthing->type == MT_JAWZ)
P_SetTarget(&tmthing->tracer, tmthing->target); // Back to the source!
tmthing->threshold = 10;
S_StartSound(thing, sfx_s3k44);
}
}
// no interaction
return true;
return K_BubbleShieldCollide(thing, tmthing);
}
else if (((tmthing->type == MT_BUBBLESHIELD && tmthing->target->player && tmthing->target->player->bubbleblowup)
|| (tmthing->player && tmthing->player->bubbleblowup))
@ -826,56 +783,48 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (tmthing->z + tmthing->height < thing->z)
return true; // underneath
if (thing->type == MT_PLAYER)
{
// Counter desyncs
/*mobj_t *oldthing = thing;
mobj_t *oldtmthing = tmthing;
P_Thrust(thing, R_PointToAngle2(tmthing->x, tmthing->y, thing->x, thing->y), 4*tmthing->scale);
thing = oldthing;
P_SetTarget(&tmthing, oldtmthing);*/
if (P_PlayerInPain(thing->player)
|| thing->player->flashing || thing->player->hyudorotimer
|| thing->player->justbumped || thing->scale > tmthing->scale + (mapobjectscale/8))
return true;
// Player Damage
P_DamageMobj(thing, ((tmthing->type == MT_BUBBLESHIELD) ? tmthing->target : tmthing), tmthing, 1, DMG_NORMAL);
S_StartSound(tmthing, sfx_s3k44);
}
else
{
if (!thing->threshold)
{
if (!thing->momx && !thing->momy)
{
thing->momz += (24*thing->scale) * P_MobjFlip(thing);
}
else
{
thing->momx = -thing->momx;
thing->momy = -thing->momy;
thing->momz = -thing->momz;
thing->angle += ANGLE_180;
}
if (thing->type == MT_JAWZ)
P_SetTarget(&thing->tracer, thing->target); // Back to the source!
thing->threshold = 10;
S_StartSound(tmthing, sfx_s3k44);
}
}
// no interaction
return true;
return K_BubbleShieldCollide(tmthing, thing);
}
// double make sure bubbles won't collide with anything else
if (thing->type == MT_BUBBLESHIELD || tmthing->type == MT_BUBBLESHIELD)
return true;
// Droptarget reflect
if ((thing->type == MT_DROPTARGET || thing->type == MT_DROPTARGET_SHIELD)
&& (tmthing->type == MT_ORBINAUT || tmthing->type == MT_JAWZ || tmthing->type == MT_JAWZ_DUD
|| tmthing->type == MT_BANANA || tmthing->type == MT_EGGMANITEM || tmthing->type == MT_BALLHOG
|| tmthing->type == MT_SSMINE || tmthing->type == MT_LANDMINE || tmthing->type == MT_SINK
|| (tmthing->type == MT_PLAYER)))
{
// see if it went over / under
if (tmthing->z > thing->z + thing->height)
return true; // overhead
if (tmthing->z + tmthing->height < thing->z)
return true; // underneath
return K_DropTargetCollide(thing, tmthing);
}
else if ((tmthing->type == MT_DROPTARGET || tmthing->type == MT_DROPTARGET_SHIELD)
&& (thing->type == MT_ORBINAUT || thing->type == MT_JAWZ || thing->type == MT_JAWZ_DUD
|| thing->type == MT_BANANA || thing->type == MT_EGGMANITEM || thing->type == MT_BALLHOG
|| thing->type == MT_SSMINE || tmthing->type == MT_LANDMINE || thing->type == MT_SINK
|| (thing->type == MT_PLAYER)))
{
// see if it went over / under
if (tmthing->z > thing->z + thing->height)
return true; // overhead
if (tmthing->z + tmthing->height < thing->z)
return true; // underneath
return K_DropTargetCollide(tmthing, thing);
}
// double make sure drop targets won't collide with anything else
if (thing->type == MT_DROPTARGET || tmthing->type == MT_DROPTARGET
|| thing->type == MT_DROPTARGET_SHIELD || tmthing->type == MT_DROPTARGET_SHIELD)
return true;
if (tmthing->type == MT_ORBINAUT || tmthing->type == MT_JAWZ || tmthing->type == MT_JAWZ_DUD
|| tmthing->type == MT_ORBINAUT_SHIELD || tmthing->type == MT_JAWZ_SHIELD)
{

View file

@ -1178,6 +1178,7 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
case MT_EGGMANITEM:
case MT_SSMINE:
case MT_LANDMINE:
case MT_DROPTARGET:
case MT_SINK:
case MT_EMERALD:
if (mo->extravalue2 > 0)
@ -2044,7 +2045,8 @@ boolean P_CheckDeathPitCollide(mobj_t *mo)
|| (mo->z + mo->height >= mo->subsector->sector->ceilingheight
&& ((mo->subsector->sector->flags & SF_TRIGGERSPECIAL_HEADBUMP) || (mo->eflags & MFE_VERTICALFLIP)) && (mo->subsector->sector->flags & SF_FLIPSPECIAL_CEILING)))
&& (GETSECSPECIAL(mo->subsector->sector->special, 1) == 6
|| GETSECSPECIAL(mo->subsector->sector->special, 1) == 7))
|| GETSECSPECIAL(mo->subsector->sector->special, 1) == 7
|| GETSECSPECIAL(mo->subsector->sector->special, 1) == 8))
return true;
return false;
@ -2142,6 +2144,7 @@ boolean P_ZMovement(mobj_t *mo)
case MT_BALLHOG:
case MT_SSMINE:
case MT_LANDMINE:
case MT_DROPTARGET:
case MT_BUBBLESHIELDTRAP:
// Remove stuff from death pits.
if (P_CheckDeathPitCollide(mo))
@ -4862,6 +4865,7 @@ boolean P_IsKartItem(INT32 type)
{
if (type == MT_EGGMANITEM || type == MT_EGGMANITEM_SHIELD ||
type == MT_BANANA || type == MT_BANANA_SHIELD ||
type == MT_DROPTARGET || type == MT_DROPTARGET_SHIELD ||
type == MT_ORBINAUT || type == MT_ORBINAUT_SHIELD ||
type == MT_JAWZ || type == MT_JAWZ_DUD || type == MT_JAWZ_SHIELD ||
type == MT_SSMINE || type == MT_SSMINE_SHIELD ||
@ -4899,12 +4903,14 @@ static void P_RemoveKartItem(mobj_t *thing)
{
mobj_t *mo;
for (mo = kitemcap; mo; mo = mo->itnext)
if (mo->itnext == thing)
{
P_SetTarget(&mo->itnext, thing->itnext);
P_SetTarget(&thing->itnext, NULL);
return;
}
{
if (mo->itnext != thing)
continue;
P_SetTarget(&mo->itnext, thing->itnext);
P_SetTarget(&thing->itnext, NULL);
return;
}
}
// Doesn't actually do anything since items have their own thinkers,
@ -5631,14 +5637,15 @@ static void P_MobjSceneryThink(mobj_t *mobj)
{
mobj_t *blast = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_BATTLEBUMPER_BLAST);
P_InitAngle(blast, R_PointToAngle2(0, 0, mobj->momx, mobj->momy) + ANGLE_45);
blast->destscale *= 4;
blast->angle = R_PointToAngle2(0, 0, mobj->momx, mobj->momy) + ANGLE_45;
if (i & 1)
{
blast->angle += ANGLE_90;
S_StartSound(blast, sfx_cdfm64);
}
P_InitAngle(blast, blast->angle);
blast->destscale *= 4;
}
for (i = 0; i < 10; i++)
@ -6155,6 +6162,7 @@ static boolean P_MobjDeadThink(mobj_t *mobj)
case MT_BANANA:
case MT_EGGMANITEM:
case MT_LANDMINE:
//case MT_DROPTARGET:
case MT_SPB:
if (P_IsObjectOnGround(mobj))
{
@ -6834,6 +6842,45 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
mobj->health = 1;
}
if (mobj->threshold > 0)
mobj->threshold--;
break;
case MT_DROPTARGET:
if (mobj->reactiontime > 0)
{
// Slippery tipping mode.
INT32 slippytip = 1 + (mobj->reactiontime/2);
if (slippytip > 64)
slippytip = 64;
else if (slippytip < 8)
slippytip = 8;
if (!(mobj->health & 1) == !(mobj->flags2 & MF2_AMBUSH))
{
slippytip = -slippytip;
}
mobj->angle += slippytip*ANG2;
mobj->friction = ((2*ORIG_FRICTION)+FRACUNIT)/3; // too low still?
/*if (mobj->momx || mobj->momy || mobj->momz)
{
mobj_t *ghost = P_SpawnGhostMobj(mobj);
ghost->colorized = true; // already has color!
}*/
if (!--mobj->reactiontime)
{
P_SetMobjState(mobj, mobj->info->spawnstate);
}
}
else
{
// Time to stop, ramp up the friction...
mobj->friction = ORIG_FRICTION/4; // too high still?
}
mobj->renderflags = (mobj->renderflags|RF_FULLBRIGHT) ^ RF_FULLDARK; // the difference between semi and fullbright
if (mobj->threshold > 0)
mobj->threshold--;
break;
@ -9013,6 +9060,13 @@ void P_MobjThinker(mobj_t *mobj)
if (mobj->hitlag > 0)
{
mobj->hitlag--;
if (mobj->type == MT_DROPTARGET && mobj->reactiontime > 0 && mobj->hitlag == 2)
{
mobj->spritexscale = FRACUNIT;
mobj->spriteyscale = 5*FRACUNIT;
}
return;
}
@ -9197,7 +9251,8 @@ void P_MobjThinker(mobj_t *mobj)
|| mobj->type == MT_CANNONBALLDECOR
|| mobj->type == MT_FALLINGROCK
|| mobj->type == MT_ORBINAUT
|| mobj->type == MT_JAWZ || mobj->type == MT_JAWZ_DUD) {
|| mobj->type == MT_JAWZ || mobj->type == MT_JAWZ_DUD
|| (mobj->type == MT_DROPTARGET && mobj->reactiontime)) {
P_TryMove(mobj, mobj->x, mobj->y, true); // Sets mo->standingslope correctly
if (P_MobjWasRemoved(mobj)) // anything that calls checkposition can be lethal
return;
@ -9510,6 +9565,10 @@ static void P_DefaultMobjShadowScale(mobj_t *thing)
thing->shadowscale = 3*FRACUNIT/2;
thing->whiteshadow = false;
break;
case MT_DROPTARGET:
thing->shadowscale = 3*FRACUNIT/2;
thing->whiteshadow = true;
break;
case MT_THUNDERSHIELD:
case MT_BUBBLESHIELD:
case MT_BUBBLESHIELDTRAP:
@ -10045,6 +10104,12 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
}
}
break;
case MT_DROPTARGET:
case MT_DROPTARGET_SHIELD:
mobj->color = SKINCOLOR_LIME;
mobj->colorized = true;
mobj->renderflags |= RF_FULLBRIGHT;
break;
case MT_SMK_MOLE:
mobj->reactiontime = P_RandomRange(0, 3*mobj->info->reactiontime/2); // Random delay on start of level
break;