init
This commit is contained in:
parent
db4ee49cae
commit
3ece6a545a
7
CHANGELOG.md
Normal file
7
CHANGELOG.md
Normal file
@ -0,0 +1,7 @@
|
||||
This mod is a fork of [Sokomine's apartment mod][upstream] from the commit [`86b9888`](https://github.com/Sokomine/apartment/commit/86b9888c703fd2711dd86f75102753024ebfac2b). This fork redone the formspec of apartment controller and added configuration copiers. Apart from that, this fork removed the apartment spawner, which was seldomly used and gliched.
|
||||
|
||||
## Changelog
|
||||
* _Refer to [the upstream][upstream] for changelog before the fork._
|
||||
* 2023/04/05: Removed apartment spawner, redone formspec, added configuration copier.
|
||||
|
||||
[upstream]: https://github.com/Sokomine/apartment/
|
15
COPYING.txt
Normal file
15
COPYING.txt
Normal file
@ -0,0 +1,15 @@
|
||||
Copyright (C) 2014 Sokomine
|
||||
Copyright (C) 2023 1F616EMO
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
@ -1 +1,8 @@
|
||||
# apartment
|
||||
This mod is a fork of [Sokomine's apartment mod][upstream] from the commit [`86b9888`](https://github.com/Sokomine/apartment/commit/86b9888c703fd2711dd86f75102753024ebfac2b). This fork redone the formspec of apartment controller and added configuration copiers. Apart from that, this fork removed the apartment spawner, which was seldom used and glitched.
|
||||
|
||||
## Features
|
||||
This mod provides a "Apartment Configuration Panel", which allows apartment owners to set up a self-service rental system. Upon renting by another player, all the locked blocks inside the apartment will become the player's.
|
||||
|
||||
This mod also provides an "Apartment Configuration Copier", for copying apartment configurations (i.e. category, description, size) to another not configured panel. To copy, punch a configured panel with the copier; to paste, right-click a not configured panel. When being pasted, the description will be altered if the original description ends with a number.
|
||||
|
||||
|
||||
|
173
chg_owner.lua
Normal file
173
chg_owner.lua
Normal file
@ -0,0 +1,173 @@
|
||||
local S_default = minetest.get_translator("default")
|
||||
local S_doors = minetest.get_translator("doors")
|
||||
local S_currency = minetest.get_translator("currency")
|
||||
local S = minetest.get_translator("apartment")
|
||||
|
||||
local function sstarts(String,Start) -- http://stackoverflow.com/questions/22831701/ddg#22831842
|
||||
return string.sub(String,1,string.len(Start))==Start
|
||||
end
|
||||
|
||||
apartment.chg_owner = function(panel_pos,pos,category,descr,original_owner,now_owner,owner,actor)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local n = minetest.get_node(pos)
|
||||
if not meta then return false, "META_NF" end
|
||||
local node_now_owner = meta:get_string("owner")
|
||||
if node_now_owner == "" then
|
||||
node_now_owner = meta:get_string("doors_owner")
|
||||
end; if node_now_owner == "" then
|
||||
node_now_owner = original_owner
|
||||
end
|
||||
if node_now_owner == original_owner or node_now_owner == now_owner then
|
||||
local owner_or_orig = (owner ~= "" and owner) or original_owner
|
||||
if n.name == "locks:shared_locked_chest" then
|
||||
locks:lock_set_owner( pos, owner_or_orig, "Shared locked chest" )
|
||||
elseif n.name == "locks:shared_locked_furnace" then
|
||||
locks:lock_set_owner( pos, owner_or_orig, "Shared locked furnace" )
|
||||
elseif n.name == "locks:shared_locked_sign_wall" then
|
||||
locks:lock_set_owner( pos, owner_or_orig, "Shared locked sign" )
|
||||
elseif sstarts(n.name,"locks:door") then
|
||||
locks:lock_set_owner( pos, owner_or_orig, "Shared locked door" )
|
||||
elseif n.name == "vendor:vendor" or n.name == "vendor:depositor" then
|
||||
meta:set_string("owner", owner_or_orig)
|
||||
vendor.refresh(pos, nil)
|
||||
elseif n.name == "travelnet:travelnet" or n.name == "travelnet:elevator"
|
||||
or n.name == "locked_travelnet:elevator" or n.name == "locked_travelnet:travelnet" then
|
||||
local oldmetadata = meta:to_table()
|
||||
travelnet.remove_box(pos, nil, oldmetadata, actor )
|
||||
meta:set_string("owner", owner_or_orig)
|
||||
minetest.registered_nodes[ n.name ].after_place_node(pos, actor, nil)
|
||||
elseif n.name == "smartshop:shop" then
|
||||
meta:set_string("owner", owner_or_orig)
|
||||
if meta:get_int("type") == 0 and not (minetest.check_player_privs(owner_or_orig, {creative=true}) or minetest.check_player_privs(owner_or_orig, {give=true})) then
|
||||
-- Avoid non-unlimited player taking unlimited player's smartshop'
|
||||
meta:set_int("creative",0)
|
||||
meta:set_int("type",1)
|
||||
end
|
||||
smartshop.update_info(pos)
|
||||
else -- These does not require special processing
|
||||
local disp_pname = owner or "- vacant -"
|
||||
local disp_descr = descr .. "@" .. category
|
||||
local infotext = ""
|
||||
if n.name == "default:chest_locked" or n.name == "default:chest_locked_open" then
|
||||
if original_owner == owner then
|
||||
infotext = S_default("Locked Chest (owned by @1)",original_owner)
|
||||
else
|
||||
infotext = S("@1 in Ap. @2 (@3)",S_default("Locked Chest"),disp_descr,disp_pname)
|
||||
end
|
||||
elseif sstarts(n.name,"doors:door_steel_") then
|
||||
if original_owner == owner then
|
||||
infotext = S_doors("Steel Door") .. "\n" .. S_doors("Owned by @1",original_owner)
|
||||
else
|
||||
infotext = S("Apartment @1 (@2)",disp_descr,disp_pname)
|
||||
end
|
||||
elseif n.name == "locked_sign:sign_wall_locked" then
|
||||
if original_owner == owner then
|
||||
infotext = "\"\" ("..original_owner..")"
|
||||
else
|
||||
infotext = "\"\" ("..disp_pname..")"
|
||||
end
|
||||
elseif n.name == 'apartment:apartment_free' or n.name == 'apartment:apartment_occupied' then
|
||||
if vector.equals(panel_pos,pos) then
|
||||
if original_owner == owner then
|
||||
infotext = S("Rent apartment @1 here by right-clicking this panel!",disp_descr)
|
||||
else
|
||||
infotext = S("Apartment rental control panel for apartment @1 (@2)",disp_descr,disp_pname)
|
||||
end
|
||||
end
|
||||
elseif n.name == "technic:iron_locked_chest" then
|
||||
if original_owner == owner then
|
||||
infotext = "Iron Locked Chest (owned by "..original_owner..")"
|
||||
else
|
||||
infotext = "Iron Locked Chest in Ap. "..descr.." ("..disp_pname..")"
|
||||
end
|
||||
elseif n.name == "technic:copper_locked_chest" then
|
||||
if original_owner == owner then
|
||||
infotext = "Copper Locked Chest (owned by "..original_owner..")"
|
||||
else
|
||||
infotext = "Copper Locked Chest in Ap. "..descr.." ("..disp_pname..")"
|
||||
end
|
||||
elseif n.name == "technic:silver_locked_chest" then
|
||||
if original_owner == owner then
|
||||
infotext = "Silver Locked Chest (owned by "..original_owner..")"
|
||||
else
|
||||
infotext = "Silver Locked Chest in Ap. "..descr.." ("..disp_pname..")"
|
||||
end
|
||||
elseif n.name == "technic:gold_locked_chest" then
|
||||
if original_owner == owner then
|
||||
infotext = "Gold Locked Chest (owned by "..original_owner..")"
|
||||
else
|
||||
infotext = "Gold Locked Chest in Ap. "..descr.." ("..disp_pname..")"
|
||||
end
|
||||
elseif n.name == "technic:mithril_locked_chest" then
|
||||
if original_owner == owner then
|
||||
infotext = "Mithril Locked Chest (owned by "..original_owner..")"
|
||||
else
|
||||
infotext = "Mithril Locked Chest in Ap. "..descr.." ("..disp_pname..")"
|
||||
end
|
||||
elseif n.name == "inbox:empty" then
|
||||
if original_owner == owner then
|
||||
infotext = original_owner.."'s Mailbox";
|
||||
else
|
||||
infotext = disp_pname.."'s Mailbox";
|
||||
end
|
||||
elseif n.name == "itemframes:frame" then
|
||||
if original_owner == owner then
|
||||
infotext = "Item frame (owned by"..original_owner..")"
|
||||
else
|
||||
infotext = "Item frame in Ap. "..descr.." ("..disp_pname..")"
|
||||
end
|
||||
elseif n.name == "itemframes:pedestral" then
|
||||
if original_owner == owner then
|
||||
infotext = "Pedestral frame (owned by "..original_owner..")"
|
||||
else
|
||||
infotext = "Pedestral frame in Ap. "..descr.." ("..disp_pname..")"
|
||||
end
|
||||
elseif n.name == "currency:safe" then
|
||||
if original_owner == owner then
|
||||
infotext = S_currency("Safe (owned by @1)",original_owner)
|
||||
else
|
||||
infotext = S("@1 in Ap. @2 (@3)",S_currency("Safe"),disp_descr,disp_pname)
|
||||
end
|
||||
elseif n.name == "currency:shop" then
|
||||
if original_owner == owner then
|
||||
infotext = S_currency("Exchange shop (owned by @1)",original_owner)
|
||||
else
|
||||
infotext = S("@1 in Ap. @2 (@3)",S_currency("Shop"),disp_descr,disp_pname)
|
||||
end
|
||||
elseif n.name == "bitchange:bank" then
|
||||
if original_owner == owner then
|
||||
infotext = "Bank (owned by "..original_owner..")"
|
||||
else
|
||||
infotext = "Bank in Ap. "..descr.." ("..disp_pname..")"
|
||||
end
|
||||
elseif n.name == "bitchange:moneychanger" then
|
||||
if original_owner == owner then
|
||||
infotext = "Moneychanger (owned by "..original_owner..")"
|
||||
else
|
||||
infotext = "Moneychanger in Ap. "..descr.." ("..disp_pname..")"
|
||||
end
|
||||
elseif n.name == "bitchange:warehouse" then
|
||||
if original_owner == owner then
|
||||
infotext = "Warehouse (owned by "..original_owner..")"
|
||||
else
|
||||
infotext = "Warehouse in Ap. "..descr.." ("..disp_pname..")"
|
||||
end
|
||||
elseif n.name == "bitchange:shop" then
|
||||
local pname = disp_pname
|
||||
if original_owner == owner then
|
||||
pname = original_owner
|
||||
end
|
||||
if meta:get_string('title') ~= '' then
|
||||
infotext = "Exchange shop \""..( meta:get_string('title')).."\" ("..pname..")";
|
||||
else
|
||||
infotext = "Exchange shop ("..pname..")";
|
||||
end
|
||||
end
|
||||
if infotext ~= "" then
|
||||
meta:set_string("infotext",infotext)
|
||||
meta:set_string("owner",owner_or_orig)
|
||||
meta:set_string("doors_owner",owner_or_orig)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
333
gui.lua
Normal file
333
gui.lua
Normal file
@ -0,0 +1,333 @@
|
||||
local S = minetest.get_translator("apartment")
|
||||
local gui = flow.widgets
|
||||
local p = {}
|
||||
|
||||
|
||||
p.configure_gui = flow.make_gui(function(player,ctx)
|
||||
local name = player:get_player_name()
|
||||
local pos = ctx.pos
|
||||
-- Error and privilege handling: These are unlikely to be reached, but anyway check them
|
||||
if not apartment.working then return gui.Label { label = "MOD_ERR" } end
|
||||
if not pos then return gui.Label { label = "NO_POS" } end
|
||||
local meta = ctx.meta or minetest.get_meta(pos)
|
||||
if meta:get_string( 'original_owner' ) ~= name then return gui.Label { label = "NOT_OWNER" } end
|
||||
|
||||
local defaults = {}
|
||||
if ctx.defaults then
|
||||
for x,y in pairs(ctx.defaults) do
|
||||
defaults[x] = tostring(y)
|
||||
end
|
||||
ctx.defaults = nil
|
||||
end
|
||||
|
||||
return gui.VBox { w = 10,
|
||||
gui.Label { label = S("Apartment Configuration") },
|
||||
gui.Box {w = 1, h = 0.05, color = "grey"},
|
||||
gui.HBox {
|
||||
gui.Label { label = S("Category"), w = 2 },
|
||||
gui.Field { name = "category", expand = true, default = defaults.category },
|
||||
gui.Tooltip {
|
||||
tooltip_text = S("In one category, every player can only rent one apartment."),
|
||||
gui_element_name = "category",
|
||||
}
|
||||
},
|
||||
gui.HBox {
|
||||
gui.Label { label = S("Name or ID"), w = 2 },
|
||||
gui.Field { name = "descr", expand = true, default = defaults.descr },
|
||||
gui.Tooltip {
|
||||
tooltip_text = S("This is the unique ID of this apartment in this category."),
|
||||
gui_element_name = "descr",
|
||||
}
|
||||
},
|
||||
gui.Box {w = 1, h = 0.05, color = "grey"},
|
||||
gui.Label { label = S("The apartment shall extend this many blocks from this panel:")},
|
||||
gui.HBox {
|
||||
gui.VBox {
|
||||
gui.Field {
|
||||
name = "size_back", label = S("Back"),
|
||||
w = 1, expand = true, align_h = "center",
|
||||
default = defaults.size_back,
|
||||
},
|
||||
gui.HBox {
|
||||
gui.Field {
|
||||
name = "size_left",
|
||||
label = S("Left"),
|
||||
w = 1, expand = true,
|
||||
default = defaults.size_left,
|
||||
},
|
||||
gui.Image {
|
||||
w = 1, h = 1, texture_name = "apartment_controls_vacant.png",
|
||||
expand = true,
|
||||
},
|
||||
gui.Field {
|
||||
name = "size_right",
|
||||
label = S("Right"),
|
||||
w = 1, expand = true,
|
||||
default = defaults.size_right,
|
||||
},
|
||||
},
|
||||
gui.Field {
|
||||
name = "size_front", label = S("Front"),
|
||||
w = 1, expand = true, align_h = "center",
|
||||
default = defaults.size_front
|
||||
},
|
||||
},
|
||||
gui.VBox { w = 4, expand = true, align_h = "right",
|
||||
gui.HBox {
|
||||
gui.Field {
|
||||
name = "size_up",
|
||||
label = S("Up"),
|
||||
expand = true, w = 1,
|
||||
default = defaults.size_up,
|
||||
},
|
||||
gui.Field {
|
||||
name = "size_down",
|
||||
label = S("Down"),
|
||||
expand = true, w = 1,
|
||||
default = defaults.size_down,
|
||||
},
|
||||
},
|
||||
gui.Spacer {},
|
||||
gui.ButtonExit {
|
||||
name = "abort",
|
||||
label = S("Abort"),
|
||||
},
|
||||
gui.ButtonExit {
|
||||
name = "store",
|
||||
label = S("Store and Offer"),
|
||||
on_event = function(player,ctx)
|
||||
local name = player:get_player_name()
|
||||
local pos = ctx.pos
|
||||
-- Error and privilege handling: These are unlikely to be reached, but anyway check them
|
||||
if not apartment.working then return false end
|
||||
if not pos then return false end
|
||||
local meta = ctx.meta or minetest.get_meta(pos)
|
||||
if meta:get_string( 'original_owner' ) ~= name then return gui.Label { label = "NOT_OWNER" } end
|
||||
local fields = ctx.form
|
||||
local size_left = tonumber( fields.size_left or -1) or -1
|
||||
local size_right = tonumber( fields.size_right or -1) or -1
|
||||
local size_up = tonumber( fields.size_up or -1) or -1
|
||||
local size_down = tonumber( fields.size_down or -1) or -1
|
||||
local size_front = tonumber( fields.size_front or -1) or -1
|
||||
local size_back = tonumber( fields.size_back or -1) or -1
|
||||
local category = tostring( fields.category ) or ""
|
||||
local descr = tostring( fields.descr ) or ""
|
||||
|
||||
if size_left < 0 or size_left > 10
|
||||
or size_right < 0 or size_right > 10
|
||||
or size_up < 0 or size_up > 10
|
||||
or size_down < 0 or size_down > 10
|
||||
or size_front < 0 or size_front > 10
|
||||
or size_back < 0 or size_back > 10
|
||||
or not category or not descr then
|
||||
minetest.chat_send_player(name, S('Error: Not all fields have been filled in or the area is too large.'))
|
||||
return
|
||||
end
|
||||
|
||||
if apartment.apartments[category] and apartment.apartments[category][descr] then
|
||||
minetest.chat_send_player(name, S("Error: The apartment @1@@@2 already exists. Please choose a different name or category.", descr, category))
|
||||
return
|
||||
end
|
||||
|
||||
meta:set_int( 'size_up', size_up )
|
||||
meta:set_int( 'size_down', size_down )
|
||||
meta:set_int( 'size_right', size_right )
|
||||
meta:set_int( 'size_left', size_left )
|
||||
meta:set_int( 'size_front', size_front )
|
||||
meta:set_int( 'size_back', size_back )
|
||||
|
||||
meta:set_string( 'descr', fields.descr )
|
||||
meta:set_string( 'category', fields.category )
|
||||
|
||||
local status, msg = apartment.rent( pos, name, nil, player )
|
||||
if status then
|
||||
minetest.chat_send_player(name, S("Apartment @1@@@2 is ready for rental.",descr,category))
|
||||
else
|
||||
minetest.chat_send_player(name, S("Failed to create apartment @1@@@2. (@3)",descr,category,msg))
|
||||
end
|
||||
end
|
||||
},
|
||||
gui.Style {
|
||||
selectors = {"abort"},
|
||||
props = {textcolor = "#FF0000"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
end)
|
||||
|
||||
p.panel_control = flow.make_gui(function(player,ctx)
|
||||
local name = player:get_player_name()
|
||||
local pos = ctx.pos
|
||||
-- Error and privilege handling: These are unlikely to be reached, but anyway check them
|
||||
if not apartment.working then return gui.Label { label = "MOD_ERR" } end
|
||||
if not pos then return gui.Label { label = "NO_POS" } end
|
||||
|
||||
local meta = ctx.meta or minetest.get_meta(pos)
|
||||
|
||||
local original_owner = meta:get_string('original_owner')
|
||||
local owner = meta:get_string('owner')
|
||||
local owner_disp = ((owner == original_owner or owner == "") and "- vacant -" or owner)
|
||||
local descr = meta:get_string('descr')
|
||||
local category = meta:get_string('category')
|
||||
|
||||
local btn = gui.Label { label = S("This apartment \nhave been rented.") }
|
||||
if not(apartment.apartments[category] and apartment.apartments[category][descr]) then
|
||||
btn = gui.Label { label = S("This apartment \nwas glitched.") }
|
||||
elseif name == owner and owner ~= original_owner then
|
||||
btn = gui.Button {
|
||||
label = S("Unrent"),
|
||||
on_event = function(player,ctx)
|
||||
local name = player:get_player_name()
|
||||
local pos = ctx.pos
|
||||
-- Error and privilege handling: These are unlikely to be reached, but anyway check them
|
||||
if not apartment.working then return end
|
||||
if not pos then return end
|
||||
|
||||
local meta = ctx.meta or minetest.get_meta(pos)
|
||||
local original_owner = meta:get_string( 'original_owner' )
|
||||
local descr = meta:get_string('descr')
|
||||
local category = meta:get_string('category')
|
||||
local status, msg = apartment.rent(pos, original_owner, nil, player)
|
||||
if status then
|
||||
minetest.chat_send_player(name,S("You have ended your rent of apartment @1@@@2. It is free for others to rent again.",descr,category))
|
||||
else
|
||||
minetest.chat_send_player(name, 'Something went wrong when giving back the apartment @1@@@2. (@3)',descr,category,msg)
|
||||
end
|
||||
return true
|
||||
end
|
||||
}
|
||||
elseif owner == original_owner then
|
||||
if name == original_owner then
|
||||
btn = gui.Label { label = S("Dig the panel \nto remove this apartment.") }
|
||||
else
|
||||
btn = gui.Button {
|
||||
label = S("Rent"),
|
||||
on_event = function(player,ctx)
|
||||
local name = player:get_player_name()
|
||||
local pos = ctx.pos
|
||||
-- Error and privilege handling: These are unlikely to be reached, but anyway check them
|
||||
if not apartment.working then return end
|
||||
if not pos then return end
|
||||
|
||||
local meta = ctx.meta or minetest.get_meta(pos)
|
||||
local descr = meta:get_string('descr')
|
||||
local category = meta:get_string('category')
|
||||
|
||||
if not(apartment.apartments[category] and apartment.apartments[category][descr]) then
|
||||
minetest.chat_send_player(name,S("This apartment (@1@@@2) is not registered. Please unrent it and ask the original builder to re-configure this panel.",descr,category))
|
||||
return true
|
||||
end
|
||||
|
||||
for k,v in pairs(apartment.apartments[category]) do
|
||||
if v and v.owner == name then
|
||||
minetest.chat_send_player(name,S("Sorry, you can only rent one apartment per category at a time. You have already rented apartment @1@@@2.",descr,category))
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
local status, msg = apartment.rent(pos, name, nil, player)
|
||||
if status then
|
||||
minetest.chat_send_player(name,S("You have rented apartment @1@@@2. Enjoy your stay!",descr,category))
|
||||
else
|
||||
minetest.chat_send_player(name, 'Something went wrong when renting the apartment @1@@@2. (@3)',descr,category,msg)
|
||||
end
|
||||
return true
|
||||
end
|
||||
}
|
||||
end
|
||||
elseif name == original_owner or minetest.check_player_privs(name,{apartment_unrent=true}) then
|
||||
btn = gui.Button {
|
||||
label = S("Force Unrent"),
|
||||
on_event = function(player,ctx)
|
||||
local name = player:get_player_name()
|
||||
local pos = ctx.pos
|
||||
-- Error and privilege handling: These are unlikely to be reached, but anyway check them
|
||||
if not apartment.working then return end
|
||||
if not pos then return end
|
||||
|
||||
local meta = ctx.meta or minetest.get_meta(pos)
|
||||
local original_owner = meta:get_string( 'original_owner' )
|
||||
local descr = meta:get_string('descr')
|
||||
local category = meta:get_string('category')
|
||||
local owner = meta:get_string('owner')
|
||||
|
||||
if not(name == original_owner or minetest.check_player_privs(name,{apartment_unrent=true})) then return end
|
||||
|
||||
local status, msg = apartment.rent(pos, original_owner, nil, player)
|
||||
if status then
|
||||
minetest.chat_send_player(name,S("Player @1 has been thrown out of apartment @2@@@3. It can now be rented by another player.",owner,descr,category))
|
||||
else
|
||||
minetest.chat_send_player(name, 'Something went wrong when throwing @1 out of the apartment @2@@@3. (@4)',owner,descr,category,msg)
|
||||
end
|
||||
return true
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
local size_up = meta:get_int( 'size_up' );
|
||||
local size_down = meta:get_int( 'size_down' );
|
||||
local size_right = meta:get_int( 'size_right' );
|
||||
local size_left = meta:get_int( 'size_left' );
|
||||
local size_front = meta:get_int( 'size_front' );
|
||||
local size_back = meta:get_int( 'size_back' );
|
||||
|
||||
return gui.VBox { w = 10,
|
||||
gui.HBox {
|
||||
gui.Label { label = S("Apartment @1@@@2",descr,category) },
|
||||
gui.ButtonExit {
|
||||
label = "x", w = 0.5, h = 0.5,
|
||||
expand = true, align_h = "right",
|
||||
}
|
||||
},
|
||||
gui.Box {w = 1, h = 0.05, color = "grey"},
|
||||
gui.HBox {
|
||||
gui.Label { label = S("Owner: @1",original_owner), w=1, expand = true },
|
||||
gui.Label { label = S("Now rented by: @1",owner_disp), w = 1, expand = true },
|
||||
},
|
||||
gui.Box {w = 1, h = 0.05, color = "grey"},
|
||||
gui.Label { label = S("The apartment extends this many blocks from this panel:")},
|
||||
gui.HBox {
|
||||
gui.VBox {
|
||||
gui.Label {
|
||||
label = S("Back\n@1",size_back),
|
||||
w = 1, expand = true, align_h = "center"
|
||||
},
|
||||
gui.HBox {
|
||||
gui.Label {
|
||||
label = S("Left\n@1",size_left),
|
||||
w = 1, expand = true,
|
||||
},
|
||||
gui.Image {
|
||||
w = 1, h = 1, texture_name = "apartment_controls_vacant.png",
|
||||
expand = true,
|
||||
},
|
||||
gui.Label {
|
||||
label = S("Right\n@1",size_right),
|
||||
w = 1, expand = true,
|
||||
},
|
||||
},
|
||||
gui.Label {
|
||||
label = S("Front\n@1",size_front),
|
||||
w = 1, expand = true, align_h = "center"
|
||||
},
|
||||
},
|
||||
gui.VBox { w = 4, expand = true, align_h = "right",
|
||||
gui.HBox {
|
||||
gui.Label {
|
||||
label = S("Up\n@1",size_up),
|
||||
expand = true, w = 1,
|
||||
},
|
||||
gui.Label {
|
||||
label = S("Down\n@1",size_down),
|
||||
expand = true, w = 1,
|
||||
},
|
||||
},
|
||||
gui.Spacer {},
|
||||
btn,
|
||||
}
|
||||
}
|
||||
}
|
||||
end)
|
||||
|
||||
return p
|
491
init.lua
Normal file
491
init.lua
Normal file
@ -0,0 +1,491 @@
|
||||
local S = minetest.get_translator("apartment")
|
||||
apartment = {}
|
||||
apartment.enable_aphome_command = minetest.settings:get_bool("apartment.enable_aphome_command",true)
|
||||
|
||||
minetest.register_privilege("apartment_unrent", {
|
||||
description = S("Allows player to throw other players out from apartments not owned by them."),
|
||||
give_to_singleplayer = false
|
||||
})
|
||||
|
||||
-- v2 will contain information about all apartments of the server in the form:
|
||||
-- { cat = { ap_descr = { pos = {x=0,y=0,z=0}, original_owner='', owner='' } } }
|
||||
apartment.apartments = {}
|
||||
apartment.working = true
|
||||
apartment.data_modified = false
|
||||
local WP = minetest.get_worldpath()
|
||||
local MP = minetest.get_modpath("apartment")
|
||||
apartment.save_path_v1 = WP .. "/apartment.data"
|
||||
apartment.save_path = WP .. "/apartment_v2.data"
|
||||
apartment.save_path_bak = WP .. "/apartment_v2.data.bak"
|
||||
apartment.gui = dofile(MP .. "/gui.lua")
|
||||
|
||||
apartment.save_data = function()
|
||||
minetest.log("action","[Apartment] Saving data")
|
||||
for k,v in pairs(apartment.apartments) do
|
||||
if next(v) == nil then
|
||||
minetest.log("action","[Apartment] Category " .. k .. " is empty, removed.")
|
||||
apartment.apartments[k] = nil
|
||||
end
|
||||
end
|
||||
local data = minetest.serialize(apartment.apartments)
|
||||
if minetest.safe_file_write(apartment.save_path, data) then
|
||||
return true
|
||||
else
|
||||
minetest.log("error","[Apartment] Failed to write save file: " .. apartment.save_path)
|
||||
end
|
||||
end
|
||||
|
||||
local function save_loop()
|
||||
if apartment.data_modified then
|
||||
apartment.data_modified = false
|
||||
apartment.save_data()
|
||||
end
|
||||
minetest.after(1,save_loop)
|
||||
end
|
||||
minetest.after(1,save_loop)
|
||||
minetest.register_on_shutdown(apartment.save_data)
|
||||
|
||||
apartment.migrate_v1 = function()
|
||||
minetest.log("action","[Apartment] Finding old files...")
|
||||
local file_v1 = io.open(apartment.save_path_v1, "r")
|
||||
if not file_v1 then
|
||||
minetest.log("error","[Apartment] v1 save file not found.")
|
||||
return false
|
||||
end
|
||||
local s_data_v1 = file_v1:read("*all")
|
||||
if s_data_v1 == "" then
|
||||
minetest.log("error","[Apartment] v1 save file was empty.")
|
||||
file_v1:close()
|
||||
return false
|
||||
end
|
||||
local data_v1 = minetest.deserialize(s_data_v1)
|
||||
if data_v1 == nil then -- Known bug of advtrains: when file grows, it may fail to load.
|
||||
apartment.working = false -- Even if pcall()ed, the mod will still refuse to do any operations.
|
||||
error("[Apartment] Failed to deserialize v1 data. Please solve this problem manually.")
|
||||
return false
|
||||
end
|
||||
local data_v2 = {}
|
||||
for k,v in pairs(data_v1) do
|
||||
if v.category then
|
||||
if not data_v2[v.category] then data_v2[v.category] = {} end
|
||||
data_v2[v.category][k] = { pos = v.pos, owner = v.owner }
|
||||
end
|
||||
end
|
||||
return data_v2
|
||||
end
|
||||
|
||||
apartment.restore_data = function()
|
||||
local file = io.open(apartment.save_path, "r")
|
||||
if not file then
|
||||
minetest.log("action","[Apartment] v2 save file not found. Finding v1 files...")
|
||||
local data = apartment.migrate_v1()
|
||||
if data then
|
||||
apartment.apartments = data
|
||||
end
|
||||
apartment.data_modified = true
|
||||
else
|
||||
local s_data = file:read("*all")
|
||||
if s_data == "" then
|
||||
minetest.log("error","[Apartment] Save file was empty: " .. apartment.save_path)
|
||||
file:close()
|
||||
return false
|
||||
end
|
||||
local data = minetest.deserialize(s_data)
|
||||
if data == nil then -- Known bug of advtrains: when file grows, it may fail to load.
|
||||
apartment.working = false -- Even if pcall()ed, the mod will still refuse to do any operations.
|
||||
error("[Apartment] Failed to deserialize data. Please solve this problem manually.")
|
||||
return false
|
||||
end
|
||||
apartment.apartments = data
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
dofile(MP .. "/chg_owner.lua")
|
||||
|
||||
apartment.rent = function( pos, owner, oldmetadata, actor )
|
||||
local node = minetest.get_node(pos)
|
||||
local meta, original_owner, now_owner, descr, category, size_up, size_down, size_right, size_left, size_front, size_back
|
||||
if not oldmetadata then
|
||||
meta = minetest.get_meta(pos)
|
||||
original_owner = meta:get_string('original_owner')
|
||||
now_owner = meta:get_string('owner')
|
||||
descr = meta:get_string('descr')
|
||||
category = meta:get_string('category')
|
||||
|
||||
size_up = meta:get_int( 'size_up' );
|
||||
size_down = meta:get_int( 'size_down' );
|
||||
size_right = meta:get_int( 'size_right' );
|
||||
size_left = meta:get_int( 'size_left' );
|
||||
size_front = meta:get_int( 'size_front' );
|
||||
size_back = meta:get_int( 'size_back' );
|
||||
else
|
||||
original_owner = oldmetadata.fields[ "original_owner" ]
|
||||
now_owner = oldmetadata.fields[ "owner" ]
|
||||
descr = oldmetadata.fields[ "descr" ]
|
||||
category = oldmetadata.fields[ "category" ]
|
||||
|
||||
size_up = tonumber(oldmetadata.fields[ "size_up" ])
|
||||
size_down = tonumber(oldmetadata.fields[ "size_down" ])
|
||||
size_right = tonumber(oldmetadata.fields[ "size_right" ])
|
||||
size_left = tonumber(oldmetadata.fields[ "size_left" ])
|
||||
size_front = tonumber(oldmetadata.fields[ "size_front" ])
|
||||
size_back = tonumber(oldmetadata.fields[ "size_back" ])
|
||||
|
||||
node.param2 = oldmetadata.param2
|
||||
end
|
||||
if not(original_owner and now_owner and descr and size_up and size_down and size_right and size_left and size_front and size_back) then
|
||||
return false, "META_LOOKUP_ERR"
|
||||
end
|
||||
|
||||
local x1 = pos.x;
|
||||
local y1 = pos.y;
|
||||
local z1 = pos.z;
|
||||
local x2 = pos.x;
|
||||
local y2 = pos.y;
|
||||
local z2 = pos.z;
|
||||
|
||||
if node.param2 == 0 then -- z gets larger
|
||||
x1 = x1 - size_left; x2 = x2 + size_right;
|
||||
z1 = z1 - size_front; z2 = z2 + size_back;
|
||||
elseif node.param2 == 1 then -- x gets larger
|
||||
z1 = z1 - size_right; z2 = z2 + size_left;
|
||||
x1 = x1 - size_front; x2 = x2 + size_back;
|
||||
elseif node.param2 == 2 then -- z gets smaller
|
||||
x1 = x1 - size_right; x2 = x2 + size_left;
|
||||
z1 = z1 - size_back; z2 = z2 + size_front;
|
||||
elseif node.param2 == 3 then -- x gets smaller
|
||||
z1 = z1 - size_left; z2 = z2 + size_right;
|
||||
x1 = x1 - size_back; x2 = x2 + size_front;
|
||||
end
|
||||
y1 = y1 - size_down; y2 = y2 + size_up;
|
||||
|
||||
local px = x1;
|
||||
local py = x1;
|
||||
local pz = z1;
|
||||
for px = x1, x2 do
|
||||
for py = y1, y2 do
|
||||
for pz = z1, z2 do
|
||||
local npos = vector.new(px,py,pz)
|
||||
apartment.chg_owner(pos,npos,category,descr,original_owner,now_owner,owner,actor)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
meta:set_string("owner",owner)
|
||||
|
||||
if not apartment.apartments[category] then apartment.apartments[category] = {} end
|
||||
apartment.apartments[category][descr] = {pos=pos,original_owner=original_owner,owner=owner}
|
||||
apartment.data_modified = true
|
||||
|
||||
if not oldmetadata then
|
||||
minetest.debug(owner,original_owner,node.name)
|
||||
if (owner == "" or original_owner == owner) and (node.name == 'apartment:apartment_occupied') then
|
||||
minetest.swap_node( pos, {name='apartment:apartment_free', param2 = node.param2} )
|
||||
elseif (original_owner ~= owner) and (node.name == 'apartment:apartment_free') then
|
||||
minetest.swap_node( pos, {name='apartment:apartment_occupied', param2 = node.param2} )
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
apartment.on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos);
|
||||
meta:set_string('infotext', S('Apartment Management Panel (unconfigured)'))
|
||||
meta:set_string('original_owner', '' )
|
||||
meta:set_string('owner', '' )
|
||||
meta:set_string('descr', '' )
|
||||
meta:set_int( 'size_up', 0 )
|
||||
meta:set_int( 'size_down', 0 )
|
||||
meta:set_int( 'size_right', 0 )
|
||||
meta:set_int( 'size_left', 0 )
|
||||
meta:set_int( 'size_front', 0 )
|
||||
meta:set_int( 'size_back', 0 )
|
||||
end
|
||||
|
||||
apartment.after_place_node = function(pos, placer)
|
||||
local meta = minetest.get_meta(pos);
|
||||
local pname = (placer:get_player_name() or "");
|
||||
meta:set_string("original_owner", pname );
|
||||
meta:set_string("owner", pname );
|
||||
meta:set_string('infotext', S('Apartment Management Panel (owned by @1)',pname))
|
||||
end
|
||||
|
||||
apartment.can_dig = function(pos,player)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local owner = meta:get_string('owner')
|
||||
local original_owner = meta:get_string( 'original_owner' )
|
||||
local pname = player:get_player_name()
|
||||
|
||||
if original_owner == '' then
|
||||
return true
|
||||
end
|
||||
if original_owner ~= pname then
|
||||
minetest.chat_send_player( pname, S('Sorry. Only the original owner of this apartment control panel can dig it.'));
|
||||
return false
|
||||
end
|
||||
if not(original_owner == owner or owner == "") then
|
||||
minetest.chat_send_player( pname, S('The apartment is currently rented to @1. Please end that first.',owner));
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
apartment.after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
if not( oldmetadata ) or oldmetadata=="nil" or not(oldmetadata.fields) then
|
||||
minetest.chat_send_player( digger:get_player_name(), S("Error: Could not find information about the apartment panel that is to be removed."))
|
||||
return
|
||||
end
|
||||
|
||||
local descr = oldmetadata.fields[ "descr" ]
|
||||
local category = oldmetadata.fields[ "category" ]
|
||||
if( apartment.apartments[ descr ] ) then
|
||||
-- actually remove the apartment
|
||||
oldmetadata.param2 = oldnode.param2
|
||||
apartment.rent( pos, '', oldmetadata, digger )
|
||||
apartment.apartments[ descr ] = nil
|
||||
apartment.data_modified = true
|
||||
minetest.chat_send_player( digger:get_player_name(), S("Removed apartment @1@@@2 successfully.",descr,category))
|
||||
end
|
||||
end
|
||||
|
||||
apartment.on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
|
||||
if not apartment.working then return end
|
||||
if not clicker:is_player() then return end
|
||||
local name = clicker:get_player_name()
|
||||
local meta = minetest.get_meta(pos)
|
||||
|
||||
local ctx = {pos=pos,meta=meta}
|
||||
local owner = meta:get_string( 'owner' )
|
||||
local original_owner = meta:get_string( 'original_owner' )
|
||||
local category = meta:get_string( 'category' )
|
||||
if original_owner == owner and category == "" then
|
||||
if itemstack:get_name() == "apartment:configuration_copier" then
|
||||
local imeta = itemstack:get_meta()
|
||||
ctx.defaults = {}
|
||||
ctx.defaults.category = imeta:get_string("category")
|
||||
ctx.defaults.descr = imeta:get_string("descr")
|
||||
|
||||
if ctx.defaults.category == "" or ctx.defaults.descr == "" then
|
||||
ctx.defaults = nil -- Unconfigured copier
|
||||
else
|
||||
while apartment.apartments[ctx.defaults.category][ctx.defaults.descr] do
|
||||
local number = string.match(ctx.defaults.descr,'%d+$')
|
||||
local new_descr = ctx.defaults.descr .. "_1"
|
||||
if number then
|
||||
new_descr = string.sub(ctx.defaults.descr,1,-#tostring(number)-1) .. tostring(number + 1)
|
||||
end
|
||||
ctx.defaults.descr = new_descr
|
||||
end
|
||||
ctx.defaults.size_up = imeta:get_int( 'size_up' )
|
||||
ctx.defaults.size_down = imeta:get_int( 'size_down' )
|
||||
ctx.defaults.size_right = imeta:get_int( 'size_right' )
|
||||
ctx.defaults.size_left = imeta:get_int( 'size_left' )
|
||||
ctx.defaults.size_front = imeta:get_int( 'size_front' )
|
||||
ctx.defaults.size_back = imeta:get_int( 'size_back' )
|
||||
end
|
||||
end
|
||||
apartment.gui.configure_gui:show(clicker,ctx)
|
||||
else
|
||||
apartment.gui.panel_control:show(clicker,ctx)
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_craftitem("apartment:configuration_copier", {
|
||||
description = S("Apartment Configuaration Copier"),
|
||||
inventory_image = "apartment_configuration_copier.png",
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
if not user:is_player() then return end
|
||||
local name = user:get_player_name()
|
||||
if pointed_thing.type ~= "node" then return end
|
||||
local pos = pointed_thing.under
|
||||
local node = minetest.get_node(pos)
|
||||
if node.name ~= "apartment:apartment_free" and node.name ~= "apartment:apartment_occupied" then return end
|
||||
local meta = minetest.get_meta(pos)
|
||||
local category = meta:get_string("category")
|
||||
local descr = meta:get_string("descr")
|
||||
|
||||
if category == "" or descr == "" then
|
||||
minetest.chat_send_player(name, S("Please configure the panel first before copying configurations from it."))
|
||||
return
|
||||
end
|
||||
|
||||
local size_up = meta:get_int( 'size_up' )
|
||||
local size_down = meta:get_int( 'size_down' )
|
||||
local size_right = meta:get_int( 'size_right' )
|
||||
local size_left = meta:get_int( 'size_left' )
|
||||
local size_front = meta:get_int( 'size_front' )
|
||||
local size_back = meta:get_int( 'size_back' )
|
||||
|
||||
local imeta = itemstack:get_meta()
|
||||
|
||||
imeta:set_string("category",category)
|
||||
imeta:set_string("descr",descr)
|
||||
|
||||
imeta:set_int("size_up",size_up)
|
||||
imeta:set_int("size_down",size_down)
|
||||
imeta:set_int("size_right",size_right)
|
||||
imeta:set_int("size_left",size_left)
|
||||
imeta:set_int("size_front",size_front)
|
||||
imeta:set_int("size_back",size_back)
|
||||
|
||||
imeta:set_string("description",S("Apartment Configuaration Copier\nU:@1 D:@2 L:@3 R:@4 F:@5 B:@6\n@7@@@8\nRightclick on a panel to paste the configurations.",size_up,size_down,size_right,size_left,size_front,size_back,descr,category))
|
||||
|
||||
minetest.chat_send_player(name, S("Configuration copied."))
|
||||
|
||||
return itemstack
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_node("apartment:apartment_free", {
|
||||
description = S("Apartment Management Panel"),
|
||||
drawtype = "nodebox",
|
||||
tiles = {"default_steel_block.png","default_steel_block.png","default_steel_block.png","default_steel_block.png",
|
||||
"default_steel_block.png","apartment_controls_vacant.png","default_steel_block.png"},
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
light_source = 14,
|
||||
groups = {cracky=2},
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{ -0.5+(1/16), -0.5+(1/16), 0.5, 0.5-(1/16), 0.5-(1/16), 0.30},
|
||||
|
||||
}
|
||||
},
|
||||
on_construct = apartment.on_construct,
|
||||
after_place_node = apartment.after_place_node,
|
||||
can_dig = apartment.can_dig,
|
||||
after_dig_node = apartment.after_dig_node,
|
||||
on_rightclick = apartment.on_rightclick,
|
||||
})
|
||||
|
||||
minetest.register_node("apartment:apartment_occupied", {
|
||||
description = S("Apartment Management Panel") .. " Occupied",
|
||||
drawtype = "nodebox",
|
||||
tiles = {"default_steel_block.png","default_steel_block.png","default_steel_block.png","default_steel_block.png",
|
||||
"default_steel_block.png","apartment_controls_occupied.png","default_steel_block.png"},
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
light_source = 14,
|
||||
groups = {cracky=2, not_in_creative_inventory=1},
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{ -0.5+(1/16), -0.5+(1/16), 0.5, 0.5-(1/16), 0.5-(1/16), 0.30},
|
||||
|
||||
}
|
||||
},
|
||||
on_construct = apartment.on_construct,
|
||||
after_place_node = function(pos,placer)
|
||||
local node = minetest.get_node(pos)
|
||||
node.name = "apartment:apartment_free"
|
||||
minetest.swap_node(pos,node)
|
||||
return apartment.after_place_node(pos,placer)
|
||||
end,
|
||||
can_dig = apartment.can_dig,
|
||||
after_dig_node = apartment.after_dig_node,
|
||||
on_rightclick = apartment.on_rightclick,
|
||||
})
|
||||
|
||||
if apartment.enable_aphome_command then
|
||||
minetest.register_chatcommand("aphome", {
|
||||
params = "[<category>]",
|
||||
description = S("Teleports you back to the apartment you rented."),
|
||||
privs = {home=true},
|
||||
func = function(name, param)
|
||||
local category = (param == "" and "apartment" or param)
|
||||
local player = minetest.get_player_by_name(name)
|
||||
|
||||
if not apartment.apartments[category] then
|
||||
return false, S("You do not have an apartment in category @1.",category)
|
||||
end
|
||||
|
||||
for k,v in pairs( apartment.apartments[category] ) do
|
||||
if v and v.owner == name then
|
||||
player:set_pos(v.pos)
|
||||
return true, S("Welcome back to your apartment @1@@@2.",k,category)
|
||||
end
|
||||
end
|
||||
|
||||
return false, S("You do not have an apartment in category @1.",category)
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
-- old version of the node - will transform into _free or _occupied
|
||||
if minetest.settings:get_bool("apartment.old_compact_codes",true) then
|
||||
minetest.register_node("apartment:apartment", {
|
||||
drawtype = "nodebox",
|
||||
description = "apartment management panel (transition state)",
|
||||
tiles = {"default_steel_block.png","default_steel_block.png","default_steel_block.png","default_steel_block.png",
|
||||
"default_steel_block.png","apartment_controls_vacant.png","default_steel_block.png"},
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
light_source = 14,
|
||||
groups = {cracky=2,not_in_creative_inventory=1},
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{ -0.5+(1/16), -0.5+(1/16), 0.5, 0.5-(1/16), 0.5-(1/16), 0.30},
|
||||
|
||||
}
|
||||
},
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{ -0.5+(1/16), -0.5+(1/16), 0.5, 0.5-(1/16), 0.5-(1/16), 0.30},
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_abm({
|
||||
nodenames = {"apartment:apartment"},
|
||||
interval = 60,
|
||||
chance = 1,
|
||||
action = function(pos, node)
|
||||
local node = minetest.get_node( pos )
|
||||
local meta = minetest.get_meta( pos )
|
||||
local owner = meta:get_string( 'owner' )
|
||||
local original_owner = meta:get_string( 'original_owner' )
|
||||
if owner == '' or original_owner==owner then
|
||||
minetest.swap_node( pos, {name='apartment:apartment_free', param2 = node.param2} )
|
||||
else
|
||||
minetest.swap_node( pos, {name='apartment:apartment_occupied', param2 = node.param2} )
|
||||
end
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
minetest.register_abm({
|
||||
nodenames= {"apartment:apartment_free" },
|
||||
interval = 1,
|
||||
chance = 1,
|
||||
action = function(pos,node)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("formspec","") -- Remove formspec used in v1
|
||||
local descr = meta:get_string("descr")
|
||||
local category = meta:get_string("category")
|
||||
|
||||
local cat_data = apartment.apartments[category]
|
||||
if not cat_data then return end
|
||||
local ap_data = cat_data[descr]
|
||||
|
||||
if not ap_data then return end -- Still writing data, please wait!
|
||||
|
||||
if not vector.equals(ap_data.pos,pos) then -- Dulplicated!
|
||||
local new_data = table.copy(ap_data)
|
||||
new_data.pos = pos
|
||||
local number = string.match(descr,'%d+$')
|
||||
local new_descr = descr .. "_1"
|
||||
if number then
|
||||
new_descr = string.sub(descr,1,-#tostring(number)-1) .. tostring(number + 1)
|
||||
end
|
||||
meta:set_string("descr",new_descr)
|
||||
cat_data[new_descr] = new_data
|
||||
apartment.data_modified = true
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
apartment.restore_data()
|
4
mod.conf
Normal file
4
mod.conf
Normal file
@ -0,0 +1,4 @@
|
||||
name = apartment
|
||||
title = Self-service rental panels for players to rent apartments or shops
|
||||
depends = flow
|
||||
optional_depends = default
|
BIN
textures/apartment_configuration_copier.png
Normal file
BIN
textures/apartment_configuration_copier.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
BIN
textures/apartment_controls_occupied.png
Normal file
BIN
textures/apartment_controls_occupied.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
BIN
textures/apartment_controls_vacant.png
Normal file
BIN
textures/apartment_controls_vacant.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
Loading…
x
Reference in New Issue
Block a user