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    : OGENMAP.CPP
22 //Description : World Map generation function part 1
23 //Ownership   : Gilbert
24 
25 #include <time.h>
26 #include <stdlib.h>
27 
28 #include <ALL.h>
29 #include <OGAME.h>
30 #include <OVGA.h>
31 #include <OTERRAIN.h>
32 #include <OWORLD.h>
33 #include <OPLASMA.h>
34 #include <OREGION.h>
35 #include <OFIRMID.h>
36 
37 //-------- Begin of function World::generate_map ----------//
38 //
generate_map()39 void World::generate_map()
40 {
41 	const int dispProgress = 1;
42 	const int maxGenMapSteps = 14;
43 	vga_front.unlock_buf();
44 
45 	int curGenMapSteps = 0;
46 	if( dispProgress )
47 	{
48 		vga_front.lock_buf();
49 		game.disp_gen_map_status( curGenMapSteps, maxGenMapSteps, 0 );
50 		vga_front.unlock_buf();
51 	}
52 
53 	//--- loc_matrix, first store terrain height, then world map icon id ---//
54 
55    loc_matrix = (Location*) mem_resize( loc_matrix, MAX_WORLD_X_LOC * MAX_WORLD_Y_LOC * sizeof(Location) );
56 
57    max_x_loc = MAX_WORLD_X_LOC;
58 	max_y_loc = MAX_WORLD_Y_LOC;
59 /*
60 #ifdef DEBUG
61 	// testing the completeness of Ocean-DarkGrass joint //
62 	static TerrainTypeCode ta[6] = { TERRAIN_OCEAN,TERRAIN_OCEAN,TERRAIN_OCEAN,
63 		TERRAIN_DARK_GRASS,TERRAIN_DARK_GRASS,TERRAIN_DARK_GRASS };
64 	static SubTerrainMask sta[6] = { BOTTOM_MASK, MIDDLE_MASK, TOP_MASK,
65 		BOTTOM_MASK, MIDDLE_MASK, TOP_MASK };
66 	int failure = 0;
67 	int nw, ne, sw, se;
68 	for( nw = 0; nw < 6; ++nw)
69 		for( ne = 0; ne < 6; ++ne)
70 			for( sw = 0; sw < 6; ++sw)
71 				for( se = 0; se < 6; ++se)
72 	{
73 		if(!terrain_res.scan( ta[nw], sta[nw], ta[ne], sta[ne],
74 			ta[sw], sta[sw], ta[se], sta[se], 1,0,0))
75 		{
76 			TerrainTypeCode nwType=ta[nw], neType=ta[ne], swType=ta[sw], seType=ta[se];
77 			SubTerrainMask nwMask=sta[nw], neMask=sta[ne], swMask=sta[sw], seMask=sta[se];
78 			failure++;
79 		};
80 	}
81 #endif
82 */
83 
84 	//----------- start generating -----------//
85 
86 	// ---------- generate plasma map ----------//
87 
88 	Plasma heightMap;
89 	memset( loc_matrix , 0, sizeof(Location) * MAX_WORLD_X_LOC * MAX_WORLD_Y_LOC );
90 	heightMap.init(max_x_loc, max_y_loc);
91 	heightMap.generate( misc.random(2), 5, misc.rand() );
92 
93 	curGenMapSteps++;			// 1
94 	if( dispProgress )
95 	{
96 		vga_front.lock_buf();
97 		game.disp_gen_map_status( curGenMapSteps, maxGenMapSteps, 0 );
98 		vga_front.unlock_buf();
99 	}
100 
101 	// ###### begin Gilbert 27/8 ########//
102 	// ---------- add base level --------//
103 	// heightMap.add_base_level(heightMap.calc_tera_base_level(TerrainRes::min_height(TERRAIN_DARK_GRASS)));
104 
105 	// grouping plasma sample data, find sea or land first
106 	int	totalLoc = (max_x_loc+1) * (max_y_loc+1);
107 	short heightLimit[2];
108 	int	heightFreq[2];
109 	int minLandCount, maxLandCount;
110 	int	initHeightLimit = TerrainRes::min_height(TERRAIN_DARK_GRASS);
111 	switch(config.land_mass)
112 	{
113 	case OPTION_LOW:
114 		minLandCount = totalLoc *4/10;
115 		maxLandCount = totalLoc *6/10;
116 		break;
117 	case OPTION_MODERATE:
118 		minLandCount = totalLoc *6/10;
119 		maxLandCount = totalLoc *8/10;
120 		break;
121 	case OPTION_HIGH:
122 		minLandCount = totalLoc *8 /10;
123 		maxLandCount = totalLoc;
124 		break;
125 	default:
126 		err_here();
127 	}
128 	int avgLandCount = (minLandCount + maxLandCount) /2;
129 
130 	heightLimit[0] = 0;
131 	heightLimit[1] = initHeightLimit;
132 	heightMap.stat(2, heightLimit, heightFreq);
133 
134 	int& landCount = heightFreq[1];
135 	int& seaCount = heightFreq[0];
136 
137 	int loopCount = 0;
138 	while( ++loopCount <= 4 && (landCount<minLandCount || landCount>maxLandCount) )
139 	{
140 		if( landCount < minLandCount )
141 		{
142 			// positive add_base_level to gain more land
143 			// find a level between 0 to TerrainRes::min_height(TERRAIN_DARK_GRASS)
144 			// assume heightlevel below heightLimit[1] is evenly distributed,
145 			// approximate a new heightLimit[1] such that landCount is avgLandCount
146 
147 			// (heightLimit[1] - newheightLimit[1]) * seaCount / (heightLimit[1] - heightLimit[0]) + landCount = avgLandCount
148 
149 			heightLimit[1] = heightLimit[1] - (avgLandCount - landCount) * (heightLimit[1] - heightLimit[0]) / seaCount;
150 		}
151 		else if( landCount > maxLandCount )
152 		{
153 			// negative add_base_level to reduce land
154 			// find a level above TerrainRes::min_height(TERRAIN_DARK_GRASS)
155 			// assume heightlevel above heightLimit[1] is evenly distributed,
156 			// approximate a new heightLimit[1] such that landCount is avgLandCount
157 
158 			const int maxHeightLimit = 255;
159 			// landCount * (maxHeightLimit - newheightLimit[1])/ (maxHeightLimit - heightLimit[1]) = avgLandCount
160 			heightLimit[1] = maxHeightLimit - avgLandCount * (maxHeightLimit - heightLimit[1]) / landCount;
161 		}
162 		heightMap.stat(2, heightLimit, heightFreq);
163 	}
164 
165 	if( abs( heightLimit[1] - initHeightLimit ) > 2 )
166 	{
167 		heightMap.add_base_level(initHeightLimit - heightLimit[1]);
168 	}
169 
170 	curGenMapSteps++;			// 2
171 	if( dispProgress )
172 	{
173 		vga_front.lock_buf();
174 		game.disp_gen_map_status( curGenMapSteps, maxGenMapSteps, 0 );
175 		vga_front.unlock_buf();
176 	}
177 	// ###### end Gilbert 27/8 ########//
178 
179 	// --------- remove odd terrain --------//
180 
181 	for(short y = 0; y <= heightMap.max_y; ++y)
182 		for(short x = 0; x <= heightMap.max_x; ++x)
183 	{
184 		remove_odd(heightMap, x, y, 5);
185 	}
186 
187 	curGenMapSteps++;			// 3
188 	if( dispProgress )
189 	{
190 		vga_front.lock_buf();
191 		game.disp_gen_map_status( curGenMapSteps, maxGenMapSteps, 0 );
192 		vga_front.unlock_buf();
193 	}
194 
195 	// ------------ shuffle sub-terrain level ---------//
196 
197 	heightMap.shuffle_level(TerrainRes::min_height(TERRAIN_OCEAN),
198 		TerrainRes::max_height(TERRAIN_OCEAN), -3 );
199 	heightMap.shuffle_level(TerrainRes::min_height(TERRAIN_DARK_GRASS),
200 		TerrainRes::max_height(TERRAIN_DARK_GRASS), 3 );
201 	heightMap.shuffle_level(TerrainRes::min_height(TERRAIN_LIGHT_GRASS),
202 		TerrainRes::max_height(TERRAIN_LIGHT_GRASS), 3 );
203 	heightMap.shuffle_level(TerrainRes::min_height(TERRAIN_DARK_DIRT),
204 		TerrainRes::max_height(TERRAIN_DARK_DIRT), 3 );
205 
206 	curGenMapSteps++;			// 4
207 	if( dispProgress )
208 	{
209 		vga_front.lock_buf();
210 		game.disp_gen_map_status( curGenMapSteps, maxGenMapSteps, 0 );
211 		vga_front.unlock_buf();
212 	}
213 
214 	set_tera_id(heightMap);
215 	curGenMapSteps++;			// 5
216 	if( dispProgress )
217 	{
218 		vga_front.lock_buf();
219 		game.disp_gen_map_status( curGenMapSteps, maxGenMapSteps, 0 );
220 		vga_front.unlock_buf();
221 	}
222 
223 	substitute_pattern();
224 	curGenMapSteps++;			// 6
225 	if( dispProgress )
226 	{
227 		vga_front.lock_buf();
228 		game.disp_gen_map_status( curGenMapSteps, maxGenMapSteps, 0 );
229 		vga_front.unlock_buf();
230 	}
231 
232 	set_loc_flags();
233 
234 	//--------- assign the map --------//
235 
236 	assign_map();
237 	curGenMapSteps++;			// 7
238 	if( dispProgress )
239 	{
240 		vga_front.lock_buf();
241 		game.disp_gen_map_status( curGenMapSteps, maxGenMapSteps, 0 );
242 		vga_front.unlock_buf();
243 	}
244 
245 	gen_hills(TERRAIN_DARK_DIRT);
246 	curGenMapSteps++;			// 8
247 	if( dispProgress )
248 	{
249 		vga_front.lock_buf();
250 		game.disp_gen_map_status( curGenMapSteps, maxGenMapSteps, 0 );
251 		vga_front.unlock_buf();
252 	}
253 
254 	set_region_id();
255 	curGenMapSteps++;			// 9
256 	if( dispProgress )
257 	{
258 		vga_front.lock_buf();
259 		game.disp_gen_map_status( curGenMapSteps, maxGenMapSteps, 0 );
260 		vga_front.unlock_buf();
261 	}
262 
263 
264 	gen_dirt(40,30,60);
265 	curGenMapSteps++;			// 10
266 	if( dispProgress )
267 	{
268 		vga_front.lock_buf();
269 		game.disp_gen_map_status( curGenMapSteps, maxGenMapSteps, 0 );
270 		vga_front.unlock_buf();
271 	}
272 
273 	gen_rocks(5,10,30);
274 	curGenMapSteps++;		// 11
275 	if( dispProgress )
276 	{
277 		vga_front.lock_buf();
278 		game.disp_gen_map_status( curGenMapSteps, maxGenMapSteps, 0 );
279 		vga_front.unlock_buf();
280 	}
281 
282 	set_harbor_bit();
283 	curGenMapSteps++;		// 12
284 	if( dispProgress )
285 	{
286 		vga_front.lock_buf();
287 		game.disp_gen_map_status( curGenMapSteps, maxGenMapSteps, 0 );
288 		vga_front.unlock_buf();
289 	}
290 
291 	plant_init();
292 	curGenMapSteps++;		// 13
293 	if( dispProgress )
294 	{
295 		vga_front.lock_buf();
296 		game.disp_gen_map_status( curGenMapSteps, maxGenMapSteps, 0 );
297 		vga_front.unlock_buf();
298 	}
299 
300 	init_fire();
301 	curGenMapSteps++;		// 14
302 	if( dispProgress )
303 	{
304 		vga_front.lock_buf();
305 		game.disp_gen_map_status( curGenMapSteps, maxGenMapSteps, 0 );
306 		vga_front.unlock_buf();
307 	}
308 
309 /*
310 	// randomly put a fire
311 	Location *locPtr;
312 
313 	do
314 	{
315 		locPtr = zoom_matrix->get_loc(misc.random(MAX_MAP_WIDTH), misc.random(MAX_MAP_HEIGHT));
316 		if( locPtr->flammability > 0)
317 		{
318 			locPtr->fire_level = 80;
319 			break;
320 		}
321 	} while(1);
322 */
323 
324 	vga_front.lock_buf();
325 
326 	//----- debug code: validate terrain_id -----//
327 
328 	#ifdef DEBUG
329 
330 	Location* locPtr = loc_matrix;
331 
332 	for( int i=0 ; i<MAX_WORLD_X_LOC*MAX_WORLD_Y_LOC ; i++, locPtr++ )
333 	{
334 		err_when( locPtr->terrain_id < 1 ||
335 					 locPtr->terrain_id > terrain_res.terrain_count );
336 	}
337 
338 	#endif
339 
340 }
341 //---------- End of function World::generate_map ------------//
342 
343 
344 //---------- Begin of function World::set_tera_id -----------//
345 //
346 // Set terrain icon id
347 //
set_tera_id(Plasma & plasma)348 void World::set_tera_id(Plasma &plasma)
349 {
350 	//------- create a world map based on the terrain map ------//
351 
352 	memset(loc_matrix, 0, sizeof(Location)*max_x_loc*max_y_loc);
353 
354 	for( int y = 0; y < max_y_loc; ++y)
355 	{
356 		for( int x = 0; x < max_x_loc; ++x)
357 		{
358 			int nwType, neType, swType, seType;
359 			int nwSubType, neSubType, swSubType, seSubType;
360 			nwType = TerrainRes::terrain_height(plasma.get_pix(x,y), &nwSubType);
361 			neType = TerrainRes::terrain_height(plasma.get_pix(x+1,y), &neSubType);
362 			swType = TerrainRes::terrain_height(plasma.get_pix(x,y+1), &swSubType);
363 			seType = TerrainRes::terrain_height(plasma.get_pix(x+1,y+1), &seSubType);
364 
365 			if((get_loc(x,y)->terrain_id = terrain_res.scan( nwType, nwSubType,
366 				neType, neSubType, swType, swSubType, seType, seSubType ,0,1,0)) == 0)
367 			{
368 				err.run("Error World::set_tera_id, Cannot find terrain type %d:%d, %d:%d, %d:%d, %d:%d",
369 					nwType, nwSubType, neType, neSubType, swType, swSubType,
370 					seType, seSubType);
371 			}
372 		}
373 	}
374 }
375 //---------- End of function World::set_tera_id -----------//
376 
377 
378 //---------- Begin of function World::set_loc_flags -----------//
379 //
set_loc_flags()380 void World::set_loc_flags()
381 {
382 	int       i;
383 	int       totalLoc=MAX_WORLD_X_LOC*MAX_WORLD_Y_LOC;
384 	Location* locPtr=loc_matrix;
385 
386 	//----- set power_off of the map edges -----//
387 
388 	for( int xLoc=0 ; xLoc<MAX_WORLD_X_LOC ; xLoc++ )	// set the top and bottom edges
389 	{
390 		get_loc(xLoc, 0)->set_power_off();
391 		get_loc(xLoc, MAX_WORLD_Y_LOC-1)->set_power_off();
392 	}
393 
394 	for( int yLoc=0 ; yLoc<MAX_WORLD_Y_LOC ; yLoc++ )	// set the left and right edges
395 	{
396 		get_loc(0, yLoc)->set_power_off();
397 		get_loc(MAX_WORLD_X_LOC-1, yLoc)->set_power_off();
398 	}
399 
400 	//-----------------------------------------//
401 
402 	if( config.explore_whole_map )
403 	{
404 		for( i=0 ; i<totalLoc ; i++, locPtr++ )
405 		{
406 			//------- set explored flag ----------//
407 			locPtr->explored_on();
408 			if( terrain_res[locPtr->terrain_id]->is_coast() )
409 			{
410 				locPtr->loc_flag |= LOCATE_COAST;
411 				if(terrain_res[locPtr->terrain_id]->average_type!=TERRAIN_OCEAN)
412 					locPtr->set_power_off();
413 				else
414 					set_surr_power_off(i%MAX_WORLD_X_LOC, i/MAX_WORLD_X_LOC);
415 			}
416 			locPtr->walkable_reset();
417 		}
418 	}
419 	else
420 	{
421 		for( i=0 ; i<totalLoc ; i++, locPtr++ )
422 		{
423 			//------- clear explored flag ----------//
424 			locPtr->explored_off();
425 			if( terrain_res[locPtr->terrain_id]->is_coast() )
426 			{
427 				locPtr->loc_flag |= LOCATE_COAST;
428 				if(terrain_res[locPtr->terrain_id]->average_type!=TERRAIN_OCEAN)
429 					locPtr->set_power_off();
430 				else
431 					set_surr_power_off(i%MAX_WORLD_X_LOC, i/MAX_WORLD_X_LOC);
432 			}
433 			locPtr->walkable_reset();
434 		}
435 	}
436 }
437 //---------- End of function World::set_loc_flags -----------//
438 
439 
440 //---------- Begin of function World::remove_odd --------//
remove_odd(Plasma & plasma,short x,short y,short recur)441 void World::remove_odd(Plasma &plasma, short x, short y, short recur)
442 {
443 	if( recur < 0)
444 		return;
445 
446 	// -------- compare the TerrainTypeCode of four adjacent square ------//
447 	int center = TerrainRes::terrain_height(plasma.get_pix(x,y));
448 	int same = 0;
449 	int diff = 0;
450 	short diffTerrain = -1;
451 	short diffHeight;
452 	short sameX, sameY;
453 
454 	// ------- compare north square -------//
455 	if( y > 0)
456 	{
457 		if( center == TerrainRes::terrain_height(plasma.get_pix(x,y-1)) )
458 		{
459 			same++;
460 			sameX = x; sameY = y-1;
461 		}
462 		else
463 		{
464 			diff++;
465 			if( diffTerrain < 0)
466 			{
467 				// new diffHeight
468 				diffHeight = plasma.get_pix(x,y-1);
469 				diffTerrain = TerrainRes::terrain_height(diffHeight);
470 
471 			}
472 			else
473 			{
474 				// three terrain types are close, don't change anything
475 				if( diffTerrain != TerrainRes::terrain_height(plasma.get_pix(x,y-1)))
476 					return;
477 			}
478 		}
479 	}
480 
481 	// ------- compare south square -------//
482 	if( y < plasma.max_y)
483 	{
484 		if( center == TerrainRes::terrain_height(plasma.get_pix(x,y+1)) )
485 		{
486 			same++;
487 			sameX = x; sameY = y+1;
488 		}
489 		else
490 		{
491 			diff++;
492 			if( diffTerrain < 0)
493 			{
494 				// new diffHeight
495 				diffHeight = plasma.get_pix(x,y+1);
496 				diffTerrain = TerrainRes::terrain_height(diffHeight);
497 			}
498 			else
499 			{
500 				// three terrain types are close, don't change anything
501 				if( diffTerrain != TerrainRes::terrain_height(plasma.get_pix(x,y+1)))
502 					return;
503 			}
504 		}
505 	}
506 
507 		// ------- compare west square -------//
508 	if( x > 0)
509 	{
510 		if( center == TerrainRes::terrain_height(plasma.get_pix(x-1,y)) )
511 		{
512 			same++;
513 			sameX = x-1; sameY = y;
514 		}
515 		else
516 		{
517 			diff++;
518 			if( diffTerrain < 0)
519 			{
520 				// new diffHeight
521 				diffHeight = plasma.get_pix(x-1,y);
522 				diffTerrain = TerrainRes::terrain_height(diffHeight);
523 			}
524 			else
525 			{
526 				// three terrain types are close, don't change anything
527 				if( diffTerrain != TerrainRes::terrain_height(plasma.get_pix(x-1,y)))
528 					return;
529 			}
530 		}
531 	}
532 
533 	// ------- compare east square -------//
534 	if( x < plasma.max_x)
535 	{
536 		if( center == TerrainRes::terrain_height(plasma.get_pix(x+1,y)) )
537 		{
538 			same++;
539 			sameX = x+1; sameY = y;
540 		}
541 		else
542 		{
543 			diff++;
544 			if( diffTerrain < 0)
545 			{
546 				// new diffHeight
547 				diffHeight = plasma.get_pix(x+1,y);
548 				diffTerrain = TerrainRes::terrain_height(diffHeight);
549 			}
550 			else
551 			{
552 				// three terrain types are close, don't change anything
553 				if( diffTerrain != TerrainRes::terrain_height(plasma.get_pix(x+1,y)))
554 					return;
555 			}
556 		}
557 	}
558 
559 	if( same <= 1 && diff >= 2)
560 	{
561 		// flatten
562 		plasma.plot(x,y, diffHeight);
563 
564 		// propagate to next square
565 		if( same == 1)
566 		{
567 			remove_odd(plasma, sameX, sameY, recur-1);
568 		}
569 	}
570 }
571 //---------- End of function World::remove_odd --------//
572 
573 
574 //---------- Begin of function World::substitute_pattern -----//
substitute_pattern()575 void World::substitute_pattern()
576 {
577 	short terrainId;
578 	int SubFound;
579 	const unsigned int resultArraySize = 20;
580 	TerrainSubInfo *candSub[resultArraySize];
581 
582 	for( short y = 0; y < max_y_loc; ++y)
583 	{
584 		for( short x = 0; x < max_x_loc; ++x)
585 		{
586 			terrainId = get_loc(x,y)->terrain_id;
587 			SubFound = terrain_res.search_pattern(
588 				terrain_res[terrainId]->pattern_id, candSub, resultArraySize);
589 			for( int i = 0; i < SubFound; ++i)
590 			{
591 				short tx = x, ty = y;
592 				char flag = 1;
593 				TerrainSubInfo *terrainSubInfo = candSub[i];
594 
595 				// ----- test if a substitution matches
596 				for(terrainSubInfo = candSub[i]; terrainSubInfo != NULL;
597 					terrainSubInfo = terrainSubInfo->next_step)
598 				{
599 					if( tx < 0 || tx >= max_x_loc || ty < 0 || ty >= max_y_loc ||
600 						terrain_res[get_loc(tx,ty)->terrain_id]->pattern_id
601 						!= terrainSubInfo->old_pattern_id)
602 					{
603 						flag = 0;
604 						break;
605 					}
606 
607 					// ----- update tx, ty according to post_move -----//
608 					switch(terrainSubInfo->post_move)
609 					{
610 					case 1: ty--; break;				// North
611 					case 2: ty--; tx++; break;		// NE
612 					case 3: tx++; break;				// East
613 					case 4: tx++; ty++; break;		// SE
614 					case 5: ty++; break;				// South
615 					case 6: ty++; tx--; break;		// SW
616 					case 7: tx--; break;				// West
617 					case 8: tx--; ty--; break;		// NW
618 					}
619 				}
620 
621 				// ------ replace pattern -------//
622 				if(flag)
623 				{
624 					tx = x; ty = y;
625 					for(terrainSubInfo = candSub[i]; terrainSubInfo != NULL;
626 						terrainSubInfo = terrainSubInfo->next_step)
627 					{
628 						TerrainInfo *oldTerrain = terrain_res[get_loc(tx,ty)->terrain_id];
629 						if( !(get_loc(tx,ty)->terrain_id = terrain_res.scan(oldTerrain->average_type,
630 							oldTerrain->secondary_type + terrainSubInfo->sec_adj,
631 							terrainSubInfo->new_pattern_id, 0,1,0) ))
632 						{
633 							err_here();		// cannot find terrain_id
634 						}
635 
636 						// ----- update tx, ty according to post_move -----//
637 						switch(terrainSubInfo->post_move)
638 						{
639 						case 1: ty--; break;				// North
640 						case 2: ty--; tx++; break;		// NE
641 						case 3: tx++; break;				// East
642 						case 4: tx++; ty++; break;		// SE
643 						case 5: ty++; break;				// South
644 						case 6: ty++; tx--; break;		// SW
645 						case 7: tx--; break;				// West
646 						case 8: tx--; ty--; break;		// NW
647 						}
648 					}
649 					break;
650 				}
651 			}
652 		}
653 	}
654 }
655 //---------- End of function World::substitute_pattern -----//
656 
657 
658 //---------- Begin of function World::set_region_id -----//
659 // must be called before any mountain or buildings on the map
660 static RegionType walkable;					// to save stack space
661 static unsigned char regionId;
set_region_id()662 void World::set_region_id()
663 {
664 	int            i,x,y;
665 	int            totalLoc=max_x_loc * max_y_loc;
666 	Location*      locPtr=loc_matrix;
667 
668 	// -------- reset region_id to zero
669 	for( i=0 ; i<totalLoc ; i++, locPtr++ )
670 	{
671 		locPtr->region_id = 0;
672 	}
673 
674 	regionId = 0;
675 	for( y = 0; y < max_y_loc; ++y)
676 	{
677 		locPtr = get_loc(0,y);
678 		for( x = 0; x < max_x_loc; ++x, ++locPtr)
679 		{
680 			if( !locPtr->region_id && locPtr->region_type() != REGION_INPASSABLE)
681 			{
682 				walkable = locPtr->region_type();
683 				++regionId;
684 				fill_region(x,y);
685 				err_when( regionId == 255);
686 			}
687 		}
688 	}
689 
690 	region_array.init(regionId);
691 
692 	// ------ update adjacency information and region area ------//
693 
694 	regionId = 0;
695 	for( y = 0; y < max_y_loc; ++y)
696 	{
697 		locPtr = get_loc(0,y);
698 		for( x = 0; x < max_x_loc; ++x, ++locPtr)
699 		{
700 			int thisRegionId = locPtr->region_id;
701 			// #### begin Gilbert 19/2 ######//
702 			if( thisRegionId > 0)
703 			{
704 				region_array.inc_size( thisRegionId );
705 			}
706 			// #### end Gilbert 19/2 ######//
707 			if( thisRegionId > regionId)
708 			{
709 				if(thisRegionId == regionId+1)
710 					regionId++;
711 				region_array.set_region( thisRegionId, locPtr->region_type());
712 			}
713 
714 			int adjRegionId;
715 			if( y > 0)
716 			{
717 				if( x > 0 && (adjRegionId = get_loc(x-1,y-1)->region_id) < thisRegionId )
718 					region_array.set_adjacent( thisRegionId, adjRegionId);
719 				if( (adjRegionId = get_loc(x,y-1)->region_id) < thisRegionId )
720 					region_array.set_adjacent( thisRegionId, adjRegionId);
721 				if( x < max_x_loc-1 && (adjRegionId = get_loc(x+1,y-1)->region_id) < thisRegionId )
722 					region_array.set_adjacent( thisRegionId, adjRegionId);
723 			}
724 
725 			if( x > 0 && (adjRegionId = get_loc(x-1,y)->region_id) < thisRegionId )
726 				region_array.set_adjacent( thisRegionId, adjRegionId);
727 			if( x < max_x_loc-1 && (adjRegionId = get_loc(x+1,y)->region_id) < thisRegionId )
728 				region_array.set_adjacent( thisRegionId, adjRegionId);
729 
730 			if( y < max_y_loc-1)
731 			{
732 				if( x > 0 && (adjRegionId = get_loc(x-1,y+1)->region_id) < thisRegionId )
733 					region_array.set_adjacent( thisRegionId, adjRegionId);
734 				if( (adjRegionId = get_loc(x,y+1)->region_id) < thisRegionId )
735 					region_array.set_adjacent( thisRegionId, adjRegionId);
736 				if( x < max_x_loc-1 && (adjRegionId = get_loc(x+1,y+1)->region_id) < thisRegionId )
737 					region_array.set_adjacent( thisRegionId, adjRegionId);
738 			}
739 		}
740 	}
741 
742    //---- sort the region after setting its size ----//
743 
744 	region_array.sort_region();
745 
746 	//-------- initialize region_stat_array ----------//
747 
748 	region_array.init_region_stat();
749 }
750 //---------- End of function World::set_region_id -----//
751 
752 
753 //---------- Begin of function World::fill_region -----//
fill_region(short x,short y)754 void World::fill_region(short x, short y)
755 {
756 	err_when( x < 0 || x >= max_x_loc || y < 0 || y >= max_y_loc);
757 
758 	short left, right;
759 	// Location *locPtr;
760 
761 	// extent x to left and right
762 	for( left = x; left >= 0 && !get_loc(left,y)->region_id && get_loc(left,y)->region_type() == walkable; --left)
763 	{
764 		get_loc(left,y)->region_id = regionId;
765 	}
766 	++left;
767 
768 	for( right=x+1; right < max_x_loc && !get_loc(right,y)->region_id && get_loc(right,y)->region_type() == walkable; ++right)
769 	{
770 		get_loc(right,y)->region_id = regionId;
771 	}
772 	--right;
773 
774 	// ------- scan line below ---------//
775 	y++;
776 	if( y < max_y_loc )
777 	{
778 		for( x = left>0?left-1:0 ; x <= right+1 && x < max_x_loc; ++x )
779 		{
780 			if( !get_loc(x,y)->region_id && get_loc(x,y)->region_type() == walkable)
781 			{
782 				fill_region(x,y);
783 			}
784 		}
785 	}
786 
787 	// ------- scan line above -------- //
788 	y -= 2;
789 	if( y >= 0)
790 	{
791 		for( x = left>0?left-1:0 ; x <= right+1 && x < max_x_loc; ++x )
792 		{
793 			if( !get_loc(x,y)->region_id && get_loc(x,y)->region_type() == walkable)
794 			{
795 				fill_region(x,y);
796 			}
797 		}
798 	}
799 }
800 //---------- End of function World::fill_region -----//
801 
802 
803 //---------- Begin of function World::set_harbor_bit -----//
set_harbor_bit()804 void World::set_harbor_bit()
805 {
806 	// a pass during genmap to set LOCATE_HARBOR_BIT
807 	// notice this bit is only a necessary condition to build harbor
808 	int x,y;
809 	Location *locPtr;
810 	for( y = 0; y < max_y_loc-2; ++y)
811 	{
812 		locPtr = get_loc(0,y);
813 		for( x = 0; x < max_x_loc-2; ++x, ++locPtr)
814 		{
815 			if( can_build_firm(x, y, FIRM_HARBOR))
816 			{
817 				locPtr->set_harbor_bit();
818 			}
819 		}
820 	}
821 }
822 //---------- End of function World::set_harbor_bit -----//
823