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()); }
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()); }
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()); }
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()); }
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; }
// 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()); } }
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()); }
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); }
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); } }
public static void GiveItem(FileSource battleSource, EncounterFile encFile, int encounterID, short itemID) { GiveBattleReward(battleSource, encFile, encounterID, "award-item", itemID); }
public static void GiveGF(FileSource battleSource, EncounterFile encFile, int encounterID, short gfID) { GiveBattleReward(battleSource, encFile, encounterID, "award-gf", gfID); }
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()); }