enable travis and uh new things™️
12
.travis.yml
Normal 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
BIN
blends/combat.blend
Normal file
BIN
blends/combat_high_tree_model.blend
Normal file
BIN
blends/combat_low_plant.blend
Normal 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."
|
return false, "You are not allowed to control the weather, you scrub. \n \n This incident WILL be reported."
|
||||||
end
|
end
|
||||||
|
|
||||||
atmos.current_weather = 0 + param
|
atmos.current_weather = 0 + param -- somehow it performs tonumber() on it's own?
|
||||||
|
|
||||||
--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)
|
|
||||||
|
|
||||||
return true, "Current weather updated."
|
return true, "Current weather updated."
|
||||||
end,
|
end,
|
||||||
|
140
mods/combat/init.lua
Normal 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
@ -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:
|
123
mods/combat/models/battlefield.x
Normal 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
|
BIN
mods/combat/models/combat_high_tree_model.b3d
Normal file
BIN
mods/combat/models/combat_low_plant.b3d
Normal file
BIN
mods/combat/textures/combat_acacia.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
mods/combat/textures/combat_birch.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
mods/combat/textures/combat_cherry.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
mods/combat/textures/combat_oak.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
mods/combat/textures/combat_pine.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
@ -98,12 +98,11 @@ minetest.register_on_newplayer(give_initial_stuff.give)
|
|||||||
local mob = {
|
local mob = {
|
||||||
|
|
||||||
visual = "mesh",
|
visual = "mesh",
|
||||||
mesh = "entity.x",
|
mesh = "lmao.b3d",
|
||||||
|
use_texture_alpha = true,
|
||||||
textures = {
|
textures = {
|
||||||
|
|
||||||
},
|
},
|
||||||
visual_size = {x=1, y=1},
|
visual_size = {x=10, y=10},
|
||||||
anim_type = 1,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
local mob_anim = {}
|
local mob_anim = {}
|
||||||
@ -129,7 +128,7 @@ function mob:on_rightclick(clicker)
|
|||||||
|
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
minetest.register_entity("core:tester", mob)
|
minetest.register_entity("core:tester", mob)
|
||||||
|
BIN
mods/core/textures/core_darken.png
Normal file
After Width: | Height: | Size: 157 B |
BIN
mods/core/textures/core_darken_circle.png
Normal file
After Width: | Height: | Size: 189 B |
@ -1108,7 +1108,7 @@ function wardrobe.load_user_data(player)
|
|||||||
|
|
||||||
print ("[Wardrobe] " .. pname .. " has a 64x32 type skin!")
|
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
|
wardrobe.player_skin_size[pname] = 64
|
||||||
|
|
||||||
|
@ -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/>
|
|
@ -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
|
|
@ -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"
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
core
|
|
@ -1 +0,0 @@
|
|||||||
This mod provides a "Wiki" block. You can create and edit wiki pages with it.
|
|
@ -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)
|
|
@ -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,
|
|
||||||
----------------------------------------------------------------
|
|
||||||
----------------------------------------------------------------
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
name = wiki
|
|
@ -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()
|
|
@ -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
|
|
Before Width: | Height: | Size: 59 KiB |
@ -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
|
|
Before Width: | Height: | Size: 532 B |
@ -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)
|
|