first commit, even though I've been "done" with the mod for like ever

This commit is contained in:
ForeverPyrite
2025-08-12 00:01:48 -05:00
commit 46bc9baab8
32 changed files with 1145 additions and 0 deletions

261
Siva.cs Normal file
View File

@@ -0,0 +1,261 @@
using System;
using System.Timers;
using System.Collections.Generic;
using MonoMod.RuntimeDetour;
using Terraria;
using Terraria.ModLoader;
using Terraria.GameContent.ItemDropRules;
using Terraria.ID;
using Terraria.ModLoader.Default;
using Terraria.ModLoader.UI;
using Terraria.DataStructures;
using Siva;
using Siva.Weapons;
using Siva.Buffs;
using Siva.Projectiles;
// only thing that really needs to be active mod wide is the drop chance and reduced crit, so here it is
namespace Siva
{
public class Siva : Mod
{
public class ReducedCritMulti : GlobalNPC // Modifies the crit multiplier on NPCs so it doesn't do insane damage with it's high crit chance
{
// Alters the base behavior of what happens when an NPC is hit by a projectile.
public override void ModifyHitByProjectile(NPC npc, Projectile projectile, ref NPC.HitModifiers modifiers)
{
if(LogicPerfected.HeldIsNorm() && LogicPerfected.Bullet(projectile))
{
modifiers.CritDamage = new(1.6f, 1f); // Modifies Outbreak's bullets crit damage to 60% to match in game
}
else if(LogicPerfected.HeldIsMaster() && LogicPerfected.Bullet(projectile))
{
modifiers.CritDamage = new(1.55f, 1f); // Modifies Outbreak's bullets crit damage to 55% as a little terraria bonus
}
}
}
public class OutbreakDrop : GlobalNPC
{
public override void ModifyNPCLoot(NPC npc, NPCLoot npcLoot)
{
if (npc.type == NPCID.MossHornet)
{
npcLoot.Add(new ConditionalNormalvsExpertDropRule(Outbreak.ItemType, 350, 250, new Conditions.DownedAllMechBosses()));
}
}
}
}
public class LogicPerfected // I got so fed up with typing the same long ass hard to read conditionals, so I made this class.
{
public static bool HeldIsNorm()
{
return Main.LocalPlayer.HeldItem.type == Outbreak.ItemType;
}
public static bool HeldIsMaster()
{
return Main.LocalPlayer.HeldItem.type == MasterworkedOutbreak.ItemType;
}
public static bool Bullet(Projectile projectile) // Really it just checks that it's a projectile that acts like a bullet while you are holding Outbreak, best way I could find to do it :/. This means hypothetically someone can shoot bullets from any other gun then quickswap. Probably not useful but I'll see..
{
return projectile.aiStyle == 1;
}
public static bool Nanite(Projectile projectile)
{
return projectile.type == SIVANanite.ProjectileType;
}
public static bool NormBullet(Projectile projectile)
{
return HeldIsNorm() && Bullet(projectile);
}
public static bool MasterBulletOrNanite(Projectile projectile)
{
return HeldIsMaster() && (Bullet(projectile) || Nanite(projectile));
}
public static bool ParasitismOnTarget(NPC npc)
{
return npc.FindBuffIndex(Parasitism.BuffType) != -1; // FindBuffIndex returns -1 if the buff isn't found
}
}
}
// none of the base game drops have a condition for the state of the game you are in and also have different chances based on expert vs master
public class ConditionalNormalvsExpertDropRule : IItemDropRule
{
private int itemId;
private int normalModeChance;
private int expertModeChance;
private IItemDropRuleCondition condition;
public ConditionalNormalvsExpertDropRule(int itemId, int normalModeChance, int expertModeChance, IItemDropRuleCondition condition)
{
this.itemId = itemId;
this.normalModeChance = normalModeChance;
this.expertModeChance = expertModeChance;
this.condition = condition;
}
public bool CanDrop(DropAttemptInfo info)
{
return condition.CanDrop(info);
}
public ItemDropAttemptResult TryDroppingItem(DropAttemptInfo info)
{
ItemDropAttemptResult result = new ItemDropAttemptResult();
if (CanDrop(info))
{
int chance = info.IsExpertMode ? expertModeChance : normalModeChance;
if (info.player.RollLuck(chance) == 0)
{
CommonCode.DropItem(info, itemId, 1, true);
result.State = ItemDropAttemptResultState.Success;
}
else
{
result.State = ItemDropAttemptResultState.FailedRandomRoll;
}
}
else
{
result.State = ItemDropAttemptResultState.DoesntFillConditions;
}
return result;
}
public void ReportDroprates(List<DropRateInfo> drops, DropRateInfoChainFeed ratesInfo)
{
DropRateInfoChainFeed ratesInfo2 = ratesInfo.With(1f);
ratesInfo2.AddCondition(condition);
float chance = ratesInfo2.parentDroprateChance != 0 && ratesInfo2.parentDroprateChance != 1f ? ratesInfo2.parentDroprateChance : (ratesInfo2.parentDroprateChance == 1f ? expertModeChance : normalModeChance);
float dropRate = 1f / chance * ratesInfo2.parentDroprateChance;
drops.Add(new DropRateInfo(itemId, 1, 1, dropRate, ratesInfo2.conditions));
}
public List<IItemDropRuleChainAttempt> ChainedRules => new List<IItemDropRuleChainAttempt>();
}
// A timer to make sure the nanite hits are consecutive
public class RapidHitTimer
{
private Timer hitTimer;
public RapidHitTimer()
{
hitTimer = new Timer
{
AutoReset = false,
};
hitTimer.Elapsed += NaniteCreation.ResetHits;
}
public void Start()
{
hitTimer.Interval = 2000;
hitTimer.Enabled = true;
}
public void Stop()
{
hitTimer.Enabled = false;
}
}
/*
Nanite creation about to go crazy
I used to have one class in each of them that was copied and pasted, and I think it might still make more sense to put them in there
Deriving them off of each other isn't too important, I just wanted to try more programming things.
I also just wanted it to be a lot more readable, hence all the extra functions like OutbreakBullet and OutbreakNanite, as well as overriding OutbreakBullet instead of making a new class just to try it.
*/
public class NaniteCreation : GlobalProjectile // Creates Nanites on sustained fire and critical kills.
{
// Alters the base behavior of what happens when a projectile hits an NPC
protected static int outbreakHits = 0;
protected static RapidHitTimer hitTimer = new RapidHitTimer();
protected static void ResetHits()
{
outbreakHits = 0;
hitTimer.Stop();
}
public static void ResetHits(Object ph, ElapsedEventArgs ph2) // Have to cater to Timer.Elapsed so I made an overload for it
{
outbreakHits = 0;
hitTimer.Stop();
}
public override void OnHitNPC(Projectile projectile, NPC target, NPC.HitInfo hit, int damage)
{
// Checks to make sure the player is holding Outbreak and the projectile was a bullet, as well as making sure that the life of the target is more than 5 (ie not magic or a critter).
if (LogicPerfected.NormBullet(projectile) && target.lifeMax > 5)
{
outbreakHits++;
hitTimer.Start();
// Main.NewText($"{outbreakHits}"); //debug text
if(outbreakHits >= 12)
{
int naniteCount = new Random().Next(2, 5); // It's just how ranges work in this function, I didn't make it, go yell at Microsoft
SIVANanite.Create(naniteCount, target, (int)(hit.SourceDamage*2.21));
ResetHits();
}
if(hit.Crit & target.life <= 0) // On critical kills make 9 nanites
{
// Main.NewText("Critical Kill!"); // debug text
SIVANanite.Create(9, target, (int)(hit.SourceDamage*1.38));
}
}
}
}
public class MasterworkedNaniteCreation : NaniteCreation
{
private new static int outbreakHits = 0;
public override void OnHitNPC(Projectile projectile, NPC target, NPC.HitInfo hit, int damage)
{
// Checks to make sure the player is holding MasterworkedOutbreak, and that the targets max life is more than 5 (ie. not magic/critters), as well as making sure the projectile is either a bullet or a siva nanite.
if (LogicPerfected.MasterBulletOrNanite(projectile) && target.lifeMax > 5)
{
// Checks to make sure that it was a bullet and not a nanite or anything
if(LogicPerfected.Bullet(projectile))
{
outbreakHits++;
hitTimer.Start();
if(outbreakHits >= 12)
{
int naniteCount = new Random().Next(2, 5); // It's just how ranges work in this function, I didn't make it, go yell at Microsoft
SIVANanite.Create(naniteCount, target, (int)(hit.SourceDamage*2.21));
outbreakHits = 0;
ResetHits();
}
}
if(target.life <= 0) // On kill
{
if(target.FindBuffIndex(Parasitism.BuffType) != -1) // If parasitism is in the buff list of the target
{
SIVANanite.Create(4, target, (int)(damage*0.6)); // It's actually 15% (46.8 vs 7) of the normal ones in game according to the Destiny Data Compendium spreedsheets and I forgot to check it myself. Maybe it was pvp or something. Idk. But they also scale damage so that might be why.
}
if(hit.Crit) // If the final blow was a crit
{
SIVANanite.Create(9, target, (int)(hit.SourceDamage*1.38));
}
}
}
}
}