diff options
Diffstat (limited to 'ch_data/init.lua')
-rw-r--r-- | ch_data/init.lua | 764 |
1 files changed, 764 insertions, 0 deletions
diff --git a/ch_data/init.lua b/ch_data/init.lua new file mode 100644 index 0000000..6373461 --- /dev/null +++ b/ch_data/init.lua @@ -0,0 +1,764 @@ +ch_base.open_mod(core.get_current_modname()) + +local worldpath = core.get_worldpath() +local datapath = worldpath.."/ch_playerdata" +local playerlist_path = worldpath.."/ch_data_players" +local storage = core.get_mod_storage() +local old_online_charinfo = {} -- uchovává online_charinfo[] po odpojení postavy +local players_list, players_set = {}, {} -- seznam/množina všech známých hráčských postav (pro offline_charinfo) +local lc_to_player_name = {} -- pro jména existujících postav lowercase => loginname +local current_format_version = 2 + +ch_data = { + online_charinfo = {}, + offline_charinfo = {}, + supported_lang_codes = {cs = true, sk = true}, + -- Tato funkce může být přepsána. Rozhoduje, zda zadané jméno postavy je přijatelné. + is_acceptable_name = function(player_name) return true end, + initial_offline_charinfo = { + -- int (> 0) -- pro [ch_core/ap], udává aktuální úroveň postavy + ap_level = 1, -- musí být > 0 + -- int (> 0) -- pro [ch_core/ap], udává verzi systému AP (pro upgrade) + ap_version = 1, + -- int (>= 0) -- pro [ch_core/ap], udává celkový počet bodů aktivity postavy + ap_xp = 0, + -- int {0, 1} -- 0 = nic, 1 = předměty házet do koše + discard_drops = 0, + -- string -- pro [ch_core/teleport], pozice uložená příkazem /domů + domov = "", + -- int (>= 0) -- pro [ch_core/chat] udává aktuální doslech + doslech = 50, + -- int {0, 1} -- pro [ch_core] 0 = normální velikost, 1 = rozšířený inventář + extended_inventory = 0, + -- string -- pole příznaků + flags = "", + -- string YYYY-MM-DD nebo "" -- datum, kdy byla hráči/ce naposledy vypsána oznámení po přihlášení do hry (YYYY-MM-DD) + last_ann_shown_date = "1970-01-01", + -- int (>= 0) -- v sekundách od 1. 1. 2000 UTC; 0 značí neplatnou hodnotu + last_login = 0, + -- int {0, 1} -- 0 = shýbat se při stisku Shift; 1 = neshýbat se + neshybat = 0, + -- int {0, 1} -- 0 = krásná obloha ano, 1 ne + no_ch_sky = 0, + -- float -- v sekundách + past_ap_playtime = 0.0, + -- float -- v sekundách + past_playtime = 0.0, + -- string -- výčet dodatečných práv naplánovaných pro registraci postavy + pending_registration_privs = "", + -- string -- typ naplánované registrace postavy + pending_registration_type = "", + -- int -- pro [ch_bank] + rezim_plateb = 0, + -- int {0, 1} -- 0 => zobrazit, 1 => skrýt + skryt_body = 0, + -- int {0, 1} -- 0 => zobrazovat (výchozí), 1 => skrýt + skryt_hlad = 0, + -- int {0, 1} -- 0 => zobrazovat (výchozí), 1 => skrýt + skryt_zbyv = 0, + -- string -- pro [ch_core/teleport], pozice uložená příkazem /stavím + stavba = "", + -- string -- nastavení filtru událostí + ui_event_filter = "", + -- int (>= 1) -- číslo verze uložených dat (umožňuje upgrade) + version = current_format_version, + -- int {1, 2, 3} -- volba cíle pro /začátek: 1 => Začátek, 2 => Masarykovo náměstí, 3 => Hlavní nádraží + zacatek_kam = 1, + }, + initial_offline_playerinfo = { + -- int -- výše uloženého trestu (může být záporná) + trest = 0, + } +} + +-- POZNÁMKA: protože příznaky z následujícího pole se mapují na znaky v řetězci 'flags', nesmí se mazat ani zakomentovat! +-- Je však možno je přejmenovat při zachování pozice. +local flag_ids = { + "discard_drops", + "extended_inventory", + "neshybat", + "no_ch_sky", + "skryt_body", + "skryt_hlad", + "skryt_zbyv", +} +local flag_name_to_id = {} + +for i, flag in ipairs(flag_ids) do + local old_id = flag_name_to_id[flag] + if old_id ~= nil then + error("Flag '"..flag.."' has multiple IDs: "..old_id..", "..i.."!") + end + flag_name_to_id[flag] = i +end +ch_data.initial_offline_charinfo.flags = string.rep(" ", #flag_ids) + +local function add_player(player_name, new_offline_charinfo, player_info) + if players_set[player_name] then + return false + end + assert(new_offline_charinfo) + local lcase = string.lower(player_name) + -- add player to players_list (persistently): + table.insert(players_list, player_name) + core.safe_file_write(playerlist_path, assert(core.serialize(players_list))) + -- add player to players_set and lc_to_player_name: + players_set[player_name] = true + lc_to_player_name[lcase] = player_name + -- add new offline_charinfo: + ch_data.offline_charinfo[player_name] = new_offline_charinfo + -- add new offline_charinfo[].player: + new_offline_charinfo.player = player_info or table.copy(ch_data.initial_offline_playerinfo) + if new_offline_charinfo.player.name == nil then + new_offline_charinfo.player.name = player_name + end + return true +end + +local function delete_player(player_name) + -- check if the player exists: + if not players_set[player_name] then + return false + end + -- detach offline_playerinfo: + local offline_player_info = assert(ch_data.offline_charinfo[player_name].player) + local aliases = {} + for alias, offline_charinfo in pairs(ch_data.offline_charinfo) do + if alias ~= player_name and offline_charinfo.player.name == player_name then + offline_player_info = offline_charinfo.player + table.insert(aliases, alias) + end + end + if #aliases > 0 then + offline_player_info.name = aliases[1] + core.log("debug", "delete_player(): dotplayer of "..table.concat(aliases, ",").." corrected to "..player_info.name) + for _, alias in ipairs(aliases) do + ch_core.save_offline_playerinfo(alias) + end + end + -- remove player from players_list: + local lcase = string.lower(player_name) + for i, pname in ipairs(players_list) do + if pname == player_name then + table.remove(players_list, i) + break + end + end + -- save the player_list: + core.safe_file_write(playerlist_path, assert(core.serialize(players_list))) + -- remove player from players_set: + players_set[player_name] = nil + -- remove player from lc_to_player_name: + lc_to_player_name[lcase] = nil + -- remove player from offline_charinfo: + ch_data.offline_charinfo[player_name] = nil + return true +end + +function ch_data.get_flag(charinfo, flag_name, default_result) + local id = flag_name_to_id[flag_name] + if id ~= nil then + local result = (charinfo.flags or ""):sub(id, id) + if result ~= "" then + return result + end + end + return default_result or " " +end + +function ch_data.get_flags(charinfo) + local flags = charinfo.flags or "" + local result = {} + for id, name in ipairs(flag_ids) do + local value = flags:sub(id, id) + if value == "" then + value = " " + end + result[name] = value + end + return result +end + +function ch_data.set_flag(charinfo, flag_name, value) + local id = flag_name_to_id[flag_name] + if id == nil then + return false + end + value = (tostring(value).." "):sub(1,1) + local flags = charinfo.flags or "" + if flags:len() < id then + flags = flags..string.rep(" ", id - flags:len() - 1)..value + else + flags = flags:sub(1, id - 1)..value..flags:sub(id + 1, -1) + end + charinfo.flags = flags + return true +end + +function ch_data.correct_player_name_casing(name) + return lc_to_player_name[string.lower(name)] +end + +function ch_data.get_joining_online_charinfo(player) + assert(core.is_player(player)) + local player_name = player:get_player_name() + local result = ch_data.online_charinfo[player_name] + if result ~= nil then + return result + end + local player_info = core.get_player_information(player_name) + local now = core.get_us_time() + result = { + areas = {{ + id = 0, + name = "Český hvozd", + type = 1, + }}, + -- časová známka vytvoření online_charinfo (vstupu postavy do hry) + join_timestamp = now, + -- jazykový kód (obvykle "cs") + lang_code = player_info.lang_code or "", + -- úroveň osvětlení postavy + light_level = 0, + -- časová známka pro úroveň osvětlení postavy + light_level_timestamp = now, + -- verze protokolu + protocol_version = player_info.protocol_version or 0, + -- tabulka již zobrazených nápověd (bude deserializována níže) + navody = {}, + -- co udělat těsně po připojení + news_role = "new_player", + -- přihlašovací jméno + player_name = player_name, + } + + -- news_role: + --[[ + 5.5.x => formspec_version = 5, protocol_version = 40 + 5.6.x => formspec_version = 6, protocol_version = 41 + 5.7.x => formspec_version = 6, protocol_version = 42 + 5.8.0 => formspec_version = 7, protocol_version = 43 + 5.9.0 => formspec_version = ?, protocol_version = ? + 5.10.0 => formspec_version = 8, protocol_version = 46 + ]] + if result.protocol_version < 42 then + result.news_role = "disconnect" + elseif not ch_data.supported_lang_codes[result.lang_code] and not core.check_player_privs(player, "server") then + result.news_role = "invalid_locale" + elseif core.check_player_privs(player, "ch_registered_player") then + result.news_role = "player" + elseif not ch_data.is_acceptable_name(player_name) then + result.news_role = "invalid_name" + else + result.news_role = "new_player" + end + + ch_data.online_charinfo[player_name] = result + local prev_online_charinfo = old_online_charinfo[player_name] + if prev_online_charinfo ~= nil then + old_online_charinfo[player_name] = nil + if prev_online_charinfo.leave_timestamp ~= nil then + result.prev_leave_timestamp = prev_online_charinfo.leave_timestamp + end + end + core.log("action", "JOIN PLAYER(" .. player_name ..") at "..now.." with lang_code \""..result.lang_code.. + "\", formspec_version = "..tostring(player_info.formspec_version)..", protocol_version = ".. + result.protocol_version..", news_role = "..result.news_role..", ip_address = "..tostring(player_info.address)) + + -- deserializovat návody: + local meta = player:get_meta() + local s = meta:get_string("navody") + if s and s ~= "" then + result.navody = core.deserialize(s, true) or result.navody + end + + if result.news_role ~= "invalid_name" then + ch_data.get_or_add_offline_charinfo(player_name) + end + --[[ + TODO: + if core.is_creative_enabled(player_name) then + result.is_creative = true + if ch_core.set_immortal then + ch_core.set_immortal(player, true) + end + end + else + core.log("error", "Player object not available for "..player_name.." in get_joining_online_charinfo()!") + end + ]] + return result +end + +function ch_data.get_leaving_online_charinfo(player) + assert(core.is_player(player)) + local player_name = player:get_player_name() + local result = ch_data.online_charinfo[player_name] + if result ~= nil then + result.leave_timestamp = core.get_us_time() + old_online_charinfo[player_name] = result + ch_data.online_charinfo[player_name] = nil + return result + else + return old_online_charinfo[player_name] + end +end + +function ch_data.delete_offline_charinfo(player_name) + if ch_data.online_charinfo[player_name] ~= nil then + return false, "Postava je ve hře!" + end + if not delete_player(player_name) then + return false, "Mazání selhalo." + end + local success, errmsg = os.remove(worldpath.."/ch_playerdata/"..player_name) + if success then + return true, "Úspěšně smazáno." + else + return false, "Mazání souboru selhalo: "..(errmsg or "nil") + end +end + +function ch_data.get_offline_charinfo(player_name) + local result = ch_data.offline_charinfo[player_name] + if result == nil then + error("Offline charinfo not found for player '"..player_name.."'!") + end + return result +end + +function ch_data.get_or_add_offline_charinfo(player_name) + local result = ch_data.offline_charinfo[player_name] + if result == nil then + add_player(player_name, table.copy(ch_data.initial_offline_charinfo)) + result = assert(ch_data.offline_charinfo[player_name]) + core.log("action", "[ch_data] Offline charinfo initialized for "..player_name) + ch_data.save_offline_charinfo(player_name) + end + return result +end + +local debug_flag = false + +function ch_data.save_offline_charinfo(player_name, include_playerinfo) + if players_set[player_name] == nil then + return false + end + local data = ch_data.offline_charinfo[player_name] + if data == nil then + return false + end + core.safe_file_write(datapath.."/"..player_name, assert(core.serialize(data))) + if include_playerinfo and data.player.name ~= player_name then + local dotplayer_name = data.player.name + assert(ch_data.offline_charinfo[dotplayer_name]) + assert(ch_data.offline_charinfo[dotplayer_name].player.name == dotplayer_name) + return ch_data.save_offline_charinfo(dotplayer_name) + end + return true +end + +function ch_data.save_offline_playerinfo(player_name) + if players_set[player_name] == nil then + return false + end + local data = ch_data.offline_charinfo[player_name] + if data == nil then + return false + end + local dotplayer_name = assert(data.player.name) + assert(ch_data.offline_charinfo[dotplayer_name]) + assert(ch_data.offline_charinfo[dotplayer_name].player.name == dotplayer_name) + return ch_data.save_offline_charinfo(dotplayer_name) +end + +local function on_joinplayer(player, last_login) + ch_data.get_joining_online_charinfo(player) +end + +local function on_leaveplayer(player) + ch_data.get_leaving_online_charinfo(player) +end + +core.register_on_joinplayer(on_joinplayer) +core.register_on_leaveplayer(on_leaveplayer) + +local function upgrade_offline_charinfo(player_name, data) + local old_version = data.version + if data.version <= 1 then + data.player.trest = data.trest or 0 + data.trest = nil + end + data.version = current_format_version + core.log("info", "Offline_charinfo["..player_name.."] upgraded from version "..old_version.." to the current version "..data.version..".") + return true +end + +-- Load and initialize: + +core.mkdir(datapath) +local function initialize() + local f = io.open(playerlist_path) + if f then + local text = f:read("*a") + f:close() + if text ~= nil and text ~= "" then + local new_players = core.deserialize(text, true) + if type(new_players) == "table" then + core.log("action", "[ch_data] "..#new_players.." known players.") + players_list = new_players + players_set = {} + for _, player_name in ipairs(players_list) do + players_set[player_name] = true + end + end + end + end + for _, player_name in ipairs(players_list) do + f = io.open(datapath.."/"..player_name) + if f then + local text = f:read("*a") + f:close() + if text ~= nil and text ~= "" then + local data = core.deserialize(text, true) + if type(data) == "table" then + ch_data.offline_charinfo[player_name] = data + lc_to_player_name[string.lower(player_name)] = player_name + end + end + end + if ch_data.offline_charinfo[player_name] == nil then + core.log("error", "[ch_data] deserialization of offline_charinfo["..player_name.."] failed!") + end + end + for player_name, poc in pairs(ch_data.offline_charinfo) do + -- vivify/upgrade/correct offline_charinfo: + for key, value in pairs(ch_data.initial_offline_charinfo) do + if poc[key] == nil then + poc[key] = value + core.log("warning", "Missing offline_charinfo key "..player_name.."/"..key.." vivified.") + end + end + -- correct invalid past_playtime: + if poc.past_playtime < 0 then + core.log("warning", "Invalid past_playtime for "..player_name.." ("..poc.past_playtime..") corrected to zero!") + poc.past_playtime = 0 -- correction of invalid data + end + -- vivify .player table (including .player.name) + if poc.player == nil or poc.player.name == nil then + poc.player = {name = player_name} + end + end + -- link .player tables according to .player.name: + for player_name, poc in pairs(ch_data.offline_charinfo) do + local dotplayer_name = assert(poc.player.name) + if dotplayer_name ~= player_name then + if players_set[dotplayer_name] and ch_data.offline_charinfo[dotplayer_name] then + poc.player = assert(ch_data.offline_charinfo[dotplayer_name].player) + else + error("offline_charinfo["..player_name.."] looks for player data of '"..dotplayer_name.."', but it doesn't exist!") + end + end + end + -- upgrade old data: + for player_name, poc in pairs(ch_data.offline_charinfo) do + if poc.version < current_format_version then + upgrade_offline_charinfo(player_name, poc) + end + end +end + +initialize() +initialize = nil + +-- Obsluhy událostí: +-- ====================================================================================================================== +local function on_joinplayer(player, last_login) + local player_name = player:get_player_name() + local online_charinfo = ch_data.get_joining_online_charinfo(player) + local offline_charinfo = ch_data.get_offline_charinfo(player_name) + online_charinfo.doslech = offline_charinfo.doslech + + if offline_charinfo ~= nil then + offline_charinfo.last_login = os.time() - 946684800 + ch_data.save_offline_charinfo(player_name) + -- lc_to_player_name[string.lower(player_name)] = player_name + end + + return true +end + +local function save_playtime(online_charinfo, offline_charinfo) + if offline_charinfo == nil then + return 0, 0, 0 + end + local now = core.get_us_time() + local past_playtime = offline_charinfo.past_playtime or 0 + local current_playtime = math.max(0, 1.0e-6 * (now - online_charinfo.join_timestamp)) + local total_playtime = past_playtime + current_playtime + + offline_charinfo.past_playtime = total_playtime + ch_data.save_offline_charinfo(online_charinfo.player_name) + online_charinfo.join_timestamp = nil + return past_playtime, current_playtime, total_playtime +end + +local function on_leaveplayer(player, timedout) + local player_name = player:get_player_name() + local online_info = ch_data.get_leaving_online_charinfo(player) + + if online_info.join_timestamp then + local past_playtime, current_playtime, total_playtime = save_playtime(online_info, ch_data.offline_charinfo[player_name]) + print("PLAYER(" .. player_name .."): played seconds: " .. current_playtime .. " / " .. total_playtime) + end +end + +local function on_shutdown() + for player_name, online_info in pairs(table.copy(ch_data.online_charinfo)) do + if online_info.join_timestamp then + local past_playtime, current_playtime, total_playtime + past_playtime, current_playtime, total_playtime = save_playtime(online_info, ch_data.offline_charinfo[player_name]) + print("PLAYER(" .. player_name .."): played seconds: " .. current_playtime .. " / " .. total_playtime) + end + end +end + +local function on_placenode(pos, newnode, placer, oldnode, itemstack, pointed_thing) + if core.is_player(placer) then + local player_name = placer:get_player_name() + local online_charinfo = ch_data.online_charinfo[player_name] + if online_charinfo ~= nil then + online_charinfo.last_placenode_ustime = core.get_us_time() + end + end +end + +local function on_dignode(pos, oldnode, digger) + if core.is_player(digger) then + local player_name = digger:get_player_name() + local online_charinfo = ch_data.online_charinfo[player_name] + if online_charinfo ~= nil then + online_charinfo.last_dignode_ustime = core.get_us_time() + end + end +end + +function ch_data.clear_help(player) + local player_name = player:get_player_name() + local online_charinfo = ch_data.online_charinfo[player_name] + if online_charinfo then + online_charinfo.navody = {} + player:get_meta():set_string("navody", core.serialize(online_charinfo.navody)) + return true + else + return false + end +end + +--[[ + Otestuje, zda podle online_charinfo má dané postavě být zobrazený + v četu návod k položce daného názvu. Pokud ano, nastaví příznak, aby se + to znovu již nestalo, a vrátí definici daného předmětu, + z níž lze z položek description a _ch_help sestavit text k zobrazení. +]] +function ch_data.should_show_help(player, online_charinfo, item_name) + local def = core.registered_items[item_name] + if def and def._ch_help then + if def._ch_help_group then + item_name = def._ch_help_group + end + local navody = online_charinfo.navody + if not navody then + navody = {[item_name] = 1} + online_charinfo.navody = navody + player:get_meta():set_string("navody", core.serialize(navody)) + return def.description ~= nil and def + end + if not navody[item_name] then + navody[item_name] = 1 + player:get_meta():set_string("navody", core.serialize(navody)) + return def.description ~= nil and def + end + end + return nil +end + +function ch_data.nastavit_shybani(player_name, shybat) + local offline_charinfo = ch_data.offline_charinfo[player_name] + if offline_charinfo == nil then + core.log("error", "ch_data.nastavit_shybani(): Expected offline charinfo for player "..player_name.." not found!") + return false + end + local new_state + if shybat then + new_state = 0 + else + new_state = 1 + end + offline_charinfo.neshybat = new_state + ch_data.save_offline_charinfo(player_name) + return true +end + +core.register_on_joinplayer(on_joinplayer) +core.register_on_leaveplayer(on_leaveplayer) +core.register_on_shutdown(on_shutdown) +core.register_on_dignode(on_dignode) +core.register_on_placenode(on_placenode) + +local def = { + description = "Smaže údaje o tom, ke kterým předmětům již byly postavě zobrazeny nápovědy, takže budou znovu zobrazovány nápovědy ke všem předmětům.", + func = function(player_name, param) + if ch_data.clear_help(core.get_player_by_name(player_name)) then + return true, "Údaje smazány." + else + core.log("error", "/návodyznovu: vnitřní chyba serveru ("..player_name..")!") + return false, "Vnitřní chyba serveru" + end + end, +} +core.register_chatcommand("návodyznovu", def) +core.register_chatcommand("navodyznovu", def) + +def = { + description = "Odstraní údaje o postavě uložené v systému ch_data. Postava nesmí být ve hře.", + privs = {server = true}, + func = function(player_name, param) + local offline_charinfo = ch_data.offline_charinfo[param] + if not offline_charinfo then + return false, "Data o "..param.." nenalezena!" + end + if ch_data.delete_offline_charinfo(param) then + return true, "Data o "..param.." smazána." + else + return false, "Při odstraňování nastala chyba." + end + end, +} + +core.register_chatcommand("delete_offline_charinfo", def) + +def = { + description = "Trvale vypne či zapne shýbání postavy při držení Shiftu.", + params = "<ano|ne>", + func = function(player_name, param) + if param ~= "ano" and param ~= "ne" then + return false, "Chybná syntaxe." + end + if ch_data.nastavit_shybani(player_name, param == "ano") then + core.chat_send_player(player_name, "*** Shýbání postavy "..(param == "ne" and "vypnuto" or "zapnuto")..".") + return true + else + core.log("error", "/shybat: Expected offline charinfo for player "..player_name.." not found!") + return false, "Vnitřní chyba serveru: Data postavy nenalezena." + end + end, +} + +core.register_chatcommand("shýbat", def) +core.register_chatcommand("shybat", def) + +local function merge_playerinfos(player_name_a, player_name_b) + if player_name_a == player_name_b then + return false, "'"..player_name_a.."' a '"..player_name_b.."' reprezentují tutéž postavu!" + end + local oci_a = ch_data.offline_charinfo[player_name_a] + local oci_b = ch_data.offline_charinfo[player_name_b] + if oci_a == nil then + return false, "Postava '"..player_name_a.."' neexistuje!" + end + if oci_b == nil then + return false, "Postava '"..player_name_b.."' neexistuje!" + end + local dotplayer_a = assert(oci_a.player.name) + local dotplayer_b = assert(oci_b.player.name) + if dotplayer_a == dotplayer_b then + return false, "Postavy '"..player_name_a.."' a '"..player_name_b.."' již patří stejné/mu hráči/ce '"..dotplayer_a.."'." + end + local aliases = {dotplayer_b} + for alias, offline_charinfo in pairs(ch_data.offline_charinfo) do + if alias ~= dotplayer_b and offline_charinfo.player.name == dotplayer_b then + table.insert(aliases, alias) + end + end + ch_data.save_offline_charinfo(dotplayer_b) + for _, alias in ipairs(aliases) do + ch_data.offline_charinfo[alias].player = oci_a.player + ch_data.save_offline_charinfo(alias) + core.log("action", "[MERGE] Player info of .player "..dotplayer_a.." assigned to player "..alias..".") + end + return true, "Postavy "..table.concat(aliases, ",").." přiřazeny hráči/ce "..dotplayer_a.."." +end + +local function set_main_player(player_name) + local oci_a = ch_data.offline_charinfo[player_name] + if oci_a == nil then + return false, "Postava '"..player_name.."' neexistuje!" + end + local old_main = assert(oci_a.player.name) + if old_main == player_name then + return false, "Postava '"..player_name.."' již je hlavní." + end + local aliases = {} + for alias, offline_charinfo in pairs(ch_data.offline_charinfo) do + if alias ~= old_main and offline_charinfo.player.name == old_main then + table.insert(aliases, alias) + end + end + oci_a.player.name = player_name + ch_data.save_offline_charinfo(old_main) + for _, alias in ipairs(aliases) do + ch_data.save_offline_charinfo(alias) + end + return true, "Postava "..player_name.." nastavena jako hlavní (původní hlavní postava: "..old_main..")." +end + +function ch_data.get_player_characters(player_name) + local offline_charinfo = ch_data.offline_charinfo[player_name] + if offline_charinfo == nil then + return nil + end + local main_name = offline_charinfo.player.name + local result = {} + for name, oci in pairs(ch_data.offline_charinfo) do + if oci.player.name == main_name then + table.insert(result, name) + end + end + if #result > 1 then + table.sort(result, function(a, b) return (a == main_name and b ~= main_name) or a < b end) -- TODO: better sorting + end + return result, main_name +end + +def = { + description = "Sloučí hráčská data odpovídající postavě B s hráčskými daty odpovídajícími postavě A", + params = "<Jmeno_postavy_hlavni_A> <Jmeno_postavy_vedlejsi_B>", + privs = {server = true}, + func = function(admin_name, param) + local a, b = string.match(param, "^([^ ]+) +([^ ]+)$") + if a == nil or b == nil then + return false, "Chybné zadání!" + end + local result, message = merge_playerinfos(a, b) + return result, message + end, +} + +core.register_chatcommand("připojit_postavu", def) +core.register_chatcommand("pripojit_postavu", def) + +def = { + description = "Změní hlavní postavu hráče/ky", + params = "<Nova_hlavni_postava>", + privs = {server = true}, + func = function(admin_name, param) + local result, message = set_main_player(param) + return result, message + end, +} + +core.register_chatcommand("hlavní_postava", def) +core.register_chatcommand("hlavni_postava", def) + +ch_base.close_mod(core.get_current_modname()) |