Yksinkertainen puzzle peli toteutettuna Hollywoodilla, jossa ohjataan Kiinanpalatsikoira Apia ja yritetään kerätä kaikki pelikentällä olevat luut. Tikapuiden avulla pääsee liikkumaan ylä -ja alasuunnassa, kiviä voi työnnellä ja hiekan näköisen peliruudun voi "kaivaa" sivusuunnassa.
Peliprojekti: http://xob.kapsi.fi/~ljl/peli/apisrc.zip
Valmiiksi käännettynä: http://xob.kapsi.fi/~ljl/peli/apiWin32.zip
@APPICON {Ic16x16 = "my16x16icon.png",
Ic24x24 = "my24x24icon.png",
Ic32x32 = "my32x32icon.png",
Ic48x48 = "my48x48icon.png",
Ic128x128 = "my128x128icon.png",
Ic256x256 = "my256x256icon.png",
Ic512x512 = "my512x512icon.png"}
;UI constants
Const #UI_PANEL_HEIGHT = 25
Const #TILESIZE = 49
;Level map dimensions
Const #COLUMNS = 11
Const #ROWS = 8
; Some constanst to help identify map tiles and brushes
Const #EMPTY = 0
Const #WALL = 1
Const #LADDER = 2
Const #WALL2 = 3
Const #ROCK = 4
Const #BONE = 5
Const #PLAYER = 6
Const #LEFT_ARROW_BUTTON = 7
Const #RIGHT_ARROW_BUTTON = 8
Const #SMILEY_BUTTON = 9
Const #APIPLEFT = 10
Const #APIPRIGHT = 11
Const #TITLE = 12
Const #TITLE_TEXT = 13
Const #PRESS_SPACE_TEXT = 14
Const #LEVEL_DONE_TEXT = 15
@DISPLAY {Width = #COLUMNS * #TILESIZE, Height = #ROWS * #TILESIZE + #UI_PANEL_HEIGHT, Title = "Api's Adventure"}
@BRUSH #WALL, "wall.png", {LoadAlpha = True}
@BRUSH #LADDER, "ladder.png", {LoadAlpha = True}
@BRUSH #WALL2, "wall2.png", {LoadAlpha = True}
@BRUSH #ROCK, "rock.png", {LoadAlpha = True}
@BRUSH #BONE, "bone.png", {LoadAlpha = True}
@BRUSH #PLAYER, "api.png", {LoadAlpha = True}
@BRUSH #LEFT_ARROW_BUTTON, "left.png", {LoadAlpha = True}
@BRUSH #RIGHT_ARROW_BUTTON, "right.png", {LoadAlpha = True}
@BRUSH #SMILEY_BUTTON, "smiley.png", {LoadAlpha = True}
@BRUSH #APIPLEFT, "apil.png", {LoadAlpha = True}
@BRUSH #APIPRIGHT, "apir.png", {LoadAlpha = True}
@BRUSH #TITLE, "title.png"
@BRUSH #TITLE_TEXT, "titlet.png", {LoadAlpha = True}
@BRUSH #PRESS_SPACE_TEXT, "pspace.png", {LoadAlpha = True}
@BRUSH #LEVEL_DONE_TEXT, "donet.png", {LoadAlpha = True}
; Create Brush for empty map tile
CreateBrush(#EMPTY, #TILESIZE, #TILESIZE, #GRAY)
Function DrawUI()
SetFillStyle(#FILLCOLOR)
Box(0, 0, 49 * 11, 25, #WHITE)
DisplayBrush(#LEFT_ARROW_BUTTON, 2, 2)
DisplayBrush(#RIGHT_ARROW_BUTTON, 22, 2)
DisplayBrush(#SMILEY_BUTTON, 11 * 47, 2)
SetFont(#TRUETYPE_DEFAULT, 20)
SetFontColor(#BLACK)
TextOut(50, 2, "level: " .. clevel + 1, #BLACK)
EndFunction
; Create level table with methods from the global levels table index n
Function InitLevel(n)
Local level = {}
level.map = CopyTable(levels[n].map)
Function level:DrawMap()
For Local j = 0 To #ROWS - 1
For Local i = 0 To #COLUMNS - 1
DisplayBrush(self.map[i][j], i * #TILESIZE, j * #TILESIZE + #UI_PANEL_HEIGHT)
Next
Next
EndFunction
level.player = { x = levels[n].player.x, y = levels[n].player.y }
Function level:DrawPlayer()
DisplayBrush(#PLAYER, self.player.x * #TILESIZE, self.player.y * #TILESIZE + #UI_PANEL_HEIGHT)
EndFunction
Function level:PlayerFall()
If self.map[self.player.x][self.player.y] <> #EMPTY Then Return
Local y = self.player.y
For Local i = y + 1 To #ROWS - 1
Local found, id, pos = self:SearchObjects(self.player.x, i)
If self.map[self.player.x][i] <> #EMPTY Or found Then Break
y = i
Next
self.player.y = y
EndFunction
level.objects = {}
level.nobjs = levels[n].nobjs
level.nbones = levels[n].nbones
For Local i = 0 To levels[n].nobjs - 1
level.objects[i] = {id = levels[n].objects[i].id, x = levels[n].objects[i].x, y = levels[n].objects[i].y}
Next
Function level:DrawObjects()
For Local i = 0 To level.nobjs - 1
DisplayBrush(self.objects[i].id, self.objects[i].x * #TILESIZE, self.objects[i].y * #TILESIZE + #UI_PANEL_HEIGHT)
Next
EndFunction
Function level:SearchObjects(x, y)
If self.nobjs < 1 Then Return(False, 0, i)
For Local i = 0 To self.nobjs - 1
If self.objects[i].x = x And self.objects[i].y = y Then Return(True, self.objects[i].id, i)
Next
Return(False, 0, i)
EndFunction
Function level:ObjectsFall()
If self.nobjs < 1 Then Return
For Local j = 0 To self.nobjs - 1
Local y = self.objects[j].y
For Local i = y + 1 To #ROWS - 1
Local found, id, pos = self:SearchObjects(self.objects[j].x, i)
If self.map[self.objects[j].x][i] <> #EMPTY Or found Or self.objects[j].x = self.player.x And i = self.player.y Then Break
y = i
Next
self.objects[j].y = y
Next
EndFunction
Function level:SortObjects()
Sort(self.objects, Function(a, b) Return(a.y > b.y) EndFunction)
EndFunction
Function level:Draw()
self:DrawMap()
self:DrawObjects()
self:DrawPlayer()
EndFunction
Return(level)
EndFunction
; Level parser, loads levels into global levels table
Function LoadLevels(fid, fname)
nlevels = 0
Local Line = 1
Local x = 0
Local y = 0
Local o = 0
Local b = 0
levels = {}
levels[nlevels] = {}
levels[nlevels].player = {x = 0, y = 0}
Dim map[11][8]
levels[nlevels].map = CopyTable(map)
map = Nil
levels[nlevels].objects = {}
OpenFile(fid, fname)
While Eof(fid) = False
Local c = ReadChr(fid)
Switch c
Case ';'
While c <> '\n' And Eof(fid) = False Do c = ReadChr(fid)
Line = Line + 1
Case '\n':
y = y + 1
If x <> 11
DebugPrint("Level parser error on line:", Line, "column:", x, "Level map must have", #COLUMNS, "columns")
End
EndIf
Line = Line + 1
x = 0
If Eof(fid) = False Then c = ReadChr(fid)
If c = '\n' Or Eof(fid) = True
If y <> 8
DebugPrint("Level parser error on line:", Line, "Levels must be separated with one line feed and level map must have:", #ROWS, "rows")
End
EndIf
levels[nlevels].nobjs = o
levels[nlevels].nbones = b
nlevels = nlevels + 1
y = 0
o = 0
b = 0
If Eof(fid) = False
Line = Line + 1
levels[nlevels] = {}
levels[nlevels].player = {x = 0, y = 0}
Dim map[11][8]
levels[nlevels].map = CopyTable(map)
map = Nil
levels[nlevels].objects = {}
EndIf
Else
Seek(fid, FilePos(fid) - 1)
EndIf
Case '0':
levels[nlevels].map[x][y] = #EMPTY
x = x + 1
Case '1':
levels[nlevels].map[x][y] = #WALL
x = x + 1
Case '2':
levels[nlevels].map[x][y] = #LADDER
x = x + 1
Case '3':
levels[nlevels].map[x][y] = #WALL2
x = x + 1
Case 'b':
levels[nlevels].objects[o] = {id = #BONE, x = x, y = y}
b = b + 1
o = o + 1
x = x + 1
Case '@':
levels[nlevels].player = {x = x, y = y}
x = x + 1
Case 'o':
levels[nlevels].objects[o] = {id = #ROCK, x = x, y = y}
o = o + 1
x = x + 1
Default:
DebugPrint("Level parser error: impossible character", Chr(c), "on line:", Line, "column:", x)
End
EndSwitch
Wend
EndFunction
Function p_HandlerFunc(msg)
Switch msg.action
Case "OnKeyDown":
Switch msg.key
Case "UP":
Local ny = level.player.y - 1
If ny >= #ROWS Or ny < 0 Then Break
Local found = level:SearchObjects(level.player.x, ny)
If found Then Break;
If level.map[level.player.x][level.player.y] = #LADDER And level.map[level.player.x][ny] = #LADDER Or
level.map[level.player.x][level.player.y] = #LADDER And level.map[level.player.x][ny] = #EMPTY
level.player.y = ny
level:PlayerFall()
level:Draw()
Flip()
StartTimer(1)
WaitTimer(1, 100)
EndIf
Case "DOWN":
Local ny = level.player.y + 1
If ny >= #ROWS Or ny < 0 Then Break
Local found = level:SearchObjects(level.player.x, ny)
If found Then Break;
If level.map[level.player.x][ny] = #LADDER Or level.map[level.player.x][level.player.y] = #LADDER And level.map[level.player.x][ny] = #EMPTY
level.player.y = ny
level:PlayerFall()
level:ObjectsFall()
level:Draw()
Flip()
StartTimer(1)
WaitTimer(1, 100)
EndIf
Case "LEFT":
Local nx = level.player.x - 1
If nx >= #COLUMNS Or nx < 0 Then Break
If level.map[nx][level.player.y] <> #WALL
Local found, id, index = level:SearchObjects(nx, level.player.y)
If found <> False
Switch id
Case #ROCK:
level:DrawMap()
level:DrawObjects()
DisplayBrush(#APIPLEFT, level.player.x * #TILESIZE, level.player.y * #TILESIZE + #UI_PANEL_HEIGHT)
Flip()
StartTimer(1)
WaitTimer(1, 100)
Local nrx = level.objects[index].x - 1
If nrx < #COLUMNS And nrx >= 0
found = level:SearchObjects(nrx, level.player.y)
If found = False And level.map[nrx][level.player.y] = #EMPTY
level.objects[index].x = nrx
level.player.x = nx
level:SortObjects()
level:PlayerFall()
level:ObjectsFall()
level:Draw()
Flip()
Return
EndIf
EndIf
Case #BONE:
RemoveItem(level.objects, index)
level.nobjs = level.nobjs - 1
level.nbones = level.nbones - 1
level.player.x = nx
EndSwitch
Else
If level.map[nx][level.player.y] = #WALL2 Then level.map[nx][level.player.y] = #EMPTY
level.player.x = nx
EndIf
level:SortObjects()
level:PlayerFall()
level:ObjectsFall()
level:Draw()
Flip()
StartTimer(1)
WaitTimer(1, 100)
EndIf
Case "RIGHT":
Local nx = level.player.x + 1
If nx >= #COLUMNS Or nx < 0 Then Break
If level.map[nx][level.player.y] <> #WALL
Local found, id, index = level:SearchObjects(nx, level.player.y)
If found <> False
Switch id
Case #ROCK:
level:DrawMap()
level:DrawObjects()
DisplayBrush(#APIPRIGHT, level.player.x * #TILESIZE, level.player.y * #TILESIZE + #UI_PANEL_HEIGHT)
Flip()
StartTimer(1)
WaitTimer(1, 100)
Local nrx = level.objects[index].x + 1
If nrx < #COLUMNS And nrx >= 0
found = level:SearchObjects(nrx, level.player.y)
If found = False And level.map[nrx][level.player.y] = #EMPTY
level.objects[index].x = nrx
level.player.x = nx
level:SortObjects()
level:PlayerFall()
level:ObjectsFall()
level:Draw()
Flip()
Return
EndIf
EndIf
Case #BONE:
RemoveItem(level.objects, index)
level.nobjs = level.nobjs - 1
level.nbones = level.nbones - 1
level.player.x = nx
EndSwitch
Else
If level.map[nx][level.player.y] = #WALL2 Then level.map[nx][level.player.y] = #EMPTY
level.player.x = nx
EndIf
level:SortObjects()
level:PlayerFall()
level:ObjectsFall()
level:Draw()
Flip()
StartTimer(1)
WaitTimer(1, 100)
EndIf
EndSwitch
EndSwitch
If level.nbones < 1
clevel = clevel + 1
clevel = Wrap(clevel, 0, nlevels)
level = InitLevel(clevel)
DisplayBrush(#LEVEL_DONE_TEXT, #CENTER, #CENTER)
Flip()
StartTimer(1)
WaitTimer(1, 1000)
DrawUI()
level:SortObjects()
level:PlayerFall()
level:ObjectsFall()
level:Draw()
Flip()
EndIf
EndFunction
Function p_ButtonHandler(msg)
Switch msg.action
Case "OnMouseUp":
Switch msg.id
Case 1:
clevel = clevel - 1
clevel = Wrap(clevel, 0, nlevels)
level = InitLevel(clevel)
DrawUI()
level:SortObjects()
level:PlayerFall()
level:ObjectsFall()
level:Draw()
Flip()
Case 2:
clevel = clevel + 1
clevel = Wrap(clevel, 0, nlevels)
level = InitLevel(clevel)
DrawUI()
level:SortObjects()
level:PlayerFall()
level:ObjectsFall()
level:Draw()
Flip()
Case 3:
level = InitLevel(clevel)
DrawUI()
level:SortObjects()
level:PlayerFall()
level:ObjectsFall()
level:Draw()
Flip()
EndSwitch
Case "OnMouseOver":
; Nothing yet, but maybe one could darken UI buttons to highlight them.
EndSwitch
EndFunction
evtmatch = {OnMouseUp = p_ButtonHandler, OnMouseOver = p_ButtonHandler}
MakeButton(1, #SIMPLEBUTTON, 2, 2, 20, 20, evtmatch)
MakeButton(2, #SIMPLEBUTTON, 22, 2, 20, 20, evtmatch)
MakeButton(3, #SIMPLEBUTTON, 11 * 47, 2, 20, 20, evtmatch)
LoadLevels(1, "levels.txt")
; Current level
clevel = 0
level = InitLevel(clevel)
DisplayBrush(#TITLE, #CENTER, #CENTER)
DisplayBrushFX(#TITLE_TEXT,#CENTER, #CENTER, {Type = #ZOOMCENTER})
DisplayBrushFX(#PRESS_SPACE_TEXT, #CENTER, #BOTTOM, {Type = #VSTRETCHCENTER})
WaitKeyDown("SPACE")
BeginDoubleBuffer()
level:SortObjects()
DrawUI()
level:Draw()
Flip()
InstallEventHandler({OnKeyDown = p_HandlerFunc})
SetEventTimeout(50)
Repeat
WaitEvent
ForeverAihe on jo aika vanha, joten et voi enää vastata siihen.