using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using Godot; using Godot.Bridge; using Godot.Collections; using Godot.NativeInterop; [ScriptPath("res://Scripts/Battle/BattleDR.cs")] public partial class BattleDR : Node2D { public enum State { Override, Next, PlayerTurn, SelectSkill, SelectItem, SelectTarget, DoSpells, DoAttack, DoEnemy, EndTurn, SelectAct } public enum Selected { Attack, Magic, Act, Item, Defend, Spare } public enum EndState { None, Special, Spared, Executed, Apprehended, Defeated } public enum EventBattle { None, WardenTutorial } [Signal] public delegate void PlayerTurnEndEventHandler(); [Signal] public delegate void EnemyTurnEndEventHandler(); public struct StartStats { public int[] hp; public int money; public Items.IDs[] items; public Audio.AudioBlock audioBlock; public Entity.IDs[] enemies; public bool bg; public bool special; public string mes; public Color roomMod; } public static BattleDR current; public State state; private Sprite2D background; public BulletBoards.SoulType defaultSoul; public BulletBoards.SoulType currentMode; public List allBattlers = new List(); public List enemies = new List(); public List party = new List(); private Enemy caller; public Coroutine busy; public Coroutine events; public EventBattle eventBattle; public List fleeing = new List(); private Vector3[] partyStartPos; public Node2D shield; public int turn; public int currentActor; public int lastMes; public int mesCount; public int prizeM; public int prizeE; public List lastActor = new List(); private bool doBG; private bool grazed; private bool firstMes; private bool playerSelect; public bool started; public bool spareAble; public bool specialWarning; public bool forceEnd; public CharacterBody2D soul; private string battleMes; public static float inputCD; public int TP; public int option; public int maxOption; public int tpPreview; public int selectedLast; public int forceMes = -1; public int focusAtk = -1; private List lastTP = new List(); private List consumeItems = new List(); public List shots = new List(); public Color bgColor = Main.colorWhite; public int[] blockedCommands; public HashSet tempFlags = new HashSet(); public List toDelete = new List(); private System.Collections.Generic.Dictionary actExtra = new System.Collections.Generic.Dictionary(); public List diag; public List portraits; private int[] possible; public int[][] resultAmts = new int[6][] { new int[2], new int[2] { 1, 0 }, new int[2] { 2, 0 }, new int[2] { 3, 0 }, new int[2] { 4, 0 }, new int[2] { 5, 0 } }; private RichTextLabel currentDiagText; public Battlers currentlyActing; public float iFrames; public float grazeCD; public BulletBoards activeBoard; public static EndState lastResult; private AudioStream owMusic; public static StartStats? reloadStats; private static readonly AudioStream defaultBTheme = GD.Load("res://Audio/Music/rudebusteryellow.wav"); private const int sort = 2000; private const int introTime = 20; private const int defendTP = 16; private const int grazeTP = 3; private const int maxShoot = 5; private const int defaultIframe = 40; private static System.Collections.Generic.Dictionary blurbText; public static System.Collections.Generic.Dictionary enemyData; public static readonly Vector2[][] partyPos = new Vector2[5][] { new Vector2[1] { new Vector2(-100f, 0f) }, new Vector2[2] { new Vector2(-86f, -34f), new Vector2(-103f, 18f) }, new Vector2[3] { new Vector2(-97f, -68f), new Vector2(-86f, -24f), new Vector2(-103f, 18f) }, new Vector2[4] { new Vector2(-97f, -68f), new Vector2(-74f, -37f), new Vector2(-101f, -13f), new Vector2(-83f, 15f) }, new Vector2[5] { new Vector2(-99f, -76f), new Vector2(-71f, -47f), new Vector2(-108f, -27f), new Vector2(-73f, -5f), new Vector2(-103f, 18f) } }; private const float textBarLength = 15f; private const float fleeTime = 7f; private const float boardSpeed = 20f; public int lastBoard; private StringName lastAttack; private static readonly List enAnim = new List { "Idle", "Happy", "Sad", "Weak" }; private Color soulColor; private float shootCD; private const float soulSpeed = 55f; private const float defaultShootCD = 10f; private static readonly PackedScene soulBullet = GD.Load("res://Objects/Bullets/SoulBullet.tscn"); public const float damageRand = 0.1f; private List extended = new List { State.SelectSkill, State.SelectAct, State.SelectItem }; public static void LoadData(bool reload = false) { if (enemyData == null || reload) { enemyData = new System.Collections.Generic.Dictionary(); blurbText = new System.Collections.Generic.Dictionary(); string[] array = FileAccess.Open(Texts.textFolder + "Blurbs.txt", FileAccess.ModeFlags.Read).GetAsText(skipCr: true).Split('\n'); BattleData battleData = GD.Load("res://Data/Battlers.tres"); for (int i = 0; i < battleData.enemies.Length; i++) { Entity.IDs key = (Entity.IDs)Enum.Parse(typeof(Entity.IDs), battleData.enemies[i].ResourceName); enemyData.Add(key, battleData.enemies[i]); for (int j = 0; j < array.Length; j++) { if (array[j] == "@" + battleData.enemies[i].ResourceName) { List list = new List(); for (int k = j + 1; k < array.Length && array[k].Length >= 3; k++) { list.Add(array[k]); } blurbText.Add(key, list.ToArray()); } } } } if (Texts.battleMes == null || Texts.battleMes.Count < 1 || reload) { Texts.SetBattleMes(); } } public static IEnumerator IntroNoise() { Audio.PlaySound("snd_tensionhorn_ch1.wav"); for (float a = 0f; a < 17f; a += Main.deltaTime) { yield return null; } Audio.PlaySound("snd_tensionhorn_ch1.wav", 1f, 1.1f); for (float a = 0f; a < 23f; a += Main.deltaTime) { yield return null; } } public static IEnumerator StartBattle(Enemy caller, bool useOWBG = false, Entity.IDs[] enemies = null, List enemyEntities = null, string battleMes = null, Audio.AudioBlock music = null, bool quickIntro = false) { GameOver.repeatable = Main.inEvent != null; if (Acts.instance == null) { Acts.instance = new Acts(); } DWMenu.instance.battleText.Text = ""; DWMenu.instance.mainBox.Visible = false; SaveFile.current.values[6]++; lastResult = EndState.None; LoadData(); DWMenu.instance.soulHitbox.AddException(DWMenu.instance.soulGrazebox); Player.instance.canInput = false; Player.instance.StopMoving(); CameraController.instance.AddChild(current = new BattleDR { Name = "Battle", ZIndex = 1200 }, forceReadableName: false, InternalMode.Disabled); if (caller != null) { caller.currentAnim = Entity.Animations.Hurt; if (GodotObject.IsInstanceValid(caller.emoticonObj)) { caller.emoticonObj.Free(); } } yield return null; Room.current.ProcessMode = ProcessModeEnum.Disabled; current.battleMes = battleMes; if (DWMenu.instance.soulGrazebox != null) { DWMenu.instance.soulGrazebox.AreaEntered += current.Graze; } if (caller != null && !quickIntro) { current.caller = caller; Coroutine i = Coroutine.Start(IntroNoise()); while (!i.done) { yield return null; } } if (Main.inEvent == null) { current.owMusic = Audio.music.Stream; } Audio.ChangeMusic((Audio.AudioBlock)null, 0.5f); current.doBG = !useOWBG; Room.UpdateEntityList(); foreach (Entity entity3 in Room.current.entities) { Main.SetActive(entity3, state: false); } Player.SetActive(state: false); current.partyStartPos = new Vector3[SaveFile.current.activeParty.Count]; if (!useOWBG) { current.background = new Sprite2D(); } List pos = new List(); for (int j = 0; j < SaveFile.current.activeParty.Count; j++) { current.allBattlers.Add(Party.party[SaveFile.current.activeParty[j]]); Entity entity = GD.Load("res://Objects/Characters/" + Party.party[SaveFile.current.activeParty[j]].id.ToString() + ".tscn").Instantiate(PackedScene.GenEditState.Disabled); if (reloadStats.HasValue) { List list = current.allBattlers; list[list.Count - 1].HP = reloadStats.Value.hp[j]; } List list2 = current.allBattlers; list2[list2.Count - 1].entity = entity; List list3 = current.allBattlers; list3[list3.Count - 1].id = entity.id; List list4 = current.allBattlers; list4[list4.Count - 1].posID = j; List list5 = current.allBattlers; list5[list5.Count - 1].selectedAction = null; List list6 = current.allBattlers; list6[list6.Count - 1].atkMod = null; List list7 = current.allBattlers; list7[list7.Count - 1].defMod = null; current.AddChild(entity, forceReadableName: false, InternalMode.Disabled); entity.trigger.ProcessMode = ProcessModeEnum.Disabled; entity.direction = Entity.Direction.West; entity.animMod = Entity.AnimMods.DW; List list8 = current.allBattlers; entity.battleData = list8[list8.Count - 1]; entity.CollisionLayer = 0u; entity.CollisionMask = 0u; entity.UpdateAnim(force: true); List list9 = current.party; List list10 = current.allBattlers; list9.Add(list10[list10.Count - 1]); entity.GlobalPosition = ((j == 0) ? Player.instance.GlobalPosition : Player.instance.followers[j - 1].GlobalPosition); if (j == 0) { List list11 = current.allBattlers; list11[list11.Count - 1].oEntity = Player.instance; } else { List list12 = current.allBattlers; list12[list12.Count - 1].oEntity = Player.instance.followers[j - 1]; } pos.Add(entity.Position); entity.ZIndex = 2000 + j; entity.doTrail = true; DWMenu.instance.partyHUDs[j].battleStuff.Visible = true; } bool hasCriminal = false; for (int k = 0; k < enemies.Length; k++) { Battlers battlers = (Battlers)enemyData[enemies[k]].Duplicate(); Vector2 globalPosition = current.GlobalPosition + new Vector2(200f, 0f); if (enemyEntities != null) { for (int l = 0; l < enemyEntities.Count && l < enemies.Length; l++) { globalPosition = enemyEntities[l].GlobalPosition; } } Entity entity2; current.AddChild(entity2 = GD.Load("res://Objects/Characters/" + enemies[k].ToString() + ".tscn").Instantiate(PackedScene.GenEditState.Disabled), forceReadableName: false, InternalMode.Disabled); battlers.entity = entity2; battlers.id = enemies[k]; if (entity2.trigger != null) { entity2.trigger.ProcessMode = ProcessModeEnum.Disabled; } entity2.direction = Entity.Direction.East; current.enemies.Add(battlers); current.allBattlers.Add(battlers); List list13 = current.allBattlers; entity2.battleData = list13[list13.Count - 1]; entity2.CollisionLayer = 0u; entity2.CollisionMask = 0u; battlers.posID = k; if (entity2.anim != null) { Array> animOverrides = entity2.battleData.animOverrides; if (animOverrides != null && animOverrides.Count > 0) { entity2.replaceAnim.AddRange(entity2.battleData.animOverrides); } entity2.anim.Play("Idle"); } entity2.GlobalPosition = globalPosition; pos.Add(entity2.Position); battlers.enemy = true; entity2.ZIndex = 2000 + k; List list14 = current.enemies; if (list14[list14.Count - 1].isOutlaw) { List list15 = current.enemies; if (list15[list15.Count - 1].id != Entity.IDs.Warden) { hasCriminal = true; } } } DWMenu.instance.tpVar = 0; Party.UpdateHUD(); DWMenu.instance.Visible = true; DWMenu.instance.showHP = -200f; DWMenu.instance.battleCover.Visible = true; current.soul = DWMenu.instance.soulBody; current.soul.Visible = false; for (float a = 0f; a <= 21f; a += Main.deltaTime) { int m = 0; int num = 0; int num2 = 0; for (; m < current.allBattlers.Count; m++) { Vector2 vector; if (current.allBattlers[m].enemy) { vector = new Vector2(0f - partyPos[current.enemies.Count - 1][num2].X, partyPos[current.enemies.Count - 1][num2].Y) + Vector2.Down * ((current.enemies.Count == 1) ? (-20) : 16) + current.allBattlers[m].positionOffset; if (enemies.Length == 2) { vector += Vector2.Up * 16f; } current.allBattlers[m].startPos = vector; num2++; } else { if (a == 0f) { current.allBattlers[m].entity.currentAnim = Entity.Animations.BattleStart; } vector = partyPos[SaveFile.current.activeParty.Count - 1][num]; num++; } current.allBattlers[m].entity.Position = pos[m].Lerp(vector, Mathf.Min(a / 20f, 1f)); } yield return null; } if (music == null) { Audio.ChangeMusic(defaultBTheme); } else { Audio.ChangeMusic(music, 0.5f); } Audio.PlaySound("snd_weaponpull.wav"); for (int n = 0; n < current.allBattlers.Count; n++) { current.allBattlers[n].entity.doTrail = false; } CameraController.Transition(Main.colorClearB, 15f); if (hasCriminal) { current.defaultSoul = BulletBoards.SoulType.Shoot; Coroutine i = Coroutine.Start(ShootSoulChangeAnim()); while (!i.done) { yield return null; } } else { current.soul.RotationDegrees = 0f; } current.started = true; current.state = State.Next; GameOver.instance = null; current.soul.TopLevel = false; yield return null; if (!reloadStats.HasValue) { reloadStats = new StartStats { items = SaveFile.current.dwItems.ToArray(), hp = new int[SaveFile.current.activeParty.Count], money = SaveFile.current.dollars, enemies = enemies, audioBlock = music, bg = useOWBG, special = (lastResult == EndState.Special), mes = battleMes, roomMod = Room.current.Modulate }; for (int num3 = 0; num3 < SaveFile.current.activeParty.Count; num3++) { reloadStats.Value.hp[num3] = Party.party[SaveFile.current.activeParty[num3]].HP; } } else { SaveFile.current.dwItems = new List(reloadStats.Value.items); SaveFile.current.dollars = reloadStats.Value.money; Room.current.Modulate = reloadStats.Value.roomMod; for (int num4 = 0; num4 < SaveFile.current.activeParty.Count; num4++) { Party.party[SaveFile.current.activeParty[num4]].HP = reloadStats.Value.hp[num4]; } if (reloadStats.Value.special) { lastResult = EndState.Special; } Party.UpdateHUD(); } } private static IEnumerator ShootSoulChangeAnim() { current.soul.RotationDegrees = 0f; current.soul.GlobalPosition = current.party[0].entity.GlobalPosition + Vector2.Up * 16f; float a; for (a = 0f; a < 20f; a += Main.deltaTime) { yield return null; } current.soul.Visible = true; Main.Particle("SoulSplit", Vector2.Up * 16f, 1, current.party[0].entity); Audio.PlaySound("snd_great_shine.ogg"); for (a = 0f; a < 40f; a += Main.deltaTime) { current.bgColor = Main.colorWhite.Lerp(Main.colorDark, a / 30f); yield return null; } Audio.PlaySound("snd_spearappear_ch1.wav"); a = 0f; for (float b = 40f; a <= b + 1f; a += Main.deltaTime) { current.soul.Rotation = Mathf.LerpAngle(0f, Mathf.DegToRad(-90f), Mathf.Min(a / b, 1f)); yield return null; } for (float b = 0f; b < 20f; b += Main.deltaTime) { yield return null; } Main.Particle("SoulSplit", Vector2.Up * 16f, 1, current.party[0].entity); Audio.PlaySound("snd_great_shine.ogg"); for (float b = 0f; b < 40f; b += Main.deltaTime) { current.bgColor = Main.colorDark.Lerp(Main.colorWhite, b / 30f); yield return null; } } private void ReturnToPrevious() { if (lastActor.Count <= 0) { return; } List list = lastActor; currentActor = list[list.Count - 1]; List list2 = lastTP; TP = list2[list2.Count - 1]; lastTP.RemoveAt(lastTP.Count - 1); List list3 = consumeItems; if (list3[list3.Count - 1] != Items.IDs.None) { List dwItems = SaveFile.current.dwItems; List list4 = consumeItems; dwItems.Add(list4[list4.Count - 1]); } consumeItems.RemoveAt(consumeItems.Count - 1); if (actExtra.Count > 0) { if (actExtra.ContainsKey(currentActor)) { for (int i = 0; i < actExtra[currentActor].Length; i++) { Party.party[(int)actExtra[currentActor][i]].acted = false; Party.party[(int)actExtra[currentActor][i]].entity.currentAnim = Entity.Animations.BattleIdle; } } actExtra.Remove(currentActor); } allBattlers[currentActor].selectedAction = null; allBattlers[currentActor].entity.currentAnim = Entity.Animations.BattleIdle; lastActor.RemoveAt(lastActor.Count - 1); option = 0; UpdateMenu(); } private void UpdateDiag() { List list = diag; if (list == null || list.Count <= 0) { return; } List list2 = portraits; if (list2 != null && list2.Count > 0) { currentDiagText = DWMenu.instance.battleText2; DWMenu.instance.battlePortrait.Visible = portraits[0] != null; DWMenu.instance.battlePortrait.Play(portraits[0]); if (!TextSystem.bleepPlayer.Playing) { float volume = 1f; TextSystem.AssignBleep(portraits[0], ref volume); TextSystem.bleepPlayer.Play(); } } else { currentDiagText = DWMenu.instance.battleText; } currentDiagText.Visible = true; Party.ShowBattleCommands(-1); currentDiagText.Text = diag[0]; if (currentDiagText.VisibleRatio < 1f) { currentDiagText.VisibleCharacters++; } else { DWMenu.instance.battlePortrait.Stop(); if (TextSystem.bleepPlayer.Playing) { TextSystem.bleepPlayer.Stop(); } } if (inputCD <= 0f && Input.IsActionJustPressed(Main.keys[4])) { AdvanceDiag(); } } public void AdvanceDiag(bool skipskip = false) { List list = diag; if (list == null || list.Count <= 0) { return; } if (TextSystem.bleepPlayer.Playing) { TextSystem.bleepPlayer.Stop(); } if (currentDiagText.VisibleRatio < 1f && !skipskip) { currentDiagText.VisibleRatio = 1f; return; } inputCD = 5f; diag.RemoveAt(0); TextSystem.bleepPlayer.PitchScale = 1f; TextSystem.bleepPlayer.VolumeDb = Mathf.LinearToDb(1f); List list2 = portraits; if (list2 != null && list2.Count > 0) { DWMenu.instance.battlePortrait.Visible = false; currentDiagText.VisibleRatio = 0f; currentDiagText.Visible = false; portraits.RemoveAt(0); } else { currentDiagText.VisibleRatio = 0f; } } public static void Abort(bool nullify = true) { if (GodotObject.IsInstanceValid(current.activeBoard)) { current.activeBoard.QueueFree(); } DWMenu.instance.bulletBoard.Visible = false; current.QueueFree(); if (nullify) { current = null; } } public override void _Process(double delta) { if (grazeCD > 0f) { grazeCD -= Main.deltaTime; } if (CameraController.instance.shakeTime > 0f) { base.Position = Vector2.One * Main.RandomRange(0f - CameraController.instance.shakeIntensity, CameraController.instance.shakeIntensity); } else { base.Position = Vector2.Zero; } UpdateTP(ref DWMenu.instance.tpVar, in TP, in tpPreview, 1); if (inputCD > 0f) { inputCD -= Main.deltaTime; } UpdateDiag(); DWMenu.instance.grazeIndicator.SelfModulate = DWMenu.instance.grazeIndicator.SelfModulate.Lerp(Main.colorClear, 0.1f); if (doBG) { DWMenu.instance.battleBG.Modulate = DWMenu.instance.battleBG.Modulate.Lerp(bgColor, 0.1f); } Coroutine coroutine = busy; if (coroutine == null || coroutine.done) { Coroutine coroutine2 = events; if (coroutine2 == null || coroutine2.done) { switch (state) { case State.Next: { if (eventBattle == EventBattle.WardenTutorial && TP >= 40 && !tempFlags.Contains("TPMes")) { tempFlags.Add("TPMes"); busy = Coroutine.Start(Acts.instance.WardenTutorial(1)); break; } spareAble = false; for (int j = 0; j < enemies.Count; j++) { if (enemies[j].CanSpare()) { spareAble = true; break; } } for (int k = 0; k < party.Count; k++) { if (party[k].CanAct() && party[k].selectedAction == null) { currentActor = k; state = State.PlayerTurn; option = 0; maxOption = 5; DWMenu.instance.partyHUDs[k].UpdateOpt(0); UpdateMenu(); break; } soul.Visible = false; ResetEnemyHighlight(); state = State.DoSpells; } break; } case State.PlayerTurn: if (DWMenu.instance.battleText.VisibleRatio < 1f) { DWMenu.instance.battleText.VisibleCharacters++; } Party.ShowBattleCommands(currentActor); if (Input.IsActionJustPressed(Main.keys[2])) { ChangeOption(-1); if (option < 0) { option = maxOption - 1; } DWMenu.instance.partyHUDs[currentActor].UpdateOpt(option); } else if (Input.IsActionJustPressed(Main.keys[3])) { ChangeOption(1); DWMenu.instance.partyHUDs[currentActor].UpdateOpt(option); } else if (Input.IsActionJustPressed(Main.keys[4])) { selectedLast = option; int[] array = blockedCommands; if (array != null && array.Contains(option)) { Audio.PlaySound(Audio.commonSounds[1]); break; } switch (option) { case 0: allBattlers[currentActor].selectedAction = new int[2]; state = State.SelectTarget; option = 0; maxOption = enemies.Count; playerSelect = false; UpdateMenu(); Audio.PlaySound(Audio.commonSounds[2]); break; case 1: if (allBattlers[currentActor].doMagicMenu) { allBattlers[currentActor].selectedAction = new int[3] { 1, 0, 0 }; state = State.SelectSkill; } else { allBattlers[currentActor].selectedAction = new int[3] { 2, 0, 0 }; state = State.SelectTarget; } option = 0; UpdateMenu(); Audio.PlaySound(Audio.commonSounds[2]); break; case 2: if (SaveFile.current.dwItems.Count > 0) { Audio.PlaySound(Audio.commonSounds[2]); allBattlers[currentActor].selectedAction = new int[3] { 3, 0, 0 }; state = State.SelectItem; option = 0; UpdateMenu(); } else { Audio.PlaySound(Audio.commonSounds[1]); } break; case 3: allBattlers[currentActor].selectedAction = new int[3] { 2, 0, 12 }; state = State.SelectTarget; option = 0; playerSelect = false; UpdateMenu(); Audio.PlaySound(Audio.commonSounds[2]); break; case 4: allBattlers[currentActor].entity.currentAnim = Entity.Animations.Defend; allBattlers[currentActor].selectedAction = new int[1] { 4 }; option = 0; lastActor.Add(currentActor); consumeItems.Add(Items.IDs.None); currentActor = -1; lastTP.Add(TP); TP = Mathf.Clamp(TP + 16, 0, 100); state = State.Next; UpdateMenu(); Audio.PlaySound(Audio.commonSounds[2]); break; } } else if (Input.IsActionJustPressed(Main.keys[5])) { ReturnToPrevious(); } break; case State.SelectSkill: case State.SelectItem: case State.SelectAct: Party.ShowBattleCommands(currentActor); if (Input.IsActionJustPressed(Main.keys[0])) { ChangeOption(-2); UpdateMenu(1); } else if (Input.IsActionJustPressed(Main.keys[1])) { ChangeOption(2); UpdateMenu(1); } else if (Input.IsActionJustPressed(Main.keys[2])) { ChangeOption(-1); UpdateMenu(1); } else if (Input.IsActionJustPressed(Main.keys[3])) { ChangeOption(1); UpdateMenu(1); } else if (Input.IsActionJustPressed(Main.keys[4])) { if (state == State.SelectItem) { allBattlers[currentActor].selectedAction[2] = (int)SaveFile.current.dwItems[option]; playerSelect = UseOnParty(currentActor); Items.IDs ds2 = SaveFile.current.dwItems[option]; if (Texts.items[ds2].instantUse) { allBattlers[currentActor].selectedAction[1] = currentActor; allBattlers[currentActor].entity.currentAnim = Entity.Animations.ItemReady; lastActor.Add(currentActor); SaveFile.current.dwItems.Remove(ds2); consumeItems.Add(ds2); currentActor = -1; lastTP.Add(TP); state = State.Next; UpdateMenu(); } else { option = 0; state = State.SelectTarget; UpdateMenu((!Texts.items[ds2].useOnEnemy) ? 2 : 0); } Audio.PlaySound(Audio.commonSounds[2]); break; } Acts.IDs ds3 = (Acts.IDs)possible[option]; if (TP >= Texts.skills[ds3].TP) { if (state == State.SelectAct || Texts.skills[ds3].skipSelection) { if (ds3 == Acts.IDs.Check) { busy = Acts.DoActRoutine("Check", enemies[allBattlers[currentActor].selectedAction[1]]); Coroutine coroutine3 = busy; coroutine3.onEnd = (Action)Delegate.Combine(coroutine3.onEnd, new Action(CancelEnemySelect)); break; } lastActor.Add(currentActor); consumeItems.Add(Items.IDs.None); allBattlers[currentActor].selectedAction[2] = possible[option]; if (allBattlers[currentActor].selectedAction[2] == 3) { allBattlers[currentActor].entity.anim.Play("Execution_Ready"); } else { allBattlers[currentActor].entity.currentAnim = ((state == State.SelectItem) ? Entity.Animations.ItemReady : ((state == State.SelectAct) ? Entity.Animations.ActReady : Entity.Animations.SkillReady)); } if (state == State.SelectAct) { List useTurns = Texts.skills[(Acts.IDs)allBattlers[currentActor].selectedAction[2]].useTurns; if (useTurns != null && useTurns.Count > 0) { actExtra.Add(currentActor, Texts.skills[(Acts.IDs)allBattlers[currentActor].selectedAction[2]].useTurns.ToArray()); for (int l = 0; l < Texts.skills[(Acts.IDs)allBattlers[currentActor].selectedAction[2]].useTurns.Count; l++) { Party.party[(int)Texts.skills[(Acts.IDs)allBattlers[currentActor].selectedAction[2]].useTurns[l]].acted = true; Party.party[(int)Texts.skills[(Acts.IDs)allBattlers[currentActor].selectedAction[2]].useTurns[l]].entity.currentAnim = Entity.Animations.ActReady; } } } currentActor = -1; lastTP.Add(TP); TP = Mathf.Clamp(TP - Texts.skills[ds3].TP, 0, 100); state = State.Next; UpdateMenu(); } else { allBattlers[currentActor].selectedAction[2] = possible[option]; option = 0; playerSelect = UseOnParty(currentActor); state = State.SelectTarget; UpdateMenu(Texts.skills[ds3].useOnParty ? 2 : 0); } Audio.PlaySound(Audio.commonSounds[2]); } else { Audio.PlaySound(Audio.commonSounds[1]); } } else if (Input.IsActionJustPressed(Main.keys[5])) { CancelEnemySelect(); Audio.PlaySound(Audio.commonSounds[2]); } break; case State.SelectTarget: Party.ShowBattleCommands(currentActor); if (!playerSelect) { for (int i = 0; i < enemies.Count; i++) { if (i == option) { enemies[i].entity.Modulate = Main.colorWhite.Lerp(Main.colorDark, Mathf.Abs(Mathf.Sin(Mathf.DegToRad(0.15f * (float)Time.GetTicksMsec())))); } else { enemies[i].entity.Modulate = Main.colorWhite; } } } if (Input.IsActionJustPressed(Main.keys[0]) || Input.IsActionJustPressed(Main.keys[2])) { ChangeOption(-1); UpdateMenu(1); } else if (Input.IsActionJustPressed(Main.keys[1]) || Input.IsActionJustPressed(Main.keys[3])) { ChangeOption(1); UpdateMenu(1); } else if (Input.IsActionJustPressed(Main.keys[4])) { if (allBattlers[currentActor].selectedAction[0] == 2 && allBattlers[currentActor].selectedAction[2] != 12) { allBattlers[currentActor].selectedAction[1] = option; state = State.SelectAct; option = 0; UpdateMenu(); } else { lastTP.Add(TP); if (allBattlers[currentActor].selectedAction[0] == 0) { allBattlers[currentActor].selectedAction[1] = option; allBattlers[currentActor].entity.currentAnim = Entity.Animations.AttackReady; allBattlers[currentActor].entity.UpdateAnim(force: true); allBattlers[currentActor].entity.anim.Stop(); } else { Acts.IDs ds = (Acts.IDs)allBattlers[currentActor].selectedAction[2]; allBattlers[currentActor].selectedAction[1] = option; if (allBattlers[currentActor].selectedAction[0] != 3) { TP = Mathf.Clamp(TP - Texts.skills[ds].TP, 0, 100); } if (allBattlers[currentActor].selectedAction[2] == 3) { allBattlers[currentActor].entity.anim.Play("Execution_Ready"); } else if (allBattlers[currentActor].selectedAction[0] == 3) { allBattlers[currentActor].entity.currentAnim = Entity.Animations.ItemReady; } else if (Texts.skills[ds].spAction || ds == Acts.IDs.Spare) { allBattlers[currentActor].entity.currentAnim = Entity.Animations.ActReady; } else { allBattlers[currentActor].entity.currentAnim = Entity.Animations.SkillReady; } } if (allBattlers[currentActor].selectedAction[0] == 3) { Items.IDs item = (Items.IDs)allBattlers[currentActor].selectedAction[2]; consumeItems.Add(item); SaveFile.current.dwItems.Remove(item); } else { consumeItems.Add(Items.IDs.None); } lastActor.Add(currentActor); currentActor = -1; state = State.Next; UpdateMenu(); } Audio.PlaySound(Audio.commonSounds[2]); } else if (Input.IsActionJustPressed(Main.keys[5])) { CancelEnemySelect(); Audio.PlaySound(Audio.commonSounds[2]); } break; case State.DoSpells: busy = Coroutine.Start(DoSpells()); break; case State.DoAttack: busy = Coroutine.Start(DoAttack()); break; case State.DoEnemy: busy = Coroutine.Start(DoEnemy()); break; case State.EndTurn: busy = Coroutine.Start(AdvanceTurn()); break; } return; } } Party.ShowBattleCommands(-1); } public static bool DoingAction() { if (current != null) { if (current.state != State.DoSpells && current.state != State.DoAttack && current.state != State.DoEnemy) { return current.state == State.EndTurn; } return true; } return false; } private void CancelEnemySelect() { state = State.PlayerTurn; option = selectedLast; maxOption = 5; allBattlers[currentActor].selectedAction = null; ResetEnemyHighlight(); UpdateMenu(); } private string GetTextBar(float amt, Color? color = null) { Color valueOrDefault = color.GetValueOrDefault(); if (!color.HasValue) { valueOrDefault = new Color(0f, 1f, 0f); color = valueOrDefault; } string text = color.Value.ToHtml(includeAlpha: false); string text2 = "#870900"; amt *= 15f; StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; (float)i < 15f; i++) { stringBuilder.Append("[img color=" + (((float)i < amt) ? text : text2) + "]res://Sprites/Menus/Menu Sprites/HPBar3.tres[/img]"); } return stringBuilder.ToString(); } private int[] GetPossibleActs(int id = -1) { if (id == -1) { id = currentActor; } List list = new List(); for (int i = 0; i < party[id].acts.Count; i++) { if (CanUseAct(party[id].acts[i])) { list.Add((int)party[id].acts[i]); } } return list.ToArray(); } private bool CanUseAct(Acts.IDs id) { List needEquip = Texts.skills[id].needEquip; if (needEquip != null && needEquip.Count > 0 && !party[currentActor].HasEquip(Texts.skills[id].needEquip.ToArray())) { return false; } if ((Texts.skills[id].needFlags == null || SaveFile.HasFlags(Texts.skills[id].needFlags)) && (Texts.skills[id].neededMembers == null || Party.HasMembers(Texts.skills[id].neededMembers, checkAlive: true)) && (!Texts.skills[id].onlyOnExecutable || enemies.FirstOrDefault((Battlers x) => x.isOutlaw) != null)) { if (Texts.skills[id].spAction) { return enemies.FirstOrDefault((Battlers x) => x.partyAction.Count > 1 || x.acts.Count > 0) != null; } return true; } return false; } public EndState GetLastResult() { return (EndState)resultAmts.OrderByDescending((int[] x) => x[1]).ToArray()[0][0]; } public IEnumerator EndBattle(EndState endState = EndState.None) { shield?.Free(); shield = null; soul.RotationDegrees = 0f; reloadStats = null; state = State.Override; Vector2[] p = new Vector2[party.Count]; for (int i = 0; i < party.Count; i++) { p[i] = party[i].entity.GlobalPosition; if (party[i].HP < 0) { party[i].HP = 1; } party[i].entity.currentAnim = Entity.Animations.BattleEnd; party[i].entity.direction = Entity.Direction.West; } if (lastResult != EndState.Special) { lastResult = GetLastResult(); } if (lastResult != EndState.Special) { prizeM = Mathf.FloorToInt((float)prizeM * Mathf.Lerp(1f, 1.5f, (float)TP / 100f)); Enemy enemy = caller; if (enemy != null && enemy.respawnType == Enemy.Respawn.NoMoney && SaveFile.HasFlag(caller.flag)) { prizeM = 0; } if (lastResult == EndState.Executed) { Audio.PlaySound("snd_dtrans_lw.ogg", 1f, 1.1f); DoDiag(new string[1] { Texts.common[129].Replace("@", "\n") }); SaveFile.current.values[7]++; for (int j = 0; j < SaveFile.current.activeParty.Count; j++) { Party.party[SaveFile.current.activeParty[j]].AddBonus(); } Party.UpdateStats(); Party.UpdateHUD(); } else { DoDiag(new string[1] { Texts.common[128].Replace("@", "\n").Replace("[EXP]", prizeE.ToString()).Replace("[MONEY]", prizeM.ToString()) }); } SaveFile.AddMoney(prizeM); while (diag.Count > 0) { yield return null; } Audio.ChangeMusic(owMusic); started = false; doBG = false; Coroutine c = Coroutine.Start(FinalizeBattle(p)); while (!c.done) { yield return null; } } else { if (endState != EndState.None) { lastResult = endState; } started = false; doBG = false; DWMenu.instance.showHP = 0f; Audio.ChangeMusic((Audio.AudioBlock)null, 5f); } } public IEnumerator FinalizeBattle(Vector2[] p = null) { for (int i = 0; i < toDelete.Count; i++) { if (GodotObject.IsInstanceValid(toDelete[i])) { toDelete[i].QueueFree(); } } if (p == null) { p = new Vector2[party.Count]; for (int j = 0; j < party.Count; j++) { p[j] = party[j].entity.GlobalPosition; } } for (float a = 0f; a < 20f; a += Main.deltaTime) { for (int k = 0; k < party.Count; k++) { party[k].entity.doTrail = true; party[k].entity.GlobalPosition = p[k].Lerp(party[k].oEntity.GlobalPosition, a / 20f); } DWMenu.instance.battleBG.Modulate = DWMenu.instance.battleBG.Modulate.Lerp(Main.colorClear, a / 20f); yield return null; } Room.UpdateEntityList(); foreach (Entity entity in Room.current.entities) { Main.SetActive(entity, state: true); } for (int l = 0; l < party.Count; l++) { Main.SetActive(party[l].oEntity, state: true); DWMenu.instance.partyHUDs[l].battleStuff.Visible = false; } Room.current.ProcessMode = ProcessModeEnum.Inherit; DWMenu.instance.showHP = 0f; Player.instance.canInput = Main.inEvent == null || Main.inEvent.done; DWMenu.instance.battleCover.Visible = false; if (caller != null) { SaveFile.AddFlag(caller.flag); if (GodotObject.IsInstanceValid(caller)) { caller.QueueFree(); } } Party.StopMoving(); current = null; QueueFree(); GC.Collect(); } public static IEnumerator KillAnim(Entity entity, float startDelay = 0f) { float a; if (startDelay > 0f) { for (a = 0f; a < startDelay; a += Main.deltaTime) { yield return null; } } entity.Shake(99999f, 1f); Audio.PlaySound("snd_vaporized.wav", 1f, 0.8f); entity.Modulate = Main.colorRed; entity.sprite.Material = (Material)GD.Load("res://Materials/Dissolve.tres").Duplicate(); StringName d = "shader_parameter/progress"; a = 0f; for (float b = 120f; a < b; a += Main.deltaTime) { entity.sprite.Material.Set(d, Mathf.Lerp(0f, 1f, a / b)); yield return null; } entity.Visible = false; } public static IEnumerator KillAnim(Battlers target, float startDelay = 0f) { target.fleeing = true; Coroutine anim = Coroutine.Start(KillAnim(target.entity, startDelay)); while (!anim.done) { yield return null; } RemoveEnemy(target, EndState.Executed); target.Delete(); yield return null; } public static IEnumerator Flee(Battlers target, float startDelay = 30f) { target.fleeing = true; target.entity.AddChild(new Sprite2D { Texture = GD.Load("res://Sprites/Menus/Menu Sprites/Sweat.tres"), Position = target.center + new Vector2(-16f, -16f) }, forceReadableName: false, InternalMode.Disabled); if (!target.dontFlee) { Audio.PlaySound("snd_defeatrun.wav"); if (startDelay > 0f) { for (float a = 0f; a < startDelay; a += Main.deltaTime) { yield return null; } } Vector2 p = target.entity.Position; target.entity.doTrail = true; for (float a = 0f; a < 7f; a += Main.deltaTime) { target.entity.Position = new Vector2(Mathf.Lerp(p.X, 200f, a / 7f), p.Y); yield return null; } } RemoveEnemy(target, EndState.Defeated); if (!target.dontFlee) { target.Delete(); } yield return null; } public static void RemoveEnemy(Battlers target, EndState defeatType) { for (int i = 0; i < current.party.Count; i++) { int[] selectedAction = current.party[i].selectedAction; if (selectedAction != null && selectedAction.Length > 1) { int[] selectedAction2 = current.party[i].selectedAction; if (((selectedAction2 != null) ? new int?(selectedAction2[1]) : ((int?)null)) > target.posID) { current.party[i].selectedAction[1]--; } } } current.toDelete.Add(target.entity); current.enemies.Remove(target); current.allBattlers.Remove(target); for (int j = 0; j < current.enemies.Count; j++) { current.enemies[j].posID = j; } if (current.caller != null && current.caller.respawnType != Enemy.Respawn.No && (current.caller.respawnType != Enemy.Respawn.NoMoney || SaveFile.HasFlag(current.caller.flag))) { return; } current.resultAmts[(int)defeatType][1]++; switch (defeatType) { case EndState.Executed: SaveFile.current.values[3]++; break; case EndState.Spared: SaveFile.current.values[1]++; current.prizeM += target.MONEY + SaveFile.current.values[1]; break; case EndState.Defeated: SaveFile.current.values[2]++; current.prizeM += target.MONEY * 2; break; case EndState.Apprehended: if (!target.isOutlaw && !SaveFile.current.apprehended.Contains(target.entity.id)) { SaveFile.current.apprehended.Add(target.entity.id); } SaveFile.current.values[4]++; break; } } public static IEnumerator ActEffect(Battlers b, float startDelay = 15f, bool flipDir = false) { if (startDelay > 0f) { for (float a = 0f; a < startDelay; a += Main.deltaTime) { yield return null; } } Sprite2D[] sp = new Sprite2D[3]; for (int i = 0; i < sp.Length; i++) { if (b.enemy) { Entity entity = b.entity; int num = i; Sprite2D obj = new Sprite2D { Texture = b.entity.sprite.Texture, Hframes = b.entity.sprite.Hframes, Vframes = b.entity.sprite.Vframes, RegionEnabled = b.entity.sprite.RegionEnabled, RegionRect = b.entity.sprite.RegionRect, Frame = Mathf.Clamp(b.actFrame, 0, b.entity.sprite.Hframes * b.entity.sprite.Vframes), ZIndex = -1 * (i + 1), Offset = b.entity.sprite.Offset }; Sprite2D node = obj; sp[num] = obj; entity.AddChild(node, forceReadableName: false, InternalMode.Disabled); } else { Entity entity2 = b.entity; int num2 = i; Sprite2D obj2 = new Sprite2D { Texture = GD.Load("res://Sprites/Particles/Act/" + b.id.ToString() + ".tres"), ZIndex = -1 * (i + 1), Offset = b.entity.sprite.Offset }; Sprite2D node = obj2; sp[num2] = obj2; entity2.AddChild(node, forceReadableName: false, InternalMode.Disabled); } } for (float a = 0f; a < 120f; a += Main.deltaTime) { for (int j = 0; j < sp.Length; j++) { if (GodotObject.IsInstanceValid(sp[j])) { sp[j].GlobalPosition += Vector2.Right * 0.35f * j * Main.deltaTime * (1f - a / 120f) * ((!flipDir) ? 1 : (-1)); sp[j].Modulate = Main.colorTransparent.Lerp(Main.colorClear, a / 120f); } } yield return null; } for (int k = 0; k < sp.Length; k++) { if (GodotObject.IsInstanceValid(sp[k])) { sp[k].Free(); } } } public void UpdateSoul(BulletBoards.SoulType mode = BulletBoards.SoulType.Current) { if (mode == BulletBoards.SoulType.Current) { mode = defaultSoul; } switch (mode) { case BulletBoards.SoulType.Blue: soul.RotationDegrees = 0f; DWMenu.instance.soul.SelfModulate = Main.colorBlue; break; case BulletBoards.SoulType.Yellow: soul.RotationDegrees = 0f; DWMenu.instance.soul.SelfModulate = Main.colorYellow; break; case BulletBoards.SoulType.Shoot: soul.RotationDegrees = -90f; DWMenu.instance.soul.SelfModulate = Main.colorYellow; break; } currentMode = mode; } public static void UpdateTP(ref int internalValue, in int amt, in int preview, int mod = 0) { if (internalValue != amt) { if (internalValue > amt) { internalValue--; } else { internalValue++; } } float num = (float)internalValue / 100f; DWMenu.instance.tpBar[1].Scale = new Vector2(1f, num); DWMenu.instance.tpBar[2].Visible = (float)internalValue > 2f; DWMenu.instance.tpBar[2].Position = new Vector2(0f, Mathf.Lerp(98f, -98f, num)); DWMenu.instance.tpBar[2].Scale = new Vector2(1f, Mathf.Clamp((float)Mathf.Clamp(preview, 0, amt) / 100f, 0.01f, 1f)); if (amt >= 100) { DWMenu.instance.tpBar[1].Modulate = DWMenu.instance.TPColors[2]; } else { DWMenu.instance.tpBar[1].Modulate = DWMenu.instance.TPColors[1]; } if (preview > 0) { DWMenu.instance.tpBar[2].Modulate = DWMenu.instance.TPColors[0].Lerp(Main.colorWhite, Mathf.Abs(Common.SinOverTime(0.35f))); } else { DWMenu.instance.tpBar[2].Modulate = DWMenu.instance.TPColors[0]; } if (mod == 1) { if (amt >= 100) { DWMenu.instance.tpText.Text = "[color=yellow] M\n A\n X"; } else { DWMenu.instance.tpText.Text = " " + internalValue + "\n %"; } } } private bool UseOnParty(int i) { if (party[i].selectedAction[0] != 3) { return Texts.skills[(Acts.IDs)party[i].selectedAction[2]].useOnParty; } return true; } private IEnumerator DoSpells() { for (int i = 0; i < party.Count; i++) { if (forceEnd) { yield break; } if (enemies.Count <= 0 || !party[i].CanAct()) { continue; } int[] selectedAction = party[i].selectedAction; if (selectedAction == null || selectedAction.Length == 0 || (party[i].selectedAction[0] != 2 && party[i].selectedAction[0] != 1 && party[i].selectedAction[0] != 3)) { continue; } currentlyActing = party[i]; Acts.IDs key = (Acts.IDs)party[i].selectedAction[2]; if (party[i].selectedAction[0] == 3) { key = Acts.IDs.UseItem; } Battlers battlers; if (party[i].selectedAction[0] == 3 || Texts.skills[key].useOnParty) { if (party[i].selectedAction[0] == 3) { if (!Texts.items[(Items.IDs)party[i].selectedAction[2]].useOnEnemy) { battlers = party[party[i].selectedAction[1]]; } else { party[i].selectedAction[1] = (int)Main.Repeat(party[i].selectedAction[1], enemies.Count); battlers = enemies[party[i].selectedAction[1]]; } } else { battlers = party[party[i].selectedAction[1]]; } } else { party[i].selectedAction[1] = (int)Main.Repeat(party[i].selectedAction[1], enemies.Count); battlers = enemies[party[i].selectedAction[1]]; } if (party[i].selectedAction[0] == 1 && Texts.skills[key].spAction) { party[i].selectedAction[0] = 2; party[i].selectedAction[2] = (int)enemyData[battlers.id].acts[enemyData[battlers.id].partyAction[Main.RandomRange(0, enemyData[battlers.id].partyAction.Count - 1)]]; key = (Acts.IDs)party[i].selectedAction[2]; } List list = new List { party[i] }; if (party[i].selectedAction[0] == 2) { party[i].entity.currentAnim = Entity.Animations.ActDo; battlers.lastestAct.Add(party[i].selectedAction[2]); Coroutine.Start(ActEffect(party[i])); if (actExtra.ContainsKey(i)) { for (int j = 0; j < actExtra[i].Length; j++) { Party.party[(int)actExtra[i][j]].entity.currentAnim = Entity.Animations.ActDo; Coroutine.Start(ActEffect(Party.party[(int)actExtra[i][j]])); list.Add(Party.party[(int)actExtra[i][j]]); } } } else if (party[i].selectedAction[0] == 3) { party[i].entity.currentAnim = Entity.Animations.ItemDo; } else { party[i].entity.currentAnim = Entity.Animations.SkillDo; } DWMenu.instance.battleText.Text = ""; Coroutine acting = Acts.DoActRoutine(key.ToString(), battlers, list.ToArray()); while (!acting.done) { yield return null; } party[i].entity.currentAnim = Entity.Animations.BattleIdle; if (actExtra.ContainsKey(i)) { for (int k = 0; k < actExtra[i].Length; k++) { Party.party[(int)actExtra[i][k]].entity.currentAnim = Entity.Animations.BattleIdle; } } } if (enemies.Count == 0 || forceEnd) { busy = Coroutine.Start(EndBattle()); } else { state = State.DoAttack; } } private IEnumerator DoAttack() { if (forceEnd) { yield break; } DWMenu.instance.battleText.Text = ""; List list = new List(); List order = new List(); for (int i = 0; i < party.Count; i++) { int[] selectedAction = party[i].selectedAction; if (selectedAction != null && selectedAction[0] == 0) { list.Add(i); order.Add(i); } } if (list.Count > 0) { AttackActionCommand.actionCD = 0f; AttackActionCommand[] bars = new AttackActionCommand[list.Count]; order = order.OrderBy((int x) => Guid.NewGuid()).ToList(); for (int num = 0; num < list.Count; num++) { bars[num] = GD.Load("res://Objects/UI/ActionCommand.tscn").Instantiate(PackedScene.GenEditState.Disabled); bars[num].ProcessPriority = order.Count - num; bars[num].linked = party[order[num]]; AddChild(bars[num], forceReadableName: false, InternalMode.Disabled); if (SaveFile.current.activeParty.Count > 3) { bars[num].Scale = new Vector2(1f, 0.5f); bars[num].Position = new Vector2(-94f, 76 + 9 * list[num]); } else { bars[num].Position = new Vector2(-94f, 76 + 17 * list[num]); } } List list2 = new List(); for (int num2 = 0; num2 < bars.Length; num2++) { for (int num3 = 0; num3 < bars.Length; num3++) { if (num2 != num3 && !list2.Contains(num3) && Mathf.Abs(bars[num3].bar.Position.X - bars[num2].bar.Position.X) < 15f) { list2.Add(num3); bars[num3].bar.Position = new Vector2(bars[num2].bar.Position.X, bars[num3].bar.Position.Y); } } } yield return null; Common.FillArray(ref order, order.Count, 0); order = order.OrderBy((int x) => bars[x].bar.Position.X).ToList(); bool flag; do { if (AttackActionCommand.actionCD > 0f) { AttackActionCommand.actionCD -= Main.deltaTime; } if (Input.IsActionJustPressed(Main.keys[4])) { for (int num4 = 0; num4 < bars.Length; num4++) { if (bars[order[num4]].active) { continue; } bars[order[num4]].Activate(); for (int num5 = 0; num5 < bars.Length; num5++) { if (order[num5] != order[num4] && !bars[order[num5]].active && Mathf.Abs(bars[order[num5]].bar.Position.X - bars[order[num4]].bar.Position.X) < 15f) { bars[order[num5]].Activate(); } } break; } } yield return null; flag = false; for (int num6 = 0; num6 < bars.Length; num6++) { if (GodotObject.IsInstanceValid(bars[num6])) { flag = true; } } } while (flag); } bool flag2; do { yield return null; flag2 = false; for (int num7 = 0; num7 < fleeing.Count; num7++) { Coroutine coroutine = fleeing[num7]; if (coroutine != null && !coroutine.done) { flag2 = true; } } } while (flag2); fleeing.Clear(); yield return null; if (enemies.Count == 0) { busy = Coroutine.Start(EndBattle()); yield break; } yield return null; state = State.DoEnemy; } private void Graze(Node other) { IBullet parentOrNull = other.GetParentOrNull(); if (parentOrNull != null && !parentOrNull.grazed && iFrames <= 0f && grazeCD <= 0f) { parentOrNull.grazed = true; Audio.PlaySound("snd_graze.wav"); TP = Mathf.Clamp(TP + (grazed ? 2 : 3), 0, 100); grazed = true; grazeCD = 5f; activeBoard.timer -= 2f; DWMenu.instance.grazeIndicator.SelfModulate = Main.colorWhite; } } public Control DoBlurb(Battlers enemy, int id, ref RichTextLabel label) { if (enemy.blurbOverride > -1) { id = enemy.blurbOverride; } Control control; AddChild(control = GD.Load("res://Objects/UI/Bubble.tscn").Instantiate(PackedScene.GenEditState.Disabled), forceReadableName: false, InternalMode.Disabled); BattleBlurbs[] blurbs = enemy.blurbs; BattleBlurbs battleBlurbs = ((blurbs != null && blurbs.Length > 1 && enemy.blurbs[id] != null) ? enemy.blurbs[id] : null); if (battleBlurbs == null) { battleBlurbs = new BattleBlurbs(); } Vector2 vector = battleBlurbs.size; if (vector.LengthSquared() < enemy.defaultBubbleSize.LengthSquared()) { vector = enemy.defaultBubbleSize; } control.GlobalPosition = enemy.entity.GlobalPosition + enemy.center + new Vector2(-20f + Mathf.Min(battleBlurbs.offset.X, vector.X / -2f), battleBlurbs.offset.Y); label = control.GetChild(0).GetChild(0); label.Text = blurbText[enemy.id][id].Replace("@", "\n"); control.GetChild(0).Size = new Vector2(vector.X, Mathf.Max((float)label.GetLineCount() * 4.5f, vector.Y)); float volume = 1f; string diagSound = enemy.diagSound; if (diagSound != null && diagSound.Length > 0) { TextSystem.AssignBleep(enemy.diagSound, ref volume); } else { TextSystem.bleepPlayer.Stream = TextSystem.defaultBleep; } return control; } private string AnySpecial() { for (int i = 0; i < enemies.Count; i++) { if (enemies[i].hasSpecial > -1 && enemies[i].CanSpecial()) { return enemies[i].bulletBoards[enemies[i].hasSpecial].ResourceName; } } return null; } private IEnumerator DoEnemy() { string special = AnySpecial(); if (special != null && specialWarning) { activeBoard = GD.Load("res://Objects/BulletBoards/" + special + ".tscn").Instantiate(PackedScene.GenEditState.Disabled); lastBoard = activeBoard.id; lastAttack = activeBoard.Name; } else { special = null; List list = new List(); List list2 = new List(); for (int i = 0; i < enemies.Count; i++) { if (enemies[i].skipAttack) { continue; } for (int j = 0; j < enemies[i].bulletBoards.Length; j++) { if (!enemies[i].bulletBoards[j].CanDo(enemies[i])) { continue; } if (enemies[i].bulletBoards[j].weight == -1) { list2.Add(new object[2] { enemies[i].bulletBoards[j].ResourceName, enemies[i] }); continue; } if (enemies[i].bulletBoards[j].weight >= 50) { list.Clear(); list.Add(new object[2] { enemies[i].bulletBoards[j].ResourceName, enemies[i] }); break; } for (int k = 0; k < enemies[i].bulletBoards[j].weight; k++) { list.Add(new object[2] { enemies[i].bulletBoards[j].ResourceName, enemies[i] }); } } } int num = 2; string text; int index; while (true) { text = null; index = 0; if (list.Count == 0) { if (list2.Count > 0) { index = Main.RandomRange(0, list2.Count - 1); text = (string)list2[index][0]; } else { state = State.EndTurn; } break; } index = Main.RandomRange(0, list.Count - 1); text = (string)list[index][0]; if (!((StringName)text == lastAttack) || num <= 0) { break; } num--; } if (text != null) { activeBoard = GD.Load("res://Objects/BulletBoards/" + text + ".tscn").Instantiate(PackedScene.GenEditState.Disabled); if (list.Count > 0) { activeBoard.caller = (Battlers)list[index][1]; } lastBoard = activeBoard.id; lastAttack = activeBoard.Name; } } AnimatedSprite2D[] reticle = null; List target = new List(); if (GodotObject.IsInstanceValid(activeBoard)) { DWMenu.instance.bulletBoard.Size = activeBoard.boardSize; DWMenu.instance.bulletBoard.AnchorsPreset = 8; DWMenu.instance.bulletBoardPivot.Position = DWMenu.boardCenter + activeBoard.boardStartOffset; if (focusAtk > -1) { activeBoard.target = BulletBoards.Target.OnlyOne; } if (activeBoard.target == BulletBoards.Target.OnlyOne) { int num2 = ((SaveFile.current.activeParty.Count < 3) ? 1 : GD.RandRange(2, 3)); for (int l = 0; l < num2 && l < party.Count && l < Party.AlivePartyAmount(); l++) { target.Add(-1); if (focusAtk > -1) { target[0] = focusAtk; break; } do { target[l] = Main.RandomRange(0, party.Count - 1); } while (party[target[l]].HP <= 0); } reticle = new AnimatedSprite2D[target.Count]; for (int m = 0; m < reticle.Length; m++) { AddChild(reticle[m] = GD.Load("res://Objects/Particles/Reticle.tscn").Instantiate(PackedScene.GenEditState.Disabled), forceReadableName: false, InternalMode.Disabled); reticle[m].GlobalPosition = party[target[m]].entity.GlobalPosition + party[target[m]].center + Vector2.Up * 8f; } } else { reticle = new AnimatedSprite2D[party.Count]; for (int n = 0; n < reticle.Length; n++) { AddChild(reticle[n] = GD.Load("res://Objects/Particles/Reticle.tscn").Instantiate(PackedScene.GenEditState.Disabled), forceReadableName: false, InternalMode.Disabled); reticle[n].GlobalPosition = party[n].entity.GlobalPosition + party[n].center; } } } yield return null; Control[] blurbs = new Control[enemies.Count]; RichTextLabel[] text2 = new RichTextLabel[enemies.Count]; for (int num3 = 0; num3 < enemies.Count; num3++) { if (!enAnim.Contains(enemies[num3].entity.anim.CurrentAnimation) && !enemies[num3].lockAnim) { enemies[num3].entity.anim.Play("Idle"); } int[] blurbOrder = enemies[num3].blurbOrder; if (blurbOrder != null && blurbOrder.Length != 0 && turn < enemies[num3].blurbOrder.Length) { blurbs[num3] = DoBlurb(enemies[num3], enemies[num3].blurbCount, ref text2[num3]); if (enemies[num3].blurbOverride == -1) { enemies[num3].blurbCount++; } continue; } int[] randomBlurbs = enemies[num3].randomBlurbs; if (randomBlurbs != null && randomBlurbs.Length != 0) { blurbs[num3] = DoBlurb(enemies[num3], enemies[num3].randomBlurbs[Main.RandomRange(0, enemies[num3].randomBlurbs.Length - 1)], ref text2[num3]); continue; } List list3 = new List(); int num4 = -1; for (int num5 = 0; num5 < enemies[num3].blurbs.Length; num5++) { if (enemies[num3].blurbOverride > -1) { num4 = enemies[num3].blurbOverride; break; } if (enemies[num3].blurbs[num5].Can(enemies[num3])) { if (enemies[num3].blurbs[num5].weight >= 50) { list3 = null; num4 = num5; break; } for (int num6 = 0; num6 < enemies[num3].blurbs[num5].weight; num6++) { list3.Add(num5); } } } if (list3 != null) { if (num4 == -1 && list3.Count > 0) { num4 = list3[Main.RandomRange(0, list3.Count - 1)]; } else if (enemies[num3].blurbOverride == -1) { num4 = -1; } } if (num4 == -1) { GD.Print("No blurbs found for " + enemies[num3].name); num4 = 0; } blurbs[num3] = DoBlurb(enemies[num3], (enemies[num3].blurbs[num4].overrideIndex > -1) ? enemies[num3].blurbs[num4].overrideIndex : num4, ref text2[num3]); } TextSystem.bleepPlayer.Play(); while (true) { bool flag = true; for (int num7 = 0; num7 < text2.Length; num7++) { text2[num7].VisibleCharacters++; if (text2[num7].VisibleRatio < 1f) { flag = false; } } if (flag && TextSystem.bleepPlayer.Playing) { TextSystem.bleepPlayer.Stop(); } yield return null; if (!Input.IsActionJustPressed(Main.keys[4])) { continue; } bool flag2 = false; for (int num8 = 0; num8 < text2.Length; num8++) { RichTextLabel obj = text2[num8]; if (obj != null && obj.VisibleRatio < 1f) { text2[num8].VisibleCharacters = 999; flag2 = true; } } if (!flag2) { break; } } TextSystem.bleepPlayer.Stop(); for (int num9 = 0; num9 < blurbs.Length; num9++) { blurbs[num9]?.Free(); } Sprite2D soulShadow = null; if (GodotObject.IsInstanceValid(activeBoard)) { for (int num10 = 0; num10 < reticle.Length; num10++) { reticle[num10].Free(); } soul.Visible = true; soul.TopLevel = true; soul.ZIndex = 4096; soulShadow = new Sprite2D { Texture = DWMenu.instance.soul.Texture, RegionEnabled = true, RegionRect = DWMenu.instance.soul.RegionRect, Modulate = new Color(soul.Modulate.R, soul.Modulate.G, soul.Modulate.B, 0.5f), ZIndex = soul.ZIndex - 1, TopLevel = true, Position = Vector2.One * 999f }; Vector2 boxCenter = DWMenu.instance.bulletBoardPivot.GlobalPosition + activeBoard.soulStartOffset; Vector2 pcCenter = party[0].entity.GlobalPosition + party[0].center; soul.GetParent().AddChild(soulShadow, forceReadableName: false, InternalMode.Disabled); soul.GlobalPosition = Vector2.One * 9999f; Main.SetActive(DWMenu.instance.bulletBoardPivot, state: true); UpdateSoul(activeBoard.soulType); Main.Particle("SoulSplit", Vector2.Up * 16f, 1, party[0].entity); DWMenu.instance.bulletBoard.Visible = true; float a; for (a = 0f; a <= activeBoard.growTime; a += Main.deltaTime) { Room.current.Modulate = Main.colorWhite.Lerp(Main.colorDark, a / activeBoard.growTime); DWMenu.instance.bulletBoardPivot.Scale = Vector2.Zero.Lerp(Vector2.One, a / activeBoard.growTime); if ((int)a % 3 == 0 && a > 0f) { soulShadow.GlobalPosition = soul.GlobalPosition; } soul.GlobalPosition = pcCenter.Lerp(boxCenter, a / activeBoard.growTime); if (activeBoard.special) { DWMenu.instance.bulletBoardPivot.Rotation = Mathf.Lerp(180f, 0f, a / activeBoard.growTime); } else { DWMenu.instance.bulletBoardPivot.Rotation = Mathf.LerpAngle(Mathf.DegToRad(90f), 0f, a / activeBoard.growTime); } for (int num11 = 0; num11 < allBattlers.Count; num11++) { allBattlers[num11].entity.Modulate = Main.colorWhite.Lerp(Main.colorDark, a / activeBoard.growTime); } yield return null; } DWMenu.instance.bulletBoardPivot.Scale = Vector2.One; DWMenu.instance.bulletBoardPivot.Rotation = 0f; for (int num12 = 0; num12 < 3; num12++) { if (num12 == 0) { DWMenu.instance.bulletBoard.GetChild(0).Visible = false; } else { DWMenu.instance.bulletBoard.GetChild(0).GetChild(num12 - 1).Visible = false; } yield return null; } soulShadow.Visible = false; DWMenu.instance.soulHitbox.Enabled = true; DWMenu.instance.soulHitbox.ForceShapecastUpdate(); iFrames = 0f; soulColor = DWMenu.instance.soul.SelfModulate; DWMenu.instance.bulletBoardPivot.AddChild(activeBoard, forceReadableName: false, InternalMode.Disabled); soul.Reparent(DWMenu.instance.bulletBoardPivot); activeBoard.targeted = target.ToArray(); yield return null; do { if (BulletBoardInput()) { yield break; } activeBoard.timer -= Main.deltaTime; yield return null; } while (activeBoard.timer > 0f); DWMenu.instance.bulletBoard.SelfModulate = Main.colorGreen; soul.Reparent(DWMenu.instance); DWMenu.instance.soul.SelfModulate = soulColor; boxCenter = soul.GlobalPosition; DWMenu.instance.soulHitbox.Enabled = false; DWMenu.instance.soulBody.Velocity = Vector2.Zero; activeBoard?.QueueFree(); yield return null; for (int num13 = 0; num13 < enemies.Count; num13++) { if (special != null) { enemies[num13].internalFlags.Add("Special"); } enemies[num13].entity.Position = enemies[num13].startPos; enemies[num13].entity.UpdateAnim(force: true); enemies[num13].entity.doTrail = false; } soulShadow.Visible = true; soulShadow.GlobalPosition = soul.GlobalPosition; a = 0f; float i2 = 0f; while (a <= 20f) { Room.current.Modulate = Main.colorDark.Lerp(Main.colorWhite, a / 20f); if (i2 < 3f) { if (i2 == 0f) { DWMenu.instance.bulletBoard.GetChild(0).Visible = true; } else { DWMenu.instance.bulletBoard.GetChild(0).GetChild((int)i2 - 1).Visible = true; } yield return null; } for (int num14 = 0; num14 < allBattlers.Count; num14++) { allBattlers[num14].entity.Modulate = Main.colorWhite.Lerp(Main.colorDark, 1f - a / 20f); } DWMenu.instance.bulletBoardPivot.Rotation = Mathf.LerpAngle(0f, Mathf.DegToRad(90f), a / 20f); DWMenu.instance.bulletBoardPivot.Scale = Vector2.Zero.Lerp(Vector2.One, 1f - a / 20f); if ((int)a % 3 == 0 && a > 0f) { soulShadow.GlobalPosition = soul.GlobalPosition; } soul.GlobalPosition = pcCenter.Lerp(boxCenter, 1f - a / 20f); yield return null; a += Main.deltaTime; i2 += 1f; } Main.Particle("SoulSplit", Vector2.Up * 16f, 1, party[0].entity); } UpdateSoul(); Room.current.Modulate = Main.colorWhite; Main.SetActive(DWMenu.instance.bulletBoardPivot, state: false); soulShadow?.Free(); soul.TopLevel = false; soul.Visible = false; state = State.EndTurn; } private bool BulletBoardInput() { if (shootCD > 0f) { shootCD -= Main.deltaTime; } switch (currentMode) { case BulletBoards.SoulType.Shoot: if (shootCD <= 0f && shots.Count < 5 && ((!Settings.file.autoFire && Input.IsActionJustPressed(Main.keys[4])) || (Settings.file.autoFire && Input.IsActionPressed(Main.keys[4])))) { shootCD = 10f; SoulBullet soulBullet; activeBoard.AddChild(soulBullet = BattleDR.soulBullet.Instantiate(PackedScene.GenEditState.Disabled), forceReadableName: false, InternalMode.Disabled); soulBullet.dir = Vector2.Up.Rotated(0f - soul.Rotation); soulBullet.GlobalPosition = soul.GlobalPosition + soulBullet.dir * 3f; shots.Add(soulBullet); } soul.Velocity = (Main.GetDirection() * Main.deltaTime).Normalized() * 55f; soul.MotionMode = CharacterBody2D.MotionModeEnum.Floating; break; case BulletBoards.SoulType.Blue: soul.MotionMode = CharacterBody2D.MotionModeEnum.Grounded; break; default: soul.Velocity = (Main.GetDirection() * Main.deltaTime).Normalized() * 55f; soul.MotionMode = CharacterBody2D.MotionModeEnum.Floating; break; } soul.MoveAndSlide(); if (iFrames > 0f) { iFrames -= Main.deltaTime; DWMenu.instance.soul.SelfModulate = soulColor.Lerp(Main.colorBlack, Mathf.Abs(Mathf.Sin(Mathf.DegToRad(Time.GetTicksMsec())))); } else { DWMenu.instance.soul.SelfModulate = soulColor; if (DWMenu.instance.soulHitbox.GetCollisionCount() > 0 && PlayerHurt()) { return true; } } return false; } private bool PlayerHurt() { IBullet bullet = null; for (int i = 0; i < DWMenu.instance.soulHitbox.GetCollisionCount(); i++) { if (GodotObject.IsInstanceValid(DWMenu.instance.soulHitbox.GetCollider(i))) { Node parent = ((Node)DWMenu.instance.soulHitbox.GetCollider(i)).GetParent(); if (parent is IBullet bullet2) { bullet = bullet2; break; } if (parent is SoulBullet) { return false; } } } if (bullet != null) { switch (bullet.type) { case IBullet.Type.Blue: if (soul.Velocity == Vector2.Zero) { return false; } break; case IBullet.Type.Orange: if (soul.Velocity != Vector2.Zero) { return false; } break; } if (shield != null) { CameraController.instance.shakeTime = 7f; shield?.Free(); shield = null; iFrames = 40 + Party.GetIframes(); Audio.PlaySound("snd_ceroba_shield_impact.wav"); return false; } float num = 0f; if (activeBoard.caller == null) { for (int j = 0; j < enemies.Count; j++) { num += (float)enemies[j].ATK; if (enemies[j].atkMod != null) { num += (float)enemies[j].atkMod[1]; } num = Mathf.Clamp(num, (float)enemies[j].ATK / 2f, (float)enemies[j].ATK * 2f); } num /= (float)enemies.Count; } else { num += (float)activeBoard.caller.ATK; if (activeBoard.caller.atkMod != null) { num += (float)activeBoard.caller.atkMod[1]; } num = Mathf.Clamp(num, (float)activeBoard.caller.ATK / 2f, (float)activeBoard.caller.ATK * 2f); } num *= activeBoard.damageMult; List list = new List(); if (activeBoard.target == BulletBoards.Target.OnlyOne) { list.Add(activeBoard.targeted[GD.RandRange(0, activeBoard.targeted.Length - 1)]); } else if (activeBoard.target == BulletBoards.Target.All) { for (int k = 0; k < party.Count; k++) { list.Add(k); } } else if (activeBoard.target == BulletBoards.Target.RandomAll) { int num2; do { num2 = Main.RandomRange(0, party.Count - 1); } while (party[num2].HP <= 0); list.Add(num2); } CameraController.instance.shakeTime = 7f; for (int l = 0; l < list.Count; l++) { if (party[list[l]].HP <= 0) { continue; } int num3 = Mathf.RoundToInt(Mathf.Clamp(num * (1f + Main.RandomRange(-0.1f, 0.1f)) - (float)party[list[l]].DEF, 1f, 999f)); if (party[list[l]].defMod != null) { num3 = Mathf.Clamp(num3 - party[list[l]].defMod[1], 0, 999); } int[] selectedAction = party[list[l]].selectedAction; if (selectedAction != null && selectedAction[0] == 4) { num3 = (int)Mathf.Max((float)num3 / 2f, (float)num3 * 0.2f); } party[list[l]].HP -= num3; if (activeBoard.cantKill) { party[list[l]].HP = Mathf.Clamp(party[list[l]].HP, 1, party[list[l]].MAXHP); } if (party[list[l]].HP <= 0) { if (Party.AlivePartyAmount() == 0) { soul.Reparent(DWMenu.instance); activeBoard.QueueFree(); Coroutine.Start(GameOver.DoGameOver()); base.ProcessMode = ProcessModeEnum.Disabled; return true; } party[list[l]].HP = -party[list[l]].MAXHP; ShowFloatingText(Texts.common[127], party[list[l]].entity.GlobalPosition + new Vector2(-16f, 0f), Main.colorRed); party[list[l]].entity.currentAnim = Entity.Animations.KO; party[list[l]].selectedAction = null; if (activeBoard.target == BulletBoards.Target.OnlyOne) { activeBoard.target = BulletBoards.Target.RandomAll; } } else { ShowFloatingText(num3.ToString(), party[list[l]].entity.GlobalPosition + new Vector2(-16f, 0f), Main.colorWhite); party[list[l]].entity.currentAnim = Entity.Animations.Hurt; Entity entity = party[list[l]].entity; int[] selectedAction2 = party[list[l]].selectedAction; Coroutine.Start(entity.DelayedAnim(30f, (selectedAction2 != null && selectedAction2[0] == 4) ? Entity.Animations.Defend : Entity.Animations.BattleIdle)); } } Audio.PlaySound("snd_hurt1.wav"); Party.UpdateHUD(); iFrames = 40 + Party.GetIframes(); return false; } return false; } public static Node2D NewBullet(in PackedScene type, Vector2 pos, Node2D parent = null, bool local = false) { Node2D node2D; if (parent == null) { current.activeBoard.AddChild(node2D = type.Instantiate(PackedScene.GenEditState.Disabled), forceReadableName: false, InternalMode.Disabled); } else { parent.AddChild(node2D = type.Instantiate(PackedScene.GenEditState.Disabled), forceReadableName: false, InternalMode.Disabled); } if (local) { node2D.Position = pos; } else { node2D.GlobalPosition = pos; } node2D.ProcessMode = ProcessModeEnum.Inherit; return node2D; } public static Node2D NewBullet(in Node2D type, Vector2 pos, Node2D parent = null, bool local = false) { Node2D node2D; if (parent == null) { current.activeBoard.AddChild(node2D = (Node2D)type.Duplicate(), forceReadableName: false, InternalMode.Disabled); } else { parent.AddChild(node2D = (Node2D)type.Duplicate(), forceReadableName: false, InternalMode.Disabled); } if (local) { node2D.Position = pos; } else { node2D.GlobalPosition = pos; } node2D.ProcessMode = ProcessModeEnum.Inherit; return node2D; } private IEnumerator AdvanceTurn() { turn++; bool flag = false; for (int i = 0; i < party.Count; i++) { party[i].selectedAction = null; party[i].acted = false; if (party[i].HP > 0) { party[i].entity.currentAnim = Entity.Animations.BattleIdle; } else { party[i].entity.currentAnim = Entity.Animations.KO; } int num = 0; if (party[i].HP <= 0) { num += party[i].MAXHP / 3; } for (int j = 0; j < 3; j++) { if (party[i].EQUIP[j] > -1 && Texts.items[(Items.IDs)party[i].EQUIP[j]].healOverTime > 0) { num += Texts.items[(Items.IDs)party[i].EQUIP[j]].healOverTime; } } if (num > 0) { Coroutine.Start(Heal(party[i], num, playParticles: false, doColor: false, showText: true, !flag)); flag = true; } } for (int k = 0; k < enemies.Count; k++) { enemies[k].lastestAct.Clear(); enemies[k].blurbOverride = -1; } for (int l = 0; l < allBattlers.Count; l++) { int[] atkMod = allBattlers[l].atkMod; if (atkMod != null && atkMod[0] > 0) { allBattlers[l].atkMod[0]--; if (allBattlers[l].atkMod[0] == 0) { allBattlers[l].atkMod = null; } } int[] defMod = allBattlers[l].defMod; if (defMod != null && defMod[0] > 0) { allBattlers[l].defMod[0]--; if (allBattlers[l].defMod[0] == 0) { allBattlers[l].defMod = null; } } allBattlers[l].bulletSpeedMod = 0f; } Party.UpdateHUD(); firstMes = false; grazed = false; actExtra.Clear(); GetNextBattleText(); lastTP.Clear(); consumeItems.Clear(); lastActor.Clear(); option = 0; focusAtk = -1; maxOption = 5; currentlyActing = null; currentActor = -1; for (float a = 0f; a < 3f; a += Main.deltaTime) { yield return null; } state = State.Next; UpdateMenu(); } private float GetMercy(int id = -1) { if (id > 3) { return 0f; } if (id == -1) { int num = 0; for (int i = 0; i < enemies.Count; i++) { num += enemies[i].spare; } return num / enemies.Count; } return enemies[id].spare; } private void GetNextBattleText() { if (AnySpecial() != null) { for (int i = 0; i < Texts.battleMes[this.battleMes].Length; i++) { if (Texts.battleMes[this.battleMes][i].special) { lastMes = i; specialWarning = true; return; } } } if (turn == 0) { lastMes = 0; return; } if (forceMes > -1) { lastMes = forceMes; forceMes = -1; return; } List list = new List(); for (int j = 1; j < Texts.battleMes[this.battleMes].Length; j++) { Texts.BattleMes battleMes = Texts.battleMes[this.battleMes][j]; Entity.IDs? check = battleMes.idToCheck; Battlers battlers = (check.HasValue ? enemies.FirstOrDefault((Battlers x) => x.id == check.Value) : null); if (!battleMes.cant && !battleMes.special && (battleMes.reqTurn <= 0 || turn >= battleMes.reqTurn) && (!check.HasValue || battlers != null) && (battleMes.everyXTurns <= 0 || turn % battleMes.everyXTurns == 0) && (battleMes.hpCheck <= 0f || (battlers != null && battlers.HPPercent() <= battleMes.hpCheck)) && (battleMes.mercyCheck <= 0f || (battlers != null && (float)battlers.spare <= battleMes.mercyCheck)) && (battleMes.atMesCount <= 0 || battleMes.atMesCount == mesCount) && (battleMes.onlyTurn <= 0 || turn == battleMes.onlyTurn) && enemies.Count >= battleMes.reqEnemyAmt && (battleMes.mercyCheck == -1f || GetMercy() >= battleMes.mercyCheck) && (battleMes.battleFlagReq == null || battleMes.battleFlagReq.Count == 0 || battleMes.battleFlagReq.All((StringName x) => tempFlags.Contains(x))) && (battleMes.battleFlagLimit == null || battleMes.battleFlagLimit.Count == 0 || !battleMes.battleFlagLimit.All((StringName x) => tempFlags.Contains(x)))) { if (battleMes.weight >= 50) { list.Clear(); list.Add(j); break; } for (int num = 0; num < battleMes.weight; num++) { list.Add(j); } } } int num2 = 0; for (int num3 = 0; num3 < 10; num3++) { num2 = ((list.Count != 0) ? list[Main.RandomRange(0, list.Count - 1)] : 0); if (num2 != lastMes) { break; } } if (Texts.battleMes[this.battleMes][num2].addCount) { mesCount++; } else if (Texts.battleMes[this.battleMes][num2].resetCount) { mesCount = 0; } lastMes = num2; } public static void DoDiag(string[] text, string[] portraits = null) { current.diag = new List(text); if (portraits != null) { current.portraits = new List(portraits); } else { current.portraits?.Clear(); } DWMenu.instance.battleText.VisibleRatio = 0f; if (portraits != null) { DWMenu.instance.battleText2.VisibleRatio = 0f; } } public void ResetEnemyHighlight() { for (int i = 0; i < enemies.Count; i++) { enemies[i].entity.Modulate = Main.colorWhite; } } private void ChangeOption(int d) { option += d; if (option < 0) { option = maxOption - 1; } else if (option >= maxOption) { option = 0; } Audio.PlaySound(Audio.commonSounds[0]); } public static IEnumerator Heal(Battlers target, int amt, bool playParticles = true, bool doColor = true, bool showText = true, bool playSound = true) { if (playParticles) { ((Node2D)Main.Particle("HealParts", target.entity.GlobalPosition + target.center, null, current, localSpace: false)).ZIndex = 3000; } if (playSound) { Audio.PlaySound("snd_power.wav"); } bool flag = target.HP <= 0; target.HP = Mathf.Clamp(target.HP + amt, -target.MAXHP, target.MAXHP); if (!target.enemy) { Party.UpdateHUD(); } if (amt >= 50000) { amt -= 50000; for (int i = 0; i < current.party.Count; i++) { if (current.party[i] != target) { Coroutine.Start(Heal(current.party[i], amt, playParticles, doColor, showText, playSound: false)); } } } if (!target.enemy && target.HP > 0 && flag) { target.entity.currentAnim = Entity.Animations.BattleIdle; if (showText) { ShowFloatingText(Texts.common[125], target.entity.GlobalPosition, Main.colorGreen); } } else if (target.HP >= target.MAXHP) { if (showText) { ShowFloatingText(Texts.common[126], target.entity.GlobalPosition, Main.colorGreen); } } else if (showText) { ShowFloatingText(amt.ToString(), target.entity.GlobalPosition, Main.colorGreen); } if (doColor) { for (float a = 0f; a < 30f; a += Main.deltaTime) { target.entity.Modulate = Main.colorGreen.Lerp(Main.colorWhite, a / 30f); yield return null; } } } public void DoDamage(Battlers attacker, Battlers target, float multiplier = 1f, bool miss = false, bool noTP = false, bool dontKill = false, bool showNumber = true, int? overrideDamage = null) { bool flag = !attacker.enemy && attacker.selectedAction != null && attacker.selectedAction[0] == 1 && Texts.skills[(Acts.IDs)attacker.selectedAction[2]].onlyOnExecutable; Vector2 pos = target.entity.GlobalPosition + Vector2.Up * 16f * attacker.posID + Vector2.Left * Main.RandomRange(-16, 3); int num = ((attacker.atkMod != null) ? attacker.atkMod[1] : 0); int num2 = ((target.defMod != null) ? target.defMod[1] : 0); int valueOrDefault = overrideDamage.GetValueOrDefault(); if (!overrideDamage.HasValue) { valueOrDefault = attacker.ATK; overrideDamage = valueOrDefault; } int num3 = Mathf.Clamp(Mathf.RoundToInt((float)(overrideDamage.Value + num) * multiplier * (1f + Main.RandomRange(-0.1f, 0.1f))) - (target.DEF + num2), 0, 999); Color value = Main.colorWhite; string text = ""; target.hpLastTurn = target.HP; if (!attacker.enemy) { value = Main.instance.partyColors[attacker.internalID]; if (!miss && !noTP) { TP = Mathf.Clamp(TP + Mathf.FloorToInt((float)num3 / 10f), 0, 100); } } if (miss) { text = Texts.common[122]; } else { target.entity.shake = 20f; text = num3.ToString(); } if (!miss) { Audio.PlaySound("snd_damage.wav"); target.HP = Mathf.Clamp(target.HP - num3, dontKill ? 1 : 0, target.MAXHP); if (num3 > 0) { target.entity.currentAnim = Entity.Animations.Hurt; } Coroutine.Stop(target.animRoutine); if (target.HP <= 0) { if (lastResult != EndState.Special) { if (flag) { fleeing.Add(Coroutine.Start(KillAnim(target))); } else if (target.callEventOnDefeat != Acts.IDs.None && (events == null || events.done)) { events = Acts.DoActRoutine(target.callEventOnDefeat.ToString(), target, new Battlers[1] { attacker }); } else if (!target.fleeing) { fleeing.Add(Coroutine.Start(Flee(target))); } } else if (flag) { RemoveEnemy(target, EndState.Executed); } else { RemoveEnemy(target, EndState.Defeated); } } else { target.animRoutine = Coroutine.Start(target.entity.DelayedAnim(30f, Entity.Animations.Idle)); } } if (showNumber) { ShowFloatingText(text, pos, value); } } public static Control ShowFloatingText(string text, Vector2 pos, Color? color = null) { Color valueOrDefault = color.GetValueOrDefault(); if (!color.HasValue) { valueOrDefault = Main.colorWhite; color = valueOrDefault; } Control control = GD.Load("res://Objects/UI/DamageNumberDR.tscn").Instantiate(PackedScene.GenEditState.Disabled); control.GetChild(0).Text = text; control.Modulate = color.Value; if (current != null) { current.AddChild(control, forceReadableName: false, InternalMode.Disabled); } else if (Room.current != null) { Room.current.AddChild(control, forceReadableName: false, InternalMode.Disabled); } else { Main.instance.AddChild(control, forceReadableName: false, InternalMode.Disabled); } control.GlobalPosition = pos; return control; } private void UpdateMenu(int mod = 0) { bool flag = extended.Contains(state); DWMenu.instance.battleText.VisibleRatio = 99f; DWMenu.instance.battleText2.Visible = flag; DWMenu.instance.battleDesc.GetParent().Visible = flag; DWMenu.instance.itemArrow.Visible = state == State.SelectItem && SaveFile.current.dwItems.Count > 6; if (!flag) { tpPreview = 0; } switch (state) { case State.PlayerTurn: DWMenu.instance.partyHUDs[currentActor].UpdateOpt(option); soul.Visible = false; DWMenu.instance.battleText.Text = Texts.battleMes[battleMes][lastMes].text; if (!firstMes) { DWMenu.instance.battleText.VisibleRatio = 0f; } firstMes = true; break; case State.SelectTarget: if (mod == 0 || mod == 2) { maxOption = ((mod == 2) ? party.Count : enemies.Count); soul.Visible = true; string text4 = "\t\t"; string text5 = ""; for (int l = 0; l < maxOption; l++) { if (mod == 2) { text4 += party[l].name; text5 = text5 + GetTextBar(party[l].HPPercent()) + "[color=black].\t\t\n"; } else { bool num = enemies[l].CanSpare(); if (num) { text4 += "[color=yellow]"; } text4 += enemies[l].name; if (num) { text4 += "[/color]"; } text5 = text5 + GetTextBar(enemies[l].HPPercent()) + "\t\t"; if (!enemies[l].noMercy) { text5 = text5 + GetTextBar((float)enemies[l].spare / 100f, Main.colorYellow) + "\n"; } } text4 += "\n\t\t"; } DWMenu.instance.battleText2.Text = text5; DWMenu.instance.battleText2.VisibleCharacters = -1; DWMenu.instance.battleText.Text = text4; } DWMenu.instance.battleText2.Visible = true; soul.Position = new Vector2(-147f, 78 + option * 17); break; case State.SelectItem: { int num2 = ((option >= 6) ? 6 : 0); string text6 = ""; string text7 = ""; for (int m = 0; m < 6 && m < SaveFile.current.dwItems.Count - num2; m++) { if (m % 2 == 0) { text6 = text6 + "\t\t" + Texts.items[SaveFile.current.dwItems[m + num2]].name + "\n"; } else { text7 = text7 + "\t\t" + Texts.items[SaveFile.current.dwItems[m + num2]].name + "\n"; } } DWMenu.instance.itemArrow.FlipV = option >= 6; DWMenu.instance.itemArrow.Position = new Vector2(DWMenu.instance.itemArrow.Position.X, (option >= 6) ? 12 : 44); DWMenu.instance.battleText.Text = text6; DWMenu.instance.battleText2.Text = text7; DWMenu.instance.battleText2.VisibleCharacters = -1; DWMenu.instance.battleText2.Visible = true; maxOption = SaveFile.current.dwItems.Count; DWMenu.instance.battleDesc.Text = "[color=gray]" + (Texts.items[SaveFile.current.dwItems[option]].shopDesc ?? Texts.items[SaveFile.current.dwItems[option]].shortDesc); soul.Visible = true; soul.Position = new Vector2(((option - num2) % 2 == 0) ? (-147) : (-41), 78 + Mathf.FloorToInt((float)(option - num2) / 2f) * 17); break; } case State.SelectSkill: case State.SelectAct: if (mod == 0) { List list = new List(GetPossibleActs()); if (state == State.SelectAct) { for (int i = 0; i < enemies[allBattlers[currentActor].selectedAction[1]].acts.Count; i++) { Acts.IDs ds = enemies[allBattlers[currentActor].selectedAction[1]].acts[i]; if (CanUseAct(ds)) { list.Add((int)ds); } } } possible = list.ToArray(); string text = ""; string text2 = ""; for (int j = 0; j < possible.Length; j++) { if (j % 2 == 0) { text = text + "\t\t" + Texts.skills[(Acts.IDs)possible[j]].name + "\n"; } else { text2 = text2 + "\t\t" + Texts.skills[(Acts.IDs)possible[j]].name + "\n"; } } DWMenu.instance.battleText.Text = text; DWMenu.instance.battleText2.Text = text2; DWMenu.instance.battleText2.VisibleCharacters = -1; DWMenu.instance.battleText2.Visible = true; maxOption = possible.Length; } if (Texts.skills[(Acts.IDs)possible[option]].spAction) { string text3 = ""; for (int k = 0; k < enemies.Count; k++) { text3 = text3 + "* " + Texts.skills[enemies[k].acts[enemies[allBattlers[currentActor].selectedAction[1]].partyAction[0]]].name + "\n"; } DWMenu.instance.battleDesc.Text = "[color=gray]" + text3; } else if (Texts.skills[(Acts.IDs)possible[option]].desc != null) { DWMenu.instance.battleDesc.Text = "[color=gray]" + Texts.skills[(Acts.IDs)possible[option]].desc; if (Texts.skills[(Acts.IDs)possible[option]].TP > 0) { RichTextLabel battleDesc = DWMenu.instance.battleDesc; battleDesc.Text = battleDesc.Text + "\n[color=#ED7117]" + Texts.skills[(Acts.IDs)possible[option]].TP + "% TP"; } } else { DWMenu.instance.battleDesc.Text = ""; } soul.Visible = true; soul.Position = new Vector2((option % 2 == 0) ? (-147) : (-41), 78 + Mathf.FloorToInt((float)option / 2f) * 17); tpPreview = Texts.skills[(Acts.IDs)possible[option]].TP; break; case State.DoSpells: case State.DoAttack: case State.DoEnemy: case State.EndTurn: break; } } }