0.9.10b release (oh boy where do I start):
- New fun options implemented (omnibusting, unlimited fuel, party time) - Biospark Carbine gets a requested nerf - Candygun combo fire has been buffed (watch out for that splash damage) - All powerup effects are additive (stacc 'em) - Automap hud respects gzdoom's cvars for toggling certain elements - Automap hud shows stats and times in gold when 100% / under par - Weapons and ammo are no longer affected by skill amount modifiers, for balance (and to avoid any weird glitches) - Sorting improvements for menu (weapons by slot, ammo by weapons, other items by value, etc.) - Grilled Cheese Sandwich now saves you from lethal falls properly - Blown kisses instakill nazis - Added non-violent Keen replacement (based on "Less mean-spirited Keen replacement" by SiFi270) - Added gib deaths for hell nobles, pinkies, cacos, revs and viles (sprites by Amuscaria and Ryan Cordell) - Blown kisses can activate use switches - Gestures can be chained by pressing a gesture button while another is playing - Fixed Grilled Cheese Sandwich not avoiding telefrags properly (now also works with voodoo dolls) - More precise weapon kill tracking (fixes some ragekit quirks) - Merge both DLC weaponsets, removing redundant weapons (see FuturePlans.md) - Discarded some collectables for the next updates, to save time - Preparation work for collectables update, including some (partial) lore files - Remove ammo fabricators from store, makes no sense to have them when you can just buy ammo directly - Cosmetic Boss Brain sprite replacements, just for fun - 10 more intermission tips, because yes - Added option to reduce distance at which enemy healthbars are picked - Various minor bugfixes and adjustments (and also some tiny typo fixes) - Ragekit now heals over time and with each hit (so it's more rewarding to go wild) - PNG optimization pass (again lol) - Fix crouched gestures having no facial animation
This commit is contained in:
parent
1daf12138f
commit
aabc9de051
471 changed files with 3003 additions and 749 deletions
|
|
@ -1,5 +1,5 @@
|
|||
// Unissix Crafts Blackfire Igniter (from UnSX 4, cut from initial SWWM GZ release)
|
||||
// Slot 6, spawns shared with Hellblazer
|
||||
// Slot 7, spawns shared with Biospark Carbine
|
||||
|
||||
Class BlackfireIgniter : SWWMWeapon
|
||||
{
|
||||
|
|
@ -12,6 +12,18 @@ Class SMW05BigAmmo : SMW05Ammo
|
|||
{
|
||||
}
|
||||
|
||||
Class SheenAmmo : Ammo
|
||||
{
|
||||
}
|
||||
|
||||
Class SheenSmallAmmo: SheenAmmo
|
||||
{
|
||||
}
|
||||
|
||||
Class SheenBigAmmo : SheenAmmo
|
||||
{
|
||||
}
|
||||
|
||||
Class QuadravolAmmo : Ammo
|
||||
{
|
||||
}
|
||||
|
|
@ -24,22 +36,18 @@ Class DarkCanister : Ammo
|
|||
{
|
||||
}
|
||||
|
||||
Class LargeDarkCanister : DarkCanister
|
||||
{
|
||||
}
|
||||
|
||||
Class KinylumUnit : Ammo
|
||||
{
|
||||
}
|
||||
|
||||
Class NokronUnit : Ammo
|
||||
{
|
||||
}
|
||||
|
||||
Class EMPCore : Ammo
|
||||
{
|
||||
}
|
||||
|
||||
Class MadCore : Ammo
|
||||
Class EMPCoreBundleSpawn : Actor
|
||||
{
|
||||
}
|
||||
|
||||
Class RayBolt : MagAmmo
|
||||
{
|
||||
}
|
||||
|
||||
Class RayAmmo : Ammo
|
||||
{
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
// Kmonn Shuna Quadravol (from UnSX series, not a Quadshot reskin anymore)
|
||||
// Slot 5, spawns shared with Eviscerator
|
||||
// Slot 6, spawns shared with Hellblazer
|
||||
|
||||
Class Quadravol : SWWMWeapon
|
||||
{
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
// PROWEL and TADEL artifacts, by Nukritas 2xx of the University of Nos-Kora (from UnSX series, based on nonsensical gibberish)
|
||||
// Slot 9, spawns shared with Candy Gun
|
||||
|
||||
Class PROWELfartsupintheTADEL : SWWMWeapon
|
||||
{
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
// Tach-Engine Technologies Series x3 Sparkster Carbine (UnSX 2)
|
||||
// Slot 7, spawns shared with Legacy Sparkster
|
||||
|
||||
Class ModernSparkster : SWWMWeapon
|
||||
{
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
// All DLC weapon ammo pickups
|
||||
|
||||
Class SheenAmmo : Ammo
|
||||
{
|
||||
}
|
||||
|
||||
Class SheenBigAmmo : SheenAmmo
|
||||
{
|
||||
}
|
||||
|
||||
Class SkullAmmo : Ammo
|
||||
{
|
||||
}
|
||||
|
||||
Class SkullPack : SkullAmmo
|
||||
{
|
||||
}
|
||||
|
||||
Class CryoMag : Ammo
|
||||
{
|
||||
}
|
||||
|
||||
Class CryoBullet : MagAmmo
|
||||
{
|
||||
}
|
||||
|
||||
Class RayAmmo : Ammo
|
||||
{
|
||||
}
|
||||
|
||||
Class RayBundle : RayAmmo
|
||||
{
|
||||
}
|
||||
|
||||
Class AODAmmo : Ammo
|
||||
{
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
// Nuutek Cryolance (from SWWM Platinum Expansion Pack 2)
|
||||
// Slot 8, spawns shared with Silver Bullet JET
|
||||
|
||||
Class Cryolance : SWWMWeapon
|
||||
{
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
// Dr. Locke's Spooky Scary Skeleton Shooter aka "Skull Launcher" (from unreleased "Weird Weapons" UT minimod)
|
||||
// Slot 6, spawns shared with Hellblazer
|
||||
|
||||
Class SkullLauncher : SWWMWeapon
|
||||
{
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
// Angels of Death (from SWWM Platinum Expansion Pack 2)
|
||||
// Slot 0, spawns shared with Ynykron
|
||||
|
||||
Class AODWeapon : SWWMWeapon
|
||||
{
|
||||
}
|
||||
|
|
@ -160,6 +160,11 @@ Mixin Class SWWMAmmo
|
|||
}
|
||||
return Super.HandlePickup(item);
|
||||
}
|
||||
|
||||
default
|
||||
{
|
||||
+INVENTORY.IGNORESKILL;
|
||||
}
|
||||
}
|
||||
|
||||
// Common code for individual bullets
|
||||
|
|
@ -1248,7 +1253,7 @@ Class AmmoFabricator : Inventory abstract
|
|||
int maxb = ib?ib.MaxAmount:GetDefaultByType(b).Amount;
|
||||
double facta = cnta/double(maxa);
|
||||
double factb = cntb/double(maxb);
|
||||
return (facta > factb);
|
||||
return (facta >= factb);
|
||||
}
|
||||
|
||||
private int partition_fabammo( Array<Class<Ammo> > a, int l, int h )
|
||||
|
|
@ -1293,7 +1298,7 @@ Class AmmoFabricator : Inventory abstract
|
|||
if ( !(def.Stamina) || (def.Stamina > maxunitprice) ) continue;
|
||||
available.Push(a);
|
||||
}
|
||||
// sort by "need weight" (prioritize ammo that the player lacks over ammo that te player has plenty of
|
||||
// sort by "need weight" (prioritize ammo that the player lacks over ammo that the player has plenty of
|
||||
qsort_fabammo(available,0,available.Size()-1);
|
||||
// loop through until we fill the inventory or run out of budget
|
||||
bool given = false;
|
||||
|
|
@ -1381,7 +1386,6 @@ Class FabricatorTier1 : AmmoFabricator
|
|||
AmmoFabricator.Budget 5000;
|
||||
AmmoFabricator.PerType 2;
|
||||
AmmoFabricator.MaxUnitPrice 2500;
|
||||
Stamina 3000;
|
||||
}
|
||||
}
|
||||
Class FabricatorTier2 : AmmoFabricator
|
||||
|
|
@ -1397,7 +1401,6 @@ Class FabricatorTier2 : AmmoFabricator
|
|||
AmmoFabricator.Budget 15000;
|
||||
AmmoFabricator.PerType 4;
|
||||
AmmoFabricator.MaxUnitPrice 10000;
|
||||
Stamina 12000;
|
||||
}
|
||||
}
|
||||
Class FabricatorTier3 : AmmoFabricator
|
||||
|
|
@ -1413,7 +1416,6 @@ Class FabricatorTier3 : AmmoFabricator
|
|||
AmmoFabricator.Budget 150000;
|
||||
AmmoFabricator.PerType 8;
|
||||
AmmoFabricator.MaxUnitPrice 80000;
|
||||
Stamina 150000;
|
||||
}
|
||||
}
|
||||
Class FabricatorTier4 : AmmoFabricator
|
||||
|
|
@ -1428,7 +1430,6 @@ Class FabricatorTier4 : AmmoFabricator
|
|||
AmmoFabricator.PerType int.max;
|
||||
AmmoFabricator.MaxUnitPrice int.max;
|
||||
-INVENTORY.AUTOACTIVATE;
|
||||
Stamina 1920000;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -331,6 +331,7 @@ Class HellblazerMissile : Actor
|
|||
s.scale *= FRandom[Hellblazer](0.9,1.8);
|
||||
}
|
||||
Spawn("HellblazerRing",pos);
|
||||
if ( swwm_omnibust ) BusterWall.ProjectileBust(self,350,(cos(angle)*cos(pitch),sin(angle)*cos(pitch),sin(-pitch)));
|
||||
}
|
||||
|
||||
void A_SubExpl( double xscale = 1. )
|
||||
|
|
@ -438,6 +439,7 @@ Class HellblazerCrackshot : HellblazerMissile
|
|||
c.target = target;
|
||||
c.ReactionTime += Random[Hellblazer](-10,10);
|
||||
}
|
||||
if ( swwm_omnibust ) BusterWall.ProjectileBust(self,300,(cos(angle)*cos(pitch),sin(angle)*cos(pitch),sin(-pitch)));
|
||||
}
|
||||
|
||||
States
|
||||
|
|
@ -496,6 +498,7 @@ Class HellblazerRavager : HellblazerMissile
|
|||
s.scale *= FRandom[Hellblazer](0.9,1.8);
|
||||
}
|
||||
Spawn("HellblazerRing",pos);
|
||||
if ( swwm_omnibust ) BusterWall.ProjectileBust(self,400,(cos(angle)*cos(pitch),sin(angle)*cos(pitch),sin(-pitch)));
|
||||
}
|
||||
|
||||
void A_RavagerSub()
|
||||
|
|
@ -574,6 +577,7 @@ Class HellblazerWarhead : HellblazerMissile
|
|||
s.scale *= FRandom[Hellblazer](0.9,1.8);
|
||||
}
|
||||
Spawn("HellblazerRing2",pos);
|
||||
if ( swwm_omnibust ) BusterWall.ProjectileBust(self,2000,(cos(angle)*cos(pitch),sin(angle)*cos(pitch),sin(-pitch)));
|
||||
}
|
||||
|
||||
void A_WarheadSub()
|
||||
|
|
|
|||
|
|
@ -584,6 +584,81 @@ Class PurpleBloodReference : Actor
|
|||
}
|
||||
}
|
||||
|
||||
// bare actor used for extra gib deaths
|
||||
Class ExtraGibDeaths : Actor
|
||||
{
|
||||
StateLabel gibstate;
|
||||
|
||||
static void GibThis( Actor a, Statelabel st )
|
||||
{
|
||||
if ( !a ) return;
|
||||
let g = ExtraGibDeaths(Spawn("ExtraGibDeaths"));
|
||||
g.master = a;
|
||||
g.gibstate = st;
|
||||
}
|
||||
|
||||
void A_DoGib()
|
||||
{
|
||||
if ( !master ) return;
|
||||
master.SetState(FindState(gibstate));
|
||||
}
|
||||
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
TNT1 A 1 NoDelay;
|
||||
TNT1 A 1 A_DoGib();
|
||||
Stop;
|
||||
DemonXDeath:
|
||||
SARX A 5;
|
||||
SARX B 5 A_XScream();
|
||||
SARX C 5 A_NoBlocking();
|
||||
SARX DEF 5;
|
||||
SARX G -1;
|
||||
Stop;
|
||||
KnightXDeath:
|
||||
BO2X A 5;
|
||||
BO2X B 5 A_XScream();
|
||||
BO2X C 5;
|
||||
BO2X D 5 A_NoBlocking();
|
||||
BO2X EFGH 5;
|
||||
BO2X I -1;
|
||||
Stop;
|
||||
BaronXDeath:
|
||||
BOSX A 5;
|
||||
BOSX B 5 A_XScream();
|
||||
BOSX C 5;
|
||||
BOSX D 5 A_NoBlocking();
|
||||
BOSX EFGH 5;
|
||||
BOSX I -1 A_BossDeath();
|
||||
Stop;
|
||||
CacoXDeath:
|
||||
CACX A 5;
|
||||
CACX B 5 A_XScream();
|
||||
CACX C 5 A_NoBlocking();
|
||||
CACX D 4;
|
||||
CACX E 3;
|
||||
CACX F 4;
|
||||
CACX G 5;
|
||||
CACX H -1;
|
||||
Stop;
|
||||
BonerXDeath:
|
||||
REVX A 3;
|
||||
REVX B 4 A_XScream();
|
||||
REVX C 5 A_NoBlocking();
|
||||
REVX DE 5;
|
||||
REVX F -1;
|
||||
Stop;
|
||||
VileXDeath:
|
||||
VILX A 5;
|
||||
VILX B 5 A_XScream();
|
||||
VILX C 5 A_NoBlocking();
|
||||
VILX DEF 5;
|
||||
VILX G -1;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
// corpse thump handler
|
||||
Class CorpseFallTracker : Thinker
|
||||
{
|
||||
|
|
@ -749,6 +824,28 @@ Class SWWMGoreHandler : EventHandler
|
|||
e.Thing.CopyBloodColor(pb);
|
||||
pb.Destroy();
|
||||
}
|
||||
else if ( e.Thing.GetClass() == "LostSoul" )
|
||||
e.Thing.bNOBLOOD = true;
|
||||
}
|
||||
|
||||
override void WorldThingDied( WorldEvent e )
|
||||
{
|
||||
// force insert gib animations on some vanilla Doom monsters
|
||||
int gibhealth = e.Thing.GetGibHealth();
|
||||
bool gotgibbed = (!e.Thing.bDONTGIB && ((e.Inflictor && e.Inflictor.bEXTREMEDEATH) || (e.DamageSource && e.DamageSource.bEXTREMEDEATH) || (e.DamageType == 'Extreme') || (e.Thing.Health < gibhealth)) && (!e.Inflictor || !e.Inflictor.bNOEXTREMEDEATH) && (!e.DamageSource || !e.DamageSource.bNOEXTREMEDEATH));
|
||||
if ( !gotgibbed ) return;
|
||||
if ( (e.Thing.GetClass() == "Demon") || (e.Thing.GetClass() == "Spectre") )
|
||||
ExtraGibDeaths.GibThis(e.Thing,"DemonXDeath");
|
||||
else if ( e.Thing.GetClass() == "HellKnight" )
|
||||
ExtraGibDeaths.GibThis(e.Thing,"KnightXDeath");
|
||||
else if ( e.Thing.GetClass() == "BaronOfHell" )
|
||||
ExtraGibDeaths.GibThis(e.Thing,"BaronXDeath");
|
||||
else if ( e.Thing.GetClass() == "Cacodemon" )
|
||||
ExtraGibDeaths.GibThis(e.Thing,"CacoXDeath");
|
||||
else if ( e.Thing.GetClass() == "Revenant" )
|
||||
ExtraGibDeaths.GibThis(e.Thing,"BonerXDeath");
|
||||
else if ( e.Thing.GetClass() == "Archvile" )
|
||||
ExtraGibDeaths.GibThis(e.Thing,"VileXDeath");
|
||||
}
|
||||
|
||||
override void WorldThingDamaged( WorldEvent e )
|
||||
|
|
@ -756,6 +853,14 @@ Class SWWMGoreHandler : EventHandler
|
|||
if ( e.Thing.Health > 0 ) return;
|
||||
// no gib if it was erased
|
||||
if ( e.DamageType == 'Ynykron' ) return;
|
||||
int gibhealth = e.Thing.GetGibHealth();
|
||||
bool gotgibbed = (!e.Thing.bDONTGIB && ((e.Inflictor && e.Inflictor.bEXTREMEDEATH) || (e.DamageSource && e.DamageSource.bEXTREMEDEATH) || (e.DamageType == 'Extreme') || (e.Thing.Health < gibhealth)) && (!e.Inflictor || !e.Inflictor.bNOEXTREMEDEATH) && (!e.DamageSource || !e.DamageSource.bNOEXTREMEDEATH));
|
||||
bool forcegibbed = false;
|
||||
// force gib availability for some vanilla Doom monsters
|
||||
if ( gotgibbed && ((e.Thing.GetClass() == "Demon") || (e.Thing.GetClass() == "Spectre") || (e.Thing.GetClass() == "HellKnight") || (e.Thing.GetClass() == "BaronOfHell") || (e.Thing.GetClass() == "Cacodemon") || (e.Thing.GetClass() == "Revenant") || (e.Thing.GetClass() == "Archvile")) )
|
||||
forcegibbed = true;
|
||||
if ( !e.Thing.FindState("XDeath",true) && !e.Thing.FindState("Death.Extreme",true) && !forcegibbed )
|
||||
gotgibbed = false;
|
||||
// only do special handling if they use our blood
|
||||
if ( (e.Thing.GetBloodType(0) != "mkBlood") || e.Thing.bNOBLOOD )
|
||||
return;
|
||||
|
|
@ -782,8 +887,7 @@ Class SWWMGoreHandler : EventHandler
|
|||
return;
|
||||
}
|
||||
// override gibbing
|
||||
int gibhealth = e.Thing.GetGibHealth();
|
||||
if ( !e.Thing.bDONTGIB && (e.Thing.FindState("XDeath",true) || e.Thing.FindState("Death.Extreme",true)) && ((e.Inflictor && e.Inflictor.bEXTREMEDEATH) || (e.DamageSource && e.DamageSource.bEXTREMEDEATH) || (e.DamageType == 'Extreme') || (e.Thing.Health < gibhealth)) && (!e.Inflictor || !e.Inflictor.bNOEXTREMEDEATH) && (!e.DamageSource || !e.DamageSource.bNOEXTREMEDEATH) )
|
||||
if ( gotgibbed )
|
||||
{
|
||||
[b,a] = e.Thing.A_SpawnItemEx("mkGibber",flags:SXF_USEBLOODCOLOR);
|
||||
if ( !b ) return;
|
||||
|
|
|
|||
|
|
@ -429,6 +429,7 @@ Class BustedQuake : Actor
|
|||
if ( special1 < 3 ) A_StartSound("wallbuster/smallbust",CHAN_VOICE,CHANF_OVERLAP,min(1.,special1*.32),1./max(1.,special1*.35),1.-special1*.05);
|
||||
else A_StartSound("wallbuster/bigbust",CHAN_VOICE,CHANF_OVERLAP,min(1.,special1*.16),1./max(1.,special1*.35),1.-special1*.03);
|
||||
A_QuakeEx(special1,special1,special1,20+special1*5,0,300+special1*90,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:special1*.1);
|
||||
A_AlertMonsters(2500);
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
|
|
@ -453,7 +454,7 @@ Class BusterWall : Thinker
|
|||
int hitplane;
|
||||
bool busted;
|
||||
Vector3 bustdir;
|
||||
int busttics;
|
||||
int busttics, delay;
|
||||
double cutheight;
|
||||
// cached
|
||||
Vector3 boundsmin, boundsmax, step;
|
||||
|
|
@ -472,7 +473,12 @@ Class BusterWall : Thinker
|
|||
return;
|
||||
}
|
||||
// fade out damage
|
||||
accdamage = int(accdamage*.9-10);
|
||||
if ( delay > 0 )
|
||||
{
|
||||
delay--;
|
||||
return;
|
||||
}
|
||||
accdamage = int(accdamage*.9-5);
|
||||
if ( accdamage <= 0 )
|
||||
{
|
||||
Destroy();
|
||||
|
|
@ -522,13 +528,17 @@ Class BusterWall : Thinker
|
|||
|
||||
private static bool IsIOSWall( Line l )
|
||||
{
|
||||
TextureID facetex[5];
|
||||
TextureID facetex[9];
|
||||
facetex[0] = TexMan.CheckForTexture("ZZZFACE1",TexMan.Type_Wall);
|
||||
facetex[1] = TexMan.CheckForTexture("ZZZFACE2",TexMan.Type_Wall);
|
||||
facetex[2] = TexMan.CheckForTexture("ZZZFACE3",TexMan.Type_Wall);
|
||||
facetex[3] = TexMan.CheckForTexture("ZZZFACE4",TexMan.Type_Wall);
|
||||
facetex[4] = TexMan.CheckForTexture("ZZZFACE5",TexMan.Type_Wall);
|
||||
for ( int i=0; i<5; i++ )
|
||||
facetex[5] = TexMan.CheckForTexture("DBRAIN1",TexMan.Type_Wall);
|
||||
facetex[6] = TexMan.CheckForTexture("DBRAIN2",TexMan.Type_Wall);
|
||||
facetex[7] = TexMan.CheckForTexture("DBRAIN3",TexMan.Type_Wall);
|
||||
facetex[8] = TexMan.CheckForTexture("DBRAIN4",TexMan.Type_Wall);
|
||||
for ( int i=0; i<9; i++ )
|
||||
{
|
||||
for ( int j=0; j<3; j++ )
|
||||
{
|
||||
|
|
@ -539,6 +549,88 @@ Class BusterWall : Thinker
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool ProjectileBust( Actor a, int accdamage, Vector3 x )
|
||||
{
|
||||
LineTracer faketracer = new("LineTracer");
|
||||
F3DFloor ff;
|
||||
Vector3 HitNormal;
|
||||
if ( a.BlockingFloor )
|
||||
{
|
||||
// find closest 3d floor for its normal
|
||||
for ( int i=0; i<a.BlockingFloor.Get3DFloorCount(); i++ )
|
||||
{
|
||||
if ( !(a.BlockingFloor.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
|
||||
if ( !(a.BlockingFloor.Get3DFloor(i).top.ZAtPoint(a.pos.xy) ~== a.floorz) ) continue;
|
||||
ff = a.BlockingFloor.Get3DFloor(i);
|
||||
break;
|
||||
}
|
||||
if ( ff )
|
||||
{
|
||||
faketracer.Results.ffloor = ff;
|
||||
HitNormal = -ff.top.Normal;
|
||||
}
|
||||
else HitNormal = a.BlockingFloor.floorplane.Normal;
|
||||
faketracer.Results.HitType = TRACE_HitFloor;
|
||||
faketracer.Results.HitSector = a.BlockingFloor;
|
||||
}
|
||||
else if ( a.BlockingCeiling )
|
||||
{
|
||||
// find closest 3d floor for its normal
|
||||
for ( int i=0; i<a.BlockingCeiling.Get3DFloorCount(); i++ )
|
||||
{
|
||||
if ( !(a.BlockingCeiling.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
|
||||
if ( !(a.BlockingCeiling.Get3DFloor(i).bottom.ZAtPoint(a.pos.xy) ~== a.ceilingz) ) continue;
|
||||
ff = a.BlockingCeiling.Get3DFloor(i);
|
||||
break;
|
||||
}
|
||||
if ( ff )
|
||||
{
|
||||
faketracer.Results.ffloor = ff;
|
||||
HitNormal = -ff.bottom.Normal;
|
||||
}
|
||||
else HitNormal = a.BlockingCeiling.ceilingplane.Normal;
|
||||
faketracer.Results.HitType = TRACE_HitCeiling;
|
||||
faketracer.Results.HitSector = a.BlockingCeiling;
|
||||
}
|
||||
else if ( a.BlockingLine )
|
||||
{
|
||||
HitNormal = (-a.BlockingLine.delta.y,a.BlockingLine.delta.x,0).unit();
|
||||
int wside = SWWMUtility.PointOnLineSide(a.pos.xy,a.BlockingLine);
|
||||
if ( !wside ) HitNormal *= -1;
|
||||
faketracer.Results.HitType = TRACE_HitWall;
|
||||
faketracer.Results.HitLine = a.BlockingLine;
|
||||
faketracer.Results.Side = wside;
|
||||
faketracer.Results.Tier = TIER_Middle;
|
||||
// guess the tier hit
|
||||
if ( a.BlockingLine.sidedef[1] )
|
||||
{
|
||||
double ceil = a.BlockingLine.sidedef[!wside].sector.ceilingplane.ZAtPoint(a.pos.xy);
|
||||
double flor = a.BlockingLine.sidedef[!wside].sector.floorplane.ZAtPoint(a.pos.xy);
|
||||
if ( a.pos.z >= ceil ) faketracer.Results.Tier = TIER_Upper;
|
||||
else if ( (a.pos.z+a.Height) <= flor ) faketracer.Results.Tier = TIER_Lower;
|
||||
}
|
||||
}
|
||||
else if ( a.BlockingMobj )
|
||||
{
|
||||
Vector3 diff = level.Vec3Diff(a.BlockingMobj.Vec3Offset(0,0,a.BlockingMobj.Height/2),a.pos);
|
||||
HitNormal = diff.unit();
|
||||
faketracer.Results.HitType = TRACE_HitActor;
|
||||
}
|
||||
return Bust(faketracer.Results,accdamage,a.target,x,a.pos.z+a.Height/2.);
|
||||
}
|
||||
|
||||
static bool BustLinetrace( FLineTraceData d, int accdamage, Actor instigator, Vector3 x, double hitz )
|
||||
{
|
||||
LineTracer faketracer = new("LineTracer");
|
||||
faketracer.Results.HitType = d.HitType;
|
||||
faketracer.Results.HitSector = d.HitSector;
|
||||
faketracer.Results.HitLine = d.HitLine;
|
||||
faketracer.Results.ffloor = d.Hit3DFloor;
|
||||
faketracer.Results.Side = d.LineSide;
|
||||
faketracer.Results.Tier = (d.LinePart==Side.Top)?TIER_UPPER:(d.LinePart==Side.Bottom)?TIER_LOWER:TIER_Middle;
|
||||
return Bust(faketracer.Results,accdamage,instigator,x,hitz);
|
||||
}
|
||||
|
||||
static bool Bust( TraceResults d, int accdamage, Actor instigator, Vector3 x, double hitz )
|
||||
{
|
||||
// we can't blow up 3D floors (yet)
|
||||
|
|
@ -586,6 +678,7 @@ Class BusterWall : Thinker
|
|||
bust.bustdir = x;
|
||||
mnew = true;
|
||||
}
|
||||
bust.delay = max(bust.delay,5+min(20,accdamage>>4));
|
||||
bust.accdamage += accdamage;
|
||||
bust.acchits.Push(accdamage);
|
||||
bust.bustdir = (bust.bustdir+x)*.5;
|
||||
|
|
@ -614,7 +707,7 @@ Class BusterWall : Thinker
|
|||
// skip if already busted
|
||||
if ( bust.busted ) return true;
|
||||
// not enough total damage
|
||||
if ( bust.accdamage < 1000 ) return false;
|
||||
if ( bust.accdamage < 100 ) return false;
|
||||
// estimate sector volume
|
||||
Vector2 a = (32767,32767), b = (-32768,-32768);
|
||||
for ( int i=0; i<hs.lines.Size(); i++ )
|
||||
|
|
@ -753,9 +846,9 @@ Class BusterWall : Thinker
|
|||
// damnums
|
||||
Vector3 bcenter = (bust.boundsmin+bust.boundsmax)*.5;
|
||||
if ( CVar.GetCVar('swwm_accdamage',players[consoleplayer]).GetBool() )
|
||||
SWWMScoreObj.Spawn(bust.accdamage,level.Vec3Offset(bcenter,(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8))),Font.CR_RED);
|
||||
SWWMScoreObj.Spawn(-bust.accdamage,level.Vec3Offset(bcenter,(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8))),Font.CR_RED);
|
||||
else for ( int i=0; i<bust.acchits.Size(); i++ )
|
||||
SWWMScoreObj.Spawn(bust.acchits[i],level.Vec3Offset(bcenter,(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8))),Font.CR_RED);
|
||||
SWWMScoreObj.Spawn(-bust.acchits[i],level.Vec3Offset(bcenter,(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8))),Font.CR_RED);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -949,12 +1042,15 @@ Class Wallbuster : SWWMWeapon
|
|||
A_OverlayFlags(PSP_FLASH-index,PSPF_RENDERSTYLE|PSPF_FORCESTYLE,true);
|
||||
A_OverlayRenderStyle(PSP_FLASH-index,STYLE_Add);
|
||||
}
|
||||
action void ProcessTraceHit( SpreadgunTracer t, Vector3 origin, Vector3 dir, int dmg, double mm, Class<Actor> impact = "SpreadImpact", int bc = 1, bool large = false )
|
||||
action void ProcessTraceHit( SpreadgunTracer t, Vector3 origin, Vector3 dir, int dmg, double mm, Class<Actor> impact = "SpreadImpact", int bc = 1, bool large = false, bool bust = false )
|
||||
{
|
||||
// Wall busting
|
||||
int bustdmg = dmg;
|
||||
if ( t is 'SpreadSlugTracer' ) bustdmg = int(SpreadSlugTracer(t).penetration);
|
||||
BusterWall.Bust(t.Results,bustdmg,self,t.Results.HitVector,t.Results.HitPos.z);
|
||||
if ( bust )
|
||||
{
|
||||
int bustdmg = dmg;
|
||||
if ( t is 'SpreadSlugTracer' ) bustdmg = int(SpreadSlugTracer(t).penetration);
|
||||
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);
|
||||
|
|
@ -1164,7 +1260,7 @@ Class Wallbuster : SWWMWeapon
|
|||
sst.shootthroughlist.Clear();
|
||||
sst.waterhitlist.Clear();
|
||||
sst.Trace(origin,level.PointInSector(origin.xy),dir,8000.,TRACE_HitSky);
|
||||
ProcessTraceHit(sst,origin,dir,0,12000,"SlugImpact",1+howmany/8,true);
|
||||
ProcessTraceHit(sst,origin,dir,0,12000,"SlugImpact",1+howmany/8,true,(howmany>1));
|
||||
for ( int i=0; i<(3-howmany/10); i++ )
|
||||
{
|
||||
let s = Spawn("SWWMViewSmoke",origin);
|
||||
|
|
@ -1202,7 +1298,7 @@ Class Wallbuster : SWWMWeapon
|
|||
b.pitch = asin(-x2.z);
|
||||
b.Stamina += howmany*16;
|
||||
b.Accuracy += 2+howmany/5;
|
||||
b.Args[1] = 1; // came from wallbuster
|
||||
b.Args[1] = (howmany>1)?2:1; // came from wallbuster
|
||||
}
|
||||
for ( int i=0; i<(9-howmany/3); i++ )
|
||||
{
|
||||
|
|
@ -1240,7 +1336,7 @@ Class Wallbuster : SWWMWeapon
|
|||
p.angle = atan2(dir.y,dir.x);
|
||||
p.pitch = asin(-dir.z);
|
||||
p.vel = dir*p.speed*1.25;
|
||||
p.special1 = 1; // came from wallbuster
|
||||
p.special1 = (howmany>1)?2:1; // came from wallbuster
|
||||
for ( int i=0; i<(4-howmany/8); i++ )
|
||||
{
|
||||
let s = Spawn("SWWMViewSmoke",origin);
|
||||
|
|
@ -1283,7 +1379,7 @@ Class Wallbuster : SWWMWeapon
|
|||
st.shootthroughlist.Clear();
|
||||
st.waterhitlist.Clear();
|
||||
st.Trace(origin,level.PointInSector(origin.xy),dir,8000.,TRACE_HitSky);
|
||||
ProcessTraceHit(st,origin,dir,individualdmg,7000,bc:5+howmany/6);
|
||||
ProcessTraceHit(st,origin,dir,individualdmg,7000,bc:5+howmany/6,false,(howmany>1));
|
||||
}
|
||||
for ( int i=0; i<(9-howmany/3); i++ )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -18,10 +18,117 @@ enum ESWWMGZChannels
|
|||
// Future planning, will be filled out with AI stuff and whatnot someday
|
||||
Class SWWMMonster : Actor
|
||||
{
|
||||
// integrated fun tags
|
||||
virtual clearscope String GetFunTag( String defstr = "" )
|
||||
{
|
||||
return GetTag(defstr);
|
||||
}
|
||||
|
||||
// the function that should be overriden in subclasses
|
||||
virtual int HandleLocationalDamage( Actor inflictor, Actor source, int damage, Name mod, Vector3 HitLocation, int flags = 0, double angle = 0 )
|
||||
{
|
||||
return damage;
|
||||
}
|
||||
|
||||
// locational damage support, akin to UE1, but hitlocation will be treated as a relative offset, to make things easier
|
||||
// this one should be called directly by everything in this mod, when possible
|
||||
int LocationalDamageMobj( Actor inflictor, Actor source, int damage, Name mod, Vector3 HitLocation, int flags = 0, double angle = 0 )
|
||||
{
|
||||
damage = HandleLocationalDamage(inflictor,source,damage,mod,HitLocation,flags,angle);
|
||||
return Super.DamageMobj(inflictor,source,damage,mod,flags,angle);
|
||||
}
|
||||
|
||||
// "estimated" locational damage for the vanilla DamageMobj
|
||||
override int DamageMobj( Actor inflictor, Actor source, int damage, Name mod, int flags, double angle )
|
||||
{
|
||||
Vector3 guesspos = (0,0,Height/2.);
|
||||
// use inflictor if available, as it may be a projectile or hitscan puff
|
||||
// if damage comes from an item, use owner
|
||||
// all of this could be done better (or implemented as an engine feature), but whatever
|
||||
Actor whomst = inflictor?inflictor:source;
|
||||
if ( whomst is 'Inventory' ) whomst = Inventory(whomst).Owner;
|
||||
if ( whomst )
|
||||
{
|
||||
if ( whomst.bMISSILE || (flags&DMG_INFLICTOR_IS_PUFF) )
|
||||
guesspos = level.Vec3Diff(pos,whomst.pos);
|
||||
else guesspos = level.Vec3Diff(pos,whomst.Vec3Offset(0,0,whomst.Height/2));
|
||||
guesspos.x = clamp(guesspos.x,-radius,radius);
|
||||
guesspos.y = clamp(guesspos.y,-radius,radius);
|
||||
guesspos.z = clamp(guesspos.z,0,height);
|
||||
}
|
||||
return LocationalDamageMobj(inflictor,source,damage,mod,guesspos,flags,angle);
|
||||
}
|
||||
}
|
||||
|
||||
// Less mean-spirited Keen
|
||||
Class SWWMHangingKeen : Actor
|
||||
{
|
||||
action void A_DropKeen()
|
||||
{
|
||||
Spawn("SWWMDroppedKeen",Vec3Offset(0,0,8));
|
||||
}
|
||||
Default
|
||||
{
|
||||
Tag "$FN_KEEN";
|
||||
Health 100;
|
||||
Radius 10;
|
||||
Height 54;
|
||||
Mass int.max;
|
||||
PainChance 256;
|
||||
+SOLID;
|
||||
+SPAWNCEILING;
|
||||
+NOGRAVITY;
|
||||
+SHOOTABLE;
|
||||
+NOICEDEATH;
|
||||
+DONTFALL;
|
||||
+NOBLOOD;
|
||||
+DONTTHRUST;
|
||||
PainSound "keen/pain";
|
||||
DeathSound "keen/death";
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
KEE2 A -1;
|
||||
Stop;
|
||||
Death:
|
||||
KEE2 A 6;
|
||||
KEE2 B 6 A_DropKeen();
|
||||
KEE2 C 6 A_Scream();
|
||||
KEE2 DE 6;
|
||||
KEE2 F 30;
|
||||
KEE2 F -1 A_KeenDie();
|
||||
Stop;
|
||||
Pain:
|
||||
KEE2 G 4;
|
||||
KEE2 G 8 A_Pain();
|
||||
Goto Spawn;
|
||||
}
|
||||
}
|
||||
Class SWWMDroppedKeen : Actor
|
||||
{
|
||||
Default
|
||||
{
|
||||
Radius 10;
|
||||
Height 32;
|
||||
Gravity .5;
|
||||
+NOBLOCKMAP;
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
KEE3 A 1 A_JumpIf(pos.z<=floorz,1);
|
||||
Wait;
|
||||
KEE3 B 1 { vel.z = 4; }
|
||||
KEE3 B 1 A_JumpIf(pos.z<=floorz,1);
|
||||
Wait;
|
||||
KEE3 B 1 { vel.z = 2; }
|
||||
KEE3 B 1 A_JumpIf(pos.z<=floorz,1);
|
||||
Wait;
|
||||
KEE3 B 12;
|
||||
TNT1 A 1 { Spawn("TeleportFog",pos,ALLOW_REPLACE); }
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
// imitates UE1 light type LT_TexturePaletteOnce/LT_TexturePaletteLoop
|
||||
|
|
|
|||
|
|
@ -228,6 +228,7 @@ Class EvisceratorChunk : Actor
|
|||
Vector3 diff = level.Vec3Diff(BlockingMobj.Vec3Offset(0,0,BlockingMobj.Height/2),pos);
|
||||
HitNormal = diff.unit();
|
||||
}
|
||||
if ( swwm_omnibust ) BusterWall.ProjectileBust(self,GetMissileDamage(0,0),oldvel.unit());
|
||||
// undo the bounce, we need to hook in our own
|
||||
vel = oldvel;
|
||||
// re-do the bounce with our formula
|
||||
|
|
@ -241,6 +242,7 @@ Class EvisceratorChunk : Actor
|
|||
let l = Spawn("ChunkImpact",pos);
|
||||
l.angle = atan2(HitNormal.y,HitNormal.x);
|
||||
l.pitch = asin(-HitNormal.z);
|
||||
A_StartSound("eviscerator/hith",CHAN_WEAPON,CHANF_OVERLAP);
|
||||
}
|
||||
A_Gravity();
|
||||
gravity = .35;
|
||||
|
|
@ -263,14 +265,14 @@ Class EvisceratorChunk : Actor
|
|||
if ( !target.bNOBLOOD && !target.bINVULNERABLE )
|
||||
{
|
||||
target.SpawnBlood(pos,AngleTo(target),damage);
|
||||
A_StartSound("eviscerator/hitf",CHAN_WEAPON,CHANF_OVERLAP,.1);
|
||||
A_StartSound("eviscerator/hitf",CHAN_WEAPON,CHANF_OVERLAP,.2);
|
||||
}
|
||||
else
|
||||
{
|
||||
let l = Spawn("ChunkImpact",pos);
|
||||
l.angle = angle+180;
|
||||
l.pitch = -pitch;
|
||||
A_StartSound("eviscerator/hit",CHAN_WEAPON,CHANF_OVERLAP,.1);
|
||||
A_StartSound("eviscerator/hith",CHAN_WEAPON,CHANF_OVERLAP,.2);
|
||||
}
|
||||
if ( swwm_extraalert || !Random[Eviscerator](0,3) ) A_AlertMonsters(900);
|
||||
return -1;
|
||||
|
|
@ -298,14 +300,14 @@ Class EvisceratorChunk : Actor
|
|||
if ( !victim.bNOBLOOD && !victim.bINVULNERABLE )
|
||||
{
|
||||
victim.SpawnBlood(pos,AngleTo(victim),damage);
|
||||
A_StartSound("eviscerator/hitf",CHAN_WEAPON,CHANF_OVERLAP,.1);
|
||||
A_StartSound("eviscerator/hitf",CHAN_WEAPON,CHANF_OVERLAP,.2);
|
||||
}
|
||||
else
|
||||
{
|
||||
let l = Spawn("ChunkImpact",pos);
|
||||
l.angle = angle+180;
|
||||
l.pitch = -pitch;
|
||||
A_StartSound("eviscerator/hit",CHAN_WEAPON,CHANF_OVERLAP,.1);
|
||||
A_StartSound("eviscerator/hith",CHAN_WEAPON,CHANF_OVERLAP,.2);
|
||||
}
|
||||
}
|
||||
vel *= .65; // reduce velocity as it rips
|
||||
|
|
@ -458,6 +460,7 @@ Class EvisceratorProj : Actor
|
|||
s.scale *= FRandom[Eviscerator](0.9,1.8);
|
||||
}
|
||||
Spawn("EvisceratorRing",pos);
|
||||
if ( swwm_omnibust ) BusterWall.ProjectileBust(self,150,(cos(angle)*cos(pitch),sin(angle)*cos(pitch),sin(-pitch)));
|
||||
}
|
||||
action void A_SubExpl()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -645,6 +645,7 @@ Class YnykronBeam : Actor
|
|||
b.pitch = asin(-norm.z);
|
||||
b.A_SprayDecal("YnykronBlast",-172);
|
||||
if ( YnykronShot(master) ) YnykronShot(master).blastcount++;
|
||||
if ( swwm_omnibust ) BusterWall.Bust(t.Results,int.max,target,t.Results.HitVector,t.Results.HitPos.z);
|
||||
// find exit point
|
||||
int maxdist = (25600-special1);
|
||||
int i;
|
||||
|
|
@ -893,6 +894,7 @@ Class DelayedWallBeam : Actor
|
|||
}
|
||||
else at.Results.HitLine.Activate(tracer,at.Results.Side,SPAC_Impact);
|
||||
}
|
||||
if ( swwm_omnibust ) BusterWall.Bust(at.Results,int.max,target,-at.Results.HitVector,at.Results.HitPos.z);
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
|
@ -1549,6 +1551,7 @@ Class YnykronLightningArc : Actor
|
|||
s.target = target;
|
||||
s.angle = atan2(normal.y,normal.x);
|
||||
s.pitch = asin(-normal.z);
|
||||
if ( swwm_omnibust ) BusterWall.Bust(t.Results,GetMissileDamage(0,0),target,t.Results.HitVector,t.Results.HitPos.z);
|
||||
}
|
||||
invoker.nextpos = t.Results.HitPos;
|
||||
bAMBUSH = true;
|
||||
|
|
@ -2278,15 +2281,7 @@ Class YnykronSingularity : Actor
|
|||
{
|
||||
// force use the sandwich, warp to safe spot
|
||||
let gc = GrilledCheeseSandwich(a.FindInventory("GrilledCheeseSandwich"));
|
||||
Spawn("SWWMItemFog",a.Vec3Offset(0,0,a.Height/2));
|
||||
Vector3 safepos;
|
||||
int safeangle;
|
||||
if ( deathmatch ) [safepos, safeangle] = level.PickDeathmatchStart();
|
||||
else [safepos, safeangle] = level.PickPlayerStart(a.PlayerNumber());
|
||||
a.vel *= 0.;
|
||||
a.SetOrigin(safepos,false);
|
||||
a.angle = safeangle;
|
||||
a.pitch = 0;
|
||||
gc.SafeTeleport(true);
|
||||
a.A_StartSound(gc.UseSound,CHAN_ITEMEXTRA);
|
||||
gc.DoTheThing(true);
|
||||
gc.Amount--;
|
||||
|
|
|
|||
|
|
@ -31,7 +31,9 @@ Class AirBullet : FastProjectile
|
|||
if ( target == lasthit ) return 0;
|
||||
lasthit = target;
|
||||
}
|
||||
SWWMUtility.DoKnockback(target,vel.unit(),10000);
|
||||
Vector3 dirto = level.Vec3Offset(pos,target.Vec3Offset(0,0,target.Height/2.));
|
||||
dirto /= dirto.length();
|
||||
SWWMUtility.DoKnockback(target,vel.unit()*.6+dirto*.4,60000);
|
||||
return damage;
|
||||
}
|
||||
override void Effect()
|
||||
|
|
@ -54,7 +56,7 @@ Class AirBullet : FastProjectile
|
|||
s.alpha *= .2;
|
||||
}
|
||||
bAMBUSH = true;
|
||||
SWWMUtility.DoExplosion(self,GetMissileDamage(0,0),0,50,ignoreme:target);
|
||||
SWWMUtility.DoExplosion(self,GetMissileDamage(0,0),0,60,ignoreme:target);
|
||||
bAMBUSH = false;
|
||||
tcnt++;
|
||||
if ( tcnt < 2 ) return;
|
||||
|
|
@ -104,6 +106,7 @@ Class AirBullet : FastProjectile
|
|||
let s = Spawn("SWWMChip",pos);
|
||||
s.vel = pvel;
|
||||
}
|
||||
if ( swwm_omnibust ) BusterWall.ProjectileBust(self,100,(cos(angle)*cos(pitch),sin(angle)*cos(pitch),sin(-pitch)));
|
||||
}
|
||||
States
|
||||
{
|
||||
|
|
@ -303,14 +306,14 @@ Class DeepImpact : SWWMWeapon
|
|||
int wallhits = 0;
|
||||
Vector3 hitnormal;
|
||||
Vector3 wnorm = (0,0,0);
|
||||
for ( double i=0; i<1.; i+=.05 )
|
||||
for ( double i=0; i<.35; i+=.05 )
|
||||
{
|
||||
for ( int j=0; j<360; j+=(360/rings) )
|
||||
{
|
||||
dir = (x+y*cos(j)*i+z*sin(j)*i).unit();
|
||||
t.hitlist.Clear();
|
||||
t.hitdist.Clear();
|
||||
t.Trace(origin,level.PointInSector(origin.xy),dir,150-i*50,0);
|
||||
t.Trace(origin,level.PointInSector(origin.xy),dir,150-i*120,0);
|
||||
for ( int i=0; i<t.hitlist.Size(); i++ )
|
||||
{
|
||||
int inl = -1;
|
||||
|
|
@ -352,6 +355,7 @@ Class DeepImpact : SWWMWeapon
|
|||
else hitnormal = t.Results.HitSector.ceilingplane.Normal;
|
||||
wnorm += (hitnormal*.2-dir)/max(50.,t.Results.Distance);
|
||||
}
|
||||
if ( swwm_omnibust ) BusterWall.Bust(t.Results,int(5*(1.-clamp(t.Results.Distance/150.,0.,1.))),target,t.Results.HitVector,t.Results.HitPos.z);
|
||||
}
|
||||
rings += 5;
|
||||
}
|
||||
|
|
@ -365,10 +369,10 @@ Class DeepImpact : SWWMWeapon
|
|||
{
|
||||
Vector3 avgdir = list[i].avgdir/list[i].nhits;
|
||||
double avgdist = list[i].avgdist/list[i].nhits;
|
||||
double dmg = 4000.*(1.-clamp(avgdist/300.,0.,1.));
|
||||
double dmg = 5000.*(1.-clamp(avgdist/200.,0.,1.));
|
||||
if ( !list[i].a.bDONTTHRUST && (list[i].a.mass < LARGE_MASS) )
|
||||
list[i].a.vel += ((avgdir+(0,0,.35))*dmg/max(50,list[i].a.mass));
|
||||
list[i].a.DamageMobj(self,self,int(dmg/500.),'Push',DMG_THRUSTLESS);
|
||||
list[i].a.vel += ((avgdir+(0,0,.2))*dmg/max(50,list[i].a.mass));
|
||||
list[i].a.DamageMobj(invoker,self,int(dmg/350.),'Push',DMG_THRUSTLESS);
|
||||
}
|
||||
let ti = ThinkerIterator.Create("Actor");
|
||||
Actor m;
|
||||
|
|
@ -457,7 +461,6 @@ Class DeepImpact : SWWMWeapon
|
|||
Inventory.Icon "graphics/HUD/Icons/W_DeepImpact.png";
|
||||
Weapon.UpSound "deepimpact/select";
|
||||
Weapon.SlotNumber 1;
|
||||
Weapon.SlotPriority 1.;
|
||||
Weapon.SelectionOrder 2000;
|
||||
Stamina 6000;
|
||||
DeepImpact.ClipCount 100;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
// collectable items that may drop sometimes (future feature)
|
||||
// collectable items that may drop sometimes
|
||||
|
||||
Class SWWMCollectable : Inventory abstract
|
||||
{
|
||||
int avail;
|
||||
bool propagated;
|
||||
|
||||
Property Availability : avail;
|
||||
|
||||
|
|
@ -27,19 +28,47 @@ Class SWWMCollectable : Inventory abstract
|
|||
+FLOATBOB;
|
||||
FloatBobStrength 0.25;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
// delet ourselves if wrong iwad
|
||||
if ( !(gameinfo.gametype&avail) )
|
||||
Destroy();
|
||||
}
|
||||
override bool CanPickup( Actor toucher )
|
||||
{
|
||||
// no pickup if wrong iwad
|
||||
if ( !(gameinfo.gametype&avail) ) return false;
|
||||
return Super.CanPickup(toucher);
|
||||
}
|
||||
override string PickupMessage()
|
||||
{
|
||||
return StringTable.Localize(PickupMsg)..String.Format(" \cj(\cg¥\cf%d\cj)\c-",Stamina);
|
||||
if ( Stamina > 0 )
|
||||
return StringTable.Localize(PickupMsg)..String.Format(" \cj(\cg¥\cf%d\cj)\c-",Stamina);
|
||||
return Super.PickupMessage();
|
||||
}
|
||||
override void AttachToOwner( Actor other )
|
||||
{
|
||||
Super.AttachToOwner(other);
|
||||
// we're only attaching to the other players
|
||||
if ( propagated )
|
||||
return;
|
||||
// give credit
|
||||
if ( other.player )
|
||||
if ( other.player && (Stamina > 0) )
|
||||
{
|
||||
SWWMScoreObj.Spawn(Stamina,other.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+other.Height/2),Font.CR_GOLD);
|
||||
SWWMCredits.Give(other.player,Stamina);
|
||||
}
|
||||
// send to all other players
|
||||
for ( int i=0; i<MAXPLAYERS; i++ )
|
||||
{
|
||||
if ( !playeringame[i] || !players[i].mo || (i == other.PlayerNumber()) )
|
||||
continue;
|
||||
let c = SWWMCollectable(Spawn(GetClass(),pos));
|
||||
c.propagated = true;
|
||||
if ( !c.CallTryPickup(players[i].mo) )
|
||||
c.Destroy();
|
||||
}
|
||||
}
|
||||
States
|
||||
{
|
||||
|
|
@ -63,11 +92,13 @@ Class FroggyChair : SWWMCollectable
|
|||
override void AttachToOwner( Actor other )
|
||||
{
|
||||
Super.AttachToOwner(other);
|
||||
cdown = 150;
|
||||
if ( !propagated )
|
||||
cdown = 150;
|
||||
}
|
||||
override void DoEffect()
|
||||
{
|
||||
Super.DoEffect();
|
||||
if ( cdown <= 0 ) return;
|
||||
if ( Owner && Owner.CheckLocalView() )
|
||||
{
|
||||
if ( cdown == 140 )
|
||||
|
|
@ -75,7 +106,7 @@ Class FroggyChair : SWWMCollectable
|
|||
else if ( cdown == 70 )
|
||||
Console.MidPrint(newsmallfont,"$D_FROGGY2");
|
||||
}
|
||||
if ( cdown > 0 ) cdown--;
|
||||
cdown--;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -109,12 +140,33 @@ Class MMiaSRVol3 : SWWMCollectable
|
|||
}
|
||||
Class MothPlushy : SWWMCollectable
|
||||
{
|
||||
int cdown;
|
||||
|
||||
Default
|
||||
{
|
||||
Tag "$T_MOTHPLUSH";
|
||||
Inventory.PickupMessage "$T_MOTHPLUSH";
|
||||
Stamina 5000;
|
||||
}
|
||||
override void AttachToOwner( Actor other )
|
||||
{
|
||||
Super.AttachToOwner(other);
|
||||
if ( !propagated )
|
||||
cdown = 175;
|
||||
}
|
||||
override void DoEffect()
|
||||
{
|
||||
Super.DoEffect();
|
||||
if ( cdown <= 0 ) return;
|
||||
if ( Owner && Owner.CheckLocalView() )
|
||||
{
|
||||
if ( cdown == 105 )
|
||||
A_StartSound("mashiro/giggle",CHAN_ITEMEXTRA,CHANF_OVERLAP|CHANF_UI,1.,0.);
|
||||
if ( cdown == 35 )
|
||||
Console.MidPrint(newsmallfont,"$D_MASHIRO");
|
||||
}
|
||||
cdown--;
|
||||
}
|
||||
}
|
||||
Class BRCDebutLP : SWWMCollectable
|
||||
{
|
||||
|
|
@ -170,15 +222,6 @@ Class HegeCactus : SWWMCollectable
|
|||
Stamina 8000;
|
||||
}
|
||||
}
|
||||
Class RaideminFig : SWWMCollectable
|
||||
{
|
||||
Default
|
||||
{
|
||||
Tag "$T_RAIDEMIN";
|
||||
Inventory.PickupMessage "$T_RAIDEMIN";
|
||||
Stamina 9000;
|
||||
}
|
||||
}
|
||||
Class FrispyCorn : SWWMCollectable
|
||||
{
|
||||
Default
|
||||
|
|
@ -188,15 +231,6 @@ Class FrispyCorn : SWWMCollectable
|
|||
Stamina 500;
|
||||
}
|
||||
}
|
||||
Class Hoagie : SWWMCollectable
|
||||
{
|
||||
Default
|
||||
{
|
||||
Tag "$T_HOAGIE";
|
||||
Inventory.PickupMessage "$T_HOAGIE";
|
||||
Stamina 800;
|
||||
}
|
||||
}
|
||||
Class LithiumVol1 : SWWMCollectable
|
||||
{
|
||||
Default
|
||||
|
|
@ -206,15 +240,6 @@ Class LithiumVol1 : SWWMCollectable
|
|||
Stamina 3500;
|
||||
}
|
||||
}
|
||||
Class MeetTheSniper : SWWMCollectable
|
||||
{
|
||||
Default
|
||||
{
|
||||
Tag "$T_PISS";
|
||||
Inventory.PickupMessage "$T_PISS";
|
||||
Stamina 1200;
|
||||
}
|
||||
}
|
||||
// Heretic
|
||||
Class DemoPlush : SWWMCollectable
|
||||
{
|
||||
|
|
@ -226,26 +251,6 @@ Class DemoPlush : SWWMCollectable
|
|||
Stamina 6400;
|
||||
}
|
||||
}
|
||||
Class Firemace : SWWMCollectable
|
||||
{
|
||||
Default
|
||||
{
|
||||
Tag "$T_FIREMACE";
|
||||
Inventory.PickupMessage "$T_FIREMACE";
|
||||
SWWMCollectable.Availability AVAIL_Heretic;
|
||||
Stamina 10000;
|
||||
}
|
||||
}
|
||||
Class DoomguyFig : SWWMCollectable
|
||||
{
|
||||
Default
|
||||
{
|
||||
Tag "$T_DOOMFIG";
|
||||
Inventory.PickupMessage "$T_DOOMFIG";
|
||||
SWWMCollectable.Availability AVAIL_Heretic;
|
||||
Stamina 9000;
|
||||
}
|
||||
}
|
||||
Class TomeOfPower : SWWMCollectable
|
||||
{
|
||||
Default
|
||||
|
|
@ -268,6 +273,8 @@ Class QuartzFlask : SWWMCollectable
|
|||
}
|
||||
Class SayaBean : SWWMCollectable
|
||||
{
|
||||
int cdown;
|
||||
|
||||
Default
|
||||
{
|
||||
Tag "$T_SAYABEAN";
|
||||
|
|
@ -275,18 +282,25 @@ Class SayaBean : SWWMCollectable
|
|||
SWWMCollectable.Availability AVAIL_Heretic;
|
||||
Stamina 12000;
|
||||
}
|
||||
}
|
||||
// Hexen
|
||||
Class PuzzleDesignBook : SWWMCollectable
|
||||
{
|
||||
Default
|
||||
override void AttachToOwner( Actor other )
|
||||
{
|
||||
Tag "$T_PUZZLEBOOK";
|
||||
Inventory.PickupMessage "$T_PUZZLEBOOK";
|
||||
SWWMCollectable.Availability AVAIL_Hexen;
|
||||
Stamina 2500;
|
||||
Super.AttachToOwner(other);
|
||||
if ( !propagated )
|
||||
cdown = 70;
|
||||
}
|
||||
override void DoEffect()
|
||||
{
|
||||
Super.DoEffect();
|
||||
if ( cdown <= 0 ) return;
|
||||
if ( Owner && Owner.CheckLocalView() )
|
||||
{
|
||||
if ( cdown == 35 )
|
||||
A_StartSound("saya/giggle",CHAN_ITEMEXTRA,CHANF_OVERLAP|CHANF_UI,1.,0.);
|
||||
}
|
||||
cdown--;
|
||||
}
|
||||
}
|
||||
// Hexen
|
||||
Class KirinCummies : SWWMCollectable
|
||||
{
|
||||
Default
|
||||
|
|
@ -309,6 +323,8 @@ Class MilkBreads : SWWMCollectable
|
|||
}
|
||||
Class EyeObelisk : SWWMCollectable
|
||||
{
|
||||
int cdown;
|
||||
|
||||
Default
|
||||
{
|
||||
Tag "$T_OBELISK";
|
||||
|
|
@ -316,6 +332,20 @@ Class EyeObelisk : SWWMCollectable
|
|||
SWWMCollectable.Availability AVAIL_Hexen;
|
||||
Stamina 24000;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
if ( InStateSequence(CurState,FindState("Spawn")) )
|
||||
A_StartSound("obelisk/idle",CHAN_BODY,CHANF_LOOPING);
|
||||
}
|
||||
override void AttachToOwner( Actor other )
|
||||
{
|
||||
Super.AttachToOwner(other);
|
||||
if ( propagated ) return;
|
||||
// nauseatingly fast trip through images of the future
|
||||
if ( other.player != players[consoleplayer] ) return;
|
||||
let hnd = EyeObeliskFlash(StaticEventHandler.Find("EyeObeliskFlash"));
|
||||
if ( hnd ) hnd.doit = true;
|
||||
}
|
||||
}
|
||||
Class KirinManga : SWWMCollectable
|
||||
{
|
||||
|
|
@ -328,6 +358,96 @@ Class KirinManga : SWWMCollectable
|
|||
}
|
||||
}
|
||||
|
||||
Class EyeObeliskFlash : StaticEventHandler
|
||||
{
|
||||
bool doit;
|
||||
int cd;
|
||||
ui bool doit_ui;
|
||||
ui int timeme;
|
||||
ui TextureID ftex[29];
|
||||
|
||||
override void UiTick()
|
||||
{
|
||||
if ( !doit && !doit_ui )
|
||||
{
|
||||
timeme = 0;
|
||||
return;
|
||||
}
|
||||
if ( timeme == 0 )
|
||||
{
|
||||
// do not trigger if the user doesn't want this
|
||||
if ( CVar.GetCVar('swwm_noscare',players[consoleplayer]).GetBool() )
|
||||
return;
|
||||
doit_ui = true;
|
||||
for ( int i=0; i<29; i++ )
|
||||
ftex[i] = TexMan.CheckForTexture(String.Format("graphics/obelisk/O_SIGHT%d.png",i),TexMan.Type_Any);
|
||||
S_StartSound("obelisk/sight",CHAN_VOICE,CHANF_UI|CHANF_NOPAUSE,1.,0.);
|
||||
}
|
||||
if ( timeme == 210 ) Console.MidPrint(newsmallfont,"$D_OBELISK");
|
||||
if ( timeme == 240 ) doit_ui = false;
|
||||
timeme++;
|
||||
}
|
||||
override void WorldTick()
|
||||
{
|
||||
if ( !doit ) return;
|
||||
cd++;
|
||||
if ( cd < 1 ) return;
|
||||
cd = 0;
|
||||
doit = false;
|
||||
}
|
||||
override void RenderOverlay( RenderEvent e )
|
||||
{
|
||||
if ( !doit_ui ) return;
|
||||
double secs = (timeme+e.FracTic)/Thinker.TICRATE;
|
||||
PlayerInfo p = players[consoleplayer];
|
||||
if ( secs < .25 ) Screen.Dim("White",(secs*4.)**2.,0,0,Screen.GetWidth(),Screen.GetHeight());
|
||||
else if ( secs < 2.25 )
|
||||
{
|
||||
Shader.SetEnabled(p,"ObPass0",true);
|
||||
Shader.SetEnabled(p,"ObPass1",true);
|
||||
Shader.SetEnabled(p,"ObPass2",true);
|
||||
Shader.SetEnabled(p,"ObPass3",true);
|
||||
Shader.SetUniform1f(p,"ObPass0","Timer",(timeme+e.FracTic)/Thinker.TICRATE);
|
||||
Shader.SetUniform1f(p,"ObPass1","Timer",(timeme+e.FracTic)/Thinker.TICRATE);
|
||||
Shader.SetUniform1f(p,"ObPass2","Timer",(timeme+e.FracTic)/Thinker.TICRATE);
|
||||
Shader.SetUniform1f(p,"ObPass3","Timer",(timeme+e.FracTic)/Thinker.TICRATE);
|
||||
secs -= .25;
|
||||
Screen.Dim("Black",1.,0,0,Screen.GetWidth(),Screen.GetHeight());
|
||||
// flash images:
|
||||
// 0. mirror man (thievery at the forsaken manor redux)
|
||||
// 1. viridescent lord (hexmas)
|
||||
// 2. nightmare lord (spooktober)
|
||||
// 3. dreadful lady (strife 25th anniversary project)
|
||||
// 4. shinnovre (unsx 6)
|
||||
// 5. hiikya (the hiikyan war)
|
||||
// 6. rebirth of azadeku (project abyss dlc1: forgotten times)
|
||||
// 7. heart of assimilation (project abyss dlc2: the void lords)
|
||||
// 8. sage of blue (project abyss dlc3: assault on blue tower)
|
||||
// 9. ser (project convergence)
|
||||
int whichimg = clamp(int((10.*secs)/2.),0,9);
|
||||
if ( !ftex[whichimg] ) return;
|
||||
double ar = Screen.GetAspectRatio();
|
||||
Vector2 tsize = TexMan.GetScaledSize(ftex[whichimg]);
|
||||
double sar = tsize.x/tsize.y;
|
||||
Vector2 vsize;
|
||||
if ( sar > ar ) vsize = (tsize.x,tsize.x/ar);
|
||||
else if ( sar < ar ) vsize = (tsize.y*ar,tsize.y);
|
||||
else vsize = tsize;
|
||||
vsize *= .75;
|
||||
Screen.DrawTexture(ftex[whichimg],false,(vsize.x-tsize.x)/2,(vsize.y-tsize.y)/2,DTA_VirtualWidthF,vsize.x,DTA_VirtualHeightF,vsize.y,DTA_KeepRatio,true);
|
||||
}
|
||||
else if ( secs < 6.25 )
|
||||
{
|
||||
Shader.SetEnabled(p,"ObPass0",false);
|
||||
Shader.SetEnabled(p,"ObPass1",false);
|
||||
Shader.SetEnabled(p,"ObPass2",false);
|
||||
Shader.SetEnabled(p,"ObPass3",false);
|
||||
secs -= 2.25;
|
||||
Screen.Dim("White",(1.-secs*.25)**1.5,0,0,Screen.GetWidth(),Screen.GetHeight());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// yay!
|
||||
Class FancyConfetti : Actor
|
||||
{
|
||||
|
|
@ -397,6 +517,97 @@ Class FancyConfetti : Actor
|
|||
Stop;
|
||||
}
|
||||
}
|
||||
Class PartyTime : Actor
|
||||
{
|
||||
bool ignite;
|
||||
|
||||
Default
|
||||
{
|
||||
Radius .1;
|
||||
Height 0.;
|
||||
+NOBLOCKMAP;
|
||||
+NOTELEPORT;
|
||||
+DONTSPLASH;
|
||||
+NOINTERACTION;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
if ( target ) specialf1 = target.Height/2.;
|
||||
else specialf1 = 16.;
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
if ( ignite )
|
||||
{
|
||||
// wait for the sound to stop
|
||||
if ( !IsActorPlayingSound(CHAN_ITEM) )
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
if ( !target || (target.tics == -1) )
|
||||
{
|
||||
// burst into treats!
|
||||
ignite = true;
|
||||
A_Confetti();
|
||||
return;
|
||||
}
|
||||
SetOrigin(target.pos,false);
|
||||
}
|
||||
action void A_Confetti()
|
||||
{
|
||||
A_StartSound("misc/tada",CHAN_ITEM);
|
||||
double ang, pt;
|
||||
int numpt = Random[ExploS](100,120);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
ang = FRandom[ExploS](0,360);
|
||||
pt = FRandom[ExploS](-90,30);
|
||||
let c = Spawn("FancyConfetti",Vec3Offset(0,0,specialf1));
|
||||
c.vel = (cos(pt)*cos(ang),cos(pt)*sin(ang),-sin(pt))*FRandom[ExploS](2,8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Class ChanceboxSpawner : Actor
|
||||
{
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
int numcol = 0;
|
||||
for ( int i=0; i<AllActorClasses.Size(); i++ )
|
||||
{
|
||||
let c = (Class<SWWMCollectable>)(AllActorClasses[i]);
|
||||
if ( !c || (c == 'SWWMCollectable') ) continue;
|
||||
let def = GetDefaultByType(c);
|
||||
// check that we can collect it in this IWAD
|
||||
if ( !(gameinfo.gametype&def.avail) ) continue;
|
||||
numcol++;
|
||||
}
|
||||
let ti = ThinkerIterator.Create("SWWMCollectable");
|
||||
while ( ti.Next() ) numcol--;
|
||||
ti = ThinkerIterator.Create("Chancebox");
|
||||
while ( ti.Next() ) numcol--;
|
||||
if ( numcol <= 0 )
|
||||
{
|
||||
// can't spawn a box, everything's been collected
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
let b = Spawn("Chancebox",pos);
|
||||
// copy all our stuff
|
||||
b.spawnangle = spawnangle;
|
||||
b.angle = angle;
|
||||
b.pitch = pitch;
|
||||
b.roll = roll;
|
||||
b.spawnpoint = spawnpoint;
|
||||
b.special = special;
|
||||
for ( int i=0; i<5; i++ )
|
||||
b.Args[i] = Args[i];
|
||||
b.spawnflags = spawnflags&~MTF_SECRET;
|
||||
b.HandleSpawnFlags();
|
||||
b.bCOUNTSECRET = spawnflags&MTF_SECRET;
|
||||
b.ChangeTid(tid);
|
||||
}
|
||||
}
|
||||
|
||||
// Collectable box (recycling of discarded "chance box" item)
|
||||
Class Chancebox : Actor
|
||||
|
|
@ -424,14 +635,21 @@ Class Chancebox : Actor
|
|||
SWWMCollectable c;
|
||||
while ( c = SWWMCollectable(ti.Next()) )
|
||||
{
|
||||
int f = candidates.Find(inv.GetClass());
|
||||
int f = candidates.Find(c.GetClass());
|
||||
if ( f < candidates.Size() )
|
||||
candidates.Delete(f);
|
||||
}
|
||||
if ( candidates.Size() <= 0 )
|
||||
{
|
||||
// TODO no candidates? just spawn some random loot
|
||||
Console.Printf("\cg// TODO spawn random loot\c-");
|
||||
// no candidates? just burst into treats
|
||||
for ( int i=0; i<=30; i++ )
|
||||
{
|
||||
let a = Spawn((i==0)?"RefresherItem":(i%3)?"HealthNuggetItem":"ArmorNuggetItem",pos);
|
||||
a.bDROPPED = true;
|
||||
a.bNOGRAVITY = false;
|
||||
a.vel.z = FRandom[Chancebox](2,4);
|
||||
if ( i > 0 ) a.vel.xy = (cos(i*12),sin(i*12))*FRandom[Chancebox](4,12);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -469,7 +687,19 @@ Class Chancebox : Actor
|
|||
override bool Used( Actor user )
|
||||
{
|
||||
if ( CurState != FindState("Spawn") ) return false;
|
||||
SetStateLabel("Active");
|
||||
if ( bCountSecret )
|
||||
{
|
||||
user.GiveSecret();
|
||||
bCountSecret = false;
|
||||
}
|
||||
if ( special )
|
||||
{
|
||||
user.A_CallSpecial(special,args[0],args[1],args[2],args[3],args[4]);
|
||||
special = 0;
|
||||
}
|
||||
SWWMLoreLibrary.Add(user.player,"Chancebox");
|
||||
specialf2 = AngleTo(user);
|
||||
SetStateLabel("PreActive");
|
||||
return true;
|
||||
}
|
||||
Default
|
||||
|
|
@ -479,6 +709,7 @@ Class Chancebox : Actor
|
|||
+MOVEWITHSECTOR;
|
||||
+ROLLSPRITE;
|
||||
+SOLID;
|
||||
+INTERPOLATEANGLES;
|
||||
Species "Chancebox";
|
||||
}
|
||||
States
|
||||
|
|
@ -486,14 +717,26 @@ Class Chancebox : Actor
|
|||
Spawn:
|
||||
XZW1 A -1;
|
||||
Stop;
|
||||
PreActive:
|
||||
XZW1 A 1
|
||||
{
|
||||
double delta = deltaangle(angle,specialf2);
|
||||
int sign = (delta>=0.)?1:-1;
|
||||
delta = clamp(abs(delta)*.15,.1,10.)*sign;
|
||||
angle += delta;
|
||||
return A_JumpIf(abs(deltaangle(angle,specialf2))<1.,"Active");
|
||||
}
|
||||
Wait;
|
||||
Active:
|
||||
XZW1 A 1
|
||||
{
|
||||
angle = specialf2;
|
||||
specialf1 = angle;
|
||||
A_StartSound("misc/drumroll",CHAN_WEAPON);
|
||||
}
|
||||
XZW1 A 1
|
||||
{
|
||||
bINTERPOLATEANGLES = false;
|
||||
angle = specialf1+FRandom[Chancebox](-5,5);
|
||||
pitch = FRandom[Chancebox](-5,5);
|
||||
roll = FRandom[Chancebox](-5,5);
|
||||
|
|
|
|||
|
|
@ -862,6 +862,11 @@ Class SWWMHandler : EventHandler
|
|||
let t = new("UglyBoyGetsFuckedUp");
|
||||
t.ChangeStatNum(Thinker.STAT_USER);
|
||||
}
|
||||
if ( swwm_partytime )
|
||||
{
|
||||
let pt = Actor.Spawn("PartyTime",e.Thing.pos);
|
||||
pt.target = e.Thing;
|
||||
}
|
||||
}
|
||||
|
||||
override void WorldThingDamaged( WorldEvent e )
|
||||
|
|
@ -935,6 +940,9 @@ Class SWWMHandler : EventHandler
|
|||
}
|
||||
}
|
||||
if ( (e.Thing.Health > 0) || e.Thing.bKilled || e.Thing.bCorpse ) return;
|
||||
// romero hax
|
||||
if ( (e.Thing is 'BossBrain') && (e.DamageType == 'Telefrag') )
|
||||
e.DamageSource.DamageMobj(null,null,Actor.TELEFRAG_DAMAGE,'EndLevel');
|
||||
if ( !e.Thing.player && !e.Thing.bIsMonster && !e.Thing.bCountKill && !(e.Thing is 'ScriptedMarine') ) return;
|
||||
if ( (e.DamageSource && e.DamageSource.player && (e.DamageSource != e.Thing)) )
|
||||
{
|
||||
|
|
@ -942,7 +950,7 @@ Class SWWMHandler : EventHandler
|
|||
if ( s )
|
||||
{
|
||||
s.kills++;
|
||||
s.AddWeaponKill(e.Inflictor,e.Thing);
|
||||
s.AddWeaponKill(e.Inflictor,e.Thing,e.DamageType);
|
||||
}
|
||||
if ( e.DamageSource == players[consoleplayer].mo )
|
||||
{
|
||||
|
|
@ -1000,7 +1008,7 @@ Class SWWMHandler : EventHandler
|
|||
{
|
||||
scr.xscore[ofs] = 0;
|
||||
scr.xtcolor[ofs] = Font.FindFontColor('BlushPink');
|
||||
scr.xstr[ofs] = StringTable.Localize("$SWWM_LOVED");
|
||||
scr.xstr[ofs] = StringTable.Localize((e.Thing is 'WolfensteinSS')?"$SWWM_LOVED_ALT":"$SWWM_LOVED");
|
||||
scr.xcnt = ++ofs;
|
||||
}
|
||||
}
|
||||
|
|
@ -1125,12 +1133,12 @@ Class SWWMHandler : EventHandler
|
|||
DoKeyTagFix(e.Thing);
|
||||
SWWMInterest.Spawn(thekey:Key(e.Thing));
|
||||
}
|
||||
else if ( e.Thing is 'BossBrain' )
|
||||
else if ( e.Thing.GetClass() == 'BossBrain' )
|
||||
{
|
||||
e.Thing.SetTag("$FN_BOSSBRAIN");
|
||||
e.Thing.A_SetSize(20,70);
|
||||
e.Thing.A_SetSize(20,40);
|
||||
e.Thing.bNOBLOOD = true;
|
||||
}
|
||||
else if ( e.Thing is 'CommanderKeen' ) e.Thing.SetTag("$FN_KEEN");
|
||||
if ( !swwm_notrack && (e.Thing.bSHOOTABLE || e.Thing.bISMONSTER) && !(e.Thing is 'LampMoth') && !(e.Thing is 'CompanionLamp') ) SWWMCombatTracker.Spawn(e.Thing);
|
||||
}
|
||||
|
||||
|
|
@ -1238,6 +1246,8 @@ Class SWWMHandler : EventHandler
|
|||
{
|
||||
if ( e.Replacement is 'DSparilHax' )
|
||||
e.Replacee = 'Sorcerer2';
|
||||
if ( e.Replacement is 'SWWMHangingKeen' )
|
||||
e.Replacee = 'CommanderKeen';
|
||||
}
|
||||
|
||||
override void CheckReplacement( ReplaceEvent e )
|
||||
|
|
@ -1253,6 +1263,17 @@ Class SWWMHandler : EventHandler
|
|||
static const Class<Actor> blackpool[] = {"BlackShell","BlackShell2"};
|
||||
if ( e.Replacee is 'ItemFog' ) e.Replacement = 'SWWMItemFog';
|
||||
if ( e.Replacee is 'TeleportFog' ) e.Replacement = 'SWWMTeleportFog';
|
||||
if ( (e.Replacee is 'CommanderKeen') && (!e.Replacement || (e.Replacement == 'CommanderKeen')) )
|
||||
{
|
||||
let def = GetDefaultByType(e.Replacee);
|
||||
bool dehackery = false;
|
||||
for ( State s=def.SpawnState; s; s=s.NextState )
|
||||
{
|
||||
if ( s.bDEHACKED ) dehackery = true;
|
||||
if ( s.NextState == s ) break;
|
||||
}
|
||||
if ( !dehackery ) e.Replacement = 'SWWMHangingKeen';
|
||||
}
|
||||
else if ( (e.Replacee is 'Chainsaw') || (e.Replacee is 'Gauntlets') || (e.Replacee is 'FWeapAxe') ) e.Replacement = 'PusherWeapon';
|
||||
else if ( (e.Replacee is 'Fist') || (e.Replacee is 'Staff') ) e.Replacement = 'DeepImpact';
|
||||
else if ( (e.Replacee is 'Pistol') || (e.Replacee is 'GoldWand') || (e.Replacee is 'FWeapFist') || (e.Replacee is 'CWeapMace') || (e.Replacee is 'MWeapWand') ) e.Replacement = 'ExplodiumGun';
|
||||
|
|
@ -1433,11 +1454,6 @@ Class SWWMHandler : EventHandler
|
|||
else if ( !Random[Replacements](0,3) ) e.Replacement = 'CandyGunBullets';
|
||||
else e.Replacement = Random[Replacements](0,2)?'SilverBullets':'SilverBullets2';
|
||||
}
|
||||
else if ( (e.Replacee == 'ArtiTeleport') || (e.Replacee == 'ArtiTeleportOther') )
|
||||
{
|
||||
if ( Random[Replacements](0,3) ) e.Replacement = 'SWWMNothing';
|
||||
else e.Replacement = 'GoldShell';
|
||||
}
|
||||
else if ( (e.Replacee == 'CellPack') || (e.Replacee == 'SkullRodHefty') )
|
||||
{
|
||||
if ( !Random[Replacements](0,2) )
|
||||
|
|
@ -1452,7 +1468,7 @@ Class SWWMHandler : EventHandler
|
|||
else if ( e.Replacee == 'Mana2' ) e.Replacement = 'FabricatorTier2';
|
||||
else if ( e.Replacee == 'Mana3' ) e.Replacement = 'FabricatorTier3';
|
||||
else if ( e.Replacee == 'ArtiBoostMana' ) e.Replacement = 'FabricatorTier4';
|
||||
else if ( (e.Replacee == 'Backpack') || (e.Replacee == 'BagOfHolding') || (e.Replacee == 'ArtiPork') || (e.Replacee == 'ArtiBoostArmor') ) e.Replacement = 'HammerspaceEmbiggener';
|
||||
else if ( (e.Replacee == 'Backpack') || (e.Replacee == 'BagOfHolding') || (e.Replacee == 'ArtiBoostArmor') ) e.Replacement = 'HammerspaceEmbiggener';
|
||||
else if ( (e.Replacee == 'FWeaponPiece1') || (e.Replacee == 'FWeaponPiece2')
|
||||
|| (e.Replacee == 'CWeaponPiece1') || (e.Replacee == 'CWeaponPiece3')
|
||||
|| (e.Replacee == 'MWeaponPiece2') || (e.Replacee == 'MWeaponPiece3') )
|
||||
|
|
@ -1481,11 +1497,12 @@ Class SWWMHandler : EventHandler
|
|||
else if ( e.Replacee == 'Radsuit' ) e.Replacement = 'EBarrier';
|
||||
else if ( (e.Replacee == 'ArtiFly') ) e.Replacement = 'GravitySuppressor';
|
||||
else if ( (e.Replacee == 'InvulnerabilitySphere') || (e.Replacee == 'ArtiInvulnerability') || (e.Replacee == 'ArtiInvulnerability2') ) e.Replacement = 'FuckingInvinciball';
|
||||
else if ( (e.Replacee == 'Berserk') || (e.Replacee == 'ArtiTomeOfPower') || (e.Replacee == 'ArtiDarkServant') || (e.Replacee == 'ArtiSpeedBoots') ) e.Replacement = 'Ragekit';
|
||||
else if ( (e.Replacee == 'Berserk') || (e.Replacee == 'ArtiTomeOfPower') || (e.Replacee == 'ArtiSpeedBoots') ) e.Replacement = 'Ragekit';
|
||||
else if ( (e.Replacee == 'AllMap') || (e.Replacee == 'SuperMap') ) e.Replacement = 'Omnisight';
|
||||
else if ( (e.Replacee == 'Infrared') || (e.Replacee == 'ArtiTorch') ) e.Replacement = 'SWWMLamp';
|
||||
else if ( (e.Replacee == 'GreenArmor') || (e.Replacee == 'SilverShield') || (e.Replacee == 'MeshArmor') ) e.Replacement = 'BlastSuitItem';
|
||||
else if ( (e.Replacee == 'BlueArmor') || (e.Replacee == 'FalconShield') || (e.Replacee == 'EnchantedShield') ) e.Replacement = 'WarArmorItem';
|
||||
else if ( (e.Replacee == 'ArtiPork') || (e.Replacee == 'ArtiDarkServant') || (e.Replacee == 'ArtiTeleport') || (e.Replacee == 'ArtiTeleportOther') ) e.Replacement = 'SWWMNothing'/*'Chancebox'*/;
|
||||
}
|
||||
|
||||
override void NetworkProcess( ConsoleEvent e )
|
||||
|
|
@ -1785,6 +1802,8 @@ Class SWWMHandler : EventHandler
|
|||
Shader.SetEnabled(p,"WaterWarp",true);
|
||||
Shader.SetUniform1f(p,"WaterWarp","timer",(gametic+e.FracTic)/Thinker.TICRATE);
|
||||
Shader.SetUniform1f(p,"WaterWarp","dfact",coat?.25:1.);
|
||||
Shader.SetUniform3f(p,"WaterWarp","lightcol",(demo.undercol.r/255.,demo.undercol.g/255.,demo.undercol.b/255.));
|
||||
|
||||
}
|
||||
else Shader.SetEnabled(p,"WaterWarp",false);
|
||||
if ( demo.lastunder == Demolitionist.UNDER_LAVA )
|
||||
|
|
@ -1792,6 +1811,7 @@ Class SWWMHandler : EventHandler
|
|||
Shader.SetEnabled(p,"LavaWarp",true);
|
||||
Shader.SetUniform1f(p,"LavaWarp","timer",(gametic+e.FracTic)/Thinker.TICRATE);
|
||||
Shader.SetUniform1f(p,"LavaWarp","dfact",coat?.25:1.);
|
||||
Shader.SetUniform3f(p,"LavaWarp","lightcol",(demo.undercol.r/255.,demo.undercol.g/255.,demo.undercol.b/255.));
|
||||
}
|
||||
else Shader.SetEnabled(p,"LavaWarp",false);
|
||||
if ( demo.lastunder == Demolitionist.UNDER_SLIME )
|
||||
|
|
@ -1799,6 +1819,7 @@ Class SWWMHandler : EventHandler
|
|||
Shader.SetEnabled(p,"SlimeWarp",true);
|
||||
Shader.SetUniform1f(p,"SlimeWarp","timer",(gametic+e.FracTic)/Thinker.TICRATE);
|
||||
Shader.SetUniform1f(p,"SlimeWarp","dfact",coat?.25:1.);
|
||||
Shader.SetUniform3f(p,"SlimeWarp","lightcol",(demo.undercol.r/255.,demo.undercol.g/255.,demo.undercol.b/255.));
|
||||
}
|
||||
else Shader.SetEnabled(p,"SlimeWarp",false);
|
||||
int lastdmg = (demo.Health>0)?demo.lastdamage:Random[Flicker](60,80);
|
||||
|
|
|
|||
|
|
@ -33,19 +33,6 @@ Class RefresherHealth : Health
|
|||
Inventory.Amount 100;
|
||||
Inventory.MaxAmount 500;
|
||||
}
|
||||
override bool TryPickup( in out Actor other )
|
||||
{
|
||||
PrevHealth = other.player?other.player.health:other.health;
|
||||
if ( other.GiveBody(Amount,MaxAmount) )
|
||||
{
|
||||
GoAwayAndDie();
|
||||
let p = Powerup(other.FindInventory("RefresherRegen"));
|
||||
if ( p ) p.EffectTics = p.default.EffectTics;
|
||||
else other.GiveInventory("RefresherRegen",1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Class RefresherRegen : Powerup
|
||||
{
|
||||
|
|
@ -54,6 +41,7 @@ Class RefresherRegen : Powerup
|
|||
Inventory.Icon "graphics/HUD/Icons/I_Refresher.png";
|
||||
Powerup.Duration -50;
|
||||
Powerup.Strength 10;
|
||||
+INVENTORY.ADDITIVETIME;
|
||||
}
|
||||
|
||||
override void EndEffect()
|
||||
|
|
@ -172,7 +160,7 @@ Class RefresherItem : SWWMHealth
|
|||
override void AutoUseExtra()
|
||||
{
|
||||
let p = Powerup(Owner.FindInventory("RefresherRegen"));
|
||||
if ( p ) p.EffectTics = p.default.EffectTics;
|
||||
if ( p ) p.EffectTics += p.default.EffectTics;
|
||||
else Owner.GiveInventory("RefresherRegen",1);
|
||||
SWWMHandler.DoFlash(Owner,Color(80,224,128,255),20);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ Class MsgLine
|
|||
Class SWWMStatusBar : BaseStatusBar
|
||||
{
|
||||
TextureID StatusTex, WeaponTex, ScoreTex[3], InventoryTex, ChatTex[6],
|
||||
HealthTex[5], FuelTex, DashTex, EnemyBTex, EnemyHTex[5], GenericAmmoTex[3];
|
||||
HealthTex[5], FuelTex[2], DashTex, EnemyBTex, EnemyHTex[5], GenericAmmoTex[3];
|
||||
HUDFont mTewiFont, mMiniwiFont, mMPlusFont, mk6x8Font;
|
||||
|
||||
// "Full History" contains all messages since session start, nothing is flushed
|
||||
|
|
@ -28,7 +28,7 @@ Class SWWMStatusBar : BaseStatusBar
|
|||
SWWMVanillaBossHandler bosshnd;
|
||||
|
||||
// client cvars
|
||||
transient CVar safezone, maxchat[2], maxpick, chatduration, msgduration, pickduration, chatcol, teamcol, obitcol, critcol, pickcol, targetter, healthnums, scorenums, scorebonus, pois, targettag, lang, maxtarg, maxscore, maxdamns, hscale, bscale, nscale, sscale, iscale, dscale, midcol, midbcol, midduration, bigtags;
|
||||
transient CVar safezone, maxchat[2], maxpick, chatduration, msgduration, pickduration, chatcol, teamcol, obitcol, critcol, pickcol, targetter, healthnums, scorenums, scorebonus, pois, targettag, lang, maxtarg, maxscore, maxdamns, hscale, bscale, nscale, sscale, iscale, dscale, midcol, midbcol, midduration, bigtags, showitems, showmaplabel, showmonsters, showsecrets, showtime, showtotaltime;
|
||||
|
||||
// shared stuff
|
||||
Vector2 ss, hs;
|
||||
|
|
@ -598,7 +598,8 @@ Class SWWMStatusBar : BaseStatusBar
|
|||
SetSize(0,640,360);
|
||||
StatusTex = TexMan.CheckForTexture("graphics/HUD/StatusBox.png",TexMan.Type_Any);
|
||||
DashTex = TexMan.CheckForTexture("graphics/HUD/DashBar.png",TexMan.Type_Any);
|
||||
FuelTex = TexMan.CheckForTexture("graphics/HUD/FuelBar.png",TexMan.Type_Any);
|
||||
FuelTex[0] = TexMan.CheckForTexture("graphics/HUD/FuelBar.png",TexMan.Type_Any);
|
||||
FuelTex[1] = TexMan.CheckForTexture("graphics/HUD/FuelBarS.png",TexMan.Type_Any);
|
||||
HealthTex[0] = TexMan.CheckForTexture("graphics/HUD/HealthBar0.png",TexMan.Type_Any);
|
||||
HealthTex[1] = TexMan.CheckForTexture("graphics/HUD/HealthBar1.png",TexMan.Type_Any);
|
||||
HealthTex[2] = TexMan.CheckForTexture("graphics/HUD/HealthBar2.png",TexMan.Type_Any);
|
||||
|
|
@ -864,40 +865,54 @@ Class SWWMStatusBar : BaseStatusBar
|
|||
int yy = margin+19;
|
||||
if ( automapactive )
|
||||
{
|
||||
if ( !showitems ) showitems = CVar.GetCVar('am_showitems',players[consoleplayer]);
|
||||
if ( !showmaplabel ) showmaplabel = CVar.GetCVar('am_showmaplabel',players[consoleplayer]);
|
||||
if ( !showmonsters ) showmonsters = CVar.GetCVar('am_showmonsters',players[consoleplayer]);
|
||||
if ( !showsecrets ) showsecrets = CVar.GetCVar('am_showsecrets',players[consoleplayer]);
|
||||
if ( !showtime ) showtime = CVar.GetCVar('am_showtime',players[consoleplayer]);
|
||||
if ( !showtotaltime ) showtotaltime = CVar.GetCVar('am_showtotaltime',players[consoleplayer]);
|
||||
int xx = int(ss.x-(margin+2));
|
||||
String str;
|
||||
if ( level.clusterflags&level.CLUSTER_HUB ) str = level.levelname;
|
||||
int label = showmaplabel.GetInt();
|
||||
if ( !label || ((level.clusterflags&level.CLUSTER_HUB) && (label == 2)) ) str = level.levelname;
|
||||
else str = String.Format("%s - %s",level.mapname.MakeUpper(),level.levelname);
|
||||
let fnt = LangFont(mTewiFont);
|
||||
Screen.DrawText(fnt,Font.CR_FIRE,xx-fnt.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
||||
yy += fnt.GetHeight();
|
||||
fnt = LangFont(mMiniwiFont);
|
||||
if ( level.total_monsters > 0 )
|
||||
if ( (level.total_monsters > 0) && showmonsters.GetBool() )
|
||||
{
|
||||
str = String.Format("\cxK \c-%d\cu/\c-%d",level.killed_monsters,level.total_monsters);
|
||||
Screen.DrawText(fnt,Font.CR_WHITE,xx-fnt.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
||||
Screen.DrawText(fnt,(level.killed_monsters>=level.total_monsters)?Font.CR_GOLD:Font.CR_WHITE,xx-fnt.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
||||
yy += fnt.GetHeight();
|
||||
}
|
||||
if ( level.total_items > 0 )
|
||||
if ( (level.total_items > 0) && showitems.GetBool() )
|
||||
{
|
||||
str = String.Format("\cxI \c-%d\cu/\c-%d",level.found_items,level.total_items);
|
||||
Screen.DrawText(fnt,Font.CR_WHITE,xx-fnt.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
||||
Screen.DrawText(fnt,(level.found_items>=level.total_items)?Font.CR_GOLD:Font.CR_WHITE,xx-fnt.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
||||
yy += fnt.GetHeight();
|
||||
}
|
||||
if ( level.total_secrets > 0 )
|
||||
if ( (level.total_secrets > 0) && showsecrets.GetBool() )
|
||||
{
|
||||
str = String.Format("\cxS \c-%d\cu/\c-%d",level.found_secrets,level.total_secrets);
|
||||
Screen.DrawText(fnt,(level.found_secrets>=level.total_secrets)?Font.CR_GOLD:Font.CR_WHITE,xx-fnt.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
||||
yy += fnt.GetHeight();
|
||||
}
|
||||
int sec;
|
||||
if ( showtime.GetBool() )
|
||||
{
|
||||
sec = Thinker.Tics2Seconds(level.maptime);
|
||||
str = String.Format("\cxT \c-%02d\cu:\c-%02d\cu:\c-%02d",sec/3600,(sec%3600)/60,sec%60);
|
||||
Screen.DrawText(fnt,(sec>3600)?Font.CR_RED:(sec<=level.partime)?Font.CR_GOLD:Font.CR_WHITE,xx-fnt.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
||||
yy += fnt.GetHeight();
|
||||
}
|
||||
if ( showtotaltime.GetBool() )
|
||||
{
|
||||
sec = Thinker.Tics2Seconds(level.totaltime);
|
||||
str = String.Format("\cxTT \c-%02d\cu:\c-%02d\cu:\c-%02d",sec/3600,(sec%3600)/60,sec%60);
|
||||
Screen.DrawText(fnt,Font.CR_WHITE,xx-fnt.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
||||
yy += fnt.GetHeight();
|
||||
}
|
||||
int sec = Thinker.Tics2Seconds(level.maptime);
|
||||
str = String.Format("\cxT \c-%02d\cu:\c-%02d\cu:\c-%02d",sec/3600,(sec%3600)/60,sec%60);
|
||||
Screen.DrawText(fnt,Font.CR_WHITE,xx-fnt.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
||||
yy += fnt.GetHeight();
|
||||
sec = Thinker.Tics2Seconds(level.totaltime);
|
||||
str = String.Format("\cxTT \c-%02d\cu:\c-%02d\cu:\c-%02d",sec/3600,(sec%3600)/60,sec%60);
|
||||
Screen.DrawText(fnt,Font.CR_WHITE,xx-fnt.StringWidth(str),yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
||||
yy += fnt.GetHeight();
|
||||
yy += 3;
|
||||
}
|
||||
// in doom/heretic (draw key icons)
|
||||
|
|
@ -1111,7 +1126,7 @@ Class SWWMStatusBar : BaseStatusBar
|
|||
if ( !d || (d.dashfuel > 20) || ((gametic%10) < 5) ) alph = 1.;
|
||||
Screen.DrawTexture(DashTex,false,margin+2,ss.y-(margin+20),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,dw,DTA_Alpha,alph);
|
||||
double fw = FuelInter.GetValue()/2.;
|
||||
Screen.DrawTexture(FuelTex,false,margin+2,ss.y-(margin+24),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,fw);
|
||||
Screen.DrawTexture(FuelTex[swwm_superfuel],false,margin+2,ss.y-(margin+24),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRightF,fw);
|
||||
double ht = clamp(HealthInter.GetValue(),0,10000);
|
||||
double hw = min(ht,100);
|
||||
if ( isInvulnerable() || CPlayer.mo.FindInventory("InvinciballPower") )
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ Class SWWMStatScreen : StatusScreen abstract
|
|||
transient TextureID bgtex, arttex;
|
||||
transient Font TewiFont, MPlusFont;
|
||||
int whichart, whichtip;
|
||||
transient CVar intertype, lang, origmus;
|
||||
transient CVar interart, lang, origmus;
|
||||
double hs, hs2;
|
||||
Vector2 ss, ss2, origin, origin2;
|
||||
double bgfade;
|
||||
|
|
@ -30,68 +30,38 @@ Class SWWMStatScreen : StatusScreen abstract
|
|||
}
|
||||
private void drawSWWMBg()
|
||||
{
|
||||
if ( !intertype ) intertype = CVar.GetCVar('swwm_intertype',players[consoleplayer]);
|
||||
if ( !interart ) interart = CVar.GetCVar('swwm_interart',players[consoleplayer]);
|
||||
let pdata = SWWMStatScreenData(ThinkerIterator.Create("SWWMStatScreenData",Thinker.STAT_STATIC).Next());
|
||||
if ( !pdata )
|
||||
{
|
||||
pdata = new("SWWMStatScreenData");
|
||||
pdata.ChangeStatNum(Thinker.STAT_STATIC);
|
||||
}
|
||||
if ( !whichart )
|
||||
if ( !whichart && interart.GetBool() )
|
||||
{
|
||||
int no = 0;
|
||||
if ( intertype.GetInt() == 1 )
|
||||
int no = StringTable.Localize("$SWWM_NFANART").ToInt();
|
||||
Array<Int> ents;
|
||||
ents.Clear();
|
||||
for ( int i=1; i<=no; i++ )
|
||||
ents.Push(i);
|
||||
if ( pdata.lastart.Size() >= no )
|
||||
{
|
||||
no = StringTable.Localize("$SWWM_NFANART").ToInt();
|
||||
Array<Int> ents;
|
||||
ents.Clear();
|
||||
for ( int i=1; i<=no; i++ )
|
||||
ents.Push(i);
|
||||
if ( pdata.lastart.Size() >= no )
|
||||
{
|
||||
// exclude last one, start over
|
||||
int excludeme = pdata.lastart[pdata.lastart.Size()-1];
|
||||
ents.Delete(excludeme-1);
|
||||
pdata.lastart.Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( int i=0; i<pdata.lastart.Size(); i++ )
|
||||
{
|
||||
int f = ents.Find(pdata.lastart[i]);
|
||||
if ( f != ents.Size() )
|
||||
ents.Delete(f);
|
||||
}
|
||||
}
|
||||
whichart = ents[Random[InterArt](0,ents.Size()-1)];
|
||||
pdata.lastart.Push(whichart);
|
||||
// exclude last one, start over
|
||||
int excludeme = pdata.lastart[pdata.lastart.Size()-1];
|
||||
ents.Delete(excludeme-1);
|
||||
pdata.lastart.Clear();
|
||||
}
|
||||
else if ( intertype.GetInt() == 2 )
|
||||
else
|
||||
{
|
||||
no = StringTable.Localize("$SWWM_N4KOMA").ToInt();
|
||||
Array<Int> ents;
|
||||
ents.Clear();
|
||||
for ( int i=1; i<=no; i++ )
|
||||
ents.Push(i);
|
||||
if ( pdata.last4koma.Size() >= no )
|
||||
for ( int i=0; i<pdata.lastart.Size(); i++ )
|
||||
{
|
||||
// exclude last one, start over
|
||||
int excludeme = pdata.last4koma[pdata.last4koma.Size()-1];
|
||||
ents.Delete(excludeme-1);
|
||||
pdata.last4koma.Clear();
|
||||
int f = ents.Find(pdata.lastart[i]);
|
||||
if ( f != ents.Size() )
|
||||
ents.Delete(f);
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( int i=0; i<pdata.last4koma.Size(); i++ )
|
||||
{
|
||||
int f = ents.Find(pdata.last4koma[i]);
|
||||
if ( f != ents.Size() )
|
||||
ents.Delete(f);
|
||||
}
|
||||
}
|
||||
whichart = ents[Random[InterArt](0,ents.Size()-1)];
|
||||
pdata.last4koma.Push(whichart);
|
||||
}
|
||||
whichart = ents[Random[InterArt](0,ents.Size()-1)];
|
||||
pdata.lastart.Push(whichart);
|
||||
}
|
||||
if ( !bgtex ) bgtex = TexMan.CheckForTexture("graphics/InterBG.png",TexMan.Type_MiscPatch);
|
||||
double ar = Screen.GetAspectRatio();
|
||||
|
|
@ -103,8 +73,8 @@ Class SWWMStatScreen : StatusScreen abstract
|
|||
else vsize = tsize;
|
||||
Screen.DrawTexture(bgtex,false,(vsize.x-tsize.x)/2,(vsize.y-tsize.y)/2,DTA_VirtualWidthF,vsize.x,DTA_VirtualHeightF,vsize.y,DTA_KeepRatio,true);
|
||||
Font fnt = LangFont(TewiFont);
|
||||
// background pics (fanart, 4komas)
|
||||
if ( intertype.GetInt() == 1 )
|
||||
// background pics
|
||||
if ( whichart )
|
||||
{
|
||||
String artstr = StringTable.Localize(String.Format("$SWWM_FANART%d",whichart));
|
||||
int semic = artstr.IndexOf(";");
|
||||
|
|
@ -121,10 +91,6 @@ Class SWWMStatScreen : StatusScreen abstract
|
|||
Screen.Dim("Black",.8,Screen.GetWidth()-bw,Screen.GetHeight()-bh,bw,bh);
|
||||
Screen.DrawText(fnt,Font.CR_GOLD,ss.x-(len+4),ss.y-(fnt.GetHeight()+2),bstr,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
||||
}
|
||||
/*else if ( intertype.GetInt() == 2 )
|
||||
{
|
||||
// TBD when there's art
|
||||
}*/
|
||||
// intermission tips at the bottom
|
||||
if ( !whichtip )
|
||||
{
|
||||
|
|
@ -250,7 +216,7 @@ Class SWWMStatScreen : StatusScreen abstract
|
|||
}
|
||||
if ( bgfade <= 0. ) return;
|
||||
// redraw bgs on top, hiding the rest of the ui
|
||||
if ( intertype.GetInt() == 1 )
|
||||
if ( whichart )
|
||||
{
|
||||
double ar = Screen.GetAspectRatio();
|
||||
Vector2 tsize = TexMan.GetScaledSize(arttex);
|
||||
|
|
@ -261,10 +227,6 @@ Class SWWMStatScreen : StatusScreen abstract
|
|||
else vsize = tsize;
|
||||
Screen.DrawTexture(arttex,false,(vsize.x-tsize.x)/2,(vsize.y-tsize.y)/2,DTA_VirtualWidthF,vsize.x,DTA_VirtualHeightF,vsize.y,DTA_KeepRatio,true,DTA_Alpha,bgfade);
|
||||
}
|
||||
/*else if ( intertype.GetInt() == 2 )
|
||||
{
|
||||
// TBD when there's art
|
||||
}*/
|
||||
else
|
||||
{
|
||||
double ar = Screen.GetAspectRatio();
|
||||
|
|
|
|||
|
|
@ -740,8 +740,6 @@ Class ParryField : Actor
|
|||
+DONTSPLASH;
|
||||
+NOTELEPORT;
|
||||
+NOINTERACTION;
|
||||
Radius 20;
|
||||
Height 40;
|
||||
}
|
||||
|
||||
override void Tick()
|
||||
|
|
@ -753,14 +751,14 @@ Class ParryField : Actor
|
|||
}
|
||||
Vector3 x, y, z, origin;
|
||||
[x, y, z] = swwm_CoordUtil.GetAxes(master.pitch,master.angle,master.roll);
|
||||
origin = level.Vec3Offset(master.Vec2OffsetZ(0,0,master.player.viewz),x*20-(0,0,20));
|
||||
SetOrigin(origin,true);
|
||||
origin = level.Vec3Offset(master.Vec2OffsetZ(0,0,master.player.viewz),x*20);
|
||||
SetOrigin(origin,false);
|
||||
// check for projectiles to deflect
|
||||
let ti = ThinkerIterator.Create("Actor");
|
||||
Actor a;
|
||||
while ( a = Actor(ti.Next()) )
|
||||
{
|
||||
if ( !((a.bMISSILE && !a.IsZeroDamage() && (a.target != master)) || a.bSKULLFLY) || a.bTHRUACTORS || (level.Vec3Diff(a.pos,Vec3Offset(0,0,20)).length() > 80) ) continue;
|
||||
if ( !((a.bMISSILE && !a.IsZeroDamage() && (a.target != master)) || a.bSKULLFLY) || a.bTHRUACTORS || (level.Vec3Diff(a.pos,pos).length() > 80) ) continue;
|
||||
Vector3 vdir = a.vel;
|
||||
Vector3 dir = level.Vec3Diff(master.Vec2OffsetZ(0,0,pos.z),a.pos).unit();
|
||||
if ( a.bMISSILE )
|
||||
|
|
@ -1133,8 +1131,6 @@ Class SWWMWeapon : Weapon abstract
|
|||
}
|
||||
action void A_Melee( int dmg = 40, String hitsound = "", double rangemul = 1. )
|
||||
{
|
||||
// temporarily disable parry field so we can trace through
|
||||
if ( invoker.pfield ) invoker.pfield.bSHOOTABLE = false;
|
||||
// check for usables
|
||||
let ut = new("UseLineTracer");
|
||||
ut.uses.Clear();
|
||||
|
|
@ -1165,12 +1161,8 @@ Class SWWMWeapon : Weapon abstract
|
|||
for ( int i=0; i<maxang; i++ )
|
||||
{
|
||||
if ( TryMelee(angle+i*(45./16),dmg,hitsound,rangemul) || TryMelee(angle-i*(45./16),dmg,hitsound,rangemul) )
|
||||
{
|
||||
if ( invoker.pfield ) invoker.pfield.bSHOOTABLE = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if ( invoker.pfield ) invoker.pfield.bSHOOTABLE = true;
|
||||
// check for walls instead
|
||||
FTranslatedLineTarget t;
|
||||
double slope = AimLineAttack(angle,DEFMELEERANGE*rangemul,t,0.,ALF_CHECK3D);
|
||||
|
|
@ -1208,6 +1200,7 @@ Class SWWMWeapon : Weapon abstract
|
|||
A_StartSound(raging?"pusher/althit":(hitsound!="")?hitsound:"demolitionist/punch",CHAN_WEAPON,CHANF_OVERLAP);
|
||||
A_AlertMonsters(100);
|
||||
if ( raging ) raging.DoHitFX();
|
||||
if ( swwm_omnibust ) BusterWall.BustLinetrace(d,raging?(dmg*8):dmg,self,d.HitDir,d.HitLocation.z);
|
||||
}
|
||||
override void PlayUpSound( Actor origin )
|
||||
{
|
||||
|
|
@ -1287,7 +1280,9 @@ Class SWWMWeapon : Weapon abstract
|
|||
Weapon.BobRangeX 0.5;
|
||||
Weapon.BobRangeY 0.2;
|
||||
Weapon.YAdjust 0;
|
||||
Weapon.SlotPriority 1.;
|
||||
Inventory.RestrictedTo "Demolitionist";
|
||||
+INVENTORY.IGNORESKILL;
|
||||
+WEAPON.NOALERT;
|
||||
+WEAPON.NODEATHINPUT;
|
||||
+FLOATBOB;
|
||||
|
|
|
|||
|
|
@ -275,7 +275,14 @@ Class PusherProjectile : Actor
|
|||
let p = Spawn("BigPusherImpact",d.HitLocation+HitNormal*4);
|
||||
p.angle = atan2(HitNormal.y,HitNormal.x);
|
||||
p.pitch = asin(-HitNormal.z);
|
||||
bNOGRAVITY = true;
|
||||
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.;
|
||||
|
|
@ -376,7 +383,7 @@ Class PusherWeapon : SWWMWeapon
|
|||
LineTrace(angle,60,pitch,TRF_ABSPOSITION,origin.z,origin.x,origin.y,d);
|
||||
if ( d.HitType != TRACE_HitNone )
|
||||
{
|
||||
A_QuakeEx(3,3,3,7,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:.8);
|
||||
A_QuakeEx(2,2,2,7,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:.8);
|
||||
A_AlertMonsters(1200);
|
||||
int dmg = int(5+invoker.chargelevel*3);
|
||||
if ( d.HitType == TRACE_HitActor )
|
||||
|
|
@ -384,7 +391,7 @@ Class PusherWeapon : SWWMWeapon
|
|||
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(4,4,4,10,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:1.1);
|
||||
d.HitActor.A_QuakeEx(3,3,3,10,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:1.1);
|
||||
dmg = d.HitActor.DamageMobj(invoker,self,dmg,'Tenderize',DMG_THRUSTLESS);
|
||||
if ( d.HitActor.bNOBLOOD || d.HitActor.bINVULNERABLE )
|
||||
{
|
||||
|
|
@ -398,8 +405,9 @@ Class PusherWeapon : SWWMWeapon
|
|||
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
|
||||
bJUSTATTACKED = true;
|
||||
// move towards target (unless we're standing on it)
|
||||
if ( !(self is 'Demolitionist') || (Demolitionist(self).oldencroached != d.HitActor) )
|
||||
bJUSTATTACKED = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -424,6 +432,7 @@ Class PusherWeapon : SWWMWeapon
|
|||
p.angle = atan2(HitNormal.y,HitNormal.x);
|
||||
p.pitch = asin(-HitNormal.z);
|
||||
}
|
||||
if ( swwm_omnibust ) BusterWall.BustLinetrace(d,dmg,self,d.HitDir,d.HitLocation.z);
|
||||
}
|
||||
int numpt = Random[Pusher](1,3);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
|
|
@ -507,6 +516,7 @@ Class PusherWeapon : SWWMWeapon
|
|||
p.angle = atan2(HitNormal.y,HitNormal.x);
|
||||
p.pitch = asin(-HitNormal.z);
|
||||
}
|
||||
if ( swwm_omnibust ) BusterWall.BustLinetrace(d,dmg,self,d.HitDir,d.HitLocation.z);
|
||||
}
|
||||
else if ( !Random[Pusher](0,3-int(invoker.chargelevel*3)) )
|
||||
{
|
||||
|
|
@ -576,6 +586,7 @@ Class PusherWeapon : SWWMWeapon
|
|||
Inventory.Icon "graphics/HUD/Icons/W_Pusher.png";
|
||||
Weapon.UpSound "pusher/select";
|
||||
Weapon.SlotNumber 1;
|
||||
Weapon.SlotPriority 2.;
|
||||
Weapon.SelectionOrder 2100;
|
||||
Stamina 10000;
|
||||
+WEAPON.MELEEWEAPON;
|
||||
|
|
|
|||
|
|
@ -957,6 +957,8 @@ Class SWWMKnowledgeBaseMenu : GenericMenu
|
|||
{
|
||||
if ( !invlist[i] ) continue;
|
||||
str = invlist[i].GetTag();
|
||||
if ( invlist[i] is 'SWWMCollectable' )
|
||||
str.AppendFormat(" (¥%d)",invlist[i].default.Stamina);
|
||||
len = fnt.StringWidth(str);
|
||||
if ( len > longest ) longest = len;
|
||||
}
|
||||
|
|
@ -1363,6 +1365,8 @@ Class SWWMKnowledgeBaseMenu : GenericMenu
|
|||
{
|
||||
if ( !invlist[i] ) continue;
|
||||
str = invlist[i].GetTag();
|
||||
if ( invlist[i] is 'SWWMCollectable' )
|
||||
str.AppendFormat(" (¥%d)",invlist[i].default.Stamina);
|
||||
len = fnt.StringWidth(str);
|
||||
if ( len > longest ) longest = len;
|
||||
}
|
||||
|
|
@ -1528,6 +1532,142 @@ Class SWWMKnowledgeBaseMenu : GenericMenu
|
|||
else if ( (b is 'Health') || (b is 'HealthPickup') || (b is 'SWWMHealth') ) tb = -2;
|
||||
else if ( (b is 'Armor') || (b is 'SWWMSpareArmor') ) tb = -1;
|
||||
else if ( b is 'PuzzleItem' ) tb = 1;
|
||||
if ( ta == tb )
|
||||
{
|
||||
if ( a is 'Weapon' )
|
||||
{
|
||||
bool dummy;
|
||||
int slota, slotb;
|
||||
[dummy, slota] = players[consoleplayer].weapons.LocateWeapon(Weapon(a).GetClass());
|
||||
if ( slota == 0 ) slota = 10;
|
||||
[dummy, slotb] = players[consoleplayer].weapons.LocateWeapon(Weapon(b).GetClass());
|
||||
if ( slotb == 0 ) slotb = 10;
|
||||
if ( slota == slotb )
|
||||
return (Weapon(a).SlotPriority <= Weapon(b).SlotPriority);
|
||||
return slota > slotb;
|
||||
}
|
||||
else if ( a is 'Ammo' )
|
||||
{
|
||||
Class<Weapon> usesa, usesb;
|
||||
for ( int i=0; i<AllActorClasses.Size(); i++ )
|
||||
{
|
||||
let w = (Class<Weapon>)(AllActorClasses[i]);
|
||||
if ( !w ) continue;
|
||||
let def = GetDefaultByType(w);
|
||||
if ( w is 'SWWMWeapon' )
|
||||
{
|
||||
if ( SWWMWeapon(def).UsesAmmo(Ammo(a).GetClass()) )
|
||||
usesa = w;
|
||||
if ( SWWMWeapon(def).UsesAmmo(Ammo(b).GetClass()) )
|
||||
usesb = w;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( (def.AmmoType1 == Ammo(a).GetClass()) || (def.AmmoType2 == Ammo(a).GetClass()) )
|
||||
usesa = w;
|
||||
if ( (def.AmmoType1 == Ammo(b).GetClass()) || (def.AmmoType2 == Ammo(b).GetClass()) )
|
||||
usesb = w;
|
||||
}
|
||||
if ( usesa && usesb )
|
||||
break;
|
||||
}
|
||||
if ( usesa && usesb )
|
||||
{
|
||||
bool dummy;
|
||||
int slota, slotb;
|
||||
[dummy, slota] = players[consoleplayer].weapons.LocateWeapon(usesa);
|
||||
if ( slota == 0 ) slota = 10;
|
||||
[dummy, slotb] = players[consoleplayer].weapons.LocateWeapon(usesb);
|
||||
if ( slotb == 0 ) slotb = 10;
|
||||
if ( slota == slotb )
|
||||
{
|
||||
// sort by unit value
|
||||
// (special, those with zero value go last)
|
||||
int vala = a.default.Stamina;
|
||||
if ( vala == 0 ) vala = int.max;
|
||||
int valb = b.default.Stamina;
|
||||
if ( valb == 0 ) valb = int.max;
|
||||
if ( vala == valb )
|
||||
{
|
||||
// sort alphabetically
|
||||
return a.GetTag() > b.GetTag();
|
||||
}
|
||||
return vala > valb;
|
||||
}
|
||||
return slota > slotb;
|
||||
}
|
||||
}
|
||||
else if ( a is 'MagAmmo' )
|
||||
{
|
||||
// oh boy this one gets complicated
|
||||
Class<Ammo> pamoa, pamob;
|
||||
pamoa = MagAmmo(a).ParentAmmo;
|
||||
pamob = MagAmmo(b).ParentAmmo;
|
||||
Class<Weapon> usesa, usesb;
|
||||
for ( int i=0; i<AllActorClasses.Size(); i++ )
|
||||
{
|
||||
let w = (Class<Weapon>)(AllActorClasses[i]);
|
||||
if ( !w ) continue;
|
||||
let def = GetDefaultByType(w);
|
||||
if ( w is 'SWWMWeapon' )
|
||||
{
|
||||
if ( SWWMWeapon(def).UsesAmmo(pamoa) )
|
||||
usesa = w;
|
||||
if ( SWWMWeapon(def).UsesAmmo(pamob) )
|
||||
usesb = w;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( (def.AmmoType1 == pamoa) || (def.AmmoType2 == pamoa) )
|
||||
usesa = w;
|
||||
if ( (def.AmmoType1 == pamob) || (def.AmmoType2 == pamob) )
|
||||
usesb = w;
|
||||
}
|
||||
if ( usesa && usesb )
|
||||
break;
|
||||
}
|
||||
if ( usesa && usesb )
|
||||
{
|
||||
bool dummy;
|
||||
int slota, slotb;
|
||||
[dummy, slota] = players[consoleplayer].weapons.LocateWeapon(usesa);
|
||||
if ( slota == 0 ) slota = 10;
|
||||
[dummy, slotb] = players[consoleplayer].weapons.LocateWeapon(usesb);
|
||||
if ( slotb == 0 ) slotb = 10;
|
||||
if ( slota == slotb )
|
||||
{
|
||||
// sort by unit value
|
||||
// (special, those with zero value go last)
|
||||
int vala = GetDefaultByType(pamoa).Stamina;
|
||||
if ( vala == 0 ) vala = int.max;
|
||||
int valb = GetDefaultByType(pamob).Stamina;
|
||||
if ( valb == 0 ) valb = int.max;
|
||||
if ( vala == valb )
|
||||
{
|
||||
// sort alphabetically
|
||||
return a.GetTag() > b.GetTag();
|
||||
}
|
||||
return vala > valb;
|
||||
}
|
||||
return slota > slotb;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// sort by unit value
|
||||
// (special, those with zero value go last)
|
||||
int vala = a.default.Stamina;
|
||||
if ( vala == 0 ) vala = int.max;
|
||||
int valb = b.default.Stamina;
|
||||
if ( valb == 0 ) valb = int.max;
|
||||
if ( vala == valb )
|
||||
{
|
||||
// sort alphabetically
|
||||
return a.GetTag() > b.GetTag();
|
||||
}
|
||||
return vala > valb;
|
||||
}
|
||||
}
|
||||
return ta > tb;
|
||||
}
|
||||
|
||||
|
|
@ -1538,15 +1678,25 @@ Class SWWMKnowledgeBaseMenu : GenericMenu
|
|||
let db = GetDefaultByType(b);
|
||||
if ( a is 'Weapon' ) ta = 2;
|
||||
else if ( a is 'Ammo' ) ta = 1;
|
||||
else if ( (a is 'PowerupGiver') || (a is 'AmmoFabricator') || da.bBIGPOWERUP ) ta = 3;
|
||||
else if ( (a is 'PowerupGiver') || da.bBIGPOWERUP ) ta = 3;
|
||||
else if ( (a is 'Health') || (a is 'HealthPickup') || (a is 'SWWMHealth') ) ta = 5;
|
||||
else if ( (a is 'Armor') || (a is 'SWWMSpareArmor') ) ta = 4;
|
||||
if ( b is 'Weapon' ) tb = 2;
|
||||
else if ( b is 'Ammo' ) tb = 1;
|
||||
else if ( (b is 'PowerupGiver') || (b is 'AmmoFabricator') || db.bBIGPOWERUP ) tb = 3;
|
||||
else if ( (b is 'PowerupGiver') || db.bBIGPOWERUP ) tb = 3;
|
||||
else if ( (b is 'Health') || (b is 'HealthPickup') || (b is 'SWWMHealth') ) tb = 5;
|
||||
else if ( (b is 'Armor') || (b is 'SWWMSpareArmor') ) tb = 4;
|
||||
return ta <= tb;
|
||||
if ( ta == tb )
|
||||
{
|
||||
// sort by unit price
|
||||
if ( da.Stamina == db.Stamina )
|
||||
{
|
||||
// sort alphabetically
|
||||
return da.GetTag() > db.GetTag();
|
||||
}
|
||||
return da.Stamina > db.Stamina;
|
||||
}
|
||||
return ta < tb;
|
||||
}
|
||||
|
||||
private int partition_inventory( Array<Inventory> a, int l, int h )
|
||||
|
|
@ -1609,13 +1759,37 @@ Class SWWMKnowledgeBaseMenu : GenericMenu
|
|||
qsort_store(a,b,p+1,h);
|
||||
}
|
||||
|
||||
private bool CmpMonsterKill( MonsterKill a, MonsterKill b )
|
||||
{
|
||||
if ( a.kills == b.kills )
|
||||
{
|
||||
// sort by name instead
|
||||
String taga, tagb;
|
||||
taga = GetDefaultByType(a.m).GetTag();
|
||||
tagb = GetDefaultByType(b.m).GetTag();
|
||||
// beautify if there's no tag
|
||||
if ( taga == FallbackTag )
|
||||
{
|
||||
taga = a.m.GetClassName();
|
||||
SWWMUtility.BeautifyClassName(taga);
|
||||
}
|
||||
if ( tagb == FallbackTag )
|
||||
{
|
||||
tagb = a.m.GetClassName();
|
||||
SWWMUtility.BeautifyClassName(tagb);
|
||||
}
|
||||
return taga > tagb;
|
||||
}
|
||||
return a.kills < b.kills;
|
||||
}
|
||||
|
||||
private int partition_mstats( Array<MonsterKill> a, int l, int h )
|
||||
{
|
||||
MonsterKill pv = a[h];
|
||||
int i = (l-1);
|
||||
for ( int j=l; j<=(h-1); j++ )
|
||||
{
|
||||
if ( pv.kills < a[j].kills )
|
||||
if ( CmpMonsterKill(pv,a[j]) )
|
||||
{
|
||||
i++;
|
||||
MonsterKill tmp = a[j];
|
||||
|
|
@ -1663,6 +1837,44 @@ Class SWWMKnowledgeBaseMenu : GenericMenu
|
|||
qsort_lore(a,p+1,h);
|
||||
}
|
||||
|
||||
private bool CmpCollectable( Inventory a, Inventory b )
|
||||
{
|
||||
if ( a.Stamina == b.Stamina )
|
||||
{
|
||||
// alphabetic
|
||||
return a.GetTag() > b.GetTag();
|
||||
}
|
||||
// descending value
|
||||
return a.default.Stamina < b.default.Stamina;
|
||||
}
|
||||
|
||||
private int partition_collectable( Array<Inventory> a, int l, int h )
|
||||
{
|
||||
Inventory pv = a[h];
|
||||
int i = (l-1);
|
||||
for ( int j=l; j<=(h-1); j++ )
|
||||
{
|
||||
if ( CmpCollectable(pv,a[j]) )
|
||||
{
|
||||
i++;
|
||||
Inventory tmp = a[j];
|
||||
a[j] = a[i];
|
||||
a[i] = tmp;
|
||||
}
|
||||
}
|
||||
Inventory tmp = a[h];
|
||||
a[h] = a[i+1];
|
||||
a[i+1] = tmp;
|
||||
return i+1;
|
||||
}
|
||||
private void qsort_collectable( Array<Inventory> a, int l, int h )
|
||||
{
|
||||
if ( l >= h ) return;
|
||||
int p = partition_collectable(a,l,h);
|
||||
qsort_collectable(a,l,p-1);
|
||||
qsort_collectable(a,p+1,h);
|
||||
}
|
||||
|
||||
override void Ticker()
|
||||
{
|
||||
Super.Ticker();
|
||||
|
|
@ -1696,7 +1908,7 @@ Class SWWMKnowledgeBaseMenu : GenericMenu
|
|||
// alphabetically sorted inventory
|
||||
for ( Inventory inv=players[consoleplayer].mo.Inv; inv; inv=inv.Inv )
|
||||
{
|
||||
if ( (inv.Amount <= 0) || !inv.SpawnState.ValidateSpriteFrame() || (inv is 'Key') || (inv is 'BasicArmor') || (inv is 'HexenArmor') || (inv is 'Powerup') || (inv is 'SWWMArmor') || (!(inv is 'Ammo') && !(inv is 'Weapon') && !inv.bINVBAR) && !(inv is 'HammerspaceEmbiggener') && !(inv is 'SWWMCollectable') && !(inv is 'MagAmmo') ) continue;
|
||||
if ( (inv.Amount <= 0) || !inv.SpawnState.ValidateSpriteFrame() || (inv is 'Key') || (inv is 'BasicArmor') || (inv is 'HexenArmor') || (inv is 'Powerup') || (inv is 'SWWMArmor') || (!(inv is 'Ammo') && !(inv is 'Weapon') && !inv.bINVBAR) && !(inv is 'HammerspaceEmbiggener') && !(inv is 'SWWMCollectable') && !(inv is 'MagAmmo') || (inv is 'SWWMCollectable') ) continue;
|
||||
// no hidden weapons
|
||||
if ( (inv is 'SWWMWeapon') && SWWMWeapon(inv).bHIDEINMENU ) continue;
|
||||
String tag = inv.GetTag();
|
||||
|
|
@ -1732,6 +1944,15 @@ Class SWWMKnowledgeBaseMenu : GenericMenu
|
|||
let k = Key(players[consoleplayer].mo.FindInventory(Key.GetKeyType(i)));
|
||||
if ( k ) invlist.Push(k);
|
||||
}
|
||||
// collectables, sorted by name
|
||||
Array<Inventory> cols;
|
||||
for ( Inventory inv=players[consoleplayer].mo.Inv; inv; inv=inv.Inv )
|
||||
{
|
||||
if ( inv is 'SWWMCollectable' )
|
||||
cols.Push(inv);
|
||||
}
|
||||
qsort_collectable(cols,0,cols.Size()-1);
|
||||
invlist.Append(cols);
|
||||
// crop selection
|
||||
if ( sel0 >= invlist.Size() ) sel0 = max(0,invlist.Size()-1);
|
||||
}
|
||||
|
|
@ -1746,8 +1967,6 @@ Class SWWMKnowledgeBaseMenu : GenericMenu
|
|||
if ( !type ) continue;
|
||||
// no collectables
|
||||
if ( type is 'SWWMCollectable' ) continue;
|
||||
// no fabricators before hexen
|
||||
if ( !(gameinfo.gametype&(GAME_Hexen|GAME_Strife)) && (type is 'AmmoFabricator') ) continue;
|
||||
// skip maxed items
|
||||
let cur = players[consoleplayer].mo.FindInventory(type);
|
||||
if ( cur && (cur.Amount >= cur.MaxAmount) ) continue;
|
||||
|
|
@ -1962,6 +2181,7 @@ Class SWWMKnowledgeBaseMenu : GenericMenu
|
|||
if ( stats.favweapon == -1 ) str = str.."N/A";
|
||||
else if ( stats.wstats[stats.favweapon].w == 'SWWMWeapon' ) str = str..StringTable.Localize("$SWWM_YOURSELF");
|
||||
else if ( stats.wstats[stats.favweapon].w == 'SWWMGesture' ) str = str..StringTable.Localize("$SWWM_DOKIDOKI");
|
||||
else if ( stats.wstats[stats.favweapon].w == 'Weapon' ) str = str..StringTable.Localize("$SWWM_GRAVKILL");
|
||||
else
|
||||
{
|
||||
let def = GetDefaultByType(stats.wstats[stats.favweapon].w);
|
||||
|
|
@ -2362,19 +2582,19 @@ Class SWWMKnowledgeBaseMenu : GenericMenu
|
|||
int ox = ((cnt>22)?623:631);
|
||||
int sec = Thinker.Tics2Seconds(stats.lstats[i].time);
|
||||
str = String.Format("%02d\cu:\c-%02d\cu:\c-%02d",sec/3600,(sec%3600)/60,sec%60);
|
||||
Screen.DrawText(fnt2,Font.CR_WHITE,origin.x+ox-fnt2.StringWidth(str),origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
||||
Screen.DrawText(fnt2,(sec>=3600)?Font.CR_RED:(sec<=stats.lstats[i].par)?Font.CR_GOLD:Font.CR_WHITE,origin.x+ox-fnt2.StringWidth(str),origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
||||
Screen.DrawText(fnt2,Font.CR_FIRE,origin.x+ox-maxlen[0],origin.y+yy,"T",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
||||
ox -= maxlen[0]+8;
|
||||
str = String.Format("%d\cu/\c-%d",stats.lstats[i].scount,stats.lstats[i].stotal);
|
||||
Screen.DrawText(fnt2,Font.CR_WHITE,origin.x+ox-fnt2.StringWidth(str),origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
||||
Screen.DrawText(fnt2,(stats.lstats[i].scount>=stats.lstats[i].stotal)?Font.CR_GOLD:Font.CR_WHITE,origin.x+ox-fnt2.StringWidth(str),origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
||||
Screen.DrawText(fnt2,Font.CR_FIRE,origin.x+ox-maxlen[1],origin.y+yy,"S",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
||||
ox -= maxlen[1]+8;
|
||||
str = String.Format("%d\cu/\c-%d",stats.lstats[i].icount,stats.lstats[i].itotal);
|
||||
Screen.DrawText(fnt2,Font.CR_WHITE,origin.x+ox-fnt2.StringWidth(str),origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
||||
Screen.DrawText(fnt2,(stats.lstats[i].icount>=stats.lstats[i].itotal)?Font.CR_GOLD:Font.CR_WHITE,origin.x+ox-fnt2.StringWidth(str),origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
||||
Screen.DrawText(fnt2,Font.CR_FIRE,origin.x+ox-maxlen[2],origin.y+yy,"I",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
||||
ox -= maxlen[2]+8;
|
||||
str = String.Format("%d\cu/\c-%d",stats.lstats[i].kcount,stats.lstats[i].ktotal);
|
||||
Screen.DrawText(fnt2,Font.CR_WHITE,origin.x+ox-fnt2.StringWidth(str),origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
||||
Screen.DrawText(fnt2,(stats.lstats[i].kcount>=stats.lstats[i].ktotal)?Font.CR_GOLD:Font.CR_WHITE,origin.x+ox-fnt2.StringWidth(str),origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
||||
Screen.DrawText(fnt2,Font.CR_FIRE,origin.x+ox-maxlen[3],origin.y+yy,"K",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
||||
yy += 14;
|
||||
}
|
||||
|
|
@ -2472,6 +2692,8 @@ Class SWWMKnowledgeBaseMenu : GenericMenu
|
|||
{
|
||||
if ( !invlist[i] ) continue;
|
||||
str = invlist[i].GetTag();
|
||||
if ( invlist[i] is 'SWWMCollectable' )
|
||||
str.AppendFormat(" (¥%d)",invlist[i].default.Stamina);
|
||||
len = fnt.StringWidth(str);
|
||||
if ( len > longest ) longest = len;
|
||||
}
|
||||
|
|
@ -2482,7 +2704,9 @@ Class SWWMKnowledgeBaseMenu : GenericMenu
|
|||
{
|
||||
if ( !invlist[i] ) continue;
|
||||
str = invlist[i].GetTag();
|
||||
Screen.DrawText(fnt,Font.CR_UNTRANSLATED,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,(i!=sel0)?Color(96,0,0,0):Color(0,0,0,0));
|
||||
if ( invlist[i] is 'SWWMCollectable' )
|
||||
str.AppendFormat(" \cj(\cg¥\cf%d\cj)\c-",invlist[i].default.Stamina);
|
||||
Screen.DrawText(fnt,(invlist[i] is 'SWWMCollectable')?Font.CR_PURPLE:Font.CR_UNTRANSLATED,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,(i!=sel0)?Color(96,0,0,0):Color(0,0,0,0));
|
||||
yy += 16;
|
||||
if ( yy >= 370 )
|
||||
{
|
||||
|
|
@ -2615,7 +2839,7 @@ Class SWWMKnowledgeBaseMenu : GenericMenu
|
|||
int clscol = Font.CR_WHITE;
|
||||
if ( storelist[i] is 'Weapon' ) clscol = Font.CR_GOLD;
|
||||
else if ( storelist[i] is 'Ammo' ) clscol = Font.CR_BROWN;
|
||||
else if ( (storelist[i] is 'PowerupGiver') || (storelist[i] is 'AmmoFabricator') || def.bBIGPOWERUP ) clscol = Font.CR_PURPLE;
|
||||
else if ( (storelist[i] is 'PowerupGiver') || def.bBIGPOWERUP ) clscol = Font.CR_PURPLE;
|
||||
else if ( (storelist[i] is 'Health') || (storelist[i] is 'HealthPickup') || (storelist[i] is 'SWWMHealth') ) clscol = Font.CR_RED;
|
||||
else if ( (storelist[i] is 'Armor') || (storelist[i] is 'SWWMSpareArmor') ) clscol = Font.CR_GREEN;
|
||||
Screen.DrawText(fnt,clscol,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,(i!=sel0)?Color(96,0,0,0):Color(0,0,0,0));
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ Class Demolitionist : PlayerPawn
|
|||
};
|
||||
|
||||
int lastunder;
|
||||
Color undercol;
|
||||
int deadtimer;
|
||||
transient int revivefail;
|
||||
|
||||
|
|
@ -75,10 +76,9 @@ Class Demolitionist : PlayerPawn
|
|||
Player.AirCapacity 0;
|
||||
Player.GruntSpeed 20;
|
||||
Player.SoundClass "demolitionist";
|
||||
DamageFactor "Drowning", 0.0;
|
||||
DamageFactor "Poison", 0.0;
|
||||
DamageFactor "PoisonCloud", 0.0;
|
||||
DamageFactor "Falling", 0.0;
|
||||
DamageFactor "Drowning", 0.;
|
||||
DamageFactor "Poison", 0.;
|
||||
DamageFactor "PoisonCloud", 0.;
|
||||
Demolitionist.DashFuel 240.;
|
||||
+NOBLOOD;
|
||||
+DONTGIB;
|
||||
|
|
@ -162,6 +162,12 @@ Class Demolitionist : PlayerPawn
|
|||
if ( !type || (type == 'SWWMArmor') ) continue;
|
||||
if ( GetReplacement(type) == type )
|
||||
{
|
||||
let owned = FindInventory(type);
|
||||
if ( owned )
|
||||
{
|
||||
owned.Amount = owned.MaxAmount;
|
||||
continue;
|
||||
}
|
||||
let item = Inventory(Spawn(type));
|
||||
item.ClearCounters(); // don't increase item counts
|
||||
item.Amount = item.MaxAmount;
|
||||
|
|
@ -175,6 +181,12 @@ Class Demolitionist : PlayerPawn
|
|||
if ( !type || (type == 'SWWMSpareArmor') ) continue;
|
||||
if ( GetReplacement(type) == type )
|
||||
{
|
||||
let owned = FindInventory(type);
|
||||
if ( owned )
|
||||
{
|
||||
owned.Amount = owned.MaxAmount;
|
||||
continue;
|
||||
}
|
||||
let item = Inventory(Spawn(type));
|
||||
item.ClearCounters(); // don't increase item counts
|
||||
item.Amount = item.MaxAmount;
|
||||
|
|
@ -262,6 +274,19 @@ Class Demolitionist : PlayerPawn
|
|||
}
|
||||
if ( !giveall ) return;
|
||||
}
|
||||
if ( (giveall == ALL_YESYES) || (name ~== "collectables") )
|
||||
{
|
||||
for ( int i=0; i<AllActorClasses.Size(); i++ )
|
||||
{
|
||||
let type = (class<SWWMCollectable>)(AllActorClasses[i]);
|
||||
if ( !type || (type == 'SWWMCollectable') ) continue;
|
||||
let def = GetDefaultByType(type);
|
||||
// check that we can collect it in this IWAD
|
||||
if ( !(gameinfo.gametype&def.avail) ) continue;
|
||||
let item = Inventory(Spawn(AllActorClasses[i]));
|
||||
if ( !item.CallTryPickup(self) ) item.Destroy();
|
||||
}
|
||||
}
|
||||
if ( giveall ) return;
|
||||
let type = name;
|
||||
if ( !type )
|
||||
|
|
@ -319,7 +344,7 @@ Class Demolitionist : PlayerPawn
|
|||
dashboost *= (player.cmd.buttons&BT_USER2)?.9:.1;
|
||||
}
|
||||
mystats.fuelusage += dashfuel-max(0.,dashfuel-dashboost);
|
||||
dashfuel = max(0.,dashfuel-dashboost);
|
||||
if ( !swwm_superfuel ) dashfuel = max(0.,dashfuel-dashboost);
|
||||
dashcooldown = min(40,max(10,int(dashcooldown*1.4)));
|
||||
fuelcooldown = max(30,fuelcooldown);
|
||||
if ( (dashfuel <= 0.) || (dashboost <= 0.) )
|
||||
|
|
@ -337,7 +362,7 @@ Class Demolitionist : PlayerPawn
|
|||
last_boost = level.maptime+1;
|
||||
}
|
||||
mystats.fuelusage += dashfuel-max(0.,dashfuel-dashboost);
|
||||
dashfuel = max(0.,dashfuel-dashboost);
|
||||
if ( !swwm_superfuel ) dashfuel = max(0.,dashfuel-dashboost);
|
||||
if ( ((dashfuel <= 0.) || (dashboost <= 0.)) )
|
||||
{
|
||||
if ( !initial )
|
||||
|
|
@ -416,6 +441,7 @@ Class Demolitionist : PlayerPawn
|
|||
curunder = UNDER_WATER;
|
||||
break;
|
||||
}
|
||||
undercol = headregion.ColorMap.LightColor;
|
||||
}
|
||||
if ( (curunder != lastunder) || restore )
|
||||
{
|
||||
|
|
@ -567,7 +593,7 @@ Class Demolitionist : PlayerPawn
|
|||
if ( vel.length() > mystats.topspeed ) mystats.topspeed = vel.length();
|
||||
if ( !myvoice ) myvoice = CVar.GetCVar('swwm_voicetype',player);
|
||||
if ( !mute ) mute = CVar.GetCVar('swwm_mutevoice',player);
|
||||
if ( player.onground && !bNoGravity && !lastground && (waterlevel < 2) && (health > 0) )
|
||||
if ( player.onground && !bNoGravity && !lastground && (waterlevel < 2) )
|
||||
{
|
||||
// bump down weapon
|
||||
bumpdown = true;
|
||||
|
|
@ -589,7 +615,7 @@ Class Demolitionist : PlayerPawn
|
|||
mystats.stompcount++;
|
||||
}
|
||||
if ( lastvelz < -10 ) A_StartSound("demolitionist/runstop",CHAN_FOOTSTEP,CHANF_OVERLAP);
|
||||
if ( (player == players[consoleplayer]) && (lastvelz < -gruntspeed) && (mute.GetInt() < 4) )
|
||||
if ( (player == players[consoleplayer]) && (lastvelz < -gruntspeed) && (mute.GetInt() < 4) && (health > 0) )
|
||||
A_StartSound(String.Format("voice/%s/grunt",myvoice.GetString()),CHAN_DEMOVOICE,CHANF_OVERLAP);
|
||||
if ( lastvelz < -1 )
|
||||
A_Footstep(0,true,clamp(-lastvelz*0.05,0.0,1.0));
|
||||
|
|
@ -702,6 +728,7 @@ Class Demolitionist : PlayerPawn
|
|||
if ( a.bACTLIKEBRIDGE && (diff.z <= -a.Height) ) continue; // don't bump bridges if hit by above
|
||||
// large monsters will stop the player (unless hit from above if we're going at ground pound speed)
|
||||
A_QuakeEx(4,4,4,10,0,128,"",QF_RELATIVE|QF_SCALEDOWN);
|
||||
A_AlertMonsters(800);
|
||||
A_StartSound("demolitionist/bump",CHAN_DAMAGE,CHANF_OVERLAP);
|
||||
a.A_StartSound("demolitionist/bump",CHAN_DAMAGE,CHANF_OVERLAP);
|
||||
bumptic = gametic+int(20+spd/4.);
|
||||
|
|
@ -776,11 +803,12 @@ Class Demolitionist : PlayerPawn
|
|||
if ( dir dot ceilnorm < -.6 )
|
||||
{
|
||||
bool busted = false;
|
||||
if ( raging )
|
||||
if ( raging || swwm_omnibust )
|
||||
{
|
||||
// see if we can bust it
|
||||
let tempme = new("LineTracer"); // gross hack to pass needed data
|
||||
int dmg = int(128+spd*20);
|
||||
int dmg = int(15+spd*2.5);
|
||||
if ( raging ) dmg *= 8;
|
||||
bool buttslam = false;
|
||||
// BUTTSLAM
|
||||
if ( dir dot viewdir < -.3 )
|
||||
|
|
@ -794,13 +822,16 @@ Class Demolitionist : PlayerPawn
|
|||
if ( BusterWall.Bust(tempme.Results,dmg,self,dir,pos.z+Height) )
|
||||
{
|
||||
// busted through
|
||||
let ps = Spawn("BigPunchSplash",Vec3Offset(0,0,Height));
|
||||
ps.damagetype = buttslam?'Buttslam':'Dash';
|
||||
ps.target = self;
|
||||
ps.special1 = int(15+spd*2.5);
|
||||
if ( raging )
|
||||
{
|
||||
let ps = Spawn("BigPunchSplash",Vec3Offset(0,0,Height));
|
||||
ps.damagetype = buttslam?'Buttslam':'Dash';
|
||||
ps.target = self;
|
||||
ps.special1 = int(15+spd*2.5);
|
||||
raging.DoHitFX();
|
||||
}
|
||||
A_StartSound("demolitionist/bump",CHAN_DAMAGE,CHANF_OVERLAP);
|
||||
busted = true;
|
||||
raging.DoHitFX();
|
||||
if ( buttslam )
|
||||
{
|
||||
A_StartSound("demolitionist/buttslam",CHAN_DAMAGE,CHANF_OVERLAP,1.,.2);
|
||||
|
|
@ -810,13 +841,14 @@ Class Demolitionist : PlayerPawn
|
|||
}
|
||||
}
|
||||
}
|
||||
if ( !busted )
|
||||
if ( !busted || !raging )
|
||||
{
|
||||
// headbump
|
||||
bumped = true;
|
||||
A_StartSound("demolitionist/bump",CHAN_DAMAGE,CHANF_OVERLAP);
|
||||
bumptic = gametic+int(20+spd/4.);
|
||||
A_QuakeEx(8,8,8,16,0,128,"",QF_RELATIVE|QF_SCALEDOWN);
|
||||
A_AlertMonsters(800);
|
||||
vel *= .2;
|
||||
vel -= dir*(10+(spd*30/mass));
|
||||
vel.z += 5+(spd*(10/mass));
|
||||
|
|
@ -853,11 +885,12 @@ Class Demolitionist : PlayerPawn
|
|||
// don't bump if we're only grazing it
|
||||
if ( dir dot wallnorm > -.6 )
|
||||
continue;
|
||||
if ( raging )
|
||||
if ( raging || swwm_omnibust )
|
||||
{
|
||||
// see if we can bust it
|
||||
let tempme = new("LineTracer"); // gross hack to pass needed data
|
||||
int dmg = int(128+spd*20);
|
||||
int dmg = int(15+spd*2.5);
|
||||
if ( raging ) dmg *= 8;
|
||||
bool buttslam = false;
|
||||
// BUTTSLAM
|
||||
if ( dir dot viewdir < -.3 )
|
||||
|
|
@ -881,12 +914,15 @@ Class Demolitionist : PlayerPawn
|
|||
if ( BusterWall.Bust(tempme.Results,dmg,self,dir,pos.z+Height/2) )
|
||||
{
|
||||
// busted through
|
||||
let ps = Spawn("BigPunchSplash",Vec3Offset(dir.x*radius,dir.y*radius,(tempme.Results.Tier==TIER_UPPER)?Height:(tempme.Results.Tier==TIER_LOWER)?0:(Height/2)));
|
||||
ps.damagetype = buttslam?'Buttslam':'Dash';
|
||||
ps.target = self;
|
||||
ps.special1 = int(15+spd*2.5);
|
||||
if ( raging )
|
||||
{
|
||||
let ps = Spawn("BigPunchSplash",Vec3Offset(dir.x*radius,dir.y*radius,(tempme.Results.Tier==TIER_UPPER)?Height:(tempme.Results.Tier==TIER_LOWER)?0:(Height/2)));
|
||||
ps.damagetype = buttslam?'Buttslam':'Dash';
|
||||
ps.target = self;
|
||||
ps.special1 = int(15+spd*2.5);
|
||||
raging.DoHitFX();
|
||||
}
|
||||
A_StartSound("demolitionist/bump",CHAN_DAMAGE,CHANF_OVERLAP);
|
||||
raging.DoHitFX();
|
||||
if ( buttslam )
|
||||
{
|
||||
A_StartSound("demolitionist/buttslam",CHAN_DAMAGE,CHANF_OVERLAP,1.,.2);
|
||||
|
|
@ -894,7 +930,7 @@ Class Demolitionist : PlayerPawn
|
|||
A_QuakeEx(8,8,8,8,0,3000,"",QF_RELATIVE|QF_SCALEDOWN,falloff:300,rollIntensity:1.);
|
||||
mystats.buttslams++;
|
||||
}
|
||||
continue;
|
||||
if ( raging ) continue; // don't stop
|
||||
}
|
||||
}
|
||||
// wallbump
|
||||
|
|
@ -902,6 +938,7 @@ Class Demolitionist : PlayerPawn
|
|||
A_StartSound("demolitionist/bump",CHAN_DAMAGE,CHANF_OVERLAP);
|
||||
bumptic = gametic+int(20+spd/4.);
|
||||
A_QuakeEx(8,8,8,16,0,128,"",QF_RELATIVE|QF_SCALEDOWN);
|
||||
A_AlertMonsters(800);
|
||||
vel *= .2;
|
||||
vel -= dir*(10+(spd*30/mass));
|
||||
vel += wallnorm*(10+(spd*50/mass));
|
||||
|
|
@ -940,6 +977,9 @@ Class Demolitionist : PlayerPawn
|
|||
}
|
||||
override int DamageMobj( Actor inflictor, Actor source, int damage, Name mod, int flags, double angle )
|
||||
{
|
||||
// completely nullify non-lethal fall damage
|
||||
if ( (mod == 'Falling') && (damage < TELEFRAG_DAMAGE) )
|
||||
damage = 0;
|
||||
if ( damage <= 0 )
|
||||
{
|
||||
lastdamage = 0;
|
||||
|
|
@ -2105,22 +2145,21 @@ Class Demolitionist : PlayerPawn
|
|||
Loop;
|
||||
CrouchWave:
|
||||
#### # 3;
|
||||
XZWE Z 3;
|
||||
XZWF ABCDEFGHIJKLMN 3;
|
||||
XZWF ABCDEFGHIJKLMNO 3;
|
||||
Goto Crouch+1;
|
||||
CrouchApprove:
|
||||
#### # 3;
|
||||
XZWF OPQRSTUVWXYZ 3;
|
||||
XZWG ABCDE 3;
|
||||
XZWF PQRSTUVWXYZ 3;
|
||||
XZWG ABCDEF 3;
|
||||
Goto Crouch+1;
|
||||
CrouchVictory:
|
||||
#### # 3;
|
||||
XZWG FGHIJKLMNOPQRSTUVWX 3;
|
||||
XZWG GHIJKLMNOPQRSTUVWXY 3;
|
||||
Goto Crouch+1;
|
||||
CrouchBlowKiss:
|
||||
#### # 3;
|
||||
XZWG YZ 3;
|
||||
XZWH ABCDEFGHIJKLMNOPQ 3;
|
||||
XZWG Z 3;
|
||||
XZWH ABCDEFGHIJKLMNOPQR 3;
|
||||
Goto Crouch+1;
|
||||
CrouchMissile:
|
||||
XZW7 M 2;
|
||||
|
|
@ -2168,23 +2207,23 @@ Class Demolitionist : PlayerPawn
|
|||
Goto Spawn+1;
|
||||
Float:
|
||||
#### # 3;
|
||||
XZWD WXYZ 3;
|
||||
XZWE ABCDEFGH 3;
|
||||
XZWD XYZ 3;
|
||||
XZWE ABCDEFGHI 3;
|
||||
Goto Float+1;
|
||||
Swim:
|
||||
#### # 2;
|
||||
XZWE IJK 2;
|
||||
XZWE JKL 2;
|
||||
Goto SwimLoop;
|
||||
SwimLoop:
|
||||
XZWE LMN 2;
|
||||
XZWE O 0 A_StartSound("demolitionist/runstart",CHAN_FOOTSTEP,CHANF_OVERLAP,.2);
|
||||
XZWE OPQRST 2;
|
||||
XZWE U 0 A_StartSound("demolitionist/runstop",CHAN_FOOTSTEP,CHANF_OVERLAP,.2);
|
||||
XZWE UVW 2;
|
||||
XZWE MNO 2;
|
||||
XZWE P 0 A_StartSound("demolitionist/runstart",CHAN_FOOTSTEP,CHANF_OVERLAP,.2);
|
||||
XZWE PQRSTU 2;
|
||||
XZWE V 0 A_StartSound("demolitionist/runstop",CHAN_FOOTSTEP,CHANF_OVERLAP,.2);
|
||||
XZWE VWX 2;
|
||||
Loop;
|
||||
SwimEnd:
|
||||
#### # 2;
|
||||
XZWE LXY 2;
|
||||
XZWE MYZ 2;
|
||||
Goto Float+1;
|
||||
VoodooSpawn:
|
||||
XZWZ A -1;
|
||||
|
|
@ -2443,11 +2482,12 @@ Class DemolitionistShockwave : Actor
|
|||
s.vel = pvel;
|
||||
}
|
||||
let raging = RagekitPower(target.FindInventory("RagekitPower"));
|
||||
if ( raging )
|
||||
if ( raging || swwm_omnibust )
|
||||
{
|
||||
// bust the floor if we can
|
||||
let tempme = new("LineTracer"); // gross hack to pass needed data
|
||||
int dmg = (40+min(special1,120))*8;
|
||||
int dmg = 40+min(special1,120);
|
||||
if ( raging ) dmg *= 8;
|
||||
F3DFloor ff;
|
||||
for ( int i=0; i<FloorSector.Get3DFloorCount(); i++ )
|
||||
{
|
||||
|
|
@ -2459,11 +2499,14 @@ Class DemolitionistShockwave : Actor
|
|||
tempme.Results.HitSector = FloorSector;
|
||||
tempme.Results.HitType = TRACE_HitFloor;
|
||||
BusterWall.Bust(tempme.Results,dmg,target,(0,0,-1),pos.z);
|
||||
let ps = Spawn("BigPunchSplash",pos);
|
||||
ps.damagetype = 'GroundPound';
|
||||
ps.target = target;
|
||||
ps.special1 = dmg;
|
||||
raging.DoHitFX();
|
||||
if ( raging )
|
||||
{
|
||||
let ps = Spawn("BigPunchSplash",pos);
|
||||
ps.damagetype = 'GroundPound';
|
||||
ps.target = target;
|
||||
ps.special1 = dmg;
|
||||
raging.DoHitFX();
|
||||
}
|
||||
}
|
||||
}
|
||||
States
|
||||
|
|
@ -2656,6 +2699,24 @@ Class LoveHeartBurstLight : PaletteLight
|
|||
}
|
||||
}
|
||||
|
||||
Class LoveHeartLight : PointLightAttenuated
|
||||
{
|
||||
Default
|
||||
{
|
||||
Args 255,176,208,80;
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
if ( target || target.InStateSequence(target.CurState,target.FindState("Death")) )
|
||||
{
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
SetOrigin(target.pos,true);
|
||||
}
|
||||
}
|
||||
|
||||
Class LoveHeart : Actor
|
||||
{
|
||||
Default
|
||||
|
|
@ -2679,6 +2740,17 @@ Class LoveHeart : Actor
|
|||
override int DoSpecialDamage( Actor target, int damage, Name damagetype )
|
||||
{
|
||||
let raging = RagekitPower(self.target.FindInventory("RagekitPower"));
|
||||
if ( raging )
|
||||
{
|
||||
bEXTREMEDEATH = true;
|
||||
bNOEXTREMEDEATH = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
bEXTREMEDEATH = false;
|
||||
bNOEXTREMEDEATH = true;
|
||||
}
|
||||
if ( target is 'WolfensteinSS' ) target.bFRIENDLY = false;
|
||||
if ( target.IsFriend(self.target) || (target is 'MBFHelperDog') )
|
||||
{
|
||||
int healamt = clamp(special2,5,15);
|
||||
|
|
@ -2701,6 +2773,8 @@ Class LoveHeart : Actor
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
Vector3 dirto = level.Vec3Diff(pos,target.Vec3Offset(0,0,target.Height/2)).unit();
|
||||
SWWMUtility.DoKnockback(target,dirto,1500.*damage);
|
||||
let bread = target.FindState("Pain");
|
||||
if ( bread ) target.SetState(bread);
|
||||
if ( raging )
|
||||
|
|
@ -2708,6 +2782,14 @@ Class LoveHeart : Actor
|
|||
damage *= 8;
|
||||
raging.DoHitFX();
|
||||
}
|
||||
if ( target is 'WolfensteinSS' )
|
||||
{
|
||||
damage = int.max;
|
||||
bEXTREMEDEATH = true;
|
||||
bNOEXTREMEDEATH = false;
|
||||
}
|
||||
else if ( target is 'SWWMHangingKeen' )
|
||||
damage = max(target.Health,damage);
|
||||
return damage;
|
||||
}
|
||||
|
||||
|
|
@ -2751,13 +2833,30 @@ Class LoveHeart : Actor
|
|||
{
|
||||
Super.PostBeginPlay();
|
||||
A_StartSound("misc/heart",CHAN_WEAPON);
|
||||
A_AttachLight('LOVELIGHT',DynamicLight.PointLight,Color(255,176,208),80,80,DYNAMICLIGHT.LF_ATTENUATE);
|
||||
//A_AttachLight('LOVELIGHT',DynamicLight.PointLight,Color(255,176,208),80,80,DYNAMICLIGHT.LF_ATTENUATE);
|
||||
// can't use Attach/RemoveLight for now due to heavy performance issues
|
||||
let l = Spawn("LoveHeartLight",pos);
|
||||
l.target = self;
|
||||
special2 = 25;
|
||||
}
|
||||
action void A_HeartBurst()
|
||||
{
|
||||
// use line
|
||||
if ( BlockingLine )
|
||||
{
|
||||
int s = SWWMUtility.PointOnLineSide(pos.xy,BlockingLine);
|
||||
BlockingLine.RemoteActivate(target,s,SPAC_Use,pos);
|
||||
}
|
||||
if ( swwm_omnibust )
|
||||
{
|
||||
int dmg = GetMissileDamage(0,0);
|
||||
let raging = RagekitPower(self.target.FindInventory("RagekitPower"));
|
||||
if ( raging ) dmg *= 8;
|
||||
if ( BusterWall.ProjectileBust(self,dmg,(cos(angle)*cos(pitch),sin(angle)*cos(pitch),sin(-pitch))) )
|
||||
raging.DoHitFX();
|
||||
}
|
||||
A_SetRenderStyle(1.,STYLE_Add);
|
||||
A_RemoveLight('LOVELIGHT');
|
||||
//A_RemoveLight('LOVELIGHT');
|
||||
A_QuakeEx(2,2,2,8,0,300,"",QF_RELATIVE|QF_SCALEDOWN);
|
||||
A_StartSound("bestsound",CHAN_VOICE);
|
||||
Spawn("LoveHeartBurstLight",pos);
|
||||
|
|
@ -2810,8 +2909,8 @@ Class HHitList
|
|||
Class SWWMGesture : SWWMWeapon
|
||||
{
|
||||
Weapon formerweapon;
|
||||
int whichgesture;
|
||||
bool deaded;
|
||||
int whichgesture, nextgesture;
|
||||
bool deaded, queued;
|
||||
int gonect;
|
||||
|
||||
// these should prevent autoswitch when out of ammo
|
||||
|
|
@ -2826,7 +2925,20 @@ Class SWWMGesture : SWWMWeapon
|
|||
|
||||
static void SetGesture( PlayerPawn mo, int which = 0 )
|
||||
{
|
||||
if ( (mo.player.ReadyWeapon is 'SWWMGesture') || (mo.player.PendingWeapon is 'SWWMGesture') ) return; // already gesturing
|
||||
if ( mo.player.PendingWeapon is 'SWWMGesture' ) return; // already initiating a gesture
|
||||
if ( (mo.player.ReadyWeapon is 'SWWMGesture') )
|
||||
{
|
||||
// already gesturing
|
||||
// just queue another one
|
||||
// (ignore grenade, that one uses special refire handling)
|
||||
if ( which != -1 )
|
||||
{
|
||||
let g = SWWMGesture(mo.player.ReadyWeapon);
|
||||
g.nextgesture = which;
|
||||
g.queued = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
SWWMGesture w = SWWMGesture(mo.FindInventory("SWWMGesture"));
|
||||
if ( !w )
|
||||
{
|
||||
|
|
@ -2850,6 +2962,13 @@ Class SWWMGesture : SWWMWeapon
|
|||
|
||||
action void A_FinishGesture()
|
||||
{
|
||||
if ( invoker.queued )
|
||||
{
|
||||
invoker.whichgesture = invoker.nextgesture;
|
||||
invoker.queued = false;
|
||||
player.SetPSprite(PSP_WEAPON,ResolveState("Ready"));
|
||||
return;
|
||||
}
|
||||
player.PendingWeapon = invoker.formerweapon;
|
||||
player.SetPSprite(PSP_WEAPON,ResolveState("Deselect"));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,14 @@ Class GrilledCheeseSandwich : Inventory
|
|||
Mixin SWWMAutoUseFix;
|
||||
Mixin SWWMOverlapPickupSound;
|
||||
|
||||
// for falling off cliffs and others
|
||||
// last 5 seconds of safe positions
|
||||
bool lastsafevalid;
|
||||
Vector3 lastsafepos[5];
|
||||
double lastsafeangle[5];
|
||||
int safetic;
|
||||
int dteleport;
|
||||
|
||||
override Inventory CreateCopy( Actor other )
|
||||
{
|
||||
// additional lore
|
||||
|
|
@ -75,23 +83,80 @@ Class GrilledCheeseSandwich : Inventory
|
|||
return; // don't trigger on endlevel damage
|
||||
if ( damageType == 'Telefrag' )
|
||||
{
|
||||
// prevent overlap with voodoo doll
|
||||
if ( source.player == Owner.player )
|
||||
return; // we can't avoid voodoo telefrag, it would break things
|
||||
else
|
||||
Owner.DamageMobj(Owner,Owner,damage,damageType,flags); // kill what attempted the telefrag
|
||||
dteleport = 1; // teleport has to be on next tic
|
||||
else source.DamageMobj(Owner,Owner,damage,damageType,flags); // kill what attempted the telefrag
|
||||
}
|
||||
if ( (Owner.Health-damage <= 0) && (Amount > 0) )
|
||||
{
|
||||
if ( (damageType == 'Falling') || (damageType == 'InstantDeath') )
|
||||
SafeTeleport(); // get out of pits
|
||||
newdamage = 0;
|
||||
if ( (Owner.player == players[consoleplayer]) || bBigPowerup ) Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA);
|
||||
DoTheThing(true);
|
||||
Amount--;
|
||||
}
|
||||
}
|
||||
void SafeTeleport( bool tostart = false )
|
||||
{
|
||||
Spawn("SWWMItemFog",Owner.Vec3Offset(0,0,Owner.Height/2));
|
||||
Vector3 safepos;
|
||||
double safeangle;
|
||||
if ( tostart || !lastsafevalid )
|
||||
{
|
||||
if ( deathmatch ) [safepos, safeangle] = level.PickDeathmatchStart();
|
||||
else [safepos, safeangle] = level.PickPlayerStart(Owner.PlayerNumber());
|
||||
}
|
||||
else
|
||||
{
|
||||
safepos = lastsafepos[4];
|
||||
safeangle = lastsafeangle[4];
|
||||
}
|
||||
Owner.Teleport(safepos,safeangle,TF_TELEFRAG|TF_FORCED|TF_USESPOTZ|TF_NOFOG);
|
||||
}
|
||||
override void DoEffect()
|
||||
{
|
||||
Super.DoEffect();
|
||||
if ( Amount <= 0 ) DepleteOrDestroy();
|
||||
if ( dteleport > 0 )
|
||||
{
|
||||
dteleport--;
|
||||
if ( dteleport <= 0 ) dteleport = -1;
|
||||
}
|
||||
else if ( dteleport == -1 )
|
||||
{
|
||||
dteleport = 0;
|
||||
SafeTeleport();
|
||||
}
|
||||
// check safe spot
|
||||
if ( Owner && !(Owner.CurSector.flags&Sector.SECF_ENDLEVEL) && (Owner.CurSector.DamageAmount <= 0) && (Owner.waterlevel < 2) && (Owner.GetFloorTerrain().DamageAmount <= 0) && (Owner.pos.z <= Owner.floorz) )
|
||||
{
|
||||
if ( safetic == 0 )
|
||||
{
|
||||
if ( lastsafevalid )
|
||||
{
|
||||
for ( int i=4; i>0; i-- )
|
||||
{
|
||||
lastsafepos[i] = lastsafepos[i-1];
|
||||
lastsafeangle[i] = lastsafeangle[i-1];
|
||||
}
|
||||
lastsafepos[0] = Owner.pos;
|
||||
lastsafeangle[0] = Owner.angle;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastsafevalid = true;
|
||||
for ( int i=0; i<5; i++ )
|
||||
{
|
||||
lastsafepos[i] = Owner.pos;
|
||||
lastsafeangle[i] = Owner.angle;
|
||||
}
|
||||
}
|
||||
}
|
||||
safetic = (safetic+1)%35;
|
||||
}
|
||||
else safetic = 1;
|
||||
if ( (Amount <= 0) && (dteleport == 0) ) DepleteOrDestroy();
|
||||
}
|
||||
override void AttachToOwner( Actor other )
|
||||
{
|
||||
|
|
@ -190,6 +255,7 @@ Class GhostPower : PowerInvisibility
|
|||
Powerup.Strength 100;
|
||||
Powerup.Mode "Translucent";
|
||||
Powerup.Color "F0E0FF", 0.1;
|
||||
+INVENTORY.ADDITIVETIME;
|
||||
}
|
||||
|
||||
override void InitEffect()
|
||||
|
|
@ -291,7 +357,7 @@ Class GhostArtifact : Inventory
|
|||
if ( pickup && !deathmatch ) return false;
|
||||
if ( pickup && ((Owner.player == players[consoleplayer]) || bBigPowerup) ) Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA);
|
||||
let g = GhostPower(Owner.FindInventory("GhostPower"));
|
||||
if ( g ) g.EffectTics = g.default.EffectTics;
|
||||
if ( g ) g.EffectTics += g.default.EffectTics;
|
||||
else Owner.GiveInventory("GhostPower",1);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -362,6 +428,7 @@ Class GravityPower : Powerup
|
|||
{
|
||||
Inventory.Icon "graphics/HUD/Icons/I_Gravity.png";
|
||||
Powerup.Duration -60;
|
||||
+INVENTORY.ADDITIVETIME;
|
||||
}
|
||||
|
||||
override void InitEffect()
|
||||
|
|
@ -417,7 +484,7 @@ Class GravitySuppressor : Inventory
|
|||
if ( pickup && !deathmatch ) return false;
|
||||
if ( pickup && ((Owner.player == players[consoleplayer]) || bBigPowerup) ) Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA);
|
||||
let g = GravityPower(Owner.FindInventory("GravityPower"));
|
||||
if ( g ) g.EffectTics = g.default.EffectTics;
|
||||
if ( g ) g.EffectTics += g.default.EffectTics;
|
||||
else Owner.GiveInventory("GravityPower",1);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -529,6 +596,7 @@ Class InvinciballPower : Powerup
|
|||
Powerup.Duration -30;
|
||||
Inventory.Icon "graphics/HUD/Icons/I_Invinciball.png";
|
||||
Powerup.Color "FF3000", 0.1;
|
||||
+INVENTORY.ADDITIVETIME;
|
||||
}
|
||||
|
||||
override void InitEffect()
|
||||
|
|
@ -638,7 +706,7 @@ Class FuckingInvinciball : Inventory
|
|||
let i = InvinciballPower(Owner.FindInventory("InvinciballPower"));
|
||||
if ( i )
|
||||
{
|
||||
i.EffectTics = i.default.EffectTics;
|
||||
i.EffectTics += i.default.EffectTics;
|
||||
i.lastpulse = max(i.lastpulse,gametic+35);
|
||||
SWWMHandler.DoFlash(Owner,Color(96,255,64,0),20);
|
||||
}
|
||||
|
|
@ -759,6 +827,7 @@ Class RagekitPower : Powerup
|
|||
Powerup.Duration -30;
|
||||
Inventory.Icon "graphics/HUD/Icons/I_Ragekit.png";
|
||||
Powerup.Color "FF0000", 0.2;
|
||||
+INVENTORY.ADDITIVETIME;
|
||||
}
|
||||
|
||||
override void InitEffect()
|
||||
|
|
@ -793,6 +862,8 @@ Class RagekitPower : Powerup
|
|||
if ( !(level.maptime%30) )
|
||||
{
|
||||
SWWMHandler.DoFlash(Owner,Color(16,255,0,0),5);
|
||||
if ( Owner.GiveBody(1,100) )
|
||||
SWWMScoreObj.Spawn(1,Owner.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+Owner.Height/2),Font.CR_BLUE);
|
||||
Owner.A_AlertMonsters(2000);
|
||||
if ( (Owner.player == players[consoleplayer]) && (gametic > lastrage) && (CVar.GetCVar('swwm_mutevoice',players[consoleplayer]).GetInt() < 2) )
|
||||
lastrage = SWWMHandler.AddOneliner("ragekit",2,5)+40;
|
||||
|
|
@ -845,6 +916,8 @@ Class RagekitPower : Powerup
|
|||
void DoHitFX()
|
||||
{
|
||||
if ( level.maptime <= lasteffect+5 ) return;
|
||||
if ( Owner.GiveBody(5,100) )
|
||||
SWWMScoreObj.Spawn(5,Owner.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+Owner.Height/2),Font.CR_BLUE);
|
||||
Owner.A_AlertMonsters(5000);
|
||||
SWWMHandler.DoFlash(Owner,Color(64,255,0,0),10);
|
||||
Owner.A_QuakeEx(8,8,8,Random[Rage](3,8),0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:1.);
|
||||
|
|
@ -883,11 +956,12 @@ Class Ragekit : Inventory
|
|||
{
|
||||
if ( pickup && !deathmatch ) return false;
|
||||
if ( pickup && ((Owner.player == players[consoleplayer]) || bBigPowerup) ) Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA);
|
||||
Owner.GiveBody(-100); // full base health
|
||||
if ( Owner.GiveBody(100,100) )
|
||||
SWWMScoreObj.Spawn(100,Owner.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+Owner.Height/2),Font.CR_BLUE);
|
||||
let r = RagekitPower(Owner.FindInventory("RagekitPower"));
|
||||
if ( r )
|
||||
{
|
||||
r.EffectTics = r.default.EffectTics;
|
||||
r.EffectTics += r.default.EffectTics;
|
||||
SWWMHandler.DoFlash(Owner,Color(64,255,0,0),30);
|
||||
Owner.A_QuakeEx(8,8,8,20,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:1.);
|
||||
r.lastpulse = max(r.lastpulse,gametic+35);
|
||||
|
|
@ -1267,6 +1341,8 @@ Class LampMashiro : Actor abstract
|
|||
// ⢅⢇⢘⢕⢍⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣎⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠿⠿⠛⠛⠛⠉⠁⠀⢀⢜⢕⢅⠕⣡⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠁⠀⠀⠐⡫⡠⠜⣡⣾⣿⣿⡿⠟⠫⠦⠪⠊
|
||||
// ⢕⢕⢸⣵⣷⣾⣿⣿⣿⣿⣟⢿⣿⣿⣿⣿⣿⣿⣿⣦⣤⡩⣉⣉⡩⣉⣉⠉⠉⠈⠀⠀⠀⠀⠀⠀⠀⢀⣀⡀⠀⠀⣤⢔⢗⢕⠕⣰⣿⣿⣿⣿⣿⣿⣿⣿⡿⢋⢔⢕⠕⣓⠏⣊⠰⠻⠟⠛⣉⠅⢄⠂⡪⡪⡪⠨
|
||||
//
|
||||
// ~it actually won't be her, but one can dream~
|
||||
//
|
||||
}
|
||||
|
||||
Class CompanionLamp : Actor
|
||||
|
|
@ -1695,6 +1771,7 @@ Class BarrierPower : PowerIronFeet
|
|||
Inventory.Icon "graphics/HUD/Icons/I_Barrier.png";
|
||||
Powerup.Duration -60;
|
||||
Powerup.Color "20FF00", 0.1;
|
||||
+INVENTORY.ADDITIVETIME;
|
||||
}
|
||||
|
||||
override void AbsorbDamage( int damage, Name damageType, out int newdamage )
|
||||
|
|
@ -1741,7 +1818,7 @@ Class EBarrier : Inventory
|
|||
if ( pickup && !deathmatch ) return false;
|
||||
if ( pickup && ((Owner.player == players[consoleplayer]) || bBigPowerup) ) Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA);
|
||||
let b = BarrierPower(Owner.FindInventory("BarrierPower"));
|
||||
if ( b ) b.EffectTics = b.default.EffectTics;
|
||||
if ( b ) b.EffectTics += b.default.EffectTics;
|
||||
else Owner.GiveInventory("BarrierPower",1);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -493,7 +493,7 @@ Class SaltImpact : Actor
|
|||
}
|
||||
override String GetObituary( Actor victim, Actor inflictor, Name mod, bool playerattack )
|
||||
{
|
||||
if ( args[0] == 1 ) return StringTable.Localize("$O_WALLBUSTER_BLUE");
|
||||
if ( args[0] >= 1 ) return StringTable.Localize("$O_WALLBUSTER_BLUE");
|
||||
return Super.GetObituary(victim,inflictor,mod,playerattack);
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
|
|
@ -584,7 +584,7 @@ Class SaltBeam : Actor
|
|||
|
||||
override String GetObituary( Actor victim, Actor inflictor, Name mod, bool playerattack )
|
||||
{
|
||||
if ( args[1] == 1 ) return StringTable.Localize("$O_WALLBUSTER_BLUE");
|
||||
if ( args[1] >= 1 ) return StringTable.Localize("$O_WALLBUSTER_BLUE");
|
||||
return Super.GetObituary(victim,inflictor,mod,playerattack);
|
||||
}
|
||||
void SpreadOut()
|
||||
|
|
@ -618,7 +618,7 @@ Class SaltBeam : Actor
|
|||
}
|
||||
if ( t.Results.HitType != TRACE_HitNone )
|
||||
{
|
||||
if ( args[1] ) BusterWall.Bust(t.Results,85+Accuracy*10,target,x,t.Results.HitPos.z);
|
||||
if ( (args[1] == 2) || swwm_omnibust ) BusterWall.Bust(t.Results,85+Accuracy*10,target,x,t.Results.HitPos.z);
|
||||
if ( t.Results.HitType == TRACE_HitActor )
|
||||
{
|
||||
SWWMUtility.DoKnockback(t.Results.HitActor,x,25000);
|
||||
|
|
@ -1329,7 +1329,7 @@ Class TheBall : Actor
|
|||
}
|
||||
override String GetObituary( Actor victim, Actor inflictor, Name mod, bool playerattack )
|
||||
{
|
||||
if ( special1 == 1 ) return StringTable.Localize("$O_WALLBUSTER_PURPLE");
|
||||
if ( special1 >= 1 ) return StringTable.Localize("$O_WALLBUSTER_PURPLE");
|
||||
return Super.GetObituary(victim,inflictor,mod,playerattack);
|
||||
}
|
||||
override int SpecialMissileHit( Actor victim )
|
||||
|
|
@ -1451,7 +1451,6 @@ Class TheBall : Actor
|
|||
lasthit = null;
|
||||
Vector3 HitNormal = -vel.unit();
|
||||
F3DFloor ff;
|
||||
LineTracer faketracer = new("LineTracer");
|
||||
if ( BlockingFloor )
|
||||
{
|
||||
// find closest 3d floor for its normal
|
||||
|
|
@ -1462,14 +1461,8 @@ Class TheBall : Actor
|
|||
ff = BlockingFloor.Get3DFloor(i);
|
||||
break;
|
||||
}
|
||||
if ( ff )
|
||||
{
|
||||
faketracer.Results.ffloor = ff;
|
||||
HitNormal = -ff.top.Normal;
|
||||
}
|
||||
if ( ff ) HitNormal = -ff.top.Normal;
|
||||
else HitNormal = BlockingFloor.floorplane.Normal;
|
||||
faketracer.Results.HitType = TRACE_HitFloor;
|
||||
faketracer.Results.HitSector = BlockingFloor;
|
||||
}
|
||||
else if ( BlockingCeiling )
|
||||
{
|
||||
|
|
@ -1481,14 +1474,8 @@ Class TheBall : Actor
|
|||
ff = BlockingCeiling.Get3DFloor(i);
|
||||
break;
|
||||
}
|
||||
if ( ff )
|
||||
{
|
||||
faketracer.Results.ffloor = ff;
|
||||
HitNormal = -ff.bottom.Normal;
|
||||
}
|
||||
if ( ff ) HitNormal = -ff.bottom.Normal;
|
||||
else HitNormal = BlockingCeiling.ceilingplane.Normal;
|
||||
faketracer.Results.HitType = TRACE_HitCeiling;
|
||||
faketracer.Results.HitSector = BlockingCeiling;
|
||||
}
|
||||
else if ( BlockingLine )
|
||||
{
|
||||
|
|
@ -1502,30 +1489,17 @@ Class TheBall : Actor
|
|||
if ( (!locknum || (target && target.CheckKeys(locknum,false,true))) && !SWWMUtility.IsExitLine(BlockingLine) )
|
||||
BlockingLine.RemoteActivate(target,wside,SPAC_Use,pos);
|
||||
}
|
||||
faketracer.Results.HitType = TRACE_HitWall;
|
||||
faketracer.Results.HitLine = BlockingLine;
|
||||
faketracer.Results.Side = wside;
|
||||
faketracer.Results.Tier = TIER_Middle;
|
||||
// guess the tier hit
|
||||
if ( BlockingLine.sidedef[1] )
|
||||
{
|
||||
double ceil = BlockingLine.sidedef[!wside].sector.ceilingplane.ZAtPoint(pos.xy);
|
||||
double flor = BlockingLine.sidedef[!wside].sector.floorplane.ZAtPoint(pos.xy);
|
||||
if ( pos.z >= ceil ) faketracer.Results.Tier = TIER_Upper;
|
||||
else if ( (pos.z+Height) <= flor ) faketracer.Results.Tier = TIER_Lower;
|
||||
}
|
||||
}
|
||||
else if ( BlockingMobj )
|
||||
{
|
||||
Vector3 diff = level.Vec3Diff(BlockingMobj.Vec3Offset(0,0,BlockingMobj.Height/2),pos);
|
||||
HitNormal = diff.unit();
|
||||
faketracer.Results.HitType = TRACE_HitActor;
|
||||
}
|
||||
// send the needed data for a bust
|
||||
if ( special1 == 1 )
|
||||
if ( (special1 == 2) || swwm_omnibust )
|
||||
{
|
||||
int dmg = int(oldvel.length()*4.2+heat*80);
|
||||
BusterWall.Bust(faketracer.Results,dmg,target,oldvel.unit(),pos.z+Height/2.);
|
||||
BusterWall.ProjectileBust(self,dmg,oldvel.unit());
|
||||
}
|
||||
// undo the bounce, we need to hook in our own
|
||||
vel = oldvel;
|
||||
|
|
@ -2100,6 +2074,13 @@ Class Spreadgun : SWWMWeapon
|
|||
|
||||
action void ProcessTraceHit( SpreadgunTracer t, Vector3 origin, Vector3 dir, int dmg, double mm, Class<Actor> impact = "SpreadImpact", int bc = 1, bool large = false )
|
||||
{
|
||||
if ( swwm_omnibust )
|
||||
{
|
||||
// Wall busting
|
||||
int bustdmg = dmg;
|
||||
if ( t is 'SpreadSlugTracer' ) bustdmg = int(SpreadSlugTracer(t).penetration);
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -257,7 +257,7 @@ Class BigBiospark : Actor
|
|||
if ( !t || !t.bSHOOTABLE ) continue;
|
||||
if ( SWWMUtility.SphereIntersect(t,pos,40) )
|
||||
{
|
||||
t.DamageMobj(self,target,4+special1*4,'Electric');
|
||||
t.DamageMobj(self,target,4+special1,'Electric');
|
||||
Health--;
|
||||
}
|
||||
if ( SWWMUtility.SphereIntersect(t,pos,120) )
|
||||
|
|
@ -268,7 +268,7 @@ Class BigBiospark : Actor
|
|||
if ( dist > 4. ) SWWMUtility.DoKnockback(t,-dirto,clamp(120.-dist,0.,120.)*100);
|
||||
}
|
||||
}
|
||||
Health -= 2;
|
||||
Health -= 3;
|
||||
if ( Health <= 0 ) ExplodeMissile();
|
||||
}
|
||||
|
||||
|
|
@ -276,7 +276,7 @@ Class BigBiospark : Actor
|
|||
{
|
||||
A_StopSound(CHAN_VOICE);
|
||||
A_AlertMonsters(15000);
|
||||
SWWMUtility.DoExplosion(self,450,200000,300,100);
|
||||
SWWMUtility.DoExplosion(self,250,200000,250,100);
|
||||
A_QuakeEx(9,9,9,30,0,1400,"",QF_RELATIVE|QF_SCALEDOWN,falloff:500,rollIntensity:1.5);
|
||||
A_StartSound("biospark/bighit",CHAN_ITEM,attenuation:.4);
|
||||
A_StartSound("biospark/bighit",CHAN_WEAPON,attenuation:.3);
|
||||
|
|
@ -330,7 +330,7 @@ Class BigBiospark : Actor
|
|||
if ( special1 > 40 ) return;
|
||||
double factor = (40-special1)/40.;
|
||||
double invfct = 1.-factor;
|
||||
SWWMUtility.DoExplosion(self,150*factor,0.,250*invfct);
|
||||
SWWMUtility.DoExplosion(self,80*factor,0.,250*invfct);
|
||||
SWWMUtility.DoExplosion(self,0,-8000*factor,500*invfct);
|
||||
int numpt = int(Random[ExploS](16,32)*factor);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
|
|
@ -536,7 +536,7 @@ Class BiosparkBall : Actor
|
|||
{
|
||||
A_StopSound(CHAN_VOICE);
|
||||
A_AlertMonsters(5000);
|
||||
SWWMUtility.DoExplosion(self,40,120000,150,80);
|
||||
SWWMUtility.DoExplosion(self,30,120000,150,80);
|
||||
A_QuakeEx(6,6,6,16,0,800,"",QF_RELATIVE|QF_SCALEDOWN,falloff:300,rollIntensity:.8);
|
||||
A_StartSound("biospark/hit",CHAN_ITEM,attenuation:.8);
|
||||
A_StartSound("biospark/hit",CHAN_WEAPON,attenuation:.6);
|
||||
|
|
@ -581,6 +581,7 @@ Class BiosparkBall : Actor
|
|||
s.ReactionTime += Random[Sparkster](0,10);
|
||||
}
|
||||
Spawn("BiosparkExplLight",pos);
|
||||
if ( swwm_omnibust ) BusterWall.ProjectileBust(self,30,(cos(angle)*cos(pitch),sin(angle)*cos(pitch),sin(-pitch)));
|
||||
}
|
||||
void A_SparkSubExpl()
|
||||
{
|
||||
|
|
@ -588,7 +589,7 @@ Class BiosparkBall : Actor
|
|||
if ( special1 > 30 ) return;
|
||||
double factor = (30-special1)/30.;
|
||||
double invfct = 1.-factor;
|
||||
SWWMUtility.DoExplosion(self,20*factor,0.,150*invfct);
|
||||
SWWMUtility.DoExplosion(self,10*factor,0.,150*invfct);
|
||||
SWWMUtility.DoExplosion(self,0,-5000*factor,300*invfct);
|
||||
int numpt = int(Random[ExploS](16,32)*factor);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
|
|
@ -699,7 +700,7 @@ Class BiosparkBeamImpact : Actor
|
|||
{
|
||||
Super.PostBeginPlay();
|
||||
A_AlertMonsters(2000);
|
||||
SWWMUtility.DoExplosion(self,30,120000,100,40);
|
||||
SWWMUtility.DoExplosion(self,25,120000,100,40);
|
||||
A_QuakeEx(3,3,3,12,0,800,"",QF_RELATIVE|QF_SCALEDOWN,falloff:300,rollIntensity:.4);
|
||||
A_StartSound("biospark/beamhit",CHAN_ITEM,attenuation:1.1);
|
||||
A_StartSound("biospark/beamhit",CHAN_WEAPON,attenuation:.8);
|
||||
|
|
@ -845,7 +846,7 @@ Class BiosparkComboImpactSub : Actor
|
|||
{
|
||||
Super.PostBeginPlay();
|
||||
if ( !bAMBUSH ) return;
|
||||
SWWMUtility.DoExplosion(self,100,10000,300,120);
|
||||
SWWMUtility.DoExplosion(self,30,10000,300,120);
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
|
|
@ -901,7 +902,7 @@ Class BiosparkComboImpact : Actor
|
|||
{
|
||||
Super.PostBeginPlay();
|
||||
A_AlertMonsters(6000);
|
||||
SWWMUtility.DoExplosion(self,bAMBUSH?(700+Args[0]*100):300,bAMBUSH?480000:200000,bAMBUSH?800:400,bAMBUSH?400:200);
|
||||
SWWMUtility.DoExplosion(self,bAMBUSH?(200+Args[0]*25):150,bAMBUSH?480000:200000,bAMBUSH?500:300,bAMBUSH?350:150);
|
||||
A_QuakeEx(9,9,9,25,0,2000,"",QF_RELATIVE|QF_SCALEDOWN,falloff:600,rollIntensity:1.5);
|
||||
A_StartSound("biospark/bighit",CHAN_ITEM,attenuation:.4);
|
||||
A_StartSound("biospark/bighit",CHAN_WEAPON,attenuation:.3);
|
||||
|
|
@ -969,8 +970,8 @@ Class BiosparkComboImpact : Actor
|
|||
if ( special1 > mx ) return;
|
||||
double factor = (mx-special1)/mx;
|
||||
double invfct = 1.-factor;
|
||||
SWWMUtility.DoExplosion(self,(bAMBUSH?(400+Args[0]*40):100)*factor,0.,(bAMBUSH?900.:300.)*invfct);
|
||||
SWWMUtility.DoExplosion(self,0.,-12000*factor,(bAMBUSH?1500:500)*invfct);
|
||||
SWWMUtility.DoExplosion(self,(bAMBUSH?(80+Args[0]*10):50)*factor,0.,(bAMBUSH?600.:400.)*invfct);
|
||||
SWWMUtility.DoExplosion(self,0.,-12000*factor,(bAMBUSH?800:600)*invfct);
|
||||
int numpt = int(Random[ExploS](8,16)*factor);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
|
|
@ -1023,7 +1024,7 @@ Class BiosparkComboImpact : Actor
|
|||
if ( (special2 > mx) || !(special2%2) ) return;
|
||||
int numpt = Random[Sparkster](0,mx-special2);
|
||||
double ang, pt;
|
||||
double mul = bAMBUSH?8:3;
|
||||
double mul = bAMBUSH?9:5;
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
ang = FRandom[Sparkster](0,360);
|
||||
|
|
@ -1160,6 +1161,7 @@ Class BiosparkBeam : Actor
|
|||
s.angle = atan2(normal.y,normal.x);
|
||||
s.pitch = asin(-normal.z);
|
||||
bAMBUSH = true;
|
||||
if ( swwm_omnibust ) BusterWall.Bust(t.Results,GetMissileDamage(0,0),target,t.Results.HitVector,t.Results.HitPos.z);
|
||||
return;
|
||||
}
|
||||
double closest = double.infinity;
|
||||
|
|
@ -1583,7 +1585,7 @@ Class BiosparkArc : Actor
|
|||
{
|
||||
Obituary "$O_SPARKSTER";
|
||||
RenderStyle "Add";
|
||||
DamageFunction 5;
|
||||
DamageFunction 3;
|
||||
ReactionTime 12;
|
||||
Speed 16;
|
||||
Radius .1;
|
||||
|
|
@ -1631,7 +1633,7 @@ Class BiosparkArcBig : BiosparkArc
|
|||
Default
|
||||
{
|
||||
ReactionTime 10;
|
||||
DamageFunction 100;
|
||||
DamageFunction 10;
|
||||
Speed 64;
|
||||
}
|
||||
States
|
||||
|
|
|
|||
|
|
@ -184,6 +184,7 @@ Class ExplodiumMagProj : Actor
|
|||
s.target = target;
|
||||
}
|
||||
Spawn("ExploLight2",pos);
|
||||
if ( swwm_omnibust ) BusterWall.ProjectileBust(self,20+15*special1,cvel);
|
||||
}
|
||||
States
|
||||
{
|
||||
|
|
@ -414,6 +415,7 @@ Class ExplodiumGun : SWWMWeapon
|
|||
b.angle = atan2(hitnormal.y,hitnormal.x);
|
||||
b.pitch = asin(-hitnormal.z);
|
||||
b.target = self;
|
||||
if ( swwm_omnibust ) BusterWall.BustLinetrace(d,50,self,d.HitDir,d.HitLocation.z);
|
||||
}
|
||||
for ( int i=0; i<6; i++ )
|
||||
{
|
||||
|
|
@ -523,7 +525,6 @@ Class ExplodiumGun : SWWMWeapon
|
|||
Weapon.UpSound "explodium/select";
|
||||
Weapon.SlotNumber 2;
|
||||
Weapon.SelectionOrder 1000;
|
||||
Weapon.SlotPriority 1.;
|
||||
Inventory.MaxAmount 2;
|
||||
Weapon.SisterWeapon "DualExplodiumGun";
|
||||
Stamina 8000;
|
||||
|
|
@ -805,6 +806,7 @@ Class DualExplodiumGun : SWWMWeapon
|
|||
b.angle = atan2(hitnormal.y,hitnormal.x);
|
||||
b.pitch = asin(-hitnormal.z);
|
||||
b.target = self;
|
||||
if ( swwm_omnibust ) BusterWall.BustLinetrace(d,50,self,d.HitDir,d.HitLocation.z);
|
||||
}
|
||||
for ( int i=0; i<6; i++ )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -453,8 +453,8 @@ Class CandyMagArmBig : CandyMagArm
|
|||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
reactiontime = Random[ExploS](10,16);
|
||||
vel *= FRandom[ExploS](.8,1.5);
|
||||
reactiontime = Random[ExploS](10,20);
|
||||
vel *= FRandom[ExploS](.8,2.);
|
||||
}
|
||||
States
|
||||
{
|
||||
|
|
@ -540,9 +540,9 @@ Class CandyGunProj : Actor
|
|||
pitch = asin(-cvel.z);
|
||||
bNOGRAVITY = true;
|
||||
A_SetRenderStyle(1.,STYLE_Add);
|
||||
Scale *= 6.+.2*special1;
|
||||
Scale *= 7.+.2*special1;
|
||||
A_AlertMonsters(40000);
|
||||
SWWMUtility.DoExplosion(self,4000+900*special1,80000+15000*special1,300+30*special1,200,DE_EXTRAZTHRUST);
|
||||
SWWMUtility.DoExplosion(self,5000+900*special1,80000+15000*special1,500+30*special1,300,DE_EXTRAZTHRUST);
|
||||
A_QuakeEx(9,9,9,70,0,1500+100*special1,"",QF_RELATIVE|QF_SCALEDOWN,falloff:1200,rollintensity:2.);
|
||||
A_StartSound("candygun/gunhit",CHAN_VOICE,attenuation:.24);
|
||||
A_StartSound("candygun/gunhit",CHAN_WEAPON,attenuation:.12);
|
||||
|
|
@ -575,7 +575,7 @@ Class CandyGunProj : Actor
|
|||
let s = Spawn("SWWMChip",pos);
|
||||
s.vel = pvel;
|
||||
}
|
||||
numpt = int(Random[ExploS](2,4)*(1.+.4*special1));
|
||||
numpt = int(Random[ExploS](2,6)*(1.+.4*special1));
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
let s = Spawn("CandyMagArmBig",pos);
|
||||
|
|
@ -583,6 +583,7 @@ Class CandyGunProj : Actor
|
|||
}
|
||||
Spawn("CandyLight3",pos);
|
||||
Spawn("CandyRing3",pos);
|
||||
if ( swwm_omnibust ) BusterWall.ProjectileBust(self,5000+900*special1,cvel);
|
||||
}
|
||||
States
|
||||
{
|
||||
|
|
@ -603,7 +604,7 @@ Class CandyGunProj : Actor
|
|||
{
|
||||
double ang = FRandom[ExploS](0,360);
|
||||
double pt = FRandom[ExploS](-90,90);
|
||||
let s = Spawn((frame>10)?"CandyBeam":"TinyCandyBeam",pos);
|
||||
let s = Spawn((frame<10)?"CandyBeam":"TinyCandyBeam",pos);
|
||||
s.target = target;
|
||||
s.angle = ang;
|
||||
s.pitch = pt;
|
||||
|
|
@ -698,6 +699,7 @@ Class CandyMagProj : Actor
|
|||
}
|
||||
Spawn("CandyLight2",pos);
|
||||
Spawn("CandyRing2",pos);
|
||||
if ( swwm_omnibust ) BusterWall.ProjectileBust(self,1000+900*special1,cvel);
|
||||
}
|
||||
States
|
||||
{
|
||||
|
|
@ -1024,6 +1026,7 @@ Class CandyGun : SWWMWeapon
|
|||
b.angle = atan2(hitnormal.y,hitnormal.x);
|
||||
b.pitch = asin(-hitnormal.z);
|
||||
b.target = self;
|
||||
if ( swwm_omnibust ) BusterWall.BustLinetrace(d,1700,self,d.HitDir,d.HitLocation.z);
|
||||
}
|
||||
for ( int i=0; i<6; i++ )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -161,9 +161,11 @@ Class SilverImpact : Actor
|
|||
|
||||
Class WallPenetrate
|
||||
{
|
||||
Vector3 hitpos, hitdir, hitnormal;
|
||||
Vector3 hitpos, hitdir, hitnormal, bustdir;
|
||||
int hitside, hittier, hittype, penetration;
|
||||
Line hitline;
|
||||
int hitside;
|
||||
Sector hitsector;
|
||||
F3DFloor hitffloor;
|
||||
}
|
||||
|
||||
Class AuxiliarySilverBulletTracer : LineTracer
|
||||
|
|
@ -237,25 +239,38 @@ Class SilverBulletTracer : SpreadSlugTracer
|
|||
Vector3 ofs = level.Vec3Offset(Results.HitPos,Results.HitVector*i);
|
||||
if ( level.IsPointInLevel(ofs) )
|
||||
{
|
||||
penetration = max(0,penetration-i*4);
|
||||
let wp = new("WallPenetrate");
|
||||
wp.hittype = Results.HitType;
|
||||
wp.hitline = Results.HitLine;
|
||||
wp.hitside = Results.Side;
|
||||
wp.hittier = Results.Tier;
|
||||
wp.hitsector = Results.HitSector;
|
||||
wp.hitffloor = Results.ffloor;
|
||||
wp.hitpos = Results.HitPos;
|
||||
wp.hitdir = Results.HitVector;
|
||||
wp.bustdir = Results.HitVector;
|
||||
wp.penetration = int(penetration);
|
||||
wp.hitnormal = (-Results.HitLine.delta.y,Results.HitLine.delta.x,0).unit();
|
||||
if ( !Results.Side ) wp.hitnormal *= -1;
|
||||
WallPenetrateList.Push(wp);
|
||||
penetration = max(0,penetration-i*4);
|
||||
// trace backwards to find exit surface
|
||||
let at = new("AuxiliarySilverBulletTracer");
|
||||
at.Trace(ofs,level.PointInSector(ofs.xy),-Results.HitVector,2.,TRACE_NoSky);
|
||||
if ( at.Results.HitType != TRACE_HitNone )
|
||||
{
|
||||
let wp2 = new("WallPenetrate");
|
||||
wp2.hittype = at.Results.HitType;
|
||||
wp2.hitline = at.Results.HitLine;
|
||||
wp2.hitside = at.Results.Side;
|
||||
wp2.hittier = at.Results.Tier;
|
||||
wp2.hitsector = at.Results.HitSector;
|
||||
wp2.hitffloor = at.Results.ffloor;
|
||||
wp2.hitside = at.Results.Side;
|
||||
wp2.hitpos = at.Results.HitPos;
|
||||
wp2.hitdir = at.Results.HitVector;
|
||||
wp2.bustdir = -at.Results.HitVector;
|
||||
wp2.penetration = int(penetration);
|
||||
if ( at.Results.HitType == TRACE_HitWall )
|
||||
{
|
||||
wp2.hitnormal = (-at.Results.HitLine.delta.y,at.Results.HitLine.delta.x,0).unit();
|
||||
|
|
@ -284,12 +299,17 @@ Class SilverBulletTracer : SpreadSlugTracer
|
|||
Vector3 ofs = level.Vec3Offset(Results.HitPos,Results.HitVector*i);
|
||||
if ( level.IsPointInLevel(ofs) )
|
||||
{
|
||||
penetration = max(0,penetration-i*4);
|
||||
let wp = new("WallPenetrate");
|
||||
wp.hittype = Results.HitType;
|
||||
wp.hitline = Results.HitLine;
|
||||
wp.hitside = Results.Side;
|
||||
wp.hittier = Results.Tier;
|
||||
wp.hitsector = Results.HitSector;
|
||||
wp.hitffloor = Results.ffloor;
|
||||
wp.hitpos = Results.HitPos;
|
||||
wp.hitdir = Results.HitVector;
|
||||
wp.bustdir = Results.HitVector;
|
||||
wp.penetration = int(penetration);
|
||||
if ( Results.HitType == TRACE_HitWall )
|
||||
{
|
||||
wp.hitnormal = (-Results.HitLine.delta.y,Results.HitLine.delta.x,0).unit();
|
||||
|
|
@ -301,16 +321,24 @@ Class SilverBulletTracer : SpreadSlugTracer
|
|||
else if ( Results.HitType == TRACE_HitFloor )
|
||||
wp.hitnormal = Results.HitSector.floorplane.Normal;
|
||||
WallPenetrateList.Push(wp);
|
||||
penetration = max(0,penetration-i*4);
|
||||
// trace backwards to find exit surface
|
||||
let at = new("AuxiliarySilverBulletTracer");
|
||||
at.Trace(ofs,level.PointInSector(ofs.xy),-Results.HitVector,2.,TRACE_NoSky);
|
||||
if ( at.Results.HitType != TRACE_HitNone )
|
||||
{
|
||||
let wp2 = new("WallPenetrate");
|
||||
wp2.hittype = at.Results.HitType;
|
||||
wp2.hitline = at.Results.HitLine;
|
||||
wp2.hitside = at.Results.Side;
|
||||
wp2.hittier = at.Results.Tier;
|
||||
wp2.hitsector = at.Results.HitSector;
|
||||
wp2.hitffloor = at.Results.ffloor;
|
||||
wp2.hitside = at.Results.Side;
|
||||
wp2.hitpos = at.Results.HitPos;
|
||||
wp2.hitdir = at.Results.HitVector;
|
||||
wp2.bustdir = -at.Results.HitVector;
|
||||
wp2.penetration = int(penetration);
|
||||
if ( at.Results.HitType == TRACE_HitWall )
|
||||
{
|
||||
wp2.hitnormal = (-at.Results.HitLine.delta.y,at.Results.HitLine.delta.x,0).unit();
|
||||
|
|
@ -776,6 +804,7 @@ Class SilverBullet : SWWMWeapon
|
|||
p.target = self;
|
||||
}
|
||||
}
|
||||
LineTracer faketracer = new("LineTracer");
|
||||
for ( int i=0; i<t.WallPenetrateList.Size(); i++ )
|
||||
{
|
||||
Vector3 hitpos = t.WallPenetrateList[i].hitpos;
|
||||
|
|
@ -784,8 +813,18 @@ Class SilverBullet : SWWMWeapon
|
|||
p.angle = atan2(hitnormal.y,hitnormal.x);
|
||||
p.pitch = asin(-hitnormal.z);
|
||||
p.target = self;
|
||||
if ( t.WallPenetrateList[i].hitline )
|
||||
if ( t.WallPenetrateList[i].hittype == TRACE_HitWall )
|
||||
t.WallPenetrateList[i].hitline.Activate(self,t.WallPenetrateList[i].hitside,SPAC_Impact);
|
||||
if ( swwm_omnibust )
|
||||
{
|
||||
faketracer.Results.HitType = t.WallPenetrateList[i].HitType;
|
||||
faketracer.Results.HitSector = t.WallPenetrateList[i].HitSector;
|
||||
faketracer.Results.HitLine = t.WallPenetrateList[i].HitLine;
|
||||
faketracer.Results.ffloor = t.WallPenetrateList[i].HitFFloor;
|
||||
faketracer.Results.Side = t.WallPenetrateList[i].HitSide;
|
||||
faketracer.Results.Tier = t.WallPenetrateList[i].HitTier;
|
||||
BusterWall.Bust(faketracer.Results,t.WallPenetrateList[i].penetration,self,t.WallPenetrateList[i].BustDir,t.WallPenetrateList[i].HitPos.z);
|
||||
}
|
||||
}
|
||||
if ( (t.Results.HitType != TRACE_HitNone) && (t.Results.HitType != TRACE_HasHitSky) && (t.Results.HitType != TRACE_HitActor) )
|
||||
{
|
||||
|
|
@ -810,6 +849,7 @@ Class SilverBullet : SWWMWeapon
|
|||
p.pitch = asin(-hitnormal.z);
|
||||
p.target = self;
|
||||
if ( t.Results.HitType == TRACE_HitWall ) t.Results.HitLine.RemoteActivate(self,t.Results.Side,SPAC_Impact,t.Results.HitPos);
|
||||
if ( swwm_omnibust ) BusterWall.Bust(t.Results,int(t.penetration),self,t.Results.HitVector,t.Results.HitPos.z);
|
||||
}
|
||||
for ( int i=0; i<t.Results.Distance; i+=16 )
|
||||
{
|
||||
|
|
@ -872,16 +912,14 @@ Class SilverBullet : SWWMWeapon
|
|||
}
|
||||
}
|
||||
else if ( t.Results.HitType == TRACE_HitWall )
|
||||
{
|
||||
t.Results.HitLine.RemoteActivate(self,t.Results.Side,SPAC_Impact,t.Results.HitPos);
|
||||
BusterWall.Bust(t.Results,invoker.proneme?2500:2000,self,t.Results.HitVector,t.Results.HitPos.z);
|
||||
}
|
||||
let p = Spawn("FatChodeImpact",t.Results.HitPos+hitnormal*4);
|
||||
p.angle = atan2(hitnormal.y,hitnormal.x);
|
||||
p.pitch = asin(-hitnormal.z);
|
||||
p.target = self;
|
||||
FatChodeImpact(p).realangle = atan2(t.Results.HitVector.y,t.Results.HitVector.x);
|
||||
FatChodeImpact(p).realpitch = asin(-t.Results.HitVector.z);
|
||||
BusterWall.Bust(t.Results,invoker.proneme?2500:2000,self,t.Results.HitVector,t.Results.HitPos.z);
|
||||
}
|
||||
for ( int i=0; i<t.Results.Distance; i+=16 )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ Class SWWMStats : Thinker
|
|||
lstats.Push(ls);
|
||||
}
|
||||
|
||||
void AddWeaponKill( Actor inflictor, Actor victim )
|
||||
void AddWeaponKill( Actor inflictor, Actor victim, Name damagetype )
|
||||
{
|
||||
if ( victim )
|
||||
{
|
||||
|
|
@ -132,6 +132,17 @@ Class SWWMStats : Thinker
|
|||
else if ( (inflictor is 'CandyBeam') || (inflictor is 'CandyPop') || (inflictor is 'CandyMagArm') || (inflictor is 'CandyGunProj') || (inflictor is 'CandyMagProj') || (inflictor is 'CandyBulletImpact') ) which = 'CandyGun';
|
||||
else if ( (inflictor is 'YnykronBeam') || (inflictor is 'YnykronImpact') || (inflictor is 'YnykronSingularity') || (inflictor is 'YnykronCloud') || (inflictor is 'YnykronVoidBeam') || (inflictor is 'YnykronLightningArc') || (inflictor is 'YnykronLightningImpact') ) which = 'Ynykron';
|
||||
else if ( (inflictor is 'Demolitionist') || (inflictor is 'DemolitionistShockwave') || (inflictor is 'DemolitionistRadiusShockwave') ) which = 'SWWMWeapon'; // hack to assume Demolitionist as weapon
|
||||
else if ( inflictor is 'BigPunchSplash' )
|
||||
{
|
||||
// guess from damagetype
|
||||
if ( (damagetype == 'Jump') || (damagetype == 'Dash') || (damagetype == 'Buttslam') || (damagetype == 'GroundPound') )
|
||||
which = 'SWWMWeapon';
|
||||
else if ( damagetype == 'Love' )
|
||||
which = 'SWWMGesture';
|
||||
// others are just weapon melee, so keep the readyweapon
|
||||
}
|
||||
if ( damagetype == 'Falling' )
|
||||
which = 'Weapon'; // the gross hacks continue
|
||||
if ( !which ) return;
|
||||
for ( int i=0; i<wstats.Size(); i++ )
|
||||
{
|
||||
|
|
@ -341,6 +352,15 @@ Class SWWMLoreLibrary : Thinker
|
|||
if ( ref ~== "TheOrder" ) return true;
|
||||
if ( ref ~== "TheFront" ) return true;
|
||||
}
|
||||
// restrict dlc weaponset until that's done
|
||||
if ( ref ~== "ItamexHammer" ) return true;
|
||||
if ( ref ~== "PuntzerBeta" ) return true;
|
||||
if ( ref ~== "PuntzerGamma" ) return true;
|
||||
if ( ref ~== "HeavyMahSheenGun" ) return true;
|
||||
if ( ref ~== "Quadravol" ) return true;
|
||||
if ( ref ~== "BlackfireIgniter" ) return true;
|
||||
if ( ref ~== "EMPCarbine" ) return true;
|
||||
if ( ref ~== "RayKhom" ) return true;
|
||||
// check if entry is for a collectable
|
||||
for ( int i=0; i<AllActorClasses.Size(); i++ )
|
||||
{
|
||||
|
|
@ -369,7 +389,7 @@ Class SWWMLoreLibrary : Thinker
|
|||
else if ( text ~== "SWWM_LORETXT_HELL" )
|
||||
text = "SWWM_LORETXT_HELL3"; // met father nostros during the wedding
|
||||
else if ( text ~== "SWWM_LORETXT_GHOULHUNT" )
|
||||
text = "SWWM_LORETXT_GHOULHUNT2"; // met anthon anderken during the
|
||||
text = "SWWM_LORETXT_GHOULHUNT2"; // met anthon anderken during the wedding
|
||||
else if ( text ~== "SWWM_LORETXT_RAGEKIT" )
|
||||
text = "SWWM_LORETXT_RAGEKIT2"; // kirin's reactions to demo using this item
|
||||
else if ( text ~== "SWWM_LORETXT_SANKAIDERIHA" )
|
||||
|
|
@ -382,6 +402,8 @@ Class SWWMLoreLibrary : Thinker
|
|||
text = "SWWM_LORETXT_ZANAVETH22"; // met at wedding
|
||||
else if ( text ~== "SWWM_LORETXT_YNYKRON" )
|
||||
text = "SWWM_LORETXT_YNYKRON2"; // confirmed to harm (but not kill) gods
|
||||
else if ( text ~== "SWWM_LORETXT_AKARIPROJECT" )
|
||||
text = "SWWM_LORETXT_AKARIPROJECT3"; // mentions kirin
|
||||
}
|
||||
if ( gameinfo.gametype&(GAME_Raven|GAME_Strife) )
|
||||
{
|
||||
|
|
@ -403,6 +425,8 @@ Class SWWMLoreLibrary : Thinker
|
|||
text = "SWWM_LORETXT_ZANAVETH32"; // iagb happened
|
||||
else if ( text ~== "SWWM_LORETXT_BIGSHOT" )
|
||||
text = "SWWM_LORETXT_BIGSHOT2"; // predictions about crimes_m
|
||||
else if ( text ~== "SWWM_LORETXT_AKARIPROJECT" )
|
||||
text = "SWWM_LORETXT_AKARIPROJECT2"; // fiction becomes reality
|
||||
}
|
||||
// check that it's valid
|
||||
if ( StringTable.Localize(tag,false) == tag ) return false;
|
||||
|
|
@ -755,12 +779,12 @@ Class SWWMCombatTracker : Thinker
|
|||
bool legged;
|
||||
int tcnt;
|
||||
double height;
|
||||
transient CVar funtags;
|
||||
transient CVar funtags, maxdist;
|
||||
|
||||
void UpdateTag()
|
||||
{
|
||||
if ( !funtags ) funtags = CVar.GetCVar('swwm_funtags',players[consoleplayer]);
|
||||
if ( mytarget && (mytarget.player || mytarget.bISMONSTER || (mytarget is 'BossBrain')) )
|
||||
if ( mytarget && (mytarget.player || mytarget.bISMONSTER || (mytarget is 'BossBrain') || (mytarget is 'SWWMHangingKeen')) )
|
||||
{
|
||||
String realtag = funtags.GetBool()?SWWMUtility.GetFunTag(mytarget,FallbackTag):mytarget.GetTag(FallbackTag);
|
||||
if ( realtag == FallbackTag )
|
||||
|
|
@ -879,22 +903,25 @@ Class SWWMCombatTracker : Thinker
|
|||
}
|
||||
lasthealth = mytarget.Health;
|
||||
intp.Update(lasthealth);
|
||||
if ( (mytarget.bISMONSTER || mytarget.player) && !mytarget.bINVISIBLE )
|
||||
if ( !maxdist ) maxdist = CVar.GetCVar('swwm_maxtargetdist',players[consoleplayer]);
|
||||
if ( (mytarget.bISMONSTER || mytarget.player) && !mytarget.bINVISIBLE && !mytarget.bCORPSE )
|
||||
{
|
||||
bool straifu = false;
|
||||
if ( (gameinfo.gametype&GAME_Strife) && (!mytarget.bINCOMBAT && !mytarget.bJUSTATTACKED) || (mytarget is 'Beggar') || (mytarget is 'Peasant') )
|
||||
straifu = true;
|
||||
// enemies within 2000mu that have us as target
|
||||
if ( !straifu && mytarget.target && (mytarget.target.Health > 0) && (mytarget.target.player == players[consoleplayer]) && (mytarget.Vec3To(mytarget.target).length() < 2000) && mytarget.CheckSight(mytarget.target,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) updated = level.maptime+70;
|
||||
int mxdist = maxdist.GetInt();
|
||||
// enemies within a set distance that have us as target
|
||||
if ( !straifu && mytarget.target && (mytarget.target.Health > 0) && (mytarget.target.player == players[consoleplayer]) && ((mxdist <= 0) || (mytarget.Vec3To(mytarget.target).length() < mxdist)) && mytarget.CheckSight(mytarget.target,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) updated = level.maptime+70;
|
||||
// players (but not voodoo dolls), always visible in sp/coop
|
||||
if ( !deathmatch && mytarget.player && (mytarget.player.mo == mytarget) ) updated = level.maptime+35;
|
||||
// any visible enemies within 600mu
|
||||
if ( (mytarget.Vec3To(players[consoleplayer].mo).length() < 600) && players[consoleplayer].mo.CheckSight(mytarget,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) updated = level.maptime;
|
||||
// any visible enemies within one quarter of the set distance
|
||||
if ( ((mxdist <= 0) || (mytarget.Vec3To(players[consoleplayer].mo).length() < (mxdist/4))) && players[consoleplayer].mo.CheckSight(mytarget,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) updated = level.maptime;
|
||||
}
|
||||
else if ( mytarget is 'BossBrain' )
|
||||
else if ( (mytarget is 'BossBrain') || (mytarget is 'SWWMHangingKeen') )
|
||||
{
|
||||
// teh romero, only if visible
|
||||
if ( (mytarget.Vec3To(players[consoleplayer].mo).length() < 600) && players[consoleplayer].mo.CheckSight(mytarget,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) updated = level.maptime;
|
||||
int mxdist = maxdist.GetInt();
|
||||
// special stuff, only if visible
|
||||
if ( ((mxdist <= 0) || (mytarget.Vec3To(players[consoleplayer].mo).length() < (mxdist/4))) && players[consoleplayer].mo.CheckSight(mytarget,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) updated = level.maptime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -474,6 +474,7 @@ Class SWWMUtility
|
|||
basetag = "WOLFSS";
|
||||
break;
|
||||
case 'CommanderKeen':
|
||||
case 'SWWMHangingKeen':
|
||||
basetag = "KEEN";
|
||||
break;
|
||||
case 'MBFHelperDog':
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue