local ns = artifact ns.players = {} local db = minetest.get_mod_storage() include "radial_menu.lua" Player = setmetatable({ new = function(p) local m = setmetatable({ object = p, pitch = 0, yaw = 0 }, {__index = Player}) m.name = p:get_player_name() m.meta = p:get_meta() m.character = m.meta:get("character") or "key" m.inv = p:get_inventory() m.inv:set_stack("main", 1, ItemStack("input")) -- Generic black sky, since the whole game takes place underground. p:set_sky{ type = "basic", base_color = "#000", clouds = false } p:set_sun{visible = false} p:set_moon{visible = false} p:set_stars{visible = false} p:set_properties { visual = "mesh", mesh = "artifact_character.gltf", shaded = false } if m.character == "vix" then artifact.apply_vix(m) else artifact.apply_key(m) end p:hud_set_flags { healthbar = false, breathbar = false, hotbar = artifact.debug, minimap = false, basic_debug = false } m.hud = {} m.poi = {} m:create_hud() m:set_hotbar_size(8) m.ctl = p:get_player_control() return m end, tick = function(m) local time = minetest.get_us_time() local p = m.object local pos = p:get_pos() local yaw = p:get_look_horizontal() local pitch = p:get_look_vertical() local dir = p:get_look_dir() m.pos = pos m.pos.y = m.pos.y +m.eye_height local pointed_found = nil m.pointed_node = nil for x in minetest.raycast(m.pos, m.pos +(dir *5)) do if x and x.type == "object" then local e = x.ref:get_luaentity() -- Ignore players. if e then local names_match = m.pointed_obj and (m.pointed_obj._name or m.pointed_obj.name) == (e._name or e.name) if m.pointed_obj and not names_match then if m.pointed_obj.on_unhover then m.pointed_obj:on_unhover(m) end if m.pointed_obj.on_interact and m.interaction_marker then m.interaction_marker:remove() m.interaction_marker = nil end end if (m.pointed_obj and not names_match and e.on_hover) or not m.pointed_obj then if e.on_hover then e:on_hover(m) end if e.on_interact then if m.interaction_marker then m.interaction_marker:remove() end m.interaction_marker = minetest.add_entity(e.object:get_pos(), "display") m.interaction_marker:set_properties { visual = "sprite", textures = {"artifact_rmb.png"} } end pointed_found = true m.pointed_obj = e break elseif m.pointed_obj and names_match then pointed_found = true break end end elseif x and x.type == "node" then m.pointed_node = x end end if not pointed_found and m.pointed_obj then if m.pointed_obj.on_unhover then m.pointed_obj:on_unhover(m) end if m.pointed_obj.on_interact and m.interaction_marker then m.interaction_marker:remove() m.interaction_marker = nil end m.pointed_obj = nil end local ctl = m.object:get_player_control() if ctl.place and not m.ctl.place and m.pointed_obj and m.pointed_obj.on_interact then if not m.interaction_start then m.interaction_start = time -- m.interaction_marker = minetest.add_entity(m.pointed_obj, "display") -- m.interaction_marker:set_properties { -- visual = "sprite", -- textures = {"rgt_interact_progress_0.png"} -- } else if time -m.interaction_start > 1100000 then m.interaction_marker:remove() m.pointed_obj:on_interact(m) elseif time -m.interaction_start > 1000000 then m.interaction_marker:set_properties { textures = {"artifact_rmb_100.png"} } elseif time -m.interaction_start > 750000 then m.interaction_marker:set_properties { textures = {"artifact_rmb_75.png"} } elseif time -m.interaction_start > 500000 then m.interaction_marker:set_properties { textures = {"artifact_rmb_50.png"} } elseif time -m.interaction_start > 250000 then m.interaction_marker:set_properties { textures = {"artifact_rmb_25.png"} } end end elseif not ctl.place and m.ctl.place and m.interaction_start then m.interacting_with = nil m.interaction_start = nil end local wi = p:get_wielded_item() m.wielded_item = wi if ctl.place and not m.ctl.place and wi:get_name() == "artifact:input" then artifact.show_radial_menu(m, { name = "construct", "test", "test2", "test3", "test4", "test5" }) elseif m._menu and not (ctl.place and wi:get_name() == "artifact:input") then artifact.dismiss_radial_menu(m, "construct") elseif m._menu then local dx = m.yaw -yaw local dy = m.pitch -pitch if dx ~= 0 and dy ~= 0 then m._menu.pos.x = m._menu.pos.x +dx *200 m._menu.pos.y = m._menu.pos.y -dy *200 local r = m._menu.pos:distance(vector.zero()) if r > 50 then r = 50 m._menu.pos = m._menu.pos:normalize() *50 end p:hud_change(m._menu.cursor._id, "offset", m._menu.pos) if r > 20 then local angle = minetest.dir_to_yaw(vector.new(m._menu.pos.x, 0, m._menu.pos.y):normalize()) local idx = math.floor((-angle +math.pi +(m._menu.step /2)) %(math.pi *2) /m._menu.step) +1 if m._menu.selected and m._menu.selected ~= idx then m._menu[m._menu.selected]:animate{ scale = { value = {x=0.7, y=0.7}, duration = 0.2 }, opacity = { value = 128, duration = 0.2 } } end if m._menu.selected ~= idx and m._menu[idx] then m._menu.selected = idx m._menu[m._menu.selected]:animate{ scale = { value = {x=1, y=1}, duration = 0.2 }, opacity = { value = 256, duration = 0.2 } } end elseif m._menu.selected then m._menu[m._menu.selected]:animate{ scale = { value = {x=0.7, y=0.7}, duration = 0.2 }, opacity = { value = 128, duration = 0.2 } } m._menu.selected = nil end end end m.ctl = ctl m.yaw = yaw m.pitch = pitch end, set_character = function(m, to) m.character = to m.meta:set_string("character", to) end, -- Initialize the player's primary HUD display based on saved state. create_hud = function(m) -- If called post-init, make sure we delete the previous HUD. -- This is useful when we want to recreate the HUD in response -- to an event, like freeing Vix. -- if m.hud then -- for _, x in pairs(m.hud) do -- if type(x) == "table" then -- for _, y in pairs(x) do -- m.object:hud_remove(y) -- end -- else -- m.object:hud_remove(x) -- end -- end -- end -- m.hud = { -- key_health = m.object:hud_add { -- type = "statbar", -- position = {x=0.5,y=1}, -- offset = {x=-27 *5,y=artifact.debug and -96 or -30}, -- scale = {x=4,y=4}, -- alignment = {x=-1, y=-1}, -- size = {x=27,y=27}, -- text = "artifact_heart_vix.png", -- text2 = "artifact_heart_bg.png", -- number = 20 -- } -- } -- -- if artifact.debug or artifact.story.states[artifact.story.get_state()] >= artifact.story.states.main then -- -- end end, set_hotbar_size = function(m, slots) local p = m.object p:hud_set_hotbar_itemcount(slots) local list = "" for i = 0, slots do list = list..":"..(21*i)..",0=artifact_hotbar_bg.png" end p:hud_set_hotbar_image("[combine:"..(21 *slots +1).."x22"..list) p:hud_set_hotbar_selected_image("artifact_hotbar_selected_bg.png") end, }, { __call = function(_, ...) return Player.new(...) end }) artifact.register_craftitem("input", { inventory_image = "artifact_rmb_100.png", on_drop = function(s, p, pos) local m = artifact.players[p:get_player_name()] if artifact.debug or artifat.story.state > artifact.story.states.pre_vix then artifact.swap_character(m) end return s end }) minetest.register_globalstep(function() for _, m in pairs(artifact.players) do m:tick() end end) minetest.register_on_joinplayer(function(p) artifact.players[p:get_player_name()] = Player(p) if artifact.debug then -- Make sure we don't have to `/grantme` a million times while testing. minetest.registered_chatcommands.grantme.func(p:get_player_name(), "all") end end)