}
################## # # Collapse # http://www.gamehouse.com/affiliates/template.jsp?AID=1406 # by Keith Vetter -- October 2003 # # KPV Oct 30, 2003 - Initial revision starting with gemgame code # KPV Nov 04, 2003 - EOR bonus, new row count down display, new levels # male Nov 21, 2003 - Game Over canvas items with tags, delete # in NewGame # suchenwi Jan 22, 2003 - adapted for iPaq # TODO: # bombs package require Tk 8.4 array set S {title "Collapse" version 1.0 cols 7 rows 10 cell 25 delay 10 mute 0 numSteps 4 level 1 ticks 13} set S(rowsX) [expr {$S(rows) - 1}] array set LEVEL { 1 {srows 3 tiles 3 newRow 4000 lines 25} 2 {srows 4 tiles 3 newRow 3000 lines 30} 3 {srows 5 tiles 3 newRow 2500 lines 30} 4 {srows 6 tiles 3 newRow 2000 lines 30} 5 {srows 7 tiles 3 newRow 2000 lines 35} 6 {srows 7 tiles 3 newRow 1500 lines 40} } proc DoDisplay {} { global S wm title . $S(title) set w [expr {$S(cell) * $S(cols) + 5}] set h [expr {$S(cell) * $S(rows) + 5}] CompressImages option add *Label.background black frame .ctrl -relief ridge -bd 2 -bg black canvas .c -relief ridge -bg black -height $h -width $w \ -highlightthickness 0 -bd 1 -relief raised canvas .cc -relief ridge -bg black -height [expr {5 + $S(cell)}] -width $w \ -highlightthickness 0 -bd 1 -relief raised label .score -text Score: -fg white .score configure -font "[font actual [.score cget -font]] -weight bold" #option add *font [.score cget -font] label .vscore -textvariable S(score) -fg yellow label .vscore2 -textvariable S(score2) -fg yellow label .level -text Level: -fg white label .vlevel -textvariable S(level) -fg yellow label .lines -text "lines left" -fg white label .vlines -textvariable S(lines) -fg yellow button .new -text "New" -command NewGame set levels {} foreach a [lsort -integer [array names ::LEVEL]] { lappend levels "L. $a" } eval tk_optionMenu .optlvl S(strlvl) $levels .optlvl config -highlightthickness 0 trace variable ::S(strlvl) w Tracer checkbutton .pause -text Pause -variable S(pause) \ -command {Pause 0} -relief raised -anchor w button .about -text About -command About button .x -text X -command exit pack .ctrl -side right -fill y ;#-ipady 5 -ipadx 5 pack .c -side top -fill both -expand 1 pack .cc -side top -fill both -expand 1 grid .score -in .ctrl -sticky ew -row 1 grid .vscore -in .ctrl -sticky ew grid .vscore2 -in .ctrl -sticky ew grid .level -in .ctrl -sticky ew grid .vlevel -in .ctrl -sticky ew grid .lines -in .ctrl -sticky ew grid .vlines -in .ctrl -sticky ew grid rowconfigure .ctrl 20 -minsize 10 grid .new -in .ctrl -sticky ew -row 25 -pady 1 grid .optlvl -in .ctrl -sticky ew -pady 1 grid .pause -in .ctrl -sticky ew -pady 1 grid rowconfigure .ctrl 50 -weight 1 grid .about -in .ctrl -row 100 -sticky ew -pady 5 grid .x -in .ctrl -sticky ew for {set row 0} {$row < $S(rows)} {incr row} { for {set col 0} {$col < $S(cols)} {incr col} { .c create image [GetXY $row $col] -tag [list c$row,$col cell] .c bind "c$row,$col" <Button-1> [list DoClick $row $col] } } for {set col 0} {$col < $S(cols)} {incr col} { .cc create image [GetXY 0 $col] -tag [list c$col cell] } } proc CompressImages {} { image create photo ::img::img(0) ;# Blank image foreach id {1 2 3 4} { ;# Each image we have foreach a {2 3 4} { ;# We need narrower images image create photo ::img::img($id,$a) if {$a == 4} continue ::img::img($id,$a) copy ::img::img($id) -subsample $a $a } } } proc Tracer {var1 var2 op} { ;# Handles level optionMenu if {$var2 == "strlvl"} { scan $::S(strlvl) "L. %d" level if {$level == $::S(level)} return set ::S(level) $level NewGame } } proc NewGame {} { array set ::S {score 0 state 0 score2 "" best 0} catch {eval .c delete gameOver;} StartLevel Banner "CLICK TO START" WaitClick } proc StartLevel {} { global S B BB LEVEL StartStop 0 array set S {busy 0 needRow 0 pause 0} if {! [info exists LEVEL($S(level))]} { ;# Above set levels set lvl [expr {$S(level) % 10}] if {$lvl == 0} {set lvl 10} if ![info exi LEVEL($lvl)] {set lvl [expr 1+$lvl%7]} array set S $LEVEL($lvl) set S(tiles) 4 ;# Always use 4 tiles } else { array set S $LEVEL($S(level)) set S(strlvl) "L. $S(level)" } set S(newRowX) [expr {$S(newRow) / $S(ticks)}] ;# Tick mark interval .c delete banner .c itemconfig cell -image {} array unset B set row1 [expr {$S(rowsX) - 4}] for {set row -1} {$row < $S(rows)} {incr row} { for {set col -1} {$col <= $S(cols)} {incr col} { if {$row < 0 || $row == $S(rows) || $col < 0 || $col == $S(cols)} { set B($row,$col) -1 } else { set B($row,$col) 0 } } } for {set col 0} {$col < $S(cols)} {incr col} { set BB($col) 0 } DrawBoard for {set i 0} {$i < $S(srows)} {incr i} { UpRow } } proc DrawBoard {} { global S B for {set row 0} {$row < $S(rows)} {incr row} { for {set col 0} {$col < $S(cols)} {incr col} { .c itemconfig "c$row,$col" -image ::img::img($B($row,$col)) } } } proc DrawBoard2 {} { ;# The new row board global S BB for {set col 0} {$col < $S(cols)} {incr col} { .cc itemconfig c$col -image ::img::img($BB($col)) } } proc GetXY {r c} { global S set x [expr {5 + $c * $S(cell) + $S(cell)/2}] set y [expr {5 + $r * $S(cell) + $S(cell)/2}] return [list $x $y] } proc DoClick {row col} { ;# Handles mouse clicks global S if {$S(state) == 0} { Banner "" StartStop 1 set S(state) 1 if {$row == -1} return } if {$S(state) != 1} return if {$S(busy)} return set S(busy) 1 Explode $row $col set S(busy) 0 if {$S(needRow)} NewRow } proc Explode {r c} { set cells [FindNeighbors $r $c] ;# Find who should explode if {$cells == {}} return # Update our score set cnt [llength $cells] set n [expr {$cnt * $cnt}] incr ::S(score) $n set ::S(score2) "" ;# Show special scores if {$cnt > 3} {set ::S(score2) "($n)"} ExplodeCells $cells ;# Do the explosion affect CollapseCells ;# Move cells down CompactCells ;# Move cells inward if {[IsEmpty]} { incr ::S(score) 1000 Banner "1000 POINT BONUS" after 500 [list Banner ""] } } proc FindNeighbors {row col} { ;# Find all triplets and up global S B # We'll do a flood fill (bfs) to find connected components set q [list $row $col] ;# Our BFS queue set qhead 0 ;# Head of the queue array unset neighbors ;# Whose in our neighborhood set neighbors($row,$col) 1 ;# We're in our own neighborhood set type $B($row,$col) ;# Type of our neighborhood set cnt 1 while {[llength $q] > $qhead} { ;# While stuff in the queue foreach {r c} [lrange $q $qhead [incr qhead]] break incr qhead foreach {dr dc} {-1 0 1 0 0 -1 0 1} { ;# Look n,s,e & w set r1 [expr {$r + $dr}] set c1 [expr {$c + $dc}] if {[info exists neighbors($r1,$c1)]} continue ;# Already seen if {$B($r1,$c1) != $type} continue ;# Wrong type set neighbors($r1,$c1) 1 ;# Another neighbor lappend q $r1 $c1 ;# Add to our BFS incr cnt } } if {$cnt < 3} {return {}} return [array names neighbors] } proc ExplodeCells {cells} { foreach stage {2 3 4} { foreach who $cells { .c itemconfig c$who -image ::img::img($::B($who),$stage) if {$stage == 4} {set ::B($who) 0} } update after [expr {$::S(delay)}] } } proc CollapseCells {} { global B S while {1} { ;# Stop when nothing slides set sliders {} for {set col 0} {$col < $S(cols)} {incr col} { set collapse 0 for {set row $S(rowsX)} {$row >= 0} {incr row -1} { if {$B($row,$col) == -1} break if {$B($row,$col) == 0} { set collapse 1 } elseif {$collapse} { lappend sliders $row $col y } } } if {$sliders == {}} break SlideCells $sliders } } proc CompactCells {} { global B S array set ::BB [array get B] set ROW $S(rowsX) set COL [expr {int($S(cols) / 2)}] while {1} { ;# Stop when nothing slides set sliders {} # Check the slide to the right columns set cols {} for {set col 0} {$col < $COL} {incr col} { if {$B($ROW,$col) <= 0} { foreach c $cols { for {set row $ROW} {$row >= 0} {incr row -1} { if {$B($row,$c) <= 0} break lappend sliders $row $c x } } set cols {} } else { lappend cols $col } } # Check slide to the left columns set cols {} for {set col [expr {$S(cols) - 1}]} {$col >= $COL} {incr col -1} { if {$B($ROW,$col) <= 0} { foreach c $cols { for {set row $ROW} {$row >= 0} {incr row -1} { if {$B($row,$c) <= 0} break lappend sliders $row $c xx } } set cols {} } else { lappend cols $col } } if {$sliders == {}} break SlideCells $sliders } } ##+########################################################################## # # SlideCells -- move a set of cells one unit in a specified direction. # # Tricky part is NOT losing the correct binding for cell X,Y. Thus we # first blank the real image and replace it with a temporary one which # we slide. DrawBoard will put the correct image back in place. # proc SlideCells {cells} { foreach {r c dir} $cells { .c itemconfig c$r,$c -image {} set M($r,$c) $::B($r,$c) set ::B($r,$c) 0 .c create image [GetXY $r $c] -image ::img::img($M($r,$c)) \ -tag slider$dir } .c raise banner set dx [expr {double($::S(cell)) / $::S(numSteps)}] set dy [expr {double($::S(cell)) / $::S(numSteps)}] for {set step 0} {$step < $::S(numSteps)} {incr step} { .c move slidery 0 $dy .c move slideryy 0 -$dy .c move sliderx $dx 0 .c move sliderxx -$dx 0 update after $::S(delay) } foreach {r c dir} $cells { ;# Update board data if {$dir == "y"} { set ::B([expr {$r+1}],$c) $M($r,$c) } elseif {$dir == "yy"} { set ::B([expr {$r-1}],$c) $M($r,$c) } elseif {$dir == "x"} { set ::B($r,[expr {$c+1}]) $M($r,$c) } elseif {$dir == "xx"} { set ::B($r,[expr {$c-1}]) $M($r,$c) } } DrawBoard .c delete slidery slideryy sliderx sliderxx } proc NewRow {} { global S B StartStop 0 if {$S(busy)} { ;# Busy handling mouse click set S(needRow) 1 ;# ...so set flag and leave return } set S(busy) 1 incr S(lines) -1 if {$S(lines) == 0} { ;# Is the level over yet??? return [LevelOver] } # Check for game over for {set col 0} {$col < $S(cols)} {incr col} { if {$B(0,$col) > 0} { return [GameOver] } } UpRow StartStop 1 set S(needRow) 0 set S(busy) 0 }##+##########################################################################
# # UpRow -- Scrolls the screen up one row and adds in another row # proc UpRow {} { global B S BB for {set col 0} {$col < $S(cols)} {incr col} { if {$BB($col) == 0} {set BB($col) [expr {1 + int(rand() * $S(tiles))}]} } set sliders {} for {set row 1} {$row < $S(rows)} {incr row} { for {set col 0} {$col < $S(cols)} {incr col} { if {$B($row,$col) == -1} continue lappend sliders $row $col yy } } for {set col 0} {$col < $S(cols)} {incr col} { set n $BB($col) if {$n == 0} {set n [expr {1 + int(rand() * $S(tiles))}]} set B($S(rows),$col) $n set BB($col) 0 lappend sliders $S(rows) $col yy } SlideCells $sliders for {set col 0} {$col < $S(cols)} {incr col} { set B($S(rows),$col) -1 } } proc IsEmpty {} { for {set row $::S(rowsX)} {$row >= 0} {incr row -1} { for {set col 0} {$col < $::S(cols)} {incr col} { if {$::B($row,$col) > 0} {return 0} } } return 1 } proc About {} { set msg "$::S(title) v$::S(version)\nby Keith Vetter, Oct. 2003 - " append msg "Based on a program by GameHouse\n" append msg " Collapse the rising blocks " append msg "to get as many points as possible.\n" append msg "Score points by clicking on a block that has " append msg "two or more neighbors of same color. Blocks above " append msg "the explosion will collapse on blocks " append msg "below. The more blocks exploded the higher your score.\n" append msg "As you play, new lines of blocks will appear. When " append msg "\"Lines Left\" reaches 0, the next level will start." tk_messageBox -message $msg } proc GameOver {{txt "Game Over"}} { set ::S(state) 2 StartStop 0 .c create rect 0 0 [winfo width .c] [winfo height .c] \ -fill white -stipple gray25 -tag gameOver .c create text [GetXY 4 3] -text $txt -font {Helvetica 18 bold} \ -fill white -tag gameOver } proc StartStop {onoff} { foreach aid [after info] {after cancel $aid} .cc itemconfig cell -image {} if {! $onoff} return set ::S(tcnt) $::S(ticks) after $::S(newRowX) ticker } proc ticker {} { global S BB incr S(tcnt) -1 set col [expr {$S(ticks) - 1 - $S(tcnt)}] set BB($col) [expr {1 + int(rand() * $S(tiles))}] DrawBoard2 if {$S(tcnt) <= 0} { NewRow } else { after $S(newRowX) ticker } } proc LevelOver {} { global S B set S(state) 3 ;# Level over state StartStop 0 Banner "LEVEL COMPLETE" update after 3000 LevelOverAnimation incr S(level) StartLevel set S(state) 1 StartStop 1 } proc LevelOverAnimation {} { global S B Banner "" for {set row 0} {$row < $S(rows)} {incr row} { set bonus [expr {100 + $row*10}] incr S(score) $bonus Banner "$bonus POINT BONUS" for {set col 0} {$col < $S(cols)} {incr col} { if {$B($row,$col) > 0} break set B($row,$col) 4 DrawBoard update after [expr {$S(delay)}] } if {$B($row,$col) > 0} break } after 2000 } ##+########################################################################## # # WaitClick -- waits for a click to begin # proc WaitClick {} { set w [winfo width .c] set h [winfo height .c] .c create rect -10 -10 $w $h -tag scrim -fill black .c lower scrim .c raise banner .c bind banner <Button-1> {DoClick -1 -1} .c bind scrim <Button-1> {DoClick -1 -1} } proc Banner {msg} { global S .c delete banner scrim if {$msg == ""} return set x [expr {[winfo width .c] / 2}] .c create rect [expr {$x - 100}] 100 [expr {$x + 100}] 200 \ -tag banner -fill black -outline gold -stipple gray50 .c create text $x 175 -tag banner -font {Helvetica 12 bold} \ -text $msg -anchor c -fill white for {set i 0} {$i < 6} {incr i} { set xx [expr {$x - (2.5-$i)*$S(cell)}] set yy [expr {120 + rand()*$S(cell)}] set who [expr {1 + int(rand() * $S(tiles))}] .c create image $xx $yy -image ::img::img($who) -tag banner } } proc Pause {byBinding} { global S if {$byBinding} { ;# Button toggles for us set S(pause) [expr {! $S(pause)}] } if {$S(pause) == 1} { ;# Pause on if {$S(state) != 1} return ;# Not in play mode foreach aid [after info] {after cancel $aid} .c create rect 0 0 [winfo width .c] [winfo height .c] \ -fill black -tag pause .c create text [GetXY 4 3] -font {Helvetica 14 bold} \ -fill white -tag pause -text "PAUSED" -justify center .c create text [GetXY 6 3] -font {Helvetica 10 bold} \ -fill white -tag pause -text "Press p to continue" -justify center } else { ;# Pause off .c delete pause after $::S(newRowX) ticker } } image create photo ::img::img(-1) image create photo ::img::img(0) image create photo ::img::img(1) -data { R0lGODdhGwAcANUAABwaKSopKi4nGAocdQYdswUhzw0jjRcgTDBr+HCX+iGX+2aG+156+hx58E5s +CZQ+BQ68gQo7K3p+5bV+5rF+nCr/JKs+D2p/BMy2RkYFyRBsCVC2T1b8hdT0j5Y0Yme90JVr1Rs 0qG5+BRPlh80bjI2TBc9kP////////////////////////////////////////////////////// /////////////////////////////////////////////ywAAAAAGwAcAAAG/0AAICAEBIQCgEAA EAACAkBAABAAAgJAIDAAEoRDYrFAKBAKhgNAACggEooFo+FAIB6PxwMIEQ6HkQPAgJBIJpSK5ZJY MBAIxOPxgDyIEIKAkJA0IMCIUIiJFIbDIQQCKQAIFUqkUCgQCIQCAVgQDoER4RBSEBAulUiBUCgQ gAXhsBApRAqRSAQCKQAIiUqEUCAQiUNgRDiEFDIERSJSKBQwwIJQiClEMBFMJBKBRCCYDGGRwAwL mAIGg4lgIphIJAKJQCCQAoCgSECEQIxQGMFAMECIcCh8PAoCzWIBxAiHGMgGCBEOiZDHAxMgLBQQ DAazEW6GD+ED8ng8HhwOJv+jWSwgGMxms9k8II8HBPgQDjkcB2Ij0CwYj81ms3lshkIgRzgUOhib jGbBeGw2m8fm8Xg8iA6Ow+FwMBYbgYaxeGw2nI3wQQQ6hEMHY7HoZDQMB4ez8Xg4HA6HyHAAGUJh IuEBaBwOjofj4XA4Do7DMRwOEx8PQONwcDwejofDcTgcjiFjwVgwFh+LJwPiODgejocTAjqEDAZj wVgwFozF4mPxCDRCB8cT4giFQIZQuGAsFoyFpRICgBwOB4fj4DgcjiFjwVgsFowFwyIKZTRAh3A4 ZDAYwIVwOEyIRB7AyMFwOBgMhjCRSHw+H4vFYhGJKBQLKHPwOIAMoXCxWCQzEonEp/KpVCwV0cdB ygBKJqBHOCQWQ8QRKSPIZASATCYDyAAEGYAgA8gAMoAMQAAQZABBADs=} image create photo ::img::img(2) -data { R0lGODdhGwAcANUAABkYFyopKhwaKS4nGFYnEasSB8oLBWkoKvE0I/hmWPhXTPVTO/VFOuw5MOgj EtkZD6gZH+QpH/CnldnHtveXjfGYcfeFdfh4b/dsZmwHBVsXE+x3Wa0mD+AqLk8ZKaU2HvVMRJ8t LqA4M6JKR/x+hPaKh+mdnf////////////////////////////////////////////////////// /////////////////////////////////////////////ywAAAAAGwAcAAAG/0BAABAACAYCgGAg GAgCgkBAEBAEBIGBYDAIEAqGgqFgKBiABeGwYCgYDAbDYSAQFBCJREKhWDAYDQQCAXQIh47H4wEJ HCKSiYRSsVwwCcWC0UAgIhGi4/EAZBiTCyIScUSIjsfD8Xg4Ho/Hw/EAZBaSBtAgFBYMBUPhYXgY HoaH4fF4PACZBSUiLAgLhoKwIHwYgA/h8KHJNCoPg8FQKBQehUfhASESHQ9ApmFxGAwFYWEIIQ4d D4fDockgNg9DQQiJPCCPiNDheAAjDocjEokAMoiEw2B4QCIPTuQRiTgckYgjEnF0EBFNBpFwGCAP DjAiHAo7RCGCgfBkEAqHgf/z6HwiHUQH0UEgEB0EooNogBqDDELheDiEnUYH2BAOEQ1EA9FgJBqa TEMRcYQiIsRwKGQwGIwGA4RhADIIRSQS6TRGDUYDyBAOiQwFhuHJMECIiKjRIIIYQJBwyAAxFBfQ INNYNDoNEYMxHAoVQwZIQQJpNA1GoyNqMEbDIUgxBDEYCpLCkwE2hMIRAwQCKUAgkAKkAIFAIIai pBhoOsMRYwQECYcKkGLIYDASJYVHg2gwGg3GcDgcghiMhoKi0GgQjU6jwWCAgAzhkNhoNBAKkwKQ 6SAQwIZQyGgAGcJhg9FoNBgXCsijiSAiiEYDBAIpFIpEIgHECIcXSqkxGDxCEB1Eo8EAgRSJRCIh vFwuFlLJoogAAJ4CxwGMCIfDRqSD6CAiCEQEEgAAAAMBQAAACAAAwUAAGAAEA8AAIAAMAIAgADs=} image create photo ::img::img(3) -data { R0lGODdhGwAcANUAACopKi4nGBwaKTZ4LhyoBSG4BSCcBzNqLyaIFVP8E337T4z8Olz3NT71FDXo DT9FMC3YCZb8aOX7kbz9birICSF0EFLrFsj8VyRDFUXYGRxtDh04DljoNkjHLFHYMGroSlfKMWrZ UWXKTDQyNEaYMk6LRxkYF0CHNUa4Lf////////////////////////////////////////////// /////////////////////////////////////////////ywAAAAAGwAcAAAG/0AAICAICAKCAEAA CAgCgoAgIAgIAoKAACAADAiFQqFAIBQIBgKBUCAQCoVCgXAABACIhEKxWCyADGBCKGw0HA2gQzh0 IAQPSEQyiUQUigUjkUgkGg0ikQKoWCQLBwQCpAiHRCEEAoE4HJBAxTJxFAgGgsFgMAAJQmGhUKBQ IBAIJFCxRBxCg2E4JBQKhQKFQoFAHJBAxXGBDIcFArAgHBYoFAoE4oBgKg5FhkAgEoEU4ZACgTgc EIzGsoAUCIWCsEAcAiFCocPhwFQaCkehUChQKBAKhDIcQhwORwOCqVgWEEqhAKQIhUCIcAhxOByO RsOBqVgWGUqBQqFQMkNHBv/oEA4bjYYDU7EwLECKUJiBZCAZh8PRcAAbQmHCsqlwGBkKpUPJZDIZ jsPBcTQ4wwaD4cBUOAwPpUPpUDIeR8bBcTCEjAajkWBYMBUOI9MBUjoUTybDsXAsDU6D0WA0GAwG B1PxcDwdSqfTyXgyHAuDw+AAGcKhwoOpeDieTqfT8Xg8HA6HMxwOFRzMwcPxADtCocfD4XA4QIZw KFQoPpgKKOQBdToijyfE4Qw/Q4VQofhgDh6OBwQCgTweDofzYXyECqIi8sFUPB+gRzj0cDgMDoPB +DAYCgZDEflgBh4OhyPkcDgfDuPDUDAYCgaDwYhEPpgDCMgRCj8fBQOoEA5GIwpgRDj0jAQkDufD +HwYH8UHqBAOiREFpxQwAU5AlHAI7AiHoA5KiBKiTgCBKWASmEwBk8AkMJkEJoEpYBIEBCaBKWAK AgA7} image create photo ::img::img(4) -data { R0lGODdhGwAcAMQAACspKzQyNExISbi4t8q7x6qpq6qnlOnp6fv8+tnY1mVnZtTZ8srJyXmId/Lp 1Ih6iLPEzHZ3dbbItLa6zDhRUYp8dHN6jZuZlB8bKCsoFf///////////////////////ywAAAAA GwAcAAAF/yAgjkAgBkBAjgEZiIIwEMNQDEMxFEVRgIM4DkURAIFxgIg4goc4IuOBHAiSJIGygIg4 kiJ4iOOBHAjCBM2BIEeSJEzCMAyTMEmSLKCzHAeSAM+BHNAwFEMxFMMwDBDDMElygAfiANGBJMRQ DMVQDMMwSATBMEmyHMcCBtGBJMNQDMMgDQMxEBDDMEySHEgiRAeIJOAgisRAMBDIiGKSJMlxJEJ0 IAkxTBIBMdAoJkySJOBxIIkQHUgiDRIBMqKYMGAiistxHEgiRAeSQATBMAw0juAhjgeSUJWYMAzE MGAiigt4iKOIIIcQHcjBMEzCJEmSkCJyIAiCJKAQHUeSMMkMkyTJcRwHciAHiIjjIUQHsiQMAyVJ Ah7iCCLiKB5CdBwOwzBJkhzHcZDkeAjRcSwJmDBMkhzHgRwgIo7kQUXHkTAMkyTLcSAHSY6HEB1H koBMwiTJcRwHiIgjiRxClBxJwjBJchxHWY6HUB3HkjBgIh7HcYCIOJLiQVnJcSRJkhzHUZbkIUTg IY4kiIgjSR5ClCDgIYogIo5kKSZCYBymaY7HBQCCUICDOIoEMzCQREASARVNAAAABmQAkAFABgJA JmZiJmaiGAIAOw==} DoDisplay NewGame wm geometry . 240x305+0+0 bind . <Up> {exec wish $argv0 &; exit} ;# rapid dev helper
Category Mobile Category Games