turtle/api.lua
2015-02-18 14:22:54 +01:00

774 lines
23 KiB
Lua

local MOVE_COST = 100
local FUEL_EFFICIENCY = 1000
tl = {}
local function delay(x)
return function() return x end
end
local function pointable(stack, node)
local nodedef = minetest.registered_nodes[node.name]
local def = minetest.registered_items[stack:get_name()]
return nodedef and def and (nodedef.pointable or (nodedef.liquidtype ~= "none" and def.liquid_pointable))
end
local NONE = 0
local FRONT = 1
local ANY = 2
function turtles.create_turtle_player(turtle_id, dir, pointed_type)
local info = turtles.get_turtle_info(turtle_id)
local inv = turtles.get_turtle_inventory(turtle_id)
local pitch
local yaw
if dir.z > 0 then
yaw = 0
pitch = 0
elseif dir.z < 0 then
yaw = math.pi
pitch = 0
elseif dir.x > 0 then
yaw = 3*math.pi/2
pitch = 0
elseif dir.x < 0 then
yaw = math.pi/2
pitch = 0
elseif dir.y > 0 then
yaw = 0
pitch = -math.pi/2
else
yaw = 0
pitch = math.pi/2
end
local player = {
get_inventory_formspec = delay(""), -- TODO
get_look_dir = delay(vector.new(dir)),
get_look_pitch = delay(pitch),
get_look_yaw = delay(yaw),
get_player_control = delay({jump = false, right = false, left = false, LMB = false, RMB = false, sneak = false, aux1 = false, down = false, up = false}),
get_player_control_bits = delay(0),
get_player_name = delay("turtle:" .. tostring(turtle_id)),
is_player = delay(true),
is_turtle = true,
set_inventory_formspec = delay(),
getpos = function() vector.subtract(info.spos, {x = 0, y = 1.5, z = 0}) end,
get_hp = delay(20),
get_inventory = function() return turtles.get_turtle_inventory(turtle_id) end,
get_wielded_item = function() return turtles.get_turtle_inventory(turtle_id):get_stack("main", info.wield_index or 1) end,
get_wield_index = function() return info.wield_index or 1 end,
get_wield_list = delay("main"),
moveto = delay(), -- TODO
punch = delay(),
remove = delay(),
right_click = delay(), -- TODO
setpos = delay(), -- TODO
set_hp = delay(),
set_properties = delay(),
set_wielded_item = function(self, item)
turtles.get_turtle_inventory(turtle_id):set_stack("main", info.wield_index or 1, item)
end,
set_animation = delay(),
set_attach = delay(), -- TODO???
set_detach = delay(),
set_bone_position = delay(),
}
if pointed_type == NONE then return player end
local above, under = nil, nil
local wieldstack = player:get_wielded_item()
local pos = vector.add(info.spos, dir)
if pointable(wieldstack, minetest.get_node(pos)) then
above = vector.new(info.spos)
under = pos
elseif pointed_type == ANY and pointable(wieldstack, minetest.get_node(vector.add(pos, dir))) then
above = pos
under = vector.add(pos, dir)
elseif pointed_type == ANY then
for i = 0, 5 do
local dir2 = directions.side_to_dir(i)
if vector.dot(dir2, dir) == 0 and pointable(wieldstack, minetest.get_node(vector.add(pos, dir2))) then
under = vector.add(pos, dir2)
break
end
end
above = pos
end
local pointed_thing = nil
if under ~= nil then
pointed_thing = {type = "node", above = above, under = under}
end
return player, pointed_thing
end
function tl.select(turtle, cptr, slot)
if 1 <= slot and slot < turtles.get_turtle_inventory(turtle):get_size("main") then
turtles.get_turtle_info(turtle).wield_index = slot
end
end
local function tl_move(turtle, cptr, dir)
tl.close_form(turtle)
local info = turtles.get_turtle_info(turtle)
if info.energy < MOVE_COST then
cptr.X = 0
return
end
local spos = info.spos
local npos = vector.add(spos, dir)
if minetest.get_node(npos).name == "air" then
minetest.set_node(npos, {name = "turtle:turtle2"})
info.npos = npos
info.moving = true
info.energy = info.energy - MOVE_COST
cptr.X = u16(-1)
cptr.paused = true
else
cptr.X = 0
end
end
function tl.forward(turtle, cptr)
local dir = turtles.get_turtle_info(turtle).dir
tl_move(turtle, cptr, minetest.facedir_to_dir(dir))
end
function tl.backward(turtle, cptr)
local dir = turtles.get_turtle_info(turtle).dir
tl_move(turtle, cptr, vector.multiply(minetest.facedir_to_dir(dir), -1))
end
function tl.up(turtle, cptr)
tl_move(turtle, cptr, {x = 0, y = 1, z = 0})
end
function tl.down(turtle, cptr)
tl_move(turtle, cptr, {x = 0, y = -1, z = 0})
end
function tl.turnleft(turtle, cptr)
tl.close_form(turtle)
local info = turtles.get_turtle_info(turtle)
info.ndir = (info.dir + 3) % 4
info.rotate = math.pi / 2
info.moving = true
cptr.paused = true
end
function tl.turnright(turtle, cptr)
tl.close_form(turtle)
local info = turtles.get_turtle_info(turtle)
info.ndir = (info.dir + 1) % 4
info.rotate = - math.pi / 2
info.moving = true
cptr.paused = true
end
local function write_string_at(cptr, addr, str)
for i = 1, string.len(str) do
cptr[u16(addr - 1 + i)] = string.byte(str, i)
end
cptr.X = string.len(str)
end
local function turtle_detect(turtle, cptr, dir)
local info = turtles.get_turtle_info(turtle)
local pos = vector.add(info.spos, dir)
local name = minetest.get_node(pos).name
write_string_at(cptr, cptr.X, name)
end
function tl.detect(turtle, cptr)
local info = turtles.get_turtle_info(turtle)
turtle_detect(turtle, cptr, minetest.facedir_to_dir(info.dir))
end
function tl.detectup(turtle, cptr)
turtle_detect(turtle, cptr, {x = 0, y = 1, z = 0})
end
function tl.detectdown(turtle, cptr)
turtle_detect(turtle, cptr, {x = 0, y = -1, z = 0})
end
local function turtle_dig(turtle, cptr, dir)
tl.close_form(turtle)
local player, pointed_thing = turtles.create_turtle_player(turtle, dir, FRONT)
if pointed_thing == nil then return end
local info = turtles.get_turtle_info(turtle)
local wieldstack = player:get_wielded_item()
local on_use = (minetest.registered_items[wieldstack:get_name()] or {}).on_use
if on_use then
player:set_wielded_item(on_use(wieldstack, player, pointed_thing) or wieldstack)
else
local pos = pointed_thing.under
local node = minetest.get_node(pos)
local def = ItemStack({name = node.name}):get_definition()
local toolcaps = wieldstack:get_tool_capabilities()
local dp = minetest.get_dig_params(def.groups, toolcaps)
local dp2 = minetest.get_dig_params(def.groups, ItemStack(""):get_tool_capabilities())
if (dp.diggable or dp2.diggable) and def.diggable and def.pointable and (not def.can_dig or def.can_dig(pos, player)) and
(not minetest.is_protected(pos, player:get_player_name())) then
local on_dig = (minetest.registered_nodes[node.name] or {on_dig = minetest.node_dig}).on_dig
on_dig(pos, node, player)
end
end
end
function tl.dig(turtle, cptr)
local info = turtles.get_turtle_info(turtle)
turtle_dig(turtle, cptr, minetest.facedir_to_dir(info.dir))
end
function tl.digup(turtle, cptr)
turtle_dig(turtle, cptr, {x = 0, y = 1, z = 0})
end
function tl.digdown(turtle, cptr)
turtle_dig(turtle, cptr, {x = 0, y = -1, z = 0})
end
local function turtle_place(turtle, cptr, dir)
tl.close_form(turtle)
local player, pointed_thing = turtles.create_turtle_player(turtle, dir, ANYDIR)
if pointed_thing == nil then return end
local formspec = minetest.get_meta(pointed_thing.under):get_string("formspec")
if formspec ~= "" then
local info = turtles.get_turtle_info(turtle)
info.open_formspec = tl.read_formspec(formspec)
info.formspec_type = {type = "node", pos = pointed_thing.under}
info.formspec_fields = {}
return
end
local wieldstack = player:get_wielded_item()
local on_place = (minetest.registered_items[wieldstack:get_name()] or {on_place = minetest.item_place}).on_place
player:set_wielded_item(on_place(wieldstack, player, pointed_thing) or wieldstack)
end
function tl.place(turtle, cptr)
local info = turtles.get_turtle_info(turtle)
turtle_place(turtle, cptr, minetest.facedir_to_dir(info.dir))
end
function tl.placeup(turtle, cptr)
turtle_place(turtle, cptr, {x = 0, y = 1, z = 0})
end
function tl.placedown(turtle, cptr)
turtle_place(turtle, cptr, {x = 0, y = -1, z = 0})
end
local function stack_set_count(stack, count)
stack = stack:to_table()
if stack == nil then return nil end
stack.count = count
return ItemStack(stack)
end
function tl.refuel(turtle, cptr, slot, nmax)
local info = turtles.get_turtle_info(turtle)
local inv = turtles.get_turtle_inventory(turtle)
local stack = inv:get_stack("main", slot)
if technic and technic.power_tools[stack:get_name()] then
local meta = minetest.deserialize(stack:get_metadata()) or {}
if not meta.charge then
meta.charge = 0
end
info.energy = info.energy + meta.charge
meta.charge = 0
local max_charge = technic.power_tools[stack:get_name()]
technic.set_RE_wear(stack, 0, max_charge)
stack:set_metadata(minetest.serialize(meta))
inv:set_stack("main", slot, stack)
cptr.X = u16(-1)
return
end
local fuel, afterfuel = minetest.get_craft_result({method = "fuel", width = 1, items = {stack}})
if fuel.time <= 0 then
cptr.X = 0
return
end
local count = math.min(stack:get_count(), nmax)
local fs = stack:to_table()
fs.count = 1
local fstack = ItemStack(fs)
local fuel, afterfuel
fuel, afterfuel = minetest.get_craft_result({method = "fuel", width = 1, items = {fstack}})
stack:take_item(count)
if afterfuel ~= nil then
afterfuel = afterfuel.items[1]
end
if afterfuel ~= nil then
afterfuel = stack_set_count(afterfuel, afterfuel:get_count()*count)
local leftover = stack:add_item(ItemStack(afterfuel))
inv:set_stack("main", slot, stack)
local leftover2 = inv:add_item("main", leftover)
minetest.add_item(info.spos, leftover2)
else
inv:set_stack("main", slot, stack)
end
info.energy = info.energy + FUEL_EFFICIENCY * count * fuel.time
cptr.X = u16(-1)
end
function tl.get_energy(turtle, cptr)
local info = turtles.get_turtle_info(turtle)
cptr.Y = u16(info.energy)
cptr.X = u16(math.floor(info.energy / 0x10000))
end
--------------
-- Formspec --
--------------
minetest.register_on_player_receive_fields(function(player, formname, fields)
if player:get_player_name():sub(1, 7) == "turtle:" and formname == "turtle:inventory" then
return true
end
end)
local function get_turtle_formspec_player(turtle)
local info = turtles.get_turtle_info(turtle)
local dir
if info.formspec_type and info.formspec_type.type == "node" then
dir = vector.normalize(vector.subtract(info.formspec_type.pos, info.spos))
else
dir = minetest.facedir_to_dir(info.dir)
end
return turtles.create_turtle_player(turtle, dir, NONE)
end
local function send_fields(turtle)
local info = turtles.get_turtle_info(turtle)
local fields = info.formspec_fields
info.formspec_fields = {}
local player = get_turtle_formspec_player(turtle)
if info.formspec_type.type == "show" then
for _, func in ipairs(minetest.registered_on_receive_fields) do
if func(player, info.formspec_type.formname, fields) then
return
end
end
else
local pos = info.formspec_type.pos
local nodedef = minetest.registered_nodes[minetest.get_node(pos).name]
if nodedef and nodedef.on_receive_fields then
nodedef.on_receive_fields(vector.new(pos), "", fields, player)
end
end
end
function tl.close_form(turtle)
local info = turtles.get_turtle_info(turtle)
if info.formspec_fields then
info.formspec_fields["quit"] = "true"
send_fields(turtle)
info.open_formspec = nil
info.formspec_type = nil
info.formspec_fields = nil
end
end
local function split_str(str, delim)
local parsed = {}
local i = 1
local s = ""
while i <= string.len(str) do
if str:sub(i, i) == "\\" then
s = s .. str:sub(i, i + 1)
i = i + 2
elseif str:sub(i, i) == delim then
parsed[#parsed + 1] = s
s = ""
i = i + 1
else
s = s .. str:sub(i, i)
i = i + 1
end
end
parsed[#parsed + 1] = s
return parsed
end
local function parse_list(lstdef)
local parsed = split_str(lstdef, ";")
local psize = split_str(parsed[4], ",")
if parsed[1] == "current_name" then parsed[1] = "context" end
return {location = parsed[1], listname = parsed[2],
size = tonumber(psize[1]) * tonumber(psize[2]),
start_index = ((parsed[5] and tonumber(parsed[5])) or 0) + 1}
end
local function merge_adjacent_lists(lsts)
local function merge_at(t, ind)
if t.starts[ind] and t.ends[ind] then
t.starts[t.ends[ind]] = t.starts[ind]
t.ends[t.starts[ind]] = t.ends[ind]
t.starts[ind] = nil
t.ends[ind] = nil
end
end
local locs = {}
for _, lst in ipairs(lsts) do
local loc = lst.location .. ";" .. lst.listname
if locs[loc] == nil then
locs[loc] = {location = lst.location, listname = lst.listname, starts = {}, ends = {}}
end
local starti, endi = lst.start_index, lst.start_index + lst.size
locs[loc].ends[endi] = starti
locs[loc].starts[starti] = endi
merge_at(locs[loc], endi)
merge_at(locs[loc], starti)
end
local new = {}
for _, lst in pairs(locs) do
for starti, endi in pairs(lst.starts) do
new[#new + 1] = {location = lst.location, listname = lst.listname, size = endi - starti, start_index = starti}
end
end
return new
end
function tl.read_formspec(formspec)
local parsed = split_str(formspec, "]")
local lsts = {}
for _, item in ipairs(parsed) do
if item:sub(1, 5) == "list[" then
lsts[#lsts + 1] = parse_list(item:sub(6, -1))
end
end
return {lists = merge_adjacent_lists(lsts)}
end
local old_show_formspec = minetest.show_formspec
function minetest.show_formspec(playername, formname, formspec)
if playername:sub(1, 7) == "turtle:" then
local id = tonumber(playername:sub(8, -1))
local info = turtles.get_turtle_info(id)
info.open_formspec = tl.read_formspec(formspec)
info.formspec_type = {type = "show", formname = formname}
info.formspec_fields = {}
return
end
old_show_formspec(playername, formname, formspec)
end
function tl.open_inv(turtle, cptr)
tl.close_form(turtle)
local info = turtles.get_turtle_info(turtle)
info.open_formspec = tl.read_formspec(
"list[current_player;main;0,4.25;8,4;]"..
"list[current_player;craft;1.75,0.5;3,3;]"..
"list[current_player;craftpreview;5.75,1.5;1,1;]")
info.formspec_type = {type = "show", formname = "turtle:inventory"}
end
-- Formspec memory layout
-- +-----+-----+-----+-----+----
-- | | Pointer | |
-- | Tag | to next | ID | Data
-- | | element | |
-- +-----+-----+-----+-----+----
--
-- For last element (TAG_END), only tag is present
local function push(cptr, addr, value)
cptr[addr] = bit32.band(value, 0xff)
cptr[u16(addr + 1)] = bit32.band(math.floor(value/256), 0xff)
return u16(addr + 2)
end
local function pushC(cptr, addr, value)
cptr[addr] = bit32.band(value, 0xff)
return u16(addr + 1)
end
local function push_string(cptr, addr, str)
for i = 1, string.len(str) do
cptr[u16(addr - 1 + i)] = string.byte(str, i)
end
return u16(addr + string.len(str))
end
local function push_string_counted(cptr, addr, str)
-- String length (2 bytes)
-- String contents
return push_string(cptr, push(cptr, addr, string.len(str)), str)
end
local function push_stack(cptr, addr, stack)
-- Count (2 bytes)
-- Wear (2 bytes)
-- Item name
return push_string_counted(cptr,
push(cptr,
push(cptr, addr,
stack:get_count()),
stack:get_wear()),
stack:get_name())
end
local TAG_END = 0
local TAG_LIST = 1
function tl.get_formspec(turtle, cptr, addr)
local info = turtles.get_turtle_info(turtle)
if not info.open_formspec then
pushC(cptr, addr, TAG_END)
return
end
local i = 0
for _, lst in ipairs(info.open_formspec.lists) do
addr = pushC(cptr, addr, TAG_LIST)
local old_addr = addr
addr = u16(addr + 2)
addr = pushC(cptr, addr, i)
i = i + 1
addr = push_string_counted(cptr, addr, lst.location)
addr = push_string_counted(cptr, addr, lst.listname)
addr = push(cptr, addr, lst.size)
addr = push(cptr, addr, lst.start_index)
push(cptr, old_addr, addr) -- Pointer to next element
end
pushC(cptr, addr, TAG_END)
end
local function get_element_by_id(formspec, elem_id)
return formspec.lists[elem_id + 1]
end
---------------
-- Inventory --
---------------
local function get_inventory_from_location(turtle, location)
if location == "current_player" then
return turtles.get_turtle_inventory(turtle)
elseif location == "context" then
local info = turtles.get_turtle_info(turtle)
local formspec = info.formspec_type
if formspec and formspec.type == "node" then
return minetest.get_meta(formspec.pos):get_inventory()
end
print("WARNING: tried to access context without open node formspec")
elseif location:sub(1, 8) == "nodemeta" then
local p = split_str(location, ":")
local spos = split_str(p[2], ",")
local pos = {x = tonumber(spos[1]), y = tonumber(spos[2]), z = tonumber(spos[3])}
if pos.x and pos.y and pos.z then
return minetest.get_meta(pos):get_inventory()
end
print("WARNING: incorrect nodemeta element: " .. location)
else
print("WARNING: unimplemented location type: " .. location)
end
end
function tl.get_stack(turtle, cptr, elem_id, slot, addr)
local info = turtles.get_turtle_info(turtle)
local stack = ItemStack("")
if info.open_formspec then
local formspec = info.open_formspec
local elem = get_element_by_id(formspec, elem_id)
if elem and elem.location and
elem.start_index <= slot and slot < elem.start_index + elem.size then
local inv = get_inventory_from_location(turtle, elem.location)
if inv then
stack = inv:get_stack(elem.listname, slot)
end
end
end
push_stack(cptr, addr, stack)
end
local function same_location(location1, location2)
if location1.type ~= location2.type then
return false
end
if location1.type == "node" then
return vector.equals(location1.pos, location2.pos)
else
return location1.name == location2.name
end
end
local function get_callbacks(location)
if location.type == "node" then
local node = minetest.get_node(location.pos)
local nodedef = minetest.registered_nodes[node.name] or {}
return {allow_move = function(list1, index1, list2, index2, count, player)
return nodedef.allow_metadata_inventory_move and
nodedef.allow_metadata_inventory_move(location.pos, list1, index1, list2, index2, count, player) or
count
end,
allow_take = function(list, index, stack, player)
return nodedef.allow_metadata_inventory_take and
nodedef.allow_metadata_inventory_take(location.pos, list, index, stack, player) or
stack:get_count()
end,
allow_put = function(list, index, stack, player)
return nodedef.allow_metadata_inventory_put and
nodedef.allow_metadata_inventory_put(location.pos, list, index, stack, player) or
stack:get_count()
end,
on_move = function(list1, index1, list2, index2, count, player)
if nodedef.on_metadata_inventory_move then
nodedef.on_metadata_inventory_move(location.pos, list1, index1, list2, index2, count, player)
end
end,
on_take = function(list, index, stack, player)
if nodedef.on_metadata_inventory_take then
nodedef.on_metadata_inventory_take(location.pos, list, index, stack, player)
end
end,
on_put = function(list, index, stack, player)
if nodedef.on_metadata_inventory_put then
nodedef.on_metadata_inventory_put(location.pos, list, index, stack, player)
end
end,
}
elseif location.type == "detached" then
print("WARNING: not yet implemented")
return {allow_move = function(list1, index1, list2, index2, count, player)
return count
end,
allow_take = function(list, index, stack, player)
return stack:get_count()
end,
allow_put = function(list, index, stack, player)
return stack:get_count()
end,
on_move = function() end,
on_take = function() end,
on_put = function() end,
}
else
return {allow_move = function(list1, index1, list2, index2, count, player)
return count
end,
allow_take = function(list, index, stack, player)
return stack:get_count()
end,
allow_put = function(list, index, stack, player)
return stack:get_count()
end,
on_move = function() end,
on_take = function() end,
on_put = function() end,
}
end
end
local function room_for_item(stack, stack2)
return stack:is_empty() or stack2:is_empty() or
(stack:get_name() == stack2:get_name() and stack:get_free_space() >= stack2:get_count())
end
local function move(inv1, list1, index1, inv2, list2, index2, player, count)
local location1 = inv1:get_location()
local location2 = inv2:get_location()
local callbacks1 = get_callbacks(location1)
local callbacks2 = get_callbacks(location2)
local stack = inv1:get_stack(list1, index1)
local stack_to = inv2:get_stack(list2, index2)
if stack_to:get_name() ~= stack:get_name() and stack_to:get_count() > 0 then -- Disallow move to different type of item
return
end
if list2 == "craftpreview" then return end -- Disallow moving items into craftpreview
if list1 ~= "craftpreview" then
count = math.min(stack:get_count(), count)
stack:set_count(count)
count = math.min(count, stack_to:get_free_space())
else
local c = 0
local crafted_stack = ItemStack("")
while c < count do
local st = minetest.craft_predict(
minetest.get_craft_result(
{method = "normal",
items = inv1:get_list("craft"),
width = inv1:get_width("craft")}).item,
player,
inv1:get_list("craft"),
inv1)
--if not stack_to:room_for_item(st) then
if not room_for_item(stack_to, st) then
break
end
local old_grid = inv1:get_list("craft")
local out, decr_input = minetest.get_craft_result(
{method = "normal",
items = inv1:get_list("craft"),
width = inv1:get_width("craft")})
local item = out.item
inv1:set_list("craft", decr_input.items)
local crafted = minetest.on_craft(item, player, old_grid, inv1)
crafted_stack:add_item(crafted)
stack_to:add_item(crafted)
c = c + 1
end
stack = crafted_stack
count = stack:get_count()
end
if count <= 0 then return end
local count1, count2
if same_location(location1, location2) then
count1 = callbacks1.allow_move(list1, index1, list2, index2, count, player)
count2 = count1
else
count1 = callbacks1.allow_take(list1, index1, stack, player)
count2 = callbacks2.allow_put(list2, index2, stack, player)
end
if count1 >= 0 then
count = math.min(count, count1)
end
if count2 >= 0 then
count = math.min(count, count2)
end
if count == 0 then return end
stack:set_count(count)
if count1 >= 0 then
local s = inv1:get_stack(list1, index1)
s:take_item(count)
inv1:set_stack(list1, index1, s)
end
if count2 >= 0 then
local s = inv2:get_stack(list2, index2)
s:add_item(stack)
inv2:set_stack(list2, index2, s)
end
if same_location(location1, location2) then
callbacks1.on_move(list1, index1, list2, index2, count, player)
else
callbacks1.on_take(list1, index1, stack, player)
callbacks2.on_put(list2, index2, stack, player)
end
end
local function readC(cptr, addr)
return cptr[addr]
end
local function read(cptr, addr)
return cptr[addr] + 256 * cptr[u16(addr + 1)]
end
function tl.move_item(turtle, cptr, addr)
local from_id = readC(cptr, addr)
local to_id = readC(cptr, u16(addr + 1))
local from_index = read(cptr, u16(addr + 2))
local to_index = read(cptr, u16(addr + 4))
local count = read(cptr, u16(addr + 6))
local info = turtles.get_turtle_info(turtle)
local player = get_turtle_formspec_player(turtle)
if info.open_formspec then
local formspec = info.open_formspec
local from_elem = get_element_by_id(formspec, from_id)
local to_elem = get_element_by_id(formspec, to_id)
if from_elem and from_elem.location and to_elem and to_elem.location and
from_elem.start_index <= from_index and from_index < from_elem.start_index + from_elem.size and
to_elem.start_index <= to_index and to_index < to_elem.start_index + to_elem.size then
local from_inv = get_inventory_from_location(turtle, from_elem.location)
local to_inv = get_inventory_from_location(turtle, to_elem.location)
if from_inv and to_inv then
move(from_inv, from_elem.listname, from_index, to_inv, to_elem.listname, to_index, player, count)
end
end
end
end