Beispiel #1
0
        public static void ApplyEdeaFix(FileSource battleSource, FileSource fieldSource)
        {
            // clone encounter
            var encFile = EncounterFile.FromSource(battleSource);

            encFile.Encounters[845] = encFile.Encounters[136];
            battleSource.ReplaceFile(EncounterFile.Path, encFile.Encode());

            // redirect field script to clone
            var fieldName = "glyagu1";
            var field     = Field.FieldScript.FromSource(fieldSource, fieldName);
            var script    = field.Entities[2].Scripts[4].Instructions;

            for (int i = 0; i < script.Count - 2; i++)
            {
                if (script[i].OpCode == Field.FieldScript.OpCodesReverse["pshn_l"] && script[i].Param == 136)
                {
                    if (script[i + 2].OpCode == Field.FieldScript.OpCodesReverse["battle"])
                    {
                        field.Entities[2].Scripts[4].Instructions[i].Param = 845;
                    }
                }
            }
            StorySkip.SaveToSource(fieldSource, fieldName, field.Encode());
        }
Beispiel #2
0
        private static void FixDiablos(FileSource battleSource, EncounterFile newEncFile, int origEncID)
        {
            // find main boss monster of the encounter replacing diablos
            var bossSlot  = Bosses.Find(b => b.EncounterID == origEncID).SlotRanks[0];
            var monsterId = newEncFile.Encounters[811].Slots[bossSlot].MonsterID;
            var monster   = Monster.ByID(battleSource, monsterId);

            // add GF unlock to monster's init script
            var script = monster.AI.Scripts.Init;

            script.InsertRange(0, new List <Battle.Instruction>
            {
                // if shared-var-4 == 0
                new Battle.Instruction(Battle.Instruction.OpCodesReverse["if"], new short[] { 0x64, 0xc8, 0x00, 0x00, 0x08 }),

                // give diablos
                new Battle.Instruction(Battle.Instruction.OpCodesReverse["award-gf"], new short[] { 0x05 }),

                // shared-var-4 = 1
                new Battle.Instruction(Battle.Instruction.OpCodesReverse["set-shared"], new short[] { 0x64, 0x01 }),

                // end if
                new Battle.Instruction(Battle.Instruction.OpCodesReverse["jmp"], new short[] { 0x00 })
            });;

            battleSource.ReplaceFile(Monster.GetPath(monsterId), monster.Encode());
        }
Beispiel #3
0
        private static void FixOdin(FileSource battleSource, EncounterFile cleanEncFile)
        {
            var monsterId = cleanEncFile.Encounters[317].Slots[0].MonsterID;
            var monster   = Monster.ByID(battleSource, monsterId);
            var script    = monster.AI.Scripts.Execute;

            script.Insert(0, new Battle.Instruction(Battle.Instruction.OpCodesReverse["return"]));
            battleSource.ReplaceFile(Monster.GetPath(monsterId), monster.Encode());
        }
Beispiel #4
0
        private static void GiveBattleReward(FileSource battleSource, EncounterFile encFile, int encounterID, string rewardOp, short rewardID)
        {
            var encounter        = encFile.Encounters[encounterID];
            var slot             = encounter.Slots[Boss.Encounters[encounterID].SlotRanks[0]];
            var monster          = slot.GetMonster(battleSource);
            var awardInstruction = new Battle.Instruction(Battle.Instruction.OpCodesReverse[rewardOp], new short[] { rewardID });

            monster.AI.Scripts.Init.Insert(0, awardInstruction);
            battleSource.ReplaceFile(Monster.GetPath(slot.MonsterID), monster.Encode());
        }
Beispiel #5
0
        private static void FixSorceresses(EncounterFile cleanEncFile, EncounterFile newEncFile, int encID)
        {
            // copy sorceress
            var sorceressEncounter = cleanEncFile.Encounters[813];

            newEncFile.Encounters[encID].Scene                    = sorceressEncounter.Scene;
            newEncFile.Encounters[encID].MainCamera               = sorceressEncounter.MainCamera;
            newEncFile.Encounters[encID].MainCameraAnimation      = sorceressEncounter.MainCameraAnimation;
            newEncFile.Encounters[encID].SecondaryCamera          = sorceressEncounter.SecondaryCamera;
            newEncFile.Encounters[encID].SecondaryCameraAnimation = sorceressEncounter.SecondaryCameraAnimation;
        }
Beispiel #6
0
 // remove existing rewards from an encounter
 private static void ClearDrops(FileSource battleSource, EncounterFile encFile, int encounterID)
 {
     foreach (var slot in encFile.Encounters[encounterID].Slots)
     {
         var monster = slot.GetMonster(battleSource);
         for (int i = 0; i < 4; i++)
         {
             monster.Info.DropLow[i]  = new HeldItem();
             monster.Info.DropMed[i]  = new HeldItem();
             monster.Info.DropHigh[i] = new HeldItem();
         }
         battleSource.ReplaceFile(Monster.GetPath(slot.MonsterID), monster.Encode());
     }
 }
Beispiel #7
0
        private static void FixIguions(FileSource battleSource, EncounterFile cleanEncFile)
        {
            var monsterId = cleanEncFile.Encounters[147].Slots[0].MonsterID;
            var monster   = Monster.ByID(battleSource, monsterId);
            var script    = monster.AI.Scripts.Init;

            script.InsertRange(0, new List <Battle.Instruction>
            {
                // if irvine is not alive
                new Battle.Instruction(Battle.Instruction.OpCodesReverse["if"], new short[] { 0x09, 0xc8, 0x03, 0x02, 0x06 }),

                // shared-var-1 (dialogue flag) = 1
                new Battle.Instruction(Battle.Instruction.OpCodesReverse["set-shared"], new short[] { 0x61, 0x01 }),

                // end if
                new Battle.Instruction(Battle.Instruction.OpCodesReverse["jmp"], new short[] { 0x00 })
            });

            battleSource.ReplaceFile(Monster.GetPath(monsterId), monster.Encode());
        }
Beispiel #8
0
        public static Dictionary <int, int> Shuffle(FileSource battleSource, bool rebalance, int seed)
        {
            var random = new Random(seed);

            var encFilePath = EncounterFile.Path;
            var sourceFile  = EncounterFile.FromSource(battleSource, encFilePath);
            var newFile     = EncounterFile.FromSource(battleSource, encFilePath);

            var bossEncounterIds = Encounters.Keys.ToList();
            var matchIdPool      = Encounters.Keys.ToList();

            var encIdMap = new Dictionary <int, int>();

            foreach (var encId in bossEncounterIds)
            {
                // pick an encounter from the pool
                var matchedId = matchIdPool[random.Next(matchIdPool.Count)];
                matchIdPool.Remove(matchedId);
                encIdMap.Add(encId, matchedId);

                // copy the monster slots from the other encounter
                for (int i = 0; i < 8; i++)
                {
                    var monsterId = sourceFile.Encounters[matchedId].Slots[i].MonsterID;

                    newFile.Encounters[encId].Slots[i] = sourceFile.Encounters[matchedId].Slots[i];

                    if (rebalance)
                    {
                        // retain level
                        newFile.Encounters[encId].Slots[i].Level = sourceFile.Encounters[encId].Slots[i].Level;
                    }

                    // update any encounter ID checks in the monster's AI scripts
                    foreach (var ec in EncounterChecks.Where(ec => ec.MonsterID == monsterId && ec.EncounterID == matchedId))
                    {
                        var monster = sourceFile.Encounters[matchedId].Slots[i].GetMonster(battleSource);
                        var script  = monster.AI.Scripts.EventScripts[ec.Script];
                        script[ec.Instruction].Args[3] = (short)encId;
                        battleSource.ReplaceFile(Monster.GetPath(monsterId), monster.Encode());
                    }
                }

                // force the nameless sorceresses to fight in the commencement room
                // so they can do the melty background thing without crashing the game
                if (matchedId == 813)
                {
                    var sorceressEncounter = sourceFile.Encounters[813];
                    newFile.Encounters[encId].Scene                    = sorceressEncounter.Scene;
                    newFile.Encounters[encId].MainCamera               = sorceressEncounter.MainCamera;
                    newFile.Encounters[encId].MainCameraAnimation      = sorceressEncounter.MainCameraAnimation;
                    newFile.Encounters[encId].SecondaryCamera          = sorceressEncounter.SecondaryCamera;
                    newFile.Encounters[encId].SecondaryCameraAnimation = sorceressEncounter.SecondaryCameraAnimation;
                }
            }

            // save new encounter file
            battleSource.ReplaceFile(encFilePath, newFile.Encode());

            return(encIdMap);
        }
Beispiel #9
0
        public static void SetRewards(FileSource battleSource, FileSource fieldSource, int seed)
        {
            var random        = new Random(seed + 11);
            var major         = new List <Reward>(Major);
            var minor         = new List <Reward>(Minor);
            var encounterFile = EncounterFile.FromSource(battleSource);

            // bosses with no fixed location are assigned rewards that don't require field scripting
            foreach (var boss in Boss.Bosses.Where(b => !b.FixedField))
            {
                var battleOnlyMajor = major.Where(r => r.Type == RewardType.GF || r.Type == RewardType.Item).ToList();
                var majorIndex      = random.Next(0, battleOnlyMajor.Count);
                var minorIndex      = random.Next(0, minor.Count);

                // remove any existing item drops
                ClearDrops(battleSource, encounterFile, boss.EncounterID);

                switch (battleOnlyMajor[majorIndex].Type)
                {
                case RewardType.GF:
                    GiveGF(battleSource, encounterFile, boss.EncounterID, battleOnlyMajor[majorIndex].ID);
                    break;

                case RewardType.Item:
                    GiveItem(battleSource, encounterFile, boss.EncounterID, battleOnlyMajor[majorIndex].ID);
                    break;
                }

                // minor rewards are all items
                GiveItem(battleSource, encounterFile, boss.EncounterID, minor[minorIndex].ID);

                // remove rewards from the pool
                major.Remove(battleOnlyMajor[majorIndex]);
                battleOnlyMajor.RemoveAt(majorIndex);
                minor.RemoveAt(minorIndex);
            }

            // the rest of the bosses can be assigned anything
            foreach (var boss in Boss.Bosses.Where(b => b.FixedField))
            {
                if (major.Count > 0)
                {
                    var majorIndex = random.Next(0, major.Count);

                    // remove any existing item drops
                    ClearDrops(battleSource, encounterFile, boss.EncounterID);

                    switch (major[majorIndex].Type)
                    {
                    case RewardType.Character:
                        GiveCharacter(fieldSource, boss.EncounterID, major[majorIndex]);
                        break;

                    case RewardType.GF:
                        GiveGF(battleSource, encounterFile, boss.EncounterID, major[majorIndex].ID);
                        break;

                    case RewardType.Special:
                        GiveSpecial(fieldSource, boss.EncounterID, major[majorIndex]);
                        break;

                    case RewardType.Seal:
                        break;

                    case RewardType.Item:
                        GiveItem(battleSource, encounterFile, boss.EncounterID, major[majorIndex].ID);
                        break;
                    }

                    major.RemoveAt(majorIndex);
                }

                // minor rewards are all items
                var minorIndex = random.Next(0, minor.Count);
                GiveItem(battleSource, encounterFile, boss.EncounterID, minor[minorIndex].ID);
                minor.RemoveAt(minorIndex);
            }
        }
Beispiel #10
0
 public static void GiveItem(FileSource battleSource, EncounterFile encFile, int encounterID, short itemID)
 {
     GiveBattleReward(battleSource, encFile, encounterID, "award-item", itemID);
 }
Beispiel #11
0
 public static void GiveGF(FileSource battleSource, EncounterFile encFile, int encounterID, short gfID)
 {
     GiveBattleReward(battleSource, encFile, encounterID, "award-gf", gfID);
 }
Beispiel #12
0
        public static void Apply(FileSource battleSource, Dictionary <int, int> encounterMap)
        {
            var cleanEncFile = EncounterFile.FromSource(battleSource, EncounterFile.Path);
            var newEncFile   = EncounterFile.FromSource(battleSource, EncounterFile.Path);

            foreach (var encID in encounterMap.Keys)
            {
                var matchedEncID = encounterMap[encID];

                // copy monster slots from the incoming encounter
                for (int i = 0; i < 8; i++)
                {
                    var newMonsterID = cleanEncFile.Encounters[matchedEncID].Slots[i].MonsterID;
                    newEncFile.Encounters[encID].Slots[i] = cleanEncFile.Encounters[matchedEncID].Slots[i];

                    // update any encounter ID checks in the monster's AI scripts
                    FixEncounterChecks(battleSource, newMonsterID, encID, matchedEncID);

                    // tonberry king
                    var tonberryIDs = new List <int>()
                    {
                        236, 237, 238
                    };
                    if (tonberryIDs.Contains(matchedEncID))
                    {
                        if (i == 0)
                        {
                            // enable tonberry king
                            newEncFile.Encounters[encID].Slots[i].Enabled      = true;
                            newEncFile.Encounters[encID].Slots[i].Hidden       = false;
                            newEncFile.Encounters[encID].Slots[i].Unloaded     = false;
                            newEncFile.Encounters[encID].Slots[i].Untargetable = false;
                        }
                        else
                        {
                            // disable everything else
                            newEncFile.Encounters[encID].Slots[i].Enabled      = false;
                            newEncFile.Encounters[encID].Slots[i].Hidden       = true;
                            newEncFile.Encounters[encID].Slots[i].Unloaded     = true;
                            newEncFile.Encounters[encID].Slots[i].Untargetable = true;
                        }
                    }

                    if (tonberryIDs.Contains(encID))
                    {
                        // disable tonberry king's replacement, to be summoned by tonberry
                        newEncFile.Encounters[encID].Slots[i].Enabled = false;
                        break;
                    }
                }

                // award diablos GF for beating whoever is in the lamp to avoid softlock
                if (encID == 811)
                {
                    FixDiablos(battleSource, newEncFile, matchedEncID);
                }

                // force the sorceresses to fight in their normal scene to avoid crash
                if (matchedEncID == 813)
                {
                    FixSorceresses(cleanEncFile, newEncFile, encID);
                }
            }

            // skip shot tutorial for iguion fight if irvine isn't present
            FixIguions(battleSource, cleanEncFile);

            // remove odin's instakill attack
            FixOdin(battleSource, cleanEncFile);

            // save changes
            battleSource.ReplaceFile(EncounterFile.Path, newEncFile.Encode());
        }