From b5947709f7b2b1cd05906cfa151af49b039f9dbb Mon Sep 17 00:00:00 2001 From: Marisa Kirisame Date: Sat, 20 Jun 2020 17:19:13 +0200 Subject: [PATCH] Final round of tuning for wall busting, it's even more HD-like now. Add option to disable unrestricted Wallbuster destruction. Add wall penetration to Silver Bullet JET. --- cvarinfo.txt | 3 +- language.def_base | 2 +- language.def_menu | 2 + language.es_base | 2 +- language.es_menu | 2 + language.version | 2 +- zscript/swwm_cbt.zsc | 159 ++++++++++++++++++------------- zscript/swwm_common.zsc | 138 +++++++++++++++++++++++++++ zscript/swwm_player.zsc | 2 +- zscript/swwm_shot.zsc | 4 +- zscript/swwm_thiccboolet.zsc | 175 ++++++++++++++++++++++++++++++++++- 11 files changed, 417 insertions(+), 74 deletions(-) diff --git a/cvarinfo.txt b/cvarinfo.txt index 2a3698792..5df97c615 100644 --- a/cvarinfo.txt +++ b/cvarinfo.txt @@ -38,7 +38,7 @@ server int swwm_revivecooldown = 30; // cooldown after using a revive, in secon user int swwm_intertype = 0; // 0 - standard bg // 1 - fanart // 2 - 4komas -server bool swwm_balluse = false; // lead ball can "press" switches remotely +server bool swwm_balluse = true; // lead ball can "press" switches remotely user bool swwm_bosshealthbars = true; // display large healthbars for vanilla boss encounters server bool swwm_upgradebosses = true; // vanilla bosses will be "upgraded" to be less insta-die prone server bool swwm_extraalert = false; // enables A_AlertMonsters calls for certain things which may be cpu-heavy @@ -57,3 +57,4 @@ user noarchive int swwm_cbtmeme = 0; // easter egg, hidden cvar user noarchive bool swwm_cbttime = false; // debug: times how long a reload takes server bool swwm_crouchjump = false; // allows crouch-jumping (which looks weird af but some maps may need it) user noarchive int swwm_cbtlast = 0; // last selected ammo for the wallbuster +server bool swwm_cbtall = true; // wallbuster breaks any wall, not just movable ones diff --git a/language.def_base b/language.def_base index fa877f8ec..0f5567134 100644 --- a/language.def_base +++ b/language.def_base @@ -723,7 +723,7 @@ SWWM_INTERTIP26 = "You can press switches and open doors by punching them. This SWWM_INTERTIP27 = "The fire from the Spreadgun's Napalm rounds will spread around to nearby enemies (or yourself). Remember, if you're on fire, stop, drop and roll... or just spin around, it works the same."; SWWM_INTERTIP28 = "Incendiary ammunition is ineffective underwater, for obvious reasons."; SWWM_INTERTIP29 = "My girlfriends are really cute. Sorry, I had to say it."; -SWWM_INTERTIP30 = "The Silver Bullet fires with such a force that its bullets leave shockwaves as they rip through the air (and enemies), dealing additional damage."; +SWWM_INTERTIP30 = "The Silver Bullet fires with such a force that its bullets leave shockwaves as they rip through the air (and enemies), dealing additional damage. It can also pierce through some walls."; // intermission fanart SWWM_FANART = "Art: "; SWWM_NFANART = "2"; diff --git a/language.def_menu b/language.def_menu index d3c384cf3..0271dccbe 100644 --- a/language.def_menu +++ b/language.def_menu @@ -99,6 +99,7 @@ SWWM_BLOOD = "Enable Custom Blood"; SWWM_FUZZ = "Enable Animated Menu BG"; SWWM_BUSTERPAUSE = "Pause on Wallbuster Reload"; SWWM_CROUCHJUMP = "Allow Crouch-Jump"; +SWWM_CBTALL = "Unlimited Wallbuster Destruction"; TOOLTIP_SWWM_VOICETYPE = "Sets the voice pack for the player."; TOOLTIP_SWWM_MUTEVOICE = "Control what gets muted, if you'd rather have a more silent protagonist."; TOOLTIP_SWWM_FLASHSTRENGTH = "Screen flashes usually happen when firing some weapons, you can lower this if these effects are harmful for you."; @@ -144,6 +145,7 @@ TOOLTIP_SWWM_BLOOD = "Please note that these effects are kinda cheap and perform TOOLTIP_SWWM_FUZZ = "Toggling this off is recommended if you're recording/streaming as this effect can harm video quality."; TOOLTIP_SWWM_CBTPAUSE = "The game will pause while the Wallbuster reload menu is open (only in singleplayer)."; TOOLTIP_SWWM_CROUCHJUMP = "Allow the player to crouch-jump (which may be needed on some maps). Note that there are no animations for this and it'll look weird."; +TOOLTIP_SWWM_CBTALL = "Allows the Wallbuster to break pretty much anything, not just doors and platforms. Note that this can break some maps, which is why this option is here."; // knowledge base SWWM_COMINGSOON = "(coming soon)"; SWWM_MISSTAB = "Mission"; diff --git a/language.es_base b/language.es_base index 8c8a9717f..f63feb036 100644 --- a/language.es_base +++ b/language.es_base @@ -707,7 +707,7 @@ SWWM_INTERTIP26 = "Puedes activar objetos y abrir puertas a puñetazos. Esto tam SWWM_INTERTIP27 = "Las llamas de los cartuchos de Napalm del Trabuco se extenderán a otros enemigos cercanos (o a ti). Recuerda, si estás ardiendo, tírate al suelo y rueda... o ponte a dar vueltas, funciona igual."; SWWM_INTERTIP28 = "La munición incendiaria es inefectiva bajo el agua, por razones obvias."; SWWM_INTERTIP29 = "Mis novias son muy cuquis. Lo siento, es que tenía que decirlo."; -SWWM_INTERTIP30 = "El Silver Bullet dispara con una fuerza tal que sus balas liberan ondas de choque al atravesar el aire (y los enemigos), causando daño adicional."; +SWWM_INTERTIP30 = "El Silver Bullet dispara con una fuerza tal que sus balas liberan ondas de choque al atravesar el aire (y los enemigos), causando daño adicional. También puede atravesar algunas paredes."; // intermission fanart SWWM_FANART = "Arte: "; // intermission 4komas (TBD) diff --git a/language.es_menu b/language.es_menu index bd3e56b58..f7afa5f4c 100644 --- a/language.es_menu +++ b/language.es_menu @@ -96,6 +96,7 @@ SWWM_BLOOD = "Habilitar Sangre Personalizada"; SWWM_FUZZ = "Habilitar Fondo Animado de Menú"; SWWM_BUSTERPAUSE = "Pausar en Regarga de Wallbuster"; SWWM_CROUCHJUMP = "Permitir Salto Agachado"; +SWWM_CBTALL = "Destrucción Ilimitada de Wallbuster"; TOOLTIP_SWWM_VOICETYPE = "Selecciona el pack de voz para el jugador."; TOOLTIP_SWWM_MUTEVOICE = "Controla lo que se mutea, si prefieres tener un protagonista más silencioso."; TOOLTIP_SWWM_FLASHSTRENGTH = "Los destellos en pantalla suelen ocurrir al disparar algunas armas, puedes reducirlo si este tipo de effectos te causan malestar."; @@ -141,6 +142,7 @@ TOOLTIP_SWWM_BLOOD = "Ten en cuenta que estos efectos son un poco cutres y bajan TOOLTIP_SWWM_FUZZ = "Desactivar ésto es recomendado si estás grabando o haciendo streaming, ya que este effecto puede dañar la calidad del vídeo."; TOOLTIP_SWWM_CBTPAUSE = "El juego será pausado mientras el menú de recarga de Wallbuster está abierto (sólo en modo de un jugador)."; TOOLTIP_SWWM_CROUCHJUMP = "Permite al jugador agacharse saltando (lo cual puede ser necesario en algunos mapas). Ten en cuenta que no hay animaciones para esto, así que se verá raro."; +TOOLTIP_SWWM_CBTALL = "Permite a la Wallbuster romper casi cualquier cosa, no solo puertas y plataformas. Ten en cuenta que esto puede romper algunos mapas, razón de que haya esta opción."; // knowledge base SWWM_COMINGSOON = "(próximamente)"; SWWM_MISSTAB = "Misión"; diff --git a/language.version b/language.version index 4112b8e8e..1608a73eb 100644 --- a/language.version +++ b/language.version @@ -1,2 +1,2 @@ [default] -SWWM_MODVER="\cxSWWM GZ\c- r364 (Sat 20 Jun 11:49:29 CEST 2020)"; +SWWM_MODVER="\cxSWWM GZ\c- r365 (Sat 20 Jun 17:19:13 CEST 2020)"; diff --git a/zscript/swwm_cbt.zsc b/zscript/swwm_cbt.zsc index 79452f84c..b41aad065 100644 --- a/zscript/swwm_cbt.zsc +++ b/zscript/swwm_cbt.zsc @@ -448,6 +448,7 @@ Class BusterWall : Thinker bool busted; Vector3 bustdir; int busttics; + double cutheight; // cached Vector3 boundsmin, boundsmax, step; @@ -513,7 +514,7 @@ Class BusterWall : Thinker } } - static void Bust( TraceResults d, int accdamage, Actor instigator, Vector3 x ) + static void Bust( TraceResults d, int accdamage, Actor instigator, Vector3 x, double hitz ) { // we can't blow up 3D floors (yet) if ( d.ffloor ) return; @@ -521,7 +522,7 @@ Class BusterWall : Thinker int hp; if ( d.HitType == TRACE_HitWall ) { - // onesided wall? no bust + // onesided wall? no bust (TODO: bust polyobjects) if ( !d.HitLine.sidedef[1] ) return; // sector is opposite of side hit hs = d.HitLine.sidedef[!d.Side].sector; @@ -537,43 +538,54 @@ Class BusterWall : Thinker int lcnt = 0; for ( int i=0; i= -4. ) return; - } - else - { - thisheight = hs.FindHighestFloorPoint(); - othersheight = hs.FindLowestFloorSurrounding(); - if ( (thisheight-othersheight) <= 4. ) return; - } - partheight = abs(thisheight-othersheight); + // Check if it's a door + if ( !swwm_cbtall && !SWWMUtility.IsDoorSector(hs,hp) ) return; let ti = ThinkerIterator.Create("BusterWall",STAT_USER); BusterWall iter, bust = null; while ( iter = BusterWall(ti.Next()) ) { if ( (iter.hitsector != hs) || (iter.hitplane != hp) ) continue; bust = iter; - bust.accdamage += accdamage; - bust.bustdir = (bust.bustdir+x)*.5; break; } + bool mnew = false; if ( !bust ) { bust = new("BusterWall"); bust.ChangeStatNum(STAT_USER); bust.hitsector = hs; - bust.accdamage = accdamage; + bust.accdamage = 0; bust.hitplane = hp; bust.bustdir = x; + mnew = true; } + bust.accdamage += accdamage; + bust.acchits.Push(accdamage); + bust.bustdir = (bust.bustdir+x)*.5; + double extracut = FRandom[Wallbuster](.01,.04)*bust.accdamage; + // is this actually sticking out? + double thisheight, othersheight, partheight, cutheight; + if ( hp ) + { + thisheight = hs.FindLowestCeilingPoint(); + othersheight = hs.FindHighestCeilingSurrounding(); + if ( (thisheight-othersheight) >= -4. ) return; + cutheight = min(hitz+extracut,othersheight-4); + } + else + { + thisheight = hs.FindHighestFloorPoint(); + othersheight = hs.FindLowestFloorSurrounding(); + if ( (thisheight-othersheight) <= 4. ) return; + cutheight = max(hitz-extracut,othersheight+4); + } + if ( hp ) bust.cutheight = mnew?cutheight:max(bust.cutheight,cutheight); + else bust.cutheight = mnew?cutheight:min(bust.cutheight,cutheight); + partheight = abs(thisheight-bust.cutheight); + // skip if we don't cut off enough + if ( partheight < 4. ) return; // skip if already busted if ( bust.busted ) return; - bust.acchits.Push(accdamage); // not enough total damage if ( bust.accdamage < 1000 ) return; // estimate sector volume @@ -591,8 +603,18 @@ Class BusterWall : Thinker if ( l.v2.p.y > b.y ) a.y = l.v2.p.y; } double girthitude = (b.x-a.x)*(b.y-a.y)*partheight; + // do a grid check to approximate "real" volume, useful for diagonal doors + double ystep = (b.y-a.y)/64.; + double xstep = (b.x-a.x)/64.; + int inspot = 0, allspot = 0; + for ( double y=a.y; y 16777216 ) return; + if ( (girthitude > 16777216) || (max(partheight,max(b.x-a.x,b.y-a.y)) > 1024) ) return; // not strong enough to bust if ( bust.accdamage < girthitude/300. ) return; bust.busted = true; @@ -606,39 +628,6 @@ Class BusterWall : Thinker if ( !rubble.IsValid() ) rubble = TexMan.CheckForTexture("LOOSERCK",TexMan.Type_Any); if ( !rubble.IsValid() ) rubble = TexMan.CheckForTexture("WASTE03",TexMan.Type_Any); if ( !rubble.IsValid() ) rubble = TexMan.CheckForTexture("SCHWAL01",TexMan.Type_Any); // Strife has a dedicated "destroyed wall" texture, nice - hs.SetTexture(hp,rubble); - hs.SetXScale(hp,1.); - hs.SetYScale(hp,1.); - hs.SetAngle(hp,0.); - for ( int i=0; i= 10) && (l.special <= 13)) + || (!part && (l.special >= 20) && (l.special <= 25)) + || (!part && (l.special == 28)) + || ((l.special >= 29) && (l.special <= 30)) + || (!part && (l.special >= 35) && (l.special <= 37)) + || (part && (l.special >= 40) && (l.special <= 45)) + || (!part && (l.special == 46)) + || (part && (l.special == 47)) + || (!part && (l.special >= 60) && (l.special <= 68)) + || (part && (l.special == 69)) + || ((l.special >= 94) && (l.special <= 96)) + || (part && (l.special == 97)) + || (!part && (l.special == 99)) + || (part && (l.special == 104)) + || (part && (l.special >= 105) && (l.special <= 106)) + || (part && (l.special >= 168) && (l.special <= 169)) + || (!part && (l.special == 172)) + || (part && (l.special >= 192) && (l.special <= 199)) + || (!part && (l.special == 200)) + || (part && (l.special >= 201) && (l.special <= 202)) + || (!part && (l.special == 203)) + || (part && (l.special == 205)) + || (!part && (l.special >= 206) && (l.special <= 207)) + || (!part && (l.special == 228)) + || (!part && (l.special >= 230) && (l.special <= 231)) + || (!part && (l.special >= 238) && (l.special <= 242)) + || ((l.special >= 245) && (l.special <= 247)) + || (part && (l.special == 249)) + || (!part && (l.special >= 250) && (l.special <= 251)) + || (part && (l.special >= 251) && (l.special <= 255)) + || (!part && (l.special >= 256) && (l.special <= 261)) + || (part && (l.special >= 262) && (l.special <= 269)) + || (!part && (l.special == 275)) + || (part && (l.special == 276)) + || (!part && (l.special == 279)) + || (part && (l.special == 280)) ) + { + let si = level.CreateSectorTagIterator(l.Args[0],l); + int idx; + while ( (idx = si.Next()) != -1 ) + if ( level.Sectors[idx] == s ) + return true; + } + } + let ti = ThinkerIterator.Create("Actor"); + Actor a; + while ( a = Actor(ti.Next()) ) + { + if ( !a.special || !a.Args[0] ) continue; + if ( (part && (a.special >= 10) && (a.special <= 13)) + || (!part && (a.special >= 20) && (a.special <= 25)) + || (!part && (a.special == 28)) + || ((a.special >= 29) && (a.special <= 30)) + || (!part && (a.special >= 35) && (a.special <= 37)) + || (part && (a.special >= 40) && (a.special <= 45)) + || (!part && (a.special == 46)) + || (part && (a.special == 47)) + || (!part && (a.special >= 60) && (a.special <= 68)) + || (part && (a.special == 69)) + || ((a.special >= 94) && (a.special <= 96)) + || (part && (a.special == 97)) + || (!part && (a.special == 99)) + || (part && (a.special == 104)) + || (part && (a.special >= 105) && (a.special <= 106)) + || (part && (a.special >= 168) && (a.special <= 169)) + || (!part && (a.special == 172)) + || (part && (a.special >= 192) && (a.special <= 199)) + || (!part && (a.special == 200)) + || (part && (a.special >= 201) && (a.special <= 202)) + || (!part && (a.special == 203)) + || (part && (a.special == 205)) + || (!part && (a.special >= 206) && (a.special <= 207)) + || (!part && (a.special == 228)) + || (!part && (a.special >= 230) && (a.special <= 231)) + || (!part && (a.special >= 238) && (a.special <= 242)) + || ((a.special >= 245) && (a.special <= 247)) + || (part && (a.special == 249)) + || (!part && (a.special >= 250) && (a.special <= 251)) + || (part && (a.special >= 251) && (a.special <= 255)) + || (!part && (a.special >= 256) && (a.special <= 261)) + || (part && (a.special >= 262) && (a.special <= 269)) + || (!part && (a.special == 275)) + || (part && (a.special == 276)) + || (!part && (a.special == 279)) + || (part && (a.special == 280)) ) + { + let si = level.CreateSectorTagIterator(a.Args[0]); + int idx; + while ( (idx = si.Next()) != -1 ) + if ( level.Sectors[idx] == s ) + return true; + } + } + return false; + } } // Stats diff --git a/zscript/swwm_player.zsc b/zscript/swwm_player.zsc index c2a62c39e..9518e940d 100644 --- a/zscript/swwm_player.zsc +++ b/zscript/swwm_player.zsc @@ -823,7 +823,7 @@ Class Demolitionist : PlayerPawn } if ( dodge == (0,0,0) ) dodge.xy = RotateVector((1,0),angle); if ( (waterlevel < 2) && !(bFly || bFlyCheat) ) - dodge.z += .15; + dodge.z += (player.cmd.buttons&BT_CROUCH)?.05:.15; if ( (dodge.length() > 0) && (dashcooldown <= 0) && (dashfuel > 20.) && player.cmd.buttons&BT_USER2 && (player.onground || level.IsJumpingAllowed()) ) { dashdir = dodge.unit(); diff --git a/zscript/swwm_shot.zsc b/zscript/swwm_shot.zsc index 9711f6082..26c5a677d 100644 --- a/zscript/swwm_shot.zsc +++ b/zscript/swwm_shot.zsc @@ -678,7 +678,7 @@ Class SaltBeam : Actor } if ( t.Results.HitType != TRACE_HitNone ) { - if ( args[1] ) BusterWall.Bust(t.Results,85+Accuracy*10,target,x); + if ( args[1] ) BusterWall.Bust(t.Results,85+Accuracy*10,target,x,t.Results.HitPos.z); if ( t.Results.HitType == TRACE_HitActor ) { SWWMHandler.DoKnockback(t.Results.HitActor,x,25000); @@ -1515,7 +1515,7 @@ Class TheBall : Actor if ( special1 == 1 ) { int dmg = int(oldvel.length()*4.2+heat*80); - BusterWall.Bust(faketracer.Results,dmg,target,oldvel.unit()); + BusterWall.Bust(faketracer.Results,dmg,target,oldvel.unit(),pos.z+Height/2.); } // undo the bounce, we need to hook in our own vel = oldvel; diff --git a/zscript/swwm_thiccboolet.zsc b/zscript/swwm_thiccboolet.zsc index 8da72e6c9..dea10e872 100644 --- a/zscript/swwm_thiccboolet.zsc +++ b/zscript/swwm_thiccboolet.zsc @@ -87,8 +87,8 @@ Class SilverImpact : Actor return; } A_StartSound("silverbullet/hit",CHAN_VOICE,CHANF_DEFAULT,1.,.7); - A_SprayDecal("BigBulletChip",-20); - A_SprayDecal("HugeWallCrack",-20); + A_SprayDecal("BigBulletChip",-64); + A_SprayDecal("HugeWallCrack",-64); int numpt = Random[Silverbullet](15,25); Vector3 x = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch)); for ( int i=0; i WallPenetrateList; + + override ETraceStatus TraceCallback() + { + // liquid splashes + if ( Results.CrossedWater ) + { + let hl = new("WaterHit"); + hl.sect = Results.CrossedWater; + hl.hitpos = Results.CrossedWaterPos; + WaterHitList.Push(hl); + } + else if ( Results.Crossed3DWater ) + { + let hl = new("WaterHit"); + hl.sect = Results.Crossed3DWater; + hl.hitpos = Results.Crossed3DWaterPos; + WaterHitList.Push(hl); + } + if ( Results.HitType == TRACE_HitActor ) + { + if ( Results.HitActor == ignoreme ) return TRACE_Skip; + if ( Results.HitActor.bSHOOTABLE ) + { + let ent = new("HitListEntry"); + ent.hitactor = Results.HitActor; + ent.hitlocation = Results.HitPos; + ent.x = Results.HitVector; + ent.hitdamage = min(Results.HitActor.health+int(Results.HitActor.GetSpawnHealth()*gameinfo.gibfactor),int(penetration)); + int killdamage = min(Results.HitActor.health,int(penetration)); + hitlist.Push(ent); + penetration = max(0,penetration-killdamage); + if ( penetration <= 0 ) return TRACE_Stop; + return TRACE_Skip; + } + 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)) ) + { + for ( int i=1; i