minetest fishing mod
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

826 lines
28KB

  1. local S = fishing_setting.func.S
  2. --function save settings
  3. function fishing_setting.func.save()
  4. local input, err = io.open(fishing_setting.file_settings, "w")
  5. if input then
  6. input:write(minetest.serialize(fishing_setting.settings))
  7. input:close()
  8. else
  9. minetest.log("error", "open(" .. fishing_setting.file_settings .. ", 'w') failed: " .. err)
  10. end
  11. end
  12. function fishing_setting.func.set_settings(new_settings, settings)
  13. if settings["message"] ~= nil then
  14. new_settings["message"] = settings["message"]
  15. end
  16. if settings["worm_is_mob"] ~= nil then
  17. new_settings["worm_is_mob"] = settings["worm_is_mob"]
  18. end
  19. if settings["worm_chance"] ~= nil then
  20. new_settings["worm_chance"] = settings["worm_chance"]
  21. end
  22. if settings["new_worm_source"] ~= nil then
  23. new_settings["new_worm_source"] = settings["new_worm_source"]
  24. end
  25. if settings["wear_out"] ~= nil then
  26. new_settings["wear_out"] = settings["wear_out"]
  27. end
  28. if settings["bobber_view_range"] ~= nil then
  29. new_settings["bobber_view_range"] = settings["bobber_view_range"]
  30. end
  31. if settings["simple_deco_fishing_pole"] ~= nil then
  32. new_settings["simple_deco_fishing_pole"] = settings["simple_deco_fishing_pole"]
  33. end
  34. if settings["fish_chance"] ~= nil then
  35. new_settings["fish_chance"] = settings["fish_chance"]
  36. end
  37. if settings["treasure_chance"] ~= nil then
  38. new_settings["treasure_chance"] = settings["treasure_chance"]
  39. end
  40. if settings["shark_chance"] ~= nil then
  41. new_settings["shark_chance"] = settings["shark_chance"]
  42. end
  43. if settings["treasure_enable"] ~= nil then
  44. new_settings["treasure_enable"] = settings["treasure_enable"]
  45. end
  46. if settings["escape_chance"] ~= nil then
  47. new_settings["escape_chance"] = settings["escape_chance"]
  48. end
  49. end
  50. --function load settings from file
  51. function fishing_setting.func.load()
  52. local file = io.open(fishing_setting.file_settings, "r")
  53. local settings = {}
  54. if file then
  55. settings = minetest.deserialize(file:read("*all"))
  56. file:close()
  57. if settings and type(settings) == "table" then
  58. fishing_setting.func.set_settings(fishing_setting.settings, settings)
  59. end
  60. end
  61. end
  62. --function return wear tool value (old or new)
  63. function fishing_setting.func.wear_value(wear)
  64. local used = 0
  65. if wear == "random" then
  66. used = (2000*(math.random(20, 29)))
  67. elseif wear == "randomtools" then
  68. used = (65535/(30-(math.random(15, 29))))
  69. end
  70. return used
  71. end
  72. -- function return table where mods actived
  73. function fishing_setting.func.ignore_mod(list)
  74. local listOk = {}
  75. for i,v in ipairs(list) do
  76. if minetest.get_modpath(v[1]) ~= nil then
  77. table.insert(listOk, v)
  78. end
  79. end
  80. return listOk
  81. end
  82. --function random hungry by bait type
  83. function fishing_setting.func.hungry_random()
  84. for i,a in pairs(fishing_setting.baits) do
  85. if string.find(i, "fishing:") ~= nil then
  86. fishing_setting.baits[i]["hungry"] = math.random(15, 80)
  87. end
  88. end
  89. -- to mobs_fish modpack
  90. if fishing_setting.baits["mobs_fish:clownfish"] then
  91. fishing_setting.baits["mobs_fish:clownfish"]["hungry"] = fishing_setting.baits["fishing:clownfish_raw"]["hungry"]
  92. end
  93. if fishing_setting.baits["mobs_fish:tropical"] then
  94. fishing_setting.baits["mobs_fish:tropical"]["hungry"] = fishing_setting.baits["fishing:exoticfish_raw"]["hungry"]
  95. end
  96. --change hungry after random time, min 0h30, max 6h00
  97. minetest.after(math.random(1, 12)*1800, fishing_setting.func.hungry_random )
  98. end
  99. function fishing_setting.func.get_loot()
  100. if #fishing_setting.prizes["stuff"] > 0 then
  101. local c = math.random(1, fishing_setting.prizes["stuff"][#fishing_setting.prizes["stuff"]][5])
  102. for i in pairs(fishing_setting.prizes["stuff"]) do
  103. local min = fishing_setting.prizes["stuff"][i][5]
  104. local chance = fishing_setting.prizes["stuff"][i][6]
  105. local max = min + chance
  106. if c <= max and c >= min then
  107. return fishing_setting.prizes["stuff"][i]
  108. end
  109. end
  110. end
  111. return ""
  112. end
  113. -- Show notification when a player catches treasure
  114. function fishing_setting.func.notify(f_name, treasure)
  115. local title = S("Lucky %s, he caught the treasure, %s!"):format(f_name, treasure[4])
  116. for _, player in ipairs(minetest.get_connected_players()) do
  117. local player_name = player:get_player_name()
  118. if player_name == f_name then
  119. minetest.chat_send_player(player_name, S("You caught the treasure, %s!"):format(treasure[4]))
  120. else
  121. minetest.chat_send_player(player_name, title)
  122. end
  123. end
  124. end
  125. -- Menu: fishing configuration
  126. fishing_setting.func.on_show_settings = function(player_name)
  127. if not fishing_setting.tmp_setting then
  128. fishing_setting.tmp_setting = {}
  129. fishing_setting.func.set_settings(fishing_setting.tmp_setting, fishing_setting.settings)
  130. end
  131. local formspec = "size[10.8,9]label[4,0;"..S("Fishing configuration").."]"..
  132. -- Fish chance
  133. "label[1.6,0.5;"..S("Fish chance").."]"..
  134. "button[0,1;1,1;cfish;-1]"..
  135. "button[1,1;1,1;cfish;-10]"..
  136. "label[2.1,1.2;"..tostring(fishing_setting.tmp_setting["fish_chance"]).."]"..
  137. "button[2.7,1;1,1;cfish;+10]"..
  138. "button[3.7,1;1,1;cfish;+1]"..
  139. -- Shark chance
  140. "label[1.5,2;"..S("Shark chance").."]"..
  141. "button[0,2.5;1,1;cshark;-1]"..
  142. "button[1,2.5;1,1;cshark;-10]"..
  143. "label[2.1,2.7;"..tostring(fishing_setting.tmp_setting["shark_chance"]).."]"..
  144. "button[2.7,2.5;1,1;cshark;+10]"..
  145. "button[3.7,2.5;1,1;cshark;+1]"..
  146. -- Treasure chance
  147. "label[1.5,3.5;"..S("Treasure chance").."]"..
  148. "button[0,4.;1,1;ctreasure;-1]"..
  149. "button[1,4;1,1;ctreasure;-10]"..
  150. "label[2.1,4.2;"..tostring(fishing_setting.tmp_setting["treasure_chance"]).."]"..
  151. "button[2.7,4;1,1;ctreasure;+10]"..
  152. "button[3.7,4;1,1;ctreasure;+1]"..
  153. -- Worm chance
  154. "label[7.5,0.5;"..S("Worm chance").."]"..
  155. "button[6,1;1,1;cworm;-1]"..
  156. "button[7,1;1,1;cworm;-10]"..
  157. "label[8.1,1.2;"..tostring(fishing_setting.tmp_setting["worm_chance"]).."]"..
  158. "button[8.7,1;1,1;cworm;+10]"..
  159. "button[9.7,1;1,1;cworm;+1]"..
  160. -- Escape chance
  161. "label[7.4,2;"..S("Escape chance").."]"..
  162. "button[6,2.5;1,1;cescape;-1]"..
  163. "button[7,2.5;1,1;cescape;-10]"..
  164. "label[8.1,2.7;"..tostring(fishing_setting.tmp_setting["escape_chance"]).."]"..
  165. "button[8.7,2.5;1,1;cescape;+10]"..
  166. "button[9.7,2.5;1,1;cescape;+1]"..
  167. -- Bobber view range
  168. "label[7.2,3.5;"..S("Bobber view range").."]"..
  169. "button[7,4;1,1;bvrange;-1]"..
  170. "label[8.1,4.2;"..tostring(fishing_setting.tmp_setting["bobber_view_range"]).."]"..
  171. "button[8.7,4;1,1;bvrange;+1]"..
  172. -- Messages display
  173. "label[0,5.7;"..S("Display messages in chat").."]"..
  174. "button[3.7,5.5;1,1;dmessages;"..tostring(fishing_setting.tmp_setting["message"]).."]"..
  175. --poledeco
  176. "label[0,6.5;"..S("Simple pole deco").."]"..
  177. "button[3.7,6.3;1,1;poledeco;"..tostring(fishing_setting.tmp_setting["simple_deco_fishing_pole"]).."]"..
  178. -- Wearout
  179. "label[0,7.3;"..S("Poles wearout").."]"..
  180. "button[3.7,7.1;1,1;wearout;"..tostring(fishing_setting.tmp_setting["wear_out"]).."]"..
  181. -- TREASURE_ENABLE
  182. "label[6,5.7;"..S("Enable treasure").."]"..
  183. "button[9.7,5.5;1,1;treasureenable;"..tostring(fishing_setting.tmp_setting["treasure_enable"]).."]"..
  184. -- NEW_WORM_SOURCE
  185. "label[6,6.5;"..S("New worm source (reboot)").."]"..
  186. "button[9.7,6.3;1,1;newworm;"..tostring(fishing_setting.tmp_setting["new_worm_source"]).."]"..
  187. -- WORM_IS_MOB
  188. "label[6,7.3;"..S("Worm is a mob (reboot)").."]"..
  189. "button[9.7,7.1;1,1;wormmob;"..tostring(fishing_setting.tmp_setting["worm_is_mob"]).."]"..
  190. "button_exit[0,8.2;1.5,1;abort;"..S("Abort").."]"..
  191. "button_exit[9.2,8.2;1.5,1;save;"..S("OK").."]"
  192. minetest.show_formspec(player_name, "fishing:settings", formspec)
  193. end
  194. local inc = function(value, field, min, max)
  195. local inc = tonumber(field)
  196. local v = value
  197. if inc ~= nil then
  198. v = value + inc
  199. end
  200. if v > max then
  201. return max
  202. end
  203. if v < min then
  204. return min
  205. end
  206. return v
  207. end
  208. local bool = function(field)
  209. return field ~= "true"
  210. end
  211. minetest.register_on_player_receive_fields(function(player, formname, fields)
  212. local player_name = player:get_player_name()
  213. if not player_name then return end
  214. if formname == "fishing:settings" then
  215. if fields["save"] then
  216. fishing_setting.func.set_settings(fishing_setting.settings, fishing_setting.tmp_setting)
  217. fishing_setting.func.save()
  218. fishing_setting.tmp_setting = nil
  219. return
  220. elseif fields["quit"] or fields["abort"] then
  221. fishing_setting.tmp_setting = nil
  222. return
  223. elseif fields["cfish"] then
  224. fishing_setting.tmp_setting["fish_chance"] = inc(fishing_setting.tmp_setting["fish_chance"], fields["cfish"], 1, 100)
  225. elseif fields["cshark"] then
  226. fishing_setting.tmp_setting["shark_chance"] = inc(fishing_setting.tmp_setting["shark_chance"], fields["cshark"], 1, 100)
  227. elseif fields["ctreasure"] then
  228. fishing_setting.tmp_setting["treasure_chance"] = inc(fishing_setting.tmp_setting["treasure_chance"], fields["ctreasure"], 1, 100)
  229. elseif fields["bvrange"] then
  230. fishing_setting.tmp_setting["bobber_view_range"] = inc(fishing_setting.tmp_setting["bobber_view_range"], fields["bvrange"], 4, 20)
  231. elseif fields["cworm"] then
  232. fishing_setting.tmp_setting["worm_chance"] = inc(fishing_setting.tmp_setting["worm_chance"], fields["cworm"], 1, 100)
  233. elseif fields["cescape"] then
  234. fishing_setting.tmp_setting["escape_chance"] = inc(fishing_setting.tmp_setting["escape_chance"], fields["cescape"], 1, 50)
  235. elseif fields["dmessages"] then
  236. fishing_setting.tmp_setting["message"] = bool(fields["dmessages"])
  237. elseif fields["poledeco"] then
  238. fishing_setting.tmp_setting["simple_deco_fishing_pole"] = bool(fields["poledeco"])
  239. elseif fields["wearout"] then
  240. fishing_setting.tmp_setting["wear_out"] = bool(fields["wearout"])
  241. elseif fields["treasureenable"] then
  242. fishing_setting.tmp_setting["treasure_enable"] = bool(fields["treasureenable"])
  243. elseif fields["newworm"] then
  244. fishing_setting.tmp_setting["new_worm_source"] = bool(fields["newworm"])
  245. elseif fields["wormmob"] then
  246. fishing_setting.tmp_setting["worm_is_mob"] = bool(fields["wormmob"])
  247. else
  248. return
  249. end
  250. fishing_setting.func.on_show_settings(player_name)
  251. elseif formname == "fishing:admin_conf" then
  252. if fields["classement"] then
  253. local formspec = fishing_setting.func.get_stat()
  254. minetest.show_formspec(player_name, "fishing:classement", formspec)
  255. elseif fields["contest"] then
  256. fishing_setting.func.on_show_settings_contest(player_name)
  257. elseif fields["configuration"] then
  258. fishing_setting.func.on_show_settings(player_name)
  259. elseif fields["hungerinfo"] then
  260. fishing_setting.func.get_hunger_info(player_name)
  261. end
  262. end
  263. end)
  264. --function load settings from file
  265. function fishing_setting.func.load_trophies()
  266. local file = io.open(fishing_setting.file_trophies, "r")
  267. fishing_setting.trophies = {}
  268. if file then
  269. fishing_setting.trophies = minetest.deserialize(file:read("*all"))
  270. file:close()
  271. if not fishing_setting.trophies or type(fishing_setting.trophies) ~= "table" then
  272. fishing_setting.trophies = {}
  273. end
  274. end
  275. end
  276. function fishing_setting.func.save_trophies()
  277. local input = io.open(fishing_setting.file_trophies, "w")
  278. if input then
  279. input:write(minetest.serialize(fishing_setting.trophies))
  280. input:close()
  281. else
  282. minetest.log("action","Open failed (mode:w) of " .. fishing_setting.file_trophies)
  283. end
  284. end
  285. minetest.register_on_shutdown(function()
  286. minetest.log("action", "[fishing] Server shuts down. saving trophies table")
  287. fishing_setting.func.save_trophies()
  288. fishing_setting.func.save_contest()
  289. end)
  290. function fishing_setting.func.timetostr(time)
  291. local countdown = time
  292. local answer = ""
  293. if countdown >= 3600 then
  294. local hours = math.floor(countdown / 3600)
  295. countdown = countdown % 3600
  296. answer = hours .. "h"
  297. end
  298. if countdown >= 60 then
  299. local minutes = math.floor(countdown / 60)
  300. countdown = countdown % 60
  301. answer = answer .. minutes .. "m"
  302. else
  303. answer = answer .. "0m"
  304. end
  305. local seconds = countdown
  306. answer = answer .. math.floor(seconds) .. "s"
  307. return answer
  308. end
  309. minetest.register_on_joinplayer(function(player)
  310. local player_name = player:get_player_name()
  311. if fishing_setting.contest["contest"] == true then
  312. minetest.chat_send_player(player_name, S("A fishing contest is in progress. (remaining time %s)"):format(fishing_setting.func.timetostr(fishing_setting.contest["duration"])))
  313. end
  314. end)
  315. function fishing_setting.func.add_to_trophies(player, fish, desc)
  316. local player_name = player:get_player_name()
  317. if not player_name then return end
  318. if string.find(fish, "_raw") ~= nil or fishing_setting.prizes["true_fish"]["little"][fish] or fishing_setting.prizes["true_fish"]["big"][fish] then
  319. if string.find(fish, "_raw") ~= nil then
  320. if fishing_setting.trophies[fish] == nil then
  321. fishing_setting.trophies[fish] = {}
  322. end
  323. fishing_setting.trophies[fish][player_name] = (fishing_setting.trophies[fish][player_name] or 0) + 1
  324. if fishing_setting.trophies[fish][player_name]%100 == 0 then
  325. minetest.chat_send_player(player_name, S("You win a new trophy, you have caught %s " .. fish.."."):format(fishing_setting.trophies[fish][player_name]))
  326. local inv = player:get_inventory()
  327. local name = "fishing:trophy_"..fish
  328. if inv:room_for_item("main", {name=name, count=1, wear=0, metadata=""}) then
  329. inv:add_item("main", {name=name, count=1, wear=0, metadata=""})
  330. else
  331. minetest.spawn_item(player:get_pos(), {name=name, count=1, wear=0, metadata=""})
  332. end
  333. end
  334. end
  335. if fishing_setting.contest["contest"] ~= nil and fishing_setting.contest["contest"] == true then
  336. if fishing_setting.contest["nb_fish"] == nil then
  337. fishing_setting.contest["nb_fish"] = {}
  338. end
  339. fishing_setting.contest["nb_fish"][player_name] = (fishing_setting.contest["nb_fish"][player_name] or 0) + 1
  340. minetest.chat_send_all(S("Yeah, %s caught "..desc):format(player_name))
  341. end
  342. end
  343. end
  344. -- Menu: fishing configuration/contest
  345. fishing_setting.func.on_show_admin_menu = function(player_name)
  346. local formspec = "size[5,5]label[1.7,0;"..S("Fishing Menu").."]"..
  347. "button[0.5,0.5;4,1;classement;"..S("Contest rankings").."]"..
  348. "button[0.5,1.5;4,1;contest;"..S("Contests").."]"..
  349. "button[0.5,2.5;4,1;configuration;"..S("Configuration").."]"..
  350. "button[0.5,3.5;4,1;hungerinfo;"..S("Hunger info").."]"..
  351. "button_exit[1,4.5;3,1;close;"..S("Close").."]"
  352. minetest.show_formspec(player_name, "fishing:admin_conf", formspec)
  353. end
  354. if (minetest.get_modpath("unified_inventory")) then
  355. unified_inventory.register_button("menu_fishing", {
  356. type = "image",
  357. image = "fishing_perch_raw.png",
  358. tooltip = "Fishing Menu Configuration",
  359. action = function(player)
  360. local player_name = player:get_player_name()
  361. if not player_name then return end
  362. if minetest.check_player_privs(player_name, {server=true}) then
  363. fishing_setting.func.on_show_admin_menu(player_name)
  364. else
  365. local formspec = fishing_setting.func.get_stat()
  366. minetest.show_formspec(player_name, "fishing:classement", formspec)
  367. end
  368. end,
  369. })
  370. end
  371. --function save settings
  372. function fishing_setting.func.save_contest()
  373. local input = io.open(fishing_setting.file_contest, "w")
  374. if input then
  375. input:write(minetest.serialize(fishing_setting.contest))
  376. input:close()
  377. else
  378. minetest.log("action","Open failed (mode:w) of " .. fishing_setting.file_contest)
  379. end
  380. end
  381. --function load contest data from file
  382. function fishing_setting.func.load_contest()
  383. local file = io.open(fishing_setting.file_contest, "r")
  384. local settings
  385. fishing_setting.contest = {["contest"] = false, ["duration"] = 3600, ["bobber_nb"] = 4}
  386. if file then
  387. settings = minetest.deserialize(file:read("*all"))
  388. file:close()
  389. if settings ~= nil and type(settings) == "table" then
  390. if settings["contest"] ~= nil then
  391. fishing_setting.contest["contest"] = settings["contest"]
  392. end
  393. if settings["duration"] ~= nil then
  394. fishing_setting.contest["duration"] = settings["duration"]
  395. end
  396. if settings["bobber_nb"] ~= nil then
  397. fishing_setting.contest["bobber_nb"] = settings["bobber_nb"]
  398. end
  399. if settings["nb_fish"] ~= nil then
  400. fishing_setting.contest["nb_fish"] = settings["nb_fish"]
  401. end
  402. end
  403. end
  404. end
  405. function fishing_setting.func.start_contest(duration)
  406. fishing_setting.contest["contest"] = true
  407. fishing_setting.contest["warning_said"] = false
  408. fishing_setting.contest["duration"] = duration
  409. minetest.chat_send_all(S("Attention, Fishing contest start (duration %s)!!!"):format(duration))
  410. minetest.sound_play("fishing_contest_start",{gain=0.8})
  411. fishing_setting.func.save_contest()
  412. fishing_setting.func.tick()
  413. end
  414. function fishing_setting.func.end_contest()
  415. fishing_setting.contest["contest"] = false
  416. fishing_setting.func.save_contest()
  417. minetest.chat_send_all(S("End of fishing contest."))
  418. minetest.sound_play("fishing_contest_end",{gain=0.8})
  419. fishing_setting.func.show_result()
  420. end
  421. --function load planned contest from file
  422. function fishing_setting.func.load_planned()
  423. local file = io.open(fishing_setting.file_planned, "r")
  424. local settings = {}
  425. if file then
  426. settings = minetest.deserialize(file:read("*all"))
  427. file:close()
  428. if settings and type(settings) == "table" then
  429. for i, p in pairs(settings) do
  430. if p["wday"] ~= nil and p["hour"] ~= nil and p["min"] ~= nil and p["duration"] ~= nil then
  431. table.insert(fishing_setting.planned, {["wday"]=p["wday"], ["hour"]=p["hour"], ["min"]=p["min"], ["duration"]=p["duration"]})
  432. end
  433. end
  434. end
  435. end
  436. end
  437. fishing_setting.func.load_planned()
  438. function fishing_setting.func.save_planned()
  439. local input = io.open(fishing_setting.file_planned, "w")
  440. if input then
  441. input:write(minetest.serialize(fishing_setting.planned))
  442. input:close()
  443. else
  444. minetest.log("action","Open failed (mode:w) of " .. fishing_setting.file_planned)
  445. end
  446. end
  447. minetest.register_chatcommand("contest_add", {
  448. params = "Wday Hours Minutes duration(in sec) (ex: 1 15 40 3600)",
  449. description = "Add contest (admin only)",
  450. privs = {server=true},
  451. func = function(player_name, param)
  452. if not player_name then return end
  453. local wday, hour, min, duration = param:match("^(%d+)%s(%d+)%s(%d+)%s(%d+)$")
  454. if ((not wday or not tonumber(wday)) or (not hour or not tonumber(hour)) or (not min and not tonumber(min)) or (not duration or not tonumber(duration))) then
  455. return false, "Invalid usage, see /help contest_add."
  456. end
  457. wday = tonumber(wday)
  458. hour = tonumber(hour)
  459. min = tonumber(min)
  460. duration = tonumber(duration)
  461. if (wday < 0 or wday > 7) then
  462. return false, "Invalid argument wday, 0-7 (0=all 1=Sunday)."
  463. end
  464. if (hour < 0 or hour > 23) then
  465. return false, "Invalid argument hour, 0-23."
  466. end
  467. if (min < 0 or min > 59) then
  468. return false, "Invalid argument minutes, 0-59."
  469. end
  470. if duration < 600 then
  471. duration = 600
  472. elseif duration > 14400 then
  473. duration = 14400
  474. end
  475. table.insert(fishing_setting.planned, {["wday"]=wday, ["hour"]=hour, ["min"]=min, ["duration"]=duration})
  476. fishing_setting.func.save_planned()
  477. return true, ("new contest registered %d %d:%d duration %d."):format(wday, hour, min, duration)
  478. end
  479. })
  480. minetest.register_chatcommand("contest_del", {
  481. params = "List number(show by contest_show command) ",
  482. description = "Delete planned contest(admin only)",
  483. privs = {server=true},
  484. func = function(player_name, param)
  485. if not player_name then return end
  486. local i = tonumber(param)
  487. if not i then
  488. return false, "Invalid usage, see /help contest_del."
  489. end
  490. if i < 1 then
  491. return false, "Invalid usage, see /help contest_del."
  492. end
  493. local c = fishing_setting.planned[i]
  494. if not c then
  495. return false, "Contest no found"
  496. end
  497. table.remove(fishing_setting.planned, i)
  498. fishing_setting.func.save_planned()
  499. return true, "contest deleted"
  500. end
  501. })
  502. minetest.register_chatcommand("contest_show", {
  503. params = "",
  504. description = "Display planned contest(admin only)",
  505. privs = {server=true},
  506. func = function(player_name, param)
  507. if not player_name then return end
  508. local text = "Registered contest:\n"
  509. for i, plan in pairs(fishing_setting.planned) do
  510. text = text ..("%d) wday:%d hour:%d min:%d duration %d.\n"):format(i, plan.wday, plan.hour, plan.min, plan.duration)
  511. end
  512. return true, text
  513. end
  514. })
  515. minetest.register_chatcommand("contest_start", {
  516. params = "Duration in seconds",
  517. description = "Start contest (admin only)",
  518. privs = {server=true},
  519. func = function(player_name, param)
  520. if not player_name then return end
  521. if fishing_setting.contest["contest"] == true then
  522. return false, "Contest already in progress."
  523. end
  524. local duration = tonumber(param)
  525. if not duration then
  526. duration = 3600
  527. end
  528. fishing_setting.contest["nb_fish"] = {}
  529. fishing_setting.func.start_contest(duration)
  530. return true, ("Contest started, duration:%d sec."):format(duration)
  531. end
  532. })
  533. minetest.register_chatcommand("contest_stop", {
  534. params = "",
  535. description = "Stop contest (admin only)",
  536. privs = {server=true},
  537. func = function(player_name, param)
  538. if not player_name then return end
  539. if fishing_setting.contest["contest"] == false then
  540. return false, "No contest in progress."
  541. end
  542. fishing_setting.func.end_contest()
  543. return true, "Contest finished."
  544. end
  545. })
  546. function fishing_setting.func.planned_tick()
  547. if fishing_setting.contest["contest"] == nil or fishing_setting.contest["contest"] == false then
  548. for i, plan in pairs(fishing_setting.planned) do
  549. local wday = plan.wday
  550. local hour = plan.hour
  551. local min = plan.min
  552. local duration = plan.duration
  553. local time = os.date("*t",os.time())
  554. if (wday == 0 or wday == time.wday) then
  555. if time.hour == hour and time.min == min then
  556. minetest.log("action", ("Starting fishing contest at %d:%d duration %d"):format( hour, min, duration))
  557. fishing_setting.contest["nb_fish"] = {}
  558. fishing_setting.func.start_contest(duration)
  559. break
  560. end
  561. end
  562. end
  563. end
  564. minetest.after(50, fishing_setting.func.planned_tick)
  565. end
  566. --Menu fishing configuration
  567. fishing_setting.func.on_show_settings_contest = function(player_name)
  568. if not fishing_setting.tmp_setting then
  569. fishing_setting.tmp_setting = { ["contest"] = (fishing_setting.contest["contest"] or false),
  570. ["duration"] = (math.floor(fishing_setting.contest["duration"]) or 3600),
  571. ["bobber_nb"] = (fishing_setting.contest["bobber_nb"] or 2),
  572. ["reset"] = false
  573. }
  574. end
  575. local formspec = "size[6.1,7]label[1.9,0;"..S("Fishing contest").."]"..
  576. --Time contest
  577. "label[2.2,0.5;"..S("Duration(in sec)").."]"..
  578. "button[0.8,1;1,1;duration;-60]"..
  579. "button[1.8,1;1,1;duration;-600]"..
  580. "label[2.7,1.2;"..tostring(fishing_setting.tmp_setting["duration"]).."]"..
  581. "button[3.5,1;1,1;duration;+600]"..
  582. "button[4.5,1;1,1;duration;+60]"..
  583. --bobber nb
  584. "label[2,2;"..S("Bobber number limit").."]"..
  585. "button[1.8,2.5;1,1;bobbernb;-1]"..
  586. "label[2.9,2.7;"..tostring(fishing_setting.tmp_setting["bobber_nb"]).."]"..
  587. "button[3.5,2.5;1,1;bobbernb;+1]"..
  588. --contest enable
  589. "label[0.8,3.8;"..S("Enable contests").."]"..
  590. "button[4.5,3.6;1,1;contest;"..tostring(fishing_setting.tmp_setting["contest"]).."]"..
  591. --reset
  592. "label[0.8,5.2;"..S("Reset rankings").."]"..
  593. "button[4.5,5;1,1;reset;"..tostring(fishing_setting.tmp_setting["reset"]).."]"..
  594. "button_exit[0.8,6.2;1.5,1;abort;"..S("Abort").."]"..
  595. "button_exit[4,6.2;1.5,1;save;"..S("OK").."]"
  596. minetest.show_formspec(player_name, "fishing:contest", formspec)
  597. end
  598. minetest.register_on_player_receive_fields(function(player, formname, fields)
  599. if formname == "fishing:contest" then
  600. local name = player:get_player_name()
  601. if not name then return end
  602. if fields["save"] then
  603. if fishing_setting.tmp_setting["reset"] == true then
  604. fishing_setting.contest["nb_fish"] = {}
  605. end
  606. local progress = (fishing_setting.contest["contest"] or false)
  607. fishing_setting.contest["duration"] = fishing_setting.tmp_setting["duration"]
  608. fishing_setting.contest["contest"] = fishing_setting.tmp_setting["contest"]
  609. fishing_setting.contest["bobber_nb"] = fishing_setting.tmp_setting["bobber_nb"]
  610. if progress == false and fishing_setting.tmp_setting["contest"] == true then
  611. local duration = fishing_setting.func.timetostr(fishing_setting.contest["duration"])
  612. fishing_setting.func.start_contest(duration)
  613. elseif progress == true and fishing_setting.tmp_setting["contest"] == false then
  614. fishing_setting.func.end_contest()
  615. end
  616. fishing_setting.func.save_contest()
  617. fishing_setting.tmp_setting = nil
  618. return
  619. elseif fields["quit"] or fields["abort"] then
  620. fishing_setting.tmp_setting = nil
  621. return
  622. elseif fields["duration"] then
  623. fishing_setting.tmp_setting["duration"] = inc(fishing_setting.tmp_setting["duration"], fields["duration"], 120, 14400)
  624. elseif fields["contest"] then
  625. fishing_setting.tmp_setting["contest"] = bool(fields["contest"])
  626. elseif fields["bobbernb"] then
  627. fishing_setting.tmp_setting["bobber_nb"] = inc(fishing_setting.tmp_setting["bobber_nb"], fields["bobbernb"], 1, 8)
  628. elseif fields["reset"] then
  629. fishing_setting.tmp_setting["reset"] = bool(fields["reset"])
  630. else
  631. return
  632. end
  633. fishing_setting.func.on_show_settings_contest(name)
  634. end
  635. end)
  636. function spairs(t, order)
  637. -- collect the keys
  638. local keys = {}
  639. for k in pairs(t) do keys[#keys+1] = k end
  640. -- if order function given, sort by it by passing the table and keys a, b,
  641. -- otherwise just sort the keys
  642. if order then
  643. table.sort(keys, function(a,b) return order(t, a, b) end)
  644. else
  645. table.sort(keys)
  646. end
  647. -- return the iterator function
  648. local i = 0
  649. return function()
  650. i = i + 1
  651. if keys[i] then
  652. return keys[i], t[keys[i]]
  653. end
  654. end
  655. end
  656. function fishing_setting.func.set_winners(list)
  657. local win = {}
  658. -- this uses an custom sorting function ordering by score descending
  659. for k,v in spairs(list, function(t,a,b) return t[b] < t[a] end) do
  660. table.insert(win, {["name"]=k, ["nb"]=v})
  661. if #win >= 15 then
  662. break
  663. end
  664. end
  665. return win
  666. end
  667. function fishing_setting.func.get_stat()
  668. local winners = {}
  669. if fishing_setting.contest["nb_fish"] ~= nil then
  670. winners = fishing_setting.func.set_winners(fishing_setting.contest["nb_fish"])
  671. end
  672. local formspec = {"size[6,8]label[2,0;"..S("Fishing contest rankings").."]"}
  673. local Y = 1.1
  674. table.insert(formspec, "label[0.5,0.5;No]")
  675. table.insert(formspec, "label[2,0.5;Name]")
  676. table.insert(formspec, "label[4.2,0.5;Fish Total]")
  677. for num,n in ipairs(winners) do
  678. table.insert(formspec, "label[0.5,"..Y..";"..tostring(num).."]") -- classement
  679. table.insert(formspec, "label[2,"..Y..";"..n["name"].."]") -- playername
  680. table.insert(formspec, "label[4.3,"..Y..";"..tostring(n["nb"]).."]") -- nb fish caught
  681. Y = Y + 0.4
  682. end
  683. table.insert(formspec, "button_exit[2.4,7.5;1.2,1;close;"..S("Close").."]")
  684. return table.concat(formspec)
  685. end
  686. function fishing_setting.func.get_hunger_info(player_name)
  687. local formspec = "size[6,9]label[1.9,0;Fishing Info Center]"
  688. local y = 0.8
  689. for i, a in pairs(fishing_setting.baits) do
  690. if string.find(i, "fishing:") ~= nil then
  691. formspec = formspec .."item_image_button[1,"..tostring(y)..";1,1;"..tostring(i)..";"..tostring(i)..";]"..
  692. "label[2.2,"..tostring(y+0.2)..";Chance to fish :"..tostring(a["hungry"]).."%]"
  693. y = y+1
  694. end
  695. end
  696. formspec = formspec .."button_exit[2,8.5;2,1;close;"..S("Close").."]"
  697. minetest.show_formspec(player_name,"fishing:material_info", formspec)
  698. end
  699. minetest.register_chatcommand("fishing_menu", {
  700. params = "",
  701. description = "Show fishing menu (admin only)",
  702. privs = {server=true},
  703. func = function(player_name, param)
  704. if not player_name then return end
  705. fishing_setting.func.on_show_admin_menu(player_name)
  706. end
  707. })
  708. minetest.register_chatcommand("fishing_classement", {
  709. params = "",
  710. description = "display classement",
  711. privs = {interact=true},
  712. func = function(player_name, param)
  713. if not player_name then return end
  714. local formspec = fishing_setting.func.get_stat()
  715. minetest.show_formspec(player_name, "fishing:classement", formspec)
  716. end
  717. })
  718. function fishing_setting.func.show_result()
  719. minetest.after(3, function()
  720. local formspec = fishing_setting.func.get_stat()
  721. for _,player in pairs(minetest.get_connected_players()) do
  722. local player_name = player:get_player_name()
  723. if player_name ~= nil then
  724. minetest.show_formspec(player_name, "fishing:classement", formspec)
  725. end
  726. end
  727. end)
  728. end
  729. local UPDATE_TIME = 1
  730. function fishing_setting.func.tick()
  731. if fishing_setting.contest["contest"] ~= nil and fishing_setting.contest["contest"] == true then
  732. fishing_setting.contest["duration"] = fishing_setting.contest["duration"] - UPDATE_TIME
  733. if fishing_setting.contest["duration"] < 30 and fishing_setting.contest["warning_said"] ~= true then
  734. minetest.chat_send_all(fishing_setting.func.S("WARNING, Fishing contest will finish in 30 seconds."))
  735. fishing_setting.contest["warning_said"] = true
  736. end
  737. if fishing_setting.contest["duration"] < 0 then
  738. fishing_setting.func.end_contest()
  739. else
  740. minetest.after(UPDATE_TIME, fishing_setting.func.tick)
  741. end
  742. end
  743. end