1.0 release. Requires 4.2.3 or higher.
- Migrated screen projection code to libeye. - Some pickups emit light, like in Doomreal. - Backported map revealer item from Doomreal. - Brand new Invulnerability and Night Vision powerups. - Add option to allow Shield Belt and armors simultaneously. - Backported armor bonus model from Doomreal. - Added Dual Enforcers icon for HUD. - Changed player class names to their character names, like in Doomreal. - Terrain splashes. - Translocator doesn't telefrag other players in coop. - Reduced view shake from Impact Hammer. - Various other updates and bug fixes.
This commit is contained in:
parent
0ed1e6aa4f
commit
b79d29f071
91 changed files with 1994 additions and 511 deletions
|
|
@ -1,8 +1,9 @@
|
|||
Class UTArmor : Armor
|
||||
{
|
||||
int absorb;
|
||||
int absorb, priority;
|
||||
|
||||
Property ArmorAbsorption : absorb;
|
||||
Property AbsorptionPriority : priority;
|
||||
|
||||
Default
|
||||
{
|
||||
|
|
@ -11,6 +12,23 @@ Class UTArmor : Armor
|
|||
+INVENTORY.KEEPDEPLETED;
|
||||
+INVENTORY.ALWAYSPICKUP;
|
||||
}
|
||||
override void AttachToOwner( Actor other )
|
||||
{
|
||||
Super.AttachToOwner(other);
|
||||
// find last armor that's better than us
|
||||
Inventory found = null;
|
||||
for ( Inventory i=other.Inv; i; i=i.Inv )
|
||||
{
|
||||
if ( !(i is 'UTArmor') || (i == self) || (UTArmor(i).priority < priority) ) continue;
|
||||
found = i;
|
||||
}
|
||||
if ( !found ) return;
|
||||
// place ourselves right after it
|
||||
Inventory saved = found.Inv;
|
||||
found.Inv = self;
|
||||
other.Inv = Inv;
|
||||
Inv = saved;
|
||||
}
|
||||
override void AbsorbDamage( int damage, Name damageType, out int newdamage )
|
||||
{
|
||||
int saved;
|
||||
|
|
@ -48,6 +66,7 @@ Class UTArmorBonus : UTArmor
|
|||
Inventory.MaxAmount 50;
|
||||
Inventory.InterHubAmount 50;
|
||||
UTArmor.ArmorAbsorption 25;
|
||||
UTArmor.AbsorptionPriority 1;
|
||||
Inventory.PickupMessage "$I_ARMORBONUS";
|
||||
Inventory.PickupSound "misc/ut_shard";
|
||||
}
|
||||
|
|
@ -63,7 +82,7 @@ Class UTThighPads : UTArmor
|
|||
{
|
||||
override bool HandlePickup( Inventory item )
|
||||
{
|
||||
if ( item is 'UTThighPads' )
|
||||
if ( flak_vanillaarmor && (item is 'UTThighPads') )
|
||||
{
|
||||
let s = Owner.FindInventory("UTShieldBelt");
|
||||
if ( s )
|
||||
|
|
@ -87,6 +106,7 @@ Class UTThighPads : UTArmor
|
|||
Inventory.MaxAmount 50;
|
||||
Inventory.InterHubAmount 50;
|
||||
UTArmor.ArmorAbsorption 50;
|
||||
UTArmor.AbsorptionPriority 7;
|
||||
Inventory.PickupMessage "$I_THIGHPADS";
|
||||
Inventory.PickupSound "misc/ut_armor";
|
||||
}
|
||||
|
|
@ -102,7 +122,7 @@ Class UTBodyArmor : UTArmor
|
|||
{
|
||||
override bool HandlePickup( Inventory item )
|
||||
{
|
||||
if ( item is 'UTBodyArmor' )
|
||||
if ( flak_vanillaarmor && (item is 'UTBodyArmor') )
|
||||
{
|
||||
let s = Owner.FindInventory("UTShieldBelt");
|
||||
if ( s )
|
||||
|
|
@ -126,6 +146,7 @@ Class UTBodyArmor : UTArmor
|
|||
Inventory.MaxAmount 100;
|
||||
Inventory.InterHubAmount 100;
|
||||
UTArmor.ArmorAbsorption 75;
|
||||
UTArmor.AbsorptionPriority 7;
|
||||
Inventory.PickupMessage "$I_BODYARMOR";
|
||||
Inventory.PickupSound "misc/ut_armor";
|
||||
}
|
||||
|
|
@ -156,7 +177,7 @@ Class UTShieldBelt : UTArmor
|
|||
}
|
||||
override bool HandlePickup( Inventory item )
|
||||
{
|
||||
if ( (item is 'UTBodyArmor') || (item is 'UTThighPads') )
|
||||
if ( flak_vanillaarmor && ((item is 'UTBodyArmor') || (item is 'UTThighPads')) )
|
||||
{
|
||||
// sum up current amounts
|
||||
let a = Owner.FindInventory("UTBodyArmor");
|
||||
|
|
@ -177,8 +198,11 @@ Class UTShieldBelt : UTArmor
|
|||
override bool Use( bool pickup )
|
||||
{
|
||||
// removes thigh pads and body armor like in UT
|
||||
Owner.TakeInventory("UTThighPads",50);
|
||||
Owner.TakeInventory("UTBodyArmor",150);
|
||||
if ( flak_vanillaarmor )
|
||||
{
|
||||
Owner.TakeInventory("UTThighPads",50);
|
||||
Owner.TakeInventory("UTBodyArmor",150);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
Default
|
||||
|
|
@ -190,6 +214,7 @@ Class UTShieldBelt : UTArmor
|
|||
Inventory.MaxAmount 150;
|
||||
Inventory.InterHubAmount 150;
|
||||
UTArmor.ArmorAbsorption 100;
|
||||
UTArmor.AbsorptionPriority 10;
|
||||
Inventory.PickupMessage "$I_SHIELDBELT";
|
||||
Inventory.PickupSound "belt/pickup";
|
||||
Inventory.RespawnTics 2100;
|
||||
|
|
|
|||
|
|
@ -95,28 +95,27 @@ Class ActUDamage : UTActivatable
|
|||
}
|
||||
}
|
||||
|
||||
Class ActShieldBelt : UTActivatable
|
||||
Class ActUTInvulnerability : UTActivatable
|
||||
{
|
||||
Default
|
||||
{
|
||||
Tag "$T_SHIELDBELT";
|
||||
Inventory.Icon "ItemBelt";
|
||||
Inventory.PickupMessage "$I_SHIELDBELT";
|
||||
Tag "$T_UTINVUL";
|
||||
Inventory.Icon "ItemInvl";
|
||||
Inventory.PickupMessage "$I_UTINVUL";
|
||||
+COUNTITEM;
|
||||
+INVENTORY.BIGPOWERUP;
|
||||
+INVENTORY.ISARMOR;
|
||||
UTActivatable.GiveItem "UTShieldBelt";
|
||||
Inventory.RespawnTics 2100;
|
||||
UTActivatable.GiveItem "UTInvulnerability";
|
||||
Inventory.RespawnTics 4200;
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
BELT A -1;
|
||||
UKEY A -1;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class ActInvisibility : UTActivatable
|
||||
Class ActUTInvisibility : UTActivatable
|
||||
{
|
||||
Default
|
||||
{
|
||||
|
|
@ -143,6 +142,33 @@ Class ActInvisibility : UTActivatable
|
|||
}
|
||||
}
|
||||
|
||||
Class ActUTNightVision : UTActivatable
|
||||
{
|
||||
Default
|
||||
{
|
||||
Tag "$T_UTVISION";
|
||||
Inventory.Icon "ItemLite";
|
||||
Inventory.PickupMessage "$I_UTVISION";
|
||||
+COUNTITEM;
|
||||
+INVENTORY.BIGPOWERUP;
|
||||
UTActivatable.GiveItem "UTNightVision";
|
||||
Inventory.RespawnTics 4200;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
tracer = Spawn("UTNightVisionX",pos);
|
||||
tracer.angle = angle;
|
||||
tracer.target = self;
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
UKEY A -1;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class ActJumpBoots : UTActivatable
|
||||
{
|
||||
Default
|
||||
|
|
@ -161,25 +187,6 @@ Class ActJumpBoots : UTActivatable
|
|||
}
|
||||
}
|
||||
|
||||
Class ActSearchlight : UTActivatable
|
||||
{
|
||||
Default
|
||||
{
|
||||
Tag "$T_SEARCHLIGHT";
|
||||
Inventory.Icon "ItemLite";
|
||||
Inventory.PickupMessage "$I_SEARCHLIGHT";
|
||||
+COUNTITEM;
|
||||
UTActivatable.GiveItem "Searchlight";
|
||||
Inventory.RespawnTics 1050;
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
SLIT A -1;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
// These have to be subclassed from HealthPickup for auto-use
|
||||
Class UTActivatableHealth : HealthPickup
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,69 +7,6 @@
|
|||
|
||||
Class dt_CoordUtil
|
||||
{
|
||||
// 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
|
||||
dt_Matrix4 mRoll = dt_Matrix4.rotate((0,0,1),roll);
|
||||
dt_Matrix4 mPitch = dt_Matrix4.rotate((1,0,0),apitch);
|
||||
dt_Matrix4 mYaw = dt_Matrix4.rotate((0,-1,0),ayaw);
|
||||
// scaling
|
||||
dt_Matrix4 mScale = dt_Matrix4.identity();
|
||||
mScale.set(1,1,pr);
|
||||
// YZ swap
|
||||
dt_Matrix4 mYZ = dt_Matrix4.create();
|
||||
mYZ.set(0,0,1);
|
||||
mYZ.set(2,1,1);
|
||||
mYZ.set(1,2,-1);
|
||||
mYZ.set(3,3,1);
|
||||
// translation
|
||||
dt_Matrix4 mMove = dt_Matrix4.identity();
|
||||
mMove.set(3,0,-eye.x);
|
||||
mMove.set(3,1,-eye.y);
|
||||
mMove.set(3,2,-eye.z);
|
||||
// perspective
|
||||
dt_Matrix4 mPerspective = dt_Matrix4.perspective(fov,ar,5,65535);
|
||||
// full matrix
|
||||
dt_Matrix4 mView = mRoll.mul(mPitch);
|
||||
mView = mView.mul(mYaw);
|
||||
mView = mView.mul(mScale);
|
||||
mView = mView.mul(mYZ);
|
||||
mView = mView.mul(mMove);
|
||||
dt_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);
|
||||
}
|
||||
|
||||
// In Tim Sweeney's own words: "transform by a pitch-yaw-roll rotation"
|
||||
static Vector3, Vector3, Vector3 GetUnAxes( double pitch, double yaw, double roll )
|
||||
{
|
||||
|
|
|
|||
58
zscript/dt_libeye/libeye.txt
Normal file
58
zscript/dt_libeye/libeye.txt
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
libeye (for projection and deprojection)
|
||||
written by KeksDose / MemeDose (May 2019)
|
||||
(updated July 2019)
|
||||
|
||||
All rights etc. etc. who cares, you may reuse this as you wish and edit it, and
|
||||
leave this note intact.
|
||||
|
||||
//
|
||||
//
|
||||
/////((
|
||||
@@////////// ((
|
||||
(( %////((///// (( (( ((
|
||||
(( @@//(((/////// ((( ////////////// ((
|
||||
( /////////////////////////(((((((////////// ((
|
||||
@@///@@@@@@//////////(((((((((//@@@////////// ((
|
||||
(( ///// /////((((((((((((((//@@% %%@/////////// ((
|
||||
//////////((((((((((((((//////((((( %%@@////////// ((
|
||||
((%%//////////@@%% @@//(((((((/// ( (((( %%///////// (
|
||||
(( ////////@@ ((( @@//(((((((///// (( ( @@/////////
|
||||
((/////////@ (( (( @@/(((((((///// (( (( @@/((((///((
|
||||
(( ///((//@@ (( (( %@@@@@@////////// (((( /((((/// ((
|
||||
((/////((//%%( ////%%%@@////////// @//((((///
|
||||
////(((// ///////// //@@/////////////////(((((//
|
||||
( ////(((////( //////////////////////@@@@////////////(((((////((
|
||||
////(((((((// //////////////////////////// %%@@///(((((((((// (
|
||||
//(((((((((/////////////////// //////////// %%@//(((((((//// ((
|
||||
//(((((((((((////////////((/// /////////////// @@//(((((((///
|
||||
//(((((((((((////////(( /////////((//////////// ( //(((((((///////
|
||||
//((((((( ((///////( ##### ////( ((/////// ( @@//(((((///////
|
||||
//((((((( (((//////((( ### (((( ##### ((/////// (( //(((///////@@
|
||||
//((((((((((((@@/////////(((((((((((((((((((((///// ///////////% ((
|
||||
//((((((((((((%% ///////((((((((((((//////// //////////////@@%% ((
|
||||
@@//(((((((((/%%(( /////////////////////// ///////////////// (((
|
||||
( //(((((((((/ (( ///////////////////////
|
||||
%%//(((((((///(( (( //////////////@///////%%
|
||||
(( @@/((((((///(( (( //////////////@@%% /////// ((
|
||||
(( /(((((((// ( //////////////@%% //////%((
|
||||
(( @@//(((////(( (( /////(((((((///@@ ((( /////// (
|
||||
( @@(((((// ( ////(((((((///@@% (((( /////////%%((
|
||||
((%%//(((/////////(((((((//@%% //////////%% ((
|
||||
((////(((((///////(((((///////////////////////% ((
|
||||
( ////(((((/////(((((((((//////////((((///@@%% ((
|
||||
////(((//////@//////(((((((((((((////@@@%% (
|
||||
(( /////////@@%% %%@@@@@@@@@@@@@@@@@@@%% ((
|
||||
(( @@@@@%% ((
|
||||
(( (((
|
||||
|
||||
|
||||
|
||||
%%//%
|
||||
( //((/ ((
|
||||
( ///////((
|
||||
( ///////((
|
||||
///// ((
|
||||
//
|
||||
//
|
||||
|
||||
(( ///// ((
|
||||
150
zscript/dt_libeye/projector gl.txt
Normal file
150
zscript/dt_libeye/projector gl.txt
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
/* kd:
|
||||
|
||||
In open-gl, your screen rotates nicely and you can do mostly what you know
|
||||
to be sane. It's all about making a rotation of your view and using what
|
||||
you know about right triangles.
|
||||
|
||||
*/
|
||||
|
||||
class dtLe_GlScreen : dtLe_ProjScreen {
|
||||
protected vector3 forw_unit;
|
||||
protected vector3 right_unit;
|
||||
protected vector3 down_unit;
|
||||
|
||||
override void Reorient (vector3 world_view_pos, vector3 world_ang) {
|
||||
|
||||
// kd: Pitch is a weird gzd joke. It's probably to compensate looking
|
||||
// speed and all. After that, you see what makes this fast.
|
||||
world_ang.y = VectorAngle(
|
||||
cos(world_ang.y),
|
||||
sin(world_ang.y) * pixel_stretch);
|
||||
|
||||
|
||||
super.Reorient(world_view_pos, world_ang);
|
||||
|
||||
let cosang = cos(world_ang.x);
|
||||
let cosvang = cos(world_ang.y);
|
||||
let cosrang = cos(world_ang.z);
|
||||
let sinang = sin(world_ang.x);
|
||||
let sinvang = sin(world_ang.y);
|
||||
let sinrang = sin(world_ang.z);
|
||||
|
||||
let right_no_roll = (
|
||||
sinang,
|
||||
- cosang,
|
||||
0);
|
||||
|
||||
let down_no_roll = (
|
||||
- sinvang * cosang,
|
||||
- sinvang * sinang,
|
||||
- cosvang);
|
||||
|
||||
forw_unit = (
|
||||
cosvang * cosang,
|
||||
cosvang * sinang,
|
||||
- sinvang);
|
||||
|
||||
down_unit = cosrang * down_no_roll - sinrang * right_no_roll;
|
||||
right_unit = cosrang * right_no_roll + sinrang * down_no_roll;
|
||||
}
|
||||
|
||||
// kd: Projection handling. These get called to make stuff a little faster,
|
||||
// since you may wanna project many many times.
|
||||
protected vector3 forw_in;
|
||||
protected vector3 right_in;
|
||||
protected vector3 down_in;
|
||||
|
||||
override void BeginProjection () {
|
||||
forw_in = forw_unit;
|
||||
right_in = right_unit / tan_fov_2.x;
|
||||
down_in = down_unit / tan_fov_2.y;
|
||||
|
||||
forw_in.z *= pixel_stretch;
|
||||
right_in.z *= pixel_stretch;
|
||||
down_in.z *= pixel_stretch;
|
||||
}
|
||||
|
||||
override void ProjectWorldPos (vector3 world_pos) {
|
||||
diff = levellocals.vec3diff(view_pos, world_pos);
|
||||
proj_pos = (diff dot right_in, diff dot down_in);
|
||||
depth = diff dot forw_in;
|
||||
}
|
||||
|
||||
override void ProjectActorPos (Actor mo, vector3 offset, double t) {
|
||||
let inter_pos = mo.prev + t * (mo.pos - mo.prev);
|
||||
diff = levellocals.vec3diff(view_pos, inter_pos + offset);
|
||||
proj_pos = (diff dot right_in, diff dot down_in);
|
||||
depth = diff dot forw_in;
|
||||
}
|
||||
|
||||
override void ProjectActorPosPortal (Actor mo, vector3 offset, double t) {
|
||||
let inter_pos = mo.prev + t * levellocals.vec3diff(mo.prev, mo.pos);
|
||||
diff = levellocals.vec3diff(view_pos, inter_pos + offset);
|
||||
proj_pos = (diff dot right_in, diff dot down_in);
|
||||
depth = diff dot forw_in;
|
||||
}
|
||||
|
||||
override vector2 ProjectToNormal () const {
|
||||
return proj_pos / depth;
|
||||
}
|
||||
|
||||
override vector2 ProjectToScreen () const {
|
||||
let normal_pos = proj_pos / depth + (1, 1);
|
||||
|
||||
return 0.5 * (
|
||||
normal_pos.x * resolution.x,
|
||||
normal_pos.y * resolution.y);
|
||||
}
|
||||
|
||||
override vector2 ProjectToCustom (
|
||||
vector2 origin,
|
||||
vector2 resolution) const {
|
||||
let normal_pos = proj_pos / depth + (1, 1);
|
||||
|
||||
return origin + 0.5 * (
|
||||
normal_pos.x * resolution.x,
|
||||
normal_pos.y * resolution.y);
|
||||
}
|
||||
|
||||
// kd: Same deal but backwards-ish.
|
||||
protected vector3 forw_out;
|
||||
protected vector3 right_out;
|
||||
protected vector3 down_out;
|
||||
|
||||
override void BeginDeprojection () {
|
||||
|
||||
// kd: Same deal as above, but reversed. This time, we're compensating
|
||||
// for what we rightfully assume is a projected position.
|
||||
forw_out = forw_unit;
|
||||
right_out = right_unit * tan_fov_2.x;
|
||||
down_out = down_unit * tan_fov_2.y;
|
||||
|
||||
forw_out.z /= pixel_stretch;
|
||||
right_out.z /= pixel_stretch;
|
||||
down_out.z /= pixel_stretch;
|
||||
}
|
||||
|
||||
override vector3 DeprojectNormalToDiff (
|
||||
vector2 normal_pos,
|
||||
double depth) const {
|
||||
return depth * (
|
||||
forw_out +
|
||||
normal_pos.x * right_out +
|
||||
normal_pos.y * down_out);
|
||||
}
|
||||
|
||||
override vector3 DeprojectScreenToDiff (
|
||||
vector2 screen_pos,
|
||||
double depth) const {
|
||||
|
||||
// kd: Same thing...
|
||||
let normal_pos = 2 * (
|
||||
screen_pos.x / resolution.x,
|
||||
screen_pos.y / resolution.y) - (1, 1);
|
||||
|
||||
return depth * (
|
||||
forw_out +
|
||||
normal_pos.x * right_out +
|
||||
normal_pos.y * down_out);
|
||||
}
|
||||
}
|
||||
125
zscript/dt_libeye/projector planar.txt
Normal file
125
zscript/dt_libeye/projector planar.txt
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
/* kd:
|
||||
|
||||
This does projection stuff in Carmack / software renderer. It's conceptually
|
||||
simpler, but nonetheless a little tricky to understand if you're
|
||||
used to open-gl.
|
||||
|
||||
*/
|
||||
|
||||
class dtLe_SwScreen : dtLe_ProjScreen {
|
||||
|
||||
// kd: Less info necessary than for open-gl, but it's there.
|
||||
protected vector2 right_planar_unit;
|
||||
protected vector3 forw_planar_unit;
|
||||
|
||||
override void Reorient (vector3 world_view_pos, vector3 world_ang) {
|
||||
super.Reorient(world_view_pos, world_ang);
|
||||
|
||||
right_planar_unit = (
|
||||
sin(view_ang.x),
|
||||
- cos(view_ang.x));
|
||||
|
||||
forw_planar_unit = (
|
||||
- right_planar_unit.y,
|
||||
right_planar_unit.x,
|
||||
tan(view_ang.y));
|
||||
}
|
||||
|
||||
// kd: Projection:
|
||||
protected vector3 forw_planar_in;
|
||||
protected vector2 right_planar_in;
|
||||
|
||||
override void BeginProjection () {
|
||||
|
||||
// kd: This doesn't cause any imprecisions. It also prevents two
|
||||
// multiplications with every projection.
|
||||
right_planar_in = right_planar_unit / tan_fov_2.x;
|
||||
forw_planar_in = forw_planar_unit;
|
||||
}
|
||||
|
||||
override void ProjectWorldPos (vector3 world_pos) {
|
||||
|
||||
// kd: Your view is flat. If you pitch up or down, imagine that all the
|
||||
// actors move up and down in reality. That's effectively how it works.
|
||||
// You can see this in the addition to diff.z.
|
||||
diff = levellocals.vec3diff(view_pos, world_pos);
|
||||
depth = forw_planar_in.xy dot diff.xy;
|
||||
diff.z += forw_planar_in.z * depth;
|
||||
proj_pos = (
|
||||
right_planar_in dot diff.xy,
|
||||
- pixel_stretch * diff.z / tan_fov_2.y);
|
||||
}
|
||||
|
||||
override void ProjectActorPos (Actor mo, vector3 offset, double t) {
|
||||
let inter_pos = mo.prev + t * (mo.pos - mo.prev);
|
||||
ProjectWorldPos(inter_pos + offset);
|
||||
}
|
||||
|
||||
override void ProjectActorPosPortal (Actor mo, vector3 offset, double t) {
|
||||
let inter_pos = mo.prev + t * levellocals.vec3diff(mo.prev, mo.pos);
|
||||
ProjectWorldPos(inter_pos + offset);
|
||||
}
|
||||
|
||||
override vector2 ProjectToNormal () const {
|
||||
return proj_pos / depth;
|
||||
}
|
||||
|
||||
override vector2 ProjectToScreen () const {
|
||||
let normal_pos = proj_pos / depth + (1, 1);
|
||||
|
||||
return 0.5 * (
|
||||
normal_pos.x * resolution.x,
|
||||
normal_pos.y * resolution.y);
|
||||
}
|
||||
|
||||
override vector2 ProjectToCustom (
|
||||
vector2 origin,
|
||||
vector2 resolution) const {
|
||||
let normal_pos = proj_pos / depth + (1, 1);
|
||||
|
||||
return origin + 0.5 * (
|
||||
normal_pos.x * resolution.x,
|
||||
normal_pos.y * resolution.y);
|
||||
}
|
||||
|
||||
// kd: Just as simple. You again assume you are trying to reverse a
|
||||
// projected position from the screen back into the world.
|
||||
protected vector3 forw_planar_out;
|
||||
protected vector3 right_planar_out;
|
||||
protected vector3 down_planar_out;
|
||||
|
||||
override void BeginDeprojection () {
|
||||
forw_planar_out.xy = forw_planar_unit.xy;
|
||||
forw_planar_out.z = 0;
|
||||
right_planar_out.xy = tan_fov_2.x * right_planar_unit;
|
||||
right_planar_out.z = 0;
|
||||
down_planar_out = (
|
||||
0,
|
||||
0,
|
||||
tan_fov_2.y / pixel_stretch);
|
||||
}
|
||||
|
||||
override vector3 DeprojectNormalToDiff (
|
||||
vector2 normal_pos,
|
||||
double depth) const {
|
||||
return depth * (
|
||||
forw_planar_out +
|
||||
normal_pos.x * right_planar_out +
|
||||
- (0, 0, forw_planar_unit.z) - normal_pos.y * down_planar_out);
|
||||
}
|
||||
|
||||
override vector3 DeprojectScreenToDiff (
|
||||
vector2 screen_pos,
|
||||
double depth) const {
|
||||
|
||||
// kd: Same thing...
|
||||
let normal_pos = 2 * (
|
||||
screen_pos.x / resolution.x,
|
||||
screen_pos.y / resolution.y) - (1, 1);
|
||||
|
||||
return depth * (
|
||||
forw_planar_out +
|
||||
normal_pos.x * right_planar_out +
|
||||
- (0, 0, forw_planar_unit.z) - normal_pos.y * down_planar_out);
|
||||
}
|
||||
}
|
||||
193
zscript/dt_libeye/projector.txt
Normal file
193
zscript/dt_libeye/projector.txt
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
/* kd:
|
||||
|
||||
Here's how to do projections and deprojections. You'd use the subclasses
|
||||
to do anything worthwhile. You may project world to screen and backwards.
|
||||
|
||||
*/
|
||||
|
||||
class dtLe_ProjScreen {
|
||||
|
||||
// kd: Screen info
|
||||
protected vector2 resolution;
|
||||
protected vector2 origin;
|
||||
protected vector2 tan_fov_2;
|
||||
protected double pixel_stretch;
|
||||
protected double aspect_ratio;
|
||||
|
||||
// kd: Setup calls which you'll need to call at least once.
|
||||
void CacheResolution () {
|
||||
CacheCustomResolution((Screen.GetWidth(), Screen.GetHeight()) );
|
||||
}
|
||||
|
||||
void CacheCustomResolution (vector2 new_resolution) {
|
||||
|
||||
// kd: This is for convenience and converting normal <-> screen pos.
|
||||
resolution = new_resolution;
|
||||
|
||||
// kd: This isn't really necessary but I kinda like it.
|
||||
pixel_stretch = level.pixelstretch;
|
||||
|
||||
// kd: Get the aspect ratio. 5:4 is handled just like 4:3... I GUESS
|
||||
// this'll do.
|
||||
aspect_ratio = max(4.0 / 3, Screen.GetAspectRatio());
|
||||
}
|
||||
|
||||
double AspectRatio () const {
|
||||
return aspect_ratio;
|
||||
}
|
||||
|
||||
// kd: Once you know you got screen info, you can call this whenever your
|
||||
// fov changes. Like CacheFov(player.fov) will do.
|
||||
void CacheFov (double hor_fov = 90) {
|
||||
|
||||
// kd: This holds: aspect ratio = tan(horizontal fov) / tan(ver fov).
|
||||
// gzd always uses hor fov, but the fov only holds in 4:3 (in a 4:3 box
|
||||
// in your screen centre), so we just extend it.
|
||||
tan_fov_2.x = tan(hor_fov / 2) * aspect_ratio / (4.0 / 3);
|
||||
tan_fov_2.y = tan_fov_2.x / aspect_ratio;
|
||||
}
|
||||
|
||||
// kd: Also need some view info. Angle is yaw, pitch, roll in world format
|
||||
// so positive pitch is up. Call one of the following functions.
|
||||
protected vector3 view_ang;
|
||||
protected vector3 view_pos;
|
||||
|
||||
ui void OrientForRenderOverlay (RenderEvent event) {
|
||||
Reorient(
|
||||
event.viewpos, (
|
||||
event.viewangle,
|
||||
event.viewpitch,
|
||||
event.viewroll));
|
||||
}
|
||||
|
||||
ui void OrientForRenderUnderlay (RenderEvent event) {
|
||||
Reorient(
|
||||
event.viewpos, (
|
||||
event.viewangle,
|
||||
event.viewpitch,
|
||||
event.viewroll));
|
||||
}
|
||||
|
||||
void OrientForPlayer (PlayerInfo player) {
|
||||
Reorient(
|
||||
player.mo.vec3offset(0, 0, player.viewheight), (
|
||||
player.mo.angle,
|
||||
player.mo.pitch,
|
||||
player.mo.roll));
|
||||
}
|
||||
|
||||
virtual void Reorient (vector3 world_view_pos, vector3 world_ang) {
|
||||
view_ang = world_ang;
|
||||
view_pos = world_view_pos;
|
||||
}
|
||||
|
||||
// kd: Now we can do projections and such (position in the level, go to
|
||||
// your screen).
|
||||
protected double depth;
|
||||
protected vector2 proj_pos;
|
||||
protected vector3 diff;
|
||||
|
||||
virtual void BeginProjection () {}
|
||||
virtual void ProjectWorldPos (vector3 world_pos) {}
|
||||
virtual void ProjectActorPos (
|
||||
Actor mo,
|
||||
vector3 offset = (0,0,0),
|
||||
double t = 1) {}
|
||||
|
||||
// kd: Portal aware version.
|
||||
virtual void ProjectActorPosPortal (
|
||||
Actor mo,
|
||||
vector3 offset = (0,0,0),
|
||||
double t = 1) {}
|
||||
|
||||
virtual vector2 ProjectToNormal () const { return (0, 0); }
|
||||
virtual vector2 ProjectToScreen () const { return (0, 0); }
|
||||
|
||||
virtual vector2 ProjectToCustom (
|
||||
vector2 origin,
|
||||
vector2 resolution) const {
|
||||
return (0, 0);
|
||||
}
|
||||
|
||||
bool IsInFront () const {
|
||||
return 0 < depth;
|
||||
}
|
||||
|
||||
bool IsInScreen () const {
|
||||
if( proj_pos.x < -depth || depth < proj_pos.x ||
|
||||
proj_pos.y < -depth || depth < proj_pos.y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// kd: Deprojection (point on screen, go into the world):
|
||||
virtual void BeginDeprojection () {}
|
||||
|
||||
virtual vector3 DeprojectNormalToDiff (
|
||||
vector2 normal_pos,
|
||||
double depth = 1) const {
|
||||
return (0, 0, 0);
|
||||
}
|
||||
|
||||
virtual vector3 DeprojectScreenToDiff (
|
||||
vector2 screen_pos,
|
||||
double depth = 1) const {
|
||||
return (0, 0, 0);
|
||||
}
|
||||
|
||||
virtual vector3 DeprojectCustomToDiff (
|
||||
vector2 origin,
|
||||
vector2 resolution,
|
||||
vector2 screen_pos,
|
||||
double depth = 1) const {
|
||||
return (0, 0, 0);
|
||||
}
|
||||
|
||||
// kd: A normal position is in the -1 <= x, y <= 1 range on your screen.
|
||||
// This will be your screen no matter the resolution:
|
||||
|
||||
/*
|
||||
|
||||
(-1, -1) -- --- --- (0, -1) --- --- --- --- (1, -1)
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
(-1, 0) (0, 0) (1, 0)
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
(-1, 1) --- --- --- (0, 1) --- --- --- --- (1, 1)
|
||||
|
||||
*/
|
||||
|
||||
// So this scales such a position back into your drawing resolution.
|
||||
|
||||
vector2 NormalToScreen (vector2 normal_pos) const {
|
||||
normal_pos = 0.5 * (normal_pos + (1, 1));
|
||||
return (
|
||||
normal_pos.x * resolution.x,
|
||||
normal_pos.y * resolution.y);
|
||||
}
|
||||
|
||||
// kd: And this brings a screen position to normal. Make sure the resolution
|
||||
// is the same for your cursor.
|
||||
|
||||
vector2 ScreenToNormal (vector2 screen_pos) const {
|
||||
screen_pos = (
|
||||
screen_pos.x / resolution.x,
|
||||
screen_pos.y / resolution.y);
|
||||
return 2 * screen_pos - (1, 1);
|
||||
}
|
||||
|
||||
// kd: Other interesting stuff.
|
||||
|
||||
vector3 Difference () const {
|
||||
return diff;
|
||||
}
|
||||
|
||||
double Distance () const {
|
||||
return diff.length();
|
||||
}
|
||||
}
|
||||
141
zscript/dt_libeye/viewport.txt
Normal file
141
zscript/dt_libeye/viewport.txt
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
/* kd:
|
||||
|
||||
This helps repositioning the view port for stuff like screen blocks. It's a
|
||||
little more than that, cuz it can also determine stuff like, "is this scene
|
||||
position in the viewport?" Cuz the scene doesn't necessarily match the
|
||||
viewport.
|
||||
|
||||
Well yea... see the examples. Imagine how annoying it is to even get this
|
||||
idea to begin with.
|
||||
|
||||
*/
|
||||
|
||||
struct dtLe_Viewport {
|
||||
|
||||
private vector2 scene_origin;
|
||||
private vector2 scene_size;
|
||||
|
||||
private vector2 viewport_origin;
|
||||
private vector2 viewport_bound;
|
||||
private vector2 viewport_size;
|
||||
|
||||
private double scene_aspect;
|
||||
private double viewport_aspect;
|
||||
|
||||
private double scale_f;
|
||||
private vector2 scene_to_viewport;
|
||||
|
||||
ui void FromHud () const {
|
||||
scene_aspect = Screen.GetAspectRatio();
|
||||
|
||||
vector2 hud_origin;
|
||||
vector2 hud_size;
|
||||
|
||||
[hud_origin.x, hud_origin.y, hud_size.x, hud_size.y] =
|
||||
Screen.GetViewWindow();
|
||||
|
||||
let window_resolution = (
|
||||
Screen.GetWidth(),
|
||||
Screen.GetHeight());
|
||||
|
||||
let window_to_normal = (
|
||||
1.0 / window_resolution.x,
|
||||
1.0 / window_resolution.y);
|
||||
|
||||
viewport_origin = (
|
||||
window_to_normal.x * hud_origin.x,
|
||||
window_to_normal.y * hud_origin.y);
|
||||
|
||||
viewport_size = (
|
||||
window_to_normal.x * hud_size.x,
|
||||
window_to_normal.y * hud_size.y);
|
||||
|
||||
viewport_aspect = hud_size.x / hud_size.y;
|
||||
|
||||
viewport_bound = viewport_origin + viewport_size;
|
||||
|
||||
// kd: The scene is what is actually rendered. It's not always the same
|
||||
// as the viewport. When the statusbar comes into play, the scene is
|
||||
// obscured by the viewport being too small.
|
||||
|
||||
// Example: Compare screenblocks 11 against screenblocks 10 in unmodded
|
||||
// Doom. You will notice that the scaling of the 3d world is the same,
|
||||
// but it's moved up by half the height of the statusbar.
|
||||
|
||||
// That makes this viewport stuff kinda really annoying to deal with.
|
||||
|
||||
// Also statusbar.getsomethingfromstatusbar, really really nice naming.
|
||||
|
||||
let statusbar_height =
|
||||
(window_resolution.y - Statusbar.GetTopOfStatusbar()) / window_resolution.y;
|
||||
|
||||
scale_f = hud_size.x / window_resolution.x;
|
||||
|
||||
scene_aspect = Screen.GetAspectRatio();
|
||||
|
||||
let offset = 10 < screenblocks ? 0 : 0.5 * statusbar_height;
|
||||
|
||||
scene_size = (
|
||||
scale_f,
|
||||
scale_f);
|
||||
|
||||
scene_origin = viewport_origin - (0, 0.5 * (scene_size.y - viewport_size.y));
|
||||
|
||||
scene_to_viewport = (
|
||||
viewport_size.x / scene_size.x,
|
||||
viewport_size.y / scene_size.y);
|
||||
}
|
||||
|
||||
// kd: Is the scene pos (normal, just like projected normal) inside the
|
||||
// view port? If yes, it's visible in the 3d world, even through resizing.
|
||||
bool IsInside (vector2 scene_pos) const {
|
||||
let normal_pos = scene_origin + (
|
||||
scene_size.x * 0.5 * (1 + scene_pos.x),
|
||||
scene_size.y * 0.5 * (1 + scene_pos.y));
|
||||
|
||||
if( normal_pos.x < viewport_origin.x || viewport_bound.x < normal_pos.x ||
|
||||
normal_pos.y < viewport_origin.y || viewport_bound.y < normal_pos.y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// kd: Use these for drawing (and make sure the aspect ratios match).
|
||||
vector2 SceneToCustom (vector2 scene_pos, vector2 resolution) const {
|
||||
let normal_pos = 0.5 * (
|
||||
(scene_pos.x + 1) * scene_size.x,
|
||||
(scene_pos.y + 1) * scene_size.y);
|
||||
|
||||
return (
|
||||
(scene_origin.x + normal_pos.x) * resolution.x,
|
||||
(scene_origin.y + normal_pos.y) * resolution.y);
|
||||
}
|
||||
|
||||
vector2 SceneToWindow (vector2 scene_pos) const {
|
||||
return SceneToCustom(
|
||||
scene_pos,
|
||||
(Screen.GetWidth(), Screen.GetHeight()) );
|
||||
}
|
||||
|
||||
vector2 ViewportToCustom (vector2 viewport_pos, vector2 resolution) const {
|
||||
let normal_pos = 0.5 * (
|
||||
(viewport_pos.x + 1) * viewport_size.x,
|
||||
(viewport_pos.y + 1) * viewport_size.y);
|
||||
|
||||
|
||||
return (
|
||||
(viewport_origin.x + normal_pos.x) * resolution.x,
|
||||
(viewport_origin.y + normal_pos.y) * resolution.y);
|
||||
}
|
||||
|
||||
vector2 ViewportToWindow (vector2 viewport_pos) const {
|
||||
return ViewportToCustom(
|
||||
viewport_pos,
|
||||
(Screen.GetWidth(), Screen.GetHeight()) );
|
||||
}
|
||||
|
||||
double Scale () const {
|
||||
return scale_f;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
/*
|
||||
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 dt_Matrix4
|
||||
{
|
||||
private double m[16];
|
||||
|
||||
dt_Matrix4 init()
|
||||
{
|
||||
int i;
|
||||
for ( i=0; i<16; i++ ) m[i] = 0;
|
||||
return self;
|
||||
}
|
||||
|
||||
static dt_Matrix4 create()
|
||||
{
|
||||
return new("dt_Matrix4").init();
|
||||
}
|
||||
|
||||
static dt_Matrix4 identity()
|
||||
{
|
||||
dt_Matrix4 o = dt_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;
|
||||
}
|
||||
|
||||
dt_Matrix4 add( dt_Matrix4 o )
|
||||
{
|
||||
dt_Matrix4 r = dt_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;
|
||||
}
|
||||
|
||||
dt_Matrix4 scale( double s )
|
||||
{
|
||||
dt_Matrix4 r = dt_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;
|
||||
}
|
||||
|
||||
dt_Matrix4 mul( dt_Matrix4 o )
|
||||
{
|
||||
dt_Matrix4 r = dt_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 dt_Matrix4 rotate( Vector3 axis, double theta )
|
||||
{
|
||||
dt_Matrix4 r = dt_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 dt_Matrix4 perspective( double fov, double ar, double znear, double zfar )
|
||||
{
|
||||
dt_Matrix4 r = dt_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;
|
||||
}
|
||||
}
|
||||
|
|
@ -51,7 +51,7 @@ Class BulletImpact : Actor
|
|||
Radius 0.1;
|
||||
Height 0;
|
||||
+NOGRAVITY;
|
||||
+NOCLIP;
|
||||
+NOBLOCKMAP;
|
||||
+DONTSPLASH;
|
||||
+NOTELEPORT;
|
||||
Scale 0.25;
|
||||
|
|
@ -84,6 +84,8 @@ Class BulletImpact : Actor
|
|||
s.vel = pvel;
|
||||
}
|
||||
A_PlaySound("bullet/hit",CHAN_VOICE,attenuation:3.0);
|
||||
let s = Spawn("Splasher",Vec3Offset(0,0,2));
|
||||
s.vel = (0,0,-4);
|
||||
}
|
||||
States
|
||||
{
|
||||
|
|
@ -93,6 +95,24 @@ Class BulletImpact : Actor
|
|||
}
|
||||
}
|
||||
|
||||
Class Splasher : Actor
|
||||
{
|
||||
Default
|
||||
{
|
||||
Radius 0.1;
|
||||
Height 0;
|
||||
+CORPSE;
|
||||
+NOTELEPORT;
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
Crash:
|
||||
TNT1 A 2;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class UTCasing : Actor
|
||||
{
|
||||
int deadtimer, numbounces;
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ Class ImpactHammer : UTWeapon
|
|||
invoker.count = 0;
|
||||
A_AlertMonsters();
|
||||
}
|
||||
A_QuakeEx(clamp(int(invoker.chargesize*3),0,3),clamp(int(invoker.chargesize*3),0,3),clamp(int(invoker.chargesize*3),0,3),2,0,96,"",QF_RELATIVE,rollIntensity:clamp(invoker.chargesize*0.3,0,0.3));
|
||||
A_QuakeEx(clamp(int(invoker.chargesize),0,2),clamp(int(invoker.chargesize),0,2),clamp(int(invoker.chargesize),0,2),2,0,96,"",QF_RELATIVE,rollIntensity:clamp(invoker.chargesize*0.3,0,0.3));
|
||||
UTMainHandler.DoSwing(self,(FRandom[Impact](-1,1),FRandom[Impact](-1,1)),invoker.chargesize*0.1,0,1,SWING_Spring);
|
||||
if ( !(player.cmd.buttons&BT_ATTACK) )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -105,6 +105,107 @@ Class DamageAmplifier : Powerup
|
|||
}
|
||||
}
|
||||
|
||||
Class UTInvulnerability : PowerupGiver
|
||||
{
|
||||
Default
|
||||
{
|
||||
Tag "$T_UTINVUL";
|
||||
Inventory.PickupMessage "$I_UTINVUL";
|
||||
+COUNTITEM;
|
||||
+INVENTORY.AUTOACTIVATE;
|
||||
+INVENTORY.ALWAYSPICKUP;
|
||||
+INVENTORY.BIGPOWERUP;
|
||||
Inventory.MaxAmount 0;
|
||||
Powerup.Type "UTInvulPower";
|
||||
Inventory.PickupSound "uinvul/pickup";
|
||||
Inventory.RespawnTics 4200;
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
UKEY A -1;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class UTInvulLight : DynamicLight
|
||||
{
|
||||
Default
|
||||
{
|
||||
DynamicLight.Type "Point";
|
||||
Args 255,238,0,80;
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
if ( !target || !master )
|
||||
{
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
if ( target.player )
|
||||
SetOrigin(target.Vec2OffsetZ(0,0,target.player.viewz),true);
|
||||
else SetOrigin(target.Vec3Offset(0,0,target.height/2),true);
|
||||
args[LIGHT_INTENSITY] = Random[UInvuln](10,12)*8;
|
||||
bDORMANT = Powerup(master).isBlinking();
|
||||
}
|
||||
}
|
||||
|
||||
Class UTInvulPower : Powerup
|
||||
{
|
||||
Actor l;
|
||||
int lasteffect;
|
||||
|
||||
Default
|
||||
{
|
||||
Powerup.Duration -60;
|
||||
Powerup.Color "FFEE00", 0.05;
|
||||
}
|
||||
|
||||
override void BeginPlay()
|
||||
{
|
||||
Super.BeginPlay();
|
||||
if ( deathmatch ) EffectTics /= 2;
|
||||
}
|
||||
|
||||
override void InitEffect()
|
||||
{
|
||||
Super.InitEffect();
|
||||
lasteffect = int.min;
|
||||
l = Spawn("UTInvulLight",Owner.pos);
|
||||
l.target = Owner;
|
||||
l.master = self;
|
||||
}
|
||||
|
||||
override void DoEffect()
|
||||
{
|
||||
Super.DoEffect();
|
||||
if ( (EffectTics == 175) || (EffectTics == 140) || (EffectTics == 105) || (EffectTics == 70) || (EffectTics == 35) )
|
||||
Owner.A_PlaySound("uinvul/drain",CHAN_7,1.0,false,0.25);
|
||||
}
|
||||
|
||||
override void EndEffect()
|
||||
{
|
||||
Super.EndEffect();
|
||||
if ( (EffectTics <= 0) && Owner && Owner.CheckLocalView() ) Console.Printf(StringTable.Localize("$D_UTINVUL"));
|
||||
}
|
||||
|
||||
override bool isBlinking()
|
||||
{
|
||||
return ((EffectTics <= 175) && (EffectTics%35 >= 30));
|
||||
}
|
||||
|
||||
override void ModifyDamage( int damage, Name damageType, out int newdamage, bool passive )
|
||||
{
|
||||
if ( !passive || (damage <= 0) ) return;
|
||||
newdamage = 0;
|
||||
if ( gametic < lasteffect ) return;
|
||||
Owner.A_PlaySound("uinvul/hit",CHAN_7,1.0,false,0.25);
|
||||
UTMainHandler.DoFlash(Owner,Color(48,255,238,0),6);
|
||||
lasteffect = gametic+5; // prevent excess flash
|
||||
}
|
||||
}
|
||||
|
||||
// Backpack that only gives ammo for valid weapons
|
||||
Class UTBackpack : BackpackItem
|
||||
{
|
||||
|
|
@ -277,7 +378,7 @@ Class UTInvisibilityX : Actor
|
|||
return;
|
||||
}
|
||||
Warp(target,flags:WARPF_COPYINTERPOLATION|WARPF_NOCHECKPOSITION);
|
||||
bInvisible = target.bInvisible;
|
||||
bInvisible = target.bInvisible||!target.InStateSequence(target.CurState,target.FindState("Spawn"));
|
||||
}
|
||||
States
|
||||
{
|
||||
|
|
@ -291,18 +392,19 @@ Class UTMapRevealer : MapRevealer
|
|||
{
|
||||
Default
|
||||
{
|
||||
Tag "$T_MAPREVEALER";
|
||||
+COUNTITEM;
|
||||
+INVENTORY.FANCYPICKUPSOUND;
|
||||
+INVENTORY.ALWAYSPICKUP;
|
||||
Inventory.MaxAmount 0;
|
||||
Inventory.PickupSound "trans/pickup";
|
||||
Inventory.PickupSound "misc/p_pkup";
|
||||
Inventory.PickupMessage "$I_MAPREVEALER";
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
TRNS A -1;
|
||||
Stop;
|
||||
TRNS ABCDCB 6;
|
||||
Loop;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -385,6 +487,7 @@ Class PowerJumpBoots_IronFeet : PowerIronFeet
|
|||
}
|
||||
override void AbsorbDamage( int damage, Name damageType, out int newdamage )
|
||||
{
|
||||
Inventory.AbsorbDamage(damage,damageType,newdamage);
|
||||
}
|
||||
override void DoEffect()
|
||||
{
|
||||
|
|
@ -394,159 +497,108 @@ Class PowerJumpBoots_IronFeet : PowerIronFeet
|
|||
}
|
||||
}
|
||||
|
||||
Class Searchlight : Inventory
|
||||
Class UTNightVision : PowerupGiver
|
||||
{
|
||||
Actor lt[3];
|
||||
int ticcnt;
|
||||
Default
|
||||
{
|
||||
Tag "$T_SEARCHLIGHT";
|
||||
Tag "$T_UTVISION";
|
||||
Inventory.PickupMessage "$I_UTVISION";
|
||||
+COUNTITEM;
|
||||
+INVENTORY.UNTOSSABLE;
|
||||
+INVENTORY.FANCYPICKUPSOUND;
|
||||
+INVENTORY.AUTOACTIVATE;
|
||||
+INVENTORY.ALWAYSPICKUP;
|
||||
Inventory.Amount 200;
|
||||
Inventory.MaxAmount 200;
|
||||
Inventory.InterHubAmount 0;
|
||||
Inventory.PickupMessage "$I_SEARCHLIGHT";
|
||||
Inventory.PickupSound "lite/pickup";
|
||||
Inventory.RespawnTics 1050;
|
||||
+INVENTORY.BIGPOWERUP;
|
||||
Inventory.MaxAmount 0;
|
||||
Powerup.Type "UTVisionPower";
|
||||
Inventory.PickupSound "uvision/pickup";
|
||||
Inventory.RespawnTics 4200;
|
||||
}
|
||||
|
||||
override bool Use( bool pickup )
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
if ( !lt[0] ) lt[0] = Spawn("mkLight");
|
||||
lt[0].target = owner;
|
||||
lt[0].master = self;
|
||||
if ( !lt[1] ) lt[1] = Spawn("mkLight2");
|
||||
lt[1].target = owner;
|
||||
lt[1].master = self;
|
||||
if ( !lt[2] ) lt[2] = Spawn("mkLight3");
|
||||
lt[2].target = owner;
|
||||
lt[2].master = self;
|
||||
return Super.Use(pickup);
|
||||
}
|
||||
override void DetachFromOwner()
|
||||
{
|
||||
Super.DetachFromOwner();
|
||||
if ( lt[0] ) lt[0].Destroy();
|
||||
if ( lt[1] ) lt[1].Destroy();
|
||||
if ( lt[2] ) lt[2].Destroy();
|
||||
}
|
||||
override void DoEffect()
|
||||
{
|
||||
Super.DoEffect();
|
||||
if ( !Owner ) return;
|
||||
if ( ticcnt++ < TICRATE ) return;
|
||||
ticcnt = 0;
|
||||
if ( --Amount <= 0 )
|
||||
{
|
||||
if ( Owner.CheckLocalView() ) Console.Printf(StringTable.Localize("$D_SEARCHLIGHT"));
|
||||
DepleteOrDestroy();
|
||||
}
|
||||
Super.PostBeginPlay();
|
||||
tracer = Spawn("UTNightVisionX",pos);
|
||||
tracer.angle = angle;
|
||||
tracer.target = self;
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
SLIT A -1;
|
||||
UKEY A -1;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
/* hello, Soundless Mound copypasted lights */
|
||||
Class mkLight : DynamicLight
|
||||
Class UTNightVisionX : UTInvisibilityX
|
||||
{
|
||||
int basecolor[3];
|
||||
Default
|
||||
{
|
||||
Alpha 0.3;
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
UKEY A -1 Bright;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class UTVisionLight : DynamicLight
|
||||
{
|
||||
Default
|
||||
{
|
||||
DynamicLight.Type "Point";
|
||||
+DynamicLight.SPOT;
|
||||
+DynamicLight.ATTENUATE;
|
||||
+DynamicLight.DONTLIGHTSELF;
|
||||
args 255,224,160,300;
|
||||
DynamicLight.SpotInnerAngle 20;
|
||||
DynamicLight.SpotOuterAngle 35;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
basecolor[0] = args[LIGHT_RED];
|
||||
basecolor[1] = args[LIGHT_GREEN];
|
||||
basecolor[2] = args[LIGHT_BLUE];
|
||||
+DYNAMICLIGHT.SPOT;
|
||||
DynamicLight.SpotInnerAngle 60;
|
||||
DynamicLight.SpotOuterAngle 90;
|
||||
Args 224,238,255,800;
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
if ( !target || !Inventory(master) )
|
||||
if ( !target || !master )
|
||||
{
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
if ( target.player ) SetOrigin(target.Vec2OffsetZ(0,0,target.player.viewz),true);
|
||||
else SetOrigin(target.vec3Offset(0,0,target.height*0.75),true);
|
||||
A_SetAngle(target.angle,SPF_INTERPOLATE);
|
||||
A_SetPitch(target.pitch,SPF_INTERPOLATE);
|
||||
args[LIGHT_RED] = int(basecolor[0]*clamp(Inventory(master).amount/40.,0.,1.));
|
||||
args[LIGHT_GREEN] = int(basecolor[1]*clamp(Inventory(master).amount/40.,0.,1.));
|
||||
args[LIGHT_BLUE] = int(basecolor[2]*clamp(Inventory(master).amount/40.,0.,1.));
|
||||
bDORMANT = (target.health <= 0);
|
||||
if ( Inventory(target) && target.bInvisible ) bDORMANT = true;
|
||||
// alert monsters hit by the light
|
||||
if ( GetClass() != "mkLight" ) return;
|
||||
if ( !bDORMANT && target.player && (target.health > 0) )
|
||||
{
|
||||
BlockThingsIterator bt = BlockThingsIterator.Create(target,args[LIGHT_INTENSITY]);
|
||||
while ( bt.Next() )
|
||||
{
|
||||
if ( !bt.Thing || (Distance3D(bt.Thing) > args[LIGHT_INTENSITY]) ) continue;
|
||||
Vector3 aimdir = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
|
||||
Vector3 reldir = Vec3To(bt.Thing).unit();
|
||||
if ( (acos(aimdir dot reldir) < SpotOuterAngle+5) && bt.Thing.CheckSight(target) ) bt.Thing.LastHeard = target;
|
||||
}
|
||||
}
|
||||
Vector3 x, y, z, origin;
|
||||
[x, y, z] = dt_CoordUtil.GetAxes(target.pitch,target.angle,target.roll);
|
||||
if ( target.player )
|
||||
origin = target.Vec2OffsetZ(0,0,target.player.viewz);
|
||||
else origin = target.Vec3Offset(0,0,target.height/2);
|
||||
SetOrigin(origin,true);
|
||||
angle = target.angle;
|
||||
pitch = target.pitch;
|
||||
args[LIGHT_INTENSITY] = Random[UVision](40,48)*20;
|
||||
bDORMANT = ((players[consoleplayer].Camera != target)||Powerup(master).isBlinking());
|
||||
}
|
||||
}
|
||||
|
||||
Class mkLight2 : mkLight
|
||||
Class UTVisionPower : Powerup
|
||||
{
|
||||
Default
|
||||
{
|
||||
args 128,112,96,300;
|
||||
DynamicLight.SpotInnerAngle 0;
|
||||
DynamicLight.SpotOuterAngle 50;
|
||||
}
|
||||
}
|
||||
|
||||
Class mkLight3 : DynamicLight
|
||||
{
|
||||
int basecolor[3];
|
||||
Actor l;
|
||||
|
||||
Default
|
||||
{
|
||||
DynamicLight.Type "Point";
|
||||
+DynamicLight.ATTENUATE;
|
||||
args 32,28,24,0;
|
||||
Powerup.Duration -90;
|
||||
Powerup.Color "AAEEFF", 0.05;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
|
||||
override void BeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
basecolor[0] = args[LIGHT_RED];
|
||||
basecolor[1] = args[LIGHT_GREEN];
|
||||
basecolor[2] = args[LIGHT_BLUE];
|
||||
Super.BeginPlay();
|
||||
if ( deathmatch ) EffectTics /= 2;
|
||||
}
|
||||
override void Tick()
|
||||
|
||||
override void InitEffect()
|
||||
{
|
||||
Super.Tick();
|
||||
if ( !target || Inventory(target) || !Inventory(master) )
|
||||
{
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
args[LIGHT_RED] = int(basecolor[0]*clamp(Inventory(master).amount/40.,0.,1.));
|
||||
args[LIGHT_GREEN] = int(basecolor[1]*clamp(Inventory(master).amount/40.,0.,1.));
|
||||
args[LIGHT_BLUE] = int(basecolor[2]*clamp(Inventory(master).amount/40.,0.,1.));
|
||||
SetOrigin(target.vec3Offset(0,0,target.height*0.5),true);
|
||||
Super.InitEffect();
|
||||
l = Spawn("UTVisionLight",Owner.pos);
|
||||
l.target = Owner;
|
||||
l.master = self;
|
||||
}
|
||||
|
||||
override void EndEffect()
|
||||
{
|
||||
Super.EndEffect();
|
||||
if ( (EffectTics <= 0) && Owner && Owner.CheckLocalView() ) Console.Printf(StringTable.Localize("$D_UTVISION"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -143,6 +143,8 @@ Class Razor2 : Actor
|
|||
}
|
||||
Goto Spawn;
|
||||
Death:
|
||||
TNT1 A 0 A_RazorHit();
|
||||
XDeath:
|
||||
TNT1 A 1 A_StopSound(CHAN_VOICE);
|
||||
Stop;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -442,6 +442,15 @@ Class Translocator : UTWeapon
|
|||
A_AlertMonsters();
|
||||
// squeeze down new z if ceiling is in the way
|
||||
if ( (newpos.z+height > moduleceilingz) ) newpos.z = max(modulefloorz,moduleceilingz-height);
|
||||
// temporarily disable telefragging for all allies
|
||||
bool oldnotele[MAXPLAYERS];
|
||||
for ( int i=0; i<MAXPLAYERS; i++ )
|
||||
{
|
||||
if ( !playeringame[i] || !players[i].mo ) continue;
|
||||
oldnotele[i] = players[i].mo.bNOTELEFRAG;
|
||||
if ( !IsFriend(players[i].mo) ) continue;
|
||||
players[i].mo.bNOTELEFRAG = true;
|
||||
}
|
||||
if ( Warp(self,newpos.x,newpos.y,newpos.z,flags:WARPF_ABSOLUTEPOSITION|WARPF_TESTONLY) && TeleportMove(newpos,true) )
|
||||
{
|
||||
SpawnTeleportFog(oldpos,true,false);
|
||||
|
|
@ -454,6 +463,11 @@ Class Translocator : UTWeapon
|
|||
player.fov = min(175,player.desiredfov+60);
|
||||
}
|
||||
else A_PlaySound("transloc/return",CHAN_WEAPON);
|
||||
for ( int i=0; i<MAXPLAYERS; i++ )
|
||||
{
|
||||
if ( !playeringame[i] || !players[i].mo ) continue;
|
||||
players[i].mo.bNOTELEFRAG = oldnotele[i];
|
||||
}
|
||||
if ( bBroken )
|
||||
{
|
||||
UTMainHandler.DoFlash(self,Color(255,255,255,255),50);
|
||||
|
|
|
|||
|
|
@ -139,13 +139,21 @@ Class UTPlayer : DoomPlayer
|
|||
if ( giveall || (name ~== "armor") )
|
||||
{
|
||||
// Doom Tournament just gives the player a shield belt and maximum bonuses
|
||||
let belt = Inventory(Spawn("UTShieldBelt"));
|
||||
belt.ClearCounters();
|
||||
if ( !belt.CallTryPickup(self) ) belt.Destroy();
|
||||
let bonus = Inventory(Spawn("UTArmorBonus"));
|
||||
bonus.ClearCounters();
|
||||
bonus.Amount = bonus.MaxAmount;
|
||||
if ( !bonus.CallTryPickup(self) ) bonus.Destroy();
|
||||
// in non-vanilla mode, also gives body/thigh armor
|
||||
Class<Inventory> which[] =
|
||||
{
|
||||
"UTShieldBelt", "UTArmorBonus",
|
||||
"UTBodyArmor", "UTThighpads"
|
||||
};
|
||||
Inventory inv;
|
||||
int mx = flak_vanillaarmor?2:4;
|
||||
for ( int i=0; i<mx; i++ )
|
||||
{
|
||||
inv = Inventory(Spawn(which[i]));
|
||||
inv.ClearCounters();
|
||||
inv.Amount = inv.MaxAmount;
|
||||
if ( !inv.CallTryPickup(self) ) inv.Destroy();
|
||||
}
|
||||
if ( !giveall ) return;
|
||||
}
|
||||
if ( giveall || (name ~== "keys") )
|
||||
|
|
@ -1274,23 +1282,71 @@ Class UTUnderSound : Actor
|
|||
}
|
||||
}
|
||||
|
||||
// TODO terrain stuff
|
||||
// terrain splashes
|
||||
Class UTTerrainFX : Actor
|
||||
{
|
||||
Default
|
||||
{
|
||||
RenderStyle "Add";
|
||||
Radius 0.1;
|
||||
Height 0;
|
||||
+NOGRAVITY;
|
||||
+NOBLOCKMAP;
|
||||
+DONTSPLASH;
|
||||
+NOTELEPORT;
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
TNT1 A 1;
|
||||
SPSH ABCDEFGHIJKLMNOPQRSTUVWXYZ 1 A_FadeOut(1./26.);
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class UTWaterSplish : UTTerrainFX
|
||||
{
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
let r = Spawn("WaterRing",pos);
|
||||
r.scale *= 0.3;
|
||||
}
|
||||
}
|
||||
|
||||
Class UTWaterSplash : UTTerrainFX
|
||||
{
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
Spawn("WaterRing",pos);
|
||||
}
|
||||
}
|
||||
|
||||
Class WaterRing : Actor
|
||||
{
|
||||
Default
|
||||
{
|
||||
RenderStyle "Add";
|
||||
Scale 0.15;
|
||||
Radius 0.1;
|
||||
Height 0;
|
||||
+NOGRAVITY;
|
||||
+NOBLOCKMAP;
|
||||
+DONTSPLASH;
|
||||
+NOTELEPORT;
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
if ( isFrozen() ) return;
|
||||
alpha -= 1./20.;
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
RNGX ABCDEF 5 Bright;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class UTBloodSplish : UTTerrainFX
|
||||
|
|
@ -1311,18 +1367,112 @@ Class UTSlimeSplash : UTTerrainFX
|
|||
|
||||
Class UTNukageSplish : UTTerrainFX
|
||||
{
|
||||
Default
|
||||
{
|
||||
+BRIGHT;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
int numpt = Random[Terrain](3,5);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (FRandom[Terrain](-1,1),FRandom[Terrain](-1,1),FRandom[Terrain](-1,1)).unit()*FRandom[Terrain](2,5);
|
||||
let s = Spawn("BioSpark",pos);
|
||||
s.vel = pvel;
|
||||
}
|
||||
numpt = Random[Terrain](1,2);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (FRandom[Terrain](-1,1),FRandom[Terrain](-1,1),FRandom[Terrain](-1,1)).unit()*FRandom[Terrain](.6,1.2);
|
||||
let s = Spawn("UTSmoke",pos);
|
||||
s.vel = pvel;
|
||||
s.scale *= 0.7;
|
||||
s.A_SetRenderStyle(0.5,STYLE_AddShaded);
|
||||
if ( Random[Terrain](0,1) ) s.SetShade("40FF60");
|
||||
else s.SetShade("60FF40");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Class UTNukageSplash : UTTerrainFX
|
||||
{
|
||||
Default
|
||||
{
|
||||
+BRIGHT;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
int numpt = Random[Terrain](8,12);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (FRandom[Terrain](-1,1),FRandom[Terrain](-1,1),FRandom[Terrain](-1,1)).unit()*FRandom[Terrain](3,12);
|
||||
let s = Spawn("BioSpark",pos);
|
||||
s.vel = pvel;
|
||||
}
|
||||
numpt = Random[Terrain](3,5);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (FRandom[Terrain](-1,1),FRandom[Terrain](-1,1),FRandom[Terrain](-1,1)).unit()*FRandom[Terrain](1.2,2.4);
|
||||
let s = Spawn("UTSmoke",pos);
|
||||
s.vel = pvel;
|
||||
s.scale *= 2;
|
||||
s.A_SetRenderStyle(0.5,STYLE_AddShaded);
|
||||
if ( Random[Terrain](0,1) ) s.SetShade("40FF60");
|
||||
else s.SetShade("60FF40");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Class UTLavaSplish : UTTerrainFX
|
||||
{
|
||||
Default
|
||||
{
|
||||
+BRIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
Class UTLavaSplash : UTTerrainFX
|
||||
{
|
||||
Default
|
||||
{
|
||||
+BRIGHT;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
Spawn("FlameExplosion",pos);
|
||||
}
|
||||
}
|
||||
|
||||
Class FlameExplosion : Actor
|
||||
{
|
||||
Default
|
||||
{
|
||||
RenderStyle "Add";
|
||||
Radius 0.1;
|
||||
Height 0;
|
||||
Scale 0.8;
|
||||
+NOGRAVITY;
|
||||
+NOBLOCKMAP;
|
||||
+DONTSPLASH;
|
||||
+NOTELEPORT;
|
||||
+FORCEXYBILLBOARD;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
A_PlaySound("ut/lavaex",CHAN_VOICE);
|
||||
Spawn("SlugSmoke",pos);
|
||||
Spawn("SlugLight",pos);
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
FEXP ABCDEFGHIJ 2 BRIGHT;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class UTNitroSplish : UTTerrainFX
|
||||
|
|
@ -2775,25 +2925,31 @@ Class UTMainHandler : EventHandler
|
|||
else if ( Random[Replacements](0,1) ) e.Replacement = 'MiniAmmo';
|
||||
else e.Replacement = 'RifleAmmo';
|
||||
}
|
||||
else if ( e.Replacee == 'InvulnerabilitySphere' ) e.Replacement = (!deathmatch||flak_dmsshock)?'EnhancedShockRifle':'UDamage';
|
||||
else if ( e.Replacee == 'InvulnerabilitySphere' ) e.Replacement = 'UTInvulnerability';
|
||||
else if ( e.Replacee == 'Berserk' ) e.Replacement = 'UDamage';
|
||||
else if ( (e.Replacee == 'ArtiTomeOfPower') || (e.Replacee == 'ArtiEgg') ) e.Replacement = 'ActUDamage';
|
||||
else if ( e.Replacee == 'Soulsphere' ) e.Replacement = 'UTHealthPack';
|
||||
else if ( e.Replacee == 'ArtiSuperHealth' ) e.Replacement = 'ActHealthPack';
|
||||
else if ( e.Replacee == 'Megasphere' ) e.Replacement = 'UTShieldBelt';
|
||||
else if ( e.Replacee == 'ArtiInvulnerability' ) e.Replacement = 'ActShieldBelt';
|
||||
else if ( e.Replacee == 'ArtiInvulnerability' ) e.Replacement = 'ActUTInvulnerability';
|
||||
else if ( (e.Replacee == 'Allmap') || (e.Replacee == 'SuperMap') ) e.Replacement = 'UTMapRevealer';
|
||||
else if ( e.Replacee == 'BlurSphere' ) e.Replacement = 'UTInvisibility';
|
||||
else if ( e.Replacee == 'ArtiInvisibility' ) e.Replacement = 'ActInvisibility';
|
||||
else if ( e.Replacee == 'Infrared' ) e.Replacement = 'Searchlight';
|
||||
else if ( e.Replacee == 'ArtiTorch' ) e.Replacement = 'ActSearchlight';
|
||||
else if ( e.Replacee == 'ArtiInvisibility' ) e.Replacement = 'ActUTInvisibility';
|
||||
else if ( e.Replacee == 'Infrared' ) e.Replacement = 'UTNightVision';
|
||||
else if ( e.Replacee == 'ArtiTorch' ) e.Replacement = 'ActUTNightVision';
|
||||
else if ( e.Replacee == 'RadSuit' ) e.Replacement = 'UTJumpBoots';
|
||||
else if ( e.Replacee == 'ArtiFly' ) e.Replacement = 'ActJumpBoots';
|
||||
else if ( (e.Replacee == 'Backpack') || (e.Replacee == 'BagOfHolding') ) e.Replacement = 'UTBackpack';
|
||||
else if ( (e.Replacee == 'ArmorBonus') || (e.Replacee == 'ArtiTimeBomb') ) e.Replacement = 'UTArmorBonus';
|
||||
else if ( (e.Replacee == 'HealthBonus') || (e.Replacee == 'CrystalVial') ) e.Replacement = 'UTHealthBonus';
|
||||
else if ( (e.Replacee == 'GreenArmor') || (e.Replacee == 'Silvershield') ) e.Replacement = 'UTThighPads';
|
||||
else if ( (e.Replacee == 'BlueArmor') || (e.Replacee == 'EnchantedShield') ) e.Replacement = 'UTBodyArmor';
|
||||
else if ( e.Replacee == 'GreenArmor' ) e.Replacement = 'UTThighPads';
|
||||
else if ( e.Replacee == 'Silvershield' )
|
||||
{
|
||||
if ( Random[Replacements](0,1) ) e.Replacement = 'UTThighPads';
|
||||
else e.Replacement = 'UTBodyArmor';
|
||||
}
|
||||
else if ( e.Replacee == 'BlueArmor' ) e.Replacement = 'UTBodyArmor';
|
||||
else if ( e.Replacee == 'EnchantedShield' ) e.Replacement = 'UTShieldBelt';
|
||||
else if ( e.Replacee == 'Stimpack' ) e.Replacement = 'UTMedBox';
|
||||
else if ( e.Replacee == 'Medikit' ) e.Replacement = 'UTHealthBox';
|
||||
else if ( e.Replacee == 'ArtiHealth' )
|
||||
|
|
@ -2804,9 +2960,7 @@ Class UTMainHandler : EventHandler
|
|||
else if ( e.Replacee == 'ArtiTeleport' )
|
||||
{
|
||||
// I have no idea what to replace this with, so just have some random stuff
|
||||
if ( Random[Replacements](0,1) ) e.Replacement = 'UTBackpack';
|
||||
else if ( Random[Replacements](0,1) ) e.Replacement = 'ActShieldBelt';
|
||||
else if ( Random[Replacements](0,1) ) e.Replacement = 'ActHealthPack';
|
||||
if ( Random[Replacements](0,1) ) e.Replacement = 'ActHealthPack';
|
||||
else e.Replacement = 'ActUDamage';
|
||||
}
|
||||
else if ( e.Replacee == 'RedCard' ) e.Replacement = 'UTRedKey';
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ Class UTBloodDrop : Actor
|
|||
RenderStyle "Translucent";
|
||||
+MISSILE;
|
||||
+NOTELEPORT;
|
||||
+DONTSPLASH;
|
||||
+THRUACTORS;
|
||||
+FORCEXYBILLBOARD;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ Class ViewTracer : LineTracer
|
|||
|
||||
Class UTHud : BaseStatusBar
|
||||
{
|
||||
TextureID AmmoBar, Boxes[4], Keys[5], BigNum[12], Flash, Slots[10], Icons[14], Uses[14], Man[5], Woman[5], Boss[5], WeaponBox, IconTloc2, UseTloc2, IconSaw2, UseSaw2, ItemBox, ItemSel, ItemFlash, ItemArrow[2], LastItem, FacePanel[3];
|
||||
TextureID AmmoBar, Boxes[4], Keys[5], BigNum[12], Flash, Slots[10], Icons[14], Uses[14], Man[5], Woman[5], Boss[5], WeaponBox, IconTloc2, UseTloc2, IconSaw2, UseSaw2, IconAuto2, UseAuto2, ItemBox, ItemSel, ItemFlash, ItemArrow[2], LastItem, FacePanel[3];
|
||||
Class<Weapon> IconClasses[14];
|
||||
double HScale;
|
||||
Color tintcolor, bgcolor;
|
||||
|
|
@ -34,6 +34,7 @@ Class UTHud : BaseStatusBar
|
|||
int lastseentic;
|
||||
bool showweapons, showfrags, showammo, showstatus, showinfo;
|
||||
double hudsize, weaponsize, statussize;
|
||||
bool justselected;
|
||||
|
||||
HUDFont mUTFont12, mUTFont40;
|
||||
|
||||
|
|
@ -167,6 +168,8 @@ Class UTHud : BaseStatusBar
|
|||
UseTloc2 = TexMan.CheckForTexture("UseTrn2",TexMan.Type_Any);
|
||||
IconSaw2 = TexMan.CheckForTexture("IconSaw2",TexMan.Type_Any);
|
||||
UseSaw2 = TexMan.CheckForTexture("UseSaw2",TexMan.Type_Any);
|
||||
IconAuto2 = TexMan.CheckForTexture("IconAut2",TexMan.Type_Any);
|
||||
UseAuto2 = TexMan.CheckForTexture("UseAut2",TexMan.Type_Any);
|
||||
FacePanel[0] = TexMan.CheckForTexture("FacePnl",TexMan.Type_Any);
|
||||
FacePanel[1] = TexMan.CheckForTexture("FacePnlA",TexMan.Type_Any);
|
||||
FacePanel[2] = TexMan.CheckForTexture("Static1",TexMan.Type_Any);
|
||||
|
|
@ -252,7 +255,9 @@ Class UTHud : BaseStatusBar
|
|||
if ( !(w is IconClasses[i]) ) continue;
|
||||
if ( use )
|
||||
{
|
||||
if ( (i == 10) && flak_sawammo )
|
||||
if ( (i == 1) && (w.Amount > 1) )
|
||||
UTDrawTintedTex(UseAuto2,sx,opacity+7);
|
||||
else if ( (i == 10) && flak_sawammo )
|
||||
UTDrawTintedTex(UseSaw2,sx,opacity+7);
|
||||
else if ( (i == 11) && flak_transloc2k4 )
|
||||
UTDrawTintedTex(UseTloc2,sx,opacity+7);
|
||||
|
|
@ -260,7 +265,9 @@ Class UTHud : BaseStatusBar
|
|||
}
|
||||
else
|
||||
{
|
||||
if ( (i == 10) && flak_sawammo )
|
||||
if ( (i == 1) && (w.Amount > 1) )
|
||||
UTDrawTintedTex(IconAuto2,sx,opacity,halftint);
|
||||
else if ( (i == 10) && flak_sawammo )
|
||||
UTDrawTintedTex(IconSaw2,sx,opacity,halftint);
|
||||
else if ( (i == 11) && flak_transloc2k4 )
|
||||
UTDrawTintedTex(IconTloc2,sx,opacity,halftint);
|
||||
|
|
@ -433,11 +440,14 @@ Class UTHud : BaseStatusBar
|
|||
CurY = 0;
|
||||
Color dollcolor = tintcolor;
|
||||
DamageAmplifier d;
|
||||
UTInvulPower p;
|
||||
UTJumpBoots j;
|
||||
d = DamageAmplifier(CPlayer.mo.FindInventory("DamageAmplifier"));
|
||||
p = UTInvulPower(CPlayer.mo.FindInventory("UTInvulPower"));
|
||||
j = UTJumpBoots(CPlayer.mo.FindInventory("UTJumpBoots"));
|
||||
if ( d && !d.isBlinking() ) dollcolor = d.BlendColor;
|
||||
int dolltype = 0;
|
||||
if ( p && !p.isBlinking() ) dollcolor = LerpColor(GoldColor,dollcolor,((gametic+fractic)/15)%1.);
|
||||
if ( CPlayer.mo is 'UTPlayer' ) dolltype = UTPlayer(CPlayer.mo).DollType;
|
||||
else
|
||||
{
|
||||
|
|
@ -1036,6 +1046,25 @@ Class UTHud : BaseStatusBar
|
|||
LastItem = CPlayer.mo.InvSel.Icon;
|
||||
LastAmount = CPlayer.mo.InvSel.Amount-1;
|
||||
}
|
||||
if ( CPlayer.inventorytics >= (5*Thinker.TICRATE)-1 )
|
||||
{
|
||||
if ( CPlayer.mo.InvSel )
|
||||
{
|
||||
PickupMsg = CPlayer.mo.InvSel.GetTag();
|
||||
PickupMsgTic = gametic+50;
|
||||
S_Sound("misc/hud_sel",CHAN_UI);
|
||||
}
|
||||
}
|
||||
if ( CPlayer.inventorytics > 0 ) justselected = false;
|
||||
else
|
||||
{
|
||||
if ( !justselected && CPlayer.mo.InvSel )
|
||||
{
|
||||
Console.Printf(StringTable.Localize("$M_ISELECT"),CPlayer.mo.InvSel.GetTag());
|
||||
S_Sound("misc/hud_sel",CHAN_UI);
|
||||
}
|
||||
justselected = true;
|
||||
}
|
||||
if ( deathmatch||teamplay )
|
||||
{
|
||||
if ( CPlayer.fragcount != lastfragcnt ) lastfrag = level.time;
|
||||
|
|
|
|||
|
|
@ -444,6 +444,13 @@ Class RedeemerHUD : HUDMessageBase
|
|||
Array<TargetActor> ta;
|
||||
Shape2D sshape, darrow;
|
||||
bool dodim;
|
||||
// libeye stuff
|
||||
dtLe_ProjScreen proj;
|
||||
dtLe_GLScreen gl_proj;
|
||||
dtLe_SWScreen sw_proj;
|
||||
dtLe_Viewport viewport;
|
||||
bool can_project;
|
||||
transient CVar cvar_renderer;
|
||||
|
||||
RedeemerHUD Init()
|
||||
{
|
||||
|
|
@ -460,15 +467,45 @@ Class RedeemerHUD : HUDMessageBase
|
|||
sshape.PushCoord((1,1));
|
||||
sshape.PushTriangle(0,3,1);
|
||||
sshape.PushTriangle(0,2,3);
|
||||
gl_proj = new("dtLe_GLScreen");
|
||||
sw_proj = new("dtLe_SWScreen");
|
||||
PrepareProjection();
|
||||
return self;
|
||||
}
|
||||
void PrepareProjection()
|
||||
{
|
||||
if ( !cvar_renderer )
|
||||
cvar_renderer = CVar.GetCVar("vid_rendermode",players[consoleplayer]);
|
||||
if ( !cvar_renderer )
|
||||
{
|
||||
can_project = proj = gl_proj;
|
||||
return;
|
||||
}
|
||||
switch ( cvar_renderer.GetInt() )
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
proj = sw_proj;
|
||||
break;
|
||||
default:
|
||||
proj = gl_proj;
|
||||
break;
|
||||
}
|
||||
can_project = proj;
|
||||
}
|
||||
override bool Tick()
|
||||
{
|
||||
PrepareProjection();
|
||||
LagRoll = dt_Quat.Normalize180(ViewRoll-LagRoll2);
|
||||
LagRoll2 += dt_Quat.Normalize180(LagRoll-LagRoll2)*0.1;
|
||||
// shootable targetting
|
||||
if ( CVar.GetCVar('flak_redeemerreadout',players[consoleplayer]).GetBool() && !CVar.GetCVar('flak_redeemerreadout_perframe',players[consoleplayer]).GetBool() )
|
||||
if ( CVar.GetCVar('flak_redeemerreadout',players[consoleplayer]).GetBool() && !CVar.GetCVar('flak_redeemerreadout_perframe',players[consoleplayer]).GetBool() && can_project )
|
||||
{
|
||||
viewport.FromHud();
|
||||
proj.CacheResolution();
|
||||
proj.CacheFov(players[consoleplayer].fov);
|
||||
proj.Reorient(ViewPos,(ViewAngle,ViewPitch,ViewRoll));
|
||||
proj.BeginProjection();
|
||||
if ( !t ) t = ThinkerIterator.Create("Actor");
|
||||
if ( !tr ) tr = new("MidTracer");
|
||||
t.Reinit();
|
||||
|
|
@ -479,11 +516,11 @@ Class RedeemerHUD : HUDMessageBase
|
|||
{
|
||||
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)) || (tdir.length() > 2000) || (acos(tdir.unit() dot vdir) > players[consoleplayer].FOV) || tr.Trace(ViewPos,Camera.CurSector,tdir.unit(),tdir.length(),0) ) continue;
|
||||
Vector3 wpos = ViewPos+tdir;
|
||||
Vector3 spos = dt_CoordUtil.WorldToScreen(wpos,ViewPos,ViewPitch,ViewAngle,ViewRoll,players[consoleplayer].FOV);
|
||||
if ( spos.z > 1.0 ) continue;
|
||||
proj.ProjectWorldPos(ViewPos+tdir);
|
||||
Vector2 npos = proj.ProjectToNormal();
|
||||
if ( !proj.IsInFront() ) continue;
|
||||
TargetActor te = new("TargetActor");
|
||||
te.vpos = dt_CoordUtil.ToViewport(spos);
|
||||
te.vpos = viewport.SceneToWindow(npos);
|
||||
te.diststr = String.Format("%f",tdir.length());
|
||||
te.diststr.Replace(".","");
|
||||
ta.Push(te);
|
||||
|
|
@ -496,10 +533,15 @@ Class RedeemerHUD : HUDMessageBase
|
|||
if ( visibility != StatusBar.HUDMSGLayer_UnderHUD ) return;
|
||||
if ( dodim ) Screen.Dim("C8 00 00",0.2,0,0,Screen.GetWidth(),Screen.GetHeight());
|
||||
// shootable targetting
|
||||
if ( CVar.GetCVar('flak_redeemerreadout',players[consoleplayer]).GetBool() )
|
||||
if ( CVar.GetCVar('flak_redeemerreadout',players[consoleplayer]).GetBool() && can_project )
|
||||
{
|
||||
if ( CVar.GetCVar('flak_redeemerreadout_perframe',players[consoleplayer]).GetBool() )
|
||||
{
|
||||
viewport.FromHud();
|
||||
proj.CacheResolution();
|
||||
proj.CacheFov(players[consoleplayer].fov);
|
||||
proj.Reorient(ViewPos,(ViewAngle,ViewPitch,ViewRoll));
|
||||
proj.BeginProjection();
|
||||
if ( !t ) t = ThinkerIterator.Create("Actor");
|
||||
if ( !tr ) tr = new("MidTracer");
|
||||
t.Reinit();
|
||||
|
|
@ -510,11 +552,11 @@ Class RedeemerHUD : HUDMessageBase
|
|||
{
|
||||
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)) || (tdir.length() > 2000) || (acos(tdir.unit() dot vdir) > players[consoleplayer].FOV) || tr.Trace(ViewPos,Camera.CurSector,tdir.unit(),tdir.length(),0) ) continue;
|
||||
Vector3 wpos = ViewPos+tdir;
|
||||
Vector3 spos = dt_CoordUtil.WorldToScreen(wpos,ViewPos,ViewPitch,ViewAngle,ViewRoll,players[consoleplayer].FOV);
|
||||
if ( spos.z > 1.0 ) continue;
|
||||
proj.ProjectWorldPos(ViewPos+tdir);
|
||||
Vector2 npos = proj.ProjectToNormal();
|
||||
if ( !proj.IsInFront() ) continue;
|
||||
TargetActor te = new("TargetActor");
|
||||
te.vpos = dt_CoordUtil.ToViewport(spos);
|
||||
te.vpos = viewport.SceneToWindow(npos);
|
||||
te.diststr = String.Format("%f",tdir.length());
|
||||
te.diststr.Replace(".","");
|
||||
ta.Push(te);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue