Added Eightball "2 second hold" feature from Unreal Bible.

Added Stinger projectile bounce from 0.866 and below.
Added Stinger damage charge&explosion from Unreal Bible.
This commit is contained in:
Marisa the Magician 2019-09-07 14:44:56 +02:00
commit 46ebde2750
8 changed files with 309 additions and 7 deletions

View file

@ -12,9 +12,12 @@ Doom Tournament (currently the devel branch is required).
- Automag (slot 2) (replaces pistol)
- Dual Automags
- Stinger (slot 3) (replaces shotguns)
- Projectile bouncing from 0.866 and below
- Tarydium charge & explosion described in Unreal Bible
- ASMD (slot 4) (replaces shotguns)
- Eightball (slot 5) (replaces rocket launcher)
- Single rocket mode for Eightball
- "Hold up to 2 seconds" feature from Unreal Bible
- Flak Cannon (slot 6) (replaces rocket launcher)
- SMP 7243 (slot 0) (replaces bfg9000)
- Backpack (replaces backpack, identical to Doom Tournament version)
@ -57,11 +60,10 @@ Doom Tournament (currently the devel branch is required).
## Planned
- Unreal Bible & prototype build behaviour restoration
- Stinger projectile remanence & explosion
- Stinger projectile bouncing
- Razorjack hold fire to increase blade speed
- Rifle restored rapid fire
- Rifle restored flashlight
- Biorifle "Hold up to 2 seconds" feature from Unreal Bible
- QOL improvements
- Make Razorjack altfire actually seek where player is aiming

View file

@ -75,4 +75,8 @@ server bool sting_olsmp = false; // adds the stupid oldskool SMP 7243 to
// the sake of completion it's there as
// an option
server bool sting_autoscuba = false; // SCUBA gear toggles automatically
// when needed
// when needed
server bool sting_ehold = false; // eightball can be held fully loaded
// for up to 2 seconds
server bool sting_bhold = false; // biorifle can be held fully loaded
// for up to 2 seconds

View file

@ -37,6 +37,7 @@ O_OWNSENTRY = "%o was gunned down by %p own Minigun Sentry.";
O_OSENTRY = "%%o took a bullet from %s.";
O_OWNOSENTRY = "%o took a bullet from %p own Light Sentry.";
O_STINGERX = "%o ate flaming Tarydium death thanks to %k.";
O_STINGERX2 = "%o ate flaming Tarydium death.";
O_OLSMP = "%o didn't stand a chance against %k's SMP 7243.";
/* Pickup messages */
I_WPOWERUP = "You got a Dispersion Pistol Powerup.";
@ -217,6 +218,8 @@ STING_STINGERB = "Stinger projectiles bounce";
STING_RIFLE = "Rifle burst altfire";
STING_RIFLEL = "Rifle flashlight";
STING_RAZOR = "Razorjack charging";
STING_EHOLD = "Loaded Eightball can be held for 2 seconds";
STING_BHOLD = "Charged Biorifle can be held for 2 seconds";
STING_FLAMET = "Old Flamethrower model";
STING_DOPTS = "Weapon dual wielding";
STING_AUTODUAL = "Automags";
@ -276,6 +279,7 @@ O_OWNSENTRY = "%o fue abatid@[ao_esp] por su propi@[ao_esp] Torreta.";
O_OSENTRY = "%%o se llevó un tiro de la %s.";
O_OWNOSENTRY = "%o se llevó un tiro de su propi@[ao_esp] Torreta Ligera.";
O_STINGERX = "%o tragó muerte ardiente de Tarydium gracias a %k.";
O_STINGERX2 = "%o tragó muerte ardiente de Tarydium.";
O_OLSMP = "%o no tenía ninguna oportunidad contra el SMP 7243 de %k.";
/* Pickup messages */
I_WPOWERUP = "Has obtenido una Mejora para la Pistola de Dispersión.";
@ -438,6 +442,8 @@ STING_STINGERB = "Los projectiles del Arma Aguijón rebotan";
STING_RIFLE = "Fuego alternativo en ráfaga de Rifle";
STING_RIFLEL = "Linterna de Rifle";
STING_RAZOR = "Carga de Razorjack";
STING_EHOLD = "El Eightball se puede mantener cargado por 2 segundos";
STING_BHOLD = "El Biorifle se puede mantener cargado por 2 segundos";
STING_FLAMET = "Modelo viejo de Lanzallamas";
STING_DOPTS = "Armas a dos manos";
STING_AUTODUAL = "Autoarmas";

View file

@ -31,6 +31,8 @@ OptionMenu "UnrealOptionMenu"
Option "$STING_RIFLE", "sting_rifle", "YesNo"
Option "$STING_RIFLEL", "sting_riflel", "YesNo"
Option "$STING_RAZOR", "sting_razor", "YesNo"
Option "$STING_EHOLD", "sting_ehold", "YesNo"
Option "$STING_BHOLD", "sting_bhold", "YesNo"
Option "$STING_FLAMET", "sting_flamet", "YesNo"
StaticText " "
StaticText "$STING_DOPTS", "Gold"

View file

@ -22,3 +22,9 @@ DoomEdNums
4510 = UTranslator
4511 = TranslatorEvent
}
DamageType TarydiumCharge
{
// obituary for no instigator
Obituary = "$O_STINGERX2"
}

View file

@ -147,8 +147,199 @@ Class ViewStingerChunk : StingerChunk
}
}
Class TarydiumExLight : PaletteLight
{
Default
{
Tag "Blue2";
Args 0,0,0,60;
ReactionTime 30;
}
}
Class TarydiumExplosion : Actor
{
Default
{
RenderStyle "Add";
+NOGRAVITY;
+NOBLOCKMAP;
+FORCEXYBILLBOARD;
+FORCERADIUSDMG;
+NODAMAGETHRUST;
DamageType 'TarydiumCharge';
Obituary "$O_STINGERX";
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
A_Explode(special1,int(90*scale.x));
UTMainHandler.DoBlast(self,90*scale.x,90000);
A_PlaySound("flare/explode");
let l = Spawn("TarydiumExLight",pos);
l.args[3] = int(60*scale.x);
scale.x *= RandomPick[Stinger](-1,1);
scale.y *= RandomPick[Stinger](-1,1);
double ang, pt;
int numpt = Random[Stinger](10,15)*min(3,special1/60);
for ( int i=0; i<numpt; i++ )
{
ang = FRandom[Stinger](0,360);
pt = FRandom[Stinger](-90,90);
let c = Spawn("UTSmoke",pos);
c.vel = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*FRandom[Stinger](2,7);
c.SetShade(Color(1,3,4)*Random[Stinger](24,63));
c.scale *= 3.;
}
numpt = Random[Stinger](4,8)*min(8,special1/25);
for ( int i=0; i<numpt; i++ )
{
ang = FRandom[Stinger](0,360);
pt = FRandom[Stinger](-90,90);
let c = Spawn("StingerChunk",pos);
c.angle = ang;
c.pitch = pt;
c.vel = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*FRandom[Stinger](6,12);
}
numpt = Random[Stinger](10,20)*min(4,special1/40);
for ( int i=0; i<numpt; i++ )
{
ang = FRandom[Stinger](0,360);
pt = FRandom[Stinger](-90,90);
let c = Spawn("UTChip",pos);
c.vel = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*FRandom[Stinger](6,12);
c.scale *= FRandom[Stinger](0.9,1.5);
}
}
States
{
Spawn:
TNT1 A 0 NoDelay A_Jump(128,"Explo2");
Explo1:
TEX1 ABCDEFGHI 3 Bright;
Stop;
Explo2:
TEX2 ABCDEFGHIJK 3 Bright;
Stop;
}
}
Class TarydiumDebuff : Thinker
{
Actor victim, instigator;
int amount; // accumulated damage for the explosion
Vector3 oldvel;
bool wasonair, reentrant;
void UpdateEffect()
{
if ( !victim )
{
BlowUp();
return;
}
victim.A_AttachLight('TDEBUFFLIGHT',DynamicLight.PointLight,Color(1,3,4)*min(amount,63),int(max(victim.radius,victim.height))+60+min(amount/4,40),0,DynamicLight.LF_ATTENUATE,(0,0,victim.height/2));
if ( Random[Stinger](0,amount) > 100 )
{
amount += 30;
BlowUp();
}
}
void BlowUp()
{
reentrant = true;
let b = victim.Spawn("TarydiumExplosion",victim.Vec3Offset(0,0,victim.height/2));
b.target = instigator;
b.special1 = amount;
b.scale *= 1.+min(1.5,amount*0.02);
Destroy();
}
override void OnDestroy()
{
Super.OnDestroy();
if ( victim ) victim.A_RemoveLight('TDEBUFFLIGHT');
}
override void Tick()
{
if ( !victim || (victim.Health <= 0) )
{
BlowUp();
return;
}
if ( victim.pos.z > victim.floorz ) wasonair = true;
else
{
if ( wasonair && (oldvel.z < -20) )
{
Amount += min(int(-oldvel.z),100);
BlowUp();
return;
}
wasonair = false;
}
oldvel = victim.vel;
if ( !(level.maptime%20) )
{
amount--;
UpdateEffect();
if ( amount <= 0 )
{
Destroy();
return;
}
}
if ( level.maptime%3 ) return;
int numpt = clamp(int(Random[Stinger](1,3)*amount*0.02),1,8);
for ( int i=0; i<numpt; i++ )
{
Vector3 pos = victim.Vec3Offset(FRandom[Stinger](-victim.radius,victim.radius),FRandom[Stinger](-victim.radius,victim.radius),FRandom[Stinger](0,victim.height));
let l = victim.Spawn("StingerBurstLight",pos);
l.Args[3] /= 2;
double ang, pt;
int numpt2 = Random[Stinger](2,5);
for ( int i=0; i<numpt; i++ )
{
ang = FRandom[Stinger](0,360);
pt = FRandom[Stinger](-90,90);
let c = victim.Spawn("UTSmoke",pos);
c.vel = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*FRandom[Stinger](0.3,0.8);
c.SetShade(Color(1,3,4)*Random[Stinger](24,63));
c.scale *= 3.;
c.alpha *= 0.35;
}
}
}
static void Apply( Actor victim, Actor instigator, int amount )
{
if ( !victim || (victim.Health <= 0) || !victim.bISMONSTER ) return;
let ti = ThinkerIterator.Create("TarydiumDebuff",STAT_USER);
TarydiumDebuff t;
while ( t = TarydiumDebuff(ti.Next()) )
{
if ( t.victim != victim ) continue;
if ( instigator ) t.instigator = instigator;
t.amount += amount;
t.UpdateEffect();
return;
}
t = new("TarydiumDebuff");
t.ChangeStatNum(STAT_USER);
t.victim = victim;
t.instigator = instigator;
t.amount = amount;
t.oldvel = victim.vel;
t.wasonair = (victim.pos.z>victim.floorz);
t.UpdateEffect();
}
}
Class StingerProjectile : Actor
{
Vector3 oldvel;
Default
{
Obituary "$O_STINGER";
@ -160,6 +351,66 @@ Class StingerProjectile : Actor
PROJECTILE;
+SKYEXPLODE;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
if ( sting_stingerb )
{
// set bounce stuff
bBOUNCEONWALLS = true;
bBOUNCEONFLOORS = true;
bBOUNCEONCEILINGS = true;
bALLOWBOUNCEONACTORS = true;
bCANBOUNCEWATER = true;
bUSEBOUNCESTATE = true;
BounceCount = 4;
BounceFactor = 1.;
WallBounceFactor = 1.;
}
}
override void Tick()
{
oldvel = vel;
Super.Tick();
}
void A_HandleBounce()
{
// cancel bounce based on "incidence"
if ( vel dot oldvel < 0.87 )
{
ClearBounce();
ExplodeMissile();
return;
}
if ( !Random[Stinger](0,2) ) A_PlaySound("stinger/hit2",CHAN_BODY,0.5,pitch:FRandom[Stinger](0.5,1.5));
else A_PlaySound("stinger/hit",CHAN_BODY,0.6);
A_SprayDecal("WallCrack",-20);
A_AlertMonsters();
let l = Spawn("StingerBurstLight",pos);
l.Args[3] /= 2;
double ang, pt;
int numpt = Random[Stinger](1,3);
for ( int i=0; i<numpt; i++ )
{
ang = FRandom[Stinger](0,360);
pt = FRandom[Stinger](-90,90);
let c = Spawn("StingerChunk",pos);
c.scale *= 0.5;
c.angle = ang;
c.pitch = pt;
c.vel = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*FRandom[Stinger](3,9);
}
numpt = Random[Stinger](2,5);
for ( int i=0; i<numpt; i++ )
{
ang = FRandom[Stinger](0,360);
pt = FRandom[Stinger](-90,90);
let c = Spawn("UTSmoke",pos);
c.vel = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*FRandom[Stinger](0.3,0.8);
c.SetShade(Color(1,3,4)*Random[Stinger](48,63));
c.alpha *= 0.35;
}
}
override int DoSpecialDamage( Actor target, int damage, Name damagetype )
{
if ( !target.bNOBLOOD )
@ -167,6 +418,7 @@ Class StingerProjectile : Actor
target.SpawnBlood(pos,AngleTo(target),damage);
A_PlaySound("stinger/flesh");
A_AlertMonsters();
if ( sting_stinger ) TarydiumDebuff.Apply(target,self.target,damage/4);
}
return damage;
}
@ -204,6 +456,9 @@ Class StingerProjectile : Actor
Spawn:
TPRJ A -1 Bright;
Stop;
Bounce:
TPRJ A 0 Bright A_HandleBounce();
Goto Spawn;
Death:
Crash:
TNT1 A 1 A_StingerHit();

View file

@ -577,13 +577,26 @@ Class Eightball : UnrealWeapon
EBLL LMNOPQRSTUVWXYZ[ 1;
EBLL Z 0;
EBLI A 0;
EBLI A 1 A_JumpIf(invoker.special1>=6,2);
EBLI A 1
{
if ( invoker.special1 >= 6 )
{
if ( sting_ehold )
{
invoker.special2 = 70;
return ResolveState("LoadHold");
}
else return ResolveState("Release");
}
return ResolveState(null);
}
EBLI A 0 A_LoadedRefire("Loading");
Goto Release;
EBLI A 2;
LoadHold:
EBLI C 2;
EBLI C 0 A_LoadedRefire("LoadHold");
EBLI A 2;
LoadHoldL:
EBLI C 1 A_JumpIf(--invoker.special2<0,"Release");
EBLI C 0 A_LoadedRefire("LoadHoldL");
Goto Release;
Release:
EBLF A 0 A_FireRockets(invoker.special1);

View file

@ -812,6 +812,20 @@ Class UnrealMainHandler : EventHandler
{
Array<AmmoUsedInSlot> AmmoSlots;
override void WorldThingDamaged( WorldEvent e )
{
// blow up stinger pumped actors when taking damage from other sources
if ( e.DamageType == 'Stinger' ) return;
let ti = ThinkerIterator.Create("TarydiumDebuff",Thinker.STAT_USER);
TarydiumDebuff t;
while ( t = TarydiumDebuff(ti.Next()) )
{
if ( (t.victim != e.Thing) || t.reentrant ) continue; // make sure to skip any debuffs that already blew up to prevent infinite recursion on chain reactions
t.Amount += e.Damage/2;
t.BlowUp();
break;
}
}
override void CheckReplacement( ReplaceEvent e )
{
if ( (e.Replacee == 'Chainsaw') || (e.Replacee == 'Gauntlets') )