Final round of tuning for wall busting, it's even more HD-like now.
Add option to disable unrestricted Wallbuster destruction. Add wall penetration to Silver Bullet JET.
This commit is contained in:
parent
2184079c07
commit
b5947709f7
11 changed files with 417 additions and 74 deletions
|
|
@ -448,6 +448,7 @@ Class BusterWall : Thinker
|
|||
bool busted;
|
||||
Vector3 bustdir;
|
||||
int busttics;
|
||||
double cutheight;
|
||||
// cached
|
||||
Vector3 boundsmin, boundsmax, step;
|
||||
|
||||
|
|
@ -513,7 +514,7 @@ Class BusterWall : Thinker
|
|||
}
|
||||
}
|
||||
|
||||
static void Bust( TraceResults d, int accdamage, Actor instigator, Vector3 x )
|
||||
static void Bust( TraceResults d, int accdamage, Actor instigator, Vector3 x, double hitz )
|
||||
{
|
||||
// we can't blow up 3D floors (yet)
|
||||
if ( d.ffloor ) return;
|
||||
|
|
@ -521,7 +522,7 @@ Class BusterWall : Thinker
|
|||
int hp;
|
||||
if ( d.HitType == TRACE_HitWall )
|
||||
{
|
||||
// onesided wall? no bust
|
||||
// onesided wall? no bust (TODO: bust polyobjects)
|
||||
if ( !d.HitLine.sidedef[1] ) return;
|
||||
// sector is opposite of side hit
|
||||
hs = d.HitLine.sidedef[!d.Side].sector;
|
||||
|
|
@ -537,43 +538,54 @@ Class BusterWall : Thinker
|
|||
int lcnt = 0;
|
||||
for ( int i=0; i<hs.Lines.Size(); i++ ) if ( hs.Lines[i].sidedef[1] ) lcnt++;
|
||||
if ( lcnt < 2 ) return;
|
||||
// is this actually sticking out?
|
||||
double thisheight, othersheight, partheight;
|
||||
if ( hp )
|
||||
{
|
||||
thisheight = hs.FindLowestCeilingPoint();
|
||||
othersheight = hs.FindHighestCeilingSurrounding();
|
||||
if ( (thisheight-othersheight) >= -4. ) return;
|
||||
}
|
||||
else
|
||||
{
|
||||
thisheight = hs.FindHighestFloorPoint();
|
||||
othersheight = hs.FindLowestFloorSurrounding();
|
||||
if ( (thisheight-othersheight) <= 4. ) return;
|
||||
}
|
||||
partheight = abs(thisheight-othersheight);
|
||||
// Check if it's a door
|
||||
if ( !swwm_cbtall && !SWWMUtility.IsDoorSector(hs,hp) ) return;
|
||||
let ti = ThinkerIterator.Create("BusterWall",STAT_USER);
|
||||
BusterWall iter, bust = null;
|
||||
while ( iter = BusterWall(ti.Next()) )
|
||||
{
|
||||
if ( (iter.hitsector != hs) || (iter.hitplane != hp) ) continue;
|
||||
bust = iter;
|
||||
bust.accdamage += accdamage;
|
||||
bust.bustdir = (bust.bustdir+x)*.5;
|
||||
break;
|
||||
}
|
||||
bool mnew = false;
|
||||
if ( !bust )
|
||||
{
|
||||
bust = new("BusterWall");
|
||||
bust.ChangeStatNum(STAT_USER);
|
||||
bust.hitsector = hs;
|
||||
bust.accdamage = accdamage;
|
||||
bust.accdamage = 0;
|
||||
bust.hitplane = hp;
|
||||
bust.bustdir = x;
|
||||
mnew = true;
|
||||
}
|
||||
bust.accdamage += accdamage;
|
||||
bust.acchits.Push(accdamage);
|
||||
bust.bustdir = (bust.bustdir+x)*.5;
|
||||
double extracut = FRandom[Wallbuster](.01,.04)*bust.accdamage;
|
||||
// is this actually sticking out?
|
||||
double thisheight, othersheight, partheight, cutheight;
|
||||
if ( hp )
|
||||
{
|
||||
thisheight = hs.FindLowestCeilingPoint();
|
||||
othersheight = hs.FindHighestCeilingSurrounding();
|
||||
if ( (thisheight-othersheight) >= -4. ) return;
|
||||
cutheight = min(hitz+extracut,othersheight-4);
|
||||
}
|
||||
else
|
||||
{
|
||||
thisheight = hs.FindHighestFloorPoint();
|
||||
othersheight = hs.FindLowestFloorSurrounding();
|
||||
if ( (thisheight-othersheight) <= 4. ) return;
|
||||
cutheight = max(hitz-extracut,othersheight+4);
|
||||
}
|
||||
if ( hp ) bust.cutheight = mnew?cutheight:max(bust.cutheight,cutheight);
|
||||
else bust.cutheight = mnew?cutheight:min(bust.cutheight,cutheight);
|
||||
partheight = abs(thisheight-bust.cutheight);
|
||||
// skip if we don't cut off enough
|
||||
if ( partheight < 4. ) return;
|
||||
// skip if already busted
|
||||
if ( bust.busted ) return;
|
||||
bust.acchits.Push(accdamage);
|
||||
// not enough total damage
|
||||
if ( bust.accdamage < 1000 ) return;
|
||||
// estimate sector volume
|
||||
|
|
@ -591,8 +603,18 @@ Class BusterWall : Thinker
|
|||
if ( l.v2.p.y > b.y ) a.y = l.v2.p.y;
|
||||
}
|
||||
double girthitude = (b.x-a.x)*(b.y-a.y)*partheight;
|
||||
// do a grid check to approximate "real" volume, useful for diagonal doors
|
||||
double ystep = (b.y-a.y)/64.;
|
||||
double xstep = (b.x-a.x)/64.;
|
||||
int inspot = 0, allspot = 0;
|
||||
for ( double y=a.y; y<b.y; y+=ystep ) for ( double x=a.x; x<b.x; x+=xstep )
|
||||
{
|
||||
allspot++;
|
||||
if ( level.PointInSector((x,y)) == hs ) inspot++;
|
||||
}
|
||||
girthitude = (girthitude*inspot)/allspot;
|
||||
// too fucking huge
|
||||
if ( girthitude > 16777216 ) return;
|
||||
if ( (girthitude > 16777216) || (max(partheight,max(b.x-a.x,b.y-a.y)) > 1024) ) return;
|
||||
// not strong enough to bust
|
||||
if ( bust.accdamage < girthitude/300. ) return;
|
||||
bust.busted = true;
|
||||
|
|
@ -606,39 +628,6 @@ Class BusterWall : Thinker
|
|||
if ( !rubble.IsValid() ) rubble = TexMan.CheckForTexture("LOOSERCK",TexMan.Type_Any);
|
||||
if ( !rubble.IsValid() ) rubble = TexMan.CheckForTexture("WASTE03",TexMan.Type_Any);
|
||||
if ( !rubble.IsValid() ) rubble = TexMan.CheckForTexture("SCHWAL01",TexMan.Type_Any); // Strife has a dedicated "destroyed wall" texture, nice
|
||||
hs.SetTexture(hp,rubble);
|
||||
hs.SetXScale(hp,1.);
|
||||
hs.SetYScale(hp,1.);
|
||||
hs.SetAngle(hp,0.);
|
||||
for ( int i=0; i<hs.Lines.Size(); i++ )
|
||||
{
|
||||
Line l = hs.Lines[i];
|
||||
if ( !l.sidedef[1] )
|
||||
{
|
||||
if ( hp )
|
||||
{
|
||||
// shift down
|
||||
if ( !(l.flags&Line.ML_DONTPEGBOTTOM) )
|
||||
l.sidedef[0].AddTextureYOffset(1,-abs(othersheight-thisheight)+4);
|
||||
}
|
||||
else
|
||||
{
|
||||
// shift up
|
||||
if ( l.flags&Line.ML_DONTPEGBOTTOM )
|
||||
l.sidedef[0].AddTextureYOffset(1,abs(othersheight-thisheight)-4);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
int away = 0;
|
||||
if ( l.sidedef[0].sector == hs ) away = 1;
|
||||
for ( int j=0; j<2; j++ )
|
||||
{
|
||||
if ( (j != away) && l.sidedef[j].GetTexture(hp?0:2).IsValid() ) continue;
|
||||
l.sidedef[j].SetTexture(hp?0:2,rubble);
|
||||
l.sidedef[j].SetTextureXScale(hp?0:2,1.);
|
||||
l.sidedef[j].SetTextureYScale(hp?0:2,1.);
|
||||
}
|
||||
}
|
||||
// activate all shoot/use specials (not locked) associated with this sector's two-sided lines
|
||||
for ( int i=0; i<hs.Lines.Size(); i++ )
|
||||
{
|
||||
|
|
@ -648,8 +637,17 @@ Class BusterWall : Thinker
|
|||
if ( !l.sidedef[1] ) continue;
|
||||
int away = 0;
|
||||
if ( l.sidedef[0].sector == hs ) away = 1;
|
||||
// temporarily set filler texture so switches don't play a sound
|
||||
TextureID oldtex[3][2];
|
||||
for ( int j=0; j<3; j++ ) for ( int k=0; k<2; k++ )
|
||||
{
|
||||
oldtex[j][k] = l.sidedef[k].GetTexture(j);
|
||||
l.sidedef[k].SetTexture(j,rubble);
|
||||
}
|
||||
l.Activate(instigator,away,SPAC_Use);
|
||||
l.Activate(instigator,away,SPAC_Impact);
|
||||
for ( int j=0; j<3; j++ ) for ( int k=0; k<2; k++ )
|
||||
l.sidedef[k].SetTexture(j,oldtex[j][k]);
|
||||
// clear any use/impact specials
|
||||
if ( l.Activation&(SPAC_Use|SPAC_Impact) )
|
||||
l.Activation &= ~(SPAC_Use|SPAC_Impact);
|
||||
|
|
@ -662,27 +660,62 @@ Class BusterWall : Thinker
|
|||
if ( se.GetSector() != hs ) continue;
|
||||
se.Destroy();
|
||||
}
|
||||
bust.step = (clamp((b.x-a.x)/4.,2.,32.),clamp((b.y-a.y)/4.,2.,32.),clamp((abs(othersheight-thisheight)-4)/4.,2.,32.));
|
||||
bust.step = (clamp((b.x-a.x)/4.,2.,32.),clamp((b.y-a.y)/4.,2.,32.),clamp(partheight/4.,2.,32.));
|
||||
// quakin'
|
||||
let q = Actor.Spawn("BustedQuake",(hs.centerspot.x,hs.centerspot.y,thisheight));
|
||||
q.special1 = clamp(int(girthitude**.15),1,9);
|
||||
if ( hp )
|
||||
{
|
||||
// blow up that ceiling
|
||||
double destheight = othersheight-4;
|
||||
hs.MoveCeiling(abs(destheight-thisheight),destheight,0,1,false);
|
||||
hs.MoveCeiling(abs(partheight),bust.cutheight,0,1,false);
|
||||
bust.boundsmin = (a.x,a.y,thisheight)+(1,1,1);
|
||||
bust.boundsmax = (b.x,b.y,destheight)-(1,1,1);
|
||||
bust.boundsmax = (b.x,b.y,bust.cutheight)-(1,1,1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// blow up that floor
|
||||
double destheight = othersheight+4;
|
||||
hs.MoveFloor(abs(destheight-thisheight),abs(destheight),0,-1,false,true);
|
||||
bust.boundsmin = (a.x,a.y,destheight)+(1,1,1);
|
||||
hs.MoveFloor(abs(partheight),abs(bust.cutheight),0,-1,false,true);
|
||||
bust.boundsmin = (a.x,a.y,bust.cutheight)+(1,1,1);
|
||||
bust.boundsmax = (b.x,b.y,thisheight)-(1,1,1);
|
||||
}
|
||||
bust.SpawnDebris(true);
|
||||
hs.SetTexture(hp,rubble);
|
||||
hs.SetXScale(hp,1.);
|
||||
hs.SetYScale(hp,1.);
|
||||
hs.SetAngle(hp,0.);
|
||||
for ( int i=0; i<hs.Lines.Size(); i++ )
|
||||
{
|
||||
Line l = hs.Lines[i];
|
||||
if ( !l.sidedef[1] )
|
||||
{
|
||||
if ( hp && !(l.flags&Line.ML_DONTPEGBOTTOM) )
|
||||
l.sidedef[0].AddTextureYOffset(1,-partheight); // shift down
|
||||
else if ( !hp && (l.flags&Line.ML_DONTPEGBOTTOM) )
|
||||
l.sidedef[0].AddTextureYOffset(1,partheight); // shift up
|
||||
continue;
|
||||
}
|
||||
int away = 0;
|
||||
if ( l.sidedef[0].sector == hs ) away = 1;
|
||||
for ( int j=0; j<2; j++ )
|
||||
{
|
||||
if ( l.sidedef[j].GetTexture(hp?0:2).IsValid() )
|
||||
{
|
||||
if ( j == away )
|
||||
{
|
||||
if ( hp && !(l.flags&Line.ML_DONTPEGTOP) )
|
||||
l.sidedef[j].AddTextureYOffset(0,-partheight); // shift down
|
||||
else if ( !hp && !(l.flags&Line.ML_DONTPEGBOTTOM) )
|
||||
l.sidedef[j].AddTextureYOffset(2,partheight); // shift up
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
l.sidedef[j].SetTexture(hp?0:2,rubble);
|
||||
l.sidedef[j].SetTextureXScale(hp?0:2,1.);
|
||||
l.sidedef[j].SetTextureYScale(hp?0:2,1.);
|
||||
}
|
||||
}
|
||||
}
|
||||
// damnums
|
||||
Vector3 bcenter = (bust.boundsmin+bust.boundsmax)*.5;
|
||||
if ( CVar.GetCVar('swwm_accdamage',players[consoleplayer]).GetBool() )
|
||||
|
|
@ -886,7 +919,7 @@ Class Wallbuster : SWWMWeapon
|
|||
// Wall busting
|
||||
int bustdmg = dmg;
|
||||
if ( t is 'SpreadSlugTracer' ) bustdmg = int(SpreadSlugTracer(t).penetration);
|
||||
BusterWall.Bust(t.Results,bustdmg,self,t.Results.HitVector);
|
||||
BusterWall.Bust(t.Results,bustdmg,self,t.Results.HitVector,t.Results.HitPos.z);
|
||||
for ( int i=0; i<t.ShootThroughList.Size(); i++ )
|
||||
{
|
||||
t.ShootThroughList[i].Activate(self,0,SPAC_PCross);
|
||||
|
|
|
|||
|
|
@ -217,6 +217,144 @@ Class SWWMUtility
|
|||
{
|
||||
return int(ceil(x/100.)*100.);
|
||||
}
|
||||
|
||||
static play bool IsDoorSector( Sector s, int part )
|
||||
{
|
||||
// super-easy mode: check for boss special sectors
|
||||
if ( (level.mapname ~== "E1M8") || (level.mapname ~== "E2M8") || (level.mapname ~== "E3M8")
|
||||
|| (level.mapname ~== "E4M6") || (level.mapname ~== "E4M8") || (level.mapname ~== "E5M8")
|
||||
|| (level.mapname ~== "MAP07") )
|
||||
{
|
||||
let si = level.CreateSectorTagIterator(666);
|
||||
int idx;
|
||||
while ( (idx = si.Next()) != -1 )
|
||||
if ( level.Sectors[idx] == s )
|
||||
return true;
|
||||
if ( level.mapname ~== "MAP07" )
|
||||
{
|
||||
let si2 = level.CreateSectorTagIterator(667);
|
||||
while ( (idx = si.Next()) != -1 )
|
||||
if ( level.Sectors[idx] == s )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// easy mode: check if it's already moving
|
||||
if ( part )
|
||||
{
|
||||
let ti = ThinkerIterator.Create("MovingCeiling",Thinker.STAT_SECTOREFFECT);
|
||||
MovingCeiling mc;
|
||||
while ( mc = MovingCeiling(ti.Next()) )
|
||||
if ( mc.GetSector() == s )
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
let ti = ThinkerIterator.Create("MovingFloor",Thinker.STAT_SECTOREFFECT);
|
||||
MovingFloor mf;
|
||||
while ( mf = MovingFloor(ti.Next()) )
|
||||
if ( mf.GetSector() == s )
|
||||
return true;
|
||||
}
|
||||
// hard mode: look for all lines/actors with movement specials referencing us
|
||||
for ( int i=0; i<level.Lines.Size(); i++ )
|
||||
{
|
||||
Line l = level.Lines[i];
|
||||
if ( !l.special ) continue;
|
||||
if ( (part && (l.special >= 10) && (l.special <= 13))
|
||||
|| (!part && (l.special >= 20) && (l.special <= 25))
|
||||
|| (!part && (l.special == 28))
|
||||
|| ((l.special >= 29) && (l.special <= 30))
|
||||
|| (!part && (l.special >= 35) && (l.special <= 37))
|
||||
|| (part && (l.special >= 40) && (l.special <= 45))
|
||||
|| (!part && (l.special == 46))
|
||||
|| (part && (l.special == 47))
|
||||
|| (!part && (l.special >= 60) && (l.special <= 68))
|
||||
|| (part && (l.special == 69))
|
||||
|| ((l.special >= 94) && (l.special <= 96))
|
||||
|| (part && (l.special == 97))
|
||||
|| (!part && (l.special == 99))
|
||||
|| (part && (l.special == 104))
|
||||
|| (part && (l.special >= 105) && (l.special <= 106))
|
||||
|| (part && (l.special >= 168) && (l.special <= 169))
|
||||
|| (!part && (l.special == 172))
|
||||
|| (part && (l.special >= 192) && (l.special <= 199))
|
||||
|| (!part && (l.special == 200))
|
||||
|| (part && (l.special >= 201) && (l.special <= 202))
|
||||
|| (!part && (l.special == 203))
|
||||
|| (part && (l.special == 205))
|
||||
|| (!part && (l.special >= 206) && (l.special <= 207))
|
||||
|| (!part && (l.special == 228))
|
||||
|| (!part && (l.special >= 230) && (l.special <= 231))
|
||||
|| (!part && (l.special >= 238) && (l.special <= 242))
|
||||
|| ((l.special >= 245) && (l.special <= 247))
|
||||
|| (part && (l.special == 249))
|
||||
|| (!part && (l.special >= 250) && (l.special <= 251))
|
||||
|| (part && (l.special >= 251) && (l.special <= 255))
|
||||
|| (!part && (l.special >= 256) && (l.special <= 261))
|
||||
|| (part && (l.special >= 262) && (l.special <= 269))
|
||||
|| (!part && (l.special == 275))
|
||||
|| (part && (l.special == 276))
|
||||
|| (!part && (l.special == 279))
|
||||
|| (part && (l.special == 280)) )
|
||||
{
|
||||
let si = level.CreateSectorTagIterator(l.Args[0],l);
|
||||
int idx;
|
||||
while ( (idx = si.Next()) != -1 )
|
||||
if ( level.Sectors[idx] == s )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
let ti = ThinkerIterator.Create("Actor");
|
||||
Actor a;
|
||||
while ( a = Actor(ti.Next()) )
|
||||
{
|
||||
if ( !a.special || !a.Args[0] ) continue;
|
||||
if ( (part && (a.special >= 10) && (a.special <= 13))
|
||||
|| (!part && (a.special >= 20) && (a.special <= 25))
|
||||
|| (!part && (a.special == 28))
|
||||
|| ((a.special >= 29) && (a.special <= 30))
|
||||
|| (!part && (a.special >= 35) && (a.special <= 37))
|
||||
|| (part && (a.special >= 40) && (a.special <= 45))
|
||||
|| (!part && (a.special == 46))
|
||||
|| (part && (a.special == 47))
|
||||
|| (!part && (a.special >= 60) && (a.special <= 68))
|
||||
|| (part && (a.special == 69))
|
||||
|| ((a.special >= 94) && (a.special <= 96))
|
||||
|| (part && (a.special == 97))
|
||||
|| (!part && (a.special == 99))
|
||||
|| (part && (a.special == 104))
|
||||
|| (part && (a.special >= 105) && (a.special <= 106))
|
||||
|| (part && (a.special >= 168) && (a.special <= 169))
|
||||
|| (!part && (a.special == 172))
|
||||
|| (part && (a.special >= 192) && (a.special <= 199))
|
||||
|| (!part && (a.special == 200))
|
||||
|| (part && (a.special >= 201) && (a.special <= 202))
|
||||
|| (!part && (a.special == 203))
|
||||
|| (part && (a.special == 205))
|
||||
|| (!part && (a.special >= 206) && (a.special <= 207))
|
||||
|| (!part && (a.special == 228))
|
||||
|| (!part && (a.special >= 230) && (a.special <= 231))
|
||||
|| (!part && (a.special >= 238) && (a.special <= 242))
|
||||
|| ((a.special >= 245) && (a.special <= 247))
|
||||
|| (part && (a.special == 249))
|
||||
|| (!part && (a.special >= 250) && (a.special <= 251))
|
||||
|| (part && (a.special >= 251) && (a.special <= 255))
|
||||
|| (!part && (a.special >= 256) && (a.special <= 261))
|
||||
|| (part && (a.special >= 262) && (a.special <= 269))
|
||||
|| (!part && (a.special == 275))
|
||||
|| (part && (a.special == 276))
|
||||
|| (!part && (a.special == 279))
|
||||
|| (part && (a.special == 280)) )
|
||||
{
|
||||
let si = level.CreateSectorTagIterator(a.Args[0]);
|
||||
int idx;
|
||||
while ( (idx = si.Next()) != -1 )
|
||||
if ( level.Sectors[idx] == s )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Stats
|
||||
|
|
|
|||
|
|
@ -823,7 +823,7 @@ Class Demolitionist : PlayerPawn
|
|||
}
|
||||
if ( dodge == (0,0,0) ) dodge.xy = RotateVector((1,0),angle);
|
||||
if ( (waterlevel < 2) && !(bFly || bFlyCheat) )
|
||||
dodge.z += .15;
|
||||
dodge.z += (player.cmd.buttons&BT_CROUCH)?.05:.15;
|
||||
if ( (dodge.length() > 0) && (dashcooldown <= 0) && (dashfuel > 20.) && player.cmd.buttons&BT_USER2 && (player.onground || level.IsJumpingAllowed()) )
|
||||
{
|
||||
dashdir = dodge.unit();
|
||||
|
|
|
|||
|
|
@ -678,7 +678,7 @@ Class SaltBeam : Actor
|
|||
}
|
||||
if ( t.Results.HitType != TRACE_HitNone )
|
||||
{
|
||||
if ( args[1] ) BusterWall.Bust(t.Results,85+Accuracy*10,target,x);
|
||||
if ( args[1] ) BusterWall.Bust(t.Results,85+Accuracy*10,target,x,t.Results.HitPos.z);
|
||||
if ( t.Results.HitType == TRACE_HitActor )
|
||||
{
|
||||
SWWMHandler.DoKnockback(t.Results.HitActor,x,25000);
|
||||
|
|
@ -1515,7 +1515,7 @@ Class TheBall : Actor
|
|||
if ( special1 == 1 )
|
||||
{
|
||||
int dmg = int(oldvel.length()*4.2+heat*80);
|
||||
BusterWall.Bust(faketracer.Results,dmg,target,oldvel.unit());
|
||||
BusterWall.Bust(faketracer.Results,dmg,target,oldvel.unit(),pos.z+Height/2.);
|
||||
}
|
||||
// undo the bounce, we need to hook in our own
|
||||
vel = oldvel;
|
||||
|
|
|
|||
|
|
@ -87,8 +87,8 @@ Class SilverImpact : Actor
|
|||
return;
|
||||
}
|
||||
A_StartSound("silverbullet/hit",CHAN_VOICE,CHANF_DEFAULT,1.,.7);
|
||||
A_SprayDecal("BigBulletChip",-20);
|
||||
A_SprayDecal("HugeWallCrack",-20);
|
||||
A_SprayDecal("BigBulletChip",-64);
|
||||
A_SprayDecal("HugeWallCrack",-64);
|
||||
int numpt = Random[Silverbullet](15,25);
|
||||
Vector3 x = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
|
|
@ -125,6 +125,163 @@ Class SilverImpact : Actor
|
|||
}
|
||||
}
|
||||
|
||||
Class WallPenetrate
|
||||
{
|
||||
Vector3 hitpos, hitdir, hitnormal;
|
||||
}
|
||||
|
||||
Class AuxiliarySilverBulletTracer : LineTracer
|
||||
{
|
||||
override ETraceStatus TraceCallback()
|
||||
{
|
||||
if ( Results.HitType == TRACE_HitActor ) return TRACE_Skip;
|
||||
else if ( (Results.HitType == TRACE_HitWall) && (Results.Tier == TIER_Middle) )
|
||||
{
|
||||
if ( !Results.HitLine.sidedef[1] || (Results.HitLine.Flags&(Line.ML_BlockHitscan|Line.ML_BlockEverything)) )
|
||||
return TRACE_Stop;
|
||||
return TRACE_Skip;
|
||||
}
|
||||
return TRACE_Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class SilverBulletTracer : SpreadSlugTracer
|
||||
{
|
||||
Array<WallPenetrate> WallPenetrateList;
|
||||
|
||||
override ETraceStatus TraceCallback()
|
||||
{
|
||||
// liquid splashes
|
||||
if ( Results.CrossedWater )
|
||||
{
|
||||
let hl = new("WaterHit");
|
||||
hl.sect = Results.CrossedWater;
|
||||
hl.hitpos = Results.CrossedWaterPos;
|
||||
WaterHitList.Push(hl);
|
||||
}
|
||||
else if ( Results.Crossed3DWater )
|
||||
{
|
||||
let hl = new("WaterHit");
|
||||
hl.sect = Results.Crossed3DWater;
|
||||
hl.hitpos = Results.Crossed3DWaterPos;
|
||||
WaterHitList.Push(hl);
|
||||
}
|
||||
if ( Results.HitType == TRACE_HitActor )
|
||||
{
|
||||
if ( Results.HitActor == ignoreme ) return TRACE_Skip;
|
||||
if ( Results.HitActor.bSHOOTABLE )
|
||||
{
|
||||
let ent = new("HitListEntry");
|
||||
ent.hitactor = Results.HitActor;
|
||||
ent.hitlocation = Results.HitPos;
|
||||
ent.x = Results.HitVector;
|
||||
ent.hitdamage = min(Results.HitActor.health+int(Results.HitActor.GetSpawnHealth()*gameinfo.gibfactor),int(penetration));
|
||||
int killdamage = min(Results.HitActor.health,int(penetration));
|
||||
hitlist.Push(ent);
|
||||
penetration = max(0,penetration-killdamage);
|
||||
if ( penetration <= 0 ) return TRACE_Stop;
|
||||
return TRACE_Skip;
|
||||
}
|
||||
return TRACE_Skip;
|
||||
}
|
||||
else if ( (Results.HitType == TRACE_HitWall) && (Results.Tier == TIER_Middle) )
|
||||
{
|
||||
if ( !Results.HitLine.sidedef[1] || (Results.HitLine.Flags&(Line.ML_BlockHitscan|Line.ML_BlockEverything)) )
|
||||
{
|
||||
for ( int i=1; i<int(penetration/16); i++ )
|
||||
{
|
||||
Vector3 ofs = level.Vec3Offset(Results.HitPos,Results.HitVector*i);
|
||||
if ( level.IsPointInLevel(ofs) )
|
||||
{
|
||||
penetration = max(0,penetration-i*8);
|
||||
let wp = new("WallPenetrate");
|
||||
wp.hitpos = Results.HitPos;
|
||||
wp.hitdir = Results.HitVector;
|
||||
wp.hitnormal = (-Results.HitLine.delta.y,Results.HitLine.delta.x,0).unit();
|
||||
if ( !Results.Side ) wp.hitnormal *= -1;
|
||||
WallPenetrateList.Push(wp);
|
||||
if ( Results.HitLine.sidedef[1] )
|
||||
ShootThroughList.Push(Results.HitLine);
|
||||
// trace backwards to find exit surface
|
||||
let at = new("AuxiliarySilverBulletTracer");
|
||||
at.Trace(ofs,level.PointInSector(ofs.xy),-Results.HitVector,2.,TRACE_HitSky);
|
||||
if ( at.Results.HitType != TRACE_HitNone )
|
||||
{
|
||||
let wp2 = new("WallPenetrate");
|
||||
wp2.hitpos = at.Results.HitPos;
|
||||
wp2.hitdir = at.Results.HitVector;
|
||||
if ( at.Results.HitType == TRACE_HitWall )
|
||||
{
|
||||
wp2.hitnormal = (-at.Results.HitLine.delta.y,at.Results.HitLine.delta.x,0).unit();
|
||||
if ( !at.Results.Side ) wp2.hitnormal *= -1;
|
||||
if ( at.Results.HitLine.sidedef[1] )
|
||||
ShootThroughList.Push(at.Results.HitLine);
|
||||
}
|
||||
else if ( at.Results.HitType == TRACE_HitCeiling )
|
||||
wp2.hitnormal = at.Results.HitSector.ceilingplane.Normal;
|
||||
else if ( at.Results.HitType == TRACE_HitFloor )
|
||||
wp2.hitnormal = at.Results.HitSector.floorplane.Normal;
|
||||
WallPenetrateList.Push(wp2);
|
||||
}
|
||||
return TRACE_Skip;
|
||||
}
|
||||
}
|
||||
return TRACE_Stop;
|
||||
}
|
||||
ShootThroughList.Push(Results.HitLine);
|
||||
return TRACE_Skip;
|
||||
}
|
||||
else if ( Results.HitType != TRACE_HitNone )
|
||||
{
|
||||
for ( int i=1; i<int(penetration/16); i++ )
|
||||
{
|
||||
Vector3 ofs = level.Vec3Offset(Results.HitPos,Results.HitVector*i);
|
||||
if ( level.IsPointInLevel(ofs) )
|
||||
{
|
||||
penetration = max(0,penetration-i*8);
|
||||
let wp = new("WallPenetrate");
|
||||
wp.hitpos = Results.HitPos;
|
||||
wp.hitdir = Results.HitVector;
|
||||
if ( Results.HitType == TRACE_HitWall )
|
||||
{
|
||||
wp.hitnormal = (-Results.HitLine.delta.y,Results.HitLine.delta.x,0).unit();
|
||||
if ( !Results.Side ) wp.hitnormal *= -1;
|
||||
ShootThroughList.Push(Results.HitLine);
|
||||
}
|
||||
else if ( Results.HitType == TRACE_HitCeiling )
|
||||
wp.hitnormal = Results.HitSector.ceilingplane.Normal;
|
||||
else if ( Results.HitType == TRACE_HitFloor )
|
||||
wp.hitnormal = Results.HitSector.floorplane.Normal;
|
||||
WallPenetrateList.Push(wp);
|
||||
// trace backwards to find exit surface
|
||||
let at = new("AuxiliarySilverBulletTracer");
|
||||
at.Trace(ofs,level.PointInSector(ofs.xy),-Results.HitVector,2.,TRACE_HitSky);
|
||||
if ( at.Results.HitType != TRACE_HitNone )
|
||||
{
|
||||
let wp2 = new("WallPenetrate");
|
||||
wp2.hitpos = at.Results.HitPos;
|
||||
wp2.hitdir = at.Results.HitVector;
|
||||
if ( at.Results.HitType == TRACE_HitWall )
|
||||
{
|
||||
wp2.hitnormal = (-at.Results.HitLine.delta.y,at.Results.HitLine.delta.x,0).unit();
|
||||
if ( !at.Results.Side ) wp2.hitnormal *= -1;
|
||||
if ( at.Results.HitLine.sidedef[1] )
|
||||
ShootThroughList.Push(at.Results.HitLine);
|
||||
}
|
||||
else if ( at.Results.HitType == TRACE_HitCeiling )
|
||||
wp2.hitnormal = at.Results.HitSector.ceilingplane.Normal;
|
||||
else if ( at.Results.HitType == TRACE_HitFloor )
|
||||
wp2.hitnormal = at.Results.HitSector.floorplane.Normal;
|
||||
WallPenetrateList.Push(wp2);
|
||||
}
|
||||
return TRACE_Skip;
|
||||
}
|
||||
}
|
||||
}
|
||||
return TRACE_Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class SilverBullet : SWWMWeapon
|
||||
{
|
||||
bool chambered, fired;
|
||||
|
|
@ -226,7 +383,7 @@ Class SilverBullet : SWWMWeapon
|
|||
else Shader.SetEnabled(players[consoleplayer],"SilverScope",false);
|
||||
}
|
||||
|
||||
action void ProcessTraceHit( SpreadgunTracer t, Vector3 origin, Vector3 dir )
|
||||
action void ProcessTraceHit( SilverBulletTracer t, Vector3 origin, Vector3 dir )
|
||||
{
|
||||
for ( int i=0; i<t.ShootThroughList.Size(); i++ )
|
||||
{
|
||||
|
|
@ -269,6 +426,15 @@ Class SilverBullet : SWWMWeapon
|
|||
p.target = self;
|
||||
}
|
||||
}
|
||||
for ( int i=0; i<t.WallPenetrateList.Size(); i++ )
|
||||
{
|
||||
Vector3 hitpos = t.WallPenetrateList[i].hitpos;
|
||||
Vector3 hitnormal = t.WallPenetrateList[i].hitnormal;
|
||||
let p = Spawn("SilverImpact",hitpos+hitnormal*4);
|
||||
p.angle = atan2(hitnormal.y,hitnormal.x);
|
||||
p.pitch = asin(-hitnormal.z);
|
||||
p.target = self;
|
||||
}
|
||||
if ( (t.Results.HitType != TRACE_HitNone) && (t.Results.HitType != TRACE_HasHitSky) && (t.Results.HitType != TRACE_HitActor) )
|
||||
{
|
||||
Vector3 hitnormal = -t.Results.HitVector;
|
||||
|
|
@ -316,12 +482,13 @@ Class SilverBullet : SWWMWeapon
|
|||
Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+1*y-1*z);
|
||||
Vector3 x2, y2, z2;
|
||||
[x2, y2, z2] = swwm_CoordUtil.GetAxes(BulletSlope(),angle,roll);
|
||||
SpreadSlugTracer sst = new("SpreadSlugTracer");
|
||||
SilverBulletTracer sst = new("SilverBulletTracer");
|
||||
sst.ignoreme = self;
|
||||
sst.penetration = 2000.;
|
||||
sst.hitlist.Clear();
|
||||
sst.shootthroughlist.Clear();
|
||||
sst.waterhitlist.Clear();
|
||||
sst.wallpenetratelist.Clear();
|
||||
sst.Trace(origin,level.PointInSector(origin.xy),x2,20000.,TRACE_HitSky);
|
||||
ProcessTraceHit(sst,origin,x2);
|
||||
for ( int i=0; i<10; i++ )
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue