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