Melee tweaks.
This commit is contained in:
parent
7ad3295046
commit
9ea1ce6210
8 changed files with 118 additions and 62 deletions
|
|
@ -303,10 +303,75 @@ Class MHitList
|
|||
Vector3 dir, pos;
|
||||
}
|
||||
|
||||
Class MeleeTracer : LineTracer
|
||||
{
|
||||
Actor ignoreme;
|
||||
Array<MHitList> hits;
|
||||
Vector3 x; // used to get closest hit to center
|
||||
bool dorip;
|
||||
|
||||
override ETraceStatus TraceCallback()
|
||||
{
|
||||
if ( Results.HitType == TRACE_HitActor )
|
||||
{
|
||||
if ( !Results.HitActor.bSHOOTABLE
|
||||
|| (Results.HitActor == ignoreme)
|
||||
|| Results.HitActor.FindInventory("ParriedBuff") ) return TRACE_Skip;
|
||||
bool addme = true;
|
||||
for ( int k=0; k<hits.Size(); k++ )
|
||||
{
|
||||
if ( hits[k].a != Results.HitActor ) continue;
|
||||
if ( (hits[k].dir dot x) < (Results.HitVector dot x) )
|
||||
{
|
||||
// closer to centerpoint
|
||||
hits[k].dir = Results.HitVector;
|
||||
hits[k].pos = Results.HitPos;
|
||||
}
|
||||
addme = false;
|
||||
break;
|
||||
}
|
||||
if ( addme )
|
||||
{
|
||||
let h = new("MHitList");
|
||||
h.a = Results.HitActor;
|
||||
h.dir = Results.HitVector;
|
||||
h.pos = Results.HitPos;
|
||||
hits.Push(h);
|
||||
}
|
||||
return dorip?TRACE_Skip:TRACE_Stop;
|
||||
}
|
||||
if ( Results.HitType == TRACE_HitWall )
|
||||
{
|
||||
if ( 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extend Class SWWMWeapon
|
||||
{
|
||||
Actor pfield; // instance of parry field for current melee attack
|
||||
bool wallponch; // is punching a wall (for activation checks)
|
||||
transient MeleeTracer mt;
|
||||
transient UseLineTracer ut;
|
||||
|
||||
// melee attack flags
|
||||
enum EMeleeFlags
|
||||
{
|
||||
MELEE_Rip = 1, // trace will continue instead of stopping at the first hit (useful for swords)
|
||||
MELEE_ForceSound = 2, // force the use of the provided hit sound while raging
|
||||
MELEE_FleshSound = 4, // hit sound has a "flesh" variant (will append "f" suffix to hitsound string)
|
||||
MELEE_ForceBust = 8, // bust walls even without Omnibusting enabled
|
||||
MELEE_Vertical = 16, // ring is widened vertically, rather than horizontally
|
||||
MELEE_Wider = 32, // ring is widened by 2.5x rather than 1.5x
|
||||
MELEE_ExtraWide = 64 // if Wider is also specified, widen by 5x, otherwise widen by 3x
|
||||
};
|
||||
|
||||
action void A_Parry( int duration )
|
||||
{
|
||||
|
|
@ -322,91 +387,75 @@ extend Class SWWMWeapon
|
|||
GiveInventory("ParryDamageChecker",1); // need this so parried projectiles deal extra damage
|
||||
}
|
||||
// multi-hit cone rather than the usual one-hit arc, more fun
|
||||
private action bool TryMelee( double spread, int dmg, String hitsound = "", double rangemul = 1., double kickmul = 1. )
|
||||
private action bool TryMelee( double spread, int dmg, String hitsound, double rangemul, double kickmul, int flags )
|
||||
{
|
||||
Vector3 x, y, z, dir;
|
||||
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
|
||||
Vector3 origin = Vec2OffsetZ(0,0,player.viewz);
|
||||
Array<MHitList> hits;
|
||||
hits.Clear();
|
||||
FLineTraceData d;
|
||||
if ( !invoker.mt ) invoker.mt = new("MeleeTracer");
|
||||
let mt = invoker.mt; // for convenience
|
||||
mt.ignoreme = self;
|
||||
mt.hits.Clear();
|
||||
mt.dorip = !!(flags&MELEE_Rip);
|
||||
int rings = 1;
|
||||
double step = spread/20.;
|
||||
double range = 1.5*DEFMELEERANGE*rangemul;
|
||||
bool raging = CountInv("RagekitPower");
|
||||
double widemul = (flags&MELEE_ExtraWide)?(flags&MELEE_Wider)?5:3:(flags&MELEE_Wider)?2.5:1.5;
|
||||
for ( double i=0; i<spread; i+=step )
|
||||
{
|
||||
for ( int j=0; j<360; j+=(360/rings) )
|
||||
{
|
||||
dir = (x+y*cos(j)*1.5*i+z*sin(j)*i).unit(); // wide ring
|
||||
LineTrace(atan2(dir.y,dir.x),range,asin(-dir.z),TRF_ABSPOSITION,origin.z,origin.x,origin.y,d);
|
||||
if ( d.HitType != TRACE_HitActor ) continue;
|
||||
if ( d.HitActor.FindInventory("ParriedBuff") ) continue;
|
||||
bool addme = true;
|
||||
for ( int k=0; k<hits.Size(); k++ )
|
||||
{
|
||||
if ( hits[k].a != d.HitActor ) continue;
|
||||
if ( (hits[k].dir dot x) < (dir dot x) )
|
||||
{
|
||||
// closer to centerpoint
|
||||
hits[k].dir = dir;
|
||||
hits[k].pos = d.HitLocation;
|
||||
}
|
||||
addme = false;
|
||||
break;
|
||||
}
|
||||
if ( !addme ) continue;
|
||||
let nhit = new("MHitList");
|
||||
nhit.a = d.HitActor;
|
||||
nhit.dir = dir;
|
||||
nhit.pos = d.HitLocation;
|
||||
hits.Push(nhit);
|
||||
// wide ring
|
||||
if ( flags&MELEE_Vertical ) dir = (x+y*cos(j)*i+z*sin(j)*widemul*i).unit();
|
||||
else dir = (x+y*cos(j)*widemul*i+z*sin(j)*i).unit();
|
||||
mt.Trace(origin,level.PointInSector(origin.xy),dir,range,0);
|
||||
}
|
||||
rings += 5;
|
||||
}
|
||||
// no targets
|
||||
if ( hits.Size() <= 0 ) return false;
|
||||
if ( mt.hits.Size() <= 0 ) return false;
|
||||
bool blooded = false;
|
||||
bool bloodless = false;
|
||||
int flg = DMG_THRUSTLESS|DMG_INFLICTOR_IS_PUFF;
|
||||
if ( raging ) flg |= DMG_FOILINVUL;
|
||||
int quakin = raging?8:2;
|
||||
double diff = 0.;
|
||||
for ( int i=0; i<hits.Size(); i++ )
|
||||
for ( int i=0; i<mt.hits.Size(); i++ )
|
||||
{
|
||||
diff += deltaangle(self.angle,AngleTo(hits[i].a));
|
||||
SWWMUtility.DoKnockback(hits[i].a,hits[i].dir,dmg*2000*kickmul);
|
||||
diff += deltaangle(self.angle,AngleTo(mt.hits[i].a));
|
||||
SWWMUtility.DoKnockback(mt.hits[i].a,mt.hits[i].dir,dmg*2000*kickmul);
|
||||
// lol oops
|
||||
if ( !hits[i].a.bDORMANT ) hits[i].a.DaggerAlert(self);
|
||||
if ( !hits[i].a.bNOBLOOD && !hits[i].a.bDORMANT && (raging || !hits[i].a.bINVULNERABLE) ) blooded = true;
|
||||
if ( !mt.hits[i].a.bDORMANT ) mt.hits[i].a.DaggerAlert(self);
|
||||
if ( !mt.hits[i].a.bNOBLOOD && !mt.hits[i].a.bDORMANT && (raging || !mt.hits[i].a.bINVULNERABLE) ) blooded = true;
|
||||
else bloodless = true;
|
||||
let p = SWWMPuff.Setup(hits[i].pos,hits[i].dir,invoker,self,hits[i].a);
|
||||
int newdmg = hits[i].a.DamageMobj(p,self,dmg,'Melee',flg);
|
||||
let p = SWWMPuff.Setup(mt.hits[i].pos,mt.hits[i].dir,invoker,self,mt.hits[i].a);
|
||||
int newdmg = mt.hits[i].a.DamageMobj(p,self,dmg,'Melee',flg);
|
||||
// things can instantly cease to exist after taking damage (wow)
|
||||
if ( hits[i].a )
|
||||
if ( mt.hits[i].a )
|
||||
{
|
||||
if ( hits[i].a.player ) hits[i].a.A_QuakeEx(quakin,quakin,quakin,6,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.125*quakin);
|
||||
if ( !hits[i].a.bNOBLOOD && !hits[i].a.bDORMANT && (raging || !hits[i].a.bINVULNERABLE) )
|
||||
if ( mt.hits[i].a.player ) mt.hits[i].a.A_QuakeEx(quakin,quakin,quakin,6,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.125*quakin);
|
||||
if ( !mt.hits[i].a.bNOBLOOD && !mt.hits[i].a.bDORMANT && (raging || !mt.hits[i].a.bINVULNERABLE) )
|
||||
{
|
||||
hits[i].a.TraceBleed(newdmg,invoker);
|
||||
hits[i].a.SpawnBlood(hits[i].pos,atan2(hits[i].dir.y,hits[i].dir.x)+180,newdmg);
|
||||
mt.hits[i].a.TraceBleed(newdmg,invoker);
|
||||
mt.hits[i].a.SpawnBlood(mt.hits[i].pos,atan2(mt.hits[i].dir.y,mt.hits[i].dir.x)+180,newdmg);
|
||||
}
|
||||
else
|
||||
{
|
||||
let p = Spawn(raging?"BigPunchImpact":"PunchImpact",hits[i].pos);
|
||||
p.angle = atan2(hits[i].dir.y,hits[i].dir.x);
|
||||
let p = Spawn(raging?"BigPunchImpact":"PunchImpact",mt.hits[i].pos);
|
||||
p.angle = atan2(mt.hits[i].dir.y,mt.hits[i].dir.x);
|
||||
}
|
||||
}
|
||||
if ( raging )
|
||||
{
|
||||
let ps = Spawn("BigPunchSplash",hits[i].pos);
|
||||
let ps = Spawn("BigPunchSplash",mt.hits[i].pos);
|
||||
ps.target = self;
|
||||
ps.special1 = dmg;
|
||||
}
|
||||
}
|
||||
self.angle += clamp(diff/hits.Size(),-5.,5.); // averaged reorient
|
||||
self.angle += clamp(diff/mt.hits.Size(),-5.,5.); // averaged reorient
|
||||
A_QuakeEx(quakin/2,quakin/2,quakin/2,3,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.06*quakin);
|
||||
if ( raging )
|
||||
if ( raging && !(flags&MELEE_ForceSound) )
|
||||
{
|
||||
if ( blooded ) A_StartSound("pusher/altmeat",CHAN_WEAPON,CHANF_OVERLAP);
|
||||
if ( bloodless ) A_StartSound("pusher/althit",CHAN_WEAPON,CHANF_OVERLAP);
|
||||
|
|
@ -416,21 +465,27 @@ extend Class SWWMWeapon
|
|||
if ( blooded ) A_StartSound("demolitionist/punchf",CHAN_WEAPON,CHANF_OVERLAP);
|
||||
if ( bloodless ) A_StartSound("demolitionist/punch",CHAN_WEAPON,CHANF_OVERLAP);
|
||||
}
|
||||
else if ( flags&MELEE_FleshSound )
|
||||
{
|
||||
if ( blooded ) A_StartSound(hitsound.."f",CHAN_WEAPON,CHANF_OVERLAP);
|
||||
if ( bloodless ) A_StartSound(hitsound,CHAN_WEAPON,CHANF_OVERLAP);
|
||||
}
|
||||
else A_StartSound(hitsound,CHAN_WEAPON,CHANF_OVERLAP);
|
||||
A_AlertMonsters(swwm_uncapalert?0:300);
|
||||
A_BumpFOV(.96);
|
||||
return true;
|
||||
}
|
||||
action void A_Melee( int dmg = 40, String hitsound = "", double rangemul = 1., double spreadmul = 1., double kickmul = 1. )
|
||||
action bool A_Melee( int dmg = 40, String hitsound = "", double rangemul = 1., double spreadmul = 1., double kickmul = 1., int flags = 0 )
|
||||
{
|
||||
let raging = RagekitPower(FindInventory("RagekitPower"));
|
||||
if ( raging ) rangemul += .2;
|
||||
Vector3 origin = Vec3Offset(0,0,player.viewheight);
|
||||
Vector3 dir = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),sin(-pitch));
|
||||
// check for usables
|
||||
let ut = new("UseLineTracer");
|
||||
if ( !invoker.ut ) invoker.ut = new("UseLineTracer");
|
||||
let ut = invoker.ut; // for convenience
|
||||
ut.uses.Clear();
|
||||
ut.Trace(origin,CurSector,dir,DEFMELEERANGE*rangemul,0);
|
||||
ut.Trace(origin,level.PointInSector(origin.xy),dir,DEFMELEERANGE*rangemul,0);
|
||||
invoker.wallponch = true;
|
||||
for ( int i=0; i<ut.uses.Size(); i++ )
|
||||
{
|
||||
|
|
@ -453,14 +508,14 @@ extend Class SWWMWeapon
|
|||
invoker.wallponch = false;
|
||||
// check for shootables
|
||||
SWWMBulletTrail.DoTrail(self,origin,dir,DEFMELEERANGE*rangemul,0);
|
||||
if ( TryMelee((raging?.3:.2)*spreadmul,dmg,hitsound,rangemul,kickmul) )
|
||||
return;
|
||||
if ( TryMelee((raging?.3:.2)*spreadmul,dmg,hitsound,rangemul,kickmul,flags) )
|
||||
return true;
|
||||
// check for walls instead
|
||||
FTranslatedLineTarget t;
|
||||
double slope = AimLineAttack(angle,DEFMELEERANGE*rangemul,t,0.,ALF_CHECK3D);
|
||||
FLineTraceData d;
|
||||
LineTrace(angle,DEFMELEERANGE*rangemul,slope,TRF_THRUACTORS,player.viewheight,data:d);
|
||||
if ( d.HitType == TRACE_HitNone ) return;
|
||||
if ( d.HitType == TRACE_HitNone ) return false;
|
||||
Vector3 HitNormal = -d.HitDir;
|
||||
if ( d.HitType == TRACE_HitFloor )
|
||||
{
|
||||
|
|
@ -491,9 +546,10 @@ extend Class SWWMWeapon
|
|||
int quakin = raging?4:1;
|
||||
A_QuakeEx(quakin,quakin,quakin,3,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.12*quakin);
|
||||
A_BumpFOV(.98);
|
||||
A_StartSound(raging?"pusher/althit":(hitsound!="")?hitsound:"demolitionist/punch",CHAN_WEAPON,CHANF_OVERLAP);
|
||||
A_StartSound((raging&&!(flags&MELEE_ForceSound))?"pusher/althit":(hitsound!="")?hitsound:"demolitionist/punch",CHAN_WEAPON,CHANF_OVERLAP);
|
||||
A_AlertMonsters(swwm_uncapalert?0:100);
|
||||
if ( raging ) raging.DoHitFX();
|
||||
if ( swwm_omnibust ) BusterWall.BustLinetrace(d,raging?(dmg*8):dmg,self,d.HitDir,d.HitLocation.z);
|
||||
if ( (flags&MELEE_ForceBust) || swwm_omnibust ) BusterWall.BustLinetrace(d,raging?(dmg*8):dmg,self,d.HitDir,d.HitLocation.z);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -554,7 +554,7 @@ Class Ynykron : SWWMWeapon
|
|||
XZW9 AB 2;
|
||||
XZW9 C 1 A_Parry(9);
|
||||
XZW9 DE 1;
|
||||
XZW9 F 1 A_Melee(100,"demolitionist/whitl",1.5,1.6,1.7);
|
||||
XZW9 F 1 A_Melee(100,"demolitionist/whitl",1.5,1.6,1.7,MELEE_Wider);
|
||||
XZW9 GHIJK 1;
|
||||
XZW9 LMNO 2;
|
||||
XZW9 P 2 A_StartSound("ynykron/meleeend",CHAN_WEAPON,CHANF_OVERLAP);
|
||||
|
|
|
|||
|
|
@ -1496,7 +1496,7 @@ Class SilverBullet : SWWMWeapon
|
|||
XZW6 IJK 3;
|
||||
XZW6 L 1 A_Parry(9);
|
||||
XZW6 MN 1;
|
||||
XZW6 O 1 A_Melee(90,"demolitionist/whitl",1.6,2.,2.);
|
||||
XZW6 O 1 A_Melee(90,"demolitionist/whitl",1.6,2.,2.,MELEE_Wider);
|
||||
XZW6 PQ 1;
|
||||
XZW6 RST 2;
|
||||
XZW6 U 3 A_StartSound("silverbullet/meleeend",CHAN_WEAPON,CHANF_OVERLAP);
|
||||
|
|
@ -1513,7 +1513,7 @@ Class SilverBullet : SWWMWeapon
|
|||
XZWC IJK 3;
|
||||
XZWC L 1 A_Parry(9);
|
||||
XZWC MN 1;
|
||||
XZWC O 1 A_Melee(90,"demolitionist/whitl",1.6,2.,2.);
|
||||
XZWC O 1 A_Melee(90,"demolitionist/whitl",1.6,2.,2.,MELEE_Wider);
|
||||
XZWC PQ 1;
|
||||
XZWC RST 2;
|
||||
XZWC U 3 A_StartSound("silverbullet/meleeend",CHAN_WEAPON,CHANF_OVERLAP);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue