From 1c0f7d08a5cc5d547a9b76b79dc301adaa1fb9c2 Mon Sep 17 00:00:00 2001 From: Marisa Kirisame Date: Wed, 5 Sep 2018 18:56:04 +0200 Subject: [PATCH] Various rebalances. Corrected some things that weren't 1:1 with UT. Restored original flak chunk damage function (no longer falls off with distance). Fixed the minigun altfire shooting bullets at the same speed as the primary fire. Small hackaround for janky player movement while moving down slopes. [WIP] The very beginning of an UT gore system (toggleable). --- Readme.md | 4 ++- cvarinfo.txt | 1 + language.txt | 3 +- menudef.txt | 1 + zscript/enforcer.zsc | 5 ++- zscript/flakcannon.zsc | 17 ++++------ zscript/impacthammer.zsc | 12 +++---- zscript/minigun.zsc | 11 ++++--- zscript/ripper.zsc | 10 +++--- zscript/sniperrifle.zsc | 2 +- zscript/utcommon.zsc | 67 ++++++++++++++++++++++++++++++++++++++-- 11 files changed, 99 insertions(+), 34 deletions(-) diff --git a/Readme.md b/Readme.md index 1bff593..fe7533f 100644 --- a/Readme.md +++ b/Readme.md @@ -59,9 +59,12 @@ This mod requires a recent GZDoom devbuild (g3.6pre-31-gd965c9aa7 or later). - Fix some oddly-oriented triangles (e.g. some parts of the flak cannon, can be easily noticed when using invisibility) - Recenter the backpack mesh (it was a complete hack job to begin with) + - UT gore system (toggleable) ## Future plans + - Change the way inventory items are dropped to be more UT-like, this will + require GZDoom changes - Add ammo counters to Pulsegun, Minigun, Flak Cannon and Rocket Launcher once scripted textures are implemented - Add player models once GZDoom gets a well deserved model animation system @@ -69,7 +72,6 @@ This mod requires a recent GZDoom devbuild (g3.6pre-31-gd965c9aa7 or later). the current state-tied system) - Add weapon attachment support to player models when that is also added in - Migrate RandomSpawners to CheckReplacement - - Perhaps come up with an add-on that imitates UT's blood/gore system - Unreal 1 weapons mod and maybe also a monsters mod - Port some of my UT weapon mods diff --git a/cvarinfo.txt b/cvarinfo.txt index 754624b..a5f75e5 100644 --- a/cvarinfo.txt +++ b/cvarinfo.txt @@ -27,3 +27,4 @@ server bool flak_doomspeed = false; // keep Doomguy run speed when using UT mov server bool flak_doomaircontrol = false; // keep Doom's limited air control when using UT movement server bool flak_nobosstelefrag = false; // disable telefragging of boss monsters (useful when translocator is enabled) server bool flak_nowalkdrop = false; // don't drop off ledges while holding walk key (glitchy) +server bool flak_corpsedamage = false; // [WIP/EXPERIMENTAL] allow corpses to take damage and be gibbed, currently just causes a jump to XDeath until gore system is implemented diff --git a/language.txt b/language.txt index 77eaa11..00e3d62 100644 --- a/language.txt +++ b/language.txt @@ -6,13 +6,12 @@ DAMNUM_TYPECOLOR_SHOT = "DamYellow"; DAMNUM_TYPECOLOR_JOLTED = "DamLightBlue"; DAMNUM_TYPECOLOR_JOLTEDX = "DamOrange"; DAMNUM_TYPECOLOR_REDEEMERDEATH = "DamBlack"; -DAMNUM_TYPECOLOR_SHREDDED = "DamGold"; +DAMNUM_TYPECOLOR_SHREDDED = "DamBrick"; DAMNUM_TYPECOLOR_FLAKDEATH = "DamGold"; DAMNUM_TYPECOLOR_SLASHED = "DamRed"; DAMNUM_TYPECOLOR_DECAPITATED = "DamDarkRed"; DAMNUM_TYPECOLOR_SLIME = "DamDarkGreen"; DAMNUM_TYPECOLOR_IMPACT = "DamGray"; -DAMNUM_TYPECOLOR_RIPPER = "DamBrick"; DAMNUM_TYPECOLOR_RIPPERALTDEATH = "DamCream"; DAMNUM_TYPECOLOR_ROCKETDEATH = "DamTan"; DAMNUM_TYPECOLOR_GRENADEDEATH = "DamTan"; diff --git a/menudef.txt b/menudef.txt index e445485..59308de 100644 --- a/menudef.txt +++ b/menudef.txt @@ -53,6 +53,7 @@ OptionMenu "UTOptionMenu" StaticText " " StaticText "Misc Options", "Gold" Option "UT Footsteps", "flak_footsteps", "YesNo" + Option "[WIP] Corpses Take Damage", "flak_corpsedamage", "YesNo" } AddOptionMenu "OptionsMenu" diff --git a/zscript/enforcer.zsc b/zscript/enforcer.zsc index 2c98d62..3d9836f 100644 --- a/zscript/enforcer.zsc +++ b/zscript/enforcer.zsc @@ -306,6 +306,7 @@ Class Enforcer : UTWeapon if ( alt ) origin = origin-z*3.0+ydir*y*1.0; else origin = origin-z*1.0+ydir*y*4.0; double a = FRandom[Enforcer](0,360), s = FRandom[Enforcer](0,alt?0.08:0.004); + if ( invoker.SlaveActive ) s *= 3; [x2, y2, z2] = Matrix4.GetAxes(BulletSlope(),angle,roll); Vector3 dir = (x2+y2*cos(a)*s+z2*sin(a)*s).unit(); FLineTraceData d; @@ -314,7 +315,9 @@ Class Enforcer : UTWeapon { int dmg = Random[Enforcer](12,17); dmg = d.HitActor.DamageMobj(invoker,self,dmg,'shot',DMG_USEANGLE|DMG_THRUSTLESS,atan2(d.HitDir.y,d.HitDir.x)); - UTMainHandler.DoKnockback(d.HitActor,d.HitDir,3000); + double mm = 3000; + if ( FRandom[Enforcer](0,1) < 0.2 ) mm *= 5; + UTMainHandler.DoKnockback(d.HitActor,d.HitDir,mm); if ( d.HitActor.bNOBLOOD ) { let p = Spawn("BulletImpact",d.HitLocation); diff --git a/zscript/flakcannon.zsc b/zscript/flakcannon.zsc index 02e4211..c3bac4b 100644 --- a/zscript/flakcannon.zsc +++ b/zscript/flakcannon.zsc @@ -107,7 +107,6 @@ Class ChunkTrail : Actor Class FlakChunk : Actor { - Actor lasthit; ChunkTrail trail; double rollvel, pitchvel, yawvel; double lifetime, lifespeed; @@ -118,7 +117,7 @@ Class FlakChunk : Actor Radius 2; Height 2; Speed 50; - DamageFunction int(Random[Flak](15,20)*max(0.1,1.0-lifetime*4.1)); + DamageFunction Random[Flak](15,20); DamageType 'Shredded'; BounceType "Doom"; BounceFactor 0.8; @@ -130,10 +129,6 @@ Class FlakChunk : Actor +SKYEXPLODE; Scale 0.3; } - override bool CanCollideWith( Actor other, bool passive ) - { - return (vel.length()>4.0); - } override void PostBeginPlay() { Super.PostBeginPlay(); @@ -208,17 +203,17 @@ Class FlakChunk : Actor A_PlaySound("flak/bounce",volume:0.3); A_AlertMonsters(); bBOUNCEAUTOOFFFLOORONLY = true; - if ( vel.length() < 4.0 ) ExplodeMissile(); + if ( vel.length() < 5.0 ) ExplodeMissile(); } override int DoSpecialDamage( Actor target, int damage, Name damagetype ) { + if ( vel.length() <= 5.0 ) return 0; if ( !target.bNOBLOOD ) { - if ( target != lasthit ) target.SpawnBlood(pos,AngleTo(target),damage); + target.SpawnBlood(pos,AngleTo(target),damage); A_PlaySound("flak/meat",volume:0.3); A_AlertMonsters(); } - lasthit = target; return damage; } States @@ -377,7 +372,7 @@ Class FlakSlug : Actor double a, s; [x, y, z] = Matrix4.GetAxes(pitch,angle,roll); Actor p; - for ( int i=0; i<6; i++ ) + for ( int i=0; i<5; i++ ) { p = Spawn("FlakChunk",pos); p.bHITOWNER = true; @@ -475,7 +470,7 @@ Class FlakCannon : UTWeapon A_OverlayRenderstyle(-2,STYLE_Add); [x, y, z] = Matrix4.GetAxes(BulletSlope(),angle,roll); Actor p; - for ( int i=0; i<10; i++ ) + for ( int i=0; i<6; i++ ) { p = Spawn("FlakChunk",origin); a = FRandom[Flak](0,360); diff --git a/zscript/impacthammer.zsc b/zscript/impacthammer.zsc index b8de009..1456c83 100644 --- a/zscript/impacthammer.zsc +++ b/zscript/impacthammer.zsc @@ -72,7 +72,7 @@ Class ImpactHammer : UTWeapon Vector3 origin = (pos.x,pos.y,player.viewz)+10.0*x+3.0*y-4.0*z; double realcharge = min(1.5,invoker.chargesize); FLineTraceData d; - LineTrace(angle,80,BulletSlope(),TRF_ABSPOSITION,origin.z,origin.x,origin.y,d); + LineTrace(angle,60,BulletSlope(),TRF_ABSPOSITION,origin.z,origin.x,origin.y,d); if ( d.HitType == TRACE_HitActor ) { int dmg = int(Random[Impact](90,120)*realcharge); @@ -133,8 +133,8 @@ Class ImpactHammer : UTWeapon [x, y, z] = Matrix4.GetAxes(pitch,angle,roll); Vector3 origin = (pos.x,pos.y,player.viewz)+10.0*x+3.0*y-4.0*z; FLineTraceData d; - LineTrace(angle,180,BulletSlope(),TRF_ABSPOSITION,origin.z,origin.x,origin.y,d); - double dscale = d.Distance/180.; + LineTrace(angle,120,BulletSlope(),TRF_ABSPOSITION,origin.z,origin.x,origin.y,d); + double dscale = d.Distance/120.; if ( d.HitType == TRACE_HitActor ) { int dmg = int(Random[Impact](25,35)*dscale); @@ -156,10 +156,10 @@ Class ImpactHammer : UTWeapon if ( !m.bMISSILE ) continue; double rdist = level.Vec3Diff(origin,m.pos).length(); Vector3 rdir = level.Vec3Diff(origin,m.pos).unit(); - if ( LineTrace(atan2(rdir.y,rdir.x),rdist,asin(-rdir.z),TRF_THRUACTORS|TRF_ABSPOSITION,origin.z,origin.x,origin.y) || (rdist > 550) || (rdir dot x < 0.9) ) continue; + if ( LineTrace(atan2(rdir.y,rdir.x),rdist,asin(-rdir.z),TRF_THRUACTORS|TRF_ABSPOSITION,origin.z,origin.x,origin.y) || (rdist > 400) || (rdir dot x < 0.9) ) continue; m.speed = m.vel.length(); - if ( m.vel dot y > 0 ) m.vel = m.speed*(m.vel+(750-rdist)*y*0.01).unit(); - else m.vel = m.speed*(m.vel-(750-rdist)*y*0.01).unit(); + if ( m.vel dot y > 0 ) m.vel = m.speed*(m.vel+(560-rdist)*y*0.01).unit(); + else m.vel = m.speed*(m.vel-(560-rdist)*y*0.01).unit(); if ( m.target == self ) continue; if ( m.bSEEKERMISSILE ) m.tracer = m.target; m.target = self; diff --git a/zscript/minigun.zsc b/zscript/minigun.zsc index ee1ca37..d77fdb6 100644 --- a/zscript/minigun.zsc +++ b/zscript/minigun.zsc @@ -69,7 +69,7 @@ Class MinigunTracer : Actor Class Minigun : UTWeapon { - int bcnt; + int bcnt, tcnt; action void A_FireBullet( bool alt = false ) { @@ -79,7 +79,8 @@ Class Minigun : UTWeapon A_Overlay(-2,"MuzzleFlash",true); A_OverlayFlags(-2,PSPF_RENDERSTYLE|PSPF_FORCESTYLE,true); A_OverlayRenderstyle(-2,STYLE_Add); - if ( (alt && (invoker.bcnt++ < 2)) || (invoker.bcnt++ < 4) ) return; + invoker.bcnt++; + if ( (alt && (invoker.bcnt < 2)) || (!alt && (invoker.bcnt < 4)) ) return; invoker.bcnt = 0; if ( !weap.DepleteAmmo(weap.bAltFire,true,1) ) return; invoker.FireEffect(); @@ -100,9 +101,11 @@ Class Minigun : UTWeapon LineTrace(atan2(dir.y,dir.x),10000,asin(-dir.z),TRF_ABSPOSITION,origin.z,origin.x,origin.y,d); if ( d.HitType == TRACE_HitActor ) { - int dmg = Random[Minigun](16,20); // fun fact: the Minigun is one of the few weapons that has actual RNG damage in UT + int dmg = Random[Minigun](9,18); // fun fact: the Minigun is one of the few weapons that has actual RNG damage in UT dmg = d.HitActor.DamageMobj(invoker,self,dmg,'shot',DMG_USEANGLE|DMG_THRUSTLESS,atan2(d.HitDir.y,d.HitDir.x)); - UTMainHandler.DoKnockback(d.HitActor,d.HitDir,dmg*500); + double mm = 500; + if ( FRandom[Minigun](0,1) < 0.2 ) mm *= 2.5; + UTMainHandler.DoKnockback(d.HitActor,d.HitDir,dmg*mm); if ( d.HitActor.bNOBLOOD ) { let p = Spawn("BulletImpact",d.HitLocation); diff --git a/zscript/ripper.zsc b/zscript/ripper.zsc index 06620a9..19cc4ec 100644 --- a/zscript/ripper.zsc +++ b/zscript/ripper.zsc @@ -57,9 +57,9 @@ Class Razor2 : Actor { Radius 2; Height 2; - Speed 40; // should be 26 but it looks way too slow - DamageFunction (Random[Ripper](30,40)*((DamageType=='Decapitated')?3.5:1.0)); - DamageType 'Ripper'; + Speed 27; + DamageFunction (Random[Ripper](25,35)*((DamageType=='Decapitated')?3.5:1.0)); + DamageType 'Shredded'; Obituary "%k ripped a chunk of meat out of %o with the Ripper."; BounceType "Doom"; ReactionTime 7; @@ -84,7 +84,7 @@ Class Razor2 : Actor } override int SpecialMissileHit( Actor victim ) { - if ( pos.z > victim.pos.z+victim.height*0.75 ) DamageType = 'Decapitated'; + if ( pos.z > victim.pos.z+victim.height*0.81 ) DamageType = 'Decapitated'; return -1; } override int DoSpecialDamage( Actor target, int damage, Name damagetype ) @@ -135,7 +135,7 @@ Class Razor2 : Actor Bounce: RAZB A 0 { - bHITOWNER = true; + bHITOWNER = true; // technically the UT version sets this 0.2 seconds after being fired, but this works better Vector3 dir = vel.unit(); A_SetAngle(atan2(dir.y,dir.x)); A_SetPitch(asin(-dir.z)); diff --git a/zscript/sniperrifle.zsc b/zscript/sniperrifle.zsc index cc4beeb..2d8a1c2 100644 --- a/zscript/sniperrifle.zsc +++ b/zscript/sniperrifle.zsc @@ -96,7 +96,7 @@ Class SniperRifle : UTWeapon if ( d.HitType == TRACE_HitActor ) { int dmg = Random[Sniper](45,60); - if ( d.HitLocation.z >= (d.HitActor.pos.z+d.HitActor.height*0.8) ) + if ( d.HitLocation.z >= (d.HitActor.pos.z+d.HitActor.height*0.81) ) { dmg = d.HitActor.DamageMobj(invoker,self,dmg+70,'Decapitated',DMG_USEANGLE|DMG_THRUSTLESS,atan2(d.HitDir.y,d.HitDir.x)); UTMainHandler.DoKnockback(d.HitActor,d.HitDir,35000); diff --git a/zscript/utcommon.zsc b/zscript/utcommon.zsc index 11042eb..d4c2788 100644 --- a/zscript/utcommon.zsc +++ b/zscript/utcommon.zsc @@ -1,6 +1,7 @@ Class UTPlayer : DoomPlayer { bool lastground; + int lastgroundtic; double lastvelz, prevvelz; transient CVar footsteps, utmovement, doomspeed, doomaircontrol, nowalkdrop; Vector2 acceleration; @@ -190,15 +191,15 @@ Class UTPlayer : DoomPlayer if ( player.onground && !bNoGravity && !lastground && (waterlevel < 3) ) { player.jumptics = 0; - if ( lastvelz < -4 ) + if ( lastvelz < -8 ) { - double vol = clamp((-lastvelz-4)*0.05,0.01,1.0); + double vol = clamp((-lastvelz-8)*0.05,0.01,1.0); if ( ((waterlevel > 0) || GetFloorTerrain().IsLiquid) && !bOnMobj ) A_PlaySound("ut/wetsplash",CHAN_AUTO,vol); else A_PlaySound("*uland",CHAN_AUTO,vol); } else forcefootstep = true; } - if ( forcefootstep || ((abs(sin(ang)) >= 1.0) && player.onground && (player.cmd.forwardmove || player.cmd.sidemove) && (waterlevel < 3)) ) + if ( forcefootstep || ((abs(sin(ang)) >= 1.0) && player.onground && lastground && (player.jumptics == 0) && (player.cmd.forwardmove || player.cmd.sidemove) && (waterlevel < 3)) ) { double vol = abs(vel.xy.length())*0.03; if ( forcefootstep ) vol = clamp(-lastvelz*0.05,0.01,1.0); @@ -237,6 +238,8 @@ Class UTPlayer : DoomPlayer } else Angle += cmd.yaw*(360./65536.); player.onground = (pos.z <= floorz) || bOnMobj || bMBFBouncer || (player.cheats & CF_NOCLIP2); + if ( player.onground ) lastgroundtic = gametic; + if ( (abs(lastgroundtic-gametic) < 4) && (player.jumptics == 0) ) player.onground = true; double friction = FrictionToUnreal(); double fs = TweakSpeeds(1.0,0.0); if ( !doomspeed.GetBool() ) @@ -289,6 +292,7 @@ Class UTPlayer : DoomPlayer player.camera = player.mo; } player.vel *= 0; + player.jumptics = -2; } else { @@ -1102,6 +1106,54 @@ Class UTBlueKey : BlueCard } } +Class ShredCorpseHitbox : Actor +{ + int accdamage; + + Default + { + +NOGRAVITY; + -SOLID; + +DONTSPLASH; + +SHOOTABLE; + Health int.max; + } + override void PostBeginPlay() + { + if ( !target ) + { + Destroy(); + return; + } + accdamage = target.Health; + A_SetSize(target.radius,target.height); + } + override void Tick() + { + Super.Tick(); + if ( !target || (target.Health > 0) || target.InStateSequence(target.CurState,target.FindState("XDeath")) ) + { + Destroy(); + return; + } + SetOrigin(target.pos,true); + A_SetSize(target.radius,target.height); + } + override int DamageMobj( Actor inflictor, Actor source, int damage, Name mod, int flags, double angle ) + { + accdamage -= damage; + int gibhealth = (target.GibHealth==int.min)?-target.SpawnHealth():target.GibHealth; + if ( accdamage < gibhealth ) + { + // force gib (cheap ATM) + State gib = target.FindState("XDeath"); + if ( gib ) target.SetState(gib); + Destroy(); + } + return 0; + } +} + Class GenericFlash : HUDMessageBase { Color col; @@ -1445,6 +1497,15 @@ Class UTMainHandler : StaticEventHandler Screen.DrawTexture(tex,true,0,0,DTA_VirtualWidth,1024,DTA_VirtualHeight,768); } + override void WorldThingDied( WorldEvent e ) + { + if ( e.Thing.bDONTGIB ) return; + // attach damage accumulator for corpses + if ( !CVar.GetCVar('flak_corpsedamage').GetBool() ) return; + let a = Actor.Spawn("ShredCorpseHitbox",e.Thing.pos); + a.target = e.Thing; + } + static void DoFlash( Actor camera, Color c, int duration ) { QueuedFlash qf = new("QueuedFlash");