-- Paint by MikuAuahDark

Paint={}
Paint.Map={}	-- [x][y]=RGB(Number)
Paint.Image={}	-- [x][y]=Image ID
Paint.Player={}	-- [id]={R,G,B,Paint Mode,Attack,Recent Color}	Attack: 0=no, 1=primary, 2=secondary, 3=pick color
-- Recent color: RGB(24bit)

-- User Configuration(UConfig)
Paint.Dir="sys/lua/paint/"	-- Save directory
Paint.Write=1			-- Save time in minutes, 0 = Save every any changes
Paint.Activate="serveraction"	-- Ways to activate paint mode. say = say !paint to toggle, serveraction = press serveraction1 to toggle
-- End UConfig

Paint.Binary=Text_MiniMapGen or function(v,size,big)
	local hex=string.format("%0"..(size*2).."X",v)
	local r=""
	if big then
		for i=1,size*2,2 do
			r=r..string.char(tonumber(hex:sub(i,i+1),16))
		end
	else
		for i=size*2-1,1,-2 do
			r=r..string.char(tonumber(hex:sub(i,i+1),16))
		end
	end
	return r
end

function Paint.PushRecent(id)
	local p=Paint.Player[id]
	local rt=p[6]
	for i=9,1,-1 do
		rt[i]=rt[i-1]
	end
	rt[1]=p[1]*65536+p[2]*256+p[3]
end

for x=0,map("xsize") do
	Paint.Image[x]={}
	Paint.Map[x]={}
end

function Paint.Save()	-- This function writes to bitmap image. Nice right?
	local temp={}
	temp[1]=io.open(Paint.Dir.."/"..game("sv_map")..".bmp","wb")
	temp[2]=io.open(Paint.Dir.."/"..game("sv_map")..".dat","w")
	temp[1]:write("BM\0\0\0\0\0\0\0\0\54\0\0\0\40\0\0\0"..Paint.Binary(map("xsize")+1,4,false)..Paint.Binary(map("ysize")+1,4,false).."\1\0\24\0\0\0\0\0\0\0\0\0\196\14\0\0\196\14\0\0\0\0\0\0\0\0\0\0")
	for y=map("ysize"),0,-1 do
		for x=0,map("xsize") do
			temp[1]:write(Paint.Binary(Paint.Map[x][y] or 16777215,3,true))
			temp[2]:write(Paint.Map[x][y] and "1" or "0")
		end
		temp[1]:write(string.rep("\0",(map("xsize")+1)%4))
	end
	temp[2]:close()
	local size=temp[1]:seek("end")
	temp[1]:seek("set",2)
	temp[1]:write(Paint.Binary(size,4,false))
	temp[1]:close()
end

Paint.Loaded=false
function Paint.Load()
	local temp={}
	temp[1]=io.open(Paint.Dir.."/"..game("sv_map")..".bmp","rb")
	temp[2]=io.open(Paint.Dir.."/"..game("sv_map")..".dat","r")
	if temp[1] and temp[2] then
		temp[1]:read(54)
		for y=map("ysize"),0,-1 do
			for x=0,map("xsize") do
				local RGBRaw=temp[1]:read(3)
				if temp[2]:read(1)=="1" then
					local RGB=RGBRaw:sub(3,3):byte()+RGBRaw:sub(2,2):byte()*256+RGBRaw:sub(1,1):byte()*65536
					Paint.Map[x][y]=RGB
					Paint.Image[x][y]=image("gfx/block.bmp",x*32+16,y*32+16,0)
					imagealpha(Paint.Image[x][y],0)
					tween_alpha(Paint.Image[x][y],1000,1)
					imagecolor(Paint.Image[x][y],RGBRaw:sub(3,3):byte(),RGBRaw:sub(2,2):byte(),RGBRaw:sub(1,1):byte())
				end
			end
			if (map("xsize")+1)%4>0 then
				temp[1]:read((map("xsize")+1)%4)
			end
		end
		temp[1]:close()
		temp[2]:close()
	end
end

addhook("startround","Paint.Startround")
function Paint.Startround()
	if Paint.Loaded==false then
		Paint.Load()
		Paint.Loaded=true
	else
		for x=0,map("xsize") do
			Paint.Image[x]={}
			Paint.Map[x]={}
		end
		Paint.Load()
	end
end
Paint.Startround()

addhook("join","Paint.Join")
function Paint.Join(id)
	Paint.Player[id]={255,255,255,false,0,{}}
end

for i=1,32 do
	Paint.Join(i)
end

if Paint.Activate=="say" then
addhook("say","Paint.Say",-32767)
end
function Paint.Say(id,txt)
	if txt:find("!paint")==1 then
		Paint.Player[id][4]=not Paint.Player[id][4]
		msg2(id,"\169000255000Paint mode "..(Paint.Player[id][4] and "" or "de").."activated!")
		return 1
	end
end

addhook("serveraction","Paint.Serveraction")
function Paint.Serveraction(id,a)
	if a==1 and Paint.Activate=="serveraction" then
		Paint.Say(id,"!paint")
	elseif a==2 then
		menu(id,"Edit Paint Color,Red|"..Paint.Player[id][1]..",Green|"..Paint.Player[id][2]..",Blue|"..Paint.Player[id][3]..",Show Sample,Recent Colors")
	elseif a==3 then
		Paint.Player[id][5]=3
		reqcld(id,2)
	end
end

addhook("attack","Paint.Attack")
function Paint.Attack(id)
	if player(id,"weapon")==50 and Paint.Player[id][4] then
		Paint.Player[id][5]=1
		reqcld(id,2)
	end
end

addhook("attack2","Paint.Attack2")
function Paint.Attack2(id)
	if player(id,"weapon")==50 and Paint.Player[id][4] then
		Paint.Player[id][5]=2
		reqcld(id,2)
	end
end

addhook("clientdata","Paint.Clientdata")
function Paint.Clientdata(id,mode,x,y)
	if mode==2 then
		local TileX,TileY=math.floor(x/32),math.floor(y/32)
		if TileX<=map("xsize") and TileY<=map("ysize") and TileX>=0 and TileY>=0 then
			if Paint.Player[id][5]==1 then
				if Paint.Image[TileX][TileY]==nil then
					if tile(TileX,TileY,"wall")==false and tile(TileX,TileY,"obstacle")==false then
						local i=image("gfx/block.bmp",TileX*32+16,TileY*32+16,0)
						local p=Paint.Player[id]
						imagecolor(i,p[1],p[2],p[3])
						imagealpha(i,0)
						tween_alpha(i,1000,1)
						Paint.Image[TileX][TileY]=i
						Paint.Map[TileX][TileY]=p[1]+p[2]*256+p[3]*65536
						local rgb=p[1]*65536+p[2]*256+p[3]
						if rgb~=p[6][1] then
							Paint.PushRecent(id)
						end
					else
						msg2(id,"\169255000000You can't draw on wall/obstacle!")
					end
				else
					tween_color(Paint.Image[TileX][TileY],1000,Paint.Player[id][1],Paint.Player[id][2],Paint.Player[id][3])
					Paint.Map[TileX][TileY]=Paint.Player[id][1]+Paint.Player[id][2]*256+Paint.Player[id][3]*65536
				end
			elseif Paint.Player[id][5]==2 then
				if Paint.Image[TileX][TileY] then
					freeimage(Paint.Image[TileX][TileY])
					Paint.Map[TileX][TileY]=nil
					Paint.Image[TileX][TileY]=nil
				end
			elseif Paint.Player[id][5]==3 then
				if Paint.Image[TileX][TileY] then
					local p=Paint.Player[id]
					local rgb=Paint.Map[TileX][TileY]
					p[1]=rgb%256
					p[2]=math.floor(rgb/256)%256
					p[3]=math.floor(rgb/256/256)
					msg2(id,"\169"..string.format("%03d%03d%03d",p[1],p[2],p[3]).."Color picked!")
				end
			end
			if Paint.Write==0 then
				Paint.Save()
			end
			Paint.Player[id][5]=0
		end
	end
end

addhook("menu","Paint.Menu")
function Paint.Menu(id,men,sel)
	if men=="Edit Paint Color" then
		local i,d={},{}
		if sel<4 and sel>0 then
			i[1],i[2],i[3],d[1],d[2],d[3]=Paint.Player[id][sel]+1,Paint.Player[id][sel]+10,Paint.Player[id][sel]+100,Paint.Player[id][sel]-1,Paint.Player[id][sel]-10,Paint.Player[id][sel]-100
		end
		if sel==1 then
			menu(id,"Paint Color Red - "..Paint.Player[id][1]..",Increase 1|"..(i[1]>255 and 255 or i[1])..",Increase 10|"..(i[2]>255 and 255 or i[2])..",Increase 100|"..(i[3]>255 and 255 or i[3])..",Decrease 1|"..(d[1]>0 and d[1] or 0)..",Decrease 10|"..(d[2]>0 and d[2] or 0)..",Decrease 100|"..(d[3]>0 and d[3] or 0))
		elseif sel==2 then
			menu(id,"Paint Color Green - "..Paint.Player[id][2]..",Increase 1|"..(i[1]>255 and 255 or i[1])..",Increase 10|"..(i[2]>255 and 255 or i[2])..",Increase 100|"..(i[3]>255 and 255 or i[3])..",Decrease 1|"..(d[1]>0 and d[1] or 0)..",Decrease 10|"..(d[2]>0 and d[2] or 0)..",Decrease 100|"..(d[3]>0 and d[3] or 0))
		elseif sel==3 then
			menu(id,"Paint Color Blue - "..Paint.Player[id][3]..",Increase 1|"..(i[1]>255 and 255 or i[1])..",Increase 10|"..(i[2]>255 and 255 or i[2])..",Increase 100|"..(i[3]>255 and 255 or i[3])..",Decrease 1|"..(d[1]>0 and d[1] or 0)..",Decrease 10|"..(d[2]>0 and d[2] or 0)..",Decrease 100|"..(d[3]>0 and d[3] or 0))
		elseif sel==4 then
			msg2(id,"\169"..string.format("%03d%03d%03d",Paint.Player[id][1],Paint.Player[id][2],Paint.Player[id][3]).."This is a Sample Message that have color that you choose!")
		elseif sel==5 then
			local lpstr={"Recent Colors",""}
			for n,v in pairs(Paint.Player[id][6]) do
				lpstr[n+1]="R: "..math.floor(v/256/256).." G: "..(math.floor(v/256)%256).." B: "..v%256
			end
			menu(id,table.concat(lpstr,","))
		end
	elseif men:find("Paint Color")==1 then
		if sel==0 then
			Paint.Serveraction(id,2)
		else
			local Col=men:match("Paint Color (%S+)")
			local Cur=tonumber(men:match("Paint Color %S+ %- (%d+)"))
			local R=0
			local I=0
			if sel>0 and sel<4 then
				R=Cur+10^(sel-1)
			elseif sel>3 and sel<7 then
				R=Cur-10^(sel-4)
			end
			if Col=="Red" then
				I=1
			elseif Col=="Green" then
				I=2
			elseif Col=="Blue" then
				I=3
			end
			if R>255 then R=255
			elseif R<0 then R=0 end
			Paint.Player[id][I]=R
			Paint.Menu(id,"Edit Paint Color",I)
		end
	elseif men=="Recent Colors" then
		if sel>0 then
			local p=Paint.Player[id]
			if p[6][sel]~=nil then
				local rgb=p[6][sel]
				p[1]=rgb%256
				p[2]=math.floor(rgb/256)%256
				p[3]=math.floor(rgb/256)%256
			end
		else
			Paint.Serveraction(id,2)
		end
	end
end

if Paint.Write>0 then
addhook("second","Paint.Second")
end
function Paint.Second()
	if os.time()%(Paint.Write*60)==0 then
		Paint.Save()
	end
end