Add SMP 7243 from Oldskool to the BFG pool (toggleable). Random fixarounds. Spent mag models for the pistols, will be used (and backported to DT) soon.
1031 lines
21 KiB
Text
1031 lines
21 KiB
Text
// Backpack that only gives ammo for valid weapons
|
|
Class UnrealBackpack : BackpackItem replaces Backpack
|
|
{
|
|
override Inventory CreateCopy( Actor other )
|
|
{
|
|
// Find every unique type of ammoitem. Give it to the player if
|
|
// he doesn't have it already, and double 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;
|
|
if ( (weap.AmmoType1 == type) || (weap.AmmoType2 == type) )
|
|
{
|
|
isvalid = true;
|
|
break;
|
|
}
|
|
}
|
|
if ( !isvalid ) continue;
|
|
let ammoitem = Ammo(other.FindInventory(type));
|
|
int amount = GetDefaultByType(type).BackpackAmount;
|
|
// extra ammo in baby mode and nightmare mode
|
|
if ( !bIgnoreSkill ) amount = int(amount*G_SkillPropertyFloat(SKILLP_AmmoFactor));
|
|
if ( amount < 0 ) amount = 0;
|
|
if ( !ammoitem )
|
|
{
|
|
// The player did not have the ammoitem. Add it.
|
|
ammoitem = Ammo(Spawn(type));
|
|
ammoitem.Amount = bDepleted?0:amount;
|
|
if ( ammoitem.BackpackMaxAmount > ammoitem.MaxAmount )
|
|
ammoitem.MaxAmount = ammoitem.BackpackMaxAmount;
|
|
if ( ammoitem.Amount > ammoitem.MaxAmount )
|
|
ammoitem.Amount = ammoitem.MaxAmount;
|
|
ammoitem.AttachToOwner(other);
|
|
}
|
|
else
|
|
{
|
|
// The player had the ammoitem. Give some more.
|
|
if ( ammoitem.MaxAmount < ammoitem.BackpackMaxAmount )
|
|
ammoitem.MaxAmount = ammoitem.BackpackMaxAmount;
|
|
if ( !bDepleted && (ammoitem.Amount < ammoitem.MaxAmount) )
|
|
{
|
|
ammoitem.Amount += amount;
|
|
if ( ammoitem.Amount > ammoitem.MaxAmount )
|
|
ammoitem.Amount = ammoitem.MaxAmount;
|
|
}
|
|
}
|
|
}
|
|
return Inventory.CreateCopy(other);
|
|
}
|
|
override bool HandlePickup( Inventory item )
|
|
{
|
|
// Since you already have a backpack, that means you already have every
|
|
// kind of ammo in your inventory, so we don't need to look at the
|
|
// entire PClass list to discover what kinds of ammo exist, and we don't
|
|
// have to alter the MaxAmount either.
|
|
if ( item is 'BackpackItem' )
|
|
{
|
|
for ( let probe = Owner.Inv; probe; probe = probe.Inv )
|
|
{
|
|
if ( probe.GetParentClass() != 'Ammo' ) continue;
|
|
if ( probe.Amount >= probe.MaxAmount && !sv_unlimited_pickup ) continue;
|
|
int amount = Ammo(probe).Default.BackpackAmount;
|
|
// extra ammo in baby mode and nightmare mode
|
|
if ( !bIgnoreSkill )
|
|
amount = int(amount*G_SkillPropertyFloat(SKILLP_AmmoFactor));
|
|
probe.Amount += amount;
|
|
if ( (probe.Amount > probe.MaxAmount) && !sv_unlimited_pickup )
|
|
probe.Amount = probe.MaxAmount;
|
|
}
|
|
// The pickup always succeeds, even if you didn't get anything
|
|
item.bPickupGood = true;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
override void DoPickupSpecial( Actor toucher )
|
|
{
|
|
Super.DoPickupSpecial(toucher);
|
|
if ( gameinfo.gametype&GAME_DOOMCHEX )
|
|
{
|
|
static const Class<Inventory> xitems[] = {"Flare", "Seeds", "SentryItem", "VoiceBox", "ForceField", "Dampener", "Peacemaker"};
|
|
int xitemn[7];
|
|
xitemn[0] = max(0,Random[BackpackExtra](-1,3));
|
|
xitemn[1] = max(0,Random[BackpackExtra](-1,3));
|
|
xitemn[2] = max(0,Random[BackpackExtra](-2,1));
|
|
xitemn[3] = max(0,Random[BackpackExtra](-2,1));
|
|
xitemn[4] = max(0,Random[BackpackExtra](-2,1));
|
|
xitemn[5] = max(0,Random[BackpackExtra](-1,1));
|
|
xitemn[6] = max(0,Random[BackpackExtra](-2,1));
|
|
// random doubling
|
|
if ( !Random[BackpackExtra](0,4) ) xitemn[0] *= 2;
|
|
if ( !Random[BackpackExtra](0,4) ) xitemn[1] *= 2;
|
|
if ( !Random[BackpackExtra](0,9) ) xitemn[2] *= 2;
|
|
if ( !Random[BackpackExtra](0,7) ) xitemn[3] *= 2;
|
|
if ( !Random[BackpackExtra](0,6) ) xitemn[4] *= 2;
|
|
if ( !Random[BackpackExtra](0,5) ) xitemn[5] *= 2;
|
|
if ( !Random[BackpackExtra](0,9) ) xitemn[6] *= 2;
|
|
for ( int i=0; i<7; i++ )
|
|
{
|
|
if ( xitemn[i] <= 0 ) continue;
|
|
toucher.GiveInventory(xitems[i],xitemn[i]);
|
|
}
|
|
}
|
|
}
|
|
Default
|
|
{
|
|
Tag "$T_BACKPACK";
|
|
Inventory.PickupMessage "$I_BACKPACK";
|
|
Inventory.RespawnTics 2100;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
BPAK A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class UTranslator : UnrealInventory
|
|
{
|
|
bool bNewMessage, bNotNewMessage;
|
|
string NewMessage, Hint;
|
|
Array<String> OldMessages, OldHints;
|
|
|
|
override void Travelled()
|
|
{
|
|
Super.Travelled();
|
|
NewMessage = Hint = "";
|
|
OldMessages.Clear();
|
|
OldHints.Clear();
|
|
}
|
|
|
|
override bool Use( bool pickup )
|
|
{
|
|
if ( pickup ) return false;
|
|
if ( Owner.player == players[consoleplayer] )
|
|
Menu.SetMenu('TranslatorMenu');
|
|
bNewMessage = bNotNewmessage = false;
|
|
return false;
|
|
}
|
|
|
|
void AddMessage( String msg, String hnt )
|
|
{
|
|
int found = -1;
|
|
for ( int i=0; i<OldMessages.Size(); i++ )
|
|
{
|
|
if ( OldMessages[i] != msg ) continue;
|
|
found = i;
|
|
}
|
|
if ( found != -1 )
|
|
{
|
|
OldMessages.Delete(found);
|
|
OldHints.Delete(found);
|
|
}
|
|
if ( (NewMessage != msg) && (NewMessage.Length() > 0) )
|
|
{
|
|
OldMessages.Push(NewMessage);
|
|
OldHints.Push(Hint);
|
|
}
|
|
NewMessage = msg;
|
|
Hint = hnt;
|
|
}
|
|
|
|
Default
|
|
{
|
|
Tag "$T_TRANSLATOR";
|
|
Inventory.PickupMessage "$I_TRANSLATOR";
|
|
Inventory.Icon "I_Tran";
|
|
Inventory.MaxAmount 1;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
TRNS A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
// To be placed by mappers
|
|
// Uses two UDMF-settable user strings
|
|
// AMBUSH: only triggered by script activation, not touch
|
|
Class TranslatorEvent : Actor
|
|
{
|
|
String user_message, user_hint;
|
|
Array<Actor> Touchers;
|
|
|
|
Default
|
|
{
|
|
Radius 40;
|
|
Height 80;
|
|
+SPECIAL;
|
|
+NOGRAVITY;
|
|
+INVISIBLE;
|
|
}
|
|
virtual void TriggerMessage( Actor who )
|
|
{
|
|
if ( special1 > gametic ) return;
|
|
let Translator = UTranslator(who.FindInventory("UTranslator"));
|
|
if ( !Translator ) return;
|
|
special1 = gametic+8;
|
|
if ( who.CheckLocalView() )
|
|
{
|
|
if ( special2 ) Console.Printf(StringTable.Localize("$TR_MSG"));
|
|
else Console.Printf(StringTable.Localize("$TR_NEWMSG"));
|
|
S_Sound("translator/event",CHAN_VOICE|CHAN_UI);
|
|
}
|
|
Translator.AddMessage(user_message,user_hint);
|
|
if ( special2 ) Translator.bNotNewMessage = true;
|
|
else Translator.bNewMessage = true;
|
|
special2 = 1;
|
|
}
|
|
// GZDoom doesn't have Touch/UnTouch like UE1 so I have to improvise
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
for ( int i=0; i<Touchers.Size(); i++ )
|
|
{
|
|
bool deletthis = false;
|
|
if ( Touchers[i].pos.x+Touchers[i].radius < pos.x-radius ) deletthis = true;
|
|
if ( Touchers[i].pos.x-Touchers[i].radius > pos.x+radius ) deletthis = true;
|
|
if ( Touchers[i].pos.y+Touchers[i].radius < pos.y-radius ) deletthis = true;
|
|
if ( Touchers[i].pos.y-Touchers[i].radius > pos.y+radius ) deletthis = true;
|
|
if ( Touchers[i].pos.z+Touchers[i].height < pos.z ) deletthis = true;
|
|
if ( Touchers[i].pos.z > pos.z+height ) deletthis = true;
|
|
if ( !deletthis ) continue;
|
|
Touchers.Delete(i);
|
|
i--;
|
|
}
|
|
}
|
|
override void Touch( Actor toucher )
|
|
{
|
|
if ( bAMBUSH || !toucher || !toucher.player ) return;
|
|
for ( int i=0; i<Touchers.Size(); i++ ) if ( Touchers[i] == toucher ) return;
|
|
Touchers.Push(toucher);
|
|
TriggerMessage(toucher);
|
|
}
|
|
override void Activate( Actor activator )
|
|
{
|
|
if ( !activator || !activator.player ) return;
|
|
TriggerMessage(activator);
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
SMSG A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class VoiceBox : UnrealInventory
|
|
{
|
|
Actor box;
|
|
|
|
Default
|
|
{
|
|
Tag "$T_VOICEBOX";
|
|
Inventory.PickupMessage "$I_VOICEBOX";
|
|
Inventory.Icon "I_VoiceB";
|
|
Inventory.MaxAmount 3;
|
|
UnrealInventory.Charge 600;
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( bActive )
|
|
{
|
|
if ( box ) Charge = box.ReactionTime;
|
|
else
|
|
{
|
|
Charge = DefaultCharge;
|
|
bActive = false;
|
|
Amount--;
|
|
if ( Amount <= 0 ) DepleteOrDestroy();
|
|
}
|
|
}
|
|
}
|
|
override bool Use( bool pickup )
|
|
{
|
|
if ( pickup || bActive ) return false;
|
|
Vector3 x, y, z;
|
|
[x, y, z] = dt_CoordUtil.GetAxes(Owner.pitch,Owner.angle,Owner.roll);
|
|
Vector3 origin = Owner.Vec2OffsetZ(0,0,Owner.player.viewz);
|
|
origin = level.Vec3Offset(origin,x*20.-z*8.);
|
|
box = Spawn("VoiceBoxActive",origin);
|
|
box.ReactionTime = Charge;
|
|
box.vel = x*9.;
|
|
box.vel.z += 1.;
|
|
box.target = Owner;
|
|
box.angle = Owner.angle;
|
|
box.pitch = Owner.pitch;
|
|
bActive = true;
|
|
return false;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
VBOX A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class VoiceBoxHitbox : Actor
|
|
{
|
|
Default
|
|
{
|
|
Tag "$T_VOICEBOX";
|
|
Radius 6;
|
|
Height 9;
|
|
Health 60;
|
|
+SHOOTABLE;
|
|
+NOGRAVITY;
|
|
+NOCLIP;
|
|
+DONTSPLASH;
|
|
+NOBLOOD;
|
|
+NOTELEPORT;
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( !master )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
SetOrigin(master.pos,true);
|
|
}
|
|
override void Die( Actor source, Actor inflictor, int dmgflags, Name MeansOfDeath )
|
|
{
|
|
if ( master ) master.ReactionTime = 0;
|
|
Super.Die(source,inflictor,dmgflags,MeansOfDeath);
|
|
}
|
|
}
|
|
|
|
Class VoiceBoxActive : Actor
|
|
{
|
|
Actor b;
|
|
double desiredangle, anglevel, oldangle;
|
|
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
b = Spawn("VoiceBoxHitbox",pos);
|
|
b.master = self;
|
|
desiredangle = FRandom[Junk](0,360);
|
|
anglevel = FRandom[Junk](5,15);
|
|
}
|
|
action void A_VoiceBoxPlay()
|
|
{
|
|
static const String BattleSounds[] =
|
|
{
|
|
"automag/shot",
|
|
"utrl/explode",
|
|
"automag/shot",
|
|
"automag/shot",
|
|
"flak/altfire",
|
|
"utrl/explode",
|
|
"flak/fire",
|
|
"shock/fire",
|
|
"stinger/hit2",
|
|
"automag/shot"
|
|
};
|
|
if ( invoker.b ) invoker.b.A_AlertMonsters(0,AMF_TARGETEMITTER);
|
|
for ( int i=0; i<10; i++ ) if ( !Random[Voicebox](0,30) ) A_PlaySound(BattleSounds[i],CHAN_AUTO,FRandom[Voicebox](0.5,1.0));
|
|
}
|
|
override void Tick()
|
|
{
|
|
oldangle = angle;
|
|
Super.Tick();
|
|
if ( deltaangle(angle,desiredangle) ~== 0 ) angle = desiredangle;
|
|
else angle += clamp(deltaangle(angle,desiredangle),-anglevel,anglevel);
|
|
}
|
|
Default
|
|
{
|
|
Radius 6;
|
|
Height 6;
|
|
PROJECTILE;
|
|
-NOGRAVITY;
|
|
+SKYEXPLODE;
|
|
+MOVEWITHSECTOR;
|
|
+CANBOUNCEWATER;
|
|
+BOUNCEAUTOOFF;
|
|
+BOUNCEAUTOOFFFLOORONLY;
|
|
+USEBOUNCESTATE;
|
|
+INTERPOLATEANGLES;
|
|
BounceType "Hexen";
|
|
BounceFactor 0.5;
|
|
BounceSound "transloc/bounce";
|
|
WallBounceFactor 0.5;
|
|
Gravity 0.35;
|
|
ReactionTime 200;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
VBOX A -1;
|
|
Stop;
|
|
Bounce:
|
|
VBOX A 0 { angle = invoker.oldangle; }
|
|
Goto Spawn;
|
|
Death:
|
|
VBOX A 30
|
|
{
|
|
invoker.anglevel *= 0;
|
|
A_PlaySound("voice/activate");
|
|
}
|
|
VBOX ABCDEFGHIJ 1
|
|
{
|
|
A_VoiceBoxPlay();
|
|
ReactionTime--;
|
|
return A_JumpIf(ReactionTime<=0,"Death2");
|
|
}
|
|
Goto Death+1;
|
|
Death2:
|
|
VBOX A 0
|
|
{
|
|
if ( invoker.b ) invoker.b.Destroy();
|
|
A_PlaySound("flare/explode",CHAN_VOICE);
|
|
A_NoGravity();
|
|
A_Stop();
|
|
A_SetRenderStyle(1.,STYLE_Add);
|
|
SetZ(pos.z+16);
|
|
Spawn("FlareXLight",pos);
|
|
bMOVEWITHSECTOR = false;
|
|
bFORCEXYBILLBOARD = true;
|
|
A_SetScale(FRandomPick[ExploS](-1.5,1.5),FRandomPick[ExploS](-1.5,1.5));
|
|
return A_Jump(256,"Explo1","Explo2","Explo3","Explo4","Explo5");
|
|
}
|
|
Explo1:
|
|
EXP1 ABCDEFGH 3 Bright;
|
|
Stop;
|
|
Explo2:
|
|
EXP2 ABCDEFGH 3 Bright;
|
|
Stop;
|
|
Explo3:
|
|
EXP3 ABCDEFGH 3 Bright;
|
|
Stop;
|
|
Explo4:
|
|
EXP4 ABCDEFGH 3 Bright;
|
|
Stop;
|
|
Explo5:
|
|
EXP5 ABCDEFGH 3 Bright;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class Flare : UnrealInventory
|
|
{
|
|
Default
|
|
{
|
|
Tag "$T_FLARES";
|
|
Inventory.PickupMessage "$I_FLARES";
|
|
Inventory.Icon "I_Flare";
|
|
Inventory.MaxAmount 20;
|
|
}
|
|
override bool Use( bool pickup )
|
|
{
|
|
if ( pickup ) return false;
|
|
Vector3 x, y, z;
|
|
[x, y, z] = dt_CoordUtil.GetAxes(Owner.pitch,Owner.angle,Owner.roll);
|
|
Vector3 origin = level.Vec3Offset(Owner.Vec2OffsetZ(0,0,Owner.player.viewz),x*10.-z*8.);
|
|
let a = Spawn("FlareThrown",origin);
|
|
a.target = Owner;
|
|
a.angle = Owner.angle;
|
|
a.pitch = Owner.pitch;
|
|
a.vel += x*a.speed;
|
|
return true;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
FLAR A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class FlareThrown : Actor
|
|
{
|
|
double pitchvel, anglevel, rollvel;
|
|
double desiredangle;
|
|
bool rotatetodesired;
|
|
double lastpitch, lastangle, lastroll;
|
|
Actor b;
|
|
Default
|
|
{
|
|
Radius 6;
|
|
Height 6;
|
|
+NOBLOCKMAP;
|
|
+MISSILE;
|
|
+MOVEWITHSECTOR;
|
|
+THRUACTORS;
|
|
+USEBOUNCESTATE;
|
|
+INTERPOLATEANGLES;
|
|
+BOUNCEAUTOOFF;
|
|
+BOUNCEAUTOOFFFLOORONLY;
|
|
+NOTELEPORT;
|
|
+FORCERADIUSDMG;
|
|
+NODAMAGETHRUST;
|
|
DamageType "Exploded";
|
|
Speed 12;
|
|
VSpeed 2;
|
|
Mass 1;
|
|
Gravity 0.35;
|
|
BounceType "Hexen";
|
|
WallBounceFactor 0.6;
|
|
BounceFactor 0.6;
|
|
ReactionTime 350;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
pitchvel = FRandom[Junk](5,15)*RandomPick[Junk](-1,1);
|
|
anglevel = FRandom[Junk](5,15)*RandomPick[Junk](-1,1);
|
|
rollvel = FRandom[Junk](5,15)*RandomPick[Junk](-1,1);
|
|
}
|
|
override void Tick()
|
|
{
|
|
lastpitch = pitch;
|
|
lastangle = angle;
|
|
lastroll = roll;
|
|
Super.Tick();
|
|
if ( rotatetodesired )
|
|
{
|
|
if ( deltaangle(pitch,0) ~== 0 ) pitch = 0;
|
|
else pitch += clamp(deltaangle(pitch,0),-pitchvel,pitchvel);
|
|
if ( deltaangle(angle,desiredangle) ~== 0 ) angle = desiredangle;
|
|
else angle += clamp(deltaangle(angle,desiredangle),-anglevel,anglevel);
|
|
if ( deltaangle(roll,0) ~== 0 ) roll = 0;
|
|
else roll += clamp(deltaangle(roll,0),-rollvel,rollvel);
|
|
}
|
|
else
|
|
{
|
|
angle += anglevel;
|
|
pitch += pitchvel;
|
|
roll += rollvel;
|
|
}
|
|
if ( ReactionTime <= 0 ) return;
|
|
if ( GetAge() < 9 ) return;
|
|
if ( waterlevel > 0 )
|
|
{
|
|
if ( tracer ) tracer.Destroy();
|
|
if ( b ) b.Destroy();
|
|
A_StopSound(CHAN_VOICE);
|
|
ReactionTime = 0;
|
|
return;
|
|
}
|
|
if ( !b )
|
|
{
|
|
A_PlaySound("flare/on");
|
|
A_PlaySound("flare/loop",CHAN_VOICE,.5,true);
|
|
tracer = Spawn("FlareThrownX",pos);
|
|
tracer.angle = angle;
|
|
tracer.pitch = pitch;
|
|
tracer.target = self;
|
|
b = Spawn("FlareHitbox",pos);
|
|
b.master = self;
|
|
}
|
|
b.A_AlertMonsters(0,AMF_TARGETEMITTER);
|
|
ReactionTime--;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
FLAR A 1 A_JumpIf(ReactionTime<=0,"Death");
|
|
Wait;
|
|
Bounce:
|
|
FLAR A 0
|
|
{
|
|
pitch = lastpitch;
|
|
angle = lastangle;
|
|
roll = lastroll;
|
|
rotatetodesired = true;
|
|
desiredangle = FRandom[Junk](0,360);
|
|
pitchvel = abs(pitchvel)*0.75;
|
|
anglevel = abs(anglevel)*0.75;
|
|
rollvel = abs(rollvel)*0.75;
|
|
}
|
|
Goto Spawn;
|
|
Death:
|
|
FLAR A 0 { anglevel *= 0; }
|
|
FLAR A 1
|
|
{
|
|
if ( waterlevel > 0 )
|
|
{
|
|
if ( tracer ) tracer.Destroy();
|
|
if ( b ) b.Destroy();
|
|
A_StopSound(CHAN_VOICE);
|
|
return ResolveState("Fizz");
|
|
}
|
|
return A_JumpIf(ReactionTime<=0,1);
|
|
}
|
|
Wait;
|
|
FLAR A 0
|
|
{
|
|
if ( tracer ) tracer.Destroy();
|
|
if ( b ) b.Destroy();
|
|
if ( waterlevel > 0 )
|
|
{
|
|
return ResolveState("Fizz");
|
|
}
|
|
A_StopSound(CHAN_VOICE);
|
|
A_PlaySound("flare/explode");
|
|
A_Explode(50,50);
|
|
A_NoGravity();
|
|
A_Stop();
|
|
A_SetRenderStyle(1.,STYLE_Add);
|
|
SetZ(pos.z+9);
|
|
Spawn("FlareXLight",pos);
|
|
bMOVEWITHSECTOR = false;
|
|
bFORCEXYBILLBOARD = true;
|
|
A_SetScale(FRandomPick[ExploS](-1.5,1.5),FRandomPick[ExploS](-1.5,1.5));
|
|
return A_Jump(256,"Explo1","Explo2","Explo3","Explo4","Explo5");
|
|
}
|
|
Explo1:
|
|
EXP1 ABCDEFGH 3 Bright;
|
|
Stop;
|
|
Explo2:
|
|
EXP2 ABCDEFGH 3 Bright;
|
|
Stop;
|
|
Explo3:
|
|
EXP3 ABCDEFGH 3 Bright;
|
|
Stop;
|
|
Explo4:
|
|
EXP4 ABCDEFGH 3 Bright;
|
|
Stop;
|
|
Explo5:
|
|
EXP5 ABCDEFGH 3 Bright;
|
|
Stop;
|
|
Fizz:
|
|
FLAR A 1
|
|
{
|
|
special1++;
|
|
if ( special1 > 150 ) A_FadeOut();
|
|
}
|
|
Wait;
|
|
}
|
|
}
|
|
|
|
Class FlareXLight : PaletteLight
|
|
{
|
|
Default
|
|
{
|
|
ReactionTime 25;
|
|
Args 0,0,0,80;
|
|
}
|
|
}
|
|
|
|
Class FlareHitbox : VoiceBoxHitbox
|
|
{
|
|
Default
|
|
{
|
|
Tag "$T_FLARES";
|
|
Radius 4;
|
|
Height 6;
|
|
Health 1;
|
|
}
|
|
}
|
|
|
|
Class FlareThrownX : Actor
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
+NOGRAVITY;
|
|
+NOCLIP;
|
|
+DONTSPLASH;
|
|
+INTERPOLATEANGLES;
|
|
Radius 0.1;
|
|
Height 0;
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( !target )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
SetOrigin(target.pos,true);
|
|
angle = target.angle;
|
|
pitch = target.pitch;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
FLAR A -1 Bright;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class BetaFlare : UnrealInventory
|
|
{
|
|
Class<Actor> ThrownClass;
|
|
|
|
Property ThrownClass : ThrownClass;
|
|
|
|
override bool TryPickup( in out Actor toucher )
|
|
{
|
|
if ( !sting_flares ) return false; // not allowed
|
|
return Super.TryPickup(toucher);
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( sting_flares ) return;
|
|
if ( Owner ) Owner.RemoveInventory(self);
|
|
Destroy();
|
|
}
|
|
Default
|
|
{
|
|
Inventory.MaxAmount 1;
|
|
UnrealInventory.Charge 100;
|
|
+INVENTORY.UNDROPPABLE;
|
|
+INVENTORY.UNTOSSABLE;
|
|
}
|
|
}
|
|
|
|
Class LightFlare : BetaFlare
|
|
{
|
|
Default
|
|
{
|
|
Tag "$T_LFLARES";
|
|
Inventory.Icon "I_FlarBL";
|
|
}
|
|
}
|
|
|
|
Class DarkFlare : BetaFlare
|
|
{
|
|
Default
|
|
{
|
|
Tag "$T_DFLARES";
|
|
Inventory.Icon "I_FlarBD";
|
|
}
|
|
}
|
|
|
|
Class Dampener : UnrealInventory
|
|
{
|
|
static bool Active( Actor Owner )
|
|
{
|
|
let d = Dampener(Owner.FindInventory("Dampener"));
|
|
if ( d && d.bActive ) return true;
|
|
return false;
|
|
}
|
|
override bool Use( bool pickup )
|
|
{
|
|
if ( pickup ) return false;
|
|
bActive = !bActive;
|
|
Owner.A_PlaySound(bActive?"dampener/on":"dampener/off",CHAN_ITEM);
|
|
return false;
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( !bActive ) return;
|
|
if ( DrainCharge(1) )
|
|
{
|
|
Owner.A_PlaySound("dampener/off",CHAN_ITEM);
|
|
if ( Owner.CheckLocalView() ) Console.Printf(StringTable.Localize("$D_DAMPENER"));
|
|
if ( Amount <= 0 ) DepleteOrDestroy();
|
|
}
|
|
}
|
|
Default
|
|
{
|
|
Tag "$T_DAMPENER";
|
|
Inventory.PickupMessage "$I_DAMPENER";
|
|
Inventory.Icon "I_Dampen";
|
|
Inventory.MaxAmount 3;
|
|
UnrealInventory.Charge 1000;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
DAMP A 8 A_CheckProximity(1,"PlayerPawn",80,1,CPXF_ANCESTOR|CPXF_CHECKSIGHT);
|
|
Wait;
|
|
DAMP ABC 8;
|
|
DAMP DEFGHIJ 3;
|
|
DAMP D 0 A_CheckProximity(1,"PlayerPawn",80,0,CPXF_ANCESTOR|CPXF_CHECKSIGHT|CPXF_EXACT);
|
|
Goto Spawn+4;
|
|
DAMP CBA 8;
|
|
Goto Spawn;
|
|
}
|
|
}
|
|
|
|
Class Forcefield : UnrealInventory
|
|
{
|
|
Default
|
|
{
|
|
Tag "$T_FORCEFIELD";
|
|
Inventory.PickupMessage "$I_FORCEFIELD";
|
|
Inventory.Icon "I_ForceF";
|
|
Inventory.MaxAmount 5;
|
|
}
|
|
override bool Use( bool pickup )
|
|
{
|
|
if ( pickup ) return false;
|
|
Vector3 x, y, z;
|
|
[x, y, z] = dt_CoordUtil.GetAxes(Owner.pitch,Owner.angle,Owner.roll);
|
|
Vector3 origin = level.Vec3Offset(Owner.Vec2OffsetZ(0,0,Owner.player.viewz),x*90.);
|
|
origin = level.Vec3Offset(origin,(0,0,-GetDefaultByType("ForceFieldEffect").Height*.5));
|
|
if ( !level.IsPointInLevel(origin) )
|
|
{
|
|
if ( Owner.CheckLocalView() ) Console.Printf(StringTable.Localize("$M_FFNOROOM"));
|
|
return false;
|
|
}
|
|
let a = Spawn("ForceFieldEffect",origin);
|
|
if ( !a.TestMobjLocation() )
|
|
{
|
|
if ( Owner.CheckLocalView() ) Console.Printf(StringTable.Localize("$M_FFNOROOM"));
|
|
a.Destroy();
|
|
return false;
|
|
}
|
|
a.target = Owner;
|
|
a.angle = Owner.angle;
|
|
return true;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
tracer = Spawn("ForcefieldX",pos);
|
|
tracer.angle = angle;
|
|
tracer.target = self;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
FFPK A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class ForcefieldX : AsmdAmmoX
|
|
{
|
|
States
|
|
{
|
|
Spawn:
|
|
FFPK A -1 Bright;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class ForceFieldLight : DynamicLight
|
|
{
|
|
double cdown;
|
|
Default
|
|
{
|
|
DynamicLight.Type "Point";
|
|
+DYNAMICLIGHT.ATTENUATE;
|
|
Args 0,0,0,100;
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( !target )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
SetOrigin(target.Vec3Offset(0,0,target.height/2.),true);
|
|
if ( isFrozen() ) return;
|
|
args[LIGHT_RED] = int(255*cdown);
|
|
args[LIGHT_BLUE] = int(255*cdown);
|
|
if ( target.bSOLID )
|
|
{
|
|
cdown = min(1.,cdown+1./27);
|
|
return;
|
|
}
|
|
cdown = max(0.,cdown-1./35);
|
|
if ( cdown <= 0. ) Destroy();
|
|
}
|
|
}
|
|
|
|
Class ForcefieldEffect : Actor
|
|
{
|
|
double nvol;
|
|
int lct;
|
|
|
|
Default
|
|
{
|
|
Tag "$T_FORCEFIELD";
|
|
RenderStyle "Add";
|
|
+NOGRAVITY;
|
|
+NOTELEPORT;
|
|
+DONTSPLASH;
|
|
+CANNOTPUSH;
|
|
+SHOOTABLE;
|
|
+SOLID;
|
|
+NODAMAGE;
|
|
+NOBLOOD;
|
|
Mass int.max;
|
|
Health int.max;
|
|
Radius 15;
|
|
Height 45;
|
|
}
|
|
override int DamageMobj( Actor inflictor, Actor source, int damage, Name mod, int flags, double angle )
|
|
{
|
|
A_PlaySound("ffield/hit",CHAN_BODY);
|
|
return Super.DamageMobj(inflictor,source,damage,mod,flags,angle);
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
A_PlaySound("ffield/on",CHAN_ITEM);
|
|
A_PlaySound("ffield/active",CHAN_VOICE,0.6,true);
|
|
let tracer = Spawn("ForceFieldLight",pos);
|
|
tracer.target = self;
|
|
lct = 24;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
FFLD ABCDEFGHIJ 3 Bright;
|
|
#### # 700 Bright;
|
|
#### # 35 Bright
|
|
{
|
|
A_UnsetShootable();
|
|
A_UnsetSolid();
|
|
}
|
|
FFLD A 1 Bright A_PlaySound("ffield/hit",CHAN_VOICE);
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class UFlashlight : UnrealInventory
|
|
{
|
|
Actor lt[3];
|
|
|
|
Default
|
|
{
|
|
Tag "$T_FLASHLIGHT";
|
|
Inventory.Icon "I_Flashl";
|
|
Inventory.MaxAmount 3;
|
|
Inventory.PickupMessage "$I_FLASHLIGHT";
|
|
UnrealInventory.Charge 2800;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
SLIT A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class USearchlight : UFlashlight
|
|
{
|
|
Default
|
|
{
|
|
Tag "$T_SEARCHLIGHT";
|
|
Inventory.Icon "I_BigFl";
|
|
Inventory.MaxAmount 1;
|
|
Inventory.PickupMessage "$I_SEARCHLIGHT";
|
|
Inventory.RespawnTics 1050;
|
|
UnrealInventory.Charge 70000;
|
|
}
|
|
}
|
|
|
|
Class SentryItem : UnrealInventory
|
|
{
|
|
Default
|
|
{
|
|
Tag "$T_SENTRY";
|
|
Inventory.Icon "I_Sentry";
|
|
Inventory.MaxAmount 1;
|
|
Inventory.PickupMessage "$I_SENTRY";
|
|
Inventory.RespawnTics 1050;
|
|
UnrealInventory.Charge 300;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
SENT A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
// The "head" of the sentry, attaches to the body
|
|
Class MinigunSentry : Actor
|
|
{
|
|
States
|
|
{
|
|
Spawn:
|
|
SENT A 15;
|
|
SENT A 0 A_PlaySound("sentry/raise");
|
|
SENR ABCDEFGHIJKLMNO 3;
|
|
Goto Idle;
|
|
Idle:
|
|
SENI A 1;
|
|
Wait;
|
|
Fire:
|
|
SENW ABCDEFGHIJKLMNOPQR 1;
|
|
Goto FireLoop;
|
|
FireLoop:
|
|
SENF ABCDEFGHIJKLMNOPQR 1;
|
|
Loop;
|
|
FireEnd:
|
|
SENU ABCDEFGHIJKLMNOPQR 1;
|
|
Goto Idle;
|
|
}
|
|
}
|
|
|
|
// The body of the sentry
|
|
Class MinigunSentryBase : Actor
|
|
{
|
|
States
|
|
{
|
|
Spawn:
|
|
SENT A 15;
|
|
SENR ABCDEFGHIJKLMNO 3;
|
|
Goto Idle;
|
|
Idle:
|
|
SENI A 1;
|
|
Wait;
|
|
Fire:
|
|
SENW ABCDEFGHIJKLMNOPQR 1;
|
|
Goto FireLoop;
|
|
FireLoop:
|
|
SENF ABCDEFGHIJKLMNOPQR 1;
|
|
Loop;
|
|
FireEnd:
|
|
SENU ABCDEFGHIJKLMNOPQR 1;
|
|
Goto Idle;
|
|
}
|
|
}
|