--[[ maps – Minetest mod to render very ugly HUD maps Copyright © 2022 Nils Dagsson Moskopp (erlehmann) This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Dieses Programm hat das Ziel, die Medienkompetenz der Leser zu steigern. Gelegentlich packe ich sogar einen handfesten Buffer Overflow oder eine Format String Vulnerability zwischen die anderen Codezeilen und schreibe das auch nicht dran. ]]-- maps = {} maps.dots = {} maps.maps = {} maps.minp = {} maps.maxp = {} maps.work = {} maps.sent = {} maps.posx = {} maps.posz = {} local size = 80 local worldpath = minetest.get_worldpath() local textures_dir = worldpath .. "/maps/" minetest.mkdir(textures_dir) maps.create_map = function(pos, player_name) local minp = vector.multiply(vector.floor(vector.divide(pos, size)), size) local maxp = vector.add(minp, vector.new(size - 1, size - 1, size - 1)) local prefix, _ = minetest.pos_to_string(maxp) prefix, _ = prefix:gsub("%(", "") prefix, _ = prefix:gsub("%)", "") prefix, _ = prefix:gsub(",", "_") local filename = prefix .. ".tga" if maps.work[filename] then return end local player = minetest.get_player_by_name(player_name) if maps.sent[filename] then maps.minp[player_name] = minp maps.maxp[player_name] = maxp player:hud_change( maps.maps[player_name], "text", filename ) return end maps.work[filename] = true player:hud_change( maps.maps[player_name], "text", "blank.png" ) local emerge_callback = function( blockpos, action, calls_remaining ) if calls_remaining > 0 then return end local pixels = {} local colormap = { { 195, 175, 140 }, -- background { 60, 35, 16 }, -- dark line { 210, 170, 130 }, -- liquid light { 135, 90, 40 }, -- liquid dark { 150, 105, 55 }, -- more liquid { 165, 120, 70 }, -- more liquid { 150, 105, 55 }, -- more liquid { 60, 35, 16 }, -- tree outline { 150, 105, 55 }, -- tree fill } for x = 1,size,1 do for z = 1,size,1 do local color = { 0 } pixels[z] = pixels[z] or {} pixels[z][x] = color end end local positions = minetest.find_nodes_in_area_under_air( minp, maxp, "group:liquid" ) for _, p in ipairs(positions) do local z = p.z - minp.z + 1 local x = p.x - minp.x + 1 pixels[z][x] = { 2 } end -- draw coastline for x = 1,size,1 do for z = 1,size,1 do if pixels[z][x][1] >= 2 then pixels[z][x] = { 2 + ( z % 2 ) } -- stripes if pixels[z][x][1] == 3 then pixels[z][x] = { 3 + ( ( math.floor( x / 7 ) + math.floor( 1.3 * z * z ) ) % 4 ) } end if z > 1 and pixels[z-1][x][1] < 2 then pixels[z-1][x] = { 1 } pixels[z][x] = { 3 } end if z < size and pixels[z+1][x][1] < 2 then pixels[z+1][x] = { 1 } pixels[z][x] = { 3 } end if x > 1 and pixels[z][x-1][1] < 2 then pixels[z][x-1] = { 1 } pixels[z][x] = { 3 } end if x < size and pixels[z][x+1][1] < 2 then pixels[z][x+1] = { 1 } pixels[z][x] = { 3 } end end end end local positions = minetest.find_nodes_in_area_under_air( minp, maxp, { "group:leaves", "default:snow", -- snow-covered leaves } ) for _, p in ipairs(positions) do local z = p.z - minp.z + 1 local x = p.x - minp.x + 1 local node = minetest.get_node({ x=p.x, y=p.y - 4, z=p.z, }) local draw_tree = ( minetest.get_item_group( node.name, "tree" ) > 0 ) and ( z < size - 6 and x > 3 and x < size - 3 ) if draw_tree then local tree = {} if nil ~= node.name:find("pine") then tree = { " # ", "#####", "#...#", " #.# ", " #.# ", " # ", } else tree = { " # ", " # ", " ### ", "#...#", "#...#", "#...#", " ### ", } end local overlap = false for t_z = 1,#tree do for t_x = 1,#tree[t_z] do local color = pixels[z + t_z][x + t_x - 3][1] -- do not draw trees close to trees or water if color > 2 then overlap = true break end end if overlap then break end end if overlap then tree = {} end for t_z = 1,#tree do for t_x = 1,#tree[t_z] do local byte = tree[t_z]:byte(t_x) if 35 == byte then -- # pixels[z + t_z][x + t_x - 3] = { 7 } elseif 46 == byte then -- . pixels[z + t_z][x + t_x - 3] = { 8 } end end end end end local filepath = textures_dir .. filename tga_encoder.image(pixels):save( filepath, { colormap=colormap } ) minetest.dynamic_add_media( filepath, function() local player =minetest.get_player_by_name(player_name) player:hud_change( maps.maps[player_name], "text", filename ) maps.minp[player_name] = minp maps.maxp[player_name] = maxp maps.sent[filename] = true maps.work[filename] = false end ) end minetest.emerge_area( minp, maxp, emerge_callback ) end minetest.register_on_joinplayer( function(player) local player_name = player:get_player_name() local map_def = { hud_elem_type = "image", text = "blank.png", position = { x = 0.15, y = 0.90 }, alignment = { x = 0, y = -1 }, offset = { x = 0, y = 0 }, scale = { x = 4, y = 4 } } local dot_def = table.copy(map_def) dot_def.text = "maps_x.tga" -- "player.png^[resize:4x8" maps.maps[player_name] = player:hud_add(map_def) maps.dots[player_name] = player:hud_add(dot_def) maps.minp[player_name] = { x=-32000, y=0, z=0 } maps.maxp[player_name] = { x=-32000, y=0, z=0 } end ) local time_elapsed = 0 minetest.register_globalstep( function(dtime) time_elapsed = time_elapsed + dtime if time_elapsed < ( 1 / 30 ) then return -- fps limiter end local players = minetest.get_connected_players() for _, player in pairs(players) do local pos = vector.round(player:get_pos()) local player_name = player:get_player_name() if ( pos.x == maps.posx[player_name] and pos.z == maps.posz[player_name] ) then -- continue else local minp = maps.minp[player_name] local maxp = maps.maxp[player_name] if pos.x < minp.x then maps.create_map(pos, player_name) elseif pos.x > maxp.x then maps.create_map(pos, player_name) end if pos.z < minp.z then maps.create_map(pos, player_name) elseif pos.z > maxp.z then maps.create_map(pos, player_name) end local x = (pos.x - minp.x - (size/2)) * 4 local y = (minp.z - pos.z) * 4 - 2 player:hud_change( maps.dots[player_name], "offset", { x = x, y = y, } ) maps.posx[player_name] = pos.x maps.posz[player_name] = pos.z end end end )