diff --git a/src/dehacked.c b/src/dehacked.c index 6a3aae290..a76e7c9f0 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -2265,6 +2265,9 @@ static actionpointer_t actionpointers[] = {{A_CrushclawLaunch}, "A_CRUSHCLAWLAUNCH"}, {{A_VultureVtol}, "A_VULTUREVTOL"}, {{A_VultureCheck}, "A_VULTURECHECK"}, + {{A_VultureHover}, "A_VULTUREHOVER"}, + {{A_VultureBlast}, "A_VULTUREBLAST"}, + {{A_VultureFly}, "A_VULTUREFLY"}, {{A_SkimChase}, "A_SKIMCHASE"}, {{A_1upThinker}, "A_1UPTHINKER"}, {{A_SkullAttack}, "A_SKULLATTACK"}, @@ -4386,15 +4389,10 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit // Vulture "S_VULTURE_STND", - "S_VULTURE_VTOL1", - "S_VULTURE_VTOL2", - "S_VULTURE_VTOL3", - "S_VULTURE_VTOL4", + "S_VULTURE_DRIFT", "S_VULTURE_ZOOM1", "S_VULTURE_ZOOM2", - "S_VULTURE_ZOOM3", - "S_VULTURE_ZOOM4", - "S_VULTURE_ZOOM5", + "S_VULTURE_STUNNED", // Pointy "S_POINTY1", diff --git a/src/info.c b/src/info.c index 659e883a5..cc0ad09f7 100644 --- a/src/info.c +++ b/src/info.c @@ -996,16 +996,11 @@ state_t states[NUMSTATES] = {SPR_SNLR, 0, 1, {A_SnailerThink}, 0, 0, S_SNAILER1}, // S_SNAILER1 // Vulture - {SPR_VLTR, 4, 35, {A_Look}, 1, 0, S_VULTURE_STND}, // S_VULTURE_STND - {SPR_VLTR, 4, 1, {A_VultureVtol}, 0, 0, S_VULTURE_VTOL2}, // S_VULTURE_VTOL1 - {SPR_VLTR, 5, 1, {A_VultureVtol}, 0, 0, S_VULTURE_VTOL3}, // S_VULTURE_VTOL2 - {SPR_VLTR, 6, 1, {A_VultureVtol}, 0, 0, S_VULTURE_VTOL4}, // S_VULTURE_VTOL3 - {SPR_VLTR, 7, 1, {A_VultureVtol}, 0, 0, S_VULTURE_VTOL1}, // S_VULTURE_VTOL4 - {SPR_VLTR, 0, 1, {A_Thrust}, 30, 1, S_VULTURE_ZOOM2}, // S_VULTURE_ZOOM1 - {SPR_VLTR, 0, 1, {A_VultureCheck}, 0, 0, S_VULTURE_ZOOM3}, // S_VULTURE_ZOOM2 - {SPR_VLTR, 1, 1, {A_VultureCheck}, 0, 0, S_VULTURE_ZOOM4}, // S_VULTURE_ZOOM3 - {SPR_VLTR, 2, 1, {A_VultureCheck}, 0, 0, S_VULTURE_ZOOM5}, // S_VULTURE_ZOOM4 - {SPR_VLTR, 3, 1, {A_VultureCheck}, 0, 0, S_VULTURE_ZOOM2}, // S_VULTURE_ZOOM5 + {SPR_VLTR, 4, 35, {A_Look}, 1, 0, S_VULTURE_STND}, // S_VULTURE_STND + {SPR_VLTR, 4, 3, {A_VultureHover}, 0, 0, S_VULTURE_DRIFT}, // S_VULTURE_DRIFT + {SPR_VLTR, 0, 6, {A_VultureBlast}, 0, 0, S_VULTURE_ZOOM2}, // S_VULTURE_ZOOM1 + {SPR_VLTR, 0, 3, {A_VultureFly}, 0, 0, S_VULTURE_ZOOM2}, // S_VULTURE_ZOOM2 + {SPR_VLTR, 0, 3*TICRATE, {NULL}, 0, 0, S_VULTURE_DRIFT}, // S_VULTURE_STUNNED // Pointy {SPR_PNTY, 0, 1, {A_PointyThink}, 0, 0, S_POINTY1}, // S_POINTY1 @@ -4451,26 +4446,26 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 115, // doomednum S_VULTURE_STND, // spawnstate 1, // spawnhealth - S_VULTURE_VTOL1,// seestate + S_VULTURE_DRIFT,// seestate sfx_None, // seesound - 2, // reactiontime - sfx_None, // attacksound - S_NULL, // painstate + TICRATE/2, // reactiontime + sfx_s3k60, // attacksound + S_VULTURE_STUNNED, // painstate S_NULL, // painchance - sfx_None, // painsound + sfx_s3k96, // painsound S_NULL, // meleestate S_VULTURE_ZOOM1,// missilestate S_XPLD_FLICKY, // deathstate S_NULL, // xdeathstate sfx_pop, // deathsound - 3, // speed + 5, // speed 12*FRACUNIT, // radius 24*FRACUNIT, // height 0, // display offset TICRATE, // mass 0, // damage sfx_jet, // activesound - MF_ENEMY|MF_SPECIAL|MF_SHOOTABLE|MF_NOGRAVITY, // flags + MF_ENEMY|MF_SPECIAL|MF_SHOOTABLE|MF_NOGRAVITY|MF_SLIDEME, // flags S_NULL // raisestate }, diff --git a/src/info.h b/src/info.h index 44f1bea1f..6e544d2d6 100644 --- a/src/info.h +++ b/src/info.h @@ -115,6 +115,9 @@ void A_CrushclawAim(); void A_CrushclawLaunch(); void A_VultureVtol(); void A_VultureCheck(); +void A_VultureHover(); +void A_VultureBlast(); +void A_VultureFly(); void A_SkimChase(); void A_SkullAttack(); void A_LobShot(); @@ -1144,15 +1147,10 @@ typedef enum state // Vulture S_VULTURE_STND, - S_VULTURE_VTOL1, - S_VULTURE_VTOL2, - S_VULTURE_VTOL3, - S_VULTURE_VTOL4, + S_VULTURE_DRIFT, S_VULTURE_ZOOM1, S_VULTURE_ZOOM2, - S_VULTURE_ZOOM3, - S_VULTURE_ZOOM4, - S_VULTURE_ZOOM5, + S_VULTURE_STUNNED, // Pointy S_POINTY1, diff --git a/src/p_enemy.c b/src/p_enemy.c index 3719d8b6c..450cba37a 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -79,6 +79,9 @@ void A_CrushclawAim(mobj_t *actor); void A_CrushclawLaunch(mobj_t *actor); void A_VultureVtol(mobj_t *actor); void A_VultureCheck(mobj_t *actor); +void A_VultureHover(mobj_t *actor); +void A_VultureBlast(mobj_t *actor); +void A_VultureFly(mobj_t *actor); void A_SkimChase(mobj_t *actor); void A_FaceTarget(mobj_t *actor); void A_FaceTracer(mobj_t *actor); @@ -2301,6 +2304,219 @@ void A_VultureCheck(mobj_t *actor) } } +static void P_VultureHoverParticle(mobj_t *actor) +{ + fixed_t fdist = actor->z - P_FloorzAtPos(actor->x, actor->y, actor->z, actor->height); + + if (fdist < 128*FRACUNIT) + { + mobj_t *dust; + UINT8 i; + angle_t angle = (leveltime % 2)*ANGLE_45/2; + + for (i = 0; i <= 7; i++) + { + angle_t fa = (angle >> ANGLETOFINESHIFT) & FINEMASK; + fixed_t px = actor->x + FixedMul(fdist + 64*FRACUNIT, FINECOSINE(fa)); + fixed_t py = actor->y + FixedMul(fdist + 64*FRACUNIT, FINESINE(fa)); + fixed_t pz = P_FloorzAtPos(px, py, actor->z, actor->height); + + dust = P_SpawnMobj(px, py, pz, MT_ARIDDUST); + P_SetMobjState(dust, (statenum_t)(dust->state + P_RandomRange(0, 2))); + P_Thrust(dust, angle, FixedDiv(12*FRACUNIT, max(FRACUNIT, fdist/2))); + dust->momx += actor->momx; + dust->momy += actor->momy; + angle += ANGLE_45; + } + } +} + +// Function: A_VultureHover +// +// Description: Vulture hovering and checking whether to attack. +// +// var1 = unused +// var2 = unused +// +void A_VultureHover(mobj_t *actor) +{ + fixed_t targetz; + fixed_t distdif; + fixed_t memz = actor->z; + INT8 i; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_VultureHover", actor)) + return; +#endif + + if (!actor->target) + { + P_SetMobjState(actor, actor->info->spawnstate); + return; + } + + actor->flags |= MF_NOGRAVITY; + + actor->momx -= actor->momx/24; + actor->momy -= actor->momy/24; + + P_VultureHoverParticle(actor); + + A_FaceTarget(actor); + targetz = actor->target->z + actor->target->height / 2; + for (i = -1; i <= 1; i++) + { + actor->z = targetz - i * 128 * FRACUNIT; + if (P_CheckSight(actor, actor->target)) + { + targetz -= i * 128 * FRACUNIT; + break; + } + } + actor->z = memz; + + distdif = (actor->z + actor->height/2) - targetz; + + if (abs(actor->momz*16) > abs(distdif)) + actor->momz -= actor->momz/16; + else if (distdif < 0) + actor->momz = min(actor->momz+FRACUNIT/8, actor->info->speed*FRACUNIT); + else + actor->momz = max(actor->momz-FRACUNIT/8, -actor->info->speed*FRACUNIT); + + if (abs(distdif) < 128*FRACUNIT && abs(actor->momz) < FRACUNIT && P_CheckSight(actor, actor->target)) + { + P_SetMobjState(actor, actor->info->missilestate); + actor->momx = 0; + actor->momy = 0; + actor->momz = 0; + actor->extravalue1 = 0; + } +} + +// Function: A_VultureBlast +// +// Description: Vulture spawning a dust cloud. +// +// var1 = unused +// var2 = unused +// +void A_VultureBlast(mobj_t *actor) +{ + mobj_t *dust; + UINT8 i; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_VultureBlast", actor)) + return; +#endif + + S_StartSound(actor, actor->info->attacksound); + + for (i = 0; i <= 7; i++) + { + angle_t fa = ((i*(angle_t)ANGLE_45) >> ANGLETOFINESHIFT) & FINEMASK; + angle_t faa = (actor->angle >> ANGLETOFINESHIFT) & FINEMASK; + dust = P_SpawnMobj(actor->x + 48*FixedMul(FINECOSINE(fa), -FINESINE(faa)), actor->y + 48*FixedMul(FINECOSINE(fa), FINECOSINE(faa)), actor->z + actor->height/2 + 48*FINESINE(fa), MT_PARTICLE); + + P_SetScale(dust, 4*FRACUNIT); + dust->destscale = FRACUNIT; + dust->scalespeed = 4*FRACUNIT/TICRATE; + dust->fuse = TICRATE; + dust->momx = FixedMul(FINECOSINE(fa), -FINESINE(faa))*3; + dust->momy = FixedMul(FINECOSINE(fa), FINECOSINE(faa))*3; + dust->momz = FINESINE(fa)*6; + } +} + +// Function: A_VultureFly +// +// Description: Vulture charging towards target. +// +// var1 = unused +// var2 = unused +// +void A_VultureFly(mobj_t *actor) +{ + fixed_t speedmax = 18*FRACUNIT; + angle_t angledif = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) - actor->angle; + fixed_t dx = actor->target->x - actor->x; + fixed_t dy = actor->target->y - actor->y; + fixed_t dz = actor->target->z - actor->z; + fixed_t dxy = FixedHypot(dx, dy); + fixed_t dm; + mobj_t *dust; + fixed_t momm; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_VultureFly", actor)) + return; +#endif + + if (leveltime % 4 == 0) + S_StartSound(actor, actor->info->activesound); + + // Tweak the target height according to the position. + if (abs(angledif) < ANGLE_45) // Centered? + { + actor->reactiontime = actor->info->reactiontime; + if (dxy > 768*FRACUNIT) + dz = max(P_FloorzAtPos(actor->target->x, actor->target->y, actor->target->z, 0) - actor->z + min(dxy/8, 128*FRACUNIT), dz); + } + else + { + actor->reactiontime--; + + if (abs(angledif) < ANGLE_90) + dz = max(P_FloorzAtPos(actor->target->x, actor->target->y, actor->target->z, 0) - actor->z + min(dxy/2, 192*FRACUNIT), dz); + else + dz = max(P_FloorzAtPos(actor->target->x, actor->target->y, actor->target->z, 0) - actor->z + 232*FRACUNIT, dz); + } + + dm = FixedHypot(dz, dxy); + + P_VultureHoverParticle(actor); + + dust = P_SpawnMobj(actor->x + P_RandomFixed() - FRACUNIT/2, actor->y + P_RandomFixed() - FRACUNIT/2, actor->z + actor->height/2 + P_RandomFixed() - FRACUNIT/2, MT_PARTICLE); + P_SetScale(dust, 2*FRACUNIT); + dust->destscale = FRACUNIT/3; + dust->scalespeed = FRACUNIT/40; + dust->fuse = TICRATE*2; + + actor->momx += FixedDiv(dx, dm)*2; + actor->momy += FixedDiv(dy, dm)*2; + actor->momz += FixedDiv(dz, dm)*2; + + momm = FixedHypot(actor->momz, FixedHypot(actor->momx, actor->momy)); + + if (momm > speedmax/2 && actor->reactiontime == 0) + { + P_SetMobjState(actor, actor->info->seestate); + return; + } + + //Hits a wall hard? + if (actor->extravalue1 - momm > 15*FRACUNIT) + { + actor->flags &= ~MF_NOGRAVITY; + P_SetMobjState(actor, actor->info->painstate); + S_StopSound(actor); + S_StartSound(actor, actor->info->painsound); + return; + } + actor->extravalue1 = momm; + + if (momm > speedmax) + { + actor->momx = FixedMul(FixedDiv(actor->momx, momm), speedmax); + actor->momy = FixedMul(FixedDiv(actor->momy, momm), speedmax); + actor->momz = FixedMul(FixedDiv(actor->momz, momm), speedmax); + } + + actor->angle = R_PointToAngle2(0, 0, actor->momx, actor->momy); +} + // Function: A_SkimChase // // Description: Thinker/Chase routine for Skims diff --git a/src/p_map.c b/src/p_map.c index ca4548d0b..db3dac86b 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -853,6 +853,17 @@ static boolean PIT_CheckThing(mobj_t *thing) P_DamageMobj(thing, tmthing, tmthing, 1, 0); } + if (thing->type == MT_VULTURE && tmthing->type == MT_VULTURE) + { + fixed_t dx = thing->x - tmthing->x; + fixed_t dy = thing->y - tmthing->y; + fixed_t dz = thing->z - tmthing->z; + fixed_t dm = FixedHypot(dz, FixedHypot(dx, dy)); + thing->momx += FixedDiv(dx, dm); + thing->momy += FixedDiv(dy, dm); + thing->momz += FixedDiv(dz, dm); + } + if (tmthing->type == MT_FANG && thing->type == MT_FSGNB) { if (thing->z > tmthing->z + tmthing->height)