Initial commit.
121
LICENSE.txt
Normal file
|
|
@ -0,0 +1,121 @@
|
||||||
|
Creative Commons Legal Code
|
||||||
|
|
||||||
|
CC0 1.0 Universal
|
||||||
|
|
||||||
|
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
|
||||||
|
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
|
||||||
|
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
|
||||||
|
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
|
||||||
|
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
|
||||||
|
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
|
||||||
|
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
|
||||||
|
HEREUNDER.
|
||||||
|
|
||||||
|
Statement of Purpose
|
||||||
|
|
||||||
|
The laws of most jurisdictions throughout the world automatically confer
|
||||||
|
exclusive Copyright and Related Rights (defined below) upon the creator
|
||||||
|
and subsequent owner(s) (each and all, an "owner") of an original work of
|
||||||
|
authorship and/or a database (each, a "Work").
|
||||||
|
|
||||||
|
Certain owners wish to permanently relinquish those rights to a Work for
|
||||||
|
the purpose of contributing to a commons of creative, cultural and
|
||||||
|
scientific works ("Commons") that the public can reliably and without fear
|
||||||
|
of later claims of infringement build upon, modify, incorporate in other
|
||||||
|
works, reuse and redistribute as freely as possible in any form whatsoever
|
||||||
|
and for any purposes, including without limitation commercial purposes.
|
||||||
|
These owners may contribute to the Commons to promote the ideal of a free
|
||||||
|
culture and the further production of creative, cultural and scientific
|
||||||
|
works, or to gain reputation or greater distribution for their Work in
|
||||||
|
part through the use and efforts of others.
|
||||||
|
|
||||||
|
For these and/or other purposes and motivations, and without any
|
||||||
|
expectation of additional consideration or compensation, the person
|
||||||
|
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
|
||||||
|
is an owner of Copyright and Related Rights in the Work, voluntarily
|
||||||
|
elects to apply CC0 to the Work and publicly distribute the Work under its
|
||||||
|
terms, with knowledge of his or her Copyright and Related Rights in the
|
||||||
|
Work and the meaning and intended legal effect of CC0 on those rights.
|
||||||
|
|
||||||
|
1. Copyright and Related Rights. A Work made available under CC0 may be
|
||||||
|
protected by copyright and related or neighboring rights ("Copyright and
|
||||||
|
Related Rights"). Copyright and Related Rights include, but are not
|
||||||
|
limited to, the following:
|
||||||
|
|
||||||
|
i. the right to reproduce, adapt, distribute, perform, display,
|
||||||
|
communicate, and translate a Work;
|
||||||
|
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||||
|
iii. publicity and privacy rights pertaining to a person's image or
|
||||||
|
likeness depicted in a Work;
|
||||||
|
iv. rights protecting against unfair competition in regards to a Work,
|
||||||
|
subject to the limitations in paragraph 4(a), below;
|
||||||
|
v. rights protecting the extraction, dissemination, use and reuse of data
|
||||||
|
in a Work;
|
||||||
|
vi. database rights (such as those arising under Directive 96/9/EC of the
|
||||||
|
European Parliament and of the Council of 11 March 1996 on the legal
|
||||||
|
protection of databases, and under any national implementation
|
||||||
|
thereof, including any amended or successor version of such
|
||||||
|
directive); and
|
||||||
|
vii. other similar, equivalent or corresponding rights throughout the
|
||||||
|
world based on applicable law or treaty, and any national
|
||||||
|
implementations thereof.
|
||||||
|
|
||||||
|
2. Waiver. To the greatest extent permitted by, but not in contravention
|
||||||
|
of, applicable law, Affirmer hereby overtly, fully, permanently,
|
||||||
|
irrevocably and unconditionally waives, abandons, and surrenders all of
|
||||||
|
Affirmer's Copyright and Related Rights and associated claims and causes
|
||||||
|
of action, whether now known or unknown (including existing as well as
|
||||||
|
future claims and causes of action), in the Work (i) in all territories
|
||||||
|
worldwide, (ii) for the maximum duration provided by applicable law or
|
||||||
|
treaty (including future time extensions), (iii) in any current or future
|
||||||
|
medium and for any number of copies, and (iv) for any purpose whatsoever,
|
||||||
|
including without limitation commercial, advertising or promotional
|
||||||
|
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
|
||||||
|
member of the public at large and to the detriment of Affirmer's heirs and
|
||||||
|
successors, fully intending that such Waiver shall not be subject to
|
||||||
|
revocation, rescission, cancellation, termination, or any other legal or
|
||||||
|
equitable action to disrupt the quiet enjoyment of the Work by the public
|
||||||
|
as contemplated by Affirmer's express Statement of Purpose.
|
||||||
|
|
||||||
|
3. Public License Fallback. Should any part of the Waiver for any reason
|
||||||
|
be judged legally invalid or ineffective under applicable law, then the
|
||||||
|
Waiver shall be preserved to the maximum extent permitted taking into
|
||||||
|
account Affirmer's express Statement of Purpose. In addition, to the
|
||||||
|
extent the Waiver is so judged Affirmer hereby grants to each affected
|
||||||
|
person a royalty-free, non transferable, non sublicensable, non exclusive,
|
||||||
|
irrevocable and unconditional license to exercise Affirmer's Copyright and
|
||||||
|
Related Rights in the Work (i) in all territories worldwide, (ii) for the
|
||||||
|
maximum duration provided by applicable law or treaty (including future
|
||||||
|
time extensions), (iii) in any current or future medium and for any number
|
||||||
|
of copies, and (iv) for any purpose whatsoever, including without
|
||||||
|
limitation commercial, advertising or promotional purposes (the
|
||||||
|
"License"). The License shall be deemed effective as of the date CC0 was
|
||||||
|
applied by Affirmer to the Work. Should any part of the License for any
|
||||||
|
reason be judged legally invalid or ineffective under applicable law, such
|
||||||
|
partial invalidity or ineffectiveness shall not invalidate the remainder
|
||||||
|
of the License, and in such case Affirmer hereby affirms that he or she
|
||||||
|
will not (i) exercise any of his or her remaining Copyright and Related
|
||||||
|
Rights in the Work or (ii) assert any associated claims and causes of
|
||||||
|
action with respect to the Work, in either case contrary to Affirmer's
|
||||||
|
express Statement of Purpose.
|
||||||
|
|
||||||
|
4. Limitations and Disclaimers.
|
||||||
|
|
||||||
|
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
||||||
|
surrendered, licensed or otherwise affected by this document.
|
||||||
|
b. Affirmer offers the Work as-is and makes no representations or
|
||||||
|
warranties of any kind concerning the Work, express, implied,
|
||||||
|
statutory or otherwise, including without limitation warranties of
|
||||||
|
title, merchantability, fitness for a particular purpose, non
|
||||||
|
infringement, or the absence of latent or other defects, accuracy, or
|
||||||
|
the present or absence of errors, whether or not discoverable, all to
|
||||||
|
the greatest extent permissible under applicable law.
|
||||||
|
c. Affirmer disclaims responsibility for clearing rights of other persons
|
||||||
|
that may apply to the Work or any use thereof, including without
|
||||||
|
limitation any person's Copyright and Related Rights in the Work.
|
||||||
|
Further, Affirmer disclaims responsibility for obtaining any necessary
|
||||||
|
consents, permissions or other rights required for any use of the
|
||||||
|
Work.
|
||||||
|
d. Affirmer understands and acknowledges that Creative Commons is not a
|
||||||
|
party to this document and has no duty or obligation with respect to
|
||||||
|
this CC0 or use of the Work.
|
||||||
8
game.conf
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
name = firefly
|
||||||
|
title = Firefly
|
||||||
|
description = TBD
|
||||||
|
allowed_mapgens = singlenode
|
||||||
|
disallowed_mapgens = v5, v7, flat, fractal, valleys, carpathian, v6
|
||||||
|
min_minetest_version = 5.10
|
||||||
|
disabled_settings = !enable_damage, creative_mode
|
||||||
|
author = Signal
|
||||||
7
mods/firefly_admin/init.lua
Normal 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
|
||||||
2
mods/firefly_admin/mod.conf
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
name = firefly_admin
|
||||||
|
depends = firefly_base
|
||||||
236
mods/firefly_base/init.lua
Normal 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
|
||||||
1
mods/firefly_base/mod.conf
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
name = firefly_base
|
||||||
BIN
mods/firefly_base/textures/firefly_number_0.png
Normal file
|
After Width: | Height: | Size: 118 B |
BIN
mods/firefly_base/textures/firefly_number_1.png
Normal file
|
After Width: | Height: | Size: 121 B |
BIN
mods/firefly_base/textures/firefly_number_2.png
Normal file
|
After Width: | Height: | Size: 131 B |
BIN
mods/firefly_base/textures/firefly_number_3.png
Normal file
|
After Width: | Height: | Size: 129 B |
BIN
mods/firefly_base/textures/firefly_number_4.png
Normal file
|
After Width: | Height: | Size: 126 B |
BIN
mods/firefly_base/textures/firefly_number_5.png
Normal file
|
After Width: | Height: | Size: 130 B |
BIN
mods/firefly_base/textures/firefly_number_6.png
Normal file
|
After Width: | Height: | Size: 125 B |
BIN
mods/firefly_base/textures/firefly_number_7.png
Normal file
|
After Width: | Height: | Size: 125 B |
BIN
mods/firefly_base/textures/firefly_number_8.png
Normal file
|
After Width: | Height: | Size: 125 B |
BIN
mods/firefly_base/textures/firefly_number_9.png
Normal file
|
After Width: | Height: | Size: 126 B |
0
mods/firefly_characters/init.lua
Normal file
2
mods/firefly_characters/mod.conf
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
name = firefly_characters
|
||||||
|
depends = firefly_player
|
||||||
1
mods/firefly_characters/models/firefly_character.gltf
Normal file
1
mods/firefly_characters/models/firefly_head.gltf
Normal 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}]}]}
|
||||||
1
mods/firefly_characters/models/firefly_jetpack.gltf
Normal file
BIN
mods/firefly_characters/textures/firefly_character.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
mods/firefly_characters/textures/firefly_character_2.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
mods/firefly_characters/textures/firefly_jetpack.png
Normal file
|
After Width: | Height: | Size: 524 B |
61
mods/firefly_font/fonts/change_atlas_cell_size.py
Normal 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)
|
||||||
20
mods/firefly_font/fonts/firefly_normal.json
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
mods/firefly_font/fonts/firefly_normal.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
mods/firefly_font/fonts/firefly_normal/firefly_char_65.png
Normal file
|
After Width: | Height: | Size: 121 B |
BIN
mods/firefly_font/fonts/firefly_normal/firefly_char_66.png
Normal file
|
After Width: | Height: | Size: 123 B |
BIN
mods/firefly_font/fonts/firefly_normal/firefly_char_67.png
Normal file
|
After Width: | Height: | Size: 119 B |
BIN
mods/firefly_font/fonts/firefly_normal/firefly_char_68.png
Normal file
|
After Width: | Height: | Size: 118 B |
BIN
mods/firefly_font/fonts/firefly_normal/firefly_char_69.png
Normal file
|
After Width: | Height: | Size: 120 B |
BIN
mods/firefly_font/fonts/firefly_normal/firefly_char_70.png
Normal file
|
After Width: | Height: | Size: 118 B |
BIN
mods/firefly_font/fonts/firefly_normal/firefly_char_71.png
Normal file
|
After Width: | Height: | Size: 123 B |
BIN
mods/firefly_font/fonts/firefly_normal/firefly_char_72.png
Normal file
|
After Width: | Height: | Size: 115 B |
BIN
mods/firefly_font/fonts/firefly_wide.png
Normal file
|
After Width: | Height: | Size: 2 KiB |
BIN
mods/firefly_font/fonts/regular.ttf
Normal file
46
mods/firefly_font/init.lua
Normal 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
|
||||||
2
mods/firefly_font/mod.conf
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
name = firefly_font
|
||||||
|
depends = firefly_base
|
||||||
289
mods/firefly_hud/init.lua
Normal 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
|
||||||
|
}
|
||||||
2
mods/firefly_hud/mod.conf
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
name = firefly_hud
|
||||||
|
depends = firefly_base
|
||||||
132
mods/firefly_hudbars/init.lua
Normal 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
|
||||||
|
|
||||||
2
mods/firefly_hudbars/mod.conf
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
name = firefly_hudbars
|
||||||
|
depends = firefly_hud, firefly_base
|
||||||
BIN
mods/firefly_hudbars/textures/firefly_hud_bar_center.png
Normal file
|
After Width: | Height: | Size: 101 B |
BIN
mods/firefly_hudbars/textures/firefly_hud_bar_center_bg.png
Normal file
|
After Width: | Height: | Size: 99 B |
BIN
mods/firefly_hudbars/textures/firefly_hud_bar_left.png
Normal file
|
After Width: | Height: | Size: 114 B |
BIN
mods/firefly_hudbars/textures/firefly_hud_bar_left_bg.png
Normal file
|
After Width: | Height: | Size: 114 B |
BIN
mods/firefly_hudbars/textures/firefly_hud_bar_right.png
Normal file
|
After Width: | Height: | Size: 114 B |
BIN
mods/firefly_hudbars/textures/firefly_hud_bar_right_bg.png
Normal file
|
After Width: | Height: | Size: 113 B |
432
mods/firefly_player/init.lua
Normal 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)
|
||||||
2
mods/firefly_player/mod.conf
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
name = firefly_player
|
||||||
|
depends = firefly_base
|
||||||
BIN
mods/firefly_player/textures/crosshair.png
Normal file
|
After Width: | Height: | Size: 126 B |
BIN
mods/firefly_player/textures/firefly_ammo_bar.png
Normal file
|
After Width: | Height: | Size: 138 B |
BIN
mods/firefly_player/textures/firefly_container_bg.png
Normal file
|
After Width: | Height: | Size: 494 B |
BIN
mods/firefly_player/textures/firefly_health_bar.png
Normal file
|
After Width: | Height: | Size: 116 B |
BIN
mods/firefly_player/textures/firefly_hotbar_bg.png
Normal file
|
After Width: | Height: | Size: 191 B |
BIN
mods/firefly_player/textures/firefly_hotbar_selected_bg.png
Normal file
|
After Width: | Height: | Size: 175 B |
BIN
mods/firefly_player/textures/firefly_scrollbar_thumb.png
Normal file
|
After Width: | Height: | Size: 191 B |
BIN
mods/firefly_player/textures/firefly_scrollbar_track.png
Normal file
|
After Width: | Height: | Size: 285 B |
BIN
mods/firefly_player/textures/firefly_stats_bg.png
Normal file
|
After Width: | Height: | Size: 472 B |
BIN
mods/firefly_player/textures/firefly_stats_bg_alt.png
Normal file
|
After Width: | Height: | Size: 472 B |
BIN
mods/firefly_player/textures/object_crosshair.png
Normal file
|
After Width: | Height: | Size: 147 B |
163
mods/firefly_state/firefly_battle_mode/beacons.lua
Normal 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
|
||||||
168
mods/firefly_state/firefly_battle_mode/init.lua
Normal 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"
|
||||||
|
})
|
||||||
2
mods/firefly_state/firefly_battle_mode/mod.conf
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
name = firefly_battle_mode
|
||||||
|
depends = firefly_lobby
|
||||||
|
After Width: | Height: | Size: 912 KiB |
404
mods/firefly_state/firefly_lobby/game_maker.lua
Normal 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
|
||||||
|
|
||||||
|
|
||||||
20
mods/firefly_state/firefly_lobby/init.lua
Normal 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")
|
||||||
73
mods/firefly_state/firefly_lobby/mapgen.lua
Normal 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)
|
||||||
2
mods/firefly_state/firefly_lobby/mod.conf
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
name = firefly_lobby
|
||||||
|
depends = firefly_state
|
||||||
|
|
@ -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}]}]}
|
||||||
|
|
@ -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}]}]}
|
||||||
BIN
mods/firefly_state/firefly_lobby/textures/firefly_choose_map.png
Normal file
|
After Width: | Height: | Size: 279 B |
|
After Width: | Height: | Size: 278 B |
|
After Width: | Height: | Size: 304 B |
BIN
mods/firefly_state/firefly_lobby/textures/firefly_screen.png
Normal file
|
After Width: | Height: | Size: 771 B |
75
mods/firefly_state/firefly_state/init.lua
Normal 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)
|
||||||
|
|
||||||
2
mods/firefly_state/firefly_state/mod.conf
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
name = firefly_state
|
||||||
|
depends = firefly_player, firefly_world
|
||||||
0
mods/firefly_state/modpack.conf
Normal file
0
mods/firefly_vehicles/modpack.conf
Normal file
9
mods/firefly_weapons/firefly_saber/init.lua
Normal 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,
|
||||||
|
})
|
||||||
2
mods/firefly_weapons/firefly_saber/mod.conf
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
name = firefly_saber
|
||||||
|
depends = firefly_weapons
|
||||||
137
mods/firefly_weapons/firefly_saber/models/firefly_saber.obj
Normal 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
|
||||||
BIN
mods/firefly_weapons/firefly_saber/textures/firefly_saber.png
Normal file
|
After Width: | Height: | Size: 239 B |
9
mods/firefly_weapons/firefly_streamer/init.lua
Normal 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
|
||||||
|
})
|
||||||
2
mods/firefly_weapons/firefly_streamer/mod.conf
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
name = firefly_streamer
|
||||||
|
depends = firefly_weapons
|
||||||
|
After Width: | Height: | Size: 120 B |
93
mods/firefly_weapons/firefly_weapons/init.lua
Normal 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
|
||||||
2
mods/firefly_weapons/firefly_weapons/mod.conf
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
name = firefly_weapons
|
||||||
|
depends = firefly_player
|
||||||
0
mods/firefly_weapons/modpack.conf
Normal file
298
mods/firefly_world/init.lua
Normal 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
|
||||||
|
})
|
||||||
2
mods/firefly_world/mod.conf
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
name = firefly_world
|
||||||
|
depends = firefly_base
|
||||||
49
mods/firefly_world/models/firefly_steel_grate.obj
Normal 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
|
||||||
BIN
mods/firefly_world/textures/firefly_cactus_side.png
Normal file
|
After Width: | Height: | Size: 234 B |
BIN
mods/firefly_world/textures/firefly_cactus_top.png
Normal file
|
After Width: | Height: | Size: 376 B |
BIN
mods/firefly_world/textures/firefly_colored_glass.png
Normal file
|
After Width: | Height: | Size: 188 B |
BIN
mods/firefly_world/textures/firefly_column.png
Normal file
|
After Width: | Height: | Size: 122 B |
BIN
mods/firefly_world/textures/firefly_concrete.png
Normal file
|
After Width: | Height: | Size: 188 B |
BIN
mods/firefly_world/textures/firefly_dirt.png
Normal file
|
After Width: | Height: | Size: 202 B |