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    : OWORLD.CPP
22 //Description : Object World
23 
24 #include <OSYS.h>
25 #include <OGAME.h>
26 #include <OVGA.h>
27 #include <OFONT.h>
28 #include <OMOUSE.h>
29 #include <OMOUSECR.h>
30 #include <OFIRMRES.h>
31 #include <OPLANT.h>
32 #include <OPOWER.h>
33 #include <OSITE.h>
34 #include <OINFO.h>
35 #include <OTOWN.h>
36 #include <ONATION.h>
37 #include <OWEATHER.h>
38 #include <OTERRAIN.h>
39 #include <OWORLD.h>
40 #include <OANLINE.h>
41 #include <OTORNADO.h>
42 #include <OU_VEHI.h>
43 #include <OSERES.h>
44 #include <OREMOTE.h>
45 #include <ONEWS.h>
46 
47 
48 //------------ Define static class variables ------------//
49 
50 short World::view_top_x, World::view_top_y;
51 int   World::max_x_loc=200, World::max_y_loc=200;
52 
53 //----------- Begin of function World::World ----------//
54 
World()55 World::World()
56 {
57 	loc_matrix = NULL;
58 	next_scroll_time = 0;
59 	scan_fire_x = 0;
60 	scan_fire_y = 0;
61 	lightning_signal = 0;
62 	plant_count = 0;
63 	plant_limit = 0;
64 
65    //------- initialize matrix objects -------//
66 
67    map_matrix  = new MapMatrix;
68    zoom_matrix = new ZoomMatrix;
69 }
70 //------------- End of function World::World -----------//
71 
72 
73 //----------- Begin of function World::~World ----------//
74 
~World()75 World::~World()
76 {
77    if( map_matrix )
78 	{
79       delete map_matrix;
80       map_matrix = NULL;
81    }
82 
83    if( zoom_matrix )
84    {
85       delete zoom_matrix;
86       zoom_matrix = NULL;
87    }
88 
89    deinit();
90 }
91 //------------- End of function World::~World -----------//
92 
93 
94 //----------- Begin of function World::init ----------//
95 
init()96 void World::init()
97 {
98 	//----------- initialize vars -------------//
99 
100 	scan_fire_x = 0;
101 	scan_fire_y = 0;
102 	lightning_signal = 0;
103 
104 	map_matrix->init_para();
105 	zoom_matrix->init_para();
106 }
107 //------------- End of function World::init -----------//
108 
109 
110 //----------- Begin of function World::deinit ----------//
111 
deinit()112 void World::deinit()
113 {
114    if( loc_matrix )
115    {
116       mem_del( loc_matrix );
117       loc_matrix  = NULL;
118    }
119 }
120 //------------- End of function World::deinit -----------//
121 
122 
123 //--------- Begin of function World::assign_map ----------//
124 //
125 // After a map is loaded, assign_map() need to be called to
126 // initial map_matrix and zoom_matrix
127 //
assign_map()128 void World::assign_map()
129 {
130 	//------------- assign map -------------//
131 
132    map_matrix-> assign_map(loc_matrix, max_x_loc, max_y_loc );
133 	zoom_matrix->assign_map(loc_matrix, max_x_loc, max_y_loc );
134 
135    //-------- set the zoom area box on map matrix ------//
136 
137    map_matrix->cur_x_loc = 0;
138    map_matrix->cur_y_loc = 0;
139    map_matrix->cur_cargo_width  = zoom_matrix->disp_x_loc;
140    map_matrix->cur_cargo_height = zoom_matrix->disp_y_loc;
141 }
142 //----------- End of function World::assign_map ----------//
143 
144 
145 //----------- Begin of function World::paint ------------//
146 //
147 // Paint world window and scroll bars
148 //
paint()149 void World::paint()
150 {
151    map_matrix->paint();
152    zoom_matrix->paint();
153 }
154 //----------- End of function World::paint ------------//
155 
156 
157 //----------- Begin of function World::refresh ------------//
158 //
refresh()159 void World::refresh()
160 {
161    map_matrix->refresh();
162    zoom_matrix->refresh();
163 }
164 //----------- End of function World::refresh ------------//
165 
166 
167 //----------- Begin of function World::process ------------//
168 //
169 // Called every frame
170 //
process()171 void World::process()
172 {
173 	//-------- process wall ----------//
174 
175 	form_world_wall();
176 
177 	//-------- process fire -----------//
178 
179 	// BUGHERE : set Location::flammability for every change in cargo
180 
181 	world.spread_fire(weather);
182 
183 	// ------- process visibility --------//
184 	process_visibility();
185 
186 	//-------- process lightning ------//
187 	// ###### begin Gilbert 11/8 ########//
188 	if(lightning_signal== 0 && weather.is_lightning())
189 	{
190 		// ------- create new lightning ----------//
191 		lightning_signal = 110;
192 	}
193 	if( lightning_signal == 106 && config.weather_effect)
194 	{
195 		lightning_strike(misc.random(MAX_MAP_WIDTH), misc.random(MAX_MAP_HEIGHT), 1);
196 	}
197 	if(lightning_signal == 100)
198 		lightning_signal = 5 + misc.random(10);
199 	else if( lightning_signal)
200 		lightning_signal--;
201 	// ###### end Gilbert 11/8 ########//
202 
203 	//---------- process ambient sound ---------//
204 
205 	if( sys.frame_count%10 == 0 )    // process once per ten frames
206 		process_ambient_sound();
207 
208 	// --------- update scan fire x y ----------//
209 	if(++scan_fire_x >= SCAN_FIRE_DIST)
210 	{
211 		scan_fire_x = 0;
212 		if( ++scan_fire_y >= SCAN_FIRE_DIST)
213 			scan_fire_y =0;
214 	}
215 
216 }
217 //----------- End of function World::process ------------//
218 
219 
220 //----------- Begin of function World::next_day ------------//
221 //
222 // Called every frame
223 //
next_day()224 void World::next_day()
225 {
226    plant_ops();
227 
228    weather = weather_forecast[0];
229 
230 	for(int foreDay=0; foreDay < MAX_WEATHER_FORECAST-1; ++foreDay)
231    {
232       weather_forecast[foreDay] = weather_forecast[foreDay+1];
233    }
234 
235    weather_forecast[MAX_WEATHER_FORECAST-1].next_day();
236 
237 	// ####### begin Gilbert 11/7 #########//
238 	magic_weather.next_day();
239 	// ####### end Gilbert 11/7 #########//
240 
241 	if(weather.has_tornado() && config.weather_effect)
242 	{
243 		tornado_array.add_tornado(weather.tornado_x_loc(max_x_loc, max_y_loc),
244 			weather.tornado_y_loc(max_x_loc, max_y_loc), 600);
245 	}
246 
247 	// ######## begin Gilbert 31/7 #######//
248 	if( weather.is_quake() && config.random_event_frequency)
249 	// ######## end Gilbert 31/7 #######//
250 	{
251 		earth_quake();
252 	}
253 
254 	//-------- Debug code: BUGHERE ----------//
255 
256 	#ifdef DEBUG
257 
258 	Location* locPtr = loc_matrix;
259 
260 	for( int y=0 ; y<MAX_WORLD_Y_LOC ; y++ )
261 	{
262 		for( int x=0 ; x<MAX_WORLD_X_LOC ; x++ )
263 		{
264 			if( locPtr->has_unit(UNIT_LAND) )
265 			{
266 				err_when( unit_array.is_truly_deleted( locPtr->unit_recno(UNIT_LAND) ) );
267 			}
268 
269 			locPtr++;
270 		}
271 	}
272 
273 	#endif
274 }
275 //----------- End of function World::next_day ------------//
276 
277 
278 //----------- Begin of function World::detect ------------//
279 //
280 // Detect mouse action from user
281 //
282 // Return : 1 - mouse pressed on World area
283 //          0 - mouse not pressed on World area
284 //
detect()285 int World::detect()
286 {
287    if( map_matrix->detect() )
288       return 1;
289 
290    if( zoom_matrix->detect() )
291       return 1;
292 
293 	if( detect_scroll() )
294 		return 1;
295 
296 	// ##### begin Gilbert 16/9 #######//
297 	// return detect_firm_town();
298 	return 0;
299 	// ##### end Gilbert 16/9 #######//
300 }
301 //----------- End of function World::detect ------------//
302 
303 
304 //--------- Begin of function World::detect_scroll ---------//
305 //
306 // Detect if the mouse cursor is pushed towards the border
307 // of the screen to scroll the zoom window.
308 //
detect_scroll()309 int World::detect_scroll()
310 {
311    int scroll_x = 0, scroll_y = 0;
312    if( !vga.is_input_grabbed() && !mouse.get_scroll(&scroll_x, &scroll_y))
313       return 0;
314 
315    if( mouse_cursor.frame_flag )    // if it's now in frame selection mode
316       return 0;
317 
318    if( next_scroll_time && misc.get_time() < next_scroll_time )      // just scrolled not too long ago, wait for a little while before next scroll.
319       return 0;
320 
321    int rc=0;
322 
323    if ( scroll_x || scroll_y )
324    {
325        zoom_matrix->scroll(scroll_x, scroll_y);
326        rc = 1;
327    }
328    else
329    {
330        //----- scroll left -----//
331 
332        if (mouse.cur_x <= mouse.bound_x1) {
333            zoom_matrix->scroll(-1, 0);
334            rc = 1;
335        }
336 
337        //---- scroll right -----//
338 
339        if (mouse.cur_x >= mouse.bound_x2) {
340            zoom_matrix->scroll(1, 0);
341            rc = 1;
342        }
343 
344        //---- scroll top -------//
345 
346        if (mouse.cur_y <= mouse.bound_y1) {
347            zoom_matrix->scroll(0, -1);
348            rc = 1;
349        }
350 
351        //---- scroll bottom ----//
352 
353        if (mouse.cur_y >= mouse.bound_y2) {
354            zoom_matrix->scroll(0, 1);
355            rc = 1;
356        }
357 
358        //----- set next scroll time based on scroll_speed -----//
359        //
360        // slowest scroll speed: 500/1  = 500 milliseconds or 1/2 second
361        // fastest scroll speed: 500/10 = 50  milliseconds or 1/20 second
362        //
363        //------------------------------------------------------//
364    }
365 
366    if( rc )
367    {
368       sys.zoom_need_redraw = 1;        // ask the zoom window to refresh next time
369       next_scroll_time     = misc.get_time() + 500/(config.scroll_speed+1);
370    }
371 
372    return rc;
373 }
374 //----------- End of function World::detect_scroll -----------//
375 
376 
377 //--------- Begin of function World::go_loc --------//
378 //
379 // Go to a specified location.
380 //
381 // <int> xLoc, yLoc - location to go to.
382 // [int] selectFlag - whether should the object on the location if
383 //							 there is one. (default: 0)
384 //
go_loc(int xLoc,int yLoc,int selectFlag)385 void World::go_loc(int xLoc, int yLoc, int selectFlag)
386 {
387 	//------- set location ---------//
388 
389 	zoom_matrix->cur_x_loc = xLoc;
390 	zoom_matrix->cur_y_loc = yLoc;
391 
392 	map_matrix->cur_x_loc = xLoc - zoom_matrix->disp_x_loc/2;
393 	map_matrix->cur_y_loc = yLoc - zoom_matrix->disp_y_loc/2;
394 
395 	//--------- refresh ------------//
396 
397 	map_matrix->valid_cur_box();
398 
399 	zoom_matrix->top_x_loc = map_matrix->cur_x_loc;
400 	zoom_matrix->top_y_loc = map_matrix->cur_y_loc;
401 
402 	sys.zoom_need_redraw = 1;
403 
404 	//---- if should select the object on the location ----//
405 
406 	if( selectFlag )
407 	{
408 		Location* locPtr = world.get_loc(xLoc, yLoc);
409 
410 		if( locPtr->has_any_unit() )
411 		{
412 			int mobileType;
413 			int unitRecno = locPtr->get_any_unit( mobileType );
414 
415 			power.reset_selection();
416 
417 			unit_array[unitRecno]->selected_flag = 1;
418 			unit_array.selected_recno = unitRecno;
419 			unit_array.selected_count++;
420 		}
421 		else if( locPtr->is_firm() )
422 		{
423 			int firmRecno = locPtr->firm_recno();
424 
425 			power.reset_selection();
426 
427 			firm_array.selected_recno = firmRecno;
428 			firm_array[firmRecno]->sort_worker();
429 		}
430 		else if( locPtr->is_town() )
431 		{
432 			power.reset_selection();
433 			town_array.selected_recno = locPtr->town_recno();
434 		}
435 		else if( locPtr->has_site() )
436 		{
437 			power.reset_selection();
438 			site_array.selected_recno = locPtr->site_recno();
439 		}
440 	}
441 
442 	//------- refresh the display -------//
443 
444 	info.disp();
445 }
446 //----------- End of function World::go_loc --------//
447 
448 
449 //-------- Begin of function World::unveil ---------//
450 //
451 // Unveil all surrounding areas of the given object.
452 //
453 // <int> xLoc1, yLoc1 = the position of the object.
454 // <int> xLoc2, yLoc2 = the position of the object.
455 //
unveil(int xLoc1,int yLoc1,int xLoc2,int yLoc2)456 void World::unveil(int xLoc1, int yLoc1, int xLoc2, int yLoc2)
457 {
458 	if( config.explore_whole_map )
459 		return;
460 
461 	xLoc1 = MAX( 0, xLoc1 - EXPLORE_RANGE);
462 	yLoc1 = MAX( 0, yLoc1 - EXPLORE_RANGE);
463 	xLoc2 = MIN( MAX_WORLD_X_LOC-1, xLoc2 + EXPLORE_RANGE);
464 	yLoc2 = MIN( MAX_WORLD_Y_LOC-1, yLoc2 + EXPLORE_RANGE);
465 
466 	explore( xLoc1, yLoc1, xLoc2, yLoc2 );
467 }
468 //--------- End of function World::unveil ---------//
469 
470 
471 //-------- Begin of function World::explore ---------//
472 //
473 // Explore a specific area. No further exploration around the area.
474 //
475 // <int> xLoc1, yLoc1 = the position of the area.
476 // <int> xLoc2, yLoc2 = the position of the area.
477 //
explore(int xLoc1,int yLoc1,int xLoc2,int yLoc2)478 void World::explore(int xLoc1, int yLoc1, int xLoc2, int yLoc2)
479 {
480 	if( config.explore_whole_map )
481 		return;
482 
483 	int 		 xLoc, yLoc;
484 	Location* locPtr;
485 	char* 	 imageBuf = map_matrix->save_image_buf + sizeof(short)*2;
486 	char*     nationColorArray = nation_array.nation_power_color_array;
487 	char* 	 writePtr;
488 
489 	int		shadowMapDist = max_x_loc + 1;
490 	int		tileYOffset;
491 	Location	*northWestPtr;
492 	char		tilePixel;
493 
494 	for( yLoc=yLoc1 ; yLoc<=yLoc2 ; yLoc++ )
495 	{
496 		locPtr = get_loc(xLoc1, yLoc);
497 
498 		for( xLoc=xLoc1 ; xLoc<=xLoc2 ; xLoc++, locPtr++ )
499 		{
500 			if( !locPtr->explored() )
501 			{
502 				locPtr->explored_on();
503 
504 				//-------- draw pixel ----------//
505 
506 				writePtr = imageBuf+MAP_WIDTH*yLoc+xLoc;
507 
508 				switch( world.map_matrix->map_mode )
509 				{
510 					case MAP_MODE_TERRAIN:
511 						if( locPtr->fire_str() > 0)
512 							*writePtr = (char) FIRE_COLOR;
513 
514 						else if( locPtr->is_plant() )
515 							*writePtr = plant_res.plant_map_color;
516 
517 						else
518 						{
519 							tileYOffset = (yLoc & TERRAIN_TILE_Y_MASK) * TERRAIN_TILE_WIDTH;
520 
521 							tilePixel = terrain_res.get_map_tile(locPtr->terrain_id)[tileYOffset + (xLoc & TERRAIN_TILE_X_MASK)];
522 
523 							if( xLoc == 0 || yLoc == 0)
524 							{
525 								*writePtr = tilePixel;
526 							}
527 							else
528 							{
529 								northWestPtr = locPtr - shadowMapDist;
530 								if( (terrain_res[locPtr->terrain_id]->average_type >=
531 									terrain_res[northWestPtr->terrain_id]->average_type) )
532 								{
533 									*writePtr = tilePixel;
534 								}
535 								else
536 								{
537 									*writePtr = (char) VGA_GRAY;
538 								}
539 							}
540 							break;
541 						}
542 						break;
543 
544 					case MAP_MODE_SPOT:
545 						if( locPtr->sailable() )
546 							*writePtr = (char) 0x32;
547 
548 						else if( locPtr->has_hill() )
549 							*writePtr = (char) V_BROWN;
550 
551 						else if( locPtr->is_plant() )
552 							*writePtr = (char) V_DARK_GREEN;
553 
554 						else
555 							*writePtr = (char) VGA_GRAY+10;
556 						break;
557 
558 					case MAP_MODE_POWER:
559 						if( locPtr->sailable() )
560 							*writePtr = (char) 0x32;
561 
562 						else if( locPtr->has_hill() )
563 							*writePtr = (char) V_BROWN;
564 
565 						else if( locPtr->is_plant() )
566 							*writePtr = (char) V_DARK_GREEN;
567 
568 						else
569 							*writePtr = nationColorArray[locPtr->power_nation_recno];
570 						break;
571 				}
572 
573 				//---- if the command base of the opponent revealed, establish contact ----//
574 
575 				if( locPtr->is_firm() )
576 				{
577 					Firm* firmPtr = firm_array[locPtr->firm_recno()];
578 
579 					if( firmPtr->nation_recno > 0 && nation_array.player_recno )
580 					{
581 						NationRelation *relation = (~nation_array)->get_relation(firmPtr->nation_recno);
582 
583 						if( !relation->has_contact )
584 						{
585 							if( !remote.is_enable() )
586 							{
587 								(~nation_array)->establish_contact(firmPtr->nation_recno);
588 							}
589 							else
590 							{
591 								if( !relation->contact_msg_flag )
592 								{
593 									// packet structure : <player nation> <explored nation>
594 									short *shortPtr = (short *)remote.new_send_queue_msg(MSG_NATION_CONTACT, 2*sizeof(short));
595 									*shortPtr = nation_array.player_recno;
596 									shortPtr[1] = firmPtr->nation_recno;
597 									relation->contact_msg_flag = 1;
598 								}
599 							}
600 						}
601 					}
602 				}
603 
604 				if( locPtr->is_town() )
605 				{
606 					Town* townPtr = town_array[locPtr->town_recno()];
607 
608 					if( townPtr->nation_recno > 0 && nation_array.player_recno )
609 					{
610 						NationRelation *relation = (~nation_array)->get_relation(townPtr->nation_recno);
611 
612 						if( !relation->has_contact )
613 						{
614 							if( !remote.is_enable() )
615 							{
616 								(~nation_array)->establish_contact(townPtr->nation_recno);
617 							}
618 							else
619 							{
620 								if( !relation->contact_msg_flag )
621 								{
622 									// packet structure : <player nation> <explored nation>
623 									short *shortPtr = (short *)remote.new_send_queue_msg(MSG_NATION_CONTACT, 2*sizeof(short));
624 									*shortPtr = nation_array.player_recno;
625 									shortPtr[1] = townPtr->nation_recno;
626 									relation->contact_msg_flag = 1;
627 								}
628 							}
629 						}
630 					}
631 				}
632 			}
633 		}
634 	}
635 }
636 //--------- End of function World::explore ---------//
637 
638 
639 //-------- Begin of function World::is_explored ---------//
640 //
641 // Check if the whole area has been explored or not.
642 //
643 // <int> xLoc1, yLoc1 = the coordination of the area to explore
644 // <int> xLoc2, yLoc2 = the coordination of the area to explore
645 //
is_explored(int xLoc1,int yLoc1,int xLoc2,int yLoc2)646 int World::is_explored(int xLoc1, int yLoc1, int xLoc2, int yLoc2)
647 {
648 	if( config.explore_whole_map )
649       return 1;
650 
651    int xLoc, yLoc;
652    Location* locPtr;
653 
654    for( yLoc=yLoc1 ; yLoc<=yLoc2 ; yLoc++ )
655    {
656       locPtr = get_loc(xLoc1, yLoc);
657 
658       for( xLoc=xLoc1 ; xLoc<=xLoc2 ; xLoc++, locPtr++ )
659       {
660          if( !locPtr->explored() )
661             return 0;
662       }
663    }
664 
665    return 1;
666 }
667 //--------- End of function World::is_explored ---------//
668 
669 
670 //----------- Begin of function World::load_map ------------//
671 //
672 // Load a custom map file.
673 //
load_map(char * fileName)674 void World::load_map(char* fileName)
675 {
676    generate_map();
677 
678    return;
679 
680    //---------- initialize the map matrix --------//
681 
682    max_x_loc = 200;
683    max_y_loc = 200;
684 
685    loc_matrix = (Location*) mem_resize( loc_matrix  , max_x_loc * max_y_loc * sizeof(Location) );
686 
687    memset( loc_matrix, 0, sizeof(Location) * max_x_loc * max_y_loc );
688 
689    int baseType = TERRAIN_DARK_DIRT;
690 
691    int terrainId    = terrain_res.scan(baseType, MIDDLE_MASK, baseType, MIDDLE_MASK,
692 					  		 baseType, MIDDLE_MASK, baseType, MIDDLE_MASK, 1);     // 1-get the first instance
693 
694    for( int i=0 ; i<max_x_loc*max_y_loc ; i++ )
695    {
696       loc_matrix[i].terrain_id = terrainId+misc.random(3);
697    }
698 
699    assign_map();
700 
701    return;
702 
703    //---------- initialize the map matrix --------//
704 
705    max_x_loc = 120;
706    max_y_loc = 120;
707 
708    loc_matrix = (Location*) mem_resize( loc_matrix  , max_x_loc * max_y_loc * sizeof(Location) );
709 
710    //-------------- read in the map -------------//
711 
712    File mapFile;
713 
714    mapFile.file_open(fileName);
715 
716    mapFile.file_read(loc_matrix, sizeof(Location)*MAX_WORLD_X_LOC*MAX_WORLD_Y_LOC );
717 
718    mapFile.file_close();
719 
720    //----- assign the map to MapMatrix and ZoomMatrix -----//
721 
722    assign_map();
723 }
724 //----------- End of function World::load_map ------------//
725 
726 
727 //-------- Begin of function World::check_unit_space ------//
728 //
729 // To check whether or not the area bounded by the upper left
730 // corner (xLoc1, yLoc1) and lower right corner (xLoc2, yLoc2)
731 // can be built.
732 //
733 // <int>  xLoc1          = the upper left x
734 // <int>  yLoc1          = the upper left y
735 // <int>  xLoc2          = the lower right x
736 // <int>  yLoc2          = the lower right y
737 // [int]  mobileType		 = mobile type (default: UNIT_LAND)
738 // [int]  buildFlag 		 = whether the located area is for building a firm/town
739 //									if so, the location must no have any raw site.
740 //									(default: 0)
741 //
742 // return 1 for true. 0 for false
743 //
check_unit_space(int xLoc1,int yLoc1,int xLoc2,int yLoc2,int mobileType,int buildFlag)744 inline int World::check_unit_space(int xLoc1, int yLoc1, int xLoc2, int yLoc2, int mobileType, int buildFlag)
745 {
746 	if(xLoc1<0 || xLoc1>=MAX_WORLD_X_LOC)
747 		return 0;
748 	if(yLoc1<0 || yLoc1>=MAX_WORLD_Y_LOC)
749 		return 0;
750 	if(xLoc2<0 || xLoc2>=MAX_WORLD_X_LOC)
751 		return 0;
752 	if(yLoc2<0 || yLoc2>=MAX_WORLD_Y_LOC)
753 		return 0;
754 
755 	Location* locPtr = world.get_loc(xLoc1, yLoc1);
756 	int x, y;
757 	int canBuildFlag = 1;
758 
759 	for(y=yLoc1; y<=yLoc2; y++)
760 	{
761 		locPtr = world.get_loc(xLoc1, y);
762 
763 		for(x=xLoc1; x<=xLoc2; x++, locPtr++)
764 		{
765 			if( !locPtr->can_move(mobileType) ||
766 				 ( buildFlag && (locPtr->is_power_off() || locPtr->has_site()) ) ) 		// if build a firm/town, there must not be any sites in the area
767 			{
768 				canBuildFlag=0;
769 				break;
770 			}
771 		}
772 
773 		if(canBuildFlag==0)
774 			break;
775 	}
776 
777 	if( canBuildFlag )
778 		return 1;
779 	else
780 		return 0;
781 }
782 //-------- End of function World::check_unit_space ------//
783 
784 
785 //-------- Begin of function World::locate_space ------//
786 //
787 // Locate an area in the world map around the firm to place
788 // the unit
789 //
790 // <int*> xLoc1          = the upper left x location of the building, also for returning the result location
791 // <int*> yLoc1          = the upper left y location of the building
792 // <int>  xLoc2          = the lower right x location of the building
793 // <int>  yLoc2          = the lower right y location of the building
794 // <int>  spaceLocWidth  = the location width of the required space
795 // <int>  spaceLocHeight = the location height of the required space
796 // [int]  mobileType		 = mobile type (default: UNIT_LAND)
797 // [int]  regionId		 = specify the region no. of the location to locate
798 //									(default: region no. of xLoc1, yLoc1)
799 // [int]  buildFlag 		 = whether the located area is for building a firm/town
800 //									if so, the location must not have any raw site.
801 //									(default: 0)
802 //
803 // return : <int> 1 - free space found
804 //                0 - free space not found
805 //
locate_space(int * pxLoc1,int * pyLoc1,int xLoc2,int yLoc2,int spaceLocWidth,int spaceLocHeight,int mobileType,int regionId,int buildFlag)806 int World::locate_space(int* pxLoc1, int* pyLoc1, int xLoc2, int yLoc2,
807 								int spaceLocWidth, int spaceLocHeight, int mobileType, int regionId, int buildFlag)
808 {
809 	int &xLoc1 = *pxLoc1, &yLoc1 = *pyLoc1;
810 
811 	if( !regionId )
812 		regionId = get_loc(xLoc1, yLoc1)->region_id;
813 
814 	int isPlateau = get_loc(xLoc1, yLoc1)->is_plateau();
815 
816 	//-----------------------------------------------------------//
817 	// xLoc, yLoc is the adjusted upper left corner location of
818 	// the firm. with the adjustment, it is easier to do the following
819 	// checking.
820 	//-----------------------------------------------------------//
821 
822 	Location* locPtr;
823 	int xLoc = xLoc1 - spaceLocWidth + 1;
824 	int yLoc = yLoc1 - spaceLocHeight + 1;
825 
826 	if(xLoc < 0)
827 		xLoc = 0;
828 	if(yLoc < 0)
829 		yLoc = 0;
830 
831 	int width   = xLoc2 - xLoc + 1;
832 	int height  = yLoc2 - yLoc + 1;
833 	int loopCount=0;
834 
835 	while(1)
836 	{
837 		err_when( ++loopCount > MAX_WORLD_X_LOC * MAX_WORLD_Y_LOC * 4 );
838 
839 		//-----------------------------------------------------------//
840 		// step 1
841 		//-----------------------------------------------------------//
842 		int xOffset = width/2;
843 		int yOffset = height;
844 		int x, y;
845 
846 		x = xLoc + xOffset;
847 		y = yLoc + yOffset;
848 
849 		if(x>=0 && y>=0 && x+spaceLocWidth-1<MAX_WORLD_X_LOC && y+spaceLocHeight-1<MAX_WORLD_Y_LOC)
850 		{
851 			if(mobileType==UNIT_LAND || (x%2==0 && y%2==0))
852 			{
853 				locPtr = get_loc(x,y);
854 
855 				if( locPtr->region_id == regionId &&
856 					 locPtr->is_plateau() == isPlateau &&
857 					 check_unit_space(x, y, x+spaceLocWidth-1, y+spaceLocHeight-1, mobileType, buildFlag))
858 				{
859 					xLoc1 = x;
860 					yLoc1 = y;
861 					return 1;
862 				}
863 			}
864 		}
865 
866 		int sign = -1;
867 		int i, j, k, limit;
868 
869 		//-----------------------------------------------------------//
870 		// step 2
871 		//-----------------------------------------------------------//
872 		//y = yLoc + yOffset;
873 		limit = width + 2;
874 		for(i=1; i<limit; i++)
875 		{
876 			xOffset += sign * i;
877 			x = xLoc + xOffset;
878 
879 			if(x>=0 && y>=0 && x+spaceLocWidth-1<MAX_WORLD_X_LOC && y+spaceLocHeight-1<MAX_WORLD_Y_LOC)
880 			{
881 				if(mobileType==UNIT_LAND || (x%2==0 && y%2==0))
882 				{
883 					locPtr = get_loc(x,y);
884 
885 					if( locPtr->region_id == regionId &&
886 						 locPtr->is_plateau() == isPlateau &&
887 						 check_unit_space(x, y, x+spaceLocWidth-1, y+spaceLocHeight-1, mobileType, buildFlag))
888 					{
889 						xLoc1 = x;
890 						yLoc1 = y;
891 						return 1;
892 					}
893 				}
894 			}
895 
896 			sign *= -1;
897 		}
898 
899 		//-----------------------------------------------------------//
900 		// step 3
901 		//-----------------------------------------------------------//
902 		i = limit-1;
903 
904 		limit = (height+1)*2;
905 		int r = sign*i;
906 		int lastX = xOffset;
907 		//int lastY = yOffset;
908 
909 		for(j=0; j<limit; j++)
910 		{
911 			if(j%2)
912 			{
913 				//x = xLoc + lastX;
914 				xOffset = lastX;
915 				x = xLoc + xOffset;
916 				//y = yLoc + yOffset;
917 
918 				if(x>=0 && y>=0 && x+spaceLocWidth-1<MAX_WORLD_X_LOC && y+spaceLocHeight-1<MAX_WORLD_Y_LOC)
919 				{
920 					if(mobileType==UNIT_LAND || (x%2==0 && y%2==0))
921 					{
922 						locPtr = get_loc(x,y);
923 
924 						if( locPtr->region_id == regionId &&
925 							 locPtr->is_plateau() == isPlateau &&
926 							 check_unit_space(x, y, x+spaceLocWidth-1, y+spaceLocHeight-1, mobileType, buildFlag))
927 						{
928 							xLoc1 = x;
929 							yLoc1 = y;
930 							return 1;
931 						}
932 					}
933 				}
934 			}
935 			else
936 			{
937 				xOffset = lastX + r;
938 				yOffset--;
939 
940 				x = xLoc + xOffset;
941 				y = yLoc + yOffset;
942 
943 				if(x>=0 && y>=0 && x+spaceLocWidth-1<MAX_WORLD_X_LOC && y+spaceLocHeight-1<MAX_WORLD_Y_LOC)
944 				{
945 					if(mobileType==UNIT_LAND || (x%2==0 && y%2==0))
946 					{
947 						locPtr = get_loc(x,y);
948 
949 						if( locPtr->region_id == regionId &&
950 							 locPtr->is_plateau() == isPlateau &&
951 							 check_unit_space(x, y, x+spaceLocWidth-1, y+spaceLocHeight-1, mobileType, buildFlag))
952 						{
953 							xLoc1 = x;
954 							yLoc1 = y;
955 							return 1;
956 						}
957 					}
958 				}
959 			}
960 		}
961 
962 		//-----------------------------------------------------------//
963 		// step 4
964 		//-----------------------------------------------------------//
965 		y = yLoc + yOffset;
966 		for(k=0; k<=width; k++)
967 		{
968 			sign *= -1;
969 			i--;
970 			r = sign*i;
971 			xOffset -= r;
972 
973 			x = xLoc + xOffset;
974 
975 			if(x>=0 && y>=0 && x+spaceLocWidth-1<MAX_WORLD_X_LOC && y+spaceLocHeight-1<MAX_WORLD_Y_LOC)
976 			{
977 				if(mobileType==UNIT_LAND || (x%2==0 && y%2==0))
978 				{
979 					locPtr = get_loc(x,y);
980 
981 					if( locPtr->region_id == regionId &&
982 						 locPtr->is_plateau() == isPlateau &&
983 						 check_unit_space(x, y, x+spaceLocWidth-1, y+spaceLocHeight-1, mobileType, buildFlag))
984 					{
985 						xLoc1 = x;
986 						yLoc1 = y;
987 						return 1;
988 					}
989 				}
990 			}
991 		}
992 
993 		//-----------------------------------------------------------//
994 		// re-init the parameters
995 		//-----------------------------------------------------------//
996 		if(xLoc<=0 && yLoc<=0 && width>=MAX_WORLD_X_LOC && height>=MAX_WORLD_Y_LOC)
997 			break;   // the whole map has been checked
998 
999 		width += 2;
1000 		height += 2;
1001 
1002 		xLoc -= 1;
1003 		yLoc -= 1;
1004 		if(xLoc<0)
1005 		{
1006 			xLoc = 0;
1007 			width--;
1008 		}
1009 		if(yLoc<0)
1010 		{
1011 			yLoc=0;
1012 			height--;
1013 		}
1014 
1015 		if(xLoc+width>MAX_WORLD_X_LOC)
1016 			width--;
1017 		if(yLoc+height>MAX_WORLD_Y_LOC)
1018 			height--;
1019 
1020 		//if(width==xLoc2-xLoc1+spaceLocWidth && height==yLoc2-yLoc1+spaceLocHeight) // terminate the checking
1021 		// return 0;
1022 	}
1023 
1024 	return 0;
1025 }
1026 //-------- End of function World::locate_space ------//
1027 
1028 
1029 //-------- Begin of function World::locate_space_random ------//
1030 //
1031 // Locate an area of space in the world map randomly. Pick any
1032 // space available in that area without a specific scanning order.
1033 //
1034 // <int&> xLoc1          = the scaning range, also for returning the result location
1035 // <int&> yLoc1          = the scaning range
1036 // <int>  xLoc2          = the scaning range
1037 // <int>  yLoc2          = the scaning range
1038 // <int>  spaceLocWidth  = the location width of the required space
1039 // <int>  spaceLocHeight = the location height of the required space
1040 // <int>  maxTries       = maximum no. of tries
1041 // [int]  regionId		 = if this is specified, the result location will
1042 //									be in this region.
1043 // [int]  buildSite      = whether locating space for building a site
1044 //                         (default: 0)
1045 // [char] teraMask		 = terrain mask (default: 1)
1046 //
1047 // return : <int> 1 - free space found
1048 //                0 - free space found
1049 //
locate_space_random(int & xLoc1,int & yLoc1,int xLoc2,int yLoc2,int spaceLocWidth,int spaceLocHeight,int maxTries,int regionId,int buildSite,char teraMask)1050 int World::locate_space_random(int& xLoc1, int& yLoc1, int xLoc2, int yLoc2,
1051 								int spaceLocWidth, int spaceLocHeight, int maxTries,
1052 								int regionId, int buildSite, char teraMask)
1053 {
1054    int       i, x, y, xTemp, xLoc, yLoc, canBuildFlag;
1055    int       scanWidth  = xLoc2-xLoc1-spaceLocWidth+2; //xLoc2-xLoc1+1-spaceLocWidth+1;
1056    int       scanHeight = yLoc2-yLoc1-spaceLocHeight+2; //yLoc2-yLoc1+1-spaceLocHeight+1;
1057 	Location* locPtr;
1058 
1059    for( i=0 ; i<maxTries ; i++ )
1060    {
1061       xLoc = xLoc1 + misc.random(scanWidth);
1062       yLoc = yLoc1 + misc.random(scanHeight);
1063 		canBuildFlag=1;
1064 
1065 		//---------- check if the area is all free ----------//
1066 
1067 		xTemp = xLoc+spaceLocWidth-1;
1068 
1069 		for( y=yLoc+spaceLocHeight-1; y>=yLoc; y-- )
1070 		{
1071 			locPtr = world.get_loc(xTemp, y);
1072 
1073 			for(x=xTemp; x>=xLoc; x--, locPtr-- )
1074 			{
1075 				if( ( buildSite ? !locPtr->can_build_site(teraMask) : !locPtr->can_build_firm(teraMask) ) ||
1076 					 locPtr->is_power_off() )
1077 				{
1078 					canBuildFlag=0;
1079 					break;
1080 				}
1081 			}
1082 
1083 			if(!canBuildFlag)
1084 				break;
1085 		}
1086 
1087 		if( !canBuildFlag )
1088 			continue;
1089 
1090 		//------ check region id. ------------//
1091 
1092 		locPtr = world.get_loc(xLoc, yLoc);
1093 
1094 		if( regionId && locPtr->region_id != regionId )
1095 			continue;
1096 
1097 		//------------------------------------//
1098 
1099 		xLoc1 = xLoc;
1100 		yLoc1 = yLoc;
1101 
1102 		err_when(buildSite && !locPtr->can_build_site(teraMask));//-*** hard codes for mine size 3x3
1103 		return 1;
1104 	}
1105 
1106 	return 0;
1107 }
1108 //-------- End of function World::locate_space_random ------//
1109 
1110 
1111 //-------- Begin of function World::can_build_firm ---------//
1112 //
1113 // Check if it is free to construct a building on the specific area.
1114 //
1115 // <int>   xLoc1, yLoc1 = the coordination of the area to can_build
1116 // <int>   firmId       = id. of the firm
1117 // [short] unitRecno    = the unit recno of the unit to build the firm
1118 //								  if the builder unit stands on the building area, still consider the area as buildable
1119 //								  (default: -1, do not take the builder into account)
1120 //
can_build_firm(int xLoc1,int yLoc1,int firmId,short unitRecno)1121 int World::can_build_firm(int xLoc1, int yLoc1, int firmId, short unitRecno)
1122 {
1123 	if( xLoc1 < 0 || yLoc1 < 0 || xLoc1 > MAX_WORLD_X_LOC || yLoc1 > MAX_WORLD_Y_LOC )
1124 		return 0;
1125 
1126 	//------------------------------------------//
1127 
1128 	FirmInfo* firmInfo = firm_res[firmId];
1129 
1130 	int xLoc, yLoc;
1131 	int xLoc2 = xLoc1 + firmInfo->loc_width - 1;
1132 	int yLoc2 = yLoc1 + firmInfo->loc_height - 1;
1133 	if(xLoc2>=max_x_loc || yLoc2>max_y_loc)
1134 		return 0;
1135 
1136 	Location* locPtr;
1137 	char teraMask, pierFlag;
1138 
1139 	switch(firmInfo->tera_type)
1140 	{
1141 	case 1:		// default : land firm
1142 	case 2:		// sea firm
1143 	case 3:		// land or sea firm
1144 		teraMask = firmInfo->tera_type;
1145 		for( yLoc=yLoc1 ; yLoc<=yLoc2 ; yLoc++ )
1146 		{
1147 			locPtr = get_loc(xLoc1, yLoc);
1148 
1149 			for( xLoc=xLoc1 ; xLoc<=xLoc2 ; xLoc++, locPtr++ )
1150 			{
1151 				// ##### patch begin Gilbert 14/3 ######//
1152 				if(!locPtr->can_build_firm(teraMask) &&
1153 					(!locPtr->has_unit(UNIT_LAND) || locPtr->unit_recno(UNIT_LAND)!=unitRecno))
1154 					return 0;
1155 				// ##### patch end Gilbert 14/3 ######//
1156 
1157 				if( firmId != FIRM_MINE && locPtr->has_site() )		// don't allow building any buildings other than mines on a location with a site
1158 					return 0;
1159 			}
1160 		}
1161 		return 1;
1162 
1163 	case 4:				// special firm, such as harbor
1164 		// must be 3x3,
1165 		// centre square of one side is land (teraMask=1),
1166 		// two squares on that side can be land or sea (teraMask=3)
1167 		// and other (6 squares) are sea (teraMask=2)
1168 		if( firmInfo->loc_width != 3 ||
1169 			firmInfo->loc_height != 3)
1170 			return 0;
1171 
1172 		pierFlag = 1|2|4|8;		// bit0=north, bit1=south, bit2=west, bit3=east
1173 		for( yLoc=yLoc1 ; yLoc<=yLoc2 ; yLoc++ )
1174 		{
1175 			locPtr = get_loc(xLoc1, yLoc);
1176 
1177 			for( xLoc=xLoc1 ; xLoc<=xLoc2 ; xLoc++, locPtr++ )
1178 			{
1179 				if( locPtr->has_site() )		// don't allow building any buildings other than mines on a location with a site
1180 					return 0;
1181 
1182 static char northPierTera[3][3] = { {2,2,2},{2,2,2},{3,1,3} };
1183 static char southPierTera[3][3] = { {3,1,3},{2,2,2},{2,2,2} };
1184 static char westPierTera[3][3] = { {2,2,3},{2,2,1},{2,2,3} };
1185 static char eastPierTera[3][3] = { {3,2,2},{1,2,2},{3,2,2} };
1186 				int x = xLoc - xLoc1;
1187 				int y = yLoc - yLoc1;
1188 				if(!locPtr->can_build_harbor(northPierTera[y][x]) )
1189 					pierFlag &= ~1;
1190 				if(!locPtr->can_build_harbor(southPierTera[y][x]) )
1191 					pierFlag &= ~2;
1192 				if(!locPtr->can_build_harbor(westPierTera[y][x]) )
1193 					pierFlag &= ~4;
1194 				if(!locPtr->can_build_harbor(eastPierTera[y][x]) )
1195 					pierFlag &= ~8;
1196 			}
1197 		}
1198 		err_when( pierFlag != 0 && pierFlag != 1 && pierFlag != 2 &&
1199 			pierFlag != 4 && pierFlag != 8 );
1200 		return pierFlag;
1201 		break;
1202 
1203 	// other tera_type here
1204 
1205 	default:
1206 		err_here();
1207 		return 0;
1208 	}
1209 }
1210 //--------- End of function World::can_build_firm ---------//
1211 
1212 
1213 //-------- Begin of function World::can_build_town ---------//
1214 //
1215 // <int>   xLoc1, yLoc1 = the coordination of the area to can_build
1216 // [short] unitRecno    = the unit recno of the unit to build the town
1217 //								  if the builder unit stands on the building area, still consider the area as buildable
1218 //								  (default: -1, do not take the builder into account)
1219 //
can_build_town(int xLoc1,int yLoc1,short unitRecno)1220 int World::can_build_town(int xLoc1, int yLoc1, short unitRecno)
1221 {
1222 	int xLoc, yLoc;
1223 	int xLoc2 = xLoc1 + STD_TOWN_LOC_WIDTH  - 1;
1224 	int yLoc2 = yLoc1 + STD_TOWN_LOC_HEIGHT - 1;
1225 
1226 	if(xLoc2>=max_x_loc || yLoc2>=max_y_loc)
1227 		return 0;
1228 
1229 	Location* locPtr;
1230 
1231 	for( yLoc=yLoc1 ; yLoc<=yLoc2 ; yLoc++ )
1232 	{
1233 		locPtr = get_loc(xLoc1, yLoc);
1234 
1235 		for( xLoc=xLoc1 ; xLoc<=xLoc2 ; xLoc++, locPtr++ )
1236 		{
1237 			// ##### patch begin Gilbert 14/3 ######//
1238 			// allow the building unit to stand in the area
1239 			if( !locPtr->can_build_town() &&
1240 				(!locPtr->has_unit(UNIT_LAND) || locPtr->unit_recno(UNIT_LAND)!=unitRecno) )
1241 				return 0;
1242 			// ##### patch end Gilbert 14/3 ######//
1243 		}
1244 	}
1245 
1246 	return 1;
1247 }
1248 //--------- End of function World::can_build_town ---------//
1249 
1250 
1251 //-------- Begin of function World::can_build_wall ---------//
1252 //
1253 // <int> xLoc, yLoc  = the coordination of the area to can_build
1254 // <int> nationRecno = recno of the builder nation.
1255 //
can_build_wall(int xLoc,int yLoc,short nationRecno)1256 int World::can_build_wall(int xLoc, int yLoc, short nationRecno)
1257 {
1258 	Location* locPtr = get_loc(xLoc, yLoc);
1259 
1260 	return locPtr->can_build_wall() && locPtr->power_nation_recno == nationRecno;
1261 }
1262 //--------- End of function World::can_build_wall ---------//
1263 
1264 
1265 //-------- Begin of function World::can_destruct_wall ---------//
1266 //
1267 // <int> xLoc, yLoc  = the coordination of the area to can_build
1268 // <int> nationRecno = recno of the builder nation.
1269 //
can_destruct_wall(int xLoc,int yLoc,short nationRecno)1270 int World::can_destruct_wall(int xLoc, int yLoc, short nationRecno)
1271 {
1272 	Location* locPtr = get_loc(xLoc, yLoc);
1273 
1274 	return locPtr->is_wall() && locPtr->power_nation_recno == nationRecno;
1275 }
1276 //--------- End of function World::can_destruct_wall ---------//
1277 
1278 
1279 //---------- Begin of function World::draw_link_line -----------//
1280 //
1281 // <int> srcFirmId          - id. of the source firm.
1282 //                            0 if the source is a town
1283 // <int> srcTownRecno       - town recno of the source town
1284 //                            0 if the source is a firm
1285 // <int> srcXLoc1, srcYLoc1 - the location of the source area
1286 //       srcXLoc2, srcYLoc2
1287 //
1288 // [int] giveEffectiveDis   - use this value as the effective distance if this is given
1289 //										(default: 0)
1290 //
draw_link_line(int srcFirmId,int srcTownRecno,int srcXLoc1,int srcYLoc1,int srcXLoc2,int srcYLoc2,int givenEffectiveDis)1291 void World::draw_link_line(int srcFirmId, int srcTownRecno, int srcXLoc1,
1292 									int srcYLoc1, int srcXLoc2, int srcYLoc2, int givenEffectiveDis)
1293 {
1294 	if( srcFirmId == FIRM_INN ) 	// FirmInn's link is only for scan for neighbor inns quickly, the link line is not displayed
1295 		return;
1296 
1297 	//--------------------------------------//
1298 
1299 	int srcXLoc = (srcXLoc1 + srcXLoc2)/2;
1300 	int srcYLoc = (srcYLoc1 + srcYLoc2)/2;
1301 
1302 	int srcX = ( ZOOM_X1 + (srcXLoc1-zoom_matrix->top_x_loc) * ZOOM_LOC_WIDTH
1303 				  + ZOOM_X1 + (srcXLoc2-zoom_matrix->top_x_loc+1) * ZOOM_LOC_WIDTH ) / 2;
1304 
1305 	int srcY = ( ZOOM_Y1 + (srcYLoc1-zoom_matrix->top_y_loc) * ZOOM_LOC_HEIGHT
1306 				  + ZOOM_Y1 + (srcYLoc2-zoom_matrix->top_y_loc+1) * ZOOM_LOC_HEIGHT ) / 2;
1307 
1308 	//------- draw lines connected to town ---------//
1309 
1310 	int   i, townX, townY, effectiveDis;
1311 	Town* townPtr;
1312 
1313 	if( givenEffectiveDis )
1314 		effectiveDis = givenEffectiveDis;
1315 	else
1316 	{
1317 		if( srcFirmId )
1318 			effectiveDis = EFFECTIVE_FIRM_TOWN_DISTANCE;
1319 		else
1320 			effectiveDis = EFFECTIVE_TOWN_TOWN_DISTANCE;
1321 	}
1322 
1323 	if( !srcFirmId || firm_res[srcFirmId]->is_linkable_to_town )    // don't draw link line to town if it's an inn
1324 	{
1325 		for( i=town_array.size() ; i>0 ; i-- )
1326 		{
1327 			if( town_array.is_deleted(i) )
1328 				continue;
1329 
1330 			townPtr = town_array[i];
1331 
1332 			if( srcTownRecno && townPtr->town_recno != srcTownRecno )
1333 				continue;
1334 
1335 			//-------- check the distance --------//
1336 
1337 			if( misc.points_distance( townPtr->center_x, townPtr->center_y,
1338 				 srcXLoc, srcYLoc ) > effectiveDis )
1339 			{
1340 				continue;
1341 			}
1342 
1343 			//------ check if both are on the same terrain type ------//
1344 
1345 			if( (world.get_loc(townPtr->center_x, townPtr->center_y)->is_plateau()==1)
1346 				 != (world.get_loc(srcXLoc, srcYLoc)->is_plateau()==1) )
1347 			{
1348 				continue;
1349 			}
1350 
1351 			//---------- draw line now -----------//
1352 
1353 			townX = ( ZOOM_X1 + (townPtr->loc_x1-zoom_matrix->top_x_loc) * ZOOM_LOC_WIDTH
1354 					  + ZOOM_X1 + (townPtr->loc_x2-zoom_matrix->top_x_loc+1) * ZOOM_LOC_WIDTH ) / 2;
1355 
1356 			townY = ( ZOOM_Y1 + (townPtr->loc_y1-zoom_matrix->top_y_loc) * ZOOM_LOC_HEIGHT
1357 					  + ZOOM_Y1 + (townPtr->loc_y2-zoom_matrix->top_y_loc+1) * ZOOM_LOC_HEIGHT ) / 2;
1358 
1359 			anim_line.draw_line(&vga_back, srcX, srcY, townX, townY);
1360 		}
1361 	}
1362 
1363 	//------- draw lines connected to firms ---------//
1364 
1365 	if( givenEffectiveDis )
1366 		effectiveDis = givenEffectiveDis;
1367 	else
1368 	{
1369 		if( srcFirmId )
1370 			effectiveDis = EFFECTIVE_FIRM_FIRM_DISTANCE;
1371 		else
1372 			effectiveDis = EFFECTIVE_FIRM_TOWN_DISTANCE;
1373 	}
1374 
1375 	int   firmX, firmY, linkFlag;
1376 	Firm* firmPtr;
1377 
1378 	for( i=firm_array.size() ; i>0 ; i-- )
1379 	{
1380 		if( firm_array.is_deleted(i) )
1381          continue;
1382 
1383 		firmPtr = firm_array[i];
1384 
1385 		//------ only link if the firms have relationship -----//
1386 
1387 		if( srcFirmId )
1388 			linkFlag = firm_res[firmPtr->firm_id]->is_linkable_to_firm(srcFirmId);
1389 		else
1390 			linkFlag = firm_res[firmPtr->firm_id]->is_linkable_to_town;
1391 
1392 		if( !linkFlag )
1393 			continue;
1394 
1395 		//-------- check the distance --------//
1396 
1397 		if( misc.points_distance( firmPtr->center_x, firmPtr->center_y,
1398 			 srcXLoc, srcYLoc ) > effectiveDis )
1399 		{
1400 			continue;
1401 		}
1402 
1403 		//------ check if both are on the same terrain type ------//
1404 
1405 		if( (world.get_loc(firmPtr->center_x, firmPtr->center_y)->is_plateau()==1)
1406 			 != (world.get_loc(srcXLoc, srcYLoc)->is_plateau()==1) )
1407 		{
1408 			continue;
1409 		}
1410 
1411 		//---------- draw line now -----------//
1412 
1413 		firmX = ( ZOOM_X1 + (firmPtr->loc_x1-zoom_matrix->top_x_loc) * ZOOM_LOC_WIDTH
1414 				  + ZOOM_X1 + (firmPtr->loc_x2-zoom_matrix->top_x_loc+1) * ZOOM_LOC_WIDTH ) / 2;
1415 
1416 		firmY = ( ZOOM_Y1 + (firmPtr->loc_y1-zoom_matrix->top_y_loc) * ZOOM_LOC_HEIGHT
1417 				  + ZOOM_Y1 + (firmPtr->loc_y2-zoom_matrix->top_y_loc+1) * ZOOM_LOC_HEIGHT ) / 2;
1418 
1419 		anim_line.draw_line(&vga_back, srcX, srcY, firmX, firmY);
1420 	}
1421 }
1422 //----------- End of function World::draw_link_line ------------//
1423 
1424 
1425 //-------- Begin of function World::set_surr_power_off ---------//
set_surr_power_off(int xLoc,int yLoc)1426 void World::set_surr_power_off(int xLoc, int yLoc)
1427 {
1428 	if(xLoc>0) // west
1429 		get_loc(xLoc-1, yLoc)->set_power_off();
1430 
1431 	if(xLoc<max_x_loc-1)
1432 		get_loc(xLoc+1, yLoc)->set_power_off();
1433 
1434 	if(yLoc>0) // north
1435 		get_loc(xLoc, yLoc-1)->set_power_off();
1436 
1437 	if(yLoc<max_y_loc-1) // south
1438 		get_loc(xLoc, yLoc+1)->set_power_off();
1439 }
1440 //----------- End of function World::set_surr_power_off ------------//
1441 
1442 
1443 //-------- Begin of function World::set_all_power ---------//
1444 //
set_all_power()1445 void World::set_all_power()
1446 {
1447 	//--------- set town's influence -----------//
1448 
1449 	Town* townPtr;
1450 	int i;
1451 
1452 	for( i=town_array.size() ; i>0 ; i-- )
1453 	{
1454 		if( town_array.is_deleted(i) )
1455 			continue;
1456 
1457 		townPtr = town_array[i];
1458 
1459 		if( !townPtr->nation_recno )
1460 			continue;
1461 
1462 		//------- set the influence range of this town -----//
1463 
1464 		set_power(townPtr->loc_x1, townPtr->loc_y1, townPtr->loc_x2, townPtr->loc_y2, (char)townPtr->nation_recno);
1465 	}
1466 
1467 	//--------- set firm's influence -----------//
1468 
1469 	Firm* firmPtr;
1470 
1471 	for( i=firm_array.size() ; i>0 ; i-- )
1472 	{
1473 		if( firm_array.is_deleted(i) )
1474 			continue;
1475 
1476 		firmPtr = firm_array[i];
1477 
1478 		if( !firmPtr->nation_recno )
1479 			continue;
1480 
1481 		if( !firmPtr->should_set_power )
1482 			continue;
1483 
1484 		//------- set the influence range of this firm -----//
1485 
1486 		set_power(firmPtr->loc_x1, firmPtr->loc_y1, firmPtr->loc_x2, firmPtr->loc_y2, (char)firmPtr->nation_recno);
1487 	}
1488 }
1489 //--------- End of function World::set_all_power ---------//
1490 
1491 
1492 //-------- Begin of function World::set_power ---------//
1493 //
1494 // <int> xLoc1, yLoc1, - area on the map which the power should be set
1495 //		   xLoc2, yLoc2
1496 //
1497 // <int> nationRcno - nation recno
1498 //
set_power(int xLoc1,int yLoc1,int xLoc2,int yLoc2,int nationRecno)1499 void World::set_power(int xLoc1, int yLoc1, int xLoc2, int yLoc2, int nationRecno)
1500 {
1501 	//------- reset power_nation_recno first ------//
1502 
1503 	int	plateauResult = (get_loc((xLoc1+xLoc2)/2, (yLoc1+yLoc2)/2)->is_plateau()==1);
1504 
1505 	int   	 xLoc, yLoc, centerY, t;
1506 	Location* locPtr = loc_matrix;
1507 
1508 	xLoc1 = MAX( 0, xLoc1 - EFFECTIVE_POWER_DISTANCE+1);
1509 	yLoc1 = MAX( 0, yLoc1 - EFFECTIVE_POWER_DISTANCE+1);
1510 	xLoc2 = MIN( MAX_WORLD_X_LOC-1, xLoc2 + EFFECTIVE_POWER_DISTANCE-1);
1511 	yLoc2 = MIN( MAX_WORLD_Y_LOC-1, yLoc2 + EFFECTIVE_POWER_DISTANCE-1);
1512 
1513 	centerY = (yLoc1+yLoc2) / 2;
1514 
1515 	for( yLoc=yLoc1 ; yLoc<=yLoc2 ; yLoc++ )
1516 	{
1517 		t=abs(yLoc-centerY)/2;
1518 
1519 		for( xLoc=xLoc1+t ; xLoc<=xLoc2-t ; xLoc++, locPtr++ )
1520 		{
1521 			locPtr = get_loc(xLoc, yLoc);
1522 
1523 			if(locPtr->sailable())//if(!locPtr->walkable())
1524 				continue;
1525 
1526 			if(locPtr->is_power_off())
1527 				continue;
1528 
1529 			if((locPtr->is_plateau()==1) != plateauResult)
1530 				continue;
1531 
1532 			if(locPtr->power_nation_recno==0)
1533 			{
1534 				locPtr->power_nation_recno = nationRecno;
1535 				sys.map_need_redraw = 1;						// request redrawing the map next time
1536 			}
1537 		}
1538 	}
1539 }
1540 //--------- End of function World::set_power ---------//
1541 
1542 
1543 //-------- Begin of function World::restore_power ---------//
1544 //
1545 // <int> xLoc1, yLoc1, - area on the map which the power should be restored
1546 //		   xLoc2, yLoc2
1547 //
1548 // <int> townRecno, firmRecno - either one
1549 //
restore_power(int xLoc1,int yLoc1,int xLoc2,int yLoc2,int townRecno,int firmRecno)1550 void World::restore_power(int xLoc1, int yLoc1, int xLoc2, int yLoc2, int townRecno, int firmRecno)
1551 {
1552 	int nationRecno;
1553 
1554 	if( townRecno )
1555 	{
1556 		nationRecno = town_array[townRecno]->nation_recno;
1557 		town_array[townRecno]->nation_recno = 0;
1558 	}
1559 
1560 	if( firmRecno )
1561 	{
1562 		nationRecno = firm_array[firmRecno]->nation_recno;
1563 		firm_array[firmRecno]->nation_recno = 0;
1564 	}
1565 
1566 	//------- reset power_nation_recno first ------//
1567 
1568 	int   	 xLoc, yLoc, centerY, t;
1569 	Location* locPtr = loc_matrix;
1570 
1571 	xLoc1 = MAX( 0, xLoc1 - EFFECTIVE_POWER_DISTANCE+1);
1572 	yLoc1 = MAX( 0, yLoc1 - EFFECTIVE_POWER_DISTANCE+1);
1573 	xLoc2 = MIN( MAX_WORLD_X_LOC-1, xLoc2 + EFFECTIVE_POWER_DISTANCE-1);
1574 	yLoc2 = MIN( MAX_WORLD_Y_LOC-1, yLoc2 + EFFECTIVE_POWER_DISTANCE-1);
1575 
1576 	centerY = (yLoc1+yLoc2) / 2;
1577 
1578 	for( yLoc=yLoc1 ; yLoc<=yLoc2 ; yLoc++ )
1579 	{
1580 		t=abs(yLoc-centerY)/2;
1581 
1582 		for( xLoc=xLoc1+t ; xLoc<=xLoc2-t ; xLoc++, locPtr++ )
1583 		{
1584 			locPtr = get_loc(xLoc, yLoc);
1585 
1586 			if( locPtr->power_nation_recno==nationRecno )
1587 			{
1588 				locPtr->power_nation_recno = 0;
1589 				sys.map_need_redraw = 1;						// request redrawing the map next time
1590 			}
1591 		}
1592 	}
1593 
1594 	//--- if some power areas are freed up, see if neighbor towns/firms should take up these power areas ----//
1595 
1596 	if( sys.map_need_redraw )	// when calls set_all_power(), the nation_recno of the calling firm must be reset
1597 		set_all_power();
1598 
1599 	//------- restore the nation recno of the calling town/firm -------//
1600 
1601 	if( townRecno )
1602 		town_array[townRecno]->nation_recno = nationRecno;
1603 
1604 	if( firmRecno )
1605 		firm_array[firmRecno]->nation_recno = nationRecno;
1606 }
1607 //--------- End of function World::restore_power ---------//
1608 
1609 
1610 //-------- Begin of function World::detect_firm_town ---------//
1611 //
detect_firm_town()1612 int World::detect_firm_town()
1613 {
1614 	// ##### begin Gilbert 19/9 ########//
1615 	// int rc = mouse.single_click(ZOOM_X1, ZOOM_Y1, ZOOM_X2, ZOOM_Y2, 2);
1616 	if( !mouse.any_click(ZOOM_X1, ZOOM_Y1, ZOOM_X2, ZOOM_Y2, 2) )
1617 		return 0;
1618 	// ##### end Gilbert 19/9 ########//
1619 
1620 	//------ detect pressing on link enable/disable sign -----//
1621 
1622 	Firm* firmPtr;
1623 
1624 	if( firm_array.selected_recno )
1625 	{
1626 		firmPtr = firm_array[firm_array.selected_recno];
1627 
1628 		if( firmPtr->should_show_info() &&				// only if should_show_info() is 1, we can detect links from this firm (it is not limited to player firms, as firms with player's workers should be allowed for resigning the player worker from the firm
1629 			 firmPtr->draw_detect_link_line(1) )		// 1-detect action
1630 		{
1631 			return 1;
1632 		}
1633 	}
1634 
1635 	Town* townPtr;
1636 
1637 	if( town_array.selected_recno )
1638 	{
1639 		townPtr = town_array[town_array.selected_recno];
1640 
1641 		if( townPtr->nation_recno==nation_array.player_recno &&
1642 			 townPtr->draw_detect_link_line(1) )		// 1-detect action
1643 		{
1644 			return 1;
1645 		}
1646 	}
1647 
1648 	// ####### begin Gilbert 12/9 #########// see Power::detect_select
1649 /*
1650 	//--------------- detect firm ------------------//
1651 
1652 	if( rc==1 )			// left click
1653 	{
1654 		int mouseAbsX = mouse.cur_x - ZOOM_X1 + World::view_top_x;
1655 		int mouseAbsY = mouse.cur_y - ZOOM_Y1 + World::view_top_y;
1656 
1657 		int  i;
1658 
1659 		for( i=firm_array.size() ; i>0 ; i-- )
1660 		{
1661 			if( firm_array.is_deleted(i) )
1662 				continue;
1663 
1664 			firmPtr = firm_array[i];
1665 
1666 			if( misc.is_touch( mouseAbsX, mouseAbsY, mouseAbsX, mouseAbsY,
1667 				firmPtr->abs_x1, firmPtr->abs_y1, firmPtr->abs_x2, firmPtr->abs_y2 ) )
1668 			{
1669 				power.reset_selection();
1670 				firm_array.selected_recno = i;
1671 				firmPtr->sort_worker();
1672 				info.disp();
1673 
1674 				// -------- sound effect -----------//
1675 
1676 				if( firmPtr->nation_recno == nation_array.player_recno && se_res.mark_select_object_time() )
1677 				{
1678 					se_res.sound(firmPtr->center_x, firmPtr->center_y, 1,
1679 						'F', firmPtr->firm_id, firmPtr->under_construction ? "SELU" : "SEL" );
1680 				}
1681 				return 1;
1682 			}
1683 		}
1684 
1685 		//----------- detect town section --------------//
1686 
1687 		for( i=town_array.size() ; i>0 ; i-- )
1688 		{
1689 			if( town_array.is_deleted(i) )
1690 				continue;
1691 
1692 			townPtr = town_array[i];
1693 
1694 			if( misc.is_touch( mouseAbsX, mouseAbsY, mouseAbsX, mouseAbsY,
1695 				 townPtr->abs_x1, townPtr->abs_y1, townPtr->abs_x2, townPtr->abs_y2 ) )
1696 			{
1697 				power.reset_selection();
1698 				town_array.selected_recno = i;
1699 				info.disp();
1700 
1701 				// -------- sound effect -----------//
1702 
1703 				if( townPtr->nation_recno == nation_array.player_recno
1704 					&& se_res.mark_select_object_time() )
1705 				{
1706 					se_res.sound(townPtr->center_x, townPtr->center_y, 1,
1707 						'T', 0, "SEL" );
1708 				}
1709 				return 1;
1710 			}
1711 		}
1712 	}
1713 	*/
1714 
1715 	return 0;
1716 }
1717 //-------- End of function World::detect_firm_town ---------//
1718 
1719 
1720 //-------- Begin of function World::earth_equake ------//
earth_quake()1721 void World::earth_quake()
1722 {
1723 	Location *locPtr;
1724 	int x,y;
1725 	for(y = 0; y < max_y_loc; ++y)
1726 	{
1727 		locPtr = get_loc(0,y);
1728 		for( x = 0; x < max_x_loc; ++x, ++locPtr)
1729 		{
1730 			if(locPtr->is_wall() )
1731 			{
1732 				locPtr->attack_wall( weather.quake_rate(x,y) /2 );
1733 			}
1734 		}
1735 	}
1736 
1737 	int firmDamage = 0;
1738 	int firmDie = 0;
1739 	int i;
1740 	for( i=firm_array.size() ; i>0 ; i-- )
1741 	{
1742 		if( firm_array.is_deleted(i) || !firm_res[firm_array[i]->firm_id]->buildable)
1743 			continue;
1744 
1745 		Firm *firmPtr = firm_array[i];
1746 		x = firmPtr->center_x;
1747 		y = firmPtr->center_y;
1748 		firmPtr->hit_points -= weather.quake_rate(x,y);
1749 		if( firmPtr->own_firm() )
1750 			firmDamage++;
1751 		if( firmPtr->hit_points <= 0)
1752 		{
1753 			firmPtr->hit_points = (float) 0;
1754 			if( firmPtr->own_firm() )
1755 				firmDie++;
1756 			se_res.sound(firmPtr->center_x, firmPtr->center_y, 1,
1757 				'F', firmPtr->firm_id, "DIE" );
1758 			firm_array.del_firm(i);
1759 		}
1760 	}
1761 
1762 	int townDamage = 0;
1763 	for( i=town_array.size() ; i>0 ; i-- )
1764 	{
1765 		if( town_array.is_deleted(i) )
1766 			continue;
1767 
1768 		Town *townPtr = town_array[i];
1769 		int ownTown = townPtr->nation_recno == nation_array.player_recno;
1770 		short beforePopulation = townPtr->population;
1771 		short causalty = weather.quake_rate(townPtr->center_x, townPtr->center_y) / 10;
1772 		for( ; causalty > 0 && !town_array.is_deleted(i); --causalty )
1773 		{
1774 			townPtr->kill_town_people(0);
1775 		}
1776 		if( town_array.is_deleted(i) )
1777 			causalty = beforePopulation;
1778 		else
1779 			causalty = beforePopulation - townPtr->population;
1780 
1781 		if(ownTown)
1782 			townDamage += causalty;
1783 	}
1784 
1785 	int unitDamage = 0;
1786 	int unitDie = 0;
1787 	for( i=unit_array.size(); i > 0; i-- )
1788 	{
1789 		if( unit_array.is_deleted(i))
1790 			continue;
1791 
1792 		Unit *unitPtr = unit_array[i];
1793 
1794 		// ###### begin Gilbert 30/8 ######//
1795 		// no damage to air unit , sea unit or overseer
1796 		if( !unitPtr->is_visible() || unitPtr->mobile_type == UNIT_AIR
1797 			|| unitPtr->mobile_type == UNIT_SEA)
1798 			continue;
1799 		// ###### end Gilbert 30/8 ######//
1800 
1801 		float damage = (float) weather.quake_rate(unitPtr->cur_x_loc(),unitPtr->cur_y_loc() ) *
1802 			unitPtr->max_hit_points / 200;
1803 		if( damage >= unitPtr->hit_points)
1804 			damage = unitPtr->hit_points -1;
1805 		if( damage < (float) 5)
1806 			damage = (float) 5;
1807 
1808 		unitPtr->hit_points -= damage;
1809 		if( unitPtr->is_own() )
1810 			unitDamage++;
1811 
1812 		if( unitPtr->hit_points <= 0)
1813 		{
1814 			unitPtr->hit_points = (float) 0;
1815 			if( unitPtr->is_own() )
1816 				unitDie++;
1817 		}
1818 		else
1819 		{
1820 			if( unit_res[unitPtr->unit_id]->solider_id &&
1821 				weather.quake_rate(unitPtr->cur_x_loc(),unitPtr->cur_y_loc()) >= 60)
1822 			{
1823 				((UnitVehicle *)unitPtr)->dismount();
1824 			}
1825 		}
1826 	}
1827 
1828 	news_array.earthquake_damage(unitDamage-unitDie, unitDie, townDamage, firmDamage-firmDie, firmDie);
1829 }
1830 //-------- End of function World::earth_equake ------//
1831 
1832 
1833 //-------- Begin of function World::lightning_strike ------//
lightning_strike(short cx,short cy,short radius)1834 void World::lightning_strike(short cx, short cy, short radius)
1835 {
1836 	short x, y;
1837 	for( y = cy-radius; y <= cy+radius; ++y)
1838 	{
1839 		if( y < 0 || y >= max_y_loc)
1840 			continue;
1841 
1842 		for( x = cx-radius; x <= cx+radius; ++x)
1843 		{
1844 			if( x < 0 || x >= max_x_loc)
1845 				continue;
1846 
1847 			Location *locPtr = get_loc(x,y);
1848 			if( locPtr->is_plant() )
1849 			{
1850 				// ---- add a fire on it ------//
1851 				locPtr->set_fire_str(80);
1852 				// ##### begin Gilbert 11/8 #####//
1853 				if( locPtr->can_set_fire() && locPtr->fire_str() < 5 )
1854 					locPtr->set_fire_str(5);
1855 				// ##### end Gilbert 11/8 #####//
1856 			}
1857 		}
1858 	}
1859 
1860 	// ------ check hitting units -------//
1861 	int i;
1862 	for( i=unit_array.size(); i > 0; i-- )
1863 	{
1864 		if( unit_array.is_deleted(i))
1865 			continue;
1866 
1867 		Unit *unitPtr = unit_array[i];
1868 
1869 		// no damage to overseer
1870 		if( !unitPtr->is_visible())
1871 			continue;
1872 
1873 		if( unitPtr->cur_x_loc() <= cx+ radius &&
1874 			unitPtr->cur_x_loc() + unitPtr->sprite_info->loc_width > cx-radius &&
1875 			unitPtr->cur_y_loc() <= cy+radius &&
1876 			unitPtr->cur_y_loc() + unitPtr->sprite_info->loc_height > cy-radius )
1877 		{
1878 			unitPtr->hit_points -= (float) unitPtr->sprite_info->lightning_damage / ATTACK_SLOW_DOWN;
1879 
1880 			// ---- add news -------//
1881 			if( unitPtr->is_own() )
1882 				news_array.lightning_damage(unitPtr->cur_x_loc(), unitPtr->cur_y_loc(),
1883 					NEWS_LOC_UNIT, i, unitPtr->hit_points <= (float) 0);
1884 
1885 			if( unitPtr->hit_points <= 0)
1886 				unitPtr->hit_points = (float) 0;
1887 		}
1888 	}
1889 
1890 	for( i=firm_array.size() ; i>0 ; i-- )
1891 	{
1892 		if( firm_array.is_deleted(i) || !firm_res[firm_array[i]->firm_id]->buildable)
1893 			continue;
1894 
1895 		Firm *firmPtr = firm_array[i];
1896 		if( firmPtr->loc_x1 <= cx+radius &&
1897 			firmPtr->loc_x2 >= cx-radius &&
1898 			firmPtr->loc_y1 <= cy+radius &&
1899 			firmPtr->loc_y2 >= cy-radius)
1900 		{
1901 			firmPtr->hit_points -= (float) 50 / ATTACK_SLOW_DOWN;
1902 
1903 			// ---- add news -------//
1904 			if( firmPtr->own_firm() )
1905 				news_array.lightning_damage(firmPtr->center_x, firmPtr->center_y,
1906 					NEWS_LOC_FIRM, i, firmPtr->hit_points <= (float) 0);
1907 
1908 			// ---- add a fire on it ------//
1909 			Location *locPtr = get_loc(firmPtr->center_x, firmPtr->center_y);
1910 			if( locPtr->can_set_fire() && locPtr->fire_str() < 5 )
1911 				locPtr->set_fire_str(5);
1912 
1913 			if( firmPtr->hit_points <= 0)
1914 			{
1915 				firmPtr->hit_points = (float) 0;
1916 				se_res.sound(firmPtr->center_x, firmPtr->center_y, 1,
1917 					'F', firmPtr->firm_id, "DIE" );
1918 				firm_array.del_firm(i);
1919 			}
1920 		}
1921 	}
1922 
1923 	for( i=town_array.size() ; i>0 ; i-- )
1924 	{
1925 		if( town_array.is_deleted(i))
1926 			continue;
1927 
1928 		Town *townPtr = town_array[i];
1929 
1930 		if( townPtr->loc_x1 <= cx+radius &&
1931 			townPtr->loc_x2 >= cx-radius &&
1932 			townPtr->loc_y1 <= cy+radius &&
1933 			townPtr->loc_y2 >= cy-radius)
1934 		{
1935 			// ---- add news -------//
1936 			if( townPtr->nation_recno == nation_array.player_recno )
1937 				news_array.lightning_damage(townPtr->center_x, townPtr->center_y,
1938 					NEWS_LOC_TOWN, i, 0);
1939 
1940 			// ---- add a fire on it ------//
1941 			// ####### begin Gilbert 11/8 #########//
1942 			Location *locPtr = get_loc(townPtr->center_x, townPtr->center_y);
1943 			if( locPtr->can_set_fire() && locPtr->fire_str() < 5)
1944 				locPtr->set_fire_str(5);
1945 			// ####### end Gilbert 11/8 #########//
1946 
1947 			townPtr->kill_town_people(0);
1948 		}
1949 	}
1950 }
1951 //-------- End of function World::lightning_strike -------//
1952 
1953 
1954 // ------- Begin of function World::visit -----------//
1955 // set the visit_level surrounding unit, town and firm
visit(int xLoc1,int yLoc1,int xLoc2,int yLoc2,int range,int extend)1956 void World::visit(int xLoc1, int yLoc1, int xLoc2, int yLoc2, int range, int extend)
1957 {
1958 	if(config.fog_of_war)
1959 	{
1960 		int left   = MAX( 0, xLoc1 - range);
1961 		int top    = MAX( 0, yLoc1 - range);
1962 		int right  = MIN( MAX_WORLD_X_LOC-1, xLoc2 + range);
1963 		int bottom = MIN( MAX_WORLD_Y_LOC-1, yLoc2 + range);
1964 
1965 		// ----- mark the visit_level of the square around the unit ------//
1966 		for( int yLoc=top ; yLoc<=bottom ; yLoc++ )
1967 		{
1968 			Location *locPtr = get_loc(left, yLoc);
1969 			for( int xLoc=left ; xLoc<=right ; xLoc++, locPtr++ )
1970 			{
1971 				locPtr->set_visited();
1972 			}
1973 		}
1974 
1975 		// ----- visit_level decreasing outside the visible range ------//
1976 		if( extend > 0)
1977 		{
1978 			int visitLevel = FULL_VISIBILITY;
1979 			int levelDrop = (FULL_VISIBILITY - EXPLORED_VISIBILITY) / (extend+1);
1980 			xLoc1 -= range;
1981 			xLoc2 += range;
1982 			yLoc1 -= range;
1983 			yLoc2 += range;
1984 			for( ++range; extend > 0; --extend, ++range)
1985 			{
1986 				xLoc1--;
1987 				xLoc2++;
1988 				yLoc1--;
1989 				yLoc2++;
1990 				visitLevel -= levelDrop;
1991 				visit_shell(xLoc1, yLoc1, xLoc2, yLoc2, visitLevel);
1992 			}
1993 		}
1994 	}
1995 }
1996 // ------- End of function World::visit -----------//
1997 
1998 
1999 // ------- Begin of function World::visit_shell -----------//
2000 // set specific visit_level on the surrounding unit, town and firm
visit_shell(int xLoc1,int yLoc1,int xLoc2,int yLoc2,int visitLevel)2001 void World::visit_shell(int xLoc1, int yLoc1, int xLoc2, int yLoc2, int visitLevel)
2002 {
2003 	int left   = MAX( 0, xLoc1 );
2004 	int top    = MAX( 0, yLoc1 );
2005 	int right  = MIN( MAX_WORLD_X_LOC-1, xLoc2);
2006 	int bottom = MIN( MAX_WORLD_Y_LOC-1, yLoc2);
2007 
2008 	// ------- top side ---------//
2009 	if( yLoc1 >= 0)
2010 	{
2011 		Location *locPtr = get_loc( left, yLoc1);
2012 		for( int x = left; x <= right; ++x, ++locPtr)
2013 			locPtr->set_visited(visitLevel);
2014 	}
2015 
2016 	// ------- bottom side ---------//
2017 	if( yLoc2 < max_y_loc)
2018 	{
2019 		Location *locPtr = get_loc( left, yLoc2);
2020 		for( int x = left; x <= right; ++x, ++locPtr)
2021 			locPtr->set_visited(visitLevel);
2022 	}
2023 
2024 	// ------- left side -----------//
2025 	if( xLoc1 >= 0)
2026 	{
2027 		for( int y = top; y <= bottom; ++y)
2028 		{
2029 			get_loc(xLoc1,y)->set_visited(visitLevel);
2030 		}
2031 	}
2032 
2033 	// ------- right side -----------//
2034 	if( xLoc2 < max_x_loc)
2035 	{
2036 		for( int y = top; y <= bottom; ++y)
2037 		{
2038 			get_loc(xLoc2,y)->set_visited(visitLevel);
2039 		}
2040 	}
2041 
2042 }
2043 // ------- End of function World::visit_shell -----------//
2044 
2045 
2046 //------- Begin of function World::process_visibility -----------//
2047 
process_visibility()2048 void World::process_visibility()
2049 {
2050 	if( config.fog_of_war )
2051 	{
2052 		// ###### begin Gilbert 13/10 ########//
2053 #ifndef USE_ASM
2054 		for( int y = 0; y < max_y_loc; ++y)
2055 		{
2056 			Location *locPtr = get_loc(0,y);
2057 			for( int x = 0; x < max_x_loc; ++x, ++locPtr)
2058 			{
2059 				locPtr->dec_visibility();
2060 			}
2061 		}
2062 #else
2063 		int count = max_x_loc * max_y_loc;
2064 		const int sizeOfLoc = sizeof(Location);
2065 		unsigned char *locVisitLevel = &get_loc(0,0)->visit_level;
2066 		unsigned char decVisitLevel = EXPLORED_VISIBILITY*2+1;
2067 #ifdef _MSC_VER
2068 		_asm
2069 		{
2070 			mov	ecx, count
2071 			mov	ebx, locVisitLevel
2072 			mov	edx, sizeOfLoc
2073 			mov	ah, decVisitLevel
2074 process_visit_level_1:
2075 			mov	al,[ebx]
2076 			cmp	al,ah			// if(al > EXPLORED_VISIBILITY*2) al--;
2077 			cmc
2078 			sbb	al,0
2079 			mov	[ebx],al
2080 			add	ebx, edx
2081 			loop	process_visit_level_1
2082 		}
2083 #else
2084 		__asm__ __volatile__ (
2085 			"movb %0, %%ah\n"
2086 		"process_visit_level_1:\n\t"
2087 			"movb (%%ebx), %%al\n\t"
2088 			"cmpb %%ah, %%al\n\t"
2089 			"cmc\n\t"
2090 			"sbbb $0, %%al\n\t"
2091 			"movb %%al, (%%ebx)\n\t"
2092 			"addl %%edx, %%ebx\n\t"
2093 			"loop process_visit_level_1\n\t"
2094 			:
2095 			: "m"(decVisitLevel), "b"(locVisitLevel), "c"(count), "d"(sizeOfLoc)
2096 			: "%eax"
2097 		);
2098 #endif
2099 #endif
2100 		// ###### end Gilbert 13/10 ########//
2101 	}
2102 }
2103 //------- End of function World::process_visibility -----------//
2104 
2105 
2106 //--------- Begin of function World::disp_next --------//
2107 //
2108 // Display the next object of the same type.
2109 //
2110 // <int> seekDir : -1 - display the previous one in the list.
2111 // 					  1 - display the next one in the list.
2112 //
2113 // <int> sameNation - whether display the next object of the same
2114 //							 nation only or of any nation.
2115 //
disp_next(int seekDir,int sameNation)2116 void World::disp_next(int seekDir, int sameNation)
2117 {
2118 	//--- if the selected one is a unit ----//
2119 
2120 	if( unit_array.selected_recno )
2121 	{
2122 		unit_array.disp_next(seekDir, sameNation);
2123 	}
2124 
2125 	//--- if the selected one is a firm ----//
2126 
2127 	if( firm_array.selected_recno )
2128 	{
2129 		firm_array.disp_next(seekDir, sameNation);
2130 	}
2131 
2132 	//--- if the selected one is a town ----//
2133 
2134 	if( town_array.selected_recno )
2135 	{
2136 		town_array.disp_next(seekDir, sameNation);
2137 	}
2138 
2139 	//--- if the selected one is a natural resource site ----//
2140 
2141 	if( site_array.selected_recno )
2142 	{
2143 		site_array.disp_next(seekDir, sameNation);
2144 	}
2145 }
2146 //----------- End of function World::disp_next --------//
2147 
2148 #ifdef DEBUG3
2149 
2150 //--------- Begin of function World::get_loc --------//
2151 //
get_loc(int xLoc,int yLoc)2152 Location* World::get_loc(int xLoc, int yLoc)
2153 {
2154 	err_when( xLoc<0 || xLoc>=MAX_WORLD_X_LOC );
2155 	err_when( yLoc<0 || yLoc>=MAX_WORLD_Y_LOC );
2156 
2157 	return loc_matrix + MAX_WORLD_X_LOC * yLoc + xLoc;
2158 }
2159 //----------- End of function World::get_loc --------//
2160 
2161 
2162 //--------- Begin of function World::get_region_id --------//
2163 //
get_region_id(int xLoc,int yLoc)2164 uint8_t World::get_region_id(int xLoc, int yLoc)
2165 {
2166 	err_when( xLoc<0 || xLoc>=MAX_WORLD_X_LOC );
2167 	err_when( yLoc<0 || yLoc>=MAX_WORLD_Y_LOC );
2168 
2169 	return loc_matrix[MAX_WORLD_X_LOC*yLoc+xLoc].region_id;
2170 }
2171 //----------- End of function World::get_region_id --------//
2172 
2173 #endif
2174 
2175 // ####### begin Gilbert 25/7 #########//
2176 // return true if any location adjacent to (x,y) is on a particular region
is_adjacent_region(int x,int y,int regionId)2177 int World::is_adjacent_region(int x, int y, int regionId)
2178 {
2179 	if( y > 0 )
2180 	{
2181 		if( x > 0 )
2182 		{
2183 			if( get_region_id(x-1,y-1) == regionId )
2184 				return 1;
2185 		}
2186 		if( get_region_id(x,y-1) == regionId )
2187 			return 1;
2188 		if( x < max_x_loc-1 )
2189 		{
2190 			if( get_region_id(x+1,y-1) == regionId )
2191 				return 1;
2192 		}
2193 	}
2194 	if( x > 0 )
2195 	{
2196 		if( get_region_id(x-1,y) == regionId )
2197 			return 1;
2198 	}
2199 	if( x < max_x_loc-1 )
2200 	{
2201 		if( get_region_id(x+1,y) == regionId )
2202 			return 1;
2203 	}
2204 	if( y < max_y_loc-1)
2205 	{
2206 		if( x > 0 )
2207 		{
2208 			if( get_region_id(x-1,y+1) == regionId )
2209 				return 1;
2210 		}
2211 		if( get_region_id(x,y+1) == regionId )
2212 			return 1;
2213 		if( x < max_x_loc-1 )
2214 		{
2215 			if( get_region_id(x+1,y+1) == regionId )
2216 				return 1;
2217 		}
2218 	}
2219 	return 0;
2220 }
2221 // ####### end Gilbert 25/7 #########//
2222