First public commit.
This commit is contained in:
commit
356219ae5c
199 changed files with 3498 additions and 0 deletions
165
zscript/LGPL3.txt
Normal file
165
zscript/LGPL3.txt
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
539
zscript/flakcannon.zsc
Normal file
539
zscript/flakcannon.zsc
Normal file
|
|
@ -0,0 +1,539 @@
|
|||
Class FlakAmmo : Ammo
|
||||
{
|
||||
Default
|
||||
{
|
||||
Tag "Flak Shells";
|
||||
Inventory.Icon "I_FLAK";
|
||||
Inventory.PickupMessage "You picked up 10 Flak Shells.";
|
||||
Inventory.PickupSound "ut/ammo";
|
||||
Inventory.Amount 10;
|
||||
Inventory.MaxAmount 50;
|
||||
Ammo.BackpackAmount 50;
|
||||
Ammo.BackpackMaxAmount 100;
|
||||
Ammo.DropAmount 10;
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
FAMO A -1;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class FlakAmmo2 : FlakAmmo
|
||||
{
|
||||
Default
|
||||
{
|
||||
Tag "Flak Shell";
|
||||
Inventory.PickupMessage "You picked up a Flak Shell.";
|
||||
Inventory.Amount 1;
|
||||
Ammo.DropAmount 1;
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
FSLG A -1;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class ChunkLight : DynamicLight
|
||||
{
|
||||
Default
|
||||
{
|
||||
DynamicLight.Type "Point";
|
||||
Args 255,224,8;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
if ( !target )
|
||||
{
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
args[LIGHT_RED] = 255*target.alpha;
|
||||
args[LIGHT_GREEN] = 224*target.alpha;
|
||||
args[LIGHT_BLUE] = 128*target.alpha;
|
||||
}
|
||||
}
|
||||
|
||||
Class ChunkTrail : Actor
|
||||
{
|
||||
Default
|
||||
{
|
||||
RenderStyle "Add";
|
||||
Radius 0.1;
|
||||
Height 0;
|
||||
+NOBLOCKMAP;
|
||||
+NOGRAVITY;
|
||||
+DONTSPLASH;
|
||||
+FORCEXYBILLBOARD;
|
||||
+INVISIBLE; // temporarily until clipping screwery is fixed
|
||||
Scale 0.2;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
let l = Spawn("ChunkLight",pos);
|
||||
l.target = self;
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
A_SpawnParticle("FFFF00",SPF_FULLBRIGHT,1,8,startalphaf:alpha);
|
||||
A_SpawnParticle("E0A000",SPF_FULLBRIGHT,1,16,startalphaf:alpha*0.6);
|
||||
A_SpawnParticle("804000",SPF_FULLBRIGHT,1,32,startalphaf:alpha*0.3);
|
||||
if ( InStateSequence(CurState,FindState("Death")) ) return;
|
||||
if ( !target )
|
||||
{
|
||||
SetStateLabel("Death");
|
||||
return;
|
||||
}
|
||||
SetOrigin(target.pos+(0,0,speed),true);
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
FGLO A 1 Bright;
|
||||
Wait;
|
||||
Death:
|
||||
FGLO A 1 Bright A_FadeOut(0.1);
|
||||
Wait;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Class FlakChunk : Actor
|
||||
{
|
||||
Actor lasthit;
|
||||
ChunkTrail trail;
|
||||
double rollvel, pitchvel;
|
||||
double lifetime, lifespeed;
|
||||
int lifetics;
|
||||
Default
|
||||
{
|
||||
Obituary "%o was ripped to shreds by %k's Flak Cannon.";
|
||||
Radius 2;
|
||||
Height 2;
|
||||
Speed 80;
|
||||
DamageFunction Random[Flak](12,18);
|
||||
DamageType 'Shredded';
|
||||
BounceType "Doom";
|
||||
BounceFactor 0.8;
|
||||
PROJECTILE;
|
||||
+USEBOUNCESTATE
|
||||
-BOUNCEAUTOOFF
|
||||
Scale 0.5;
|
||||
}
|
||||
override bool CanCollideWith( Actor other, bool passive )
|
||||
{
|
||||
return (vel.length()>4.0);
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
lifetime = 0;
|
||||
lifespeed = FRandom[Flak](0.004,0.008);
|
||||
trail = ChunkTrail(Spawn("ChunkTrail",pos));
|
||||
trail.target = self;
|
||||
trail.speed = 0.5;
|
||||
rollvel = FRandom[Flak](50,100)*RandomPick[Flak](-1,1);
|
||||
scale *= Frandom[Flak](0.8,1.2);
|
||||
SetState(ResolveState("Spawn")+Random[Flak](0,3));
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
lifetics++;
|
||||
if ( lifetics > 3 )
|
||||
{
|
||||
lifetics = 0;
|
||||
if ( frame < 11 ) frame++;
|
||||
}
|
||||
lifetime += lifespeed;
|
||||
if ( (waterlevel <= 0) && (frame < 10) ) A_SpawnParticle("AAAAAA",0,35,2.0,velx:FRandom[Flak](-0.1,0.1),vely:FRandom[Flak](-0.1,0.1),velz:FRandom[Flak](-0.1,0.1),accelz:0.02,startalphaf:scale.x/0.5,sizestep:0.2);
|
||||
if ( trail ) trail.alpha = max(0,11-frame)/11.;
|
||||
if ( InStateSequence(CurState,FindState("Death")) ) return;
|
||||
A_SetRoll(roll+rollvel,SPF_INTERPOLATE);
|
||||
A_SetPitch(pitch+pitchvel,SPF_INTERPOLATE);
|
||||
}
|
||||
action void A_HandleBounce()
|
||||
{
|
||||
A_SprayDecal("WallCrack",-8);
|
||||
A_Gravity();
|
||||
invoker.rollvel = FRandom[Flak](50,100)*RandomPick[Flak](-1,1)*(vel.length()/speed);
|
||||
invoker.pitchvel = FRandom[Flak](50,100)*RandomPick[Flak](-1,1)*(vel.length()/speed);
|
||||
vel = (vel.unit()+(FRandom[Flak](-0.4,0.4),FRandom[Flak](-0.4,0.4),FRandom[Flak](-0.4,0.4))).unit()*vel.length();
|
||||
A_PlaySound("flak/bounce",volume:0.3);
|
||||
if ( vel.length() < 4.0 ) ExplodeMissile();
|
||||
}
|
||||
override int DoSpecialDamage( Actor target, int damage, Name damagetype )
|
||||
{
|
||||
if ( !target.bNOBLOOD )
|
||||
{
|
||||
if ( target != lasthit ) target.SpawnBlood(pos,AngleTo(target),damage);
|
||||
A_PlaySound("flak/meat",volume:0.3);
|
||||
}
|
||||
lasthit = target;
|
||||
return damage;
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
FCH1 A 0;
|
||||
Goto Idle;
|
||||
FCH2 A 0;
|
||||
Goto Idle;
|
||||
FCH3 A 0;
|
||||
Goto Idle;
|
||||
FCH4 A 0;
|
||||
Goto Idle;
|
||||
Idle:
|
||||
#### # -1;
|
||||
Stop;
|
||||
Bounce:
|
||||
#### # 0 A_HandleBounce();
|
||||
Goto Idle;
|
||||
Death:
|
||||
#### # 0
|
||||
{
|
||||
bMOVEWITHSECTOR = true;
|
||||
A_SetTics(Random[Flak](30,50));
|
||||
}
|
||||
#### # 1
|
||||
{
|
||||
A_SetScale(scale.x-0.002);
|
||||
if ( scale.x <= 0.0 ) Destroy();
|
||||
}
|
||||
Wait;
|
||||
Crash:
|
||||
TNT1 A 0
|
||||
{
|
||||
Spawn("BulletPuff",pos);
|
||||
A_PlaySound("flak/hit",volume:0.3);
|
||||
A_AlertMonsters();
|
||||
}
|
||||
XDeath:
|
||||
TNT1 A 1;
|
||||
Stop;
|
||||
Dummy:
|
||||
FCH1 ABCDEFGHIJKL -1;
|
||||
FCH2 ABCDEFGHIJKL -1;
|
||||
FCH3 ABCDEFGHIJKL -1;
|
||||
FCH4 ABCDEFGHIJKL -1;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class SlugSmoke : Actor
|
||||
{
|
||||
double lifetime, lifespeed;
|
||||
Default
|
||||
{
|
||||
Radius 0.1;
|
||||
Height 0;
|
||||
+NOBLOCKMAP;
|
||||
+NOGRAVITY;
|
||||
+DONTSPLASH;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
lifetime = 0;
|
||||
lifespeed = FRandom[Flak](0.004,0.008);
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
lifetime += lifespeed;
|
||||
if ( waterlevel <= 0 ) A_SpawnParticle("AAAAAA",0,50,16.0,velx:FRandom[Flak](-0.5,0.5),vely:FRandom[Flak](-0.5,0.5),velz:FRandom[Flak](-0.5,0.5),accelz:0.05,startalphaf:scale.x,sizestep:1.0);
|
||||
scale.x = max(0,1-lifetime);
|
||||
if ( scale.x <= 0 ) Destroy();
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
TNT1 A -1;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class SlugLight : DynamicLight
|
||||
{
|
||||
double lifetime;
|
||||
Default
|
||||
{
|
||||
DynamicLight.Type "Point";
|
||||
Args 255,224,128,80;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
lifetime = 1.0;
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
args[LIGHT_RED] = 255*lifetime;
|
||||
args[LIGHT_GREEN] = 224*lifetime;
|
||||
args[LIGHT_BLUE] = 128*lifetime;
|
||||
lifetime -= 0.05;
|
||||
if ( lifetime <= 0 ) Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
Class FlakSlug : Actor
|
||||
{
|
||||
ChunkTrail trail;
|
||||
Default
|
||||
{
|
||||
Obituary "%o was ripped to shreds by %k's Flak Cannon.";
|
||||
DamageType 'FlakDeath';
|
||||
Radius 2;
|
||||
Height 2;
|
||||
Speed 40;
|
||||
PROJECTILE;
|
||||
-NOGRAVITY;
|
||||
+SKYEXPLODE;
|
||||
+FORCERADIUSDMG;
|
||||
+HITTRACER;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
trail = ChunkTrail(Spawn("ChunkTrail",pos));
|
||||
trail.target = self;
|
||||
trail.speed = 1;
|
||||
vel.z += 5;
|
||||
}
|
||||
action void A_FlakExplode()
|
||||
{
|
||||
bForceXYBillboard = true;
|
||||
A_SetRenderStyle(1.0,STYLE_Add);
|
||||
A_SprayDecal("RocketBlast",150);
|
||||
A_NoGravity();
|
||||
A_SetScale(1.2);
|
||||
A_Explode(Random[Flak](60,80),150);
|
||||
A_QuakeEx(4,4,4,8,0,200,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.2);
|
||||
A_PlaySound("flak/explode",CHAN_VOICE);
|
||||
if ( !Tracer ) Spawn("SlugSmoke",pos);
|
||||
Spawn("SlugLight",pos);
|
||||
Vector3 x, y, z;
|
||||
double a, s;
|
||||
[x, y, z] = Matrix4.GetAxes(pitch,angle,roll);
|
||||
Actor p;
|
||||
for ( int i=0; i<5; i++ )
|
||||
{
|
||||
p = Spawn("FlakChunk",pos);
|
||||
a = FRandom[Flak](0,360);
|
||||
s = FRandom[Flak](0,0.2);
|
||||
Vector3 dir = (x+y*cos(a)*s+z*sin(a)*s).unit();
|
||||
p.angle = atan2(dir.y,dir.x);
|
||||
p.pitch = -asin(dir.z);
|
||||
p.vel = (cos(p.angle)*cos(p.pitch),sin(p.angle)*cos(p.pitch),-sin(p.pitch))*p.speed*FRandom[Flak](0.5,1.5);
|
||||
p.target = target;
|
||||
}
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
FSLG A 1
|
||||
{
|
||||
for ( int i=0; i<6; i++ )
|
||||
A_SpawnParticle("AAAAAA",0,50,12.0,velx:FRandom[Flak](-0.5,0.5),vely:FRandom[Flak](-0.5,0.5),velz:FRandom[Flak](-0.5,0.5),accelz:0.02,startalphaf:0.5,sizestep:1.0);
|
||||
}
|
||||
Wait;
|
||||
Death:
|
||||
EXP2 A 0 A_FlakExplode();
|
||||
EXP2 ABCDEFGHIJKLMNOPQR 1 BRIGHT;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class FlakLight : DynamicLight
|
||||
{
|
||||
Default
|
||||
{
|
||||
DynamicLight.Type "Point";
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
args[LIGHT_INTENSITY] = 150;
|
||||
args[LIGHT_RED] = 255;
|
||||
args[LIGHT_GREEN] = 224;
|
||||
args[LIGHT_BLUE] = 128;
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
if ( !target )
|
||||
{
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
SetOrigin(target.pos,true);
|
||||
}
|
||||
}
|
||||
|
||||
Class FlakMuzzle : Actor
|
||||
{
|
||||
Vector3 ofs;
|
||||
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
let l = Spawn("FlakLight",pos);
|
||||
l.target = self;
|
||||
if ( target ) ofs = target.Vec3To(self);
|
||||
else ofs = (0,0,0);
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
if ( !target )
|
||||
{
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
bInvisible = (target != players[consoleplayer].camera);
|
||||
SetOrigin(target.Vec3Offset(ofs.x-target.vel.x,ofs.y-target.vel.y,ofs.z-target.vel.z),true);
|
||||
}
|
||||
Default
|
||||
{
|
||||
RenderStyle "Add";
|
||||
Radius 0.1;
|
||||
Height 0;
|
||||
Scale 0.08;
|
||||
+NOGRAVITY;
|
||||
+NOBLOCKMAP;
|
||||
+DONTSPLASH;
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
FMUZ A 3 Bright;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class FlakCannon : UTWeapon
|
||||
{
|
||||
action void A_Selecting()
|
||||
{
|
||||
A_PlaySound("flak/select",CHAN_WEAPON);
|
||||
}
|
||||
action void A_Loading( bool first = false )
|
||||
{
|
||||
if ( first ) A_PlaySound("flak/load",CHAN_WEAPON);
|
||||
else A_PlaySound("flak/reload",CHAN_WEAPON);
|
||||
}
|
||||
action void A_FireChunks()
|
||||
{
|
||||
Weapon weap = Weapon(invoker);
|
||||
if ( !weap ) return;
|
||||
if ( weap.Ammo1.Amount <= 0 ) return;
|
||||
if ( !weap.DepleteAmmo(weap.bAltFire,true,1) ) return;
|
||||
A_PlaySound("flak/fire",CHAN_WEAPON);
|
||||
A_QuakeEx(1,1,1,3,0,64,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.05);
|
||||
Vector3 x, y, z;
|
||||
double a, s;
|
||||
[x, y, z] = Matrix4.GetAxes(pitch,angle,roll);
|
||||
Vector3 origin = pos+(0,0,player.viewheight)+10.0*x+2.0*y-3.0*z;
|
||||
let m = Spawn("FlakMuzzle",pos+(0,0,player.viewheight)+20.0*x+5.0*y-3.0*z);
|
||||
m.target = self;
|
||||
[x, y, z] = Matrix4.GetAxes(BulletSlope(),angle,roll);
|
||||
Actor p;
|
||||
for ( int i=0; i<8; i++ )
|
||||
{
|
||||
p = Spawn("FlakChunk",origin);
|
||||
a = FRandom[Flak](0,360);
|
||||
s = FRandom[Flak](0,0.2);
|
||||
Vector3 dir = (x+y*cos(a)*s+z*sin(a)*s).unit();
|
||||
p.angle = atan2(dir.y,dir.x);
|
||||
p.pitch = -asin(dir.z);
|
||||
p.vel = (cos(p.angle)*cos(p.pitch),sin(p.angle)*cos(p.pitch),-sin(p.pitch))*p.speed;
|
||||
p.target = self;
|
||||
}
|
||||
}
|
||||
action void A_FireSlug()
|
||||
{
|
||||
Weapon weap = Weapon(invoker);
|
||||
if ( !weap ) return;
|
||||
if ( weap.Ammo1.Amount <= 0 ) return;
|
||||
if ( !weap.DepleteAmmo(weap.bAltFire,true,1) ) return;
|
||||
A_PlaySound("flak/altfire",CHAN_WEAPON);
|
||||
A_QuakeEx(2,2,2,10,0,64,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.1);
|
||||
Vector3 x, y, z;
|
||||
double a, s;
|
||||
[x, y, z] = Matrix4.GetAxes(pitch,angle,roll);
|
||||
Vector3 origin = pos+(0,0,player.viewheight)+10.0*x+2.0*y-3.0*z;
|
||||
let m = Spawn("FlakMuzzle",pos+(0,0,player.viewheight)+20.0*x+5.0*y-3.0*z);
|
||||
m.target = self;
|
||||
Actor p = Spawn("FlakSlug",origin);
|
||||
p.angle = angle;
|
||||
p.pitch = BulletSlope();
|
||||
p.vel = (cos(p.angle)*cos(p.pitch),sin(p.angle)*cos(p.pitch),-sin(p.pitch))*p.speed;
|
||||
p.target = self;
|
||||
}
|
||||
|
||||
Default
|
||||
{
|
||||
Tag "Flak Cannon";
|
||||
Inventory.PickupMessage "You got the Flak Cannon.";
|
||||
Weapon.SlotNumber 8;
|
||||
Weapon.AmmoType "FlakAmmo";
|
||||
Weapon.AmmoUse 1;
|
||||
Weapon.AmmoType2 "FlakAmmo";
|
||||
Weapon.AmmoUse2 1;
|
||||
Weapon.AmmoGive 10;
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
FPCK A -1;
|
||||
Stop;
|
||||
FPCK B -1;
|
||||
Stop;
|
||||
Ready:
|
||||
FLKS A 1 A_Selecting();
|
||||
FLKS BCDEFGHIJKLMNOPQRSTUVWXYZ 1;
|
||||
FKS2 ABC 1;
|
||||
FLKL A 1 A_Loading(true);
|
||||
FLKL BCDEFGHIJKLMNO 1;
|
||||
Goto Idle;
|
||||
Loading:
|
||||
FLKL A 1
|
||||
{
|
||||
A_CheckReload();
|
||||
if ( invoker.Ammo1.Amount > 0 ) A_Loading();
|
||||
}
|
||||
FLKL BCDEFGHIJKLMNO 1;
|
||||
Idle:
|
||||
FLKI A 10;
|
||||
FLKI A 1 A_WeaponReady();
|
||||
Wait;
|
||||
Fire:
|
||||
FLKF A 1 A_FireChunks();
|
||||
FLKF BCDEFGHIJ 1;
|
||||
FLKF JJ 4;
|
||||
Goto Loading;
|
||||
AltFire:
|
||||
FLKA A 1 A_FireSlug();
|
||||
FLKA BCDEFGHIJK 2;
|
||||
FLKA KKK 4;
|
||||
Goto Loading;
|
||||
Select:
|
||||
FLKS A 1 A_Raise(int.max);
|
||||
Wait;
|
||||
Deselect:
|
||||
FLKD ABCDEFGHIJ 2;
|
||||
FLKD J 1 A_Lower(int.max);
|
||||
Wait;
|
||||
}
|
||||
}
|
||||
72
zscript/mk_coordutil.zsc
Normal file
72
zscript/mk_coordutil.zsc
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
Coordinate Utility helper class.
|
||||
(C)2018 Marisa Kirisame, UnSX Team.
|
||||
Released under the GNU Lesser General Public License version 3 (or later).
|
||||
See https://www.gnu.org/licenses/lgpl-3.0.txt for its terms.
|
||||
*/
|
||||
|
||||
Class mkCoordUtil
|
||||
{
|
||||
// projects a world point onto screen
|
||||
// view matrix setup mostly pulled from gutawer's code
|
||||
static Vector3 WorldToScreen( Vector3 vect, Vector3 eye, double pitch, double yaw, double roll, double vfov )
|
||||
{
|
||||
double ar = Screen.getWidth()/double(Screen.getHeight());
|
||||
double fovr = (ar>=1.3)?1.333333:ar;
|
||||
double fov = 2*atan(tan(clamp(vfov,5,170)*0.5)/fovr);
|
||||
float pr = level.pixelstretch;
|
||||
double angx = cos(pitch);
|
||||
double angy = sin(pitch)*pr;
|
||||
double alen = sqrt(angx*angx+angy*angy);
|
||||
double apitch = asin(angy/alen);
|
||||
double ayaw = yaw-90;
|
||||
// rotations
|
||||
Matrix4 mRoll = Matrix4.rotate((0,0,1),roll);
|
||||
Matrix4 mPitch = Matrix4.rotate((1,0,0),apitch);
|
||||
Matrix4 mYaw = Matrix4.rotate((0,-1,0),ayaw);
|
||||
// scaling
|
||||
Matrix4 mScale = Matrix4.identity();
|
||||
mScale.set(1,1,pr);
|
||||
// YZ swap
|
||||
Matrix4 mYZ = Matrix4.create();
|
||||
mYZ.set(0,0,1);
|
||||
mYZ.set(2,1,1);
|
||||
mYZ.set(1,2,-1);
|
||||
mYZ.set(3,3,1);
|
||||
// translation
|
||||
Matrix4 mMove = Matrix4.identity();
|
||||
mMove.set(3,0,-eye.x);
|
||||
mMove.set(3,1,-eye.y);
|
||||
mMove.set(3,2,-eye.z);
|
||||
// perspective
|
||||
Matrix4 mPerspective = Matrix4.perspective(fov,ar,5,65535);
|
||||
// full matrix
|
||||
Matrix4 mView = mRoll.mul(mPitch);
|
||||
mView = mView.mul(mYaw);
|
||||
mView = mView.mul(mScale);
|
||||
mView = mView.mul(mYZ);
|
||||
mView = mView.mul(mMove);
|
||||
Matrix4 mWorldToScreen = mPerspective.mul(mView);
|
||||
return mWorldToScreen.vmat(vect);
|
||||
}
|
||||
|
||||
// converts a projected screen position to 2D canvas coords
|
||||
// thanks once again to gutawer for making this thing screenblocks-aware
|
||||
// [NEW] added second return value: true if the point has valid depth (i.e.: it's not behind view)
|
||||
// [TODO] handle forced aspect ratio (e.g.: 320x200 scaling)
|
||||
static Vector2, bool ToViewport( Vector3 screenpos, bool scrblocks = true )
|
||||
{
|
||||
if ( scrblocks )
|
||||
{
|
||||
int winx, winy, winw, winh;
|
||||
[winx,winy,winw,winh] = Screen.getViewWindow();
|
||||
int sh = Screen.getHeight();
|
||||
int ht = sh;
|
||||
int screenblocks = CVar.GetCVar("screenblocks",players[consoleplayer]).getInt();
|
||||
if ( screenblocks < 10 ) ht = (screenblocks*sh/10)&~7;
|
||||
int bt = sh-(ht+winy-((ht-winh)/2));
|
||||
return (winx,sh-bt-ht)+((screenpos.x+1)*winw,(-screenpos.y+1)*ht)*0.5, (screenpos.z<=1.0);
|
||||
}
|
||||
else return ((screenpos.x+1)*Screen.getWidth(),(-screenpos.y+1)*Screen.getHeight())*0.5, (screenpos.z<=1.0);
|
||||
}
|
||||
}
|
||||
123
zscript/mk_matrix.zsc
Normal file
123
zscript/mk_matrix.zsc
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
Matrix Math helper class.
|
||||
(C)2018 Marisa Kirisame, UnSX Team.
|
||||
Released under the GNU Lesser General Public License version 3 (or later).
|
||||
See https://www.gnu.org/licenses/lgpl-3.0.txt for its terms.
|
||||
*/
|
||||
|
||||
Class Matrix4
|
||||
{
|
||||
private double m[16];
|
||||
|
||||
Matrix4 init()
|
||||
{
|
||||
int i;
|
||||
for ( i=0; i<16; i++ ) m[i] = 0;
|
||||
return self;
|
||||
}
|
||||
|
||||
static Matrix4 create()
|
||||
{
|
||||
return new("Matrix4").init();
|
||||
}
|
||||
|
||||
static Matrix4 identity()
|
||||
{
|
||||
Matrix4 o = Matrix4.create();
|
||||
for ( int i=0; i<4; i++ ) o.set(i,i,1);
|
||||
return o;
|
||||
}
|
||||
|
||||
double get( int c, int r )
|
||||
{
|
||||
return m[r*4+c];
|
||||
}
|
||||
|
||||
void set( int c, int r, double v )
|
||||
{
|
||||
m[r*4+c] = v;
|
||||
}
|
||||
|
||||
Matrix4 add( Matrix4 o )
|
||||
{
|
||||
Matrix4 r = Matrix4.create();
|
||||
int i, j;
|
||||
for ( i=0; i<4; i++ ) for ( j=0; j<4; j++ )
|
||||
r.set(j,i,get(j,i)+o.get(j,i));
|
||||
return r;
|
||||
}
|
||||
|
||||
Matrix4 scale( double s )
|
||||
{
|
||||
Matrix4 r = Matrix4.create();
|
||||
int i, j;
|
||||
for ( i=0; i<4; i++ ) for ( j=0; j<4; j++ )
|
||||
r.set(j,i,get(j,i)*s);
|
||||
return r;
|
||||
}
|
||||
|
||||
Matrix4 mul( Matrix4 o )
|
||||
{
|
||||
Matrix4 r = Matrix4.create();
|
||||
int i, j;
|
||||
for ( i=0; i<4; i++ ) for ( j=0; j<4; j++ )
|
||||
r.set(j,i,get(0,i)*o.get(j,0)+get(1,i)*o.get(j,1)+get(2,i)*o.get(j,2)+get(3,i)*o.get(j,3));
|
||||
return r;
|
||||
}
|
||||
|
||||
Vector3 vmat( Vector3 o )
|
||||
{
|
||||
double x, y, z, w;
|
||||
x = get(0,0)*o.x+get(1,0)*o.y+get(2,0)*o.z+get(3,0);
|
||||
y = get(0,1)*o.x+get(1,1)*o.y+get(2,1)*o.z+get(3,1);
|
||||
z = get(0,2)*o.x+get(1,2)*o.y+get(2,2)*o.z+get(3,2);
|
||||
w = get(0,3)*o.x+get(1,3)*o.y+get(2,3)*o.z+get(3,3);
|
||||
return (x,y,z)/w;
|
||||
}
|
||||
|
||||
static Matrix4 rotate( Vector3 axis, double theta )
|
||||
{
|
||||
Matrix4 r = Matrix4.identity();
|
||||
double s, c, oc;
|
||||
s = sin(theta);
|
||||
c = cos(theta);
|
||||
oc = 1.0-c;
|
||||
r.set(0,0,oc*axis.x*axis.x+c);
|
||||
r.set(1,0,oc*axis.x*axis.y-axis.z*s);
|
||||
r.set(2,0,oc*axis.x*axis.z+axis.y*s);
|
||||
r.set(0,1,oc*axis.y*axis.x+axis.z*s);
|
||||
r.set(1,1,oc*axis.y*axis.y+c);
|
||||
r.set(2,1,oc*axis.y*axis.z-axis.x*s);
|
||||
r.set(0,2,oc*axis.z*axis.x-axis.y*s);
|
||||
r.set(1,2,oc*axis.z*axis.y+axis.x*s);
|
||||
r.set(2,2,oc*axis.z*axis.z+c);
|
||||
return r;
|
||||
}
|
||||
|
||||
static Matrix4 perspective( double fov, double ar, double znear, double zfar )
|
||||
{
|
||||
Matrix4 r = Matrix4.create();
|
||||
double f = 1/tan(fov*0.5);
|
||||
r.set(0,0,f/ar);
|
||||
r.set(1,1,f);
|
||||
r.set(2,2,(zfar+znear)/(znear-zfar));
|
||||
r.set(3,2,(2*zfar*znear)/(znear-zfar));
|
||||
r.set(2,3,-1);
|
||||
return r;
|
||||
}
|
||||
|
||||
// UE-like axes from rotation
|
||||
static Vector3, Vector3, Vector3 getaxes( double pitch, double yaw, double roll )
|
||||
{
|
||||
Vector3 x = (1,0,0), y = (0,-1,0), z = (0,0,1); // y inverted for left-handed result
|
||||
Matrix4 mRoll = Matrix4.rotate((1,0,0),roll);
|
||||
Matrix4 mPitch = Matrix4.rotate((0,1,0),pitch);
|
||||
Matrix4 mYaw = Matrix4.rotate((0,0,1),yaw);
|
||||
Matrix4 mRot = mRoll.mul(mYaw);
|
||||
mRot = mRot.mul(mPitch);
|
||||
x = mRot.vmat(x);
|
||||
y = mRot.vmat(y);
|
||||
z = mRot.vmat(z);
|
||||
return x, y, z;
|
||||
}
|
||||
}
|
||||
486
zscript/shockrifle.zsc
Normal file
486
zscript/shockrifle.zsc
Normal file
|
|
@ -0,0 +1,486 @@
|
|||
Class ShockAmmo : Ammo
|
||||
{
|
||||
Default
|
||||
{
|
||||
Tag "Flak Shells";
|
||||
Inventory.Icon "I_ASMD";
|
||||
Inventory.PickupMessage "You picked up a Shock Core.";
|
||||
Inventory.PickupSound "ut/ammo";
|
||||
Inventory.Amount 10;
|
||||
Inventory.MaxAmount 50;
|
||||
Ammo.BackpackAmount 50;
|
||||
Ammo.BackpackMaxAmount 100;
|
||||
Ammo.DropAmount 10;
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
SHOA A -1;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class ShockBeamTracer : LineTracer
|
||||
{
|
||||
Actor owner, ignore;
|
||||
|
||||
override ETraceStatus TraceCallback()
|
||||
{
|
||||
if ( Results.HitType == TRACE_HitActor )
|
||||
{
|
||||
if ( (Results.HitActor == owner) || (Results.HitActor == ignore) ) return TRACE_Skip;
|
||||
if ( Results.HitActor.bSHOOTABLE || Results.HitActor is 'ShockHitbox' ) return TRACE_Stop;
|
||||
return TRACE_Skip;
|
||||
}
|
||||
else if ( (Results.HitType == TRACE_HitWall) && (Results.Tier == TIER_Middle) )
|
||||
{
|
||||
if ( !Results.HitLine.sidedef[1] || (Results.HitLine.Flags&Line.ML_BlockHitscan) )
|
||||
return TRACE_Stop;
|
||||
return TRACE_Skip;
|
||||
}
|
||||
return TRACE_Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class ShockRifleWave : Actor
|
||||
{
|
||||
Default
|
||||
{
|
||||
RenderStyle "Add";
|
||||
Radius 0.1;
|
||||
Height 0;
|
||||
Scale 0.7;
|
||||
+NOBLOCKMAP;
|
||||
+NOGRAVITY;
|
||||
+DONTSPLASH;
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
alpha -= 1/50.;
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
SWAV A 50 Bright;
|
||||
SWAV B 0 Bright;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class ShockBeamRing : Actor
|
||||
{
|
||||
Default
|
||||
{
|
||||
RenderStyle "Add";
|
||||
Radius 0.1;
|
||||
Height 0;
|
||||
Scale 0.5;
|
||||
ReactionTime 18;
|
||||
+NOBLOCKMAP;
|
||||
+NOGRAVITY;
|
||||
+DONTSPLASH;
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
alpha -= 1./ReactionTime;
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
SRNG ABCDEFGHI 2 Bright;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class ShockBlastRing : ShockBeamRing
|
||||
{
|
||||
Default
|
||||
{
|
||||
Scale 3.0;
|
||||
ReactionTime 45;
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
SRNG ABCDEFGHI 5 Bright;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class ShockBeam : Actor
|
||||
{
|
||||
ShockBeamTracer t;
|
||||
Vector3 tracedir;
|
||||
bool moving;
|
||||
double totaldist;
|
||||
|
||||
Default
|
||||
{
|
||||
Obituary "%k inflicted mortal damage upon %o with the Shock Rifle";
|
||||
RenderStyle "Add";
|
||||
Radius 0.1;
|
||||
Height 0;
|
||||
Scale 0.4;
|
||||
DamageFunction Random[ASMD](30,45);
|
||||
+NOGRAVITY;
|
||||
+NOCLIP;
|
||||
+DONTSPLASH;
|
||||
+FORCEXYBILLBOARD;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
t = new("ShockBeamTracer");
|
||||
t.owner = target;
|
||||
t.ignore = self;
|
||||
moving = true;
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
if ( !moving ) return;
|
||||
// step trace
|
||||
tracedir = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
|
||||
t.Trace(pos,cursector,tracedir,1000,0);
|
||||
totaldist += t.Results.Distance;
|
||||
// spawn particles
|
||||
for ( int i=0; i<t.Results.Distance; i+=80 )
|
||||
Spawn("ShockBeamLight",Vec3Offset(tracedir.x*i,tracedir.y*i,tracedir.z*i));
|
||||
for ( int i=0; i<t.Results.Distance; i+=8 )
|
||||
{
|
||||
A_SpawnParticle("F0A0FF",SPF_FULLBRIGHT,15,2,0,tracedir.x*i,tracedir.y*i,tracedir.z*i,FRandom[ASMD](-.1,.1),FRandom[ASMD](-.1,.1),FRandom[ASMD](-.1,.1),startalphaf:1,sizestep:-.1);
|
||||
A_SpawnParticle("A040FF",SPF_FULLBRIGHT,20,4,0,tracedir.x*i,tracedir.y*i,tracedir.z*i,FRandom[ASMD](-.1,.1),FRandom[ASMD](-.1,.1),FRandom[ASMD](-.1,.1),startalphaf:.75,sizestep:-.1);
|
||||
A_SpawnParticle("8020FF",SPF_FULLBRIGHT,25,6,0,tracedir.x*i,tracedir.y*i,tracedir.z*i,FRandom[ASMD](-.1,.1),FRandom[ASMD](-.1,.1),FRandom[ASMD](-.1,.1),startalphaf:.5,sizestep:-.1);
|
||||
A_SpawnParticle("602080",SPF_FULLBRIGHT,30,8,0,tracedir.x*i,tracedir.y*i,tracedir.z*i,FRandom[ASMD](-.1,.1),FRandom[ASMD](-.1,.1),FRandom[ASMD](-.1,.1),startalphaf:.25,sizestep:-.1);
|
||||
}
|
||||
if ( totaldist >= 10000.0 )
|
||||
{
|
||||
// reposition and explode on air
|
||||
SetOrigin(t.Results.HitPos-t.Results.HitVector*4,true);
|
||||
A_SprayDecal("ShockMark",16);
|
||||
ExplodeMissile(t.Results.HitLine,null);
|
||||
moving = false;
|
||||
let r = Spawn("ShockBeamRing",pos);
|
||||
r.angle = atan2(t.Results.HitVector.y,t.Results.HitVector.x);
|
||||
r.pitch = asin(-t.Results.HitVector.z);
|
||||
}
|
||||
else if ( t.Results.HitType == TRACE_HitNone )
|
||||
{
|
||||
// reposition
|
||||
SetOrigin(t.Results.HitPos+t.Results.HitVector,true);
|
||||
angle = atan2(t.Results.HitVector.y,t.Results.HitVector.x);
|
||||
pitch = asin(-t.Results.HitVector.z);
|
||||
}
|
||||
else if ( t.Results.HitType == TRACE_HitActor )
|
||||
{
|
||||
// reposition and explode on actor
|
||||
SetOrigin(t.Results.HitPos-t.Results.HitVector*4,true);
|
||||
ExplodeMissile(null,t.Results.HitActor);
|
||||
if ( t.Results.HitActor is 'ShockHitbox' )
|
||||
{
|
||||
if ( target ) target.TakeInventory('ShockAmmo',2);
|
||||
let b = t.Results.HitActor.target;
|
||||
b.ExplodeMissile(null,self);
|
||||
b.A_Explode(Random[ASMD](150,160),250);
|
||||
b.A_QuakeEx(6,6,6,60,0,1200,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.2);
|
||||
b.A_SprayDecal("BigShockMark1",100);
|
||||
b.A_SprayDecal("BigShockMark2",100);
|
||||
Spawn("ShockRifleWave",b.pos);
|
||||
Spawn("ShockBlastLight",b.pos);
|
||||
let r = Spawn("ShockBlastRing",b.pos);
|
||||
r.angle = atan2(t.Results.HitVector.y,t.Results.HitVector.x);
|
||||
r.pitch = asin(-t.Results.HitVector.z);
|
||||
A_PlaySound("shock/blast",CHAN_WEAPON,attenuation:0.5);
|
||||
}
|
||||
else
|
||||
{
|
||||
t.Results.HitActor.DamageMobj(self,target,Random[ASMD](35,50),'jolted');
|
||||
let r = Spawn("ShockBeamRing",pos);
|
||||
r.angle = atan2(t.Results.HitVector.y,t.Results.HitVector.x);
|
||||
r.pitch = asin(-t.Results.HitVector.z);
|
||||
}
|
||||
moving = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// reposition and explode on wall
|
||||
SetOrigin(t.Results.HitPos-t.Results.HitVector*4,true);
|
||||
A_SprayDecal("ShockMark",16);
|
||||
ExplodeMissile(t.Results.HitLine,null);
|
||||
moving = false;
|
||||
Vector3 HitNormal = t.Results.HitVector;
|
||||
if ( t.Results.HitType == TRACE_HitWall )
|
||||
{
|
||||
t.Results.HitLine.RemoteActivate(target,t.Results.Side,SPAC_Impact,pos);
|
||||
// calculate normal
|
||||
HitNormal = (-t.Results.HitLine.delta.y,t.Results.HitLine.delta.x,0).unit();
|
||||
if ( t.Results.Side == 1 ) HitNormal *= -1;
|
||||
}
|
||||
else if ( t.Results.HitType == TRACE_HitFloor )
|
||||
HitNormal = t.Results.HitSector.floorplane.Normal;
|
||||
else if ( t.Results.HitType == TRACE_HitCeiling )
|
||||
HitNormal = t.Results.HitSector.ceilingplane.Normal;
|
||||
let r = Spawn("ShockBeamRing",pos);
|
||||
r.angle = atan2(HitNormal.y,HitNormal.x);
|
||||
r.pitch = asin(-HitNormal.z);
|
||||
}
|
||||
}
|
||||
action void A_BeamExplode()
|
||||
{
|
||||
Spawn("ShockBeamLight",pos);
|
||||
A_QuakeEx(2,2,2,5,0,120,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.1);
|
||||
A_PlaySound("shock/hit",CHAN_VOICE);
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
TNT1 A 1;
|
||||
Wait;
|
||||
Death:
|
||||
TNT1 A 0 A_BeamExplode();
|
||||
AEXP ABCDEFGHIJKL 1 Bright;
|
||||
TNT1 A 100;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class ShockBallLight : DynamicLight
|
||||
{
|
||||
Default
|
||||
{
|
||||
DynamicLight.Type "Point";
|
||||
Args 160,128,255,120;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
if ( !target || target.InStateSequence(target.CurState,target.ResolveState("Death")) )
|
||||
{
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
SetOrigin(target.pos,true);
|
||||
args[LIGHT_INTENSITY] = Random[ASMD](10,14)*10;
|
||||
}
|
||||
}
|
||||
|
||||
Class ShockBeamLight : ShockExplLight
|
||||
{
|
||||
Default
|
||||
{
|
||||
ReactionTime 15;
|
||||
Args 0,0,0,80;
|
||||
}
|
||||
}
|
||||
|
||||
Class ShockBeamHitLight : ShockExplLight
|
||||
{
|
||||
Default
|
||||
{
|
||||
ReactionTime 24;
|
||||
Args 0,0,0,120;
|
||||
}
|
||||
}
|
||||
|
||||
Class ShockBlastLight : ShockExplLight
|
||||
{
|
||||
Default
|
||||
{
|
||||
ReactionTime 50;
|
||||
Args 0,0,0,300;
|
||||
}
|
||||
}
|
||||
|
||||
Class ShockExplLight : DynamicLight
|
||||
{
|
||||
double lifetime;
|
||||
Default
|
||||
{
|
||||
DynamicLight.Type "Point";
|
||||
ReactionTime 30;
|
||||
Args 160,128,255,150;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
lifetime = 1.0;
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
args[LIGHT_RED] = 160*lifetime;
|
||||
args[LIGHT_GREEN] = 128*lifetime;
|
||||
args[LIGHT_BLUE] = 255*lifetime;
|
||||
lifetime -= 1./ReactionTime;
|
||||
if ( lifetime <= 0 ) Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
Class ShockHitbox : Actor
|
||||
{
|
||||
Default
|
||||
{
|
||||
Radius 16;
|
||||
Height 16;
|
||||
+NOGRAVITY;
|
||||
+NOCLIP;
|
||||
+DONTSPLASH;
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
if ( !target || target.InStateSequence(target.CurState,target.ResolveState("Death")) )
|
||||
{
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
SetOrigin(target.pos-(0,0,height*0.5),true);
|
||||
}
|
||||
}
|
||||
|
||||
Class ShockBall : Actor
|
||||
{
|
||||
Actor l, b;
|
||||
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
l = Spawn("ShockBallLight",pos);
|
||||
l.target = self;
|
||||
b = Spawn("ShockHitbox",pos);
|
||||
b.target = self;
|
||||
}
|
||||
action void A_BallExplode()
|
||||
{
|
||||
A_Explode(Random[ASMD](50,60),70);
|
||||
A_SprayDecal("ShockMarkBig",16);
|
||||
Spawn("ShockExplLight",pos);
|
||||
A_SetScale(1.0);
|
||||
let r = Spawn("ShockBeamRing",pos);
|
||||
r.angle = angle;
|
||||
r.pitch = pitch;
|
||||
r.scale *= 1.5;
|
||||
A_PlaySound("shock/hit",CHAN_VOICE);
|
||||
A_PlaySound("shock/ball",CHAN_WEAPON);
|
||||
A_QuakeEx(4,4,4,30,0,200,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.15);
|
||||
}
|
||||
Default
|
||||
{
|
||||
Obituary "%k inflicted mortal damage upon %o with the Shock Rifle";
|
||||
RenderStyle "Add";
|
||||
DamageType 'jolted';
|
||||
Radius 4;
|
||||
Height 4;
|
||||
Scale 0.4;
|
||||
Speed 20;
|
||||
PROJECTILE;
|
||||
+FORCEXYBILLBOARD;
|
||||
+SKYEXPLODE;
|
||||
+FORCERADIUSDMG;
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
ABAL ABCD 2 Bright;
|
||||
Loop;
|
||||
Death:
|
||||
TNT1 A 0 A_BallExplode();
|
||||
AEXP ABCDEFGHIJKL 2 Bright;
|
||||
TNT1 A 300;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class ShockRifle : UTWeapon
|
||||
{
|
||||
action void A_Selecting()
|
||||
{
|
||||
A_PlaySound("shock/select",CHAN_WEAPON);
|
||||
}
|
||||
action void A_ShockFire()
|
||||
{
|
||||
Weapon weap = Weapon(invoker);
|
||||
if ( !weap ) return;
|
||||
if ( weap.Ammo1.Amount <= 0 ) return;
|
||||
if ( !weap.DepleteAmmo(weap.bAltFire,true,1) ) return;
|
||||
A_PlaySound("shock/fire",CHAN_WEAPON);
|
||||
A_QuakeEx(3,3,3,4,0,64,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.1);
|
||||
Vector3 x, y, z;
|
||||
double a, s;
|
||||
[x, y, z] = Matrix4.GetAxes(pitch,angle,roll);
|
||||
Vector3 origin = pos+(0,0,player.viewheight)+10.0*x+3.0*y-4.0*z;
|
||||
Actor p = Spawn("ShockBeam",origin);
|
||||
p.angle = angle;
|
||||
p.pitch = BulletSlope();
|
||||
p.target = self;
|
||||
}
|
||||
action void A_ShockAlt()
|
||||
{
|
||||
Weapon weap = Weapon(invoker);
|
||||
if ( !weap ) return;
|
||||
if ( weap.Ammo1.Amount <= 0 ) return;
|
||||
if ( !weap.DepleteAmmo(weap.bAltFire,true,1) ) return;
|
||||
A_PlaySound("shock/altfire",CHAN_WEAPON);
|
||||
A_QuakeEx(3,3,3,8,0,64,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.1);
|
||||
Vector3 x, y, z;
|
||||
double a, s;
|
||||
[x, y, z] = Matrix4.GetAxes(pitch,angle,roll);
|
||||
Vector3 origin = pos+(0,0,player.viewheight)+10.0*x+3.0*y-4.0*z;
|
||||
Actor p = Spawn("ShockBall",origin);
|
||||
p.angle = angle;
|
||||
p.pitch = BulletSlope();
|
||||
p.vel = (cos(p.angle)*cos(p.pitch),sin(p.angle)*cos(p.pitch),-sin(p.pitch))*p.speed;
|
||||
p.target = self;
|
||||
}
|
||||
|
||||
Default
|
||||
{
|
||||
Tag "Shock Rifle";
|
||||
Inventory.PickupMessage "You got the ASMD Shock Rifle.";
|
||||
Weapon.SlotNumber 4;
|
||||
Weapon.AmmoType "ShockAmmo";
|
||||
Weapon.AmmoUse 1;
|
||||
Weapon.AmmoType2 "ShockAmmo";
|
||||
Weapon.AmmoUse2 1;
|
||||
Weapon.AmmoGive 20;
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
ASMP A -1;
|
||||
Stop;
|
||||
ASMP B -1;
|
||||
Stop;
|
||||
Ready:
|
||||
ASMS A 1 A_Selecting();
|
||||
ASMS BCDEFGHIJKLMNO 1;
|
||||
Idle:
|
||||
ASMI A 1
|
||||
{
|
||||
A_CheckReload();
|
||||
A_WeaponReady();
|
||||
}
|
||||
Wait;
|
||||
Fire:
|
||||
ASMF A 1 A_ShockFire();
|
||||
ASMF BCDEFGHIJ 2;
|
||||
Goto Idle;
|
||||
AltFire:
|
||||
ASMA A 1 A_ShockAlt();
|
||||
ASMA BCDEFGHIJ 2;
|
||||
Goto Idle;
|
||||
Deselect:
|
||||
ASMD ABCDEFG 1;
|
||||
ASMD G 1 A_Lower(int.max);
|
||||
Wait;
|
||||
Select:
|
||||
ASMS A 1 A_Raise(int.max);
|
||||
Wait;
|
||||
}
|
||||
}
|
||||
64
zscript/utcommon.zsc
Normal file
64
zscript/utcommon.zsc
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
Class UTWeapon : Weapon
|
||||
{
|
||||
override Inventory CreateTossable( int amt )
|
||||
{
|
||||
Inventory d = Super.CreateTossable(amt);
|
||||
if ( d && (d.GetClass() == GetClass()) )
|
||||
d.SetState(d.ResolveState("Spawn")+1);
|
||||
return d;
|
||||
}
|
||||
|
||||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
if ( !Owner || !Owner.player || (Owner.player.ReadyWeapon != self) ) return;
|
||||
Owner.player.WeaponState |= WF_WEAPONBOBBING; // UT weapons always bob
|
||||
}
|
||||
|
||||
Default
|
||||
{
|
||||
Inventory.PickupSound "ut/weapon";
|
||||
Weapon.BobStyle "Smooth";
|
||||
Weapon.BobSpeed 1.5;
|
||||
Weapon.BobRangeX 0.2;
|
||||
Weapon.BobRangeY 0.4;
|
||||
}
|
||||
}
|
||||
|
||||
Class UTMenuHandler : StaticEventHandler
|
||||
{
|
||||
ui TextureID tex;
|
||||
|
||||
ui void StartMenu()
|
||||
{
|
||||
if ( gamestate != GS_TITLELEVEL ) return;
|
||||
if ( CVar.GetCVar('flak_protomenu',players[consoleplayer]).GetBool() )
|
||||
{
|
||||
S_ChangeMusic("xyzdMenu");
|
||||
tex = TexMan.CheckForTexture("protobg",TexMan.Type_Any);
|
||||
}
|
||||
else
|
||||
{
|
||||
S_ChangeMusic("utmenu23");
|
||||
tex = TexMan.CheckForTexture("finalbg",TexMan.Type_Any);
|
||||
}
|
||||
}
|
||||
|
||||
override void ConsoleProcess( ConsoleEvent e )
|
||||
{
|
||||
if ( e.Name ~== "refreshmenu" ) StartMenu();
|
||||
}
|
||||
|
||||
override void PostUiTick()
|
||||
{
|
||||
if ( gametic <= 0 ) StartMenu();
|
||||
}
|
||||
|
||||
override void RenderOverlay( RenderEvent e )
|
||||
{
|
||||
if ( gamestate != GS_TITLELEVEL ) return;
|
||||
if ( tex.IsNull() || !tex.IsValid() ) return;
|
||||
Screen.Dim("Black",1.0,0,0,Screen.GetWidth(),Screen.GetHeight());
|
||||
Screen.DrawTexture(tex,true,0,0,DTA_VirtualWidth,1024,DTA_VirtualHeight,768);
|
||||
}
|
||||
}
|
||||
574
zscript/warheadlauncher.zsc
Normal file
574
zscript/warheadlauncher.zsc
Normal file
|
|
@ -0,0 +1,574 @@
|
|||
// shouldn't be placed in the world (it wasn't in UT99)
|
||||
Class WarheadAmmo : Ammo
|
||||
{
|
||||
Default
|
||||
{
|
||||
Tag "Redeemer Missile";
|
||||
Inventory.Icon "I_WARH";
|
||||
Inventory.PickupMessage "You picked up a Redeemer Missile.";
|
||||
Inventory.PickupSound "ut/ammo";
|
||||
Inventory.Amount 1;
|
||||
Inventory.MaxAmount 2;
|
||||
Ammo.BackpackAmount 0;
|
||||
Ammo.BackpackMaxAmount 2;
|
||||
Ammo.DropAmount 1;
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
WMIS A -1;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class ShockWave : Actor
|
||||
{
|
||||
double shocksize, olddmgradius;
|
||||
double lifespan;
|
||||
int icount;
|
||||
ThinkerIterator t;
|
||||
Default
|
||||
{
|
||||
Obituary "%o was vaporized by %k's Redeemer!!";
|
||||
RenderStyle "Add";
|
||||
Radius 0.1;
|
||||
Height 0;
|
||||
Scale 1.0;
|
||||
ReactionTime 60;
|
||||
+NOBLOCKMAP;
|
||||
+NOGRAVITY;
|
||||
+DONTSPLASH;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
lifespan = ReactionTime;
|
||||
A_PlaySound("warhead/explode",CHAN_VOICE,attenuation:ATTN_NONE);
|
||||
A_QuakeEx(9,9,9,100,0,12000,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.5);
|
||||
t = ThinkerIterator.Create("Actor");
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
if ( alpha <= 0 ) return;
|
||||
icount++;
|
||||
if ( icount == 4 ) Spawn("WarheadSubExplosion",pos);
|
||||
lifespan--;
|
||||
alpha -= 1./ReactionTime;
|
||||
shocksize = 13*(ReactionTime-lifespan)+3.5/(lifespan/ReactionTime+0.05);
|
||||
A_SetScale(shocksize*0.25);
|
||||
double dmgradius = shocksize*1.5;
|
||||
Actor a;
|
||||
t.Reinit();
|
||||
while ( a = Actor(t.Next()) )
|
||||
{
|
||||
if ( !a.bShootable || !CheckSight(a) || (Distance3D(a) > dmgradius) ) continue;
|
||||
Vector3 dir = Vec3To(a);
|
||||
double dist = max(1,dir.length());
|
||||
dir = dir/dist+(0,0,0.3);
|
||||
double moscale = max(0,1100-0.22*dist);
|
||||
if ( (dist > olddmgradius) || (dir dot a.vel < 0) )
|
||||
{
|
||||
a.vel += dir*(moscale/a.mass+20);
|
||||
a.DamageMobj(self,target,moscale,'RedeemerDeath');
|
||||
}
|
||||
}
|
||||
olddmgradius = dmgradius;
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
RWAV A 100 Bright;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class WarheadSubExplosion : Actor
|
||||
{
|
||||
Default
|
||||
{
|
||||
Renderstyle "Add";
|
||||
Scale 2.8;
|
||||
+NOGRAVITY;
|
||||
+NOCLIP;
|
||||
+DONTSPLASH;
|
||||
+FORCEXYBILLBOARD;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
Spawn("WarheadExplodLight",pos);
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
WE__ ABCDEFGHIJKLMNOPR 3 Bright;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class WarheadHitbox : Actor
|
||||
{
|
||||
Default
|
||||
{
|
||||
Radius 8;
|
||||
Height 8;
|
||||
+SHOOTABLE;
|
||||
+NOGRAVITY;
|
||||
+NOCLIP;
|
||||
+DONTSPLASH;
|
||||
+NOBLOOD;
|
||||
}
|
||||
override int DamageMobj( Actor inflictor, Actor source, int damage, Name mod, int flags, double angle )
|
||||
{
|
||||
if ( (damage > 5) && target )
|
||||
{
|
||||
target.bAMBUSH = true;
|
||||
target.ExplodeMissile(null,inflictor);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
if ( !target )
|
||||
{
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
SetOrigin(target.pos-(0,0,height*0.5),true);
|
||||
}
|
||||
}
|
||||
|
||||
Class WarheadExplodLight : DynamicLight
|
||||
{
|
||||
double lifetime;
|
||||
Default
|
||||
{
|
||||
DynamicLight.Type "Point";
|
||||
ReactionTime 50;
|
||||
Args 255,192,128,300;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
lifetime = 1.0;
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
args[LIGHT_RED] = 255*lifetime;
|
||||
args[LIGHT_GREEN] = 192*lifetime;
|
||||
args[LIGHT_BLUE] = 128*lifetime;
|
||||
lifetime -= 1./ReactionTime;
|
||||
if ( lifetime <= 0 ) Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
Class WarheadLight : DynamicLight
|
||||
{
|
||||
Default
|
||||
{
|
||||
DynamicLight.Type "Point";
|
||||
Args 255,224,192,70;
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
if ( !target )
|
||||
{
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
Vector3 taildir = -(cos(target.angle)*cos(target.pitch),sin(target.angle)*cos(target.pitch),-sin(target.pitch));
|
||||
SetOrigin(target.Vec3Offset(taildir.x*20,taildir.y*20,taildir.z*20),true);
|
||||
args[LIGHT_INTENSITY] = Random[Warhead](6,8)*10;
|
||||
}
|
||||
}
|
||||
|
||||
Class WarShell : Actor
|
||||
{
|
||||
double destangle, destpitch;
|
||||
Actor l, b;
|
||||
|
||||
Default
|
||||
{
|
||||
Obituary "%o was vaporized by %k's Redeemer!!";
|
||||
Radius 2;
|
||||
Height 2;
|
||||
Speed 5;
|
||||
DamageType 'RedeemerDeath';
|
||||
PROJECTILE;
|
||||
+FORCEXYBILLBOARD;
|
||||
+SKYEXPLODE;
|
||||
+FORCERADIUSDMG;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
l = Spawn("Warheadlight",pos);
|
||||
l.target = self;
|
||||
b = Spawn("WarheadHitbox",pos);
|
||||
b.target = self;
|
||||
A_PlaySound("warhead/fly",CHAN_VOICE,1.0,true);
|
||||
}
|
||||
override int SpecialMissileHit( Actor victim )
|
||||
{
|
||||
if ( victim == b ) return 1;
|
||||
return -1;
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
if ( vel.length() > 0 )
|
||||
{
|
||||
Vector3 dir = vel.unit();
|
||||
destangle = atan2(dir.y,dir.x);
|
||||
destpitch = asin(-dir.z);
|
||||
A_SetAngle(angle*0.9+destangle*0.1,SPF_INTERPOLATE);
|
||||
A_SetPitch(pitch*0.9+destpitch*0.1,SPF_INTERPOLATE);
|
||||
if ( vel.length() < 10 )
|
||||
{
|
||||
Vector3 dir = vel.unit();
|
||||
vel += dir*1;
|
||||
}
|
||||
}
|
||||
}
|
||||
action void A_Trail()
|
||||
{
|
||||
Vector3 taildir = -(cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
|
||||
for ( int i=0; i<8; i++ )
|
||||
A_SpawnParticle("404040",0,20,2,0,taildir.x*32,taildir.y*32,taildir.z*32,taildir.x*2+FRandom[Warhead](-.5,.5),taildir.y*2+FRandom[Warhead](-.5,.5),taildir.z*2+FRandom[Warhead](-.5,.5),accelz:0.1,sizestep:1);
|
||||
for ( int i=0; i<8; i++ )
|
||||
{
|
||||
A_SpawnParticle("FFA020",SPF_FULLBRIGHT,10,6,0,taildir.x*35+FRandom[Warhead](-1,1),taildir.y*35+FRandom[Warhead](-1,1),taildir.z*35+FRandom[Warhead](-1,1),taildir.x*4+FRandom[Warhead](-.25,.25),taildir.y*4+FRandom[Warhead](-.25,.25),taildir.z*4+FRandom[Warhead](-.25,.25));
|
||||
}
|
||||
}
|
||||
action void A_Vaporize()
|
||||
{
|
||||
if ( invoker.l ) invoker.l.Destroy();
|
||||
if ( invoker.b ) invoker.b.Destroy();
|
||||
A_SetScale(2.0);
|
||||
A_Explode(1000,300);
|
||||
A_SprayDecal("BigBlast");
|
||||
A_QuakeEx(8,8,8,20,0,300,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.35);
|
||||
A_PlaySound("shock/hit",CHAN_VOICE,attenuation:0.5);
|
||||
A_SetRenderStyle(1.0,STYLE_Add);
|
||||
Spawn("WarheadExplodLight",pos);
|
||||
let s = Spawn("ShockWave",pos);
|
||||
s.target = target;
|
||||
}
|
||||
action void A_Intercepted()
|
||||
{
|
||||
if ( invoker.l ) invoker.l.Destroy();
|
||||
if ( invoker.b ) invoker.b.Destroy();
|
||||
A_Explode(1000,350);
|
||||
A_SprayDecal("BigBlast");
|
||||
A_QuakeEx(8,8,8,20,0,300,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.35);
|
||||
A_PlaySound("shock/hit",CHAN_VOICE,attenuation:0.5);
|
||||
A_SetRenderStyle(1.0,STYLE_Add);
|
||||
Spawn("WarheadExplodLight",pos);
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
WMIS A 1 A_Trail();
|
||||
Wait;
|
||||
Death:
|
||||
TNT1 A 0 A_JumpIf(bAMBUSH,"Death.Intercept");
|
||||
TNT1 A 0 A_Vaporize();
|
||||
NE__ ABCDEFGHIJKLMNOPR 3 Bright;
|
||||
Stop;
|
||||
Death.Intercept:
|
||||
TNT1 A 0 A_Intercepted();
|
||||
WE__ ABCDEFGHIJKLMNOPR 3 Bright;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class GuidedWarShell : WarShell
|
||||
{
|
||||
double lagangle, lagpitch, lagangle2, lagpitch2;
|
||||
double guideangle, guidepitch, lastguideroll;
|
||||
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
if ( target && target.player ) target.player.camera = self;
|
||||
guideangle = angle;
|
||||
guidepitch = pitch;
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
Actor.Tick();
|
||||
if ( !bMISSILE ) return;
|
||||
if ( !target || !target.player || (target.Health <= 0) )
|
||||
{
|
||||
bAMBUSH = true;
|
||||
ExplodeMissile();
|
||||
return;
|
||||
}
|
||||
if ( target.player.cmd.buttons&BT_ATTACK )
|
||||
{
|
||||
ExplodeMissile();
|
||||
return;
|
||||
}
|
||||
if ( vel.length() > 0 )
|
||||
{
|
||||
lagangle = target.player.cmd.yaw/128.;
|
||||
lagpitch = -target.player.cmd.pitch/128.;
|
||||
guideangle += lagangle2*0.95+lagangle*0.05;
|
||||
guidepitch += lagpitch2*0.95+lagpitch*0.05;
|
||||
guidepitch = Clamp(guidepitch,-89,89);
|
||||
double guideroll = -lagangle2*15;
|
||||
Vector3 dir = (cos(guideangle)*cos(guidepitch),sin(guideangle)*cos(guidepitch),-sin(guidepitch));
|
||||
destangle = atan2(dir.y,dir.x);
|
||||
destpitch = asin(-dir.z);
|
||||
double destroll = lastguideroll*0.9+guideroll*0.1;
|
||||
A_SetAngle(destangle,SPF_INTERPOLATE);
|
||||
A_SetPitch(destpitch,SPF_INTERPOLATE);
|
||||
A_SetRoll(destroll,SPF_INTERPOLATE);
|
||||
vel = vel.length()*(cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
|
||||
if ( vel.length() < 10 )
|
||||
{
|
||||
Vector3 dir = vel.unit();
|
||||
vel += dir*1;
|
||||
}
|
||||
}
|
||||
lagangle2 = lagangle2*0.95+lagangle*0.05;
|
||||
lagpitch2 = lagpitch2*0.95+lagpitch*0.05;
|
||||
lastguideroll = roll*0.98;
|
||||
}
|
||||
States
|
||||
{
|
||||
Death:
|
||||
TNT1 A 0
|
||||
{
|
||||
if ( WarheadLauncher(master) )
|
||||
WarheadLauncher(master).Guided = null;
|
||||
if ( target && target.player && target.player.camera == self ) target.player.camera = target;
|
||||
}
|
||||
Goto Super::Death;
|
||||
}
|
||||
}
|
||||
|
||||
Class MidTracer : LineTracer
|
||||
{
|
||||
override ETraceStatus TraceCallback()
|
||||
{
|
||||
if ( Results.HitType == TRACE_HitActor ) return TRACE_Skip;
|
||||
else if ( (Results.HitType == TRACE_HitWall) && (Results.Tier == TIER_Middle) )
|
||||
{
|
||||
if ( !Results.HitLine.sidedef[1] ) return TRACE_Stop;
|
||||
return TRACE_Skip;
|
||||
}
|
||||
return TRACE_Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class RedeemerHUD : HUDMessageBase
|
||||
{
|
||||
Actor Camera;
|
||||
Vector3 ViewPos;
|
||||
double ViewAngle, ViewPitch, ViewRoll;
|
||||
TextureID reticle, mark, readout;
|
||||
Font whfont;
|
||||
ThinkerIterator t;
|
||||
MidTracer tr;
|
||||
|
||||
RedeemerHUD Init()
|
||||
{
|
||||
reticle = TexMan.CheckForTexture("GuidedX",TexMan.Type_Any);
|
||||
mark = TexMan.CheckForTexture("Crosshr6",TexMan.Type_Any);
|
||||
readout = TexMan.CheckForTexture("Readout",TexMan.Type_Any);
|
||||
whfont = Font.GetFont('WHFONT');
|
||||
t = ThinkerIterator.Create("Actor");
|
||||
tr = new("MidTracer");
|
||||
return self;
|
||||
}
|
||||
override bool Tick()
|
||||
{
|
||||
return !Camera;
|
||||
}
|
||||
override void Draw( int bottom, int visibility )
|
||||
{
|
||||
if ( visibility != StatusBar.HUDMSGLayer_UnderHUD ) return;
|
||||
Screen.Dim("Red",0.5,0,0,Screen.GetWidth(),Screen.GetHeight());
|
||||
// shootable targetting
|
||||
t.Reinit();
|
||||
Actor a;
|
||||
while ( a = Actor(t.Next()) )
|
||||
{
|
||||
Vector3 tdir = Level.Vec3Diff(ViewPos,a.Pos+(0,0,a.Height*0.5));
|
||||
if ( !a.bSHOOTABLE || (a.Health <= 0) || ((Camera is 'GuidedWarShell') && (a == GuidedWarShell(Camera).b)) || tr.Trace(ViewPos,Camera.CurSector,tdir.unit(),tdir.length(),0) ) continue;
|
||||
Vector3 wpos = ViewPos+tdir;
|
||||
Vector3 spos = mkCoordUtil.WorldToScreen(wpos,ViewPos,ViewPitch,ViewAngle,ViewRoll,players[consoleplayer].FOV);
|
||||
if ( spos.z > 1.0 ) continue;
|
||||
Vector2 vpos = mkCoordUtil.ToViewport(spos);
|
||||
Screen.DrawTexture(mark,false,vpos.x,vpos.y);
|
||||
String diststr = String.Format("%f",tdir.length());
|
||||
diststr.Replace(".","");
|
||||
Screen.DrawText(whfont,Font.CR_UNTRANSLATED,(vpos.x-whfont.StringWidth(diststr)/2)-12,vpos.y+8,diststr);
|
||||
}
|
||||
// other stuff
|
||||
Screen.DrawTexture(reticle,false,320,240,DTA_VirtualWidth,640,DTA_VirtualHeight,480);
|
||||
int numreadouts = Screen.GetHeight()/128+2;
|
||||
for ( int i=0; i<numreadouts; i++ )
|
||||
{
|
||||
int scroll = (gametic*5)%128;
|
||||
Screen.DrawTexture(readout,false,0,i*128-scroll);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Class RedeemerHUDStatic : HUDMessageBase
|
||||
{
|
||||
int tickcnt;
|
||||
TextureID tx;
|
||||
|
||||
RedeemerHUDStatic Init()
|
||||
{
|
||||
tx = TexMan.CheckForTexture("static1",TexMan.Type_Any);
|
||||
tickcnt = 0;
|
||||
return self;
|
||||
}
|
||||
override bool Tick()
|
||||
{
|
||||
return (++tickcnt>15);
|
||||
}
|
||||
override void Draw( int bottom, int visibility )
|
||||
{
|
||||
if ( visibility != StatusBar.HUDMSGLayer_UnderHUD ) return;
|
||||
double sw, sh;
|
||||
sw = 256.;
|
||||
sh = sw*(Screen.GetHeight()/double(Screen.GetWidth()));
|
||||
Screen.DrawTexture(tx,true,0,0,DTA_VirtualWidthF,sw,DTA_VirtualHeightF,sh,DTA_KeepRatio,true);
|
||||
}
|
||||
}
|
||||
|
||||
Class RedeemerHUDHandler : EventHandler
|
||||
{
|
||||
ui RedeemerHUD rhud;
|
||||
|
||||
override void RenderOverlay( RenderEvent e )
|
||||
{
|
||||
if ( e.Camera is 'GuidedWarShell' )
|
||||
{
|
||||
if ( !rhud )
|
||||
{
|
||||
rhud = new("RedeemerHUD").Init();
|
||||
StatusBar.AttachMessage(rhud,0,StatusBar.HUDMSGLayer_UnderHUD);
|
||||
}
|
||||
rhud.Camera = e.Camera;
|
||||
rhud.ViewPos = e.ViewPos;
|
||||
rhud.ViewAngle = e.ViewAngle;
|
||||
rhud.ViewPitch = e.ViewPitch;
|
||||
rhud.ViewRoll = e.ViewRoll;
|
||||
}
|
||||
else if ( rhud )
|
||||
{
|
||||
StatusBar.DetachMessage(rhud);
|
||||
rhud.Destroy();
|
||||
StatusBar.AttachMessage(new("RedeemerHUDStatic").Init(),0,StatusBar.HUDMSGLayer_UnderHUD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Class WarheadLauncher : UTWeapon
|
||||
{
|
||||
Actor guided;
|
||||
action void A_Selecting()
|
||||
{
|
||||
A_PlaySound("warhead/select",CHAN_WEAPON);
|
||||
}
|
||||
action void A_WarheadFire()
|
||||
{
|
||||
Weapon weap = Weapon(invoker);
|
||||
if ( !weap ) return;
|
||||
if ( weap.Ammo1.Amount <= 0 ) return;
|
||||
if ( !weap.DepleteAmmo(weap.bAltFire,true,1) ) return;
|
||||
A_PlaySound("warhead/fire",CHAN_WEAPON);
|
||||
A_QuakeEx(6,6,6,20,0,100,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.2);
|
||||
Vector3 x, y, z;
|
||||
double a, s;
|
||||
[x, y, z] = Matrix4.GetAxes(pitch,angle,roll);
|
||||
vel -= x*10;
|
||||
Vector3 origin = pos+(0,0,player.viewheight)+10.0*x+2.0*y-2.0*z;
|
||||
Actor p = Spawn("WarShell",origin);
|
||||
p.angle = angle;
|
||||
p.pitch = BulletSlope();
|
||||
p.vel = (cos(p.angle)*cos(p.pitch),sin(p.angle)*cos(p.pitch),-sin(p.pitch))*p.speed;
|
||||
p.target = self;
|
||||
}
|
||||
action void A_WarheadAlt()
|
||||
{
|
||||
Weapon weap = Weapon(invoker);
|
||||
if ( !weap ) return;
|
||||
if ( weap.Ammo1.Amount <= 0 ) return;
|
||||
if ( !weap.DepleteAmmo(weap.bAltFire,true,1) ) return;
|
||||
A_PlaySound("warhead/fire",CHAN_WEAPON);
|
||||
A_QuakeEx(6,6,6,20,0,100,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.2);
|
||||
Vector3 x, y, z;
|
||||
double a, s;
|
||||
[x, y, z] = Matrix4.GetAxes(pitch,angle,roll);
|
||||
vel -= x*10;
|
||||
Vector3 origin = pos+(0,0,player.viewheight)+10.0*x+2.0*y-2.0*z;
|
||||
Actor p = Spawn("GuidedWarShell",origin);
|
||||
p.angle = angle;
|
||||
p.pitch = BulletSlope();
|
||||
p.vel = (cos(p.angle)*cos(p.pitch),sin(p.angle)*cos(p.pitch),-sin(p.pitch))*p.speed;
|
||||
p.target = self;
|
||||
p.master = invoker;
|
||||
invoker.guided = p;
|
||||
}
|
||||
|
||||
Default
|
||||
{
|
||||
Tag "Redeemer";
|
||||
Inventory.PickupMessage "You got the Redeemer.";
|
||||
Weapon.SlotNumber 0;
|
||||
Weapon.AmmoType "WarheadAmmo";
|
||||
Weapon.AmmoUse 1;
|
||||
Weapon.AmmoType2 "WarheadAmmo";
|
||||
Weapon.AmmoUse2 1;
|
||||
Weapon.AmmoGive 1;
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
RDMP A -1;
|
||||
Stop;
|
||||
RDMP B -1;
|
||||
Stop;
|
||||
Ready:
|
||||
WARS A 1 A_Selecting();
|
||||
WARS BCDEFGHIJKLMNO 1;
|
||||
Idle:
|
||||
WARI A 1
|
||||
{
|
||||
A_CheckReload();
|
||||
A_WeaponReady();
|
||||
}
|
||||
Wait;
|
||||
Fire:
|
||||
WARI A 3;
|
||||
WARF A 3 A_WarheadFire();
|
||||
WARF BCDEFG 3;
|
||||
WARI A 5;
|
||||
Goto Idle;
|
||||
AltFire:
|
||||
WARI A 3;
|
||||
WARF A 3 A_WarheadAlt();
|
||||
WARF BCDEFG 3;
|
||||
WARI A 1 A_JumpIf(!invoker.Guided,1);
|
||||
Wait;
|
||||
WARI A 30;
|
||||
Goto Idle;
|
||||
Select:
|
||||
WARS A 1 A_Raise(int.max);
|
||||
Wait;
|
||||
Deselect:
|
||||
WARD ABCDEFG 2;
|
||||
WARD G 1 A_Lower(int.max);
|
||||
Wait;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue