public override void ModifyHitNPC(Projectile projectile, NPC target, ref int damage, ref float knockback, ref bool crit, ref int hitDirection) { //this is actually how vanilla does projectile crits, which might explain why there are no vanilla multiclass weapons, since a 4% crit chance with a 4-class weapon would crit ~15% of the time OriginPlayer originPlayer = Main.player[projectile.owner].GetModPlayer <OriginPlayer>(); if (IsExplosive(projectile) && Main.rand.Next(1, 101) <= originPlayer.explosiveCrit) { crit = true; } if (viperEffect) { bool crt = crit; for (int i = 0; i < target.buffType.Length; i++) { if (Main.debuff[target.buffType[i]] && target.buffType[i] != Solvent_Debuff.ID) { crit = true; break; } } if (crt || Main.rand.Next(0, 9) == 0) { target.AddBuff(Solvent_Debuff.ID, 450); } } if (target.boss && godHunterEffect != 0f) { damage += (int)(damage * godHunterEffect); } }
public override void UpdateArmorSet(Player player) { OriginPlayer originPlayer = player.GetModPlayer <OriginPlayer>(); player.setBonus = "Moving quickly will build up a static charge to boost your next attack's damage"; originPlayer.felnumSet = true; if (player.velocity.Length() > 4) { originPlayer.felnumShock += player.velocity.Length() / 4; } else if (originPlayer.felnumShock > 0) { originPlayer.felnumShock--; } if (player.HasBuff(BuffID.Electrified)) { int id = BuffID.BeetleMight1; if (player.HasBuff(BuffID.BeetleMight1)) { id = BuffID.BeetleMight2; } else if (player.HasBuff(BuffID.BeetleMight2)) { id = BuffID.BeetleMight3; } else if (player.HasBuff(BuffID.BeetleMight3)) { id = BuffID.BeetleEndurance3; } player.buffType[player.FindBuffIndex(BuffID.Electrified)] = id; } }
public override void UpdateUI(GameTime gameTime) { if (Main.playerInventory) { if (eyndumCoreUI?.CurrentState is Eyndum_Core_UI eyndumCoreUIState) { OriginPlayer originPlayer = Main.LocalPlayer.GetModPlayer <OriginPlayer>(); if (eyndumCoreUIState?.itemSlot?.item == originPlayer.eyndumCore) { if (!originPlayer.eyndumSet) { if (eyndumCoreUIState?.itemSlot?.item?.Value?.IsAir ?? true) { eyndumCoreUI.SetState(null); } else { eyndumCoreUIState.hasSetBonus = false; eyndumCoreUI.Update(gameTime); } } else { eyndumCoreUI.Update(gameTime); } } else { eyndumCoreUI.SetState(null); } } } }
public override void UpdateEquip(Player player) { OriginPlayer originPlayer = player.GetModPlayer <OriginPlayer>(); originPlayer.dimStarlight = true; float light = 0.1f + (originPlayer.dimStarlightCooldown / 1000f); Lighting.AddLight(player.Center, light, light, light); }
public override bool RecipeAvailable(Recipe recipe) { OriginPlayer originPlayer = Main.LocalPlayer.GetModPlayer <OriginPlayer>(); if (recipe.createItem.type == ItemID.BottledWater) { return(!originPlayer.ZoneBrine); } return(true); }
public override void ModifyDamageHitbox(Projectile projectile, ref Rectangle hitbox) { if (IsExplosive(projectile)) { OriginPlayer originPlayer = Main.player[projectile.owner].GetModPlayer <OriginPlayer>(); if (originPlayer.madHand && (projectile.timeLeft <= 3 || projectile.penetrate == 0)) { hitbox.Inflate(hitbox.Width / 4, hitbox.Height / 4); } } }
public override bool PreKill(Projectile projectile, int timeLeft) { if (felnumEffect && projectile.type == ProjectileID.WaterGun)//projectile.aiStyle==60 { OriginPlayer originPlayer = Main.player[projectile.owner].GetModPlayer <OriginPlayer>(); Projectile.NewProjectileDirect(projectile.Center, Vector2.Zero, ModContent.ProjectileType <Shock_Grenade_Shock>(), (int)(originPlayer.felnumShock / 2.5f), projectile.knockBack, projectile.owner).timeLeft = 1; originPlayer.felnumShock = 0; Main.PlaySound(SoundID.Item, (int)projectile.Center.X, (int)projectile.Center.Y, 122, 2f, 1f); } return(true); }
public override void OnHitNPC(Projectile projectile, NPC target, int damage, float knockback, bool crit) { if (IsExplosive(projectile)) { OriginPlayer originPlayer = Main.player[projectile.owner].GetModPlayer <OriginPlayer>(); if (originPlayer.madHand) { target.AddBuff(BuffID.Oiled, 600); target.AddBuff(BuffID.OnFire, 600); } } }
public override bool OnPickup(Item item, Player player) { OriginPlayer originPlayer = player.GetModPlayer <OriginPlayer>(); if (originPlayer.cryostenSet) { if (item.type == ItemID.Heart || item.type == ItemID.CandyApple || item.type == ItemID.SugarPlum) { originPlayer.cryostenLifeRegenCount += 20; } } return(true); }
public override void NPCLoot(NPC npc) { switch (npc.type) { case NPCID.CaveBat: case NPCID.GiantBat: case NPCID.IceBat: case NPCID.IlluminantBat: case NPCID.JungleBat: case NPCID.VampireBat: Item.NewItem((int)npc.position.X, (int)npc.position.Y, npc.width, npc.height, ModContent.ItemType <Bat_Hide>(), 1 + Main.rand.Next(2)); break; case NPCID.SkeletronHead: if (!downedSkeletron) { GenFelnumOre(); } break; case NPCID.ArmoredSkeleton: case NPCID.SkeletonArcher: if (Main.rand.Next(50) == 0) { Item.NewItem((int)npc.position.X, (int)npc.position.Y, npc.width, npc.height, ModContent.ItemType <Tiny_Sniper>()); } break; case NPCID.MossHornet: case NPCID.BigMossHornet: case NPCID.GiantMossHornet: case NPCID.LittleMossHornet: case NPCID.TinyMossHornet: if (Main.rand.NextBool(4)) { Item.NewItem((int)npc.position.X, (int)npc.position.Y, npc.width, npc.height, ModContent.ItemType <Peat_Moss>(), Main.rand.Next(1, 4)); } break; default: break; } Player closestPlayer = Main.player[Player.FindClosest(npc.position, npc.width, npc.height)]; OriginPlayer originPlayer = closestPlayer.GetModPlayer <OriginPlayer>(); if (Main.rand.Next(2500) == 0 && originPlayer.ZoneDefiled) { Item.NewItem((int)npc.position.X, (int)npc.position.Y, npc.width, npc.height, ModContent.ItemType <Defiled_Key>()); } }
public override void UpdateEquip(Item item, Player player) { OriginPlayer originPlayer = player.GetModPlayer <OriginPlayer>(); switch (item.type) { case ItemID.MiningHelmet: originPlayer.explosiveCrit += 3; break; case ItemID.MiningShirt: originPlayer.explosiveDamage += 0.05f; break; } }
int GetCritMod(Player player) { OriginPlayer modPlayer = player.GetModPlayer <OriginPlayer>(); int critMod = 0; if ((modPlayer.oldBonuses & 1) != 0 || modPlayer.fiberglassSet || modPlayer.fiberglassDagger) { critMod = -50; } if ((modPlayer.oldBonuses & 2) != 0 || modPlayer.felnumSet) { critMod = -64; } return(critMod); }
public override void UpdateMusic(ref int music, ref MusicPriority priority) { if (Main.myPlayer == -1 || Main.gameMenu || !Main.LocalPlayer.active) { return; } Vector2 position = Main.LocalPlayer.Bottom / 16; OriginPlayer originPlayer = Main.LocalPlayer.GetModPlayer <OriginPlayer>(); if (originPlayer.ZoneVoid && priority < MusicPriority.Event) { music = Music.Dusk; priority = MusicPriority.Event; } else if (originPlayer.ZoneDefiled && priority < MusicPriority.Event) { music = (position.Y >= (Main.worldSurface + 30))?Music.UndergroundDefiled:Music.Defiled; priority = MusicPriority.Event; } }
public override void AI() { Player player = Main.player[projectile.owner]; #region Active check // This is the "active check", makes sure the minion is alive while the player is alive, and despawns if not if (player.dead || !player.active) { player.ClearBuff(Rotting_Worm_Staff.buffID); } if (player.HasBuff(Rotting_Worm_Staff.buffID)) { projectile.timeLeft = 2; } #endregion #region General behavior Vector2 idlePosition = player.Top; idlePosition.X -= 48f * player.direction; // Teleport to player if distance is too big Vector2 vectorToIdlePosition = idlePosition - projectile.Center; float distanceToIdlePosition = vectorToIdlePosition.Length(); if (Main.myPlayer == player.whoAmI && distanceToIdlePosition > 2000f) { // Whenever you deal with non-regular events that change the behavior or position drastically, make sure to only run the code on the owner of the projectile, // and then set netUpdate to true projectile.position = idlePosition; projectile.velocity *= 0.1f; projectile.netUpdate = true; } // If your minion is flying, you want to do this independently of any conditions float overlapVelocity = 0.04f; for (int i = 0; i < Main.maxProjectiles; i++) { // Fix overlap with other minions Projectile other = Main.projectile[i]; if (i != projectile.whoAmI && other.active && other.owner == projectile.owner && Math.Abs(projectile.position.X - other.position.X) + Math.Abs(projectile.position.Y - other.position.Y) < projectile.width) { if (projectile.position.X < other.position.X) { projectile.velocity.X -= overlapVelocity; } else { projectile.velocity.X += overlapVelocity; } if (projectile.position.Y < other.position.Y) { projectile.velocity.Y -= overlapVelocity; } else { projectile.velocity.Y += overlapVelocity; } } } #endregion #region Find target // Starting search distance float targetDist = 700f; float targetAngle = -2; Vector2 targetCenter = projectile.position; int target = -1; bool foundTarget = false; if (player.HasMinionAttackTargetNPC) { NPC npc = Main.npc[player.MinionAttackTargetNPC]; float between = Vector2.Distance(npc.Center, projectile.Center); if (between < 2000f) { targetDist = between; targetCenter = npc.Center; target = player.MinionAttackTargetNPC; foundTarget = true; } } if (!foundTarget) { for (int i = 0; i < Main.maxNPCs; i++) { NPC npc = Main.npc[i]; if (npc.CanBeChasedBy()) { Vector2 diff = projectile.Center - projectile.Center; float dist = diff.Length(); if (dist > targetDist) { continue; } float dot = NormDot(diff, projectile.velocity); bool inRange = dist < targetDist; //bool jumpOfHight = (npc.Bottom.Y-projectile.Top.Y)<160; if (((dot > targetAngle && inRange) || !foundTarget)) { targetDist = dist; targetAngle = dot; targetCenter = npc.height / (float)npc.width > 1 ? npc.Top + new Vector2(0, 8) : npc.Center; target = npc.whoAmI; foundTarget = true; } } } } projectile.friendly = foundTarget; #endregion #region Movement bool leap = false; if (foundTarget || distanceToIdlePosition <= 600f) { if (Collision.CanHitLine(projectile.position, projectile.width, projectile.height, projectile.position + projectile.velocity * 4, projectile.width, projectile.height)) { if (projectile.localAI[2] <= 0) { leap = true; } projectile.localAI[2] = 5; } } if (distanceToIdlePosition > 900f) { projectile.localAI[2] = 0; } // Default movement parameters (here for attacking) float speed = 8f + (targetCenter.Y < projectile.Center.Y?(projectile.Center.Y - targetCenter.Y) / 32f:0); float turnSpeed = 2f; float currentSpeed = projectile.velocity.Length(); if (foundTarget) { if ((int)Math.Ceiling(targetAngle) == -1) { targetCenter.Y -= 16; } } else { if (distanceToIdlePosition > 600f) { speed = 16f; } else if (distanceToIdlePosition <= 120f) { speed = 4f; } } if (projectile.localAI[2] > 0) { projectile.velocity.Y += 0.3f; turnSpeed = 0.1f; projectile.localAI[2]--; if (leap) { turnSpeed = 10f; targetCenter.Y -= 64 * NormDot(projectile.velocity, foundTarget ? targetCenter - projectile.Center : vectorToIdlePosition); } } else { LinearSmoothing(ref currentSpeed, speed, currentSpeed < 1?1:0.1f); } Vector2 direction = foundTarget?targetCenter - projectile.Center:vectorToIdlePosition; direction.Normalize(); projectile.velocity = Vector2.Normalize(projectile.velocity + direction * turnSpeed) * currentSpeed; if (projectile.localAI[2] <= 0 && (++projectile.frameCounter) * currentSpeed > 60) { Microsoft.Xna.Framework.Audio.SoundEffectInstance se = Main.PlaySound(new Terraria.Audio.LegacySoundStyle(15, 1), projectile.Center); if (!(se is null)) { se.Pitch *= 2f; } projectile.frameCounter = 0; } #endregion #region Worminess projectile.rotation = projectile.velocity.ToRotation() + MathHelper.PiOver2; OriginPlayer originPlayer = player.GetModPlayer <OriginPlayer>(); if (projectile.localAI[0] == 0f) { //if(originPlayer.wormHeadIndex==-1) { projectile.velocity.Y += 6; projectile.localAI[3] = projectile.whoAmI; int current = 0; int last = projectile.whoAmI; int type = Rotting_Worm_Body.ID; //body current = Projectile.NewProjectile(projectile.Center, Vector2.Zero, type, projectile.damage, projectile.knockBack, projectile.owner); Main.projectile[current].localAI[3] = projectile.whoAmI; Main.projectile[current].localAI[1] = last; Main.projectile[last].localAI[0] = current; last = current; //tail current = Projectile.NewProjectile(projectile.Center, Vector2.Zero, Rotting_Worm_Tail.ID, projectile.damage, projectile.knockBack, projectile.owner); Main.projectile[current].localAI[3] = projectile.whoAmI; Main.projectile[current].localAI[1] = last; Main.projectile[last].localAI[0] = current; /*} else { * Projectile segment = Main.projectile[originPlayer.wormHeadIndex]; * int i = 0; * while(segment.type==Rotting_Worm_Staff.projectileID||segment.type==Rotting_Worm_Body.ID) { * segment.damage++; * if(i++>4)break; * segment.whoAmI+=0; * segment = Main.projectile[(int)segment.localAI[0]]; * } * if(segment.type==Rotting_Worm_Tail.ID) { * float[] segmentAI = new float[4] { projectile.whoAmI, segment.localAI[1], segment.localAI[2], segment.localAI[3] }; * segment.SetToType(Rotting_Worm_Body.ID); * segment.localAI = segmentAI; * projectile.SetToType(Rotting_Worm_Tail.ID); * projectile.localAI = new float[4] { 0, segment.whoAmI, 0, segmentAI[3] }; * } * }*/ }/* else { * originPlayer.wormHeadIndex = projectile.whoAmI; * }*/ #endregion }
public override void AI() { Player player = Main.player[projectile.owner]; #region Active check // This is the "active check", makes sure the minion is alive while the player is alive, and despawns if not if (player.dead || !player.active) { player.ClearBuff(Eyeball_Staff.buffID); } if (player.HasBuff(Eyeball_Staff.buffID)) { projectile.timeLeft = 2; } OriginPlayer originPlayer = player.GetModPlayer <OriginPlayer>(); originPlayer.minionSubSlots[0] += 0.5f; int eyeCount = player.ownedProjectileCounts[Eyeball_Staff.projectileID] / 2; if (originPlayer.minionSubSlots[0] <= eyeCount) { projectile.minionSlots = 0.5f; } else { projectile.minionSlots = 0; } #endregion #region General behavior Vector2 idlePosition = player.Top + new Vector2(player.direction * -player.width / 2, 0); idlePosition.X -= 48f * player.direction; // Teleport to player if distance is too big Vector2 vectorToIdlePosition = idlePosition - projectile.Center; float distanceToIdlePosition = vectorToIdlePosition.Length(); if (Main.myPlayer == player.whoAmI && distanceToIdlePosition > 2000f) { // Whenever you deal with non-regular events that change the behavior or position drastically, make sure to only run the code on the owner of the projectile, // and then set netUpdate to true projectile.position = idlePosition; projectile.velocity *= 0.1f; projectile.netUpdate = true; } // If your minion is flying, you want to do this independently of any conditions float overlapVelocity = 0.04f; for (int i = 0; i < Main.maxProjectiles; i++) { // Fix overlap with other minions Projectile other = Main.projectile[i]; if (i != projectile.whoAmI && other.active && other.owner == projectile.owner && Math.Abs(projectile.position.X - other.position.X) + Math.Abs(projectile.position.Y - other.position.Y) < projectile.width) { if (projectile.position.X < other.position.X) { projectile.velocity.X -= overlapVelocity; } else { projectile.velocity.X += overlapVelocity; } if (projectile.position.Y < other.position.Y) { projectile.velocity.Y -= overlapVelocity; } else { projectile.velocity.Y += overlapVelocity; } } } #endregion #region Find target // Starting search distance float targetDist = 700f; float targetAngle = -2; Vector2 targetCenter = projectile.Center; int target = -1; bool foundTarget = false; if (player.HasMinionAttackTargetNPC) { NPC npc = Main.npc[player.MinionAttackTargetNPC]; float dist = Vector2.Distance(npc.Center, projectile.Center); if (dist < 2000f) { targetDist = dist; targetCenter = npc.Center; target = player.MinionAttackTargetNPC; foundTarget = true; } } if (projectile.ai[1] < 0) { goto movement; } if (!foundTarget) { for (int i = 0; i < Main.maxNPCs; i++) { NPC npc = Main.npc[i]; if (npc.CanBeChasedBy()) { Vector2 diff = projectile.Center - projectile.Center; float dist = diff.Length(); if (dist > targetDist) { continue; } float dot = NormDot(diff, projectile.velocity); bool inRange = dist <= targetDist; bool lineOfSight = Collision.CanHitLine(projectile.position, projectile.width, projectile.height, npc.position, npc.width, npc.height); if (((dot >= targetAngle && inRange) || !foundTarget) && lineOfSight) { targetDist = dist; targetAngle = dot; targetCenter = npc.Center; target = npc.whoAmI; foundTarget = true; } } } } projectile.friendly = foundTarget; #endregion #region Movement movement: // Default movement parameters (here for attacking) float speed = 6f + projectile.localAI[0] / 15; float turnSpeed = 1f + Math.Max((projectile.localAI[0] - 15) / 30, 0); float currentSpeed = projectile.velocity.Length(); projectile.tileCollide = true; if (foundTarget) { projectile.tileCollide = true; if (projectile.ai[0] != target) { projectile.ai[0] = target; projectile.ai[1] = 0; } else { if (++projectile.ai[1] > 180) { projectile.ai[1] = -30; } } if ((int)Math.Ceiling(targetAngle) == -1) { targetCenter.Y -= 16; } } else { if (distanceToIdlePosition > 640f) { projectile.tileCollide = false; speed = 16f; } else if (distanceToIdlePosition < 64f) { speed = 4f; turnSpeed = 0; } else { speed = 6f; } if (!Collision.CanHitLine(projectile.position, projectile.width, projectile.height, idlePosition, 1, 1)) { projectile.tileCollide = false; } } LinearSmoothing(ref currentSpeed, speed, currentSpeed < 1?1:0.1f + projectile.localAI[0] / 60f); Vector2 direction = foundTarget?targetCenter - projectile.Center:vectorToIdlePosition; direction.Normalize(); projectile.velocity = Vector2.Normalize(projectile.velocity + direction * turnSpeed) * currentSpeed; #endregion #region Animation and visuals // So it will lean slightly towards the direction it's moving projectile.rotation = (float)Math.Atan(projectile.velocity.Y / projectile.velocity.X); projectile.spriteDirection = Math.Sign(projectile.velocity.X); // This is a simple "loop through all frames from top to bottom" animation projectile.frameCounter++; if (projectile.frameCounter >= frameSpeed) { projectile.frameCounter = 0; projectile.frame++; if (projectile.frame >= Main.projFrames[projectile.type]) { projectile.frame = 0; } } #endregion if (projectile.localAI[0] > 0) { projectile.localAI[0]--; } }