e43ff53a29
git-svn-id: svn://kolibrios.org@1771 a494cfbc-eb01-0410-851d-a64ba20cac60
496 lines
12 KiB
Plaintext
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
|