From aa2ae43852a927693f44b0643e98d617a68bff86 Mon Sep 17 00:00:00 2001 From: Fernando Carmona Varo Date: Sat, 24 Oct 2015 22:12:45 +0200 Subject: Do not save state to disk anymore, instead properly end the game and move the player outside. Also other players won't be able to enter a game already in progress --- pacmine/gamestate.lua | 66 +++++++++++++++------------------------------------ pacmine/ghost.lua | 1 - pacmine/init.lua | 23 ++---------------- 3 files changed, 21 insertions(+), 69 deletions(-) diff --git a/pacmine/gamestate.lua b/pacmine/gamestate.lua index 53e2985..718bf02 100755 --- a/pacmine/gamestate.lua +++ b/pacmine/gamestate.lua @@ -18,17 +18,19 @@ local score_for_life_award = 5000 function pacmine.game_start(pos, player) -- create an id unique for the given position local id = minetest.pos_to_string(pos) + local player_name = player:get_player_name() -- make sure any previous game with the same id has ended local gamestate = pacmine.games[id] if gamestate then - pacmine.game_end(id) + minetest.chat_send_player(name, "A game is already in progress for player " .. gamestate.player_name) + return end -- Create a new game state with that id and add it to the game list gamestate = { id = id, - player_name = player:get_player_name(), + player_name = player_name, pos = pos, start = {x=pos.x+14,y=pos.y+0.5,z=pos.z+16}, pellet_count = 0, @@ -56,7 +58,12 @@ end -- Finish the game with the given id function pacmine.game_end(id) pacmine.remove_ghosts(id) - pacmine.remove_hud(pacmine.players[id], pacmine.games[id].player_name) + local gamestate = pacmine.games[id] + local player = pacmine.players[id] or minetest.get_player_by_name(gamestate.player_name) + if player then + pacmine.remove_hud(player, gamestate.player_name) + player:moveto(vector.add(gamestate.pos,{x=0.5,y=0.5,z=-1.5})) + end -- Clear the data pacmine.games[id] = nil pacmine.players[id] = nil @@ -122,10 +129,12 @@ function pacmine.remove_ghosts(id) end end +-- Add a fruit to the game board function pacmine.add_fruit(id) local gamestate = pacmine.games[id] if not gamestate then return end local node = {} + -- Different fruit will be used depending on the level if gamestate.level == 1 then node.name = "pacmine:cherrys" elseif gamestate.level == 2 then @@ -137,6 +146,7 @@ function pacmine.add_fruit(id) end local pos = vector.add(gamestate.start,{x=0,y=-1,z=0}) minetest.set_node(pos, node) + -- Set the timer for the fruit to disappear minetest.get_node_timer(pos):start(math.random(20, 30)) end @@ -149,6 +159,7 @@ function pacmine.on_player_got_pellet(player) gamestate.pellet_count = gamestate.pellet_count + 1 gamestate.score = gamestate.score + 10 pacmine.update_hud(gamestate.id, player) + minetest.sound_play("pacmine_chomp", {object = player, max_hear_distance = 6}) if gamestate.pellet_count == 70 or gamestate.pellet_count == 180 then pacmine.add_fruit(gamestate.id) @@ -200,7 +211,6 @@ function pacmine.on_player_got_power_pellet(player) minetest.chat_send_player(name, "POWER PELLET wore off") end end) - minetest.sound_play("pacmine_eatfruit", {pos = pos, max_hear_distance = 6}) end -- A player got a fruit, update the state @@ -225,26 +235,6 @@ end --------------------------------------------------------- --- Private functions (only can be used inside this file) --- Save Table -local function gamestate_save() - local data = pacmine.games - local f, err = io.open(minetest.get_worldpath().."/pacmine_data", "w") - if err then return err end - f:write(minetest.serialize(data)) - f:close() -end - ---Read Table -local function gamestate_load() - local f, err = io.open(minetest.get_worldpath().."/pacmine_data", "r") - if f then - local data = minetest.deserialize(f:read("*a")) - f:close() - return data - else - return nil - end -end -- Called every 0.5 seconds for each player that is currently playing local function on_player_gamestep(player, gameid) @@ -281,44 +271,32 @@ end ------------------- --- Execution code --- load the gamestate from disk -pacmine.games = gamestate_load() or {} -- Time counters local tmr_gamestep = 0 -local tmr_savestep = 0 minetest.register_globalstep(function(dtime) tmr_gamestep = tmr_gamestep + dtime; if tmr_gamestep > 0.2 then for id,player in pairs(pacmine.players) do on_player_gamestep(player, id) end - tmr_savestep = tmr_savestep + tmr_gamestep - if tmr_savestep > 10 then - gamestate_save() - tmr_savestep = 0 - end tmr_gamestep = 0 end end) -minetest.register_on_joinplayer(function(player) +minetest.register_on_leaveplayer(function(player) local name = player:get_player_name() for id,game in pairs(pacmine.games) do if game.player_name == name then - pacmine.players[id] = player - pacmine.update_hud(id, player) + pacmine.game_end(id) end end end) -minetest.register_on_leaveplayer(function(player) - local name = player:get_player_name() +minetest.register_on_shutdown(function() + minetest.log("action", "Server shuts down. Ending all pacmine games") for id,game in pairs(pacmine.games) do - if game.player_name == name then - pacmine.players[id] = nil - pacmine.remove_hud(player, name) - end + pacmine.game_end(id) end end) @@ -330,15 +308,9 @@ minetest.register_chatcommand("pacmine_exit", { local gamestate = pacmine.get_game_by_player(name) if gamestate then pacmine.game_end(gamestate.id) - minetest.get_player_by_name(name):moveto(vector.add(gamestate.pos,{x=0.5,y=0.5,z=-1.5})) minetest.chat_send_player(name, "You are no longer playing pacmine") else minetest.chat_send_player(name, "You are not currently in a pacmine game") end end }) - -minetest.register_on_shutdown(function() - minetest.log("action", "Server shuts down. Saving pacmine data") - gamestate_save() -end) diff --git a/pacmine/ghost.lua b/pacmine/ghost.lua index 7c7c374..adc106d 100644 --- a/pacmine/ghost.lua +++ b/pacmine/ghost.lua @@ -97,7 +97,6 @@ for i in ipairs(ghosts) do gamestate.lives = gamestate.lives - 1 if gamestate.lives < 1 then minetest.chat_send_player(gamestate.player_name,"Game Over") - player:moveto(vector.add(gamestate.pos,{x=0.5,y=0.5,z=-1.5})) pacmine.game_end(self.gameid) minetest.sound_play("pacmine_death", {pos = boardcenter,max_hear_distance = 20, object=player, loop=false}) diff --git a/pacmine/init.lua b/pacmine/init.lua index 4d4db2a..e9e37dc 100644 --- a/pacmine/init.lua +++ b/pacmine/init.lua @@ -22,23 +22,13 @@ minetest.register_node("pacmine:pellet_1", { walkable = false, light_source = 11, drop = "", - groups = {dig_immediate = 3, not_in_creative_inventory = 0}, + groups = {immortal = 1, not_in_creative_inventory = 1}, node_box = { type = "fixed", fixed = { {-0.625, 0.25, -0.125, -0.375, 0.5, 0.125}, } }, - on_destruct = function(pos) - minetest.sound_play("pacmine_chomp", { - pos = pos, - max_hear_distance = 100, - gain = 10.0, - }) - end, - after_dig_node = function(pos, oldnode, oldmetadata, digger) - pacmine.on_player_got_pellet(digger) - end, }) --Power Pellets. Need to make these do something @@ -56,7 +46,7 @@ minetest.register_node("pacmine:pellet_2", { {items = {"pacmine:peach"},rarity = 4,}, {items = {"pacmine:strawberry"},rarity = 4,},}, }, - groups = {dig_immediate = 3, not_in_creative_inventory = 0}, + groups = {immortal = 1, not_in_creative_inventory = 1}, node_box = { type = "fixed", fixed = { @@ -66,15 +56,6 @@ minetest.register_node("pacmine:pellet_2", { {-0.6875, -0.1875, -0.1875, -0.3125, 0.1875, 0.1875}, } }, - after_dig_node = function(pos, oldnode, oldmetadata, digger) - pacmine.on_player_got_power_pellet(digger) - - minetest.sound_play("pacmine_eatfruit", { - pos = pos, - max_hear_distance = 100, - gain = 10.0, - }) - end, }) --The placer block -- cgit v1.2.3 From ebde4407511a7255e1e5b6d897f81188c4fe2eb3 Mon Sep 17 00:00:00 2001 From: Fernando Carmona Varo Date: Sat, 24 Oct 2015 22:31:23 +0200 Subject: Some refactoring and organization, added api.lua --- myhighscore/api.lua | 9 +++++++ myhighscore/init.lua | 65 +++------------------------------------------- myhighscore/scoreboard.lua | 64 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 62 deletions(-) create mode 100755 myhighscore/api.lua create mode 100755 myhighscore/scoreboard.lua diff --git a/myhighscore/api.lua b/myhighscore/api.lua new file mode 100755 index 0000000..bbad4d7 --- /dev/null +++ b/myhighscore/api.lua @@ -0,0 +1,9 @@ + +myhighscore.registered_games = {} + + +-- You can register a new arcade game using this function +myhighscore.register_game(name, definition) + definition.description = definition.description or name + myhighscore.registered_games[name] = definition +end diff --git a/myhighscore/init.lua b/myhighscore/init.lua index 0eab03c..854be70 100644 --- a/myhighscore/init.lua +++ b/myhighscore/init.lua @@ -1,64 +1,5 @@ +myhighscore = {} -local button_form = "size[6,8;]".. - "background[0,0;6,8;myhighscore_form_bg.png]".. - "label[1,0.5;HIGH SCORES]".. - "button[1,1;4,1;game;label]".. - "button_exit[4,7;1,2;exit;Exit]" - ---place holders -local game_name = "the game" -local game_player_name = "the player" -local game_player_score = "648138" - -local game_form = "size[6,8;]".. - "background[0,0;6,8;myhighscore_form_bg.png]".. - "label[1,0.5;HIGH SCORES FOR "..game_name.."]".. - "label[1,1.5;PLAYER]".. - "label[3.5,1.5;SCORE]".. - "label[0.5,2;"..game_player_name.."]".. - "label[3,2;"..game_player_score.."]".. - "button[2,7;1,2;back;Back]".. - "button_exit[4,7;1,2;exit;Exit]" - -minetest.register_node("myhighscore:score_board", { - description = "Score Board", - tiles = { - "myhighscore_top.png", - "myhighscore_back.png", - "myhighscore_side.png^[transformFX", - "myhighscore_side.png", - "myhighscore_back.png", - "myhighscore_front.png", - }, - drawtype = "nodebox", - paramtype = "light", - paramtype2 = "facedir", - groups = {cracky = 1}, - node_box = { - type = "fixed", - fixed = { - {-0.375, -0.5, -0.5, 0.375, -0.1875, 0.5}, - {-0.375, -0.5, 0.1875, 0.375, 0.5, 0.5}, - {-0.1875, -0.5, -0.3125, -0.125, 0, -0.25}, - {-0.375, -0.5, 0, -0.3125, 0.5, 0.5}, - {0.3125, -0.5, 0, 0.375, 0.5, 0.5}, - {-0.375, 0.4375, 0, 0.375, 0.5, 0.5}, - } - }, - -on_construct = function(pos) - local meta = minetest.env:get_meta(pos) - meta:set_string("formspec", button_form) - meta:set_string("infotext", "High Scores") -end, -on_receive_fields = function(pos, formname, fields, sender) - local meta = minetest.env:get_meta(pos) - if fields['game'] then - meta:set_string('formspec', game_form) - elseif fields["back"] then - meta:set_string('formspec', button_form) - end -end, - -}) +dofile(minetest.get_modpath("myhighscore").."/api.lua") +dofile(minetest.get_modpath("myhighscore").."/scoreboard.lua") diff --git a/myhighscore/scoreboard.lua b/myhighscore/scoreboard.lua new file mode 100755 index 0000000..226e86a --- /dev/null +++ b/myhighscore/scoreboard.lua @@ -0,0 +1,64 @@ + + + + +local button_form = "size[6,8;]".. + "background[0,0;6,8;myhighscore_form_bg.png]".. + "label[1,0.5;HIGH SCORES]".. + "button[1,1;4,1;game;label]".. + "button_exit[4,7;1,2;exit;Exit]" + +--place holders +local game_name = "the game" +local game_player_name = "the player" +local game_player_score = "648138" + +local game_form = "size[6,8;]".. + "background[0,0;6,8;myhighscore_form_bg.png]".. + "label[1,0.5;HIGH SCORES FOR "..game_name.."]".. + "label[1,1.5;PLAYER]".. + "label[3.5,1.5;SCORE]".. + "label[0.5,2;"..game_player_name.."]".. + "label[3,2;"..game_player_score.."]".. + "button[2,7;1,2;back;Back]".. + "button_exit[4,7;1,2;exit;Exit]" + +minetest.register_node("myhighscore:score_board", { + description = "Score Board", + tiles = { + "myhighscore_top.png", + "myhighscore_back.png", + "myhighscore_side.png^[transformFX", + "myhighscore_side.png",y + "myhighscore_back.png", + "myhighscore_front.png", + }, + drawtype = "nodebox", + paramtype = "light", + paramtype2 = "facedir", + groups = {cracky = 1}, + node_box = { + type = "fixed", + fixed = { + {-0.375, -0.5, -0.5, 0.375, -0.1875, 0.5}, + {-0.375, -0.5, 0.1875, 0.375, 0.5, 0.5}, + {-0.1875, -0.5, -0.3125, -0.125, 0, -0.25}, + {-0.375, -0.5, 0, -0.3125, 0.5, 0.5}, + {0.3125, -0.5, 0, 0.375, 0.5, 0.5}, + {-0.375, 0.4375, 0, 0.375, 0.5, 0.5}, + } + }, + on_construct = function(pos) + local meta = minetest.env:get_meta(pos) + meta:set_string("formspec", button_form) + meta:set_string("infotext", "High Scores") + end, + on_receive_fields = function(pos, formname, fields, sender) + local meta = minetest.env:get_meta(pos) + if fields['game'] then + meta:set_string('formspec', game_form) + elseif fields["back"] then + meta:set_string('formspec', button_form) + end + end, +}) -- cgit v1.2.3 From 289cacf17a5812c5fb6cfc7134dedabfea0d86e7 Mon Sep 17 00:00:00 2001 From: Fernando Carmona Varo Date: Sun, 25 Oct 2015 02:51:44 +0200 Subject: Implemented myhighscores API, and used it in pacmine --- myhighscore/api.lua | 68 +++++++++++++++++++++++++++++++++++++++++++++- myhighscore/scoreboard.lua | 33 ++++++++++++++-------- pacmine/depends.txt | 1 + pacmine/gamestate.lua | 14 ++++++++++ 4 files changed, 104 insertions(+), 12 deletions(-) create mode 100755 pacmine/depends.txt diff --git a/myhighscore/api.lua b/myhighscore/api.lua index bbad4d7..f1e84f8 100755 --- a/myhighscore/api.lua +++ b/myhighscore/api.lua @@ -1,9 +1,75 @@ +-- Store any information we might need for the games that will use highscore +-- (icons, description, or whatever) myhighscore.registered_games = {} +-- This table will contain a table for each registered game which +-- will be an array of player scores +myhighscore.scores = {} + +-- How many scores to keep saved per game +local stored_scores = 50 + +-- Name of the folder to save the scores to +-- each game highscore list will be saved in a file inside this directory +local score_directory = minetest.get_worldpath().."/myhighscores/" -- You can register a new arcade game using this function -myhighscore.register_game(name, definition) +-- The definition will get added to the table of registered games. +function myhighscore.register_game(name, definition) definition.description = definition.description or name myhighscore.registered_games[name] = definition + myhighscore.load_scores(name) +end + +-- Returns true if score from A is smaller than score from B +-- Used for sorting the score arra +function myhighscore.is_score_higher(scoreA, scoreB) + return scoreA.score > scoreB.score +end + +-- Saves a given score for the given game. "score" will be a table containing at least: +-- player (player name) and score (points) +function myhighscore.save_score(name, score) + local scores = myhighscore.scores[name] + + -- Check first if the last score is higher + if scores[stored_scores] and + myhighscore.is_score_higher(scores[stored_scores], score) then + return false + end + + table.insert(scores, score) + -- sort the array + table.sort(scores, myhighscore.is_score_higher) + -- check position and remove any extra ones + local pos = 0 + for i,sc in pairs(scores) do + if sc == score then + pos = i + elseif i > stored_scores then + scores[i] = nil + end + end + -- save it to disk + local f, err = io.open(score_directory .. name, "w") + f:write(minetest.serialize(scores)) + f:close() + -- return the position we hold on the list + return pos +end + + +-- Read scores from disk for the given game, or initialize the scores table if not present +function myhighscore.load_scores(name) + local f, err = io.open(score_directory .. name, "r") + local data = {} + if f then + data = minetest.deserialize(f:read("*a")) or {} + f:close() + end + myhighscore.scores[name] = data end + +-- Create the scores directory if it doesn't exist! +minetest.mkdir(score_directory) diff --git a/myhighscore/scoreboard.lua b/myhighscore/scoreboard.lua index 226e86a..38e659e 100755 --- a/myhighscore/scoreboard.lua +++ b/myhighscore/scoreboard.lua @@ -13,15 +13,26 @@ local game_name = "the game" local game_player_name = "the player" local game_player_score = "648138" -local game_form = "size[6,8;]".. - "background[0,0;6,8;myhighscore_form_bg.png]".. - "label[1,0.5;HIGH SCORES FOR "..game_name.."]".. - "label[1,1.5;PLAYER]".. - "label[3.5,1.5;SCORE]".. - "label[0.5,2;"..game_player_name.."]".. - "label[3,2;"..game_player_score.."]".. - "button[2,7;1,2;back;Back]".. - "button_exit[4,7;1,2;exit;Exit]" +local function get_formspec_for_game(name) + local def = myhighscore.registered_games[name] + local scores = myhighscore.scores[name] or {} + -- Obtain a comma separated list of scores to display + local scorelist = "" + for _,score in pairs(scores) do + scorelist = scorelist .. minetest.formspec_escape(score.player) .. + "\t\t\t\t " .. score.score .."," + end + + return "size[6,8;]".. + "background[0,0;6,8;myhighscore_form_bg.png]".. + "label[1,0.5;HIGH SCORES FOR "..def.description.."]".. + "label[1,1.5;PLAYER]".. + "label[3.5,1.5;SCORE]".. + "textlist[0.5,2;5,5;;"..scorelist.."]".. + "button[2,7;1,2;back;Back]".. + "button_exit[4,7;1,2;exit;Exit]" +end + minetest.register_node("myhighscore:score_board", { description = "Score Board", @@ -29,7 +40,7 @@ minetest.register_node("myhighscore:score_board", { "myhighscore_top.png", "myhighscore_back.png", "myhighscore_side.png^[transformFX", - "myhighscore_side.png",y + "myhighscore_side.png", "myhighscore_back.png", "myhighscore_front.png", }, @@ -56,7 +67,7 @@ minetest.register_node("myhighscore:score_board", { on_receive_fields = function(pos, formname, fields, sender) local meta = minetest.env:get_meta(pos) if fields['game'] then - meta:set_string('formspec', game_form) + meta:set_string('formspec', get_formspec_for_game("pacmine")) elseif fields["back"] then meta:set_string('formspec', button_form) end diff --git a/pacmine/depends.txt b/pacmine/depends.txt new file mode 100755 index 0000000..01e0fb0 --- /dev/null +++ b/pacmine/depends.txt @@ -0,0 +1 @@ +myhighscore diff --git a/pacmine/gamestate.lua b/pacmine/gamestate.lua index 718bf02..7bbc0af 100755 --- a/pacmine/gamestate.lua +++ b/pacmine/gamestate.lua @@ -64,6 +64,14 @@ function pacmine.game_end(id) pacmine.remove_hud(player, gamestate.player_name) player:moveto(vector.add(gamestate.pos,{x=0.5,y=0.5,z=-1.5})) end + -- Save score + local ranking = myhighscore.save_score("pacmine", { + player = gamestate.player_name, + score = gamestate.score + }) + if ranking then + minetest.chat_send_player(gamestate.player_name, "You made it to the highscores! Your Ranking: " .. ranking) + end -- Clear the data pacmine.games[id] = nil pacmine.players[id] = nil @@ -314,3 +322,9 @@ minetest.register_chatcommand("pacmine_exit", { end end }) + +-- Register with the myhighscore mod +myhighscore.register_game("pacmine", { + description = "Pacmine", + icon = "pacmine_1.png", +}) -- cgit v1.2.3