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 $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";
223 /* display email on screen,
226 $message = str_replace("\n","<br />\n",$message);
227 $message = preg_replace("#(\w+://[^<>\s]+[\w/]*)#",
228 "<a href=\"$1\">$1</a>", $message);
230 echo "<br />To: $To<br />";
232 echo $header."<br />";
233 echo "Subject: $Subject <br />$message<br />\n";
237 mail($To,$Subject,$message,$header);
239 mail($To,$Subject,$message);
245 /* returns 1 if all names passed as args are defined by a GET or POST statement,
250 $args = func_get_args();
252 foreach($args as $arg)
254 $ok = $ok * isset($_REQUEST[$arg]);
255 /*echo "$arg: ok = $ok <br />";
261 function myerror($message)
263 echo "<span class=\"error\">".htmlspecialchars($message)."</span>\n";
264 sendmail($ADMIN_EMAIL,$EmailName." Error in Code",$message);
268 function pos_array($c,$arr)
285 function is_trump($c)
289 if(in_array($c,$CARDS["trump"]))
295 function is_same_suite($c1,$c2)
299 if(in_array($c1,$CARDS["trump"] ) && in_array($c2,$CARDS["trump"] ) ) return 1;
300 if(in_array($c1,$CARDS["clubs"] ) && in_array($c2,$CARDS["clubs"] ) ) return 1;
301 if(in_array($c1,$CARDS["hearts"] ) && in_array($c2,$CARDS["hearts"] ) ) return 1;
302 if(in_array($c1,$CARDS["spades"] ) && in_array($c2,$CARDS["spades"] ) ) return 1;
303 if(in_array($c1,$CARDS["diamonds"]) && in_array($c2,$CARDS["diamonds"]) ) return 1;
308 function compare_cards($a,$b,$game)
310 /* if "a" is higher than "b" return 1, else 0, "a" being the card first played */
316 /* first map all cards to the odd number,
317 * this insure that the first card wins the trick
318 * if they are the same card
320 if( $a/2 - (int)($a/2) != 0.5)
322 if( $b/2 - (int)($b/2) != 0.5)
325 /* check for schweinchen and ten of hearts*/
331 if($RULES['schweinchen']=='both' && $GAME['schweinchen-who'])
333 if($a == 19 || $a == 20 )
335 if($b == 19 || $b == 20 )
338 else if($RULES['schweinchen']=='second' && $GAME['schweinchen-second'])
340 if($a == 19 || $a == 20 )
342 if($b == 19 || $b == 20 )
345 else if($RULES['schweinchen']=='secondaftercall' && $GAME['schweinchen-who'] && $GAME['schweinchen-second'] )
347 /* check if a call was made either by the player or his partner. If so activate Schweinchen rule. */
348 if(DB_get_call_by_hash($GAME['schweinchen-who']) || DB_get_partner_call_by_hash($GAME['schweinchen-who']) )
350 if($a == 19 || $a == 20 )
352 if($b == 19 || $b == 20 )
355 /* if not, do nothing and the foxes are just handeled as normal trump */
361 /* check for ten of hearts rule */
362 if($RULES["dullen"]=="secondwins")
363 if($a==1 && $b==1) /* both 10 of hearts */
364 return 0; /* second one wins.*/
368 /* no special cases here */
372 if(is_trump($a) && is_trump($b) && $a<=$b)
374 else if(is_trump($a) && is_trump($b) )
377 { /*$a is not a trump */
381 { /* both no trump */
384 $posA = pos_array($a,$CARDS["clubs"]);
385 $posB = pos_array($b,$CARDS["clubs"]);
393 $posA = pos_array($a,$CARDS["spades"]);
394 $posB = pos_array($b,$CARDS["spades"]);
402 $posA = pos_array($a,$CARDS["hearts"]);
403 $posB = pos_array($b,$CARDS["hearts"]);
411 $posA = pos_array($a,$CARDS["diamonds"]);
412 $posB = pos_array($b,$CARDS["diamonds"]);
419 /* not the same suit and no trump: a wins */
425 function get_winner($p,$mode)
427 /* get all 4 cards played in a trick, in the order they are played */
430 $c1pos = $tmp["pos"];
434 $c2pos = $tmp["pos"];
438 $c3pos = $tmp["pos"];
442 $c4pos = $tmp["pos"];
444 /* first card is better than all the rest */
445 if( compare_cards($c1,$c2,$mode) && compare_cards($c1,$c3,$mode) && compare_cards($c1,$c4,$mode) )
448 /* second card is better than first and better than the rest */
449 if( !compare_cards($c1,$c2,$mode) && compare_cards($c2,$c3,$mode) && compare_cards($c2,$c4,$mode) )
452 /* third card is better than first card and better than last */
453 if( !compare_cards($c1,$c3,$mode) && compare_cards($c3,$c4,$mode) )
454 /* if second card is better than first, third card needs to be even better */
455 if( !compare_cards($c1,$c2,$mode) && !compare_cards($c2,$c3,$mode) )
457 /* second is worse than first, e.g. not following suite */
458 else if (compare_cards($c1,$c2,$mode) )
461 /* non of the above */
465 function count_nines($cards)
469 foreach($cards as $c)
471 if($c == "25" || $c == "26") $nines++;
472 else if($c == "33" || $c == "34") $nines++;
473 else if($c == "41" || $c == "42") $nines++;
474 else if($c == "47" || $c == "48") $nines++;
480 function check_wedding($cards)
483 if( in_array("3",$cards) && in_array("4",$cards) )
489 function count_trump($cards,$status='pregame')
495 /* count each trump, including the foxes, since this is used to determine poverty status */
496 foreach($cards as $c)
500 /* In case we really want to know the amount of trump, we can use the status variable.
501 * This is needed for example to figure out what icon to display on the table in case of
502 * trump given back in poverty */
503 if($status=='all') return $trump;
505 /* normally foxes don't count as trump, so we substract them here
506 * in case someone has schweinchen, one or two of them should count as trump
507 * though, so we need to add one trump for those cases */
510 if( in_array("19",$cards))
512 if( in_array("20",$cards) )
515 /* handle case where player has schweinchen */
516 if( in_array("19",$cards) && in_array("20",$cards) )
517 switch($RULES["schweinchen"])
520 /* add two, in case the player has both foxes (schweinchen) */
525 case "secondaftercall":
526 /* add one, in case the player has both foxes (schweinchen) */
536 function check_low_trump($cards)
540 if($RULES['lowtrump']=='none')
543 /* check if we have low trump */
546 foreach($cards as $card)
548 /* card a trump, but not a diamond? */
553 /* handle case where player has schweinchen */
554 if( in_array("19",$cards) && in_array("20",$cards) )
555 switch($RULES["schweinchen"])
559 case "secondaftercall":
569 function create_array_of_random_numbers($useridA,$useridB,$useridC,$useridD)
577 /* fix the hands; makes debugging easier; the following hands have lots of sicknesses,
578 * to make testing easier
580 $r[ 0]=1; $r[12]=47; $r[24]=13; $r[36]=37;
581 $r[ 1]=2; $r[13]=23; $r[25]=14; $r[37]=38;
582 $r[ 2]=3; $r[14]=27; $r[26]=15; $r[38]=39;
583 $r[ 3]=4; $r[15]=16; $r[27]=28; $r[39]=40;
584 $r[ 4]=5; $r[16]=17; $r[28]=29; $r[40]=21;
585 $r[ 5]=18; $r[17]=6; $r[29]=30; $r[41]=42;
586 $r[ 6]=41; $r[18]=7; $r[30]=31; $r[42]=43;
587 $r[ 7]=22; $r[19]=8; $r[31]=32; $r[43]=20;
588 $r[ 8]=45; $r[20]=9; $r[32]=33; $r[44]=19;
589 $r[ 9]=46; $r[21]=10; $r[33]=44; $r[45]=24;
590 $r[10]=35; $r[22]=11; $r[34]=48; $r[46]=25;
591 $r[11]=36; $r[23]=12; $r[35]=34; $r[47]=26;
595 /* check if we can find a game were non of the player was involved and return
598 $userstr = "'".implode("','",array($useridA,$useridB,$useridC,$useridD))."'";
599 $randomnumbers = DB_get_unused_randomnumbers($userstr);
600 $randomnumbers = explode(":",$randomnumbers);
602 if(sizeof($randomnumbers)==48)
603 return $randomnumbers;
605 /* need to create new numbers */
609 /* shuffle using a better random generator than the standard one */
610 for ($i = 0; $i <48; $i++)
612 $j = @mt_rand(0, $i);
622 function display_cards($me,$myturn)
627 function have_suit($cards,$c)
632 if(in_array($c,$CARDS["trump"]))
633 $suite = $CARDS["trump"];
634 else if(in_array($c,$CARDS["clubs"]))
635 $suite = $CARDS["clubs"];
636 else if(in_array($c,$CARDS["spades"]))
637 $suite = $CARDS["spades"];
638 else if(in_array($c,$CARDS["hearts"]))
639 $suite = $CARDS["hearts"];
640 else if(in_array($c,$CARDS["diamonds"]))
641 $suite = $CARDS["diamonds"];
643 foreach($cards as $card)
645 if(in_array($card,$suite))
652 function same_type($card,$c)
657 /* figure out what kind of card c is */
658 if(in_array($c,$CARDS["trump"]))
659 $suite = $CARDS["trump"];
660 else if(in_array($c,$CARDS["clubs"]))
661 $suite = $CARDS["clubs"];
662 else if(in_array($c,$CARDS["spades"]))
663 $suite = $CARDS["spades"];
664 else if(in_array($c,$CARDS["hearts"]))
665 $suite = $CARDS["hearts"];
666 else if(in_array($c,$CARDS["diamonds"]))
667 $suite = $CARDS["diamonds"];
669 /* card is the same suid return 1 */
670 if(in_array($card,$suite))
676 function set_gametype($gametype)
690 $CARDS["trump"] = array('1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16',
691 '17','18','19','20','21','22','23','24','25','26');
692 $CARDS["diamonds"] = array();
693 $CARDS["clubs"] = array('27','28','29','30','31','32','33','34');
694 $CARDS["spades"] = array('35','36','37','38','39','40','41','42');
695 $CARDS["hearts"] = array('43','44','45','46','47','48');
696 $CARDS["foxes"] = array('19','20');
697 if($RULES["dullen"]=='none')
699 $CARDS["trump"] = array('3','4','5','6','7','8','9','10','11','12','13','14','15','16',
700 '17','18','19','20','21','22','23','24','25','26');
701 $CARDS["hearts"] = array('43','44','1','2','45','46','47','48');
703 /* do we need to reorder for Schweinchen? need to search for it because of special case for dullen above*/
704 if($RULES['schweinchen']=='both'&& $GAME['schweinchen-who'])
706 /* find the fox and put them at the top of the stack */
707 foreach(array('19','20') as $fox)
710 $trump = $CARDS['trump'];
711 $key = array_keys($trump, $fox);
715 $foxa[]=$trump[$key[0]];
716 unset($trump[$key[0]]);
717 $trump = array_merge($foxa,$trump);
718 $CARDS['trump'] = $trump;
721 else if( ($RULES['schweinchen']=='second' || $RULES['schweinchen']=='secondaftercall')
722 && $GAME['schweinchen-who'])
724 /* find the fox and put them at the top of the stack */
725 $trump = $CARDS['trump'];
726 $key = array_keys($trump, '19');
730 $foxa[]=$trump[$key[0]];
731 unset($trump[$key[0]]);
732 $trump = array_merge($foxa,$trump);
733 $CARDS['trump'] = $trump;
737 $CARDS["trump"] = array('3','4','5','6','7','8','9','10');
738 $CARDS["clubs"] = array('27','28','29','30','31','32','11','12','33','34');
739 $CARDS["spades"] = array('35','36','37','38','39','40','13','14','41','42');
740 $CARDS["hearts"] = array('43','44', '1', '2','45','46','15','16','47','48');
741 $CARDS["diamonds"] = array('19','20','21','22','23','24','17','18','25','26');
742 $CARDS["foxes"] = array();
745 $CARDS["trump"] = array('11','12','13','14','15','16','17','18');
746 $CARDS["clubs"] = array('27','28','29','30','31','32','3', '4','33','34');
747 $CARDS["spades"] = array('35','36','37','38','39','40','5', '6','41','42');
748 $CARDS["hearts"] = array('43','44', '1', '2','45','46','7', '8','47','48');
749 $CARDS["diamonds"] = array('19','20','21','22','23','24','9','10','25','26');
750 $CARDS["foxes"] = array();
753 $CARDS["trump"] = array();
754 $CARDS["clubs"] = array('27','28','29','30','31','32','3', '4','11','12','33','34');
755 $CARDS["spades"] = array('35','36','37','38','39','40','5', '6','13','14','41','42');
756 $CARDS["hearts"] = array('43','44', '1', '2','45','46','7', '8','15','16','47','48');
757 $CARDS["diamonds"] = array('19','20','21','22','23','24','9','10','17','18','25','26');
758 $CARDS["foxes"] = array();
761 $CARDS["trump"] = array('1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16',
762 '17','18','27','28','29','30','31','32','33','34');
763 $CARDS["clubs"] = array();
764 $CARDS["spades"] = array('35','36','37','38','39','40','41','42');
765 $CARDS["hearts"] = array('43','44','45','46','47','48');
766 $CARDS["diamonds"] = array('19','20','21','22','23','24','25','26');
767 $CARDS["foxes"] = array();
768 if($RULES["dullen"]=='none')
770 $CARDS["trump"] = array('3','4','5','6','7','8','9','10','11','12','13','14','15','16',
771 '17','18','27','28','29','30','31','32','33','34');
772 $CARDS["hearts"] = array('43','44','1','2','45','46','47','48');
776 $CARDS["trump"] = array('1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16',
777 '17','18','35','36','37','38','39','40','41','42');
778 $CARDS["clubs"] = array('27','28','29','30','31','32','33','34');
779 $CARDS["spades"] = array();
780 $CARDS["hearts"] = array('43','44','45','46','47','48');
781 $CARDS["diamonds"] = array('19','20','21','22','23','24','25','26');
782 $CARDS["foxes"] = array();
783 if($RULES["dullen"]=='none')
785 $CARDS["trump"] = array('3','4','5','6','7','8','9','10','11','12','13','14','15','16',
786 '17','18','35','36','37','38','39','40','41','42');
787 $CARDS["hearts"] = array('43','44','1','2','45','46','47','48');
791 $CARDS["trump"] = array('1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16',
792 '17','18','43','44','45','46','47','48');
793 $CARDS["clubs"] = array('27','28','29','30','31','32','33','34');
794 $CARDS["spades"] = array('35','36','37','38','39','40','41','42');
795 $CARDS["hearts"] = array();
796 $CARDS["diamonds"] = array('19','20','21','22','23','24','25','26');
797 $CARDS["foxes"] = array();
798 if($RULES["dullen"]=='none')
800 $CARDS["trump"] = array('3','4','5','6','7','8','9','10','11','12','13','14','15','16',
801 '17','18','43','44','1','2','45','46','47','48');
807 function mysort($cards,$gametype)
810 if(isset($PREF['sorting']))
811 if($PREF['sorting']=='high-low')
812 usort ( $cards, 'sort_comp_high_low' );
814 usort ( $cards, 'sort_comp_low_high' );
816 usort ( $cards, 'sort_comp_high_low' );
820 function sort_comp_high_low($a,$b)
825 $ALL = array_merge($CARDS['trump'],$CARDS['diamonds'],$CARDS['clubs'],
826 $CARDS['hearts'],$CARDS['spades']);
828 return pos_array($a,$ALL)-pos_array($b,$ALL);
831 function sort_comp_low_high($a,$b)
836 $ALL = array_merge($CARDS['trump'],$CARDS['diamonds'],$CARDS['clubs'],
837 $CARDS['hearts'],$CARDS['spades']);
839 return -pos_array($a,$ALL)+pos_array($b,$ALL);
842 function can_call($what,$hash)
844 /* figure out if a person can make a call:
845 $what in 0,30,60,90,120 = points of the call
846 $hash = the hash of the person who wants to make the call
849 0 can't make that call
851 2 can make the call, but this is the last chance to do so...
856 /* get some information
858 $gameid = DB_get_gameid_by_hash($hash);
859 $gametype = DB_get_gametype_by_gameid($gameid);
860 $oldcall = DB_get_call_by_hash($hash); /* did the person already made a call? */
861 $pcall = DB_get_partner_call_by_hash($hash); /* did the partner already made a call */
864 /* you're call must be better than the one you or your partner already made
866 if( ($pcall!=NULL && ($what >= $pcall))
867 || ($oldcall!=NULL && ($what >=$oldcall)) )
872 /* for some rules we need to know how many cards people have
874 $NRcards = count(DB_get_hand($hash));
879 $user = DB_get_hash_from_game_and_pos($gameid,$i);
880 $NRallcards += count(DB_get_hand($user));
883 /* in case of a wedding, everything will be delayed by an offset
886 if($gametype=="wedding")
888 $offset = DB_get_sickness_by_gameid($gameid);
889 if ($offset <0) /* not resolved */
893 /* now check if the call is allowed depending on the rule set
895 switch ($RULES["call"])
898 /* calls can be made before/while you play your card...
899 * first card = 120, second card = 90, etc.
901 if( 4-($what/30) == 12 - ($NRcards + $offset))
903 if( 4-($what/30) > 12 - ($NRcards + $offset))
907 /* you can make the first call anytime during the first trick
909 if( 27+4*($what/30) == $NRallcards + $offset*4)
911 if( 27+4*($what/30) < $NRallcards + $offset*4)
915 /* you can call 120 with 12 cards, 90 with 9 or more cards, 60 with 6 or more, etc.
916 * you can't skip a call though
919 /* figure out last call
921 if($oldcall!=NULL && $pcall!=NULL)
922 $mincall = ($oldcall>$pcall) ? $pcall : $oldcall;
923 else if($oldcall!=NULL)
925 else if ($pcall!=NULL)
931 if( 12 == ($NRcards + $offset))
935 else if( 12 < ($NRcards + $offset))
939 else if ( 9 == ($NRcards + $offset))
941 if( ($mincall>=0 && $mincall<=120 && $what<=90 ) )
944 else if ( 9 < ($NRcards + $offset))
946 if( ($mincall>=0 && $mincall<=120 && $what<=90 ) )
949 else if ( 6 == ($NRcards + $offset))
951 if( ($mincall>=0 && $mincall<=90 && $what<=60 ) )
954 else if ( 6 < ($NRcards + $offset))
956 if( ($mincall>=0 && $mincall<=90 && $what<=60 ) )
959 else if ( 3 == ($NRcards + $offset))
961 if( ($mincall>=0 && $mincall<=60 && $what<=30 ) )
964 else if ( 3 < ($NRcards + $offset))
966 if( ($mincall>=0 && $mincall<=60 && $what<=30 ) )
969 else if ( 0 == ($NRcards + $offset))
971 if( ($mincall>=0 && $mincall<=30 && $what==0 ) )
974 else if ( 0 < ($NRcards + $offset))
976 if( ($mincall>=0 && $mincall<=30 && $what==0 ) )
985 function display_table_begin ()
987 global $gameid, $GT, $debug,$INDEX,$defaulttimezone,$session;
988 global $RULES,$GAME,$gametype;
990 $result = DB_query("SELECT User.fullname as name,".
991 " Hand.position as position, ".
993 " Hand.party as party, ".
994 " Hand.sickness as sickness, ".
995 " Hand.point_call, ".
996 " User.last_login, ".
1001 "LEFT JOIN User ON User.id=Hand.user_id ".
1002 "WHERE Hand.game_id='".$gameid."' ".
1003 "ORDER BY position ASC");
1005 $row0 = DB_fetch_array($result);
1006 $row1 = DB_fetch_array($result);
1007 $row2 = DB_fetch_array($result);
1008 $row3 = DB_fetch_array($result);
1010 echo "<div class=\"table\">\n";
1011 display_single_user($row1);
1012 echo "\n<div class=\"middle\">\n";
1013 display_single_user($row0,1); /* mark starting player in case re/contra is not set yet */
1014 echo " <img class=\"table\" src=\"pics/table.png\" alt=\"table\" />\n";
1015 display_single_user($row2);
1019 function display_table_end ()
1021 global $gameid, $GT, $debug,$INDEX,$defaulttimezone,$session;
1022 global $RULES,$GAME,$gametype;
1024 $result = DB_query("SELECT User.fullname as name,".
1025 " Hand.position as position, ".
1027 " Hand.party as party, ".
1028 " Hand.sickness as sickness, ".
1029 " Hand.point_call, ".
1030 " User.last_login, ".
1035 "LEFT JOIN User ON User.id=Hand.user_id ".
1036 "WHERE Hand.game_id='".$gameid."' ".
1037 "ORDER BY position ASC");
1039 $row0 = DB_fetch_array($result);
1040 $row1 = DB_fetch_array($result);
1041 $row2 = DB_fetch_array($result);
1042 $row3 = DB_fetch_array($result);
1045 display_single_user($row3);
1051 function display_single_user($r,$start=0)
1053 /* start=1, mark starting player, default=0, so the player on the left is not marked */
1055 global $gameid, $GT, $debug,$INDEX,$defaulttimezone,$session;
1056 global $RULES,$GAME,$gametype;
1067 $wins = DB_get_number_of_tricks($gameid,$pos);
1068 date_default_timezone_set($defaulttimezone);
1069 $lastlogin = strtotime($r[6]);
1070 date_default_timezone_set($timezone);
1071 $timenow = strtotime(date("Y-m-d H:i:s"));
1072 $gravatar = "$name<br />\n <img class=\"gravatar\" title=\"$name\" src=\"http://www.gravatar.com/avatar/".
1073 md5(strtolower(trim($email)))."?d=identicon\" alt=\"$name's gravatar\" />";
1075 echo " <div class=\"table".($pos-1)."\">\n";
1077 /* mark starting player */
1078 if($start && ! ($party=="re" || $party=="contra"))
1079 echo ' <span class="start">'._('Starting Player')."</span> <br />\n";
1082 echo " <a href=\"".$INDEX."?action=game&me=".$hash."\">";
1083 if($vacation = check_vacation($user))
1085 $start = $vacation[0];
1086 $stop = substr($vacation[1],0,10);
1087 $comment = $vacation[2];
1089 $title = "begin: $start end: $stop $comment";
1090 echo " <span class=\"vacation\" title=\"$title\">$gravatar (on vacation until $stop)</span> \n";
1093 echo " $gravatar \n";
1097 /* add hints for poverty, wedding, solo, etc */
1098 if( $gametype != "solo")
1099 if( $RULES["schweinchen"]=="both" && $GAME["schweinchen-who"]==$hash )
1100 echo " Schweinchen. <br />";
1102 if($GT=="poverty" && $party=="re")
1103 if($sickness=="poverty" || ($RULES['lowtrump']=='poverty' && $sickness=='lowtrump'))
1105 $userhash = DB_get_hash_from_gameid_and_userid($gameid,$user);
1106 $cards = DB_get_all_hand($userhash);
1107 $trumpNR = count_trump($cards,'all');
1109 echo " <img src=\"pics/button/poverty_trump_button.png\" class=\"button\" ".
1110 "alt=\"poverty - trump back\" title=\"poverty - trump back\" />\n";
1112 echo " <img src=\"pics/button/poverty_notrump_button.png\" class=\"button\" ".
1113 "alt=\"poverty - no trump back\" title=\"poverty - no trump back\" />\n";
1116 echo " <img src=\"pics/button/poverty_partner_button.png\" class=\"button\" ".
1117 "alt=\"poverty partner\" title=\"poverty partner\" />\n";
1121 if($sickness=="poverty" || ($RULES['lowtrump']=='poverty' && $sickness=='lowtrump'))
1123 $userhash = DB_get_hash_from_gameid_and_userid($gameid,$user);
1124 $cards = DB_get_all_hand($userhash);
1125 $trumpNR = count_trump($cards,'all');
1127 echo " <img src=\"pics/button/poverty_trump_button.png\" class=\"button\" ".
1128 "alt=\"poverty < trump back\" title=\"poverty - trump back\" />\n";
1130 echo " <img src=\"pics/button/poverty_notrump_button.png\" class=\"button\" ".
1131 "alt=\"poverty <\" title=\"poverty - no trump back\" />\n";
1134 echo " <img src=\"pics/button/poverty_partner_button.png\" class=\"button\" ".
1135 "alt=\"poverty >\" title=\"poverty partner\" />\n";
1137 if($sickness=="poverty" || ($RULES['lowtrump']=='poverty' && $sickness=='lowtrump'))
1139 $userhash = DB_get_hash_from_gameid_and_userid($gameid,$user);
1140 $cards = DB_get_all_hand($userhash);
1141 $trumpNR = count_trump($cards,'all');
1143 echo " <img src=\"pics/button/poverty2_trump_button.png\" class=\"button\" ".
1144 "alt=\"poverty2 < trump back\" title=\"poverty2 - trump back\"/>\n";
1146 echo " <img src=\"pics/button/poverty2_notrump_button.png\" class=\"button\" ".
1147 "alt=\"poverty2 <\" title=\"poverty2 - no trump back\" />\n";
1150 echo " <img src=\"pics/button/poverty2_partner_button.png\" class=\"button\" ".
1151 "alt=\"poverty2 >\" title=\"poverty2 partner\" />\n";
1153 if($GT=="wedding" && $party=="re")
1154 if($sickness=="wedding")
1155 echo " <img src=\"pics/button/wedding_button.png\" class=\"button\" alt=\"wedding\" title=\"wedding\" />\n";
1157 echo " <img src=\"pics/button/wedding_partner_button.png\" class=\"button\" ".
1158 "alt=\"wedding partner\" title=\"wedding partner\" />\n";
1160 if( (strpos($GT,"solo")!==false) && $party=="re")
1162 if(strpos($GT,"queen")!==false)
1163 echo " <img src=\"pics/button/queensolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Queen solo\" />\n";
1164 else if(strpos($GT,"jack")!==false)
1165 echo " <img src=\"pics/button/jacksolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Jack solo\" />\n";
1166 else if(strpos($GT,"club")!==false)
1167 echo " <img src=\"pics/button/clubsolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Club solo\" />\n";
1168 else if(strpos($GT,"spade")!==false)
1169 echo " <img src=\"pics/button/spadesolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Spade solo\" />\n";
1170 else if(strpos($GT,"heart")!==false)
1171 echo " <img src=\"pics/button/heartsolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Heart solo\" />\n";
1172 else if(strpos($GT,"trumpless")!==false)
1173 echo " <img src=\"pics/button/notrumpsolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Trumpless solo\" />\n";
1174 else if(strpos($GT,"trump")!==false)
1175 echo " <img src=\"pics/button/trumpsolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Trump solo\" />\n";
1178 /* add point calls */
1182 echo " <img src=\"pics/button/re_button.png\" class=\"button\" alt=\"re\" title=\"Re\" />\n";
1184 echo " <img src=\"pics/button/contra_button.png\" class=\"button\" alt=\"contra\" title=\"Contra\" />\n";
1188 echo " <img src=\"pics/button/0_button.png\" class=\"button\" alt=\"0\" title=\"Call 0\" />\n";
1191 echo " <img src=\"pics/button/30_button.png\" class=\"button\" alt=\"30\" title=\"Call 30\" />\n";
1194 echo " <img src=\"pics/button/60_button.png\" class=\"button\" alt=\"60\" title=\"Call 60\" />\n";
1197 echo " <img src=\"pics/button/90_button.png\" class=\"button\" alt=\"90\" title=\"Call 90\" />\n";
1202 echo " <img src=\"pics/button/time-info.png\" class=\"button\" alt=\"time info\" ".
1203 "title=\"local time: ".date("Y-m-d H:i:s",$timenow). " ".
1204 "last login: ".date("Y-m-d H:i:s",$lastlogin)."\" />";
1206 echo " <br /><span class=\"numberoftricks\">";
1207 /* show how many tricks the person made */
1211 echo _('#tricks 0'); break;
1213 echo _('#tricks 1'); break;
1217 echo _('#tricks few'); break;
1219 echo _('#tricks many'); break;
1226 function display_user_menu($id, $skiphash=NULL)
1228 global $WIKI,$INDEX;
1231 $result = DB_query("SELECT Hand.hash,Hand.game_id,Game.player from Hand".
1232 " LEFT JOIN Game On Hand.game_id=Game.id".
1233 " WHERE Hand.user_id='$id'".
1234 " AND Hand.hash!='$skiphash'".
1235 " AND ( Game.player='$id' OR ISNULL(Game.player) )".
1236 " AND ( Game.status='pre' OR Game.status='play' )".
1237 " ORDER BY Game.session" );
1239 $result = DB_query("SELECT Hand.hash,Hand.game_id,Game.player from Hand".
1240 " LEFT JOIN Game On Hand.game_id=Game.id".
1241 " WHERE Hand.user_id='$id'".
1242 " AND ( Game.player='$id' OR ISNULL(Game.player) )".
1243 " AND ( Game.status='pre' OR Game.status='play' )".
1244 " ORDER BY Game.session" );
1247 while( $r = DB_fetch_array($result))
1251 echo "\n<div class=\"usermenu\">\n ";
1252 echo _('It\'s your turn in these games').":\n";
1260 echo " <a href=\"".$INDEX."?action=game&me=".$r[0].
1261 "\"> ".DB_format_gameid($r[1])." </a>\n";
1274 function generate_score_table($session)
1276 /* returns an array with N entries
1277 * $score[$i]["gameid"] = gameid
1278 * $score[$i]["players"] = array (id=>total points)
1279 * $score[$i]["points"] = points for this game
1280 * $score[$i]["solo"] = 1 or 0
1285 /* get all ids, scores and gametypes */
1286 $gameids = DB_get_gameids_of_finished_games_by_session($session);
1288 if($gameids == NULL)
1292 $player_party = array();
1294 /* get player id from the first game */
1295 $result = DB_query("SELECT user_id from Hand".
1296 " WHERE Hand.game_id=".$gameids[0][0]);
1297 while( $r = DB_fetch_array($result))
1300 /* get party of players for each game in the session */
1301 foreach($player as $id=>$points)
1302 $player_party[$id]=DB_get_party_by_session_and_userid($session,$id);
1304 /* get points and generate table */
1305 foreach($gameids as $gameid)
1307 $re_score = $gameid[1];
1308 $gametype = $gameid[2];
1309 foreach($player as $id=>$points)
1311 $party = $player_party[$id][$i][0];
1313 if($gametype=="solo")
1314 $player[$id] += 3*$re_score;
1316 $player[$id] += $re_score;
1317 else if ($party == "contra")
1318 $player[$id] -= $re_score;
1320 $score[$i]['gameid'] = $gameid[0] ;
1321 $score[$i]['players'] = $player;
1322 $score[$i]['points'] = abs($re_score);
1323 $score[$i]['solo'] = ($gametype=="solo");
1331 function generate_global_score_table()
1335 /* get all ids, scores and gametypes */
1336 $gameids = DB_get_gameids_of_finished_games_by_session(0);
1338 if($gameids == NULL)
1342 /* get player id, names... from the User table */
1343 $result = DB_query('SELECT User.id, User.fullname FROM User');
1345 /* save information in an array */
1346 while( $r = DB_fetch_array($result))
1347 $player[$r[0]] = array('name'=> $r[1], 'points' => 0 , 'nr' => 0, 'active' => 0,
1348 'response' => 0 , 'solo' => 0, 'soloavg' => 0);
1350 /* get points and generate table */
1351 foreach($gameids as $gameid)
1353 $re_score = $gameid[1];
1354 $gametype = $gameid[2];
1356 /* get players involved in this game */
1357 $result = DB_query('SELECT user_id FROM Hand WHERE game_id='.DB_quote_smart($gameid[0]));
1358 while($r = DB_fetch_array($result))
1361 $party = DB_get_party_by_gameid_and_userid($gameid[0],$id);
1363 if($gametype=='solo')
1364 $player[$id]['points'] += 3*$re_score;
1366 $player[$id]['points'] += $re_score;
1367 else if ($party == 'contra')
1368 $player[$id]['points'] -= $re_score;
1370 $player[$id]['nr']+=1;
1374 /* add number of active games */
1375 $result = DB_query_array_all("SELECT user_id, COUNT(*) as c " .
1377 " LEFT JOIN Game ON Game.id=game_id".
1378 " WHERE Game.status IN ('pre','play')".
1379 " GROUP BY user_id");
1381 foreach($result as $res)
1383 $player[$res[0]]['active'] = $res[1];
1386 /* response time of users*/
1387 $result = DB_query_array_all("SELECT user_id,".
1388 "IFNULL(AVG(if(P1.sequence in (2,3,4),".
1389 "-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 ".
1391 "LEFT JOIN Hand_Card ON P1.hand_card_id=Hand_Card.id ".
1392 "LEFT JOIN Hand ON Hand.id=Hand_Card.hand_id ".
1393 "GROUP BY user_id ");
1395 foreach($result as $res)
1397 $player[$res[0]]['response'] = $res[1];
1401 $result = DB_query_array_all("SELECT user_id as uid,".
1403 " COUNT(*)/(SELECT COUNT(*) FROM Hand LEFT JOIN User ON User.id=Hand.user_id WHERE User.id=uid) as c ".
1405 " LEFT JOIN Hand ON Hand.position=startplayer AND Game.id=Hand.game_id ".
1406 " WHERE type='solo' AND Game.status='gameover' ".
1407 " GROUP BY user_id ");
1409 foreach($result as $res)
1411 $player[$res[0]]['solo'] = $res[1];
1412 $player[$res[0]]['soloavg'] = $res[2];
1416 /* sort everything nicely */
1420 if($a['nr']==0) return 1;
1421 if($b['nr']==0) return 1;
1423 $a=$a['points']/$a['nr'];
1424 $b=$b['points']/$b['nr'];
1428 return ($a > $b) ? -1 : 1;
1430 usort($player,'cmp');
1433 foreach($player as $pl)
1435 /* limit to players with at least 10 games */
1437 $return[] = array( $pl['name'], round($pl['points']/$pl['nr'],3), $pl['points'],$pl['nr'],$pl['active'],
1438 $pl['response'],$pl['solo'],$pl['soloavg']);
1444 function format_score_table_ascii($score)
1447 if(sizeof($score)==0)
1450 /* truncate table if we have too many games */
1451 $max = sizeof($score);
1452 if($max>6) $output.=" (table truncated to last 6 games)\n";
1455 foreach($score[0]['players'] as $id=>$points)
1457 $name = DB_get_name('userid',$id); /*TODO*/
1458 $output.= " ".substr($name,0,2)." |";
1461 $output.= "------+------+------+------+------+\n";
1463 /* output score for each game */
1465 foreach($score as $game)
1468 if($i-1<$max-6) continue;
1470 foreach($game['players'] as $id=>$points)
1471 $output.=str_pad($points,6," ",STR_PAD_LEFT)."|";
1472 $output.=str_pad($game['points'],4," ",STR_PAD_LEFT);
1474 /* check for solo */
1485 function format_score_table_html($score,$userid)
1489 if(sizeof($score)==0)
1492 $output = "<div class=\"scoretable\">\n<table class=\"score\">\n";
1496 $header.= " <thead>\n <tr>\n";
1497 $header.= " <th> No </th>";
1498 foreach($score[0]['players'] as $id=>$points)
1500 $name = DB_get_name('userid',$id); /*TODO*/
1501 $header.= "<th> ".substr($name,0,2)." </th>";
1503 $header.="<th>P</th>\n </tr>\n </thead>\n";
1505 /* use the same as footer */
1507 $footer.= " <tfoot>\n <tr>\n";
1508 $footer.= " <td> No </td>";
1509 foreach($score[0]['players'] as $id=>$points)
1511 $name = DB_get_name('userid',$id); /*TODO*/
1512 $footer.= "<td> ".substr($name,0,2)." </td>";
1514 $footer.="<td>P</td>\n </tr>\n </tfoot>\n";
1518 $body.= " <tbody>\n";
1520 foreach($score as $game)
1524 $userhash = DB_get_hash_from_gameid_and_userid($game['gameid'],$userid);
1525 /* create link to old games only if you are logged in and its your game*/
1526 if(isset($_SESSION['id']) && $_SESSION['id']==$userid)
1527 $body.=" <td> <a href=\"".$INDEX."?action=game&me=".$userhash."\">$i</a></td>";
1529 $body.=" <td>$i</td>";
1531 foreach($game['players'] as $id=>$points)
1532 $body.="<td>".$points."</td>";
1533 $body.="<td>".$game['points'];
1535 /* check for solo */
1538 $body.="</td></tr>\n";
1546 $output.=" </tbody>\n</table>\n</div>\n";
1551 function createCache($content, $cacheFile)
1553 $fp = fopen($cacheFile,"w");
1556 fwrite($fp,$content);
1560 echo "WARNING: couldn't create cache file";
1565 function getCache($cacheFile, $expireTime)
1567 if( file_exists($cacheFile) &&
1568 filemtime($cacheFile )>( time() - $expireTime ) )
1570 return file_get_contents($cacheFile);
1576 function check_vacation($userid)
1578 /* get start date */
1579 $result = DB_query_array("SELECT value FROM User_Prefs".
1580 " WHERE user_id='$userid' AND pref_key='vacation start'" );
1582 $start = $result[0];
1587 $result = DB_query_array("SELECT value FROM User_Prefs".
1588 " WHERE user_id='$userid' AND pref_key='vacation stop'" );
1595 $result = DB_query_array("SELECT value FROM User_Prefs".
1596 " WHERE user_id='$userid' AND pref_key='vacation comment'" );
1598 $comment = $result[0];
1602 /* check if user is on vacation. TODO: use user's timezone */
1603 if( (time() - strtotime($start) >0) &&
1604 (strtotime($stop) - time() >0))
1605 return array ($start,$stop,$comment);
1610 function cancel_game($why,$gameid)
1612 $gameid = DB_quote_smart($gameid);
1614 /* update the game table */
1618 DB_query("UPDATE Game SET status='cancel-timedout' WHERE id=$gameid");
1621 DB_query("UPDATE Game SET status='cancel-nines' WHERE id=$gameid");
1624 DB_query("UPDATE Game SET status='cancel-trump' WHERE id=$gameid");
1627 DB_query("UPDATE Game SET status='cancel-noplay' WHERE id=$gameid");
1630 DB_query("UPDATE Game SET status='cancel-lowtrump' WHERE id=$gameid");
1633 /* set each player to gameover */
1634 $result = DB_query("SELECT id FROM Hand WHERE game_id=".DB_quote_smart($gameid));
1635 while($r = DB_fetch_array($result))
1638 DB_query("UPDATE Hand SET status='gameover' WHERE id=".DB_quote_smart($id));
1644 function get_user_token($userid)
1649 $date = DB_get_user_creation_date($userid);
1650 $name = DB_get_name('userid',$userid);
1653 $token = md5("token".$name.$date);
1658 function verify_password($email, $password)
1660 /* verify password, if old password has length 32 assume it's an old md5, else use new password scheme */
1661 /* return 0 if verified, else return error code
1662 * 1 can't find email
1663 * 2 can't calculate correct hash
1667 /* check user email by getting his id */
1668 $userid = DB_get_userid('email',$email);
1672 /* test for temporary passwords, only valid for one date (tested in the DB) */
1673 $tmppasswd = md5($password);
1674 if(DB_check_recovery_passwords($tmppasswd,$email))
1677 /* get saved password */
1678 $existingpassword = DB_get_passwd_by_userid($userid);
1680 if(strlen($existingpassword)==32) /* old password type */
1682 if ($existingpassword == md5($password))
1684 /* update password to new crypt version */
1685 // create a password hash using the crypt function, need php 5.3 for this
1686 // create and random salt
1687 $salt = substr(str_replace('+', '.', base64_encode(sha1(microtime(true), true))), 0, 22);
1688 // hash incoming password using 12 rounds of blowfish
1689 $hash = crypt($password, '$2y$12$' . $salt);
1690 if(strlen($hash)>13)
1691 DB_query("UPDATE User SET password='$hash' where id='$userid'");
1700 if ($existingpassword == crypt($password, $existingpassword))
1707 /* language functions */
1708 function detectlanguage()
1710 /* read out browser's prefered language, taken from php-manual*/
1711 $langcode = explode(";", $_SERVER['HTTP_ACCEPT_LANGUAGE']);
1712 $langcode = explode(",", $langcode['0']);
1713 return $langcode['0'];
1716 function set_language($l,$type='lang')
1720 $userPREF = DB_get_PREF($l);
1721 $l = $userPREF['language'];
1727 putenv("LC_ALL=de_DE");
1728 setlocale(LC_ALL, "de_DE");
1731 putenv("LC_ALL=en_US");
1732 setlocale(LC_ALL, "en_US");
1736 // Specify location of translation tables
1737 bindtextdomain("edoko", "./locale");
1738 bind_textdomain_codeset("edoko", 'UTF-8');
1740 textdomain("edoko");