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";
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*/
332 if($RULES['schweinchen']=='both' && $GAME['schweinchen-who'])
334 if($a == 19 || $a == 20 )
336 if($b == 19 || $b == 20 )
339 else if($RULES['schweinchen']=='second' && $GAME['schweinchen-second'])
341 if($a == 19 || $a == 20 )
343 if($b == 19 || $b == 20 )
346 else if($RULES['schweinchen']=='secondaftercall' && $GAME['schweinchen-who'] && $GAME['schweinchen-second'] )
348 /* check if a call was made either by the player or his partner. If so activate Schweinchen rule. */
349 if(DB_get_call_by_hash($GAME['schweinchen-who']) || DB_get_partner_call_by_hash($GAME['schweinchen-who']) )
351 if($a == 19 || $a == 20 )
353 if($b == 19 || $b == 20 )
356 /* if not, do nothing and the foxes are just handeled as normal trump */
362 /* check for ten of hearts rule */
363 if($RULES["dullen"]=="secondwins")
364 if($a==1 && $b==1) /* both 10 of hearts */
365 return 0; /* second one wins.*/
369 /* no special cases here */
373 if(is_trump($a) && is_trump($b) && $a<=$b)
375 else if(is_trump($a) && is_trump($b) )
378 { /*$a is not a trump */
382 { /* both no trump */
385 $posA = pos_array($a,$CARDS["clubs"]);
386 $posB = pos_array($b,$CARDS["clubs"]);
394 $posA = pos_array($a,$CARDS["spades"]);
395 $posB = pos_array($b,$CARDS["spades"]);
403 $posA = pos_array($a,$CARDS["hearts"]);
404 $posB = pos_array($b,$CARDS["hearts"]);
412 $posA = pos_array($a,$CARDS["diamonds"]);
413 $posB = pos_array($b,$CARDS["diamonds"]);
420 /* not the same suit and no trump: a wins */
426 function get_winner($p,$mode)
428 /* get all 4 cards played in a trick, in the order they are played */
431 $c1pos = $tmp["pos"];
435 $c2pos = $tmp["pos"];
439 $c3pos = $tmp["pos"];
443 $c4pos = $tmp["pos"];
445 /* first card is better than all the rest */
446 if( compare_cards($c1,$c2,$mode) && compare_cards($c1,$c3,$mode) && compare_cards($c1,$c4,$mode) )
449 /* second card is better than first and better than the rest */
450 if( !compare_cards($c1,$c2,$mode) && compare_cards($c2,$c3,$mode) && compare_cards($c2,$c4,$mode) )
453 /* third card is better than first card and better than last */
454 if( !compare_cards($c1,$c3,$mode) && compare_cards($c3,$c4,$mode) )
455 /* if second card is better than first, third card needs to be even better */
456 if( !compare_cards($c1,$c2,$mode) && !compare_cards($c2,$c3,$mode) )
458 /* second is worse than first, e.g. not following suite */
459 else if (compare_cards($c1,$c2,$mode) )
462 /* non of the above */
466 function count_nines($cards)
470 foreach($cards as $c)
472 if($c == "25" || $c == "26") $nines++;
473 else if($c == "33" || $c == "34") $nines++;
474 else if($c == "41" || $c == "42") $nines++;
475 else if($c == "47" || $c == "48") $nines++;
481 function check_wedding($cards)
484 if( in_array("3",$cards) && in_array("4",$cards) )
490 function count_trump($cards,$status='pregame')
496 /* count each trump, including the foxes, since this is used to determine poverty status */
497 foreach($cards as $c)
501 /* In case we really want to know the amount of trump, we can use the status variable.
502 * This is needed for example to figure out what icon to display on the table in case of
503 * trump given back in poverty */
504 if($status=='all') return $trump;
506 /* normally foxes don't count as trump, so we substract them here
507 * in case someone has schweinchen, one or two of them should count as trump
508 * though, so we need to add one trump for those cases */
511 if( in_array("19",$cards))
513 if( in_array("20",$cards) )
516 /* handle case where player has schweinchen */
517 if( in_array("19",$cards) && in_array("20",$cards) )
518 switch($RULES["schweinchen"])
521 /* add two, in case the player has both foxes (schweinchen) */
526 case "secondaftercall":
527 /* add one, in case the player has both foxes (schweinchen) */
537 function check_low_trump($cards)
541 if($RULES['lowtrump']=='none')
544 /* check if we have low trump */
547 foreach($cards as $card)
549 /* card a trump, but not a diamond? */
554 /* handle case where player has schweinchen */
555 if( in_array("19",$cards) && in_array("20",$cards) )
556 switch($RULES["schweinchen"])
560 case "secondaftercall":
570 function create_array_of_random_numbers($useridA,$useridB,$useridC,$useridD)
578 /* fix the hands; makes debugging easier; the following hands have lots of sicknesses,
579 * to make testing easier
581 $r[ 0]=1; $r[12]=47; $r[24]=13; $r[36]=37;
582 $r[ 1]=2; $r[13]=23; $r[25]=14; $r[37]=38;
583 $r[ 2]=3; $r[14]=27; $r[26]=15; $r[38]=39;
584 $r[ 3]=4; $r[15]=16; $r[27]=28; $r[39]=40;
585 $r[ 4]=5; $r[16]=17; $r[28]=29; $r[40]=21;
586 $r[ 5]=18; $r[17]=6; $r[29]=30; $r[41]=42;
587 $r[ 6]=41; $r[18]=7; $r[30]=31; $r[42]=43;
588 $r[ 7]=22; $r[19]=8; $r[31]=32; $r[43]=20;
589 $r[ 8]=45; $r[20]=9; $r[32]=33; $r[44]=19;
590 $r[ 9]=46; $r[21]=10; $r[33]=44; $r[45]=24;
591 $r[10]=35; $r[22]=11; $r[34]=48; $r[46]=25;
592 $r[11]=36; $r[23]=12; $r[35]=34; $r[47]=26;
596 /* check if we can find a game were non of the player was involved and return
599 $userstr = "'".implode("','",array($useridA,$useridB,$useridC,$useridD))."'";
600 $randomnumbers = DB_get_unused_randomnumbers($userstr);
601 $randomnumbers = explode(":",$randomnumbers);
603 if(sizeof($randomnumbers)==48)
604 return $randomnumbers;
606 /* need to create new numbers */
610 /* shuffle using a better random generator than the standard one */
611 for ($i = 0; $i <48; $i++)
613 $j = @mt_rand(0, $i);
623 function display_cards($me,$myturn)
628 function have_suit($cards,$c)
633 if(in_array($c,$CARDS["trump"]))
634 $suite = $CARDS["trump"];
635 else if(in_array($c,$CARDS["clubs"]))
636 $suite = $CARDS["clubs"];
637 else if(in_array($c,$CARDS["spades"]))
638 $suite = $CARDS["spades"];
639 else if(in_array($c,$CARDS["hearts"]))
640 $suite = $CARDS["hearts"];
641 else if(in_array($c,$CARDS["diamonds"]))
642 $suite = $CARDS["diamonds"];
644 foreach($cards as $card)
646 if(in_array($card,$suite))
653 function same_type($card,$c)
658 /* figure out what kind of card c is */
659 if(in_array($c,$CARDS["trump"]))
660 $suite = $CARDS["trump"];
661 else if(in_array($c,$CARDS["clubs"]))
662 $suite = $CARDS["clubs"];
663 else if(in_array($c,$CARDS["spades"]))
664 $suite = $CARDS["spades"];
665 else if(in_array($c,$CARDS["hearts"]))
666 $suite = $CARDS["hearts"];
667 else if(in_array($c,$CARDS["diamonds"]))
668 $suite = $CARDS["diamonds"];
670 /* card is the same suid return 1 */
671 if(in_array($card,$suite))
677 function set_gametype($gametype)
691 $CARDS["trump"] = array('1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16',
692 '17','18','19','20','21','22','23','24','25','26');
693 $CARDS["diamonds"] = array();
694 $CARDS["clubs"] = array('27','28','29','30','31','32','33','34');
695 $CARDS["spades"] = array('35','36','37','38','39','40','41','42');
696 $CARDS["hearts"] = array('43','44','45','46','47','48');
697 $CARDS["foxes"] = array('19','20');
698 if($RULES["dullen"]=='none')
700 $CARDS["trump"] = array('3','4','5','6','7','8','9','10','11','12','13','14','15','16',
701 '17','18','19','20','21','22','23','24','25','26');
702 $CARDS["hearts"] = array('43','44','1','2','45','46','47','48');
704 /* do we need to reorder for Schweinchen? need to search for it because of special case for dullen above*/
705 if($RULES['schweinchen']=='both'&& $GAME['schweinchen-who'])
707 /* find the fox and put them at the top of the stack */
708 foreach(array('19','20') as $fox)
711 $trump = $CARDS['trump'];
712 $key = array_keys($trump, $fox);
716 $foxa[]=$trump[$key[0]];
717 unset($trump[$key[0]]);
718 $trump = array_merge($foxa,$trump);
719 $CARDS['trump'] = $trump;
722 else if( ($RULES['schweinchen']=='second' || $RULES['schweinchen']=='secondaftercall')
723 && $GAME['schweinchen-who'])
725 /* find the fox and put them at the top of the stack */
726 $trump = $CARDS['trump'];
727 $key = array_keys($trump, '19');
731 $foxa[]=$trump[$key[0]];
732 unset($trump[$key[0]]);
733 $trump = array_merge($foxa,$trump);
734 $CARDS['trump'] = $trump;
738 $CARDS["trump"] = array('3','4','5','6','7','8','9','10');
739 $CARDS["clubs"] = array('27','28','29','30','31','32','11','12','33','34');
740 $CARDS["spades"] = array('35','36','37','38','39','40','13','14','41','42');
741 $CARDS["hearts"] = array('43','44', '1', '2','45','46','15','16','47','48');
742 $CARDS["diamonds"] = array('19','20','21','22','23','24','17','18','25','26');
743 $CARDS["foxes"] = array();
746 $CARDS["trump"] = array('11','12','13','14','15','16','17','18');
747 $CARDS["clubs"] = array('27','28','29','30','31','32','3', '4','33','34');
748 $CARDS["spades"] = array('35','36','37','38','39','40','5', '6','41','42');
749 $CARDS["hearts"] = array('43','44', '1', '2','45','46','7', '8','47','48');
750 $CARDS["diamonds"] = array('19','20','21','22','23','24','9','10','25','26');
751 $CARDS["foxes"] = array();
754 $CARDS["trump"] = array();
755 $CARDS["clubs"] = array('27','28','29','30','31','32','3', '4','11','12','33','34');
756 $CARDS["spades"] = array('35','36','37','38','39','40','5', '6','13','14','41','42');
757 $CARDS["hearts"] = array('43','44', '1', '2','45','46','7', '8','15','16','47','48');
758 $CARDS["diamonds"] = array('19','20','21','22','23','24','9','10','17','18','25','26');
759 $CARDS["foxes"] = array();
762 $CARDS["trump"] = array('1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16',
763 '17','18','27','28','29','30','31','32','33','34');
764 $CARDS["clubs"] = array();
765 $CARDS["spades"] = array('35','36','37','38','39','40','41','42');
766 $CARDS["hearts"] = array('43','44','45','46','47','48');
767 $CARDS["diamonds"] = array('19','20','21','22','23','24','25','26');
768 $CARDS["foxes"] = array();
769 if($RULES["dullen"]=='none')
771 $CARDS["trump"] = array('3','4','5','6','7','8','9','10','11','12','13','14','15','16',
772 '17','18','27','28','29','30','31','32','33','34');
773 $CARDS["hearts"] = array('43','44','1','2','45','46','47','48');
777 $CARDS["trump"] = array('1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16',
778 '17','18','35','36','37','38','39','40','41','42');
779 $CARDS["clubs"] = array('27','28','29','30','31','32','33','34');
780 $CARDS["spades"] = array();
781 $CARDS["hearts"] = array('43','44','45','46','47','48');
782 $CARDS["diamonds"] = array('19','20','21','22','23','24','25','26');
783 $CARDS["foxes"] = array();
784 if($RULES["dullen"]=='none')
786 $CARDS["trump"] = array('3','4','5','6','7','8','9','10','11','12','13','14','15','16',
787 '17','18','35','36','37','38','39','40','41','42');
788 $CARDS["hearts"] = array('43','44','1','2','45','46','47','48');
792 $CARDS["trump"] = array('1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16',
793 '17','18','43','44','45','46','47','48');
794 $CARDS["clubs"] = array('27','28','29','30','31','32','33','34');
795 $CARDS["spades"] = array('35','36','37','38','39','40','41','42');
796 $CARDS["hearts"] = array();
797 $CARDS["diamonds"] = array('19','20','21','22','23','24','25','26');
798 $CARDS["foxes"] = array();
799 if($RULES["dullen"]=='none')
801 $CARDS["trump"] = array('3','4','5','6','7','8','9','10','11','12','13','14','15','16',
802 '17','18','43','44','1','2','45','46','47','48');
808 function mysort($cards,$gametype)
811 if(isset($PREF['sorting']))
812 if($PREF['sorting']=='high-low')
813 usort ( $cards, 'sort_comp_high_low' );
815 usort ( $cards, 'sort_comp_low_high' );
817 usort ( $cards, 'sort_comp_high_low' );
821 function sort_comp_high_low($a,$b)
826 $ALL = array_merge($CARDS['trump'],$CARDS['diamonds'],$CARDS['clubs'],
827 $CARDS['hearts'],$CARDS['spades']);
829 return pos_array($a,$ALL)-pos_array($b,$ALL);
832 function sort_comp_low_high($a,$b)
837 $ALL = array_merge($CARDS['trump'],$CARDS['diamonds'],$CARDS['clubs'],
838 $CARDS['hearts'],$CARDS['spades']);
840 return -pos_array($a,$ALL)+pos_array($b,$ALL);
843 function can_call($what,$hash)
845 /* figure out if a person can make a call:
846 $what in 0,30,60,90,120 = points of the call
847 $hash = the hash of the person who wants to make the call
850 0 can't make that call
852 2 can make the call, but this is the last chance to do so...
857 /* get some information
859 $gameid = DB_get_gameid_by_hash($hash);
860 $gametype = DB_get_gametype_by_gameid($gameid);
861 $oldcall = DB_get_call_by_hash($hash); /* did the person already made a call? */
862 $pcall = DB_get_partner_call_by_hash($hash); /* did the partner already made a call */
865 /* you're call must be better than the one you or your partner already made
867 if( ($pcall!=NULL && ($what >= $pcall))
868 || ($oldcall!=NULL && ($what >=$oldcall)) )
873 /* for some rules we need to know how many cards people have
875 $NRcards = count(DB_get_hand($hash));
880 $user = DB_get_hash_from_game_and_pos($gameid,$i);
881 $NRallcards += count(DB_get_hand($user));
884 /* in case of a wedding, everything will be delayed by an offset
887 if($gametype=="wedding")
889 $offset = DB_get_sickness_by_gameid($gameid);
890 if ($offset <0) /* not resolved */
894 /* now check if the call is allowed depending on the rule set
896 switch ($RULES["call"])
899 /* calls can be made before/while you play your card...
900 * first card = 120, second card = 90, etc.
902 if( 4-($what/30) == 12 - ($NRcards + $offset))
904 if( 4-($what/30) > 12 - ($NRcards + $offset))
908 /* you can make the first call anytime during the first trick
910 if( 27+4*($what/30) == $NRallcards + $offset*4)
912 if( 27+4*($what/30) < $NRallcards + $offset*4)
916 /* you can call 120 with 12 cards, 90 with 9 or more cards, 60 with 6 or more, etc.
917 * you can't skip a call though
920 /* figure out last call
922 if($oldcall!=NULL && $pcall!=NULL)
923 $mincall = ($oldcall>$pcall) ? $pcall : $oldcall;
924 else if($oldcall!=NULL)
926 else if ($pcall!=NULL)
932 if( 12 == ($NRcards + $offset))
936 else if( 12 < ($NRcards + $offset))
940 else if ( 9 == ($NRcards + $offset))
942 if( ($mincall>=0 && $mincall<=120 && $what<=90 ) )
945 else if ( 9 < ($NRcards + $offset))
947 if( ($mincall>=0 && $mincall<=120 && $what<=90 ) )
950 else if ( 6 == ($NRcards + $offset))
952 if( ($mincall>=0 && $mincall<=90 && $what<=60 ) )
955 else if ( 6 < ($NRcards + $offset))
957 if( ($mincall>=0 && $mincall<=90 && $what<=60 ) )
960 else if ( 3 == ($NRcards + $offset))
962 if( ($mincall>=0 && $mincall<=60 && $what<=30 ) )
965 else if ( 3 < ($NRcards + $offset))
967 if( ($mincall>=0 && $mincall<=60 && $what<=30 ) )
970 else if ( 0 == ($NRcards + $offset))
972 if( ($mincall>=0 && $mincall<=30 && $what==0 ) )
975 else if ( 0 < ($NRcards + $offset))
977 if( ($mincall>=0 && $mincall<=30 && $what==0 ) )
986 function display_table_begin ()
990 $result = DB_query('SELECT User.fullname as name,'.
991 ' Hand.position as position,'.
993 ' Hand.party as party,'.
994 ' Hand.sickness as sickness,'.
1001 ' LEFT JOIN User ON User.id=Hand.user_id'.
1002 ' WHERE Hand.game_id='.DB_quote_smart($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);
1021 function display_table_end ()
1025 $result = DB_query('SELECT User.fullname as name,'.
1026 ' Hand.position as position,'.
1028 ' Hand.party as party,'.
1029 ' Hand.sickness as sickness,'.
1030 ' Hand.point_call,'.
1031 ' User.last_login,'.
1036 ' LEFT JOIN User ON User.id=Hand.user_id'.
1037 ' WHERE Hand.game_id='.DB_quote_smart($gameid).
1038 ' ORDER BY position ASC');
1040 $row0 = DB_fetch_array($result);
1041 $row1 = DB_fetch_array($result);
1042 $row2 = DB_fetch_array($result);
1043 $row3 = DB_fetch_array($result);
1046 display_single_user($row3);
1052 function display_single_user($r,$start=0)
1054 /* start=1, mark starting player, default=0, so the player on the left is not marked */
1056 global $gameid, $debug,$INDEX,$defaulttimezone;
1057 global $RULES,$GAME, $gametype_raw;
1068 $wins = DB_get_number_of_tricks($gameid,$pos);
1069 date_default_timezone_set($defaulttimezone);
1070 $lastlogin = strtotime($r[6]);
1071 date_default_timezone_set($timezone);
1072 $timenow = strtotime(date("Y-m-d H:i:s"));
1073 $gravatar = "$name<br />\n <img class=\"gravatar\" title=\"$name\" src=\"http://www.gravatar.com/avatar/".
1074 md5(strtolower(trim($email)))."?d=identicon\" alt=\"$name's gravatar\" />";
1076 echo " <div class=\"table".($pos-1)."\">\n";
1078 /* mark starting player */
1079 if($start && ! ($party=="re" || $party=="contra"))
1080 echo ' <span class="start">'._('Starting Player')."</span> <br />\n";
1083 echo " <a href=\"".$INDEX."?action=game&me=".$hash."\">";
1084 if($vacation = check_vacation($user))
1086 $start = $vacation[0];
1087 $stop = substr($vacation[1],0,10);
1088 $comment = $vacation[2];
1090 $title = _("begin:")." $start "._("end:")." $stop $comment";
1091 echo " <span class=\"vacation\" title=\"$title\">$gravatar "._("(on vacation until $stop)")."</span> \n";
1094 echo " $gravatar \n";
1098 /* add hints for poverty, wedding, solo, etc */
1099 if( $gametype_raw != "solo")
1100 if( $RULES["schweinchen"]=="both" && $GAME["schweinchen-who"]==$hash )
1101 echo " Schweinchen. <br />";
1103 if($gametype_raw=="poverty" && $party=="re")
1104 if($sickness=="poverty" || ($RULES['lowtrump']=='poverty' && $sickness=='lowtrump'))
1106 $userhash = DB_get_hash_from_gameid_and_userid($gameid,$user);
1107 $cards = DB_get_all_hand($userhash);
1108 $trumpNR = count_trump($cards,'all');
1110 echo " <img src=\"pics/button/poverty_trump_button.png\" class=\"button\" ".
1111 "alt=\"poverty - trump back\" title=\"poverty - trump back\" />\n";
1113 echo " <img src=\"pics/button/poverty_notrump_button.png\" class=\"button\" ".
1114 "alt=\"poverty - no trump back\" title=\"poverty - no trump back\" />\n";
1117 echo " <img src=\"pics/button/poverty_partner_button.png\" class=\"button\" ".
1118 "alt=\"poverty partner\" title=\"poverty partner\" />\n";
1120 if($gametype_raw=="dpoverty")
1122 if($sickness=="poverty" || ($RULES['lowtrump']=='poverty' && $sickness=='lowtrump'))
1124 $userhash = DB_get_hash_from_gameid_and_userid($gameid,$user);
1125 $cards = DB_get_all_hand($userhash);
1126 $trumpNR = count_trump($cards,'all');
1128 echo " <img src=\"pics/button/poverty_trump_button.png\" class=\"button\" ".
1129 "alt=\"poverty < trump back\" title=\"poverty - trump back\" />\n";
1131 echo " <img src=\"pics/button/poverty_notrump_button.png\" class=\"button\" ".
1132 "alt=\"poverty <\" title=\"poverty - no trump back\" />\n";
1135 echo " <img src=\"pics/button/poverty_partner_button.png\" class=\"button\" ".
1136 "alt=\"poverty >\" title=\"poverty partner\" />\n";
1138 if($sickness=="poverty" || ($RULES['lowtrump']=='poverty' && $sickness=='lowtrump'))
1140 $userhash = DB_get_hash_from_gameid_and_userid($gameid,$user);
1141 $cards = DB_get_all_hand($userhash);
1142 $trumpNR = count_trump($cards,'all');
1144 echo " <img src=\"pics/button/poverty2_trump_button.png\" class=\"button\" ".
1145 "alt=\"poverty2 < trump back\" title=\"poverty2 - trump back\"/>\n";
1147 echo " <img src=\"pics/button/poverty2_notrump_button.png\" class=\"button\" ".
1148 "alt=\"poverty2 <\" title=\"poverty2 - no trump back\" />\n";
1151 echo " <img src=\"pics/button/poverty2_partner_button.png\" class=\"button\" ".
1152 "alt=\"poverty2 >\" title=\"poverty2 partner\" />\n";
1154 if($gametype_raw=="wedding" && $party=="re")
1155 if($sickness=="wedding")
1156 echo " <img src=\"pics/button/wedding_button.png\" class=\"button\" alt=\"wedding\" title=\"wedding\" />\n";
1158 echo " <img src=\"pics/button/wedding_partner_button.png\" class=\"button\" ".
1159 "alt=\"wedding partner\" title=\"wedding partner\" />\n";
1161 if( $gametype_raw=='solo' && $party=="re")
1163 $solotype = DB_get_solo_by_gameid($gameid);
1164 $GT = get_display_gametype($gameid);
1166 if($solotype=='queen')
1167 echo " <img src=\"pics/button/queensolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Queen solo\" />\n";
1168 else if($solotype=='jack')
1169 echo " <img src=\"pics/button/jacksolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Jack solo\" />\n";
1170 else if($solotype=='club')
1171 echo " <img src=\"pics/button/clubsolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Club solo\" />\n";
1172 else if($solotype=='spade')
1173 echo " <img src=\"pics/button/spadesolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Spade solo\" />\n";
1174 else if($solotype=='heart')
1175 echo " <img src=\"pics/button/heartsolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Heart solo\" />\n";
1176 else if($solotype=='trumpless')
1177 echo " <img src=\"pics/button/notrumpsolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Trumpless solo\" />\n";
1178 else if($solotype=='trump')
1179 echo " <img src=\"pics/button/trumpsolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Trump solo\" />\n";
1182 /* add point calls */
1186 echo " <img src=\"pics/button/re_button.png\" class=\"button\" alt=\"re\" title=\"Re\" />\n";
1188 echo " <img src=\"pics/button/contra_button.png\" class=\"button\" alt=\"contra\" title=\"Contra\" />\n";
1192 echo " <img src=\"pics/button/0_button.png\" class=\"button\" alt=\"0\" title=\"Call 0\" />\n";
1195 echo " <img src=\"pics/button/30_button.png\" class=\"button\" alt=\"30\" title=\"Call 30\" />\n";
1198 echo " <img src=\"pics/button/60_button.png\" class=\"button\" alt=\"60\" title=\"Call 60\" />\n";
1201 echo " <img src=\"pics/button/90_button.png\" class=\"button\" alt=\"90\" title=\"Call 90\" />\n";
1206 echo " <img src=\"pics/button/time-info.png\" class=\"button\" alt=\"time info\" ".
1207 "title=\"local time: ".date("Y-m-d H:i:s",$timenow). " ".
1208 "last login: ".date("Y-m-d H:i:s",$lastlogin)."\" />";
1210 echo " <br /><span class=\"numberoftricks\">";
1211 /* show how many tricks the person made */
1215 echo _('#tricks 0'); break;
1217 echo _('#tricks 1'); break;
1221 echo _('#tricks few'); break;
1223 echo _('#tricks many'); break;
1230 function display_user_menu($id, $skiphash=NULL)
1232 global $WIKI,$INDEX;
1235 $result = DB_query("SELECT Hand.hash,Hand.game_id,Game.player from Hand".
1236 " LEFT JOIN Game On Hand.game_id=Game.id".
1237 " WHERE Hand.user_id=".DB_quote_smart($id).
1238 " AND Hand.hash!=".DB_quote_smart($skiphash).
1239 " AND ( Game.player='$id' OR ISNULL(Game.player) )".
1240 " AND ( Game.status='pre' OR Game.status='play' )".
1241 " ORDER BY Game.session" );
1243 $result = DB_query('SELECT Hand.hash,Hand.game_id,Game.player from Hand'.
1244 ' LEFT JOIN Game On Hand.game_id=Game.id'.
1245 ' WHERE Hand.user_id='.DB_quote_smart($id).
1246 ' AND ( Game.player='.DB_quote_smart($id).' OR ISNULL(Game.player) )'.
1247 " AND ( Game.status='pre' OR Game.status='play' )".
1248 ' ORDER BY Game.session' );
1251 while( $r = DB_fetch_array($result))
1255 echo "\n<div class=\"usermenu\">\n ";
1256 echo _('It\'s your turn in these games').":\n";
1264 echo " <a href=\"".$INDEX."?action=game&me=".$r[0].
1265 "\"> ".DB_format_gameid($r[1])." </a>\n";
1278 function generate_score_table($session)
1280 /* returns an array with N entries
1281 * $score[$i]["gameid"] = gameid
1282 * $score[$i]["players"] = array (id=>total points)
1283 * $score[$i]["points"] = points for this game
1284 * $score[$i]["solo"] = 1 or 0
1289 /* get all ids, scores and gametypes */
1290 $gameids = DB_get_gameids_of_finished_games_by_session($session);
1292 if($gameids == NULL)
1296 $player_party = array();
1298 /* get player id from the first game */
1299 $result = DB_query('SELECT user_id from Hand'.
1300 ' WHERE Hand.game_id='.DB_quote_smart($gameids[0][0]));
1301 while( $r = DB_fetch_array($result))
1304 /* get party of players for each game in the session */
1305 foreach($player as $id=>$points)
1306 $player_party[$id]=DB_get_party_by_session_and_userid($session,$id);
1308 /* get points and generate table */
1309 foreach($gameids as $gameid)
1311 $re_score = $gameid[1];
1312 $gametype = $gameid[2];
1313 foreach($player as $id=>$points)
1315 $party = $player_party[$id][$i][0];
1317 if($gametype=='solo')
1318 $player[$id] += 3*$re_score;
1320 $player[$id] += $re_score;
1321 else if ($party == 'contra')
1322 $player[$id] -= $re_score;
1324 $score[$i]['gameid'] = $gameid[0] ;
1325 $score[$i]['players'] = $player;
1326 $score[$i]['points'] = abs($re_score);
1327 $score[$i]['solo'] = ($gametype=='solo');
1335 function generate_global_score_table()
1339 /* get all ids, scores and gametypes */
1340 $gameids = DB_get_gameids_of_finished_games_by_session(0);
1342 if($gameids == NULL)
1346 /* get player id, names... from the User table */
1347 $result = DB_query('SELECT User.id, User.fullname FROM User');
1349 /* save information in an array */
1350 while( $r = DB_fetch_array($result))
1351 $player[$r[0]] = array('name'=> $r[1], 'points' => 0 , 'nr' => 0, 'active' => 0,
1352 'response' => 0 , 'solo' => 0, 'soloavg' => 0);
1354 /* get points and generate table */
1355 foreach($gameids as $gameid)
1357 $re_score = $gameid[1];
1358 $gametype = $gameid[2];
1360 /* get players involved in this game */
1361 $result = DB_query('SELECT user_id FROM Hand WHERE game_id='.DB_quote_smart($gameid[0]));
1362 while($r = DB_fetch_array($result))
1365 $party = DB_get_party_by_gameid_and_userid($gameid[0],$id);
1367 if($gametype=='solo')
1368 $player[$id]['points'] += 3*$re_score;
1370 $player[$id]['points'] += $re_score;
1371 else if ($party == 'contra')
1372 $player[$id]['points'] -= $re_score;
1374 $player[$id]['nr']+=1;
1378 /* add number of active games */
1379 $result = DB_query_array_all("SELECT user_id, COUNT(*) as c " .
1381 " LEFT JOIN Game ON Game.id=game_id".
1382 " WHERE Game.status IN ('pre','play')".
1383 " GROUP BY user_id");
1385 foreach($result as $res)
1387 $player[$res[0]]['active'] = $res[1];
1390 /* response time of users*/
1391 $result = DB_query_array_all("SELECT user_id,".
1392 "IFNULL(AVG(if(P1.sequence in (2,3,4),".
1393 "-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 ".
1395 "LEFT JOIN Hand_Card ON P1.hand_card_id=Hand_Card.id ".
1396 "LEFT JOIN Hand ON Hand.id=Hand_Card.hand_id ".
1397 "GROUP BY user_id ");
1399 foreach($result as $res)
1401 $player[$res[0]]['response'] = $res[1];
1405 $result = DB_query_array_all("SELECT user_id as uid,".
1407 " COUNT(*)/(SELECT COUNT(*) FROM Hand LEFT JOIN User ON User.id=Hand.user_id WHERE User.id=uid) as c ".
1409 " LEFT JOIN Hand ON Hand.position=startplayer AND Game.id=Hand.game_id ".
1410 " WHERE type='solo' AND Game.status='gameover' ".
1411 " GROUP BY user_id ");
1413 foreach($result as $res)
1415 $player[$res[0]]['solo'] = $res[1];
1416 $player[$res[0]]['soloavg'] = $res[2];
1420 /* sort everything nicely */
1424 if($a['nr']==0) return 1;
1425 if($b['nr']==0) return 1;
1427 $a=$a['points']/$a['nr'];
1428 $b=$b['points']/$b['nr'];
1432 return ($a > $b) ? -1 : 1;
1434 usort($player,'cmp');
1437 foreach($player as $pl)
1439 /* limit to players with at least 10 games */
1441 $return[] = array( $pl['name'], round($pl['points']/$pl['nr'],3), $pl['points'],$pl['nr'],$pl['active'],
1442 $pl['response'],$pl['solo'],$pl['soloavg']);
1448 function format_score_table_ascii($score)
1451 if(sizeof($score)==0)
1454 /* truncate table if we have too many games */
1455 $max = sizeof($score);
1456 if($max>6) $output.=" "._("(table truncated to last 6 games)")."\n";
1459 foreach($score[0]['players'] as $id=>$points)
1461 $name = DB_get_name('userid',$id); /*TODO*/
1462 $output.= " ".substr($name,0,2)." |";
1465 $output.= "------+------+------+------+------+\n";
1467 /* output score for each game */
1469 foreach($score as $game)
1472 if($i-1<$max-6) continue;
1474 foreach($game['players'] as $id=>$points)
1475 $output.=str_pad($points,6," ",STR_PAD_LEFT)."|";
1476 $output.=str_pad($game['points'],4," ",STR_PAD_LEFT);
1478 /* check for solo */
1489 function format_score_table_html($score,$userid)
1493 if(sizeof($score)==0)
1496 $output = "<div class=\"scoretable\">\n<table class=\"score\">\n";
1500 $header.= " <thead>\n <tr>\n";
1501 $header.= " <th> No </th>";
1502 foreach($score[0]['players'] as $id=>$points)
1504 $name = DB_get_name('userid',$id); /*TODO*/
1505 $header.= "<th> ".substr($name,0,2)." </th>";
1507 $header.="<th>P</th>\n </tr>\n </thead>\n";
1509 /* use the same as footer */
1511 $footer.= " <tfoot>\n <tr>\n";
1512 $footer.= " <td> No </td>";
1513 foreach($score[0]['players'] as $id=>$points)
1515 $name = DB_get_name('userid',$id); /*TODO*/
1516 $footer.= "<td> ".substr($name,0,2)." </td>";
1518 $footer.="<td>P</td>\n </tr>\n </tfoot>\n";
1522 $body.= " <tbody>\n";
1524 foreach($score as $game)
1528 $userhash = DB_get_hash_from_gameid_and_userid($game['gameid'],$userid);
1529 /* create link to old games only if you are logged in and its your game*/
1530 if(isset($_SESSION['id']) && $_SESSION['id']==$userid)
1531 $body.=" <td> <a href=\"".$INDEX."?action=game&me=".$userhash."\">$i</a></td>";
1533 $body.=" <td>$i</td>";
1535 foreach($game['players'] as $id=>$points)
1536 $body.="<td>".$points."</td>";
1537 $body.="<td>".$game['points'];
1539 /* check for solo */
1542 $body.="</td></tr>\n";
1550 $output.=" </tbody>\n</table>\n</div>\n";
1555 function createCache($content, $cacheFile)
1557 $fp = fopen($cacheFile,"w");
1560 fwrite($fp,$content);
1564 echo "WARNING: couldn't create cache file";
1569 function getCache($cacheFile, $expireTime)
1571 if( file_exists($cacheFile) &&
1572 filemtime($cacheFile )>( time() - $expireTime ) )
1574 return file_get_contents($cacheFile);
1580 function check_vacation($userid)
1582 /* get start date */
1583 $result = DB_query_array("SELECT value FROM User_Prefs".
1584 " WHERE user_id=".DB_quote_smart($userid)." AND pref_key='vacation start'" );
1586 $start = $result[0];
1591 $result = DB_query_array("SELECT value FROM User_Prefs".
1592 " WHERE user_id=".DB_quote_smart($userid)." AND pref_key='vacation stop'" );
1599 $result = DB_query_array("SELECT value FROM User_Prefs".
1600 " WHERE user_id=".DB_quote_smart($userid)." AND pref_key='vacation comment'" );
1602 $comment = $result[0];
1606 /* check if user is on vacation. TODO: use user's timezone */
1607 if( (time() - strtotime($start) >0) &&
1608 (strtotime($stop) - time() >0))
1609 return array ($start,$stop,$comment);
1614 function cancel_game($why,$gameid)
1616 $gameid = DB_quote_smart($gameid);
1618 /* update the game table */
1622 DB_query("UPDATE Game SET status='cancel-timedout' WHERE id=$gameid");
1625 DB_query("UPDATE Game SET status='cancel-nines' WHERE id=$gameid");
1628 DB_query("UPDATE Game SET status='cancel-trump' WHERE id=$gameid");
1631 DB_query("UPDATE Game SET status='cancel-noplay' WHERE id=$gameid");
1634 DB_query("UPDATE Game SET status='cancel-lowtrump' WHERE id=$gameid");
1637 /* set each player to gameover */
1638 $result = DB_query("SELECT id FROM Hand WHERE game_id=".DB_quote_smart($gameid));
1639 while($r = DB_fetch_array($result))
1642 DB_query("UPDATE Hand SET status='gameover' WHERE id=".DB_quote_smart($id));
1648 function get_user_token($userid)
1653 $date = DB_get_user_creation_date($userid);
1654 $name = DB_get_name('userid',$userid);
1657 $token = md5("token".$name.$date);
1662 function verify_password($email, $password)
1664 /* verify password, if old password has length 32 assume it's an old md5, else use new password scheme */
1665 /* return 0 if verified, else return error code
1666 * 1 can't find email
1667 * 2 can't calculate correct hash
1671 /* check user email by getting his id */
1672 $userid = DB_get_userid('email',$email);
1676 /* test for temporary passwords, only valid for one date (tested in the DB) */
1677 $tmppasswd = md5($password);
1678 if(DB_check_recovery_passwords($tmppasswd,$email))
1681 /* get saved password */
1682 $existingpassword = DB_get_passwd_by_userid($userid);
1684 if(strlen($existingpassword)==32) /* old password type */
1686 if ($existingpassword == md5($password))
1688 /* update password to new crypt version */
1689 // create a password hash using the crypt function, need php 5.3 for this
1690 // create and random salt
1691 $salt = substr(str_replace('+', '.', base64_encode(sha1(microtime(true), true))), 0, 22);
1692 // hash incoming password using 12 rounds of blowfish
1693 $hash = crypt($password, '$2y$12$' . $salt);
1694 if(strlen($hash)>13)
1695 DB_query("UPDATE User SET password='$hash' where id='$userid'");
1704 if ($existingpassword == crypt($password, $existingpassword))
1711 /* language functions */
1712 function detectlanguage()
1714 /* read out browser's prefered language, taken from php-manual*/
1715 $langcode = explode(";", $_SERVER['HTTP_ACCEPT_LANGUAGE']);
1716 $langcode = explode(",", $langcode['0']);
1717 return $langcode['0'];
1720 function set_language($l,$type='lang')
1724 $userPREF = DB_get_PREF($l);
1725 $l = $userPREF['language'];
1731 putenv("LC_ALL=de_DE");
1732 setlocale(LC_ALL, "de_DE");
1735 putenv("LC_ALL=en_US");
1736 setlocale(LC_ALL, "en_US");
1740 // Specify location of translation tables
1741 bindtextdomain("edoko", "./locale");
1742 bind_textdomain_codeset("edoko", 'UTF-8');
1744 textdomain("edoko");
1749 function get_display_gametype($gameid)
1751 /* return a readable string that can be displayed to show the game type
1752 * this means hiding silent solo from the user
1755 $gametype = DB_get_gametype_by_gameid($gameid);
1757 if ($gametype == 'normal')
1759 else if($gametype=='solo')
1761 $solotype = DB_get_solo_by_gameid($gameid);
1766 $GT = _('trumpless solo');
1769 $GT = _('jack solo');
1772 $GT = _('queen solo');
1775 $GT = _('trump solo');
1778 $GT = _('club solo');
1781 $GT = _('spade solo');
1784 $GT = _('heart solo');
1787 $GT = _('normal'); /* this is change compared to $gametype */
1791 else if ($gametype == 'wedding')
1793 else if ($gametype == 'poverty')
1795 else if ($gametype == 'dpoverty')
1796 $GT = _('double poverty');