Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New mob affixes #664

Merged
merged 6 commits into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added Assets/AffixIcons/AggravatorAffix.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Assets/AffixIcons/DamageAffix.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Assets/AffixIcons/DoubleLife.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Assets/AffixIcons/FastAffix.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Assets/AffixIcons/SiphonerAffix.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion Common/Buffs/ChilledFunctionality.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public override void Update(int type, NPC npc, ref int buffIndex)
{
if (type == BuffID.Chilled)
{
npc.GetGlobalNPC<SlowDownNPC>().SlowDown += 0.2f;
npc.GetGlobalNPC<SlowDownNPC>().SpeedModifier += 0.2f;

if (Main.rand.NextBool(20))
{
Expand Down
2 changes: 2 additions & 0 deletions Common/Systems/Affixes/Affix.cs
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,8 @@ public void Load(Mod mod)
continue;
case MobAffix mobAffix:
_mobAffixes.Add(mobAffix);

MobAffix.MobAffixIconsByAffixName[mobAffix.GetType().AssemblyQualifiedName] = ModContent.Request<Texture2D>(mobAffix.TexturePath);
break;
}
}
Expand Down
37 changes: 30 additions & 7 deletions Common/Systems/Affixes/MobAffix.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,30 @@
using PathOfTerraria.Common.Enums;
using ReLogic.Content;
using System.Collections.Generic;
using Terraria.Localization;
using Terraria.ModLoader.IO;

namespace PathOfTerraria.Common.Systems.Affixes;

internal abstract class MobAffix : Affix
{
public static readonly Dictionary<string, Asset<Texture2D>> MobAffixIconsByAffixName = [];

public Asset<Texture2D> Icon => MobAffixIconsByAffixName[GetType().AssemblyQualifiedName];

public virtual ItemRarity MinimumRarity => ItemRarity.Magic;
public virtual bool Allowed => true;


/// <summary>
/// Texture path that points to the icon that shows over an NPC.
/// </summary>
public virtual string TexturePath => Mod.Name + "/Assets/AffixIcons/" + GetType().Name;

/// <summary>
/// Text for the affix's prefix, such as the Strong in "Strong Blue Slime".
/// </summary>
public virtual LocalizedText Prefix => this.GetLocalization("Prefix");

// would prefer ProgressionLock, but then you'd have to write !Main.moonlordDowned
// but its mainly for progression
public virtual float DropQuantityFlat => 0;
Expand All @@ -16,24 +33,30 @@ internal abstract class MobAffix : Affix
public virtual float DropRarityMultiplier => 1f;

/// <summary>
/// after the rarity buff has been applied
/// Runs after the rarity buff has been applied.
/// </summary>
public virtual void PostRarity(NPC npc) { }

/// <summary>
/// before the rarity buff has been applied
/// Runs before the rarity buff has been applied.
/// </summary>
public virtual void PreRarity(NPC npc) { }

public virtual bool PreAi(NPC npc) { return true; }
public virtual void Ai(NPC npc) { }
public virtual void PostAi(NPC npc) { }
public virtual bool PreAI(NPC npc) { return true; }
public virtual void AI(NPC npc) { }
public virtual void PostAI(NPC npc) { }
public virtual bool PreDraw(NPC npc, SpriteBatch spriteBatch, Vector2 screenPos, Color drawColor) { return true; }
public virtual void OnKill(NPC npc) { }
public virtual bool PreKill(NPC npc) { return true; }

internal override void CreateLocalization()
{
// Populate prefix, don't store
this.GetLocalization("Prefix");
}

/// <summary>
/// Generates an affix from a tag, used on load to re-populate affixes
/// Generates an affix from a tag, used on load to re-populate affixes.
/// </summary>
/// <param name="tag"></param>
/// <returns></returns>
Expand Down
35 changes: 35 additions & 0 deletions Common/Systems/Affixes/MobAffixIconDrawing.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using PathOfTerraria.Common.Systems.MobSystem;
using System.Collections.Generic;

namespace PathOfTerraria.Common.Systems.Affixes;

internal class MobAffixIconDrawing : GlobalNPC
{
public override bool InstancePerEntity => true;

private float _hoverStrength = 0;

public override void PostDraw(NPC npc, SpriteBatch spriteBatch, Vector2 screenPos, Color drawColor)
{
List<MobAffix> affixes = npc.GetGlobalNPC<ArpgNPC>().Affixes;

if (affixes.Count == 0)
{
return;
}

_hoverStrength = MathHelper.Lerp(_hoverStrength, npc.Hitbox.Contains(Main.MouseWorld.ToPoint()) ? 1 : 0, 0.1f);

float offset = affixes.Count / 2f - 0.5f;
float scale = MathHelper.Lerp(1f, 1.5f, _hoverStrength);
float opacity = MathHelper.Lerp(0.6f, 1f, _hoverStrength);

for (int i = 0; i < affixes.Count; i++)
{
MobAffix affix = affixes[i];

Vector2 position = npc.Center - screenPos + new Vector2((i * 20 - offset * 20) * scale, -npc.height / 2 - 12);
spriteBatch.Draw(affix.Icon.Value, position, null, drawColor * opacity, 0f, affix.Icon.Size() / 2f, scale, SpriteEffects.None, 0);
}
}
}
12 changes: 12 additions & 0 deletions Common/Systems/Affixes/MobTypes/DamageAffixes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace PathOfTerraria.Common.Systems.Affixes.MobTypes;

internal class DamageAffixes
{
internal class DamageAffix : MobAffix
{
public override void PostRarity(NPC npc)
{
npc.damage = (int)(npc.damage * 1.5f);
}
}
}
28 changes: 28 additions & 0 deletions Common/Systems/Affixes/MobTypes/SpeedAffixes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@

namespace PathOfTerraria.Common.Systems.Affixes.MobTypes;

internal class SpeedAffixes
{
public class FastAffix : MobAffix
{
public override bool PreAI(NPC npc)
{
npc.GetGlobalNPC<SpeedUpNPC>().ExtraAISpeed += 0.3f;
return true;
}
}

public class AggravatorAffix : MobAffix
{
public override bool PreAI(NPC npc)
{
if (npc.life < npc.lifeMax)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be looking for half health? Doesn't look like it is

{
npc.GetGlobalNPC<SpeedUpNPC>().ExtraAISpeed += 0.3f;
npc.defense = npc.defDefense + 10;
}

return true;
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these should just be individual files tbh. I find these classes with multiple classes within it a bit hard to find sometimes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, I was just following what had already been set up - DoubleLife was nested in a LifeAffixes class.

}
23 changes: 23 additions & 0 deletions Common/Systems/Affixes/MobTypes/UniqueAffixes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using PathOfTerraria.Common.Enums;
using PathOfTerraria.Common.Systems.MobSystem;

namespace PathOfTerraria.Common.Systems.Affixes.MobTypes;

internal class UniqueAffixes
{
internal class SiphonerAffix : MobAffix
{
public override ItemRarity MinimumRarity => ItemRarity.Rare;

public class SiphonerNPC : GlobalNPC
{
public override void OnHitPlayer(NPC npc, Player target, Player.HurtInfo hurtInfo)
{
if (npc.GetGlobalNPC<ArpgNPC>().HasAffix<SiphonerAffix>())
{
target.CheckMana(hurtInfo.Damage / 2, true);
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,22 @@
using PathOfTerraria.Common.Systems.ModPlayers;
using PathOfTerraria.Core.Items;
using SubworldLibrary;
using Terraria;
using Terraria.ID;
using Terraria.Localization;
using Terraria.ModLoader.IO;

namespace PathOfTerraria.Common.Systems.MobSystem;

internal class MobAprgSystem : GlobalNPC
internal class ArpgNPC : GlobalNPC
{
public override bool InstancePerEntity => true;

public int? Experience;
public ItemRarity Rarity = ItemRarity.Normal;
public List<MobAffix> Affixes = [];

private readonly Player _lastPlayerHit = null;

private List<MobAffix> _affixes = [];
private bool _synced = false;

// should somehow work together with magic find (that i assume we will have) to increase rarity / if its a unique
Expand All @@ -34,8 +33,8 @@ private float DropRarity
get
{
float dropRarity = 0;
_affixes.ForEach(a => dropRarity += a.DropRarityFlat);
_affixes.ForEach(a => dropRarity *= a.DropRarityMultiplier);
Affixes.ForEach(a => dropRarity += a.DropRarityFlat);
Affixes.ForEach(a => dropRarity *= a.DropRarityMultiplier);
return dropRarity; // rounds down iirc
}
}
Expand All @@ -54,39 +53,39 @@ private float DropRarity
get
{
float dropQuantity = 1;
_affixes.ForEach(a => dropQuantity += a.DropQuantityFlat);
_affixes.ForEach(a => dropQuantity *= a.DropQuantityMultiplier);
Affixes.ForEach(a => dropQuantity += a.DropQuantityFlat);
Affixes.ForEach(a => dropQuantity *= a.DropQuantityMultiplier);
return dropQuantity;
}
}

public override bool PreAI(NPC npc)
{
bool doRunNormalAi = true;
_affixes.ForEach(a => doRunNormalAi = doRunNormalAi && a.PreAi(npc));
Affixes.ForEach(a => doRunNormalAi = doRunNormalAi && a.PreAI(npc));
return doRunNormalAi;
}

public override void AI(NPC npc)
{
_affixes.ForEach(a => a.Ai(npc));
Affixes.ForEach(a => a.AI(npc));
}

public override void PostAI(NPC npc)
{
_affixes.ForEach(a => a.PostAi(npc));
Affixes.ForEach(a => a.PostAI(npc));
}

public override bool PreDraw(NPC npc, SpriteBatch spriteBatch, Vector2 screenPos, Color drawColor)
{
bool doDraw = true;
_affixes.ForEach(a => doDraw = doDraw && a.PreDraw(npc, spriteBatch, screenPos, drawColor));
Affixes.ForEach(a => doDraw = doDraw && a.PreDraw(npc, spriteBatch, screenPos, drawColor));
return doDraw;
}

public override void OnKill(NPC npc)
{
_affixes.ForEach(a => a.OnKill(npc));
Affixes.ForEach(a => a.OnKill(npc));

if (npc.lifeMax <= 5 || npc.SpawnedFromStatue || npc.boss)
{
Expand Down Expand Up @@ -124,11 +123,11 @@ public override void OnKill(NPC npc)
public override bool PreKill(NPC npc)
{
bool doKill = true;
_affixes.ForEach(a => doKill = doKill && a.PreKill(npc));
Affixes.ForEach(a => doKill = doKill && a.PreKill(npc));
return doKill;
}

public override void SetDefaultsFromNetId(NPC npc)
public override void SetDefaults(NPC npc)
{
//We only want to trigger these changes on hostile non-boss, non Eater of Worlds mobs in-game
if (npc.friendly || npc.boss || Main.gameMenu || npc.type is NPCID.EaterofWorldsBody or NPCID.EaterofWorldsHead or NPCID.EaterofWorldsTail)
Expand Down Expand Up @@ -161,18 +160,14 @@ public override void SetDefaultsFromNetId(NPC npc)
}
}

public void ApplyRarity(NPC npc)
public override void SetDefaultsFromNetId(NPC npc)
{
// npc.TypeName uses only the netID, which is not set by SetDefaults...for some reason.
// This works the same, just using type if netID isn't helpful.
string typeName = NPCLoader.ModifyTypeName(npc, Lang.GetNPCNameValue(npc.netID == 0 ? npc.type : npc.netID));
SetName(npc);
}

npc.GivenName = Rarity switch
{
ItemRarity.Magic or ItemRarity.Rare => $"{Language.GetTextValue($"Mods.{PoTMod.ModName}.Misc.RarityNames." + Enum.GetName(Rarity))} {typeName}",
ItemRarity.Unique => "UNIQUE MOB",
_ => typeName
};
public void ApplyRarity(NPC npc)
{
string typeName = SetName(npc);

if (MobRegistry.TryGetMobData(npc.type, out MobData mobData))
{
Expand Down Expand Up @@ -202,14 +197,14 @@ public void ApplyRarity(NPC npc)
}

List<MobAffix> possible = AffixHandler.GetAffixes(Rarity);
_affixes = Rarity switch

Affixes = Rarity switch
{
ItemRarity.Magic => Affix.GenerateAffixes(possible, PoTItemHelper.GetAffixCount(Rarity)),
ItemRarity.Rare => Affix.GenerateAffixes(possible, PoTItemHelper.GetAffixCount(Rarity)),
ItemRarity.Magic or ItemRarity.Rare => Affix.GenerateAffixes(possible, PoTItemHelper.GetMaxMobAffixCounts(Rarity)),
_ => []
};

_affixes.ForEach(a => a.PreRarity(npc));
Affixes.ForEach(a => a.PreRarity(npc));

switch (Rarity)
{
Expand All @@ -233,10 +228,43 @@ public void ApplyRarity(NPC npc)
throw new InvalidOperationException("Invalid rarity!");
}

_affixes.ForEach(a => a.PostRarity(npc));
SetName(npc);

Affixes.ForEach(a => a.PostRarity(npc));
_synced = true;
}

private string SetName(NPC npc)
{
// npc.TypeName uses only the netID, which is not set by SetDefaults...for some reason.
// This works the same, just using type if netID isn't helpful.
string typeName = NPCLoader.ModifyTypeName(npc, Lang.GetNPCNameValue(npc.netID == 0 ? npc.type : npc.netID));

npc.GivenName = Rarity switch
{
ItemRarity.Magic or ItemRarity.Rare => $"{Language.GetTextValue($"Mods.{PoTMod.ModName}.Misc.RarityNames." + Enum.GetName(Rarity))} {typeName}",
ItemRarity.Unique => "UNIQUE MOB",
_ => typeName
};

npc.GivenName = GetAffixPrefixes(npc) + npc.GivenName;

return typeName;
}

private static string GetAffixPrefixes(NPC npc)
{
List<MobAffix> affixes = npc.GetGlobalNPC<ArpgNPC>().Affixes;
string prefix = "";

foreach (MobAffix affix in affixes)
{
prefix += affix.Prefix + " ";
}

return prefix;
}

public override void SendExtraAI(NPC npc, BitWriter bitWriter, BinaryWriter binaryWriter)
{
binaryWriter.Write((byte)Rarity);
Expand All @@ -259,4 +287,17 @@ public override void ReceiveExtraAI(NPC npc, BitReader bitReader, BinaryReader b
ApplyRarity(npc);
}
}

public bool HasAffix<T>() where T : MobAffix
{
foreach (MobAffix affix in Affixes)
{
if (affix.GetType() == typeof(T))
{
return true;
}
}

return false;
}
}
Loading