summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xgamestate.lua170
-rw-r--r--ghost.lua212
-rw-r--r--init.lua141
3 files changed, 265 insertions, 258 deletions
diff --git a/gamestate.lua b/gamestate.lua
new file mode 100755
index 0000000..683ce3f
--- /dev/null
+++ b/gamestate.lua
@@ -0,0 +1,170 @@
+
+-- Array to hold all the running game states
+mypacman.games = {}
+
+---------------------------------------------------------
+-- Public functions (these can be called from any other place)
+
+-- Start the game from the spawn block at position "pos" activated by "player"
+function mypacman.game_start(pos, player)
+ -- create an id unique for the given position
+ local id = minetest.pos_to_string(pos)
+
+ -- make sure any previous game with the same id has ended
+ if mypacman.games[id] then
+ mypacman.game_end(id)
+ end
+
+ -- Create a new game state with that id and add it to the game list
+ local gamestate = {
+ id = id,
+ player_name = player:get_player_name(),
+ pos = pos,
+ start = {x=pos.x+14,y=pos.y+0.5,z=pos.z+16},
+ pellet_count = 0,
+ level = 1,
+ speed = 2,
+ lives = 3,
+ }
+ mypacman.games[id] = gamestate
+ minetest.log("action","New pacman game started at " .. id .. " by " .. gamestate.player_name)
+
+ -- place schematic
+ local schem = minetest.get_modpath("mypacman").."/schems/mypacman_3.mts"
+ minetest.place_schematic({x=pos.x,y=pos.y-1,z=pos.z-2},schem,0, "air", true)
+
+ -- Set start positions
+ mypacman.game_reset(id, player)
+ minetest.sound_play("mypacman_beginning", {pos = pos,max_hear_distance = 40,gain = 10.0,})
+end
+
+-- Finish the game with the given id
+function mypacman.game_end(id)
+ mypacman.remove_ghosts(id)
+ -- Clear the data
+ mypacman.games[id] = nil
+end
+
+-- Resets the game to the start positions
+function mypacman.game_reset(id, player)
+ local gamestate = mypacman.games[id]
+ minetest.log("action", "resetting game " .. id)
+
+ -- Position the player
+ local player = player or minetest.get_player_by_name(gamestate.player_name)
+ player:setpos(gamestate.start)
+
+ -- Spawn the ghosts and assign the game id to each ghost
+ minetest.after(2, function()
+ local pos = vector.add(gamestate.pos, {x=13,y=0.5,z=19})
+ local ghost = minetest.add_entity(pos, "mypacman:inky")
+ ghost:get_luaentity().gameid = id
+ end)
+ minetest.after(12, function()
+ local pos = vector.add(gamestate.pos, {x=15,y=0.5,z=19})
+ local ghost = minetest.add_entity(pos, "mypacman:pinky")
+ ghost:get_luaentity().gameid = id
+ end)
+ minetest.after(22, function()
+ local pos = vector.add(gamestate.pos, {x=13,y=0.5,z=18})
+ local ghost = minetest.add_entity(pos, "mypacman:blinky")
+ ghost:get_luaentity().gameid = id
+ end)
+ minetest.after(32, function()
+ local pos = vector.add(gamestate.pos, {x=15,y=0.5,z=18})
+ local ghost = minetest.add_entity(pos, "mypacman:clyde")
+ ghost:get_luaentity().gameid = id
+ end)
+end
+
+-- Remove all the ghosts from the board with the given id
+function mypacman.remove_ghosts(id)
+ local gamestate = mypacman.games[id]
+ if not gamestate then return end
+
+ -- Remove all non-players (ghosts!)
+ local boardcenter = vector.add(gamestate.pos, {x=13,y=0.5,z=15})
+ for index, object in ipairs(minetest.get_objects_inside_radius(boardcenter,20)) do
+ if object:is_player() ~= true then
+ object:remove()
+ end
+ end
+end
+
+-- A player got a pellet, update the state
+function mypacman.on_player_got_pellet(player)
+ local name = player:get_player_name()
+ local gamestate = mypacman.get_game_by_player(name)
+ if not gamestate then return end
+
+ gamestate.pellet_count = gamestate.pellet_count + 1
+ if gamestate.pellet_count >= 20 then -- 252
+ minetest.chat_send_player(name, "You cleared the board!")
+
+ mypacman.remove_ghosts(gamestate.id)
+ gamestate.pellet_count = 0
+ gamestate.level = gamestate.level + 1
+ gamestate.speed = gamestate.level + 1
+
+ minetest.after(3.0, function()
+ minetest.chat_send_player(name, "Starting Level "..gamestate.level)
+ -- place schematic
+ local schem = minetest.get_modpath("mypacman").."/schems/mypacman_3.mts"
+ minetest.place_schematic(vector.add(gamestate.pos, {x=0,y=-1,z=-2}),schem,0, "air", true)
+
+ -- Set start positions
+ mypacman.game_reset(gamestate.id, player)
+ minetest.sound_play("mypacman_beginning", {pos = pos,max_hear_distance = 40,gain = 10.0,})
+ end)
+ end
+
+end
+
+-- Get the game that the given player is playing
+function mypacman.get_game_by_player(player_name)
+ for _,gamestate in pairs(mypacman.games) do
+ if gamestate.player_name == player_name then
+ return gamestate
+ end
+ end
+end
+
+---------------------------------------------------------
+--- Private functions (only can be used inside this file)
+
+-- Save Table
+local function gamestate_save()
+ local data = mypacman.games
+ local f, err = io.open(minetest.get_worldpath().."/mypacman_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().."/mypacman_data", "r")
+ if f then
+ local data = minetest.deserialize(f:read("*a"))
+ f:close()
+ return data
+ else
+ return nil
+ end
+end
+
+-------------------
+--- Execution code
+
+-- load the gamestate from disk
+mypacman.games = gamestate_load() or {}
+
+local tmr = 0
+--Save Table every 10 seconds
+minetest.register_globalstep(function(dtime)
+ tmr = tmr + dtime;
+ if tmr >= 10 then
+ tmr = 0
+ gamestate_save()
+ end
+end)
diff --git a/ghost.lua b/ghost.lua
index 4774e94..2714710 100644
--- a/ghost.lua
+++ b/ghost.lua
@@ -1,24 +1,3 @@
---The code used for the ghosts was made by Tenplus1
-
-local myghosts = {}
-local deathcount = 0
-local gravity = -10
-
-clear_ghosts = function()
- local pos = mypacman.start
-
- for index, object in ipairs(minetest.get_objects_inside_radius({x=pos.x+13,y=pos.y+0.5,z=pos.z+15},20)) do
- --local obj = object:get_luaentity()
- if object:is_player() ~= true then
- object:moveto({x=pos.x+13,y=pos.y+0.5,z=pos.z+19})
- end
- end
- --minetest.add_entity({x=pos.x+13,y=pos.y+0.5,z=pos.z+19}, "mypacman:inky")
- --minetest.add_entity({x=pos.x+15,y=pos.y+0.5,z=pos.z+19}, "mypacman:pinky")
- --minetest.add_entity({x=pos.x+13,y=pos.y+0.5,z=pos.z+18}, "mypacman:blinky")
- --minetest.add_entity({x=pos.x+15,y=pos.y+0.5,z=pos.z+18}, "mypacman:clyde")
-
-end
local ghosts = {
{"pinky","Pinky"},
@@ -30,122 +9,97 @@ for i in ipairs(ghosts) do
local itm = ghosts[i][1]
local desc = ghosts[i][2]
-minetest.register_entity("mypacman:"..itm, {
-
- hp_max = 1,
- physical = true,
- collide_with_objects = true,
- visual = "cube",
- visual_size = {x = 0.6, y = 1},
- textures =
- {"mypacman_"..itm.."s.png",
- "mypacman_"..itm.."s.png",
- "mypacman_"..itm.."s.png",
- "mypacman_"..itm.."s.png",
- "mypacman_"..itm.."f.png",
- "mypacman_"..itm.."s.png",
+ minetest.register_entity("mypacman:"..itm, {
+ hp_max = 1,
+ physical = true,
+ collide_with_objects = true,
+ visual = "cube",
+ visual_size = {x = 0.6, y = 1},
+ textures = {
+ "mypacman_"..itm.."s.png",
+ "mypacman_"..itm.."s.png",
+ "mypacman_"..itm.."s.png",
+ "mypacman_"..itm.."s.png",
+ "mypacman_"..itm.."f.png",
+ "mypacman_"..itm.."s.png",
},
- velocity = {x=math.random(-1,1), y=0, z=math.random(-1,1)},
- collisionbox = {-0.25, -1.0, -0.25, 0.25, 0.48, 0.25},
- weight = 5, -- ??
- is_visible = true,
- automatic_rotate = true,
- automatic_face_movement_dir = -90, -- set yaw direction in degrees, false to disable
- stepheight = 1.1,
- makes_footstep_sound = false,
- floats = 1,
- view_range = 40,
- speed = mypacman.spd,
- jump_height = 0,
+ groups = {immortal = 1},
+ velocity = {x=math.random(-1,1), y=0, z=math.random(-1,1)},
+ collisionbox = {-0.25, -1.0, -0.25, 0.25, 0.48, 0.25},
+ is_visible = true,
+ automatic_rotate = true,
+ automatic_face_movement_dir = -90, -- set yaw direction in degrees, false to disable
+ makes_footstep_sound = false,
- set_velocity = function(self, v)
- if not v then v = 0 end
- local yaw = self.object:getyaw()
- self.object:setvelocity({x=math.sin(yaw) * -v, y=self.object:getvelocity().y, z=math.cos(yaw) * v})
- end,
+ set_velocity = function(self, v)
+ if not v then v = 0 end
+ local yaw = self.object:getyaw()
+ self.object:setvelocity({x=math.sin(yaw) * -v, y=self.object:getvelocity().y, z=math.cos(yaw) * v})
+ end,
- on_step = function(self, dtime)
-
- -- every 1 second
- self.timer = (self.timer or 0) + dtime
- if self.timer < 1 then return end
- self.timer = 0
+ on_step = function(self, dtime)
+ -- every 1 second
+ self.timer = (self.timer or 0) + dtime
+ if self.timer < 1 then return end
+ self.timer = 0
- -- make sure object floats (or not) when in water
- if minetest.get_item_group(minetest.get_node(self.object:getpos()).name, "water") ~= 0 then
- if self.floats == 1 then
- self.object:setacceleration({x = self.object:getacceleration().x, y = 1.5, z = self.object:getacceleration().z})
- end
- else
- self.object:setacceleration({x = self.object:getacceleration().x, y = gravity, z = self.object:getacceleration().z})
- end
+ -- Do we have game state? if not just die
+ local gamestate = mypacman.games[self.gameid]
+ if not gamestate then
+ minetest.log("action", "Removing pacman ghost from finished game " .. (self.gameid or ""))
+ self.object:remove()
+ return
+ end
- local s, p, dist, nod
- -- find player to follow
- for _,player in pairs(minetest.get_connected_players()) do
- s = self.object:getpos()
- p = player:getpos()
+ -- Make sure we have a targetted player
+ if not self.target then
+ self.target = minetest.get_player_by_name(gamestate.player_name)
+ end
+ local player = self.target
- -- find distance
- dist = ((p.x-s.x)^2 + (p.y-s.y)^2 + (p.z-s.z)^2)^0.5
- if dist < self.view_range then
- local vec = {x=p.x-s.x, y=p.y-s.y, z=p.z-s.z}
- local yaw = (math.atan(vec.z/vec.x)+math.pi/2)
- if p.x > s.x then
- yaw = yaw + math.pi
- end
- -- face player
- self.object:setyaw(yaw)
+ local s = self.object:getpos() -- ghost
+ local p = player:getpos() -- player
- -- find direction and show node facing
- self.direction = {x = math.sin(yaw)*-1, y = 0, z = math.cos(yaw)}
- nod = minetest.get_node_or_nil({x=s.x + self.direction.x,y=s.y+1,z=s.z + self.direction.z})
-
- -- more than 2 nodes ahead then follow, otherwise stop
- if dist > 0 then
- if self.jump_height > 0 and self.object:getvelocity().y == 0 then
- local v = self.object:getvelocity()
- v.y = self.jump_height
- self.object:setvelocity(v)
- end
-
- self.set_velocity(self, self.speed)
- else
- self.set_velocity(self, 0)
- end
+ -- find distance from ghost to player
+ local distance = ((p.x-s.x)^2 + (p.y-s.y)^2 + (p.z-s.z)^2)^0.5
+ if distance < 1.5 then
+ -- player is so close it got catched!!
+ 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}))
+ mypacman.game_end(self.gameid)
+ elseif gamestate.lives == 1 then
+ minetest.chat_send_player(gamestate.player_name,"This is your last life")
+ mypacman.game_reset(self.gameid, player)
+ else
+ minetest.chat_send_player(gamestate.player_name,"You have ".. gamestate.lives .." lives left")
+ mypacman.game_reset(self.gameid, player)
+ end
- -- break look after player found
- break
- end
- end
-
- -- if touches player then death
- local s = self.object:getpos()
- local obs = {}
- for _,oir in ipairs(minetest.get_objects_inside_radius(s, 1.5)) do
- local obj = oir:get_luaentity()
- if oir:is_player() then
- local player = oir
- local pos = mypacman.start
- local name = player:get_player_name()
- if deathcount == 0 then
- player:moveto({x=pos.x+13,y=pos.y+0.5,z=pos.z+15.5})
- minetest.chat_send_player(name,"You have 1 more life after this")
- deathcount = 1
- clear_ghosts()
- elseif deathcount == 1 then
- player:moveto({x=pos.x+13,y=pos.y+0.5,z=pos.z+15.5})
- minetest.chat_send_player(name,"This is your last life")
- deathcount = 2
- clear_ghosts()
- elseif deathcount == 2 then
- player:moveto({x=pos.x+0.5,y=pos.y+0.5,z=pos.z-1.5})
- minetest.chat_send_player(name,"Game Over")
- deathcount = 0
- end
- end
+ else
+ local vec = {x=p.x-s.x, y=p.y-s.y, z=p.z-s.z}
+ local yaw = (math.atan(vec.z/vec.x)+math.pi/2)
+ if p.x > s.x then
+ yaw = yaw + math.pi
end
- end,
- })
+ -- face player and move towards him
+ self.object:setyaw(yaw)
+ self.set_velocity(self, gamestate.speed)
+ end
+ end,
+
+ -- This function should return the saved state of the entity in a string
+ get_staticdata = function(self)
+ return self.gameid or ""
+ end,
+
+ -- This function should load the saved state of the entity from a string
+ on_activate = function(self, staticdata)
+ if staticdata and staticdata ~= "" then
+ self.gameid = staticdata
+ end
+ end
+ })
end
diff --git a/init.lua b/init.lua
index a5c8be9..2ef6f29 100644
--- a/init.lua
+++ b/init.lua
@@ -1,71 +1,14 @@
---Save Table
-function save_table()
- local data = mypacman
- local f, err = io.open(minetest.get_worldpath().."/mypacman_data", "w")
- if err then return err end
- f:write(minetest.serialize(data))
- f:close()
-end
---Read Table
-local function read_table()
- local f, err = io.open(minetest.get_worldpath().."/mypacman_data", "r")
- local data = minetest.deserialize(f:read("*a"))
- f:close()
- return data
-end
-local tmr = 0
---Save Table every 10 seconds
-minetest.register_globalstep(function(dtime)
- tmr = tmr + dtime;
- if tmr >= 10 then
- tmr = 0
- save_table()
- end
-end)
---removes the ghosts from the game
-local function remove_ghosts()
- local pos = mypacman.start
- for index, object in ipairs(minetest.get_objects_inside_radius({x=pos.x+13,y=pos.y+0.5,z=pos.z+15},20)) do
- if object:is_player() ~= true then
- object:remove()
- end
- end
-end
+-- This variable will be exported to other mods when they "depend" on this mod
+mypacman = {}
-local function spawn_ghosts()
- local pos = mypacman.start
- minetest.after(2, function()
- minetest.add_entity({x=pos.x+13,y=pos.y+0.5,z=pos.z+19}, "mypacman:inky")
- end)
- minetest.after(12, function()
- minetest.add_entity({x=pos.x+15,y=pos.y+0.5,z=pos.z+19}, "mypacman:pinky")
- end)
- minetest.after(22, function()
- minetest.add_entity({x=pos.x+13,y=pos.y+0.5,z=pos.z+18}, "mypacman:blinky")
- end)
- minetest.after(32, function()
- minetest.add_entity({x=pos.x+15,y=pos.y+0.5,z=pos.z+18}, "mypacman:clyde")
- end)
-end
---Check to see if table exists. Need to see if there is a better way
-local f, err = io.open(minetest.get_worldpath().."/mypacman_data", "r")
-if f == nil then
-mypacman = {}
-mypacman.start = {}
-mypacman.pellet_count = 0
-mypacman.level = 1
-mypacman.spd = 2
-mypacman.board_num = 1
-else
-mypacman = read_table().start
-mypacman.start = read_table().start
-mypacman.pellet_count = read_table().pellet_count
-mypacman.level = read_table().level
-mypacman.spd = read_table().spd
-mypacman.board_num = read_table().board_num
-end
+dofile(minetest.get_modpath("mypacman").."/craftitems.lua")
+dofile(minetest.get_modpath("mypacman").."/ghost.lua")
+dofile(minetest.get_modpath("mypacman").."/blocks.lua")
+dofile(minetest.get_modpath("mypacman").."/portals.lua")
+dofile(minetest.get_modpath("mypacman").."/gamestate.lua")
+
--Yellow Pellets
minetest.register_node("mypacman:pellet_1", {
@@ -92,25 +35,7 @@ minetest.register_node("mypacman:pellet_1", {
})
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
- local name = digger:get_player_name()
- local pos = mypacman.start
- local schem = minetest.get_modpath("mypacman").."/schems/mypacman_3.mts"
- mypacman.pellet_count = mypacman.pellet_count + 1
- if mypacman.pellet_count >= 1 then --252
- remove_ghosts()
- minetest.chat_send_player(name, "You cleared the board!")
- mypacman.pellet_count = 0
- mypacman.level = mypacman.level + 1
- mypacman.spd = mypacman.level + 1
- minetest.after(3.0, function()
- local pos = mypacman.start
- digger:setpos({x=pos.x+13,y=pos.y+0.5,z=pos.z+15.5})
- minetest.chat_send_player(name, "Starting Level "..mypacman.level)
- minetest.sound_play("mypacman_beginning", {pos = pos,max_hear_distance = 40,gain = 10.0,})
- spawn_ghosts()
- end)
- minetest.place_schematic({x=pos.x,y=pos.y-1,z=pos.z-2},schem,0, "air", true)
- end
+ mypacman.on_player_got_pellet(digger)
end,
})
@@ -165,49 +90,7 @@ minetest.register_node("mypacman:block2",{
paramtype2 = "facedir",
light_source = 8,
groups = {cracky = 1},
-
-
-on_rightclick = function(pos, node, player, itemstack, pointed_thing)
-local schem = minetest.get_modpath("mypacman").."/schems/mypacman_3.mts"
- minetest.place_schematic({x=pos.x,y=pos.y-1,z=pos.z-2},schem,0, "air", true)
- mypacman.start = {x=pos.x, y=pos.y, z=pos.z}
- mypacman.pellet_count = 0
- mypacman.level = 1
- mypacman.spd = 2
- remove_ghosts()
- player:setpos({x=pos.x+14,y=pos.y+0.5,z=pos.z+16})
- mypacman.pellet_count = 0
- if mypacman.pellet_count >= 252 then
- remove_ghosts()
- end
- minetest.sound_play("mypacman_beginning", {pos = pos,max_hear_distance = 40,gain = 10.0,})
-
- minetest.after(2, function()
- minetest.add_entity({x=pos.x+13,y=pos.y+0.5,z=pos.z+19}, "mypacman:inky")
- end)
- minetest.after(12, function()
- minetest.add_entity({x=pos.x+15,y=pos.y+0.5,z=pos.z+19}, "mypacman:pinky")
- end)
- minetest.after(22, function()
- minetest.add_entity({x=pos.x+13,y=pos.y+0.5,z=pos.z+18}, "mypacman:blinky")
- end)
- minetest.after(32, function()
- minetest.add_entity({x=pos.x+15,y=pos.y+0.5,z=pos.z+18}, "mypacman:clyde")
- end)
-end,
+ on_rightclick = function(pos, node, player, itemstack, pointed_thing)
+ mypacman.game_start(pos, player)
+ end,
})
-
-
-dofile(minetest.get_modpath("mypacman").."/craftitems.lua")
-dofile(minetest.get_modpath("mypacman").."/ghost.lua")
-dofile(minetest.get_modpath("mypacman").."/blocks.lua")
-dofile(minetest.get_modpath("mypacman").."/portals.lua")
-
-
-
-
-
-
-
-
-