/*****
*
* Two-Player Memory Match
* Version: 1.0
* Last Revision: 04.09.2007
* steve@slayeroffice.com
*
* Also uses the WIM API, documented here:
* http://developer.aim.com/web-aim
*
******/
function dummy(){};
var d = document;
var mm = {
cap:"550e8400e29b41d4a716446655440000",
invitationTimeout:10000,
inGame:false,
opponent:null,
dataIMGranted:false,
init: function() {
mm.ui.createDeck();
mm.ui.createUI();
mm.ui.dealDeck();
AIM.params.callbacks.listener.dataIM = ["mm.com.acceptIncomingData"];
AIM.params.callbacks.sendDataIM = ["mm.com.acceptDataIM"];
AIM.params.callbacks.listener.buddylist = ["dummy"];
AIM.params.DEBUG = false;
AIM.params.wimKey = "ih1lb685w1HENSGU";
AIM.params.assertCaps = mm.cap;
AIM.params.interestCaps = mm.cap;
AIM.core.subscriptions = "buddylist,dataIM";
AIM.transactions.getToken(AIM.core.subscriptions);
},
com: {
acceptIncomingData: function(json) {
switch(json.dataType) {
case "invite":
if(mm.inGame) {
AIM.transactions.sendDataIM(json.source.aimId,"Sorry, " + AIM.params.user + " is already engaged in a match.",mm.cap,"Deny");
return;
}
if(confirm(json.source.displayId + " has challenged you to a match. Accept?")) {
AIM.transactions.sendDataIM(json.source.aimId, AIM.params.user + " has accepted your invitation.",mm.cap,"Accept");
mm.opponent = json.source.aimId;
mm.ui.setTurn(0);
mm.ui.prepWork();
mm.ui.myTurn = true;
} else {
AIM.transactions.sendDataIM(json.source.aimId,"Sorry, " + AIM.params.user + " has declined your invitation.",mm.cap,"Deny");
alert("You have declined the invitation.");
}
break;
case "accept":
d.getElementById("msgBox").innerHTML = json.source.displayId + " has accepted your invitation!";
mm.opponent = json.source.aimId;
var i = mm.ui.cards.length;
var oString = "{oData={dType:'deck',data:[";
while(i-->0) {
oString+="{s:'" + mm.ui.cards[i].suit + "',v:'" + mm.ui.cards[i].value + "'},";
}
oString += "]}}";
oString = oString.replace(/,\]/,"]");
AIM.transactions.sendDataIM(json.source.aimId,oString,mm.cap,"Data");
mm.ui.myTurn = false;
mm.ui.setTurn(1);
mm.ui.prepWork();
break;
case "deny":
alert(json.dataIM);
d.getElementById("msgBox").innerHTML = "Send an invitation or wait for an invite.";
break;
case "end":
alert(mm.opponent + " has ended the session unexpectedly.");
mm.inGame = false;
location.reload();
break;
case "data":
var oData = eval(json.dataIM);
switch(oData.dType) {
// rebuild the deal so they are the same
case "deck":
var i = oData.data.length;
oData.data = oData.data.reverse();
while(i-->0) {
mm.ui.cards[i].suit = oData.data[i].s;
mm.ui.cards[i].value = oData.data[i].v;
}
mm.ui.deleteDeck();
mm.ui.dealDeck();
break;
case "chat":
var cContainer = d.getElementById("chatWindow");
var str = "" + json.source.displayId + ": " + oData.data + "
";
cContainer.innerHTML += str;
cContainer.scrollTop = cContainer.scrollHeight;
break;
case "move":
var oCard = mm.ui.getElementByXIndex(oData.data);
oCard.className = "card cardFace " + mm.ui.cards[oData.data].suit;
break;
case "turnOver":
if(oData.success) {
var fns = function() {
mm.ui.getElementByXIndex(oData.card1).style.display = "none";
mm.ui.getElementByXIndex(oData.card2).style.display = "none";
mm.ui.myTurn = false;
mm.ui.opAttempts++;
mm.ui.opMatches++;
mm.ui.setTurn(1);
d.getElementById("dataDisplay").innerHTML = mm.ui.showStats();
if(mm.ui.matches + mm.ui.opMatches == 26) mm.ui.endGame();
}
} else {
var fns = function() {
mm.ui.getElementByXIndex(oData.card1).className = "card cardBack";
mm.ui.getElementByXIndex(oData.card2).className = "card cardBack";
mm.ui.myTurn = true;
mm.ui.opAttempts++;
mm.ui.setTurn(0);
d.getElementById("dataDisplay").innerHTML = mm.ui.showStats();
}
}
setTimeout(fns,900);
break;
}
break;
}
},
acceptDataIM: function(json) {
switch(json.response.statusCode) {
case 200:
break;
case 450:
AIM.core.createAuthWindow(json.response.data.redirectURL + "?k=" + AIM.params.wimKey);
AIM.core.pendingTransaction = {
msg:AIM.core.AIMData[json.response.requestId].objData.data,
to:AIM.core.AIMData[json.response.requestId].objData.to,
type:"sendDataIM",
cap:AIM.core.AIMData[json.response.requestId].objData.cap,
dType:AIM.core.AIMData[json.response.requestId].objData.dType
}
break;
case 602:
alert("That user is not currently online.");
d.getElementById("msgBox").innerHTML = "Send an invitation or wait for an invite.";
break;
case 605:
alert("That user is not currently using the Memory Match client.");
d.getElementById("msgBox").innerHTML = "Send an invitation or wait for an invite.";
break;
default:
alert("Something unexpected occured. Error code is " + json.response.statusCode);
break;
}
},
sendInvite: function(oNew) {
if(oNew) {
var oSN = prompt("Enter the screen name of the person you'd like to send in invitation to:","");
} else {
var oSN = mm.opponent;
}
if(!oSN) return;
if(oSN.toLowerCase() == AIM.params.user.toLowerCase()) return alert("You can't play yourself!");
AIM.transactions.sendDataIM(oSN,"hello",mm.cap,"Invite");
d.getElementById("msgBox").innerHTML = "Invitation sent...waiting for response.";
var fn = function() {
alert("The invitation has timed out. Please try again or invite another player.");
d.getElementById("msgBox").innerHTML = "Send an invitation or wait for an invite.";
}
}
},
ui: {
attempts:0,
matches:0,
opAttempts:0,
opMatches:0,
canClick:true,
cards:[],
myTurn:false,
gameOver:true,
opClick:true,
clickData: {
firstClick:true,
clickValue:null,
clickIndex:null,
clickElement:null
},
firstClick:true,
firstClickValue:null,
showStats: function() {
return "" + AIM.params.user + "" + ": Attempts: " + mm.ui.attempts + " || Matches: " + mm.ui.matches + " || Accuracy: " + mm.ui.calculateAccuracy(1) + "%
" + mm.opponent + ": Attempts: " + mm.ui.opAttempts + " || Matches: " + mm.ui.opMatches + " || Accuracy: " + mm.ui.calculateAccuracy(0) + "%";
},
setTurn: function(who) {
if(who) {
d.getElementById("turn").className="theirTurn";
d.getElementById("turn").setAttribute("title","It is your opponent's turn.");
} else {
d.getElementById("turn").className="yourTurn";
d.getElementById("turn").setAttribute("title","It is your turn.");
}
},
prepWork: function() {
d.getElementById("dataDisplay").innerHTML = mm.ui.showStats();
d.getElementById("chatWindow").style.display = "block";
d.getElementById("chatInput").style.display = "block";
d.getElementById("msgBox").style.display = "none";
d.getElementById("turn").style.display = "block";
mm.inGame = true;
mm.ui.gameOver = false;
},
createDeck: function() {
var suits = ["spade","heart","club","diamond"];
var values = ["A","2","3","4","5","6","7","8","9","10","J","Q","K"];
var i = suits.length;
var k = 0;
while(i-->0) {
var j = values.length;
while(j-->0) {
mm.ui.cards[k] = {
suit:suits[i],
value:values[j],
clicked:0
}
k++;
}
}
fn = function() {return (Math.round(Math.random())-0.5); }
mm.ui.cards = mm.ui.cards.sort(fn);
},
deleteDeck: function() {
var oCards = AIM.util.getElementsByClassName(d.getElementById("mContainer"),"div","card");
var i = oCards.length
while(i-->0) oCards[i].parentNode.removeChild(oCards[i]);
},
createUI:function() {
var oAttempts = d.createElement("div");
oAttempts.setAttribute("id","dataDisplay");
d.getElementById("mContainer").appendChild(oAttempts);
var oMessage = d.createElement("div");
oMessage.innerHTML = "Send an invitation or wait for an invite.";
oMessage.setAttribute("id","msgBox");
d.getElementById("mContainer").appendChild(oMessage);
var oTurn = d.createElement("div");
oTurn.innerHTML = "";
oTurn.setAttribute("id","turn");
d.getElementById("mContainer").appendChild(oTurn);
var oChatWindow = d.createElement("div");
oChatWindow.setAttribute("id","chatWindow");
d.getElementById("mContainer").appendChild(oChatWindow);
var oChatInput = d.createElement("input");
oChatInput.setAttribute("id","chatInput");
oChatInput.setAttribute("type","text");
oChatInput.onkeyup = function(e) {
var keyCode = window.event?event.keyCode:e.keyCode;
if(keyCode == 13) {
var cContainer = d.getElementById("chatWindow");
cContainer.innerHTML += "" + AIM.params.user + ": " + this.value + "
";
cContainer.scrollTop = cContainer.scrollHeight;
AIM.transactions.sendDataIM(mm.opponent,"{nData={dType:'chat',data:'" + this.value + "'}}",mm.cap,"Data");
this.value = "";
}
}
d.getElementById("mContainer").appendChild(oChatInput);
},
dealDeck: function() {
var i = mm.ui.cards.length;
var oFrag = d.createDocumentFragment();
var x=5,y=5;
while(i-->0) {
var o = d.createElement("div");
o.xIndex = i;
o.className = "card cardBack";
o.style.top = y + "px";
o.style.left = x + "px";
o.onclick = function() {
if(!mm.ui.canClick || mm.ui.gameOver || !mm.ui.myTurn)return;
var oVal = mm.ui.cards[this.xIndex].value;
AIM.transactions.sendDataIM(mm.opponent,"{nData={dType:'move',data:" + this.xIndex + "}}",mm.cap,"Data");
this.className = "card cardFace " + mm.ui.cards[this.xIndex].suit;
var me = this;
if(mm.ui.clickData.firstClick) {
mm.ui.clickData.clickValue = oVal;
mm.ui.clickData.clickIndex = this.xIndex;
mm.ui.clickData.firstClick = false;
mm.ui.clickData.clickElement = this;
mm.ui.cards[this.xIndex].clicked++;
} else {
if(this.xIndex == mm.ui.clickData.clickIndex) return;
mm.ui.cards[this.xIndex].clicked++;
mm.ui.attempts++;
if(oVal == mm.ui.clickData.clickValue) {
var fn = function() {
me.style.display = "none";
mm.ui.clickData.clickElement.style.display = "none";
mm.ui.canClick = true;
mm.ui.matches++;
if(mm.ui.matches + mm.ui.opMatches == 26) mm.ui.endGame();
mm.ui.setTurn(0);
d.getElementById("dataDisplay").innerHTML =mm.ui.showStats();
}
var success = 1;
mm.ui.myTurn = true;
} else {
mm.ui.canClick = false;
var fn = function() {
me.className = "card cardBack";
mm.ui.clickData.clickElement.className = "card cardBack";
mm.ui.canClick = true;
mm.ui.setTurn(1);
d.getElementById("dataDisplay").innerHTML = mm.ui.showStats();
}
var success = 0;
mm.ui.myTurn = false;
}
AIM.transactions.sendDataIM(mm.opponent,"{nData={dType:'turnOver',success:" + success + ",card1:" + this.xIndex + ",card2:" + mm.ui.clickData.clickElement.xIndex + "}}",mm.cap,"Data");
setTimeout(fn,1000);
mm.ui.clickData.firstClick = true;
}
}
x+=40;
if(x>=512) {
x=5; y+=50;
}
o.innerHTML = mm.ui.cards[i].value;
oFrag.appendChild(o);
}
d.getElementById("mContainer").appendChild(oFrag);
},
replay: function(sameOp) {
mm.ui.deleteDeck();
mm.ui.createDeck();
mm.ui.dealDeck();
if(sameOp) {
mm.com.sendInvite(false);
} else {
mm.com.sendInvite(true);
}
},
calculateAccuracy: function(who) {
if(who) {
if(mm.ui.matches==0) {
return 0;
} else {
return Math.round((mm.ui.matches/mm.ui.attempts)*100);
}
} else {
if(mm.ui.opMatches == 0) {
return 0;
} else {
return Math.round((mm.ui.opMatches/mm.ui.opAttempts)*100);
}
}
},
getElementByXIndex: function(xIndex) {
var oCards = AIM.util.getElementsByClassName(d.getElementById("mContainer"),"div","card");
var i = oCards.length;
while(i-->0) if(oCards[i].xIndex == xIndex) return oCards[i];
return 0;
},
endGame: function() {
mm.inGame = false;
mm.ui.gameOver = true;
mm.ui.matches = 0; mm.ui.opMatches = 0;
mm.ui.attempts = 0; mm.ui.opAttempts = 0;
mm.ui.clickData.firstClick=true;
mm.ui.clickData.clickValue=null;
mm.ui.clickData.clickIndex=null;
mm.ui.clickData.clickElement=null;
mm.ui.firstClick=true,
mm.ui.firstClickValue=null,
d.getElementById("msgBox").innerHTML = "GAME OVER!
Play each other again?
Play Someone Else";
d.getElementById("msgBox").style.display = "block";
}
}
}
window.onload = mm.init;
window.onunload = function() {
if(mm.inGame) {
mm.inGame = false;
AIM.transactions.sendDataIM(mm.opponent,"bye",mm.cap,"End");
AIM.transactions.endSession();
}
}