stinger_m/zscript/upowerups.zsc
Marisa Kirisame 225ffcc1e9 Overhaul to how reloading works, not much else has happened.
Addition to HUD for showing clip counts (kinda cheap-looking, but still better than what Oldskool did).
Charge for some weapons and loaded rockets for eightball also use the clipcount display, like in Doom Tournament.
Small fixups for dual wielding logic.
2019-09-17 02:47:13 +02:00

562 lines
14 KiB
Text

Class UInvisibility : UnrealInventory
{
Default
{
Tag "$T_INVISIBILITY";
+COUNTITEM;
+INVENTORY.BIGPOWERUP;
+INVENTORY.ALWAYSPICKUP;
Inventory.Icon "I_Invis";
Inventory.PickupMessage "$I_INVISIBILITY";
Inventory.RespawnTics 3500;
Inventory.MaxAmount 1;
UnrealInventory.Charge 100;
}
override bool Use( bool pickup )
{
if ( pickup ) return false;
bActive = !bActive;
if ( bActive )
{
Owner.A_PlaySound("invis/pickup",CHAN_ITEM);
Owner.GiveInventory("PowerUInvisibility",1);
}
else Owner.TakeInventory("PowerUInvisibility",1);
return false;
}
override void DoEffect()
{
Super.DoEffect();
if ( !bActive ) return;
if ( special1 == -1 )
{
Owner.TakeInventory("PowerUInvisibility",1);
special1 = 3;
}
else if ( special1 > 1 ) special1--;
else if ( special1 == 1 )
{
Owner.GiveInventory("PowerUInvisibility",1);
special1 = 0;
}
if ( !(level.maptime%35) && DrainCharge(1) )
{
if ( Owner.CheckLocalView() ) Console.Printf(StringTable.Localize("$D_INVISIBILITY"));
Owner.TakeInventory("PowerUInvisibility",1);
DepleteOrDestroy();
}
}
override void OnDrop( Actor dropper )
{
Super.OnDrop(dropper);
dropper.TakeInventory("PowerUInvisibility",1);
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
tracer = Spawn("UInvisibilityX",pos);
tracer.angle = angle;
tracer.target = self;
}
States
{
Spawn:
INVS A -1;
Stop;
}
}
Class UInvisibilityX : AsmdAmmoX
{
States
{
Spawn:
INVS A -1 Bright;
Stop;
}
}
Class PowerUInvisibility : PowerInvisibility
{
Default
{
Powerup.Duration 0x7FFFFFFD;
Powerup.Strength 90;
Powerup.Mode "Additive";
}
}
Class Amplifier : UnrealInventory
{
Default
{
Tag "$T_AMPLIFIER";
+COUNTITEM;
+INVENTORY.BIGPOWERUP;
+INVENTORY.ALWAYSPICKUP;
Inventory.Icon "I_Amp";
Inventory.PickupMessage "$I_AMPLIFIER";
Inventory.RespawnTics 3150;
Inventory.MaxAmount 1;
UnrealInventory.Charge 1000;
}
static double GetMult( Actor Owner, int val )
{
if ( !Owner ) return 1.;
let d = Amplifier(Owner.FindInventory("Amplifier"));
if ( !d || !d.bActive ) return 1.;
double Multiplier = max(1,4*(double(d.Charge-val)/d.DefaultCharge));
d.DrainCharge(val);
return Multiplier;
}
override bool Use( bool pickup )
{
if ( pickup ) return false;
bActive = !bActive;
Owner.A_PlaySound("amplifier/set",CHAN_ITEM);
return false;
}
override void DoEffect()
{
Super.DoEffect();
if ( bActive && !tracer )
{
tracer = Spawn("AmpSound",Owner.pos);
tracer.target = Owner;
tracer.master = self;
}
else if ( !bActive && tracer ) tracer.Destroy();
if ( !bActive ) return;
if ( (Charge <= 0) || (!(level.maptime%35) && DrainCharge(2)) )
{
Owner.A_PlaySound("amplifier/set",CHAN_ITEM);
if ( Owner.CheckLocalView() ) Console.Printf(StringTable.Localize("$D_AMPLIFIER"));
if ( tracer ) tracer.Destroy();
DepleteOrDestroy();
}
}
States
{
Spawn:
AMPP A -1;
Stop;
}
}
Class AmpSound : Actor
{
Default
{
+NOBLOCKMAP;
+NOGRAVITY;
}
override void Tick()
{
Super.Tick();
if ( !target || !master )
{
Destroy();
return;
}
SetOrigin(target.pos,true);
if ( target.CheckLocalView() )
{
A_SoundVolume(CHAN_VOICE,0.0);
A_SoundVolume(CHAN_7,1.0);
}
else
{
A_SoundVolume(CHAN_VOICE,0.25);
A_SoundVolume(CHAN_7,0.0);
}
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
A_PlaySound("amplifier/act",CHAN_VOICE,0.25,true,1.5);
A_PlaySound("amplifier/act",CHAN_7,1.0,true,ATTN_NONE);
}
override void OnDestroy()
{
Super.OnDestroy();
A_StopSound(CHAN_VOICE);
A_StopSound(CHAN_7);
}
}
Class UJumpBoots : UnrealInventory
{
int draincnt;
Default
{
Tag "$T_LBOOTS";
+COUNTITEM;
+INVENTORY.BIGPOWERUP;
+INVENTORY.ALWAYSPICKUP;
Inventory.Icon "I_Boots";
Inventory.PickupMessage "$I_LBOOTS";
Inventory.RespawnTics 1050;
Inventory.MaxAmount 1;
UnrealInventory.Charge 3;
}
override bool Use( bool pickup )
{
if ( pickup ) return false;
bActive = !bActive;
Owner.A_PlaySound("boot/pickup",CHAN_ITEM);
if ( bActive ) Owner.GiveInventory("PowerJumpBoots_HighJump",1);
else Owner.TakeInventory("PowerJumpBoots_HighJump",1);
return false;
}
override void DoEffect()
{
Super.DoEffect();
if ( !Owner || !Owner.player ) return;
draincnt++;
if ( (draincnt >= 700) || (bActive && (owner.player.jumptics == -1)) )
{
draincnt = 0;
charge--;
Owner.A_PlaySound("boot/jump",CHAN_BODY);
}
else if ( (charge <= 0) && owner.player.onground )
{
if ( Owner.CheckLocalView() ) Console.Printf(StringTable.Localize("$D_LBOOTS"));
Amount--;
Owner.TakeInventory("PowerJumpBoots_HighJump",1);
charge = defaultcharge;
bActive = false;
if ( Amount <= 0 ) DepleteOrDestroy();
}
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
if ( (level.maptime > 0) || !InStateSequence(CurState,FindState("Spawn")) ) return;
// detect hurtfloors
// can't detect terraindef-based damage
// this is currently an engine limitation
bool foundslime = false;
bool foundlava = false;
bool foundswim = false;
for ( int i=0; i<level.Sectors.Size(); i++ )
{
Sector s = level.Sectors[i];
if ( s.MoreFlags&(Sector.SECMF_UNDERWATER|Sector.SECMF_FORCEDUNDERWATER) ) foundswim = true;
for ( int i=0; i<s.Get3DFloorCount(); i++ )
if ( s.Get3DFloor(i).flags&F3DFloor.FF_SWIMMABLE ) foundswim = true;
if ( !s.DamageInterval || !s.DamageAmount ) continue;
if ( s.DamageType == 'Slime' ) foundslime = true;
else if ( s.DamageType == 'Fire' ) foundlava = true;
}
// random chance to ignore if a replacement already was made
let ti = ThinkerIterator.Create("Inventory");
Inventory a;
while ( a = Inventory(ti.Next()) )
{
// exclude owned items
if ( a.Owner ) continue;
if ( (a is "ToxinSuit") && Random[LBootRep](0,2) )
foundslime = false;
if ( (a is "AsbestosSuit") && Random[LBootRep](0,2) )
foundlava = false;
if ( (a is "SCUBAGear") && Random[LBootRep](0,2) )
foundswim = false;
}
// replace self with asbestos/toxin suits or scuba
// this is extremely naive and doesn't check proximity to the
// hurtfloor/swimmable, but it's better than nothing
Array<String> replacements;
replacements.Clear();
if ( foundslime ) replacements.Push("ToxinSuit");
if ( foundlava ) replacements.Push("AsbestosSuit");
if ( foundswim ) replacements.Push("SCUBAGear");
if ( replacements.Size() > 0 )
{
int rslot = Random[LBootRep](0,replacements.Size()-1);
let r = Spawn(replacements[rslot],pos,ALLOW_REPLACE);
r.spawnangle = spawnangle;
r.spawnpoint = spawnpoint;
r.angle = angle;
r.pitch = pitch;
r.roll = roll;
r.special = special;
r.args[0] = args[0];
r.args[1] = args[1];
r.args[2] = args[2];
r.args[3] = args[3];
r.args[4] = args[4];
r.ChangeTid(tid);
r.SpawnFlags = SpawnFlags&~MTF_SECRET;
r.HandleSpawnFlags();
r.SpawnFlags = SpawnFlags;
r.bCountSecret = SpawnFlags&MTF_SECRET;
r.vel = vel;
r.master = master;
r.target = target;
r.tracer = tracer;
r.bDropped = bDropped;
Destroy();
}
}
override void AttachToOwner( Actor Other )
{
Super.AttachToOwner(Other);
Other.GiveInventory("PowerJumpBoots_IronFeet",1);
}
override void DetachFromOwner()
{
Super.DetachFromOwner();
Owner.TakeInventory("PowerJumpBoots_HighJump",1);
Owner.TakeInventory("PowerJumpBoots_IronFeet",1);
}
States
{
Spawn:
JBUT A -1;
Stop;
}
}
Class MotionDetector : UnrealInventory
{
ui TextureID DetHud, DetSpot[2];
Array<Actor> nearscan;
Default
{
Tag "$T_DETECTOR";
+COUNTITEM;
+INVENTORY.BIGPOWERUP;
+INVENTORY.ALWAYSPICKUP;
Inventory.MaxAmount 1;
Inventory.Icon "I_Detect";
Inventory.PickupMessage "$I_DETECTOR";
Inventory.RespawnTics 1050;
UnrealInventory.Charge 7000;
}
override bool TryPickup( in out Actor toucher )
{
bool valid = Super.TryPickup(toucher);
if ( valid ) level.allmap = true;
return valid;
}
override void PostRender( double lbottom )
{
if ( !bActive ) return;
double xpos = UnrealHUD(StatusBar).ClipX-96;
double ypos = 0;
// offset if inventory display present on top right
if ( UnrealHUD(StatusBar).HudMode < 2 ) ypos += 32;
if ( DetHud.IsNull() ) DetHud = TexMan.CheckForTexture("DetHud",TexMan.Type_Any);
if ( DetSpot[0].IsNull() ) DetSpot[0] = TexMan.CheckForTexture("DetSpot0",TexMan.Type_Any);
if ( DetSpot[1].IsNull() ) DetSpot[1] = TexMan.CheckForTexture("DetSpot1",TexMan.Type_Any);
Screen.DrawTexture(DetHud,false,xpos,ypos,DTA_VirtualWidthF,UnrealHUD(StatusBar).ClipX,DTA_VirtualHeightF,UnrealHUD(StatusBar).ClipY,DTA_KeepRatio,true);
double alph = max(0.,0.25+0.75*sin((gametic+UnrealHUD(StatusBar).fractic)*6.));
Screen.Dim(Color("FF 40 00"),alph*.25,int((xpos+3)*UnrealHUD(StatusBar).scalev.x),int((ypos+3)*UnrealHUD(StatusBar).scalev.y),int(90*UnrealHUD(StatusBar).scalev.x),int(90*UnrealHUD(StatusBar).scalev.y));
Screen.DrawTexture(DetSpot[0],false,xpos+48,ypos+48,DTA_VirtualWidthF,UnrealHUD(StatusBar).ClipX,DTA_VirtualHeightF,UnrealHUD(StatusBar).ClipY,DTA_KeepRatio,true);
alph = max(0.,0.5+0.5*sin((gametic+UnrealHUD(StatusBar).fractic-10)*6.));
for ( int i=0; i<nearscan.Size(); i++ )
{
Vector2 absofs = level.Vec2Diff(Owner.pos.xy,nearscan[i].pos.xy);
absofs *= (96./2048.);
double ang = Owner.angle-90;
Vector2 relofs = (absofs.x*cos(ang)+absofs.y*sin(ang),-absofs.y*cos(ang)+absofs.x*sin(ang));
if ( max(abs(relofs.x),abs(relofs.y)) > 48. ) continue;
// this is a long line, but it's not the longest I've ever seen
// oh I have seen things... php code that would make you want to stab your eyes with forks...
Screen.DrawTexture(DetSpot[1],false,xpos+48+relofs.x,ypos+48+relofs.y,DTA_VirtualWidthF,UnrealHUD(StatusBar).ClipX,DTA_VirtualHeightF,UnrealHUD(StatusBar).ClipY,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_ClipLeft,int((xpos+3)*UnrealHUD(StatusBar).scalev.x),DTA_ClipTop,int((ypos+3)*UnrealHUD(StatusBar).scalev.y),DTA_ClipRight,int((xpos+93)*UnrealHUD(StatusBar).scalev.x),DTA_ClipBottom,int((ypos+93)*UnrealHUD(StatusBar).scalev.y));
}
}
override bool Use( bool pickup )
{
if ( pickup ) return false;
bActive = !bActive;
if ( bActive ) Owner.A_PlaySound("detector/start",CHAN_ITEM);
else Owner.A_PlaySound("detector/stop",CHAN_ITEM,0.1,false,3.);
return false;
}
override void DoEffect()
{
Super.DoEffect();
if ( bActive && !tracer )
{
tracer = Spawn("DetectorSound",Owner.pos);
tracer.target = Owner;
tracer.master = self;
}
else if ( !bActive && tracer ) tracer.Destroy();
if ( !bActive ) return;
nearscan.Clear();
let bi = BlockThingsIterator.Create(Owner,2048);
while ( bi.Next() )
{
if ( !bi.Thing || (bi.Thing == Owner) || !bi.Thing.bISMONSTER || bi.Thing.Health <= 0 ) continue;
nearscan.Push(bi.Thing);
}
if ( (Charge <= 0) || DrainCharge(1) )
{
Owner.A_PlaySound("detector/stop",CHAN_ITEM,0.1,false,3.);
if ( Owner.CheckLocalView() ) Console.Printf(StringTable.Localize("$D_DETECTOR"));
if ( tracer ) tracer.Destroy();
DepleteOrDestroy();
}
}
States
{
Spawn:
MDET A -1;
Stop;
}
}
Class DetectorSound : Actor
{
Default
{
+NOBLOCKMAP;
+NOGRAVITY;
}
override void Tick()
{
Super.Tick();
if ( !target || !master )
{
Destroy();
return;
}
SetOrigin(target.pos,true);
A_SoundVolume(CHAN_VOICE,target.CheckLocalView()?0.1:0.0);
A_SoundVolume(CHAN_7,!target.CheckLocalView()?0.1:0.0);
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
A_PlaySound("detector/active",CHAN_VOICE,0.1,true,ATTN_NONE);
A_PlaySound("detector/active",CHAN_7,0.1,true,3.);
}
override void OnDestroy()
{
Super.OnDestroy();
A_StopSound(CHAN_VOICE);
A_StopSound(CHAN_7);
}
}
Class SCUBAGear : UnrealInventory
{
int oldwaterlevel;
Default
{
Tag "$T_SCUBA";
Inventory.MaxAmount 1;
Inventory.Icon "I_Scuba";
Inventory.PickupMessage "$I_SCUBA";
Inventory.RespawnTics 700;
UnrealInventory.Charge 4200;
}
override bool Use( bool pickup )
{
if ( pickup ) return false;
bActive = !bActive;
if ( !bActive ) Owner.A_PlaySound("scuba/stop",CHAN_ITEM);
return false;
}
override void AttachToOwner( Actor other )
{
Super.AttachToOwner(other);
oldwaterlevel = other.waterlevel;
}
override void AbsorbDamage( int damage, Name damageType, out int newdamage )
{
if ( bActive && (damageType == 'Drowning') )
newdamage = 0;
}
override void DoEffect()
{
Super.DoEffect();
if ( (oldwaterlevel < 2) && (owner.waterlevel > 2) )
{
if ( sting_autoscuba && !bActive ) Use(false);
oldwaterlevel = owner.waterlevel;
}
else if ( (oldwaterlevel > 2) && (owner.waterlevel < 2) )
{
if ( sting_autoscuba && bActive ) Use(false);
oldwaterlevel = owner.waterlevel;
}
if ( bActive && !tracer )
{
tracer = Spawn("SCUBASound",Owner.pos);
tracer.target = Owner;
tracer.master = self;
}
else if ( !bActive && tracer ) tracer.Destroy();
if ( !bActive ) return;
if ( PlayerPawn(Owner) ) PlayerPawn(Owner).ResetAirSupply();
if ( (Charge <= 0) || DrainCharge(1) )
{
Owner.A_PlaySound("scuba/stop",CHAN_ITEM);
if ( Owner.CheckLocalView() ) Console.Printf(StringTable.Localize("$D_SCUBA"));
if ( tracer ) tracer.Destroy();
DepleteOrDestroy();
}
}
States
{
Spawn:
SCUB A -1;
Stop;
}
}
Class SCUBASound : Actor
{
Default
{
+NOBLOCKMAP;
+NOGRAVITY;
}
override void Tick()
{
Super.Tick();
if ( !target || !master )
{
Destroy();
return;
}
SetOrigin(target.pos,true);
if ( target.CheckLocalView() )
{
A_SoundVolume(CHAN_VOICE,0.0);
A_SoundVolume(CHAN_5,0.0);
A_SoundVolume(CHAN_6,(target.waterlevel<3)?1.0:0.0);
A_SoundVolume(CHAN_7,(target.waterlevel>=3)?1.0:0.0);
}
else
{
A_SoundVolume(CHAN_VOICE,(target.waterlevel<3)?0.25:0.0);
A_SoundVolume(CHAN_5,(target.waterlevel>=3)?0.25:0.0);
A_SoundVolume(CHAN_6,0.0);
A_SoundVolume(CHAN_7,0.0);
}
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
A_PlaySound("scuba/air",CHAN_VOICE,0.25,true,1.5);
A_PlaySound("scuba/water",CHAN_5,0.25,true,1.5);
A_PlaySound("scuba/air",CHAN_6,1.0,true,ATTN_NONE);
A_PlaySound("scuba/water",CHAN_7,1.0,true,ATTN_NONE);
}
override void OnDestroy()
{
Super.OnDestroy();
A_StopSound(CHAN_VOICE);
A_StopSound(CHAN_5);
A_StopSound(CHAN_6);
A_StopSound(CHAN_7);
}
}