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