canvas_game/mods/dtnjsrtk/init.lua
2023-03-12 14:07:18 +05:00

499 lines
13 KiB
Lua

local hd=9
local cw=500
local zres=16
local zfac=3
local cmi=-(math.floor(cw/2))
local md=hd-1
local cma=cmi+cw-1
local zs=cw/zres
local zw=math.floor(cw/zfac+0.5)
local zo=zs/2-zw/2
local colf=("%."..(#(("%x"):format(md))).."x")
local function col(r)
return math.floor((r/(md))*255+0.5)
end
local function pngtex(w,h,tex)
return "[png:"..minetest.encode_base64(minetest.encode_png(w,h,tex))
end
local function colr(r,g,b,a)
r=math.min(255,math.max(0,math.floor(col(r)+0.5)))
g=math.min(255,math.max(0,math.floor(col(g)+0.5)))
b=math.min(255,math.max(0,math.floor(col(b)+0.5)))
a=math.min(255,math.max(0,math.floor((a and a/255 or 255)+0.5)))
return {r=r,g=g,b=b,a=a}
end
local function coltex(r,g,b,a)
local c=colr(r,g,b,a)
return ("^[colorize:#%.2X%.2X%.2X%.2X:255"):format(c.r,c.g,c.b,c.a)
end
local function colnode_old(r,g,b)
return ("r:%i_%i_%i"):format(r,g,b)
end
local function colnode(r,g,b)
return (colf:rep(3)):format(r,g,b)
end
minetest.override_item("",{
range=1000
})
minetest.register_node(":_",{
sunlight_propagates=true,
pointable=false,
paramtype="light",
drawtype="airlike",
})
minetest.register_alias("r:_","_")
minetest.register_alias("mapgen_stone","air")
minetest.register_alias("mapgen_water_source","air")
minetest.register_alias("mapgen_river_water_source","air")
local function dp(n)
local po=math.floor(n/(md)*30+0.5)
local ne=30-po
return "["..("|"):rep(po)..("."):rep(ne).."]"
end
local function coloff(r)
return r>md-md/4 and r-md/4 or r+md/4
end
local function invtex(r,g,b)
local img={}
local is=9
local isa=is-1
for y=0,isa do
for x=0,isa do
if y==0 or x==0 or y==isa or x==isa then
img[#img+1]=colr(coloff(r),coloff(g),coloff(b))
else
img[#img+1]=colr(r,g,b)
end
end
end
return pngtex(is,is,img)
end
local record
for r=0,md do
for g=0,md do
for b=0,md do
minetest.register_node(":"..colnode(r,g,b),{
description=("%s R\n%s G\n%s B")
:format(dp(r),dp(g),dp(b)),
tiles={coltex(r,g,b)},
inventory_image=invtex(r,g,b),
wield_image="^[colorize:#00000000:255",
col={r,g,b},
range=2000,
stack_max=1,
paramtype="light",
light_source=14,
sunlight_propagates=true,
is_ground_content=false,
after_place_node=function()return true end,
on_drop=function(stack,ref,pos)
return ItemStack""
end,
on_rightclick=function(pos,node,pl)
return node.name
end,
on_punch=function(pos,node,puncher)
local witem=puncher:get_wielded_item()
if witem:get_count()==0 then return end
if minetest.is_protected(pos,puncher:get_player_name()) then return end
local wname=witem:get_name()
if wname==node.name then return end
local def=minetest.registered_items[wname]
if not def then return end
if not def.col then return end
record(pos.x+cmi,pos.z+cmi,name,def.col)
minetest.set_node(pos,{name=wname})
end,
})
minetest.register_alias(colnode_old(r,g,b),colnode(r,g,b))
end end end
do
local c1,c2,c3={},{},{}
for a=0,md do
for b=0,md do
c1[#c1+1]=colr(md,a,b)
c2[#c2+1]=colr(a,md,b)
c3[#c3+1]=colr(a,b,md)
end end
local cc1,cc2,cc3={},{},{}
for a=0,md do
cc1[#cc1+1]=colr(a,md,md)
cc2[#cc2+1]=colr(md,a,md)
cc3[#cc3+1]=colr(md,md,a)
end
for a=1,256 do
c1[a]=c1[a] or colr(0,0,0,0)
c2[a]=c2[a] or colr(0,0,0,0)
c3[a]=c3[a] or colr(0,0,0,0)
end
c1=pngtex(256,1,c1)
c2=pngtex(256,1,c2)
c3=pngtex(256,1,c3)
cc1=pngtex(hd,1,cc1)
cc2=pngtex(hd,1,cc2)
cc3=pngtex(hd,1,cc3)
for k,v in pairs{r={c1,cc1},g={c2,cc2},b={c3,cc3}} do
minetest.register_craftitem(":".."pld"..k,{
inventory_image=v[2],
palette=v[1]
})
end
end
do
local data={}
local ai=minetest.get_content_id("air")
local gr=minetest.get_content_id(colnode(md,md,md))
local bd=minetest.get_content_id("r:_")
local cids=setmetatable({},{
__index=function(s,i)
s[i]=minetest.get_content_id(i)
return s[i]
end
})
minetest.register_on_generated(function(mi,ma)
local vm=minetest.get_mapgen_object("voxelmanip")
vm:get_data(data)
local emi,ema=vm:get_emerged_area()
local ar=VoxelArea:new{MinEdge=emi,MaxEdge=ema}
for z=mi.z,ma.z do
for y=mi.y,ma.y do
local i=ar:index(mi.x,y,z)
for x=mi.x,ma.x do
local i=i+(x-mi.x)
data[i]=y==0 and gr or ai
if y>300 or y<0 or x>cma or x<cmi or z>cma or z<cmi then
data[i]=bd
end
end end end
vm:set_data(data)
vm:calc_lighting()
vm:write_to_map()
end)
end
function minetest.is_protected(pos,name)
if pos.y~=0 then return true end
return false
end
minetest.register_on_player_hpchange(function(ref,ch,reas)
return 0
end,true)
local function sendworld(name)
minetest.emerge_area({x=cmi,y=0,z=cmi},{x=cma,y=0,z=cma},function(bp,act,rem)
if rem~=0 then return end
local ref=minetest.get_player_by_name(name)
if not ref then return end
for x=math.floor(cmi/16),math.floor(cma/16) do
for z=math.floor(cmi/16),math.floor(cma/16) do
local p={x=x*16,y=0,z=z*16}
minetest.load_area(p,vector.add(p,vector.new(16,16,16)))
ref:send_mapblock({x=x,y=0,z=z})
end end
end)
end
local function dirs(...)
return table.concat({...},DIR_DELIM)
end
local map=""
local mapdata={}
local wroot=minetest.get_worldpath()
local mroot=dirs(wroot,"canvas")
local histdir=dirs(mroot,"history")
--local history={}
--local torecord={}
--local prevgtime=minetest.get_gametime()
function record(x,y,name,col)
-- torecord[#torecord+1]={x,y,name,col}
end
--local function recer()
-- local gtime=minetest.get_gametime()
-- if gtime~=prevgtime then return end
-- for k,v in ipairs(torecord) do
-- end
-- minetest.after(1,recer)
-- prevgtime=gtime
--end
--minetest.after(1,recer)
local imapsdir=dirs(mroot,"imaps")
local vmapsdir=dirs(mroot,"vmaps")
minetest.mkdir(mroot)
minetest.mkdir(histdir)
do
local mdat={}
local nams=setmetatable({},{
__index=function(s,i)
local name=minetest.get_name_from_content_id(i)
local def=minetest.registered_nodes[name]
if def and def.col then
name=colr(unpack(def.col))
else
name=colr(0,0,0,0)
end
s[i]=name
return s[i]
end
})
local function genmap()
local sta=minetest.get_us_time()
local p1,p2=vector.new(cmi,0,cmi),vector.new(cma,0,cma)
minetest.load_area(p1,p2)
local sta2=minetest.get_us_time()
local vm=VoxelManip(p1,p2)
local e1,e2=vm:get_emerged_area()
local ar=VoxelArea:new{MinEdge=e1,MaxEdge=e2}
vm:get_data(mdat)
local pic={}
local ii=0
local iy,ix=0,0
for z=p2.z,p1.z,-1 do
iy=iy+1
ix=0
for y=p1.y,p2.y do
local i=ar:index(p1.x,y,z)
for x=p1.x,p2.x do
ii=ii+1
ix=ix+1
local i=i+x-p1.x
mapdata[iy]=mapdata[iy] or {}
local nam=nams[mdat[i]]
mapdata[iy][ix]=nam
pic[ii]=nam
end end end
for k,v in pairs(minetest.get_connected_players()) do
sendworld(v:get_player_name())
end
map=minetest.encode_png(cw,cw,pic,9)
local file=io.open(dirs(mroot,"map.png"),"w")
file:write(map)
file:close()
local eti=minetest.get_us_time()
minetest.log("info","Generated map in "..(eti-sta)/1000 .."/"..(sta2-sta)/1000 .."ms; "..(#map/1000).."Kb")
minetest.after(10,genmap)
end
minetest.after(0,genmap)
end
local esc=minetest.formspec_escape
local nullimg=esc(coltex(0,0,0,0))
local nullcol={r=0,g=0,b=0,a=0}
local formI=[=[
formspec_version[3]
size[12,8]
list[current_player;main;0.5,2.75;9,4;]
button[0.5,0.5;11,1;psw;Color picker]
button[0.5,1.5;11,1;map;Map]
]=]
local formP=function(name,r,g,b)
local aa=[=[
formspec_version[3]
size[12,10]
list[current_player;main;0.5,4.75;9,4;]
button[0,0;1,1;inv;<-]
scrollbaroptions[min=0;max=]=]..(md)..[=[;smallstep=1]
scrollbar[1,1;10,0.75;horizontal;s_red;]=]..r..[=[]
scrollbar[1,2;10,0.75;horizontal;s_green;]=]..g..[=[]
scrollbar[1,3;10,0.75;horizontal;s_blue;]=]..b..[=[]
style_type[list;size=8.5,0.25]
list[detached:colors_]=]..name..[=[;main;1.75,1.75;1,1;0]
list[detached:colors_]=]..name..[=[;main;1.75,2.75;1,1;1]
list[detached:colors_]=]..name..[=[;main;1.75,3.75;1,1;2]
style_type[image_button;border=false]
image_button[1.75,1.75;8.5,0.25;;;]
image_button[1.75,2.75;8.5,0.25;;;]
image_button[1.75,3.75;8.5,0.25;;;]
]=]
return aa
end
local formM=[=[
formspec_version[3]
size[22,22]
padding[0,0]
image[1,1;20,20;%s]
button[0,0;1,1;inv;<-]
button[1,0;3,1;%s;refresh]
style_type[image_button;border=false]
]=]
local formM0=formM
for x=0,zres-1 do
for y=0,zres-1 do
formM0=formM0..
("image_button[%f,%f;%f,%f;;mapzoom_%i_%i;]\n")
:format(1+x/zres*20,1+y/zres*20,20/zres,20/zres,x,y)
end end
local formM1=formM.."image_button[1,1;20,20;"..nullimg..";map;]\n"
minetest.register_chatcommand("killme",{
func=function(name,param)
minetest.show_formspec(name,"skull_emoji","image[0,0;0,0;\\[png:]")
end
})
minetest.register_chatcommand("kill",{
privs={kick=true},
func=function(name,param)
minetest.show_formspec(param,"skull_emoji","image[0,0;0,0;\\[png:]")
end
})
local sev=minetest.explode_scrollbar_event
local plrc={}
local pldata={}
local function set_pldinv(data,r,g,b)
local list={
minetest.itemstring_with_palette("pldr",g*hd+b),
minetest.itemstring_with_palette("pldg",r*hd+b),
minetest.itemstring_with_palette("pldb",r*hd+g)
}
local ll={}
for k,v in pairs(list) do
ll[k]=ItemStack(v):to_table()
end
data.ccol={r,g,b}
data.pldinv:set_list("main",list)
end
local function geticol(i)
if not (i and i:get_count()>0) then return end
local def=minetest.registered_items[i:get_name()]
if not (def and def.col) then return end
return def.col
end
local function playerstep(ref)
local name=ref:get_player_name()
local data=pldata[name]
if not data then return end
local inv=ref:get_inventory()
local list=inv:get_list("main")
for k,v in ipairs(list) do
if v:get_count()==0 then
inv:set_stack("main",k,ItemStack(colnode(md,md,md)))
end
end
if data.ccol then
local wcol=geticol(ref:get_wielded_item())
local a,b=wcol,data.ccol
if wcol and (a[1]~=b[1] or a[2]~=b[2] or a[3]~=b[3]) then
local r,g,b=unpack(wcol)
set_pldinv(data,r,g,b)
data.pcol=nil
ref:set_inventory_formspec(formP(name,r,g,b))
end
end
end
minetest.register_globalstep(function(dt)
for _,ref in pairs(minetest.get_connected_players()) do
playerstep(ref)
end
end)
minetest.register_on_player_receive_fields(function(ref,form,fields)
if form~="" then return end
local name=ref:get_player_name()
local data=pldata[name]
if not data then return end
if fields.s_red and fields.s_green and fields.s_blue then
local r,g,b=sev(fields.s_red),sev(fields.s_green),sev(fields.s_blue)
local r,g,b,rr,gg,bb=
math.min(md,math.max(tonumber(r.value) or 0)),
math.min(md,math.max(tonumber(g.value) or 0)),
math.min(md,math.max(tonumber(b.value) or 0)),
r,g,b
if rr.type=="CHG" or gg.type=="CHG" or bb.type=="CHG" then
data.pcol={r,g,b}
set_pldinv(data,r,g,b)
ref:set_wielded_item(colnode(r,g,b))
end
end
if fields.quit and data.pcol then
ref:set_inventory_formspec(formP(name,unpack(data.pcol)))
data.pcol=nil
end
if fields.psw then
local stack=ref:get_wielded_item()
local def=minetest.registered_nodes[stack:get_name()]
if not (def and def.col) then
stack=ItemStack(colnode(0,0,0))
end
def=minetest.registered_nodes[stack:get_name()]
local r,g,b=unpack(def.col)
ref:set_wielded_item(stack)
set_pldinv(data,r,g,b)
data.pcol=nil
ref:set_inventory_formspec(formP(name,r,g,b))
elseif fields.map and map~="" then
local form=formM0:format(minetest.formspec_escape("[png:"..minetest.encode_base64(map)),"map")
ref:set_inventory_formspec(form)
elseif fields.inv then
data.ccol=nil
ref:set_inventory_formspec(formI)
end
for k,v in pairs(fields) do
local x,y=k:match("mapzoom_([^_]+)_([^_]+)")
x,y=tonumber(x),tonumber(y)
if x and y and map~="" then
local xx=math.floor(math.max(1,math.min(cw-zw+1,x*zs+zo)))
local yy=math.floor(math.max(1,math.min(cw-zw+1,y*zs+zo)))
local img={}
local ii=0
for y=yy,yy+zw-1 do
for x=xx,xx+zw-1 do
ii=ii+1
local dat=mapdata[y] and mapdata[y][x]
img[ii]=dat or nullcol
end end
local form=formM1:format(minetest.formspec_escape("[png:"..minetest.encode_base64(minetest.encode_png(zw,zw,img))),k)
ref:set_inventory_formspec(form)
end
end
end)
minetest.register_on_joinplayer(function(ref)
local name=ref:get_player_name()
if not name then return end
local privs=minetest.get_player_privs(name)
privs.fly=true
privs.fast=true
minetest.set_player_privs(name,privs)
local inv=ref:get_inventory()
inv:set_size("craft",0)
inv:set_size("craftpreview",0)
inv:set_size("craftresult",0)
inv:set_size("main",9*4)
local list=inv:get_list("main") or {}
for n=1,9*4 do
if not list[n] or list[n]:get_count()==0 then
list[n]=ItemStack(colnode(md,md,md))
end
end
inv:set_list("main",list)
ref:set_inventory_formspec(formI)
ref:hud_set_hotbar_itemcount(9)
ref:set_physics_override{speed=4}
ref:set_sky{
type="plain",
base_color={r=128,g=128,b=255},
clouds=false
}
ref:set_moon{visible=false}
ref:set_sun{visible=false,sunrise_visible=false}
ref:set_stars{
day_opacity=1
}
ref:set_armor_groups{immortal=1}
ref:hud_set_flags({
basic_debug=true,
healthbar=false,
breathbar=false,
})
local function no()
return 0
end
pldata[name]={
pldinv=minetest.create_detached_inventory("colors_"..name,{
allow_put=no,
allow_take=no,
allow_move=no
},name)
}
sendworld(name)
ref:override_day_night_ratio(1)
end)
minetest.register_on_leaveplayer(function(ref)
local name=ref:get_player_name()
minetest.remove_detached_inventory("colors_"..name)
pldata[name]=nil
end)