kolibrios-gitea/programs/games/mine/trunk/mine.c--
Kirill Lipatov (Leency) 11771c85cf fixed small bug in changing MineSweeper's window mode
git-svn-id: svn://kolibrios.org@963 a494cfbc-eb01-0410-851d-a64ba20cac60
2008-12-16 19:29:41 +00:00

496 lines
12 KiB
Plaintext

/*******************************************************************************
MenuetOS MineSweeper
Copyright (C) 2003, 2004 Ivan Poddubny
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*******************************************************************************/
? pragma option LST // generate ASM listing file - ñîçäàòü àññåìáëåðíûé ëèñòèíã
? warning TRUE // âêëþ÷èòü ðåæèì âûâîäà ïðåäóïðåæäåíèé
? jumptomain NONE
? include "kos_sys.h--" // MenuetOS system functions - ñèñòåìíûå ôóíêöèè MenuetOS
//? define DEBUG 1
? print "\nÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿"
? print "\n³ MenuetOS MineSweeper v0.4 ³"
? print "\n³ (C) Ivan Poddubny (ivan-yar@bk.ru) 2003,2004 ³"
? print "\nÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ\n\n"
/************************************** DATA **************************************/
? define XPX 16 // X pixels by square - ðàçìåð êëåòêè â ïèêñåëÿõ
? define YPX 16 // Y pixels by square
? define MINE 255 // â êëåòêå ìèíà, åñëè value = MINE
struct
{
byte value; // number of mines - êîëè÷åñòâî ìèí â îêðóæàþùèõ êëåòêàõ
byte open; // square is open - êëåòêà îòêðûòà
byte press; // reserved - çàðåçåðâèðîâàíî
byte mark; // square is marked - êëåòêà ïîìå÷åíà
} massiv[30*30];
struct
{
byte a_inc;
byte b_inc;
} matrix[8] = {-1,-1,1,0,1,0,0,1,-2,0,0,1,1,0,1,0};
struct
{
byte x_size;
byte y_size;
byte nmines;
} stdmodes[3] = {9,9,10, 16,16,40, 30,16,99}; // {x,y,m}
int XST, // offset of first pixel X - ñìåùåíèå ïîëÿ îò ãðàíèöû îêíà
YST,
ncx, // number of squares in X - ðàçìåð ïîëÿ
ncy,
cmines, // mines discovered - êîëè÷åñòâî íåîòêðûòûõ ìèí
initmines, // number of initial mines - èçíà÷àëüíîå êîëè÷åñòâî ìèí
sqclosed; // squares still closed - êîëè÷åñòâî çàêðûòûõ êëåòîê
dword xpos = 100, // window coordinates - êîîðäèíàòû îêíà
ypos = 100,
xsize, // window size
ysize;
byte stop_game = FALSE, // game stopped - ïðèçíàê êîíöà èãðû
mouse_en = TRUE, // mouse enabled - ìûøü
mode = 3, // ðåæèì èãðû 1-íîâè÷îê 2-ëþáèòåëü 3-ýêñïåðò (0 îñîáûé)
mouse_status,
firstmine;
ProcessInfo procinfo;
SystemColors colors;
/************************************** CODE **************************************/
inline void fastcall mouse_enable()
{
$mov eax,40
$mov ebx,100111b
$int 0x40
}
inline void fastcall mouse_disable()
{
$mov eax,40
$mov ebx,000111b
$int 0x40
}
# include "timer.h--" // timer functions
# include "draw.h--" // drawing functions
# include "access.h--" // get & set functions
# include "random.h--" // random number generator
//? include "uf.h--" // user field window
void init()
// Èíèöèàëèçàöèÿ
{
XST = 10; YST = 52; // FIELD POSITION IN WINDOW
ECX = mode;
IF (ECX != 0)
{
//ncx = stdmodes[ECX-1].x_size;
//ncy = stdmodes[ECX-1].y_size;
//cmines = initmines = stdmodes[ECX-1].nmines;
EBX = #stdmodes;
ECX--; ECX *= 3;
EBX += ECX;
ncx = DSBYTE[EBX]; EBX++;
ncy = DSBYTE[EBX]; EBX++;
cmines = initmines = DSBYTE[EBX];
}
xsize = ncx * XPX + XST + XST;
ysize = ncy * YPX + YST + XST;
} // init
void clear_all()
// Î÷èñòèòü ïîëå
{
EAX = 0;
EDI = #massiv;
ECX = ncx * ncy;
$REP $STOSD
} // clear_all
void new_game()
// Íîâàÿ èãðà
{
init(); // èíèöèàëèçàöèÿ
randomize(); // ãåíåðàòîð ñëó÷àéíûõ ÷èñåë
clear_all(); // î÷èñòèòü ïîëå
firstmine = TRUE; // èãðà íå íà÷àòà
mouse_en = TRUE; // ìûøü ðàçðåøåíà
stop_game = FALSE; // èãðà íå çàêîí÷åíà
stop_timer();
time = 0; // âðåìÿ = 0
} // new_game
void set_mines(int nminas, no_x, no_y)
// Ðàññòàâèòü ìèíû
{
int i, x, y, a, b;
#ifdef DEBUG
sys_debug_write_string("MINE: set_mines called\n");
#endif
sqclosed = ncx * ncy - nminas; // êîëè÷åñòâî ÍÅîòêðûòûõ êëåòîê = ïëîùàäü ïîëÿ - êîë-âî ìèí
FOR (i = nminas; i > 0; i--) // ðàññòàâèòü ìèíû
{
x = random(ncx);
y = random(ncy);
WHILE ((get_value(x, y) == MINE) || ((x == no_x) && (y == no_y)))
{
x = random(ncx);
y = random(ncy);
}
set_value(x, y, MINE);
}
for (x = ncx-1; x >= 0; x--) // ðàññòàâèòü öèôðû
{
for (y = ncy-1; y >= 0; y--)
{
IF (get_value(x, y) == MINE)
continue;
EDX = x * ncy + y*4 + #massiv;
a = x; b = y;
FOR (i = 0; i < 8; i++)
{
AL = matrix[i].a_inc;
$movsx eax,al
a += EAX;
AL = matrix[i].b_inc;
$movsx eax,al
b += EAX;
IF ((a >= 0) && (b >= 0) && (a < ncx) && (b < ncy) && (get_value(a, b) == MINE))
DSBYTE[EDX]++;
}
}
}
} // set_mines
inline void do_mouse(void)
// Îáðàáîò÷èê ìûøè
{
int x,y;
EAX = sys_read_mouse(2); // ìûøü íå íàæàòà -> âûõîä
IF (EAX == 0)
{
// sys_debug_write_string("Strange\n");
return;
}
mouse_status = AL;
EAX = sys_read_mouse(1); // ìûøü âíå ïîëÿ -> âûõîä
EBX = EAX; EAX >>= 16; EBX &= 0xffff;
ECX = ncx * XPX + XST - 1;
EDX = ncy * YPX + YST - 1;
IF ((EAX < XST) || (EBX < YST) || (EAX > ECX) || (EBX > EDX)) return;
EAX -= XST; EAX /= XPX; x = EAX; // âû÷èñëèòü x è y
EBX -= YST; EBX /= YPX; y = EBX;
IF ((mouse_status == 1) && (!get_open(x, y)) && (get_mark(x, y) != 1))
{
// íà íåîòêðûòîé êëåòêå áåç ôëàæêà íàæàòà ëåâàÿ êíîïêà ìûøè
// left mouse button is pressed
IF (firstmine == TRUE)
{
firstmine = FALSE;
set_mines(initmines, x, y);
start_timer();
time = 1;
draw_time();
}
IF (get_value(x, y) == MINE)
{
end_game();
return;
}
open_square(x, y);
}
else IF ((mouse_status == 2) && (!get_open(x, y)))
{
// íà íåîòêðûòîé êëåòêå íàæàòà ïðàâàÿ êíîïêà ìûøè
// right mouse button is pressed
EBX = get_mark(x, y); EBX++;
EBX = EBX%3;
SWITCH (EBX)
{
CASE 2: cmines++; BREAK;
CASE 1: cmines--;
}
set_mark(x, y, EBX);
draw_minesi();
draw_square(x, y);
return;
}
ELSE IF ((mouse_status == 3) && (get_open(x, y)))
{
// íà îòêðûòîé êëåòêå íàæàòû îáå êíîïêè ìûøè
// both mouse buttons are pressed
IF (open_near_squares(x, y) == TRUE)
end_game();
}
IF (sqclosed == 0)
{
// îòêðûòû âñå êëåòêè
// all squares are opened
mouse_en = FALSE; // çàïðåòèòü ìûøü
stop_timer();
stop_game = TRUE; // èãðà çàâåðøåíà
// ïîñòàâèòü íåðàññòàâëåííûå ìèíû
FOR (x = 0; x < ncx; x++)
FOR (y = 0; y < ncy; y++)
IF ((get_value(x, y) == MINE) && (get_mark(x, y) != 1))
{
set_mark(x, y, 1);
cmines--;
draw_square(x, y);
}
draw_minesi();
}
} // do_mouse
void open_square(int x, y)
// Îòêðûòü êëåòêó
{
int a, b, i;
#ifdef DEBUG
sys_debug_write_string("MINE: open_square called\n");
#endif
set_open(x, y, TRUE);
sqclosed--;
IF (get_value(x, y) != 0)
{
draw_square(x, y);
}
else
{
draw_square(x, y);
a = x; b = y;
FOR (i = 0; i < 8; i++)
{
//a += matrix[i].a_inc;
//b += matrix[i].b_inc;
AL = matrix[i].a_inc;
$movsx eax,al
a += EAX;
AL = matrix[i].b_inc;
$movsx eax,al
b += EAX;
IF ((a >= 0) && (b >= 0) && (a < ncx) && (b < ncy) && (!get_open(a, b)) && (get_mark(a, b) != 1))
open_square(a, b);
}
}
} // open_square
int open_near_squares(int x, y)
// Îòêðûòü áëèçëåæàùèå êëåòêè (îáå êíîïêè ìûøè âìåñòå)
{
int a, b, i;
dword suma = 0;
#ifdef DEBUG
sys_debug_write_string("MINE: open_near_squares called\n");
#endif
a = x;
b = y;
FOR (i = 0; i < 8; i++)
{
//a+=matrix[i].a_inc;
//b+=matrix[i].b_inc;
AL = matrix[i].a_inc;
$movsx eax,al
a += EAX;
AL = matrix[i].b_inc;
$movsx eax,al
b += EAX;
IF ((a >= 0) && (b >= 0) && (a < ncx) && (b < ncy) && (get_mark(a, b) == 1))
suma++;
}
if (suma == get_value(x, y))
{
suma = 0;
a = x;
b = y;
for (i = 0; i < 8; i++)
{
//a+=matrix[i].a_inc;
//b+=matrix[i].b_inc;
AL = matrix[i].a_inc;
$movsx eax,al
a += EAX;
AL = matrix[i].b_inc;
$movsx eax,al
b += EAX;
IF ((a >= 0) && (b >= 0) && (a < ncx) && (b < ncy) && (!get_open(a, b)) && (get_mark(a, b) != 1))
{
IF (get_value(a, b) == MINE)
suma = 1;
open_square(a, b);
}
}
RETURN suma;
}
ELSE
RETURN 0;
} // open_near_squares
void end_game()
{
int x,y;
#ifdef DEBUG
sys_debug_write_string("MINE: end_game called\n");
#endif
stop_game = TRUE;
stop_timer();
for (x=0; x<ncx; x++)
{
for (y=0; y<ncy; y++)
{
IF (get_value(x, y) == MINE)
{
set_mark(x, y, FALSE); // ñíÿòü ôëàã
open_square(x, y);
}
ELSE IF (get_mark(x, y) == 1) // åñëè ìèíû íåò, à ôëàæîê åñòü
{
EBX = XPX * x + XST; // x left
ECX = EBX + XPX - 1; // x right
EBX <<= 16; EBX += ECX;
$PUSH EBX
ECX = YPX * y + YST; // y top
$PUSH ECX
EDX = ECX + YPX - 1; // y bottom
ECX <<= 16; ECX += EDX;
sys_draw_line(EBX, ECX, clBlack);
$POP EDX
ECX = EDX + YPX - 1;
ECX <<= 16; ECX += EDX;
$POP EBX
sys_draw_line(EBX, ECX, clBlack);
CONTINUE;
}
}
}
} // end_game
void main()
{
new_game();
draw_window();
mouse_enable();
while()
{
switch (sys_wait_event_timeout(100)) // wait for 1 second
{
case evReDraw:
draw_window();
continue;
case evKey:
IF (sys_get_key() == 27)
sys_exit_process();
continue;
case evButton:
EAX = sys_get_button_id();
IF (EAX == 911) // new game
{
new_game();
draw_squares();
draw_time();
draw_minesi();
}
ELSE IF (EAX == 1001) // change mode
{
// mode++; mode%=3; mode++;
EAX = mode; EAX++; EAX = EAX%3; EAX++; mode = AL;
new_game();
window_move_size(OLD,OLD,xsize,ysize);
CONTINUE;
}
// ELSE IF (EAX == 1002)
// {
// start_uf();
// }
ELSE IF (EAX == 1) // close window
sys_exit_process();
CONTINUE;
case evMouse:
IF (!mouse_en) // is mouse enabled ?
CONTINUE;
do_mouse();
// wait for mouse release - æäàòü îòïóñêàíèÿ êíîïêè
WHILE (sys_read_mouse(2) == mouse_status)
{
check_timer();
sys_delay(3);
CONTINUE;
}
check_timer();
IF (stop_game) // disable mouse if game is stopped
mouse_en = FALSE;
CONTINUE;
}
check_timer();
sys_delay(2);
}
} // main