Stuff and things:

- Reset nugget amounts back to 5 per pickup.
 - Added Omnisight (currently just allmap).
 - Added Lämp (currently just aesthetic, no moths yet).
 - Some stuff I can't remember.
 - Added konami code easter egg to demolitionist menu.
This commit is contained in:
Mari the Deer 2020-02-05 01:43:13 +01:00
commit b6f434a28d
13 changed files with 354 additions and 46 deletions

View file

@ -347,32 +347,30 @@ have a spare. Most powerups can be toggled, unless specified otherwise.
### Health Nugget, replaces Health Bonus, Crystal Vial
Health nuggets increase health by 1% up to a cap of 200.
Health nuggets increase health by 5% up to a cap of 200.
### Health Tetrahedron, replaces Stimpak, Quartz Flask
Health tetrahedrons provide a 15% health boost up to a cap of 100.
### Health Cube, replaces Medkit, Quartz Flask
### Health Cube, replaces Medkit, Mystic Urn (Hexen), Quartz Flask (Heretic)
Health cubes provide a 30% health boost up to a cap of 100.
### Refresher, replaces Soulsphere, Mystic Urn
### Refresher, replaces Soulsphere, Mystic Urn (Heretic), Mystic Ambit Incant
This artifact provides a massive boost of health to 500, plus a regeneration
effect that heals 10% every 5 seconds, for up to 60 seconds, thus it doubles
effect that heals 5% every 2 seconds, for up to 60 seconds, thus it doubles
as a powerup. Like other health items, the Refresher is auto-activated if
you're about to die, though it sometimes won't be enough to save you.
### Armor Nugget, replaces Armor Bonus, Timebomb of the Ancients, Disc of Repulsion
Cumulative armor items that can increase resistance to all damage by as much
as you can find. Each nugget adds 1% to the total. Above 100%, damage gets
as you can find. Each nugget adds 5% to the total. Above 100%, damage gets
turned into additional health (up to the standard 100% cap).
The upper cap for these is 200%.
Protection decreases by a 10% of absorbed damage.
### Blast Suit, replaces Green Armor, Silver Shield, Mesh Armor
The blast suit is a nice little light armor which provides a 75% reduction to
@ -428,7 +426,7 @@ Just be careful with height when the effect is about to run out.
This thing makes you impervious to pretty much everything excluding the Ynykron
Artifact.
You're fucking invincible for a total of 90 seconds.
You're fucking invincible for a total of 30 seconds.
### Hammerspace Embiggener, replaces Backpack, Bag of Holding, Porkalator
@ -441,7 +439,7 @@ Separated into four tiers, they work pretty much like the ammo cubes in Doom
Tournament, except they try to "balance" the total ammo given. The max tier
fabricator is the only one capable of producing ammo for superweapons.
### Lamp, replaces Lite-Amp, Torch, Mystic Ambit Incant
### Lamp, replaces Lite-Amp, Torch
A floating lamp companion, may attract moths. The moths will disperse and
attack nearby enemies when toggling it off.

View file

@ -45,6 +45,14 @@ Brightmap Texture "models/Ragekit.png"
{
Map "models/Ragekit_bright.png"
}
Brightmap Texture "models/Omnisight.png"
{
Map "models/Omnisight_bright.png"
}
Brightmap Texture "models/Lamp.png"
{
Map "models/Lamp_bright.png"
}
PointLight ARMORNUGGETLIGHT
{
@ -144,3 +152,17 @@ Object Ragekit
{
Frame "XZW1" { light "RAGELIGHT" }
}
FlickerLight2 LAMPLIGHT
{
Color 0.6 1.0 0.7
Size 240
SecondarySize 248
Interval 0.1
Offset 0 8 0
Attenuate 1
}
Object CompanionLamp
{
Frame "XZW1B" { light "LAMPLIGHT" }
}

BIN
graphics/KBase/Drawing.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

View file

@ -101,6 +101,7 @@ SWWM_MSGSENT = "You sent %dx %s to %s.";
SWWM_MSGRECV = "%s sent you %dx %s.";
SWWM_CHATTAB = "Chat Log";
SWWM_SECRETTAB = "Secret";
SWWM_TODEMO = "To Demo-chan, from Saya and Ibuki \cg♥\c-";
SWWM_MAINCONTROLS = "PgUp/PgDn: Switch Tab | Arrows: Navigate | ";
SWWM_INVCONTROLS = "Enter: Use | Backspace: Drop | ";
SWWM_STRCONTROLS = "Enter: Buy | ";
@ -815,11 +816,13 @@ T_TETRAHEALTH = "Health Tetrahedron";
T_CUBEHEALTH = "Health Cube";
T_INVINCIBALL = "Fuckin' Invinciball";
T_LAMP = "Lämp";
I_LAMP = "Companion Lamp";
T_MOTH = "Moth";
T_MASHIRO = "White Moth";
T_NUGGETH = "Health Nugget";
T_NUGGETA = "Armor Nugget";
T_OMNISIGHT = "Omnisight";
I_OMNISIGHT = "Omnisight Mapping Unit";
T_RAGEKIT = "Ragekit";
T_REFRESHER = "Refresher";
T_SANDWICH = "Grilled Cheese Sandwich";

View file

@ -171,3 +171,41 @@ Model "Ragekit"
FrameIndex XZW1 A 0 0
}
Model "Omnisight"
{
Path "models"
Model 0 "Omnisight_d.3d"
Skin 0 "Omnisight.png"
Scale 0.04 0.04 0.04
RollOffset 30
ZOffset 16
ROTATING
FrameIndex XZW1 A 0 0
}
Model "CompanionLamp"
{
Path "models"
Model 0 "Lamp_d.3d"
Skin 0 "Lamp_off.png"
Scale 0.03 0.03 0.03
ZOffset 8
FrameIndex XZW1 A 0 0
Skin 0 "Lamp.png"
FrameIndex XZW1 B 0 0
}
Model "SWWMLamp"
{
Path "models"
Model 0 "Lamp_d.3d"
Skin 0 "Lamp_off.png"
Scale 0.05 0.05 0.05
ZOffset 16
ROTATING
FrameIndex XZW1 A 0 0
}

View file

@ -443,3 +443,6 @@ menu/demoscroll sounds/menu/menuscroll.ogg
menu/democlose sounds/menu/menuclose.ogg
menu/noinvuse sounds/menu/failinv.ogg
$alias misc/invchange menu/demosel
UseArtifact DSEMPTY

View file

@ -4,11 +4,10 @@ Class ArmorNugget : SWWMArmor
Default
{
Inventory.Icon "graphics/HUD/Icons/I_ArmorNugget.png";
Inventory.Amount 1;
Inventory.Amount 5;
Inventory.MaxAmount 200;
Inventory.InterHubAmount 200;
SWWMArmor.ArmorPriority 10;
SWWMArmor.DrainFactor .1;
SWWMArmor.GiverArmor "ArmorNuggetItem";
}

View file

@ -1515,15 +1515,22 @@ Class SWWMHandler : EventHandler
else if ( e.Replacee == 'Medikit' ) e.Replacement = 'CubeHealthItem';
else if ( e.Replacee == 'ArtiHealth' )
{
if ( Random[Replacements](0,1) ) e.Replacement = 'CubeHealthItem';
if ( gameinfo.gametype&GAME_Heretic && Random[Replacements](0,1) ) e.Replacement = 'CubeHealthItem';
else e.Replacement = 'TetraHealthItem';
}
else if ( (e.Replacee == 'Soulsphere') || (e.Replacee == 'ArtiSuperHealth') ) e.Replacement = 'RefresherItem';
else if ( (e.Replacee == 'Soulsphere') || (e.Replacee == 'ArtiSuperHealth') )
{
if ( gameinfo.gametype&GAME_Heretic ) e.Replacement = 'RefresherItem';
else e.Replacement = 'CubeHealthItem';
}
else if ( e.Replacee == 'ArtiHealingRadius' ) e.Replacement = 'RefresherItem';
else if ( (e.Replacee == 'Megasphere') || (e.Replacee == 'ArtiEgg') || (e.Replacee == 'PlatinumHelm') ) e.Replacement = 'GrilledCheeseSandwich';
else if ( (e.Replacee == 'Blursphere') || (e.Replacee == 'ArtiInvisibility') || (e.Replacee == 'AmuletOfWarding') ) e.Replacement = 'GhostArtifact';
else if ( (e.Replacee == 'Radsuit') || (e.Replacee == 'ArtiFly') || (e.Replacee == 'ArtiSpeedBoots') ) e.Replacement = 'GravitySuppressor';
else if ( (e.Replacee == 'InvulnerabilitySphere') || (e.Replacee == 'ArtiInvulnerability') || (e.Replacee == 'ArtiInvulnerability2') ) e.Replacement = 'FuckingInvinciball';
else if ( (e.Replacee == 'Berserk') || (e.Replacee == 'ArtiTomeOfPower') || (e.Replacee == 'ArtiDarkServant') || (e.Replacee == 'ArtiBoostArmor') ) e.Replacement = 'Ragekit';
else if ( (e.Replacee == 'AllMap') || (e.Replacee == 'SuperMap') ) e.Replacement = 'Omnisight';
else if ( (e.Replacee == 'Infrared') || (e.Replacee == 'ArtiTorch') || (e.Replacee == 'ArtiDarkServant') || (e.Replacee == 'ArtiBoostArmor') ) e.Replacement = 'SWWMLamp';
else if ( (e.Replacee == 'GreenArmor') || (e.Replacee == 'SilverShield') || (e.Replacee == 'MeshArmor') ) e.Replacement = 'BlastSuitItem';
else if ( (e.Replacee == 'BlueArmor') || (e.Replacee == 'FalconShield') || (e.Replacee == 'EnchantedShield') ) e.Replacement = 'WarArmorItem';
}

View file

@ -3,7 +3,7 @@ Class HealthNugget : Health
{
Default
{
Inventory.Amount 1;
Inventory.Amount 5;
Inventory.MaxAmount 200;
}
}
@ -53,7 +53,7 @@ Class RefresherRegen : Powerup
{
Inventory.Icon "graphics/HUD/Icons/I_Refresher.png";
Powerup.Duration -60;
Powerup.Strength 10;
Powerup.Strength 5;
}
override void EndEffect()
@ -65,7 +65,7 @@ Class RefresherRegen : Powerup
override void DoEffect()
{
Super.DoEffect();
if ( Owner && (Owner.health > 0) && !(EffectTics%175) )
if ( Owner && (Owner.health > 0) && !(EffectTics%70) )
{
if ( Owner.GiveBody(int(Strength),500) )
{

View file

@ -27,8 +27,6 @@ Class SWWMStatusBar : BaseStatusBar
double FracTic;
int chatopen;
bool justselected;
DynamicValueInterpolator HealthInter, ScoreInter, FuelInter, DashInter;
override void FlushNotify()
@ -103,18 +101,6 @@ Class SWWMStatusBar : BaseStatusBar
override void Tick()
{
Super.Tick();
if ( CPlayer.inventorytics >= (5*Thinker.TICRATE)-1 )
{
if ( CPlayer.mo.InvSel )
S_StartSound("menu/demoscroll",CHAN_BODY,CHANF_UI|CHANF_MAYBE_LOCAL);
}
if ( CPlayer.inventorytics > 0 ) justselected = false;
else
{
if ( !justselected && CPlayer.mo.InvSel )
S_StartSound("menu/democlose",CHAN_BODY,CHANF_UI|CHANF_MAYBE_LOCAL);
justselected = true;
}
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]);

View file

@ -16,12 +16,10 @@ Mixin Class SWWMAutoUseFix
Class SWWMArmor : Armor abstract
{
int priority;
double reduction;
String drainmsg;
Class<SWWMSpareArmor> parent;
Property ArmorPriority : priority;
Property DrainFactor : reduction;
Property DrainMessage : drainmsg;
Property GiverArmor : parent;
@ -32,7 +30,6 @@ Class SWWMArmor : Armor abstract
+INVENTORY.UNDROPPABLE;
+INVENTORY.KEEPDEPLETED;
+INVENTORY.ALWAYSPICKUP;
SWWMArmor.DrainFactor 1.;
}
override void AttachToOwner( Actor other )
{
@ -65,10 +62,10 @@ Class SWWMArmor : Armor abstract
SWWMHandler.DoFlash(Owner,Color(int(clamp(damage*.15,1,16)),255,224,192),3);
Owner.A_StartSound("armor/hit",CHAN_BODY,CHANF_DEFAULT,clamp(damage*.03,0.,1.),2.5);
saved = HandleDamage(damage,damageType,flags);
if ( amount <= int(ceil(saved*reduction)) ) saved = amount;
if ( amount <= saved ) saved = amount;
newdamage -= saved;
if ( newdamage < 0 ) Owner.GiveBody(abs(newdamage));
amount -= int(ceil(saved*reduction));
amount -= saved;
damage = newdamage;
if ( amount <= 0 )
{
@ -161,7 +158,9 @@ Class SWWMHealth : Inventory abstract
if ( UseSound ) Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA,CHANF_DEFAULT,.6);
while ( (Amount > 0) && (newdamage > 0) )
{
newdamage = max(0,damage-GetDefaultByType(giveme).Amount);
newdamage = damage-GetDefaultByType(giveme).Amount;
if ( newdamage < 0 ) Owner.GiveBody(-newdamage,GetDefaultByType(giveme).MaxAmount);
newdamage = max(0,newdamage);
AutoUseExtra();
Amount--;
}

View file

@ -15,7 +15,7 @@ Class SWWMKnowledgeBaseMenu : GenericMenu
};
TextureID MainWindow, TabSeparator, WindowSeparator, WindowSeparatorH,
FancyBg;
FancyBg, EasterEgg;
Font TewiFont;
int curtab;
// for scrolling
@ -59,11 +59,12 @@ Class SWWMKnowledgeBaseMenu : GenericMenu
return;
}
TewiFont = Font.GetFont('TewiShaded');
FancyBg = TexMan.CheckForTexture("graphics/tempbg.png",TexMan.Type_Any);
MainWindow = TexMan.CheckForTexture("graphics/KBase/MainWindow.png",TexMan.Type_Any);
TabSeparator = TexMan.CheckForTexture("graphics/KBase/TabSeparator.png",TexMan.Type_Any);
WindowSeparator = TexMan.CheckForTexture("graphics/KBase/WindowSeparator.png",TexMan.Type_Any);
WindowSeparatorH = TexMan.CheckForTexture("graphics/KBase/WindowSeparatorH.png",TexMan.Type_Any);
FancyBg = TexMan.CheckForTexture("graphics/tempbg.png",TexMan.Type_MiscPatch);
MainWindow = TexMan.CheckForTexture("graphics/KBase/MainWindow.png",TexMan.Type_MiscPatch);
TabSeparator = TexMan.CheckForTexture("graphics/KBase/TabSeparator.png",TexMan.Type_MiscPatch);
WindowSeparator = TexMan.CheckForTexture("graphics/KBase/WindowSeparator.png",TexMan.Type_MiscPatch);
WindowSeparatorH = TexMan.CheckForTexture("graphics/KBase/WindowSeparatorH.png",TexMan.Type_MiscPatch);
EasterEgg = TexMan.CheckForTexture("graphics/KBase/Drawing.png",TexMan.Type_MiscPatch);
curtab = CVar.GetCVar('swwm_lasttab',players[consoleplayer]).GetInt();
if ( (curtab < 0) || (curtab > 7) ) curtab = 0;
MenuSound("menu/demoopen");
@ -637,9 +638,10 @@ Class SWWMKnowledgeBaseMenu : GenericMenu
}
else if ( curtab == TAB_SECRET )
{
// TODO easter egg "konami code" hidden tab
str = StringTable.Localize("$SWWM_COMINGSOON");
Screen.DrawText(TewiFont,Font.CR_FIRE,(ss.x-TewiFont.StringWidth(str))/2.,(ss.y-TewiFont.GetHeight())/2.,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
// hidden secret tab
Screen.DrawTexture(EasterEgg,false,origin.x+20,origin.y+40,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
str = StringTable.Localize("$SWWM_TODEMO");
Screen.DrawText(TewiFont,Font.CR_FIRE,origin.x+(640-TewiFont.StringWidth(str))/2.,origin.y+350,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
}
}
}

View file

@ -401,7 +401,7 @@ Class InvinciballPower : Powerup
Default
{
Powerup.Duration -90;
Powerup.Duration -30;
Inventory.Icon "graphics/HUD/Icons/I_Invinciball.png";
Powerup.Color "FF3000", 0.1;
}
@ -666,3 +666,254 @@ Class Ragekit : Inventory
Stop;
}
}
Class Omnisight : Inventory
{
override bool Use( bool pickup )
{
level.allmap = true;
// not used up, must be kept for the targetting features to work
return false;
}
Default
{
Tag "$T_OMNISIGHT";
Inventory.PickupSound "misc/p_pkup";
Inventory.PickupMessage "$I_OMNISIGHT";
Inventory.MaxAmount 1;
Inventory.InterHubAmount 0;
+INVENTORY.ALWAYSPICKUP;
+INVENTORY.AUTOACTIVATE;
+COUNTITEM;
+INVENTORY.BIGPOWERUP;
+INVENTORY.UNDROPPABLE;
+INVENTORY.UNTOSSABLE;
+FLOATBOB;
FloatBobStrength 0.25;
}
States
{
Spawn:
XZW1 A -1;
Stop;
}
}
Class LampMoth : Actor
{
}
Class LampMoth2 : LampMoth
{
}
Class LampMashiro : Actor abstract
{
//
// ~nothing here yet, but she will make an appearance someday~
//
// ⠀⠀⠀⠀⠤⠀⠄⠀⠀⠀⠳⠀⠂⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⡣⣁⢌⡀⢄⠁⡁⠝⢿⣿⣿⣿⡻⣿⣿⣷⣦
// ⠀⠀⠠⠀⠠⠀⠀⡀⠘⣠⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣊⢇⠠⢐⢄⡙⢿⣿⣿⣾⠫⣻⣿
// ⠀⡄⠂⢴⠠⠌⠰⢇⠀⠀⠀⠀⠀⠀⠀⢀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⡀⠣⡣⡱⣌⠻⣿⣿⣿⣿⣿
// ⠀⠁⠛⠂⠀⠉⡍⠀⠀⠀⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⠘⣮⣾⡮⢦⡹⣿⣿⣿⣿
// ⠄⠠⠉⢼⡇⠶⠀⠀⠀⠀⠀⠀⢠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡆⢿⣿⣿⡦⢣⡉⢝⢝⢽
// ⠀⠀⠚⠃⠀⠀⡀⠀⠀⠀⠀⣠⣿⣿⣿⣿⣿⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⢸⣿⣿⣿⢀⢃⠀⡁⠑
// ⠰⠀⠂⠁⠀⠀⡆⠀⠀⠀⣴⣿⣿⣿⣿⣿⠋⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡈⣿⣿⣿⣇⠆⢃⠈⡇
// ⠀⠀⠀⢠⠄⣠⣇⠀⢀⣾⣿⣿⣿⣿⣿⡃⢀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⣿⣿⣿⣿⢔⢌⢆⢑
// ⠀⠀⠀⢀⣶⣿⣷⢀⣾⣿⣿⣿⣿⡯⡊⠀⢸⡏⣟⣻⣽⣭⣽⣛⡛⠿⠿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡯⡇⣿⣿⣿⣿⣗⢕⢕⠄
// ⠀⢠⣶⣿⣿⢿⢃⣾⣿⣿⣿⣿⡫⡪⠀⠀⢸⡇⣿⣿⣿⣿⣿⣿⣿⣦⡘⠄⢹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡯⡇⣿⣿⣿⣿⣗⢔⢕⢅
// ⠀⣺⣿⡉⠕⠁⣼⣿⣿⣿⡿⡫⡪⠂⠀⢔⢸⢀⠸⣿⣿⣿⣿⣿⣿⣿⣿⣶⣸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣪⠃⣿⣿⣿⣿⡟⢄⣡⣵
// ⡛⠟⢋⠀⠀⢸⣿⣿⣿⣿⢠⢫⡊⠀⡔⢵⡈⢠⢣⡹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠡⠚⠓⠪⠉⠛⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡫⡎⣸⣿⣿⣿⡟⢠⢃⣂⡿
// ⡃⡊⢃⡔⡠⣿⣿⣿⣿⡇⣜⡘⢀⢜⡀⡅⡆⠘⢐⠁⠙⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢾⠿⢿⣿⣿⣿⣿⣷⣾⣽⡻⢿⣿⣿⣿⣿⣿⣿⣿⡿⣛⣿⣿⣟⡜⠠⣻⣿⣿⡟⠴⠃⠉⠁⠀
// ⡺⢠⡾⣸⡷⣿⣿⣿⣿⠂⣓⠂⡎⡺⠪⠒⠃⠀⠀⠀⠀⠀⠙⠿⣯⢻⣿⣿⣿⡟⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣵⣾⣿⡷⣲⣿⣿⣿⣿⣿⣿⣿⣷⣝⢿⣿⣿⣿⡿⡫⡺⣽⣿⣿⡗⠀⢸⣿⣿⠏⠀⠀⠀⠀⠀⠀
// ⣴⣿⢣⣿⢳⣿⣿⣿⡿⡨⡊⠠⡪⡢⠂⠀⠀⠀⠀⠀⢀⣀⠀⠀⠘⢧⡻⣿⣿⡇⢿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣿⣿⣵⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⢳⣝⠿⡫⡪⣪⡮⣾⣿⡟⢠⠅⣿⠟⠋⠀⠀⠀⠀⠀⠀⠀
// ⣿⡏⣾⢣⡾⣿⣿⣿⡇⢪⠂⡨⡠⠀⠀⠀⠀⢀⡴⠋⠉⠈⠉⢦⡀⠠⢅⠹⣿⢰⢹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢟⣫⣾⡿⣫⣦⠸⢊⡄⣼⣿⡟⢠⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⡿⢸⣏⣾⣇⣿⣿⣿⡇⢵⢀⢓⠀⠀⠀⠀⠀⡮⠀⠀⠀⠀⠀⠈⣇⠀⠧⡗⡈⢿⣺⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠟⣯⣾⣿⡿⠛⠊⣬⠴⢪⠋⣼⣿⠟⢔⢝⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⠃⡿⣸⣿⣿⢸⣿⣿⡇⡊⢰⢱⢂⡀⠀⠀⠀⢳⠀⠀⠀⠀⠀⢰⡇⠀⣸⢐⡈⢄⢿⠿⠿⢿⡿⠽⢫⣵⣿⡿⠿⠛⠛⠙⠉⠁⠀⠞⠙⠃⠍⡁⠖⡪⡫⡪⣻⢁⣾⡿⢃⢞⢕⡝⢰⣆⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀
// ⢸⢣⣿⣿⡗⡈⢿⣿⡇⠀⢸⣿⣷⣵⣄⠀⠀⠈⠲⣠⣠⣠⡴⠋⠀⠀⢒⢔⢂⢀⢎⢇⣓⡕⠂⡚⡩⢡⢰⢂⣓⡣⣢⠒⠀⠀⠀⠀⠀⠀⠀⠈⠢⡈⡲⡑⢡⣾⠟⡠⡣⣂⢇⠃⣿⣿⣷⣦⡀⠀⠀⠀⠀⠀⠀⠀
// ⡟⣾⣿⡿⣸⢸⡘⣿⣷⠀⢸⣿⣿⣿⣿⣿⣦⣄⣀⣀⣀⣀⣀⣠⣤⣜⢔⢕⢕⢔⢕⢕⣗⣇⣳⡪⣺⢐⢱⢑⢒⠖⠁⠀⠀⢀⠄⠔⠖⢦⣀⠀⠀⠰⠌⣴⠟⡡⡪⡪⡪⡜⡜⣸⣿⣿⣿⣿⡿⡢⠀⠀⠀⠀⠀⠀
// ⢱⣿⣿⡣⢑⠔⡕⠘⣿⡀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣷⣷⣵⣕⣥⣣⣣⡣⡪⣐⢱⢠⡃⠀⠀⠀⣴⠁⠀⠀⠀⠀⠸⣆⠀⠀⠘⠀⡪⡪⡪⡪⡪⣸⢡⣿⣿⣿⣿⣿⡯⣺⡀⢤⡀⠀⠀⠀
// ⣿⣿⣟⣝⣝⣺⠁⠀⠘⣧⢘⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣷⣇⣣⠣⡘⡀⠀⠀⠀⡟⠀⠀⠀⠀⠀⠨⡗⠀⠀⠀⠈⢮⠺⡪⢊⢫⠃⣾⣿⣿⣿⣿⣿⡪⡏⣦⡀⢹⣷⣤⣀
// ⣿⣿⢑⢇⢆⠆⠀⠀⣸⣎⠸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣮⣧⣀⠀⠀⢻⡀⠀⠀⠀⢀⡼⠃⠀⠀⠀⠀⠸⢘⢜⡐⡕⣸⣿⣿⣿⣿⣿⣃⣟⣱⣿⣿⣧⢻⣿⣿
// ⣿⣟⢕⢕⢼⠀⠀⠀⣿⣿⣧⡹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⢡⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠉⠓⠒⠓⠋⠀⠀⠀⠀⠀⠠⠀⠱⡱⡨⢣⣿⣿⣿⣿⣿⢗⡯⣱⣿⣿⣿⢇⣄⠃⠙
// ⣿⡒⡢⡢⡃⠀⠀⠀⣿⣿⣿⣷⣝⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣤⣄⣀⣀⣀⣀⢀⣀⡀⡠⣀⡢⡪⠂⣽⣿⣿⣿⣿⣟⡕⣺⣿⣿⣿⣏⣿⣷⢔⡄
// ⡿⡸⢰⢔⠂⠀⠀⠀⢿⣿⣿⣿⣿⣯⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣯⢮⡊⡠⣰⣿⣿⣿⣿⡿⣡⣿⣿⣿⣿⡟⣾⣿⣿⢵⠅
// ⣟⢕⢝⣗⠀⠀⠀⡹⡘⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⣫⡾⢱⣿⣿⣿⣿⡟⣼⣿⣿⣿⣿⡿⣹⣿⣿⡟⡹⢰
// ⢕⢕⢕⢕⠠⡢⣪⢂⢇⢹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⣫⣾⣿⢣⣿⣿⣿⣿⣿⣻⣿⣿⣿⣿⡿⣱⣿⣿⣿⡫⡇⣼
// ⢕⢕⢕⠅⣘⡪⡚⡔⠍⠂⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⣫⣾⣿⢟⢁⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢣⣿⣿⣿⣏⡼⢠⣿
// ⢕⢕⢕⠀⣖⡪⡪⣂⠀⠐⠈⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⢟⣫⣵⡿⢟⣫⡴⢁⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠃⣸⣿⣿⣿⢒⠇⣼⣿
// ⢕⢅⢕⠨⣃⢪⢨⢂⠀⠀⠀⠈⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣄⣳⢰⢬⡙⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣍⣛⠻⠿⠿⠿⢛⣯⡭⠶⣞⣛⣭⣵⣾⣿⠿⢁⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠃⢀⣿⣿⣿⡯⡝⢰⣿⣿
// ⢝⢕⠇⢸⠱⡑⡁⠀⣀⠀⠀⠀⠈⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣷⣬⣃⣹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣶⣾⣿⣿⣿⣿⣿⣿⣿⡿⡱⢃⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠃⠀⣼⣿⣿⣿⣸⢡⣿⣿⣿
// ⢕⢕⠅⢜⠕⡠⣢⣾⣿⣷⣤⣄⢀⣬⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⢛⠴⢡⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠁⠀⢠⣿⣿⣿⢝⢡⣿⣿⣿⣿
// ⢕⢕⠅⣕⢥⡶⢀⠻⣿⣿⣿⣟⢿⣿⣿⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⢫⡐⣕⢡⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⠀⠀⢀⣿⣿⣿⠏⢁⣿⣿⣿⣿⣿
// ⢕⢕⢠⢗⣛⣓⣁⢱⣾⣿⣿⣿⣷⣷⣽⣿⡻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢛⢔⠕⠓⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠀⠀⢀⣾⣿⡿⡣⢎⣿⣿⣿⣿⣿⣿
// ⡕⡕⠠⡅⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⡝⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠋⠐⣁⡴⡴⢣⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠃⠀⠀⢠⣾⠿⣫⠞⣱⣿⣿⣿⣿⣿⠟⡡
// ⢅⢇⢘⢕⢍⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣎⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠿⠿⠛⠛⠛⠉⠁⠀⢀⢜⢕⢅⠕⣡⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠁⠀⠀⠐⡫⡠⠜⣡⣾⣿⣿⡿⠟⠫⠦⠪⠊
// ⢕⢕⢸⣵⣷⣾⣿⣿⣿⣿⣟⢿⣿⣿⣿⣿⣿⣿⣿⣦⣤⡩⣉⣉⡩⣉⣉⠉⠉⠈⠀⠀⠀⠀⠀⠀⠀⢀⣀⡀⠀⠀⣤⢔⢗⢕⠕⣰⣿⣿⣿⣿⣿⣿⣿⣿⡿⢋⢔⢕⠕⣓⠏⣊⠰⠻⠟⠛⣉⠅⢄⠂⡪⡪⡪⠨
//
}
Class CompanionLamp : Actor
{
Vector3 Trail;
Array<LampMoth> moff;
Default
{
+NOGRAVITY;
+NOCLIP;
+SHOOTABLE;
+NODAMAGE;
+NOBLOOD;
+DONTSPLASH;
+FLOATBOB;
+INTERPOLATEANGLES;
Radius 4;
Height 8;
FloatBobStrength 0.5;
}
action void A_Moth()
{
// random chance to spawn moths
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
if ( !target || !SWWMLamp(master) )
{
Destroy();
return;
}
Trail = pos;
}
override void Tick()
{
Super.Tick();
if ( !target || !SWWMLamp(master) )
{
Destroy();
return;
}
// update trailing position
bool foundspot = false;
for ( int i=0; i<180; i++ )
{
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);
if ( !level.IsPointInLevel(testpos) ) continue;
Trail = testpos;
foundspot = true;
}
// check at most for a 45 degree offset
if ( foundspot && (i > 45) ) break;
}
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;
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;
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;
}
}
States
{
Spawn:
XZW1 A 1 A_JumpIf(SWWMLamp(master)&&SWWMLamp(master).bActive,1);
Wait;
XZW1 B 0 A_JumpIf(!SWWMLamp(master)||!SWWMLamp(master).bActive,"Spawn");
XZW1 B 1 A_Moth();
Loop;
}
}
Class SWWMLamp : Inventory
{
bool bActive;
TextureID OnIcon;
Actor thelamp;
int charge;
Property Charge : charge;
override Inventory CreateCopy( Actor other )
{
// additional lore
SWWMLoreLibrary.Add(other.player,"Lamp");
return Super.CreateCopy(other);
}
override bool HandlePickup( Inventory item )
{
// add charge
if ( item.GetClass() == GetClass() )
Charge = min(default.Charge,Charge+SWWMLamp(item).Charge);
return Super.HandlePickup(item);
}
override bool Use( bool pickup )
{
if ( pickup && !deathmatch ) return false;
bActive = !bActive;
if ( !OnIcon ) OnIcon = TexMan.CheckForTexture("graphics/HUD/Icons/I_Lamp.png",TexMan.Type_MiscPatch);
Icon = bActive?OnIcon:default.Icon;
// don't consume on use
Amount++;
return true;
}
override void DoEffect()
{
Super.DoEffect();
if ( !thelamp )
{
thelamp = Spawn("CompanionLamp",Owner.Vec3Offset(cos(Owner.angle-180)*32,sin(Owner.angle-180)*32,Owner.height-8));
thelamp.target = Owner;
thelamp.master = self;
}
if ( bActive && !(level.maptime%35) ) Charge--;
if ( Charge <= 0 )
{
Amount--;
if ( Amount <= 0 ) DepleteOrDestroy();
}
}
override void DetachFromOwner()
{
Super.DetachFromOwner();
if ( thelamp ) thelamp.Destroy();
Icon = default.Icon;
bActive = false;
}
Default
{
Tag "$T_LAMP";
Inventory.Icon "graphics/HUD/Icons/I_LampOff.png";
Inventory.PickupSound "misc/p_pkup";
Inventory.PickupMessage "$I_LAMP";
Inventory.Amount 1;
Inventory.MaxAmount 1;
Inventory.InterHubAmount 1;
+INVENTORY.ALWAYSPICKUP;
+INVENTORY.AUTOACTIVATE;
+INVENTORY.INVBAR;
+COUNTITEM;
+INVENTORY.BIGPOWERUP;
+FLOATBOB;
FloatBobStrength 0.25;
SWWMLamp.Charge 100;
}
States
{
Spawn:
XZW1 A -1;
Stop;
}
}