Advertisement
Medar

Crawl 0.15 autopickup script

Aug 27th, 2014
809
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 20.44 KB | None | 0 0
  1. -- Autopickup script for DCSS 0.15
  2.  
  3. -- TL;DR if you pick up armour or weapon that you think shouldn't have been
  4. -- picked up, add an inscription _lock to your current one (with { key)
  5.  
  6. -- Picks up:
  7. -- all artefacts
  8. -- one blowgun and one buckler per game (shield for troll/ogre)
  9. -- needles if blowgun hasn't been found yet or one is in inventory
  10. -- armour for empty auxillary slots
  11. -- ego armour/shield/weapon that matches current items
  12. -- * can be disabled with _noego inscription
  13. -- * for shields also heavier versions are picked up
  14. -- better weapons of the same school than anything in your inventory
  15. -- * can be disabled with _noup inscription
  16. -- * going from one handed to two handed can be enabled with _2h inscription
  17. -- items that have better plusses and the same brand as the current item (Ash)
  18. -- * brand can be ignored with _plain inscription
  19.  
  20. -- Options with default values:
  21. -- autopickup_artefacts = true
  22. -- autopickup_blowgun = true
  23. -- autopickup_buckler = true
  24. -- autopickup_upgrade_weapon = true
  25.  
  26. -- Inscriptions:
  27. -- _noego       don't pick up matching ego items
  28. -- _noup        don't upgrade this item
  29. -- _lock        shortcut for both _noego and _noup
  30. -- _plain       don't consider this item to have an ego or be an artefact
  31. -- _2h          allow replacing this weapon with a two handed version
  32. --              implies _up
  33. -- _noart       don't pick up artefacts of this type
  34.  
  35. -- TODO:
  36. -- fix small race two handed weapon detection
  37. -- consider all carried armour
  38. -- add inscriptions to picked up items in certain cases (_2h, _noup)
  39.  
  40. local AUTOPICKUP_ARTEFACTS = true
  41. local AUTOPICKUP_BLOWGUN = true
  42. local AUTOPICKUP_BUCKLER = true
  43. local AUTOPICKUP_UPGRADE_WEAPON = true
  44.  
  45. local initialized = false
  46. local need_inventory_check = false
  47.  
  48. local body_armour_data = {
  49.     { "robe",                   2,  0, false },
  50.     { "leather armour",         3,  4, false },
  51.     { "ring mail",              5,  7, false },
  52.     { "scale mail",             6, 11, false },
  53.     { "chain mail",             8, 15, false },
  54.     { "plate armour",          10, 18, false },
  55.     { "crystal plate armour",  14, 24, false },
  56.     { "animal skin",            2,  0, false },
  57.     { "troll leather armour",   4,  4, true },
  58.     { "steam dragon armour",    5,  0, true },
  59.     { "mottled dragon armour",  6,  5, true },
  60.     { "swamp dragon armour",    7,  7, true },
  61.     { "fire dragon armour",     8, 11, true },
  62.     { "ice dragon armour",      9, 11, true },
  63.     { "pearl dragon armour",   10, 11, true },
  64.     { "storm dragon armour",   10, 17, true },
  65.     { "gold dragon armour",    12, 25, true },
  66.     { "troll hide",             4,  4, true },
  67.     { "steam dragon hide",      5,  0, true },
  68.     { "mottled dragon hide",    6,  5, true },
  69.     { "swamp dragon hide",      7,  7, true },
  70.     { "fire dragon hide",       8, 11, true },
  71.     { "ice dragon hide",        9, 11, true },
  72.     { "pearl dragon hide",     10, 11, true },
  73.     { "storm dragon hide",     10, 17, true },
  74.     { "gold dragon hide",      12, 25, true } }
  75. -- scythe handled the same as halberd
  76. local twohanded_weapon_list = { "great sword", "claymore", "battleaxe",
  77.     "executioner's axe", "dire flail", "great mace", "giant club",
  78.     "giant spiked club", "halberd", "glaive", "bardiche", "quaterstaff",
  79.     "lajatang" }
  80. local spriggan_onehanded_weapon_list = { "dagger", "short sword", "cutlass",
  81.     "quick blade", "club", "whip", "mace", "flail", "demon whip", "falchion",
  82.     "hand axe" }
  83. local weapon_upgrade_table = {
  84.     { "dagger", "short sword", "cutlass", "quick blade" },
  85.     { "falchion", "long sword", "blessed falchion", "scimitar",
  86.       "blessed long sword", "blessed scimitar", "demon blade", "bastard sword",
  87.       "eudemon blade", "great sword", "blessed bastard sword",
  88.       "blessed great sword", "claymore", "blessed claymore" },
  89.     { "hand axe", "war axe", "broad axe", "battleaxe", "executioner's axe" },
  90.     { "club", "whip", "hammer", "mace", "flail", "morningstar", "demon whip",
  91.       "dire flail", "sacred scourge", "eveningstar", "great mace",
  92.       "giant club", "giant spiked club" },
  93.     { "spear", "trident", "halberd", "demon trident", "trishula", "glaive",
  94.       "bardiche" },
  95.     { "quarterstaff", "lajatang" },
  96.     { "hunting sling", "greatsling" },
  97.     { "shortbow", "longbow" },
  98.     { "hand crossbow", "arbalest", "triple crossbow" },
  99.     { "blowgun" } }
  100.  
  101. -- HELPER FUNCTIONS
  102.  
  103. local function Set(list)
  104.     local set = {}
  105.     for _, l in ipairs(list) do set[l] = true end
  106.     return set
  107. end
  108.  
  109. local function control(c)
  110.     return string.char(string.byte(c) - string.byte('a') + 1)
  111. end
  112.  
  113. local function stash_search(search)
  114.     if search:find("dropped") and you.turns() == 0 then
  115.         return false
  116.     end
  117.     crawl.process_keys(control('f') .. search .. "\r" .. string.char(27)
  118.                        .. string.char(27))
  119.     crawl.flush_input()
  120.     return not crawl.messages(2):find("Can't find anything matching that.")
  121. end
  122.  
  123. local function warning(message)
  124.     --crawl.mpr("Script error: " .. message)
  125. end
  126.  
  127. local function inventory()
  128.     return iter.invent_iterator:new(items.inventory())
  129. end
  130.  
  131. local function upgrade_list_for_weapon(name)
  132.     if name == "scythe" then
  133.         name = "halberd"
  134.     end
  135.     local found
  136.     for row = 1, #weapon_upgrade_table do
  137.         for col = 1, #weapon_upgrade_table[row] do
  138.             if name == weapon_upgrade_table[row][col] then
  139.                 found = { row=row, col=col }
  140.                 break
  141.             end
  142.         end
  143.         if found then
  144.             break
  145.         end
  146.     end
  147.     local from = {}
  148.     local to = {}
  149.     if not found then
  150.         warning("No upgrade data for weapon: " .. name)
  151.     else
  152.         for col = 1, found.col - 1 do
  153.             from[weapon_upgrade_table[found.row][col]] = true
  154.             if weapon_upgrade_table[found.row][col] == "halberd" then
  155.                 from["scythe"] = true
  156.             end
  157.         end
  158.         for col = found.col, #weapon_upgrade_table[found.row] do
  159.             to[weapon_upgrade_table[found.row][col]] = true
  160.             if weapon_upgrade_table[found.row][col] == "halberd" then
  161.                 to["scythe"] = true
  162.             end
  163.         end
  164.     end
  165.     return from, to
  166. end
  167.  
  168. local function plus_or_0(item)
  169.     if item.plus == nil then
  170.         return 0
  171.     else
  172.         return item.plus
  173.     end
  174. end
  175.  
  176. local function basename(item)
  177.     if item.artefact then
  178.         local name = item.name("base")
  179.         if item.fully_identified then
  180.             return name:gsub(" \".-\"$", ""):gsub(" of .-$", "")
  181.         else
  182.             return name:gsub("^.- ", "")
  183.         end
  184.     else
  185.         return item.name("base")
  186.     end
  187. end
  188.  
  189. local function i_subtype(item)
  190.     if item.class(true) == "jewellery" then
  191.         if basename(item):find("amulet") then
  192.             return "amulet"
  193.         else
  194.             return "ring"
  195.         end
  196.     end
  197.     return item.subtype()
  198. end
  199.  
  200. local function er(item)
  201.     if item.class(true) ~= "armour" then return nil end
  202.     local name = basename(item)
  203.     local subtype = i_subtype(item)
  204.     if subtype == "shield" then
  205.         if name == "buckler" then
  206.             return 1
  207.         elseif name == "shield" then
  208.             return 3
  209.         elseif name == "large shield" then
  210.             return 5
  211.         else
  212.             warning("Unknown shield: " .. name)
  213.             return -1
  214.         end
  215.     elseif subtype == "body" then
  216.         if body_armour_data[name] ~= nil then
  217.             return body_armour_data[name].er
  218.         else
  219.             warning("Unknown body armour: " .. name)
  220.             return -1
  221.         end
  222.     else
  223.         if name:find("barding") then
  224.             return 6
  225.         else
  226.             return 0
  227.         end
  228.     end
  229. end
  230.  
  231. -- also does SH
  232. local function base_ac(item)
  233.     if item.class(true) ~= "armour" then return nil end
  234.     local name = basename(item)
  235.     local subtype = i_subtype(item)
  236.     if subtype == "shield" then
  237.         if name == "buckler" then
  238.             return 5
  239.         elseif name == "shield" then
  240.             return 8
  241.         elseif name == "large shield" then
  242.             return 13
  243.         else
  244.             warning("Unknown shield: " .. name)
  245.             return 99
  246.         end
  247.     elseif subtype == "body" then
  248.         if body_armour_data[name] ~= nil then
  249.             return body_armour_data[name].ac
  250.         else
  251.             return 99
  252.         end
  253.     else
  254.         if name:find("barding") then
  255.             return 4
  256.         elseif name == "hat" then
  257.             return 0
  258.         else
  259.             return 1
  260.         end
  261.     end
  262. end
  263.  
  264. -- also does SH
  265. local function estimate_ac(item)
  266.     if item.class(true) ~= "armour" then return nil end
  267.     return base_ac(item) + plus_or_0(item)
  268. end
  269.  
  270. local function is_hide(item)
  271.     if item.class(true) ~= "armour" or i_subtype(item) ~= "armour" then
  272.         return nil
  273.     end
  274.     return basename(item):find("hide")
  275. end
  276.  
  277. local function inventory_match(func, result)
  278.     for item in inventory() do
  279.         if func(item) == result then
  280.             return item
  281.         end
  282.     end
  283.     return nil
  284. end
  285.  
  286. local function inscription_no_ego(item)
  287.     return item.name("qual"):find("_noego") ~= nil
  288.            or item.name("qual"):find("_lock") ~= nil
  289. end
  290.  
  291. local function inscription_no_upgrade(item)
  292.     return item.name("qual"):find("_noup") ~= nil
  293.            or item.name("qual"):find("_lock") ~= nil
  294. end
  295.  
  296. local function inscription_plain(item)
  297.     return item.name("qual"):find("_plain") ~= nil
  298. end
  299.  
  300. local function inscription_twohanded(item)
  301.     return item.name("qual"):find("_2h") ~= nil
  302. end
  303.  
  304. local function inscription_no_artefact(item)
  305.     return item.name("qual"):find("_noart") ~= nil
  306. end
  307.  
  308. local function is_upgradable(item)
  309.     if item.class(true) == "weapon" and AUTOPICKUP_UPGRADE_WEAPON then
  310.         return not inscription_no_upgrade(item)
  311.     end
  312.     return false
  313. end
  314.  
  315. local function is_special(item)
  316.     return (item.artefact or item.branded) and not inscription_plain(item)
  317. end
  318.  
  319. local function is_twohanded(item)
  320.     if item.class(true) ~= "weapon" then return nil end
  321.     if you.genus() == "formicid" or inscription_twohanded(item) then
  322.         return true
  323.     end
  324.     if you.genus() == "spriggan" then
  325.         return not (spriggan_onehanded_weapon_list[basename(item)] ~= nil)
  326.     end
  327.     return twohanded_weapon_list[basename(item)] ~= nil
  328. end
  329.  
  330. local function ego(item)
  331.     if inscription_plain(item) then
  332.         return "plain"
  333.     elseif item.artefact then
  334.         return "artefact"
  335.     elseif item.ego_type_terse ~= "" and item.ego_type_terse ~= "unknown" then
  336.         return item.ego_type_terse
  337.     elseif body_armour_data[basename(item)] ~= nil
  338.            and body_armour_data[basename(item)].ego == true then
  339.         return "innate"
  340.     elseif item.branded then
  341.         return "unknown"
  342.     else
  343.         return "plain"
  344.     end
  345. end
  346.  
  347. local function same_ego(a, b)
  348.     local ego_a = ego(a)
  349.     if ego_a ~= ego(b) then
  350.         return false
  351.     end
  352.     if ego_a == "unknown" or ego_a == "artefact" then
  353.         return false
  354.     end
  355.     if ego_a == "innate" then
  356.         return basename(a) == basename(b)
  357.     end
  358.     return true
  359. end
  360.  
  361. local function parse_body_armour_data()
  362.     local parsed = {}
  363.     for _, v in ipairs(body_armour_data) do
  364.         parsed[v[1]] = { ac=v[2], er=v[3], ego=v[4] }
  365.     end
  366.     return parsed
  367. end
  368.  
  369. local function set_found(key)
  370.     if inventory_match(basename, key) or stash_search(key .. " && dropped") then
  371.         autopickup_found[key] = true
  372.     else
  373.         autopickup_found[key] = false
  374.     end
  375. end
  376.  
  377. local function smallest_shield(genus)
  378.     if genus == "troll" or genus == "ogre" then
  379.         return "shield"
  380.     else
  381.         return "buckler"
  382.     end
  383. end
  384.  
  385. local function initialize()
  386.     if you.genus() == "felid" then
  387.         autopickup_found = {}
  388.         return
  389.     end
  390.  
  391.     local shield_type = smallest_shield(you.genus())
  392.     if autopickup_found == nil then
  393.         autopickup_found = {}
  394.         if AUTOPICKUP_BLOWGUN then
  395.             autopickup_found["blowgun"] = false
  396.         end
  397.         if AUTOPICKUP_BUCKLER then
  398.             autopickup_found[shield_type] = false
  399.         end
  400.         for key, _ in pairs(autopickup_found) do
  401.             set_found(key)
  402.         end
  403.     else
  404.         if not AUTOPICKUP_BLOWGUN then
  405.             autopickup_found["blowgun"] = nil
  406.         elseif autopickup_found["blowgun"]  == nil then
  407.             set_found("blowgun")
  408.         end
  409.         if not AUTOPICKUP_BUCKLER then
  410.             autopickup_found[shield_type] = nil
  411.         elseif autopickup_found[shield_type]  == nil then
  412.             set_found(shield_type)
  413.         end
  414.     end
  415. end
  416.  
  417. local function check_inventory()
  418.     for key, value in pairs(autopickup_found) do
  419.         if value == false and inventory_match(basename, key) then
  420.             autopickup_found[key] = true
  421.         end
  422.     end
  423. end
  424.  
  425. -- CALLED BY THE GAME
  426.  
  427. function set_artefacts(key, value, mode)
  428.     AUTOPICKUP_ARTEFACTS = string.lower(value) ~= "false"
  429. end
  430.  
  431. function set_blowgun(key, value, mode)
  432.     AUTOPICKUP_BLOWGUN = string.lower(value) ~= "false"
  433.     if you.genus() == "felid" then return end
  434.     if not AUTOPICKUP_BLOWGUN then
  435.         autopickup_found["blowgun"] = nil
  436.     elseif autopickup_found["blowgun"] == nil then
  437.         set_found("blowgun")
  438.     end
  439. end
  440.  
  441. function set_buckler(key, value, mode)
  442.     AUTOPICKUP_BUCKLER = string.lower(value) ~= "false"
  443.     if you.genus() == "felid" then return end
  444.     local shield_type = smallest_shield(you.genus())
  445.     if not AUTOPICKUP_BUCKLER then
  446.         autopickup_found[shield_type] = nil
  447.     elseif autopickup_found[shield_type] == nil then
  448.         set_found(shield_type)
  449.     end
  450. end
  451.  
  452. function set_upgrade_weapon(key, value, mode)
  453.     AUTOPICKUP_UPGRADE_WEAPON = string.lower(value) ~= "false"
  454. end
  455.  
  456. local function autopickup(item)
  457.     local name = basename(item)
  458.     local class = item.class(true)
  459.  
  460.     if item.artefact and AUTOPICKUP_ARTEFACTS then
  461.         local skip = false
  462.         local classes = {}
  463.         local subtype = nil
  464.         classes[class] = true
  465.         if class == "weapon" then
  466.             classes["rod"] = true
  467.             classes["magical staff"] = true
  468.         elseif class == "jewellery" or class == "armour" then
  469.             subtype = i_subtype(item)
  470.         end
  471.         for inv in inventory() do
  472.             if classes[inv.class(true)] and inscription_no_artefact(inv) then
  473.                 if subtype == nil or i_subtype(inv) == subtype then
  474.                     skip = true
  475.                     break
  476.                 end
  477.             end
  478.         end
  479.         if not skip then
  480.             return true
  481.         end
  482.     end
  483.  
  484.     if autopickup_found ~= nil then
  485.         if autopickup_found[name] == false then
  486.             return true
  487.         end
  488.         if autopickup_found["blowgun"] ~= nil and name:find("needle") then
  489.             return autopickup_found["blowgun"] == false
  490.                    or inventory_match(basename, "blowgun")
  491.         end
  492.     end
  493.  
  494.     if class == "armour" then
  495.         local subtype = i_subtype(item)
  496.         local current = nil
  497.         if subtype == "body" then
  498.             current = items.equipped_at("armour")
  499.         else
  500.             current = items.equipped_at(subtype)
  501.         end
  502.         if subtype == "body" then
  503.             if current ~= nil and er(item) == er(current)
  504.                and base_ac(item) == base_ac(current) then
  505.                 if is_hide(current) and not is_hide(item) then
  506.                     return true
  507.                 elseif same_ego(item, current) then
  508.                     if estimate_ac(item) > estimate_ac(current) then
  509.                         return true
  510.                     end
  511.                 elseif is_special(item)
  512.                        and not inscription_no_ego(current) then
  513.                     return true
  514.                 end
  515.             end
  516.         elseif subtype == "shield" then
  517.             if current ~= nil and base_ac(item) >= base_ac(current) then
  518.                 if base_ac(item) > base_ac(current) then
  519.                     if inscription_no_upgrade(item) then
  520.                         return false
  521.                     end
  522.                     if same_ego(item, current) then
  523.                         return true
  524.                     elseif is_special(item)
  525.                            and not inscription_no_ego(current) then
  526.                         return true
  527.                     end
  528.                 else
  529.                     if same_ego(item, current) then
  530.                         if estimate_ac(item) > estimate_ac(current) then
  531.                             return true
  532.                         end
  533.                     elseif is_special(item)
  534.                            and not inscription_no_ego(current) then
  535.                         return true
  536.                     end
  537.                 end
  538.             end
  539.         else
  540.             if estimate_ac(item) >= 0 or is_special(item) then
  541.                 if current == nil then
  542.                     return true
  543.                 end
  544.                 if same_ego(item, current) then
  545.                     if estimate_ac(item) > estimate_ac(current) then
  546.                         return true
  547.                     end
  548.                     if estimate_ac(item) == estimate_ac(current)
  549.                        and base_ac(item) > base_ac(current) then
  550.                         return true
  551.                     end
  552.                 elseif is_special(item) and not inscription_no_ego(current) then
  553.                     return true
  554.                 end
  555.             end
  556.         end
  557.     end
  558.  
  559.     if class == "weapon" then
  560.         local match_found = false
  561.         local upgrade_found = false
  562.         local no_upgrade = false
  563.         local upgrade_from, upgrade_to = upgrade_list_for_weapon(name)
  564.         for inv in inventory() do
  565.             if class == inv.class(true) then
  566.                 if name == basename(inv) then
  567.                     match_found = true
  568.                     no_upgrade = true
  569.                     if inscription_no_ego(inv) then
  570.                         return false
  571.                     end
  572.                     if is_special(item) then
  573.                         if same_ego(item, inv)
  574.                            and plus_or_0(inv) >= plus_or_0(item) then
  575.                             return false
  576.                         end
  577.                     elseif is_special(inv)
  578.                            or plus_or_0(inv) >= plus_or_0(item) then
  579.                         return false
  580.                     end
  581.                 elseif upgrade_to[basename(inv)] then
  582.                     no_upgrade = true
  583.                 elseif upgrade_from[basename(inv)] and
  584.                        (not is_twohanded(item) or is_twohanded(inv)) then
  585.                     upgrade_found = true
  586.                     if not is_upgradable(inv) then
  587.                         no_upgrade = true
  588.                     end
  589.                 end
  590.             end
  591.         end
  592.         return match_found or (upgrade_found and not no_upgrade)
  593.     end
  594. end
  595. add_autopickup_func(autopickup)
  596.  
  597. function c_assign_invletter()
  598.     need_inventory_check = true
  599. end
  600.  
  601. function ready()
  602.     if not initialized then
  603.         crawl.more_autoclear(true)
  604.         initialize()
  605.         crawl.more_autoclear(false)
  606.         initialized = true
  607.     else
  608.         if need_inventory_check then
  609.             check_inventory()
  610.         end
  611.     end
  612. end
  613.  
  614. chk_lua_option.autopickup_artefacts = set_artefacts
  615. chk_lua_option.autopickup_blowgun = set_blowgun
  616. chk_lua_option.autopickup_buckler = set_buckler
  617. chk_lua_option.autopickup_upgrade_weapon = set_upgrade_weapon
  618. if options.autopickup_artefacts ~= nil then
  619.     set_artefacts(nil, options.autopickup_artefacts, nil);
  620. end
  621. if options.autopickup_blowgun ~= nil then
  622.     set_blowgun(nil, options.autopickup_blowgun, nil);
  623. end
  624. if options.autopickup_buckler ~= nil then
  625.     set_buckler(nil, options.autopickup_buckler, nil);
  626. end
  627. if options.autopickup_upgrade_weapon ~= nil then
  628.     set_upgrade_weapon(nil, options.autopickup_upgrade_weapon, nil);
  629. end
  630.  
  631. twohanded_weapon_list = Set(twohanded_weapon_list)
  632. spriggan_onehanded_weapon_list = Set(spriggan_onehanded_weapon_list)
  633. body_armour_data = parse_body_armour_data()
  634.  
  635. function write_bool_table(table, aname)
  636.     local res = aname .. " = { "
  637.     for k, v in pairs(table) do
  638.         res = res .. k .. '=' .. tostring(v) .. ", "
  639.     end
  640.     return res .. "}\n"
  641. end
  642.  
  643. function autopickup_save()
  644.     return write_bool_table(autopickup_found, "autopickup_found")
  645. end
  646.  
  647. table.insert(chk_lua_save, autopickup_save)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement