Major code refactoring. SWWMHandler could still use some more, though.

This commit is contained in:
Mari the Deer 2021-02-27 23:59:40 +01:00
commit c5abe83831
94 changed files with 17859 additions and 17678 deletions

View file

@ -0,0 +1,501 @@
// ============================================================================
// Ammo fabricator
// ============================================================================
Class AmmoFabricator : Inventory abstract
{
Mixin SWWMOverlapPickupSound;
Mixin SWWMUseToPickup;
int budget, pertype, maxunitprice;
Property Budget : budget;
Property PerType : pertype;
Property MaxUnitPrice : maxunitprice;
override Inventory CreateCopy( Actor other )
{
// additional lore
SWWMLoreLibrary.Add(other.player,"Fabricator");
return Super.CreateCopy(other);
}
private bool CmpFabAmmo( Class<Ammo> a, Class<Ammo> b )
{
let ia = Owner.FindInventory(a);
int cnta = ia?ia.Amount:0;
int maxa = ia?ia.MaxAmount:GetDefaultByType(a).Amount;
let ib = Owner.FindInventory(b);
int cntb = ib?ib.Amount:0;
int maxb = ib?ib.MaxAmount:GetDefaultByType(b).Amount;
double facta = cnta/double(maxa);
double factb = cntb/double(maxb);
return (facta >= factb);
}
private int partition_fabammo( Array<Class<Ammo> > a, int l, int h )
{
Class<Ammo> pv = a[h];
int i = (l-1);
for ( int j=l; j<=(h-1); j++ )
{
if ( CmpFabAmmo(pv,a[j]) )
{
i++;
Class<Ammo> tmp = a[j];
a[j] = a[i];
a[i] = tmp;
}
}
Class<Ammo> tmp = a[h];
a[h] = a[i+1];
a[i+1] = tmp;
return i+1;
}
private void qsort_fabammo( Array<Class<Ammo> > a, int l, int h )
{
if ( l >= h ) return;
int p = partition_fabammo(a,l,h);
qsort_fabammo(a,l,p-1);
qsort_fabammo(a,p+1,h);
}
bool FabricateAmmo()
{
Array<Class<Ammo> > available;
// populate ammo production list
for ( int i=0; i<AllActorClasses.Size(); i++ )
{
let a = (Class<Ammo>)(AllActorClasses[i]);
// skip over candy gun spares, they're "special ammo"
if ( a == 'CandyGunSpares' ) continue;
// only direct descendants of ammo with a set price below our max unit price
if ( !a || (a.GetParentClass() != 'Ammo') ) continue;
let def = GetDefaultByType(a);
if ( (def.Stamina <= 0) || (def.Stamina > maxunitprice) ) continue;
// only ammo for weapons that are valid (can be used)
bool isvalid = false;
for ( int j=0; j<AllActorClasses.Size(); j++ )
{
let type = (class<Weapon>)(AllActorClasses[j]);
if ( !type ) continue;
let rep = GetReplacement(type);
if ( (rep != type) && !(rep is "DehackedPickup") ) continue;
readonly<Weapon> weap = GetDefaultByType(type);
if ( !Owner.player || !Owner.player.weapons.LocateWeapon(type) || weap.bCheatNotWeapon ) continue;
let ready = weap.FindState("Ready");
if ( !ready || !ready.ValidateSpriteFrame() ) continue;
if ( (type is 'SWWMWeapon') && SWWMWeapon(weap).UsesAmmo(a) )
{
isvalid = true;
break;
}
if ( (weap.AmmoType1 == a) || (weap.AmmoType2 == a) )
{
isvalid = true;
break;
}
}
if ( !isvalid ) continue;
available.Push(a);
}
// sort by "need weight" (prioritize ammo that the player lacks over ammo that the player has plenty of
qsort_fabammo(available,0,available.Size()-1);
// loop through until we fill the inventory or run out of budget
bool given = false;
int consumed = 0;
String fabstr = "";
bool comma = false;
int tpertype = pertype;
for ( int i=0; i<available.Size(); i++ )
{
int amt, lim;
int cnt = 0;
Ammo cur = Ammo(Owner.FindInventory(available[i]));
if ( cur )
{
amt = cur.Amount;
lim = cur.MaxAmount;
}
else
{
cur = Ammo(Spawn(available[i]));
amt = cur.Amount = 0;
lim = cur.MaxAmount;
cur.AttachToOwner(Owner);
}
// percentage based on DEFAULT max amount (capped at 1 minimum)
if ( pertype < 0 ) tpertype = max(1,-int(cur.default.MaxAmount*pertype*.01));
while ( (amt < lim) && (consumed+cur.default.Stamina < budget) && (cnt < tpertype) )
{
consumed += cur.default.Stamina;
amt = ++cur.Amount;
cnt++;
given = true;
}
if ( cnt > 0 )
{
if ( comma ) fabstr.AppendFormat(", %dx %s",cnt,cur.GetTag());
else fabstr.AppendFormat("%dx %s",cnt,cur.GetTag());
comma = true;
}
}
if ( given ) PrintPickupMessage(true,fabstr);
return given;
}
override bool Use( bool pickup )
{
bool shouldautouse = false;
if ( swwm_enforceautouseammo == 1 ) shouldautouse = true;
else if ( swwm_enforceautouseammo == -1 ) shouldautouse = false;
else shouldautouse = CVar.GetCVar('swwm_autouseammo',Owner.player).GetBool();
if ( pickup && !shouldautouse ) return false;
if ( FabricateAmmo() )
{
if ( pickup && ((Owner.player == players[consoleplayer]) || bBigPowerup) ) Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA);
return true;
}
return false;
}
Default
{
+INVENTORY.INVBAR;
+INVENTORY.AUTOACTIVATE;
+FLOATBOB;
Inventory.UseSound "fabricator/use";
Inventory.PickupFlash "SWWMPickupFlash";
FloatBobStrength 0.25;
Radius 10;
Height 24;
}
States
{
Spawn:
XZW1 A -1;
Stop;
}
}
Class FabricatorTier1 : AmmoFabricator
{
Mixin SWWMAutoUseFix;
Default
{
Tag "$T_FABRICATOR1";
Stamina -2500;
Inventory.Icon "graphics/HUD/Icons/I_Fabricator1.png";
Inventory.PickupMessage "$T_FABRICATOR1";
Inventory.MaxAmount 20;
Inventory.InterHubAmount 20;
AmmoFabricator.Budget 3000;
AmmoFabricator.PerType 1;
AmmoFabricator.MaxUnitPrice 2500;
}
}
Class FabricatorTier2 : AmmoFabricator
{
Mixin SWWMAutoUseFix;
Default
{
Tag "$T_FABRICATOR2";
Stamina -12000;
Inventory.Icon "graphics/HUD/Icons/I_Fabricator2.png";
Inventory.PickupMessage "$T_FABRICATOR2";
Inventory.MaxAmount 15;
Inventory.InterHubAmount 15;
AmmoFabricator.Budget 15000;
AmmoFabricator.PerType 2;
AmmoFabricator.MaxUnitPrice 12000;
}
}
Class FabricatorTier3 : AmmoFabricator
{
Mixin SWWMAutoUseFix;
Default
{
Tag "$T_FABRICATOR3";
Stamina -80000;
Inventory.Icon "graphics/HUD/Icons/I_Fabricator3.png";
Inventory.PickupMessage "$T_FABRICATOR3";
Inventory.MaxAmount 10;
Inventory.InterHubAmount 10;
AmmoFabricator.Budget 100000;
AmmoFabricator.PerType 4;
AmmoFabricator.MaxUnitPrice 80000;
}
}
Class FabricatorTier4 : AmmoFabricator
{
Default
{
Tag "$T_FABRICATOR4";
Stamina -1000000;
Inventory.Icon "graphics/HUD/Icons/I_Fabricator4.png";
Inventory.PickupMessage "$T_FABRICATOR4";
Inventory.MaxAmount 5;
Inventory.InterHubAmount 5;
AmmoFabricator.Budget int.max;
AmmoFabricator.PerType -50;
AmmoFabricator.MaxUnitPrice 1000000;
-INVENTORY.AUTOACTIVATE;
}
}
// ============================================================================
// Hammerspace embiggener
// ============================================================================
Class HammerspaceEmbiggener : Inventory
{
Mixin SWWMOverlapPickupSound;
Mixin SWWMUseToPickup;
override Inventory CreateCopy( Actor other )
{
bool traded = (GetClass()=='TradedHammerspaceEmbiggener');
if ( !traded ) other.A_StartSound("powerup/embiggener",CHAN_ITEMEXTRA);
// Find every unique type of ammoitem. Give it to the player if
// he doesn't have it already, and increase its maximum capacity.
for ( int i=0; i<AllActorClasses.Size(); i++ )
{
let type = (class<Ammo>)(AllActorClasses[i]);
if ( !type || (type.GetParentClass() != 'Ammo') ) continue;
// check that it's for a valid weapon
bool isvalid = false;
for ( int j=0; j<AllActorClasses.Size(); j++ )
{
let type2 = (class<Weapon>)(AllActorClasses[j]);
if ( !type2 ) continue;
let rep = GetReplacement(type2);
if ( (rep != type2) && !(rep is "DehackedPickup") ) continue;
readonly<Weapon> weap = GetDefaultByType(type2);
if ( !other.player || !other.player.weapons.LocateWeapon(type2) || weap.bCheatNotWeapon ) continue;
let ready = weap.FindState("Ready");
if ( !ready || !ready.ValidateSpriteFrame() ) continue;
if ( (type2 is 'SWWMWeapon') && SWWMWeapon(weap).UsesAmmo(type) )
{
isvalid = true;
break;
}
if ( (weap.AmmoType1 == type) || (weap.AmmoType2 == type) )
{
isvalid = true;
break;
}
}
if ( !isvalid ) continue;
let ammoitem = Ammo(other.FindInventory(type));
int amount = GetDefaultByType(type).BackpackAmount*self.Amount;
if ( traded ) amount = 0;
if ( amount < 0 ) amount = 0;
if ( !ammoitem )
{
// The player did not have the ammoitem. Add it.
ammoitem = Ammo(Spawn(type));
ammoitem.Amount = amount;
if ( ammoitem.BackpackMaxAmount > 0 )
{
double factor = (ammoitem.BackpackMaxAmount-ammoitem.default.MaxAmount)/double(MaxAmount);
ammoitem.MaxAmount = int(ammoitem.default.MaxAmount+min(self.Amount,MaxAmount)*factor);
}
if ( (ammoitem.Amount > ammoitem.MaxAmount) && !sv_unlimited_pickup )
ammoitem.Amount = ammoitem.MaxAmount;
ammoitem.AttachToOwner(other);
}
else
{
// The player had the ammoitem. Give some more.
if ( ammoitem.BackpackMaxAmount > 0 )
{
double factor = (ammoitem.BackpackMaxAmount-ammoitem.default.MaxAmount)/double(MaxAmount);
ammoitem.MaxAmount = int(ammoitem.default.MaxAmount+min(self.Amount,MaxAmount)*factor);
}
if ( ammoitem.Amount < ammoitem.MaxAmount )
{
if ( (ammoitem.Amount > 0) && (ammoitem.Amount+amount < 0) )
ammoitem.Amount = int.max;
else ammoitem.Amount += amount;
if ( (ammoitem.Amount > ammoitem.MaxAmount) && !sv_unlimited_pickup )
ammoitem.Amount = ammoitem.MaxAmount;
}
}
}
self.Amount = min(self.Amount,MaxAmount);
if ( GetParentClass() == 'HammerspaceEmbiggener' )
{
if ( !GoAway() ) Destroy();
let copy = Inventory(Spawn('HammerspaceEmbiggener'));
copy.ClearCounters();
copy.Amount = self.Amount;
copy.MaxAmount = self.MaxAmount;
return copy;
}
if ( GoAway() )
{
let copy = Inventory(Spawn(GetClass()));
copy.ClearCounters();
copy.Amount = self.Amount;
copy.MaxAmount = self.MaxAmount;
return copy;
}
return self;
}
override bool HandlePickup( Inventory item )
{
if ( (item.GetClass() == GetClass()) || (item.GetParentClass() == 'HammerspaceEmbiggener') )
{
bool traded = (item.GetClass()=='TradedHammerspaceEmbiggener');
if ( !traded ) Owner.A_StartSound("powerup/embiggener",CHAN_ITEMEXTRA);
if ( (Amount > 0) && (Amount+item.Amount < 0) )
Amount = int.max;
else Amount += item.Amount;
if ( Amount > MaxAmount ) Amount = MaxAmount;
item.bPickupGood = true;
// readjust ammo values to new capacity
for ( Inventory i=Owner.Inv; i; i=i.Inv )
{
if ( !(i is 'Ammo') ) continue;
if ( Ammo(i).BackpackMaxAmount > 0 )
{
double factor = (Ammo(i).BackpackMaxAmount-i.default.MaxAmount)/double(MaxAmount);
i.MaxAmount = int(i.default.MaxAmount+Amount*factor);
}
int amount = Ammo(i).BackpackAmount*item.Amount;
if ( traded ) i.Amount = 0;
if ( (i.Amount > 0) && (i.Amount+amount < 0) )
i.Amount = int.max;
else i.Amount += amount;
if ( (i.Amount > i.MaxAmount) && !sv_unlimited_pickup )
i.Amount = i.MaxAmount;
}
return true;
}
// new ammo suddenly added? upgrade it (this shouldn't happen unless fucky scripting has been involved)
if ( (item is 'Ammo') && !Owner.FindInventory(Ammo(item).GetParentAmmo()) )
{
if ( Ammo(item).BackpackMaxAmount > 0 )
{
double factor = (Ammo(item).BackpackMaxAmount-item.default.MaxAmount)/double(MaxAmount);
item.MaxAmount = int(item.default.MaxAmount+Amount*factor);
}
}
return false;
}
override void DepleteOrDestroy()
{
// reset upgrade
for ( Inventory i=Owner.Inv; i; i=i.Inv )
{
if ( !(i is 'Ammo') ) continue;
i.MaxAmount = i.default.MaxAmount;
if ( i.Amount > i.MaxAmount ) i.Amount = i.MaxAmount;
}
Super.DepleteOrDestroy();
}
// merges overlapping embiggeners into a bulk upgrade
void A_MergeEmbiggeners()
{
let bt = BlockThingsIterator.Create(self,16);
int tamount = Amount;
while ( bt.Next() )
{
let t = bt.Thing;
if ( !t || (t == self) || !(t is 'HammerspaceEmbiggener') || !(t.spawnpoint ~== spawnpoint) ) continue;
tamount += HammerspaceEmbiggener(t).Amount;
t.ClearCounters();
t.Destroy();
}
if ( tamount <= 1 ) return;
tamount -= tamount%2; // always even numbered
if ( GetClass() == 'BulkHammerspaceEmbiggener' )
{
Amount = min(tamount,MaxAmount);
return;
}
let n = Spawn("BulkHammerspaceEmbiggener",pos);
Inventory(n).Amount = min(tamount,MaxAmount);
n.spawnpoint = spawnpoint;
n.spawnangle = spawnangle;
n.angle = angle;
n.pitch = pitch;
n.roll = roll;
n.special = special;
for ( int i=0; i<5; i++ ) n.args[i] = args[i];
n.special1 = special1;
n.special2 = special2;
n.spawnflags = spawnflags&~MTF_SECRET;
n.HandleSpawnFlags();
n.spawnflags = spawnflags;
n.bCountSecret = spawnflags&MTF_SECRET;
n.ChangeTid(tid);
n.vel = vel;
n.master = master;
n.tracer = tracer;
n.target = target;
if ( !bDROPPED ) n.bDROPPED = false;
ClearCounters();
Destroy();
}
Default
{
Tag "$T_EMBIGGENER";
Stamina -800000;
Inventory.PickupMessage "$T_EMBIGGENER";
Inventory.MaxAmount 8;
Inventory.InterHubAmount 8;
Inventory.PickupFlash "SWWMPickupFlash";
+INVENTORY.UNDROPPABLE;
+INVENTORY.UNTOSSABLE;
+INVENTORY.ALWAYSPICKUP;
+COUNTITEM;
+FLOATBOB;
FloatBobStrength 0.25;
Radius 8;
Height 24;
}
States
{
Spawn:
XZW1 A -1 NoDelay A_MergeEmbiggeners();
Stop;
}
}
// used when cheating or trading, this version does not give ammo and is meant
// only for GiveInventory, so it shouldn't be spawned in the world
Class TradedHammerspaceEmbiggener : HammerspaceEmbiggener {}
// used to denote "merged" embiggeners, changes color based on amount
// green (2+)
// blue (4+)
// purple (6+)
// black (8+)
Class BulkHammerspaceEmbiggener : HammerspaceEmbiggener
{
override string PickupMessage()
{
return String.Format("%dx %s",Amount,StringTable.Localize("$T_BULKEMBIGGENER"));
}
States
{
Spawn:
XZW1 A -1 NoDelay
{
A_MergeEmbiggeners();
if ( bDestroyed ) return ResolveState(null);
if ( Amount > 1 ) return SpawnState+min(4,Amount/2);
return ResolveState(null);
}
XZW1 BCDE -1;
Stop;
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,172 @@
// All the armor items go here
Class ArmorNugget : SWWMArmor
{
Default
{
Inventory.Icon "graphics/HUD/Icons/I_ArmorNugget.png";
Inventory.Amount 1;
Inventory.MaxAmount 200;
Inventory.InterHubAmount 200;
SWWMArmor.ArmorPriority 1;
SWWMArmor.GiverArmor "ArmorNuggetItem";
}
override int HandleDamage( int damage, Name damageType, int flags )
{
double factor = amount*.01;
return int(ceil(damage*factor));
}
}
Class ArmorNuggetItem : SWWMSpareArmor
{
override Inventory CreateCopy( Actor other )
{
// additional lore
SWWMLoreLibrary.Add(other.player,"Nugget");
return Super.CreateCopy(other);
}
Default
{
Tag "$T_NUGGETA";
Stamina 300;
Inventory.Icon "graphics/HUD/Icons/I_ArmorNugget.png";
Inventory.PickupMessage "$T_NUGGETA";
Inventory.MaxAmount 20;
Inventory.InterHubAmount 20;
Inventory.UseSound "misc/armor_pkup";
SWWMSpareArmor.GiveArmor "ArmorNugget";
+INVENTORY.ALWAYSPICKUP;
Radius 4;
Height 22;
}
States
{
Spawn:
XZW1 # -1 NoDelay
{
frame = Random[Nugget](0,7);
}
Stop;
Dummy:
XZW1 ABCDEFGH -1;
Stop;
}
}
Class ArmorNuggetBundleSpawn : 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("ArmorNuggetItem",Vec3Angle(8,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 BlastSuit : SWWMArmor
{
Default
{
Inventory.Icon "graphics/HUD/Icons/I_BlastSuit.png";
Inventory.Amount 150;
Inventory.MaxAmount 150;
Inventory.InterHubAmount 150;
SWWMArmor.ArmorPriority 2;
SWWMArmor.DrainMessage "$D_BLASTSUIT";
SWWMArmor.GiverArmor "BlastSuitItem";
}
override int HandleDamage( int damage, Name damageType, int flags )
{
double factor = .3;
if ( flags&DMG_EXPLOSION ) factor = 1.-(1.-factor)*.5;
return int(ceil(damage*factor));
}
}
Class BlastSuitItem : SWWMSpareArmor
{
override Inventory CreateCopy( Actor other )
{
// additional lore
SWWMLoreLibrary.Add(other.player,"BlastSuit");
return Super.CreateCopy(other);
}
Default
{
Tag "$T_BLASTSUIT";
Stamina 40000;
Inventory.Icon "graphics/HUD/Icons/I_BlastSuit.png";
Inventory.PickupMessage "$T_BLASTSUIT";
Inventory.UseSound "armor/blastsuit";
SWWMSpareArmor.GiveArmor "BlastSuit";
Radius 12;
Height 30;
}
States
{
Spawn:
XZW1 A -1;
Stop;
}
}
Class WarArmor : SWWMArmor
{
Default
{
Inventory.Icon "graphics/HUD/Icons/I_WarArmor.png";
Inventory.Amount 250;
Inventory.MaxAmount 250;
Inventory.InterHubAmount 250;
SWWMArmor.ArmorPriority 6;
SWWMArmor.DrainMessage "$D_WARARMOR";
SWWMArmor.GiverArmor "WarArmorItem";
}
override int HandleDamage( int damage, Name damageType, int flags )
{
double factor;
// should be enough "elemental" damage types I guess
if ( (damageType == 'Fire') || (damageType == 'Ice') || (damageType == 'Slime') || (damageType == 'Electric') || (damageType == 'Wind') || (damageType == 'Water') || (damageType == 'Corroded') || (damageType == 'Lava') ) factor = .8;
else factor = .5;
if ( flags&DMG_EXPLOSION ) factor = 1.-(1.-factor)*.7;
return int(ceil(damage*factor));
}
}
Class WarArmorItem : SWWMSpareArmor
{
override Inventory CreateCopy( Actor other )
{
// additional lore
SWWMLoreLibrary.Add(other.player,"WarArmor");
return Super.CreateCopy(other);
}
Default
{
Tag "$T_WARARMOR";
Stamina 100000;
Inventory.Icon "graphics/HUD/Icons/I_WarArmor.png";
Inventory.PickupMessage "$T_WARARMOR";
Inventory.UseSound "armor/wararmor";
SWWMSpareArmor.GiveArmor "WarArmor";
Radius 16;
Height 32;
}
States
{
Spawn:
XZW1 A -1;
Stop;
}
}

View file

@ -0,0 +1,377 @@
// Common code for ammo division
Mixin Class SWWMAmmo
{
private Inventory DoDrop( Class<Inventory> type )
{
let copy = Inventory(Spawn(type,Owner.Pos,NO_REPLACE));
if ( !copy ) return null;
copy.DropTime = 30;
copy.bSpecial = copy.bSolid = false;
copy.SetOrigin(Owner.Vec3Offset(0,0,10.),false);
copy.Angle = Owner.Angle;
copy.VelFromAngle(5.);
copy.Vel.Z = 1.;
copy.Vel += Owner.Vel;
copy.bNoGravity = false;
copy.ClearCounters();
copy.OnDrop(Owner);
copy.vel += (RotateVector((FRandom[Junk](-1.5,.5),FRandom[Junk](-2.5,2.5)),Owner.angle),FRandom[Junk](2.,5.));
return copy;
}
override bool SpecialDropAction( Actor dropper )
{
if ( swwm_enemydrops >= 0 )
{
if ( Amount == default.Amount ) return false;
// subdivide
Owner = dropper; // needed for positioning to work
CreateTossable(Amount);
return true;
}
// no ammo drops from enemies
return true;
}
private bool CmpAmmo( Class<Ammo> a, Class<Ammo> b )
{
let amta = GetDefaultByType(a).Amount;
let amtb = GetDefaultByType(b).Amount;
return (amta < amtb);
}
private int partition_ammotypes( Array<Class<Ammo> > a, int l, int h )
{
Class<Ammo> pv = a[h];
int i = (l-1);
for ( int j=l; j<=(h-1); j++ )
{
if ( CmpAmmo(pv,a[j]) )
{
i++;
Class<Ammo> tmp = a[j];
a[j] = a[i];
a[i] = tmp;
}
}
Class<Ammo> tmp = a[h];
a[h] = a[i+1];
a[i+1] = tmp;
return i+1;
}
private void qsort_ammotypes( Array<Class<Ammo> > a, int l, int h )
{
if ( l >= h ) return;
int p = partition_ammotypes(a,l,h);
qsort_ammotypes(a,l,p-1);
qsort_ammotypes(a,p+1,h);
}
override inventory CreateTossable( int amt )
{
if ( bUndroppable || bUntossable || !Owner || (Amount <= 0) || (amt == 0) )
return null;
// cap
amt = min(amount,amt);
// enumerate all subclasses
Array<Class<Ammo> > ammotypes;
ammotypes.Clear();
for ( int i=0; i<AllActorClasses.Size(); i++ )
{
if ( AllActorClasses[i] is GetParentAmmo() )
ammotypes.Push((Class<Ammo>)(AllActorClasses[i]));
}
// sort from largest to smallest
qsort_ammotypes(ammotypes,0,ammotypes.Size()-1);
// perform subdivision
Inventory last = null;
while ( amt > 0 )
{
for ( int i=0; i<ammotypes.Size(); i++ )
{
let def = GetDefaultByType(ammotypes[i]);
if ( amt >= def.Amount )
{
last = DoDrop(ammotypes[i]);
amt -= def.Amount;
Amount -= def.Amount;
break;
}
}
}
return last;
}
override bool HandlePickup( Inventory item )
{
// drop excess ammo
if ( (item is 'Ammo') && (Ammo(item).GetParentAmmo() == GetParentAmmo()) )
{
int excess = Amount+item.Amount;
if ( excess > MaxAmount ) excess -= MaxAmount;
if ( excess < item.Amount )
{
// enumerate all subclasses
Array<Class<Ammo> > ammotypes;
ammotypes.Clear();
for ( int i=0; i<AllActorClasses.Size(); i++ )
{
if ( AllActorClasses[i] is GetParentAmmo() )
ammotypes.Push((Class<Ammo>)(AllActorClasses[i]));
}
// sort from largest to smallest
for ( int i=0; i<ammotypes.Size(); i++ )
{
int j = 1;
while ( j < ammotypes.Size() )
{
int k = j;
while ( (k > 0) && CmpAmmo(ammotypes[k-1],ammotypes[k]) )
{
Class<Ammo> tmp = ammotypes[k];
ammotypes[k] = ammotypes[k-1];
ammotypes[k-1] = tmp;
k--;
}
j++;
}
}
// drop spares
Inventory last;
while ( excess > 0 )
{
for ( int i=0; i<ammotypes.Size(); i++ )
{
let def = GetDefaultByType(ammotypes[i]);
if ( excess >= def.Amount )
{
double ang = FRandom[Junk](0,360);
last = DoDrop(ammotypes[i]);
last.SetOrigin(item.pos,false);
last.vel.xy = (cos(ang),sin(ang))*FRandom[Junk](2,5);
excess -= def.Amount;
break;
}
}
}
}
}
return Super.HandlePickup(item);
}
override void DoEffect()
{
Super.DoEffect();
// drop excess ammo
if ( !sv_infiniteammo && !Owner.FindInventory('PowerInfiniteAmmo') )
{
int excess = Amount-MaxAmount;
if ( excess > 0 ) CreateTossable(excess);
}
}
default
{
+INVENTORY.IGNORESKILL;
Inventory.PickupFlash "SWWMPickupFlash";
}
}
// Common code for individual bullets
Class MagAmmo : Inventory abstract
{
Mixin SWWMOverlapPickupSound;
Mixin SWWMUseToPickup;
Class<Ammo> ParentAmmo;
Ammo pamo;
int ClipSize;
int countdown;
Property ParentAmmo : ParentAmmo;
Property ClipSize : ClipSize;
default
{
+INVENTORY.KEEPDEPLETED;
Inventory.PickupSound "misc/bullet_pkup";
Inventory.Amount 1;
Inventory.PickupFlash "SWWMPickupFlash";
}
override bool HandlePickup( Inventory item )
{
// see if the mag can be split apart
if ( (item is 'Ammo') && (ParentAmmo == Ammo(item).GetParentAmmo()) )
{
// double-check that parent ammo exists
if ( !pamo )
{
pamo = Ammo(Owner.FindInventory(ParentAmmo));
if ( !pamo )
{
pamo = Ammo(Spawn(ParentAmmo));
pamo.AttachToOwner(Owner);
pamo.Amount = 0;
}
}
if ( (pamo.Amount >= pamo.MaxAmount) && (Amount < MaxAmount) )
{
// split
for ( int i=0; i<item.Amount; i++ )
{
int bul = ClipSize;
int maxgiveamt = min(MaxAmount-Amount,bul);
int dropamt = bul-maxgiveamt;
if ( dropamt > 0 ) CreateTossable(dropamt);
Amount = min(MaxAmount,Amount+bul);
}
item.bPickupGood = true;
return true;
}
}
return Super.HandlePickup(item);
}
private Inventory DoDrop( Class<Inventory> type )
{
let copy = Inventory(Spawn(type,Owner.Pos,NO_REPLACE));
if ( !copy ) return null;
copy.DropTime = 30;
copy.bSpecial = copy.bSolid = false;
copy.SetOrigin(Owner.Vec3Offset(0,0,10.),false);
copy.Angle = Owner.Angle;
copy.VelFromAngle(5.);
copy.Vel.Z = 1.;
copy.Vel += Owner.Vel;
copy.bNoGravity = false;
copy.ClearCounters();
copy.OnDrop(Owner);
copy.vel += (RotateVector((FRandom[Junk](-1.5,.5),FRandom[Junk](-2.5,2.5)),Owner.angle),FRandom[Junk](2.,5.));
return copy;
}
override bool SpecialDropAction( Actor dropper )
{
if ( swwm_enemydrops >= 0 )
{
if ( Amount == default.Amount ) return false;
// subdivide
Owner = dropper; // needed for positioning to work
CreateTossable(Amount);
return true;
}
// no ammo drops from enemies
return true;
}
override void DoEffect()
{
Super.DoEffect();
// drop excess ammo
if ( !sv_infiniteammo && !Owner.FindInventory('PowerInfiniteAmmo') )
{
int excess = Amount-MaxAmount;
if ( excess > 0 ) CreateTossable(excess);
}
if ( !pamo )
{
pamo = Ammo(Owner.FindInventory(ParentAmmo));
if ( !pamo )
{
pamo = Ammo(Spawn(ParentAmmo));
pamo.AttachToOwner(Owner);
pamo.Amount = 0;
}
}
// check if we can fill a mag (delayed)
if ( (Amount < ClipSize) || (pamo.Amount >= pamo.MaxAmount) )
{
countdown = 35;
return;
}
if ( countdown-- > 0 ) return;
MagFill();
}
bool MagFill()
{
// double-check that parent ammo exists
if ( !pamo )
{
pamo = Ammo(Owner.FindInventory(ParentAmmo));
if ( !pamo )
{
pamo = Ammo(Spawn(ParentAmmo));
pamo.AttachToOwner(Owner);
pamo.Amount = 0;
}
}
bool given = false;
while ( (pamo.Amount < pamo.MaxAmount) && (Amount >= ClipSize) )
{
pamo.Amount++;
Amount -= ClipSize;
given = true;
if ( Owner.CheckLocalView() )
pamo.PrintPickupMessage(true,pamo.PickupMessage());
}
if ( given ) pamo.PlayPickupSound(Owner);
return given;
}
override inventory CreateTossable( int amt )
{
if ( bUndroppable || bUntossable || !Owner || (Amount <= 0) || (amt == 0) )
return null;
// cap
amt = min(amount,amt);
// perform subdivision
Inventory last = null;
let pammo = GetDefaultByType(ParentAmmo);
while ( amt > 0 )
{
// drop full mag if possible
if ( amt >= ClipSize )
{
last = DoDrop(ParentAmmo);
amt -= ClipSize;
Amount -= ClipSize;
continue;
}
// drop individual bullets
last = DoDrop(GetClass());
amt--;
Amount--;
}
return last;
}
override void ModifyDropAmount( int dropamount )
{
Super.ModifyDropAmount(dropamount);
Amount = min(Random[ShellDrop](1,ClipSize),Amount);
}
}
// Common code for grouped shell handling and per-amount pickup messages
Mixin Class SWWMShellAmmo
{
override string PickupMessage()
{
String tagstr = "$T_"..GetParentAmmo().GetClassName();
tagstr.MakeUpper();
if ( Amount > 1 )
{
tagstr = tagstr.."S";
return String.Format("%d %s",Amount,StringTable.Localize(tagstr));
}
return StringTable.Localize(tagstr);
}
override void ModifyDropAmount( int dropamount )
{
Super.ModifyDropAmount(dropamount);
Amount = max(1,Amount+Random[ShellDrop](-2,1));
}
}

View file

@ -0,0 +1,185 @@
// Base class for all SWWM Armors
Class SWWMArmor : Armor abstract
{
int priority;
String drainmsg;
Class<SWWMSpareArmor> parent;
Property ArmorPriority : priority;
Property DrainMessage : drainmsg;
Property GiverArmor : parent;
Default
{
+INVENTORY.AUTOACTIVATE;
+INVENTORY.UNTOSSABLE;
+INVENTORY.UNDROPPABLE;
+INVENTORY.KEEPDEPLETED;
+INVENTORY.ALWAYSPICKUP;
}
override void AttachToOwner( Actor other )
{
Super.AttachToOwner(other);
// find last armor that's better than us
Inventory found = null;
for ( Inventory i=other.Inv; i; i=i.Inv )
{
if ( !(i is 'SWWMArmor') || (i == self) || (SWWMArmor(i).priority < priority) ) continue;
found = i;
}
if ( !found )
{
// find first item with an armor worse than us after it
for ( Inventory i=other.Inv; i; i=i.Inv )
{
if ( (i == self) || !(i.Inv is 'SWWMArmor') ) continue;
if ( SWWMArmor(i.Inv).priority > priority ) continue;
found = i;
break;
}
}
if ( !found )
{
// is first item plating or a collar?
if ( (other.Inv is 'AlmasteelPlating') || (other.Inv is 'SayaCollar') )
{
// we're good
return;
}
// find first item with plating or collar after it
for ( Inventory i=other.Inv; i; i=i.Inv )
{
if ( (i == self) || (!(i.Inv is 'AlmasteelPlating' ) && !(i.Inv is 'SayaCollar')) ) continue;
found = i;
break;
}
}
if ( !found )
{
// check if first item in inventory is health or a sandwich
if ( (other.Inv is 'SWWMHealth') || (other.Inv is 'GrilledCheeseSandwich') )
{
// we're good
return;
}
// find first item with health or sandwich after it
for ( Inventory i=other.Inv; i; i=i.Inv )
{
if ( (i == self) || (!(i.Inv is 'SWWMHealth' ) && !(i.Inv is 'GrilledCheeseSandwich')) ) continue;
found = i;
break;
}
}
if ( !found )
{
// find last of either invinciball/ragekit/barrier power
for ( Inventory i=other.Inv; i; i=i.Inv )
{
if ( !(i is 'InvinciballPower') && !(i is 'RagekitPower') && !(i is 'BarrierPower') ) continue;
found = i;
}
}
if ( !found ) return;
// place ourselves right after it
Inventory saved = found.Inv;
found.Inv = self;
other.Inv = Inv;
Inv = saved;
}
// for subclasses
virtual int HandleDamage( int damage, Name damageType, int flags )
{
return damage;
}
override void AbsorbDamage( int damage, Name damageType, out int newdamage, Actor inflictor, Actor source, int flags )
{
int saved;
if ( (amount <= 0) || DamageTypeDefinition.IgnoreArmor(damageType) || (damage <= 0) )
return;
SWWMHandler.DoFlash(Owner,Color(int(clamp(damage*.15,1,16)),255,224,192),3);
Owner.A_StartSound("armor/hit",CHAN_BODY,CHANF_DEFAULT,clamp(damage*.03,0.,1.),2.5);
saved = HandleDamage(damage,damageType,flags);
int healed = max(0,saved-damage);
saved = min(saved,damage);
if ( amount <= saved ) saved = amount;
newdamage -= saved;
if ( healed > 0 ) Owner.GiveBody(healed);
if ( (swwm_strictuntouchable == 1) && (saved > 0) && Owner.player )
{
let hnd = SWWMHandler(EventHandler.Find("SWWMHandler"));
if ( hnd ) hnd.tookdamage[Owner.PlayerNumber()] = true;
}
amount -= saved;
damage = newdamage;
bool shouldautouse = false;
if ( swwm_enforceautousearmor == 1 ) shouldautouse = true;
else if ( swwm_enforceautousearmor == -1 ) shouldautouse = false;
else shouldautouse = CVar.GetCVar('swwm_autousearmor',Owner.player).GetBool();
if ( (amount <= (MaxAmount-default.Amount)) && (Owner.CountInv(parent) > 0) && shouldautouse )
{
if ( GetDefaultByType(parent).UseSound ) Owner.A_StartSound(GetDefaultByType(parent).UseSound,CHAN_ITEMEXTRA,CHANF_DEFAULT,.6);
int tgive = 0;
while ( (amount <= (MaxAmount-default.Amount)) && (Owner.CountInv(parent) > 0) )
{
if ( swwm_accdamage ) tgive += default.Amount;
else SWWMScoreObj.Spawn(default.Amount,Owner.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+Owner.Height/2),ST_Armor);
Amount += default.Amount;
Owner.TakeInventory(parent,1);
// absorb the extra damage too
saved = HandleDamage(damage,damageType,flags);
healed = max(0,saved-damage);
saved = min(saved,damage);
if ( amount <= saved ) saved = amount;
newdamage -= saved;
if ( healed > 0 ) Owner.GiveBody(healed);
amount -= saved;
damage = newdamage;
}
if ( swwm_accdamage ) SWWMScoreObj.Spawn(tgive,Owner.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+Owner.Height/2),ST_Armor);
}
else if ( amount <= 0 )
{
if ( Owner.CheckLocalView() && (drainmsg != "") ) Console.Printf(StringTable.Localize(drainmsg));
DepleteOrDestroy();
return;
}
}
}
// gives armor when used
Class SWWMSpareArmor : Inventory abstract
{
Mixin SWWMAutoUseFix;
Mixin SWWMUseToPickup;
Mixin SWWMOverlapPickupSound;
Class<SWWMArmor> giveme;
Property GiveArmor : giveme;
override bool Use( bool pickup )
{
let cur = Owner.FindInventory(giveme);
if ( !cur || (!pickup && (cur.Amount < cur.MaxAmount)) || (GetDefaultByType(giveme).Amount+cur.Amount <= cur.MaxAmount) )
{
if ( pickup && ((Owner.player == players[consoleplayer]) || bBigPowerup) ) Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA);
Owner.GiveInventory(giveme,GetDefaultByType(giveme).Amount);
SWWMHandler.ArmorFlash(Owner.PlayerNumber());
SWWMScoreObj.Spawn(GetDefaultByType(giveme).Amount,Owner.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+Owner.Height/2),ST_Armor);
return true;
}
return false;
}
Default
{
+INVENTORY.INVBAR;
+INVENTORY.ISARMOR;
+INVENTORY.AUTOACTIVATE;
Inventory.MaxAmount 5;
Inventory.InterHubAmount 5;
Inventory.PickupFlash "SWWMGreenPickupFlash";
+FLOATBOB;
FloatBobStrength 0.25;
}
}

View file

@ -0,0 +1,160 @@
// Base class for all SWWM Health
Class SWWMHealth : Inventory abstract
{
Mixin SWWMAutoUseFix;
Mixin SWWMUseToPickup;
Mixin SWWMOverlapPickupSound;
// can't use the Health class for whatever reason
// nice parser you got there I guess?
Class<Inventory> giveme;
Property GiveHealth : giveme;
override void AttachToOwner( Actor other )
{
Super.AttachToOwner(other);
// find last health item that's better than us
Inventory found = null;
for ( Inventory i=other.Inv; i; i=i.Inv )
{
if ( !(i is 'SWWMHealth') || (i == self) || (GetDefaultByType(SWWMHealth(i).giveme).Amount < GetDefaultByType(giveme).Amount) ) continue;
found = i;
}
if ( !found )
{
// find first item with health that's worse than us after it
for ( Inventory i=other.Inv; i; i=i.Inv )
{
if ( (i == self) || !(i.Inv is 'SWWMHealth') ) continue;
if ( GetDefaultByType(SWWMHealth(i.Inv).giveme).Amount > GetDefaultByType(giveme).Amount ) continue;
found = i;
break;
}
}
if ( !found )
{
// find last armor item, plating or collar
for ( Inventory i=other.Inv; i; i=i.Inv )
{
if ( !(i is 'SWWMArmor') && !(i is 'AlmasteelPlating') && !(i is 'SayaCollar') ) continue;
found = i;
}
}
if ( !found )
{
// check if the first item in inventory is a sandwich
if ( other.Inv is 'GrilledCheeseSandwich' )
{
// we're good
return;
}
// find first item next to a sandwich
for ( Inventory i=other.Inv; i; i=i.Inv )
{
if ( (i == self) || !(i.Inv is 'GrilledCheeseSandwich') ) continue;
found = i;
break;
}
}
if ( !found )
{
// find last of either invinciball/ragekit/barrier power
for ( Inventory i=other.Inv; i; i=i.Inv )
{
if ( !(i is 'InvinciballPower') && !(i is 'RagekitPower') && !(i is 'BarrierPower') ) continue;
found = i;
}
}
if ( !found ) return;
// place ourselves right after it
Inventory saved = found.Inv;
found.Inv = self;
other.Inv = Inv;
Inv = saved;
}
override bool Use( bool pickup )
{
if ( Owner.Health >= GetDefaultByType(giveme).MaxAmount ) return false;
// healing items won't get auto-used on pickup if their healing could "be wasted", unless they're powerup health (e.g. Refresher)
if ( pickup && !bBIGPOWERUP && (Owner.Health+GetDefaultByType(giveme).Amount > GetDefaultByType(giveme).MaxAmount) ) return false;
if ( pickup && ((Owner.player == players[consoleplayer]) || bBigPowerup) ) Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA);
SWWMHandler.HealthFlash(Owner.PlayerNumber());
Owner.GiveInventory(giveme,GetDefaultByType(giveme).Amount);
SWWMScoreObj.Spawn(GetDefaultByType(giveme).Amount,Owner.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+Owner.Height/2),ST_Health);
AutoUseExtra(false);
return true;
}
// additional effects when automatically used
// recursive: if true, the auto-use was called on another copy of the
// item in a "stacked" heal. can be used to prevent certain
// effects from happening multiple times in one go
virtual void AutoUseExtra( bool recursive )
{
}
override void DoEffect()
{
Super.DoEffect();
if ( Amount <= 0 ) DepleteOrDestroy();
}
override void AbsorbDamage( int damage, Name damageType, out int newdamage, Actor inflictor, Actor source, int flags )
{
if ( Owner.ApplyDamageFactor(damageType,damage) <= 0 )
return; // this damage type is ignored by the player, so it does not affect us
if ( damageType == 'EndLevel' )
return; // don't trigger on endlevel damage
bool shouldautouse = false;
if ( swwm_enforceautousehealth == 1 ) shouldautouse = true;
else if ( swwm_enforceautousehealth == -1 ) shouldautouse = false;
else shouldautouse = CVar.GetCVar('swwm_autousehealth',Owner.player).GetBool();
if ( !shouldautouse && !bBIGPOWERUP ) return; // powerup health is always auto-used
if ( (Owner.Health-damage <= (GetDefaultByType(giveme).MaxAmount-GetDefaultByType(giveme).Amount)) )
{
newdamage = damage;
// lesser healing items can't prevent lethal damage
// bigger healing items only autoactivate on lethal damage
if ( !bBIGPOWERUP && (Owner.Health-damage <= 0) )
return;
else if ( bBIGPOWERUP && (Owner.Health-damage > 0) )
return;
if ( (swwm_strictuntouchable == 1) && Owner.player )
{
let hnd = SWWMHandler(EventHandler.Find("SWWMHandler"));
if ( hnd ) hnd.tookdamage[Owner.PlayerNumber()] = true;
}
if ( ((Owner.player == players[consoleplayer]) || bBigPowerup) ) Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA);
int tgive = 0;
bool morethanonce = false;
while ( (Amount > 0) && (newdamage > 0) )
{
if ( swwm_accdamage ) tgive += GetDefaultByType(giveme).Amount;
else SWWMScoreObj.Spawn(GetDefaultByType(giveme).Amount,Owner.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+Owner.Height/2),ST_Health);
newdamage = newdamage-GetDefaultByType(giveme).Amount;
if ( newdamage < 0 ) Owner.GiveBody(-newdamage,GetDefaultByType(giveme).MaxAmount);
newdamage = max(0,newdamage);
AutoUseExtra(morethanonce);
morethanonce = true;
Amount--;
}
if ( swwm_accdamage ) SWWMScoreObj.Spawn(tgive,Owner.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+Owner.Height/2),ST_Health);
}
else newdamage = damage;
}
Default
{
+INVENTORY.INVBAR;
+INVENTORY.ISHEALTH;
+INVENTORY.AUTOACTIVATE;
Inventory.MaxAmount 5;
Inventory.InterHubAmount 5;
Inventory.UseSound "misc/health_pkup";
Inventory.PickupFlash "SWWMBluePickupFlash";
+FLOATBOB;
FloatBobStrength 0.25;
}
}

View file

@ -0,0 +1,88 @@
// Inventory stuff
Mixin Class SWWMAutoUseFix
{
override bool HandlePickup( Inventory item )
{
if ( GetClass() == item.GetClass() )
{
if ( Use(true) ) Amount--;
// sell excess if there's a price
if ( bALWAYSPICKUP && (Amount+item.Amount > MaxAmount) && (Stamina != 0) )
{
int sellprice = int(abs(Stamina)*.5);
SWWMScoreObj.Spawn(sellprice,Owner.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+Owner.Height/2));
SWWMCredits.Give(Owner.player,sellprice);
if ( Owner.player )
Console.Printf(StringTable.Localize(SWWMUtility.SellFemaleItem(item)?"$SWWM_SELLEXTRA_FEM":"$SWWM_SELLEXTRA"),Owner.player.GetUserName(),GetTag(),sellprice);
}
}
return Super.HandlePickup(item);
}
}
Class CrossLineFinder : LineTracer
{
Array<Line> clines;
Array<int> csides;
override ETraceStatus TraceCallback()
{
if ( (Results.HitType == TRACE_HitWall) && (Results.HitLine.activation&SPAC_Cross) )
{
clines.Push(Results.HitLine);
csides.Push(Results.Side);
}
return TRACE_Skip;
}
}
Mixin Class SWWMUseToPickup
{
// allow pickup by use
override bool Used( Actor user )
{
Vector3 itempos = Vec3Offset(0,0,Height/2),
userpos = user.Vec2OffsetZ(0,0,user.player.viewz);
// test vertical range
Vector3 diff = level.Vec3Diff(user.Vec3Offset(0,0,user.Height/2),Vec3Offset(0,0,Height/2));
double rang = user.player?PlayerPawn(user.player.mo).UseRange:(user.Height/2);
if ( abs(diff.z) > rang ) return false;
Touch(user);
// we got picked up
if ( bDestroyed || Owner || !bSPECIAL )
{
Vector3 tracedir = level.Vec3Diff(userpos,itempos);
double dist = tracedir.length();
tracedir /= dist;
let cf = new("CrossLineFinder");
cf.Trace(userpos,level.PointInSector(userpos.xy),tracedir,dist,0);
// trigger all player cross lines found between user and item
for ( int i=0; i<cf.clines.Size(); i++ )
cf.clines[i].Activate(user,cf.csides[i],SPAC_Cross);
return true;
}
return false;
}
}
Mixin Class SWWMOverlapPickupSound
{
// overlap sounds
override void PlayPickupSound( Actor toucher )
{
let hnd = SWWMHandler(EventHandler.Find("SWWMHandler"));
if ( hnd )
{
if ( hnd.lastpickuptic[toucher.PlayerNumber()] == gametic )
return; // don't play if picked up on the same exact tic (overlapping items)
hnd.lastpickuptic[toucher.PlayerNumber()] = gametic;
}
double atten;
int flags = CHANF_OVERLAP|CHANF_MAYBE_LOCAL;
if ( bNoAttenPickupSound ) atten = ATTN_NONE;
else atten = ATTN_NORM;
if ( toucher && toucher.CheckLocalView() )
flags |= CHANF_NOPAUSE;
toucher.A_StartSound(PickupSound,CHAN_ITEM,flags,1.,atten);
}
}

View file

@ -0,0 +1,243 @@
// collectible items that may drop sometimes
Class SWWMCollectible : Inventory abstract
{
Mixin SWWMUseToPickup;
int avail;
bool propagated;
Class<SWWMItemGesture> gesture;
Property Availability : avail;
Property GestureWeapon : gesture;
// minimum gametype requirements
enum EAvailability
{
AVAIL_Strife = GAME_Strife,
AVAIL_Hexen = AVAIL_Strife|GAME_Hexen,
AVAIL_Heretic = AVAIL_Hexen|GAME_Heretic,
AVAIL_All = AVAIL_Heretic|GAME_DoomChex
};
Default
{
Inventory.PickupSound "menu/buyinv";
Inventory.Amount 1;
Inventory.MaxAmount 1;
Inventory.PickupFlash "SWWMCyanPickupFlash";
SWWMCollectible.Availability AVAIL_All;
+INVENTORY.UNTOSSABLE;
+INVENTORY.UNDROPPABLE;
+INVENTORY.UNCLEARABLE;
+INVENTORY.AUTOACTIVATE;
+FLOATBOB;
FloatBobStrength 0.25;
Radius 8;
Height 24;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
// delet ourselves if wrong iwad
if ( !(gameinfo.gametype&avail) )
Destroy();
}
override bool CanPickup( Actor toucher )
{
// no pickup if wrong iwad
if ( !(gameinfo.gametype&avail) ) return false;
return Super.CanPickup(toucher);
}
override string PickupMessage()
{
if ( Stamina > 0 )
return StringTable.Localize(PickupMsg)..String.Format(" \cj(\cg¥\cf%d\cj)\c-",Stamina);
return Super.PickupMessage();
}
override bool Use( bool pickup )
{
if ( Owner.player && !propagated )
{
if ( pickup && CVar.GetCVar('swwm_collectanim',Owner.player).GetBool() )
SWWMGesture.SetSpecialGesture(Owner.player.mo,gesture);
else if ( !pickup )
SWWMGesture.SetSpecialGesture(Owner.player.mo,gesture,true);
}
// clean up the flag
propagated = false;
return false;
}
override void AttachToOwner( Actor other )
{
Super.AttachToOwner(other);
// we're only attaching to the other players
if ( propagated )
return;
// give credit
if ( other.player && (Stamina > 0) )
{
SWWMScoreObj.Spawn(Stamina,other.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+other.Height/2));
SWWMCredits.Give(other.player,Stamina);
}
// send to all other players
for ( int i=0; i<MAXPLAYERS; i++ )
{
if ( !playeringame[i] || !players[i].mo || (i == other.PlayerNumber()) )
continue;
let c = SWWMCollectible(Spawn(GetClass(),pos));
c.propagated = true;
if ( !c.CallTryPickup(players[i].mo) )
c.Destroy();
}
}
States
{
Spawn:
XZW1 A -1;
Stop;
}
}
// The collectibles
Class GenericCube : SWWMCollectible
{
Default
{
Tag "$T_PERFECTLYGENERIC";
Inventory.PickupMessage "$T_PERFECTLYGENERIC";
SWWMCollectible.GestureWeapon "GenericCubeGesture";
Stamina 1000;
}
}
Class AkariProject : SWWMCollectible
{
Default
{
Tag "$T_AKARIPROJECT";
Inventory.PickupMessage "$T_AKARIPROJECT";
SWWMCollectible.GestureWeapon "AkariProjectGesture";
Stamina 2000;
Radius 4;
Height 22;
}
}
Class LoveSignalsCD : SWWMCollectible
{
Default
{
Tag "$T_LOVESIGNALS";
Inventory.PickupMessage "$T_LOVESIGNALS";
SWWMCollectible.GestureWeapon "LoveSignalsCDGesture";
Stamina 3000;
Radius 4;
Height 21;
}
}
Class NutatcoBar : SWWMCollectible
{
Default
{
Tag "$T_NUTATCO";
Inventory.PickupMessage "$T_NUTATCO";
SWWMCollectible.GestureWeapon "NutatcoBarGesture";
Stamina 200;
Radius 3;
Height 22;
}
}
Class FrispyCorn : SWWMCollectible
{
Default
{
Tag "$T_FRISPYCORN";
Inventory.PickupMessage "$T_FRISPYCORN";
SWWMCollectible.GestureWeapon "FrispyCornGesture";
Stamina 400;
Radius 5;
Height 23;
}
}
Class SayaBean : SWWMCollectible
{
bool callout; // already called the player a perv for loading h-doom
Default
{
Tag "$T_SAYABEAN";
Inventory.PickupMessage "$T_SAYABEAN";
SWWMCollectible.GestureWeapon "SayaBeanGesture";
Stamina 5000;
Radius 6;
Height 23;
}
}
// Heretic
Class DemoPlush : SWWMCollectible
{
Default
{
Tag "$T_DEMOPLUSH";
Inventory.PickupMessage "$T_DEMOPLUSH";
SWWMCollectible.Availability AVAIL_Heretic;
SWWMCollectible.GestureWeapon "DemoPlushGesture";
Stamina 6000;
Radius 12;
Height 36;
}
}
// Hexen
Class KirinCummies : SWWMCollectible
{
Default
{
Tag "$T_PEACH";
Inventory.PickupMessage "$T_PEACH";
SWWMCollectible.Availability AVAIL_Hexen;
SWWMCollectible.GestureWeapon "KirinCummiesGesture";
Stamina 300;
Radius 3;
Height 21;
}
}
Class MilkBreads : SWWMCollectible
{
Default
{
Tag "$T_MILKBREAD";
Inventory.PickupMessage "$T_MILKBREAD";
SWWMCollectible.Availability AVAIL_Hexen;
SWWMCollectible.GestureWeapon "MilkBreadsGesture";
Stamina 900;
Radius 4;
Height 21;
}
}
Class KirinManga : SWWMCollectible
{
Default
{
Tag "$T_KIRINMANGA";
Inventory.PickupMessage "$T_KIRINMANGA";
SWWMCollectible.Availability AVAIL_Hexen;
SWWMCollectible.GestureWeapon "KirinMangaGesture";
Stamina 1600;
Radius 4;
Height 22;
}
}
Class KirinPlush : SWWMCollectible
{
Default
{
Tag "$T_KIRINPLUSH";
Inventory.PickupMessage "$T_KIRINPLUSH";
SWWMCollectible.Availability AVAIL_Hexen;
SWWMCollectible.GestureWeapon "KirinPlushGesture";
Stamina 8000;
Radius 14;
Height 37;
}
}

View file

@ -0,0 +1,12 @@
// TODO them gestures
Class GenericCubeGesture : SWWMItemGesture {}
Class AkariProjectGesture : SWWMItemGesture {}
Class LoveSignalsCDGesture : SWWMItemGesture {}
Class NutatcoBarGesture : SWWMItemGesture {}
Class FrispyCornGesture : SWWMItemGesture {}
Class DemoPlushGesture : SWWMItemGesture {}
Class SayaBeanGesture : SWWMItemGesture {}
Class KirinCummiesGesture : SWWMItemGesture {}
Class MilkBreadsGesture : SWWMItemGesture {}
Class KirinMangaGesture : SWWMItemGesture {}
Class KirinPlushGesture : SWWMItemGesture {}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,222 @@
// all the healing items go here
Class HealthNugget : Health
{
Default
{
Inventory.Amount 1;
Inventory.MaxAmount 200;
}
}
Class TetraHealth : Health
{
Default
{
Inventory.Amount 10;
Inventory.MaxAmount 100;
}
}
Class CubeHealth : Health
{
Default
{
Inventory.Amount 20;
Inventory.MaxAmount 100;
}
}
Class RefresherHealth : Health
{
Default
{
Inventory.Amount 100;
Inventory.MaxAmount 500;
}
}
Class RefresherRegen : Powerup
{
Default
{
Inventory.Icon "graphics/HUD/Icons/I_Refresher.png";
Powerup.Duration -50;
Powerup.Strength 10;
+INVENTORY.ADDITIVETIME;
}
override void EndEffect()
{
Super.EndEffect();
if ( (EffectTics <= 0) && Owner && Owner.CheckLocalView() ) Console.Printf(StringTable.Localize("$D_REFRESHER"));
}
override void DoEffect()
{
Super.DoEffect();
if ( Owner && (Owner.health > 0) && !((EffectTics-5)%175) )
{
if ( Owner.GiveBody(int(Strength),500) )
{
SWWMScoreObj.Spawn(int(Strength),Owner.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+Owner.Height/2),ST_Health);
SWWMHandler.DoFlash(Owner,Color(32,224,128,255),10);
Owner.A_StartSound("powerup/refresher",CHAN_ITEM,CHANF_LOCAL,.4);
}
}
}
}
Class HealthNuggetItem : SWWMHealth
{
override Inventory CreateCopy( Actor other )
{
// additional lore
SWWMLoreLibrary.Add(other.player,"Nugget");
return Super.CreateCopy(other);
}
Default
{
Tag "$T_NUGGETH";
Stamina 200;
Inventory.Icon "graphics/HUD/Icons/I_HealthNugget.png";
Inventory.PickupMessage "$T_NUGGETH";
Inventory.MaxAmount 20;
Inventory.InterHubAmount 20;
SWWMHealth.GiveHealth "HealthNugget";
+INVENTORY.ALWAYSPICKUP;
Radius 4;
Height 22;
}
States
{
Spawn:
XZW1 # -1 NoDelay
{
frame = Random[Nugget](0,7);
}
Stop;
Dummy:
XZW1 ABCDEFGH -1;
Stop;
}
}
Class HealthNuggetBundleSpawn : 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("HealthNuggetItem",Vec3Angle(8,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 TetraHealthItem : SWWMHealth
{
override Inventory CreateCopy( Actor other )
{
// additional lore
SWWMLoreLibrary.Add(other.player,"HealthGeom");
return Super.CreateCopy(other);
}
Default
{
Tag "$T_TETRAHEALTH";
Stamina 3000;
Inventory.Icon "graphics/HUD/Icons/I_HealthTetra.png";
Inventory.PickupMessage "$T_TETRAHEALTH";
Inventory.MaxAmount 15;
Inventory.InterHubAmount 15;
SWWMHealth.GiveHealth "TetraHealth";
Radius 8;
Height 24;
}
States
{
Spawn:
XZW1 # -1;
Stop;
}
}
Class CubeHealthItem : SWWMHealth
{
override Inventory CreateCopy( Actor other )
{
// additional lore
SWWMLoreLibrary.Add(other.player,"HealthGeom");
return Super.CreateCopy(other);
}
Default
{
Tag "$T_CUBEHEALTH";
Stamina 8000;
Inventory.Icon "graphics/HUD/Icons/I_HealthCube.png";
Inventory.PickupMessage "$T_CUBEHEALTH";
Inventory.MaxAmount 10;
Inventory.InterHubAmount 10;
SWWMHealth.GiveHealth "CubeHealth";
Radius 8;
Height 24;
}
States
{
Spawn:
XZW1 # -1;
Stop;
}
}
Class RefresherItem : SWWMHealth
{
override Inventory CreateCopy( Actor other )
{
// additional lore
SWWMLoreLibrary.Add(other.player,"Refresher");
return Super.CreateCopy(other);
}
override void AutoUseExtra( bool recursive )
{
// regen effect doesn't stack if we autoactivated recursively
if ( recursive ) return;
let p = Powerup(Owner.FindInventory("RefresherRegen"));
if ( p ) p.EffectTics += p.default.EffectTics;
else Owner.GiveInventory("RefresherRegen",1);
SWWMHandler.DoFlash(Owner,Color(80,224,128,255),20);
}
override bool Use( bool pickup )
{
// never get auto-used on pickup unless we're in deathmatch
if ( pickup && !deathmatch ) return false;
return Super.Use(pickup);
}
Default
{
Tag "$T_REFRESHER";
Stamina 160000;
Inventory.Icon "graphics/HUD/Icons/I_Refresher.png";
Inventory.PickupMessage "$T_REFRESHER";
Inventory.PickupSound "misc/p_pkup";
Inventory.UseSound "powerup/refresheruse";
SWWMHealth.GiveHealth "RefresherHealth";
+COUNTITEM;
+INVENTORY.BIGPOWERUP;
+INVENTORY.ALWAYSPICKUP;
Radius 6;
Height 24;
}
States
{
Spawn:
XZW1 # -1;
Stop;
}
}

346
zscript/items/swwm_keys.zsc Normal file
View file

@ -0,0 +1,346 @@
// Key item replacements, including some for popular map packs
Class SWWMKey : Key abstract
{
Mixin SWWMOverlapPickupSound;
Mixin SWWMUseToPickup;
bool propagated;
Class<SWWMItemGesture> gesture;
Property GestureWeapon : gesture;
override void DoEffect()
{
Super.DoEffect();
if ( Icon.IsNull() )
{
// fetch icon from parent (if it exists)
Class<Key> pc = Species;
if ( !pc ) return;
let p = GetDefaultByType(pc);
Icon = p.Icon;
}
}
override void AttachToOwner( Actor other )
{
Super.AttachToOwner(other);
// also attach the vanilla key that we replace, mainly for script compatibility
Class<Key> pc = Species;
if ( pc )
{
let p = Inventory(Spawn(pc));
if ( Owner is 'Demolitionist' )
Demolitionist(Owner).key_reentrant = true; // avoid infinite loop
p.AttachToOwner(Owner);
if ( Owner is 'Demolitionist' )
Demolitionist(Owner).key_reentrant = false;
}
}
override bool Use( bool pickup )
{
if ( Owner.player && !propagated )
{
if ( pickup && CVar.GetCVar('swwm_collectanimkey',Owner.player).GetBool() )
SWWMGesture.SetSpecialGesture(Owner.player.mo,gesture);
else if ( !pickup )
SWWMGesture.SetSpecialGesture(Owner.player.mo,gesture,true);
}
// clean up the flag
propagated = false;
return false;
}
Default
{
+NOTDMATCH;
+FLOATBOB;
+INVENTORY.AUTOACTIVATE;
FloatBobStrength 0.25;
}
}
Class SWWMRedCard : SWWMKey
{
Default
{
Tag "$T_REDCARD";
Species "RedCard";
Inventory.PickupMessage "$T_REDCARD";
Inventory.PickupFlash "SWWMRedPickupFlash";
SWWMKey.GestureWeapon "SWWMRedCardGesture";
Radius 10;
Height 25;
}
States
{
Spawn:
XZW1 AB 10;
Loop;
}
}
Class SWWMYellowCard : SWWMKey
{
Default
{
Tag "$T_YELLOWCARD";
Species "YellowCard";
Inventory.PickupMessage "$T_YELLOWCARD";
Inventory.PickupFlash "SWWMPickupFlash";
SWWMKey.GestureWeapon "SWWMYellowCardGesture";
Radius 10;
Height 25;
}
States
{
Spawn:
XZW1 AB 10;
Loop;
}
}
Class SWWMBlueCard : SWWMKey
{
Default
{
Tag "$T_BLUECARD";
Species "BlueCard";
Inventory.PickupMessage "$T_BLUECARD";
Inventory.PickupFlash "SWWMBluePickupFlash";
SWWMKey.GestureWeapon "SWWMBlueCardGesture";
Radius 10;
Height 25;
}
States
{
Spawn:
XZW1 AB 10;
Loop;
}
}
Class SWWMSilverCardKDiZD : SWWMKey
{
Default
{
Tag "$T_SILVERCARD";
Species "BlueSkull";
Inventory.PickupMessage "$T_SILVERCARD";
Inventory.PickupFlash "SWWMWhitePickupFlash";
SWWMKey.GestureWeapon "SWWMSilverCardGesture";
Radius 10;
Height 25;
}
States
{
Spawn:
XZW1 AB 10;
Loop;
}
}
Class SWWMGreenCardKDiZD : SWWMKey
{
Default
{
Tag "$T_GREENCARD";
Species "YellowSkull";
Inventory.PickupMessage "$T_GREENCARD";
Inventory.PickupFlash "SWWMGreenPickupFlash";
SWWMKey.GestureWeapon "SWWMGreenCardGesture";
Radius 10;
Height 25;
}
States
{
Spawn:
XZW1 AB 10;
Loop;
}
}
Class SWWMOrangeCardKDiZD : SWWMKey
{
Default
{
Tag "$T_ORANGECARD";
Species "RedSkull";
Inventory.PickupMessage "$T_ORANGECARD";
Inventory.PickupFlash "SWWMPickupFlash";
SWWMKey.GestureWeapon "SWWMOrangeCardGesture";
Radius 10;
Height 25;
}
States
{
Spawn:
XZW1 AB 10;
Loop;
}
}
Class SWWMGreenCard : SWWMKey
{
Default
{
Tag "$T_GREENCARD";
Species "GreenCard";
Inventory.PickupMessage "$T_GREENCARD";
Inventory.PickupFlash "SWWMGreenPickupFlash";
SWWMKey.GestureWeapon "SWWMGreenCardGesture";
Radius 10;
Height 25;
}
States
{
Spawn:
XZW1 AB 10;
Loop;
}
}
// more Doom key color variants will be implemented as needed
Class SWWMRedSkull : SWWMKey
{
Default
{
Tag "$T_REDSKULL";
Species "RedSkull";
Inventory.PickupMessage "$T_REDSKULL";
Inventory.PickupFlash "SWWMRedPickupFlash";
SWWMKey.GestureWeapon "SWWMRedSkullGesture";
Radius 10;
Height 25;
}
States
{
Spawn:
XZW1 A -1;
Stop;
}
}
Class SWWMBlueSkull : SWWMKey
{
Default
{
Tag "$T_BLUESKULL";
Species "BlueSkull";
Inventory.PickupMessage "$T_BLUESKULL";
Inventory.PickupFlash "SWWMBluePickupFlash";
SWWMKey.GestureWeapon "SWWMBlueSkullGesture";
Radius 10;
Height 25;
}
States
{
Spawn:
XZW1 A -1;
Stop;
}
}
Class SWWMYellowSkull : SWWMKey
{
Default
{
Tag "$T_YELLOWSKULL";
Species "YellowSkull";
Inventory.PickupMessage "$T_YELLOWSKULL";
Inventory.PickupFlash "SWWMPickupFlash";
SWWMKey.GestureWeapon "SWWMYellowSkullGesture";
Radius 10;
Height 25;
}
States
{
Spawn:
XZW1 A -1;
Stop;
}
}
Class SWWMKeyGreen : SWWMKey
{
Default
{
Tag "$T_KEYGREEN";
Species "KeyGreen";
Inventory.PickupMessage "$T_KEYGREEN";
Inventory.PickupFlash "SWWMGreenPickupFlash";
SWWMKey.GestureWeapon "SWWMGreenKeyGesture";
Radius 10;
Height 25;
}
States
{
Spawn:
XZW1 A -1;
Stop;
}
}
Class SWWMKeyBlue : SWWMKey
{
Default
{
Tag "$T_KEYBLUE";
Species "KeyBlue";
Inventory.PickupMessage "$T_KEYBLUE";
Inventory.PickupFlash "SWWMBluePickupFlash";
SWWMKey.GestureWeapon "SWWMBlueKeyGesture";
Radius 10;
Height 25;
}
States
{
Spawn:
XZW1 A -1;
Stop;
}
}
Class SWWMKeyYellow : SWWMKey
{
Default
{
Tag "$T_KEYYELLOW";
Species "KeyYellow";
Inventory.PickupMessage "$T_KEYYELLOW";
Inventory.PickupFlash "SWWMPickupFlash";
SWWMKey.GestureWeapon "SWWMYellowKeyGesture";
Radius 10;
Height 25;
}
States
{
Spawn:
XZW1 A -1;
Stop;
}
}
Class SWWMKeyRed : SWWMKey
{
Default
{
Tag "$T_KEYRED";
Species "KeyRed";
Inventory.PickupMessage "$T_KEYRED";
Inventory.PickupFlash "SWWMRedPickupFlash";
SWWMKey.GestureWeapon "SWWMRedKeyGesture";
Radius 10;
Height 25;
}
States
{
Spawn:
XZW1 A -1;
Stop;
}
}
// HEXDD thingy
Class SWWMChaosSphere : Key
{
Default
{
Tag "$T_CHAOSSPHERE";
Inventory.InterHubAmount 1; // don't strip, this thing is always kept
+INVENTORY.UNDROPPABLE;
+INVENTORY.UNTOSSABLE;
+INVENTORY.UNCLEARABLE;
}
}

View file

@ -0,0 +1,140 @@
// Key gestures
// (they all use the same exact animations, just with the object changed)
// (yeah, I'm lazy, and there's a lot of keys)
Class SWWMKeyGesture : SWWMItemGesture abstract
{
// due to specifics™ we have to handle the punching here
override void DoEffect()
{
Super.DoEffect();
if ( !Owner || !Owner.player || (Owner.player.Health <= 0) || (Owner.player.ReadyWeapon != self) )
return;
PSprite psp = Owner.player.FindPSPrite(PSP_WEAPON+1);
if ( !(Owner.player.cmd.buttons&(BT_ATTACK|BT_ALTATTACK|BT_USER1)) && !psp )
{
// not punching, move weapon back
psp = Owner.player.FindPSPrite(PSP_WEAPON);
if ( psp )
{
psp.oldx = psp.x;
psp.x = max(0,psp.x-8);
psp.oldy = psp.y;
psp.y = min(32,psp.y+4);
}
return;
}
if ( psp )
{
// already punching, let's shift the weapon away
psp = Owner.player.FindPSPrite(PSP_WEAPON);
if ( psp )
{
// shift away from center to center
psp.oldx = psp.x;
psp.x = min(70,psp.x+8);
psp.oldy = psp.y;
psp.y = max(16,psp.y-4);
}
return;
}
// start punch
if ( Owner.player.cmd.buttons&(BT_ATTACK|BT_ALTATTACK|BT_USER1) )
{
psp = Owner.player.FindPSPrite(PSP_WEAPON);
if ( psp && (psp.CurState == FindState("WaitingForEnd")) )
return;
Owner.player.SetPSprite(PSP_WEAPON+1,FindState("Punch"));
psp = Owner.player.FindPSPrite(PSP_WEAPON+1);
if ( psp )
{
psp.bAddWeapon = false;
psp.bAddBob = false;
psp.x = -50;
psp.y = 32;
}
}
}
States
{
Fire:
XZW1 A 3 A_Jump(128,"AltFire","AltFire2");
XZW1 B 3 A_StartSound("demolitionist/handsup",CHAN_WEAPON,CHANF_OVERLAP);
XZW1 CDEF 3;
XZW1 GHIJKLMNO 4;
XZW1 P 3 A_StartSound("demolitionist/handsdown",CHAN_WEAPON,CHANF_OVERLAP);
XZW1 QRST 3;
Goto WaitingForEnd;
AltFire:
XZW1 A 3 A_Jump(128,"Fire","AltFire2");
XZW1 U 3 A_StartSound("demolitionist/handsup",CHAN_WEAPON,CHANF_OVERLAP);
XZW1 VWX 3;
XZW1 YZ 4;
XZW2 ABC 4;
XZW2 D 4 A_StartSound("demolitionist/handsdown",CHAN_WEAPON,CHANF_OVERLAP,pitch:.7);
XZW2 EFGHIJ 4;
XZW2 KL 3;
XZW2 M 3 A_StartSound("demolitionist/handsdown",CHAN_WEAPON,CHANF_OVERLAP);
XZW2 NOPQR 3;
Goto WaitingForEnd;
AltFire2:
XZW1 A 3;
XZW2 S 3 A_StartSound("demolitionist/handsup",CHAN_WEAPON,CHANF_OVERLAP);
XZW2 TUVWX 3;
XZW2 YZ 4;
XZW3 ABCDE 4;
XZW3 F 2 A_StartSound("demolitionist/handsdown",CHAN_WEAPON,CHANF_OVERLAP);
XZW3 GHI 2;
XZW3 JKL 3;
XZW3 MN 2;
XZW3 O 2 A_StartSound("demolitionist/petting",CHAN_WEAPON,CHANF_OVERLAP,.4);
XZW3 PQ 2;
XZW3 RS 4;
XZW3 T 4 A_StartSound("demolitionist/handsdown",CHAN_WEAPON,CHANF_OVERLAP);
XZW3 UV 4;
XZW3 WXY 3;
Goto WaitingForEnd;
WaitingForEnd:
XZW1 A 1 A_JumpIf(!player.FindPSprite(PSP_WEAPON+1),1);
Wait;
XZW1 A -1 A_FinishGesture();
Stop;
// overlay for melee
Punch:
XZW0 ABC 1;
PunchHold:
XZW0 D 1
{
A_PlayerMelee(true);
A_StartSound("demolitionist/swing",CHAN_WEAPON,CHANF_OVERLAP);
A_Parry(9);
}
XZW0 EF 1;
XZW0 G 1 A_Melee();
XZW0 HIJKLMN 2;
XZW0 A 0
{
if ( player.cmd.buttons&(BT_ATTACK|BT_ALTATTACK|BT_USER1) )
{
let psp = player.FindPSprite(PSP_WEAPON);
if ( psp && (psp.CurState != ResolveState("WaitingForEnd")) )
return ResolveState("PunchHold");
}
return ResolveState(null);
}
Stop;
}
}
Class SWWMRedCardGesture : SWWMKeyGesture {}
Class SWWMYellowCardGesture : SWWMKeyGesture {}
Class SWWMBlueCardGesture : SWWMKeyGesture {}
Class SWWMSilverCardGesture : SWWMKeyGesture {}
Class SWWMGreenCardGesture : SWWMKeyGesture {}
Class SWWMOrangeCardGesture : SWWMKeyGesture {}
Class SWWMRedSkullGesture : SWWMKeyGesture {}
Class SWWMYellowSkullGesture : SWWMKeyGesture {}
Class SWWMBlueSkullGesture : SWWMKeyGesture {}
Class SWWMGreenKeyGesture : SWWMKeyGesture {}
Class SWWMBlueKeyGesture : SWWMKeyGesture {}
Class SWWMYellowKeyGesture : SWWMKeyGesture {}
Class SWWMRedKeyGesture : SWWMKeyGesture {}

File diff suppressed because it is too large Load diff