The Pusher is gone.

This commit is contained in:
Mari the Deer 2022-05-16 16:39:11 +02:00
commit 834116c8c7
70 changed files with 77 additions and 1257 deletions

View file

@ -1,5 +1,5 @@
// Itamex Reinforced Combat Hammer (from UnSX 5)
// Slot 1, spawns shared with Pusher
// Slot 1, spawns shared with Deep Impact
Class ItamexHammer : SWWMWeapon
{
@ -16,7 +16,7 @@ Class ItamexHammer : SWWMWeapon
SWWMWeapon.GetLine "getitamexhammer";
Inventory.Icon "graphics/HUD/Icons/W_ItamexHammer.png";
Weapon.SlotNumber 1;
Weapon.SlotPriority 3.;
Weapon.SlotPriority 2.;
Weapon.SelectionOrder 1200;
Stamina 9000;
+WEAPON.MELEEWEAPON;

View file

@ -209,8 +209,6 @@ extend Class SWWMHandler
if ( (e.Thing is 'Cyberdemon') && (inflictor is 'Rocket') && (buff.tracer == e.Thing) )
SWWMUtility.MarkAchievement("cybully",src.player);
}
if ( (inflictor is 'PusherWeapon') || (inflictor is 'PusherProjectile') )
SWWMUtility.AchievementProgressInc("tender",1,src.player);
Inventory tk;
if ( (tk = e.Thing.FindInventory("DeepImpactOnlyToken")) && (tk.special1 == 1) )
SWWMUtility.MarkAchievement("shame",src.player);

View file

@ -210,106 +210,6 @@ extend Class SWWMHandler
Console.Printf("%d effects cleared.",n);
return;
}
else if ( e.Name ~== "swwmdebugdumprng" )
{
if ( multiplayer && (e.player != Net_Arbitrator) )
{
if ( e.player == consoleplayer )
Console.Printf("Only the net arbitrator can call this event.");
return;
}
// dump the values of all mod RNGs (might help someday to track down what desyncs)
String msg = String.Format("\cxRNG dump for player %d (\c-%s\cx):\c-",consoleplayer,players[consoleplayer].GetUserName());
msg.AppendFormat("\n\n\cfPlay RNG (will cause desyncs if mismatched):\c-\n");
msg.AppendFormat("\nBlood: %08x",Random2[Blood]());
msg.AppendFormat("\nBoolet: %08x",Random2[Boolet]());
msg.AppendFormat("\nBundle: %08x",Random2[Bundle]());
msg.AppendFormat("\nCandy: %08x",Random2[Candy]());
msg.AppendFormat("\nChancebox: %08x",Random2[Chancebox]());
msg.AppendFormat("\nCorrode: %08x",Random2[Corrode]());
msg.AppendFormat("\nDemolitionist: %08x",Random2[Demolitionist]());
msg.AppendFormat("\nDoBlast: %08x",Random2[DoBlast]());
msg.AppendFormat("\nDropChance: %08x",Random2[DropChance]());
msg.AppendFormat("\nEviscerator: %08x",Random2[Eviscerator]());
msg.AppendFormat("\nExplodium: %08x",Random2[Explodium]());
msg.AppendFormat("\nExploS: %08x",Random2[ExploS]());
msg.AppendFormat("\nExtraMissiles: %08x",Random2[ExtraMissiles]());
msg.AppendFormat("\nFlameT: %08x",Random2[FlameT]());
msg.AppendFormat("\nFlicker: %08x",Random2[Flicker]());
msg.AppendFormat("\nGesture: %08x",Random2[Gesture]());
msg.AppendFormat("\nGibs: %08x",Random2[Gibs]());
msg.AppendFormat("\nGoldDrop: %08x",Random2[GoldDrop]());
msg.AppendFormat("\nGoldy: %08x",Random2[Goldy]());
msg.AppendFormat("\nGunFlash: %08x",Random2[GunFlash]());
msg.AppendFormat("\nHellblazer: %08x",Random2[Hellblazer]());
msg.AppendFormat("\nImpact: %08x",Random2[Impact]());
msg.AppendFormat("\nInvinciball: %08x",Random2[Invinciball]());
msg.AppendFormat("\nJunk: %08x",Random2[Junk]());
msg.AppendFormat("\nMoth: %08x",Random2[Moth]());
msg.AppendFormat("\nMykradvo: %08x",Random2[Mykradvo]());
msg.AppendFormat("\nNugget: %08x",Random2[Nugget]());
msg.AppendFormat("\nParry: %08x",Random2[Parry]());
msg.AppendFormat("\nPonch: %08x",Random2[Ponch]());
msg.AppendFormat("\nPuff: %08x",Random2[Puff]());
msg.AppendFormat("\nPusher: %08x",Random2[Pusher]());
msg.AppendFormat("\nRage: %08x",Random2[Rage]());
msg.AppendFormat("\nReplacements: %08x",Random2[Replacements]());
msg.AppendFormat("\nShellDrop: %08x",Random2[ShellDrop]());
msg.AppendFormat("\nShivers: %08x",Random2[Shivers]());
msg.AppendFormat("\nSilverbullet: %08x",Random2[Silverbullet]());
msg.AppendFormat("\nSpareShells: %08x",Random2[SpareShells]());
msg.AppendFormat("\nSparkster: %08x",Random2[Sparkster]());
msg.AppendFormat("\nSpread: %08x",Random2[Spread]());
msg.AppendFormat("\nSpreadgun: %08x",Random2[Spreadgun]());
msg.AppendFormat("\nWallbuster: %08x",Random2[Wallbuster]());
msg.AppendFormat("\nYnykron: %08x",Random2[Ynykron]());
msg.AppendFormat("\n\n\cfUI RNG (should not cause desyncs if mismatched):\c-\n");
msg.AppendFormat("\nbdscreen: %08x",Random2[bdscreen]());
msg.AppendFormat("\nClientSparkles: %08x",Random2[ClientSparkles]());
msg.AppendFormat("\nDemoLines: %08x",Random2[DemoLines]());
msg.AppendFormat("\nFInTheChat: %08x",Random2[FInTheChat]());
msg.AppendFormat("\nFunTags: %08x",Random2[FunTags]());
msg.AppendFormat("\nhdscreen: %08x",Random2[hdscreen]());
msg.AppendFormat("\nHudStuff: %08x",Random2[HudStuff]());
msg.AppendFormat("\nInterArt: %08x",Random2[InterArt]());
msg.AppendFormat("\nScoreBits: %08x",Random2[ScoreBits]());
msg.AppendFormat("\nTUID: %08x",Random2[TUID]());
msg.AppendFormat("\nUIStuff: %08x",Random2[UIStuff]());
msg.AppendFormat("\nWallbusterMenu: %08x",Random2[WallbusterMenu]());
Console.Printf(msg);
return;
}
else if ( e.Name ~== "swwmdebugdlglines" )
{
if ( multiplayer && (e.player != Net_Arbitrator) )
{
if ( e.player == consoleplayer )
Console.Printf("Only the net arbitrator can call this event.");
return;
}
// checks that ALL dialogue text fits in 3 lines
String alldlg_pack = "SWWM_SAYAPHOBOS1:SWWM_SAYAPHOBOS2:SWWM_SAYAPHOBOS3:SWWM_SAYAPHOBOS4:SWWM_SAYADEIMOS1:SWWM_SAYADEIMOS2:SWWM_SAYADEIMOS3:SWWM_SAYADEIMOS4:SWWM_SAYADIS1:SWWM_SAYADIS2:SWWM_SAYADIS3:SWWM_SAYADIS4:SWWM_SAYATHY1:SWWM_SAYATHY2:SWWM_SAYATHY3:SWWM_SAYATHY4:SWWM_CYTHOSIGIL1:SWWM_CYTHOSIGIL2:SWWM_CYTHOSIGIL3:SWWM_CYTHOSIGIL4:SWWM_SAYADIMPLE1:SWWM_SAYADIMPLE2:SWWM_SAYADIMPLE3:SWWM_SAYADIMPLE4:SWWM_SAYADIMPLE5:SWWM_SAYACIRCLE1:SWWM_SAYACIRCLE2:SWWM_SAYACIRCLE3:SWWM_SAYACIRCLE4:SWWM_SAYACIRCLE5:SWWM_SAYAGOTCHA1:SWWM_SAYAGOTCHA2:SWWM_SAYAGOTCHA3:SWWM_SAYAGOTCHA4:SWWM_SAYAGOTCHA5:SWWM_SAYAGOTCHAEND1:SWWM_SAYAGOTCHAEND2:SWWM_SAYAGOTCHAEND3:SWWM_SAYAGOTCHAEND4:SWWM_SAYAGOTCHAEND5:SWWM_SAYAIOS1:SWWM_SAYAIOS2:SWWM_SAYAIOS3:SWWM_SAYAIOS4:SWWM_SAYAIOS5:SWWM_SAYARAMPANCY1:SWWM_SAYARAMPANCY2:SWWM_SAYARAMPANCY3:SWWM_SAYARAMPANCY4:SWWM_CYTHONERVE1:SWWM_CYTHONERVE2:SWWM_CYTHONERVE3:SWWM_CYTHONERVE4:SWWM_CYTHONERVE5:SWWM_SAYAEVIA1:SWWM_SAYAEVIA2:SWWM_SAYAEVIA3:SWWM_SAYAEVIA4:SWWM_SAYAEVIB1:SWWM_SAYAEVIB2:SWWM_SAYAMAW1:SWWM_SAYAMAW2:SWWM_SAYAMAW3:SWWM_SAYAMAW4:SWWM_SAYAMAW5:SWWM_SAYAMASTERS1:SWWM_SAYAMASTERS2:SWWM_SAYAMASTERS3:SWWM_SAYAMASTERS4:SWWM_SAYAMASTERS5:SWWM_SAYADSPARIL1:SWWM_SAYADSPARIL2:SWWM_SAYADSPARIL3:SWWM_SAYADSPARIL4:SWWM_SAYADSPARIL5:SWWM_SAYAHEADS1:SWWM_SAYAHEADS2:SWWM_SAYAHEADS3:SWWM_SAYAHEADS4:SWWM_SAYAHEADS5:SWWM_SAYAHEADS6:SWWM_SAYABULLS1:SWWM_SAYABULLS2:SWWM_SAYABULLS3:SWWM_SAYABULLS4:SWWM_SAYABULLS5:SWWM_SAYAGREETA1:SWWM_SAYAGREETA2:SWWM_SAYAGREETA3:SWWM_SAYAGREETB1:SWWM_SAYAGREETC1:SWWM_SAYAGREETD1:SWWM_SAYAGREETE1:SWWM_SAYAGREETF1:SWWM_SAYABLOODA1:SWWM_SAYABLOODA2:SWWM_SAYABLOODB1:SWWM_SAYABLOODC1:SWWM_SAYABLOODD1:SWWM_SAYAHYPO1:SWWM_SAYAHYPO2:SWWM_SAYAHYPO3:SWWM_SAYAHYPO4:SWWM_KIRINWORSHIPA1:SWWM_KIRINWORSHIPB1:SWWM_KIRINWORSHIPC1:SWWM_KIRINWORSHIPD1:SWWM_KIRINWORSHIPD2:SWWM_SAYAGAMEA1:SWWM_SAYAGAMEA2:SWWM_SAYAGAMEB1:SWWM_SAYAGAMEC1:SWWM_SAYAMASTERSA1:SWWM_SAYAMASTERSA2:SWWM_SAYAMASTERSB1:SWWM_SAYAMASTERSC1:SWWM_SAYAMASTERSD1:SWWM_SAYAMASTERSE1:SWWM_SAYAMASTERSF1:SWWM_SAYAFIGHTER1:SWWM_SAYAFIGHTER2:SWWM_SAYACLERICA1:SWWM_SAYACLERICA2:SWWM_SAYACLERICB1:SWWM_SAYACLERICC1:SWWM_SAYACLERICC2:SWWM_SAYAMAGE1:SWWM_SAYAMAGE2:SWWM_SAYAMAGE3:SWWM_SAYAMAGE4:SWWM_SAYAKORAXA1:SWWM_SAYAKORAXB1:SWWM_SAYAKORAXC1:SWWM_SAYAKORAXD1:SWWM_SAYAKORAXE1:SWWM_SAYABLIGHTA1:SWWM_SAYABLIGHTB1:SWWM_SAYABLIGHTC1:SWWM_SAYABLIGHTC2:SWWM_SAYACONSTABLEA1:SWWM_SAYACONSTABLEA2:SWWM_SAYACONSTABLEB1:SWWM_SAYACONSTABLEC1:SWWM_SAYACONSTABLED1:SWWM_SAYANAVEA1:SWWM_SAYANAVEA2:SWWM_SAYANAVEB1:SWWM_SAYANAVEC1:SWWM_SAYANAVED1:SWWM_SAYANAVEE1:SWWM_SAYANAVEF1:SWWM_SAYADEATHKINGS1:SWWM_KIRINPUZZLEA1:SWWM_KIRINPUZZLEA2:SWWM_KIRINPUZZLEB1:SWWM_KIRINPUZZLEC1:SWWM_KIRINPUZZLEC2:SWWM_KIRINPUZZLED1:SWWM_KIRINPUZZLED2:SWWM_KIRINPUZZLEE1:SWWM_KIRINPUZZLEE2:SWWM_KIRINPUZZLEF1:SWWM_KIRINPUZZLEF2:SWWM_KIRINPUZZLEF3:SWWM_KIRINPUZZLEG1:SWWM_KIRINPUZZLEH1:SWWM_KIRINPUZZLEI1:SWWM_KIRINPUZZLEI2:SWWM_KIRINPUZZLEJ1:SWWM_KIRINPUZZLEJ2:SWWM_KIRINPUZZLEK1:SWWM_KIRINPUZZLEL1:SWWM_KIRINPUZZLEM1:SWWM_KIRINPUZZLEN1:SWWM_KIRINPUZZLEO1:SWWM_KIRINPUZZLEP1:SWWM_KIRINPUZZLEQ1:SWWM_KIRINPUZZLER1:SWWM_KIRINPUZZLER2:SWWM_KIRINPUZZLER3:SWWM_KIRINPUZZLES1:SWWM_KIRINPUZZLET1:SWWM_KIRINPUZZLEU1:SWWM_ZNVTXT1:SWWM_ZNVTXT2:SWWM_ZNVTXT3:SWWM_ZNVTXT4:SWWM_ZNVTXT5";
Array<String> alldlg;
alldlg_pack.Split(alldlg,":");
let mSmallFont = Font.GetFont('TewiFont');
for ( int i=0; i<alldlg.Size(); i++ )
{
let l = mSmallFont.BreakLines(StringTable.Localize(alldlg[i],false),220);
if ( l.Count() > 3 ) Console.Printf("\cg%s exceeds line limit (%d > 3)\c-",alldlg[i],l.Count());
else
{
if ( !e.Args[0] )
{
l.Destroy();
continue;
}
Console.Printf("\cd%s is within line limit (%d <= 3)\c-",alldlg[i],l.Count());
}
for ( int j=0; j<l.Count(); j++ ) Console.Printf("> %s",l.StringAt(j));
l.Destroy();
}
return;
}
else if ( e.Name ~== "swwmprofilehandler" )
{
if ( multiplayer && (e.player != Net_Arbitrator) )

View file

@ -163,7 +163,6 @@ Class SWWMStats : SWWMStaticThinker
if ( inflictor && inflictor.FindInventory("ParriedBuff") ) which = 'DoomWeapon'; // gross hack
// properly credit some projectiles to their respective gun
else if ( inflictor is 'AirBullet' ) which = 'DeepImpact';
else if ( inflictor is 'PusherProjectile' ) which = 'PusherWeapon';
else if ( (inflictor is 'ExplodiumMagArm') || (inflictor is 'ExplodiumMagProj') || (inflictor is 'ExplodiumBulletImpact') ) which = 'ExplodiumGun';
else if ( ((inflictor is 'SaltImpact') && !inflictor.Args[0]) || ((inflictor is 'SaltBeam') && !inflictor.Args[1]) || (inflictor is 'CorrodeDebuff') || (inflictor is 'CorrosiveFlechette') || ((inflictor is 'TheBall') && !inflictor.special1) || (inflictor is 'GoldenImpact') || (inflictor is 'GoldenSubImpact') || (inflictor is 'GoldenSubSubImpact') ) which = 'Spreadgun';
else if ( ((inflictor is 'SaltImpact') && inflictor.Args[0]) || ((inflictor is 'SaltBeam') && inflictor.Args[1]) || ((inflictor is 'TheBall') && inflictor.special1) ) which = 'Wallbuster';

View file

@ -1368,7 +1368,6 @@ Class SWWMUtility
{
if ( !a.bMISSILE ) return false;
if ( a is 'AirBullet' ) return true;
if ( a is 'PusherProjectile' ) return true;
if ( a is 'ExplodiumMagProj' ) return true;
if ( a is 'CorrosiveFlechette' ) return true;
if ( a is 'TheBall' ) return true;
@ -2148,20 +2147,13 @@ Class SWWMUtility
return c;
}
// melee weapons + extra slot 2 guns (50% chance)
// melee weapon + extra slot 2 guns
static Class<Weapon> PickSWWMSlot1()
{
// so the player can recover it if they decided to drop it in a previous map, or they didn't start with it
if ( CheckNeedsItem('DeepImpact') ) return 'DeepImpact';
bool hasmelee = (!CheckNeedsItem('PusherWeapon')/*||!CheckNeedsItem('ItamexHammer')*/);
bool hasallmelee = (!CheckNeedsItem('PusherWeapon')/*&&!CheckNeedsItem('ItamexHammer')*/);
bool gunexists = ItemExists('ExplodiumGun',worldonly:true)/*||ItemExists('PlasmaBlast',worldonly:true)*/;
// if the player already has a melee weapon, 50% chance to spawn either slot 2 weapon as long as one doesn't exist in the map already
// if the player has ALL melee weapons (somehow), that chance becomes 100%
if ( hasmelee && !gunexists && (hasallmelee || Random[Replacements](0,1)) )
return PickSWWMSlot2();
//return PickPair('PusherWeapon','ItamexHammer');
return 'PusherWeapon';
//if ( CheckNeedsItem('ItamexHammer') ) return 'ItamexHammer';
return PickSWWMSlot2();
}
// pistol spawn, pretty simple
static Class<Weapon> PickSWWMSlot2()
@ -2202,13 +2194,16 @@ Class SWWMUtility
// second plasma rifle spawn
static Class<Weapon> PickSWWMSlot8()
{
//return PickPair('SilverBullet','MisterRifle');
//return PickPair('SilverBullet','RayKhom');
return 'SilverBullet';
}
// first bfg spawn
static Class<Weapon> PickSWWMSlot9()
{
//return PickPair('CandyGun','RayKhom');
// 33% chance to still drop another candy gun if it's not at max capacity
//if ( !Random[Replacements](0,2) && ItemExists('CandyGun') && CheckNeedsItem('CandyGunSpares',true) )
// return 'CandyGun';
//return PickPair('CandyGun','MisterRifle');
return 'CandyGun';
}
// second bfg spawn (each weapon can only exist once)
@ -2230,7 +2225,7 @@ Class SWWMUtility
static Class<Weapon> PickDoomSlot6()
{
bool hasslot7 = (!CheckNeedsItem('Sparkster')/*||!CheckNeedsItem('ModernSparkster')*/);
bool hasslot8 = (!CheckNeedsItem('SilverBullet')/*||!CheckNeedsItem('MortalRifle')*/);
bool hasslot8 = (!CheckNeedsItem('SilverBullet')/*||!CheckNeedsItem('RayKhom')*/);
// if the player already has a slot 7 weapon...
if ( hasslot7 )
{
@ -2246,7 +2241,7 @@ Class SWWMUtility
// either bfg spawn
static Class<Weapon> PickDoomSlot7()
{
bool hasslot9 = (!CheckNeedsItem('CandyGun')/*||!CheckNeedsItem('RayKhom')*/);
bool hasslot9 = (!CheckNeedsItem('CandyGun')/*||!CheckNeedsItem('MisterRifle')*/);
bool hasslot0 = (!CheckNeedsItem('Ynykron')/*||!CheckNeedsItem('RafanKos')*/);
let rep = PickSWWMSlot0(false);
// if the player already has a slot 9 weapon (and a slot 0 weapon can still spawn)...

View file

@ -257,8 +257,8 @@ Class BigPunchImpact : Actor
override void PostBeginPlay()
{
Super.PostBeginPlay();
A_QuakeEx(8,8,8,18,0,600,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,falloff:200,rollIntensity:.9);
A_StartSound("pusher/althit",CHAN_VOICE,CHANF_DEFAULT,bAMBUSH?.6:1.);
A_QuakeEx(8,8,8,18,0,600,"",QF_RELATIVE|QF_SCALEDOWN,falloff:200,rollIntensity:.9);
A_StartSound("demolitionist/xpunch",CHAN_VOICE,CHANF_DEFAULT,bAMBUSH?.6:1.);
A_SprayDecal("BigWallCrack",-20);
int numpt = Random[Ponch](9,16);
if ( bAMBUSH ) numpt /= 3;

View file

@ -457,8 +457,8 @@ extend Class SWWMWeapon
A_QuakeEx(quakin/2,quakin/2,quakin/2,3,0,1,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,rollIntensity:0.06*quakin);
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);
if ( blooded ) A_StartSound("demolitionist/xpunchf",CHAN_WEAPON,CHANF_OVERLAP);
if ( bloodless ) A_StartSound("demolitionist/xpunch",CHAN_WEAPON,CHANF_OVERLAP);
}
else if ( hitsound == "" )
{
@ -546,7 +546,7 @@ extend Class SWWMWeapon
int quakin = raging?4:1;
A_QuakeEx(quakin,quakin,quakin,3,0,1,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,rollIntensity:0.12*quakin);
A_BumpFOV(.98);
A_StartSound((raging&&!(flags&MELEE_ForceSound))?"pusher/althit":(hitsound!="")?hitsound:"demolitionist/punch",CHAN_WEAPON,CHANF_OVERLAP);
A_StartSound((raging&&!(flags&MELEE_ForceSound))?"demolitionist/xpunch":(hitsound!="")?hitsound:"demolitionist/punch",CHAN_WEAPON,CHANF_OVERLAP);
A_AlertMonsters(swwm_uncapalert?0:100);
if ( raging ) raging.DoHitFX();
if ( (flags&MELEE_ForceBust) || swwm_omnibust ) BusterWall.BustLinetrace(d,raging?(dmg*8):dmg,self,d.HitDir,d.HitLocation.z);

View file

@ -1,399 +0,0 @@
// Tach-Engine Technologies Microfusion Rotary Hammer aka "Pusher" (planned for unreleased Zanaveth Ultra Suite 2)
// Slot 1, replaces Chainsaw, Gauntlets, Timon's Axe
Class PusherWeapon : SWWMWeapon
{
double chargelevel, vibe;
int hitcnt;
transient ui DynamicValueInterpolator ChargeInter;
override void HudTick()
{
Super.HudTick();
if ( !ChargeInter ) ChargeInter = DynamicValueInterpolator.Create(int(chargelevel*100),.5,1,50);
ChargeInter.Update(int(chargelevel*100));
}
override bool ReportHUDAmmo()
{
return true;
}
override Vector3 GetTraceOffset()
{
return (10.,2.,-3.5);
}
action void A_PusherDrill()
{
invoker.chargelevel = clamp(invoker.chargelevel+FRandom[Pusher](-.04,.08),.3,1.);
A_QuakeEx(1,1,1,3,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:.5);
A_WeaponOffset(FRandom[Pusher](-1,1)*2,32+FRandom[Pusher](-1,1)*2);
A_BumpFOV(1.01);
A_Recoil(-cos(pitch));
Vector3 x, y, z;
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+2*y-3.5*z);
FLineTraceData d;
LineTrace(angle,60,pitch,TRF_ABSPOSITION,origin.z,origin.x,origin.y,d);
SWWMBulletTrail.DoTrail(self,origin,x,60,0);
if ( d.HitType != TRACE_HitNone )
{
A_QuakeEx(2,2,2,7,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:.8);
A_AlertMonsters(swwm_uncapalert?0:1200);
int dmg = int(4+invoker.chargelevel*8);
if ( invoker.chargelevel > .4 ) invoker.chargelevel -= FRandom[Pusher](.01,.03);
if ( d.HitType == TRACE_HitActor )
{
double diff = deltaangle(self.angle,AngleTo(d.HitActor));
self.angle += clamp(diff,-5.,5.);
SWWMUtility.DoKnockback(d.HitActor,d.HitDir,8500);
d.HitActor.A_QuakeEx(3,3,3,10,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:1.1);
let p = SWWMPuff.Setup(d.HitLocation,d.HitDir,invoker,self,d.HitActor);
dmg = d.HitActor.DamageMobj(p,self,dmg,'Tenderize',DMG_THRUSTLESS|DMG_INFLICTOR_IS_PUFF);
if ( d.HitActor.bNOBLOOD || d.HitActor.bDORMANT || d.HitActor.bINVULNERABLE )
{
let p = Spawn("PusherImpact",d.HitLocation-d.HitDir*4);
p.angle = atan2(-d.HitDir.y,-d.HitDir.x);
p.pitch = asin(d.HitDir.z);
}
else
{
d.HitActor.TraceBleed(dmg,invoker);
d.HitActor.SpawnBlood(d.HitLocation,atan2(d.HitDir.y,d.HitDir.x)+180,dmg);
d.HitActor.A_StartSound("pusher/meat",CHAN_DAMAGE,CHANF_OVERLAP);
}
// move towards target (unless we're standing on it)
if ( !(self is 'Demolitionist') || (Demolitionist(self).oldencroached != d.HitActor) )
bJUSTATTACKED = true;
}
else
{
Vector3 HitNormal = -d.HitDir;
if ( d.HitType == TRACE_HitFloor )
{
if ( d.Hit3DFloor ) HitNormal = -d.Hit3DFloor.top.Normal;
else HitNormal = d.HitSector.floorplane.Normal;
}
else if ( d.HitType == TRACE_HitCeiling )
{
if ( d.Hit3DFloor ) HitNormal = -d.Hit3DFloor.bottom.Normal;
else HitNormal = d.HitSector.ceilingplane.Normal;
}
else if ( d.HitType == TRACE_HitWall )
{
HitNormal = (-d.HitLine.delta.y,d.HitLine.delta.x,0).unit();
if ( !d.LineSide ) HitNormal *= -1;
d.HitLine.RemoteActivate(self,d.LineSide,SPAC_Impact,d.HitLocation+HitNormal*4);
}
let p = Spawn("PusherImpact",d.HitLocation+HitNormal*4);
p.angle = atan2(HitNormal.y,HitNormal.x);
p.pitch = asin(-HitNormal.z);
if ( d.HitType == TRACE_HitFloor ) p.CheckSplash(40);
if ( waterlevel > 2 ) SWWMUtility.DoKnockback(self,-x,30000);
}
if ( swwm_omnibust ) BusterWall.BustLinetrace(d,dmg,self,d.HitDir,d.HitLocation.z);
}
else if ( waterlevel > 2 ) SWWMUtility.DoKnockback(self,-x,50000);
if ( swwm_extraalert || !(invoker.hitcnt%20) ) A_AlertMonsters(swwm_uncapalert?0:500);
invoker.hitcnt++;
}
action void A_PusherAlt()
{
A_StopSound(CHAN_WEAPON);
if ( IsActorPlayingSound(CHAN_WEAPONEXTRA,"pusher/motor") )
A_StartSound("pusher/motorend",CHAN_WEAPONEXTRA,CHANF_DEFAULT,pitch:1.5);
A_StartSound("pusher/stop",CHAN_WEAPON,CHANF_OVERLAP);
A_StartSound("pusher/altfire",CHAN_WEAPON,CHANF_OVERLAP);
A_BumpFOV(1.+invoker.chargelevel*.2);
A_Recoil(-(2.+4.*invoker.chargelevel)*cos(pitch));
A_QuakeEx(2+int(invoker.chargelevel*2),2+int(invoker.chargelevel*2),2+int(invoker.chargelevel*2),3+int(invoker.chargelevel*6),0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:.3+invoker.chargelevel*.7);
A_WeaponOffset(0,32);
A_Overlay(-9999,null);
A_PlayerFire();
Vector3 x, y, z;
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+2*y-3.5*z);
FLineTraceData d;
LineTrace(angle,80,pitch,TRF_ABSPOSITION,origin.z,origin.x,origin.y,d);
SWWMBulletTrail.DoTrail(self,origin,x,80,0);
bool gone = false;
if ( d.HitType != TRACE_HitNone )
{
A_QuakeEx(8,8,8,12,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:.8);
A_AlertMonsters(swwm_uncapalert?0:1600);
int dmg = int(240*invoker.chargelevel);
if ( d.HitType == TRACE_HitActor )
{
double diff = deltaangle(self.angle,AngleTo(d.HitActor));
self.angle += clamp(diff,-5.,5.);
SWWMUtility.DoKnockback(d.HitActor,d.HitDir,85000);
d.HitActor.A_QuakeEx(9,9,9,15,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:1.1);
let p = SWWMPuff.Setup(d.HitLocation,d.HitDir,invoker,self,d.HitActor);
dmg = d.HitActor.DamageMobj(p,self,dmg,'Tenderize',DMG_THRUSTLESS|DMG_INFLICTOR_IS_PUFF);
if ( d.HitActor.bNOBLOOD || d.HitActor.bDORMANT || d.HitActor.bINVULNERABLE )
{
let p = Spawn("BigPusherImpact",d.HitLocation-d.HitDir*4);
p.angle = atan2(-d.HitDir.y,-d.HitDir.x);
p.pitch = asin(d.HitDir.z);
}
else
{
d.HitActor.TraceBleed(dmg,invoker);
d.HitActor.SpawnBlood(d.HitLocation,atan2(d.HitDir.y,d.HitDir.x)+180,dmg);
d.HitActor.A_StartSound("pusher/altmeat",CHAN_DAMAGE,CHANF_OVERLAP);
}
}
else
{
Vector3 HitNormal = -d.HitDir;
if ( d.HitType == TRACE_HitFloor )
{
if ( d.Hit3DFloor ) HitNormal = -d.Hit3DFloor.top.Normal;
else HitNormal = d.HitSector.floorplane.Normal;
}
else if ( d.HitType == TRACE_HitCeiling )
{
if ( d.Hit3DFloor ) HitNormal = -d.Hit3DFloor.bottom.Normal;
else HitNormal = d.HitSector.ceilingplane.Normal;
}
else if ( d.HitType == TRACE_HitWall )
{
HitNormal = (-d.HitLine.delta.y,d.HitLine.delta.x,0).unit();
if ( !d.LineSide ) HitNormal *= -1;
d.HitLine.RemoteActivate(self,d.LineSide,SPAC_Impact,d.HitLocation+HitNormal*4);
}
let p = Spawn("BigPusherImpact",d.HitLocation+HitNormal*4);
p.angle = atan2(HitNormal.y,HitNormal.x);
p.pitch = asin(-HitNormal.z);
if ( d.HitType == TRACE_HitFloor ) p.CheckSplash(40);
}
if ( swwm_omnibust ) BusterWall.BustLinetrace(d,dmg,self,d.HitDir,d.HitLocation.z);
}
else if ( !Random[Pusher](0,3-int(invoker.chargelevel*3)) )
{
// didn't hit anything, randomly slip off
player.SetPSprite(PSP_WEAPON,ResolveState("AltMiss"));
invoker.bNODEATHDESELECT = true; // prevent any glitching that could happen if the sequence is interrupted
A_StopSound(CHAN_WEAPON);
A_StopSound(CHAN_WEAPONEXTRA);
A_StartSound("pusher/miss",CHAN_WEAPON,CHANF_OVERLAP);
let p = Spawn("PusherProjectile",origin);
p.angle = angle;
p.pitch = pitch;
p.vel = x*p.speed*invoker.chargelevel;
p.target = self;
SWWMUtility.DoKnockback(self,x,85000.);
}
A_AlertMonsters(swwm_uncapalert?0:1200);
invoker.chargelevel = 0.;
}
action void A_BeginCharge()
{
invoker.chargelevel = invoker.vibe = 0.;
A_WeaponOffset(0,32);
A_QuakeEx(1,1,1,33,0,1,"",QF_RELATIVE|QF_SCALEUP,rollIntensity:.5);
A_Overlay(-9999,"Dummy");
}
action void A_ChargeUp()
{
invoker.chargelevel = min(1.,invoker.chargelevel+.025);
if ( invoker.chargelevel >= .5 ) invoker.vibe = min(1.,invoker.vibe+.02);
A_WeaponOffset(FRandom[Pusher](-1,1)*(invoker.chargelevel-invoker.vibe),32+FRandom[Pusher](-1,1)*(invoker.chargelevel-invoker.vibe));
if ( !(player.cmd.buttons&BT_ALTATTACK) && (invoker.chargelevel > .3) )
player.SetPSprite(PSP_WEAPON,ResolveState("AltRelease"));
}
override void MarkPrecacheSounds()
{
Super.MarkPrecacheSounds();
MarkSound("pusher/select");
MarkSound("pusher/deselect");
MarkSound("pusher/motor");
MarkSound("pusher/motorend");
MarkSound("pusher/start");
MarkSound("pusher/drill");
MarkSound("pusher/hit1");
MarkSound("pusher/hit2");
MarkSound("pusher/hit3");
MarkSound("pusher/meat1");
MarkSound("pusher/meat2");
MarkSound("pusher/meat3");
MarkSound("pusher/end");
MarkSound("pusher/checkout");
MarkSound("pusher/pullback");
MarkSound("pusher/altfire1");
MarkSound("pusher/altfire2");
MarkSound("pusher/miss");
MarkSound("pusher/althit1");
MarkSound("pusher/althit2");
MarkSound("pusher/altmeat1");
MarkSound("pusher/altmeat2");
MarkSound("pusher/fly");
MarkSound("pusher/bounce1");
MarkSound("pusher/bounce2");
MarkSound("pusher/bounce3");
}
Default
{
//$Title Pusher
//$Group Weapons
//$Sprite graphics/HUD/Icons/W_Pusher.png
//$Icon weapon
Tag "$T_PUSHER";
Inventory.PickupMessage "$I_PUSHER";
Obituary "$O_PUSHER";
SWWMWeapon.Tooltip "$TT_PUSHER";
SWWMWeapon.GetLine "getpusherweapon";
Inventory.Icon "graphics/HUD/Icons/W_Pusher.png";
Weapon.UpSound "pusher/select";
Weapon.SlotNumber 1;
Weapon.SlotPriority 2.;
Weapon.SelectionOrder 1500;
Stamina 10000;
+WEAPON.MELEEWEAPON;
//+WEAPON.NOAUTOSWITCHTO;
Radius 20;
Height 32;
}
States
{
Spawn:
XZW1 A -1;
Stop;
Select:
XZW2 G 2 A_FullRaise();
XZW2 HIJKL 2;
Goto Ready;
Ready:
XZW2 A 1 A_WeaponReady(WRF_ALLOWRELOAD|WRF_ALLOWZOOM|WRF_ALLOWUSER1);
Wait;
Fire:
XZW2 A 2
{
A_WeaponOffset(0,32);
invoker.chargelevel = .2;
invoker.hitcnt = 0;
A_StartSound("pusher/start",CHAN_WEAPON,CHANF_OVERLAP);
A_StartSound("pusher/motor",CHAN_WEAPONEXTRA,CHANF_LOOP,pitch:1.5);
}
XZW2 M 2;
XZW2 N 0 A_StartSound("pusher/drill",CHAN_WEAPONEXTRA2,CHANF_LOOP);
Hold:
XZW2 N 1
{
A_WeaponOffset(FRandom[Pusher](-1,1),32+FRandom[Pusher](-1,1));
A_Recoil(cos(pitch));
}
XZW2 O 1 A_PusherDrill();
XZW2 P 1
{
A_WeaponOffset(FRandom[Pusher](-1,1),32+FRandom[Pusher](-1,1));
A_Recoil(cos(pitch));
}
XZW2 Q 1 A_PusherDrill();
XZW2 R 1
{
A_WeaponOffset(FRandom[Pusher](-1,1),32+FRandom[Pusher](-1,1));
A_Recoil(cos(pitch));
}
XZW2 S 1 A_PusherDrill();
XZW2 N 2
{
if ( player.cmd.buttons&BT_ATTACK )
return ResolveState("Hold");
invoker.chargelevel *= .4;
A_Recoil(.5*cos(pitch));
A_ClearRefire();
A_WeaponOffset(0,32);
A_StopSound(CHAN_WEAPONEXTRA2);
A_StartSound("pusher/stop",CHAN_WEAPON,CHANF_OVERLAP);
A_StartSound("pusher/motorend",CHAN_WEAPONEXTRA,CHANF_DEFAULT,pitch:1.5);
return ResolveState(null);
}
XZW2 T 2 { invoker.chargelevel = 0.; }
Goto Ready;
Dummy:
TNT1 A 1 A_ChargeUp();
Wait;
AltFire:
XZW2 A 2
{
A_StartSound("pusher/start",CHAN_WEAPON,CHANF_OVERLAP);
A_StartSound("pusher/motor",CHAN_WEAPONEXTRA,CHANF_LOOP,pitch:1.5);
A_StartSound("pusher/pullback",CHAN_WEAPON,CHANF_OVERLAP);
}
XZW2 UVW 2;
XZW2 X 0 A_BeginCharge();
XZW2 XYZ 3;
XZW3 ABCDEFG 3;
XZW3 H 0
{
A_QuakeEx(1,1,1,8,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:.5);
A_StartSound("pusher/motorend",CHAN_WEAPONEXTRA,CHANF_DEFAULT,pitch:1.5);
}
XZW3 H 3;
Wait;
AltRelease:
#### # 1 A_PusherAlt();
XZW5 R 2;
XZW3 IJKL 2;
XZW3 MNOP 3;
Goto Ready;
AltMiss:
XZW3 QRSTUVW 1;
TNT1 A -1
{
invoker.bNODEATHDESELECT = false;
let nw = player.mo.PickNextWeapon();
// gross hack (don't prioritize Deep Impact if we have something better than it)
if ( nw is 'DeepImpact' )
{
player.ReadyWeapon = nw;
nw = player.mo.PickNextWeapon();
player.ReadyWeapon = invoker;
}
if ( nw != invoker ) player.PendingWeapon = nw;
RemoveInventory(invoker);
invoker.Destroy();
}
Stop;
Reload:
Zoom:
XZW2 A 2
{
A_StartSound("pusher/checkout",CHAN_WEAPON,CHANF_OVERLAP);
A_PlayerCheckGun();
}
XZW3 XYZ 2;
XZW4 ABCDEFGHIJKLMNOPQR 2;
XZW4 STUVWXYZ 3;
Goto Ready;
User1:
XZW2 A 2
{
A_StartSound("demolitionist/wswing",CHAN_WEAPON,CHANF_OVERLAP);
A_PlayerMelee();
}
XZW5 ABC 2;
XZW5 D 1 A_Parry(9);
XZW5 EFGH 1;
XZW5 I 0 A_Melee(70,"demolitionist/whitl",1.1,1.2,1.2);
XZW5 IJ 2;
XZW5 K 2 { invoker.PlayUpSound(self); }
XZW5 LM 2;
XZW5 NOPQ 3;
Goto Ready;
Deselect:
XZW2 B 2 A_StartSound("pusher/deselect",CHAN_WEAPON,CHANF_OVERLAP);
XZW2 CDEF 2;
XZW2 F -1 A_FullLower();
Stop;
}
}

View file

@ -1,376 +0,0 @@
// Pusher projectiles and effects
Class PusherImpact : Actor
{
Default
{
Radius 0.1;
Height 0;
+NOGRAVITY;
+NOCLIP;
+NOTELEPORT;
+NOINTERACTION;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
A_QuakeEx(2,2,2,12,0,200,"",QF_RELATIVE|QF_SCALEDOWN,falloff:100,rollIntensity:.3);
A_StartSound("pusher/hit",CHAN_VOICE);
A_SprayDecal("WallCrack",-20);
int numpt = Random[Pusher](1,3);
Vector3 x = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (x+(FRandom[Pusher](-.8,.8),FRandom[Pusher](-.8,.8),FRandom[Pusher](-.8,.8))).unit()*FRandom[Pusher](.1,1.2);
let s = Spawn("SWWMSmoke",pos);
s.vel = pvel;
s.SetShade(Color(1,1,1)*Random[Pusher](128,192));
}
numpt = Random[Pusher](0,2);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[Pusher](-1,1),FRandom[Pusher](-1,1),FRandom[Pusher](-1,1)).unit()*FRandom[Pusher](2,8);
let s = Spawn("SWWMSpark",pos);
s.vel = pvel;
}
numpt = Random[Pusher](1,3);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[Pusher](-1,1),FRandom[Pusher](-1,1),FRandom[Pusher](-1,1)).unit()*FRandom[Pusher](2,8);
let s = Spawn("SWWMChip",pos);
s.vel = pvel;
}
Destroy();
}
}
Class BigPusherImpact : Actor
{
Default
{
Radius 0.1;
Height 0;
+NOGRAVITY;
+NOCLIP;
+NOTELEPORT;
+NOINTERACTION;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
A_QuakeEx(5,5,5,15,0,300,"",QF_RELATIVE|QF_SCALEDOWN,falloff:200,rollIntensity:.8);
A_StartSound("pusher/althit",CHAN_VOICE);
A_SprayDecal("ImpactMark",-20);
int numpt = Random[Pusher](8,16);
Vector3 x = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (x+(FRandom[Pusher](-.8,.8),FRandom[Pusher](-.8,.8),FRandom[Pusher](-.8,.8))).unit()*FRandom[Pusher](.8,2.6);
let s = Spawn("SWWMSmoke",pos);
s.vel = pvel;
s.SetShade(Color(1,1,1)*Random[Pusher](128,192));
}
numpt = Random[Pusher](4,10);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[Pusher](-1,1),FRandom[Pusher](-1,1),FRandom[Pusher](-1,1)).unit()*FRandom[Pusher](2,12);
let s = Spawn("SWWMSpark",pos);
s.vel = pvel;
}
numpt = Random[Pusher](8,20);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[Pusher](-1,1),FRandom[Pusher](-1,1),FRandom[Pusher](-1,1)).unit()*FRandom[Pusher](2,16);
let s = Spawn("SWWMChip",pos);
s.vel = pvel;
}
Destroy();
}
}
Class PusherProjectile : Actor
{
Vector3 oldvel;
double oldangle, oldpitch;
Actor lasthit;
int hittics;
bool bUsePickup;
Default
{
Obituary "$O_PUSHER";
Speed 50;
Radius 10;
Height 10;
DamageFunction clamp(int(4*vel.length()),0,200);
DamageType 'Tenderize';
BounceType "Hexen";
BounceFactor 1.0;
WallBounceFactor 1.0;
Gravity 0.3;
PROJECTILE;
+USEBOUNCESTATE;
+CANBOUNCEWATER;
+INTERPOLATEANGLES;
+DONTBOUNCEONSHOOTABLES;
-BOUNCEAUTOOFF;
+NODAMAGETHRUST;
-BOUNCEONUNRIPPABLES;
-ALLOWBOUNCEONACTORS;
+RIPPER;
-NOGRAVITY;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
A_StartSound("pusher/fly",CHAN_BODY,CHANF_LOOP,1.,2.);
A_StartSound("pusher/altfire",CHAN_VOICE);
oldvel = vel;
oldangle = angle;
oldpitch = pitch;
}
void A_Reorient()
{
oldvel = vel;
oldangle = angle;
oldpitch = pitch;
if ( vel.length() <= 0. ) return;
Vector3 dir = vel.unit();
angle += clamp(deltaangle(angle,atan2(dir.y,dir.x)),-2,2);
pitch += clamp(deltaangle(pitch,asin(-dir.z)),-2,2);
// cancel if we hit a wall dead-on
FLineTraceData d;
LineTrace(oldangle,30,oldpitch,TRF_THRUACTORS|TRF_NOSKY,5,data:d);
if ( d.HitType != TRACE_HitNone )
{
angle = oldangle;
pitch = oldpitch;
ClearBounce();
special1 = 1;
ExplodeMissile(BlockingLine,BlockingMobj);
}
}
private bool HitSkyLine( Line l, int hitside )
{
if ( !l ) return false;
// if it's onesided, check if it's a Line_Horizon
if ( !l.sidedef[1] ) return (l.special == Line_Horizon);
Sector outs, ins;
if ( hitside )
{
ins = l.backsector;
outs = l.frontsector;
}
else
{
ins = l.frontsector;
outs = l.backsector;
}
// return true if we're in a sector with sky and we hit the upper part of the line
if ( ins.GetTexture(1) != skyflatnum ) return false;
return (outs.ceilingplane.ZAtPoint(pos.xy) <= pos.z);
}
void A_HandleBounce()
{
Vector3 HitNormal = -vel.unit();
F3DFloor ff;
int lineside = 1;
if ( BlockingFloor )
{
// find closest 3d floor for its normal
for ( int i=0; i<BlockingFloor.Get3DFloorCount(); i++ )
{
if ( !(BlockingFloor.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(BlockingFloor.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
ff = BlockingFloor.Get3DFloor(i);
break;
}
if ( ff ) HitNormal = -ff.top.Normal;
else HitNormal = BlockingFloor.floorplane.Normal;
}
else if ( BlockingCeiling )
{
// find closest 3d floor for its normal
for ( int i=0; i<BlockingCeiling.Get3DFloorCount(); i++ )
{
if ( !(BlockingCeiling.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(BlockingCeiling.Get3DFloor(i).bottom.ZAtPoint(pos.xy) ~== ceilingz) ) continue;
ff = BlockingCeiling.Get3DFloor(i);
break;
}
if ( ff ) HitNormal = -ff.bottom.Normal;
else HitNormal = BlockingCeiling.ceilingplane.Normal;
}
else if ( BlockingLine )
{
HitNormal = (-BlockingLine.delta.y,BlockingLine.delta.x,0).unit();
if ( !SWWMUtility.PointOnLineSide(pos.xy,BlockingLine) )
{
lineside = 0;
HitNormal *= -1;
}
}
else if ( BlockingMobj )
{
Vector3 diff = level.Vec3Diff(pos,BlockingMobj.pos);
if ( (pos.x+radius) <= (BlockingMobj.pos.x-BlockingMobj.radius) )
HitNormal = (-1,0,0);
else if ( (pos.x-radius) >= (BlockingMobj.pos.x+BlockingMobj.radius) )
HitNormal = (1,0,0);
else if ( (pos.y+radius) <= (BlockingMobj.pos.y-BlockingMobj.radius) )
HitNormal = (0,-1,0);
else if ( (pos.y-radius) >= (BlockingMobj.pos.y+BlockingMobj.radius) )
HitNormal = (0,1,0);
else if ( pos.z >= (BlockingMobj.pos.z+BlockingMobj.height) )
HitNormal = (0,0,1);
else if ( (pos.z+height) <= BlockingMobj.pos.z )
HitNormal = (0,0,-1);
}
// undo the bounce, we need to hook in our own
angle = oldangle;
pitch = oldpitch;
vel = oldvel;
// try to guess if we hit the sky
if ( HitSkyLine(BlockingLine,lineside) || (BlockingCeiling && (ceilingpic == skyflatnum)) || (BlockingFloor && (floorpic == skyflatnum)) )
{
special1 = 0;
ExplodeMissile();
return;
}
// re-do the bounce with our formula
vel = .8*((vel dot HitNormal)*HitNormal*(-1.8+FRandom[Pusher](.0,.8))+vel);
A_StartSound("pusher/bounce",volume:.3);
A_AlertMonsters(swwm_uncapalert?0:300);
if ( vel.length() < 5 )
{
special1 = 0;
ExplodeMissile();
}
}
void A_BecomePickup()
{
if ( special1 )
{
// stuff from direct hit
FLineTraceData d;
LineTrace(angle,40,pitch,0,5,data:d);
Vector3 HitNormal = -d.HitDir;
if ( d.HitType == TRACE_HitFloor )
{
if ( d.Hit3DFloor ) HitNormal = -d.Hit3DFloor.top.Normal;
else HitNormal = d.HitSector.floorplane.Normal;
}
else if ( d.HitType == TRACE_HitCeiling )
{
if ( d.Hit3DFloor ) HitNormal = -d.Hit3DFloor.bottom.Normal;
else HitNormal = d.HitSector.ceilingplane.Normal;
}
else if ( d.HitType == TRACE_HitWall )
{
HitNormal = (-d.HitLine.delta.y,d.HitLine.delta.x,0).unit();
if ( !d.LineSide ) HitNormal *= -1;
}
let p = Spawn("BigPusherImpact",d.HitLocation+HitNormal*4);
p.angle = atan2(HitNormal.y,HitNormal.x);
p.pitch = asin(-HitNormal.z);
bool busted = false;
if ( swwm_omnibust )
{
if ( BusterWall.BustLinetrace(d,100,target,d.HitDir,d.HitLocation.z) )
busted = true;
}
if ( busted ) pitch = 0.;
else bNOGRAVITY = true;
}
else pitch = 0;
gravity = 1.;
ClearBounce();
bSPECIAL = true;
A_SetSize(20,16);
A_ChangeLinkFlags(0);
A_StopSound(CHAN_BODY);
}
override int DoSpecialDamage( Actor target, int damage, Name damagetype )
{
if ( target == lasthit ) return 0;
lasthit = target;
if ( target.bNOBLOOD || target.bDORMANT || target.bINVULNERABLE ) A_StartSound("pusher/althit",CHAN_WEAPON,CHANF_OVERLAP);
else A_StartSound("pusher/altmeat",CHAN_WEAPON,CHANF_OVERLAP);
target.A_QuakeEx(6,6,6,10,0,200,"",QF_RELATIVE|QF_SCALEDOWN,falloff:100,rollIntensity:.7);
SWWMUtility.DoKnockback(target,vel.unit(),85000);
return damage;
}
override void Touch( Actor toucher )
{
if ( toucher.player && swwm_usetopickup && !bUsePickup )
return;
// cannot pick up swapweapon unless explicitly pressing use
let pw = GetDefaultByType("PusherWeapon");
SWWMWeapon sw;
if ( swwm_swapweapons && (sw = pw.HasSwapWeapon(toucher)) )
{
if ( toucher.CheckLocalView() )
Console.MidPrint(SmallFont,String.Format(StringTable.Localize("$SWWM_SWAPWEAPON"),sw.GetTag(),StringTable.Localize("$T_PUSHER")));
return;
}
let w = toucher.FindInventory("PusherWeapon");
if ( toucher.player && w )
{
let psp = toucher.player.GetPSPrite(PSP_WEAPON);
if ( psp && psp.CurState.InStateSequence(w.FindState("AltMiss")) )
return;
}
if ( !toucher.player || !toucher.GiveInventory("PusherWeapon",1) ) return;
if ( toucher.CheckLocalView() )
{
toucher.A_StartSound("misc/w_pkup",CHAN_ITEM,CHANF_NOPAUSE|CHANF_MAYBE_LOCAL);
let w = toucher.FindInventory("PusherWeapon");
if ( w ) w.PrintPickupMessage(true,w.PickupMessage());
}
else toucher.A_StartSound("misc/w_pkup",CHAN_ITEM,CHANF_MAYBE_LOCAL);
toucher.A_SelectWeapon("PusherWeapon");
Spawn("SWWMRedPickupFlash",pos);
Destroy();
}
override bool Used( Actor user )
{
// test vertical range
Vector3 diff = level.Vec3Diff(user.Vec3Offset(0,0,user.Height/2),Vec3Offset(0,0,Height/2));
double rang = user.player?PlayerPawn(user.player.mo).UseRange:(user.Height/2);
if ( abs(diff.z) > rang ) return false;
// if the toucher owns our SwapWeapon, drop it before picking us up
let pw = GetDefaultByType("PusherWeapon");
SWWMWeapon sw;
if ( swwm_swapweapons && (sw = pw.HasSwapWeapon(user)) )
{
bool swapto = false;
if ( sw == user.player.ReadyWeapon ) swapto = true;
user.DropInventory(sw);
// don't autoswitch just yet (hacky)
if ( swapto )
{
user.player.ReadyWeapon = null;
user.player.PendingWeapon = WP_NOCHANGE;
}
}
bUsePickup = true;
Touch(user);
bUsePickup = false;
return bDestroyed;
}
States
{
Spawn:
XZW1 A 1 A_Reorient();
Wait;
Bounce:
XZW1 A 0 A_HandleBounce();
Goto Spawn;
Death:
XZW1 A 0 A_BecomePickup();
XZW1 A 1 A_JumpIf(pos.z<=floorz,1);
Wait;
XZW1 A -1 A_StartSound("pusher/bounce");
Stop;
}
}

View file

@ -1063,7 +1063,7 @@ Class TheBall : Actor
override void PostBeginPlay()
{
Super.PostBeginPlay();
A_StartSound("pusher/fly",CHAN_WEAPON,CHANF_LOOP,.6,3.,2.);
A_StartSound("spreadgun/ballfly",CHAN_WEAPON,CHANF_LOOP,.6,3.,2.);
heat = 1.;
}
override void Tick()