2 /* Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 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 $header = sprintf(_('Hello %s'),$name);
129 $To = DB_get_email('userid',$user);
131 /* check if user wants email right away or if we should save it in
132 * the database for later delivery
135 $uidPREF = DB_get_PREF($user);
136 if( $uidPREF['digest'] != 'digest-off' )
138 /* use local language */
139 set_language($uidPREF['language']);
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);
204 /* reset language to original user*/
205 set_language($PREF['language']);
210 function sendmail($To,$Subject,$message)
212 /* this function sends the mail or outputs to the screen in case of debugging */
213 global $debug,$EMAIL_REPLY;
217 if(isset($EMAIL_REPLY))
218 $header .= "From: e-DoKo daemon <$EMAIL_REPLY>\r\n";
222 /* display email on screen,
225 $message = str_replace("\n","<br />\n",$message);
226 $message = preg_replace("#(\w+://[^<>\s]+[\w/]*)#",
227 "<a href=\"$1\">$1</a>", $message);
229 echo "<br />To: $To<br />";
231 echo $header."<br />";
232 echo "Subject: $Subject <br />$message<br />\n";
236 mail($To,$Subject,$message,$header);
238 mail($To,$Subject,$message);
244 /* returns 1 if all names passed as args are defined by a GET or POST statement,
249 $args = func_get_args();
251 foreach($args as $arg)
253 $ok = $ok * isset($_REQUEST[$arg]);
254 /*echo "$arg: ok = $ok <br />";
260 function myerror($message)
262 echo "<span class=\"error\">".htmlspecialchars($message)."</span>\n";
263 sendmail($ADMIN_EMAIL,$EmailName." Error in Code",$message);
267 function pos_array($c,$arr)
284 function is_trump($c)
288 if(in_array($c,$CARDS["trump"]))
294 function is_same_suite($c1,$c2)
298 if(in_array($c1,$CARDS["trump"] ) && in_array($c2,$CARDS["trump"] ) ) return 1;
299 if(in_array($c1,$CARDS["clubs"] ) && in_array($c2,$CARDS["clubs"] ) ) return 1;
300 if(in_array($c1,$CARDS["hearts"] ) && in_array($c2,$CARDS["hearts"] ) ) return 1;
301 if(in_array($c1,$CARDS["spades"] ) && in_array($c2,$CARDS["spades"] ) ) return 1;
302 if(in_array($c1,$CARDS["diamonds"]) && in_array($c2,$CARDS["diamonds"]) ) return 1;
307 function compare_cards($a,$b,$game)
309 /* if "a" is higher than "b" return 1, else 0, "a" being the card first played */
315 /* first map all cards to the odd number,
316 * this insure that the first card wins the trick
317 * if they are the same card
319 if( $a/2 - (int)($a/2) != 0.5)
321 if( $b/2 - (int)($b/2) != 0.5)
324 /* check for schweinchen and ten of hearts*/
330 if($RULES['schweinchen']=='both' && $GAME['schweinchen-who'])
332 if($a == 19 || $a == 20 )
334 if($b == 19 || $b == 20 )
337 else if($RULES['schweinchen']=='second' && $GAME['schweinchen-second'])
339 if($a == 19 || $a == 20 )
341 if($b == 19 || $b == 20 )
344 else if($RULES['schweinchen']=='secondaftercall' && $GAME['schweinchen-who'] && $GAME['schweinchen-second'] )
346 /* check if a call was made either by the player or his partner. If so activate Schweinchen rule. */
347 if(DB_get_call_by_hash($GAME['schweinchen-who']) || DB_get_partner_call_by_hash($GAME['schweinchen-who']) )
349 if($a == 19 || $a == 20 )
351 if($b == 19 || $b == 20 )
354 /* if not, do nothing and the foxes are just handeled as normal trump */
360 /* check for ten of hearts rule */
361 if($RULES["dullen"]=="secondwins")
362 if($a==1 && $b==1) /* both 10 of hearts */
363 return 0; /* second one wins.*/
367 /* no special cases here */
371 if(is_trump($a) && is_trump($b) && $a<=$b)
373 else if(is_trump($a) && is_trump($b) )
376 { /*$a is not a trump */
380 { /* both no trump */
383 $posA = pos_array($a,$CARDS["clubs"]);
384 $posB = pos_array($b,$CARDS["clubs"]);
392 $posA = pos_array($a,$CARDS["spades"]);
393 $posB = pos_array($b,$CARDS["spades"]);
401 $posA = pos_array($a,$CARDS["hearts"]);
402 $posB = pos_array($b,$CARDS["hearts"]);
410 $posA = pos_array($a,$CARDS["diamonds"]);
411 $posB = pos_array($b,$CARDS["diamonds"]);
418 /* not the same suit and no trump: a wins */
424 function get_winner($p,$mode)
426 /* get all 4 cards played in a trick, in the order they are played */
429 $c1pos = $tmp["pos"];
433 $c2pos = $tmp["pos"];
437 $c3pos = $tmp["pos"];
441 $c4pos = $tmp["pos"];
443 /* first card is better than all the rest */
444 if( compare_cards($c1,$c2,$mode) && compare_cards($c1,$c3,$mode) && compare_cards($c1,$c4,$mode) )
447 /* second card is better than first and better than the rest */
448 if( !compare_cards($c1,$c2,$mode) && compare_cards($c2,$c3,$mode) && compare_cards($c2,$c4,$mode) )
451 /* third card is better than first card and better than last */
452 if( !compare_cards($c1,$c3,$mode) && compare_cards($c3,$c4,$mode) )
453 /* if second card is better than first, third card needs to be even better */
454 if( !compare_cards($c1,$c2,$mode) && !compare_cards($c2,$c3,$mode) )
456 /* second is worse than first, e.g. not following suite */
457 else if (compare_cards($c1,$c2,$mode) )
460 /* non of the above */
464 function count_nines($cards)
468 foreach($cards as $c)
470 if($c == "25" || $c == "26") $nines++;
471 else if($c == "33" || $c == "34") $nines++;
472 else if($c == "41" || $c == "42") $nines++;
473 else if($c == "47" || $c == "48") $nines++;
479 function check_wedding($cards)
482 if( in_array("3",$cards) && in_array("4",$cards) )
488 function count_trump($cards,$status='pregame')
494 /* count each trump, including the foxes, since this is used to determine poverty status */
495 foreach($cards as $c)
499 /* In case we really want to know the amount of trump, we can use the status variable.
500 * This is needed for example to figure out what icon to display on the table in case of
501 * trump given back in poverty */
502 if($status=='all') return $trump;
504 /* normally foxes don't count as trump, so we substract them here
505 * in case someone has schweinchen, one or two of them should count as trump
506 * though, so we need to add one trump for those cases */
509 if( in_array("19",$cards))
511 if( in_array("20",$cards) )
514 /* handle case where player has schweinchen */
515 if( in_array("19",$cards) && in_array("20",$cards) )
516 switch($RULES["schweinchen"])
519 /* add two, in case the player has both foxes (schweinchen) */
524 case "secondaftercall":
525 /* add one, in case the player has both foxes (schweinchen) */
535 function check_low_trump($cards)
539 if($RULES['lowtrump']=='none')
542 /* check if we have low trump */
545 foreach($cards as $card)
547 /* card a trump, but not a diamond? */
552 /* handle case where player has schweinchen */
553 if( in_array("19",$cards) && in_array("20",$cards) )
554 switch($RULES["schweinchen"])
558 case "secondaftercall":
568 function create_array_of_random_numbers($useridA,$useridB,$useridC,$useridD)
576 /* fix the hands; makes debugging easier; the following hands have lots of sicknesses,
577 * to make testing easier
579 $r[ 0]=1; $r[12]=47; $r[24]=13; $r[36]=37;
580 $r[ 1]=2; $r[13]=23; $r[25]=14; $r[37]=38;
581 $r[ 2]=3; $r[14]=27; $r[26]=15; $r[38]=39;
582 $r[ 3]=4; $r[15]=16; $r[27]=28; $r[39]=40;
583 $r[ 4]=5; $r[16]=17; $r[28]=29; $r[40]=21;
584 $r[ 5]=18; $r[17]=6; $r[29]=30; $r[41]=42;
585 $r[ 6]=41; $r[18]=7; $r[30]=31; $r[42]=43;
586 $r[ 7]=22; $r[19]=8; $r[31]=32; $r[43]=20;
587 $r[ 8]=45; $r[20]=9; $r[32]=33; $r[44]=19;
588 $r[ 9]=46; $r[21]=10; $r[33]=44; $r[45]=24;
589 $r[10]=35; $r[22]=11; $r[34]=48; $r[46]=25;
590 $r[11]=36; $r[23]=12; $r[35]=34; $r[47]=26;
594 /* check if we can find a game were non of the player was involved and return
597 $userstr = "'".implode("','",array($useridA,$useridB,$useridC,$useridD))."'";
598 $randomnumbers = DB_get_unused_randomnumbers($userstr);
599 $randomnumbers = explode(":",$randomnumbers);
601 if(sizeof($randomnumbers)==48)
602 return $randomnumbers;
604 /* need to create new numbers */
608 /* shuffle using a better random generator than the standard one */
609 for ($i = 0; $i <48; $i++)
611 $j = @mt_rand(0, $i);
621 function display_cards($me,$myturn)
626 function have_suit($cards,$c)
631 if(in_array($c,$CARDS["trump"]))
632 $suite = $CARDS["trump"];
633 else if(in_array($c,$CARDS["clubs"]))
634 $suite = $CARDS["clubs"];
635 else if(in_array($c,$CARDS["spades"]))
636 $suite = $CARDS["spades"];
637 else if(in_array($c,$CARDS["hearts"]))
638 $suite = $CARDS["hearts"];
639 else if(in_array($c,$CARDS["diamonds"]))
640 $suite = $CARDS["diamonds"];
642 foreach($cards as $card)
644 if(in_array($card,$suite))
651 function same_type($card,$c)
656 /* figure out what kind of card c is */
657 if(in_array($c,$CARDS["trump"]))
658 $suite = $CARDS["trump"];
659 else if(in_array($c,$CARDS["clubs"]))
660 $suite = $CARDS["clubs"];
661 else if(in_array($c,$CARDS["spades"]))
662 $suite = $CARDS["spades"];
663 else if(in_array($c,$CARDS["hearts"]))
664 $suite = $CARDS["hearts"];
665 else if(in_array($c,$CARDS["diamonds"]))
666 $suite = $CARDS["diamonds"];
668 /* card is the same suid return 1 */
669 if(in_array($card,$suite))
675 function set_gametype($gametype)
689 $CARDS["trump"] = array('1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16',
690 '17','18','19','20','21','22','23','24','25','26');
691 $CARDS["diamonds"] = array();
692 $CARDS["clubs"] = array('27','28','29','30','31','32','33','34');
693 $CARDS["spades"] = array('35','36','37','38','39','40','41','42');
694 $CARDS["hearts"] = array('43','44','45','46','47','48');
695 $CARDS["foxes"] = array('19','20');
696 if($RULES["dullen"]=='none')
698 $CARDS["trump"] = array('3','4','5','6','7','8','9','10','11','12','13','14','15','16',
699 '17','18','19','20','21','22','23','24','25','26');
700 $CARDS["hearts"] = array('43','44','1','2','45','46','47','48');
702 /* do we need to reorder for Schweinchen? need to search for it because of special case for dullen above*/
703 if($RULES['schweinchen']=='both'&& $GAME['schweinchen-who'])
705 /* find the fox and put them at the top of the stack */
706 foreach(array('19','20') as $fox)
709 $trump = $CARDS['trump'];
710 $key = array_keys($trump, $fox);
714 $foxa[]=$trump[$key[0]];
715 unset($trump[$key[0]]);
716 $trump = array_merge($foxa,$trump);
717 $CARDS['trump'] = $trump;
720 else if( ($RULES['schweinchen']=='second' || $RULES['schweinchen']=='secondaftercall')
721 && $GAME['schweinchen-who'])
723 /* find the fox and put them at the top of the stack */
724 $trump = $CARDS['trump'];
725 $key = array_keys($trump, '19');
729 $foxa[]=$trump[$key[0]];
730 unset($trump[$key[0]]);
731 $trump = array_merge($foxa,$trump);
732 $CARDS['trump'] = $trump;
736 $CARDS["trump"] = array('3','4','5','6','7','8','9','10');
737 $CARDS["clubs"] = array('27','28','29','30','31','32','11','12','33','34');
738 $CARDS["spades"] = array('35','36','37','38','39','40','13','14','41','42');
739 $CARDS["hearts"] = array('43','44', '1', '2','45','46','15','16','47','48');
740 $CARDS["diamonds"] = array('19','20','21','22','23','24','17','18','25','26');
741 $CARDS["foxes"] = array();
744 $CARDS["trump"] = array('11','12','13','14','15','16','17','18');
745 $CARDS["clubs"] = array('27','28','29','30','31','32','3', '4','33','34');
746 $CARDS["spades"] = array('35','36','37','38','39','40','5', '6','41','42');
747 $CARDS["hearts"] = array('43','44', '1', '2','45','46','7', '8','47','48');
748 $CARDS["diamonds"] = array('19','20','21','22','23','24','9','10','25','26');
749 $CARDS["foxes"] = array();
752 $CARDS["trump"] = array();
753 $CARDS["clubs"] = array('27','28','29','30','31','32','3', '4','11','12','33','34');
754 $CARDS["spades"] = array('35','36','37','38','39','40','5', '6','13','14','41','42');
755 $CARDS["hearts"] = array('43','44', '1', '2','45','46','7', '8','15','16','47','48');
756 $CARDS["diamonds"] = array('19','20','21','22','23','24','9','10','17','18','25','26');
757 $CARDS["foxes"] = array();
760 $CARDS["trump"] = array('1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16',
761 '17','18','27','28','29','30','31','32','33','34');
762 $CARDS["clubs"] = array();
763 $CARDS["spades"] = array('35','36','37','38','39','40','41','42');
764 $CARDS["hearts"] = array('43','44','45','46','47','48');
765 $CARDS["diamonds"] = array('19','20','21','22','23','24','25','26');
766 $CARDS["foxes"] = array();
767 if($RULES["dullen"]=='none')
769 $CARDS["trump"] = array('3','4','5','6','7','8','9','10','11','12','13','14','15','16',
770 '17','18','27','28','29','30','31','32','33','34');
771 $CARDS["hearts"] = array('43','44','1','2','45','46','47','48');
775 $CARDS["trump"] = array('1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16',
776 '17','18','35','36','37','38','39','40','41','42');
777 $CARDS["clubs"] = array('27','28','29','30','31','32','33','34');
778 $CARDS["spades"] = array();
779 $CARDS["hearts"] = array('43','44','45','46','47','48');
780 $CARDS["diamonds"] = array('19','20','21','22','23','24','25','26');
781 $CARDS["foxes"] = array();
782 if($RULES["dullen"]=='none')
784 $CARDS["trump"] = array('3','4','5','6','7','8','9','10','11','12','13','14','15','16',
785 '17','18','35','36','37','38','39','40','41','42');
786 $CARDS["hearts"] = array('43','44','1','2','45','46','47','48');
790 $CARDS["trump"] = array('1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16',
791 '17','18','43','44','45','46','47','48');
792 $CARDS["clubs"] = array('27','28','29','30','31','32','33','34');
793 $CARDS["spades"] = array('35','36','37','38','39','40','41','42');
794 $CARDS["hearts"] = array();
795 $CARDS["diamonds"] = array('19','20','21','22','23','24','25','26');
796 $CARDS["foxes"] = array();
797 if($RULES["dullen"]=='none')
799 $CARDS["trump"] = array('3','4','5','6','7','8','9','10','11','12','13','14','15','16',
800 '17','18','43','44','1','2','45','46','47','48');
806 function mysort($cards,$gametype)
809 if(isset($PREF['sorting']))
810 if($PREF['sorting']=='high-low')
811 usort ( $cards, 'sort_comp_high_low' );
813 usort ( $cards, 'sort_comp_low_high' );
815 usort ( $cards, 'sort_comp_high_low' );
819 function sort_comp_high_low($a,$b)
824 $ALL = array_merge($CARDS['trump'],$CARDS['diamonds'],$CARDS['clubs'],
825 $CARDS['hearts'],$CARDS['spades']);
827 return pos_array($a,$ALL)-pos_array($b,$ALL);
830 function sort_comp_low_high($a,$b)
835 $ALL = array_merge($CARDS['trump'],$CARDS['diamonds'],$CARDS['clubs'],
836 $CARDS['hearts'],$CARDS['spades']);
838 return -pos_array($a,$ALL)+pos_array($b,$ALL);
841 function can_call($what,$hash)
843 /* figure out if a person can make a call:
844 $what in 0,30,60,90,120 = points of the call
845 $hash = the hash of the person who wants to make the call
848 0 can't make that call
850 2 can make the call, but this is the last chance to do so...
855 /* get some information
857 $gameid = DB_get_gameid_by_hash($hash);
858 $gametype = DB_get_gametype_by_gameid($gameid);
859 $oldcall = DB_get_call_by_hash($hash); /* did the person already made a call? */
860 $pcall = DB_get_partner_call_by_hash($hash); /* did the partner already made a call */
863 /* you're call must be better than the one you or your partner already made
865 if( ($pcall!=NULL && ($what >= $pcall))
866 || ($oldcall!=NULL && ($what >=$oldcall)) )
871 /* for some rules we need to know how many cards people have
873 $NRcards = count(DB_get_hand($hash));
878 $user = DB_get_hash_from_game_and_pos($gameid,$i);
879 $NRallcards += count(DB_get_hand($user));
882 /* in case of a wedding, everything will be delayed by an offset
885 if($gametype=="wedding")
887 $offset = DB_get_sickness_by_gameid($gameid);
888 if ($offset <0) /* not resolved */
892 /* now check if the call is allowed depending on the rule set
894 switch ($RULES["call"])
897 /* calls can be made before/while you play your card...
898 * first card = 120, second card = 90, etc.
900 if( 4-($what/30) == 12 - ($NRcards + $offset))
902 if( 4-($what/30) > 12 - ($NRcards + $offset))
906 /* you can make the first call anytime during the first trick
908 if( 27+4*($what/30) == $NRallcards + $offset*4)
910 if( 27+4*($what/30) < $NRallcards + $offset*4)
914 /* you can call 120 with 12 cards, 90 with 9 or more cards, 60 with 6 or more, etc.
915 * you can't skip a call though
918 /* figure out last call
920 if($oldcall!=NULL && $pcall!=NULL)
921 $mincall = ($oldcall>$pcall) ? $pcall : $oldcall;
922 else if($oldcall!=NULL)
924 else if ($pcall!=NULL)
930 if( 12 == ($NRcards + $offset))
934 else if( 12 < ($NRcards + $offset))
938 else if ( 9 == ($NRcards + $offset))
940 if( ($mincall>=0 && $mincall<=120 && $what<=90 ) )
943 else if ( 9 < ($NRcards + $offset))
945 if( ($mincall>=0 && $mincall<=120 && $what<=90 ) )
948 else if ( 6 == ($NRcards + $offset))
950 if( ($mincall>=0 && $mincall<=90 && $what<=60 ) )
953 else if ( 6 < ($NRcards + $offset))
955 if( ($mincall>=0 && $mincall<=90 && $what<=60 ) )
958 else if ( 3 == ($NRcards + $offset))
960 if( ($mincall>=0 && $mincall<=60 && $what<=30 ) )
963 else if ( 3 < ($NRcards + $offset))
965 if( ($mincall>=0 && $mincall<=60 && $what<=30 ) )
968 else if ( 0 == ($NRcards + $offset))
970 if( ($mincall>=0 && $mincall<=30 && $what==0 ) )
973 else if ( 0 < ($NRcards + $offset))
975 if( ($mincall>=0 && $mincall<=30 && $what==0 ) )
984 function display_table_begin ()
986 global $gameid, $GT, $debug,$INDEX,$defaulttimezone,$session;
987 global $RULES,$GAME,$gametype;
989 $result = DB_query("SELECT User.fullname as name,".
990 " Hand.position as position, ".
992 " Hand.party as party, ".
993 " Hand.sickness as sickness, ".
994 " Hand.point_call, ".
995 " User.last_login, ".
1000 "LEFT JOIN User ON User.id=Hand.user_id ".
1001 "WHERE Hand.game_id='".$gameid."' ".
1002 "ORDER BY position ASC");
1004 $row0 = DB_fetch_array($result);
1005 $row1 = DB_fetch_array($result);
1006 $row2 = DB_fetch_array($result);
1007 $row3 = DB_fetch_array($result);
1009 echo "<div class=\"table\">\n";
1010 display_single_user($row1);
1011 echo "\n<div class=\"middle\">\n";
1012 display_single_user($row0,1); /* mark starting player in case re/contra is not set yet */
1013 echo " <img class=\"table\" src=\"pics/table.png\" alt=\"table\" />\n";
1014 display_single_user($row2);
1018 function display_table_end ()
1020 global $gameid, $GT, $debug,$INDEX,$defaulttimezone,$session;
1021 global $RULES,$GAME,$gametype;
1023 $result = DB_query("SELECT User.fullname as name,".
1024 " Hand.position as position, ".
1026 " Hand.party as party, ".
1027 " Hand.sickness as sickness, ".
1028 " Hand.point_call, ".
1029 " User.last_login, ".
1034 "LEFT JOIN User ON User.id=Hand.user_id ".
1035 "WHERE Hand.game_id='".$gameid."' ".
1036 "ORDER BY position ASC");
1038 $row0 = DB_fetch_array($result);
1039 $row1 = DB_fetch_array($result);
1040 $row2 = DB_fetch_array($result);
1041 $row3 = DB_fetch_array($result);
1044 display_single_user($row3);
1050 function display_single_user($r,$start=0)
1052 /* start=1, mark starting player, default=0, so the player on the left is not marked */
1054 global $gameid, $GT, $debug,$INDEX,$defaulttimezone,$session;
1055 global $RULES,$GAME,$gametype;
1066 $wins = DB_get_number_of_tricks($gameid,$pos);
1067 date_default_timezone_set($defaulttimezone);
1068 $lastlogin = strtotime($r[6]);
1069 date_default_timezone_set($timezone);
1070 $timenow = strtotime(date("Y-m-d H:i:s"));
1071 $gravatar = "$name<br />\n <img class=\"gravatar\" title=\"$name\" src=\"http://www.gravatar.com/avatar/".
1072 md5(strtolower(trim($email)))."?d=identicon\" alt=\"$name's gravatar\" />";
1074 echo " <div class=\"table".($pos-1)."\">\n";
1076 /* mark starting player */
1077 if($start && ! ($party=="re" || $party=="contra"))
1078 echo ' <span class="start">'._('Starting Player')."</span> <br />\n";
1081 echo " <a href=\"".$INDEX."?action=game&me=".$hash."\">";
1082 if($vacation = check_vacation($user))
1084 $start = $vacation[0];
1085 $stop = substr($vacation[1],0,10);
1086 $comment = $vacation[2];
1088 $title = "begin: $start end: $stop $comment";
1089 echo " <span class=\"vacation\" title=\"$title\">$gravatar (on vacation until $stop)</span> \n";
1092 echo " $gravatar \n";
1096 /* add hints for poverty, wedding, solo, etc */
1097 if( $gametype != "solo")
1098 if( $RULES["schweinchen"]=="both" && $GAME["schweinchen-who"]==$hash )
1099 echo " Schweinchen. <br />";
1101 if($GT=="poverty" && $party=="re")
1102 if($sickness=="poverty" || ($RULES['lowtrump']=='poverty' && $sickness=='lowtrump'))
1104 $userhash = DB_get_hash_from_gameid_and_userid($gameid,$user);
1105 $cards = DB_get_all_hand($userhash);
1106 $trumpNR = count_trump($cards,'all');
1108 echo " <img src=\"pics/button/poverty_trump_button.png\" class=\"button\" ".
1109 "alt=\"poverty - trump back\" title=\"poverty - trump back\" />\n";
1111 echo " <img src=\"pics/button/poverty_notrump_button.png\" class=\"button\" ".
1112 "alt=\"poverty - no trump back\" title=\"poverty - no trump back\" />\n";
1115 echo " <img src=\"pics/button/poverty_partner_button.png\" class=\"button\" ".
1116 "alt=\"poverty partner\" title=\"poverty partner\" />\n";
1120 if($sickness=="poverty" || ($RULES['lowtrump']=='poverty' && $sickness=='lowtrump'))
1122 $userhash = DB_get_hash_from_gameid_and_userid($gameid,$user);
1123 $cards = DB_get_all_hand($userhash);
1124 $trumpNR = count_trump($cards,'all');
1126 echo " <img src=\"pics/button/poverty_trump_button.png\" class=\"button\" ".
1127 "alt=\"poverty < trump back\" title=\"poverty - trump back\" />\n";
1129 echo " <img src=\"pics/button/poverty_notrump_button.png\" class=\"button\" ".
1130 "alt=\"poverty <\" title=\"poverty - no trump back\" />\n";
1133 echo " <img src=\"pics/button/poverty_partner_button.png\" class=\"button\" ".
1134 "alt=\"poverty >\" title=\"poverty partner\" />\n";
1136 if($sickness=="poverty" || ($RULES['lowtrump']=='poverty' && $sickness=='lowtrump'))
1138 $userhash = DB_get_hash_from_gameid_and_userid($gameid,$user);
1139 $cards = DB_get_all_hand($userhash);
1140 $trumpNR = count_trump($cards,'all');
1142 echo " <img src=\"pics/button/poverty2_trump_button.png\" class=\"button\" ".
1143 "alt=\"poverty2 < trump back\" title=\"poverty2 - trump back\"/>\n";
1145 echo " <img src=\"pics/button/poverty2_notrump_button.png\" class=\"button\" ".
1146 "alt=\"poverty2 <\" title=\"poverty2 - no trump back\" />\n";
1149 echo " <img src=\"pics/button/poverty2_partner_button.png\" class=\"button\" ".
1150 "alt=\"poverty2 >\" title=\"poverty2 partner\" />\n";
1152 if($GT=="wedding" && $party=="re")
1153 if($sickness=="wedding")
1154 echo " <img src=\"pics/button/wedding_button.png\" class=\"button\" alt=\"wedding\" title=\"wedding\" />\n";
1156 echo " <img src=\"pics/button/wedding_partner_button.png\" class=\"button\" ".
1157 "alt=\"wedding partner\" title=\"wedding partner\" />\n";
1159 if( (strpos($GT,"solo")!==false) && $party=="re")
1161 if(strpos($GT,"queen")!==false)
1162 echo " <img src=\"pics/button/queensolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Queen solo\" />\n";
1163 else if(strpos($GT,"jack")!==false)
1164 echo " <img src=\"pics/button/jacksolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Jack solo\" />\n";
1165 else if(strpos($GT,"club")!==false)
1166 echo " <img src=\"pics/button/clubsolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Club solo\" />\n";
1167 else if(strpos($GT,"spade")!==false)
1168 echo " <img src=\"pics/button/spadesolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Spade solo\" />\n";
1169 else if(strpos($GT,"heart")!==false)
1170 echo " <img src=\"pics/button/heartsolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Heart solo\" />\n";
1171 else if(strpos($GT,"trumpless")!==false)
1172 echo " <img src=\"pics/button/notrumpsolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Trumpless solo\" />\n";
1173 else if(strpos($GT,"trump")!==false)
1174 echo " <img src=\"pics/button/trumpsolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Trump solo\" />\n";
1177 /* add point calls */
1181 echo " <img src=\"pics/button/re_button.png\" class=\"button\" alt=\"re\" title=\"Re\" />\n";
1183 echo " <img src=\"pics/button/contra_button.png\" class=\"button\" alt=\"contra\" title=\"Contra\" />\n";
1187 echo " <img src=\"pics/button/0_button.png\" class=\"button\" alt=\"0\" title=\"Call 0\" />\n";
1190 echo " <img src=\"pics/button/30_button.png\" class=\"button\" alt=\"30\" title=\"Call 30\" />\n";
1193 echo " <img src=\"pics/button/60_button.png\" class=\"button\" alt=\"60\" title=\"Call 60\" />\n";
1196 echo " <img src=\"pics/button/90_button.png\" class=\"button\" alt=\"90\" title=\"Call 90\" />\n";
1201 echo " <img src=\"pics/button/time-info.png\" class=\"button\" alt=\"time info\" ".
1202 "title=\"local time: ".date("Y-m-d H:i:s",$timenow). " ".
1203 "last login: ".date("Y-m-d H:i:s",$lastlogin)."\" />";
1205 echo " <br /><span class=\"numberoftricks\">";
1206 /* show how many tricks the person made */
1210 echo _('#tricks 0'); break;
1212 echo _('#tricks 1'); break;
1216 echo _('#tricks few'); break;
1218 echo _('#tricks many'); break;
1225 function display_user_menu($id, $skiphash=NULL)
1227 global $WIKI,$INDEX;
1230 $result = DB_query("SELECT Hand.hash,Hand.game_id,Game.player from Hand".
1231 " LEFT JOIN Game On Hand.game_id=Game.id".
1232 " WHERE Hand.user_id='$id'".
1233 " AND Hand.hash!='$skiphash'".
1234 " AND ( Game.player='$id' OR ISNULL(Game.player) )".
1235 " AND ( Game.status='pre' OR Game.status='play' )".
1236 " ORDER BY Game.session" );
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='$id'".
1241 " AND ( Game.player='$id' OR ISNULL(Game.player) )".
1242 " AND ( Game.status='pre' OR Game.status='play' )".
1243 " ORDER BY Game.session" );
1246 while( $r = DB_fetch_array($result))
1250 echo "\n<div class=\"usermenu\">\n ";
1251 echo _('It\'s your turn in these games').":\n";
1259 echo " <a href=\"".$INDEX."?action=game&me=".$r[0].
1260 "\"> ".DB_format_gameid($r[1])." </a>\n";
1273 function generate_score_table($session)
1275 /* returns an array with N entries
1276 * $score[$i]["gameid"] = gameid
1277 * $score[$i]["players"] = array (id=>total points)
1278 * $score[$i]["points"] = points for this game
1279 * $score[$i]["solo"] = 1 or 0
1284 /* get all ids, scores and gametypes */
1285 $gameids = DB_get_gameids_of_finished_games_by_session($session);
1287 if($gameids == NULL)
1291 $player_party = array();
1293 /* get player id from the first game */
1294 $result = DB_query("SELECT user_id from Hand".
1295 " WHERE Hand.game_id=".$gameids[0][0]);
1296 while( $r = DB_fetch_array($result))
1299 /* get party of players for each game in the session */
1300 foreach($player as $id=>$points)
1301 $player_party[$id]=DB_get_party_by_session_and_userid($session,$id);
1303 /* get points and generate table */
1304 foreach($gameids as $gameid)
1306 $re_score = $gameid[1];
1307 $gametype = $gameid[2];
1308 foreach($player as $id=>$points)
1310 $party = $player_party[$id][$i][0];
1312 if($gametype=="solo")
1313 $player[$id] += 3*$re_score;
1315 $player[$id] += $re_score;
1316 else if ($party == "contra")
1317 $player[$id] -= $re_score;
1319 $score[$i]['gameid'] = $gameid[0] ;
1320 $score[$i]['players'] = $player;
1321 $score[$i]['points'] = abs($re_score);
1322 $score[$i]['solo'] = ($gametype=="solo");
1330 function generate_global_score_table()
1334 /* get all ids, scores and gametypes */
1335 $gameids = DB_get_gameids_of_finished_games_by_session(0);
1337 if($gameids == NULL)
1341 /* get player id, names... from the User table */
1342 $result = DB_query('SELECT User.id, User.fullname FROM User');
1344 /* save information in an array */
1345 while( $r = DB_fetch_array($result))
1346 $player[$r[0]] = array('name'=> $r[1], 'points' => 0 , 'nr' => 0, 'active' => 0,
1347 'response' => 0 , 'solo' => 0, 'soloavg' => 0);
1349 /* get points and generate table */
1350 foreach($gameids as $gameid)
1352 $re_score = $gameid[1];
1353 $gametype = $gameid[2];
1355 /* get players involved in this game */
1356 $result = DB_query('SELECT user_id FROM Hand WHERE game_id='.DB_quote_smart($gameid[0]));
1357 while($r = DB_fetch_array($result))
1360 $party = DB_get_party_by_gameid_and_userid($gameid[0],$id);
1362 if($gametype=='solo')
1363 $player[$id]['points'] += 3*$re_score;
1365 $player[$id]['points'] += $re_score;
1366 else if ($party == 'contra')
1367 $player[$id]['points'] -= $re_score;
1369 $player[$id]['nr']+=1;
1373 /* add number of active games */
1374 $result = DB_query_array_all("SELECT user_id, COUNT(*) as c " .
1376 " LEFT JOIN Game ON Game.id=game_id".
1377 " WHERE Game.status IN ('pre','play')".
1378 " GROUP BY user_id");
1380 foreach($result as $res)
1382 $player[$res[0]]['active'] = $res[1];
1385 /* response time of users*/
1386 $result = DB_query_array_all("SELECT user_id,".
1387 "IFNULL(AVG(if(P1.sequence in (2,3,4),".
1388 "-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 ".
1390 "LEFT JOIN Hand_Card ON P1.hand_card_id=Hand_Card.id ".
1391 "LEFT JOIN Hand ON Hand.id=Hand_Card.hand_id ".
1392 "GROUP BY user_id ");
1394 foreach($result as $res)
1396 $player[$res[0]]['response'] = $res[1];
1400 $result = DB_query_array_all("SELECT user_id as uid,".
1402 " COUNT(*)/(SELECT COUNT(*) FROM Hand LEFT JOIN User ON User.id=Hand.user_id WHERE User.id=uid) as c ".
1404 " LEFT JOIN Hand ON Hand.position=startplayer AND Game.id=Hand.game_id ".
1405 " WHERE type='solo' AND Game.status='gameover' ".
1406 " GROUP BY user_id ");
1408 foreach($result as $res)
1410 $player[$res[0]]['solo'] = $res[1];
1411 $player[$res[0]]['soloavg'] = $res[2];
1415 /* sort everything nicely */
1419 if($a['nr']==0) return 1;
1420 if($b['nr']==0) return 1;
1422 $a=$a['points']/$a['nr'];
1423 $b=$b['points']/$b['nr'];
1427 return ($a > $b) ? -1 : 1;
1429 usort($player,'cmp');
1432 foreach($player as $pl)
1434 /* limit to players with at least 10 games */
1436 $return[] = array( $pl['name'], round($pl['points']/$pl['nr'],3), $pl['points'],$pl['nr'],$pl['active'],
1437 $pl['response'],$pl['solo'],$pl['soloavg']);
1443 function format_score_table_ascii($score)
1446 if(sizeof($score)==0)
1449 /* truncate table if we have too many games */
1450 $max = sizeof($score);
1451 if($max>6) $output.=" (table truncated to last 6 games)\n";
1454 foreach($score[0]['players'] as $id=>$points)
1456 $name = DB_get_name('userid',$id); /*TODO*/
1457 $output.= " ".substr($name,0,2)." |";
1460 $output.= "------+------+------+------+------+\n";
1462 /* output score for each game */
1464 foreach($score as $game)
1467 if($i-1<$max-6) continue;
1469 foreach($game['players'] as $id=>$points)
1470 $output.=str_pad($points,6," ",STR_PAD_LEFT)."|";
1471 $output.=str_pad($game['points'],4," ",STR_PAD_LEFT);
1473 /* check for solo */
1484 function format_score_table_html($score,$userid)
1488 if(sizeof($score)==0)
1491 $output = "<div class=\"scoretable\">\n<table class=\"score\">\n";
1495 $header.= " <thead>\n <tr>\n";
1496 $header.= " <th> No </th>";
1497 foreach($score[0]['players'] as $id=>$points)
1499 $name = DB_get_name('userid',$id); /*TODO*/
1500 $header.= "<th> ".substr($name,0,2)." </th>";
1502 $header.="<th>P</th>\n </tr>\n </thead>\n";
1504 /* use the same as footer */
1506 $footer.= " <tfoot>\n <tr>\n";
1507 $footer.= " <td> No </td>";
1508 foreach($score[0]['players'] as $id=>$points)
1510 $name = DB_get_name('userid',$id); /*TODO*/
1511 $footer.= "<td> ".substr($name,0,2)." </td>";
1513 $footer.="<td>P</td>\n </tr>\n </tfoot>\n";
1517 $body.= " <tbody>\n";
1519 foreach($score as $game)
1523 $userhash = DB_get_hash_from_gameid_and_userid($game['gameid'],$userid);
1524 /* create link to old games only if you are logged in and its your game*/
1525 if(isset($_SESSION['id']) && $_SESSION['id']==$userid)
1526 $body.=" <td> <a href=\"".$INDEX."?action=game&me=".$userhash."\">$i</a></td>";
1528 $body.=" <td>$i</td>";
1530 foreach($game['players'] as $id=>$points)
1531 $body.="<td>".$points."</td>";
1532 $body.="<td>".$game['points'];
1534 /* check for solo */
1537 $body.="</td></tr>\n";
1545 $output.=" </tbody>\n</table>\n</div>\n";
1550 function createCache($content, $cacheFile)
1552 $fp = fopen($cacheFile,"w");
1555 fwrite($fp,$content);
1559 echo "WARNING: couldn't create cache file";
1564 function getCache($cacheFile, $expireTime)
1566 if( file_exists($cacheFile) &&
1567 filemtime($cacheFile )>( time() - $expireTime ) )
1569 return file_get_contents($cacheFile);
1575 function check_vacation($userid)
1577 /* get start date */
1578 $result = DB_query_array("SELECT value FROM User_Prefs".
1579 " WHERE user_id='$userid' AND pref_key='vacation start'" );
1581 $start = $result[0];
1586 $result = DB_query_array("SELECT value FROM User_Prefs".
1587 " WHERE user_id='$userid' AND pref_key='vacation stop'" );
1594 $result = DB_query_array("SELECT value FROM User_Prefs".
1595 " WHERE user_id='$userid' AND pref_key='vacation comment'" );
1597 $comment = $result[0];
1601 /* check if user is on vacation. TODO: use user's timezone */
1602 if( (time() - strtotime($start) >0) &&
1603 (strtotime($stop) - time() >0))
1604 return array ($start,$stop,$comment);
1609 function cancel_game($why,$gameid)
1611 $gameid = DB_quote_smart($gameid);
1613 /* update the game table */
1617 DB_query("UPDATE Game SET status='cancel-timedout' WHERE id=$gameid");
1620 DB_query("UPDATE Game SET status='cancel-nines' WHERE id=$gameid");
1623 DB_query("UPDATE Game SET status='cancel-trump' WHERE id=$gameid");
1626 DB_query("UPDATE Game SET status='cancel-noplay' WHERE id=$gameid");
1629 DB_query("UPDATE Game SET status='cancel-lowtrump' WHERE id=$gameid");
1632 /* set each player to gameover */
1633 $result = DB_query("SELECT id FROM Hand WHERE game_id=".DB_quote_smart($gameid));
1634 while($r = DB_fetch_array($result))
1637 DB_query("UPDATE Hand SET status='gameover' WHERE id=".DB_quote_smart($id));
1643 function get_user_token($userid)
1648 $date = DB_get_user_creation_date($userid);
1649 $name = DB_get_name('userid',$userid);
1652 $token = md5("token".$name.$date);
1657 function verify_password($email, $password)
1659 /* verify password, if old password has length 32 assume it's an old md5, else use new password scheme */
1660 /* return 0 if verified, else return error code
1661 * 1 can't find email
1662 * 2 can't calculate correct hash
1666 /* check user email by getting his id */
1667 $userid = DB_get_userid('email',$email);
1671 /* test for temporary passwords, only valid for one date (tested in the DB) */
1672 $tmppasswd = md5($password);
1673 if(DB_check_recovery_passwords($tmppasswd,$email))
1676 /* get saved password */
1677 $existingpassword = DB_get_passwd_by_userid($userid);
1679 if(strlen($existingpassword)==32) /* old password type */
1681 if ($existingpassword == md5($password))
1683 /* update password to new crypt version */
1684 // create a password hash using the crypt function, need php 5.3 for this
1685 // create and random salt
1686 $salt = substr(str_replace('+', '.', base64_encode(sha1(microtime(true), true))), 0, 22);
1687 // hash incoming password using 12 rounds of blowfish
1688 $hash = crypt($password, '$2y$12$' . $salt);
1689 if(strlen($hash)>13)
1690 DB_query("UPDATE User SET password='$hash' where id='$userid'");
1699 if ($existingpassword == crypt($password, $existingpassword))
1706 /* language functions */
1707 function detectlanguage()
1709 /* read out browser's prefered language, taken from php-manual*/
1710 $langcode = explode(";", $_SERVER['HTTP_ACCEPT_LANGUAGE']);
1711 $langcode = explode(",", $langcode['0']);
1712 return $langcode['0'];
1715 function set_language($l,$type='lang')
1719 $userPREF = DB_get_PREF($l);
1720 $l = $userPREF['language'];
1726 putenv("LC_ALL=de_DE");
1727 setlocale(LC_ALL, "de_DE");
1728 // Specify location of translation tables
1729 bindtextdomain("edoko", "./locale");
1730 bind_textdomain_codeset("edoko", 'UTF-8');
1732 textdomain("edoko");