enable travis and uh new things™️

master
Jordach 2018-09-12 22:15:04 +01:00
parent c4f2b3b53d
commit f5ab3e7e7e
37 changed files with 320 additions and 730 deletions

12
.travis.yml Normal file
View File

@ -0,0 +1,12 @@
language: generic
sudo: false
addons:
apt:
packages:
- luarocks
before_install:
- luarocks install --local luacheck
script:
- $HOME/.luarocks/bin/luacheck --no-color mods/
notifications:
email: true

BIN
blends/CharacterCubic.blend Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
blends/combat.blend Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -12,15 +12,7 @@ minetest.register_chatcommand("weather", {
return false, "You are not allowed to control the weather, you scrub. \n \n This incident WILL be reported."
end
atmos.current_weather = 0 + param
--local player = minetest.get_player_by_name(name)
--player:set_sky("#000000", "skybox", {"core_glass.png", "core_glass.png", "core_glass.png", "core_glass.png", "core_glass.png", "core_glass.png"}, false, true)
--player:override_day_night_ratio(0)
--atmos.set_skybox(player)
atmos.current_weather = 0 + param -- somehow it performs tonumber() on it's own?
return true, "Current weather updated."
end,

140
mods/combat/init.lua Normal file
View File

@ -0,0 +1,140 @@
local battlefields = {}
local active_battlefields = {}
local function create_battlefield(name, top, side, bottom)
battlefields[name] = {
visual = "mesh",
mesh = "battlefield.x",
textures = {
top .. "^core_darken_circle.png",
side .. "^core_darken.png^core_darken_circle.png",
bottom .. "^core_darken.png^core_darken.png^core_darken_circle.png"
},
visual_size = {x=10, y=10},
physical = true,
collisionbox = {-7.5, -0.5, -8.5, 8.5, 0.5, 7.5},
selectionbox = {-7.5, -0.5, -8.5, 8.5, 0.5, 7.5},
}
minetest.register_entity("combat:battlefield_" .. name, battlefields[name])
end
local high_tree = {
visual = "mesh",
mesh = "combat_high_tree_model.b3d",
visual_size = {x=10, y=10},
use_texture_alpha = true,
}
minetest.register_entity("combat:tree_cover", high_tree)
local low_plant = {
visual = "mesh",
mesh = "combat_low_plant.b3d",
backface_culling = false,
visual_size = {x=10, y=10},
}
minetest.register_entity("combat:plant_cover", low_plant)
local function battlefield_generator(battle_id, biome) -- battle_id refers entirely to the name of the person or creature that initiated the round
local natural_low
local natural_high
local low_chance = 0
local high_chance = 0
if biome == "plains" then
natural_low = "core_long_grass_2.png"
low_chance = 7
natural_high = "non_acacia"
high_chance = 30
end
active_battlefields[battle_id] = {}
active_battlefields[battle_id].biome = biome
for x=1, 16 do
active_battlefields[battle_id][x] = {} -- fucks given. 0
for y=1, 16 do
active_battlefields[battle_id][x][y] = {}
active_battlefields[battle_id][x][y].model = "air"
active_battlefields[battle_id][x][y].texture = "air"
if math.random(1, low_chance) == 2 then
active_battlefields[battle_id][x][y].model = "combat:plant_cover"
active_battlefields[battle_id][x][y].texture = natural_low
end
if math.random(1, high_chance) == 2 then
active_battlefields[battle_id][x][y].model = "combat:tree_cover"
if natural_high == "non_acacia" then
local randr = math.random(1, 3)
if randr == 1 then
active_battlefields[battle_id][x][y].texture = "combat_oak.png"
elseif randr == 2 then
active_battlefields[battle_id][x][y].texture = "combat_birch.png"
else
active_battlefields[battle_id][x][y].texture = "combat_cherry.png"
end
end
end
end
end
end
local function destroy_battlefield(pos)
end
local function render_battlefield(battle_id, pos)
-- todo, destroy old map here when done or re-rendering instead of abusing /clearobjects
-- we want nice round numbers not shitty floating points
local px = math.floor(pos.x)
local py = math.floor(pos.y)
local pz = math.floor(pos.z)
minetest.add_entity({x=px, y=py, z=pz}, "combat:battlefield_" .. active_battlefields[battle_id].biome)
for x=1, 16 do -- offset entity positions by uh -8 on x, and y * -1
for y=1, 16 do
if active_battlefields[battle_id][x][y].model ~= "air" then
minetest.add_entity({x=(px - 8) + x, y=py, z=(pz - 9) + y}, active_battlefields[battle_id][x][y].model)
local texel = minetest.get_objects_inside_radius({x=(px - 8) + x, y=py, z=(pz - 9) + y}, 0.05)
texel[1]:set_properties({
textures = {
active_battlefields[battle_id][x][y].texture
}
})
texel[1]:set_yaw((90*(math.pi/180))*math.random(1,4))
end
end
end
end
create_battlefield("plains", "core_grass.png", "core_dirt.png^core_grass_side.png", "core_dirt.png")
minetest.register_chatcommand("test_battle", {
description = "generates a test battlefield",
param = "lol k",
func = function(name, param)
battlefield_generator(name .. "_testing", "plains")
local player = minetest.get_player_by_name(name)
local pos = player:get_pos()
render_battlefield(name .. "_testing", pos)
return true, "Battlefield generated."
end,
})

39
mods/combat/logic.txt Normal file
View File

@ -0,0 +1,39 @@
I'm writing this so I can get things logically sorted when working through this monster of a component:
Initiate Battlefield with objects low and high.
Dispatch entities to render on the battlefield.
Invite players that are partied with the user.
Wait until party invites expire (30 sec or 2 minutes)
Grab player skin data (and render this to the models)
Make an API for wardrobe to return this information?
Hide any player nametags.
Randomly choose attacking order except for the first person to start it.
Battle loop:
Build the new HUD elements that are restricted to combat only.
Check for player inputs here, do not move the player.
Allow the player to use two camera modes, free mode, and over the shoulder.
Display options that can be used.
Check for unlocked skills and hide locked ones. (They can view it in their codex later.)
If choosing to attack a target, a HUD element shows the player to attack. AoE attacks uses an entity renderer.
The AoE and freeform targeter will point at the square, and have your players head visible over the top of it.
Users in stealth are NOT shown on the HUD.
If melee, an AP cost is shown to move in range of the target.
Wait for all connected players to perform their actions, any disconnected players are considered dead.
Perform skills and player movements in the order defined at init.
Players move first, then perform the skills.
Skills must check for in cover, but AP will still be consumed when moving.
Skills also check for dodge percentages and any active stealth users. AP will also still be consumed when performing these.
Untargeted AoE attacks will hit any users that are actively using stealth and dodging.
Cycle through the turns until nobody is left player wise.
AI entities in PvE will always attack last, even if they initiate the battle.
AIs attacks will always be in a random order, unlike players.
AIs also have to perform the same skill checks as players do.
If an attack hits, damage processing occurs here:
Resistances to light, dark, radiation, fire, ice, biological, electrical, plasma, laser and physical are done here.
Buffs and passives are added onto base resistances last.
Players taking damage will emit a hit noise, and display HP lost over their heads.
Players or AI that are killed will be removed from the battle immediately.
If partied players are the only ones surviving, then end the battle, and grant XP to the survivors and end the battle loop.
Return to battle loop start:

View File

@ -0,0 +1,123 @@
xof 0303txt 0032
Frame Root {
FrameTransformMatrix {
1.000000, 0.000000, 0.000000, 0.000000,
0.000000,-0.000000, 1.000000, 0.000000,
0.000000, 1.000000, 0.000000, 0.000000,
0.000000, 0.000000, 0.000000, 1.000000;;
}
Frame Cube {
FrameTransformMatrix {
1.000000, 0.000000, 0.000000, 0.000000,
0.000000, 1.000000, 0.000000, 0.000000,
0.000000, 0.000000, 1.000000, 0.000000,
0.000000, 0.000000, 0.000000, 1.000000;;
}
Mesh { // Cube mesh
24;
8.500001; 7.500000;-0.500000;,
8.500001;-8.500000;-0.500000;,
-7.500001;-8.499998;-0.500000;,
-7.499997; 7.500003;-0.500000;,
8.500004; 7.499996; 0.500000;,
-7.499999; 7.500001; 0.500000;,
-7.500003;-8.499997; 0.500000;,
8.499995;-8.500005; 0.500000;,
8.500001; 7.500000;-0.500000;,
8.500004; 7.499996; 0.500000;,
8.499995;-8.500005; 0.500000;,
8.500001;-8.500000;-0.500000;,
8.500001;-8.500000;-0.500000;,
8.499995;-8.500005; 0.500000;,
-7.500003;-8.499997; 0.500000;,
-7.500001;-8.499998;-0.500000;,
-7.500001;-8.499998;-0.500000;,
-7.500003;-8.499997; 0.500000;,
-7.499999; 7.500001; 0.500000;,
-7.499997; 7.500003;-0.500000;,
8.500004; 7.499996; 0.500000;,
8.500001; 7.500000;-0.500000;,
-7.499997; 7.500003;-0.500000;,
-7.499999; 7.500001; 0.500000;;
6;
4;3,2,1,0;,
4;7,6,5,4;,
4;11,10,9,8;,
4;15,14,13,12;,
4;19,18,17,16;,
4;23,22,21,20;;
MeshNormals { // Cube normals
6;
0.000000; 0.000000;-1.000000;,
0.000000;-0.000000; 1.000000;,
1.000000;-0.000000; 0.000001;,
-0.000000;-1.000000;-0.000002;,
-1.000000; 0.000000;-0.000002;,
0.000000; 1.000000; 0.000003;;
6;
4;0,0,0,0;,
4;1,1,1,1;,
4;2,2,2,2;,
4;3,3,3,3;,
4;4,4,4,4;,
4;5,5,5,5;;
} // End of Cube normals
MeshTextureCoords { // Cube UV coordinates
24;
-7.500000;-7.500000;,
-7.500000; 8.500000;,
8.500000; 8.500000;,
8.500000;-7.500000;,
8.000000;-8.000000;,
-8.000000;-8.000000;,
-8.000000; 8.000000;,
8.000000; 8.000000;,
8.937500; 1.000000;,
8.937500; 0.000000;,
-7.062500; 0.000000;,
-7.062500; 1.000000;,
9.000000; 1.000000;,
9.000000; 0.000000;,
-7.000000; 0.000000;,
-7.000000; 1.000000;,
9.000000; 1.000000;,
9.000000; 0.000000;,
-7.000000; 0.000000;,
-7.000000; 1.000000;,
-7.062500; 0.000000;,
-7.062500; 1.000000;,
8.937500; 1.000000;,
8.937500; 0.000000;;
} // End of Cube UV coordinates
MeshMaterialList { // Cube material list
3;
6;
2,
0,
1,
1,
1,
1;
Material Top {
0.640000; 0.640000; 0.640000; 1.000000;;
96.078431;
0.500000; 0.500000; 0.500000;;
0.000000; 0.000000; 0.000000;;
}
Material Side {
0.640000; 0.640000; 0.640000; 1.000000;;
96.078431;
0.500000; 0.500000; 0.500000;;
0.000000; 0.000000; 0.000000;;
}
Material Bottom {
0.640000; 0.640000; 0.640000; 1.000000;;
96.078431;
0.500000; 0.500000; 0.500000;;
0.000000; 0.000000; 0.000000;;
}
} // End of Cube material list
} // End of Cube mesh
} // End of Cube
} // End of Root

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -98,12 +98,11 @@ minetest.register_on_newplayer(give_initial_stuff.give)
local mob = {
visual = "mesh",
mesh = "entity.x",
mesh = "lmao.b3d",
use_texture_alpha = true,
textures = {
},
visual_size = {x=1, y=1},
anim_type = 1,
visual_size = {x=10, y=10},
}
local mob_anim = {}
@ -129,7 +128,7 @@ function mob:on_rightclick(clicker)
end
self.object:set_animation(mob_anim[self.anim_type], 30, 0, false)
--self.object:set_animation(mob_anim[self.anim_type], 30, 0, false)
end
minetest.register_entity("core:tester", mob)

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 B

View File

@ -1108,7 +1108,7 @@ function wardrobe.load_user_data(player)
print ("[Wardrobe] " .. pname .. " has a 64x32 type skin!")
elseif w / h == 1 then -- this is a square 64x64 type skin;
else -- this is a square 64x64 type skin;
wardrobe.player_skin_size[pname] = 64

View File

@ -1,25 +0,0 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>

View File

@ -1,27 +0,0 @@
Wiki Mod
========
Another random mod by me.
This mod provides a "Wiki" block. You can create and edit wiki pages with it.
The pages are saved as `<worldpath>/wiki/<pagename>`. All spaces in the page
name are converted to underscores, and all other characters not in
`[A-Za-z0-9-]` are converted to hex notation `%XX`.
The text can contain hyperlinks in the form of `[link text]` to other pages.
Such links are added at the right of the form.
You can craft a "Wiki block" by putting 9 bookshelves in the crafting grid.
Only players with the `wiki` priv can create/edit pages.
## Installing
Install by following the instructions in the [Installing mods][install]
article on the Minetest wiki, then add `wiki` to the `secure.trusted_mods`
setting in `minetest.conf`.
[install]: https://wiki.minetest.net/Installing_mods

View File

@ -1,18 +0,0 @@
{
"name": "wiki",
"description": "Online collaborative documentation browser.",
"keywords": [
"wiki",
"doc",
"documentation",
"browser"
],
"homepage": "https://github.com/kaeza/minetest-wiki.git",
"screenshots": [
"https://dl.dropboxusercontent.com/u/100008207/minetest/mods/Kaeza-minetest-wiki.jpg"
],
"authors": [
"Diego Martínez <lkaezadl3@yahoo.com>"
],
"license": "BSD 2-Clause"
}

View File

@ -1 +0,0 @@
core

View File

@ -1 +0,0 @@
This mod provides a "Wiki" block. You can create and edit wiki pages with it.

View File

@ -1,19 +0,0 @@
local MODPATH = minetest.get_modpath("wiki")
wikilib = { }
local ie = minetest.request_insecure_environment()
assert(ie, "you must allow `wiki` in `secure.trusted_mods`")
local private = { }
private.open = ie.io.open
private.mkdir = ie.core.mkdir
loadfile(MODPATH.."/strfile.lua")(private)
loadfile(MODPATH.."/wikilib.lua")(private)
loadfile(MODPATH.."/internal.lua")(private)
loadfile(MODPATH.."/plugins.lua")(private)
loadfile(MODPATH.."/plugin_forum.lua")(private)

View File

@ -1,164 +0,0 @@
wikilib.internal_pages = {
----------------------------------------------------------------
----------------------------------------------------------------
[".Intro"] = [[
Thank you for using the Wiki Mod.
This is a mod that allows one to edit pages via a block. You
can use it to document interesting places in a server, to provide
a place to post griefing reports, or any kind of text you want.
To create a new page, enter the name in the field at the top of the
form, then click "Go". If the page already exists, it's contents will
be displayed. Edit the page as you see fit, then click on "Save" to
write the changes to disk.
Please note that page names starting with a dot ('.') are reserved
for internal topics such as this one. Users cannot edit/create such
pages from the mod interface.
See also:
* [.Tags]
* [.License]
* [.Help Index]
]],
----------------------------------------------------------------
----------------------------------------------------------------
[".Tags"] = [[
The wiki supports some special tags.
You can place hyperlinks to other pages in the Wiki, by surrounding
text in square brackets (for example, [.Intro]). Such links will
appear at the bottom of the form.
See also:
* [.Intro]
]],
----------------------------------------------------------------
----------------------------------------------------------------
[".License"] = [[
Copyright (c) 2013, Diego Martínez
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
* Go to [.Intro].
]],
----------------------------------------------------------------
----------------------------------------------------------------
[".NotFound_Internal"] = [[
The specified internal page cannot be found. You may want to:
* Back to [Main].
* Go to [.Intro].
]],
----------------------------------------------------------------
----------------------------------------------------------------
[".NotFound"] = [[
This page does not exist yet.
* Back to [Main].
* Go to [.Help Index].
]],
----------------------------------------------------------------
----------------------------------------------------------------
[".BadPageName"] = [[
The page name you entered is wrong. See [.Page Names] for more info.
* Back to [Main].
* Go to [.Help Index].
]],
----------------------------------------------------------------
----------------------------------------------------------------
[".Forbidden"] = [[
You have not enough privileges to view this page.
* Back to [Main].
* Go to [.Help Index].
]],
----------------------------------------------------------------
----------------------------------------------------------------
[".Help Index"] = [[
* [.Intro]
* [.Plugins]
* [.Page Names]
* [.User Pages]
* Back to [Main].
]],
----------------------------------------------------------------
----------------------------------------------------------------
[".Page Names"] = [[
Page names must be in any of the following formats:
<pagename>
Display global page <pagename>.
:<n>
Display page <n> from your user space. <n> must be a number between
0 and 9. See [.User Pages] for more info.
:
This is equivalent to ":0" (shows your private page).
:<user>:<n>
Display page "Page Name" from the specified user's space. Note that page
number 0 is never accessible this way, even if you specify yourself as
<user>.
* Back to [.Help Index].
* Back to [Main].
]],
----------------------------------------------------------------
----------------------------------------------------------------
[".User Pages"] = [[
Users can have up to 10 pages in their "user space", numbered 0-9. These pages
are accessed through the special page names ":<n>", and ":<user>:<n>". Page 0
is your private page. This page is not accessible to anyone but you. You can
use it to write down secret locations, etc.
* Back to [.Help Index].
* Back to [Main].
]],
----------------------------------------------------------------
----------------------------------------------------------------
[".My Pages"] = [[
* Profile: [:profile]
* Private page: [:0]
* Pages: [:1] [:2] [:3] [:4] [:5] [:6] [:7] [:8] [:9]
]],
----------------------------------------------------------------
----------------------------------------------------------------
[".Plugins"] = function()
local page = "Installed Plugins:\n\n"
for _,plugin in ipairs(wikilib.registered_plugins) do
page = page.." * "..plugin.description.."\n"
end
page = (page
.. "\n"
.. " * Back to [.Help Index].\n"
.. " * Back to [Main].\n"
)
return page
end,
----------------------------------------------------------------
----------------------------------------------------------------
}

View File

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

View File

@ -1,147 +0,0 @@
local private = ...
local BASEPATH = wikilib.paths.plugins.."/ml"
private.mkdir(BASEPATH)
local ML_DB_FILE = BASEPATH.."/posts.dat"
local posts = { }
local function load_posts()
local f = private.open(ML_DB_FILE, "r")
if not f then return false end
local list = { }
local post = { text="" }
for line in f:lines() do
if line:len() == 0 then
if post.who and post.date then
table.insert(list, post)
post = { text="" }
end
elseif line:sub(1, 5) == "From:" then
post.who = line:sub(6):trim()
elseif line:sub(1, 5) == "Date:" then
post.date = line:sub(6):trim()
else
post.text = post.text..line.."\n"
end
end
if post.who and post.date then
table.insert(list, post)
post = { text="" }
end
f:close()
posts = list
return true
end
local function save_posts()
local f = private.open(ML_DB_FILE, "w")
if not f then return false end
for _, post in ipairs(posts) do
f:write("From: "..post.who.."\n")
f:write("Date: "..post.date.."\n")
for _, line in ipairs(post.text:split("\n")) do
if line:len() == 0 then
f:write(" \n")
elseif (line:sub(1, 5) == "From:")
or (line:sub(1, 5) == "Date:") then
f:write(" "..line.."\n")
else
f:write(line.."\n")
end
end
f:write("\n")
end
f:close()
return true
end
local player_states = { }
local BACKLOG = 5
local function get_player_state(name)
if not player_states[name] then
player_states[name] = { }
end
return player_states[name]
end
local SEP = ("-"):rep(64)
wikilib.register_plugin({
regex = "^/ml/.*",
description = "Mailing List [/ml/recent]",
load_page = function(entry, player) --> text, allow_save
local state = get_player_state(player)
local what = entry:match("^/ml/(.*)")
if not what then
what = "recent"
end
what = what:lower()
if what == "recent" then
local text = "Recent Posts:\n\n"..SEP.."\n"
for i = #posts - BACKLOG, #posts do
local p = posts[i]
if p then
local nl = ((p.text:sub(-1) == "\n") and "" or "\n")
text = (text
.. "[/ml/"..i.."] \n"
.. "From: "..p.who.."\n"
.. "Date: "..p.date.."\n"
.. p.text..nl
.. SEP.."\n"
)
end
end
text = text.."\n * [/ml/Post] a new message"
text = text.."\n * Back to [Main]"
return text, false
elseif what:match("[0-9]+") then
local n = tonumber(what)
local text
if posts[n] then
local nl = ((posts[n].text:sub(-1) == "\n") and "" or "\n")
text = ("Post #"..n.."\n"
.. "From: "..posts[n].who.." [:"..posts[n].who..":profile]\n"
.. "Date: "..posts[n].date.."\n"
.. posts[n].text..nl
.. "\n"
)
else
text = "No such post.\n\n"
end
text = text.."\n * [/ml/Post] a new message"
text = text.."\n * View [/ml/Recent] messages"
text = text.."\n * Back to [Main]"
return text, false
elseif what == "post" then
return "Subject:\n\n<Edit this message and save to post>", true
end
return "Wrong request.", false
end,
save_page = function(entry, player, text) --> bool
local state = get_player_state(player)
local what = entry:match("^/ml/(.*)")
if not what then
what = "post"
end
what = what:lower()
if what == "post" then
posts[#posts + 1] = {
who = player,
date = os.date("%Y-%m-%d %H:%M:%S"),
text = text,
}
save_posts()
return "/ml/recent"
end
return true
end,
})
load_posts()

View File

@ -1,36 +0,0 @@
--[[
plugindef = {
regex = "^/foo/bar/.*",
description = "My Awesome Plugin",
^ Can contain links
load_page = func(entry, player),
^ Must return text, allow_save
save_page = func(entry, player),
^ Must return bool
}
]]
local plugin_defs = { }
function wikilib.register_plugin(def)
plugin_defs[#plugin_defs + 1] = def
end
local function do_handle(what, entry, player, text)
for _,pi in ipairs(plugin_defs) do
if entry:match(pi.regex) then
return pi[what](entry, player, text)
end
end
end
function wikilib.plugin_handle_load(entry, player)
return do_handle("load_page", entry, player)
end
function wikilib.plugin_handle_save(entry, player, text)
return do_handle("save_page", entry, player, text)
end
wikilib.registered_plugins = plugin_defs

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

View File

@ -1,28 +0,0 @@
strfile = { }
function strfile.open(s)
return {
_buf = s,
_pos = 1,
_readline = function(self)
if self._pos == nil then
return nil
end
local nl = self._buf:find("\n", self._pos, true)
local line
if nl then
line = self._buf:sub(self._pos, nl - 1)
nl = nl + 1
else
line = self._buf:sub(self._pos)
end
self._pos = nl
return line
end,
lines = function(self)
return self._readline, self, true
end,
close = function(self) end,
}
end

Binary file not shown.

Before

Width:  |  Height:  |  Size: 532 B

View File

@ -1,248 +0,0 @@
local private = ...
local WP = minetest.get_worldpath().."/wiki"
wikilib.paths = { }
wikilib.paths.root = WP
wikilib.paths.pages = WP.."/pages"
wikilib.paths.plugins = WP.."/plugins"
wikilib.paths.users = WP.."/users"
local WIKI_FORMNAME = "wiki:wiki"
private.mkdir(WP)
private.mkdir(wikilib.paths.pages)
private.mkdir(wikilib.paths.plugins)
private.mkdir(wikilib.paths.users)
local function name_to_filename(name)
name = name:gsub("[^A-Za-z0-9-]", function(c)
if c == " " then
return "_"
else
return ("%%%02X"):format(c:byte(1))
end
end)
return name:lower()
end
wikilib.name_to_filename = name_to_filename
local function get_page_path(name, player) --> path, is_file, allow_save
local allow_save = minetest.check_player_privs(player, {wiki=true})
if name:sub(1, 1) == "." then
local text = wikilib.internal_pages[name] or wikilib.internal_pages[".NotFound_Internal"]
if type(text) == "function" then
text = text(player)
end
return text, false, false
elseif name:sub(1, 1) == ":" then
if name:match("^:[0-9]?$") then
local n = tonumber(name:sub(2,2)) or 0
path = "users/"..player.."/page"..n
private.mkdir(wikilib.paths.users.."/"..player)
elseif name == ":profile" then
path = "users/"..player.."/profile"
private.mkdir(wikilib.paths.users.."/"..player)
elseif name:match("^:.-:[0-9]$") then
local user, n = name:match("^:(.-):([0-9])$")
if user:find("..[/\\]") then
return wikilib.internal_pages[".BadPageName"], false, false
end
if (n == "0") and (not minetest.check_player_privs(player, {wiki_admin=true})) then
return wikilib.internal_pages[".Forbidden"], false, false
end
path = "users/"..user.."/page"..n
private.mkdir(WP.."/users/"..user)
allow_save = false
elseif name:match("^:.-:profile$") then
local user = name:match("^:(.-):.*$")
if user:find("..[/\\]") then
return wikilib.internal_pages[".BadPageName"], false, false
end
path = "users/"..user.."/profile"
private.mkdir(WP.."/users/"..user)
allow_save = false
else
return wikilib.internal_pages[".BadPageName"], false, false
end
else
path = "pages/"..name_to_filename(name)
end
return WP.."/"..path, true, allow_save
end
local function find_links(lines) --> links
local links = { }
local links_n = 0
for _,line in ipairs(lines) do
for link in line:gmatch("%[(.-)%]") do
links_n = links_n + 1
links[links_n] = link
end
end
return links
end
local function load_page(name, player) --> text, links, allow_save
local text, allow_save = wikilib.plugin_handle_load(name, player)
if text then
return text, find_links(text:split("\n")), allow_save
end
local path, is_file, allow_save = get_page_path(name, player)
local f
if is_file then
f = private.open(path)
if not f then
f = strfile.open(wikilib.internal_pages[".NotFound"])
end
else
f = strfile.open(path)
end
local lines = { }
local lines_n = 0
for line in f:lines() do
lines_n = lines_n + 1
lines[lines_n] = line
end
f:close()
local text = table.concat(lines, "\n")
local links = find_links(lines)
return text, links, allow_save
end
local function save_page(name, player, text)
local ok = wikilib.plugin_handle_save(name, player, text)
if ok then return ok end
local path, is_file, allow_save = get_page_path(name, player)
if (not is_file) or (not allow_save) then return end
local f = private.open(path, "w")
if not f then return end
f:write(text)
f:close()
end
local esc = minetest.formspec_escape
function wikilib.get_wiki_page_formspec(player, name)
if name == "" then name = "Main" end
local text, links, allow_save = load_page(name, player)
local buttons, nbuttons = { }, 0
local bx, by = 12, 1.1
for i, link in ipairs(links) do
if i%15 == 0 then
bx = bx + 2
by = 1.1
end
link = esc(link)
nbuttons = nbuttons + 1
buttons[nbuttons] = (("button[%f,%f;2.1,0.5;page_%s;%s]")
:format(bx, by, link, link))
by = by + 0.65
end
buttons = table.concat(buttons)
local toolbar = (allow_save
and "button[-.1,9.2;2.4,1;save;Save]"
or "label[0,9;You are not authorized to edit this page.]")
return ("size[16,10]"
.. "label[-0.1,0;Page]"
.. "field[1.5,0.1;13,1;page;;"..esc(name).."]"
.. "button[14,0;1,0.5;go;Go]"
.. "button_exit[15,0;1,0.5;close;X]"
.. "textarea[0.2,1.1;12,9;text;"..esc(name)..";"..esc(text).."]"
.. buttons
.. toolbar
)
end
function wikilib.show_wiki_page(player, name)
local fs = wikilib.get_wiki_page_formspec(player, name)
minetest.show_formspec(player, WIKI_FORMNAME, fs)
end
minetest.register_node("wiki:wiki", {
description = "Wiki",
tiles = {
"core_mese_old.png"
},
groups = { choppy=3, oddly_breakable_by_hand=2, flammable=3 },
sounds = mcore.sound_wood,
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("infotext", "Wiki")
end,
on_rightclick = function(pos, node, clicker, itemstack)
if clicker then
wikilib.show_wiki_page(clicker:get_player_name(), "Main")
end
end,
})
minetest.register_privilege("wiki", {
description = "Allow editing wiki pages in the global space",
give_to_singleplayer = false,
})
minetest.register_privilege("wiki_admin", {
description = "Allow editing wiki pages in any space",
give_to_singleplayer = false,
})
local BS = "default:bookshelf"
local BSL = { BS, BS, BS }
minetest.register_craft({
output = "wiki:wiki",
recipe = { BSL, BSL, BSL },
})
function wikilib.handle_formspec(player, formname, fields)
if (not formname) or (formname ~= WIKI_FORMNAME) then return end
if fields.quit or fields.close then return end
local plname = player:get_player_name()
if fields.save then
local r = save_page(fields.page, plname, fields.text)
if type(r) == "string" then
wikilib.show_wiki_page(plname, r)
else
wikilib.show_wiki_page(plname, fields.page)
end
return true
elseif fields.go then
wikilib.show_wiki_page(plname, fields.page)
return true
else
for k in pairs(fields) do
if type(k) == "string" then
local name = k:match("^page_(.*)")
if name then
wikilib.show_wiki_page(plname, name)
return true
end
end
end
end
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
wikilib.handle_formspec(player, formname, fields)
end)