SHARE
TWEET

h2turtle API (for CC1.65 or over)

hevohevo Feb 14th, 2015 181 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. -- #############################################################
  2. -- h2turtle API
  3. -- version 0.2
  4. -- Turtle API for ComputerCraft 1.65 or over
  5. --     required function: "turtle.getItemDetail()", "turtle.getItemDetail()"
  6.  
  7. -- (c) 2015 hevohevo, License: MIT
  8. -- twitter: @hevohevo, http://hevohevo.hatenablog.com/
  9.  
  10.  
  11. -- ##############################################################
  12. -- API List
  13.  
  14. -- h2turtle.sortInventory()
  15. --        インベントリ内のアイテムを整理し並べ替える
  16. -- h2turtle.collectItem()
  17. --        インベントリ内のアイテムをまとめる
  18. -- h2turtle.getItemCountAll(item_name_str, [damage])
  19. --        インベントリ内のアイテム(名前・ダメージ値指定)の総数を返す
  20. -- h2turtle.selectItem(item_name_str, [damage])
  21. --        アイテム(名前・ダメージ値指定)があるスロットを選択する
  22. -- h2turtle.getEmptySlot()
  23. --        空のスロット番号を返す
  24. -- h2turtle.selectEmptySlot()
  25. --        空のスロットを選択する
  26. -- h2turtle.changeItems(slot0, slot1, tmp_slot)
  27. --        slot0とslot1のアイテムを入れ替える。なおtmp_slotは入れ替えるときの一時アイテム置き場。必須。
  28. -- h2turtle.digFor(block_names_tbl) / digUpFor() / digDownFor()
  29. --        指定したブロック名(部分一致、複数可)と**マッチした**ブロックだけ採掘
  30. --        例:block_names_tbl = {{"dirt",0}, "stone", {"wood",1}}
  31. -- h2turtle.digExcept(block_names_tbl) / digUpExcept() / digDownExcept()
  32. --        指定したブロック名(部分一致、複数可)と**マッチしない**ブロックだけ採掘
  33. -- h2turtle.isBlock(block_names_tbl) / isUpBlock() / isDownBlock() => true/false, マッチした名前
  34. --        隣接ブロックが指定したブロック名とマッチするかどうかを返す
  35. -- h2turtle.placeItem(item_name, item_damage) / placeUpItem() / placeDownItem()
  36. --        指定したアイテム名(部分一致)とマッチしたアイテムを使用(設置)する
  37. -- h2turtle.waitForEnoughItems(required_qty, item_name, [item_damage])
  38. --        指定した個数、指定したアイテム(ダメージ値)がインベントリに入るまで待つ
  39.  
  40. -- ## prompt
  41. -- h2turtle.promptYN(prompt_msg) => true/false
  42. --        Yes/Noを聞いてくるプロンプト
  43. -- h2turtle.promptValue(prompt_msg, default_value) => (string)value
  44. --        値を入力するよう促してくる、デフォルト値付き
  45. -- ##############################################################
  46.  
  47. -- 上記、ブロック名リストにマッチするかどうかを判定するサブ関数
  48. function _matchNames(names, block_name, block_meta)
  49.   for i,p in ipairs(names) do
  50.     if type(p)=="table" then
  51.       if string.match(block_name, p[1]) and block_meta == p[2] then
  52.         return true, p
  53.       end
  54.     else
  55.       if string.match(block_name, p) then
  56.         return true, p
  57.       end
  58.     end
  59.   end
  60.  
  61.   return false, "No block to match"
  62. end
  63.  
  64. function _isBlock(names, inspect_func)
  65.   local status, detail = inspect_func()
  66.   if not status then return false end -- その方向にブロックなかったらfalse
  67.   return _matchNames(names, detail["name"], detail["metadata"])
  68. end
  69.  
  70. function isBlock(names)
  71.   return _isBlock(names, turtle.inspect)
  72. end
  73. function isUpBlock(names)
  74.   return _isBlock(names, turtle.inspectUp)
  75. end
  76. function isDownBlock(names)
  77.   return _isBlock(names, turtle.inspectDown)
  78. end
  79.  
  80. -- 各種digFor/digExcept関数を作るための元関数
  81. function _digFor(tbl, inspect_func, dig_func, except_flag)
  82.   if type(tbl) ~= "table" then return dig_func() end
  83.  
  84.   local status, value = inspect_func()
  85.   print(value["name"])
  86.   if status then
  87.     -- ブロックが存在するとき
  88.     if _matchNames(tbl, value["name"], value["metadata"]) then
  89.       if except_flag then -- 除外フラグtrueならマッチしたときに何もしない
  90.         return false, "Find an exception block"
  91.       else
  92.         return dig_func()
  93.       end
  94.     else
  95.       if except_flag then -- 除外フラグfalseならマッチしたときに採掘
  96.         return dig_func()
  97.       else
  98.         return false, "No block to match"
  99.       end
  100.     end
  101.    
  102.   else
  103.     -- ブロックが存在しないとき
  104.     return dig_func()
  105.   end
  106.  
  107. end
  108.  
  109. -- 各方向の関数を定義
  110. -- digFor/digExcept, digUpFor/digUpExcept, digDownFor/digDownExcept
  111.  
  112. function digFor(tbl)
  113.   return _digFor(tbl, turtle.inspect, turtle.dig, false)
  114. end
  115.  
  116. function digExcept(tbl)
  117.   return _digFor(tbl, turtle.inspect, turtle.dig, true)
  118. end
  119.  
  120. function digUpFor(tbl)
  121.   return _digFor(tbl, turtle.inspectUp, turtle.digUp, false)
  122. end
  123.  
  124. function digUpExcept(tbl)
  125.   return _digFor(tbl, turtle.inspectUp, turtle.digUp, true)
  126. end
  127.  
  128. function digDownFor(tbl)
  129.   return _digFor(tbl, turtle.inspectDown, turtle.digDown, false)
  130. end
  131.  
  132. function digDownExcept(tbl)
  133.   return _digFor(tbl, turtle.inspectDown, turtle.digDown, true)
  134. end
  135.  
  136.  
  137. -- インベントリ内にバラバラに入っているアイテムをできるだけまとめる
  138. -- turtle.transferTo(slot [, quantity]), 1/27作
  139. function collectItem()
  140.   local selected_slot = turtle.getSelectedSlot()
  141.   for i=1,16 do
  142.     local detail = turtle.getItemDetail(i)
  143.     if detail then -- スロットになにかアイテムある
  144.       for j=i,16 do
  145.         local detail2 = turtle.getItemDetail(j)
  146.         if detail2 and detail["name"]==detail2["name"] and detail["damage"]==detail2["damage"] then
  147.           turtle.select(j)
  148.           turtle.transferTo(i)
  149.         end
  150.       end
  151.     else -- スロットにアイテムない
  152.     end
  153.   end
  154.   turtle.select(selected_slot)
  155. end
  156.  
  157.  
  158. -- turtle.getItemCounrt(slot_num) , 1/27作
  159. -- 発展→ getItemCountAll(item_name, damage) => アイテム総数
  160. function getItemCountAll(item_name, damage)
  161.   local count = 0
  162.   for i=1,16 do
  163.     local detail = turtle.getItemDetail(i)
  164.     if detail then  -- スロットになにかアイテムある
  165.       if string.match(detail["name"],item_name) then  -- アイテム名がマッチする
  166.         if damage == nil or damage==detail["damage"] then  -- ダメージ値の指定があり、それが一致する
  167.           count = count + detail["count"]
  168.         end
  169.       else  -- アイテム名がマッチしない
  170.       end
  171.     else  -- スロットにアイテムない
  172.     end
  173.   end
  174.   return count
  175. end
  176.  
  177. -- selectItem(name, damage) , 1/26作
  178. -- スロット内を探し、name(damage値指定があるときはそれも)とマッチするアイテムを選択する。
  179. function selectItem(name,damage)
  180.   -- local selected_slot = turtle.getSelectedSlot()
  181.  
  182.   for i=1,16 do
  183.     local item = turtle.getItemDetail(i)
  184.     if type(item)=="table" then -- スロットに何かアイテム
  185.       -- print("slot=",i," ",item["name"]," ",item["damage"])
  186.       if string.match(item["name"],name) then -- 指定アイテムの名前と一致
  187.         if damage==nil or damage == item["damage"] then -- ダメージ値指定がない、または指定と一致
  188.           turtle.select(i)
  189.           return true, item["count"]
  190.         else -- 名前は一致したがダメージ値が違う
  191.           -- do nothing
  192.         end
  193.       else -- 指定アイテムの名前と不一致
  194.         -- do nothing
  195.       end
  196.     else -- スロット内にアイテムなし
  197.       -- do nothing
  198.     end
  199.   end
  200.   -- turtle.select(selected_slot)
  201.   return false, "No item to match"
  202. end
  203.  
  204. -- スロット番号の小さいほうから探し、空っぽのスロットを選択する。
  205. function selectEmptySlot()
  206.   for i=1, 16 do
  207.     local item = turtle.getItemDetail(i)
  208.     if item == nil then
  209.       turtle.select(i)
  210.       return true
  211.     end
  212.   end
  213.   return false
  214. end
  215.  
  216. -- スロット番号の小さいほうから探し、空っぽのスロット番号を返す
  217. function getEmptySlot()
  218.   for i=1, 16 do
  219.     if turtle.getItemCount(i) == 0 then
  220.       return i
  221.     end
  222.   end
  223.   return false
  224. end
  225.  
  226. -- slot0とslot1のアイテムを入れ替える。tmp_slotは入れ替え時に用いる一時アイテム置き場
  227. function changeItems(slot0, slot1, tmp_slot)
  228.   if slot0 == slot1 then return end -- slot0とslot1が同じならすぐ終了
  229.   if turtle.getItemCount(tmp_slot)>0 then return false, "tmp_slot must be empty." end
  230.   if turtle.getItemCount(slot1)>0 then -- 移動先slot1が埋まっている
  231.     if turtle.getItemCount(slot0)>0 then -- 移動先slot0も埋まっているので、一時置き場を使おう
  232.       turtle.select(slot1)
  233.       turtle.transferTo(tmp_slot) -- slot1のアイテムを退避
  234.       turtle.select(slot0)
  235.       turtle.transferTo(slot1) -- slot0のアイテムをslot1に移動
  236.       turtle.select(tmp_slot)
  237.       turtle.transferTo(slot0) -- 退避スロットのアイテムをslot1に移動
  238.     else -- 移動先slot0があいているので slot1からslot0へ移動させよう
  239.       turtle.select(slot1)
  240.       turtle.transferTo(slot0)
  241.     end
  242.   else
  243.     turtle.select(slot0)
  244.     turtle.transferTo(slot1) -- slot0のアイテムをslot1に移動
  245.   end
  246. end
  247.  
  248.  
  249. -- table.sort()で用いる比較関数の定義。名前順でダメージ値の順。
  250. --   _compare({name="minecraft:dirt", damage=0}, {name="minecraft:wool", damage=1})
  251. --     => true   (名前のアルファベット順で左の方が前だから)
  252. --   _compare({name="minecraft:wool", damage=3}, {name="minecraft:wool", damage=1})
  253. --     => false   (名前は同じだがダメージ値が後の方が小さいので)
  254. local function _compare(detail0, detail1)
  255.   -- 引数がおかしいとエラー終了
  256.   assert(detail0 and detail1 and detail0["name"] and detail1["name"] and detail0["damage"] and detail1["damage"])
  257.  
  258.   if detail0["name"] < detail1["name"] then
  259.     return true -- detail0が名前順で前ならばtrue
  260.   elseif detail0["name"] == detail1["name"] then
  261.     -- detail0の名前が同じならばdamage値が小さければtrue
  262.     return detail0["damage"] <= detail1["damage"]
  263.   else
  264.     return false -- detail0が名前順で後ろならばfalse
  265.   end
  266.    
  267. end
  268.  
  269. -- ###################################################################
  270. function sortInventory()
  271.   local tmp_slot = 16
  272.   collectItem() -- まずは整理しようね。
  273.  
  274.   -- スロット16(tmp_slot)があいてない場合はエラー返して終了するよ
  275.   if turtle.getItemCount(tmp_slot) > 0 then
  276.     local empty_slot = getEmptySlot()
  277.     if empty_slot == false then -- 空ける場所もないのでfalse終了
  278.       return false, "Slot "..tmp_slot.." must be empty."
  279.     else
  280.       turtle.select(tmp_slot)
  281.       turtle.transferTo(empty_slot)
  282.       collectItem()
  283.     end
  284.   end
  285.  
  286.   -- インベントリアイテムの情報を収集するよ
  287.   local items = {}
  288.   for i=1,15 do
  289.     local item = turtle.getItemDetail(i)
  290.     if item then -- スロットにアイテムあります。
  291.       table.insert(items, item)
  292.     else
  293.       -- スロットは空です。
  294.     end
  295.   end
  296.   table.sort(items, _compare) -- 文字列順にソートじゃい。比較用関数は自分で作ったの使っています。
  297.  
  298.   for i,_item in ipairs(items) do
  299.     selectItem(_item["name"], _item["damage"])
  300.     local slot0 = turtle.getSelectedSlot()
  301.     print(slot0..'->'..i)
  302.     changeItems(slot0, i, tmp_slot)
  303.   end
  304. end
  305.  
  306. -- #######################################################
  307.  
  308. function _placeItem(_place_func, item_name, item_damage)
  309.   local place_func = _place_func or turtle.place
  310.  
  311.  
  312.   if selectItem(item_name, item_damage) then
  313.     -- マッチするアイテムあり
  314.     return place_func()
  315.   else
  316.     -- マッチするアイテムなし
  317.     return false, "No item to match"
  318.   end
  319.  
  320. end
  321.  
  322. function placeItem(item_name, item_damage)
  323.   return _placeItem(turtle.place, item_name, iem_damage)
  324. end
  325. function placeUpItem(item_name, item_damage)
  326.   return _placeItem(turtle.placeUp, item_name, iem_damage)
  327. end
  328. function placeDownItem(item_name, item_damage)
  329.   return _placeItem(turtle.placeDown, item_name, iem_damage)
  330. end
  331.  
  332.  
  333.  
  334. function waitForEnoughItems(required_qty, item_name, item_damage)
  335.   local ppItem = function(item_name, item_damage, current_qty, required_qty)
  336.     if item_damage then
  337.       print(string.format("%s(%d): %d/%d", item_name, item_damage, current_qty,required_qty))
  338.     else
  339.       print(string.format("%s: %d/%d", item_name, current_qty, required_qty))
  340.     end    
  341.   end
  342.  
  343.   local current_qty = h2turtle.getItemCountAll(item_name, item_damage)
  344.  
  345.   while current_qty < required_qty do
  346.     ppItem(item_name, item_damage, current_qty, required_qty)
  347.     os.sleep(0.5)
  348.     os.pullEvent("turtle_inventory")
  349.     current_qty = h2turtle.getItemCountAll(item_name, item_damge)
  350.   end
  351.   ppItem(item_name, item_damage, current_qty, required_qty)
  352. end
  353.  
  354.  
  355. -- ####################################
  356. -- prompt
  357.  
  358. function promptValue(prompt_msg, default_value)
  359.   assert(default_value, "promptValue(prompt_msg, default_value)")
  360.   prompt_msg = prompt_msg or "Please input"
  361.   prompt_msg = prompt_msg.." [\""..default_value.."\"]: "
  362.   print(prompt_msg)
  363.   term.write(" >>")
  364.   local inputed_value = read()
  365.  
  366.   if inputed_value == "" then
  367.     -- 入力なしのエンターキーならば、デフォルト値を返す
  368.     return default_value
  369.   else
  370.     return inputed_value
  371.   end
  372. end
  373.  
  374. function promptYN(prompt_msg)
  375.   prompt_msg = prompt_msg or "ok? ([y]/n): "
  376.   local pattern_tbl = {
  377.     yes=true, y=true, Y=true, Yes=true,
  378.     no=false, No=false, n=false, N=false
  379.   }
  380.   while true do
  381.     term.write(prompt_msg)
  382.     local value = read()
  383.     if value=="" then
  384.       return true
  385.     else
  386.       local tmp = pattern_tbl[value]
  387.       if tmp ~= nil then return tmp end
  388.  
  389.       -- tmp==nil すなわち、意味不明文字列の場合に再入力を促す
  390.     end
  391.   end
  392. end
RAW Paste Data
Top