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,7 @@
local ns = firefly
-- Determine whether the target player is an admin.
local admin = minetest.settings:get("name") -- Assume this will never be changed live.
function ns.is_admin(name)
return name == admin or name == "singleplayer" and firefly.singleplayer_admin
end

View file

@ -0,0 +1,2 @@
name = firefly_admin
depends = firefly_base

236
mods/firefly_base/init.lua Normal file
View file

@ -0,0 +1,236 @@
-- Enable Minetest forever.
minetest = core
firefly = {
-- Set to `true` to enable testing admin things without having to open a server.
singleplayer_admin = true
}
local ns = firefly
function include(file)
return dofile(minetest.get_modpath(minetest.get_current_modname()).."/"..file)
end
function enum(cases)
local out = {}
local i = 0
for _, x in ipairs(cases) do
out[x] = i
i = i +1
end
return out
end
say = minetest.chat_send_all
function extend(dst, src)
for k, v in pairs(src) do
dst[k] = v
end
return dst
end
Promise = {
resolve = function(e, ...)
if e.resolved then return end
e.resolved = true
if e._after then e._after(...) end
end,
after = function(e, fn)
e._after = fn
end
}
Promise.__index = Promise
setmetatable(Promise, {
__call = function(_, fn)
local e = {resolved = false}
setmetatable(e, Promise)
fn(function(...) e:resolve(...) end)
return e
end
})
EventTarget = {
init = function()
local e = {
listeners = {}
}
return setmetatable(e, EventTarget)
end,
listen = function(e, channel, fn)
if not e.listeners[channel] then e.listeners[channel] = {} end
local l = e.listeners[channel]
l[#l +1] = fn
end,
unlisten = function(e, channel, fn)
if not e.listeners[channel] then return end
local l = e.listeners[channel]
local idx = table.indexof(l, fn)
if idx < 0 then return end
table.remove(l, idx)
end,
dispatch = function(e, channel, ...)
local l = e.listeners[channel]
if not l then return end
for i = 1, #l do
l[i](...)
end
end
}
EventTarget.__index = EventTarget
setmetatable(EventTarget, {
__call = function(_, ...) return EventTarget.init(...) end
})
-- HACK: Lookup table for getting a rotation from a
-- facedir (because Minetest doesn't have any way
-- to get this information normally).
local facedir_rotations = {
-- +Y
[0] = vector.new(0, 0, 0),
[1] = vector.new(0, math.pi * 1.5, 0),
[2] = vector.new(0, math.pi * 1.0, 0),
[3] = vector.new(0, math.pi * 0.5, 0),
-- +Z
[4] = vector.new(math.pi * 1.5, 0, 0),
[5] = vector.new(0, math.pi * 1.5, math.pi * 1.5),
[6] = vector.new(math.pi * 0.5, math.pi * 1.0, 0),
[7] = vector.new(0, math.pi * 0.5, math.pi * 0.5),
-- -Z
[8] = vector.new(math.pi * 0.5, 0, 0),
[9] = vector.new(0, math.pi * 1.5, math.pi * 0.5),
[10] = vector.new(math.pi * 1.5, math.pi * 1.0, 0),
[11] = vector.new(0, math.pi * 0.5, math.pi * 1.5),
-- +X
[12] = vector.new(0, 0, math.pi * 0.5),
[13] = vector.new(math.pi * 1.5, math.pi * 1.5, 0),
[14] = vector.new(0, math.pi * 1.0, math.pi * 1.5),
[15] = vector.new(math.pi * 0.5, math.pi * 0.5, 0),
-- -X
[16] = vector.new(0, 0, math.pi * 1.5),
[17] = vector.new(math.pi * 0.5, math.pi * 1.5, 0),
[18] = vector.new(0, math.pi * 1.0, math.pi * 0.5),
[19] = vector.new(math.pi * 1.5, math.pi * 0.5, 0),
-- -Y
[20] = vector.new(0, 0, math.pi * 1.0),
[21] = vector.new(0, math.pi * 0.5, math.pi * 1.0),
[22] = vector.new(0, math.pi * 1.0, math.pi * 1.0),
[23] = vector.new(0, math.pi * 1.5, math.pi * 1.0),
}
function ns.facedir_to_rotation(facedir)
return facedir_rotations[facedir] or minetest.facedir_to_dir(facedir):dir_to_rotation()
end
function ns.rotate_selectionbox(box, rot)
local a = vector.new(box[1], box[2], box[3]):rotate(rot)
local b = vector.new(box[4], box[5], box[6]):rotate(rot)
return {
a.x, a.y, a.z,
b.x, b.y, b.z
}
end
function ns.register_item(name, def)
local needs_alias
if not name:find ":" then
def._name = name
name = "firefly:"..name
needs_alias = true
end
minetest.register_craftitem(":"..name, def)
if needs_alias then
minetest.register_alias(def._name, name)
end
end
function ns.solid_color_frames(frames)
local out = "[fill:1x"..#frames..":0,0:#000"
for i, x in ipairs(frames) do
out = out.."^[fill:1x3:0,"..(i -1)..":"..x
end
return out
end
local digit_widths = {
[0] = 7,
6,
7,
7,
7,
7,
7,
7,
7,
7,
}
function ns.texture_from_number(num)
local w = 0
local digits = {}
repeat
w = w +1
digits[w] = num %10
num = math.floor(num /10)
until num <= 0
local width = 0
local out = ""
for i = w, 1, -1 do
out = out..":"..width..",1=firefly_number_"..digits[i]..".png"
width = width +digit_widths[digits[i]] +(i > 1 and 2 or 0)
end
return "[combine:"..width.."x16"..out, width
end
function ns.read_file(path)
local f = io.open(path)
if not f then return false end
local out = f:read("a")
f:close()
return out
end
function ns.manhattan_distance(a, b)
return math.abs(b.x -a.x) +math.abs(b.y -a.y) +math.abs(b.z -a.z)
end
minetest.register_lbm {
name = ":firefly:on_load",
nodenames = {"group:call_on_load"},
action = function(pos, node)
minetest.registered_nodes[node.name].on_load(pos)
end
}
ns.timer = EventTarget()
local last_time = minetest.get_us_time()
minetest.register_globalstep(function()
local time = minetest.get_us_time()
if time -last_time > 1000000 then
ns.timer:dispatch("every_second")
last_time = time
end
end)
minetest.register_entity(":display", {
initial_properties = {
visual = "sprite",
textures = {"blank.png"},
pointable = false,
static_save = false
},
on_activate = function(e)
e.object:set_armor_groups{immortal = 1}
end
})
if minetest.get_modpath("testtools") then
minetest.override_item("testtools:param2tool", {
pointabilities = {
nodes = {["group:everything"] = true},
objects = {["group:immortal"] = false}
}
})
end

View file

@ -0,0 +1 @@
name = firefly_base

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 B

View file

View file

@ -0,0 +1,2 @@
name = firefly_characters
depends = firefly_player

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
{"asset":{"version":"2.0","generator":"Blockbench 4.12.5 glTF exporter"},"scenes":[{"nodes":[2],"name":"blockbench_export"}],"scene":0,"nodes":[{"translation":[0,-2.5,0],"name":"Head","mesh":0},{"translation":[0,-2.5,0],"name":"Hat Layer","mesh":1},{"children":[0,1]}],"bufferViews":[{"buffer":0,"byteOffset":0,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":288,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":576,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":768,"byteLength":72,"target":34963},{"buffer":0,"byteOffset":840,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":1128,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":1416,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":1608,"byteLength":72,"target":34963}],"buffers":[{"byteLength":1680,"uri":"data:application/octet-stream;base64,AAAgQAAAoEAAACBAAAAgQAAAoEAAACDAAAAgQAAAAAAAACBAAAAgQAAAAAAAACDAAAAgwAAAoEAAACDAAAAgwAAAoEAAACBAAAAgwAAAAAAAACDAAAAgwAAAAAAAACBAAAAgwAAAoEAAACDAAAAgQAAAoEAAACDAAAAgwAAAoEAAACBAAAAgQAAAoEAAACBAAAAgwAAAAAAAACBAAAAgQAAAAAAAACBAAAAgwAAAAAAAACDAAAAgQAAAAAAAACDAAAAgwAAAoEAAACBAAAAgQAAAoEAAACBAAAAgwAAAAAAAACBAAAAgQAAAAAAAACBAAAAgQAAAoEAAACDAAAAgwAAAoEAAACDAAAAgQAAAAAAAACDAAAAgwAAAAAAAACDAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AACAOQBAAD4AgP89AEAAPgAAgDkAwH8+AID/PQDAfz4AIIA+AEAAPgDgvz4AQAA+ACCAPgDAfz4A4L8+AMB/PgDAfz4AgP89AEAAPgCA/z0AwH8+AACAOQBAAD4AAIA5AOC/PgAAgDkAIIA+AACAOQDgvz4AgP89ACCAPgCA/z0AIMA+AEAAPgDg/z4AQAA+ACDAPgDAfz4A4P8+AMB/PgBAAD4AQAA+AMB/PgBAAD4AQAA+AMB/PgDAfz4AwH8+AAACAAEAAgADAAEABAAGAAUABgAHAAUACAAKAAkACgALAAkADAAOAA0ADgAPAA0AEAASABEAEgATABEAFAAWABUAFgAXABUAAAA0QAAAqkAAADRAAAA0QAAAqkAAADTAAAA0QAAAoL4AADRAAAA0QAAAoL4AADTAAAA0wAAAqkAAADTAAAA0wAAAqkAAADRAAAA0wAAAoL4AADTAAAA0wAAAoL4AADRAAAA0wAAAqkAAADTAAAA0QAAAqkAAADTAAAA0wAAAqkAAADRAAAA0QAAAqkAAADRAAAA0wAAAoL4AADRAAAA0QAAAoL4AADRAAAA0wAAAoL4AADTAAAA0QAAAoL4AADTAAAA0wAAAqkAAADRAAAA0QAAAqkAAADRAAAA0wAAAoL4AADRAAAA0QAAAoL4AADRAAAA0QAAAqkAAADTAAAA0wAAAqkAAADTAAAA0QAAAoL4AADTAAAA0wAAAoL4AADTAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/ABAAPwBAAD4A8B8/AEAAPgAQAD8AwH8+APAfPwDAfz4AEEA/AEAAPgDwXz8AQAA+ABBAPwDAfz4A8F8/AMB/PgDwPz8AgP89ABAgPwCA/z0A8D8/AACAOQAQID8AAIA5APBfPwAAgDkAEEA/AACAOQDwXz8AgP89ABBAPwCA/z0AEGA/AEAAPgDwfz8AQAA+ABBgPwDAfz4A8H8/AMB/PgAQID8AQAA+APA/PwBAAD4AECA/AMB/PgDwPz8AwH8+AAACAAEAAgADAAEABAAGAAUABgAHAAUACAAKAAkACgALAAkADAAOAA0ADgAPAA0AEAASABEAEgATABEAFAAWABUAFgAXABUA"}],"accessors":[{"bufferView":0,"componentType":5126,"count":24,"max":[2.5,5,2.5],"min":[-2.5,0,-2.5],"type":"VEC3"},{"bufferView":1,"componentType":5126,"count":24,"max":[1,1,1],"min":[-1,-1,-1],"type":"VEC3"},{"bufferView":2,"componentType":5126,"count":24,"max":[0.499755859375,0.249755859375],"min":[0.000244140625,0.000244140625],"type":"VEC2"},{"bufferView":3,"componentType":5123,"count":36,"max":[23],"min":[0],"type":"SCALAR"},{"bufferView":4,"componentType":5126,"count":24,"max":[2.8125,5.3125,2.8125],"min":[-2.8125,-0.3125,-2.8125],"type":"VEC3"},{"bufferView":5,"componentType":5126,"count":24,"max":[1,1,1],"min":[-1,-1,-1],"type":"VEC3"},{"bufferView":6,"componentType":5126,"count":24,"max":[0.999755859375,0.249755859375],"min":[0.500244140625,0.000244140625],"type":"VEC2"},{"bufferView":7,"componentType":5123,"count":36,"max":[23],"min":[0],"type":"SCALAR"}],"materials":[{"pbrMetallicRoughness":{"metallicFactor":0,"roughnessFactor":1,"baseColorTexture":{"index":0}},"alphaMode":"MASK","alphaCutoff":0.05,"doubleSided":true}],"textures":[{"sampler":0,"source":0,"name":"artifact_key.png"}],"samplers":[{"magFilter":9728,"minFilter":9728,"wrapS":33071,"wrapT":33071}],"images":[{"mimeType":"image/png","name":"firefly_character_2.png","uri":"firefly_character_2.png"}],"meshes":[{"primitives":[{"mode":4,"attributes":{"POSITION":0,"NORMAL":1,"TEXCOORD_0":2},"indices":3,"material":0}]},{"primitives":[{"mode":4,"attributes":{"POSITION":4,"NORMAL":5,"TEXCOORD_0":6},"indices":7,"material":0}]}]}

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 524 B

View file

@ -0,0 +1,61 @@
from PIL import Image
def adjust_font_atlas(input_path, output_path, current_width, current_height, new_width, new_height):
"""
Adjusts the cell dimensions of a pixel font atlas sprite sheet by creating larger cells
and placing the original sprites in the top-left corner of each new cell, filling
the extra space with the background color detected from the top-left pixel of the
original image. This allows for manual extension of sprites without repositioning them.
Args:
input_path (str): Path to the input atlas image.
output_path (str): Path to save the output atlas image.
current_width (int): Current width of each cell (in pixels).
current_height (int): Current height of each cell (in pixels).
new_width (int): New larger width for each cell (in pixels).
new_height (int): New larger height for each cell (in pixels).
"""
if new_width < current_width or new_height < current_height:
raise ValueError("New dimensions must be larger than the current dimensions.")
img = Image.open(input_path)
width, height = img.size
if width % current_width != 0 or height % current_height != 0:
raise ValueError("Image dimensions are not multiples of the current cell dimensions.")
cols = width // current_width
rows = height // current_height
# Create a new image with the same mode
new_img = Image.new(img.mode, (cols * new_width, rows * new_height))
# Detect background color from top-left pixel (assuming it's background)
bg_color = img.getpixel((0, 0))
# Fill the new image with the background color
new_img.paste(bg_color, (0, 0, new_img.width, new_img.height))
# Copy each original sprite into the top-left of its new larger cell
for r in range(rows):
for c in range(cols):
# Crop the original sprite
left = c * current_width
top = r * current_height
right = left + current_width
bottom = top + current_height
sprite = img.crop((left, top, right, bottom))
# Paste into new position
new_left = c * new_width
new_top = r * new_height
new_img.paste(sprite, (new_left, new_top))
# Save the new atlas
new_img.save(output_path)
# Example usage:
base_path = "/Users/iboettcher/eclipse-workspace/firefly/mods/firefly_font/fonts/"
adjust_font_atlas(f'{base_path}firefly_normal.png',
f'{base_path}firefly_wide.png', 8, 17, 17, 17)

View file

@ -0,0 +1,20 @@
{
"A": {
"width": 7,
"height": 10,
"base": 0,
"advance": 2
},
"B": {
"width": 7,
"height": 10,
"base": 0,
"advance": 2
},
"C": {
"width": 7,
"height": 10,
"base": 0,
"advance": 2
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

View file

@ -0,0 +1,46 @@
local ns = firefly
local modname = minetest.get_current_modname()
ns.fonts = {}
function ns.rasterize(str, font, max_width)
if not font then font = "firefly_normal" end
local atlas = ns.fonts[font] or minetest.parse_json(ns.read_file(minetest.get_modpath(modname).."/fonts/"..font..".json"))
if not ns.fonts[font] then
ns.fonts[font] = atlas
end
local newline = string.byte("\n", 1)
local out = {}
local width = 0
local height = 0
local x = 0
local y = 0
for i = 0, #str do
local char = str:byte(i)
if not char then goto continue end
if char == newline then
goto continue
end
local glyph = atlas[string.char(char)]
local num = #out
out[num +1] = ":"
out[num +2] = x
out[num +3] = ","
out[num +4] = y
out[num +5] = "="
out[num +6] = font
out[num +7] = "/firefly_char_"
out[num +8] = char
out[num +9] = ".png"
x = x +glyph.width +glyph.advance
if x > width then
width = x
end
::continue::
end
return "[combine:"..width.."x"..height..table.concat(out)
end

View file

@ -0,0 +1,2 @@
name = firefly_font
depends = firefly_base

289
mods/firefly_hud/init.lua Normal file
View file

@ -0,0 +1,289 @@
local ns = firefly
ns.hud_types = {}
ns.Element = {
animate = function(e, target)
if not e.targets then e.targets = {} end
local time = minetest.get_us_time()
for k, v in pairs(target) do
e.targets[k] = {
ref = {
time = time,
value = e[k]
},
target = {
time = time +(v.duration or 1) *1000000,
value = v.value
},
ease_fn = v.ease_fn
}
end
end
}
local function bezier_ease(t, x1, y1, x2, y2)
if t <= 0 then return 0 end
if t >= 1 then return 1 end
local low = 0
local high = 1
local epsilon = 1e-6
local iterations = 0
while (high - low > epsilon) and (iterations < 100) do
local mid = (low + high) / 2
local x = 3 * mid * (1 - mid) ^ 2 * x1 + 3 * mid ^ 2 * (1 - mid) * x2 + mid ^ 3
if x < t then
low = mid
else
high = mid
end
iterations = iterations + 1
end
local u = (low + high) / 2
local y = 3 * u * (1 - u) ^ 2 * y1 + 3 * u ^ 2 * (1 - u) * y2 + u ^ 3
return y
end
local function interpolate(ref, target, t, x1, y1, x2, y2)
local eased_t = bezier_ease(t, x1 or 0, y1 or 0, x2 or 1, y2 or 1)
return ref + (target - ref) * eased_t
end
ns.interpolate = interpolate
function ns.register_hud_type(def)
ns.hud_types[def.name] = setmetatable(def, {__index = ns.Element})
end
function ns.validate_type(elem, type)
if not ns.hud_types[elem.type] then
warn("Unknown HUD type `"..type.."` for element `"..elem.name.."`; ignoring.")
return false
end
if ns.hud_types[type].required_fields then
for _, field in ipairs(ns.hud_types[type].required_fields) do
if elem[field] == nil then return false end
end
end
return true
end
function ns.hud_add(m, def)
if not ns.validate_type(def, def.type) then
return false
end
local type = ns.hud_types[def.type]
if type.defaults then
def = extend(table.copy(type.defaults), def)
end
-- Create a random name if none is given, since the
-- assumption is that the user doesn't care about the name.
if not def.name then
def.name = ""..math.random()
end
local el
if m.hud[def.name] then
el = m.hud[def.name]
-- Simply write all modified fields to the existing element.
extend(el, def)
else
el = setmetatable(def, {__index = type})
m.hud[def.name] = el
el:add(m)
end
return el
end
function ns.update_poi(m)
for _, x in pairs(m.poi) do
x:remove(m)
end
m.poi = {}
for _, x in ipairs(minetest.find_nodes_in_area(m.pos:offset(-100, -100, -100), m.pos:offset(100,100,100), "group:poi")) do
m.poi[#m.poi +1] = ns.hud_add(m, {
name = "poi:"..x:to_string(),
type = "poi",
world_pos = x,
})
end
end
local default_ease_fn = {0,0,1,1}
minetest.register_globalstep(function(dtime)
local time = minetest.get_us_time()
for _, m in pairs(ns.players) do
for k, el in pairs(m.hud) do
if el.remove_after then
el.remove_after = el.remove_after -dtime
if el.remove_after < 0 then
el:remove(m)
m.hud[k] = nil
end
end
if el.targets and next(el.targets) then
local changes = {}
for key, target in pairs(el.targets) do
local fac = (time -target.ref.time) /(target.target.time -target.ref.time)
local ease_fn = target.ease_fn or default_ease_fn
local value
if el.field_types[key] == "vec2" then
value = {
x = interpolate(target.ref.value.x, target.target.value.x, fac, ease_fn[1], ease_fn[2], ease_fn[3], ease_fn[4]),
y = interpolate(target.ref.value.y, target.target.value.y, fac, ease_fn[1], ease_fn[2], ease_fn[3], ease_fn[4])
}
if fac >= 1 then
el.targets[key] = nil
end
elseif el.field_types[key] == "color" then
value = {
r = interpolate(target.ref.value.r, target.target.value.r, fac, ease_fn[1], ease_fn[2], ease_fn[3], ease_fn[4]),
g = interpolate(target.ref.value.g, target.target.value.g, fac, ease_fn[1], ease_fn[2], ease_fn[3], ease_fn[4]),
b = interpolate(target.ref.value.b, target.target.value.b, fac, ease_fn[1], ease_fn[2], ease_fn[3], ease_fn[4]),
a = interpolate(target.ref.value.a, target.target.value.a, fac, ease_fn[1], ease_fn[2], ease_fn[3], ease_fn[4]),
}
if value.r == target.target.value.r and value.g == target.target.value.g and value.b == target.target.value.b and value.a == target.target.value.a then
el.targets[key] = nil
end
else
value = interpolate(target.ref.value, target.target.value, fac, ease_fn[1], ease_fn[2], ease_fn[3], ease_fn[4])
if value == target.target.value then
el.targets[key] = nil
end
end
el[key] = value
-- We could just set this to true, but since we already
-- have a new table, we might as well use it.
changes[key] = value
end
el:update(m, changes)
end
end
-- for k, el in ipairs(m.poi) do
-- if m.dir:distance(m.pos:direction(el.world_pos)) < 0.05 then
-- el.focused = true
-- el:animate {
-- scale = {
-- value = {x=2,y=2},
-- duration = 0.2,
-- }
-- }
-- elseif el.focused then
-- el.focused = false
-- el:animate {
-- scale = {
-- value = {x=1,y=1},
-- duration = 0.2,
-- }
-- }
-- end
-- end
end
end)
function ns.color_to_number(color)
return tonumber(string.format("0x%.2x%.2x%.2x", color.r, color.g, color.b))
end
ns.register_hud_type {
name = "text",
required_fields = {"pos", "text"},
field_types = {
offset = "vec2",
pos = "vec2",
size = "vec2",
color = "color"
},
defaults = {
dir = 0,
align = {x=0, y=0},
offset = {x=0, y=0},
size = {x=1, y=1},
color = {r = 0xff, g = 0xff, b = 0xff, a = 0xff}
},
add = function(e, m)
e._id = m.player:hud_add {
type = "text",
position = e.pos,
direction = e.dir,
alignment = e.align,
offset = e.offset,
scale = {x=100, y=100},
size = e.size,
text = e.text,
number = ns.color_to_number(e.color)
}
end,
update = function(e, m, changes)
for k, v in pairs(changes) do
if k == "color" then
k = "number"
v = ns.color_to_number(v)
elseif k == "dir" then
k = "direction"
elseif k == "align" then
k = "alignment"
end
m.player:hud_change(e._id, k, v)
end
end,
remove = function(e, m)
m.hud[e.name] = nil
m.player:hud_remove(e._id)
e._id = nil
-- Prevent ongoing animations from attempting to change a nonexistent element.
e.update = function() end
end
}
ns.register_hud_type {
name = "image",
required_fields = {"pos", "image"},
field_types = {
offset = "vec2",
scale = "vec2",
pos = "vec2"
},
defaults = {
dir = 0,
align = {x=0, y=0},
offset = {x=0, y=0},
scale = {x=1, y=1},
opacity = 256
},
add = function(e, m)
e._id = m.player:hud_add {
type = "image",
position = e.pos,
direction = e.dir,
alignment = e.align,
offset = e.offset,
scale = e.scale,
text = e.image..string.format("^[opacity:%i", e.opacity)
}
end,
update = function(e, m, changes)
for k, v in pairs(changes) do
if k == "align" then
k = "alignment"
elseif k == "pos" then
k = "position"
elseif k == "image" then
k = "text"
elseif k == "opacity" then
k = "text"
v = e.image..string.format("^[opacity:%i", e.opacity)
end
m.player:hud_change(e._id, k, v)
end
end,
remove = function(e, m)
m.hud[e.name] = nil
m.player:hud_remove(e._id)
e._id = nil
-- Prevent ongoing animations from attempting to change a nonexistent element.
e.update = function() end
end
}

View file

@ -0,0 +1,2 @@
name = firefly_hud
depends = firefly_base

View file

@ -0,0 +1,132 @@
local ns = firefly
Player:listen('init', function(m)
m.hud_bars = {}
m.hud_bars_list = {}
end)
function ns.add_hud_bar(m, name, def)
if m.hud_bars[name] then
ns.remove_hud_bar(m, name)
end
if not def.color then def.color = "#48d" end
local ypos = #m.hud_bars_list *50
local pixel_scale = 3
local hud = {
left = ns.hud_add(m, {
type = "image",
image = "firefly_hud_bar_left"..(def.value == 0 and "_bg" or "")..".png^[multiply:"..def.color,
pos = {x = 0.5, y = 0},
offset = {x = -400 -pixel_scale, y = ypos +36},
scale = {x = pixel_scale, y = pixel_scale}
}),
center = ns.hud_add(m, {
type = "image",
image = "firefly_hud_bar_center_bg.png^[multiply:"..def.color,
pos = {x = 0.5, y = 0},
offset = {x = 0, y = ypos +36},
scale = {x = 800, y = pixel_scale}
}),
overlay = ns.hud_add(m, {
type = "image",
image = "firefly_hud_bar_center.png^[multiply:"..def.color,
pos = {x = 0.5, y = 0},
offset = {x = -400, y = ypos +36},
align = {x = 1, y = 0},
scale = {x = 800 *(def.value /def.max), y = pixel_scale}
}),
right = ns.hud_add(m, {
type = "image",
image = "firefly_hud_bar_right"..(def.value == def.max and "" or "_bg")..".png^[multiply:"..def.color,
pos = {x = 0.5, y = 0},
offset = {x = 400 +pixel_scale, y = ypos +36},
scale = {x = pixel_scale, y = pixel_scale}
}),
title = ns.hud_add(m, {
type = "text",
text = def.title or "",
pos = {x = 0.5, y = 0},
offset = {x = 0, y = ypos +4},
align = {x = 0, y = 1},
color = minetest.colorspec_to_table(def.color)
})
}
m.hud_bars[name] = {
def = def,
hud = hud,
index = #m.hud_bars_list +1
}
table.insert(m.hud_bars_list, name)
end
function ns.change_hud_bar(m, name, def)
local bar = m.hud_bars[name]
if not bar then return end
local last_value = bar.def.value
local last_title = bar.def.title
local last_color = bar.def.color
extend(bar.def, def)
if def.value or def.max then
if last_color ~= bar.def.color then
bar.hud.right:update(m, {text = "firefly_hud_bar_right"..(def.value == def.max and "" or "_bg")..".png^[multiply:"..def.color})
bar.hud.left:update(m, {text = "firefly_hud_bar_left"..(def.value == 0 and "_bg" or "")..".png^[multiply:"..def.color})
bar.hud.center:update(m, {text = "firefly_hud_bar_center_bg.png^[multiply:"..def.color})
bar.hud.overlay:update(m, {text = "firefly_hud_bar_center.png^[multiply:"..def.color})
bar.hud.title:update(m, {color = minetest.colorspec_to_table(def.color)})
end
if bar.def.value == bar.def.max and last_value ~= bar.def.max then
minetest.after(def.ease or 0.3, function()
bar.hud.right:update(m, {text = "firefly_hud_bar_right.png^[multiply:"..bar.def.color})
end)
elseif last_value == bar.def.max then
bar.hud.right:update(m, {text = "firefly_hud_bar_right_bg.png^[multiply:"..bar.def.color})
end
if bar.def.value == 0 and last_value ~= 0 then
minetest.after(def.ease or 0.3, function()
bar.hud.left:update(m, {image = "firefly_hud_bar_left_bg.png^[multiply:"..bar.def.color})
end)
elseif last_value == 0 then
bar.hud.left:update(m, {image = "firefly_hud_bar_left.png^[multiply:"..bar.def.color})
end
if last_title ~= bar.def.title then
bar.hud.title:update(m, {text = bar.def.title})
end
bar.hud.overlay:animate {
scale = {
value = {x = 800 *(bar.def.value /bar.def.max), y = 3},
duration = def.ease or 0.3,
ease_fn = {0.42, 0, 0.58, 1.06}
}
}
end
end
function ns.remove_hud_bar(m, name)
if not m.hud_bars[name] then return end
for _, x in pairs(m.hud_bars[name].hud) do
x:remove(m)
end
m.hud_bars[name] = nil
table.remove(m.hud_bars_list, table.indexof(m.hud_bars_list, name))
-- Reposition all other HUD bars so there are no gaps.
for i = 1, #m.hud_bars_list do
local bar = m.hud_bars[m.hud_bars_list[i]]
if bar.index ~= i then
local dist = i *50
bar.hud.right:update(m, {offset = {x = bar.hud.right.offset.x, y = dist +36}})
bar.hud.left:update(m, {offset = {x = bar.hud.left.offset.x, y = dist +36}})
bar.hud.center:update(m, {offset = {x = bar.hud.center.offset.x, y = dist +36}})
bar.hud.overlay:update(m, {offset = {x = bar.hud.overlay.offset.x, y = dist +36}})
bar.hud.title:update(m, {offset = {x = bar.hud.title.offset.x, y = dist +4}})
end
end
end

View file

@ -0,0 +1,2 @@
name = firefly_hudbars
depends = firefly_hud, firefly_base

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 B

View file

@ -0,0 +1,432 @@
local ns = firefly
ns.players = {}
minetest.register_entity(":firefly:player", {
initial_properties = {
visual = "mesh",
mesh = "firefly_character.gltf",
textures = {"firefly_character.png"},
backface_culling = false,
pointable = false,
visual_size = vector.new(1,1,1),
collisionbox = {2/3, 1.625, 2/3, -2/3, 0, -2/3},
selectionbox = {2/3, 1.625, 2/3, -2/3, 0, -2/3},
static_save = false,
},
on_deactivate = function(e)
-- Ensure that the player's display will never get lost until the player leaves.
if e.owner and e.owner.player:get_pos() then
e.owner.object = minetest.add_entity(e.owner.pos, "firefly:player")
e.owner.object:set_attach(e.owner.player)
end
end,
on_step = function(e, dtime, movement)
if e.owner then
e.owner.movement = movement
end
end
})
function ns.add_jetpack_particles(m)
local def = {
attached = m.jetpack_a,
pos = {
min = vector.new(-0.1,-0.1,-0.1),
max = vector.new(0.1,0.1,0.1)
},
vel = {
min = vector.new(0, -5, 0),
max = vector.new(0, -1, 0)
},
animation = {
type = "vertical_frames",
aspect_w = 1,
aspect_h = 1,
length = -1
},
texture = ns.solid_color_frames {"#f7d19b", "#f0a951", "#e1820c", "#cd5819", "#5d342c", "#444"},
time = 0,
amount = 50,
exptime = 0.5,
size_tween = {
{min = 1, max = 2},
0.05
}
}
m.jetpack_particles_a = minetest.add_particlespawner(table.copy(def))
def.attached = m.jetpack_b
m.jetpack_particles_b = minetest.add_particlespawner(def)
end
function ns.remove_jetpack_particles(m)
minetest.delete_particlespawner(m.jetpack_particles_a)
minetest.delete_particlespawner(m.jetpack_particles_b)
end
function ns.enter_jetpack_mode(m)
m.jetpack_mode = true
m:set_physics_override("jetpack", {
speed = 3,
})
ns.add_jetpack_particles(m)
end
function ns.exit_jetpack_mode(m)
m.jetpack_mode = nil
m:set_physics_override("jetpack")
ns.remove_jetpack_particles(m)
end
local blank_physics_override = {
speed = 1,
speed_walk = 1,
speed_crouch = 1,
speed_fast = 1,
speed_climb = 1,
speed_jump = 1,
jump = 1,
gravity = 1,
liquid_fluidity = 1,
liquid_fluidity_smooth = 1,
liquid_sink = 1,
acceleration_default = 1,
acceleration_air = 1,
acceleration_fast = 1,
}
Player = {
listeners = {},
init = function(p)
local m = {
active = true,
player = p,
name = p:get_player_name(),
object = minetest.add_entity(p:get_pos(), "firefly:player"),
hud = {},
physics_overrides = {},
pos = p:get_pos()
}
setmetatable(m, {__index = Player})
m.object:get_luaentity().owner = m
p:set_properties {
visual = "sprite",
textures = {"blank.png"},
pointable = false
}
p:hud_set_flags {
healthbar = false,
breathbar = false,
}
m.eye_height = p:get_properties().eye_height
m.object:set_attach(p)
m.jetpack = minetest.add_entity(m.pos, "display")
m.jetpack:set_properties {
visual = "mesh",
mesh = "firefly_jetpack.gltf",
textures = {"firefly_jetpack.png", "blank.png"}
}
m.jetpack:set_attach(m.object, "Torso")
m.jetpack_a = minetest.add_entity(m.pos, "display")
m.jetpack_a:set_attach(m.jetpack, "exhaust1")
m.jetpack_b = minetest.add_entity(m.pos, "display")
m.jetpack_b:set_attach(m.jetpack, "exhaust2")
m.stats_bg = m.player:hud_add {
type = "image",
text = "firefly_stats_bg.png",
position = {x = 0, y = 1},
offset = {x = 50, y = -50},
alignment = {x = 1, y = -1},
scale = {x = 6, y = 6},
}
m.healthbar = m.player:hud_add {
type = "image",
text = "[fill:4x32:0,0:#0000^[lowpart:100:firefly_health_bar.png^[transformR270^[multiply:#d33",
position = {x = 0, y = 1},
offset = {x = 50 +(29 *6), y = -50 -(19 *6)},
alignment = {x = 1, y = -1},
scale = {x = 6, y = 6},
}
m.ammobar = m.player:hud_add {
type = "image",
text = "[fill:4x32:0,0:#0000^[lowpart:100:firefly_health_bar.png^[transformR270^[multiply:#dc4",
position = {x = 0, y = 1},
offset = {x = 50 +(29 *6), y = -50 -(13 *6)},
alignment = {x = 1, y = -1},
scale = {x = 6, y = 6},
}
m.ammobar2 = m.player:hud_add {
type = "image",
text = "[fill:4x32:0,0:#0000^[lowpart:100:firefly_health_bar.png^[transformR270^[multiply:#4dc",
position = {x = 0, y = 1},
offset = {x = 50 +(29 *6), y = -50 -(7 *6)},
alignment = {x = 1, y = -1},
scale = {x = 6, y = 6},
}
m:set_hotbar_size(8)
m.ctl = {}
m.pitch = 0
m.yaw = 0
m.last_jump = 0
Player:dispatch('init', m)
return m
end,
deinit = function(m)
m.active = false
end,
tick = function(m, dtime)
local p = m.player
local pos = p:get_pos()
m.eye_pos = pos:offset(0, m.eye_height, 0)
local vel = p:get_velocity()
local pitch = p:get_look_vertical()
local yaw = p:get_look_horizontal()
local look_dir = p:get_look_dir()
local ctl = p:get_player_control()
local time = minetest.get_us_time()
local standing_on = minetest.get_node(pos:offset(0, -0.5, 0))
local moving = ctl.up or ctl.left or ctl.down or ctl.right
-- MARK: Wield callbacks
local wielded_item = p:get_wielded_item()
local wi_def = wielded_item:get_definition()
if not m.wielded_item or m.wielded_item:get_name() ~= wielded_item:get_name() then
if m.wielded_item then
local old_def = m.wielded_item:get_definition()
if old_def.on_unwield then
old_def.on_unwield(m.wielded_item, old_def, m)
end
end
m.wielded_item = wielded_item
if wi_def.on_wield then
wi_def.on_wield(wielded_item, wi_def, m)
end
end
if wi_def.while_wielded then
wi_def.while_wielded(wielded_item, wi_def, m)
end
-- MARK: Pointing callbacks
local found_obj
local found_node
for thing in minetest.raycast(m.eye_pos, m.eye_pos +(look_dir *5)) do
if thing.type == "object" then
found_obj = true
local e = thing.ref:get_luaentity()
if not m.pointed_obj or (m.pointed_obj.name or m.pointed_obj._name) ~= (e.name or e._name) then
if m.pointed_obj and m.pointed_obj.on_unhover then
m.pointed_obj:on_unhover(m)
end
m.pointed_obj = e
if e.on_hover then
e:on_hover(m)
end
end
break
elseif thing.type == "node" then
found_node = true
if not m.pointed_node or thing.under ~= m.pointed_node.under then
if m.pointed_node then
local on_unhover = minetest.registered_nodes[m.pointed_node.node_under.name].on_unhover
if on_unhover then
on_unhover(m.pointed_node.under, m)
end
end
thing.node_under = minetest.get_node(thing.under)
m.pointed_node = thing
local on_hover = minetest.registered_nodes[thing.node_under.name].on_hover
if on_hover then
on_hover(thing.under, m)
end
end
break
end
end
if not found_obj and m.pointed_obj then
if m.pointed_obj and m.pointed_obj.on_unhover then
m.pointed_obj:on_unhover(m)
end
m.pointed_obj = nil
end
if not found_node and m.pointed_node then
local on_unhover = minetest.registered_nodes[m.pointed_node.node_under.name].on_unhover
if m.pointed_node and on_unhover then
on_unhover(m.pointed_node.under, m)
end
m.pointed_node = nil
end
-- MARK: Animation
m.object:set_bone_override("root", {
rotation = {
vec = vector.new(0, -yaw, 0), absolute = true, interpolation = 0.1
}
})
m.object:set_bone_override("Head", {
rotation = {
vec = vector.new(pitch, 0, 0), absolute = true, interpolation = 0.1
}
})
m.moving = moving
if m.jetpack_mode then
if ctl.jump and vel.y < 10 then
p:add_velocity(vector.new(0, 32 *dtime, 0))
if not m.ctl.jump then
m:set_physics_override("jetpack", {
speed = 3,
})
ns.add_jetpack_particles(m)
end
end
if m.ctl.jump and not ctl.jump then
m:set_physics_override("jetpack")
ns.remove_jetpack_particles(m)
end
if standing_on.name ~= "air" then
ns.exit_jetpack_mode(m)
end
else
if ctl.jump and not m.ctl.jump then
if standing_on.name == "air" then
ns.enter_jetpack_mode(m)
end
end
end
m.standing_on = standing_on
m.yaw = yaw
m.pitch = pitch
m.look_dir = look_dir
m.pos = pos
m.ctl = ctl
Player:dispatch('tick', m)
end,
set_properties = function(m, ...)
return m.object:set_properties(...)
end,
set_physics_override = function(m, name, override)
m.physics_overrides[name] = override
m.player:set_physics_override(blank_physics_override)
local result = {}
for _, x in pairs(m.physics_overrides) do
for k, v in pairs(x) do
result[k] = (result[k] or 1) *v
end
end
m.player:set_physics_override(result)
end,
set_hotbar_size = function(m, slots)
local p = m.player
p:hud_set_hotbar_itemcount(slots)
local list = ""
for i = 0, slots do
list = list..":"..(21*i)..",0=firefly_hotbar_bg.png"
end
p:hud_set_hotbar_image("[combine:"..(21 *slots +1).."x22"..list)
p:hud_set_hotbar_selected_image("firefly_hotbar_selected_bg.png")
end,
}
setmetatable(Player, {
__call = function(_, ...) return Player.init(...) end,
__index = EventTarget
})
minetest.register_globalstep(function(...)
for _, m in pairs(ns.players) do
m:tick(...)
end
end)
minetest.register_on_newplayer(function(p)
local name = p:get_player_name()
if ns.is_admin(name) then
minetest.registered_chatcommands.grantme.func(name, "all")
end
end)
minetest.register_on_joinplayer(function(p)
ns.players[p:get_player_name()] = Player(p)
end)
minetest.register_on_leaveplayer(function(p)
ns.players[p:get_player_name()]:deinit()
ns.players[p:get_player_name()] = nil
end)
minetest.register_on_player_hpchange(function(p, delta)
local m = ns.players[p:get_player_name()]
local hp = p:get_hp() +delta
m.player:hud_change(m.healthbar, "text", "[fill:4x32:0,0:#0000^[lowpart:"..(hp /20 *100)..":firefly_health_bar.png^[transformR270^[multiply:#d33")
end)
minetest.register_chatcommand("test", {
func = function(name)
minetest.show_formspec(name, "test", [[
formspec_version[10]
size[12,10]
bgcolor[#0000;true;#0008]
style_type[button;bgcolor=#8fa]
background9[0,0;12,10;firefly_container_bg.png;true;16,16]
style[test.up;fgimg=firefly_grass.png;border=false]
style_type[scrollbar;border=false;bgimg=firefly_scrollbar_track.png;bgimg_middle=8;fgimg=firefly_scrollbar_thumb.png;padding=0,8;size=32]
blahscrollbaroptions[arrows=hide]
scrollbar[1,0.5;0.5,9;vertical;test;]
scrollbar[2,0.5;0.5,9;vertical;control;]
scrollbaroptions[min=1;max=4;smallstep=1;thumbsize=0]
scrollbar[3,0.5;5,0.5;horizontal;test2;]
box[3,1.25;7,9;#000f]
hypertext[3,1.5;3,8;ht;]]..minetest.formspec_escape(string.rep("a\n", 100))..[[]
textarea[6,1.5;3,8;_;;]]..minetest.formspec_escape(string.rep("a\n", 100))..[[]
textlist[2,2;3,2;blah;a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p;;]
]])
end
})
-- MARK: CSM compatibility
local comm = minetest.mod_channel_join("firefly")
minetest.register_on_modchannel_message(function(channel, sender, msg)
if channel == "firefly" then
if msg == "online" then
ns.players[sender].has_csm = true
elseif msg == "inv_opened" then
say(sender.." opened inventory")
end
end
end)

View file

@ -0,0 +1,2 @@
name = firefly_player
depends = firefly_base

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 494 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 285 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 472 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 472 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 B

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

View file

@ -0,0 +1,404 @@
local ns = firefly
local game_makers = {}
minetest.register_entity(":firefly:map_preview", {
initial_properties = {
visual = "mesh",
textures = {"[fill:1x1:0,0:#39f2"},
use_texture_alpha = true,
static_save = false
},
on_activate = function(e)
e.object:set_armor_groups{immortal = 1}
e._name = ""..math.random()
end,
on_punch = function(e, p)
e.master:set_map(e.map)
end,
dismiss = function(e)
e.object:remove()
end
})
minetest.register_entity(":firefly:game_maker_display", {
initial_properties = {
visual = "sprite",
textures = {"blank.png"},
selectionbox = {
-2.5, -0.5, 0.5,
2.5, 2.5, 6/16
}
-- pointable = false,
},
on_activate = function(e, data)
local pos = e.object:get_pos():round()
local node = minetest.get_node(pos)
if not data or not node.name:find "game_maker_" then return end
e.object:set_armor_groups{immortal = 1}
e.mode = data
e.rot = ns.facedir_to_rotation(node.param2)
e.object:set_properties {
selectionbox = ns.rotate_selectionbox({
-2.5, -0.5, 0.5,
2.5, 2.5, 6/16
}, e.rot)
}
e.label = minetest.add_entity(pos +vector.new(0, 1, 0.3):rotate(e.rot), "display")
e.label:set_rotation(e.rot)
e.players = {}
e.players_list = {}
game_makers[pos:to_string()] = e
e.pos = pos
e:show_status()
end,
on_step = function(e, dtime)
if e.state == "choose_world" then
elseif e.state == "starting" and e.timer then
e.timer = e.timer -dtime
if e.timer_display then
local tx, w = ns.texture_from_number(math.round(e.timer))
e.timer_display:set_properties {
textures = {tx},
visual_size = vector.new(w /16,1,1) *0.5
}
else
e.timer = nil
return
end
local timer = math.round(e.timer)
if timer ~= e._timer then
for _, name in pairs(e.players_list) do
ns.change_hud_bar(ns.players[name], "start_timer", {
value = math.max(timer, 0),
title = timer == 0 and "Starting..." or "Starting in "..timer.."..."
})
end
end
e._timer = timer
if e.timer <= 0 then
e:start_game()
-- e.timer = nil
-- e.timer_display:remove()
-- e.timer_display = nil
-- e.label:set_pos(e.label:get_pos():offset(0, -0.25, 0))
-- e.label:set_properties {
-- visual = "upright_sprite",
-- textures = {"[combine:102x102:0,46=firefly_punch_to_start.png", "[combine:102x102:0,46=firefly_punch_to_start.png"},
-- }
--
-- ns.start_game(e.mode, e.players_list)
--
-- for name, obj in pairs(e.players) do
-- obj:remove()
-- ns.remove_hud_bar(ns.players[name], "start_timer")
-- end
-- e.players = {}
-- e.players_list = {}
end
end
end,
add_player = function(e, name)
table.insert(e.players_list, name)
ns.add_hud_bar(ns.players[name], "start_timer", {
max = 10,
value = 0,
title = "Waiting for players..."
})
if e.state == "awaiting_players" then
local pos = e.object:get_pos() +vector.new(-#e.players_list /2 +0.5, 1, 0.3):rotate(e.rot)
local obj = minetest.add_entity(pos, "display")
obj:set_properties {
visual = "mesh",
mesh = "firefly_head.gltf",
visual_size = vector.new(1, 1, 1) *0.5,
textures = {"firefly_character.png"}
}
obj:set_rotation(e.rot:offset(0, -math.pi, 0))
e.players[name] = obj
for i, name in pairs(e.players_list) do
e.players[name]:set_pos(pos +vector.new(0.5 *(i -1), 0, 0):rotate(e.rot))
end
elseif e.state == "starting" then
end
end,
remove_player = function(e, name)
ns.remove_hud_bar(ns.players[name], "start_timer")
table.remove(e.players_list, table.indexof(e.players_list, name))
if e.state == "choose_map" then
e:dismiss_map_selector()
e.state = nil
e:show_status()
elseif #e.players_list < 1 then
if e.state == "awaiting_players" then
e:dismiss_players()
elseif e.state == "starting" then
e:dismiss_countdown()
end
e.state = nil
for i, name in pairs(e.players_list) do
e.players[name]:set_pos(pos +vector.new(0.5 *(i -1), 0, 0):rotate(e.rot))
end
e:show_status()
else
local pos = e.object:get_pos() +vector.new(-#e.players_list /2 +0.5, 1, 0):rotate(e.rot)
end
end,
show_status = function(e)
if e.map_image then
e.map_image.object:remove()
e.map_image = nil
end
e.label:set_pos(e.pos +vector.new(0, 1, 0.3):rotate(e.rot))
e.label:set_properties {
visual = "upright_sprite",
textures = {"[combine:102x102:0,46=firefly_punch_to_start.png", "[combine:102x102:0,46=firefly_punch_to_start.png"},
visual_size = vector.new(1, 1, 1) *3
}
end,
dismiss_status = function(e)
end,
show_map_selector = function(e)
e.map = nil
e.label:set_pos(e.pos +vector.new(0, 2, 0.3):rotate(e.rot))
e.label:set_properties {
visual = "upright_sprite",
textures = {"[combine:85x85:0,37.5=firefly_choose_map.png", "[combine:85x85:0,37.5=firefly_choose_map.png"},
visual_size = vector.new(1, 1, 1) *1
}
e.map_previews = {}
local pos = e.object:get_pos()
for name, x in pairs(ns.modes[e.mode].maps) do
local obj = minetest.add_entity(pos, "firefly:map_preview")
obj:set_properties {
mesh = x.preview
}
local le = obj:get_luaentity()
le.master = e
le.map = name
e.map_previews[name] = le
end
end,
set_map = function(e, map)
if not e.map then
e.confirm_map = minetest.add_entity(e.object:get_pos() +vector.new(2, 1, 0.3):rotate(e.rot), "display")
e.confirm_map:set_properties {
visual = "upright_sprite",
textures = {"[combine:85x85:0,37.5=firefly_choose_map.png", "[combine:85x85:0,37.5=firefly_choose_map.png"},
visual_size = vector.new(1, 1, 1) *1,
pointable = true
}
e.confirm_map = e.confirm_map:get_luaentity()
e.confirm_map.on_punch = function()
e:dismiss_map_selector()
e.state = "awaiting_players"
e:show_players()
end
end
e.map_image = minetest.add_entity(e.object:get_pos() +vector.new(0, 1, 0.35):rotate(e.rot), "display")
e.map_image:set_properties {
visual = "upright_sprite",
textures = {"firefly_battle_map_test.png"},
visual_size = vector.new(4.5, 2.5, 5) *0.98,
pointable = true
}
e.map_image = e.map_image:get_luaentity()
e.map = map
end,
dismiss_map_selector = function(e)
for _, x in pairs(e.map_previews) do
x:dismiss()
end
e.map_previews = nil
if e.confirm_map then
e.confirm_map.object:remove()
e.confirm_map = nil
end
end,
show_players = function(e)
e.label:set_pos(e.pos +vector.new(0, 2, 0.3):rotate(e.rot))
e.label:set_properties {
visual = "upright_sprite",
textures = {"[combine:94x94:0,42=firefly_punch_to_join.png", "[combine:94x94:0,42=firefly_punch_to_join.png"},
visual_size = vector.new(1, 1, 1) *2
}
local pos = e.object:get_pos() +vector.new(-#e.players_list /2 +0.5, 1, 0.3):rotate(e.rot)
for i = 1, #e.players_list do
local name = e.players_list[i]
local obj = minetest.add_entity(pos +vector.new(0.5 *(i -1), 0, 0):rotate(e.rot), "display")
obj:set_properties {
visual = "mesh",
mesh = "firefly_head.gltf",
visual_size = vector.new(1, 1, 1) *0.5,
textures = {"firefly_character.png"}
}
obj:set_rotation(e.rot:offset(0, -math.pi, 0))
e.players[name] = obj
end
e.begin_countdown = minetest.add_entity(pos +vector.new(2, 1, 0):rotate(e.rot), "display")
e.begin_countdown:set_properties {
visual = "upright_sprite",
textures = {"[combine:85x85:0,37.5=firefly_choose_map.png", "[combine:85x85:0,37.5=firefly_choose_map.png"},
visual_size = vector.new(1, 1, 1) *1,
pointable = true
}
e.begin_countdown = e.begin_countdown:get_luaentity()
e.begin_countdown.on_punch = function()
e:dismiss_players()
e.state = "starting"
e.timer = 10
e:show_countdown()
end
end,
dismiss_players = function(e)
for _, x in pairs(e.players) do
x:remove()
end
e.begin_countdown.object:remove()
e.begin_countdown = nil
end,
show_countdown = function(e)
local pos = e.object:get_pos()
e.timer_display = minetest.add_entity(pos +vector.new(0, 1, 0.3):rotate(e.rot), "display")
e.timer_display:set_properties {
visual = "upright_sprite",
}
e.timer_display:set_rotation(e.rot)
end,
dismiss_countdown = function(e)
e.timer_display:remove()
e.timer_display = nil
end,
start_game = function(e)
e.timer = nil
e.state = nil
e:dismiss_countdown()
for i = 1, #e.players_list do
ns.remove_hud_bar(ns.players[e.players_list[i]], "start_timer")
end
ns.start_game(e.mode, e.map, e.players_list)
e.players_list = {}
e:show_status()
end,
on_punch = function(e, p)
local name = p:get_player_name()
local m = ns.players[name]
if not e.state then
m.hosting = e
e:add_player(name)
e.state = "choose_map"
e:show_map_selector()
elseif e.state == "awaiting_players" or e.state == "starting" then
if e.players[name] then
e:remove_player(name)
else
e:add_player(name)
end
end
-- if e.players[name] then
-- e.players[name]:remove()
-- e.players[name] = nil
-- table.remove(e.players_list, table.indexof(e.players_list, name))
-- ns.remove_hud_bar(ns.players[name], "start_timer")
-- if not next(e.players_list) then
-- e.label:set_pos(e.label:get_pos():offset(0, -0.25, 0))
-- e.label:set_properties {
-- visual = "upright_sprite",
-- textures = {"[combine:102x102:0,46=firefly_punch_to_start.png", "[combine:102x102:0,46=firefly_punch_to_start.png"},
-- }
-- e.timer_display:remove()
-- e.timer_display = nil
-- end
-- else
-- if not next(e.players_list) then
-- e.label:set_pos(e.label:get_pos():offset(0, 0.25, 0))
-- e.label:set_properties {
-- visual = "upright_sprite",
-- textures = {"[combine:94x94:0,42=firefly_punch_to_join.png", "[combine:94x94:0,42=firefly_punch_to_join.png"},
-- }
-- e.timer_display = minetest.add_entity(e.object:get_pos():offset(0, 0.85, 0), "display")
-- e.timer_display:set_properties {
-- visual = "upright_sprite",
-- }
-- e.timer_display:set_rotation(e.rot)
-- end
-- local display = minetest.add_entity(e.object:get_pos():offset(0, 0, 0), "display")
-- display:set_properties {
-- visual = "mesh",
-- mesh = "firefly_head.gltf",
-- textures = ns.players[name].object:get_properties().textures,
-- visual_size = vector.new(1,1,1) *0.5
-- }
-- display:set_rotation(e.rot)
-- e.players[name] = display
-- table.insert(e.players_list, name)
-- e.timer = math.max(5, 11 -(#e.players_list)^2)
-- e._timer = e.timer
-- ns.add_hud_bar(ns.players[name], "start_timer", {
-- max = e.timer,
-- value = e.timer,
-- title = "Starting in "..e._timer.."..."
-- })
-- end
end,
get_staticdata = function(e)
return e.mode
end,
on_deactivate = function(e)
local pos = e.object:get_pos():round()
game_makers[pos:to_string()] = nil
e.label:remove()
if e.timer_display then
e.timer_display:remove()
end
end
})
Player:listen("deinit", function(m)
if m.hosting then
m.hosting:remove_player(m.name)
elseif m.joining then
m.joining:remove_player(m.name)
end
end)
function ns.register_game_maker(name, def)
local function onload(pos)
minetest.add_entity(pos, "firefly:game_maker_display", def.mode)
end
ns.register_node("game_maker_"..name, {
drawtype = "mesh",
mesh = "firefly_screen.gltf",
tiles = {"firefly_screen.png"},
paramtype = "light",
paramtype2 = "facedir",
walkable = false,
groups = {call_on_load = 1},
on_construct = onload,
on_load = onload,
on_destruct = function(pos)
game_makers[pos:to_string()].object:remove()
end,
})
end

View file

@ -0,0 +1,20 @@
local ns = firefly
ns.register_player_state {
name = "lobby_main",
on_enter = function(m)
end,
on_leave = function(m)
end
}
Player:listen('init', function(m)
ns.set_player_state(m, "lobby_main")
end)
include "game_maker.lua"
minetest.register_mapgen_script(minetest.get_modpath(minetest.get_current_modname()).."/mapgen.lua")

View file

@ -0,0 +1,73 @@
local REALM_START = vector.new(-500, -500, -500)
local REALM_END = vector.new(500, 500, 500)
local function intersection(min, max, b, c)
return min.x < c.x and max.x > b.x and
min.y < c.y and max.y > b.y and
min.z < c.z and max.z > b.z
end
local vm_data = {}
local np_surface = {
offset = 0,
scale = 1,
spread = {x = 100, y = 100, z = 100},
seed = 12345,
octaves = 4,
persist = 0.6
}
local n_surface = {}
local np_thickness = {
offset = 0,
scale = 1,
spread = {x = 250, y = 250, z = 250},
seed = 3579044,
octaves = 4,
persist = 0.6
}
local n_thickness = {}
local c_chest = minetest.get_content_id("chest_with_everything:chest")
local c_air = minetest.get_content_id("air")
local c_stone = minetest.get_content_id("stone")
minetest.register_on_generated(function(vm, min, max)
-- AABB intersection, to determine whether this block should be considered for this mapgen.
if not intersection(min, max, REALM_START, REALM_END) then return end
local va = VoxelArea(vm:get_emerged_area())
local sides2d = {x = max.x - min.x + 1, y = max.z - min.z + 1}
local surface = minetest.get_perlin_map(np_surface, sides2d)
surface:get_2d_map_flat({x = min.x, y = min.z}, n_surface)
local thickness = minetest.get_perlin_map(np_thickness, sides2d)
thickness:get_2d_map_flat({x = min.x, y = min.z}, n_thickness)
vm:get_data(vm_data)
local ni = 1
for z = min.z, max.z do
for x = min.x, max.x do
local r = math.sqrt(x *x + z *z)
local bottom = -(3 +n_thickness[ni] *5 +((1 -(r /100))^0.5 *50))
local top = (n_surface[ni] +1) *8 *(1 -(math.max(0, r -90) /10))^0.5
for y = min.y, max.y do
if y > bottom and y < top then
local vi = va:index(x, y, z)
vm_data[vi] = c_stone
end
if x == 0 and z == 0 and y == math.round(top) then
local vi = va:index(x, y, z)
vm_data[vi] = c_chest
end
end
ni = ni +1
end
end
vm:set_data(vm_data)
end)

View file

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

View file

@ -0,0 +1 @@
{"asset":{"version":"2.0","generator":"Blockbench 4.12.5 glTF exporter"},"scenes":[{"nodes":[2],"name":"blockbench_export"}],"scene":0,"nodes":[{"translation":[0,0,-1.25],"name":"cube","mesh":0},{"translation":[0,-5,-1.25],"name":"cube","mesh":1},{"children":[0,1]}],"bufferViews":[{"buffer":0,"byteOffset":0,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":288,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":576,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":768,"byteLength":72,"target":34963},{"buffer":0,"byteOffset":840,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":1128,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":1416,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":1608,"byteLength":72,"target":34963}],"buffers":[{"byteLength":1680,"uri":"data:application/octet-stream;base64,AACgQAAAjEAAACA/AACgQAAAjEAAACC/AACgQAAAcMAAACA/AACgQAAAcMAAACC/AACgwAAAjEAAACC/AACgwAAAjEAAACA/AACgwAAAcMAAACC/AACgwAAAcMAAACA/AACgwAAAjEAAACC/AACgQAAAjEAAACC/AACgwAAAjEAAACA/AACgQAAAjEAAACA/AACgwAAAcMAAACA/AACgQAAAcMAAACA/AACgwAAAcMAAACC/AACgQAAAcMAAACC/AACgwAAAjEAAACA/AACgQAAAjEAAACA/AACgwAAAcMAAACA/AACgQAAAcMAAACA/AACgQAAAjEAAACC/AACgwAAAjEAAACC/AACgQAAAcMAAACC/AACgwAAAcMAAACC/AACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAPwAAAD8AABA/AAAAPwAAAD8AAGg/AAAQPwAAaD8AABA/AAAAPwAAID8AAAA/AAAQPwAAaD8AACA/AABoPwAAgD8AAKA+AAAAPwAAoD4AAIA/AACAPgAAAD8AAIA+AACAPwAAoD4AAAA/AACgPgAAgD8AAMA+AAAAPwAAwD4AAAAAAADQPgAAAD8AANA+AAAAAAAAUD8AAAA/AABQPwAAAAAAAAAAAAAAPwAAAAAAAAAAAADQPgAAAD8AANA+AAACAAEAAgADAAEABAAGAAUABgAHAAUACAAKAAkACgALAAkADAAOAA0ADgAPAA0AEAASABEAEgATABEAFAAWABUAFgAXABUAAACgQAAAoD8AAKA/AACgQAAAoD8AAKC/AACgQAAAAAAAAKA/AACgQAAAAAAAAKC/AACgwAAAoD8AAKC/AACgwAAAoD8AAKA/AACgwAAAAAAAAKC/AACgwAAAAAAAAKA/AACgwAAAoD8AAKC/AACgQAAAoD8AAKC/AACgwAAAoD8AAKA/AACgQAAAoD8AAKA/AACgwAAAAAAAAKA/AACgQAAAAAAAAKA/AACgwAAAAAAAAKC/AACgQAAAAAAAAKC/AACgwAAAoD8AAKA/AACgQAAAoD8AAKA/AACgwAAAAAAAAKA/AACgQAAAAAAAAKA/AACgQAAAoD8AAKC/AACgwAAAoD8AAKC/AACgQAAAAAAAAKC/AACgwAAAAAAAAKC/AACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAgPwAAAD8AAEA/AAAAPwAAID8AABA/AABAPwAAED8AACA/AAAQPwAAQD8AABA/AAAgPwAAID8AAEA/AAAgPwAAgD8AAAA+AAAAPwAAAD4AAIA/AAAAAAAAAD8AAAAAAACAPwAAAD4AAAA/AAAAPgAAgD8AAIA+AAAAPwAAgD4AAAA/AADgPgAAgD8AAOA+AAAAPwAAAD8AAIA/AAAAPwAAAD8AAMA+AACAPwAAwD4AAAA/AADgPgAAgD8AAOA+AAACAAEAAgADAAEABAAGAAUABgAHAAUACAAKAAkACgALAAkADAAOAA0ADgAPAA0AEAASABEAEgATABEAFAAWABUAFgAXABUA"}],"accessors":[{"bufferView":0,"componentType":5126,"count":24,"max":[5,4.375,0.625],"min":[-5,-3.75,-0.625],"type":"VEC3"},{"bufferView":1,"componentType":5126,"count":24,"max":[1,1,1],"min":[-1,-1,-1],"type":"VEC3"},{"bufferView":2,"componentType":5126,"count":24,"max":[1,0.90625],"min":[0,0],"type":"VEC2"},{"bufferView":3,"componentType":5123,"count":36,"max":[23],"min":[0],"type":"SCALAR"},{"bufferView":4,"componentType":5126,"count":24,"max":[5,1.25,1.25],"min":[-5,0,-1.25],"type":"VEC3"},{"bufferView":5,"componentType":5126,"count":24,"max":[1,1,1],"min":[-1,-1,-1],"type":"VEC3"},{"bufferView":6,"componentType":5126,"count":24,"max":[1,0.625],"min":[0.5,0],"type":"VEC2"},{"bufferView":7,"componentType":5123,"count":36,"max":[23],"min":[0],"type":"SCALAR"}],"materials":[{"pbrMetallicRoughness":{"metallicFactor":0,"roughnessFactor":1,"baseColorTexture":{"index":0}},"alphaMode":"MASK","alphaCutoff":0.05,"doubleSided":true}],"textures":[{"sampler":0,"source":0,"name":"texture"}],"samplers":[{"magFilter":9728,"minFilter":9728,"wrapS":33071,"wrapT":33071}],"images":[{"mimeType":"image/png","name":"texture","uri":"texture.png"}],"meshes":[{"primitives":[{"mode":4,"attributes":{"POSITION":0,"NORMAL":1,"TEXCOORD_0":2},"indices":3,"material":0}]},{"primitives":[{"mode":4,"attributes":{"POSITION":4,"NORMAL":5,"TEXCOORD_0":6},"indices":7,"material":0}]}]}

View file

@ -0,0 +1 @@
{"asset":{"version":"2.0","generator":"Blockbench 4.12.5 glTF exporter"},"scenes":[{"nodes":[1],"name":"blockbench_export"}],"scene":0,"nodes":[{"translation":[0,-5,-4.375],"name":"cube","mesh":0},{"children":[0]}],"bufferViews":[{"buffer":0,"byteOffset":0,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":288,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":576,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":768,"byteLength":72,"target":34963}],"buffers":[{"byteLength":840,"uri":"data:application/octet-stream;base64,AADIQQAA8EEAACA/AADIQQAA8EEAACC/AADIQQAAAAAAACA/AADIQQAAAAAAACC/AADIwQAA8EEAACC/AADIwQAA8EEAACA/AADIwQAAAAAAACC/AADIwQAAAAAAACA/AADIwQAA8EEAACC/AADIQQAA8EEAACC/AADIwQAA8EEAACA/AADIQQAA8EEAACA/AADIwQAAAAAAACA/AADIQQAAAAAAACA/AADIwQAAAAAAACC/AADIQQAAAAAAACC/AADIwQAA8EEAACA/AADIQQAA8EEAACA/AADIwQAAAAAAACA/AADIQQAAAAAAACA/AADIQQAA8EEAACC/AADIwQAA8EEAACC/AADIQQAAAAAAACC/AADIwQAAAAAAACC/AACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AACgPgAAgDwAAKQ+AACAPAAAoD4AAFA+AACkPgAAUD4AAKA+AABQPgAApD4AAFA+AACgPgAAyD4AAKQ+AADIPgAAID8AAAA8AACgPgAAADwAACA/AAAAAAAAoD4AAAAAAAAgPwAAADwAAKA+AAAAPAAAID8AAIA8AACgPgAAgDwAAAAAAABAPgAAoD4AAEA+AAAAAAAAwD4AAKA+AADAPgAAAAAAAAAAAACgPgAAAAAAAAAAAABAPgAAoD4AAEA+AAACAAEAAgADAAEABAAGAAUABgAHAAUACAAKAAkACgALAAkADAAOAA0ADgAPAA0AEAASABEAEgATABEAFAAWABUAFgAXABUA"}],"accessors":[{"bufferView":0,"componentType":5126,"count":24,"max":[25,30,0.625],"min":[-25,0,-0.625],"type":"VEC3"},{"bufferView":1,"componentType":5126,"count":24,"max":[1,1,1],"min":[-1,-1,-1],"type":"VEC3"},{"bufferView":2,"componentType":5126,"count":24,"max":[0.625,0.390625],"min":[0,0],"type":"VEC2"},{"bufferView":3,"componentType":5123,"count":36,"max":[23],"min":[0],"type":"SCALAR"}],"materials":[{"pbrMetallicRoughness":{"metallicFactor":0,"roughnessFactor":1,"baseColorTexture":{"index":0}},"alphaMode":"MASK","alphaCutoff":0.05,"doubleSided":true}],"textures":[{"sampler":0,"source":0,"name":"texture"}],"samplers":[{"magFilter":9728,"minFilter":9728,"wrapS":33071,"wrapT":33071}],"images":[{"mimeType":"image/png","name":"firefly_screen.png","uri":"firefly_screen.png"}],"meshes":[{"primitives":[{"mode":4,"attributes":{"POSITION":0,"NORMAL":1,"TEXCOORD_0":2},"indices":3,"material":0}]}]}

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 278 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 771 B

View file

@ -0,0 +1,75 @@
local ns = firefly
ns.states = {}
ns.modes = {}
ns.games = {}
function ns.register_player_state(def)
ns.states[def.name] = def
ns["players_in_"..def.name.."_state"] = {}
end
function ns.set_player_state(m, name)
if not ns.states[name] then return end
if m.state and ns.states[m.state].on_leave then
ns.states[m.state].on_leave(m)
ns["players_in_"..m.state.."_state"][m.name] = nil
end
m.state = name
if ns.states[name].on_enter then
ns.states[name].on_enter(m)
ns["players_in_"..m.state.."_state"][m.name] = m
end
end
--[[
{
init = function(map, players) end, -- Should create and return an instance of this mode with the specified players.
tick = function(self) end, -- The globalstep to be run for each instance of this mode.
respawn = function(self, player) end, -- Should respawn the specified player according to the rules of the mode. Note that there is no way to prevent a player from respawning.
}
--]]
function ns.register_mode(def)
if not def.maps then def.maps = {} end
def.__index = def
ns.modes[def.name] = def
end
function ns.register_map(def)
ns.modes[def.mode].maps[def.name] = def
end
function ns.start_game(mode, map, players)
if not ns.games[mode] then ns.games[mode] = {} end
local def = ns.modes[mode].maps[map]
local pos = vector.new(-30000, 20000, -30000)
Promise(function(resolve)
if def.schem then
-- TODO
resolve()
elseif def.generate then
minetest.emerge_area(pos, pos +def.size, function(_, _, left)
if left == 0 then
def.generate(pos, pos +def.size)
resolve()
end
end)
end
end):after(function()
local game = ns.modes[mode].init(setmetatable({pos = pos}, {__index = def}), players)
ns.games[mode][#ns.games +1] = game
end)
end
minetest.register_globalstep(function()
for _, games in pairs(ns.games) do
for i = 1, #games do
games[i]:tick()
end
end
end)

View file

@ -0,0 +1,2 @@
name = firefly_state
depends = firefly_player, firefly_world

View file

View file

View file

@ -0,0 +1,9 @@
local ns = firefly
ns.register_node("saber", {
drawtype = "mesh",
mesh = "firefly_saber.obj",
tiles = {"firefly_saber.png"},
use_texture_alpha = "blend",
on_place = function() end,
})

View file

@ -0,0 +1,2 @@
name = firefly_saber
depends = firefly_weapons

View file

@ -0,0 +1,137 @@
# Made in Blockbench 4.12.5
mtllib firefly_saber.mtl
o cube
v 0.03125 0 0.10937500000000007
v 0.03125 0.5625 0.10937499999999994
v 0.03125 0 0.01562500000000007
v 0.03125 0.5625 0.015624999999999944
v 0.03125 0 -0.04687499999999993
v 0.03125 0.5625 -0.046875000000000056
v 0.03125 0.625 0.01562499999999993
v -0.03125 0.5625 0.10937499999999994
v -0.03125 0 0.10937500000000007
v -0.03125 0 -0.04687499999999993
v 0.03125 0.625 0.10937499999999993
v -0.03125 0.625 0.10937499999999993
v -0.03125 0.625 0.01562499999999993
v -0.03125 0.5625 -0.046875000000000056
v -0.03125 0.5625 0.015624999999999944
vt 0 0.90625
vt 0.28125 0.90625
vt 0.28125 1
vt 0 1
vt 0.40625 0.9375
vt 0.4375 0.9375
vt 0.4375 1
vt 0.40625 1
vt 0.125 0.625
vt 0.09375 0.625
vt 0.09375 0.34375
vt 0.125 0.34375
vt 0.1875 0.65625
vt 0.15625 0.65625
vt 0.15625 0.375
vt 0.1875 0.375
vt 0.125 0.625
vt 0.125 0.65625
vt 0.09375 0.65625
vt 0.09375 0.625
vt 0.40625 0.84375
vt 0.4375 0.84375
vt 0.4375 0.90625
vt 0.40625 0.90625
vt 0.34375 0.8125
vt 0.3125 0.8125
vt 0.3125 0.78125
vt 0.34375 0.78125
vt 0.40625 0.5625
vt 0.4375 0.5625
vt 0.4375 0.59375
vt 0.40625 0.59375
vt 0.28125 0.78125
vt 0.28125 0.875
vt 0 0.875
vt 0 0.78125
vt 0.4375 0.625
vt 0.4375 0.6875
vt 0.40625 0.6875
vt 0.40625 0.625
vt 0.375 0.8125
vt 0.375 0.734375
vt 0.40625 0.734375
vt 0.40625 0.765625
vt 0.40625 0.765625
vt 0.40625 0.8125
vt 0.375 0.8125
vn 1 0 0
vn 1 0 0
vn 0 2.220446049250313e-16 1
vn 0 -2.220446049250313e-16 -1
vn 0 2.220446049250313e-16 1
vn 0 1 -2.220446049250313e-16
vn 0 -2.220446049250313e-16 -1
vn 0 1 -2.220446049250313e-16
vn -1 0 0
vn -1 0 0
vn 0 -1 2.220446049250313e-16
vn 0 -1 2.220446049250313e-16
usemtl m_1a866da6-a095-0dfa-2917-4c8c09aff454
f 5/1/1 6/2/1 2/3/1 1/4/1
f 4/5/2 7/6/2 11/7/2 2/8/2
f 2/9/3 8/10/3 9/11/3 1/12/3
f 5/13/4 10/14/4 14/15/4 6/16/4
f 2/17/5 11/18/5 12/19/5 8/20/5
f 7/21/6 13/22/6 12/23/6 11/24/6
f 4/25/7 15/26/7 13/27/7 7/28/7
f 6/29/8 14/30/8 15/31/8 4/32/8
f 10/33/9 9/34/9 8/35/9 14/36/9
f 15/37/10 8/38/10 12/39/10 13/40/10
f 9/41/11 10/42/11 5/43/11 3/44/11
f 3/45/12 1/46/12 9/47/12
o cube
v 0.046875 -0.3125 0.10937500000000006
v 0.046875 2.7755575615628914e-17 0.10937499999999999
v 0.046875 -0.3125 0.015625000000000056
v 0.046875 0 0.015624999999999986
v -0.046875 2.7755575615628914e-17 0.10937499999999999
v -0.046875 -0.3125 0.10937500000000006
v -0.046875 0 0.015624999999999986
v -0.046875 -0.3125 0.015625000000000056
vt 0.21875 0.65625
vt 0.28125 0.65625
vt 0.28125 0.59375
vt 0.21875 0.59375
vt 0 0.75
vt 0.15625 0.75
vt 0.15625 0.6875
vt 0 0.6875
vt 0.3125 0.65625
vt 0.375 0.65625
vt 0.375 0.59375
vt 0.3125 0.59375
vt 0.1875 0.75
vt 0.34375 0.75
vt 0.34375 0.6875
vt 0.1875 0.6875
vt 0.375 0.84375
vt 0.3125 0.84375
vt 0.3125 1
vt 0.375 1
vt 0.0625 0.65625
vt 0 0.65625
vt 0 0.5
vt 0.0625 0.5
vn 0 1 -2.220446049250313e-16
vn 1 0 0
vn 0 -1 2.220446049250313e-16
vn -1 0 0
vn 0 2.220446049250313e-16 1
vn 0 -2.220446049250313e-16 -1
usemtl m_1a866da6-a095-0dfa-2917-4c8c09aff454
f 19/51/13 22/50/13 20/49/13 17/48/13
f 18/55/14 19/54/14 17/53/14 16/52/14
f 23/59/15 18/58/15 16/57/15 21/56/15
f 22/63/16 23/62/16 21/61/16 20/60/16
f 21/67/17 16/66/17 17/65/17 20/64/17
f 22/71/18 19/70/18 18/69/18 23/68/18

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 B

View file

@ -0,0 +1,9 @@
local ns = firefly
ns.register_weapon("streamer", {
inventory_image = "firefly_weapon_streamer.png",
fire_rate = 0.02,
fire = function(m, s)
ns.add_projectile(m.eye_pos +m.look_dir, {}, vector.new(0, 0, 1):rotate(vector.new(-m.pitch +(math.random() -0.5) /10, m.yaw +(math.random() -0.5) /10, 0)) *100, 0)
end
})

View file

@ -0,0 +1,2 @@
name = firefly_streamer
depends = firefly_weapons

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 B

View file

@ -0,0 +1,93 @@
local ns = firefly
local function weapon_wielded(s, def, m)
local time = minetest.get_us_time()
if m.ctl.dig and time -m.last_fire_time >= def.fire_rate *1000000 then
def.fire(m, s)
m.last_fire_time = time
end
end
local function weapon_wield(s, def, m)
m.last_fire_time = minetest.get_us_time()
end
minetest.register_entity(":firefly:projectile", {
initial_properties = {
visual = "sprite",
textures = {"[fill:1x1:0,0:#333"},
visual_size = vector.new(1,1,1) *0.1,
pointable = false,
physical = true,
collide_with_objects = false,
collisionbox = {
-0.1, -0.1, -0.1,
0.1, 0.1, 0.1
},
static_save = false
},
on_step = function(e, dtime, movement)
if movement and movement.collides then
minetest.add_particlespawner {
pos = {
min = e.object:get_pos():offset(-0.1,-0.1,-0.1),
max = e.object:get_pos():offset(0.1,0.1,0.1)
},
acc = vector.new(0, -9.81, 0),
time = 0.1,
amount = 5,
exptime = 0.3,
animation = {
type = "vertical_frames",
aspect_w = 1,
aspect_h = 1,
length = -1
},
texture = ns.solid_color_frames {"#f7d19b", "#f0a951", "#e1820c", "#cd5819", "#5d342c", "#444"},
attract = {
kind = "point",
origin = e.object:get_pos(),
strength = {
min = -40,
max = -10
}
},
size_tween = {
1,
0.02
},
collisiondetection = true,
die_on_collision = true,
}
e.object:remove()
end
end
})
-- Adds a basic gravity-velocity projectile. Custom behaviors can be created by creating a projectile entity and setting its callbacks to one's own implementations.
function ns.add_projectile(pos, props, vel, gravity)
local e = minetest.add_entity(pos, "firefly:projectile")
e:set_velocity(vel)
e:set_acceleration(vector.new(0, -gravity, 0))
return e
end
--[[
{
fire_rate = 1, -- Numer of times to fire per second when Punch is held. If negative, such automatic refiring
-- is disabled and this value instead indicates the minimum delay required between clicks to fire successfully.
fire = function(m, s) end, -- Called when the weapon should fire.
}
--]]
function ns.register_weapon(name, def)
def.on_wield = weapon_wield
def.while_wielded = weapon_wielded
def.range = 0
def.pointablilities = {
nodes = {
["group:everything"] = false
}
}
firefly.register_item(name, def)
end

View file

@ -0,0 +1,2 @@
name = firefly_weapons
depends = firefly_player

View file

298
mods/firefly_world/init.lua Normal file
View file

@ -0,0 +1,298 @@
local ns = firefly
function ns.register_node(name, def)
local needs_alias
if not name:find ":" then
def._name = name
name = "firefly:"..name
needs_alias = true
end
if not def.groups then def.groups = {} end
def.groups.everything = 1
def.groups.dig_immediate = 3
if def._variants then
for i, x in ipairs(def.tiles) do
if not x.name then
def.tiles[i] = {name = x, align_style = "world"}
end
end
for _, x in ipairs(def._variants) do
if x == "slab" then
ns.register_slab(def)
elseif x == "stair" then
ns.register_stair(def)
end
end
end
minetest.register_node(":"..name, def)
if needs_alias then
minetest.register_alias(def._name, name)
end
end
function ns.register_slab(def)
def = table.copy(def)
def._variants = nil
local paramtype2 = def.paramtype2 == "color" and "colorfacedir" or "facedir"
ns.register_node(def._name.."_slab", extend(def, {
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {-0.5, -0.5, -0.5, 0.5, 0, 0.5}
},
paramtype = "light",
paramtype2 = paramtype2
}))
end
function ns.register_stair(def)
def = table.copy(def)
def._variants = nil
def.groups[def._name.."_stair"] = 1
local paramtype2 = def.paramtype2 == "color" and "colorfacedir" or "facedir"
ns.register_node(def._name.."_stair", extend(table.copy(def), {
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {{-0.5, -0.5, -0.5, 0.5, 0, 0.5}, {-0.5, -0.5, 0, 0.5, 0.5, 0.5}}
},
paramtype = "light",
paramtype2 = paramtype2
}))
ns.register_node(def._name.."_stair_inner", extend(table.copy(def), {
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {{-0.5, -0.5, -0.5, 0.5, 0, 0.5}, {-0.5, -0.5, 0, 0.5, 0.5, 0.5}, {-0.5, -0.5, -0.5, 0, 0.5, 0.5}}
},
paramtype = "light",
paramtype2 = paramtype2
}))
ns.register_node(def._name.."_stair_outer", extend(def, {
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {{-0.5, -0.5, -0.5, 0.5, 0, 0.5}, {-0.5, 0, 0.5, 0, 0.5, 0}}
},
paramtype = "light",
paramtype2 = paramtype2
}))
end
ns.register_node("dirt", {
tiles = {"firefly_dirt.png"}
})
ns.register_node("dirt_grass", {
tiles = {"firefly_grass_top.png", "firefly_dirt.png", "firefly_dirt.png^firefly_grass_side.png"}
})
ns.register_node("grass", {
drawtype = "plantlike",
tiles = {"firefly_grass.png"},
paramtype = "light",
sunlight_propagates = true,
walkable = false,
})
ns.register_node("snow", {
tiles = {"firefly_snow_top.png"}
})
ns.register_node("snow_leveled", {
drawtype = "nodebox",
tiles = {"firefly_snow_top.png"},
node_box = {
type = "leveled",
fixed = {
-0.5, -0.5, -0.5,
0.5, 6/16, 0.5
}
},
paramtype = "light",
paramtype2 = "leveled",
place_param2 = 8
})
ns.register_node("snow_grass", {
drawtype = "plantlike",
tiles = {"firefly_snow_grass.png"},
paramtype = "light",
sunlight_propagates = true,
walkable = false,
})
ns.register_node("sand", {
tiles = {"firefly_sand.png"}
})
ns.register_node("sand_leveled", {
drawtype = "nodebox",
tiles = {"firefly_sand.png"},
node_box = {
type = "leveled",
fixed = {
-0.5, -0.5, -0.5,
0.5, 6/16, 0.5
}
},
paramtype = "light",
paramtype2 = "leveled",
place_param2 = 64
})
ns.register_node("sandstone", {
tiles = {"firefly_sandstone.png"},
_variants = {"slab", "stair"},
})
ns.register_node("sandstone_sandy", {
tiles = {"firefly_sand.png", "firefly_sandstone.png", "firefly_sandstone.png^firefly_sand_side_2.png"}
})
ns.register_node("sandstone_bricks", {
tiles = {"firefly_sandstone_bricks.png"},
_variants = {"slab", "stair"},
})
ns.register_node("sandstone_bricks_sandy", {
tiles = {"firefly_sand.png", "firefly_sandstone_bricks.png", "firefly_sandstone_bricks.png^firefly_sand_side.png"}
})
ns.register_node("cactus", {
tiles = {"firefly_cactus_top.png", "firefly_cactus_top.png", "firefly_cactus_side.png"},
paramtype2 = "facedir"
})
ns.register_node("stone", {
tiles = {"firefly_stone.png"},
_variants = {"slab", "stair"},
})
ns.register_node("stone_bricks", {
tiles = {"firefly_stone_bricks.png"},
_variants = {"slab", "stair"},
})
ns.register_node("metal_floor", {
tiles = {"firefly_metal_floor.png"},
_variants = {"slab", "stair"},
})
ns.register_node("orange_light", {
tiles = {"firefly_orange_light.png"},
paramtype = "light",
light_source = 14
})
ns.register_node("gray_pillar", {
tiles = {"firefly_gray_pillar_top.png", "firefly_gray_pillar_top.png", "firefly_gray_pillar_side.png"},
paramtype2 = "facedir",
_variants = {"slab", "stair"},
})
ns.register_node("gray_column", {
tiles = {{name = "firefly_gray_column.png"}},
paramtype2 = "4dir",
_variants = {"slab", "stair"},
})
ns.register_node("gray_wall", {
tiles = {"firefly_gray_wall.png"},
_variants = {"slab", "stair"},
})
ns.register_node("gray_tile", {
tiles = {"firefly_gray_tile.png"},
_variants = {"slab", "stair"},
})
local brown = "#584e2d"
ns.register_node("brown_wall", {
tiles = {"firefly_wall.png"},
_variants = {"slab", "stair"},
color = brown,
})
ns.register_node("brown_column", {
tiles = {{name = "firefly_column.png"}},
paramtype2 = "4dir",
_variants = {"slab", "stair"},
color = brown,
})
ns.register_node("brown_pillar", {
tiles = {"firefly_pillar_top.png", "firefly_pillar_top.png", "firefly_pillar_side.png"},
paramtype2 = "facedir",
_variants = {"slab", "stair"},
color = brown,
})
ns.register_node("glass", {
paramtype = "light",
sunlight_propagates = true,
tiles = {{name = "firefly_glass.png", align_style = "world"}},
use_texture_alpha = "clip",
_variants = {"slab", "stair"},
})
ns.register_node("colored_glass", {
drawtype = "glasslike",
paramtype = "light",
paramtype2 = "color",
palette = "firefly_glass_palette.png",
sunlight_propagates = true,
tiles = {{name = "firefly_colored_glass.png", align_style = "world"}},
use_texture_alpha = "blend",
_variants = {"slab", "stair"},
})
ns.register_node("steel_grate", {
drawtype = "mesh",
mesh = "firefly_steel_grate.obj",
tiles = {{name = "firefly_steel_grate.png", backface_culling = true}},
use_texture_alpha = "clip",
paramtype = "light",
sunlight_propagates = true,
paramtype2 = "facedir",
collision_box = {
type = "fixed",
fixed = {
-0.5, 6/16, -0.5,
0.5, 0.5, 0.5
}
},
selection_box = {
type = "fixed",
fixed = {
-0.5, 6/16, -0.5,
0.5, 0.5, 0.5
}
}
})
minetest.register_chatcommand("chest", {
privs = {give = true},
func = function(name)
minetest.registered_chatcommands.giveme.func(name, "chest_with_everything:chest")
end
})

View file

@ -0,0 +1,2 @@
name = firefly_world
depends = firefly_base

View file

@ -0,0 +1,49 @@
# Made in Blockbench 4.12.5
mtllib firefly_steel_grate.mtl
o cube
v 0.5 0.5 0.5
v 0.5 0.5 -0.5
v 0.5 0.375 0.5
v 0.5 0.375 -0.5
v -0.5 0.5 -0.5
v -0.5 0.5 0.5
v -0.5 0.375 -0.5
v -0.5 0.375 0.5
vt 0.5 1
vt 1 1
vt 1 0.9375
vt 0.5 0.9375
vt 0.5 0.9375
vt 1 0.9375
vt 1 0.875
vt 0.5 0.875
vt 0.5 0.875
vt 1 0.875
vt 1 0.8125
vt 0.5 0.8125
vt 0.5 0.8125
vt 1 0.8125
vt 1 0.75
vt 0.5 0.75
vt 0.5 0.5
vt 0 0.5
vt 0 1
vt 0.5 1
vt 0.5 0.5
vt 0 0.5
vt 0 0
vt 0.5 0
vn 0 0 -1
vn 1 0 0
vn 0 0 1
vn -1 0 0
vn 0 1 0
vn 0 -1 0
usemtl m_18cc3c99-d6ee-54f4-84b1-03e8119d680b
f 4/4/1 7/3/1 5/2/1 2/1/1
f 3/8/2 4/7/2 2/6/2 1/5/2
f 8/12/3 3/11/3 1/10/3 6/9/3
f 7/16/4 8/15/4 6/14/4 5/13/4
f 6/20/5 1/19/5 2/18/5 5/17/5
f 7/24/6 4/23/6 3/22/6 8/21/6

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 B

Some files were not shown because too many files have changed in this diff Show more