Notable changes since last commit are the full implementation of the automag and asmd. Also the Translator is now fully functional. Fonts have been restructured to a neater format. There have also been other random changes I don't have the time to document in detail.
909 lines
19 KiB
Text
909 lines
19 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;
|
|
Stop;
|
|
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 LightFlare : UnrealInventory
|
|
{
|
|
}
|
|
|
|
Class DarkFlare : UnrealInventory
|
|
{
|
|
}
|
|
|
|
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
|
|
{
|
|
}
|
|
|
|
Class USearchlight : UnrealInventory
|
|
{
|
|
}
|
|
|
|
Class SentryItem : UnrealInventory
|
|
{
|
|
}
|
|
|
|
Class MinigunSentry : Actor
|
|
{
|
|
}
|