2022-12-01 10:55:35 +00:00
|
|
|
class DukeMortar : DukeActor
|
|
|
|
{
|
|
|
|
default
|
|
|
|
{
|
2022-12-22 18:46:00 +00:00
|
|
|
pic "MORTER";
|
2023-01-08 15:38:30 +00:00
|
|
|
DukeMortar.ceilingdist 3;
|
2022-12-22 18:46:00 +00:00
|
|
|
DukeMortar.spawnscale 0.5;
|
2022-12-01 10:55:35 +00:00
|
|
|
}
|
2023-01-08 15:38:30 +00:00
|
|
|
|
|
|
|
meta int ceilingdist;
|
2022-12-22 18:46:00 +00:00
|
|
|
meta double spawnscale;
|
2023-01-08 15:38:30 +00:00
|
|
|
property ceilingdist: ceilingdist;
|
2022-12-22 18:46:00 +00:00
|
|
|
property spawnscale: spawnscale;
|
2022-12-01 10:55:35 +00:00
|
|
|
|
2022-12-22 18:46:00 +00:00
|
|
|
|
|
|
|
override bool ShootThis(DukeActor actor, DukePlayer p, Vector3 pos, double ang) const
|
|
|
|
{
|
|
|
|
let sect = actor.sector;
|
|
|
|
if (actor.extra >= 0) actor.shade = -96;
|
|
|
|
|
|
|
|
double x;
|
|
|
|
DukePlayer p;
|
|
|
|
[p, x] = actor.findplayer();
|
|
|
|
let plActor = p.Actor;
|
|
|
|
x = (plActor.pos.XY - actor.pos.XY).Length();
|
|
|
|
|
|
|
|
double zvel = -x * 0.5;
|
|
|
|
|
|
|
|
if (zvel < -8)
|
|
|
|
zvel = -4;
|
|
|
|
double vel = x / 16.;
|
|
|
|
dlevel.SpawnActor(sect, pos.plusZ(-6) + ang.ToVector() * 4, GetClass(), -64, (self.spawnscale, self.spawnscale), ang, vel, zvel, actor, STAT_ACTOR);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-12-01 10:55:35 +00:00
|
|
|
override void Tick()
|
|
|
|
{
|
2022-12-13 18:39:27 +00:00
|
|
|
let spawned = self.spawn("DukeFrameEffect");
|
2022-12-22 08:49:42 +00:00
|
|
|
if (spawned) spawned.counter = 3;
|
2022-12-01 10:55:35 +00:00
|
|
|
Common(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Common(int itemmode)
|
|
|
|
{
|
|
|
|
let sectp = self.sector;
|
|
|
|
DukePlayer p;
|
|
|
|
double xx;
|
|
|
|
|
|
|
|
[p,xx] = self.findplayer();
|
|
|
|
|
2022-12-18 08:14:11 +00:00
|
|
|
if (xx < 1220 / 16.) self.cstat &= ~CSTAT_SPRITE_BLOCK_ALL;
|
|
|
|
else self.cstat |= CSTAT_SPRITE_BLOCK_ALL;
|
|
|
|
|
2022-12-01 10:55:35 +00:00
|
|
|
if (self.temp_data[3] == 0)
|
|
|
|
{
|
|
|
|
int j = self.ifhitbyweapon();
|
|
|
|
if (j >= 0)
|
|
|
|
{
|
|
|
|
self.temp_data[3] = 1;
|
|
|
|
self.temp_data[4] = 0;
|
|
|
|
self.vel.X = 0;
|
|
|
|
self.DetonateIt(itemmode);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (itemmode != 0)
|
|
|
|
{
|
|
|
|
self.makeitfall();
|
|
|
|
|
|
|
|
// Feature check later needs to be map controlled, not game controlled.
|
|
|
|
if (sectp.lotag != ST_1_ABOVE_WATER && (!Raze.isRRRA() || sectp.lotag != ST_160_FLOOR_TELEPORT) && self.pos.Z >= self.floorz - 1 && self.yint < 3)
|
|
|
|
{
|
|
|
|
if (self.yint > 0 || (self.yint == 0 && self.floorz == sectp.floorz))
|
|
|
|
{
|
|
|
|
if (itemmode != 2)
|
|
|
|
self.PlayActorSound("PIPEBOMB_BOUNCE");
|
|
|
|
else if (self.temp_data[3] == 0)
|
|
|
|
{
|
|
|
|
self.temp_data[3] = 1;
|
|
|
|
self.temp_data[4] = 0;
|
|
|
|
self.DetonateIt(itemmode);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
self.vel.Z = -(4 - self.yint);
|
|
|
|
if (sectp.lotag == 2)
|
|
|
|
self.vel.Z *= 0.25;
|
|
|
|
self.yint++;
|
|
|
|
}
|
2023-01-08 15:38:30 +00:00
|
|
|
if (itemmode != 2 && self.pos.Z < self.ceilingz + self.ceilingdist && (!Raze.isRR() || sectp.lotag != ST_2_UNDERWATER)) // underwater check only for RR
|
2022-12-01 10:55:35 +00:00
|
|
|
{
|
2023-01-08 15:38:30 +00:00
|
|
|
self.pos.Z = self.ceilingz + self.ceilingdist;
|
2022-12-01 10:55:35 +00:00
|
|
|
self.vel.Z = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CollisionData coll;
|
|
|
|
self.movesprite_ex((self.angle.ToVector() * self.vel.X, self.vel.Z), CLIPMASK0, coll);
|
|
|
|
|
|
|
|
if (sectp.lotag == ST_1_ABOVE_WATER && self.vel.Z == 0)
|
|
|
|
{
|
|
|
|
self.pos.Z += 32;
|
2022-12-22 08:49:42 +00:00
|
|
|
if (self.temp_data[0] == 0)
|
2022-12-01 10:55:35 +00:00
|
|
|
{
|
2022-12-22 08:49:42 +00:00
|
|
|
self.temp_data[0] = 1;
|
2022-12-13 18:39:27 +00:00
|
|
|
self.spawn("DukeWaterSplash");
|
2022-12-01 10:55:35 +00:00
|
|
|
}
|
|
|
|
}
|
2022-12-22 08:49:42 +00:00
|
|
|
else self.temp_data[0] = 0;
|
2022-12-01 10:55:35 +00:00
|
|
|
|
|
|
|
if (self.temp_data[3] == 0 && (coll.type || xx < 844 / 16.))
|
|
|
|
{
|
|
|
|
self.temp_data[3] = 1;
|
|
|
|
self.temp_data[4] = 0;
|
|
|
|
self.vel.X = 0;
|
|
|
|
}
|
|
|
|
else if(self.vel.X > 0)
|
|
|
|
{
|
|
|
|
self.vel.X -= 5. / 16;
|
|
|
|
if (sectp.lotag == ST_2_UNDERWATER)
|
|
|
|
self.vel.X -= 10. / 16;
|
|
|
|
|
|
|
|
if(self.vel.X < 0)
|
|
|
|
self.vel.X = 0;
|
|
|
|
//if (int(self.vel.X * 16) & 8) self.spr.cstat ^= CSTAT_SPRITE_XFLIP;
|
|
|
|
}
|
|
|
|
self.DetonateIt(itemmode);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DetonateIt(int itemmode)
|
|
|
|
{
|
|
|
|
if (self.temp_data[3] == 1)
|
|
|
|
{
|
|
|
|
self.temp_data[4]++;
|
|
|
|
|
2022-12-19 09:21:20 +00:00
|
|
|
DukePlayer p;
|
|
|
|
double xx;
|
|
|
|
|
|
|
|
[p,xx] = self.findplayer();
|
2022-12-01 10:55:35 +00:00
|
|
|
|
|
|
|
if (self.temp_data[4] == 2)
|
|
|
|
{
|
|
|
|
int x = self.extra;
|
|
|
|
int m = itemmode == 0? gs.bouncemineblastradius : gs.morterblastradius;
|
|
|
|
|
|
|
|
if (self.sector.lotag != 800 || !Raze.isRR()) // this line is RR only
|
|
|
|
{
|
|
|
|
self.hitradius(m, x >> 2, x >> 1, x - (x >> 2), x);
|
|
|
|
self.spawn("DukeExplosion2");
|
|
|
|
if (self.vel.Z == 0 && !Raze.isRR()) self.spawn("DukeExplosion2Bot"); // this line is Duke only
|
|
|
|
if (itemmode == 2) self.spawn("DukeBurning");
|
|
|
|
self.PlayActorSound("PIPEBOMB_EXPLODE");
|
|
|
|
for (x = 0; x < 8; x++)
|
|
|
|
self.RANDOMSCRAP();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (self.scale.Y)
|
|
|
|
{
|
|
|
|
self.scale.Y = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (self.temp_data[4] > 20)
|
|
|
|
{
|
|
|
|
self.Destroy();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (itemmode == 2)
|
|
|
|
{
|
|
|
|
self.spawn("DukeBurning");
|
|
|
|
self.Destroy();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2022-12-22 08:49:42 +00:00
|
|
|
if (self.counter < 8) self.counter++;
|
2022-12-01 10:55:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
class DukeBounceMine : DukeMortar
|
|
|
|
{
|
|
|
|
default
|
|
|
|
{
|
|
|
|
pic "BOUNCEMINE";
|
|
|
|
}
|
|
|
|
|
|
|
|
override void Initialize()
|
|
|
|
{
|
|
|
|
// This is only for placed items, not for armed weapons!
|
|
|
|
// Although this can be shot, it doesn't really work for that.
|
2022-12-13 10:29:37 +00:00
|
|
|
if (self.mapSpawned)
|
2022-12-01 10:55:35 +00:00
|
|
|
{
|
|
|
|
self.ownerActor = self;
|
|
|
|
self.extra = gs.impact_damage << 2;
|
|
|
|
self.cstat |= CSTAT_SPRITE_BLOCK_ALL; // Make it hitable
|
|
|
|
self.ChangeStat(STAT_ZOMBIEACTOR);
|
|
|
|
self.shade = -127;
|
|
|
|
self.Scale = (0.375, 0.375);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override void Tick()
|
|
|
|
{
|
|
|
|
Common(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-04 12:09:47 +00:00
|
|
|
class RedneckMortar : DukeMortar
|
2022-12-01 10:55:35 +00:00
|
|
|
{
|
|
|
|
default
|
|
|
|
{
|
2023-01-08 15:38:30 +00:00
|
|
|
DukeMortar.ceilingdist 16;
|
2022-12-01 10:55:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
override void Tick()
|
|
|
|
{
|
|
|
|
Common(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
class RedneckCheerBomb : DukeMortar
|
|
|
|
{
|
|
|
|
default
|
|
|
|
{
|
|
|
|
spriteset "CHEERBOMB", "CHEERBOMB1", "CHEERBOMB2", "CHEERBOMB3";
|
2023-01-08 15:38:30 +00:00
|
|
|
DukeMortar.ceilingdist 16;
|
2022-12-16 11:47:30 +00:00
|
|
|
+NOFLOORPAL;
|
2022-12-22 18:46:00 +00:00
|
|
|
DukeMortar.spawnscale 0.25;
|
2022-12-01 10:55:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
override bool Animate(tspritetype t)
|
|
|
|
{
|
|
|
|
t.SetSpritePic(self, (PlayClock >> 4) & 3);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
override void Tick()
|
|
|
|
{
|
|
|
|
Common(2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|