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:
parent
d7fe8cbfdd
commit
07121636f5
14 changed files with 499 additions and 18 deletions
15
ItemLore.md
15
ItemLore.md
|
|
@ -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
|
||||
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
|
||||
|
||||
A deployable little helper that will gun down any enemies that stand in its
|
||||
view range. Starts with a full 200 bullets, and must be replenished by players.
|
||||
A big, heavy turret that will gun down any enemies that stand in its view
|
||||
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
|
||||
with ammunition, like the Turrets in ChaosUT.
|
||||
|
|
|
|||
|
|
@ -102,8 +102,8 @@
|
|||
redone the whole thing. Since I didn't feel like making new textures this
|
||||
thing now mixes and matches a couple weapon skins.
|
||||
- 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
|
||||
its frankenUVs. Will have to stitch a skin for it tho.
|
||||
- Original version is available as a separate item. Gave it some stitched
|
||||
textures.
|
||||
|
||||
### Peacemaker
|
||||
|
||||
|
|
|
|||
|
|
@ -44,7 +44,8 @@ Doom Tournament (currently the devel branch is required).
|
|||
- SCUBA Gear (replaces radsuit if map has swimmable water)
|
||||
- Motion Detector (replaces computer map)
|
||||
- Light & Dark Flares
|
||||
- Minigun Sentry (rare spawn in backpacks)
|
||||
- Minigun Sentry (rare berserk replacement)
|
||||
- Light Sentry (rare spawn in backpacks)
|
||||
|
||||
## In progress
|
||||
|
||||
|
|
@ -79,8 +80,6 @@ Doom Tournament (currently the devel branch is required).
|
|||
- Demolisher (slot 9) (replaces bfg9000)
|
||||
- Autocannon (slot 0) (replaces bfg9000)
|
||||
|
||||
- Original Sentry Gun (rare spawn in backpacks)
|
||||
|
||||
## Known bugs
|
||||
|
||||
- N/A
|
||||
|
|
|
|||
19
gldefs.txt
19
gldefs.txt
|
|
@ -350,6 +350,21 @@ Object MinigunSentry
|
|||
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
|
||||
HardwareShader Texture "graphics/MenuBarr.png"
|
||||
{
|
||||
|
|
@ -733,3 +748,7 @@ HardwareShader Texture "models/OLSMP_.png"
|
|||
Texture "masktex" "models/OLSMP_m.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 |
BIN
graphics/icons/I_OSntry.png
Normal file
BIN
graphics/icons/I_OSntry.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
24
language.txt
24
language.txt
|
|
@ -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_SMINI = "%o got blasted into steaming chunks by %k's Autocannon.";
|
||||
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_OLSMP = "%o didn't stand a chance against %k's SMP 7243.";
|
||||
/* Pickup messages */
|
||||
|
|
@ -76,7 +78,8 @@ I_FLAMEGUN = "You got the Fireblaster.";
|
|||
I_FLAMETHROWER = "You got the Flamethrower.";
|
||||
I_BIGGUN = "You picked up the Demolisher.";
|
||||
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_UARMOR = "You got the Assault Vest.";
|
||||
I_KEVSUIT = "You picked up the Kevlar Suit.";
|
||||
|
|
@ -138,8 +141,10 @@ T_FLAMEGUN = "Fireblaster";
|
|||
T_FLAMETHROWER = "Flamethrower";
|
||||
T_BIGGUN = "Demolisher";
|
||||
T_SMINI = "Autocannon";
|
||||
T_SENTRY = "Sentry";
|
||||
T_OWNEDSENTRY = "%s's Sentry";
|
||||
T_SENTRY = "Minigun Sentry";
|
||||
T_OSENTRY = "Light Sentry";
|
||||
T_OWNEDSENTRY = "%s's Minigun Sentry";
|
||||
T_OWNEDOSENTRY = "%s's Light Sentry";
|
||||
T_TRANSLATOR = "Translator";
|
||||
T_UARMOR = "Assault Vest";
|
||||
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_DETECTOR = "The Detector has run out of battery.";
|
||||
D_LBOOTS = "The Jump Boots have drained.";
|
||||
M_SENTRYDOWN = "Your Sentry has been destroyed.";
|
||||
M_SENTRYDRY = "Your Sentry has run out of ammo.";
|
||||
M_SENTRYHIJACK = "Your Sentry has been hijacked.";
|
||||
M_SENTRYDOWN = "Your Minigun Sentry has been destroyed.";
|
||||
M_SENTRYDRY = "Your Minigun Sentry has run out of ammo.";
|
||||
M_SENTRYHIJACK = "Your Minigun Sentry has been hijacked.";
|
||||
M_MSNOROOM = "No room to deploy Sentry.";
|
||||
M_NSTOOFAR = "Cannot recall Sentry from this distance.";
|
||||
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_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_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_OLSMP = "%o no tenía ninguna oportunidad contra el SMP 7243 de %k.";
|
||||
/* Pickup messages */
|
||||
|
|
@ -311,6 +318,7 @@ I_FLAMETHROWER = "Has obtenido el Lanzallamas.";
|
|||
I_BIGGUN = "Has recogido el Demoledor.";
|
||||
I_SMINI = "Has obtenido el Autocañón.";
|
||||
I_SENTRY = "Has recogido una Torreta.";
|
||||
I_OSENTRY = "Has recogido una Torreta Ligera.";
|
||||
I_TRANSLATOR = "Has obtenido el Traductor Universal.";
|
||||
I_UARMOR = "Has obtenido la Coraza de Asalto.";
|
||||
I_KEVSUIT = "Has recogido el Traje de Kevlar.";
|
||||
|
|
@ -370,6 +378,8 @@ T_BIGGUN = "Demoledor";
|
|||
T_SMINI = "Autocañón";
|
||||
T_SENTRY = "Torreta";
|
||||
T_OWNEDSENTRY = "Torreta de %s";
|
||||
T_OSENTRY = "Torreta Ligera";
|
||||
T_OWNEDOSENTRY = "Torreta Ligera de %s";
|
||||
T_TRANSLATOR = "Traductor";
|
||||
T_UARMOR = "Coraza de Asalto";
|
||||
T_KEVSUIT = "Traje de Kevlar";
|
||||
|
|
|
|||
|
|
@ -673,6 +673,97 @@ Model "MinigunSentryBase"
|
|||
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"
|
||||
{
|
||||
Path "models"
|
||||
|
|
|
|||
BIN
models/JSentry1.png
Normal file
BIN
models/JSentry1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 44 KiB |
BIN
models/JSentry1_.png
Normal file
BIN
models/JSentry1_.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 44 KiB |
BIN
models/SentryM_a.3d
Normal file
BIN
models/SentryM_a.3d
Normal file
Binary file not shown.
BIN
models/SentryM_d.3d
Normal file
BIN
models/SentryM_d.3d
Normal file
Binary file not shown.
|
|
@ -88,7 +88,7 @@ Class UnrealBackpack : BackpackItem replaces Backpack
|
|||
Super.DoPickupSpecial(toucher);
|
||||
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];
|
||||
xitemn[0] = 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.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 )
|
||||
{
|
||||
if ( sentry.master ) sentry.master.TakeInventory("SentryItem",200);
|
||||
|
|
@ -1500,7 +1505,11 @@ Class SentryItem : UnrealInventory
|
|||
override void DoEffect()
|
||||
{
|
||||
Super.DoEffect();
|
||||
if ( !bActive ) return;
|
||||
if ( !bActive )
|
||||
{
|
||||
if ( !(level.maptime%10) ) Charge = min(DefaultCharge,Charge+1);
|
||||
return;
|
||||
}
|
||||
if ( !tracer )
|
||||
{
|
||||
bActive = false;
|
||||
|
|
@ -2015,7 +2024,11 @@ Class MinigunSentryBase : Actor
|
|||
Vector3 x, y, z;
|
||||
[x, y, z] = dt_CoordUtil.GetAxes(pitch,angle,roll);
|
||||
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);
|
||||
else tracer.bFRIENDLY = false;
|
||||
}
|
||||
|
|
@ -2127,3 +2140,340 @@ Class MinigunSentryBase : Actor
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -979,7 +979,8 @@ Class UnrealMainHandler : EventHandler
|
|||
else if ( (e.Replacee == 'InvulnerabilitySphere') || (e.Replacee == 'ArtiInvulnerability') ) e.Replacement = 'PowerShield';
|
||||
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 if ( e.Replacee == 'ArtiEgg' ) e.Replacement = 'VoiceBox';
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue