static string RandomBaseBlueprintId(ItemTypeData selectedItemData) { string[] guids; switch (selectedItemData.Type) { case UsableItemType.Scroll: guids = new string[] { "17959707c7004bd4abad2983f8a4af66", "be452dba5acdd9441841d2189e1ae55a", "fbdd06f0414c3ef458eb4b2a8072e502", "358ee9cb540a9af4e9bc76cc1af62e86", "e5700c45eb88bdd40a324e10d3de4a07", "33ea3e3e578d4db4c8e57632fca4c9ec", "68d5aa212b7323e4e95e0fe731ea50cf" }; break; case UsableItemType.Wand: guids = new string[] { "4bf15a56d9ade8f47bf93fda7aa84d8b", "85a4ff725c5236b4f9e0adb17fb64e2b", "ce90a6251242af745b3daa56f84a5fe5", "a20d40dc97457f041a2c29bdb2e2efe8", "229fcbd357a9d6b48bc63b79188cdbd6", "021b4a12739c59541922e3857f3fb3a4", "394d337603392eb4c817994c45877fc0", "8cb627da1a91069428ce87d9a114cdd6", "85a4ff725c5236b4f9e0adb17fb64e2b" }; break; default: return(null); } return(guids[random.Next(guids.Length)]); }
static void OnGui(UnityModManager.ModEntry modEntry) { if (!modEnabled) { GUILayout.BeginHorizontal(); GUILayout.Label("The mod is disabled. Loading saved games with custom items will cause them to revert to regular versions."); GUILayout.EndHorizontal(); return; } UnitEntityData mainCharacterValue = Game.Instance?.Player?.MainCharacter.Value; if (mainCharacterValue == null || !mainCharacterValue.IsViewActive || ( Game.Instance.CurrentMode != GameModeType.Default && Game.Instance.CurrentMode != GameModeType.GlobalMap && Game.Instance.CurrentMode != GameModeType.FullScreenUi && Game.Instance.CurrentMode != GameModeType.Pause && Game.Instance.CurrentMode != GameModeType.EscMode && Game.Instance.CurrentMode != GameModeType.Rest && Game.Instance.CurrentMode != GameModeType.Kingdom )) { GUILayout.BeginHorizontal(); GUILayout.Label("Item crafting is not available in this game state."); GUILayout.EndHorizontal(); return; } GUILayout.BeginHorizontal(); GUILayout.Label($"Number of custom Craft Magic Items blueprints loaded: {customBlueprintGUIDs.Count}"); GUILayout.EndHorizontal(); RenderSelection(ref selectedItemTypeIndex, "Item Type: ", itemTypeNames, 3); ItemTypeData selectedType = itemTypeData[selectedItemTypeIndex]; // Only allow remote companions if in Oleg's (in Act I) or your capital (in Act II+) bool remote = Game.Instance.CurrentlyLoadedArea.IsCapital; List <UnitEntityData> partySpellCasters = (from entity in UIUtility.GetGroup(remote) where entity.IsPlayerFaction && !entity.Descriptor.IsPet && entity.Descriptor.Spellbooks != null && entity.Descriptor.Spellbooks.Any() && !entity.Descriptor.State.IsFinallyDead select entity).ToList <UnitEntityData>(); if (partySpellCasters.Count == 0) { GUILayout.BeginHorizontal(); GUILayout.Label("No characters with spells available."); GUILayout.EndHorizontal(); return; } GUILayout.BeginVertical(); string[] partyNames = (from entity in partySpellCasters select entity.CharacterName).ToArray <string>(); RenderSelection(ref selectedSpellcasterIndex, "Caster: ", partyNames, 8); UnitEntityData caster = partySpellCasters[selectedSpellcasterIndex]; List <Spellbook> spellbooks = (from book in caster.Descriptor.Spellbooks where book.CasterLevel > 0 select book).ToList <Spellbook>(); if (spellbooks.Count == 0) { GUILayout.BeginHorizontal(); GUILayout.Label($"{caster.CharacterName} is not yet able to cast spells."); GUILayout.EndHorizontal(); } else if (spellbooks.Count == 1) { selectedSpellbookIndex = 0; } else { string[] spellbookNames = (from book in spellbooks select book.Blueprint.Name.ToString()).ToArray <string>(); RenderSelection(ref selectedSpellbookIndex, "Class: ", spellbookNames, 10); } if (selectedSpellbookIndex < spellbooks.Count) { Spellbook spellbook = spellbooks[selectedSpellbookIndex]; int maxLevel = Math.Min(spellbook.MaxSpellLevel, selectedType.MaxSpellLevel); string[] spellLevelNames = (from index in Enumerable.Range(0, maxLevel) select $"Level {index}").ToArray <string>(); RenderSelection(ref selectedSpellLevelIndex, "Select spell level: ", spellLevelNames, 10); int spellLevel = selectedSpellLevelIndex; IEnumerable <AbilityData> spellOptions = null; if (spellLevel == 0) { // Cantrips/Orisons are special. spellOptions = spellbook.GetKnownSpells(spellLevel); } else if (spellbook.Blueprint.Spontaneous) { // Spontaneous spellcaster if (spellbook.GetSpontaneousSlots(spellLevel) > 0) { GUILayout.BeginHorizontal(); GUILayout.Label($"{caster.CharacterName} can cast {spellbook.GetSpontaneousSlots(spellLevel)} more level {spellLevel} spells today."); GUILayout.EndHorizontal(); spellOptions = spellbook.GetKnownSpells(spellLevel); } } else { // Prepared spellcaster spellOptions = (from slot in spellbook.GetMemorizedSpells(spellLevel) where slot.Spell != null && slot.Available select slot.Spell); } if (spellOptions == null || !spellOptions.Any()) { GUILayout.BeginHorizontal(); GUILayout.Label($"{caster.CharacterName} cannot currently cast any level {spellLevel} spells."); GUILayout.EndHorizontal(); } else { int minCasterLevel = Math.Max(1, 2 * spellLevel - 1); if (minCasterLevel < spellbook.CasterLevel) { selectedCasterLevel = Mathf.RoundToInt(Mathf.Clamp(selectedCasterLevel, minCasterLevel, spellbook.CasterLevel)); GUILayout.BeginHorizontal(); GUILayout.Label("Caster level: ", GUILayout.ExpandWidth(false)); selectedCasterLevel = Mathf.RoundToInt(GUILayout.HorizontalSlider(selectedCasterLevel, minCasterLevel, spellbook.CasterLevel, GUILayout.Width(300))); GUILayout.Label($"{selectedCasterLevel}", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } else { selectedCasterLevel = minCasterLevel; GUILayout.BeginHorizontal(); GUILayout.Label($"Caster level: {selectedCasterLevel}", GUILayout.ExpandWidth(false)); GUILayout.EndHorizontal(); } foreach (AbilityData spell in spellOptions.OrderBy(spell => spell.Name).Distinct()) { if (spell.MetamagicData != null && spell.MetamagicData.NotEmpty) { GUILayout.Label($"Cannot craft {itemTypeNames[selectedItemTypeIndex]} of {spell.Name} with metamagic applied."); } else if (spell.Blueprint.HasVariants) { // Spells with choices (e.g. Protection from Alignment, which can be Protection from Evil, Good, Chaos or Law) foreach (BlueprintAbility variant in spell.Blueprint.Variants) { RenderCraftItemControl(spellbook, spell, variant, spellLevel, selectedCasterLevel); } } else { RenderCraftItemControl(spellbook, spell, spell.Blueprint, spellLevel, selectedCasterLevel); } } } GUILayout.BeginHorizontal(); GUILayout.Label($"Current Money: {Game.Instance.Player.Money}"); GUILayout.EndHorizontal(); } GUILayout.EndVertical(); }
static void RenderCraftItemControl(Spellbook spellbook, AbilityData spell, BlueprintAbility spellBlueprint, int spellLevel, int casterLevel) { ItemTypeData selectedItemData = itemTypeData[selectedItemTypeIndex]; List <BlueprintItemEquipment> itemBlueprintList = FindItemBlueprintForSpell(spellBlueprint, selectedItemData.Type); if (itemBlueprintList == null && selectedItemData.Type == UsableItemType.Potion) { GUILayout.Label($"There is no {itemTypeNames[selectedItemTypeIndex]} of {spellBlueprint.Name}"); return; } BlueprintItemEquipment existingItemBlueprint = (itemBlueprintList == null) ? null : itemBlueprintList.Find(bp => bp.SpellLevel == spellLevel && bp.CasterLevel == casterLevel); int goldCost = selectedItemData.BaseItemGoldCost * Math.Max(1, spellLevel) * casterLevel / (spellLevel == 0 ? 8 : 4); bool canAfford = (Game.Instance.Player.Money >= goldCost); string cost = $"{goldCost} gold{(canAfford ? "" : " (which you can't afford)")}"; if (spell.RequireMaterialComponent) { int count = spellBlueprint.MaterialComponent.Count * selectedItemData.Charges; cost += $" and {count} {spellBlueprint.MaterialComponent.Item.Name}"; if (!Game.Instance.Player.Inventory.Contains(spellBlueprint.MaterialComponent.Item, count)) { canAfford = false; cost += " (which you don't have)"; } } string custom = (itemBlueprintList == null || existingItemBlueprint == null || existingItemBlueprint.AssetGuid.Length > vanillaAssetIdLength) ? "(custom) " : ""; if (!canAfford) { GUILayout.Label($"Craft {custom}{itemTypeNames[selectedItemTypeIndex]} of {spellBlueprint.Name} for {cost}"); } else if (GUILayout.Button($"Craft {custom}{itemTypeNames[selectedItemTypeIndex]} of {spellBlueprint.Name} for {cost}", GUILayout.ExpandWidth(false))) { Game.Instance.Player.SpendMoney(goldCost); spell.SpendFromSpellbook(); if (spell.RequireMaterialComponent) { int count = spellBlueprint.MaterialComponent.Count * selectedItemData.Charges; Game.Instance.Player.Inventory.Remove(spellBlueprint.MaterialComponent.Item, count); } string blueprintId = null; if (itemBlueprintList == null) { // Create a custom blueprint with casterLevel, spellLevel and spellId blueprintId = BuildCustomItemGuid(RandomBaseBlueprintId(selectedItemData), casterLevel, spellLevel, spell.Blueprint.AssetGuid); } else if (existingItemBlueprint == null) { // Create a custom blueprint with casterLevel and optionally SpellLevel blueprintId = BuildCustomItemGuid(itemBlueprintList[0].AssetGuid, casterLevel, itemBlueprintList[0].SpellLevel == spellLevel ? -1 : spellLevel); } else { // Use an existing blueprint blueprintId = existingItemBlueprint.AssetGuid; } BlueprintItemEquipment actualBlueprint = (BlueprintItemEquipment)ResourcesLibrary.TryGetBlueprint(blueprintId); ItemEntity item = ItemsEntityFactory.CreateEntity(actualBlueprint); item.IsIdentified = true; // Mark the item as identified. item.Charges = selectedItemData.Charges; // Set the charges, since wand blueprints have random values. Game.Instance.Player.Inventory.Add(item); if (existingItemBlueprint == null) { AddItemBlueprintForSpell(spell.Blueprint, selectedItemData.Type, actualBlueprint); } switch (selectedItemData.Type) { case UsableItemType.Scroll: Game.Instance.UI.Common.UISound.Play(UISoundType.NewInformation); break; case UsableItemType.Potion: Game.Instance.UI.Common.UISound.PlayItemSound(SlotAction.Take, item, false); break; case UsableItemType.Wand: Game.Instance.UI.Common.UISound.Play(UISoundType.SettlementBuildStart); break; } } }