deck-cd2025/init.lua

676 lines
20 KiB
Lua
Raw Normal View History

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.." "..t..": "..stuff)
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 }
2020-05-03 00:30:37 +03:00
local suit = { "club","diamond","heart","spade" }
2020-06-09 17:58:06 +03:00
local suitcolorizeindex={ 2,1,1,2}
2020-06-09 19:09:59 +03:00
local suitcolorize = { "\\^[colorize\\:#ff0000\\:alpha","\\^[colorize\\:#000000\\:alpha" }
local rank = { "Ace","Two","Three","Four","Five","Six","Seven","Eight","Nine","Ten",
2020-06-01 21:47:46 +03:00
"Jack","Queen","King"}
local rank_short = { "a","2","3","4","5","6","7","8","9","t","j","q","k" }
2020-05-03 00:30:37 +03:00
local card_shortname = {}
2020-06-01 21:47:46 +03:00
local textures = {}
2020-05-03 00:30:37 +03:00
2020-06-01 21:47:46 +03:00
local descriptions = {}
2020-05-03 00:30:37 +03:00
local cardnames = {}
local cardprefix="deck:card_"
local cardprefixlen=string.len(cardprefix)
2020-05-15 20:26:42 +03:00
local carddescriptions = {}
local texturepositions = {
2020-06-14 19:21:30 +03:00
-- These are a bit crowded looking positions for 128x128 texture
-- {"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
{"32,28"}, -- a
{"32,28"}, -- 2
{"32,28"}, -- 3
{"32,28"}, -- 4
{"32,28"}, -- 5
{"32,28"}, -- 6
{"32,28"}, -- 7
{"32,28"}, -- 8
{"32,28"}, -- 9
{"32,28"}, -- 10
{"32,28"}, -- J
{"32,28"}, -- Q
{"32,28"}, -- K
}
2020-05-03 00:30:37 +03:00
2020-06-01 21:47:46 +03:00
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)
2020-06-14 19:21:30 +03:00
textures[i]="deck_white.png^[resize:96x96^[combine:96x96"
for p=1,table.getn(texturepositions[r]),1 do
textures[i]=textures[i]..":"..texturepositions[r][p].."=deck_"..suit[s]..".png"
end
2020-06-09 19:09:59 +03:00
textures[i]=textures[i]..
2020-06-14 19:21:30 +03:00
":3,28=deck_"..rank_short[r]..".png"..suitcolorize[suitcolorizeindex[s]]
2020-06-01 21:47:46 +03:00
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
2020-06-01 21:47:46 +03:00
generate_descriptions()
2020-05-03 00:30:37 +03:00
for i = 1,table.getn(textures),1 do
local name=cardprefix..card_shortname[i]
2020-05-03 00:30:37 +03:00
table.insert(cardnames,name)
2020-05-15 20:26:42 +03:00
carddescriptions[name]=descriptions[i]
minetest.register_node(name, {
description = descriptions[i],
groups = cardgroups,
palette = "deck_palette.png",
paramtype2 = "color",
2020-06-14 19:21:30 +03:00
drawtype = "normal",
param2 = 4,
2020-05-15 20:26:42 +03:00
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] }
2020-05-15 20:26:42 +03:00
})
2020-05-03 00:30:37 +03:00
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
2020-05-03 00:30:37 +03:00
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
2020-05-15 20:40:11 +03:00
local function draw_one_card(pos,formname,fields,sender)
2020-05-03 00:30:37 +03:00
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)
2020-05-15 20:40:11 +03:00
return false
2020-05-03 00:30:37 +03:00
else
player_inv:add_item("main",stack)
if pile_peek_first(pile_inv) == nil then
darken_pile(pos)
else
defragment_pile(pos)
end
2020-05-15 20:40:11 +03:00
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
2020-05-15 20:40:11 +03:00
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
2020-05-03 00:30:37 +03:00
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)
2020-05-03 00:30:37 +03:00
end
end
2020-05-09 21:41:18 +03:00
2020-05-15 20:26:42 +03:00
local function on_dig_pile_getcards(pos,node,digger)
2020-05-09 21:41:18 +03:00
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
2020-05-15 20:26:42 +03:00
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")
2020-06-01 21:56:10 +03:00
minetest.remove_node(pos)
2020-05-15 20:26:42 +03:00
return
end
local descr=""
while cardstack ~= nil do
local cardname=cardstack:get_name()
2020-06-02 21:48:30 +03:00
minetest.log("getpile: got "..cardname)
2020-05-15 20:26:42 +03:00
stackmeta:set_string(i,cardname)
cardstack=pile_pop(pile_inv)
descr=descr..", "..carddescriptions[cardname]
2020-06-02 21:48:30 +03:00
i=i+1
2020-05-15 20:26:42 +03:00
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")
2020-06-02 21:48:30 +03:00
darken_pile(pos)
2020-05-15 20:26:42 +03:00
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
local function describe_cardtable(pos)
local meta=minetest.get_meta(pos)
local positions=minetest.deserialize(meta:get_string("cardtable_positions"))
for key,p in ipairs(positions) do
minetest.log("cardtable piece in "..minetest.pos_to_string(p))
end
end
local function add_node_to_cardtable(main_pos,new_pos)
minetest.log("add "..minetest.pos_to_string(new_pos).." to old cardtable with main pos="..minetest.pos_to_string(main_pos))
local new_meta=minetest.get_meta(new_pos)
local main_meta=minetest.get_meta(main_pos)
local positions=minetest.deserialize(main_meta:get_string("cardtable_positions"))
table.insert(positions,new_pos)
main_meta:set_string("cardtable_positions",minetest.serialize(positions))
new_meta:set_string("cardtable_main_x",main_pos.x)
new_meta:set_string("cardtable_main_y",main_pos.y)
new_meta:set_string("cardtable_main_z",main_pos.z)
describe_cardtable(main_pos)
end
local function on_construct_cardtable(pos)
minetest.log("construct cardtable")
local around={
{x=pos.x-1, y=pos.y, z=pos.z-1},{x=pos.x,y=pos.y,z=pos.z-1},{x=pos.x+1,y=pos.y,z=pos.z-1},
{x=pos.x-1, y=pos.y, z=pos.z}, {x=pos.x+1,y=pos.y,z=pos.z},
{x=pos.x-1, y=pos.y, z=pos.z+1},{x=pos.x,y=pos.y,z=pos.z+1},{x=pos.x+1,y=pos.y,z=pos.z+1}
}
for key,p in ipairs(around) do
local n=minetest.get_node(p)
if n.name == "deck:cardtable" then
local meta=minetest.get_meta(p)
local tmx=meta:get_string("cardtable_main_x")
local tmz=meta:get_string("cardtable_main_z")
add_node_to_cardtable({x=tmx,y=pos.y,z=tmz},pos)
return
end
end
-- this is a new cardtable
minetest.log("new cardtable")
local meta=minetest.get_meta(pos)
meta:set_string("cardtable_main_x",pos.x)
meta:set_string("cardtable_main_y",pos.y)
meta:set_string("cardtable_main_z",pos.z)
meta:set_string("cardtable_positions",minetest.serialize({pos}))
describe_cardtable(pos)
end
local function after_dig_cardtable(pos, oldnode, oldmeta, digger)
minetest.log("after dig")
describe("after_dig_meta",oldmeta)
local meta=oldmeta["fields"]
local tmx=meta["cardtable_main_x"]
local tmy=meta["cardtable_main_y"]
local tmz=meta["cardtable_main_z"]
if(pos.x==tonumber(tmx) and pos.y==tonumber(tmy) and pos.z==tonumber(tmz)) then
minetest.log("digged main node of cardtable at "..minetest.pos_to_string(pos))
local positions=minetest.deserialize(meta["cardtable_positions"])
for i,pos in ipairs(positions) do
minetest.remove_node(pos)
minetest.log("removing at "..minetest.pos_to_string(pos).." too.")
end
else
minetest.log("digged non-main node of cardtable. main="..tmx..","..tmy..","..tmz.." digged="..minetest.pos_to_string(pos))
end
end
2020-05-03 00:30:37 +03:00
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",
2020-05-03 00:30:37 +03:00
groups = pilegroups,
paramtype2 = "color",
drawtype = "color",
2020-05-15 20:26:42 +03:00
on_construct = function(pos)
pile_inv_setup(pos)
2020-05-03 00:30:37 +03:00
local meta=minetest.get_meta(pos)
2020-06-03 22:01:25 +03:00
meta:set_string("formspec", "size[13,11]"..
2020-05-15 20:40:11 +03:00
"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]"..
2020-06-03 22:01:25 +03:00
"list[current_player;main;0,6;13,5;]")
2020-05-03 00:30:37 +03:00
end,
2020-05-15 20:26:42 +03:00
on_dig = on_dig_pile_getpile,
stack_max = 1,
after_place_node=after_place_pile,
2020-05-03 00:30:37 +03:00
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",
2020-05-15 20:26:42 +03:00
on_construct = function(pos)
pile_inv_setup(pos)
2020-05-03 00:30:37 +03:00
local meta=minetest.get_meta(pos)
2020-06-09 19:43:22 +03:00
meta:set_string("formspec","size[13,6]"..
2020-05-15 20:40:11 +03:00
"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]"..
2020-06-09 19:43:22 +03:00
"list[current_player;main;0,1;13,5;]"
2020-05-03 00:30:37 +03:00
)
end,
2020-05-15 20:26:42 +03:00
on_dig = on_dig_pile_getpile,
stack_max = 1,
after_place_node=after_place_pile,
2020-05-03 00:30:37 +03:00
on_receive_fields = draw_card
})
minetest.register_node("deck:cardtable", {
description = "Table where cards can be easily dealt",
tiles = { "deck_table.png" },
on_construct = on_construct_cardtable,
groups = {crumbly=1, dig_immediate=3},
after_dig_node = after_dig_cardtable
})
2020-05-03 00:30:37 +03:00
-- 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
2020-05-03 00:30:37 +03:00
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
2020-05-03 00:30:37 +03:00
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" }}
})
minetest.register_craft({
output = "deck:cardtable 99",
recipe = {{ "group:wood", "group:wood"},{"group:wood","group:wood"}}
})
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()
2020-06-02 21:48:30 +03:00
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)
2020-06-03 22:01:25 +03:00
minetest.register_on_joinplayer(function(player)
--minetest.log(player:get_inventory_formspec())
2020-06-03 22:01:25 +03:00
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())
2020-06-03 22:01:25 +03:00
end)