// If the item is a magic weapon it will explode when the projectile dies private void MagicExplode() { if (!StoredItem.magic) { return; } if (Main.myPlayer == Projectile.owner) { Tools.ResizeProjectile(Projectile.whoAmI, Projectile.width + 50, Projectile.height + 50); Projectile.Damage(); // Applies damage in the area Projectile.netUpdate = true; } SoundEngine.PlaySound(SoundID.Item14, Projectile.Center); for (int i = 0; i < Math.Max(4, (int)GobblerHelper.DiagonalSize(StoredItem) / 4); i++) // More dust the higher the size { Gore.NewGore( Projectile.position + new Vector2(Main.rand.NextFloat(Projectile.width), Main.rand.NextFloat(Projectile.height)), Vector2.Zero, Main.rand.Next(61, 64), Main.rand.NextFloat(0.2f, 1.2f)); Dust.NewDust( Projectile.position, Projectile.width, Projectile.height, /*Type*/ 31, 0f, 0f, 0, default(Color), Main.rand.NextFloat(2)); } }
// When the projectile dies and the stored item was set to consumed private void ItemConsume() { if (!Consumed) { return; } Player player = Main.player[Projectile.owner]; if (GobblerHelper.IsDepletable(StoredItem)) // Item won't be returned { if (StoredItem.buffTime != 0) // Buff-giving consumables { player.AddBuff(StoredItem.buffType, StoredItem.buffTime); } if (StoredItem.makeNPC != 0 && Main.netMode != NetmodeID.MultiplayerClient) // Critters { NPC.NewNPC((int)(Projectile.Center.X), (int)(Projectile.Center.Y), StoredItem.makeNPC); } } else // Drops the stored item { if (Main.netMode != NetmodeID.MultiplayerClient) // Will be synced from the server in multiplayer { Item.NewItem(Projectile.Center, StoredItem.type, prefixGiven: StoredItem.prefix); } } }
public override bool CanUseItem(Player player) { // Right click if (player.altFunctionUse == 2) { Item.useTime = 1; // Shooting code runs every tick, but the animation is longer so I can control what's happening Item.useAnimation = 30; // About right for the looping sound } // Left click else { Item.useTime = 1; Item.useAnimation = 20; var modPlayer = player.GetModPlayer <VirtuousPlayer>(); if (modPlayer.GobblerStorage.Count > 0 && GobblerHelper.ConsumeChance(modPlayer.GobblerStorage.First().MakeItem()) == 0f) { Item.useAnimation = 15; // An exception: Shoots faster with endless quiver or musket pouch } } return(base.CanUseItem(player)); }
// If the item is a tool, it will bounce off in the direction it came from when specified private bool ToolBounce() { if (GobblerHelper.IsTool(StoredItem)) { if (Projectile.penetrate > 1) { if (StoredItem.UseSound != null) { SoundEngine.PlaySound(StoredItem.UseSound, Projectile.Center); } Projectile.penetrate--; Projectile.velocity *= new Vector2(-0.5f, -0.5f); Projectile.netUpdate = true; // Sync to multiplayer just in case return(true); } else { Projectile.Kill(); } } return(false); }
public override void AI() { Player player = Main.player[Projectile.owner]; // First tick if (Projectile.timeLeft == Lifespan && StoredItem.type != ItemID.None) { // Inherit properties from the stored item Tools.ResizeProjectile(Projectile.whoAmI, StoredItem.width, StoredItem.height); Projectile.damage = GobblerHelper.ShotDamage(StoredItem, player); Projectile.knockBack = GobblerHelper.ShotKnockBack(StoredItem, player); Projectile.melee = StoredItem.melee; Projectile.magic = StoredItem.magic; Projectile.ranged = StoredItem.ranged; Projectile.Name = StoredItem.Name; // Transparency; copies appear translucent if (!Consumed && !GobblerHelper.IsDepletable(StoredItem)) { Projectile.alpha = 120; } // Items without gravity if (ItemID.Sets.ItemNoGravity[StoredItem.type]) { Projectile.timeLeft = 2 * 60; Projectile.penetrate = -1; } // Penetration if (StoredItem.melee) { Projectile.penetrate = -1; // Melee weapons penetrate infinitely } if (GobblerHelper.IsTool(StoredItem)) { Projectile.penetrate = 3; // But tools penetrate only a bit } else if (StoredItem.accessory) { Projectile.penetrate = 2; } Projectile.netUpdate = true; // Sync to multiplayer } // Every tick: Projectile rotation and movement if (!ItemID.Sets.ItemNoGravity[StoredItem.type]) { Projectile.velocity.Y += GobblerHelper.DiagonalSize(StoredItem) / 200f; // How fast they fall down depends on their size // Swingable weapons and projectiles point to where they're going, adjusted for sprite orientation if (StoredItem.useStyle == 1 && !StoredItem.consumable && !GobblerHelper.IsTool(StoredItem)) { Projectile.rotation = Projectile.velocity.ToRotation() + 45.ToRadians(); } else if (StoredItem.ammo > 0) { Projectile.rotation = Projectile.velocity.ToRotation(); if (StoredItem.ammo == AmmoID.Arrow) { Projectile.rotation += -90.ToRadians(); } else if (StoredItem.ammo == AmmoID.Bullet || StoredItem.ammo == AmmoID.Dart) { Projectile.rotation += 90.ToRadians(); } else if (StoredItem.ammo == AmmoID.StyngerBolt || StoredItem.ammo == AmmoID.CandyCorn) { Projectile.rotation += 45.ToRadians(); } } else { Projectile.rotation += Tools.RevolutionPerSecond; // The rest of the items spin } } }
// When this projectile dies it can shoot out what the stored item would shoot private void ItemShoot() { if (Projectile.owner != Main.myPlayer) { return; // It'll get synced in multiplayer } Player player = Main.player[Projectile.owner]; // Orbital behavior var orbitalItem = StoredItem.ModItem as OrbitalItem; if (orbitalItem != null) { Vector2 position = player.Center; Vector2 velocity = Vector2.Zero; int type = orbitalItem.Item.shoot; int damage = StoredItem.damage; orbitalItem.GetWeaponDamage(player, ref damage); orbitalItem.Shoot(player, ref position, ref velocity.X, ref velocity.Y, ref type, ref damage, ref StoredItem.knockBack); return; } // Shooting exceptions else if (StoredItem.type == ItemID.ExplosiveBunny) // I love these, and they don't have a value for shoot { var proj = Projectile.NewProjectileDirect( Projectile.Center, Vector2.Zero, ProjectileID.ExplosiveBunny, StoredItem.damage, Projectile.knockBack, player.whoAmI); proj.timeLeft = 3; } // General shooting behavior else if (StoredItem.shoot > 0 && StoredItem.ammo == 0 && StoredItem.type != ItemID.StardustDragonStaff) // Stardust dragon was very buggy so it's excluded { // Summon and pet behavior if (StoredItem.buffType != 0) { if (player.FindBuffIndex(StoredItem.buffType) < 0) { player.AddBuff(StoredItem.buffType, 60); // Player doesn't have the buff active, adds it } else // Player has the corresponding buff active { var summon = Main.projectile.First(x => x.active && x.type == StoredItem.shoot && x.owner == Projectile.owner); summon.Center = Projectile.Center; // Teleports the pet or summon to this projectile if (StoredItem.damage <= 0) { return; // Does nothing else if it's a pet } } } // Get projectile amount int projAmount = 1; if (StoredItem.damage > 0 && !StoredItem.consumable && (!StoredItem.melee || StoredItem.useStyle == 1) || StoredItem.type == ItemID.Clentaminator) { projAmount = Main.rand.Next(4, 7); // Weapons excluding non-swingable melee weapons shoot a random amount of projectiles } if (StoredItem.ranged) { projAmount += projAmount / 2 + (int)(60f / StoredItem.useAnimation); // Ranged weapons shoot a lot more based on their speed } // Get projectile type. Some guns and dart guns don't have the right values so we overwrite them int projType = StoredItem.shoot; if (projType == 10 && StoredItem.useAmmo == AmmoID.Bullet) { projType = ProjectileID.Bullet; } else if (StoredItem.useAmmo == AmmoID.Dart) { projType = ProjectileID.PoisonDart; } // Get projectile damage float damage = StoredItem.damage; GobblerHelper.ApplyClassDamage(ref damage, StoredItem, player); // Spawning the projectiles Vector2 startingRotation = Main.rand.NextVector2(); for (int i = 0; i < projAmount; i++) { Vector2 rotation = startingRotation.RotatedBy(Tools.FullCircle * i / projAmount); // In a circle Vector2 position = Projectile.Center + rotation; Vector2 velocity = rotation * StoredItem.shootSpeed; var proj = Projectile.NewProjectileDirect( position, velocity, projType, (int)damage, StoredItem.knockBack, player.whoAmI); if (GobblerHelper.IsExplosive(StoredItem)) { proj.timeLeft = 3; // Explodes immediately } if (StoredItem.sentry) // Turrets { proj.position.Y -= 20; // So it doesn't sink into the ground proj.position.X += Main.rand.Next(-20, 21); player.UpdateMaxTurrets(); } proj.friendly = true; proj.hostile = false; } } }
public override void ModifyTooltips(List <TooltipLine> tooltips) { string descriptionText; if (Language.ActiveCulture == GameCulture.FromCultureName(GameCulture.CultureName.Spanish)) { descriptionText = $"Click Derecho para succionar objetos en el suelo, Click Izquierdo para dispararlos\n" + $"Presiona Tirar Objeto{" (con el arma en favoritos)".If(!Item.favorited)} para vaciar el arma\n" + $"El daño, propiedades y comportamiento del proyectil dependerá según el objeto que dispares\n" + $"Los objetos no-consumibles siempre serán recuperados una vez disparados"; } else { descriptionText = $"Right Click to suck items from the ground, Left Click to shoot them\n" + $"Press Throw{" while favorited".If(!Item.favorited)} to release the storage\n" + $"Projectile damage, properties and behavior vary on the item\n" + $"Non-consumable items are never lost and will drop after use"; } var player = Main.player[Item.playerIndexTheItemIsReservedFor]; var modPlayer = player.GetModPlayer <VirtuousPlayer>(); Item storedItem = modPlayer.GobblerStorage.Count > 0 ? modPlayer.GobblerStorage.First().MakeItem() : null; var nextItemTooltip = new StringBuilder(); if (storedItem == null) { nextItemTooltip.Append("Variable damage\nVariable knockback"); } else { int damage = GobblerHelper.ShotDamage(storedItem, player); float knockBack = GobblerHelper.ShotKnockBack(storedItem, player); int preserveChance = 100 - (int)(GobblerHelper.ConsumeChance(storedItem) * 100); nextItemTooltip.Append($"Next item: {storedItem.Name}"); if (storedItem.ammo == AmmoID.Bullet) { nextItemTooltip.Append(" (The WHOLE bullet)"); } else if (storedItem.ammo == AmmoID.Rocket) { nextItemTooltip.Append(" (...Non-ignited)"); } nextItemTooltip.Append($"\n Damage: {damage} "); if (storedItem.melee) { nextItemTooltip.Append("(melee)"); } else if (storedItem.ranged) { nextItemTooltip.Append("(ranged)"); } else if (storedItem.magic) { nextItemTooltip.Append("(magic)"); } else if (storedItem.summon) { nextItemTooltip.Append("(summon)"); } else if (storedItem.thrown) { nextItemTooltip.Append("(thrown)"); } nextItemTooltip.Append($"\n Knockback: {knockBack.ToString("0.0")} "); if (knockBack <= 0.0f) { nextItemTooltip.Append("(None)"); } else if (knockBack <= 1.5f) { nextItemTooltip.Append("(Extremely weak)"); } else if (knockBack <= 3.0f) { nextItemTooltip.Append("(Very weak)"); } else if (knockBack <= 4.0f) { nextItemTooltip.Append("(Weak)"); } else if (knockBack <= 6.0f) { nextItemTooltip.Append("(Average)"); } else if (knockBack <= 7.0f) { nextItemTooltip.Append("(Strong)"); } else if (knockBack <= 9.0f) { nextItemTooltip.Append("(Very strong)"); } else if (knockBack <= 11.0f) { nextItemTooltip.Append("(Extremely strong)"); } else { nextItemTooltip.Append("(Insane)"); } nextItemTooltip.Append($"\n Preserve chance: {preserveChance}%"); } var customTooltips = new List <TooltipLine>(); string capacityTooltip = $"Current capacity: {modPlayer.GobblerStorage.Count}/{StorageCapacity}"; customTooltips.Add(new TooltipLine(Mod, "GobblerCapacity", capacityTooltip)); customTooltips.Add(new TooltipLine(Mod, "GobblerItem", nextItemTooltip.ToString())); customTooltips.Add(new TooltipLine(Mod, "GobblerTooltip", descriptionText)); tooltips.RemoveAll(line => line.mod == "Terraria" && TooltipsToRemove.Contains(line.Name)); tooltips.InsertRange(1, customTooltips); }
public override bool Shoot(Player player, EntitySource_ItemUse_WithAmmo source, Vector2 position, Vector2 velocity, int type, int damage, float knockback) { var modPlayer = player.GetModPlayer <VirtuousPlayer>(); position = player.Center + (Main.MouseWorld - player.Center).OfLength(Item.width); // Tip of the nozzle position += position.Perpendicular(10); // Moves it up to be centered if (!Collision.CanHit(player.Center, 0, 0, position, 0, 0)) { position = player.Center; // So it doesn't shoot through walls } // Right click, absorb if (player.altFunctionUse == 2) { if (player.itemAnimation == 1) // Resets the animation so it doesn't return to resting position { player.itemAnimation = Item.useAnimation; } if (PlayerInput.Triggers.JustReleased.MouseRight) // Stops the item use immediately { player.itemAnimation = 0; foreach (var item in Main.item.Where(x => x.active)) { item.GetGlobalItem <VirtuousItem>().beingGobbled = false; // Makes items able to be picked up again } return(false); } if (player.itemAnimation == Item.useAnimation - 1) { SoundEngine.PlaySound(SoundID.Item22, position); // Once at the beginning of the animation } bool sucked = false; // Whether an item has been sucked in this tick foreach (Item item in Main.item) { if (IsGobblableItem(item)) { if (item.WithinRange(position, AttractRange)) { item.GetGlobalItem <VirtuousItem>().beingGobbled = true; // So it can't be picked up item.velocity -= (item.Center - position).OfLength(0.5f); // Drawn toward the nozzle if (item.WithinRange(position, StoreRange)) { while (item.stack > 0 && modPlayer.GobblerStorage.Count < StorageCapacity) { if (!sucked) { sucked = true; SoundEngine.PlaySound(SoundID.Item3, position); } modPlayer.GobblerStorage.Add(new GobblerStoredItem(item)); if (--item.stack == 0) { item.active = false; } } } if (Main.netMode == NetmodeID.MultiplayerClient) // Syncs to multiplayer { NetMessage.SendData(MessageID.SyncItem, -1, -1, null, item.whoAmI); } } } } } // Left click, shoot else { if (player.itemAnimation == Item.useAnimation - 1) // Once every animation { if (modPlayer.GobblerStorage.Count == 0) { SoundEngine.PlaySound(SoundID.Item23, position); } else { SoundEngine.PlaySound(SoundID.Item5, position); var gobblerItem = modPlayer.GobblerStorage.First(); var item = gobblerItem.MakeItem(); bool consume = Main.rand.NextFloat() < GobblerHelper.ConsumeChance(item); if (item.ammo == AmmoID.Arrow) // Arrows are shot just fine { var proj = Projectile.NewProjectileDirect( position, new Vector2(speedX, speedY), item.shoot, GobblerHelper.ShotDamage(item, player), GobblerHelper.ShotKnockBack(item, player), player.whoAmI); proj.noDropItem = true; proj.netUpdate = true; } else // Shooting the custom projectile that takes the form of any item { if (gobblerItem.type == ItemID.EndlessMusketPouch) { gobblerItem.type = ItemID.MusketBall; // Exception } var proj = Projectile.NewProjectileDirect( position, new Vector2(speedX, speedY), type, damage, knockBack, player.whoAmI); var gobblerProj = proj.ModProjectile as ProjGobblerItem; gobblerProj.Consumed = consume; gobblerProj.GobblerItem = gobblerItem; proj.netUpdate = true; if (gobblerItem.type == ItemID.Arkhalis) // Ridiculous effect for ridiculous weapon { for (int i = 0; i < 5; i++) { proj = Projectile.NewProjectileDirect( position, new Vector2(speedX, speedY) * Main.rand.NextFloat(), type, damage, knockBack, player.whoAmI); gobblerProj = proj.ModProjectile as ProjGobblerItem; gobblerProj.Consumed = false; gobblerProj.GobblerItem = gobblerItem; proj.netUpdate = true; } } } if (consume) { modPlayer.GobblerStorage.RemoveAt(0); } } } } return(false); }