Big changes (still no Ynykron altfire, sorry):
- Split off big code files for easier navigation. - Moved DoExplosion and DoKnockback to the SWWMUtility class. - Removed DoBlast as it is no longer used, having been replaced entirely. - Finalized Mag Manager: * Implemented partial mag loading for Silver Bullet and Candygun. * Show spare bullets on ammo displays of Silver Bullet and Candygun. - Rebalanced Eviscerator and Hellblazer damages. - Adjusted Dragon's Breath damage and effects. - Adjusted ammo spawns again. * Reduced shell spawns, as they seemed to max out too quickly. * Added "intermediate" bundle spawns for Eviscerator shells, Hellblazer missiles and Silver Bullet / Candygun rounds. - Doubled max ammo of Biospark Carbine. - Biospark beams no longer spawn arcs near their start point. This should reduce the likelihood of self-damage.
This commit is contained in:
parent
383e170ae0
commit
f28e7e01fb
25 changed files with 4723 additions and 4545 deletions
3
TODO.md
3
TODO.md
|
|
@ -5,7 +5,6 @@ Not so fundamental things during first beta:
|
|||
- Extra Demolitionist animations (swimming, additional gestures)
|
||||
- Dual wielding Explodium Gun
|
||||
- Quick grenade function (Explodium Mag)
|
||||
- Allow loading partial mags from spare bullets
|
||||
- Parrying for hitscan weapons (currently parrying only handles vanilla LineAttack)
|
||||
- Fun options
|
||||
- Omnibusting (all weapons can bust walls)
|
||||
|
|
@ -13,7 +12,7 @@ Not so fundamental things during first beta:
|
|||
- Confetti gibs
|
||||
- Keen replacement (need ideas)
|
||||
- Achievements
|
||||
- Extra Demolitionist Menu tabs (radio, pong minigame)
|
||||
- Extra Demolitionist Menu tabs (radio, minigames)
|
||||
- Collectables
|
||||
|
||||
Extra things for later:
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ SWWM_ZOOMFIRE = "Tertiary Fire / Zoom";
|
|||
SWWM_MELEE = "Melee Attack";
|
||||
SWWM_DASH = "Dash";
|
||||
SWWM_ITEMSENSE = "Item Sense";
|
||||
SWWM_EXTRAFIRE = "Quaternary Fire";
|
||||
SWWM_EXTRAFIRE = "Quick Grenade";
|
||||
SWWM_GESTURE1 = "Wave";
|
||||
SWWM_GESTURE2 = "Thumbs Up";
|
||||
SWWM_GESTURE3 = "Victory";
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ SWWM_ZOOMFIRE = "Fuego Terciario / Zoom";
|
|||
SWWM_MELEE = "Ataque a Melé";
|
||||
SWWM_DASH = "Esprintar";
|
||||
SWWM_ITEMSENSE = "Sensor de Items";
|
||||
SWWM_EXTRAFIRE = "Fuego Cuaternario";
|
||||
SWWM_EXTRAFIRE = "Granada Rápida";
|
||||
SWWM_GESTURE1 = "Saludar";
|
||||
SWWM_GESTURE2 = "Pulgar Arriba";
|
||||
SWWM_GESTURE3 = "Victoria";
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
[default]
|
||||
SWWM_MODVER="\chSWWM \cwGZ\c- r503 (Sat 22 Aug 15:18:03 CEST 2020)";
|
||||
SWWM_MODVER="\chSWWM \cwGZ\c- r505 (Sun 23 Aug 16:32:44 CEST 2020)";
|
||||
|
|
|
|||
|
|
@ -14,13 +14,18 @@ version "4.4"
|
|||
#include "zscript/swwm_libeye/viewport.txt"
|
||||
#include "zscript/swwm_coordutil.zsc"
|
||||
#include "zscript/swwm_quaternion.zsc"
|
||||
#include "zscript/swwm_crimesdlg.zsc"
|
||||
// base code
|
||||
#include "zscript/swwm_common.zsc"
|
||||
#include "zscript/swwm_utility.zsc"
|
||||
#include "zscript/swwm_handler.zsc"
|
||||
#include "zscript/swwm_shame.zsc"
|
||||
#include "zscript/swwm_thinkers.zsc"
|
||||
#include "zscript/swwm_player.zsc"
|
||||
#include "zscript/swwm_inventory.zsc"
|
||||
#include "zscript/swwm_hud.zsc"
|
||||
#include "zscript/swwm_hudextra.zsc"
|
||||
#include "zscript/swwm_menu.zsc"
|
||||
#include "zscript/swwm_crimesdlg.zsc"
|
||||
#include "zscript/swwm_options.zsc"
|
||||
#include "zscript/swwm_title.zsc"
|
||||
#include "zscript/swwm_inter.zsc"
|
||||
|
|
|
|||
|
|
@ -230,6 +230,11 @@ Class MagAmmo : Inventory abstract
|
|||
return;
|
||||
}
|
||||
if ( countdown-- > 0 ) return;
|
||||
MagFill();
|
||||
}
|
||||
|
||||
bool MagFill()
|
||||
{
|
||||
bool given = false;
|
||||
while ( (pamo.Amount < pamo.MaxAmount) && (Amount >= ClipSize) )
|
||||
{
|
||||
|
|
@ -240,6 +245,7 @@ Class MagAmmo : Inventory abstract
|
|||
pamo.PrintPickupMessage(true,pamo.PickupMessage());
|
||||
}
|
||||
if ( given ) pamo.PlayPickupSound(Owner);
|
||||
return given;
|
||||
}
|
||||
|
||||
override inventory CreateTossable( int amt )
|
||||
|
|
@ -701,6 +707,28 @@ Class EvisceratorSixPack : EvisceratorShell
|
|||
}
|
||||
}
|
||||
|
||||
Class EvisceratorTrioSpawn : Actor
|
||||
{
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
if ( bCOUNTSECRET ) level.total_secrets--;
|
||||
for ( int i=0; i<3; i++ )
|
||||
{
|
||||
let a = Spawn("EvisceratorShell",Vec3Angle(12,i*120));
|
||||
a.special = special;
|
||||
a.angle = i*120;
|
||||
a.FloatBobPhase = FloatBobPhase;
|
||||
for ( int j=0; j<5; j++ ) a.args[j] = args[j];
|
||||
if ( bCOUNTSECRET )
|
||||
{
|
||||
a.bCOUNTSECRET = true;
|
||||
level.total_secrets++;
|
||||
}
|
||||
}
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Hellblazer ammo
|
||||
// ============================================================================
|
||||
|
|
@ -743,6 +771,27 @@ Class HellblazerMissileMag : HellblazerMissiles
|
|||
Inventory.Amount 6;
|
||||
}
|
||||
}
|
||||
Class HellblazerMissileTrioSpawn : Actor
|
||||
{
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
if ( bCOUNTSECRET ) level.total_secrets--;
|
||||
for ( int i=0; i<3; i++ )
|
||||
{
|
||||
let a = Spawn("HellblazerMissiles",Vec3Angle(8,i*120));
|
||||
a.special = special;
|
||||
a.angle = i*120;
|
||||
a.FloatBobPhase = FloatBobPhase;
|
||||
for ( int j=0; j<5; j++ ) a.args[j] = args[j];
|
||||
if ( bCOUNTSECRET )
|
||||
{
|
||||
a.bCOUNTSECRET = true;
|
||||
level.total_secrets++;
|
||||
}
|
||||
}
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
Class HellblazerCrackshots : Ammo
|
||||
{
|
||||
|
|
@ -876,7 +925,7 @@ Class SparkUnit : Ammo
|
|||
Stamina 50000;
|
||||
Inventory.Icon "graphics/HUD/Icons/A_Sparkster.png";
|
||||
Inventory.Amount 1;
|
||||
Inventory.MaxAmount 4;
|
||||
Inventory.MaxAmount 8;
|
||||
Ammo.BackpackAmount 1;
|
||||
Ammo.DropAmount 1;
|
||||
+FLOATBOB;
|
||||
|
|
@ -991,6 +1040,51 @@ Class SilverBullets2 : MagAmmo
|
|||
}
|
||||
}
|
||||
|
||||
Class SilverBulletsBundleSpawn : Actor
|
||||
{
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
if ( bCOUNTSECRET ) level.total_secrets--;
|
||||
int bnd = Random[Bundle](2,3);
|
||||
for ( int i=0; i<3; i++ )
|
||||
{
|
||||
let a = Spawn("SilverBullets",Vec3Angle(6,i*(360/bnd)));
|
||||
a.special = special;
|
||||
a.angle = i*(360/bnd);
|
||||
a.FloatBobPhase = FloatBobPhase;
|
||||
for ( int j=0; j<5; j++ ) a.args[j] = args[j];
|
||||
if ( bCOUNTSECRET )
|
||||
{
|
||||
a.bCOUNTSECRET = true;
|
||||
level.total_secrets++;
|
||||
}
|
||||
}
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
Class SilverBullets2BundleSpawn : Actor
|
||||
{
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
if ( bCOUNTSECRET ) level.total_secrets--;
|
||||
int bnd = Random[Bundle](2,3);
|
||||
for ( int i=0; i<bnd; i++ )
|
||||
{
|
||||
let a = Spawn("SilverBullets2",Vec3Angle(6,i*(360/bnd)));
|
||||
a.special = special;
|
||||
a.angle = i*(360/bnd);
|
||||
a.FloatBobPhase = FloatBobPhase;
|
||||
for ( int j=0; j<5; j++ ) a.args[j] = args[j];
|
||||
if ( bCOUNTSECRET )
|
||||
{
|
||||
a.bCOUNTSECRET = true;
|
||||
level.total_secrets++;
|
||||
}
|
||||
}
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Candygun ammo
|
||||
// ============================================================================
|
||||
|
|
@ -1044,6 +1138,28 @@ Class CandyGunBullets : MagAmmo
|
|||
}
|
||||
}
|
||||
|
||||
Class CandyGunBulletsBundleSpawn : Actor
|
||||
{
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
if ( bCOUNTSECRET ) level.total_secrets--;
|
||||
int bnd = Random[Bundle](2,3);
|
||||
for ( int i=0; i<bnd; i++ )
|
||||
{
|
||||
let a = Spawn("CandyGunBullets",Vec3Angle(4,i*(360/bnd)));
|
||||
a.special = special;
|
||||
a.angle = i*(360/bnd);
|
||||
for ( int j=0; j<5; j++ ) a.args[j] = args[j];
|
||||
if ( bCOUNTSECRET )
|
||||
{
|
||||
a.bCOUNTSECRET = true;
|
||||
level.total_secrets++;
|
||||
}
|
||||
}
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
Class CandyGunSpares : Ammo
|
||||
{
|
||||
Default
|
||||
|
|
|
|||
|
|
@ -251,7 +251,7 @@ Class HellblazerMissile : Actor
|
|||
A_SetRenderStyle(1.0,STYLE_Add);
|
||||
A_SprayDecal("BigScorch",50);
|
||||
A_SetScale(4.5);
|
||||
SWWMHandler.DoExplosion(self,250,320000,200,90);
|
||||
SWWMUtility.DoExplosion(self,350,320000,200,90);
|
||||
A_NoGravity();
|
||||
A_QuakeEx(5,5,5,15,0,1500,"",QF_RELATIVE|QF_SCALEDOWN,falloff:500,rollIntensity:.8);
|
||||
A_StopSound(CHAN_BODY);
|
||||
|
|
@ -347,7 +347,7 @@ Class HellblazerCrackshot : HellblazerMissile
|
|||
A_SetRenderStyle(1.0,STYLE_Add);
|
||||
A_SprayDecal("BigScorch",50);
|
||||
A_SetScale(6.);
|
||||
SWWMHandler.DoExplosion(self,300,320000,250,100);
|
||||
SWWMUtility.DoExplosion(self,300,320000,250,100);
|
||||
A_NoGravity();
|
||||
A_QuakeEx(6,6,6,20,0,2000,"",QF_RELATIVE|QF_SCALEDOWN,falloff:800,rollIntensity:1.);
|
||||
A_StopSound(CHAN_BODY);
|
||||
|
|
@ -416,7 +416,7 @@ Class HellblazerRavager : HellblazerMissile
|
|||
A_SetRenderStyle(1.0,STYLE_Add);
|
||||
A_SprayDecal("HugeScorch",50);
|
||||
A_SetScale(8.);
|
||||
SWWMHandler.DoExplosion(self,500,320000,300,120);
|
||||
SWWMUtility.DoExplosion(self,400,320000,300,120);
|
||||
A_NoGravity();
|
||||
A_QuakeEx(6,6,6,30,0,2000,"",QF_RELATIVE|QF_SCALEDOWN,falloff:800,rollIntensity:1.);
|
||||
A_StopSound(CHAN_BODY);
|
||||
|
|
@ -494,7 +494,7 @@ Class HellblazerWarhead : HellblazerMissile
|
|||
A_SetRenderStyle(1.0,STYLE_Add);
|
||||
A_SprayDecal("WumboScorch",150);
|
||||
A_SetScale(7.);
|
||||
SWWMHandler.DoExplosion(self,2000,600000,400,200);
|
||||
SWWMUtility.DoExplosion(self,2000,600000,400,200);
|
||||
A_NoGravity();
|
||||
A_QuakeEx(9,9,9,150,0,12000,"",QF_RELATIVE|QF_SCALEDOWN,falloff:4000,rollIntensity:2.);
|
||||
A_StopSound(CHAN_BODY);
|
||||
|
|
@ -534,7 +534,7 @@ Class HellblazerWarhead : HellblazerMissile
|
|||
void A_WarheadSub()
|
||||
{
|
||||
if ( special1 < 40 )
|
||||
SWWMHandler.DoExplosion(self,320-special1*8,600000-special1*12000,200+special1*30);
|
||||
SWWMUtility.DoExplosion(self,320-special1*8,600000-special1*12000,200+special1*30);
|
||||
special1++;
|
||||
if ( (special1 <= 30) && !(special1%2) )
|
||||
{
|
||||
|
|
@ -782,7 +782,7 @@ Class HellblazerClusterMini : HellblazerMissile2
|
|||
A_SetRenderStyle(1.0,STYLE_Add);
|
||||
A_SprayDecal("BigScorch",50);
|
||||
A_SetScale(2.5);
|
||||
SWWMHandler.DoExplosion(self,80,200000,150,60);
|
||||
SWWMUtility.DoExplosion(self,80,200000,150,60);
|
||||
A_NoGravity();
|
||||
A_QuakeEx(4,4,4,12,0,1000,"",QF_RELATIVE|QF_SCALEDOWN,falloff:400,rollIntensity:.6);
|
||||
A_StopSound(CHAN_BODY);
|
||||
|
|
@ -1052,7 +1052,7 @@ Class HellblazerRavagerArm : Actor
|
|||
l.target = p;
|
||||
}
|
||||
if ( !(ReactionTime%1) )
|
||||
SWWMHandler.DoExplosion(self,4+reactiontime*2,1000+200*reactiontime,250-6*reactiontime);
|
||||
SWWMUtility.DoExplosion(self,4+reactiontime*2,1000+200*reactiontime,250-6*reactiontime);
|
||||
double spd = vel.length();
|
||||
vel = (vel*.4+(FRandom[ExploS](-.2,.2),FRandom[ExploS](-.2,.2),FRandom[ExploS](-.2,.2))).unit()*spd;
|
||||
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](1,5);
|
||||
|
|
@ -1134,7 +1134,7 @@ Class HellblazerWarheadArm : Actor
|
|||
{
|
||||
A_CountDown();
|
||||
Spawn("HellblazerWarheadTrail",pos);
|
||||
SWWMHandler.DoExplosion(self,30+reactiontime*5,3000+500*reactiontime,120+3*reactiontime);
|
||||
SWWMUtility.DoExplosion(self,30+reactiontime*5,3000+500*reactiontime,120+3*reactiontime);
|
||||
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](1,5);
|
||||
let s = Spawn("SWWMHalfSmoke",pos);
|
||||
s.vel = pvel+vel*.2;
|
||||
|
|
@ -1257,7 +1257,7 @@ Class Hellblazer : SWWMWeapon
|
|||
Vector3 x, y, z, x2, y2, z2, dir, origin;
|
||||
double a, s;
|
||||
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
|
||||
SWWMHandler.DoKnockback(self,-x,bAlt?22000.:32000.);
|
||||
SWWMUtility.DoKnockback(self,-x,bAlt?22000.:32000.);
|
||||
[x2, y2, z2] = swwm_CoordUtil.GetAxes(BulletSlope(),angle,roll);
|
||||
origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+3*y-5*z);
|
||||
a = FRandom[Hellblazer](0,360);
|
||||
|
|
|
|||
|
|
@ -975,7 +975,7 @@ Class Wallbuster : SWWMWeapon
|
|||
{
|
||||
int realdmg = dmg?dmg:t.HitList[i].HitDamage;
|
||||
SWWMDamageAccumulator.Accumulate(t.HitList[i].HitActor,realdmg,invoker,self,'shot',!large);
|
||||
SWWMHandler.DoKnockback(t.HitList[i].HitActor,t.HitList[i].x+(0,0,0.025),mm*FRandom[Wallbuster](0.4,1.2));
|
||||
SWWMUtility.DoKnockback(t.HitList[i].HitActor,t.HitList[i].x+(0,0,0.025),mm*FRandom[Wallbuster](0.4,1.2));
|
||||
if ( t.HitList[i].HitActor.bNOBLOOD || t.HitList[i].HitActor.bINVULNERABLE )
|
||||
{
|
||||
let p = Spawn(impact,t.HitList[i].HitLocation);
|
||||
|
|
@ -1187,7 +1187,7 @@ Class Wallbuster : SWWMWeapon
|
|||
s.alpha *= .4;
|
||||
s.vel += vel*.5+x*FRandom[Wallbuster](4.,8.)+y*FRandom[Wallbuster](-1,1)+z*FRandom[Wallbuster](-1,1);
|
||||
}
|
||||
SWWMHandler.DoKnockback(self,-x,18000.);
|
||||
SWWMUtility.DoKnockback(self,-x,18000.);
|
||||
break;
|
||||
case 2:
|
||||
// saltshot
|
||||
|
|
@ -1227,7 +1227,7 @@ Class Wallbuster : SWWMWeapon
|
|||
s.alpha *= .4;
|
||||
s.vel += vel*.5+x*FRandom[Wallbuster](4.,8.)+y*FRandom[Wallbuster](-2,2)+z*FRandom[Wallbuster](-2,2);
|
||||
}
|
||||
SWWMHandler.DoKnockback(self,-x,17000.);
|
||||
SWWMUtility.DoKnockback(self,-x,17000.);
|
||||
break;
|
||||
case 3:
|
||||
// lead ball
|
||||
|
|
@ -1263,7 +1263,7 @@ Class Wallbuster : SWWMWeapon
|
|||
s.alpha *= .4;
|
||||
s.vel += vel*.5+x*FRandom[Wallbuster](4.,8.)+y*FRandom[Wallbuster](-1,1)+z*FRandom[Wallbuster](-1,1);
|
||||
}
|
||||
SWWMHandler.DoKnockback(self,-x,7200.);
|
||||
SWWMUtility.DoKnockback(self,-x,7200.);
|
||||
break;
|
||||
default:
|
||||
// buckshot
|
||||
|
|
@ -1308,7 +1308,7 @@ Class Wallbuster : SWWMWeapon
|
|||
s.alpha *= .4;
|
||||
s.vel += vel*.5+x*FRandom[Wallbuster](4.,8.)+y*FRandom[Wallbuster](-2,2)+z*FRandom[Wallbuster](-2,2);
|
||||
}
|
||||
SWWMHandler.DoKnockback(self,-x,12000.);
|
||||
SWWMUtility.DoKnockback(self,-x,12000.);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -84,7 +84,7 @@ Class EvisceratorChunk : Actor
|
|||
Radius 2;
|
||||
Height 2;
|
||||
Speed 50;
|
||||
DamageFunction int(clamp((vel.length()-6)*.2+max(0,1.-lifetime)*5.,0,12));
|
||||
DamageFunction int(clamp((vel.length()-6)*.15+max(0,1.-lifetime)*3.,0,10));
|
||||
DamageType 'shot';
|
||||
BounceFactor 1.0;
|
||||
WallBounceFactor 1.0;
|
||||
|
|
@ -237,7 +237,7 @@ Class EvisceratorChunk : Actor
|
|||
lasthit = victim;
|
||||
// don't knock back if already dead
|
||||
int oldamt = SWWMDamageAccumulator.GetAmount(victim);
|
||||
if ( victim.health-oldamt > 0 ) SWWMHandler.DoKnockback(victim,vel.unit(),12000);
|
||||
if ( victim.health-oldamt > 0 ) SWWMUtility.DoKnockback(victim,vel.unit(),12000);
|
||||
// gather damage
|
||||
SWWMDamageAccumulator.Accumulate(victim,GetMissileDamage(0,0),self,target,damagetype);
|
||||
int amt = SWWMDamageAccumulator.GetAmount(victim);
|
||||
|
|
@ -359,7 +359,7 @@ Class EvisceratorProj : Actor
|
|||
A_SprayDecal("BigScorch",50);
|
||||
A_NoGravity();
|
||||
A_SetScale(3.5);
|
||||
SWWMHandler.DoExplosion(self,150,120000,200,80);
|
||||
SWWMUtility.DoExplosion(self,150,120000,200,80);
|
||||
A_QuakeEx(6,6,6,20,0,1200,"",QF_RELATIVE|QF_SCALEDOWN,falloff:300,rollIntensity:.7);
|
||||
A_StartSound("eviscerator/shell",CHAN_WEAPON,attenuation:.5);
|
||||
A_StartSound("eviscerator/shell",CHAN_VOICE,attenuation:.3);
|
||||
|
|
@ -612,7 +612,7 @@ Class Eviscerator : SWWMWeapon
|
|||
Vector3 x, y, z, x2, y2, z2, dir, origin;
|
||||
double a, s;
|
||||
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
|
||||
SWWMHandler.DoKnockback(self,-x,25000.);
|
||||
SWWMUtility.DoKnockback(self,-x,25000.);
|
||||
[x2, y2, z2] = swwm_CoordUtil.GetAxes(BulletSlope(),angle,roll);
|
||||
origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+3*y-5*z);
|
||||
for ( int i=0; i<40; i++ )
|
||||
|
|
@ -669,7 +669,7 @@ Class Eviscerator : SWWMWeapon
|
|||
Vector3 x, y, z, x2, y2, z2, dir, origin;
|
||||
double a, s;
|
||||
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
|
||||
SWWMHandler.DoKnockback(self,-x,32000.);
|
||||
SWWMUtility.DoKnockback(self,-x,32000.);
|
||||
[x2, y2, z2] = swwm_CoordUtil.GetAxes(BulletSlope(),angle,roll);
|
||||
origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+3*y-5*z);
|
||||
a = FRandom[Eviscerator](0,360);
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ Class AirBullet : FastProjectile
|
|||
if ( target == lasthit ) return 0;
|
||||
lasthit = target;
|
||||
}
|
||||
SWWMHandler.DoKnockback(target,vel.unit(),10000);
|
||||
SWWMUtility.DoKnockback(target,vel.unit(),10000);
|
||||
return damage;
|
||||
}
|
||||
override void Effect()
|
||||
|
|
@ -54,7 +54,7 @@ Class AirBullet : FastProjectile
|
|||
s.alpha *= .2;
|
||||
}
|
||||
bAMBUSH = true;
|
||||
SWWMHandler.DoExplosion(self,GetMissileDamage(0,0),0,50,ignoreme:target);
|
||||
SWWMUtility.DoExplosion(self,GetMissileDamage(0,0),0,50,ignoreme:target);
|
||||
bAMBUSH = false;
|
||||
tcnt++;
|
||||
if ( tcnt < 2 ) return;
|
||||
|
|
@ -72,9 +72,9 @@ Class AirBullet : FastProjectile
|
|||
dir /= dist;
|
||||
double mm = 8000000./max(20.,dist);
|
||||
if ( (target.pos.z > target.floorz) && target.TestMobjZ() ) mm *= 1.6;
|
||||
SWWMHandler.DoKnockback(target,dir,mm);
|
||||
SWWMUtility.DoKnockback(target,dir,mm);
|
||||
}
|
||||
SWWMHandler.DoExplosion(self,0,100000,150,ignoreme:target);
|
||||
SWWMUtility.DoExplosion(self,0,100000,150,ignoreme:target);
|
||||
A_QuakeEx(6,6,6,20,0,250,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:1.);
|
||||
A_StartSound("deepimpact/bullethit",CHAN_VOICE,CHANF_DEFAULT,1.,.3);
|
||||
A_SprayDecal("ImpactMark");
|
||||
|
|
@ -282,7 +282,7 @@ Class DeepImpact : SWWMWeapon
|
|||
invoker.clipcount = max(0,invoker.clipcount-3);
|
||||
Vector3 x, y, z, dir;
|
||||
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
|
||||
SWWMHandler.DoKnockback(self,-x,2000.);
|
||||
SWWMUtility.DoKnockback(self,-x,2000.);
|
||||
Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+2*y-3*z);
|
||||
DeepTracer t = new("DeepTracer");
|
||||
t.ignoreme = self;
|
||||
|
|
@ -348,7 +348,7 @@ Class DeepImpact : SWWMWeapon
|
|||
{
|
||||
wnorm /= wallhits;
|
||||
if ( (pos.z > floorz) && TestMobjZ() ) wnorm *= 2.4;
|
||||
SWWMHandler.DoKnockback(self,wnorm.unit(),wnorm.length()*5000000.);
|
||||
SWWMUtility.DoKnockback(self,wnorm.unit(),wnorm.length()*5000000.);
|
||||
}
|
||||
for ( int i=0; i<list.Size(); i++ )
|
||||
{
|
||||
|
|
@ -401,7 +401,7 @@ Class DeepImpact : SWWMWeapon
|
|||
invoker.clipcount = 0;
|
||||
Vector3 x, y, z, x2, y2, z2;
|
||||
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
|
||||
SWWMHandler.DoKnockback(self,-x,42000.);
|
||||
SWWMUtility.DoKnockback(self,-x,42000.);
|
||||
Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+2*y-3*z);
|
||||
double a = FRandom[Spread](0,360), s = FRandom[Spread](0,.002);
|
||||
[x2, y2, z2] = swwm_CoordUtil.GetAxes(BulletSlope(),angle,roll);
|
||||
|
|
|
|||
|
|
@ -330,6 +330,76 @@ Class KirinManga : SWWMCollectable
|
|||
}
|
||||
*/
|
||||
|
||||
// yay!
|
||||
Class FancyConfetti : Actor
|
||||
{
|
||||
int deadtimer;
|
||||
double anglevel, pitchvel, rollvel;
|
||||
|
||||
Default
|
||||
{
|
||||
Radius 2;
|
||||
Height 2;
|
||||
+NOBLOCKMAP;
|
||||
+DROPOFF;
|
||||
+MOVEWITHSECTOR;
|
||||
+THRUACTORS;
|
||||
+NOTELEPORT;
|
||||
+DONTSPLASH;
|
||||
+INTERPOLATEANGLES;
|
||||
+ROLLSPRITE;
|
||||
+ROLLCENTER;
|
||||
+SLIDESONWALLS;
|
||||
Gravity 0.05;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
deadtimer = Random[Junk](-30,30);
|
||||
anglevel = FRandom[Junk](3,12)*RandomPick[Junk](-1,1);
|
||||
pitchvel = FRandom[Junk](3,12)*RandomPick[Junk](-1,1);
|
||||
rollvel = FRandom[Junk](3,12)*RandomPick[Junk](-1,1);
|
||||
if ( bAMBUSH ) frame = 0;
|
||||
else frame = Random[Junk](0,9);
|
||||
scale *= Frandom[Junk](0.8,1.2);
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
if ( isFrozen() ) return;
|
||||
vel.xy *= 0.98;
|
||||
if ( vel.z > 0 ) vel.z *= 0.98;
|
||||
if ( CurState == ResolveState("Death") )
|
||||
{
|
||||
deadtimer++;
|
||||
if ( deadtimer > 300 ) A_FadeOut(0.05);
|
||||
return;
|
||||
}
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
XZW1 # 1
|
||||
{
|
||||
angle += anglevel;
|
||||
pitch += pitchvel;
|
||||
roll += rollvel;
|
||||
return A_JumpIf(pos.z<=floorz,"Death");
|
||||
}
|
||||
Loop;
|
||||
Death:
|
||||
XZW1 # -1
|
||||
{
|
||||
A_Stop();
|
||||
pitch = roll = 0;
|
||||
}
|
||||
Stop;
|
||||
Dummy:
|
||||
XZW1 ABCDEFGHIJ -1;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
// Collectable box (recycling of discarded "chance box" item)
|
||||
Class Chancebox : Actor
|
||||
{
|
||||
|
|
|
|||
1713
zscript/swwm_handler.zsc
Normal file
1713
zscript/swwm_handler.zsc
Normal file
File diff suppressed because it is too large
Load diff
166
zscript/swwm_hudextra.zsc
Normal file
166
zscript/swwm_hudextra.zsc
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
// additional hud things
|
||||
|
||||
// Press F to Pay Respects
|
||||
Class PayRespects : HUDMessageBase
|
||||
{
|
||||
Vector2 basepos;
|
||||
int lifespan, initialspan, starttic;
|
||||
transient Font TewiFont;
|
||||
double scale;
|
||||
Vector2 hs, ss;
|
||||
int seed, seed2;
|
||||
|
||||
static PayRespects PressF()
|
||||
{
|
||||
let f = new("PayRespects");
|
||||
f.basepos = (FRandom[FInTheChat](0.,1.),FRandom[FInTheChat](1.02,1.05));
|
||||
f.scale = FRandom[FInTheChat](.5,2.);
|
||||
f.lifespan = f.initialspan = Random[FInTheChat](20,80);
|
||||
f.starttic = level.maptime;
|
||||
f.seed = Random[FInTheChat]();
|
||||
f.seed2 = Random[FInTheChat]();
|
||||
f.ScreenSizeChanged();
|
||||
return f;
|
||||
}
|
||||
|
||||
override bool Tick()
|
||||
{
|
||||
lifespan--;
|
||||
return (lifespan<=0);
|
||||
}
|
||||
|
||||
override void ScreenSizeChanged()
|
||||
{
|
||||
hs = StatusBar.GetHUDScale()*scale;
|
||||
ss = (Screen.GetWidth()/hs.x,Screen.GetHeight()/hs.y);
|
||||
}
|
||||
|
||||
override void Draw( int bottom, int visibility )
|
||||
{
|
||||
Vector2 realpos = (basepos.x*ss.x,basepos.y*ss.y);
|
||||
if ( !TewiFont ) TewiFont = Font.GetFont('TewiShaded');
|
||||
Vector2 fo = (TewiFont.StringWidth("F")/2.,-TewiFont.GetHeight());
|
||||
// F rise up
|
||||
int initspd = (128-seed);
|
||||
if ( (initspd >= 0) && (initspd < 32) ) initspd = 32;
|
||||
if ( (initspd < 0) && (initspd > -32) ) initspd = -32;
|
||||
int boostup = 32+(seed2/4);
|
||||
double fractic = SWWMStatusBar(statusbar)?SWWMStatusBar(statusbar).fractic:0;
|
||||
fo.x += (.15*initspd)*((initialspan-(lifespan-fractic))**.6);
|
||||
fo.y += ((initialspan-(lifespan-fractic))**1.6)-boostup*sin((90./initialspan)*(level.maptime+fractic-starttic));
|
||||
double alph = clamp((lifespan+fractic)/double(initialspan),0.,1.);
|
||||
Screen.DrawText(TewiFont,Font.CR_GREEN,realpos.x-fo.x,realpos.y-fo.y,"F",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
|
||||
}
|
||||
}
|
||||
|
||||
// One-liners
|
||||
Class SWWMOneLiner : HUDMessageBase
|
||||
{
|
||||
String whichline;
|
||||
int lifespan, curtime;
|
||||
transient Font TewiFont, MPlusFont;
|
||||
transient CVar safezone, lang, hscale;
|
||||
|
||||
static SWWMOneLiner Make( String whichline, int lifespan )
|
||||
{
|
||||
let l = new("SWWMOneLiner");
|
||||
l.whichline = whichline;
|
||||
l.curtime = l.lifespan = lifespan;
|
||||
return l;
|
||||
}
|
||||
|
||||
override bool Tick()
|
||||
{
|
||||
if ( players[consoleplayer].Health <= 0 ) curtime = int.min;
|
||||
curtime--;
|
||||
return (curtime<-20);
|
||||
}
|
||||
|
||||
override void Draw( int bottom, int visibility )
|
||||
{
|
||||
if ( !safezone ) safezone = CVar.GetCVar('swwm_hudmargin',players[consoleplayer]);
|
||||
if ( !lang ) lang = CVar.GetCVar('language',players[consoleplayer]);
|
||||
if ( !TewiFont ) TewiFont = Font.GetFont('TewiShaded');
|
||||
if ( !MPlusFont ) MPlusFont = Font.GetFont('MPlusShaded');
|
||||
if ( !hscale ) hscale = CVar.GetCVar('swwm_hudscale',players[consoleplayer]);
|
||||
int margin = safezone.GetInt();
|
||||
Vector2 hs;
|
||||
if ( hscale.GetInt() <= 0 ) hs = StatusBar.GetHUDScale();
|
||||
else
|
||||
{
|
||||
hs.x = hscale.GetInt();
|
||||
if ( Screen.GetWidth()/hs.x < 640. ) hs.x = max(1,floor(Screen.GetWidth()/640.));
|
||||
hs.y = hs.x;
|
||||
}
|
||||
Vector2 ss = (Screen.GetWidth()/hs.x,Screen.GetHeight()/hs.y);
|
||||
String loc = StringTable.Localize(whichline);
|
||||
if ( loc.Length() <= 0 ) return; // don't draw empty strings
|
||||
String locs = StringTable.Localize("$SWWM_LQUOTE")..loc..StringTable.Localize("$SWWM_RQUOTE");
|
||||
Font fnt = TewiFont;
|
||||
if ( lang.GetString() ~== "jp" ) fnt = MPlusFont;
|
||||
// split so it can fit
|
||||
BrokenLines l = fnt.BreakLines(locs,int(ss.x*.5));
|
||||
int maxlen = 0;
|
||||
for ( int i=0; i<l.Count(); i++ )
|
||||
{
|
||||
int len = fnt.StringWidth(l.StringAt(i));
|
||||
if ( len > maxlen ) maxlen = len;
|
||||
}
|
||||
int h = fnt.GetHeight();
|
||||
int fh = h*l.Count();
|
||||
double alph = clamp((curtime/20.)+1.,0.,1.);
|
||||
alph *= clamp((lifespan-curtime)/10.,0.,1.);
|
||||
Screen.Dim("Black",alph*.8,int((Screen.GetWidth()-(maxlen+12)*hs.x)/2.),int(bottom-(margin+2+fh)*hs.y),int((maxlen+12)*hs.x),int((fh+4)*hs.y));
|
||||
int yy = margin+fh;
|
||||
for ( int i=0; i<l.Count(); i++ )
|
||||
{
|
||||
int len = fnt.StringWidth(l.StringAt(i));
|
||||
Screen.DrawText(fnt,Font.CR_FIRE,int((ss.x-len)/2.),(bottom/hs.y)-yy,l.StringAt(i),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
|
||||
yy -= h;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Class LastLine
|
||||
{
|
||||
String type;
|
||||
int lineno;
|
||||
}
|
||||
|
||||
// Screen flashes from DT
|
||||
Class GenericFlash : HUDMessageBase
|
||||
{
|
||||
Color col;
|
||||
int duration;
|
||||
double alpha;
|
||||
Actor cam;
|
||||
transient CVar str;
|
||||
GenericFlash Setup( Actor camera, Color c, int d )
|
||||
{
|
||||
alpha = 1.0;
|
||||
col = c;
|
||||
duration = d;
|
||||
cam = camera;
|
||||
return self;
|
||||
}
|
||||
override bool Tick()
|
||||
{
|
||||
if ( duration > 0 ) alpha -= 1./duration;
|
||||
return (alpha<=0)||(!cam);
|
||||
}
|
||||
override void Draw( int bottom, int visibility )
|
||||
{
|
||||
if ( automapactive || (visibility != BaseStatusBar.HUDMSGLayer_UnderHUD) ) return;
|
||||
if ( cam && (players[consoleplayer].camera != cam) ) return;
|
||||
if ( !str ) str = CVar.GetCVar('swwm_flashstrength',players[consoleplayer]);
|
||||
Screen.Dim(col,(col.a/255.)*alpha*str.GetFloat(),0,0,Screen.GetWidth(),Screen.GetHeight());
|
||||
}
|
||||
}
|
||||
|
||||
Class QueuedFlash
|
||||
{
|
||||
Color c;
|
||||
int duration;
|
||||
int tic;
|
||||
Actor cam;
|
||||
}
|
||||
|
|
@ -572,7 +572,7 @@ Class BigPunchSplash : Actor
|
|||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
SWWMHandler.DoExplosion(self,special1,40000,120,60,ignoreme:target);
|
||||
SWWMUtility.DoExplosion(self,special1,40000,120,60,ignoreme:target);
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
|
@ -1149,7 +1149,7 @@ Class SWWMWeapon : Weapon abstract
|
|||
bool bloodless = true;
|
||||
double diff = deltaangle(self.angle,AngleTo(d.HitActor));
|
||||
self.angle += clamp(diff,-5.,5.);
|
||||
SWWMHandler.DoKnockback(d.HitActor,d.HitDir+(0,0,.2),dmg*2000);
|
||||
SWWMUtility.DoKnockback(d.HitActor,d.HitDir+(0,0,.2),dmg*2000);
|
||||
if ( raging )
|
||||
{
|
||||
invoker.bEXTREMEDEATH = true;
|
||||
|
|
|
|||
|
|
@ -290,7 +290,7 @@ Class PusherProjectile : Actor
|
|||
if ( target.bNOBLOOD || target.bINVULNERABLE ) A_StartSound("pusher/althit",CHAN_WEAPON,CHANF_OVERLAP);
|
||||
else A_StartSound("pusher/altmeat",CHAN_WEAPON,CHANF_OVERLAP);
|
||||
target.A_QuakeEx(6,6,6,10,0,200,"",QF_RELATIVE|QF_SCALEDOWN,falloff:100,rollIntensity:.7);
|
||||
SWWMHandler.DoKnockback(target,vel.unit(),85000);
|
||||
SWWMUtility.DoKnockback(target,vel.unit(),85000);
|
||||
return damage;
|
||||
}
|
||||
override void Touch( Actor toucher )
|
||||
|
|
@ -381,7 +381,7 @@ Class PusherWeapon : SWWMWeapon
|
|||
{
|
||||
double diff = deltaangle(self.angle,AngleTo(d.HitActor));
|
||||
self.angle += clamp(diff,-5.,5.);
|
||||
SWWMHandler.DoKnockback(d.HitActor,d.HitDir,8500);
|
||||
SWWMUtility.DoKnockback(d.HitActor,d.HitDir,8500);
|
||||
d.HitActor.A_QuakeEx(4,4,4,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 )
|
||||
|
|
@ -466,7 +466,7 @@ Class PusherWeapon : SWWMWeapon
|
|||
{
|
||||
double diff = deltaangle(self.angle,AngleTo(d.HitActor));
|
||||
self.angle += clamp(diff,-5.,5.);
|
||||
SWWMHandler.DoKnockback(d.HitActor,d.HitDir,85000);
|
||||
SWWMUtility.DoKnockback(d.HitActor,d.HitDir,85000);
|
||||
d.HitActor.A_QuakeEx(9,9,9,15,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 )
|
||||
|
|
@ -517,7 +517,7 @@ Class PusherWeapon : SWWMWeapon
|
|||
p.pitch = pitch;
|
||||
p.vel = x*p.speed*invoker.chargelevel;
|
||||
p.target = self;
|
||||
SWWMHandler.DoKnockback(self,x,85000.);
|
||||
SWWMUtility.DoKnockback(self,x,85000.);
|
||||
}
|
||||
if ( !gone )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1016,7 +1016,7 @@ Class Demolitionist : PlayerPawn
|
|||
}
|
||||
if ( jumpactor && jumpactor.bSHOOTABLE )
|
||||
{
|
||||
SWWMHandler.DoKnockback(jumpactor,(-walldir,0),12000);
|
||||
SWWMUtility.DoKnockback(jumpactor,(-walldir,0),12000);
|
||||
int dmg = jumpactor.DamageMobj(self,self,10,'Jump');
|
||||
if ( FindInventory("RagekitPower") )
|
||||
{
|
||||
|
|
@ -2006,7 +2006,7 @@ Class DemolitionistShockwave : Actor
|
|||
A_StartSound("demolitionist/hardland",CHAN_FOOTSTEP,CHANF_OVERLAP,attenuation:.2,pitch:.7);
|
||||
A_StartSound("demolitionist/hardland",CHAN_FOOTSTEP,CHANF_OVERLAP,attenuation:.1,pitch:.4);
|
||||
}
|
||||
SWWMHandler.DoExplosion(self,40+min(special1,120),100000+min(special1*2000,150000),100+min(special1*2,130),80,DE_BLAST|DE_EXTRAZTHRUST,'GroundPound',target);
|
||||
SWWMUtility.DoExplosion(self,40+min(special1,120),100000+min(special1*2000,150000),100+min(special1*2,130),80,DE_BLAST|DE_EXTRAZTHRUST,'GroundPound',target);
|
||||
for ( int i=0; i<360; i+=5 )
|
||||
{
|
||||
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](1,3);
|
||||
|
|
|
|||
123
zscript/swwm_shame.zsc
Normal file
123
zscript/swwm_shame.zsc
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
// SHAMEFUL DISPLAY
|
||||
|
||||
// >loading brutal doom with this
|
||||
Class SWWMBrutalHandler : StaticEventHandler
|
||||
{
|
||||
ui int timer;
|
||||
ui TextureID scr;
|
||||
bool detected;
|
||||
|
||||
override void OnRegister()
|
||||
{
|
||||
for ( int i=0; i<AllActorClasses.size(); i++ )
|
||||
{
|
||||
if ( (AllActorClasses[i].GetClassName() != "BrutalWeapon")
|
||||
&& (AllActorClasses[i].GetClassName() != "BrutalDoomer") ) continue;
|
||||
detected = true;
|
||||
break;
|
||||
}
|
||||
SetRandomSeed[bdscreen](Random[bdscreen]()+consoleplayer+MSTime());
|
||||
if ( detected )
|
||||
Console.Printf("\cg========\n\cgIf you have BD on your autoload, you really shouldn't.\n\cgIf you manually loaded it with this mod, why would you?\n\cgThey're not compatible and never will be.\n\cg========");
|
||||
}
|
||||
|
||||
override void UiTick()
|
||||
{
|
||||
if ( !detected ) return;
|
||||
if ( gamestate == GS_LEVEL )
|
||||
{
|
||||
if ( timer == 1 )
|
||||
{
|
||||
S_StartSound("brutal/ezmodo",CHAN_YOUDONEFUCKEDUP,CHANF_UI|CHANF_NOPAUSE|CHANF_OVERLAP,1,ATTN_NONE);
|
||||
S_StartSound("brutal/ezmodo",CHAN_YOUDONEFUCKEDUP,CHANF_UI|CHANF_NOPAUSE|CHANF_OVERLAP,1,ATTN_NONE);
|
||||
}
|
||||
else if ( timer == 350 ) ThrowAbortException(">Brutal Doom");
|
||||
timer++;
|
||||
}
|
||||
else timer = 0;
|
||||
}
|
||||
|
||||
override void WorldTick()
|
||||
{
|
||||
if ( !detected ) return;
|
||||
for ( int i=0; i<MAXPLAYERS; i++ ) if ( playeringame[i] ) players[i].cheats |= CF_TOTALLYFROZEN;
|
||||
}
|
||||
|
||||
override void RenderOverlay( RenderEvent e )
|
||||
{
|
||||
if ( !detected ) return;
|
||||
if ( !scr ) scr = TexMan.CheckForTexture("graphics/bdscreen.png",TexMan.Type_Any);
|
||||
Screen.Dim("Red",(timer/350.)-.2,0,0,Screen.GetWidth(),Screen.GetHeight());
|
||||
double ar = Screen.GetAspectRatio();
|
||||
Vector2 tsize = TexMan.GetScaledSize(scr);
|
||||
Vector2 vsize = (Screen.GetWidth(),Screen.GetHeight());
|
||||
if ( (tsize.x > vsize.x) || (tsize.y > vsize.y) )
|
||||
{
|
||||
double sar = tsize.x/tsize.y;
|
||||
if ( sar > ar ) vsize = (tsize.x,tsize.x/ar);
|
||||
else if ( sar < ar ) vsize = (tsize.y*ar,tsize.y);
|
||||
else vsize = tsize;
|
||||
}
|
||||
Screen.DrawTexture(scr,false,(vsize.x-tsize.x)/2.+FRandom[bdscreen](-1,1)*max(timer-40,0)**3*.000003,(vsize.y-tsize.y)/2.+FRandom[bdscreen](-1,1)*max(timer-40,0)**3*.000003,DTA_VirtualWidthF,vsize.x,DTA_VirtualHeightF,vsize.y,DTA_KeepRatio,true,DTA_Alpha,min(1.,timer/50.));
|
||||
Screen.Dim("Red",(timer/70.)-3.5,0,0,Screen.GetWidth(),Screen.GetHeight());
|
||||
}
|
||||
}
|
||||
|
||||
// HORNY
|
||||
Class SWWMHDoomHandler : StaticEventHandler
|
||||
{
|
||||
ui int timer;
|
||||
ui TextureID scr;
|
||||
bool detected;
|
||||
|
||||
override void OnRegister()
|
||||
{
|
||||
for ( int i=0; i<AllActorClasses.size(); i++ )
|
||||
{
|
||||
if ( AllActorClasses[i].GetClassName() != "HDoomPlayer" ) continue;
|
||||
detected = true;
|
||||
break;
|
||||
}
|
||||
SetRandomSeed[hdscreen](Random[hdscreen]()+consoleplayer+MSTime());
|
||||
if ( detected )
|
||||
Console.Printf("\cg========\n\cgHa ha very funny.\n\cgIf you want the Demolitionist to fuck some hot demon girls go commission a porn artist.\n\cg========");
|
||||
}
|
||||
|
||||
override void UiTick()
|
||||
{
|
||||
if ( !detected ) return;
|
||||
if ( gamestate == GS_LEVEL )
|
||||
{
|
||||
if ( timer == 50 )
|
||||
{
|
||||
S_StartSound("bestsound",CHAN_YOUDONEFUCKEDUP,CHANF_UI|CHANF_NOPAUSE|CHANF_OVERLAP,1,ATTN_NONE);
|
||||
S_StartSound("bestsound",CHAN_YOUDONEFUCKEDUP,CHANF_UI|CHANF_NOPAUSE|CHANF_OVERLAP,1,ATTN_NONE);
|
||||
}
|
||||
else if ( timer == 70 )
|
||||
{
|
||||
int ngiggl = Random[hdscreen](1,14);
|
||||
S_StartSound(String.Format("saya/giggle%d",ngiggl),CHAN_YOUDONEFUCKEDUP,CHANF_UI|CHANF_NOPAUSE|CHANF_OVERLAP,1,ATTN_NONE);
|
||||
S_StartSound(String.Format("saya/giggle%d",ngiggl),CHAN_YOUDONEFUCKEDUP,CHANF_UI|CHANF_NOPAUSE|CHANF_OVERLAP,1,ATTN_NONE);
|
||||
}
|
||||
timer++;
|
||||
}
|
||||
else timer = 0;
|
||||
}
|
||||
|
||||
override void RenderOverlay( RenderEvent e )
|
||||
{
|
||||
if ( !detected || (timer < 50) ) return;
|
||||
if ( !scr ) scr = TexMan.CheckForTexture("graphics/hdscreen.png",TexMan.Type_Any);
|
||||
double ar = Screen.GetAspectRatio();
|
||||
Vector2 tsize = TexMan.GetScaledSize(scr);
|
||||
Vector2 vsize = (Screen.GetWidth(),Screen.GetHeight());
|
||||
if ( (tsize.x > vsize.x) || (tsize.y > vsize.y) )
|
||||
{
|
||||
double sar = tsize.x/tsize.y;
|
||||
if ( sar > ar ) vsize = (tsize.x,tsize.x/ar);
|
||||
else if ( sar < ar ) vsize = (tsize.y*ar,tsize.y);
|
||||
else vsize = tsize;
|
||||
}
|
||||
Screen.DrawTexture(scr,false,(vsize.x-tsize.x)/2.,(vsize.y-tsize.y)/2.,DTA_VirtualWidthF,vsize.x,DTA_VirtualHeightF,vsize.y,DTA_KeepRatio,true);
|
||||
}
|
||||
}
|
||||
|
|
@ -26,89 +26,6 @@ Class GoldShellCasing : RedShellCasing
|
|||
}
|
||||
}
|
||||
|
||||
Class SWWMDamageAccumulator : Thinker
|
||||
{
|
||||
Actor victim, inflictor, source;
|
||||
Array<Int> amounts;
|
||||
int total;
|
||||
Name type;
|
||||
bool dontgib;
|
||||
int flags;
|
||||
|
||||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
// so many damn safeguards in this
|
||||
if ( !victim )
|
||||
{
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
int gibhealth = victim.GetGibHealth();
|
||||
// おまえはもう死んでいる
|
||||
if ( (victim.health-total <= gibhealth) && !dontgib )
|
||||
{
|
||||
// safeguard for inflictors that have somehow ceased to exist, which apparently STILL CAN HAPPEN
|
||||
if ( inflictor ) inflictor.bEXTREMEDEATH = true;
|
||||
else type = 'Extreme';
|
||||
}
|
||||
// make sure accumulation isn't reentrant
|
||||
if ( inflictor && (inflictor is 'EvisceratorChunk') ) inflictor.bAMBUSH = true;
|
||||
// 何?
|
||||
for ( int i=0; i<amounts.Size(); i++ )
|
||||
{
|
||||
if ( !victim ) break;
|
||||
victim.DamageMobj(inflictor,source,amounts[i],type,DMG_THRUSTLESS|flags);
|
||||
}
|
||||
// clean up
|
||||
if ( inflictor )
|
||||
{
|
||||
if ( inflictor is 'EvisceratorChunk' ) inflictor.bAMBUSH = false;
|
||||
inflictor.bEXTREMEDEATH = false;
|
||||
}
|
||||
Destroy();
|
||||
}
|
||||
|
||||
static void Accumulate( Actor victim, int amount, Actor inflictor, Actor source, Name type, bool dontgib = false, int flags = 0 )
|
||||
{
|
||||
if ( !victim ) return;
|
||||
let ti = ThinkerIterator.Create("SWWMDamageAccumulator",STAT_USER);
|
||||
SWWMDamageAccumulator a, match = null;
|
||||
while ( a = SWWMDamageAccumulator(ti.Next()) )
|
||||
{
|
||||
if ( a.victim != victim ) continue;
|
||||
match = a;
|
||||
break;
|
||||
}
|
||||
if ( !match )
|
||||
{
|
||||
match = new("SWWMDamageAccumulator");
|
||||
match.ChangeStatNum(STAT_USER);
|
||||
match.victim = victim;
|
||||
match.amounts.Clear();
|
||||
}
|
||||
match.amounts.Push(amount);
|
||||
match.total += amount;
|
||||
match.inflictor = inflictor;
|
||||
match.source = source;
|
||||
match.type = type;
|
||||
match.dontgib = dontgib;
|
||||
match.flags = flags;
|
||||
}
|
||||
|
||||
static clearscope int GetAmount( Actor victim )
|
||||
{
|
||||
let ti = ThinkerIterator.Create("SWWMDamageAccumulator",STAT_USER);
|
||||
SWWMDamageAccumulator a, match = null;
|
||||
while ( a = SWWMDamageAccumulator(ti.Next()) )
|
||||
{
|
||||
if ( a.victim != victim ) continue;
|
||||
return a.total;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Class SpreadgunTracer : LineTracer
|
||||
{
|
||||
Actor ignoreme;
|
||||
|
|
@ -457,7 +374,7 @@ Class DragonBreathArm : Actor
|
|||
let p = Spawn("DragonBreathPuff",pos);
|
||||
p.alpha *= .6+.4*(ReactionTime/20.);
|
||||
p.scale *= 3.5-2.5*(ReactionTime/20.);
|
||||
if ( !(ReactionTime%3) )
|
||||
if ( !(ReactionTime%5) )
|
||||
{
|
||||
let l = Spawn("PaletteLight",pos);
|
||||
l.Args[3] = int(90+50*(ReactionTime/20.));
|
||||
|
|
@ -465,7 +382,7 @@ Class DragonBreathArm : Actor
|
|||
l.target = p;
|
||||
}
|
||||
if ( !(ReactionTime%2) )
|
||||
SWWMHandler.DoExplosion(self,1+(reactiontime/1.5),1000+200*reactiontime,150-6*reactiontime,ignoreme:bHITOWNER?null:target);
|
||||
SWWMUtility.DoExplosion(self,1+(reactiontime*1.5),1000+200*reactiontime,150-6*reactiontime,ignoreme:bHITOWNER?null:target);
|
||||
double spd = vel.length();
|
||||
vel = (vel*.4+(FRandom[ExploS](-.2,.2),FRandom[ExploS](-.2,.2),FRandom[ExploS](-.2,.2))).unit()*spd;
|
||||
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](1,5);
|
||||
|
|
@ -581,7 +498,7 @@ Class SaltImpact : Actor
|
|||
{
|
||||
Super.PostBeginPlay();
|
||||
A_AlertMonsters(6000);
|
||||
SWWMHandler.DoExplosion(self,25+special2*5,15000,100,40);
|
||||
SWWMUtility.DoExplosion(self,25+special2*5,15000,100,40);
|
||||
A_QuakeEx(3,3,3,10,0,250,"",QF_RELATIVE|QF_SCALEDOWN,falloff:150,rollintensity:0.2);
|
||||
A_StartSound("spreadgun/salt",CHAN_VOICE,attenuation:.35);
|
||||
A_SprayDecal("ShockMarkSmall",-172);
|
||||
|
|
@ -691,7 +608,7 @@ Class SaltBeam : Actor
|
|||
if ( args[1] ) BusterWall.Bust(t.Results,85+Accuracy*10,target,x,t.Results.HitPos.z);
|
||||
if ( t.Results.HitType == TRACE_HitActor )
|
||||
{
|
||||
SWWMHandler.DoKnockback(t.Results.HitActor,x,25000);
|
||||
SWWMUtility.DoKnockback(t.Results.HitActor,x,25000);
|
||||
t.Results.HitActor.DamageMobj(self,target,60+Accuracy*5,'Salt',DMG_THRUSTLESS);
|
||||
}
|
||||
Vector3 norm = -x;
|
||||
|
|
@ -761,7 +678,7 @@ Class SaltBeam : Actor
|
|||
if ( isFrozen() ) return;
|
||||
A_FadeOut(.04);
|
||||
if ( Random[Spreadgun](-2,args[2]/10) == 0 )
|
||||
SWWMHandler.DoExplosion(self,5+Accuracy,5000,32,ignoreme:target);
|
||||
SWWMUtility.DoExplosion(self,5+Accuracy,5000,32,ignoreme:target);
|
||||
if ( ((special2%5) || args[2]) && !special1 ) SpreadOut();
|
||||
args[2]++;
|
||||
if ( !CheckNoDelay() || (tics == -1) ) return;
|
||||
|
|
@ -1423,7 +1340,7 @@ Class TheBall : Actor
|
|||
}
|
||||
crit = true;
|
||||
}
|
||||
SWWMHandler.DoKnockback(victim,vel.unit(),slamforce);
|
||||
SWWMUtility.DoKnockback(victim,vel.unit(),slamforce);
|
||||
bool bleeds = (victim && !victim.bINVULNERABLE && !victim.bNOBLOOD && is_schutt);
|
||||
int newdmg = victim.DamageMobj(self,target,dmg,'Concussion',crit?(DMG_THRUSTLESS|DMG_FOILINVUL):DMG_THRUSTLESS); // crits ignore invulnerability
|
||||
Vector3 dir = -vel.unit();
|
||||
|
|
@ -1450,7 +1367,7 @@ Class TheBall : Actor
|
|||
}
|
||||
}
|
||||
if ( crit )
|
||||
SWWMHandler.DoExplosion(self,dmg/2,25000,150,80,ignoreme:target);
|
||||
SWWMUtility.DoExplosion(self,dmg/2,25000,150,80,ignoreme:target);
|
||||
// only rip shootables
|
||||
if ( (slamforce > girth) && is_schutt )
|
||||
{
|
||||
|
|
@ -1656,7 +1573,7 @@ Class GoldenImpact : Actor
|
|||
{
|
||||
Super.PostBeginPlay();
|
||||
A_AlertMonsters(40000);
|
||||
SWWMHandler.DoExplosion(self,7777,40000,600,500,DE_EXTRAZTHRUST);
|
||||
SWWMUtility.DoExplosion(self,7777,40000,600,500,DE_EXTRAZTHRUST);
|
||||
A_QuakeEx(9,9,9,40,0,5000,"",QF_RELATIVE|QF_SCALEDOWN,falloff:500,rollintensity:1.5);
|
||||
A_StartSound("spreadgun/goldexpl",CHAN_VOICE,attenuation:.3);
|
||||
A_StartSound("spreadgun/goldexpl",CHAN_WEAPON,attenuation:.15);
|
||||
|
|
@ -1783,7 +1700,7 @@ Class GoldenSubImpact : Actor
|
|||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
SWWMHandler.DoExplosion(self,777,30000,400,300,DE_EXTRAZTHRUST);
|
||||
SWWMUtility.DoExplosion(self,777,30000,400,300,DE_EXTRAZTHRUST);
|
||||
A_QuakeEx(7,7,7,20,0,2000,"",QF_RELATIVE|QF_SCALEDOWN,falloff:200,rollintensity:.8);
|
||||
A_SprayDecal("BigScorch",-172);
|
||||
Scale *= FRandom[ExploS](0.8,1.1);
|
||||
|
|
@ -1908,7 +1825,7 @@ Class GoldenSubSubImpact : Actor
|
|||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
SWWMHandler.DoExplosion(self,77,20000,200,100,DE_EXTRAZTHRUST);
|
||||
SWWMUtility.DoExplosion(self,77,20000,200,100,DE_EXTRAZTHRUST);
|
||||
A_QuakeEx(4,4,4,15,0,1000,"",QF_RELATIVE|QF_SCALEDOWN,falloff:100,rollintensity:.4);
|
||||
A_SprayDecal("Scorch",-172);
|
||||
Scale *= FRandom[ExploS](0.8,1.1);
|
||||
|
|
@ -2128,7 +2045,7 @@ Class Spreadgun : SWWMWeapon
|
|||
{
|
||||
int realdmg = dmg?dmg:t.HitList[i].HitDamage;
|
||||
SWWMDamageAccumulator.Accumulate(t.HitList[i].HitActor,realdmg,invoker,self,'shot',!large);
|
||||
SWWMHandler.DoKnockback(t.HitList[i].HitActor,t.HitList[i].x+(0,0,0.025),mm*FRandom[Spreadgun](0.4,1.2));
|
||||
SWWMUtility.DoKnockback(t.HitList[i].HitActor,t.HitList[i].x+(0,0,0.025),mm*FRandom[Spreadgun](0.4,1.2));
|
||||
if ( t.HitList[i].HitActor.bNOBLOOD || t.HitList[i].HitActor.bINVULNERABLE )
|
||||
{
|
||||
let p = Spawn(impact,t.HitList[i].HitLocation);
|
||||
|
|
@ -2233,10 +2150,10 @@ Class Spreadgun : SWWMWeapon
|
|||
s.alpha *= .4;
|
||||
s.vel += vel*.5+x*FRandom[Spreadgun](4.,8.)+y*FRandom[Spreadgun](-1,1)+z*FRandom[Spreadgun](-1,1);
|
||||
}
|
||||
SWWMHandler.DoKnockback(self,-x,25000.);
|
||||
SWWMUtility.DoKnockback(self,-x,25000.);
|
||||
break;
|
||||
case 2:
|
||||
for ( int j=0; j<9; j++ )
|
||||
for ( int j=0; j<5; j++ )
|
||||
{
|
||||
a = FRandom[Spreadgun](0,360);
|
||||
s = FRandom[Spreadgun](0,.2);
|
||||
|
|
@ -2270,7 +2187,7 @@ Class Spreadgun : SWWMWeapon
|
|||
s.alpha *= .4;
|
||||
s.vel += vel*.5+x*FRandom[Spreadgun](4.,8.)+y*FRandom[Spreadgun](-2,2)+z*FRandom[Spreadgun](-2,2);
|
||||
}
|
||||
SWWMHandler.DoKnockback(self,-x,13000.);
|
||||
SWWMUtility.DoKnockback(self,-x,13000.);
|
||||
break;
|
||||
case 3:
|
||||
for ( int j=0; j<8; j++ )
|
||||
|
|
@ -2306,7 +2223,7 @@ Class Spreadgun : SWWMWeapon
|
|||
s.alpha *= .4;
|
||||
s.vel += vel*.5+x*FRandom[Spreadgun](4.,8.)+y*FRandom[Spreadgun](-2,2)+z*FRandom[Spreadgun](-2,2);
|
||||
}
|
||||
SWWMHandler.DoKnockback(self,-x,23000.);
|
||||
SWWMUtility.DoKnockback(self,-x,23000.);
|
||||
break;
|
||||
case 4:
|
||||
for ( int j=0; j<10; j++ )
|
||||
|
|
@ -2344,7 +2261,7 @@ Class Spreadgun : SWWMWeapon
|
|||
s.alpha *= .4;
|
||||
s.vel += vel*.5+x*FRandom[Spreadgun](4.,12.)+y*FRandom[Spreadgun](-2,2)+z*FRandom[Spreadgun](-2,2);
|
||||
}
|
||||
SWWMHandler.DoKnockback(self,-x,14000.);
|
||||
SWWMUtility.DoKnockback(self,-x,14000.);
|
||||
break;
|
||||
case 5:
|
||||
a = FRandom[Spreadgun](0,360);
|
||||
|
|
@ -2378,7 +2295,7 @@ Class Spreadgun : SWWMWeapon
|
|||
s.alpha *= .4;
|
||||
s.vel += vel*.5+x*FRandom[Spreadgun](4.,8.)+y*FRandom[Spreadgun](-1,1)+z*FRandom[Spreadgun](-1,1);
|
||||
}
|
||||
SWWMHandler.DoKnockback(self,-x,9500.);
|
||||
SWWMUtility.DoKnockback(self,-x,9500.);
|
||||
break;
|
||||
case 6:
|
||||
a = FRandom[Spreadgun](0,360);
|
||||
|
|
@ -2443,7 +2360,7 @@ Class Spreadgun : SWWMWeapon
|
|||
s.bAMBUSH = true;
|
||||
s.vel += vel*.5+x*FRandom[Spreadgun](1.,20.)+y*FRandom[Spreadgun](-2,2)+z*FRandom[Spreadgun](-2,2);
|
||||
}
|
||||
SWWMHandler.DoKnockback(self,-x,30000.);
|
||||
SWWMUtility.DoKnockback(self,-x,30000.);
|
||||
break;
|
||||
default:
|
||||
st = new("SpreadgunTracer");
|
||||
|
|
@ -2483,7 +2400,7 @@ Class Spreadgun : SWWMWeapon
|
|||
s.alpha *= .4;
|
||||
s.vel += vel*.5+x*FRandom[Spreadgun](4.,8.)+y*FRandom[Spreadgun](-2,2)+z*FRandom[Spreadgun](-2,2);
|
||||
}
|
||||
SWWMHandler.DoKnockback(self,-x,20000.);
|
||||
SWWMUtility.DoKnockback(self,-x,20000.);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -265,7 +265,7 @@ Class BigBiospark : Actor
|
|||
Vector3 dirto = level.Vec3Diff(pos,t.Vec3Offset(0,0,t.height/2));
|
||||
double dist = dirto.length();
|
||||
dirto /= dist;
|
||||
if ( dist > 4. ) SWWMHandler.DoKnockback(t,-dirto,clamp(120.-dist,0.,120.)*100);
|
||||
if ( dist > 4. ) SWWMUtility.DoKnockback(t,-dirto,clamp(120.-dist,0.,120.)*100);
|
||||
}
|
||||
}
|
||||
Health -= 2;
|
||||
|
|
@ -276,7 +276,7 @@ Class BigBiospark : Actor
|
|||
{
|
||||
A_StopSound(CHAN_VOICE);
|
||||
A_AlertMonsters(15000);
|
||||
SWWMHandler.DoExplosion(self,450,200000,300,100);
|
||||
SWWMUtility.DoExplosion(self,450,200000,300,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,8 +330,8 @@ Class BigBiospark : Actor
|
|||
if ( special1 > 40 ) return;
|
||||
double factor = (40-special1)/40.;
|
||||
double invfct = 1.-factor;
|
||||
SWWMHandler.DoExplosion(self,150*factor,0.,250*invfct);
|
||||
SWWMHandler.DoExplosion(self,0,-8000*factor,500*invfct);
|
||||
SWWMUtility.DoExplosion(self,150*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);
|
||||
SWWMHandler.DoExplosion(self,50,120000,150,80);
|
||||
SWWMUtility.DoExplosion(self,50,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);
|
||||
|
|
@ -588,8 +588,8 @@ Class BiosparkBall : Actor
|
|||
if ( special1 > 30 ) return;
|
||||
double factor = (30-special1)/30.;
|
||||
double invfct = 1.-factor;
|
||||
SWWMHandler.DoExplosion(self,30*factor,0.,150*invfct);
|
||||
SWWMHandler.DoExplosion(self,0,-5000*factor,300*invfct);
|
||||
SWWMUtility.DoExplosion(self,30*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 +699,7 @@ Class BiosparkBeamImpact : Actor
|
|||
{
|
||||
Super.PostBeginPlay();
|
||||
A_AlertMonsters(2000);
|
||||
SWWMHandler.DoExplosion(self,30,120000,100,40);
|
||||
SWWMUtility.DoExplosion(self,30,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);
|
||||
|
|
@ -752,8 +752,8 @@ Class BiosparkBeamImpact : Actor
|
|||
if ( special1 > 30 ) return;
|
||||
double factor = (30-special1)/30.;
|
||||
double invfct = 1.-factor;
|
||||
SWWMHandler.DoExplosion(self,10*factor,0.,50*invfct);
|
||||
SWWMHandler.DoExplosion(self,0.,-5000*factor,100*invfct);
|
||||
SWWMUtility.DoExplosion(self,10*factor,0.,50*invfct);
|
||||
SWWMUtility.DoExplosion(self,0.,-5000*factor,100*invfct);
|
||||
int numpt = int(Random[ExploS](8,16)*factor);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
|
|
@ -834,7 +834,7 @@ Class BiosparkComboImpactSub : Actor
|
|||
{
|
||||
Super.PostBeginPlay();
|
||||
if ( !bAMBUSH ) return;
|
||||
SWWMHandler.DoExplosion(self,200,10000,300,120);
|
||||
SWWMUtility.DoExplosion(self,200,10000,300,120);
|
||||
}
|
||||
States
|
||||
{
|
||||
|
|
@ -887,7 +887,7 @@ Class BiosparkComboImpact : Actor
|
|||
{
|
||||
Super.PostBeginPlay();
|
||||
A_AlertMonsters(6000);
|
||||
SWWMHandler.DoExplosion(self,bAMBUSH?(700+Args[0]*100):300,bAMBUSH?480000:200000,bAMBUSH?800:400,bAMBUSH?400:200);
|
||||
SWWMUtility.DoExplosion(self,bAMBUSH?(700+Args[0]*100):300,bAMBUSH?480000:200000,bAMBUSH?800:400,bAMBUSH?400:200);
|
||||
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);
|
||||
|
|
@ -955,8 +955,8 @@ Class BiosparkComboImpact : Actor
|
|||
if ( special1 > mx ) return;
|
||||
double factor = (mx-special1)/mx;
|
||||
double invfct = 1.-factor;
|
||||
SWWMHandler.DoExplosion(self,(bAMBUSH?(500+Args[0]*50):200)*factor,0.,(bAMBUSH?900.:300.)*invfct);
|
||||
SWWMHandler.DoExplosion(self,0.,-12000*factor,(bAMBUSH?1500:500)*invfct);
|
||||
SWWMUtility.DoExplosion(self,(bAMBUSH?(500+Args[0]*50):200)*factor,0.,(bAMBUSH?900.:300.)*invfct);
|
||||
SWWMUtility.DoExplosion(self,0.,-12000*factor,(bAMBUSH?1500:500)*invfct);
|
||||
int numpt = int(Random[ExploS](8,16)*factor);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
|
|
@ -1096,7 +1096,7 @@ Class BiosparkBeam : Actor
|
|||
}
|
||||
else
|
||||
{
|
||||
SWWMHandler.DoKnockback(t.hitlist[i].hitactor,t.hitlist[i].x,15000);
|
||||
SWWMUtility.DoKnockback(t.hitlist[i].hitactor,t.hitlist[i].x,15000);
|
||||
t.hitlist[i].hitactor.DamageMobj(self,target,GetMissileDamage(0,0),'Electric',DMG_THRUSTLESS);
|
||||
}
|
||||
}
|
||||
|
|
@ -1177,7 +1177,7 @@ Class BiosparkBeam : Actor
|
|||
int numpt = Random[Sparkster](-1,6);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
let a = Spawn("BiosparkArc",level.Vec3Offset(pos,tdir*FRandom[Sparkster](0,1)));
|
||||
let a = Spawn("BiosparkArc",level.Vec3Offset(pos,tdir*FRandom[Sparkster](frame?0:.3,1)));
|
||||
a.angle = angle;
|
||||
a.pitch = pitch;
|
||||
a.target = target;
|
||||
|
|
@ -1186,7 +1186,7 @@ Class BiosparkBeam : Actor
|
|||
numpt = Random[Sparkster](3,6);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
let a = Spawn("BiosparkArcSmall",level.Vec3Offset(pos,tdir*FRandom[Sparkster](0,1)));
|
||||
let a = Spawn("BiosparkArcSmall",level.Vec3Offset(pos,tdir*FRandom[Sparkster](frame?0:.3,1)));
|
||||
a.angle = angle;
|
||||
a.pitch = pitch;
|
||||
a.target = target;
|
||||
|
|
@ -1239,7 +1239,7 @@ Class BiosparkBeam : Actor
|
|||
}
|
||||
else
|
||||
{
|
||||
SWWMHandler.DoKnockback(t.hitlist[i].hitactor,t.hitlist[i].x,15000);
|
||||
SWWMUtility.DoKnockback(t.hitlist[i].hitactor,t.hitlist[i].x,15000);
|
||||
t.hitlist[i].hitactor.DamageMobj(self,target,int(GetMissileDamage(0,0)*alpha),'Electric',DMG_THRUSTLESS);
|
||||
}
|
||||
}
|
||||
|
|
@ -1428,7 +1428,7 @@ Class BiosparkArc : Actor
|
|||
}
|
||||
for ( int i=0; i<t.hitlist.Size(); i++ )
|
||||
{
|
||||
SWWMHandler.DoKnockback(t.hitlist[i].hitactor,-t.hitlist[i].x,GetMissileDamage(0,0)*1000);
|
||||
SWWMUtility.DoKnockback(t.hitlist[i].hitactor,-t.hitlist[i].x,GetMissileDamage(0,0)*1000);
|
||||
t.hitlist[i].hitactor.DamageMobj(self,target,GetMissileDamage(0,0),'Electric',DMG_THRUSTLESS);
|
||||
}
|
||||
Vector3 normal = -t.Results.HitVector, dir = t.Results.HitVector;
|
||||
|
|
@ -1761,7 +1761,7 @@ Class BiosparkCore : Actor
|
|||
bNOGRAVITY = true;
|
||||
A_SetRenderStyle(1.,STYLE_Add);
|
||||
A_AlertMonsters(5000);
|
||||
SWWMHandler.DoExplosion(self,50,120000,150,60);
|
||||
SWWMUtility.DoExplosion(self,50,120000,150,60);
|
||||
A_QuakeEx(6,6,6,16,0,800,"",QF_RELATIVE|QF_SCALEDOWN,falloff:300,rollIntensity:.8);
|
||||
Scale *= FRandom[ExploS](0.8,1.1);
|
||||
Scale.x *= RandomPick[ExploS](-1,1);
|
||||
|
|
@ -1810,8 +1810,8 @@ Class BiosparkCore : Actor
|
|||
if ( special2 > 30 ) return;
|
||||
double factor = (30-special2)/30.;
|
||||
double invfct = 1.-factor;
|
||||
SWWMHandler.DoExplosion(self,0.,-5000*factor,300*invfct);
|
||||
SWWMHandler.DoExplosion(self,30*factor,0.,150*invfct);
|
||||
SWWMUtility.DoExplosion(self,0.,-5000*factor,300*invfct);
|
||||
SWWMUtility.DoExplosion(self,30*factor,0.,150*invfct);
|
||||
int numpt = int(Random[ExploS](16,32)*factor);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
|
|
@ -2022,7 +2022,7 @@ Class Sparkster : SWWMWeapon
|
|||
A_ZoomFactor(1.);
|
||||
A_AlertMonsters(1200);
|
||||
A_PlayerFire();
|
||||
SWWMHandler.DoKnockback(self,-x,2500.);
|
||||
SWWMUtility.DoKnockback(self,-x,2500.);
|
||||
a = FRandom[Spread](0,360);
|
||||
s = FRandom[Spread](0,.012);
|
||||
[x2, y2, z2] = swwm_CoordUtil.GetAxes(BulletSlope(),angle,roll);
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ Class ExplodiumMagArm : Actor
|
|||
{
|
||||
A_CountDown();
|
||||
Spawn("ExplodiumMagTrail",pos);
|
||||
SWWMHandler.DoExplosion(self,2+reactiontime/3,3000+500*reactiontime,40+3*reactiontime,20);
|
||||
SWWMUtility.DoExplosion(self,2+reactiontime/3,3000+500*reactiontime,40+3*reactiontime,20);
|
||||
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](1,5);
|
||||
let s = Spawn("SWWMHalfSmoke",pos);
|
||||
s.vel = pvel+vel*.2;
|
||||
|
|
@ -133,7 +133,7 @@ Class ExplodiumMagProj : Actor
|
|||
A_SetRenderStyle(1.,STYLE_Add);
|
||||
Scale *= 2.+.2*special1;
|
||||
A_AlertMonsters(6000);
|
||||
SWWMHandler.DoExplosion(self,20+15*special1,80000+8000*special1,90+10*special1,60,DE_EXTRAZTHRUST);
|
||||
SWWMUtility.DoExplosion(self,20+15*special1,80000+8000*special1,90+10*special1,60,DE_EXTRAZTHRUST);
|
||||
A_QuakeEx(9,9,9,30,0,400+80*special1,"",QF_RELATIVE|QF_SCALEDOWN,falloff:300,rollintensity:2.);
|
||||
A_StartSound("explodium/maghit",CHAN_VOICE,attenuation:.35);
|
||||
A_StartSound("explodium/maghit",CHAN_WEAPON,attenuation:.2);
|
||||
|
|
@ -227,7 +227,7 @@ Class ExplodiumBulletImpact : Actor
|
|||
{
|
||||
Super.PostBeginPlay();
|
||||
A_AlertMonsters(3000);
|
||||
SWWMHandler.DoExplosion(self,25,80000,90,40,DE_EXTRAZTHRUST);
|
||||
SWWMUtility.DoExplosion(self,25,80000,90,40,DE_EXTRAZTHRUST);
|
||||
A_QuakeEx(4,4,4,10,0,250,"",QF_RELATIVE|QF_SCALEDOWN,falloff:150,rollintensity:0.2);
|
||||
A_StartSound("explodium/hit",CHAN_VOICE,attenuation:.6);
|
||||
A_StartSound("explodium/hit",CHAN_WEAPON,attenuation:.3);
|
||||
|
|
@ -304,7 +304,7 @@ Class ExplodiumGun : SWWMWeapon
|
|||
A_PlayerFire();
|
||||
Vector3 x, y, z, x2, y2, z2;
|
||||
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
|
||||
SWWMHandler.DoKnockback(self,-x,12000.);
|
||||
SWWMUtility.DoKnockback(self,-x,4000.);
|
||||
Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+3*y-2*z);
|
||||
double a = FRandom[Spread](0,360), s = FRandom[Spread](0,.002);
|
||||
[x2, y2, z2] = swwm_CoordUtil.GetAxes(BulletSlope(),angle,roll);
|
||||
|
|
@ -315,7 +315,7 @@ Class ExplodiumGun : SWWMWeapon
|
|||
if ( d.HitType == TRACE_HitActor )
|
||||
{
|
||||
int dmg = 25;
|
||||
SWWMHandler.DoKnockback(d.HitActor,d.HitDir,48000);
|
||||
SWWMUtility.DoKnockback(d.HitActor,d.HitDir,48000);
|
||||
dmg = d.HitActor.DamageMobj(invoker,self,dmg,'Explodium',DMG_USEANGLE|DMG_THRUSTLESS,atan2(d.HitDir.y,d.HitDir.x));
|
||||
if ( d.HitActor.bNOBLOOD || d.HitActor.bINVULNERABLE )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ Class CandyBeam : Actor
|
|||
}
|
||||
for ( int i=0; i<t.hitlist.Size(); i++ )
|
||||
{
|
||||
SWWMHandler.DoKnockback(t.hitlist[i].hitactor,t.hitlist[i].x,12000);
|
||||
SWWMUtility.DoKnockback(t.hitlist[i].hitactor,t.hitlist[i].x,12000);
|
||||
t.hitlist[i].hitactor.DamageMobj(self,target,GetMissileDamage(0,0),'Explodium',DMG_THRUSTLESS);
|
||||
}
|
||||
Vector3 normal = -t.Results.HitVector, dir = t.Results.HitVector;
|
||||
|
|
@ -250,7 +250,7 @@ Class CandyPop : Actor
|
|||
Spawn:
|
||||
BLPF B 3 NoDelay
|
||||
{
|
||||
SWWMHandler.DoExplosion(self,200,60000,120,40);
|
||||
SWWMUtility.DoExplosion(self,200,60000,120,40);
|
||||
Scale *= FRandom[ExploS](0.6,1.8);
|
||||
Scale.x *= RandomPick[ExploS](-1,1);
|
||||
Scale.y *= RandomPick[ExploS](-1,1);
|
||||
|
|
@ -314,7 +314,7 @@ Class TinyCandyPop : CandyPop
|
|||
Spawn:
|
||||
BLPF B 3 NoDelay
|
||||
{
|
||||
SWWMHandler.DoExplosion(self,60,32000,80,20);
|
||||
SWWMUtility.DoExplosion(self,60,32000,80,20);
|
||||
Scale *= FRandom[ExploS](0.6,1.8);
|
||||
Scale.x *= RandomPick[ExploS](-1,1);
|
||||
Scale.y *= RandomPick[ExploS](-1,1);
|
||||
|
|
@ -372,7 +372,7 @@ Class CandyMagArm : Actor
|
|||
{
|
||||
A_CountDown();
|
||||
Spawn("CandyMagTrail",pos);
|
||||
SWWMHandler.DoExplosion(self,80+reactiontime*7,3000+800*reactiontime,50+6*reactiontime);
|
||||
SWWMUtility.DoExplosion(self,80+reactiontime*7,3000+800*reactiontime,50+6*reactiontime);
|
||||
double spd = vel.length();
|
||||
vel = (vel*.1+(FRandom[ExploS](-.7,.7),FRandom[ExploS](-.7,.7),FRandom[ExploS](-.7,.7))).unit()*spd;
|
||||
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](1,5);
|
||||
|
|
@ -448,7 +448,7 @@ Class CandyMagArmBig : CandyMagArm
|
|||
{
|
||||
ReactionTime--;
|
||||
Spawn("CandyMagTrailBig",pos);
|
||||
SWWMHandler.DoExplosion(self,120+reactiontime*10,3000+900*reactiontime,100+8*reactiontime);
|
||||
SWWMUtility.DoExplosion(self,120+reactiontime*10,3000+900*reactiontime,100+8*reactiontime);
|
||||
double spd = vel.length();
|
||||
vel = (vel*.1+(FRandom[ExploS](-.5,.5),FRandom[ExploS](-.5,.5),FRandom[ExploS](-.5,.5))).unit()*spd;
|
||||
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](1,5);
|
||||
|
|
@ -527,7 +527,7 @@ Class CandyGunProj : Actor
|
|||
A_SetRenderStyle(1.,STYLE_Add);
|
||||
Scale *= 6.+.2*special1;
|
||||
A_AlertMonsters(40000);
|
||||
SWWMHandler.DoExplosion(self,4000+700*special1,80000+15000*special1,400+20*special1,250,DE_EXTRAZTHRUST);
|
||||
SWWMUtility.DoExplosion(self,4000+700*special1,80000+15000*special1,400+20*special1,250,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);
|
||||
|
|
@ -637,7 +637,7 @@ Class CandyMagProj : Actor
|
|||
A_SetRenderStyle(1.,STYLE_Add);
|
||||
Scale *= 3.+.2*special1;
|
||||
A_AlertMonsters(20000);
|
||||
SWWMHandler.DoExplosion(self,800+700*special1,60000+15000*special1,200+15*special1,100,DE_EXTRAZTHRUST);
|
||||
SWWMUtility.DoExplosion(self,800+700*special1,60000+15000*special1,200+15*special1,100,DE_EXTRAZTHRUST);
|
||||
A_QuakeEx(9,9,9,30,0,500+80*special1,"",QF_RELATIVE|QF_SCALEDOWN,falloff:500,rollintensity:2.);
|
||||
A_StartSound("candygun/maghit",CHAN_VOICE,attenuation:.24);
|
||||
A_StartSound("candygun/maghit",CHAN_WEAPON,attenuation:.12);
|
||||
|
|
@ -731,7 +731,7 @@ Class CandyBulletImpact : Actor
|
|||
{
|
||||
Super.PostBeginPlay();
|
||||
A_AlertMonsters(9000);
|
||||
SWWMHandler.DoExplosion(self,700,48000,200,80,DE_EXTRAZTHRUST);
|
||||
SWWMUtility.DoExplosion(self,700,48000,200,80,DE_EXTRAZTHRUST);
|
||||
A_QuakeEx(6,6,6,15,0,300,"",QF_RELATIVE|QF_SCALEDOWN,falloff:200,rollintensity:0.2);
|
||||
A_StartSound("candygun/hit",CHAN_VOICE,attenuation:.25);
|
||||
A_StartSound("candygun/hit",CHAN_WEAPON,attenuation:.5);
|
||||
|
|
@ -900,7 +900,14 @@ Class CandyGun : SWWMWeapon
|
|||
if ( chambered ) Screen.DrawText(TewiFont,Font.CR_FIRE,bx-22,by-21,"⁺¹",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Spacing,-1);
|
||||
Screen.DrawText(TewiFont,Font.CR_FIRE,bx-19,by-14,String.Format("%d",max(clipcount,0)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
||||
int cx = (Ammo1.Amount>9)?48:45;
|
||||
Screen.DrawText(TewiFont,Font.CR_FIRE,bx-cx,by-18,String.Format("%d",Ammo1.Amount),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
||||
int sb = Owner.CountInv("CandyGunBullets");
|
||||
if ( sb > 0 )
|
||||
{
|
||||
int cbx = (sb>9)?50:47;
|
||||
Screen.DrawText(TewiFont,Font.CR_FIRE,bx-cbx,by-21,String.Format("⁺%s",SWWMUtility.SuperscriptNum(sb)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Spacing,-1);
|
||||
Screen.DrawText(TewiFont,Font.CR_FIRE,bx-cx,by-14,String.Format("%d",Ammo1.Amount),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
||||
}
|
||||
else Screen.DrawText(TewiFont,Font.CR_FIRE,bx-cx,by-18,String.Format("%d",Ammo1.Amount),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
||||
Screen.DrawText(TewiFont,Font.CR_FIRE,bx-37,by-40,String.Format("%d",Ammo2.Amount),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
||||
}
|
||||
|
||||
|
|
@ -920,7 +927,7 @@ Class CandyGun : SWWMWeapon
|
|||
A_PlayerFire();
|
||||
Vector3 x, y, z, x2, y2, z2;
|
||||
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
|
||||
SWWMHandler.DoKnockback(self,-x,18000.);
|
||||
SWWMUtility.DoKnockback(self,-x,18000.);
|
||||
Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+3*y-2*z);
|
||||
double a = FRandom[Spread](0,360), s = FRandom[Spread](0,.005);
|
||||
[x2, y2, z2] = swwm_CoordUtil.GetAxes(BulletSlope(),angle,roll);
|
||||
|
|
@ -931,7 +938,7 @@ Class CandyGun : SWWMWeapon
|
|||
if ( d.HitType == TRACE_HitActor )
|
||||
{
|
||||
int dmg = 900;
|
||||
SWWMHandler.DoKnockback(d.HitActor,d.HitDir,72000);
|
||||
SWWMUtility.DoKnockback(d.HitActor,d.HitDir,72000);
|
||||
dmg = d.HitActor.DamageMobj(invoker,self,dmg,'Explodium',DMG_USEANGLE|DMG_THRUSTLESS|DMG_FOILINVUL,atan2(d.HitDir.y,d.HitDir.x));
|
||||
if ( d.HitActor.bNOBLOOD )
|
||||
{
|
||||
|
|
@ -1054,8 +1061,9 @@ Class CandyGun : SWWMWeapon
|
|||
int dropamt = invoker.clipcount-maxgiveamt;
|
||||
if ( dropamt > 0 ) ma.CreateTossable(dropamt);
|
||||
ma.Amount = min(ma.MaxAmount,ma.Amount+invoker.clipcount);
|
||||
if ( CheckLocalView() ) for ( int i=0; i<(invoker.clipcount-dropamt); i++ ) ma.PrintPickupMessage(true,ma.PickupMessage());
|
||||
if ( (invoker.clipcount-dropamt) > 0 ) ma.PlayPickupSound(self);
|
||||
ma.MagFill();
|
||||
if ( CheckLocalView() ) for ( int i=0; i<min(ma.Amount,invoker.clipcount-dropamt); i++ ) ma.PrintPickupMessage(true,ma.PickupMessage());
|
||||
if ( min(ma.Amount,invoker.clipcount-dropamt) > 0 ) ma.PlayPickupSound(self);
|
||||
invoker.clipcount = 0;
|
||||
}
|
||||
|
||||
|
|
@ -1075,14 +1083,14 @@ Class CandyGun : SWWMWeapon
|
|||
override bool CheckAmmo( int fireMode, bool autoSwitch, bool requireAmmo, int ammocount )
|
||||
{
|
||||
if ( sv_infiniteammo || Owner.FindInventory('PowerInfiniteAmmo',true) ) return true;
|
||||
if ( fireMode == PrimaryFire ) return (chambered || (clipcount > 0) || (Ammo1.Amount > 0));
|
||||
if ( fireMode == AltFire ) return (Ammo1.Amount > 0);
|
||||
if ( fireMode == PrimaryFire ) return (chambered || (clipcount > 0) || (Ammo1.Amount > 0) || (Owner.CountInv("CandyGunBullets") > 0));
|
||||
if ( fireMode == AltFire ) return ((Ammo1.Amount > 0) || (Owner.CountInv("CandyGunBullets") > 0));
|
||||
return Super.CheckAmmo(firemode,autoswitch,requireammo,ammocount);
|
||||
}
|
||||
|
||||
override bool ReportHUDAmmo()
|
||||
{
|
||||
if ( chambered || (clipcount > 0) ) return true;
|
||||
if ( chambered || (clipcount > 0) || (Owner.CountInv("CandyGunBullets") > 0) ) return true;
|
||||
if ( Ammo1.Amount <= 0 ) return false;
|
||||
return Super.ReportHUDAmmo();
|
||||
}
|
||||
|
|
@ -1119,13 +1127,13 @@ Class CandyGun : SWWMWeapon
|
|||
Ready:
|
||||
XZW2 A 1
|
||||
{
|
||||
if ( (invoker.clipcount <= 0) && !invoker.chambered && (invoker.Ammo1.Amount > 0) ) player.SetPSprite(PSP_WEAPON,ResolveState("Reload"));
|
||||
if ( (invoker.clipcount <= 0) && !invoker.chambered && ((invoker.Ammo1.Amount > 0) || (CountInv("CandyGunBullets") > 0)) ) player.SetPSprite(PSP_WEAPON,ResolveState("Reload"));
|
||||
else if ( (invoker.clipcount > 0) && !invoker.chambered ) player.SetPSprite(PSP_WEAPON,ResolveState("Slide"));
|
||||
else
|
||||
{
|
||||
int flg = WRF_ALLOWZOOM|WRF_ALLOWUSER1;
|
||||
if ( sv_infiniteammo || FindInventory('PowerInfiniteAmmo',true) || (invoker.Ammo1.Amount > 0) || invoker.chambered ) flg |= WRF_ALLOWRELOAD;
|
||||
if ( (invoker.Ammo1.Amount <= 0) && !sv_infiniteammo && !FindInventory('PowerInfiniteAmmo',true) ) flg |= WRF_NOSECONDARY;
|
||||
if ( (invoker.Ammo1.Amount <= 0) && (CountInv("CandyGunBullets") <= 0) && !sv_infiniteammo && !FindInventory('PowerInfiniteAmmo',true) ) flg |= WRF_NOSECONDARY;
|
||||
A_WeaponReady(flg);
|
||||
if ( player.cmd.buttons&(BT_ATTACK|BT_ALTATTACK) )
|
||||
invoker.CheckAmmo(EitherFire,true);
|
||||
|
|
@ -1148,7 +1156,7 @@ Class CandyGun : SWWMWeapon
|
|||
XZW5 Q 1;
|
||||
XZW5 R 1
|
||||
{
|
||||
if ( player.cmd.buttons&BT_ATTACK && (((invoker.Ammo1.Amount > 0) && (invoker.Ammo2.Amount > 0)) || sv_infiniteammo || FindInventory('PowerInfiniteAmmo',true)) )
|
||||
if ( player.cmd.buttons&BT_ATTACK && ((((invoker.Ammo1.Amount > 0) || (CountInv("CandyGunBullets") > 0)) && (invoker.Ammo2.Amount > 0)) || sv_infiniteammo || FindInventory('PowerInfiniteAmmo',true)) )
|
||||
player.SetPSprite(PSP_WEAPON,ResolveState("SpecialFire"));
|
||||
}
|
||||
XZW5 STUVWXYZ 1;
|
||||
|
|
@ -1187,15 +1195,26 @@ Class CandyGun : SWWMWeapon
|
|||
XZW1 B 0
|
||||
{
|
||||
invoker.PlayUpSound(self);
|
||||
if ( !sv_infiniteammo && !FindInventory('PowerInfiniteAmmo',true) )
|
||||
if ( sv_infiniteammo || FindInventory('PowerInfiniteAmmo',true) )
|
||||
invoker.clipcount = invoker.default.clipcount;
|
||||
else if ( invoker.Ammo1.Amount <= 0 )
|
||||
{
|
||||
MagAmmo sb = MagAmmo(FindInventory("CandyGunBullets"));
|
||||
int takeamt = min(sb.Amount,sb.ClipSize);
|
||||
invoker.clipcount = takeamt;
|
||||
sb.Amount -= takeamt;
|
||||
}
|
||||
else
|
||||
{
|
||||
invoker.Ammo1.Amount = max(0,invoker.Ammo1.Amount-1);
|
||||
invoker.clipcount = invoker.default.clipcount;
|
||||
invoker.clipcount = invoker.default.clipcount;
|
||||
}
|
||||
}
|
||||
Goto Select;
|
||||
Reload:
|
||||
XZW2 A 1
|
||||
{
|
||||
if ( (invoker.Ammo1.Amount <= 0) || (invoker.clipcount >= invoker.default.clipcount) ) return ResolveState("CheckBullet");
|
||||
if ( ((invoker.Ammo1.Amount <= 0) && (CountInv("CandyGunBullets") <= 0)) || (invoker.clipcount >= invoker.default.clipcount) ) return ResolveState("CheckBullet");
|
||||
A_PlayerReload();
|
||||
if ( invoker.clipcount <= 0 ) return ResolveState("ReloadEmpty");
|
||||
return ResolveState(null);
|
||||
|
|
@ -1225,9 +1244,20 @@ Class CandyGun : SWWMWeapon
|
|||
XZW4 R 1
|
||||
{
|
||||
A_StartSound("explodium/jamitin",CHAN_WEAPON,CHANF_OVERLAP);
|
||||
invoker.clipcount = invoker.default.clipcount;
|
||||
if ( !sv_infiniteammo && !FindInventory('PowerInfiniteAmmo',true) )
|
||||
if ( sv_infiniteammo || FindInventory('PowerInfiniteAmmo',true) )
|
||||
invoker.clipcount = invoker.default.clipcount;
|
||||
else if ( invoker.Ammo1.Amount <= 0 )
|
||||
{
|
||||
MagAmmo sb = MagAmmo(FindInventory("CandyGunBullets"));
|
||||
int takeamt = min(sb.Amount,sb.ClipSize);
|
||||
invoker.clipcount = takeamt;
|
||||
sb.Amount -= takeamt;
|
||||
}
|
||||
else
|
||||
{
|
||||
invoker.Ammo1.Amount = max(0,invoker.Ammo1.Amount-1);
|
||||
invoker.clipcount = invoker.default.clipcount;
|
||||
}
|
||||
}
|
||||
XZW4 STUV 1;
|
||||
XZW2 A 1 A_JumpIf(!invoker.chambered,"Slide");
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ Class SilverAirRip : Actor
|
|||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
SWWMHandler.DoExplosion(self,40,2000,40,ignoreme:target);
|
||||
SWWMUtility.DoExplosion(self,40,2000,40,ignoreme:target);
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
|
@ -78,7 +78,7 @@ Class SilverAirRip2 : Actor
|
|||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
SWWMHandler.DoExplosion(self,20,2000,30,ignoreme:target);
|
||||
SWWMUtility.DoExplosion(self,20,2000,30,ignoreme:target);
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
|
@ -101,7 +101,7 @@ Class SilverImpact : Actor
|
|||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
SWWMHandler.DoExplosion(self,100,8000,100,20);
|
||||
SWWMUtility.DoExplosion(self,100,8000,100,20);
|
||||
A_AlertMonsters(2500);
|
||||
A_QuakeEx(4,4,4,20,0,400,"",QF_RELATIVE|QF_SCALEDOWN,falloff:100,rollIntensity:.9);
|
||||
if ( special1 )
|
||||
|
|
@ -394,7 +394,7 @@ Class FatChodeImpact : Actor
|
|||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
SWWMHandler.DoExplosion(self,1500,40000,250,120,DE_THRUWALLS|DE_EXTRAZTHRUST);
|
||||
SWWMUtility.DoExplosion(self,1500,40000,250,120,DE_THRUWALLS|DE_EXTRAZTHRUST);
|
||||
A_AlertMonsters(8000);
|
||||
A_QuakeEx(7,7,7,50,0,2000,"",QF_RELATIVE|QF_SCALEDOWN,falloff:800,rollIntensity:1.);
|
||||
A_StartSound("silverbullet/chode",CHAN_VOICE,CHANF_DEFAULT,1.,.35);
|
||||
|
|
@ -528,7 +528,7 @@ Class FatChodeExplosionArm : Actor
|
|||
TNT1 A 1
|
||||
{
|
||||
A_CountDown();
|
||||
SWWMHandler.DoExplosion(self,20+reactiontime,8000+1500*reactiontime,80+5*reactiontime,50,DE_THRUWALLS);
|
||||
SWWMUtility.DoExplosion(self,20+reactiontime,8000+1500*reactiontime,80+5*reactiontime,50,DE_THRUWALLS);
|
||||
if ( level.IsPointInLevel(pos) )
|
||||
{
|
||||
A_SprayDecal("HugeScorch",-32);
|
||||
|
|
@ -596,9 +596,23 @@ Class SilverBullet : SWWMWeapon
|
|||
Screen.DrawTexture(AmmoIcon[0],false,bx-18,by-19,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,fcbselected?Color(128,0,0,0):Color(0,0,0,0));
|
||||
Screen.DrawTexture(AmmoIcon[1],false,bx-18,by-41,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,fcbselected?Color(0,0,0,0):Color(128,0,0,0));
|
||||
int cx = (Ammo1.Amount>9)?32:29;
|
||||
Screen.DrawText(TewiFont,Font.CR_FIRE,bx-cx,by-18,String.Format("%d",Ammo1.Amount),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,fcbselected?Color(128,0,0,0):Color(0,0,0,0));
|
||||
int sb = Owner.CountInv("SilverBullets");
|
||||
if ( sb > 0 )
|
||||
{
|
||||
int cbx = (sb>9)?34:30;
|
||||
Screen.DrawText(TewiFont,Font.CR_FIRE,bx-cbx,by-21,String.Format("⁺%s",SWWMUtility.SuperscriptNum(sb)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Spacing,-1,DTA_ColorOverlay,fcbselected?Color(128,0,0,0):Color(0,0,0,0));
|
||||
Screen.DrawText(TewiFont,Font.CR_FIRE,bx-cx,by-14,String.Format("%d",Ammo1.Amount),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,fcbselected?Color(128,0,0,0):Color(0,0,0,0));
|
||||
}
|
||||
else Screen.DrawText(TewiFont,Font.CR_FIRE,bx-cx,by-18,String.Format("%d",Ammo1.Amount),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,fcbselected?Color(128,0,0,0):Color(0,0,0,0));
|
||||
cx = (Ammo2.Amount>9)?32:29;
|
||||
Screen.DrawText(TewiFont,Font.CR_FIRE,bx-cx,by-40,String.Format("%d",Ammo2.Amount),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,fcbselected?Color(0,0,0,0):Color(128,0,0,0));
|
||||
sb = Owner.CountInv("SilverBullets2");
|
||||
if ( sb > 0 )
|
||||
{
|
||||
int cbx = (sb>9)?34:30;
|
||||
Screen.DrawText(TewiFont,Font.CR_FIRE,bx-cbx,by-43,String.Format("⁺%s",SWWMUtility.SuperscriptNum(sb)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Spacing,-1,DTA_ColorOverlay,fcbselected?Color(0,0,0,0):Color(128,0,0,0));
|
||||
Screen.DrawText(TewiFont,Font.CR_FIRE,bx-cx,by-36,String.Format("%d",Ammo2.Amount),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,fcbselected?Color(0,0,0,0):Color(128,0,0,0));
|
||||
}
|
||||
else Screen.DrawText(TewiFont,Font.CR_FIRE,bx-cx,by-40,String.Format("%d",Ammo2.Amount),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,fcbselected?Color(0,0,0,0):Color(128,0,0,0));
|
||||
}
|
||||
override void HudTick()
|
||||
{
|
||||
|
|
@ -609,7 +623,7 @@ Class SilverBullet : SWWMWeapon
|
|||
override bool ReportHUDAmmo()
|
||||
{
|
||||
if ( (chambered && !fired) || (clipcount > 0) ) return true;
|
||||
if ( (Ammo1.Amount <= 0) && (Ammo2.Amount <= 0) ) return false;
|
||||
if ( (Ammo1.Amount <= 0) && (Ammo2.Amount <= 0) && (CountInv("SilverBullets") <= 0) && (CountInv("SilverBullets2") <= 0) ) return false;
|
||||
return Super.ReportHUDAmmo();
|
||||
}
|
||||
override bool CheckAmmo( int firemode, bool autoswitch, bool requireammo, int ammocount )
|
||||
|
|
@ -620,7 +634,7 @@ Class SilverBullet : SWWMWeapon
|
|||
// allow player to still use the zoom even if there's no ammo left
|
||||
// (should work fine, assuming I've correctly interpreted the execution chain of all this stuff)
|
||||
if ( autoswitch && (fireMode == AltFire) ) return true;
|
||||
return ((chambered && !fired) || (clipcount > 0) || (Ammo1.Amount > 0) || (Ammo2.Amount > 0));
|
||||
return ((chambered && !fired) || (clipcount > 0) || (Ammo1.Amount > 0) || (Ammo2.Amount > 0) || (CountInv("SilverBullets") > 0) || (CountInv("SilverBullets2") > 0));
|
||||
}
|
||||
return Super.CheckAmmo(firemode,autoswitch,requireammo,ammocount);
|
||||
}
|
||||
|
|
@ -692,7 +706,7 @@ Class SilverBullet : SWWMWeapon
|
|||
{
|
||||
int realdmg = t.HitList[i].HitDamage;
|
||||
SWWMDamageAccumulator.Accumulate(t.HitList[i].HitActor,realdmg,invoker,self,'shot',false,DMG_FOILINVUL);
|
||||
SWWMHandler.DoKnockback(t.HitList[i].HitActor,t.HitList[i].x+(0,0,0.025),realdmg*20.*FRandom[SilverBullet](.8,1.2));
|
||||
SWWMUtility.DoKnockback(t.HitList[i].HitActor,t.HitList[i].x+(0,0,0.025),realdmg*20.*FRandom[SilverBullet](.8,1.2));
|
||||
if ( t.HitList[i].HitActor.bNOBLOOD )
|
||||
{
|
||||
let p = Spawn("SilverImpact",t.HitList[i].HitLocation);
|
||||
|
|
@ -797,7 +811,7 @@ Class SilverBullet : SWWMWeapon
|
|||
if ( t.Results.HitType == TRACE_HitActor )
|
||||
{
|
||||
int dmg = t.Results.HitActor.DamageMobj(invoker,self,1000,'shot',DMG_FOILINVUL|DMG_USEANGLE|DMG_THRUSTLESS,atan2(t.Results.HitVector.y,t.Results.HitVector.x));
|
||||
SWWMHandler.DoKnockback(t.Results.HitActor,t.Results.HitVector+(0,0,.025),dmg*20.*FRandom[SilverBullet](.8,1.2));
|
||||
SWWMUtility.DoKnockback(t.Results.HitActor,t.Results.HitVector+(0,0,.025),dmg*20.*FRandom[SilverBullet](.8,1.2));
|
||||
if ( !t.Results.HitActor.bNOBLOOD )
|
||||
{
|
||||
t.Results.HitActor.TraceBleed(dmg,self);
|
||||
|
|
@ -899,7 +913,7 @@ Class SilverBullet : SWWMWeapon
|
|||
}
|
||||
double fact = invoker.fcbchambered?270000.:320000.;
|
||||
if ( player.mo.CanCrouch() && (player.crouchfactor != 1) ) fact /= 10.;
|
||||
SWWMHandler.DoKnockback(self,-x,fact);
|
||||
SWWMUtility.DoKnockback(self,-x,fact);
|
||||
}
|
||||
action void A_DropCasing( bool fcb = false )
|
||||
{
|
||||
|
|
@ -945,8 +959,9 @@ Class SilverBullet : SWWMWeapon
|
|||
int dropamt = invoker.clipcount-maxgiveamt;
|
||||
if ( dropamt > 0 ) ma.CreateTossable(dropamt);
|
||||
ma.Amount = min(ma.MaxAmount,ma.Amount+invoker.clipcount);
|
||||
if ( CheckLocalView() ) for ( int i=0; i<(invoker.clipcount-dropamt); i++ ) ma.PrintPickupMessage(true,ma.PickupMessage());
|
||||
if ( (invoker.clipcount-dropamt) > 0 ) ma.PlayPickupSound(self);
|
||||
ma.MagFill();
|
||||
if ( CheckLocalView() ) for ( int i=0; i<min(ma.Amount,invoker.clipcount-dropamt); i++ ) ma.PrintPickupMessage(true,ma.PickupMessage());
|
||||
if ( min(ma.Amount,invoker.clipcount-dropamt) > 0 ) ma.PlayPickupSound(self);
|
||||
}
|
||||
invoker.ClipCount = 0;
|
||||
Vector3 x, y, z;
|
||||
|
|
@ -983,8 +998,10 @@ Class SilverBullet : SWWMWeapon
|
|||
action void A_SwitchAmmoType( bool ifempty = false )
|
||||
{
|
||||
bool oldsel = invoker.fcbselected;
|
||||
if ( invoker.fcbselected && (invoker.Ammo1.Amount > 0) ) invoker.fcbselected = (ifempty&&(invoker.Ammo2.Amount>0))?true:false;
|
||||
else if ( !invoker.fcbselected && (invoker.Ammo2.Amount > 0) ) invoker.fcbselected = (ifempty&&(invoker.Ammo1.Amount>0))?false:true;
|
||||
if ( invoker.fcbselected && ((invoker.Ammo1.Amount > 0) || (CountInv("SilverBullets") > 0)) )
|
||||
invoker.fcbselected = (ifempty&&((invoker.Ammo2.Amount>0)||(CountInv("SilverBullets2")>0)))?true:false;
|
||||
else if ( !invoker.fcbselected && ((invoker.Ammo2.Amount > 0) || (CountInv("SilverBullets2") > 0)) )
|
||||
invoker.fcbselected = (ifempty&&((invoker.Ammo1.Amount>0)||(CountInv("SilverBullets")>0)))?false:true;
|
||||
if ( oldsel != invoker.fcbselected ) A_StartSound("misc/invchange",CHAN_WEAPONEXTRA,CHANF_UI|CHANF_LOCAL);
|
||||
A_WeaponReady(WRF_NOFIRE);
|
||||
}
|
||||
|
|
@ -1067,7 +1084,7 @@ Class SilverBullet : SWWMWeapon
|
|||
{
|
||||
if ( !invoker.chambered || invoker.fired )
|
||||
{
|
||||
if ( !invoker.fired && (invoker.clipcount <= 0) && (sv_infiniteammo || FindInventory('PowerInfiniteAmmo',true) || (invoker.Ammo1.Amount > 0) || (invoker.Ammo2.Amount > 0)) )
|
||||
if ( !invoker.fired && (invoker.clipcount <= 0) && (sv_infiniteammo || FindInventory('PowerInfiniteAmmo',true) || (invoker.Ammo1.Amount > 0) || (invoker.Ammo2.Amount > 0) || (CountInv("SilverBullets") > 0) || (CountInv("SilverBullets2") > 0)) )
|
||||
{
|
||||
A_SwitchAmmoType(true);
|
||||
return ResolveState("Reload");
|
||||
|
|
@ -1275,7 +1292,7 @@ Class SilverBullet : SWWMWeapon
|
|||
Reload:
|
||||
XZW2 A 0
|
||||
{
|
||||
if ( ((invoker.clipcount >= invoker.default.clipcount) && (invoker.fcbselected == invoker.fcbloaded)) || (!sv_infiniteammo && !FindInventory('PowerInfiniteAmmo',true) && (invoker.Ammo1.Amount <= 0) && (invoker.Ammo2.Amount <= 0)) )
|
||||
if ( ((invoker.clipcount >= invoker.default.clipcount) && (invoker.fcbselected == invoker.fcbloaded)) || (!sv_infiniteammo && !FindInventory('PowerInfiniteAmmo',true) && (invoker.Ammo1.Amount <= 0) && (invoker.Ammo2.Amount <= 0) && (CountInv("SilverBullets") <= 0) && (CountInv("SilverBullets2") <= 0)) )
|
||||
return ResolveState("Idle");
|
||||
if ( invoker.zoomed )
|
||||
{
|
||||
|
|
@ -1328,9 +1345,20 @@ Class SilverBullet : SWWMWeapon
|
|||
XZW5 D 2
|
||||
{
|
||||
invoker.fcbloaded = false;
|
||||
invoker.clipcount = invoker.default.clipcount;
|
||||
if ( !sv_infiniteammo && !FindInventory('PowerInfiniteAmmo',true) )
|
||||
if ( sv_infiniteammo || FindInventory('PowerInfiniteAmmo',true) )
|
||||
invoker.clipcount = invoker.default.clipcount;
|
||||
else if ( invoker.Ammo1.Amount <= 0 )
|
||||
{
|
||||
MagAmmo sb = MagAmmo(FindInventory("SilverBullets"));
|
||||
int takeamt = min(sb.Amount,sb.ClipSize);
|
||||
invoker.clipcount = takeamt;
|
||||
sb.Amount -= takeamt;
|
||||
}
|
||||
else
|
||||
{
|
||||
invoker.Ammo1.Amount = max(0,invoker.Ammo1.Amount-1);
|
||||
invoker.clipcount = invoker.default.clipcount;
|
||||
}
|
||||
A_SwitchAmmoType(true);
|
||||
A_StartSound("silverbullet/magin",CHAN_WEAPON,CHANF_OVERLAP);
|
||||
}
|
||||
|
|
@ -1343,9 +1371,20 @@ Class SilverBullet : SWWMWeapon
|
|||
XZWB D 2
|
||||
{
|
||||
invoker.fcbloaded = true;
|
||||
invoker.clipcount = invoker.default.clipcount;
|
||||
if ( !sv_infiniteammo && !FindInventory('PowerInfiniteAmmo',true) )
|
||||
if ( sv_infiniteammo || FindInventory('PowerInfiniteAmmo',true) )
|
||||
invoker.clipcount = invoker.default.clipcount;
|
||||
else if ( invoker.Ammo2.Amount <= 0 )
|
||||
{
|
||||
MagAmmo sb = MagAmmo(FindInventory("SilverBullets2"));
|
||||
int takeamt = min(sb.Amount,sb.ClipSize);
|
||||
invoker.clipcount = takeamt;
|
||||
sb.Amount -= takeamt;
|
||||
}
|
||||
else
|
||||
{
|
||||
invoker.Ammo2.Amount = max(0,invoker.Ammo2.Amount-1);
|
||||
invoker.clipcount = invoker.default.clipcount;
|
||||
}
|
||||
A_SwitchAmmoType(true);
|
||||
A_StartSound("silverbullet/magin",CHAN_WEAPON,CHANF_OVERLAP);
|
||||
}
|
||||
|
|
|
|||
1066
zscript/swwm_thinkers.zsc
Normal file
1066
zscript/swwm_thinkers.zsc
Normal file
File diff suppressed because it is too large
Load diff
688
zscript/swwm_utility.zsc
Normal file
688
zscript/swwm_utility.zsc
Normal file
|
|
@ -0,0 +1,688 @@
|
|||
// Misc. Utility code
|
||||
|
||||
enum EDoExplosionFlags
|
||||
{
|
||||
DE_BLAST = 1, // sets BLASTED flag on pushed actors
|
||||
DE_NOBLEED = 2, // does not spawn blood decals on hit
|
||||
DE_NOSPLASH = 4, // like XF_NOSPLASH
|
||||
DE_THRUWALLS = 8, // damages through geometry (no sight check)
|
||||
DE_NOTMISSILE = 16, // instigator is the source itself (normally it'd be its target pointer)
|
||||
DE_EXTRAZTHRUST = 32, // applies a higher Z thrust to enemies on ground
|
||||
};
|
||||
|
||||
Class SWWMUtility
|
||||
{
|
||||
static clearscope void StripColor( out String str )
|
||||
{
|
||||
int len = str.CodePointCount();
|
||||
for ( int i=0; i<len; i++ )
|
||||
{
|
||||
int remlen = 0;
|
||||
if ( str.GetNextCodePoint(i) != 0x1C )
|
||||
continue;
|
||||
remlen++;
|
||||
if ( str.GetNextCodePoint(i+remlen) == 0x5B )
|
||||
while ( str.GetNextCodePoint(i+remlen) != 0x5D )
|
||||
remlen++;
|
||||
remlen++;
|
||||
str.Remove(i,remlen);
|
||||
len -= remlen;
|
||||
}
|
||||
}
|
||||
|
||||
static clearscope String SuperscriptNum( int val )
|
||||
{
|
||||
// unicode is fun
|
||||
static const int digs[] = {0x2070,0x00B9,0x00B2,0x00B3,0x2074,0x2075,0x2076,0x2077,0x2078,0x2079};
|
||||
String str = "";
|
||||
int digits = int(Log10(val));
|
||||
for ( int i=digits; i>=0; i-- )
|
||||
{
|
||||
int d = int(val/(10**i))%10;
|
||||
str.AppendCharacter(digs[d]);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
static clearscope void BeautifyClassName( out String str )
|
||||
{
|
||||
String workstr = str;
|
||||
str.Truncate(0);
|
||||
workstr.Replace("_"," ");
|
||||
int len = workstr.CodePointCount();
|
||||
for ( int i=0; i<len; i++ )
|
||||
{
|
||||
int cp1 = workstr.GetNextCodePoint(i);
|
||||
str.AppendCharacter(cp1);
|
||||
if ( i < len-1 )
|
||||
{
|
||||
int cp2 = workstr.GetNextCodePoint(i+1);
|
||||
if ( (String.CharLower(cp1) == cp1) && (String.CharUpper(cp2) == cp2) )
|
||||
str.AppendCharacter(0x20);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static clearscope int GetLineLock( Line l )
|
||||
{
|
||||
int locknum = l.locknumber;
|
||||
if ( !locknum )
|
||||
{
|
||||
// check the special
|
||||
switch ( l.special )
|
||||
{
|
||||
case FS_Execute:
|
||||
locknum = l.Args[2];
|
||||
break;
|
||||
case Door_LockedRaise:
|
||||
case Door_Animated:
|
||||
locknum = l.Args[3];
|
||||
break;
|
||||
case ACS_LockedExecute:
|
||||
case ACS_LockedExecuteDoor:
|
||||
case Generic_Door:
|
||||
locknum = l.Args[4];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return locknum;
|
||||
}
|
||||
|
||||
static clearscope bool IsExitLine( Line l )
|
||||
{
|
||||
if ( (l.special == Exit_Normal) || (l.special == Exit_Secret) || (l.special == Teleport_EndGame) || (l.special == Teleport_NewMap) )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// how the fuck is this not available to ZScript?
|
||||
// copied from P_PointOnLineSidePrecise()
|
||||
static clearscope int PointOnLineSide( Vector2 p, Line l )
|
||||
{
|
||||
if ( !l ) return 0;
|
||||
return (((p.y-l.v1.p.y)*l.delta.x+(l.v1.p.x-p.x)*l.delta.y) > double.epsilon);
|
||||
}
|
||||
|
||||
// box intersection check, for collision detection
|
||||
static clearscope bool BoxIntersect( Actor a, Actor b, Vector3 ofs = (0,0,0), int pad = 0 )
|
||||
{
|
||||
Vector3 diff = level.Vec3Diff(level.Vec3Offset(a.pos,ofs),b.pos);
|
||||
if ( (abs(diff.x) > (a.radius+b.radius+pad)) || (abs(diff.y) > (a.radius+b.radius+pad)) ) return false;
|
||||
if ( (diff.z > a.height+pad) || (diff.z < -(b.height+pad)) ) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// extruded box intersection check, useful when checking things that might be hit along a path
|
||||
static clearscope bool ExtrudeIntersect( Actor a, Actor b, Vector3 range, int steps, int pad = 0 )
|
||||
{
|
||||
if ( steps <= 0 ) return BoxIntersect(a,b,pad:pad);
|
||||
double step = 1./steps;
|
||||
for ( double i=step; i<=1.; i+=step )
|
||||
{
|
||||
if ( BoxIntersect(a,b,range*i,pad) )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// sphere intersection check, useful for proximity detection
|
||||
static clearscope bool SphereIntersect( Actor a, Vector3 p, double radius )
|
||||
{
|
||||
Vector3 ap = p+level.Vec3Diff(p,a.pos); // portal-relative actor position
|
||||
Vector3 amin = ap+(-a.radius,-a.radius,0),
|
||||
amax = ap+(a.radius,a.radius,a.height);
|
||||
double distsq = 0.;
|
||||
if ( p.x < amin.x ) distsq += (amin.x-p.x)**2;
|
||||
if ( p.x > amax.x ) distsq += (p.x-amax.x)**2;
|
||||
if ( p.y < amin.y ) distsq += (amin.y-p.y)**2;
|
||||
if ( p.y > amax.y ) distsq += (p.y-amax.y)**2;
|
||||
if ( p.z < amin.z ) distsq += (amin.z-p.z)**2;
|
||||
if ( p.z > amax.z ) distsq += (p.z-amax.z)**2;
|
||||
return (distsq <= (radius**2));
|
||||
}
|
||||
|
||||
// THANKS FOR NOT GIVING US ANY OTHER WAY TO CHECK IF A LOCK NUMBER IS VALID
|
||||
static clearscope bool IsValidLockNum( int l )
|
||||
{
|
||||
if ( (l < 1) || (l > 255) ) return true;
|
||||
Array<Int> valid;
|
||||
valid.Clear();
|
||||
for ( int i=0; i<Wads.GetNumLumps(); i++ )
|
||||
{
|
||||
String lname = Wads.GetLumpName(i);
|
||||
if ( !(lname ~== "LOCKDEFS") ) continue;
|
||||
String data = Wads.ReadLump(i);
|
||||
Array<String> lines;
|
||||
lines.Clear();
|
||||
data.Split(lines,"\n");
|
||||
for ( int j=0; j<lines.Size(); j++ )
|
||||
{
|
||||
if ( lines[j].Left(10) ~== "CLEARLOCKS" ) valid.Clear();
|
||||
else if ( Lines[j].Left(5) ~== "LOCK " )
|
||||
{
|
||||
Array<String> spl;
|
||||
spl.Clear();
|
||||
lines[j].Split(spl," ",TOK_SKIPEMPTY);
|
||||
// check game string (if any)
|
||||
if ( spl.Size() > 2 )
|
||||
{
|
||||
if ( (spl[2] ~== "DOOM") && !(gameinfo.gametype&GAME_Doom) ) continue;
|
||||
else if ( (spl[2] ~== "HERETIC") && !(gameinfo.gametype&GAME_Heretic) ) continue;
|
||||
else if ( (spl[2] ~== "HEXEN") && !(gameinfo.gametype&GAME_Hexen) ) continue;
|
||||
else if ( (spl[2] ~== "STRIFE") && !(gameinfo.gametype&GAME_Strife) ) continue;
|
||||
else if ( (spl[2] ~== "CHEX") && !(gameinfo.gametype&GAME_Chex) ) continue;
|
||||
}
|
||||
valid.Push(spl[1].ToInt());
|
||||
}
|
||||
}
|
||||
}
|
||||
for ( int i=0; i<valid.Size(); i++ )
|
||||
{
|
||||
if ( valid[i] == l ) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// wheeeeeeee, let's play a game of "who is who"
|
||||
static clearscope bool IsCivilian( Actor a )
|
||||
{
|
||||
if ( a is 'Beggar' )
|
||||
{
|
||||
if ( (a.level.mapname ~== "MAP32") && (a is 'Beggar1') )
|
||||
return false; // Prisoner (sorry but we have to)
|
||||
return true;
|
||||
}
|
||||
if ( a is 'Peasant' )
|
||||
{
|
||||
// exclude certain key NPCs
|
||||
if ( (a.level.mapname ~== "MAP01") && (a is 'Peasant9') )
|
||||
return false; // Beldin (sorry but we have to)
|
||||
if ( (a.level.mapname ~== "MAP02") && (a is 'Peasant22') )
|
||||
return false; // Mourel (fuck that guy)
|
||||
if ( (a.level.mapname ~== "MAP02") && (a is 'Peasant4') )
|
||||
return false; // Harris (also fuck that guy)
|
||||
if ( (a.level.mapname ~== "MAP04") && (a is 'Peasant5') )
|
||||
return false; // Derwin (fat bastard)
|
||||
if ( (a.level.mapname ~== "MAP04") && (a is 'Peasant7') )
|
||||
return false; // Ketrick (THIS IS GARBAGE)
|
||||
if ( (a.level.mapname ~== "MAP05") && (a is 'Peasant7') )
|
||||
return false; // Montag (gimme the damn key)
|
||||
if ( (a.level.mapname ~== "MAP05") && (a is 'Peasant8') )
|
||||
return false; // Wolenick (gimme a hand)
|
||||
if ( (a.level.mapname ~== "MAP33") && (a is 'Peasant5') )
|
||||
return false; // Harris (also fuck that guy)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Thanks to ZZYZX and Nash
|
||||
static play void SetToSlope( Actor a, double dang )
|
||||
{
|
||||
vector3 fnormal = a.CurSector.floorplane.Normal;
|
||||
// find closest 3d floor for its normal
|
||||
F3DFloor ff;
|
||||
for ( int i=0; i<a.CurSector.Get3DFloorCount(); i++ )
|
||||
{
|
||||
if ( !(a.CurSector.Get3DFloor(i).top.ZAtPoint(a.pos.xy) ~== a.floorz) ) continue;
|
||||
ff = a.CurSector.Get3DFloor(i);
|
||||
break;
|
||||
}
|
||||
if ( ff ) fnormal = -ff.top.Normal;
|
||||
vector2 fnormalp1 = ((fnormal.x != 0) || (fnormal.y != 0))?(fnormal.x,fnormal.y).Unit():(0,0);
|
||||
vector2 fnormalp2 = ((fnormal.x,fnormal.y).Length(),fnormal.z);
|
||||
double fang = atan2(fnormalp1.y,fnormalp1.x); // floor angle (not pitch!)
|
||||
double fpitch = atan2(fnormalp2.x,fnormalp2.y); // floor pitch
|
||||
double ddiff1 = sin(fang-dang);
|
||||
double ddiff2 = cos(fang-dang);
|
||||
a.pitch = fpitch*ddiff2;
|
||||
a.roll = -fpitch*ddiff1;
|
||||
a.angle = dang;
|
||||
}
|
||||
|
||||
static clearscope int Round100( double x )
|
||||
{
|
||||
return int(ceil(x/100.)*100.);
|
||||
}
|
||||
|
||||
// can't make clearscope because of SectorEffect.GetSector(), isn't that amazing?
|
||||
static play bool IsDoorSector( Sector s, int part )
|
||||
{
|
||||
// super-easy mode: check for boss special sectors
|
||||
if ( (level.mapname ~== "E1M8") || (level.mapname ~== "E2M8") || (level.mapname ~== "E3M8")
|
||||
|| (level.mapname ~== "E4M6") || (level.mapname ~== "E4M8") || (level.mapname ~== "E5M8")
|
||||
|| (level.mapname ~== "MAP07") )
|
||||
{
|
||||
let si = level.CreateSectorTagIterator(666);
|
||||
int idx;
|
||||
while ( (idx = si.Next()) != -1 )
|
||||
if ( level.Sectors[idx] == s )
|
||||
return true;
|
||||
if ( level.mapname ~== "MAP07" )
|
||||
{
|
||||
let si2 = level.CreateSectorTagIterator(667);
|
||||
while ( (idx = si.Next()) != -1 )
|
||||
if ( level.Sectors[idx] == s )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// easy mode: check if it's already moving
|
||||
if ( part )
|
||||
{
|
||||
let ti = ThinkerIterator.Create("MovingCeiling",Thinker.STAT_SECTOREFFECT);
|
||||
MovingCeiling mc;
|
||||
while ( mc = MovingCeiling(ti.Next()) )
|
||||
if ( mc.GetSector() == s )
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
let ti = ThinkerIterator.Create("MovingFloor",Thinker.STAT_SECTOREFFECT);
|
||||
MovingFloor mf;
|
||||
while ( mf = MovingFloor(ti.Next()) )
|
||||
if ( mf.GetSector() == s )
|
||||
return true;
|
||||
}
|
||||
// hard mode: look for all lines/actors with movement specials referencing us
|
||||
for ( int i=0; i<level.Lines.Size(); i++ )
|
||||
{
|
||||
Line l = level.Lines[i];
|
||||
if ( !l.special ) continue;
|
||||
if ( (part && (l.special >= 10) && (l.special <= 13))
|
||||
|| (!part && (l.special >= 20) && (l.special <= 25))
|
||||
|| (!part && (l.special == 28))
|
||||
|| ((l.special >= 29) && (l.special <= 30))
|
||||
|| (!part && (l.special >= 35) && (l.special <= 37))
|
||||
|| (part && (l.special >= 40) && (l.special <= 45))
|
||||
|| (!part && (l.special == 46))
|
||||
|| (part && (l.special == 47))
|
||||
|| (!part && (l.special >= 60) && (l.special <= 68))
|
||||
|| (part && (l.special == 69))
|
||||
|| ((l.special >= 94) && (l.special <= 96))
|
||||
|| (part && (l.special == 97))
|
||||
|| (!part && (l.special == 99))
|
||||
|| (part && (l.special == 104))
|
||||
|| (part && (l.special >= 105) && (l.special <= 106))
|
||||
|| (part && (l.special >= 168) && (l.special <= 169))
|
||||
|| (!part && (l.special == 172))
|
||||
|| (part && (l.special >= 192) && (l.special <= 199))
|
||||
|| (!part && (l.special == 200))
|
||||
|| (part && (l.special >= 201) && (l.special <= 202))
|
||||
|| (!part && (l.special == 203))
|
||||
|| (part && (l.special == 205))
|
||||
|| (!part && (l.special >= 206) && (l.special <= 207))
|
||||
|| (!part && (l.special == 228))
|
||||
|| (!part && (l.special >= 230) && (l.special <= 231))
|
||||
|| (!part && (l.special >= 238) && (l.special <= 242))
|
||||
|| ((l.special >= 245) && (l.special <= 247))
|
||||
|| (part && (l.special == 249))
|
||||
|| (!part && (l.special >= 250) && (l.special <= 251))
|
||||
|| (part && (l.special >= 251) && (l.special <= 255))
|
||||
|| (!part && (l.special >= 256) && (l.special <= 261))
|
||||
|| (part && (l.special >= 262) && (l.special <= 269))
|
||||
|| (!part && (l.special == 275))
|
||||
|| (part && (l.special == 276))
|
||||
|| (!part && (l.special == 279))
|
||||
|| (part && (l.special == 280)) )
|
||||
{
|
||||
let si = level.CreateSectorTagIterator(l.Args[0],l);
|
||||
int idx;
|
||||
while ( (idx = si.Next()) != -1 )
|
||||
if ( level.Sectors[idx] == s )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
let ti = ThinkerIterator.Create("Actor");
|
||||
Actor a;
|
||||
while ( a = Actor(ti.Next()) )
|
||||
{
|
||||
if ( !a.special || !a.Args[0] ) continue;
|
||||
if ( (part && (a.special >= 10) && (a.special <= 13))
|
||||
|| (!part && (a.special >= 20) && (a.special <= 25))
|
||||
|| (!part && (a.special == 28))
|
||||
|| ((a.special >= 29) && (a.special <= 30))
|
||||
|| (!part && (a.special >= 35) && (a.special <= 37))
|
||||
|| (part && (a.special >= 40) && (a.special <= 45))
|
||||
|| (!part && (a.special == 46))
|
||||
|| (part && (a.special == 47))
|
||||
|| (!part && (a.special >= 60) && (a.special <= 68))
|
||||
|| (part && (a.special == 69))
|
||||
|| ((a.special >= 94) && (a.special <= 96))
|
||||
|| (part && (a.special == 97))
|
||||
|| (!part && (a.special == 99))
|
||||
|| (part && (a.special == 104))
|
||||
|| (part && (a.special >= 105) && (a.special <= 106))
|
||||
|| (part && (a.special >= 168) && (a.special <= 169))
|
||||
|| (!part && (a.special == 172))
|
||||
|| (part && (a.special >= 192) && (a.special <= 199))
|
||||
|| (!part && (a.special == 200))
|
||||
|| (part && (a.special >= 201) && (a.special <= 202))
|
||||
|| (!part && (a.special == 203))
|
||||
|| (part && (a.special == 205))
|
||||
|| (!part && (a.special >= 206) && (a.special <= 207))
|
||||
|| (!part && (a.special == 228))
|
||||
|| (!part && (a.special >= 230) && (a.special <= 231))
|
||||
|| (!part && (a.special >= 238) && (a.special <= 242))
|
||||
|| ((a.special >= 245) && (a.special <= 247))
|
||||
|| (part && (a.special == 249))
|
||||
|| (!part && (a.special >= 250) && (a.special <= 251))
|
||||
|| (part && (a.special >= 251) && (a.special <= 255))
|
||||
|| (!part && (a.special >= 256) && (a.special <= 261))
|
||||
|| (part && (a.special >= 262) && (a.special <= 269))
|
||||
|| (!part && (a.special == 275))
|
||||
|| (part && (a.special == 276))
|
||||
|| (!part && (a.special == 279))
|
||||
|| (part && (a.special == 280)) )
|
||||
{
|
||||
let si = level.CreateSectorTagIterator(a.Args[0]);
|
||||
int idx;
|
||||
while ( (idx = si.Next()) != -1 )
|
||||
if ( level.Sectors[idx] == s )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// because GetTag() returns the localized string, we need to do things the hard way
|
||||
static clearscope String GetFunTag( Actor a, String defstr = "" )
|
||||
{
|
||||
if ( a is 'SWWMMonster' ) return SWWMMonster(a).GetFunTag(defstr);
|
||||
int ntags = 1;
|
||||
String basetag = "";
|
||||
switch ( a.GetClassName() )
|
||||
{
|
||||
// Doom
|
||||
case 'ZombieMan':
|
||||
case 'StealthZombieMan':
|
||||
basetag = "ZOMBIE";
|
||||
break;
|
||||
case 'ShotgunGuy':
|
||||
case 'StealthShotgunGuy':
|
||||
basetag = "SHOTGUN";
|
||||
break;
|
||||
case 'ChaingunGuy':
|
||||
case 'StealthChaingunGuy':
|
||||
basetag = "HEAVY";
|
||||
break;
|
||||
case 'DoomImp':
|
||||
case 'StealthDoomImp':
|
||||
basetag = "IMP";
|
||||
break;
|
||||
case 'Demon':
|
||||
case 'StealthDemon':
|
||||
basetag = "DEMON";
|
||||
break;
|
||||
case 'Spectre':
|
||||
basetag = "SPECTRE";
|
||||
break;
|
||||
case 'LostSoul':
|
||||
basetag = "LOST";
|
||||
break;
|
||||
case 'Cacodemon':
|
||||
case 'StealthCacodemon':
|
||||
basetag = "CACO";
|
||||
break;
|
||||
case 'HellKnight':
|
||||
case 'StealthHellKnight':
|
||||
basetag = "HELL";
|
||||
break;
|
||||
case 'BaronOfHell':
|
||||
case 'StealthBaron':
|
||||
basetag = "BARON";
|
||||
break;
|
||||
case 'Arachnotron':
|
||||
case 'StealthArachnotron':
|
||||
basetag = "ARACH";
|
||||
break;
|
||||
case 'PainElemental':
|
||||
basetag = "PAIN";
|
||||
break;
|
||||
case 'Revenant':
|
||||
case 'StealthRevenant':
|
||||
basetag = "REVEN";
|
||||
break;
|
||||
case 'Fatso':
|
||||
case 'StealthFatso':
|
||||
basetag = "MANCU";
|
||||
break;
|
||||
case 'Archvile':
|
||||
case 'StealthArchvile':
|
||||
basetag = "ARCH";
|
||||
break;
|
||||
case 'SpiderMastermind':
|
||||
basetag = "SPIDER";
|
||||
break;
|
||||
case 'Cyberdemon':
|
||||
basetag = "CYBER";
|
||||
break;
|
||||
case 'BossBrain':
|
||||
basetag = "BOSSBRAIN";
|
||||
break;
|
||||
case 'WolfensteinSS':
|
||||
basetag = "WOLFSS";
|
||||
break;
|
||||
case 'CommanderKeen':
|
||||
basetag = "KEEN";
|
||||
break;
|
||||
case 'MBFHelperDog':
|
||||
basetag = "DOG";
|
||||
break;
|
||||
// Heretic
|
||||
case 'Chicken':
|
||||
basetag = "CHICKEN";
|
||||
break;
|
||||
case 'Beast':
|
||||
basetag = "BEAST";
|
||||
break;
|
||||
case 'Clink':
|
||||
basetag = "CLINK";
|
||||
break;
|
||||
case 'Sorcerer1':
|
||||
case 'Sorcerer2':
|
||||
basetag = "DSPARIL";
|
||||
break;
|
||||
case 'HereticImp':
|
||||
case 'HereticImpLeader':
|
||||
basetag = "HERETICIMP";
|
||||
break;
|
||||
case 'Ironlich':
|
||||
basetag = "IRONLICH";
|
||||
break;
|
||||
case 'Knight':
|
||||
case 'KnightGhost':
|
||||
basetag = "BONEKNIGHT";
|
||||
break;
|
||||
case 'Minotaur':
|
||||
case 'MinotaurFriend':
|
||||
basetag = "MINOTAUR";
|
||||
break;
|
||||
case 'Mummy':
|
||||
case 'MummyGhost':
|
||||
basetag = "MUMMY";
|
||||
break;
|
||||
case 'MummyLeader':
|
||||
case 'MummyLeaderGhost':
|
||||
basetag = "MUMMYLEADER";
|
||||
break;
|
||||
case 'Snake':
|
||||
basetag = "SNAKE";
|
||||
break;
|
||||
case 'Wizard':
|
||||
basetag = "WIZARD";
|
||||
break;
|
||||
// Hexen
|
||||
case 'FireDemon':
|
||||
basetag = "FIREDEMON";
|
||||
break;
|
||||
case 'Demon1':
|
||||
case 'Demon1Mash':
|
||||
case 'Demon2':
|
||||
case 'Demon2Mash':
|
||||
basetag = "DEMON1";
|
||||
break;
|
||||
case 'Ettin':
|
||||
case 'EttinMash':
|
||||
basetag = "ETTIN";
|
||||
break;
|
||||
case 'Centaur':
|
||||
case 'CentaurMash':
|
||||
basetag = "CENTAUR";
|
||||
break;
|
||||
case 'CentaurLeader':
|
||||
basetag = "SLAUGHTAUR";
|
||||
break;
|
||||
case 'Bishop':
|
||||
basetag = "BISHOP";
|
||||
break;
|
||||
case 'IceGuy':
|
||||
basetag = "ICEGUY";
|
||||
break;
|
||||
case 'Serpent':
|
||||
case 'SerpentLeader':
|
||||
basetag = "SERPENT";
|
||||
break;
|
||||
case 'Wraith':
|
||||
case 'WraithBuried':
|
||||
basetag = "WRAITH";
|
||||
break;
|
||||
case 'Dragon':
|
||||
basetag = "DRAGON";
|
||||
break;
|
||||
case 'Korax':
|
||||
basetag = "KORAX";
|
||||
break;
|
||||
case 'FighterBoss':
|
||||
basetag = "FBOSS";
|
||||
break;
|
||||
case 'MageBoss':
|
||||
basetag = "MBOSS";
|
||||
break;
|
||||
case 'ClericBoss':
|
||||
basetag = "CBOSS";
|
||||
break;
|
||||
case 'Heresiarch':
|
||||
basetag = "HERESIARCH";
|
||||
break;
|
||||
}
|
||||
if ( basetag == "" ) return a.GetTag(defstr);
|
||||
String funtag = "FN_"..basetag.."_FUN";
|
||||
String lfuntag = StringTable.Localize(funtag,false);
|
||||
if ( lfuntag != funtag ) return lfuntag;
|
||||
String nfuntag = "FN_"..basetag.."_FUNN";
|
||||
String lnfuntag = StringTable.Localize(nfuntag,false);
|
||||
if ( lnfuntag == nfuntag ) return a.GetTag(defstr);
|
||||
ntags = lnfuntag.ToInt();
|
||||
return StringTable.Localize(String.Format("$FN_%s_FUN%d",basetag,Random[FunTags](1,ntags)));
|
||||
}
|
||||
|
||||
// Apply full 3D knockback in a specific direction, useful for hitscan
|
||||
static play void DoKnockback( Actor Victim, Vector3 HitDirection, double MomentumTransfer )
|
||||
{
|
||||
if ( !Victim )
|
||||
return;
|
||||
if ( !Victim.bSHOOTABLE && !Victim.bVULNERABLE )
|
||||
return;
|
||||
if ( Victim.bDONTTHRUST || (Victim.Mass >= Actor.LARGE_MASS) )
|
||||
return;
|
||||
Vector3 Momentum = HitDirection*MomentumTransfer;
|
||||
if ( (Victim.pos.z <= Victim.floorz) || !Victim.TestMobjZ() )
|
||||
Momentum.z = max(Momentum.z,.1*Momentum.length());
|
||||
Momentum /= Thinker.TICRATE*max(50,Victim.Mass);
|
||||
Victim.vel += Momentum;
|
||||
}
|
||||
|
||||
// complete spherical and more accurate replacement of A_Explode
|
||||
// 100% free of the buggery GZDoom's own splash damage has
|
||||
static play void DoExplosion( Actor Source, double Damage, double MomentumTransfer, double ExplosionRadius, double FullDamageRadius = 0., int flags = 0, Name DamageType = '', Actor ignoreme = null )
|
||||
{
|
||||
// debug, display radius sphere
|
||||
if ( swwm_explosiondebug )
|
||||
{
|
||||
let s = Actor.Spawn("RadiusDebugSphere",Source.pos);
|
||||
s.Scale *= ExplosionRadius;
|
||||
s.SetShade((Damage>0)?"Green":"Blue");
|
||||
if ( FullDamageRadius > 0. )
|
||||
{
|
||||
let s = Actor.Spawn("RadiusDebugSphere",Source.pos);
|
||||
s.Scale *= FullDamageRadius;
|
||||
s.SetShade("Red");
|
||||
}
|
||||
}
|
||||
if ( !(flags&DE_NOSPLASH) ) Source.CheckSplash(ExplosionRadius);
|
||||
double brange = 1./(ExplosionRadius-FullDamageRadius);
|
||||
Actor Instigator = (flags&DE_NOTMISSILE)?Source:Source.target;
|
||||
BlockThingsIterator bi = BlockThingsIterator.Create(Source,ExplosionRadius*2); // test with doubled radius, just to be sure
|
||||
while ( bi.Next() )
|
||||
{
|
||||
Actor a = bi.Thing;
|
||||
// early checks for self and ignored actor (usually the instigator)
|
||||
if ( !a || (a == ignoreme) || (a == Source) )
|
||||
continue;
|
||||
// can't be affected
|
||||
if ( !a.bSHOOTABLE && !a.bVULNERABLE )
|
||||
continue;
|
||||
// no blasting if no radius dmg (unless forced)
|
||||
if ( a.bNORADIUSDMG && !Source.bFORCERADIUSDMG )
|
||||
continue;
|
||||
// check the DONTHARMCLASS/DONTHARMSPECIES flags
|
||||
if ( !a.player && ((Source.bDONTHARMCLASS && (a.GetClass() == Source.GetClass())) || (Source.bDONTHARMSPECIES && (a.GetSpecies() == Source.GetSpecies()))) )
|
||||
continue;
|
||||
// can we see it
|
||||
if ( !(flags&DE_THRUWALLS) && !Source.CheckSight(a,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) )
|
||||
continue;
|
||||
// intersecting?
|
||||
if ( !SWWMUtility.SphereIntersect(a,Source.pos,ExplosionRadius) )
|
||||
continue;
|
||||
// calculate factor
|
||||
Vector3 dir = level.Vec3Diff(Source.pos,a.Vec3Offset(0,0,a.Height/2));
|
||||
double dist = dir.length();
|
||||
// intersecting, randomize direction
|
||||
if ( dir.length() <= double.epsilon )
|
||||
{
|
||||
double ang = FRandom[DoBlast](0,360);
|
||||
double pt = FRandom[DoBlast](-90,90);
|
||||
dir = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt));
|
||||
}
|
||||
dir /= dist;
|
||||
dist = clamp(dist-FullDamageRadius,0,min(dist,ExplosionRadius));
|
||||
double damagescale = 1.-clamp((dist-a.Radius)*brange,0.,1.);
|
||||
double mm = MomentumTransfer*damagescale;
|
||||
// no knockback if massive/unpushable
|
||||
if ( (abs(mm) > 0.) && !a.bDORMANT && !a.bDONTTHRUST && (a.Mass < Actor.LARGE_MASS) )
|
||||
{
|
||||
Vector3 Momentum = dir*mm;
|
||||
if ( (a.pos.z <= a.floorz) || !a.TestMobjZ() )
|
||||
Momentum.z = max(Momentum.z,(flags&DE_EXTRAZTHRUST?.4:.1)*Momentum.length());
|
||||
Momentum /= Thinker.TICRATE*max(50,a.Mass); // prevent tiny things from getting yeeted at warp speed
|
||||
a.vel += Momentum;
|
||||
if ( (flags&DE_BLAST) && a.bCANBLAST && !a.bDONTBLAST ) a.bBLASTED = true;
|
||||
}
|
||||
// hit it
|
||||
int dmg = int(Damage*damagescale);
|
||||
if ( dmg <= 0 ) continue; // no harm
|
||||
int ndmg = a.DamageMobj(Instigator,Source,dmg,(DamageType!='')?Source.DamageType:DamageType,DMG_EXPLOSION,atan2(-dir.y,-dir.x));
|
||||
if ( !(flags&DE_NOBLEED) ) a.TraceBleed((ndmg>0)?ndmg:dmg,Source);
|
||||
}
|
||||
// TODO destructible geometry support
|
||||
}
|
||||
}
|
||||
|
||||
Class RadiusDebugSphere : Actor
|
||||
{
|
||||
Default
|
||||
{
|
||||
RenderStyle "AddStencil";
|
||||
StencilColor "White";
|
||||
Radius .1;
|
||||
Height 0.;
|
||||
+NOGRAVITY;
|
||||
+NOINTERACTION;
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
XZW1 A 1 BRIGHT A_FadeOut();
|
||||
Wait;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue