--LUA Script - precede every function and global member with lowercase name of script + '_main' --DESCRIPTION: smallg's breakout script --DESCRIPTION: [PLAY!=0] --DESCRIPTION: [LEVEL=1(1,99)] (i.e. level_01.txt) --DESCRIPTION: [GAMESPEED=10] --DESCRIPTION: [STARTINGLIVES=1(1,9)] --DESCRIPTION: [SCOREPERBLOCK=10] --DESCRIPTION: [BLOCKWIDTH=1(1,10)] --DESCRIPTION: [BLOCKHEIGHT=1(1,10)] --DESCRIPTION: [PLAYERWIDTH=10(1,99]] --DESCRIPTION: [PLAYERHEIGHT=5(1,20)] --DESCRIPTION: [BALLWIDTH=1] --DESCRIPTION: [BALLHEIGHT=1] --DESCRIPTION: [OVERLAYX=0] --DESCRIPTION: [OVERLAYY=0] --DESCRIPTION: [OVERLAYWIDTH=100] --DESCRIPTION: [OVERLAYHEIGHT=100] --DESCRIPTION: [SCOREX=50] (score is centered on this position) --DESCRIPTION: [SCOREY=10] --DESCRIPTION: [SCORESIZE=5] --DESCRIPTION: [LIVESX=70] --DESCRIPTION: [LIVESY=10] --DESCRIPTION: [LIVESWIDTH=5] --DESCRIPTION: [LIVESHEIGHT=5] --DESCRIPTION: [CLOSEX=80] --DESCRIPTION: [CLOSEY=0] --DESCRIPTION: [CLOSEWIDTH=5] --DESCRIPTION: [CLOSEHEIGHT=5] --DESCRIPTION: [CURSORWIDTH=3] --DESCRIPTION: [CURSORHEIGHT=3] --DESCRIPTION: [PLAYAREAX1=8] --DESCRIPTION: [PLAYAREAY1=8] --DESCRIPTION: [PLAYAREAX2=92] --DESCRIPTION: [PLAYAREAY2=65] --DESCRIPTION: [SHOWPLAYAREA!=0] --DESCRIPTION: [USEPROMPT$="PLAY BREAKOUT (E)"] --DESCRIPTION: [USERANGE=130] --DESCRIPTION: [USEANGLE=25(5,180)] --DESCRIPTION: (How to make your own levels) --DESCRIPTION: (save your levels in "scriptbank\\smallg\\images\\breakout\\") --DESCRIPTION: (file name = "level_" followed by the level number") --DESCRIPTION: (i.e. "level_01.txt" is level 1, "level_25.txt" is level 25 etc) --DESCRIPTION: (to make new levels use a text file and fill with the health) --DESCRIPTION: (of each block in that row - i.e.) --DESCRIPTION: (0011100 = 2 blank spaces followed by 3 x blocks with 1 HP followed by 2 blank spaces) --DESCRIPTION: (Power ups = replace numbers with letters to change gameplay when hit) --DESCRIPTION: (use L to add extra life, B to add extra ball, S to speed up game, D to slow down game) --DESCRIPTION: (sounds: 0 = bounce, 1 = win, 2 = lose) U = U or require "scriptbank\\utillib" local timer, blockhealth, balls, ballx, bally, blockx, blocky, lives, speed, blocktype, ballvx, ballvy, score, playerx, playery, currentlevel = {},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{} g_breakout = {} local mouse, pressE, levelfile, blocksinarow, filelines = false, false, "", 0, 0 local overlayimg, cursorimg, closeimg, playerimg, livesimg, ballimg local increasespeedimg, decreasespeedimg, extralifeimg, extraballimg local overlayspr, cursorspr, closespr, playerspr, livesspr local blockimg = {} local ballspr, blockspr = {},{} local blocksremaining, newspeed = 0,0 function breakout_properties(e, play, level, gamespeed, startinglives, scoreperblock, blockwidth, blockheight, playerwidth, playerheight, ballwidth, ballheight, overlayx, overlayy, overlaywidth, overlayheight, scorex, scorey, scoresize, livesx, livesy, liveswidth, livesheight, closex, closey, closewidth, closeheight, cursorwidth, cursorheight, playareax1, playareay1, playareax2, playareay2, showplayarea, useprompt, userange, useangle) local b = g_breakout[e] b.play = play b.level = level b.gamespeed = gamespeed b.startinglives = startinglives b.scoreperblock = scoreperblock b.blockwidth = blockwidth b.blockheight = blockheight b.playerwidth = playerwidth b.playerheight = playerheight b.ballwidth = ballwidth b.ballheight = ballheight b.overlayx = overlayx b.overlayy = overlayy b.overlaywidth = overlaywidth b.overlayheight = overlayheight b.scorex = scorex b.scorey = scorey b.scoresize = scoresize b.livesx = livesx b.livesy = livesy b.liveswidth = liveswidth b.livesheight = livesheight b.closex = closex b.closey = closey b.closewidth = closewidth b.closeheight = closeheight b.cursorwidth = cursorwidth b.cursorheight = cursorheight b.playareax1 = playareax1 b.playareay1 = playareay1 b.playareax2 = playareax2 b.playareay2 = playareay2 b.showplayarea = showplayarea b.useprompt = useprompt b.userange = userange b.useangle = useangle end function breakout_init(e) g_breakout[e] = {} local b = g_breakout[e] b.play = 0 b.level = 1 b.gamespeed = 10 b.startinglives = 1 b.scoreperblock = 10 b.blockwidth = 10 b.blockheight = 10 b.playerwidth = 10 b.playerheight = 2 b.ballwidth = 3 b.ballheight = 1 b.overlayx = 0 b.overlayy = 0 b.overlaywidth = 100 b.overlayheight = 100 b.scorex = 50 b.scorey = 10 b.scoresize = 5 b.livesx = 70 b.livesy = 10 b.liveswidth = 5 b.livesheight = 5 b.closex = 80 b.closey = 10 b.closewidth = 5 b.closeheight = 5 b.cursorwidth = 3 b.cursorheight = 3 b.playareax1 = 8 b.playareay1 = 8 b.playareax2 = 92 b.playareay2 = 65 b.showplayarea = 1 b.useprompt = "Play Breakout? (E)" b.userange = 130 b.useangle = 25 timer[e] = {} blockhealth[e] = {} ballx[e] = {} bally[e] = {} ballvx[e] = {} ballvy[e] = {} blockx[e] = {} blocky[e] = {} blocktype[e] = {} end function breakout_main(e) local function file_exists(name) local f=io.open(name,"r") if f~=nil then io.close(f) return true else return false end end local function MoveOffScreen(v) SetSpritePosition(v, 2000, 2000) end local function lines_from(file) local function file_exists(name) local f=io.open(name,"r") if f~=nil then io.close(f) return true else return false end end if not file_exists(file) then return {} end lines = {} for line in io.lines(file) do lines[#lines + 1] = line end return lines end local function CleanUp(e) local b = g_breakout[e] DeleteImage(overlayimg) DeleteImage(cursorimg) DeleteImage(closeimg) DeleteImage(livesimg) DeleteImage(playerimg) DeleteImage(ballimg) DeleteImage(extraballimg) DeleteImage(extralifeimg) DeleteImage(increasespeedimg) DeleteImage(decreasespeedimg) for a = 1, #blockimg do DeleteImage(blockimg[a]) end DeleteSprite(overlayspr) DeleteSprite(playerspr) DeleteSprite(closespr) DeleteSprite(livesspr) DeleteSprite(cursorspr) for a = 1, balls[e] do DeleteSprite(ballspr[a]) end for x = 1, blocksinarow do for y = 1, #filelines do DeleteSprite(blockspr[x][y]) end end end local function UpdateGame(e,v) local b = g_breakout[e] if b.showplayarea == 1 then Text(b.playareax1, b.playareay1, 3, "+") Text(b.playareax1, b.playareay2, 3, "+") Text(b.playareax2, b.playareay1, 3, "+") Text(b.playareax2, b.playareay2, 3, "+") end local mx, my = g_MouseX, g_MouseY PasteSpritePosition(overlayspr, b.overlayx, b.overlayy) PasteSpritePosition(closespr, b.closex, b.closey) if v ~= 0 then playerx[e] = mx - (b.playerwidth / 2) if playerx[e] < b.playareax1 then playerx[e] = b.playareax1 elseif playerx[e] + b.playerwidth > b.playareax2 then playerx[e] = b.playareax2 - b.playerwidth end end PasteSpritePosition(playerspr, playerx[e], playery[e]) --position the blocks for x = 1, blocksinarow do for y = 1, #filelines do PasteSpritePosition(blockspr[x][y], blockx[e][x][y], blocky[e][x][y]) --TextCenterOnX(blockx[e][x][y], blocky[e][x][y], 5, blocktype[e][x][y]) end end for a = 1, balls[e] do --move the balls if math.abs(ballvx[e][a]) + math.abs(ballvy[e][a]) > 1 then local xperc = ballvx[e][a] / 1 local yperc = ballvy[e][a] / 1 repeat ballvx[e][a] = ballvx[e][a] - (0.01 * xperc) ballvy[e][a] = ballvy[e][a] - (0.01 * yperc) until math.abs(ballvx[e][a]) + math.abs(ballvy[e][a]) < 1 end --TextCenterOnX(50,75,4,ballvx[e][a].." , "..ballvy[e][a]) ballx[e][a] = ballx[e][a] + (ballvx[e][a] * speed[e]) * v bally[e][a] = bally[e][a] + (ballvy[e][a] * speed[e]) * v local bx1 = ballx[e][a] local bx2 = bx1 + b.ballwidth local by1 = bally[e][a] local by2 = by1 + b.ballheight local bcx = bx1 + (b.ballwidth / 2) local bcy = by1 + (b.ballheight / 2) --check the blocks local hitblock = false local function Get2DDistance(x1,y1,x2,y2) local x3,y3 = x1-x2, y1-y2 return (x3*x3)+(y3*y3) end for x = 1, blocksinarow do if hitblock == true then break end for y = 1, #filelines do local blx1 = blockx[e][x][y] local bly1 = blocky[e][x][y] local blx2 = blx1 + b.blockwidth local bly2 = bly1 + b.blockheight if bcx >= blx1-1 and bcx <= blx2+1 and bcy >= bly1-1 and bcy <= bly2+1 then --check which part of block we hit --bottom local x3 = blx1 + (b.blockwidth / 2) local y3 = bly2 local dist = {} dist[1] = Get2DDistance(bcx,bcy,x3,y3) --top x3 = x3 y3 = bly1 dist[2] = Get2DDistance(bcx,bcy,x3,y3) --left x3 = blx1 y3 = bly1 + (b.blockheight / 2) dist[3] = Get2DDistance(bcx,bcy,x3,y3) --right x3 = blx2 y3 = y3 dist[4] = Get2DDistance(bcx,bcy,x3,y3) local mdist = 999999 local closest = 0 for a = 1, 4 do if dist[a] < mdist then closest = a mdist = dist[a] end end if closest > 0 then PlaySound(e,0) score[e] = score[e] + b.scoreperblock if closest == 1 then --bottom if ballvy[e][a] < 0 then ballvy[e][a] = ballvy[e][a] * -1 end --PromptDuration("bottom",20000) --speed[e] = 0.1 elseif closest == 2 then --top if ballvy[e][a] > 0 then ballvy[e][a] = ballvy[e][a] * -1 end --PromptDuration("top",20000) --speed[e] = 0.1 elseif closest == 3 then --left if ballvx[e][a] > 0 then ballvx[e][a] = ballvx[e][a] * -1 end --PromptDuration("left",20000) --speed[e] = 0.1 else if ballvx[e][a] < 0 then ballvx[e][a] = ballvx[e][a] * -1 end --PromptDuration("right",20000) --speed[e] = 0.1 end if blockhealth[e][x][y] > 0 then local bt = blocktype[e][x][y] if bt == "L" then --SetSpriteImage(bs, extralifeimg) lives[e] = lives[e] + 1 blockx[e][x][y] = 2000 blocky[e][x][y] = 2000 blockhealth[e][x][y] = 0 blocksremaining = blocksremaining - 1 elseif bt == "B" then --SetSpriteImage(bs, extraballimg) balls[e] = balls[e] + 1 ballspr[balls[e]] = CreateSprite(ballimg) SetSpriteSize(ballspr[balls[e]], b.ballwidth, b.ballheight) MoveOffScreen(ballspr[balls[e]]) ballx[e][balls[e]] = blx1 + (b.blockwidth * 0.5) - (b.ballwidth * 0.5) bally[e][balls[e]] = bly1 + (b.blockheight * 0.5) - (b.ballwidth * 0.5) ballvx[e][balls[e]] = ballvx[e][a] ballvy[e][balls[e]] = ballvy[e][a] blockx[e][x][y] = 2000 blocky[e][x][y] = 2000 blockhealth[e][x][y] = 0 blocksremaining = blocksremaining - 1 elseif bt == "S" then --SetSpriteImage(bs, increasespeedimg) speed[e] = speed[e] + (newspeed * 0.25) if speed[e] > newspeed * 2 then speed[e] = newspeed * 2 end blockx[e][x][y] = 2000 blocky[e][x][y] = 2000 blockhealth[e][x][y] = 0 blocksremaining = blocksremaining - 1 elseif bt == "D" then speed[e] = speed[e] - (newspeed * 0.25) if speed[e] < newspeed * 0.5 then speed[e] = newspeed * 0.5 end blockx[e][x][y] = 2000 blocky[e][x][y] = 2000 blockhealth[e][x][y] = 0 blocksremaining = blocksremaining - 1 --SetSpriteImage(bs, decreasespeedimg) else blockhealth[e][x][y] = blockhealth[e][x][y] - 1 blocktype[e][x][y] = blockhealth[e][x][y] if blockhealth[e][x][y] < 1 then blockx[e][x][y] = 2000 blocky[e][x][y] = 2000 blocksremaining = blocksremaining - 1 else bt = blocktype[e][x][y] bt = tonumber(bt) local bs = blockspr[x][y] for a = 1, #blockimg do if bt <= a then SetSpriteImage(bs, blockimg[a]) break end end end end end hitblock = true break end end end end --check the player hits the ball if ballvy[e][a] > 0 then if bcx >= playerx[e] and bcx <= playerx[e] + b.playerwidth and by2 > playery[e] then local xvelochange = math.random(1,10) xvelochange = xvelochange - 5 xvelochange = xvelochange / 100 ballvx[e][a] = ballvx[e][a] * (1-xvelochange) ballvy[e][a] = ballvy[e][a] * -1 PlaySound(e,0) local temp = bally[e][a] repeat temp = temp - 0.01 until temp < playery[e] + (b.playerheight * 0.5) bally[e][a] = temp end end --check game boundaries if bx1 <= b.playareax1 then if ballvx[e][a] < 0 then ballvx[e][a] = ballvx[e][a] * -1 end ballx[e][a] = b.playareax1 elseif bx2 >= b.playareax2 then if ballvx[e][a] > 0 then ballvx[e][a] = ballvx[e][a] * -1 end ballx[e][a] = b.playareax2 - b.ballwidth end if by1 <= b.playareay1 then if ballvy[e][a] < 0 then ballvy[e][a] = ballvy[e][a] * -1 end bally[e][a] = b.playareay1 elseif by2 >= b.playareay2 then if ballvy[e][a] > 0 then lives[e] = lives[e] - 1 if lives[e] < 1 then PlaySound(e,2) b.play = 3 timer[e][2] = GetTimer(e) + 2001 end end if ballvy[e][a] > 0 then ballvy[e][a] = ballvy[e][a] * -1 end bally[e][a] = b.playareay2 - b.ballheight end PasteSpritePosition(ballspr[a], ballx[e][a], bally[e][a]) end --Prompt(blocksinarow) PasteSpritePosition(livesspr, b.livesx, b.livesy) Text(b.livesx + b.liveswidth + 1, b.livesy, b.scoresize, "x"..lives[e]) TextCenterOnX(b.scorex, b.scorey, b.scoresize, score[e]) end local b = g_breakout[e] if b.play == 0 then if U.PlayerLookingNear(e, b.userange, b.useangle) == true then PromptLocal(e, b.useprompt) if g_KeyPressE == 1 then if not pressE then pressE = true b.play = 1 end else pressE = false end end elseif b.play == 1 then local imagepath = "scriptbank\\smallg\\images\\breakout\\" --create the GUI --load game images overlayimg = LoadImage(imagepath.."overlay.png") cursorimg = LoadImage(imagepath.."cursor.png") closeimg = LoadImage(imagepath.."close.png") livesimg = LoadImage(imagepath.."lives.png") playerimg = LoadImage(imagepath.."player.png") ballimg = LoadImage(imagepath.."ball.png") extraballimg = LoadImage(imagepath.."extraball.png") extralifeimg = LoadImage(imagepath.."extralife.png") increasespeedimg = LoadImage(imagepath.."increasespeed.png") decreasespeedimg = LoadImage(imagepath.."decreasespeed.png") local temp = 0 for a = 1, 9 do local fn = imagepath.."block_00" fn = fn..a..".png" if file_exists(fn) == true then temp = temp + 1 blockimg[temp] = LoadImage(fn) end end --create the game sprites overlayspr = CreateSprite( overlayimg ) SetSpriteSize( overlayspr, b.overlaywidth, b.overlayheight ) SetSpriteDepth( overlayspr, 99 ) MoveOffScreen( overlayspr ) playerspr = CreateSprite( playerimg ) SetSpriteSize( playerspr, b.playerwidth, b.playerheight ) SetSpriteDepth( playerspr, 10 ) MoveOffScreen( playerspr ) closespr = CreateSprite( closeimg ) SetSpriteSize( closespr, b.closewidth, b.closeheight ) SetSpriteDepth( closespr, 5 ) MoveOffScreen( closespr ) livesspr = CreateSprite( livesimg ) SetSpriteSize( livesspr, b.liveswidth, b.livesheight ) SetSpriteDepth( livesspr, 5 ) MoveOffScreen( livesspr ) cursorspr = CreateSprite( cursorimg ) SetSpriteSize( cursorspr, b.cursorwidth, b.cursorheight ) SetSpriteDepth( cursorspr, 0 ) MoveOffScreen( cursorspr ) SetFreezePosition(g_PlayerPosX, g_PlayerPosY, g_PlayerPosZ) SetFreezeAngle(g_PlayerAngX, g_PlayerAngY, g_PlayerAngZ) lives[e] = b.startinglives balls[e] = 1 newspeed = b.gamespeed / 10 speed[e] = newspeed score[e] = 0 playerx[e] = ((b.playareax2 - b.playareax1) / 2) + b.playareax1 - (b.playerwidth / 2) playery[e] = b.playareay2 - b.playerheight for a = 1, balls[e] do ballx[e][a] = ((b.playareax2 - b.playareax1) / 2) + b.playareax1 - (b.ballwidth / 2) bally[e][a] = playery[e] - b.ballheight local tx = math.random(1,2) if tx == 1 then tx = -1 else tx = 1 end local tx2 = 0 repeat tx2 = math.random(1,100)/100 until tx2 < -0.5 or tx2 > 0.5 tx = tx * tx2 ty = 1 * (math.random(70,100)/100) ballvx[e][a] = tx ballvy[e][a] = ty ballspr[a] = CreateSprite(ballimg) SetSpriteSize( ballspr[a], b.ballwidth, b.ballheight ) SetSpriteDepth( ballspr[a], 50 ) SetSpriteOffset( ballspr[a], b.ballwidth / 2, -1 ) SetSpriteSize( ballspr[a], b.ballwidth, -1 ) MoveOffScreen( ballspr[a] ) end --create the level currentlevel[e] = b.level local tries = 0 local gotlevel = false repeat fn = "scriptbank\\smallg\\images\\breakout\\level_" if currentlevel[e] < 10 then fn = fn.."0" end fn = fn..currentlevel[e]..".txt" if file_exists(fn) == true then gotlevel = true else currentlevel[e] = currentlevel[e] + 1 if currentlevel[e] > 99 then currentlevel[e] = 1 end tries = tries + 1 end until gotlevel == true or tries > 99 if tries > 99 then b.play = -99 return else levelfile = fn local bx = b.playareax1 filelines = lines_from(levelfile) blocksinarow = string.len(filelines[1]) if blocksinarow > 0 then bx = bx + (blocksinarow * b.blockwidth) if bx >= b.playareax2 then repeat b.blockwidth = b.blockwidth - 0.01 b.blockheight = b.blockheight - 0.01 bx = b.playareax1 bx = bx + (blocksinarow * b.blockwidth) until bx < b.playareax2 end bx = b.playareax1 local by = b.playareay1 for x = 1, blocksinarow do blockspr[x] = {} if blockhealth[e][x] == nil then blockhealth[e][x] = {} end blocktype[e][x] = {} if blockx[e][x] == nil then blockx[e][x] = {} blocky[e][x] = {} end for y = 1, #filelines do blockx[e][x][y] = bx + ((x-1) * b.blockwidth) blocky[e][x][y] = by + ((y-1) * b.blockheight) blockspr[x][y] = CreateSprite(blockimg[1]) local bs = blockspr[x][y] SetSpriteDepth( bs, 50 ) SetSpriteSize( bs, b.blockwidth, b.blockheight ) blocktype[e][x][y] = string.sub(filelines[y],x,x) local bt = blocktype[e][x][y] --(use L to add extra life, B to add extra ball, S to speed up game, D to slow down game) blockhealth[e][x][y] = 1 if bt == "L" then SetSpriteImage(bs, extralifeimg) elseif bt == "B" then SetSpriteImage(bs, extraballimg) elseif bt == "S" then SetSpriteImage(bs, increasespeedimg) elseif bt == "D" then SetSpriteImage(bs, decreasespeedimg) else bt = tonumber(bt) blockhealth[e][x][y] = bt if bt == 0 then blockx[e][x][y] = 2000 blocky[e][x][y] = 2000 blocksremaining = blocksremaining - 1 else for a = 1, #blockimg do if bt <= a then SetSpriteImage(bs, blockimg[a]) break end end end end blocksremaining = blocksremaining + 1 SetSpriteSize(blockspr[x][y], b.blockwidth*1.05, b.blockheight*1.05) MoveOffScreen(blockspr[x][y]) end end else b.play = -99 return end end FreezePlayer() ActivateMouse() b.play = 2 elseif b.play == 2 then local mx,my = g_MouseX, g_MouseY UpdateGame(e,speed[e]) if g_MouseClick == 1 then if not mouse then mouse = true if mx >= b.closex and mx <= b.closex + b.closewidth and my >= b.closey and my <= b.closey + b.closeheight then b.play = 6 end end else mouse = false end PasteSpritePosition(cursorspr, mx, my) --TextCenterOnX(50, b.scorey + 4, 4, blocksremaining) if blocksremaining < 1 then PlaySound(e,1) b.play = 4 timer[e][3] = GetTimer(e) + 2001 end elseif b.play == 3 then --no lives remaining if GetTimer(e) > timer[e][2] then b.play = 6 else UpdateGame(e,0) end elseif b.play == 4 then --won level if GetTimer(e) > timer[e][3] then b.play = 6 else UpdateGame(e,0) end elseif b.play == 6 then --close game CleanUp(e) UnFreezePlayer() DeactivateMouse() b.play = 0 end end