private void Close() { UILoader.GetUIState <RichTextBox>().Visible = false; RichTextBox.SetData(null, "", ""); Main.player[Main.myPlayer].talkNPC = -1; textState = 0; }
public override bool NewRightClick(int i, int j) { var tile = (Tile)Framing.GetTileSafely(i, j).Clone(); if (CanOpen(Main.LocalPlayer) && tile.frameX < 32) { for (int x = 0; x < 2; x++) { for (int y = 0; y < 4; y++) { int realX = x + i - tile.frameX / 18; int realY = y + j - tile.frameY / 18; Framing.GetTileSafely(realX, realY).frameX += 36; } } Loot[] smallLoot = new Loot[5]; List <Loot> types = Helper.RandomizeList(SmallLootPool); for (int k = 0; k < 5; k++) { smallLoot[k] = types[k]; } UILoader.GetUIState <LootUI>().SetItems(GoldLootPool[Main.rand.Next(GoldLootPool.Count)], smallLoot); UILoader.GetUIState <LootUI>().Visible = true; return(true); } return(false); }
public override void RightClick(Player player) { UpdateBagSlots(); item.stack++; ChefBagUI.openBag = this; UILoader.GetUIState <ChefBagUI>().OnInitialize(); }
private void Bless() { UILoader.GetUIState <RichTextBox>().Visible = false; RichTextBox.SetData(null, "", ""); Main.player[Main.myPlayer].talkNPC = -1; Main.LocalPlayer.AddBuff(BuffType <SpikeImmuneBuff>(), 3600); //TODO: this may need manual sync later? not sure (Remember this is really being called from a UI) }
public override string GetChat() { textState = 0; UILoader.GetUIState <RichTextBox>().Visible = true; RichTextBox.ClearButtons(); SetData(); RichTextBox.AddButton("[]Next", Debug); return(""); }
private void OpenEnchantUI() { EnchantmentMenu.SetActive(npc.Center + new Vector2(0, -300), this); //ZoomHandler.SetZoomAnimation(2.5f, 60); Main.LocalPlayer.GetModPlayer <StarlightPlayer>().ScreenMoveTarget = npc.Center + new Vector2(0, -300); Main.LocalPlayer.GetModPlayer <StarlightPlayer>().ScreenMoveTime = 120; Main.LocalPlayer.GetModPlayer <StarlightPlayer>().ScreenMoveHold = true; Main.LocalPlayer.talkNPC = -1; enchanting = true; UILoader.GetUIState <RichTextBox>().Visible = false; }
public static void AddButton(string message, Action onClick) { RichTextButton add = new RichTextButton(message, onClick); add.Top.Set(HeightOff, 0); add.Left.Set(50 + Main.screenWidth / 2 - 260 + widthOff, 0); add.Width.Set(Markdown.GetWidth(message, 1) + 20, 0); add.Height.Set(32, 0); widthOff += Markdown.GetWidth(message, 1) + 24; UILoader.GetUIState <RichTextBox>().Append(add); }
public override void OnChatButtonClicked(bool firstButton, ref bool shop) { if (firstButton) { shop = true; } else { UILoader.GetUIState <TownQuestList>().Visible = true; UILoader.GetUIState <TownQuestList>().PopulateList(); } }
public override string GetChat() { textState = 0; UILoader.GetUIState <RichTextBox>().Visible = true; RichTextBox.ClearButtons(); SetData(); RichTextBox.AddButton("[]Chat", Chat); RichTextBox.AddButton("[<color:200, 140, 255>]Enchant", OpenEnchantUI); RichTextBox.AddButton("[]Move Altar", PackUp); return(""); }
public override void AI() { if (RichTextBox.talking == npc) { SetData(); if (Main.player[Main.myPlayer].talkNPC != npc.whoAmI) { UILoader.GetUIState <RichTextBox>().Visible = false; RichTextBox.SetData(null, "", ""); } } }
public override bool NewRightClick(int i, int j) { var state = UILoader.GetUIState <CookingUI>(); if (!state.Visible) { state.Visible = true; Main.PlaySound(SoundID.MenuOpen); } else { state.Visible = false; Main.PlaySound(SoundID.MenuClose); } return(true); }
public override bool NewRightClick(int i, int j) { if (CanOpen(Main.LocalPlayer)) { WorldGen.KillTile(i, j); Loot[] smallLoot = new Loot[5]; List <Loot> types = Helper.RandomizeList(SmallLootPool); for (int k = 0; k < 5; k++) { smallLoot[k] = types[k]; } UILoader.GetUIState <LootUI>().SetItems(GoldLootPool[Main.rand.Next(GoldLootPool.Count)], smallLoot); UILoader.GetUIState <LootUI>().Visible = true; return(true); } return(false); }
public override void PickupEffects(Player player) { AbilityHandler ah = player.GetHandler(); ah.Shards.Add(Parent.frameX); if (ah.ShardCount % 3 == 0) { UILoader.GetUIState <TextCard>().Display("Stamina Vessel", "Your maximum stamina has increased by 1", null, 240, 0.8f); } else { UILoader.GetUIState <TextCard>().Display("Stamina Vessel Shard", "Collect " + (3 - ah.ShardCount % 3) + " more to increase your maximum stamina", null, 240, 0.6f); } player.GetModPlayer <Core.StarlightPlayer>().MaxPickupTimer = 1; Helper.UnlockEntry <StaminaShardEntry>(Main.LocalPlayer); }
public override void PickupVisuals(int timer) { if (timer == 1) { Main.PlaySound(mod.GetLegacySoundSlot(SoundType.Custom, "Sounds/Pickups/get")); //start the SFX Filters.Scene.Deactivate("Shockwave"); } if (timer < 119) { } if (timer == 119) { string message = "Open the codex from your inventory to learn about the world."; UILoader.GetUIState <TextCard>().Display("Starlight Codex", message, null, 240); Helper.UnlockEntry <CodexEntry>(Main.LocalPlayer); } }
private string SetUpgradeUI(On.Terraria.NPC.orig_GetChat orig, NPC self) { if (StarlightWorld.TownUpgrades.TryGetValue(self.TypeName, out bool unlocked)) { if (unlocked) { UILoader.GetUIState <ChatboxOverUI>().SetState(TownUpgrade.FromString(self.TypeName)); } else { UILoader.GetUIState <ChatboxOverUI>().SetState(new LockedUpgrade()); } } else { UILoader.GetUIState <ChatboxOverUI>().SetState(null); } return(orig(self)); }
public static void UnlockEntry <type>(Player player) { CodexHandler mp = player.GetModPlayer <CodexHandler>(); CodexEntry entry = mp.Entries.FirstOrDefault(n => n is type); if (entry.RequiresUpgradedBook && mp.CodexState != 2) { return; //dont give the player void entries if they dont have the void book } if (entry.Locked) { entry.Locked = false; entry.New = true; if (mp.CodexState != 0) { UILoader.GetUIState <CodexPopup>().TripEntry(entry.Title); } Main.PlaySound(SoundID.Item30); } }
public static void UnlockEntry <type>(Player player) { CodexHandler mp = player.GetModPlayer <CodexHandler>(); CodexEntry entry = mp.Entries.FirstOrDefault(n => n is type); if (entry is null || (entry.RequiresUpgradedBook && mp.CodexState != 2)) { return; //dont give the player void entries if they dont have the void book } if (entry.Locked) { entry.Locked = false; entry.New = true; if (mp.CodexState != 0) { UILoader.GetUIState <CodexPopup>().TripEntry(entry.Title, entry.Icon); Main.PlaySound(StarlightRiver.Instance.GetLegacySoundSlot(SoundType.Custom, "Sounds/CodexUnlock")); } } }
public override void PreUpdate() { if (PickupTarget != null) { PickupTimer++; player.immune = true; player.immuneTime = 5; player.immuneNoBlink = true; player.Center = PickupTarget.Center; if (PickupTimer >= MaxPickupTimer) { PickupTarget = null; } } else { PickupTimer = 0; } platformTimer--; if (Main.netMode != NetmodeID.Server) { var staminaState = UILoader.GetUIState <Stamina>(); var infusionState = UILoader.GetUIState <Infusion>(); var codexState = UILoader.GetUIState <Content.GUI.Codex>(); var collectionState = UILoader.GetUIState <Collection>(); AbilityHandler mp = player.GetHandler(); staminaState.Visible = false; infusionState.Visible = false; if (mp.AnyUnlocked) { staminaState.Visible = true; } if (Main.playerInventory) { if (player.chest == -1 && Main.npcShop == 0) { collectionState.Visible = true; Content.GUI.Codex.ButtonVisible = true; if (mp.AnyUnlocked) { infusionState.Visible = true; } } else { collectionState.Visible = false; Content.GUI.Codex.ButtonVisible = false; if (mp.AnyUnlocked) { infusionState.Visible = false; } } } else { collectionState.Visible = false; Collection.ActiveAbility = null; Content.GUI.Codex.ButtonVisible = false; Content.GUI.Codex.Open = false; infusionState.Visible = false; } } if (DarkSlow) { player.velocity.X *= 0.8f; } DarkSlow = false; if (!player.immune) { VitricSpike.CollideWithSpikes(player, out int damage); if (damage > 0) { player.Hurt(PlayerDeathReason.ByCustomReason(player.name + " was impaled by glass shards."), damage, 0); } } }
public override void PickupVisuals(int timer) { Player player = Main.LocalPlayer; //blood spray and sounds if (timer == 15 || (timer > 120 && timer < 220 && timer % 10 == 8)) { for (int k = 0; k < 20; k++) { Dust.NewDustPerfect(player.Center, DustID.Blood, Vector2.UnitY.RotatedBy(timer / 10f - 1.57f).RotatedByRandom(0.25f) * Main.rand.NextFloat(10)); } player.headPosition = Vector2.UnitX.RotatedByRandom(3.14f) * Main.rand.NextFloat(5); player.bodyPosition = Vector2.UnitX.RotatedByRandom(3.14f) * Main.rand.NextFloat(5); player.legPosition = Vector2.UnitX.RotatedByRandom(3.14f) * Main.rand.NextFloat(5); Helper.PlayPitched("Impale", 1, Main.rand.NextFloat(0.6f, 0.9f), player.Center); Main.PlaySound(SoundID.PlayerHit, player.Center); } if (timer >= 15) { CreepyVignette.visible = true; CreepyVignette.opacityMult = 0.5f; CreepyVignette.holeSize = Vector2.One * 400; } if (timer == 360) { Helper.PlayPitched("Impale", 1, Main.rand.NextFloat(0.6f, 0.9f), player.Center); //placeholder sound } if (timer >= 360) { CreepyVignette.offset = Vector2.SmoothStep(Vector2.Zero, new Vector2(-Main.screenWidth / 2 + 100, -Main.screenHeight / 2 + 300), Math.Min(1, (timer - 360) / 120f)); CreepyVignette.opacityMult = 0.5f + Math.Min(1, (timer - 360) / 120f) * 0.25f; CreepyVignette.holeSize = Vector2.One * (400 - Math.Min(1, (timer - 360) / 120f) * 64); } if (timer < 360) { if (Main.playerInventory) { player.controlInv = true; player.releaseInventory = true; Main.playerInventory = false; } } if (timer >= 360) { if (!Main.playerInventory) { player.ToggleInv(); Main.playerInventory = true; } } if (timer > 530) { CreepyVignette.visible = false; CreepyVignette.offset = new Vector2(-Main.screenWidth / 2 + 100, -Main.screenHeight / 2 + 300); CreepyVignette.opacityMult = 0.75f - Math.Min(1, (timer - 530) / 30f) * 0.75f; CreepyVignette.holeSize = Vector2.One * (336 + (Math.Min(1, (timer - 530) / 30f) * 512)); } if (timer == 559) { UILoader.GetUIState <TextCard>().Display("Mysterious Technology", "What has it done to you?", time: 360); Helper.UnlockEntry <InfusionEntry>(Main.LocalPlayer); player.headPosition = Vector2.Zero; player.bodyPosition = Vector2.Zero; player.legPosition = Vector2.Zero; } }
public static void ClearButtons() { widthOff = 0; UILoader.GetUIState <RichTextBox>().Elements.Clear(); }
public override void AI() { //Ticks the timer GlobalTimer++; AttackTimer++; if (Phase != (int)AIStates.Leaving && arena != new Rectangle() && !Main.player.Any(n => n.active && n.statLife > 0 && n.Hitbox.Intersects(arena))) //if no valid players are detected { GlobalTimer = 0; Phase = (int)AIStates.Leaving; //begone thot! crystals.ForEach(n => n.ai[2] = 4); crystals.ForEach(n => n.ai[1] = 0); } switch (Phase) { //on spawn effects case (int)AIStates.SpawnEffects: StarlightPlayer mp = Main.LocalPlayer.GetModPlayer <StarlightPlayer>(); mp.ScreenMoveTarget = npc.Center + new Vector2(0, -850); mp.ScreenMoveTime = 600; UILoader.GetUIState <TextCard>().Display(npc.FullName, Main.rand.Next(10000) == 0 ? "Glass tax returns" : "Shattered Sentinel", null, 500); //Screen pan + intro text for (int k = 0; k < Main.maxNPCs; k++) //finds all the large platforms to add them to the list of possible locations for the nuke attack { NPC npc = Main.npc[k]; if (npc?.active == true && (npc.type == NPCType <VitricBossPlatformUp>() || npc.type == NPCType <VitricBossPlatformDown>())) { crystalLocations.Add(npc.Center + new Vector2(0, -48)); } } ChangePhase(AIStates.SpawnAnimation, true); break; case (int)AIStates.SpawnAnimation: //the animation that plays while the boss is spawning and the title card is shown if (GlobalTimer == 2) { npc.friendly = true; //so he wont kill you during the animation RandomizeTarget(); //pick a random target so the eyes will follow them } if (GlobalTimer <= 200) { npc.Center += new Vector2(0, -4f); //rise up } if (GlobalTimer > 200 && GlobalTimer <= 300) { npc.scale = 0.5f + (GlobalTimer - 200) / 200f; //grow } if (GlobalTimer > 280) //summon crystal babies { for (int k = 0; k <= 4; k++) { if (GlobalTimer == 280 + k * 30) { Vector2 target = new Vector2(npc.Center.X + (-100 + k * 50), StarlightWorld.VitricBiome.Top * 16 + 1100); int index = NPC.NewNPC((int)target.X, (int)target.Y, NPCType <VitricBossCrystal>(), 0, 2); //spawn in state 2: sandstone forme (Main.npc[index].modNPC as VitricBossCrystal).Parent = this; (Main.npc[index].modNPC as VitricBossCrystal).StartPos = target; (Main.npc[index].modNPC as VitricBossCrystal).TargetPos = npc.Center + new Vector2(0, -120).RotatedBy(6.28f / 4 * k); crystals.Add(Main.npc[index]); //add this crystal to the list of crystals the boss controls } } } if (GlobalTimer > 620) //start the fight { npc.dontTakeDamage = false; //make him vulnerable npc.friendly = false; //and hurt when touched homePos = npc.Center; //set the NPCs home so it can return here after attacks int index = NPC.NewNPC((int)npc.Center.X, (int)npc.Center.Y, NPCType <ArenaBottom>()); (Main.npc[index].modNPC as ArenaBottom).Parent = this; ChangePhase(AIStates.FirstPhase, true); ResetAttack(); const int arenaWidth = 1408; const int arenaHeight = 900; arena = new Rectangle((int)npc.Center.X - arenaWidth / 2, (int)npc.Center.Y - arenaHeight / 2, arenaWidth, arenaHeight); } break; case (int)AIStates.FirstPhase: int healthGateAmount = npc.lifeMax / 7; if (npc.life <= npc.lifeMax - (1 + crystals.Count(n => n.ai[0] == 3 || n.ai[0] == 1)) * healthGateAmount && !npc.dontTakeDamage) { npc.dontTakeDamage = true; //boss is immune at phase gate npc.life = npc.lifeMax - (1 + crystals.Count(n => n.ai[0] == 3 || n.ai[0] == 1)) * healthGateAmount - 1; //set health at phase gate Main.PlaySound(SoundID.ForceRoar, npc.Center); } if (AttackTimer == 1) //switching out attacks { if (npc.dontTakeDamage) { AttackPhase = 0; //nuke attack once the boss turns immortal for a chance to break a crystal } else //otherwise proceed with attacking pattern { AttackPhase++; if (AttackPhase > 4) { AttackPhase = 1; } } } switch (AttackPhase) //switch for crystal behavior { case 0: NukePlatforms(); break; case 1: CrystalCage(); break; case 2: CrystalSmash(); break; case 3: RandomSpikes(); break; case 4: PlatformDash(); break; } break; case (int)AIStates.Anger: //the short anger phase attack when the boss loses a crystal AngerAttack(); break; case (int)AIStates.FirstToSecond: if (GlobalTimer == 2) { foreach (NPC crystal in crystals) { crystal.ai[0] = 0; crystal.ai[2] = 5; //turn the crystals to transform mode } } if (GlobalTimer == 120) { SetFrameX(1); foreach (NPC crystal in crystals) //kill all the crystals { crystal.Kill(); } npc.friendly = true; //so we wont get contact damage } if (GlobalTimer > 120) { foreach (Player player in Main.player) { if (Abilities.AbilityHelper.CheckDash(player, npc.Hitbox)) //boss should be dashable now, when dashed: { player.immune = true; player.immuneTime = 60; SetFrameX(2); ChangePhase(AIStates.SecondPhase, true); //go on to the next phase ResetAttack(); //reset attack foreach (NPC wall in Main.npc.Where(n => n.modNPC is VitricBackdropLeft)) { wall.ai[1] = 3; //make the walls scroll } foreach (NPC plat in Main.npc.Where(n => n.modNPC is VitricBossPlatformUp)) { plat.ai[0] = 1; //make the platforms scroll } break; } } } /*if (GlobalTimer > 900) //after waiting too long, wipe all players * { * foreach (Player player in Main.player.Where(n => n.Hitbox.Intersects(arena))) * { * player.KillMe(Terraria.DataStructures.PlayerDeathReason.ByCustomReason(player.name + " was shattered..."), double.MaxValue, 0); * } * ChangePhase(AIStates.Leaving, true); * }*/ break; case (int)AIStates.SecondPhase: if (GlobalTimer == 60) { npc.dontTakeDamage = false; //damagable again npc.friendly = false; } if (GlobalTimer == 1) { music = mod.GetSoundSlot(SoundType.Music, "VortexHasASmallPussy"); //handles the music transition } if (GlobalTimer == 2) { music = mod.GetSoundSlot(SoundType.Music, "Sounds/Music/GlassBossTransition"); } if (GlobalTimer == 701) { music = mod.GetSoundSlot(SoundType.Music, "VortexHasASmallPussy"); } if (GlobalTimer == 702) { music = mod.GetSoundSlot(SoundType.Music, "Sounds/Music/GlassBoss2"); } if (GlobalTimer > 702 && GlobalTimer < 760) //no fadein { for (int k = 0; k < Main.musicFade.Length; k++) { if (k == Main.curMusic) { Main.musicFade[k] = 1; } } } if (AttackTimer == 1) //switching out attacks { AttackPhase++; if (AttackPhase > 3) { AttackPhase = 0; } } switch (AttackPhase) //switch for crystal behavior { case 0: Volley(); break; case 1: Mines(); break; case 2: Whirl(); break; case 3: Rest(); break; } break; case (int)AIStates.Leaving: npc.position.Y += 7; if (GlobalTimer >= 180) { npc.active = false; //leave foreach (NPC npc in Main.npc.Where(n => n.modNPC is VitricBackdropLeft || n.modNPC is VitricBossPlatformUp)) { npc.active = false; //arena reset } } break; case (int)AIStates.Dying: if (GlobalTimer == 1) { foreach (NPC npc in Main.npc.Where(n => n.modNPC is VitricBackdropLeft || n.modNPC is VitricBossPlatformUp)) { npc.ai[1] = 4; } startPos = npc.Center; } if (GlobalTimer < 60) { npc.Center = Vector2.SmoothStep(startPos, homePos, GlobalTimer / 60f); } if (GlobalTimer == 60) { Main.PlaySound(SoundID.DD2_WinScene, npc.Center); //SFX } if (GlobalTimer > 60 && GlobalTimer < 120) { Main.musicFade[Main.curMusic] = 1 - (GlobalTimer - 60) / 60f; } if (GlobalTimer > 120) { Main.musicFade[Main.curMusic] = 0; for (int k = 0; k < 10; k++) { Dust.NewDustPerfect(npc.Center, DustType <Dusts.Sand>(), Vector2.One.RotatedByRandom(6.28f) * Main.rand.NextFloat(10), 40, default, 2); } for (int k = 0; k < 2; k++) { Dust.NewDustPerfect(npc.Center, DustType <Dusts.Starlight>(), Vector2.One.RotatedByRandom(6.28f) * Main.rand.NextFloat(100)); } }
public override void AI() { //Ticks the timer GlobalTimer++; AttackTimer++; //twisting if (twistTimer < maxTwistTimer) { twistTimer++; } if (twistTimer == maxTwistTimer) { lastTwistState = twistTarget; } //Main AI body.UpdateBody(); //update the physics on the body Lighting.AddLight(npc.Center, new Vector3(1, 0.8f, 0.4f)); //glow if (Phase != (int)AIStates.Leaving && arena != new Rectangle() && !Main.player.Any(n => n.active && n.statLife > 0 && n.Hitbox.Intersects(arena))) //if no valid players are detected { GlobalTimer = 0; Phase = (int)AIStates.Leaving; //begone thot! crystals.ForEach(n => n.ai[2] = 4); crystals.ForEach(n => n.ai[1] = 0); } switch (Phase) { //on spawn effects case (int)AIStates.SpawnEffects: StarlightPlayer mp = Main.LocalPlayer.GetModPlayer <StarlightPlayer>(); mp.ScreenMoveTarget = npc.Center + new Vector2(0, -850); mp.ScreenMoveTime = 600; UILoader.GetUIState <TextCard>().Display(npc.FullName, Main.rand.Next(10000) == 0 ? "Glass tax returns" : "Shattered Sentinel", null, 500); //Screen pan + intro text for (int k = 0; k < Main.maxNPCs; k++) //finds all the large platforms to add them to the list of possible locations for the nuke attack { NPC npc = Main.npc[k]; if (npc?.active == true && (npc.type == NPCType <VitricBossPlatformUp>() || npc.type == NPCType <VitricBossPlatformDown>())) { crystalLocations.Add(npc.Center + new Vector2(0, -48)); } } const int arenaWidth = 1408; const int arenaHeight = 900; arena = new Rectangle((int)npc.Center.X - arenaWidth / 2, (int)npc.Center.Y - 800 - arenaHeight / 2, arenaWidth, arenaHeight); ChangePhase(AIStates.SpawnAnimation, true); break; case (int)AIStates.SpawnAnimation: //the animation that plays while the boss is spawning and the title card is shown if (GlobalTimer == 2) { npc.friendly = true; //so he wont kill you during the animation RandomizeTarget(); //pick a random target so the eyes will follow them } if (GlobalTimer <= 200) { npc.Center += new Vector2(0, -4f); //rise up } if (GlobalTimer > 280) //summon crystal babies { for (int k = 0; k <= 4; k++) { if (GlobalTimer == 280 + k * 30) { Vector2 target = new Vector2(npc.Center.X + (-100 + k * 50), StarlightWorld.VitricBiome.Top * 16 + 1100); int index = NPC.NewNPC((int)target.X, (int)target.Y, NPCType <VitricBossCrystal>(), 0, 2); //spawn in state 2: sandstone forme (Main.npc[index].modNPC as VitricBossCrystal).Parent = this; (Main.npc[index].modNPC as VitricBossCrystal).StartPos = target; (Main.npc[index].modNPC as VitricBossCrystal).TargetPos = npc.Center + new Vector2(0, -120).RotatedBy(6.28f / 4 * k); crystals.Add(Main.npc[index]); //add this crystal to the list of crystals the boss controls } } } if (GlobalTimer > 620) //start the fight { npc.dontTakeDamage = false; //make him vulnerable npc.friendly = false; //and hurt when touched homePos = npc.Center; //set the NPCs home so it can return here after attacks int index = NPC.NewNPC((int)npc.Center.X, (int)npc.Center.Y, NPCType <ArenaBottom>()); (Main.npc[index].modNPC as ArenaBottom).Parent = this; ChangePhase(AIStates.FirstPhase, true); ResetAttack(); } break; case (int)AIStates.FirstPhase: int healthGateAmount = npc.lifeMax / 7; if (npc.life <= npc.lifeMax - (1 + crystals.Count(n => n.ai[0] == 3 || n.ai[0] == 1)) * healthGateAmount && !npc.dontTakeDamage) { npc.dontTakeDamage = true; //boss is immune at phase gate npc.life = npc.lifeMax - (1 + crystals.Count(n => n.ai[0] == 3 || n.ai[0] == 1)) * healthGateAmount - 1; //set health at phase gate Main.PlaySound(SoundID.ForceRoar, npc.Center); } if (AttackTimer == 1) //switching out attacks { if (npc.dontTakeDamage) { AttackPhase = 0; //nuke attack once the boss turns immortal for a chance to break a crystal } else //otherwise proceed with attacking pattern { AttackPhase++; if (AttackPhase > 4) { AttackPhase = 1; } } } switch (AttackPhase) //Attacks { case 0: NukePlatforms(); break; case 1: CrystalCage(); break; case 2: CrystalSmash(); break; case 3: RandomSpikes(); break; case 4: PlatformDash(); break; } break; case (int)AIStates.Anger: //the short anger phase attack when the boss loses a crystal AngerAttack(); break; case (int)AIStates.FirstToSecond: Vignette.offset = (npc.Center - Main.LocalPlayer.Center) * 0.9f; Vignette.extraOpacity = 0.5f + (float)Math.Sin(GlobalTimer / 25f) * 0.2f; if (GlobalTimer == 2) { music = mod.GetSoundSlot(SoundType.Music, "Sounds/Music/GlassBossAmbient"); foreach (NPC crystal in crystals) { crystal.ai[0] = 0; crystal.ai[2] = 5; //turn the crystals to transform mode } } if (GlobalTimer == 120) { SetFrameX(1); foreach (NPC crystal in crystals) //kill all the crystals { crystal.Kill(); } npc.friendly = true; //so we wont get contact damage StarlightPlayer mp2 = Main.LocalPlayer.GetModPlayer <StarlightPlayer>(); mp2.ScreenMoveTarget = npc.Center; mp2.ScreenMoveTime = 660; } if (GlobalTimer > 120 && GlobalTimer < 240) { npc.Center = Vector2.SmoothStep(homePos, homePos + new Vector2(0, 650), (GlobalTimer - 120) / 120f); } if (GlobalTimer > 240 && GlobalTimer < 700 && GlobalTimer % 120 == 0) { StarlightPlayer mp2 = Main.LocalPlayer.GetModPlayer <StarlightPlayer>(); mp2.Shake += (int)(GlobalTimer / 20); } if (GlobalTimer >= 700 && GlobalTimer < 730) { npc.Center = Vector2.SmoothStep(homePos + new Vector2(0, 650), homePos, (GlobalTimer - 700) / 30f); } if (GlobalTimer == 760) { Main.PlaySound(SoundID.Roar, npc.Center); StarlightPlayer mp2 = Main.LocalPlayer.GetModPlayer <StarlightPlayer>(); mp2.Shake += 60; } if (GlobalTimer > 850) { SetFrameX(2); ChangePhase(AIStates.SecondPhase, true); //go on to the next phase ResetAttack(); //reset attack foreach (NPC wall in Main.npc.Where(n => n.modNPC is VitricBackdropLeft)) { wall.ai[1] = 3; //make the walls scroll } foreach (NPC plat in Main.npc.Where(n => n.modNPC is VitricBossPlatformUp)) { plat.ai[0] = 1; //make the platforms scroll } Vignette.visible = true; break; } break; case (int)AIStates.SecondPhase: Vignette.offset = (npc.Center - Main.LocalPlayer.Center) * 0.8f; Vignette.extraOpacity = 0.3f; if (GlobalTimer == 60) { npc.dontTakeDamage = false; //damagable again npc.friendly = false; Vignette.visible = true; } if (GlobalTimer == 1) { music = mod.GetSoundSlot(SoundType.Music, "VortexHasASmallPussy"); //handles the music transition } if (GlobalTimer == 2) { music = mod.GetSoundSlot(SoundType.Music, "Sounds/Music/GlassBoss2"); } if (GlobalTimer > 702 && GlobalTimer < 760) //no fadein { for (int k = 0; k < Main.musicFade.Length; k++) { if (k == Main.curMusic) { Main.musicFade[k] = 1; } } } if (AttackTimer == 1) //switching out attacks { AttackPhase++; if (AttackPhase > 3) { AttackPhase = 0; } } switch (AttackPhase) //switch for crystal behavior { case 0: Volley(); break; case 1: Mines(); break; case 2: Whirl(); break; case 3: Rest(); break; } break; case (int)AIStates.LastStand: if (GlobalTimer == 1) { foreach (NPC npc in Main.npc.Where(n => n.modNPC is VitricBackdropLeft || n.modNPC is VitricBossPlatformUp)) { npc.ai[1] = 4; } Vignette.extraOpacity = 0; startPos = npc.Center; } if (GlobalTimer < 60) { npc.Center = Vector2.SmoothStep(startPos, homePos + new Vector2(0, -100), GlobalTimer / 60f); } if (GlobalTimer == 90) { Twist(30); } if (GlobalTimer > 120 && GlobalTimer <= 140) { glowColor = Color.Lerp(Color.Transparent, Color.White, (GlobalTimer - 120) / 20f); } if (GlobalTimer == 140) { npc.frame.Y += 160; } if (GlobalTimer > 140 && GlobalTimer <= 200) { glowColor = Color.Lerp(Color.White, Color.Red * 0.5f, (GlobalTimer - 140) / 60f); } if (GlobalTimer > 200 && GlobalTimer <= 240) { glowColor = Color.Lerp(Color.Red * 0.5f, Color.Transparent, (GlobalTimer - 200) / 40f); } if (GlobalTimer == 300) { int i = NPC.NewNPC((int)npc.Center.X - 200, (int)npc.Center.Y - 180, NPCType <GlassMinibossHelpful>()); (Main.npc[i].modNPC as GlassMinibossHelpful).parent = this; } if (GlobalTimer > 660) { if (GlobalTimer % 120 == 0) { Main.NewText("ShootFire"); Main.PlaySound(SoundID.DD2_BetsyScream); int i = Projectile.NewProjectile(npc.Center, Vector2.Normalize(Main.player[npc.target].Center - npc.Center) * 3, ProjectileType <FinalFire>(), 100, 0, Main.myPlayer); (Main.projectile[i].modProjectile as FinalFire).parent = this; } } break; case (int)AIStates.Leaving: npc.position.Y += 7; Vignette.visible = false; if (GlobalTimer >= 180) { npc.active = false; //leave foreach (NPC npc in Main.npc.Where(n => n.modNPC is VitricBackdropLeft || n.modNPC is VitricBossPlatformUp)) { npc.active = false; //arena reset } } break; case (int)AIStates.Dying: Vignette.offset = Vector2.Zero; Vignette.extraOpacity = 0.5f + Math.Min(GlobalTimer / 60f, 0.5f); if (GlobalTimer == 60) { Main.PlaySound(mod.GetLegacySoundSlot(SoundType.Custom, "Sounds/GlassBossDeath")); } if (GlobalTimer > 60 && GlobalTimer < 120) { Main.musicFade[Main.curMusic] = 1 - (GlobalTimer - 60) / 60f; } if (GlobalTimer > 120) { Main.musicFade[Main.curMusic] = 0; for (int k = 0; k < 10; k++) { Dust.NewDustPerfect(npc.Center, DustType <Dusts.Sand>(), Vector2.One.RotatedByRandom(6.28f) * Main.rand.NextFloat(10), 40, default, 2); } for (int k = 0; k < 2; k++) { Dust.NewDustPerfect(npc.Center, DustType <Dusts.Starlight>(), Vector2.One.RotatedByRandom(6.28f) * Main.rand.NextFloat(100)); } }
public override void AI() { Lighting.AddLight(npc.Center, new Vector3(1, 1, 0.8f)); GlobalTimer++; //tick our timer up constantly AttackTimer++; //tick up our attack timer if (npc.ai[0] == (int)OvergrowBossPhase.Struggle) //when the boss is trapped before spawning the first time { if (spawnPoint == Vector2.Zero) { spawnPoint = npc.Center; //sets the boss' home } npc.velocity.Y = (float)Math.Sin((GlobalTimer % 120) / 120f * 6.28f) * 0.6f; if (!Main.npc.Any(n => n.active && n.type == NPCType <OvergrowBossAnchor>())) //once the chains are broken { npc.velocity *= 0; npc.Center = spawnPoint; GlobalTimer = 0; StarlightPlayer mp = Main.LocalPlayer.GetModPlayer <StarlightPlayer>(); mp.ScreenMoveTime = 860; mp.ScreenMoveTarget = npc.Center; mp.ScreenMovePan = npc.Center + new Vector2(0, -100); Phase = (int)OvergrowBossPhase.spawnAnimation; } } if (Phase == (int)OvergrowBossPhase.spawnAnimation) //the boss' spawn animation. { if (GlobalTimer == 1) { music = mod.GetSoundSlot(SoundType.Music, "Sounds/Music/OvergrowBoss"); } if (GlobalTimer <= 120) { npc.position.Y--; } if (GlobalTimer == 120) { StarlightWorld.Flag(WorldFlags.OvergrowBossFree); } if (GlobalTimer == 500) { string message = "Faerie Guardian"; if (Main.rand.Next(10000) == 0) { message = "Titty Elongator"; // Yep } UILoader.GetUIState <TextCard>().Display("Eggshells", message, null, 220); } if (GlobalTimer >= 860) { Phase = (int)OvergrowBossPhase.Setup; } } if (Phase == (int)OvergrowBossPhase.Setup) { npc.boss = true; int index = NPC.NewNPC((int)npc.Center.X, (int)npc.Center.Y, NPCType <OvergrowBossFlail>()); //spawn the flail after intro (Main.npc[index].modNPC as OvergrowBossFlail).parent = this; //set the flail's parent flail = Main.npc[index].modNPC as OvergrowBossFlail; //tells the boss what flail it owns Phase = (int)OvergrowBossPhase.FirstAttack; //move on to the first attack phase GlobalTimer = 0; //reset our timer npc.ai[3] = 0; //reset our attack timer } if (flail == null) { return; //at this point, our boss should have her flail. if for some reason she dosent, this is a safety check } if (Phase == (int)OvergrowBossPhase.FirstAttack) //the first attacking phase { //attack pattern advancement logic if (AttackTimer == 1) { RandomizeTarget(); if (AttackPhase == 1) { AttackPhase++; //tick up an additional time so that we dont use 2 alternate attacks in a row. TODO: Should make a cleaner way to do this. } AttackPhase++; if (AttackPhase == 1 && Main.rand.Next(2) == 0) { AttackPhase++; } if (AttackPhase > 6) { AttackPhase = 0; } if (flail.npc.life <= 1) //move to next phase once the flail is depleated { Phase = (int)OvergrowBossPhase.FirstToss; AttackPhase = 0; ResetAttack(); //foreach (Projectile proj in Main.projectile.Where(p => p.type == ProjectileType<Projectiles.Dummies.OvergrowBossPitDummy>())) proj.ai[1] = 1; //opens the pits } } switch (AttackPhase) //attack pattern { case 0: Phase1Spin(); break; case 1: Phase1Bolts(); break; //______randonly picks between these two case 2: Phase1Trap(); break; //___| case 3: Phase1Toss(); break; case 4: Phase1Toss(); break; case 5: Phase1Bolts(); break; case 6: Phase1Toss(); break; } } if (Phase == (int)OvergrowBossPhase.FirstToss) { RapidToss(); //toss rapidly till thrown into a pit } if (Phase == (int)OvergrowBossPhase.Stun) { if (GlobalTimer == 1) { npc.alpha = 255; for (int k = 0; k < 100; k++) { Dust d = Dust.NewDustPerfect(npc.Center, 1 /*DustType<>()*/, Vector2.One.RotatedByRandom(Math.PI) * Main.rand.NextFloat(5)); d.customData = npc.Center; } npc.Center = spawnPoint + new Vector2(0, 320); flail.npc.ai[0] = 1; } if (GlobalTimer >= 120) { npc.alpha = 0; if (npc.Hitbox.Intersects(flail.npc.Hitbox)) { flail.npc.ai[0] = 0; flail.npc.ai[3] = 1; flail.npc.velocity *= 0; flail.npc.life = flail.npc.lifeMax; flail.npc.dontTakeDamage = false; flail.npc.friendly = false; npc.life -= 20000; Phase = (int)OvergrowBossPhase.SecondAttack; ResetAttack(); CombatText.NewText(npc.Hitbox, Color.Red, 20000, true); Main.PlaySound(SoundID.DD2_BetsyScream, npc.Center); Main.LocalPlayer.GetModPlayer <StarlightPlayer>().Shake += 30; for (int k = 0; k < 100; k++) { Dust d = Dust.NewDustPerfect(flail.npc.Center, DustType <Dusts.Stone>(), Vector2.One.RotatedByRandom(Math.PI) * Main.rand.NextFloat(5)); } } } } }