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