diff --git a/TODO.md b/TODO.md index 5b9758fb8..f4806c681 100644 --- a/TODO.md +++ b/TODO.md @@ -3,7 +3,6 @@ - Extra Demolitionist animations (swimming, additional gestures) - Dual wielding Explodium Gun - Quick grenade function (Explodium Mag) - - Parrying for hitscan weapons (currently parrying only handles vanilla LineAttack) - Fun options - Omnibusting (all weapons can bust walls) - Infinite fuel diff --git a/language.version b/language.version index 843aae16c..819e2f6aa 100644 --- a/language.version +++ b/language.version @@ -1,2 +1,2 @@ [default] -SWWM_MODVER="\chSWWM \cwGZ\c- 0.9b r549 (Tue 15 Sep 19:18:10 CEST 2020)"; +SWWM_MODVER="\chSWWM \cwGZ\c- 0.9b r549 (Sat 19 Sep 11:20:53 CEST 2020)"; diff --git a/sndinfo.txt b/sndinfo.txt index a5d0e2ff3..931a4548d 100644 --- a/sndinfo.txt +++ b/sndinfo.txt @@ -357,6 +357,7 @@ $random demolitionist/whitm { demolitionist/whitm1 demolitionist/whitm2 demoliti demolitionist/whitl1 sounds/demolitionist/demowhitl1.ogg demolitionist/whitl2 sounds/demolitionist/demowhitl2.ogg $random demolitionist/whitl { demolitionist/whitl1 demolitionist/whitl2 } +demolitionist/buttslam sounds/demolitionist/demobutt.ogg $playersound demolitionist neutral *grunt DSEMPTY $playeralias demolitionist neutral *pain100 demolitionist/lopain diff --git a/sounds/demolitionist/demobutt.ogg b/sounds/demolitionist/demobutt.ogg new file mode 100644 index 000000000..70b434581 Binary files /dev/null and b/sounds/demolitionist/demobutt.ogg differ diff --git a/zscript/swwm_handler.zsc b/zscript/swwm_handler.zsc index 8bbc98221..7514b9371 100644 --- a/zscript/swwm_handler.zsc +++ b/zscript/swwm_handler.zsc @@ -571,7 +571,7 @@ Class SWWMHandler : EventHandler override void PlayerEntered( PlayerEvent e ) { - // create some static thinkers for this player + // create some static thinkers for this player if needed PlayerInfo p = players[e.playernumber]; SWWMTradeHistory th = SWWMTradeHistory.Find(p); if ( !th ) @@ -634,13 +634,30 @@ Class SWWMHandler : EventHandler // reset combat tracker if ( !swwm_notrack ) SWWMCombatTracker.Spawn(players[e.playernumber].mo); - // initialize some player vars if ( p.mo is 'Demolitionist' ) { + // reinitialize Demolitionist(p.mo).dashfuel = Demolitionist(p.mo).default.dashfuel; Demolitionist(p.mo).last_boost = 0; Demolitionist(p.mo).last_kick = 0; + // cancel dash/boost + p.mo.A_StopSound(CHAN_JETPACK); + Demolitionist(p.mo).fuelcooldown = 0.; + Demolitionist(p.mo).dashcooldown = 0.; + Demolitionist(p.mo).dashboost = 0.; + Demolitionist(p.mo).dashsnd = false; + // prevent sudden stomping if we were previously falling + Demolitionist(p.mo).lastvelz = p.mo.vel.z; + // early cancel gestures + if ( p.ReadyWeapon is 'SWWMGesture' ) + { + p.PendingWeapon = SWWMGesture(p.ReadyWeapon).formerweapon; + p.SetPSprite(PSP_WEAPON,p.ReadyWeapon.ResolveState("Deselect")); + } } + // reset score (optional) if inventory should be cleared + if ( level.removeitems && !e.IsReturn && swwm_resetscore ) + c.credits = c.hcredits = 0; } override void PlayerRespawned( PlayerEvent e ) diff --git a/zscript/swwm_hud.zsc b/zscript/swwm_hud.zsc index 49ec08162..8a5493afd 100644 --- a/zscript/swwm_hud.zsc +++ b/zscript/swwm_hud.zsc @@ -173,7 +173,7 @@ Class SWWMStatusBar : BaseStatusBar { // treat as chat message printlevel = PRINT_CHAT; - outline = "Korax: "..outline; + outline = "\cmKorax\c-: "..outline; } let m = new("MsgLine"); m.str = outline.Left(outline.Length()-1); // strip newline diff --git a/zscript/swwm_inventory.zsc b/zscript/swwm_inventory.zsc index ebd209706..c9c926997 100644 --- a/zscript/swwm_inventory.zsc +++ b/zscript/swwm_inventory.zsc @@ -739,13 +739,7 @@ Class ParryField : Actor +NOCLIP; +DONTSPLASH; +NOTELEPORT; - +SHOOTABLE; - +NONSHOOTABLE; - +NOBLOOD; - +DONTTHRUST; +NOINTERACTION; - Health int.max; - Mass int.max; Radius 20; Height 40; } @@ -814,73 +808,6 @@ Class ParryField : Actor } if ( --special1 <= 0 ) Destroy(); } - - override bool CanCollideWith( Actor other, bool passive ) - { - return false; - } - - override int DamageMobj( Actor inflictor, Actor source, int damage, Name mod, int flags, double angle ) - { - if ( (flags&DMG_INFLICTOR_IS_PUFF) && (source != master) ) - { - Vector3 vdir = (cos(angle),sin(angle),0); - Vector3 vpos = inflictor.pos; // puff goes here - let raging = RagekitPower(master.FindInventory("RagekitPower")); - let i = Spawn(raging?"BigPunchImpact":"PunchImpact",vpos); - if ( raging ) raging.DoHitFX(); - i.angle = angle+180; - i.bAMBUSH = true; - // deflect hitscan - A_StartSound("misc/ricochet",CHAN_VOICE,CHANF_OVERLAP,.7); - A_QuakeEx(3,3,3,10,0,64,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:.2); - A_StartSound("demolitionist/parry",CHAN_WEAPON); - double mult = 1.5; - if ( raging ) mult = 8.; - if ( (level.maptime > lasteggtic) && !Random[Parry](0,4) ) - { - for ( int i=1; i<6; i++ ) - { - let r = Spawn("ParryRing",vpos); - r.specialf1 = i*.04; - } - mult *= 2.; - A_StartSound("misc/soulsparry",CHAN_ITEM,CHANF_OVERLAP,1.,.5); - lasteggtic = level.maptime+5; - } - // three options: - switch ( Random[Parry](0,7) ) - { - case 0: - case 1: - case 2: - // 1. just block the bullet, making it bounce off - let b = Spawn("ReflectedBullet",vpos); - b.angle = angle; - b.target = master; - b.vel = (-vdir+(FRandom[Parry](-.4,.4),FRandom[Parry](-.4,.4),FRandom[Parry](-.4,.4))).unit()*FRandom[Parry](1,2)*mult+(0,0,4); - break; - case 3: - case 4: - case 5: - // 2. ricochet in random direction - Vector3 rdir = (-vdir+(FRandom[Parry](-.6,.6),FRandom[Parry](-.6,.6),FRandom[Parry](-.6,.6))).unit(); - bSHOOTABLE = false; - master.LineAttack(atan2(rdir.y,rdir.x),8000,asin(-rdir.z),int(damage*mult),mod,inflictor.GetClass(),LAF_ABSPOSITION,null,vpos.z,vpos.x,vpos.y); - bSHOOTABLE = true; - break; - case 6: - case 7: - // 3. ricochet directly back to source - Vector3 tdir = source?(level.Vec3Diff(vpos,source.Vec3Offset(0,0,source.height/2))).unit():(-vdir); - bSHOOTABLE = false; - master.LineAttack(atan2(tdir.y,tdir.x),8000,asin(-tdir.z),int(damage*mult),mod,inflictor.GetClass(),LAF_ABSPOSITION,null,vpos.z,vpos.x,vpos.y); - bSHOOTABLE = true; - break; - } - } - return 0; - } } Class UseList diff --git a/zscript/swwm_player.zsc b/zscript/swwm_player.zsc index 40a9f45c9..1550278d5 100644 --- a/zscript/swwm_player.zsc +++ b/zscript/swwm_player.zsc @@ -275,14 +275,7 @@ Class Demolitionist : PlayerPawn override void GiveDefaultInventory() { Super.GiveDefaultInventory(); - // reset score (optional) - if ( swwm_resetscore ) - { - let creds = SWWMCredits.Find(player); - if ( creds ) creds.credits = creds.hcredits = 0; - } // preloaded gun - let dp = DeepImpact(FindInventory("DeepImpact")); let eg = ExplodiumGun(FindInventory("ExplodiumGun")); if ( !eg ) return; eg.clipcount = 7; @@ -719,7 +712,13 @@ Class Demolitionist : PlayerPawn if ( raging ) flg |= DMG_FOILINVUL; if ( !a.player && !a.bDONTBLAST ) a.bBLASTED = true; int dmg = int(15+spd*2.5); - if ( dir dot viewdir < -.3 ) dmg *= 3; // BUTTSLAM + bool buttslam = false; + // BUTTSLAM + if ( dir dot viewdir < -.3 ) + { + dmg *= 3; + buttslam = true; + } if ( a.bSHOOTABLE ) { dmg = a.DamageMobj(self,self,dmg,'Dash',flg); @@ -728,6 +727,12 @@ Class Demolitionist : PlayerPawn a.TraceBleed(dmg,self); a.SpawnBlood(level.Vec3Offset(pos,diff/2),atan2(dir.y,dir.x)+180,dmg); } + if ( buttslam && (!a || (a.Health <= 0)) ) + { + A_StartSound("demolitionist/buttslam",CHAN_DAMAGE,CHAN_OVERLAP,1.,.2); + Spawn("SWWMItemFog",level.Vec3Offset(pos,diff/2)); + A_QuakeEx(8,8,8,8,0,3000,"",QF_RELATIVE|QF_SCALEDOWN,falloff:300,rollIntensity:1.); + } } if ( raging ) { @@ -760,7 +765,13 @@ Class Demolitionist : PlayerPawn // see if we can bust it let tempme = new("LineTracer"); // gross hack to pass needed data int dmg = int(128+spd*20); - if ( dir dot viewdir < -.3 ) dmg *= 3; // BUTTSLAM + bool buttslam = false; + // BUTTSLAM + if ( dir dot viewdir < -.3 ) + { + dmg *= 3; + buttslam = true; + } if ( ff ) tempme.Results.ffloor = ff; tempme.Results.HitSector = CeilingSector; tempme.Results.HitType = TRACE_HitCeiling; @@ -774,6 +785,12 @@ Class Demolitionist : PlayerPawn A_StartSound("demolitionist/bump",CHAN_DAMAGE,CHANF_OVERLAP); busted = true; raging.DoHitFX(); + if ( buttslam ) + { + A_StartSound("demolitionist/buttslam",CHAN_DAMAGE,CHANF_OVERLAP,1.,.2); + Spawn("SWWMItemFog",Vec3Offset(0,0,Height)); + A_QuakeEx(8,8,8,8,0,3000,"",QF_RELATIVE|QF_SCALEDOWN,falloff:300,rollIntensity:1.); + } } } if ( !busted ) @@ -802,9 +819,12 @@ Class Demolitionist : PlayerPawn // check for wall collision FCheckPosition tm; Vector2 steppy = dir.xy*spd/8.; + Vector3 oldpos = pos; + bool oldthru = bTHRUACTORS; + bTHRUACTORS = true; for ( int i=1; i<=8; i++ ) { - if ( (spd > 0) && !bumped && !CheckMove(Vec2Offset(steppy.x*i,steppy.y*i),PCM_DROPOFF|PCM_NOACTORS,tm) && BlockingLine ) + if ( (spd > 0) && !bumped && !TryMove(Vec2Offset(steppy.x,steppy.y),1,false,tm) && BlockingLine ) { Vector3 wallnorm = (-BlockingLine.delta.y,BlockingLine.delta.x,0).unit(); int lside = 1; @@ -821,7 +841,13 @@ Class Demolitionist : PlayerPawn // see if we can bust it let tempme = new("LineTracer"); // gross hack to pass needed data int dmg = int(128+spd*20); - if ( dir dot viewdir < -.3 ) dmg *= 3; // BUTTSLAM + bool buttslam = false; + // BUTTSLAM + if ( dir dot viewdir < -.3 ) + { + dmg *= 3; + buttslam = true; + } tempme.Results.HitLine = BlockingLine; tempme.Results.HitType = TRACE_HitWall; tempme.Results.Side = lside; @@ -844,6 +870,12 @@ Class Demolitionist : PlayerPawn ps.special1 = int(15+spd*2.5); A_StartSound("demolitionist/bump",CHAN_DAMAGE,CHANF_OVERLAP); raging.DoHitFX(); + if ( buttslam ) + { + A_StartSound("demolitionist/buttslam",CHAN_DAMAGE,CHANF_OVERLAP,1.,.2); + Spawn("SWWMItemFog",Vec3Offset(dir.x*radius,dir.y*radius,(tempme.Results.Tier==TIER_UPPER)?Height:(tempme.Results.Tier==TIER_LOWER)?0:(Height/2))); + A_QuakeEx(8,8,8,8,0,3000,"",QF_RELATIVE|QF_SCALEDOWN,falloff:300,rollIntensity:1.); + } continue; } } @@ -873,6 +905,8 @@ Class Demolitionist : PlayerPawn break; } } + SetOrigin(oldpos,true); + bTHRUACTORS = oldthru; } else if ( isboosting && (dashboost > 0.) ) { @@ -964,8 +998,8 @@ Class Demolitionist : PlayerPawn } override void MovePlayer() { - if ( InStateSequence(CurState,FindState("Dash")) ) - player.cmd.forwardmove = player.cmd.sidemove = 0; + bool isdashing = InStateSequence(CurState,FindState("Dash")); + if ( isdashing ) player.cmd.forwardmove = player.cmd.sidemove = 0; if ( (waterlevel < 2) && (bFly || bFlyCheat) && !(player.cheats&CF_NOCLIP2) ) { player.onground = false; @@ -1049,7 +1083,7 @@ Class Demolitionist : PlayerPawn guidepitch *= .9; guideroll *= .9; // anchor to ground when going down steps - if ( lastground && !player.onground && !bFly && !bFlyCheat && (waterlevel < 2) && (abs(pos.z-floorz) <= maxdropoffheight) && (player.jumptics == 0) && (vel.z < 0) ) + if ( lastground && !player.onground && !bFly && !bFlyCheat && (waterlevel < 2) && (abs(pos.z-floorz) <= maxdropoffheight) && (player.jumptics == 0) && (vel.z < 0) && !isdashing ) { // test for gap crossing (i.e: climbing up platforms with holes between them) Vector3 storepos = pos; @@ -1082,12 +1116,10 @@ Class Demolitionist : PlayerPawn if ( fm ) dodge += (fm>0)?X:-X; if ( sm ) dodge += (sm>0)?Y:-Y; if ( player.cmd.buttons&BT_CROUCH ) dodge = (0,0,-1); // death from above - if ( player.onground ) dodge.z = max(0,dodge.z); if ( dodge == (0,0,0) ) dodge.xy = RotateVector((1,0),angle); - if ( (waterlevel < 2) && !(bFly || bFlyCheat) ) - dodge.z += (player.cmd.buttons&BT_CROUCH)?-.05:.15; if ( !level.IsJumpingAllowed() ) dodge.z = min(0,dodge.z); - if ( (dodge.length() > 0) && (dashcooldown <= 0) && (dashfuel > 20.) && player.cmd.buttons&BT_USER2 && (player.onground || level.IsJumpingAllowed()) && (gamestate == GS_LEVEL) ) + if ( player.onground ) dodge.z = max(0,dodge.z); + if ( (dodge.length() > 0) && (dashcooldown <= 0) && (dashfuel > 20.) && player.cmd.buttons&BT_USER2 && (player.onground || level.IsJumpingAllowed() || (player.cmd.buttons&BT_CROUCH)) && (gamestate == GS_LEVEL) ) { dashdir = dodge.unit(); dashcooldown = 10;