Skip to content
Snippets Groups Projects
Commit d204b461 authored by mcmlxxix's avatar mcmlxxix
Browse files

Dice Warz 2 [IN WORK]

realtime interbbs multiplayer dice warz
asynchronous shit-talkin' AI (by Deuce)
now with "fancy land" and chat room
parent 60abbfd9
No related branches found
No related tags found
No related merge requests found
************************************
***** 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!
[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
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);
}
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 ` ` `pPpLpApYpEpRpSpp ` ` ` ` ` ` ` ` `` wTp xp wDp wp xRp p` ``                                             `                  `             `` ~   ~   ~   ~   ~   ~   ~   ~   ~   ~   ~   `                  `             ``   ~   ~   ~   ~   ~   ~   ~   ~   ~   ~   ~ `                  `             `` ~   ~   ~   ~   ~   ~   ~   ~   ~   ~   ~   `                  `             ``   ~   ~   ~   ~   ~   ~   ~   ~   ~   ~   ~ `                  `             `` ~   ~   ~   ~   ~   ~   ~   ~   ~   ~   ~   `                  `             ``   ~   ~   ~   ~   ~   ~   ~   ~   ~   ~   ~ `                  `             `` ~   ~   ~   ~   ~   ~   ~   ~   ~   ~   ~   `                  `             ``   ~   ~   ~   ~   ~   ~   ~   ~   ~   ~   ~ `                  `             `` ~   ~   ~   ~   ~   ~   ~   ~   ~   ~   ~   ` `pApCpTpIpVpIpTpYpp ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ``   ~   ~   ~   ~   ~   ~   ~   ~   ~   ~   ~ `                                `` ~   ~   ~   ~   ~   ~   ~   ~   ~   ~   ~   `                                ``   ~   ~   ~   ~   ~   ~   ~   ~   ~   ~   ~ `                                `` ~   ~   ~   ~   ~   ~   ~   ~   ~   ~   ~   `                                ``   ~   ~   ~   ~   ~   ~   ~   ~   ~   ~   ~ `                                `` ~   ~   ~   ~   ~   ~   ~   ~   ~   ~   ~   ` `pCpHpApTpp ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ``   ~   ~   ~   ~   ~   ~   ~   ~   ~   ~   ~ `                                `` ~   ~   ~   ~   ~   ~   ~   ~   ~   ~   ~   `                                ``   ~   ~   ~   ~   ~   ~   ~   ~   ~   ~   ~ `                                `` ~   ~   ~   ~   ~   ~   ~   ~   ~   ~   ~   `                                ``   ~   ~   ~   ~   ~   ~   ~   ~   ~   ~   ~ `                                ``                                             `                                ` `` pMpEpNpUp:p` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `
\ No newline at end of file
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
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();
                                                                                                                             
                                                  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.                     ;; 33 3333333;                                                      .  ; ;33333333;      All javascript games by Matt Johnson are           3333    free and available for download from the         >333333;;;? 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
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
This diff is collapsed.
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);
}
//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()
{
}
//#########################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);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment