extend class Actor { //--------------------------------------------------------------------------- // // Used by A_CustomBulletAttack and A_FireBullets // //--------------------------------------------------------------------------- static void AimBulletMissile(Actor proj, Actor puff, int flags, bool temp, bool cba) { if (proj && puff) { // FAF_BOTTOM = 1 // Aim for the base of the puff as that's where blood puffs will spawn... roughly. proj.A_Face(puff, 0., 0., 0., 0., 1); proj.Vel3DFromAngle(proj.Speed, proj.Angle, proj.Pitch); if (!temp) { if (cba) { if (flags & CBAF_PUFFTARGET) proj.target = puff; if (flags & CBAF_PUFFMASTER) proj.master = puff; if (flags & CBAF_PUFFTRACER) proj.tracer = puff; } else { if (flags & FBF_PUFFTARGET) proj.target = puff; if (flags & FBF_PUFFMASTER) proj.master = puff; if (flags & FBF_PUFFTRACER) proj.tracer = puff; } } } if (puff && temp) { puff.Destroy(); } } //--------------------------------------------------------------------------- // // // //--------------------------------------------------------------------------- void A_CustomBulletAttack(double spread_xy, double spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", double range = 0, int flags = 0, int ptr = AAPTR_TARGET, class missile = null, double Spawnheight = 32, double Spawnofs_xy = 0) { let ref = GetPointer(ptr); if (range == 0) range = MISSILERANGE; int i; double bangle; double bslope = 0.; int laflags = (flags & CBAF_NORANDOMPUFFZ)? LAF_NORANDOMPUFFZ : 0; if (ref != NULL || (flags & CBAF_AIMFACING)) { if (!(flags & CBAF_AIMFACING)) { A_Face(ref); } bangle = self.Angle; if (!(flags & CBAF_NOPITCH)) bslope = AimLineAttack (bangle, MISSILERANGE); if (pufftype == null) pufftype = 'BulletPuff'; A_PlaySound(AttackSound, CHAN_WEAPON); for (i = 0; i < numbullets; i++) { double pangle = bangle; double slope = bslope; if (flags & CBAF_EXPLICITANGLE) { pangle += spread_xy; slope += spread_z; } else { pangle += spread_xy * Random2[cwbullet]() / 255.; slope += spread_z * Random2[cwbullet]() / 255.; } int damage = damageperbullet; if (!(flags & CBAF_NORANDOM)) damage *= random[cwbullet](1, 3); let puff = LineAttack(pangle, range, slope, damage, 'Hitscan', pufftype, laflags); if (missile != null && pufftype != null) { double x = Spawnofs_xy * cos(pangle); double y = Spawnofs_xy * sin(pangle); SetXYZ(Vec3Offset(x, y, 0.)); let proj = SpawnMissileAngleZSpeed(Pos.Z + GetBobOffset() + Spawnheight, missile, self.Angle, 0, GetDefaultByType(missile).Speed, self, false); SetXYZ(pos); if (proj) { bool temp = (puff == null); if (!puff) { puff = LineAttack(pangle, range, slope, 0, 'Hitscan', pufftype, laflags | LAF_NOINTERACT); } if (puff) { AimBulletMissile(proj, puff, flags, temp, true); } } } } } } //============================================================================ // // P_DaggerAlert // //============================================================================ void DaggerAlert(Actor target) { Actor looker; if (LastHeard != NULL) return; if (health <= 0) return; if (!bIsMonster) return; if (bInCombat) return; bInCombat = true; self.target = target; let painstate = FindState('Pain', 'Dagger'); if (painstate != NULL) { SetState(painstate); } for (looker = cursector.thinglist; looker != NULL; looker = looker.snext) { if (looker == self || looker == target) continue; if (looker.health <= 0) continue; if (!looker.bSeesDaggers) continue; if (!looker.bInCombat) { if (!looker.CheckSight(target) && !looker.CheckSight(self)) continue; looker.target = target; if (looker.SeeSound) { looker.A_PlaySound(looker.SeeSound, CHAN_VOICE); } looker.SetState(looker.SeeState); looker.bInCombat = true; } } } }