Added original Sentry as a separate item, and made it spawn in Backpacks, while the bigger Sentry is a rare Berserk replacement.

PNG optimization.
This commit is contained in:
Marisa the Magician 2019-09-06 20:46:39 +02:00
commit 07121636f5
14 changed files with 499 additions and 18 deletions

View file

@ -181,10 +181,21 @@ infinitely regenerating supply of both, but only one can be used at a time.
These merely existed as a gimmick to show off dynamic lighting in Unreal These merely existed as a gimmick to show off dynamic lighting in Unreal
Engine, so they're not very practical or balanced. Engine, so they're not very practical or balanced.
## Light Sentry
Pocket turrets that shoot at any enemies standing in front of them. Easy to
carry and deploy, but once they're out in the field that's it. They will keep
going until they run out of ammo or battery, after which they will
self-destruct.
## Minigun Sentry ## Minigun Sentry
A deployable little helper that will gun down any enemies that stand in its A big, heavy turret that will gun down any enemies that stand in its view
view range. Starts with a full 200 bullets, and must be replenished by players. range.
Unlike the Light Sentries this one has a much wider range of view and can be
resupplied with extra ammo. Conveniently, you can also recall it to put it back
in your inventory. While carried it will slowly repair any damage it has taken.
In deathmatch, the Sentry will "switch owners" to whoever last replenished it In deathmatch, the Sentry will "switch owners" to whoever last replenished it
with ammunition, like the Turrets in ChaosUT. with ammunition, like the Turrets in ChaosUT.

View file

@ -102,8 +102,8 @@
redone the whole thing. Since I didn't feel like making new textures this redone the whole thing. Since I didn't feel like making new textures this
thing now mixes and matches a couple weapon skins. thing now mixes and matches a couple weapon skins.
- It's composed of two models so the gun part can rotate independently. - It's composed of two models so the gun part can rotate independently.
- Thinking of making an alternate item that still uses the source model and - Original version is available as a separate item. Gave it some stitched
its frankenUVs. Will have to stitch a skin for it tho. textures.
### Peacemaker ### Peacemaker

View file

@ -44,7 +44,8 @@ Doom Tournament (currently the devel branch is required).
- SCUBA Gear (replaces radsuit if map has swimmable water) - SCUBA Gear (replaces radsuit if map has swimmable water)
- Motion Detector (replaces computer map) - Motion Detector (replaces computer map)
- Light & Dark Flares - Light & Dark Flares
- Minigun Sentry (rare spawn in backpacks) - Minigun Sentry (rare berserk replacement)
- Light Sentry (rare spawn in backpacks)
## In progress ## In progress
@ -79,8 +80,6 @@ Doom Tournament (currently the devel branch is required).
- Demolisher (slot 9) (replaces bfg9000) - Demolisher (slot 9) (replaces bfg9000)
- Autocannon (slot 0) (replaces bfg9000) - Autocannon (slot 0) (replaces bfg9000)
- Original Sentry Gun (rare spawn in backpacks)
## Known bugs ## Known bugs
- N/A - N/A

View file

@ -350,6 +350,21 @@ Object MinigunSentry
Frame "SENFQ" { light "SENTRYLIGHT2" } Frame "SENFQ" { light "SENTRYLIGHT2" }
} }
FlickerLight2 SENTRYLIGHT3
{
Color 1.0 0.6 0.0
Size 40
SecondarySize 48
Interval 0.1
Offset 0 16 10
}
Object SentryGun
{
Frame "SENFA" { light "SENTRYLIGHT3" }
Frame "SENFC" { light "SENTRYLIGHT3" }
}
// Shaders / Brightmaps // Shaders / Brightmaps
HardwareShader Texture "graphics/MenuBarr.png" HardwareShader Texture "graphics/MenuBarr.png"
{ {
@ -733,3 +748,7 @@ HardwareShader Texture "models/OLSMP_.png"
Texture "masktex" "models/OLSMP_m.png" Texture "masktex" "models/OLSMP_m.png"
texture "envtex" "models/OLSMP_env.png" texture "envtex" "models/OLSMP_env.png"
} }
HardwareShader Texture "models/JSentry1_.png"
{
Shader "shaders/glsl/AmbientGlow.fp"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Before After
Before After

BIN
graphics/icons/I_OSntry.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View file

@ -33,7 +33,9 @@ O_FLAMETHROWER = "%o was thoroughly roasted by %k's Flamethrower.";
O_BIGGUN = "%k blew a hole through %o with the Demolisher."; O_BIGGUN = "%k blew a hole through %o with the Demolisher.";
O_SMINI = "%o got blasted into steaming chunks by %k's Autocannon."; O_SMINI = "%o got blasted into steaming chunks by %k's Autocannon.";
O_SENTRY = "%%o shouldn't have walked into the sights of %s."; O_SENTRY = "%%o shouldn't have walked into the sights of %s.";
O_OWNSENTRY = "%o was gunned down by %p own Sentry."; O_OWNSENTRY = "%o was gunned down by %p own Minigun Sentry.";
O_OSENTRY = "%%o took a bullet from %s.";
O_OWNOSENTRY = "%o took a bullet from %p own Light Sentry.";
O_STINGERX = "%o ate flaming Tarydium death thanks to %k."; O_STINGERX = "%o ate flaming Tarydium death thanks to %k.";
O_OLSMP = "%o didn't stand a chance against %k's SMP 7243."; O_OLSMP = "%o didn't stand a chance against %k's SMP 7243.";
/* Pickup messages */ /* Pickup messages */
@ -76,7 +78,8 @@ I_FLAMEGUN = "You got the Fireblaster.";
I_FLAMETHROWER = "You got the Flamethrower."; I_FLAMETHROWER = "You got the Flamethrower.";
I_BIGGUN = "You picked up the Demolisher."; I_BIGGUN = "You picked up the Demolisher.";
I_SMINI = "You got the Autocannon."; I_SMINI = "You got the Autocannon.";
I_SENTRY = "You picked up a Sentry."; I_SENTRY = "You picked up a Minigun Sentry.";
I_OSENTRY = "You picked up a Light Sentry.";
I_TRANSLATOR = "You picked up the Universal Translator."; I_TRANSLATOR = "You picked up the Universal Translator.";
I_UARMOR = "You got the Assault Vest."; I_UARMOR = "You got the Assault Vest.";
I_KEVSUIT = "You picked up the Kevlar Suit."; I_KEVSUIT = "You picked up the Kevlar Suit.";
@ -138,8 +141,10 @@ T_FLAMEGUN = "Fireblaster";
T_FLAMETHROWER = "Flamethrower"; T_FLAMETHROWER = "Flamethrower";
T_BIGGUN = "Demolisher"; T_BIGGUN = "Demolisher";
T_SMINI = "Autocannon"; T_SMINI = "Autocannon";
T_SENTRY = "Sentry"; T_SENTRY = "Minigun Sentry";
T_OWNEDSENTRY = "%s's Sentry"; T_OSENTRY = "Light Sentry";
T_OWNEDSENTRY = "%s's Minigun Sentry";
T_OWNEDOSENTRY = "%s's Light Sentry";
T_TRANSLATOR = "Translator"; T_TRANSLATOR = "Translator";
T_UARMOR = "Assault Vest"; T_UARMOR = "Assault Vest";
T_KEVSUIT = "Kevlar Suit"; T_KEVSUIT = "Kevlar Suit";
@ -186,9 +191,9 @@ D_FLASHLIGHT = "The Flashlight batteries have died.";
D_SEARCHLIGHT = "The Searchlight has run out of battery."; D_SEARCHLIGHT = "The Searchlight has run out of battery.";
D_DETECTOR = "The Detector has run out of battery."; D_DETECTOR = "The Detector has run out of battery.";
D_LBOOTS = "The Jump Boots have drained."; D_LBOOTS = "The Jump Boots have drained.";
M_SENTRYDOWN = "Your Sentry has been destroyed."; M_SENTRYDOWN = "Your Minigun Sentry has been destroyed.";
M_SENTRYDRY = "Your Sentry has run out of ammo."; M_SENTRYDRY = "Your Minigun Sentry has run out of ammo.";
M_SENTRYHIJACK = "Your Sentry has been hijacked."; M_SENTRYHIJACK = "Your Minigun Sentry has been hijacked.";
M_MSNOROOM = "No room to deploy Sentry."; M_MSNOROOM = "No room to deploy Sentry.";
M_NSTOOFAR = "Cannot recall Sentry from this distance."; M_NSTOOFAR = "Cannot recall Sentry from this distance.";
M_FFNOROOM = "No room to activate Force Field."; M_FFNOROOM = "No room to activate Force Field.";
@ -268,6 +273,8 @@ O_BIGGUN = "%k abrió un hoyo a través de %o con el Demoledor.";
O_SMINI = "%o fue reventad@[ao_esp] en pedazos humeantes por el Autocañón de %k."; O_SMINI = "%o fue reventad@[ao_esp] en pedazos humeantes por el Autocañón de %k.";
O_SENTRY = "%%o no debería haberse metido en el punto de mira de la %s."; O_SENTRY = "%%o no debería haberse metido en el punto de mira de la %s.";
O_OWNSENTRY = "%o fue abatid@[ao_esp] por su propi@[ao_esp] Torreta."; O_OWNSENTRY = "%o fue abatid@[ao_esp] por su propi@[ao_esp] Torreta.";
O_OSENTRY = "%%o se llevó un tiro de la %s.";
O_OWNOSENTRY = "%o se llevó un tiro de su propi@[ao_esp] Torreta Ligera.";
O_STINGERX = "%o tragó muerte ardiente de Tarydium gracias a %k."; O_STINGERX = "%o tragó muerte ardiente de Tarydium gracias a %k.";
O_OLSMP = "%o no tenía ninguna oportunidad contra el SMP 7243 de %k."; O_OLSMP = "%o no tenía ninguna oportunidad contra el SMP 7243 de %k.";
/* Pickup messages */ /* Pickup messages */
@ -311,6 +318,7 @@ I_FLAMETHROWER = "Has obtenido el Lanzallamas.";
I_BIGGUN = "Has recogido el Demoledor."; I_BIGGUN = "Has recogido el Demoledor.";
I_SMINI = "Has obtenido el Autocañón."; I_SMINI = "Has obtenido el Autocañón.";
I_SENTRY = "Has recogido una Torreta."; I_SENTRY = "Has recogido una Torreta.";
I_OSENTRY = "Has recogido una Torreta Ligera.";
I_TRANSLATOR = "Has obtenido el Traductor Universal."; I_TRANSLATOR = "Has obtenido el Traductor Universal.";
I_UARMOR = "Has obtenido la Coraza de Asalto."; I_UARMOR = "Has obtenido la Coraza de Asalto.";
I_KEVSUIT = "Has recogido el Traje de Kevlar."; I_KEVSUIT = "Has recogido el Traje de Kevlar.";
@ -370,6 +378,8 @@ T_BIGGUN = "Demoledor";
T_SMINI = "Autocañón"; T_SMINI = "Autocañón";
T_SENTRY = "Torreta"; T_SENTRY = "Torreta";
T_OWNEDSENTRY = "Torreta de %s"; T_OWNEDSENTRY = "Torreta de %s";
T_OSENTRY = "Torreta Ligera";
T_OWNEDOSENTRY = "Torreta Ligera de %s";
T_TRANSLATOR = "Traductor"; T_TRANSLATOR = "Traductor";
T_UARMOR = "Coraza de Asalto"; T_UARMOR = "Coraza de Asalto";
T_KEVSUIT = "Traje de Kevlar"; T_KEVSUIT = "Traje de Kevlar";

View file

@ -673,6 +673,97 @@ Model "MinigunSentryBase"
FrameIndex SENU R 0 67 FrameIndex SENU R 0 67
} }
Model "SentryGunItem"
{
Path "models"
Model 0 "SentryM_d.3d"
SurfaceSkin 0 1 "JSentry1_.png"
AngleOffset -90
Scale 0.12 0.12 0.144
ZOffset 16
FrameIndex SENT A 0 0
}
Model "SentryGunX"
{
Path "models"
Model 0 "SentryM_d.3d"
SurfaceSkin 0 0 "JSentry1.png"
AngleOffset -90
Scale 0.12 0.12 0.144
ZOffset 16
DONTCULLBACKFACES
FrameIndex SENF A 0 20
FrameIndex SENF C 0 22
}
Model "SentryGun"
{
Path "models"
Model 0 "SentryM_d.3d"
SurfaceSkin 0 1 "JSentry1.png"
AngleOffset -90
Scale 0.12 0.12 0.144
ZOffset 16
// Spawn
FrameIndex SENT A 0 0
// Up
FrameIndex SENR A 0 0
FrameIndex SENR B 0 1
FrameIndex SENR C 0 2
FrameIndex SENR D 0 3
FrameIndex SENR E 0 4
// Still
FrameIndex SENI A 0 5
// Wind
FrameIndex SENW A 0 6
FrameIndex SENW B 0 7
FrameIndex SENW C 0 8
FrameIndex SENW D 0 9
FrameIndex SENW E 0 10
FrameIndex SENW F 0 11
FrameIndex SENW G 0 12
FrameIndex SENW H 0 13
FrameIndex SENW I 0 14
FrameIndex SENW J 0 15
FrameIndex SENW K 0 16
FrameIndex SENW L 0 17
FrameIndex SENW M 0 18
FrameIndex SENW N 0 19
// Fire
FrameIndex SENF A 0 20
FrameIndex SENF B 0 21
FrameIndex SENF C 0 22
FrameIndex SENF D 0 23
// Unwind
FrameIndex SENU A 0 24
FrameIndex SENU B 0 25
FrameIndex SENU C 0 26
FrameIndex SENU D 0 27
FrameIndex SENU E 0 28
FrameIndex SENU F 0 29
FrameIndex SENU G 0 30
FrameIndex SENU H 0 31
FrameIndex SENU I 0 32
FrameIndex SENU J 0 33
FrameIndex SENU K 0 34
FrameIndex SENU L 0 35
FrameIndex SENU M 0 36
FrameIndex SENU N 0 37
FrameIndex SENU O 0 38
FrameIndex SENU P 0 39
FrameIndex SENU Q 0 40
// Down
FrameIndex SEND A 0 41
FrameIndex SEND B 0 42
FrameIndex SEND C 0 43
FrameIndex SEND D 0 44
FrameIndex SEND E 0 45
}
Model "MotionDetector" Model "MotionDetector"
{ {
Path "models" Path "models"

BIN
models/JSentry1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

BIN
models/JSentry1_.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

BIN
models/SentryM_a.3d Normal file

Binary file not shown.

BIN
models/SentryM_d.3d Normal file

Binary file not shown.

View file

@ -88,7 +88,7 @@ Class UnrealBackpack : BackpackItem replaces Backpack
Super.DoPickupSpecial(toucher); Super.DoPickupSpecial(toucher);
if ( gameinfo.gametype&GAME_DOOMCHEX ) if ( gameinfo.gametype&GAME_DOOMCHEX )
{ {
static const Class<Inventory> xitems[] = {"Flare", "Seeds", "SentryItem", "VoiceBox", "ForceField", "Dampener", "Peacemaker"}; static const Class<Inventory> xitems[] = {"Flare", "Seeds", "SentryGunItem", "VoiceBox", "ForceField", "Dampener", "Peacemaker"};
int xitemn[7]; int xitemn[7];
xitemn[0] = max(0,Random[BackpackExtra](-1,3)); xitemn[0] = max(0,Random[BackpackExtra](-1,3));
xitemn[1] = max(0,Random[BackpackExtra](-1,3)); xitemn[1] = max(0,Random[BackpackExtra](-1,3));
@ -1432,6 +1432,11 @@ Class SentryItem : UnrealInventory
UnrealInventory.Charge MinigunSentryBase.sentryhealth; UnrealInventory.Charge MinigunSentryBase.sentryhealth;
+UNREALINVENTORY.DRAWSPECIAL; +UNREALINVENTORY.DRAWSPECIAL;
} }
override bool HandlePickup( Inventory item )
{
if ( item.GetClass() == GetClass() ) return true; // can never get more than one
return Super.HandlePickup(item);
}
static void TransferOwnership( Actor newowner, Actor sentry ) static void TransferOwnership( Actor newowner, Actor sentry )
{ {
if ( sentry.master ) sentry.master.TakeInventory("SentryItem",200); if ( sentry.master ) sentry.master.TakeInventory("SentryItem",200);
@ -1500,7 +1505,11 @@ Class SentryItem : UnrealInventory
override void DoEffect() override void DoEffect()
{ {
Super.DoEffect(); Super.DoEffect();
if ( !bActive ) return; if ( !bActive )
{
if ( !(level.maptime%10) ) Charge = min(DefaultCharge,Charge+1);
return;
}
if ( !tracer ) if ( !tracer )
{ {
bActive = false; bActive = false;
@ -2015,7 +2024,11 @@ Class MinigunSentryBase : Actor
Vector3 x, y, z; Vector3 x, y, z;
[x, y, z] = dt_CoordUtil.GetAxes(pitch,angle,roll); [x, y, z] = dt_CoordUtil.GetAxes(pitch,angle,roll);
tracer.SetOrigin(level.Vec3Offset(pos,z*38),false); tracer.SetOrigin(level.Vec3Offset(pos,z*38),false);
if ( !deathmatch ) return; if ( !deathmatch )
{
if ( !master || !master.player ) bFRIENDLY = false;
return;
}
if ( master && master.player ) tracer.SetFriendPlayer(master.player); if ( master && master.player ) tracer.SetFriendPlayer(master.player);
else tracer.bFRIENDLY = false; else tracer.bFRIENDLY = false;
} }
@ -2127,3 +2140,340 @@ Class MinigunSentryBase : Actor
Stop; Stop;
} }
} }
// original fun-size stationary version
Class SentryGunItem : UnrealInventory
{
Default
{
Tag "$T_OSENTRY";
Inventory.Icon "I_OSntry";
Inventory.MaxAmount 3;
Inventory.PickupMessage "$I_OSENTRY";
Inventory.RespawnTics 1050;
}
override bool Use( bool pickup )
{
if ( pickup ) return false;
Vector3 origin = Owner.Vec2OffsetZ(0,0,Owner.player.viewz);
FLineTraceData d;
Owner.LineTrace(Owner.angle,90,Owner.pitch,TRF_ABSPOSITION,origin.z,origin.x,origin.y,data:d);
if ( d.HitType != TRACE_HitNone ) origin = d.HitLocation-d.HitDir*20;
else origin = d.HitLocation;
Owner.LineTrace(0,56,90,TRF_ABSPOSITION,origin.z,origin.x,origin.y,data:d);
origin = d.HitLocation;
let a = Spawn("SentryGun",origin);
if ( !a.TestMobjLocation() )
{
if ( Owner.CheckLocalView() ) Console.Printf(StringTable.Localize("$M_MSNOROOM"));
a.Destroy();
return false;
}
tracer = a;
a.master = Owner;
a.angle = Owner.angle;
a.pitch = 0;
a.roll = 0;
return true;
}
States
{
Spawn:
SENT A -1;
Stop;
}
}
Class SentryGunX : Actor
{
Default
{
RenderStyle "Add";
+NOGRAVITY;
+NOBLOCKMAP;
+INTERPOLATEANGLES;
}
override void Tick()
{
Super.Tick();
if ( !tracer || !tracer.InStateSequence(tracer.CurState,tracer.FindState("Fire")) )
{
Destroy();
return;
}
SetOrigin(tracer.pos,true);
angle = tracer.angle;
pitch = tracer.pitch;
roll = tracer.roll;
}
States
{
Spawn:
SENF A 2 Bright;
TNT1 A 2;
SENF C 2 Bright;
TNT1 A 2;
Stop;
}
}
Class SentryGun : Actor
{
int rememberedplayer;
Default
{
Health 50;
Mass int.max;
Radius 10;
Height 24;
+SOLID;
+SHOOTABLE;
+NOBLOOD;
+DONTTHRUST;
+FRIENDLY;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
if ( master && master.player )
{
SetTag(String.Format(StringTable.Localize("$T_OWNEDOSENTRY"),master.player.GetUserName()));
rememberedplayer = master.playernumber();
}
else
{
SetTag(StringTable.Localize("$T_OSENTRY"));
rememberedplayer = -1;
}
if ( !deathmatch )
{
if ( !master || !master.player ) bFRIENDLY = false;
return;
}
if ( master && master.player ) SetFriendPlayer(master.player);
else bFRIENDLY = false;
}
override string GetObituary( Actor victim, Actor inflictor, Name mod, bool playerattack )
{
if ( victim == master ) return String.Format(StringTable.Localize("$O_OWNOSENTRY"),GetTag());
return String.Format(StringTable.Localize("$O_OSENTRY"),GetTag());
}
override void Tick()
{
Super.Tick();
if ( !master && (rememberedplayer != -1) && playeringame[rememberedplayer] )
master = players[rememberedplayer].mo;
}
bool IsEnemy( Actor a )
{
if ( !a || !a.bSHOOTABLE || !a.bISMONSTER || (a.Health <= 0) ) return false;
if ( deathmatch ) return ((a != master) && (a.master != master));
return (!bFRIENDLY || (!a.bFRIENDLY && !a.player));
}
bool HasTarget()
{
// check for targets in range
let ti = ThinkerIterator.Create("Actor");
Actor a;
while ( a = Actor(ti.Next()) )
{
if ( !IsEnemy(a) ) continue;
Vector3 x = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
Vector3 vecto = level.Vec3Diff(Vec3Offset(0,0,16),a.Vec3Offset(0,0,a.height/2));
double distto = vecto.length();
Vector3 dirto = vecto/distto;
double angleto = atan2(dirto.y,dirto.x);
double pitchto = asin(-dirto.z);
if ( (distto < 6000) && (dirto dot x > 0.95) && !LineTrace(angleto,distto,pitchto,TRF_THRUACTORS,16) )
{
target = a;
return true;
}
}
// check for targets in a straight line
FLineTraceData d;
LineTrace(angle,200,pitch,0,16,data:d);
if ( (d.HitType == TRACE_HitActor) && IsEnemy(d.HitActor) )
{
target = d.HitActor;
return true;
}
target = null;
return false;
}
// if there's a target and we have ammo, jump to first state (if set)
// if there's no target but we still have ammo, jump to second state (if set)
// if we have no ammo, jump to third state (if set)
void A_SentryGunCheck( statelabel actstate = null, statelabel idlestate = null, statelabel failstate = null )
{
if ( !(GetAge()%35) ) special1++;
if ( (special1 >= 200) && failstate ) SetStateLabel(failstate);
else if ( HasTarget() && actstate ) SetStateLabel(actstate);
else if ( !HasTarget() && idlestate ) SetStateLabel(idlestate);
}
void A_SentryGunAttack( statelabel failstate = null )
{
special1++;
if ( ((special1 >= 200) || !HasTarget()) && failstate )
{
A_StopSound(CHAN_BODY);
SetStateLabel(failstate);
return;
}
A_AlertMonsters(0,AMF_TARGETEMITTER);
A_PlaySound("sentry/fire",CHAN_WEAPON,pitch:1.6);
Vector3 x, y, z, origin;
[x, y, z] = dt_CoordUtil.GetAxes(pitch,angle,roll);
origin = level.Vec3Offset(pos,x*12+z*16);
double a = FRandom[Sentry](0,360), s = FRandom[Sentry](0,0.05);
Vector3 nx = target?Vec3To(target).unit():x;
Vector3 dir = (nx+y*cos(a)*s+z*sin(a)*s).unit();
FLineTraceData d;
LineTrace(atan2(dir.y,dir.x),10000,asin(-dir.z),TRF_ABSPOSITION,origin.z,origin.x,origin.y,d);
if ( d.HitType == TRACE_HitActor )
{
int dmg = Random[OSentry](6,17);
dmg = d.HitActor.DamageMobj(self,self,dmg,'shot',DMG_USEANGLE|DMG_THRUSTLESS,atan2(d.HitDir.y,d.HitDir.x));
double mm = 3000;
if ( FRandom[OSentry](0,1) < 0.2 ) mm *= 5;
UTMainHandler.DoKnockback(d.HitActor,d.HitDir,mm);
if ( d.HitActor.bNOBLOOD )
{
let p = Spawn("BulletImpact",d.HitLocation);
p.angle = atan2(d.HitDir.y,d.HitDir.x)+180;
p.pitch = asin(d.HitDir.z);
}
else
{
d.HitActor.TraceBleed(dmg,self);
d.HitActor.SpawnBlood(d.HitLocation,atan2(d.HitDir.y,d.HitDir.x)+180,dmg);
}
}
else if ( d.HitType != TRACE_HitNone )
{
Vector3 hitnormal = -d.HitDir;
if ( d.HitType == TRACE_HitFloor ) hitnormal = d.HitSector.floorplane.Normal;
else if ( d.HitType == TRACE_HitCeiling ) hitnormal = d.HitSector.ceilingplane.Normal;
else if ( d.HitType == TRACE_HitWall )
{
hitnormal = (-d.HitLine.delta.y,d.HitLine.delta.x,0).unit();
if ( !d.LineSide ) hitnormal *= -1;
}
let p = Spawn("BulletImpact",d.HitLocation+hitnormal*0.01);
p.angle = atan2(hitnormal.y,hitnormal.x);
p.pitch = asin(-hitnormal.z);
if ( d.HitLine ) d.HitLine.RemoteActivate(self,d.LineSide,SPAC_Impact,d.HitLocation);
}
for ( int i=0; i<3; i++ )
{
let s = Spawn("UTSmoke",origin);
s.alpha *= 0.5;
s.scale *= 0.7;
s.vel += x*2;
}
let c = Spawn("UCasing",level.Vec3Offset(pos,-x*8+y*0.6+z*16));
c.scale *= 0.5;
c.vel = x*FRandom[Junk](-1.5,1.5)+y*FRandom[Junk](2,4)+z*FRandom[Junk](2,3);
}
States
{
Spawn:
SENT A 15;
Goto StartUp;
StartUp:
SENR A 0
{
A_PlaySound("sentry/raise",pitch:1.6);
A_AlertMonsters(0,AMF_TARGETEMITTER);
}
SENR ABCDE 4;
Goto Idle;
Idle:
SENI A 1 A_SentryGunCheck("WindUp",null,"ShutDown");
Wait;
WindUp:
SENW A 0
{
A_PlaySound("sentry/wind",looping:true,pitch:1.6);
A_AlertMonsters(0,AMF_TARGETEMITTER);
}
SENW ABCDEFGHIJKLMN 1;
Fire:
SENF A 0
{
let f = Spawn("SentryGunX",pos);
f.angle = angle;
f.pitch = pitch;
f.roll = roll;
f.tracer = self;
}
SENF A 2 A_SentryGunAttack("Unwind");
SENF B 2;
SENF C 2 A_SentryGunAttack("Unwind");
SENF D 2;
SENU A 0; // tweening hack
Loop;
Unwind:
SENU A 0 A_PlaySound("sentry/unwind",pitch:1.6);
SENU ABCDEFGHIJKLMN 1;
Goto Idle;
ShutDown:
SEND A 0 A_PlaySound("sentry/raise",pitch:1.6);
SEND ABCDE 4;
SEND E 20;
SEND E -1 A_Die();
Stop;
Death:
TNT1 A 0
{
A_StopSound(CHAN_BODY);
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));
int numpt = Random[ExploS](15,30);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](1,3);
let s = Spawn("UTSmoke",pos);
s.vel = pvel;
}
numpt = Random[ExploS](9,18);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](2,6);
let s = Spawn("UTSpark",pos);
s.vel = pvel;
}
numpt = Random[ExploS](18,28);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](2,12);
let s = Spawn("UTChip",pos);
s.vel = pvel;
s.scale *= FRandom[ExploS](0.9,2.7);
}
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;
}
}

View file

@ -979,7 +979,8 @@ Class UnrealMainHandler : EventHandler
else if ( (e.Replacee == 'InvulnerabilitySphere') || (e.Replacee == 'ArtiInvulnerability') ) e.Replacement = 'PowerShield'; else if ( (e.Replacee == 'InvulnerabilitySphere') || (e.Replacee == 'ArtiInvulnerability') ) e.Replacement = 'PowerShield';
else if ( (e.Replacee == 'Berserk') || (e.Replacee == 'ArtiTomeOfPower') ) else if ( (e.Replacee == 'Berserk') || (e.Replacee == 'ArtiTomeOfPower') )
{ {
if ( !Random[Replacements](0,2) ) e.Replacement = 'WeaponPowerUp'; if ( !Random[Replacements](0,9) ) e.Replacement = 'SentryItem';
else if ( !Random[Replacements](0,2) ) e.Replacement = 'WeaponPowerUp';
else e.Replacement = 'Amplifier'; else e.Replacement = 'Amplifier';
} }
else if ( e.Replacee == 'ArtiEgg' ) e.Replacement = 'VoiceBox'; else if ( e.Replacee == 'ArtiEgg' ) e.Replacement = 'VoiceBox';