script.js 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952
  1. // Solitaire for HTML5
  2. // tepaanan@gmail.com
  3. // Mouse pos
  4. var mousex=0, mousey=0;
  5. // Mouse click and card's upper left corner offset
  6. var xOff=0, yOff=0;
  7. // Mouse offset between moves
  8. var moveXAmount=0;
  9. var moveYAmount=0;
  10. // Card size
  11. var cardHeight=110;
  12. var cardWidth=75;
  13. var cardInitVal=0;
  14. // Canvas
  15. var canvas
  16. var ctx;
  17. var tmpCanvas;
  18. var tmpCtx;
  19. // Is mouse down
  20. var mouseDown=false;
  21. // For cards
  22. var activeCard=undefined;
  23. var cardLoadingIndex=0;
  24. var cardArray = new Array();
  25. var cardNameArray = new Array();
  26. var movingCardsDrawed = true;
  27. var generalGraphicsArray = new Array();
  28. var generalGraphicsLoadingIndex = 0;
  29. // Deck types
  30. var DeckType = {
  31. Foundation:1,
  32. Waste:2,
  33. Stock:3,
  34. Target:4
  35. };
  36. // Card lands
  37. var CardLand = {
  38. Club:1,
  39. Diamond:2,
  40. Heart:3,
  41. Spade:4
  42. };
  43. // For decks
  44. var deck1 = new DeckObject(DeckType.Foundation,0,0);
  45. var deck2 = new DeckObject(DeckType.Foundation,0,0);
  46. var deck3 = new DeckObject(DeckType.Foundation,0,0);
  47. var deck4 = new DeckObject(DeckType.Foundation,0,0);
  48. var deck5 = new DeckObject(DeckType.Foundation,0,0);
  49. var deck6 = new DeckObject(DeckType.Foundation,0,0);
  50. var deck7 = new DeckObject(DeckType.Foundation,0,0);
  51. var stock = new DeckObject(DeckType.Stock,0,0);
  52. var waste = new DeckObject(DeckType.Waste,0,0);
  53. var target1 = new DeckObject(DeckType.Target,0,0);
  54. var target2 = new DeckObject(DeckType.Target,0,0);
  55. var target3 = new DeckObject(DeckType.Target,0,0);
  56. var target4 = new DeckObject(DeckType.Target,0,0);
  57. // Background
  58. var background = new Image();
  59. var cardBackground = new Image();
  60. var deckBackground = new Image();
  61. // Loading graphics -message
  62. var message;
  63. // Window resize event
  64. var resizeTimer = undefined;
  65. var documentWidth = 0;
  66. var documentHeight = 0;
  67. /******************************************************************************
  68. * requestAnimFrame
  69. * http://www.html5canvastutorials.com/labs/html5-canvas-ultimate-flash-killer/
  70. */
  71. window.requestAnimFrame = (function(callback){
  72. return window.requestAnimationFrame ||
  73. window.webkitRequestAnimationFrame ||
  74. window.mozRequestAnimationFrame ||
  75. window.oRequestAnimationFrame ||
  76. window.msRequestAnimationFrame ||
  77. function(callback){
  78. window.setTimeout(callback, 1000 / 60);
  79. };
  80. })();
  81. /******************************************************************************
  82. * Card object
  83. * http://www.javascriptkit.com/javatutors/object2.shtml
  84. */
  85. function CardObject(id, x, y, img){
  86. // Properties
  87. this.id = id;
  88. this.land = 0;
  89. this.deckId = 0;
  90. this.isTurned = false;
  91. this.deckObject = undefined;
  92. this.x = x;
  93. this.y = y;
  94. this.oldX = x;
  95. this.oldY = y;
  96. this.img = img;
  97. this.topCard = undefined;
  98. this.isBlack = false;
  99. // Methods
  100. this.cancel = _CardObject_cancel;
  101. this.move = _CardObject_move;
  102. this.storePos = _CardObject_storePos;
  103. this.drawCard = _CardObject_drawCard;
  104. }
  105. function _CardObject_drawCard(ctx,drawAlsoTopCard) {
  106. // Draw this card
  107. if (this.isTurned) {
  108. ctx.drawImage(this.img,this.x,this.y,cardWidth,cardHeight);
  109. } else {
  110. ctx.drawImage(cardBackground,this.x,this.y,cardWidth,cardHeight);
  111. }
  112. // And also its top cards if needed
  113. if (drawAlsoTopCard && this.topCard) {
  114. this.topCard.drawCard(ctx,drawAlsoTopCard);
  115. }
  116. }
  117. function _CardObject_storePos(x,y) {
  118. this.x = x;
  119. this.y = y;
  120. this.oldX = x;
  121. this.oldY = y;
  122. }
  123. function _CardObject_move(x,y) {
  124. if (this.isTurned) {
  125. this.x = x;
  126. this.y = y;
  127. if (this.topCard) {
  128. this.topCard.move(x, y + cardHeight * 0.2);
  129. }
  130. }
  131. }
  132. function _CardObject_cancel() {
  133. this.x = this.oldX;
  134. this.y = this.oldY;
  135. if (this.topCard) {
  136. this.topCard.cancel();
  137. }
  138. }
  139. /******************************************************************************
  140. * Deck object
  141. */
  142. function DeckObject(id, x, y){
  143. // Properties
  144. this.id = id;
  145. this.x = x;
  146. this.y = y;
  147. this.cardArray = new Array();
  148. // Methods
  149. this.setPos = _DeckObject_setPos;
  150. this.addCard = _DeckObject_addCard;
  151. this.cardUnderMouse = _DeckObject_cardUnderMouse;
  152. this.deckUnderMouse = _DeckObject_deckUnderMouse;
  153. this.drawDeck = _DeckObject_drawDeck;
  154. this.removeTopCard = _DeckObject_removeTopCard;
  155. this.removeFromThisCard = _DeckObject_removeFromThisCard;
  156. }
  157. function _DeckObject_drawDeck(ctx) {
  158. for(var i=0 ; i < this.cardArray.length ; i++) {
  159. var card = this.cardArray[i];
  160. // Do not draw active card and its top cards
  161. if (card!=activeCard) {
  162. card.drawCard(ctx,false);
  163. } else {
  164. return;
  165. }
  166. }
  167. }
  168. function _DeckObject_setPos(x,y){
  169. this.x = x;
  170. this.y = y;
  171. }
  172. function _DeckObject_addCard(card){
  173. var yCap = cardHeight * 0.2;
  174. // Set new position for the card
  175. if (this.id == DeckType.Foundation) {
  176. card.storePos(this.x,this.y + yCap * this.cardArray.length);
  177. } else {
  178. card.storePos(this.x,this.y);
  179. }
  180. // Store new deck data into card
  181. card.deckId = this.id;
  182. card.deckObject = this;
  183. // Set new card as top card of previous top
  184. if(this.cardArray.length > 0) {
  185. this.cardArray[this.cardArray.length-1].topCard = card;
  186. }
  187. // Add new card into deck array
  188. this.cardArray.push(card);
  189. // Add top card into this deck
  190. if (card.topCard) {
  191. this.addCard(card.topCard);
  192. }
  193. }
  194. function _DeckObject_removeTopCard() {
  195. // Get top most card
  196. var card = this.cardArray.pop();
  197. // Reset old top card data
  198. if(this.cardArray.length > 0) {
  199. this.cardArray[this.cardArray.length-1].topCard = undefined;
  200. //this.cardArray[this.cardArray.length-1].isTurned = true;
  201. }
  202. return card;
  203. }
  204. function _DeckObject_removeFromThisCard(card) {
  205. // Remove all card from the deck starting from this card
  206. for(var i=0;i<this.cardArray.length;i++) {
  207. if (card != this.cardArray[this.cardArray.length-1]) {
  208. this.cardArray.pop();
  209. i--;
  210. } else if (card == this.cardArray[this.cardArray.length-1]) {
  211. this.cardArray.pop();
  212. if(this.cardArray.length > 0) {
  213. this.cardArray[this.cardArray.length-1].topCard = undefined;
  214. this.cardArray[this.cardArray.length-1].isTurned = true;
  215. }
  216. return;
  217. }
  218. }
  219. }
  220. function _DeckObject_cardUnderMouse(x,y){
  221. for(var i=this.cardArray.length-1;i>=0;i--) {
  222. var card = this.cardArray[i];
  223. if (card.x < x && card.y < y && card.x+cardWidth > x && card.y+cardHeight > y) {
  224. return card;
  225. }
  226. }
  227. return undefined;
  228. }
  229. function _DeckObject_deckUnderMouse(x,y) {
  230. var yCap = cardHeight * 0.2 * this.cardArray.length;
  231. if (this.id != DeckType.Foundation) {
  232. if (this.x < x && this.y < y && this.x+cardWidth > x && this.y+cardHeight > y) {
  233. return this;
  234. }
  235. } else {
  236. if (this.x < x && this.y < y && this.x+cardWidth > x && this.y+cardHeight+yCap > y) {
  237. return this;
  238. }
  239. }
  240. return undefined;
  241. }
  242. /******************************************************************************
  243. * Solitaire game logic
  244. * Check is the move allowed
  245. */
  246. function isAllowedMove(fromDeck, toDeck, card) {
  247. // Get card that will be under this new card
  248. var topOfCard = undefined;
  249. if (toDeck.cardArray.length > 0)
  250. topOfCard = toDeck.cardArray[toDeck.cardArray.length-1];
  251. // Check deck issues
  252. if (topOfCard && topOfCard.isTurned == false)
  253. return false;
  254. if (fromDeck.id != DeckType.Foundation && fromDeck.id != DeckType.Waste)
  255. return false;
  256. if (toDeck.id != DeckType.Foundation && toDeck.id != DeckType.Target)
  257. return false;
  258. // Card's decks must differ
  259. if (fromDeck == toDeck)
  260. return false;
  261. // Check card's issues
  262. if(toDeck.cardArray.length>0) {
  263. if (toDeck.id == DeckType.Foundation) {
  264. // Card can be top of one step greater card and different color
  265. // Card can not be same color
  266. if (card.land == topOfCard.land || topOfCard.id != card.id + 1 || card.isBlack == topOfCard.isBlack)
  267. return false;
  268. } else if (toDeck.id == DeckType.Target) {
  269. // Cards must be in ascending order and same suite in 2 target deck
  270. if (topOfCard.id + 1 != card.id || topOfCard.land != card.land)
  271. return false;
  272. }
  273. } else {
  274. // Moving top of empty deck
  275. // If there is no cards in the deck, then the first one must be King card in source decks 1
  276. if (toDeck.cardArray.length == 0 && card.id != 13 && toDeck.id == DeckType.Foundation)
  277. return false;
  278. // Ace card must be the first card in foundation
  279. if (toDeck.id == DeckType.Target && toDeck.cardArray.length == 0 && card.id != 1)
  280. return false;
  281. }
  282. return true;
  283. }
  284. /******************************************************************************
  285. * Clear canvas
  286. * TODO: Not in use
  287. */
  288. function clearCanvas(x,y,w,h) {
  289. // Whole canvas
  290. ctx.clearRect(0,0,canvas.width,canvas.height);
  291. }
  292. /******************************************************************************
  293. * Window resize event handling
  294. */
  295. function resizeEvent(event) {
  296. if(resizeTimer) {
  297. clearTimeout(resizeTimer);
  298. resizeTimer = undefined;
  299. }
  300. //resizeTimer = setTimeout("doResize()",300);
  301. }
  302. function doResize() {
  303. resizeTimer = undefined;
  304. // TODO: is that good solution?
  305. window.location.reload();
  306. }
  307. /******************************************************************************
  308. * Draw fast single card
  309. * Draw only dirty background behind the card
  310. * Draw active moving card on top of all others
  311. */
  312. function drawCardFast(cardToDraw, toContext, toBackground) {
  313. // Draw dirty background behind the card
  314. if (toBackground) {
  315. if (cardToDraw.topCard) {
  316. toContext.drawImage(toBackground, cardToDraw.x-moveXAmount, 0, cardWidth+moveXAmount*2, canvas.height,
  317. cardToDraw.x-moveXAmount, 0, cardWidth+moveXAmount*2, canvas.height);
  318. } else {
  319. toContext.drawImage(toBackground, cardToDraw.x-moveXAmount, cardToDraw.y-moveYAmount, cardWidth+moveXAmount*2, cardHeight+moveYAmount*2,
  320. cardToDraw.x-moveXAmount, cardToDraw.y-moveYAmount, cardWidth+moveXAmount*2, cardHeight+moveYAmount*2 );
  321. }
  322. }
  323. // Draw card and its parent cards
  324. cardToDraw.drawCard(toContext,true);
  325. }
  326. /******************************************************************************
  327. * Copy whole canvas and draw it once
  328. * Starts showing copy of the original canvas
  329. */
  330. function copyCanvasAndDraw() {
  331. // Draw target canvas to ready for copying it
  332. ctx.drawImage(background,0,0,documentWidth,documentHeight);
  333. // Target backgrounds
  334. var capX = (canvas.width - (7 * cardWidth)) / 8;
  335. ctx.drawImage(deckBackground,cardWidth*3+capX*4,capX,cardWidth,cardHeight);
  336. ctx.drawImage(deckBackground,cardWidth*4+capX*5,capX,cardWidth,cardHeight);
  337. ctx.drawImage(deckBackground,cardWidth*5+capX*6,capX,cardWidth,cardHeight);
  338. ctx.drawImage(deckBackground,cardWidth*6+capX*7,capX,cardWidth,cardHeight);
  339. // Draw decks
  340. deck1.drawDeck(ctx);
  341. deck2.drawDeck(ctx);
  342. deck3.drawDeck(ctx);
  343. deck4.drawDeck(ctx);
  344. deck5.drawDeck(ctx);
  345. deck6.drawDeck(ctx);
  346. deck7.drawDeck(ctx);
  347. stock.drawDeck(ctx);
  348. waste.drawDeck(ctx);
  349. target1.drawDeck(ctx);
  350. target2.drawDeck(ctx);
  351. target3.drawDeck(ctx);
  352. target4.drawDeck(ctx);
  353. // Draw target canvas to temporary canvas
  354. tmpCtx.drawImage(canvas, 0, 0);
  355. // And active card on that
  356. if (activeCard) {
  357. activeCard.drawCard(tmpCtx,true);
  358. }
  359. // Change temporary canvas to visible
  360. canvas.style.display="none";
  361. tmpCanvas.style.display="block";
  362. }
  363. /******************************************************************************
  364. * Set original canvas back to visible
  365. */
  366. function resetCanvas() {
  367. canvas.style.display="block";
  368. tmpCanvas.style.display="none";
  369. }
  370. /******************************************************************************
  371. * Draw all
  372. */
  373. function drawAll() {
  374. // Background
  375. ctx.drawImage(background,0,0,documentWidth,documentHeight);
  376. // Target backgrounds
  377. var capX = (canvas.width - (7 * cardWidth)) / 8;
  378. ctx.drawImage(deckBackground,cardWidth*3+capX*4,capX,cardWidth,cardHeight);
  379. ctx.drawImage(deckBackground,cardWidth*4+capX*5,capX,cardWidth,cardHeight);
  380. ctx.drawImage(deckBackground,cardWidth*5+capX*6,capX,cardWidth,cardHeight);
  381. ctx.drawImage(deckBackground,cardWidth*6+capX*7,capX,cardWidth,cardHeight);
  382. // Draw decks
  383. deck1.drawDeck(ctx);
  384. deck2.drawDeck(ctx);
  385. deck3.drawDeck(ctx);
  386. deck4.drawDeck(ctx);
  387. deck5.drawDeck(ctx);
  388. deck6.drawDeck(ctx);
  389. deck7.drawDeck(ctx);
  390. stock.drawDeck(ctx);
  391. waste.drawDeck(ctx);
  392. target1.drawDeck(ctx);
  393. target2.drawDeck(ctx);
  394. target3.drawDeck(ctx);
  395. target4.drawDeck(ctx);
  396. // Draw active card lates to get it on top of all rest
  397. if (activeCard) {
  398. activeCard.drawCard(ctx,true);
  399. }
  400. }
  401. /******************************************************************************
  402. * Initialize general graphics
  403. */
  404. function initGeneralGraphics() {
  405. if (generalGraphicsLoadingIndex==0) {
  406. background.onload = function(){
  407. initGeneralGraphics();
  408. //setTimeout(initGeneralGraphics, 500);
  409. };
  410. background.src = generalGraphicsArray[generalGraphicsLoadingIndex];
  411. } else if (generalGraphicsLoadingIndex==1) {
  412. cardBackground.onload = function(){
  413. initGeneralGraphics();
  414. //setTimeout(initGeneralGraphics, 500);
  415. };
  416. cardBackground.src = generalGraphicsArray[generalGraphicsLoadingIndex];
  417. } else if (generalGraphicsLoadingIndex==2) {
  418. deckBackground.onload = function(){
  419. initGeneralGraphics();
  420. //setTimeout(initGeneralGraphics, 500);
  421. };
  422. deckBackground.src = generalGraphicsArray[generalGraphicsLoadingIndex];
  423. } else {
  424. initCards();
  425. }
  426. generalGraphicsLoadingIndex++;
  427. updateMessage('Downloading general graphics...');
  428. }
  429. /******************************************************************************
  430. * Initialize cards and load card graphics
  431. */
  432. function initCards() {
  433. updateMessage('Downloading graphics for cards... '+cardLoadingIndex+' / ' + cardNameArray.length);
  434. if (cardNameArray.length == cardLoadingIndex) {
  435. message.style.display='none';
  436. // All loaded
  437. initDecks();
  438. return;
  439. }
  440. // Create card object
  441. var card = new CardObject(1,0,0,undefined);
  442. card.img = new Image();
  443. var landVal = (cardLoadingIndex+1) / 13;
  444. if (landVal<=1) {
  445. card.land = CardLand.Club;
  446. card.isBlack = true;
  447. if (cardInitVal > 12)
  448. cardInitVal = 0;
  449. cardInitVal++;
  450. } else if (landVal>1 && landVal<=2) {
  451. card.land = CardLand.Diamond;
  452. card.isBlack = false;
  453. if (cardInitVal > 12)
  454. cardInitVal = 0;
  455. cardInitVal++;
  456. } else if (landVal>2 && landVal<=3) {
  457. card.land = CardLand.Heart;
  458. card.isBlack = false;
  459. if (cardInitVal > 12)
  460. cardInitVal = 0;
  461. cardInitVal++;
  462. } else {
  463. card.land = CardLand.Spade;
  464. card.isBlack = true;
  465. if (cardInitVal > 12)
  466. cardInitVal = 0;
  467. cardInitVal++;
  468. }
  469. card.id = cardInitVal;
  470. card.img.onload = function(){
  471. initCards();
  472. //setTimeout(initCards, 100);
  473. };
  474. card.img.src = cardNameArray[cardLoadingIndex];
  475. cardArray.push(card);
  476. cardLoadingIndex++;
  477. }
  478. /******************************************************************************
  479. * Create all game decks
  480. */
  481. function initDecks() {
  482. // Mess cards first
  483. for (var i=0;i<300;i++) {
  484. var randNro1=Math.floor(Math.random()*cardArray.length);
  485. var card1 = cardArray[randNro1];
  486. var randNro2=Math.floor(Math.random()*cardArray.length);
  487. var card2 = cardArray[randNro2];
  488. cardArray[randNro1] = card2;
  489. cardArray[randNro2] = card1;
  490. }
  491. // Deal cards into decks
  492. var capX = (canvas.width - (7 * cardWidth)) / 8;
  493. var yPos = capX * 2 + cardHeight;
  494. var index = 0;
  495. deck1.setPos(capX,yPos);
  496. deck1.addCard(cardArray[index++]);
  497. deck1.cardArray[deck1.cardArray.length-1].isTurned = true;
  498. deck2.setPos(cardWidth*1+capX*2,yPos);
  499. deck2.addCard(cardArray[index++]);
  500. deck2.addCard(cardArray[index++]);
  501. deck2.cardArray[deck2.cardArray.length-1].isTurned = true;
  502. deck3.setPos(cardWidth*2+capX*3,yPos);
  503. deck3.addCard(cardArray[index++]);
  504. deck3.addCard(cardArray[index++]);
  505. deck3.addCard(cardArray[index++]);
  506. deck3.cardArray[deck3.cardArray.length-1].isTurned = true;
  507. deck4.setPos(cardWidth*3+capX*4,yPos);
  508. deck4.addCard(cardArray[index++]);
  509. deck4.addCard(cardArray[index++]);
  510. deck4.addCard(cardArray[index++]);
  511. deck4.addCard(cardArray[index++]);
  512. deck4.cardArray[deck4.cardArray.length-1].isTurned = true;
  513. deck5.setPos(cardWidth*4+capX*5,yPos);
  514. deck5.addCard(cardArray[index++]);
  515. deck5.addCard(cardArray[index++]);
  516. deck5.addCard(cardArray[index++]);
  517. deck5.addCard(cardArray[index++]);
  518. deck5.addCard(cardArray[index++]);
  519. deck5.cardArray[deck5.cardArray.length-1].isTurned = true;
  520. deck6.setPos(cardWidth*5+capX*6,yPos);
  521. deck6.addCard(cardArray[index++]);
  522. deck6.addCard(cardArray[index++]);
  523. deck6.addCard(cardArray[index++]);
  524. deck6.addCard(cardArray[index++]);
  525. deck6.addCard(cardArray[index++]);
  526. deck6.addCard(cardArray[index++]);
  527. deck6.cardArray[deck6.cardArray.length-1].isTurned = true;
  528. deck7.setPos(cardWidth*6+capX*7,yPos);
  529. deck7.addCard(cardArray[index++]);
  530. deck7.addCard(cardArray[index++]);
  531. deck7.addCard(cardArray[index++]);
  532. deck7.addCard(cardArray[index++]);
  533. deck7.addCard(cardArray[index++]);
  534. deck7.addCard(cardArray[index++]);
  535. deck7.addCard(cardArray[index++]);
  536. deck7.cardArray[deck7.cardArray.length-1].isTurned = true;
  537. stock.setPos(capX,capX);
  538. while (index < cardArray.length -1) {
  539. stock.addCard(cardArray[index++]);
  540. }
  541. waste.setPos(cardWidth*1+capX*2,capX);
  542. waste.addCard(cardArray[index++]);
  543. waste.cardArray[waste.cardArray.length-1].isTurned = true;
  544. target1.setPos(cardWidth*3+capX*4,capX);
  545. target2.setPos(cardWidth*4+capX*5,capX);
  546. target3.setPos(cardWidth*5+capX*6,capX);
  547. target4.setPos(cardWidth*6+capX*7,capX);
  548. // All created
  549. drawAll();
  550. }
  551. /******************************************************************************
  552. * Update message to the user
  553. */
  554. function updateMessage(text) {
  555. message.innerHTML = text;
  556. }
  557. /******************************************************************************
  558. * Initialize canvas for drawing and load graphics
  559. */
  560. function init() {
  561. // Document size
  562. documentWidth = document.body.offsetWidth;
  563. documentHeight = document.body.offsetHeight;
  564. // Card size
  565. cardHeight=documentWidth / 7;
  566. cardWidth=cardHeight / 1.46;
  567. // Main canvas for drawing surface
  568. canvas = document.getElementById('deskCanvas');
  569. canvas.width = documentWidth - canvas.offsetLeft*2;
  570. canvas.height = documentHeight - canvas.offsetTop;
  571. canvas.style.display="block";
  572. ctx = document.getElementById('deskCanvas').getContext('2d');
  573. // Add the temporary canvas where main canvas is copied/drawed in mousedown
  574. // Temporary canvas is drawed in mousemove
  575. var container = canvas.parentNode;
  576. tmpCanvas = document.createElement('canvas');
  577. tmpCanvas.style.display="none";
  578. tmpCanvas.id = 'tmpDeskCanvas';
  579. tmpCanvas.width = canvas.width;
  580. tmpCanvas.height = canvas.height;
  581. tmpCanvas.offsetLeft = canvas.offsetLeft;
  582. tmpCanvas.offsetRight = canvas.offsetRight;
  583. container.appendChild(tmpCanvas);
  584. tmpCtx = tmpCanvas.getContext('2d');
  585. // Loading graphics message
  586. message = document.getElementById('message');
  587. // as Safari
  588. canvas.addEventListener( 'touchstart', ev_mousedown, false);
  589. canvas.addEventListener( 'touchmove', ev_mousemove, false);
  590. canvas.addEventListener( 'touchend', ev_mouseup, false );
  591. canvas.addEventListener('mouseup', ev_mouseup, false);
  592. tmpCanvas.addEventListener( 'touchstart', ev_mousedown, false);
  593. tmpCanvas.addEventListener('touchmove', ev_mousemove, false);
  594. tmpCanvas.addEventListener('touchend', ev_mouseup, false);
  595. tmpCanvas.addEventListener('mouseup', ev_mouseup, false);
  596. // Card names
  597. cardLoadingIndex = 0;
  598. cardNameArray.push('gfx/Club_ace.png');
  599. cardNameArray.push('gfx/Club_2.png');
  600. cardNameArray.push('gfx/Club_3.png');
  601. cardNameArray.push('gfx/Club_4.png');
  602. cardNameArray.push('gfx/Club_5.png');
  603. cardNameArray.push('gfx/Club_6.png');
  604. cardNameArray.push('gfx/Club_7.png');
  605. cardNameArray.push('gfx/Club_8.png');
  606. cardNameArray.push('gfx/Club_9.png');
  607. cardNameArray.push('gfx/Club_10.png');
  608. cardNameArray.push('gfx/Club_jack.png');
  609. cardNameArray.push('gfx/Club_queen.png');
  610. cardNameArray.push('gfx/Club_king.png');
  611. cardNameArray.push('gfx/Diamond_ace.png');
  612. cardNameArray.push('gfx/Diamond_2.png');
  613. cardNameArray.push('gfx/Diamond_3.png');
  614. cardNameArray.push('gfx/Diamond_4.png');
  615. cardNameArray.push('gfx/Diamond_5.png');
  616. cardNameArray.push('gfx/Diamond_6.png');
  617. cardNameArray.push('gfx/Diamond_7.png');
  618. cardNameArray.push('gfx/Diamond_8.png');
  619. cardNameArray.push('gfx/Diamond_9.png');
  620. cardNameArray.push('gfx/Diamond_10.png');
  621. cardNameArray.push('gfx/Diamond_jack.png');
  622. cardNameArray.push('gfx/Diamond_queen.png');
  623. cardNameArray.push('gfx/Diamond_king.png');
  624. cardNameArray.push('gfx/Heart_ace.png');
  625. cardNameArray.push('gfx/Heart_2.png');
  626. cardNameArray.push('gfx/Heart_3.png');
  627. cardNameArray.push('gfx/Heart_4.png');
  628. cardNameArray.push('gfx/Heart_5.png');
  629. cardNameArray.push('gfx/Heart_6.png');
  630. cardNameArray.push('gfx/Heart_7.png');
  631. cardNameArray.push('gfx/Heart_8.png');
  632. cardNameArray.push('gfx/Heart_9.png');
  633. cardNameArray.push('gfx/Heart_10.png');
  634. cardNameArray.push('gfx/Heart_jack.png');
  635. cardNameArray.push('gfx/Heart_queen.png');
  636. cardNameArray.push('gfx/Heart_king.png');
  637. cardNameArray.push('gfx/Spade_ace.png');
  638. cardNameArray.push('gfx/Spade_2.png');
  639. cardNameArray.push('gfx/Spade_3.png');
  640. cardNameArray.push('gfx/Spade_4.png');
  641. cardNameArray.push('gfx/Spade_5.png');
  642. cardNameArray.push('gfx/Spade_6.png');
  643. cardNameArray.push('gfx/Spade_7.png');
  644. cardNameArray.push('gfx/Spade_8.png');
  645. cardNameArray.push('gfx/Spade_9.png');
  646. cardNameArray.push('gfx/Spade_10.png');
  647. cardNameArray.push('gfx/Spade_jack.png');
  648. cardNameArray.push('gfx/Spade_queen.png');
  649. cardNameArray.push('gfx/Spade_king.png');
  650. // General graphics
  651. generalGraphicsLoadingIndex = 0;
  652. generalGraphicsArray.push('gfx/background.png');
  653. generalGraphicsArray.push('gfx/card_background.png');
  654. generalGraphicsArray.push('gfx/deck_background.png');
  655. // Start loading general graphics
  656. initGeneralGraphics();
  657. }
  658. /******************************************************************************
  659. * Find card under mouse coordinates
  660. */
  661. function cardUnderMouse(x,y) {
  662. // Find card under user mouse press
  663. var card = undefined;
  664. if(card = deck1.cardUnderMouse(x,y)) return card;
  665. if(card = deck2.cardUnderMouse(x,y)) return card;
  666. if(card = deck3.cardUnderMouse(x,y)) return card;
  667. if(card = deck4.cardUnderMouse(x,y)) return card;
  668. if(card = deck5.cardUnderMouse(x,y)) return card;
  669. if(card = deck6.cardUnderMouse(x,y)) return card;
  670. if(card = deck7.cardUnderMouse(x,y)) return card;
  671. if(card = waste.cardUnderMouse(x,y)) return card;
  672. if(card = stock.cardUnderMouse(x,y)) return card;
  673. return undefined;
  674. }
  675. /******************************************************************************
  676. * Find deck under mouse coordinates
  677. */
  678. function deckUnderMouse(x,y) {
  679. // Find deck under user mouse press
  680. var deck = undefined;
  681. if(deck = deck1.deckUnderMouse(x,y)) return deck;
  682. if(deck = deck2.deckUnderMouse(x,y)) return deck;
  683. if(deck = deck3.deckUnderMouse(x,y)) return deck;
  684. if(deck = deck4.deckUnderMouse(x,y)) return deck;
  685. if(deck = deck5.deckUnderMouse(x,y)) return deck;
  686. if(deck = deck6.deckUnderMouse(x,y)) return deck;
  687. if(deck = deck7.deckUnderMouse(x,y)) return deck;
  688. if(deck = waste.deckUnderMouse(x,y)) return deck;
  689. if(deck = stock.deckUnderMouse(x,y)) return deck;
  690. if(deck = target1.deckUnderMouse(x,y)) return deck;
  691. if(deck = target2.deckUnderMouse(x,y)) return deck;
  692. if(deck = target3.deckUnderMouse(x,y)) return deck;
  693. if(deck = target4.deckUnderMouse(x,y)) return deck;
  694. return undefined;
  695. }
  696. /******************************************************************************
  697. * Mouse down
  698. */
  699. function ev_mousedown (ev) {
  700. if (mouseDown)
  701. return;
  702. ev.preventDefault();
  703. mouseDown = true;
  704. // mousex = ev.clientX - canvas.offsetLeft;
  705. // mousey = ev.clientY - canvas.offsetTop;
  706. // mousex = ev.offsetX - canvas.offsetLeft;
  707. // mousey = ev.offsetY - canvas.offsetTop;
  708. mousex = ev.targetTouches[0].pageX - canvas.offsetLeft;
  709. mousey = ev.targetTouches[0].pageY - canvas.offsetTop;
  710. activeCard = cardUnderMouse(mousex,mousey);
  711. var activeDeck = deckUnderMouse(mousex,mousey);
  712. // User wants more cards from stock to waste
  713. if ((activeCard && activeCard.deckId == DeckType.Stock) ||
  714. (activeDeck && activeDeck.id == DeckType.Stock) ) {
  715. if (activeCard && stock.cardArray.length > 0) {
  716. // Do move from stock to waste
  717. stock.removeTopCard();
  718. activeCard.topCard = undefined;
  719. activeCard.isTurned = true;
  720. waste.addCard(activeCard);
  721. } else {
  722. // Stock is empty, copy card back from waste
  723. var card = waste.removeTopCard();
  724. while(card) {
  725. card.topCard = undefined;
  726. card.isTurned = false;
  727. stock.addCard(card);
  728. card = waste.removeTopCard();
  729. }
  730. }
  731. mouseDown = false;
  732. activeCard = undefined;
  733. return;
  734. }
  735. // User starts moving cards
  736. if (activeCard) {
  737. xOff = mousex - activeCard.x;
  738. yOff = mousey - activeCard.y;
  739. // Copy main canvas and start drawing copy of it
  740. copyCanvasAndDraw();
  741. } else {
  742. mouseDown = false;
  743. }
  744. }
  745. /******************************************************************************
  746. * Mouse move
  747. */
  748. function ev_mousemove (ev) {
  749. if (!mouseDown)
  750. return;
  751. if (!activeCard) {
  752. return;
  753. }
  754. ev.preventDefault();
  755. // var newX = ev.clientX - tmpCanvas.offsetLeft;
  756. // var newY = ev.clientY - tmpCanvas.offsetTop;
  757. // var newX = ev.offsetX - tmpCanvas.offsetLeft;
  758. // var newY = ev.offsetY - tmpCanvas.offsetTop;
  759. var newX = ev.targetTouches[0].pageX - tmpCanvas.offsetLeft;
  760. var newY = ev.targetTouches[0].pageY - tmpCanvas.offsetTop;
  761. // Is mouse position outside of canvas?
  762. var tmpX = newX - xOff;
  763. var tmpY = newY - yOff;
  764. if (tmpX < 1 ||
  765. tmpX + cardWidth >= canvas.width ||
  766. tmpY < 1) {
  767. // MouseUp
  768. mouseDown = false;
  769. // Cancel move
  770. activeCard.cancel();
  771. activeCard = undefined;
  772. // Draw whole main canvas
  773. drawAll();
  774. // Start showing again main canvas
  775. resetCanvas();
  776. return;
  777. }
  778. // Move card
  779. if (movingCardsDrawed) {
  780. moveXAmount = Math.abs(mousex - newX) +2;
  781. moveYAmount = Math.abs(mousey - newY) +2;
  782. movingCardsDrawed = false;
  783. } else {
  784. moveXAmount += Math.abs(mousex - newX) +2;
  785. moveYAmount += Math.abs(mousey - newY) +2;
  786. }
  787. mousex = newX;
  788. mousey = newY;
  789. activeCard.move(mousex - xOff, mousey - yOff);
  790. // request new frame
  791. requestAnimFrame(function(){
  792. drawCardFast(activeCard,tmpCtx,canvas);
  793. movingCardsDrawed = true;
  794. });
  795. }
  796. /******************************************************************************
  797. * Mouse up
  798. */
  799. function ev_mouseup (ev) {
  800. mouseDown = false;
  801. ev.preventDefault();
  802. var x = mousex;
  803. var y = mousey;
  804. if (ev.targetTouches.length > 0) {
  805. x = ev.targetTouches[0].pageX - tmpCanvas.offsetLeft;
  806. y = ev.targetTouches[0].pageY - tmpCanvas.offsetTop;
  807. }
  808. // Change card into different deck
  809. if (activeCard) {
  810. var activeDeck = deckUnderMouse(x,y);
  811. if (activeDeck) {
  812. if (isAllowedMove(activeCard.deckObject, activeDeck, activeCard)) {
  813. // Remove cards from the original deck
  814. activeCard.deckObject.removeFromThisCard(activeCard);
  815. // Add cards into new deck
  816. activeDeck.addCard(activeCard);
  817. } else {
  818. activeCard.cancel();
  819. }
  820. } else {
  821. activeCard.cancel();
  822. }
  823. }
  824. activeCard = undefined;
  825. // Draw whole main canvas
  826. drawAll();
  827. // Start showing again main canvas
  828. resetCanvas();
  829. movingCardsDrawed = true;
  830. }