| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- using System;
- using System.Collections.Generic;
- using System.Diagnostics.CodeAnalysis;
- using System.Linq;
- using Microsoft.Xna.Framework;
- using OpenVIII.Kernel;
- namespace OpenVIII
- {
- public class DeadTime : Slide<int>
- {
- private static int Lerp(int start, int end, float amount) => checked((int)MathHelper.Lerp(start, end, amount));
- private static TimeSpan GenerateTotalTime(int start) => TimeSpan.FromMilliseconds((1000d / 15d) * start);
- public DeadTime() : base(200, 0, GenerateTotalTime(200), Lerp)
- {
- Repeat = true;
- DoneEvent += DeadTime_DoneEvent;
- }
- protected override void CheckRepeat()
- {
- if (Done)
- {
- DoneEvent?.Invoke(this, End);
- }
- base.CheckRepeat();
- }
- public override void GotoEnd()
- {
- DoneEvent?.Invoke(this, End);
- base.GotoEnd();
- }
- private event EventHandler<int> DoneEvent;
- public event EventHandler<int> Gilgamesh;
- public event EventHandler<Saves.Item> AngeloSearch;
- public event EventHandler<Characters> AngeloReverse;
- public event EventHandler<Characters> AngeloRecover;
- /// <summary>
- /// Test if an ability can trigger for Angelo.
- /// </summary>
- /// <param name="ability"></param>
- /// <returns></returns>
- private static bool TestAngeloAbilityTriggers(Angelo ability)
- {
- //else if (8 >= [0..255] Angelo Recover is used (3.3 %)
- //else if (2 >= [0..255] Angelo Reverse is used (1 %)
- //else if (8 >= [0..255] Angelo Search is used (3.2 %)
- //Angelo_Disabled I think is set when Rinoa is in space so angelo is out of reach;
- //https://gamefaqs.gamespot.com/ps/197343-final-fantasy-viii/faqs/25194
- if (Memory.State.BattleMiscFlags.HasFlag(Saves.BattleMiscFlags.AngeloDisabled) ||
- !Memory.State.Party.Contains(Characters.Rinoa_Heartilly) ||
- !Memory.State.LimitBreakAngeloCompleted.HasFlag(ability)) return false;
- switch (ability)
- {
- case Angelo.Recover:
- //Characters.Any(x => x.Value.IsCritical && !x.Value.IsDead && Memory.State.PartyData.Contains(x.Key))
- return !Memory.State.AnyDeadPartyMembers && Memory.State.AnyCriticalPartyMembers && Memory.Random.Next(256) < 8;
- case Angelo.Reverse:
- return Memory.State.AnyDeadPartyMembers && Memory.Random.Next(256) < 2;
- case Angelo.Search:
- var c = Memory.State[Characters.Rinoa_Heartilly];
- if (!(c.IsGameOver ||
- c.Statuses1.HasFlag(BattleOnlyStatuses.Sleep) ||
- c.Statuses1.HasFlag(BattleOnlyStatuses.Stop) ||
- c.Statuses1.HasFlag(BattleOnlyStatuses.Confuse) ||
- c.Statuses0.HasFlag(PersistentStatuses.Berserk) ||
- c.Statuses1.HasFlag(BattleOnlyStatuses.AngelWing)))
- return Memory.Random.Next(256) < 8;
- break;
- case Angelo.None:
- break;
- case Angelo.Rush:
- break;
- case Angelo.Cannon:
- break;
- case Angelo.Strike:
- break;
- case Angelo.Invincible_Moon:
- break;
- case Angelo.Wishing_Star:
- break;
- case Angelo.Angel_Wing:
- break;
- default:
- throw new ArgumentOutOfRangeException(nameof(ability), ability, null);
- }
- return false;
- }
- /// <summary>
- /// if (12 >= [0..255]) Gilgamesh is summoned (5.1 %)
- /// </summary>
- /// <returns>bool</returns>
- private static bool TestGilgamesh() =>
- Memory.State.BattleMiscFlags.HasFlag(Saves.BattleMiscFlags.Gilgamesh) && Memory.Random.Next(256) <= 12;
- /// <summary>
- /// Trigger Event when DeadTime is done.
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- /// <see cref="https://gamefaqs.gamespot.com/ps/197343-final-fantasy-viii/faqs/58936"/>
- [SuppressMessage("ReSharper", "PossibleMultipleEnumeration")]
- private void DeadTime_DoneEvent(object sender, int e)
- {
- bool save(IEnumerable<Characters> hurt, ref EventHandler<Characters> @event)
- {
- if (hurt == null || !hurt.Any()) return false;
- var c = hurt.Random();
- @event?.Invoke(this, c);
- return true;
- }
- //Will Gilgamesh appear?
- if (TestGilgamesh())
- {
- Gilgamesh?.Invoke(this, 0);
- }
- //Will Angelo Recover be used?
- else if (TestAngeloAbilityTriggers(Angelo.Recover) &&
- save(Memory.State.Party.Where(x => x != Characters.Blank && Memory.State[x].IsCritical), ref AngeloRecover))
- { }
- //Will Angelo Reverse be used?
- else if (TestAngeloAbilityTriggers(Angelo.Reverse) &&
- save(Memory.State.Party.Where(x => x != Characters.Blank && Memory.State[x].IsDead), ref AngeloReverse))
- {}
- //Will Angelo Search be used?
- else if (TestAngeloAbilityTriggers(Angelo.Search))
- {
- //Real game has a counter that Count to 255 and resets to 0
- //instead of a random number. The counter counts up every 1 tick.
- //60 ticks per second.
- var rnd = checked((byte)Memory.Random.Next(256));
- if (rnd < 128) AngeloSearch?.Invoke(this,Algorithm(1));
- else if (rnd < 160) AngeloSearch?.Invoke(this, Algorithm(2));
- else if (rnd < 176) AngeloSearch?.Invoke(this, Algorithm(3));
- else if (rnd < 192) AngeloSearch?.Invoke(this, Algorithm(4));
- else if (rnd < 200) AngeloSearch?.Invoke(this, Algorithm(5));
- else AngeloSearch?.Invoke(this, Algorithm(6));
- Saves.Item Algorithm(byte i)
- {
- //https://gamefaqs.gamespot.com/ps/197343-final-fantasy-viii/faqs/58936
- //I'm unsure where in the game files this is.
- //In remaster they changed this. But unsure how
- // they added (Ribbon, Friendship, and Mog's Amulet)
- // using a true random kinda breaks this.
- // because in game random is a set array of numbers 0-255
- // so the number you get previous would determine the possible number you get
- // so these can only select specific numbers. But because we are using a real random
- // more items are possible. might need to tweak this.
- //these are added in remaster as possible items.
- //const byte Ribbon = 100;
- //const byte Friendship = 32;
- //const byte Mog's_Amulet = 65;
- var item = new Saves.Item { QTY = 1 };
- rnd = checked((byte)Memory.Random.Next(256));
- switch (i)
- {
- case 1: // 1-8
- item.ID = (byte)(rnd % 8 + 1);
- break;
- case 2: // 102-199
- item.ID = (byte)(rnd % 98);
- if (item.ID == 0) item.ID = 98;
- item.ID += 101;
- break;
- case 3: // 102-124
- item.ID = (byte)(rnd % 23);
- if (item.ID == 0)
- item.ID = 23;
- item.ID += 101;
- break;
- case 4: // 67-100
- item.ID = (byte)(rnd % 34);
- if (item.ID == 0)
- item.ID = 34;
- item.ID += 66;
- break;
- case 5: // 33-54
- item.ID = (byte)(rnd % 32 + 33);
- break;
- default: // 33-40
- item.ID = (byte)(rnd % 7 + 33);
- break;
- }
- return item;
- }
- }
- }
- }
- }
|