037da48f97bc233abe64f84ada2710ab0e7988e4
[e-DoKo.git] / include / functions.php
1 <?php
2 /* Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012 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;
110
111   /* do we send the email right away or save it in the database? */
112   $send_now = 1;
113
114   /* add standard header and footer */
115   $subject = "$EmailName ";
116   if($gameid)
117     $game = DB_format_gameid($gameid);
118   else
119     $game = '';
120
121   switch($type)
122     {
123     case GAME_CANCELED:
124       $subject.=sprintf(_("Game %s canceled"),$game);
125       break;
126     case GAME_CANCELED_POVERTY:
127       $subject.=sprintf(_("Game %s canceled (poverty not resolved)"),$game);
128       break;
129     case GAME_CANCELED_TIMEOUT:
130       $subject.=sprintf(_("Game %s canceled (timed out)"),$game);
131       break;
132     case GAME_YOUR_TURN:
133       $subject.=sprintf(_("A card has been played in game %s"),$game);
134       break;
135     case GAME_READY:
136       $subject.=sprintf(_("Ready, set, go... (game %s)"),$game);
137       break;
138     case GAME_POVERTY:
139       $subject.=sprintf(_("Poverty (game %s)"),$game);
140       break;
141     case GAME_DPOVERTY:
142       $subject.=sprintf(_("Double poverty (game %s)"),$game);
143       break;
144     case GAME_OVER:
145       $subject.=sprintf(_("Game over (game %s)"),$game);
146       break;
147     case GAME_RECOVERY:
148       $subject.=_("Recovery");
149       break;
150     case GAME_REMINDER:
151       $subject.=sprintf(_("Reminder: game %s it's your turn"),$game);
152       break;
153     case GAME_NEW:
154       $subject.=sprintf(_("You are invited to a game of DoKo (game %s)"),$game);
155       break;
156     default:
157       $subject.=sprintf(_("Problem with email, contact admin (errorcode %d)"),$gameid);
158     }
159
160   /* standard goodbye */
161   $footer  = "\nHave a nice day\n".
162     "   your E-Doko service department\n\n".
163     "-- \n".
164     "You can change your mail delivery mode in the preference menu.\n".
165     'web: http://doko.nubati.net   '.
166     "help, bugs, etc.: $WIKI";
167
168   if(is_array($uid))
169     {
170       /* send email to more than one person */
171
172       $header  = "Hello all\n\n";
173
174       foreach($uid as $user)
175         {
176           $all[] = DB_get_email('userid',$user);
177         }
178       $To = implode(",",$all);
179     }
180   else
181     {
182       /* standard greeting */
183       $name    = DB_get_name('userid',$uid);
184       $header  = "Hello $name\n\n";
185
186       $To = DB_get_email('userid',$uid);
187
188       /* check if user wants email right away or if we should save it in
189        * the database for later delivery
190        */
191
192       $PREF = DB_get_PREF($uid);
193       if( $PREF['digest'] != 'digest-off' )
194         $send_now = 0;
195     }
196
197   if($send_now)
198     sendmail($To,$subject,$header.$message.$footer);
199   else
200     {
201       /* store email in database */
202       DB_digest_insert_email($To,$message,$type,$gameid);
203     }
204 }
205
206 function sendmail($To,$Subject,$message)
207 {
208   /* this function sends the mail or outputs to the screen in case of debugging */
209   global $debug,$EMAIL_REPLY;
210
211   $header = "";
212
213   if(isset($EMAIL_REPLY))
214     $header .= "From: e-DoKo daemon <$EMAIL_REPLY>\r\n";
215
216   if($debug)
217     {
218       /* display email on screen,
219        * change txt -> html
220        */
221       $message = str_replace("\n","<br />\n",$message);
222       $message = preg_replace("#(\w+://[^<>\s]+[\w/]*)#",
223                               "<a href=\"$1\">$1</a>", $message);
224
225       echo "<br />To: $To<br />";
226       if($header != "")
227         echo $header."<br />";
228       echo "Subject: $Subject <br />$message<br />\n";
229     }
230   else
231     if($header != "")
232       mail($To,$Subject,$message,$header);
233     else
234       mail($To,$Subject,$message);
235   return;
236 }
237
238 function myisset()
239 {
240   /* returns 1 if all names passed as args are defined by a GET or POST statement,
241    * else return 0
242    */
243
244   $ok   = 1;
245   $args = func_get_args();
246
247   foreach($args as $arg)
248     {
249       $ok = $ok * isset($_REQUEST[$arg]);
250       /*echo "$arg: ok = $ok <br />";
251        */
252     }
253   return $ok;
254 }
255
256 function myerror($message)
257 {
258   echo "<span class=\"error\">".htmlspecialchars($message)."</span>\n";
259   sendmail($ADMIN_EMAIL,$EmailName." Error in Code",$message);
260   return;
261 }
262
263 function pos_array($c,$arr)
264 {
265   $ret = 0;
266
267   $i   = 0;
268   foreach($arr as $a)
269     {
270       $i++;
271       if($a == $c)
272         {
273           $ret = $i;
274           break;
275         }
276     }
277   return $ret;
278 }
279
280 function is_trump($c)
281 {
282   global $CARDS;
283
284   if(in_array($c,$CARDS["trump"]))
285     return 1;
286   else
287     return 0;
288 }
289
290 function is_same_suite($c1,$c2)
291 {
292   global $CARDS;
293
294   if(in_array($c1,$CARDS["trump"]   ) && in_array($c2,$CARDS["trump"]   ) ) return 1;
295   if(in_array($c1,$CARDS["clubs"]   ) && in_array($c2,$CARDS["clubs"]   ) ) return 1;
296   if(in_array($c1,$CARDS["hearts"]  ) && in_array($c2,$CARDS["hearts"]  ) ) return 1;
297   if(in_array($c1,$CARDS["spades"]  ) && in_array($c2,$CARDS["spades"]  ) ) return 1;
298   if(in_array($c1,$CARDS["diamonds"]) && in_array($c2,$CARDS["diamonds"]) ) return 1;
299
300   return 0;
301 }
302
303 function compare_cards($a,$b,$game)
304 {
305   /* if "a" is higher than "b" return 1, else 0, "a" being the card first played */
306
307   global $CARDS;
308   global $RULES;
309   global $GAME;
310
311   /* first map all cards to the odd number,
312    * this insure that the first card wins the trick
313    * if they are the same card
314    */
315   if( $a/2 - (int)($a/2) != 0.5)
316     $a--;
317   if( $b/2 - (int)($b/2) != 0.5)
318     $b--;
319
320   /* check for schweinchen and ten of hearts*/
321   switch($game)
322     {
323     case "normal":
324     case "silent":
325     case "trump":
326       if($RULES['schweinchen']=='both' && $GAME['schweinchen-who'])
327         {
328           if($a == 19 || $a == 20 )
329             return 1;
330           if($b == 19 || $b == 20 )
331             return 0;
332         }
333       else if($RULES['schweinchen']=='second' && $GAME['schweinchen-second'])
334         {
335           if($a == 19 || $a == 20 )
336             return 1;
337           if($b == 19 || $b == 20 )
338             return 0;
339         }
340       else if($RULES['schweinchen']=='secondaftercall' && $GAME['schweinchen-who'] && $GAME['schweinchen-second'] )
341         {
342           /* check if a call was made either by the player or his partner. If so activate Schweinchen rule. */
343           if(DB_get_call_by_hash($GAME['schweinchen-who']) || DB_get_partner_call_by_hash($GAME['schweinchen-who']) )
344             {
345               if($a == 19 || $a == 20 )
346                 return 1;
347               if($b == 19 || $b == 20 )
348                 return 0;
349             }
350           /* if not, do nothing and the foxes are just handeled as normal trump */
351         }
352         ;
353     case "heart":
354     case "spade":
355     case "club":
356       /* check for ten of hearts rule */
357       if($RULES["dullen"]=="secondwins")
358         if($a==1 && $b==1) /* both 10 of hearts */
359           return 0;        /* second one wins.*/
360     case "trumpless":
361     case "jack":
362     case "queen":
363       /* no special cases here */
364     }
365
366   /* normal case */
367   if(is_trump($a) && is_trump($b) && $a<=$b)
368     return 1;
369   else if(is_trump($a) && is_trump($b) )
370     return 0;
371   else
372     { /*$a is not a trump */
373       if(is_trump($b))
374         return 0;
375       else
376         { /* both no trump */
377
378           /* both clubs? */
379           $posA = pos_array($a,$CARDS["clubs"]);
380           $posB = pos_array($b,$CARDS["clubs"]);
381           if($posA && $posB)
382             if($posA <= $posB)
383               return 1;
384             else
385               return 0;
386
387           /* both spades? */
388           $posA = pos_array($a,$CARDS["spades"]);
389           $posB = pos_array($b,$CARDS["spades"]);
390           if($posA && $posB)
391             if($posA <= $posB)
392               return 1;
393             else
394               return 0;
395
396           /* both hearts? */
397           $posA = pos_array($a,$CARDS["hearts"]);
398           $posB = pos_array($b,$CARDS["hearts"]);
399           if($posA && $posB)
400             if($posA <= $posB)
401               return 1;
402             else
403               return 0;
404
405           /* both diamonds? */
406           $posA = pos_array($a,$CARDS["diamonds"]);
407           $posB = pos_array($b,$CARDS["diamonds"]);
408           if($posA && $posB)
409             if($posA <= $posB)
410               return 1;
411             else
412               return 0;
413
414           /* not the same suit and no trump: a wins */
415           return 1;
416         }
417     }
418 }
419
420 function get_winner($p,$mode)
421 {
422   /* get all 4 cards played in a trick, in the order they are played */
423   $tmp = $p[1];
424   $c1    = $tmp["card"];
425   $c1pos = $tmp["pos"];
426
427   $tmp = $p[2];
428   $c2    = $tmp["card"];
429   $c2pos = $tmp["pos"];
430
431   $tmp = $p[3];
432   $c3    = $tmp["card"];
433   $c3pos = $tmp["pos"];
434
435   $tmp = $p[4];
436   $c4    = $tmp["card"];
437   $c4pos = $tmp["pos"];
438
439   /* first card is better than all the rest */
440   if( compare_cards($c1,$c2,$mode) && compare_cards($c1,$c3,$mode) && compare_cards($c1,$c4,$mode) )
441     return $c1pos;
442
443   /* second card is better than first and better than the rest */
444   if( !compare_cards($c1,$c2,$mode) &&  compare_cards($c2,$c3,$mode) && compare_cards($c2,$c4,$mode) )
445     return $c2pos;
446
447   /* third card is better than first card and better than last */
448   if( !compare_cards($c1,$c3,$mode) &&  compare_cards($c3,$c4,$mode) )
449     /* if second card is better than first, third card needs to be even better */
450     if( !compare_cards($c1,$c2,$mode) && !compare_cards($c2,$c3,$mode) )
451       return $c3pos;
452     /* second is worse than first, e.g. not following suite */
453     else if (compare_cards($c1,$c2,$mode) )
454       return $c3pos;
455
456   /* non of the above */
457   return $c4pos;
458 }
459
460 function count_nines($cards)
461 {
462   $nines = 0;
463
464   foreach($cards as $c)
465     {
466       if($c == "25" || $c == "26") $nines++;
467       else if($c == "33" || $c == "34") $nines++;
468       else if($c == "41" || $c == "42") $nines++;
469       else if($c == "47" || $c == "48") $nines++;
470     }
471
472   return $nines;
473 }
474
475 function check_wedding($cards)
476 {
477
478   if( in_array("3",$cards) && in_array("4",$cards) )
479     return 1;
480
481   return 0;
482 }
483
484 function count_trump($cards,$status='pregame')
485 {
486   global $RULES;
487
488   $trump = 0;
489
490   /* count each trump, including the foxes, since this is used to determine poverty status */
491   foreach($cards as $c)
492     if( (int)($c) <27)
493       $trump++;
494
495   /* In case we really want to know the amount of trump, we can use the status variable.
496    * This is needed for example to figure out what icon to display on the table in case of
497    * trump given back in poverty */
498   if($status=='all') return $trump;
499
500   /* normally foxes don't count as trump, so we substract them here
501    * in case someone has schweinchen, one or two of them should count as trump
502    * though, so we need to add one trump for those cases */
503
504   /* subtract foxes */
505   if( in_array("19",$cards))
506     $trump--;
507   if( in_array("20",$cards) )
508     $trump--;
509
510   /* handle case where player has schweinchen */
511   if( in_array("19",$cards) && in_array("20",$cards) )
512     switch($RULES["schweinchen"])
513       {
514       case "both":
515         /* add two, in case the player has both foxes (schweinchen) */
516         $trump++;
517         $trump++;
518         break;
519       case "second":
520       case "secondaftercall":
521         /* add one, in case the player has both foxes (schweinchen) */
522         $trump++;
523         break;
524       case "none":
525         break;
526       }
527
528   return $trump;
529 }
530
531 function check_low_trump($cards)
532 {
533   global $RULES;
534
535   if($RULES['lowtrump']=='none')
536     return 0;
537
538   /* check if we have low trump */
539
540   $lowtrump=1;
541   foreach($cards as $card)
542     {
543       /* card a trump, but not a diamond? */
544       if( $card<19 )
545          $lowtrump=0;
546     }
547
548   /* handle case where player has schweinchen */
549   if( in_array("19",$cards) && in_array("20",$cards) )
550     switch($RULES["schweinchen"])
551       {
552       case "both":
553       case "second":
554       case "secondaftercall":
555         $lowtrump=0;
556         break;
557       case "none":
558         break;
559       }
560
561   return $lowtrump;
562 }
563
564 function  create_array_of_random_numbers($useridA,$useridB,$useridC,$useridD)
565 {
566   global $debug;
567
568   $r = array();
569
570   if($debug)
571     {
572       /* fix the hands; makes debugging easier; the following hands have lots of sicknesses,
573        * to make testing easier
574        */
575       $r[ 0]=1;     $r[12]=47;   $r[24]=13;       $r[36]=37;
576       $r[ 1]=2;     $r[13]=23;   $r[25]=14;       $r[37]=38;
577       $r[ 2]=3;     $r[14]=27;   $r[26]=15;       $r[38]=39;
578       $r[ 3]=4;     $r[15]=16;   $r[27]=28;       $r[39]=40;
579       $r[ 4]=5;     $r[16]=17;   $r[28]=29;       $r[40]=21;
580       $r[ 5]=18;    $r[17]=6;    $r[29]=30;       $r[41]=42;
581       $r[ 6]=41;    $r[18]=7;    $r[30]=31;       $r[42]=43;
582       $r[ 7]=22;    $r[19]=8;    $r[31]=32;       $r[43]=20;
583       $r[ 8]=45;    $r[20]=9;    $r[32]=33;       $r[44]=19;
584       $r[ 9]=46;    $r[21]=10;   $r[33]=44;       $r[45]=24;
585       $r[10]=35;    $r[22]=11;   $r[34]=48;       $r[46]=25;
586       $r[11]=36;    $r[23]=12;   $r[35]=34;       $r[47]=26;
587     }
588   else
589     {
590       /* check if we can find a game were non of the player was involved and return
591        * cards instead
592        */
593       $userstr = "'".implode("','",array($useridA,$useridB,$useridC,$useridD))."'";
594       $randomnumbers = DB_get_unused_randomnumbers($userstr);
595       $randomnumbers = explode(":",$randomnumbers);
596
597       if(sizeof($randomnumbers)==48)
598         return $randomnumbers;
599
600       /* need to create new numbers */
601       for($i=0;$i<48;$i++)
602         $r[$i]=$i+1;
603
604       /* shuffle using a better random generator than the standard one */
605       for ($i = 0; $i <48; $i++)
606         {
607           $j = @mt_rand(0, $i);
608           $tmp = $r[$i];
609           $r[$i] = $r[$j];
610           $r[$j] = $tmp;
611         }
612     };
613
614   return $r;
615 }
616
617 function display_cards($me,$myturn)
618 {
619   return;
620 }
621
622 function have_suit($cards,$c)
623 {
624   global $CARDS;
625   $suite = array();
626
627   if(in_array($c,$CARDS["trump"]))
628     $suite = $CARDS["trump"];
629   else if(in_array($c,$CARDS["clubs"]))
630     $suite = $CARDS["clubs"];
631   else if(in_array($c,$CARDS["spades"]))
632     $suite = $CARDS["spades"];
633   else if(in_array($c,$CARDS["hearts"]))
634     $suite = $CARDS["hearts"];
635   else if(in_array($c,$CARDS["diamonds"]))
636     $suite = $CARDS["diamonds"];
637
638   foreach($cards as $card)
639     {
640       if(in_array($card,$suite))
641         return 1;
642     }
643
644   return 0;
645 }
646
647 function same_type($card,$c)
648 {
649   global $CARDS;
650   $suite = "";
651
652   /* figure out what kind of card c is */
653   if(in_array($c,$CARDS["trump"]))
654     $suite = $CARDS["trump"];
655   else if(in_array($c,$CARDS["clubs"]))
656     $suite = $CARDS["clubs"];
657   else if(in_array($c,$CARDS["spades"]))
658     $suite = $CARDS["spades"];
659   else if(in_array($c,$CARDS["hearts"]))
660     $suite = $CARDS["hearts"];
661   else if(in_array($c,$CARDS["diamonds"]))
662     $suite = $CARDS["diamonds"];
663
664   /* card is the same suid return 1 */
665   if(in_array($card,$suite))
666     return 1;
667
668   return 0;
669 }
670
671 function set_gametype($gametype)
672 {
673   global $CARDS;
674   global $RULES;
675   global $GAME;
676
677   switch($gametype)
678     {
679     case "normal":
680     case "wedding":
681     case "poverty":
682     case "dpoverty":
683     case "trump":
684     case "silent":
685       $CARDS["trump"]    = array('1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16',
686                                  '17','18','19','20','21','22','23','24','25','26');
687       $CARDS["diamonds"] = array();
688       $CARDS["clubs"]    = array('27','28','29','30','31','32','33','34');
689       $CARDS["spades"]   = array('35','36','37','38','39','40','41','42');
690       $CARDS["hearts"]   = array('43','44','45','46','47','48');
691       $CARDS["foxes"]    = array('19','20');
692       if($RULES["dullen"]=='none')
693         {
694           $CARDS["trump"]    = array('3','4','5','6','7','8','9','10','11','12','13','14','15','16',
695                                      '17','18','19','20','21','22','23','24','25','26');
696           $CARDS["hearts"]   = array('43','44','1','2','45','46','47','48');
697         }
698       /* do we need to reorder for Schweinchen? need to search for it because of special case for dullen above*/
699       if($RULES['schweinchen']=='both'&& $GAME['schweinchen-who'])
700         {
701           /* find the fox and put them at the top of the stack */
702           foreach(array('19','20') as $fox)
703             {
704               /* search for fox */
705               $trump = $CARDS['trump'];
706               $key = array_keys($trump, $fox);
707
708               /* reorder */
709               $foxa = array();
710               $foxa[]=$trump[$key[0]];
711               unset($trump[$key[0]]);
712               $trump = array_merge($foxa,$trump);
713               $CARDS['trump'] = $trump;
714             }
715         }
716       else if( ($RULES['schweinchen']=='second' || $RULES['schweinchen']=='secondaftercall')
717                && $GAME['schweinchen-who'])
718         {
719           /* find the fox and put them at the top of the stack */
720           $trump = $CARDS['trump'];
721           $key = array_keys($trump, '19');
722
723           /* reorder */
724           $foxa = array();
725           $foxa[]=$trump[$key[0]];
726           unset($trump[$key[0]]);
727           $trump = array_merge($foxa,$trump);
728           $CARDS['trump'] = $trump;
729         }
730       break;
731     case "queen":
732       $CARDS["trump"]    = array('3','4','5','6','7','8','9','10');
733       $CARDS["clubs"]    = array('27','28','29','30','31','32','11','12','33','34');
734       $CARDS["spades"]   = array('35','36','37','38','39','40','13','14','41','42');
735       $CARDS["hearts"]   = array('43','44', '1', '2','45','46','15','16','47','48');
736       $CARDS["diamonds"] = array('19','20','21','22','23','24','17','18','25','26');
737       $CARDS["foxes"]    = array();
738       break;
739     case "jack":
740       $CARDS["trump"]    = array('11','12','13','14','15','16','17','18');
741       $CARDS["clubs"]    = array('27','28','29','30','31','32','3', '4','33','34');
742       $CARDS["spades"]   = array('35','36','37','38','39','40','5', '6','41','42');
743       $CARDS["hearts"]   = array('43','44', '1', '2','45','46','7', '8','47','48');
744       $CARDS["diamonds"] = array('19','20','21','22','23','24','9','10','25','26');
745       $CARDS["foxes"]    = array();
746       break;
747     case "trumpless":
748       $CARDS["trump"]    = array();
749       $CARDS["clubs"]    = array('27','28','29','30','31','32','3', '4','11','12','33','34');
750       $CARDS["spades"]   = array('35','36','37','38','39','40','5', '6','13','14','41','42');
751       $CARDS["hearts"]   = array('43','44', '1', '2','45','46','7', '8','15','16','47','48');
752       $CARDS["diamonds"] = array('19','20','21','22','23','24','9','10','17','18','25','26');
753       $CARDS["foxes"]    = array();
754       break;
755     case "club":
756       $CARDS["trump"]    = array('1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16',
757                                  '17','18','27','28','29','30','31','32','33','34');
758       $CARDS["clubs"]    = array();
759       $CARDS["spades"]   = array('35','36','37','38','39','40','41','42');
760       $CARDS["hearts"]   = array('43','44','45','46','47','48');
761       $CARDS["diamonds"] = array('19','20','21','22','23','24','25','26');
762       $CARDS["foxes"]    = array();
763       if($RULES["dullen"]=='none')
764         {
765           $CARDS["trump"]    = array('3','4','5','6','7','8','9','10','11','12','13','14','15','16',
766                                      '17','18','27','28','29','30','31','32','33','34');
767           $CARDS["hearts"]   = array('43','44','1','2','45','46','47','48');
768         }
769       break;
770     case "spade":
771       $CARDS["trump"]    = array('1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16',
772                                  '17','18','35','36','37','38','39','40','41','42');
773       $CARDS["clubs"]    = array('27','28','29','30','31','32','33','34');
774       $CARDS["spades"]   = array();
775       $CARDS["hearts"]   = array('43','44','45','46','47','48');
776       $CARDS["diamonds"] = array('19','20','21','22','23','24','25','26');
777       $CARDS["foxes"]    = array();
778       if($RULES["dullen"]=='none')
779         {
780           $CARDS["trump"]    = array('3','4','5','6','7','8','9','10','11','12','13','14','15','16',
781                                      '17','18','35','36','37','38','39','40','41','42');
782           $CARDS["hearts"]   = array('43','44','1','2','45','46','47','48');
783         }
784       break;
785     case "heart":
786       $CARDS["trump"]    = array('1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16',
787                                  '17','18','43','44','45','46','47','48');
788       $CARDS["clubs"]    = array('27','28','29','30','31','32','33','34');
789       $CARDS["spades"]   = array('35','36','37','38','39','40','41','42');
790       $CARDS["hearts"]   = array();
791       $CARDS["diamonds"] = array('19','20','21','22','23','24','25','26');
792       $CARDS["foxes"]    = array();
793       if($RULES["dullen"]=='none')
794         {
795           $CARDS["trump"]    = array('3','4','5','6','7','8','9','10','11','12','13','14','15','16',
796                             '17','18','43','44','1','2','45','46','47','48');
797         }
798       break;
799     }
800 }
801
802 function mysort($cards,$gametype)
803 {
804   global $PREF;
805   if(isset($PREF['sorting']))
806     if($PREF['sorting']=='high-low')
807       usort ( $cards, 'sort_comp_high_low' );
808     else
809       usort ( $cards, 'sort_comp_low_high' );
810   else
811     usort ( $cards, 'sort_comp_high_low' );
812   return $cards;
813 }
814
815 function sort_comp_high_low($a,$b)
816 {
817   global $CARDS;
818
819   $ALL = array();
820   $ALL = array_merge($CARDS['trump'],$CARDS['diamonds'],$CARDS['clubs'],
821                      $CARDS['hearts'],$CARDS['spades']);
822
823   return pos_array($a,$ALL)-pos_array($b,$ALL);
824 }
825
826 function sort_comp_low_high($a,$b)
827 {
828   global $CARDS;
829
830   $ALL = array();
831   $ALL = array_merge($CARDS['trump'],$CARDS['diamonds'],$CARDS['clubs'],
832                      $CARDS['hearts'],$CARDS['spades']);
833
834   return -pos_array($a,$ALL)+pos_array($b,$ALL);
835 }
836
837 function can_call($what,$hash)
838 {
839   /* figure out if a person can make a call:
840    $what in 0,30,60,90,120 = points of the call
841    $hash                   = the hash of the person who wants to make the call
842
843    return values:
844    0   can't make that call
845    1   can make the call
846    2   can make the call, but this is the last chance to do so...
847    */
848
849   global $RULES;
850
851   /* get some information
852    */
853   $gameid   = DB_get_gameid_by_hash($hash);
854   $gametype = DB_get_gametype_by_gameid($gameid);
855   $oldcall  = DB_get_call_by_hash($hash); /* did the person already made a call? */
856   $pcall    = DB_get_partner_call_by_hash($hash); /* did the partner already made a call */
857
858
859   /* you're call must be better than the one you or your partner already made
860    */
861   if( ($pcall!=NULL && ($what >= $pcall))
862       || ($oldcall!=NULL && ($what >=$oldcall)) )
863     {
864       return 0;
865     }
866
867   /* for some rules we need to know how many cards people have
868    */
869   $NRcards  = count(DB_get_hand($hash));
870
871   $NRallcards = 0;
872   for ($i=1;$i<5;$i++)
873     {
874       $user         = DB_get_hash_from_game_and_pos($gameid,$i);
875       $NRallcards  += count(DB_get_hand($user));
876     };
877
878   /* in case of a wedding, everything will be delayed by an offset
879    */
880   $offset = 0;
881   if($gametype=="wedding")
882     {
883       $offset = DB_get_sickness_by_gameid($gameid);
884       if ($offset <0) /* not resolved */
885         return 0;
886     };
887
888   /* now check if the call is allowed depending on the rule set
889    */
890   switch ($RULES["call"])
891     {
892     case "1st-own-card":
893       /* calls can be made before/while you play your card...
894        * first card = 120, second card = 90, etc.
895        */
896       if( 4-($what/30) == 12 - ($NRcards + $offset))
897         return 2;
898       if( 4-($what/30) > 12 - ($NRcards + $offset))
899         return 1;
900       break;
901     case "5th-card":
902       /* you can make the first call anytime during the first trick
903        */
904       if( 27+4*($what/30) == $NRallcards + $offset*4)
905         return 2;
906       if( 27+4*($what/30) < $NRallcards + $offset*4)
907         return 1;
908       break;
909     case "9-cards":
910       /* you can call 120 with 12 cards, 90 with 9 or more cards, 60 with 6 or more, etc.
911        * you can't skip a call though
912        */
913
914       /* figure out last call
915        */
916       if($oldcall!=NULL && $pcall!=NULL)
917         $mincall = ($oldcall>$pcall) ? $pcall : $oldcall;
918       else if($oldcall!=NULL)
919         $mincall = $oldcall;
920       else if ($pcall!=NULL)
921         $mincall = $pcall;
922       else
923         $mincall = -1;
924
925
926       if( 12 == ($NRcards + $offset))
927         {
928           return 2;
929         }
930       else if( 12 < ($NRcards + $offset))
931         {
932           return 1;
933         }
934       else if ( 9 == ($NRcards + $offset))
935         {
936           if( ($mincall>=0 && $mincall<=120 && $what<=90 ) )
937             return 2;
938         }
939       else if ( 9 < ($NRcards + $offset))
940         {
941           if( ($mincall>=0 && $mincall<=120 && $what<=90 ) )
942             return 1;
943         }
944       else if ( 6 == ($NRcards + $offset))
945         {
946           if( ($mincall>=0 && $mincall<=90 && $what<=60 ) )
947             return 2;
948         }
949       else if ( 6 < ($NRcards + $offset))
950         {
951           if( ($mincall>=0 && $mincall<=90 && $what<=60 ) )
952             return 1;
953         }
954       else if ( 3 == ($NRcards + $offset))
955         {
956           if( ($mincall>=0 && $mincall<=60 && $what<=30 ) )
957             return 2;
958         }
959       else if ( 3 < ($NRcards + $offset))
960         {
961           if( ($mincall>=0 && $mincall<=60 && $what<=30 ) )
962             return 1;
963         }
964       else if ( 0 == ($NRcards + $offset))
965         {
966           if( ($mincall>=0 && $mincall<=30 && $what==0 ) )
967             return 2;
968         }
969       else if ( 0 < ($NRcards + $offset))
970         {
971           if( ($mincall>=0 && $mincall<=30 && $what==0 ) )
972             return 1;
973         };
974       break;
975     }
976
977   return 0;
978 }
979
980 function display_table_begin ()
981 {
982   global $gameid, $GT, $debug,$INDEX,$defaulttimezone,$session;
983   global $RULES,$GAME,$gametype;
984
985   $result = DB_query("SELECT  User.fullname as name,".
986                      "        Hand.position as position, ".
987                      "        User.id, ".
988                      "        Hand.party as party, ".
989                      "        Hand.sickness as sickness, ".
990                      "        Hand.point_call, ".
991                      "        User.last_login, ".
992                      "        Hand.hash,       ".
993                      "        User.timezone,    ".
994                      "        User.email       ".
995                      "FROM Hand ".
996                      "LEFT JOIN User ON User.id=Hand.user_id ".
997                      "WHERE Hand.game_id='".$gameid."' ".
998                      "ORDER BY position ASC");
999
1000   $row0 = DB_fetch_array($result);
1001   $row1 = DB_fetch_array($result);
1002   $row2 = DB_fetch_array($result);
1003   $row3 = DB_fetch_array($result);
1004
1005   echo "<div class=\"table\">\n";
1006   display_single_user($row1);
1007   echo "\n<div class=\"middle\">\n";
1008   display_single_user($row0,1); /* mark starting player in case re/contra is not set yet */
1009   echo "  <img class=\"table\" src=\"pics/table.png\" alt=\"table\" />\n";
1010   display_single_user($row2);
1011
1012   return;
1013 }
1014 function display_table_end ()
1015 {
1016   global $gameid, $GT, $debug,$INDEX,$defaulttimezone,$session;
1017   global $RULES,$GAME,$gametype;
1018
1019   $result = DB_query("SELECT  User.fullname as name,".
1020                      "        Hand.position as position, ".
1021                      "        User.id, ".
1022                      "        Hand.party as party, ".
1023                      "        Hand.sickness as sickness, ".
1024                      "        Hand.point_call, ".
1025                      "        User.last_login, ".
1026                      "        Hand.hash,       ".
1027                      "        User.timezone,    ".
1028                      "        User.email       ".
1029                      "FROM Hand ".
1030                      "LEFT JOIN User ON User.id=Hand.user_id ".
1031                      "WHERE Hand.game_id='".$gameid."' ".
1032                      "ORDER BY position ASC");
1033
1034   $row0 = DB_fetch_array($result);
1035   $row1 = DB_fetch_array($result);
1036   $row2 = DB_fetch_array($result);
1037   $row3 = DB_fetch_array($result);
1038
1039   echo "</div>\n";
1040   display_single_user($row3);
1041   echo "</div>\n";
1042
1043   return;
1044 }
1045
1046 function display_single_user($r,$start=0)
1047 {
1048   /* start=1, mark starting player, default=0, so the player on the left is not marked */
1049
1050   global $gameid, $GT, $debug,$INDEX,$defaulttimezone,$session;
1051   global $RULES,$GAME,$gametype;
1052
1053       $name  = $r[0];
1054       $pos   = $r[1];
1055       $user  = $r[2];
1056       $party = $r[3];
1057       $sickness  = $r[4];
1058       $call      = $r[5];
1059       $hash      = $r[7];
1060       $timezone  = $r[8];
1061       $email     = $r[9];
1062       $wins      = DB_get_number_of_tricks($gameid,$pos);
1063       date_default_timezone_set($defaulttimezone);
1064       $lastlogin = strtotime($r[6]);
1065       date_default_timezone_set($timezone);
1066       $timenow   = strtotime(date("Y-m-d H:i:s"));
1067       $gravatar = "$name<br />\n       <img class=\"gravatar\" title=\"$name\" src=\"http://www.gravatar.com/avatar/".
1068         md5(strtolower(trim($email)))."?d=identicon\" alt=\"$name's gravatar\" />";
1069
1070       echo "  <div class=\"table".($pos-1)."\">\n";
1071
1072       /* mark starting player */
1073       if($start && ! ($party=="re" || $party=="contra"))
1074         echo '   <span class="start">'._('Starting Player')."</span> <br />\n";
1075
1076       if($debug)
1077         echo "   <a href=\"".$INDEX."?action=game&amp;me=".$hash."\">";
1078       if($vacation = check_vacation($user))
1079         {
1080           $start   = $vacation[0];
1081           $stop    = substr($vacation[1],0,10);
1082           $comment = $vacation[2];
1083
1084               $title = "begin: $start  end: $stop $comment";
1085               echo "   <span class=\"vacation\" title=\"$title\">$gravatar (on vacation until $stop)</span> \n";
1086         }
1087       else
1088         echo "   $gravatar \n";
1089       if($debug)
1090         echo"   </a>\n";
1091
1092       /* add hints for poverty, wedding, solo, etc */
1093       if( $gametype != "solo")
1094         if( $RULES["schweinchen"]=="both" && $GAME["schweinchen-who"]==$hash )
1095           echo " Schweinchen. <br />";
1096
1097       if($GT=="poverty" && $party=="re")
1098         if($sickness=="poverty" || ($RULES['lowtrump']=='poverty' && $sickness=='lowtrump'))
1099           {
1100             $userhash = DB_get_hash_from_gameid_and_userid($gameid,$user);
1101             $cards    = DB_get_all_hand($userhash);
1102             $trumpNR  = count_trump($cards,'all');
1103             if($trumpNR)
1104               echo "   <img src=\"pics/button/poverty_trump_button.png\" class=\"button\" ".
1105                 "alt=\"poverty - trump back\" title=\"poverty - trump back\" />\n";
1106             else
1107               echo "   <img src=\"pics/button/poverty_notrump_button.png\" class=\"button\" ".
1108                 "alt=\"poverty - no trump back\" title=\"poverty - no trump back\" />\n";
1109           }
1110         else
1111           echo "   <img src=\"pics/button/poverty_partner_button.png\" class=\"button\" ".
1112             "alt=\"poverty partner\" title=\"poverty partner\" />\n";
1113
1114       if($GT=="dpoverty")
1115         if($party=="re")
1116           if($sickness=="poverty" || ($RULES['lowtrump']=='poverty' && $sickness=='lowtrump'))
1117             {
1118               $userhash = DB_get_hash_from_gameid_and_userid($gameid,$user);
1119               $cards    = DB_get_all_hand($userhash);
1120               $trumpNR  = count_trump($cards,'all');
1121               if($trumpNR)
1122                 echo "   <img src=\"pics/button/poverty_trump_button.png\" class=\"button\" ".
1123                   "alt=\"poverty < trump back\" title=\"poverty - trump back\" />\n";
1124               else
1125                 echo "   <img src=\"pics/button/poverty_notrump_button.png\" class=\"button\" ".
1126                   "alt=\"poverty <\" title=\"poverty - no trump back\" />\n";
1127             }
1128           else
1129             echo "   <img src=\"pics/button/poverty_partner_button.png\" class=\"button\" ".
1130               "alt=\"poverty >\" title=\"poverty partner\" />\n";
1131         else
1132           if($sickness=="poverty"  || ($RULES['lowtrump']=='poverty' && $sickness=='lowtrump'))
1133             {
1134               $userhash = DB_get_hash_from_gameid_and_userid($gameid,$user);
1135               $cards    = DB_get_all_hand($userhash);
1136               $trumpNR  = count_trump($cards,'all');
1137               if($trumpNR)
1138                 echo "   <img src=\"pics/button/poverty2_trump_button.png\" class=\"button\" ".
1139                   "alt=\"poverty2 < trump back\" title=\"poverty2 - trump back\"/>\n";
1140               else
1141                 echo "   <img src=\"pics/button/poverty2_notrump_button.png\" class=\"button\" ".
1142                   "alt=\"poverty2 <\" title=\"poverty2 - no trump back\" />\n";
1143             }
1144           else
1145             echo "   <img src=\"pics/button/poverty2_partner_button.png\" class=\"button\" ".
1146               "alt=\"poverty2 >\" title=\"poverty2 partner\" />\n";
1147
1148       if($GT=="wedding" && $party=="re")
1149         if($sickness=="wedding")
1150           echo "   <img src=\"pics/button/wedding_button.png\" class=\"button\" alt=\"wedding\" title=\"wedding\" />\n";
1151         else
1152           echo "   <img src=\"pics/button/wedding_partner_button.png\" class=\"button\" ".
1153             "alt=\"wedding partner\" title=\"wedding partner\" />\n";
1154
1155       if( (strpos($GT,"solo")!==false) && $party=="re")
1156         {
1157           if(strpos($GT,"queen")!==false)
1158             echo "   <img src=\"pics/button/queensolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Queen solo\" />\n";
1159           else if(strpos($GT,"jack")!==false)
1160             echo "   <img src=\"pics/button/jacksolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Jack solo\" />\n";
1161           else if(strpos($GT,"club")!==false)
1162             echo "   <img src=\"pics/button/clubsolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Club solo\" />\n";
1163           else if(strpos($GT,"spade")!==false)
1164             echo "   <img src=\"pics/button/spadesolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Spade solo\" />\n";
1165           else if(strpos($GT,"heart")!==false)
1166             echo "   <img src=\"pics/button/heartsolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Heart solo\" />\n";
1167           else if(strpos($GT,"trumpless")!==false)
1168             echo "   <img src=\"pics/button/notrumpsolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Trumpless solo\" />\n";
1169           else if(strpos($GT,"trump")!==false)
1170             echo "   <img src=\"pics/button/trumpsolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Trump solo\" />\n";
1171         }
1172
1173       /* add point calls */
1174       if($call!=NULL)
1175         {
1176           if($party=="re")
1177             echo "   <img src=\"pics/button/re_button.png\" class=\"button\" alt=\"re\" title=\"Re\" />\n";
1178           else
1179             echo "   <img src=\"pics/button/contra_button.png\" class=\"button\" alt=\"contra\" title=\"Contra\" />\n";
1180           switch($call)
1181             {
1182             case "0":
1183               echo "   <img src=\"pics/button/0_button.png\" class=\"button\" alt=\"0\" title=\"Call 0\" />\n";
1184               break;
1185             case "30":
1186               echo "   <img src=\"pics/button/30_button.png\" class=\"button\" alt=\"30\" title=\"Call 30\" />\n";
1187               break;
1188             case "60":
1189               echo "   <img src=\"pics/button/60_button.png\" class=\"button\" alt=\"60\" title=\"Call 60\" />\n";
1190               break;
1191             case "90":
1192               echo "   <img src=\"pics/button/90_button.png\" class=\"button\" alt=\"90\" title=\"Call 90\" />\n";
1193               break;
1194             }
1195         }
1196
1197       echo "   <img src=\"pics/button/time-info.png\" class=\"button\" alt=\"time info\" ".
1198         "title=\"local time: ".date("Y-m-d H:i:s",$timenow).  " ".
1199         "last login: ".date("Y-m-d H:i:s",$lastlogin)."\" />";
1200
1201       echo "   <br /><span class=\"numberoftricks\">";
1202       /* show how many tricks the person made */
1203       switch($wins)
1204         {
1205         case 0:
1206           echo "#tricks 0"; break;
1207         case 1:
1208           echo "#tricks 1"; break;
1209         case 2:
1210         case 3:
1211         case 4:
1212           echo "#tricks few"; break;
1213         default:
1214           echo "#tricks many"; break;
1215         }
1216       echo "</span>\n";
1217       echo "  </div>\n";
1218 }
1219
1220
1221 function display_user_menu($id, $skiphash=NULL)
1222 {
1223   global $WIKI,$INDEX;
1224
1225   if($skiphash)
1226     $result = DB_query("SELECT Hand.hash,Hand.game_id,Game.player from Hand".
1227                        " LEFT JOIN Game On Hand.game_id=Game.id".
1228                        " WHERE Hand.user_id='$id'".
1229                        " AND Hand.hash!='$skiphash'".
1230                        " AND ( Game.player='$id' OR ISNULL(Game.player) )".
1231                        " AND ( Game.status='pre' OR Game.status='play' )".
1232                        " ORDER BY Game.session" );
1233   else
1234     $result = DB_query("SELECT Hand.hash,Hand.game_id,Game.player from Hand".
1235                        " LEFT JOIN Game On Hand.game_id=Game.id".
1236                        " WHERE Hand.user_id='$id'".
1237                        " AND ( Game.player='$id' OR ISNULL(Game.player) )".
1238                        " AND ( Game.status='pre' OR Game.status='play' )".
1239                        " ORDER BY Game.session" );
1240
1241   $i=0;
1242   while( $r = DB_fetch_array($result))
1243     {
1244       if($i==0)
1245         {
1246           echo "\n<div class=\"usermenu\">\n  ";
1247           echo _('It\'s your turn in these games').":\n";
1248         }
1249       else
1250         {
1251           echo ", ";
1252         }
1253
1254       $i++;
1255       echo "  <a href=\"".$INDEX."?action=game&amp;me=".$r[0].
1256         "\"> ".DB_format_gameid($r[1])." </a>\n";
1257       if($i>4)
1258         {
1259           echo ",  ...\n";
1260           break;
1261         }
1262     }
1263
1264   if($i)
1265     echo  "</div>\n\n";
1266   return;
1267 }
1268
1269 function generate_score_table($session)
1270 {
1271   /* returns an array with N entries
1272    * $score[$i]["gameid"]   = gameid
1273    * $score[$i]["players"] = array (id=>total points)
1274    * $score[$i]["points"]   = points for this game
1275    * $score[$i]["solo"]     = 1 or 0
1276    */
1277   $score = array();
1278   $i=0;
1279
1280   /* get all ids, scores and gametypes */
1281   $gameids = DB_get_gameids_of_finished_games_by_session($session);
1282
1283   if($gameids == NULL)
1284     return $score;
1285
1286   $player = array();
1287   $player_party = array();
1288
1289   /* get player id from the first game */
1290   $result = DB_query("SELECT user_id from Hand".
1291                      " WHERE Hand.game_id=".$gameids[0][0]);
1292   while( $r = DB_fetch_array($result))
1293     $player[$r[0]] = 0;
1294
1295   /* get party of players for each game in the session */
1296   foreach($player as $id=>$points)
1297     $player_party[$id]=DB_get_party_by_session_and_userid($session,$id);
1298
1299   /* get points and generate table */
1300   foreach($gameids as $gameid)
1301     {
1302       $re_score = $gameid[1];
1303       $gametype = $gameid[2];
1304       foreach($player as $id=>$points)
1305         {
1306           $party = $player_party[$id][$i][0];
1307           if($party == "re")
1308             if($gametype=="solo")
1309               $player[$id] += 3*$re_score;
1310             else
1311               $player[$id] += $re_score;
1312           else if ($party == "contra")
1313             $player[$id] -= $re_score;
1314         }
1315       $score[$i]['gameid']  = $gameid[0] ;
1316       $score[$i]['players'] = $player;
1317       $score[$i]['points']  = abs($re_score);
1318       $score[$i]['solo']    = ($gametype=="solo");
1319
1320       $i++;
1321     }
1322
1323   return $score;
1324 }
1325
1326 function generate_global_score_table()
1327 {
1328   $return = array();
1329
1330   /* get all ids, scores and gametypes */
1331   $gameids = DB_get_gameids_of_finished_games_by_session(0);
1332
1333   if($gameids == NULL)
1334     return '';
1335
1336   $player = array();
1337   /* get player id, names... from the User table */
1338   $result = DB_query('SELECT User.id, User.fullname FROM User');
1339
1340   /* save information in an array */
1341   while( $r = DB_fetch_array($result))
1342     $player[$r[0]] = array('name'=> $r[1], 'points' => 0 , 'nr' => 0, 'active' => 0,
1343                            'response' => 0 , 'solo' => 0, 'soloavg' => 0);
1344
1345   /* get points and generate table */
1346   foreach($gameids as $gameid)
1347     {
1348       $re_score = $gameid[1];
1349       $gametype = $gameid[2];
1350
1351       /* get players involved in this game */
1352       $result = DB_query('SELECT user_id FROM Hand WHERE game_id='.DB_quote_smart($gameid[0]));
1353       while($r = DB_fetch_array($result))
1354         {
1355           $id = $r[0];
1356           $party = DB_get_party_by_gameid_and_userid($gameid[0],$id);
1357           if($party == 're')
1358             if($gametype=='solo')
1359               $player[$id]['points'] += 3*$re_score;
1360             else
1361               $player[$id]['points'] += $re_score;
1362           else if ($party == 'contra')
1363             $player[$id]['points'] -= $re_score;
1364           if($party)
1365             $player[$id]['nr']+=1;
1366         }
1367     }
1368
1369   /* add number of active games */
1370   $result = DB_query_array_all("SELECT user_id, COUNT(*) as c  " .
1371                                " FROM Hand".
1372                                " LEFT JOIN Game ON Game.id=game_id".
1373                                " WHERE Game.status IN ('pre','play')".
1374                                " GROUP BY user_id");
1375
1376   foreach($result as $res)
1377     {
1378       $player[$res[0]]['active'] = $res[1];
1379     }
1380
1381   /* response time of users*/
1382   $result = DB_query_array_all("SELECT user_id,".
1383                               "IFNULL(AVG(if(P1.sequence in (2,3,4),".
1384                               "-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 ".
1385                               "FROM Play P1 ".
1386                               "LEFT JOIN Hand_Card ON P1.hand_card_id=Hand_Card.id ".
1387                               "LEFT JOIN Hand ON Hand.id=Hand_Card.hand_id ".
1388                               "GROUP BY user_id ");
1389
1390   foreach($result as $res)
1391     {
1392       $player[$res[0]]['response'] = $res[1];
1393     }
1394
1395   /* most solos */
1396   $result = DB_query_array_all("SELECT user_id as uid,".
1397                                "       COUNT(*), ".
1398                                "       COUNT(*)/(SELECT COUNT(*) FROM Hand LEFT JOIN User ON User.id=Hand.user_id WHERE User.id=uid) as c ".
1399                                " FROM Game ".
1400                                " LEFT JOIN Hand ON Hand.position=startplayer AND Game.id=Hand.game_id ".
1401                                " WHERE type='solo' AND Game.status='gameover' ".
1402                                " GROUP BY user_id ");
1403
1404   foreach($result as $res)
1405     {
1406       $player[$res[0]]['solo'] = $res[1];
1407       $player[$res[0]]['soloavg'] = $res[2];
1408     }
1409
1410
1411   /* sort everything nicely */
1412
1413   function cmp($a,$b)
1414   {
1415     if($a['nr']==0) return 1;
1416     if($b['nr']==0) return 1;
1417
1418     $a=$a['points']/$a['nr'];
1419     $b=$b['points']/$b['nr'];
1420
1421     if ($a == $b)
1422       return 0;
1423     return ($a > $b) ? -1 : 1;
1424   }
1425   usort($player,'cmp');
1426
1427
1428   foreach($player as $pl)
1429     {
1430       /* limit to players with at least 10 games */
1431       if($pl['nr']>10)
1432         $return[] = array( $pl['name'], round($pl['points']/$pl['nr'],3), $pl['points'],$pl['nr'],$pl['active'],
1433                            $pl['response'],$pl['solo'],$pl['soloavg']);
1434     }
1435
1436   return $return;
1437 }
1438
1439 function format_score_table_ascii($score)
1440 {
1441   $output="";
1442   if(sizeof($score)==0)
1443     return "";
1444
1445   /* truncate table if we have too many games */
1446   $max = sizeof($score);
1447   if($max>6) $output.=" (table truncated to last 6 games)\n";
1448
1449   /* output header */
1450   foreach($score[0]['players'] as $id=>$points)
1451     {
1452       $name = DB_get_name('userid',$id); /*TODO*/
1453       $output.= "  ".substr($name,0,2)."  |";
1454     }
1455   $output.="  P   |\n";
1456   $output.= "------+------+------+------+------+\n";
1457
1458   /* output score for each game */
1459   $i=0;
1460   foreach($score as $game)
1461     {
1462       $i++;
1463       if($i-1<$max-6) continue;
1464
1465       foreach($game['players'] as $id=>$points)
1466         $output.=str_pad($points,6," ",STR_PAD_LEFT)."|";
1467       $output.=str_pad($game['points'],4," ",STR_PAD_LEFT);
1468
1469       /* check for solo */
1470       if($game['solo'])
1471         $output.= " S|";
1472       else
1473         $output.= "  |";
1474
1475       $output.="\n";
1476     }
1477   return $output;
1478 }
1479
1480 function format_score_table_html($score,$userid)
1481 {
1482   global $INDEX;
1483
1484   if(sizeof($score)==0)
1485     return "";
1486
1487   $output = "<div class=\"scoretable\">\n<table class=\"score\">\n";
1488
1489   /* output header */
1490   $header = "";
1491   $header.= " <thead>\n  <tr>\n";
1492   $header.= "   <th> No </th>";
1493   foreach($score[0]['players'] as $id=>$points)
1494     {
1495       $name = DB_get_name('userid',$id); /*TODO*/
1496       $header.= "<th> ".substr($name,0,2)." </th>";
1497     }
1498   $header.="<th>P</th>\n  </tr>\n </thead>\n";
1499
1500   /* use the same as footer */
1501   $footer = "";
1502   $footer.= " <tfoot>\n  <tr>\n";
1503   $footer.= "   <td> No </td>";
1504   foreach($score[0]['players'] as $id=>$points)
1505     {
1506       $name = DB_get_name('userid',$id); /*TODO*/
1507       $footer.= "<td> ".substr($name,0,2)." </td>";
1508     }
1509   $footer.="<td>P</td>\n  </tr>\n </tfoot>\n";
1510
1511   /* body */
1512   $body = "";
1513   $body.= " <tbody>\n";
1514   $i=0;
1515   foreach($score as $game)
1516     {
1517       $i++;
1518       $body.="  <tr>";
1519       $userhash = DB_get_hash_from_gameid_and_userid($game['gameid'],$userid);
1520       /* create link to old games only if you are logged in and its your game*/
1521       if(isset($_SESSION['id']) && $_SESSION['id']==$userid)
1522         $body.="  <td> <a href=\"".$INDEX."?action=game&amp;me=".$userhash."\">$i</a></td>";
1523       else
1524         $body.="  <td>$i</td>";
1525
1526       foreach($game['players'] as $id=>$points)
1527         $body.="<td>".$points."</td>";
1528       $body.="<td>".$game['points'];
1529
1530       /* check for solo */
1531       if($game['solo'])
1532         $body.= " S";
1533       $body.="</td></tr>\n";
1534     }
1535
1536   $output.=$header;
1537   if($i>12)
1538     $output.=$footer;
1539   $output.=$body;
1540
1541   $output.=" </tbody>\n</table>\n</div>\n";
1542
1543   return $output;
1544 }
1545
1546 function createCache($content, $cacheFile)
1547 {
1548   $fp = fopen($cacheFile,"w");
1549   if($fp)
1550     {
1551       fwrite($fp,$content);
1552       fclose($fp);
1553     }
1554   else
1555     echo "WARNING: couldn't create cache file";
1556
1557   return;
1558 }
1559
1560 function getCache($cacheFile, $expireTime)
1561 {
1562   if( file_exists($cacheFile) &&
1563       filemtime($cacheFile )>( time() - $expireTime ) )
1564     {
1565       return file_get_contents($cacheFile);
1566     }
1567
1568   return false;
1569 }
1570
1571 function check_vacation($userid)
1572 {
1573   /* get start date */
1574   $result = DB_query_array("SELECT value FROM User_Prefs".
1575                      " WHERE user_id='$userid' AND pref_key='vacation start'" );
1576   if($result)
1577     $start = $result[0];
1578   else
1579     return NULL;
1580
1581   /* get end date */
1582   $result = DB_query_array("SELECT value FROM User_Prefs".
1583                      " WHERE user_id='$userid' AND pref_key='vacation stop'" );
1584   if($result)
1585     $stop = $result[0];
1586   else
1587     return NULL;
1588
1589   /* get comment */
1590   $result = DB_query_array("SELECT value FROM User_Prefs".
1591                      " WHERE user_id='$userid' AND pref_key='vacation comment'" );
1592   if($result)
1593     $comment = $result[0];
1594   else
1595     $comment = '';
1596
1597   /* check if user is on vacation. TODO: use user's timezone */
1598   if( (time() - strtotime($start) >0) &&
1599       (strtotime($stop) - time()  >0))
1600     return array ($start,$stop,$comment);
1601   else
1602     return NULL;
1603 }
1604
1605 function cancel_game($why,$gameid)
1606 {
1607   $gameid = DB_quote_smart($gameid);
1608
1609   /* update the game table */
1610   switch($why)
1611     {
1612     case 'timedout':
1613       DB_query("UPDATE Game SET status='cancel-timedout' WHERE id=$gameid");
1614       break;
1615     case 'nines':
1616       DB_query("UPDATE Game SET status='cancel-nines' WHERE id=$gameid");
1617       break;
1618     case 'trump':
1619       DB_query("UPDATE Game SET status='cancel-trump' WHERE id=$gameid");
1620       break;
1621     case 'noplay':
1622       DB_query("UPDATE Game SET status='cancel-noplay' WHERE id=$gameid");
1623       break;
1624     case 'lowtrump':
1625       DB_query("UPDATE Game SET status='cancel-lowtrump' WHERE id=$gameid");
1626       break;
1627     }
1628   /* set each player to gameover */
1629   $result = DB_query("SELECT id FROM Hand WHERE game_id=".DB_quote_smart($gameid));
1630   while($r = DB_fetch_array($result))
1631     {
1632       $id = $r[0];
1633       DB_query("UPDATE Hand SET status='gameover' WHERE id=".DB_quote_smart($id));
1634     }
1635
1636   return;
1637 }
1638
1639 function get_user_token($userid)
1640 {
1641
1642   $token = NULL;
1643
1644   $date = DB_get_user_creation_date($userid);
1645   $name = DB_get_name('userid',$userid);
1646
1647   if($date && $name)
1648     $token = md5("token".$name.$date);
1649
1650   return $token;
1651 }
1652
1653 ?>