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."
|
||||
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
@ -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 = {
|
||||
|
||||
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)
|
||||
|
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!")
|
||||
|
||||
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
|
||||
|
||||
|
@ -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)
|