class RedneckBowlingPin : DukeActor { default { statnum STAT_ZOMBIEACTOR; clipdist 12; scaleX 0.359375; scaleY 0.359375; detail 0; spriteset "BOWLINGPIN", "BOWLINGPIN1"; } override void Initialize() { self.cstat |= CSTAT_SPRITE_BLOCK_ALL; } protected void DoTick(int type) { if (self.sector.lotag == 900) self.vel.X = 0; if(self.vel.X != 0) { self.makeitfall(); CollisionData coll; self.movesprite_ex((self.angle.ToVector() * self.vel.X, self.vel.Z), CLIPMASK0, coll); if (coll.type) { if (coll.type == kHitWall) { double k = coll.hitWall().delta().Angle(); self.angle = k * 2 - self.angle; } else if (coll.type == kHitSprite) { let hitact = DukeActor(coll.hitActor()); // avoid checkhitsprite here. The way this was handled was just wrong on all accounts self.collide(hitact); //if (hitact is "RedneckHen") // does not work yet - Hen is not scriptified. if (hitact.checkType("HEN")) // Temporary workaround { let ns = hitact.spawn("RedneckHenstand"); hitact.scale = (0,0); hitact.ChangeStat(STAT_MISC); if (ns) { ns.vel.X = 2; ns.lotag = 40; ns.angle = self.angle; } } } } self.vel.X -= 1/16.; if(self.vel.X < 0) self.vel.X = 0; self.cstat = CSTAT_SPRITE_BLOCK_ALL; if (type < 2 && self.vel.X > 0) { self.cstat |= CSTAT_SPRITE_XFLIP & int(self.vel.X * 16); self.cstat |= CSTAT_SPRITE_YFLIP & int(self.vel.X * 16); if (random(0, 1)) self.setSpritesetImage(1); } if (type < 2 && self.vel.X == 0) { return; } } else if (self.sector.lotag == 900 && type != 2) { self.Destroy(); } } override void Tick() { DoTick(0); } virtual void collide(DukeActor targa) { let targ = RedneckBowlingPin(targa); if (!targ) return; if (targ.detail == 0) { self.vel.X *= 0.75; self.angle -= targ.angle * 2 + frandom(0, 11.25); targ.angle += frandom(0, 22.5 / 8); targ.PlayActorSound("BOWLPIN"); } else if (targ.detail == 1) { self.vel.X *= 0.75; self.angle -= targ.angle * 2 + frandom(0, 22.5 / 8); targ.angle += frandom(0, 22.5 / 8); targ.PlayActorSound("BOWLPIN"); } } override void onHit(DukeActor hitter) { if (random(0, 3)) { self.vel.X = 10.25; self.angle = hitter.angle; } } } // chickens on the bowling lane... class RedneckHenstand : RedneckBowlingPin { default { scaleY 0.234375; spriteset "HENSTAND", "HENSTAND1"; detail 1; } override void Tick() { self.lotag--; if (self.lotag == 0) { self.spawn("RedneckHen"); self.scale = (0,0); self.ChangeStat(STAT_MISC); return; } DoTick(1); } } class RedneckBowlingBall : RedneckBowlingPin { default { clipdist 17; scaleX 0.171875; scaleY 0.140625; statnum STAT_ACTOR; pic "BOWLINGBALL"; detail 2; } override void Tick() { if (self.vel.X != 0) { if(!Duke.CheckSoundPlaying("BOWLLOOP")) self.PlayActorSound("BOWLLOOP"); } else { self.spawn("RedneckBowlingBallSprite"); self.Destroy(); return; } if (self.sector.lotag == 900) { self.StopSound("BOWLLOOP"); } DoTick(2); if (self.sector.lotag == 900) { self.ballreturn(); self.Destroy(); return; } } private void ballreturn() { DukeStatIterator it; for (let act1 = it.First(STAT_BOWLING); act1; act1 = it.Next()) { if (act1.getClassName() == 'RedneckBowlingSectorLink' && self.sector == act1.sector) { DukeStatIterator it2; for (let act2 = it2.First(STAT_BOWLING); act2; act2 = it2.Next()) { if (act2.getClassName() == 'RedneckBowlingBallSpot' && act1.hitag == act2.hitag) { act2.spawn("RedneckBowlingBallSprite"); } if (act2.getClassName() == 'RedneckBowlingPinController' && act1.hitag == act2.hitag && act2.lotag == 0) { let sec = act2.sector; act2.lotag = 100; act2.extra++; int j = dlevel.getanimationindex(dlevel.anim_ceilingz, sec); if (j == -1) dlevel.setanimation(sec, dlevel.anim_ceilingz, sec, sec.floorz, 0.25); } } } } } override void onHit(DukeActor hitter) { } override void collide(DukeActor targ) { targ.vel.X = self.vel.X * 0.75; if (random(0, 32767) & 16) targ.angle -= 22.5 / 8; targ.PlayActorSound("BOWLPIN"); } override bool ShootThis(DukeActor actor, DukePlayer plr, Vector3 spos, double sang) { let j = actor.spawn(self.GetClassName()); if (j) { j.vel.X = 250 / 16.; j.angle = self.angle; j.pos.Z -= 15; } return true; } } class RedneckBowlingController : DukeActor { default { statnum STAT_BOWLING; scaleX 0; scaleY 0; clipdist 0; extra 0; } override void Initialize() { self.cstat = CSTAT_SPRITE_INVISIBLE; } } class RedneckBowlingPinController : RedneckBowlingController { override void Tick() { if (self.lotag == 100) { let pst = pinsectorresetup(); if (pst) { self.lotag = 0; if (self.extra == 1) { pst = checkpins(); if (!pst) { self.extra = 2; } } if (self.extra == 2) { self.extra = 0; resetpins(); } } } } int pinsectorresetup() { let sec = self.sector; int j = dlevel.getanimationindex(dlevel.anim_ceilingz, sec); if (j == -1) { double z = sec.nextsectorneighborz(sec.ceilingz, sectortype.Find_CeilingUp | sectortype.Find_Safe).ceilingz; dlevel.setanimation(sec, dlevel.anim_ceilingz, sec, z, 0.25); return 1; } return 0; } int checkpins() { int pins = 0; int pin = 0; DukeSectIterator it; for (let a2 = it.First(self.sector); a2; a2 = it.Next()) { if (a2.GetClassName() == 'RedneckBowlingPin' && a2.spritesetindex == 0) { pin++; pins |= 1 << a2.lotag; } } Duke.updatepindisplay(self.hitag, pins); return pin; } void resetpins() { int i, tag = 0; DukeSectIterator it; for (let a2 = it.First(self.sector); a2; a2 = it.Next()) { if (a2.GetClassName() == 'RedneckBowlingPin') a2.Destroy(); } for (let a2 = it.First(self.sector); a2; a2 = it.Next()) { if (a2.GetClassName() == 'RedneckBowlingPinSpot') { let spawned = a2.spawn('RedneckBowlingPin'); if (spawned) { spawned.lotag = a2.lotag; spawned.clipdist = 12; // random formula here was bogus and always produced 48. spawned.angle -= 22.5 * 0.125 * (((random(0, 32767) & 32) - (random(0, 32767) & 64)) >> 5); } } } Duke.updatepindisplay(self.hitag, 0xffff); } } class RedneckBowlingSectorLink : RedneckBowlingController { } class RedneckBowlingBallSpot : RedneckBowlingController { } class RedneckBowlingPinSpot : RedneckBowlingController { }