diff options
| -rwxr-xr-x | gamestate.lua | 170 | ||||
| -rw-r--r-- | ghost.lua | 212 | ||||
| -rw-r--r-- | init.lua | 141 | 
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) @@ -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 @@ -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") - - - - - - - - - | 
