1 /*
2  * Seven Kingdoms: Ancient Adversaries
3  *
4  * Copyright 1997,1998 Enlight Software Ltd.
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 // Filename    : OW_ROCK.CPP
22 // Description : generate random rock on map
23 
24 
25 #include <OWORLD.h>
26 #include <OROCKRES.h>
27 #include <OROCK.h>
28 #include <OTERRAIN.h>
29 
30 
31 //--------------- begin of function World::can_add_rock ----------//
can_add_rock(short x1,short y1,short x2,short y2)32 int World::can_add_rock(short x1, short y1, short x2, short y2)
33 {
34 	int x,y;
35 	err_when(x1 > x2 || y1 > y2);
36 	for(y = y1; y <= y2; ++y)
37 		for( x = x1; x <= x2; ++x)
38 			if( !get_loc(x,y)->can_add_rock(3) )
39 				return 0;
40 	return 1;
41 }
42 //--------------- end of function World::can_add_rock ----------//
43 
44 
45 // --------- begin of function World::add_rock ----------//
46 //
47 // note : make sure the location in the area is free
48 //
add_rock(short rockRecno,short x1,short y1)49 void World::add_rock(short rockRecno, short x1, short y1)
50 {
51 	// ------- get the delay remain count for the first frame -----//
52 	Rock newRock(rockRecno, x1, y1);
53 	int rockArrayRecno = rock_array.add(&newRock);
54 	RockInfo *rockInfo = rock_res.get_rock_info(rockRecno);
55 
56 	for( short dy = 0; dy < rockInfo->loc_height && y1+dy < max_y_loc; ++dy)
57 	{
58 		for( short dx = 0; dx < rockInfo->loc_width && x1+dx < max_x_loc; ++dx)
59 		{
60 			short rockBlockRecno = rock_res.locate_block(rockRecno, dx, dy);
61 			if( rockBlockRecno )
62 			{
63 				Location *locPtr = get_loc(x1+dx, y1+dy);
64 				err_when( !locPtr->can_add_rock(3) );
65 				locPtr->set_rock(rockArrayRecno);
66 				locPtr->set_power_off();
67 				set_surr_power_off(x1, y1);
68 			}
69 		}
70 	}
71 }
72 // --------- end of function World::add_rock ----------//
73 
74 
75 // --------- begin of function World::gen_rocks ----------//
gen_rocks(int nGrouped,int nLarge,int nSmall)76 void World::gen_rocks(int nGrouped, int nLarge, int nSmall)
77 {
78 	// one 'large' (size 1 to 4) at the center
79 	// and a number 'small' (size 1 to 2) at the surroundings
80 
81 	const int GAP=4;
82 	const int HUGE_ROCK_SIZE=6;
83 	const int LARGE_ROCK_SIZE=4;
84 	const int SMALL_ROCK_SIZE=2;
85 
86 	int trial = (nGrouped + nLarge + nSmall) * 2;
87 
88 	while( (nGrouped > 0 || nLarge > 0 || nSmall > 0) && --trial > 0)
89 	{
90 		// generate grouped rocks
91 		if( nGrouped > 0 )
92 		{
93 			short x = (GAP+SMALL_ROCK_SIZE)+misc.random( max_x_loc - LARGE_ROCK_SIZE +1 - 2*(GAP+SMALL_ROCK_SIZE));
94 			short y = (GAP+SMALL_ROCK_SIZE)+misc.random( max_y_loc - LARGE_ROCK_SIZE +1 - 2*(GAP+SMALL_ROCK_SIZE));
95 			short x2 = x + LARGE_ROCK_SIZE -1;
96 			short y2 = y + LARGE_ROCK_SIZE -1;
97 
98 			if( can_add_rock(x,y, x2,y2) )
99 			{
100 				short rockRecno = rock_res.search("R", 1,LARGE_ROCK_SIZE,1,LARGE_ROCK_SIZE,-1,0,
101 					terrain_res[get_loc(x,y)->terrain_id]->average_type );
102 				if( !rockRecno )
103 					continue;
104 
105 				RockInfo *rockInfo = rock_res.get_rock_info(rockRecno);
106 				x2 = x + rockInfo->loc_width - 1;
107 				y2 = y + rockInfo->loc_height -1;
108 				if( rockInfo->valid_terrain(terrain_res[get_loc(x2, y)->terrain_id]->average_type)
109 					&& rockInfo->valid_terrain(terrain_res[get_loc(x, y2)->terrain_id]->average_type)
110 					&& rockInfo->valid_terrain(terrain_res[get_loc(x2,y2)->terrain_id]->average_type))
111 				{
112 					add_rock(rockRecno, x, y);
113 
114 					// add other smaller rock
115 					for(int subTrial = misc.random(14); subTrial > 0 ; --subTrial)
116 					{
117 						// sx from x-SMALL_ROCK_SIZE to x+4-1+SMALL_ROCK_SIZE
118 						short sx = x - SMALL_ROCK_SIZE - GAP + misc.random( LARGE_ROCK_SIZE + SMALL_ROCK_SIZE + 2*GAP);
119 						short sy = y - SMALL_ROCK_SIZE - GAP + misc.random( LARGE_ROCK_SIZE + SMALL_ROCK_SIZE + 2*GAP);
120 						short sx2 = sx + SMALL_ROCK_SIZE-1;
121 						short sy2 = sy + SMALL_ROCK_SIZE-1;
122 
123 						if( can_add_rock( sx, sy, sx2, sy2))
124 						{
125 							short rock2Recno = rock_res.search("R", 1,SMALL_ROCK_SIZE,1,SMALL_ROCK_SIZE,-1,0,
126 								terrain_res[get_loc(sx,sy)->terrain_id]->average_type );
127 							if(!rock2Recno)
128 								continue;
129 
130 							RockInfo *rock2Info = rock_res.get_rock_info(rock2Recno);
131 							sx2 = sx + rock2Info->loc_width -1;
132 							sy2 = sy + rock2Info->loc_height -1;
133 							if( rock2Info->valid_terrain(terrain_res[get_loc(sx2,sy)->terrain_id]->average_type)
134 								&& rock2Info->valid_terrain(terrain_res[get_loc(sx,sy2)->terrain_id]->average_type)
135 								&& rock2Info->valid_terrain(terrain_res[get_loc(sx2,sy2)->terrain_id]->average_type) )
136 							{
137 								add_rock(rock2Recno, sx, sy);
138 							}
139 						}
140 					}
141 					nGrouped--;
142 				}
143 			}
144 		}
145 
146 		// generate stand-alone large rock
147 		if( nLarge > 0 )
148 		{
149 			short x = misc.random( max_x_loc - HUGE_ROCK_SIZE);
150 			short y = misc.random( max_y_loc - HUGE_ROCK_SIZE);
151 			short x2 = x + HUGE_ROCK_SIZE -1;
152 			short y2 = y + HUGE_ROCK_SIZE -1;
153 
154 			if( can_add_rock( x, y, x2, y2) )
155 			{
156 				short rockRecno = rock_res.search("R", SMALL_ROCK_SIZE+1,HUGE_ROCK_SIZE,LARGE_ROCK_SIZE+1,HUGE_ROCK_SIZE,-1,0,
157 					terrain_res[get_loc(x,y)->terrain_id]->average_type );
158 				if( !rockRecno )
159 					continue;
160 
161 				RockInfo *rockInfo = rock_res.get_rock_info(rockRecno);
162 				x2 = x + rockInfo->loc_width - 1;
163 				y2 = y + rockInfo->loc_height -1;
164 				if( rockInfo->valid_terrain(terrain_res[get_loc(x2, y)->terrain_id]->average_type)
165 					&& rockInfo->valid_terrain(terrain_res[get_loc(x, y2)->terrain_id]->average_type)
166 					&& rockInfo->valid_terrain(terrain_res[get_loc(x2,y2)->terrain_id]->average_type))
167 				{
168 					add_rock(rockRecno, x, y);
169 					nLarge--;
170 				}
171 			}
172 		}
173 
174 		// generate stand-alone small rock
175 		if( nSmall > 0)
176 		{
177 			short x = misc.random( max_x_loc - SMALL_ROCK_SIZE);
178 			short y = misc.random( max_y_loc - SMALL_ROCK_SIZE);
179 			short x2 = x + SMALL_ROCK_SIZE -1;
180 			short y2 = y + SMALL_ROCK_SIZE -1;
181 
182 			if( can_add_rock( x, y, x2, y2) )
183 			{
184 				short rockRecno = rock_res.search("R", 1,SMALL_ROCK_SIZE,1,SMALL_ROCK_SIZE,-1,0,
185 					terrain_res[get_loc(x,y)->terrain_id]->average_type );
186 				if( !rockRecno )
187 					continue;
188 
189 				RockInfo *rockInfo = rock_res.get_rock_info(rockRecno);
190 				x2 = x + rockInfo->loc_width - 1;
191 				y2 = y + rockInfo->loc_height -1;
192 				if( rockInfo->valid_terrain(terrain_res[get_loc(x2, y)->terrain_id]->average_type)
193 					&& rockInfo->valid_terrain(terrain_res[get_loc(x, y2)->terrain_id]->average_type)
194 					&& rockInfo->valid_terrain(terrain_res[get_loc(x2,y2)->terrain_id]->average_type))
195 				{
196 					add_rock(rockRecno, x, y);
197 					nSmall--;
198 				}
199 			}
200 		}
201 	}
202 }
203 // --------- end of function World::gen_rocks ----------//
204 
205 
206 //--------------- begin of function World::can_add_dirt ----------//
can_add_dirt(short x1,short y1,short x2,short y2)207 int World::can_add_dirt(short x1, short y1, short x2, short y2)
208 {
209 	int x,y;
210 	err_when(x1 > x2 || y1 > y2);
211 	for(y = y1; y <= y2; ++y)
212 		for( x = x1; x <= x2; ++x)
213 			if( !get_loc(x,y)->can_add_dirt() )
214 				return 0;
215 	return 1;
216 }
217 //--------------- end of function World::can_add_dirt ----------//
218 
219 
220 // --------- begin of function World::add_dirt ----------//
221 //
222 // note : make sure the location in the area is free
223 //
add_dirt(short dirtRecno,short x1,short y1)224 void World::add_dirt(short dirtRecno, short x1, short y1)
225 {
226 	if( dirt_array.size() >= 255 )
227 		return;
228 
229 	// ------- get the delay remain count for the first frame -----//
230 	Rock newDirt(dirtRecno, x1, y1);
231 	int dirtArrayRecno = dirt_array.add(&newDirt);
232 
233 	if( dirtArrayRecno >= 255)		// Location::extra_para is only BYTE
234 		return;
235 
236 	RockInfo *dirtInfo = rock_res.get_rock_info(dirtRecno);
237 
238 	for( short dy = 0; dy < dirtInfo->loc_height && y1+dy < max_y_loc; ++dy)
239 	{
240 		for( short dx = 0; dx < dirtInfo->loc_width && x1+dx < max_x_loc; ++dx)
241 		{
242 			short dirtBlockRecno = rock_res.locate_block(dirtRecno, dx, dy);
243 			if( dirtBlockRecno )
244 			{
245 				Location *locPtr = get_loc(x1+dx, y1+dy);
246 				err_when( !locPtr->can_add_dirt() );
247 				locPtr->set_dirt(dirtArrayRecno);
248 
249 				if( dirtInfo->rock_type == DIRT_BLOCKING_TYPE )
250 					locPtr->walkable_off();
251 			}
252 		}
253 	}
254 }
255 // --------- end of function World::add_rock ----------//
256 
257 
258 // --------- begin of function World::gen_dirt ----------//
gen_dirt(int nGrouped,int nLarge,int nSmall)259 void World::gen_dirt(int nGrouped, int nLarge, int nSmall)
260 {
261 	// one 'large' (size 1 to 4) at the center
262 	// and a number 'small' (size 1 to 2) at the surroundings
263 
264 	const int GAP=4;
265 	const int HUGE_ROCK_SIZE=6;
266 	const int LARGE_ROCK_SIZE=4;
267 	const int SMALL_ROCK_SIZE=2;
268 
269 	int trial = (nGrouped + nLarge + nSmall) * 2;
270 
271 	while( (nGrouped > 0 || nLarge > 0 || nSmall > 0) && --trial > 0)
272 	{
273 		// generate grouped dirt
274 		if( nGrouped > 0 )
275 		{
276 			short x = (GAP+SMALL_ROCK_SIZE)+misc.random( max_x_loc - LARGE_ROCK_SIZE +1 - 2*(GAP+SMALL_ROCK_SIZE));
277 			short y = (GAP+SMALL_ROCK_SIZE)+misc.random( max_y_loc - LARGE_ROCK_SIZE +1 - 2*(GAP+SMALL_ROCK_SIZE));
278 			short x2 = x + LARGE_ROCK_SIZE -1;
279 			short y2 = y + LARGE_ROCK_SIZE -1;
280 
281 			if( can_add_dirt(x,y, x2,y2) )
282 			{
283 				short rockRecno = rock_res.search("DE", 1,LARGE_ROCK_SIZE,1,LARGE_ROCK_SIZE,-1,0,
284 					terrain_res[get_loc(x,y)->terrain_id]->average_type );
285 				if( !rockRecno )
286 					continue;
287 
288 				RockInfo *rockInfo = rock_res.get_rock_info(rockRecno);
289 				x2 = x + rockInfo->loc_width - 1;
290 				y2 = y + rockInfo->loc_height -1;
291 				if( rockInfo->valid_terrain(terrain_res[get_loc(x2, y)->terrain_id]->average_type)
292 					&& rockInfo->valid_terrain(terrain_res[get_loc(x, y2)->terrain_id]->average_type)
293 					&& rockInfo->valid_terrain(terrain_res[get_loc(x2,y2)->terrain_id]->average_type))
294 				{
295 					add_dirt(rockRecno, x, y);
296 
297 					// add other smaller rock
298 					for(int subTrial = misc.random(14); subTrial > 0 ; --subTrial)
299 					{
300 						// sx from x-SMALL_ROCK_SIZE to x+4-1+SMALL_ROCK_SIZE
301 						short sx = x - SMALL_ROCK_SIZE - GAP + misc.random( LARGE_ROCK_SIZE + SMALL_ROCK_SIZE + 2*GAP);
302 						short sy = y - SMALL_ROCK_SIZE - GAP + misc.random( LARGE_ROCK_SIZE + SMALL_ROCK_SIZE + 2*GAP);
303 						short sx2 = sx + SMALL_ROCK_SIZE-1;
304 						short sy2 = sy + SMALL_ROCK_SIZE-1;
305 
306 						if( can_add_dirt( sx, sy, sx2, sy2))
307 						{
308 							short rock2Recno = rock_res.search("DE", 1,SMALL_ROCK_SIZE,1,SMALL_ROCK_SIZE,-1,0,
309 								terrain_res[get_loc(sx,sy)->terrain_id]->average_type );
310 							if(!rock2Recno)
311 								continue;
312 
313 							RockInfo *rock2Info = rock_res.get_rock_info(rock2Recno);
314 							sx2 = sx + rock2Info->loc_width -1;
315 							sy2 = sy + rock2Info->loc_height -1;
316 							if( rock2Info->valid_terrain(terrain_res[get_loc(sx2,sy)->terrain_id]->average_type)
317 								&& rock2Info->valid_terrain(terrain_res[get_loc(sx,sy2)->terrain_id]->average_type)
318 								&& rock2Info->valid_terrain(terrain_res[get_loc(sx2,sy2)->terrain_id]->average_type) )
319 							{
320 								add_dirt(rock2Recno, sx, sy);
321 							}
322 						}
323 					}
324 					nGrouped--;
325 				}
326 			}
327 		}
328 
329 		// generate stand-alone large dirt
330 		if( nLarge > 0 )
331 		{
332 			short x = misc.random( max_x_loc - HUGE_ROCK_SIZE);
333 			short y = misc.random( max_y_loc - HUGE_ROCK_SIZE);
334 			short x2 = x + HUGE_ROCK_SIZE -1;
335 			short y2 = y + HUGE_ROCK_SIZE -1;
336 
337 			if( can_add_dirt( x, y, x2, y2) )
338 			{
339 				short rockRecno = rock_res.search("DE", SMALL_ROCK_SIZE+1,HUGE_ROCK_SIZE,SMALL_ROCK_SIZE+1,HUGE_ROCK_SIZE,-1,0,
340 					terrain_res[get_loc(x,y)->terrain_id]->average_type );
341 				if( !rockRecno )
342 					continue;
343 
344 				RockInfo *rockInfo = rock_res.get_rock_info(rockRecno);
345 				x2 = x + rockInfo->loc_width - 1;
346 				y2 = y + rockInfo->loc_height -1;
347 				if( rockInfo->valid_terrain(terrain_res[get_loc(x2, y)->terrain_id]->average_type)
348 					&& rockInfo->valid_terrain(terrain_res[get_loc(x, y2)->terrain_id]->average_type)
349 					&& rockInfo->valid_terrain(terrain_res[get_loc(x2,y2)->terrain_id]->average_type))
350 				{
351 					add_dirt(rockRecno, x, y);
352 					nLarge--;
353 				}
354 			}
355 		}
356 
357 		// generate stand-alone small dirt
358 		if( nSmall > 0 )
359 		{
360 			short x = misc.random( max_x_loc - SMALL_ROCK_SIZE);
361 			short y = misc.random( max_y_loc - SMALL_ROCK_SIZE);
362 			short x2 = x + SMALL_ROCK_SIZE -1;
363 			short y2 = y + SMALL_ROCK_SIZE -1;
364 
365 			if( can_add_dirt( x, y, x2, y2) )
366 			{
367 				short rockRecno = rock_res.search("DE", 1,SMALL_ROCK_SIZE,1,SMALL_ROCK_SIZE,-1,0,
368 					terrain_res[get_loc(x,y)->terrain_id]->average_type );
369 				if( !rockRecno )
370 					continue;
371 
372 				RockInfo *rockInfo = rock_res.get_rock_info(rockRecno);
373 				x2 = x + rockInfo->loc_width - 1;
374 				y2 = y + rockInfo->loc_height -1;
375 				if( rockInfo->valid_terrain(terrain_res[get_loc(x2, y)->terrain_id]->average_type)
376 					&& rockInfo->valid_terrain(terrain_res[get_loc(x, y2)->terrain_id]->average_type)
377 					&& rockInfo->valid_terrain(terrain_res[get_loc(x2,y2)->terrain_id]->average_type))
378 				{
379 					add_dirt(rockRecno, x, y);
380 					nSmall--;
381 				}
382 			}
383 		}
384 	}
385 }
386 // --------- end of function World::gen_dirt ----------//
387