in some cases the user has to reload the page to get to the next pre-game phase....
[e-DoKo.git] / include / functions.php
1 <?php
2 /* Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Arun Persaud <arun@nubati.net>
3  *
4  *   This file is part of e-DoKo.
5  *
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.
10  *
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.
15  *
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/>.
18  *
19  */
20
21 /* make sure that we are not called from outside the scripts,
22  * use a variable defined in config.php to check this
23  */
24 if(!isset($HOST))
25   exit;
26
27 function config_check()
28 {
29   global $EmailName,$EMAIL_REPLY,$ADMIN_NAME,$ADMIN_EMAIL,$DB_work;
30
31   /* check if some variables are set in the config file, else set defaults */
32   if(!isset($EmailName))
33     $EmailName='[DoKo] ';
34   if(isset($EMAIL_REPLY))
35     {
36       ini_set('sendmail_from',$EMAIL_REPLY);
37     }
38   if(!isset($ADMIN_NAME))
39     {
40       output_header();
41       echo '<h1>Setup not completed</h1>';
42       echo 'You need to set $ADMIN_NAME in config.php.';
43       output_footer();
44       exit();
45     }
46   if(!isset($ADMIN_EMAIL))
47     {
48       output_header();
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.';
52       output_footer();
53       exit();
54     }
55   if(!isset($DB_work))
56     {
57       output_header();
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.';
63       output_footer();
64       exit();
65     }
66   if($DB_work)
67     {
68       output_header();
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 ;)").
71         '</div>';
72       output_footer();
73       exit();
74     }
75
76   return;
77 }
78
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);
91
92 /* define possible status for showing cards */
93
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)*/
100
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
105  */
106
107 function mymail($uid,$gameid=0,$type,$message)
108 {
109   global $EmailName,$WIKI,$PREF;
110
111   /* uid can be either a single uid or an array, convert everything to
112    *  an array, so that we can loop over it */
113   if(!is_array($uid))
114     {
115       $to_uid=$uid;
116       $uid = array();
117       $uid[]=$to_uid;
118     }
119
120   foreach($uid as $user)
121     {
122       /* do we send the email right away or save it in the database? */
123       $send_now = 1;
124
125       $name = DB_get_name('userid',$user);
126       $To   = DB_get_email('userid',$user);
127
128       /* check if user wants email right away or if we should save it in
129        * the database for later delivery
130        */
131
132       $uidPREF = DB_get_PREF($user);
133       if( $uidPREF['digest'] != 'digest-off' )
134         $send_now = 0;
135       /* use local language */
136       set_language($uidPREF['language']);
137
138       $header  = sprintf(_('Hello %s'),$name);
139       $header .= "\n\n";
140
141       /* add standard header and footer */
142       $subject = "$EmailName ";
143       if($gameid)
144         $game = DB_format_gameid($gameid);
145       else
146         $game = '';
147
148       switch($type)
149         {
150         case GAME_CANCELED:
151           $subject.=sprintf(_('Game %s canceled'),$game);
152           break;
153         case GAME_CANCELED_POVERTY:
154           $subject.=sprintf(_('Game %s canceled (poverty not resolved)'),$game);
155           break;
156         case GAME_CANCELED_TIMEOUT:
157           $subject.=sprintf(_('Game %s canceled (timed out)'),$game);
158           break;
159         case GAME_YOUR_TURN:
160           $subject.=sprintf(_('A card has been played in game %s'),$game);
161           break;
162         case GAME_READY:
163           $subject.=sprintf(_('Ready, set, go... (game %s)'),$game);
164           break;
165         case GAME_POVERTY:
166           $subject.=sprintf(_('Poverty (game %s)'),$game);
167           break;
168         case GAME_DPOVERTY:
169           $subject.=sprintf(_('Double poverty (game %s)'),$game);
170           break;
171         case GAME_OVER:
172           $subject.=sprintf(_('Game over (game %s)'),$game);
173           break;
174         case GAME_RECOVERY:
175           $subject.=_('Recovery');
176           break;
177         case GAME_REMINDER:
178           $subject.=sprintf(_("Reminder: game %s it's your turn"),$game);
179           break;
180         case GAME_NEW:
181           $subject.=sprintf(_('You are invited to a game of DoKo (game %s)'),$game);
182           break;
183         default:
184           $subject.=sprintf(_('Problem with email, contact admin (errorcode %d)'),$gameid);
185         }
186
187       /* standard goodbye */
188       $footer  = "\n"._('Have a nice day')."\n   "._('your E-Doko service department').
189         "\n\n".
190         "-- \n".
191         _('You can change your mail delivery mode in the preference menu.').
192         "\n".
193         _('web').': http://doko.nubati.net   '.
194         _('help, bugs, etc.').": $WIKI";
195
196       if($send_now)
197         sendmail($To,$subject,$header.$message.$footer);
198       else
199         {
200           /* store email in database */
201           DB_digest_insert_email($To,$message,$type,$gameid);
202         }
203     }
204
205   /* reset language to original user*/
206   set_language($PREF['language']);
207
208   return;
209 }
210
211 function sendmail($To,$Subject,$message)
212 {
213   /* this function sends the mail or outputs to the screen in case of debugging */
214   global $debug,$EMAIL_REPLY;
215
216   $header = "";
217
218   if(isset($EMAIL_REPLY))
219     $header .= "From: e-DoKo daemon <$EMAIL_REPLY>\r\n";
220
221   $header .= "Content-Type: text/plain; charset = \"UTF-8\";\r\n";
222   $header .= "Content-Transfer-Encoding: 8bit\r\n";
223   $header .= "\r\n";
224
225   if($debug)
226     {
227       /* display email on screen,
228        * change txt -> html
229        */
230       $message = str_replace("\n","<br />\n",$message);
231       $message = preg_replace("#(\w+://[^<>\s]+[\w/]*)#",
232                               "<a href=\"$1\">$1</a>", $message);
233
234       echo "<br />To: $To<br />";
235       echo $header."<br />";
236       echo "Subject: $Subject <br />$message<br />\n";
237     }
238   else
239     mail($To,$Subject,$message,$header);
240
241   return;
242 }
243
244 function myisset()
245 {
246   /* returns 1 if all names passed as args are defined by a GET or POST statement,
247    * else return 0
248    */
249
250   $ok   = 1;
251   $args = func_get_args();
252
253   foreach($args as $arg)
254     {
255       $ok = $ok * isset($_REQUEST[$arg]);
256       /*echo "$arg: ok = $ok <br />";
257        */
258     }
259   return $ok;
260 }
261
262 function myerror($message)
263 {
264   echo "<span class=\"error\">".htmlspecialchars($message)."</span>\n";
265   sendmail($ADMIN_EMAIL,$EmailName." Error in Code",$message);
266   return;
267 }
268
269 function pos_array($c,$arr)
270 {
271   $ret = 0;
272
273   $i   = 0;
274   foreach($arr as $a)
275     {
276       $i++;
277       if($a == $c)
278         {
279           $ret = $i;
280           break;
281         }
282     }
283   return $ret;
284 }
285
286 function is_trump($c)
287 {
288   global $CARDS;
289
290   if(in_array($c,$CARDS["trump"]))
291     return 1;
292   else
293     return 0;
294 }
295
296 function is_same_suite($c1,$c2)
297 {
298   global $CARDS;
299
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;
305
306   return 0;
307 }
308
309 function compare_cards($a,$b,$game)
310 {
311   /* if "a" is higher than "b" return 1, else 0, "a" being the card first played */
312
313   global $CARDS;
314   global $RULES;
315   global $GAME;
316
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
320    */
321   if( $a/2 - (int)($a/2) != 0.5)
322     $a--;
323   if( $b/2 - (int)($b/2) != 0.5)
324     $b--;
325
326   /* check for schweinchen and ten of hearts*/
327   switch($game)
328     {
329     case "normal":
330     case "silent":
331     case "trump":
332       if($RULES['schweinchen']=='both' && $GAME['schweinchen-who'])
333         {
334           if($a == 19 || $a == 20 )
335             return 1;
336           if($b == 19 || $b == 20 )
337             return 0;
338         }
339       else if($RULES['schweinchen']=='second' && $GAME['schweinchen-second'])
340         {
341           if($a == 19 || $a == 20 )
342             return 1;
343           if($b == 19 || $b == 20 )
344             return 0;
345         }
346       else if($RULES['schweinchen']=='secondaftercall' && $GAME['schweinchen-who'] && $GAME['schweinchen-second'] )
347         {
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']) )
350             {
351               if($a == 19 || $a == 20 )
352                 return 1;
353               if($b == 19 || $b == 20 )
354                 return 0;
355             }
356           /* if not, do nothing and the foxes are just handeled as normal trump */
357         }
358         ;
359     case "heart":
360     case "spade":
361     case "club":
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.*/
366     case "trumpless":
367     case "jack":
368     case "queen":
369       /* no special cases here */
370     }
371
372   /* normal case */
373   if(is_trump($a) && is_trump($b) && $a<=$b)
374     return 1;
375   else if(is_trump($a) && is_trump($b) )
376     return 0;
377   else
378     { /*$a is not a trump */
379       if(is_trump($b))
380         return 0;
381       else
382         { /* both no trump */
383
384           /* both clubs? */
385           $posA = pos_array($a,$CARDS["clubs"]);
386           $posB = pos_array($b,$CARDS["clubs"]);
387           if($posA && $posB)
388             if($posA <= $posB)
389               return 1;
390             else
391               return 0;
392
393           /* both spades? */
394           $posA = pos_array($a,$CARDS["spades"]);
395           $posB = pos_array($b,$CARDS["spades"]);
396           if($posA && $posB)
397             if($posA <= $posB)
398               return 1;
399             else
400               return 0;
401
402           /* both hearts? */
403           $posA = pos_array($a,$CARDS["hearts"]);
404           $posB = pos_array($b,$CARDS["hearts"]);
405           if($posA && $posB)
406             if($posA <= $posB)
407               return 1;
408             else
409               return 0;
410
411           /* both diamonds? */
412           $posA = pos_array($a,$CARDS["diamonds"]);
413           $posB = pos_array($b,$CARDS["diamonds"]);
414           if($posA && $posB)
415             if($posA <= $posB)
416               return 1;
417             else
418               return 0;
419
420           /* not the same suit and no trump: a wins */
421           return 1;
422         }
423     }
424 }
425
426 function get_winner($p,$mode)
427 {
428   /* get all 4 cards played in a trick, in the order they are played */
429   $tmp = $p[1];
430   $c1    = $tmp["card"];
431   $c1pos = $tmp["pos"];
432
433   $tmp = $p[2];
434   $c2    = $tmp["card"];
435   $c2pos = $tmp["pos"];
436
437   $tmp = $p[3];
438   $c3    = $tmp["card"];
439   $c3pos = $tmp["pos"];
440
441   $tmp = $p[4];
442   $c4    = $tmp["card"];
443   $c4pos = $tmp["pos"];
444
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) )
447     return $c1pos;
448
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) )
451     return $c2pos;
452
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) )
457       return $c3pos;
458     /* second is worse than first, e.g. not following suite */
459     else if (compare_cards($c1,$c2,$mode) )
460       return $c3pos;
461
462   /* non of the above */
463   return $c4pos;
464 }
465
466 function count_nines($cards)
467 {
468   $nines = 0;
469
470   foreach($cards as $c)
471     {
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++;
476     }
477
478   return $nines;
479 }
480
481 function check_wedding($cards)
482 {
483
484   if( in_array("3",$cards) && in_array("4",$cards) )
485     return 1;
486
487   return 0;
488 }
489
490 function count_trump($cards,$status='pregame')
491 {
492   global $RULES;
493
494   $trump = 0;
495
496   /* count each trump, including the foxes, since this is used to determine poverty status */
497   foreach($cards as $c)
498     if( (int)($c) <27)
499       $trump++;
500
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;
505
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 */
509
510   /* subtract foxes */
511   if( in_array("19",$cards))
512     $trump--;
513   if( in_array("20",$cards) )
514     $trump--;
515
516   /* handle case where player has schweinchen */
517   if( in_array("19",$cards) && in_array("20",$cards) )
518     switch($RULES["schweinchen"])
519       {
520       case "both":
521         /* add two, in case the player has both foxes (schweinchen) */
522         $trump++;
523         $trump++;
524         break;
525       case "second":
526       case "secondaftercall":
527         /* add one, in case the player has both foxes (schweinchen) */
528         $trump++;
529         break;
530       case "none":
531         break;
532       }
533
534   return $trump;
535 }
536
537 function check_low_trump($cards)
538 {
539   global $RULES;
540
541   if($RULES['lowtrump']=='none')
542     return 0;
543
544   /* check if we have low trump */
545
546   $lowtrump=1;
547   foreach($cards as $card)
548     {
549       /* card a trump, but not a diamond? */
550       if( $card<19 )
551          $lowtrump=0;
552     }
553
554   /* handle case where player has schweinchen */
555   if( in_array("19",$cards) && in_array("20",$cards) )
556     switch($RULES["schweinchen"])
557       {
558       case "both":
559       case "second":
560       case "secondaftercall":
561         $lowtrump=0;
562         break;
563       case "none":
564         break;
565       }
566
567   return $lowtrump;
568 }
569
570 function  create_array_of_random_numbers($useridA,$useridB,$useridC,$useridD)
571 {
572   global $debug;
573
574   $r = array();
575
576   if($debug)
577     {
578       /* fix the hands; makes debugging easier; the following hands have lots of sicknesses,
579        * to make testing easier
580        */
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;
593     }
594   else
595     {
596       /* check if we can find a game were non of the player was involved and return
597        * cards instead
598        */
599       $userstr = "'".implode("','",array($useridA,$useridB,$useridC,$useridD))."'";
600       $randomnumbers = DB_get_unused_randomnumbers($userstr);
601       $randomnumbers = explode(":",$randomnumbers);
602
603       if(sizeof($randomnumbers)==48)
604         return $randomnumbers;
605
606       /* need to create new numbers */
607       for($i=0;$i<48;$i++)
608         $r[$i]=$i+1;
609
610       /* shuffle using a better random generator than the standard one */
611       for ($i = 0; $i <48; $i++)
612         {
613           $j = @mt_rand(0, $i);
614           $tmp = $r[$i];
615           $r[$i] = $r[$j];
616           $r[$j] = $tmp;
617         }
618     };
619
620   return $r;
621 }
622
623 function display_cards($me,$myturn)
624 {
625   return;
626 }
627
628 function have_suit($cards,$c)
629 {
630   global $CARDS;
631   $suite = array();
632
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"];
643
644   foreach($cards as $card)
645     {
646       if(in_array($card,$suite))
647         return 1;
648     }
649
650   return 0;
651 }
652
653 function same_type($card,$c)
654 {
655   global $CARDS;
656   $suite = "";
657
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"];
669
670   /* card is the same suid return 1 */
671   if(in_array($card,$suite))
672     return 1;
673
674   return 0;
675 }
676
677 function set_gametype($gametype)
678 {
679   global $CARDS;
680   global $RULES;
681   global $GAME;
682
683   switch($gametype)
684     {
685     case "normal":
686     case "wedding":
687     case "poverty":
688     case "dpoverty":
689     case "trump":
690     case "silent":
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')
699         {
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');
703         }
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'])
706         {
707           /* find the fox and put them at the top of the stack */
708           foreach(array('19','20') as $fox)
709             {
710               /* search for fox */
711               $trump = $CARDS['trump'];
712               $key = array_keys($trump, $fox);
713
714               /* reorder */
715               $foxa = array();
716               $foxa[]=$trump[$key[0]];
717               unset($trump[$key[0]]);
718               $trump = array_merge($foxa,$trump);
719               $CARDS['trump'] = $trump;
720             }
721         }
722       else if( ($RULES['schweinchen']=='second' || $RULES['schweinchen']=='secondaftercall')
723                && $GAME['schweinchen-who'])
724         {
725           /* find the fox and put them at the top of the stack */
726           $trump = $CARDS['trump'];
727           $key = array_keys($trump, '19');
728
729           /* reorder */
730           $foxa = array();
731           $foxa[]=$trump[$key[0]];
732           unset($trump[$key[0]]);
733           $trump = array_merge($foxa,$trump);
734           $CARDS['trump'] = $trump;
735         }
736       break;
737     case "queen":
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();
744       break;
745     case "jack":
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();
752       break;
753     case "trumpless":
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();
760       break;
761     case "club":
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')
770         {
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');
774         }
775       break;
776     case "spade":
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')
785         {
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');
789         }
790       break;
791     case "heart":
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')
800         {
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');
803         }
804       break;
805     }
806 }
807
808 function mysort($cards,$gametype)
809 {
810   global $PREF;
811   if(isset($PREF['sorting']))
812     if($PREF['sorting']=='high-low')
813       usort ( $cards, 'sort_comp_high_low' );
814     else
815       usort ( $cards, 'sort_comp_low_high' );
816   else
817     usort ( $cards, 'sort_comp_high_low' );
818   return $cards;
819 }
820
821 function sort_comp_high_low($a,$b)
822 {
823   global $CARDS;
824
825   $ALL = array();
826   $ALL = array_merge($CARDS['trump'],$CARDS['diamonds'],$CARDS['clubs'],
827                      $CARDS['hearts'],$CARDS['spades']);
828
829   return pos_array($a,$ALL)-pos_array($b,$ALL);
830 }
831
832 function sort_comp_low_high($a,$b)
833 {
834   global $CARDS;
835
836   $ALL = array();
837   $ALL = array_merge($CARDS['trump'],$CARDS['diamonds'],$CARDS['clubs'],
838                      $CARDS['hearts'],$CARDS['spades']);
839
840   return -pos_array($a,$ALL)+pos_array($b,$ALL);
841 }
842
843 function can_call($what,$hash)
844 {
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
848
849    return values:
850    0   can't make that call
851    1   can make the call
852    2   can make the call, but this is the last chance to do so...
853    */
854
855   global $RULES;
856
857   /* get some information
858    */
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 */
863
864
865   /* you're call must be better than the one you or your partner already made
866    */
867   if( ($pcall!=NULL && ($what >= $pcall))
868       || ($oldcall!=NULL && ($what >=$oldcall)) )
869     {
870       return 0;
871     }
872
873   /* for some rules we need to know how many cards people have
874    */
875   $NRcards  = count(DB_get_hand($hash));
876
877   $NRallcards = 0;
878   for ($i=1;$i<5;$i++)
879     {
880       $user         = DB_get_hash_from_game_and_pos($gameid,$i);
881       $NRallcards  += count(DB_get_hand($user));
882     };
883
884   /* in case of a wedding, everything will be delayed by an offset
885    */
886   $offset = 0;
887   if($gametype=="wedding")
888     {
889       $offset = DB_get_sickness_by_gameid($gameid);
890       if ($offset <0) /* not resolved */
891         return 0;
892     };
893
894   /* now check if the call is allowed depending on the rule set
895    */
896   switch ($RULES["call"])
897     {
898     case "1st-own-card":
899       /* calls can be made before/while you play your card...
900        * first card = 120, second card = 90, etc.
901        */
902       if( 4-($what/30) == 12 - ($NRcards + $offset))
903         return 2;
904       if( 4-($what/30) > 12 - ($NRcards + $offset))
905         return 1;
906       break;
907     case "5th-card":
908       /* you can make the first call anytime during the first trick
909        */
910       if( 27+4*($what/30) == $NRallcards + $offset*4)
911         return 2;
912       if( 27+4*($what/30) < $NRallcards + $offset*4)
913         return 1;
914       break;
915     case "9-cards":
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
918        */
919
920       /* figure out last call
921        */
922       if($oldcall!=NULL && $pcall!=NULL)
923         $mincall = ($oldcall>$pcall) ? $pcall : $oldcall;
924       else if($oldcall!=NULL)
925         $mincall = $oldcall;
926       else if ($pcall!=NULL)
927         $mincall = $pcall;
928       else
929         $mincall = -1;
930
931
932       if( 12 == ($NRcards + $offset))
933         {
934           return 2;
935         }
936       else if( 12 < ($NRcards + $offset))
937         {
938           return 1;
939         }
940       else if ( 9 == ($NRcards + $offset))
941         {
942           if( ($mincall>=0 && $mincall<=120 && $what<=90 ) )
943             return 2;
944         }
945       else if ( 9 < ($NRcards + $offset))
946         {
947           if( ($mincall>=0 && $mincall<=120 && $what<=90 ) )
948             return 1;
949         }
950       else if ( 6 == ($NRcards + $offset))
951         {
952           if( ($mincall>=0 && $mincall<=90 && $what<=60 ) )
953             return 2;
954         }
955       else if ( 6 < ($NRcards + $offset))
956         {
957           if( ($mincall>=0 && $mincall<=90 && $what<=60 ) )
958             return 1;
959         }
960       else if ( 3 == ($NRcards + $offset))
961         {
962           if( ($mincall>=0 && $mincall<=60 && $what<=30 ) )
963             return 2;
964         }
965       else if ( 3 < ($NRcards + $offset))
966         {
967           if( ($mincall>=0 && $mincall<=60 && $what<=30 ) )
968             return 1;
969         }
970       else if ( 0 == ($NRcards + $offset))
971         {
972           if( ($mincall>=0 && $mincall<=30 && $what==0 ) )
973             return 2;
974         }
975       else if ( 0 < ($NRcards + $offset))
976         {
977           if( ($mincall>=0 && $mincall<=30 && $what==0 ) )
978             return 1;
979         };
980       break;
981     }
982
983   return 0;
984 }
985
986 function display_table_begin ()
987 {
988   global $gameid;
989
990   $result = DB_query('SELECT  User.fullname as name,'.
991                      '        Hand.position as position,'.
992                      '        User.id,'.
993                      '        Hand.party as party,'.
994                      '        Hand.sickness as sickness,'.
995                      '        Hand.point_call,'.
996                      '        User.last_login,'.
997                      '        Hand.hash,'.
998                      '        User.timezone,'.
999                      '        User.email'.
1000                      ' FROM Hand'.
1001                      ' LEFT JOIN User ON User.id=Hand.user_id'.
1002                      ' WHERE Hand.game_id='.DB_quote_smart($gameid).
1003                      ' ORDER BY position ASC');
1004
1005   $row0 = DB_fetch_array($result);
1006   $row1 = DB_fetch_array($result);
1007   $row2 = DB_fetch_array($result);
1008   $row3 = DB_fetch_array($result);
1009
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);
1016
1017   return;
1018 }
1019
1020
1021 function display_table_end ()
1022 {
1023   global $gameid;
1024
1025   $result = DB_query('SELECT  User.fullname as name,'.
1026                      '        Hand.position as position,'.
1027                      '        User.id,'.
1028                      '        Hand.party as party,'.
1029                      '        Hand.sickness as sickness,'.
1030                      '        Hand.point_call,'.
1031                      '        User.last_login,'.
1032                      '        Hand.hash,'.
1033                      '        User.timezone,'.
1034                      '        User.email'.
1035                      ' FROM Hand'.
1036                      ' LEFT JOIN User ON User.id=Hand.user_id'.
1037                      ' WHERE Hand.game_id='.DB_quote_smart($gameid).
1038                      ' ORDER BY position ASC');
1039
1040   $row0 = DB_fetch_array($result);
1041   $row1 = DB_fetch_array($result);
1042   $row2 = DB_fetch_array($result);
1043   $row3 = DB_fetch_array($result);
1044
1045   echo "</div>\n";
1046   display_single_user($row3);
1047   echo "</div>\n";
1048
1049   return;
1050 }
1051
1052 function display_single_user($r,$start=0)
1053 {
1054   /* start=1, mark starting player, default=0, so the player on the left is not marked */
1055
1056   global $gameid, $debug,$INDEX,$defaulttimezone;
1057   global $RULES,$GAME, $gametype_raw;
1058
1059       $name  = $r[0];
1060       $pos   = $r[1];
1061       $user  = $r[2];
1062       $party = $r[3];
1063       $sickness  = $r[4];
1064       $call      = $r[5];
1065       $hash      = $r[7];
1066       $timezone  = $r[8];
1067       $email     = $r[9];
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\" />";
1075
1076       echo "  <div class=\"table".($pos-1)."\">\n";
1077
1078       /* mark starting player */
1079       if($start && ! ($party=="re" || $party=="contra"))
1080         echo '   <span class="start">'._('Starting Player')."</span> <br />\n";
1081
1082       if($debug)
1083         echo "   <a href=\"".$INDEX."?action=game&amp;me=".$hash."\">";
1084       if($vacation = check_vacation($user))
1085         {
1086           $start   = $vacation[0];
1087           $stop    = substr($vacation[1],0,10);
1088           $comment = $vacation[2];
1089
1090           $title = _("begin:")." $start  "._("end:")." $stop $comment";
1091               echo "   <span class=\"vacation\" title=\"$title\">$gravatar "._("(on vacation until $stop)")."</span> \n";
1092         }
1093       else
1094         echo "   $gravatar \n";
1095       if($debug)
1096         echo"   </a>\n";
1097
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 />";
1102
1103       if($gametype_raw=="poverty" && $party=="re")
1104         if($sickness=="poverty" || ($RULES['lowtrump']=='poverty' && $sickness=='lowtrump'))
1105           {
1106             $userhash = DB_get_hash_from_gameid_and_userid($gameid,$user);
1107             $cards    = DB_get_all_hand($userhash);
1108             $trumpNR  = count_trump($cards,'all');
1109             if($trumpNR)
1110               echo "   <img src=\"pics/button/poverty_trump_button.png\" class=\"button\" ".
1111                 "alt=\"poverty - trump back\" title=\"poverty - trump back\" />\n";
1112             else
1113               echo "   <img src=\"pics/button/poverty_notrump_button.png\" class=\"button\" ".
1114                 "alt=\"poverty - no trump back\" title=\"poverty - no trump back\" />\n";
1115           }
1116         else
1117           echo "   <img src=\"pics/button/poverty_partner_button.png\" class=\"button\" ".
1118             "alt=\"poverty partner\" title=\"poverty partner\" />\n";
1119
1120       if($gametype_raw=="dpoverty")
1121         if($party=="re")
1122           if($sickness=="poverty" || ($RULES['lowtrump']=='poverty' && $sickness=='lowtrump'))
1123             {
1124               $userhash = DB_get_hash_from_gameid_and_userid($gameid,$user);
1125               $cards    = DB_get_all_hand($userhash);
1126               $trumpNR  = count_trump($cards,'all');
1127               if($trumpNR)
1128                 echo "   <img src=\"pics/button/poverty_trump_button.png\" class=\"button\" ".
1129                   "alt=\"poverty < trump back\" title=\"poverty - trump back\" />\n";
1130               else
1131                 echo "   <img src=\"pics/button/poverty_notrump_button.png\" class=\"button\" ".
1132                   "alt=\"poverty <\" title=\"poverty - no trump back\" />\n";
1133             }
1134           else
1135             echo "   <img src=\"pics/button/poverty_partner_button.png\" class=\"button\" ".
1136               "alt=\"poverty >\" title=\"poverty partner\" />\n";
1137         else
1138           if($sickness=="poverty"  || ($RULES['lowtrump']=='poverty' && $sickness=='lowtrump'))
1139             {
1140               $userhash = DB_get_hash_from_gameid_and_userid($gameid,$user);
1141               $cards    = DB_get_all_hand($userhash);
1142               $trumpNR  = count_trump($cards,'all');
1143               if($trumpNR)
1144                 echo "   <img src=\"pics/button/poverty2_trump_button.png\" class=\"button\" ".
1145                   "alt=\"poverty2 < trump back\" title=\"poverty2 - trump back\"/>\n";
1146               else
1147                 echo "   <img src=\"pics/button/poverty2_notrump_button.png\" class=\"button\" ".
1148                   "alt=\"poverty2 <\" title=\"poverty2 - no trump back\" />\n";
1149             }
1150           else
1151             echo "   <img src=\"pics/button/poverty2_partner_button.png\" class=\"button\" ".
1152               "alt=\"poverty2 >\" title=\"poverty2 partner\" />\n";
1153
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";
1157         else
1158           echo "   <img src=\"pics/button/wedding_partner_button.png\" class=\"button\" ".
1159             "alt=\"wedding partner\" title=\"wedding partner\" />\n";
1160
1161       if( $gametype_raw=='solo' && $party=="re")
1162         {
1163           $solotype = DB_get_solo_by_gameid($gameid);
1164           $GT = get_display_gametype($gameid);
1165
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";
1180         }
1181
1182       /* add point calls */
1183       if($call!=NULL)
1184         {
1185           if($party=="re")
1186             echo "   <img src=\"pics/button/re_button.png\" class=\"button\" alt=\"re\" title=\"Re\" />\n";
1187           else
1188             echo "   <img src=\"pics/button/contra_button.png\" class=\"button\" alt=\"contra\" title=\"Contra\" />\n";
1189           switch($call)
1190             {
1191             case "0":
1192               echo "   <img src=\"pics/button/0_button.png\" class=\"button\" alt=\"0\" title=\"Call 0\" />\n";
1193               break;
1194             case "30":
1195               echo "   <img src=\"pics/button/30_button.png\" class=\"button\" alt=\"30\" title=\"Call 30\" />\n";
1196               break;
1197             case "60":
1198               echo "   <img src=\"pics/button/60_button.png\" class=\"button\" alt=\"60\" title=\"Call 60\" />\n";
1199               break;
1200             case "90":
1201               echo "   <img src=\"pics/button/90_button.png\" class=\"button\" alt=\"90\" title=\"Call 90\" />\n";
1202               break;
1203             }
1204         }
1205
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)."\" />";
1209
1210       echo "   <br /><span class=\"numberoftricks\">";
1211       /* show how many tricks the person made */
1212       switch($wins)
1213         {
1214         case 0:
1215           echo _('#tricks 0'); break;
1216         case 1:
1217           echo _('#tricks 1'); break;
1218         case 2:
1219         case 3:
1220         case 4:
1221           echo _('#tricks few'); break;
1222         default:
1223           echo _('#tricks many'); break;
1224         }
1225       echo "</span>\n";
1226       echo "  </div>\n";
1227 }
1228
1229
1230 function display_user_menu($id, $skiphash=NULL)
1231 {
1232   global $WIKI,$INDEX;
1233
1234   if($skiphash)
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" );
1242   else
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' );
1249
1250   $i=0;
1251   while( $r = DB_fetch_array($result))
1252     {
1253       if($i==0)
1254         {
1255           echo "\n<div class=\"usermenu\">\n  ";
1256           echo _('It\'s your turn in these games').":\n";
1257         }
1258       else
1259         {
1260           echo ", ";
1261         }
1262
1263       $i++;
1264       echo "  <a href=\"".$INDEX."?action=game&amp;me=".$r[0].
1265         "\"> ".DB_format_gameid($r[1])." </a>\n";
1266       if($i>4)
1267         {
1268           echo ",  ...\n";
1269           break;
1270         }
1271     }
1272
1273   if($i)
1274     echo  "</div>\n\n";
1275   return;
1276 }
1277
1278 function generate_score_table($session)
1279 {
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
1285    */
1286   $score = array();
1287   $i=0;
1288
1289   /* get all ids, scores and gametypes */
1290   $gameids = DB_get_gameids_of_finished_games_by_session($session);
1291
1292   if($gameids == NULL)
1293     return $score;
1294
1295   $player = array();
1296   $player_party = array();
1297
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))
1302     $player[$r[0]] = 0;
1303
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);
1307
1308   /* get points and generate table */
1309   foreach($gameids as $gameid)
1310     {
1311       $re_score = $gameid[1];
1312       $gametype = $gameid[2];
1313       foreach($player as $id=>$points)
1314         {
1315           $party = $player_party[$id][$i][0];
1316           if($party == 're')
1317             if($gametype=='solo')
1318               $player[$id] += 3*$re_score;
1319             else
1320               $player[$id] += $re_score;
1321           else if ($party == 'contra')
1322             $player[$id] -= $re_score;
1323         }
1324       $score[$i]['gameid']  = $gameid[0] ;
1325       $score[$i]['players'] = $player;
1326       $score[$i]['points']  = abs($re_score);
1327       $score[$i]['solo']    = ($gametype=='solo');
1328
1329       $i++;
1330     }
1331
1332   return $score;
1333 }
1334
1335 function generate_global_score_table()
1336 {
1337   $return = array();
1338
1339   /* get all ids, scores and gametypes */
1340   $gameids = DB_get_gameids_of_finished_games_by_session(0);
1341
1342   if($gameids == NULL)
1343     return '';
1344
1345   $player = array();
1346   /* get player id, names... from the User table */
1347   $result = DB_query('SELECT User.id, User.fullname FROM User');
1348
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);
1353
1354   /* get points and generate table */
1355   foreach($gameids as $gameid)
1356     {
1357       $re_score = $gameid[1];
1358       $gametype = $gameid[2];
1359
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))
1363         {
1364           $id = $r[0];
1365           $party = DB_get_party_by_gameid_and_userid($gameid[0],$id);
1366           if($party == 're')
1367             if($gametype=='solo')
1368               $player[$id]['points'] += 3*$re_score;
1369             else
1370               $player[$id]['points'] += $re_score;
1371           else if ($party == 'contra')
1372             $player[$id]['points'] -= $re_score;
1373           if($party)
1374             $player[$id]['nr']+=1;
1375         }
1376     }
1377
1378   /* add number of active games */
1379   $result = DB_query_array_all("SELECT user_id, COUNT(*) as c  " .
1380                                " FROM Hand".
1381                                " LEFT JOIN Game ON Game.id=game_id".
1382                                " WHERE Game.status IN ('pre','play')".
1383                                " GROUP BY user_id");
1384
1385   foreach($result as $res)
1386     {
1387       $player[$res[0]]['active'] = $res[1];
1388     }
1389
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 ".
1394                               "FROM Play P1 ".
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 ");
1398
1399   foreach($result as $res)
1400     {
1401       $player[$res[0]]['response'] = $res[1];
1402     }
1403
1404   /* most solos */
1405   $result = DB_query_array_all("SELECT user_id as uid,".
1406                                "       COUNT(*), ".
1407                                "       COUNT(*)/(SELECT COUNT(*) FROM Hand LEFT JOIN User ON User.id=Hand.user_id WHERE User.id=uid) as c ".
1408                                " FROM Game ".
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 ");
1412
1413   foreach($result as $res)
1414     {
1415       $player[$res[0]]['solo'] = $res[1];
1416       $player[$res[0]]['soloavg'] = $res[2];
1417     }
1418
1419
1420   /* sort everything nicely */
1421
1422   function cmp($a,$b)
1423   {
1424     if($a['nr']==0) return 1;
1425     if($b['nr']==0) return 1;
1426
1427     $a=$a['points']/$a['nr'];
1428     $b=$b['points']/$b['nr'];
1429
1430     if ($a == $b)
1431       return 0;
1432     return ($a > $b) ? -1 : 1;
1433   }
1434   usort($player,'cmp');
1435
1436
1437   foreach($player as $pl)
1438     {
1439       /* limit to players with at least 10 games */
1440       if($pl['nr']>10)
1441         $return[] = array( $pl['name'], round($pl['points']/$pl['nr'],3), $pl['points'],$pl['nr'],$pl['active'],
1442                            $pl['response'],$pl['solo'],$pl['soloavg']);
1443     }
1444
1445   return $return;
1446 }
1447
1448 function format_score_table_ascii($score)
1449 {
1450   $output="";
1451   if(sizeof($score)==0)
1452     return "";
1453
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";
1457
1458   /* output header */
1459   foreach($score[0]['players'] as $id=>$points)
1460     {
1461       $name = DB_get_name('userid',$id); /*TODO*/
1462       $output.= "  ".substr($name,0,2)."  |";
1463     }
1464   $output.="  P   |\n";
1465   $output.= "------+------+------+------+------+\n";
1466
1467   /* output score for each game */
1468   $i=0;
1469   foreach($score as $game)
1470     {
1471       $i++;
1472       if($i-1<$max-6) continue;
1473
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);
1477
1478       /* check for solo */
1479       if($game['solo'])
1480         $output.= " S|";
1481       else
1482         $output.= "  |";
1483
1484       $output.="\n";
1485     }
1486   return $output;
1487 }
1488
1489 function format_score_table_html($score,$userid)
1490 {
1491   global $INDEX;
1492
1493   if(sizeof($score)==0)
1494     return "";
1495
1496   $output = "<div class=\"scoretable\">\n<table class=\"score\">\n";
1497
1498   /* output header */
1499   $header = "";
1500   $header.= " <thead>\n  <tr>\n";
1501   $header.= "   <th> No </th>";
1502   foreach($score[0]['players'] as $id=>$points)
1503     {
1504       $name = DB_get_name('userid',$id); /*TODO*/
1505       $header.= "<th> ".substr($name,0,2)." </th>";
1506     }
1507   $header.="<th>P</th>\n  </tr>\n </thead>\n";
1508
1509   /* use the same as footer */
1510   $footer = "";
1511   $footer.= " <tfoot>\n  <tr>\n";
1512   $footer.= "   <td> No </td>";
1513   foreach($score[0]['players'] as $id=>$points)
1514     {
1515       $name = DB_get_name('userid',$id); /*TODO*/
1516       $footer.= "<td> ".substr($name,0,2)." </td>";
1517     }
1518   $footer.="<td>P</td>\n  </tr>\n </tfoot>\n";
1519
1520   /* body */
1521   $body = "";
1522   $body.= " <tbody>\n";
1523   $i=0;
1524   foreach($score as $game)
1525     {
1526       $i++;
1527       $body.="  <tr>";
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&amp;me=".$userhash."\">$i</a></td>";
1532       else
1533         $body.="  <td>$i</td>";
1534
1535       foreach($game['players'] as $id=>$points)
1536         $body.="<td>".$points."</td>";
1537       $body.="<td>".$game['points'];
1538
1539       /* check for solo */
1540       if($game['solo'])
1541         $body.= " S";
1542       $body.="</td></tr>\n";
1543     }
1544
1545   $output.=$header;
1546   if($i>12)
1547     $output.=$footer;
1548   $output.=$body;
1549
1550   $output.=" </tbody>\n</table>\n</div>\n";
1551
1552   return $output;
1553 }
1554
1555 function createCache($content, $cacheFile)
1556 {
1557   $fp = fopen($cacheFile,"w");
1558   if($fp)
1559     {
1560       fwrite($fp,$content);
1561       fclose($fp);
1562     }
1563   else
1564     echo "WARNING: couldn't create cache file";
1565
1566   return;
1567 }
1568
1569 function getCache($cacheFile, $expireTime)
1570 {
1571   if( file_exists($cacheFile) &&
1572       filemtime($cacheFile )>( time() - $expireTime ) )
1573     {
1574       return file_get_contents($cacheFile);
1575     }
1576
1577   return false;
1578 }
1579
1580 function check_vacation($userid)
1581 {
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'" );
1585   if($result)
1586     $start = $result[0];
1587   else
1588     return NULL;
1589
1590   /* get end date */
1591   $result = DB_query_array("SELECT value FROM User_Prefs".
1592                            " WHERE user_id=".DB_quote_smart($userid)." AND pref_key='vacation stop'" );
1593   if($result)
1594     $stop = $result[0];
1595   else
1596     return NULL;
1597
1598   /* get comment */
1599   $result = DB_query_array("SELECT value FROM User_Prefs".
1600                            " WHERE user_id=".DB_quote_smart($userid)." AND pref_key='vacation comment'" );
1601   if($result)
1602     $comment = $result[0];
1603   else
1604     $comment = '';
1605
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);
1610   else
1611     return NULL;
1612 }
1613
1614 function cancel_game($why,$gameid)
1615 {
1616   $gameid = DB_quote_smart($gameid);
1617
1618   /* update the game table */
1619   switch($why)
1620     {
1621     case 'timedout':
1622       DB_query("UPDATE Game SET status='cancel-timedout' WHERE id=$gameid");
1623       break;
1624     case 'nines':
1625       DB_query("UPDATE Game SET status='cancel-nines' WHERE id=$gameid");
1626       break;
1627     case 'trump':
1628       DB_query("UPDATE Game SET status='cancel-trump' WHERE id=$gameid");
1629       break;
1630     case 'noplay':
1631       DB_query("UPDATE Game SET status='cancel-noplay' WHERE id=$gameid");
1632       break;
1633     case 'lowtrump':
1634       DB_query("UPDATE Game SET status='cancel-lowtrump' WHERE id=$gameid");
1635       break;
1636     }
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))
1640     {
1641       $id = $r[0];
1642       DB_query("UPDATE Hand SET status='gameover' WHERE id=".DB_quote_smart($id));
1643     }
1644
1645   return;
1646 }
1647
1648 function get_user_token($userid)
1649 {
1650
1651   $token = NULL;
1652
1653   $date = DB_get_user_creation_date($userid);
1654   $name = DB_get_name('userid',$userid);
1655
1656   if($date && $name)
1657     $token = md5("token".$name.$date);
1658
1659   return $token;
1660 }
1661
1662 function verify_password($email, $password)
1663 {
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
1668    *        3 misc error
1669    */
1670
1671   /* check user email by getting his id */
1672   $userid = DB_get_userid('email',$email);
1673   if(!$userid)
1674     return 1;
1675
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))
1679     return 0;
1680
1681   /* get saved password */
1682   $existingpassword =  DB_get_passwd_by_userid($userid);
1683
1684   if(strlen($existingpassword)==32) /* old password type */
1685     {
1686       if ($existingpassword == md5($password))
1687         {
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'");
1696           else
1697             return 2;
1698
1699           return 0;
1700         }
1701     }
1702   else
1703     {
1704       if ($existingpassword == crypt($password, $existingpassword))
1705         return 0;
1706     };
1707
1708   return 3;
1709 }
1710
1711 /* language functions */
1712 function detectlanguage()
1713 {
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'];
1718 }
1719
1720 function set_language($l,$type='lang')
1721 {
1722    if($type=='uid')
1723      {
1724        $userPREF = DB_get_PREF($l);
1725        $l = $userPREF['language'];
1726      };
1727
1728     switch($l)
1729       {
1730       case 'de':
1731         putenv("LC_ALL=de_DE");
1732         setlocale(LC_ALL, "de_DE");
1733         break;
1734       default:
1735         putenv("LC_ALL=en_US");
1736         setlocale(LC_ALL, "en_US");
1737         break;
1738       }
1739
1740     // Specify location of translation tables
1741     bindtextdomain("edoko", "./locale");
1742     bind_textdomain_codeset("edoko", 'UTF-8');
1743     // Choose domain
1744     textdomain("edoko");
1745
1746     return;
1747 }
1748
1749 function get_display_gametype($gameid)
1750 {
1751   /* return a readable string that can be displayed to show the game type
1752    * this means hiding silent solo from the user
1753    */
1754
1755   $gametype = DB_get_gametype_by_gameid($gameid);
1756
1757   if ($gametype == 'normal')
1758     $GT = _('normal');
1759   else if($gametype=='solo')
1760     {
1761       $solotype = DB_get_solo_by_gameid($gameid);
1762
1763       switch($solotype)
1764         {
1765         case 'trumpless':
1766           $GT = _('trumpless solo');
1767           break;
1768         case 'jack':
1769           $GT = _('jack solo');
1770           break;
1771         case 'queen':
1772           $GT = _('queen solo');
1773           break;
1774         case 'trump':
1775           $GT = _('trump solo');
1776           break;
1777         case 'club':
1778           $GT = _('club solo');
1779           break;
1780         case 'spade':
1781           $GT = _('spade solo');
1782           break;
1783         case 'heart':
1784           $GT = _('heart solo');
1785           break;
1786         case 'silent':
1787           $GT = _('normal');   /* this is change compared to $gametype */
1788           break;
1789         }
1790     }
1791   else if ($gametype == 'wedding')
1792     $GT = _('wedding');
1793   else if ($gametype == 'poverty')
1794     $GT = _('poverty');
1795   else if ($gametype == 'dpoverty')
1796     $GT = _('double poverty');
1797
1798   return $GT;
1799 }
1800
1801 ?>