diff --git a/ExampleMod/Content/Items/Consumables/ExampleLifeFruit.cs b/ExampleMod/Content/Items/Consumables/ExampleLifeFruit.cs index 0caa063094d..66ef5cfe0e5 100644 --- a/ExampleMod/Content/Items/Consumables/ExampleLifeFruit.cs +++ b/ExampleMod/Content/Items/Consumables/ExampleLifeFruit.cs @@ -64,10 +64,10 @@ public class ExampleLifeFruitPlayer : ModPlayer { public int exampleLifeFruits; - public override void ResetEffects() { - // Increasing health in the ResetEffects hook in particular is important so it shows up properly in the player select menu - // and so that life regeneration properly scales with the bonus health - Player.statLifeMax2 += exampleLifeFruits * ExampleLifeFruit.LifePerFruit; + public override void ModifyMaxStats(ref int lifeMax, ref int manaMax) { + // "lifeMax" is added as a shortcut for "player.statLifeMax" + // Modifying "lifeMax" here allows the changes to appear in the player select menu as well + lifeMax += exampleLifeFruits * ExampleLifeFruit.LifePerFruit; } public override void SyncPlayer(int toWho, int fromWho, bool newPlayer) { diff --git a/patches/tModLoader/Terraria/Chest.cs.patch b/patches/tModLoader/Terraria/Chest.cs.patch index 562c84efc8d..f92ed3ca863 100644 --- a/patches/tModLoader/Terraria/Chest.cs.patch +++ b/patches/tModLoader/Terraria/Chest.cs.patch @@ -146,6 +146,21 @@ } public void SetupShop(int type) { +@@ -2015,12 +_,12 @@ + num++; + array[num].SetDefaults(1979); + num++; +- if (Main.player[Main.myPlayer].statLifeMax >= 400) { ++ if (Main.player[Main.myPlayer].ConsumedLifeCrystals == Player.LifeCrystalMax) { + array[num].SetDefaults(1977); + num++; + } + +- if (Main.player[Main.myPlayer].statManaMax >= 200) { ++ if (Main.player[Main.myPlayer].ConsumedManaCrystals == Player.ManaCrystalMax) { + array[num].SetDefaults(1978); + num++; + } @@ -2611,6 +_,7 @@ array[num++].SetDefaults(4921); } diff --git a/patches/tModLoader/Terraria/GameContent/Achievements/AchievementsHelper.cs.patch b/patches/tModLoader/Terraria/GameContent/Achievements/AchievementsHelper.cs.patch index 1c36967ba9c..ee6e8dd13bf 100644 --- a/patches/tModLoader/Terraria/GameContent/Achievements/AchievementsHelper.cs.patch +++ b/patches/tModLoader/Terraria/GameContent/Achievements/AchievementsHelper.cs.patch @@ -6,12 +6,16 @@ namespace Terraria.GameContent.Achievements { public class AchievementsHelper -@@ -99,7 +_,7 @@ - if (player.statManaMax > 20) +@@ -96,10 +_,10 @@ + } + } + +- if (player.statManaMax > 20) ++ if (player.ConsumedManaCrystals > 0) Main.Achievements.GetCondition("STAR_POWER", "Use").Complete(); - if (player.statLifeMax == 500 && player.statManaMax == 200) -+ if (player.statLifeMax >= 500 && player.statManaMax >= 200) ++ if (player.ConsumedLifeCrystals == Player.LifeCrystalMax && player.ConsumedLifeFruit == Player.LifeFruitMax && player.ConsumedManaCrystals == Player.ManaCrystalMax) Main.Achievements.GetCondition("TOPPED_OFF", "Use").Complete(); if (player.miscEquips[4].type > 0) @@ -29,13 +33,13 @@ case 1: Main.Achievements.GetCondition("STAR_POWER", "Use").Complete(); - if (player.statLifeMax == 500 && player.statManaMax == 200) -+ if (player.statLifeMax >= 500 && player.statManaMax >= 200) ++ if (player.ConsumedLifeCrystals == Player.LifeCrystalMax && player.ConsumedLifeFruit == Player.LifeFruitMax && player.ConsumedManaCrystals == Player.ManaCrystalMax) Main.Achievements.GetCondition("TOPPED_OFF", "Use").Complete(); break; case 2: Main.Achievements.GetCondition("GET_A_LIFE", "Use").Complete(); - if (player.statLifeMax == 500 && player.statManaMax == 200) -+ if (player.statLifeMax >= 500 && player.statManaMax >= 200) ++ if (player.ConsumedLifeCrystals == Player.LifeCrystalMax && player.ConsumedLifeFruit == Player.LifeFruitMax && player.ConsumedManaCrystals == Player.ManaCrystalMax) Main.Achievements.GetCondition("TOPPED_OFF", "Use").Complete(); break; case 3: diff --git a/patches/tModLoader/Terraria/GameContent/UI/States/UICharacterCreation.cs.patch b/patches/tModLoader/Terraria/GameContent/UI/States/UICharacterCreation.cs.patch index 7b891e6631b..6f62d427e59 100644 --- a/patches/tModLoader/Terraria/GameContent/UI/States/UICharacterCreation.cs.patch +++ b/patches/tModLoader/Terraria/GameContent/UI/States/UICharacterCreation.cs.patch @@ -8,6 +8,22 @@ using Terraria.UI; using Terraria.UI.Gamepad; +@@ -1019,8 +_,15 @@ + private void SetupPlayerStatsAndInventoryBasedOnDifficulty() { + int num = 0; + if (_player.difficulty == 3) { ++ _player.statLifeMax = 100; ++ _player.statManaMax = 20; ++ PlayerLoader.ModifyBaseMaxStats(_player); ++ _player.statLife = _player.statLifeMax; ++ _player.statMana = _player.statManaMax; ++ /* + _player.statLife = (_player.statLifeMax = 100); + _player.statMana = (_player.statManaMax = 20); ++ */ + _player.inventory[num].SetDefaults(6); + _player.inventory[num++].Prefix(-1); + _player.inventory[num].SetDefaults(1); @@ -1055,6 +_,8 @@ _player.savedPerPlayerFieldsThatArentInThePlayerClass = new Player.SavedPlayerDataWithAnnoyingRules(); diff --git a/patches/tModLoader/Terraria/Main.cs.patch b/patches/tModLoader/Terraria/Main.cs.patch index 5cbae03c0c8..60a2db9be22 100644 --- a/patches/tModLoader/Terraria/Main.cs.patch +++ b/patches/tModLoader/Terraria/Main.cs.patch @@ -2941,6 +2941,140 @@ spriteBatch.Draw(TextureAssets.Dust.Value, dust.position - screenPosition, dust.frame, newColor, dust.GetVisualRotation(), new Vector2(4f, 4f), scale, SpriteEffects.None, 0f); if (dust.color.PackedValue != 0) { Microsoft.Xna.Framework.Color color6 = dust.GetColor(newColor); +@@ -28506,11 +_,11 @@ + + private static void HelpText() { + bool flag = false; +- if (player[myPlayer].statLifeMax > 100) ++ if (player[myPlayer].ConsumedLifeCrystals > 0) + flag = true; + + bool flag2 = false; +- if (player[myPlayer].statManaMax > 20) ++ if (player[myPlayer].ConsumedManaCrystals > 0) + flag2 = true; + + bool flag3 = true; +@@ -28932,7 +_,7 @@ + return; + } + +- if (helpText == 202 && !hardMode && player[myPlayer].statLifeMax >= 140) { ++ if (helpText == 202 && !hardMode && player[myPlayer].ConsumedLifeCrystals >= 2) { + npcChatText = Language.GetTextValue("GuideHelpTextSpecific.Help_1120"); + return; + } +@@ -28942,12 +_,12 @@ + return; + } + +- if (helpText == 204 && !NPC.downedGoblins && player[myPlayer].statLifeMax >= 200 && WorldGen.shadowOrbSmashed) { ++ if (helpText == 204 && !NPC.downedGoblins && player[myPlayer].ConsumedLifeCrystals >= 5 && WorldGen.shadowOrbSmashed) { + npcChatText = Language.GetTextValue("GuideHelpTextSpecific.Help_1122"); + return; + } + +- if (helpText == 205 && hardMode && !NPC.downedPirates && player[myPlayer].statLifeMax >= 200) { ++ if (helpText == 205 && hardMode && !NPC.downedPirates && player[myPlayer].ConsumedLifeCrystals >= 5) { + npcChatText = Language.GetTextValue("GuideHelpTextSpecific.Help_1123"); + return; + } +@@ -29026,7 +_,7 @@ + return; + } + +- if (helpText == 1050 && !NPC.downedBoss1 && player[myPlayer].statLifeMax < 200) { ++ if (helpText == 1050 && !NPC.downedBoss1 && player[myPlayer].ConsumedLifeCrystals < 5) { + npcChatText = Lang.dialog(211); + return; + } +@@ -29036,22 +_,22 @@ + return; + } + +- if (helpText == 1052 && !NPC.downedBoss1 && player[myPlayer].statLifeMax >= 200 && player[myPlayer].statDefense > 10) { ++ if (helpText == 1052 && !NPC.downedBoss1 && player[myPlayer].ConsumedLifeCrystals >= 5 && player[myPlayer].statDefense > 10) { + npcChatText = Lang.dialog(WorldGen.crimson ? 404 : 213); + return; + } + +- if (helpText == 1053 && NPC.downedBoss1 && !NPC.downedBoss2 && player[myPlayer].statLifeMax < 300) { ++ if (helpText == 1053 && NPC.downedBoss1 && !NPC.downedBoss2 && player[myPlayer].ConsumedLifeCrystals < 10) { + npcChatText = Lang.dialog(214); + return; + } + +- if (helpText == 1054 && NPC.downedBoss1 && !NPC.downedBoss2 && !WorldGen.crimson && player[myPlayer].statLifeMax >= 300) { ++ if (helpText == 1054 && NPC.downedBoss1 && !NPC.downedBoss2 && !WorldGen.crimson && player[myPlayer].ConsumedLifeCrystals >= 10) { + npcChatText = Lang.dialog(215); + return; + } + +- if (helpText == 1055 && NPC.downedBoss1 && !NPC.downedBoss2 && !WorldGen.crimson && player[myPlayer].statLifeMax >= 300) { ++ if (helpText == 1055 && NPC.downedBoss1 && !NPC.downedBoss2 && !WorldGen.crimson && player[myPlayer].ConsumedLifeCrystals >= 10) { + npcChatText = Lang.dialog(216); + return; + } +@@ -29061,22 +_,22 @@ + return; + } + +- if (helpText == 1057 && NPC.downedBoss1 && NPC.downedBoss2 && NPC.downedBoss3 && !hardMode && player[myPlayer].statLifeMax < 400) { ++ if (helpText == 1057 && NPC.downedBoss1 && NPC.downedBoss2 && NPC.downedBoss3 && !hardMode && player[myPlayer].ConsumedLifeCrystals < Player.LifeCrystalMax) { + npcChatText = Lang.dialog(218); + return; + } + +- if (helpText == 1058 && NPC.downedBoss1 && NPC.downedBoss2 && NPC.downedBoss3 && !hardMode && player[myPlayer].statLifeMax >= 400) { ++ if (helpText == 1058 && NPC.downedBoss1 && NPC.downedBoss2 && NPC.downedBoss3 && !hardMode && player[myPlayer].ConsumedLifeCrystals == Player.LifeCrystalMax) { + npcChatText = Lang.dialog(219); + return; + } + +- if (helpText == 1059 && NPC.downedBoss1 && NPC.downedBoss2 && NPC.downedBoss3 && !hardMode && player[myPlayer].statLifeMax >= 400) { ++ if (helpText == 1059 && NPC.downedBoss1 && NPC.downedBoss2 && NPC.downedBoss3 && !hardMode && player[myPlayer].ConsumedLifeCrystals == Player.LifeCrystalMax) { + npcChatText = Lang.dialog(220); + return; + } + +- if (helpText == 1060 && NPC.downedBoss1 && NPC.downedBoss2 && NPC.downedBoss3 && !hardMode && player[myPlayer].statLifeMax >= 400) { ++ if (helpText == 1060 && NPC.downedBoss1 && NPC.downedBoss2 && NPC.downedBoss3 && !hardMode && player[myPlayer].ConsumedLifeCrystals == Player.LifeCrystalMax) { + npcChatText = Lang.dialog(221); + return; + } +@@ -29091,12 +_,12 @@ + return; + } + +- if (helpText == 1140 && NPC.downedBoss1 && !NPC.downedBoss2 && WorldGen.crimson && player[myPlayer].statLifeMax >= 300) { ++ if (helpText == 1140 && NPC.downedBoss1 && !NPC.downedBoss2 && WorldGen.crimson && player[myPlayer].ConsumedLifeCrystals >= 10) { + npcChatText = Language.GetTextValue("GuideHelpTextSpecific.Help_1140"); + return; + } + +- if (helpText == 1141 && NPC.downedBoss1 && !NPC.downedBoss2 && WorldGen.crimson && player[myPlayer].statLifeMax >= 300) { ++ if (helpText == 1141 && NPC.downedBoss1 && !NPC.downedBoss2 && WorldGen.crimson && player[myPlayer].ConsumedLifeCrystals >= 10) { + npcChatText = Language.GetTextValue("GuideHelpTextSpecific.Help_1141"); + return; + } +@@ -29106,7 +_,7 @@ + return; + } + +- if (helpText == 1143 && NPC.downedBoss2 && !NPC.downedQueenBee && player[myPlayer].statLifeMax >= 300) { ++ if (helpText == 1143 && NPC.downedBoss2 && !NPC.downedQueenBee && player[myPlayer].ConsumedLifeCrystals >= 10) { + npcChatText = Language.GetTextValue("GuideHelpTextSpecific.Help_1143"); + return; + } +@@ -29136,7 +_,7 @@ + return; + } + +- if (helpText == 1149 && hardMode && NPC.downedMechBossAny && player[myPlayer].statLifeMax < 500) { ++ if (helpText == 1149 && hardMode && NPC.downedMechBossAny && player[myPlayer].ConsumedLifeCrystals == Player.LifeCrystalMax && player[myPlayer].ConsumedLifeFruit < Player.LifeFruitMax) { + npcChatText = Language.GetTextValue("GuideHelpTextSpecific.Help_1149"); + return; + } @@ -29206,8 +_,8 @@ int num = (mouseTextColor * 2 + 255) / 3; Microsoft.Xna.Framework.Color textColor = new Microsoft.Xna.Framework.Color(num, num, num, num); @@ -4990,6 +5124,24 @@ if (invasionX > (double)spawnTileX) { invasionX -= num; +@@ -49722,7 +_,7 @@ + + int num = 0; + for (int i = 0; i < 255; i++) { +- if (player[i].active && player[i].statLifeMax >= 200) ++ if (player[i].active && player[i].ConsumedLifeCrystals >= 5) + num++; + } + +@@ -49738,7 +_,7 @@ + + int num = 0; + for (int i = 0; i < 255; i++) { +- if (player[i].active && player[i].statLifeMax >= 200) ++ if (player[i].active && player[i].ConsumedLifeCrystals >= 5) + num++; + } + @@ -49871,7 +_,7 @@ Netplay.Clients[k].TimeOutTimer += 3; @@ -5097,6 +5249,15 @@ if (!NPC.downedSlimeKing) num3 /= 2; +@@ -50069,7 +_,7 @@ + + bool flag = false; + for (int i = 0; i < 255; i++) { +- if (Main.player[i].active && Main.player[i].statLifeMax > 140 && Main.player[i].statDefense > 8) ++ if (Main.player[i].active && Main.player[i].ConsumedLifeCrystals > 2 && Main.player[i].statDefense > 8) + flag = true; + } + @@ -50141,6 +_,7 @@ WorldGen.UnspawnTravelNPC(); } @@ -5115,6 +5276,24 @@ int num8 = 0; for (int j = 0; j < 200; j++) { if (npc[j].active && npc[j].townNPC && npc[j].type != 37 && npc[j].type != 453) +@@ -50288,7 +_,7 @@ + if (!NPC.downedBoss1 && netMode != 1) { + bool flag = false; + for (int i = 0; i < 255; i++) { +- if (player[i].active && player[i].statLifeMax >= 200 && player[i].statDefense > 10) { ++ if (player[i].active && player[i].ConsumedLifeCrystals >= 5 && player[i].statDefense > 10) { + flag = true; + break; + } +@@ -50360,7 +_,7 @@ + + if (!WorldGen.spawnEye && moonPhase != 4 && rand.Next(maxValue) == 0 && netMode != 1) { + for (int m = 0; m < 255; m++) { +- if (player[m].active && player[m].statLifeMax > 120) { ++ if (player[m].active && player[m].ConsumedLifeCrystals > 1) { + bloodMoon = true; + break; + } @@ -50505,6 +_,11 @@ } diff --git a/patches/tModLoader/Terraria/ModLoader/ModPlayer.cs b/patches/tModLoader/Terraria/ModLoader/ModPlayer.cs index cbd3285edd4..3946be71afe 100644 --- a/patches/tModLoader/Terraria/ModLoader/ModPlayer.cs +++ b/patches/tModLoader/Terraria/ModLoader/ModPlayer.cs @@ -62,6 +62,35 @@ public virtual void Initialize() { public virtual void ResetEffects() { } + /// + /// Allows you to modify the player's base max stats before increases from the Life Crystal, Life Fruit and Mana Crystal are applied + /// + /// + /// The base maximum health. Defaults to 100 + /// The base maximum mana. Defaults to 20 + public virtual void ModifyBaseMaxStats(ref int lifeMax, ref int manaMax) { + } + + /// + /// This is called before , but after the intial increases from the Life Crystal, Life Fruit, Mana Crystal and are applied + /// + public virtual void PreModifyMaxStats(int lifeMax, int manaMax) { + } + + /// + /// Allows you to modify the player's max stats. This hook runs after vanilla increases from the Life Crystal, Life Fruit and Mana Crystal are applied + /// + /// The base maximum health. Defaults to 100 + /// The base maximum mana. Defaults to 20 + public virtual void ModifyMaxStats(ref int lifeMax, ref int manaMax) { + } + + /// + /// This is called after + /// + public virtual void PostModifyMaxStats(int lifeMax, int manaMax) { + } + /// /// Similar to UpdateDead, except this is only called when the player is dead. If this is called, then ResetEffects will not be called. /// diff --git a/patches/tModLoader/Terraria/ModLoader/PlayerLoader.cs b/patches/tModLoader/Terraria/ModLoader/PlayerLoader.cs index 00fe03307da..1fe08e1878f 100644 --- a/patches/tModLoader/Terraria/ModLoader/PlayerLoader.cs +++ b/patches/tModLoader/Terraria/ModLoader/PlayerLoader.cs @@ -78,6 +78,59 @@ public static void ResetEffects(Player player) { } } + private delegate void DelegateModifyBaseMaxStats(Player player, ref int healthMax, ref int manaMax); + private static HookList HookModifyBaseMaxStats = AddHook(p => p.ModifyBaseMaxStats); + + public static void ModifyBaseMaxStats(Player player) { + foreach (var modPlayer in HookModifyBaseMaxStats.Enumerate(player.modPlayers)) { + modPlayer.ModifyBaseMaxStats(ref player.statLifeMax, ref player.statManaMax); + } + } + + private delegate void DelegatePreModifyMaxStats(int healthMax, int manaMax); + private static HookList HookPreModifyMaxStats = AddHook(p => p.PreModifyMaxStats); + + public static void PreModifyMaxStats(Player player) { + foreach (var modPlayer in HookPreModifyMaxStats.Enumerate(player.modPlayers)) { + modPlayer.PreModifyMaxStats(player.statLifeMax, player.statManaMax); + } + } + + private delegate void DelegateModifyMaxStats(ref int healthMax, ref int manaMax); + private static HookList HookModifyMaxStats = AddHook(p => p.ModifyMaxStats); + + public static void ModifyMaxStats(Player player) { + foreach (var modPlayer in HookModifyMaxStats.Enumerate(player.modPlayers)) { + modPlayer.ModifyMaxStats(ref player.statLifeMax, ref player.statManaMax); + } + } + + private delegate void DelegatePostModifyMaxStats(int healthMax, int manaMax); + private static HookList HookPostModifyMaxStats = AddHook(p => p.PostModifyMaxStats); + + public static void PostModifyMaxStats(Player player) { + foreach (var modPlayer in HookPostModifyMaxStats.Enumerate(player.modPlayers)) { + modPlayer.PostModifyMaxStats(player.statLifeMax, player.statManaMax); + } + } + + public static void UpdateMaxStats(Player player) { + player.statLifeMax = 100; + player.statManaMax = 20; + + ModifyBaseMaxStats(player); + + player.statLifeMax += player.ConsumedLifeCrystals * 20 + player.ConsumedLifeFruit * 5; + player.statManaMax += player.ConsumedManaCrystals * 20; + + PreModifyMaxStats(player); + ModifyMaxStats(player); + PostModifyMaxStats(player); + + player.statLifeMax2 = player.statLifeMax; + player.statManaMax2 = player.statManaMax; + } + private static HookList HookUpdateDead = AddHook(p => p.UpdateDead); public static void UpdateDead(Player player) { diff --git a/patches/tModLoader/Terraria/NPC.cs.patch b/patches/tModLoader/Terraria/NPC.cs.patch index d423330d216..475678849b4 100644 --- a/patches/tModLoader/Terraria/NPC.cs.patch +++ b/patches/tModLoader/Terraria/NPC.cs.patch @@ -1310,6 +1310,15 @@ if (Main.player[num7].ZoneTowerNebula) { bool flag19 = true; int num50 = 0; +@@ -60086,7 +_,7 @@ + int num105 = Main.rand.Next(7); + int num106 = 12; + int maxValue3 = 20; +- if (Main.player[num7].statLifeMax <= 100) { ++ if (Main.player[num7].ConsumedLifeCrystals == 0) { + num106 = 5; + num106 -= Main.CurrentFrameFlags.ActivePlayersCount / 2; + if (num106 < 2) @@ -60370,6 +_,11 @@ } } @@ -1593,6 +1602,15 @@ float num = (float)(255 - alpha) / 255f; int num2 = (int)((float)(int)newColor.R * num); int num3 = (int)((float)(int)newColor.G * num); +@@ -71473,7 +_,7 @@ + break; + } + } +- else if (Main.player[Main.myPlayer].statLifeMax < 300 || Main.player[Main.myPlayer].statDefense < 10) { ++ else if (Main.player[Main.myPlayer].ConsumedLifeCrystals < 10 || Main.player[Main.myPlayer].statDefense < 10) { + switch (Main.rand.Next(4)) { + case 0: + result = Lang.dialog(85); @@ -72350,6 +_,7 @@ result = ((!HasSpecialEventText("Bunny", out specialEventText)) ? Lang.BunnyChat(this) : specialEventText); } diff --git a/patches/tModLoader/Terraria/Player.cs.patch b/patches/tModLoader/Terraria/Player.cs.patch index ee32283223f..8c024103b54 100644 --- a/patches/tModLoader/Terraria/Player.cs.patch +++ b/patches/tModLoader/Terraria/Player.cs.patch @@ -2464,7 +2464,16 @@ hasFootball = false; drawingFootball = false; minionKB = 0f; -@@ -13116,11 +_,19 @@ +@@ -13110,17 +_,28 @@ + gravControl = false; + honeyCombItem = null; + gravControl2 = false; ++ PlayerLoader.UpdateMaxStats(this); ++ /* + statLifeMax2 = statLifeMax; + statManaMax2 = statManaMax; ++ */ + chloroAmmoCost80 = false; huntressAmmoCost90 = false; ammoCost80 = false; ammoCost75 = false; @@ -5919,7 +5928,7 @@ try { RijndaelManaged rijndaelManaged = new RijndaelManaged(); rijndaelManaged.Padding = PaddingMode.None; -@@ -38410,16 +_,22 @@ +@@ -38410,16 +_,24 @@ player.statLife = binaryReader.ReadInt32(); player.statLifeMax = binaryReader.ReadInt32(); @@ -5939,6 +5948,8 @@ if (player.statMana > 400) player.statMana = 400; + */ ++ ++ PlayerLoader.UpdateMaxStats(player); if (num >= 125) player.extraAccessory = binaryReader.ReadBoolean(); @@ -6044,9 +6055,11 @@ width = 20; height = 42; name = string.Empty; -@@ -38926,7 +_,7 @@ +@@ -38925,8 +_,9 @@ + lastVisualizedSelectedItem = new Item(); grappling[0] = -1; statManaMax = 20; ++ PlayerLoader.ModifyBaseMaxStats(this); extraAccessory = false; - for (int n = 0; n < 625; n++) { + for (int n = 0; n < adjTile.Length; n++) {