Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[
- --*--*--*--*--*--*--*--*--*--*--*--*--*--*--
- --* SpaceShip Game *--
- --* https://pastebin.com/rW9x5QvX *--
- --* by: GravityCube and Archmaestro *--
- --*--*--*--*--*--*--*--*--*--*--*--*--*--*--
- Changelog:
- 1.0.0 First release
- --]]
- levels = {}
- levels[1] = {
- ["enemies"] = {
- [1]={
- ["entity_type"] = "enemy_1",
- ["spawn_rate"] = 2.5,
- ["x_velocity"] = 1.5,
- ["lives"] = 1,
- ["points"] = 50,
- }
- }
- }
- levels[2] = {
- ["enemies"] = {
- [1]={
- ["entity_type"] = "enemy_1",
- ["spawn_rate"] = 1.5,
- ["x_velocity"] = 1.5,
- ["lives"] = 1,
- ["points"] = 50,
- },
- [2]={
- ["entity_type"] = "enemy_2",
- ["entity_type"] = "enemy_2",
- ["spawn_rate"] = 1,
- ["x_velocity"] = 1.7,
- ["lives"] = 2,
- ["points"] = 150,
- ["bullets"] = {
- [1]={
- ["position"]={["x"]=-3,["y"]=0},
- ["speed"]=-2.5,
- ["rate"]=1,
- }
- }
- }
- }
- }
- levels[3] = {
- ["enemies"] = {
- [1]={
- ["entity_type"] = "enemy_2",
- ["spawn_rate"] = 1,
- ["x_velocity"] = 1.6,
- ["lives"] = 2,
- ["points"] = 150,
- ["bullets"] = {
- [1]={
- ["position"]={["x"]=-3,["y"]=0},
- ["speed"]=-2.5,
- ["rate"]=1,
- }
- }
- },
- [2]={
- ["entity_type"] = "enemy_3",
- ["spawn_rate"] = 1,
- ["x_velocity"] = 1.8,
- ["lives"] = 1,
- ["points"] = 200,
- ["bullets"] = {
- [1]={
- ["position"]={["x"]=-3,["y"]=2},
- ["speed"]=-2.5,
- ["rate"]=1,
- },
- [2]={
- ["position"]={["x"]=-3,["y"]=-2},
- ["speed"]=-2.5,
- ["rate"]=1,
- }
- }
- }
- }
- }
- levels[4] = {
- ["enemies"] = {
- [1]={
- ["entity_type"] = "enemy_1",
- ["spawn_rate"] = 2,
- ["x_velocity"] = 1.5,
- ["lives"] = 1,
- ["points"] = 50,
- ["bullets"] = {
- [1]={
- ["position"]={["x"]=-3,["y"]=0},
- ["speed"]=-2.5,
- ["rate"]=1,
- }
- }
- },
- [2]={
- ["entity_type"] = "enemy_3",
- ["spawn_rate"] = 1,
- ["x_velocity"] = 1.9,
- ["lives"] = 1,
- ["points"] = 200,
- ["bullets"] = {
- [1]={
- ["position"]={["x"]=-3,["y"]=2},
- ["speed"]=-2.5,
- ["rate"]=1,
- },
- [2]={
- ["position"]={["x"]=-3,["y"]=-2},
- ["speed"]=-2.5,
- ["rate"]=1,
- }
- }
- }
- }
- }
- levels[0] = {
- ["enemies"] = {
- [1]={
- ["entity_type"] = "boss_1",
- ["spawn_rate"] = 0,
- ["x_velocity"] = 20,
- ["lives"] = 100,
- ["points"] = 50000,
- ["position"] = {["x"]=0.5, ["y"] = 0.5}
- }
- }
- }
- --------------------------------------------------------
- --> Variables <--
- --------------------------------------------------------
- os.loadAPI("gcapi")
- os.loadAPI("mLink")
- os.loadAPI("ocs/apis/sensor")
- os.loadAPI("gameModels")
- os.loadAPI("bigMessages")
- os.loadAPI("CLKeysAPI")
- local score = 0
- local coins = 0
- local level = 1
- local entities = {}
- local args = {...}
- local player = (args[1] and args[1] ~= '' and args[1]) or 'pim'
- local pixelsUsed = {} -- {[x]={[y]={entityIDs}}}
- local clock = 0
- local pim = peripheral.find("pim")
- local mon = peripheral.wrap("top")
- mon.setTextScale(0.5)
- local max_x, max_y = mon.getSize()
- local mon2 = nil
- for _,pName in pairs(peripheral.getNames()) do
- if peripheral.getType(pName) == "monitor" then
- if pName ~= "top" then
- mon2 = peripheral.wrap(pName)
- end
- end
- end
- local s = nil
- for _,pName in pairs(peripheral.getNames()) do
- if peripheral.getType(pName) == "sensor" then
- s = sensor.wrap(pName)
- end
- end
- --------------------------------------------------------
- --> Player Cursor <--
- --------------------------------------------------------
- local isBlocking = false
- function getCursorPlayer(player)
- local targetDetails = s.getTargetDetails(player)
- if targetDetails then
- local pos = targetDetails["Position"]
- local yaw = targetDetails["Yaw"]
- local pitch = targetDetails["Pitch"]
- local x,y = mLink.getCursorPos(pos.X, pos.Y, pos.Z, yaw, pitch)
- local ib = targetDetails["IsBlocking"]
- if ib ~= isBlocking then
- os.queueEvent("blocking_event", player, x, y, ib)
- end
- isBlocking = ib
- return x, y
- end
- return -1, -1
- end
- function insideBoundaries(x,y)
- if x > max_x or y > max_y or x < 1 or y < 1 then
- return false
- end
- return true
- end
- function checkPlayer(player)
- if getCurrentPlayer() == player then
- return true
- end
- return false
- end
- function getCurrentPlayer()
- return pim.getInventoryName()
- end
- --------------------------------------------------------
- --> Entities <--
- --------------------------------------------------------
- Entity = {}
- Entity.__index = Entity
- function Entity.create(entity_type)
- local entity = {}
- setmetatable(entity,Entity)
- entity.team = 2
- entity.velocity = {["x"]=0, ["y"]=0}
- entity.position = {["x"]=1, ["y"]=math.floor(max_y/2)}
- entity.state = "hidden"
- entity.type = entity_type
- entity.lives = 1
- entity.god_time = 6
- entity.deathEvents = {}
- entity.crashEvents = {}
- entity.pixels = gameModels.getModel(entity_type)
- return entity
- end
- function Entity:getPos()
- local pos = self.position
- return pos.x, pos.y
- end
- function Entity:setPos(x,y)
- self.position.x = x
- self.position.y = y
- end
- function Entity:deathEvent()
- self.state = "dead"
- if self.points then
- score = score + self.points
- end
- for _,event in pairs(self.deathEvents) do
- event(self)
- end
- end
- function Entity:update()
- local sState = string.split(self.state .. "_", "_")
- if sState[1] == "god" then
- local t = tonumber(sState[2]) - 1
- self:setState("god_" .. t)
- if t == 0 then
- self:setState("active")
- end
- end
- if self.bullets or self.bullet then
- self:shoot()
- end
- if self.state == "active" or sState[1] == "god" then
- self:updateMovement()
- end
- end
- function Entity:crashEvent()
- self.lives = self.lives - 1
- self.state = "god_" .. tostring(self.god_time)
- for _,event in pairs(self.crashEvents) do
- event(self)
- end
- if self.lives == 0 then
- self:deathEvent()
- end
- end
- function Entity:updateMovement()
- local xo, yo = self:getPos()
- local vx, vy = self:getVelocity()
- local nx = xo + vx
- local ny = yo + vy
- --Collision with wall (x)
- if ny > max_y or ny < 1 then
- self:setVelocity(vx,-vy)
- ny = yo - vy
- end
- if not insideBoundaries(nx,ny) then
- self:deathEvent()
- end
- self:setPos(xo+vx, yo+vy)
- end
- function Entity:getVelocity()
- local vel = self.velocity
- return vel.x, vel.y
- end
- function Entity:setVelocity(x,y)
- self.velocity.x = x
- self.velocity.y = y
- end
- function Entity:setState(state)
- self.state = state
- end
- local noPixels = {}
- function Entity:getPixels()
- local sState = string.split(self.state .. "_", "_")
- if sState[1] == "god" then
- if tonumber(sState[2]) % 2 == 0 then
- return gameModels.models.blackDot
- end
- end
- local pixels = self.pixels
- if pixels then
- return pixels
- end
- return noPixels
- end
- function updateEntities()
- dead_entities = {}
- for i,entity in pairs(entities) do
- entity:update()
- if entity.state == "dead" and entity.type ~= "player" then
- table.insert(dead_entities, i)
- end
- end
- for _,i in pairs(dead_entities) do
- entities[i] = nil
- end
- end
- function checkCollisions()
- for x,y_list in pairs(pixelsUsed) do
- for y, id_list in pairs(y_list) do
- if #id_list > 1 and not sameTeam(id_list) then
- for _,i in pairs(id_list) do
- local entity = entities[i]
- if entity then
- entity.state = "crashed"
- end
- end
- end
- end
- end
- for _,entity in pairs(entities) do
- if entity.state == "crashed" then
- entity:crashEvent()
- end
- end
- end
- function sameTeam(id_list)
- local teams = {}
- for _,i in pairs(id_list) do
- local entity = entities[i]
- if entity then
- local team = entity.team
- if not table.contains(teams, team) then
- table.insert(teams,team)
- end
- end
- end
- if #teams > 1 then
- return false
- end
- return true
- end
- --------------------------------------------------------
- --> Player SpaceShip <--
- --------------------------------------------------------
- SpaceShip = setmetatable({}, {__index = Entity})
- SpaceShip.__index = SpaceShip
- function SpaceShip.create()
- local self = setmetatable(Entity.create("player"), SpaceShip)
- self.state = "active"
- self.lives = 5
- self.god_time = 10
- self.team = 1
- self.max_velocity = 2.4
- self.bullet = {}
- self.bullet.type = "bullet"
- self.bullet.speed = 2.5
- self.bullet.rate = 5 -- x per sec
- return self
- end
- function SpaceShip:updateMovement()
- local x, y = getCursorPlayer(player)
- if not insideBoundaries(x,y) then return end
- --[[
- local max_velocity = self.max_velocity
- local xo, yo = self:getPos()
- local max_velocity2 = max_velocity^2
- local dx2 = (x-xo)^2
- local dy2 = (y-yo)^2
- if dx2 + dy2 > max_velocity2 then
- local p = (max_velocity2/(dx2 + dy2) )^0.5
- x = ((x-xo) * p) + xo
- y = ((y-yo) * p) + yo
- end--]]
- self:setPos(x,y)
- end
- function SpaceShip:shoot()
- if not (math.floor(clock % (20/self.bullet.rate)) == 0) then return end
- local x,y = self:getPos()
- local vx = self.bullet.speed
- local bullet = Bullet.create(x+5,y,vx,1, true)
- local crashEvent = function ()
- killSound()
- end
- table.insert(bullet.crashEvents, crashEvent)
- table.insert(entities, bullet)
- end
- function SpaceShip:setBulletSpeed(speed)
- self.bullet.speed = speed
- end
- function SpaceShip:setBulletType(bullet_type)
- self.bullet.type = bullet_type
- end
- --------------------------------------------------------
- --> Bullet Entity <--
- --------------------------------------------------------
- Bullet = setmetatable({}, {__index = Entity})
- Bullet.__index = Bullet
- function Bullet.create(x, y, vx, team, fromPlayer)
- local entity_type = "bullet"
- if fromPlayer then
- entity_type = "player_bullet"
- end
- local self = setmetatable(Entity.create(entity_type), Bullet)
- self.state = "active"
- self.team = team
- self.velocity.x = vx
- self.position.x = x
- self.position.y = y
- return self
- end
- --------------------------------------------------------
- --> Sound <--
- --------------------------------------------------------
- local nb = peripheral.find("music")
- function killSound()
- nb.playSound("random.pop",1,1)
- end
- function playSound(sound_name)
- nb.playSound(sound_name,1,1)
- end
- --------------------------------------------------------
- --> ScoreBar <--
- --------------------------------------------------------
- function updateScoreBar(ss)
- local mon = mon2
- if not mon then return end
- mon2.setTextScale(1.8)
- mon.setBackgroundColor(colors.black)
- mon.clear()
- local max_x, max_y = mon.getSize()
- local lives = ss.lives
- local levelText = 'Level ' .. tostring(level)
- mon.setCursorPos(gcapi.getCenter(max_x, levelText),1)
- mon.write(levelText)
- local scoreText = 'Score ' .. tostring(score)
- mon.setCursorPos(gcapi.getCenter(max_x, scoreText),2)
- mon.write(scoreText)
- mon.setCursorPos(1,3)
- mon.write('Lives ')
- for i=1, lives do
- mon.setBackgroundColor(colors.black)
- mon.write(' ')
- mon.setBackgroundColor(colors.red)
- mon.write(' ')
- end
- end
- --------------------------------------------------------
- --> BigButtons <--
- --------------------------------------------------------
- local buttons = {}
- for x=1, max_x do
- buttons[x] = {}
- end
- Button = {}
- Button.__index = Button
- function Button.create(corner1, corner2, func)
- local button = {}
- setmetatable(button,Button)
- button.func = func
- for x=corner1.x, corner2.x do
- for y=corner1.y, corner2.y do
- buttons[x][y] = button
- end
- end
- return button
- end
- function buttonListener(tEvent)
- if tEvent[1] == "blocking_event" then
- local player = tEvent[2]
- local x = tEvent[3]
- local y = tEvent[4]
- local pushed = tEvent[5]
- if not pushed then
- return
- end
- local button = buttons[x][y]
- if button then
- playSound("random.click")
- button.func()
- end
- end
- end
- --------------------------------------------------------
- --> ScoreBoard <--
- --------------------------------------------------------
- local scoreboard = {}
- function loadScoreboard()
- prizes = gcapi.getListFromFile("/disk/scoreboard")
- end
- function saveScoreboard()
- gcapi.saveListToFile("/disk/scoreboard", prizes)
- end
- function addNewScore(nick, score)
- loadScoreboard()
- if not scoreboard[nick] or scoreboard[nick] < score then
- scoreboard[nick] = score
- saveScoreboard()
- return true
- end
- return false
- end
- function scoreMenu()
- local time = os.clock() + 10
- while true do
- local seconds = math.floor(time - os.clock())
- if seconds < 0 then break end
- cleanScreen()
- bigMessages.displayMessage(mon, "Save your score using", colors.red, nil, gcapi.getCenter(max_y, 5)-4)
- bigMessages.displayMessage(mon, "!save <nickname>", colors.red, nil, gcapi.getCenter(max_y, 5)+2)
- bigMessages.displayMessage(mon, "You have " .. seconds .. " seconds.", colors.red, nil, gcapi.getCenter(max_y, 5)+8)
- tEvent = {os.pullEvent()}
- if tEvent[1] == "chatEvent" then
- local player = tEvent[2]
- if checkPlayer(player) then
- local co = tEvent[3]
- local command = gcapi.split(co .. " ", " ")
- if command[1] == "save" then
- local nick = command[2]
- if command[2] and command[2] ~= '' then
- addNewScore(nick, score)
- break
- else
- displayError("You need to specify a nickname")
- sleep(2)
- end
- end
- if command[1] == "skip" then break end
- end
- end
- end
- end
- --------------------------------------------------------
- --> Monitor <--
- --------------------------------------------------------
- mon.setTextColor(colors.black)
- function cleanScreen()
- mon.setBackgroundColor(colors.white)
- mon.clear()
- end
- function printMenu()
- cleanScreen()
- bigMessages.displayMessage(mon, "Space Invaders", colors.magenta, nil, gcapi.getCenter(max_y, 5)-2)
- if player ~= "pim" then
- bigMessages.displayMessage(mon, "Start with !play", colors.cyan, nil, gcapi.getCenter(max_y, 5)+4)
- else
- bigMessages.displayMessage(mon, "Stand in the PIM", colors.cyan, nil, gcapi.getCenter(max_y, 5)+4)
- end
- mon.setBackgroundColor(colors.white)
- local infoMessage = "NOTE: By using this machine and writing !play you acknowledge that your keys will be deducted from your inventory"
- mon.setTextColor(colors.black)
- mon.setCursorPos(gcapi.getCenter(max_x, infoMessage), max_y-1)
- mon.write(infoMessage)
- end
- function displayError(err)
- cleanScreen()
- bigMessages.displayMessage(mon, err, colors.red)
- end
- function updateGameScreen()
- cleanScreen()
- pixelsUsed = {}
- for i, entity in pairs(entities) do
- local xo, yo = entity:getPos()
- for a,pixel in pairs(entity:getPixels()) do
- local x = math.floor(pixel.x + xo)
- local y = math.floor(pixel.y + yo)
- mon.setBackgroundColor(pixel.color)
- mon.setCursorPos(x, y)
- mon.write(" ")
- if (entity.state == "active") then
- addToPixel(x, y, i)
- end
- end
- end
- end
- function addToPixel(x, y, i)
- if not pixelsUsed[x]then
- pixelsUsed[x] = {}
- end
- id_list = pixelsUsed[x][y]
- if not id_list then
- pixelsUsed[x][y] = {i}
- return
- end
- table.insert(id_list, i)
- end
- --------------------------------------------------------
- --> Game functions <--
- --------------------------------------------------------
- function spawnEnemies(level)
- for _,enemy_settings in pairs(levels[level].enemies) do
- if (math.floor(clock % (20/enemy_settings.spawn_rate)) == 0) then
- local vx = -enemy_settings.x_velocity
- local vy = (gcapi.getRandom(4, 9)/10)
- if gcapi.getRandom(1,2) == 1 then
- vy = -vy
- end
- local enemy = Entity.create(enemy_settings.entity_type)
- local x = max_x
- local y = gcapi.getRandom(1,max_y)
- local position = enemy_settings.position
- if position then
- if position.x then
- x = max_x*position.x
- end
- if position.y then
- y = max_y*position.y
- end
- end
- enemy:setPos(x, y)
- enemy:setVelocity(vx, vy)
- enemy.lives = enemy_settings.lives
- enemy:setState("active")
- enemy.points = enemy_settings.points
- local bullets = enemy_settings.bullets
- if bullets then
- enemy.bullets = bullets
- enemy.shoot = function (self)
- for _,bullet in pairs(self.bullets) do
- if (math.floor(clock % (20/bullet.rate)) == 0) then
- local x,y = self:getPos()
- local pos = bullet.position
- local vx = bullet.speed
- local bullet = Bullet.create(x+pos.x,y+pos.y,vx,2)
- table.insert(entities, bullet)
- end
- end
- end
- end
- table.insert(entities, enemy)
- end
- end
- end
- function startGame()
- parallel.waitForAny(startGameThread, gameListener)
- end
- function startGameThread()
- mon.setBackgroundColor(colors.white)
- mon.clear()
- entities = {}
- score = 0
- local spaceShip = SpaceShip:create("player")
- spaceShip:setState("active")
- table.insert(entities, spaceShip)
- level = 1
- local levelChangeScore = 0
- while spaceShip.state ~= "dead" do
- if player ~= "pim" then
- if score - levelChangeScore > 2000 and levels[level+1] then
- level = level + 1
- levelChangeScore = score
- playSound("random.levelup")
- end
- spawnEnemies(level)
- updateEntities()
- updateGameScreen()
- checkCollisions()
- updateScoreBar(spaceShip)
- sleep(0.05)
- clock = clock + 1
- else
- bigMessages.displayMessage(mon, "Pause", colors.magenta)
- sleep(1)
- end
- end
- bigMessages.displayMessage(mon, "You are dead!", colors.red)
- sleep(2.5)
- end
- function gameListener()
- while true do
- tEvent = {os.pullEvent()}
- if tEvent[1] == "player_on" then
- player = pim.getInventoryName()
- elseif tEvent[1] == "player_off" then
- player = pim.getInventoryName()
- elseif tEvent[1] == "blocking_event" then
- local player = tEvent[2]
- local x = tEvent[3]
- local y = tEvent[4]
- local state = tEvent[5]
- end
- end
- end
- --------------------------------------------------------
- --> Menu functions <--
- --------------------------------------------------------
- function insertCoin()
- local qty, err = CLKeysAPI.moveKeysToSystem(1)
- if qty == 1 then
- return true
- else
- return false, err
- end
- end
- function menuListener()
- sleep(1)
- printMenu()
- player = pim.getInventoryName()
- while true do
- tEvent = {os.pullEvent()}
- if tEvent[1] == "player_on" then
- player = pim.getInventoryName()
- if not CLKeysAPI then
- print(player .. " started a game")
- startGame()
- end
- printMenu()
- elseif tEvent[1] == "player_off" then
- player = pim.getInventoryName()
- printMenu()
- elseif tEvent[1] == "chatEvent" then
- local player = tEvent[2]
- co = tEvent[3]
- if checkPlayer(player) then
- if co == "play" then
- if insertCoin() then
- print(player .. " started a game")
- startGame()
- scoreMenu()
- printMenu()
- else
- displayError("You dont have enough keys!")
- print(player .. " doesnt have enough keys")
- sleep(4)
- printMenu()
- end
- end
- end
- end
- end
- end
- parallel.waitForAny(menuListener, gcapi.startChatEventQueue)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement