function describe(prefix,stuff) local t=type(stuff) if(t == "table") then for key,value in pairs(stuff) do minetest.log(prefix.." "..key .. "=".. type(value)) describe(prefix.." ",value) end elseif(t=="nil" or t=="userdata") then minetest.log(prefix.." "..t) elseif(t=="number" or t=="string" or t=="boolean") then minetest.log(prefix.." "..value) else minetest.log(t) end end local cardgroups = { crumbly=1, falling_node=1, dig_immediate=3, card=1 } local pilegroups = { crumbly=1, dig_immediate=3 } local suit = { "club","diamond","heart","spade" } local suitcolorizeindex={ 2,1,1,2} local suitcolorize = { "\\^[colorize\\:#ff0000\\:alpha","\\^[colorize\\:#000000\\:alpha" } local rank = { "Ace","Two","Three","Four","Five","Six","Seven","Eight","Nine","Ten", "Jack","Queen","King"} local rank_short = { "a","2","3","4","5","6","7","8","9","t","j","q","k" } local card_shortname = {} local textures = {} local descriptions = {} local cardnames = {} local cardprefix="deck:card_" local cardprefixlen=string.len(cardprefix) local carddescriptions = {} local texturepositions = { {"50,50"}, -- a {"50,15","50,65"}, -- 2 {"50,2","50,42","50,84"}, -- 3 {"30,12","30,62","70,12","70,62"}, -- 4 {"30,2","80,2","60,40","35,75","85,75"}, -- 5 {"30,2","30,42","30,84","70,2","70,42","70,84"}, -- 6 {"40,2","40,42","40,84","80,2","80,42","80,84","5,62"}, -- 7 {"40,2","40,42","40,84","80,2","80,42","80,84","2,84","2,42"}, -- 8 {"48,2","48,42","48,84","88,2","88,42","88,84","10,84","10,42","10,2"}, -- 9 {"48,2","48,42","48,84","88,2","88,42","88,84","10,84","10,42","20,12","60,52"}, -- 10 {"33,1"}, -- J {"33,1"}, -- Q {"33,1"}, -- K } local function generate_descriptions() local i=1 local s, r for s=1,4,1 do for r=1,13,1 do descriptions[i]=rank[r].." of "..suit[s].."s" card_shortname[i]=rank_short[r]..string.sub(suit[s],1,1) textures[i]="deck_white.png^[combine:128x128" for p=1,table.getn(texturepositions[r]),1 do textures[i]=textures[i]..":"..texturepositions[r][p].."=deck_"..suit[s]..".png" end textures[i]=textures[i].. ":0,0=deck_"..rank_short[r]..".png"..suitcolorize[suitcolorizeindex[s]] i=i+1 end end end local function pile_add_card(inv,cardname) local s=inv:get_size("main") local place=s local i for i=1,s,1 do local stack=inv:get_stack("main",i) if stack:get_count() > 0 then place=i-1 break end end if place > 0 then inv:set_stack("main",place,cardname) minetest.log("deck_add_card done") return true end return false end local function pile_add_card_from_pos(inv,pos) local cardname=ItemStack(minetest.get_node(pos).name) return pile_add_card(inv,cardname) end local function flip_card(pos,formname,fields,sender) local n=minetest.get_node(pos) local pile if fields.to_stockpile then pile="deck:stockpile" elseif fields.to_chestpile then pile="deck:chestpile" else minetest.log("not flipped") return end minetest.log(n.name.." to "..pile) minetest.remove_node(pos) minetest.place_node(pos,{name=pile}) local meta=minetest.get_meta(pos) local inv=meta:get_inventory() pile_add_card(inv,n.name) minetest.close_formspec(sender:get_player_name(),"") end generate_descriptions() for i = 1,table.getn(textures),1 do local name=cardprefix..card_shortname[i] table.insert(cardnames,name) carddescriptions[name]=descriptions[i] minetest.register_node(name, { description = descriptions[i], groups = cardgroups, palette = "deck_palette.png", paramtype2 = "color", drawtype = "color", param2 = 4, on_construct = function(pos) local meta=minetest.get_meta(pos) meta:set_string("formspec", "size[3,3]".. "label[0,0;Flip card to make a]".. "button[0,1;2,1;to_stockpile;Stockpile]".. "button[0,2;2,1;to_chestpile;Chestpile]") end, on_receive_fields = flip_card, tiles = { textures[i] } }) end local function pile_inv_setup(pos, placer, itemstack, pointed_thing) local meta=minetest.get_meta(pos) local inv=meta:get_inventory() local invsize=13*4 if inv:set_size("main",invsize) then inv:set_width("main",13) minetest.log("deck_setup: size set to "..invsize) else minetest.log("deck_setup: failed to set size") end --for i=1,invsize,1 do -- local stack=inv:get_stack("main",i) --end end local function pile_pop(inv) local s=inv:get_size("main") local i for i=1,s,1 do local stack=inv:get_stack("main",i) if stack:get_count() > 0 then local item=stack:take_item(1) inv:set_stack("main",i,stack) return item end end end local function pile_peek_first(inv) local s=inv:get_size("main") for i=1,s,1 do local stack=inv:get_stack("main",i) if stack:get_count() > 0 then return stack:get_name() end end end local function add_to_inv(inv, cardname) local s=inv:get_size("main") for i=1,s,1 do local stack=inv:get_stack("main",i) if stack:get_count() == 0 then minetest.log(cardname) inv:set_stack("main",i,ItemStack(cardname)) return true end end return false end local function darken_pile(pos) minetest.log("darken pile: "..minetest.pos_to_string(pos)) local node=minetest.get_node(pos) node.param2=1 minetest.set_node(pos,node) end local function lighten_pile(pos) minetest.log("darken pile: "..minetest.pos_to_string(pos)) local node=minetest.get_node(pos) node.param2=0 minetest.set_node(pos,node) end local function defragment_pile(pos) local meta=minetest.get_meta(pos) local pile_inv=meta:get_inventory() local s=pile_inv:get_size("main") local search_start=s-1 for i=s,1,-1 do minetest.log("defrag:"..i) local stack=pile_inv:get_stack("main",i) if stack:is_empty() then for j=search_start,1,-1 do local st=pile_inv:get_stack("main",j) if st:is_empty() then minetest.log("defrag: empty stack i="..i.." j="..j) else pile_inv:set_stack("main",i,st) pile_inv:set_stack("main",j,ItemStack()) minetest.log("defrag:move"..j.."->"..i) search_start=j-1 if search_start==0 then minetest.log("defrag:exit at i="..i) return end break end if j==1 then minetest.log("defrag:exit at j=1") return end end elseif search_start > i-1 then search_start=i-1 end end end local function put_all_to_pile(pos,formname,fields,sender) local player_inv=minetest.get_inventory({type="player", name=sender:get_player_name()}) local meta=minetest.get_meta(pos) local pile_inv=meta:get_inventory() local s=player_inv:get_size("main") local i if pile_peek_first(pile_inv) == nil then lighten_pile(pos) end for i=1,s,1 do local stack=player_inv:get_stack("main",i) if stack:get_count() > 0 then local cardname=stack:get_name() if string.sub(cardname,1,cardprefixlen) == cardprefix then local item=stack:take_item(1) if item ~= nil then add_to_inv(pile_inv, cardname) player_inv:set_stack("main",i,stack) end end end end if pile_peek_first(pile_inv) == nil then darken_pile(pos) else defragment_pile(pos) end end local function draw_one_card(pos,formname,fields,sender) local player_inv=minetest.get_inventory({type="player", name=sender:get_player_name()}) local meta=minetest.get_meta(pos) local pile_inv=meta:get_inventory() if pile_inv == nil then minetest.log("pile inv=nil") return end local stack=pile_pop(pile_inv) if stack == nil then minetest.log("empty pile") darken_pile(pos) return false else player_inv:add_item("main",stack) if pile_peek_first(pile_inv) == nil then darken_pile(pos) else defragment_pile(pos) end return true end end local function shuffle_pile(pos,formname,fields,sender) local meta=minetest.get_meta(pos) local pile_inv=meta:get_inventory() local s=pile_inv:get_size("main") local newpos={} local i for i=1,s,1 do local try=math.random(s) while newpos[try] ~= nil do try=try+1 if try > s then try=1 end end newpos[try]=pile_inv:get_stack("main",i) end for i=1,s,1 do pile_inv:set_stack("main",i,newpos[i]) end defragment_pile(pos) end local function convert_pile(pos,nodename) local oldmeta=minetest.get_meta(pos) local oldinv=oldmeta:get_inventory() local s=oldinv:get_size("main") local cards={} for i=1,s,1 do local stack=oldinv:get_stack("main",i) cards[i]=stack:get_name() end minetest.remove_node(pos) minetest.place_node(pos,{name=nodename}) local newmeta=minetest.get_meta(pos) local newinv=newmeta:get_inventory() local s=oldinv:get_size("main") for i=1,s,1 do local stack=ItemStack(cards[i]) newinv:set_stack("main",i,stack) end defragment_pile(pos) end local function draw_card(pos,formname,fields,sender) if fields.draw then return draw_one_card(pos,formname,fields,sender) elseif fields.drawall then while draw_one_card(pos,formname,fields,sender) do end elseif fields.shuffle then shuffle_pile(pos,formname,fields,sender) elseif fields.tostock then minetest.close_formspec(sender:get_player_name(),"") convert_pile(pos,"deck:stockpile") elseif fields.alltopile then put_all_to_pile(pos,formname,fields,sender) end end local function on_dig_pile_getcards(pos,node,digger) local meta=minetest.get_meta(pos) local pile_inv=meta:get_inventory() local player_inv=minetest.get_inventory({type="player", name=digger:get_player_name()}) local stack=pile_pop(pile_inv) while stack ~= nil do player_inv:add_item("main",stack) stack=pile_pop(pile_inv) end minetest.remove_node(pos) end local function on_dig_pile_getpile(pos,node,digger) local meta=minetest.get_meta(pos) local pile_inv=meta:get_inventory() local player_inv=minetest.get_inventory({type="player", name=digger:get_player_name()}) local new_chestpile=ItemStack("deck:chestpile") local stackmeta=new_chestpile:get_meta() local i=1 local cardstack=pile_pop(pile_inv) if cardstack == nil then stackmeta:set_string("description","Empty pile") minetest.remove_node(pos) return end local descr="" while cardstack ~= nil do local cardname=cardstack:get_name() minetest.log("getpile: got "..cardname) stackmeta:set_string(i,cardname) cardstack=pile_pop(pile_inv) descr=descr..", "..carddescriptions[cardname] i=i+1 end stackmeta:set_string("description",string.sub(descr,3)) player_inv:add_item("main",new_chestpile) minetest.remove_node(pos) end local function after_place_pile(pos,placer,itemstack,pointed_thing) local stackmeta=itemstack:get_meta() local i=1 local card=stackmeta:get_string(i) if card == nil then stackmeta:set_string("description","Empty pile") darken_pile(pos) return end local pilemeta=minetest.get_meta(pos) local pile_inv=pilemeta:get_inventory() local descr="" while card ~= "" do minetest.log("after_place_pile: i="..i.." card="..card) pile_add_card(pile_inv,card) descr=descr..", "..carddescriptions[card] i=i+1 card=stackmeta:get_string(i) end stackmeta:set_string("description",string.sub(descr,3)) end minetest.register_node("deck:chestpile", { description = "Card pile that user has full access to. Works also like a minetest chest.", tiles = { "deck_back.png","deck_side.png" }, palette = "deck_palette.png", groups = pilegroups, paramtype2 = "color", drawtype = "color", on_construct = function(pos) pile_inv_setup(pos) local meta=minetest.get_meta(pos) meta:set_string("formspec", "size[13,11]".. "list[context;main;0,0;13,4;]".. "button[0,4;2,1;draw;Draw]".. "button[2,4;2,1;drawall;Draw all]".. "button[4,4;2,1;alltopile;Add all to pile]".. "button[6,4;2,1;shuffle;Shuffle cards]".. "button[8,4;2,1;tostock;Make stockpile]".. "list[current_player;main;0,6;13,5;]") end, on_dig = on_dig_pile_getpile, stack_max = 1, after_place_node=after_place_pile, on_receive_fields = draw_card }) minetest.register_node("deck:stockpile", { description = "Stock pile of cards. Can't be peeked.", groups = pilegroups, tiles = { "deck_back.png" }, palette = "deck_palette.png", paramtype2 = "color", drawtype = "color", on_construct = function(pos) pile_inv_setup(pos) local meta=minetest.get_meta(pos) meta:set_string("formspec","size[13,6]".. "button[0,0;2,1;draw;Draw]".. "button[2,0;2,1;drawall;Draw all]".. "button[4,0;2,1;alltopile;Add all to pile]".. "button[6,0;2,1;shuffle;Shuffle cards]".. "list[current_player;main;0,1;13,5;]" ) end, on_dig = on_dig_pile_getpile, stack_max = 1, after_place_node=after_place_pile, on_receive_fields = draw_card }) -- minetest.register_on_player_receive_fields(function(player, formname, fields) -- minetest.log("xformname="..formname) -- if fields.draw then -- minetest.chat_send_all("player "..player.name.."draw card") -- end -- end) minetest.register_abm({ label="Drop a card to deck", nodenames={"deck:chestpile","deck:stockpile"}, neighbors=cardnames, interval=1.0, chance = 1, action=function(pos,node,active_object_count,active_object_count_wider) local above = {x=pos.x,y=pos.y+1,z=pos.z} local abovenode = minetest.get_node(above) --minetest.log("abm1"..minetest.pos_to_string(pos).." "..node.name.. --""..abovenode.name) if string.sub(abovenode.name,1,cardprefixlen) ~= cardprefix then -- minetest.log("not card, but "..abovenode.name) return end local meta=minetest.get_meta(pos) local inv=meta:get_inventory() if pile_peek_first(inv) == nil then lighten_pile(pos) end if pile_add_card_from_pos(inv,above) then minetest.remove_node(above) while true do above={x=above.x,y=above.y+1,z=above.z} abovenode = minetest.get_node(above) if string.sub(abovenode.name,1,cardprefixlen) == cardprefix then minetest.spawn_falling_node(above) else return end end end end }) minetest.register_craft({ output = "deck:stockpile", recipe = {{"group:card"}} }) minetest.register_craft({ output = "deck:chestpile", recipe = {{"group:card"}} }) minetest.register_craft({ output = "deck:chestpile", recipe = {{ "default:paper" },{ "default:paper" }} }) local function craft_pile(itemstack,player,old_craft_grid,craft_inv,really) --describe("craft",old_craft_grid) -- local s=craft_inv:get_size("craft") local place, cardname local onlycards=true local onlypaper=true for key,value in pairs(old_craft_grid) do --local stack=craft_inv:get_stack("craft",i) local stack=old_craft_grid[key] if stack:is_empty() then --minetest.log("empty "..key) else place=key cardname=stack:get_name() if string.sub(cardname,1,10) ~= cardprefix then onlycards=false end if cardname ~= "default:paper" then onlypaper=false end minetest.log("craft:"..key.."="..stack:get_name()) end end if (onlycards==false and onlypaper==false) then return nil end if onlypaper then local resultname=itemstack:get_name() if resultname == "deck:chestpile" then local stackmeta=itemstack:get_meta() local i for i=1,52,1 do stackmeta:set_string(i,cardnames[i]) end return itemstack end return nil end local pilename if place < 5 then pilename="deck:chestpile" else pilename="deck:stockpile" end minetest.log("place="..place.." pilename="..pilename) local pilestack=ItemStack(pilename) local stackmeta=pilestack:get_meta() stackmeta:set_string(1,cardname) if really then stackmeta:set_string("description",carddescriptions[cardname]) end return pilestack end minetest.register_on_craft(function(itemstack,player,old_craft_grid,craft_inv) return craft_pile(itemstack,player,old_craft_grid,craft_inv,true) end) minetest.register_craft_predict(function(itemstack,player,old_craft_grid,craft_inv) return craft_pile(itemstack,player,old_craft_grid,craft_inv,false) end) minetest.register_on_joinplayer(function(player) --minetest.log(player:get_inventory_formspec()) player:get_inventory():set_size("main", 60) player:set_inventory_formspec("size[13,11]list[current_player;main;0,3.5;13,5;]list[current_player;craft;3,0;3,3;]listring[]list[current_player;craftpreview;7,1;1,1;]") --minetest.log(player:get_inventory_formspec()) end)