Completed Chainsaw. Added some extra visual effects. Made various particle effects actor-based.
Removed key replacement classes, turns out this breaks maps.
This commit is contained in:
parent
72eb6ca8d1
commit
eb6c8e1c35
190 changed files with 831 additions and 166 deletions
|
|
@ -37,6 +37,47 @@ Class BioAmmo : Ammo
|
|||
}
|
||||
}
|
||||
|
||||
Class BioSpark : Actor
|
||||
{
|
||||
Default
|
||||
{
|
||||
RenderStyle "Add";
|
||||
Radius 2;
|
||||
Height 0;
|
||||
+NOBLOCKMAP;
|
||||
+FORCEXYBILLBOARD;
|
||||
+MISSILE;
|
||||
+MOVEWITHSECTOR;
|
||||
+THRUACTORS;
|
||||
+ROLLSPRITE;
|
||||
+ROLLCENTER;
|
||||
+NOTELEPORT;
|
||||
BounceType "Doom";
|
||||
BounceFactor 0.5;
|
||||
WallBounceFactor 0.5;
|
||||
Gravity 0.2;
|
||||
Scale 0.04;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
frame = Random[GES](0,4);
|
||||
roll = FRandom[GES](0,360);
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
GBLB # 1 Bright A_FadeOut(FRandom[GES](0.005,0.015));
|
||||
Wait;
|
||||
Death:
|
||||
GBLB # 1 Bright A_FadeOut(FRandom[GES](0.04,0.06));
|
||||
Wait;
|
||||
Dummy:
|
||||
GBLB ABCDE -1;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class BioHitbox : Actor
|
||||
{
|
||||
Default
|
||||
|
|
@ -174,7 +215,8 @@ Class BioGel : Actor
|
|||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (FRandom[GES](-1,1),FRandom[GES](-1,1),FRandom[GES](-1,1)).unit()*FRandom[GES](1,3);
|
||||
A_SpawnParticle("40FF30",SPF_FULLBRIGHT,Random[GES](30,60),FRandom[GES](1.2,2.4),0,0,0,0,pvel.x,pvel.y,pvel.z,0,0,-0.2,3.0);
|
||||
let s = Spawn("BioSpark",pos);
|
||||
s.vel = pvel;
|
||||
}
|
||||
}
|
||||
if ( deadtimer <= -1 ) return;
|
||||
|
|
@ -253,7 +295,8 @@ Class BioGel : Actor
|
|||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (normal+(FRandom[GES](-.8,.8),FRandom[GES](-.8,.8),FRandom[GES](-.8,.8))).unit()*FRandom[GES](3,6);
|
||||
A_SpawnParticle("40FF30",SPF_FULLBRIGHT,Random[GES](30,60),FRandom[GES](1.2,3.6),0,0,0,0,pvel.x,pvel.y,pvel.z,0,0,-0.2,3.0);
|
||||
let s = Spawn("BioSpark",pos);
|
||||
s.vel = pvel;
|
||||
}
|
||||
}
|
||||
action void A_DropDrip()
|
||||
|
|
@ -283,7 +326,8 @@ Class BioGel : Actor
|
|||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (FRandom[GES](-1,1),FRandom[GES](-1,1),FRandom[GES](-1,1)).unit()*FRandom[GES](3,12);
|
||||
A_SpawnParticle("40FF30",SPF_FULLBRIGHT,Random[GES](30,60),FRandom[GES](2.4,6.4),0,0,0,0,pvel.x,pvel.y,pvel.z,0,0,-0.2,3.0);
|
||||
let s = Spawn("BioSpark",pos);
|
||||
s.vel = pvel;
|
||||
}
|
||||
Scale *= 0.5;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,28 +1,133 @@
|
|||
Class SawImpact : Actor
|
||||
{
|
||||
Default
|
||||
{
|
||||
Radius 0.1;
|
||||
Height 0;
|
||||
+NOGRAVITY;
|
||||
+NOCLIP;
|
||||
+DONTSPLASH;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
A_SprayDecal("WallCrack",20);
|
||||
int numpt = Random[Chainsaw](5,10);
|
||||
Vector3 x = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (-x+(FRandom[Chainsaw](-.8,.8),FRandom[Chainsaw](-.8,.8),FRandom[Chainsaw](-.8,.8))).unit()*FRandom[Chainsaw](0.1,1.2);
|
||||
let s = Spawn("UTSmoke",pos);
|
||||
s.vel = pvel;
|
||||
s.SetShade(Color(1,1,1)*Random[Chainsaw](128,192));
|
||||
}
|
||||
numpt = Random[Chainsaw](4,12);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (FRandom[Chainsaw](-1,1),FRandom[Chainsaw](-1,1),FRandom[Chainsaw](-1,1)).unit()*FRandom[Chainsaw](2,8);
|
||||
let s = Spawn("UTSpark",pos);
|
||||
s.vel = pvel;
|
||||
}
|
||||
numpt = Random[Chainsaw](4,8);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (FRandom[Chainsaw](-1,1),FRandom[Chainsaw](-1,1),FRandom[Chainsaw](-1,1)).unit()*FRandom[Chainsaw](2,8);
|
||||
let s = Spawn("UTChip",pos);
|
||||
s.vel = pvel;
|
||||
}
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
Class UTChainsaw : UTWeapon replaces Chainsaw
|
||||
{
|
||||
double sawcnt;
|
||||
|
||||
action void A_SawHit()
|
||||
{
|
||||
A_QuakeEx(3,3,3,2,0,1,"",QF_RELATIVE,rollIntensity:0.15);
|
||||
A_QuakeEx(2,2,2,2,0,1,"",QF_RELATIVE,rollIntensity:0.15);
|
||||
invoker.sawcnt += 1./TICRATE;
|
||||
if ( invoker.sawcnt < 0.15 ) return;
|
||||
invoker.sawcnt = 0;
|
||||
invoker.FireEffect();
|
||||
A_AlertMonsters();
|
||||
Vector3 x, y, z;
|
||||
[x, y, z] = Matrix4.GetAxes(pitch,angle,roll);
|
||||
Vector3 origin = (pos.x,pos.y,player.viewz)+10.0*x-4.0*z;
|
||||
FLineTraceData d;
|
||||
LineTrace(angle,90,BulletSlope(),TRF_ABSPOSITION,origin.z,origin.x,origin.y,d);
|
||||
if ( d.HitType == TRACE_HitActor )
|
||||
{
|
||||
d.HitActor.DamageMobj(invoker,self,20,'slashed');
|
||||
d.HitActor.vel -= x*(500/d.HitActor.mass);
|
||||
vel += x*(100/mass);
|
||||
if ( d.HitActor.player ) d.HitActor.A_QuakeEx(5,5,5,6,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.25);
|
||||
if ( d.HitActor.bNOBLOOD )
|
||||
{
|
||||
let p = Spawn("SawImpact",d.HitLocation-d.HitDir*4);
|
||||
p.angle = atan2(d.HitDir.y,d.HitDir.x);
|
||||
p.pitch = asin(-d.HitDir.z);
|
||||
}
|
||||
else
|
||||
{
|
||||
d.HitActor.TraceBleed(20,invoker);
|
||||
d.HitActor.SpawnBlood(d.HitLocation,atan2(-d.HitDir.y,-d.HitDir.x),20);
|
||||
}
|
||||
}
|
||||
else if ( d.HitType != TRACE_HitNone )
|
||||
{
|
||||
let p = Spawn("SawImpact",d.HitLocation-d.HitDir*4);
|
||||
p.angle = atan2(d.HitDir.y,d.HitDir.x);
|
||||
p.pitch = asin(-d.HitDir.z);
|
||||
if ( d.HitType == TRACE_HitWall ) d.HitLine.RemoteActivate(self,d.LineSide,SPAC_Impact,d.HitLocation-d.HitDir*4);
|
||||
}
|
||||
}
|
||||
action void A_SawSwipe()
|
||||
{
|
||||
A_QuakeEx(3,3,3,3,0,1,"",QF_RELATIVE,rollIntensity:0.15);
|
||||
A_QuakeEx(2,2,2,3,0,1,"",QF_RELATIVE,rollIntensity:0.15);
|
||||
invoker.FireEffect();
|
||||
A_AlertMonsters();
|
||||
Vector3 x, y, z;
|
||||
[x, y, z] = Matrix4.GetAxes(pitch,angle,roll);
|
||||
Vector3 origin = (pos.x,pos.y,player.viewz)+10.0*x-2.0*z;
|
||||
FLineTraceData d;
|
||||
LineTrace(angle,90,BulletSlope(),TRF_ABSPOSITION,origin.z,origin.x,origin.y,d);
|
||||
if ( d.HitType == TRACE_HitActor )
|
||||
{
|
||||
d.HitActor.DamageMobj(invoker,self,110,'Decapitated');
|
||||
d.HitActor.vel = -y*(1200/d.HitActor.mass);
|
||||
vel += x*(100/mass);
|
||||
if ( d.HitActor.player ) d.HitActor.A_QuakeEx(5,5,5,6,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.25);
|
||||
if ( d.HitActor.bNOBLOOD )
|
||||
{
|
||||
let p = Spawn("SawImpact",d.HitLocation-d.HitDir*4);
|
||||
p.angle = atan2(d.HitDir.y,d.HitDir.x);
|
||||
p.pitch = asin(-d.HitDir.z);
|
||||
}
|
||||
else
|
||||
{
|
||||
d.HitActor.TraceBleed(110,invoker);
|
||||
d.HitActor.SpawnBlood(d.HitLocation,atan2(-d.HitDir.y,-d.HitDir.x),110);
|
||||
}
|
||||
}
|
||||
else if ( d.HitType != TRACE_HitNone )
|
||||
{
|
||||
let p = Spawn("SawImpact",d.HitLocation-d.HitDir*4);
|
||||
p.angle = atan2(d.HitDir.y,d.HitDir.x);
|
||||
p.pitch = asin(-d.HitDir.z);
|
||||
if ( d.HitType == TRACE_HitWall ) d.HitLine.RemoteActivate(self,d.LineSide,SPAC_Impact,d.HitLocation-d.HitDir*4);
|
||||
}
|
||||
}
|
||||
Default
|
||||
{
|
||||
Tag "Chainsaw";
|
||||
Obituary "%k ripped into %o with a blood soaked Chainsaw.";
|
||||
Inventory.PickupMessage "It's been twenty five years since I've seen one of these."; // was five years in UT99
|
||||
Weapon.UpSound "chainsaw/select";
|
||||
Weapon.SlotNumber 1;
|
||||
Weapon.SelectionOrder 9;
|
||||
+WEAPON.MELEEWEAPON;
|
||||
+FORCEPAIN;
|
||||
}
|
||||
States
|
||||
{
|
||||
|
|
@ -35,18 +140,27 @@ Class UTChainsaw : UTWeapon replaces Chainsaw
|
|||
CSWS A 1 A_Raise(int.max);
|
||||
Wait;
|
||||
Ready:
|
||||
CSWS ABCDEFGHIJLMNO 1 A_QuakeEx(1,1,1,2,0,1,"",QF_RELATIVE,rollIntensity:0.1);
|
||||
CSWS ABCDEFGHIJLMNO 1
|
||||
{
|
||||
A_AlertMonsters();
|
||||
A_QuakeEx(1,1,1,2,0,1,"",QF_RELATIVE,rollIntensity:0.1);
|
||||
}
|
||||
Idle:
|
||||
CSWI A 0 A_PlaySound("chainsaw/idle",CHAN_6,looping:true);
|
||||
CSWI ABCDEFGHIJ 1
|
||||
{
|
||||
A_AlertMonsters();
|
||||
A_WeaponReady();
|
||||
A_QuakeEx(1,1,1,2,0,1,"",QF_RELATIVE,rollIntensity:0.1);
|
||||
}
|
||||
Goto Idle+1;
|
||||
Fire:
|
||||
CSWJ A 1 A_PlaySound("chainsaw/fire",CHAN_6,looping:true);
|
||||
CSWJ BCDEF 1 A_QuakeEx(1,1,1,2,0,1,"",QF_RELATIVE,rollIntensity:0.1);
|
||||
CSWJ BCDEF 1
|
||||
{
|
||||
A_AlertMonsters();
|
||||
A_QuakeEx(1,1,1,2,0,1,"",QF_RELATIVE,rollIntensity:0.1);
|
||||
}
|
||||
Hold:
|
||||
CSWJ G 1 A_SawHit();
|
||||
CSWJ H 0 A_Refire(1);
|
||||
|
|
@ -87,13 +201,25 @@ Class UTChainsaw : UTWeapon replaces Chainsaw
|
|||
CSWJ S 1 A_SawHit();
|
||||
CSWJ G 0 A_Refire("Hold");
|
||||
Release:
|
||||
CSWJ FEDCBA 1 A_QuakeEx(1,1,1,2,0,1,"",QF_RELATIVE,rollIntensity:0.1);
|
||||
CSWJ FEDCBA 1
|
||||
{
|
||||
A_AlertMonsters();
|
||||
A_QuakeEx(1,1,1,2,0,1,"",QF_RELATIVE,rollIntensity:0.1);
|
||||
}
|
||||
Goto Idle;
|
||||
AltFire:
|
||||
CSWA A 0 A_PlaySound("chainsaw/fire",CHAN_6);
|
||||
CSWA ABCDEFG 2 A_QuakeEx(3,3,3,3,0,1,"",QF_RELATIVE,rollIntensity:0.15);
|
||||
CSWA ABCDEFG 2
|
||||
{
|
||||
A_AlertMonsters();
|
||||
A_QuakeEx(2,2,2,3,0,1,"",QF_RELATIVE,rollIntensity:0.15);
|
||||
}
|
||||
CSWA H 2 A_SawSwipe();
|
||||
CSWA IJK 2 A_QuakeEx(3,3,3,3,0,1,"",QF_RELATIVE,rollIntensity:0.15);
|
||||
CSWA IJK 2
|
||||
{
|
||||
A_AlertMonsters();
|
||||
A_QuakeEx(2,2,2,3,0,1,"",QF_RELATIVE,rollIntensity:0.15);
|
||||
}
|
||||
CSWA K 0 A_PlaySound("chainsaw/idle",CHAN_6,looping:true);
|
||||
Goto Ready;
|
||||
Deselect:
|
||||
|
|
|
|||
|
|
@ -194,7 +194,19 @@ Class FlakChunk : Actor
|
|||
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 ( (waterlevel <= 0) && (frame < 10) )
|
||||
{
|
||||
let s = Spawn("UTSmoke",pos);
|
||||
s.vel = (FRandom[Flak](-0.1,0.1),FRandom[Flak](-0.1,0.1),FRandom[Flak](-0.1,0.1));
|
||||
s.alpha = scale.x/0.5;
|
||||
s.SetShade("AAAAAA");
|
||||
}
|
||||
else if ( waterlevel > 0 )
|
||||
{
|
||||
let s = Spawn("UTBubble",pos);
|
||||
s.vel = (FRandom[Flak](-0.1,0.1),FRandom[Flak](-0.1,0.1),FRandom[Flak](-0.1,0.1));
|
||||
s.scale *= scale.x*0.5;
|
||||
}
|
||||
if ( trail ) trail.alpha = max(0,11-frame)/11.;
|
||||
if ( InStateSequence(CurState,FindState("Death")) ) return;
|
||||
A_SetRoll(roll+rollvel,SPF_INTERPOLATE);
|
||||
|
|
@ -205,11 +217,15 @@ Class FlakChunk : Actor
|
|||
{
|
||||
invoker.hasbounced = true;
|
||||
A_SprayDecal("WallCrack",-8);
|
||||
int numpt = Random[Flak](8,12);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
int numpt = Random[Flak](3,6);
|
||||
if ( frame < 10 )
|
||||
{
|
||||
Vector3 pvel = (FRandom[Flak](-1,1),FRandom[Flak](-1,1),FRandom[Flak](-1,1)).unit()*FRandom[Flak](2,4);
|
||||
A_SpawnParticle("FFA000",SPF_FULLBRIGHT,Random[Flak](10,20),FRandom[Flak](1.2,3.6),0,0,0,0,pvel.x,pvel.y,pvel.z,0,0,0,3.0,-1,-0.25);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (FRandom[Flak](-1,1),FRandom[Flak](-1,1),FRandom[Flak](-1,1)).unit()*FRandom[Flak](2,4);
|
||||
let s = Spawn("UTSpark",pos);
|
||||
s.vel = pvel;
|
||||
}
|
||||
}
|
||||
A_Gravity();
|
||||
invoker.rollvel = FRandom[Flak](50,100)*RandomPick[Flak](-1,1)*(vel.length()/speed);
|
||||
|
|
@ -301,7 +317,11 @@ Class SlugSmoke : Actor
|
|||
Super.Tick();
|
||||
if ( globalfreeze || level.frozen ) return;
|
||||
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);
|
||||
let s = Spawn("UTSmoke",pos);
|
||||
s.vel = (FRandom[Flak](-0.5,0.5),FRandom[Flak](-0.5,0.5),FRandom[Flak](-0.5,0.5));
|
||||
s.vel.z += 2.;
|
||||
s.alpha = scale.x;
|
||||
s.SetShade("AAAAAA");
|
||||
scale.x = max(0,1-lifetime);
|
||||
if ( scale.x <= 0 ) Destroy();
|
||||
}
|
||||
|
|
@ -399,11 +419,19 @@ Class FlakSlug : Actor
|
|||
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;
|
||||
}
|
||||
int numpt = Random[Flak](40,80);
|
||||
int numpt = Random[Flak](10,20);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (FRandom[Flak](-1,1),FRandom[Flak](-1,1),FRandom[Flak](-1,1)).unit()*FRandom[Flak](2,4);
|
||||
A_SpawnParticle("FFA000",SPF_FULLBRIGHT,Random[Flak](20,40),FRandom[Flak](4.8,7.2),0,0,0,0,pvel.x,pvel.y,pvel.z,0,0,0,3.0,-1,-0.25);
|
||||
Vector3 pvel = (FRandom[Flak](-1,1),FRandom[Flak](-1,1),FRandom[Flak](-1,1)).unit()*FRandom[Flak](2,8);
|
||||
let s = Spawn("UTSpark",pos);
|
||||
s.vel = pvel;
|
||||
}
|
||||
numpt = Random[Flak](20,40);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (FRandom[Flak](-1,1),FRandom[Flak](-1,1),FRandom[Flak](-1,1)).unit()*FRandom[Flak](2,8);
|
||||
let s = Spawn("UTChip",pos);
|
||||
s.vel = pvel;
|
||||
}
|
||||
}
|
||||
States
|
||||
|
|
@ -411,9 +439,13 @@ Class FlakSlug : Actor
|
|||
Spawn:
|
||||
FSLG A 1
|
||||
{
|
||||
if ( waterlevel > 0 ) return;
|
||||
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);
|
||||
{
|
||||
let s = Spawn("UTSmoke",pos);
|
||||
s.vel = (FRandom[Flak](-0.5,0.5),FRandom[Flak](-0.5,0.5),FRandom[Flak](-0.5,0.5));
|
||||
s.alpha = 0.5;
|
||||
s.SetShade("AAAAAA");
|
||||
}
|
||||
}
|
||||
Wait;
|
||||
Death:
|
||||
|
|
@ -493,8 +525,10 @@ Class FlakCannon : UTWeapon
|
|||
int numpt = Random[Flak](20,30);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (x+(FRandom[Flak](-.8,.8),FRandom[Flak](-.8,.8),FRandom[Flak](-.8,.8))).unit()*FRandom[Flak](2,4);
|
||||
A_SpawnParticle("FFA000",SPF_FULLBRIGHT,Random[Flak](10,20),FRandom[Flak](2.4,3.6),0,origin.x-pos.x,origin.y-pos.y,origin.z-pos.z,pvel.x,pvel.y,pvel.z,0,0,-0.1,3.0,-1,-0.25);
|
||||
Vector3 pvel = (x+(FRandom[Flak](-.8,.8),FRandom[Flak](-.8,.8),FRandom[Flak](-.8,.8))).unit()*FRandom[Flak](8,32);
|
||||
let s = Spawn("UTSpark",origin);
|
||||
s.vel = pvel;
|
||||
s.alpha *= 0.2;
|
||||
}
|
||||
}
|
||||
action void A_FireSlug()
|
||||
|
|
@ -523,8 +557,10 @@ Class FlakCannon : UTWeapon
|
|||
int numpt = Random[Flak](10,15);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (x+(FRandom[Flak](-.8,.8),FRandom[Flak](-.8,.8),FRandom[Flak](-.8,.8))).unit()*FRandom[Flak](2,4);
|
||||
A_SpawnParticle("FFA000",SPF_FULLBRIGHT,Random[Flak](10,20),FRandom[Flak](2.4,3.6),0,origin.x-pos.x,origin.y-pos.y,origin.z-pos.z,pvel.x,pvel.y,pvel.z,0,0,-0.1,3.0,-1,-0.25);
|
||||
Vector3 pvel = (x+(FRandom[Flak](-.8,.8),FRandom[Flak](-.8,.8),FRandom[Flak](-.8,.8))).unit()*FRandom[Flak](8,32);
|
||||
let s = Spawn("UTSpark",origin);
|
||||
s.vel = pvel;
|
||||
s.alpha *= 0.2;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,14 +16,24 @@ Class HammerImpact : Actor
|
|||
Vector3 x = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (x+(FRandom[Impact](-.8,.8),FRandom[Impact](-.8,.8),FRandom[Impact](-.8,.8))).unit()*FRandom[Impact](1,3);
|
||||
A_SpawnParticle(Color(1,1,1)*Random[Impact](128,192),0,Random[Impact](30,60),FRandom[Impact](2,8),0,0,0,0,pvel.x,pvel.y,pvel.z,0,0,0.03,0.5,-1,0.5);
|
||||
Vector3 pvel = (-x+(FRandom[Impact](-.8,.8),FRandom[Impact](-.8,.8),FRandom[Impact](-.8,.8))).unit()*FRandom[Impact](0.1,1.2);
|
||||
let s = Spawn("UTSmoke",pos);
|
||||
s.vel = pvel;
|
||||
s.SetShade(Color(1,1,1)*Random[Impact](128,192));
|
||||
}
|
||||
numpt = Random[Impact](8,12);
|
||||
numpt = Random[Impact](4,12);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (FRandom[Impact](-1,1),FRandom[Impact](-1,1),FRandom[Impact](-1,1)).unit()*FRandom[Impact](2,4);
|
||||
A_SpawnParticle("FFA000",SPF_FULLBRIGHT,Random[Impact](10,20),FRandom[Impact](1.2,3.6),0,0,0,0,pvel.x,pvel.y,pvel.z,0,0,0,3.0,-1,-0.25);
|
||||
Vector3 pvel = (FRandom[Impact](-1,1),FRandom[Impact](-1,1),FRandom[Impact](-1,1)).unit()*FRandom[Impact](2,8);
|
||||
let s = Spawn("UTSpark",pos);
|
||||
s.vel = pvel;
|
||||
}
|
||||
numpt = Random[Impact](4,16);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (FRandom[Impact](-1,1),FRandom[Impact](-1,1),FRandom[Impact](-1,1)).unit()*FRandom[Impact](2,8);
|
||||
let s = Spawn("UTChip",pos);
|
||||
s.vel = pvel;
|
||||
}
|
||||
Destroy();
|
||||
}
|
||||
|
|
@ -92,17 +102,21 @@ Class ImpactHammer : UTWeapon replaces Fist
|
|||
}
|
||||
A_QuakeEx(realcharge*6,realcharge*6,realcharge*6,16,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:realcharge*0.2);
|
||||
realcharge = max(1.0,realcharge);
|
||||
int numpt = Random[Impact](20,40);
|
||||
int numpt = Random[Impact](5,10);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (x+(FRandom[Impact](-.4,.4),FRandom[Impact](-.4,.4),FRandom[Impact](-.4,.4))).unit()*FRandom[Impact](1,3)*realcharge;
|
||||
A_SpawnParticle(Color(1,1,1)*Random[Impact](128,192),0,Random[Impact](30,60),FRandom[Impact](2,8),0,origin.x-pos.x,origin.y-pos.y,origin.z-pos.z,pvel.x,pvel.y,pvel.z,0,0,0.03,0.5,-1,0.5);
|
||||
let s = Spawn("UTSmoke",origin);
|
||||
s.vel = pvel;
|
||||
s.SetShade(Color(1,1,1)*Random[Impact](128,192));
|
||||
}
|
||||
numpt = Random[Impact](10,20);
|
||||
numpt = Random[Impact](4,8);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (x+(FRandom[Impact](-.5,.5),FRandom[Impact](-.5,.5),FRandom[Impact](-.5,.5))).unit()*FRandom[Impact](2,4)*realcharge;
|
||||
A_SpawnParticle(Color(1,1,1)*Random[Impact](16,64),0,Random[Impact](5,10),FRandom[Impact](0.3,0.8),0,origin.x-pos.x,origin.y-pos.y,origin.z-pos.z,pvel.x,pvel.y,pvel.z,0,0,-0.2,2.,-0.1);
|
||||
Vector3 pvel = (x+(FRandom[Impact](-.5,.5),FRandom[Impact](-.5,.5),FRandom[Impact](-.5,.5))).unit()*FRandom[Impact](2,16)*realcharge;
|
||||
let s = Spawn("UTChip",origin);
|
||||
s.vel = pvel;
|
||||
s.scale *= 0.4;
|
||||
}
|
||||
}
|
||||
action void A_FireAltBlast()
|
||||
|
|
@ -146,17 +160,21 @@ Class ImpactHammer : UTWeapon replaces Fist
|
|||
if ( m.bSEEKERMISSILE ) m.tracer = m.target;
|
||||
m.target = self;
|
||||
}
|
||||
int numpt = Random[Impact](20,40);
|
||||
int numpt = Random[Impact](5,10);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (x+(FRandom[Impact](-.4,.4),FRandom[Impact](-.4,.4),FRandom[Impact](-.4,.4))).unit()*FRandom[Impact](1,3);
|
||||
A_SpawnParticle(Color(1,1,1)*Random[Impact](128,192),0,Random[Impact](30,60),FRandom[Impact](2,8),0,origin.x-pos.x,origin.y-pos.y,origin.z-pos.z,pvel.x,pvel.y,pvel.z,0,0,0.03,0.5,-1,0.5);
|
||||
let s = Spawn("UTSmoke",origin);
|
||||
s.vel = pvel;
|
||||
s.SetShade(Color(1,1,1)*Random[Impact](128,192));
|
||||
}
|
||||
numpt = Random[Impact](10,20);
|
||||
numpt = Random[Impact](4,8);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (x+(FRandom[Impact](-.5,.5),FRandom[Impact](-.5,.5),FRandom[Impact](-.5,.5))).unit()*FRandom[Impact](2,4);
|
||||
A_SpawnParticle(Color(1,1,1)*Random[Impact](16,64),0,Random[Impact](5,10),FRandom[Impact](0.3,0.8),0,origin.x-pos.x,origin.y-pos.y,origin.z-pos.z,pvel.x,pvel.y,pvel.z,0,0,-0.2,2.,-0.1);
|
||||
Vector3 pvel = (x+(FRandom[Impact](-.5,.5),FRandom[Impact](-.5,.5),FRandom[Impact](-.5,.5))).unit()*FRandom[Impact](2,16);
|
||||
let s = Spawn("UTChip",origin);
|
||||
s.vel = pvel;
|
||||
s.scale *= 0.4;
|
||||
}
|
||||
}
|
||||
action void A_ImpactRefire( statelabel flash = null )
|
||||
|
|
@ -261,6 +279,7 @@ Class ImpactHammer : UTWeapon replaces Fist
|
|||
IMPF ABCDEFGHIJKLMNOP 1;
|
||||
Goto Idle;
|
||||
Deselect:
|
||||
IMPD A 0 A_StopSound(CHAN_WEAPON);
|
||||
IMPD ABCDE 3;
|
||||
IMPD E 1 A_Lower(int.max);
|
||||
Wait;
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ Class DamageAmpLight : DynamicLight
|
|||
Destroy();
|
||||
return;
|
||||
}
|
||||
SetOrigin(target.pos+(0,0,target.height*0.5),true);
|
||||
SetOrigin(target.pos,true);
|
||||
args[LIGHT_INTENSITY] = Random[ASMD](10,12)*8;
|
||||
bDORMANT = Powerup(master).isBlinking();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -537,6 +537,7 @@ Class PulseGun : UTWeapon
|
|||
PGR2 ABCDEFGHIJKLMNOPQRSTUVWX 1;
|
||||
Goto Idle;
|
||||
Deselect:
|
||||
PGNS W 0 A_StopSound(CHAN_WEAPON);
|
||||
PGNS WVUTSRQPONMLKJIHGFEDCBA 1;
|
||||
PGNS A 1 A_Lower(int.max);
|
||||
Wait;
|
||||
|
|
|
|||
|
|
@ -178,6 +178,70 @@ Class SuperShockBlastRing : ShockBeamRing
|
|||
}
|
||||
}
|
||||
|
||||
Class ShockSpark : Actor
|
||||
{
|
||||
Default
|
||||
{
|
||||
RenderStyle "Add";
|
||||
Radius 2;
|
||||
Height 0;
|
||||
+NOBLOCKMAP;
|
||||
+NOGRAVITY;
|
||||
+MISSILE;
|
||||
+FORCEXYBILLBOARD;
|
||||
+THRUACTORS;
|
||||
+ROLLSPRITE;
|
||||
+ROLLCENTER;
|
||||
+NOTELEPORT;
|
||||
BounceType "Doom";
|
||||
BounceFactor 1.0;
|
||||
WallBounceFactor 1.0;
|
||||
Scale 0.1;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
if ( !bAMBUSH )
|
||||
{
|
||||
roll = FRandom[ASMD](0,360);
|
||||
let s = Spawn(GetClass(),pos);
|
||||
s.bAMBUSH = true;
|
||||
s.vel = vel;
|
||||
s.scale = scale;
|
||||
s.roll = roll;
|
||||
}
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
ASMK A 1 Bright
|
||||
{
|
||||
A_FadeOut(FRandom[ASMD](0.0,0.1));
|
||||
vel *= 0.98;
|
||||
}
|
||||
Wait;
|
||||
}
|
||||
}
|
||||
|
||||
Class ShockSparkTrail : ShockSpark
|
||||
{
|
||||
Default
|
||||
{
|
||||
+AMBUSH;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
roll = FRandom[ASMD](0,360);
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
ASMK A 1 Bright A_FadeOut(FRandom[ASMD](0.0,0.2));
|
||||
Wait;
|
||||
}
|
||||
}
|
||||
|
||||
Class ShockBeam : Actor
|
||||
{
|
||||
ShockBeamTracer t;
|
||||
|
|
@ -220,10 +284,9 @@ Class ShockBeam : Actor
|
|||
Spawn("ShockBeamLight",Vec3Offset(tracedir.x*i,tracedir.y*i,tracedir.z*i));
|
||||
for ( int i=0; i<t.Results.Distance; i+=2 )
|
||||
{
|
||||
Vector3 pofs = Level.Vec3Diff(pos,pos+tracedir*FRandom[ASMD](0,2)+(FRandom[ASMD](-.5,.5),FRandom[ASMD](-.5,.5),FRandom[ASMD](-.5,.5)));
|
||||
A_SpawnParticle("FFFFFF",SPF_FULLBRIGHT,30,2,0,tracedir.x*i+pofs.x,tracedir.y*i+pofs.y,tracedir.z*i+pofs.z,FRandom[ASMD](-.03,.03),FRandom[ASMD](-.03,.03),FRandom[ASMD](-.03,.03),startalphaf:1,sizestep:-.1);
|
||||
A_SpawnParticle("5020FF",SPF_FULLBRIGHT,45,4,0,tracedir.x*i+pofs.x,tracedir.y*i+pofs.y,tracedir.z*i+pofs.z,FRandom[ASMD](-.03,.03),FRandom[ASMD](-.03,.03),FRandom[ASMD](-.03,.03),startalphaf:.5,sizestep:-.1);
|
||||
A_SpawnParticle("402080",SPF_FULLBRIGHT,60,8,0,tracedir.x*i+pofs.x,tracedir.y*i+pofs.y,tracedir.z*i+pofs.z,FRandom[ASMD](-.03,.03),FRandom[ASMD](-.03,.03),FRandom[ASMD](-.03,.03),startalphaf:.25,sizestep:-.1);
|
||||
Vector3 pofs = tracedir*FRandom[ASMD](0,2)+(FRandom[ASMD](-.5,.5),FRandom[ASMD](-.5,.5),FRandom[ASMD](-.5,.5));
|
||||
let s = Spawn("ShockSparkTrail",Vec3Offset(tracedir.x*i+pofs.x,tracedir.y*i+pofs.y,tracedir.z*i+pofs.z));
|
||||
s.vel = (FRandom[ASMD](-.03,.03),FRandom[ASMD](-.03,.03),FRandom[ASMD](-.03,.03));
|
||||
}
|
||||
if ( totaldist >= 10000.0 )
|
||||
{
|
||||
|
|
@ -265,10 +328,9 @@ Class ShockBeam : Actor
|
|||
int numpt = Random[ASMD](200,300);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (FRandom[ASMD](-1,1),FRandom[ASMD](-1,1),FRandom[ASMD](-1,1)).unit()*FRandom[ASMD](2,8);
|
||||
A_SpawnParticle("FFFFFF",SPF_FULLBRIGHT,Random[ASMD](20,80),FRandom[ASMD](1.6,4.8),0,0,0,0,pvel.x,pvel.y,pvel.z,0,0,0,1,-1,-.05);
|
||||
A_SpawnParticle("5020FF",SPF_FULLBRIGHT,Random[ASMD](40,120),FRandom[ASMD](4.8,11.2),0,0,0,0,pvel.x,pvel.y,pvel.z,0,0,0,.5,-1,-.05);
|
||||
A_SpawnParticle("402080",SPF_FULLBRIGHT,Random[ASMD](50,140),FRandom[ASMD](5.6,12.8),0,0,0,0,pvel.x,pvel.y,pvel.z,0,0,0,.25,-1,-.05);
|
||||
Vector3 pvel = (FRandom[ASMD](-1,1),FRandom[ASMD](-1,1),FRandom[ASMD](-1,1)).unit()*FRandom[ASMD](1,32);
|
||||
let s = Spawn("ShockSpark",b.pos);
|
||||
s.vel = pvel;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -314,9 +376,8 @@ Class ShockBeam : Actor
|
|||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (FRandom[ASMD](-1,1),FRandom[ASMD](-1,1),FRandom[ASMD](-1,1)).unit()*FRandom[ASMD](3,12);
|
||||
A_SpawnParticle("FFFFFF",SPF_FULLBRIGHT,Random[ASMD](20,40),FRandom[ASMD](1.6,2.4),0,0,0,0,pvel.x,pvel.y,pvel.z,0,0,0,1,-1,-.1);
|
||||
A_SpawnParticle("5020FF",SPF_FULLBRIGHT,Random[ASMD](40,60),FRandom[ASMD](4.8,5.6),0,0,0,0,pvel.x,pvel.y,pvel.z,0,0,0,.5,-1,-.1);
|
||||
A_SpawnParticle("402080",SPF_FULLBRIGHT,Random[ASMD](50,70),FRandom[ASMD](5.6,6.4),0,0,0,0,pvel.x,pvel.y,pvel.z,0,0,0,.25,-1,-.1);
|
||||
let s = Spawn("ShockSpark",pos);
|
||||
s.vel = pvel;
|
||||
}
|
||||
}
|
||||
States
|
||||
|
|
@ -332,6 +393,70 @@ Class ShockBeam : Actor
|
|||
}
|
||||
}
|
||||
|
||||
Class SuperShockSpark : Actor
|
||||
{
|
||||
Default
|
||||
{
|
||||
RenderStyle "Add";
|
||||
Radius 2;
|
||||
Height 0;
|
||||
+NOBLOCKMAP;
|
||||
+NOGRAVITY;
|
||||
+MISSILE;
|
||||
+FORCEXYBILLBOARD;
|
||||
+THRUACTORS;
|
||||
+ROLLSPRITE;
|
||||
+ROLLCENTER;
|
||||
+NOTELEPORT;
|
||||
BounceType "Doom";
|
||||
BounceFactor 1.0;
|
||||
WallBounceFactor 1.0;
|
||||
Scale 0.1;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
if ( !bAMBUSH )
|
||||
{
|
||||
roll = FRandom[ASMD](0,360);
|
||||
let s = Spawn(GetClass(),pos);
|
||||
s.bAMBUSH = true;
|
||||
s.vel = vel;
|
||||
s.scale = scale;
|
||||
s.roll = roll;
|
||||
}
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
SSMK A 1 Bright
|
||||
{
|
||||
A_FadeOut(FRandom[ASMD](0.0,0.1));
|
||||
vel *= 0.98;
|
||||
}
|
||||
Wait;
|
||||
}
|
||||
}
|
||||
|
||||
Class SuperShockSparkTrail : ShockSpark
|
||||
{
|
||||
Default
|
||||
{
|
||||
+AMBUSH;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
roll = FRandom[ASMD](0,360);
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
SSMK A 1 Bright A_FadeOut(FRandom[ASMD](0.0,0.2));
|
||||
Wait;
|
||||
}
|
||||
}
|
||||
|
||||
Class SuperShockBeam : Actor
|
||||
{
|
||||
ShockBeamTracer t;
|
||||
|
|
@ -375,10 +500,9 @@ Class SuperShockBeam : Actor
|
|||
Spawn("SuperShockBeamLight",Vec3Offset(tracedir.x*i,tracedir.y*i,tracedir.z*i));
|
||||
for ( int i=0; i<t.Results.Distance; i++ )
|
||||
{
|
||||
Vector3 pofs = Level.Vec3Diff(pos,pos+tracedir*FRandom[ASMD](0,1)+(FRandom[ASMD](-.5,.5),FRandom[ASMD](-.5,.5),FRandom[ASMD](-.5,.5)));
|
||||
A_SpawnParticle("FFF080",SPF_FULLBRIGHT,30,2,0,tracedir.x*i+pofs.x,tracedir.y*i+pofs.y,tracedir.z*i+pofs.z,FRandom[ASMD](-.03,.03),FRandom[ASMD](-.03,.03),FRandom[ASMD](-.03,.03),startalphaf:1,sizestep:-.1);
|
||||
A_SpawnParticle("FF5020",SPF_FULLBRIGHT,45,4,0,tracedir.x*i+pofs.x,tracedir.y*i+pofs.y,tracedir.z*i+pofs.z,FRandom[ASMD](-.03,.03),FRandom[ASMD](-.03,.03),FRandom[ASMD](-.03,.03),startalphaf:.5,sizestep:-.1);
|
||||
A_SpawnParticle("804020",SPF_FULLBRIGHT,60,8,0,tracedir.x*i+pofs.x,tracedir.y*i+pofs.y,tracedir.z*i+pofs.z,FRandom[ASMD](-.03,.03),FRandom[ASMD](-.03,.03),FRandom[ASMD](-.03,.03),startalphaf:.25,sizestep:-.1);
|
||||
Vector3 pofs = tracedir*FRandom[ASMD](0,2)+(FRandom[ASMD](-.5,.5),FRandom[ASMD](-.5,.5),FRandom[ASMD](-.5,.5));
|
||||
let s = Spawn("SuperShockSparkTrail",Vec3Offset(tracedir.x*i+pofs.x,tracedir.y*i+pofs.y,tracedir.z*i+pofs.z));
|
||||
s.vel = (FRandom[ASMD](-.03,.03),FRandom[ASMD](-.03,.03),FRandom[ASMD](-.03,.03));
|
||||
}
|
||||
if ( totaldist >= 10000.0 )
|
||||
{
|
||||
|
|
@ -418,13 +542,12 @@ Class SuperShockBeam : Actor
|
|||
r.pitch = asin(-t.Results.HitVector.z);
|
||||
A_PlaySound("shock/blast",CHAN_WEAPON,attenuation:0.5);
|
||||
A_PlaySound("sshock/blast",CHAN_6,attenuation:0.5);
|
||||
int numpt = Random[ASMD](400,600);
|
||||
int numpt = Random[ASMD](200,300);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (FRandom[ASMD](-1,1),FRandom[ASMD](-1,1),FRandom[ASMD](-1,1)).unit()*FRandom[ASMD](2,8);
|
||||
A_SpawnParticle("FFF080",SPF_FULLBRIGHT,Random[ASMD](20,80),FRandom[ASMD](1.6,9.6),0,0,0,0,pvel.x,pvel.y,pvel.z,0,0,0,1,-1,-.05);
|
||||
A_SpawnParticle("FF5020",SPF_FULLBRIGHT,Random[ASMD](40,120),FRandom[ASMD](4.8,22.4),0,0,0,0,pvel.x,pvel.y,pvel.z,0,0,0,.5,-1,-.05);
|
||||
A_SpawnParticle("804020",SPF_FULLBRIGHT,Random[ASMD](50,140),FRandom[ASMD](5.6,25.6),0,0,0,0,pvel.x,pvel.y,pvel.z,0,0,0,.25,-1,-.05);
|
||||
Vector3 pvel = (FRandom[ASMD](-1,1),FRandom[ASMD](-1,1),FRandom[ASMD](-1,1)).unit()*FRandom[ASMD](2,64);
|
||||
let s = Spawn("SuperShockSpark",b.pos);
|
||||
s.vel = pvel;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -468,13 +591,12 @@ Class SuperShockBeam : Actor
|
|||
A_PlaySound("shock/hit",CHAN_VOICE,attenuation:0.5);
|
||||
A_PlaySound("sshock/blast",CHAN_6,attenuation:0.5);
|
||||
A_AlertMonsters();
|
||||
int numpt = Random[ASMD](40,100);
|
||||
int numpt = Random[ASMD](20,50);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (FRandom[ASMD](-1,1),FRandom[ASMD](-1,1),FRandom[ASMD](-1,1)).unit()*FRandom[ASMD](3,12);
|
||||
A_SpawnParticle("FFF080",SPF_FULLBRIGHT,Random[ASMD](20,40),FRandom[ASMD](1.6,4.8),0,0,0,0,pvel.x,pvel.y,pvel.z,0,0,0,1,-1,-.1);
|
||||
A_SpawnParticle("FF5020",SPF_FULLBRIGHT,Random[ASMD](40,60),FRandom[ASMD](4.8,11.2),0,0,0,0,pvel.x,pvel.y,pvel.z,0,0,0,.5,-1,-.1);
|
||||
A_SpawnParticle("804020",SPF_FULLBRIGHT,Random[ASMD](50,70),FRandom[ASMD](5.6,12.8),0,0,0,0,pvel.x,pvel.y,pvel.z,0,0,0,.25,-1,-.1);
|
||||
Vector3 pvel = (FRandom[ASMD](-1,1),FRandom[ASMD](-1,1),FRandom[ASMD](-1,1)).unit()*FRandom[ASMD](3,24);
|
||||
let s = Spawn("SuperShockSpark",pos);
|
||||
s.vel = pvel;
|
||||
}
|
||||
}
|
||||
States
|
||||
|
|
@ -683,9 +805,8 @@ Class ShockBall : Actor
|
|||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (FRandom[ASMD](-1,1),FRandom[ASMD](-1,1),FRandom[ASMD](-1,1)).unit()*FRandom[ASMD](3,12);
|
||||
A_SpawnParticle("FFFFFF",SPF_FULLBRIGHT,Random[ASMD](20,40),FRandom[ASMD](1.6,2.4),0,0,0,0,pvel.x,pvel.y,pvel.z,0,0,0,1,-1,-.1);
|
||||
A_SpawnParticle("5020FF",SPF_FULLBRIGHT,Random[ASMD](40,60),FRandom[ASMD](4.8,5.6),0,0,0,0,pvel.x,pvel.y,pvel.z,0,0,0,.5,-1,-.1);
|
||||
A_SpawnParticle("402080",SPF_FULLBRIGHT,Random[ASMD](50,70),FRandom[ASMD](5.6,6.4),0,0,0,0,pvel.x,pvel.y,pvel.z,0,0,0,.25,-1,-.1);
|
||||
let s = Spawn("ShockSpark",pos);
|
||||
s.vel = pvel;
|
||||
}
|
||||
}
|
||||
Default
|
||||
|
|
@ -742,13 +863,12 @@ Class SuperShockBall : Actor
|
|||
A_PlaySound("sshock/blast",CHAN_6,attenuation:0.5);
|
||||
A_QuakeEx(8,8,8,30,0,300,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.25);
|
||||
A_AlertMonsters();
|
||||
int numpt = Random[ASMD](100,200);
|
||||
int numpt = Random[ASMD](50,100);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (FRandom[ASMD](-1,1),FRandom[ASMD](-1,1),FRandom[ASMD](-1,1)).unit()*FRandom[ASMD](3,12);
|
||||
A_SpawnParticle("FFF080",SPF_FULLBRIGHT,Random[ASMD](20,40),FRandom[ASMD](1.6,4.8),0,0,0,0,pvel.x,pvel.y,pvel.z,0,0,0,1,-1,-.1);
|
||||
A_SpawnParticle("FF5020",SPF_FULLBRIGHT,Random[ASMD](40,60),FRandom[ASMD](4.8,11.2),0,0,0,0,pvel.x,pvel.y,pvel.z,0,0,0,.5,-1,-.1);
|
||||
A_SpawnParticle("804020",SPF_FULLBRIGHT,Random[ASMD](50,70),FRandom[ASMD](5.6,12.8),0,0,0,0,pvel.x,pvel.y,pvel.z,0,0,0,.25,-1,-.1);
|
||||
Vector3 pvel = (FRandom[ASMD](-1,1),FRandom[ASMD](-1,1),FRandom[ASMD](-1,1)).unit()*FRandom[ASMD](3,24);
|
||||
let s = Spawn("SuperShockSpark",pos);
|
||||
s.vel = pvel;
|
||||
}
|
||||
}
|
||||
Default
|
||||
|
|
|
|||
|
|
@ -312,87 +312,233 @@ Class UTItemFog : Actor replaces ItemFog
|
|||
}
|
||||
}
|
||||
|
||||
Class UTRedSkull : RedSkull replaces RedSkull
|
||||
Class UTSpark : Actor
|
||||
{
|
||||
Default
|
||||
{
|
||||
Tag "Red Skull";
|
||||
Inventory.PickupMessage "You got the Red Skull.";
|
||||
RenderStyle "Add";
|
||||
Radius 2;
|
||||
Height 0;
|
||||
+NOBLOCKMAP;
|
||||
+FORCEXYBILLBOARD;
|
||||
+MISSILE;
|
||||
+MOVEWITHSECTOR;
|
||||
+THRUACTORS;
|
||||
+NOTELEPORT;
|
||||
BounceType "Doom";
|
||||
BounceFactor 0.4;
|
||||
Gravity 0.5;
|
||||
Scale 0.05;
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
if ( waterlevel > 0 )
|
||||
{
|
||||
let b = Spawn("UTBubble",pos);
|
||||
b.vel = vel;
|
||||
b.scale *= 0.3;
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
USKL A -1;
|
||||
SPRK A 1 Bright A_FadeOut(0.01);
|
||||
Wait;
|
||||
Death:
|
||||
SPRK A 1 Bright A_FadeOut(0.05);
|
||||
Wait;
|
||||
}
|
||||
}
|
||||
|
||||
Class UTChip : Actor
|
||||
{
|
||||
int deadtimer;
|
||||
double rollvel, anglevel, pitchvel;
|
||||
|
||||
Default
|
||||
{
|
||||
Radius 2;
|
||||
Height 0;
|
||||
+NOBLOCKMAP;
|
||||
+MISSILE;
|
||||
+MOVEWITHSECTOR;
|
||||
+THRUACTORS;
|
||||
+NOTELEPORT;
|
||||
BounceType "Doom";
|
||||
BounceFactor 0.3;
|
||||
Gravity 0.7;
|
||||
Scale 0.2;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
deadtimer = 0;
|
||||
anglevel = FRandom[Junk](10,30)*RandomPick[Junk](-1,1);
|
||||
pitchvel = FRandom[Junk](10,30)*RandomPick[Junk](-1,1);
|
||||
rollvel = FRandom[Junk](10,30)*RandomPick[Junk](-1,1);
|
||||
frame = Random[Junk](0,3);
|
||||
scale *= Frandom[Junk](0.8,1.2);
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
if ( level.frozen || globalfreeze ) return;
|
||||
if ( InStateSequence(CurState,ResolveState("Death")) )
|
||||
{
|
||||
deadtimer++;
|
||||
if ( deadtimer > 300 ) A_FadeOut(0.05);
|
||||
return;
|
||||
}
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
CHIP # 1
|
||||
{
|
||||
A_SetAngle(angle+anglevel,SPF_INTERPOLATE);
|
||||
A_SetPitch(pitch+pitchvel,SPF_INTERPOLATE);
|
||||
A_SetRoll(roll+rollvel,SPF_INTERPOLATE);
|
||||
}
|
||||
Loop;
|
||||
Bounce:
|
||||
CHIP # 0
|
||||
{
|
||||
anglevel = FRandom[Junk](10,30)*RandomPick[Junk](-1,1);
|
||||
pitchvel = FRandom[Junk](10,30)*RandomPick[Junk](-1,1);
|
||||
rollvel = FRandom[Junk](10,30)*RandomPick[Junk](-1,1);
|
||||
}
|
||||
Goto Spawn;
|
||||
Death:
|
||||
CHIP # -1;
|
||||
Stop;
|
||||
Dummy:
|
||||
CHIP ABCD -1;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
Class UTGoldSkull : YellowSkull replaces YellowSkull
|
||||
|
||||
Class UTBubble : Actor
|
||||
{
|
||||
Default
|
||||
{
|
||||
Tag "Gold Skull";
|
||||
Inventory.PickupMessage "You got the Gold Skull.";
|
||||
RenderStyle "Add";
|
||||
Radius 2;
|
||||
Height 0;
|
||||
+NOBLOCKMAP;
|
||||
+NOGRAVITY;
|
||||
+DONTSPLASH;
|
||||
+FORCEXYBILLBOARD;
|
||||
+NOTELEPORT;
|
||||
Scale 0.05;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
double ang, pt;
|
||||
scale *= FRandom[Puff](0.5,1.5);
|
||||
ang = FRandom[Puff](0,360);
|
||||
pt = FRandom[Puff](-90,90);
|
||||
vel += (cos(pt)*cos(ang),cos(pt)*sin(ang),-sin(pt))*FRandom[Puff](0.2,0.8);
|
||||
if ( waterlevel <= 0 ) Destroy();
|
||||
SetState(ResolveState("Spawn")+Random[Puff](0,2));
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
if ( level.frozen || globalfreeze ) return;
|
||||
vel *= 0.96;
|
||||
vel.z += 0.05;
|
||||
if ( (waterlevel <= 0) || !Random[Puff](0,100) ) Destroy();
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
USKL B -1;
|
||||
BUBL ABC -1;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
Class UTBlueSkull : BlueSkull replaces BlueSkull
|
||||
|
||||
Class UTSmoke : Actor
|
||||
{
|
||||
Default
|
||||
{
|
||||
Tag "Blue Skull";
|
||||
Inventory.PickupMessage "You got the Blue Skull.";
|
||||
RenderStyle "Shaded";
|
||||
StencilColor "FFFFFF";
|
||||
Radius 2;
|
||||
Height 0;
|
||||
+NOBLOCKMAP;
|
||||
+NOGRAVITY;
|
||||
+DONTSPLASH;
|
||||
+FORCEXYBILLBOARD;
|
||||
+THRUACTORS;
|
||||
+NOTELEPORT;
|
||||
BounceType "Hexen";
|
||||
BounceFactor 1.0;
|
||||
WallBounceFactor 1.0;
|
||||
Scale 0.5;
|
||||
}
|
||||
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
double ang, pt;
|
||||
scale *= FRandom[Puff](0.5,1.5);
|
||||
alpha *= FRandom[Puff](0.5,1.5);
|
||||
ang = FRandom[Puff](0,360);
|
||||
pt = FRandom[Puff](-90,90);
|
||||
vel += (cos(pt)*cos(ang),cos(pt)*sin(ang),-sin(pt))*FRandom[Puff](0.2,0.8);
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
if ( level.frozen || globalfreeze ) return;
|
||||
vel *= 0.96;
|
||||
vel.z += 0.01;
|
||||
A_FadeOut(1/32.);
|
||||
if ( waterlevel > 0 )
|
||||
{
|
||||
let b = Spawn("UTBubble",pos);
|
||||
b.vel = vel;
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
USKL C -1;
|
||||
TNT1 A 0 NoDelay A_Jump(255,"US1","US2","US3","US4","US5","US6","US7","US8","US9","US10");
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
Class UTRedKey : RedCard replaces RedCard
|
||||
{
|
||||
Default
|
||||
{
|
||||
Tag "Red Key";
|
||||
Inventory.PickupMessage "You got the Red Key.";
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
UKEY A -1;
|
||||
US1:
|
||||
US1_ ABCDEFGHIJKLMNOP 2;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
Class UTGoldKey : YellowCard replaces YellowCard
|
||||
{
|
||||
Default
|
||||
{
|
||||
Tag "Gold Key";
|
||||
Inventory.PickupMessage "You got the Gold Key.";
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
UKEY B -1;
|
||||
US2:
|
||||
US2_ ABCDEFGHIJKLMNOP 2;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
Class UTBlueKey : BlueCard replaces BlueCard
|
||||
{
|
||||
Default
|
||||
{
|
||||
Tag "Blue Key";
|
||||
Inventory.PickupMessage "You got the Blue Key.";
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
UKEY C -1;
|
||||
US3:
|
||||
US3_ ABCDEFGHIJKLMNOP 2;
|
||||
Stop;
|
||||
US4:
|
||||
US4_ ABCDEFGHIJKLMNO 2;
|
||||
Stop;
|
||||
US5:
|
||||
US5_ ABCDEFGHIJKLMNO 2;
|
||||
Stop;
|
||||
US6:
|
||||
US6_ ABCDEFGHIJKLMNOP 2;
|
||||
Stop;
|
||||
US7:
|
||||
US7_ ABCDEFGHIJKLMNOP 2;
|
||||
Stop;
|
||||
US8:
|
||||
US8_ ABCDEFGHIJKLMNOP 2;
|
||||
Stop;
|
||||
US9:
|
||||
US9_ ABCDEFGHIJKLMNOP 2;
|
||||
Stop;
|
||||
US10:
|
||||
US10 ABCDEFGHIJKLMNOP 2;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
|
@ -435,12 +581,10 @@ Class QueuedFlash
|
|||
Class UTMainHandler : StaticEventHandler
|
||||
{
|
||||
ui TextureID tex;
|
||||
transient int lastfrag;
|
||||
Array<QueuedFlash> flashes;
|
||||
|
||||
override void WorldLoaded( WorldEvent e )
|
||||
{
|
||||
lastfrag = int.min;
|
||||
if ( gamestate != GS_LEVEL || e.IsSaveGame ) return;
|
||||
if ( level.levelname ~== "Modder Test Map" )
|
||||
{
|
||||
|
|
@ -489,8 +633,6 @@ Class UTMainHandler : StaticEventHandler
|
|||
StatusBar.AttachMessage(gf,0,BaseStatusBar.HUDMSGLayer_UnderHUD);
|
||||
}
|
||||
if ( gametic <= 0 ) StartMenu();
|
||||
if ( !(StatusBar is 'UTHUD') ) return;
|
||||
UTHUD(StatusBar).lastfrag = lastfrag;
|
||||
}
|
||||
|
||||
override void RenderOverlay( RenderEvent e )
|
||||
|
|
@ -501,12 +643,6 @@ Class UTMainHandler : StaticEventHandler
|
|||
Screen.DrawTexture(tex,true,0,0,DTA_VirtualWidth,1024,DTA_VirtualHeight,768);
|
||||
}
|
||||
|
||||
override void WorldThingDamaged( WorldEvent e )
|
||||
{
|
||||
if ( (e.Thing.Health <= 0) && e.DamageSource && (e.DamageSource != e.Thing) && e.DamageSource.player && (e.DamageSource.player == players[consoleplayer]) )
|
||||
lastfrag = gametic;
|
||||
}
|
||||
|
||||
static void DoFlash( Actor camera, Color c, int duration )
|
||||
{
|
||||
QueuedFlash qf = new("QueuedFlash");
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ Class UTHud : BaseStatusBar
|
|||
double HScale;
|
||||
Color tintcolor, bgcolor;
|
||||
double opacity;
|
||||
int lastfrag, lastpickup, lastslot;
|
||||
int lastfrag, lastfragcnt, lastpickup, lastslot;
|
||||
ViewTracer vtracer;
|
||||
Actor lastseen;
|
||||
int lastseentic;
|
||||
|
|
@ -42,6 +42,8 @@ Class UTHud : BaseStatusBar
|
|||
{
|
||||
Super.Init();
|
||||
SetSize(0,320,200);
|
||||
lastfrag = int.min;
|
||||
lastfragcnt = 0;
|
||||
vtracer = new("ViewTracer");
|
||||
// Set defaults
|
||||
DrawColor = WhiteColor = "White";
|
||||
|
|
@ -310,7 +312,7 @@ Class UTHud : BaseStatusBar
|
|||
double WeaponOffset = 128*WeapScale;
|
||||
let cw = CPlayer.ReadyWeapon;
|
||||
let pw = CPlayer.PendingWeapon;
|
||||
if ( cw )
|
||||
if ( cw && (cw.SlotNumber != -1) )
|
||||
{
|
||||
int slot = cw.SlotNumber?(cw.SlotNumber-1):9;
|
||||
CurX = BaseX+slot*WeaponOffset;
|
||||
|
|
@ -320,7 +322,7 @@ Class UTHud : BaseStatusBar
|
|||
CurY = BaseY;
|
||||
UTDrawPlainTex(WeaponBox,0.8);
|
||||
}
|
||||
if ( pw && (pw != WP_NOCHANGE) )
|
||||
if ( pw && (pw.SlotNumber != -1) && (pw != WP_NOCHANGE) )
|
||||
{
|
||||
int slot = pw.SlotNumber?(pw.SlotNumber-1):9;
|
||||
CurX = BaseX+slot*WeaponOffset-64*WeapScale;
|
||||
|
|
@ -333,6 +335,7 @@ Class UTHud : BaseStatusBar
|
|||
{
|
||||
if ( !(i is 'Weapon') ) continue;
|
||||
let w = Weapon(i);
|
||||
if ( w.SlotNumber == -1 ) continue;
|
||||
int slot = w.SlotNumber?(w.SlotNumber-1):9;
|
||||
if ( !wslots[slot] ) wslots[slot] = w;
|
||||
else if ( (wslots[slot] != cw) && ((wslots[slot] != pw)
|
||||
|
|
@ -344,14 +347,10 @@ Class UTHud : BaseStatusBar
|
|||
CurX = BaseX+i*WeaponOffset;
|
||||
CurY = BaseY;
|
||||
if ( !wslots[i] )
|
||||
{
|
||||
UTDrawTintedTex(Slots[i],1.6,tintcolor/2);
|
||||
}
|
||||
else if ( wslots[i] != cw )
|
||||
{
|
||||
if ( !UTDrawWeaponIcon(wslots[i],false,wslots[i]==pw,0.8) )
|
||||
UTDrawTintedTex(Slots[i],1.6,tintcolor/2);
|
||||
}
|
||||
}
|
||||
for ( int i=0; i<10; i++ )
|
||||
{
|
||||
|
|
@ -471,6 +470,16 @@ Class UTHud : BaseStatusBar
|
|||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
if ( deathmatch||teamplay )
|
||||
{
|
||||
if ( CPlayer.fragcount != lastfragcnt ) lastfrag = gametic;
|
||||
lastfragcnt = CPlayer.fragcount;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( CPlayer.killcount != lastfragcnt ) lastfrag = gametic;
|
||||
lastfragcnt = CPlayer.killcount;
|
||||
}
|
||||
vtracer.ignore = CPlayer.mo;
|
||||
vtracer.trace(CPlayer.mo.Vec2OffsetZ(0,0,CPlayer.viewz),CPlayer.mo.CurSector,(cos(CPlayer.mo.angle)*cos(CPlayer.mo.pitch),sin(CPlayer.mo.angle)*cos(CPlayer.mo.pitch),-sin(CPlayer.mo.pitch)),1000,0);
|
||||
if ( vtracer.Results.HitType != TRACE_HitActor ) return;
|
||||
|
|
|
|||
|
|
@ -192,6 +192,48 @@ Class WarheadLight : DynamicLight
|
|||
}
|
||||
}
|
||||
|
||||
Class WarheadTrail : Actor
|
||||
{
|
||||
Default
|
||||
{
|
||||
RenderStyle "Add";
|
||||
Radius 0.1;
|
||||
Height 0;
|
||||
+NOGRAVITY;
|
||||
+NOCLIP;
|
||||
+DONTSPLASH;
|
||||
+FORCEXYBILLBOARD;
|
||||
+ROLLSPRITE;
|
||||
+ROLLCENTER;
|
||||
Scale 0.2;
|
||||
}
|
||||
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
double ang, pt;
|
||||
scale *= FRandom[Puff](0.5,1.5);
|
||||
alpha *= FRandom[Puff](0.5,1.5);
|
||||
ang = FRandom[Puff](0,360);
|
||||
pt = FRandom[Puff](-90,90);
|
||||
vel += (cos(pt)*cos(ang),cos(pt)*sin(ang),-sin(pt))*FRandom[Puff](0.2,0.8);
|
||||
roll = FRandom[Puff](0,360);
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
if ( level.frozen || globalfreeze ) return;
|
||||
vel *= 0.99;
|
||||
A_FadeOut(0.1);
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
RTRL A -1 Bright;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class WarShell : Actor
|
||||
{
|
||||
double destangle, destpitch;
|
||||
|
|
@ -245,14 +287,24 @@ Class WarShell : Actor
|
|||
Vector3 taildir = -(cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
|
||||
if ( waterlevel > 0 )
|
||||
{
|
||||
for ( int i=0; i<8; i++ )
|
||||
A_SpawnParticle("6060FF",0,Random[Warhead](10,30),FRandom[Warhead](2,4),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.2,fadestepf:0);
|
||||
for ( int i=0; i<4; i++ )
|
||||
{
|
||||
let s = Spawn("UTBubble",pos+taildir*32+(FRandom[Warhead](-.5,.5),FRandom[Warhead](-.5,.5),FRandom[Warhead](-.5,.5)));
|
||||
s.vel = taildir*2;
|
||||
}
|
||||
return;
|
||||
}
|
||||
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));
|
||||
for ( int i=0; i<4; i++ )
|
||||
{
|
||||
let s = Spawn("UTSmoke",pos+taildir*32+(FRandom[Warhead](-.5,.5),FRandom[Warhead](-.5,.5),FRandom[Warhead](-.5,.5)));
|
||||
s.vel = taildir*2;
|
||||
s.SetShade("404040");
|
||||
}
|
||||
for ( int i=0; i<4; i++ )
|
||||
{
|
||||
let s = Spawn("WarheadTrail",pos+taildir*35+(FRandom[Warhead](-1,1),FRandom[Warhead](-1,1),FRandom[Warhead](-1,1)));
|
||||
s.vel = taildir*4;
|
||||
}
|
||||
}
|
||||
action void A_Vaporize()
|
||||
{
|
||||
|
|
@ -545,7 +597,9 @@ Class WarheadLauncher : UTWeapon replaces BFG9000
|
|||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (x+(FRandom[Warhead](-.8,.8),FRandom[Warhead](-.8,.8),FRandom[Warhead](-.8,.8))).unit()*FRandom[Warhead](1,2);
|
||||
A_SpawnParticle(Color(1,1,1)*Random[Warhead](32,128),0,Random[Warhead](40,50),FRandom[Warhead](4,12),0,origin.x-pos.x,origin.y-pos.y,origin.z-pos.z,pvel.x,pvel.y,pvel.z,0,0,0.03,0.5,-1,0.5);
|
||||
let s = Spawn("UTSmoke",origin);
|
||||
s.vel = pvel;
|
||||
s.SetShade(Color(1,1,1)*Random[Warhead](32,128));
|
||||
}
|
||||
}
|
||||
action void A_WarheadAlt()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue