|
| 1 | +-- Script to add unknown crafting recipes to the player's civ. |
| 2 | +--[====[ |
| 3 | +add-recipe |
| 4 | +========== |
| 5 | +Adds unknown weapon and armor crafting recipes to your civ. |
| 6 | +E.g. some civilizations never learn to craft high boots. This script can |
| 7 | +help with that, and more. Only weapons and armor are currently supported; |
| 8 | +things such as instruments are not. Available options: |
| 9 | +
|
| 10 | +* ``add-recipe all`` adds *all* available weapons and armor, including exotic items |
| 11 | + like blowguns, two-handed swords, and capes. |
| 12 | +
|
| 13 | +* ``add-recipe native`` adds only native (but unknown) crafting recipes. Civilizations |
| 14 | + pick randomly from a pool of possible recipes, which means not all civs get |
| 15 | + high boots, for instance. This command gives you all the recipes your |
| 16 | + civilisation could have gotten. |
| 17 | + |
| 18 | +* ``add-recipe single <item token>`` adds a single item by the given |
| 19 | + item token. For example, ``add-recipe single SHOES:ITEM_SHOES_BOOTS``. |
| 20 | +]====] |
| 21 | + |
| 22 | +local itemDefs = df.global.world.raws.itemdefs |
| 23 | +local resources = df.historical_entity.find(df.global.ui.civ_id).resources |
| 24 | +local civ = df.historical_entity.find(df.global.ui.civ_id).entity_raw |
| 25 | + |
| 26 | +if (resources == nil) then |
| 27 | + qerror("Could not find entity resources") |
| 28 | +elseif (itemDefs == nil) then |
| 29 | + qerror("Could not find item raws!") |
| 30 | +elseif (civ == nil) then |
| 31 | + qerror("Could not find civilization type!") |
| 32 | +end |
| 33 | + |
| 34 | +--array that categorises the various containers we need to access per type |
| 35 | +--each type is represented by an array with the following elements: |
| 36 | + --1: the currently known recipes to the player civ |
| 37 | + --2: the native (non-exotic) recipes to the player civ |
| 38 | + --3: all possible recipes including exotic |
| 39 | +local categories = { |
| 40 | + weapon = {resources.weapon_type, civ.equipment.weapon_id, itemDefs.weapons }, |
| 41 | + shield = {resources.shield_type, civ.equipment.shield_id, itemDefs.shields }, |
| 42 | + ammo = {resources.ammo_type, civ.equipment.ammo_id, itemDefs.ammo }, |
| 43 | + armor = {resources.armor_type, civ.equipment.armor_id, itemDefs.armor }, |
| 44 | + gloves = {resources.gloves_type, civ.equipment.gloves_id, itemDefs.gloves }, |
| 45 | + shoes = {resources.shoes_type, civ.equipment.shoes_id, itemDefs.shoes }, |
| 46 | + helm = {resources.helm_type, civ.equipment.helm_id, itemDefs.helms }, |
| 47 | + pants = {resources.pants_type, civ.equipment.pants_id, itemDefs.pants } |
| 48 | +} |
| 49 | + |
| 50 | +local diggers = resources.digger_type |
| 51 | + |
| 52 | +function checkKnown(known, itemType) |
| 53 | + --checks if the item with the given subtype is already known to the civ |
| 54 | + --params: |
| 55 | + --known: the resources field for the civ |
| 56 | + --itemType: the item subtype we're checking |
| 57 | + for _, id in ipairs(known) do |
| 58 | + if id == itemType then |
| 59 | + return true |
| 60 | + end |
| 61 | + end |
| 62 | + return false |
| 63 | +end |
| 64 | + |
| 65 | +function checkNative(native, itemType) |
| 66 | + --checks if the given itemtype is native to the player's civ |
| 67 | + --params: |
| 68 | + --native: the list of native item types |
| 69 | + --itemType: the item subtype we're checking |
| 70 | + for _, id in ipairs(native) do |
| 71 | + if id == itemType then |
| 72 | + return true |
| 73 | + end |
| 74 | + end |
| 75 | + return false |
| 76 | +end |
| 77 | + |
| 78 | +function addItems(category, exotic) |
| 79 | + --makes all available recipes of the given category known to the player's civ |
| 80 | + --params: |
| 81 | + --category: the category of items we're adding |
| 82 | + --exotic: whether to add exotic items |
| 83 | + --returns: list of item objects that were added |
| 84 | + known = category[1] |
| 85 | + native = category[2] |
| 86 | + all = category[3] |
| 87 | + added = {} |
| 88 | + |
| 89 | + for _, item in ipairs(all) do |
| 90 | + subtype = item.subtype |
| 91 | + itemOk = false |
| 92 | + |
| 93 | + --check if it's a training weapon |
| 94 | + t1, t2 = pcall(function () return item.flags.TRAINING == false end) |
| 95 | + training = not(not t1 or t2) |
| 96 | + |
| 97 | + --we don't want procedural items with adjectives such as "wavy spears" |
| 98 | + --(because they don't seem to be craftable even if added) |
| 99 | + --nor do we want known items or training items (because adding training |
| 100 | + --items seems to allow them to be made out of metals) |
| 101 | + if (item.adjective == "" and not training and not checkKnown(known, subtype)) then |
| 102 | + itemOk = true |
| 103 | + end |
| 104 | + |
| 105 | + if (not exotic and not checkNative(native, subtype)) then |
| 106 | + itemOk = false |
| 107 | + end |
| 108 | + |
| 109 | + --check that the weapon we're adding is not already known to the civ as |
| 110 | + --a digging implement so picks don't get duplicated |
| 111 | + if (checkKnown(diggers, subtype)) then |
| 112 | + itemOk = false |
| 113 | + end |
| 114 | + |
| 115 | + if (itemOk) then |
| 116 | + known:insert('#', subtype) |
| 117 | + table.insert(added, item) |
| 118 | + end |
| 119 | + end |
| 120 | + |
| 121 | + return added |
| 122 | +end |
| 123 | + |
| 124 | + |
| 125 | +function printItems(itemList) |
| 126 | + for _, v in ipairs(added) do |
| 127 | + print("Added recipe " .. v.id .. " (" .. v.name .. ")") |
| 128 | + end |
| 129 | +end |
| 130 | + |
| 131 | +function addAllItems(exotic) |
| 132 | + printItems(addItems(categories.weapon, exotic)) |
| 133 | + printItems(addItems(categories.shield, exotic)) |
| 134 | + printItems(addItems(categories.ammo, exotic)) |
| 135 | + printItems(addItems(categories.armor, exotic)) |
| 136 | + printItems(addItems(categories.gloves, exotic)) |
| 137 | + printItems(addItems(categories.shoes, exotic)) |
| 138 | + printItems(addItems(categories.helm, exotic)) |
| 139 | + printItems(addItems(categories.pants, exotic)) |
| 140 | +end |
| 141 | + |
| 142 | +function addSingleItem(itemstring) |
| 143 | + itemType, itemId = string.match(itemstring, "(.*):(.*)") |
| 144 | + if (itemType == nil or itemId == nil) then return end |
| 145 | + category = categories[string.lower(itemType)] |
| 146 | + if (category == nil) then return end |
| 147 | + known = category[1] |
| 148 | + all = category[3] |
| 149 | + |
| 150 | + addedItem = nil |
| 151 | + --assume the user knows what they're doing, so no need for sanity checks |
| 152 | + for _, item in ipairs(all) do |
| 153 | + if (item.id == itemId) then |
| 154 | + known:insert('#', item.subtype) |
| 155 | + addedItem = item |
| 156 | + break |
| 157 | + end |
| 158 | + end |
| 159 | + |
| 160 | + if (addedItem ~= nil) then |
| 161 | + print("Added recipe " .. addedItem.id .. " (" .. addedItem.name .. ")") |
| 162 | + end |
| 163 | +end |
| 164 | + |
| 165 | +local args = {...} |
| 166 | +local cmd = args[1] |
| 167 | +if (cmd == "all") then |
| 168 | + addAllItems(true) |
| 169 | +elseif (cmd == "native") then |
| 170 | + addAllItems(false) |
| 171 | +elseif (cmd == "single") then |
| 172 | + addSingleItem(args[2]) |
| 173 | +else |
| 174 | + print("Available options:\n" |
| 175 | + .."all: adds all supported crafting recipes.\n" |
| 176 | + .."native: adds only unknown native recipes (eg. high boots for " |
| 177 | + .."some dwarves)\n" |
| 178 | + .."single: adds a specific item by itemstring (eg. " |
| 179 | + .."SHOES:ITEM_SHOES_BOOTS)") |
| 180 | +end |
0 commit comments