local ns = firefly --minetest.register_entity(":firefly:beacon", { -- initial_properties = { -- visual = "sprite", -- textures = {"blank.png"}, -- static_save = false, -- }, -- time = 0, -- on_step = function(e) -- local time = minetest.get_us_time() -- if time -e.time > 1000000 then -- e.delegate:check_nearby() -- e.time = time -- end -- end, --}) local beacons = {} local MAX_LOYALTY = 10 local Beacon Beacon = { init = function(game, pos, team) local e = { id = "beacon_"..minetest.get_us_time().."_"..math.random(1, 1000000), game = game, pos = game.map.pos +pos, team = team or "__neutral", loyalty = MAX_LOYALTY, nearby = {}, } setmetatable(e, Beacon) beacons[e.id] = e e:rebuild() e._timer = function() e:check_nearby() end ns.timer:listen("every_second", e._timer) -- minetest.set_node(e.pos, {name = "beacon"}) -- minetest.get_meta(e.pos):set_string("beacon", e.id) -- minetest.get_node_timer(e.pos):start(1) return e end, deinit = function(e) ns.timer:unlisten("every_second", e._timer) beacons[e.id] = nil end, rebuild = function(e) for x = e.pos.x -1, e.pos.x +1 do for z = e.pos.z -1, e.pos.z +1 do minetest.set_node(vector.new(x, e.pos.y -1, z), {name = "colored_glass", param2 = e.team == "__neutral" and 0 or e.team == "red" and 1 or 2}) end end end, check_nearby = function(e) local team = e.game.teams[e.team] -- Give score to the controlling team, if there is one. if team then e.game:add_score(e.team, 1) end local not_nearby = table.copy(e.nearby) local enemies_near = {} local ally_near for _, m in pairs(ns.players) do if ns.manhattan_distance(m.pos, e.pos) < 3 then if not e.nearby[m.name] then ns.add_hud_bar(m, "beacon_status", { max = MAX_LOYALTY, min = 0, title = "Beacon", -- Charge-down if we are controlled by someone, but charge-up if contested. value = e.team == "__neutral" and MAX_LOYALTY -e.loyalty or e.loyalty, color = e.team == "__neutral" and "#fff" or e.game.teams[e.team].color, }) end e.nearby[m.name] = true not_nearby[m.name] = nil if m.team ~= e.team then table.insert(enemies_near, m) else ally_near = true end end end for name in pairs(not_nearby) do e.nearby[name] = nil ns.remove_hud_bar(ns.players[name], "beacon_status") end -- If an enemy is near, weaken our team loyalty (but not if someone from out team is also near). if #enemies_near > 0 and not ally_near then -- Interference from competing enemy teams will also prevent us from losing loyalty, if we are contested. local team if e.team == "__neutral" then for i = 1, #enemies_near do local m = enemies_near[i] if team and m.team ~= team then team = nil break end team = m.team end if team then e:set_loyalty(e.loyalty -1) end -- Otherwise, we only care that at least one enemy is near. else e:set_loyalty(e.loyalty -1) end -- If this dropped our loyalty to zero, we must switch teams. if e.loyalty <= 0 then e:switch_team(team) end -- If no enemies are near, we can rebuild loyalty. elseif e.loyalty < MAX_LOYALTY then -- Loyalty is rebuilt faster if an ally is near. e:set_loyalty(e.loyalty +(ally_near and 2 or 1)) end end, set_loyalty = function(e, value) e.loyalty = value -- Update the status bar seen by nearby players. for name in pairs(e.nearby) do ns.change_hud_bar(ns.players[name], "beacon_status",{ value = e.team == "__neutral" and MAX_LOYALTY -e.loyalty or e.loyalty, }) end end, switch_team = function(e, team) -- If we are switching from a non-contested state, we must enter a contested state before we can be assigned a new team. if team and e.team ~= "__neutral" then team = "__neutral" end -- If we didn't get a team, we weren't contested, but should be. e.team = team or "__neutral" -- Reset our loyalty. e.loyalty = MAX_LOYALTY -- We don't use set_loyalty to update the status bar because we also change the color. for name in pairs(e.nearby) do ns.change_hud_bar(ns.players[name], "beacon_status", { value = e.team == "__neutral" and MAX_LOYALTY -e.loyalty or e.loyalty, color = e.team == "__neutral" and "#fff" or e.game.teams[e.team].color or "#48d", }) end e:rebuild() end, } Beacon.__index = Beacon return Beacon