diff --git a/src/dehacked.c b/src/dehacked.c index b52c79461f80d0e9ec55d05b01ee70f61081f089..78a9912a456f999bb4deba6f5adf741238a8f5fa 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1703,7 +1703,9 @@ static actionpointer_t actionpointers[] = {{A_JetJawChomp}, "A_JETJAWCHOMP"}, {{A_PointyThink}, "A_POINTYTHINK"}, {{A_CheckBuddy}, "A_CHECKBUDDY"}, + {{A_HoodFire}, "A_HOODFIRE"}, {{A_HoodThink}, "A_HOODTHINK"}, + {{A_HoodFall}, "A_HOODFALL"}, {{A_ArrowCheck}, "A_ARROWCHECK"}, {{A_SnailerThink}, "A_SNAILERTHINK"}, {{A_SharpChase}, "A_SHARPCHASE"}, @@ -3757,11 +3759,12 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit // Robo-Hood "S_ROBOHOOD_LOOK", - "S_ROBOHOOD_STND", - "S_ROBOHOOD_SHOOT", - "S_ROBOHOOD_JUMP", + "S_ROBOHOOD_STAND", + "S_ROBOHOOD_FIRE1", + "S_ROBOHOOD_FIRE2", + "S_ROBOHOOD_JUMP1", "S_ROBOHOOD_JUMP2", - "S_ROBOHOOD_FALL", + "S_ROBOHOOD_JUMP3", // CastleBot FaceStabber "S_FACESTABBER_STND1", diff --git a/src/info.c b/src/info.c index 4f4dc1aa7bf22ddaadcd3375cfdfd2cd4089a0c7..01edc0eb2e9694cb47484aae93ae1650033be17a 100644 --- a/src/info.c +++ b/src/info.c @@ -981,12 +981,13 @@ state_t states[NUMSTATES] = {SPR_PNTY, 1, 1, {A_CheckBuddy}, 0, 0, S_POINTYBALL1}, // S_POINTYBALL1 // Robo-Hood - {SPR_ARCH, 0, 14, {A_Look}, (512<<16), 0, S_ROBOHOOD_LOOK}, // S_ROBOHOOD_LOOK - {SPR_ARCH, 2, 1, {A_HoodThink}, 0, 0, S_ROBOHOOD_STND}, // S_ROBOHOOD_STND - {SPR_ARCH, 0, 35, {A_FireShot}, MT_ARROW, -24, S_ROBOHOOD_STND}, // S_ROBOHOOD_SHOOT - {SPR_ARCH, 1, 1, {A_BunnyHop}, 8, 5, S_ROBOHOOD_JUMP2}, // S_ROBOHOOD_JUMP - {SPR_ARCH, 1, 1, {A_HoodThink}, 0, 0, S_ROBOHOOD_JUMP2}, // S_ROBOHOOD_JUMP2 - {SPR_ARCH, 0, 1, {A_HoodThink}, 0, 0, S_ROBOHOOD_FALL}, // S_ROBOHOOD_FALL + {SPR_ARCH, 0, 4, {A_Look}, 2048<<FRACBITS, 0, S_ROBOHOOD_LOOK}, // S_ROBOHOOD_LOOK + {SPR_ARCH, 0, 1, {A_HoodThink}, 0, 0, S_ROBOHOOD_STAND}, // S_ROBOHOOD_STAND + {SPR_ARCH, 2, TICRATE, {A_PlayActiveSound}, 0, 0, S_ROBOHOOD_FIRE2}, // S_ROBOHOOD_FIRE1 + {SPR_ARCH, 2, 20, {A_HoodFire}, MT_ARROW, 0, S_ROBOHOOD_STAND}, // S_ROBOHOOD_FIRE2 + {SPR_ARCH, 1, 1, {A_FaceTarget}, 0, 0, S_ROBOHOOD_JUMP2}, // S_ROBOHOOD_JUMP1 + {SPR_ARCH, 1, 1, {A_BunnyHop}, 4, -10, S_ROBOHOOD_JUMP3}, // S_ROBOHOOD_JUMP2 + {SPR_ARCH, 1, 1, {A_HoodFall}, 0, 0, S_ROBOHOOD_JUMP3}, // S_ROBOHOOD_JUMP3 // Castlebot Facestabber {SPR_CBFS, 0, 1, {A_Chase}, 0, 0, S_FACESTABBER_STND2}, // S_FACESTABBER_STND1 @@ -2941,8 +2942,8 @@ state_t states[NUMSTATES] = {SPR_SEED, FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 2, 2, S_NULL}, // S_SEED // Particle sprite - {SPR_PRTL, FF_FULLBRIGHT|FF_TRANS70, 2*TICRATE, {NULL}, 0, 0, S_NULL}, // S_PARTICLE - {SPR_NULL, 0, 3, {A_ParticleSpawn}, 0, 0, S_PARTICLEGEN}, // S_PARTICLEGEN + {SPR_PRTL, 0, 2*TICRATE, {NULL}, 0, 0, S_NULL}, // S_PARTICLE + {SPR_NULL, 0, 3, {A_ParticleSpawn}, 0, 0, S_PARTICLEGEN}, // S_PARTICLEGEN {SPR_SCOR, 0, 32, {A_ScoreRise}, 0, 0, S_NULL}, // S_SCRA - 100 {SPR_SCOR, 1, 32, {A_ScoreRise}, 0, 0, S_NULL}, // S_SCRB - 200 @@ -4219,27 +4220,27 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 117, // doomednum S_ROBOHOOD_LOOK, // spawnstate 1, // spawnhealth - S_ROBOHOOD_STND, // seestate + S_ROBOHOOD_STAND, // seestate sfx_None, // seesound TICRATE, // reactiontime sfx_None, // attacksound - S_ROBOHOOD_JUMP, // painstate + S_NULL, // painstate 0, // painchance sfx_None, // painsound - S_NULL, // meleestate - S_ROBOHOOD_SHOOT, // missilestate + S_ROBOHOOD_JUMP3, // meleestate + S_ROBOHOOD_FIRE1, // missilestate S_XPLD_FLICKY, // deathstate - S_ROBOHOOD_JUMP2, // xdeathstate + S_NULL, // xdeathstate sfx_pop, // deathsound - 0, // speed + 3, // speed 24*FRACUNIT, // radius 32*FRACUNIT, // height 0, // display offset 100, // mass 0, // damage - sfx_None, // activesound + sfx_s3k4a, // activesound MF_ENEMY|MF_SPECIAL|MF_SHOOTABLE, // flags - S_ROBOHOOD_FALL // raisestate + S_ROBOHOOD_JUMP1 // raisestate }, { // MT_FACESTABBER @@ -8616,7 +8617,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_ARROW, // spawnstate 1, // spawnhealth S_NULL, // seestate - sfx_None, // seesound + sfx_s3ka0, // seesound 32, // reactiontime sfx_None, // attacksound S_NULL, // painstate @@ -8626,15 +8627,15 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // missilestate S_NULL, // deathstate S_ARROWDOWN, // xdeathstate - sfx_None, // deathsound + sfx_s3k52, // deathsound 16*FRACUNIT, // speed 4*FRACUNIT, // radius 8*FRACUNIT, // height 0, // display offset 0, // mass 1, // damage - sfx_None, // activesound - MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY, // flags + sfx_s3k51, // activesound + MF_NOBLOCKMAP|MF_MISSILE, // flags S_ARROWUP // raisestate }, diff --git a/src/info.h b/src/info.h index c75ed0e6fb735d7b2c8d0ce1cac4cbb73debd42b..8134a1a49abb16517e688e6524a979964e43eb9f 100644 --- a/src/info.h +++ b/src/info.h @@ -102,7 +102,9 @@ void A_JetJawRoam(); void A_JetJawChomp(); void A_PointyThink(); void A_CheckBuddy(); +void A_HoodFire(); void A_HoodThink(); +void A_HoodFall(); void A_ArrowCheck(); void A_SnailerThink(); void A_SharpChase(); @@ -1107,11 +1109,12 @@ typedef enum state // Robo-Hood S_ROBOHOOD_LOOK, - S_ROBOHOOD_STND, - S_ROBOHOOD_SHOOT, - S_ROBOHOOD_JUMP, + S_ROBOHOOD_STAND, + S_ROBOHOOD_FIRE1, + S_ROBOHOOD_FIRE2, + S_ROBOHOOD_JUMP1, S_ROBOHOOD_JUMP2, - S_ROBOHOOD_FALL, + S_ROBOHOOD_JUMP3, // Castlebot Facestabber S_FACESTABBER_STND1, diff --git a/src/p_enemy.c b/src/p_enemy.c index 20b32f2202415f8a884e7181c5c560bf092b4025..8a09df286aa741f5d11219737e4d921eafdd6416 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -63,7 +63,9 @@ void A_JetJawRoam(mobj_t *actor); void A_JetJawChomp(mobj_t *actor); void A_PointyThink(mobj_t *actor); void A_CheckBuddy(mobj_t *actor); +void A_HoodFire(mobj_t *actor); void A_HoodThink(mobj_t *actor); +void A_HoodFall(mobj_t *actor); void A_ArrowCheck(mobj_t *actor); void A_SnailerThink(mobj_t *actor); void A_SharpChase(mobj_t *actor); @@ -1591,6 +1593,62 @@ void A_CheckBuddy(mobj_t *actor) P_RemoveMobj(actor); } +// Helper function for the Robo Hood. +// Don't ask me how it works. Nev3r made it with dark majyks. +void P_ParabolicMove(mobj_t *actor, fixed_t x, fixed_t y, fixed_t z, fixed_t speed) +{ + fixed_t dh; + + x -= actor->x; + y -= actor->y; + z -= actor->z; + + dh = P_AproxDistance(x, y); + + actor->momx = FixedMul(FixedDiv(x, dh), speed); + actor->momy = FixedMul(FixedDiv(y, dh), speed); + + if (!gravity) + return; + + dh = FixedDiv(FixedMul(dh, gravity), speed); + actor->momz = (dh>>1) + FixedDiv(z, dh<<1); +} + +// Function: A_HoodFire +// +// Description: Firing Robo-Hood +// +// var1 = object type to fire +// var2 = unused +// +void A_HoodFire(mobj_t *actor) +{ + mobj_t *arrow; + INT32 locvar1 = var1; + //INT32 locvar2 = var2; +#ifdef HAVE_BLUA + if (LUA_CallAction("A_HoodFire", actor)) + return; +#endif + + // Check target first. + if (!actor->target) + { + actor->reactiontime = actor->info->reactiontime; + P_SetMobjState(actor, actor->info->spawnstate); + return; + } + + A_FaceTarget(actor); + + if (!(arrow = P_SpawnMissile(actor, actor->target, (mobjtype_t)locvar1))) + return; + + // Set a parabolic trajectory for the arrow. + P_ParabolicMove(arrow, actor->target->x, actor->target->y, actor->target->z, arrow->info->speed); +} + // Function: A_HoodThink // // Description: Thinker for Robo-Hood @@ -1600,53 +1658,87 @@ void A_CheckBuddy(mobj_t *actor) // void A_HoodThink(mobj_t *actor) { + fixed_t dx, dy, dz, dm; + boolean checksight; #ifdef HAVE_BLUA if (LUA_CallAction("A_HoodThink", actor)) return; #endif - // Currently in the air... - if (!(actor->eflags & MFE_VERTICALFLIP) && actor->z > actor->floorz) + + // Check target first. + if (!actor->target) { - if (actor->momz > 0) - P_SetMobjStateNF(actor, actor->info->xdeathstate); // Rising - else - P_SetMobjStateNF(actor, actor->info->raisestate); // Falling + actor->reactiontime = actor->info->reactiontime; + P_SetMobjState(actor, actor->info->spawnstate); + return; + } + dx = (actor->target->x - actor->x), dy = (actor->target->y - actor->y), dz = (actor->target->z - actor->z); + dm = P_AproxDistance(dx, dy); + // Target dangerously close to robohood, retreat then. + if ((dm < 256<<FRACBITS) && (abs(dz) < 128<<FRACBITS)) + { + P_SetMobjState(actor, actor->info->raisestate); return; } - else if ((actor->eflags & MFE_VERTICALFLIP) && actor->z + actor->height < actor->ceilingz) + + // If target on sight, look at it. + if ((checksight = P_CheckSight(actor, actor->target))) { - if (actor->momz < 0) - P_SetMobjStateNF(actor, actor->info->xdeathstate); // Rising + angle_t dang = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); + if (actor->angle >= ANGLE_180) + { + actor->angle = InvAngle(actor->angle)>>1; + actor->angle = InvAngle(actor->angle); + } else - P_SetMobjStateNF(actor, actor->info->raisestate); // Falling + actor->angle >>= 1; - return; - } + if (dang >= ANGLE_180) + { + dang = InvAngle(dang)>>1; + dang = InvAngle(dang); + } + else + dang >>= 1; - if (actor->state == &states[actor->info->xdeathstate] - || actor->state == &states[actor->info->raisestate]) - P_SetMobjStateNF(actor, actor->info->seestate); + actor->angle += dang; + } - if (!actor->target) + // Check whether to do anything. + if ((--actor->reactiontime) <= 0) { - P_SetMobjState(actor, actor->info->spawnstate); - return; - } + actor->reactiontime = actor->info->reactiontime; - A_FaceTarget(actor); // Aiming... aiming... + // If way too far, don't shoot. + if ((dm < (3072<<FRACBITS)) && checksight) + { + P_SetMobjState(actor, actor->info->missilestate); + return; + } + } +} - if (--actor->reactiontime > 0) +// Function: A_HoodFall +// +// Description: Falling Robo-Hood +// +// var1 = unused +// var2 = unused +// +void A_HoodFall(mobj_t *actor) +{ +#ifdef HAVE_BLUA + if (LUA_CallAction("A_HoodFall", actor)) return; +#endif - // Shoot, if not too close (cheap shots are lame) - if ((P_AproxDistance(actor->x-actor->target->x, actor->y-actor->target->y) > FixedMul(192*FRACUNIT, actor->scale)) - || (actor->spawnpoint && (actor->spawnpoint->options & MTF_AMBUSH))) // If you can't jump, might as well shoot regardless of distance! - P_SetMobjState(actor, actor->info->missilestate); - else if (!(actor->spawnpoint && (actor->spawnpoint->options & MTF_AMBUSH)))// But we WILL jump! - P_SetMobjState(actor, actor->info->painstate); + if (!P_IsObjectOnGround(actor)) + return; + actor->momx = actor->momy = 0; actor->reactiontime = actor->info->reactiontime; + P_SetMobjState(actor, actor->info->seestate); } // Function: A_ArrowCheck diff --git a/src/p_mobj.c b/src/p_mobj.c index 8232586b2e3192acee06c33732015de6151d0ad6..3b6ea394c738740baac82d4a0f8d8e997c9f8e57 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7354,6 +7354,20 @@ void P_MobjThinker(mobj_t *mobj) } P_MobjCheckWater(mobj); break; + case MT_ARROW: + if (!(mobj->extravalue1) && (mobj->momz < 0)) + { + mobj->extravalue1 = 1; + S_StartSound(mobj, mobj->info->activesound); + } + if (leveltime & 1) + { + mobj_t *dust = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_PARTICLE); + dust->tics = 18; + dust->scalespeed = 4096; + dust->destscale = FRACUNIT/32; + } + break; case MT_EMERALDSPAWN: if (mobj->threshold) {