diff --git a/patches/tModLoader/Terraria/Player.TML.cs b/patches/tModLoader/Terraria/Player.TML.cs
index 1c93be9c4de..0afa9f7349c 100644
--- a/patches/tModLoader/Terraria/Player.TML.cs
+++ b/patches/tModLoader/Terraria/Player.TML.cs
@@ -259,7 +259,34 @@ public float GetWeaponAttackSpeed(Item sItem) {
return attackSpeed;
}
+ // Legacy Thrower properties (uppercase+property in TML)
+ ///
+ /// Multiplier to shot projectile velocity before throwing. Result will be capped to 16f.
+ ///
Only applies to items counted as the damage type
+ ///
+ public float ThrownVelocity { get; set; }
+
+ ///
+ /// If true, player has a 33% chance of not consuming the thrown item.
+ ///
Only applies to consumable items and projectiles counted as the damage type.
+ ///
Projectiles spawned from a player who holds such item will set to prevent duplication.
+ ///
Stacks with multiplicatively
+ ///
+ public bool ThrownCost33 { get; set; }
+
+ ///
+ /// If true, player has a 50% chance of not consuming the thrown item.
+ ///
Only applies to consumable items counted as the damage type.
+ ///
Projectiles spawned from a player who holds such item will set to prevent duplication.
+ ///
Stacks with multiplicatively
+ ///
+ public bool ThrownCost50 { get; set; }
+
+ ///
+ /// Returns true if either or are true
+ ///
+ public bool AnyThrownCostReduction => ThrownCost33 || ThrownCost50;
///
/// Container for current SceneEffect client properties such as: Backgrounds, music, and water styling
diff --git a/patches/tModLoader/Terraria/Player.cs.patch b/patches/tModLoader/Terraria/Player.cs.patch
index cfd9e9cb2dc..bf18196dd3f 100644
--- a/patches/tModLoader/Terraria/Player.cs.patch
+++ b/patches/tModLoader/Terraria/Player.cs.patch
@@ -2347,8 +2347,13 @@
hasFootball = false;
drawingFootball = false;
minionKB = 0f;
-@@ -13118,9 +_,14 @@
+@@ -13116,11 +_,19 @@
+ huntressAmmoCost90 = false;
+ ammoCost80 = false;
ammoCost75 = false;
++ ThrownCost50 = false;
++ ThrownCost33 = false;
++ ThrownVelocity = 1f;
manaRegenBuff = false;
hasCreditsSceneMusicBox = false;
+ arrowDamage = StatModifier.Default;
@@ -4592,7 +4597,7 @@
if (sItem.stack <= 0)
sItem.SetDefaults();
}
-@@ -33081,16 +_,21 @@
+@@ -33081,16 +_,28 @@
}
private void ItemCheck_Shoot(int i, Item sItem, int weaponDamage) {
@@ -4605,6 +4610,13 @@
if (sItem.melee && projToShoot != 699 && projToShoot != 707 && (uint)(projToShoot - 877) > 2u)
- speed /= meleeSpeed;
+ speed /= inverseMeleeSpeed;
++
++ // Copied as-is from 1.3
++ if (sItem.CountsAsClass(DamageClass.Throwing) && speed < 16f) {
++ speed *= ThrownVelocity;
++ if (speed > 16f)
++ speed = 16f;
++ }
bool canShoot = false;
int Damage = weaponDamage;
@@ -5200,10 +5212,19 @@
if (huntressAmmoCost90 && Main.rand.Next(10) == 0)
flag2 = true;
-@@ -37226,6 +_,7 @@
+@@ -37226,6 +_,16 @@
if (ammoCost75 && Main.rand.Next(4) == 0)
flag2 = true;
++ // Copied as-is from 1.3
++ if (item.CountsAsClass(DamageClass.Throwing)) {
++ if (ThrownCost50 && Main.rand.Next(100) < 50)
++ flag2 = true;
++
++ if (ThrownCost33 && Main.rand.Next(100) < 33)
++ flag2 = true;
++ }
++
+ /* Flamethrower + Elf Melter (handled by consumeAmmoOnFirstShotOnly) + Clentaminator (handled by consumeAmmoOnFirstShotOnly)
if (projToShoot == 85 && itemAnimation < itemAnimationMax - 2)
flag2 = true;
diff --git a/patches/tModLoader/Terraria/Projectile.cs.patch b/patches/tModLoader/Terraria/Projectile.cs.patch
index 6f6300033d9..38eb64029a6 100644
--- a/patches/tModLoader/Terraria/Projectile.cs.patch
+++ b/patches/tModLoader/Terraria/Projectile.cs.patch
@@ -324,7 +324,19 @@
if (Owner == Main.myPlayer) {
if (ProjectileID.Sets.IsAGolfBall[Type] && Damage <= 0) {
-@@ -8330,6 +_,11 @@
+@@ -8325,11 +_,23 @@
+
+ if (Type == 777 || Type == 781 || Type == 794 || Type == 797 || Type == 800 || Type == 785 || Type == 788 || Type == 791 || Type == 903 || Type == 904 || Type == 905 || Type == 906 || Type == 910 || Type == 911)
+ projectile.timeLeft = 180;
++
++ // Copied from 1.3, adjusted to check for actual player (servers never shoot thrower projectiles)
++ if (Main.netMode != NetmodeID.Server) {
++ Player throwingPlayer = Main.player[Owner];
++ if (throwingPlayer.AnyThrownCostReduction && throwingPlayer.HeldItem.CountsAsClass(DamageClass.Throwing))
++ projectile.noDropItem = true;
++ }
+ }
+
if (Type == 249)
projectile.frame = Main.rand.Next(5);
diff --git a/tModPorter/tModPorter.Tests/TestData/SimpleRenamedVanillaMembersTest.Expected.cs b/tModPorter/tModPorter.Tests/TestData/SimpleRenamedVanillaMembersTest.Expected.cs
index 644653badf6..eba7d730255 100644
--- a/tModPorter/tModPorter.Tests/TestData/SimpleRenamedVanillaMembersTest.Expected.cs
+++ b/tModPorter/tModPorter.Tests/TestData/SimpleRenamedVanillaMembersTest.Expected.cs
@@ -95,6 +95,9 @@ void Method() {
var hasBanner = Main.SceneMetrics.hasBanner;
var bannerBuff = Main.SceneMetrics.NPCBannerBuff;
var extraAccessorySlots = player.GetAmountOfExtraAccessorySlotsToShow();
+ var thrownCost33 = player.ThrownCost33;
+ var thrownCost50 = player.ThrownCost50;
+ var thrownVelocity = player.ThrownVelocity;
Main.PlayerRenderer.DrawPlayer(Main.Camera, player, Vector2.Zero, 0f, Vector2.Zero, 1f);
diff --git a/tModPorter/tModPorter.Tests/TestData/SimpleRenamedVanillaMembersTest.cs b/tModPorter/tModPorter.Tests/TestData/SimpleRenamedVanillaMembersTest.cs
index 049100b55f5..d3c27e8a36d 100644
--- a/tModPorter/tModPorter.Tests/TestData/SimpleRenamedVanillaMembersTest.cs
+++ b/tModPorter/tModPorter.Tests/TestData/SimpleRenamedVanillaMembersTest.cs
@@ -94,6 +94,9 @@ void Method() {
var hasBanner = player.hasBanner;
var bannerBuff = player.NPCBannerBuff;
var extraAccessorySlots = player.extraAccessorySlots;
+ var thrownCost33 = player.thrownCost33;
+ var thrownCost50 = player.thrownCost50;
+ var thrownVelocity = player.thrownVelocity;
Main.DrawPlayer(player, Vector2.Zero, 0f, Vector2.Zero, 1f);
diff --git a/tModPorter/tModPorter/Config.Terraria.cs b/tModPorter/tModPorter/Config.Terraria.cs
index eeb503151ef..aa6a307c30b 100644
--- a/tModPorter/tModPorter/Config.Terraria.cs
+++ b/tModPorter/tModPorter/Config.Terraria.cs
@@ -158,6 +158,9 @@ private static void AddTerrariaRefactors() {
RenameInstanceField("Terraria.Player", from: "doubleJumpSail", to: "hasJumpOption_Sail");
RenameInstanceField("Terraria.Player", from: "doubleJumpSandstorm",to: "hasJumpOption_Sandstorm");
RenameInstanceField("Terraria.Player", from: "doubleJumpUnicorn", to: "hasJumpOption_Unicorn");
+ RenameInstanceField("Terraria.Player", from: "thrownCost33", to: "ThrownCost33");
+ RenameInstanceField("Terraria.Player", from: "thrownCost50", to: "ThrownCost50");
+ RenameInstanceField("Terraria.Player", from: "thrownVelocity", to: "ThrownVelocity");
RenameMethod("Terraria.Item", from: "IsNotTheSameAs", to: "IsNotSameTypePrefixAndStack");
RenameMethod("Terraria.Lighting", from: "BlackOut", to: "Clear");