All items done (excl. Lootboxes). On to the weapons now.

This commit is contained in:
Mari the Deer 2020-02-05 23:31:56 +01:00
commit 9ce417a49d
28 changed files with 641 additions and 41 deletions

View file

@ -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

View file

@ -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
{

View file

@ -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.";

View file

@ -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 " "

View file

@ -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"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 9.6 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9 KiB

After

Width:  |  Height:  |  Size: 9 KiB

Before After
Before After

View file

@ -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

BIN
sounds/items/lampappear.ogg Normal file

Binary file not shown.

Binary file not shown.

BIN
sounds/items/lampoff.ogg Normal file

Binary file not shown.

BIN
sounds/items/lampon.ogg Normal file

Binary file not shown.

BIN
sounds/items/makeammo.ogg Normal file

Binary file not shown.

BIN
sounds/items/mothatk1.ogg Normal file

Binary file not shown.

BIN
sounds/items/mothatk2.ogg Normal file

Binary file not shown.

BIN
sounds/items/mothatk3.ogg Normal file

Binary file not shown.

BIN
sounds/items/mothatk4.ogg Normal file

Binary file not shown.

BIN
sounds/items/mothdie1.ogg Normal file

Binary file not shown.

BIN
sounds/items/mothdie2.ogg Normal file

Binary file not shown.

BIN
sounds/items/mothfly.ogg Normal file

Binary file not shown.

BIN
sounds/items/omnisight.ogg Normal file

Binary file not shown.

View file

@ -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<Class<Ammo> > available;
// populate ammo production list
for ( int i=0; i<AllActorClasses.Size(); i++ )
{
let a = (Class<Ammo>)(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<available.Size(); i++ )
{
int amt, lim;
int cnt = 0;
Ammo cur = Ammo(Owner.FindInventory(available[i]));
if ( cur )
{
amt = cur.Amount;
lim = cur.MaxAmount;
}
else
{
cur = Ammo(Spawn(available[i]));
amt = cur.Amount = 0;
lim = cur.MaxAmount;
cur.AttachToOwner(Owner);
}
while ( (amt < lim) && (consumed+cur.default.Stamina < budget) && (cnt < pertype) )
{
consumed += cur.default.Stamina;
amt = ++cur.Amount;
cnt++;
given = true;
}
if ( cnt > 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;
}
}

View file

@ -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';

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -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<moff.Size(); i++ )
{
if ( moff[i] && (moff[i].lamp == self) && moff[i].isEntranced() ) continue;
moff.Delete(i);
i--;
}
if ( (GetAge()%35) || Random[Moth](0,9) || (moff.Size() >= 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<BlockingFloor.Get3DFloorCount(); i++ )
{
if ( !(BlockingFloor.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
normal = -BlockingFloor.Get3DFLoor(i).top.Normal;
break;
}
vel += 4.*normal;
blocked = true;
}
if ( BlockingCeiling )
{
// push away from ceiling
Vector3 normal = BlockingCeiling.ceilingplane.Normal;
// find closest 3d floor for its normal
for ( int i=0; i<BlockingCeiling.Get3DFloorCount(); i++ )
{
if ( !(BlockingCeiling.Get3DFloor(i).bottom.ZAtPoint(pos.xy) ~== ceilingz) ) continue;
normal = -BlockingCeiling.Get3DFloor(i).bottom.Normal;
break;
}
vel += 4.*normal;
blocked = true;
}
if ( (diff.x > -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;
}