Initial commit.

This commit is contained in:
Signal 2026-02-14 12:36:36 -05:00
commit b5c753ff4d
129 changed files with 4472 additions and 0 deletions

View file

@ -0,0 +1,163 @@
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

View file

@ -0,0 +1,168 @@
local ns = firefly
local Beacon = include "beacons.lua"
local BattleMode = {
name = "battle"
}
BattleMode.__index = BattleMode
function BattleMode.init(map, players)
local e = {
map = map,
players = {},
beacons = {},
teams = {},
victory_conditions = {
max_score = 100,
}
}
setmetatable(e, BattleMode)
local teams_list = {}
for name, def in pairs(e.map.teams) do
e.teams[name] = {
color = def.color,
label = def.label,
score = 0,
players = {},
}
table.insert(teams_list, name)
end
for i = 1, #players do
local m = ns.players[players[i]]
local team = teams_list[math.random(1, #teams_list)]
e:add_player(team, m)
e.players[m.name] = m
end
for _, x in ipairs(map.beacons) do
table.insert(e.beacons, Beacon.init(e, x.pos or x, x.team))
end
return e
end
function BattleMode.deinit(e)
for i = 1, #e.beacons do
e.beacons[i]:deinit()
end
for name, m in pairs(e.players) do
for name, def in pairs(e.map.teams) do
ns.remove_hud_bar(m, name.."_team_score")
end
ns.remove_hud_bar(m, "beacon_status")
m.player:set_pos(vector.new(0, 12, 0))
end
end
function BattleMode.add_player(e, team, m)
m.game = e
m.player:set_pos(vector.new(math.random(e.map.pos.x, e.map.pos.x +e.map.size.x), e.map.pos.y +2, math.random(e.map.pos.z, e.map.pos.z +e.map.size.z)))
local players_in_team = #e.teams[team].players
for name, def in pairs(e.map.teams) do
ns.add_hud_bar(m, name.."_team_score", {
max = e.victory_conditions.max_score,
value = 0,
title = def.label or string.upper(string.sub(name, 1, 1))..string.sub(name, 2).." Team",
color = def.color
})
-- If the random choice would result in another team having two fewer players than this one, the player should be added to the underdog team instead.
if #e.teams[name].players < players_in_team then
team = name
end
end
m.team = team
table.insert(e.teams[team].players, m)
end
function BattleMode.remove_player(e, m)
end
function BattleMode.add_score(e, team, amount)
if e.game_over then return end
e.teams[team].score = e.teams[team].score +amount
-- Reflect the new score on players' HUD.
for name, m in pairs(e.players) do
ns.change_hud_bar(m, team.."_team_score", {
value = e.teams[team].score
})
end
if e.victory_conditions.max_score and e.teams[team].score >= e.victory_conditions.max_score then
e:declare_victory(team)
end
end
function BattleMode.declare_victory(e, team)
e.game_over = true
say("The "..team.." team has won the match!")
minetest.after(10, function()
e:deinit()
end)
end
function BattleMode.tick(e)
end
ns.register_mode(BattleMode)
local c_dirt_grass = minetest.get_content_id("dirt_grass")
local c_grass = minetest.get_content_id("grass")
ns.register_map {
name = "battle_test",
mode = "battle",
preview = "firefly_map_preview_battle_test.gltf",
preview_image = "firefly_battle_map_test.png",
size = vector.new(50, 50, 50),
beacons = {
vector.new(5, 1, 5),
vector.new(45, 1, 45),
{pos = vector.new(25, 2, 25), team = "red"}
},
teams = {
red = {
color = "#9b3c3c",
spawnpoint = vector.new(5, 2, 45)
},
blue = {
spawnpoint = vector.new(45, 2, 5)
}
},
generate = function(minp, maxp)
local vm = minetest.get_voxel_manip(minp, maxp)
local va = VoxelArea(vm:get_emerged_area())
local data = vm:get_data()
for x = minp.x, maxp.x do
for z = minp.z, maxp.z do
data[va:index(x, minp.y, z)] = c_dirt_grass
if math.random() < 0.4 then
data[va:index(x, minp.y +1, z)] = c_grass
end
end
end
vm:set_data(data)
vm:write_to_map()
end
}
ns.register_game_maker("battle", {
texture = "firefly_sand.png",
mode = "battle"
})

View file

@ -0,0 +1,2 @@
name = firefly_battle_mode
depends = firefly_lobby

Binary file not shown.

After

Width:  |  Height:  |  Size: 912 KiB

File diff suppressed because one or more lines are too long