Platon Technologies
not logged in Login Registration
EnglishSlovak
open source software development celebrating 10 years of open source development! Saturday, April 20, 2024

File: [Platon] / games / mines / mines.c (download)

Revision 1.23, Mon Sep 20 09:18:46 2004 UTC (19 years, 7 months ago) by nepto


Changes since 1.22: +3 -3 lines

Changed Platon SDG postal address.

/*
 * mines - Super Mines game for MS-Dos/Win32/SVGAlib/X11
 *
 * mines.c - main game file
 * ____________________________________________________________
 *
 * Developed by Ondrej Jombik <nepto@platon.sk>
 * Copyright (c) 1997-2000 Condy software inc.
 * Copyright (c) 2001-2004 Platon SDG, http://platon.sk/
 * All rights reserved.
 *
 * See README file for more information about this software.
 * See COPYING file for license information.
 *
 * Download the latest version from
 * http://platon.sk/projects/games/
 */

/* $Platon: games/mines/mines.c,v 1.22 2004/04/06 09:54:17 nepto Exp $ */

/* LANGUAGE */
#define LANG_ENGLISH_NEW    0
#define LANG_ENGLISH_OLD    1
#define LANG_SLOVAK            2
#define LANG_ENGLISH        LANG_ENGLISH_NEW
#define LANGUAGE            LANG_ENGLISH /* alter this to change language */

#define PSQUARE_DYNAMIC_ALLOCATION    (0)
#define ASSERTION_USAGE                (1)

/* CONSTS */
#if LANGUAGE == LANG_SLOVAK
#  define EXENAME     "mines.exe"
#  define ERR_ARGC    "Pr¡lis vela argumentov v pr¡kazovom riadku."
#  define ERR_EXEC    "Nem“zem spustit"
#  define ERR_BREAK   "Chyba v presmerovan¡ Ctrl-Break." /* N/A */
#  define ERR_MOUSE   "Tento program potrebuje mys."
#  define ERR_WRITE   "Chyba pri z pise. Plny disk?"
#  define ERR_MEMORY  "Nedostatok volnej pam„te."
#  define ERR_GRAPH   "Chyba grafiky:"
#  define STR_OK                "OK"
#  define STR_YES               "Ano"
#  define STR_NO                "Nie"
#  define STR_RESET             "Reset"
#  define STR_MORE_INFO         "viac info"
#  define STR_PLAYGROUND_WIDTH  "S¡rka pola"
#  define STR_PLAYGROUND_HEIGHT "Vyska pola"
#  define STR_INFO_TABLE        "Info tabulka"
#  define STR_PAUSE             "P A U Z A"
#  define STR_CLICK_HERE        "Klikni sem pre pokracovanie..."
#  define STR_WELL_DONE         "Hotovo!"
#  define STR_MINES_REPORT      "%u m¡n si zlikvidoval(a) na ploche %ux%u za %u:%02u:%02u"
#  define STR_ENTER_YOUR_NAME   "Zadaj svoje meno:"
#  define STR_BAD_LUCK          "Upsss... SMOLA!"
#  define STR_PLAY_AGAIN        "Chces hrat znovu?"
#  define STR_HELP              "Pomoc"
#  define STR_OTHER_PROGRAMS    "In‚ programy"
#  define STR_SOURCE_EXAMPLE    "Uk zka zdrojov‚ho textu"
#  define STR_SOURCE_EXAMPLE_2    "Uk zka zdrojov‚ho textu z tohto programu"
#  define STR_BACK              "<--sp„t--"
#  define STR_DIFFICULTY        "Obtiaznost"
#  define STR_END_GAME          "Koniec hry?"
#  define STR_HALL_OF_FAME      "Tabulka najleps¡ch"
#  define STR_HSC_ENTRY         "M¡n:%u / Velkost:%ux%u / Cas:%u:%02u:%02u / D tum:%u.%u.%u"
#  define STR_LONG_OTHER_PROGRAMS "\
< In‚ programyô?õ Niektor‚ sa nach dzaj£\n\
<na mojej ôwebstránkeõ, ale viac informaci¡\n\
< sa dozviete prostredn¡ctvom ôe-mailõu.\n"
#  define STR_LONG_HELP_TEXT "\
Cielom je odm¡novat cel‚ pole.\n\
Je nutn‚ oznacit vsetky m¡ny a odokryt vsetky nezam¡novane pol¡cka.\n\
Hra sa ovl da pomocou mysi a kl vesnice.\n\
\n\
<ôLav‚ tlacidloõ  odkryva policko. V pr¡pade, ze sa tam nach dza\n\
<               m¡na hra ne£spesne konc¡. Inak sa odokryj£ vsetky\n\
<               nezam¡novan‚ pol¡cka nach dzaj£ce sa v jeho okol¡.\n\
\n\
<ôPrav‚ tlacidloõ oznac¡ pol¡cko ako m¡nu. Po dalsom stlacen¡ ako\n\
<               potencialnu m¡nu a po dalsom oznacenie zrus¡. Miesta\n\
<               oznacen‚ ako m¡na s£ zabezpecen‚ pred odokryvan¡m.\n\
\n\
<ôEscõ vykon  priame ukoncenie hry a n vrat do menu.\n\
<ôF1õ  zobraz¡ okno pomoci.\n\
<ôF4õ  docasne prerus¡ hru (PAUZA).\n\
\n\
Po oznacen¡ vsetkych m¡n a odkryt¡ vsetkych nezam¡novanych pol¡cok\n\
sa hra £spesne konc¡ a moze byt zap¡san  do ôTabulky najleps¡chõ.\n\
Hlavnym krit‚riom pre z pis je vacs¡ pocet m¡n, pri rovnosti\n\
rozhoduje mens¡ cas.\n\
\n\
<Tato hra vznikla z podnetu nezn meho autora ako pr¡klad softv‚rov‚ho\n\
<produktu. Je volne s¡riteln  a ak‚kolvek vyuz¡vanie na komercn‚\n\
<£cely je mozn‚ len so s£hlasom autora. V pr¡pade z ujmu o dalsie\n\
<programy sa informujte na adrese:\n\
\n\
>ôOndrej Jomb¡k ml.õ\n\
>ôHol¡cska 26õ      \n\
>ô851 01 Bratislavaõ       \n"
#  define STR_LONG_SOURCE_CODE        "\
<      Tak toto je cast hlavn‚ho ovl dacieho modulu tohto programu,\n\
<ktory m  (zatial) nieco cez ô10 000 riadkovõ. Ako programovac¡ jazyk\n\
<bol zvoleny ôBorland C++ v3.1õ od firmy Borland International, Inc.\n\
<Samozrejme, ze v skutocnosti zdrojovy k¢d nevyzer  takto, tu je\n\
<len trosku zhusteny, aby sa toho viac zmestilo na obrazovku.\n\
ôÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜõ\n\
if (but&&isininfo(x,y)){register WORD xx,yy;\n\
while (!releasebutton(but-1,&xx,&yy));hidemouse();\n\
if (xx!=x||yy!=y)WriteInfo(xx-(x-infox),yy-(y-infoy));\n\
showmouse();but=0;}\n\
but&=3;x=(x-xoff)/barsize;y=(y-yoff)/barsize;\n\
if (xold==0xffff){xold=x;yold=y;}\n\
if ((x!=xold||y!=yold)){\n\
if (xold<nx&&yold<ny&&sqpress(xold,yold)&&!sqopen(xold,yold)){\n\
sqpress(xold,yold)=NO;hidemouse();\n\
SetSquare(xold,yold,1);showmouse();}\n\
xold=x;yold=y;}if (x<nx&&y<ny&&!underinfo(x,y)){\n\
if (!but){mlstant=mrstant=0;\n\
(void)releasebutton(0,NULL,NULL);(void)releasebutton(1,NULL,NULL);}\n\
if ((but==2)&&!sqopen(x,y)&&mlstant!=but){mlstant=but;\n\
switch(((sqmark(x,y)+(!sqmark(x,y)&&!cmines?2:1))%3)){\n\
case 1:cmines--;sqmark(x,y)=1;break;\n\
case 2:if (sqmark(x,y)==1)cmines++;sqmark(x,y)=2;break;\n\
default:sqmark(x,y)=0;break;}hidemouse();SetSquare(x,y,1);showmouse();}\n\
else{if (but==1&&!sqopen(x,y)&&!sqpress(x,y)&&sqmark(x,y)!=1){\n\
sqpress(x,y)=YES; hidemouse();SetSquare(x,y,0);showmouse();}\n\
else{if (!but&&!sqopen(x,y)&&sqpress(x,y)&&sqmark(x,y)!=1){\n\
if (value(x,y)==MINE)break;hidemouse();OpenSquare(x,y);showmouse();\n\
if (infosafe==NULL)ShowInfo();}else{\n\
if (but==3&&sqopen(x,y)&&mrstant!=but){mrstant=but;\n\
if (OpenNearSquares(x,y)==YES)break;\n\
}}}}}}HideInfo();(void)releasebutton(0,NULL,NULL);\n\
ôßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßõ\n"
#else
#  define EXENAME     "mines.exe"
#  define ERR_ARGC    "Too many arguments in command line."
#  define ERR_EXEC    "Can't run"
#  define ERR_BREAK   "Error redirecting Ctrl-Break."
#  define ERR_MOUSE   "This program requires mouse."
#  define ERR_WRITE   "Can't write. Disk full?"
#  define ERR_MEMORY  "Not enough memory"
#  define ERR_GRAPH   "Graphics error: "
#  define STR_OK                "OK"
#  define STR_YES               "Yes"
#  define STR_NO                "No"
#  define STR_RESET             "Reset"
#  define STR_MORE_INFO         "more info"
#  define STR_PLAYGROUND_WIDTH  "Width"
#  define STR_PLAYGROUND_HEIGHT "Height"
#  define STR_INFO_TABLE        "Info table"
#  define STR_PAUSE             "P A U S E"
#  define STR_CLICK_HERE        "Click here to continue..."
#  define STR_WELL_DONE         "Well done!"
#  define STR_MINES_REPORT      "%u mines on %ux%u size playground were destroyed in %u:%02u:%02u"
#  define STR_ENTER_YOUR_NAME   "Enter your name:"
#  define STR_BAD_LUCK          "Upsss... SHAME!"
#  define STR_PLAY_AGAIN        "Do you want to play again?"
#  define STR_HELP              "Help"
#  define STR_OTHER_PROGRAMS    "Other programs"
#  define STR_SOURCE_EXAMPLE    "Source code example"
#  define STR_SOURCE_EXAMPLE_2  "This program source code example"
#  define STR_BACK              "<--back--"
#  define STR_DIFFICULTY        "Difficulty"
#  define STR_END_GAME          "End game?"
#  define STR_HALL_OF_FAME      "Hall of fame"
#  define STR_HSC_ENTRY         "Mines:%u / Size:%ux%u / Time:%u:%02u:%02u / Date:%u.%u.%u"
#  define STR_LONG_OTHER_PROGRAMS "\
< Other programsô?õ Some of them are located\n\
<on my ôhomepageõ, but you can get more\n\
<information through ôe-mailõ.\n"
#  define STR_LONG_HELP_TEXT "\
The goal is to remove all mines from playground.\n\
You have to mark all the mines and uncover all fields without mines.\n\
The games is controlled using mouse and keyboard.\n\
\n\
<ôLeft buttonõ    reveals the field. In case there is a mine located,\n\
<               game is lost. Elsewhere all fields around mentioned\n\
<               field not containing a mine are uncovered.\n\
\n\
<ôRight buttonõ   marks field as a mine. After next clicking it marks\n\
<               field as a potencial mine. And finally, after further\n\
<               clicking is mine mark removed. Fields marked as a mine\n\
<               are protected before revealing.\n\
\n\
<ôEscõ quits the played game and returns to main menu.\n\
<ôF1õ  shows window with game help.\n\
<ôF4õ  temporarily interrupts the game (PAUSE).\n\
\n\
<When all mines are marked and all other fields are revealed, the game\n\
<successfully finished and it could be written in the ôHall of fameõ table.\n\
<The criterium in the table is the number of revealed mines, than time.\n\
\n\
<This game is free software, which comes with absolutely no warranty.\n\
<It is licensed under GNU General Public License. For more information\n\
<you can visit our website located at ôhttp://platon.sk/õ or e-mail us\n\
<at ôplaton@platon.skõ or our postal address:\n\
>ôPlaton SDGõ      \n\
>ôHlavna 3õ        \n\
>ô927 01  Salaõ            \n\
>ôSlovakiaõ        \n\
>ôEuropeõ          \n"
#  define STR_LONG_SOURCE_CODE "\
<So this is the part of the main control module of this program, which has\n\
<currently around the ô10 000 linesõ. When game was developed on MS-Dos\n\
<platform, the ôBorland C++ v3.1õ was chosen as the programming language.\n\
<Of course, source actually does not look like it is shown below. Here it\n\
<is just a little bit compressed, so more lines could fit into the screen.\n\
ôÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜõ\n\
if (but&&isininfo(x,y)){register WORD xx,yy;\n\
while (!releasebutton(but-1,&xx,&yy));hidemouse();\n\
if (xx!=x||yy!=y)WriteInfo(xx-(x-infox),yy-(y-infoy));\n\
showmouse();but=0;}\n\
but&=3;x=(x-xoff)/barsize;y=(y-yoff)/barsize;\n\
if (xold==0xffff){xold=x;yold=y;}\n\
if ((x!=xold||y!=yold)){\n\
if (xold<nx&&yold<ny&&sqpress(xold,yold)&&!sqopen(xold,yold)){\n\
sqpress(xold,yold)=NO;hidemouse();\n\
SetSquare(xold,yold,1);showmouse();}\n\
xold=x;yold=y;}if (x<nx&&y<ny&&!underinfo(x,y)){\n\
if (!but){mlstant=mrstant=0;\n\
(void)releasebutton(0,NULL,NULL);(void)releasebutton(1,NULL,NULL);}\n\
if ((but==2)&&!sqopen(x,y)&&mlstant!=but){mlstant=but;\n\
switch(((sqmark(x,y)+(!sqmark(x,y)&&!cmines?2:1))%3)){\n\
case 1:cmines--;sqmark(x,y)=1;break;\n\
case 2:if (sqmark(x,y)==1)cmines++;sqmark(x,y)=2;break;\n\
default:sqmark(x,y)=0;break;}hidemouse();SetSquare(x,y,1);showmouse();}\n\
else{if (but==1&&!sqopen(x,y)&&!sqpress(x,y)&&sqmark(x,y)!=1){\n\
sqpress(x,y)=YES; hidemouse();SetSquare(x,y,0);showmouse();}\n\
else{if (!but&&!sqopen(x,y)&&sqpress(x,y)&&sqmark(x,y)!=1){\n\
if (value(x,y)==MINE)break;hidemouse();OpenSquare(x,y);showmouse();\n\
if (infosafe==NULL)ShowInfo();}else{\n\
if (but==3&&sqopen(x,y)&&mrstant!=but){mrstant=but;\n\
if (OpenNearSquares(x,y)==YES)break;\n\
}}}}}}HideInfo();(void)releasebutton(0,NULL,NULL);\n\
ôßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßõ\n"
#endif

#define MINBARSIZE    (8)
#define MAXBARSIZE    (18)
#define DEFDIFF        (1)
#define DIFFOFFSET    (13)
#define DIFFPOINT    (3)    /* !!! DIFFOFFSET+DIFFPOINT must equal 16 */
#define DEFNX        (30)                        /* default x size */
#define DEFNY        (25)                        /* default y size */
#define INFOXSIZE    (textwidth(infostr3[0])+10)
#define INFOYSIZE    (textheight(infostr3[0])*INFOLINES+(itabsize+1)*6)
#define INFOLINES    (14)
#define DEFITABSIZE    (0)
#define FADESTEPS    (100)

#if PSQUARE_DYNAMIC_ALLOCATION
#  define MAXNX        ((getmaxx()+1)/MINBARSIZE)    /* MAXIMUM x size */
#  define MAXNY        ((getmaxy()+1)/MINBARSIZE)    /* MAXIMUM y size */
#else
#  define MAXNX        (80)    /* MAXIMUM x size */
#  define MAXNY        (60)    /* MAXIMUM y size */
#endif

#define I_BCKCOLOR    BLACK
#define I_RCTCOLOR    LIGHTGRAY
#define I_TXTCOLOR    LIGHTGREEN
#define I_NUMCOLOR    YELLOW
#define H_DEFCOLOR    LIGHTGREEN
#define H_INSCOLOR    YELLOW

#define isinbar(x,y,x1,y1,x2,y2)    (x>=x1&&x<=x2&&y>=y1&&y<=y2)
#define isinnormbutton(x,y,xx,yy)    (isinbar(x,y,xx-47,yy-1,xx+47,yy+19))
#define isinnumbutton(x,y,xx,yy) \
    (isinbar(x,y,xx-47,yy-1,xx-20,yy+19)?(isinbar(x,y,xx-47,yy+13,xx-37,yy+17)?3:1): \
     isinbar(x,y,xx+20,yy-1,xx+47,yy+19)?(isinbar(x,y,xx+37,yy+13,xx+47,yy+17)?4:2):0)
#define isininfo(x,y)   isinbar(x,y,infox,infoy,infox+INFOXSIZE,infoy+INFOYSIZE)
#define underinfo(x,y)  (isininfo(xoff+x*barsize,yoff+y*barsize) \
        ||isininfo(xoff-1+(x+1)*barsize,yoff+y*barsize) \
        ||isininfo(xoff-1+(x+1)*barsize,yoff-1+(y+1)*barsize) \
        ||isininfo(xoff+x*barsize,yoff-1+(y+1)*barsize))
#define HideInfo()    WriteInfo(0xffff,0xffff)
#define ShowInfo()    WriteInfo(infox,infoy)
#if PLATON_SYSTEM_WIN32 || PLATON_SYSTEM_X11
#  define FadeIn()        (void)kbhit()
#  define FadeOut()        (void)kbhit()
#else
#  define FadeIn()    fade_in(FADESTEPS)
#  define FadeOut()    fade_out(FADESTEPS)
#endif

#define YES 1
#define NO  0
#define MINE 255-'0'    /* So that when it prints, it prints char 0xff */
#define getmines(__nx,__ny,__diff) \
(max(1,((WORD)(((long)(__nx)*(long)(__ny)*(long)(DIFFOFFSET+(__diff)*DIFFPOINT))/100))))

    /* INCLUDE */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#if ASSERTION_USAGE
#  include <assert.h>
#endif

#include <system.h>

#if PLATON_SYSTEM_SVGALIB || PLATON_SYSTEM_X11
#  include <sys/times.h>
#  include <dos2linux.h>
#  define CLOCK_FNC        times(NULL)
#  define CLOCK_DIV        sysconf(_SC_CLK_TCK)
#endif

#if PLATON_SYSTEM_MSDOS || PLATON_SYSTEM_WIN32
#  include <conio.h>
#  include <dos.h>
#  define CLOCK_FNC        clock()
#  define CLOCK_DIV        CLOCKS_PER_SEC
#endif

#if PLATON_SYSTEM_WIN32
#  include <dos2win32.h>
#  include <winbgim.h>
#endif

#if PLATON_SYSTEM_MSDOS
#  include <alloc.h>
#endif

#include <typedef.h>
#include <standart.h>
#include <my-graph.h>
#include <mouse.h>
#include <menu.h>

/* #include "data.h" FOR MINES IMAGE */
#include "hiscore.h"

#if PLATON_SYSTEM_MSDOS || PLATON_SYSTEM_WIN32
#  define RAND_INT(__lo, __hi)    (__lo + random(__hi - __lo + 1))
#endif

#if PLATON_SYSTEM_SVGALIB || PLATON_SYSTEM_X11
#  define RAND_INT(__lo, __hi)    (__lo + (random() % (__hi - __lo + 1)))
#endif

typedef struct stsquare
{
    BYTE value;         /* Number of mines in the surround squares */
    BYTE sqopen;        /* Square is open */
    BYTE sqpress;       /* Square is pressed */
    BYTE sqmark;        /* Square is marked */
} STSQUARE;

enum desktop_operation
{
    DESKTOP_SAVE    = 0,
    DESKTOP_RESTORE = 1
};

/* /////////////////////////////////////////////////////////////////////// */
/* GLOBAL IDENTIFICATORS */
#if PLATON_SYSTEM_MSDOS
extern unsigned _stklen = 65000U;
#endif
#if PSQUARE_DYNAMIC_ALLOCATION
STSQUARE *psquare;
#else
STSQUARE psquare[MAXNX * MAXNY];
#endif
/* All unneccessary question marks will be removed. */
#if LANGUAGE == LANG_SLOVAK
char infostr1[]="Super Mines v????????? - (c) 1999 Condy software inc.",
    infostr2[]="Ondrej Jomb¡k - Gymn zium Bil¡kova 24 - Okt va C - 1998/99",
    *infostr3[]={"       "," MINES ","","   x   ","","  Cas  "," :  :  ","","  M¡n  ","--   --","","EscMenu","F1Pomoc","F4Pauza"};
char*yesnostr[]={"Ano","Nie",NULL};
#else
char infostr1[]="Super Mines v????????? by Ondrej Jombik <nepto@platon.sk>",
    infostr2[]="Copyright (c) 2001-2004 Platon SDG, http://platon.sk/",
    *infostr3[]={"       "," MINES ","","   x   ",""," Time  "," :  :  ",""," Mines ","--   --","","EscExit","F1Help ","F4Pause"};
char*yesnostr[]={"Yes","No",NULL};
#endif
BYTE barsize,                /* pixels by square */
    diff=DEFDIFF,
    itabsize=DEFITABSIZE,    /* Info Tab Size */
    nx=DEFNX,                /* Number of squares in X */
    ny=DEFNY;
void*infosafe=NULL;
WORD xoff,                    /* Offset of first pixel X */
    yoff,
    infox=30,infoy=30,
    cmines,                    /* Mines UN-discovered */
    sqclosed;                /* Squares still closed */
/* GAME ENDS IF cmines==0 AND sqclosed==0 */
char gastxt[]="\
ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ\n\r\
Ý                                   Þ\n\r\
Ý   N'=NSvt/6V | p'=-p | p'-p=2p    Þ\n\r\
Ý    p=N'(p'-p)=2pN'=NSmtvý/3V     Þ\n\r\
Ý    F=p/t=NSmtvý/3Vt=NSmvý/3V     Þ\n\r\
Ý     p=F/S=NSmvý/3VS=Nmvý/3V       Þ\n\r\
Ý      pV=Nmvý/3 | v=û(3kT/m)       Þ\n\r\
Ý       pV=NkT | n=m/M=N/Nø         Þ\n\r\
Ý         pV=nkNøT | R=kNø          Þ\n\r\
Ý        pV=nRT | p'V'=nRT'         Þ\n\r\
Ý          nR=pV/T=p'V'/T'          Þ\n\r\
Ý            constðpV/T             Þ\n\r\
Ý     constðp ÷> izobar_process     Þ\n\r\
Ý     constðV ÷> izochor_process    Þ\n\r\
Ý     constðT ÷> izoterm_process    Þ\n\r\
Ý (p+a/Vý)(V-b)=RT ÷> Van_der_Waals Þ\n\r\
Ý                                   Þ\n\r\
ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß";

#if ASSERTION_USAGE
BYTE value(int x, int y)   { assert(x>=0&&y>=0&&x<nx&&y<ny); return (psquare+(x)*ny+(y))->value;   }
BYTE sqopen(int x, int y)  { assert(x>=0&&y>=0&&x<nx&&y<ny); return (psquare+(x)*ny+(y))->sqopen;  }
BYTE sqpress(int x, int y) { assert(x>=0&&y>=0&&x<nx&&y<ny); return (psquare+(x)*ny+(y))->sqpress; }
BYTE sqmark(int x, int y)  { assert(x>=0&&y>=0&&x<nx&&y<ny); return (psquare+(x)*ny+(y))->sqmark;  }
void set_value(int x, int y, BYTE a)   { assert(x>=0&&y>=0&&x<nx&&y<ny); (psquare+(x)*ny+(y))->value   = a; }
void set_sqopen(int x, int y, BYTE a)  { assert(x>=0&&y>=0&&x<nx&&y<ny); (psquare+(x)*ny+(y))->sqopen  = a; }
void set_sqpress(int x, int y, BYTE a) { assert(x>=0&&y>=0&&x<nx&&y<ny); (psquare+(x)*ny+(y))->sqpress = a; }
void set_sqmark(int x, int y, BYTE a)  { assert(x>=0&&y>=0&&x<nx&&y<ny); (psquare+(x)*ny+(y))->sqmark  = a; }
#else
#  define value(x, y)            ((psquare + (x) * ny + (y))->value      )
#  define sqopen(x, y)            ((psquare + (x) * ny + (y))->sqopen     )
#  define sqpress(x, y)            ((psquare + (x) * ny + (y))->sqpress    )
#  define sqmark(x, y)            ((psquare + (x) * ny + (y))->sqmark     )
#  define set_value(x, y, a)    ((psquare + (x) * ny + (y))->value   = a)
#  define set_sqopen(x, y, a)    ((psquare + (x) * ny + (y))->sqopen  = a)
#  define set_sqpress(x, y, a)    ((psquare + (x) * ny + (y))->sqpress = a)
#  define set_sqmark(x, y, a)    ((psquare + (x) * ny + (y))->sqmark  = a)
#endif

/* /////////////////////////////////////////////////////////////////////// */
/* FUNCTIONS DECLARATION */
int brkfnc(void);
void koniec(void);
void WriteError(void);

BYTE MainMenu(void);
int GraphInit(void);
void SetData(void);
void SetMines();
void SetExcludeMines(int ex, int ey);
void SetSquare(WORD x,WORD y,BYTE status);
void WriteInfo(int x, int y);
BYTE DoAll(void);
void Help(void);
void ShowHelpText(WORD x,WORD y,WORD linesize,WORD defcolor,WORD inscolor,char*helpstr);
void OpenSquare(WORD x,WORD y);
WORD OpenNearSquares(WORD x,WORD y);

void DrawDiffButton(WORD x,WORD y,BYTE diff,BYTE label);
void DrawDefWindow(WORD sizex,WORD y1,WORD y2,char*text);
void DrawWindow(WORD x1,WORD y1,WORD x2,WORD y2,BYTE bckcolor,BYTE rctcolor);
void DrawNormButton(WORD x,WORD y,char*label,char*str,BYTE bckcolor,BYTE rctcolor,BYTE txtcolor);
void DrawNumButton(WORD x,WORD y,char*label,WORD num,BYTE bckcolor,BYTE rctcolor,BYTE txtcolor);
void DrawNumPlus10(WORD x,WORD y,BYTE c);
BYTE YesNo();
BYTE ColorConvert(BYTE value);
void fade_out(WORD steps);
void fade_in(WORD steps);
void desktop_save_or_restore(enum desktop_operation op);

/* High scores handling */
void HscTable(void);
clock_t time2clock(struct time time);

/* strplus.h extract */
char *strdel(char *s);

/* /////////////////////////////////////////////////////////////////////// */
/* MAIN */
int main(int argc, char **argv)
{
    register WORD k;
    gotoxy(1,25);
    textattr(0x07);
    for (k=0;k<80;k++)
        putch('_'); /* putch('Ä'); */
    putch('\n');
    setcbrk(1);
    ctrlbrk(brkfnc);
    atexit(koniec);
#if 0
#if PLATON_SYSTEM_MSDOS
    if (argc>1) {
        puts(ERR_ARGC);
        return 1;
    }
    {
        char exename[]=EXENAME;
        if (strcmpi(exename,argv[0]+strlen(argv[0])-strlen(exename))) {
            printf("\n%s %s\n",ERR_EXEC,strupr(exename));
            return 1;
        }
    }
#endif
#endif
    if (!initmouse()) {
        puts(ERR_MOUSE);
        return 1;
    }
#if PLATON_SYSTEM_MSDOS
    argc = argc; /* just to prevent warning */
    hiscore_init(argv[0], HISCORE_AUTODETECT);
#elif PLATON_SYSTEM_WIN32
    hiscore_init("c:\\windows\\mines.hsc", 0L);
#elif PLATON_SYSTEM_SVGALIB || PLATON_SYSTEM_X11
    hiscore_init("/var/lib/games/mines/hiscore.dat", 0L);
#else
#  error hiscore not initialized
#endif
    if (GraphInit() < 0)
        return 1;
    strncpy(strchr(infostr1,'?'),__APPVERSION__,strlen(__APPVERSION__));
    while (strchr(infostr1,'?')!=NULL)
        strdel(strchr(infostr1,'?'));
    while (1) {
        switch (MainMenu()) {
            case 0:
                do {
                    SetData();
                    SetMines();
                } while (DoAll());
#if PSQUARE_DYNAMIC_ALLOCATION
#  if ASSERTION_USAGE
                assert(psquare != NULL)
#  endif
                    free(psquare);
                psquare = NULL;
#endif
                if (infosafe != NULL) {
                    free(infosafe);
                    infosafe = NULL;
                }
                break;
            case 2:
                HscTable();
                break;
            case 3:
                Help();
                break;
            case 4:
                return 0;
        }
    }
    /* never reached */
}

/* ////////////////////////////////////////////////////////////////////// */
/* FUNCTIONS DEFINITIONS */
/*************************************************************************
 *                                                                       *
 *                           F U N C T I O N S                           *
 *                                                                       *
 *************************************************************************/
int brkfnc(void) /* {{{ */
{
    gotoxy(1,1);
    return(1);
} /* }}} */

void koniec(void) /* {{{ */
{
    my_graph_close();
    hiscore_close();
    fcloseall();
    endstring("MINES");
#if (LANGUAGE == LANG_ENGLISH)
    epilogue();
#else
    randomize();
    switch (RAND_INT(0, 3)) {
        case 0:
            textattr(0x03);
            cputs(gastxt);
            break;
        default:
            textattr(LIGHTMAGENTA);cputs("\n\r  e-mail");
            textattr(128+LIGHTMAGENTA);cputs(":");
            textattr(WHITE);
            cputs("   Jombik@pobox.sk");

            textattr(LIGHTMAGENTA);cputs("\n\r  homepage");
            textattr(128+LIGHTMAGENTA);cputs(":");
            textattr(WHITE);
            cputs(" http://Jombik.w3.to");

            if (!RAND_INT(0, 2)) {
                textattr(0x02);
                cputs("\n\n\n\rSo doN'T foRgeT To ViSit ouR inCreDibLe _talker_ ");
                textattr(WHITE);
                cputs("telnet://atlantis.sk:7000\n");
            }
            else{
                textattr(LIGHTMAGENTA);cputs("\n\r  talker");
                textattr(128+LIGHTMAGENTA);cputs(":");
                textattr(WHITE);
                cputs("   telnet://atlantis.sk:7000");
            }

            textattr(GREEN);cputs("\n\n\rThis is an ");
            textattr(LIGHTCYAN);cputs("eXtreme & precizion ");
            textattr(LIGHTGREEN);cputs("Neptun ");
            textattr(GREEN);cputs("software production.");

            textattr(GREEN);cputs("\n\rEspecially thanx 2 ");
            textattr(LIGHTCYAN);cputs("neverending ");
            textattr(LIGHTGREEN);cputs("Wolcaan ");
            textattr(GREEN);cputs("bug reporting.");
            break;
    }
    textattr(0x07);cputs("\n\r");
#endif
} /* }}} */

void WriteError(void) /* {{{ */
{
    my_graph_close();
    puts(ERR_WRITE);
    exit(1);
} /* }}} */

/*----------------------------------------------------------------------*/
BYTE MainMenu(void) /* {{{ */
{
    register BYTE but;
    WORD x,y;
#if (LANGUAGE == LANG_ENGLISH)
    char*menustr[]={"New game","Settings","Hall of fame","Information","Quit to OS",NULL};
    char*itabstr[]={"Normal","High","Very high"};
    char*infostr[]={"Systematically analyzed,","psychically transformed", "and as well as programmed by:","Ondrej Jombik"};
#else
    char*menustr[]={"Nov  Hra","Nastavenie","Tabulka najleps¡ch","Inform cie","Odchod do DOSu",NULL};
    char*itabstr[]={"Norm lna","Velk ","Velmi velk "};
    char*infostr[]={"Systematicky analyzoval,","psychicky transformoval", "a v konecnom d“sledku naprogramoval:","Ondrej Jomb¡k"};
#endif
    FadeOut();
    hidemouse();
    DrawWindow(0,0,getmaxx(),getmaxy(),BLACK,DARKGRAY);
    DrawWindow(140,50,getmaxx()-140,110,RED,GREEN);
    setcolor(LIGHTGREEN);settextstyle(0,0,4);
    outtextxy(getmaxx()/2+2,82,"M I N E S");
    DrawWindow(40,410,getmaxx()-40,440,DARKGRAY,LIGHTGRAY);
    setcolor(WHITE);settextstyle(0,0,1);
    outtextxy(getmaxx()/2,420,infostr1);
    outtextxy(getmaxx()/2,432,infostr2);
    rangex(111,getmaxx()-111);
    rangey(196,324);
    DrawDefWindow(420,195,325,NULL);
    showmouse();
    FadeIn();
    while (1) {
        hidemouse();
        DrawDefWindow(420,195,325,NULL);
        showmouse();
        switch (but=menu(menustr,getmaxx()/2,205,0,2,24,BLACK,WHITE)) {
            case 4: /* Quit to DOS */
                hidemouse();
                DrawDefWindow(420,195,325,menustr[but]);
                showmouse();
                if (menu(yesnostr,getmaxx()/2,256,0,2,25,RED,LIGHTGREEN))
                    break;
            case 0: /* Start game */
            case 2: /* Hall of fame */
                rangex(0,getmaxx());
                rangey(0,getmaxy());
                FadeOut();
                return(but);
            case 1:
                hidemouse();
                DrawDefWindow( 420, 195, 325, menustr[but]);
                DrawNumButton( 190, 254, STR_PLAYGROUND_WIDTH,  nx, GREEN, BLUE, WHITE);
                DrawNumButton( 190, 296, STR_PLAYGROUND_HEIGHT, ny, GREEN, BLUE, WHITE);
                DrawDiffButton(320, 254, diff,1);
                DrawNormButton(320, 296, STR_INFO_TABLE, itabstr[itabsize], BLUE, ColorConvert(itabsize+2), WHITE);
                DrawNormButton(450, 254, "", STR_RESET, RED, WHITE, WHITE);
                DrawNormButton(450, 296, "", STR_OK,    RED, WHITE, WHITE);
                showmouse();
                while (!(but=releasebutton(0,&x,&y))||!isinnormbutton(x,y,450,296)) {
                    if (kbhit()) /* catching characters */
                        getch(); /* in keyboard buffer  */
                    if (but) {
                        if (isinnormbutton(x,y,450,254) != 0) { /* Reset */
                            hidemouse();
                            nx = DEFNX;
                            ny = DEFNY;
                            itabsize = DEFITABSIZE;
                            diff     = DEFDIFF;
                            DrawNumButton( 190, 254, STR_PLAYGROUND_WIDTH,  nx, GREEN, BLUE, WHITE);
                            DrawNumButton( 190, 296, STR_PLAYGROUND_HEIGHT, ny, GREEN, BLUE, WHITE);
                            DrawNormButton(320, 296, STR_INFO_TABLE, itabstr[itabsize], BLUE, ColorConvert(itabsize+2), WHITE);
                            DrawDiffButton(320, 254, diff, 1);
                            showmouse();
                        }
                        if (isinnormbutton(x,y,320,296) != 0) { /* Info table */
                            itabsize++;
                            if (itabsize>2)
                                itabsize=0;
                            hidemouse();
                            DrawNormButton(320, 296, STR_INFO_TABLE,
                                    itabstr[itabsize], BLUE, ColorConvert(itabsize + 2), WHITE);
                            showmouse();
                        }
                        if ((but=isinnormbutton(x,y,320,254))!=0) {
                            diff++;
                            if (diff>3)
                                diff=0;
                            hidemouse();
                            DrawDiffButton(320,254,diff,1);
                            showmouse();
                        }
                        if ((but=isinnumbutton(x,y,190,254))!=0&&((but%2&&nx>1)||(!(but%2)&&nx<MAXNX))) {
                            switch (but) {
                                case 1:nx--;break;
                                case 2:nx++;break;
                                case 3:nx-=min(10,nx-1);break;
                                case 4:nx+=min(10,MAXNX-nx);break;
                            }
                            hidemouse();
                            DrawNumButton(190, 254, STR_PLAYGROUND_WIDTH, nx, GREEN, BLUE, WHITE);
                            showmouse();
                        }
                        if ((but=isinnumbutton(x,y,190,296))!=0&&((but%2&&ny>1)||(!(but%2)&&ny<MAXNY))) {
                            switch (but) {
                                case 1:ny--;break;
                                case 2:ny++;break;
                                case 3:ny-=min(10,ny-1);break;
                                case 4:ny+=min(10,MAXNY-ny);break;
                            }
                            hidemouse();
                            DrawNumButton(190, 296, STR_PLAYGROUND_HEIGHT, ny, GREEN, BLUE, WHITE);
                            showmouse();
                        }
                    }
                }
                break;
            case 3: /* Information */
                hidemouse();
                DrawDefWindow(420,195,325,menustr[but]);
                DrawNormButton(getmaxx() / 2 - 65, 297, "", STR_OK,        RED, WHITE, WHITE);
                DrawNormButton(getmaxx() / 2 + 65, 297, "", STR_MORE_INFO, RED, WHITE, WHITE);
                for (but=0;but<3;but++) {
                    setcolor(ColorConvert(but+2));
                    outtextxy(getmaxx()/2,242+but*11,infostr[but]);
                }
                setcolor(DARKGRAY);
                outtextxy(getmaxx()/2+2,281+2,infostr[3]);
                setcolor(LIGHTGRAY);
                outtextxy(getmaxx()/2+1,281+1,infostr[3]);
                setcolor(WHITE);
                outtextxy(getmaxx()/2,281,infostr[3]);
                showmouse();
                while (1) {
                    if (kbhit())getch();
                    if (releasebutton(0,&x,&y)) {
                        if (isinnormbutton(x,y,getmaxx()/2-65,297))
                            break;
                        if (isinnormbutton(x,y,getmaxx()/2+65,297)) {
                            rangex(0,getmaxx());
                            rangey(0,getmaxy());
                            FadeOut();
                            return(3);
                        }
                    }
                }
                break;
        };
    }
} /* }}} */

/*----------------------------------------------------------------------*/
int GraphInit(void) /* {{{ */
{
#if 0
    int gdriver=9,gmode=2,errorcode;
    if (set_egavga_bgi()!=1) {puts(ERR_WRITE);exit(1);}
    initgraph(&gdriver,&gmode,"");
    if ((errorcode=graphresult())!=grOk) {printf("\n%s %s\n",ERR_GRAPH,grapherrormsg(errorcode));exit(1);}
    remove("eGaVgA.bGI");
#endif
    if (my_graph_init(0) < 0) {
        return -1;
    }

    FadeOut();
    showmouse();
    /* !!! for whole game !!! */
    settextjustify(CENTER_TEXT, CENTER_TEXT);
    settextstyle(0,0,1);
    return 0;
} /* }}} */

/*----------------------------------------------------------------------*/
void SetData(void) /* {{{ */
{
    nx = min(nx,MAXNX);
    ny = min(ny,MAXNY);
    for (barsize = MAXBARSIZE; barsize >= MINBARSIZE; barsize--)
        if ((barsize*nx<=getmaxx()+1)&&(barsize*ny<=getmaxy()+1))
            break;

#if PSQUARE_DYNAMIC_ALLOCATION
    if ((psquare=(STSQUARE *)calloc(nx*ny,sizeof(STSQUARE))) == NULL) {
        my_graph_close();
        puts(ERR_MEMORY);
        exit(1);
    }
#endif
} /* }}} */

/*----------------------------------------------------------------------*/
void SetMines() /* {{{ */
{
    SetExcludeMines(-1, -1);
} /* }}} */

void SetExcludeMines(int ex, int ey) /* {{{ */
{
    STSQUARE *p;
    int i, x, y, a, b;

    randomize();
    cmines   = getmines(nx, ny, diff);
    sqclosed = (nx * ny) - cmines;
    p = psquare;
    for (i = nx *ny; i >0; i--, p++)
        p->value = p->sqopen = p->sqpress = p->sqmark = NO;

    i = getmines(nx, ny, diff);
    if (nx * ny - i < 1)
        ex = ey = -1; /* Disable exclusion if no empty field is available */
    for (i = i; i > 0; i--) {
        do {
            x = RAND_INT(0, nx - 1);
            y = RAND_INT(0, ny - 1);
        } while ((x == ex && y == ey) || value(x, y) == MINE);
        set_value(x, y, MINE);
    }
    for (x=nx-1;x>=0;x--) {
        for (y=ny-1;y>=0;y--) {
            if (value(x,y)==MINE)
                continue;
            a = x - 1;
            b = y - 1;
            i = 0;
            if (a>=0 && b>=0 && a<nx && b<ny) i += (value(a, b) == MINE); a++;
            if (a>=0 && b>=0 && a<nx && b<ny) i += (value(a, b) == MINE); a++;
            if (a>=0 && b>=0 && a<nx && b<ny) i += (value(a, b) == MINE); b++;
            if (a>=0 && b>=0 && a<nx && b<ny) i += (value(a, b) == MINE); a--; a--;
            if (a>=0 && b>=0 && a<nx && b<ny) i += (value(a, b) == MINE); b++;
            if (a>=0 && b>=0 && a<nx && b<ny) i += (value(a, b) == MINE); a++;
            if (a>=0 && b>=0 && a<nx && b<ny) i += (value(a, b) == MINE); a++;
            if (a>=0 && b>=0 && a<nx && b<ny) i += (value(a, b) == MINE);
            set_value(x, y, value(x, y) + i);
        }
    }
} /* }}} */

/*----------------------------------------------------------------------*/
/*   If status=1 then draw the square up, if it's 0 then draw it down */
void SetSquare(WORD x,WORD y,BYTE status) /* {{{ */
{
    WORD x1,x2,y1,y2;
    if (underinfo(x,y)&&infosafe!=NULL)
        HideInfo();
    x1=xoff+barsize*x;
    x2=x1+barsize-1;
    y1=yoff+barsize*y;
    y2=y1+barsize-1;
    setfillstyle(SOLID_FILL, LIGHTGRAY);
    bar(x1, y1, x2, y2);
    if (status) {
        setcolor(WHITE);
        line(x1,y1,x1,y2-1);
        line(x1,y1,x2-1,y1);
        setcolor(DARKGRAY);
        line(x2,y2,x1,y2);
        line(x2,y2,x2,y1);
        switch (sqmark(x,y)) {
            case 2 : setfillstyle(SOLID_FILL, LIGHTBLUE);
                     setcolor(LIGHTBLUE);
                     break;
            case 1 : setfillstyle(SOLID_FILL, LIGHTRED);
                     setcolor(LIGHTRED);
                     break;
            default: setcolor(LIGHTGRAY);
        }
        fillellipse(xoff+barsize*x+barsize/2, yoff+barsize*y+barsize/2, 3, 3);
        switch (sqmark(x,y)) {
            case 2 :
            case 1 : setfillstyle(SOLID_FILL, YELLOW);
                     setcolor(YELLOW);
                     fillellipse(xoff+barsize*x+barsize/2, yoff+barsize*y+barsize/2, 1, 1);
        }
    } else{
        setcolor(DARKGRAY);
        line(x1,y1,x1,y2);
        line(x1,y1,x2,y1);
    }
} /* }}} */

/*----------------------------------------------------------------------*/
/* this expect mouse turned on */
void WriteInfo(int x, int y) /* {{{ */
{
    register BYTE k;
    char txt[30];
    if (infosafe != NULL) {
        hidemouse();
        putimage(infox, infoy, infosafe, COPY_PUT);
        showmouse();
    }

    /* HideInfo() */
    if ((WORD) x == 0xffff && (WORD) y == 0xffff) {
        if (infosafe != NULL) {
            free(infosafe);
            infosafe = NULL;
        }
        return;
    }

    infox = max(0, min((int) x, getmaxx() - INFOXSIZE));
    infoy = max(0, min((int) y, getmaxy() - INFOYSIZE));
    if (infosafe == NULL) {
        if ((infosafe = malloc(imagesize(infox, infoy, infox + INFOXSIZE,
                            infoy + INFOYSIZE))) == NULL) {
            my_graph_close();
            puts(ERR_MEMORY);
            exit(1);
        }
    }
    hidemouse();
    getimage(infox, infoy, infox + INFOXSIZE, infoy + INFOYSIZE, infosafe);
    DrawWindow(infox, infoy, infox + INFOXSIZE, infoy + INFOYSIZE,
            I_BCKCOLOR, I_RCTCOLOR);

    for (k = 0; k < INFOLINES; k++) {
        setcolor(I_TXTCOLOR);
        moveto(infox + INFOXSIZE / 2, textheight(infostr3[0]) / 2
                + infoy + (k * textheight(infostr3[k])));
        outtext(infostr3[k]);
        switch (k) {
            case 3:  sprintf(txt, " %02u %02u ", nx, ny);    break;
            case 9:  sprintf(txt, "  %03u  ", cmines);       break;
            case 11: sprintf(txt, "%.3s    ", infostr3[k]);  break;
            case 12:
            case 13: sprintf(txt, "%.2s     ", infostr3[k]); break;
            default: txt[0] = EOS;
        }
        setcolor(I_NUMCOLOR);
        outtext(txt);
    }
    showmouse();
} /* }}} */

/*----------------------------------------------------------------------*/
/*   Here we do all the job */
BYTE DoAll(void) /* {{{ */
{
    WORD x,y,xold=0xffff,yold=0,mlstant=0,mrstant=0,cminesold=0;
    BYTE but = 0, first_click = 1;
    clock_t start, curr, clktmp;
    start = curr = CLOCK_FNC;

    xoff=(getmaxx()+1-nx*barsize)/2;
    yoff=(getmaxy()+1-ny*barsize)/2;
    hidemouse();
    cleardevice();
    setcolor(WHITE);
    settextstyle(0,0,1);
    if (yoff>textheight(infostr1)) {
        outtextxy(getmaxx()/2,yoff/2,infostr1);
        outtextxy(getmaxx()/2,getmaxy()-yoff/2,infostr2);
    }
    else if (yoff>textheight(infostr1)/2) {
        yoff=getmaxy()+1-ny*barsize;
        outtextxy(getmaxx()/2,yoff/2,infostr1);
    }
    for (x=0;x<nx;x++)
        for (y=0;y<ny;y++)
            SetSquare(x,y,1);
    showmouse();

    settextstyle(0,0,itabsize+1);
    ShowInfo();
    FadeIn();
    while (1) {
        if (kbhit()) {
            if ((but = getch()) == ESC) {
                (void)getmousepos(&x, &y);
                if (YesNo() == YES)
                    break;
            }
            if (!but) {
                switch (but = getch()) {
                    case 59: /* F1 */
                        clktmp = CLOCK_FNC;
                        hidemouse();
                        desktop_save_or_restore(DESKTOP_SAVE);
                        FadeOut();
                        showmouse();
                        Help();
                        hidemouse();
                        desktop_save_or_restore(DESKTOP_RESTORE);
                        showmouse();
                        start += CLOCK_FNC - clktmp;
                        break;
                    case 62: /* F4 */
                        clktmp = CLOCK_FNC;
                        hidemouse();
                        desktop_save_or_restore(DESKTOP_SAVE);
                        cleardevice();
                        DrawWindow(getmaxx() / 2 - 150, getmaxy() / 2 - 20,
                                getmaxx() / 2 + 150, getmaxy() / 2 + 20, 15, 0);
                        settextstyle(0, 0, 2);
                        outtextxy(getmaxx() / 2, getmaxy() / 2 - 6, STR_PAUSE);
                        settextstyle(0, 0, 1);
                        outtextxy(getmaxx() / 2, getmaxy() / 2 + 10, STR_CLICK_HERE);
                        showmouse();
                        while ((! releasebutton(0, &x, &y) || ! isinbar(x, y,
                                        getmaxx() / 2 - 150, getmaxy() / 2 - 20,
                                        getmaxx() / 2 + 150, getmaxy() / 2 + 20)))
                        {
                            while (kbhit())
                                getch();
                        }
                        hidemouse();
                        desktop_save_or_restore(DESKTOP_RESTORE);
                        showmouse();
                        start += CLOCK_FNC - clktmp;
                        break;
                }
            }
        }
        but = getmousepos(&x, &y);
        if (!but && !sqclosed && !cmines) {
            curr = CLOCK_FNC - start;
            break;
        } /* All mines discovered */
        if (cminesold != cmines) { /* Update Mines */
            char txt[30]=" ÛÛÛ ";
            if (cminesold>999) {
                txt[0]=txt[1];
                txt[4]=EOS;
            }
            cminesold=cmines;
            if (isininfo(x,y))
                hidemouse();
            setcolor(I_BCKCOLOR);
            outtextxy(infox+INFOXSIZE/2,textheight(infostr3[0])/2+infoy+(9*textheight(infostr3[0])),txt);
            sprintf(txt,"%03u",cmines);
            setcolor(I_NUMCOLOR);
            outtextxy(infox+INFOXSIZE/2,textheight(infostr3[0])/2+infoy+(9*textheight(infostr3[0])),txt);
            if (isininfo(x,y))
                showmouse();
        }
        if ((unsigned) (curr / CLOCK_DIV) != (unsigned) (CLOCK_FNC / CLOCK_DIV)) {
            /* Update Time */
            char txt[30] = "Û ÛÛ ÛÛ";
            curr = CLOCK_FNC;
            if (isininfo(x,y))
                hidemouse();
            setcolor(I_BCKCOLOR);
            moveto(infox + INFOXSIZE / 2, textheight(infostr3[0]) / 2
                    + infoy + (6 * textheight(infostr3[0])));
            outtext(txt);
            sprintf(txt,"%u %02u %02u",
                    (unsigned) (((curr - start) / CLOCK_DIV) / 60) / 60,
                    (unsigned) (((curr - start) / CLOCK_DIV) / 60) % 60,
                    (unsigned)  ((curr - start) / CLOCK_DIV) % 60);
            setcolor(I_NUMCOLOR);
            outtext(txt);
            if (isininfo(x,y))
                showmouse();
        }
        if (but && isininfo(x, y)) {
            register int diff_x, diff_y;
            WORD xx, yy;
            while (! releasebutton(but - 1, (WORD *) &xx, (WORD *) &yy))
                if (kbhit()) /* catching characters */
                    getch(); /* in keyboard buffer  */
            diff_x = xx - x;
            diff_y = yy - y;
            if (diff_x != 0 || diff_y != 0)
                WriteInfo((int) infox + diff_x, (int) infoy + diff_y);
            but = 0;
        }
        but &= 3;
        x = (x-xoff) / barsize;
        y = (y-yoff) / barsize;
        if (xold==0xffff) {
            xold=x;
            yold=y;
        }
        if ((x!=xold||y!=yold)) {
            /* Position change */
            if (xold<nx&&yold<ny&&sqpress(xold,yold)&&!sqopen(xold,yold)) {
                set_sqpress(xold, yold, NO);
                hidemouse();
                SetSquare(xold,yold,1);
                showmouse();
            }
            xold=x;
            yold=y;
        }
        if (x < nx && y < ny && ! underinfo(x, y)) {
            if (!but){
                mlstant=mrstant=0;
                (void)releasebutton(0,NULL,NULL);
                (void)releasebutton(1,NULL,NULL);
            }
            if (but == 2 && ! sqopen(x, y) && mlstant != but) {
                /* Right button pressed */
                mlstant=but;
                switch (((sqmark(x,y)+(!sqmark(x,y)&&!cmines?2:1))%3)) {
                    case 1:  cmines--; set_sqmark(x, y, 1); break;
                    case 2:  if (sqmark(x, y) == 1) cmines++; set_sqmark(x, y, 2); break;
                    default: set_sqmark(x, y, 0); break;
                }
                hidemouse();
                SetSquare(x,y,1);
                showmouse();
            } else if (but == 1 &&
                    ! sqopen(x, y) && ! sqpress(x, y) && sqmark(x, y) != 1) {
                /* Left button pressed and square not pressed */
                set_sqpress(x, y, YES);
                hidemouse();
                SetSquare(x,y,0);
                showmouse();
            } else if (but == 0 &&
                    ! sqopen(x, y) && sqpress(x, y) && sqmark(x, y) != 1) {
                if (first_click) {
                    if (value(x, y) == MINE)
                        SetExcludeMines(x, y);
                    first_click = 0;
                }
                /* Left button released; Open the square */
                if (value(x,y) == MINE) {
                    sqclosed = 0xffff;
                    break;
                }
                hidemouse();
                OpenSquare(x,y);
                showmouse();
                if (infosafe == NULL)
                    ShowInfo();
                /* previous info hide was done by Set Square */
            } else if (but == 3 && sqopen(x, y) && mrstant != but) {
                /* Open near squares */
                mrstant=but;
                HideInfo();
                if (OpenNearSquares(x,y)==YES)
                    break;
                ShowInfo();
            }
        }
    }
    HideInfo();
    (void)releasebutton(0,NULL,NULL);
    if (but!=ESC) { /* game end (not break) */
        if (sqclosed) { /* GAME LOST */
            settextstyle(0,0,1);
            hidemouse();
            for (x=0;x<nx;x++) {
                for (y=0;y<ny;y++) {
                    if (value(x,y)==MINE) {
                        setcolor(LIGHTRED);
                        outtextxy(xoff+barsize*x+barsize/2-1, yoff+barsize*y+barsize/2, "Û");
                        setcolor(BLACK);
                        outtextxy(xoff+barsize*x+barsize/2-1, yoff+barsize*y+barsize/2, "*");
                    }
                    else if (sqmark(x,y)==1) {
                        setcolor(YELLOW);
                        line(xoff + barsize * x,
                                yoff + barsize * y,
                                xoff + barsize * x + barsize - 1,
                                yoff + barsize * y + barsize - 1);
                        line(xoff + barsize * x,
                                yoff + barsize * y + barsize - 1,
                                xoff + barsize * x + barsize - 1,
                                yoff + barsize * y);
                    }
                }
            }
            showmouse();
            while (kbhit())
                (void) getch();
            while (! releasebutton(0, NULL, NULL) && ! kbhit());
            hidemouse();
            DrawDefWindow(500, 190, 290, STR_BAD_LUCK);
            outtextxy(getmaxx() / 2, 243, STR_PLAY_AGAIN);
            DrawNormButton(getmaxx() / 2 - 65, 262, "", STR_YES, GREEN, WHITE, WHITE);
            DrawNormButton(getmaxx() / 2 + 65, 262, "", STR_NO, RED, WHITE, WHITE);
            showmouse();
            while (kbhit())
                (void) getch();
            while (1) {
                if ((but = releasebutton(0, &x, &y)) != 0) {
                    if (isinnormbutton(x, y, getmaxx() / 2 - 65, 262)) {
                        FadeOut();
                        return 1;
                    }
                    if (isinnormbutton(x, y, getmaxx() / 2 + 65, 262))
                        return 0;
                }
                if (kbhit()) {
                    but = getch();
                    if (but == EOL) {
                        FadeOut();
                        return 1;
                    }
                    if (but == ESC)
                        return 0;
                }
            }
        } else { /* GAME WIN */
            register int k, items;
            HISCORE_ITEM item;
            char s[80];
            hidemouse();
            DrawDefWindow(500, 190, 290, STR_WELL_DONE);
            DrawNormButton(getmaxx() / 2, 262, "", STR_OK, RED, WHITE, WHITE);
            sprintf(s, STR_MINES_REPORT, getmines(nx, ny, diff), nx, ny,
                    (unsigned) ((curr / CLOCK_DIV) / 60) / 60,
                    (unsigned) ((curr / CLOCK_DIV) / 60) % 60,
                    (unsigned)  (curr / CLOCK_DIV) % 60);
            setcolor(LIGHTGREEN);outtextxy(getmaxx()/2,245,s);
            for (k=0; s[k]!=EOS; k++)
                if (!isdigit(s[k]))
                    s[k]=SPC;
            setcolor(RED);outtextxy(getmaxx()/2+1,245+1,s);
            setcolor(LIGHTRED);outtextxy(getmaxx()/2,245,s);
            showmouse();
            while (!(releasebutton(0,&x,&y))
                    ||!isinnormbutton(x,y,getmaxx()/2,262))
                if (kbhit())
                    getch();
            if ((items = hiscore_items()) >= 0) {
                for (k = 0; k <= min(items, HISCORE_MAX_ITEMS - 1); k++) {
                    if (k == items)
                        break;
                    if (hiscore_get_item(&item, k) < 0)
                        WriteError();
                    if (getmines(nx,ny,diff) > getmines(item.nx,item.ny,item.diff))
                        break;
                    if (getmines(nx,ny,diff) == getmines(item.nx,item.ny,item.diff)) {
                        if (diff > item.diff)
                            break;
                        if (diff == item.diff) {
                            if (curr < time2clock(item.time))
                                break;
                        }
                    }
                    if (k == HISCORE_MAX_ITEMS - 1) {
                        k = 0xff;
                        break;
                    }
                }
                if (k!=0xff) {
                    register BYTE count=0,c;
                    hidemouse();
                    DrawDefWindow(550, 207, 273, STR_ENTER_YOUR_NAME);
                    memset(item.name,EOS,HISCORE_NAME_LEN+1);
                    while (((c=getch())!=EOL)||(!strlen(item.name))) {
                        setcolor(BLUE);outtextxy(getmaxx()/2,257,item.name);
                        switch (c) {
                            case EOL:break;
                            case NUL:if (getch()!=DELETE)break;
                            case BS:if (count) {count--;item.name[count]=EOS;}
                                        break;
                            default:if (c>=0x20&&c<0xff) /* better than isprint(c) */
                                        if (count < HISCORE_NAME_LEN) {
                                            item.name[count] = c;
                                            count++;
                                        }
                                    break;
                        }
                        setcolor(k>2?LIGHTCYAN:ColorConvert(4-k));outtextxy(getmaxx()/2,257,item.name);
                    }
                    showmouse();
                    item.nx   = nx;
                    item.ny   = ny;
                    item.diff = diff;
                    getdate(&item.date);
                    item.time.ti_hour = (unsigned) ((curr / CLOCK_DIV) / 60) / 60;
                    item.time.ti_min  = (unsigned) ((curr / CLOCK_DIV) / 60) % 60;
                    item.time.ti_sec  = (unsigned)  (curr / CLOCK_DIV) % 60;
                    if (hiscore_set_item(&item, k) < 0)
                        WriteError();
                    HscTable();
                    FadeOut();
                }
            }
        }
    }
    return 0;
} /* }}} */

/*----------------------------------------------------------------------*/
void Help(void) /* {{{ */
{
    WORD x,y;
    do {
        char helptext[] = STR_LONG_HELP_TEXT;
        FadeOut();
        hidemouse();
        cleardevice();
        DrawDefWindow(getmaxx()-30,15,getmaxy()-15,STR_HELP);
        DrawNormButton(getmaxx()/2,getmaxy()-93,"",STR_OK,RED,WHITE,WHITE);
        DrawNormButton(40+50,getmaxy()-93,STR_OTHER_PROGRAMS,"Pexeso",BLUE,H_DEFCOLOR,H_INSCOLOR);
        DrawNormButton(40+75,getmaxy()-78,"","ImageEdit",BLUE,H_DEFCOLOR,H_INSCOLOR);
        DrawNormButton(40+100,getmaxy()-63,"","2D / 3D",BLUE,H_DEFCOLOR,H_INSCOLOR);
        DrawNormButton(40+125,getmaxy()-48,"","...",BLUE,H_DEFCOLOR,H_INSCOLOR);
        DrawWindow(getmaxx()/2-49,getmaxy()-48,getmaxx()-40,getmaxy()-33,MAGENTA,LIGHTCYAN);
        setcolor(WHITE);
        outtextxy((getmaxx()/2-49+getmaxx()-40)/2,getmaxy()-40, STR_SOURCE_EXAMPLE_2);
        ShowHelpText(40,70,12,H_DEFCOLOR,H_INSCOLOR,helptext);
        showmouse();
        FadeIn();
        while (1) {
            if (kbhit())
                if (getch()==EOL); /* break; */
            if (releasebutton(0,&x,&y)) {
                if (isinnormbutton(x,y,40+50,getmaxy()-93)||
                        isinnormbutton(x,y,40+75,getmaxy()-78)||
                        isinnormbutton(x,y,40+100,getmaxy()-63)||
                        isinnormbutton(x,y,40+125,getmaxy()-48)){
                    void*safe;
                    static WORD fontcolor=2;
                    char other_programs_txt[] = STR_LONG_OTHER_PROGRAMS;
                    hidemouse();
                    if ((safe=malloc(imagesize(229,374,getmaxx()-9,getmaxy()-9)))==NULL)exit(1);
                    getimage(229,374,getmaxx()-9,getmaxy()-9,safe);
                    DrawWindow(229,374,getmaxx()-9,getmaxy()-9,BLUE,WHITE);
                    DrawNormButton((getmaxx()+229)/2,getmaxy()-38,"",STR_BACK,GREEN,WHITE,WHITE);
                    ShowHelpText(280, 392, 15, 11 + (fontcolor++) % 3,
                            WHITE, other_programs_txt);
                    showmouse();
                    while (!(releasebutton(0,&x,&y))
                            ||!isinnormbutton(x,y,(getmaxx()+229)/2,getmaxy()-38))
                        if (kbhit())
                            getch();
                    hidemouse();
                    putimage(229, 374, safe, COPY_PUT);
                    showmouse();
#if ASSERTION_USAGE
                    assert(safe != NULL);
#endif
                    free(safe);
                    x = y = 0;
                }
                if (isinnormbutton(x,y,getmaxx()/2,getmaxy()-93)) {
                    x=y=0xffff;
                    break;
                }
                if (isinbar(x,y,getmaxx()/2-49,getmaxy()-48,getmaxx()-40,getmaxy()-33)) {
                    char zdrojtext[] = STR_LONG_SOURCE_CODE;
                    FadeOut();
                    hidemouse();
                    DrawDefWindow(getmaxx(),0,getmaxy(),STR_SOURCE_EXAMPLE);
                    DrawNormButton(getmaxx()/2,getmaxy()-31,"",STR_OK,RED,WHITE,WHITE);
                    ShowHelpText(30,52,12,LIGHTGREEN,LIGHTCYAN,zdrojtext);
                    showmouse();
                    FadeIn();
                    while (!(releasebutton(0,&x,&y))
                            ||!isinnormbutton(x,y,getmaxx()/2,getmaxy()-31))
                        if (kbhit())
                            getch();
                    break;
                }
            }
        }
    } while (x != 0xffff || y != 0xffff);
} /* }}} */

/*----------------------------------------------------------------------*/
void ShowHelpText(WORD x,WORD y,WORD linesize,WORD defcolor,WORD inscolor,char*helpstr) /* {{{ */
{
    register BYTE count=0;
    register WORD posx;
    char*tmpbegin,*tmpend = NULL,*endline;
    settextstyle(0,0,1);
    while ((endline=strchr(helpstr,'\n'))!=NULL) {
        *(endline)=EOS;
        switch (helpstr[0]) {
            case'<':posx=x;settextjustify(LEFT_TEXT,CENTER_TEXT);strdel(helpstr);break;
            case'>':posx=getmaxx()-x;settextjustify(RIGHT_TEXT,CENTER_TEXT);strdel(helpstr);break;
            default:posx=getmaxx()/2;settextjustify(CENTER_TEXT,CENTER_TEXT);break;
        }
        if ((tmpbegin=strchr(helpstr,'ô'))!=NULL&&(tmpbegin<strchr(helpstr,EOS))) {
            if (*(tmpbegin+1)=='ô')tmpbegin=NULL;
            else{
                strdel(tmpbegin);
                strdel(tmpend=strchr(helpstr,'õ'));
                tmpend-=1;
            }
        }
        else tmpbegin=tmpend=NULL;
        setcolor(defcolor);
        if (strlen(helpstr))outtextxy(posx,y+count*linesize,helpstr);
        if (tmpbegin!=NULL) {
            char*tmpstr=helpstr;
            while (*helpstr!=EOS) {
                if ((helpstr<tmpbegin)||(helpstr>tmpend))*(helpstr)=SPC;
                helpstr++;
            }
            setcolor(inscolor);
            outtextxy(posx,y+count*linesize,tmpstr);
        }
        helpstr=endline+1;
        count++;
    }
    settextjustify(CENTER_TEXT,CENTER_TEXT);
} /* }}} */

/*----------------------------------------------------------------------*/
/* !!! mouse must be turned off when entering function */
void OpenSquare(WORD x, WORD y) /* {{{ */
{
    char num[2]="0";
    register int a,b;

    settextstyle(0,0,1);
    set_sqopen(x, y, YES);
    sqclosed--;
    if ((num[0]=value(x,y)) != 0) {
        setcolor(ColorConvert(num[0]));
        num[0]+='0';
        outtextxy(barsize/2+min(getmaxx()-textwidth(num),xoff+barsize*x),
                1+barsize/2+min(getmaxy()-textheight(num),yoff+barsize*y),num);
    }
    else{               /* Open near squares if the current number is 0 */
        a=x-1;
        b=y-1;
        if (a>=0 && b>=0 && a<nx && b<ny && !sqopen(a,b) && sqmark(a,b)!=1) {
            SetSquare(a,b,0);
            OpenSquare(a,b);
        }
        a++;
        if (a>=0 && b>=0 && a<nx && b<ny && !sqopen(a,b) && sqmark(a,b)!=1) {
            SetSquare(a,b,0);
            OpenSquare(a,b);
        }
        a++;
        if (a>=0 && b>=0 && a<nx && b<ny && !sqopen(a,b) && sqmark(a,b)!=1) {
            SetSquare(a,b,0);
            OpenSquare(a,b);
        }
        b++;
        if (a>=0 && b>=0 && a<nx && b<ny && !sqopen(a,b) && sqmark(a,b)!=1) {
            SetSquare(a,b,0);
            OpenSquare(a,b);
        }
        a-=2;
        if (a>=0 && b>=0 && a<nx && b<ny && !sqopen(a,b) && sqmark(a,b)!=1) {
            SetSquare(a,b,0);
            OpenSquare(a,b);
        }
        b++;
        if (a>=0 && b>=0 && a<nx && b<ny && !sqopen(a,b) && sqmark(a,b)!=1) {
            SetSquare(a,b,0);
            OpenSquare(a,b);
        }
        a++;
        if (a>=0 && b>=0 && a<nx && b<ny && !sqopen(a,b) && sqmark(a,b)!=1) {
            SetSquare(a,b,0);
            OpenSquare(a,b);
        }
        a++;
        if (a>=0 && b>=0 && a<nx && b<ny && !sqopen(a,b) && sqmark(a,b)!=1) {
            SetSquare(a,b,0);
            OpenSquare(a,b);
        }
    }
    settextstyle(0,0,itabsize+1);
} /* }}} */

/*----------------------------------------------------------------------*/
/* Open the sorrounded squares. Returns != 0 if I activated a mine */
WORD  OpenNearSquares(WORD x,WORD y) /* {{{ */
{
    register int a,b;
    register WORD suma=0;

    a=x-1;
    b=y-1;
    if (a>=0 && b>=0 && a<nx && b<ny && sqmark(a,b)==1)
        suma++;
    a++;
    if (a>=0 && b>=0 && a<nx && b<ny && sqmark(a,b)==1)
        suma++;
    a++;
    if (a>=0 && b>=0 && a<nx && b<ny && sqmark(a,b)==1)
        suma++;
    b++;
    if (a>=0 && b>=0 && a<nx && b<ny && sqmark(a,b)==1)
        suma++;
    a-=2;
    if (a>=0 && b>=0 && a<nx && b<ny && sqmark(a,b)==1)
        suma++;
    b++;
    if (a>=0 && b>=0 && a<nx && b<ny && sqmark(a,b)==1)
        suma++;
    a++;
    if (a>=0 && b>=0 && a<nx && b<ny && sqmark(a,b)==1)
        suma++;
    a++;
    if (a>=0 && b>=0 && a<nx && b<ny && sqmark(a,b)==1)
        suma++;
    if (suma == value(x,y)) {
        suma=0;
        a=x-1;
        b=y-1;
        hidemouse();
        if (a>=0 && b>=0 && a<nx && b<ny && !sqopen(a,b) && sqmark(a,b)!=1) {
            suma|=(value(a,b)==MINE);
            SetSquare(a,b,0);
            OpenSquare(a,b);
        }
        a++;
        if (a>=0 && b>=0 && a<nx && b<ny && !sqopen(a,b) && sqmark(a,b)!=1) {
            suma|=(value(a,b)==MINE);
            SetSquare(a,b,0);
            OpenSquare(a,b);
        }
        a++;
        if (a>=0 && b>=0 && a<nx && b<ny && !sqopen(a,b) && sqmark(a,b)!=1) {
            suma|=(value(a,b)==MINE);
            SetSquare(a,b,0);
            OpenSquare(a,b);
        }
        b++;
        if (a>=0 && b>=0 && a<nx && b<ny && !sqopen(a,b) && sqmark(a,b)!=1) {
            suma|=(value(a,b)==MINE);
            SetSquare(a,b,0);
            OpenSquare(a,b);
        }
        a-=2;
        if (a>=0 && b>=0 && a<nx && b<ny && !sqopen(a,b) && sqmark(a,b)!=1) {
            suma|=(value(a,b)==MINE);
            SetSquare(a,b,0);
            OpenSquare(a,b);
        }
        b++;
        if (a>=0 && b>=0 && a<nx && b<ny && !sqopen(a,b) && sqmark(a,b)!=1) {
            suma|=(value(a,b)==MINE);
            SetSquare(a,b,0);
            OpenSquare(a,b);
        }
        a++;
        if (a>=0 && b>=0 && a<nx && b<ny && !sqopen(a,b) && sqmark(a,b)!=1) {
            suma|=(value(a,b)==MINE);
            SetSquare(a,b,0);
            OpenSquare(a,b);
        }
        a++;
        if (a>=0 && b>=0 && a<nx && b<ny && !sqopen(a,b) && sqmark(a,b)!=1) {
            suma|=(value(a,b)==MINE);
            SetSquare(a,b,0);
            OpenSquare(a,b);
        }
        showmouse();
        return(suma);
    }
    else
        return 0;
} /* }}} */

/*----------------------------------------------------------------------*/
void DrawDiffButton(WORD x,WORD y,BYTE diff,BYTE label) /* {{{ */
{
#if LANGUAGE == LANG_SLOVAK
    char*diffstr[]={"Lahk ","Norm lna","Tazk ","Velmi tazk "};
#else
    char*diffstr[]={"Easy","Normal","Difficult","Extrem"};
#endif
    DrawNormButton(x, y, label ? STR_DIFFICULTY : "", diffstr[diff],
            BLUE, ! diff ? CYAN : ColorConvert(diff + 1), WHITE);
} /* }}} */

void DrawDefWindow(WORD sizex,WORD y1,WORD y2,char*text) /* {{{ */
{
    DrawWindow((getmaxx()-sizex)/2,y1,getmaxx()-(getmaxx()-sizex)/2,y2,BLUE,WHITE);
    if (text!=NULL) {
        line((getmaxx()-sizex)/2+10,y1+33,getmaxx()-10-(getmaxx()-sizex)/2,y1+33);
        settextstyle(0, 0, 2);
        outtextxy(getmaxx() / 2, y1 + 19,text);
    }
} /* }}} */

void DrawWindow(WORD x1,WORD y1,WORD x2,WORD y2,BYTE bckcolor,BYTE rctcolor) /* {{{ */
{
    setfillstyle(1,bckcolor);setcolor(rctcolor);
    bar(x1,y1,x2,y2);
    rectangle(x1+1,y1+1,x2-1,y2-1);
} /* }}} */

void DrawNormButton(WORD x,WORD y,char*label,char*str,BYTE bckcolor,BYTE rctcolor,BYTE txtcolor) /* {{{ */
{
    DrawWindow(x-49,y,x+49,y+18,bckcolor,rctcolor);
    settextstyle(0,0,1);
    outtextxy(x,y+10,str);
    setcolor(txtcolor);
    outtextxy(x,y-7,label);
} /* }}} */

void DrawNumButton(WORD x,WORD y,char*label,WORD num,BYTE bckcolor,BYTE rctcolor,BYTE txtcolor) /* {{{ */
{
    char str[4];
    DrawWindow(x-49,y,x+49,y+18,bckcolor,rctcolor);
    DrawWindow(x-49,y-1,x-20,y+19,rctcolor,bckcolor);
    DrawWindow(x+20,y-1,x+49,y+19,rctcolor,bckcolor);
    settextstyle(0,0,1);
    sprintf(str,"%u",num);
    setcolor(rctcolor);
    outtextxy(x,y+10,str);
    setcolor(txtcolor);
    outtextxy(x,y-7,label);
    settextstyle(0,0,2);
    outtextxy(x-34,y+11,"-");
    outtextxy(x+36,y+11,"+");
    DrawNumPlus10(x-46,y+14,'-');
    DrawNumPlus10(x+38,y+14,'+');
} /* }}} */

void DrawNumPlus10(WORD x,WORD y,BYTE c) /* {{{ */
{
    switch (c) {
        case '+':line(x+1,y,x+1,y+2);
        case '-':line(x,y+1,x+2,y+1);
                 line(x+4,y,x+4,y+2);
                 rectangle(x+6,y,x+8,y+2);
                 break;
    }
} /* }}} */

BYTE YesNo() /* {{{ */
{
    void*safe;
    register BYTE ret;
    hidemouse();
    HideInfo();
    if ((safe = malloc(imagesize(0, 195, getmaxx(), 325))) == NULL)
        desktop_save_or_restore(DESKTOP_SAVE);
    getimage(0, 195, getmaxx(), 325, safe);
    DrawDefWindow(420, 195, 325, STR_END_GAME);
    showmouse();
    ret = menu(yesnostr, getmaxx() / 2, 256, 0, 2, 25, RED, LIGHTGREEN);
    settextstyle(0, 0, 1);
    hidemouse();
    if (safe == NULL) {
        desktop_save_or_restore(DESKTOP_RESTORE);
    } else {
        putimage(0, 195, safe, COPY_PUT);
        free(safe);
    }
    ShowInfo();
    showmouse();
    return ret ? NO : YES;
} /* }}} */

BYTE YesNoOld(int x,int y) /* {{{ */
{
    void*safe;
    register BYTE ret;
    x=max(0,min(x,getmaxx()-56));
    y=max(0,min(y,getmaxy()-40));
    hidemouse();
    if ((safe=malloc(imagesize(x,y,x+56,y+40)))==NULL)exit(1);
    getimage(x,y,x+56,y+40,safe);
    DrawWindow(x,y,x+56,y+40,BLUE,WHITE);
    showmouse();
    ret=menu(yesnostr,x+28,y+5,0,2,17,RED,LIGHTGREEN);
    hidemouse();
    putimage(x, y, safe, COPY_PUT);
    showmouse();
#if ASSERTION_USAGE
    assert(safe != NULL);
#endif
    free(safe);
    return ret ? NO : YES;
} /* }}} */

BYTE ColorConvert(BYTE c) /* {{{ */
{
    switch (c) {
        case 1: return LIGHTBLUE;
        case 2: return LIGHTGREEN;
        case 3: return YELLOW;
        case 4: return LIGHTRED;
        default: return LIGHTMAGENTA;
    }
} /* }}} */

void fade_out(WORD steps) /* {{{ */
{
    register WORD k,l;
    int size;
    struct palettetype start_pal, curr_pal;
    getpalette(&start_pal);
    size = start_pal.size;
    curr_pal.size = size;
    for (l = 0; l < steps; l++) {
        for (k = 0; k < size; k++) {
            curr_pal.colors[k] = start_pal.colors[k] * (steps - l - 1) / steps;
        }
        setallpalette(&curr_pal);
    }
} /* }}} */

void fade_in(WORD steps) /* {{{ */
{
    register WORD k, l;
    int size = getdefaultpalette()->size;
    struct palettetype curr_pal;
    curr_pal.size = size;
    for (l = 0; l < steps; l++) {
        for (k = 0; k < size; k++) {
            curr_pal.colors[k] = getdefaultpalette()->colors[k] * (l + 1) / steps;
        }
        setallpalette(&curr_pal);
    }
} /* }}} */

void desktop_save_or_restore(enum desktop_operation op) /* {{{ */
{
    static void *buffer  = NULL;
    static FILE *fhandle = NULL;
    static int   bufsize = 0;
    static int   y_size  = 0;
    register int i;
    if (op == DESKTOP_SAVE) {
        if (buffer != NULL) {
            free(buffer);
            buffer = NULL;
        }
        if (fhandle != NULL) {
            fclose(fhandle);
            fhandle = NULL;
        }
        for (y_size = getmaxy() + 1; ; y_size = (y_size / 2) + 1) {
            bufsize = imagesize(0, 0, getmaxx(), y_size - 1);
            if ((buffer = malloc(bufsize)) != NULL)
                break;
#if PLATON_SYSTEM_X11
            /* Desktop save/restore disk swapping/storage mechanism does not
               properly work with X11 pixmaps due to known issues (see notes
               nead getimage()/putimage in x11-bgi.c file). Thus if we failed
               to allocate 8 bytes size buffer, we exit immidiatelly. */
            WriteError();
#endif
        }
        if (y_size <= getmaxy()) {
            if ((fhandle = tmpfile()) == NULL)
                WriteError();
        }
        for (i = 0; i <= getmaxy(); i += y_size) {
#if 0
            fprintf(stderr, "getimage(0, %d, %d, %d, %p);\n",
                    i, getmaxx(), min(getmaxy(), i + y_size - 1), buffer);
#endif
            getimage(0, i, getmaxx(), min(getmaxy(), i + y_size - 1), buffer);
            if (i + y_size < getmaxy()) {
                if (fwrite(buffer, bufsize, 1, fhandle) != 1)
                    WriteError();
            }
        }
    } else if (op == DESKTOP_RESTORE) {
        if (fhandle != NULL)
            rewind(fhandle);
        for (i = 0; i < getmaxy() + 1 - y_size; i += y_size)
            ;
#if 0
        fprintf(stderr, "putimage(0, %d, %p, COPY_PUT);\n", i, buffer);
#endif
        putimage(0, i, buffer, COPY_PUT);
        for (i -= y_size; i >= 0; i -= y_size) {
            if (fread(buffer, bufsize, 1, fhandle) != 1)
                WriteError();
            putimage(0, i, buffer, COPY_PUT);
        }
        if (buffer != NULL) {
            free(buffer);
            buffer = NULL;
        }
        if (fhandle != NULL) {
            fclose(fhandle);
            fhandle = NULL;
        }
    }
} /* }}} */

/* /////////////////////////////////////////////// */
void HscTable(void) /* {{{ */
{
    register BYTE k,l;
    WORD x,y;
    HISCORE_ITEM item;
    char s[80];
    hidemouse();
    DrawDefWindow(getmaxx(), 0, getmaxy(), STR_HALL_OF_FAME);
    for (k=0;k<min(hiscore_items(),HISCORE_MAX_ITEMS);k++) {
        if (hiscore_get_item(&item,k) < 0)
            WriteError();
        /* LINE */
        setcolor(WHITE);
        if (k)
            line(25,39+k*40,getmaxx()-25,39+k*40);
        /* NAME */
        settextjustify(LEFT_TEXT,TOP_TEXT);
        settextstyle(0,0,2);
        sprintf(s,"%2d. %s",k+1,item.name);
        setcolor(k>2?LIGHTCYAN:ColorConvert(4-k));
        outtextxy(10,47+k*40,s);
        /* STATUS */
        settextstyle(0,0,1);
        sprintf(s, STR_HSC_ENTRY,
                getmines(item.nx,item.ny,item.diff),item.nx,item.ny,
                item.time.ti_hour,item.time.ti_min,item.time.ti_sec,
                item.date.da_day,item.date.da_mon,item.date.da_year);
        setcolor(k>2?LIGHTCYAN:ColorConvert(4-k));
        outtextxy(75,66+k*40,s);
        for (l=0; s[l]!=EOS; l++)
            if (!isdigit(s[l]))
                s[l]=SPC;
        setcolor(WHITE);
        outtextxy(75,66+k*40,s);
        /* DIFF ICON */
        settextjustify(CENTER_TEXT,CENTER_TEXT);
        DrawDiffButton(566,51+k*40,item.diff,k?0:1);
    }
    DrawNormButton(getmaxx() / 2, getmaxy() - 31, "", STR_OK, RED, WHITE, WHITE);
    showmouse();
    FadeIn();
    while (!(releasebutton(0,&x,&y))
            ||!isinnormbutton(x,y,getmaxx()/2,getmaxy()-31))
        if (kbhit())
            getch();
} /* }}} */

clock_t time2clock(struct time time) /* {{{ */
{
    return CLOCK_DIV *
        (long)((long)time.ti_sec+(long)time.ti_min*60+(long)time.ti_hour*3600);
} /* }}} */

/* strplus.c extract */
char * strdel(char *s) /* {{{ */
{
#if 1
    return (char *) memmove(s, s + 1, strlen(s));
#else
    register int i;

    for (i = 0; s[i] != '\0'; i++)
        s[i] = s[i + 1];

    return s;
#endif
} /* }}} */

/* Modeline for ViM {{{
 * vim: set ts=4:
 * vim600: fdm=marker fdl=0 fdc=0:
 * }}} */


Platon Group <platon@platon.org> http://platon.org/
Copyright © 2002-2006 Platon Group
Site powered by Metafox CMS
Go to Top