From 20474716a260664546facb24c0c595e94654e4fd Mon Sep 17 00:00:00 2001 From: Collin Summers Date: Thu, 5 Feb 2026 13:19:46 -0500 Subject: [PATCH 1/7] basic implementation --- Assets/Buffs/ThoughtProvokerSummonBuff.png | Bin 0 -> 685 bytes Assets/Items/Crimson/ThoughtProvoker.png | Bin 0 -> 800 bytes .../Crimson/ThoughtProvokerProjectile.png | Bin 0 -> 462 bytes .../Buffs/Summon/ThoughtProvokerSummonBuff.cs | 30 ++ Content/GUI/Tooltip.cs | 2 +- .../Items/Crimson/Weapons.ThoughtProvoker.cs | 329 ++++++++++++++++++ Localization/en-US_Mods.StarlightRiver.hjson | 16 + 7 files changed, 376 insertions(+), 1 deletion(-) create mode 100644 Assets/Buffs/ThoughtProvokerSummonBuff.png create mode 100644 Assets/Items/Crimson/ThoughtProvoker.png create mode 100644 Assets/Items/Crimson/ThoughtProvokerProjectile.png create mode 100644 Content/Buffs/Summon/ThoughtProvokerSummonBuff.cs create mode 100644 Content/Items/Crimson/Weapons.ThoughtProvoker.cs diff --git a/Assets/Buffs/ThoughtProvokerSummonBuff.png b/Assets/Buffs/ThoughtProvokerSummonBuff.png new file mode 100644 index 0000000000000000000000000000000000000000..7fabe344ea51f739631e3f7fab1730aed4a944a1 GIT binary patch literal 685 zcmV;e0#f~nP)Px%XGugsR9J=8mqBO~K@^6+s4WP^LlN4tfoPCOZELHb9u&cY7^$F$(t>zOP&^6g zITXpcxf&sRDng=C6f8u9c-Mo(8mk^w11U`}A}DxJjE9*QcGulhLDKO*?Y^BiGylKu zy?GNEI+6fjY=;@fPL#W0Lf$$04qPI z7S;-zqrkd0EbCZ^$K#%X<+9rG(93$@L>q_30LW&uf!`~Y3bv0?=Cf4n`{=`5newu==V7!05rrKzph78i416 z1K?6(do&70Dp2(?zxgu~=pc-RX_#H!=NIonK$b+c5?ijo4!=S2eDvxSk6oAvBR?jb zCb+UfFgrO8K&J6A(9felB9Zv3-Tw=86bM^f@_XgWXK*nJiv@pu*bL^xfSgj-mP!De z)ipaG-vhu(O(`JEg{i==kSJ5vu@T!BQ|nlk$8XCO`28%Oul^Q*v7G~+iR<6gxb=zs02B%Z09p}MU(Bn7{?pLk$q1yE>vui?aCr9!LGUvt z+7JK5X(%0$Fqck7y5+Fg5X53C+B?iOY}*E-JEFEP`a8^ZSIo>sujfLk`^@^EODv^Q zDP^CVRSO%}6*rrzVo62Z>}DjfBFrSe!(i^s=<<1$ulFCl>*?+IU<%AJy<% T0_U-E00000NkvXXu0mjfM!rFA literal 0 HcmV?d00001 diff --git a/Assets/Items/Crimson/ThoughtProvoker.png b/Assets/Items/Crimson/ThoughtProvoker.png new file mode 100644 index 0000000000000000000000000000000000000000..3d436e7356b19dc9828b131b40a0fc1de5caa8c4 GIT binary patch literal 800 zcmV+*1K<3KP)Px%+DSw~R9J=8m`_L)aTLctqif;6vRxe6q-|&I5(^QEQGcMuD-3*c)m@4N40)0Vae;PuLKsQv%h>USen5H`00a#tz^1=)|GTi`dXu022 z%!R4w4fy<|I@>LPVJ%0;c(+(oSDI=ug_kupB4 zQ~<~o3ScmG-^}|AH+4)MEzf=Y4nS`}FOcWcx2`MyuigRB9E(AujO{axYDGK0e2U(O zj{vZB>}22a^oh^zgO=qBNRCJ@Y^*H$?B#vYRj%Pomj}>)^#TAd7QO&5`F7H0C@YsN z|Gc{cz?E}xFtRwfpGR(v0C2DGG8kVbx)=vFutI0DRK>z9-%az{}-t09>;Z032wh!I~|IjeHo)8l4KIvahB~%?-*ev3j+S>y+!pdc`fjuO^+y zr_9jV*Mu=|`xx74HL1wtA&kXmwG)J(b}Cmjq|e7K6f;$k^ei=}_owLH_3&CAMC~(n z*LQqfMy5!k>&VIB*u3GtU@VZi+YZRc6na9`K4UrQOP@CSwofmA0**uNRxUxceLf}v)-!DY0000Px$h)G02R9J=8mOGBZFcd{kM)d4~3WqJ;wXKqMptEeoMx zikU0fZ(=?v#^F@>5!<=vIZ+Y_7N(S4yziY)U6&Sq3GE zs?LjUprIc&!D6uhV7*=gFr7|u|If0_>$U1>ntB_A=E+2K1Ieq&H5TXd*&D0J*Xz}* zw^}W)u6epXx`Bo**rXxUYZYMCkdJ5nJ!~``-AO ziTDOW&+TL~skETZ%yPK|AkTAeU7>yB8@OC93C=rOJwKgJ;Pg236j)<2FrUu>Sglq7 zbh}+}-hkRSz5)HPXW@7}0x%d1z`1i_dur))I^H@mVE3ty0rg}w8r=bQyPbDov)O#O z(Cu~uCwaTw24FUu@w=|KkBDv{_=P(h4m}e^QNT|E?>Z$`UE^M_2Tt<+e*Ym~#g>qX z5U(Z|^*11%nRqw3_#6Ymnh@_M7oTT9$b@(|xrlDy8?1ZEU)mS%yZ`_I07*qoM6N<$ Ef&y~Od;kCd literal 0 HcmV?d00001 diff --git a/Content/Buffs/Summon/ThoughtProvokerSummonBuff.cs b/Content/Buffs/Summon/ThoughtProvokerSummonBuff.cs new file mode 100644 index 000000000..4c4475c25 --- /dev/null +++ b/Content/Buffs/Summon/ThoughtProvokerSummonBuff.cs @@ -0,0 +1,30 @@ +using StarlightRiver.Content.Items.Crimson; +using StarlightRiver.Content.Items.Haunted; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace StarlightRiver.Content.Buffs.Summon +{ + class ThoughtProvokerSummonBuff : SmartBuff + { + public override string Texture => AssetDirectory.Buffs + Name; + + public ThoughtProvokerSummonBuff() : base("Thinky Juniors", "1000 IQ", false, true) { } + + public override void Update(Player Player, ref int buffIndex) + { + if (Player.ownedProjectileCounts[ModContent.ProjectileType()] > 0) + { + Player.buffTime[buffIndex] = 18000; + } + else + { + Player.DelBuff(buffIndex); + buffIndex--; + } + } + } +} diff --git a/Content/GUI/Tooltip.cs b/Content/GUI/Tooltip.cs index 257a8c253..5c295551e 100644 --- a/Content/GUI/Tooltip.cs +++ b/Content/GUI/Tooltip.cs @@ -57,7 +57,7 @@ public static void SetColor(Color color) public override void Draw(SpriteBatch spriteBatch) { - if (text is null || text.Length <= 0) + if (text is null || text.Length <= 0 || tooltip is null) return; ReLogic.Graphics.DynamicSpriteFont font = Terraria.GameContent.FontAssets.MouseText.Value; diff --git a/Content/Items/Crimson/Weapons.ThoughtProvoker.cs b/Content/Items/Crimson/Weapons.ThoughtProvoker.cs new file mode 100644 index 000000000..ec33933b2 --- /dev/null +++ b/Content/Items/Crimson/Weapons.ThoughtProvoker.cs @@ -0,0 +1,329 @@ +using StarlightRiver.Content.Buffs.Summon; +using StarlightRiver.Content.Items.Haunted; +using StarlightRiver.Content.Items.Palestone; +using System; +using System.Linq; +using Terraria.DataStructures; +using Terraria.ID; + +namespace StarlightRiver.Content.Items.Crimson +{ + public class ThoughtProvoker : ModItem + { + public override string Texture => AssetDirectory.CrimsonItem + Name; + public override void SetStaticDefaults() + { + DisplayName.SetDefault("Thought Provoker"); + Tooltip.SetDefault( + "Summons Thinky Jr to protect you\n" + + "Endurance is increased by 5% per Thinky Jr alive\n" + + "If hit by an enemy or projectile, Thinky Jr will target the nearest enemy and explode violently"); + ItemID.Sets.GamepadWholeScreenUseRange[Item.type] = true; // This lets the Player target anywhere on the whole screen while using a controller. + ItemID.Sets.LockOnIgnoresCollision[Item.type] = true; + } + + public override void SetDefaults() + { + Item.damage = 45; + Item.knockBack = 10f; + Item.mana = 30; + Item.width = 32; + Item.height = 32; + Item.useTime = 24; + Item.useAnimation = 24; + Item.useStyle = ItemUseStyleID.Swing; + Item.value = Item.buyPrice(gold: 3); + Item.rare = ItemRarityID.Orange; + Item.UseSound = SoundID.Item44; + + Item.noMelee = true; + Item.DamageType = DamageClass.Summon; + Item.buffType = ModContent.BuffType(); + Item.shoot = ModContent.ProjectileType(); + } + + public override bool Shoot(Player player, EntitySource_ItemUse_WithAmmo source, Vector2 position, Vector2 velocity, int type, int damage, float knockback) + { + player.AddBuff(Item.buffType, 2); + Projectile.NewProjectileDirect(source, Main.MouseWorld, velocity, type, damage, knockback, Main.myPlayer).originalDamage = Item.damage; + + return false; + } + } + + public class ThoughtProvokerPlayer : ModPlayer + { + public override void UpdateEquips() + { + // 5% increased endurance per Thinky Jr + if (Player.ownedProjectileCounts[ModContent.ProjectileType()] > 0) + Player.endurance += 0.05f * Player.ownedProjectileCounts[ModContent.ProjectileType()]; + } + } + + public class ThoughtProvokerProjectile : ModProjectile + { + public int resetTimer; + public int lifetime; + public ref float TargetWhoAmI => ref Projectile.ai[1]; + public NPC Target => TargetWhoAmI > -1 ? Main.npc[(int)TargetWhoAmI] : null; + public bool FoundTarget => Target != null; + + public NPC MinionTarget + { + get + { + if (Owner.HasMinionAttackTargetNPC && Main.npc[Owner.MinionAttackTargetNPC].Distance(Projectile.Center) < 1000f) + return Main.npc[Owner.MinionAttackTargetNPC]; + + return null; + } + } + public int Lifetime + { + get + { + if (Projectile.minionPos <= 0) + { + return lifetime; + } + else + { + Projectile proj = Main.projectile.Where(p => p.active && p.type == Type && p.owner == Projectile.owner && p.minionPos == 0).FirstOrDefault(); + if (proj != null) + { + var dagger = proj.ModProjectile as ThoughtProvokerProjectile; + if (dagger != null) + return dagger.lifetime; + } + } + + return 0; + } + } + + public const int maxMinionChaseRange = 500; + public ref float AttackState => ref Projectile.ai[0]; + public ref float EnemyWhoAmI => ref Projectile.ai[1]; + public ref float AttackDelay => ref Projectile.ai[2]; + public Player Owner => Main.player[Projectile.owner]; + public override string Texture => AssetDirectory.CrimsonItem + Name; + + public override void SetStaticDefaults() + { + DisplayName.SetDefault("Thinky Junior"); + + Main.projPet[Projectile.type] = true; // Denotes that this Projectile is a pet or minion + ProjectileID.Sets.MinionTargettingFeature[Projectile.type] = true; // This is necessary for right-click targeting + ProjectileID.Sets.MinionSacrificable[Projectile.type] = true; // This is needed so your minion can properly spawn when summoned and replaced when other minions are summoned + ProjectileID.Sets.CultistIsResistantTo[Projectile.type] = true; // Don't mistake this with "if this is true, then it will automatically home". It is just for damage reduction for certain NPCs + } + public override void OnSpawn(IEntitySource source) + { + TargetWhoAmI = -1f; + } + + public override void SetDefaults() + { + Projectile.width = 24; + Projectile.height = 24; + + Projectile.tileCollide = false; + Projectile.ignoreWater = true; + + Projectile.minion = true; + + Projectile.minionSlots = 1f; + + Projectile.penetrate = -1; + Projectile.DamageType = DamageClass.Summon; + + Projectile.friendly = true; + } + + public override void AI() + { + Player Player = Main.player[Projectile.owner]; + + if (resetTimer > 0) + resetTimer--; + + if (AttackDelay > 0) + AttackDelay--; + + #region Active check + if (Player.dead || !Player.active) + Player.ClearBuff(ModContent.BuffType()); + + if (Player.HasBuff(ModContent.BuffType())) + Projectile.timeLeft = 2; + + lifetime++; + + //closest npc + NPC target = FindTarget(); + if (target != default) + TargetWhoAmI = target.whoAmI; + + #endregion + + if (AttackState == 0) + { + #region Shielding Behavior + + float totalCount = Owner.ownedProjectileCounts[Type] > 0 ? Owner.ownedProjectileCounts[Type] : 1; + + Vector2 idlePos = Owner.Center + new Vector2(0, 50).RotatedBy(MathHelper.ToRadians(Projectile.minionPos / totalCount * 360f + (Projectile.minionPos == totalCount ? 360f / totalCount : 0f)) + MathHelper.ToRadians(Lifetime)); + + float dist = Vector2.Distance(Projectile.Center, idlePos); + + Vector2 toIdlePos = idlePos - Projectile.Center; + if (toIdlePos.Length() < 0.0001f) + { + toIdlePos = Vector2.Zero; + } + else + { + float speed = 50f; + if (dist < 1000f) + speed = MathHelper.Lerp(15f, 50f, dist / 1000f); + + if (dist < 100f) + speed = MathHelper.Lerp(3f, 15f, dist / 100f); + + toIdlePos.Normalize(); + toIdlePos *= speed; + } + + Projectile.velocity = (Projectile.velocity * (5f - 1) + toIdlePos) / 5f; + + if (dist > 2000f) + { + Projectile.Center = idlePos; + Projectile.velocity = Vector2.Zero; + Projectile.netUpdate = true; + } + + Projectile.rotation = Projectile.velocity.X * 0.05f; + + // checks if the projectile is colliding with a npc or hostile projectile hitbox + + Entity colliding = CheckCollisions(target); + + if (colliding != null && resetTimer <= 0) + { + //special case for projectiles + if (colliding is Projectile) + (colliding as Projectile).penetrate--; + + AttackState = 1; + + AttackDelay = 30; + Projectile.velocity *= 0.05f; + Projectile.velocity += Main.rand.NextVector2CircularEdge(10f, 10f); + } + + + #endregion + } + else + { + #region Exploding Behavior + + //prioritize minion target over closest npc + if (MinionTarget != null) + TargetWhoAmI = MinionTarget.whoAmI; + + if (Target is null) + { + TargetWhoAmI = -1; + AttackDelay = 45; + } + + if (AttackDelay <= 0) + { + Vector2 direction = Target.Center - Projectile.Center; + direction.Normalize(); + if (Projectile.Distance(Target.Center) > 400f) + direction *= 20f; + else + { + float mult = MathHelper.Lerp(20f, 100f, 1f - Projectile.Distance(Target.Center) / 400f); + direction *= mult; + } + + Projectile.velocity = Vector2.Lerp(Projectile.velocity, direction, 0.05f); + Projectile.rotation += Projectile.velocity.Length() * 0.02f; // more aggressive spin when attacking + + } + else + { + Projectile.rotation += Projectile.velocity.Length() * 0.01f; + Projectile.velocity *= 0.985f; + } + + if (AttackDelay == 1 && Target is null) + ResetToIdle(); + + #endregion + } + } + + public override bool PreDraw(ref Color lightColor) + { + Texture2D tex = Assets.Items.Crimson.ThoughtProvokerProjectile.Value; + + float fade = 1f; + if (resetTimer > 0) + fade = 1f - resetTimer / 120f; + + Main.spriteBatch.Draw(tex, Projectile.Center - Main.screenPosition, null, Color.White * fade, Projectile.rotation, tex.Size() / 2f, Projectile.scale, 0f, 0f); + + return false; + } + + public override void OnHitNPC(NPC target, NPC.HitInfo hit, int damageDone) + { + ResetToIdle(); + } + public override bool? CanHitNPC(NPC target) + { + return target.whoAmI == TargetWhoAmI; + } + + public override bool MinionContactDamage() + { + return AttackDelay <= 0 && AttackState == 1; + } + + internal Entity CheckCollisions(NPC target) + { + // we dont want the shield to break if its not actively "protecting" its owner, for example on spawn + if (Projectile.Distance(Owner.Center) > 75f) + return null; + + Projectile closest = Main.projectile.Where(p => p.active && p.hostile && p.Distance(Projectile.Center) < 100f).OrderBy(p => p.Distance(Projectile.Center)).FirstOrDefault(); + + if (closest != default && Projectile.Hitbox.Intersects(closest.Hitbox)) + return closest; + + if (target != null && Projectile.Hitbox.Intersects(target.Hitbox)) + return target; + + return null; + } + + internal NPC FindTarget() + { + return Main.npc.Where(n => n.CanBeChasedBy() && n.Distance(Owner.Center) < 1000f).OrderBy(n => n.Distance(Projectile.Center)).FirstOrDefault(); + } + + internal void ResetToIdle() + { + AttackState = 0; + Projectile.position = Owner.Center; + resetTimer = 120; + AttackDelay = 45; + } + } +} diff --git a/Localization/en-US_Mods.StarlightRiver.hjson b/Localization/en-US_Mods.StarlightRiver.hjson index 03220b412..a9a90c8cf 100644 --- a/Localization/en-US_Mods.StarlightRiver.hjson +++ b/Localization/en-US_Mods.StarlightRiver.hjson @@ -3871,6 +3871,16 @@ Items: { DisplayName: Pink Laser Pointer Tooltip: "" } + + ThoughtProvoker: { + DisplayName: Thought Provoker + Tooltip: + ''' + Summons Thinky Jr to protect you + Endurance is increased by 5% per Thinky Jr alive + If hit by an enemy or projectile, Thinky Jr will target the nearest enemy and explode violently + ''' + } } Tiles: { @@ -4451,6 +4461,7 @@ Projectiles: { ThoughtPoliceProjectile.DisplayName: Thoughtcrime ThoughtPoliceShard.DisplayName: Thoughtcrime ThoughtPoliceCage.DisplayName: Thoughtcrime + ThoughtProvokerProjectile.DisplayName: Thinky Junior } Biomes: { @@ -4972,6 +4983,11 @@ Buffs: { DisplayName: Full Description: Mods.StarlightRiver.Buffs.Full.Description } + + ThoughtProvokerSummonBuff: { + DisplayName: Thinky Juniors + Description: 1000 IQ + } } Prefixes: { From 9abfedf9b47873b9a71396aab112331b33e25e51 Mon Sep 17 00:00:00 2001 From: Collin Summers Date: Thu, 5 Feb 2026 14:10:20 -0500 Subject: [PATCH 2/7] explosion start --- .../Items/Crimson/Weapons.ThoughtProvoker.cs | 141 ++++++++++++++++++ Localization/en-US_Mods.StarlightRiver.hjson | 1 + 2 files changed, 142 insertions(+) diff --git a/Content/Items/Crimson/Weapons.ThoughtProvoker.cs b/Content/Items/Crimson/Weapons.ThoughtProvoker.cs index ec33933b2..124c9ef29 100644 --- a/Content/Items/Crimson/Weapons.ThoughtProvoker.cs +++ b/Content/Items/Crimson/Weapons.ThoughtProvoker.cs @@ -1,7 +1,10 @@ using StarlightRiver.Content.Buffs.Summon; using StarlightRiver.Content.Items.Haunted; using StarlightRiver.Content.Items.Palestone; +using StarlightRiver.Core.Loaders; +using StarlightRiver.Core.Systems.PixelationSystem; using System; +using System.Collections.Generic; using System.Linq; using Terraria.DataStructures; using Terraria.ID; @@ -284,6 +287,9 @@ public override bool PreDraw(ref Color lightColor) public override void OnHitNPC(NPC target, NPC.HitInfo hit, int damageDone) { + if (Main.myPlayer == Projectile.owner) + Projectile.NewProjectile(Projectile.GetSource_OnHit(target), Projectile.Center, Vector2.Zero, ModContent.ProjectileType(), Projectile.damage * 2, 5f, Projectile.owner, 50); + ResetToIdle(); } public override bool? CanHitNPC(NPC target) @@ -326,4 +332,139 @@ internal void ResetToIdle() AttackDelay = 45; } } + public class ThoughtProvokerExplosion : ModProjectile + { + private List cache; + + private Trail trail; + private Trail trail2; + public override string Texture => AssetDirectory.Invisible; + private float Progress => Utils.Clamp(1 - Projectile.timeLeft / 30f, 0f, 1f); + + private float Radius => Projectile.ai[0] * Eases.EaseQuinticOut(Progress); + + public override void SetDefaults() + { + Projectile.width = 2; + Projectile.height = 2; + Projectile.DamageType = DamageClass.Summon; + Projectile.friendly = true; + Projectile.tileCollide = false; + Projectile.penetrate = -1; + Projectile.timeLeft = 30; + + Projectile.usesLocalNPCImmunity = true; + Projectile.localNPCHitCooldown = 20; + } + + public override void SetStaticDefaults() + { + DisplayName.SetDefault("Greymatter Explosion"); + } + + public override void AI() + { + if (Main.netMode != NetmodeID.Server) + { + ManageCaches(); + ManageTrail(); + } + + /*for (int k = 0; k < 6; k++) + { + float rot = Main.rand.NextFloat(0, 6.28f); + + Dust.NewDustPerfect(Projectile.Center + Vector2.One.RotatedBy(rot) * Radius, DustID.Torch, + Vector2.One.RotatedBy(rot) * 0.5f, 0, default, Main.rand.NextFloat(1.5f, 3f)).noGravity = true; + + Dust.NewDustPerfect(Projectile.Center + Vector2.One.RotatedBy(rot) * Radius, DustID.Torch, + Vector2.One.RotatedBy(rot) * 0.5f + Main.rand.NextVector2Circular(2f, 2f), 50, default, Main.rand.NextFloat(0.5f, 1f)); + }*/ + } + + public override bool? Colliding(Rectangle projHitbox, Rectangle targetHitbox) + { + Vector2 line = targetHitbox.Center.ToVector2() - Projectile.Center; + line.Normalize(); + line *= Radius; + return Collision.CheckAABBvLineCollision(targetHitbox.TopLeft(), targetHitbox.Size(), Projectile.Center, Projectile.Center + line); + } + + public override void OnHitNPC(NPC target, NPC.HitInfo hit, int damageDone) + { + //target.AddBuff(BuffID.OnFire, 300); + } + + public override bool PreDraw(ref Color lightColor) + { + DrawPrimitives(); + return false; + } + + private void ManageCaches() + { + if (cache is null) + { + cache = []; + + for (int i = 0; i < 40; i++) + { + cache.Add(Projectile.Center); + } + } + + for (int k = 0; k < 40; k++) + { + cache[k] = Projectile.Center + Vector2.One.RotatedBy(k / 38f * 6.28f) * Radius; + } + + while (cache.Count > 40) + { + cache.RemoveAt(0); + } + } + + private void ManageTrail() + { + trail ??= new Trail(Main.instance.GraphicsDevice, 40, new TriangularTip(1), factor => 40 * (1f - Progress), factor => Color.Lerp(new Color(255, 180, 20), new Color(255, 20, 20), Eases.EaseQuinticInOut(Progress))); + + trail2 ??= new Trail(Main.instance.GraphicsDevice, 40, new TriangularTip(1), factor => 30 * (1f - Progress), factor => Color.Lerp(new Color(255, 255, 255), new Color(255, 180, 20), Eases.EaseQuinticInOut(Progress))); + + trail.Positions = cache.ToArray(); + trail.NextPosition = cache[39]; + + trail2.Positions = cache.ToArray(); + trail2.NextPosition = cache[39]; + } + + public void DrawPrimitives() + { + if (Projectile.timeLeft < 2) + return; + + ModContent.GetInstance().QueueRenderAction("UnderProjectiles", () => + { + Effect effect = ShaderLoader.GetShader("CeirosRing").Value; + + if (effect != null) + { + var world = Matrix.CreateTranslation(-Main.screenPosition.ToVector3()); + Matrix view = Matrix.Identity; + var projection = Matrix.CreateOrthographicOffCenter(0, Main.screenWidth, Main.screenHeight, 0, -1, 1); + + effect.Parameters["transformMatrix"].SetValue(world * view * projection); + effect.Parameters["time"].SetValue(Projectile.timeLeft * -0.01f); + effect.Parameters["repeats"].SetValue(5f); + effect.Parameters["sampleTexture"].SetValue(ModContent.Request(AssetDirectory.Assets + "FireTrail").Value); + + trail?.Render(effect); + trail2?.Render(effect); + + effect.Parameters["sampleTexture"].SetValue(ModContent.Request(AssetDirectory.Assets + "EnergyTrail").Value); + + trail2?.Render(effect); + } + }); + } + } } diff --git a/Localization/en-US_Mods.StarlightRiver.hjson b/Localization/en-US_Mods.StarlightRiver.hjson index a9a90c8cf..330232b51 100644 --- a/Localization/en-US_Mods.StarlightRiver.hjson +++ b/Localization/en-US_Mods.StarlightRiver.hjson @@ -4462,6 +4462,7 @@ Projectiles: { ThoughtPoliceShard.DisplayName: Thoughtcrime ThoughtPoliceCage.DisplayName: Thoughtcrime ThoughtProvokerProjectile.DisplayName: Thinky Junior + ThoughtProvokerExplosion.DisplayName: Greymatter Explosion } Biomes: { From 2a4a32ad080f2efb39393d6e604b72a16cfde789 Mon Sep 17 00:00:00 2001 From: SkippZzMods Date: Fri, 6 Feb 2026 21:26:53 -0500 Subject: [PATCH 3/7] prog --- .../Items/Crimson/Weapons.ThoughtProvoker.cs | 462 ++++++++++++++++-- Effects/Source/Decay.fx | 70 +++ StarlightRiver.csproj | 1 + 3 files changed, 502 insertions(+), 31 deletions(-) create mode 100644 Effects/Source/Decay.fx diff --git a/Content/Items/Crimson/Weapons.ThoughtProvoker.cs b/Content/Items/Crimson/Weapons.ThoughtProvoker.cs index 124c9ef29..f1e369206 100644 --- a/Content/Items/Crimson/Weapons.ThoughtProvoker.cs +++ b/Content/Items/Crimson/Weapons.ThoughtProvoker.cs @@ -1,18 +1,68 @@ -using StarlightRiver.Content.Buffs.Summon; +using Microsoft.Xna.Framework.Graphics; +using StarlightRiver.Content.Biomes; +using StarlightRiver.Content.Buffs.Summon; +using StarlightRiver.Content.Dusts; using StarlightRiver.Content.Items.Haunted; using StarlightRiver.Content.Items.Palestone; +using StarlightRiver.Content.Projectiles; using StarlightRiver.Core.Loaders; +using StarlightRiver.Core.Systems.CameraSystem; using StarlightRiver.Core.Systems.PixelationSystem; using System; using System.Collections.Generic; using System.Linq; +using Terraria.Audio; using Terraria.DataStructures; using Terraria.ID; +using static tModPorter.ProgressUpdate; namespace StarlightRiver.Content.Items.Crimson { public class ThoughtProvoker : ModItem { + public override void Load() + { + StarlightPlayer.PostDrawEvent += DrawShield; + } + + private void DrawShield(Player player, SpriteBatch spriteBatch) + { + if (player.ownedProjectileCounts[ModContent.ProjectileType()] > 0) + { + Texture2D tex = Assets.Bosses.TheThinkerBoss.ShieldMap.Value; + + Effect effect = ShaderLoader.GetShader("BrainShield").Value; + + if (effect != null) + { + float fade = player.GetModPlayer().shieldFade / 30f; + + effect.Parameters["time"]?.SetValue(Main.GameUpdateCount * 0.02f); + effect.Parameters["size"]?.SetValue(tex.Size() * 0.6f); + effect.Parameters["opacity"]?.SetValue(fade); + effect.Parameters["pixelRes"]?.SetValue(2f); + + effect.Parameters["drawTexture"]?.SetValue(tex); + effect.Parameters["noiseTexture"]?.SetValue(Assets.Noise.SwirlyNoiseLooping.Value); + effect.Parameters["pulseTexture"]?.SetValue(Assets.Noise.PerlinNoise.Value); + effect.Parameters["edgeTexture"]?.SetValue(Assets.Bosses.TheThinkerBoss.ShieldEdge.Value); + effect.Parameters["outTexture"]?.SetValue(Assets.Bosses.TheThinkerBoss.ShieldMapOut.Value); + effect.Parameters["color"].SetValue(Vector3.Lerp(Vector3.One, new Vector3(1, 0.5f, 0.5f), 1f)); + + spriteBatch.End(); + spriteBatch.Begin(default, BlendState.Additive, default, default, Main.Rasterizer, effect, Main.GameViewMatrix.TransformationMatrix); + + spriteBatch.Draw(tex, player.Center + new Vector2(0f, player.gfxOffY) - Main.screenPosition, null, Color.White, 0, tex.Size() / 2f, 0.18f, SpriteEffects.FlipVertically, 0); + + spriteBatch.End(); + spriteBatch.Begin(default, default, default, default, Main.Rasterizer, default, Main.GameViewMatrix.TransformationMatrix); + } + + effect = ShaderLoader.GetShader("BrainShield").Value; + + } + } + public override string Texture => AssetDirectory.CrimsonItem + Name; public override void SetStaticDefaults() { @@ -50,22 +100,55 @@ public override bool Shoot(Player player, EntitySource_ItemUse_WithAmmo source, player.AddBuff(Item.buffType, 2); Projectile.NewProjectileDirect(source, Main.MouseWorld, velocity, type, damage, knockback, Main.myPlayer).originalDamage = Item.damage; + for (int i = 0; i < 5; i++) + { + float r = 0.2f + (float)Math.Sin(Main.GameUpdateCount * 0.1f) * 0.03f; + float g = 0.3f + (float)Math.Sin(Main.GameUpdateCount * 0.1f + 2f) * 0.05f; + float b = 0.7f + (float)Math.Sin(Main.GameUpdateCount * 0.1f + 4f) * 0.03f; + Color blue = new Color(r, g, b); + + r = 0.7f + (float)Math.Sin(Main.GameUpdateCount * 0.1f) * 0.03f; + g = 0.3f + (float)Math.Sin(Main.GameUpdateCount * 0.1f + 2f) * 0.05f; + b = 0.3f + (float)Math.Sin(Main.GameUpdateCount * 0.1f + 4f) * 0.03f; + Color red = new Color(r, g, b); + + Color c = Main.rand.NextBool() ? red : blue; + + Dust.NewDustPerfect(Main.MouseWorld, + ModContent.DustType(), Main.rand.NextVector2CircularEdge(2f, 2f), 0, c with { A = 0 }, Main.rand.NextFloat(0.5f)).customData = -1; + } + + return false; } } public class ThoughtProvokerPlayer : ModPlayer { + public int shieldFade; + public override void UpdateEquips() { // 5% increased endurance per Thinky Jr - if (Player.ownedProjectileCounts[ModContent.ProjectileType()] > 0) - Player.endurance += 0.05f * Player.ownedProjectileCounts[ModContent.ProjectileType()]; + int shieldingThinkers = Main.projectile.Where(p => p.active && p.type == ModContent.ProjectileType() + && p.owner == Player.whoAmI && (p.ModProjectile as ThoughtProvokerProjectile).AttackState == 0 && (p.ModProjectile as ThoughtProvokerProjectile).resetTimer <= 0).Count(); + + if (shieldingThinkers > 0) + { + Player.endurance += 0.05f * shieldingThinkers; + if (shieldFade < 30) + shieldFade++; + } + else if (shieldFade > 0) + shieldFade--; } } public class ThoughtProvokerProjectile : ModProjectile { + private List cache; + private Trail trail; + public int resetTimer; public int lifetime; public ref float TargetWhoAmI => ref Projectile.ai[1]; @@ -95,9 +178,9 @@ public int Lifetime Projectile proj = Main.projectile.Where(p => p.active && p.type == Type && p.owner == Projectile.owner && p.minionPos == 0).FirstOrDefault(); if (proj != null) { - var dagger = proj.ModProjectile as ThoughtProvokerProjectile; - if (dagger != null) - return dagger.lifetime; + var brain = proj.ModProjectile as ThoughtProvokerProjectile; + if (brain != null) + return brain.lifetime; } } @@ -124,6 +207,7 @@ public override void SetStaticDefaults() public override void OnSpawn(IEntitySource source) { TargetWhoAmI = -1f; + resetTimer = 35; } public override void SetDefaults() @@ -174,9 +258,15 @@ public override void AI() { #region Shielding Behavior + if (!Main.dedServ) + { + ManageCaches(); + ManageTrail(); + } + float totalCount = Owner.ownedProjectileCounts[Type] > 0 ? Owner.ownedProjectileCounts[Type] : 1; - Vector2 idlePos = Owner.Center + new Vector2(0, 50).RotatedBy(MathHelper.ToRadians(Projectile.minionPos / totalCount * 360f + (Projectile.minionPos == totalCount ? 360f / totalCount : 0f)) + MathHelper.ToRadians(Lifetime)); + Vector2 idlePos = Owner.Center + new Vector2(0, 65).RotatedBy(MathHelper.ToRadians(Projectile.minionPos / totalCount * 360f + (Projectile.minionPos == totalCount ? 360f / totalCount : 0f)) + MathHelper.ToRadians(Lifetime)); float dist = Vector2.Distance(Projectile.Center, idlePos); @@ -224,8 +314,24 @@ public override void AI() AttackDelay = 30; Projectile.velocity *= 0.05f; Projectile.velocity += Main.rand.NextVector2CircularEdge(10f, 10f); + + for (int i = 0; i < 10; i++) + { + Dust.NewDustPerfect(Projectile.Center, + ModContent.DustType(), Main.rand.NextVector2CircularEdge(2f, 2f), 0, TrailColor(false) with { A = 0 }, Main.rand.NextFloat(0.5f)).customData = 1; + } + + CameraSystem.shake += 3; + SoundEngine.PlaySound(SoundID.NPCDeath1, Projectile.Center); + + trail?.Dispose(); + + trail = null; + cache = null; } - + + if (Projectile.Distance(Owner.Center) >= 200f) + Projectile.Center = Owner.Center; #endregion } @@ -254,10 +360,12 @@ public override void AI() float mult = MathHelper.Lerp(20f, 100f, 1f - Projectile.Distance(Target.Center) / 400f); direction *= mult; } - + Projectile.velocity = Vector2.Lerp(Projectile.velocity, direction, 0.05f); Projectile.rotation += Projectile.velocity.Length() * 0.02f; // more aggressive spin when attacking + Dust.NewDustPerfect(Projectile.Center + Main.rand.NextVector2CircularEdge(2f, 2f), + ModContent.DustType(), Main.rand.NextVector2Circular(2f, 2f), 0, TrailColor(false) with { A = 0 }, Main.rand.NextFloat(0.5f)).customData = Main.rand.NextBool() ? -1 : 1; } else { @@ -265,7 +373,7 @@ public override void AI() Projectile.velocity *= 0.985f; } - if (AttackDelay == 1 && Target is null) + if (Target is null || !Target.active) ResetToIdle(); #endregion @@ -274,27 +382,121 @@ public override void AI() public override bool PreDraw(ref Color lightColor) { + SpriteBatch spriteBatch = Main.spriteBatch; + Texture2D tex = Assets.Items.Crimson.ThoughtProvokerProjectile.Value; + Texture2D bloomTex = Assets.Masks.GlowAlpha.Value; + Texture2D starTex = Assets.StarTexture_Alt.Value; + + if (AttackState == 0) + { + DrawTrail(); + spriteBatch.Draw(bloomTex, Owner.Center - Main.screenPosition, null, TrailColor() with { A = 0}, 0f, bloomTex.Size() / 2f, Projectile.scale, 0f, 0f); + ModContent.GetInstance().QueueRenderAction("OverPlayers", () => + { + spriteBatch.Draw(bloomTex, Owner.Center - Main.screenPosition, null, TrailColor() with { A = 0 }, 0f, bloomTex.Size() / 2f, 0.3f / Owner.ownedProjectileCounts[Type], 0f, 0f); + spriteBatch.Draw(bloomTex, Owner.Center - Main.screenPosition, null, Color.White with { A = 0 }, 0f, bloomTex.Size() / 2f, 0.25f / Owner.ownedProjectileCounts[Type], 0f, 0f); + }); + } + float fade = 1f; if (resetTimer > 0) fade = 1f - resetTimer / 120f; - Main.spriteBatch.Draw(tex, Projectile.Center - Main.screenPosition, null, Color.White * fade, Projectile.rotation, tex.Size() / 2f, Projectile.scale, 0f, 0f); + //Main.spriteBatch.Draw(tex, Projectile.Center - Main.screenPosition, null, Color.White * fade, Projectile.rotation, tex.Size() / 2f, Projectile.scale, 0f, 0f); + + float scaleCalc = 1.25f + 0.2f * (float)Math.Sin(Main.GameUpdateCount * 0.02f); + + + Effect bodyShader = ShaderLoader.GetShader("ThinkerBody").Value; + + if (bodyShader != null) + { + Vector3 c = new Vector3(0.7f, 0.3f, 0.3f); + + if (AttackDelay > 0) + c = Vector3.Lerp(new Vector3(1f, 1f, 1f), new Vector3(0.7f, 0.3f, 0.3f), 1f - AttackDelay / 30f); + + bodyShader.Parameters["u_resolution"].SetValue(Assets.Bosses.TheThinkerBoss.Heart.Size() * scaleCalc); + bodyShader.Parameters["u_time"].SetValue(Main.GameUpdateCount * 0.015f); + + bodyShader.Parameters["mainbody_t"].SetValue(Assets.Bosses.TheThinkerBoss.Heart.Value); + bodyShader.Parameters["linemap_t"].SetValue(Assets.Bosses.TheThinkerBoss.HeartLine.Value); + bodyShader.Parameters["noisemap_t"].SetValue(Assets.Noise.ShaderNoise.Value); + bodyShader.Parameters["overlay_t"].SetValue(Assets.Bosses.TheThinkerBoss.HeartOver.Value); + bodyShader.Parameters["normal_t"].SetValue(Assets.Bosses.TheThinkerBoss.HeartNormal.Value); + bodyShader.Parameters["u_color"].SetValue(c * fade); + bodyShader.Parameters["u_fade"].SetValue(Vector3.Lerp(new Vector3(0.0f, 0.2f, 0.4f), new Vector3(0.3f, 0.5f, 0.3f), (float)Math.Sin(Main.GameUpdateCount * 0.01f)) * fade); // Lerp here so this is the same as the flower core at 0 scale + bodyShader.Parameters["mask_t"].SetValue(Assets.MagicPixel.Value); + + spriteBatch.End(); + spriteBatch.Begin(SpriteSortMode.Immediate, default, SamplerState.PointWrap, default, Main.Rasterizer, bodyShader, Main.GameViewMatrix.ZoomMatrix); + + Texture2D t = Assets.Bosses.TheThinkerBoss.Heart.Value; + spriteBatch.Draw(t, Projectile.Center - Main.screenPosition, null, Color.White, Projectile.rotation, t.Size() / 2f, scaleCalc * 0.35f, 0, 0); + + spriteBatch.End(); + spriteBatch.Begin(default, default, default, default, Main.Rasterizer, default, Main.GameViewMatrix.TransformationMatrix); + } + + spriteBatch.Draw(bloomTex, Projectile.Center - Main.screenPosition, null, TrailColor() with { A = 0 }, 0f, bloomTex.Size() / 2f, Projectile.scale, 0f, 0f); + spriteBatch.Draw(bloomTex, Projectile.Center - Main.screenPosition, null, TrailColor() with { A = 0 }, 0f, bloomTex.Size() / 2f, Projectile.scale * 0.5f, 0f, 0f); + spriteBatch.Draw(bloomTex, Projectile.Center - Main.screenPosition, null, Color.White with { A = 0 } * fade, 0f, bloomTex.Size() / 2f, Projectile.scale * 0.25f, 0f, 0f); + + if (AttackDelay > 0 && AttackState == 1) + { + float fadeIn = AttackDelay / 30f; + + spriteBatch.Draw(starTex, Projectile.Center - Main.screenPosition, null, TrailColor() with { A = 0 } * fadeIn, 0f, starTex.Size() / 2f, Projectile.scale, 0f, 0f); + spriteBatch.Draw(starTex, Projectile.Center - Main.screenPosition, null, TrailColor() with { A = 0 } * fadeIn, 0f, starTex.Size() / 2f, Projectile.scale * 0.5f, 0f, 0f); + spriteBatch.Draw(starTex, Projectile.Center - Main.screenPosition, null, Color.White with { A = 0 } * fadeIn, Projectile.rotation, starTex.Size() / 2f, Projectile.scale, 0f, 0f); + } return false; } + public override void OnKill(int timeLeft) + { + trail?.Dispose(); + + trail = null; + cache = null; + } + public override void OnHitNPC(NPC target, NPC.HitInfo hit, int damageDone) { if (Main.myPlayer == Projectile.owner) Projectile.NewProjectile(Projectile.GetSource_OnHit(target), Projectile.Center, Vector2.Zero, ModContent.ProjectileType(), Projectile.damage * 2, 5f, Projectile.owner, 50); + CameraSystem.shake = 5; + + SoundHelper.PlayPitched("Impacts/GoreHeavy", 0.5f, 0.1f, Projectile.Center); + + for (int i = 0; i < 10; i++) + { + float r = 0.2f + (float)Math.Sin(Main.GameUpdateCount * 0.1f) * 0.03f; + float g = 0.3f + (float)Math.Sin(Main.GameUpdateCount * 0.1f + 2f) * 0.05f; + float b = 0.7f + (float)Math.Sin(Main.GameUpdateCount * 0.1f + 4f) * 0.03f; + Color blue = new Color(r, g, b); + + r = 0.7f + (float)Math.Sin(Main.GameUpdateCount * 0.1f) * 0.03f; + g = 0.3f + (float)Math.Sin(Main.GameUpdateCount * 0.1f + 2f) * 0.05f; + b = 0.3f + (float)Math.Sin(Main.GameUpdateCount * 0.1f + 4f) * 0.03f; + Color red = new Color(r, g, b); + + Color c = Main.rand.NextBool() ? red : blue; + c.A = 0; + + Dust.NewDustPerfect(Projectile.Center, + ModContent.DustType(), -Projectile.velocity.RotatedByRandom(1f) * Main.rand.NextFloat(1f), 0, c, Main.rand.NextFloat(0.1f, 0.15f)).customData = Main.rand.NextBool() ? -1 : 1; + } + ResetToIdle(); } public override bool? CanHitNPC(NPC target) { - return target.whoAmI == TargetWhoAmI; + return target.whoAmI == TargetWhoAmI && target.CanBeChasedBy(Projectile); } public override bool MinionContactDamage() @@ -326,11 +528,141 @@ internal NPC FindTarget() internal void ResetToIdle() { - AttackState = 0; - Projectile.position = Owner.Center; - resetTimer = 120; AttackDelay = 45; + resetTimer = 120; + + trail?.Dispose(); + + trail = null; + cache = null; + + AttackState = 0; + Projectile.Center = Owner.Center + Main.rand.NextVector2CircularEdge(25f, 25f); + } + + #region PRIMITIVE DRAWING + private Color TrailColor(bool fadeColor = true) + { + float r = 0.2f + (float)Math.Sin(Main.GameUpdateCount * 0.1f) * 0.03f; + float g = 0.3f + (float)Math.Sin(Main.GameUpdateCount * 0.1f + 2f) * 0.05f; + float b = 0.7f + (float)Math.Sin(Main.GameUpdateCount * 0.1f + 4f) * 0.03f; + Color blue = new Color(r, g, b); + + r = 0.7f + (float)Math.Sin(Main.GameUpdateCount * 0.1f) * 0.03f; + g = 0.3f + (float)Math.Sin(Main.GameUpdateCount * 0.1f + 2f) * 0.05f; + b = 0.3f + (float)Math.Sin(Main.GameUpdateCount * 0.1f + 4f) * 0.03f; + Color red = new Color(r, g, b); + + float fade = 0f; + if (resetTimer < 30f) + fade = 1f - resetTimer / 30f; + else if (resetTimer <= 0) + fade = 1f; + + if (!fadeColor) + fade = 1f; + + return (Projectile.minionPos % 2 == 0 ? red : blue) * fade; + } + + private BezierCurve GetBezierCurve() + { + float lerper = 1f - Vector2.Distance(Projectile.Center, Owner.Center) / 200f; + + if (lerper > 1f || lerper < 0f || resetTimer > 30) + return null; + + Vector2[] curvePoints = + { + Vector2.Lerp(Projectile.Center + Projectile.velocity, Owner.Center, 0.3f) + new Vector2(0f, -MathHelper.Lerp(10f, 20f, lerper) * (float)Math.Sin(lifetime * 0.05f)).RotatedBy(Projectile.DirectionTo(Owner.Center).ToRotation()), + Vector2.Lerp(Projectile.Center + Projectile.velocity, Owner.Center, 0.6f) + new Vector2(0f, MathHelper.Lerp(30f, 15f, lerper) * (float)Math.Cos(lifetime * -0.075f)).RotatedBy(Projectile.DirectionTo(Owner.Center).ToRotation()), + }; + + var curve = new BezierCurve(new Vector2[] { + Projectile.Center + Projectile.velocity, + curvePoints[0], + curvePoints[1], + Owner.Center + }); + + return curve; + } + + private void ManageCaches() + { + BezierCurve curve = GetBezierCurve(); + if (curve is null) + { + trail?.Dispose(); + + trail = null; + cache = null; + return; + } + + if (cache is null) + { + cache = new List(); + + for (int i = 0; i < 26; i++) + { + cache.Add(Projectile.Center + Projectile.velocity); + } + } + + //cache.Add(Projectile.Center); + + //while (cache.Count > 15) + //{ + // cache.RemoveAt(0); + //} + + for (int k = 0; k < 26; k++) + { + int points = 26; + Vector2[] curvePositions = curve.GetPoints(points).ToArray(); + + cache[k] = curvePositions[k]; + } + } + + private void ManageTrail() + { + if (cache is null || GetBezierCurve() is null) + return; + + trail ??= new Trail(Main.instance.GraphicsDevice, 26, new NoTip(), factor => 5f, factor => TrailColor()); + + trail.Positions = cache.ToArray(); + trail.NextPosition = cache[25]; + } + + private void DrawTrail() + { + if (lifetime < 2) + return; + + ModContent.GetInstance().QueueRenderAction("OverPlayers", () => + { + Effect effect = ShaderLoader.GetShader("CeirosRing").Value; + + if (effect != null) + { + var world = Matrix.CreateTranslation(-Main.screenPosition.ToVector3()); + Matrix view = Matrix.Identity; + var projection = Matrix.CreateOrthographicOffCenter(0, Main.screenWidth, Main.screenHeight, 0, -1, 1); + + effect.Parameters["transformMatrix"].SetValue(world * view * projection); + effect.Parameters["time"].SetValue(Projectile.timeLeft * -0.01f); + effect.Parameters["repeats"].SetValue(5f); + effect.Parameters["sampleTexture"].SetValue(Assets.GlowTrail.Value); + + trail?.Render(effect); + } + }); } + + #endregion PRIMITIVEDRAWING } public class ThoughtProvokerExplosion : ModProjectile { @@ -339,10 +671,13 @@ public class ThoughtProvokerExplosion : ModProjectile private Trail trail; private Trail trail2; public override string Texture => AssetDirectory.Invisible; - private float Progress => Utils.Clamp(1 - Projectile.timeLeft / 30f, 0f, 1f); + private float Progress => Utils.Clamp(1 - Projectile.timeLeft / 45f, 0f, 1f); private float Radius => Projectile.ai[0] * Eases.EaseQuinticOut(Progress); - + public override void Load() + { + GraymatterBiome.onDrawHallucinationMap += DrawHallucinationExplosion; + } public override void SetDefaults() { Projectile.width = 2; @@ -351,7 +686,7 @@ public override void SetDefaults() Projectile.friendly = true; Projectile.tileCollide = false; Projectile.penetrate = -1; - Projectile.timeLeft = 30; + Projectile.timeLeft = 45; Projectile.usesLocalNPCImmunity = true; Projectile.localNPCHitCooldown = 20; @@ -364,22 +699,31 @@ public override void SetStaticDefaults() public override void AI() { + GraymatterBiome.forceGrayMatter = true; + if (Main.netMode != NetmodeID.Server) { ManageCaches(); ManageTrail(); } - /*for (int k = 0; k < 6; k++) + Color c = TrailColor(); + c.A = 0; + + Dust.NewDustPerfect(Projectile.Center + Main.rand.NextVector2CircularEdge(Radius, Radius), + ModContent.DustType(), Main.rand.NextVector2Circular(2f, 2f), 0, c, Main.rand.NextFloat(0.5f)).customData = Main.rand.NextBool() ? -1 : 1; + + for (int k = 0; k < 2; k++) { float rot = Main.rand.NextFloat(0, 6.28f); - Dust.NewDustPerfect(Projectile.Center + Vector2.One.RotatedBy(rot) * Radius, DustID.Torch, - Vector2.One.RotatedBy(rot) * 0.5f, 0, default, Main.rand.NextFloat(1.5f, 3f)).noGravity = true; + Dust.NewDustPerfect(Projectile.Center + Vector2.One.RotatedBy(rot) * Radius, ModContent.DustType(), + Vector2.One.RotatedBy(rot) * 0.5f, 0, default, Main.rand.NextFloat(0.5f, 1f)); + + Dust.NewDustPerfect(Projectile.Center + Vector2.One.RotatedBy(rot) * Radius, ModContent.DustType(), + Vector2.One.RotatedBy(rot) * 1f, 0, new Color(255, 255, 255, 0) * Main.rand.NextFloat(0.2f, 0.6f), Main.rand.NextFloat(0.25f, 0.4f)); - Dust.NewDustPerfect(Projectile.Center + Vector2.One.RotatedBy(rot) * Radius, DustID.Torch, - Vector2.One.RotatedBy(rot) * 0.5f + Main.rand.NextVector2Circular(2f, 2f), 50, default, Main.rand.NextFloat(0.5f, 1f)); - }*/ + } } public override bool? Colliding(Rectangle projHitbox, Rectangle targetHitbox) @@ -401,6 +745,21 @@ public override bool PreDraw(ref Color lightColor) return false; } + private Color TrailColor() + { + float r = 0.2f + (float)Math.Sin(Main.GameUpdateCount * 0.1f) * 0.03f; + float g = 0.3f + (float)Math.Sin(Main.GameUpdateCount * 0.1f + 2f) * 0.05f; + float b = 0.7f + (float)Math.Sin(Main.GameUpdateCount * 0.1f + 4f) * 0.03f; + Color blue = new Color(r, g, b); + + r = 0.7f + (float)Math.Sin(Main.GameUpdateCount * 0.1f) * 0.03f; + g = 0.3f + (float)Math.Sin(Main.GameUpdateCount * 0.1f + 2f) * 0.05f; + b = 0.3f + (float)Math.Sin(Main.GameUpdateCount * 0.1f + 4f) * 0.03f; + Color red = new Color(r, g, b); + + return Color.Lerp(blue, red, Progress); + } + private void ManageCaches() { if (cache is null) @@ -426,9 +785,11 @@ private void ManageCaches() private void ManageTrail() { - trail ??= new Trail(Main.instance.GraphicsDevice, 40, new TriangularTip(1), factor => 40 * (1f - Progress), factor => Color.Lerp(new Color(255, 180, 20), new Color(255, 20, 20), Eases.EaseQuinticInOut(Progress))); + trail ??= new Trail(Main.instance.GraphicsDevice, 40, new NoTip(), + factor => 40 * (1f - Progress), factor => TrailColor()); - trail2 ??= new Trail(Main.instance.GraphicsDevice, 40, new TriangularTip(1), factor => 30 * (1f - Progress), factor => Color.Lerp(new Color(255, 255, 255), new Color(255, 180, 20), Eases.EaseQuinticInOut(Progress))); + trail2 ??= new Trail(Main.instance.GraphicsDevice, 40, new NoTip(), + factor => 20 * (1f - Progress), factor => Color.White); trail.Positions = cache.ToArray(); trail.NextPosition = cache[39]; @@ -436,6 +797,49 @@ private void ManageTrail() trail2.Positions = cache.ToArray(); trail2.NextPosition = cache[39]; } + private void DrawHallucinationExplosion(SpriteBatch batch) + { + foreach (Projectile proj in Main.ActiveProjectiles) + { + if (proj.type == Type) + { + ThoughtProvokerExplosion p = proj.ModProjectile as ThoughtProvokerExplosion; + + Texture2D tex = Assets.Masks.GlowAlpha.Value; + //batch.Draw(tex, proj.Center - Main.screenPosition, null, new Color(255, 255, 255, 0) * (1f - p.Progress), 0, tex.Size() / 2f, MathHelper.Lerp(1f, 2.5f, Eases.EaseQuinticOut(p.Progress)), 0, 0); + + Main.spriteBatch.End(); + Main.spriteBatch.Begin(default, default, default, default, default, default, Main.GameViewMatrix.EffectMatrix); + + Effect effect = ShaderLoader.GetShader("Decay").Value; + + if (effect is null) + return; + + if (p.Progress >= 1f) + return; + + Main.spriteBatch.End(); + Main.spriteBatch.Begin(default, BlendState.AlphaBlend, Main.DefaultSamplerState, default, Main.Rasterizer, effect, Main.GameViewMatrix.TransformationMatrix); + + effect.Parameters["uTime"].SetValue(p.Progress * 0.2f); + + effect.Parameters["uImage1"].SetValue(Assets.Noise.PerlinNoise.Value); + effect.Parameters["uProgress"].SetValue(p.Progress); + Color color = new Color(255, 255, 255, 0); + + effect.Parameters["uColor"].SetValue(color.ToVector4()); + effect.Parameters["uOpacity"].SetValue(0f); + + effect.CurrentTechnique.Passes[0].Apply(); + + batch.Draw(tex, proj.Center - Main.screenPosition, null, Color.White, 0f, tex.Size() / 2f, MathHelper.Lerp(0.7f, 2f, Eases.EaseQuinticOut(p.Progress)), 0f, 0f); + + Main.spriteBatch.End(); + Main.spriteBatch.Begin(default, default, default, default, default, default, Main.GameViewMatrix.TransformationMatrix); + } + } + } public void DrawPrimitives() { @@ -455,14 +859,10 @@ public void DrawPrimitives() effect.Parameters["transformMatrix"].SetValue(world * view * projection); effect.Parameters["time"].SetValue(Projectile.timeLeft * -0.01f); effect.Parameters["repeats"].SetValue(5f); - effect.Parameters["sampleTexture"].SetValue(ModContent.Request(AssetDirectory.Assets + "FireTrail").Value); + effect.Parameters["sampleTexture"].SetValue(Assets.BlurryTrail.Value); trail?.Render(effect); trail2?.Render(effect); - - effect.Parameters["sampleTexture"].SetValue(ModContent.Request(AssetDirectory.Assets + "EnergyTrail").Value); - - trail2?.Render(effect); } }); } diff --git a/Effects/Source/Decay.fx b/Effects/Source/Decay.fx new file mode 100644 index 000000000..290c462f3 --- /dev/null +++ b/Effects/Source/Decay.fx @@ -0,0 +1,70 @@ +#include "Common.fxh" + +sampler uImage0 : register(s0); + +texture uImage1; +sampler2D uImage1Sampler = sampler_state +{ + texture = ; + magfilter = LINEAR; + minfilter = LINEAR; + mipfilter = LINEAR; + AddressU = wrap; + AddressV = wrap; +}; + +float3 uColor; +float3 uSecondaryColor; +float uOpacity; +float uSaturation; +float uRotation; +float uTime; +float4 uSourceRect; +float2 uWorldPosition; +float uDirection; +float3 uLightSource; +float2 uImageSize0; +float2 uImageSize1; +float power; +float speed; +float opacity; + +float uProgress; + +float4 PixelShaderFunction(float2 coords : TEXCOORD0) : COLOR0 +{ + float2 noiseCoords = coords + float2(uTime * 0.5, uTime * 0.1); + + float4 noiseColor = tex2D(uImage1Sampler, noiseCoords); + + float2 distortionOffset = (noiseColor.rg - 0.5) * 0.1; + + float2 uv = coords + distortionOffset; + + float4 shapeColor = tex2D(uImage0, uv); + + float4 finalColor = shapeColor * float4(uColor.r, uColor.g, uColor.b, uOpacity); + + float dissolveValue = noiseColor.r; + + float lerper = 1 - uProgress; + + float dist = length(coords - 0.5); + + // decay from the inside out based on the noise map provided + + if (dissolveValue > lerp(dist, 1, lerper)) + { + finalColor.rgb *= float3(0, 0, 0); + } + + return finalColor; +} + +technique Technique1 +{ + pass P0 + { + PixelShader = compile ps_3_0 PixelShaderFunction(); + } +} \ No newline at end of file diff --git a/StarlightRiver.csproj b/StarlightRiver.csproj index 462b61e36..0ddba2e18 100644 --- a/StarlightRiver.csproj +++ b/StarlightRiver.csproj @@ -10,6 +10,7 @@ + From 07062bdf31bab71ecd308ab6c5ba2a09df55972c Mon Sep 17 00:00:00 2001 From: SkippZzMods Date: Sat, 7 Feb 2026 16:34:57 -0500 Subject: [PATCH 4/7] complete --- Assets/Items/Crimson/ThoughtProvoker.png | Bin 800 -> 864 bytes .../Items/Crimson/Weapons.ThoughtProvoker.cs | 177 ++++++++++-------- 2 files changed, 104 insertions(+), 73 deletions(-) diff --git a/Assets/Items/Crimson/ThoughtProvoker.png b/Assets/Items/Crimson/ThoughtProvoker.png index 3d436e7356b19dc9828b131b40a0fc1de5caa8c4..61dbf83b6aaea8a94af07c89320629952663e95d 100644 GIT binary patch literal 864 zcmV-m1E2hfP)Px&8c9S!R7i=vmrY1iQ51l`XWGwHV_G^DDQZm`$fRThLA9ufiWcD@gwn!=)GlZf zl@w7#1TBI#K~NAzP?>=gq%Ha(5Hd@mU$7zjn+iqCF-zyQIQL+8EZoFBn|trM_uO~C zcg{WUJda6ac}@-h1sO8#P2vAJ9~?~qFnATrq2MN zaNaBc<^-kz(Dv$`53qfztiO>Ik}ZJ@YrJexz6Y=%SL_!r%my41WhzN_mK-(lW7r1> z4GCGKY_7D0(&n{30ib?WrM1zsx4i%ikEDDUCkZSRLU%+;GVtrC4-m=81)$+bJpiGS z3IGy4j{%4q!!ARn63-MLoxRm$uWxDh!6i{TNnLCmFixVP<2daAJPwLpqpe|6jQ^KQlyMc*h2X@5(D6X!y^crnSQdS&teUI|90EmoA)W!A{0?-z#1t7Y!$ubC^ zF9#sdTVm;zTt(l=_g|7u-4P9c81rEwiAu+rIsk%KPXdt8`Q8Ko&D(YW(AaXpveT#| z-s3nkXlL-11YPK9D*%b|t=71^G-w(2C2s>zF(_k=Hq8iu3h`mSS?``GxKyG;Nd~Kq z18~2;&oVfCLJ*X2rP0S*BnO7}2$7O?7`;29Zgb-3Es6Um7XdhA^bcRZwhXGmVE|&+ z*8<~Ny#9-{H5(;L(`yO$K2p)>n@l1vjjt{X*}0m#09;-n*}SH+3mC8W+!N_{CW`nf zwo+btRXEQw&@XYis4sXfwZ!I`0T1BjP!e!l1$hA7{e9w`PMN6vC?v(PO8~t2yk4eP zKLDV+RC1sCD$7KfW{P8(Ngp7b<+=5dmtLuARiu9j`$y$0Uk%xnB~ro0h7JOdcUpW> zxoWw!@j2tGMJ9q^mN9_QN|r8qpUP6Q_Y1Sk8PRXDj0t#HXSTus0000Px%+DSw~R9J=8m`_L)aTLctqif;6vRxe6q-|&I5(^QEQGcMuD-3*c)m@4N40)0Vae;PuLKsQv%h>USen5H`00a#tz^1=)|GTi`dXu022 z%!R4w4fy<|I@>LPVJ%0;c(+(oSDI=ug_kupB4 zQ~<~o3ScmG-^}|AH+4)MEzf=Y4nS`}FOcWcx2`MyuigRB9E(AujO{axYDGK0e2U(O zj{vZB>}22a^oh^zgO=qBNRCJ@Y^*H$?B#vYRj%Pomj}>)^#TAd7QO&5`F7H0C@YsN z|Gc{cz?E}xFtRwfpGR(v0C2DGG8kVbx)=vFutI0DRK>z9-%az{}-t09>;Z032wh!I~|IjeHo)8l4KIvahB~%?-*ev3j+S>y+!pdc`fjuO^+y zr_9jV*Mu=|`xx74HL1wtA&kXmwG)J(b}Cmjq|e7K6f;$k^ei=}_owLH_3&CAMC~(n z*LQqfMy5!k>&VIB*u3GtU@VZi+YZRc6na9`K4UrQOP@CSwofmA0**uNRxUxceLf}v)-!DY0000 200f) + pos = player.Center; - Dust.NewDustPerfect(Main.MouseWorld, - ModContent.DustType(), Main.rand.NextVector2CircularEdge(2f, 2f), 0, c with { A = 0 }, Main.rand.NextFloat(0.5f)).customData = -1; + for (int i = 0; i < 5; i++) + { + Color c = Main.rand.NextBool() ? new Color(236, 189, 64) : new Color(200, 80, 220); + + Dust.NewDustPerfect(pos, ModContent.DustType(), Main.rand.NextVector2CircularEdge(2f, 2f), 0, c with { A = 0 }, Main.rand.NextFloat(0.5f)).customData = -1; } - return false; } } @@ -146,8 +139,11 @@ public override void UpdateEquips() public class ThoughtProvokerProjectile : ModProjectile { + public const int RESET_TIME = 300; + private List cache; private Trail trail; + private Trail trail2; public int resetTimer; public int lifetime; @@ -266,7 +262,7 @@ public override void AI() float totalCount = Owner.ownedProjectileCounts[Type] > 0 ? Owner.ownedProjectileCounts[Type] : 1; - Vector2 idlePos = Owner.Center + new Vector2(0, 65).RotatedBy(MathHelper.ToRadians(Projectile.minionPos / totalCount * 360f + (Projectile.minionPos == totalCount ? 360f / totalCount : 0f)) + MathHelper.ToRadians(Lifetime)); + Vector2 idlePos = Owner.Center + new Vector2(0, 80).RotatedBy(MathHelper.ToRadians(Projectile.minionPos / totalCount * 360f + (Projectile.minionPos == totalCount ? 360f / totalCount : 0f)) + MathHelper.ToRadians(Lifetime)); float dist = Vector2.Distance(Projectile.Center, idlePos); @@ -324,10 +320,7 @@ public override void AI() CameraSystem.shake += 3; SoundEngine.PlaySound(SoundID.NPCDeath1, Projectile.Center); - trail?.Dispose(); - - trail = null; - cache = null; + DisposeTrails(); } if (Projectile.Distance(Owner.Center) >= 200f) @@ -388,26 +381,30 @@ public override bool PreDraw(ref Color lightColor) Texture2D bloomTex = Assets.Masks.GlowAlpha.Value; Texture2D starTex = Assets.StarTexture_Alt.Value; + Texture2D glow = Assets.Masks.Glow.Value; + + float fade = 1f; + if (resetTimer > 0) + fade = 1f - resetTimer / (float)RESET_TIME; + + float scaleCalc = 1f + 0.15f * (float)Math.Sin(Main.GameUpdateCount * 0.02f); + + spriteBatch.Draw(glow, Projectile.Center - Main.screenPosition, null, Color.Black * 0.15f * fade, 0f, glow.Size() / 2f, scaleCalc * 1.5f, 0, 0); + + spriteBatch.Draw(glow, Projectile.Center - Main.screenPosition, null, Color.Black * 0.5f * fade, 0f, glow.Size() / 2f, scaleCalc * 0.8f, 0, 0); + if (AttackState == 0) { DrawTrail(); - spriteBatch.Draw(bloomTex, Owner.Center - Main.screenPosition, null, TrailColor() with { A = 0}, 0f, bloomTex.Size() / 2f, Projectile.scale, 0f, 0f); ModContent.GetInstance().QueueRenderAction("OverPlayers", () => { spriteBatch.Draw(bloomTex, Owner.Center - Main.screenPosition, null, TrailColor() with { A = 0 }, 0f, bloomTex.Size() / 2f, 0.3f / Owner.ownedProjectileCounts[Type], 0f, 0f); spriteBatch.Draw(bloomTex, Owner.Center - Main.screenPosition, null, Color.White with { A = 0 }, 0f, bloomTex.Size() / 2f, 0.25f / Owner.ownedProjectileCounts[Type], 0f, 0f); }); - } + } - float fade = 1f; - if (resetTimer > 0) - fade = 1f - resetTimer / 120f; - - //Main.spriteBatch.Draw(tex, Projectile.Center - Main.screenPosition, null, Color.White * fade, Projectile.rotation, tex.Size() / 2f, Projectile.scale, 0f, 0f); - - float scaleCalc = 1.25f + 0.2f * (float)Math.Sin(Main.GameUpdateCount * 0.02f); - + //Main.spriteBatch.Draw(tex, Projectile.Center - Main.screenPosition, null, Color.White * fade, Projectile.rotation, tex.Size() / 2f, Projectile.scale, 0f, 0f); Effect bodyShader = ShaderLoader.GetShader("ThinkerBody").Value; @@ -440,10 +437,10 @@ public override bool PreDraw(ref Color lightColor) spriteBatch.Begin(default, default, default, default, Main.Rasterizer, default, Main.GameViewMatrix.TransformationMatrix); } - spriteBatch.Draw(bloomTex, Projectile.Center - Main.screenPosition, null, TrailColor() with { A = 0 }, 0f, bloomTex.Size() / 2f, Projectile.scale, 0f, 0f); - spriteBatch.Draw(bloomTex, Projectile.Center - Main.screenPosition, null, TrailColor() with { A = 0 }, 0f, bloomTex.Size() / 2f, Projectile.scale * 0.5f, 0f, 0f); - spriteBatch.Draw(bloomTex, Projectile.Center - Main.screenPosition, null, Color.White with { A = 0 } * fade, 0f, bloomTex.Size() / 2f, Projectile.scale * 0.25f, 0f, 0f); - + spriteBatch.Draw(bloomTex, Projectile.Center - Main.screenPosition, null, TrailColor() with { A = 0 } * 0.35f * fade, 0f, bloomTex.Size() / 2f, scaleCalc * 0.7f, 0f, 0f); + spriteBatch.Draw(bloomTex, Projectile.Center - Main.screenPosition, null, TrailColor() with { A = 0 } * 0.5f * fade, 0f, bloomTex.Size() / 2f, scaleCalc * 0.3f, 0f, 0f); + spriteBatch.Draw(bloomTex, Projectile.Center - Main.screenPosition, null, Color.White with { A = 0 } * fade * 0.6f, 0f, bloomTex.Size() / 2f, scaleCalc * 0.1f, 0f, 0f); + if (AttackDelay > 0 && AttackState == 1) { float fadeIn = AttackDelay / 30f; @@ -458,10 +455,7 @@ public override bool PreDraw(ref Color lightColor) public override void OnKill(int timeLeft) { - trail?.Dispose(); - - trail = null; - cache = null; + DisposeTrails(); } public override void OnHitNPC(NPC target, NPC.HitInfo hit, int damageDone) @@ -507,7 +501,7 @@ public override bool MinionContactDamage() internal Entity CheckCollisions(NPC target) { // we dont want the shield to break if its not actively "protecting" its owner, for example on spawn - if (Projectile.Distance(Owner.Center) > 75f) + if (Projectile.Distance(Owner.Center) > 125f) return null; Projectile closest = Main.projectile.Where(p => p.active && p.hostile && p.Distance(Projectile.Center) < 100f).OrderBy(p => p.Distance(Projectile.Center)).FirstOrDefault(); @@ -529,12 +523,9 @@ internal NPC FindTarget() internal void ResetToIdle() { AttackDelay = 45; - resetTimer = 120; - - trail?.Dispose(); + resetTimer = RESET_TIME; - trail = null; - cache = null; + DisposeTrails(); AttackState = 0; Projectile.Center = Owner.Center + Main.rand.NextVector2CircularEdge(25f, 25f); @@ -543,15 +534,26 @@ internal void ResetToIdle() #region PRIMITIVE DRAWING private Color TrailColor(bool fadeColor = true) { - float r = 0.2f + (float)Math.Sin(Main.GameUpdateCount * 0.1f) * 0.03f; - float g = 0.3f + (float)Math.Sin(Main.GameUpdateCount * 0.1f + 2f) * 0.05f; - float b = 0.7f + (float)Math.Sin(Main.GameUpdateCount * 0.1f + 4f) * 0.03f; - Color blue = new Color(r, g, b); + Color c = Color.Lerp(new Color(236, 189, 64), new Color(200, 80, 220), (float)Math.Sin(Main.GameUpdateCount * 0.01f)); + + if (Projectile.minionPos % 2 == 0) + c = Color.Lerp(new Color(200, 80, 220), new Color(236, 189, 64), (float)Math.Sin(Main.GameUpdateCount * 0.01f)); - r = 0.7f + (float)Math.Sin(Main.GameUpdateCount * 0.1f) * 0.03f; - g = 0.3f + (float)Math.Sin(Main.GameUpdateCount * 0.1f + 2f) * 0.05f; - b = 0.3f + (float)Math.Sin(Main.GameUpdateCount * 0.1f + 4f) * 0.03f; - Color red = new Color(r, g, b); + float fade = 0f; + if (resetTimer < 30f) + fade = 1f - resetTimer / 30f; + else if (resetTimer <= 0) + fade = 1f; + + if (!fadeColor) + fade = 1f; + + return c * fade; + } + + private Color AltTrailColor(bool fadeColor = true) + { + Color c = Color.Lerp(new Color(112, 249, 235), new Color(249, 255, 191), (float)Math.Sin(Main.GameUpdateCount * 0.035f)); float fade = 0f; if (resetTimer < 30f) @@ -562,7 +564,18 @@ private Color TrailColor(bool fadeColor = true) if (!fadeColor) fade = 1f; - return (Projectile.minionPos % 2 == 0 ? red : blue) * fade; + return c * fade; + } + + private Color FadingWhite() + { + float fade = 0f; + if (resetTimer < 30f) + fade = 1f - resetTimer / 30f; + else if (resetTimer <= 0) + fade = 1f; + + return Color.White * fade; } private BezierCurve GetBezierCurve() @@ -593,10 +606,8 @@ private void ManageCaches() BezierCurve curve = GetBezierCurve(); if (curve is null) { - trail?.Dispose(); + DisposeTrails(); - trail = null; - cache = null; return; } @@ -631,10 +642,15 @@ private void ManageTrail() if (cache is null || GetBezierCurve() is null) return; - trail ??= new Trail(Main.instance.GraphicsDevice, 26, new NoTip(), factor => 5f, factor => TrailColor()); + trail ??= new Trail(Main.instance.GraphicsDevice, 26, new NoTip(), factor => 2.5f, factor => TrailColor() * 0.5f); trail.Positions = cache.ToArray(); trail.NextPosition = cache[25]; + + trail2 ??= new Trail(Main.instance.GraphicsDevice, 26, new TriangularTip(1), factor => 7f, factor => Color.Lerp(FadingWhite(), AltTrailColor(), (float)Math.Sin(Main.GameUpdateCount * 0.01f)) * 0.5f); + + trail2.Positions = cache.ToArray(); + trail2.NextPosition = cache[25]; } private void DrawTrail() @@ -642,7 +658,7 @@ private void DrawTrail() if (lifetime < 2) return; - ModContent.GetInstance().QueueRenderAction("OverPlayers", () => + ModContent.GetInstance().QueueRenderAction("UnderProjectiles", () => { Effect effect = ShaderLoader.GetShader("CeirosRing").Value; @@ -658,10 +674,26 @@ private void DrawTrail() effect.Parameters["sampleTexture"].SetValue(Assets.GlowTrail.Value); trail?.Render(effect); + + effect.Parameters["repeats"].SetValue(1f); + effect.Parameters["time"].SetValue((float)Main.timeForVisualEffects * 0.01f); + effect.Parameters["sampleTexture"].SetValue(Assets.FireTrail.Value); + + trail2?.Render(effect); } }); } + private void DisposeTrails() + { + trail?.Dispose(); + trail2?.Dispose(); + + trail = null; + trail2 = null; + cache = null; + } + #endregion PRIMITIVEDRAWING } public class ThoughtProvokerExplosion : ModProjectile @@ -710,15 +742,22 @@ public override void AI() Color c = TrailColor(); c.A = 0; - Dust.NewDustPerfect(Projectile.Center + Main.rand.NextVector2CircularEdge(Radius, Radius), - ModContent.DustType(), Main.rand.NextVector2Circular(2f, 2f), 0, c, Main.rand.NextFloat(0.5f)).customData = Main.rand.NextBool() ? -1 : 1; + + if (Main.rand.NextBool()) + { + Dust.NewDustPerfect(Projectile.Center + Main.rand.NextVector2CircularEdge(Radius, Radius), + ModContent.DustType(), Main.rand.NextVector2Circular(2f, 2f), 0, c, Main.rand.NextFloat(0.5f)).customData = Main.rand.NextBool() ? -1 : 1; + } for (int k = 0; k < 2; k++) { float rot = Main.rand.NextFloat(0, 6.28f); - Dust.NewDustPerfect(Projectile.Center + Vector2.One.RotatedBy(rot) * Radius, ModContent.DustType(), + if (Main.rand.NextBool()) + { + Dust.NewDustPerfect(Projectile.Center + Vector2.One.RotatedBy(rot) * Radius, ModContent.DustType(), Vector2.One.RotatedBy(rot) * 0.5f, 0, default, Main.rand.NextFloat(0.5f, 1f)); + } Dust.NewDustPerfect(Projectile.Center + Vector2.One.RotatedBy(rot) * Radius, ModContent.DustType(), Vector2.One.RotatedBy(rot) * 1f, 0, new Color(255, 255, 255, 0) * Main.rand.NextFloat(0.2f, 0.6f), Main.rand.NextFloat(0.25f, 0.4f)); @@ -747,17 +786,9 @@ public override bool PreDraw(ref Color lightColor) private Color TrailColor() { - float r = 0.2f + (float)Math.Sin(Main.GameUpdateCount * 0.1f) * 0.03f; - float g = 0.3f + (float)Math.Sin(Main.GameUpdateCount * 0.1f + 2f) * 0.05f; - float b = 0.7f + (float)Math.Sin(Main.GameUpdateCount * 0.1f + 4f) * 0.03f; - Color blue = new Color(r, g, b); - - r = 0.7f + (float)Math.Sin(Main.GameUpdateCount * 0.1f) * 0.03f; - g = 0.3f + (float)Math.Sin(Main.GameUpdateCount * 0.1f + 2f) * 0.05f; - b = 0.3f + (float)Math.Sin(Main.GameUpdateCount * 0.1f + 4f) * 0.03f; - Color red = new Color(r, g, b); + Color c = Color.Lerp(new Color(236, 189, 64), new Color(200, 80, 220), Progress); - return Color.Lerp(blue, red, Progress); + return c; } private void ManageCaches() From af6239f878a576827d390d70145145f08c0a8a3f Mon Sep 17 00:00:00 2001 From: SkippZzMods Date: Sat, 7 Feb 2026 16:51:45 -0500 Subject: [PATCH 5/7] pixels --- Content/Items/Crimson/Weapons.ThoughtProvoker.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Content/Items/Crimson/Weapons.ThoughtProvoker.cs b/Content/Items/Crimson/Weapons.ThoughtProvoker.cs index e928da24e..202e4d64a 100644 --- a/Content/Items/Crimson/Weapons.ThoughtProvoker.cs +++ b/Content/Items/Crimson/Weapons.ThoughtProvoker.cs @@ -40,7 +40,7 @@ private void DrawShield(Player player, SpriteBatch spriteBatch) effect.Parameters["time"]?.SetValue(Main.GameUpdateCount * 0.02f); effect.Parameters["size"]?.SetValue(tex.Size() * 0.6f); effect.Parameters["opacity"]?.SetValue(fade); - effect.Parameters["pixelRes"]?.SetValue(2f); + effect.Parameters["pixelRes"]?.SetValue(4f); effect.Parameters["drawTexture"]?.SetValue(tex); effect.Parameters["noiseTexture"]?.SetValue(Assets.Noise.SwirlyNoiseLooping.Value); @@ -415,7 +415,7 @@ public override bool PreDraw(ref Color lightColor) if (AttackDelay > 0) c = Vector3.Lerp(new Vector3(1f, 1f, 1f), new Vector3(0.7f, 0.3f, 0.3f), 1f - AttackDelay / 30f); - bodyShader.Parameters["u_resolution"].SetValue(Assets.Bosses.TheThinkerBoss.Heart.Size() * scaleCalc); + bodyShader.Parameters["u_resolution"].SetValue(Assets.Bosses.TheThinkerBoss.Heart.Size() / 3 * scaleCalc); bodyShader.Parameters["u_time"].SetValue(Main.GameUpdateCount * 0.015f); bodyShader.Parameters["mainbody_t"].SetValue(Assets.Bosses.TheThinkerBoss.Heart.Value); From 709410a544ca29236f12f9f6b8ec57320fc8eeb7 Mon Sep 17 00:00:00 2001 From: bobfishkins23 Date: Sun, 22 Feb 2026 15:27:41 -0500 Subject: [PATCH 6/7] Formatting --- .../Items/Crimson/Weapons.ThoughtProvoker.cs | 164 +++++++++--------- 1 file changed, 79 insertions(+), 85 deletions(-) diff --git a/Content/Items/Crimson/Weapons.ThoughtProvoker.cs b/Content/Items/Crimson/Weapons.ThoughtProvoker.cs index 202e4d64a..ca32e065a 100644 --- a/Content/Items/Crimson/Weapons.ThoughtProvoker.cs +++ b/Content/Items/Crimson/Weapons.ThoughtProvoker.cs @@ -1,10 +1,6 @@ -using Microsoft.Xna.Framework.Graphics; -using StarlightRiver.Content.Biomes; +using StarlightRiver.Content.Biomes; using StarlightRiver.Content.Buffs.Summon; using StarlightRiver.Content.Dusts; -using StarlightRiver.Content.Items.Haunted; -using StarlightRiver.Content.Items.Palestone; -using StarlightRiver.Content.Projectiles; using StarlightRiver.Core.Loaders; using StarlightRiver.Core.Systems.CameraSystem; using StarlightRiver.Core.Systems.PixelationSystem; @@ -14,56 +10,18 @@ using Terraria.Audio; using Terraria.DataStructures; using Terraria.ID; -using static tModPorter.ProgressUpdate; namespace StarlightRiver.Content.Items.Crimson { public class ThoughtProvoker : ModItem { + public override string Texture => AssetDirectory.CrimsonItem + Name; + public override void Load() { StarlightPlayer.PostDrawEvent += DrawShield; } - private void DrawShield(Player player, SpriteBatch spriteBatch) - { - if (player.ownedProjectileCounts[ModContent.ProjectileType()] > 0) - { - Texture2D tex = Assets.Bosses.TheThinkerBoss.ShieldMap.Value; - - Effect effect = ShaderLoader.GetShader("BrainShield").Value; - - if (effect != null) - { - float fade = player.GetModPlayer().shieldFade / 30f; - - effect.Parameters["time"]?.SetValue(Main.GameUpdateCount * 0.02f); - effect.Parameters["size"]?.SetValue(tex.Size() * 0.6f); - effect.Parameters["opacity"]?.SetValue(fade); - effect.Parameters["pixelRes"]?.SetValue(4f); - - effect.Parameters["drawTexture"]?.SetValue(tex); - effect.Parameters["noiseTexture"]?.SetValue(Assets.Noise.SwirlyNoiseLooping.Value); - effect.Parameters["pulseTexture"]?.SetValue(Assets.Noise.PerlinNoise.Value); - effect.Parameters["edgeTexture"]?.SetValue(Assets.Bosses.TheThinkerBoss.ShieldEdge.Value); - effect.Parameters["outTexture"]?.SetValue(Assets.Bosses.TheThinkerBoss.ShieldMapOut.Value); - effect.Parameters["color"].SetValue(Vector3.Lerp(Vector3.One, new Vector3(1, 0.5f, 0.5f), 1f)); - - spriteBatch.End(); - spriteBatch.Begin(default, BlendState.Additive, default, default, Main.Rasterizer, effect, Main.GameViewMatrix.TransformationMatrix); - - spriteBatch.Draw(tex, player.Center + new Vector2(0f, player.gfxOffY) - Main.screenPosition, null, Color.White, 0, tex.Size() / 2f, 0.18f, SpriteEffects.FlipVertically, 0); - - spriteBatch.End(); - spriteBatch.Begin(default, default, default, default, Main.Rasterizer, default, Main.GameViewMatrix.TransformationMatrix); - } - - effect = ShaderLoader.GetShader("BrainShield").Value; - - } - } - - public override string Texture => AssetDirectory.CrimsonItem + Name; public override void SetStaticDefaults() { DisplayName.SetDefault("Thought Provoker"); @@ -99,21 +57,56 @@ public override bool Shoot(Player player, EntitySource_ItemUse_WithAmmo source, { player.AddBuff(Item.buffType, 2); Projectile.NewProjectileDirect(source, Main.MouseWorld, velocity, type, damage, knockback, Main.myPlayer).originalDamage = Item.damage; - + Vector2 pos = Main.MouseWorld; if (Vector2.Distance(Main.MouseWorld, player.Center) > 200f) pos = player.Center; for (int i = 0; i < 5; i++) - { + { Color c = Main.rand.NextBool() ? new Color(236, 189, 64) : new Color(200, 80, 220); - + Dust.NewDustPerfect(pos, ModContent.DustType(), Main.rand.NextVector2CircularEdge(2f, 2f), 0, c with { A = 0 }, Main.rand.NextFloat(0.5f)).customData = -1; } return false; } + + private void DrawShield(Player player, SpriteBatch spriteBatch) + { + if (player.ownedProjectileCounts[ModContent.ProjectileType()] > 0) + { + Texture2D tex = Assets.Bosses.TheThinkerBoss.ShieldMap.Value; + + Effect effect = ShaderLoader.GetShader("BrainShield").Value; + + if (effect != null) + { + float fade = player.GetModPlayer().shieldFade / 30f; + + effect.Parameters["time"]?.SetValue(Main.GameUpdateCount * 0.02f); + effect.Parameters["size"]?.SetValue(tex.Size() * 0.6f); + effect.Parameters["opacity"]?.SetValue(fade); + effect.Parameters["pixelRes"]?.SetValue(4f); + + effect.Parameters["drawTexture"]?.SetValue(tex); + effect.Parameters["noiseTexture"]?.SetValue(Assets.Noise.SwirlyNoiseLooping.Value); + effect.Parameters["pulseTexture"]?.SetValue(Assets.Noise.PerlinNoise.Value); + effect.Parameters["edgeTexture"]?.SetValue(Assets.Bosses.TheThinkerBoss.ShieldEdge.Value); + effect.Parameters["outTexture"]?.SetValue(Assets.Bosses.TheThinkerBoss.ShieldMapOut.Value); + effect.Parameters["color"].SetValue(Vector3.Lerp(Vector3.One, new Vector3(1, 0.5f, 0.5f), 1f)); + + spriteBatch.End(); + spriteBatch.Begin(default, BlendState.Additive, default, default, Main.Rasterizer, effect, Main.GameViewMatrix.TransformationMatrix); + + spriteBatch.Draw(tex, player.Center + new Vector2(0f, player.gfxOffY) - Main.screenPosition, null, Color.White, 0, tex.Size() / 2f, 0.18f, SpriteEffects.FlipVertically, 0); + + spriteBatch.End(); + spriteBatch.Begin(default, default, default, default, Main.Rasterizer, default, Main.GameViewMatrix.TransformationMatrix); + } + } + } } public class ThoughtProvokerPlayer : ModPlayer @@ -129,17 +122,21 @@ public override void UpdateEquips() if (shieldingThinkers > 0) { Player.endurance += 0.05f * shieldingThinkers; + if (shieldFade < 30) shieldFade++; } else if (shieldFade > 0) - shieldFade--; + { + shieldFade--; + } } } public class ThoughtProvokerProjectile : ModProjectile { public const int RESET_TIME = 300; + public const int MAX_CHASE_RANGE = 500; private List cache; private Trail trail; @@ -147,10 +144,19 @@ public class ThoughtProvokerProjectile : ModProjectile public int resetTimer; public int lifetime; + public ref float TargetWhoAmI => ref Projectile.ai[1]; public NPC Target => TargetWhoAmI > -1 ? Main.npc[(int)TargetWhoAmI] : null; public bool FoundTarget => Target != null; + public ref float AttackState => ref Projectile.ai[0]; + public ref float EnemyWhoAmI => ref Projectile.ai[1]; + public ref float AttackDelay => ref Projectile.ai[2]; + + public Player Owner => Main.player[Projectile.owner]; + + public override string Texture => AssetDirectory.CrimsonItem + Name; + public NPC MinionTarget { get @@ -161,6 +167,7 @@ public NPC MinionTarget return null; } } + public int Lifetime { get @@ -171,7 +178,7 @@ public int Lifetime } else { - Projectile proj = Main.projectile.Where(p => p.active && p.type == Type && p.owner == Projectile.owner && p.minionPos == 0).FirstOrDefault(); + Projectile proj = Main.projectile.FirstOrDefault(p => p.active && p.type == Type && p.owner == Projectile.owner && p.minionPos == 0); if (proj != null) { var brain = proj.ModProjectile as ThoughtProvokerProjectile; @@ -184,13 +191,6 @@ public int Lifetime } } - public const int maxMinionChaseRange = 500; - public ref float AttackState => ref Projectile.ai[0]; - public ref float EnemyWhoAmI => ref Projectile.ai[1]; - public ref float AttackDelay => ref Projectile.ai[2]; - public Player Owner => Main.player[Projectile.owner]; - public override string Texture => AssetDirectory.CrimsonItem + Name; - public override void SetStaticDefaults() { DisplayName.SetDefault("Thinky Junior"); @@ -347,7 +347,9 @@ public override void AI() Vector2 direction = Target.Center - Projectile.Center; direction.Normalize(); if (Projectile.Distance(Target.Center) > 400f) + { direction *= 20f; + } else { float mult = MathHelper.Lerp(20f, 100f, 1f - Projectile.Distance(Target.Center) / 400f); @@ -388,7 +390,7 @@ public override bool PreDraw(ref Color lightColor) fade = 1f - resetTimer / (float)RESET_TIME; float scaleCalc = 1f + 0.15f * (float)Math.Sin(Main.GameUpdateCount * 0.02f); - + spriteBatch.Draw(glow, Projectile.Center - Main.screenPosition, null, Color.Black * 0.15f * fade, 0f, glow.Size() / 2f, scaleCalc * 1.5f, 0, 0); spriteBatch.Draw(glow, Projectile.Center - Main.screenPosition, null, Color.Black * 0.5f * fade, 0f, glow.Size() / 2f, scaleCalc * 0.8f, 0, 0); @@ -402,15 +404,15 @@ public override bool PreDraw(ref Color lightColor) spriteBatch.Draw(bloomTex, Owner.Center - Main.screenPosition, null, TrailColor() with { A = 0 }, 0f, bloomTex.Size() / 2f, 0.3f / Owner.ownedProjectileCounts[Type], 0f, 0f); spriteBatch.Draw(bloomTex, Owner.Center - Main.screenPosition, null, Color.White with { A = 0 }, 0f, bloomTex.Size() / 2f, 0.25f / Owner.ownedProjectileCounts[Type], 0f, 0f); }); - } - + } + //Main.spriteBatch.Draw(tex, Projectile.Center - Main.screenPosition, null, Color.White * fade, Projectile.rotation, tex.Size() / 2f, Projectile.scale, 0f, 0f); Effect bodyShader = ShaderLoader.GetShader("ThinkerBody").Value; if (bodyShader != null) { - Vector3 c = new Vector3(0.7f, 0.3f, 0.3f); + var c = new Vector3(0.7f, 0.3f, 0.3f); if (AttackDelay > 0) c = Vector3.Lerp(new Vector3(1f, 1f, 1f), new Vector3(0.7f, 0.3f, 0.3f), 1f - AttackDelay / 30f); @@ -472,12 +474,12 @@ public override void OnHitNPC(NPC target, NPC.HitInfo hit, int damageDone) float r = 0.2f + (float)Math.Sin(Main.GameUpdateCount * 0.1f) * 0.03f; float g = 0.3f + (float)Math.Sin(Main.GameUpdateCount * 0.1f + 2f) * 0.05f; float b = 0.7f + (float)Math.Sin(Main.GameUpdateCount * 0.1f + 4f) * 0.03f; - Color blue = new Color(r, g, b); + var blue = new Color(r, g, b); r = 0.7f + (float)Math.Sin(Main.GameUpdateCount * 0.1f) * 0.03f; g = 0.3f + (float)Math.Sin(Main.GameUpdateCount * 0.1f + 2f) * 0.05f; b = 0.3f + (float)Math.Sin(Main.GameUpdateCount * 0.1f + 4f) * 0.03f; - Color red = new Color(r, g, b); + var red = new Color(r, g, b); Color c = Main.rand.NextBool() ? red : blue; c.A = 0; @@ -488,6 +490,7 @@ public override void OnHitNPC(NPC target, NPC.HitInfo hit, int damageDone) ResetToIdle(); } + public override bool? CanHitNPC(NPC target) { return target.whoAmI == TargetWhoAmI && target.CanBeChasedBy(Projectile); @@ -528,14 +531,14 @@ internal void ResetToIdle() DisposeTrails(); AttackState = 0; - Projectile.Center = Owner.Center + Main.rand.NextVector2CircularEdge(25f, 25f); + Projectile.Center = Owner.Center + Main.rand.NextVector2CircularEdge(25f, 25f); } #region PRIMITIVE DRAWING private Color TrailColor(bool fadeColor = true) { - Color c = Color.Lerp(new Color(236, 189, 64), new Color(200, 80, 220), (float)Math.Sin(Main.GameUpdateCount * 0.01f)); - + var c = Color.Lerp(new Color(236, 189, 64), new Color(200, 80, 220), (float)Math.Sin(Main.GameUpdateCount * 0.01f)); + if (Projectile.minionPos % 2 == 0) c = Color.Lerp(new Color(200, 80, 220), new Color(236, 189, 64), (float)Math.Sin(Main.GameUpdateCount * 0.01f)); @@ -553,7 +556,7 @@ private Color TrailColor(bool fadeColor = true) private Color AltTrailColor(bool fadeColor = true) { - Color c = Color.Lerp(new Color(112, 249, 235), new Color(249, 255, 191), (float)Math.Sin(Main.GameUpdateCount * 0.035f)); + var c = Color.Lerp(new Color(112, 249, 235), new Color(249, 255, 191), (float)Math.Sin(Main.GameUpdateCount * 0.035f)); float fade = 0f; if (resetTimer < 30f) @@ -613,7 +616,7 @@ private void ManageCaches() if (cache is null) { - cache = new List(); + cache = []; for (int i = 0; i < 26; i++) { @@ -621,18 +624,11 @@ private void ManageCaches() } } - //cache.Add(Projectile.Center); - - //while (cache.Count > 15) - //{ - // cache.RemoveAt(0); - //} - for (int k = 0; k < 26; k++) { int points = 26; Vector2[] curvePositions = curve.GetPoints(points).ToArray(); - + cache[k] = curvePositions[k]; } } @@ -696,20 +692,24 @@ private void DisposeTrails() #endregion PRIMITIVEDRAWING } + public class ThoughtProvokerExplosion : ModProjectile { private List cache; private Trail trail; private Trail trail2; + public override string Texture => AssetDirectory.Invisible; private float Progress => Utils.Clamp(1 - Projectile.timeLeft / 45f, 0f, 1f); private float Radius => Projectile.ai[0] * Eases.EaseQuinticOut(Progress); + public override void Load() { GraymatterBiome.onDrawHallucinationMap += DrawHallucinationExplosion; } + public override void SetDefaults() { Projectile.width = 2; @@ -742,7 +742,6 @@ public override void AI() Color c = TrailColor(); c.A = 0; - if (Main.rand.NextBool()) { Dust.NewDustPerfect(Projectile.Center + Main.rand.NextVector2CircularEdge(Radius, Radius), @@ -773,11 +772,6 @@ public override void AI() return Collision.CheckAABBvLineCollision(targetHitbox.TopLeft(), targetHitbox.Size(), Projectile.Center, Projectile.Center + line); } - public override void OnHitNPC(NPC target, NPC.HitInfo hit, int damageDone) - { - //target.AddBuff(BuffID.OnFire, 300); - } - public override bool PreDraw(ref Color lightColor) { DrawPrimitives(); @@ -786,7 +780,7 @@ public override bool PreDraw(ref Color lightColor) private Color TrailColor() { - Color c = Color.Lerp(new Color(236, 189, 64), new Color(200, 80, 220), Progress); + var c = Color.Lerp(new Color(236, 189, 64), new Color(200, 80, 220), Progress); return c; } @@ -834,7 +828,7 @@ private void DrawHallucinationExplosion(SpriteBatch batch) { if (proj.type == Type) { - ThoughtProvokerExplosion p = proj.ModProjectile as ThoughtProvokerExplosion; + var p = proj.ModProjectile as ThoughtProvokerExplosion; Texture2D tex = Assets.Masks.GlowAlpha.Value; //batch.Draw(tex, proj.Center - Main.screenPosition, null, new Color(255, 255, 255, 0) * (1f - p.Progress), 0, tex.Size() / 2f, MathHelper.Lerp(1f, 2.5f, Eases.EaseQuinticOut(p.Progress)), 0, 0); @@ -857,7 +851,7 @@ private void DrawHallucinationExplosion(SpriteBatch batch) effect.Parameters["uImage1"].SetValue(Assets.Noise.PerlinNoise.Value); effect.Parameters["uProgress"].SetValue(p.Progress); - Color color = new Color(255, 255, 255, 0); + var color = new Color(255, 255, 255, 0); effect.Parameters["uColor"].SetValue(color.ToVector4()); effect.Parameters["uOpacity"].SetValue(0f); From 3c7f6ffd75efcaa3b3ced561d51d6a1559b6cdce Mon Sep 17 00:00:00 2001 From: bobfishkins23 Date: Sun, 22 Feb 2026 17:03:47 -0500 Subject: [PATCH 7/7] Texture fix, minor behavior changes to smooth motion --- .../Crimson/ThoughtProvokerProjectile.png | Bin 462 -> 183 bytes .../ThoughtProvokerProjectileNormal.png | Bin 0 -> 1330 bytes .../Crimson/ThoughtProvokerProjectileOver.png | Bin 0 -> 118 bytes .../Items/Crimson/Weapons.ThoughtProvoker.cs | 94 +++++++++--------- 4 files changed, 46 insertions(+), 48 deletions(-) create mode 100644 Assets/Items/Crimson/ThoughtProvokerProjectileNormal.png create mode 100644 Assets/Items/Crimson/ThoughtProvokerProjectileOver.png diff --git a/Assets/Items/Crimson/ThoughtProvokerProjectile.png b/Assets/Items/Crimson/ThoughtProvokerProjectile.png index db56c1042855b0ffbd3c92a29b4891546c7250f7..ad517287c9d94027bddd5d383e0cf848be2bcb8c 100644 GIT binary patch delta 155 zcmV;M0A&Bp1GfQ?B!7NML_t(oh3%Fx5`ZuW1cU$oGd5mBL=xf{7}?fA?zRc7{T0()V7r0h1QgRZEHL)Ch8+L^002ov JPDHLkV1jGfL7D&n delta 436 zcmV;l0Zab30nP)EB!2;OQb$4nuFf3k0004qNklLx;Z*n$+qvgCQ4#`-$K!iheY@Qz zp*dCNeLY(2KlpQ3O0d~%N+)Dl1|^BA&WmoKp&vHEVzB^Vy?$U1> zntB_A=E+2K1Ieq&H5TXd*&D0J*Xz}*w^}W)u6epXx`Bo**rXxUYZYMCkdJ5nJ!~``-AOiTDOW&+TL~skETZ%yPK|AkTAeU7>yB8@OC9 z3C=rOJwKgJ;D7Wu^b}ZQGBBUd0a&e80Cc-uaNdC0H@*S=uxH_TJOVHn48XZ_VS8%n zbUNNTGGOuLn-@{eJ%;U&WS?i4dGEXh)I!UAtCv9U}>hOZ})lZM=gSGa9`8SfRFFs>o339IS~ld)U-%1=M| zEb4E-XN_Y`9Wf&hJ`74jMP6%OnOEgi55D;*&3OOM_dW+KPt{iIo2W5|HY^xt4wE=p z9S}N$vlMif8<1fmgCh?bwtd`s+AJEUbv)NNYh0A)8Yka#P*342eGb}0TZgHS=h~dR zUF4QS>=waPygA%}?AATP^XTJ29}i1BoP2x6&CWMd8|D_57Uumc@^h&GGdYL2#EY7D zeK_msY}-?g9wSvMs?!ZfGPJ~=w{5&rhC5R@I;#iI`mif`3UOg9V9_2xGf>bYY-X9c zEVe7@w2lW2ag+OyQd+$?w{Af85PM8@I9$gU=k&re9Gzl(X8D3)VW?mO`@RD#004sr z^+{#IH1l+co08(4><4Ka28&hJ4H!IFOXHgFUgYDm@WPY2J!L*eSY%b`fM0dH2ABZ{ zBv1<8Q(w>9`J^Xv2y@ome7LPSw-|Z^Vh_2*!zmp<3&&6T;nOmlwJ>*9M;9azFyP=C zz$UQDyrpi*)yQ>op zifJDZ&R|uP2Xtel6~(n(q~$#BcEL`g-N|8VLq-5L1xJ(LJ*!7&b=)m+URYMO;$FKt z;7(ZrPObscj%*@3QH{}9V2eWN7oqHId1}+v#!c)g24JjhJJ)eq^E`)jW}VR&_u{Hl z6*?tG?k)N4uigjn?q42JovK72A`xWfku9<&)Ce~jki4We$2wV?*e3ZR6rl)J?4|bq9*t(EyC(7VwE+8j=1-N?EyknC>~pnUQK2q zL4ptf$OTmZWP#1VEY8B>Se^)SZU>~9u_*Kw{Bm*<1PD@3oHOf0L0db*SXB4o({FmRlkNvvgMGH-o zQ|+p|;G%a^CAtG(D2CO-N?*VgEJAa-{D%B+1KU-#&zzKsnv%jlEG#1cHij zF)Xw~t56gDqwjoi_FDm$MTv5tN^qe&z0;cvFs>mirj;sC6&$!V``iln?)M%5_}#A` zO6~HNy8pvLSTDO%4f4lt-aPwr09QT$s9&wYsV)NM#jd*d=ccyj0N!}>K7c>|>XFo3 zl#76=QVsCm|M1_<{vQFZd^pUV-rxct@9wT!R07*qoM6N<$f||~NZU6uP literal 0 HcmV?d00001 diff --git a/Assets/Items/Crimson/ThoughtProvokerProjectileOver.png b/Assets/Items/Crimson/ThoughtProvokerProjectileOver.png new file mode 100644 index 0000000000000000000000000000000000000000..fe280ac4781a2d9b61fbec38686341083600a3ca GIT binary patch literal 118 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzTTd6qkcif|mkqfX6nLC39{YXY zQcq7$$g%Ll{*5L}MWR?4_6Og}xE&nOwORY^kqN79mVAvpuYZ84hLM5cMaE0()] > 0) + var count = player.ownedProjectileCounts[ModContent.ProjectileType()]; + + if (count > 0) { Texture2D tex = Assets.Bosses.TheThinkerBoss.ShieldMap.Value; @@ -83,24 +85,24 @@ private void DrawShield(Player player, SpriteBatch spriteBatch) if (effect != null) { - float fade = player.GetModPlayer().shieldFade / 30f; + float fade = player.GetModPlayer().shieldFade / 120f; effect.Parameters["time"]?.SetValue(Main.GameUpdateCount * 0.02f); - effect.Parameters["size"]?.SetValue(tex.Size() * 0.6f); + effect.Parameters["size"]?.SetValue(tex.Size() * 0.2f); effect.Parameters["opacity"]?.SetValue(fade); - effect.Parameters["pixelRes"]?.SetValue(4f); + effect.Parameters["pixelRes"]?.SetValue(2f); effect.Parameters["drawTexture"]?.SetValue(tex); effect.Parameters["noiseTexture"]?.SetValue(Assets.Noise.SwirlyNoiseLooping.Value); effect.Parameters["pulseTexture"]?.SetValue(Assets.Noise.PerlinNoise.Value); effect.Parameters["edgeTexture"]?.SetValue(Assets.Bosses.TheThinkerBoss.ShieldEdge.Value); effect.Parameters["outTexture"]?.SetValue(Assets.Bosses.TheThinkerBoss.ShieldMapOut.Value); - effect.Parameters["color"].SetValue(Vector3.Lerp(Vector3.One, new Vector3(1, 0.5f, 0.5f), 1f)); + effect.Parameters["color"].SetValue(new Vector3(1f, 0.5f, 0.5f)); spriteBatch.End(); spriteBatch.Begin(default, BlendState.Additive, default, default, Main.Rasterizer, effect, Main.GameViewMatrix.TransformationMatrix); - spriteBatch.Draw(tex, player.Center + new Vector2(0f, player.gfxOffY) - Main.screenPosition, null, Color.White, 0, tex.Size() / 2f, 0.18f, SpriteEffects.FlipVertically, 0); + spriteBatch.Draw(tex, player.Center + new Vector2(0f, player.gfxOffY) - Main.screenPosition, null, Color.White, 0, tex.Size() / 2f, 0.2f, SpriteEffects.FlipVertically, 0); spriteBatch.End(); spriteBatch.Begin(default, default, default, default, Main.Rasterizer, default, Main.GameViewMatrix.TransformationMatrix); @@ -115,16 +117,27 @@ public class ThoughtProvokerPlayer : ModPlayer public override void UpdateEquips() { + var count = Player.ownedProjectileCounts[ModContent.ProjectileType()]; + + // Max effect appears at 5 minions + if (count < 5) + count = 5; + // 5% increased endurance per Thinky Jr - int shieldingThinkers = Main.projectile.Where(p => p.active && p.type == ModContent.ProjectileType() - && p.owner == Player.whoAmI && (p.ModProjectile as ThoughtProvokerProjectile).AttackState == 0 && (p.ModProjectile as ThoughtProvokerProjectile).resetTimer <= 0).Count(); + int shieldingThinkers = Main.projectile.Count(p => p.active && p.type == ModContent.ProjectileType() + && p.owner == Player.whoAmI && (p.ModProjectile as ThoughtProvokerProjectile).AttackState == 0 && (p.ModProjectile as ThoughtProvokerProjectile).resetTimer <= 0); + + int maxFade = (int)(120 * (shieldingThinkers / (float)count)); if (shieldingThinkers > 0) { Player.endurance += 0.05f * shieldingThinkers; - if (shieldFade < 30) + if (shieldFade < maxFade) shieldFade++; + + if (shieldFade > maxFade) + shieldFade--; } else if (shieldFade > 0) { @@ -262,29 +275,12 @@ public override void AI() float totalCount = Owner.ownedProjectileCounts[Type] > 0 ? Owner.ownedProjectileCounts[Type] : 1; - Vector2 idlePos = Owner.Center + new Vector2(0, 80).RotatedBy(MathHelper.ToRadians(Projectile.minionPos / totalCount * 360f + (Projectile.minionPos == totalCount ? 360f / totalCount : 0f)) + MathHelper.ToRadians(Lifetime)); + Vector2 idlePos = Owner.Center + (Vector2.UnitY * Owner.gfxOffY) + new Vector2(0, 80).RotatedBy(MathHelper.ToRadians(Projectile.minionPos / totalCount * 360f + (Projectile.minionPos == totalCount ? 360f / totalCount : 0f)) + MathHelper.ToRadians(Lifetime)); float dist = Vector2.Distance(Projectile.Center, idlePos); Vector2 toIdlePos = idlePos - Projectile.Center; - if (toIdlePos.Length() < 0.0001f) - { - toIdlePos = Vector2.Zero; - } - else - { - float speed = 50f; - if (dist < 1000f) - speed = MathHelper.Lerp(15f, 50f, dist / 1000f); - - if (dist < 100f) - speed = MathHelper.Lerp(3f, 15f, dist / 100f); - - toIdlePos.Normalize(); - toIdlePos *= speed; - } - - Projectile.velocity = (Projectile.velocity * (5f - 1) + toIdlePos) / 5f; + Projectile.velocity = toIdlePos * 0.1f; if (dist > 2000f) { @@ -323,7 +319,7 @@ public override void AI() DisposeTrails(); } - if (Projectile.Distance(Owner.Center) >= 200f) + if (Projectile.Distance(Owner.Center) >= 2000f) Projectile.Center = Owner.Center; #endregion @@ -383,7 +379,7 @@ public override bool PreDraw(ref Color lightColor) Texture2D bloomTex = Assets.Masks.GlowAlpha.Value; Texture2D starTex = Assets.StarTexture_Alt.Value; - Texture2D glow = Assets.Masks.Glow.Value; + Texture2D glow = Assets.Masks.GlowSoft.Value; float fade = 1f; if (resetTimer > 0) @@ -391,9 +387,9 @@ public override bool PreDraw(ref Color lightColor) float scaleCalc = 1f + 0.15f * (float)Math.Sin(Main.GameUpdateCount * 0.02f); - spriteBatch.Draw(glow, Projectile.Center - Main.screenPosition, null, Color.Black * 0.15f * fade, 0f, glow.Size() / 2f, scaleCalc * 1.5f, 0, 0); + spriteBatch.Draw(glow, Projectile.Center - Main.screenPosition, null, Color.Black * fade, 0f, glow.Size() / 2f, scaleCalc * 1.2f, 0, 0); - spriteBatch.Draw(glow, Projectile.Center - Main.screenPosition, null, Color.Black * 0.5f * fade, 0f, glow.Size() / 2f, scaleCalc * 0.8f, 0, 0); + //spriteBatch.Draw(glow, Projectile.Center - Main.screenPosition, null, Color.Black * 0.5f * fade, 0f, glow.Size() / 2f, scaleCalc * 0.8f, 0, 0); if (AttackState == 0) { @@ -417,31 +413,31 @@ public override bool PreDraw(ref Color lightColor) if (AttackDelay > 0) c = Vector3.Lerp(new Vector3(1f, 1f, 1f), new Vector3(0.7f, 0.3f, 0.3f), 1f - AttackDelay / 30f); - bodyShader.Parameters["u_resolution"].SetValue(Assets.Bosses.TheThinkerBoss.Heart.Size() / 3 * scaleCalc); + bodyShader.Parameters["u_resolution"].SetValue(Assets.Items.Crimson.ThoughtProvokerProjectile.Size() * scaleCalc); bodyShader.Parameters["u_time"].SetValue(Main.GameUpdateCount * 0.015f); - bodyShader.Parameters["mainbody_t"].SetValue(Assets.Bosses.TheThinkerBoss.Heart.Value); + bodyShader.Parameters["mainbody_t"].SetValue(Assets.Items.Crimson.ThoughtProvokerProjectile.Value); bodyShader.Parameters["linemap_t"].SetValue(Assets.Bosses.TheThinkerBoss.HeartLine.Value); bodyShader.Parameters["noisemap_t"].SetValue(Assets.Noise.ShaderNoise.Value); - bodyShader.Parameters["overlay_t"].SetValue(Assets.Bosses.TheThinkerBoss.HeartOver.Value); - bodyShader.Parameters["normal_t"].SetValue(Assets.Bosses.TheThinkerBoss.HeartNormal.Value); + bodyShader.Parameters["overlay_t"].SetValue(Assets.Items.Crimson.ThoughtProvokerProjectileOver.Value); + bodyShader.Parameters["normal_t"].SetValue(Assets.Items.Crimson.ThoughtProvokerProjectileNormal.Value); bodyShader.Parameters["u_color"].SetValue(c * fade); - bodyShader.Parameters["u_fade"].SetValue(Vector3.Lerp(new Vector3(0.0f, 0.2f, 0.4f), new Vector3(0.3f, 0.5f, 0.3f), (float)Math.Sin(Main.GameUpdateCount * 0.01f)) * fade); // Lerp here so this is the same as the flower core at 0 scale + bodyShader.Parameters["u_fade"].SetValue(Vector3.Lerp(new Vector3(0.0f, 0.2f, 0.4f), new Vector3(0.3f, 0.5f, 0.3f), fade)); // Lerp here so this is the same as the flower core at 0 scale bodyShader.Parameters["mask_t"].SetValue(Assets.MagicPixel.Value); spriteBatch.End(); spriteBatch.Begin(SpriteSortMode.Immediate, default, SamplerState.PointWrap, default, Main.Rasterizer, bodyShader, Main.GameViewMatrix.ZoomMatrix); - Texture2D t = Assets.Bosses.TheThinkerBoss.Heart.Value; - spriteBatch.Draw(t, Projectile.Center - Main.screenPosition, null, Color.White, Projectile.rotation, t.Size() / 2f, scaleCalc * 0.35f, 0, 0); + Texture2D t = Assets.Items.Crimson.ThoughtProvokerProjectile.Value; + spriteBatch.Draw(t, Projectile.Center - Main.screenPosition, null, Color.White, Projectile.rotation, t.Size() / 2f, scaleCalc, 0, 0); spriteBatch.End(); spriteBatch.Begin(default, default, default, default, Main.Rasterizer, default, Main.GameViewMatrix.TransformationMatrix); } - spriteBatch.Draw(bloomTex, Projectile.Center - Main.screenPosition, null, TrailColor() with { A = 0 } * 0.35f * fade, 0f, bloomTex.Size() / 2f, scaleCalc * 0.7f, 0f, 0f); - spriteBatch.Draw(bloomTex, Projectile.Center - Main.screenPosition, null, TrailColor() with { A = 0 } * 0.5f * fade, 0f, bloomTex.Size() / 2f, scaleCalc * 0.3f, 0f, 0f); - spriteBatch.Draw(bloomTex, Projectile.Center - Main.screenPosition, null, Color.White with { A = 0 } * fade * 0.6f, 0f, bloomTex.Size() / 2f, scaleCalc * 0.1f, 0f, 0f); + //spriteBatch.Draw(bloomTex, Projectile.Center - Main.screenPosition, null, TrailColor() with { A = 0 } * 0.35f * fade, 0f, bloomTex.Size() / 2f, scaleCalc * 0.7f, 0f, 0f); + //spriteBatch.Draw(bloomTex, Projectile.Center - Main.screenPosition, null, TrailColor() with { A = 0 } * 0.5f * fade, 0f, bloomTex.Size() / 2f, scaleCalc * 0.3f, 0f, 0f); + //spriteBatch.Draw(bloomTex, Projectile.Center - Main.screenPosition, null, Color.White with { A = 0 } * fade * 0.6f, 0f, bloomTex.Size() / 2f, scaleCalc * 0.1f, 0f, 0f); if (AttackDelay > 0 && AttackState == 1) { @@ -583,15 +579,15 @@ private Color FadingWhite() private BezierCurve GetBezierCurve() { - float lerper = 1f - Vector2.Distance(Projectile.Center, Owner.Center) / 200f; + float lerper = Vector2.Distance(Projectile.Center, Owner.Center) / 200f; - if (lerper > 1f || lerper < 0f || resetTimer > 30) + if (resetTimer > 30) return null; Vector2[] curvePoints = { - Vector2.Lerp(Projectile.Center + Projectile.velocity, Owner.Center, 0.3f) + new Vector2(0f, -MathHelper.Lerp(10f, 20f, lerper) * (float)Math.Sin(lifetime * 0.05f)).RotatedBy(Projectile.DirectionTo(Owner.Center).ToRotation()), - Vector2.Lerp(Projectile.Center + Projectile.velocity, Owner.Center, 0.6f) + new Vector2(0f, MathHelper.Lerp(30f, 15f, lerper) * (float)Math.Cos(lifetime * -0.075f)).RotatedBy(Projectile.DirectionTo(Owner.Center).ToRotation()), + Vector2.Lerp(Projectile.Center + Projectile.velocity, Owner.Center, 0.3f) + new Vector2(0f, (-20 + lerper * 10) * (float)Math.Sin(lifetime * 0.05f)).RotatedBy(Projectile.DirectionTo(Owner.Center).ToRotation()), + Vector2.Lerp(Projectile.Center + Projectile.velocity, Owner.Center, 0.6f) + new Vector2(0f, 15 * (1 + lerper) * (float)Math.Cos(lifetime * -0.075f)).RotatedBy(Projectile.DirectionTo(Owner.Center).ToRotation()), }; var curve = new BezierCurve(new Vector2[] { @@ -638,12 +634,14 @@ private void ManageTrail() if (cache is null || GetBezierCurve() is null) return; - trail ??= new Trail(Main.instance.GraphicsDevice, 26, new NoTip(), factor => 2.5f, factor => TrailColor() * 0.5f); + if (trail is null || trail.IsDisposed) + trail = new Trail(Main.instance.GraphicsDevice, 26, new NoTip(), factor => 2.5f, factor => TrailColor() * 0.5f); trail.Positions = cache.ToArray(); trail.NextPosition = cache[25]; - trail2 ??= new Trail(Main.instance.GraphicsDevice, 26, new TriangularTip(1), factor => 7f, factor => Color.Lerp(FadingWhite(), AltTrailColor(), (float)Math.Sin(Main.GameUpdateCount * 0.01f)) * 0.5f); + if (trail2 is null || trail2.IsDisposed) + trail2 = new Trail(Main.instance.GraphicsDevice, 26, new TriangularTip(1), factor => 7f, factor => Color.Lerp(FadingWhite(), AltTrailColor(), (float)Math.Sin(Main.GameUpdateCount * 0.01f)) * 0.5f); trail2.Positions = cache.ToArray(); trail2.NextPosition = cache[25];