diff --git a/language.def_menu b/language.def_menu index 6251d092e..6bb9d2fd3 100644 --- a/language.def_menu +++ b/language.def_menu @@ -106,6 +106,7 @@ SWWM_OTHERVOICE = "Co-op Voice"; SWWM_REVIVE = "Emergency Reboot System"; SWWM_REVIVECOOLDOWN = "Reboot Cooldown"; SWWM_UNLIMITED = "Unlimited"; +SWWM_ONERETRY = "One Retry"; SWWM_NONE = "None"; SWWM_INTERART = "Intermission Art"; SWWM_BALLUSE = "Lead Balls can Activate Switches"; @@ -280,7 +281,7 @@ TOOLTIP_SWWM_EARBUSTER = "The Wallbuster's firing sounds may be painfully loud a TOOLTIP_SWWM_SHADERS = "Use postprocess shaders for things like powerups and the Silver Bullet scope. You can disable this if you'd prefer something lighter on the eyes."; TOOLTIP_SWWM_OTHERVOICE = "Allows you to hear other player's voice lines, provided you're close enough."; TOOLTIP_SWWM_REVIVE = "Allows the player to get back up after dying by pressing Fire. Has a configurable cooldown."; -TOOLTIP_SWWM_REVIVECOOLDOWN = "Time in seconds of downtime after using a reboot, where if you die again, you can't get back up. Set to 0 to allow unlimited reboots."; +TOOLTIP_SWWM_REVIVECOOLDOWN = "Time in minutes of downtime after using a reboot, where if you die again, you can't get back up. Set to 0 to allow unlimited reboots. Alternatively, you can also set it to only allow one reboot per map (enforced on expert difficulties)."; TOOLTIP_SWWM_INTERART = "If enabled, displays randomly selected fanart during intermissions."; TOOLTIP_SWWM_BALLUSE = "Lead Ball projectiles can remotely activate use switches (excluding exits). Potentially OP."; TOOLTIP_SWWM_BOSSHEALTHBARS = "Show a healthbar for vanilla boss encounters at the bottom of the screen. Just like Dark Souls™!"; diff --git a/language.es_menu b/language.es_menu index 32fb57654..bae27d3ad 100644 --- a/language.es_menu +++ b/language.es_menu @@ -104,6 +104,7 @@ SWWM_OTHERVOICE = "Voz en Cooperativo"; SWWM_REVIVE = "Sistema de Reinicio de Emergencia"; SWWM_REVIVECOOLDOWN = "Tiempo de recarga de Reinicio"; SWWM_UNLIMITED = "Ilimitado"; +SWWM_ONERETRY = "Un Reintento"; SWWM_NONE = "Ninguno"; SWWM_INTERART = "Arte de Intermisión"; SWWM_BALLUSE = "Las Bolas de Plomo Activan Botones"; @@ -277,7 +278,7 @@ TOOLTIP_SWWM_EARBUSTER = "Los sonidos de disparo del Wallbuster pueden a veces s TOOLTIP_SWWM_SHADERS = "Usa shaders de postprocesado para cosas como potenciadores y la mira del Silver Bullet. Puedes desactivar esto si prefieres algo más ligero para la vista."; TOOLTIP_SWWM_OTHERVOICE = "Te permite oír los comentarios de voz de otros jugadores, si estás lo suficientemente cerca."; TOOLTIP_SWWM_REVIVE = "Permite al jugador volver a levantarse tras morir pulsando Fuego. Tiene un cooldown configurable."; -TOOLTIP_SWWM_REVIVECOOLDOWN = "Tiempo en segundos tras reiniciar, durante el cual si mueres otra vez, no puedes volver a levantarte. Pon a 0 para permitir reinicios ilimitados."; +TOOLTIP_SWWM_REVIVECOOLDOWN = "Tiempo en minutos tras reiniciar, durante el cual si mueres otra vez, no puedes volver a levantarte. Pon a 0 para permitir reinicios ilimitados. Alternativamente, puedes elegir que solo se permita un reinicio por mapa (forzado en dificultades expertas)."; TOOLTIP_SWWM_INTERART = "Si está activado, muestra fanart aleatorio durante intermisiones."; TOOLTIP_SWWM_BALLUSE = "Los proyectiles de Bola de Plomo pueden activar botones utilizables remotamente (excluyendo salidas). Potencialmente roto."; TOOLTIP_SWWM_BOSSHEALTHBARS = "Muestra una barra de vida para bosses vanilla en la parte inferior de la pantalla. ¡Es justo como Dark Souls™!"; diff --git a/language.version b/language.version index 5b501028f..233e41e2e 100644 --- a/language.version +++ b/language.version @@ -1,3 +1,3 @@ [default] -SWWM_MODVER="\chSWWM \czGZ\c- \cw0.9.11b-pre r386 \cu(Sat 20 Mar 23:26:41 CET 2021)\c-"; -SWWM_SHORTVER="\cw0.9.11b-pre r386 \cu(2021-03-20 23:26:41)\c-"; +SWWM_MODVER="\chSWWM \czGZ\c- \cw0.9.11b-pre r387 \cu(Sun 21 Mar 00:57:23 CET 2021)\c-"; +SWWM_SHORTVER="\cw0.9.11b-pre r387 \cu(2021-03-21 00:57:23)\c-"; diff --git a/menudef.txt b/menudef.txt index be086bb09..d65fdfdd0 100644 --- a/menudef.txt +++ b/menudef.txt @@ -85,7 +85,7 @@ OptionMenu "SWWMOptionMenu" Option "$SWWM_MUTELEVEL", "swwm_mutevoice", "SWWMVoice" Option "$SWWM_6DOF", "swwm_fly6dof", "YesNo" Option "$SWWM_REVIVE", "swwm_revive", "YesNo" - ScaleSlider "$SWWM_REVIVECOOLDOWN", "swwm_revivecooldown", 0, 300, 30, "$SWWM_UNLIMITED" + ScaleSlider "$SWWM_REVIVECOOLDOWN", "swwm_revivecooldown", -1, 5, 1, "$SWWM_UNLIMITED", "$SWWM_ONERETRY" Option "$SWWM_MENUPAUSE", "swwm_menupause", "YesNo" Option "$SWWM_PRECISECROSSHAIR", "swwm_precisecrosshair", "YesNo" StaticText " " diff --git a/modeldef.ynykron b/modeldef.ynykron index 0c4979648..3e7665704 100644 --- a/modeldef.ynykron +++ b/modeldef.ynykron @@ -1,3 +1,18 @@ +Model "AshenRemains" +{ + Path "models/extra" + + Model 0 "flat_d.3d" + Scale 0.1 0.1 0.1 + ZOffset 0.1 + USEACTORPITCH + USEACTORROLL + DONTCULLBACKFACES + + Skin 0 "BigBlast.png" + FrameIndex XZW1 A 0 0 +} + Model "YnykronBeam" { Path "models/extra" diff --git a/models/extra/BigBlast.png b/models/extra/BigBlast.png new file mode 100644 index 000000000..e99c463bb Binary files /dev/null and b/models/extra/BigBlast.png differ diff --git a/shaders/pp/Barrier.fp b/shaders/pp/Barrier.fp index bbf995819..20b48ac05 100644 --- a/shaders/pp/Barrier.fp +++ b/shaders/pp/Barrier.fp @@ -7,14 +7,14 @@ void main() flood += texture(WarpTex,uv*sr*2.+vec2(-timer*.07,-timer*.13)).xy; flood += texture(WarpTex,uv*sr*.5+vec2(0.,-timer*.06)).xy; flood /= 3.; - vec3 col = texture(InputTexture,uv).rgb*3.; + vec3 col = texture(InputTexture,uv).rgb*6.; for ( int i=0; i<3; i++ ) { - uv = (uv*.985)+.005; - uv += (flood-.5)*.005; + uv = (uv*.995)+.0025; + uv += (flood-.5)*.003; col += texture(InputTexture,uv).rgb; } - col.rgb /= 5.; + col.rgb /= 8.; col.rgb = pow(max(col.rgb,vec3(0.)),vec3(1.2,1.15,.77))*vec3(1.03,1.32,.98); FragColor = vec4(col,1.); } diff --git a/zscript/swwm_player.zsc b/zscript/swwm_player.zsc index 5f0eb82b1..16ee5612f 100644 --- a/zscript/swwm_player.zsc +++ b/zscript/swwm_player.zsc @@ -22,6 +22,7 @@ Class Demolitionist : PlayerPawn SWWMStats mystats; int cairtime; bool hasteleported; + bool hasrevived; int lastmpain; @@ -1328,6 +1329,41 @@ Class Demolitionist : PlayerPawn } } } + private void CheckBreakCrusher() + { + double gaph = (ceilingz-floorz); + if ( gaph > height*.6 ) return; + // the smaller the gap, the more likely the crusher will snap + if ( Random[Demolitionist](0,3) && (FRandom[Demolitionist](0,gaph/height) > .1) ) return; + double diffh = 8.+(default.height-gaph); // how much the crusher will have to "snap" after breaking + let ceil = ceilingsector; + let flor = floorsector; + let ceilse = ceil.ceilingdata; + let florse = flor.floordata; + if ( ceilse && florse ) + { + // snap both planes + let q = Spawn("BustedQuake",(ceil.centerspot.x,ceil.centerspot.y,ceil.ceilingplane.ZAtPoint(ceil.centerspot))); + q.special1 = 6; + q = Spawn("BustedQuake",(flor.centerspot.x,flor.centerspot.y,flor.floorplane.ZAtPoint(flor.centerspot))); + q.special1 = 6; + SWWMCrusherBroken.Create(flor,ceil,diffh/2.); + } + else if ( ceilse ) + { + // snap ceiling + let q = Spawn("BustedQuake",(ceil.centerspot.x,ceil.centerspot.y,ceil.ceilingplane.ZAtPoint(ceil.centerspot))); + q.special1 = 10; + SWWMCrusherBroken.Create(null,ceil,diffh); + } + else if ( florse ) + { + // snap floor + let q = Spawn("BustedQuake",(flor.centerspot.x,flor.centerspot.y,flor.floorplane.ZAtPoint(flor.centerspot))); + q.special1 = 10; + SWWMCrusherBroken.Create(flor,null,diffh); + } + } override int DamageMobj( Actor inflictor, Actor source, int damage, Name mod, int flags, double angle ) { // we still have to ENSURE ENTIRELY that this gets nullified (TELEFRAG_DAMAGE overrides damage factors somehow) @@ -1338,6 +1374,9 @@ Class Demolitionist : PlayerPawn let hnd = SWWMHandler(EventHandler.Find("SWWMHandler")); if ( hnd ) hnd.tookdamage[PlayerNumber()] = true; } + // check if we can break any active crushers + if ( (mod == 'Crush') && !inflictor && !source ) + CheckBreakCrusher(); // no damage whatsoever if ( scriptedinvul ) return 0; @@ -1832,8 +1871,9 @@ Class Demolitionist : PlayerPawn else if ( (player.cmd.buttons&BT_ATTACK) && (deadtimer > 120) && swwm_revive ) { // reboot (if possible) - if ( !FindInventory("ReviveCooldown") ) + if ( !FindInventory("ReviveCooldown") && (((swwm_revivecooldown >= 0) && (G_SkillPropertyInt(SKILLP_ACSReturn) < 4)) || !hasrevived) ) { + hasrevived = true; player.Resurrect(); player.damagecount = 0; player.bonuscount = 0; @@ -1857,7 +1897,7 @@ Class Demolitionist : PlayerPawn SWWMHandler.DoFlash(self,Color(255,128,192,255),30); SWWMScoreObj.Spawn(default.health,Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+Height/2),ST_Health); if ( special1 > 2 ) special1 = 0; - if ( swwm_revivecooldown > 0 ) + if ( (swwm_revivecooldown > 0) && (G_SkillPropertyInt(SKILLP_ACSReturn) < 4) ) GiveInventory("ReviveCooldown",1); } else if ( level.maptime > revivefail ) @@ -2429,6 +2469,7 @@ Class Demolitionist : PlayerPawn dashfuel = default.dashfuel; last_boost = 0; last_kick = 0; + hasrevived = false; // cancel dash/boost A_StopSound(CHAN_JETPACK); fuelcooldown = 0.; diff --git a/zscript/swwm_player_items.zsc b/zscript/swwm_player_items.zsc index 0cde432dd..86fa3135d 100644 --- a/zscript/swwm_player_items.zsc +++ b/zscript/swwm_player_items.zsc @@ -71,43 +71,7 @@ Class AlmasteelPlating : Inventory // 80% reduction for explosions if ( flags&DMG_EXPLOSION ) newdamage = newdamage/5; // 50% reduction for crushing - if ( damageType == 'Crush' ) - { - newdamage = newdamage/2; - // additionally, check if we can break any active crushers - double gaph = (Owner.ceilingz-Owner.floorz); - if ( gaph > Owner.height*.6 ) return; - // the smaller the gap, the more likely the crusher will snap - if ( Random[Demolitionist](0,3) && (FRandom[Demolitionist](0,gaph/Owner.height) > .1) ) return; - double diffh = 8.+(Owner.default.height-gaph); // how much the crusher will have to "snap" after breaking - let ceil = Owner.ceilingsector; - let flor = Owner.floorsector; - let ceilse = ceil.ceilingdata; - let florse = flor.floordata; - if ( ceilse && florse ) - { - // snap both planes - let q = Spawn("BustedQuake",(ceil.centerspot.x,ceil.centerspot.y,ceil.ceilingplane.ZAtPoint(ceil.centerspot))); - q.special1 = 6; - q = Spawn("BustedQuake",(flor.centerspot.x,flor.centerspot.y,flor.floorplane.ZAtPoint(flor.centerspot))); - q.special1 = 6; - SWWMCrusherBroken.Create(flor,ceil,diffh/2.); - } - else if ( ceilse ) - { - // snap ceiling - let q = Spawn("BustedQuake",(ceil.centerspot.x,ceil.centerspot.y,ceil.ceilingplane.ZAtPoint(ceil.centerspot))); - q.special1 = 10; - SWWMCrusherBroken.Create(null,ceil,diffh); - } - else if ( florse ) - { - // snap floor - let q = Spawn("BustedQuake",(flor.centerspot.x,flor.centerspot.y,flor.floorplane.ZAtPoint(flor.centerspot))); - q.special1 = 10; - SWWMCrusherBroken.Create(flor,null,diffh); - } - } + if ( damageType == 'Crush' ) newdamage = newdamage/2; } override bool HandlePickup( Inventory item ) { @@ -142,7 +106,7 @@ Class ReviveCooldown : Powerup Default { Inventory.Icon "graphics/HUD/Icons/I_Revive.png"; - Powerup.Duration -30; + Powerup.Duration -60; } override void Tick() @@ -156,7 +120,7 @@ Class ReviveCooldown : Powerup { Super.InitEffect(); // adjust the duration - EffectTics = max(0,swwm_revivecooldown)*GameTicRate; + EffectTics = clamp(swwm_revivecooldown*60,0,300)*GameTicRate; } override void EndEffect() { diff --git a/zscript/weapons/swwm_deathlydeathcannon_fx.zsc b/zscript/weapons/swwm_deathlydeathcannon_fx.zsc index 7ca07fc1b..1ac470a61 100644 --- a/zscript/weapons/swwm_deathlydeathcannon_fx.zsc +++ b/zscript/weapons/swwm_deathlydeathcannon_fx.zsc @@ -1,5 +1,47 @@ // Ynykron projectiles and effects +// there was an enemy here, but it's gone now +Class AshenRemains : Actor +{ + override void Tick() + { + double fz = CurSector.floorplane.ZAtPoint(pos.xy); + if ( fz != pos.z ) SetOrigin((pos.x,pos.y,fz),true); + if ( isFrozen() ) return; + special1++; + if ( special1 > 350 ) A_FadeOut(0.01); + } + override void PostBeginPlay() + { + if ( (waterlevel > 0) || GetFloorTerrain().isliquid ) + { + Destroy(); + return; + } + double fz = CurSector.floorplane.ZAtPoint(pos.xy); + SetZ(fz); + prev.z = fz; + SWWMUtility.SetToSlope(self,FRandom[Ynykron](0,360)); + } + default + { + RenderStyle "Shaded"; + StencilColor "000000"; + Radius .1; + Height 0.; + +NOBLOCKMAP; + +NOINTERACTION; + +DONTSPLASH; + +NOTELEPORT; + } + States + { + Spawn: + XZW1 A -1; + Stop; + } +} + // cheap way to let players know they just got fucking erased from existence Class PlayerGone : PlayerChunk { @@ -360,7 +402,15 @@ Class YnykronImpact : Actor { // voodoo dolls just get erased (how convenient) // otherwise instantly vaporize the fucker - if ( tracer.player && (tracer.player.mo != tracer) ) tracer.Destroy(); + if ( tracer.player && (tracer.player.mo != tracer) ) + { + if ( tracer.pos.z < (tracer.floorz+64) ) + { + let r = Spawn("AshenRemains",tracer.pos); + r.scale *= tracer.radius/16.; + } + tracer.Destroy(); + } else if ( tracer.CountInv("GrilledCheeseSandwich") > 0 ) { // force use the sandwich @@ -382,6 +432,11 @@ Class YnykronImpact : Actor tracer.A_ChangeLinkFlags(true); // remove from blockmap, should guarantee archviles not raising this IDontFeelSoGood.DeletThis(tracer); // ensures corpse is deleted too } + if ( tracer.pos.z < (tracer.floorz+64) ) + { + let r = Spawn("AshenRemains",tracer.pos); + r.scale *= tracer.radius/16.; + } } } if ( YnykronShot(master) )