2 /* Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2016 Arun Persaud <arun@nubati.net>
4 * This file is part of e-DoKo.
6 * e-DoKo is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * e-DoKo is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with e-DoKo. If not, see <http://www.gnu.org/licenses/>.
21 /* make sure that we are not called from outside the scripts,
22 * use a variable defined in config.php to check this
27 function config_check()
29 global $EmailName,$EMAIL_REPLY,$ADMIN_NAME,$ADMIN_EMAIL,$DB_work;
31 /* check if some variables are set in the config file, else set defaults */
32 if(!isset($EmailName))
34 if(isset($EMAIL_REPLY))
36 ini_set('sendmail_from',$EMAIL_REPLY);
38 if(!isset($ADMIN_NAME))
41 echo '<h1>Setup not completed</h1>';
42 echo 'You need to set $ADMIN_NAME in config.php.';
46 if(!isset($ADMIN_EMAIL))
49 echo '<h1>Setup not completed</h1>';
50 echo 'You need to set $ADMIN_EMAIL in config.php. '.
51 'If something goes wrong an email will be send to this address.';
58 echo '<h1>Setup not completed</h1>';
59 echo 'You need to set $DB_work in config.php. '.
60 'If this is set to anything else than 0, the game will be suspended and one can work safely on the database. '.
61 'A message will be displayed that it will probably take about N minutes, with N being the number $DB_work is set to. '.
62 'The default should be 0 for the game to work.';
69 echo '<div class="WIP">'.
70 _("Working on some aspect of e-DoKo... This will probably take max. $DB_work minutes. It could be over in a few seconds too though ;)").
79 /* define possible status for email subsjects */
80 define("GAME_CANCELED", 0);
81 define("GAME_CANCELED_POVERTY", 1);
82 define("GAME_CANCELED_TIMEOUT", 2);
83 define("GAME_YOUR_TURN", 3);
84 define("GAME_READY", 4);
85 define("GAME_POVERTY", 5);
86 define("GAME_DPOVERTY", 6);
87 define("GAME_OVER", 7);
88 define("GAME_RECOVERY", 8);
89 define("GAME_REMINDER", 9);
90 define("GAME_NEW", 10);
92 /* define possible status for showing cards */
94 define("CARDS_EMPTY", 0); /* show player's hand*/
95 define("CARDS_SHOW", 1); /* show player's hand*/
96 define("CARDS_MYTURN", 2); /* show radiobuttons for cards that can be played*/
97 define("CARDS_EXCHANGE", 3); /* do we need to return cards to our partner in poverty?*/
98 define("CARDS_GAMEOVER_ME", 4); /* show all cards from everyone*/
99 define("CARDS_GAMEOVER", 5); /* show all cards from everyone (looking at someone else's game)*/
101 /* cards_status: SHOW show our hand
102 * MYTURN show radiobutton for cards that can be played
103 * EXCHANGE do we need to return cards to our partner in poverty?
104 * GAMEOVER show all cards from everyone
107 function mymail($uid,$gameid=0,$type,$message)
109 global $EmailName,$WIKI,$PREF;
111 /* uid can be either a single uid or an array, convert everything to
112 * an array, so that we can loop over it */
120 foreach($uid as $user)
122 /* do we send the email right away or save it in the database? */
125 $name = DB_get_name('userid',$user);
126 $To = DB_get_email('userid',$user);
128 /* check if user wants email right away or if we should save it in
129 * the database for later delivery
132 $uidPREF = DB_get_PREF($user);
133 if( $uidPREF['digest'] != 'digest-off' )
135 /* use local language */
136 set_language($uidPREF['language']);
138 $header = sprintf(_('Hello %s'),$name);
141 /* add standard header and footer */
142 $subject = "$EmailName ";
144 $game = DB_format_gameid($gameid);
151 $subject.=sprintf(_('Game %s canceled'),$game);
153 case GAME_CANCELED_POVERTY:
154 $subject.=sprintf(_('Game %s canceled (poverty not resolved)'),$game);
156 case GAME_CANCELED_TIMEOUT:
157 $subject.=sprintf(_('Game %s canceled (timed out)'),$game);
160 $subject.=sprintf(_('A card has been played in game %s'),$game);
163 $subject.=sprintf(_('Ready, set, go... (game %s)'),$game);
166 $subject.=sprintf(_('Poverty (game %s)'),$game);
169 $subject.=sprintf(_('Double poverty (game %s)'),$game);
172 $subject.=sprintf(_('Game over (game %s)'),$game);
175 $subject.=_('Recovery');
178 $subject.=sprintf(_("Reminder: game %s it's your turn"),$game);
181 $subject.=sprintf(_('You are invited to a game of DoKo (game %s)'),$game);
184 $subject.=sprintf(_('Problem with email, contact admin (errorcode %d)'),$gameid);
187 /* standard goodbye */
188 $footer = "\n"._('Have a nice day')."\n "._('your E-Doko service department').
191 _('You can change your mail delivery mode in the preference menu.').
193 _('web').': http://doko.nubati.net '.
194 _('help, bugs, etc.').": $WIKI";
197 sendmail($To,$subject,$header.$message.$footer);
200 /* store email in database */
201 DB_digest_insert_email($To,$message,$type,$gameid);
205 /* reset language to original user*/
206 set_language($PREF['language']);
211 function sendmail($To,$Subject,$message)
213 /* this function sends the mail or outputs to the screen in case of debugging */
214 global $debug,$EMAIL_REPLY;
218 if(isset($EMAIL_REPLY))
219 $header .= "From: e-DoKo daemon <$EMAIL_REPLY>\r\n";
221 $header .= "Content-Type: text/plain; charset = \"UTF-8\";\r\n";
222 $header .= "Content-Transfer-Encoding: 8bit\r\n";
227 /* display email on screen,
230 $message = str_replace("\n","<br />\n",$message);
231 $message = preg_replace("#(\w+://[^<>\s]+[\w/]*)#",
232 "<a href=\"$1\">$1</a>", $message);
234 echo "<br />To: $To<br />";
235 echo $header."<br />";
236 echo "Subject: $Subject <br />$message<br />\n";
239 mail($To,$Subject,$message,$header);
246 /* returns 1 if all names passed as args are defined by a GET or POST statement,
251 $args = func_get_args();
253 foreach($args as $arg)
255 $ok = $ok * isset($_REQUEST[$arg]);
256 /*echo "$arg: ok = $ok <br />";
262 function myerror($message)
264 echo "<span class=\"error\">".htmlspecialchars($message)."</span>\n";
265 sendmail($ADMIN_EMAIL,$EmailName." Error in Code",$message);
269 function pos_array($c,$arr)
286 function is_trump($c)
290 if(in_array($c,$CARDS["trump"]))
296 function is_same_suite($c1,$c2)
300 if(in_array($c1,$CARDS["trump"] ) && in_array($c2,$CARDS["trump"] ) ) return 1;
301 if(in_array($c1,$CARDS["clubs"] ) && in_array($c2,$CARDS["clubs"] ) ) return 1;
302 if(in_array($c1,$CARDS["hearts"] ) && in_array($c2,$CARDS["hearts"] ) ) return 1;
303 if(in_array($c1,$CARDS["spades"] ) && in_array($c2,$CARDS["spades"] ) ) return 1;
304 if(in_array($c1,$CARDS["diamonds"]) && in_array($c2,$CARDS["diamonds"]) ) return 1;
309 function compare_cards($a,$b,$game)
311 /* if "a" is higher than "b" return 1, else 0, "a" being the card first played */
317 /* first map all cards to the odd number,
318 * this insure that the first card wins the trick
319 * if they are the same card
321 if( $a/2 - (int)($a/2) != 0.5)
323 if( $b/2 - (int)($b/2) != 0.5)
326 /* check for schweinchen and ten of hearts*/
333 if($RULES['schweinchen']=='both' && $GAME['schweinchen-who'])
335 if($a == 19 || $a == 20 )
337 if($b == 19 || $b == 20 )
340 else if($RULES['schweinchen']=='second' && $GAME['schweinchen-second'])
342 if($a == 19 || $a == 20 )
344 if($b == 19 || $b == 20 )
347 else if($RULES['schweinchen']=='secondaftercall' && $GAME['schweinchen-who'] && $GAME['schweinchen-second'] )
349 /* check if a call was made either by the player or his partner. If so activate Schweinchen rule. */
350 if(DB_get_call_by_hash($GAME['schweinchen-who']) || DB_get_partner_call_by_hash($GAME['schweinchen-who']) )
352 if($a == 19 || $a == 20 )
354 if($b == 19 || $b == 20 )
357 /* if not, do nothing and the foxes are just handeled as normal trump */
365 /* check for ten of hearts rule */
366 if($RULES["dullen"]=="secondwins")
367 if($a==1 && $b==1) /* both 10 of hearts */
368 return 0; /* second one wins.*/
372 /* no special cases here */
376 if(is_trump($a) && is_trump($b) && $a<=$b)
378 else if(is_trump($a) && is_trump($b) )
381 { /*$a is not a trump */
385 { /* both no trump */
388 $posA = pos_array($a,$CARDS["clubs"]);
389 $posB = pos_array($b,$CARDS["clubs"]);
397 $posA = pos_array($a,$CARDS["spades"]);
398 $posB = pos_array($b,$CARDS["spades"]);
406 $posA = pos_array($a,$CARDS["hearts"]);
407 $posB = pos_array($b,$CARDS["hearts"]);
415 $posA = pos_array($a,$CARDS["diamonds"]);
416 $posB = pos_array($b,$CARDS["diamonds"]);
423 /* not the same suit and no trump: a wins */
429 function get_winner($p,$mode)
431 /* get all 4 cards played in a trick, in the order they are played */
434 $c1pos = $tmp["pos"];
438 $c2pos = $tmp["pos"];
442 $c3pos = $tmp["pos"];
446 $c4pos = $tmp["pos"];
448 /* first card is better than all the rest */
449 if( compare_cards($c1,$c2,$mode) && compare_cards($c1,$c3,$mode) && compare_cards($c1,$c4,$mode) )
452 /* second card is better than first and better than the rest */
453 if( !compare_cards($c1,$c2,$mode) && compare_cards($c2,$c3,$mode) && compare_cards($c2,$c4,$mode) )
456 /* third card is better than first card and better than last */
457 if( !compare_cards($c1,$c3,$mode) && compare_cards($c3,$c4,$mode) )
458 /* if second card is better than first, third card needs to be even better */
459 if( !compare_cards($c1,$c2,$mode) && !compare_cards($c2,$c3,$mode) )
461 /* second is worse than first, e.g. not following suite */
462 else if (compare_cards($c1,$c2,$mode) )
465 /* non of the above */
469 function count_nines($cards)
473 foreach($cards as $c)
475 if($c == "25" || $c == "26") $nines++;
476 else if($c == "33" || $c == "34") $nines++;
477 else if($c == "41" || $c == "42") $nines++;
478 else if($c == "47" || $c == "48") $nines++;
484 function check_wedding($cards)
487 if( in_array("3",$cards) && in_array("4",$cards) )
493 function count_trump($cards,$status='pregame')
499 /* count each trump, including the foxes, since this is used to determine poverty status */
500 foreach($cards as $c)
504 /* In case we really want to know the amount of trump, we can use the status variable.
505 * This is needed for example to figure out what icon to display on the table in case of
506 * trump given back in poverty */
507 if($status=='all') return $trump;
509 /* normally foxes don't count as trump, so we substract them here
510 * in case someone has schweinchen, one or two of them should count as trump
511 * though, so we need to add one trump for those cases */
514 if( in_array("19",$cards))
516 if( in_array("20",$cards) )
519 /* handle case where player has schweinchen */
520 if( in_array("19",$cards) && in_array("20",$cards) )
521 switch($RULES["schweinchen"])
524 /* add two, in case the player has both foxes (schweinchen) */
529 case "secondaftercall":
530 /* add one, in case the player has both foxes (schweinchen) */
540 function check_low_trump($cards)
544 if($RULES['lowtrump']=='none')
547 /* check if we have low trump */
550 foreach($cards as $card)
552 /* card a trump, but not a diamond? */
557 /* handle case where player has schweinchen */
558 if( in_array("19",$cards) && in_array("20",$cards) )
559 switch($RULES["schweinchen"])
563 case "secondaftercall":
573 function create_array_of_random_numbers($useridA,$useridB,$useridC,$useridD)
581 /* fix the hands; makes debugging easier; the following hands have lots of sicknesses,
582 * to make testing easier
584 $r[ 0]=1; $r[12]=47; $r[24]=13; $r[36]=37;
585 $r[ 1]=2; $r[13]=23; $r[25]=14; $r[37]=38;
586 $r[ 2]=3; $r[14]=27; $r[26]=15; $r[38]=39;
587 $r[ 3]=4; $r[15]=16; $r[27]=28; $r[39]=40;
588 $r[ 4]=5; $r[16]=17; $r[28]=29; $r[40]=21;
589 $r[ 5]=18; $r[17]=6; $r[29]=30; $r[41]=42;
590 $r[ 6]=41; $r[18]=7; $r[30]=31; $r[42]=43;
591 $r[ 7]=22; $r[19]=8; $r[31]=32; $r[43]=20;
592 $r[ 8]=45; $r[20]=9; $r[32]=33; $r[44]=19;
593 $r[ 9]=46; $r[21]=10; $r[33]=44; $r[45]=24;
594 $r[10]=35; $r[22]=11; $r[34]=48; $r[46]=25;
595 $r[11]=36; $r[23]=12; $r[35]=34; $r[47]=26;
599 /* check if we can find a game were non of the player was involved and return
602 $userstr = "'".implode("','",array($useridA,$useridB,$useridC,$useridD))."'";
603 $randomnumbers = DB_get_unused_randomnumbers($userstr);
604 $randomnumbers = explode(":",$randomnumbers);
606 if(sizeof($randomnumbers)==48)
607 return $randomnumbers;
609 /* need to create new numbers */
613 /* shuffle using a better random generator than the standard one */
614 for ($i = 0; $i <48; $i++)
616 $j = @mt_rand(0, $i);
626 function display_cards($me,$myturn)
631 function have_suit($cards,$c)
636 if(in_array($c,$CARDS["trump"]))
637 $suite = $CARDS["trump"];
638 else if(in_array($c,$CARDS["clubs"]))
639 $suite = $CARDS["clubs"];
640 else if(in_array($c,$CARDS["spades"]))
641 $suite = $CARDS["spades"];
642 else if(in_array($c,$CARDS["hearts"]))
643 $suite = $CARDS["hearts"];
644 else if(in_array($c,$CARDS["diamonds"]))
645 $suite = $CARDS["diamonds"];
647 foreach($cards as $card)
649 if(in_array($card,$suite))
656 function same_type($card,$c)
661 /* figure out what kind of card c is */
662 if(in_array($c,$CARDS["trump"]))
663 $suite = $CARDS["trump"];
664 else if(in_array($c,$CARDS["clubs"]))
665 $suite = $CARDS["clubs"];
666 else if(in_array($c,$CARDS["spades"]))
667 $suite = $CARDS["spades"];
668 else if(in_array($c,$CARDS["hearts"]))
669 $suite = $CARDS["hearts"];
670 else if(in_array($c,$CARDS["diamonds"]))
671 $suite = $CARDS["diamonds"];
673 /* card is the same suid return 1 */
674 if(in_array($card,$suite))
680 function set_gametype($gametype)
694 $CARDS["trump"] = array('1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16',
695 '17','18','19','20','21','22','23','24','25','26');
696 $CARDS["diamonds"] = array();
697 $CARDS["clubs"] = array('27','28','29','30','31','32','33','34');
698 $CARDS["spades"] = array('35','36','37','38','39','40','41','42');
699 $CARDS["hearts"] = array('43','44','45','46','47','48');
700 $CARDS["foxes"] = array('19','20');
701 if($RULES["dullen"]=='none')
703 $CARDS["trump"] = array('3','4','5','6','7','8','9','10','11','12','13','14','15','16',
704 '17','18','19','20','21','22','23','24','25','26');
705 $CARDS["hearts"] = array('43','44','1','2','45','46','47','48');
707 /* do we need to reorder for Schweinchen? need to search for it because of special case for dullen above*/
708 if($RULES['schweinchen']=='both'&& $GAME['schweinchen-who'])
710 /* find the fox and put them at the top of the stack */
711 foreach(array('19','20') as $fox)
714 $trump = $CARDS['trump'];
715 $key = array_keys($trump, $fox);
719 $foxa[]=$trump[$key[0]];
720 unset($trump[$key[0]]);
721 $trump = array_merge($foxa,$trump);
722 $CARDS['trump'] = $trump;
725 else if( ($RULES['schweinchen']=='second' || $RULES['schweinchen']=='secondaftercall')
726 && $GAME['schweinchen-who'])
728 /* find the fox and put them at the top of the stack */
729 $trump = $CARDS['trump'];
730 $key = array_keys($trump, '19');
734 $foxa[]=$trump[$key[0]];
735 unset($trump[$key[0]]);
736 $trump = array_merge($foxa,$trump);
737 $CARDS['trump'] = $trump;
741 $CARDS["trump"] = array('3','4','5','6','7','8','9','10');
742 $CARDS["clubs"] = array('27','28','29','30','31','32','11','12','33','34');
743 $CARDS["spades"] = array('35','36','37','38','39','40','13','14','41','42');
744 $CARDS["hearts"] = array('43','44', '1', '2','45','46','15','16','47','48');
745 $CARDS["diamonds"] = array('19','20','21','22','23','24','17','18','25','26');
746 $CARDS["foxes"] = array();
749 $CARDS["trump"] = array('11','12','13','14','15','16','17','18');
750 $CARDS["clubs"] = array('27','28','29','30','31','32','3', '4','33','34');
751 $CARDS["spades"] = array('35','36','37','38','39','40','5', '6','41','42');
752 $CARDS["hearts"] = array('43','44', '1', '2','45','46','7', '8','47','48');
753 $CARDS["diamonds"] = array('19','20','21','22','23','24','9','10','25','26');
754 $CARDS["foxes"] = array();
757 $CARDS["trump"] = array();
758 $CARDS["clubs"] = array('27','28','29','30','31','32','3', '4','11','12','33','34');
759 $CARDS["spades"] = array('35','36','37','38','39','40','5', '6','13','14','41','42');
760 $CARDS["hearts"] = array('43','44', '1', '2','45','46','7', '8','15','16','47','48');
761 $CARDS["diamonds"] = array('19','20','21','22','23','24','9','10','17','18','25','26');
762 $CARDS["foxes"] = array();
765 $CARDS["trump"] = array('1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16',
766 '17','18','27','28','29','30','31','32','33','34');
767 $CARDS["clubs"] = array();
768 $CARDS["spades"] = array('35','36','37','38','39','40','41','42');
769 $CARDS["hearts"] = array('43','44','45','46','47','48');
770 $CARDS["diamonds"] = array('19','20','21','22','23','24','25','26');
771 $CARDS["foxes"] = array();
772 if($RULES["dullen"]=='none')
774 $CARDS["trump"] = array('3','4','5','6','7','8','9','10','11','12','13','14','15','16',
775 '17','18','27','28','29','30','31','32','33','34');
776 $CARDS["hearts"] = array('43','44','1','2','45','46','47','48');
780 $CARDS["trump"] = array('1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16',
781 '17','18','35','36','37','38','39','40','41','42');
782 $CARDS["clubs"] = array('27','28','29','30','31','32','33','34');
783 $CARDS["spades"] = array();
784 $CARDS["hearts"] = array('43','44','45','46','47','48');
785 $CARDS["diamonds"] = array('19','20','21','22','23','24','25','26');
786 $CARDS["foxes"] = array();
787 if($RULES["dullen"]=='none')
789 $CARDS["trump"] = array('3','4','5','6','7','8','9','10','11','12','13','14','15','16',
790 '17','18','35','36','37','38','39','40','41','42');
791 $CARDS["hearts"] = array('43','44','1','2','45','46','47','48');
795 $CARDS["trump"] = array('1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16',
796 '17','18','43','44','45','46','47','48');
797 $CARDS["clubs"] = array('27','28','29','30','31','32','33','34');
798 $CARDS["spades"] = array('35','36','37','38','39','40','41','42');
799 $CARDS["hearts"] = array();
800 $CARDS["diamonds"] = array('19','20','21','22','23','24','25','26');
801 $CARDS["foxes"] = array();
802 if($RULES["dullen"]=='none')
804 $CARDS["trump"] = array('3','4','5','6','7','8','9','10','11','12','13','14','15','16',
805 '17','18','43','44','1','2','45','46','47','48');
811 function mysort($cards,$gametype)
814 if(isset($PREF['sorting']))
815 if($PREF['sorting']=='high-low')
816 usort ( $cards, 'sort_comp_high_low' );
818 usort ( $cards, 'sort_comp_low_high' );
820 usort ( $cards, 'sort_comp_high_low' );
824 function sort_comp_high_low($a,$b)
829 $ALL = array_merge($CARDS['trump'],$CARDS['diamonds'],$CARDS['clubs'],
830 $CARDS['hearts'],$CARDS['spades']);
832 return pos_array($a,$ALL)-pos_array($b,$ALL);
835 function sort_comp_low_high($a,$b)
840 $ALL = array_merge($CARDS['trump'],$CARDS['diamonds'],$CARDS['clubs'],
841 $CARDS['hearts'],$CARDS['spades']);
843 return -pos_array($a,$ALL)+pos_array($b,$ALL);
846 function can_call($what,$hash)
848 /* figure out if a person can make a call:
849 $what in 0,30,60,90,120 = points of the call
850 $hash = the hash of the person who wants to make the call
853 0 can't make that call
855 2 can make the call, but this is the last chance to do so...
860 /* get some information
862 $gameid = DB_get_gameid_by_hash($hash);
863 $gametype = DB_get_gametype_by_gameid($gameid);
864 $oldcall = DB_get_call_by_hash($hash); /* did the person already made a call? */
865 $pcall = DB_get_partner_call_by_hash($hash); /* did the partner already made a call */
868 /* you're call must be better than the one you or your partner already made
870 if( ($pcall!=NULL && ($what >= $pcall))
871 || ($oldcall!=NULL && ($what >=$oldcall)) )
876 /* for some rules we need to know how many cards people have
878 $NRcards = count(DB_get_hand($hash));
883 $user = DB_get_hash_from_game_and_pos($gameid,$i);
884 $NRallcards += count(DB_get_hand($user));
887 /* in case of a wedding, everything will be delayed by an offset
890 if($gametype=="wedding")
892 $offset = DB_get_sickness_by_gameid($gameid);
893 if ($offset <0) /* not resolved */
897 /* now check if the call is allowed depending on the rule set
899 switch ($RULES["call"])
902 /* calls can be made before/while you play your card...
903 * first card = 120, second card = 90, etc.
905 if( 4-($what/30) == 12 - ($NRcards + $offset))
907 if( 4-($what/30) > 12 - ($NRcards + $offset))
911 /* you can make the first call anytime during the first trick
913 if( 27+4*($what/30) == $NRallcards + $offset*4)
915 if( 27+4*($what/30) < $NRallcards + $offset*4)
919 /* you can call 120 with 12 cards, 90 with 9 or more cards, 60 with 6 or more, etc.
920 * you can't skip a call though
923 /* figure out last call
925 if($oldcall!=NULL && $pcall!=NULL)
926 $mincall = ($oldcall>$pcall) ? $pcall : $oldcall;
927 else if($oldcall!=NULL)
929 else if ($pcall!=NULL)
935 if( 12 == ($NRcards + $offset))
939 else if( 12 < ($NRcards + $offset))
943 else if ( 9 == ($NRcards + $offset))
945 if( ($mincall>=0 && $mincall<=120 && $what<=90 ) )
948 else if ( 9 < ($NRcards + $offset))
950 if( ($mincall>=0 && $mincall<=120 && $what<=90 ) )
953 else if ( 6 == ($NRcards + $offset))
955 if( ($mincall>=0 && $mincall<=90 && $what<=60 ) )
958 else if ( 6 < ($NRcards + $offset))
960 if( ($mincall>=0 && $mincall<=90 && $what<=60 ) )
963 else if ( 3 == ($NRcards + $offset))
965 if( ($mincall>=0 && $mincall<=60 && $what<=30 ) )
968 else if ( 3 < ($NRcards + $offset))
970 if( ($mincall>=0 && $mincall<=60 && $what<=30 ) )
973 else if ( 0 == ($NRcards + $offset))
975 if( ($mincall>=0 && $mincall<=30 && $what==0 ) )
978 else if ( 0 < ($NRcards + $offset))
980 if( ($mincall>=0 && $mincall<=30 && $what==0 ) )
989 function display_table_begin ()
993 $result = DB_query('SELECT User.fullname as name,'.
994 ' Hand.position as position,'.
996 ' Hand.party as party,'.
997 ' Hand.sickness as sickness,'.
1004 ' LEFT JOIN User ON User.id=Hand.user_id'.
1005 ' WHERE Hand.game_id='.DB_quote_smart($gameid).
1006 ' ORDER BY position ASC');
1008 $row0 = DB_fetch_array($result);
1009 $row1 = DB_fetch_array($result);
1010 $row2 = DB_fetch_array($result);
1011 $row3 = DB_fetch_array($result);
1013 echo "<div class=\"table\">\n";
1014 display_single_user($row1);
1015 echo "\n<div class=\"middle\">\n";
1016 display_single_user($row0,1); /* mark starting player in case re/contra is not set yet */
1017 echo " <img class=\"table\" src=\"pics/table.png\" alt=\"table\" />\n";
1018 display_single_user($row2);
1024 function display_table_end ()
1028 $result = DB_query('SELECT User.fullname as name,'.
1029 ' Hand.position as position,'.
1031 ' Hand.party as party,'.
1032 ' Hand.sickness as sickness,'.
1033 ' Hand.point_call,'.
1034 ' User.last_login,'.
1039 ' LEFT JOIN User ON User.id=Hand.user_id'.
1040 ' WHERE Hand.game_id='.DB_quote_smart($gameid).
1041 ' ORDER BY position ASC');
1043 $row0 = DB_fetch_array($result);
1044 $row1 = DB_fetch_array($result);
1045 $row2 = DB_fetch_array($result);
1046 $row3 = DB_fetch_array($result);
1049 display_single_user($row3);
1055 function display_single_user($r,$start=0)
1057 /* start=1, mark starting player, default=0, so the player on the left is not marked */
1059 global $gameid, $debug,$INDEX,$defaulttimezone;
1060 global $RULES,$GAME, $gametype_raw;
1071 $wins = DB_get_number_of_tricks($gameid,$pos);
1072 date_default_timezone_set($defaulttimezone);
1073 $lastlogin = strtotime($r[6]);
1074 date_default_timezone_set($timezone);
1075 $timenow = strtotime(date("Y-m-d H:i:s"));
1076 $gravatar = "$name<br />\n <img class=\"gravatar\" title=\"$name\" src=\"https://www.gravatar.com/avatar/".
1077 md5(strtolower(trim($email)))."?d=identicon\" alt=\"$name's gravatar\" />";
1079 echo " <div class=\"table".($pos-1)."\">\n";
1081 /* mark starting player */
1082 if($start && ! ($party=="re" || $party=="contra"))
1083 echo ' <span class="start">'._('Starting Player')."</span> <br />\n";
1086 echo " <a href=\"".$INDEX."?action=game&me=".$hash."\">";
1087 if($vacation = check_vacation($user))
1089 $start = $vacation[0];
1090 $stop = substr($vacation[1],0,10);
1091 $comment = $vacation[2];
1093 $title = _("begin:")." $start "._("end:")." $stop $comment";
1094 echo " <span class=\"vacation\" title=\"$title\">$gravatar "._("(on vacation until $stop)")."</span> \n";
1097 echo " $gravatar \n";
1101 /* add hints for poverty, wedding, solo, etc */
1102 if( $gametype_raw != "solo")
1103 if( $RULES["schweinchen"]=="both" && $GAME["schweinchen-who"]==$hash )
1104 echo " Schweinchen. <br />";
1106 if($gametype_raw=="poverty" && $party=="re")
1107 if($sickness=="poverty" || ($RULES['lowtrump']=='poverty' && $sickness=='lowtrump'))
1109 $userhash = DB_get_hash_from_gameid_and_userid($gameid,$user);
1110 $cards = DB_get_all_hand($userhash);
1111 $trumpNR = count_trump($cards,'all');
1113 echo " <img src=\"pics/button/poverty_trump_button.png\" class=\"button\" ".
1114 "alt=\"poverty - trump back\" title=\"poverty - trump back\" />\n";
1116 echo " <img src=\"pics/button/poverty_notrump_button.png\" class=\"button\" ".
1117 "alt=\"poverty - no trump back\" title=\"poverty - no trump back\" />\n";
1120 echo " <img src=\"pics/button/poverty_partner_button.png\" class=\"button\" ".
1121 "alt=\"poverty partner\" title=\"poverty partner\" />\n";
1123 if($gametype_raw=="dpoverty")
1125 if($sickness=="poverty" || ($RULES['lowtrump']=='poverty' && $sickness=='lowtrump'))
1127 $userhash = DB_get_hash_from_gameid_and_userid($gameid,$user);
1128 $cards = DB_get_all_hand($userhash);
1129 $trumpNR = count_trump($cards,'all');
1131 echo " <img src=\"pics/button/poverty_trump_button.png\" class=\"button\" ".
1132 "alt=\"poverty < trump back\" title=\"poverty - trump back\" />\n";
1134 echo " <img src=\"pics/button/poverty_notrump_button.png\" class=\"button\" ".
1135 "alt=\"poverty <\" title=\"poverty - no trump back\" />\n";
1138 echo " <img src=\"pics/button/poverty_partner_button.png\" class=\"button\" ".
1139 "alt=\"poverty >\" title=\"poverty partner\" />\n";
1141 if($sickness=="poverty" || ($RULES['lowtrump']=='poverty' && $sickness=='lowtrump'))
1143 $userhash = DB_get_hash_from_gameid_and_userid($gameid,$user);
1144 $cards = DB_get_all_hand($userhash);
1145 $trumpNR = count_trump($cards,'all');
1147 echo " <img src=\"pics/button/poverty2_trump_button.png\" class=\"button\" ".
1148 "alt=\"poverty2 < trump back\" title=\"poverty2 - trump back\"/>\n";
1150 echo " <img src=\"pics/button/poverty2_notrump_button.png\" class=\"button\" ".
1151 "alt=\"poverty2 <\" title=\"poverty2 - no trump back\" />\n";
1154 echo " <img src=\"pics/button/poverty2_partner_button.png\" class=\"button\" ".
1155 "alt=\"poverty2 >\" title=\"poverty2 partner\" />\n";
1157 if($gametype_raw=="wedding" && $party=="re")
1158 if($sickness=="wedding")
1159 echo " <img src=\"pics/button/wedding_button.png\" class=\"button\" alt=\"wedding\" title=\"wedding\" />\n";
1161 echo " <img src=\"pics/button/wedding_partner_button.png\" class=\"button\" ".
1162 "alt=\"wedding partner\" title=\"wedding partner\" />\n";
1164 if( $gametype_raw=='solo' && $party=="re")
1166 $solotype = DB_get_solo_by_gameid($gameid);
1167 $GT = get_display_gametype($gameid);
1169 if($solotype=='queen')
1170 echo " <img src=\"pics/button/queensolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Queen solo\" />\n";
1171 else if($solotype=='jack')
1172 echo " <img src=\"pics/button/jacksolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Jack solo\" />\n";
1173 else if($solotype=='club')
1174 echo " <img src=\"pics/button/clubsolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Club solo\" />\n";
1175 else if($solotype=='spade')
1176 echo " <img src=\"pics/button/spadesolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Spade solo\" />\n";
1177 else if($solotype=='heart')
1178 echo " <img src=\"pics/button/heartsolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Heart solo\" />\n";
1179 else if($solotype=='trumpless')
1180 echo " <img src=\"pics/button/notrumpsolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Trumpless solo\" />\n";
1181 else if($solotype=='trump')
1182 echo " <img src=\"pics/button/trumpsolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Trump solo\" />\n";
1185 /* add point calls */
1189 echo " <img src=\"pics/button/re_button.png\" class=\"button\" alt=\"re\" title=\"Re\" />\n";
1191 echo " <img src=\"pics/button/contra_button.png\" class=\"button\" alt=\"contra\" title=\"Contra\" />\n";
1195 echo " <img src=\"pics/button/0_button.png\" class=\"button\" alt=\"0\" title=\"Call 0\" />\n";
1198 echo " <img src=\"pics/button/30_button.png\" class=\"button\" alt=\"30\" title=\"Call 30\" />\n";
1201 echo " <img src=\"pics/button/60_button.png\" class=\"button\" alt=\"60\" title=\"Call 60\" />\n";
1204 echo " <img src=\"pics/button/90_button.png\" class=\"button\" alt=\"90\" title=\"Call 90\" />\n";
1209 echo " <img src=\"pics/button/time-info.png\" class=\"button\" alt=\"time info\" ".
1210 "title=\"local time: ".date("Y-m-d H:i:s",$timenow). " ".
1211 "last login: ".date("Y-m-d H:i:s",$lastlogin)."\" />";
1213 echo " <br /><span class=\"numberoftricks\">";
1214 /* show how many tricks the person made */
1218 echo _('#tricks 0'); break;
1220 echo _('#tricks 1'); break;
1224 echo _('#tricks few'); break;
1226 echo _('#tricks many'); break;
1233 function display_user_menu($id, $skiphash=NULL)
1235 global $WIKI,$INDEX;
1238 $result = DB_query("SELECT Hand.hash,Hand.game_id,Game.player from Hand".
1239 " LEFT JOIN Game On Hand.game_id=Game.id".
1240 " WHERE Hand.user_id=".DB_quote_smart($id).
1241 " AND Hand.hash!=".DB_quote_smart($skiphash).
1242 " AND ( Game.player='$id' OR ISNULL(Game.player) )".
1243 " AND ( Game.status='pre' OR Game.status='play' )".
1244 " ORDER BY Game.session" );
1246 $result = DB_query('SELECT Hand.hash,Hand.game_id,Game.player from Hand'.
1247 ' LEFT JOIN Game On Hand.game_id=Game.id'.
1248 ' WHERE Hand.user_id='.DB_quote_smart($id).
1249 ' AND ( Game.player='.DB_quote_smart($id).' OR ISNULL(Game.player) )'.
1250 " AND ( Game.status='pre' OR Game.status='play' )".
1251 ' ORDER BY Game.session' );
1254 while( $r = DB_fetch_array($result))
1258 echo "\n<div class=\"usermenu\">\n ";
1259 echo _('It\'s your turn in these games').":\n";
1267 echo " <a href=\"".$INDEX."?action=game&me=".$r[0].
1268 "\"> ".DB_format_gameid($r[1])." </a>\n";
1281 function generate_score_table($session)
1283 /* returns an array with N entries
1284 * $score[$i]["gameid"] = gameid
1285 * $score[$i]["players"] = array (id=>total points)
1286 * $score[$i]["points"] = points for this game
1287 * $score[$i]["solo"] = 1 or 0
1292 /* get all ids, scores and gametypes */
1293 $gameids = DB_get_gameids_of_finished_games_by_session($session);
1295 if($gameids == NULL)
1299 $player_party = array();
1301 /* get player id from the first game */
1302 $result = DB_query('SELECT user_id from Hand'.
1303 ' WHERE Hand.game_id='.DB_quote_smart($gameids[0][0]));
1304 while( $r = DB_fetch_array($result))
1307 /* get party of players for each game in the session */
1308 foreach($player as $id=>$points)
1309 $player_party[$id]=DB_get_party_by_session_and_userid($session,$id);
1311 /* get points and generate table */
1312 foreach($gameids as $gameid)
1314 $re_score = $gameid[1];
1315 $gametype = $gameid[2];
1316 foreach($player as $id=>$points)
1318 $party = $player_party[$id][$i][0];
1320 if($gametype=='solo')
1321 $player[$id] += 3*$re_score;
1323 $player[$id] += $re_score;
1324 else if ($party == 'contra')
1325 $player[$id] -= $re_score;
1327 $score[$i]['gameid'] = $gameid[0] ;
1328 $score[$i]['players'] = $player;
1329 $score[$i]['points'] = abs($re_score);
1330 $score[$i]['solo'] = ($gametype=='solo');
1338 function generate_global_score_table()
1342 /* get all ids, scores and gametypes */
1343 $gameids = DB_get_gameids_of_finished_games_by_session(0);
1345 if($gameids == NULL)
1349 /* get player id, names... from the User table */
1350 $result = DB_query('SELECT User.id, User.fullname FROM User');
1352 /* save information in an array */
1353 while( $r = DB_fetch_array($result))
1354 $player[$r[0]] = array('name'=> $r[1], 'points' => 0 , 'nr' => 0, 'active' => 0,
1355 'response' => 0 , 'solo' => 0, 'soloavg' => 0);
1357 /* get points and generate table */
1358 foreach($gameids as $gameid)
1360 $re_score = $gameid[1];
1361 $gametype = $gameid[2];
1363 /* get players involved in this game */
1364 $result = DB_query('SELECT user_id FROM Hand WHERE game_id='.DB_quote_smart($gameid[0]));
1365 while($r = DB_fetch_array($result))
1368 $party = DB_get_party_by_gameid_and_userid($gameid[0],$id);
1370 if($gametype=='solo')
1371 $player[$id]['points'] += 3*$re_score;
1373 $player[$id]['points'] += $re_score;
1374 else if ($party == 'contra')
1375 $player[$id]['points'] -= $re_score;
1377 $player[$id]['nr']+=1;
1381 /* add number of active games */
1382 $result = DB_query_array_all("SELECT user_id, COUNT(*) as c " .
1384 " LEFT JOIN Game ON Game.id=game_id".
1385 " WHERE Game.status IN ('pre','play')".
1386 " GROUP BY user_id");
1388 foreach($result as $res)
1390 $player[$res[0]]['active'] = $res[1];
1393 /* response time of users*/
1394 $result = DB_query_array_all("SELECT user_id,".
1395 "IFNULL(AVG(if(P1.sequence in (2,3,4),".
1396 "-timestampdiff(MINUTE,mod_date,(select mod_date from Play P2 where P1.trick_id=P2.trick_id and P2.sequence=P1.sequence-1)),NULL )),1e9) as a ".
1398 "LEFT JOIN Hand_Card ON P1.hand_card_id=Hand_Card.id ".
1399 "LEFT JOIN Hand ON Hand.id=Hand_Card.hand_id ".
1400 "GROUP BY user_id ");
1402 foreach($result as $res)
1404 $player[$res[0]]['response'] = $res[1];
1408 $result = DB_query_array_all("SELECT user_id as uid,".
1410 " COUNT(*)/(SELECT COUNT(*) FROM Hand LEFT JOIN User ON User.id=Hand.user_id WHERE User.id=uid) as c ".
1412 " LEFT JOIN Hand ON Hand.position=startplayer AND Game.id=Hand.game_id ".
1413 " WHERE type='solo' AND Game.status='gameover' ".
1414 " GROUP BY user_id ");
1416 foreach($result as $res)
1418 $player[$res[0]]['solo'] = $res[1];
1419 $player[$res[0]]['soloavg'] = $res[2];
1423 /* sort everything nicely */
1427 if($a['nr']==0) return 1;
1428 if($b['nr']==0) return 1;
1430 $a=$a['points']/$a['nr'];
1431 $b=$b['points']/$b['nr'];
1435 return ($a > $b) ? -1 : 1;
1437 usort($player,'cmp');
1440 foreach($player as $pl)
1442 /* limit to players with at least 10 games */
1444 $return[] = array( $pl['name'], round($pl['points']/$pl['nr'],3), $pl['points'],$pl['nr'],$pl['active'],
1445 $pl['response'],$pl['solo'],$pl['soloavg']);
1451 function format_score_table_ascii($score)
1454 if(sizeof($score)==0)
1457 /* truncate table if we have too many games */
1458 $max = sizeof($score);
1459 if($max>6) $output.=" "._("(table truncated to last 6 games)")."\n";
1462 foreach($score[0]['players'] as $id=>$points)
1464 $name = DB_get_name('userid',$id); /*TODO*/
1465 $output.= " ".substr($name,0,2)." |";
1468 $output.= "------+------+------+------+------+\n";
1470 /* output score for each game */
1472 foreach($score as $game)
1475 if($i-1<$max-6) continue;
1477 foreach($game['players'] as $id=>$points)
1478 $output.=str_pad($points,6," ",STR_PAD_LEFT)."|";
1479 $output.=str_pad($game['points'],4," ",STR_PAD_LEFT);
1481 /* check for solo */
1492 function format_score_table_html($score,$userid)
1496 if(sizeof($score)==0)
1499 $output = "<div class=\"scoretable\">\n<table class=\"score\">\n";
1503 $header.= " <thead>\n <tr>\n";
1504 $header.= " <th> No </th>";
1505 foreach($score[0]['players'] as $id=>$points)
1507 $name = DB_get_name('userid',$id); /*TODO*/
1508 $header.= "<th> ".substr($name,0,2)." </th>";
1510 $header.="<th>P</th>\n </tr>\n </thead>\n";
1512 /* use the same as footer */
1514 $footer.= " <tfoot>\n <tr>\n";
1515 $footer.= " <td> No </td>";
1516 foreach($score[0]['players'] as $id=>$points)
1518 $name = DB_get_name('userid',$id); /*TODO*/
1519 $footer.= "<td> ".substr($name,0,2)." </td>";
1521 $footer.="<td>P</td>\n </tr>\n </tfoot>\n";
1525 $body.= " <tbody>\n";
1527 foreach($score as $game)
1531 $userhash = DB_get_hash_from_gameid_and_userid($game['gameid'],$userid);
1532 /* create link to old games only if you are logged in and its your game*/
1533 if(isset($_SESSION['id']) && $_SESSION['id']==$userid)
1534 $body.=" <td> <a href=\"".$INDEX."?action=game&me=".$userhash."\">$i</a></td>";
1536 $body.=" <td>$i</td>";
1538 foreach($game['players'] as $id=>$points)
1539 $body.="<td>".$points."</td>";
1540 $body.="<td>".$game['points'];
1542 /* check for solo */
1545 $body.="</td></tr>\n";
1553 $output.=" </tbody>\n</table>\n</div>\n";
1558 function createCache($content, $cacheFile)
1560 $fp = fopen($cacheFile,"w");
1563 fwrite($fp,$content);
1567 echo "WARNING: couldn't create cache file";
1572 function getCache($cacheFile, $expireTime)
1574 if( file_exists($cacheFile) &&
1575 filemtime($cacheFile )>( time() - $expireTime ) )
1577 return file_get_contents($cacheFile);
1583 function check_vacation($userid)
1585 /* get start date */
1586 $result = DB_query_array("SELECT value FROM User_Prefs".
1587 " WHERE user_id=".DB_quote_smart($userid)." AND pref_key='vacation start'" );
1589 $start = $result[0];
1594 $result = DB_query_array("SELECT value FROM User_Prefs".
1595 " WHERE user_id=".DB_quote_smart($userid)." AND pref_key='vacation stop'" );
1602 $result = DB_query_array("SELECT value FROM User_Prefs".
1603 " WHERE user_id=".DB_quote_smart($userid)." AND pref_key='vacation comment'" );
1605 $comment = $result[0];
1609 /* check if user is on vacation. TODO: use user's timezone */
1610 if( (time() - strtotime($start) >0) &&
1611 (strtotime($stop) - time() >0))
1612 return array ($start,$stop,$comment);
1617 function cancel_game($why,$gameid)
1619 $gameid = DB_quote_smart($gameid);
1621 /* update the game table */
1625 DB_query("UPDATE Game SET status='cancel-timedout' WHERE id=$gameid");
1628 DB_query("UPDATE Game SET status='cancel-nines' WHERE id=$gameid");
1631 DB_query("UPDATE Game SET status='cancel-trump' WHERE id=$gameid");
1634 DB_query("UPDATE Game SET status='cancel-noplay' WHERE id=$gameid");
1637 DB_query("UPDATE Game SET status='cancel-lowtrump' WHERE id=$gameid");
1640 /* set each player to gameover */
1641 $result = DB_query("SELECT id FROM Hand WHERE game_id=".DB_quote_smart($gameid));
1642 while($r = DB_fetch_array($result))
1645 DB_query("UPDATE Hand SET status='gameover' WHERE id=".DB_quote_smart($id));
1651 function get_user_token($userid)
1656 $date = DB_get_user_creation_date($userid);
1657 $name = DB_get_name('userid',$userid);
1660 $token = md5("token".$name.$date);
1665 function verify_password($email, $password)
1667 /* verify password, if old password has length 32 assume it's an old md5, else use new password scheme */
1668 /* return 0 if verified, else return error code
1669 * 1 can't find email
1670 * 2 can't calculate correct hash
1674 /* check user email by getting his id */
1675 $userid = DB_get_userid('email',$email);
1679 /* test for temporary passwords, only valid for one date (tested in the DB) */
1680 $tmppasswd = md5($password);
1681 if(DB_check_recovery_passwords($tmppasswd,$email))
1684 /* get saved password */
1685 $existingpassword = DB_get_passwd_by_userid($userid);
1687 if(strlen($existingpassword)==32) /* old password type */
1689 if ($existingpassword == md5($password))
1691 /* update password to new crypt version */
1692 // create a password hash using the crypt function, need php 5.3 for this
1693 // create and random salt
1694 $salt = substr(str_replace('+', '.', base64_encode(sha1(microtime(true), true))), 0, 22);
1695 // hash incoming password using 12 rounds of blowfish
1696 $hash = crypt($password, '$2y$12$' . $salt);
1697 if(strlen($hash)>13)
1698 DB_query("UPDATE User SET password='$hash' where id='$userid'");
1707 if ($existingpassword == crypt($password, $existingpassword))
1714 /* language functions */
1715 function detectlanguage()
1717 /* read out browser's prefered language, taken from php-manual*/
1718 $langcode = explode(";", $_SERVER['HTTP_ACCEPT_LANGUAGE']);
1719 $langcode = explode(",", $langcode['0']);
1720 return $langcode['0'];
1723 function set_language($l,$type='lang')
1727 $userPREF = DB_get_PREF($l);
1728 $l = $userPREF['language'];
1734 putenv("LC_ALL=de_DE");
1735 setlocale(LC_ALL, "de_DE");
1738 putenv("LC_ALL=en_US");
1739 setlocale(LC_ALL, "en_US");
1743 // Specify location of translation tables
1744 bindtextdomain("edoko", "./locale");
1745 bind_textdomain_codeset("edoko", 'UTF-8');
1747 textdomain("edoko");
1752 function get_display_gametype($gameid)
1754 /* return a readable string that can be displayed to show the game type
1755 * this means hiding silent solo from the user
1758 $gametype = DB_get_gametype_by_gameid($gameid);
1760 if ($gametype == 'normal')
1762 else if($gametype=='solo')
1764 $solotype = DB_get_solo_by_gameid($gameid);
1769 $GT = _('trumpless solo');
1772 $GT = _('jack solo');
1775 $GT = _('queen solo');
1778 $GT = _('trump solo');
1781 $GT = _('club solo');
1784 $GT = _('spade solo');
1787 $GT = _('heart solo');
1790 $GT = _('normal'); /* this is change compared to $gametype */
1794 else if ($gametype == 'wedding')
1796 else if ($gametype == 'poverty')
1798 else if ($gametype == 'dpoverty')
1799 $GT = _('double poverty');