buttons.lua 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  1. --[[
  2. Ideally all the level data should be read/written from storage, rather than node metadata. Maybe store in metadata until the final submission.
  3. This would allow for a node to be connected to an already existing ID, which could be useful if a spawn changed for any reason.
  4. This can be changed in the future I expect, as the data all exists in both locations currently.
  5. ]]
  6. local esc = minetest.formspec_escape
  7. local function random_pos()
  8. local pos_x = math.random(-30000,30000)
  9. local pos_y = math.random(-100,30000)
  10. local pos_z = math.random(-30000,30000)
  11. local pos = (pos_x..','..pos_y..','..pos_z)
  12. return pos
  13. end
  14. local function button_create(pos, player)
  15. local meta = minetest.get_meta(pos)
  16. local owner = meta:get_string('owner')
  17. local id = meta:get_string('id')
  18. local name = meta:get_string('name')
  19. local player_count = meta:get_int('player_count') or 3
  20. local xp = meta:get_int('xp') or 50
  21. local pos_string = minetest.string_to_pos(meta:get_string('pos'))
  22. local desc = meta:get_string('desc')
  23. local builders = meta:get_string('builders') or ''
  24. local solo = meta:get_string('solo') or 'true'
  25. local clean_pos = pos_string.x..','..pos_string.y..','..pos_string.z
  26. local formspec =
  27. 'formspec_version[3]'..
  28. 'size[12,8]'..
  29. 'background[-1,-1;14,10;lobby_button_bg.png]'..
  30. 'field[4.375,.5;3.25,.5;name;Map Name;'..esc(name)..']'..
  31. 'tooltip[name;Will be used in chat messages and as the infotext]'..
  32. 'checkbox[8.25,.75;solo;Allow Singleplayer;'..solo..']'..
  33. 'field[0.5,1.5;3.25,.5;player_count;Required # of Players;'..esc(player_count)..']'..
  34. 'field[4.375,1.5;3.25,.5;xp;Required XP;'..esc(xp)..']'..
  35. 'field[8.25,1.5;3.25,.5;pos;Spawn POS (x,y,z);'..esc(clean_pos)..']'..
  36. 'field[0.5,2.5;11,.5;builders;Allowed Builders;'..esc(builders)..']'..
  37. 'tooltip[builders;List of players that should be able to visit the map as builders.]'..
  38. 'textarea[0.5,3.5;11,3.5;desc;Description of map;'..esc(desc)..']'..
  39. 'button[.5,7.25;2,.75;adv;Advanced]'..
  40. 'tooltip[adv;Set advanced level options.]'..
  41. 'button[3.5,7.25;2,.75;save;Save]'..
  42. 'tooltip[save;Saves values without making the button active.]'..
  43. 'button[6.5,7.25;2,.75;submit;Submit]'..
  44. 'tooltip[submit;Saves values and makes the button active.]'..
  45. 'button_exit[9.5,7.25;2,.75;discard;Unclaim]'..
  46. 'tooltip[discard;Clears all values and unclaims the button.]'
  47. if minetest.check_player_privs(player, {server = true}) then
  48. local i = 2
  49. local ids = owner..'_'..1
  50. local map_id = owner..'_'..2
  51. local owner_length = string.len(owner)
  52. local current_id = string.sub(id, (owner_length+2))
  53. while lobby.savedata.IDs[map_id] do
  54. ids = ids..','..map_id
  55. i = i + 1
  56. map_id = owner..'_'..i
  57. end
  58. formspec = formspec..'label[.5,.75;Map ID:]'..
  59. 'dropdown[1.5,.5;2.25,.5;id;'..ids..';'..current_id..']'
  60. else
  61. formspec = formspec..
  62. 'label[.5,.75;Map ID: '..esc(id)..']'
  63. end
  64. return formspec
  65. end
  66. local function button_create_adv(pos)
  67. local meta = minetest.get_meta(pos)
  68. local owner = meta:get_string('owner')
  69. local id = meta:get_string('id')
  70. local name = meta:get_string('name') or ''
  71. local spos = pos.x ..','.. pos.y ..','.. pos.z
  72. local cooldown = meta:get_int('cooldown') or 20
  73. local chance = meta:get_int('chance') or 100
  74. local damage = meta:get_int('damage') or 100
  75. local formspec =
  76. 'formspec_version[3]'..
  77. 'size[12,8]'..
  78. 'background[-1,-1;14,10;lobby_button_bg.png]'..
  79. 'style_type[textarea;textcolor=#ccddff;border=true]'..
  80. 'label[0.5,.7;Map Name:]'..
  81. 'textarea[3.25,.55;7,.4;;;'..esc(name)..' (by '..owner..')]'..
  82. 'label[0.5,1.1;Map ID:]'..
  83. 'textarea[3.25,.95;7,.4;;;'..esc(id)..']'..
  84. 'field[3,2;2.5,.5;cooldown;Weapon Cooldown:;'..cooldown..']'..
  85. 'field[3,3;2.5,.5;chance;Attack Chance:;'..chance..']'..
  86. 'field[3,4;2.5,.5;damage;Attack Damage:;'..damage..']'..
  87. 'style_type[textarea;textcolor=red;border=true]'..
  88. 'textarea[5.75,1.5;6,6.25;;; Weapon Cooldown:\n'..
  89. 'How many seconds elapse until the Traitor get\'s the weapon back. Must be 20 or more. This number is quarted if the attack is not successful.\n\n'..
  90. ' Attack Chance:\n'..
  91. 'What chance is there that the attack is successful, at 100% all will be, at 0% none will be.\n\n'..
  92. ' Attack Damage: (!!!Not Implemented!!!)\n'..
  93. 'How much damage the player should be dealt in a percentage. (100 they die) Keep in mind players auto-heal so setting this low may make it impossible for a traitor to ever win.\n\n'..
  94. ' Weapon Selection:\n'..
  95. 'Hover the weapon options to see the different range, and put the weapon you want for the level in the inventory slot to the left.]'..
  96. 'label[0.5,1.75;Weapons List:]'..
  97. 'label[3,5.25;Selected Weapon:]'..
  98. 'list[detached:weapons_list;main;.5,2;2,4;]'..
  99. 'list[nodemeta:'..spos..';weapon;3.25,5.75;1,1;]'..
  100. 'button[.5,7.25;2,.75;back;Back]'..
  101. 'tooltip[back;Takes you back to the previous menu.]'
  102. return formspec
  103. end
  104. local function button_display(pos)
  105. local meta = minetest.get_meta(pos)
  106. local owner = meta:get_string('owner')
  107. local id = meta:get_string('id')
  108. local name = meta:get_string('name')
  109. local player_count = meta:get_int('player_count') or 3
  110. local xp = meta:get_int('xp') or 50
  111. local pos = meta:get_string('pos')
  112. local desc = meta:get_string('desc')
  113. local cooldown = meta:get_int('cooldown') or 20
  114. local chance = meta:get_int('chance') or 100
  115. local formspec =
  116. 'formspec_version[3]'..
  117. 'size[12,8]'..
  118. 'background[-1,-1;14,10;lobby_button_bg.png]'..
  119. 'image_button[10.5,.5;1,1;lobby_report_icon.png;report;;;false]'..
  120. 'tooltip[report;Report this level as incomplete.]'..
  121. 'style_type[textarea;textcolor=#ccddff;border=true]'..
  122. 'label[0.5,.7;Map Name:]'..
  123. 'textarea[3.25,.55;7,.4;;;'..esc(name)..' (by '..owner..')]'..
  124. 'label[0.5,1.1;Map ID:]'..
  125. 'textarea[3.25,.95;7,.4;;;'..esc(id)..']'..
  126. 'label[0.5,1.5;Req. # of Players:]'..
  127. 'textarea[3.25,1.35;2,.4;;;'..esc(player_count)..']'..
  128. 'label[0.5,1.9;Req. XP:]'..
  129. 'textarea[3.25,1.75;2,.4;;;'..esc(xp)..']'..
  130. 'label[5,1.5;Weapon Cooldown:]'..
  131. 'textarea[7.5,1.35;2,.4;;;'..esc(cooldown)..']'..
  132. 'label[5,1.9;Attack Chance:]'..
  133. 'textarea[7.5,1.75;2,.4;;;'..esc(chance)..'%]'..
  134. 'label[0.5,2.5;Description:]'..
  135. 'textarea[0.5,2.75;11,2.75;;;'..esc(desc)..']'..
  136. 'style_type[textarea;textcolor=#999999]'..
  137. 'textarea[0.5,6.4;9,1.1;;;Sneak punch to visit without starting a game. Return with /lobby.\n'..
  138. 'Be sure all interested parties are standing within three nodes of the button before punching.]'..
  139. 'button[10,6.75;1.5,0.75;stats;Stats]'
  140. return formspec
  141. end
  142. local function button_claim(pos)
  143. local formspec =
  144. 'formspec_version[3]'..
  145. 'size[12,8]'..
  146. 'background[-1,-1;14,10;lobby_button_bg.png]'..
  147. 'label[4.5,1;Claim this button (15XP)]'..
  148. 'button_exit[4,4;4,1;claim;Claim This Button]'
  149. return formspec
  150. end
  151. local function button_save(name, pos, fields, map_id)
  152. local meta = minetest.get_meta(pos)
  153. meta:set_string('infotext', fields.name)
  154. meta:set_string('name', fields.name)
  155. meta:set_int('player_count', fields.player_count)
  156. meta:set_int('xp', fields.xp)
  157. meta:set_string('pos', fields.pos)
  158. meta:set_string('desc', fields.desc)
  159. meta:set_string('builders', fields.builders)
  160. meta:set_string('id', map_id)
  161. local dist = tonumber(minetest.settings:get("map_generation_limit") or 31000)
  162. local x, y, z = string.match(fields.pos, "^(-?%d+),(-?%d+),(-?%d+)$")
  163. local pos_x = tonumber(x)
  164. local pos_y = tonumber(y)
  165. local pos_z = tonumber(z)
  166. local saveable = 0
  167. if fields.name == '' then
  168. minetest.chat_send_player(name, 'A name is required. You can always change it later')
  169. saveable = 1
  170. end
  171. if pos_x > dist or pos_x < -dist or pos_y > dist or pos_y < -dist or pos_z > dist or pos_z < -dist then
  172. minetest.chat_send_player(name, 'Double check your spawn pos, values seem to be invalid.')
  173. saveable = 1
  174. end
  175. if not lobby.is_integer(fields.player_count) then
  176. minetest.chat_send_player(name, 'An Integer is a whole number, your required player count is not.')
  177. saveable = 1
  178. end
  179. if not lobby.is_integer(fields.xp) then
  180. minetest.chat_send_player(name, 'An Integer is a whole number, your required XP amount is not.')
  181. saveable = 1
  182. end
  183. if saveable == 0 then
  184. local owner = meta:get_string('owner')
  185. local data = lobby.savedata.data[map_id] or {}
  186. data.builders = fields.builders
  187. data.description = fields.desc
  188. data.level_pos = {x = pos_x, y = pos_y+1, z = pos_z}
  189. data.map_name = fields.name
  190. data.owner_name = owner
  191. data.required_players = math.max(fields.player_count, 3)
  192. data.xp = math.max(tonumber(fields.xp),1)
  193. lobby.savedata.data[map_id] = data
  194. lobby.savedata.name_2_id[fields.name] = map_id
  195. lobby.savedata.id_2_name[map_id] = fields.name
  196. lobby.savedata.IDs[map_id] = true
  197. lobby.save()
  198. return true
  199. end
  200. end
  201. minetest.register_node('lobby:button_0', {
  202. description = 'Unconfigured Button',
  203. tiles = {'lobby_button_0.png'},
  204. groups = {breakable=1, not_in_creative_inventory=1},
  205. light_source = 5,
  206. after_place_node = function(pos, placer)
  207. local meta = minetest.get_meta(pos)
  208. local inv = meta:get_inventory()
  209. inv:set_size('weapon', 1)
  210. meta:set_string('infotext', 'Unconfigured/Unclaimed button')
  211. meta:set_string('name', '')
  212. meta:set_int('player_count', 3)
  213. meta:set_int('xp', 50)
  214. meta:set_int('chance', 100)
  215. meta:set_int('cooldown', 20)
  216. meta:set_string('pos', '')
  217. meta:set_string('desc', '')
  218. meta:set_string('builders', '')
  219. meta:set_string('solo', 'true')
  220. end,
  221. on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
  222. local player_name = clicker:get_player_name()
  223. lobby.button_pos[player_name] = pos
  224. local meta = minetest.get_meta(pos)
  225. local owner = meta:get_string('owner')
  226. local id = meta:get_string('id')
  227. if owner == '' then
  228. minetest.show_formspec(player_name, 'lobby:button_claim', button_claim(pos))
  229. elseif owner == player_name or minetest.check_player_privs(clicker, {server = true}) then
  230. minetest.show_formspec(player_name, 'lobby:button_create', button_create(pos, clicker))
  231. else
  232. minetest.show_formspec(player_name, 'lobby:button_display', button_display(pos))
  233. lobby.stat[player_name] = id
  234. end
  235. end,
  236. on_punch = function(pos, node, puncher, pointed_thing)
  237. local meta = minetest.get_meta(pos)
  238. local owner = meta:get_string('owner')
  239. local loc = meta:get_string('pos')
  240. local pos = minetest.string_to_pos(loc)
  241. local name = puncher:get_player_name()
  242. local map_id = meta:get_string('id')
  243. local builders = meta:get_string('builders')
  244. local player_attributes = puncher:get_meta()
  245. if name == owner then
  246. puncher:set_pos(pos)
  247. minetest.chat_send_player(name, 'Taking you to the level. Return to the lobby with /spawn')
  248. player_attributes:set_string('mode', 'builder')
  249. lobby.game[name] = map_id..'_builder'
  250. elseif minetest.check_player_privs(name, { creative = true }) and puncher:get_player_control().sneak and string.find(builders, name) then
  251. puncher:set_pos(pos)
  252. minetest.chat_send_player(name, 'Taking you to the level. Return to the lobby with /spawn')
  253. player_attributes:set_string('mode', 'builder')
  254. lobby.game[name] = map_id..'_builder'
  255. end
  256. end,
  257. })
  258. minetest.register_node('lobby:button_1', {
  259. description = 'Configured Button',
  260. tiles = {'lobby_button_1.png'},
  261. groups = {not_in_creative_inventory=1},
  262. drop = 'lobby:button_0',
  263. light_source = 14,
  264. on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
  265. local meta = minetest.get_meta(pos)
  266. local id = meta:get_string('id')
  267. local item = itemstack:get_name()
  268. local player_name = clicker:get_player_name()
  269. local owner = meta:get_string('owner')
  270. if item == 'creative:tool_breaking' or item == 'tasks:configurator' then
  271. if owner == player_name or minetest.check_player_privs(clicker, {server = true}) then
  272. minetest.swap_node(pos, {name = 'lobby:button_0'})
  273. end
  274. else
  275. minetest.show_formspec(player_name, 'lobby:button_display', button_display(pos))
  276. lobby.stat[player_name] = id
  277. end
  278. end,
  279. on_punch = function(pos, node, puncher, pointed_thing)
  280. local name = puncher:get_player_name()
  281. local meta = minetest.get_meta(pos)
  282. local map_id = meta:get_string('id')
  283. local game_data = lobby.savedata.data[map_id]
  284. local game_pos = game_data['level_pos']
  285. local builders = meta:get_string('builders')
  286. local player_attributes = puncher:get_meta()
  287. if minetest.check_player_privs(name, { creative = true }) and puncher:get_player_control().sneak and string.find(builders, name) then
  288. puncher:set_pos({x=game_pos.x+(math.random(-2,2)),y=game_pos.y+2,z=game_pos.z+(math.random(-2,2))})
  289. minetest.chat_send_player(name, 'Taking you to the level. Return to the lobby with /spawn')
  290. player_attributes:set_string('mode', 'builder')
  291. lobby.game[name] = map_id..'_builder'
  292. else
  293. local needed_players = game_data['required_players']
  294. local objs = minetest.get_objects_inside_radius(pos, 3)
  295. local player_count = 0
  296. local map_players = {}
  297. for _, obj in pairs(objs) do
  298. if obj:is_player() then
  299. player_count = player_count + 1
  300. local player_name = obj:get_player_name()
  301. table.insert(map_players, player_name)
  302. end
  303. end
  304. if player_count >= needed_players then
  305. if lobby.map[map_id] == 0 or lobby.map[map_id] == nil then
  306. minetest.chat_send_player(name, 'you can start the game!')
  307. lobby.play_time[map_id] = minetest.get_us_time()
  308. minetest.log('action', name..' just started a game on '..map_id)
  309. lobby.map[map_id] = player_count
  310. lobby.update_stats(map_id, 'player', '', player_count)
  311. local traitor = math.random(1, player_count)
  312. local inv = meta:get_inventory()
  313. local weapon = inv:get_stack('weapon', 1):get_name()
  314. print (weapon)
  315. if weapon == '' then
  316. weapon = 'lobby:shank'
  317. end
  318. lobby.xp[map_id] = 0
  319. lobby.votes[map_id] = 0
  320. lobby.corpses[map_id] = {}
  321. lobby.sabotage[map_id] = false
  322. lobby.sabotage_level[map_id] = 5
  323. sabotage.timer[map_id] = 0
  324. for i=1,player_count do
  325. minetest.chat_send_player(map_players[i], 'Hold tight, loading the level.')
  326. local player = minetest.get_player_by_name(map_players[i])
  327. local player_attributes = player:get_meta()
  328. player_attributes:set_string('voting', 'false')
  329. player_attributes:set_string('mode', 'player')
  330. lobby.voted[map_players[i]] = true
  331. if i == traitor then
  332. local cooldown = 20
  333. local data = lobby.savedata.data[map_id]
  334. if data and data.cooldown then
  335. cooldown = data.cooldown * 2
  336. end
  337. minetest.chat_send_player(map_players[i], 'You\'re the imposter. Try to kill all the other players.')
  338. minetest.chat_send_player(map_players[i], 'You\'ll get a weapon in a '..cooldown..' seconds.')
  339. lobby.traitors[map_id] = map_players[i]
  340. local player = minetest.get_player_by_name(map_players[i])
  341. local player_inv = player:get_inventory()
  342. minetest.after(cooldown, function()
  343. player_inv:add_item('main', weapon)
  344. end)
  345. player_attributes:set_string('mode', 'traitor')
  346. end
  347. local privs = minetest.get_player_privs(map_players[i])
  348. local player_inv = player:get_inventory()
  349. player_inv:set_list('main', {})
  350. player_inv:set_size('main', 16)
  351. lobby.game[map_players[i]] = map_id
  352. player:set_pos({x=game_pos.x+(math.random(-2,2)),y=game_pos.y,z=game_pos.z+(math.random(-2,2))})
  353. privs.fly = nil
  354. privs.fast = nil
  355. privs.creative = nil
  356. privs.areas = nil
  357. minetest.set_player_privs(map_players[i], privs)
  358. end
  359. lobby.voting_formspec(map_id, true)
  360. else
  361. minetest.chat_send_player(puncher:get_player_name(), 'You can\'t join an in progress game.\nYou can possibly play solo by sneak+punching.')
  362. end
  363. elseif puncher:get_player_control().sneak then
  364. local solo = meta:get_string('solo')
  365. if solo == 'true' then
  366. lobby.update_stats(map_id, 'solo')
  367. local name = puncher:get_player_name()
  368. puncher:set_nametag_attributes({
  369. color = {a = 0, r = 255, g = 255, b = 255}
  370. })
  371. puncher:set_properties({visual_size = {x = 0, y = 0}, collisionbox = {-0.3, 0.0, -0.3, 0.3, 1.7, 0.3}})
  372. lobby.builder_to_player(puncher)
  373. puncher:set_pos(game_pos)
  374. lobby.game[name] = map_id..'_solo'
  375. minetest.chat_send_player(name, 'Travel back to the lobby with the /lobby chat command.')
  376. else
  377. minetest.chat_send_player(name, 'Sorry this level is not able to be played solo.')
  378. end
  379. else
  380. minetest.chat_send_player(puncher:get_player_name(), 'Maybe not enough players? Right click the button for more information.')
  381. end
  382. end
  383. end,
  384. })
  385. minetest.register_on_player_receive_fields(function(player, formname, fields)
  386. if formname == 'lobby:button_display' then
  387. local name = player:get_player_name()
  388. local map_id = lobby.stat[name]
  389. print (map_id)
  390. if fields.stats then
  391. minetest.show_formspec(name, 'lobby:stats', lobby.retrieve_stats(map_id))
  392. elseif fields.report then
  393. if not lobby.is_builder(player) then
  394. minetest.chat_send_player(name, 'Sorry, only builders can report levels.')
  395. else
  396. minetest.show_formspec(name, 'lobby:report', lobby.report_level(map_id))
  397. end
  398. end
  399. elseif formname == 'lobby:report' then
  400. local name = player:get_player_name()
  401. local map_id = lobby.stat[name]
  402. if fields.save then
  403. local reason = fields.reason
  404. if reason then
  405. local input = fields.input
  406. minetest.chat_send_player(name, 'Thanks for your report')
  407. local map_name = lobby.savedata.id_2_name[map_id] or map_id
  408. local data = lobby.savedata.data[map_id]
  409. local map_owner = data.owner_name
  410. local src = 'system'
  411. local dst = 'Admin, '..map_owner..', '..name
  412. local subject = name..' reported '..reason..' on '..map_name
  413. local body = input..'\n\n\nThis is an automated message, please do not respond.'
  414. mail.send(src, dst, subject, body)
  415. else
  416. minetest.chat_send_player(name, 'You need to select a reason.')
  417. end
  418. end
  419. elseif formname == 'lobby:button_claim' then
  420. if fields.claim then
  421. local name = player:get_player_name()
  422. if lobby.is_builder(player) then
  423. if lobby.take_xp(player, 15) then
  424. local pos = lobby.button_pos[name]
  425. local meta = minetest.get_meta(pos)
  426. minetest.show_formspec(name, 'lobby:get_started', lobby.getting_started)
  427. meta:set_string('owner', name)
  428. local map_id = lobby.create_id(name)
  429. meta:set_string('id', map_id)
  430. local pos_string = random_pos()
  431. local pos = minetest.string_to_pos(pos_string)
  432. local run = true
  433. while run do
  434. if not minetest.is_protected(pos, player) and run then
  435. minetest.load_area(pos)
  436. meta:set_string('pos', pos_string)
  437. worldedit.cube(pos, 5, 1, 5, 'color:grey_blocks', false)
  438. minetest.set_node(pos, {name = 'lights:block_4'})
  439. run = false
  440. end
  441. end
  442. end
  443. else
  444. minetest.chat_send_player(name, 'You need more XP!')
  445. end
  446. end
  447. elseif formname == 'lobby:button_create' then
  448. local name = player:get_player_name()
  449. local pos = lobby.button_pos[name]
  450. local meta = minetest.get_meta(pos)
  451. local map_id = meta:get_string('id')
  452. local owner = meta:get_string('owner')
  453. if owner == name or minetest.check_player_privs(player, {server = true}) then
  454. if fields.id and fields.id ~= map_id then
  455. local stats = lobby.savedata.stats[map_id]
  456. if not stats then
  457. lobby.savedata.IDs[map_id] = nil
  458. lobby.savedata.data[map_id] = nil
  459. lobby.savedata.id_2_name[map_id] = nil
  460. end
  461. local map_id = fields.id
  462. local data = lobby.savedata.data[map_id]
  463. if data and data.map_name then
  464. meta:set_string('id', map_id)
  465. minetest.show_formspec(name, 'lobby:button_create', button_create(pos, player))
  466. else
  467. minetest.chat_send_player(name, 'That ID never had any data saved.')
  468. end
  469. end
  470. if not string.find(map_id, owner) then --Using old player assigned IDs
  471. local map_id_new = lobby.create_id(owner)
  472. lobby.savedata.IDs[map_id_new] = true
  473. meta:set_string('id', map_id_new)
  474. if lobby.savedata.stats[map_id] then
  475. local stats = lobby.savedata.stats[map_id] or {}
  476. local stats_new = {}
  477. stats_new.solo_play = stats.solo_play or 0
  478. stats_new.multi_play = stats.multi_play or 0
  479. stats_new.winner_traitor = stats.winner_traitor or 0
  480. stats_new.winner_team = stats.winner_team or 0
  481. stats_new.player_count = stats.player_count or 0
  482. stats_new.max_players = stats.max_players or 0
  483. lobby.savedata.stats[map_id_new] = stats_new
  484. lobby.savedata.IDs[map_id] = nil
  485. lobby.savedata.stats[map_id] = nil
  486. lobby.savedata.data[map_id] = nil
  487. end
  488. map_id = map_id_new
  489. end
  490. if fields.solo then
  491. meta:set_string('solo', fields.solo)
  492. elseif fields.adv then
  493. if button_save(name, pos, fields, map_id) then
  494. minetest.show_formspec(name, 'lobby:button_create_adv', button_create_adv(pos))
  495. end
  496. elseif fields.save then
  497. if button_save(name, pos, fields, map_id) then
  498. minetest.close_formspec(name, 'lobby:button_create')
  499. end
  500. elseif fields.submit then
  501. if button_save(name, pos, fields, map_id) then
  502. minetest.swap_node(pos, {name = 'lobby:button_1'})
  503. minetest.close_formspec(name, 'lobby:button_create')
  504. end
  505. elseif fields.discard then
  506. meta:set_string('owner', '')
  507. meta:set_string('infotext', 'Unconfigured/Unclaimed Button')
  508. meta:set_string('id', '')
  509. meta:set_string('name', '')
  510. meta:set_int('player_count', '3')
  511. meta:set_int('xp', '50')
  512. meta:set_string('pos', '')
  513. meta:set_string('desc', '')
  514. meta:set_string('builders', '')
  515. meta:set_string('solo', 'true')
  516. local stats = lobby.savedata.stats[map_id]
  517. if not stats then
  518. lobby.savedata.IDs[map_id] = nil
  519. lobby.savedata.data[map_id] = nil
  520. lobby.savedata.id_2_name[map_id] = nil
  521. end
  522. lobby.give_xp(player, 15)
  523. end
  524. end
  525. elseif formname == 'lobby:button_create_adv' then
  526. local name = player:get_player_name()
  527. local pos = lobby.button_pos[name]
  528. if fields.back then
  529. local cooldown = fields.cooldown
  530. local chance = fields.chance
  531. if lobby.is_integer(cooldown) and lobby.is_integer(chance) then
  532. cooldown = math.max(cooldown, 20)
  533. chance = math.max(0, math.min(100, chance))
  534. local meta = minetest.get_meta(pos)
  535. local map_id = meta:get_string('id')
  536. meta:set_int('cooldown', cooldown)
  537. meta:set_int('chance', chance)
  538. local data = lobby.savedata.data[map_id]
  539. data.cooldown = cooldown
  540. data.chance = chance
  541. lobby.savedata.data[map_id] = data
  542. lobby.save()
  543. minetest.show_formspec(name, 'lobby:button_create', button_create(pos, player))
  544. else
  545. minetest.chat_send_player(name, 'Uhhh, so you need a number, specifically an integer for the weapon cooldown.')
  546. end
  547. end
  548. end
  549. end)
  550. minetest.register_lbm({
  551. label = 'Frees abandoned buttons',
  552. name = 'lobby:clean_buttons',
  553. run_at_every_load = true,
  554. nodenames = {'lobby:button_0'},
  555. action = function(pos, node)
  556. local meta = minetest.get_meta(pos)
  557. local owner = meta:get_string('owner')
  558. local pauth = core.get_auth_handler().get_auth(owner)
  559. if pauth and pauth.last_login and pauth.last_login ~= -1 then
  560. local diff = math.ceil(os.difftime(pauth.last_login, os.time())/86400)
  561. if diff < -60 then
  562. local name = meta:get_string('name')
  563. minetest.log('info', 'Unclaimed '..owner..'\'s button at '..minetest.pos_to_string(pos)..' due to abandonment.')
  564. meta:set_string('owner', '')
  565. meta:set_string('infotext', 'Unconfigured/Unclaimed Button')
  566. meta:set_string('id', '')
  567. meta:set_string('name', '')
  568. meta:set_int('player_count', '3')
  569. meta:set_int('xp', '50')
  570. meta:set_string('pos', '')
  571. meta:set_string('desc', '')
  572. meta:set_string('builders', '')
  573. meta:set_string('solo', 'true')
  574. local src = 'system'
  575. local dst = 'Admin, '..owner
  576. local subject = 'Abandoned level button cleared'
  577. local body = 'This is just to let you know that one of your '..name..' buttons was unclaimed due to inactivity. You can claim a new button and ask an Admin to repopulate it with the old data.\n\n\nThis is an automated message, please do not respond.'
  578. mail.send(src, dst, subject, body)
  579. end
  580. end
  581. end
  582. })