Melee tweaks.

This commit is contained in:
Mari the Deer 2022-04-26 18:52:56 +02:00
commit c2d142cbb0
8 changed files with 118 additions and 62 deletions

View file

@ -1738,7 +1738,7 @@ SWWM_LORETXT_ITAMEXHAMMER =
"\n"
"\cfPrimary Fire:\c- Rapid swings, from side to side. Good for quickly plowing through enemy hordes.\n"
"\n"
"\cfSecondary Fire:\c- Hold to ready up a vertical swing, release to let the hammer drop on whatever poor fool is standing in front of you. The longer you hold, the stronger the hit.\n"
"\cfSecondary Fire:\c- Hold to ready up a vertical swing, release to let the hammer drop on whatever poor fool is standing in front of you. The longer you hold, the stronger the hit. This attack can potentially break down doors, among other things.\n"
"\n"
"\cfTertiary Fire:\c- Hold to ready up a wide horizontal swing, release to perform a potent spin attack, smashing away everything around you. Consecutive presses of tertiary fire while spinning will keep the motion going for longer. Being a combat robot, you should be free from any motion sickness that a human would typically develop while performing this action.\n"
"\n"

View file

@ -1611,7 +1611,7 @@ SWWM_LORETXT_ITAMEXHAMMER =
"\n"
"\cfFuego Primario:\c- Golpes rápidos, de lado a lado. Bueno para cargar a través de hordas enemigas.\n"
"\n"
"\cfFuego Secundario:\c- Mantén para preparar un golpe vertical, suelta para dejar caer el martillo sobre cualquier pobre insensato que se te ponga delante. Cuanto más lo mantengas, más fuerte será el golpe.\n"
"\cfFuego Secundario:\c- Mantén para preparar un golpe vertical, suelta para dejar caer el martillo sobre cualquier pobre insensato que se te ponga delante. Cuanto más lo mantengas, más fuerte será el golpe. Este ataque puede potencialmente echar abajo puertas, entre otras cosas.\n"
"\n"
"\cfFuego Terciario\c- Mantén para preparar un largo golpe vertical, suelta para ejecutar un potente ataque giratorio, destrozando todo a tu alrededor. Las pulsaciones consecutivas del fuego terciario mientras giras harán que se mantenga el movimiento durante más tiempo. Siendo un robot de combate, deberías estar libre de cualquier mareo por el movimiento que un humano típicamente desarrollaría haciendo algo así.\n"
"\n"

View file

@ -1,3 +1,3 @@
[default]
SWWM_MODVER="\cyDEMOLITIONIST \cw1.3pre r47 \cu(Fri 22 Apr 12:51:02 CEST 2022)\c-";
SWWM_SHORTVER="\cw1.3pre r47 \cu(2022-04-22 12:51:02)\c-";
SWWM_MODVER="\cyDEMOLITIONIST \cw1.3pre r48 \cu(Tue 26 Apr 18:52:56 CEST 2022)\c-";
SWWM_SHORTVER="\cw1.3pre r48 \cu(2022-04-26 18:52:56)\c-";

View file

@ -18,7 +18,7 @@ The Reinforced Combat Hammer is primarily meant to be used in quickly dismantlin
\cfPrimary Fire:\c- Rapid swings, from side to side. Good for quickly plowing through enemy hordes.
\cfSecondary Fire:\c- Hold to ready up a vertical swing, release to let the hammer drop on whatever poor fool is standing in front of you. The longer you hold, the stronger the hit.
\cfSecondary Fire:\c- Hold to ready up a vertical swing, release to let the hammer drop on whatever poor fool is standing in front of you. The longer you hold, the stronger the hit. This attack can potentially break down doors, among other things.
\cfTertiary Fire:\c- Hold to ready up a wide horizontal swing, release to perform a potent spin attack, smashing away everything around you. Consecutive presses of tertiary fire while spinning will keep the motion going for longer. Being a combat robot, you should be free from any motion sickness that a human would typically develop while performing this action.

View file

@ -14,7 +14,7 @@ El Martillo de Combate Reforzado es principalmente usado para desmantelar rápid
\cfFuego Primario:\c- Golpes rápidos, de lado a lado. Bueno para cargar a través de hordas enemigas.
\cfFuego Secundario:\c- Mantén para preparar un golpe vertical, suelta para dejar caer el martillo sobre cualquier pobre insensato que se te ponga delante. Cuanto más lo mantengas, más fuerte será el golpe.
\cfFuego Secundario:\c- Mantén para preparar un golpe vertical, suelta para dejar caer el martillo sobre cualquier pobre insensato que se te ponga delante. Cuanto más lo mantengas, más fuerte será el golpe. Este ataque puede potencialmente echar abajo puertas, entre otras cosas.
\cfFuego Terciario\c- Mantén para preparar un largo golpe vertical, suelta para ejecutar un potente ataque giratorio, destrozando todo a tu alrededor. Las pulsaciones consecutivas del fuego terciario mientras giras harán que se mantenga el movimiento durante más tiempo. Siendo un robot de combate, deberías estar libre de cualquier mareo por el movimiento que un humano típicamente desarrollaría haciendo algo así.

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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);