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