Merge branch 'droptarget' into 'master'

"Drop Target" item

See merge request KartKrew/Kart!562
This commit is contained in:
SteelT 2022-03-22 03:33:54 +00:00
commit dbdaebbb04
15 changed files with 565 additions and 112 deletions

View file

@ -349,6 +349,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

@ -151,7 +151,8 @@ Run this macro, then #undef FOREACH afterward
FOREACH (HYUDORO, 17),\
FOREACH (POGOSPRING, 18),\
FOREACH (SUPERRING, 19),\
FOREACH (KITCHENSINK, 20)
FOREACH (KITCHENSINK, 20),\
FOREACH (DROPTARGET, 21)
typedef enum
{

View file

@ -3812,6 +3812,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",
@ -5522,6 +5526,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

@ -446,6 +446,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))
@ -498,6 +672,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

@ -11,6 +11,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

@ -121,6 +121,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];
@ -410,6 +411,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);
@ -460,6 +462,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);
@ -1111,7 +1114,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
@ -1178,6 +1181,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;
@ -1266,6 +1273,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;
@ -4551,6 +4561,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

@ -215,6 +215,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);
@ -321,6 +322,7 @@ consvar_t *KartItemCVars[NUMKARTRESULTS-1] =
&cv_jawz,
&cv_mine,
&cv_landmine,
&cv_droptarget,
&cv_ballhog,
&cv_selfpropelledbomb,
&cv_grow,
@ -350,12 +352,12 @@ 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
/*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
@ -367,6 +369,7 @@ static INT32 K_KartItemOddsRace[NUMKARTRESULTS-1][8] =
/*Pogo Spring*/ { 0, 0, 0, 0, 0, 0, 0, 0 }, // Pogo Spring
/*Super Ring*/ { 2, 1, 1, 0, 0, 0, 0, 0 }, // Super Ring
/*Kitchen Sink*/ { 0, 0, 0, 0, 0, 0, 0, 0 }, // Kitchen Sink
/*Drop Target*/ { 4, 0, 0, 0, 0, 0, 0, 0 }, // Drop Target
/*Sneaker x2*/ { 0, 0, 2, 2, 1, 0, 0, 0 }, // Sneaker x2
/*Sneaker x3*/ { 0, 0, 0, 2, 6,10, 5, 0 }, // Sneaker x3
/*Banana x3*/ { 0, 1, 1, 0, 0, 0, 0, 0 }, // Banana x3
@ -399,6 +402,7 @@ static INT32 K_KartItemOddsBattle[NUMKARTRESULTS][2] =
/*Pogo Spring*/ { 2, 0 }, // Pogo Spring
/*Super Ring*/ { 0, 0 }, // Super Ring
/*Kitchen Sink*/ { 0, 0 }, // Kitchen Sink
/*Drop Target*/ { 0, 0 }, // Drop Target
/*Sneaker x2*/ { 0, 0 }, // Sneaker x2
/*Sneaker x3*/ { 1, 1 }, // Sneaker x3
/*Banana x3*/ { 1, 0 }, // Banana x3
@ -674,6 +678,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:
@ -1231,6 +1236,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;
}
@ -1264,6 +1273,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);
@ -1379,6 +1394,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;
@ -4857,6 +4873,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
@ -4886,7 +4908,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);
@ -5352,7 +5374,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)
{
@ -5555,6 +5578,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
@ -5576,6 +5602,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;
@ -5598,14 +5629,24 @@ void K_DropHnextList(player_t *player, boolean keepshields)
P_SetScale(dropwork, work->scale);
dropwork->destscale = K_ItemScaleForPlayer(player); //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;
@ -5673,14 +5714,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);
@ -6192,10 +6241,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)
@ -6208,11 +6259,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;
@ -6221,7 +6278,7 @@ static void K_MoveHeldObjects(player_t *player)
if (!cur->health)
{
cur = cur->hnext;
cur = curnext;
continue;
}
@ -6239,7 +6296,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)));
@ -6270,7 +6330,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))
{
@ -6278,7 +6345,7 @@ static void K_MoveHeldObjects(player_t *player)
cur->radius, cur->height, (cur->eflags & MFE_VERTICALFLIP), false);
}
cur = cur->hnext;
cur = curnext;
}
}
break;
@ -9250,6 +9317,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

@ -942,6 +942,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
@ -981,6 +982,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)
@ -1496,6 +1498,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;
}
@ -1834,6 +1841,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)
@ -1906,7 +1917,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

@ -1179,6 +1179,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)
@ -2045,7 +2046,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;
@ -2143,6 +2145,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))
@ -4866,6 +4869,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 ||
@ -4903,12 +4907,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,
@ -5640,14 +5646,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++)
@ -6164,6 +6171,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))
{
@ -6843,6 +6851,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;
@ -9050,6 +9097,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;
}
@ -9234,7 +9288,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;
@ -9547,6 +9602,11 @@ static void P_DefaultMobjShadowScale(mobj_t *thing)
thing->shadowscale = 3*FRACUNIT/2;
thing->whiteshadow = false;
break;
case MT_DROPTARGET:
case MT_DROPTARGET_SHIELD:
thing->shadowscale = 5*FRACUNIT/4;
thing->whiteshadow = true;
break;
case MT_THUNDERSHIELD:
case MT_BUBBLESHIELD:
case MT_BUBBLESHIELDTRAP:
@ -10082,6 +10142,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;