Lorne's Stupid Thread of War and elgiu (because if everyone else can abuse Discourse so can I :doing_it_wrong:)
-
In the Status thread, I posted a quick-n-dirty War in Javascript game. If you want to find it, be my guest.
I've been tinkering with the code trying to turn it into a playable game. Mostly for my amusement. Partially because of-- secret raisins. In any case, I figured I should get the code into some sort of code tracker system, so I can track revisions. But rather than doing it in any sane or correct way-- Discourse!
You can probably safely ignore this thread for a while. There won't be anything production ready until it's ready for production.
-
Version 2.0****strong text
First release.- Mostly works
- UI is shit
- Has a button you can click
- Hard coded JQuery to my own server, so please don't rape it too much
- There were previous versions, but not tracked.
- Fuck you, give me money.
<html> <head> <script src="http://sevenseventeen.ca/wp-includes/js/jquery/jquery.js" type="text/javascript"></script> <script type="text/javascript">
var decks = [];
var wins = [];
var kitty = [];
var winner = 0;
var battle = [];var suites = ["Hearts", "Spades", "Diamonds", "Clubs"];
var ranks = {"Two" : 2, "Three" : 3, "Four" : 4, "Five" : 5, "Six" : 6, "Seven" : 7, "Eight" : 8, "Nine" : 9, "Ten" : 10, "Jack" : 11, "Queen" : 12, "King" : 13, "Ace": 14};
var GameDeck = [];for(s = 0; s < suites.length; s++)
{
suit = suites[s];for(var rank in ranks) { card = {"Suit" : suit, "Rank" : rank, "Value" : ranks[rank]}; GameDeck.push(card); }
}
// UI functions
// TODO put visibility of card into card properties
// player = 0 index id of player
function PutCardOnBattleground(player, card)
{var batleground_area = document.getElementById("battleground_p" + player); var cardui = document.createElement("div"); cardui.className = "card"; cardui.textContent = card.Rank + " " + card.Suit; batleground_area.appendChild(cardui); $(cardui).data("card", card);
}
function SortByValue(c1, c2)
{
var a = $(c1).data("card").Value;
var b = $(c2).data("card").Value;
return a < b ? 1 : a > b ? -1 : 0;
}// Collect all ventured cards into the winners Win pile
function CollectWinnings(player)
{var winnings = $(".battleground .area.stack .card"); var wins = $("#player"+player+"_area_wins"); wins.find(".card").removeClass("latest"); winnings.addClass("latest"); winnings.sort(SortByValue); winnings.detach().prependTo(wins); /* //var winpile = document.getElementById("player"+player+"_area_wins"); var winpile = $("#player"+player+"_area_wins"); if(winpile != null) { for(var i = 0; i <=1; i++) { var ba = document.getElementById("battleground_p" + i); while(ba.childNodes.length > 0) { winpile.appendChild(ba.childNodes[0]); } } } */
}
// Empty Win Pile UI
function ClearWinsPile(player)
{
var winpile = document.getElementById("player"+player+"_area_wins");
while(winpile.childNodes.length > 0)
{
winpile.removeChild(winpile.firstChild);
}
}// face down deck. Clear anything in there, put face down card, and add counter
function RefreshDeck(player)
{
var deck = document.getElementById("player"+player+"_area_deck");
while(deck.childNodes.length > 0)
{
deck.removeChild(deck.firstChild);
}var card = document.createElement("div"); card.className = "card facedown"; deck.appendChild(card); var cnt = document.createElement("div"); card.appendChild(cnt); cnt.textContent = decks[player].length;
}
// End UI functions
function shuffle(array)
{
var currentIndex = array.length, temporaryValue, randomIndex ;// While there remain elements to shuffle...
while (0 !== currentIndex) {// Pick a remaining element... randomIndex = Math.floor(Math.random() * currentIndex); currentIndex -= 1; // And swap it with the current element. temporaryValue = array[currentIndex]; array[currentIndex] = array[randomIndex]; array[randomIndex] = temporaryValue;
}
return array;
}// draw one card from deck IDX, return that card or null
// when a deck runs out, reshuffle win pile into deck
// if no cards remain in deck or win pile, returns null
function draw(idx)
{
if(decks[idx].length == 0)
{wins[idx] = shuffle(wins[idx]); while(wins[idx].length > 0) { decks[idx].push(wins[idx].shift()); ClearWinsPile(idx); } } card = decks[idx].shift(); RefreshDeck(idx); return card;
} // end function draw
function CardsOwned(player)
{
return decks[player].length + wins[player].length;
}function DoWar(numcards)
{winner = -1; // tie var PlayerDepleted = false; for(var i=0; i<=1; i++) { if(CardsOwned(i) == 0) { PlayerDepleted = true; } } if(PlayerDepleted) { // there is a player who cannot war no more. The only way to resolve this is // First, who has the most rank values. // If still tied, who has the most cards. // If STILL tied, then both players are exactly where they were when they started. Reshuffle everything and start again. console.log("Player " + i + " has run out of cards and cannot commit to war. Checking for armistice."); // someone has run out of cards, AND ended with a war // the winner of the game will be whoever has more cards for(var idx = 0; idx <= 1; idx++) { // move everything into the battle piles while(wins[idx].length > 0) { card = wins[idx].shift(); battle[idx].push(card); PutCardOnBattleground(idx, card); } while(decks[idx].length > 0) { card = decks[idx].shift(); battle[idx].push(card); PutCardOnBattleground(idx, card); } ClearWinsPile(idx); RefreshDeck(idx); } winner = -1; // tie // total up the values of the cards in the decks totals = []; totals[0] = 0; totals[1] = 0; for(var i = 0; i <=1; i++) { for(j = 0; j < battle[i].length; j++) { totals[i] = totals[i] + battle[i][j].Value; } } // compare totals for(var i = 0; i <=1; i++) { console.log("Player " + i + " has " + totals[i] + " points in rank"); up = i % 2; down = (i+1) % 2; if(totals[up] > totals[down]) { winner = up; } } console.log("A winner of the whole game is " + winner); if(winner < 0) { console.log("Players are tied in rank. Checking by number of cards"); // it is still a tie because both players have the same value of cards // go by number of cards for(var i = 0; i <=1; i++) { console.log("Player " + i + " has " + battle[i].length + " cards"); up = i % 2; down = (i+1) % 2; if(battle[up].length > battle[down].length) { winner = up; } } } console.log("A winner of the whole game is " + winner); if(winner < 0) { console.log("Players are equal in rank and cards. Putting all cards back into decks and starting again."); // OMFG both players have the same number of cards and the same total values. // just start the damn game again! SetupNewGame(1); } if(winner < 0) { // forget it. The universe has ended. throw new Exception("Forget it. The universe has ended"); } return winner; } // end tiebreaker // Only venture as many cards as any one player has for(var i=0; i<=1; i++) { if(CardsOwned(i) < numcards) { console.log("Player " + i + " cannot venture " + numcards + " cards, so instead we'll do " + CardsOwned(i)); numcards = CardsOwned(i); } } for(drawidx = 0; drawidx < numcards; drawidx++) { for(var i = 0; i <=1; i++) { // Each player adds a card to the top of the battlegrounds, to face off card = draw(i); battle[i].push(card); PutCardOnBattleground(i, card); RefreshDeck(i); } } // Check for the winner by comparing the top cards of the battleground to each other for(var i = 0; i <=1; i++) { up = i % 2; down = (i+1) % 2; if(battle[up][battle[up].length - 1].Value > battle[down][battle[down].length - 1].Value) { winner = up; } } if(winner < 0) { console.log("We're at war!"); if(numcards > 1) { console.log("EXTRA WAR!!!"); } // Oh shnit! We have a tie. Let us settle it with W-A-R!!!! // a tie had occured. Oh noes! // W-A-R then flip 1 winner = DoWar(4); } // end WAR return winner;
} // end battle
function PlayOneRound()
{
winner = -1;// Do the War function until there is a winner while(winner < 0) { winner = DoWar(1); // check the topmost card in each player battle pile, and the winner is returned, or -1 for a tie } // Move all cards from both Battlegrounds into the win pile of the winner (obj) for(var i = 0; i <=1; i++) { while(battle[i].length > 0) { wins[winner].push(battle[i].shift()); } } // Move all the cards from the Battleground into the win pile of the winner (UI) CollectWinnings(winner); return winner;
}
function SetUpNewGame(numPlayersZeroIndex)
{
GameDeck = shuffle(GameDeck);for(var i = 0; i<= numPlayersZeroIndex; i++) { decks[i] = []; wins[i] = []; battle[i] = []; } for(var i = 0; i < GameDeck.length; i++) { decks[i%(numPlayersZeroIndex + 1)].push(GameDeck[i]); } // set up deck UI for(var i = 0; i<= numPlayersZeroIndex; i++) { CollectWinnings(i); ClearWinsPile(i); RefreshDeck(i); }
}
function PlayGame()
{// keep going until someone runs out of cards while(CardsOwned(0) > 0 && CardsOwned(1) > 0) { winner = PlayOneRound(); } // someone has run out of cards console.log("The winner of the game is " + winner);
}
<script type="text/javascript"> // jquery sheeeeeet $(document).ready(function() { SetUpNewGame(1); $("#OneRound").click(function(e) { winner = PlayOneRound(); }); }); </script> <style type='text/css'> .area, .card { min-height:180px; width:120px; display:block; border:1px solid black; border-radius:5px; } .area { background-color: grey; } .card { background-color:white; } .card.facedown { background-color:blue; } #playarea { position:relative; width:90%; margin-left:auto; margin-right:auto; } #battleground { background-color:orange; width:500px; margin-left:auto; margin-right:auto; position:relative; } .area.player, .area.stack { position:absolute; top:0px; } .area.p0 { left:0px; } .area.p1 { right:0px; } .card.latest { background-color:yellow !important; } .wins .card { position:relative; margin-top:-97%; z-index:99; } .wins .card.latest { margin-top:0px; z-index:9; } </style> </head> <body> <button id="OneRound">Play One Round</button>
</script><div id="player0_area" class="area player p0"> <div id="player0_area_deck" class="p0 area deck"></div> <div id="player0_area_wins" class="p0 area wins"></div> </div> <div id="battleground" class="area battleground"> <div id="battleground_p0" class="area stack p0"></div> <div id="battleground_p1" class="area stack p1"></div> </div> <div id="player1_area" class="area player p1"> <div id="player1_area_deck" class="p1 area deck"></div> <div id="player1_area_wins" class="p1 area wins"></div> </div>
-
-
You might be doing this wrong on purpose but we have a "Programmers Testing"-Area for stuff like this, afaik.
Filed Under: Then again, blakeyrat didn't boil you alive for posting this in a category he doesn't mute, so I guess all is well?
-
Oh I guess I didn't notice the category.
Either way, making War into a "playable game" is an impossible Don Quixote-esque task. That was my point.
-
He could just programm one of the milion browser versions of chess!
Filed Under: Or shougi, or Settlers of Cathan, I guess? I don't really know that many board games even though I am German
-
Either way, making War into a "playable game" is an impossible Don Quixote-esque task. That was my point.
You see before you some 52 lawless cards with whom I mean to do battle. I shall deprive them of their lives, and with the spoils from this encounter, we shall begin to enrich ourselves.
-
Browser-based Pandemic would be cool.
-
So make it something other than War.
That is the plan, eventually.
"Programmers Testing"-Area
Categories are a to Doing It Right. Feel free to Jeff the post if you need to.
-
@Lorne_Kates said:
please don't rape it too much
Considering it's a Wordpress site...
@Lorne_Kates said:
UI is shit
What is this I don't even...@Lorne_Kates said:
Has a button you can click
Doesn't look like a cookie.@Lorne_Kates said:
Mostly works
After 719 iterations.... I won!
-
Version 2.1
-Added slightly less shit UI
-Refactoring to event driven to support eventual framework
-Moved css to war.css because I felt like it
-First stab at animation. It works, but need to use event framework to wait to move card off battlefield until after battle is done.War.html
<html> <head> <link href="http://sevenseventeen.ca/war.css" rel="stylesheet"></link> <script src="http://sevenseventeen.ca/wp-includes/js/jquery/jquery.js" type="text/javascript"></script> <script src="http://sevenseventeen.ca/wp-includes/js/jquery/ui/jquery-ui.js" type="text/javascript"></script> <link href="http://sevenseventeen.ca/wp-includes/js/jquery/ui/jquery-ui.min.css" rel="stylesheet"></link> <script type="text/javascript"> var $Universe = null; var decks = []; var wins = []; var kitty = []; var winner = 0; var battle = []; var suites = ["Hearts", "Spades", "Diamonds", "Clubs"]; var ranks = {"Two" : 2, "Three" : 3, "Four" : 4, "Five" : 5, "Six" : 6, "Seven" : 7, "Eight" : 8, "Nine" : 9, "Ten" : 10, "Jack" : 11, "Queen" : 12, "King" : 13, "Ace": 14}; var GameDeck = []; for(s = 0; s < suites.length; s++) { suit = suites[s]; for(var rank in ranks) { card = {"Suit" : suit, "Rank" : rank, "Value" : ranks[rank]}; GameDeck.push(card); } } function CreateCardElement(card) { var $card = $("<div></div>"); $card.addClass("card"); $card.addClass(card.Suit); $card.text(card.Rank + " " + card.Suit); $card.data("card", card); return $card; } // UI functions // TODO put visibility of card into card properties // player = 0 index id of player function PutCardOnBattleground(player, card) { var batleground_area = $("#battleground_p" + player); var cardui = CreateCardElement(card); batleground_area.append(cardui); } function SortByValue(c1, c2) { var a = $(c1).data("card").Value; var b = $(c2).data("card").Value; return a < b ? 1 : a > b ? -1 : 0; } // Collect all ventured cards into the winners Win pile function CollectWinnings(player) { var winnings = $(".battleground .area.stack .card"); var wins = $("#player"+player+"_area_wins"); var winpile = $("#player"+player+"_area_wins"); wins.find(".card").removeClass("latest"); winnings.addClass("latest"); winnings.sort(SortByValue); winnings.each(function() { var opts = {}; opts.from = $(this).parents(".battle:first"); opts.to = winpile; opts.cardui = $(this); $Universe.trigger("MoveCard", opts); }); } // Empty Win Pile UI function ClearWinsPile(player) { var winpile = document.getElementById("player"+player+"_area_wins"); while(winpile.childNodes.length > 0) { winpile.removeChild(winpile.firstChild); } } // face down deck. Clear anything in there, put face down card, and add counter function RefreshDeck(player) { var deck = document.getElementById("player"+player+"_area_deck"); while(deck.childNodes.length > 0) { deck.removeChild(deck.firstChild); } var card = document.createElement("div"); card.className = "card facedown"; deck.appendChild(card); var cnt = document.createElement("div"); card.appendChild(cnt); cnt.textContent = decks[player].length; } // End UI functions function shuffle(array) { var currentIndex = array.length, temporaryValue, randomIndex ; // While there remain elements to shuffle... while (0 !== currentIndex) { // Pick a remaining element... randomIndex = Math.floor(Math.random() * currentIndex); currentIndex -= 1; // And swap it with the current element. temporaryValue = array[currentIndex]; array[currentIndex] = array[randomIndex]; array[randomIndex] = temporaryValue; } return array; } // draw one card from deck IDX, return that card or null // when a deck runs out, reshuffle win pile into deck // if no cards remain in deck or win pile, returns null function draw(idx) { if(decks[idx].length == 0) { while(wins[idx].length > 0) { card = wins[idx].shift(); decks[idx].push(card); ClearWinsPile(idx); } decks[idx] == shuffle(decks[idx]); } if(decks[idx].length > 0) { $Universe.trigger("CardExposed", { player: idx, card: decks[idx][0], from: $(".deck").eq(idx), to: $(".battle").eq(idx), facedown_from: false, facedown_to: true }); } card = decks[idx].shift(); RefreshDeck(idx); return card; } // end function draw function CardsOwned(player) { return decks[player].length + wins[player].length; } function DoWar(numcards) { winner = -1; // tie var PlayerDepleted = false; for(var i=0; i<=1; i++) { if(CardsOwned(i) == 0) { PlayerDepleted = true; } } if(PlayerDepleted) { // there is a player who cannot war no more. The only way to resolve this is // First, who has the most rank values. // If still tied, who has the most cards. // If STILL tied, then both players are exactly where they were when they started. Reshuffle everything and start again. console.log("Player " + i + " has run out of cards and cannot commit to war. Checking for armistice."); // someone has run out of cards, AND ended with a war // the winner of the game will be whoever has more cards for(var idx = 0; idx <= 1; idx++) { // move everything into the battle piles while(wins[idx].length > 0) { card = wins[idx].shift(); battle[idx].push(card); PutCardOnBattleground(idx, card); } while(decks[idx].length > 0) { card = decks[idx].shift(); battle[idx].push(card); PutCardOnBattleground(idx, card); } ClearWinsPile(idx); RefreshDeck(idx); } winner = -1; // tie // total up the values of the cards in the decks totals = []; totals[0] = 0; totals[1] = 0; for(var i = 0; i <=1; i++) { for(j = 0; j < battle[i].length; j++) { totals[i] = totals[i] + battle[i][j].Value; } } // compare totals for(var i = 0; i <=1; i++) { console.log("Player " + i + " has " + totals[i] + " points in rank"); up = i % 2; down = (i+1) % 2; if(totals[up] > totals[down]) { winner = up; } } console.log("A winner of the whole game is " + winner); if(winner < 0) { console.log("Players are tied in rank. Checking by number of cards"); // it is still a tie because both players have the same value of cards // go by number of cards for(var i = 0; i <=1; i++) { console.log("Player " + i + " has " + battle[i].length + " cards"); up = i % 2; down = (i+1) % 2; if(battle[up].length > battle[down].length) { winner = up; } } } console.log("A winner of the whole game is " + winner); if(winner < 0) { console.log("Players are equal in rank and cards. Putting all cards back into decks and starting again."); // OMFG both players have the same number of cards and the same total values. // just start the damn game again! SetupNewGame(1); } if(winner < 0) { // forget it. The universe has ended. throw new Exception("Forget it. The universe has ended"); } return winner; } // end tiebreaker // Only venture as many cards as any one player has for(var i=0; i<=1; i++) { if(CardsOwned(i) < numcards) { console.log("Player " + i + " cannot venture " + numcards + " cards, so instead we'll do " + CardsOwned(i)); numcards = CardsOwned(i); } } for(drawidx = 0; drawidx < numcards; drawidx++) { for(var i = 0; i <=1; i++) { // Each player adds a card to the top of the battlegrounds, to face off card = draw(i); battle[i].push(card); PutCardOnBattleground(i, card); RefreshDeck(i); } } // Check for the winner by comparing the top cards of the battleground to each other for(var i = 0; i <=1; i++) { up = i % 2; down = (i+1) % 2; if(battle[up][battle[up].length - 1].Value > battle[down][battle[down].length - 1].Value) { winner = up; } } if(winner < 0) { console.log("We're at war!"); if(numcards > 1) { console.log("EXTRA WAR!!!"); } // Oh shnit! We have a tie. Let us settle it with W-A-R!!!! // a tie had occured. Oh noes! // W-A-R then flip 1 winner = DoWar(4); } // end WAR return winner; } // end battle function PlayOneRound() { winner = -1; // Do the War function until there is a winner while(winner < 0) { winner = DoWar(1); // check the topmost card in each player battle pile, and the winner is returned, or -1 for a tie } // Move all cards from both Battlegrounds into the win pile of the winner (obj) for(var i = 0; i <=1; i++) { while(battle[i].length > 0) { wins[winner].push(battle[i].shift()); } } // Move all the cards from the Battleground into the win pile of the winner (UI) CollectWinnings(winner); return winner; } function SetupBoard() { $(".cards").each(function(e) { var $this = $(this); $this.data("cards", []); }); } function SetUpNewGame(numPlayersZeroIndex) { GameDeck = shuffle(GameDeck); for(var i = 0; i<= numPlayersZeroIndex; i++) { decks[i] = []; $("#player"+i+"_area_deck").data("cards", decks[i]); wins[i] = []; $("#player"+i+"_area_wins").data("cards", wins[i]); battle[i] = []; $("#battleground_p" + i).data("cards", battle[i]); } for(var i = 0; i < GameDeck.length; i++) { decks[i%(numPlayersZeroIndex + 1)].push(GameDeck[i]); } // set up deck UI for(var i = 0; i<= numPlayersZeroIndex; i++) { CollectWinnings(i); ClearWinsPile(i); RefreshDeck(i); } } function PlayGame() { // keep going until someone runs out of cards while(CardsOwned(0) > 0 && CardsOwned(1) > 0) { winner = PlayOneRound(); } // someone has run out of cards console.log("The winner of the game is " + winner); } </script> <script type="text/javascript"> // jquery sheeeeeet $(document).ready(function() { SetupBoard(); SetUpNewGame(1); $Universe = $("#Universe"); $("#OneRound").click(function(e) { $Universe.trigger("PlayOneRound"); }); }); // Universe handlers $(document).ready(function() { $Universe.on("PlayOneRound", function(e) { // A round has been triggered. Play it, then call On Complete $Universe.trigger("OnBeforePlayOneRound", e); winner = PlayOneRound(); // draw // might trigger shuffle // put on battle ground // compare // flash winner // move all cards to wins e.winner = winner; $Universe.trigger("OnAfterPlayOneRound", e); }); // default round actions $Universe.on("OnBeforePlayOneRound", function(e) { // default action: disable action things $(".action").addClass("ui-state-disabled"); }); $Universe.on("OnAfterPlayOneRound", function(e) { // restore action buttons $(".action").removeClass("ui-state-disabled"); }); /* A card has been made public from this area. See if card exists. If not, create it. Then draw it on this area */ $Universe.on("CardExposed", function(e, opts) { // check from, and look through its data to see if card is in there var $FromUI = $(opts.from); if($FromUI != null && $FromUI.data("cards") != null) { var cards = $FromUI.data("cards"); var card = null; for(var idx = 0; idx < cards.length; idx++) { if(opts.card == cards[idx]) { card = cards[idx]; idx = cards.length; } } if(card == null) { // the card is not in this stack opts.error = true; } else { $card = CreateCardElement(card); $FromUI.append($card); } } var new_opts = { after:null, cardui: $card}; $.extend(new_opts, opts); if(opts.after != null && typeof(opts.after) === "function") { opts.after(e, new_opts); } $Universe.trigger("MoveCard", new_opts); }); /* player: idx, card: card, from: decks[idx], to: battle[idx], facedown_from: false, facedown_to: true */ $Universe.on("MoveCard", function(e, opts) { // get the card from the target // expose it on the target // animate it to the other target var $card = $(opts.cardui); var $FromUI = $(opts.from); var $ToUI = $(opts.to); var top = $card.offset().top; var left = $card.offset().left; $card .detach() .appendTo("body") .css("position", "absolute") .css("top", top) .css("left", left) .animate ( { left:$ToUI.offset().left, top:$ToUI.offset().top }, "slow", function() { $card.appendTo($ToUI); $card.css("position", "static"); } ); }); }); </script> </head> <body> <div id="Universe"> <div style="position:static;"> <button id="OneRound" class="action">Play One Round</button> </div> <div id="playarea" class="" style="margin-top:2em;"> <div id="player0_area" class="area player p0"> <div id="player0_area_deck" class="p0 area deck cards"></div> <div id="player0_area_wins" class="p0 area wins cards"></div> </div> <div id="battleground" class="area battleground"> <div id="battleground_p0" class="area stack battle p0 cards"></div> <div id="battleground_p1" class="area stack battle p1 cards"></div> </div> <div id="player1_area" class="area player p1"> <div id="player1_area_deck" class="p1 area deck cards"></div> <div id="player1_area_wins" class="p1 area wins cards"></div> </div> </div> </div> </body> </html>
War.css
.area, .card { min-height:180px; width:120px; display:block; border:1px solid black; border-radius:5px; } .area { background-color: grey; } .card { background-color:white; } .card.facedown { background-color:blue; } #playarea { position:relative; width:90%; margin-left:auto; margin-right:auto; } #battleground { background-color:orange; width:500px; margin-left:auto; margin-right:auto; position:relative; } .area.player, .area.stack { position:absolute; top:0px; } .area.p0 { left:0px; } .area.p1 { right:0px; } .card.latest { background-color:yellow !important; } .wins .card { position:relative; margin-top:-97%; z-index:99; } .wins .card.latest { margin-top:0px; z-index:9; } body { overflow-x:hidden; }
-
Version 2.65
- Event driven framework is now way more functional. Need to add back in game-ending ties
- Rudimentary animation that is only slightly
- Moar colours
- Add "Play one card" button and "Play entire game" button
- Speed factor present, will add slider in the future
- Need to add "interrupt"
- Shorterm goal: Add some sort of progress indicator to show who is winning (total cards owned vs. cards in deck)
- Longterm goal: anything that is framework (move cards, compare stacks, etc) move into framework
- Longterm goal: anything custom to the game-- abstract it, add it to framework, and implement in game
- Shortterm goal: More fun matchups, such as Crushing Victory (Ace beats 2 gets extra card)
- Shortterm goal: alt win conditions, such as World War III (3 WARS chained together result in next WAR ending game), and Royal Domination (insta win if you have all 4 suites of JQKA)
War.html
<html> <head> <link href="http://sevenseventeen.ca/war.css" rel="stylesheet"></link> <script src="http://sevenseventeen.ca/wp-includes/js/jquery/jquery.js" type="text/javascript"></script> <script src="http://sevenseventeen.ca/wp-includes/js/jquery/ui/jquery-ui.js" type="text/javascript"></script> <link href="http://sevenseventeen.ca/wp-includes/js/jquery/ui/jquery-ui.min.css" rel="stylesheet"></link> <script type="text/javascript"> var SpeedFactor = 0.75; var $Universe = null; var decks = []; var wins = []; var kitty = []; var winner = 0; var battle = []; var suites = ["Hearts", "Spades", "Diamonds", "Clubs"]; var ranks = {"Two" : 2, "Three" : 3, "Four" : 4, "Five" : 5, "Six" : 6, "Seven" : 7, "Eight" : 8, "Nine" : 9, "Ten" : 10, "Jack" : 11, "Queen" : 12, "King" : 13, "Ace": 14}; var GameDeck = []; for(s = 0; s < suites.length; s++) { suit = suites[s]; for(var rank in ranks) { card = {"Suit" : suit, "Rank" : rank, "Value" : ranks[rank]}; GameDeck.push(card); } } function CreateCardElement(card) { var $card = $("<div></div>"); $card.addClass("card"); $card.addClass(card.Suit); $card.text(card.Rank + " " + card.Suit); $card.data("card", card); return $card; } // UI functions // TODO put visibility of card into card properties // player = 0 index id of player function PutCardOnBattleground(player, card) { var batleground_area = $("#battleground_p" + player); var cardui = CreateCardElement(card); batleground_area.append(cardui); } function SortByValue(a,b) { var c1=$(a).data("card").Value; var c2=$(b).data("card").Value; var ret = c1 < c2 ? 1 : c1 > c2 ? -1 : 0; return ret; } // Collect all ventured cards into the winners Win pile function CollectWinnings(player) { var winnings = $(".battle .card"); var winpile = $("#player"+player+"_area_wins"); var $Universe = $("#Universe"); winpile.find(".card").removeClass("latest"); winnings.addClass("latest"); $Universe.on("MoveCardsCompleted", OnMoveCardsCompleted_SortWinnings); $Universe.on("MoveCardsCompleted", OnMoveCardsCompleted_ToWinPile); $(".battle").each(function() { var opts = {}; opts.MoveAllCards = true; opts.from = $(this); opts.to = winpile; opts.prepend = true; $Universe.trigger("MoveCard", opts); }); /* winnings.each(function() { var opts = {}; opts.from = $(this).parents(".battle:first"); opts.to = winpile; opts.prepend = true; opts.cardui = $(this); $Universe.trigger("MoveCard", opts); }); */ } function OnMoveCardsCompleted_SortWinnings(e, opts) { var $Universe = $("#Universe"); $Universe.off("MoveCardsCompleted", OnMoveCardsCompleted_SortWinnings); for(var i = 0; i <= 1; i++) { var cards = $(".wins").eq(i).find(".card.latest"); if(cards.length > 0) { cards .detach() .sort(SortByValue) .prependTo($(".wins").eq(i)); } } } // Empty Win Pile UI function ClearWinsPile(player) { var winpile = document.getElementById("player"+player+"_area_wins"); while(winpile.childNodes.length > 0) { winpile.removeChild(winpile.firstChild); } } // face down deck. Clear anything in there, put face down card, and add counter function RefreshDeck(player) { var deck = document.getElementById("player"+player+"_area_deck"); while(deck.childNodes.length > 0) { deck.removeChild(deck.firstChild); } var card = document.createElement("div"); card.className = "area facedown"; deck.appendChild(card); var cnt = document.createElement("div"); card.appendChild(cnt); cnt.textContent = decks[player].length; } // End UI functions function shuffle(array) { var currentIndex = array.length, temporaryValue, randomIndex ; // While there remain elements to shuffle... while (0 !== currentIndex) { // Pick a remaining element... randomIndex = Math.floor(Math.random() * currentIndex); currentIndex -= 1; // And swap it with the current element. temporaryValue = array[currentIndex]; array[currentIndex] = array[randomIndex]; array[randomIndex] = temporaryValue; } return array; } // draw one card from deck IDX, return that card or null // when a deck runs out, reshuffle win pile into deck // if no cards remain in deck or win pile, returns null function draw(idx) { if(decks[idx].length == 0) { while(wins[idx].length > 0) { card = wins[idx].shift(); decks[idx].push(card); ClearWinsPile(idx); } decks[idx] == shuffle(decks[idx]); } card = decks[idx].shift(); RefreshDeck(idx); return card; } // end function draw function CardsOwned(player) { return decks[player].length + wins[player].length; } function DoWar(numcards) { winner = -1; // tie var PlayerDepleted = false; for(var i=0; i<=1; i++) { if(CardsOwned(i) == 0) { PlayerDepleted = true; } } if(PlayerDepleted) { // there is a player who cannot war no more. The only way to resolve this is // First, who has the most rank values. // If still tied, who has the most cards. // If STILL tied, then both players are exactly where they were when they started. Reshuffle everything and start again. console.log("Player " + i + " has run out of cards and cannot commit to war. Checking for armistice."); // someone has run out of cards, AND ended with a war // the winner of the game will be whoever has more cards for(var idx = 0; idx <= 1; idx++) { // move everything into the battle piles while(wins[idx].length > 0) { card = wins[idx].shift(); battle[idx].push(card); PutCardOnBattleground(idx, card); } while(decks[idx].length > 0) { card = decks[idx].shift(); battle[idx].push(card); PutCardOnBattleground(idx, card); } ClearWinsPile(idx); RefreshDeck(idx); } winner = -1; // tie // total up the values of the cards in the decks totals = []; totals[0] = 0; totals[1] = 0; for(var i = 0; i <=1; i++) { for(j = 0; j < battle[i].length; j++) { totals[i] = totals[i] + battle[i][j].Value; } } // compare totals for(var i = 0; i <=1; i++) { console.log("Player " + i + " has " + totals[i] + " points in rank"); up = i % 2; down = (i+1) % 2; if(totals[up] > totals[down]) { winner = up; } } console.log("A winner of the whole game is " + winner); if(winner < 0) { console.log("Players are tied in rank. Checking by number of cards"); // it is still a tie because both players have the same value of cards // go by number of cards for(var i = 0; i <=1; i++) { console.log("Player " + i + " has " + battle[i].length + " cards"); up = i % 2; down = (i+1) % 2; if(battle[up].length > battle[down].length) { winner = up; } } } console.log("A winner of the whole game is " + winner); if(winner < 0) { console.log("Players are equal in rank and cards. Putting all cards back into decks and starting again."); // OMFG both players have the same number of cards and the same total values. // just start the damn game again! SetupNewGame(1); } if(winner < 0) { // forget it. The universe has ended. throw new Exception("Forget it. The universe has ended"); } return winner; } // end tiebreaker // Only venture as many cards as any one player has for(var i=0; i<=1; i++) { if(CardsOwned(i) < numcards) { console.log("Player " + i + " cannot venture " + numcards + " cards, so instead we'll do " + CardsOwned(i)); numcards = CardsOwned(i); } } for(drawidx = 0; drawidx < numcards; drawidx++) { for(var i = 0; i <=1; i++) { // Each player adds a card to the top of the battlegrounds, to face off card = draw(i); battle[i].push(card); PutCardOnBattleground(i, card); RefreshDeck(i); } } // Check for the winner by comparing the top cards of the battleground to each other for(var i = 0; i <=1; i++) { up = i % 2; down = (i+1) % 2; if(battle[up][battle[up].length - 1].Value > battle[down][battle[down].length - 1].Value) { winner = up; } } if(winner < 0) { console.log("We're at war!"); if(numcards > 1) { console.log("EXTRA WAR!!!"); } // Oh shnit! We have a tie. Let us settle it with W-A-R!!!! // a tie had occured. Oh noes! // W-A-R then flip 1 winner = DoWar(4); } // end WAR return winner; } // end battle function CheckCurrentBattleWinner(bottom) { var winner = -1; bottom = (bottom == null ? false : bottom); // Check for the winner by comparing the top cards of the battleground to each other for(var i = 0; i <=1; i++) { up = i % 2; down = (i+1) % 2; if(battle[up][bottom ? battle[up].length - 1 : 0].Value > battle[down][bottom ? battle[down].length - 1 : 0].Value) { winner = up; } } return winner; } function PlayOneRound(NumberOfCards) { // When we're done moving cards from the decks to the battleground, initiate the battle $Universe.on("MoveCardsCompleted", OnMoveCardsCompleted_ToBattleground); // Only venture as many cards as any one player has for(var i=0; i<=1; i++) { if(CardsOwned(i) < NumberOfCards) { console.log("Player " + i + " cannot venture " + NumberOfCards + " cards, so instead we'll do " + CardsOwned(i)); NumberOfCards = CardsOwned(i); } } // Draw cards. Create UI for them. Move them. for(var i = 0; i<=1; i++) { var fromui = $(".deck").eq(i); var toui = $(".battle").eq(i); for(var cnt = 0; cnt < NumberOfCards; cnt++) { var card = draw(i); var cardui = CreateCardElement(card); fromui.append(cardui); var opts = {}; opts.from = fromui; opts.to = toui; opts.prepend = true; opts.cardui = cardui; //opts.MoveAllCards = true; $Universe.trigger("MoveCard", opts); } } } function OnMoveCardsCompleted_ToBattleground() { // Stop listening // Probably better to do something like adding this listener to the UI target itself rather than the Universe $Universe.off("MoveCardsCompleted", OnMoveCardsCompleted_ToBattleground); winner = CheckCurrentBattleWinner(); if(winner < 0) { var opts = {}; opts.NumberOfCards = 4; Pulse($(".battle .card"), "ui-state-error", 3, PlayOneRound, 4); } else { Pulse($(".battle").eq(winner).find(".card"), "ui-state-default", 1, CollectWinnings, winner); //CollectWinnings(winner); } } function Pulse(elms, cssClass, numPulses, OnComplete, opts) { var $Universe = $("#Universe"); var anim = 0; // flash the cards as a warning $(elms) .addClass(cssClass, { duration:250 * SpeedFactor, complete: function() { anim++; $(this).removeClass(cssClass, { duration:250 * SpeedFactor, complete:function() { anim--; if(anim == 0) { if(numPulses <= 0) { OnComplete(opts); } else { numPulses = numPulses - 1; Pulse(elms, cssClass, numPulses, OnComplete, opts); } } } }) } }); } function OnMoveCardsCompleted_ToWinPile(e, opts) { $Universe.off("MoveCardsCompleted", OnMoveCardsCompleted_ToWinPile); $Universe.trigger("OnAfterPlayOneRound"); } function SetupBoard() { $(".cards").each(function(e) { var $this = $(this); $this.data("cards", []); }); } function SetUpNewGame(numPlayersZeroIndex) { GameDeck = shuffle(GameDeck); for(var i = 0; i<= numPlayersZeroIndex; i++) { decks[i] = []; $("#player"+i+"_area_deck").data("cards", decks[i]); wins[i] = []; $("#player"+i+"_area_wins").data("cards", wins[i]); battle[i] = []; $("#battleground_p" + i).data("cards", battle[i]); } for(var i = 0; i < GameDeck.length; i++) { decks[i%(numPlayersZeroIndex + 1)].push(GameDeck[i]); } // set up deck UI for(var i = 0; i<= numPlayersZeroIndex; i++) { ClearWinsPile(i); RefreshDeck(i); } } </script> <script type="text/javascript"> // jquery sheeeeeet $(document).ready(function() { SetupBoard(); SetUpNewGame(1); $Universe = $("#Universe"); $Universe.data("cards_moving", 0); $("#OneRound").click(function(e) { var opts = {}; opts.NumberOfCards = 1; $Universe.trigger("PlayOneRound", opts); }); $("#AllRounds").click(function(e) { $("#Universe").on("OnAfterPlayOneRound", OnAfterPlayOneRound_AllRounds); var opts = {}; opts.NumberOfCards = 1; $Universe.trigger("PlayOneRound", opts); }); $("#PushTest").click(function(e) { for(var i=0;i<=1;i++) { var card = {}; card.Value = 15; card.Suit = "Hearts"; card.Rank = "Test"; decks[i].unshift(card); } }); }); function OnAfterPlayOneRound_AllRounds() { if(CardsOwned(0) > 0 && CardsOwned(1) > 0) { var opts = {}; opts.NumberOfCards = 1; $Universe.trigger("PlayOneRound", opts); } } // Universe handlers $(document).ready(function() { $Universe.on("PlayOneRound", function(e, opts) { var defaults = {}; defaults.NumberOfCards = 1; $.merge(defaults, opts); // A round has been triggered. Play it, then call On Complete $Universe.trigger("OnBeforePlayOneRound", e); var NumberOfCards = opts.NumberOfCards; PlayOneRound(NumberOfCards); }); // default round actions $Universe.on("OnBeforePlayOneRound", function(e) { // default action: disable action things $(".action").addClass("ui-state-disabled"); }); $Universe.on("OnAfterPlayOneRound", function(e) { // restore action buttons $(".action").removeClass("ui-state-disabled"); }); /* player: idx, card: card, from: decks[idx], to: battle[idx], facedown_from: false, facedown_to: true */ $Universe.on("MoveCard", function(e, opts) { var defaults = {MoveAllCards : false}; $.merge(opts, defaults); // get the card from the target // expose it on the target // animate it to the other target var $card = $(opts.cardui); var $FromUI = $(opts.from); var $ToUI = $(opts.to); var $LastCard = $FromUI.find(".card:last"); if(opts.MoveAllCards) { if($LastCard.length > 0) { $card = $LastCard; } } var top = $FromUI.offset().top; var left = $FromUI.offset().left; var card = $card.data("card"); var cards = $FromUI.data("cards"); // remove the card from the target UI, if it exists if(cards != null && cards.indexOf(card) >= 0) { cards.splice(cards.indexOf(card), 1); } $card .detach() .appendTo("body") .css("position", "absolute") .css("top", top) .css("left", left) .animate ( { left:$ToUI.offset().left, top:$ToUI.offset().top }, "slow", function() { var newOpts = {}; $.extend(newOpts, opts); newOpts.cardui = $card; $Universe.trigger("MoveCardComplete", newOpts); if(opts.MoveAllCards && $FromUI.find(".card").length > 0) { $Universe.trigger("MoveCard", opts); } } ); }); $Universe.on("MoveCardComplete", function(e, opts) { var $card = $(opts.cardui); var $FromUI = $(opts.from); var $ToUI = $(opts.to); var card = $card.data("card"); var cards = $ToUI.data("cards"); if(opts.prepend) { $card.prependTo($ToUI); cards.unshift(card); } else { $card.appendTo($ToUI); cards.push(card); } $card.css("position", "static"); }); // Card in motion tracking $Universe.on("MoveCard", function(e, opts) { $Universe.data("cards_moving", $Universe.data("cards_moving") + 1); }); $Universe.on("MoveCardComplete", function(e, opts) { $Universe.data("cards_moving", $Universe.data("cards_moving") - 1); // I have a feeling there's a better way to do this-- push all card moves onto a stack, then raise a Move Stack ready-- then raise a Move Stack Complete // Next iteration it is. I'll live with the race condition for now. if($Universe.data("cards_moving") == 0) { $Universe.trigger("MoveCardsCompleted"); } }); }); </script> </head> <body> <div id="Universe"> <div style="position:block;min-height:2em;"> <div style="position:absolute;"> <button id="OneRound" class="action">Play One Round</button> <button id="AllRounds" class="action">Play All</button> <button id="PushTest" class="action">Push Test Cards for Tie</button> </div> </div> <div id="playarea" class="" style="margin-top:2em;"> <div id="player0_area" class="area player p0"> <div id="player0_area_deck" class="p0 area deck cards stack"></div> <div id="player0_area_wins" class="p0 area wins cards stack"></div> </div> <div id="battleground" class="area battleground"> <div id="battleground_p0" class="p0 area battle cards stack"></div> <div id="battleground_p1" class="p1 area battle cards stack"></div> </div> <div id="player1_area" class="area player p1"> <div id="player1_area_deck" class="p1 area deck cards pile"></div> <div id="player1_area_wins" class="p1 area wins cards stack"></div> </div> </div> </div> </body>
War.css
body { overflow-x:hidden; background-color:#32CD32; } .area, .card { max-height:180px; height:100%; width:120px; display:block; border:1px solid black; border-radius:5px; } .area { background-color: grey; } .card { background-color:white; z-index:50000; } .card.facedown { background-color:blue; } #playarea { position:relative; width:90%; margin-left:auto; margin-right:auto; } #battleground { background-color:orange; width:500px; margin-left:auto; margin-right:auto; position:relative; } .area.player, .area.stack { position:absolute; top:0px; } .area.player { min-width:360px; } .area.player .pile, .area.player .stack, .battle { position:absolute; } .area.player.p0 .deck { left:0px; z-index:500; } .area.player.p0 .wins { right:0px; z-index:500; } .area.player.p1 { right:0px; } .area.player.p1 .deck { position:absolute; right:0px !important; z-index:500; background-color:purple; } .area.player.p1 .wins { left:0px; z-index:501; background-color:purple; } .battleground .battle.p1 { position:absolute; right:0px; } .card.latest { background-color:yellow !important; } /* Cards stacked so you can see the one underneath */ .stack .card { position:relative; margin-top:-160px; z-index:999; } .stack .card:first-child { margin-top:0px; } /* Cards piled so you can't see what is underneath */ .pile .card { position:relative; margin-top:-100%; z-index:999; } .pile .card:first-of-type { margin-top:0px; }
-
-
What variant of English pluralizes suit to suites? My decks come with 4 suits
-
But what is it good for?
-
-
@Jaloopa said:
But what is it good for?
Absolutely nothing, oh hoh, oh
Learning to make Javascript-enabled pages.
So, your point is still 100% valid.
-
What variant of English pluralizes suit to suites? My decks come with 4 suits
Spelling is for programmers. (CLOSED_WONT_FIX)[will fix in next iteration]
-
@Lorne_Kates said:
So, your point is still 100% valid.
i had a point?
i was just posting the next line of the lyrics....
-
I actually wrote a JS cards framework that was intended to take .js plug-in files and run them. For the cards, I used images I stole from the BOWEP card games.
I might see if I still have that anywhere. I had a working Solitaire and a semi-completed BlackJack. War should be pretty easy, although the user interaction required is basically zero: just wait until they click so that the game's slow enough for them to see it.
-
I thought you meant you were going to use the XSS injection (probably patched now) to make the game playable right here.
-
PROTIP: when you make a joke that is actually slightly funny, DO NOT LATER EXPLAIN THE JOKE AND RUIN IT
-
PROTIP: when you make a joke that is actually slightly funny, DO NOT LATER EXPLAIN THE JOKE AND RUIN IT
I'll remember that if i ever make a joke on purpose.
-
PROTIP: when you make a joke that is actually slightly funny,
DO NOT LATER EXPLAIN THE JOKE AND RUIN ITYa probably weren't trying ta make a joke in tha first place!FTFY
-
**Version 2.95. **
- better UI still mostly
- Added "Crushing Defeat" on Ace vs. 2
- Messaging system
- alt victory conditions, but must signal game to stop
- "Royal Capture" victory if you have JQK of all suites.
- Reversed tie breaker. If both players have same total value of cards, then player with FEWER cards (more high value cards) wins.
- MOAR EVENTS. Too many events? ?
- Add .TotalValue function to decks
- MILESTONE REACHED: hit 32000 character limit to message. Will post the codez in next replies
-
war.html
<html> <head> <link href="http://sevenseventeen.ca/war.css" rel="stylesheet"></link> <script src="http://sevenseventeen.ca/wp-includes/js/jquery/jquery.js" type="text/javascript"></script> <script src="http://sevenseventeen.ca/wp-includes/js/jquery/ui/jquery-ui.js" type="text/javascript"></script> <link href="http://sevenseventeen.ca/wp-includes/js/jquery/ui/jquery-ui.min.css" rel="stylesheet"></link> <script type="text/javascript"> // Assign to deck arrays function TotalValue() { var t = 0; for(var idx = 0; idx < this.length; idx++) { t += this[idx].Value; } return t; } function GetNewDeck() { var ret = []; ret.TotalValue = TotalValue; return ret; } var SpeedFactor = 0.6; var $Universe = null; var decks = []; var wins = []; var kitty = []; var winner = 0; var battle = []; var suites = ["Hearts", "Spades", "Diamonds", "Clubs"]; var glyphs = ["♥", "♠", "⋄", "♣"]; var ranks = {"Two" : 2, "Three" : 3, "Four" : 4, "Five" : 5, "Six" : 6, "Seven" : 7, "Eight" : 8, "Nine" : 9, "Ten" : 10, "Jack" : 11, "Queen" : 12, "King" : 13, "Ace": 14}; var shorts = ["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"]; var GameDeck = GetNewDeck(); for(s = 0; s < suites.length; s++) { suit = suites[s]; var idx = 0; for(var rank in ranks) { card = {"Suit" : suit, "Rank" : rank, "Value" : ranks[rank], "Glyph" : glyphs[s], "Short" : shorts[idx]}; GameDeck.push(card); idx++; } } function CreateCardElement(card) { var $card = $("<div></div>"); $card.addClass("card"); $card.addClass(card.Suit); var $text = $("<div></div>"); if(card.Glyph != null) { $card.html(card.Short + " " + card.Glyph); } else { $card.html(card.Rank + " " + card.Suit); } //$card.append($text); $card.data("card", card); return $card; } // UI functions // TODO put visibility of card into card properties // player = 0 index id of player function PutCardOnBattleground(player, card) { var batleground_area = $("#battleground_p" + player); var cardui = CreateCardElement(card); batleground_area.append(cardui); } function SortByValue(a,b) { var c1=$(a).data("card").Value; var c2=$(b).data("card").Value; var ret = c1 < c2 ? 1 : c1 > c2 ? -1 : 0; return ret; } // Collect all ventured cards into the winners Win pile function CollectWinnings(player) { var winnings = $(".battle .card"); var winpile = $("#player"+player+"_area_wins"); var $Universe = $("#Universe"); winpile.find(".card").removeClass("latest"); winnings.addClass("latest"); $Universe.on("MoveCardsCompleted", OnMoveCardsCompleted_SortWinnings); $Universe.on("MoveCardsCompleted", OnMoveCardsCompleted_ToWinPile); $(".battle").each(function() { var opts = {}; opts.MoveAllCards = true; opts.from = $(this); opts.to = winpile; opts.prepend = true; $Universe.trigger("MoveCard", opts); }); } function OnMoveCardsCompleted_SortWinnings(e, opts) { var $Universe = $("#Universe"); $Universe.off("MoveCardsCompleted", OnMoveCardsCompleted_SortWinnings); for(var i = 0; i <= 1; i++) { var cards = $(".wins").eq(i).find(".card.latest"); if(cards.length > 0) { cards .detach() .sort(SortByValue) .prependTo($(".wins").eq(i)); } } } // Empty Win Pile UI function ClearWinsPile(player) { var winpile = document.getElementById("player"+player+"_area_wins"); while(winpile.childNodes.length > 0) { winpile.removeChild(winpile.firstChild); } } // face down deck. Clear anything in there, put face down card, and add counter function RefreshDeck(player) { var deck = document.getElementById("player"+player+"_area_deck"); while(deck.childNodes.length > 0) { deck.removeChild(deck.firstChild); } var card = document.createElement("div"); card.className = "area facedown"; deck.appendChild(card); var cnt = document.createElement("div"); card.appendChild(cnt); cnt.textContent = decks[player].length; } // End UI functions function shuffle(array) { var currentIndex = array.length, temporaryValue, randomIndex ; // While there remain elements to shuffle... while (0 !== currentIndex) { // Pick a remaining element... randomIndex = Math.floor(Math.random() * currentIndex); currentIndex -= 1; // And swap it with the current element. temporaryValue = array[currentIndex]; array[currentIndex] = array[randomIndex]; array[randomIndex] = temporaryValue; } return array; } // draw one card from deck IDX, return that card or null // when a deck runs out, reshuffle win pile into deck // if no cards remain in deck or win pile, returns null function draw(idx) { if(decks[idx].length == 0) { while(wins[idx].length > 0) { card = wins[idx].shift(); decks[idx].push(card); ClearWinsPile(idx); } decks[idx] == shuffle(decks[idx]); } card = decks[idx].shift(); RefreshDeck(idx); return card; } // end function draw function CardsOwned(player) { return decks[player].length + wins[player].length; } function CheckCurrentBattleWinner(bottom) { var winner = -1; bottom = (bottom == null ? false : bottom); // Check for the winner by comparing the top cards of the battleground to each other for(var i = 0; i <=1; i++) { up = i % 2; down = (i+1) % 2; if(battle[up][bottom ? battle[up].length - 1 : 0].Value > battle[down][bottom ? battle[down].length - 1 : 0].Value) { winner = up; } } return winner; } function PlayOneRound(NumberOfCards) { var PlayerDepleted = false; var DepletedPlayer = -1; for(var i=0; i<=1; i++) { if(CardsOwned(i) == 0) { PlayerDepleted = true; DepletedPlayer = i; } } if(PlayerDepleted) { var opts = {}; opts.message = "Player " + (DepletedPlayer+1) + " cannot commit to war. Checking for armistice."; opts.delay = 5000; $Universe.trigger("ShowMessage", opts); var card; $Universe.on("MoveCardsCompleted", OnMoveCardsCompleted_Armistice); // Move all cards onto the Battleground for final reckoning for(var i=0; i<=1; i++) { var fromui = $(".deck").eq(i); var toui = $(".battle").eq(i); card = draw(i); while(card != null) { var cardui = CreateCardElement(card); fromui.append(cardui); var opts = {}; opts.from = fromui; opts.to = toui; opts.prepend = true; opts.cardui = cardui; $Universe.trigger("MoveCard", opts); card = draw(i); } } return; // else if } // END PlayerDepleted // When we are done moving cards from the decks to the battleground, initiate the battle $Universe.on("MoveCardsCompleted", OnMoveCardsCompleted_ToBattleground); // Only venture as many cards as any one player has for(var i=0; i<=1; i++) { if(CardsOwned(i) < NumberOfCards) { console.log("Player " + i + " cannot venture " + NumberOfCards + " cards, so instead we'll do " + CardsOwned(i)); NumberOfCards = CardsOwned(i); } } // Draw cards. Create UI for them. Move them. for(var i = 0; i<=1; i++) { var fromui = $(".deck").eq(i); var toui = $(".battle").eq(i); for(var cnt = 0; cnt < NumberOfCards; cnt++) { var card = draw(i); var cardui = CreateCardElement(card); fromui.append(cardui); var opts = {}; opts.from = fromui; opts.to = toui; opts.prepend = true; opts.cardui = cardui; //opts.MoveAllCards = true; $Universe.trigger("MoveCard", opts); } } } function OnMoveCardsCompleted_Armistice(e, opts) { var $Universe = $("#Universe"); $Universe.off("MoveCardsCompleted", OnMoveCardsCompleted_ToBattleground); // Check for alt victory conditions // there is a player who cannot war no more. The only way to resolve this is // First, who has the most rank values. // If still tied, who has the most cards. // If STILL tied, then both players are exactly where they were when they started. Reshuffle everything and start again. var winner = -1; // tie var gopts = {}; // total up the values of the cards in the decks totals = []; totals[0] = 0; totals[1] = 0; for(var i = 0; i <=1; i++) { totals[i] = decks[i].TotalValue() + battle[i].TotalValue() + wins[i].TotalValue(); } // compare totals for(var i = 0; i <=1; i++) { up = i % 2; down = (i+1) % 2; if(totals[up] > totals[down]) { winner = up; gopts.winner = winner; gopts.message = totals[i] + " points in ranks"; } } if(winner < 0) { var mopts = {}; mopts.message = "Players are tied in rank. Checking number of high cards"; $Universe.trigger("ShowMessage", mopts); // it is still a tie because both players have the same value of cards // go by number of cards for(var i = 0; i <=1; i++) { up = i % 2; down = (i+1) % 2; // having fewer cards is better, because you captured more of the high cards if(battle[up].length < battle[down].length) { winner = up; gopts.winner = winner; gopts.message = " has " + battle[up].length + " cards"; } } } if(winner < 0) { var mopts = {}; mopts.message = "Still tied. Starting over."; $Universe.trigger("ShowMessage", mopts); $Universe.on("MoveCardsCompleted", OnMoveCardsCompleted_StartNewRound); for(var i=0; i<=1; i++) { var fromui = $(".battle").eq(i); var toui = $(".wins").eq(i); var opts = {}; opts.MoveAllCards = true; opts.from = formui; opts.to = toui; opts.prepend = true; $Universe.trigger("MoveCard", opts); } } // restart game else { // trigger game over var opts = {}; opts.keep = true; opts.message = "Player " + (winner + 1) + " wins! " + gopts.message; $Universe.trigger("ShowMessage", opts); $Universe.trigger("GameOver"); } } function OnMoveCardsCompleted_StartNewRound(e, opts) { var ropts = {}; ropts.NumberOfCards = 1; $Universe.trigger("PlayOneRound", ropts); } function OnMoveCardsCompleted_ToBattleground() { // Stop listening // Probably better to do something like adding this listener to the UI target itself rather than the Universe var $Universe = $("#Universe"); $Universe.off("MoveCardsCompleted", OnMoveCardsCompleted_ToBattleground); var winner = CheckCurrentBattleWinner(); if(winner < 0) { var mopts = {}; mopts.message = "W-A-R!"; $Universe.trigger("ShowMessage", mopts); /* DO WAR */ var opts = {}; opts.NumberOfCards = 4; Pulse($(".battle .card"), "ui-state-error", 3, PlayOneRound, 4); } else { /* Check for extra points */ var opts = {}; opts.winner = winner; var $Universe = $("#Universe"); $Universe.on("OnPostCheckWinner", OnPostCheckWinner_ExtraCards); $Universe.trigger("OnPostCheckWinner", opts); } } // After winner is determined, check for other things function OnPostCheckWinner_ExtraCards(e, opts) { var $Universe = $("#Universe"); $Universe.off("OnPostCheckWinner", OnPostCheckWinner_ExtraCards); $Universe.on("MoveCardsCompleted", MoveCardsCompleted_CollectWinnings); var winner = opts.winner; var loser = ((winner + 1) % 2); var special = false; if(battle[winner].length > 0 && battle[loser].length > 0) { var WinningCard = battle[winner][battle[winner].length - 1]; var LosingCard = battle[loser][battle[loser].length - 1]; var newOpts = {}; if(WinningCard.Value == 14 && LosingCard.Value == 2) { console.log("Crushing defeat!"); var mopts = {message: "Crushing Defeat!"}; $Universe.trigger("ShowMessage", mopts); card = draw(loser); newOpts.cardui = CreateCardElement(card); newOpts.from = $(".deck").eq(loser); newOpts.to = $(".battle").eq(loser); newOpts.winner = winner; newOpts.loser = loser; $Universe.trigger("MoveCard", newOpts); special = true; } } if(! special) { MoveCardsCompleted_CollectWinnings(null, opts); } } // Now collect winnings function MoveCardsCompleted_CollectWinnings(e, opts) { var $Universe = $("#Universe"); $Universe.off("MoveCardsCompleted", MoveCardsCompleted_CollectWinnings); var winner = opts.winner; Pulse($(".battle").eq(winner).find(".card"), "ui-state-default", 1, CollectWinnings, winner); } function DoCollectWinnings(winner) { } function Pulse(elms, cssClass, numPulses, OnComplete, opts) { var $Universe = $("#Universe"); var anim = 0; // flash the cards as a warning $(elms) .addClass(cssClass, { duration:250 * SpeedFactor, complete: function() { anim++; $(this).removeClass(cssClass, { duration:250 * SpeedFactor, complete:function() { anim--; if(anim == 0) { if(numPulses <= 0) { OnComplete(opts); } else { numPulses = numPulses - 1; Pulse(elms, cssClass, numPulses, OnComplete, opts); } } } }) } }); } function OnMoveCardsCompleted_ToWinPile(e, opts) { $Universe.off("MoveCardsCompleted", OnMoveCardsCompleted_ToWinPile); $Universe.trigger("OnAfterPlayOneRound", opts); } function SetupBoard() { $(".cards").each(function(e) { var $this = $(this); $this.data("cards", GetNewDeck()); }); } function SetUpNewGame(numPlayersZeroIndex) { GameDeck = shuffle(GameDeck); for(var i = 0; i<= numPlayersZeroIndex; i++) { decks[i] = GetNewDeck(); $("#player"+i+"_area_deck").data("cards", decks[i]); wins[i] = GetNewDeck(); $("#player"+i+"_area_wins").data("cards", wins[i]); battle[i] = GetNewDeck(); $("#battleground_p" + i).data("cards", battle[i]); } for(var i = 0; i < GameDeck.length; i++) { decks[i%(numPlayersZeroIndex + 1)].push(GameDeck[i]); } // set up deck UI for(var i = 0; i<= numPlayersZeroIndex; i++) { ClearWinsPile(i); RefreshDeck(i); } } </script> <script type="text/javascript"> // jquery sheeeeeet $(document).ready(function() { $(".action").removeClass("ui-state-disabled").attr("disabled", false); SetupBoard(); SetUpNewGame(1); $Universe = $("#Universe"); $Universe.data("cards_moving", 0); $("#OneRound").click(function(e) { var opts = {}; opts.NumberOfCards = 1; $Universe.trigger("PlayOneRound", opts); }); $("#AllRounds").click(function(e) { $("#Universe").on("OnAfterPlayOneRound", OnAfterPlayOneRound_AllRounds); var opts = {}; opts.NumberOfCards = 1; $Universe.trigger("PlayOneRound", opts); }); $("#PushTest").click(function(e) { for(var i=0;i<=1;i++) { var card = {}; card.Value = 15; card.Suit = "Hearts"; card.Rank = "Test"; decks[i].unshift(card); } }); $("#PushAceTwoTest").click(function(e) { var card = {}; card.Value = 14; card.Suit = "Hearts"; card.Rank = "Ace"; decks[0].unshift(card); card = {}; card.Value = 2; card.Suit = "Hearts"; card.Rank = "Two"; decks[1].unshift(card); RefreshDeck(0); RefreshDeck(1); }); $("#SetupShortGame").click(function(e) { for(var i=0;i<=1;i++) { while(decks[i].length > 1) { decks[i].shift(); } RefreshDeck(i); } }); $("#SetupArmisticeRank").click(function(e) { var card; var suit; for(var i=0;i<=1;i++) { decks[i] = GetNewDeck(); var idx = 0; for(var rank in ranks) { card = {"Suit" : suites[0], "Rank" : rank, "Value" : ranks[rank], "Glyph" : glyphs[0], "Short" : shorts[idx]}; if(idx < 7 && ( i==0 || (i==1 && idx < 2))) { decks[i].push(card); } idx++; } RefreshDeck(i); } }); $("#SetupArmisticeCount").click(function(e) { var card; var suit; var lastcard; for(var i=0;i<=1;i++) { decks[i] = GetNewDeck(); var idx = 0; for(var rank in ranks) { card = {"Suit" : suites[0], "Rank" : rank, "Value" : ranks[rank], "Glyph" : glyphs[0], "Short" : shorts[idx]}; if(idx == 0) { lastcard = {"Suit" : suites[0], "Rank" : rank, "Value" : ranks[rank], "Glyph" : glyphs[0], "Short" : shorts[idx]}; // deck 1 gets 3 2s, deck 2 gets a 2 and a 4 decks[i].push(card); if(i == 0) { card = {"Suit" : suites[0], "Rank" : rank, "Value" : ranks[rank], "Glyph" : glyphs[0], "Short" : shorts[idx]}; decks[i].push(card); card = {"Suit" : suites[0], "Rank" : rank, "Value" : ranks[rank], "Glyph" : glyphs[0], "Short" : shorts[idx]}; decks[i].push(card); } } else if (idx == 2 && i == 1) { // deck 2 gets one 4 decks[i].push(card); } idx++; } decks[i].push(lastcard); RefreshDeck(i); } }); $("#SetupRoyalDefeat").click(function(e) { decks[0] = GetNewDeck(); decks[1] = GetNewDeck(); var card; var suit; for(var s = 0; s < suites.length; s++) { suit = suites[s]; var idx = 0; for(var rank in ranks) { if(ranks[rank] >= 11 && ranks[rank] <= 14) { card = {"Suit" : suit, "Rank" : rank, "Value" : ranks[rank], "Glyph" : glyphs[s], "Short" : shorts[idx]}; decks[0].push(card); } idx++; } } for(var s = 0; s < suites.length; s++) { suit = suites[s]; var idx = 0; for(var rank in ranks) { if(ranks[rank] < 11) { card = {"Suit" : suit, "Rank" : rank, "Value" : ranks[rank], "Glyph" : glyphs[s], "Short" : shorts[idx]}; decks[1].push(card); } idx++; } } RefreshDeck(0); RefreshDeck(1); }); }); function OnAfterPlayOneRound_AllRounds() { if(CardsOwned(0) > 0 && CardsOwned(1) > 0) { var opts = {}; opts.NumberOfCards = 1; $Universe.trigger("PlayOneRound", opts); } } // Check for victory conditions function OnAfterPlayOneRound_CheckVictory(e, opts) { // If one player is out of cards, the other player automagically wins // TODO: Also create a wordpress style call stack instead of events? var winner = -1; var winMessage = ""; for(i=1; i<=1; i++) { // todo: show message without clearing if(CardsOwned(i) == 0) { winner = ((i + 1) % 2); winMessage = "Complete Domination!"; } } for(i=0; i<=1; i++) { // Check to see if anyone has all royal families (J-K) var RoyalCount = 0; var card; for(var idx = 0; idx < decks[i].length; idx++) { card = decks[i][idx]; if(card.Value >= 11 && card.Value <= 13) { RoyalCount = RoyalCount + 1; } } for(var idx = 0; idx < wins[i].length; idx++) { card = wins[i][idx]; if(card.Value >= 11 && card.Value <= 13) { RoyalCount = RoyalCount + 1; } } if(RoyalCount == 12) { winner = i; winMessage = "Royal Capture"; } } if (winner >= 0) { var opts = {}; opts.keep = true; opts.message = "Player " + (winner + 1) + " wins! " + winMessage $Universe.trigger("ShowMessage", opts); $Universe.trigger("GameOver"); } } // Universe handlers $(document).ready(function() { $Universe.on("OnAfterPlayOneRound", OnAfterPlayOneRound_CheckVictory); $Universe.on("PlayOneRound", function(e, opts) { var defaults = {}; defaults.NumberOfCards = 1; $.merge(defaults, opts); // A round has been triggered. Play it, then call On Complete $Universe.trigger("OnBeforePlayOneRound", e); var NumberOfCards = opts.NumberOfCards; PlayOneRound(NumberOfCards); }); // default round actions $Universe.on("OnBeforePlayOneRound", function(e) { // default action: disable action things $(".action").addClass("ui-state-disabled"); }); $Universe.on("OnAfterPlayOneRound", function(e) { // restore action buttons $(".action").removeClass("ui-state-disabled"); }); /* player: idx, card: card, from: decks[idx], to: battle[idx], facedown_from: false, facedown_to: true */ $Universe.on("MoveCard", function(e, opts) { var defaults = {MoveAllCards : false}; $.merge(opts, defaults); // get the card from the target // expose it on the target // animate it to the other target var $card = $(opts.cardui); var $FromUI = $(opts.from); var $ToUI = $(opts.to); var $LastCard = $FromUI.find(".card:last"); if(opts.MoveAllCards) { if($LastCard.length > 0) { $card = $LastCard; } } var top = $FromUI.offset().top; var left = $FromUI.offset().left; var card = $card.data("card"); var cards = $FromUI.data("cards"); // remove the card from the target UI, if it exists if(cards != null && cards.indexOf(card) >= 0) { cards.splice(cards.indexOf(card), 1); } $card .detach() .appendTo("body") .css("position", "absolute") .css("top", top) .css("left", left) .animate ( { left:$ToUI.offset().left, top:$ToUI.offset().top }, "slow", function() { var newOpts = {}; $.extend(newOpts, opts); newOpts.cardui = $card; $Universe.trigger("MoveCardComplete", newOpts); if(opts.MoveAllCards && $FromUI.find(".card").length > 0) { $Universe.trigger("MoveCard", opts); } } ); }); $Universe.on("MoveCardComplete", function(e, opts) { var $card = $(opts.cardui); var $FromUI = $(opts.from); var $ToUI = $(opts.to); var card = $card.data("card"); var cards = $ToUI.data("cards"); if(opts.prepend) { $card.prependTo($ToUI); cards.unshift(card); } else { $card.appendTo($ToUI); cards.push(card); } $card.css("position", "static"); }); // Card in motion tracking $Universe.on("MoveCard", function(e, opts) { $Universe.data("cards_moving", $Universe.data("cards_moving") + 1); }); $Universe.on("MoveCardComplete", function(e, opts) { $Universe.data("cards_moving", $Universe.data("cards_moving") - 1); // I have a feeling there's a better way to do this-- push all card moves onto a stack, then raise a Move Stack ready-- then raise a Move Stack Complete // Next iteration it is. I'll live with the race condition for now. if($Universe.data("cards_moving") == 0) { $Universe.trigger("MoveCardsCompleted", opts); } }); var MessageBuffer = []; var MessageMutex = null; $Universe.on("ShowMessage", function(e, opts) { // Put message into stack MessageBuffer.push(opts); // Try to show the message TryShowMessage(opts); }); function TryShowMessage(opts) { // if my message is the first one, show it // otherwise HideMessage will be responsible for showing the next one if(MessageBuffer.length > 0 && MessageBuffer[0] == opts) { // remove from buffer var opts = MessageBuffer[0]; var defaults = {delay:2000, speed:"fast"}; $.extend(opts, defaults); if(opts.message != null) { var Message = opts.message; var $Message = $("#Message"); var $MessageText = $("<div></div>"); $MessageText.text(Message); $MessageText.addClass("message-text"); $MessageText.css("position", "absolute"); $MessageText.css("left", $Message.width()); $Message.append($MessageText); $MessageText.width($Message.width()) $MessageText.animate ( {left: 0}, opts.speed, function() { if(! opts.keep) { var hopts = {}; $.extend(hopts, opts); hopts.ui = $(this); setTimeout(function(){$Universe.trigger("HideMessage", hopts)}, opts.delay); } } ); } } } // try show message $Universe.on("HideMessage", function(e, opts) { var defaults = {delay:2000, speed:"fast"}; $.extend(opts, defaults); var $ui = opts.ui; var $Message = $("#Message"); $ui.animate ( {left: $Message.width() * - 1.2}, opts.speed, function() { $(this).detach(); // get rid of message from queue MessageBuffer.shift(); // Try to show the next message if(MessageBuffer.length > 0) { TryShowMessage(MessageBuffer[0]); } } ); }); $Universe.on("GameOver", function(e, opts) { $(".action").attr("disabled", true).addClass("ui-state-disabled"); // Stop the game, but how? }); }); </script> </head> <body> <div id="Universe"> <div style="position:block;min-height:2em;"> <div style="position:absolute;"> <button id="OneRound" class="action">Play One Round</button> <button id="AllRounds" class="action">Play All</button> <button id="PushTest" class="action">Push Test Cards for Tie</button> <button id="PushAceTwoTest" class="action">Push Ace Two Cards for Tie</button> <button id="SetupRoyalDefeat" class="action">Royal Defeat Decks</button> <button id="SetupShortGame" class="action">Short Game</button> <button id="SetupArmisticeRank" class="action">Armistice Rank</button> <button id="SetupArmisticeCount" class="action">Armistice Count</button> </div> </div> <div id="MessageWrap" style='width:100%;height:2em;'> <div id="Message"> </div> </div> <div id="playarea" class="" style="margin-top:2em;"> <div id="player0_area" class="area player p0"> <div id="player0_area_deck" class="p0 area deck cards stack"></div> <div id="player0_area_wins" class="p0 area wins cards stack"></div> </div> <div id="battleground" class="area battleground"> <div id="battleground_p0" class="p0 area battle cards stack"></div> <div id="battleground_p1" class="p1 area battle cards stack"></div> </div> <div id="player1_area" class="area player p1"> <div id="player1_area_deck" class="p1 area deck cards pile"></div> <div id="player1_area_wins" class="p1 area wins cards stack"></div> </div> </div> </div> </body>
-
War.css
body { overflow-x:hidden; background-color:#32CD32; } .area, .card { max-height:180px; height:100%; width:120px; display:block; border:1px solid black; border-radius:5px; } .area { background-color: grey; } .card { background-color:white; z-index:50000; font-size:1.1em; } .card.Hearts, .card.Diamonds { color: red !important; } .card.Clubs, .card.Spades { color:black; } .card div { background-color:white; } .card.facedown { background-color:blue; } #playarea { position:relative; width:90%; margin-left:auto; margin-right:auto; } #battleground { background-color:orange; width:500px; margin-left:auto; margin-right:auto; position:relative; } .area.player, .area.stack { position:absolute; top:0px; } .area.player { min-width:360px; } .area.player .pile, .area.player .stack, .battle { position:absolute; } .area.player.p0 .deck { left:0px; z-index:500; } .area.player.p0 .wins { right:0px; z-index:500; } .area.player.p1 { right:0px; } .area.player.p1 .deck { position:absolute; right:0px !important; z-index:500; background-color:purple; } .area.player.p1 .wins { left:0px; z-index:501; background-color:purple; } .battleground .battle.p1 { position:absolute; right:0px; } .card.latest { background-color:yellow !important; } /* Cards stacked so you can see the one underneath */ .stack .card { position:relative; margin-top:-150px; z-index:999; } .stack .card:first-child { margin-top:0px; } /* Cards piled so you can't see what is underneath */ .pile .card { position:relative; margin-top:-100%; z-index:999; } .pile .card:first-of-type { margin-top:0px; } #Message { overflow:hidden; position:relative; min-height:1.5em; width:30%; margin-left:auto; margin-right:auto; border:1px solid black; background-color:white; border-radius:5px; text-align:center; font-family:arial; padding:0.5em; } .message-text { background-color:white; }
-
I'll remember that if i ever make a joke on purpose
that sounds like an admission that everything that looks like a joke from you is a whoosh...
-
@accalia said:
I'll remember that if i ever make a joke on purpose
that sounds like an admission that everything that looks like a joke from you is a whoosh...
-
Version 3.III.Three.piggy
- Fixed Royal Capture victory condition by hacking in GameOver attribute to Universe
- Royal Capture shows cards to prove it (but that is also broken)
- No change in UI. Same level of as before
- Added WWIII endgame-- the third chained WAR will trigger a climactic showdown that determines the winner of the game. It doesn't work quite right, and may freeze your browser. Push the test button at your own risk.
- Need to add better "MoveCard" code, so that data can be passed (array, card object) instead of UI elements (UI of deck, card UI). Need to decide exactly how I want data layer and UI layer to interact. I'd like all commands and shit to be handled at the data/object layer, which then bubble up events for the UI to handle. That way the data layer can act independently of the UI layer (for bots and replays).
- Next next goal will be codifying the rules engine, so that the game can be defined as a script that grafts onto the engine.
Teh Codez to follow
-
War.html (part 1)
<html> <head> <link href="http://sevenseventeen.ca/war.css" rel="stylesheet"></link> <script src="http://sevenseventeen.ca/wp-includes/js/jquery/jquery.js" type="text/javascript"></script> <script src="http://sevenseventeen.ca/wp-includes/js/jquery/ui/jquery-ui.js" type="text/javascript"></script> <link href="http://sevenseventeen.ca/wp-includes/js/jquery/ui/jquery-ui.min.css" rel="stylesheet"></link> <script type="text/javascript"> // Assign to deck arrays function TotalValue() { var t = 0; for(var idx = 0; idx < this.length; idx++) { t += this[idx].Value; } return t; } function GetNewDeck() { var ret = []; ret.TotalValue = TotalValue; return ret; } var SpeedFactor = 0.6; var $Universe = null; var decks = []; var wins = []; var winner = 0; var battle = []; var suites = ["Hearts", "Spades", "Diamonds", "Clubs"]; var glyphs = ["♥", "♠", "⋄", "♣"]; var ranks = {"Two" : 2, "Three" : 3, "Four" : 4, "Five" : 5, "Six" : 6, "Seven" : 7, "Eight" : 8, "Nine" : 9, "Ten" : 10, "Jack" : 11, "Queen" : 12, "King" : 13, "Ace": 14}; var shorts = ["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"]; var GameDeck = GetNewDeck(); for(s = 0; s < suites.length; s++) { suit = suites[s]; var idx = 0; for(var rank in ranks) { card = {"Suit" : suit, "Rank" : rank, "Value" : ranks[rank], "Glyph" : glyphs[s], "Short" : shorts[idx]}; GameDeck.push(card); idx++; } } function CreateCardElement(card) { var $card = $("<div></div>"); $card.addClass("card"); $card.addClass(card.Suit); var $text = $("<div></div>"); if(card.Glyph != null) { $card.html(card.Short + " " + card.Glyph); } else { $card.html(card.Rank + " " + card.Suit); } //$card.append($text); $card.data("card", card); return $card; } // UI functions // TODO put visibility of card into card properties // player = 0 index id of player function SortByValue(a,b) { var c1=$(a).data("card").Value; var c2=$(b).data("card").Value; var ret = c1 < c2 ? 1 : c1 > c2 ? -1 : 0; return ret; } // Collect all ventured cards into the winners Win pile function CollectWinnings(player) { var winnings = $(".battle .card"); var winpile = $("#player"+player+"_area_wins"); var $Universe = $("#Universe"); winpile.find(".card").removeClass("latest"); winnings.addClass("latest"); $Universe.on("MoveCardsCompleted", OnMoveCardsCompleted_SortWinnings); $Universe.on("MoveCardsCompleted", OnMoveCardsCompleted_ToWinPile); $(".battle").each(function() { var opts = {}; opts.MoveAllCards = true; opts.from = $(this); opts.to = winpile; opts.prepend = true; $Universe.trigger("MoveCard", opts); }); } function OnMoveCardsCompleted_SortWinnings(e, opts) { var $Universe = $("#Universe"); $Universe.off("MoveCardsCompleted", OnMoveCardsCompleted_SortWinnings); for(var i = 0; i <= 1; i++) { var cards = $(".wins").eq(i).find(".card.latest"); if(cards.length > 0) { cards .detach() .sort(SortByValue) .prependTo($(".wins").eq(i)); } } } // Empty Win Pile UI function ClearWinsPile(player) { var winpile = document.getElementById("player"+player+"_area_wins"); while(winpile.childNodes.length > 0) { winpile.removeChild(winpile.firstChild); } } // face down deck. Clear anything in there, put face down card, and add counter function RefreshDeck(player) { var deck = document.getElementById("player"+player+"_area_deck"); while(deck.childNodes.length > 0) { deck.removeChild(deck.firstChild); } var card = document.createElement("div"); card.className = "area facedown"; deck.appendChild(card); var cnt = document.createElement("div"); card.appendChild(cnt); cnt.textContent = decks[player].length; } // End UI functions function shuffle(array) { var currentIndex = array.length, temporaryValue, randomIndex ; // While there remain elements to shuffle... while (0 !== currentIndex) { // Pick a remaining element... randomIndex = Math.floor(Math.random() * currentIndex); currentIndex -= 1; // And swap it with the current element. temporaryValue = array[currentIndex]; array[currentIndex] = array[randomIndex]; array[randomIndex] = temporaryValue; } return array; } // draw one card from deck IDX, return that card or null // when a deck runs out, reshuffle win pile into deck // if no cards remain in deck or win pile, returns null function draw(idx) { if(decks[idx].length == 0) { while(wins[idx].length > 0) { card = wins[idx].shift(); decks[idx].push(card); ClearWinsPile(idx); } decks[idx] == shuffle(decks[idx]); } card = decks[idx].shift(); RefreshDeck(idx); return card; } // end function draw function CardsOwned(player) { return decks[player].length + wins[player].length; } function CheckCurrentBattleWinner(bottom) { var winner = -1; bottom = (bottom == null ? false : bottom); // Check for the winner by comparing the top cards of the battleground to each other for(var i = 0; i <=1; i++) { up = i % 2; down = (i+1) % 2; if(battle[up][bottom ? battle[up].length - 1 : 0].Value > battle[down][bottom ? battle[down].length - 1 : 0].Value) { winner = up; } } return winner; } function PlayOneRound(NumberOfCards) { var PlayerDepleted = false; var DepletedPlayer = -1; for(var i=0; i<=1; i++) { if(CardsOwned(i) == 0) { PlayerDepleted = true; DepletedPlayer = i; } } if(PlayerDepleted) { var opts = {}; opts.message = "Player " + (DepletedPlayer+1) + " cannot commit to war. Checking for armistice."; opts.delay = 5000; $Universe.trigger("ShowMessage", opts); var card; $Universe.on("MoveCardsCompleted", OnMoveCardsCompleted_Armistice); // Move all cards onto the Battleground for final reckoning for(var i=0; i<=1; i++) { var fromui = $(".deck").eq(i); var toui = $(".battle").eq(i); card = draw(i); while(card != null) { var cardui = CreateCardElement(card); fromui.append(cardui); var opts = {}; opts.from = fromui; opts.to = toui; opts.prepend = true; opts.cardui = cardui; $Universe.trigger("MoveCard", opts); card = draw(i); } } return; // else if } // END PlayerDepleted // When we are done moving cards from the decks to the battleground, initiate the battle $Universe.on("MoveCardsCompleted", OnMoveCardsCompleted_ToBattleground); // Only venture as many cards as any one player has for(var i=0; i<=1; i++) { if(CardsOwned(i) < NumberOfCards) { var mopts = "Player " + (i+1) + " only has " + NumberOfCards + " cards"; $Universe.trigger("ShowMessage", mopts); NumberOfCards = CardsOwned(i); } } // Draw cards. Create UI for them. Move them. for(var i = 0; i<=1; i++) { var fromui = $(".deck").eq(i); var toui = $(".battle").eq(i); for(var cnt = 0; cnt < NumberOfCards; cnt++) { var card = draw(i); var cardui = CreateCardElement(card); fromui.append(cardui); var opts = {}; opts.from = fromui; opts.to = toui; opts.prepend = true; opts.cardui = cardui; //opts.MoveAllCards = true; $Universe.trigger("MoveCard", opts); } } } function OnMoveCardsCompleted_Armistice(e, opts) { var $Universe = $("#Universe"); $Universe.off("MoveCardsCompleted", OnMoveCardsCompleted_ToBattleground); // Check for alt victory conditions // there is a player who cannot war no more. The only way to resolve this is // First, who has the most rank values. // If still tied, who has the most cards. // If STILL tied, then both players are exactly where they were when they started. Reshuffle everything and start again. var winner = -1; // tie var gopts = {}; // total up the values of the cards in the decks totals = []; totals[0] = 0; totals[1] = 0; for(var i = 0; i <=1; i++) { totals[i] = decks[i].TotalValue() + battle[i].TotalValue() + wins[i].TotalValue(); } // compare totals for(var i = 0; i <=1; i++) { up = i % 2; down = (i+1) % 2; if(totals[up] > totals[down]) { winner = up; gopts.winner = winner; gopts.message = totals[i] + " points in ranks"; } } if(winner < 0) { var mopts = {}; mopts.message = "Tied in rank. Checking number of high cards"; $Universe.trigger("ShowMessage", mopts); // it is still a tie because both players have the same value of cards // go by number of cards for(var i = 0; i <=1; i++) { up = i % 2; down = (i+1) % 2; // having fewer cards is better, because you captured more of the high cards if(battle[up].length < battle[down].length) { winner = up; gopts.winner = winner; gopts.message = " has " + battle[up].length + " cards"; } } } if(winner < 0) { var mopts = {}; mopts.message = "Still tied. Starting over."; $Universe.trigger("ShowMessage", mopts); $Universe.on("MoveCardsCompleted", OnMoveCardsCompleted_StartNewRound); for(var i=0; i<=1; i++) { var fromui = $(".battle").eq(i); var toui = $(".wins").eq(i); var opts = {}; opts.MoveAllCards = true; opts.from = formui; opts.to = toui; opts.prepend = true; $Universe.trigger("MoveCard", opts); } } // restart game else { // trigger game over var opts = {}; opts.keep = true; opts.message = "Player " + (winner + 1) + " wins! " + gopts.message; $Universe.trigger("ShowMessage", opts); $Universe.trigger("GameOver"); } } function OnMoveCardsCompleted_StartNewRound(e, opts) { var ropts = {}; ropts.NumberOfCards = 1; $Universe.trigger("PlayOneRound", ropts); } function OnMoveCardsCompleted_ToBattleground(e, opts) { // Stop listening // Probably better to do something like adding this listener to the UI target itself rather than the Universe var $Universe = $("#Universe"); $Universe.off("MoveCardsCompleted", OnMoveCardsCompleted_ToBattleground); var winner = CheckCurrentBattleWinner(); if(winner < 0) { var wardepth = $Universe.data("wardepth"); if(wardepth == null) { wardepth = 0; } wardepth++; $Universe.data("wardepth", wardepth); // Check for MEGA WAR!!! var card = battle[0][battle[0].length - 1]; var mopts = {}; var opts = {}; if(wardepth == 3) { // this is going to be the big one mopts.message = "WORLD WAR III!!!"; opts.NumberOfCards = 3; } else if(card.Value == 14) { opts.NumberOfCards = 7; mopts.message = "MEGA W-A-R!!!!!"; } else { mopts.message = "W-A-R!"; opts.NumberOfCards = 4; } $Universe.trigger("ShowMessage", mopts); /* DO WAR */ Pulse($(".battle .card"), "ui-state-error", 3, PlayOneRound, opts.NumberOfCards); } else { /* Check for extra points */ var opts = {}; opts.winner = winner; var $Universe = $("#Universe"); $Universe.on("OnPostCheckWinner", OnPostCheckWinner_ExtraCards); $Universe.trigger("OnPostCheckWinner", opts); // TODO: Need to pass this better $Universe.data("wardepth", 0); } } // After winner is determined, check for other things function OnPostCheckWinner_ExtraCards(e, opts) { var $Universe = $("#Universe"); $Universe.off("OnPostCheckWinner", OnPostCheckWinner_ExtraCards); $Universe.on("MoveCardsCompleted", MoveCardsCompleted_CollectWinnings); var winner = opts.winner; var loser = ((winner + 1) % 2); var special = false; if(battle[winner].length > 0 && battle[loser].length > 0) { // wwiii // check for wwiii // if WWIII, winner takes all var WarDepth = $Universe.data("wardepth"); if(WarDepth == null) { WarDepth = 0; } if(WarDepth >= 3) { // TODO: Move everything to winner's win pile special = true; var moves = []; card = draw(loser); while(card != null) { var mopts = {}; mopts.cardui = CreateCardElement(card); mopts.from = $(".deck").eq(loser); mopts.to = $(".battle").eq(loser); mopts.speed = "fast"; $Universe.trigger("MoveCard", mopts); } } if( ! special) { var WinningCard = battle[winner][battle[winner].length - 1]; var LosingCard = battle[loser][battle[loser].length - 1]; var newOpts = {}; if(WinningCard.Value == 14 && LosingCard.Value == 2) { var mopts = {message: "Crushing Defeat!"}; $Universe.trigger("ShowMessage", mopts); card = LosingCard; while(card != null && card.Value == 2) { // If you draw another 2, steal that as well. card = draw(loser); newOpts.cardui = CreateCardElement(card); newOpts.from = $(".deck").eq(loser); newOpts.to = $(".battle").eq(loser); newOpts.winner = winner; newOpts.loser = loser; $Universe.trigger("MoveCard", newOpts); } special = true; } } } if(! special) { MoveCardsCompleted_CollectWinnings(null, opts); } } // Now collect winnings function MoveCardsCompleted_CollectWinnings(e, opts) { var $Universe = $("#Universe"); $Universe.off("MoveCardsCompleted", MoveCardsCompleted_CollectWinnings); var winner = opts.winner; Pulse($(".battle").eq(winner).find(".card"), "ui-state-default", 1, CollectWinnings, winner); } function Pulse(elms, cssClass, numPulses, OnComplete, opts) { var $Universe = $("#Universe"); var anim = 0; // flash the cards as a warning $(elms) .addClass(cssClass, { duration:250 * SpeedFactor, complete: function() { anim++; $(this).removeClass(cssClass, { duration:250 * SpeedFactor, complete:function() { anim--; if(anim == 0) { if(numPulses <= 0) { OnComplete(opts); } else { numPulses = numPulses - 1; Pulse(elms, cssClass, numPulses, OnComplete, opts); } } } }) } }); } function OnMoveCardsCompleted_ToWinPile(e, opts) { $Universe.off("MoveCardsCompleted", OnMoveCardsCompleted_ToWinPile); $Universe.trigger("OnAfterPlayOneRound", opts); } function SetupBoard() { $(".cards").each(function(e) { var $this = $(this); $this.data("cards", GetNewDeck()); }); } function SetUpNewGame(numPlayersZeroIndex) { GameDeck = shuffle(GameDeck); for(var i = 0; i<= numPlayersZeroIndex; i++) { decks[i] = GetNewDeck(); $("#player"+i+"_area_deck").data("cards", decks[i]); wins[i] = GetNewDeck(); $("#player"+i+"_area_wins").data("cards", wins[i]); battle[i] = GetNewDeck(); $("#battleground_p" + i).data("cards", battle[i]); } for(var i = 0; i < GameDeck.length; i++) { decks[i%(numPlayersZeroIndex + 1)].push(GameDeck[i]); } // set up deck UI for(var i = 0; i<= numPlayersZeroIndex; i++) { ClearWinsPile(i); RefreshDeck(i); } } </script>
-
war.html part 2
<script type="text/javascript"> // jquery sheeeeeet $(document).ready(function() { $(".action").removeClass("ui-state-disabled").attr("disabled", false); SetupBoard(); SetUpNewGame(1); $Universe = $("#Universe"); $Universe.data("cards_moving", 0); $("#OneRound").click(function(e) { var opts = {}; opts.NumberOfCards = 1; $Universe.trigger("PlayOneRound", opts); }); $("#AllRounds").click(function(e) { $("#Universe").on("OnAfterPlayOneRound", OnAfterPlayOneRound_AllRounds); var opts = {}; opts.NumberOfCards = 1; $Universe.trigger("PlayOneRound", opts); }); $("#PushTest").click(function(e) { for(var i=0;i<=1;i++) { var card = {}; card.Value = 15; card.Suit = "Hearts"; card.Rank = "Test"; decks[i].unshift(card); } }); $("#PushAceTwoTest").click(function(e) { var card = {}; card.Value = 14; card.Suit = "Hearts"; card.Rank = "Ace"; decks[0].unshift(card); card = {}; card.Value = 2; card.Suit = "Hearts"; card.Rank = "Two"; decks[1].unshift(card); RefreshDeck(0); RefreshDeck(1); }); $("#SetupShortGame").click(function(e) { for(var i=0;i<=1;i++) { while(decks[i].length > 1) { decks[i].shift(); } RefreshDeck(i); } }); $("#SetupWWIII").click(function(e) { var card; var suit; for(var i=0;i<=1;i++) { decks[i] = GetNewDeck(); for(var s=0; s<suites.length; s++) { var idx = 0; for(var rank in ranks) { card = {"Suit" : suites[s], "Rank" : rank, "Value" : ranks[rank], "Glyph" : glyphs[s], "Short" : shorts[idx]}; if(i == 0 || (i == 1 && idx != 12)) { decks[i].push(card); } idx++; } RefreshDeck(i); } } }); $("#SetupArmisticeRank").click(function(e) { var card; var suit; for(var i=0;i<=1;i++) { decks[i] = GetNewDeck(); var idx = 0; for(var rank in ranks) { card = {"Suit" : suites[0], "Rank" : rank, "Value" : ranks[rank], "Glyph" : glyphs[0], "Short" : shorts[idx]}; if(idx < 7 && ( i==0 || (i==1 && idx < 2))) { decks[i].push(card); } idx++; } RefreshDeck(i); } }); $("#SetupArmisticeCount").click(function(e) { var card; var suit; var lastcard; for(var i=0;i<=1;i++) { decks[i] = GetNewDeck(); var idx = 0; for(var rank in ranks) { card = {"Suit" : suites[0], "Rank" : rank, "Value" : ranks[rank], "Glyph" : glyphs[0], "Short" : shorts[idx]}; if(idx == 0) { lastcard = {"Suit" : suites[0], "Rank" : rank, "Value" : ranks[rank], "Glyph" : glyphs[0], "Short" : shorts[idx]}; // deck 1 gets 3 2s, deck 2 gets a 2 and a 4 decks[i].push(card); if(i == 0) { card = {"Suit" : suites[0], "Rank" : rank, "Value" : ranks[rank], "Glyph" : glyphs[0], "Short" : shorts[idx]}; decks[i].push(card); card = {"Suit" : suites[0], "Rank" : rank, "Value" : ranks[rank], "Glyph" : glyphs[0], "Short" : shorts[idx]}; decks[i].push(card); } } else if (idx == 2 && i == 1) { // deck 2 gets one 4 decks[i].push(card); } idx++; } decks[i].push(lastcard); RefreshDeck(i); } }); $("#SetupRoyalDefeat").click(function(e) { decks[0] = GetNewDeck(); decks[1] = GetNewDeck(); var card; var suit; var lastcard0 = null; var lastcard1 = null; for(var s = 0; s < suites.length; s++) { suit = suites[s]; var idx = 0; for(var rank in ranks) { if(ranks[rank] >= 11 && ranks[rank] <= 14) { card = {"Suit" : suit, "Rank" : rank, "Value" : ranks[rank], "Glyph" : glyphs[s], "Short" : shorts[idx]}; if(s == 0 && ranks[rank] == 11) { // deck 1 will get the Jh lastcard1 = card; } else if (s== 0 && ranks[rank] == 14) { //deck 0 will get the Ah lastcard0 = card; } else { decks[0].push(card); } } idx++; } } for(var s = 0; s < suites.length; s++) { suit = suites[s]; var idx = 0; for(var rank in ranks) { if(ranks[rank] < 11) { card = {"Suit" : suit, "Rank" : rank, "Value" : ranks[rank], "Glyph" : glyphs[s], "Short" : shorts[idx]}; decks[1].push(card); } idx++; } } // now push the J and A onto the decks decks[0].unshift(lastcard0); decks[1].unshift(lastcard1); RefreshDeck(0); RefreshDeck(1); }); }); function OnAfterPlayOneRound_AllRounds() { if(CardsOwned(0) > 0 && CardsOwned(1) > 0) { var opts = {}; opts.NumberOfCards = 1; $Universe.trigger("PlayOneRound", opts); } } // Check for victory conditions function OnAfterPlayOneRound_CheckVictory(e, opts) { // If one player is out of cards, the other player automagically wins // TODO: Also create a wordpress style call stack instead of events? var winner = -1; var winMessage = ""; for(i=1; i<=1; i++) { // todo: show message without clearing if(CardsOwned(i) == 0) { winner = ((i + 1) % 2); winMessage = "Complete Domination!"; } } if(winner == -1) { } if(winner == -1) { for(i=0; i<=1; i++) { // Check to see if anyone has all royal families (J-K) var RoyalCount = 0; var card; for(var idx = 0; idx < decks[i].length; idx++) { card = decks[i][idx]; if(card.Value >= 11 && card.Value <= 13) { RoyalCount = RoyalCount + 1; } } for(var idx = 0; idx < wins[i].length; idx++) { card = wins[i][idx]; if(card.Value >= 11 && card.Value <= 13) { RoyalCount = RoyalCount + 1; } } if(RoyalCount == 12) { winner = i; winMessage = "Royal Capture"; var moves = []; for(var s = 0; s<suites.length; s++) { var suit = suites[s]; for(var val = 11; val <= 13; val++) { // Move all cards to the win pile to show them off for(var idx = 0; idx < decks[winner].length; idx++) { card = decks[winner][idx]; if(card.Value == val && card.Suit == suit) { //card = decks[winner].splice(idx, 1)[0]; var opts = {}; opts.cardui = CreateCardElement(card); opts.from = $(".deck").eq(winner); opts.to = $(".battle").eq(winner); moves.push(opts); idx = decks[winner].length; } } for(var idx = 0; idx < wins[winner].length; idx++) { card = wins[winner][idx]; if(card.Value == val && card.Suit == suit) { var opts = {}; opts.cardui = $(".wins").eq(winner).find(".card").eq(idx); opts.cardui.removeClass("latest"); opts.from = $(".wins").eq(winner); opts.to = $(".battle").eq(winner); moves.push(opts); idx = wins[winner].length; } } } } // do the moves for(var idx = 0; idx < moves.length; idx++) { $Universe.trigger("MoveCard", moves[idx]); } for(var i=0; i<=1; i++) { RefreshDeck(i); } } } } if (winner >= 0) { var opts = {}; opts.keep = true; opts.message = "Player " + (winner + 1) + " wins! " + winMessage $Universe.trigger("ShowMessage", opts); $Universe.trigger("GameOver"); } } // Universe handlers $(document).ready(function() { $Universe.on("OnAfterPlayOneRound", OnAfterPlayOneRound_CheckVictory); $Universe.on("PlayOneRound", function(e, opts) { if(! $Universe.GameOver) { var defaults = {}; defaults.NumberOfCards = 1; $.merge(defaults, opts); // A round has been triggered. Play it, then call On Complete $Universe.trigger("OnBeforePlayOneRound", e); var NumberOfCards = opts.NumberOfCards; PlayOneRound(NumberOfCards); } }); // default round actions $Universe.on("OnBeforePlayOneRound", function(e) { // default action: disable action things $(".action").addClass("ui-state-disabled"); }); $Universe.on("OnAfterPlayOneRound", function(e) { // restore action buttons $(".action").removeClass("ui-state-disabled"); }); /* player: idx, card: card, from: decks[idx], to: battle[idx], facedown_from: false, facedown_to: true */ $Universe.on("MoveCard", function(e, opts) { var defaults = {MoveAllCards : false, speed:"slow"}; $.merge(opts, defaults); // get the card from the target // expose it on the target // animate it to the other target var $card = $(opts.cardui); var $FromUI = $(opts.from); var $ToUI = $(opts.to); var $LastCard = $FromUI.find(".card:last"); if(opts.MoveAllCards) { if($LastCard.length > 0) { $card = $LastCard; } } var top = $FromUI.offset().top; var left = $FromUI.offset().left; var cards = $FromUI.data("cards"); // maybe we can also find by card object? if(opts.card != null) { $FromUI.find(".cards").each(function() { var $this = $(this); if($this.data("card") == opts.card) { $card = $this; opts.cardui = $this; } }); } var card = $card.data("card"); // remove the card from the target UI, if it exists if(cards != null && cards.indexOf(card) >= 0) { cards.splice(cards.indexOf(card), 1); } $card .detach() .appendTo("body") .css("position", "absolute") .css("top", top) .css("left", left) .animate ( { left:$ToUI.offset().left, top:$ToUI.offset().top }, opts.speed, function() { var newOpts = {}; $.extend(newOpts, opts); newOpts.cardui = $card; $Universe.trigger("MoveCardComplete", newOpts); if(opts.MoveAllCards && $FromUI.find(".card").length > 0) { $Universe.trigger("MoveCard", opts); } } ); }); $Universe.on("MoveCardComplete", function(e, opts) { var $card = $(opts.cardui); var $FromUI = $(opts.from); var $ToUI = $(opts.to); var card = $card.data("card"); var cards = $ToUI.data("cards"); if(opts.prepend) { $card.prependTo($ToUI); cards.unshift(card); } else { $card.appendTo($ToUI); cards.push(card); } $card.css("position", "static"); }); // Card in motion tracking $Universe.on("MoveCard", function(e, opts) { $Universe.data("cards_moving", $Universe.data("cards_moving") + 1); }); $Universe.on("MoveCardComplete", function(e, opts) { $Universe.data("cards_moving", $Universe.data("cards_moving") - 1); // I have a feeling there's a better way to do this-- push all card moves onto a stack, then raise a Move Stack ready-- then raise a Move Stack Complete // Next iteration it is. I'll live with the race condition for now. if($Universe.data("cards_moving") == 0) { $Universe.trigger("MoveCardsCompleted", opts); } }); var MessageBuffer = []; var MessageMutex = null; $Universe.on("ShowMessage", function(e, opts) { // Put message into stack MessageBuffer.push(opts); // Try to show the message TryShowMessage(opts); }); function TryShowMessage(opts) { // if my message is the first one, show it // otherwise HideMessage will be responsible for showing the next one if(MessageBuffer.length > 0 && MessageBuffer[0] == opts) { // remove from buffer var opts = MessageBuffer[0]; var defaults = {delay:2000, speed:"fast"}; $.extend(opts, defaults); if(opts.message != null) { var Message = opts.message; var $Message = $("#Message"); var $MessageText = $("<div></div>"); $MessageText.text(Message); $MessageText.addClass("message-text"); $MessageText.css("position", "absolute"); $MessageText.css("left", $Message.width()); $Message.append($MessageText); $MessageText.width($Message.width()) $MessageText.animate ( {left: 0}, opts.speed, function() { if(! opts.keep) { var hopts = {}; $.extend(hopts, opts); hopts.ui = $(this); setTimeout(function(){$Universe.trigger("HideMessage", hopts)}, opts.delay); } } ); } } } // try show message $Universe.on("HideMessage", function(e, opts) { var defaults = {delay:2000, speed:"fast"}; $.extend(opts, defaults); var $ui = opts.ui; var $Message = $("#Message"); $ui.animate ( {left: $Message.width() * - 1.2}, opts.speed, function() { $(this).detach(); // get rid of message from queue MessageBuffer.shift(); // Try to show the next message if(MessageBuffer.length > 0) { TryShowMessage(MessageBuffer[0]); } } ); }); $Universe.on("GameOver", function(e, opts) { $(".action").attr("disabled", true).addClass("ui-state-disabled"); $Universe.GameOver = true; // Stop the game, but how? }); }); </script> </head> <body> <div id="Universe"> <div style="position:block;min-height:2em;"> <div style="position:absolute;"> <button id="OneRound" class="action">Play One Round</button> <button id="AllRounds" class="action">Play All</button> <button id="PushTest" class="action">Push Test Cards for Tie</button> <button id="PushAceTwoTest" class="action">Push Ace Two Cards for Tie</button> <button id="SetupRoyalDefeat" class="action">Royal Defeat Decks</button> <button id="SetupShortGame" class="action">Short Game</button> <button id="SetupArmisticeRank" class="action">Armistice Rank</button> <button id="SetupArmisticeCount" class="action">Armistice Count</button> <button id="SetupWWIII" class="action">Setup WWIII</button> </div> </div> <div id="MessageWrap" style='width:100%;height:2em;'> <div id="Message"> </div> </div> <div id="playarea" class="" style="margin-top:2em;"> <div id="player0_area" class="area player p0"> <div id="player0_area_deck" class="p0 area deck cards stack"></div> <div id="player0_area_wins" class="p0 area wins cards stack"></div> </div> <div id="battleground" class="area battleground"> <div id="battleground_p0" class="p0 area battle cards stack"></div> <div id="battleground_p1" class="p1 area battle cards stack"></div> </div> <div id="player1_area" class="area player p1"> <div id="player1_area_deck" class="p1 area deck cards pile"></div> <div id="player1_area_wins" class="p1 area wins cards stack"></div> </div> </div> </div> </body>