/* Mines ver. 1.0 Copyright (C) 2001 Antonin Vecera email: antonin.vecera@gmail.com 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 */ #include #include #include #include #include "game.h" #include "push.h" #include "move.h" #include "win.h" #include "oops.h" #include "sign.h" #include "digit0.h" #include "digit1.h" #include "digit2.h" #include "digit3.h" #include "digit4.h" #include "digit5.h" #include "digit6.h" #include "digit7.h" #include "digit8.h" #include "digit9.h" #include "unknown.h" #include "empty0.h" #include "empty1.h" #include "empty2.h" #include "empty3.h" #include "empty4.h" #include "empty5.h" #include "empty6.h" #include "empty7.h" #include "empty8.h" #include "query.h" #include "mouse.h" #include "mark.h" #include "mined.h" #include "explosion.h" #include "fault.h" enum { FALSE = 0, TRUE = 1, CellBytes = 15 * 15 * 3, DigitBytes = 11 * 21 * 3, ButtonBytes = 25 * 25 * 3, INT_MAX = 0x7fffffff }; enum { Beginner, Advanced, Expert, Custom }; enum { Game, Push, Move, Win, Oops }; enum { Empty0 = 0, Empty1 = 1, Empty2 = 2, Empty3 = 3, Empty4 = 4, Empty5 = 5, Empty6 = 6, Empty7 = 7, Empty8 = 8, Query, MouseQuery, Mark, Fault, Mined, Explosion, Unknown }; typedef struct { int Mine, Picture, Neighbours; } FieldCell; struct { int MaxX, MaxY, Mines; } Settings[] = { {8, 8, 10}, {16, 16, 40}, {30, 16, 99}, {0, 0, 0} }; int MaxX, MaxY, Mines, Level, UnknownCell, Playing, MinesRemain, Time, Status, UseQuery = TRUE, UseColor = TRUE; Point Origin; Image *RGB000000, *RGB0000FF, *RGB007F00, *RGB7F7F7F, *RGBBFBFBF, *RGBFF0000, *RGBFFFF00, *RGBFFFFFF, *ImageButton[5], *ImageSign, *ImageDigit[10], *ImageCell[16]; FieldCell **MineField; void Pack(Point *p, Point p0, Point p1, Point p2, Point p3, Point p4, Point p5) { p[0] = p0; p[1] = p1; p[2] = p2; p[3] = p3; p[4] = p4; p[5] = p5; } void Button3d(Image *im, Rectangle r, int i, Image *color1, Image *color2, Image *color3, Point sp) { Point p[6]; if(i < 0){ r = insetrect(r, i); i = -i; } draw(im, Rect(r.min.x + i, r.min.y + i, r.max.x - i, r.max.y - i), color1, nil, Pt(sp.x + i, sp.y + i)); Pack(p, r.min, Pt(r.min.x, r.max.y), Pt(r.min.x + i, r.max.y - i), Pt(r.min.x + i, r.min.y + i), Pt(r.max.x - i, r.min.y + i), Pt(r.max.x, r.min.y)); fillpoly(im, p, 6, 0, color2, sp); Pack(p, r.max, Pt(r.min.x, r.max.y), Pt(r.min.x + i, r.max.y - i), Pt(r.max.x - i, r.max.y - i), Pt(r.max.x - i, r.min.y + i), Pt(r.max.x, r.min.y)); fillpoly(im, p, 6, 0, color3, sp); } void DisplayCounter(int x, int n) { Image *A, *B, *C; Button3d(screen, Rect(x, Origin.y + 16, x + 41, Origin.y + 41), 1, RGB000000, RGB7F7F7F, RGBFFFFFF, ZP); if(n < -99) n = -99; if(n > 999) n = 999; A = ImageDigit[abs(n / 100 - n / 1000 * 10)]; B = ImageDigit[abs(n / 10 - n / 100 * 10)]; C = ImageDigit[abs(n / 1 - n / 10 * 10)]; if(n < 0) A = ImageSign; draw(screen, Rect(x + 2, Origin.y + 18, x + 13, Origin.y + 39), A, nil, ZP); draw(screen, Rect(x + 15, Origin.y + 18, x + 26, Origin.y + 39), B, nil, ZP); draw(screen, Rect(x + 28, Origin.y + 18, x + 39, Origin.y + 39), C, nil, ZP); } void DrawButton(int Index) { draw(screen, Rect(Origin.x + MaxX * 8 - 1, Origin.y + 16, Origin.x + MaxX * 8 + 24, Origin.y + 41), ImageButton[Index], nil, ZP); } void DrawCell(Point Cell) { draw(screen, Rect(Origin.x + 12 + Cell.x * 16, Origin.y + 57 + Cell.y * 16, Origin.x + 12 + Cell.x * 16 + Dx(ImageCell[MineField[Cell.x][Cell.y].Picture]->r), Origin.y + 57 + Cell.y * 16 + Dy(ImageCell[MineField[Cell.x][Cell.y].Picture]->r)), ImageCell[MineField[Cell.x][Cell.y].Picture], nil, ZP); } void eresized(int New) { if(New && getwindow(display, Refmesg) < 0) fprint(2,"%s: can't reattach to window", argv0); Origin.x = screen->r.min.x + (screen->r.max.x - screen->r.min.x - 23 - MaxX * 16) / 2; Origin.y = screen->r.min.y + (screen->r.max.y - screen->r.min.y - 68 - MaxY * 16) / 2; draw(screen, screen->r, RGB0000FF, nil, ZP); /* main window */ Button3d(screen, Rect(Origin.x, Origin.y, Origin.x + 23 + MaxX * 16, Origin.y + 68 + MaxY * 16), 3, RGBBFBFBF, RGBFFFFFF, RGB7F7F7F, ZP); /* top small window with button and 2 counters */ Button3d(screen, Rect(Origin.x + 9, Origin.y + 9, Origin.x + 14 + MaxX * 16, Origin.y + 48), 2, RGBBFBFBF, RGB7F7F7F, RGBFFFFFF, ZP); /* button */ DrawButton(Status); /* counter on the left side - remaining mines */ DisplayCounter(Origin.x + 16, MinesRemain); /* counter on the right side - timer */ DisplayCounter(Origin.x -34 + MaxX * 16, Time); /* bottom window - mine field */ Button3d(screen, Rect(Origin.x + 9, Origin.y + 54, Origin.x + 14 + MaxX * 16, Origin.y + 59 + MaxY * 16), 3, RGBBFBFBF, RGB7F7F7F, RGBFFFFFF, ZP); { int x, y; for(x = 1; x < MaxX; x++) line(screen, Pt(Origin.x + 11 + x * 16, Origin.y + 57), Pt(Origin.x + 11 + x * 16, Origin.y + 55 + MaxY * 16), Endsquare, Endsquare, 0, RGB7F7F7F, ZP); for(y = 1; y < MaxY; y++) line(screen, Pt(Origin.x + 12, Origin.y + 56 + y * 16), Pt(Origin.x + 10 + MaxX * 16, Origin.y + 56 + y * 16), Endsquare, Endsquare, 0, RGB7F7F7F, ZP); for(y = 0; y < MaxY; y++) for(x = 0; x < MaxX; x++) DrawCell(Pt(x, y)); } } void MouseCell(Point Cell) { int Picture; switch(MineField[Cell.x][Cell.y].Picture) { case Unknown: Picture = Empty0; break; case Query: Picture = MouseQuery; break; default: return; } draw(screen, Rect(Origin.x + 12 + Cell.x * 16, Origin.y + 57 + Cell.y * 16, Origin.x + 12 + Cell.x * 16 + Dx(ImageCell[Picture]->r), Origin.y + 57 + Cell.y * 16 + Dy(ImageCell[Picture]->r)), ImageCell[Picture], nil, ZP); } void RecoverCell(Point Cell) { switch(MineField[Cell.x][Cell.y].Picture) { case Unknown: case Query: draw(screen, Rect(Origin.x + 12 + Cell.x * 16, Origin.y + 57 + Cell.y * 16, Origin.x + 12 + Cell.x * 16 + Dx(ImageCell[MineField[Cell.x][Cell.y].Picture]->r), Origin.y + 57 + Cell.y * 16 + Dy(ImageCell[MineField[Cell.x][Cell.y].Picture]->r)), ImageCell[MineField[Cell.x][Cell.y].Picture], nil, ZP); } } void *emalloc(ulong size) { void *p; p = malloc(size); if(p == 0) { fprint(2, "%s: no memory: %r\n", argv0); exits("no mem"); } return p; } void InitMineField(void) { /* clean up mine field, make all cells unknown and place new mines */ { int i, x, y; for(y = 0; y < MaxY; y++) for(x = 0; x < MaxX; x++) { MineField[x][y].Mine = FALSE; MineField[x][y].Picture = Unknown; } for(i = 0; i < Mines; ) { x = nrand(MaxX); y = nrand(MaxY); if(MineField[x][y].Mine) continue; MineField[x][y].Mine = TRUE; i++; } } /* count mines in neighbourhood */ { int x, y; for(y = 0; y < MaxY; y++) for(x = 0; x < MaxX; x++) { MineField[x][y].Neighbours = 0; if(x > 0 && MineField[x - 1][y].Mine) MineField[x][y].Neighbours++; if(y > 0 && MineField[x][y - 1].Mine) MineField[x][y].Neighbours++; if(x < MaxX -1 && MineField[x + 1][y].Mine) MineField[x][y].Neighbours++; if(y < MaxY - 1 && MineField[x][y + 1].Mine) MineField[x][y].Neighbours++; if(x > 0 && y > 0 && MineField[x - 1][y - 1].Mine) MineField[x][y].Neighbours++; if(x > 0 && y < MaxY - 1 && MineField[x - 1][y + 1].Mine) MineField[x][y].Neighbours++; if(x < MaxX - 1 && y > 0 && MineField[x + 1][y - 1].Mine) MineField[x][y].Neighbours++; if(x < MaxX - 1 && y < MaxY - 1 && MineField[x + 1][y + 1].Mine) MineField[x][y].Neighbours++; } } Status = Game; Playing = FALSE; MinesRemain = Mines; Time = 0; UnknownCell = MaxX * MaxY - Mines; } void NewMineField(int NewLevel) { int CurrentMaxX, CurrentMaxY; CurrentMaxX = MaxX; CurrentMaxY = MaxY; Level = NewLevel; /* set size of mine field and number of mines */ if(Level == Custom) { /* here should ask a player about custom size of mine field and number of mines; in next release, may be... */ if(MaxX < 8) MaxX = 8; if(MaxY < 8) MaxY = 8; if(Mines < 10) Mines = 10; if(MaxX > 30) MaxX = 30; if(MaxY > 24) MaxY = 24; if(Mines > (MaxX - 1) * (MaxY - 1)) Mines = (MaxX - 1) * (MaxY - 1); } else { MaxX = Settings[Level].MaxX; MaxY = Settings[Level].MaxY; Mines = Settings[Level].Mines; Settings[Custom].MaxX = MaxX; Settings[Custom].MaxY = MaxY; Settings[Custom].Mines = Mines; } if(MaxX != CurrentMaxX || MaxY != CurrentMaxY) { int x; /* if some memory is in use, release it */ if(MineField) { for(x = 0; x < CurrentMaxX; x++) free(MineField[x]); free(MineField); } /* allocate new memory */ MineField = (FieldCell **)emalloc(MaxX * sizeof(FieldCell *)); for(x = 0; x < MaxX; x++) MineField[x] = (FieldCell *)emalloc(MaxY * sizeof(FieldCell)); } InitMineField(); } void GameOver(void) { int x, y; Playing = FALSE; for(y = 0; y < MaxY; y++) for(x = 0; x < MaxX; x++) switch(MineField[x][y].Picture) { case Unknown: case Query: if(MineField[x][y].Mine) { switch(Status) { case Win: MineField[x][y].Picture = Mark; DisplayCounter(Origin.x + 16, --MinesRemain); break; case Oops: MineField[x][y].Picture = Mined; } DrawCell(Pt(x, y)); } break; case Mark: if(! MineField[x][y].Mine) { MineField[x][y].Picture = Fault; DrawCell(Pt(x, y)); } } } void LeftClick(Point Cell) { if(! (Status == Game) || Cell.x < 0 || Cell.y < 0) return; Playing = TRUE; switch(MineField[Cell.x][Cell.y].Picture) { case Query: case Unknown: if(MineField[Cell.x][Cell.y].Mine) { MineField[Cell.x][Cell.y].Picture = Explosion; DrawCell(Cell); Status = Oops; GameOver(); return; } MineField[Cell.x][Cell.y].Picture = MineField[Cell.x][Cell.y].Neighbours; DrawCell(Cell); if(! --UnknownCell) { Status = Win; GameOver(); } else if(MineField[Cell.x][Cell.y].Neighbours == 0) { if(Cell.x > 0) LeftClick(Pt(Cell.x - 1, Cell.y)); if(Cell.y > 0) LeftClick(Pt(Cell.x, Cell.y - 1)); if(Cell.x < MaxX - 1) LeftClick(Pt(Cell.x + 1, Cell.y)); if(Cell.y < MaxY - 1) LeftClick(Pt(Cell.x, Cell.y + 1)); if(Cell.x > 0 && Cell.y > 0) LeftClick(Pt(Cell.x - 1, Cell.y - 1)); if(Cell.x > 0 && Cell.y < MaxY - 1) LeftClick(Pt(Cell.x - 1, Cell.y + 1)); if(Cell.x < MaxX - 1 && Cell.y > 0) LeftClick(Pt(Cell.x + 1, Cell.y - 1)); if(Cell.x < MaxX - 1 && Cell.y < MaxY - 1) LeftClick(Pt(Cell.x + 1, Cell.y + 1)); } } } void MiddleClick(Point Cell) { int Neighbours = 0; if(! (Status == Game) || Cell.x < 0 || Cell.y < 0) return; Playing = TRUE; switch(MineField[Cell.x][Cell.y].Picture) { case Empty1: case Empty2: case Empty3: case Empty4: case Empty5: case Empty6: case Empty7: case Empty8: break; default: return; } if(Cell.x > 0 && MineField[Cell.x - 1][Cell.y].Picture == Mark) Neighbours++; if(Cell.y > 0 && MineField[Cell.x][Cell.y - 1].Picture == Mark) Neighbours++; if(Cell.x < MaxX - 1 && MineField[Cell.x + 1][Cell.y].Picture == Mark) Neighbours++; if(Cell.y < MaxY - 1 && MineField[Cell.x][Cell.y + 1].Picture == Mark) Neighbours++; if(Cell.x > 0 && Cell.y > 0 && MineField[Cell.x - 1][Cell.y - 1].Picture == Mark) Neighbours++; if(Cell.x > 0 && Cell.y < MaxY - 1 && MineField[Cell.x - 1][Cell.y + 1].Picture == Mark) Neighbours++; if(Cell.x < MaxX - 1 && Cell.y > 0 && MineField[Cell.x + 1][Cell.y - 1].Picture == Mark) Neighbours++; if(Cell.x < MaxX - 1 && Cell.y < MaxY - 1 && MineField[Cell.x + 1][Cell.y + 1].Picture == Mark) Neighbours++; if(Neighbours == MineField[Cell.x][Cell.y].Neighbours) { if(Cell.x > 0) LeftClick(Pt(Cell.x - 1, Cell.y)); if(Cell.y > 0) LeftClick(Pt(Cell.x, Cell.y - 1)); if(Cell.x < MaxX - 1) LeftClick(Pt(Cell.x + 1, Cell.y)); if(Cell.y < MaxY - 1) LeftClick(Pt(Cell.x, Cell.y + 1)); if(Cell.x > 0 && Cell.y > 0) LeftClick(Pt(Cell.x - 1, Cell.y - 1)); if(Cell.x > 0 && Cell.y < MaxY - 1) LeftClick(Pt(Cell.x - 1, Cell.y + 1)); if(Cell.x < MaxX - 1 && Cell.y > 0) LeftClick(Pt(Cell.x + 1, Cell.y - 1)); if(Cell.x < MaxX - 1 && Cell.y < MaxY - 1) LeftClick(Pt(Cell.x + 1, Cell.y + 1)); } } void RightClick(Point Cell) { if(! (Status == Game) || Cell.x < 0 || Cell.y < 0) return; Playing = TRUE; switch(MineField[Cell.x][Cell.y].Picture) { case Unknown: MineField[Cell.x][Cell.y].Picture = Mark; DrawCell(Cell); DisplayCounter(Origin.x + 16, --MinesRemain); break; case Mark: MineField[Cell.x][Cell.y].Picture = (UseQuery ? Query : Unknown); DrawCell(Cell); DisplayCounter(Origin.x + 16, ++MinesRemain); break; case Query: MineField[Cell.x][Cell.y].Picture = Unknown; DrawCell(Cell); } } void Usage(void) { fprint(2, "Usage: %s\n", argv0); exits("usage"); } void main(int argc, char **argv) { ARGBEGIN { default: Usage(); } ARGEND if(argc > 0) Usage(); if(initdraw(nil, nil, "mines") < 0) { fprint(2, "%s: can't open display: %r\n", argv0); exits("initdraw"); } RGB000000 = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x000000ff); RGB0000FF = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x0000ffff); RGB007F00 = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x007f00ff); RGB7F7F7F = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x7f7f7fff); RGBBFBFBF = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xbfbfbfff); RGBFF0000 = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xff0000ff); RGBFFFF00 = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xffff00ff); RGBFFFFFF = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xffffffff); ImageButton[Game] = allocimage(display, Rect(0, 0, 25, 25), RGB24, 0, DNofill); loadimage(ImageButton[Game], ImageButton[Game]->r, SrcButtonGame, ButtonBytes); ImageButton[Push] = allocimage(display, Rect(0, 0, 25, 25), RGB24, 0, DNofill); loadimage(ImageButton[Push], ImageButton[Push]->r, SrcButtonPush, ButtonBytes); ImageButton[Move] = allocimage(display, Rect(0, 0, 25, 25), RGB24, 0, DNofill); loadimage(ImageButton[Move], ImageButton[Move]->r, SrcButtonMove, ButtonBytes); ImageButton[Win] = allocimage(display, Rect(0, 0, 25, 25), RGB24, 0, DNofill); loadimage(ImageButton[Win], ImageButton[Win]->r, SrcButtonWin, ButtonBytes); ImageButton[Oops] = allocimage(display, Rect(0, 0, 25, 25), RGB24, 0, DNofill); loadimage(ImageButton[Oops], ImageButton[Oops]->r, SrcButtonOops, ButtonBytes); ImageSign = allocimage(display, Rect(0, 0, 11, 21), RGB24, 0, DNofill); loadimage(ImageSign, ImageSign->r, SrcSign, DigitBytes); ImageDigit[0] = allocimage(display, Rect(0, 0, 11, 21), RGB24, 0, DNofill); loadimage(ImageDigit[0], ImageDigit[0]->r, SrcDigit0, DigitBytes); ImageDigit[1] = allocimage(display, Rect(0, 0, 11, 21), RGB24, 0, DNofill); loadimage(ImageDigit[1], ImageDigit[1]->r, SrcDigit1, DigitBytes); ImageDigit[2] = allocimage(display, Rect(0, 0, 11, 21), RGB24, 0, DNofill); loadimage(ImageDigit[2], ImageDigit[2]->r, SrcDigit2, DigitBytes); ImageDigit[3] = allocimage(display, Rect(0, 0, 11, 21), RGB24, 0, DNofill); loadimage(ImageDigit[3], ImageDigit[3]->r, SrcDigit3, DigitBytes); ImageDigit[4] = allocimage(display, Rect(0, 0, 11, 21), RGB24, 0, DNofill); loadimage(ImageDigit[4], ImageDigit[4]->r, SrcDigit4, DigitBytes); ImageDigit[5] = allocimage(display, Rect(0, 0, 11, 21), RGB24, 0, DNofill); loadimage(ImageDigit[5], ImageDigit[5]->r, SrcDigit5, DigitBytes); ImageDigit[6] = allocimage(display, Rect(0, 0, 11, 21), RGB24, 0, DNofill); loadimage(ImageDigit[6], ImageDigit[6]->r, SrcDigit6, DigitBytes); ImageDigit[7] = allocimage(display, Rect(0, 0, 11, 21), RGB24, 0, DNofill); loadimage(ImageDigit[7], ImageDigit[7]->r, SrcDigit7, DigitBytes); ImageDigit[8] = allocimage(display, Rect(0, 0, 11, 21), RGB24, 0, DNofill); loadimage(ImageDigit[8], ImageDigit[8]->r, SrcDigit8, DigitBytes); ImageDigit[9] = allocimage(display, Rect(0, 0, 11, 21), RGB24, 0, DNofill); loadimage(ImageDigit[9], ImageDigit[9]->r, SrcDigit9, DigitBytes); ImageCell[Empty0] = allocimage(display, Rect(0, 0, 15, 15), RGB24, 0, DNofill); loadimage(ImageCell[Empty0], ImageCell[Empty0]->r, SrcEmpty0, CellBytes); ImageCell[Empty1] = allocimage(display, Rect(0, 0, 15, 15), RGB24, 0, DNofill); loadimage(ImageCell[Empty1], ImageCell[Empty1]->r, SrcEmpty1, CellBytes); ImageCell[Empty2] = allocimage(display, Rect(0, 0, 15, 15), RGB24, 0, DNofill); loadimage(ImageCell[Empty2], ImageCell[Empty2]->r, SrcEmpty2, CellBytes); ImageCell[Empty3] = allocimage(display, Rect(0, 0, 15, 15), RGB24, 0, DNofill); loadimage(ImageCell[Empty3], ImageCell[Empty3]->r, SrcEmpty3, CellBytes); ImageCell[Empty4] = allocimage(display, Rect(0, 0, 15, 15), RGB24, 0, DNofill); loadimage(ImageCell[Empty4], ImageCell[Empty4]->r, SrcEmpty4, CellBytes); ImageCell[Empty5] = allocimage(display, Rect(0, 0, 15, 15), RGB24, 0, DNofill); loadimage(ImageCell[Empty5], ImageCell[Empty5]->r, SrcEmpty5, CellBytes); ImageCell[Empty6] = allocimage(display, Rect(0, 0, 15, 15), RGB24, 0, DNofill); loadimage(ImageCell[Empty6], ImageCell[Empty6]->r, SrcEmpty6, CellBytes); ImageCell[Empty7] = allocimage(display, Rect(0, 0, 15, 15), RGB24, 0, DNofill); loadimage(ImageCell[Empty7], ImageCell[Empty7]->r, SrcEmpty7, CellBytes); ImageCell[Empty8] = allocimage(display, Rect(0, 0, 15, 15), RGB24, 0, DNofill); loadimage(ImageCell[Empty8], ImageCell[Empty8]->r, SrcEmpty8, CellBytes); ImageCell[Unknown] = allocimage(display, Rect(0, 0, 15, 15), RGB24, 0, DNofill); loadimage(ImageCell[Unknown], ImageCell[Unknown]->r, SrcUnknown, CellBytes); ImageCell[Mark] = allocimage(display, Rect(0, 0, 15, 15), RGB24, 0, DNofill); loadimage(ImageCell[Mark], ImageCell[Mark]->r, SrcMark, CellBytes); ImageCell[Query] = allocimage(display, Rect(0, 0, 15, 15), RGB24, 0, DNofill); loadimage(ImageCell[Query], ImageCell[Query]->r, SrcQuery, CellBytes); ImageCell[MouseQuery] = allocimage(display, Rect(0, 0, 15, 15), RGB24, 0, DNofill); loadimage(ImageCell[MouseQuery], ImageCell[MouseQuery]->r, SrcMouseQuery, CellBytes); ImageCell[Mined] = allocimage(display, Rect(0, 0, 15, 15), RGB24, 0, DNofill); loadimage(ImageCell[Mined], ImageCell[Mined]->r, SrcMined, CellBytes); ImageCell[Explosion] = allocimage(display, Rect(0, 0, 15, 15), RGB24, 0, DNofill); loadimage(ImageCell[Explosion], ImageCell[Explosion]->r, SrcExplosion, CellBytes); ImageCell[Fault] = allocimage(display, Rect(0, 0, 15, 15), RGB24, 0, DNofill); loadimage(ImageCell[Fault], ImageCell[Fault]->r, SrcFault, CellBytes); srand(time(0)); /* initialize generator of random numbers */ NewMineField(Beginner); eresized(0); einit(Emouse | Ekeyboard); { int PushButton = FALSE, Button = FALSE, CurrentButton, ChargedButton = FALSE, MiddleButton = FALSE, LastButton = 0; ulong Key, Etimer; Event Event; Point CurrentCell, Cell = Pt(-1, -1); Etimer = etimer(0, 1000); for(;;) { Key = event(&Event); if(Key == Etimer) { if(Playing && Time < INT_MAX) DisplayCounter(Origin.x -34 + MaxX * 16, ++Time); } if(Key == Emouse) { /* mouse over button? */ CurrentButton = FALSE; if(Event.mouse.xy.x > Origin.x + MaxX * 8 && Event.mouse.xy.x < Origin.x + MaxX * 8 + 25 && Event.mouse.xy.y > Origin.y + 17 && Event.mouse.xy.y < Origin.y + 42) CurrentButton = TRUE; /* mouse over any cell? */ CurrentCell = Pt(-1, -1); if(Event.mouse.xy.x > Origin.x + 12 && Event.mouse.xy.x < Origin.x + 12 + MaxX * 16) CurrentCell.x = (Event.mouse.xy.x - Origin.x - 13) / 16; if(Event.mouse.xy.y > Origin.y + 57 && Event.mouse.xy.y < Origin.y + 57 + MaxY * 16) CurrentCell.y = (Event.mouse.xy.y - Origin.y - 58) / 16; /* pressed mouse button */ if(Event.mouse.buttons > LastButton) { if(CurrentButton) switch(Event.mouse.buttons) { case 1: PushButton = TRUE; break; default: if(PushButton) DrawButton(Status); PushButton = FALSE; } if(! (CurrentCell.x < 0) && ! (CurrentCell.y < 0)) { switch(Event.mouse.buttons) { case 1: ChargedButton = TRUE; MiddleButton = FALSE; break; case 2: if(LastButton == 0) ChargedButton = TRUE; MiddleButton = TRUE; break; case 4: if(LastButton == 0) RightClick(CurrentCell); else MiddleButton = TRUE; break; default: ChargedButton = TRUE; MiddleButton = TRUE; } if(ChargedButton && Status == Game) DrawButton(Move); } } if(PushButton && CurrentButton != Button) { if(CurrentButton) DrawButton(Push); else DrawButton(Status); Button = CurrentButton; } if(ChargedButton && (! eqpt(CurrentCell, Cell) || Event.mouse.buttons != LastButton) && Status == Game) { if(! (Cell.x < 0) && ! (Cell.y < 0)) { RecoverCell(Cell); if(Cell.x > 0) RecoverCell(Pt(Cell.x - 1, Cell.y)); if(Cell.y > 0) RecoverCell(Pt(Cell.x, Cell.y - 1)); if(Cell.x < MaxX - 1) RecoverCell(Pt(Cell.x + 1, Cell.y)); if(Cell.y < MaxY - 1) RecoverCell(Pt(Cell.x, Cell.y + 1)); if(Cell.x > 0 && Cell.y > 0) RecoverCell(Pt(Cell.x - 1, Cell.y - 1)); if(Cell.x > 0 && Cell.y < MaxY - 1) RecoverCell(Pt(Cell.x - 1, Cell.y + 1)); if(Cell.x < MaxX - 1 && Cell.y > 0) RecoverCell(Pt(Cell.x + 1, Cell.y - 1)); if(Cell.x < MaxX - 1 && Cell.y < MaxY - 1) RecoverCell(Pt(Cell.x + 1, Cell.y + 1)); } Cell = CurrentCell; if(! (Cell.x < 0) && ! (Cell.y < 0) && ! (Event.mouse.buttons < LastButton)) { MouseCell(Cell); if(MiddleButton) { if(Cell.x > 0) MouseCell(Pt(Cell.x - 1, Cell.y)); if(Cell.y > 0) MouseCell(Pt(Cell.x, Cell.y - 1)); if(Cell.x < MaxX - 1) MouseCell(Pt(Cell.x + 1, Cell.y)); if(Cell.y < MaxY - 1) MouseCell(Pt(Cell.x, Cell.y + 1)); if(Cell.x > 0 && Cell.y > 0) MouseCell(Pt(Cell.x - 1, Cell.y - 1)); if(Cell.x > 0 && Cell.y < MaxY - 1) MouseCell(Pt(Cell.x - 1, Cell.y + 1)); if(Cell.x < MaxX - 1 && Cell.y > 0) MouseCell(Pt(Cell.x + 1, Cell.y - 1)); if(Cell.x < MaxX - 1 && Cell.y < MaxY - 1) MouseCell(Pt(Cell.x + 1, Cell.y + 1)); } } } /* released mouse button */ if(Event.mouse.buttons < LastButton) { if(PushButton && CurrentButton) { InitMineField(); eresized(0); } Button = FALSE; PushButton = FALSE; if(ChargedButton) { if(MiddleButton) MiddleClick(Cell); else LeftClick(Cell); DrawButton(Status); } Cell = Pt(-1, -1); ChargedButton = FALSE; } LastButton = Event.mouse.buttons; } if(Key == Ekeyboard) { switch(Event.kbdc) { case 'n': case 'N': InitMineField(); eresized(0); break; case 'b': case 'B': NewMineField(Beginner); eresized(0); break; case 'a': case 'A': NewMineField(Advanced); eresized(0); break; case 'e': case 'E': NewMineField(Expert); eresized(0); break; case 'q': case 'Q': case 127: exits(nil); } } } } }