protected override void ExecuteCore(LivingEntity source, LivingEntity target) { var targetName = (target is Player) ? "You are" : $"The {target.Name} is"; var hp = Rng.Between(_minHeal, _maxHeal); OnExecuted(new ActionCommandEventArgs($"{targetName} healed for {hp} points")); target.Heal(hp); //One use item target.RemoveFromInventory(_item.Id, 1); }
protected override void ExecuteCore(LivingEntity source, LivingEntity target) { var sourceName = (source is Player) ? "You" : $"The {source.Name}"; var targetName = (target is Player) ? "You" : $"The {target.Name}"; var dmg = Rng.Between(_minDmg, _maxDmg); if (dmg == 0) { OnExecuted(new ActionCommandEventArgs($"{sourceName} missed")); } else { OnExecuted(new ActionCommandEventArgs($"{sourceName} hit {targetName} for {dmg} damage")); target.TakeDamage(dmg); }; }
//TODO: Use MonsterInstance instead public virtual Monster CreateInstance() { var instance = new Monster(Id, Name, MaximumHitPoints, RewardXP, ImagePath, Gold); //Figure out loot foreach (var loot in _lootTable) { if (Rng.Between(1, 100) <= loot.Percentage) { instance.AddToInventory(ItemFactory.NewItem(loot.Id)); } } ; instance.CurrentWeapon = CurrentWeapon; return(instance); }
private static Call Create(Action <Chat, CallScenario> scriptBuilder, CallResolution requestedOption) { var correctResolution = Rng.Between(requestedOption, CallResolution.Reject, 0.70); var scenario = CallScenarioFactory.Create(Job.ReturnSpecialistLevel1, PatienceLevel.Random); var chat = InitChat(scenario); scriptBuilder(chat, scenario); AddPlayerRequestConfirmation(scenario); var purchase = CreatePurchase(scenario, correctResolution); Debug.WriteLine($"CallResolution: Requested {requestedOption}. Expects {correctResolution} for {purchase.ProductName}"); var history = Purchase.CreateInfiniteWith(purchase).Take(1000).Where(x => x.PurchasedWithinLast(90)); scenario.Purchases = history; scenario.Target = new Optional <Purchase>(purchase); return(new Call(chat, scenario, correctResolution, Level1Options)); }
public Monster GetEncounter() { if (!Encounters.Any()) { return(null); } var totalChance = Encounters.Sum(x => x.Percentage); var result = Rng.Between(1, totalChance); var total = 0; foreach (var encounter in Encounters) { total += encounter.Percentage; if (result <= total) { return(MonsterFactory.Get(encounter.Id)); } } ; return(null); }
public void Randomize(Blob seed, Flags flags, Preferences preferences) { MT19337 rng; using (SHA256 hasher = SHA256.Create()) { Blob FlagsBlob = Encoding.UTF8.GetBytes(Flags.EncodeFlagsText(flags)); Blob SeedAndFlags = Blob.Concat(new Blob[] { FlagsBlob, seed }); Blob hash = hasher.ComputeHash(SeedAndFlags); rng = new MT19337(BitConverter.ToUInt32(hash, 0)); } if (flags.TournamentSafe) { AssureSafe(); } UpgradeToMMC3(); MakeSpace(); Bank1E(); Bank1B(); EasterEggs(); DynamicWindowColor(preferences.MenuColor); PermanentCaravan(); ShiftEarthOrbDown(); CastableItemTargeting(); FixEnemyPalettes(); // fixes a bug in the original game's programming that causes third enemy slot's palette to render incorrectly FixWarpBug(); // The warp bug must be fixed for magic level shuffle and spellcrafter SeparateUnrunnables(); var talkroutines = new TalkRoutines(); var npcdata = new NPCdata(this); UpdateDialogs(npcdata); if (flags.TournamentSafe) { Put(0x3FFE3, Blob.FromHex("66696E616C2066616E74617379")); } flags = Flags.ConvertAllTriState(flags, rng); TeleportShuffle teleporters = new TeleportShuffle(); var palettes = OverworldMap.GeneratePalettes(Get(OverworldMap.MapPaletteOffset, MapCount * OverworldMap.MapPaletteSize).Chunk(OverworldMap.MapPaletteSize)); var overworldMap = new OverworldMap(this, flags, palettes, teleporters); var maps = ReadMaps(); var shopItemLocation = ItemLocations.CaravanItemShop1; var oldItemNames = ReadText(ItemTextPointerOffset, ItemTextPointerBase, ItemTextPointerCount); if (flags.EFGWaterfall || flags.EFGEarth1 || flags.EFGEarth2) { MapRequirements reqs; MapGeneratorStrategy strategy; MapGenerator generator = new MapGenerator(); if (flags.EFGWaterfall) { reqs = new MapRequirements { MapId = MapId.Waterfall, Rom = this, }; strategy = MapGeneratorStrategy.WaterfallClone; CompleteMap waterfall = generator.Generate(rng, strategy, reqs); // Should add more into the reqs so that this can be done inside the generator. teleporters.Waterfall.SetEntrance(waterfall.Entrance); overworldMap.PutOverworldTeleport(OverworldTeleportIndex.Waterfall, teleporters.Waterfall); maps[(int)MapId.Waterfall] = waterfall.Map; } if (flags.EFGEarth1) { reqs = new MapRequirements { MapId = MapId.EarthCaveB1, Rom = this, }; strategy = MapGeneratorStrategy.Square; var earthB1 = generator.Generate(rng, strategy, reqs); // Should add more into the reqs so that this can be done inside the generator. teleporters.EarthCave1.SetEntrance(earthB1.Entrance); overworldMap.PutOverworldTeleport(OverworldTeleportIndex.EarthCave1, teleporters.EarthCave1); maps[(int)MapId.EarthCaveB1] = earthB1.Map; } if (flags.EFGEarth2) { reqs = new MapRequirements { MapId = MapId.EarthCaveB2, Rom = this, }; strategy = MapGeneratorStrategy.Square; var earthB2 = generator.Generate(rng, strategy, reqs); // Should add more into the reqs so that this can be done inside the generator. teleporters.EarthCave2.SetEntrance(earthB2.Entrance); overworldMap.PutStandardTeleport(TeleportIndex.EarthCave2, teleporters.EarthCave2, OverworldTeleportIndex.EarthCave1); maps[(int)MapId.EarthCaveB2] = earthB2.Map; } } var flippedMaps = new List <MapId>(); if ((bool)flags.FlipDungeons) { flippedMaps = HorizontalFlipDungeons(rng, maps, teleporters, overworldMap); } if ((bool)flags.RandomizeFormationEnemizer) { DoEnemizer(rng, (bool)flags.RandomizeEnemizer, (bool)flags.RandomizeFormationEnemizer, flags.EnemizerDontMakeNewScripts); } if (preferences.ModernBattlefield) { EnableModernBattlefield(); } if ((bool)flags.TitansTrove) { EnableTitansTrove(maps); } if ((bool)flags.LefeinShops) { EnableLefeinShops(maps); } // This has to be done before we shuffle spell levels. if (flags.SpellBugs) { FixSpellBugs(); } //must be done before spells get shuffled around otherwise we'd be changing a spell that isnt lock if (flags.LockMode != LockHitMode.Vanilla) { ChangeLockMode(flags.LockMode); } if (flags.EnemySpellsTargetingAllies) { FixEnemyAOESpells(); } if (flags.AllSpellLevelsForKnightNinja) { KnightNinjaChargesForAllLevels(); } if (flags.BuffHealingSpells) { BuffHealingSpells(); } UpdateMagicAutohitThreshold(rng, flags.MagicAutohitThreshold); if ((bool)flags.GenerateNewSpellbook) { CraftNewSpellbook(rng, (bool)flags.SpellcrafterMixSpells, flags.LockMode, (bool)flags.MagicLevels, (bool)flags.SpellcrafterRetainPermissions); } if ((bool)flags.MagisizeWeapons) { MagisizeWeapons(rng, (bool)flags.MagisizeWeaponsBalanced); } if ((bool)flags.ItemMagic) { ShuffleItemMagic(rng, (bool)flags.BalancedItemMagicShuffle); } if ((bool)flags.GuaranteedRuseItem) { CraftRuseItem(); } if ((bool)flags.ShortToFR) { ShortenToFR(maps, (bool)flags.PreserveFiendRefights, (bool)flags.PreserveAllFiendRefights, rng); } if (((bool)flags.Treasures) && flags.ShardHunt && !flags.FreeOrbs) { EnableShardHunt(rng, talkroutines, flags.ShardCount); } if ((bool)flags.TransformFinalFormation && !flags.SpookyFlag) { TransformFinalFormation((FinalFormation)rng.Between(0, Enum.GetValues(typeof(FinalFormation)).Length - 1), flags.EvadeCap); } var maxRetries = 8; for (var i = 0; i < maxRetries; i++) { try { overworldMap = new OverworldMap(this, flags, palettes, teleporters); if (((bool)flags.Entrances || (bool)flags.Floors || (bool)flags.Towns) && ((bool)flags.Treasures) && ((bool)flags.NPCItems)) { overworldMap.ShuffleEntrancesAndFloors(rng, flags); // Disable the Princess Warp back to Castle Coneria if ((bool)flags.Entrances || (bool)flags.Floors) { talkroutines.ReplaceChunk(newTalkRoutines.Talk_Princess1, Blob.FromHex("20CC90"), Blob.FromHex("EAEAEA")); } } if ((bool)flags.Treasures && (bool)flags.ShuffleObjectiveNPCs) { overworldMap.ShuffleObjectiveNPCs(rng); } IncentiveData incentivesData = new IncentiveData(rng, flags, overworldMap, shopItemLocation); if (((bool)flags.Shops)) { var excludeItemsFromRandomShops = new List <Item>(); if ((bool)flags.Treasures) { excludeItemsFromRandomShops = incentivesData.ForcedItemPlacements.Select(x => x.Item).Concat(incentivesData.IncentiveItems).ToList(); } if (!((bool)flags.RandomWaresIncludesSpecialGear)) { excludeItemsFromRandomShops.AddRange(ItemLists.SpecialGear); if ((bool)flags.GuaranteedRuseItem) { excludeItemsFromRandomShops.Add(Item.PowerRod); } } if ((bool)flags.NoMasamune) { excludeItemsFromRandomShops.Add(Item.Masamune); } shopItemLocation = ShuffleShops(rng, (bool)flags.ImmediatePureAndSoftRequired, ((bool)flags.RandomWares), excludeItemsFromRandomShops, flags.WorldWealth); incentivesData = new IncentiveData(rng, flags, overworldMap, shopItemLocation); } if ((bool)flags.Treasures) { generatedPlacement = ShuffleTreasures(rng, flags, incentivesData, shopItemLocation, overworldMap, teleporters); } break; } catch (InsaneException e) { Console.WriteLine(e.Message); if (maxRetries > (i + 1)) { continue; } throw new InvalidOperationException(e.Message); } } // Change Astos routine so item isn't lost in wall of text if ((bool)flags.NPCItems || (bool)flags.NPCFetchItems || (bool)flags.ShuffleAstos) { talkroutines.Replace(newTalkRoutines.Talk_Astos, Blob.FromHex("A674F005BD2060F027A5738561202096B020A572203D96A575200096A476207F90207392A5611820109F201896A9F060A57060")); } npcdata.UpdateItemPlacement(generatedPlacement); if ((bool)flags.MagicShopLocs) { ShuffleMagicLocations(rng); } if (((bool)flags.MagicShops)) { ShuffleMagicShops(rng); } if (((bool)flags.MagicLevels)) { ShuffleMagicLevels(rng, ((bool)flags.MagicPermissions), (bool)flags.MagicLevelsTiered, (bool)flags.MagicLevelsMixed, (bool)!flags.GenerateNewSpellbook); } new StartingInventory(rng, flags, this).SetStartingInventory(); /* * if (flags.WeaponPermissions) * { * ShuffleWeaponPermissions(rng); * } * * if (flags.ArmorPermissions) * { * ShuffleArmorPermissions(rng); * } */ if (flags.SaveGameWhenGameOver) { EnableSaveOnDeath(flags); } // Ordered before RNG shuffle. In the event that both flags are on, RNG shuffle depends on this. if (((bool)flags.FixMissingBattleRngEntry)) { FixMissingBattleRngEntry(); } if (((bool)flags.Rng)) { ShuffleRng(rng); } if (((bool)flags.EnemyScripts)) { ShuffleEnemyScripts(rng, (bool)flags.AllowUnsafePirates, (bool)!flags.BossScriptsOnly, ((bool)flags.EnemySkillsSpellsTiered || (bool)flags.ScaryImps), (bool)flags.ScaryImps); } if (((bool)flags.EnemySkillsSpells)) { if ((bool)flags.EnemySkillsSpellsTiered && (bool)!flags.BossSkillsOnly) { GenerateBalancedEnemyScripts(rng, (bool)flags.SwolePirates); ShuffleEnemySkillsSpells(rng, false); } else { ShuffleEnemySkillsSpells(rng, (bool)!flags.BossSkillsOnly); } } if (((bool)flags.EnemyStatusAttacks)) { if (((bool)flags.RandomStatusAttacks)) { RandomEnemyStatusAttacks(rng, (bool)flags.AllowUnsafePirates, (bool)flags.DisableStunTouch); } else { ShuffleEnemyStatusAttacks(rng, (bool)flags.AllowUnsafePirates); } } if (flags.Runnability == Runnability.Random) { flags.Runnability = (Runnability)Rng.Between(rng, 0, 3); } if (flags.Runnability == Runnability.AllRunnable) { CompletelyRunnable(); } else if (flags.Runnability == Runnability.AllUnrunnable) { CompletelyUnrunnable(); } else if (flags.Runnability == Runnability.Shuffle) { ShuffleUnrunnable(rng); } // Always on to supply the correct changes for WaitWhenUnrunnable AllowStrikeFirstAndSurprise(flags.WaitWhenUnrunnable, (bool)flags.UnrunnablesStrikeFirstAndSurprise); if (((bool)flags.EnemyFormationsSurprise)) { ShuffleSurpriseBonus(rng); } // Put this before other encounter / trap tile edits. if ((bool)flags.AllowUnsafeMelmond) { EnableMelmondGhetto(flags.EnemizerEnabled); } // After unrunnable shuffle and before formation shuffle. Perfect! if (flags.WarMECHMode != WarMECHMode.Vanilla) { WarMECHNpc(flags.WarMECHMode, npcdata, rng, maps); } if (flags.WarMECHMode == WarMECHMode.Unleashed) { UnleashWarMECH(); } if ((bool)flags.ClassAsNpcFiends || (bool)flags.ClassAsNpcKeyNPC) { ClassAsNPC(flags, talkroutines, npcdata, flippedMaps, rng); } if ((bool)flags.FiendShuffle) { FiendShuffle(rng); } if (flags.FormationShuffleMode != FormationShuffleMode.None && !flags.EnemizerEnabled) { ShuffleEnemyFormations(rng, flags.FormationShuffleMode); } if ((bool)flags.RemoveTrapTiles) { RemoveTrapTiles(flags.EnemizerEnabled); } if (((bool)flags.EnemyTrapTiles) && !flags.EnemizerEnabled) { ShuffleTrapTiles(rng, ((bool)flags.RandomTrapFormations)); } if ((bool)flags.OrdealsPillars) { ShuffleOrdeals(rng, maps); } if (flags.SkyCastle4FMazeMode == SkyCastle4FMazeMode.Maze) { DoSkyCastle4FMaze(rng, maps); } else if (flags.SkyCastle4FMazeMode == SkyCastle4FMazeMode.Teleporters) { ShuffleSkyCastle4F(rng, maps); } if ((bool)flags.ConfusedOldMen) { EnableConfusedOldMen(rng); } if ((bool)flags.EarlyOrdeals) { EnableEarlyOrdeals(); } if (flags.ChaosRush) { EnableChaosRush(); } if ((bool)flags.EarlyKing) { EnableEarlyKing(npcdata); } if ((bool)flags.EarlySarda) { EnableEarlySarda(npcdata); } if ((bool)flags.EarlySage) { EnableEarlySage(npcdata); } if ((bool)flags.FreeBridge) { EnableFreeBridge(); } if ((bool)flags.FreeAirship) { EnableFreeAirship(); } if ((bool)flags.FreeShip) { EnableFreeShip(); } if (flags.FreeOrbs) { EnableFreeOrbs(); } if ((bool)flags.FreeCanal) { EnableFreeCanal((bool)flags.NPCItems, npcdata); } if ((bool)flags.FreeCanoe) { EnableFreeCanoe(); } if ((bool)flags.FreeLute) { EnableFreeLute(); } if ((bool)flags.FreeTail && !(bool)flags.NoTail) { EnableFreeTail(); } if (flags.NoPartyShuffle) { DisablePartyShuffle(); } if (flags.SpeedHacks) { EnableSpeedHacks(); } if (flags.IdentifyTreasures) { EnableIdentifyTreasures(); } if (flags.Dash) { EnableDash(); } if (flags.BuyTen) { EnableBuyQuantity(); } else if (flags.BuyTenOld) { EnableBuyTen(); } if (flags.WaitWhenUnrunnable) { ChangeUnrunnableRunToWait(); } if (flags.SpeedHacks && flags.EnableCritNumberDisplay) { EnableCritNumberDisplay(); } if (flags.BattleMagicMenuWrapAround) { BattleMagicMenuWrapAround(); } if (flags.NPCSwatter) { EnableNPCSwatter(npcdata); } if (flags.EasyMode) { EnableEasyMode(); } if ((bool)flags.TrappedChests || (bool)flags.TCMasaGuardian || (bool)flags.TrappedShards) { MonsterInABox(rng, flags); } if (flags.HouseMPRestoration || flags.HousesFillHp) { FixHouse(flags.HouseMPRestoration, flags.HousesFillHp); } if (flags.BBCritRate) { DontDoubleBBCritRates(); } if (flags.WeaponCritRate) { DoubleWeaponCritRates(); } //needs to go after item magic, moved after double weapon crit to have more control over the actual number of crit gained. if ((bool)flags.RandomWeaponBonus) { RandomWeaponBonus(rng, flags.RandomWeaponBonusLow, flags.RandomWeaponBonusHigh, (bool)flags.RandomWeaponBonusExcludeMasa); } if ((bool)flags.RandomArmorBonus) { RandomArmorBonus(rng, flags.RandomArmorBonusLow, flags.RandomArmorBonusHigh); } if (flags.WeaponBonuses) { IncreaseWeaponBonus(flags.WeaponTypeBonusValue); } if (flags.WeaponStats) { FixWeaponStats(); } if (flags.ChanceToRun) { FixChanceToRun(); } if (flags.EnemyStatusAttackBug) { FixEnemyStatusAttackBug(); } if (flags.BlackBeltAbsorb) { FixBBAbsorbBug(); } if (flags.MDefMode != MDEFGrowthMode.None) { MDefChanges(flags.MDefMode); } if (flags.ThiefHitRate) { ThiefHitRate(); } if (flags.ImproveTurnOrderRandomization) { ImproveTurnOrderRandomization(rng); } if (flags.FixHitChanceCap) { FixHitChanceCap(); } if (flags.EnemyElementalResistancesBug) { FixEnemyElementalResistances(); } if (preferences.FunEnemyNames && !flags.EnemizerEnabled) { FunEnemyNames(preferences.TeamSteak); } var itemText = ReadText(ItemTextPointerOffset, ItemTextPointerBase, ItemTextPointerCount); itemText[(int)Item.Ribbon] = itemText[(int)Item.Ribbon].Remove(7); if ((bool)flags.HintsVillage || (bool)flags.HintsDungeon) { if ((bool)flags.HintsDungeon) { SetDungeonNPC(flippedMaps, rng); } NPCHints(rng, npcdata, flags, overworldMap); } if (flags.Etherizer && !flags.HouseMPRestoration && !flags.HousesFillHp) { Etherizer(); itemText[(int)Item.Tent] = "ETHR@p"; itemText[(int)Item.Cabin] = "DRY@p "; itemText[(int)Item.House] = "XETH@p"; } ExpGoldBoost(flags.ExpBonus, flags.ExpMultiplier); ScalePrices(flags, itemText, rng, ((bool)flags.ClampMinimumPriceScale), shopItemLocation); ScaleEncounterRate(flags.EncounterRate / 30.0, flags.DungeonEncounterRate / 30.0); overworldMap.ApplyMapEdits(); WriteMaps(maps); WriteText(itemText, ItemTextPointerOffset, ItemTextPointerBase, ItemTextOffset, UnusedGoldItems); if ((bool)flags.SwolePirates) { EnableSwolePirates(); } if (flags.EnemyScaleStatsHigh != 100 || flags.EnemyScaleStatsLow != 100 || ((bool)flags.SeparateEnemyHPScaling && (flags.EnemyScaleHpLow != 100 || flags.EnemyScaleHpHigh != 100))) { ScaleEnemyStats(rng, flags); } if (flags.BossScaleStatsHigh != 100 || flags.BossScaleStatsLow != 100 || ((bool)flags.SeparateBossHPScaling && (flags.BossScaleHpLow != 100 || flags.BossScaleHpHigh != 100))) { ScaleBossStats(rng, flags); } PartyComposition(rng, flags, preferences); if (((bool)flags.RecruitmentMode)) { PubReplaceClinic(rng, flags); } if ((bool)flags.ChangeMaxMP) { SetMPMax(flags.RedMageMaxMP, flags.WhiteMageMaxMP, flags.BlackMageMaxMP, flags.KnightMaxMP, flags.NinjaMaxMP); } if ((bool)flags.ShuffleAstos) { ShuffleAstos(flags, npcdata, talkroutines, rng); } if ((bool)flags.EnablePoolParty) { EnablePoolParty(flags, rng); } if ((bool)flags.MapCanalBridge) { EnableCanalBridge(); } if (flags.NoDanMode) { NoDanMode(); } SetProgressiveScaleMode(flags); if ((bool)flags.RandomizeClass) { RandomizeClass(rng, flags, oldItemNames); } if ((bool)flags.EnableRandomPromotions) { EnableRandomPromotions(flags, rng); } if (flags.DisableTentSaving) { CannotSaveOnOverworld(); } if (flags.DisableInnSaving) { CannotSaveAtInns(); } if (flags.PacifistMode && !flags.SpookyFlag) { PacifistEnd(talkroutines, npcdata, (bool)flags.EnemyTrapTiles || flags.EnemizerEnabled); } if (flags.ShopInfo) { ShopUpgrade(); } if (flags.SpookyFlag) { Spooky(talkroutines, npcdata, rng, flags); } if (flags.InventoryAutosort && !(preferences.RenounceAutosort)) { EnableInventoryAutosort(); } // We have to do "fun" stuff last because it alters the RNG state. // Back up Rng so that fun flags are uniform when different ones are selected uint funRngSeed = rng.Next(); RollCredits(rng); if (preferences.DisableDamageTileFlicker) { DisableDamageTileFlicker(); } if (preferences.ThirdBattlePalette) { UseVariablePaletteForCursorAndStone(); } if (preferences.PaletteSwap && !flags.EnemizerEnabled) { rng = new MT19337(funRngSeed); PaletteSwap(rng); } if (preferences.TeamSteak && !(bool)flags.RandomizeEnemizer) { TeamSteak(); } if (preferences.ChangeLute) { rng = new MT19337(funRngSeed); ChangeLute(rng); } rng = new MT19337(funRngSeed); HurrayDwarfFate(preferences.HurrayDwarfFate, npcdata, rng); if (preferences.Music != MusicShuffle.None) { rng = new MT19337(funRngSeed); ShuffleMusic(preferences.Music, rng); } if (preferences.DisableSpellCastFlash) { DisableSpellCastScreenFlash(); } npcdata.WriteNPCdata(this); talkroutines.WriteRoutines(this); talkroutines.UpdateNPCRoutines(this, npcdata); WriteSeedAndFlags(seed.ToHex(), Flags.EncodeFlagsText(flags)); ExtraTrackingAndInitCode(flags); }
public void MagisizeWeapons(MT19337 rng, bool balanced) { var Spells = GetSpells(); if (!balanced) { Spells.RemoveAll(spell => spell.Data[4] == 0); foreach (Item weapon in ItemLists.AllWeapons.Except(ItemLists.AllMagicItem).ToList()) { WriteItemSpellData(Spells.SpliceRandom(rng), weapon); } } else { var tieredSpells = new List <List <MagicSpell> > { Spells.GetRange(0, 16), Spells.GetRange(16, 16), Spells.GetRange(32, 16), Spells.GetRange(48, 16) }; var commonOdds = new List <int> { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2 }; var rareOdds = new List <int> { 0, 1, 1, 1, 2, 2, 2, 3, 3, 3 }; var legendaryOdds = new List <int> { 1, 2, 2, 2, 3, 3, 3, 3, 3, 3 }; for (int i = 0; i < 4; i++) { tieredSpells[i].RemoveAll(spell => spell.Data[4] == 0); } foreach (Item weapon in ItemLists.CommonWeaponTier) { var selectedTier = commonOdds.PickRandom(rng); while (tieredSpells[selectedTier].Count == 0) { selectedTier = commonOdds.PickRandom(rng); } WriteItemSpellData(tieredSpells[selectedTier].SpliceRandom(rng), weapon); } foreach (Item weapon in ItemLists.RareWeaponTier.Except(ItemLists.AllMagicItem).ToList()) { var selectedTier = rareOdds.PickRandom(rng); while (tieredSpells[selectedTier].Count == 0) { selectedTier = rareOdds.PickRandom(rng); } WriteItemSpellData(tieredSpells[selectedTier].SpliceRandom(rng), weapon); } foreach (Item weapon in ItemLists.LegendaryWeaponTier) { var selectedTier = legendaryOdds.PickRandom(rng); while (tieredSpells[selectedTier].Count == 0) { selectedTier = legendaryOdds.PickRandom(rng); } WriteItemSpellData(tieredSpells[selectedTier].SpliceRandom(rng), weapon); } foreach (Item weapon in ItemLists.UberTier) { var selectedTier = Rng.Between(rng, 0, 3); while (tieredSpells[selectedTier].Count == 0) { selectedTier = Rng.Between(rng, 0, 3); } WriteItemSpellData(tieredSpells[selectedTier].SpliceRandom(rng), weapon); } } }
public void MonsterInABox(MT19337 rng, Flags flags) { const int lut_TreasureOffset = 0x3100; const int BANK_SMINFO = 0x00; const int lut_TileSMsetProp = 0x8800; // BANK_SMINFO - page - 0x100 bytes x 8 (2 bytes per) // Replace OpenTreasureChest routine, see 11_8EC0_CheckTrap.asm PutInBank(0x1F, 0xDD78, Blob.FromHex("A9002003FEA645BD00B18561A9112003FE20A08E8A60")); // Check for trapped monster routine, see 11_8EC0_CheckTrap.asm PutInBank(0x11, 0x8EA0, Blob.FromHex("A5612080B1B045A645BD008FF03A856AA56148A9008561A9C0203D96A56A200096A903CD866BD0096820189668684C4396688561A97BC56AF00B20EE8E201896A2F08645604C38C920EE8E60AA6018A5612010B4A445B90062090499006260")); InsertDialogs(0x110, "Monster-in-a-box!"); // 0xC0 List <IRewardSource> validChests = new(); var chestMonsterList = new byte[0x100]; var treasureList = Get(lut_TreasureOffset, 0x100); // Select treasures var betterEquipmentList = ItemLists.UberTier.Concat(ItemLists.LegendaryArmorTier).Concat(ItemLists.LegendaryWeaponTier).Concat(ItemLists.RareArmorTier).Concat(ItemLists.RareWeaponTier); var RangeKeyItems = ItemLocations.AllTreasures.Where(x => !x.IsUnused && ItemLists.AllQuestItems.Contains((Item)treasureList[x.Address - lut_TreasureOffset])); var RangeShards = ItemLocations.AllTreasures.Where(x => !x.IsUnused && treasureList[x.Address - lut_TreasureOffset] == (int)Item.Shard); var RangeBetterTreasure = ItemLocations.AllTreasures.Where(x => !x.IsUnused && betterEquipmentList.Contains((Item)treasureList[x.Address - lut_TreasureOffset])); var RangeRandom = ItemLocations.AllTreasures.Where(x => !x.IsUnused && !RangeKeyItems.Contains(x) && !RangeShards.Contains(x) && !RangeBetterTreasure.Contains(x)); var RangeMasamune = ItemLocations.AllTreasures.Where(x => !x.IsUnused && treasureList[x.Address - lut_TreasureOffset] == (int)Item.Masamune); if (flags.TCKeyItems == TCOptions.Pooled) { validChests.AddRange(RangeKeyItems); } if (flags.TCShards == TCOptions.Pooled) { validChests.AddRange(RangeShards); } if (flags.TCBetterTreasure == TCOptions.Pooled) { validChests.AddRange(RangeBetterTreasure); } if (flags.TCExcludeCommons == false) { validChests.AddRange(RangeRandom); } if ((bool)flags.TCMasaGuardian == true) { validChests.RemoveAll(x => treasureList[x.Address - lut_TreasureOffset] == (int)Item.Masamune); } if (flags.TCProtectIncentives == true) { validChests.RemoveAll(x => GetIncentiveList(flags).Contains((Item)treasureList[x.Address - lut_TreasureOffset])); } int maxChests = 0; int guaranteedChests = ((flags.TCKeyItems == TCOptions.All) ? RangeKeyItems.Count() : 0) + ((flags.TCShards == TCOptions.All) ? RangeShards.Count() : 0) + ((flags.TCBetterTreasure == TCOptions.All) ? RangeBetterTreasure.Count() : 0) + (((bool)flags.TCMasaGuardian) ? RangeMasamune.Count() : 0) + (((bool)flags.TrappedChaos) ? 1 : 0); if (flags.TCChestCount == 13) { maxChests = Rng.Between(rng, 20, (240 - guaranteedChests)); } else if (flags.TCChestCount > 0) { maxChests = Math.Max(0, (flags.TCChestCount * 20) - guaranteedChests); } else { maxChests = 0; } // Get encounters const byte spookyZomBull = 0xB2; const byte spookyZombieD = 0xCB; const byte fightBahamut = 0xF1; List <byte> altEncountersList = Enumerable.Range(128, FirstBossEncounterIndex).Select(value => (byte)value).ToList(); altEncountersList.Add(0xFF); // IronGol if ((bool)flags.SpookyFlag) { altEncountersList.Remove(spookyZomBull); altEncountersList.Remove(spookyZombieD); } if ((bool)flags.FightBahamut) { altEncountersList.Remove(fightBahamut); } List <byte> encounters = new(); List <List <byte> > encountersGroup = new(); // Formations List for Vanilla Spikes & Local Formations List <byte> castleEncounters = new() { 0x84, 0x8C, 0x8D, 0x92 }; List <byte> caveEncounters = new() { 0x9D, 0x9C, 0x95, 0x97 }; List <byte> cardiaEncounters = new() { 0xAA, 0xB0, 0xCB, 0xCE, 0xD9 }; // Formations List for Vanilla Spikes List <byte> tofEncounters = new() { 0x10 }; List <byte> nwcastleEncounters = new() { 0x18, 0x1D }; List <byte> marshEncounters = new() { 0x1C, 0x15 }; List <byte> earthEncounters = new() { 0x21, 0x1E, 0x1F, 0x6E, 0x6F }; List <byte> volcEncounters = new() { 0x27, 0x28, 0x29, 0x2A }; List <byte> iceEncounters = new() { 0x2C, 0x2D, 0x2F, 0x30, 0x69, }; List <byte> ordealsEncounters = new() { 0x3F, 0x4F, 0x4B }; List <byte> waterfallEncounters = new() { 0x4A }; List <byte> seaEncounters = new() { 0x44, 0x45, 0x49, 0x4A }; List <byte> mirageEncounters = new() { 0x4E }; List <byte> tofrEncounters = new() { 0x46 }; if (flags.TCFormations == FormationPool.Random) { flags.TCFormations = (FormationPool)Rng.Between(rng, 0, 4); } switch (flags.TCFormations) { case FormationPool.AltFormationDist: List <List <byte> > baseEncounterList = new(); for (int i = 0; i < 3; i++) { baseEncounterList.Add(new List <byte>(altEncountersList)); baseEncounterList.Last().Shuffle(rng); } encounters = baseEncounterList.SelectMany(x => x).ToList(); break; case FormationPool.AltFormationRng: encounters = altEncountersList; break; case FormationPool.LocalFormations: encountersGroup = Get(ZoneFormationsOffset + (8 * 0x40), 8 * 0x40).Chunk(0x08).Select(x => x.ToBytes().Select(y => (byte)(y | 0x80)).ToList()).ToList(); encountersGroup[(int)MapId.ConeriaCastle1F] = castleEncounters; encountersGroup[(int)MapId.ElflandCastle] = castleEncounters; encountersGroup[(int)MapId.NorthwestCastle] = castleEncounters; encountersGroup[(int)MapId.CastleOfOrdeals1F] = castleEncounters; encountersGroup[(int)MapId.Cardia] = cardiaEncounters; encountersGroup[(int)MapId.BahamutsRoomB1] = cardiaEncounters; encountersGroup[(int)MapId.BahamutsRoomB2] = cardiaEncounters; encountersGroup[(int)MapId.DwarfCave] = caveEncounters; encountersGroup[(int)MapId.SardasCave] = caveEncounters; encountersGroup[(int)MapId.MatoyasCave] = caveEncounters; break; case FormationPool.VanillaSpikes: encountersGroup = new() { castleEncounters, castleEncounters, castleEncounters, castleEncounters, castleEncounters, castleEncounters, castleEncounters, castleEncounters, castleEncounters, castleEncounters, nwcastleEncounters, ordealsEncounters, tofEncounters, earthEncounters, volcEncounters, iceEncounters, cardiaEncounters, cardiaEncounters, waterfallEncounters, caveEncounters, caveEncounters, caveEncounters, marshEncounters, mirageEncounters, castleEncounters, ordealsEncounters, ordealsEncounters, marshEncounters, marshEncounters, earthEncounters, earthEncounters, earthEncounters, earthEncounters, volcEncounters, volcEncounters, volcEncounters, volcEncounters, iceEncounters, iceEncounters, cardiaEncounters, mirageEncounters, mirageEncounters, seaEncounters, seaEncounters, seaEncounters, seaEncounters, seaEncounters, mirageEncounters, mirageEncounters, mirageEncounters, mirageEncounters, mirageEncounters, tofrEncounters, tofrEncounters, tofrEncounters, tofrEncounters, tofrEncounters, tofrEncounters, tofrEncounters, tofrEncounters, caveEncounters, }; break; case FormationPool.Fiends: encounters = Enumerable.Range(0x77, 4).Select(value => (byte)value).ToList(); break; case FormationPool.Phantom: encounters = new List <byte> { 0x46 }; break; } int altFormationPosition = 0; var chestsMapLocations = ItemLocations.GetTreasuresMapLocation().ToDictionary(x => x.Key, x => ItemLocations.MapLocationToMapId[x.Value]); byte GetEncounter(int i) { if (flags.TCFormations == FormationPool.LocalFormations || flags.TCFormations == FormationPool.VanillaSpikes) { return(encountersGroup[(int)chestsMapLocations[i]].PickRandom(rng)); } else if (flags.TCFormations == FormationPool.AltFormationDist) { return(encounters[altFormationPosition++]); } else { return(encounters.PickRandom(rng)); } } // Process pool first if (maxChests > 0) { maxChests = Math.Min(maxChests, validChests.Count); for (int i = 0; i < maxChests; i++) { var selectedChest = validChests.SpliceRandom(rng).Address - lut_TreasureOffset; chestMonsterList[selectedChest] = GetEncounter(selectedChest); } } // Better Treasure if (flags.TCBetterTreasure == TCOptions.All) { for (int i = 0; i < 0x100; i++) { if (betterEquipmentList.Contains((Item)treasureList[i])) { chestMonsterList[i] = GetEncounter(i); } } } // Key Items if (flags.TCKeyItems == TCOptions.All) { for (int i = 0; i < 0x100; i++) { if (ItemLists.AllQuestItems.Contains((Item)treasureList[i])) { chestMonsterList[i] = GetEncounter(i); } } } // Shards if (flags.TCShards == TCOptions.All) { for (int i = 0; i < 0x100; i++) { if (treasureList[i] == (byte)Item.Shard) { chestMonsterList[i] = GetEncounter(i); } } } // Masamune if ((bool)flags.TCMasaGuardian) { for (int i = 0; i < 0x100; i++) { if (treasureList[i] == (byte)Item.Masamune) { chestMonsterList[i] = (byte)WarMECHFormationIndex; } } } // Chaos if ((bool)flags.TrappedChaos) { List <MapLocation> disallowedLocations = new() { MapLocation.TempleOfFiends1Room1, MapLocation.TempleOfFiends1Room2, MapLocation.TempleOfFiends2, MapLocation.TempleOfFiends3, MapLocation.TempleOfFiendsAir, MapLocation.TempleOfFiendsChaos, MapLocation.TempleOfFiendsEarth, MapLocation.TempleOfFiendsFire, MapLocation.TempleOfFiendsPhantom, MapLocation.TempleOfFiendsWater, MapLocation.MatoyasCave, MapLocation.DwarfCave }; validChests.RemoveAll(x => disallowedLocations.Contains(x.MapLocation)); // Replace a random chest if there's no valid location left for Chaos if (!validChests.Any()) { validChests = RangeRandom.ToList(); validChests.RemoveAll(x => disallowedLocations.Contains(x.MapLocation) || ((bool)flags.TCMasaGuardian == true && treasureList[x.Address - lut_TreasureOffset] == (int)Item.Masamune) || ((bool)flags.TCProtectIncentives == true && GetIncentiveList(flags).Contains((Item)treasureList[x.Address - lut_TreasureOffset]))); } chestMonsterList[validChests.SpliceRandom(rng).Address - lut_TreasureOffset] = ChaosFormationIndex; } //Spoilers /* * int count = 0; * for (int i = 0; i < 0x100; i++) * { * if (chestMonsterList[i] > 0) * { * count++; * Console.WriteLine(count + ". " + ItemLocations.AllTreasures.Where(x => (x.Address - lut_TreasureOffset) == i).First().Name + " -> " + Enum.GetName((Item)treasureList[i])); * } * } */ // Mark trapped chests if ((bool)flags.TCIndicator) { for (int i = 0; i < 8; i++) { for (int j = 0; j < 0x80; j++) { var tempTileProperties = GetFromBank(BANK_SMINFO, lut_TileSMsetProp + (i * 0x100) + (j * 2), 2); if ((tempTileProperties[0] & (byte)TilePropFunc.TP_SPEC_TREASURE) > 0 && (tempTileProperties[0] & (byte)TilePropFunc.TP_NOMOVE) > 0) { if (chestMonsterList[(int)tempTileProperties[1]] > 0) { TileSM temptile = new((byte)j, i, this); temptile.TileGraphic = new List <byte> { 0x2A, 0x7C, 0x3A, 0x3B }; temptile.Write(this); } } } } } // Insert trapped chest list PutInBank(0x11, 0x8F00, chestMonsterList); } public void SetChaosForMIAB(NPCdata npcdata) { npcdata.SetRoutine((ObjectId)0x1A, newTalkRoutines.Talk_4Orb); npcdata.GetTalkArray((ObjectId)0x1A)[(int)TalkArrayPos.dialogue_1] = 0x30; npcdata.GetTalkArray((ObjectId)0x1A)[(int)TalkArrayPos.dialogue_2] = 0x30; npcdata.GetTalkArray((ObjectId)0x1A)[(int)TalkArrayPos.dialogue_3] = 0x30; Data[MapObjGfxOffset + 0x18] = 0xF4; Data[MapObjGfxOffset + 0x19] = 0xF4; Data[MapObjGfxOffset + 0x1A] = 0xF4; PutInBank(0x00, 0xA000 + ((byte)MapId.TempleOfFiendsRevisitedChaos * 0x30) + 0x18, Blob.FromHex("000F1636000F1636")); Dictionary <int, string> newgarlanddialogue = new Dictionary <int, string>(); newgarlanddialogue.Add(0x2E, "That's right, it's me,\nBurtReynoldz. Didn't\nexpect to see me, right?"); newgarlanddialogue.Add(0x2F, "Many moons ago I managed\nto run away from Chaos.\nAnd lo and behold,\nI BECAME Chaos. I took\nhis place."); newgarlanddialogue.Add(0x30, "Okay, I won't fight you.\nSome say you can find\nthe other Chaos hidden\nsomewhere in a chest.\nGood luck!"); InsertDialogs(newgarlanddialogue); } public static List <Item> GetIncentiveList(Flags flags) { var incentivePool = new List <Item>(); if (flags.IncentivizeMasamune ?? false) { incentivePool.Add(Item.Masamune); } if (flags.IncentivizeKatana ?? false) { incentivePool.Add(Item.Katana); } if (flags.IncentivizeVorpal ?? false) { incentivePool.Add(Item.Vorpal); } if (flags.IncentivizeDefCastWeapon ?? false) { incentivePool.Add(Item.Defense); } if (flags.IncentivizeOffCastWeapon ?? false) { incentivePool.Add(Item.ThorHammer); } if (flags.IncentivizeOpal ?? false) { incentivePool.Add(Item.Opal); } if (flags.IncentivizeOtherCastArmor ?? false) { incentivePool.Add(Item.PowerGauntlets); } if (flags.IncentivizePowerRod ?? false) { incentivePool.Add(Item.PowerRod); } if (flags.IncentivizeDefCastArmor ?? false) { incentivePool.Add(Item.WhiteShirt); } if (flags.IncentivizeOffCastArmor ?? false) { incentivePool.Add(Item.BlackShirt); } if (flags.IncentivizeRibbon ?? false) { incentivePool.Add(Item.Ribbon); } if (flags.IncentivizeXcalber ?? false) { incentivePool.Add(Item.Xcalber); } if (flags.IncentivizeSlab ?? false) { incentivePool.Add(Item.Slab); } if (flags.IncentivizeRuby ?? false) { incentivePool.Add(Item.Ruby); } if (flags.IncentivizeFloater ?? false) { incentivePool.Add(Item.Floater); } if (flags.IncentivizeTnt ?? false) { incentivePool.Add(Item.Tnt); } if (flags.IncentivizeCrown ?? false) { incentivePool.Add(Item.Crown); } if (flags.IncentivizeTail ?? false) { incentivePool.Add(Item.Tail); } if (flags.IncentivizeAdamant ?? false) { incentivePool.Add(Item.Adamant); } if (flags.IncentivizeCrystal ?? false) { incentivePool.Add(Item.Crystal); } if (flags.IncentivizeBottle ?? false) { incentivePool.Add(Item.Bottle); } if (flags.IncentivizeHerb ?? false) { incentivePool.Add(Item.Herb); } if (flags.IncentivizeKey ?? false) { incentivePool.Add(Item.Key); } if (flags.IncentivizeOxyale ?? false) { incentivePool.Add(Item.Oxyale); } if (flags.IncentivizeLute ?? false) { incentivePool.Add(Item.Lute); } if (flags.IncentivizeRod ?? false) { incentivePool.Add(Item.Rod); } if (flags.IncentivizeCube ?? false) { incentivePool.Add(Item.Cube); } if (flags.IncentivizeChime ?? false) { incentivePool.Add(Item.Chime); } if (flags.IncentivizeBridge ?? false) { incentivePool.Add(Item.Bridge); } if (flags.IncentivizeShip ?? false) { incentivePool.Add(Item.Ship); } if (flags.IncentivizeCanoe ?? false) { incentivePool.Add(Item.Canoe); } if (flags.IncentivizeCanal ?? false) { incentivePool.Add(Item.Canal); } return(incentivePool.ToList()); } } }