diff --git a/xtrn/uberblox/blox.bin b/xtrn/uberblox/blox.bin new file mode 100644 index 0000000000000000000000000000000000000000..602ce3cec338fd39ba23e83d0980230e37d8d014 --- /dev/null +++ b/xtrn/uberblox/blox.bin @@ -0,0 +1 @@ + � ���0 ��0��0 �V �����0���� � �C �b �R �$�b ��0 � ������ �B�A�#�T�2 ��0������� � �2�F��b�Q ����������PLAYER��� ������������������������������SCORE��� ��������������������������SELECTION��� ������������������������������LEVEL��� �������������������������������GOAL��� ������������������� \ No newline at end of file diff --git a/xtrn/uberblox/blox.js b/xtrn/uberblox/blox.js new file mode 100644 index 0000000000000000000000000000000000000000..844502827a0badec419adebeb16688b7c5501471 --- /dev/null +++ b/xtrn/uberblox/blox.js @@ -0,0 +1,611 @@ +/* + UBER BLOX! + + A javascript block puzzle game similar to GameHouse "Super Collapse" + by Matt Johnson (2009) + + for Synchronet v3.15+ +*/ + +var gameroot; +try { barfitty.barf(barf); } catch(e) { gameroot = e.fileName; } +gameroot = gameroot.replace(/[^\/\\]*$/,""); + +load("graphic.js"); +load("sbbsdefs.js") +load("logging.js"); +load("funclib.js"); + +var oldpass=console.ctrl_key_passthru; +//var gamelog=new Logger(gameroot,"blox"); +var gamelog=false; + +function Blox() +{ + const columns=20; + const rows=11; + const bg=[BG_GREEN,BG_BLUE,BG_RED,BG_BROWN,BG_MAGENTA,BG_CYAN]; + const fg=[LIGHTGREEN,LIGHTBLUE,LIGHTRED,YELLOW,LIGHTMAGENTA,LIGHTCYAN]; + + var level=0; + var points=0; + var current; + var scores; + var players; + var gameover=false; + + const points_base= 15; + const points_increment= 10; + const minimum_cluster= 3; + const colors= [3,3,3,3,3,4,4,4,4,5,5,5,6,6]; //COLORS PER MAP (DEFAULT ex.: levels 1-5 have 3 colors) + const tiles_per_color= [8,7,6,5,4,10,9,8,7,12,11,10,12,11]; //TARGET FOR LEVEL COMPLETION (DEFAULT ex. level 1 target: 220 total tiles minus 6 tiles per color times 3 colors = 202) + + var lobby; + var logo; + var gameend; + var selx=0; + var sely=0; + + var selection=[]; + var selected=false; + var counted; + const xlist=[0,0,1,-1]; + const ylist=[-1,1,0,0]; + + function Lobby() + { + DrawLobby(); + while(1) + { + var k=console.inkey(K_NOCRLF|K_NOSPIN|K_NOECHO,5); + if(k) + { + switch(k.toUpperCase()) + { + case "\x1b": + case "Q": + SplashExit(); + case "I": + ShowInstructions(); + DrawLobby(); + break; + case "P": + Main(); + DrawLobby(); + break; + case "R": + DrawLobby(); + break; + default: + break; + } + } + } + } + function ShowInstructions() + { + console.clear(ANSI_NORMAL); + bbs.sys_status&=~SS_PAUSEOFF; + bbs.sys_status|=SS_PAUSEON; + var helpfile=gameroot + "help.doc"; + if(file_exists(helpfile)) console.printfile(helpfile); + bbs.sys_status&=~SS_PAUSEON; + bbs.sys_status|=SS_PAUSEOFF; + } + function Main() + { + gameover=false; + GenerateLevel(); + Redraw(); + while(1) + { + if(gameover) + { + while(console.inkey()==""); + return; + } + var k=console.inkey(K_NOCRLF|K_NOSPIN|K_NOECHO,5); + if(k) + { + switch(k.toUpperCase()) + { + case KEY_UP: + case KEY_DOWN: + case KEY_LEFT: + case KEY_RIGHT: + if(selected) + { + Unselect(); + } + MovePosition(k); + break; + case "R": + Redraw(); + break; + case "\x1b": + case "Q": + EndGame(); + break; + case "\r": + case "\n": + ProcessSelection(); + break; + default: + break; + } + } + } + } + function DrawLobby() + { + lobby.draw(1,1); + ShowScores(); + } + function LevelUp() + { + level+=1; + GenerateLevel(); + } + function EndGame() + { + if(players.players[user.alias].score<points) + { + players.players[user.alias].score=points; + players.StorePlayer(); + } + console.clear(); + gameend.draw(); + console.gotoxy(52,5); + console.putmsg(CenterString("\1n\1y" + points,13)); + console.gotoxy(52,13); + console.putmsg(CenterString("\1n\1y" + (parseInt(level)+1),13)); + gameover=true; + } + function SplashStart() + { + console.ctrlkey_passthru="+ACGKLOPQRTUVWXYZ_"; + bbs.sys_status|=SS_MOFF; + bbs.sys_status|=SS_PAUSEOFF; + console.clear(); + } + function SplashExit() + { + console.ctrlkey_passthru=oldpass; + bbs.sys_status&=~SS_MOFF; + bbs.sys_status&=~SS_PAUSEOFF; + players.StorePlayer(); + console.clear(ANSI_NORMAL); + exit(0); + } + function Init() + { + logo=new Graphic(18,22); + logo.load(gameroot + "blox.bin"); + lobby=new Graphic(80,23); + lobby.load(gameroot + "lobby.bin"); + gameend=new Graphic(80,23); + gameend.load(gameroot + "gameend.bin"); + players=new PlayerList(); + } + function GenerateLevel() + { + var numcolors=colors[level]; + var tiles=(columns*rows)-(numcolors*tiles_per_color[level]); + + grid=new Array(columns); + for(var x=0;x<grid.length;x++) + { + grid[x]=new Array(rows); + for(var y=0;y<grid[x].length;y++) + { + var col=random(numcolors); + grid[x][y]=new Tile(bg[col],fg[col],x,y); + } + } + current=new Level(grid,tiles); + } + function Redraw() + { + console.clear(ANSI_NORMAL); + DrawGrid(); + DrawLogo(); + DrawInfo(); + ShowPosition(); + } + function DrawGrid() + { + ClearBlock(1,1,60,23); + for(var x=0;x<current.grid.length;x++) + { + for(var y=0;y<current.grid[x].length;y++) + { + current.grid[x][y].draw(false,x,y); + } + } + console.attributes=ANSI_NORMAL; + } + function DrawLogo() + { + logo.draw(62,1); + console.attributes=ANSI_NORMAL; + } + function DrawInfo() + { + ShowPlayer(); + ShowScore(); + ShowSelection(selection.length); + ShowLevel(); + ShowTiles(); + console.gotoxy(1,24); + console.putmsg("\1nArrow keys : move \1k\1h[\1nENTER\1k\1h]\1n : select \1k\1h[\1nQ\1k\1h]\1n : quit \1k\1h[\1n?\1k\1h]\1n : help \1k\1h[\1nR\1k\1h]\1n : redraw"); + } + function Gotoxy(x,y) + { + var posx=(x*3)+2; + var posy=22-(y*2); + console.gotoxy(posx,posy); + } + function MovePosition(k) + { + current.grid[selx][sely].draw(false,selx,sely); + switch(k) + { + case KEY_DOWN: + if(sely>0) sely--; + else sely=current.grid[selx].length-1; + break; + case KEY_UP: + if(sely<current.grid[selx].length-1) sely++; + else sely=0; + break; + case KEY_LEFT: + if(selx>0) selx--; + else selx=current.grid.length-1; + if(sely>=current.grid[selx].length) sely=current.grid[selx].length-1; + break; + case KEY_RIGHT: + if(selx<current.grid.length-1) selx++; + else selx=0; + if(sely>=current.grid[selx].length) sely=current.grid[selx].length-1; + break; + } + ShowPosition() + } + function Grid(c,r) + { + var array=new Array(c); + for(var cc=0;cc<array.length;cc++) + { + array[cc]=new Array(r); + } + return array; + } + function Select() + { + for(var s in selection) + { + var spot=selection[s]; + var tile=current.grid[spot.x][spot.y]; + tile.draw(true,spot.x,spot.y); + } + selected=true; + ShowSelection(selection.length); + } + function Unselect() + { + for(var s in selection) + { + var spot=selection[s]; + var tile=current.grid[spot.x][spot.y]; + tile.draw(false,spot.x,spot.y); + } + selection=[]; + selected=false; + ShowSelection(0); + } + function ProcessSelection() + { + if(selected) + { + RemoveBlocks(); + if(!FindValidMove()) + { + if(current.tiles<=0) + { + mswait(1000); + LevelUp(); + } + else EndGame(); + Redraw(); + } + } + else + { + counted=Grid(columns,rows); + if(Search(selx,sely)) + { + Log("Selecting " + selection.length + " tiles"); + Select(); + } + else + { + selection=[]; + } + } + } + function Search(x,y) + { + var testcolor=current.grid[x][y].bg; + counted[x][y]=true; + selection.push(new Coord(x,y)); + + for(var i=0;i<4;i++) + { + var spot=new Coord(x+xlist[i],y+ylist[i]); + if(current.grid[spot.x] && !counted[spot.x][spot.y]) + { + if(current.grid[spot.x][spot.y] && current.grid[spot.x][spot.y].bg==testcolor) + { + Search(spot.x,spot.y); + } + } + } + if(selection.length>=minimum_cluster) return true; + else return false; + } + function Coord(x,y) + { + this.x=x; + this.y=y; + } + function SortSelection() + { + for(var n=0;n<selection.length;n++) + { + for(var m = 0; m < (selection.length-1); m++) + { + if(selection[m].x < selection[m+1].x) + { + var holder = selection[m+1]; + selection[m+1] = selection[m]; + selection[m] = holder; + } + else if(selection[m].x == selection[m+1].x) + { + if(selection[m].y < selection[m+1].y) + { + var holder = selection[m+1]; + selection[m+1] = selection[m]; + selection[m] = holder; + } + } + } + } + } + function RemoveBlocks() + { + Log("Removing " + selection.length + " blocks"); + + SortSelection(); + + for(var s=0;s<selection.length;s++) + { + var coord=selection[s]; + current.grid[coord.x].splice(coord.y,1); + if(current.grid[coord.x].length==0) current.grid.splice(coord.x,1); + } + if(current.tiles>0) current.tiles-=selection.length; + points+=CalculatePoints(); + selection=[]; + Unselect(); + ShowTiles(); + + if(selx>=current.grid.length) selx=current.grid.length-1; + if(sely>=current.grid[selx].length) sely=current.grid[selx].length-1; + + ShowScore(); + DrawGrid(); + ShowPosition(); + } + function ShowPosition() + { + current.grid[selx][sely].draw(true,selx,sely); + } + function ShowPlayer() + { + console.gotoxy(63,9); + console.putmsg("\1w\1h" + user.alias); + } + function ShowScore() + { + console.gotoxy(63,12); + console.putmsg(PrintPadded("\1w\1h" + points,15)); + } + function ShowSelection() + { + console.gotoxy(63,15); + console.putmsg(PrintPadded("\1w\1h" + CalculatePoints(),15)); + } + function ShowLevel() + { + console.gotoxy(63,18); + console.putmsg("\1w\1h" + (parseInt(level)+1)); + } + function ShowTiles() + { + console.gotoxy(63,21); + console.putmsg(PrintPadded("\1w\1h" + current.tiles,15)); + } + function CalculatePoints() + { + if(selection.length) + { + var p=points_base; + for(var t=0;t<selection.length;t++) + { + p+=points_base+(t*points_increment); + } + return p; + } + return 0; + } + function FindValidMove() + { + var canmove=false; + for(var x=0;x<current.grid.length && !canmove;x++) + { + for(var y=0;y<current.grid[x].length && !canmove;y++) + { + if(Search(x,y)) + { + canmove=true; + } + selection=[]; + } + } + return canmove; + } + function SortScores() + { + var sorted=[]; + for(var p in players.players) + { + var s=players.players[p]; + sorted.push(s); + } + var numScores=sorted.length; + for(n=0;n<numScores;n++) + { + for(m = 0; m < (numScores-1); m++) + { + if(sorted[m].score < sorted[m+1].score) + { + holder = sorted[m+1]; + sorted[m+1] = sorted[m]; + sorted[m] = holder; + } + } + } + return sorted; + } + function ShowScores() + { + var posx=3; + var posy=4; + var index=0; + + var scores=SortScores(); + for(var s in scores) + { + var score=scores[s]; + if(score.score>0) + { + if(score.name==user.alias) console.attributes=YELLOW; + else console.attributes=BROWN; + console.gotoxy(posx,posy+index); + console.putmsg(score.name,P_SAVEATR); + console.right(20-score.name.length); + console.putmsg(PrintPadded(score.score,11,undefined,"right"),P_SAVEATR); + console.right(3); + console.putmsg(PrintPadded(players.FormatDate(score.laston),8,undefined,"right"),P_SAVEATR); + index++; + } + } + } + +// GAME OBJECTS + + function PlayerList() + { + this.file=new File(gameroot + "players.ini"); + this.players=[]; + this.Init=function() + { + this.file.open(file_exists(this.file.name)?'r+':'w+',true); + if(!this.file.iniGetValue(user.alias,"name")) + { + Log("Creating new player data: " + user.alias); + this.file.iniSetObject(user.alias,new Player()); + } + var plyrs=this.file.iniGetAllObjects(); + this.file.close(); + for(p in plyrs) + { + var plyr=plyrs[p]; + Log("Loading player data: " + plyr.name); + if(plyr.name==user.alias) plyr.laston=time(); + this.players[plyr.name]=new Player(plyr.name,plyr.score,plyr.laston); + } + } + this.FormatDate=function(timet) + { + var date=new Date(timet*1000); + var m=date.getMonth()+1; + var d=date.getDate(); + var y=date.getFullYear()-2000; //assuming no one goes back in time to 1999 to play this + + if(m<10) m="0"+m; + if(d<10) d="0"+d; + if(y<10) y="0"+y; + + return (m + "/" + d + "/" + y); + } + this.Reset=function() + { + file_remove(this.file.name); + this.Init(); + } + this.StorePlayer=function() + { + this.file.open('r+',true); + this.file.iniSetObject(user.alias,this.players[user.alias]); + this.file.close(); + } + this.FindUser=function(alias) + { + return this.players[alias]; + } + function Player(name,score,laston) + { + this.name=name?name:user.alias; + this.score=score?score:0; + this.laston=laston?laston:time(); + } + this.Init(); + } + function Level(grid,tiles) + { + this.grid=grid; + this.tiles=tiles; + } + function Tile(bg,fg) + { + this.bg=bg; + this.fg=fg; + this.draw=function(selected,x,y) + { + Gotoxy(x,y); + if(selected) + { + console.attributes=this.fg; + console.putmsg("\xDB\xDB",P_SAVEATR); + } + else + { + console.attributes=this.bg; + console.putmsg(" ",P_SAVEATR); + } + } + } + + SplashStart(); + Init(); + Lobby(); + SplashExit(); +} +function Log(text) +{ + if(gamelog) gamelog.Log(text); +} + +Blox(); \ No newline at end of file diff --git a/xtrn/uberblox/gameend.bin b/xtrn/uberblox/gameend.bin new file mode 100644 index 0000000000000000000000000000000000000000..6581d50fe044609f4919d4e0942a46c12c626a09 --- /dev/null +++ b/xtrn/uberblox/gameend.bin @@ -0,0 +1 @@ + ���������������������������������� ��������������� � �� �� �� �� �� ��� � FINAL SCORE � � � ��������������� ��� �� �� �� �� �� �� �� � � � � � � � � �� �� �� �� �� �� �� �� ��� � � � � ��������������� � �� �� �� �� �� �� � � � ��������������� ��� �� �� �� �� �� �� ��� � LEVEL � � � ��������������� � � � � � � � � ��� �� �� �� �� �� �� �� �� � � � � � ��������������� ��� �� �� �� �� �� ��� � � ��� �� �� �� �� �� �� �� � PRESS ANY KEY � � ��� �� �� �� �� �� ��� TO RETURN TO � � ��� �� �� �� �� �� �� ��� GAME MENU ���������������������������������� \ No newline at end of file diff --git a/xtrn/uberblox/help.doc b/xtrn/uberblox/help.doc new file mode 100644 index 0000000000000000000000000000000000000000..1e72383b843b6713ac5a93492ea5a98b47aed81c --- /dev/null +++ b/xtrn/uberblox/help.doc @@ -0,0 +1,49 @@ + **************************************** + * UBER BLOX! - for Synchronet v3.15+ * + * by Matt Johnson - 2009 * + **************************************** + +Uber Blox is a puzzle strategy game similar to that of the popular +web game "Super Collapse" by GameHouse. The object is to either clear +the screen entirely, or clear the number of blocks specified by the +"GOAL" for each particular level before running out of moves. + +Each level increases the "GOAL" to make it more difficult to clear +the level and after a certain number of levels the game will add +another color to the block field. + +***COMMANDS*** + +ARROW KEYS (up,down,left,right): + + Navigate the field, highlighting the color of the block over + which you are current positioned. + +ENTER KEY: + + When you press the ENTER key, it will light up a cluster of + connected blocks of the same color as the block you are + currently on. The point value of this cluster will be shown + in the "SELECTION" field to the right of the block field. + + If you wish to clear this cluster of blocks, Press the ENTER + key again and the score shown in the "SELECTION" field will be + added to your score. Otherwise, simply move your position + using the arrow keys and it will deselect the cluster. + +QUITTING: + + If you press "Q" or the ESCAPE key, your current game will be + ended and your score will be saved if it is higher than your + current best score. Otherwise your score will be discarded + until you beat your previous best score. + +***RULES*** + +By default, the smallest grouping of blocks you can select is THREE. +If you try to select a single block or TWO blocks grouped together +(depending on your SysOp's game setup) it will ignore the command. + + + + diff --git a/xtrn/uberblox/lobby.bin b/xtrn/uberblox/lobby.bin new file mode 100644 index 0000000000000000000000000000000000000000..d84de6b39bb7189c54de203ab88a9654e2541a43 --- /dev/null +++ b/xtrn/uberblox/lobby.bin @@ -0,0 +1 @@ +���������������������������������������������� � Player Name � High Score � Last On � �� �� �� �� �� �� �� �� �� �� �� ���������������������������������������������� � � � � �� �� �� �� �� �� �� �� �� �� �� � � � � � � � � �� �� �� �� �� �� �� �� �� �� �� � � � � � � � � �� �� �� �� �� �� �� �� �� �� �� � � � � � � � � �� �� �� �� �� �� �� �� �� �� �� � � � � � � � � �� �� �� �� �� �� �� �� �� �� �� � � � � � � � � �� �� �� �� �� �� �� �� �� �� �� � � � � � � � � �� �� �� �� �� �� �� �� �� �� �� ���������������������������������������������� � OPTIONS: � All-Time High Score: � �� �� �� �� �� �� �� �� �� �� �� � [P] Play Game � � � [I] Instructions � � �� �� �� �� �� �� �� �� �� �� �� � [R] Refresh Screen � � � [Q] Quit Game � � �� �� �� �� �� �� �� �� �� �� �� ���������������������������������������������� \ No newline at end of file diff --git a/xtrn/uberblox/sysop.doc b/xtrn/uberblox/sysop.doc new file mode 100644 index 0000000000000000000000000000000000000000..b9890f96668debdd892c7fa09119dfa91618ca03 --- /dev/null +++ b/xtrn/uberblox/sysop.doc @@ -0,0 +1,21 @@ +Configuration in Synchronet: + +[Uber Blox] + 1: Name Uber Blox + 2: Internal Code UBERBLOX + 3: Start-up Directory + 4: Command Line *../xtrn/blox/blox.js + 5: Clean-up Command Line + 6: Execution Cost None + 7: Access Requirements + 8: Execution Requirements + 9: Multiple Concurrent Users Yes +10: Intercept Standard I/O No +11: Native (32-bit) Executable No +12: Use Shell to Execute No +13: Modify User Data No +14: Execute on Event No +15: Pause After Execution No +16: BBS Drop File Type None +17: Place Drop File In Node Directory +18: Time Options...