Adjust SCUBA Gear autouse behaviour so it works properly with manual use. Add 3D floor handling code on various things. Increased size of Eightball explosions to match original game. Fix invisibility playing no sound when activated.
562 lines
14 KiB
Text
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 2;
|
|
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 2;
|
|
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.MaxAmount 3;
|
|
Inventory.Icon "I_Boots";
|
|
Inventory.PickupMessage "$I_LBOOTS";
|
|
Inventory.RespawnTics 1050;
|
|
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);
|
|
}
|
|
}
|