266 lines
6.7 KiB
Text
266 lines
6.7 KiB
Text
// common code goes here
|
|
|
|
// extra sound channels for the mod
|
|
enum ESWWMGZChannels
|
|
{
|
|
CHAN_YOUDONEFUCKEDUP = 63200, // exception handler
|
|
CHAN_DEMOVOICE = 63201, // demolitionist voices
|
|
CHAN_FOOTSTEP = 63202, // footstep sounds and others
|
|
CHAN_WEAPONEXTRA = 63203, // additional weapon sounds (usually loops)
|
|
CHAN_POWERUP = 63204, // powerup sounds
|
|
CHAN_POWERUPEXTRA = 63205, // additional powerup sounds
|
|
CHAN_JETPACK = 63206, // jetpack sound
|
|
CHAN_ITEMEXTRA = 63207, // additional item sounds
|
|
CHAN_WEAPONEXTRA2 = 63208, // additional weapon sound slot
|
|
CHAN_WEAPONEXTRA3 = 63209, // additional weapon sound slot (again)
|
|
CHAN_DAMAGE = 63210, // used for impact/hit sounds
|
|
CHAN_AMBEXTRA = 63211, // player ambience when submerged
|
|
CHAN_DEMOVOICEAUX = 63212, // extra channel to make oneliner voices louder
|
|
CHAN_DEMOVOICEAUX2 = 63213, // how many more channels do I need???
|
|
CHAN_DEMOVOICEAUX3 = 63214, // oh god, the loudening
|
|
CHAN_FUELREGEN = 63215 // sound of fuel regenerating
|
|
};
|
|
|
|
const FallbackTag = "AWESOME IT'S PENIS"; // used on tag processing, please don't mind the actual string used)
|
|
const MaxBouncePerTic = 40; // maximum simultaneous bounces in one tic for a lightweight actor before we consider it's stuck
|
|
|
|
// basic "does nothing" actor, used to remove stuff in CheckReplacement
|
|
Class SWWMNothing : Actor
|
|
{
|
|
States
|
|
{
|
|
Spawn:
|
|
TNT1 A 1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class SWWMDamageAccumulator : Inventory
|
|
{
|
|
Actor inflictor, source;
|
|
Array<Int> amounts;
|
|
int total;
|
|
Name type;
|
|
bool dontgib;
|
|
int flags;
|
|
|
|
override void DoEffect()
|
|
{
|
|
Super.DoEffect();
|
|
// so many damn safeguards in this
|
|
if ( !Owner || (Owner.Health <= 0) )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
int gibhealth = Owner.GetGibHealth();
|
|
// お前はもう死んでいる
|
|
if ( (Owner.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 ( !Owner ) break;
|
|
Owner.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;
|
|
SWWMDamageAccumulator match = SWWMDamageAccumulator(victim.FindInventory("SWWMDamageAccumulator"));
|
|
if ( !match )
|
|
{
|
|
match = SWWMDamageAccumulator(Spawn("SWWMDamageAccumulator"));
|
|
match.AttachToOwner(victim);
|
|
}
|
|
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 match = SWWMDamageAccumulator(victim.FindInventory("SWWMDamageAccumulator"));
|
|
if ( match )
|
|
{
|
|
if ( match.source && match.source.FindInventory("AngeryPower") )
|
|
return (match.total>85899345)?int.max:(match.total*25);
|
|
return match.total;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
default
|
|
{
|
|
+INVENTORY.UNTOSSABLE;
|
|
+INVENTORY.UNDROPPABLE;
|
|
+INVENTORY.UNCLEARABLE;
|
|
}
|
|
}
|
|
|
|
// Track last damage source to blame fall damage on
|
|
Class SWWMWhoPushedMe : Inventory
|
|
{
|
|
Actor instigator;
|
|
|
|
static void SetInstigator( Actor b, Actor whomst )
|
|
{
|
|
if ( !b || !whomst ) return;
|
|
SWWMWhoPushedMe ffd = SWWMWhoPushedMe(b.FindInventory("SWWMWhoPushedMe"));
|
|
if ( ffd )
|
|
{
|
|
ffd.instigator = whomst;
|
|
return;
|
|
}
|
|
ffd = SWWMWhoPushedMe(Spawn("SWWMWhoPushedMe"));
|
|
ffd.AttachToOwner(b);
|
|
ffd.instigator = whomst;
|
|
}
|
|
|
|
static Actor RecallInstigator( Actor b )
|
|
{
|
|
if ( !b ) return null;
|
|
SWWMWhoPushedMe ffd = SWWMWhoPushedMe(b.FindInventory("SWWMWhoPushedMe"));
|
|
if ( ffd )
|
|
{
|
|
Actor whomst = ffd.instigator;
|
|
ffd.Destroy();
|
|
return whomst;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
default
|
|
{
|
|
+INVENTORY.UNTOSSABLE;
|
|
+INVENTORY.UNDROPPABLE;
|
|
+INVENTORY.UNCLEARABLE;
|
|
}
|
|
}
|
|
|
|
Class SWWMFlyTracker : Inventory
|
|
{
|
|
Actor instigator;
|
|
Vector3 startpos, curpos;
|
|
double maxdist;
|
|
int gracepd;
|
|
|
|
static void Track( Actor b, Actor whomst )
|
|
{
|
|
if ( !b || !whomst ) return;
|
|
SWWMFlyTracker ffd = SWWMFlyTracker(b.FindInventory("SWWMFlyTracker"));
|
|
if ( ffd )
|
|
{
|
|
ffd.instigator = whomst;
|
|
return;
|
|
}
|
|
ffd = SWWMFlyTracker(Spawn("SWWMFlyTracker"));
|
|
ffd.AttachToOwner(b);
|
|
ffd.instigator = whomst;
|
|
ffd.curpos = ffd.startpos = b.pos;
|
|
ffd.maxdist = 0;
|
|
}
|
|
|
|
override void DoEffect()
|
|
{
|
|
maxdist = max(maxdist,level.Vec3Diff(startpos,curpos).length());
|
|
if ( !Owner || Owner.bFLOAT || Owner.bNOGRAVITY || (Owner.waterlevel > 1) || (Owner.pos.z <= Owner.floorz) || !Owner.TestMobjZ(false) )
|
|
{
|
|
gracepd++;
|
|
if ( gracepd < 10 ) return;
|
|
if ( instigator ) SWWMUtility.AchievementProgress("flight",int(maxdist),instigator.player);
|
|
Destroy();
|
|
return;
|
|
}
|
|
gracepd = 0;
|
|
curpos = Owner.pos;
|
|
}
|
|
|
|
default
|
|
{
|
|
+INVENTORY.UNTOSSABLE;
|
|
+INVENTORY.UNDROPPABLE;
|
|
+INVENTORY.UNCLEARABLE;
|
|
}
|
|
}
|
|
|
|
// fractic-compatible interpolators, with double value
|
|
Class SmoothLinearValueInterpolator
|
|
{
|
|
private double val, oldval, diff;
|
|
|
|
static SmoothLinearValueInterpolator Create( double val, double diff )
|
|
{
|
|
let v = new("SmoothLinearValueInterpolator");
|
|
v.oldval = v.val = val;
|
|
v.diff = diff;
|
|
return v;
|
|
}
|
|
void Reset( double newval )
|
|
{
|
|
oldval = val = newval;
|
|
}
|
|
void Update( double newval )
|
|
{
|
|
oldval = val;
|
|
if ( abs(newval-val) < diff ) val = newval;
|
|
else if ( val > newval ) val = max(newval,val-diff);
|
|
else val = min(newval,val+diff);
|
|
}
|
|
double GetValue( double fractic = 1. )
|
|
{
|
|
return (val~==oldval)?val:SWWMUtility.Lerp(oldval,val,fractic);
|
|
}
|
|
}
|
|
Class SmoothDynamicValueInterpolator
|
|
{
|
|
private double val, oldval, factor, mindiff, maxdiff;
|
|
|
|
static SmoothDynamicValueInterpolator Create( double val, double factor, double mindiff, double maxdiff )
|
|
{
|
|
let v = new("SmoothDynamicValueInterpolator");
|
|
v.oldval = v.val = val;
|
|
v.factor = factor;
|
|
v.mindiff = mindiff;
|
|
v.maxdiff = maxdiff;
|
|
return v;
|
|
}
|
|
void Reset( double newval )
|
|
{
|
|
oldval = val = newval;
|
|
}
|
|
void Update( double newval )
|
|
{
|
|
oldval = val;
|
|
if ( abs(newval-val) < mindiff ) val = newval;
|
|
else
|
|
{
|
|
double diff = min(abs(newval-val)*factor,maxdiff);
|
|
if ( val > newval ) val = max(newval,val-diff);
|
|
else val = min(newval,val+diff);
|
|
}
|
|
}
|
|
double GetValue( double fractic = 1. )
|
|
{
|
|
return (val~==oldval)?val:SWWMUtility.Lerp(oldval,val,fractic);
|
|
}
|
|
}
|