diff --git a/cvarinfo.txt b/cvarinfo.txt index 005023954..e2428f4c1 100644 --- a/cvarinfo.txt +++ b/cvarinfo.txt @@ -17,3 +17,9 @@ user int swwm_msgduration = 5; // lifespan of other messages user int swwm_pickduration = 3; // lifespan of pickup messages server bool swwm_sharekeys = true; // share keys in mp user noarchive int swwm_lasttab = 0; // last selected tab in the menu +user bool swwm_autousearmor = true; // automatically use armor items when possible +user bool swwm_autousehealth = true; // automatically use health items when possible +user bool swwm_autouseammo = true; // automatically use ammo fabricators when possible (excl. tier 4) +server int swwm_enforceautousearmor = 0; // 1: server enforces auto use, -1: server enforces no auto use, 0: server respects user setting +server int swwm_enforceautousehealth = 0; // likewise for health +server int swwm_enforceautouseammo = 0; // likewise for fabricators diff --git a/gldefs.pickups b/gldefs.pickups index 301aee663..03929d460 100644 --- a/gldefs.pickups +++ b/gldefs.pickups @@ -53,6 +53,10 @@ Brightmap Texture "models/Lamp.png" { Map "models/Lamp_bright.png" } +Brightmap Texture "models/Moth_Mashiro.png" +{ + Map "models/Moth_Mashiro_bright.png" +} PointLight ARMORNUGGETLIGHT { diff --git a/language.txt b/language.txt index 303a8d069..8f9737298 100644 --- a/language.txt +++ b/language.txt @@ -32,8 +32,15 @@ SWWM_MAXPICK = "Max pickup messages"; SWWM_CHATLEN = "Chat message duration"; SWWM_MSGLEN = "General message duration"; SWWM_PICKLEN = "Pickup message duration"; +SWWM_ITITLE = "Item Options"; +SWWM_ARMORUSE = "Automatically Use Armor"; +SWWM_HEALTHUSE = "Automatically Use Health"; +SWWM_AMMOUSE = "Automatically Use Fabricators"; SWWM_CTITLE = "Multiplayer Options"; SWWM_SKEYS = "Share Keys"; +SWWM_SVARMORUSE = "Enforce Armor Auto-Use"; +SWWM_SVHEALTHUSE = "Enforce Health Auto-Use"; +SWWM_SVAMMOUSE = "Enforce Fabricator Auto-Use"; SWWM_MCREDS = "SWWM GZ Credits"; SWWM_CLEAD = "Development Lead:"; SWWM_CASSETS = "Additional Assets:"; @@ -50,9 +57,12 @@ SWWM_CCOMMUNITY1 = "All my amazing friends from the Doom community"; SWWM_CCOMMUNITY2 = "(For helping me keep this whole thing rolling, and for all the time we've spent together)"; SWWM_CCOMMUNITY3 = "(Here's to many more years of Dooming. Stay awesome, everyone!)"; SWWM_CDEVS1 = "Randi, Graf, Rachael, Mental, dpJudas and the rest of the GZDoom dev team"; -SWWM_CDEVS2 = "(For their work on the source port that brough back my faith in modding. You guys rock!)"; +SWWM_CDEVS2 = "(For their work on the source port that brought back my faith in modding. You guys rock!)"; +SWWM_FORCEDISABLE = "Force Disable"; +SWWM_USERSET = "User Set"; +SWWM_FORCEENABLE = "Force Enable"; TOOLTIP_SWWM_VOICETYPE = "Sets the voice pack for the player (clientside)."; -TOOLTIP_SWWM_MUTEPLAYER = "Control what gets muted, if you'd rather have a more silent protagonist."; +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."; TOOLTIP_SWWM_HUDMARGIN = "Margin around HUD elements, in (scaled) pixels."; TOOLTIP_SWWM_MAXSHOWN = "Maximum messages (not lines) shown in the top left part of the HUD."; @@ -62,6 +72,12 @@ TOOLTIP_SWWM_CHATDURATION = "Duration of chat messages in seconds."; TOOLTIP_SWWM_MSGDURATION = "Duration of obituaries and other messages in seconds."; TOOLTIP_SWWM_PICKDURATION = "Duration of pickup messages in seconds."; TOOLTIP_SWWM_SHAREKEYS = "When this is enabled, picking up a key item will send a copy to all other players."; +TOOLTIP_SWWM_AUTOUSEARMOR = "When enabled, new armor items are automatically worn when picked up."; +TOOLTIP_SWWM_AUTOUSEHEALTH = "When enabled, health items are automatically used if they can heal. This excludes Refreshers since they count as powerups."; +TOOLTIP_SWWM_AUTOUSEAMMO = "When enabled, ammo fabricators are automatically used on pickup. This excludes Tier 4 fabricators since they count as powerups."; +TOOLTIP_SWWM_ENFORCEAUTOUSEARMOR = "Enforce a specific armor auto-use setting for all players, or respects per-player settings."; +TOOLTIP_SWWM_ENFORCEAUTOUSEHEALTH = "Enforce a specific health auto-use setting for all players, or respects per-player settings."; +TOOLTIP_SWWM_ENFORCEAUTOUSEAMMO = "Enforce a specific ammo fabricator auto-use setting for all players, or respects per-player settings."; // knowledge base SWWM_COMINGSOON = "(coming soon)"; SWWM_MISSTAB = "Mission"; @@ -389,8 +405,8 @@ SWWM_LORETXT_HAMMERSPACEEMBIGGENER = "Addendum: You may find these tucked away in certain spots throughout your mission.\n" "\n" "Saya's Note: Is that even a real word?"; -SWWM_LORETAG_AMMOFABRICATOR = "Ammo Fabricator"; -SWWM_LORETXT_AMMOFABRICATOR = +SWWM_LORETAG_FABRICATOR = "Ammo Fabricator"; +SWWM_LORETXT_FABRICATOR = "Designation: Universal Ammo Fabricator\n" "Manufacturer: Cyrus Enterprises\n" "\n" @@ -818,7 +834,8 @@ T_INVINCIBALL = "Fuckin' Invinciball"; T_LAMP = "Lämp"; I_LAMP = "Companion Lamp"; T_MOTH = "Moth"; -T_MASHIRO = "White Moth"; +T_WMOTH = "White Moth"; +T_MASHIRO = "Mashiro"; T_NUGGETH = "Health Nugget"; T_NUGGETA = "Armor Nugget"; T_OMNISIGHT = "Omnisight"; @@ -871,7 +888,15 @@ O_YNYKRONALT = "%o was spaghettified by %k."; O_POUND = "%o was very impressed by %k's landing."; O_DASH = "%o was discombobulated by a very fast moving %k."; O_MELEE = "%o was K.O.'d by %k."; -O_LAMP = "%o was assaulted by %k's moths."; +O_MOTH = "%%o was assaulted by %s's moths."; +O_MOTH2 = "%o was assaulted by moths."; +O_MASHIRO1 = "%o should have kept the lights on."; +O_MASHIRO2 = "%o now belongs to Mashiro."; +O_MASHIRO3 = "%o made a terrible mistake."; +O_MASHIRO4 = "%o mysteriously disappeared."; +O_MASHIRO5 = "%o is now part of a live-action recreation of Layers of White."; +O_MASHIRO6 = "%o angered the wrong moth."; +O_MASHIRO7 = "%o and Mashiro are now TOGETHER FOREVER."; // misc D_BLASTSUIT = "The Blast Suit broke down."; D_GHOSTARTI = "The Ghost Artifact ran out of energy."; diff --git a/menudef.txt b/menudef.txt index 16081fe90..ae0706b0e 100644 --- a/menudef.txt +++ b/menudef.txt @@ -6,6 +6,12 @@ OptionValue "SWWMVoice" 3, "$SWWM_MUTELINERS" 4, "$SWWM_MUTEALL" } +OptionValue "SWWMEnforce" +{ + -1, "$SWWM_FORCEDISABLE" + 0, "$SWWM_USERSET" + 1, "$SWWM_FORCEENABLE" +} OptionMenu "SWWMOptionMenu" { Class "SWWMOptionMenu" @@ -25,8 +31,16 @@ OptionMenu "SWWMOptionMenu" Slider "$SWWM_MSGLEN", "swwm_msgduration", 1, 30, 1, 0 Slider "$SWWM_PICKLEN", "swwm_pickduration", 1, 30, 1, 0 StaticText " " + StaticText "$SWWM_ITITLE", "Gold" + Option "$SWWM_ARMORUSE", "swwm_autousearmor", "YesNo" + Option "$SWWM_HEALTHUSE", "swwm_autousehealth", "YesNo" + Option "$SWWM_AMMOUSE", "swwm_autouseammo", "YesNo" + StaticText " " StaticText "$SWWM_CTITLE", "Gold" Option "$SWWM_SKEYS", "swwm_sharekeys", "YesNo" + Option "$SWWM_SVARMORUSE", "swwm_enforceautousearmor", "SWWMEnforce" + Option "$SWWM_SVHEALTHUSE", "swwm_enforceautousehealth", "SWWMEnforce" + Option "$SWWM_SVAMMOUSE", "swwm_enforceautouseammo", "SWWMEnforce" } OptionMenu "SWWMCreditsMenu" { @@ -38,7 +52,7 @@ OptionMenu "SWWMCreditsMenu" StaticText " " StaticText "$SWWM_CASSETS", "Red" StaticText " " - StaticText "Bethesda Softworks", "Gold" + StaticText "Bethesda Game Studios", "Gold" StaticText "Fallout: New Vegas", "White" StaticText "Fallout 4", "White" StaticText " " diff --git a/modeldef.pickups b/modeldef.pickups index 993fe132e..43a1f59e8 100644 --- a/modeldef.pickups +++ b/modeldef.pickups @@ -185,6 +185,33 @@ Model "Omnisight" FrameIndex XZW1 A 0 0 } +Model "LampMoth" +{ + Path "models" + Model 0 "Moth_d.3d" + Skin 0 "Moth.png" + Scale 0.005 0.005 0.005 + ZOffset 0.5 + USEACTORPITCH + DONTCULLBACKFACES + + FrameIndex XZW1 B 0 1 + FrameIndex XZW1 C 0 2 +} +Model "LampMoth2" +{ + Path "models" + Model 0 "Moth_d.3d" + Skin 0 "Moth_Mashiro.png" + Scale 0.008 0.008 0.008 + ZOffset 0.5 + USEACTORPITCH + DONTCULLBACKFACES + + FrameIndex XZW1 B 0 1 + FrameIndex XZW1 C 0 2 +} + Model "CompanionLamp" { Path "models" diff --git a/models/Moth.png b/models/Moth.png index 75f36ed34..a381204e0 100644 Binary files a/models/Moth.png and b/models/Moth.png differ diff --git a/models/Moth_Mashiro.png b/models/Moth_Mashiro.png index 9e1d965e4..12cdefe30 100644 Binary files a/models/Moth_Mashiro.png and b/models/Moth_Mashiro.png differ diff --git a/sndinfo.txt b/sndinfo.txt index 8b8b40704..ddefbf7fd 100644 --- a/sndinfo.txt +++ b/sndinfo.txt @@ -316,12 +316,20 @@ $playeralias demolitionist neutral *pain50 demolitionist/pain $playeralias demolitionist neutral *pain25 demolitionist/hipain $playersound demolitionist neutral *usefail sounds/menu/failuse.ogg $playeralias demolitionist neutral *death demolitionist/death +$playeralias demolitionist neutral *burndeath demolitionist/death $playeralias demolitionist neutral *xdeath demolitionist/xdeath $playeralias demolitionist neutral *gibbed demolitionist/xdeath +$playeralias demolitionist neutral *crazydeath demolitionist/xdeath $playeralias demolitionist neutral *wimpydeath demolitionist/wdeath $playersound demolitionist neutral *land DSEMPTY $playersound demolitionist neutral *falling DSEMPTY $playersound demolitionist neutral *puzzfail sounds/menu/failuse.ogg +$playersound demolitionist neutral *poison DSEMPTY +$playersound demolitionist neutral *dive DSEMPTY +$playersound demolitionist neutral *surface DSEMPTY +$playersound demolitionist neutral *gasp DSEMPTY +$playersound demolitionist neutral *taunt DSEMPTY +$playersound demolitionist neutral *evillaugh DSEMPTY explodium/casing1 sounds/explodiumgun/expl_case1.ogg explodium/casing2 sounds/explodiumgun/expl_case2.ogg @@ -425,6 +433,29 @@ powerup/ragekit sounds/items/ragekiton.ogg powerup/ragekitact sounds/items/ragekitact.ogg powerup/ragekithit sounds/items/ragekithit.ogg powerup/ragekitend sounds/items/ragekitend.ogg +powerup/omnisight sounds/items/omnisight.ogg + +lamp/on sounds/items/lampon.ogg +lamp/off sounds/items/lampoff.ogg +lamp/appear sounds/items/lampappear.ogg +lamp/disappear sounds/items/lampdisappear.ogg +// maybe eventually +//mashiro/see (some sort of creepy yandere girl giggling I guess) +//mashiro/active (more creepy giggles?) +//mashiro/attack (clawing) +moth/scrape1 sounds/items/mothatk1.ogg +moth/scrape2 sounds/items/mothatk2.ogg +moth/scrape3 sounds/items/mothatk3.ogg +moth/scrape4 sounds/items/mothatk4.ogg +$random moth/scrape { moth/scrape1 moth/scrape2 moth/scrape3 moth/scrape4 } +$limit moth/scrape 30 +moth/die1 sounds/items/mothdie1.ogg +moth/die2 sounds/items/mothdie2.ogg +$random moth/die { moth/die1 moth/die2 } +moth/fly sounds/items/mothfly.ogg +$limit moth/fly 30 + +fabricator/use sounds/items/makeammo.ogg menu/activate sounds/hmenu/hmenu1.ogg menu/backup sounds/hmenu/hmenu2.ogg diff --git a/sounds/items/lampappear.ogg b/sounds/items/lampappear.ogg new file mode 100644 index 000000000..6ce38c2ec Binary files /dev/null and b/sounds/items/lampappear.ogg differ diff --git a/sounds/items/lampdisappear.ogg b/sounds/items/lampdisappear.ogg new file mode 100644 index 000000000..9e84696db Binary files /dev/null and b/sounds/items/lampdisappear.ogg differ diff --git a/sounds/items/lampoff.ogg b/sounds/items/lampoff.ogg new file mode 100644 index 000000000..ed7c8a5ce Binary files /dev/null and b/sounds/items/lampoff.ogg differ diff --git a/sounds/items/lampon.ogg b/sounds/items/lampon.ogg new file mode 100644 index 000000000..f5a97ea70 Binary files /dev/null and b/sounds/items/lampon.ogg differ diff --git a/sounds/items/makeammo.ogg b/sounds/items/makeammo.ogg new file mode 100644 index 000000000..33b64dabe Binary files /dev/null and b/sounds/items/makeammo.ogg differ diff --git a/sounds/items/mothatk1.ogg b/sounds/items/mothatk1.ogg new file mode 100644 index 000000000..69330d093 Binary files /dev/null and b/sounds/items/mothatk1.ogg differ diff --git a/sounds/items/mothatk2.ogg b/sounds/items/mothatk2.ogg new file mode 100644 index 000000000..9e236541a Binary files /dev/null and b/sounds/items/mothatk2.ogg differ diff --git a/sounds/items/mothatk3.ogg b/sounds/items/mothatk3.ogg new file mode 100644 index 000000000..40c6cd803 Binary files /dev/null and b/sounds/items/mothatk3.ogg differ diff --git a/sounds/items/mothatk4.ogg b/sounds/items/mothatk4.ogg new file mode 100644 index 000000000..67b74916a Binary files /dev/null and b/sounds/items/mothatk4.ogg differ diff --git a/sounds/items/mothdie1.ogg b/sounds/items/mothdie1.ogg new file mode 100644 index 000000000..f72f56610 Binary files /dev/null and b/sounds/items/mothdie1.ogg differ diff --git a/sounds/items/mothdie2.ogg b/sounds/items/mothdie2.ogg new file mode 100644 index 000000000..7de17c010 Binary files /dev/null and b/sounds/items/mothdie2.ogg differ diff --git a/sounds/items/mothfly.ogg b/sounds/items/mothfly.ogg new file mode 100644 index 000000000..0e70f923a Binary files /dev/null and b/sounds/items/mothfly.ogg differ diff --git a/sounds/items/omnisight.ogg b/sounds/items/omnisight.ogg new file mode 100644 index 000000000..c9194ba4a Binary files /dev/null and b/sounds/items/omnisight.ogg differ diff --git a/zscript/swwm_ammo.zsc b/zscript/swwm_ammo.zsc index d0a17858d..20d2f6e6e 100644 --- a/zscript/swwm_ammo.zsc +++ b/zscript/swwm_ammo.zsc @@ -767,9 +767,10 @@ Class YnykronAmmo : Ammo Class AmmoFabricator : Inventory abstract { - int budget; + int budget, pertype; Property Budget : budget; + Property PerType : pertype; override Inventory CreateCopy( Actor other ) { @@ -779,10 +780,80 @@ Class AmmoFabricator : Inventory abstract return Super.CreateCopy(other); } + bool FabricateAmmo() + { + Array > available; + // populate ammo production list + for ( int i=0; i)(AllActorClasses[i]); + // only direct descendants of ammo with a set price below our budget + if ( !a || (a.GetParentClass() != 'Ammo') ) continue; + let def = GetDefaultByType(a); + if ( !(def.Stamina) || (def.Stamina > budget) ) continue; + available.Push(a); + } + // start from lowest to highest needed until we fill the inventory or run out of budget + bool given = false; + int consumed = 0; + String fabstr = ""; + bool comma = false; + for ( int i=0; i 0 ) + { + if ( comma ) fabstr.AppendFormat(", %dx %s",cnt,cur.GetTag()); + else fabstr.AppendFormat("%dx %s",cnt,cur.GetTag()); + comma = true; + } + } + if ( given ) PrintPickupMessage(true,fabstr); + return given; + } + + override bool Use( bool pickup ) + { + bool shouldautouse = false; + if ( swwm_enforceautouseammo == 1 ) shouldautouse = true; + else if ( swwm_enforceautouseammo == -1 ) shouldautouse = false; + else shouldautouse = CVar.GetCVar('swwm_autouseammo',Owner.player).GetBool(); + if ( pickup && !shouldautouse ) return false; + if ( FabricateAmmo() ) + { + Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA); + return true; + } + return false; + } + Default { +INVENTORY.INVBAR; + +INVENTORY.AUTOACTIVATE; +FLOATBOB; + Inventory.UseSound "fabricator/use"; Inventory.MaxAmount 32; Inventory.InterHubAmount 32; FloatBobStrength 0.25; @@ -803,7 +874,8 @@ Class FabricatorTier1 : AmmoFabricator Inventory.Icon "graphics/HUD/Icons/I_Fabricator1.png"; Inventory.PickupMessage "$T_FABRICATOR1"; Inventory.MaxAmount 30; - AmmoFabricator.Budget 5000; + AmmoFabricator.Budget 10000; + AmmoFabricator.PerType 4; Stamina 3000; } } @@ -815,7 +887,8 @@ Class FabricatorTier2 : AmmoFabricator Inventory.Icon "graphics/HUD/Icons/I_Fabricator2.png"; Inventory.PickupMessage "$T_FABRICATOR2"; Inventory.MaxAmount 20; - AmmoFabricator.Budget 20000; + AmmoFabricator.Budget 25000; + AmmoFabricator.PerType 8; Stamina 12000; } } @@ -828,6 +901,7 @@ Class FabricatorTier3 : AmmoFabricator Inventory.PickupMessage "$T_FABRICATOR3"; Inventory.MaxAmount 10; AmmoFabricator.Budget 500000; + AmmoFabricator.PerType 16; Stamina 480000; } } @@ -839,7 +913,9 @@ Class FabricatorTier4 : AmmoFabricator Inventory.Icon "graphics/HUD/Icons/I_Fabricator4.png"; Inventory.PickupMessage "$T_FABRICATOR4"; Inventory.MaxAmount 5; - AmmoFabricator.Budget -1; + AmmoFabricator.Budget int.max; + AmmoFabricator.PerType int.max; + -INVENTORY.AUTOACTIVATE; Stamina 1920000; } } diff --git a/zscript/swwm_common.zsc b/zscript/swwm_common.zsc index 913a12edd..e19fb4458 100644 --- a/zscript/swwm_common.zsc +++ b/zscript/swwm_common.zsc @@ -913,7 +913,7 @@ Class SWWMHandler : EventHandler if ( !hnd ) return 0; CVar voicetype = CVar.GetCVar('swwm_voicetype',players[consoleplayer]); // suppress non-rage comments when ragekit is active, only screaming allowed - if ( players[consoleplayer].mo.FindInventory("RagekitPower") && (type != "ragekit") ) return 0; + if ( players[consoleplayer].mo.FindInventory("RagekitPower") && (type != "ragekit") && (CVar.GetCVar('swwm_mutevoice',players[consoleplayer]).GetInt() < 2) ) return 0; int whichline; int countem = 0, i = 1; String testme, locme; @@ -1054,6 +1054,14 @@ Class SWWMHandler : EventHandler PlayerEntered(e); } + override void WorldThingRevived( WorldEvent e ) + { + if ( !(e.Thing is 'PlayerPawn') ) return; + // reset uptime since player had just died + SWWMStats s = SWWMStats.Find(e.Thing.player); + if ( s ) s.lastspawn = gametic; + } + override void WorldTick() { if ( !mutevoice ) mutevoice = CVar.GetCVar('swwm_mutevoice',players[consoleplayer]); @@ -1520,8 +1528,8 @@ Class SWWMHandler : EventHandler } else if ( (e.Replacee == 'Soulsphere') || (e.Replacee == 'ArtiSuperHealth') ) { - if ( gameinfo.gametype&GAME_Heretic ) e.Replacement = 'RefresherItem'; - else e.Replacement = 'CubeHealthItem'; + if ( gameinfo.gametype&GAME_Hexen ) e.Replacement = 'CubeHealthItem'; + else e.Replacement = 'RefresherItem'; } else if ( e.Replacee == 'ArtiHealingRadius' ) e.Replacement = 'RefresherItem'; else if ( (e.Replacee == 'Megasphere') || (e.Replacee == 'ArtiEgg') || (e.Replacee == 'PlatinumHelm') ) e.Replacement = 'GrilledCheeseSandwich'; diff --git a/zscript/swwm_hud.zsc b/zscript/swwm_hud.zsc index 92643e6b0..b5933bf08 100644 --- a/zscript/swwm_hud.zsc +++ b/zscript/swwm_hud.zsc @@ -191,7 +191,15 @@ Class SWWMStatusBar : BaseStatusBar Screen.DrawTexture(i.Icon,false,dx,dy,DTA_VirtualWidthF,dw,DTA_VirtualHeightF,dh,DTA_KeepRatio,true,DTA_Alpha,Powerup(i).IsBlinking()?alpha*.5:alpha,DTA_TopOffset,0,DTA_LeftOffset,0); String nstr = String.Format("%ds",Powerup(i).EffectTics/Thinker.TICRATE); int len = mTewiFont.mFont.StringWidth(nstr); - Screen.DrawText(mTewiFont.mFont,Font.CR_FIRE,(xx+30)-len,(yy+30)-11,nstr,DTA_VirtualWidthF,dw,DTA_VirtualHeightF,dh,DTA_KeepRatio,true,DTA_Alpha,Powerup(i).IsBlinking()?alpha*.5:alpha); + Screen.DrawText(mTewiFont.mFont,Font.CR_FIRE,(xx+30)-len,(yy+30)-11,nstr,DTA_VirtualWidthF,dw,DTA_VirtualHeightF,dh,DTA_KeepRatio,true,DTA_Alpha,Powerup(i).IsBlinking()?alpha*.5:alpha); + return; + } + if ( i is 'SWWMLamp' ) + { + Screen.DrawTexture(i.Icon,false,dx,dy,DTA_VirtualWidthF,dw,DTA_VirtualHeightF,dh,DTA_KeepRatio,true,DTA_Alpha,alpha,DTA_TopOffset,0,DTA_LeftOffset,0); + String nstr = String.Format("%d%%",SWWMLamp(i).Charge); + int len = mTewiFont.mFont.StringWidth(nstr); + Screen.DrawText(mTewiFont.mFont,Font.CR_FIRE,(xx+30)-len,(yy+30)-11,nstr,DTA_VirtualWidthF,dw,DTA_VirtualHeightF,dh,DTA_KeepRatio,true,DTA_Alpha,alpha); return; } Screen.DrawTexture(i.Icon,false,dx,dy,DTA_VirtualWidthF,dw,DTA_VirtualHeightF,dh,DTA_KeepRatio,true,DTA_Alpha,alpha,DTA_TopOffset,0,DTA_LeftOffset,0); diff --git a/zscript/swwm_inventory.zsc b/zscript/swwm_inventory.zsc index 74c2298a7..8355412e7 100644 --- a/zscript/swwm_inventory.zsc +++ b/zscript/swwm_inventory.zsc @@ -99,6 +99,11 @@ Class SWWMSpareArmor : Inventory abstract override bool Use( bool pickup ) { + bool shouldautouse = false; + if ( swwm_enforceautousearmor == 1 ) shouldautouse = true; + else if ( swwm_enforceautousearmor == -1 ) shouldautouse = false; + else shouldautouse = CVar.GetCVar('swwm_autousearmor',Owner.player).GetBool(); + if ( pickup && !shouldautouse ) return false; let cur = Owner.FindInventory(giveme); if ( !cur || (cur.Amount < cur.MaxAmount) ) { @@ -134,6 +139,11 @@ Class SWWMHealth : Inventory abstract override bool Use( bool pickup ) { + bool shouldautouse = false; + if ( swwm_enforceautousehealth == 1 ) shouldautouse = true; + else if ( swwm_enforceautousehealth == -1 ) shouldautouse = false; + else shouldautouse = CVar.GetCVar('swwm_autousehealth',Owner.player).GetBool(); + if ( pickup && !shouldautouse ) return false; if ( Owner.Health >= GetDefaultByType(giveme).MaxAmount ) return false; if ( UseSound ) Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA,CHANF_DEFAULT,.6); SWWMHandler.DoFlash(Owner,Color(48,64,128,255),5); diff --git a/zscript/swwm_menu.zsc b/zscript/swwm_menu.zsc index ebafc6bac..343a5fc43 100644 --- a/zscript/swwm_menu.zsc +++ b/zscript/swwm_menu.zsc @@ -52,9 +52,9 @@ Class SWWMKnowledgeBaseMenu : GenericMenu override void Init( Menu parent ) { Super.Init(parent); - if ( gamestate != GS_LEVEL ) + if ( (gamestate != GS_LEVEL) || (players[consoleplayer].Health <= 0) ) { - // can't open this menu outside of the game + // can't open this menu outside of the game or if dead Close(); return; } @@ -201,8 +201,8 @@ Class SWWMKnowledgeBaseMenu : GenericMenu if ( invlist[sel0] is 'Ammo' ) return true; lastuse = invlist[sel0].GetClass(); lastuseamt = invlist[sel0].Amount; - // don't check weapons - if ( !(invlist[sel0] is 'Weapon') ) + // don't check weapons (or the lamp) + if ( !(invlist[sel0] is 'Weapon') && !(invlist[sel0] is 'SWWMLamp') ) checkuse = gametic+1; EventHandler.SendNetworkEvent(String.Format("swwmuseitem.%s",invlist[sel0].GetClassName()),consoleplayer); } @@ -223,6 +223,13 @@ Class SWWMKnowledgeBaseMenu : GenericMenu override void Ticker() { Super.Ticker(); + if ( players[consoleplayer].Health <= 0 ) + { + // ded + MenuSound("menu/democlose"); + Close(); + return; + } // mark lore entries as read if ( (curtab == TAB_LIBRARY) && (lorelib.ent.Size() > 0) && !lorelib.ent[sel0].read ) EventHandler.SendNetworkEvent("swwmmarkloreread",consoleplayer,sel0); diff --git a/zscript/swwm_player.zsc b/zscript/swwm_player.zsc index 4b2cf4298..b33eb499e 100644 --- a/zscript/swwm_player.zsc +++ b/zscript/swwm_player.zsc @@ -33,6 +33,7 @@ Class Demolitionist : PlayerPawn Mass 500; PainChance 255; Player.DisplayName "Demolitionist"; + Player.StartItem "DeepImpact"; Player.StartItem "ExplodiumGun"; Player.ViewHeight 52; Player.AirCapacity 0; @@ -40,6 +41,7 @@ Class Demolitionist : PlayerPawn Player.SoundClass "demolitionist"; DamageFactor "Drowning", 0.0; DamageFactor "Poison", 0.0; + DamageFactor "PoisonCloud", 0.0; DamageFactor "Falling", 0.0; +NOBLOOD; +DONTGIB; diff --git a/zscript/swwm_powerup.zsc b/zscript/swwm_powerup.zsc index ffa7a30af..e029e5067 100644 --- a/zscript/swwm_powerup.zsc +++ b/zscript/swwm_powerup.zsc @@ -594,7 +594,7 @@ Class RagekitPower : Powerup if ( !(level.maptime%30) ) { SWWMHandler.DoFlash(Owner,Color(16,255,0,0),5); - if ( (Owner.player == players[consoleplayer]) && (gametic > lastrage) ) + if ( (Owner.player == players[consoleplayer]) && (gametic > lastrage) && (CVar.GetCVar('swwm_mutevoice',players[consoleplayer]).GetInt() < 2) ) lastrage = SWWMHandler.AddOneliner("ragekit",5); Owner.A_QuakeEx(2,2,2,Random[Rage](1,2),0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:.5); } @@ -671,13 +671,18 @@ Class Omnisight : Inventory { override bool Use( bool pickup ) { - level.allmap = true; + if ( !level.allmap ) + { + Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA); + level.allmap = true; + } // not used up, must be kept for the targetting features to work return false; } Default { Tag "$T_OMNISIGHT"; + Inventory.UseSound "powerup/omnisight"; Inventory.PickupSound "misc/p_pkup"; Inventory.PickupMessage "$I_OMNISIGHT"; Inventory.MaxAmount 1; @@ -701,10 +706,249 @@ Class Omnisight : Inventory Class LampMoth : Actor { + Actor lamp; + Vector3 trail, ofs; + int lifespan; + + Default + { + Tag "$T_MOTH"; + Radius 1; + Height 2; + Speed 2; + DamageFunction 1; + MeleeRange 16; + Mass 10; + Health 10; + DeathSound "moth/die"; + BloodColor "20 10 10"; + MONSTER; + -COUNTKILL; + +THRUACTORS; + +NOGRAVITY; + +NOTELEPORT; + +FLOAT; + +NOPAIN; + +FRIENDLY; + +LOOKALLAROUND; + +QUICKTORETALIATE; + +INTERPOLATEANGLES; + } + override string GetObituary( Actor victim, Actor inflictor, Name mod, bool playerattack ) + { + if ( master && master.player ) return String.Format(StringTable.Localize("$O_MOTH"),master.player.GetUserName()); + return StringTable.Localize("$O_MOTH2"); + } + override void PostBeginPlay() + { + Super.PostBeginPlay(); + A_StartSound("moth/fly",CHAN_BODY,CHANF_LOOPING,.15,4.,FRandom[Moth](.8,1.2)); + if ( master && master.player ) SetFriendPlayer(master.player); + else bFRIENDLY = false; + } + bool isEntranced() + { + if ( !lamp ) + { + // look for nearby lamps + let bi = BlockThingsIterator.Create(self,250); + double mindist = 250.; + while ( bi.Next() ) + { + if ( !bi.Thing || !(bi.Thing is 'CompanionLamp') ) continue; + Actor a = bi.Thing; + double dist = Distance3D(a); + if ( (a.frame == 0) || (dist > mindist) && !CheckSight(a) ) continue; + mindist = dist; + lamp = a; + master = a.target; + if ( CompanionLamp(lamp).moff.Find(self) == -1 ) + CompanionLamp(lamp).moff.Push(self); + if ( master && master.player ) SetFriendPlayer(master.player); + else bFRIENDLY = false; + } + } + if ( !lamp || (lamp.frame == 0) || (Distance3D(lamp) > 250) || !CheckSight(lamp) ) return false; + return true; + } + void A_SmoothWander() + { + if ( level.Vec3Diff(pos,trail).length() < speed ) + { + double ang = FRandom[Moth](0,360); + double pt = FRandom[Moth](-30,30); + double dist = FRandom[Moth](20,40); + ofs = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*dist; + } + Vector3 newpos = level.Vec3Offset(pos,ofs); + if ( level.IsPointInLevel(newpos) ) trail = newpos; + if ( vel.length() > 0 ) + { + Vector3 uvel = vel.unit(); + angle += Clamp(deltaangle(angle,atan2(uvel.y,uvel.x)),-5.,5.); + pitch += Clamp(deltaangle(pitch,asin(-uvel.z)),-5.,5.); + } + vel *= .8; + Vector3 dir = level.Vec3Diff(pos,trail); + if ( dir.length() > 0 ) vel += dir.unit()*clamp(dir.length()*.05,.4*speed,.5*speed); + } + void A_SmoothChase() + { + if ( !target || (target.Health <= 0) ) + { + A_ClearTarget(); + SetStateLabel("Spawn"); + return; + } + if ( CheckMeleeRange() ) + { + SetStateLabel("Melee"); + return; + } + Vector3 dest = target.Vec3Offset(0,0,target.height*.75); + Vector3 dir = level.Vec3Diff(pos,dest); + Vector3 dirunit = dir.unit(); + FLineTraceData d; + LineTrace(atan2(dirunit.y,dirunit.x),dir.length(),asin(-dirunit.z),data:d); + if ( (d.HitType != TRACE_HitActor) && (d.HitActor != target) ) + { + A_Chase(); + return; + } + if ( vel.length() > 0 ) + { + Vector3 uvel = vel.unit(); + angle = atan2(uvel.y,uvel.x); + pitch = asin(-uvel.z); + } + vel *= .8; + if ( dir.length() > 0 ) vel += dir.unit()*clamp(dir.length()*.02,.3*speed,2.*speed); + } + void A_FollowLamp() + { + if ( !lamp ) + { + SetStateLabel("Spawn"); + return; + } + double dst = level.Vec3Diff(pos,trail).length(); + if ( (dst < speed) || (dst > 50) ) + { + double ang = FRandom[Moth](0,360); + double pt = FRandom[Moth](-30,30); + double dist = FRandom[Moth](20,30); + ofs = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*dist; + } + Vector3 newpos = level.Vec3Offset(lamp.Vec3Offset(0,0,lamp.height/2),ofs); + if ( level.IsPointInLevel(newpos) ) trail = newpos; + if ( vel.length() > 0 ) + { + Vector3 uvel = vel.unit(); + angle = atan2(uvel.y,uvel.x); + pitch = asin(-uvel.z); + } + vel *= .8; + Vector3 dir = level.Vec3Diff(pos,trail); + if ( dir.length() > 0 ) vel += dir.unit()*clamp(dir.length()*.02,.4*speed,2.*speed); + Vector3 diff = level.Vec3Diff(pos,lamp.pos); + if ( (diff.x > -8) && (diff.x < 8) && (diff.y > -8) && (diff.y < 8) && (diff.z > -4) && (diff.z < lamp.height+4) ) + { + if ( diff.x < 0 ) vel.x -= .2; + else vel.x += .2; + if ( diff.y < 0 ) vel.y -= .2; + else vel.y += .2; + if ( diff.z < 0 ) vel.z -= .2; + else vel.z += .2; + } + } + void A_SmoothMove() + { + if ( vel.length() > 0 ) + { + Vector3 uvel = vel.unit(); + angle = atan2(uvel.y,uvel.x); + pitch = asin(-uvel.z); + } + vel *= .8; + } + void A_Scrape() + { + if ( CheckMeleeRange() ) + { + A_FaceTarget(0,0); + lifespan -= 5; + Vector3 awaydir = level.Vec3Diff(target.Vec3Offset(0,0,target.height),pos).unit(); + vel += awaydir*32.; + int dmg = target.DamageMobj(self,self,GetMissileDamage(0,0),'Melee',Random[Moth](0,8)?DMG_NO_PAIN:0); + if ( !target.bNOBLOOD ) + { + target.TraceBleed(dmg,self); + target.SpawnBlood(pos,atan2(awaydir.y,awaydir.x)+180,dmg); + } + A_StartSound("moth/scrape",CHAN_WEAPON,CHANF_OVERLAP,.2,2.5); + DamageMobj(target,target,1,'Melee'); + } + } + override void Tick() + { + Super.Tick(); + if ( isFrozen() || isEntranced() ) + { + lifespan = 100; + return; + } + if ( target && (target.Health > 0) ) lifespan = max(20,lifespan); + lifespan--; + if ( lifespan <= 0 ) + { + let s = Spawn("SWWMSmallSmoke",pos); + s.alpha *= .3; + Destroy(); + } + } + States + { + Spawn: + XZW1 B 0 A_JumpIf(isEntranced(),"See.Entranced"); + XZW1 BC 1 + { + A_SmoothWander(); + A_Look(); + } + Loop; + See: // go for enemies + XZW1 B 0 A_JumpIf(isEntranced(),"See.Entranced"); + XZW1 BC 1 A_SmoothChase(); + Loop; + See.Entranced: // follow the lamp + XZW1 B 0 A_JumpIf(!isEntranced(),"Spawn"); + XZW1 BC 1 A_FollowLamp(); + Loop; + Melee: + XZW1 B 0 A_Scrape(); + XZW1 BCBC 1 A_SmoothMove(); + Goto See; + Death: + TNT1 A 1 + { + A_StartSound("moth/die",CHAN_VOICE,CHANF_OVERLAP,.6,2.5); + let s = Spawn("SWWMSmallSmoke",pos); + s.alpha *= .3; + } + Stop; + } } Class LampMoth2 : LampMoth { + Default + { + Tag "$T_WMOTH"; + DamageFunction 3; + Speed 3; + Scale 1.5; + Health 100; + } } Class LampMashiro : Actor abstract @@ -761,20 +1005,46 @@ Class CompanionLamp : Actor Default { +NOGRAVITY; - +NOCLIP; +SHOOTABLE; + +NOTELEPORT; +NODAMAGE; +NOBLOOD; +DONTSPLASH; - +FLOATBOB; +INTERPOLATEANGLES; + +LOOKALLAROUND; Radius 4; - Height 8; - FloatBobStrength 0.5; + Height 16; } - action void A_Moth() + // random chance to spawn moths + void A_Moth() { - // random chance to spawn moths + // count up + for ( int i=0; i= 30) ) return; + // spawn a moth at a random offset + double ang = FRandom[Moth](0,360); + double pt = FRandom[Moth](-30,30); + double dist = FRandom[Moth](10,30); + Vector3 ofs = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*dist; + Vector3 spawnpos = level.Vec3Offset(Vec3Offset(0,0,height/2),ofs); + if ( !level.IsPointInLevel(spawnpos) ) return; + let m = LampMoth(Spawn(Random[Moth](0,9)?"LampMoth":"LampMoth2",spawnpos)); + if ( !m.TestMobjLocation() ) + { + m.Destroy(); + return; + } + let s = Spawn("SWWMSmallSmoke",m.pos); + s.alpha *= .3; + m.master = target; + m.lamp = self; + m.trail = m.pos; + moff.Push(m); } override void PostBeginPlay() { @@ -784,8 +1054,24 @@ Class CompanionLamp : Actor Destroy(); return; } + Spawn("SWWMItemFog",pos); Trail = pos; } + // the stupidest thing ever, it's called BlockingLine but it's not always blocking us + private bool BlockingLineIsBlocking() + { + if ( !BlockingLine ) return false; + // one-sided + if ( !BlockingLine.sidedef[1] ) return true; + // blocks us + if ( BlockingLine.flags&(Line.ML_BLOCKING|Line.ML_BLOCKEVERYTHING) ) return true; + return false; + } + private int WhichBlockingLineSide() + { + if ( !BlockingLine ) return 0; + return ((pos.y-BlockingLine.v1.p.y)*BlockingLine.delta.x+(BlockingLine.v1.p.x-pos.x)*BlockingLine.delta.y > double.epsilon); + } override void Tick() { Super.Tick(); @@ -794,28 +1080,95 @@ Class CompanionLamp : Actor Destroy(); return; } + if ( isFrozen() ) return; // update trailing position bool foundspot = false; - for ( int i=0; i<180; i++ ) + for ( int i=0; i<180; i+=5 ) { for ( int j=1; j>=-1; j-=2 ) { double ang = (target.angle-180)+i*j; - Vector3 testpos = target.Vec3Offset(cos(ang)*32,sin(ang)*32,target.height-8); + Vector3 testpos = level.Vec3Offset(target.pos,(cos(ang)*32,sin(ang)*32,target.height-8+1.5*sin(level.maptime*3.))); if ( !level.IsPointInLevel(testpos) ) continue; + Vector3 oldpos = pos; + Vector3 oldprev = prev; + Actor oldblockingmobj = blockingmobj; + Line oldblockingline = blockingline; + Sector oldblockingfloor = blockingfloor, oldblockingceiling = blockingceiling; + SetOrigin(testpos,false); + if ( !TestMobjLocation() || BlockingLineIsBlocking() || BlockingFloor || BlockingCeiling ) + { + SetOrigin(oldpos,false); + prev = oldprev; + blockingmobj = oldblockingmobj; + blockingline = oldblockingline; + blockingfloor = oldblockingfloor; + blockingceiling = oldblockingceiling; + continue; + } + SetOrigin(oldpos,false); + prev = oldprev; + blockingmobj = oldblockingmobj; + blockingline = oldblockingline; + blockingfloor = oldblockingfloor; + blockingceiling = oldblockingceiling; Trail = testpos; foundspot = true; } // check at most for a 45 degree offset if ( foundspot && (i > 45) ) break; } + Vector3 diff = level.Vec3Diff(pos,target.pos); + if ( (diff.length() > 400) || !CheckSight(target) ) + { + Actor f = Spawn("SWWMItemFog",pos); + f.A_StartSound("lamp/disappear",CHAN_VOICE); + SetOrigin(trail,false); + angle = AngleTo(target); + vel *= 0.; + f = Spawn("SWWMItemFog",pos); + f.A_StartSound("lamp/appear",CHAN_VOICE); + return; + } angle += Clamp(deltaangle(angle,AngleTo(target)),-5.,5.); vel *= .8; - Vector3 newpos = Trail; - Vector3 dir = level.Vec3Diff(pos,newpos); - if ( dir.length() > 0 ) - vel += dir.unit()*min(dir.length()*.05,20.); - Vector3 diff = pos-target.pos; + bool blocked = false; + if ( BlockingLine && BlockingLineIsBlocking() ) + { + // push away from wall + Vector3 normal = (-BlockingLine.delta.y,BlockingLine.delta.x,0).unit(); + if ( !WhichBlockingLineSide() ) normal *= -1; + vel += 4.*normal; + blocked = true; + } + if ( BlockingFloor ) + { + // push away from floor + Vector3 normal = BlockingFloor.floorplane.Normal; + // find closest 3d floor for its normal + for ( int i=0; i -16) && (diff.x < 16) && (diff.y > -16) && (diff.y < 16) && (diff.z > -16) && (diff.z < target.height+8) ) { if ( diff.x < 0 ) vel.x -= .2; @@ -824,16 +1177,38 @@ Class CompanionLamp : Actor else vel.y += .2; if ( diff.z < 0 ) vel.z -= .2; else vel.z += .2; + blocked = true; } + if ( blocked ) return; + Vector3 dir = level.Vec3Diff(pos,trail); + if ( dir.length() > 0 ) + vel += dir.unit()*min(dir.length()*.05,20.); } States { Spawn: - XZW1 A 1 A_JumpIf(SWWMLamp(master)&&SWWMLamp(master).bActive,1); + XZW1 A 1 + { + if ( SWWMLamp(master) && SWWMLamp(master).bActive ) + { + A_StartSound("lamp/on",CHAN_ITEMEXTRA); + return ResolveState("Active"); + } + return ResolveState(null); + } + Wait; + Active: + XZW1 B 1 + { + A_Moth(); + if ( !SWWMLamp(master) || !SWWMLamp(master).bActive ) + { + A_StartSound("lamp/off",CHAN_ITEMEXTRA); + return ResolveState("Spawn"); + } + return ResolveState(null); + } Wait; - XZW1 B 0 A_JumpIf(!SWWMLamp(master)||!SWWMLamp(master).bActive,"Spawn"); - XZW1 B 1 A_Moth(); - Loop; } } @@ -849,7 +1224,7 @@ Class SWWMLamp : Inventory override Inventory CreateCopy( Actor other ) { // additional lore - SWWMLoreLibrary.Add(other.player,"Lamp"); + SWWMLoreLibrary.Add(other.player,"MothLamp"); return Super.CreateCopy(other); } override bool HandlePickup( Inventory item ) @@ -877,8 +1252,10 @@ Class SWWMLamp : Inventory thelamp = Spawn("CompanionLamp",Owner.Vec3Offset(cos(Owner.angle-180)*32,sin(Owner.angle-180)*32,Owner.height-8)); thelamp.target = Owner; thelamp.master = self; + let f = Spawn("SWWMItemFog",thelamp.pos); + f.A_StartSound("lamp/appear",CHAN_VOICE); } - if ( bActive && !(level.maptime%35) ) Charge--; + if ( bActive && !(level.maptime%35) && !isFrozen() ) Charge--; if ( Charge <= 0 ) { Amount--; @@ -888,7 +1265,12 @@ Class SWWMLamp : Inventory override void DetachFromOwner() { Super.DetachFromOwner(); - if ( thelamp ) thelamp.Destroy(); + if ( thelamp ) + { + let f = Spawn("SWWMItemFog",thelamp.pos); + f.A_StartSound("lamp/disappear",CHAN_VOICE); + thelamp.Destroy(); + } Icon = default.Icon; bActive = false; }