From 068e07974df4ad1276291a44c9c1ce95cf4d7c64 Mon Sep 17 00:00:00 2001 From: MascaraSnake Date: Mon, 10 Jun 2019 20:32:50 +0200 Subject: [PATCH] Hardcoded the new Snapper behavior --- src/dehacked.c | 11 ++ src/hardware/hw_light.c | 2 + src/info.c | 84 +++++++++++-- src/info.h | 13 ++ src/p_enemy.c | 261 ++++++++++++++++++++++++++++++++++++++++ src/sounds.c | 2 +- 6 files changed, 361 insertions(+), 12 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index c4b8ca3bc..8c88521fb 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -2402,6 +2402,9 @@ static actionpointer_t actionpointers[] = {{A_TrainCameo}, "A_TRAINCAMEO"}, {{A_TrainCameo2}, "A_TRAINCAMEO2"}, {{A_CanarivoreGas}, "A_CANARIVOREGAS"}, + {{A_KillSegments}, "A_KILLSEGMENTS"}, + {{A_SnapperSpawn}, "A_SNAPPERSPAWN"}, + {{A_SnapperThinker}, "A_SNAPPERTHINKER"}, {{NULL}, "NONE"}, // This NULL entry must be the last in the list @@ -4443,11 +4446,17 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_EGGSHIELDBREAK", // Green Snapper + "S_SNAPPER_SPAWN", + "S_SNAPPER_SPAWN2", "S_GSNAPPER_STND", "S_GSNAPPER1", "S_GSNAPPER2", "S_GSNAPPER3", "S_GSNAPPER4", + "S_SNAPPER_XPLD", + "S_SNAPPER_LEG", + "S_SNAPPER_LEGRAISE", + "S_SNAPPER_HEAD", // Minus "S_MINUS_INIT", @@ -7175,6 +7184,8 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_EGGGUARD", // Egg Guard "MT_EGGSHIELD", // Egg Guard's shield "MT_GSNAPPER", // Green Snapper + "MT_SNAPPER_LEG", // Green Snapper leg + "MT_SNAPPER_HEAD", // Green Snapper head "MT_MINUS", // Minus "MT_MINUSDIRT", // Minus dirt "MT_SPRINGSHELL", // Spring Shell diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c index 874670266..8c302909f 100644 --- a/src/hardware/hw_light.c +++ b/src/hardware/hw_light.c @@ -172,6 +172,8 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_SPSH &lspr[NOLIGHT], // SPR_ESHI &lspr[NOLIGHT], // SPR_GSNP + &lspr[NOLIGHT], // SPR_GSNL + &lspr[NOLIGHT], // SPR_GSNH &lspr[NOLIGHT], // SPR_MNUS &lspr[NOLIGHT], // SPR_MNUD &lspr[NOLIGHT], // SPR_SSHL diff --git a/src/info.c b/src/info.c index d5b9271b3..692d485ea 100644 --- a/src/info.c +++ b/src/info.c @@ -60,6 +60,8 @@ char sprnames[NUMSPRITES + 1][5] = "SPSH", // Egg Guard "ESHI", // Egg Guard's shield "GSNP", // Green Snapper + "GSNL", // Green Snapper leg + "GSNH", // Green Snapper head "MNUS", // Minus "MNUD", // Minus dirt "SSHL", // Spring Shell @@ -1054,11 +1056,17 @@ state_t states[NUMSTATES] = {SPR_ESHI, 0, TICRATE/2, {NULL}, 0, 0, S_NULL}, // S_EGGSHIELDBREAK // Green Snapper - {SPR_GSNP, 0, 1, {A_Look}, 0, 0, S_GSNAPPER_STND}, // S_GSNAPPER_STND - {SPR_GSNP, 0, 2, {A_Chase}, 0, 0, S_GSNAPPER2}, // S_GSNAPPER1 - {SPR_GSNP, 1, 2, {A_Chase}, 0, 0, S_GSNAPPER3}, // S_GSNAPPER2 - {SPR_GSNP, 2, 2, {A_Chase}, 0, 0, S_GSNAPPER4}, // S_GSNAPPER3 - {SPR_GSNP, 3, 2, {A_Chase}, 0, 0, S_GSNAPPER1}, // S_GSNAPPER4 + {SPR_GSNP, 0, TICRATE, {NULL}, 0, 0, S_SNAPPER_SPAWN2}, // S_SNAPPER_SPAWN + {SPR_GSNP, 0, 2, {A_SnapperSpawn}, MT_SNAPPER_LEG, MT_SNAPPER_HEAD, S_GSNAPPER_STND}, // S_SNAPPER_SPAWN2 + {SPR_GSNP, 0, 1, {A_SnapperThinker}, 0, 0, S_GSNAPPER_STND}, // S_GSNAPPER_STND + {SPR_GSNP, 0, 2, {A_Chase}, 0, 0, S_GSNAPPER2}, // S_GSNAPPER1 + {SPR_GSNP, 1, 2, {A_Chase}, 0, 0, S_GSNAPPER3}, // S_GSNAPPER2 + {SPR_GSNP, 2, 2, {A_Chase}, 0, 0, S_GSNAPPER4}, // S_GSNAPPER3 + {SPR_GSNP, 3, 2, {A_Chase}, 0, 0, S_GSNAPPER1}, // S_GSNAPPER4 + {SPR_GSNP, 0, -1, {A_KillSegments}, 0, 0, S_XPLD_FLICKY}, // S_SNAPPER_XPLD + {SPR_GSNL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SNAPPER_LEG + {SPR_GSNL, 1, -1, {NULL}, 0, 0, S_NULL}, // S_SNAPPER_LEGRAISE + {SPR_GSNH, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SNAPPER_HEAD // Minus {SPR_MNUD, 0, 1, {NULL}, 0, 0, S_MINUS_STND}, // S_MINUS_INIT (required for objectplace to work) @@ -4679,28 +4687,82 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_GSNAPPER 120, // doomednum - S_GSNAPPER_STND,// spawnstate + S_SNAPPER_SPAWN,// spawnstate 1, // spawnhealth S_GSNAPPER1, // seestate sfx_None, // seesound - 32, // reactiontime + 10, // reactiontime sfx_None, // attacksound S_NULL, // painstate 200, // painchance sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate - S_XPLD_FLICKY, // deathstate + S_SNAPPER_XPLD, // deathstate S_NULL, // xdeathstate sfx_pop, // deathsound - 3, // speed + 4, // speed 24*FRACUNIT, // radius - 24*FRACUNIT, // height + 32*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_s3k7e, // activesound + MF_ENEMY|MF_SPECIAL|MF_SHOOTABLE, // flags + S_NULL // raisestate + }, + + { // MT_SNAPPER_LEG + -1, // doomednum + S_SNAPPER_LEG, // 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 + 6*FRACUNIT, // radius + 12*FRACUNIT, // height 0, // display offset 100, // mass 0, // damage sfx_None, // activesound - MF_ENEMY|MF_SPECIAL|MF_SHOOTABLE, // flags + MF_SCENERY|MF_PAIN|MF_NOCLIPHEIGHT|MF_NOBLOCKMAP|MF_NOGRAVITY, // flags + S_SNAPPER_LEGRAISE // raisestate + }, + + { // MT_SNAPPER_HEAD + -1, // doomednum + S_SNAPPER_HEAD, // 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 + 6*FRACUNIT, // radius + 12*FRACUNIT, // height + 0, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_PAIN|MF_NOBLOCKMAP|MF_NOGRAVITY, // flags S_NULL // raisestate }, diff --git a/src/info.h b/src/info.h index fd60902ff..0616cf970 100644 --- a/src/info.h +++ b/src/info.h @@ -260,6 +260,9 @@ void A_DebrisRandom(); void A_TrainCameo(); void A_TrainCameo2(); void A_CanarivoreGas(); +void A_KillSegments(); +void A_SnapperSpawn(); +void A_SnapperThinker(); // ratio of states to sprites to mobj types is roughly 6 : 1 : 1 #define NUMMOBJFREESLOTS 256 @@ -300,6 +303,8 @@ typedef enum sprite SPR_SPSH, // Egg Guard SPR_ESHI, // Egg Guard's shield SPR_GSNP, // Green Snapper + SPR_GSNL, // Green Snapper leg + SPR_GSNH, // Green Snapper head SPR_MNUS, // Minus SPR_MNUD, // Minus dirt SPR_SSHL, // Spring Shell @@ -1202,11 +1207,17 @@ typedef enum state S_EGGSHIELDBREAK, // Green Snapper + S_SNAPPER_SPAWN, + S_SNAPPER_SPAWN2, S_GSNAPPER_STND, S_GSNAPPER1, S_GSNAPPER2, S_GSNAPPER3, S_GSNAPPER4, + S_SNAPPER_XPLD, + S_SNAPPER_LEG, + S_SNAPPER_LEGRAISE, + S_SNAPPER_HEAD, // Minus S_MINUS_INIT, @@ -3954,6 +3965,8 @@ typedef enum mobj_type MT_EGGGUARD, // Egg Guard MT_EGGSHIELD, // Egg Guard's shield MT_GSNAPPER, // Green Snapper + MT_SNAPPER_LEG, // Green Snapper leg + MT_SNAPPER_HEAD, // Green Snapper head MT_MINUS, // Minus MT_MINUSDIRT, // Minus dirt MT_SPRINGSHELL, // Spring Shell diff --git a/src/p_enemy.c b/src/p_enemy.c index 2d4b39ff0..0d545da66 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -289,6 +289,9 @@ void A_DebrisRandom(mobj_t *actor); void A_TrainCameo(mobj_t *actor); void A_TrainCameo2(mobj_t *actor); void A_CanarivoreGas(mobj_t *actor); +void A_KillSegments(mobj_t *actor); +void A_SnapperSpawn(mobj_t *actor); +void A_SnapperThinker(mobj_t *actor); //for p_enemy.c // @@ -13196,4 +13199,262 @@ void A_CanarivoreGas(mobj_t *actor) P_DustRing(locvar1, 4, actor->x, actor->y, actor->z + actor->height / 5, 18, 0, FRACUNIT/10, actor->scale); P_DustRing(locvar1, 6, actor->x, actor->y, actor->z + actor->height / 5, 28, FRACUNIT, FRACUNIT/10, actor->scale); +} + +// +// Function: A_KillSegments +// +// Description: Causes segments attached via tracer chain to be killed; forces into next state. +// +// var1 = Fuse (if 0, default to TICRATE/2). +// var2 = Unused +// +void A_KillSegments(mobj_t *actor) +{ + INT32 locvar1 = var1; + mobj_t *seg = actor->tracer; + INT32 fuse = locvar1 ? locvar1 : TICRATE/2; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_KillSegments", actor)) + return; +#endif + + while (seg) + { + mobj_t *kseg = seg; + seg = seg->tracer; + + kseg->flags = MF_NOBLOCKMAP|MF_BOUNCE; + kseg->flags2 = 0; + kseg->fuse = fuse; + P_Thrust(kseg, R_PointToAngle2(actor->x, actor->y, kseg->x, kseg->y), 3*actor->scale); + kseg->momz = 3*actor->scale; + } + + P_SetMobjState(actor, actor->state->nextstate); +} + +static void P_SnapperLegPlace(mobj_t *mo) +{ + mobj_t *seg = mo->tracer; + fixed_t x0 = mo->x; + fixed_t y0 = mo->y; + angle_t a = mo->angle; + angle_t fa = (a >> ANGLETOFINESHIFT) & FINEMASK; + fixed_t c = FINECOSINE(fa); + fixed_t s = FINESINE(fa); + fixed_t x, y; + INT32 o1, o2; + INT32 woffset = mo->extravalue1; + INT32 side = mo->extravalue2; + INT32 alt; + + // Move head first. + fixed_t rad = mo->radius; + INT32 necklen = (32*(mo->info->reactiontime - mo->reactiontime))/mo->info->reactiontime; // Not in FU + + P_TeleportMove(seg, mo->x + FixedMul(c, rad) + necklen*c, mo->y + FixedMul(s, rad) + necklen*s, mo->z + mo->height/3); + seg->angle = a; + + // Move as many legs as available. + seg = seg->tracer; + do + { + o1 = seg->extravalue1; + o2 = seg->extravalue2; + alt = seg->cusval; + + if (alt == 1) + o2 += woffset; + else + o2 -= woffset; + + if (alt != side) + { + x = c*o2 + s*o1; + y = s*o2 - c*o1; + P_TryMove(seg, x0 + x, y0 + y, true); + P_SetMobjState(seg, seg->info->raisestate); + } + else + P_SetMobjState(seg, seg->info->spawnstate); + + seg->angle = R_PointToAngle2(x0, y0, seg->x, seg->y); + + seg = seg->tracer; + } while (seg); +} + +// +// Function: A_SnapperSpawn +// +// Description: Sets up Green Snapper legs and head. +// +// var1 = Leg mobj type. +// var2 = Head mobj type. +// +void A_SnapperSpawn(mobj_t *actor) +{ + mobjtype_t legtype = (mobjtype_t)var1; + mobjtype_t headtype = (mobjtype_t)var2; + mobj_t *ptr = actor; + INT32 i; + mobj_t *seg; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SnapperSpawn", actor)) + return; +#endif + + // It spawns 1 head. + seg = P_SpawnMobj(actor->x, actor->y, actor->z, headtype); + ptr->tracer = seg; + ptr = seg; + + // It spawns 4 legs which will be handled in the thinker function. + for (i = 1; i <= 4; i++) + { + seg = P_SpawnMobj(actor->x, actor->y, actor->z, legtype); + ptr->tracer = seg; + ptr = seg; + + // The legs' base offsets are stored as extravalues, as relative coordinates in xy space. + seg->extravalue1 = 28; + seg->extravalue2 = 28; + if (i % 2) + seg->extravalue1 = -seg->extravalue1; + + if ((i/2) % 2) + seg->extravalue2 = -seg->extravalue2; + + // Alternating motion stuff. + seg->cusval = ((i + 1)/2) % 2; + } + + actor->extravalue1 = 0; + actor->extravalue2 = 0; + P_SnapperLegPlace(actor); +} + +// +// Function: A_SnapperThinker +// +// Description: Thinker for Green Snapper. +// +// var1 = Unused +// var2 = Unused +// +void A_SnapperThinker(mobj_t *actor) +{ + fixed_t x0 = actor->x; + fixed_t y0 = actor->y; + fixed_t xs, ys; + fixed_t x1, y1; + fixed_t dist; + boolean chasing; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_SnapperThinker", actor)) + return; +#endif + + // We make a check just in case there's no spawnpoint. + if (actor->spawnpoint) + { + xs = actor->spawnpoint->x*FRACUNIT; + ys = actor->spawnpoint->y*FRACUNIT; + } + else + { + xs = x0; + ys = y0; + } + + // Look for nearby, valid players to chase angrily at. + if ((actor->target || P_LookForPlayers(actor, true, false, 1024*FRACUNIT)) + && P_AproxDistance(actor->target->x - xs, actor->target->y - ys) < 2048*FRACUNIT + && abs(actor->target->z - actor->z) < 80*FRACUNIT + && P_CheckSight(actor, actor->target)) + { + chasing = true; + x1 = actor->target->x; + y1 = actor->target->y; + } + else + { + chasing = false; + x1 = xs; + y1 = ys; + } + + dist = P_AproxDistance(x1 - x0, y1 - y0); + + // The snapper either chases what it considers to be a nearby player, or instead decides to go back to its spawnpoint. + if (chasing || dist > 32*FRACUNIT) + { + INT32 speed = actor->info->speed + actor->info->reactiontime - actor->reactiontime; + + angle_t maxang = FixedAngle(speed*FRACUNIT/2); + angle_t ang = actor->angle; + angle_t realang = R_PointToAngle2(x0, y0, x1, y1); + angle_t dif = realang - ang; + angle_t fa; + fixed_t c, s; + + if (dif < ANGLE_180 && dif > maxang) + actor->angle += maxang; + else if (dif >= ANGLE_180 && dif < InvAngle(maxang)) + actor->angle -= maxang; + else + actor->angle = realang; + + fa = (actor->angle >> ANGLETOFINESHIFT) & FINEMASK; + c = FINECOSINE(fa); + s = FINESINE(fa); + + P_TryMove(actor, actor->x + c*speed, actor->y + s*speed, false); + + // The snapper spawns dust if going fast! + if (actor->reactiontime < 4) + { + mobj_t *dust = P_SpawnMobj(x0, y0, actor->z, MT_SPINDUST); + P_Thrust(dust, ang + ANGLE_180 + FixedAngle(P_RandomRange(-20, 20)*FRACUNIT), speed*FRACUNIT); + } + + if (actor->extravalue2 == 0) + { + if (actor->extravalue1 > 16) + { + A_PlayActiveSound(actor); + actor->extravalue2 = 1; + + // If the snapper is chasing, accelerate; otherwise, decelerate. + if (chasing) + actor->reactiontime = max(0, actor->reactiontime - 1); + else + actor->reactiontime = min(actor->info->reactiontime, actor->reactiontime + 1); + } + else + actor->extravalue1 += speed; + } + else + { + if (actor->extravalue1 < -16) + { + A_PlayActiveSound(actor); + actor->extravalue2 = 0; + + // If the snapper is chasing, accelerate; otherwise, decelerate. + if (chasing) + actor->reactiontime = max(0, actor->reactiontime - 1); + else + actor->reactiontime = min(actor->info->reactiontime, actor->reactiontime + 1); + } + else + actor->extravalue1 -= speed; + } + } + + P_SnapperLegPlace(actor); } \ No newline at end of file diff --git a/src/sounds.c b/src/sounds.c index 5cfa59508..a707e4428 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -364,7 +364,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3k7b", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Soft bounce"}, {"s3k7c", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Magnet"}, {"s3k7d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, - {"s3k7e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Eating dirt"}, + {"s3k7e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Dust"}, {"s3k7f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Freeze"}, {"s3k80", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ice spike burst"}, {"s3k81", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Burst"},