diff --git a/Readme.md b/Readme.md index 0634f18..c152429 100644 --- a/Readme.md +++ b/Readme.md @@ -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 diff --git a/cvarinfo.txt b/cvarinfo.txt index 8d1c03f..75fbdbb 100644 --- a/cvarinfo.txt +++ b/cvarinfo.txt @@ -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 \ No newline at end of file + // 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 diff --git a/language.txt b/language.txt index 0de8ef2..211edfc 100644 --- a/language.txt +++ b/language.txt @@ -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"; diff --git a/menudef.txt b/menudef.txt index 6fa2e9c..60f4fc8 100644 --- a/menudef.txt +++ b/menudef.txt @@ -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" diff --git a/zmapinfo.txt b/zmapinfo.txt index 5d113fd..93158d1 100644 --- a/zmapinfo.txt +++ b/zmapinfo.txt @@ -22,3 +22,9 @@ DoomEdNums 4510 = UTranslator 4511 = TranslatorEvent } + +DamageType TarydiumCharge +{ + // obituary for no instigator + Obituary = "$O_STINGERX2" +} diff --git a/zscript/stinger.zsc b/zscript/stinger.zsc index c4f5634..dae65c9 100644 --- a/zscript/stinger.zsc +++ b/zscript/stinger.zsc @@ -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 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; ivictim.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=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); diff --git a/zscript/unrealcommon.zsc b/zscript/unrealcommon.zsc index 35cf605..890a573 100644 --- a/zscript/unrealcommon.zsc +++ b/zscript/unrealcommon.zsc @@ -812,6 +812,20 @@ Class UnrealMainHandler : EventHandler { Array 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') )