diff --git a/GunLore.md b/GunLore.md index e0b1766..920f8be 100644 --- a/GunLore.md +++ b/GunLore.md @@ -167,8 +167,6 @@ Any targets unlucky enough to stand in its way will be pushed away. Secondary fire: "Inverts the polarity" of the charge, which results in the complete opposite effect, causing targets to instead be pulled towards you. -The secondary fire can be useful to pick up items that are way out of reach. - Since the charge rod rapidly extends on shoot, both fire modes additionally deal considerable melee damage to anything that's too close. diff --git a/Readme.md b/Readme.md index a452601..b4bb30d 100644 --- a/Readme.md +++ b/Readme.md @@ -35,6 +35,7 @@ Doom Tournament (currently the devel branch is required). - Protomag (slot 2) (replaces pistol) - Dual Protomags - Quadshot (slot 3) (replaces shotguns) + - Stunner (slot 4) (replaces chainsaw) - Fireblaster (slot 5) (replaces rocket launcher) - Peacemaker (slot 8) (rare spawn in backpacks) - Demolisher (slot 9) (replaces bfg9000) @@ -71,7 +72,6 @@ Doom Tournament (currently the devel branch is required). ## In progress - - Stunner (slot 4) (replaces chainsaw) - Flamethrower (slot 6) (replaces plasma rifle) - Impaler (slot 7) (replaces plasma rifle) diff --git a/modeldef.stunner b/modeldef.stunner index 4dddc2b..fa7f4bb 100644 --- a/modeldef.stunner +++ b/modeldef.stunner @@ -13,6 +13,48 @@ Model "Stunner" FrameIndex STNP A 1 0 } +Model "StunTrail" +{ + Path "models" + Model 0 "FatRing_d.3d" + Skin 0 "JRingEx2.png" + PitchOffset 90 + Scale 0.01 0.05 0.05 + DONTCULLBACKFACES + USEACTORPITCH + USEACTORROLL + + FrameIndex FATR A 0 11 + FrameIndex FATR B 0 12 + FrameIndex FATR C 0 13 + FrameIndex FATR D 0 14 + FrameIndex FATR E 0 15 +} + +Model "StunProj" +{ + Path "models" + Model 0 "FatRing_d.3d" + Skin 0 "JRingEx2.png" + PitchOffset 90 + Scale 0.1 0.5 0.5 + DONTCULLBACKFACES + USEACTORPITCH + USEACTORROLL + + FrameIndex FATR A 0 0 + FrameIndex FATR B 0 1 + FrameIndex FATR C 0 2 + FrameIndex FATR D 0 3 + FrameIndex FATR E 0 4 + FrameIndex FATR F 0 5 + FrameIndex FATR G 0 6 + FrameIndex FATR H 0 7 + FrameIndex FATR I 0 8 + FrameIndex FATR J 0 9 + FrameIndex FATR K 0 10 +} + Model "Stunner" { Path "models" diff --git a/models/JRingex2.png b/models/JRingex2.png new file mode 100644 index 0000000..d02f9a3 Binary files /dev/null and b/models/JRingex2.png differ diff --git a/zscript/biggun.zsc b/zscript/biggun.zsc index b6b87d3..6b843b3 100644 --- a/zscript/biggun.zsc +++ b/zscript/biggun.zsc @@ -102,7 +102,7 @@ Class FatRing : Actor { Super.Tick(); if ( isFrozen() ) return; - A_FadeOut(1/21.,0); + A_FadeOut(1/19.,0); } States { @@ -128,6 +128,7 @@ Class BigBlast : Actor override void PostBeginPlay() { Super.PostBeginPlay(); + A_AlertMonsters(); A_Explode(50+special1,150); A_QuakeEx(4,4,4,10,0,300,"",QF_RELATIVE|QF_SCALEDOWN,falloff:150,rollintensity:0.2); A_PlaySound("big/blast",CHAN_VOICE,pitch:FRandom[BigGun](0.8,1.2)); @@ -326,6 +327,7 @@ Class BigGun : UnrealWeapon l.hitactor.DamageMobj(invoker,self,l.hitdamage,'BigShot',DMG_THRUSTLESS); UTMainHandler.DoKnockback(l.hitactor,l.x,90000.); let b = Spawn("BigBlast",l.hitlocation-l.x*8.); + b.target = self; b.special1 = l.hitdamage; b.angle = atan2(l.x.y,l.x.x); b.pitch = asin(-l.x.z); @@ -349,6 +351,7 @@ Class BigGun : UnrealWeapon if ( !invoker.t.Results.Side ) hitnormal *= -1; } let b = Spawn("BigBlast",invoker.t.Results.HitPos+hitnormal*8.); + b.target = self; b.special1 = int(invoker.t.penetration); b.angle = atan2(hitnormal.y,hitnormal.x); b.pitch = asin(-hitnormal.z); diff --git a/zscript/flamegun.zsc b/zscript/flamegun.zsc index e8bac2b..bba4987 100644 --- a/zscript/flamegun.zsc +++ b/zscript/flamegun.zsc @@ -125,7 +125,7 @@ Class UFireball : Actor { A_PlaySound("flamegun/exp",CHAN_VOICE,pitch:1.2); Spawn("UFireLight",pos); - A_Explode(GetMissileDamage(0,0),60,XF_HURTSOURCE); + A_Explode(GetMissileDamage(0,0),60); UTMainHandler.DoBlast(self,60,9000); } A_SprayDecal("SmallRocketBlast"); @@ -184,7 +184,7 @@ Class UFireball2 : UFireball action void A_FireballExplo2() { scale *= 2.; - A_Explode(GetMissileDamage(0,0),90,XF_HURTSOURCE); + A_Explode(GetMissileDamage(0,0),90); UTMainHandler.DoBlast(self,90,12000); Vector3 dir = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch)); int numpt = Random[ExploS](10,15); diff --git a/zscript/gatling.zsc b/zscript/gatling.zsc index fa3c965..3fe33f9 100644 --- a/zscript/gatling.zsc +++ b/zscript/gatling.zsc @@ -68,6 +68,7 @@ Class SMiniShell : FastProjectile action void A_ShellExplode() { bFORCEXYBILLBOARD = true; + A_AlertMonsters(); A_SetRenderStyle(1.0,STYLE_Add); A_NoGravity(); A_Explode(150,50,XF_HURTSOURCE|XF_EXPLICITDAMAGETYPE,damagetype:'exploded'); diff --git a/zscript/stunner.zsc b/zscript/stunner.zsc index 174caf3..84f489c 100644 --- a/zscript/stunner.zsc +++ b/zscript/stunner.zsc @@ -24,10 +24,247 @@ Class StunnerAmmo : Ammo Class StunTrail : Actor { + Default + { + RenderStyle "Add"; + Radius 0.1; + Height 0; + +NOBLOCKMAP; + +NOGRAVITY; + +DONTSPLASH; + +NOTELEPORT; + +FORCEXYBILLBOARD; + } + override void Tick() + { + Super.Tick(); + if ( isFrozen() ) return; + A_FadeOut(1./11.,0); + } + States + { + Spawn: + FATR ABCDE 3 Bright; + Stop; + } +} + +Class StunLight : PaletteLight +{ + Default + { + Tag "DYellow"; + } +} + +Class StunTracer : LineTracer +{ + Actor owner, ignore; + + override ETraceStatus TraceCallback() + { + if ( Results.HitType == TRACE_HitActor ) + { + if ( (Results.HitActor == owner) || (Results.HitActor == ignore) ) return TRACE_Skip; + if ( Results.HitActor.bSHOOTABLE ) return TRACE_Stop; + return TRACE_Skip; + } + else if ( (Results.HitType == TRACE_HitWall) && (Results.Tier == TIER_Middle) ) + { + if ( !Results.HitLine.sidedef[1] || (Results.HitLine.Flags&(Line.ML_BlockHitscan|Line.ML_BlockEverything)) ) + return TRACE_Stop; + return TRACE_Skip; + } + return TRACE_Stop; + } } Class StunProj : Actor { + StunTracer t; + Vector3 tracedir; + bool moving; + double totaldist; + + override void PostBeginPlay() + { + Super.PostBeginPlay(); + t = new("StunTracer"); + t.owner = target; + t.ignore = self; + moving = true; + } + override void Tick() + { + Super.Tick(); + if ( isFrozen() ) return; + if ( !moving ) + { + A_FadeOut(1/19.,0); + return; + } + // step trace + tracedir = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch)); + t.Trace(pos,cursector,tracedir,500,0); + totaldist += t.Results.Distance; + // spawn particles + for ( int i=10; i= 10000.0 ) + { + // reposition and explode on air + SetOrigin(t.Results.HitPos-t.Results.HitVector*4,false); + StunExplode(); + } + else if ( t.Results.HitType == TRACE_HitNone ) + { + // reposition + SetOrigin(t.Results.HitPos+t.Results.HitVector,false); + angle = atan2(t.Results.HitVector.y,t.Results.HitVector.x); + pitch = asin(-t.Results.HitVector.z); + } + else if ( t.Results.HitType == TRACE_HitActor ) + { + // reposition and explode on actor + SetOrigin(t.Results.HitPos-t.Results.HitVector*4,false); + StunExplode(); + Actor a = t.Results.HitActor; + a.DamageMobj(self,target,max(1,int(1.1*specialf1)),'jolted',DMG_USEANGLE,atan2(t.Results.HitVector.y,t.Results.HitVector.x)); + if ( !a.bDONTTHRUST ) + { + UTMainHandler.DoKnockback(a,t.Results.HitVector,(bAMBUSH?-22000:26000)*specialf1); + a.vel.z += 2.*specialf1; + } + angle = atan2(t.Results.HitVector.y,t.Results.HitVector.x); + pitch = asin(-t.Results.HitVector.z); + } + else + { + // reposition and explode on wall + SetOrigin(t.Results.HitPos-t.Results.HitVector*4,false); + A_SprayDecal("ShockMark",16); + Vector3 HitNormal = t.Results.HitVector; + if ( t.Results.HitType == TRACE_HitWall ) + { + t.Results.HitLine.RemoteActivate(target,t.Results.Side,SPAC_Impact,pos); + // calculate normal + HitNormal = (-t.Results.HitLine.delta.y,t.Results.HitLine.delta.x,0).unit(); + if ( t.Results.Side == 0 ) HitNormal *= -1; + } + else if ( t.Results.HitType == TRACE_HitFloor ) + { + if ( t.Results.ffloor ) HitNormal = -t.Results.ffloor.top.Normal; + else HitNormal = t.Results.HitSector.floorplane.Normal; + } + else if ( t.Results.HitType == TRACE_HitCeiling ) + { + if ( t.Results.ffloor ) HitNormal = -t.Results.ffloor.bottom.Normal; + else HitNormal = t.Results.HitSector.ceilingplane.Normal; + } + StunExplode(); + angle = atan2(HitNormal.y,HitNormal.x); + pitch = asin(-HitNormal.z); + } + } + void StunExplode() + { + moving = false; + SetStateLabel("Death"); + A_Explode(int(0.6*specialf1),50); + A_QuakeEx(1,1,1,3,0,250,"",QF_RELATIVE|QF_SCALEDOWN,falloff:120,rollintensity:0.2); + A_PlaySound("stun/hit",CHAN_VOICE,pitch:FRandom[Stunner](1.5,1.9)-0.08*specialf1); + UTMainHandler.DoBlast(self,50,(bAMBUSH?-7000:11000)*specialf1); + Vector3 dir = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch)); + int numpt = Random[ExploS](10,15); + for ( int i=0; i= (d.HitActor.pos.z+d.HitActor.height*0.81) ) + dmg = d.HitActor.DamageMobj(invoker,self,dmg*2,'Decapitated',DMG_THRUSTLESS); + else dmg = d.HitActor.DamageMobj(invoker,self,dmg,'impact',DMG_THRUSTLESS); + UTMainHandler.DoKnockback(d.HitActor,x,4000*invoker.chargesize); + if ( d.HitActor.bNOBLOOD ) + { + let p = Spawn("StunnerImpact",d.HitLocation-d.HitDir*4); + p.angle = atan2(d.HitDir.y,d.HitDir.x); + p.pitch = asin(-d.HitDir.z); + } + else + { + d.HitActor.TraceBleed(dmg,invoker); + d.HitActor.SpawnBlood(d.HitLocation,atan2(d.HitDir.y,d.HitDir.x)+180,dmg); + } + } + else if ( d.HitType != TRACE_HitNone ) + { + let p = Spawn("StunnerImpact",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_BeginCharge() {