diff --git a/xtrn/dicewarz2/DICE.DOC b/xtrn/dicewarz2/DICE.DOC new file mode 100644 index 0000000000000000000000000000000000000000..dee7c3fc5dec6205414a24efb018ae792f82007c --- /dev/null +++ b/xtrn/dicewarz2/DICE.DOC @@ -0,0 +1,71 @@ + ************************************ + ***** BBS DICE WARZ (2008) ****** + ** for use with Synchronet v3.14+ ** + *** by Matt Johnson ************** + ************************************ + +This game was modelled after "Dice Wars" which is a web-interface strategy +game involving dice, similar to Risk. + +The object of the game is to conquer the map by rolling dice against +neighboring tiles. The game can be played by 4 to 7 players, and can +be either 1 human player vs. all computer players, all human vs. human +players, or a mix of humans and computers. + +While the settings can be adjusted, the default maximum dice per tile is 8, +and the default maximum reserve dice is 30. + + ####GAMEPLAY#### + +When it is your turn, you press "T" to start your turn, and then "A" to +begin attacking. Use the arrow keys to move around the map, and the [ENTER] +key to select a territory. It would make sense to not attack a tile when +the odds are against you. You are not required to make an attack at all, +and you can simply press "E" to end your turn immediately if you only wish +to place reinforcements. + +Example: + Attacking tile's dice: 2 (6 + 6) + Defending tile's dice: 8 (6 + 6 + 6 + 6 + 6 + 6 + 6 + 6) + +In this scenario, the highest possible roll you can get as the attacker is +a 12, whereas the highest roll the defender can get is 48. You will most +likely lose, and would be better off attacking somewhere else. + +When rolling dice against another player, all ties go to the defender. + +If you win the dice roll, the defending tile becomes yours, and all but +one of your dice are automatically moved to the tile. The remaining die +is left behind on the tile from which you attacked. + +When you are finished attacking press "E" to end your turn, and you will +be given reinforcement dice equal to the largest number of CONNECTED +tiles you possess. This creates a secondary objective in the game which +is to connect as many of your tiles on board as possible, so as to get +more reinforcements. These are placed randomly on your tiles. + +If all of your tiles have reached the maximum number of dice per tile, +any remaining reinforcements will be added to a reserve, up to a maximum +of 30 dice. These reserve dice will be placed at the end of your turn +along with your regular reinforcements as needed, unless all of your +territories are already full. + +The game is over (for you) when you have either conquered all of the +tiles on the board, or had all of your tiles taken over by other players. + + ####SCORING#### + +1st place: +2 points +2nd place: +1 point +3rd place: no change +4th place: -1 point +5th place: -2 points +6th place: -2 points +7th place: -2 points + + ####THANKS TO#### + +Landis for his coding advice. +Chrispi for his relentless bug detection. + +Now everyone go get killed! diff --git a/xtrn/dicewarz2/ai.ini b/xtrn/dicewarz2/ai.ini new file mode 100644 index 0000000000000000000000000000000000000000..3805f555e1c7d384c60edef3c15d99703958255d --- /dev/null +++ b/xtrn/dicewarz2/ai.ini @@ -0,0 +1,34 @@ +[Attila The Hun] +sort=killMost +check=paranoid +quantity=full + +[Dweeble] +sort=wild +check=wild +quantity=full + +[Deep Blue] +sort=groupParanoid +check=ultraParanoid +quantity=random + +[AutoDeuce] +sort=paranoia +check=paranoid +quantity=full + +[Twitcher] +sort=randomAI +check=random +quantity=random + +[Hitler] +sort=wild +check=paranoid +quantity=full + +[Stalin] +sort=random +check=paranoid +quantity=random diff --git a/xtrn/dicewarz2/ai.js b/xtrn/dicewarz2/ai.js new file mode 100644 index 0000000000000000000000000000000000000000..e82475e9ce5b60f88d8ff7669da76e8d6a1b7ef6 --- /dev/null +++ b/xtrn/dicewarz2/ai.js @@ -0,0 +1,307 @@ +load("funclib.js"); +var game_number=argv[0]; +var game_dir=argv[1]; +load(game_dir+"maps.js"); +var map=game_data.list[game_number]; + +var sortFunctions={random:randomSort, wild:wildAndCrazyAISort, killMost:killMostDiceAISort, paranoia:paranoiaAISort, randomAI:randomAISort, groupParanoid:groupAndParanoidAISort}; +var checkFunctions={random:randomAICheck, paranoid:paranoidAICheck, wild:wildAndCrazyAICheck, ultraParanoid:ultraParanoidAICheck}; +var qtyFunctions={random:randomAttackQuantity, full:fullAttackQuantity, single:singleAttackQuantity}; + +/* Callbacks for sorting the targets array */ +function randomSort() +{ + return(random(2)*2-1); +} +function slowAndSteadyAISort(a, b) +{ + var adiff=0; + var bdiff=0; + + adiff=a.base.dice - a.target.dice; + bdiff=b.base.dice - b.target.dice; + return(adiff-bdiff); +} +function wildAndCrazyAISort(a, b) +{ + var adiff=0; + var bdiff=0; + + adiff=a.base.dice - a.target.dice; + bdiff=b.base.dice - b.target.dice; + return(bdiff-adiff); +} +function killMostDiceAISort(a, b) +{ + return(b.base.dice - a.target.dice); +} +function paranoiaAISort(a,b) +{ + var ascore=0; + var bscore=0; + + ascore = a.base.dice - a.target.dice; + ascore *= a.target.dice; + bscore = b.base.dice - b.target.dice; + bscore *= b.target.dice; + return(bscore-ascore); +} +function randomAISort(a,b) +{ + var sortfuncs=new Array(randomSort, slowAndSteadyAISort, wildAndCrazyAISort, killMostDiceAISort, paranoiaAISort); + + return(sortfuncs[random(sortfuncs.length)](a,b)); +} +function groupAndParanoidAISort(a,b) +{ + var aopts=0; + var bopts=0; + + function countem(map, location, p) { + var ret=0; + var neighbors=getNeighboringTiles(location,map); + for(var n=0;n<neighbors.length;n++) { + var neighbor=neighbors[n]; + if(neighbor.owner!=p) + ret++; + } + return(ret); + } + + var aopts=countem(a.map, a.target, a.base.owner); + var bopts=countem(b.map, b.target, b.base.owner); + + if(aopts==bopts) + return(paranoiaAISort(a,b)); + return(aopts-bopts); +} + +/* Callbacks for deciding if a given attack should go into the targets array */ +function randomAICheck(map, base, target) +{ + var computer=map.players[base.owner]; + var rand=random(100); + + if(rand>10 && base.dice>target.dice) + return(true); + var computer_tiles=getPlayerTiles(map,base.owner); + if(base.dice==target.dice) { + if(rand>50 || base.dice==settings.max_dice) { + if(computer_tiles.length>map.tiles.length/6 || computer.reserve>=settings.max_reserve*.66) + return(true); + if(countConnected(map,computer_tiles,base.owner)+computer.reserve>=settings.max_dice) + return(true); + } + } + if(rand>90 && base.dice==target.dice-1) { + if(computer_tiles.length>map.tiles.length/6) + return(true); + } + return(false); +} +function paranoidAICheck(map, base, target) +{ + var computer=map.players[base.owner]; + var rand=random(100); + + /* If we have an advantage, add to targets array */ + if(base.dice>target.dice) + return(true); + /* If we are equal, only add to targets if we are maxDice */ + if(base.dice==target.dice && base.dice==settings.max_dice) { + return(true); + } + return(false); +} +function wildAndCrazyAICheck(map, base, target) +{ + var computer=map.players[base.owner]; + var rand=random(100); + + if(base.dice>target.dice) + return(true); + var computer_tiles=getPlayerTiles(map,base.owner); + if(base.dice==target.dice) { + if(computer_tiles.length>map.tiles.length/6 || computer.reserve>=settings.max_reserve*.66) + return(true); + else { + if(countConnected(map,computer_tiles,base.owner)+computer.reserve>=settings.max_dice) + return(true); + } + } + if(rand>50 && base.dice==target.dice-1) { + if(computer_tiles.length>map.tiles.length/6) + return(true); + } + return(false); +} +function ultraParanoidAICheck(map, base, target) +{ + var computer=map.players[base.owner]; + var rand=random(100); + + var computer_tiles=getPlayerTiles(map,base.owner); + /* If we don't have our "fair share" of territories, use paranoid attack */ + if(computer_tiles.length < map.tiles.length/map.players.length) { + return(paranoidAICheck(map, base, target)); + } + + /* If reserves + expected new dice - used reserves is still greater than seven, use the merely paranoid attack */ + if(computer.reserve + computer_tiles.length - (computer.AI.moves*settings.max_dice) > settings.max_dice-1) { + return(paranoidAICheck(map, base, target)); + } + + /* Always try to attack on the first turn */ + if(computer.AI.turns==0) { + return(paranoidAICheck(map, base, target)); + } + + /* First, check if we would leave ourselves open. If so, + * do not take the risk */ + var neighbors=getNeighboringTiles(base,map); + for(var n=0;n<neighbors.length;n++) { + var neighbor=neighbors[n]; + if(neighbors[n].id==target.id) + continue; + if(neighbor.owner!=base.owner && neighbor.dice>=2) + return(false); + } + + /* Next, check that we have a dice advantage */ + if(base.dice <= target.dice) + return(false); + + /* Finally, check that we will still be at least equal to all neighbors after the capture */ + neighbors=getNeighboringTiles(target,map); + for(var n=0;n<neighbors.length;n++) { + var neighbor=neighbors[n]; + if(neighbor.id==base.id) + continue; + if(neighbor.owner!=base.owner && neighbor.dice >= base.dice) { + return(false); + } + } + return(true); +} + +/* Callbacks for selecting the number of targets to use */ +function randomAttackQuantity(tlen) +{ + if(tlen <= 2) + return(tlen); + return(random(tlen-2)+2); +} +function fullAttackQuantity(tlen) +{ + return(tlen); +} +function singleAttackQuantity(tlen) +{ + if(tlen > 0) + return(1); + return(0); +} + +/* Attack functions */ +function takeTurn() +{ + var computer=map.players[map.turn]; + debug("computer taking turn: " + computer.name); + var territories=getPlayerTiles(map,map.turn); + var attacks=[]; + + /* For each owned territory */ + for(var t=0;t<territories.length;t++) { + var base=territories[t]; + /* If we have enough to attack */ + var attack_options=canAttack(map,base); + if(attack_options.length>0) { + var basetargets=[]; + /* Randomize the order to check in */ + attack_options.sort(randomSort); + for(var o=0;o<attack_options.length;o++) { + var target=attack_options[o]; + /* Check if this is an acceptable attack */ + if(checkFunctions[computer.AI.check](map,base,target)) + basetargets.push({map:map,target:target,base:base}); + } + /* If we found acceptable attacks, sort them and choose the best one */ + if(basetargets.length > 0) { + basetargets.sort(sortFunctions[computer.AI.sort]); + attacks.push(basetargets.shift()); + } + } + } + /* Randomize the targets array */ + attacks.sort(randomSort); + attackQuantity=qtyFunctions[computer.AI.qty](attacks.length); + if(attackQuantity<1) return false; + + attacks.sort(sortFunctions[computer.AI.sort]); + for(var a=0;a<attackQuantity;a++) + { + var attack=attacks.shift(); + var attacking=attack.base; + var defending=attack.target; + var attacker=map.players[attacking.owner].name; + var defender=map.players[defending.owner].name; + + var a=new Roll(attacking.owner); + for(var r=0;r<attacking.dice;r++) { + var roll=random(6)+1; + a.roll(roll); + } + var d=new Roll(defending.owner); + for(var r=0;r<defending.dice;r++) { + var roll=random(6)+1; + d.roll(roll); + } + var data=new Data("battle"); + data.a=a; + data.d=d; + stream.send(data); + + if(a.total>d.total) { + defending.assign(attacking.owner,attacking.dice-1); + } + attacking.dice=1; + + game_data.saveActivity(map,attacker + " attacked " + defender + ": " + attacking.dice + " vs " + defending.dice); + game_data.saveActivity(map,attacker + ": " + a.total + " " + defender + ": " + d.total); + game_data.saveTile(map,attacking); + game_data.saveTile(map,defending); + computer.AI.moves++; + } + computer.AI.turns++; + return true; +} +function reinforce() +{ + var player_tiles=getPlayerTiles(map,map.turn); + var reinforcements=countConnected(map,player_tiles,map.turn); + var placed=placeReinforcements(map,player_tiles,reinforcements); + var reserved=placeReserves(map,reinforcements-placed.length); + var data=new Data("activity"); + if(placed.length>0) { + data.activity=("\1n\1y" + map.players[map.turn].name + " placed " + placed.length + " dice"); + stream.send(data); + } + if(reserved>0) { + data.activity=("\1n\1y" + map.players[map.turn].name + " reserved " + reserved + " dice"); + stream.send(data); + } +} + +while(map.players[map.turn].AI && map.in_progress) { + while(1) { + if(!takeTurn()) { + updateStatus(map); + break; + } + updateStatus(map); + } + reinforce(); + nextTurn(map); + map.attacking=map.turn; + game_data.saveData(map); +} diff --git a/xtrn/dicewarz2/background.bin b/xtrn/dicewarz2/background.bin new file mode 100644 index 0000000000000000000000000000000000000000..3185b859d89ebd14b1bbabd9886dd827ff9fd40e --- /dev/null +++ b/xtrn/dicewarz2/background.bin @@ -0,0 +1 @@ + l�` pDp ~Ip ~Cp ~Ep ~-p ~Wp ~Ap ~Rp ~Zp ~-p ~]p[p p�` g g g g g g g g g g g g g g g g g g ` ` `�pPpLpApYpEpRpSp�p ` ` ` ` ` ` ` ` `�` wTp x�p wDp w�p xRp p�` `�` �` �` �`�` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ �` �` �`�` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ �` �` �`�` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ �` �` �`�` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ �` �` �`�` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ �` �` �`�` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ �` �` �`�` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ �` �` �`�` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ �` �` �`�` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ �` `�pApCpTpIpVpIpTpYp�p ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `�` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ �` �`�` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ �` �`�` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ �` �`�` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ �` �`�` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ �` �`�` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ �` `�pCpHpApTp�p ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `�` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ �` �`�` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ �` �`�` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ �` �`�` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ �` �`�` ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ �` �`�` �` �` `�` pMpEpNpUp:p�` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` \ No newline at end of file diff --git a/xtrn/dicewarz2/dice.ini b/xtrn/dicewarz2/dice.ini new file mode 100644 index 0000000000000000000000000000000000000000..c1d16abb27fd92dc2afa5410c54415d294d207f8 --- /dev/null +++ b/xtrn/dicewarz2/dice.ini @@ -0,0 +1,52 @@ +points_to_win= 100 +min_points= -2 +max_games= 100 +max_games_per_player= 30 +num_players= 7 +min_tile_size= 3 +max_tile_size= 7 +max_dice= 8 +max_reserve= 30 +logging_enabled= true +ai_file= ai.ini +player_file= players.ini +hof_file= hof.ini +instruction_file= dice.doc +background_file= background.bin +lobby_file= lobby.bin +border_color= DARKGRAY +highlight_color= LIGHTRED + +[background_colors] +0=BG_BLUE +1=BG_CYAN +2=BG_RED +3=BG_GREEN +4=BG_BROWN +5=BG_MAGENTA +6=BG_LIGHTGRAY + +[foreground_colors] +0=BLUE +1=CYAN +2=RED +3=GREEN +4=BROWN +5=MAGENTA +6=LIGHTGRAY + +[text_colors] +0=WHITE +1=LIGHTCYAN +2=LIGHTRED +3=LIGHTGREEN +4=YELLOW +5=LIGHTMAGENTA +6=BLACK + +;points awarded +[point_set] +win=2 +loss=-2 +kill=1 +forfeit=-1 \ No newline at end of file diff --git a/xtrn/dicewarz2/dice2.js b/xtrn/dicewarz2/dice2.js new file mode 100644 index 0000000000000000000000000000000000000000..ce0052ebe0f834fb098e5580629e1f51216d88be --- /dev/null +++ b/xtrn/dicewarz2/dice2.js @@ -0,0 +1,731 @@ +load("sbbsdefs.js"); +load("graphic.js"); +load("chateng.js"); +load("funclib.js"); + +var game_dir=js.exec_dir; + +load(game_dir+"maps.js"); +load(game_dir+"menu.js"); + +var oldpass=console.ctrlkey_passthru; +console.ctrlkey_passthru="+ACGKLOPQRTUVWXYZ_"; +bbs.sys_status|=SS_MOFF; + +var menu; +var chat= new ChatEngine(game_dir); +var players= new PlayerData(game_dir+settings.player_file); +var game_background=loadGraphic(game_dir+settings.background_file); +var lobby_background=loadGraphic(game_dir+settings.lobby_file); + +//GLOBAL GAME FUNCTIONS +function splashStart() +{ + console.clear(); + var splash_filename=game_dir + "welcome.bin"; + if(file_exists(splash_filename)) { + var splash=new Graphic(80,24); + splash.load(splash_filename); + splash.draw(); + + console.gotoxy(1,23); + console.center("\1n\1c[\1hPress any key to continue\1n\1c]"); + while(console.inkey(K_NOECHO|K_NOSPIN)==""); + } +} +function splashExit() +{ + stream.close(); + chat.exit(); + console.ctrlkey_passthru=oldpass; + bbs.sys_status&=~SS_MOFF; + console.clear(ANSI_NORMAL); + var splash_filename=game_dir + "exit.bin"; + if(file_exists(splash_filename)) { + var splash_size=file_size(splash_filename); + splash_size/=2; + splash_size/=80; + var splash=new Graphic(80,splash_size); + splash.load(splash_filename); + splash.draw(); + + console.gotoxy(1,23); + console.center("\1n\1c[\1hPress any key to continue\1n\1c]"); + console.getkey(K_NOSPIN|K_NOCRLF); + } + exit(); +} +function loadGraphic(filename) +{ + log("loading graphic: " + filename); + var graphic=new Graphic(80,24); + graphic.load(filename); + return graphic; +} +function chatInput() +{ + chat.input_line.clear(); + while(1) { + var key=console.inkey(K_NOCRLF|K_NOSPIN|K_NOECHO,5); + if(key) { + chat.processKey(key); + switch(key) { + case '\r': + case '\n': + hideChatLine(); + return true; + default: + break; + } + } + cycle(); + } +} +function hideChatLine() +{ + console.gotoxy(chat.input_line); + console.cleartoeol(BG_BROWN); +} +function menuPrompt(string,append) +{ + if(append) console.popxy(); + else { + menu.clear(); + console.gotoxy(menu.x,menu.y); + } + console.attributes=BG_BROWN+BLACK; + console.putmsg(string,P_SAVEATR); + console.pushxy(); + return console.getkey(K_NOECHO|K_NOCRLF|K_UPPER|K_NOSPIN); +} +function menuText(string,append) +{ + if(append) console.popxy(); + else { + menu.clear(); + console.gotoxy(menu.x,menu.y); + } + console.attributes=BG_BROWN+BLACK; + console.putmsg(string,P_SAVEATR); + console.pushxy(); +} +function viewInstructions(section) +{ + +} +function cycle() +{ + chat.receive(); +} + +//LOBBY LOOP +function lobby() +{ + initMenu(); + initChat(); + + function main() + { + redraw(); + while(1) + { + var cmd=console.inkey(K_NOCRLF|K_NOSPIN|K_NOECHO|K_UPPER,5); + if(cmd) { + menu.clear(); + switch(cmd) + { + case "R": + viewRankings(); + break; + case "S": + if(selectGame()) return true; + break; + case "I": + viewInstructions(); + break; + case "B": + createNewGame(); + break; + case "C": + chatInput(); + break; + case KEY_UP: + case KEY_DOWN: + case KEY_HOME: + case KEY_END: + chat.processKey(cmd); + break; + case "\x1b": + case "Q": + return false; + default: + break; + } + menu.draw(); + } + lobbyCycle(); + } + } + function lobbyCycle() + { + game_data.update(); + cycle(); + } + function wrap(msg,lst) + { + console.pushxy(); + console.putmsg(msg); + console.putmsg(" \1w\1h: "); + var col=32; + var delimiter="\1n\1g,"; + for(aa=0;aa<lst.length;aa++) + { + if(aa==lst.length-1) delimiter=""; + var item=lst[aa]+delimiter; + if((col + console.strlen(item))>78) { + console.crlf(); + console.right(31); + col=32; + } + console.putmsg("\1h\1g" + item); + col += console.strlen(item); + } + console.crlf(); + console.right(); + } + function gameList() + { + var sorted=sortGameData(game_data.list); + clearBlock(2,2,78,16); + console.gotoxy(2,2); + wrap("\1gGames in progress ",sorted.started); + wrap("\1gGames needing more players ",sorted.waiting); + wrap("\1gCompleted games ",sorted.finished); + wrap("\1gYou are involved in games ",sorted.yourgames); + wrap("\1gIt is your turn in games ",sorted.yourturn); + wrap("\1gYou are eliminated in games",sorted.eliminated); + wrap("\1gYou have won games ",sorted.yourwins); + wrap("\1gSingle-player games ",sorted.singleplayer); + } + function initChat() + { + chat.init("dice warz",78,5,2,19); + chat.input_line.init(10,18,70,"\0017","\1k"); + } + function initMenu() + { + var menu_items=[ "", + "\1w\1h~R\1n\1k\0013ankings", + "\1w\1h~S\1n\1k\0013elect game", + "\1w\1h~B\1n\1k\0013egin new game", + "\1w\1h~H\1n\1k\0013elp", + "\1w\1h~C\1n\1k\0013hat", + "\1w\1h~Q\1n\1k\0013uit"]; + menu=new Menu(menu_items,BG_BROWN,10,24); + } + function selectGame() + { + if(game_data.count()==0) { + menuPrompt("No games to select \1w\1h[press any key]"); + return false; + } + while(1) { + menuText("Game number: \1w\1h"); + var num=console.getstr(game_data.last_game_number.toString().length,K_NUMBER|K_NOCRLF|K_NOSPIN); + if(!num) { + return false; + } + if(game_data.list[num]) { + run(game_data.list[num]); + return true; + } else { + menuText("\1w\1hNo such game!",true); + menuPrompt(" [press any key]",true); + } + } + } + function startGame(map) + { + if(map.players.length==1) map.single_player=true; + addComputers(map); + generateMap(map); + shufflePlayers(map); + dispersePlayers(map); + map.in_progress=true; + game_data.save(map); + } + function joinGame(map) + { + addPlayer(map,user.alias,getVote()); + } + function createNewGame() + { + response=menuPrompt("Begin a new game? \1w\1h[Y/n]: "); + if(response!=='Y') return false; + var new_game=new MapData(); + + while(1) { + response=menuPrompt("Single player game? \1w\1h[y/N]: "); + if(response=='\x1b' || response=='Q') { + return false; + } else if(response=='Y') { + addPlayer(new_game,user.alias,true); + startGame(new_game); + run(new_game); + break; + } else if(response=='N') { + game_data.save(new_game); + break; + } else { + menuPrompt("Invalid response \1w\1h[press any key]",true); + } + } + } + function getVote() + { + } + function redraw() + { + console.clear(ANSI_NORMAL); + lobby_background.draw(); + menu.draw(); + chat.redraw(); + hideChatLine(); + gameList(); + } + + main(); +} +//GAME LOOP +function run(map) +{ + var activity_window=new Graphic(32,5); + var ax=48; + var ay=12; + var player=findPlayer(map,user.alias); + var update=true; + + function main() + { + menu.draw(); + turnAlert(); + var coords=false; + if(map.single_player && player>=0 && map.players[map.turn].AI) { + load(true,game_dir + "ai.js",map.game_number,game_dir); + } + + while(1) + { + gameCycle(); + var cmd=console.inkey(K_NOCRLF|K_NOSPIN|K_NOECHO|K_UPPER,5); + if(cmd && menu.items[cmd] && menu.items[cmd].enabled) { + menu.clear(); + switch(cmd) + { + case "I": + viewInstructions(); + break; + case "T": + takeTurn(); + break; + case "A": + coords=attack(coords); + listPlayers(); + break; + case "E": + endturn(); + break; + case "F": + forfeit(); + break; + case "C": + chatInput(); + break; + case "R": + redraw(); + break; + case KEY_UP: + case KEY_DOWN: + case KEY_HOME: + case KEY_END: + chat.processKey(cmd); + break; + case "\x1b": + case "Q": + return lobby(); + default: + break; + } + setMenuCommands(); + } + } + } + function endturn() + { + reinforce(); + nextTurn(map); + map.attacking=map.turn; + game_data.saveData(map); + if(map.players[map.turn].AI) { + load(true,game_dir + "ai.js",map.game_number,game_dir); + } + listPlayers(); + } + function reinforce() + { + var player_tiles=getPlayerTiles(map,map.turn); + var reinforcements=countConnected(map,player_tiles,map.turn); + var placed=placeReinforcements(map,player_tiles,reinforcements); + if(placed.length>0) { + for(var p=0;p<placed.length;p++) { + var home=map.tiles[placed[p]].home; + drawSector(map,home.x,home.y); + } + activityAlert("\1n\1y" + map.players[map.turn].name + " placed " + placed.length + " dice"); + } + var reserved=placeReserves(map,reinforcements-placed.length); + if(reserved>0) { + activityAlert("\1n\1y" + map.players[map.turn].name + " reserved " + reserved + " dice"); + } + } + function turnAlert() + { + if(map.turn==player) activityAlert("\1c\1hIt is your turn"); + else activityAlert("\1n\1cIt is " + map.players[map.turn].name + "'s turn"); + } + function takeTurn() + { + map.attacking=player; + } + function attack(coords) + { + if(!coords) coords=new Coords(map.width/2,map.height/2,0); + var attacking; + var attacker=map.players[player].name; + var defending; + var defender; + + activityAlert("\1nChoose \1r\1hattacking \1nterritory"); + while(1) { + coords=select(coords); + if(!coords) return false; + attacking=map.tiles[map.grid[coords.x][coords.y]]; + if(attacking.owner==player) { + if(attacking.dice>1) break; + else activityAlert("\1r\1hNot enough dice to attack"); + } else { + activityAlert("\1r\1hNot your territory"); + } + } + activityAlert("\1nChoose \1r\1htarget \1nterritory"); + while(1) { + coords=select(coords); + if(!coords) return false; + defending=map.tiles[map.grid[coords.x][coords.y]]; + if(defending.owner!=player) { + if(connected(attacking,defending,map)) { + defender=map.players[defending.owner].name; + break; + } else { + activityAlert("\1r\1hNot connected"); + } + } else { + activityAlert("\1r\1hNot an enemy territory"); + } + } + + chat.chat_room.clear(); + var a=new Roll(attacking.owner); + for(var r=0;r<attacking.dice;r++) { + var roll=random(6)+1; + a.roll(roll); + } + showRoll(a.rolls,LIGHTGRAY+BG_RED,chat.chat_room.x,chat.chat_room.y); + var d=new Roll(defending.owner); + for(var r=0;r<defending.dice;r++) { + var roll=random(6)+1; + d.roll(roll); + } + showRoll(d.rolls,BLACK+BG_LIGHTGRAY,chat.chat_room.x,chat.chat_room.y+3); + chat.chat_room.draw(); + battle(a,d); + var data=new Data("battle"); + data.a=a; + data.d=d; + stream.send(data); + + if(a.total>d.total) { + defending.assign(attacking.owner,attacking.dice-1); + if(countTiles(map,defending.owner)==0) map.players[defending.owner].active=false; + drawTile(map,defending); + } + attacking.dice=1; + drawSector(map,attacking.home.x,attacking.home.y); + + game_data.saveActivity(map,attacker + " attacked " + defender + ": " + attacking.dice + " vs " + defending.dice); + game_data.saveActivity(map,attacker + ": " + a.total + " " + defender + ": " + d.total); + game_data.saveTile(map,attacking); + game_data.saveTile(map,defending); + + updateStatus(map); + + return coords; + } + function battle(a,d) + { + activityAlert("\1n" + map.players[a.pnum].name + " vs. " + map.players[d.pnum].name); + activityAlert("\1n" + map.players[a.pnum].name + " rolls " + a.rolls.length + (a.rolls.length>1?" dice":" die")+"\1h: \1c" + a.total); + activityAlert("\1n" + map.players[d.pnum].name + " rolls " + d.rolls.length + (d.rolls.length>1?" dice":" die")+"\1h: \1c" + d.total); + } + function select(start) + { + var posx=start.x; + var posy=start.y; + var yoffset=start.z; + var cursor="\0017\1k\xC5"; + getxy(posx,posy); + if(yoffset>0) console.down(); + console.pushxy(); + console.putmsg(cursor,P_SAVEATR); + + while(1) + { + var xoffset=posx%2; + var cmd=console.inkey(K_NOCRLF|K_NOSPIN|K_NOECHO|K_UPPER,5); + if(cmd) { + drawSector(map,posx,posy); + console.popxy(); + switch(cmd) + { + case "R": + redraw(); + console.popxy(); + break; + case "C": + chatInput(); + console.popxy(); + break; + case KEY_UP: + if(posy<=0) break; + if(yoffset==1) yoffset--; + else { + yoffset++; + posy--; + } + console.up(); + break; + case KEY_DOWN: + if(posy==map.height-1 && yoffset==1) break; + if(posy>=map.height) break; + if(yoffset==0) yoffset++; + else { + yoffset--; + posy++; + } + console.down(); + break; + case KEY_LEFT: + if(posx==0) break; + if(yoffset==0) { + yoffset++; + if(xoffset==0) posy--; + } else { + yoffset--; + if(xoffset==1) posy++; + } + posx--; + console.left(2); + break; + case KEY_RIGHT: + if(posx==map.width-1) break; + if(yoffset==0) { + yoffset++; + if(xoffset==0) posy--; + } else { + yoffset--; + if(xoffset==1) posy++; + } + posx++; + console.right(2); + break; + case KEY_HOME: + if(posx==0) posx=map.width-1; + else posx=0; + posy=0; + getxy(posx,posy); + console.down(); + break; + case KEY_END: + if(posx==0) posx=map.width-1; + else posx=0; + posy=map.height-1; + getxy(posx,posy); + console.down(); + break; + case "\r": + case "\n": + var tile=map.grid[posx][posy]; + var north=map.grid[posx][posy-1]; + var valid=true; + if(yoffset==1) { + if(tile==undefined) valid=false; + } else if(tile==undefined && north==undefined) valid=false; + else if(tile!==north) { + if(north>=0 && tile==undefined) posy-=1; + else if(tile>=0 && north>=0) valid=false; + } + if(valid) { + var position=new Coords(posx,posy,yoffset); + return position; + } + activityAlert("\1r\1hInvalid selection"); + console.popxy(); + break; + case "\x1b": + case "Q": + return false; + default: + break; + } + console.pushxy(); + console.putmsg(cursor,P_SAVEATR); + gameCycle(); + } + } + + } + function initMenu() + { + var menu_items=[ "", + "\1w\1h~T\1n\1k\0013ake turn", + "\1w\1h~A\1n\1k\0013ttack", + "\1w\1h~E\1n\1k\0013nd turn", + "\1w\1h~R\1n\1k\0013edraw", + "\1w\1h~H\1n\1k\0013elp", + "\1w\1h~F\1n\1k\0013orfeit", + "\1w\1h~C\1n\1k\0013hat", + "\1w\1h~Q\1n\1k\0013uit"]; + menu=new Menu(menu_items,BG_BROWN,10,24); + setMenuCommands(); + } + function setMenuCommands() + { + update=true; + if(player>=0 && map.in_progress) { + if(player==map.attacking) { + menu.enable("A"); + menu.enable("E"); + menu.enable("F"); + menu.disable("T"); + return; + } + if(player==map.turn) { + menu.enable("T"); + menu.disable("A"); + menu.disable("E"); + menu.disable("F"); + return; + } + } + menu.disable("T"); + menu.disable("A"); + menu.disable("E"); + menu.disable("F"); + } + function initChat() + { + chat.init("dice warz game #" + map.game_number,31,6,48,18); + chat.input_line.init(10,24,70,"\0017","\1k"); + } + function initGame() + { + } + function activityAlert(msg) + { + activity_window.putmsg(undefined,undefined,msg+"\r\n",undefined,true); + activity_window.draw(ax,ay); + } + function gameCycle() + { + cycle(); + var data=stream.receive(); + if(data) { + debug(data,LOG_WARNING); + switch(data.type) + { + case "battle": + battle(data.a,data.d); + break; + case "turn": + map.turn=data.turn; + turnAlert(); + setMenuCommands(); + break; + case "tile": + map.tiles[data.tile.id].assign(data.tile.owner,data.tile.dice); + drawTile(map,map.tiles[data.tile.id]); + break; + case "activity": + activityAlert(data.activity); + break; + default: + break; + } + listPlayers(); + } + if(update) { + menu.draw(); + update=false; + } + } + function listPlayers() + { + var x=48; + var y=3; + for(var p=0;p<map.players.length;p++) { + var plyr=map.players[p]; + var fg=plyr.active?getColor(settings.foreground_colors[p]):BLACK; + var bg=plyr.active?getColor(settings.background_colors[p]):BG_BLACK; + var txt=plyr.active?getColor(settings.text_colors[p]):DARKGRAY; + + console.gotoxy(x,y+p); + console.attributes=BG_BLACK + fg; + console.putmsg("\xDE",P_SAVEATR); + console.attributes=bg + txt; + console.putmsg(printPadded(plyr.name,16),P_SAVEATR); + console.attributes=BG_BLACK + fg; + console.putmsg("\xDD",P_SAVEATR); + console.right(); + console.attributes=bg + txt; + console.putmsg(printPadded(countTiles(map,p),4," ","right"),P_SAVEATR); + console.attributes=bg + BLACK; + console.putmsg("\xB3",P_SAVEATR); + console.attributes=bg + txt; + console.putmsg(printPadded(countDice(map,p),3," ","right"),P_SAVEATR); + console.attributes=bg + BLACK; + console.putmsg("\xB3",P_SAVEATR); + console.attributes=bg + txt; + console.putmsg(printPadded(plyr.reserve+" ",4," ","right"),P_SAVEATR); + } + } + function redraw() + { + console.clear(ANSI_NORMAL); + game_background.draw(); + drawMap(map); + listPlayers(); + chat.redraw(); + activity_window.draw(48,12); + hideChatLine(); + } + + initMenu(); + initChat(); + initGame(); + redraw(); + main(); +} + +splashStart(); +while(1) if(!lobby()) break; +splashExit(); diff --git a/xtrn/dicewarz2/exit.bin b/xtrn/dicewarz2/exit.bin new file mode 100644 index 0000000000000000000000000000000000000000..cf3e6659afe57a9eaed6f58089faaa3d7a9f8517 --- /dev/null +++ b/xtrn/dicewarz2/exit.bin @@ -0,0 +1,80 @@ + ���������������������������������� + � THE BROKEN BUBBLE BBS � T +H +A +N +K +S + +F +O +R + +P +L +A +Y +I +N +G +! + � o . �� � o o . � o . ���� If you enjoyed playing this game, please � . � o �������� �� � feel free to try out the other originals, � �� . ������������ . �. o � and if you have your own BBS, please consider� . ��� ���;�;����������3 � � setting them up for your users. � � ���;�; 3�3 3�3�3�3�3�3�3���; ��� � � . � ���; ;�3�3�3���3�3�3�3���3�;�� � � � All javascript games by Matt Johnson are � � �����3�3�3��������3��� ����� free and available for download from the � � ���>�������3�3�3�3�3��3�;�;�;�? o � � Synchronet CVS repository at: � .�������� ; ; ; ;�3�;�;�;�;�� � .� � �� ;������ ;�3�;�;�;�;�;�� .� � h +t +t +p +: +/ +/ +c +v +s +. +s +y +n +c +h +r +o +. +n +e +t +/ + � � o� � ; ; ; ;�;�;�;�;�;�;��?� � o� � . ��� o��;�;�;�;�;�;���?�� � . . � -or- � �� �� �������� � � � � � � o � . � h +t +t +p +: +/ +/ +w +w +w +. +t +h +e +b +r +o +k +e +n +b +u +b +b +l +e +. +c +o +m +: +8 +0 +0 +0 +/ + � � . . o o � � � http://www.thebrokenbubble.com � ���������������������������������� \ No newline at end of file diff --git a/xtrn/dicewarz2/lobby.bin b/xtrn/dicewarz2/lobby.bin new file mode 100644 index 0000000000000000000000000000000000000000..4cfb58285000bafeb0ab4a352034b4077dd6d71c --- /dev/null +++ b/xtrn/dicewarz2/lobby.bin @@ -0,0 +1 @@ + l�` pDp ~Ip ~Cp ~Ep ~-p ~Wp ~Ap ~Rp ~Zp ~-p ~]p[p p�` g g g g g g g g g g g g g g g g g g g g g g g g g g g g g `b`y` nM`a`t`t` `J`o`h`n`s`o`n` f(`2`0`1`0`)` h�` �`�` �`�` �`�` �`�` �`�` �`�` �`�` �`�` �`�` �`�` �`�` �`�` �`�` �`�` �`�` �` o�` pCpHpApTp:p�` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `�` �`�` �`�` �`�` �`�` �` `�` pMpEpNpUp:p�` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` \ No newline at end of file diff --git a/xtrn/dicewarz2/maps.js b/xtrn/dicewarz2/maps.js new file mode 100644 index 0000000000000000000000000000000000000000..ee4334f67e0c08c2d0d60d954a69e297c05c04a3 --- /dev/null +++ b/xtrn/dicewarz2/maps.js @@ -0,0 +1,838 @@ +load(game_dir+"player.js"); +load(game_dir+"rolldice.js"); +load("commclient.js"); + +var settings= loadSettings(game_dir+"dice.ini"); +var game_data= new GameData(game_dir+"*.dw"); +var stream= new ServiceConnection("Dice Warz ][","dicewars"); + +function Char(ch,fg,bg) +{ + this.ch=ch; + this.fg=fg; + this.bg=bg; + this.draw=function() { + console.attributes=this.fg+this.bg; + console.putmsg(this.ch,P_SAVEATR); + } +} +function MapData(game_number) +{ + this.width=22; + this.height=10; + this.grid=createGrid(this.width,this.height); + this.tiles=[]; + this.players=[]; + this.history=[]; + this.turn=0; + this.round=0; + this.attacking=false; + this.in_progress=false; + this.single_player=false; + this.winner=false; + this.game_number=game_number?game_number:getNewGameNumber(); + this.last_update=time(); +} +function Tile(id) +{ + this.id=id; + this.coords=[]; + this.home; + this.owner; + this.dice=0; + this.assign=function(owner,dice) + { + this.owner=owner; + this.dice=dice; + } +} +function Coords(x,y,z) +{ + this.x=x; + this.y=y; + this.z=z; +} +function GameData(filemask) +{ + this.files=filemask; + this.list=[]; + this.last_game_number=0; + this.last_update=0; + + const update_frequency=5 //SECONDS BETWEEN GAME UPDATE SCANS + + this.count=function() + { + var count=0; + for(var i in this.list) { + count++; + } + return count; + } + this.init=function() + { + this.update(); + } + this.load=function(filename) + { + var file=new File(filename); + file.open('r+',true); + + var game_number=getGameNumber(filename); + if(game_number>this.last_game_number) this.last_game_number=game_number; + var map=new MapData(game_number); + debug("loading game: " + game_number,LOG_DEBUG); + + map.num_players=file.iniGetValue(null,"num_players"); + map.single_player=file.iniGetValue(null,"single_player"); + map.in_progress=file.iniGetValue(null,"in_progress"); + map.winner=file.iniGetValue(null,"winner"); + map.turn=file.iniGetValue(null,"turn"); + + var players=file.iniGetAllObjects("index","p"); + var aifile=new File(game_dir + settings.ai_file); + aifile.open("r",true); + for(var p=0;p<players.length;p++) { + var player=players[p]; + map.players[player.index]=new Player(player.name,player.vote); + map.players[player.index].reserve=player.reserve; + if(player.AI) { + var sort=aifile.iniGetValue(player.name, "sort"); + var check=aifile.iniGetValue(player.name, "check"); + var qty=aifile.iniGetValue(player.name, "quantity"); + map.players[player.index].AI=new AI(sort,check,qty); + } + } + aifile.close(); + + var array=file.iniGetAllObjects("index","t"); + for(var t=0;t<array.length;t++) { + var tile=new Tile(array[t].index); + tile.assign(array[t].o,array[t].d); + + var home=array[t].h.split("-"); + tile.home=new Coords(home[0],home[1]); + + var sectors=array[t].s.split(","); + for(var s=0;s<sectors.length;s++) { + var sector=sectors[s].split("-"); + var coords=new Coords(sector[0],sector[1]); + tile.coords.push(coords); + map.grid[coords.x][coords.y]=array[t].index; + } + map.tiles[array[t].index]=tile; + } + for(var p=0;p<map.players.length;p++) { + if(countTiles(map,p)==0) map.players[p].active=false; + } + this.list[game_number]=map; + } + this.save=function(map) + { + this.list[map.game_number]=map; + if(map.game_number>this.last_game_number) this.last_game_number=map.game_number; + + menuText("Storing game data"); + this.saveData(map); + + menuText("Storing player data"); + for(var p=0;p<map.players.length;p++) + { + menuText(".",true); + var player=map.players[p]; + this.savePlayer(map,player,p); + } + + menuText("Storing map data"); + for(var t=0;t<map.tiles.length;t++) + { + menuText(".",true); + var tile=map.tiles[t]; + this.saveTile(map,tile); + } + } + this.closeGameFile=function(file,map) + { + if(file.is_open) file.close(); + map.last_update=file_date(file.name); + } + this.openGameFile=function(map) + { + var filename=getFileName(map.game_number); + var file=new File(filename); + if(!file.is_open) file.open((file_exists(file.name) ? 'r+':'w+'),true); + return file; + } + this.saveActivity=function(map,activity) + { + } + this.savePlayer=function(map,p,n) + { + var file=this.openGameFile(map); + file.iniSetValue("p"+n,"name",p.name); + file.iniSetValue("p"+n,"reserve",p.reserve); + file.iniSetValue("p"+n,"vote",p.vote); + file.iniSetValue("p"+n,"AI",p.AI?true:false); + this.closeGameFile(file,map); + } + this.saveData=function(map) + { + var file=this.openGameFile(map); + file.iniSetValue(null,"num_players",map.num_players); + file.iniSetValue(null,"single_player",map.game_number); + file.iniSetValue(null,"in_progress",map.in_progress); + file.iniSetValue(null,"winner",map.winner); + file.iniSetValue(null,"turn",map.turn); + file.iniSetValue(null,"round",map.round); + this.closeGameFile(file,map); + } + this.saveTile=function(map,tile) + { + var file=this.openGameFile(map); + file.iniSetValue("t"+tile.id,"d",tile.dice); + file.iniSetValue("t"+tile.id,"o",tile.owner); + file.iniSetValue("t"+tile.id,"h",tile.home.x + "-" + tile.home.y); + var slist=[]; + for(var c=0;c<tile.coords.length;c++) + { + var sector=tile.coords[c]; + slist.push(sector.x+"-"+sector.y); + } + file.iniSetValue("t"+tile.id,"s",slist); + this.closeGameFile(file,map); + + var data=new Data("tile"); + data.tile=tile; + stream.send(data); + } + this.update=function() + { + if(time()-this.last_update<update_frequency) return false; + + var game_list=directory(this.files); + for(var g=0;g<game_list.length;g++) { + var game_number=getGameNumber(game_list[g]); + if(this.list[game_number]) { + if(this.list[game_number].last_update<file_date(game_list[g])) { + debug("file has been modified, reloading: " + game_list[g]); + this.load(game_list[g]); + } + } else { + this.load(game_list[g]); + } + } + this.last_update=time(); + } + this.init(); +} +function Data(type) +{ + this.type=type; +} + + //GAME DATA FUNCTIONS + function getxy(x,y) + { + var offset=(x%2); + var posx=(x*2)+3; + var posy=(y*2)+2+offset; + var coords=new Coords(posx,posy); + console.gotoxy(coords); + return coords; + } + function loadSettings(filename) + { + var file=new File(filename); + file.open('r',true); + + var data=file.iniGetObject(null); + data.background_colors=file.iniGetObject("background_colors"); + data.foreground_colors=file.iniGetObject("foreground_colors"); + data.text_colors=file.iniGetObject("text_colors"); + data.point_set=file.iniGetObject("point_set"); + + file.close(); + return data; + } + function getPlayerColors(pnum) + { + var colors=new Object(); + colors.bg=(pnum>=0?getColor(settings.background_colors[pnum]):BG_BLACK); + colors.fg=(pnum>=0?getColor(settings.foreground_colors[pnum]):BLACK); + colors.txt=(pnum>=0?getColor(settings.text_colors[pnum]):BLUE); + return colors; + } + function sortGameData(array) + { + var sorted=new Object(); + sorted.started=[]; + sorted.waiting=[]; + sorted.finished=[]; + sorted.yourgames=[]; + sorted.yourturn=[]; + sorted.eliminated=[]; + sorted.yourwins=[]; + sorted.singleplayer=[]; + + for(var i in array) { + var game=array[i]; + var in_game=findPlayer(game,user.alias); + + if(game.single_player) { + if(in_game) sorted.singleplayer.push(i); + } else { + if(in_game) { + sorted.yourgames.push(i); + if(game.turn==in_game) sorted.yourturn.push(i); + } + if(game.in_progress) sorted.started.push(i); + else if(game.winner) { + sorted.finished.push(i); + if(game.winner==user.alias) sorted.yourwins.push(i); + else sorted.eliminated.push(i); + } else { + sorted.waiting.push(i); + } + } + } + return sorted; + } + function getFileName(game_number) + { + var name=game_number; + if(name<10) name="0"+name; + return game_dir+name+".dw"; + } + function getGameNumber(filename) + { + filename=file_getname(filename); + var game_number=parseInt(filename.substring(0,filename.indexOf("."))); + return game_number; + } + function getNewGameNumber() + { + var next=1; + while(file_exists(getFileName(next))) + { + next++; + } + if(next>settings.max_games) return false; + return next; + } + + //MAP DISPLAY FUNCTIONS + function findTile(grid,coords) + { + if(coords && grid[coords.x][coords.y]>=0) return grid[coords.x][coords.y]; + else return -1; + } + function drawTile(map,tile) + { + for(var c=0;c<tile.coords.length;c++) { + var coords=tile.coords[c]; + drawSector(map,coords.x,coords.y); + } + var borders=getBorders(map,tile); + for(var x in borders) { + if(borders[x]) { + for(var y in borders[x]) { + drawSector(map,x,y); + } + } + } + } + function drawSector(map,x,y) // YAY 168 LINES OF CODE TO DRAW 4 CHARACTERS + { + var current_coords=new Coords(x,y); + var neighbors=getNeighboringSectors(current_coords,map.grid); + var current=findTile(map.grid,current_coords); + var north=findTile(map.grid,neighbors.north); + var northwest=findTile(map.grid,neighbors.northwest); + var northeast=findTile(map.grid,neighbors.northeast); + var south=findTile(map.grid,neighbors.south); + var southwest=findTile(map.grid,neighbors.southwest); + var southeast=findTile(map.grid,neighbors.southeast); + + var top_char; + var left_char; + var middle_char; + var right_char; + var bottom_char; + + var current_colors; + var current_tile; + + if(current>=0) { + var current_tile=map.tiles[current]; + current_colors=getPlayerColors(current_tile.owner); + //MIDDLE CHAR + if(x==current_tile.home.x && y==current_tile.home.y) { + middle_char=new Char(current_tile.dice,current_colors.txt,current_colors.bg); + } else { + middle_char=new Char(" ",current_colors.fg,current_colors.bg); + } + //TOP CHAR + if(north>=0) { + var north_tile=map.tiles[north]; + var north_colors=getPlayerColors(north_tile.owner); + if(north==current) { + top_char=new Char(" ",current_colors.fg,current_colors.bg); + } else if(north_tile.owner==current_tile.owner) { + top_char=new Char("\xC4",BLACK,current_colors.bg); + } else top_char=new Char("\xDF",north_colors.fg,current_colors.bg); + } else { + top_char=new Char("\xDC",current_colors.fg,BG_BLACK); + } + //LEFT CHAR + if(northwest==current && southwest==current) { + left_char=new Char(" ",current_colors.fg,current_colors.bg); + } else if(northwest==southwest) { + if(northwest>=0 && map.tiles[northwest].owner==current_tile.owner) { + left_char=new Char("\xB3",BLACK,current_colors.bg); + } else if(northwest>=0) { + var colors=getPlayerColors(map.tiles[northwest].owner); + left_char=new Char("\xDD",colors.fg,current_colors.bg); + } else { + left_char=new Char("\xDE",current_colors.fg,BG_BLACK); + } + } else if(northwest>=0 && southwest>=0 && map.tiles[northwest].owner==current_tile.owner && map.tiles[southwest].owner==current_tile.owner && northwest!=current && southwest!=current) { + left_char=new Char("\xB4",BLACK,current_colors.bg); + } else if(northwest>=0 && map.tiles[northwest].owner==current_tile.owner && northwest!=current) { + left_char=new Char("\xD9",BLACK,current_colors.bg); + } else if(southwest>=0 && map.tiles[southwest].owner==current_tile.owner && southwest!=current) { + left_char=new Char("\xBF",BLACK,current_colors.bg); + } else if(northwest>=0 || southwest>=0) { + left_char=new Char(" ",current_colors.fg,current_colors.bg); + } else { + left_char=new Char("\xDE",current_colors.fg,BG_BLACK); + } + //RIGHT CHAR + if(northeast==current && southeast==current) { + right_char=new Char(" ",current_colors.fg,current_colors.bg); + } else if(northeast==southeast) { + if(northeast>=0 && map.tiles[northeast].owner==current_tile.owner) { + right_char=new Char("\xB3",BLACK,current_colors.bg); + } else if(northeast>=0) { + var colors=getPlayerColors(map.tiles[northeast].owner); + right_char=new Char("\xDE",colors.fg,current_colors.bg); + } else { + right_char=new Char("\xDD",current_colors.fg,BG_BLACK); + } + } else if(northeast>=0 && southeast>=0 && map.tiles[northeast].owner==current_tile.owner && map.tiles[southeast].owner==current_tile.owner && northeast!=current && southeast!=current) { + right_char=new Char("\xC3",BLACK,current_colors.bg); + } else if(northeast>=0 && map.tiles[northeast].owner==current_tile.owner && northeast!=current) { + right_char=new Char("\xC0",BLACK,current_colors.bg); + } else if(southeast>=0 && map.tiles[southeast].owner==current_tile.owner && southeast!=current) { + right_char=new Char("\xDA",BLACK,current_colors.bg); + } else if(northeast>=0 || southeast>=0) { + right_char=new Char(" ",current_colors.fg,current_colors.bg); + } else { + right_char=new Char("\xDD",current_colors.fg,BG_BLACK); + } + //BOTTOM CHAR + if(south<0) { + bottom_char=new Char("\xDF",current_colors.fg,BG_BLACK); + } + } else { + middle_char=new Char("~",BLUE,BG_BLACK); + if(north>=0) { + var north_tile=map.tiles[north]; + var north_colors=getPlayerColors(north_tile.owner); + top_char=new Char("\xDF",north_colors.fg,BG_BLACK); + } else top_char=new Char(" ",BLACK,BG_BLACK); + if(northwest>=0 && northwest==southwest) { + var southwest_colors=getPlayerColors(map.tiles[southwest].owner); + left_char=new Char("\xDD",southwest_colors.fg,BG_BLACK); + } else left_char=new Char(" ",BLACK,BG_BLACK); + if(northeast>=0 && northeast==southeast) { + var southeast_colors=getPlayerColors(map.tiles[southeast].owner); + right_char=new Char("\xDE",southeast_colors.fg,BG_BLACK); + } else right_char=new Char(" ",BLACK,BG_BLACK); + } + + getxy(x,y); + top_char.draw(); + console.down(); + console.left(2); + left_char.draw(); + middle_char.draw(); + right_char.draw(); + if(bottom_char) { + console.down(); + console.left(2); + bottom_char.draw(); + } + } + function drawMap(map) + { + for(var x=0;x<map.grid.length;x++) { + for(var y=0;y<map.grid[x].length;y++) { + drawSector(map,x,y); + } + } + } + function drawTiles(map) + { + for(var t in map.tiles) + { + drawTile(map,map.tiles[t]); + } + } + + //MAP DATA FUNCTIONS + function updateStatus(map) + { + for(var p=0;p<map.players.length;p++) { + if(map.players[p].active) { + if(countTiles(map,p)==0) map.players[p].active=false; + } + } + if(map.single_player) { + for(var p=0;p<map.players.length;p++) { + var player=map.players[p]; + /* for a single player game, find the non-AI player and check whether active. if not, game over */ + if(!player.AI && !player.active) { + map.in_progress=false; + findWinner(map); + break; + } + } + } else { + var eliminated=0; + for(var p=0;p<map.players.length;p++) { + if(!map.players[p].active) eliminated++; + } + if(eliminated==map.players.length-1) findWinner(map); + } + } + function findWinner(map) + { + + } + function placeReinforcements(map,pt,reinforcements) + { + var placed=[]; + while(reinforcements>0 && pt.length>0) { + var rand=random(pt.length); + var tile=pt[rand]; + if(tile.dice<settings.max_dice) { + tile.dice++; + reinforcements--; + placed.push(tile.id); + game_data.saveTile(map,tile); + } else { + pt.splice(rand,1); + } + } + while(map.players[map.turn].reserve>0 && pt.length>0) { + var rand=random(pt.length); + var tile=pt[rand]; + if(tile.dice<settings.max_dice) { + tile.dice++; + map.players[map.turn].reserve--; + placed.push(tile.id); + game_data.saveTile(map,tile); + } else { + pt.splice(rand,1); + } + } + return placed; + } + function placeReserves(map,num) + { + var placed=0; + if(map.players[map.turn].reserve<settings.max_reserve) { + map.players[map.turn].reserve+=num; + placed=num; + if(map.players[map.turn].reserve>settings.max_reserve) { + placed-=map.players[map.turn].reserve-settings.max_reserve; + map.players[map.turn].reserve=settings.max_reserve; + } + game_data.savePlayer(map,map.players[map.turn],map.turn); + } + return placed; + } + function nextTurn(map) + { + if(map.turn==map.players.length-1) { + map.turn=0; + map.round++; + } else map.turn++; + if(!map.players[map.turn].active) nextTurn(map); + else { + var data=new Data("turn"); + data.turn=map.turn; + stream.send(data); + } + } + function forfeit(map) + { + } + function getPlayerTiles(map,pnum) + { + var player_tiles=[]; + for(var t in map.tiles) { + if(map.tiles[t].owner==pnum) { + player_tiles.push(map.tiles[t]); + } + } + return player_tiles; + } + function canAttack(map,base) + { + + var valid_targets=[]; + if(base.dice>1) { + var neighbors=getNeighboringTiles(base,map); + for(var n=0;n<neighbors.length;n++) { + var tile=neighbors[n]; + if(tile.owner!=base.owner) valid_targets.push(tile); + } + } + return valid_targets; + } + function countConnected(map,array,player) + { + var counted=[]; + var largest_group=0; + var match=player; + + for(var t in array) { + if(!counted[array[t].id]) { + var count=[]; + count[array[t].id]=true; + var grid=getBorders(map,array[t]); + var connections=trace(map,grid,count,match); + counted.concat(connections); + var group_size=countSparseArray(connections); + if(group_size>largest_group) largest_group=group_size; + } + } + return largest_group; + } + function trace(map,grid,counted,match) + { + for(var x in grid) { + for(var y in grid[x]) { + if(map.grid[x][y]>=0) { + var tile=map.tiles[map.grid[x][y]]; + if(tile.owner==match) { + if(!counted[tile.id]) { + counted[tile.id]=true; + counted.concat(trace(map,getBorders(map,tile),counted,match)); + } + } + } + } + } + return counted; + } + function findPlayer(map,name) + { + for(var p in map.players) + { + if(map.players[p].name==name) return p; + } + return -1; + } + function addComputers(map) + { + var num=settings.num_players-map.players.length; + if(num>0) { + var aifile=new File(game_dir + settings.ai_file); + aifile.open("r",true); + var possibleplayers=aifile.iniGetSections(); + while(num>0) { + var p=random(possibleplayers.length); + var name=possibleplayers[p]; + + var player=new Player(name,true); + var sort=aifile.iniGetValue(name, "sort"); + var check=aifile.iniGetValue(name, "check"); + var qty=aifile.iniGetValue(name, "quantity"); + player.AI=new AI(sort,check,qty); + map.players.push(player); + + possibleplayers.splice(p,1); + num--; + } + aifile.close(); + } + } + function addPlayer(map,name,vote) + { + map.players.push(new Player(name,vote)); + } + function shufflePlayers(map) + { + map.players=shuffle(map.players); + } + function dispersePlayers(map) + { + var tiles_per_player=map.tiles.length/map.players.length; + var placeholder=[]; + + for(var p=0;p<map.players.length;p++) + { + var t=tiles_per_player; + var occupied=[]; + + while(t>0) + { + var rand_t=random(map.tiles.length); + if(placeholder[rand_t]) continue; + + map.tiles[rand_t].assign(p,1); + placeholder[rand_t]=true; + occupied.push(rand_t); + t--; + } + + var d=tiles_per_player; + if(p==map.players.length-1) d+=2; + else if(p>=(map.players.length-1)/2) d++; + while(d>0) + { + var rand_t=occupied[random(occupied.length)]; + if(map.tiles[rand_t].dice==settings.max_dice) continue; + map.tiles[rand_t].dice++; + d--; + } + } + } + function connected(tile1,tile2,map) + { + for(var c=0;c<tile1.coords.length;c++) { + var valid_directions=getNeighboringSectors(tile1.coords[c],map.grid); + for(var d in valid_directions) { + var dir=valid_directions[d]; + if(map.grid[dir.x][dir.y]==tile2.id) return true; + } + } + return false; + } + function getBorders(map,tile) + { + var borders=[]; + for(var c in tile.coords) { + var coord=tile.coords[c]; + var neighbors=getNeighboringSectors(coord,map.grid); + for(var n in neighbors) { + var neighbor=neighbors[n]; + if(map.grid[neighbor.x][neighbor.y]!=tile.id) { + if(!borders[neighbor.x]) borders[neighbor.x]=[]; + borders[neighbor.x][neighbor.y]=true; + } + } + } + return borders; + } + function getNeighboringTiles(tile,map) + { + var found=[]; + var neighbors=[]; + for(var c=0;c<tile.coords.length;c++) { + var valid_directions=getNeighboringSectors(tile.coords[c],map.grid); + for(var d in valid_directions) { + var dir=valid_directions[d]; + var t=map.grid[dir.x][dir.y]; + if(t>=0 && t!=tile.id && !found[t]) { + found[t]=true; + neighbors.push(map.tiles[t]); + } + } + } + return neighbors; + } + function getNeighboringSectors(relative_to_position,on_grid) + { + var xlimit=on_grid.length; + var ylimit=on_grid[0].length; + var offset=relative_to_position.x%2; + var neighbors=[]; + var dir_names=["northwest","north","northeast","southwest","south","southeast"]; + var dir_x=[-1,0,1,-1,0,1]; + var dir_y=[-1+offset,-1,-1+offset,0+offset,1,0+offset]; + for(var i=0;i<dir_x.length;i++) { + var x=parseInt(relative_to_position.x,10)+dir_x[i]; + var y=parseInt(relative_to_position.y,10)+dir_y[i]; + if(x>=xlimit || y>=ylimit || x<0 || y<0) continue; + neighbors[dir_names[i]]=new Coords(x,y); + } + return neighbors; + } + function getRandomDirection(from_position,on_grid) + { + var valid_directions=getNeighboringSectors(from_position,on_grid); + var available=[]; + for(var d in valid_directions) { + available.push(d); + } + while(available.length) { + var rand=random(available.length); + var random_dir=valid_directions[available[rand]]; + available.splice(rand,1); + if(on_grid[random_dir.x][random_dir.y]>=0) continue; + return random_dir; + } + return false; + } + function landNearby(grid,x,y) + { + var valid_directions=getNeighboringSectors(new Coords(x,y),grid); + var land=0; + for(var d in valid_directions) { + var coords=valid_directions[d]; + if(grid[coords.x][coords.y]>=0) land++; + } + return land; + } + function generateMap(map) + { + var total=map.width*map.height; + var min_size=settings.min_tile_size; + var max_size=settings.max_tile_size; + + map.num_players=settings.num_players; + var num_tiles=parseInt(total/(max_size-1),10); + num_tiles-=num_tiles%map.players.length; + + for(var t=0;t<num_tiles;t++) + { + map.tiles[t]=new Tile(t); + var size=random(max_size-min_size)+min_size; + + while(1) + { + x=random(map.width-1)+1; + y=random(map.height-1)+1; + + if(map.grid[x][y]>=0) continue; + if(t==0) break; + + var land_nearby=landNearby(map.grid,x,y); + if(land_nearby>0 && land_nearby<6) break; + } + + var sector=new Coords(x,y); + map.grid[sector.x][sector.y]=t; + map.tiles[t].coords.push(new Coords(x,y)); + + for(var s=1;s<size;s++) + { + sector=getRandomDirection(sector,map.grid); + if(!sector) break; + map.grid[sector.x][sector.y]=t; + map.tiles[t].coords.push(sector); + } + + var home=random(map.tiles[t].coords.length); + map.tiles[t].home=map.tiles[t].coords[home]; + } + } + function createGrid(w,h) + { + var grid=new Array(w); + for(var x=0;x<grid.length;x++) grid[x]=new Array(h); + return grid; + } diff --git a/xtrn/dicewarz2/menu.js b/xtrn/dicewarz2/menu.js new file mode 100644 index 0000000000000000000000000000000000000000..2ad8939958fb7ab735bca9922c1f5f3e27918eba --- /dev/null +++ b/xtrn/dicewarz2/menu.js @@ -0,0 +1,53 @@ +function Menu(items,bg,x,y) +{ //MENU CLASSES + this.items=[]; + this.x=x; + this.y=y; + this.bg=bg; + + this.disable=function(item) + { + this.items[item].enabled=false; + } + this.enable=function(item) + { + this.items[item].enabled=true; + } + this.add=function(items) + { + for(i=0;i<items.length;i++) + { + hotkey=get_hotkey(items[i]); + this.items[hotkey]=new Item(items[i],hotkey); + } + } + this.clear=function() + { + console.gotoxy(this); + console.cleartoeol(this.bg); + } + this.draw=function() + { + console.gotoxy(this); + console.pushxy(); + console.cleartoeol(this.bg); + console.popxy(); + for(i in this.items) + { + if(this.items[i].enabled==true) console.putmsg(this.items[i].text + " ",P_SAVEATR); + } + console.attributes=ANSI_NORMAL; + } + this.add(items); +} +function Item(item,hotkey) +{ //MENU ITEM OBJECT + this.enabled=true; + this.hotkey=hotkey; + this.text=item.replace(("~" + hotkey) , hotkey); +} +function get_hotkey(item) +{ + keyindex=item.indexOf("~")+1; + return item.charAt(keyindex); +} diff --git a/xtrn/dicewarz2/player.js b/xtrn/dicewarz2/player.js new file mode 100644 index 0000000000000000000000000000000000000000..b401ed05cfe68d5286c2d77ac2366e9fc08b1d9a --- /dev/null +++ b/xtrn/dicewarz2/player.js @@ -0,0 +1,48 @@ +//PLAYER OBJECTS +function Player(name,vote) +{ + this.name=name; + this.vote=vote; + this.reserve=0; + this.active=true; + this.AI=false; +} +function AI(sort,check,qty) +{ + this.sort=sort + this.check=check; + this.qty=qty; + this.turns=0; + this.moves=0; +} + //PLAYER FUNCTIONS + function countDice(map,p) + { + var dice=0; + var tiles=getPlayerTiles(map,p); + for(var t=0;t<tiles.length;t++) { + dice+=tiles[t].dice; + } + return dice; + } + function countTiles(map,p) + { + return getPlayerTiles(map,p).length; + } + +//PLAYER DATA OBJECT +function PlayerData(filename) +{ + this.list=[]; + this.scores=[]; + this.load=function() + { + + } +} + //PLAYER DATA FUNCTIONS + function viewRankings() + { + + } + diff --git a/xtrn/dicewarz2/rolldice.js b/xtrn/dicewarz2/rolldice.js new file mode 100644 index 0000000000000000000000000000000000000000..b02ce63418c034d8ce9997a07632dd81c00c214d --- /dev/null +++ b/xtrn/dicewarz2/rolldice.js @@ -0,0 +1,101 @@ +//#########################DICE ROLLING FUNCTIONS############################ +var dice=loadDice(); + +function rollDice(n) +{ + var total=0; + for(var i=0;i<n;i++) { + total+=rollDie(); + if(i<n-1) { + console.up(2); + console.right(); + } + } + return total; +} +function rollDie(value,attr,num) +{ + console.attributes=attr; + console.pushxy(); + for(var r=0;num>0 && r<num;r++) { + console.popxy(); + dice[random(6)+1].draw(); + mswait(10); + } + console.popxy(); + var roll=value?value:random(6)+1; + dice[roll].draw(); + return roll; +} +function showRoll(rolls,attr,x,y) +{ + var total=0; + console.gotoxy(x,y); + console.pushxy(); + for(var r=0;r<rolls.length;r++) { + rollDie(rolls[r],attr); + total+=rolls[r]; + if(r<rolls.length-1) { + console.popxy(); + console.right(4); + console.pushxy(); + } + } + mswait(500); + return total; +} +function loadDice() +{ //INITIALIZE SIX SIDED DICE OBJECTS + var dice=[]; + for(d=1;d<=6;d++) + { + dice[d]=new Die(d); + } + return dice; +} + +function Roll(pnum) +{ + this.pnum=pnum; + this.rolls=[]; + this.total=0; + this.roll=function(num) + { + this.rolls.push(num); + this.total+=num; + } +} +function Die(number) +{ //DICE CLASS + this.number=number; + this.line1=" "; + this.line2=" "; + this.line3=" "; + this.dot="\xFE"; + + if(this.number==2 || this.number==3) + { + this.line1=this.dot+" "; + this.line3=" "+this.dot; + } + if(this.number==4 || this.number==5 || this.number==6) + { + this.line1=this.dot+" "+this.dot; + this.line3=this.dot+" "+this.dot; + } + if(this.number==1 || this.number==3 || this.number==5) + this.line2=" "+this.dot+" "; + if(this.number==6) + this.line2=this.dot+" "+this.dot; + + this.draw=function() + { + console.putmsg(this.line1,P_SAVEATR); + console.down(); + console.left(3); + console.putmsg(this.line2,P_SAVEATR); + console.down(); + console.left(3); + console.putmsg(this.line3,P_SAVEATR); + } +}