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