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).
This commit is contained in:
Marisa the Magician 2018-09-05 18:56:04 +02:00
commit 1c0f7d08a5
11 changed files with 99 additions and 34 deletions

View file

@ -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

View file

@ -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

View file

@ -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";

View file

@ -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"

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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));

View file

@ -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);

View file

@ -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");