ff3181d0ad4db7ca71b249dd66a835e6586b97f8
[sdk] / samples / games / bomb / bomb.ec
1 import "ecere"
2
3 #define NUMLEVELS 11
4 #define DIMX      16
5 #define DIMY      16
6 #define MAXTIME   (5*60)
7 #define TIME2     (4*60)
8 #define TIME1     (2*60)
9 #define TIMEBAR   gray
10 #define TIMEFILL  darkBlue
11
12 #define NOTHING   0
13 #define PLAYER    1
14 #define BOMB5     2
15 #define BOMB3     3
16 #define BOMB1     4
17 #define BOMBD     5
18 #define DESACTIV  6
19 #define BLOCK     7
20
21 #define STATE_MENU      0
22 #define STATE_GAME      1
23 #define STATE_CREDITS   2
24 #define STATE_ENDSCREEN 3
25 #define STATE_PASSWORD  4
26
27 static char passwords[NUMLEVELS+1][5] =
28 {
29    "","1111","2222","3333","4444","5555","6666",
30    "7777","8888","9999","AAAA","BBBB"
31 };
32
33 BombApp app;
34
35 class Bomb : Window
36 {
37    borderStyle = sizable, hasMaximize = true, hasMinimize = true, hasClose = true;
38    text = "Bomb Squad", clientSize = Size { 640,400 };
39       
40    bool fullScreen;
41    char board[DIMY][DIMX];
42
43    Bitmap gfx[8];
44    Bitmap mainBitmap {};
45    Bitmap credits {};
46    Bitmap endScreen {};
47    Bitmap password {};
48
49    Size mapSize;
50    Point player;
51    double startTime, secPassed;
52    int level;
53    int state;
54
55    bool DelayExpired()
56    {
57       int x,y, b;
58       double currentTime = GetTime();
59       secPassed = currentTime - startTime;
60            if(secPassed >= TIME2)b=BOMB1;
61       else if(secPassed >= TIME1)b=BOMB3;
62       else                       b=BOMB5;
63
64       for(y=0; y<DIMY; y++)
65          for(x=0; x<DIMX; x++)
66             if((board[y][x]==BOMB1)||(board[y][x]==BOMB3)||(board[y][x]==BOMB5))
67                board[y][x]=(byte)b;
68
69       if(secPassed >= MAXTIME)
70       {
71          state = STATE_MENU;
72          SetPalette(true);
73          timer.Stop();
74       }
75       Update(null);
76       return true;
77    }
78    Timer timer
79    {
80       this, Seconds { 1 }, DelayExpired = DelayExpired
81    };
82    EditBox passEdit
83    {
84       this, textHorzScroll = true, text = "Password", 
85       anchor = Anchor { left = 0.03, top = 0.05, right = 0.84, bottom = 0.80 }, 
86       autoCreate = false
87    };
88    Bitmap buffer {};
89
90    bool IsDone()
91    {
92       bool lost = false;
93       int x,y;
94       for(y=0; y<DIMY; y++)
95          for(x=0; x<DIMX; x++)
96             if((board[y][x]==BOMB1)||(board[y][x]==BOMB3)||(board[y][x]==BOMB5))
97                lost = true;
98       return !lost;
99    }
100
101    void SetPalette(bool flag)
102    {
103       ColorAlpha * palette = null;
104       switch(state)
105       {
106          case STATE_GAME: palette = LoadPalette(":nothing.pcx", null); break;
107          case STATE_MENU: palette = LoadPalette(":max3.pcx", null); break;
108          case STATE_CREDITS: palette = LoadPalette(":3.pcx", null); break;
109          case STATE_ENDSCREEN: palette = LoadPalette(":max3.pcx", null); break;
110       }
111       CopyBytesBy4(buffer.palette, palette, 256);
112       display.SetPalette(palette, flag);
113       delete palette;
114    }
115
116    void LoadLevel(int level)
117    {
118       File f;
119       char map[80];
120
121       // Start the game
122       this.level = level;
123       state = STATE_GAME;
124       timer.Start();
125       startTime = GetTime();
126       sprintf(map,":map%d.dat",level);
127
128       f = FileOpen(map, read);
129       if(f)
130       {
131          int x,y;
132          for(y=0; y<DIMY; y++)
133             for(x=0; x<DIMX; x++)
134             {
135                char ch;
136                f.Getc(&ch);
137                board[y][x] = ch;
138
139                if(board[y][x]==PLAYER)
140                {
141                   player = Point{x,y};
142                   board[y][x]=NOTHING;
143                }
144             }
145          delete f;
146       }
147
148       DelayExpired();
149       SetPalette(true);
150    }
151
152    bool OnStateChange(WindowState state, Modifiers mods)
153    {
154       if(state == maximized && (Key)mods == hotKey)
155       {
156          app.fullScreen = true;
157          app.resolution = res320x200;
158          app.pixelFormat = pixelFormat8;
159          borderStyle = none;
160          anchor = Anchor { left = 0, top = 0, right = 0, bottom = 0 };
161          return false;
162       }
163       return true;
164    }
165
166    bool OnLoadGraphics()
167    {
168       int c;
169       endScreen.Load(":max3.pcx", null, null);
170       mainBitmap.Load(":max3.pcx", null, null);
171       credits.Load(":3.pcx", null, null);
172       password.Load(":password.pcx", null, null);
173
174       for(c = 0; c<8; c++)
175          gfx[c] = Bitmap {};
176       gfx[NOTHING].Load(":nothing.pcx", null, null);
177       gfx[PLAYER].Load(":player.pcx", null, null);
178       gfx[BOMB5].Load(":bomb.pcx", null, null);
179       gfx[BOMB3].Load(":deadeac.pcx", null, null);
180       gfx[BOMB1].Load(":deadeac.pcx", null, null);
181       gfx[BOMBD].Load(":deacbomb.pcx", null, null);
182       gfx[DESACTIV].Load(":desactiv.pcx", null, null);
183       gfx[BLOCK].Load(":block.pcx", null, null);
184
185       mapSize.w = gfx[0].width;
186       mapSize.h = gfx[0].height;
187
188       buffer.AllocateDD(displaySystem, 320, 200);
189
190       SetPalette(true);
191       return true;
192    }
193
194    void OnUnloadGraphics()
195    {
196       int c;
197
198       for(c=0; c<8; c++)
199          delete gfx[c];
200       mainBitmap.Free();
201       credits.Free();
202       endScreen.Free();
203       password.Free();
204       buffer.Free();
205    }
206
207    void OnRedraw(Surface surface2)
208    {
209       Surface surface = buffer.GetSurface(0,0, null);
210
211       surface.SetBackground(black);
212       surface.Clear(colorBuffer);
213       switch(state)
214       {
215          case STATE_GAME:
216          {
217             int x,y;
218             int width;
219             int offX = (320 - mapSize.w * DIMX) / 2;
220             int offY = (200 - mapSize.h * DIMY - 20) / 2;
221
222             for(y=0; y<DIMY; y++)
223                for(x=0; x<DIMX; x++)
224                   surface.Blit(gfx[board[y][x]],
225                      offX + x*mapSize.w, offY + y*mapSize.h, 0,0,
226                      mapSize.w,mapSize.h);
227             surface.Blit(gfx[PLAYER],
228                offX + player.x*mapSize.w, offY + player.y*mapSize.h,
229                0,0,mapSize.w,mapSize.h);
230             
231             surface.SetForeground(TIMEBAR);
232             surface.Rectangle(0,buffer.height - 20,buffer.width-1,buffer.height-1);
233             width = (int)((buffer.width - 2)*(MAXTIME-secPassed)/MAXTIME);
234             surface.SetBackground(TIMEFILL);
235             surface.Area(1,buffer.height - 19,width,buffer.height - 2);
236             break;
237          }
238          case STATE_MENU:
239             surface.Blit(mainBitmap, 0,0, 0,0, mainBitmap.width,mainBitmap.height);
240             break;
241          case STATE_CREDITS:
242             surface.Blit(credits, 0,0, 0,0, credits.width,credits.height);
243             break;
244          case STATE_ENDSCREEN:
245             surface.Blit(endScreen, 0,0, 0,0, endScreen.width,endScreen.height);
246             break;
247          case STATE_PASSWORD:
248             surface.Blit(password, 0,0,0,0,password.width, password.height);
249             break;
250       }
251
252       delete surface;
253       surface2.Stretch(buffer, 0,0, 0,0, clientSize.w, clientSize.h, 
254          buffer.width, buffer.height);
255    }
256
257    bool OnKeyDown(Key key, unichar character)
258    {
259       if(state == STATE_PASSWORD)
260       {
261          if(key == enter)
262          {
263             int l;
264             char * pwd = passEdit.contents;
265             for(l=1; l<=NUMLEVELS; l++)
266                if(!strcmpi(pwd,passwords[l]))
267                {
268                   char string[80];
269                   sprintf(string, "Wrapping to level %d...",l);
270                   MessageBox { text = "Password Accepted", contents = string }.Modal();
271                   LoadLevel(l);
272                   break;
273                }
274          }
275          else if(key != escape)
276             return true;
277
278          passEdit.Destroy(0);
279          if(state == STATE_PASSWORD) state = STATE_MENU;
280          Update(null);
281       }
282       else if(state == STATE_MENU)
283       {
284          switch(key)
285          {
286             case s: LoadLevel(1); break;
287             case p:    
288                state = STATE_PASSWORD;
289                passEdit.Create();
290                break;
291             case x: Destroy(0); return false;
292             case c: state = STATE_CREDITS; SetPalette(true); break;
293          }
294          Update(null);
295       }
296       switch(key)
297       {
298          case escape: 
299             if(state == STATE_GAME)
300                timer.Stop();
301             state = STATE_MENU; 
302             SetPalette(true);
303             Update(null);
304             break;
305          case altEnter:
306             fullScreen = false;
307             borderStyle = sizable, hasClose = true, hasMinimize = true, hasMaximize = true;
308             clientSize = { 640, 400 };
309             return false;
310       }
311       return true;
312    }
313
314    bool OnKeyHit(Key key, unichar ch)
315    {
316       if(state == STATE_GAME)
317       {
318          int dx=0,dy=0;
319
320          switch(key)
321          {
322             case up: dy=-1; break;
323             case down: dy=1; break;
324             case left: dx=-1; break;
325             case right: dx=1; break;
326             default: return true;
327          }
328
329          if((player.x+dx<0)||(player.y+dy<0)||(player.x+dx>=DIMX)||(player.y+dy>=DIMY))
330             return true;
331
332          if(board[player.y+dy][player.x+dx]==BLOCK) return true;
333          if((board[player.y+dy][player.x+dx]==BOMB5)
334           ||(board[player.y+dy][player.x+dx]==BOMB3)
335           ||(board[player.y+dy][player.x+dx]==BOMB1)
336           ||(board[player.y+dy][player.x+dx]==BOMBD))
337          {
338             if((player.x+dx*2<0)||(player.y+dy*2<0)||(player.x+dx*2>=DIMX)||(player.y+dy*2>=DIMY))
339                return true;
340             if((board[player.y+2*dy][player.x+2*dx]!=DESACTIV)&&
341                (board[player.y+2*dy][player.x+2*dx]!=NOTHING))
342                return true;
343             if(board[player.y+dy][player.x+dx]==BOMBD)
344                board[player.y+dy][player.x+dx]=DESACTIV;
345             else
346                board[player.y+dy][player.x+dx]=NOTHING;
347             if(board[player.y+2*dy][player.x+2*dx]==DESACTIV)
348                board[player.y+2*dy][player.x+2*dx]=BOMBD;
349             else
350             {
351                int b;
352                     if(secPassed >= TIME2)b=BOMB1;
353                else if(secPassed >= TIME1)b=BOMB3;
354                else                             b=BOMB5;
355                board[player.y+2*dy][player.x+2*dx]=(byte)b;
356             }
357          }
358
359          player.x+=dx;
360          player.y+=dy;
361
362          if(IsDone())
363          {
364             if(level == NUMLEVELS)
365             {
366                state = STATE_ENDSCREEN;
367                SetPalette(true);
368             }
369             else
370             {
371                char string[80];
372                sprintf(string, "Password to level %d is: %s",level+1,passwords[level+1]);
373                timer.Stop();
374                MessageBox { text = "Congratulations! You win!", contents = string }.Modal();
375                LoadLevel(level + 1);
376             }
377          }
378          Update(null);
379       }
380       return true;
381    }
382 }
383
384 class BombApp : GuiApplication
385 {
386    Bomb bomb {};
387    void Main()
388    {
389       app = this;
390       GuiApplication::Main();
391    }
392 }