Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
31 halyavin 1
/*******************************************************************************
2
 
3
    MenuetOS MineSweeper
4
    Copyright (C) 2003  Ivan Poddubny
5
 
6
    This program 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 2 of the License, or
9
    (at your option) any later version.
10
 
11
    This program 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 this program; if not, write to the Free Software
18
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
 
20
*******************************************************************************/
21
 
22
//? pragma option LST    // generate ASM listing file - создать ассемблерный листинг
23
//? warning    TRUE      // включить режим вывода предупреждений
24
? pragma option meos
25
? jumptomain NONE
26
? include "msys.h--"   // MenuetOS system functions - системные функции MenuetOS
27
 
28
? print "\nЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї"
29
? print "\nі          MeOS MineSweeper v0.3          і"
30
? print "\nі (C) Ivan Poddubny (ivan-yar@bk.ru) 2003 і"
31
? print "\nАДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ\n\n"
32
 
33
/************************************** DATA **************************************/
34
 
35
? define XPX 16      // X pixels by square - размер клетки в пикселях
36
? define YPX 16      // Y pixels by square
37
? define MINE 255    // значение для мины в поле value
38
 
39
struct
40
{
41
  byte value;        // number of mines   - количество мин в окружающих клетках
42
  byte open;         // square is open    - клетка открыта
43
  byte press;        // reserved          - зарезервировано
44
  byte mark;         // square is marked  - клетка помечена
45
} massiv[30*30];
46
 
47
struct
48
{
49
  byte a_inc;
50
  byte b_inc;
51
} matrix[8] = {-1,-1,1,0,1,0,0,1,-2,0,0,1,1,0,1,0};
52
 
53
struct
54
{
55
  byte   x_size;
56
  byte   y_size;
57
  byte   nmines;
58
} stdmodes[3] = {9,9,10, 16,16,40, 30,16,99}; // {x,y,m}
59
 
60
int XST,             // offset of first pixel X - смещение поля от границы окна
61
    YST,
62
    ncx,             // number of squares in X  - размер пол
63
    ncy,
64
    cmines,          // mines discovered        - количество неоткрытых мин
65
    initmines,       // number of initial mines - изначальное количество мин
66
    sqclosed;        // squares still closed    - количество закрытых клеток
67
 
68
dword xpos = 100,    // window coordinates      - координаты окна
69
      ypos = 100,
70
      xsize,         // window size
71
      ysize;
72
 
73
byte stop_game = FALSE,   // game stopped - признак конца игры
74
     mouse_en = TRUE,     // mouse enabled   - мышь
75
     mode = 3,            // режим игры 1-новичок 2-любитель 3-эксперт (0 особый)
76
     mouse_status,
77
     firstmine;
78
 
79
ProcessInfo  procinfo;
80
SystemColors colors;
81
 
82
/************************************** CODE **************************************/
83
 
84
inline void fastcall mouse_enable()
85
{
86
  $mov eax,40
87
  $mov ebx,100111b
88
  $int 0x40
89
}
90
 
91
inline void fastcall mouse_disable()
92
{
93
  $mov eax,40
94
  $mov ebx,000111b
95
  $int 0x40
96
}
97
 
98
? include "timer.h--"  // timer functions
99
? include "draw.h--"   // drawing functions
100
? include "access.h--" // get & set functions
101
? include "random.h--" // random number generator
102
//? include "uf.h--"     // user field window
103
 
104
void init()
105
// Инициализаци
106
{
107
  XST = 10; YST = 52;      // FIELD POSITION IN WINDOW
108
 
109
  ECX = mode;
110
  IF (ECX != 0)
111
  {
112
    //ncx = stdmodes[ECX-1].x_size;
113
    //ncy = stdmodes[ECX-1].y_size;
114
    //cmines = initmines = stdmodes[ECX-1].nmines;
115
 
116
    EBX = #stdmodes;
117
    ECX--; ECX *= 3;
118
    EBX += ECX;
119
 
120
    ncx = DSBYTE[EBX]; EBX++;
121
    ncy = DSBYTE[EBX]; EBX++;
122
    cmines = initmines = DSBYTE[EBX];
123
  }
124
 
125
  xsize = ncx * XPX + XST + XST;
126
  ysize = ncy * YPX + YST + XST;
127
} // init
128
 
129
void clear_all()
130
// Очистить поле
131
{
132
  EAX = 0;
133
  EDI = #massiv;
134
  ECX = ncx * ncy;
135
  $REP $STOSD
136
} // clear_all
137
 
138
void new_game()
139
// Новая игра
140
{
141
  init();            // инициализаци
142
  randomize();       // генератор случайных чисел
143
  clear_all();       // очистить поле
144
 
145
  firstmine = TRUE;  // игра не начата
146
  mouse_en = TRUE;   // мышь разрешена
147
  stop_game = FALSE; // игра не закончена
148
  stop_timer();
149
  time = 0;          // время = 0
150
} // new_game
151
 
152
void set_mines(int nminas, no_x, no_y)
153
// Расставить мины
154
{
155
  int i, x, y, a, b;
156
 
157
  sqclosed = ncx * ncy - nminas;  // количество НЕоткрытых клеток = площадь поля - кол-во мин
158
 
159
  FOR (i = nminas; i > 0; i--)    // расставить мины
160
  {
161
    x = random(ncx); y = random(ncy);
162
    WHILE ((get_value(x, y) == MINE) || ((x == no_x) && (y == no_y)))
163
    {
164
      x = random(ncx);
165
      y = random(ncy);
166
    }
167
    set_value(x, y, MINE);
168
  }
169
 
170
  for (x = ncx-1; x >= 0; x--)    // расставить цифры
171
  {
172
    for (y = ncy-1; y >= 0; y--)
173
    {
174
      IF (get_value(x, y) == MINE)
175
        continue;
176
      EDX = x * ncy + y*4 + #massiv;
177
      a = x; b = y;
178
      FOR (i = 0; i < 8; i++)
179
      {
180
         AL = matrix[i].a_inc;
181
         $movsx eax,al
182
         a += EAX;
183
         AL = matrix[i].b_inc;
184
         $movsx eax,al
185
         b += EAX;
186
         IF ((a >= 0) && (b >= 0) && (a < ncx) && (b < ncy) && (get_value(a, b) == MINE))
187
           DSBYTE[EDX]++;
188
      }
189
    }
190
  }
191
}  // set_mines
192
 
193
inline void do_mouse(void)
194
// Обработчик мыши
195
{
196
  int x,y;
197
 
198
  EAX = sys_read_mouse(2);            // мышь не нажата -> выход
199
  IF (EAX == 0) return;
200
 
201
  mouse_status = AL;
202
 
203
  EAX = sys_read_mouse(1);            // мышь вне поля  -> выход
204
  EBX = EAX; EAX >>= 16; EBX &= 0xffff;
205
  ECX = ncx * XPX + XST - 1;
206
  EDX = ncy * YPX + YST - 1;
207
  IF ((EAX < XST) || (EBX < YST) || (EAX > ECX) || (EBX > EDX)) return;
208
 
209
  EAX -= XST; EAX /= XPX; x = EAX;    // вычислить x и y
210
  EBX -= YST; EBX /= YPX; y = EBX;
211
 
212
  IF ((mouse_status == 1) && (!get_open(x, y)) && (get_mark(x, y) != 1))
213
  {
214
    // на неоткрытой клетке без флажка нажата левая кнопка мыши
215
    // left mouse button is pressed
216
    IF (firstmine == TRUE)
217
    {
218
      firstmine = FALSE;
219
      set_mines(cmines, x, y);
220
      start_timer();
221
    }
222
    IF (get_value(x, y) == MINE)
223
    {
224
      end_game();
225
      return;
226
    }
227
    open_square(x, y);
228
  }
229
  else IF ((mouse_status == 2) && (!get_open(x, y)))
230
  {
231
    // на неоткрытой клетке нажата правая кнопка мыши
232
    // right mouse button is pressed
233
    EBX = get_mark(x, y); EBX++;
234
    EBX = EBX%3;
235
    SWITCH (EBX)
236
    {
237
      CASE 2: cmines++; BREAK;
238
      CASE 1: cmines--;
239
    }
240
 
241
    set_mark(x, y, EBX);
242
 
243
    draw_minesi();
244
    draw_square(x, y);
245
    return;
246
  }
247
  ELSE IF ((mouse_status == 3) && (get_open(x, y)))
248
  {
249
    // на открытой клетке нажаты обе кнопки мыши
250
    // both mouse buttons are pressed
251
    IF (open_near_squares(x, y) == TRUE)
252
      end_game();
253
  }
254
 
255
  if (sqclosed == 0)
256
  // открыты все клетки
257
  // all squares are opened
258
  {
259
    mouse_en   = FALSE;  // запретить мышь
260
    stop_timer();
261
    stop_game  = TRUE;   // игра завершена
262
 
263
    // поставить нерасставленные мины
264
    FOR (x = 0; x < ncx; x++)
265
      FOR (y = 0; y < ncy; y++)
266
        IF ((get_value(x, y) == MINE) && (get_mark(x, y) != 1))
267
        {
268
          set_mark(x, y, 1);
269
          cmines--;
270
          draw_square(x, y);
271
        }
272
    draw_minesi();
273
  }
274
}  // do_mouse
275
 
276
void open_square(int x, y)
277
// Открыть клетку
278
{
279
  int a, b, i;
280
 
281
  set_open(x, y, TRUE);
282
  sqclosed--;
283
 
284
  IF (get_value(x, y) != 0)
285
  {
286
    draw_square(x, y);
287
  }
288
  else
289
  {
290
    draw_square(x, y);
291
    a = x; b = y;
292
    FOR (i = 0; i < 8; i++)
293
    {
294
      //a += matrix[i].a_inc;
295
      //b += matrix[i].b_inc;
296
      AL = matrix[i].a_inc;
297
      $movsx eax,al
298
      a += EAX;
299
      AL = matrix[i].b_inc;
300
      $movsx eax,al
301
      b += EAX;
302
      IF ((a >= 0) && (b >= 0) && (a < ncx) && (b < ncy) && (!get_open(a, b)) && (get_mark(a, b) != 1))
303
        open_square(a, b);
304
    }
305
  }
306
}  // open_square
307
 
308
int open_near_squares(int x, y)
309
// Открыть близлежащие клетки (обе кнопки мыши вместе)
310
{
311
  int a, b, i;
312
  dword suma = 0;
313
 
314
  a = x;
315
  b = y;
316
  FOR (i = 0; i < 8; i++)
317
  {
318
    //a+=matrix[i].a_inc;
319
    //b+=matrix[i].b_inc;
320
    AL = matrix[i].a_inc;
321
    $movsx eax,al
322
    a += EAX;
323
    AL = matrix[i].b_inc;
324
    $movsx eax,al
325
    b += EAX;
326
    IF ((a >= 0) && (b >= 0) && (a < ncx) && (b < ncy) && (get_mark(a, b) == 1))
327
      suma++;
328
  }
329
 
330
  if (suma == get_value(x, y))
331
  {
332
    suma = 0;
333
    a = x;
334
    b = y;
335
    for (i = 0; i < 8; i++)
336
    {
337
      //a+=matrix[i].a_inc;
338
      //b+=matrix[i].b_inc;
339
      AL = matrix[i].a_inc;
340
      $movsx eax,al
341
      a += EAX;
342
      AL = matrix[i].b_inc;
343
      $movsx eax,al
344
      b += EAX;
345
      IF ((a >= 0) && (b >= 0) && (a < ncx) && (b < ncy) && (!get_open(a, b)) && (get_mark(a, b) != 1))
346
      {
347
        IF (get_value(a, b) == MINE)
348
          suma = 1;
349
        open_square(a, b);
350
      }
351
    }
352
    RETURN suma;
353
  }
354
  ELSE
355
    RETURN 0;
356
}  // open_near_squares
357
 
358
void end_game()
359
{
360
  int x,y;
361
 
362
  stop_game = TRUE;
363
  stop_timer();
364
  for (x=0; x
365
  {
366
    for (y=0; y
367
    {
368
      IF (get_value(x, y) == MINE)
369
      {
370
        set_mark(x, y, FALSE); // снять флаг
371
        open_square(x, y);
372
      }
373
      ELSE IF (get_mark(x, y) == 1)      // если мины нет, а флажок есть
374
      {
375
        EBX = XPX * x + XST;      // x left
376
        ECX = EBX + XPX - 1;      // x right
377
        EBX <<= 16; EBX += ECX;
378
        $PUSH EBX
379
 
380
        ECX = YPX * y + YST;      // y top
381
        $PUSH ECX
382
        EDX = ECX + YPX - 1;      // y bottom
383
        ECX <<= 16; ECX += EDX;
384
        sys_draw_line(EBX, ECX, clBlack);
385
 
386
        $POP EDX
387
        ECX = EDX + YPX - 1;
388
        ECX <<= 16; ECX += EDX;
389
        $POP EBX
390
        sys_draw_line(EBX, ECX, clBlack);
391
        CONTINUE;
392
      }
393
    }
394
  }
395
}  // end_game
396
 
397
 
398
void main()
399
{
400
  sys_delay(5);   // for old kernel only!
401
  new_game();
402
  draw_window();
403
 
404
  mouse_enable();
405
  while()
406
  {
407
    switch (sys_wait_event_timeout(100))  // wait for 1 second
408
    {
409
      CASE evReDraw:
410
        draw_window();
411
        continue;
412
 
413
      CASE evKey:
414
        IF (sys_get_key() == 27)
415
          sys_exit_process();
416
        continue;
417
 
418
      CASE evButton:
419
        EAX = sys_get_button_id();
420
        IF (EAX == 911)              // new game
421
        {
422
          new_game();
423
          draw_squares();
424
          draw_time();
425
          draw_minesi();
426
        }
427
        ELSE IF (EAX == 1001)        // change mode
428
        {
429
          // mode++; mode%=3; mode++;
430
          EAX = mode; EAX++; EAX = EAX%3; EAX++; mode = AL;
431
 
432
          // get window position - получить координаты окна
433
          sys_process_info(#procinfo, -1);
434
          xpos = procinfo.xstart;
435
          ypos = procinfo.ystart;
436
 
437
          // start a new process and terminate this one
438
          sys_create_thread(#main, ESP);
439
          sys_exit_process();
440
        }
441
        //ELSE IF (EAX == 1002)
442
        //{
443
        //  start_uf();
444
        //}
445
        ELSE IF (EAX == 1)           // close window
446
          sys_exit_process();
447
        CONTINUE;
448
 
449
      case evMouse:
450
        IF (!mouse_en) // is mouse enabled ?
451
          CONTINUE;
452
        do_mouse();
453
        // wait for mouse release - ждать отпускания кнопки
454
        WHILE (sys_read_mouse(2) == mouse_status)
455
        {
456
          check_timer();
457
          sys_delay(6);
458
          CONTINUE;
459
        }
460
        check_timer();
461
        IF (stop_game)      // disable mouse if game is stopped
462
          mouse_en = FALSE;
463
        CONTINUE;
464
    }
465
    check_timer();
466
    sys_delay(2);
467
  }
468
}  // main