diff --git a/cvarinfo.txt b/cvarinfo.txt index 944bd9a7b..47e51dbc4 100644 --- a/cvarinfo.txt +++ b/cvarinfo.txt @@ -28,7 +28,7 @@ user bool swwm_targettags = false; // show enemy tags above healthbars user bool swwm_healthnums = true; // show damage/healing numbers user bool swwm_scorenums = true; // show score numbers user bool swwm_scorebonus = true; // show score bonuses -user bool swwm_fly6dof = true; // flying uses 6dof movement, toggleable for those who get motion sickness +user bool swwm_fly6dof = false; // flying uses 6dof movement, toggleable for those who get motion sickness user bool swwm_othervoice = true; // can hear other player's voice lines in coop user bool swwm_shaders = true; // use pp shaders for some effects user bool swwm_earbuster = false; // limits loudness of wallbuster fire sounds @@ -38,3 +38,5 @@ user int swwm_intertype = 0; // 0 - standard bg // 1 - fanart // 2 - 4komas server bool swwm_balluse = false; // 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 diff --git a/graphics/HUD/BossHealthBar.png b/graphics/HUD/BossHealthBar.png new file mode 100644 index 000000000..1a64aaf38 Binary files /dev/null and b/graphics/HUD/BossHealthBar.png differ diff --git a/graphics/HUD/BossHealthBarBox.png b/graphics/HUD/BossHealthBarBox.png new file mode 100644 index 000000000..fed7aa36b Binary files /dev/null and b/graphics/HUD/BossHealthBarBox.png differ diff --git a/graphics/HUD/BossHealthBarDecay.png b/graphics/HUD/BossHealthBarDecay.png new file mode 100644 index 000000000..48bd5dc9c Binary files /dev/null and b/graphics/HUD/BossHealthBarDecay.png differ diff --git a/graphics/HUD/HellblazerCrackshot.png b/graphics/HUD/HellblazerCrackshot.png new file mode 100644 index 000000000..22e576bf7 Binary files /dev/null and b/graphics/HUD/HellblazerCrackshot.png differ diff --git a/graphics/HUD/HellblazerCrackshotLoaded.png b/graphics/HUD/HellblazerCrackshotLoaded.png new file mode 100644 index 000000000..52dbe98ac Binary files /dev/null and b/graphics/HUD/HellblazerCrackshotLoaded.png differ diff --git a/graphics/HUD/HellblazerDisplay.png b/graphics/HUD/HellblazerDisplay.png new file mode 100644 index 000000000..4514f797a Binary files /dev/null and b/graphics/HUD/HellblazerDisplay.png differ diff --git a/graphics/HUD/HellblazerMissile.png b/graphics/HUD/HellblazerMissile.png new file mode 100644 index 000000000..2aeff31b3 Binary files /dev/null and b/graphics/HUD/HellblazerMissile.png differ diff --git a/graphics/HUD/HellblazerMissileLoaded.png b/graphics/HUD/HellblazerMissileLoaded.png new file mode 100644 index 000000000..3161ec2b2 Binary files /dev/null and b/graphics/HUD/HellblazerMissileLoaded.png differ diff --git a/graphics/HUD/HellblazerRavager.png b/graphics/HUD/HellblazerRavager.png new file mode 100644 index 000000000..b65aa2b93 Binary files /dev/null and b/graphics/HUD/HellblazerRavager.png differ diff --git a/graphics/HUD/HellblazerRavagerLoaded.png b/graphics/HUD/HellblazerRavagerLoaded.png new file mode 100644 index 000000000..738d7e976 Binary files /dev/null and b/graphics/HUD/HellblazerRavagerLoaded.png differ diff --git a/graphics/HUD/HellblazerWarhead.png b/graphics/HUD/HellblazerWarhead.png new file mode 100644 index 000000000..1708ffc64 Binary files /dev/null and b/graphics/HUD/HellblazerWarhead.png differ diff --git a/graphics/HUD/HellblazerWarheadLoaded.png b/graphics/HUD/HellblazerWarheadLoaded.png new file mode 100644 index 000000000..97f563d05 Binary files /dev/null and b/graphics/HUD/HellblazerWarheadLoaded.png differ diff --git a/language.def_base b/language.def_base index 1adbbb6fc..57a63d1cb 100644 --- a/language.def_base +++ b/language.def_base @@ -449,33 +449,33 @@ TXT_HEXEN_WIN3MSG = "got a fine lady waiting for me back home.\""; // Re-tagged monsters FN_ZOMBIE = "Zomb"; -FN_SHOTGUN = "Baldy"; +FN_SHOTGUN = "Bald Zomb"; FN_HEAVY = "Annoyance"; -FN_IMP = "Simp"; -FN_DEMON = "Pinky"; -FN_SPECTRE = "Fuzzy"; -FN_LOST = "Skully"; -FN_CACO = "Caco"; -FN_HELL = "Brownie"; +FN_IMP = "Spiky Boi"; +FN_DEMON = "Pinky Boi"; +FN_SPECTRE = "Fuzzy Boi"; +FN_LOST = "Fire Skully"; +FN_CACO = "Friend-Shaped Demon"; +FN_HELL = "Discount Baron"; FN_BARON = "Mr. Gruh"; -FN_ARACH = "Babby"; +FN_ARACH = "Babby Spooder"; FN_PAIN = "Ass Pain"; FN_REVEN = "AAAAAAAAA"; FN_MANCU = "He Thicc"; -FN_ARCH = "Pls No"; +FN_ARCH = "1000 Points Off"; FN_SPIDER = "Mama Spooder"; FN_CYBER = "Dat Ass"; FN_WOLFSS = "Mein Lieben"; CC_ZOMBIE = "Zomb"; -CC_SHOTGUN = "Baldy"; +CC_SHOTGUN = "Bald Zomb"; CC_HEAVY = "Annoyance"; -CC_IMP = "Simp"; -CC_DEMON = "Pinky"; -CC_LOST = "Skully"; -CC_CACO = "Caco"; -CC_HELL = "Brownie"; +CC_IMP = "Spiky Boi"; +CC_DEMON = "Pinky Boi"; +CC_LOST = "Fire Skully"; +CC_CACO = "Friend-Shaped Demon"; +CC_HELL = "Discount Baron"; CC_BARON = "Mr. Gruh"; -CC_ARACH = "Babby"; +CC_ARACH = "Babby Spooder"; CC_PAIN = "Ass Pain"; CC_REVEN = "AAAAAAAAA"; CC_MANCU = "He Thicc"; @@ -484,16 +484,16 @@ CC_SPIDER = "Mama Spooder"; CC_CYBER = "Dat Ass"; CC_HERO = "You!"; FN_DOG = "Goodest Boy"; -FN_CHICKEN = "Clucker"; +FN_CHICKEN = "PECK"; FN_BEAST = "Друг"; -FN_CLINK = "Slashy"; -FN_DSPARIL = "Oh He Mad"; +FN_CLINK = "Slashy Boi"; +FN_DSPARIL = "Little Red Riding Hood"; FN_HERETICIMP = "Flying Pest"; FN_IRONLICH = "Jolly Lad"; FN_BONEKNIGHT = "Rattle Me Bones"; -FN_MINOTAUR = "Buff"; -FN_MUMMY = "Mummy"; -FN_MUMMYLEADER = "Big Mummy"; +FN_MINOTAUR = "Buff Bull"; +FN_MUMMY = "Toilet Paper"; +FN_MUMMYLEADER = "Toilet Paper whomst Scream"; FN_SNAKE = "Snek"; FN_WIZARD = "Yer a Wizard, Harry"; FN_FIREDEMON = "Hot Stuff"; @@ -501,16 +501,19 @@ FN_DEMON1 = "Big Lizard"; FN_ETTIN = "Double Boi"; FN_CENTAUR = "Shield Idiot"; FN_SLAUGHTAUR = "Shield Idioter"; -FN_BISHOP = "Hoodie"; -FN_ICEGUY = "Cool Stuff"; +FN_BISHOP = "Hoodie Boi"; +FN_ICEGUY = "Cool Story Bro"; FN_SERPENT = "Swamp Snek"; -FN_WRAITH = "Ded"; +FN_WRAITH = "Ded Boi"; FN_DRAGON = "Buy Skyrim"; FN_KORAX = "Ugly Stinky Boi"; FN_FBOSS = "Buff Boi"; FN_MBOSS = "Magic Boi"; FN_CBOSS = "Holy Boi"; FN_HERESIARCH = "Oh Lawd He Comin'"; +// Additional tags +FN_BOSSBRAIN = "Daikatana"; +FN_KEEN = "Ruined by Bethesda"; // obituaries O_PUSHER = "%k opened some air holes into %o."; O_DEEPIMPACT = "%o was impacted deeply by %k."; @@ -553,7 +556,7 @@ OB_SLIME = "%o got slimed."; OB_LAVA = "%o overheated"; OB_BARREL = "%o got barreled."; OB_SPLASH = "%o got a bit too close there."; -OB_R_SPLASH = "%o was rawket'd."; +OB_R_SPLASH = "%o did an Icarus."; OB_ROCKET = "%o ate a rocket."; OB_KILLEDSELF = "%o self-destructed."; OB_VOODOO = "%o violated the laws of causality."; @@ -646,6 +649,21 @@ SWWM_LQUOTE = "\""; SWWM_RQUOTE = "\""; D_FROGGY1 = "\cjA small price to pay...\c-"; D_FROGGY2 = "\cj... for \cdFroggy Chair\cj.\c-"; +// boss tags +BT_BRUISERS = "Super Bruiser Bros"; +BT_CYBIE = "Shoot It Until It Dies"; +BT_SPIDER = "Big Brains Idiot"; +BT_IOS = "Goaty McGoatface"; +BT_LICHES = "The Jolly Lad Squad"; +BT_MINOTAUR = "AWAKEN MY MASTERS"; +BT_DSPARIL = "Red Robed Wizard Dude and Lizard"; +BT_DSPARIL2 = "Red Robed Wizard Dude"; +BT_CLERIC = "Traductus the Holy Boi"; +BT_FIGHTER = "Zedek the Buff Boi"; +BT_MAGE = "Menelkir the Magic Boi"; +BT_DRAGON = "A Motherfucking Dragon"; +BT_HERESIARCH = "Very Pissed Off Red Dude"; +BT_KORAX = "Korax the Big Stinky Ugly Bastard"; // targetter SWWM_OVERKILL = "Overkill"; SWWM_MULTIKILL = "Multi Kill"; diff --git a/language.def_menu b/language.def_menu index 5a65bb8e9..2d03f4f8f 100644 --- a/language.def_menu +++ b/language.def_menu @@ -79,6 +79,9 @@ SWWM_INTERDEF = "N/A"; SWWM_INTERART = "Fanart"; SWWM_INTER4KOMA = "4Koma"; SWWM_BALLUSE = "Lead Balls can activate switches"; +SWWM_BOSSBAR = "Show Boss Healthbars"; +SWWM_BTITLE = "Balance Options"; +SWWM_BOSSENHANCE = "Enhance Vanilla Bosses"; 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."; @@ -109,6 +112,8 @@ TOOLTIP_SWWM_REVIVE = "Allows the player to get back up after dying by pressing 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_INTERTYPE = "Choose what to display in the background 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™!"; +TOOLTIP_SWWM_UPGRADEBOSSES = "Buffs the health of vanilla bosses in order to make the fights more \"fair\" with this mod, and less prone to instant wins."; // knowledge base SWWM_COMINGSOON = "(coming soon)"; SWWM_MISSTAB = "Mission"; diff --git a/language.es_base b/language.es_base index 8c26df73a..fbc1f8439 100644 --- a/language.es_base +++ b/language.es_base @@ -448,42 +448,44 @@ TXT_HEXEN_WIN3MSG = "una bella dama que me espera en casa.\""; // Re-tagged monsters FN_ZOMBIE = "Zombi"; -FN_SHOTGUN = "Calvito"; +FN_SHOTGUN = "Zombi Calvete"; FN_HEAVY = "Tocacojones"; +FN_IMP = "Pinchitos"; FN_DEMON = "Rosita"; FN_SPECTRE = "Borroncito"; FN_LOST = "Calaverita"; FN_CACO = "Tomatín"; -FN_HELL = "Marroncito"; +FN_HELL = "Barón de Hacendado"; FN_BARON = "Señor Gruñón"; -FN_ARACH = "Ñiño"; +FN_ARACH = "Ñiño Araña"; FN_PAIN = "Dolor de Culo"; FN_SPIDER = "Mami Araña"; -FN_CYBER = "Madre Mía Que Culazo"; +FN_CYBER = "Culazo"; FN_WOLFSS = "Votante de VOX"; CC_ZOMBIE = "Zombi"; -CC_SHOTGUN = "Calvito"; +CC_SHOTGUN = "Zombi Calvete"; CC_HEAVY = "Tocacojones"; +CC_IMP = "Pinchitos"; CC_DEMON = "Rosita"; CC_LOST = "Calaverita"; CC_CACO = "Tomatín"; -CC_HELL = "Marroncito"; +CC_HELL = "Barón de Hacendado"; CC_BARON = "Señor Gruñón"; -CC_ARACH = "Ñiño"; +CC_ARACH = "Ñiño Araña"; CC_PAIN = "Dolor de Culo"; CC_SPIDER = "Mami Araña"; -CC_CYBER = "Madre Mía Que Culazo"; +CC_CYBER = "Culazo"; CC_HERO = "¡Tú!"; FN_DOG = "Perrete"; FN_CHICKEN = "Gallina"; FN_CLINK = "Rasguñitos"; -FN_DSPARIL = "El Brujo Ese"; +FN_DSPARIL = "Caperucita Roja"; FN_HERETICIMP = "Bicho con Alas"; FN_IRONLICH = "Risitas"; FN_BONEKNIGHT = "Huesitos"; -FN_MINOTAUR = "Tó Ciclao"; -FN_MUMMY = "Momia"; -FN_MUMMYLEADER = "Momia Grandota"; +FN_MINOTAUR = "Toro Ciclao"; +FN_MUMMY = "Papel de Culo"; +FN_MUMMYLEADER = "Papel de Culo que Grita"; FN_SNAKE = "Culebrilla"; FN_WIZARD = "Eres Un Mago, Harry"; FN_FIREDEMON = "Bicho Ardiente"; @@ -491,9 +493,9 @@ FN_DEMON1 = "Lagarto Grandote"; FN_ETTIN = "Perrito Doble"; FN_CENTAUR = "Idiota con Escudo"; FN_SLAUGHTAUR = "Superidiota con Escudo"; -FN_BISHOP = "Encapuchao Volador"; -FN_ICEGUY = "Bicho de Hielo"; -FN_SERPENT = "Bicho del Pantano"; +FN_BISHOP = "Encapuchao"; +FN_ICEGUY = "Cosa Fría"; +FN_SERPENT = "Bicho de Pantano"; FN_WRAITH = "Pariente de Fraga"; FN_DRAGON = "Compra Skyrim"; FN_KORAX = "El Tío Feo Ese"; @@ -501,6 +503,8 @@ FN_FBOSS = "Tío Ciclao"; FN_MBOSS = "Tío Mágico"; FN_CBOSS = "Tío Santurrón"; FN_HERESIARCH = "Hostia Puta"; +// Additional tags +FN_KEEN = "Arruinado por Bethesda"; // obituaries O_PUSHER = "%k le abrió unos agujeros de ventilación a %o."; O_DEEPIMPACT = "%o fue impactad@[ao_esp] profundamente por %k."; @@ -603,8 +607,8 @@ OB_DEMON1 = "%o se comió la bola de fuego de un lagarto grandote."; OB_DEMON2 = "%o se comió los mocos de un lagarto grandote."; OB_ETTIN = "%o se llevó un coscorrón del perrito doble."; OB_CENTAUR = "%o fue acuchillad@[ao_esp] por un idiota con escudo."; -OB_SLAUGHTAURHIT = "%o fue acuchillad@[ao_esp] por un muy idiota con escudo."; -OB_SLAUGHTAUR = "%o se comió un disparo del muy idiota con escudo."; +OB_SLAUGHTAURHIT = "%o fue acuchillad@[ao_esp] por un superidiota con escudo."; +OB_SLAUGHTAUR = "%o se comió un disparo del superidiota con escudo."; OB_BISHOP = "%o se comió toda la magia del encapuchao."; OB_ICEGUY = "%o tiene frío."; OB_SERPENTHIT = "%o encontró la cosa del pantano."; @@ -634,6 +638,19 @@ SWWM_REFAIL = "REINICIO DE EMERGENCIA FALLIDO - NO HAY SUFICIENTE POTENCIA AUXIL D_REFAIL = "El Sistema de Reinicio de Emergencia se ha recargado completamente."; D_FROGGY1 = "\cjUn pequeño precio a pagar...\c-"; D_FROGGY1 = "\cj... por una \cdSilla Rana\cj.\c-"; +// boss tags +BT_CYBIE = "Dispara hasta que muera"; +BT_SPIDER = "Cerebrito Idiota"; +BT_IOS = "Cabra Emparedada"; +BT_LICHES = "El Escuadrón Risitas"; +BT_DSPARIL = "El Brujo Rojo Ese y Lagarto"; +BT_DSPARIL2 = "El Brujo Rojo Ese"; +BT_CLERIC = "Traductus el Santurrón"; +BT_FIGHTER = "Zedek el Ciclao"; +BT_MAGE = "Menelkir el Mágico"; +BT_DRAGON = "Un Puñetero Dragón"; +BT_HERESIARCH = "Tío Rojo Muy Cabreado"; +BT_KORAX = "Korax el Bastardo Feo Asqueroso"; // targetter SWWM_MULTIKILL = "Racha"; SWWM_SPREEKILL = "Intocable"; diff --git a/language.es_menu b/language.es_menu index 9ccf7a76e..7c39e0ba7 100644 --- a/language.es_menu +++ b/language.es_menu @@ -76,6 +76,9 @@ SWWM_REVIVECOOLDOWN = "Tiempo de recarga de Reinicio"; SWWM_UNLIMITED = "Ilimitado"; SWWM_INTERTYPE = "Arte de Intermisión"; SWWM_BALLUSE = "Las Bolas de Plomo activan botones"; +SWWM_BOSSBAR = "Mostrar Barras de Salud de Bosses"; +SWWM_BTITLE = "Opciones de Balance"; +SWWM_BOSSENHANCE = "Mejorar Bosses Vanilla"; 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."; @@ -106,6 +109,8 @@ TOOLTIP_SWWM_REVIVE = "Permite al jugador volver a levantarse tras morir pulsand 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_INTERTYPE = "Elige qué mostrar de fondo durante intermisiones."; TOOLTIP_SWWM_BALLUSE = "Los proyectiles de Bola de Plomo pueden activar botones usables 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™!"; +TOOLTIP_SWWM_UPGRADEBOSSES = "Incrementa la salud de bosses vanilla para hacer que las peleas sean más \"justas\" con este mod, y no tan propensas a ganarse al instante."; // knowledge base SWWM_COMINGSOON = "(próximamente)"; SWWM_MISSTAB = "Misión"; diff --git a/menudef.txt b/menudef.txt index 64de562de..08bdfff02 100644 --- a/menudef.txt +++ b/menudef.txt @@ -41,12 +41,16 @@ OptionMenu "SWWMOptionMenu" Slider "$SWWM_PICKLEN", "swwm_pickduration", 1, 30, 1, 0 Option "$SWWM_TARGET", "swwm_targeter", "YesNo" Option "$SWWM_TARGETTAG", "swwm_targettags", "YesNo" + Option "$SWWM_BOSSBAR", "swwm_bosshealthbars", "YesNo" Option "$SWWM_DAMNUMS", "swwm_healthnums", "YesNo" Option "$SWWM_SCORENUMS", "swwm_scorenums", "YesNo" Option "$SWWM_SCOREBONUS", "swwm_scorebonus", "YesNo" Option "$SWWM_SHADERS", "swwm_shaders", "YesNo" Option "$SWWM_INTERTYPE", "swwm_intertype", "SWWMInterType" StaticText " " + StaticText "$SWWM_BTITLE", "Gold" + Option "$SWWM_BOSSENHANCE", "swwm_upgradebosses", "YesNo" + StaticText " " StaticText "$SWWM_ITITLE", "Gold" Option "$SWWM_ARMORUSE", "swwm_autousearmor", "YesNo" Option "$SWWM_HEALTHUSE", "swwm_autousehealth", "YesNo" diff --git a/modeldef.hellblazer b/modeldef.hellblazer index c0d9ce8ea..f6f8597fd 100644 --- a/modeldef.hellblazer +++ b/modeldef.hellblazer @@ -44,6 +44,18 @@ Model "HellblazerCrackshot2" FrameIndex XZW1 A 0 0 } +Model "HellblazerClusterMini" +{ + Path "models" + + Model 0 "HellblazerProj_d.3d" + Skin 0 "HellblazerMissile_Cluster.png" + Scale 0.02 0.02 0.02 + USEACTORPITCH + USEACTORROLL + + FrameIndex XZW1 A 0 0 +} Model "HellblazerRavager" { Path "models" @@ -466,13 +478,13 @@ Model "Hellblazer" // CycleStart/End FrameIndex XZW7 Z 1 33 // Cycle2 - FrameIndex XZW8 A 0 41 - FrameIndex XZW8 B 0 42 - FrameIndex XZW8 C 0 43 - FrameIndex XZW8 D 0 44 - FrameIndex XZW8 E 0 45 - FrameIndex XZW8 F 0 46 - FrameIndex XZW8 G 0 47 + FrameIndex XZW8 A 1 41 + FrameIndex XZW8 B 1 42 + FrameIndex XZW8 C 1 43 + FrameIndex XZW8 D 1 44 + FrameIndex XZW8 E 1 45 + FrameIndex XZW8 F 1 46 + FrameIndex XZW8 G 1 47 // Unload FrameIndex XZW8 H 1 59 FrameIndex XZW8 I 1 60 @@ -740,13 +752,13 @@ Model "Hellblazer" FrameIndex XZWH M 1 22 FrameIndex XZWH N 1 23 // AltFire - FrameIndex XZWH O 0 25 - FrameIndex XZWH P 0 26 - FrameIndex XZWH Q 0 27 - FrameIndex XZWH R 0 28 - FrameIndex XZWH S 0 29 - FrameIndex XZWH T 0 30 - FrameIndex XZWH U 0 31 + FrameIndex XZWH O 1 25 + FrameIndex XZWH P 1 26 + FrameIndex XZWH Q 1 27 + FrameIndex XZWH R 1 28 + FrameIndex XZWH S 1 29 + FrameIndex XZWH T 1 30 + FrameIndex XZWH U 1 31 // CycleStart/End FrameIndex XZWH V 1 33 // Cycle3 diff --git a/palettes/DRed.pal b/palettes/DRed.pal new file mode 100644 index 000000000..6b60d9574 Binary files /dev/null and b/palettes/DRed.pal differ diff --git a/sndinfo.txt b/sndinfo.txt index 4fa0fc65a..566b6c3cc 100644 --- a/sndinfo.txt +++ b/sndinfo.txt @@ -590,6 +590,10 @@ hellblazer/hitcs1 sounds/hellblazer/blaze_hitcs1.ogg hellblazer/hitcs2 sounds/hellblazer/blaze_hitcs2.ogg hellblazer/hitcs3 sounds/hellblazer/blaze_hitcs3.ogg $random hellblazer/hitcs { hellblazer/hitcs1 hellblazer/hitcs2 hellblazer/hitcs3 } +hellblazer/hitr1 sounds/hellblazer/blaze_hitr1.ogg +hellblazer/hitr2 sounds/hellblazer/blaze_hitr2.ogg +hellblazer/hitr3 sounds/hellblazer/blaze_hitr3.ogg +$random hellblazer/hitr { hellblazer/hitr1 hellblazer/hitr2 hellblazer/hitr3 } hellblazer/hitw1 sounds/hellblazer/blaze_hitw1.ogg hellblazer/hitw2 sounds/hellblazer/blaze_hitw2.ogg $random hellblazer/hitw { hellblazer/hitw1 hellblazer/hitw2 } diff --git a/sprites/RFLMA0.png b/sprites/RFLMA0.png new file mode 100644 index 000000000..b636e9767 Binary files /dev/null and b/sprites/RFLMA0.png differ diff --git a/sprites/RFLMB0.png b/sprites/RFLMB0.png new file mode 100644 index 000000000..47044c541 Binary files /dev/null and b/sprites/RFLMB0.png differ diff --git a/sprites/RFLMC0.png b/sprites/RFLMC0.png new file mode 100644 index 000000000..d62da63ba Binary files /dev/null and b/sprites/RFLMC0.png differ diff --git a/sprites/RFLMD0.png b/sprites/RFLMD0.png new file mode 100644 index 000000000..ec77a9596 Binary files /dev/null and b/sprites/RFLMD0.png differ diff --git a/sprites/RFLME0.png b/sprites/RFLME0.png new file mode 100644 index 000000000..2da6141f2 Binary files /dev/null and b/sprites/RFLME0.png differ diff --git a/sprites/RFLMF0.png b/sprites/RFLMF0.png new file mode 100644 index 000000000..0636c00c1 Binary files /dev/null and b/sprites/RFLMF0.png differ diff --git a/sprites/RFLMG0.png b/sprites/RFLMG0.png new file mode 100644 index 000000000..c2f862adc Binary files /dev/null and b/sprites/RFLMG0.png differ diff --git a/sprites/RFLMH0.png b/sprites/RFLMH0.png new file mode 100644 index 000000000..941c51322 Binary files /dev/null and b/sprites/RFLMH0.png differ diff --git a/sprites/RFLMI0.png b/sprites/RFLMI0.png new file mode 100644 index 000000000..1ee7c626f Binary files /dev/null and b/sprites/RFLMI0.png differ diff --git a/sprites/RFLMJ0.png b/sprites/RFLMJ0.png new file mode 100644 index 000000000..10a84a0d4 Binary files /dev/null and b/sprites/RFLMJ0.png differ diff --git a/sprites/RFLMK0.png b/sprites/RFLMK0.png new file mode 100644 index 000000000..912d66372 Binary files /dev/null and b/sprites/RFLMK0.png differ diff --git a/sprites/RFLML0.png b/sprites/RFLML0.png new file mode 100644 index 000000000..430ac6526 Binary files /dev/null and b/sprites/RFLML0.png differ diff --git a/sprites/RFLMM0.png b/sprites/RFLMM0.png new file mode 100644 index 000000000..15eed6ece Binary files /dev/null and b/sprites/RFLMM0.png differ diff --git a/sprites/RFLMN0.png b/sprites/RFLMN0.png new file mode 100644 index 000000000..b9557403c Binary files /dev/null and b/sprites/RFLMN0.png differ diff --git a/sprites/RFLMO0.png b/sprites/RFLMO0.png new file mode 100644 index 000000000..6c265e38b Binary files /dev/null and b/sprites/RFLMO0.png differ diff --git a/sprites/RFLMP0.png b/sprites/RFLMP0.png new file mode 100644 index 000000000..5c766f606 Binary files /dev/null and b/sprites/RFLMP0.png differ diff --git a/sprites/RFLMQ0.png b/sprites/RFLMQ0.png new file mode 100644 index 000000000..7ce7656e0 Binary files /dev/null and b/sprites/RFLMQ0.png differ diff --git a/sprites/RFLMR0.png b/sprites/RFLMR0.png new file mode 100644 index 000000000..3830ffa51 Binary files /dev/null and b/sprites/RFLMR0.png differ diff --git a/sprites/RFLMS0.png b/sprites/RFLMS0.png new file mode 100644 index 000000000..39c9ddd77 Binary files /dev/null and b/sprites/RFLMS0.png differ diff --git a/sprites/RFLMT0.png b/sprites/RFLMT0.png new file mode 100644 index 000000000..42ac58a1b Binary files /dev/null and b/sprites/RFLMT0.png differ diff --git a/zmapinfo.txt b/zmapinfo.txt index 253e16321..308f08b8a 100644 --- a/zmapinfo.txt +++ b/zmapinfo.txt @@ -1,17 +1,17 @@ GameInfo { - AddEventHandlers = "SWWMCrashHandler", "SWWMBrutalHandler", "SWWMHandler" + AddEventHandlers = "SWWMCrashHandler", "SWWMBrutalHandler", "SWWMVanillaBossHandler", "SWWMHandler" PlayerClasses = "Demolitionist" StatusBarClass = "SWWMStatusBar" BackpackType = "HammerspaceEmbiggener" StatScreen_Single = "SWWMStatScreen_SP" StatScreen_Coop = "SWWMStatScreen_Coop" StatScreen_DM = "SWWMStatScreen_DM" - QuitSound = "" + QuitSound = "misc/teleport" QuitMessages = "$QUITMSG", "$QUITMSG1", "$QUITMSG2", "$QUITMSG3", "$QUITMSG4", "$QUITMSG5", "$QUITMSG6", "$QUITMSG7", "$QUITMSG8", "$QUITMSG9", "$QUITMSG10", "$QUITMSG11", - "$QUITMSG12", "$QUITMSG13", "$QUITMSG14", "$QUITMSG15" + "$QUITMSG12", "$QUITMSG13", "$QUITMSG14" ChatSound = "misc/chat" IntermissionMusic = "music/DRAGONY.XM" DefaultConversationMenuClass = "SWWMConversationMenu" diff --git a/zscript.txt b/zscript.txt index 7d16c7e06..185a5ded9 100644 --- a/zscript.txt +++ b/zscript.txt @@ -25,6 +25,7 @@ version "4.3" #include "zscript/swwm_title.zsc" #include "zscript/swwm_inter.zsc" #include "zscript/swwm_strife.zsc" +#include "zscript/swwm_vanillaboss.zsc" // items #include "zscript/swwm_health.zsc" #include "zscript/swwm_armor.zsc" diff --git a/zscript/swwm_blazeit.zsc b/zscript/swwm_blazeit.zsc index 674247fa5..8dbc1777d 100644 --- a/zscript/swwm_blazeit.zsc +++ b/zscript/swwm_blazeit.zsc @@ -10,6 +10,24 @@ Class HellblazerExplLight : PaletteLight ReactionTime 25; } } +Class HellblazerExplLight2 : PaletteLight +{ + Default + { + Tag "HellExpl"; + Args 0,0,0,120; + ReactionTime 20; + } +} +Class HellblazerExplLight3 : PaletteLight +{ + Default + { + Tag "HellExpl"; + Args 0,0,0,900; + ReactionTime 60; + } +} Class HellblazerSubExpl : Actor { @@ -54,6 +72,27 @@ Class HellblazerRing : Actor } } +Class HellblazerRing2 : Actor +{ + Default + { + RenderStyle "Add"; + Scale 3.; + Radius 0.1; + Height 0; + +NOGRAVITY; + +NOBLOCKMAP; + +FORCEXYBILLBOARD; + +NOTELEPORT; + } + States + { + Spawn: + XRG3 ABCDEFGHIJKLMNOPQRSTUVWX 1 Bright A_SetScale(scale.x*1.1); + Stop; + } +} + Class HellblazerTrail : Actor { Default @@ -138,6 +177,8 @@ Class HellblazerFlare : Actor // rockets Class HellblazerMissile : Actor { + int deto; + Default { Obituary "$O_HELLBLAZER"; @@ -162,7 +203,7 @@ Class HellblazerMissile : Actor } } - action void A_BlazerTick( Color smokecol ) + void A_BlazerTick( Color smokecol ) { Vector3 traildir = -(cos(angle)*cos(pitch),sin(angle)*cos(pitch),sin(-pitch)); for ( int i=0; i<3; i++ ) @@ -182,18 +223,23 @@ Class HellblazerMissile : Actor t.vel = traildir*4.; } } + if ( deto > 1 ) + { + ExplodeMissile(); + return; + } // proximity check let bt = BlockThingsIterator.Create(self,200); while ( bt.Next() ) { let t = bt.Thing; - if ( !t || !t.bSHOOTABLE || !t.bISMONSTER || (t.Health <= 0) || t.IsFriend(target) || !SWWMUtility.SphereIntersect(t,pos,bNOGRAVITY?50:90) || !CheckSight(t,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue; - ExplodeMissile(); + if ( !t || !t.bSHOOTABLE || (!t.bISMONSTER && !(t is 'BossBrain')) || (t.Health <= 0) || t.IsFriend(target) || !SWWMUtility.SphereIntersect(t,level.Vec3Offset(pos,vel),bNOGRAVITY?50:90) || !CheckSight(t,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue; + deto++; break; } } - action void A_BlazerMissileExplode() + void A_BlazerMissileExplode() { bForceXYBillboard = true; bRollSprite = false; @@ -201,7 +247,7 @@ Class HellblazerMissile : Actor A_SprayDecal("BigScorch",50); A_SetScale(4.5); SWWMHandler.DoBlast(self,200,320000); - A_Explode(500,200,fulldamagedistance:(bNOGRAVITY?50:90)); + A_Explode(500,200); A_NoGravity(); A_QuakeEx(5,5,5,15,0,1500,"",QF_RELATIVE|QF_SCALEDOWN,falloff:500,rollIntensity:.8); A_StopSound(CHAN_BODY); @@ -238,7 +284,7 @@ Class HellblazerMissile : Actor Spawn("HellblazerRing",pos); } - action void A_SubExpl() + void A_SubExpl( double xscale = 1. ) { special1++; if ( (special1 > 8) || !(special1%2) ) return; @@ -250,7 +296,7 @@ Class HellblazerMissile : Actor pt = FRandom[Hellblazer](-90,90); FLineTraceData d; Vector3 HitNormal; - LineTrace(ang,FRandom[Hellblazer](10,20)+10*special1,pt,TRF_THRUACTORS,data:d); + LineTrace(ang,FRandom[Hellblazer](10,20)+10*special1*xscale,pt,TRF_THRUACTORS,data:d); hitnormal = -d.HitDir; if ( d.HitType == TRACE_HitFloor ) { @@ -271,7 +317,7 @@ Class HellblazerMissile : Actor p.angle = atan2(hitnormal.y,hitnormal.x); p.pitch = asin(-hitnormal.z); p.target = target; - p.scale *= 2-special1*.1; + p.scale *= xscale*(2-special1*.1); p.alpha *= 1-special1*.1; } } @@ -290,31 +336,273 @@ Class HellblazerMissile : Actor Class HellblazerCrackshot : HellblazerMissile { + void A_BlazerCrackshotExplode() + { + bForceXYBillboard = true; + bRollSprite = false; + A_SetRenderStyle(1.0,STYLE_Add); + A_SprayDecal("BigScorch",50); + A_SetScale(6.); + SWWMHandler.DoBlast(self,250,320000); + A_Explode(500,250); + A_NoGravity(); + A_QuakeEx(6,6,6,20,0,2000,"",QF_RELATIVE|QF_SCALEDOWN,falloff:800,rollIntensity:1.); + A_StopSound(CHAN_BODY); + A_StartSound("hellblazer/hitc",CHAN_WEAPON,attenuation:.7); + A_StartSound("hellblazer/hitc",CHAN_VOICE,attenuation:.4); + A_AlertMonsters(3000); + Spawn("HellblazerExplLight",pos); + int numpt = Random[Hellblazer](16,32); + for ( int i=0; i 10) || (special2%3) ) return; + int numpt = 6-special2/2; + for ( int i=0; i 85 ) ExplodeMissile(); + ReactionTime--; + if ( ReactionTime <= 0 ) ExplodeMissile(); } void A_HandleBounce() { @@ -438,6 +727,7 @@ Class HellblazerMissile2 : HellblazerMissile BounceFactor 1.; WallBounceFactor 1.; Gravity .35; + ReactionTime 85; -NOGRAVITY; +USEBOUNCESTATE; +BOUNCEONWALLS; @@ -461,6 +751,7 @@ Class HellblazerCrackshot2 : HellblazerCrackshot BounceFactor 1.; WallBounceFactor 1.; Gravity .35; + ReactionTime 85; -NOGRAVITY; +USEBOUNCESTATE; +BOUNCEONWALLS; @@ -484,6 +775,7 @@ Class HellblazerRavager2 : HellblazerRavager BounceFactor 1.; WallBounceFactor 1.; Gravity .35; + ReactionTime 85; -NOGRAVITY; +USEBOUNCESTATE; +BOUNCEONWALLS; @@ -507,6 +799,7 @@ Class HellblazerWarhead2 : HellblazerWarhead BounceFactor 1.; WallBounceFactor 1.; Gravity .35; + ReactionTime 85; -NOGRAVITY; +USEBOUNCESTATE; +BOUNCEONWALLS; @@ -521,25 +814,501 @@ Class HellblazerWarhead2 : HellblazerWarhead } } +Class HellblazerClusterMini : HellblazerMissile +{ + Mixin HellblazerGrenade; + + Default + { + Radius 2; + Height 4; + Speed 20; + BounceFactor 1.; + WallBounceFactor 1.; + Gravity .35; + ReactionTime 30; + -NOGRAVITY; + +USEBOUNCESTATE; + +BOUNCEONWALLS; + +BOUNCEONFLOORS; + +BOUNCEONCEILINGS; + +ALLOWBOUNCEONACTORS; + +DONTBOUNCEONSKY; + +CANBOUNCEWATER; + +INTERPOLATEANGLES; + +ROLLSPRITE; + +ROLLCENTER; + } + + void A_ClusterTick( Color smokecol ) + { + Vector3 traildir = -(cos(angle)*cos(pitch),sin(angle)*cos(pitch),sin(-pitch)); + for ( int i=0; i<2; i++ ) + { + let s = Spawn("SWWMSmoke",level.Vec3Offset(pos,traildir*3)); + s.SetShade(smokecol*Random[Hellblazer](48,63)); + s.scale *= FRandom[Hellblazer](.6,.8); + s.special1 = Random[Hellblazer](0,1); + s.alpha *= .4; + s.vel = .3*vel + (traildir+(FRandom[Hellblazer](-.4,.4),FRandom[Hellblazer](-.4,.4),FRandom[Hellblazer](-.4,.4))).unit()*FRandom[Hellblazer](1.,2.); + } + if ( (deto > 2) && (GetAge() > 4) ) + { + ExplodeMissile(); + return; + } + // proximity check + let bt = BlockThingsIterator.Create(self,200); + while ( bt.Next() ) + { + let t = bt.Thing; + if ( !t || !t.bSHOOTABLE || (!t.bISMONSTER && !(t is 'BossBrain')) || (t.Health <= 0) || t.IsFriend(target) || !SWWMUtility.SphereIntersect(t,level.Vec3Offset(pos,vel),80) || !CheckSight(t,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue; + deto++; + break; + } + } + + void A_ClusterExplode() + { + bForceXYBillboard = true; + bRollSprite = false; + A_SetRenderStyle(1.0,STYLE_Add); + A_SprayDecal("BigScorch",50); + A_SetScale(2.5); + SWWMHandler.DoBlast(self,150,200000); + A_Explode(100,150); + A_NoGravity(); + A_QuakeEx(4,4,4,12,0,1000,"",QF_RELATIVE|QF_SCALEDOWN,falloff:400,rollIntensity:.6); + A_StopSound(CHAN_BODY); + A_StartSound("hellblazer/hitcs",CHAN_WEAPON,attenuation:.9); + A_StartSound("hellblazer/hitcs",CHAN_VOICE,attenuation:.5); + A_AlertMonsters(2000); + Spawn("HellblazerExplLight2",pos); + int numpt = Random[Hellblazer](6,16); + for ( int i=0; i 5) || !(special1%2) ) return; + int numpt = Random[Hellblazer](0,5-special1); + double ang, pt; + for ( int i=0; i0)?.1:.02); + scale += initsc*.2; + } + States + { + Spawn: + RFLM ABCDEFGHIJKLMNOPQRST -1 Bright; + Stop; + } +} + +Class HellblazerRavagerArm : Actor +{ + Vector3 oldvel; + + Default + { + Obituary "$O_HELLBLAZER"; + DamageType 'Fire'; + +NOBLOCKMAP; + +THRUACTORS; + +BOUNCEONWALLS; + +BOUNCEONFLOORS; + +BOUNCEONCEILINGS; + +USEBOUNCESTATE; + +MISSILE; + +NODAMAGETHRUST; + +FORCERADIUSDMG; + +NOTELEPORT; + -NOGRAVITY; + Gravity 0.15; + BounceFactor 1.0; + Radius 2; + Height 2; + } + override void PostBeginPlay() + { + Super.PostBeginPlay(); + reactiontime = Random[ExploS](18,24); + vel = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch))*FRandom[ExploS](10.,30.); + } + override void Tick() + { + oldvel = vel; + Super.Tick(); + } + void A_HandleBounce() + { + Vector3 HitNormal = -vel.unit(); + F3DFloor ff; + if ( BlockingFloor ) + { + // find closest 3d floor for its normal + for ( int i=0; i= (BlockingMobj.pos.x+BlockingMobj.radius) ) + HitNormal = (1,0,0); + else if ( (pos.y+radius) <= (BlockingMobj.pos.y-BlockingMobj.radius) ) + HitNormal = (0,-1,0); + else if ( (pos.y-radius) >= (BlockingMobj.pos.y+BlockingMobj.radius) ) + HitNormal = (0,1,0); + else if ( pos.z >= (BlockingMobj.pos.z+BlockingMobj.height) ) + HitNormal = (0,0,1); + else if ( (pos.z+height) <= BlockingMobj.pos.z ) + HitNormal = (0,0,-1); + } + // undo the bounce, we need to hook in our own + vel = oldvel; + // re-do the bounce with our formula + vel = .8*((vel dot HitNormal)*HitNormal*FRandom[Hellblazer](-1.5,-1.)+vel); + bHITOWNER = true; + } + States + { + Spawn: + TNT1 A 1 + { + if ( waterlevel > 0 ) ReactionTime -= 2; + A_CountDown(); + let p = Spawn("RavagerPuff",pos); + p.alpha *= .6+.4*(ReactionTime/20.); + p.scale *= 3.5-2.5*(ReactionTime/20.); + if ( !(ReactionTime%3) ) + { + let l = Spawn("RavagerLight",pos); + l.Args[3] = int(90+50*(ReactionTime/20.)); + l.ReactionTime = int(2+8*(ReactionTime/20.)); + l.target = p; + } + if ( !(GetAge()%2) ) + { + SWWMHandler.DoBlast(self,250-6*reactiontime,1000+200*reactiontime,bHITOWNER?null:target); + A_Explode(4+reactiontime*4,250-6*reactiontime,bHITOWNER?XF_HURTSOURCE:0); + } + double spd = vel.length(); + vel = (vel*.4+(FRandom[ExploS](-.2,.2),FRandom[ExploS](-.2,.2),FRandom[ExploS](-.2,.2))).unit()*spd; + Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](1,5); + if ( !(ReactionTime%2) ) + { + let s = Spawn("SWWMSmoke",pos); + s.vel = pvel+vel*.2; + s.SetShade(Color(4,2,2)*Random[ExploS](48,63)); + s.special1 = Random[ExploS](2,4); + s.scale *= 3.2; + s.alpha *= .1+.2*(ReactionTime/20.); + int numpt = Random[Hellblazer](-2,4); + for ( int i=0; i loadammo, nextammo; + int spinskipped; Property ClipCount : clipcount; - transient ui TextureID WeaponBox, AmmoIcon; + transient ui TextureID WeaponBox, AmmoIcon[4], LoadedIcon[4]; transient ui Font TewiFont; override void DrawWeapon( double TicFrac, double bx, double by, Vector2 hs, Vector2 ss ) { + static const Class types[] = {"HellblazerMissiles","HellblazerCrackshots","HellblazerRavagers","HellblazerWarheads"}; if ( !TewiFont ) TewiFont = Font.GetFont('TewiShaded'); - // DEBUG - Screen.DrawText(TewiFont,Font.CR_RED,bx-160,by-59,"NOT YET FULLY IMPLEMENTED",DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); - Screen.DrawText(TewiFont,Font.CR_RED,bx-160,by-46,String.Format("Loaded: %s",loadammo?GetDefaultByType(loadammo).GetTag():"(null)"),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); - Screen.DrawText(TewiFont,Font.CR_RED,bx-160,by-33,String.Format("Next: %s",nextammo?GetDefaultByType(nextammo).GetTag():"(null)"),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); - Screen.DrawText(TewiFont,Font.CR_RED,bx-160,by-20,String.Format("Clip: %d / %d",clipcount,LoadedCapacity()),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); - // TODO the ammo display itself + if ( !WeaponBox ) + { + WeaponBox = TexMan.CheckForTexture("graphics/HUD/HellblazerDisplay.png",TexMan.Type_Any); + AmmoIcon[0] = TexMan.CheckForTexture("graphics/HUD/HellblazerMissile.png",TexMan.Type_Any); + AmmoIcon[1] = TexMan.CheckForTexture("graphics/HUD/HellblazerCrackshot.png",TexMan.Type_Any); + AmmoIcon[2] = TexMan.CheckForTexture("graphics/HUD/HellblazerRavager.png",TexMan.Type_Any); + AmmoIcon[3] = TexMan.CheckForTexture("graphics/HUD/HellblazerWarhead.png",TexMan.Type_Any); + LoadedIcon[0] = TexMan.CheckForTexture("graphics/HUD/HellblazerMissileLoaded.png",TexMan.Type_Any); + LoadedIcon[1] = TexMan.CheckForTexture("graphics/HUD/HellblazerCrackshotLoaded.png",TexMan.Type_Any); + LoadedIcon[2] = TexMan.CheckForTexture("graphics/HUD/HellblazerRavagerLoaded.png",TexMan.Type_Any); + LoadedIcon[3] = TexMan.CheckForTexture("graphics/HUD/HellblazerWarheadLoaded.png",TexMan.Type_Any); + } + double xx = -57, yy = -50; + Screen.DrawTexture(WeaponBox,false,bx+xx,by+yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); + int curtype = 0; + for ( int i=0; i<4; i++ ) + { + if ( loadammo != types[i] ) continue; + curtype = i; + break; + } + xx += 2; + yy += 1; + for ( int i=0; i<4; i++ ) + { + int amt = CountInv(types[i]); + String amtstr = String.Format("%3d",amt); + Screen.DrawText(TewiFont,Font.CR_FIRE,bx+xx,by+yy,amtstr,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,(types[i]==nextammo)?Color(0,0,0,0):Color(128,0,0,0)); + Screen.DrawTexture(AmmoIcon[i],false,bx+xx+19,by+yy+1,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,(types[i]==nextammo)?Color(0,0,0,0):Color(128,0,0,0)); + yy += 13; + if ( i%2 ) + { + yy -= 26; + xx += 28; + } + } + yy = -19; + switch ( curtype ) + { + case 0: + xx = -55; + for ( int i=0; i<6; i++ ) + { + Screen.DrawTexture(LoadedIcon[0],false,bx+xx,by+yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,(i==magpos)?magstate[i]?Color(192,0,0,0):Color(0,0,0,0):magstate[i]?Color(224,0,0,0):Color(96,0,0,0)); + xx += 9; + } + break; + case 1: + xx = -50; + for ( int i=0; i<3; i++ ) + { + Screen.DrawTexture(LoadedIcon[1],false,bx+xx,by+yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,(i==magpos)?magstate[i]?Color(192,0,0,0):Color(0,0,0,0):magstate[i]?Color(224,0,0,0):Color(96,0,0,0)); + xx += 18; + } + break; + case 2: + xx = -50; + for ( int i=0; i<3; i++ ) + { + Screen.DrawTexture(LoadedIcon[2],false,bx+xx,by+yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,(i==magpos)?magstate[i]?Color(192,0,0,0):Color(0,0,0,0):magstate[i]?Color(224,0,0,0):Color(96,0,0,0)); + xx += 18; + } + break; + case 3: + xx = -46; + for ( int i=0; i<2; i++ ) + { + Screen.DrawTexture(LoadedIcon[3],false,bx+xx,by+yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_ColorOverlay,(i==magpos)?magstate[i]?Color(192,0,0,0):Color(0,0,0,0):magstate[i]?Color(224,0,0,0):Color(96,0,0,0)); + xx += 27; + } + break; + } } action void A_HellblazerFire( int type = 0, bool bAlt = false ) @@ -556,6 +1325,8 @@ Class Hellblazer : SWWMWeapon A_ZoomFactor(1.); A_Recoil(bAlt?.3:.5); invoker.clipcount = max(0,invoker.clipcount-1); + invoker.magstate[invoker.magpos] = true; + invoker.spinskipped++; Vector3 x, y, z, x2, y2, z2, dir, origin; double a, s; [x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll); @@ -710,6 +1481,9 @@ Class Hellblazer : SWWMWeapon invoker.clipcount = invoker.LoadedCapacity(); if ( !sv_infiniteammo && !FindInventory('PowerInfiniteAmmo',true) ) amo.Amount = max(0,amo.Amount-takeamt); + invoker.magpos = 0; + for ( int i=0; i<6; i++ ) + invoker.magstate[i] = !(invoker.clipcount > i); return; } // re-add/drop any still loaded @@ -721,6 +1495,9 @@ Class Hellblazer : SWWMWeapon invoker.clipcount = 0; invoker.loadammo = invoker.nextammo; invoker.clipcount = invoker.LoadedCapacity(); + invoker.magpos = 0; + for ( int i=0; i<6; i++ ) + invoker.magstate[i] = !(invoker.clipcount > i); if ( !sv_infiniteammo && !FindInventory('PowerInfiniteAmmo',true) ) { let namo = FindInventory(invoker.loadammo); @@ -746,6 +1523,20 @@ Class Hellblazer : SWWMWeapon invoker.CheckAmmo(EitherFire,true); } + // check if weapon was dropped or interrupted in some way before the mag spin could be done + action void A_CheckSpinSkip() + { + static const Class types[] = {"HellblazerMissiles","HellblazerCrackshots","HellblazerRavagers","HellblazerWarheads"}; + static const int magcap[] = {6,3,3,2}; + for ( int i=0; i<4; i++ ) + { + if ( invoker.loadammo != types[i] ) continue; + invoker.magpos = (invoker.magpos+invoker.spinskipped)%magcap[i]; + invoker.spinskipped = 0; + break; + } + } + Default { Tag "$T_HELLBLAZER"; @@ -768,6 +1559,7 @@ Class Hellblazer : SWWMWeapon Select: XZW2 I 0 { + A_CheckSpinSkip(); A_FullRaise(); return A_JumpByAmmoType("Select_1","Select_2","Select_3","Select_4","Select_G"); } @@ -895,14 +1687,24 @@ Class Hellblazer : SWWMWeapon XZWM PQRSTUV 2; Goto Ready_G; // state jump to cycling is done elsewhere Cycle_1: - XZW2 A 3 A_GlassOverlay("Cycle_G1"); + XZW2 A 3 + { + invoker.spinskipped--; + invoker.magpos = (invoker.magpos+1)%6; + A_GlassOverlay("Cycle_G1"); + } XZW3 E 3; XZW3 FGHI 2; XZW3 I 0; XZW3 FE 3; Goto Ready_1; Cycle_2: - XZW6 V 3 A_GlassOverlay("Cycle_G2"); + XZW6 V 3 + { + invoker.spinskipped--; + invoker.magpos = (invoker.magpos+1)%3; + A_GlassOverlay("Cycle_G2"); + } XZW7 Z 3; XZW8 ABCDEFG 2; XZW8 G 0; @@ -910,7 +1712,12 @@ Class Hellblazer : SWWMWeapon XZW7 Z 3; Goto Ready_2; Cycle_3: - XZWB T 3 A_GlassOverlay("Cycle_G2"); + XZWB T 3 + { + invoker.spinskipped--; + invoker.magpos = (invoker.magpos+1)%3; + A_GlassOverlay("Cycle_G2"); + } XZWC X 3; XZWC YZ 2; XZWD ABCDE 2; @@ -918,7 +1725,12 @@ Class Hellblazer : SWWMWeapon XZWC YX 3; Goto Ready_3; Cycle_4: - XZWG R 3 A_GlassOverlay("Cycle_G3"); + XZWG R 3 + { + invoker.spinskipped--; + invoker.magpos = (invoker.magpos+1)%2; + A_GlassOverlay("Cycle_G3"); + } XZWH V 3; XZWH WXYZ 2; XZWI ABCDEF 2; diff --git a/zscript/swwm_common.zsc b/zscript/swwm_common.zsc index e898aa2b7..12a6d7561 100644 --- a/zscript/swwm_common.zsc +++ b/zscript/swwm_common.zsc @@ -2126,6 +2126,8 @@ Class SWWMHandler : EventHandler DoKeyTagFix(e.Thing); SWWMInterest.Spawn(thekey:Key(e.Thing)); } + else if ( e.Thing is 'BossBrain' ) e.Thing.SetTag("$FN_BOSSBRAIN"); + else if ( e.Thing is 'CommanderKeen' ) e.Thing.SetTag("$FN_KEEN"); if ( (e.Thing.bSHOOTABLE || e.Thing.bISMONSTER) && !(e.Thing is 'LampMoth') && !(e.Thing is 'CompanionLamp') ) SWWMCombatTracker.Spawn(e.Thing); } diff --git a/zscript/swwm_hud.zsc b/zscript/swwm_hud.zsc index 909606578..cf8d409db 100644 --- a/zscript/swwm_hud.zsc +++ b/zscript/swwm_hud.zsc @@ -23,6 +23,8 @@ Class SWWMStatusBar : BaseStatusBar // the event handler, holding all sorts of stuff SWWMHandler hnd; + // the boss stuff handler, for the boss healthbar + SWWMVanillaBossHandler bosshnd; // client cvars transient CVar safezone, maxchat[2], maxpick, chatduration, msgduration, pickduration, chatcol, teamcol, obitcol, critcol, pickcol, targetter, healthnums, scorenums, scorebonus, targettag, lang; @@ -765,80 +767,79 @@ Class SWWMStatusBar : BaseStatusBar Screen.DrawText(mTewiFont.mFont,hcolor,margin+108,ss.y-(margin+16),String.Format("%3d",clamp(ht,0,999)),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); } + private void DrawPickups() + { + if ( !pickduration ) pickduration = CVar.GetCVar('swwm_pickduration',players[consoleplayer]); + if ( !pickcol ) pickcol = CVar.GetCVar('msg0color',players[consoleplayer]); + if ( PickupQueue.Size() <= 0 ) return; + // reverse order since they're drawn bottom to top + int mend = max(0,PickupQueue.Size()-(1+maxpick.GetInt())); + double yy = ss.y-(margin+50); + if ( bosshnd && (bosshnd.alpha > 0.) ) yy -= int(25*clamp(bosshnd.alpha*2.,0.,1.)); + for ( int i=PickupQueue.Size()-1; i>=mend; i-- ) + { + String cstr = PickupQueue[i].str; + if ( PickupQueue[i].rep > 1 ) cstr.AppendFormat(" (x%d)",PickupQueue[i].rep); + int curtime = (PickupQueue[i].tic+35*pickduration.GetInt())-level.totaltime; + double alph = clamp(curtime/20.,0.,1.); + Font fnt = LangFont(mTewiFont); + BrokenLines l = fnt.BreakLines(cstr,int(ss.x*.75)); + int maxlen = 0; + for ( int j=0; j maxlen ) maxlen = len; + } + int h = fnt.GetHeight(); + double xx = (ss.x-maxlen)/2.; + Screen.Dim("Black",.8*alph,int((xx-6)*hs.x),int((yy-h*(l.Count()-1))*hs.y),int((maxlen+12)*hs.x),int((h*l.Count()+4)*hs.y)); + for ( int j=l.Count()-1; j>=0; j-- ) + { + int len = fnt.StringWidth(l.StringAt(j)); + xx = (ss.x-len)/2.; + Screen.DrawText(fnt,pickcol.GetInt(),xx,yy+2,l.StringAt(j),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph); + yy -= h; + } + yy -= 6; + } + } + private void DrawMessages() { if ( !chatduration ) chatduration = CVar.GetCVar('swwm_chatduration',players[consoleplayer]); if ( !msgduration ) msgduration = CVar.GetCVar('swwm_msgduration',players[consoleplayer]); - if ( !pickduration ) pickduration = CVar.GetCVar('swwm_pickduration',players[consoleplayer]); - if ( !pickcol ) pickcol = CVar.GetCVar('msg0color',players[consoleplayer]); if ( !obitcol ) obitcol = CVar.GetCVar('msg1color',players[consoleplayer]); if ( !critcol ) critcol = CVar.GetCVar('msg2color',players[consoleplayer]); if ( !chatcol ) chatcol = CVar.GetCVar('msg3color',players[consoleplayer]); if ( !teamcol ) teamcol = CVar.GetCVar('msg4color',players[consoleplayer]); - // common message area - if ( MainQueue.Size() > 0 ) + if ( MainQueue.Size() <= 0 ) return; + int mstart = max(0,MainQueue.Size()-(1+maxchat[chatopen>=gametic].GetInt())); + double xx = margin, yy = margin; + bool smol = (ss.x<640); + Screen.DrawTexture(ChatTex[smol?3:0],false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); + yy++; + for ( int i=mstart; i=gametic].GetInt())); - double xx = margin, yy = margin; - bool smol = (ss.x<640); - Screen.DrawTexture(ChatTex[smol?3:0],false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); - yy++; - for ( int i=mstart; i 1 ) cstr.AppendFormat(" (x%d)",MainQueue[i].rep); + int curtime = MainQueue[i].tic-level.totaltime; + if ( MainQueue[i].type < PRINT_CHAT ) curtime += 35*msgduration.GetInt(); + else curtime += 35*chatduration.GetInt(); + double alph = clamp(curtime/20.,0.,1.); + Font fnt = LangFont(mTewiFont); + BrokenLines l = fnt.BreakLines(cstr,smol?211:361); + for ( int j=0; j 1 ) cstr.AppendFormat(" (x%d)",MainQueue[i].rep); - int curtime = MainQueue[i].tic-level.totaltime; - if ( MainQueue[i].type < PRINT_CHAT ) curtime += 35*msgduration.GetInt(); - else curtime += 35*chatduration.GetInt(); - double alph = clamp(curtime/20.,0.,1.); - Font fnt = LangFont(mTewiFont); - BrokenLines l = fnt.BreakLines(cstr,smol?211:361); - for ( int j=0; j 0 ) - { - // reverse order since they're drawn bottom to top - int mend = max(0,PickupQueue.Size()-(1+maxpick.GetInt())); - double yy = ss.y-(margin+50); - for ( int i=PickupQueue.Size()-1; i>=mend; i-- ) - { - String cstr = PickupQueue[i].str; - if ( PickupQueue[i].rep > 1 ) cstr.AppendFormat(" (x%d)",PickupQueue[i].rep); - int curtime = (PickupQueue[i].tic+35*pickduration.GetInt())-level.totaltime; - double alph = clamp(curtime/20.,0.,1.); - Font fnt = LangFont(mTewiFont); - BrokenLines l = fnt.BreakLines(cstr,int(ss.x*.75)); - int maxlen = 0; - for ( int j=0; j maxlen ) maxlen = len; - } - int h = fnt.GetHeight(); - double xx = (ss.x-maxlen)/2.; - Screen.Dim("Black",.8*alph,int((xx-6)*hs.x),int((yy-h*(l.Count()-1))*hs.y),int((maxlen+12)*hs.x),int((h*l.Count()+4)*hs.y)); - for ( int j=l.Count()-1; j>=0; j-- ) - { - int len = fnt.StringWidth(l.StringAt(j)); - xx = (ss.x-len)/2.; - Screen.DrawText(fnt,pickcol.GetInt(),xx,yy+2,l.StringAt(j),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph); - yy -= h; - } - yy -= 6; + Screen.DrawTexture(ChatTex[smol?4:1],false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); + Screen.DrawText(fnt,col,xx+4,yy,l.StringAt(j),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph); + yy += 13; } } + Screen.DrawTexture(ChatTex[smol?5:2],false,xx,yy,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true); } override bool DrawChat( String txt ) @@ -953,6 +954,9 @@ Class SWWMStatusBar : BaseStatusBar DrawInventory(); DrawStatus(); DrawWeapon(); + if ( !bosshnd ) bosshnd = SWWMVanillaBossHandler(EventHandler.Find("SWWMVanillaBossHandler")); + else bosshnd.DrawBossBar(self); + DrawPickups(); DrawDeath(); DrawMessages(); } diff --git a/zscript/swwm_inventory.zsc b/zscript/swwm_inventory.zsc index 4be91f8ea..948d18fcd 100644 --- a/zscript/swwm_inventory.zsc +++ b/zscript/swwm_inventory.zsc @@ -182,6 +182,7 @@ Class SWWMHealth : Inventory abstract override void ModifyDamage( int damage, Name damageType, out int newdamage, bool passive, Actor inflictor, Actor source, int flags ) { + if ( damageType == 'EndLevel' ) return; bool shouldautouse = false; if ( swwm_enforceautousehealth == 1 ) shouldautouse = true; else if ( swwm_enforceautousehealth == -1 ) shouldautouse = false; diff --git a/zscript/swwm_jackhammer.zsc b/zscript/swwm_jackhammer.zsc index 6c6da614d..89afdf568 100644 --- a/zscript/swwm_jackhammer.zsc +++ b/zscript/swwm_jackhammer.zsc @@ -413,7 +413,7 @@ Class PusherWeapon : SWWMWeapon { A_QuakeEx(8,8,8,12,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:.8); A_AlertMonsters(1600); - int dmg = int(150*invoker.chargelevel); + int dmg = int(300*invoker.chargelevel); if ( d.HitType == TRACE_HitActor ) { double diff = deltaangle(self.angle,AngleTo(d.HitActor)); diff --git a/zscript/swwm_player.zsc b/zscript/swwm_player.zsc index a916675e5..cd28283e4 100644 --- a/zscript/swwm_player.zsc +++ b/zscript/swwm_player.zsc @@ -489,7 +489,7 @@ Class Demolitionist : PlayerPawn // bump down weapon bumpdown = true; bumpvelz = -lastvelz; - if ( lastvelz < -30 ) + if ( lastvelz < -25 ) { let s = Spawn("DemolitionistShockwave",pos); s.target = self; @@ -602,6 +602,13 @@ Class Demolitionist : PlayerPawn // lucky collar if ( Health < 25 ) damage /= 4; if ( source == self ) damage /= 2; + if ( !inflictor && !source && (CurSector.flags&Sector.SECF_ENDLEVEL) ) + { + // end level hax + damage = max(50,health-100); + flags |= DMG_FORCED|DMG_NO_ARMOR; + mod = 'EndLevel'; + } lastdamage = Super.DamageMobj(inflictor,source,damage,mod,flags,angle); lastdamagetic = max(lastdamagetic,gametic+clamp(lastdamage/2,10,40)); if ( (lastdamage > 0) && (PainChance == 0) && (level.maptime>lastmpain) ) diff --git a/zscript/swwm_powerup.zsc b/zscript/swwm_powerup.zsc index cf011bc8d..31d11b706 100644 --- a/zscript/swwm_powerup.zsc +++ b/zscript/swwm_powerup.zsc @@ -40,6 +40,7 @@ Class GrilledCheeseSandwich : Inventory } override void ModifyDamage( int damage, Name damageType, out int newdamage, bool passive, Actor inflictor, Actor source, int flags ) { + if ( damageType == 'EndLevel' ) return; if ( passive && (Owner.Health-damage <= 0) && (Amount > 0) ) { newdamage = 0; @@ -502,15 +503,13 @@ Class InvinciballPower : Powerup override void ModifyDamage( int damage, Name damageType, out int newdamage, bool passive, Actor inflictor, Actor source, int flags ) { + if ( damageType == 'EndLevel' ) return; if ( (damage > 0) && passive ) { if ( (damagetype == 'Drowning') || (damagetype == 'Falling') || (damagetype == 'Poison') || (damagetype == 'PoisonCloud') ) return; // these go through armor and get ignored by the player if ( damageType == 'Ynykron' ) - { - newdamage = damage; - return; - } + return; // can't block this newdamage = 0; if ( level.maptime > lasteffect+5 ) { diff --git a/zscript/swwm_tastytreat.zsc b/zscript/swwm_tastytreat.zsc index ff8094a14..c83051330 100644 --- a/zscript/swwm_tastytreat.zsc +++ b/zscript/swwm_tastytreat.zsc @@ -172,7 +172,7 @@ Class CandyBeam : Actor { RenderStyle "Add"; Alpha 0.4; - DamageFunction 12; + DamageFunction 20; ReactionTime 12; Radius 0.1; Height 0; @@ -232,7 +232,7 @@ Class CandyPop : Actor { A_AlertMonsters(); SWWMHandler.DoBlast(self,120,60000); - A_Explode(50,120); + A_Explode(100,120); Scale *= FRandom[ExploS](0.6,1.8); Scale.x *= RandomPick[ExploS](-1,1); Scale.y *= RandomPick[ExploS](-1,1); @@ -273,7 +273,7 @@ Class TinyCandyBeam : CandyBeam Default { ReactionTime 12; - DamageFunction 5; + DamageFunction 10; } States { @@ -299,7 +299,7 @@ Class TinyCandyPop : CandyPop { A_AlertMonsters(); SWWMHandler.DoBlast(self,80,32000); - A_Explode(20,80); + A_Explode(40,80); Scale *= FRandom[ExploS](0.6,1.8); Scale.x *= RandomPick[ExploS](-1,1); Scale.y *= RandomPick[ExploS](-1,1); @@ -359,7 +359,7 @@ Class CandyMagArm : Actor SWWMHandler.DoBlast(self,50+6*reactiontime,3000+800*reactiontime); double spd = vel.length(); vel = (vel*.1+(FRandom[ExploS](-.7,.7),FRandom[ExploS](-.7,.7),FRandom[ExploS](-.7,.7))).unit()*spd; - A_Explode(20+reactiontime*3,50+6*reactiontime); + A_Explode(40+reactiontime*5,50+6*reactiontime); Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](1,5); let s = Spawn("SWWMSmoke",pos); s.vel = pvel+vel*.2; @@ -435,7 +435,7 @@ Class CandyMagArmBig : CandyMagArm SWWMHandler.DoBlast(self,100+8*reactiontime,3000+900*reactiontime); double spd = vel.length(); vel = (vel*.1+(FRandom[ExploS](-.5,.5),FRandom[ExploS](-.5,.5),FRandom[ExploS](-.5,.5))).unit()*spd; - A_Explode(50+reactiontime*5,100+8*reactiontime); + A_Explode(80+reactiontime*8,100+8*reactiontime); Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](1,5); let s = Spawn("SWWMSmoke",pos); s.vel = pvel+vel*.2; @@ -512,7 +512,7 @@ Class CandyGunProj : Actor Scale *= 6.+.2*special1; A_AlertMonsters(); SWWMHandler.DoBlast(self,300+20*special1,80000+8000*special1); - A_Explode(1500+200*special1,300+20*special1); + A_Explode(3000+400*special1,300+20*special1); A_QuakeEx(9,9,9,70,0,1500+100*special1,"",QF_RELATIVE|QF_SCALEDOWN,falloff:1200,rollintensity:2.); A_StartSound("candygun/gunhit",CHAN_VOICE,attenuation:.24); A_StartSound("candygun/gunhit",CHAN_WEAPON,attenuation:.12); @@ -621,7 +621,7 @@ Class CandyMagProj : Actor Scale *= 3.+.2*special1; A_AlertMonsters(); SWWMHandler.DoBlast(self,250+25*special1,80000+8000*special1); - A_Explode(300+200*special1,250+25*special1); + A_Explode(600+400*special1,250+25*special1); A_QuakeEx(9,9,9,30,0,500+80*special1,"",QF_RELATIVE|QF_SCALEDOWN,falloff:500,rollintensity:2.); A_StartSound("candygun/maghit",CHAN_VOICE,attenuation:.24); A_StartSound("candygun/maghit",CHAN_WEAPON,attenuation:.12); @@ -713,7 +713,7 @@ Class CandyBulletImpact : Actor Super.PostBeginPlay(); A_AlertMonsters(); SWWMHandler.DoBlast(self,200,48000); - A_Explode(300,200); + A_Explode(350,200); A_QuakeEx(6,6,6,15,0,300,"",QF_RELATIVE|QF_SCALEDOWN,falloff:200,rollintensity:0.2); A_StartSound("candygun/hit",CHAN_VOICE,attenuation:.25); A_StartSound("candygun/hit",CHAN_WEAPON,attenuation:.5); @@ -872,7 +872,7 @@ Class CandyGun : SWWMWeapon SWWMBulletTrail.DoTrail(self,origin,dir,10000,2); if ( d.HitType == TRACE_HitActor ) { - int dmg = 350; + int dmg = 500; SWWMHandler.DoKnockback(d.HitActor,d.HitDir,72000); dmg = d.HitActor.DamageMobj(invoker,self,dmg,'Explodium',DMG_USEANGLE|DMG_THRUSTLESS,atan2(d.HitDir.y,d.HitDir.x)); if ( d.HitActor.bNOBLOOD || d.HitActor.bINVULNERABLE ) diff --git a/zscript/swwm_vanillaboss.zsc b/zscript/swwm_vanillaboss.zsc new file mode 100644 index 000000000..2eab0f521 --- /dev/null +++ b/zscript/swwm_vanillaboss.zsc @@ -0,0 +1,274 @@ +// This is stuff for making vanilla doom/heretic/hexen boss encounters +// a bit more... "fair", so to speak +// Also adds cool Souls-style healthbars + +Class SWWMVanillaBossHandler : EventHandler +{ + String bosstag; + Array bossactors; + + Actor bossbrainactor; + Actor bossviewactor; + TextureID facetex[5]; + + bool initialized; + ui bool ui_initialized; + ui TextureID bbar_f, bbar_r, bbar_d; + ui double alpha; + ui DynamicValueInterpolator ihealth, ihealthr; + ui int thealth, hmax; + ui int oldhealth[30]; + ui int cummdamage, lastcummtic; // please do not misread + transient ui CVar dodrawbossbar; + + override void WorldThingSpawned( WorldEvent e ) + { + bool upgrademe = swwm_upgradebosses; + if ( gameinfo.gametype&GAME_Doom ) + { + if ( level.mapname ~== "E1M8" ) + { + if ( e.Thing is 'BaronOfHell' ) + { + bossactors.Push(e.Thing); + if ( upgrademe ) e.Thing.Health *= 3; + } + bosstag = "$BT_BRUISERS"; + } + else if ( level.mapname ~== "E2M8" ) + { + if ( e.Thing is 'Cyberdemon' ) + { + bossactors.Push(e.Thing); + if ( upgrademe ) e.Thing.Health *= 4; + } + bosstag = "$BT_CYBIE"; + } + else if ( (level.mapname ~== "E3M8") || (level.mapname ~== "E4M8") ) + { + if ( e.Thing is 'Spidermastermind' ) + { + bossactors.Push(e.Thing); + if ( upgrademe ) + { + if ( level.mapname ~== "E3M8" ) e.Thing.Health *= 5; + else e.Thing.Health *= 3; + } + } + bosstag = "$BT_SPIDER"; + } + else if ( level.mapname ~== "MAP30" ) + { + if ( e.Thing is 'BossBrain' ) + { + bossbrainactor = e.Thing; + bossactors.Push(e.Thing); + if ( upgrademe ) e.Thing.Health *= 16; // goodbye, instakills + } + if ( e.Thing is 'BossEye' ) + bossviewactor = e.Thing; + bosstag = "$BT_IOS"; + } + } + else if ( gameinfo.gametype&GAME_Heretic ) + { + if ( (level.mapname ~== "E1M8") || (level.mapname ~== "E4M8") ) + { + if ( e.Thing is 'IronLich' ) + { + bossactors.Push(e.Thing); + if ( upgrademe ) e.Thing.Health *= 4; + } + bosstag = "$BT_LICHES"; + } + else if ( (level.mapname ~== "E2M8") || (level.mapname ~== "E5M8") ) + { + if ( e.Thing is 'Minotaur' ) + { + bossactors.Push(e.Thing); + if ( upgrademe ) e.Thing.Health *= 2; + } + bosstag = "$BT_MINOTAUR"; + } + else if ( level.mapname ~== "E3M8" ) + { + if ( e.Thing is 'Sorcerer1' ) + { + bossactors.Push(e.Thing); + if ( upgrademe ) e.Thing.Health *= 2; + bosstag = "$BT_DSPARIL"; + } + else if ( e.Thing is 'Sorcerer2' ) + { + // second phase + bossactors.Clear(); + initialized = false; + bossactors.Push(e.Thing); + if ( upgrademe ) e.Thing.Health *= 3; + bosstag = "$BT_DSPARIL2"; + } + } + } + else if ( gameinfo.gametype&GAME_Hexen ) + { + if ( e.Thing is 'ClericBoss' ) + { + bossactors.Push(e.Thing); + if ( upgrademe ) e.Thing.Health *= 3; + bosstag = "$BT_CLERIC"; + } + else if ( e.Thing is 'FighterBoss' ) + { + bossactors.Push(e.Thing); + if ( upgrademe ) e.Thing.Health *= 3; + bosstag = "$BT_FIGHTER"; + } + else if ( e.Thing is 'MageBoss' ) + { + bossactors.Push(e.Thing); + if ( upgrademe ) e.Thing.Health *= 3; + bosstag = "$BT_MAGE"; + } + else if ( e.Thing is 'Dragon' ) + { + bossactors.Push(e.Thing); + if ( upgrademe ) e.Thing.Health *= 4; + bosstag = "$BT_DRAGON"; + } + else if ( e.Thing is 'Heresiarch' ) + { + bossactors.Push(e.Thing); + if ( upgrademe ) e.Thing.Health *= 6; + bosstag = "$BT_HERESIARCH"; + } + else if ( e.Thing is 'Korax' ) + { + bossactors.Push(e.Thing); + if ( upgrademe ) e.Thing.Health *= 8; + bosstag = "$BT_KORAX"; + } + } + } + + override void WorldTick() + { + if ( initialized ) return; + // wait until bosses are active + for ( int i=0; i 0 ) + { + cummdamage += curcumm; + lastcummtic = gametic; + } + else if ( gametic > lastcummtic+150 ) cummdamage = 0; + thealth = newhealth; + ihealthr.Update(thealth); + if ( thealth > oldhealth[29] ) + for ( int i=29; i>0; i-- ) + oldhealth[i] = thealth; + ihealth.Update(oldhealth[29]); + for ( int i=29; i>0; i-- ) + oldhealth[i] = oldhealth[i-1]; + if ( thealth > 0 ) alpha = min(3.,alpha+1./30.); + else alpha = max(0,alpha-1./50.); + } + + // called by HUD + ui void DrawBossBar( SWWMStatusBar bar ) + { + if ( !ui_initialized || (alpha <= 0.) ) return; + if ( !dodrawbossbar ) dodrawbossbar = CVar.GetCVar('swwm_bosshealthbars',players[consoleplayer]); + if ( !dodrawbossbar.GetBool() ) return; + if ( !bbar_f ) bbar_f = TexMan.CheckForTexture("graphics/HUD/BossHealthBarBox.png",TexMan.Type_Any); + if ( !bbar_r ) bbar_r = TexMan.CheckForTexture("graphics/HUD/BossHealthBar.png",TexMan.Type_Any); + if ( !bbar_d ) bbar_d = TexMan.CheckForTexture("graphics/HUD/BossHealthBarDecay.png",TexMan.Type_Any); + Vector2 vpos = ((bar.ss.x-300)/2.,bar.ss.y-(bar.margin+35)); + Screen.DrawTexture(bbar_f,false,vpos.x-2,vpos.y-2,DTA_VirtualWidthF,bar.ss.x,DTA_VirtualHeightF,bar.ss.y,DTA_KeepRatio,true,DTA_Alpha,alpha); + int rw = int(clamp((ihealthr.GetValue()*300.)/hmax,0.,300.)); + int dw = int(clamp((ihealth.GetValue()*300.)/hmax,0.,300.)); + Screen.DrawTexture(bbar_d,false,vpos.x,vpos.y,DTA_VirtualWidthF,bar.ss.x,DTA_VirtualHeightF,bar.ss.y,DTA_KeepRatio,true,DTA_Alpha,alpha,DTA_WindowRight,dw); + Screen.DrawTexture(bbar_r,false,vpos.x,vpos.y,DTA_VirtualWidthF,bar.ss.x,DTA_VirtualHeightF,bar.ss.y,DTA_KeepRatio,true,DTA_Alpha,alpha,DTA_WindowRight,rw); + Font barfnt = bar.LangFont(bar.mTewiFont); + Font dmgfnt = bar.mTewiFont.mFont; + if ( (cummdamage > 0) && (gametic < lastcummtic+150) ) + { + double calph = clamp(((lastcummtic+150)-gametic)/50.,0.,1.); + string dnum = String.Format("%d",cummdamage); + Screen.DrawText(dmgfnt,Font.CR_RED,vpos.x+300-dmgfnt.StringWidth(dnum),vpos.y-(dmgfnt.GetHeight()+2),dnum,DTA_VirtualWidthF,bar.ss.x,DTA_VirtualHeightF,bar.ss.y,DTA_KeepRatio,true,DTA_Alpha,alpha*calph); + } + Screen.DrawText(barfnt,Font.CR_WHITE,vpos.x,vpos.y-(barfnt.GetHeight()+2),StringTable.Localize(bosstag),DTA_VirtualWidthF,bar.ss.x,DTA_VirtualHeightF,bar.ss.y,DTA_KeepRatio,true,DTA_Alpha,alpha); + } + + // can't use this until I actually figure out how to make those walls damageable + /*private bool IsIOSWall( Line l ) + { + if ( !facetex[0] ) + { + facetex[0] = TexMan.CheckForTexture("ZZZFACE1",TexMan.Type_Wall); + facetex[1] = TexMan.CheckForTexture("ZZZFACE2",TexMan.Type_Wall); + facetex[2] = TexMan.CheckForTexture("ZZZFACE3",TexMan.Type_Wall); + facetex[3] = TexMan.CheckForTexture("ZZZFACE4",TexMan.Type_Wall); + facetex[4] = TexMan.CheckForTexture("ZZZFACE5",TexMan.Type_Wall); + } + for ( int i=0; i<5; i++ ) + { + for ( int j=0; j<3; j++ ) + { + if ( l.sidedef[0].GetTexture(j) == facetex[i] ) return true; + if ( l.sidedef[1] && l.sidedef[1].GetTexture(j) == facetex[i] ) return true; + } + } + return false; + } + + override void WorldLineDamaged( WorldEvent e ) + { + // allow boss brain to take (reduced) damage from the facewall being shot + if ( level.mapname ~== "MAP30" ) + { + if ( !IsIOSWall(e.DamageLine) ) return; + if ( bossbrainactor ) + bossbrainactor.DamageMobj(e.Inflictor,e.DamageSource,e.Damage/3,e.DamageType,e.DamageFlags,e.DamageAngle); + e.NewDamage = 0; + } + }*/ +}