1 /*
2 * IceBreaker
3 * Copyright (c) 2000-2002 Matthew Miller <mattdm@mattdm.org>
4 *
5 * <http://www.mattdm.org/icebreaker/>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc., 59
19 * Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23 #include <SDL.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include "icebreaker.h"
27 #include "laundry.h"
28 #include "grid.h"
29 #include "penguin.h"
30 #include "globals.h"
31 #include "themes.h"
32
33 SDL_Surface* gridsave;
34 char grid[WIDTH][HEIGHT];
35
36
37 static char maskgrid[WIDTH][HEIGHT];
38
39 // kludge-o-rama
40 static long rcount;
41 #define MAXRCOUNT 80000
42
43
initgrid()44 int initgrid()
45 {
46 // fix -- add error checking
47 gridsave = SDL_CreateRGBSurface(SDL_SWSURFACE,WIDTH,HEIGHT,screen->format->BitsPerPixel,0,0,0,0);
48 return 0;
49 }
50
quitgrid()51 void quitgrid()
52 {
53 SDL_FreeSurface(gridsave);
54 }
55
drawgridblocks()56 void drawgridblocks()
57 {
58 int r,g,b;
59 SDL_Rect tmprect;
60
61 SDL_FillRect(gridsave,NULL,color.background);
62
63
64 for (tmprect.x=BORDERLEFT;tmprect.x<BORDERRIGHT;tmprect.x+=BLOCKWIDTH)
65 for (tmprect.y=BORDERTOP;tmprect.y<BORDERBOTTOM;tmprect.y+=BLOCKHEIGHT)
66 {
67 r = (random() % (color.boardfillmaxr-color.boardfillminr+1))+color.boardfillminr;
68
69 if (color.boardfillminr == color.boardfillming && color.boardfillmaxr == color.boardfillmaxg)
70 g=r;
71 else
72 g = (random() % (color.boardfillmaxg-color.boardfillming+1))+color.boardfillming;
73
74 if (color.boardfillminr == color.boardfillminb && color.boardfillmaxr == color.boardfillmaxb)
75 b=r;
76 else if (color.boardfillming == color.boardfillminb && color.boardfillmaxg == color.boardfillmaxb)
77 b=g;
78 else
79 b = (random() % (color.boardfillmaxb-color.boardfillminb+1))+color.boardfillminb;
80
81 //if (grid[tmprect.x][tmprect.y]==' ' || grid[tmprect.x][tmprect.y]=='w')
82 if (grid[tmprect.x][tmprect.y]!='.' && grid[tmprect.x][tmprect.y]!='-' && grid[tmprect.x][tmprect.y]!='|')
83 {
84 tmprect.w=BLOCKWIDTH; tmprect.h=BLOCKHEIGHT;
85 SDL_FillRect(gridsave,&tmprect,color.gridline);
86 if (color.gridhighlight==color.gridline)
87 {
88 tmprect.w=BLOCKWIDTH-1; tmprect.h=BLOCKHEIGHT-1; // this makes the gridline show up
89 SDL_FillRect(gridsave,&tmprect,SDL_MapRGB(screen->format, r, g, b));
90 }
91 else
92 {
93 tmprect.w=BLOCKWIDTH-1; tmprect.h=BLOCKHEIGHT-1;
94 SDL_FillRect(gridsave,&tmprect,color.gridhighlight);
95
96 tmprect.w=BLOCKWIDTH-2; tmprect.h=BLOCKHEIGHT-2;
97 // FIX! this is kludgy! changing the index variable on the fly bad bad bad. (even if I do put it back!)
98 tmprect.x++; tmprect.y++;
99 SDL_FillRect(gridsave,&tmprect,SDL_MapRGB(screen->format, r, g, b));
100 tmprect.x--; tmprect.y--;
101
102 }
103 }
104 }
105
106 tmprect.x=BORDERLEFT; tmprect.y=BORDERTOP;
107 tmprect.w=PLAYWIDTH; tmprect.h=PLAYHEIGHT;
108 SDL_BlitSurface(gridsave, &tmprect, screen, &tmprect);
109 }
110
markgrid(int x,int y,int w,int h,char fillchar)111 void markgrid(int x, int y, int w, int h, char fillchar)
112 {
113 int i;
114
115 // Optimizing this routine much further seems about impossible to me
116 // but if you know how to do it, let me know. This is by far the
117 // most frequently-called function in the whole game. Short of
118 // rethinking the collision detection -- which could stand a rethink
119 // anyway -- there's not much that can be done.
120
121 for (i=x;i<x+w;i++)
122 memset(&grid[i][y],fillchar,h);
123
124 /*
125 int i, j;
126 for (j=y;j<y+h;j++)
127 for (i=x;i<x+w;i++)
128 grid[i][j]=fillchar;
129 */
130 }
131
countcleared()132 long countcleared()
133 {
134 int i, j;
135 long c;
136 c=0;
137 for (i=BORDERLEFT;i<BORDERRIGHT;i++)
138 for (j=BORDERTOP;j<BORDERBOTTOM;j++)
139 if (grid[i][j] == ' ' || grid[i][j] == '*')
140 c++;
141 //return(100-(c*100/(PLAYWIDTH*PLAYHEIGHT)));
142 return(c);
143
144 }
145
146 #ifdef DEBUG
printboard()147 void printboard()
148 {
149 int i, j;
150
151 for (j=BLOCKWIDTH/2;j<HEIGHT;j+=BLOCKHEIGHT)
152 {
153 for (i=BLOCKWIDTH/2;i<WIDTH;i+=BLOCKWIDTH)
154 {
155 printf("%c ",grid[i][j]);
156 }
157 printf("\n");
158 }
159 }
160 #endif
161
162 #ifdef DEBUG
printwholegrid()163 void printwholegrid()
164 {
165 int i, j;
166
167 printf ("grid:\n");
168 for (j=0;j<HEIGHT;j++)
169 {
170 for (i=0;i<WIDTH;i++)
171 {
172 printf("%c ",grid[i][j]);
173 }
174 printf("\n");
175 }
176 }
177 #endif
178
179 #ifdef DEBUG
printwholemaskgrid()180 void printwholemaskgrid()
181 {
182 int i, j;
183
184 printf ("maskgrid:\n");
185 for (j=0;j<HEIGHT;j++)
186 {
187 for (i=0;i<WIDTH;i++)
188 {
189 printf("%c ",maskgrid[i][j]);
190 }
191 printf("\n");
192 }
193 }
194 #endif
195
checkempty(int x,int y)196 void checkempty(int x, int y)
197 {
198 //int i,j;
199
200 // for debugging...
201
202 SDL_Rect tmprect;
203
204
205 // if square isn't empty, just return....
206 if (grid[x][y]!=' ') { return; }
207
208
209 // it'd be nice to find a way to keep this longer...
210 memcpy(maskgrid,grid,WIDTH*HEIGHT);
211
212
213 // penguinsearch at that spot...
214 rcount=0;
215 if (!penguinsearch(x,y)) // area is clear!
216 {
217 //printwholemaskgrid();
218
219
220
221 //floodfill(x,y);
222
223 // this makes sure x and y are the top left corners of blocks.
224 // since the area is empty of penguins, it should be completely
225 // safe to use this isntead of floodfill here. really. :)
226 squarefill( (((x-BORDERLEFT)/BLOCKWIDTH ) * BLOCKWIDTH ) +BORDERLEFT, (((y-BORDERTOP)/BLOCKHEIGHT) * BLOCKHEIGHT) +BORDERTOP);
227
228 tmprect.w=BLOCKWIDTH; tmprect.h=BLOCKHEIGHT;
229 for (tmprect.x=BORDERLEFT;tmprect.x<BORDERRIGHT;tmprect.x+=BLOCKWIDTH)
230 for (tmprect.y=BORDERTOP;tmprect.y<BORDERBOTTOM;tmprect.y+=BLOCKHEIGHT)
231 if (grid[tmprect.x][tmprect.y]=='.') // clear it!)
232 {
233 SDL_FillRect(screen,&tmprect,color.background);
234 soil(tmprect);
235 }
236 //printwholegrid();
237 }
238 /* printf("Search took %ld recursions.\n",rcount); */
239
240 /*
241 for (j=0;j<HEIGHT;j+=BLOCKHEIGHT)
242 {
243 for (i=0;i<WIDTH;i+=BLOCKWIDTH)
244 {
245 printf("%c ",maskgrid[i][j]);
246 }
247 printf("\n");
248 }
249 printf("\n");
250 */
251 }
252
253
penguinsearch(int i,int j)254 int penguinsearch(int i, int j)
255 {
256 int searchval=0;
257
258 rcount++;
259 // kludge! FIX! BAD!
260 if (rcount>MAXRCOUNT) // bail
261 {
262 fprintf(stderr,"Damn. Ran out of recursions.\n");
263 return(2);
264 }
265
266
267 // shouldn't need to check bounds because we're only painting in the
268 // middle. and we call this function so much that the time saved
269 // is worth it
270 //if (i<0 || j<0 || i>=WIDTH || j>=HEIGHT)
271 //{
272 // fprintf(stderr,"That shouldn't have happened (penguinsearch)! (%d,%d)\n",i,j);
273 // exit(1);
274 //}
275
276
277 if (maskgrid[i][j]==' '
278 || maskgrid[i][j]=='1' || maskgrid[i][j]=='2' || maskgrid[i][j]=='w') // Ah ha! The nefarious "instant melting ice" bug solved! NOTE: if more lines are added to the game, add them here too!
279 {
280 maskgrid[i][j]=',';
281
282 // hmmm. the "ice-shelf-collapse" bug *isn't* fixed. :(
283
284 searchval=penguinsearch(i+BLOCKWIDTH, j);
285 if (!searchval) searchval=penguinsearch(i-BLOCKWIDTH, j);
286 if (!searchval) searchval=penguinsearch(i, j-BLOCKHEIGHT);
287 if (!searchval) searchval=penguinsearch(i, j+BLOCKHEIGHT);
288
289 }
290 else if (maskgrid[i][j]=='*') // found a penguin!
291 {
292 searchval=1;
293 }
294 return(searchval);
295 }
296
297
floodfill(int x,int y)298 void floodfill(int x, int y)
299 {
300 // shouldn't need to check bounds because we're only painting in the
301 // middle. ie (x<0 || y<0 || x>WIDTH || y>HEIGHT) is always false.
302 if (grid[x][y]==' ' || grid[x][y]=='1' || grid[x][y]=='2' || grid[x][y]=='w')
303 {
304 grid[x][y]='.';
305 floodfill(x+1, y);
306 floodfill(x-1, y);
307 floodfill(x, y+1);
308 floodfill(x, y-1);
309 }
310 }
311
squarefill(int x,int y)312 void squarefill(int x, int y)
313 {
314 // x and y must be the top left corner of a square, or else this
315 // will look silly. and there's no bounds checking!
316
317 if (grid[x][y]==' ' || grid[x][y]=='1' || grid[x][y]=='2' || grid[x][y]=='w')
318 {
319 markgrid(x,y,BLOCKWIDTH,BLOCKHEIGHT,'.');
320 squarefill(x+BLOCKWIDTH, y);
321 squarefill(x-BLOCKWIDTH, y);
322 squarefill(x, y+BLOCKHEIGHT);
323 squarefill(x, y-BLOCKHEIGHT);
324 }
325 }
326
327