ThatFallingBlockGame was a Tetris clone created on the User Generated Content platform Metaplace.com. With the closing of that platform, the game can no longer be played, so all that remains is a short sample of video and the scripts used to create the game, which are posted below.




The not-necessarily-pretty-but-functional scripts include:
  • player - to manage input from the client
  • world - for storing scores and exposing those score via web servies
  • tet_grid - manages the play area and checks for line completion
  • block_spawner - spawns blocks!
  • master_block - invisible object that represents the Tetromino and is a
  • control object for the individual blocks.
  • block - the individual blocks of a Tetromino.

  • tfbg.php - an external php file that connected to the game world to extract and render highscores as a png to be displayed on the games profile page.


(Note: the following uses a very simple and quickly hacked syntax highlighting, so there may be errors...)

The player script: as can be seen this script started off as a default player script, so there is some old code remaining that was never removed.
Code: MetaScript

-- PLAYER default player with 4-way sliding movement.
-- Basic four directional movement for top-down view using SlideObject.
-- Usage: Attach this behavior to individual player objects to provide a basic top down movement via sliding based on move_speed.
--
-- Created by: Thor Alexander
-- Created on: 11/28/2007
-- Version 1.1
--
-- Version History:
-- 1.1 11/28 Initial release. (TA)
-- 1.2 2/28/08 Update for self changes. (JW)

--- constants 


--- properties

Define Properties()

   -- Parameters
   spawner = '_object_'
   move_speed = 1.0
   ExposeProperty( 'move_speed', 'Movement rate in tiles/second.')
   SetPropRange( 'move_speed', 0, 10 )
   pause = 0
   ui = {}
   continous_move = 0
   continous_moves = 0
   continous_move_down = 0
   
    meeper = 1
end

GAME_OVER = '0:26'
PLAY_AGAIN1 = '0:27'
PLAY_AGAIN2 = '0:28'

PLAY1 = '0:29'
PLAY2 = '0:31'

NAME = '0:30'
CONTROLS = '0:32'
PAUSED = '0:39'

CONTINOUS_MOVE_INTERVAL = 100
--- commands

Define Commands()

    MakeInput("Press 'LEFT' to start moving left.", 'left', 'down', 'none', 'move_block left')
    MakeInput("Press 'RIGHT' to start moving left.", 'right', 'down', 'none', 'move_block right')
    MakeInput("Press 'UP' to start moving up.", 'up', 'down', 'none', 'move_block up')
    MakeInput("Press 'DOWN' to start moving up.", 'down', 'down', 'none', 'move_block down')

    MakeInput("Release 'LEFT' to stop moving left.", 'left', 'up', 'none', 'move_block stop')
    MakeInput("Release 'RIGHT' to stop moving left.", 'right', 'up', 'none', 'move_block stop')
    MakeInput("Release 'DOWN' to stop moving up.", 'down', 'up', 'none', 'move_block stop')

    MakeInput('hold','space','down','none','hold')

    MakeInput('clockwise','z','down','none','rotate_block clock')
    MakeInput('anti-clockwise','x','down','none','rotate_block anti')
    MakeInput('pause','p','down','none','pause')
    MakeInput('scoreboard','h','down','none','scoreboard 604800')
    MakeInput('controls','c','down','none','controls')
    MakeInput('meeper','m','down','none','meeper')

    MakeCommand('move_block', 'Move', 'dir:string')
    MakeCommand('meeper','meeper')
    MakeCommand('rotate_block','rotate_block','dir:string')
    MakeCommand('clear', 'clear')
    MakeCommand('hold','hold')
    MakeCommand('pause','pause')
    MakeCommand('new_game','new_game')
    MakeCommand('scoreboard','scoreboard','interval:int', 'pos:int', 'force:int')
    MakeCommand('controls','controls')
    MakeCommand('goto_central','goto_central')
end

Command goto_central()
    UserGotoWorld(self,'mpcentrallive')
end
Command meeper()
    if self.meeper == 0 then
        self.meeper = 1
    else
        self.meeper = 0
    end
end

Command controls()
    SendTo(self,'display_controls',0)
end
Command scoreboard(interval, posforce)
    SendTo(self,'display_hiscore',0, pos,15,nil,0,interval,force)
--    (pos, num, status, off, interval)
end
Command new_game()
    self.pause = 0
    --(pos, num, status, off, interval,force)
    SendTo(self,'display_hiscore',0,nil,nil,nil,1)
    SendTo(self,'display_controls',0,nil,1)
    SendTo(self.spawner.grid,'init',0)
    SendTo(self.spawner,'start_game',50)
end
Command pause()
    if self.spawner.grid.game_status == 1 then
        if self.pause == 0 then
        
            self.ui['pause_bg'] = UiRect(0, 'pause', 0, 0, 640, 480)
            UiColor(self.ui.pause_bg, 0,0,0,0.5)
            UiAlign(self.ui.pause_bg, 0, 0, 'top_left', 'scale_both')
            UiAttachUser(selfself.ui.pause_bg)
            
            self.ui['pause_img'] = UiImage(0,'pause_img',0,0,200,50,PAUSED)
            UiAlign(self.ui.pause_img, 0, 0, 'center', 'scale_none')
            UiAttachUser(selfself.ui.pause_img)
            UiVisible(self.ui.pause_img, 1)
            
            self.pause = 1
            SendTo(self.spawner,'lock',0)
        else
            if self.ui.pause_img then UiDelete(self.ui.pause_img) self.ui.pause_img = nil end
            if self.ui.pause_bg then UiDelete(self.ui.pause_bg) self.ui.pause_bg = nil end
            self.pause = 0
            SendTo(self.spawner,'unlock',0)
        end
    end
end
Command clear()
    if IsSuperuser(self== 1 then
        local objs = FindObjectsInPlaceById(GetPlace(),'0:4')
        for _,v in ipairs(objs) do
            DestroyObject(v)
        end
        local objs = FindObjectsInPlaceById(GetPlace(),'0:5')
        for _,v in ipairs(objs) do
            DestroyObject(v)
        end
    end
end
Command rotate_block(dir)
    if self.spawner.grid.game_status == 1  and self.pause == 0 then
        if self.spawner then
            SendTo(self.spawner,'rotate_block',0,dir)
        end
    end
end

Command hold()
    if self.spawner.grid.game_status == 1 and self.pause == 0 then
        if self.spawner then
            SendTo(self.spawner,'hold',0)
        end
    end
end
Command move_block(dir)
    if dir == 'stop' then
        self.continous_move = 0
        self.continous_moves = 0
        self.continous_move_down = 0
    else
        self.continous_move = 1
        SendTo(self,'continous_move',0,dir)
    end
end
-- triggers
Trigger enter()
    --MoveObject(self,0,0,0,1)
    enter(self)
end

Trigger continous_move(dir)
    if self.continous_move == 1 then
        if self.spawner.grid.game_status == 1 and self.pause == 0 then
            if self.spawner then
                if dir == 'down' then self.continous_move_down = 1 end
                SendTo(self.spawner,'move_block',0,dir)
                if dir == 'down' then
                    local interval = CONTINOUS_MOVE_INTERVAL
                    if self.continous_moves == 0 then interval = CONTINOUS_MOVE_INTERVAL * 2 end
                    SendTo(self,'continous_move',interval,dir)
                    self.continous_moves = self.continous_moves + 1
                end
            end
        end
    end
end

Trigger display_hiscore(pos, num, status, off, interval,force)
    local killed = false
    if type(force) ~= 'number' then force = nil end
    if self.ui.hi_score_bg or off == 1 then
        if self.ui.hi_score_bg then
            UiDelete(self.ui.hi_score_bg)
            UiDelete(self.ui.hi_score_win)
            self.ui.hi_score_win = nil
            self.ui.hi_score_bg = nil
            killed = true
        end
    end
    if off ~= 1 and (force or not killed) then
        self.ui['hi_score_bg'] = UiRect(0, 'hi_score', 0, 0, 640, 480)
        UiColor(self.ui.hi_score_bg, 0,0,0,0.5)
        UiAlign(self.ui.hi_score_bg, 0, 0, 'top_left', 'scale_both')
        UiAttachUser(selfself.ui.hi_score_bg)
        
        self.ui['hi_score_win'] = hi_score(self, 0, pos, num, 0, 0, status,interval)
        UiAlign(self.ui.hi_score_win, 0, 0, 'center', 'scale_none')
        UiAttachUser(selfself.ui.hi_score_win)
        UiVisible(self.ui.hi_score_win, 1)
    end
end

Trigger display_controls(status, off)
    if self.ui.controls_bg or off == 1 then
        if self.ui.controls_bg then
            UiDelete(self.ui.controls_bg)
            UiDelete(self.ui.controls_win)
            self.ui.controls_win = nil
            self.ui.controls_bg = nil
        end
    else
        self.ui['controls_bg'] = UiRect(0, 'controls', 0, 0, 640, 480)
        UiColor(self.ui.controls_bg, 0,0,0,0.5)
        UiAlign(self.ui.controls_bg, 0, 0, 'top_left', 'scale_both')
        UiAttachUser(selfself.ui.controls_bg)
        
        self.ui['controls_win'] = controls(self, 0, 0, 0, status)
        UiAlign(self.ui.controls_win, 0, 0, 'center', 'scale_none')
        UiAttachUser(selfself.ui.controls_win)
        UiVisible(self.ui.controls_win, 1)
    end
end

--functions
function hi_score(self, parent, pos, num, dx, dy, status, interval)
    interval = tonumber(interval) or 0
    if type(pos) ~= 'number' or (type(pos== 'number' and pos <1 ) then pos = 0 end

    if type(num) ~= 'number' then num = 15 end
    local height = (20*num)+120
    if pos and pos > num then
        height = (20*(num+1))+120
    end
    local hi_score_win = UiWindow(parent, 'hi_score_win', dx, dy, 300, height, '0:7')

    if status == 1 or self.spawner.grid.game_status == 0 then
        local img = UiImage(hi_score_win, 'game_over', 50,5, 199,37,GAME_OVER)
        UiImageButton(hi_score_win,'play_again', 50,height-45,200,40,PLAY_AGAIN1,PLAY_AGAIN2,PLAY_AGAIN2,'new_game')
    end
    local TW_text
    local AT_text
    if interval > 0 then
        TW_text = "<b>THIS WEEK</b>"
        AT_text = "All Time"
    else
        TW_text = "This Week"
        AT_text = "<b>ALL TIME</b>"
    end      
    local this_week = UiTextButton(hi_score_win,'this_week',20,45,100,25,'0:7',TW_text,'scoreboard 604800 '..pos..' 1')
    local all_time = UiTextButton(hi_score_win,'all_time',170,45,100,25,'0:7',AT_text,'scoreboard 0 '..pos..' 1')

    UiVisible(hi_score_win, 0)
    local w = GetWorld()
    local tot = 0
    local i = 1
    local red = false
    while tot<num do
        local score = w.hi_score[i]
        i = i + 1
        if score then
            local go = true
            if interval > 0 and os.time() - tonumber(score.date) > interval then
                go = false
            end
            if go then
                tot = tot+1
                local tot_off = 0
                if tot >= 10 then
                    tot_off = -9
                end
                local l = UiMultiLabel(hi_score_win, 'score'..i, 35+tot_off, (tot*20)+50, 80, 25, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0)
                local html = "<font size='14'>"
                if pos == i-1 then
                    html = "<font size='14' color='#ff0000'>"
                    red = true
                end
                UiText(l, html..tot..") "..score.score.."</font>")
                
                local lvl = UiMultiLabel(hi_score_win, 'score'..i, 115, (tot*20)+50, 120, 25, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0)
                local level = score.level and score.level or '?'
                UiText(lvl, html..level.."</font>")
                
                local n = UiMultiLabel(hi_score_win, 'score'..i, 150, (tot*20)+50, 120, 25, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0)
                UiText(n, html..score.username.."</font>")
            end
        else
            break
        end
    end
    if pos and pos > num and not red then
       local score = w.hi_score[pos]
       if score then
            local l = UiMultiLabel(hi_score_win, 'score'..pos, 35-9, ((num+1)*20)+50, 80, 25, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0)
            UiText(l, "<font size='14' color='#ff0000'>"..pos..") "..score.score.."</font>")
            
            local n = UiMultiLabel(hi_score_win, 'score'..pos, 115, ((num+1)*20)+50, 120, 25, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0)
            local level = score.level and score.level or '?'
            UiText(n, "<font size='14' color='#ff0000'>"..level.."</font>")
            
            local n = UiMultiLabel(hi_score_win, 'score'..pos, 150, ((num+1)*20)+50, 120, 25, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0)
            UiText(n, "<font size='14' color='#ff0000'>"..score.username.."</font>")
        end
    end
    return hi_score_win
end

function controls(self, parent, dx, dy, status)
    local height = 390
    local controls_win = UiWindow(parent, 'controls_win', dx, dy, 420, height, '0:7')
    local img = UiImage(controls_win, 'name', 10,5, 400,80,NAME)
    local con = UiImage(controls_win, 'con', 10,80, 400,270,CONTROLS)
    if status == 1  or self.spawner.grid.game_status == 0 then
        UiImageButton(controls_win,'play', 110,height-45,200,40,PLAY1,PLAY2,PLAY2,'new_game')
    end

    UiVisible(controls_win, 0)
    return controls_win
end

Trigger ready_waiting()
    if self.spawner then
        SendTo(self,'display_controls',0,1)
    end
end
function enter(self)

    local grid = FindObjectsInPlaceById(GetPlace(),'0:7')[1]
    if grid then
        SendTo(grid,'join_game',0,self)
        SendTo(self,'ready_waiting',0)
    else
        Debug('I cant find a grid')
    end
end



world
[code="MetaScript"]
Define Properties()
fontrec = {sprite='24614:593', width=15,height=20 }
fontrec_lcd_blue = {sprite='24598:573', width=15,height=20 }

hi_score = {}
PersistProperty('hi_score')
end

WebTrigger scoreboard(request)
WebResponse(200)
WebHeader("content-type: text/html")
local num = 15
local interval = request.interval and tonumber(request.interval) or 0
local response = '<scores>'
local total = 0
local i = 1
while total<num do
local score = self.hi_score[i]
i = i + 1
if score then
local go = true
if interval > 0 and os.time() - tonumber(score.date) > interval then
go = false
end
if go then
total = total + 1
response = response .. '<score>'
response = response .. '<username>' .. score.username .. '</username>'
response = response .. '<user_score>' .. score.score .. '</user_score>'
local level = score.level ~= nil and score.level or ''
response = response .. '<level>' .. level .. '</level>'
response = response .. '<date>' .. score.date .. '</date>'
response = response .. '</score>'
end
else
break
end
end
response = response .. '</scores>'
WebWrite(response)
WebEnd()
end

WebTrigger scoreboard2(request)
WebResponse(200)
WebHeader("content-type: text/html")
local num = 15
local response = '<scores>'
for i=1,num do
local score = self.hi_score[i]
if score then
response = response .. '<score>'
response = response .. '<username>' .. score.username .. '</username>'
response = response .. '<user_score>' .. score.score .. '</user_score>'
local level =
www.oscan.net
oscan.net (2024) All Rights Reserved.
[Login]