1 /*
2 * IceBreaker
3 * Copyright (c) 2000-2002 Matthew Miller <mattdm@mattdm.org>
4 * http://www.mattdm.org/
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc., 59
18 * Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22
23 #include <SDL.h>
24 #include "icebreaker.h"
25 #include "globals.h"
26 #include "line.h"
27 #include "laundry.h"
28 #include "grid.h"
29 #include "themes.h"
30
createline(int linenum)31 Line createline(int linenum)
32 {
33 static Line l;
34
35 memset(&l, 0, sizeof(l));
36 switch (linenum)
37 {
38 case 1:
39 l.id='1';
40 l.colorpointer=&(color.line1);
41 break;
42 case 2:
43 l.id='2';
44 l.colorpointer=&(color.line2);
45 break;
46 default:
47 l.id='L';
48 l.colorpointer=&(color.background);
49 break;
50 }
51
52 l.on=false;
53 l.dir=UP;
54 l.geom.x=0;
55 l.geom.y=0;
56 l.geom.w=BLOCKWIDTH;
57 l.geom.h=BLOCKHEIGHT;
58 l.mark=l.geom;
59 l.dead=false;
60 l.speedslower=false;
61 l.stuckcount=0;
62 return(l);
63 }
64
startline(Line * l,LineDir d,int x,int y)65 void startline(Line * l, LineDir d, int x, int y)
66 {
67 l->on=true;
68 l->dir=d;
69 l->stuckcount=0;
70
71 switch (d)
72 {
73 case UP:
74 l->geom.w=BLOCKWIDTH;
75 l->geom.h=1;
76 l->geom.x=x;
77 l->geom.y=y-1;
78 break;
79 case DOWN:
80 l->geom.w=BLOCKWIDTH;
81 l->geom.h=1;
82 l->geom.x=x;
83 l->geom.y=y;
84 break;
85 case LEFT:
86 l->geom.w=1;
87 l->geom.h=BLOCKHEIGHT;
88 l->geom.x=x-1;
89 l->geom.y=y;
90 break;
91 case RIGHT:
92 l->geom.w=1;
93 l->geom.h=BLOCKHEIGHT;
94 l->geom.x=x;
95 l->geom.y=y;
96 break;
97 }
98 l->mark=l->geom;
99 }
100
101
moveline(Line * l)102 int moveline(Line * l)
103 {
104 int finish=false;
105 char check1;
106 char check2;
107
108 markgrid(l->mark.x,l->mark.y,l->mark.w,l->mark.h,l->id);
109 SDL_FillRect(screen,&(l->mark),*(l->colorpointer));
110 soil(l->mark);
111
112 switch (l->dir)
113 {
114 case UP:
115 check1=grid[l->geom.x][l->geom.y-1];
116 check2=grid[l->geom.x+BLOCKWIDTH-1][l->geom.y-1];
117 break;
118 case DOWN:
119 check1=grid[l->geom.x][l->geom.y+l->geom.h];
120 check2=grid[l->geom.x+BLOCKWIDTH-1][l->geom.y+l->geom.h];
121 break;
122 case LEFT:
123 check1=grid[l->geom.x-1][l->geom.y];
124 check2=grid[l->geom.x-1][l->geom.y+BLOCKHEIGHT-1];
125 break;
126 case RIGHT:
127 check1=grid[l->geom.x+l->geom.w][l->geom.y];
128 check2=grid[l->geom.x+l->geom.w][l->geom.y+BLOCKHEIGHT-1];
129 break;
130 default: // this will never happen. really.
131 fprintf(stderr,"Line has no direction. That shouldn't have happened.\n");
132 check1='!';
133 check2='!';
134 break;
135 }
136
137
138 if (check1 == ' ' && check2 == ' ')
139 { // next space is empty
140 switch (l->dir)
141 {
142 case UP:
143 l->geom.y--;
144 l->geom.h++;
145 l->mark.y--;
146 l->mark.h=1;
147 break;
148 case DOWN:
149 l->geom.h++; // increase length of line -- top stays same
150 l->mark.y+=l->mark.h;
151 l->mark.h=1;
152 break;
153 case LEFT:
154 l->geom.x--;
155 l->geom.w++;
156 l->mark.x--;
157 l->mark.w=1;
158 break;
159 case RIGHT:
160 l->geom.w++; // increase width of line -- left side stays same
161 l->mark.x+=l->mark.w;
162 l->mark.w=1;
163 break;
164 }
165 }
166 else if (check1 == '*' || check2 == '*')
167 { // hit a penguin. kills line.
168 l->dead=true;
169 }
170 else if (check1 == '1' || check2 == '1' || check1 == '2' || check2 == '2')
171 {
172 if (l->stuckcount>LINEMAXSTUCK)
173 {
174 // FIX -- should play sound when this happens, to
175 // let users know that this isn't a mistake.
176 finish=true;
177 }
178 else
179 {
180 l->stuckcount++;
181
182 // FIX: kludge-o-rama!!
183 // this could work around the irritating thing where
184 // a line gets started 'on top' of another line. but it
185 // is totally repairing the symptom, not the bug. *sigh*
186 //if (l->geom.w==1 || l->geom.h==1) finish=true;
187 }
188 }
189 else
190 { // hit something else
191 finish=true;
192 }
193
194 if (finish)
195 {
196 markgrid(l->mark.x,l->mark.y,l->mark.w,l->mark.h,l->id);
197 SDL_FillRect(screen,&(l->mark),*(l->colorpointer));
198 soil(l->mark);
199 finishline(l);
200 return(1);
201 }
202
203 return(0);
204 }
205
finishline(Line * l)206 void finishline(Line * l)
207 {
208 int i;
209 int quick1=false;
210 int quick2=false;
211
212 l->on=false;
213
214 //printwholegrid();
215
216 switch (l->dir)
217 {
218 case DOWN:
219 // falls through.
220 case UP:
221 markgrid(l->geom.x,l->geom.y,l->geom.w,l->geom.h,'|');
222 SDL_FillRect(screen,&l->geom,color.background);
223 soil(l->geom);
224
225 // scan along edges to quickly determine if this
226 // is going to be complicated.
227 quick1=true; quick2=true;
228 for (i=l->geom.y+BLOCKHEIGHT/2;i<l->geom.y+l->geom.h;i++)
229 {
230 if (grid[l->geom.x-1][i] != ' ' && grid[l->geom.x-1][i] != '*') quick1=false;
231 if (grid[l->geom.x+BLOCKWIDTH][i] != ' ' && grid[l->geom.x+BLOCKWIDTH][i] != '*') quick2=false;
232 }
233
234 //printf("Quick %d %d\n",quick1,quick2);
235
236 checkempty(l->geom.x-BLOCKWIDTH/2,l->geom.y+BLOCKHEIGHT/2);
237 checkempty(l->geom.x+BLOCKWIDTH+BLOCKWIDTH/2/2,l->geom.y+BLOCKHEIGHT/2);
238
239 if (!quick1)
240 for (i=l->geom.y+BLOCKHEIGHT/2+BLOCKHEIGHT;i<l->geom.y+l->geom.h;i+=BLOCKHEIGHT)
241 checkempty(l->geom.x-BLOCKWIDTH/2,i);
242 if (!quick2)
243 for (i=l->geom.y+BLOCKHEIGHT/2+BLOCKHEIGHT;i<l->geom.y+l->geom.h;i+=BLOCKHEIGHT)
244 checkempty(l->geom.x+BLOCKWIDTH+BLOCKWIDTH/2,i);
245 break;
246 case RIGHT:
247 // falls through
248 case LEFT:
249 markgrid(l->geom.x,l->geom.y,l->geom.w,l->geom.h,'-');
250 SDL_FillRect(screen,&l->geom,color.background);
251 soil(l->geom);
252
253 // scan along edges to quickly determine if this
254 // is going to be complicated.
255 quick1=true; quick2=true;
256 for (i=l->geom.x+BLOCKWIDTH/2;i<l->geom.x+l->geom.w;i++)
257 {
258 if (grid[i][l->geom.y-1] != ' ' && grid[i][l->geom.y-1] != '*') quick1=false;
259 if (grid[i][l->geom.y+BLOCKHEIGHT] != ' ' && grid[i][l->geom.y+BLOCKHEIGHT] != '*') quick2=false;
260 }
261
262 //printf("Quick %d %d\n",quick1,quick2);
263
264 checkempty(l->geom.x+BLOCKWIDTH/2,l->geom.y-BLOCKHEIGHT/2);
265 checkempty(l->geom.x+BLOCKWIDTH/2,l->geom.y+BLOCKHEIGHT+BLOCKHEIGHT/2);
266
267 if (!quick1)
268 for (i=l->geom.x+BLOCKWIDTH/2+BLOCKWIDTH;i<l->geom.x+l->geom.w;i+=BLOCKWIDTH)
269 checkempty(i,l->geom.y-BLOCKHEIGHT/2);
270
271 if (!quick2)
272 for (i=l->geom.x+BLOCKWIDTH/2+BLOCKWIDTH;i<l->geom.x+l->geom.w;i+=BLOCKWIDTH)
273 checkempty(i,l->geom.y+BLOCKHEIGHT+BLOCKHEIGHT/2);
274
275 break;
276 }
277
278 }
279
280
killline(Line * l)281 void killline(Line * l)
282 {
283 l->on=false;
284 l->dead=false;
285
286 switch (l->dir)
287 {
288 case DOWN:
289 // falls through.
290 case UP:
291 markgrid(l->geom.x,l->geom.y,l->geom.w,l->geom.h,' ');
292 // FIXORAMA
293 SDL_BlitSurface(gridsave,&l->geom, screen, &l->geom);
294 soil(l->geom);
295 break;
296 case RIGHT:
297 // falls through
298 case LEFT:
299 markgrid(l->geom.x,l->geom.y,l->geom.w,l->geom.h,' ');
300 // FIXORAMA
301 SDL_BlitSurface(gridsave,&l->geom, screen, &l->geom);
302 soil(l->geom);
303 break;
304 }
305 }
306