Spreadgun buckshot and slug implemented.
Tweaks here and there to other stuff. Refined wall jumping/climbing, also works on actors (including other players). Refined how boosting/dashing handles falling speeds. Added improved air control. It was very much needed. Added "kick" sounds to wall jumps. Add option to hear other player's voices in mp. Fix some broken localization. Fix invulnerable monsters bleeding from some attacks. Fix desync when jumping on top of another player with prediction enabled. Make moths immune to your damage, so you can stop accidentally killing them. Make normal ammo buyable in Hexen again.
This commit is contained in:
parent
66ca017300
commit
7a01fdc4e8
57 changed files with 979 additions and 115 deletions
|
|
@ -874,7 +874,7 @@ Class FabricatorTier1 : AmmoFabricator
|
|||
Inventory.PickupMessage "$T_FABRICATOR1";
|
||||
Inventory.MaxAmount 30;
|
||||
AmmoFabricator.Budget 2000;
|
||||
AmmoFabricator.PerType 4;
|
||||
AmmoFabricator.PerType 2;
|
||||
Stamina 3000;
|
||||
}
|
||||
}
|
||||
|
|
@ -887,7 +887,7 @@ Class FabricatorTier2 : AmmoFabricator
|
|||
Inventory.PickupMessage "$T_FABRICATOR2";
|
||||
Inventory.MaxAmount 20;
|
||||
AmmoFabricator.Budget 15000;
|
||||
AmmoFabricator.PerType 8;
|
||||
AmmoFabricator.PerType 4;
|
||||
Stamina 12000;
|
||||
}
|
||||
}
|
||||
|
|
@ -900,7 +900,7 @@ Class FabricatorTier3 : AmmoFabricator
|
|||
Inventory.PickupMessage "$T_FABRICATOR3";
|
||||
Inventory.MaxAmount 10;
|
||||
AmmoFabricator.Budget 100000;
|
||||
AmmoFabricator.PerType 16;
|
||||
AmmoFabricator.PerType 8;
|
||||
Stamina 150000;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -515,6 +515,7 @@ Class SWWMOneLiner : HUDMessageBase
|
|||
|
||||
override bool Tick()
|
||||
{
|
||||
if ( players[consoleplayer].Health <= 0 ) curtime = int.min;
|
||||
curtime--;
|
||||
return (curtime<-20);
|
||||
}
|
||||
|
|
@ -818,6 +819,7 @@ Class SWWMChip : Actor
|
|||
+INTERPOLATEANGLES;
|
||||
+ROLLSPRITE;
|
||||
+ROLLCENTER;
|
||||
+FORCEXYBILLBOARD;
|
||||
BounceType "Doom";
|
||||
BounceFactor 0.3;
|
||||
Gravity 0.35;
|
||||
|
|
@ -1019,14 +1021,14 @@ Class SWWMBulletTrail : LineTracer
|
|||
t.ShootThroughList[i].Activate(target,0,SPAC_PCross);
|
||||
for ( int i=0; i<t.WaterHitList.Size(); i++ )
|
||||
{
|
||||
let b = Actor.Spawn("InvisibleSplasher",t.WaterHitList[0].hitpos);
|
||||
let b = Actor.Spawn("InvisibleSplasher",t.WaterHitList[i].hitpos);
|
||||
b.A_CheckTerrain();
|
||||
}
|
||||
for ( int i=5; i<t.Results.Distance; i+=10 )
|
||||
{
|
||||
if ( !Random[Boolet](0,bubblechance) ) continue;
|
||||
let b = Actor.Spawn(smoky?"SWWMSmallSmoke":"SWWMBubble",level.Vec3Offset(pos,dir*i));
|
||||
b.Scale *= FRandom[Boolet](0.4,0.6);
|
||||
b.Scale *= FRandom[Boolet](.4,.6);
|
||||
}
|
||||
t.Destroy();
|
||||
}
|
||||
|
|
@ -1177,7 +1179,7 @@ Class LastLine
|
|||
Class SWWMHandler : EventHandler
|
||||
{
|
||||
transient String oneliner, onelinersnd;
|
||||
transient int onelinertic, onelinerspan;
|
||||
transient int onelinertic, onelinerspan, onelinerlevel;
|
||||
transient int lastlock, lastcombat;
|
||||
transient Array<Actor> combatactors;
|
||||
transient Array<Int> combattics;
|
||||
|
|
@ -1192,25 +1194,40 @@ Class SWWMHandler : EventHandler
|
|||
|
||||
transient CVar mutevoice;
|
||||
|
||||
static int AddOneliner( String type, int delay = 5 )
|
||||
static int AddOneliner( String type, int level, int delay = 5 )
|
||||
{
|
||||
let hnd = SWWMHandler(EventHandler.Find("SWWMHandler"));
|
||||
if ( !hnd ) return 0;
|
||||
CVar voicetype = CVar.GetCVar('swwm_voicetype',players[consoleplayer]);
|
||||
String voicetype = CVar.GetCVar('swwm_voicetype',players[consoleplayer]).GetString();
|
||||
// suppress non-rage comments when ragekit is active, only screaming allowed
|
||||
if ( players[consoleplayer].mo.FindInventory("RagekitPower") && (type != "ragekit") && (CVar.GetCVar('swwm_mutevoice',players[consoleplayer]).GetInt() < 2) ) return 0;
|
||||
if ( players[consoleplayer].mo.FindInventory("RagekitPower") && (type != "ragekit") ) return 0;
|
||||
int whichline;
|
||||
int countem = 0, i = 1;
|
||||
String testme, locme;
|
||||
do
|
||||
{
|
||||
testme = String.Format("SWWM_SUBS_%s_%s%d",voicetype.GetString().MakeUpper(),type.MakeUpper(),i);
|
||||
testme = String.Format("SWWM_SUBS_%s_%s%d",voicetype.MakeUpper(),type.MakeUpper(),i);
|
||||
locme = StringTable.Localize(testme,false);
|
||||
if ( testme != locme ) countem++;
|
||||
i++;
|
||||
}
|
||||
while ( (testme != locme) && (i < 100) ); // gotta prevent infinite loops
|
||||
if ( countem == 0 ) return 0;
|
||||
if ( countem == 0 )
|
||||
{
|
||||
if ( voicetype ~== "default" ) return 0;
|
||||
// retry with the default voicetype
|
||||
voicetype = "default";
|
||||
i = 1;
|
||||
do
|
||||
{
|
||||
testme = String.Format("SWWM_SUBS_DEFAULT_%s%d",type.MakeUpper(),i);
|
||||
locme = StringTable.Localize(testme,false);
|
||||
if ( testme != locme ) countem++;
|
||||
i++;
|
||||
}
|
||||
while ( (testme != locme) && (i < 100) ); // gotta prevent infinite loops
|
||||
if ( countem == 0 ) return 0;
|
||||
}
|
||||
// check last line so we don't repeat
|
||||
int last = 0, ent;
|
||||
for ( int i=0; i<hnd.lastlines.Size(); i++ )
|
||||
|
|
@ -1234,10 +1251,11 @@ Class SWWMHandler : EventHandler
|
|||
lst.lineno = whichline;
|
||||
hnd.lastlines.Push(lst);
|
||||
}
|
||||
hnd.oneliner = String.Format("$SWWM_SUBS_%s_%s%d",voicetype.GetString().MakeUpper(),type.MakeUpper(),whichline);
|
||||
hnd.onelinersnd = String.Format("voice/%s/%s%d",voicetype.GetString(),type,whichline);
|
||||
hnd.oneliner = String.Format("$SWWM_SUBS_%s_%s%d",voicetype.MakeUpper(),type.MakeUpper(),whichline);
|
||||
hnd.onelinersnd = String.Format("voice/%s/%s%d",voicetype,type,whichline);
|
||||
hnd.onelinertic = gametic+delay;
|
||||
hnd.onelinerspan = int(S_GetLength(hnd.onelinersnd)*Thinker.TICRATE);
|
||||
hnd.onelinerlevel = level;
|
||||
return hnd.onelinertic+hnd.onelinerspan;
|
||||
}
|
||||
|
||||
|
|
@ -1325,8 +1343,8 @@ Class SWWMHandler : EventHandler
|
|||
override void WorldLoaded( WorldEvent e )
|
||||
{
|
||||
if ( !mutevoice ) mutevoice = CVar.GetCVar('swwm_mutevoice',players[consoleplayer]);
|
||||
if ( !e.IsSaveGame && !e.IsReopen && (gamestate != GS_TITLELEVEL) && (mutevoice.GetInt() < 3) )
|
||||
AddOneliner("mapstart");
|
||||
if ( !e.IsSaveGame && !e.IsReopen && (gamestate != GS_TITLELEVEL) )
|
||||
AddOneliner("mapstart",3);
|
||||
if ( !e.IsSaveGame && !e.IsReopen )
|
||||
{
|
||||
// for skipping over merged exit lines (sharing vertices)
|
||||
|
|
@ -1467,7 +1485,11 @@ Class SWWMHandler : EventHandler
|
|||
if ( onelinertic && (onelinertic < gametic) )
|
||||
{
|
||||
if ( players[consoleplayer].health > 0 )
|
||||
players[consoleplayer].mo.A_StartSound(onelinersnd,CHAN_DEMOVOICE,CHANF_DEFAULT,1.,ATTN_NONE);
|
||||
{
|
||||
if ( onelinerlevel > mutevoice.GetInt() )
|
||||
players[consoleplayer].mo.A_StartSound(onelinersnd,CHAN_DEMOVOICE,CHANF_DEFAULT,1.,ATTN_NONE);
|
||||
SendNetworkEvent("swwmremoteliner."..onelinersnd,consoleplayer,onelinerlevel);
|
||||
}
|
||||
onelinertic = 0;
|
||||
onelinerspan = 0;
|
||||
}
|
||||
|
|
@ -1540,8 +1562,8 @@ Class SWWMHandler : EventHandler
|
|||
enteredcombat = true;
|
||||
}
|
||||
}
|
||||
if ( enteredcombat && (!highesttic || (gametic > highesttic+100)) && (mutevoice.GetInt() < 1) )
|
||||
lastcombat = AddOneliner("fightstart",10);
|
||||
if ( enteredcombat && (!highesttic || (gametic > highesttic+100)) )
|
||||
lastcombat = AddOneliner("fightstart",1,10);
|
||||
}
|
||||
|
||||
override void WorldThingDied( WorldEvent e )
|
||||
|
|
@ -1557,7 +1579,6 @@ Class SWWMHandler : EventHandler
|
|||
|
||||
override void WorldThingDamaged( WorldEvent e )
|
||||
{
|
||||
if ( !mutevoice ) mutevoice = CVar.GetCVar('swwm_mutevoice',players[consoleplayer]);
|
||||
if ( e.Damage > 0 )
|
||||
SWWMScoreObj.Spawn(-e.Damage,e.Thing.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+e.Thing.Height/2),Font.CR_RED);
|
||||
if ( e.Thing.player )
|
||||
|
|
@ -1577,8 +1598,8 @@ Class SWWMHandler : EventHandler
|
|||
{
|
||||
if ( (e.DamageSource.bISMONSTER || e.DamageSource.player) && (e.Thing == players[consoleplayer].mo) && (e.Thing.Health > 0) )
|
||||
{
|
||||
if ( (!lastcombat || (gametic > lastcombat+20)) && (mutevoice.GetInt() < 1) )
|
||||
lastcombat = AddOneliner(e.Thing.IsFriend(e.DamageSource)?"friendhit":"gethit",15);
|
||||
if ( !lastcombat || (gametic > lastcombat+20) )
|
||||
lastcombat = AddOneliner(e.Thing.IsFriend(e.DamageSource)?"friendhit":"gethit",1,15);
|
||||
highesttic = gametic;
|
||||
}
|
||||
if ( (e.DamageSource == players[consoleplayer].mo) && (e.Thing.bISMONSTER || e.Thing.player) )
|
||||
|
|
@ -1586,8 +1607,8 @@ Class SWWMHandler : EventHandler
|
|||
// make sure it's not a moth, because otherwise they won't shut up about accidentally hurting them (it happens a lot)
|
||||
if ( e.Thing.IsFriend(e.DamageSource) && !(e.Thing is 'LampMoth') )
|
||||
{
|
||||
if ( (!lastcombat || (gametic > lastcombat+20)) && (mutevoice.GetInt() < 1) )
|
||||
lastcombat = AddOneliner("hitfriend",15);
|
||||
if ( !lastcombat || (gametic > lastcombat+20) )
|
||||
lastcombat = AddOneliner("hitfriend",1,15);
|
||||
highesttic = gametic;
|
||||
}
|
||||
}
|
||||
|
|
@ -1606,8 +1627,8 @@ Class SWWMHandler : EventHandler
|
|||
if ( e.DamageSource == players[consoleplayer].mo )
|
||||
{
|
||||
highesttic = gametic;
|
||||
if ( (!lastcombat || (gametic > lastcombat+20)) && (mutevoice.GetInt() < 1) )
|
||||
lastcombat = AddOneliner("scorekill",15);
|
||||
if ( !lastcombat || (gametic > lastcombat+20) )
|
||||
lastcombat = AddOneliner("scorekill",1,15);
|
||||
}
|
||||
if ( !e.Thing.default.bCountKill ) // no credits
|
||||
return;
|
||||
|
|
@ -1621,7 +1642,7 @@ Class SWWMHandler : EventHandler
|
|||
// scoring
|
||||
int score = min(2000,int(ceil(e.Thing.SpawnHealth()*.5)*10));
|
||||
int ofs = 0;
|
||||
if ( e.Thing.Health <= e.Thing.GetGibHealth() )
|
||||
if ( ((e.Thing.Health <= e.Thing.GetGibHealth()) || (e.DamageSource.bEXTREMEDEATH) || (e.Inflictor && e.Inflictor.bEXTREMEDEATH)) && !e.DamageSource.bNOEXTREMEDEATH && !(e.Inflictor && e.Inflictor.bNOEXTREMEDEATH) )
|
||||
{
|
||||
score = int(score*1.25);
|
||||
if ( e.DamageSource.player == players[consoleplayer] )
|
||||
|
|
@ -1640,7 +1661,7 @@ Class SWWMHandler : EventHandler
|
|||
{
|
||||
score += 10000;
|
||||
if ( e.DamageSource.player == players[consoleplayer] )
|
||||
SWWMScoreObj.Spawn(score,e.Thing.Vec3Offset(0,0,e.Thing.Height/2),Font.CR_FIRE,"$SWWM_BOSSKILL",++ofs);
|
||||
SWWMScoreObj.Spawn(0,e.Thing.Vec3Offset(0,0,e.Thing.Height/2),Font.CR_FIRE,"$SWWM_BOSSKILL",++ofs);
|
||||
}
|
||||
SWWMCredits.Give(e.DamageSource.player,score);
|
||||
if ( e.DamageSource.player == players[consoleplayer] )
|
||||
|
|
@ -1702,6 +1723,7 @@ Class SWWMHandler : EventHandler
|
|||
{
|
||||
let l = SWWMOneLiner.Make(oneliner,onelinerspan);
|
||||
StatusBar.AttachMessage(l,-3473);
|
||||
SendNetworkEvent("swwmremotelinertxt."..oneliner,consoleplayer,onelinerlevel);
|
||||
}
|
||||
for ( int i=0; i<flashes.size(); i++ )
|
||||
{
|
||||
|
|
@ -1738,8 +1760,8 @@ Class SWWMHandler : EventHandler
|
|||
if ( !locknum ) return;
|
||||
if ( e.Thing.CheckLocalView() && !e.Thing.CheckKeys(locknum,false,true) )
|
||||
{
|
||||
if ( (!lastlock || (gametic > lastlock+20)) && (mutevoice.GetInt() < 2) )
|
||||
lastlock = AddOneliner("locked");
|
||||
if ( !lastlock || (gametic > lastlock+20) )
|
||||
lastlock = AddOneliner("locked",2);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2066,26 +2088,41 @@ Class SWWMHandler : EventHandler
|
|||
else if ( e.Name ~== "swwmkoraxline" )
|
||||
{
|
||||
if ( consoleplayer != e.Args[1] ) return;
|
||||
if ( CVar.GetCVar('swwm_mutevoice',players[consoleplayer]).GetInt() >= 3 ) return;
|
||||
switch ( e.Args[0] )
|
||||
{
|
||||
case 0:
|
||||
AddOneliner("koraxgreet",60);
|
||||
AddOneliner("koraxgreet",3,60);
|
||||
break;
|
||||
case 1:
|
||||
AddOneliner("koraxblood",150);
|
||||
AddOneliner("koraxblood",3,150);
|
||||
break;
|
||||
case 2:
|
||||
AddOneliner("koraxgame",120);
|
||||
AddOneliner("koraxgame",3,120);
|
||||
break;
|
||||
case 3:
|
||||
AddOneliner("koraxworship",80);
|
||||
AddOneliner("koraxworship",3,80);
|
||||
break;
|
||||
case 4:
|
||||
AddOneliner("koraxmasters",90);
|
||||
AddOneliner("koraxmasters",3,90);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ( e.Name.Left(16) ~== "swwmremoteliner." )
|
||||
{
|
||||
if ( consoleplayer == e.Args[0] ) return;
|
||||
if ( !CVar.GetCVar('swwm_othervoice',players[consoleplayer]).GetBool() ) return;
|
||||
if ( CVar.GetCVar('swwm_mutevoice',players[consoleplayer]).GetInt() >= e.Args[1] ) return;
|
||||
players[e.Args[0]].mo.A_StartSound(e.Name.Mid(16),CHAN_DEMOVOICE,attenuation:.5);
|
||||
}
|
||||
else if ( e.Name.Left(19) ~== "swwmremotelinertxt." )
|
||||
{
|
||||
if ( consoleplayer == e.Args[0] ) return;
|
||||
if ( !CVar.GetCVar('swwm_othervoice',players[consoleplayer]).GetBool() ) return;
|
||||
if ( CVar.GetCVar('swwm_mutevoice',players[consoleplayer]).GetInt() >= e.Args[1] ) return;
|
||||
double dist = players[consoleplayer].Camera.Distance3D(players[e.Args[0]].mo);
|
||||
if ( dist < 2000 )
|
||||
Console.Printf("\cx%s\cx: %s\c-",players[e.Args[0]].GetUserName(),StringTable.Localize(e.Name.Mid(19)));
|
||||
}
|
||||
}
|
||||
|
||||
// stuff for hud
|
||||
|
|
|
|||
|
|
@ -269,9 +269,8 @@ Class SWWMCasing : Actor abstract
|
|||
Death:
|
||||
#### # -1
|
||||
{
|
||||
pitch = 0;
|
||||
pitch = roll = 0;
|
||||
angle = FRandom[Junk](0,360);
|
||||
roll = FRandom[Junk](0,360);
|
||||
}
|
||||
Stop;
|
||||
}
|
||||
|
|
@ -470,7 +469,7 @@ Class SWWMWeapon : Weapon abstract
|
|||
invoker.bEXTREMEDEATH = invoker.default.bEXTREMEDEATH;
|
||||
invoker.bNOEXTREMEDEATH = invoker.default.bEXTREMEDEATH;
|
||||
if ( d.HitActor.player ) d.HitActor.A_QuakeEx(2,2,2,6,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.25);
|
||||
if ( !d.HitActor.bNOBLOOD )
|
||||
if ( !d.HitActor.bNOBLOOD && !d.HitActor.bINVULNERABLE )
|
||||
{
|
||||
d.HitActor.TraceBleed(dmg,invoker);
|
||||
d.HitActor.SpawnBlood(d.HitLocation,atan2(d.HitDir.y,d.HitDir.x)+180,dmg);
|
||||
|
|
@ -531,6 +530,14 @@ Class SWWMWeapon : Weapon abstract
|
|||
{
|
||||
return (AmmoType1&&(kind is AmmoType1))||(AmmoType2&&(kind is AmmoType2));
|
||||
}
|
||||
override void ModifyDropAmount( int dropamount )
|
||||
{
|
||||
Super.ModifyDropAmount(dropamount);
|
||||
if ( (AmmoGive1 <= 0) && (default.AmmoGive1 > 0) )
|
||||
AmmoGive1 = 1;
|
||||
if ( (AmmoGive2 <= 0) && (default.AmmoGive2 > 0) )
|
||||
AmmoGive2 = 1;
|
||||
}
|
||||
Default
|
||||
{
|
||||
Weapon.BobStyle "Alpha";
|
||||
|
|
|
|||
|
|
@ -252,7 +252,7 @@ Class PusherProjectile : Actor
|
|||
{
|
||||
if ( target == lasthit ) return 0;
|
||||
lasthit = target;
|
||||
if ( target.bNOBLOOD ) A_StartSound("pusher/althit",CHAN_WEAPON,CHANF_OVERLAP);
|
||||
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);
|
||||
|
|
@ -339,7 +339,7 @@ Class PusherWeapon : SWWMWeapon
|
|||
SWWMHandler.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 )
|
||||
if ( d.HitActor.bNOBLOOD || d.HitActor.bINVULNERABLE )
|
||||
{
|
||||
let p = Spawn("PusherImpact",d.HitLocation-d.HitDir*4);
|
||||
p.angle = atan2(-d.HitDir.y,-d.HitDir.x);
|
||||
|
|
@ -421,7 +421,7 @@ Class PusherWeapon : SWWMWeapon
|
|||
SWWMHandler.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 )
|
||||
if ( d.HitActor.bNOBLOOD || d.HitActor.bINVULNERABLE )
|
||||
{
|
||||
let p = Spawn("BigPusherImpact",d.HitLocation-d.HitDir*4);
|
||||
p.angle = atan2(-d.HitDir.y,-d.HitDir.x);
|
||||
|
|
|
|||
|
|
@ -504,8 +504,7 @@ Class SWWMKnowledgeBaseMenu : GenericMenu
|
|||
if ( !type ) continue;
|
||||
// skip chanceboxes, since they're not yet implemented
|
||||
if ( type is 'Chancebox' ) continue;
|
||||
// no fabricators outside of hexen, otherwise no ammo
|
||||
if ( (gameinfo.gametype&GAME_Hexen) && (type is 'Ammo') ) continue;
|
||||
// no fabricators outside of hexen
|
||||
if ( !(gameinfo.gametype&GAME_Hexen) && (type is 'AmmoFabricator') ) continue;
|
||||
// skip maxed items
|
||||
let cur = players[consoleplayer].mo.FindInventory(type);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// The Demolitionist
|
||||
Class Demolitionist : PlayerPawn
|
||||
{
|
||||
int last_jump_held;
|
||||
int last_jump_held, last_boost;
|
||||
Vector3 dashdir;
|
||||
double dashfuel, dashboost;
|
||||
int dashcooldown, boostcooldown, fuelcooldown;
|
||||
|
|
@ -225,6 +225,7 @@ Class Demolitionist : PlayerPawn
|
|||
}
|
||||
override String GetObituary( Actor victim, Actor inflictor, Name mod, bool playerattack )
|
||||
{
|
||||
if ( mod == 'Jump' ) return StringTable.Localize("$O_JUMP");
|
||||
if ( mod == 'Dash' ) return StringTable.Localize("$O_DASH");
|
||||
if ( mod == 'GroundPound' ) return StringTable.Localize("$O_POUND");
|
||||
return Super.GetObituary(victim,inflictor,mod,playerattack);
|
||||
|
|
@ -275,6 +276,7 @@ Class Demolitionist : PlayerPawn
|
|||
{
|
||||
A_AlertMonsters(800);
|
||||
dashboost *= (player.cmd.buttons&BT_JUMP)?.9:.4;
|
||||
last_boost = level.maptime+1;
|
||||
}
|
||||
mystats.fuelusage += dashfuel-max(0.,dashfuel-dashboost);
|
||||
dashfuel = max(0.,dashfuel-dashboost);
|
||||
|
|
@ -531,6 +533,19 @@ Class Demolitionist : PlayerPawn
|
|||
else
|
||||
{
|
||||
Super.MovePlayer();
|
||||
// override air control because we REALLY need the extra mobility
|
||||
if ( !player.onground && !bNOGRAVITY && (waterlevel < 2) )
|
||||
{
|
||||
double fs = TweakSpeeds(1.,0.);
|
||||
fs *= max(abs(player.cmd.forwardmove/12800.),abs(player.cmd.sidemove/10240.));
|
||||
if ( CanCrouch() && (player.crouchfactor != -1) ) fs *= player.crouchfactor;
|
||||
Vector3 accel = (RotateVector((player.cmd.forwardmove,-player.cmd.sidemove),angle),0);
|
||||
accel *= fs/960.;
|
||||
double spd = vel.length();
|
||||
if ( spd > 10. ) vel = (vel+accel/TICRATE).unit()*spd;
|
||||
else vel = vel+accel/TICRATE;
|
||||
player.jumptics = -2;
|
||||
}
|
||||
if ( abs(roll) > 0. ) roll += clamp(deltaangle(roll,0),-3.,3.);
|
||||
}
|
||||
guideangle *= .9;
|
||||
|
|
@ -568,7 +583,7 @@ Class Demolitionist : PlayerPawn
|
|||
player.cheats &= ~CF_REVERTPLEASE;
|
||||
player.camera = player.mo;
|
||||
}
|
||||
vel *= 0;
|
||||
vel.z += clamp(-vel.z*.4,0.,30.);
|
||||
player.jumptics = -1;
|
||||
SetStateLabel("Dash");
|
||||
A_StartSound("demolitionist/jet",CHAN_JETPACK,CHANF_LOOP);
|
||||
|
|
@ -578,8 +593,53 @@ Class Demolitionist : PlayerPawn
|
|||
override void CheckJump()
|
||||
{
|
||||
if ( InStateSequence(CurState,FindState("Dash")) ) return; // do not
|
||||
bool walljump = LineTrace(angle-180,Radius*2,0,TRF_NOSKY|TRF_THRUHITSCAN|TRF_BLOCKSELF|TRF_SOLIDACTORS,height*.2);
|
||||
bool wallclimb = LineTrace(angle,Radius*2,0,TRF_NOSKY|TRF_THRUHITSCAN|TRF_BLOCKSELF|TRF_SOLIDACTORS,height*.2);
|
||||
Vector2 walldir = (cos(angle),sin(angle));
|
||||
bool walljump = false, wallclimb = false;
|
||||
FLineTraceData d;
|
||||
Actor jumpactor = null;
|
||||
for ( int i=-4; i<int(height*.8); i++ )
|
||||
{
|
||||
if ( !wallclimb )
|
||||
{
|
||||
for ( int k=0; k<30; k+=10 )
|
||||
{
|
||||
for ( int j=-1; j<=1; j+=2 )
|
||||
{
|
||||
double ang = angle+k*j;
|
||||
wallclimb = LineTrace(ang,Radius+12,0,TRF_NOSKY|TRF_THRUHITSCAN|TRF_BLOCKSELF|TRF_SOLIDACTORS,i,data:d);
|
||||
if ( wallclimb )
|
||||
{
|
||||
jumpactor = d.HitActor;
|
||||
walldir = (walldir*.7+(cos(ang),sin(ang))*.3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( wallclimb ) break;
|
||||
}
|
||||
if ( wallclimb ) break;
|
||||
}
|
||||
if ( wallclimb ) break;
|
||||
if ( !walljump )
|
||||
{
|
||||
for ( int k=0; k<60; k+=10 )
|
||||
{
|
||||
for ( int j=-1; j<=1; j+=2 )
|
||||
{
|
||||
double ang = (angle-180)+k*j;
|
||||
walljump = LineTrace(ang,Radius+12,0,TRF_NOSKY|TRF_THRUHITSCAN|TRF_BLOCKSELF|TRF_SOLIDACTORS,i,data:d);
|
||||
if ( walljump )
|
||||
{
|
||||
jumpactor = d.HitActor;
|
||||
walldir = (walldir*.7+(cos(ang+180),sin(ang+180))*.3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( walljump ) break;
|
||||
}
|
||||
if ( walljump ) break;
|
||||
}
|
||||
if ( walljump ) break;
|
||||
}
|
||||
if ( player.cmd.buttons&BT_JUMP )
|
||||
{
|
||||
if ( player.crouchoffset ) player.crouching = 1;
|
||||
|
|
@ -590,6 +650,7 @@ Class Demolitionist : PlayerPawn
|
|||
&& ((player.onground && (player.jumptics == 0))
|
||||
|| (!player.onground && (level.maptime > last_jump_held) && (((dashfuel > 10.) && (boostcooldown <= 0)) || walljump || wallclimb))) )
|
||||
{
|
||||
if ( !player.onground && (level.maptime < last_boost+8) ) return;
|
||||
double jumpvelz = JumpZ*35./TICRATE;
|
||||
double jumpfac = 0;
|
||||
for ( let p=Inv; p; p=p.Inv )
|
||||
|
|
@ -603,21 +664,27 @@ Class Demolitionist : PlayerPawn
|
|||
}
|
||||
if ( jumpfac > 0 ) jumpvelz *= jumpfac;
|
||||
double pvelz = vel.z;
|
||||
if ( !player.onground )
|
||||
if ( !player.onground && !(player.cheats&CF_PREDICTING) )
|
||||
{
|
||||
// check for wall stuff
|
||||
if ( walljump )
|
||||
{
|
||||
vel.z = max(-abs(vel.z)*.1,vel.z);
|
||||
vel.z += jumpvelz;
|
||||
vel.xy = (cos(angle),sin(angle))*20*Speed;
|
||||
if ( vel.z < 10. )
|
||||
vel.z += jumpvelz+clamp(-pvelz*.6,0.,30.);
|
||||
vel.xy += walldir*20*Speed;
|
||||
}
|
||||
else if ( wallclimb )
|
||||
{
|
||||
vel.z = max(-abs(vel.z)*.1,vel.z);
|
||||
vel.z += jumpvelz;
|
||||
vel.xy = (cos(angle),sin(angle))*5*Speed;
|
||||
if ( vel.z < 10. )
|
||||
vel.z += jumpvelz+clamp(-pvelz*.8,0.,30.);
|
||||
vel.xy += walldir*5*Speed;
|
||||
}
|
||||
if ( jumpactor && jumpactor.bSHOOTABLE )
|
||||
{
|
||||
SWWMHandler.DoKnockback(jumpactor,(-walldir,0),12000);
|
||||
jumpactor.DamageMobj(self,self,10,'Jump');
|
||||
}
|
||||
if ( walljump || wallclimb ) A_StartSound("demolitionist/kick",CHAN_FOOTSTEP,CHANF_OVERLAP);
|
||||
}
|
||||
bOnMobj = false;
|
||||
player.jumpTics = -1;
|
||||
|
|
@ -627,16 +694,19 @@ Class Demolitionist : PlayerPawn
|
|||
{
|
||||
dashboost = 3.;
|
||||
boostcooldown = 20;
|
||||
vel.z += jumpvelz+clamp(-pvelz,0.,30.);
|
||||
if ( vel.z < 10. )
|
||||
vel.z += jumpvelz+clamp(-pvelz*.4,0.,30.);
|
||||
A_StartSound("demolitionist/jet",CHAN_JETPACK,CHANF_LOOP);
|
||||
mystats.boostcount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
dashboost = 0.;
|
||||
vel.z += jumpvelz*1.25;
|
||||
if ( vel.z < 10. )
|
||||
vel.z += jumpvelz*1.25;
|
||||
}
|
||||
SetStateLabel("Jump");
|
||||
if ( !player.onground ) last_boost = level.maptime+1;
|
||||
}
|
||||
last_jump_held = level.maptime+1;
|
||||
}
|
||||
|
|
@ -819,6 +889,7 @@ Class Demolitionist : PlayerPawn
|
|||
}
|
||||
void A_DemoScream()
|
||||
{
|
||||
A_StopSound(CHAN_DEMOVOICE);
|
||||
if ( !myvoice ) myvoice = CVar.GetCVar('swwm_voicetype',player);
|
||||
if ( !mute ) mute = CVar.GetCVar('swwm_mutevoice',player);
|
||||
A_PlayerScream();
|
||||
|
|
@ -828,7 +899,6 @@ Class Demolitionist : PlayerPawn
|
|||
override bool OnGiveSecret( bool printmsg, bool playsound )
|
||||
{
|
||||
if ( !player ) return false;
|
||||
if ( !mute ) mute = CVar.GetCVar('swwm_mutevoice',player);
|
||||
int score = 500;
|
||||
// last secret (this is called before counting it up, so have to subtract)
|
||||
if ( level.found_secrets == level.total_secrets-1 )
|
||||
|
|
@ -837,7 +907,7 @@ Class Demolitionist : PlayerPawn
|
|||
Console.Printf(StringTable.Localize("$SWWM_LASTSECRET"),player.GetUserName(),score);
|
||||
}
|
||||
else Console.Printf(StringTable.Localize("$SWWM_FINDSECRET"),player.GetUserName(),score);
|
||||
if ( CheckLocalView() && (mute.GetInt() < 2) ) SWWMHandler.AddOneliner("findsecret",40);
|
||||
if ( CheckLocalView() ) SWWMHandler.AddOneliner("findsecret",2,40);
|
||||
SWWMCredits.Give(player,score);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -847,9 +917,8 @@ Class Demolitionist : PlayerPawn
|
|||
if ( !player ) return;
|
||||
// add lore if any
|
||||
SWWMLoreLibrary.Add(player,item.GetClassName());
|
||||
if ( !mute ) mute = CVar.GetCVar('swwm_mutevoice',player);
|
||||
if ( (item is 'Weapon') && mystats && !mystats.GotWeapon(Weapon(item).GetClass()) && CheckLocalView() && (mute.GetInt() < 2) )
|
||||
SWWMHandler.AddOneliner("getweapon");
|
||||
if ( (item is 'Weapon') && mystats && !mystats.GotWeapon(Weapon(item).GetClass()) && CheckLocalView() )
|
||||
SWWMHandler.AddOneliner("getweapon",2);
|
||||
if ( (item is 'Key') && !key_reentrant )
|
||||
{
|
||||
// score
|
||||
|
|
@ -871,15 +940,14 @@ Class Demolitionist : PlayerPawn
|
|||
override bool UseInventory( Inventory item )
|
||||
{
|
||||
if ( !player ) return Super.UseInventory(item);
|
||||
if ( !mute ) mute = CVar.GetCVar('swwm_mutevoice',player);
|
||||
bool res = Super.UseInventory(item);
|
||||
if ( CheckLocalView() )
|
||||
{
|
||||
if ( !res && !(item is 'Weapon') ) A_StartSound("menu/noinvuse",CHAN_ITEM);
|
||||
if ( (item is 'PuzzleItem') && (mute.GetInt() < 2) )
|
||||
if ( item is 'PuzzleItem' )
|
||||
{
|
||||
if ( res ) SWWMHandler.AddOneliner("puzzsucc",10);
|
||||
else SWWMHandler.AddOneliner("puzzfail",20);
|
||||
if ( res ) SWWMHandler.AddOneliner("puzzsucc",2,10);
|
||||
else SWWMHandler.AddOneliner("puzzfail",2,20);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
|
|
@ -902,9 +970,11 @@ Class Demolitionist : PlayerPawn
|
|||
override bool Used( Actor user )
|
||||
{
|
||||
if ( !(user is 'Demolitionist') || !user.player ) return false;
|
||||
CVar othermute = CVar.GetCVar('swwm_mutevoice',user.player);
|
||||
if ( (user.player == players[consoleplayer]) && (othermute.GetInt() < 2) )
|
||||
SWWMHandler.AddOneliner("greet");
|
||||
if ( (user.player == players[consoleplayer]) && (health > 0) )
|
||||
{
|
||||
SWWMHandler.AddOneliner("greet",2);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
States
|
||||
|
|
|
|||
|
|
@ -576,7 +576,7 @@ Class RagekitPower : Powerup
|
|||
Super.InitEffect();
|
||||
if ( !Owner ) return;
|
||||
if ( Owner.player == players[consoleplayer] )
|
||||
lastrage = SWWMHandler.AddOneliner("ragekit",20);
|
||||
lastrage = SWWMHandler.AddOneliner("ragekit",2,20);
|
||||
SWWMHandler.DoFlash(Owner,Color(64,255,0,0),30);
|
||||
Owner.A_QuakeEx(8,8,8,20,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:1.);
|
||||
lasteffect = int.min;
|
||||
|
|
@ -596,7 +596,7 @@ Class RagekitPower : Powerup
|
|||
{
|
||||
SWWMHandler.DoFlash(Owner,Color(16,255,0,0),5);
|
||||
if ( (Owner.player == players[consoleplayer]) && (gametic > lastrage) && (CVar.GetCVar('swwm_mutevoice',players[consoleplayer]).GetInt() < 2) )
|
||||
lastrage = SWWMHandler.AddOneliner("ragekit",5);
|
||||
lastrage = SWWMHandler.AddOneliner("ragekit",2,5);
|
||||
Owner.A_QuakeEx(2,2,2,Random[Rage](1,2),0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:.5);
|
||||
}
|
||||
}
|
||||
|
|
@ -619,7 +619,7 @@ Class RagekitPower : Powerup
|
|||
SWWMHandler.DoFlash(Owner,Color(64,255,0,0),10);
|
||||
Owner.A_QuakeEx(8,8,8,Random[Rage](3,8),0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:1.);
|
||||
if ( (Owner.player == players[consoleplayer]) && (gametic > lastrage) )
|
||||
lastrage = SWWMHandler.AddOneliner("ragekit",5);
|
||||
lastrage = SWWMHandler.AddOneliner("ragekit",2,5);
|
||||
Owner.A_StartSound("powerup/ragekithit",CHAN_POWERUP);
|
||||
lasteffect = level.maptime;
|
||||
}
|
||||
|
|
@ -748,6 +748,12 @@ Class LampMoth : Actor
|
|||
if ( master && master.player ) SetFriendPlayer(master.player);
|
||||
else bFRIENDLY = false;
|
||||
}
|
||||
override int DamageMobj( Actor inflictor, Actor source, int damage, Name mod, int flags, double angle )
|
||||
{
|
||||
// no hurt moff
|
||||
if ( source && IsFriend(source) ) damage = 0;
|
||||
return Super.DamageMobj(inflictor,source,damage,mod,flags,angle);
|
||||
}
|
||||
bool isEntranced()
|
||||
{
|
||||
if ( !lamp )
|
||||
|
|
@ -880,7 +886,7 @@ Class LampMoth : Actor
|
|||
A_FaceTarget(0,0);
|
||||
lifespan -= 5;
|
||||
Vector3 awaydir = level.Vec3Diff(target.Vec3Offset(0,0,target.height),pos).unit();
|
||||
vel += awaydir*32.;
|
||||
vel += awaydir*8.;
|
||||
int dmg = target.DamageMobj(self,self,GetMissileDamage(0,0),'Melee',Random[Moth](0,8)?DMG_NO_PAIN:0);
|
||||
if ( !target.bNOBLOOD )
|
||||
{
|
||||
|
|
@ -1003,6 +1009,7 @@ Class CompanionLamp : Actor
|
|||
{
|
||||
Vector3 Trail;
|
||||
Array<LampMoth> moff;
|
||||
Actor parent;
|
||||
|
||||
Default
|
||||
{
|
||||
|
|
@ -1046,7 +1053,7 @@ Class CompanionLamp : Actor
|
|||
}
|
||||
let s = Spawn("SWWMSmallSmoke",m.pos);
|
||||
s.alpha *= .3;
|
||||
m.master = target;
|
||||
m.master = parent;
|
||||
m.lamp = self;
|
||||
m.trail = m.pos;
|
||||
moff.Push(m);
|
||||
|
|
@ -1054,7 +1061,7 @@ Class CompanionLamp : Actor
|
|||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
if ( !target || !SWWMLamp(master) )
|
||||
if ( !parent || !SWWMLamp(master) )
|
||||
{
|
||||
Destroy();
|
||||
return;
|
||||
|
|
@ -1080,7 +1087,7 @@ Class CompanionLamp : Actor
|
|||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
if ( !target || !SWWMLamp(master) )
|
||||
if ( !parent || !SWWMLamp(master) )
|
||||
{
|
||||
Destroy();
|
||||
return;
|
||||
|
|
@ -1092,8 +1099,8 @@ Class CompanionLamp : Actor
|
|||
{
|
||||
for ( int j=1; j>=-1; j-=2 )
|
||||
{
|
||||
double ang = (target.angle-180)+i*j;
|
||||
Vector3 testpos = level.Vec3Offset(target.pos,(cos(ang)*32,sin(ang)*32,target.height-8+1.5*sin(level.maptime*3.)));
|
||||
double ang = (parent.angle-180)+i*j;
|
||||
Vector3 testpos = level.Vec3Offset(parent.pos,(cos(ang)*32,sin(ang)*32,parent.height-8+1.5*sin(level.maptime*3.)));
|
||||
if ( !level.IsPointInLevel(testpos) ) continue;
|
||||
Vector3 oldpos = pos;
|
||||
Vector3 oldprev = prev;
|
||||
|
|
@ -1123,19 +1130,19 @@ Class CompanionLamp : Actor
|
|||
// check at most for a 45 degree offset
|
||||
if ( foundspot && (i > 45) ) break;
|
||||
}
|
||||
Vector3 diff = level.Vec3Diff(pos,target.pos);
|
||||
Vector3 diff = level.Vec3Diff(pos,parent.pos);
|
||||
if ( diff.length() > 400 )
|
||||
{
|
||||
Actor f = Spawn("SWWMItemFog",pos);
|
||||
f.A_StartSound("lamp/disappear",CHAN_VOICE);
|
||||
SetOrigin(trail,false);
|
||||
angle = AngleTo(target);
|
||||
angle = AngleTo(parent);
|
||||
vel *= 0.;
|
||||
f = Spawn("SWWMItemFog",pos);
|
||||
f.A_StartSound("lamp/appear",CHAN_VOICE);
|
||||
return;
|
||||
}
|
||||
angle += Clamp(deltaangle(angle,AngleTo(target)),-5.,5.);
|
||||
angle += Clamp(deltaangle(angle,AngleTo(parent)),-5.,5.);
|
||||
vel *= .8;
|
||||
bool blocked = false;
|
||||
if ( BlockingLine && BlockingLineIsBlocking() )
|
||||
|
|
@ -1174,7 +1181,7 @@ Class CompanionLamp : Actor
|
|||
vel += 4.*normal;
|
||||
blocked = true;
|
||||
}
|
||||
if ( (diff.x > -16) && (diff.x < 16) && (diff.y > -16) && (diff.y < 16) && (diff.z > -16) && (diff.z < target.height+8) )
|
||||
if ( (diff.x > -16) && (diff.x < 16) && (diff.y > -16) && (diff.y < 16) && (diff.z > -16) && (diff.z < parent.height+8) )
|
||||
{
|
||||
if ( diff.x < 0 ) vel.x -= .2;
|
||||
else vel.x += .2;
|
||||
|
|
@ -1277,7 +1284,7 @@ Class SWWMLamp : Inventory
|
|||
if ( !thelamp )
|
||||
{
|
||||
thelamp = Spawn("CompanionLamp",Owner.Vec3Offset(cos(Owner.angle)*20,sin(Owner.angle)*20,24));
|
||||
thelamp.target = Owner;
|
||||
CompanionLamp(thelamp).parent = Owner;
|
||||
thelamp.master = self;
|
||||
let f = Spawn("SWWMItemFog",thelamp.pos);
|
||||
f.A_StartSound("lamp/appear",CHAN_VOICE);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,303 @@
|
|||
// Blackmann "Rhino Stopper" Spreadgun (from Instant Action 3, also planned for Zanaveth Ultra Suite 2)
|
||||
// Slot 3, replaces Shotgun, Ethereal Crossbow, Serpent Staff
|
||||
|
||||
Class RedShellCasing : SWWMCasing
|
||||
{
|
||||
Default
|
||||
{
|
||||
BounceSound "spreadgun/casing";
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
heat = 0;
|
||||
}
|
||||
}
|
||||
Class GreenShellCasing : RedShellCasing {}
|
||||
Class WhiteShellCasing : RedShellCasing {}
|
||||
Class BlueShellCasing : RedShellCasing {}
|
||||
Class BlackShellCasing : RedShellCasing {}
|
||||
Class PurpleShellCasing : RedShellCasing {}
|
||||
Class GoldShellCasing : RedShellCasing
|
||||
{
|
||||
Default
|
||||
{
|
||||
BounceSound "spreadgun/gcasing";
|
||||
}
|
||||
}
|
||||
|
||||
Class SWWMDamageAccumulator : Thinker
|
||||
{
|
||||
Actor victim, inflictor, source;
|
||||
Array<Int> amounts;
|
||||
int total;
|
||||
Name type;
|
||||
bool dontgib;
|
||||
|
||||
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
|
||||
// 何?
|
||||
for ( int i=0; i<amounts.Size(); i++ )
|
||||
{
|
||||
if ( !victim ) break;
|
||||
victim.DamageMobj(inflictor,source,amounts[i],type,DMG_THRUSTLESS);
|
||||
}
|
||||
// clean up
|
||||
if ( inflictor ) inflictor.bEXTREMEDEATH = false;
|
||||
Destroy();
|
||||
}
|
||||
|
||||
static void Accumulate( Actor victim, int amount, Actor inflictor, Actor source, Name type, bool dontgib = false )
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
Array<HitListEntry> hitlist;
|
||||
Array<Line> shootthroughlist;
|
||||
Array<WaterHit> waterhitlist;
|
||||
|
||||
override ETraceStatus TraceCallback()
|
||||
{
|
||||
// liquid splashes
|
||||
if ( Results.CrossedWater )
|
||||
{
|
||||
let hl = new("WaterHit");
|
||||
hl.sect = Results.CrossedWater;
|
||||
hl.hitpos = Results.CrossedWaterPos;
|
||||
WaterHitList.Push(hl);
|
||||
}
|
||||
else if ( Results.Crossed3DWater )
|
||||
{
|
||||
let hl = new("WaterHit");
|
||||
hl.sect = Results.Crossed3DWater;
|
||||
hl.hitpos = Results.Crossed3DWaterPos;
|
||||
WaterHitList.Push(hl);
|
||||
}
|
||||
if ( Results.HitType == TRACE_HitActor )
|
||||
{
|
||||
if ( Results.HitActor == ignoreme ) return TRACE_Skip;
|
||||
if ( Results.HitActor.bSHOOTABLE )
|
||||
{
|
||||
int amt = SWWMDamageAccumulator.GetAmount(Results.HitActor);
|
||||
// getgibhealth isn't clearscope, fuck
|
||||
int gibhealth = -int(Results.HitActor.GetSpawnHealth()*gameinfo.gibfactor);
|
||||
if ( Results.HitActor.GibHealth != int.min ) gibhealth = -abs(Results.HitActor.GibHealth);
|
||||
// if gibbed, go through without dealing more damage
|
||||
if ( Results.HitActor.health-amt <= gibhealth ) return TRACE_Skip;
|
||||
let ent = new("HitListEntry");
|
||||
ent.hitactor = Results.HitActor;
|
||||
ent.hitlocation = Results.HitPos;
|
||||
ent.x = Results.HitVector;
|
||||
hitlist.Push(ent);
|
||||
// go right on through if dead
|
||||
if ( Results.HitActor.health-amt <= 0 ) return TRACE_Skip;
|
||||
// stap
|
||||
return TRACE_Abort;
|
||||
}
|
||||
return TRACE_Skip;
|
||||
}
|
||||
else if ( (Results.HitType == TRACE_HitWall) && (Results.Tier == TIER_Middle) )
|
||||
{
|
||||
if ( !Results.HitLine.sidedef[1] || (Results.HitLine.Flags&(Line.ML_BlockHitscan|Line.ML_BlockEverything)) )
|
||||
return TRACE_Stop;
|
||||
ShootThroughList.Push(Results.HitLine);
|
||||
return TRACE_Skip;
|
||||
}
|
||||
return TRACE_Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class SpreadSlugTracer : SpreadgunTracer
|
||||
{
|
||||
double penetration; // please don't laugh
|
||||
|
||||
override ETraceStatus TraceCallback()
|
||||
{
|
||||
// liquid splashes
|
||||
if ( Results.CrossedWater )
|
||||
{
|
||||
let hl = new("WaterHit");
|
||||
hl.sect = Results.CrossedWater;
|
||||
hl.hitpos = Results.CrossedWaterPos;
|
||||
WaterHitList.Push(hl);
|
||||
}
|
||||
else if ( Results.Crossed3DWater )
|
||||
{
|
||||
let hl = new("WaterHit");
|
||||
hl.sect = Results.Crossed3DWater;
|
||||
hl.hitpos = Results.Crossed3DWaterPos;
|
||||
WaterHitList.Push(hl);
|
||||
}
|
||||
if ( Results.HitType == TRACE_HitActor )
|
||||
{
|
||||
if ( Results.HitActor == ignoreme ) return TRACE_Skip;
|
||||
if ( Results.HitActor.bSHOOTABLE )
|
||||
{
|
||||
let ent = new("HitListEntry");
|
||||
ent.hitactor = Results.HitActor;
|
||||
ent.hitlocation = Results.HitPos;
|
||||
ent.x = Results.HitVector;
|
||||
ent.hitdamage = min(Results.HitActor.health+int(Results.HitActor.GetSpawnHealth()*gameinfo.gibfactor),int(penetration));
|
||||
hitlist.Push(ent);
|
||||
penetration = max(0,penetration-ent.hitdamage);
|
||||
if ( penetration <= 0 ) return TRACE_Abort;
|
||||
return TRACE_Skip;
|
||||
}
|
||||
return TRACE_Skip;
|
||||
}
|
||||
else if ( (Results.HitType == TRACE_HitWall) && (Results.Tier == TIER_Middle) )
|
||||
{
|
||||
if ( !Results.HitLine.sidedef[1] || (Results.HitLine.Flags&(Line.ML_BlockHitscan|Line.ML_BlockEverything)) )
|
||||
return TRACE_Stop;
|
||||
ShootThroughList.Push(Results.HitLine);
|
||||
return TRACE_Skip;
|
||||
}
|
||||
return TRACE_Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class SpreadImpact : Actor
|
||||
{
|
||||
Default
|
||||
{
|
||||
Radius 0.1;
|
||||
Height 0;
|
||||
+NOGRAVITY;
|
||||
+NOCLIP;
|
||||
+DONTSPLASH;
|
||||
+NOTELEPORT;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
A_StartSound("spreadgun/pellet",CHAN_VOICE,CHANF_DEFAULT,.4,4.);
|
||||
A_SprayDecal("TinyBulletChip",-20);
|
||||
int numpt = Random[Spreadgun](-2,2);
|
||||
Vector3 x = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (-x+(FRandom[Spreadgun](-.8,.8),FRandom[Spreadgun](-.8,.8),FRandom[Spreadgun](-.8,.8))).unit()*FRandom[Spreadgun](.1,1.2);
|
||||
let s = Spawn("SWWMSmoke",pos);
|
||||
s.vel = pvel;
|
||||
s.scale *= .6;
|
||||
s.special1 = Random[Spreadgun](0,1);
|
||||
s.SetShade(Color(1,1,1)*Random[Spreadgun](96,192));
|
||||
}
|
||||
numpt = Random[Spreadgun](-3,3);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (FRandom[Spreadgun](-1,1),FRandom[Spreadgun](-1,1),FRandom[Spreadgun](-1,1)).unit()*FRandom[Spreadgun](2,8);
|
||||
let s = Spawn("SWWMSpark",pos);
|
||||
s.vel = pvel;
|
||||
}
|
||||
numpt = Random[Spreadgun](-2,2);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (FRandom[Spreadgun](-1,1),FRandom[Spreadgun](-1,1),FRandom[Spreadgun](-1,1)).unit()*FRandom[Spreadgun](2,8);
|
||||
let s = Spawn("SWWMChip",pos);
|
||||
s.vel = pvel;
|
||||
}
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
Class SlugImpact : Actor
|
||||
{
|
||||
Default
|
||||
{
|
||||
Radius 0.1;
|
||||
Height 0;
|
||||
+NOGRAVITY;
|
||||
+NOCLIP;
|
||||
+DONTSPLASH;
|
||||
+NOTELEPORT;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
A_StartSound("spreadgun/slug",CHAN_VOICE,CHANF_DEFAULT,1.,2.);
|
||||
A_SprayDecal("BulletChip",-20);
|
||||
int numpt = Random[Spreadgun](6,12);
|
||||
Vector3 x = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (-x+(FRandom[Spreadgun](-.8,.8),FRandom[Spreadgun](-.8,.8),FRandom[Spreadgun](-.8,.8))).unit()*FRandom[Spreadgun](.1,1.2);
|
||||
let s = Spawn("SWWMSmoke",pos);
|
||||
s.vel = pvel;
|
||||
s.special1 = Random[Spreadgun](0,2);
|
||||
s.SetShade(Color(1,1,1)*Random[Spreadgun](96,192));
|
||||
}
|
||||
numpt = Random[Spreadgun](4,8);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (FRandom[Spreadgun](-1,1),FRandom[Spreadgun](-1,1),FRandom[Spreadgun](-1,1)).unit()*FRandom[Spreadgun](2,8);
|
||||
let s = Spawn("SWWMSpark",pos);
|
||||
s.vel = pvel;
|
||||
}
|
||||
numpt = Random[Spreadgun](10,15);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (FRandom[Spreadgun](-1,1),FRandom[Spreadgun](-1,1),FRandom[Spreadgun](-1,1)).unit()*FRandom[Spreadgun](2,8);
|
||||
let s = Spawn("SWWMChip",pos);
|
||||
s.vel = pvel;
|
||||
}
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
Class Spreadgun : SWWMWeapon
|
||||
{
|
||||
bool fired; // shell was used
|
||||
|
|
@ -9,6 +306,18 @@ Class Spreadgun : SWWMWeapon
|
|||
transient ui TextureID WeaponBox, AmmoIcon[7], LoadedIcon[7];
|
||||
transient ui Font TewiFont;
|
||||
|
||||
override String GetObituary( Actor victim, Actor inflictor, Name mod, bool playerattack )
|
||||
{
|
||||
if ( loadammo is 'RedShell' ) return StringTable.Localize("$O_SPREADGUN_RED");
|
||||
if ( loadammo is 'GreenShell' ) return StringTable.Localize("$O_SPREADGUN_GREEN");
|
||||
if ( loadammo is 'WhiteShell' ) return StringTable.Localize("$O_SPREADGUN_WHITE");
|
||||
if ( loadammo is 'BlueShell' ) return StringTable.Localize("$O_SPREADGUN_BLUE");
|
||||
if ( loadammo is 'BlackShell' ) return StringTable.Localize("$O_SPREADGUN_BLACK");
|
||||
if ( loadammo is 'PurpleShell' ) return StringTable.Localize("$O_SPREADGUN_PURPLE");
|
||||
if ( loadammo is 'GoldShell' ) return StringTable.Localize("$O_SPREADGUN_GOLD");
|
||||
return Super.GetObituary(victim,inflictor,mod,playerattack);
|
||||
}
|
||||
|
||||
override void DrawWeapon( double TicFrac, double bx, double by, Vector2 hs, Vector2 ss )
|
||||
{
|
||||
static const Class<Ammo> types[] = {"RedShell","GreenShell","WhiteShell","BlueShell","BlackShell","PurpleShell","GoldShell"};
|
||||
|
|
@ -122,6 +431,7 @@ Class Spreadgun : SWWMWeapon
|
|||
action void A_DropShell()
|
||||
{
|
||||
static const Class<Ammo> types[] = {"RedShell","GreenShell","WhiteShell","BlueShell","BlackShell","PurpleShell","GoldShell"};
|
||||
static const Class<Actor> casetypes[] = {"RedShellCasing","GreenShellCasing","WhiteShellCasing","BlueShellCasing","BlackShellCasing","PurpleShellCasing","GoldShellCasing"};
|
||||
if ( !invoker.fired )
|
||||
{
|
||||
for ( int i=0; i<7; i++ )
|
||||
|
|
@ -131,7 +441,81 @@ Class Spreadgun : SWWMWeapon
|
|||
break;
|
||||
}
|
||||
}
|
||||
else Console.Printf("// TODO drop spent shell");
|
||||
else
|
||||
{
|
||||
for ( int i=0; i<7; i++ )
|
||||
{
|
||||
if ( invoker.loadammo != types[i] ) continue;
|
||||
Vector3 x, y, z;
|
||||
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
|
||||
Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x-10*z);
|
||||
let c = Spawn(casetypes[i],origin);
|
||||
c.angle = angle;
|
||||
c.pitch = pitch;
|
||||
c.vel = x*FRandom[Junk](-.2,.2)+y*FRandom[Junk](-.2,.2)-(0,0,FRandom[Junk](2,3));
|
||||
c.vel += vel*.5;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action void ProcessTraceHit( SpreadgunTracer t, Vector3 origin, Vector3 dir, int dmg, double mm, Class<Actor> impact = "SpreadImpact", int bc = 1, bool large = false )
|
||||
{
|
||||
for ( int i=0; i<t.ShootThroughList.Size(); i++ )
|
||||
t.ShootThroughList[i].Activate(self,0,SPAC_PCross);
|
||||
for ( int i=0; i<t.WaterHitList.Size(); i++ )
|
||||
{
|
||||
let b = Spawn(large?"InvisibleSplasher":"SmolInvisibleSplasher",t.WaterHitList[i].hitpos);
|
||||
b.A_CheckTerrain();
|
||||
}
|
||||
for ( int i=5; i<t.Results.Distance; i+=10 )
|
||||
{
|
||||
if ( !Random[Boolet](0,bc) ) continue;
|
||||
let b = Actor.Spawn("SWWMBubble",level.Vec3Offset(origin,dir*i));
|
||||
b.Scale *= FRandom[Boolet](.1,.3);
|
||||
}
|
||||
for ( int i=0; i<t.HitList.Size(); i++ )
|
||||
{
|
||||
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));
|
||||
if ( t.HitList[i].HitActor.bNOBLOOD || t.HitList[i].HitActor.bINVULNERABLE )
|
||||
{
|
||||
let p = Spawn(impact,t.HitList[i].HitLocation);
|
||||
p.angle = atan2(t.HitList[i].x.y,t.HitList[i].x.x)+180;
|
||||
p.pitch = asin(t.HitList[i].x.z);
|
||||
}
|
||||
else
|
||||
{
|
||||
t.HitList[i].HitActor.TraceBleed(realdmg,self);
|
||||
t.HitList[i].HitActor.SpawnBlood(t.HitList[i].HitLocation,atan2(t.HitList[i].x.y,t.HitList[i].x.x)+180,realdmg);
|
||||
if ( large ) t.HitList[i].HitActor.A_StartSound("spreadgun/slugf",CHAN_BODY,CHANF_OVERLAP,1.,2.);
|
||||
else t.HitList[i].HitActor.A_StartSound("spreadgun/pelletf",CHAN_BODY,CHANF_OVERLAP,.4,4.);
|
||||
}
|
||||
}
|
||||
if ( t.Results.HitType != TRACE_HitNone )
|
||||
{
|
||||
Vector3 hitnormal = -t.Results.HitVector;
|
||||
if ( t.Results.HitType == TRACE_HitFloor )
|
||||
{
|
||||
if ( t.Results.FFloor ) hitnormal = -t.Results.FFloor.top.Normal;
|
||||
else hitnormal = t.Results.HitSector.floorplane.Normal;
|
||||
}
|
||||
else if ( t.Results.HitType == TRACE_HitCeiling )
|
||||
{
|
||||
if ( t.Results.FFloor ) hitnormal = -t.Results.FFloor.bottom.Normal;
|
||||
else hitnormal = t.Results.HitSector.ceilingplane.Normal;
|
||||
}
|
||||
else if ( t.Results.HitType == TRACE_HitWall )
|
||||
{
|
||||
hitnormal = (-t.Results.HitLine.delta.y,t.Results.HitLine.delta.x,0).unit();
|
||||
if ( !t.Results.Side ) hitnormal *= -1;
|
||||
}
|
||||
let p = Spawn(impact,t.Results.HitPos+hitnormal*4);
|
||||
p.angle = atan2(hitnormal.y,hitnormal.x);
|
||||
p.pitch = asin(-hitnormal.z);
|
||||
if ( t.Results.HitLine ) t.Results.HitLine.RemoteActivate(self,t.Results.Side,SPAC_Impact,t.Results.HitPos);
|
||||
}
|
||||
}
|
||||
|
||||
action void A_FireShell()
|
||||
|
|
@ -142,7 +526,6 @@ Class Spreadgun : SWWMWeapon
|
|||
static const int louds[] = {800,1000,1100,1200,1400,600,2500};
|
||||
static const int quakes[] = {3,4,2,4,3,1,6};
|
||||
static const Color cols[] = {Color(40,255,192,64),Color(36,255,192,80),Color(64,255,160,32),Color(48,32,176,255),Color(72,255,128,16),Color(24,255,224,96),Color(96,255,224,16)};
|
||||
Console.Printf("// TODO fire shell");
|
||||
for ( int i=0; i<7; i++ )
|
||||
{
|
||||
if ( invoker.loadammo != types[i] ) continue;
|
||||
|
|
@ -153,6 +536,108 @@ Class Spreadgun : SWWMWeapon
|
|||
A_ZoomFactor(1.+quakes[i]*.04,ZOOM_INSTANT);
|
||||
A_ZoomFactor(1.);
|
||||
SWWMHandler.DoFlash(self,cols[i],5);
|
||||
Vector3 x, y, z;
|
||||
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
|
||||
Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+2*y-2*z);
|
||||
Vector3 x2, y2, z2;
|
||||
[x2, y2, z2] = swwm_CoordUtil.GetAxes(BulletSlope(),angle,roll);
|
||||
double a, s;
|
||||
Vector3 dir;
|
||||
SpreadgunTracer st;
|
||||
SpreadSlugTracer sst;
|
||||
switch ( i )
|
||||
{
|
||||
case 1:
|
||||
sst = new("SpreadSlugTracer");
|
||||
sst.ignoreme = self;
|
||||
sst.penetration = 250.;
|
||||
a = FRandom[Spreadgun](0,360);
|
||||
s = FRandom[Spreadgun](0,.01);
|
||||
dir = (x2+y2*cos(a)*s+z2*sin(a)*s).unit();
|
||||
sst.hitlist.Clear();
|
||||
sst.shootthroughlist.Clear();
|
||||
sst.waterhitlist.Clear();
|
||||
sst.Trace(origin,level.PointInSector(origin.xy),dir,8000.,0);
|
||||
ProcessTraceHit(sst,origin,dir,0,12000,"SlugImpact",1,true);
|
||||
for ( int i=0; i<3; i++ )
|
||||
{
|
||||
let s = Spawn("SWWMViewSmoke",origin);
|
||||
SWWMViewSmoke(s).ofs = (15,3,-3);
|
||||
s.target = self;
|
||||
s.SetShade(Color(1,1,1)*Random[Spreadgun](96,192));
|
||||
s.alpha *= 0.5;
|
||||
}
|
||||
for ( int i=0; i<6; i++ )
|
||||
{
|
||||
let s = Spawn("SWWMSmoke",origin);
|
||||
s.scale *= .8;
|
||||
s.alpha *= .3;
|
||||
s.SetShade(Color(1,1,1)*Random[Spreadgun](96,192));
|
||||
s.vel += vel*.5+x*FRandom[Spreadgun](3.,5.);
|
||||
}
|
||||
for ( int i=0; i<10; i++ )
|
||||
{
|
||||
let s = Spawn("SWWMSpark",origin);
|
||||
s.scale *= .2;
|
||||
s.alpha *= .4;
|
||||
s.vel += vel*.5+x*FRandom[Spreadgun](4.,8.)+y*FRandom[Spreadgun](-1,1)+z*FRandom[Spreadgun](-1,1);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
Console.Printf("\cg// TODO Dragon's Breath\c-");
|
||||
break;
|
||||
case 3:
|
||||
Console.Printf("\cg// TODO Kinylum Saltshot\c-");
|
||||
break;
|
||||
case 4:
|
||||
Console.Printf("\cg// TODO Napalm Rounds\c-");
|
||||
break;
|
||||
case 5:
|
||||
Console.Printf("\cg// TODO The Ball\c-");
|
||||
break;
|
||||
case 6:
|
||||
Console.Printf("\cg// TODO Golden Shell\c-");
|
||||
break;
|
||||
default:
|
||||
st = new("SpreadgunTracer");
|
||||
st.ignoreme = self;
|
||||
for ( int j=0; j<30; j++ )
|
||||
{
|
||||
a = FRandom[Spreadgun](0,360);
|
||||
s = FRandom[Spreadgun](0,.22);
|
||||
dir = (x2+y2*cos(a)*s+z2*sin(a)*s).unit();
|
||||
st.hitlist.Clear();
|
||||
st.shootthroughlist.Clear();
|
||||
st.waterhitlist.Clear();
|
||||
st.Trace(origin,level.PointInSector(origin.xy),dir,8000.,0);
|
||||
ProcessTraceHit(st,origin,dir,6,7000,bc:5);
|
||||
}
|
||||
for ( int i=0; i<9; i++ )
|
||||
{
|
||||
let s = Spawn("SWWMViewSmoke",origin);
|
||||
SWWMViewSmoke(s).ofs = (15,3,-3);
|
||||
s.target = self;
|
||||
s.SetShade(Color(1,1,1)*Random[Spreadgun](96,192));
|
||||
s.alpha *= .2;
|
||||
}
|
||||
for ( int i=0; i<16; i++ )
|
||||
{
|
||||
let s = Spawn("SWWMSmoke",origin);
|
||||
s.special1 = 1;
|
||||
s.scale *= .9;
|
||||
s.alpha *= .3;
|
||||
s.SetShade(Color(1,1,1)*Random[Spreadgun](96,192));
|
||||
s.vel += vel*.5+x*FRandom[Spreadgun](3.,5.)+y*FRandom[Spreadgun](-1,1)+z*FRandom[Spreadgun](-1,1);
|
||||
}
|
||||
for ( int i=0; i<20; i++ )
|
||||
{
|
||||
let s = Spawn("SWWMSpark",origin);
|
||||
s.scale *= .3;
|
||||
s.alpha *= .4;
|
||||
s.vel += vel*.5+x*FRandom[Spreadgun](4.,8.)+y*FRandom[Spreadgun](-2,2)+z*FRandom[Spreadgun](-2,2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
A_StartSound("spreadgun/hammer",CHAN_WEAPON,CHANF_OVERLAP);
|
||||
|
|
@ -185,7 +670,6 @@ Class Spreadgun : SWWMWeapon
|
|||
Ammo a = Ammo(other.FindInventory(types[i]));
|
||||
if ( !a ) continue;
|
||||
nextammo = types[i];
|
||||
Ammo1 = a;
|
||||
return;
|
||||
}
|
||||
nextammo = AmmoType1;
|
||||
|
|
@ -206,17 +690,21 @@ Class Spreadgun : SWWMWeapon
|
|||
int ridx;
|
||||
if ( rev )
|
||||
{
|
||||
ridx = (cur-i)%7;
|
||||
if ( ridx < 0 ) ridx = 6;
|
||||
ridx = cur-i;
|
||||
if ( ridx < 0 ) break;
|
||||
}
|
||||
else ridx = (i+cur+1)%7;
|
||||
if ( CountInv(types[ridx]) <= 0 ) continue;
|
||||
next = ridx;
|
||||
break;
|
||||
}
|
||||
if ( rev && (invoker.nextammo == types[next]) )
|
||||
{
|
||||
A_SwitchAmmoType(false); // recheck forward
|
||||
return;
|
||||
}
|
||||
if ( invoker.nextammo != types[next] ) A_StartSound("misc/invchange",CHAN_WEAPONEXTRA,CHANF_UI|CHANF_LOCAL);
|
||||
invoker.nextammo = types[next];
|
||||
invoker.Ammo1 = Ammo(FindInventory(invoker.nextammo));
|
||||
A_WeaponReady(WRF_NOFIRE);
|
||||
}
|
||||
|
||||
|
|
@ -532,25 +1020,67 @@ Class Spreadgun : SWWMWeapon
|
|||
XZWK FGHI 2;
|
||||
Goto ReadyFired;
|
||||
FlashRed:
|
||||
XZWZ A 2 Bright;
|
||||
XZWZ A 2 Bright
|
||||
{
|
||||
let l = Spawn("SWWMWeaponLight",pos);
|
||||
l.args[3] = 120;
|
||||
l.target = self;
|
||||
}
|
||||
Stop;
|
||||
FlashGreen:
|
||||
XZWZ B 2 Bright;
|
||||
XZWZ B 2 Bright
|
||||
{
|
||||
let l = Spawn("SWWMWeaponLight",pos);
|
||||
l.args[3] = 90;
|
||||
l.target = self;
|
||||
}
|
||||
Stop;
|
||||
FlashWhite:
|
||||
XZWZ C 2 Bright;
|
||||
XZWZ C 2 Bright
|
||||
{
|
||||
let l = Spawn("SWWMWeaponLight",pos);
|
||||
l.args[1] = 176;
|
||||
l.args[2] = 32;
|
||||
l.args[3] = 160;
|
||||
l.target = self;
|
||||
}
|
||||
Stop;
|
||||
FlashBlue:
|
||||
XZWZ D 2 Bright;
|
||||
XZWZ D 2 Bright
|
||||
{
|
||||
let l = Spawn("SWWMWeaponLight",pos);
|
||||
l.args[0] = 96;
|
||||
l.args[1] = 224;
|
||||
l.args[2] = 255;
|
||||
l.args[3] = 160;
|
||||
l.target = self;
|
||||
}
|
||||
Stop;
|
||||
FlashBlack:
|
||||
XZWZ E 2 Bright;
|
||||
XZWZ E 2 Bright
|
||||
{
|
||||
let l = Spawn("SWWMWeaponLight",pos);
|
||||
l.args[1] = 144;
|
||||
l.args[2] = 16;
|
||||
l.args[3] = 280;
|
||||
l.target = self;
|
||||
}
|
||||
Stop;
|
||||
FlashPurple:
|
||||
XZWZ F 2 Bright;
|
||||
XZWZ F 2 Bright
|
||||
{
|
||||
let l = Spawn("SWWMWeaponLight",pos);
|
||||
l.args[3] = 60;
|
||||
l.target = self;
|
||||
}
|
||||
Stop;
|
||||
FlashGold:
|
||||
XZWZ G 2 Bright;
|
||||
XZWZ G 2 Bright
|
||||
{
|
||||
let l = Spawn("SWWMWeaponLight",pos);
|
||||
l.args[3] = 300;
|
||||
l.target = self;
|
||||
}
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -318,7 +318,7 @@ Class ExplodiumGun : SWWMWeapon
|
|||
int dmg = 40;
|
||||
SWWMHandler.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 )
|
||||
if ( d.HitActor.bNOBLOOD || d.HitActor.bINVULNERABLE )
|
||||
{
|
||||
let p = Spawn("SWWMBulletImpact",d.HitLocation);
|
||||
p.angle = atan2(d.HitDir.y,d.HitDir.x)+180;
|
||||
|
|
|
|||
|
|
@ -825,7 +825,7 @@ Class CandyGun : SWWMWeapon
|
|||
int dmg = 350;
|
||||
SWWMHandler.DoKnockback(d.HitActor,d.HitDir,72000);
|
||||
dmg = d.HitActor.DamageMobj(invoker,self,dmg,'Explodium',DMG_USEANGLE|DMG_THRUSTLESS,atan2(d.HitDir.y,d.HitDir.x));
|
||||
if ( d.HitActor.bNOBLOOD )
|
||||
if ( d.HitActor.bNOBLOOD || d.HitActor.bINVULNERABLE )
|
||||
{
|
||||
let p = Spawn("SWWMBulletImpact",d.HitLocation);
|
||||
p.angle = atan2(d.HitDir.y,d.HitDir.x)+180;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue