Finish set bonuses, add more options to the Avali Trader
@@ -0,0 +1,23 @@
|
|||||||
|
using Terraria;
|
||||||
|
using Terraria.DataStructures;
|
||||||
|
using Terraria.ModLoader;
|
||||||
|
using ForgottenWawiTech.Content.Projectiles.Protogen;
|
||||||
|
|
||||||
|
namespace ForgottenWawiTech.Content.GlobalProjectiles
|
||||||
|
{
|
||||||
|
public class ProtogenSentinelGlobalProjectile : GlobalProjectile
|
||||||
|
{
|
||||||
|
public bool DisableSentinelSplit { get; set; }
|
||||||
|
|
||||||
|
public override bool InstancePerEntity => true;
|
||||||
|
|
||||||
|
public override void OnSpawn(Projectile projectile, IEntitySource source)
|
||||||
|
{
|
||||||
|
if (projectile.type == ModContent.ProjectileType<ProtogenSentinelFragment>() ||
|
||||||
|
projectile.type == ModContent.ProjectileType<ProtogenSentinelCoreBeam>())
|
||||||
|
{
|
||||||
|
DisableSentinelSplit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ using ForgottenWawiTech.Content.Items.Materials;
|
|||||||
using ForgottenWawiTech.Content.Rarities;
|
using ForgottenWawiTech.Content.Rarities;
|
||||||
using ForgottenWawiTech.Content.Tiles.CraftingStations;
|
using ForgottenWawiTech.Content.Tiles.CraftingStations;
|
||||||
using ForgottenWawiTech.Content.Items.Armor.AvaliSkirmisherSet;
|
using ForgottenWawiTech.Content.Items.Armor.AvaliSkirmisherSet;
|
||||||
|
using ForgottenWawiTech.Content.Players;
|
||||||
|
|
||||||
namespace ForgottenWawiTech.Content.Items.Armor.AvaliVanguardSet
|
namespace ForgottenWawiTech.Content.Items.Armor.AvaliVanguardSet
|
||||||
{
|
{
|
||||||
@@ -44,7 +45,7 @@ namespace ForgottenWawiTech.Content.Items.Armor.AvaliVanguardSet
|
|||||||
}
|
}
|
||||||
|
|
||||||
player.endurance += 0.10f;
|
player.endurance += 0.10f;
|
||||||
// TODO: Implement hunting drone projectile system
|
player.GetModPlayer<AvaliVanguardPlayer>().EnableHuntingDrones();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AddRecipes()
|
public override void AddRecipes()
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using ForgottenWawiTech.Content.Items.Materials;
|
|||||||
using ForgottenWawiTech.Content.Rarities;
|
using ForgottenWawiTech.Content.Rarities;
|
||||||
using ForgottenWawiTech.Content.Tiles.CraftingStations;
|
using ForgottenWawiTech.Content.Tiles.CraftingStations;
|
||||||
using ForgottenWawiTech.Content.Items.Armor.AvaliSkirmisherSet;
|
using ForgottenWawiTech.Content.Items.Armor.AvaliSkirmisherSet;
|
||||||
|
using ForgottenWawiTech.Content.Players;
|
||||||
|
|
||||||
namespace ForgottenWawiTech.Content.Items.Armor.AvaliVanguardSet
|
namespace ForgottenWawiTech.Content.Items.Armor.AvaliVanguardSet
|
||||||
{
|
{
|
||||||
@@ -45,7 +46,7 @@ namespace ForgottenWawiTech.Content.Items.Armor.AvaliVanguardSet
|
|||||||
}
|
}
|
||||||
|
|
||||||
player.endurance += 0.10f;
|
player.endurance += 0.10f;
|
||||||
// TODO: Implement hunting drone projectile system
|
player.GetModPlayer<AvaliVanguardPlayer>().EnableHuntingDrones();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AddRecipes()
|
public override void AddRecipes()
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using ForgottenWawiTech.Content.Items.Materials;
|
|||||||
using ForgottenWawiTech.Content.Rarities;
|
using ForgottenWawiTech.Content.Rarities;
|
||||||
using ForgottenWawiTech.Content.Tiles.CraftingStations;
|
using ForgottenWawiTech.Content.Tiles.CraftingStations;
|
||||||
using ForgottenWawiTech.Content.Items.Armor.AvaliSkirmisherSet;
|
using ForgottenWawiTech.Content.Items.Armor.AvaliSkirmisherSet;
|
||||||
|
using ForgottenWawiTech.Content.Players;
|
||||||
|
|
||||||
namespace ForgottenWawiTech.Content.Items.Armor.AvaliVanguardSet
|
namespace ForgottenWawiTech.Content.Items.Armor.AvaliVanguardSet
|
||||||
{
|
{
|
||||||
@@ -45,7 +46,7 @@ namespace ForgottenWawiTech.Content.Items.Armor.AvaliVanguardSet
|
|||||||
}
|
}
|
||||||
|
|
||||||
player.endurance += 0.10f;
|
player.endurance += 0.10f;
|
||||||
// TODO: Implement hunting drone projectile system
|
player.GetModPlayer<AvaliVanguardPlayer>().EnableHuntingDrones();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AddRecipes()
|
public override void AddRecipes()
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using ForgottenWawiTech.Content.Items.Materials;
|
|||||||
using ForgottenWawiTech.Content.Rarities;
|
using ForgottenWawiTech.Content.Rarities;
|
||||||
using ForgottenWawiTech.Content.Tiles.CraftingStations;
|
using ForgottenWawiTech.Content.Tiles.CraftingStations;
|
||||||
using ForgottenWawiTech.Content.Items.Armor.AvaliSkirmisherSet;
|
using ForgottenWawiTech.Content.Items.Armor.AvaliSkirmisherSet;
|
||||||
|
using ForgottenWawiTech.Content.Players;
|
||||||
|
|
||||||
namespace ForgottenWawiTech.Content.Items.Armor.AvaliVanguardSet
|
namespace ForgottenWawiTech.Content.Items.Armor.AvaliVanguardSet
|
||||||
{
|
{
|
||||||
@@ -44,7 +45,7 @@ namespace ForgottenWawiTech.Content.Items.Armor.AvaliVanguardSet
|
|||||||
}
|
}
|
||||||
|
|
||||||
player.endurance += 0.10f;
|
player.endurance += 0.10f;
|
||||||
// TODO: Implement hunting drone projectile system
|
player.GetModPlayer<AvaliVanguardPlayer>().EnableHuntingDrones();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AddRecipes()
|
public override void AddRecipes()
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using Terraria.ModLoader;
|
|||||||
using ForgottenWawiTech.Content.Items.Materials;
|
using ForgottenWawiTech.Content.Items.Materials;
|
||||||
using ForgottenWawiTech.Content.Rarities;
|
using ForgottenWawiTech.Content.Rarities;
|
||||||
using ForgottenWawiTech.Content.Items.Armor.ProtogenInitiateSet;
|
using ForgottenWawiTech.Content.Items.Armor.ProtogenInitiateSet;
|
||||||
|
using ForgottenWawiTech.Content.Players;
|
||||||
|
|
||||||
namespace ForgottenWawiTech.Content.Items.Armor.ProtogenOperativeSet
|
namespace ForgottenWawiTech.Content.Items.Armor.ProtogenOperativeSet
|
||||||
{
|
{
|
||||||
@@ -37,7 +38,7 @@ namespace ForgottenWawiTech.Content.Items.Armor.ProtogenOperativeSet
|
|||||||
player.setBonus = "Taking damage releases seeking nanites\nNanites heal you for 50% of damage dealt\n+2 max minions and +18% summon damage";
|
player.setBonus = "Taking damage releases seeking nanites\nNanites heal you for 50% of damage dealt\n+2 max minions and +18% summon damage";
|
||||||
player.maxMinions += 2;
|
player.maxMinions += 2;
|
||||||
player.GetDamage(DamageClass.Summon) += 0.18f;
|
player.GetDamage(DamageClass.Summon) += 0.18f;
|
||||||
// TODO: Implement nanite swarm healing system
|
player.GetModPlayer<ProtogenOperativePlayer>().EnableNaniteSwarm();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AddRecipes()
|
public override void AddRecipes()
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using Terraria.ModLoader;
|
|||||||
using ForgottenWawiTech.Content.Items.Materials;
|
using ForgottenWawiTech.Content.Items.Materials;
|
||||||
using ForgottenWawiTech.Content.Rarities;
|
using ForgottenWawiTech.Content.Rarities;
|
||||||
using ForgottenWawiTech.Content.Items.Armor.ProtogenInitiateSet;
|
using ForgottenWawiTech.Content.Items.Armor.ProtogenInitiateSet;
|
||||||
|
using ForgottenWawiTech.Content.Players;
|
||||||
|
|
||||||
namespace ForgottenWawiTech.Content.Items.Armor.ProtogenOperativeSet
|
namespace ForgottenWawiTech.Content.Items.Armor.ProtogenOperativeSet
|
||||||
{
|
{
|
||||||
@@ -38,7 +39,7 @@ namespace ForgottenWawiTech.Content.Items.Armor.ProtogenOperativeSet
|
|||||||
player.setBonus = "Taking damage releases seeking nanites\nNanites heal you for 50% of damage dealt\n+12% melee damage and speed";
|
player.setBonus = "Taking damage releases seeking nanites\nNanites heal you for 50% of damage dealt\n+12% melee damage and speed";
|
||||||
player.GetDamage(DamageClass.Melee) += 0.12f;
|
player.GetDamage(DamageClass.Melee) += 0.12f;
|
||||||
player.GetAttackSpeed(DamageClass.Melee) += 0.12f;
|
player.GetAttackSpeed(DamageClass.Melee) += 0.12f;
|
||||||
// TODO: Implement nanite swarm healing system
|
player.GetModPlayer<ProtogenOperativePlayer>().EnableNaniteSwarm();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AddRecipes()
|
public override void AddRecipes()
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using Terraria.ModLoader;
|
|||||||
using ForgottenWawiTech.Content.Items.Materials;
|
using ForgottenWawiTech.Content.Items.Materials;
|
||||||
using ForgottenWawiTech.Content.Rarities;
|
using ForgottenWawiTech.Content.Rarities;
|
||||||
using ForgottenWawiTech.Content.Items.Armor.ProtogenInitiateSet;
|
using ForgottenWawiTech.Content.Items.Armor.ProtogenInitiateSet;
|
||||||
|
using ForgottenWawiTech.Content.Players;
|
||||||
|
|
||||||
namespace ForgottenWawiTech.Content.Items.Armor.ProtogenOperativeSet
|
namespace ForgottenWawiTech.Content.Items.Armor.ProtogenOperativeSet
|
||||||
{
|
{
|
||||||
@@ -37,7 +38,7 @@ namespace ForgottenWawiTech.Content.Items.Armor.ProtogenOperativeSet
|
|||||||
player.setBonus = "Taking damage releases seeking nanites\nNanites heal you for 50% of damage dealt\n+18% magic damage and -18% mana cost";
|
player.setBonus = "Taking damage releases seeking nanites\nNanites heal you for 50% of damage dealt\n+18% magic damage and -18% mana cost";
|
||||||
player.GetDamage(DamageClass.Magic) += 0.18f;
|
player.GetDamage(DamageClass.Magic) += 0.18f;
|
||||||
player.manaCost -= 0.18f;
|
player.manaCost -= 0.18f;
|
||||||
// TODO: Implement nanite swarm healing system
|
player.GetModPlayer<ProtogenOperativePlayer>().EnableNaniteSwarm();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AddRecipes()
|
public override void AddRecipes()
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using Terraria.ModLoader;
|
|||||||
using ForgottenWawiTech.Content.Items.Materials;
|
using ForgottenWawiTech.Content.Items.Materials;
|
||||||
using ForgottenWawiTech.Content.Rarities;
|
using ForgottenWawiTech.Content.Rarities;
|
||||||
using ForgottenWawiTech.Content.Items.Armor.ProtogenInitiateSet;
|
using ForgottenWawiTech.Content.Items.Armor.ProtogenInitiateSet;
|
||||||
|
using ForgottenWawiTech.Content.Players;
|
||||||
|
|
||||||
namespace ForgottenWawiTech.Content.Items.Armor.ProtogenOperativeSet
|
namespace ForgottenWawiTech.Content.Items.Armor.ProtogenOperativeSet
|
||||||
{
|
{
|
||||||
@@ -37,7 +38,7 @@ namespace ForgottenWawiTech.Content.Items.Armor.ProtogenOperativeSet
|
|||||||
player.setBonus = "Taking damage releases seeking nanites\nNanites heal you for 50% of damage dealt\n+15% ranged damage and critical strike chance";
|
player.setBonus = "Taking damage releases seeking nanites\nNanites heal you for 50% of damage dealt\n+15% ranged damage and critical strike chance";
|
||||||
player.GetDamage(DamageClass.Ranged) += 0.15f;
|
player.GetDamage(DamageClass.Ranged) += 0.15f;
|
||||||
player.GetCritChance(DamageClass.Ranged) += 15;
|
player.GetCritChance(DamageClass.Ranged) += 15;
|
||||||
// TODO: Implement nanite swarm healing system
|
player.GetModPlayer<ProtogenOperativePlayer>().EnableNaniteSwarm();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AddRecipes()
|
public override void AddRecipes()
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using ForgottenWawiTech.Content.Items.Materials;
|
|||||||
using ForgottenWawiTech.Content.Rarities;
|
using ForgottenWawiTech.Content.Rarities;
|
||||||
using ForgottenWawiTech.Content.Tiles.CraftingStations;
|
using ForgottenWawiTech.Content.Tiles.CraftingStations;
|
||||||
using ForgottenWawiTech.Content.Items.Armor.ProtogenOperativeSet;
|
using ForgottenWawiTech.Content.Items.Armor.ProtogenOperativeSet;
|
||||||
|
using ForgottenWawiTech.Content.Players;
|
||||||
|
|
||||||
namespace ForgottenWawiTech.Content.Items.Armor.ProtogenSentinelSet
|
namespace ForgottenWawiTech.Content.Items.Armor.ProtogenSentinelSet
|
||||||
{
|
{
|
||||||
@@ -47,7 +48,7 @@ namespace ForgottenWawiTech.Content.Items.Armor.ProtogenSentinelSet
|
|||||||
player.buffImmune[BuffID.Weak] = true;
|
player.buffImmune[BuffID.Weak] = true;
|
||||||
player.buffImmune[BuffID.Silenced] = true;
|
player.buffImmune[BuffID.Silenced] = true;
|
||||||
player.buffImmune[BuffID.Cursed] = true;
|
player.buffImmune[BuffID.Cursed] = true;
|
||||||
// TODO: Implement AI core projectile and splitting projectile system
|
player.GetModPlayer<ProtogenSentinelPlayer>().EnableSentinelCore();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AddRecipes()
|
public override void AddRecipes()
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using ForgottenWawiTech.Content.Items.Materials;
|
|||||||
using ForgottenWawiTech.Content.Rarities;
|
using ForgottenWawiTech.Content.Rarities;
|
||||||
using ForgottenWawiTech.Content.Tiles.CraftingStations;
|
using ForgottenWawiTech.Content.Tiles.CraftingStations;
|
||||||
using ForgottenWawiTech.Content.Items.Armor.ProtogenOperativeSet;
|
using ForgottenWawiTech.Content.Items.Armor.ProtogenOperativeSet;
|
||||||
|
using ForgottenWawiTech.Content.Players;
|
||||||
|
|
||||||
namespace ForgottenWawiTech.Content.Items.Armor.ProtogenSentinelSet
|
namespace ForgottenWawiTech.Content.Items.Armor.ProtogenSentinelSet
|
||||||
{
|
{
|
||||||
@@ -48,7 +49,7 @@ namespace ForgottenWawiTech.Content.Items.Armor.ProtogenSentinelSet
|
|||||||
player.buffImmune[BuffID.Weak] = true;
|
player.buffImmune[BuffID.Weak] = true;
|
||||||
player.buffImmune[BuffID.Silenced] = true;
|
player.buffImmune[BuffID.Silenced] = true;
|
||||||
player.buffImmune[BuffID.Cursed] = true;
|
player.buffImmune[BuffID.Cursed] = true;
|
||||||
// TODO: Implement AI core projectile and splitting projectile system
|
player.GetModPlayer<ProtogenSentinelPlayer>().EnableSentinelCore();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AddRecipes()
|
public override void AddRecipes()
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using ForgottenWawiTech.Content.Items.Materials;
|
|||||||
using ForgottenWawiTech.Content.Rarities;
|
using ForgottenWawiTech.Content.Rarities;
|
||||||
using ForgottenWawiTech.Content.Tiles.CraftingStations;
|
using ForgottenWawiTech.Content.Tiles.CraftingStations;
|
||||||
using ForgottenWawiTech.Content.Items.Armor.ProtogenOperativeSet;
|
using ForgottenWawiTech.Content.Items.Armor.ProtogenOperativeSet;
|
||||||
|
using ForgottenWawiTech.Content.Players;
|
||||||
|
|
||||||
namespace ForgottenWawiTech.Content.Items.Armor.ProtogenSentinelSet
|
namespace ForgottenWawiTech.Content.Items.Armor.ProtogenSentinelSet
|
||||||
{
|
{
|
||||||
@@ -47,7 +48,7 @@ namespace ForgottenWawiTech.Content.Items.Armor.ProtogenSentinelSet
|
|||||||
player.buffImmune[BuffID.Weak] = true;
|
player.buffImmune[BuffID.Weak] = true;
|
||||||
player.buffImmune[BuffID.Silenced] = true;
|
player.buffImmune[BuffID.Silenced] = true;
|
||||||
player.buffImmune[BuffID.Cursed] = true;
|
player.buffImmune[BuffID.Cursed] = true;
|
||||||
// TODO: Implement AI core projectile and splitting projectile system
|
player.GetModPlayer<ProtogenSentinelPlayer>().EnableSentinelCore();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AddRecipes()
|
public override void AddRecipes()
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using ForgottenWawiTech.Content.Items.Materials;
|
|||||||
using ForgottenWawiTech.Content.Rarities;
|
using ForgottenWawiTech.Content.Rarities;
|
||||||
using ForgottenWawiTech.Content.Tiles.CraftingStations;
|
using ForgottenWawiTech.Content.Tiles.CraftingStations;
|
||||||
using ForgottenWawiTech.Content.Items.Armor.ProtogenOperativeSet;
|
using ForgottenWawiTech.Content.Items.Armor.ProtogenOperativeSet;
|
||||||
|
using ForgottenWawiTech.Content.Players;
|
||||||
|
|
||||||
namespace ForgottenWawiTech.Content.Items.Armor.ProtogenSentinelSet
|
namespace ForgottenWawiTech.Content.Items.Armor.ProtogenSentinelSet
|
||||||
{
|
{
|
||||||
@@ -47,7 +48,7 @@ namespace ForgottenWawiTech.Content.Items.Armor.ProtogenSentinelSet
|
|||||||
player.buffImmune[BuffID.Weak] = true;
|
player.buffImmune[BuffID.Weak] = true;
|
||||||
player.buffImmune[BuffID.Silenced] = true;
|
player.buffImmune[BuffID.Silenced] = true;
|
||||||
player.buffImmune[BuffID.Cursed] = true;
|
player.buffImmune[BuffID.Cursed] = true;
|
||||||
// TODO: Implement AI core projectile and splitting projectile system
|
player.GetModPlayer<ProtogenSentinelPlayer>().EnableSentinelCore();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AddRecipes()
|
public override void AddRecipes()
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using Terraria.ModLoader;
|
|||||||
using ForgottenWawiTech.Content.Items.Materials;
|
using ForgottenWawiTech.Content.Items.Materials;
|
||||||
using ForgottenWawiTech.Content.Rarities;
|
using ForgottenWawiTech.Content.Rarities;
|
||||||
using ForgottenWawiTech.Content.Tiles.CraftingStations;
|
using ForgottenWawiTech.Content.Tiles.CraftingStations;
|
||||||
|
using ForgottenWawiTech.Content.Players;
|
||||||
|
|
||||||
namespace ForgottenWawiTech.Content.Items.Armor.SingularitySet
|
namespace ForgottenWawiTech.Content.Items.Armor.SingularitySet
|
||||||
{
|
{
|
||||||
@@ -40,9 +41,7 @@ namespace ForgottenWawiTech.Content.Items.Armor.SingularitySet
|
|||||||
player.GetCritChance(DamageClass.Generic) += 20;
|
player.GetCritChance(DamageClass.Generic) += 20;
|
||||||
player.endurance += 0.15f;
|
player.endurance += 0.15f;
|
||||||
player.waterWalk = true;
|
player.waterWalk = true;
|
||||||
|
player.GetModPlayer<SingularityPlayer>().EnableSingularityOrb();
|
||||||
// TODO: Implement singularity orb minion projectile
|
|
||||||
// For now, grant increased stats as placeholder
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AddRecipes()
|
public override void AddRecipes()
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ using System;
|
|||||||
using Terraria;
|
using Terraria;
|
||||||
using Terraria.ID;
|
using Terraria.ID;
|
||||||
using Terraria.ModLoader;
|
using Terraria.ModLoader;
|
||||||
|
using ForgottenWawiTech.Content.Players;
|
||||||
|
|
||||||
namespace ForgottenWawiTech.Content.Items.Armor.TranscendentSet
|
namespace ForgottenWawiTech.Content.Items.Armor.TranscendentSet
|
||||||
{
|
{
|
||||||
@@ -87,7 +88,9 @@ namespace ForgottenWawiTech.Content.Items.Armor.TranscendentSet
|
|||||||
player.buffImmune[buffId] = true;
|
player.buffImmune[buffId] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Implement Ascendant Swarm minions, sentinel beam volley, and nanite shard projectiles.
|
player.GetModPlayer<TranscendentPlayer>().EnableTranscendentSet();
|
||||||
|
player.GetModPlayer<ProtogenSentinelPlayer>().EnableSentinelCore();
|
||||||
|
player.GetModPlayer<SingularityPlayer>().EnableSingularityOrb();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,69 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
using Terraria;
|
using Terraria;
|
||||||
using Terraria.ID;
|
using Terraria.ID;
|
||||||
using Terraria.ModLoader;
|
using Terraria.ModLoader;
|
||||||
using Terraria.GameContent.Personalities;
|
using Terraria.GameContent.Personalities;
|
||||||
using Terraria.Localization;
|
using Terraria.Localization;
|
||||||
|
using ForgottenWawiTech;
|
||||||
|
|
||||||
namespace ForgottenWawiTech.Content.NPCs.TownNPCs
|
namespace ForgottenWawiTech.Content.NPCs.TownNPCs
|
||||||
{
|
{
|
||||||
public class AvalianTrader : ModNPC
|
public class AvalianTrader : ModNPC
|
||||||
{
|
{
|
||||||
|
private static readonly Condition HasDefeatedAnyMechBoss = new("Mods.ForgottenWawiTech.Conditions.HasDefeatedAnyMechBoss", () =>
|
||||||
|
NPC.downedMechBoss1 || NPC.downedMechBoss2 || NPC.downedMechBoss3);
|
||||||
|
|
||||||
|
private static readonly Condition HasDefeatedLexy = new("Mods.ForgottenWawiTech.Conditions.HasDefeatedLexy", () =>
|
||||||
|
Main.hardMode && WorldDefeatedBosses.Lexy);
|
||||||
|
|
||||||
|
private static readonly Condition HasDefeatedNiko = new("Mods.ForgottenWawiTech.Conditions.HasDefeatedNiko", () =>
|
||||||
|
Main.hardMode && WorldDefeatedBosses.Niko);
|
||||||
|
|
||||||
|
private static readonly Condition HasDefeatedNeptune = new("Mods.ForgottenWawiTech.Conditions.HasDefeatedNeptune", () =>
|
||||||
|
Main.hardMode && WorldDefeatedBosses.Neptune);
|
||||||
|
|
||||||
|
private static readonly Condition HasDefeatedLyyka = new("Mods.ForgottenWawiTech.Conditions.HasDefeatedLyyka", () =>
|
||||||
|
Main.hardMode && WorldDefeatedBosses.Lyyka);
|
||||||
|
|
||||||
|
private static readonly Condition HasDefeatedCorruptedSwarm = new("Mods.ForgottenWawiTech.Conditions.HasDefeatedCorruptedSwarm", () =>
|
||||||
|
Main.hardMode && WorldDefeatedBosses.Niko); // TODO: Replace with Corrupted Swarm flag once implemented.
|
||||||
|
|
||||||
|
private static readonly Condition HasDefeatedExoMechs = new("Mods.ForgottenWawiTech.Conditions.HasDefeatedExoMechs", CheckExoMechsDowned);
|
||||||
|
|
||||||
|
private static readonly Condition HasDefeatedMoonLord = new("Mods.ForgottenWawiTech.Conditions.HasDefeatedMoonLord", () =>
|
||||||
|
NPC.downedMoonlord);
|
||||||
|
|
||||||
|
private static bool CheckExoMechsDowned()
|
||||||
|
{
|
||||||
|
if (!ModLoader.TryGetMod("CalamityMod", out Mod calamityMod))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var calamityWorldType = calamityMod.Code?.GetType("CalamityMod.World.CalamityWorld");
|
||||||
|
if (calamityWorldType == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const BindingFlags flags = BindingFlags.Public | BindingFlags.Static;
|
||||||
|
|
||||||
|
var field = calamityWorldType.GetField("downedExoMechs", flags);
|
||||||
|
if (field?.GetValue(null) is bool fieldValue)
|
||||||
|
{
|
||||||
|
return fieldValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var property = calamityWorldType.GetProperty("downedExoMechs", flags);
|
||||||
|
if (property?.GetValue(null) is bool propertyValue)
|
||||||
|
{
|
||||||
|
return propertyValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public override void SetStaticDefaults()
|
public override void SetStaticDefaults()
|
||||||
{
|
{
|
||||||
Main.npcFrameCount[NPC.type] = 25; // The amount of frames the NPC has
|
Main.npcFrameCount[NPC.type] = 25; // The amount of frames the NPC has
|
||||||
@@ -92,48 +147,119 @@ namespace ForgottenWawiTech.Content.NPCs.TownNPCs
|
|||||||
|
|
||||||
public override void AddShops()
|
public override void AddShops()
|
||||||
{
|
{
|
||||||
|
Item rainbowBrick = new();
|
||||||
|
rainbowBrick.SetDefaults(ItemID.RainbowBrick);
|
||||||
|
rainbowBrick.value = Item.buyPrice(silver: 90);
|
||||||
|
|
||||||
new NPCShop(Type)
|
new NPCShop(Type)
|
||||||
.Add<Items.Materials.RGBass>(Condition.DownedMoonLord)
|
.Add<Items.Materials.VisorShard>(HasDefeatedLexy)
|
||||||
.Add<Items.Materials.VisorShard>(Condition.Hardmode)
|
.Add<Items.Materials.FallenAngelFeather>(HasDefeatedNiko)
|
||||||
.Add(ItemID.RainbowBrick, Condition.Hardmode) // TODO: Force Rainbow Brick to not have No Value.
|
.Add<Items.Materials.HalfEatenFish>(HasDefeatedNeptune)
|
||||||
|
.Add<Items.Materials.LyykaBossDrop>(HasDefeatedLyyka)
|
||||||
|
.Add<Items.Materials.UnstableMatter>(HasDefeatedCorruptedSwarm)
|
||||||
|
.Add(rainbowBrick, Condition.Hardmode)
|
||||||
.Add<Items.Materials.AvaliFeather>()
|
.Add<Items.Materials.AvaliFeather>()
|
||||||
|
.Add<Items.Materials.RGBAlloy>(HasDefeatedMoonLord)
|
||||||
|
.Add<Items.Materials.EnergyCore>(HasDefeatedAnyMechBoss)
|
||||||
|
.Add<Items.Materials.ContainmentUnit>(HasDefeatedExoMechs)
|
||||||
|
.Add<Items.Materials.ControlledSingularity>(HasDefeatedExoMechs)
|
||||||
|
.Add<Items.Materials.MiniSingularity>(HasDefeatedExoMechs)
|
||||||
|
.Add<Items.Materials.SingularityAlloy>(HasDefeatedExoMechs)
|
||||||
|
.Add<Items.Materials.RGBass>(HasDefeatedMoonLord)
|
||||||
.Register();
|
.Register();
|
||||||
}
|
}
|
||||||
public override string GetChat()
|
public override string GetChat()
|
||||||
{
|
{
|
||||||
switch (Main.rand.Next(15))
|
List<string> lines = new()
|
||||||
{
|
{
|
||||||
case 0:
|
"*avalian chirping*",
|
||||||
return "*avalian chirping*";
|
"Welcome! I've traveled far from Avalon to bring you the finest technology.",
|
||||||
case 1:
|
"My pack may be small, but I've traversed dimensions to get here.",
|
||||||
return "Welcome! I've traveled far from Avalon to bring you the finest technology.";
|
"*chirps excitedly* Oh, you're interested in our wares?",
|
||||||
case 2:
|
"RGBass - it's not just a material, it's a lifestyle.",
|
||||||
return "These feathers? They're not just for show - they're quite valuable!";
|
"Those rainbow bricks? Ninety silver each. I have transport costs, you know.",
|
||||||
case 3:
|
"The journey here was long, but your world has such fascinating resources!",
|
||||||
return "RGB technology is all the rage back home. Everything needs more colors!";
|
"Need something? My shop is always open!",
|
||||||
case 4:
|
"Avalian markets never sleep; neither does my inventory.",
|
||||||
return "The visor shards I sell are fragments from our most advanced equipment.";
|
"If you see a hover sled parked outside, please don't touch the controls.",
|
||||||
case 5:
|
"Try not to lick the stock. Some of it bites back.",
|
||||||
return "My pack may be small, but I've traversed dimensions to get here.";
|
"The atmosphere here is thick, but profits make it worth the acclimation.",
|
||||||
case 6:
|
"I keep a thermal blanket under the clothes —these nights get cold even for an Avali.",
|
||||||
return "*chirps excitedly* Oh, you're interested in our wares?";
|
"Do you have any idea how much customs paperwork interstellar trade requires?",
|
||||||
case 7:
|
"If you hear humming, that's just the containment field. Probably."
|
||||||
return "Avalon sends its regards! And its finest materials.";
|
};
|
||||||
case 8:
|
|
||||||
return "Don't underestimate the power of a well-crafted alloy.";
|
if (HasDefeatedLexy.IsMet())
|
||||||
case 9:
|
{
|
||||||
return "The journey here was long, but your world has such fascinating resources!";
|
lines.Add("Defeated Lexy, have you? His visor shards always sell out fast.");
|
||||||
case 10:
|
lines.Add("Lexy's visor tech makes for excellent souvenirs. Stock up while I have them.");
|
||||||
return "*preens feathers* Presentation is important in any trade.";
|
|
||||||
case 11:
|
|
||||||
return "RGBass - it's not just a material, it's a lifestyle.";
|
|
||||||
case 12:
|
|
||||||
return "I wonder what the other traders back on Avalon would think of this place...";
|
|
||||||
case 13:
|
|
||||||
return "My species may be small, but we're excellent engineers!";
|
|
||||||
default:
|
|
||||||
return "Need something? My shop is always open!";
|
|
||||||
}
|
}
|
||||||
|
else if (Main.hardMode)
|
||||||
|
{
|
||||||
|
lines.Add("Still hunting Lexy? Bring me his visor and I'll unlock some premium stock.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HasDefeatedNiko.IsMet())
|
||||||
|
{
|
||||||
|
lines.Add("Astramora's Fallen Angel Feathers? Delicate, pricey, worth every coin.");
|
||||||
|
lines.Add("I've reinforced the shipping crates just for Astramora's volatile feathers.");
|
||||||
|
}
|
||||||
|
else if (Main.hardMode)
|
||||||
|
{
|
||||||
|
lines.Add("I've heard whispers of a rat angel around these parts of the galaxy...");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HasDefeatedNeptune.IsMet())
|
||||||
|
{
|
||||||
|
lines.Add("Neptune leaves quite the mess. Half-eaten fish, anyone?");
|
||||||
|
lines.Add("Neptune's half-eaten catches sell faster than I'd like—apparently otter bites add flavor.");
|
||||||
|
}
|
||||||
|
else if (Main.hardMode)
|
||||||
|
{
|
||||||
|
lines.Add("If you're braving the tides, bring Neptune down and I'll import his catches.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HasDefeatedLyyka.IsMet())
|
||||||
|
{
|
||||||
|
lines.Add("Avalon sends its regards! Lyyka's gear is highly sought after.");
|
||||||
|
lines.Add("Lyyka's encore was explosive. Her gear? Even more so.");
|
||||||
|
}
|
||||||
|
else if (Main.hardMode)
|
||||||
|
{
|
||||||
|
lines.Add("Bring down Lyyka and I'll uncrate her signature alloys.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HasDefeatedCorruptedSwarm.IsMet())
|
||||||
|
{
|
||||||
|
lines.Add("Unstable Matter? Just delicate enough for my clientele.");
|
||||||
|
lines.Add("Careful with the Unstable Matter; Avalon still has a watchful eye on it.");
|
||||||
|
}
|
||||||
|
else if (Main.hardMode)
|
||||||
|
{
|
||||||
|
lines.Add("Rumor says there is a swarm of corrupted tech out there. If you defeat it, I might have something worth the risk.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HasDefeatedAnyMechBoss.IsMet())
|
||||||
|
{
|
||||||
|
lines.Add("Mechanical husks make great recycling. Fancy some RGB alloys?");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HasDefeatedMoonLord.IsMet())
|
||||||
|
{
|
||||||
|
lines.Add("Moon Lord down? Excellent. His trinkets pair nicely with Avalian engineering.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HasDefeatedExoMechs.IsMet())
|
||||||
|
{
|
||||||
|
lines.Add("The Exo Mechs are no more? Splendid! I've got singularities ready for purchase.");
|
||||||
|
lines.Add("You walked away from the Exo Mechs? Take these singularities before they destabilize.");
|
||||||
|
}
|
||||||
|
else if (ModLoader.TryGetMod("CalamityMod", out _))
|
||||||
|
{
|
||||||
|
lines.Add("Calamity's Exo Mechs still stalk your skies. Ground them and my singularity cache opens.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines.Count > 0 ? lines[Main.rand.Next(lines.Count)] : "Need something? My shop is always open!";
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void TownNPCAttackStrength(ref int damage, ref float knockback)
|
public override void TownNPCAttackStrength(ref int damage, ref float knockback)
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Terraria;
|
||||||
|
using Terraria.ModLoader;
|
||||||
|
using ForgottenWawiTech.Content.Projectiles.Avali;
|
||||||
|
|
||||||
|
namespace ForgottenWawiTech.Content.Players
|
||||||
|
{
|
||||||
|
public class AvaliVanguardPlayer : ModPlayer
|
||||||
|
{
|
||||||
|
private const int DroneCount = 3;
|
||||||
|
private const float SpawnRadius = 72f;
|
||||||
|
public bool HuntingDronesActive { get; private set; }
|
||||||
|
|
||||||
|
public static int GetDroneBaseDamage(Player player)
|
||||||
|
{
|
||||||
|
const int droneBaseDamage = 240;
|
||||||
|
return (int)player.GetTotalDamage(DamageClass.Summon).ApplyTo(droneBaseDamage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ResetEffects()
|
||||||
|
{
|
||||||
|
HuntingDronesActive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EnableHuntingDrones()
|
||||||
|
{
|
||||||
|
HuntingDronesActive = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PostUpdate()
|
||||||
|
{
|
||||||
|
if (!HuntingDronesActive || Player.whoAmI != Main.myPlayer)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int droneType = ModContent.ProjectileType<AvaliHuntingDrone>();
|
||||||
|
int owned = Player.ownedProjectileCounts[droneType];
|
||||||
|
if (owned >= DroneCount)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var source = Player.GetSource_Misc("AvaliVanguardSet");
|
||||||
|
for (int i = owned; i < DroneCount; i++)
|
||||||
|
{
|
||||||
|
float rotationOffset = MathHelper.TwoPi * i / DroneCount;
|
||||||
|
Vector2 spawnPos = Player.Center + rotationOffset.ToRotationVector2() * SpawnRadius;
|
||||||
|
Projectile projectile = Projectile.NewProjectileDirect(
|
||||||
|
source,
|
||||||
|
spawnPos,
|
||||||
|
Vector2.Zero,
|
||||||
|
droneType,
|
||||||
|
0,
|
||||||
|
0f,
|
||||||
|
Player.whoAmI,
|
||||||
|
i,
|
||||||
|
DroneCount);
|
||||||
|
projectile.originalDamage = GetDroneBaseDamage(Player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Terraria;
|
||||||
|
using Terraria.ModLoader;
|
||||||
|
using ForgottenWawiTech.Content.Projectiles.Protogen;
|
||||||
|
|
||||||
|
namespace ForgottenWawiTech.Content.Players
|
||||||
|
{
|
||||||
|
public class ProtogenOperativePlayer : ModPlayer
|
||||||
|
{
|
||||||
|
private const int NaniteProjectileCount = 3;
|
||||||
|
private const int NaniteCooldownTicks = 90;
|
||||||
|
private const int NaniteBaseDamage = 90;
|
||||||
|
private const float NaniteSpawnRadius = 30f;
|
||||||
|
|
||||||
|
private int naniteCooldownTimer;
|
||||||
|
|
||||||
|
public bool NaniteSwarmActive { get; private set; }
|
||||||
|
|
||||||
|
public override void ResetEffects()
|
||||||
|
{
|
||||||
|
NaniteSwarmActive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdateDead()
|
||||||
|
{
|
||||||
|
NaniteSwarmActive = false;
|
||||||
|
naniteCooldownTimer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PostUpdate()
|
||||||
|
{
|
||||||
|
if (naniteCooldownTimer > 0)
|
||||||
|
{
|
||||||
|
naniteCooldownTimer--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EnableNaniteSwarm()
|
||||||
|
{
|
||||||
|
NaniteSwarmActive = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnHurt(Player.HurtInfo info)
|
||||||
|
{
|
||||||
|
if (!NaniteSwarmActive || info.Damage <= 0 || naniteCooldownTimer > 0 || Player.whoAmI != Main.myPlayer)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
naniteCooldownTimer = NaniteCooldownTicks;
|
||||||
|
var source = Player.GetSource_Misc("ProtogenOperativeNanites");
|
||||||
|
int damage = (int)Player.GetTotalDamage(DamageClass.Generic).ApplyTo(NaniteBaseDamage);
|
||||||
|
|
||||||
|
for (int i = 0; i < NaniteProjectileCount; i++)
|
||||||
|
{
|
||||||
|
float angle = MathHelper.TwoPi * i / NaniteProjectileCount;
|
||||||
|
Vector2 spawnOffset = angle.ToRotationVector2() * NaniteSpawnRadius;
|
||||||
|
Vector2 spawnVelocity = spawnOffset.SafeNormalize(Vector2.UnitY) * 6f + Player.velocity;
|
||||||
|
|
||||||
|
Projectile.NewProjectile(
|
||||||
|
source,
|
||||||
|
Player.Center + spawnOffset,
|
||||||
|
spawnVelocity,
|
||||||
|
ModContent.ProjectileType<ProtogenOperativeNanite>(),
|
||||||
|
damage,
|
||||||
|
2f,
|
||||||
|
Player.whoAmI);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Terraria;
|
||||||
|
using Terraria.ModLoader;
|
||||||
|
using ForgottenWawiTech.Content.Projectiles.Protogen;
|
||||||
|
using ForgottenWawiTech.Content.GlobalProjectiles;
|
||||||
|
|
||||||
|
namespace ForgottenWawiTech.Content.Players
|
||||||
|
{
|
||||||
|
public class ProtogenSentinelPlayer : ModPlayer
|
||||||
|
{
|
||||||
|
private const int CoreProjectileCount = 1;
|
||||||
|
private const int CoreBaseDamage = 320;
|
||||||
|
private const float CoreSpawnOffset = -68f;
|
||||||
|
private const float FragmentSplitChance = 0.20f;
|
||||||
|
|
||||||
|
public bool SentinelCoreActive { get; private set; }
|
||||||
|
public bool SentinelProjectileSplitActive { get; private set; }
|
||||||
|
|
||||||
|
public override void ResetEffects()
|
||||||
|
{
|
||||||
|
SentinelCoreActive = false;
|
||||||
|
SentinelProjectileSplitActive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EnableSentinelCore()
|
||||||
|
{
|
||||||
|
SentinelCoreActive = true;
|
||||||
|
SentinelProjectileSplitActive = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PostUpdate()
|
||||||
|
{
|
||||||
|
if (!SentinelCoreActive)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Player.whoAmI != Main.myPlayer)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int coreType = ModContent.ProjectileType<ProtogenSentinelCore>();
|
||||||
|
if (Player.ownedProjectileCounts[coreType] >= CoreProjectileCount)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var source = Player.GetSource_Misc("ProtogenSentinelSet");
|
||||||
|
Vector2 spawnPos = Player.Center + new Vector2(0f, CoreSpawnOffset);
|
||||||
|
Projectile.NewProjectile(
|
||||||
|
source,
|
||||||
|
spawnPos,
|
||||||
|
Vector2.Zero,
|
||||||
|
coreType,
|
||||||
|
0,
|
||||||
|
0f,
|
||||||
|
Player.whoAmI);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetCoreDamage(Player player)
|
||||||
|
{
|
||||||
|
return (int)player.GetTotalDamage(DamageClass.Summon).ApplyTo(CoreBaseDamage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnHitNPCWithProj(Projectile proj, NPC target, NPC.HitInfo hit, int damageDone)
|
||||||
|
{
|
||||||
|
if (!SentinelProjectileSplitActive || Player.whoAmI != Main.myPlayer)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!proj.friendly || proj.owner != Player.whoAmI)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proj.GetGlobalProjectile<ProtogenSentinelGlobalProjectile>().DisableSentinelSplit)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proj.type == ModContent.ProjectileType<ProtogenSentinelCoreBeam>() || proj.type == ModContent.ProjectileType<ProtogenSentinelFragment>())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (damageDone <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Main.rand.NextFloat() > FragmentSplitChance)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SpawnFragments(proj, damageDone);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SpawnFragments(Projectile sourceProj, int damageDone)
|
||||||
|
{
|
||||||
|
int fragmentType = ModContent.ProjectileType<ProtogenSentinelFragment>();
|
||||||
|
int fragmentCount = 2;
|
||||||
|
int fragmentDamage = Math.Max(1, damageDone / 2);
|
||||||
|
var source = Player.GetSource_Misc("ProtogenSentinelSplit");
|
||||||
|
|
||||||
|
for (int i = 0; i < fragmentCount; i++)
|
||||||
|
{
|
||||||
|
float rotation = MathHelper.ToRadians(Main.rand.NextFloat(-18f, 18f));
|
||||||
|
Vector2 launch = sourceProj.velocity.SafeNormalize(Vector2.UnitY).RotatedBy(rotation) * 14f;
|
||||||
|
Projectile fragment = Projectile.NewProjectileDirect(
|
||||||
|
source,
|
||||||
|
sourceProj.Center,
|
||||||
|
launch,
|
||||||
|
fragmentType,
|
||||||
|
fragmentDamage,
|
||||||
|
2f,
|
||||||
|
Player.whoAmI);
|
||||||
|
fragment.GetGlobalProjectile<ProtogenSentinelGlobalProjectile>().DisableSentinelSplit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Terraria;
|
||||||
|
using Terraria.ModLoader;
|
||||||
|
using ForgottenWawiTech.Content.Projectiles.Singularity;
|
||||||
|
|
||||||
|
namespace ForgottenWawiTech.Content.Players
|
||||||
|
{
|
||||||
|
public class SingularityPlayer : ModPlayer
|
||||||
|
{
|
||||||
|
private const int OrbProjectileLimit = 1;
|
||||||
|
private const int OrbBaseDamage = 420;
|
||||||
|
private const float OrbSpawnOffset = -80f;
|
||||||
|
|
||||||
|
public bool SingularityOrbActive { get; private set; }
|
||||||
|
|
||||||
|
public override void ResetEffects()
|
||||||
|
{
|
||||||
|
SingularityOrbActive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EnableSingularityOrb()
|
||||||
|
{
|
||||||
|
SingularityOrbActive = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PostUpdate()
|
||||||
|
{
|
||||||
|
if (!SingularityOrbActive || Player.whoAmI != Main.myPlayer)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int orbType = ModContent.ProjectileType<SingularityOrb>();
|
||||||
|
if (Player.ownedProjectileCounts[orbType] >= OrbProjectileLimit)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var source = Player.GetSource_Misc("SingularitySet");
|
||||||
|
Vector2 spawnPos = Player.Center + new Vector2(0f, OrbSpawnOffset);
|
||||||
|
Projectile.NewProjectile(
|
||||||
|
source,
|
||||||
|
spawnPos,
|
||||||
|
Vector2.Zero,
|
||||||
|
orbType,
|
||||||
|
0,
|
||||||
|
0f,
|
||||||
|
Player.whoAmI);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetOrbDamage(Player player)
|
||||||
|
{
|
||||||
|
return (int)player.GetTotalDamage(DamageClass.Generic).ApplyTo(OrbBaseDamage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
|
using System;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Terraria;
|
using Terraria;
|
||||||
|
using Terraria.DataStructures;
|
||||||
using Terraria.ID;
|
using Terraria.ID;
|
||||||
using Terraria.ModLoader;
|
using Terraria.ModLoader;
|
||||||
using ForgottenWawiTech.Content.Projectiles.Transcendent;
|
using ForgottenWawiTech.Content.Projectiles.Transcendent;
|
||||||
@@ -8,60 +10,215 @@ namespace ForgottenWawiTech.Content.Players
|
|||||||
{
|
{
|
||||||
public class TranscendentPlayer : ModPlayer
|
public class TranscendentPlayer : ModPlayer
|
||||||
{
|
{
|
||||||
|
private const int AccessoryShardInterval = 90;
|
||||||
|
private const int SetShardInterval = 45;
|
||||||
|
private const int AccessoryShardBaseDamage = 220;
|
||||||
|
private const int SetShardBaseDamage = 320;
|
||||||
|
private const int AscendantDroneCount = 4;
|
||||||
|
private const int AscendantDroneBaseDamage = 360;
|
||||||
|
private const int NaniteShardBaseDamage = 260;
|
||||||
|
|
||||||
public bool SwarmModuleEquipped;
|
public bool SwarmModuleEquipped;
|
||||||
|
private Item swarmAccessorySourceItem;
|
||||||
private int swarmTimer;
|
private int swarmTimer;
|
||||||
|
private int naniteShardCooldown;
|
||||||
|
|
||||||
|
private bool transcendentSetActive;
|
||||||
|
|
||||||
public void HandleSwarmAccessory(Item sourceItem)
|
public void HandleSwarmAccessory(Item sourceItem)
|
||||||
{
|
{
|
||||||
SwarmModuleEquipped = true;
|
SwarmModuleEquipped = true;
|
||||||
|
swarmAccessorySourceItem = sourceItem;
|
||||||
if (Player.whoAmI != Main.myPlayer)
|
|
||||||
return;
|
|
||||||
|
|
||||||
swarmTimer++;
|
|
||||||
if (swarmTimer >= 90)
|
|
||||||
{
|
|
||||||
swarmTimer = 0;
|
|
||||||
|
|
||||||
int baseDamage = 220;
|
|
||||||
int damage = (int)Player.GetDamage(DamageClass.Summon).ApplyTo(baseDamage);
|
|
||||||
float knockBack = 3f;
|
|
||||||
Vector2 velocity = Main.rand.NextVector2Circular(6f, 6f);
|
|
||||||
if (velocity.LengthSquared() < 0.01f)
|
|
||||||
{
|
|
||||||
velocity = new Vector2(0f, -6f);
|
|
||||||
}
|
|
||||||
|
|
||||||
Projectile.NewProjectile(
|
|
||||||
Player.GetSource_Accessory(sourceItem),
|
|
||||||
Player.Center,
|
|
||||||
velocity,
|
|
||||||
ModContent.ProjectileType<TranscendentBladeShard>(),
|
|
||||||
damage,
|
|
||||||
knockBack,
|
|
||||||
Player.whoAmI);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void EnableTranscendentSet()
|
||||||
|
{
|
||||||
|
transcendentSetActive = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasTranscendentSet => transcendentSetActive;
|
||||||
|
|
||||||
public override void ResetEffects()
|
public override void ResetEffects()
|
||||||
{
|
{
|
||||||
SwarmModuleEquipped = false;
|
SwarmModuleEquipped = false;
|
||||||
|
transcendentSetActive = false;
|
||||||
|
swarmAccessorySourceItem = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PostUpdate()
|
public override void PostUpdate()
|
||||||
{
|
{
|
||||||
if (SwarmModuleEquipped)
|
bool swarmActive = SwarmModuleEquipped || transcendentSetActive;
|
||||||
|
|
||||||
|
if (swarmActive && Player.whoAmI == Main.myPlayer)
|
||||||
{
|
{
|
||||||
if (Main.rand.NextBool(6))
|
int interval = transcendentSetActive ? SetShardInterval : AccessoryShardInterval;
|
||||||
|
swarmTimer++;
|
||||||
|
if (swarmTimer >= interval)
|
||||||
{
|
{
|
||||||
Dust dust = Dust.NewDustDirect(Player.position, Player.width, Player.height, DustID.RainbowTorch, Player.velocity.X * 0.2f, Player.velocity.Y * 0.2f, 150, default, 1.1f);
|
swarmTimer = 0;
|
||||||
dust.noGravity = true;
|
SpawnAscendantShards(transcendentSetActive);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Player.whoAmI == Main.myPlayer && swarmTimer > 0)
|
else if (Player.whoAmI == Main.myPlayer && swarmTimer > 0)
|
||||||
{
|
{
|
||||||
swarmTimer = 0;
|
swarmTimer = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (naniteShardCooldown > 0)
|
||||||
|
{
|
||||||
|
naniteShardCooldown--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transcendentSetActive)
|
||||||
|
{
|
||||||
|
MaintainAscendantDrones();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (swarmActive)
|
||||||
|
{
|
||||||
|
if (Main.rand.NextBool(transcendentSetActive ? 4 : 6))
|
||||||
|
{
|
||||||
|
Dust dust = Dust.NewDustDirect(Player.position, Player.width, Player.height, DustID.RainbowTorch, Player.velocity.X * 0.2f, Player.velocity.Y * 0.2f, 150, default, 1.1f);
|
||||||
|
dust.noGravity = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SpawnAscendantShards(bool fromSet)
|
||||||
|
{
|
||||||
|
int baseDamage = fromSet ? SetShardBaseDamage : AccessoryShardBaseDamage;
|
||||||
|
int damage = (int)Player.GetDamage(DamageClass.Summon).ApplyTo(baseDamage);
|
||||||
|
float knockBack = fromSet ? 4f : 3f;
|
||||||
|
float speed = fromSet ? 8f : 6f;
|
||||||
|
int shardCount = fromSet ? 2 : 1;
|
||||||
|
|
||||||
|
if (!fromSet && swarmAccessorySourceItem == null)
|
||||||
|
{
|
||||||
|
swarmAccessorySourceItem = Player.HeldItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
IEntitySource source = fromSet
|
||||||
|
? Player.GetSource_Misc("TranscendentAscendantSwarm")
|
||||||
|
: Player.GetSource_Accessory(swarmAccessorySourceItem ?? Player.HeldItem);
|
||||||
|
|
||||||
|
for (int i = 0; i < shardCount; i++)
|
||||||
|
{
|
||||||
|
Vector2 velocity = Main.rand.NextVector2Circular(speed, speed);
|
||||||
|
if (velocity.LengthSquared() < 0.01f)
|
||||||
|
{
|
||||||
|
velocity = new Vector2(0f, -speed);
|
||||||
|
}
|
||||||
|
|
||||||
|
Projectile shard = Projectile.NewProjectileDirect(
|
||||||
|
source,
|
||||||
|
Player.Center,
|
||||||
|
velocity,
|
||||||
|
ModContent.ProjectileType<TranscendentBladeShard>(),
|
||||||
|
damage,
|
||||||
|
knockBack,
|
||||||
|
Player.whoAmI);
|
||||||
|
shard.originalDamage = damage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MaintainAscendantDrones()
|
||||||
|
{
|
||||||
|
if (Player.whoAmI != Main.myPlayer)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int droneType = ModContent.ProjectileType<TranscendentAscendantDrone>();
|
||||||
|
int owned = Player.ownedProjectileCounts[droneType];
|
||||||
|
if (owned >= AscendantDroneCount)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var source = Player.GetSource_Misc("TranscendentAscendantDrones");
|
||||||
|
for (int i = owned; i < AscendantDroneCount; i++)
|
||||||
|
{
|
||||||
|
Projectile.NewProjectile(
|
||||||
|
source,
|
||||||
|
Player.Center,
|
||||||
|
Vector2.Zero,
|
||||||
|
droneType,
|
||||||
|
0,
|
||||||
|
0f,
|
||||||
|
Player.whoAmI,
|
||||||
|
i,
|
||||||
|
AscendantDroneCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnHitNPC(NPC target, NPC.HitInfo hit, int damageDone)
|
||||||
|
{
|
||||||
|
TrySpawnNaniteShards(target.Center, damageDone);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnHitNPCWithProj(Projectile proj, NPC target, NPC.HitInfo hit, int damageDone)
|
||||||
|
{
|
||||||
|
if (proj.owner != Player.whoAmI || !proj.friendly)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proj.type == ModContent.ProjectileType<TranscendentNaniteShard>() ||
|
||||||
|
proj.type == ModContent.ProjectileType<TranscendentAscendantBolt>() ||
|
||||||
|
proj.type == ModContent.ProjectileType<TranscendentBladeShard>())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TrySpawnNaniteShards(target.Center, damageDone);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TrySpawnNaniteShards(Vector2 position, int damageDone)
|
||||||
|
{
|
||||||
|
if (!transcendentSetActive || Player.whoAmI != Main.myPlayer)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (damageDone <= 0 || naniteShardCooldown > 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
naniteShardCooldown = 8;
|
||||||
|
int baseDamage = GetNaniteShardDamage(Player);
|
||||||
|
int computed = Math.Max(baseDamage, damageDone / 2);
|
||||||
|
float speed = 13f;
|
||||||
|
var source = Player.GetSource_Misc("TranscendentNaniteShards");
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
Vector2 velocity = Main.rand.NextVector2CircularEdge(1f, 1f) * speed;
|
||||||
|
if (velocity.LengthSquared() < 0.01f)
|
||||||
|
{
|
||||||
|
velocity = new Vector2(0f, -speed);
|
||||||
|
}
|
||||||
|
|
||||||
|
Projectile shard = Projectile.NewProjectileDirect(
|
||||||
|
source,
|
||||||
|
position,
|
||||||
|
velocity,
|
||||||
|
ModContent.ProjectileType<TranscendentNaniteShard>(),
|
||||||
|
computed,
|
||||||
|
2f,
|
||||||
|
Player.whoAmI);
|
||||||
|
shard.originalDamage = computed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetAscendantDroneDamage(Player player)
|
||||||
|
{
|
||||||
|
return (int)player.GetTotalDamage(DamageClass.Summon).ApplyTo(AscendantDroneBaseDamage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetNaniteShardDamage(Player player)
|
||||||
|
{
|
||||||
|
return (int)player.GetTotalDamage(DamageClass.Generic).ApplyTo(NaniteShardBaseDamage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,126 @@
|
|||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Terraria;
|
||||||
|
using Terraria.Audio;
|
||||||
|
using Terraria.ID;
|
||||||
|
using Terraria.ModLoader;
|
||||||
|
using ForgottenWawiTech.Content.Players;
|
||||||
|
|
||||||
|
namespace ForgottenWawiTech.Content.Projectiles.Avali
|
||||||
|
{
|
||||||
|
public class AvaliHuntingDrone : ModProjectile
|
||||||
|
{
|
||||||
|
private const float OrbitSpeed = 0.045f;
|
||||||
|
private const float OrbitRadius = 96f;
|
||||||
|
private const int ShootCooldown = 28;
|
||||||
|
private const float TargetRange = 920f;
|
||||||
|
private const float ShotSpeed = 19.5f;
|
||||||
|
|
||||||
|
public override void SetStaticDefaults()
|
||||||
|
{
|
||||||
|
ProjectileID.Sets.MinionSacrificable[Type] = false;
|
||||||
|
ProjectileID.Sets.MinionTargettingFeature[Type] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetDefaults()
|
||||||
|
{
|
||||||
|
Projectile.width = 26;
|
||||||
|
Projectile.height = 26;
|
||||||
|
Projectile.friendly = false;
|
||||||
|
Projectile.minion = true;
|
||||||
|
Projectile.penetrate = -1;
|
||||||
|
Projectile.tileCollide = false;
|
||||||
|
Projectile.ignoreWater = true;
|
||||||
|
Projectile.DamageType = DamageClass.Summon;
|
||||||
|
Projectile.netImportant = true;
|
||||||
|
Projectile.timeLeft = 2;
|
||||||
|
Projectile.minionSlots = 0f;
|
||||||
|
Projectile.damage = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void AI()
|
||||||
|
{
|
||||||
|
Player owner = Main.player[Projectile.owner];
|
||||||
|
AvaliVanguardPlayer modPlayer = owner.GetModPlayer<AvaliVanguardPlayer>();
|
||||||
|
if (!owner.active || owner.dead || !modPlayer.HuntingDronesActive)
|
||||||
|
{
|
||||||
|
Projectile.Kill();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Projectile.timeLeft = 2;
|
||||||
|
|
||||||
|
float index = Projectile.ai[0];
|
||||||
|
float total = Projectile.ai[1];
|
||||||
|
if (total <= 0f)
|
||||||
|
{
|
||||||
|
total = 3f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float rotation = (Main.GameUpdateCount * OrbitSpeed) + index * MathHelper.TwoPi / total;
|
||||||
|
Vector2 offset = rotation.ToRotationVector2() * OrbitRadius;
|
||||||
|
Projectile.Center = owner.Center + offset;
|
||||||
|
Projectile.velocity = owner.velocity;
|
||||||
|
Projectile.rotation = (owner.Center - Projectile.Center).ToRotation() + MathHelper.PiOver2;
|
||||||
|
|
||||||
|
Lighting.AddLight(Projectile.Center, 0.35f, 0.6f, 1f);
|
||||||
|
|
||||||
|
if (Projectile.owner == Main.myPlayer)
|
||||||
|
{
|
||||||
|
Projectile.localAI[0]++;
|
||||||
|
if (Projectile.localAI[0] >= ShootCooldown)
|
||||||
|
{
|
||||||
|
Projectile.localAI[0] = 0f;
|
||||||
|
NPC target = AcquireTarget(owner, Projectile.Center, TargetRange);
|
||||||
|
if (target != null)
|
||||||
|
{
|
||||||
|
Vector2 velocity = (target.Center - Projectile.Center).SafeNormalize(Vector2.UnitY) * ShotSpeed;
|
||||||
|
int damage = AvaliVanguardPlayer.GetDroneBaseDamage(owner);
|
||||||
|
var source = Projectile.GetSource_FromAI();
|
||||||
|
Projectile.NewProjectile(
|
||||||
|
source,
|
||||||
|
Projectile.Center,
|
||||||
|
velocity,
|
||||||
|
ModContent.ProjectileType<AvaliHuntingDroneShot>(),
|
||||||
|
damage,
|
||||||
|
2f,
|
||||||
|
owner.whoAmI);
|
||||||
|
SoundEngine.PlaySound(SoundID.Item12 with { Volume = 0.6f }, Projectile.Center);
|
||||||
|
Projectile.netUpdate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static NPC AcquireTarget(Player owner, Vector2 center, float range)
|
||||||
|
{
|
||||||
|
if (owner.HasMinionAttackTargetNPC)
|
||||||
|
{
|
||||||
|
NPC target = Main.npc[owner.MinionAttackTargetNPC];
|
||||||
|
if (target.CanBeChasedBy())
|
||||||
|
{
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NPC closest = null;
|
||||||
|
float squaredRange = range * range;
|
||||||
|
for (int i = 0; i < Main.maxNPCs; i++)
|
||||||
|
{
|
||||||
|
NPC npc = Main.npc[i];
|
||||||
|
if (!npc.active || npc.friendly || npc.dontTakeDamage || npc.life <= 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float distance = Vector2.DistanceSquared(npc.Center, center);
|
||||||
|
if (distance <= squaredRange && Collision.CanHitLine(center, 0, 0, npc.Center, 0, 0))
|
||||||
|
{
|
||||||
|
squaredRange = distance;
|
||||||
|
closest = npc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return closest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 504 B |
@@ -0,0 +1,52 @@
|
|||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Terraria;
|
||||||
|
using Terraria.Audio;
|
||||||
|
using Terraria.ID;
|
||||||
|
using Terraria.ModLoader;
|
||||||
|
|
||||||
|
namespace ForgottenWawiTech.Content.Projectiles.Avali
|
||||||
|
{
|
||||||
|
public class AvaliHuntingDroneShot : ModProjectile
|
||||||
|
{
|
||||||
|
public override void SetStaticDefaults()
|
||||||
|
{
|
||||||
|
ProjectileID.Sets.MinionShot[Type] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetDefaults()
|
||||||
|
{
|
||||||
|
Projectile.width = 12;
|
||||||
|
Projectile.height = 12;
|
||||||
|
Projectile.friendly = true;
|
||||||
|
Projectile.timeLeft = 120;
|
||||||
|
Projectile.penetrate = 1;
|
||||||
|
Projectile.tileCollide = false;
|
||||||
|
Projectile.ignoreWater = true;
|
||||||
|
Projectile.DamageType = DamageClass.Summon;
|
||||||
|
Projectile.usesLocalNPCImmunity = true;
|
||||||
|
Projectile.localNPCHitCooldown = 10;
|
||||||
|
Projectile.extraUpdates = 1;
|
||||||
|
Projectile.alpha = 40;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void AI()
|
||||||
|
{
|
||||||
|
Projectile.rotation = Projectile.velocity.ToRotation();
|
||||||
|
Lighting.AddLight(Projectile.Center, 0.4f, 0.7f, 1.2f);
|
||||||
|
|
||||||
|
if (Main.rand.NextBool(3))
|
||||||
|
{
|
||||||
|
Dust dust = Dust.NewDustDirect(Projectile.position, Projectile.width, Projectile.height, DustID.Electric, 0f, 0f, 120, default, 1.1f);
|
||||||
|
dust.noGravity = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnHitNPC(NPC target, NPC.HitInfo hit, int damageDone)
|
||||||
|
{
|
||||||
|
if (Main.myPlayer == Projectile.owner)
|
||||||
|
{
|
||||||
|
SoundEngine.PlaySound(SoundID.Item93 with { Volume = 0.4f }, Projectile.Center);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 504 B |
@@ -0,0 +1,115 @@
|
|||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Terraria;
|
||||||
|
using Terraria.ID;
|
||||||
|
using Terraria.ModLoader;
|
||||||
|
|
||||||
|
namespace ForgottenWawiTech.Content.Projectiles.Protogen
|
||||||
|
{
|
||||||
|
public class ProtogenOperativeNanite : ModProjectile
|
||||||
|
{
|
||||||
|
private const float DetectionRange = 640f;
|
||||||
|
private const float HomingStrength = 0.14f;
|
||||||
|
private const float DesiredSpeed = 14f;
|
||||||
|
|
||||||
|
public override void SetStaticDefaults()
|
||||||
|
{
|
||||||
|
ProjectileID.Sets.MinionShot[Type] = true;
|
||||||
|
ProjectileID.Sets.MinionSacrificable[Type] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetDefaults()
|
||||||
|
{
|
||||||
|
Projectile.width = 14;
|
||||||
|
Projectile.height = 14;
|
||||||
|
Projectile.friendly = true;
|
||||||
|
Projectile.penetrate = 1;
|
||||||
|
Projectile.timeLeft = 360;
|
||||||
|
Projectile.tileCollide = false;
|
||||||
|
Projectile.ignoreWater = true;
|
||||||
|
Projectile.DamageType = DamageClass.Generic;
|
||||||
|
Projectile.usesLocalNPCImmunity = true;
|
||||||
|
Projectile.localNPCHitCooldown = 20;
|
||||||
|
Projectile.extraUpdates = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void AI()
|
||||||
|
{
|
||||||
|
Player owner = Main.player[Projectile.owner];
|
||||||
|
if (!owner.active || owner.dead)
|
||||||
|
{
|
||||||
|
Projectile.Kill();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Projectile.rotation += 0.2f * Projectile.direction;
|
||||||
|
Lighting.AddLight(Projectile.Center, 0.25f, 0.55f, 0.75f);
|
||||||
|
|
||||||
|
NPC target = AcquireTarget(owner, Projectile.Center, DetectionRange);
|
||||||
|
if (target != null)
|
||||||
|
{
|
||||||
|
Vector2 desiredVelocity = (target.Center - Projectile.Center).SafeNormalize(Vector2.Zero) * DesiredSpeed;
|
||||||
|
Projectile.velocity = Vector2.Lerp(Projectile.velocity, desiredVelocity, HomingStrength);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Projectile.velocity *= 0.98f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Main.rand.NextBool(4))
|
||||||
|
{
|
||||||
|
Dust dust = Dust.NewDustDirect(Projectile.position, Projectile.width, Projectile.height, DustID.Electric, 0f, 0f, 100, default, 1.1f);
|
||||||
|
dust.noGravity = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnHitNPC(NPC target, NPC.HitInfo hit, int damageDone)
|
||||||
|
{
|
||||||
|
if (Main.myPlayer != Projectile.owner)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player owner = Main.player[Projectile.owner];
|
||||||
|
int healAmount = (int)(damageDone * 0.5f);
|
||||||
|
if (healAmount <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
owner.statLife = Utils.Clamp(owner.statLife + healAmount, 0, owner.statLifeMax2);
|
||||||
|
owner.HealEffect(healAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static NPC AcquireTarget(Player owner, Vector2 center, float range)
|
||||||
|
{
|
||||||
|
if (owner.HasMinionAttackTargetNPC)
|
||||||
|
{
|
||||||
|
NPC target = Main.npc[owner.MinionAttackTargetNPC];
|
||||||
|
if (target.CanBeChasedBy())
|
||||||
|
{
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NPC closest = null;
|
||||||
|
float squaredRange = range * range;
|
||||||
|
for (int i = 0; i < Main.maxNPCs; i++)
|
||||||
|
{
|
||||||
|
NPC npc = Main.npc[i];
|
||||||
|
if (!npc.active || npc.friendly || npc.dontTakeDamage || npc.life <= 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float distance = Vector2.DistanceSquared(npc.Center, center);
|
||||||
|
if (distance <= squaredRange && Collision.CanHitLine(center, 0, 0, npc.Center, 0, 0))
|
||||||
|
{
|
||||||
|
squaredRange = distance;
|
||||||
|
closest = npc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return closest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 504 B |
@@ -0,0 +1,124 @@
|
|||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Terraria;
|
||||||
|
using Terraria.Audio;
|
||||||
|
using Terraria.ID;
|
||||||
|
using Terraria.ModLoader;
|
||||||
|
using ForgottenWawiTech.Content.Players;
|
||||||
|
using ForgottenWawiTech.Content.GlobalProjectiles;
|
||||||
|
|
||||||
|
namespace ForgottenWawiTech.Content.Projectiles.Protogen
|
||||||
|
{
|
||||||
|
public class ProtogenSentinelCore : ModProjectile
|
||||||
|
{
|
||||||
|
private const float HoverRadius = 70f;
|
||||||
|
private const float HoverSpeed = 0.035f;
|
||||||
|
private const int FireCooldown = 32;
|
||||||
|
private const float TargetRange = 950f;
|
||||||
|
private const float BeamVelocity = 18f;
|
||||||
|
|
||||||
|
public override void SetStaticDefaults()
|
||||||
|
{
|
||||||
|
ProjectileID.Sets.MinionSacrificable[Type] = false;
|
||||||
|
ProjectileID.Sets.MinionTargettingFeature[Type] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetDefaults()
|
||||||
|
{
|
||||||
|
Projectile.width = 36;
|
||||||
|
Projectile.height = 36;
|
||||||
|
Projectile.friendly = false;
|
||||||
|
Projectile.minion = true;
|
||||||
|
Projectile.tileCollide = false;
|
||||||
|
Projectile.ignoreWater = true;
|
||||||
|
Projectile.penetrate = -1;
|
||||||
|
Projectile.netImportant = true;
|
||||||
|
Projectile.timeLeft = 2;
|
||||||
|
Projectile.damage = 0;
|
||||||
|
Projectile.minionSlots = 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void AI()
|
||||||
|
{
|
||||||
|
Player owner = Main.player[Projectile.owner];
|
||||||
|
ProtogenSentinelPlayer modPlayer = owner.GetModPlayer<ProtogenSentinelPlayer>();
|
||||||
|
if (!owner.active || owner.dead || !modPlayer.SentinelCoreActive)
|
||||||
|
{
|
||||||
|
Projectile.Kill();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Projectile.timeLeft = 2;
|
||||||
|
|
||||||
|
float rotation = ((float)Main.GameUpdateCount * HoverSpeed) % MathHelper.TwoPi;
|
||||||
|
Vector2 desiredOffset = new Vector2(0f, -HoverRadius).RotatedBy(rotation);
|
||||||
|
Vector2 desiredPosition = owner.Center + desiredOffset;
|
||||||
|
Projectile.Center = Vector2.Lerp(Projectile.Center, desiredPosition, 0.2f);
|
||||||
|
Projectile.velocity = owner.velocity;
|
||||||
|
|
||||||
|
Lighting.AddLight(Projectile.Center, 0.2f, 0.6f, 0.9f);
|
||||||
|
|
||||||
|
if (Projectile.owner == Main.myPlayer)
|
||||||
|
{
|
||||||
|
Projectile.localAI[0]++;
|
||||||
|
if (Projectile.localAI[0] >= FireCooldown)
|
||||||
|
{
|
||||||
|
Projectile.localAI[0] = 0f;
|
||||||
|
NPC target = AcquireTarget(owner, Projectile.Center, TargetRange);
|
||||||
|
if (target != null)
|
||||||
|
{
|
||||||
|
FireBeam(owner, target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FireBeam(Player owner, NPC target)
|
||||||
|
{
|
||||||
|
Vector2 velocity = (target.Center - Projectile.Center).SafeNormalize(Vector2.UnitY) * BeamVelocity;
|
||||||
|
int damage = ProtogenSentinelPlayer.GetCoreDamage(owner);
|
||||||
|
var source = Projectile.GetSource_FromThis();
|
||||||
|
Projectile beam = Projectile.NewProjectileDirect(
|
||||||
|
source,
|
||||||
|
Projectile.Center,
|
||||||
|
velocity,
|
||||||
|
ModContent.ProjectileType<ProtogenSentinelCoreBeam>(),
|
||||||
|
damage,
|
||||||
|
3f,
|
||||||
|
owner.whoAmI);
|
||||||
|
beam.GetGlobalProjectile<ProtogenSentinelGlobalProjectile>().DisableSentinelSplit = true;
|
||||||
|
SoundEngine.PlaySound(SoundID.Item33 with { Volume = 0.7f, Pitch = 0.15f }, Projectile.Center);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static NPC AcquireTarget(Player owner, Vector2 center, float range)
|
||||||
|
{
|
||||||
|
if (owner.HasMinionAttackTargetNPC)
|
||||||
|
{
|
||||||
|
NPC target = Main.npc[owner.MinionAttackTargetNPC];
|
||||||
|
if (target.CanBeChasedBy())
|
||||||
|
{
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NPC closest = null;
|
||||||
|
float squaredRange = range * range;
|
||||||
|
for (int i = 0; i < Main.maxNPCs; i++)
|
||||||
|
{
|
||||||
|
NPC npc = Main.npc[i];
|
||||||
|
if (!npc.active || npc.friendly || npc.dontTakeDamage || npc.life <= 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float distance = Vector2.DistanceSquared(npc.Center, center);
|
||||||
|
if (distance <= squaredRange && Collision.CanHitLine(center, 0, 0, npc.Center, 0, 0))
|
||||||
|
{
|
||||||
|
squaredRange = distance;
|
||||||
|
closest = npc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return closest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 504 B |
@@ -0,0 +1,50 @@
|
|||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Terraria;
|
||||||
|
using Terraria.DataStructures;
|
||||||
|
using Terraria.ID;
|
||||||
|
using Terraria.ModLoader;
|
||||||
|
using ForgottenWawiTech.Content.GlobalProjectiles;
|
||||||
|
|
||||||
|
namespace ForgottenWawiTech.Content.Projectiles.Protogen
|
||||||
|
{
|
||||||
|
public class ProtogenSentinelCoreBeam : ModProjectile
|
||||||
|
{
|
||||||
|
public override void SetStaticDefaults()
|
||||||
|
{
|
||||||
|
ProjectileID.Sets.MinionShot[Type] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetDefaults()
|
||||||
|
{
|
||||||
|
Projectile.width = 18;
|
||||||
|
Projectile.height = 18;
|
||||||
|
Projectile.friendly = true;
|
||||||
|
Projectile.timeLeft = 120;
|
||||||
|
Projectile.penetrate = 2;
|
||||||
|
Projectile.tileCollide = false;
|
||||||
|
Projectile.ignoreWater = true;
|
||||||
|
Projectile.DamageType = DamageClass.Summon;
|
||||||
|
Projectile.extraUpdates = 1;
|
||||||
|
Projectile.usesLocalNPCImmunity = true;
|
||||||
|
Projectile.localNPCHitCooldown = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void AI()
|
||||||
|
{
|
||||||
|
Projectile.rotation = Projectile.velocity.ToRotation();
|
||||||
|
Lighting.AddLight(Projectile.Center, 0.35f, 0.9f, 1.2f);
|
||||||
|
|
||||||
|
if (Main.rand.NextBool(3))
|
||||||
|
{
|
||||||
|
Dust dust = Dust.NewDustDirect(Projectile.position, Projectile.width, Projectile.height, DustID.BlueCrystalShard, 0f, 0f, 150, default, 1.1f);
|
||||||
|
dust.noGravity = true;
|
||||||
|
dust.velocity = Projectile.velocity * 0.2f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnSpawn(IEntitySource source)
|
||||||
|
{
|
||||||
|
Projectile.GetGlobalProjectile<ProtogenSentinelGlobalProjectile>().DisableSentinelSplit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 504 B |
@@ -0,0 +1,87 @@
|
|||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Terraria;
|
||||||
|
using Terraria.DataStructures;
|
||||||
|
using Terraria.ID;
|
||||||
|
using Terraria.ModLoader;
|
||||||
|
using ForgottenWawiTech.Content.GlobalProjectiles;
|
||||||
|
|
||||||
|
namespace ForgottenWawiTech.Content.Projectiles.Protogen
|
||||||
|
{
|
||||||
|
public class ProtogenSentinelFragment : ModProjectile
|
||||||
|
{
|
||||||
|
private const float HomingRange = 560f;
|
||||||
|
private const float HomingStrength = 0.18f;
|
||||||
|
private const float DesiredSpeed = 15f;
|
||||||
|
|
||||||
|
public override void SetStaticDefaults()
|
||||||
|
{
|
||||||
|
ProjectileID.Sets.MinionShot[Type] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetDefaults()
|
||||||
|
{
|
||||||
|
Projectile.width = 14;
|
||||||
|
Projectile.height = 14;
|
||||||
|
Projectile.friendly = true;
|
||||||
|
Projectile.penetrate = 1;
|
||||||
|
Projectile.timeLeft = 240;
|
||||||
|
Projectile.tileCollide = false;
|
||||||
|
Projectile.ignoreWater = true;
|
||||||
|
Projectile.DamageType = DamageClass.Generic;
|
||||||
|
Projectile.extraUpdates = 1;
|
||||||
|
Projectile.usesLocalNPCImmunity = true;
|
||||||
|
Projectile.localNPCHitCooldown = 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void AI()
|
||||||
|
{
|
||||||
|
Projectile.rotation = Projectile.velocity.ToRotation();
|
||||||
|
Lighting.AddLight(Projectile.Center, 0.3f, 0.8f, 1.15f);
|
||||||
|
|
||||||
|
NPC target = AcquireTarget(Projectile.Center, HomingRange);
|
||||||
|
if (target != null)
|
||||||
|
{
|
||||||
|
Vector2 desiredVelocity = (target.Center - Projectile.Center).SafeNormalize(Vector2.Zero) * DesiredSpeed;
|
||||||
|
Projectile.velocity = Vector2.Lerp(Projectile.velocity, desiredVelocity, HomingStrength);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Projectile.velocity *= 0.99f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Main.rand.NextBool(4))
|
||||||
|
{
|
||||||
|
Dust dust = Dust.NewDustDirect(Projectile.position, Projectile.width, Projectile.height, DustID.Electric, 0f, 0f, 120, default, 1.05f);
|
||||||
|
dust.noGravity = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnSpawn(IEntitySource source)
|
||||||
|
{
|
||||||
|
Projectile.GetGlobalProjectile<ProtogenSentinelGlobalProjectile>().DisableSentinelSplit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static NPC AcquireTarget(Vector2 center, float range)
|
||||||
|
{
|
||||||
|
NPC closest = null;
|
||||||
|
float squaredRange = range * range;
|
||||||
|
for (int i = 0; i < Main.maxNPCs; i++)
|
||||||
|
{
|
||||||
|
NPC npc = Main.npc[i];
|
||||||
|
if (!npc.active || npc.friendly || npc.dontTakeDamage || npc.life <= 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float distance = Vector2.DistanceSquared(npc.Center, center);
|
||||||
|
if (distance <= squaredRange && Collision.CanHitLine(center, 0, 0, npc.Center, 0, 0))
|
||||||
|
{
|
||||||
|
squaredRange = distance;
|
||||||
|
closest = npc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return closest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 504 B |
@@ -0,0 +1,123 @@
|
|||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Terraria;
|
||||||
|
using Terraria.Audio;
|
||||||
|
using Terraria.ID;
|
||||||
|
using Terraria.ModLoader;
|
||||||
|
using ForgottenWawiTech.Content.Players;
|
||||||
|
|
||||||
|
namespace ForgottenWawiTech.Content.Projectiles.Singularity
|
||||||
|
{
|
||||||
|
public class SingularityOrb : ModProjectile
|
||||||
|
{
|
||||||
|
private const float OrbitRadius = 90f;
|
||||||
|
private const float OrbitSpeed = 0.04f;
|
||||||
|
private const int FireCooldown = 22;
|
||||||
|
private const float TargetRange = 1000f;
|
||||||
|
private const float BeamSpeed = 21f;
|
||||||
|
|
||||||
|
public override void SetStaticDefaults()
|
||||||
|
{
|
||||||
|
ProjectileID.Sets.MinionSacrificable[Type] = false;
|
||||||
|
ProjectileID.Sets.MinionTargettingFeature[Type] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetDefaults()
|
||||||
|
{
|
||||||
|
Projectile.width = 32;
|
||||||
|
Projectile.height = 32;
|
||||||
|
Projectile.friendly = false;
|
||||||
|
Projectile.minion = true;
|
||||||
|
Projectile.DamageType = DamageClass.Generic;
|
||||||
|
Projectile.penetrate = -1;
|
||||||
|
Projectile.tileCollide = false;
|
||||||
|
Projectile.ignoreWater = true;
|
||||||
|
Projectile.netImportant = true;
|
||||||
|
Projectile.timeLeft = 2;
|
||||||
|
Projectile.minionSlots = 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void AI()
|
||||||
|
{
|
||||||
|
Player owner = Main.player[Projectile.owner];
|
||||||
|
SingularityPlayer modPlayer = owner.GetModPlayer<SingularityPlayer>();
|
||||||
|
if (!owner.active || owner.dead || !modPlayer.SingularityOrbActive)
|
||||||
|
{
|
||||||
|
Projectile.Kill();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Projectile.timeLeft = 2;
|
||||||
|
|
||||||
|
float rotation = ((float)Main.GameUpdateCount * OrbitSpeed) + Projectile.identity * 0.2f;
|
||||||
|
Vector2 offset = new Vector2(0f, -OrbitRadius).RotatedBy(rotation);
|
||||||
|
Vector2 desiredPos = owner.Center + offset;
|
||||||
|
Projectile.Center = Vector2.Lerp(Projectile.Center, desiredPos, 0.28f);
|
||||||
|
Projectile.velocity = owner.velocity;
|
||||||
|
Projectile.rotation += 0.03f * Projectile.direction;
|
||||||
|
|
||||||
|
Lighting.AddLight(Projectile.Center, 0.55f, 0.2f, 0.65f);
|
||||||
|
|
||||||
|
if (Projectile.owner == Main.myPlayer)
|
||||||
|
{
|
||||||
|
Projectile.localAI[0]++;
|
||||||
|
if (Projectile.localAI[0] >= FireCooldown)
|
||||||
|
{
|
||||||
|
Projectile.localAI[0] = 0f;
|
||||||
|
NPC target = AcquireTarget(owner, Projectile.Center, TargetRange);
|
||||||
|
if (target != null)
|
||||||
|
{
|
||||||
|
FireBeam(owner, target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FireBeam(Player owner, NPC target)
|
||||||
|
{
|
||||||
|
Vector2 velocity = (target.Center - Projectile.Center).SafeNormalize(Vector2.UnitY) * BeamSpeed;
|
||||||
|
int damage = SingularityPlayer.GetOrbDamage(owner);
|
||||||
|
var source = Projectile.GetSource_FromThis();
|
||||||
|
Projectile.NewProjectile(
|
||||||
|
source,
|
||||||
|
Projectile.Center,
|
||||||
|
velocity,
|
||||||
|
ModContent.ProjectileType<SingularityOrbBeam>(),
|
||||||
|
damage,
|
||||||
|
2f,
|
||||||
|
owner.whoAmI);
|
||||||
|
SoundEngine.PlaySound(SoundID.Item91 with { Volume = 0.7f, Pitch = 0.35f }, Projectile.Center);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static NPC AcquireTarget(Player owner, Vector2 center, float range)
|
||||||
|
{
|
||||||
|
if (owner.HasMinionAttackTargetNPC)
|
||||||
|
{
|
||||||
|
NPC forced = Main.npc[owner.MinionAttackTargetNPC];
|
||||||
|
if (forced.CanBeChasedBy())
|
||||||
|
{
|
||||||
|
return forced;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NPC closest = null;
|
||||||
|
float sqrRange = range * range;
|
||||||
|
for (int i = 0; i < Main.maxNPCs; i++)
|
||||||
|
{
|
||||||
|
NPC npc = Main.npc[i];
|
||||||
|
if (!npc.active || npc.friendly || npc.dontTakeDamage || npc.life <= 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float dist = Vector2.DistanceSquared(npc.Center, center);
|
||||||
|
if (dist <= sqrRange && Collision.CanHitLine(center, 0, 0, npc.Center, 0, 0))
|
||||||
|
{
|
||||||
|
sqrRange = dist;
|
||||||
|
closest = npc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return closest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 504 B |
@@ -0,0 +1,42 @@
|
|||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Terraria;
|
||||||
|
using Terraria.ID;
|
||||||
|
using Terraria.ModLoader;
|
||||||
|
|
||||||
|
namespace ForgottenWawiTech.Content.Projectiles.Singularity
|
||||||
|
{
|
||||||
|
public class SingularityOrbBeam : ModProjectile
|
||||||
|
{
|
||||||
|
public override void SetStaticDefaults()
|
||||||
|
{
|
||||||
|
ProjectileID.Sets.MinionShot[Type] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetDefaults()
|
||||||
|
{
|
||||||
|
Projectile.width = 16;
|
||||||
|
Projectile.height = 16;
|
||||||
|
Projectile.friendly = true;
|
||||||
|
Projectile.timeLeft = 120;
|
||||||
|
Projectile.penetrate = 3;
|
||||||
|
Projectile.tileCollide = false;
|
||||||
|
Projectile.ignoreWater = true;
|
||||||
|
Projectile.DamageType = DamageClass.Generic;
|
||||||
|
Projectile.extraUpdates = 1;
|
||||||
|
Projectile.usesLocalNPCImmunity = true;
|
||||||
|
Projectile.localNPCHitCooldown = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void AI()
|
||||||
|
{
|
||||||
|
Projectile.rotation = Projectile.velocity.ToRotation();
|
||||||
|
Lighting.AddLight(Projectile.Center, 0.7f, 0.25f, 0.85f);
|
||||||
|
|
||||||
|
if (Main.rand.NextBool(3))
|
||||||
|
{
|
||||||
|
Dust dust = Dust.NewDustDirect(Projectile.position, Projectile.width, Projectile.height, DustID.PinkTorch, Projectile.velocity.X * 0.2f, Projectile.velocity.Y * 0.2f, 150, default, 1.2f);
|
||||||
|
dust.noGravity = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 504 B |
@@ -0,0 +1,76 @@
|
|||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Terraria;
|
||||||
|
using Terraria.ID;
|
||||||
|
using Terraria.ModLoader;
|
||||||
|
|
||||||
|
namespace ForgottenWawiTech.Content.Projectiles.Transcendent
|
||||||
|
{
|
||||||
|
public class TranscendentAscendantBolt : ModProjectile
|
||||||
|
{
|
||||||
|
private const float HomingRange = 720f;
|
||||||
|
private const float HomingStrength = 0.2f;
|
||||||
|
private const float DesiredSpeed = 20f;
|
||||||
|
|
||||||
|
/* public override void SetStaticDefaults()
|
||||||
|
{
|
||||||
|
ProjectileID.Sets.MinionShot[Type] = true;
|
||||||
|
} */
|
||||||
|
|
||||||
|
public override void SetDefaults()
|
||||||
|
{
|
||||||
|
Projectile.width = 18;
|
||||||
|
Projectile.height = 18;
|
||||||
|
Projectile.friendly = true;
|
||||||
|
Projectile.timeLeft = 180;
|
||||||
|
Projectile.penetrate = 2;
|
||||||
|
Projectile.tileCollide = false;
|
||||||
|
Projectile.ignoreWater = true;
|
||||||
|
Projectile.DamageType = DamageClass.Summon;
|
||||||
|
Projectile.extraUpdates = 1;
|
||||||
|
Projectile.usesLocalNPCImmunity = true;
|
||||||
|
Projectile.localNPCHitCooldown = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void AI()
|
||||||
|
{
|
||||||
|
Projectile.rotation = Projectile.velocity.ToRotation();
|
||||||
|
Lighting.AddLight(Projectile.Center, 0.6f, 0.55f, 1.2f);
|
||||||
|
|
||||||
|
NPC target = AcquireTarget(Projectile.Center, HomingRange);
|
||||||
|
if (target != null)
|
||||||
|
{
|
||||||
|
Vector2 desiredVelocity = (target.Center - Projectile.Center).SafeNormalize(Vector2.Zero) * DesiredSpeed;
|
||||||
|
Projectile.velocity = Vector2.Lerp(Projectile.velocity, desiredVelocity, HomingStrength);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Main.rand.NextBool(4))
|
||||||
|
{
|
||||||
|
Dust dust = Dust.NewDustDirect(Projectile.position, Projectile.width, Projectile.height, DustID.Enchanted_Pink, Projectile.velocity.X * 0.2f, Projectile.velocity.Y * 0.2f, 150, default, 1.15f);
|
||||||
|
dust.noGravity = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static NPC AcquireTarget(Vector2 center, float range)
|
||||||
|
{
|
||||||
|
NPC closest = null;
|
||||||
|
float sqrRange = range * range;
|
||||||
|
for (int i = 0; i < Main.maxNPCs; i++)
|
||||||
|
{
|
||||||
|
NPC npc = Main.npc[i];
|
||||||
|
if (!npc.active || npc.friendly || npc.dontTakeDamage || npc.life <= 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float dist = Vector2.DistanceSquared(npc.Center, center);
|
||||||
|
if (dist <= sqrRange && Collision.CanHitLine(center, 0, 0, npc.Center, 0, 0))
|
||||||
|
{
|
||||||
|
sqrRange = dist;
|
||||||
|
closest = npc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return closest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 504 B |
@@ -0,0 +1,130 @@
|
|||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Terraria;
|
||||||
|
using Terraria.Audio;
|
||||||
|
using Terraria.ID;
|
||||||
|
using Terraria.ModLoader;
|
||||||
|
using ForgottenWawiTech.Content.Players;
|
||||||
|
|
||||||
|
namespace ForgottenWawiTech.Content.Projectiles.Transcendent
|
||||||
|
{
|
||||||
|
public class TranscendentAscendantDrone : ModProjectile
|
||||||
|
{
|
||||||
|
private const float OrbitRadius = 136f;
|
||||||
|
private const float OrbitSpeed = 0.055f;
|
||||||
|
private const int FireCooldown = 18;
|
||||||
|
private const float TargetRange = 1100f;
|
||||||
|
private const float BoltSpeed = 19f;
|
||||||
|
|
||||||
|
public override void SetStaticDefaults()
|
||||||
|
{
|
||||||
|
ProjectileID.Sets.MinionSacrificable[Type] = false;
|
||||||
|
ProjectileID.Sets.MinionTargettingFeature[Type] = true;
|
||||||
|
//ProjectileID.Sets.Minion[Type] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetDefaults()
|
||||||
|
{
|
||||||
|
Projectile.width = 28;
|
||||||
|
Projectile.height = 28;
|
||||||
|
Projectile.friendly = false;
|
||||||
|
Projectile.minion = true;
|
||||||
|
Projectile.penetrate = -1;
|
||||||
|
Projectile.tileCollide = false;
|
||||||
|
Projectile.ignoreWater = true;
|
||||||
|
Projectile.netImportant = true;
|
||||||
|
Projectile.timeLeft = 2;
|
||||||
|
Projectile.minionSlots = 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void AI()
|
||||||
|
{
|
||||||
|
Player owner = Main.player[Projectile.owner];
|
||||||
|
TranscendentPlayer modPlayer = owner.GetModPlayer<TranscendentPlayer>();
|
||||||
|
if (!owner.active || owner.dead || !modPlayer.HasTranscendentSet)
|
||||||
|
{
|
||||||
|
Projectile.Kill();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Projectile.timeLeft = 2;
|
||||||
|
|
||||||
|
float index = Projectile.ai[0];
|
||||||
|
float total = Projectile.ai[1];
|
||||||
|
if (total <= 0f)
|
||||||
|
{
|
||||||
|
total = 4f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float rotation = ((float)Main.GameUpdateCount * OrbitSpeed) + index * MathHelper.TwoPi / total;
|
||||||
|
Vector2 offset = rotation.ToRotationVector2() * OrbitRadius;
|
||||||
|
Projectile.Center = owner.Center + offset;
|
||||||
|
Projectile.velocity = owner.velocity;
|
||||||
|
Projectile.rotation = (owner.Center - Projectile.Center).ToRotation() + MathHelper.PiOver2;
|
||||||
|
|
||||||
|
Lighting.AddLight(Projectile.Center, 0.45f, 0.6f, 1.05f);
|
||||||
|
|
||||||
|
if (Projectile.owner == Main.myPlayer)
|
||||||
|
{
|
||||||
|
Projectile.localAI[0]++;
|
||||||
|
if (Projectile.localAI[0] >= FireCooldown)
|
||||||
|
{
|
||||||
|
Projectile.localAI[0] = 0f;
|
||||||
|
NPC target = AcquireTarget(owner, Projectile.Center, TargetRange);
|
||||||
|
if (target != null)
|
||||||
|
{
|
||||||
|
FireBolt(owner, target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FireBolt(Player owner, NPC target)
|
||||||
|
{
|
||||||
|
Vector2 velocity = (target.Center - Projectile.Center).SafeNormalize(Vector2.UnitY) * BoltSpeed;
|
||||||
|
int damage = TranscendentPlayer.GetAscendantDroneDamage(owner);
|
||||||
|
var source = Projectile.GetSource_FromThis();
|
||||||
|
Projectile.NewProjectile(
|
||||||
|
source,
|
||||||
|
Projectile.Center,
|
||||||
|
velocity,
|
||||||
|
ModContent.ProjectileType<TranscendentAscendantBolt>(),
|
||||||
|
damage,
|
||||||
|
4f,
|
||||||
|
owner.whoAmI);
|
||||||
|
SoundEngine.PlaySound(SoundID.Item33 with { Volume = 0.6f, Pitch = 0.2f }, Projectile.Center);
|
||||||
|
Projectile.netUpdate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static NPC AcquireTarget(Player owner, Vector2 center, float range)
|
||||||
|
{
|
||||||
|
if (owner.HasMinionAttackTargetNPC)
|
||||||
|
{
|
||||||
|
NPC forced = Main.npc[owner.MinionAttackTargetNPC];
|
||||||
|
if (forced.CanBeChasedBy())
|
||||||
|
{
|
||||||
|
return forced;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NPC closest = null;
|
||||||
|
float sqrRange = range * range;
|
||||||
|
for (int i = 0; i < Main.maxNPCs; i++)
|
||||||
|
{
|
||||||
|
NPC npc = Main.npc[i];
|
||||||
|
if (!npc.active || npc.friendly || npc.dontTakeDamage || npc.life <= 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float dist = Vector2.DistanceSquared(npc.Center, center);
|
||||||
|
if (dist <= sqrRange && Collision.CanHitLine(center, 0, 0, npc.Center, 0, 0))
|
||||||
|
{
|
||||||
|
sqrRange = dist;
|
||||||
|
closest = npc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return closest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 504 B |
@@ -0,0 +1,81 @@
|
|||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Terraria;
|
||||||
|
using Terraria.ID;
|
||||||
|
using Terraria.ModLoader;
|
||||||
|
|
||||||
|
namespace ForgottenWawiTech.Content.Projectiles.Transcendent
|
||||||
|
{
|
||||||
|
public class TranscendentNaniteShard : ModProjectile
|
||||||
|
{
|
||||||
|
private const float HomingRange = 680f;
|
||||||
|
private const float HomingStrength = 0.22f;
|
||||||
|
private const float DesiredSpeed = 18f;
|
||||||
|
|
||||||
|
public override void SetStaticDefaults()
|
||||||
|
{
|
||||||
|
ProjectileID.Sets.MinionShot[Type] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetDefaults()
|
||||||
|
{
|
||||||
|
Projectile.width = 14;
|
||||||
|
Projectile.height = 14;
|
||||||
|
Projectile.friendly = true;
|
||||||
|
Projectile.penetrate = 1;
|
||||||
|
Projectile.timeLeft = 220;
|
||||||
|
Projectile.tileCollide = false;
|
||||||
|
Projectile.ignoreWater = true;
|
||||||
|
Projectile.extraUpdates = 1;
|
||||||
|
Projectile.DamageType = DamageClass.Generic;
|
||||||
|
Projectile.usesLocalNPCImmunity = true;
|
||||||
|
Projectile.localNPCHitCooldown = 12;
|
||||||
|
Projectile.alpha = 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void AI()
|
||||||
|
{
|
||||||
|
Projectile.rotation += 0.35f * Projectile.direction;
|
||||||
|
Lighting.AddLight(Projectile.Center, 0.45f, 0.8f, 1.15f);
|
||||||
|
|
||||||
|
NPC target = AcquireTarget(Projectile.Center, HomingRange);
|
||||||
|
if (target != null)
|
||||||
|
{
|
||||||
|
Vector2 desiredVelocity = (target.Center - Projectile.Center).SafeNormalize(Vector2.Zero) * DesiredSpeed;
|
||||||
|
Projectile.velocity = Vector2.Lerp(Projectile.velocity, desiredVelocity, HomingStrength);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Projectile.velocity *= 0.98f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Main.rand.NextBool(5))
|
||||||
|
{
|
||||||
|
Dust dust = Dust.NewDustDirect(Projectile.position, Projectile.width, Projectile.height, DustID.Electric, 0f, 0f, 120, default, 1.05f);
|
||||||
|
dust.noGravity = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static NPC AcquireTarget(Vector2 center, float range)
|
||||||
|
{
|
||||||
|
NPC closest = null;
|
||||||
|
float sqrRange = range * range;
|
||||||
|
for (int i = 0; i < Main.maxNPCs; i++)
|
||||||
|
{
|
||||||
|
NPC npc = Main.npc[i];
|
||||||
|
if (!npc.active || npc.friendly || npc.dontTakeDamage || npc.life <= 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float dist = Vector2.DistanceSquared(npc.Center, center);
|
||||||
|
if (dist <= sqrRange && Collision.CanHitLine(center, 0, 0, npc.Center, 0, 0))
|
||||||
|
{
|
||||||
|
sqrRange = dist;
|
||||||
|
closest = npc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return closest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 504 B |
@@ -896,6 +896,17 @@ Items: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Conditions: {
|
||||||
|
HasDefeatedAnyMechBoss: Defeated a mechanical boss
|
||||||
|
HasDefeatedExoMechs: Defeated the Exo Mechs
|
||||||
|
HasDefeatedLexy: Defeated Lexy
|
||||||
|
HasDefeatedNiko: Defeated Niko
|
||||||
|
HasDefeatedNeptune: Defeated Neptune
|
||||||
|
HasDefeatedLyyka: Defeated Lyyka
|
||||||
|
HasDefeatedCorruptedSwarm: Defeated the Corrupted Swarm
|
||||||
|
HasDefeatedMoonLord: Defeated the Moon Lord
|
||||||
|
}
|
||||||
|
|
||||||
NPCs: {
|
NPCs: {
|
||||||
Lexy.DisplayName: Lexy
|
Lexy.DisplayName: Lexy
|
||||||
|
|
||||||
@@ -992,6 +1003,17 @@ Projectiles: {
|
|||||||
TranscendentNova.DisplayName: Transcendent Nova
|
TranscendentNova.DisplayName: Transcendent Nova
|
||||||
TranscendentRailBolt.DisplayName: Transcendent Rail Bolt
|
TranscendentRailBolt.DisplayName: Transcendent Rail Bolt
|
||||||
AvaliThermalDrone.DisplayName: Avali Thermal Drone
|
AvaliThermalDrone.DisplayName: Avali Thermal Drone
|
||||||
|
AvaliHuntingDrone.DisplayName: Avali Hunting Drone
|
||||||
|
AvaliHuntingDroneShot.DisplayName: Avali Hunting Drone Pulse
|
||||||
|
ProtogenOperativeNanite.DisplayName: Operative Nanite
|
||||||
|
ProtogenSentinelCore.DisplayName: Sentinel AI Core
|
||||||
|
ProtogenSentinelCoreBeam.DisplayName: Sentinel Core Beam
|
||||||
|
ProtogenSentinelFragment.DisplayName: Sentinel Split Fragment
|
||||||
|
SingularityOrb.DisplayName: Singularity Orb
|
||||||
|
SingularityOrbBeam.DisplayName: Singularity Orb Beam
|
||||||
|
TranscendentAscendantDrone.DisplayName: Ascendant Swarm Drone
|
||||||
|
TranscendentAscendantBolt.DisplayName: Ascendant Swarm Bolt
|
||||||
|
TranscendentNaniteShard.DisplayName: Nanite Shard
|
||||||
}
|
}
|
||||||
|
|
||||||
Prefixes: {
|
Prefixes: {
|
||||||
|
|||||||