From b880c1c53a2bf2f8256804bcb504267718fb179d Mon Sep 17 00:00:00 2001 From: paramat Date: Wed, 8 Mar 2017 15:53:54 +0000 Subject: [PATCH] Only 'dofiles' in init.lua. Add mapgen.lua. Add spacesuit glove and texture. Improve rover textures. Change spacesuit cap to black. Don't include internal character.png. Update rover 'on place', 'punch' and 'rightclick' functions to current boat code --- README.txt | 2 +- init.lua | 564 +----------------------- mapgen.lua | 578 +++++++++++++++++++++++++ nodes.lua | 21 + rover.lua | 179 ++++---- textures/moonrealm_character.png | Bin 2754 -> 0 bytes textures/moonrealm_glove.png | Bin 0 -> 110 bytes textures/moonrealm_rover_back.png | Bin 199 -> 205 bytes textures/moonrealm_rover_base.png | Bin 98 -> 115 bytes textures/moonrealm_rover_front.png | Bin 176 -> 165 bytes textures/moonrealm_rover_left.png | Bin 207 -> 225 bytes textures/moonrealm_rover_right.png | Bin 201 -> 222 bytes textures/moonrealm_space_character.png | Bin 701 -> 625 bytes 13 files changed, 679 insertions(+), 665 deletions(-) create mode 100644 mapgen.lua delete mode 100644 textures/moonrealm_character.png create mode 100644 textures/moonrealm_glove.png diff --git a/README.txt b/README.txt index 5df0457..34109c6 100644 --- a/README.txt +++ b/README.txt @@ -1,4 +1,4 @@ -moonrealm 0.10.1 by paramat +moonrealm 0.10.2 by paramat For Minetest 0.4.14 or later Depends default Licenses: Code LGPL 2.1. Media CC BY-SA 3.0 diff --git a/init.lua b/init.lua index d714646..ea054e0 100644 --- a/init.lua +++ b/init.lua @@ -1,569 +1,7 @@ --- Parameters - -local YMIN = -8000 -- Approx lower limit -local GRADCEN = 1 -- Gradient centre / terrain centre average level -local YMAX = 8000 -- Approx upper limit -local XMIN = -8000 -- Approx horizontal limits -local XMAX = 8000 -local ZMIN = -8000 -local ZMAX = 8000 - -local CENAMP = 64 -- Grad centre amplitude, terrain centre is varied by this -local HIGRAD = 128 -- Surface generating noise gradient above gradcen, controls depth of upper terrain -local LOGRAD = 128 -- Surface generating noise gradient below gradcen, controls depth of lower terrain -local HEXP = 0.5 -- Noise offset exponent above gradcen, 1 = normal 3D perlin terrain -local LEXP = 2 -- Noise offset exponent below gradcen -local STOT = 0.04 -- Stone density threshold, depth of dust - -local ICECHA = 1 / (13 * 13 * 13) -- Ice chance per dust node at terrain centre, decreases with altitude -local ICEGRAD = 128 -- Ice gradient, vertical distance for no ice -local ORECHA = 7 * 7 * 7 -- Ore 1/x chance per stone node -local TFIS = 0.01 -- Fissure threshold. Controls size of fissures -local FOOT = true -- Footprints in dust - --- 3D noise for terrain - -local np_terrain = { - offset = 0, - scale = 1, - spread = {x = 384, y = 384, z = 384}, - seed = 58588900033, - octaves = 5, - persist = 0.67 -} - --- 3D noise for alt terrain, 414 / 256 = golden ratio - -local np_terralt = { - offset = 0, - scale = 1, - spread = {x = 311, y = 311, z = 311}, - seed = 13331930910, - octaves = 5, - persist = 0.67 -} - --- 2D noise for smooth terrain - -local np_smooth = { - offset = 0, - scale = 1, - spread = {x = 512, y = 512, z = 512}, - seed = 113, - octaves = 3, - persist = 0.4 -} - --- 3D noise for fissures - -local np_fissure = { - offset = 0, - scale = 1, - spread = {x = 192, y = 192, z = 192}, - seed = 8181112, - octaves = 4, - persist = 0.5 -} - - --- 3D noise for faults - -local np_fault = { - offset = 0, - scale = 1, - spread = {x = 414, y = 828, z = 414}, - seed = 14440002, - octaves = 4, - persist = 0.5 -} - --- 2D noise for terrain centre - -local np_gradcen = { - offset = 0, - scale = 1, - spread = {x = 1024, y = 1024, z = 1024}, - seed = 9344, - octaves = 4, - persist = 0.4 -} - --- 2D noise for terrain blend - -local np_terblen = { - offset = 0, - scale = 1, - spread = {x = 1024, y = 1024, z = 1024}, - seed = -13002, - octaves = 3, - persist = 0.4 -} - - -- Do files dofile(minetest.get_modpath("moonrealm") .. "/nodes.lua") dofile(minetest.get_modpath("moonrealm") .. "/crafting.lua") dofile(minetest.get_modpath("moonrealm") .. "/functions.lua") dofile(minetest.get_modpath("moonrealm") .. "/rover.lua") - - --- Set mapgen parameters - -minetest.set_mapgen_params({mgname = "singlenode", water_level = -31000}) - - --- Player positions, spacesuit texture status - -local player_pos = {} -local player_pos_previous = {} -local player_spacesuit = {} - -minetest.register_on_joinplayer(function(player) - player_pos_previous[player:get_player_name()] = {x = 0, y = 0, z = 0} - - if player:get_inventory():contains_item("main", "moonrealm:spacesuit") then - player:set_properties({textures = {"moonrealm_space_character.png"}}) - player_spacesuit[player:get_player_name()] = true - else - player:set_properties({textures = {"moonrealm_character.png"}}) - player_spacesuit[player:get_player_name()] = false - end -end) - -minetest.register_on_leaveplayer(function(player) - player_pos_previous[player:get_player_name()] = nil - player_spacesuit[player:get_player_name()] = nil -end) - - --- Globalstep function - -minetest.register_globalstep(function(dtime) - for _, player in ipairs(minetest.get_connected_players()) do - if FOOT and math.random() < 0.15 and -- footprints - player_pos_previous[player:get_player_name()] ~= nil then - local pos = player:getpos() - player_pos[player:get_player_name()] = { - x = math.floor(pos.x + 0.5), - y = math.floor(pos.y + 0.2), - z = math.floor(pos.z + 0.5) - } - local p_ground = { - x = math.floor(pos.x + 0.5), - y = math.floor(pos.y + 0.4), - z = math.floor(pos.z + 0.5) - } - local n_ground = minetest.get_node(p_ground).name - local p_groundpl = { - x = math.floor(pos.x + 0.5), - y = math.floor(pos.y - 0.5), - z = math.floor(pos.z + 0.5) - } - if player_pos[player:get_player_name()].x ~= - player_pos_previous[player:get_player_name()].x or - player_pos[player:get_player_name()].y < - player_pos_previous[player:get_player_name()].y or - player_pos[player:get_player_name()].z ~= - player_pos_previous[player:get_player_name()].z then - if n_ground == "moonrealm:dust" then - if math.random() < 0.5 then - minetest.add_node( - p_groundpl, - {name = "moonrealm:dustprint1"} - ) - else - minetest.add_node( - p_groundpl, - {name = "moonrealm:dustprint2"} - ) - end - end - end - player_pos_previous[player:get_player_name()] = { - x = player_pos[player:get_player_name()].x, - y = player_pos[player:get_player_name()].y, - z = player_pos[player:get_player_name()].z - } - end - - if math.random() < 0.04 then -- spacesuit restores breath, reset spacesuit texture - if player:get_inventory():contains_item("main", "moonrealm:spacesuit") then - if player:get_breath() < 10 then - player:set_breath(10) - end - - if player_spacesuit[player:get_player_name()] == false then -- if no spacesuit texture, add - player:set_properties({textures = {"moonrealm_space_character.png"}}) - player_spacesuit[player:get_player_name()] = true - end - else -- no spacesuit in inventory - if player_spacesuit[player:get_player_name()] == true then -- if spacesuit texture, remove - player:set_properties({textures = {"moonrealm_character.png"}}) - player_spacesuit[player:get_player_name()] = false - end - end - end - - if math.random() < 0.01 then -- set gravity, skybox and override light - local pos = player:getpos() - if pos.y > YMIN and pos.y < YMAX then -- entering realm - player:set_physics_override(1, 0.6, 0.2) -- speed, jump, gravity - local skytextures = { - "moonrealm_posy.png", - "moonrealm_negy.png", - "moonrealm_posz.png", - "moonrealm_negz.png", - "moonrealm_negx.png", - "moonrealm_posx.png", - } - player:set_sky({r = 0, g = 0, b = 0, a = 0}, "skybox", skytextures) - player:override_day_night_ratio(1) - else -- on leaving realm - player:set_physics_override(1, 1, 1) - player:set_sky({}, "regular", {}) - player:override_day_night_ratio(nil) - end - end - end -end) - - --- Initialize noise objects to nil - -local nobj_terrain = nil -local nobj_terralt = nil -local nobj_fissure = nil -local nobj_fault = nil - -local nobj_smooth = nil -local nobj_terblen = nil -local nobj_gradcen = nil - - --- Localise noise buffers - -local nbuf_terrain -local nbuf_terralt -local nbuf_fissure -local nbuf_fault - -local nbuf_smooth -local nbuf_terblen -local nbuf_gradcen - - --- Localise data buffer - -local dbuf - - --- On generated function - -minetest.register_on_generated(function(minp, maxp, seed) - if minp.x < XMIN or maxp.x > XMAX or - minp.y < YMIN or maxp.y > YMAX or - minp.z < ZMIN or maxp.z > ZMAX then - return - end - - --local t1 = os.clock() - local x1 = maxp.x - local y1 = maxp.y - local z1 = maxp.z - local x0 = minp.x - local y0 = minp.y - local z0 = minp.z - - local vm, emin, emax = minetest.get_mapgen_object("voxelmanip") - local area = VoxelArea:new{MinEdge = emin, MaxEdge = emax} - local data = vm:get_data(dbuf) - - local c_air = minetest.get_content_id("air") - local c_ignore = minetest.get_content_id("ignore") - local c_mese = minetest.get_content_id("moonrealm:mese") - local c_mrironore = minetest.get_content_id("moonrealm:ironore") - local c_mrcopperore = minetest.get_content_id("moonrealm:copperore") - local c_mrgoldore = minetest.get_content_id("moonrealm:goldore") - local c_mrdiamondore = minetest.get_content_id("moonrealm:diamondore") - local c_mrstone = minetest.get_content_id("moonrealm:stone") - local c_waterice = minetest.get_content_id("moonrealm:waterice") - local c_dust = minetest.get_content_id("moonrealm:dust") - local c_vacuum = minetest.get_content_id("moonrealm:vacuum") - - local chulens = x1 - x0 + 1 - local pmaplens2d = {x = chulens, y = chulens, z = 1} - local pmaplens3d = {x = chulens, y = chulens, z = chulens} - local minpos2d = {x = x0, y = z0} - local minpos3d = {x = x0, y = y0, z = z0} - - nobj_terrain = nobj_terrain or minetest.get_perlin_map(np_terrain, pmaplens3d) - nobj_terralt = nobj_terralt or minetest.get_perlin_map(np_terralt, pmaplens3d) - nobj_fissure = nobj_fissure or minetest.get_perlin_map(np_fissure, pmaplens3d) - nobj_fault = nobj_fault or minetest.get_perlin_map(np_fault, pmaplens3d) - - nobj_smooth = nobj_smooth or minetest.get_perlin_map(np_smooth, pmaplens2d) - nobj_terblen = nobj_terblen or minetest.get_perlin_map(np_terblen, pmaplens2d) - nobj_gradcen = nobj_gradcen or minetest.get_perlin_map(np_gradcen, pmaplens2d) - - local nvals_terrain = nobj_terrain:get3dMap_flat(minpos3d, nbuf_terrain) - local nvals_terralt = nobj_terralt:get3dMap_flat(minpos3d, nbuf_terralt) - local nvals_fissure = nobj_fissure:get3dMap_flat(minpos3d, nbuf_fissure) - local nvals_fault = nobj_fault :get3dMap_flat(minpos3d, nbuf_fault) - - local nvals_smooth = nobj_smooth :get2dMap_flat(minpos2d, nbuf_smooth) - local nvals_terblen = nobj_terblen:get2dMap_flat(minpos2d, nbuf_terblen) - local nvals_gradcen = nobj_gradcen:get2dMap_flat(minpos2d, nbuf_gradcen) - - local ni3d = 1 - local ni2d = 1 - local stable = {} - - for z = z0, z1 do - local viu = area:index(x0, y0 - 1, z) - - for x = x0, x1 do - local si = x - x0 + 1 - local nodid = data[viu] - if nodid == c_vacuum then - stable[si] = false - else - stable[si] = true - end - viu = viu + 1 - end - - for y = y0, y1 do - local vi = area:index(x0, y, z) - local icecha = ICECHA * (1 + (GRADCEN - y) / ICEGRAD) - - for x = x0, x1 do - local nodid = data[vi] - local empty = (nodid == c_air or nodid == c_ignore) - local grad - local density - local si = x - x0 + 1 - local terblen = math.max(math.min( - math.abs(nvals_terblen[ni2d]) * 4, 1.5), 0.5) - 0.5 - local gradcen = GRADCEN + nvals_gradcen[ni2d] * CENAMP - - if y > gradcen then - grad = -((y - gradcen) / HIGRAD) ^ HEXP - else - grad = ((gradcen - y) / LOGRAD) ^ LEXP - end - - if nvals_fault[ni3d] >= 0 then - density = (nvals_terrain[ni3d] + - nvals_terralt[ni3d]) / 2 * (1 - terblen) + - nvals_smooth[ni2d] * terblen + grad - else - density = (nvals_terrain[ni3d] - - nvals_terralt[ni3d]) / 2 * (1 - terblen) - - nvals_smooth[ni2d] * terblen + grad - end - - if density > 0 and empty then -- if terrain and node empty - local nofis = false - if math.abs(nvals_fissure[ni3d]) > TFIS then - nofis = true - end - if density >= STOT and nofis then -- stone, ores - if math.random(ORECHA) == 2 then - local osel = math.random(25) - if osel == 25 then - data[vi] = c_mese - elseif osel >= 22 then - data[vi] = c_mrdiamondore - elseif osel >= 19 then - data[vi] = c_mrgoldore - elseif osel >= 10 then - data[vi] = c_mrcopperore - else - data[vi] = c_mrironore - end - else - data[vi] = c_mrstone - end - stable[si] = true - elseif density < STOT then -- fine materials - if nofis and stable[si] then - if math.random() < icecha then - data[vi] = c_waterice - else - data[vi] = c_dust - end - else -- fissure - data[vi] = c_vacuum - stable[si] = false - end - else -- fissure or unstable missing node - data[vi] = c_vacuum - stable[si] = false - end - else -- vacuum or spawn egg - if empty then - data[vi] = c_vacuum - end - stable[si] = false - end - - ni3d = ni3d + 1 - ni2d = ni2d + 1 - vi = vi + 1 - end - ni2d = ni2d - chulens - end - ni2d = ni2d + chulens - end - - vm:set_data(data) - vm:set_lighting({day=0, night=0}) - vm:calc_lighting() - vm:write_to_map(data) - - --local chugent = math.ceil((os.clock() - t1) * 1000) - --print ("[moonrealm] chunk generation " .. chugent .. " ms") -end) - - --- Find spawn function, dependant on chunk size of 80 nodes --- TODO allow any chunksize, search using 2D noises first - -local function moonrealm_find_spawn() - local PSCA = 8 - - local nobj_terrain = nil - local nobj_terralt = nil - local nobj_fault = nil - - local nobj_smooth = nil - local nobj_terblen = nil - local nobj_gradcen = nil - - for chunk = 1, 128 do - print ("[moonrealm] searching for spawn " .. chunk) - - local x0 = 80 * math.random(-PSCA, PSCA) - 32 - local z0 = 80 * math.random(-PSCA, PSCA) - 32 - local y0 = 80 * math.floor((GRADCEN + 32) / 80) - 32 - local x1 = x0 + 79 - local z1 = z0 + 79 - local y1 = y0 + 79 - - local chulens = x1 - x0 + 1 - local pmaplens2d = {x = chulens, y = chulens, z = 1} - local pmaplens3d = {x = chulens, y = chulens, z = chulens} - local minpos2d = {x = x0, y = z0} - local minpos3d = {x = x0, y = y0, z = z0} - - nobj_terrain = nobj_terrain or minetest.get_perlin_map(np_terrain, pmaplens3d) - nobj_terralt = nobj_terralt or minetest.get_perlin_map(np_terralt, pmaplens3d) - nobj_fault = nobj_fault or minetest.get_perlin_map(np_fault, pmaplens3d) - - nobj_smooth = nobj_smooth or minetest.get_perlin_map(np_smooth, pmaplens2d) - nobj_terblen = nobj_terblen or minetest.get_perlin_map(np_terblen, pmaplens2d) - nobj_gradcen = nobj_gradcen or minetest.get_perlin_map(np_gradcen, pmaplens2d) - - local nvals_terrain = nobj_terrain:get3dMap_flat(minpos3d) - local nvals_terralt = nobj_terralt:get3dMap_flat(minpos3d) - local nvals_fault = nobj_fault :get3dMap_flat(minpos3d) - - local nvals_smooth = nobj_smooth :get2dMap_flat(minpos2d) - local nvals_terblen = nobj_terblen:get2dMap_flat(minpos2d) - local nvals_gradcen = nobj_gradcen:get2dMap_flat(minpos2d) - - local ni3d = 1 - local ni2d = 1 - local stable = {} - - for z = z0, z1 do - for y = y0, y1 do - for x = x0, x1 do - local si = x - x0 + 1 - local grad - local density - local terblen = math.max(math.min( - math.abs(nvals_terblen[ni2d]) * 4, 1.5), 0.5) - 0.5 - local gradcen = GRADCEN + nvals_gradcen[ni2d] * CENAMP - - if y > gradcen then - grad = -((y - gradcen) / HIGRAD) ^ HEXP - else - grad = ((gradcen - y) / LOGRAD) ^ LEXP - end - - if nvals_fault[ni3d] >= 0 then - density = (nvals_terrain[ni3d] + - nvals_terralt[ni3d]) / 2 * (1 - terblen) + - nvals_smooth[ni2d] * terblen + grad - else - density = (nvals_terrain[ni3d] - - nvals_terralt[ni3d]) / 2 * (1 - terblen) - - nvals_smooth[ni2d] * terblen + grad - end - - if density >= STOT then - stable[si] = true - -- just above ground, smooth terrain, away from faults - elseif stable[si] and density < 0 and terblen == 1 and - math.abs(nvals_fault[ni3d]) > 0.25 then - return {x = x, y = y, z = z} - end - - ni3d = ni3d + 1 - ni2d = ni2d + 1 - end - ni2d = ni2d - chulens - end - ni2d = ni2d + chulens - end - end - - return {x = 0, y = GRADCEN, z = 0} -- fallback spawn point -end - - --- Spawn newplayer function - -minetest.register_on_newplayer(function(player) - local spawn_pos = moonrealm_find_spawn() - print ("[moonrealm] spawn new player (" .. spawn_pos.x .. " " .. - spawn_pos.y .. " " .. spawn_pos.z .. ")") - player:setpos(spawn_pos) - - local inv = player:get_inventory() - inv:add_item("main", "default:pick_diamond 4") - inv:add_item("main", "default:shovel_diamond 4") - inv:add_item("main", "default:axe_diamond 4") - inv:add_item("main", "default:apple 64") - inv:add_item("main", "moonrealm:photovoltaic 256") - inv:add_item("main", "moonrealm:light 16") - inv:add_item("main", "moonrealm:glass 16") - inv:add_item("main", "moonrealm:storage 4") - inv:add_item("main", "moonrealm:airlock 4") - inv:add_item("main", "moonrealm:airgen 4") - inv:add_item("main", "moonrealm:air_cylinder 4") - inv:add_item("main", "moonrealm:hlsource 4") - inv:add_item("main", "moonrealm:sapling 4") - inv:add_item("main", "moonrealm:spacesuit 4") - inv:add_item("main", "moonrealm:rover") -end) - - --- Respawn player function - -minetest.register_on_respawnplayer(function(player) - local spawn_pos = moonrealm_find_spawn() - print ("[moonrealm] respawn player (" .. spawn_pos.x .. " " .. - spawn_pos.y .. " " .. spawn_pos.z .. ")") - player:setpos(spawn_pos) - - local inv = player:get_inventory() - inv:add_item("main", "default:pick_diamond") - inv:add_item("main", "default:shovel_diamond 4") - inv:add_item("main", "default:apple 16") - inv:add_item("main", "moonrealm:spacesuit") - - return true -end) +dofile(minetest.get_modpath("moonrealm") .. "/mapgen.lua") diff --git a/mapgen.lua b/mapgen.lua new file mode 100644 index 0000000..d287d7b --- /dev/null +++ b/mapgen.lua @@ -0,0 +1,578 @@ +-- Parameters + +local YMIN = -8000 -- Approx lower limit +local GRADCEN = 1 -- Gradient centre / terrain centre average level +local YMAX = 8000 -- Approx upper limit +local XMIN = -8000 -- Approx horizontal limits +local XMAX = 8000 +local ZMIN = -8000 +local ZMAX = 8000 + +local CENAMP = 64 -- Grad centre amplitude, terrain centre is varied by this +local HIGRAD = 128 -- Surface generating noise gradient above gradcen, controls depth of upper terrain +local LOGRAD = 128 -- Surface generating noise gradient below gradcen, controls depth of lower terrain +local HEXP = 0.5 -- Noise offset exponent above gradcen, 1 = normal 3D perlin terrain +local LEXP = 2 -- Noise offset exponent below gradcen +local STOT = 0.04 -- Stone density threshold, depth of dust + +local ICECHA = 1 / (13 * 13 * 13) -- Ice chance per dust node at terrain centre, decreases with altitude +local ICEGRAD = 128 -- Ice gradient, vertical distance for no ice +local ORECHA = 7 * 7 * 7 -- Ore 1/x chance per stone node +local TFIS = 0.01 -- Fissure threshold. Controls size of fissures +local FOOT = true -- Footprints in dust + +-- 3D noise for terrain + +local np_terrain = { + offset = 0, + scale = 1, + spread = {x = 384, y = 384, z = 384}, + seed = 58588900033, + octaves = 5, + persist = 0.67 +} + +-- 3D noise for alt terrain, 414 / 256 = golden ratio + +local np_terralt = { + offset = 0, + scale = 1, + spread = {x = 311, y = 311, z = 311}, + seed = 13331930910, + octaves = 5, + persist = 0.67 +} + +-- 2D noise for smooth terrain + +local np_smooth = { + offset = 0, + scale = 1, + spread = {x = 512, y = 512, z = 512}, + seed = 113, + octaves = 3, + persist = 0.4 +} + +-- 3D noise for fissures + +local np_fissure = { + offset = 0, + scale = 1, + spread = {x = 192, y = 192, z = 192}, + seed = 8181112, + octaves = 4, + persist = 0.5 +} + + +-- 3D noise for faults + +local np_fault = { + offset = 0, + scale = 1, + spread = {x = 414, y = 828, z = 414}, + seed = 14440002, + octaves = 4, + persist = 0.5 +} + +-- 2D noise for terrain centre + +local np_gradcen = { + offset = 0, + scale = 1, + spread = {x = 1024, y = 1024, z = 1024}, + seed = 9344, + octaves = 4, + persist = 0.4 +} + +-- 2D noise for terrain blend + +local np_terblen = { + offset = 0, + scale = 1, + spread = {x = 1024, y = 1024, z = 1024}, + seed = -13002, + octaves = 3, + persist = 0.4 +} + + +-- Set mapgen parameters + +minetest.set_mapgen_params({mgname = "singlenode", water_level = -31000}) + + +-- Player positions, spacesuit texture status + +local player_pos = {} +local player_pos_previous = {} +local player_spacesuit = {} -- To avoid unnecessary resetting of character model + +minetest.register_on_joinplayer(function(player) + player_pos_previous[player:get_player_name()] = {x = 0, y = 0, z = 0} + + if player:get_inventory():contains_item("main", "moonrealm:spacesuit") then + player:set_properties({textures = {"moonrealm_space_character.png"}}) + player_spacesuit[player:get_player_name()] = true + player:get_inventory():set_stack("hand", 1, "moonrealm:glove") + else + player:set_properties({textures = {"character.png"}}) + player_spacesuit[player:get_player_name()] = false + player:get_inventory():set_stack("hand", 1, "") + end +end) + +minetest.register_on_leaveplayer(function(player) + player_pos_previous[player:get_player_name()] = nil + player_spacesuit[player:get_player_name()] = nil +end) + + +-- Globalstep function + +minetest.register_globalstep(function(dtime) + for _, player in ipairs(minetest.get_connected_players()) do + + -- Footprints + if FOOT and math.random() < 0.15 and + player_pos_previous[player:get_player_name()] ~= nil then + local pos = player:getpos() + player_pos[player:get_player_name()] = { + x = math.floor(pos.x + 0.5), + y = math.floor(pos.y + 0.2), + z = math.floor(pos.z + 0.5) + } + local p_ground = { + x = math.floor(pos.x + 0.5), + y = math.floor(pos.y + 0.4), + z = math.floor(pos.z + 0.5) + } + local n_ground = minetest.get_node(p_ground).name + local p_groundpl = { + x = math.floor(pos.x + 0.5), + y = math.floor(pos.y - 0.5), + z = math.floor(pos.z + 0.5) + } + if player_pos[player:get_player_name()].x ~= + player_pos_previous[player:get_player_name()].x or + player_pos[player:get_player_name()].y < + player_pos_previous[player:get_player_name()].y or + player_pos[player:get_player_name()].z ~= + player_pos_previous[player:get_player_name()].z then + if n_ground == "moonrealm:dust" then + if math.random() < 0.5 then + minetest.add_node( + p_groundpl, + {name = "moonrealm:dustprint1"} + ) + else + minetest.add_node( + p_groundpl, + {name = "moonrealm:dustprint2"} + ) + end + end + end + player_pos_previous[player:get_player_name()] = { + x = player_pos[player:get_player_name()].x, + y = player_pos[player:get_player_name()].y, + z = player_pos[player:get_player_name()].z + } + end + + -- Spacesuit. Restore breath, reset spacesuit texture and glove + if math.random() < 0.04 then + if player:get_inventory():contains_item("main", "moonrealm:spacesuit") then + -- Spacesuit in inventory + if player:get_breath() < 10 then + player:set_breath(10) + end + if player_spacesuit[player:get_player_name()] == false then + player:set_properties({textures = {"moonrealm_space_character.png"}}) + player_spacesuit[player:get_player_name()] = true + player:get_inventory():set_stack("hand", 1, "moonrealm:glove") + end + else + -- No spacesuit in inventory + if player_spacesuit[player:get_player_name()] == true then + player:set_properties({textures = {"character.png"}}) + player_spacesuit[player:get_player_name()] = false + player:get_inventory():set_stack("hand", 1, "") + end + end + end + + -- Set gravity and skybox, override light + if math.random() < 0.01 then + local pos = player:getpos() + if pos.y > YMIN and pos.y < YMAX then -- Entering realm + player:set_physics_override(1, 0.6, 0.2) -- Speed, jump, gravity + local skytextures = { + "moonrealm_posy.png", + "moonrealm_negy.png", + "moonrealm_posz.png", + "moonrealm_negz.png", + "moonrealm_negx.png", + "moonrealm_posx.png", + } + player:set_sky({r = 0, g = 0, b = 0, a = 0}, "skybox", skytextures) + player:override_day_night_ratio(1) + else + -- Leaving realm + player:set_physics_override(1, 1, 1) + player:set_sky({}, "regular", {}) + player:override_day_night_ratio(nil) + end + end + end +end) + + +-- Initialize noise objects to nil + +local nobj_terrain = nil +local nobj_terralt = nil +local nobj_fissure = nil +local nobj_fault = nil + +local nobj_smooth = nil +local nobj_terblen = nil +local nobj_gradcen = nil + + +-- Localise noise buffers + +local nbuf_terrain +local nbuf_terralt +local nbuf_fissure +local nbuf_fault + +local nbuf_smooth +local nbuf_terblen +local nbuf_gradcen + + +-- Localise data buffer + +local dbuf + + +-- On generated function + +minetest.register_on_generated(function(minp, maxp, seed) + if minp.x < XMIN or maxp.x > XMAX or + minp.y < YMIN or maxp.y > YMAX or + minp.z < ZMIN or maxp.z > ZMAX then + return + end + + --local t1 = os.clock() + local x1 = maxp.x + local y1 = maxp.y + local z1 = maxp.z + local x0 = minp.x + local y0 = minp.y + local z0 = minp.z + + local vm, emin, emax = minetest.get_mapgen_object("voxelmanip") + local area = VoxelArea:new{MinEdge = emin, MaxEdge = emax} + local data = vm:get_data(dbuf) + + local c_air = minetest.get_content_id("air") + local c_ignore = minetest.get_content_id("ignore") + local c_mese = minetest.get_content_id("moonrealm:mese") + local c_mrironore = minetest.get_content_id("moonrealm:ironore") + local c_mrcopperore = minetest.get_content_id("moonrealm:copperore") + local c_mrgoldore = minetest.get_content_id("moonrealm:goldore") + local c_mrdiamondore = minetest.get_content_id("moonrealm:diamondore") + local c_mrstone = minetest.get_content_id("moonrealm:stone") + local c_waterice = minetest.get_content_id("moonrealm:waterice") + local c_dust = minetest.get_content_id("moonrealm:dust") + local c_vacuum = minetest.get_content_id("moonrealm:vacuum") + + local chulens = x1 - x0 + 1 + local pmaplens2d = {x = chulens, y = chulens, z = 1} + local pmaplens3d = {x = chulens, y = chulens, z = chulens} + local minpos2d = {x = x0, y = z0} + local minpos3d = {x = x0, y = y0, z = z0} + + nobj_terrain = nobj_terrain or minetest.get_perlin_map(np_terrain, pmaplens3d) + nobj_terralt = nobj_terralt or minetest.get_perlin_map(np_terralt, pmaplens3d) + nobj_fissure = nobj_fissure or minetest.get_perlin_map(np_fissure, pmaplens3d) + nobj_fault = nobj_fault or minetest.get_perlin_map(np_fault, pmaplens3d) + + nobj_smooth = nobj_smooth or minetest.get_perlin_map(np_smooth, pmaplens2d) + nobj_terblen = nobj_terblen or minetest.get_perlin_map(np_terblen, pmaplens2d) + nobj_gradcen = nobj_gradcen or minetest.get_perlin_map(np_gradcen, pmaplens2d) + + local nvals_terrain = nobj_terrain:get3dMap_flat(minpos3d, nbuf_terrain) + local nvals_terralt = nobj_terralt:get3dMap_flat(minpos3d, nbuf_terralt) + local nvals_fissure = nobj_fissure:get3dMap_flat(minpos3d, nbuf_fissure) + local nvals_fault = nobj_fault :get3dMap_flat(minpos3d, nbuf_fault) + + local nvals_smooth = nobj_smooth :get2dMap_flat(minpos2d, nbuf_smooth) + local nvals_terblen = nobj_terblen:get2dMap_flat(minpos2d, nbuf_terblen) + local nvals_gradcen = nobj_gradcen:get2dMap_flat(minpos2d, nbuf_gradcen) + + local ni3d = 1 + local ni2d = 1 + local stable = {} + + for z = z0, z1 do + local viu = area:index(x0, y0 - 1, z) + + for x = x0, x1 do + local si = x - x0 + 1 + local nodid = data[viu] + if nodid == c_vacuum then + stable[si] = false + else + stable[si] = true + end + viu = viu + 1 + end + + for y = y0, y1 do + local vi = area:index(x0, y, z) + local icecha = ICECHA * (1 + (GRADCEN - y) / ICEGRAD) + + for x = x0, x1 do + local nodid = data[vi] + local empty = nodid == c_air or nodid == c_ignore + local grad + local density + local si = x - x0 + 1 + local terblen = math.max(math.min( + math.abs(nvals_terblen[ni2d]) * 4, 1.5), 0.5) - 0.5 + local gradcen = GRADCEN + nvals_gradcen[ni2d] * CENAMP + + if y > gradcen then + grad = -((y - gradcen) / HIGRAD) ^ HEXP + else + grad = ((gradcen - y) / LOGRAD) ^ LEXP + end + + if nvals_fault[ni3d] >= 0 then + density = (nvals_terrain[ni3d] + + nvals_terralt[ni3d]) / 2 * (1 - terblen) + + nvals_smooth[ni2d] * terblen + grad + else + density = (nvals_terrain[ni3d] - + nvals_terralt[ni3d]) / 2 * (1 - terblen) - + nvals_smooth[ni2d] * terblen + grad + end + + if density > 0 and empty then + -- Terrain and node empty + local nofis = false + if math.abs(nvals_fissure[ni3d]) > TFIS then + nofis = true + end + if density >= STOT and nofis then + -- Stone, ores + if math.random(ORECHA) == 2 then + local osel = math.random(25) + if osel == 25 then + data[vi] = c_mese + elseif osel >= 22 then + data[vi] = c_mrdiamondore + elseif osel >= 19 then + data[vi] = c_mrgoldore + elseif osel >= 10 then + data[vi] = c_mrcopperore + else + data[vi] = c_mrironore + end + else + data[vi] = c_mrstone + end + stable[si] = true + elseif density < STOT then + -- Fine materials or fissure + if nofis and stable[si] then + -- Fine materials + if math.random() < icecha then + data[vi] = c_waterice + else + data[vi] = c_dust + end + else + -- Fissure + data[vi] = c_vacuum + stable[si] = false + end + else + -- Fissure or unstable missing node + data[vi] = c_vacuum + stable[si] = false + end + else + -- Vacuum + if empty then + data[vi] = c_vacuum + end + stable[si] = false + end + + ni3d = ni3d + 1 + ni2d = ni2d + 1 + vi = vi + 1 + end + ni2d = ni2d - chulens + end + ni2d = ni2d + chulens + end + + vm:set_data(data) + vm:set_lighting({day=0, night=0}) + vm:calc_lighting() + vm:write_to_map(data) + + --local chugent = math.ceil((os.clock() - t1) * 1000) + --print ("[moonrealm] chunk generation " .. chugent .. " ms") +end) + + +-- Find spawn function, dependant on chunk size of 80 nodes +-- TODO Allow any chunksize, search using 2D noises first + +local function moonrealm_find_spawn() + local PSCA = 8 + + local nobj_terrain = nil + local nobj_terralt = nil + local nobj_fault = nil + + local nobj_smooth = nil + local nobj_terblen = nil + local nobj_gradcen = nil + + for chunk = 1, 128 do + print ("[moonrealm] searching for spawn " .. chunk) + + local x0 = 80 * math.random(-PSCA, PSCA) - 32 + local z0 = 80 * math.random(-PSCA, PSCA) - 32 + local y0 = 80 * math.floor((GRADCEN + 32) / 80) - 32 + local x1 = x0 + 79 + local z1 = z0 + 79 + local y1 = y0 + 79 + + local chulens = x1 - x0 + 1 + local pmaplens2d = {x = chulens, y = chulens, z = 1} + local pmaplens3d = {x = chulens, y = chulens, z = chulens} + local minpos2d = {x = x0, y = z0} + local minpos3d = {x = x0, y = y0, z = z0} + + nobj_terrain = nobj_terrain or minetest.get_perlin_map(np_terrain, pmaplens3d) + nobj_terralt = nobj_terralt or minetest.get_perlin_map(np_terralt, pmaplens3d) + nobj_fault = nobj_fault or minetest.get_perlin_map(np_fault, pmaplens3d) + + nobj_smooth = nobj_smooth or minetest.get_perlin_map(np_smooth, pmaplens2d) + nobj_terblen = nobj_terblen or minetest.get_perlin_map(np_terblen, pmaplens2d) + nobj_gradcen = nobj_gradcen or minetest.get_perlin_map(np_gradcen, pmaplens2d) + + local nvals_terrain = nobj_terrain:get3dMap_flat(minpos3d) + local nvals_terralt = nobj_terralt:get3dMap_flat(minpos3d) + local nvals_fault = nobj_fault :get3dMap_flat(minpos3d) + + local nvals_smooth = nobj_smooth :get2dMap_flat(minpos2d) + local nvals_terblen = nobj_terblen:get2dMap_flat(minpos2d) + local nvals_gradcen = nobj_gradcen:get2dMap_flat(minpos2d) + + local ni3d = 1 + local ni2d = 1 + local stable = {} + + for z = z0, z1 do + for y = y0, y1 do + for x = x0, x1 do + local si = x - x0 + 1 + local grad + local density + local terblen = math.max(math.min( + math.abs(nvals_terblen[ni2d]) * 4, 1.5), 0.5) - 0.5 + local gradcen = GRADCEN + nvals_gradcen[ni2d] * CENAMP + + if y > gradcen then + grad = -((y - gradcen) / HIGRAD) ^ HEXP + else + grad = ((gradcen - y) / LOGRAD) ^ LEXP + end + + if nvals_fault[ni3d] >= 0 then + density = (nvals_terrain[ni3d] + + nvals_terralt[ni3d]) / 2 * (1 - terblen) + + nvals_smooth[ni2d] * terblen + grad + else + density = (nvals_terrain[ni3d] - + nvals_terralt[ni3d]) / 2 * (1 - terblen) - + nvals_smooth[ni2d] * terblen + grad + end + + if density >= STOT then + stable[si] = true + -- Just above ground, smooth terrain, away from faults + elseif stable[si] and density < 0 and terblen == 1 and + math.abs(nvals_fault[ni3d]) > 0.25 then + return {x = x, y = y, z = z} + end + + ni3d = ni3d + 1 + ni2d = ni2d + 1 + end + ni2d = ni2d - chulens + end + ni2d = ni2d + chulens + end + end + + return {x = 0, y = GRADCEN, z = 0} -- Fallback spawn point +end + + +-- Spawn newplayer function + +minetest.register_on_newplayer(function(player) + local spawn_pos = moonrealm_find_spawn() + print ("[moonrealm] spawn new player (" .. spawn_pos.x .. " " .. + spawn_pos.y .. " " .. spawn_pos.z .. ")") + player:setpos(spawn_pos) + + local inv = player:get_inventory() + inv:add_item("main", "default:pick_diamond 4") + inv:add_item("main", "default:shovel_diamond 4") + inv:add_item("main", "default:axe_diamond 4") + inv:add_item("main", "default:apple 64") + inv:add_item("main", "moonrealm:photovoltaic 256") + inv:add_item("main", "moonrealm:light 16") + inv:add_item("main", "moonrealm:glass 16") + inv:add_item("main", "moonrealm:storage 4") + inv:add_item("main", "moonrealm:airlock 4") + inv:add_item("main", "moonrealm:airgen 4") + inv:add_item("main", "moonrealm:air_cylinder 4") + inv:add_item("main", "moonrealm:hlsource 4") + inv:add_item("main", "moonrealm:sapling 4") + inv:add_item("main", "moonrealm:spacesuit 4") + inv:add_item("main", "moonrealm:rover") +end) + + +-- Respawn player function + +minetest.register_on_respawnplayer(function(player) + local spawn_pos = moonrealm_find_spawn() + print ("[moonrealm] respawn player (" .. spawn_pos.x .. " " .. + spawn_pos.y .. " " .. spawn_pos.z .. ")") + player:setpos(spawn_pos) + + local inv = player:get_inventory() + inv:add_item("main", "default:pick_diamond") + inv:add_item("main", "default:shovel_diamond 4") + inv:add_item("main", "default:apple 16") + inv:add_item("main", "moonrealm:spacesuit") + + return true +end) diff --git a/nodes.lua b/nodes.lua index 9e5b1da..ef17424 100644 --- a/nodes.lua +++ b/nodes.lua @@ -497,3 +497,24 @@ minetest.register_craftitem("moonrealm:lifesupport", { inventory_image = "moonrealm_lifesupport.png", groups = {not_in_creative_inventory = 1}, }) + + +-- Glove + +minetest.register_item("moonrealm:glove", { + type = "none", + wield_image = "moonrealm_glove.png", + wield_scale = {x = 1, y = 1, z = 2.5}, + stack_max = 1, + tool_capabilities = { + full_punch_interval = 0.9, + max_drop_level = 0, + groupcaps = { + crumbly = {times = {[2] = 3.00, [3] = 0.70}, uses = 0, maxlevel = 1}, + snappy = {times = {[3] = 0.40}, uses = 0, maxlevel = 1}, + oddly_breakable_by_hand = + {times = {[1] = 3.50, [2] = 2.00, [3] = 0.70}, uses = 0} + }, + damage_groups = {fleshy = 1}, + } +}) diff --git a/rover.lua b/rover.lua index a75e1b8..ec7e02c 100644 --- a/rover.lua +++ b/rover.lua @@ -6,11 +6,6 @@ local STEPH = 1.1 -- Stepheight, 0.6 = climb slabs, 1.1 = climb nodes -- Functions -local function is_ground(pos) - return minetest.registered_nodes[minetest.get_node(pos).name].walkable -end - - local function get_sign(i) if i == 0 then return 0 @@ -32,15 +27,16 @@ local function get_v(v) end --- Rover +-- Rover entity local rover = { physical = true, collide_with_objects = true, - collisionbox = {-0.53, -1.0, -0.53, 0.53, 1.0, 0.53}, + collisionbox = {-0.7, -1.0, -0.7, 0.7, 1.0, 0.7}, visual = "cube", visual_size = {x = 2.0, y = 2.0}, - textures = { -- top base rightside leftside front back + textures = { + -- Top, base, right, left, front, back "moonrealm_rover_top.png", "moonrealm_rover_base.png", "moonrealm_rover_right.png", @@ -56,6 +52,47 @@ local rover = { } +-- Rover item + +minetest.register_craftitem("moonrealm:rover", { + description = "Rover", + inventory_image = "moonrealm_rover_front.png", + wield_scale = {x = 2, y = 2, z = 2}, + + on_place = function(itemstack, placer, pointed_thing) + local under = pointed_thing.under + local node = minetest.get_node(under) + local udef = minetest.registered_nodes[node.name] + if udef and udef.on_rightclick and + not (placer and placer:get_player_control().sneak) then + return udef.on_rightclick(under, node, placer, itemstack, + pointed_thing) or itemstack + end + + if pointed_thing.type == "node" and + minetest.registered_nodes[node.name].walkable then + under.y = under.y + 1.5 + local rover = minetest.add_entity(under, "moonrealm:rover") + if rover then + rover:setyaw(placer:get_look_horizontal()) + if not minetest.setting_getbool("creative_mode") then + itemstack:take_item() + end + end + end + + return itemstack + end, +}) + + +-- Register entity + +minetest.register_entity("moonrealm:rover", rover) + + +-- Rover entity functions + function rover:on_rightclick(clicker) if not clicker or not clicker:is_player() then return @@ -68,6 +105,14 @@ function rover:on_rightclick(clicker) default.player_attached[name] = false default.player_set_animation(clicker, "stand" , 30) elseif not self.driver then + local attach = clicker:get_attach() + if attach and attach:get_luaentity() then + local luaentity = attach:get_luaentity() + if luaentity.driver then + luaentity.driver = nil + end + clicker:set_detach() + end self.driver = clicker clicker:set_attach(self.object, "", {x = 0, y = 3, z = -2}, {x = 0, y = 0, z = 0}) @@ -75,7 +120,7 @@ function rover:on_rightclick(clicker) minetest.after(0.2, function() default.player_set_animation(clicker, "sit" , 30) end) - self.object:setyaw(clicker:get_look_yaw() - math.pi / 2) + clicker:set_look_horizontal(self.object:getyaw()) end end @@ -96,20 +141,29 @@ end function rover.on_punch(self, puncher, time_from_last_punch, tool_capabilities, direction) - if self.driver then - self.driver:set_detach() - local name = self.driver:get_player_name() - default.player_attached[name] = false - default.player_set_animation(self.driver, "stand" , 30) - self.driver = nil + if not puncher or not puncher:is_player() or self.removed then + return end - -- delay remove to ensure player is detached - minetest.after(0.1, function() - self.object:remove() - end) - if puncher and puncher:is_player() and - not minetest.setting_getbool("creative_mode") then - puncher:get_inventory():add_item("main", "moonrealm:rover") + if self.driver and puncher == self.driver then + self.driver = nil + puncher:set_detach() + default.player_attached[puncher:get_player_name()] = false + end + if not self.driver then + self.removed = true + local inv = puncher:get_inventory() + if not minetest.setting_getbool("creative_mode") + or not inv:contains_item("main", "moonrealm:rover") then + local leftover = inv:add_item("main", "moonrealm:rover") + -- If no room in inventory add a replacement rover to the world + if not leftover:is_empty() then + minetest.add_item(self.object:getpos(), leftover) + end + end + -- Delay remove to ensure player is detached + minetest.after(0.1, function() + self.object:remove() + end) end end @@ -144,6 +198,7 @@ function rover:on_step(dtime) self.object:setyaw(self.object:getyaw() - turn) end end + local s = get_sign(self.v) self.v = self.v - 0.03 * s if s ~= get_sign(self.v) then @@ -155,87 +210,9 @@ function rover:on_step(dtime) if absv > MAXSP then self.v = MAXSP * get_sign(self.v) end + self.object:setacceleration({x = 0, y = -1.962, z = 0}) self.object:setvelocity(get_velocity(self.v, self.object:getyaw(), self.object:getvelocity().y)) self.object:setpos(self.object:getpos()) end - - --- Register entity - -minetest.register_entity("moonrealm:rover", rover) - - --- Item - -minetest.register_craftitem("moonrealm:rover", { - description = "Rover", - inventory_image = "moonrealm_rover_front.png", - wield_scale = {x = 2, y = 2, z = 2}, - liquids_pointable = true, - - on_place = function(itemstack, placer, pointed_thing) - if pointed_thing.type ~= "node" then - return - end - - if not is_ground(pointed_thing.under) then - return - end - - pointed_thing.under.y = pointed_thing.under.y + 1.5 - minetest.add_entity(pointed_thing.under, "moonrealm:rover") - if not minetest.setting_getbool("creative_mode") then - itemstack:take_item() - end - return itemstack - end, -}) - ---[[ -minetest.register_craftitem("mesecar:motor", { - description = "Mesecar Motor", - inventory_image = "mesecar_motor.png", - groups = {not_in_creative_inventory=1}, -}) - - -minetest.register_craftitem("mesecar:battery", { - description = "Mesecar Battery", - inventory_image = "mesecar_battery.png", - groups = {not_in_creative_inventory=1}, -}) - - --- Crafting - -minetest.register_craft({ - output = "mesecar:motor", - recipe = { - {"default:steel_ingot", "default:copper_ingot", "default:steel_ingot"}, - {"default:copper_ingot", "default:steel_ingot", "default:copper_ingot"}, - {"default:steel_ingot", "default:copper_ingot", "default:steel_ingot"}, - }, -}) - - -minetest.register_craft({ - output = "mesecar:battery", - recipe = { - {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"}, - {"default:steel_ingot", "default:mese_block", "default:steel_ingot"}, - {"default:copper_ingot", "default:copper_ingot", "default:steel_ingot"}, - }, -}) - - -minetest.register_craft({ - output = "mesecar:mesecar4", -- Mesecar - recipe = { - {"default:steel_ingot", "dye:yellow", "default:steel_ingot"}, - {"default:steel_ingot", "group:wool", "default:glass"}, - {"mesecar:motor", "mesecar:battery", "mesecar:motor"}, - }, -}) ---]] diff --git a/textures/moonrealm_character.png b/textures/moonrealm_character.png deleted file mode 100644 index 05021781e03fbb71cb309d5ac233c6c90f332fda..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2754 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 FO#sEyAEf{Q literal 0 HcmV?d00001 diff --git a/textures/moonrealm_rover_back.png b/textures/moonrealm_rover_back.png index 8d34cb9df445d353e3a40c4d726f12977b1df324..a458887287a7b7cab35abef48863d3132fa9fd28 100644 GIT binary patch delta 177 zcmV;i08anM0nGuBB!84iL_t(I%e9it4S*mFg^TeB3v_`FzygfMXe_`0EWiTgt|t?v zS~Ti+qiG-gd4`!6c){EUthH)EYfTq8OWG)<0000H=>k_EA~@#`u}S;s4imiORA4{j zrybN<#dxOo0W+&2{SxO@Ij8aOc5z*9K#~3>ygdnCF=Ok~7L`47eV3t5F4%t3U ZumhyKDn-xpoy!0K002ovPDHLkV1oNLNbmpv diff --git a/textures/moonrealm_rover_base.png b/textures/moonrealm_rover_base.png index 453dc1ad78f087a356b6bb5c63b5e1556293f0f3..5a51e430bdc549ea66b7089fb2ec0b93425cfba8 100644 GIT binary patch delta 84 zcmYc)o}l7y<>}%WVsSe8&YsH8^=v8+UcWwlqJdpub$V)QYC_TihCl!Q&NgC}kdR<& oWL%tJz~JUJ>C*!b59WLZ1|LB|XPIQ~Xa*qgboFyt=akR{0NJh|BLDyZ delta 67 zcmXR;nxJB*>FMGaVsSe8&c@{9^=v8+9zHyHqJe$E>hz=q0zAyjZU++>dKP=mEMjJO XFo!R(pd~Vo0SG)@{an^LB{Ts5upJrZ diff --git a/textures/moonrealm_rover_front.png b/textures/moonrealm_rover_front.png index e9a91d361375da7067b4e3f17107757c5e703656..0609c19cf3d8539268a9b70a5f93ce870474e16d 100644 GIT binary patch delta 137 zcmV;40CxYd0i^+uB!6s4L_t(I%VYff`SX7U3IHPm0|P|{uv}S$TT&+uLgQ1z#6Te! z1_n?b3;+LP>i_cP3s%KEJUo~#pg18J8yjO7aNxiJtco2R95B7m(9nP)fX+t;=<*cD r0t>pp*|TREd3ky9>G?mn5)uI6k00w#8m_wl0000blOl||S!%LjgD zU}B&Uj2ghezyOU#vhe56pZ_!d|NkE&9enxn1*>H|JUkd;jFcuMMyPYpy@gdVFE3_- zW7)A|2a14)hX-C8(bW%pG_qg|7i@k-0{^M%0szD&Grftbunoij0000-4!k#p|D z7^BcybNV)N`#&He5D{|D%f)?jC4ft!PmSC+a8pJc$P?J~00000NkvXXu0mjf8M|0f delta 179 zcmV;k08Ibk0nY)DB!8AkL_t(I%f*s04g(D-o$IKm)v4fIuEHt#J7)an{lt#xWpO6lIln41y+ zQv;Fy6RoxLE$sV#B4dnG@l2}$Qc8{R-hYfdYBzuo!q>)jA1s5m9g=en=Nvg_0Ch2Q h9km)bntsBleFL=nH+O5H%6R|)002ovPDHLkV1l+NPLlut diff --git a/textures/moonrealm_rover_right.png b/textures/moonrealm_rover_right.png index d81e6c466d0fa9e18e8024c9a62f0856de213539..fe160c38a382d57c4140c0358b4731e82a1e1843 100644 GIT binary patch delta 194 zcmV;z06qW70p06aY2c&kaz?)j}<)ga-Jf1}MP% z$tzJHzRO8S@o!hFk+rfFGj}YE{uQv+t^okxahLsV2X0uL{{Xgqp#x?f%AEVqS67`u zuTi~s@eW#RgEq#9V6}Qkiiku&N@>s`1i8c*E`eEnqY)9+p!a^7opTo@0H7K$ zpNsU~>t86POk_$)6>C}x0JYX95o3HCdDPnD5JEs}?c?1?ttJHkBAU8+akGqC3*f7* bJ4WpWgl;zNOBWTLJtKGf+sK1ROq#O_9j>F#$0p$AvqxCnLbsY2Uqk26nZgu~SK#8p z9ZoXTa8^+`nGAxDh{4U}5m6x-<4u5oHRix)tzrLH6Ptj;55)zr;J5b>0a0172Bj2A zIUq6t1V})F%70|R1yK%0Yue3SylHRz32?o9=mOHoIBq_Nn}=cD|DS08FB~P>_qo5( z!EPnp1^z>xKTf-1!f~WO;PcxhloK6le9gJ*x5k@*&9!A(KX#bCvdH{=i&szH0I+y( zfz?%ykFR&}N;90jc5}Q4*j!tVv`eKD#bPUL7mGpP*MF|@NhBhY1vXZmABdNZlGA(5 zK8U{Rx!G_`-C=c#>OlHL}Z}#8;wT9 zUa3?D(o$a&p9WI`CY=DWNh#cqDW;?@kP?s*kP?uV!zUTtN-s@=Lr#NkT!zc#aw>#U nA(Z4G*j?@pidwCfXaar%SHshbaclW%00000NkvXXu0mjf3U({p delta 678 zcmV;X0$Kg>1ib~2BYyx1a7bBm000XU000XU0RWnu7ytkO2XskIMF-#q1`-!0h4)08 z00079Nkl)n-S4=G{(5b zD{&tHZ45e?JDMSnAk!b&6%I*4fObOsUSkrDRw`?W`fkv#wbqxFH9q1oMTlFTIs8Xgt{ zrk?-M`U;z?brzP&l$T4Myu4guVX4gKYMrh1mH*EJdX38G^W<_Z?>(1u zWnX*xpS^l><_Pd*fe(!*`^8IF?Cdn%QrAvkr%!mYj*Fg9wdTg%`@DYlE!6&vN0Uv1 z5_bQuR4P7wtyYs!{vU*HNMxw_8;yofUn~|SvLJXI5EF3R37Gs{VB7|V#FY35#010y z#013G;b}&1r5C5ch|{1wD#L|BAufdCLTHwQU?1;wcUV-b)tM&XFAEgrrM`t!A^-pY M07*qoM6N<$f@9q~UH||9