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    : OMATRIX.CPP
22 //Description : Object road direction turn, derived by World, Chain class
23 
24 #include <ALL.h>
25 #include <OVGA.h>
26 #include <OMOUSE.h>
27 #include <OSYS.h>
28 #include <OSITE.h>
29 #include <OFIRM.h>
30 #include <OTERRAIN.h>
31 #include <OPLANT.h>
32 #include <OPOWER.h>
33 #include <OUNIT.h>
34 #include <OWORLD.h>
35 #include <OHILLRES.h>
36 
37 // --------- define constant ----------//
38 #define DEFAULT_WALL_TIMEOUT 10
39 #define WALL_DEFENCE 5
40 #define MIN_WALL_DAMAGE 3
41 
42 //----------- Begin of function Matrix::init ----------//
43 //
44 // <int> winX1,winY1 = the coordination of the win,
45 //       winX2,winY2   including the scroll bar and up,down panel
46 //
47 // <int> areaWidth   = width and height of the bitmap area
48 //       areaHeight
49 //
50 // <int> locWidth    = width and height of each location
51 // <int> locHeight
52 //
53 // <int> maxCargoWidth  = MAX. widht of height of cargo
54 //       maxCargoHeight  (unit is Loc, not pixel
55 //
56 // <int> saveAreaToBuf = whether save the area to a buffer,
57 //                       set it true - when the area will be ruined by
58 //                                     animation
59 //
init(int winX1,int winY1,int winX2,int winY2,int areaWidth,int areaHeight,int locWidth,int locHeight,int saveAreaToBuf)60 void Matrix::init(int winX1, int winY1, int winX2, int winY2, int areaWidth,
61 						int areaHeight, int locWidth, int locHeight, int saveAreaToBuf )
62 {
63 	err_when(FULL_VISIBILITY != MAX_BRIGHTNESS_ADJUST_DEGREE * 8 + 7);
64 	win_x1 = winX1;      // window area,
65 	win_y1 = winY1;      // including scroll bar
66 	win_x2 = winX2;
67 	win_y2 = winY2;
68 
69 	image_width  = areaWidth;
70 	image_height = areaHeight;
71 
72 	image_x1 = win_x1;  // bitmap area only
73 	image_y1 = win_y1;
74 	image_x2 = image_x1+image_width-1;
75 	image_y2 = image_y1+image_height-1;
76 
77 	loc_width  = locWidth;
78 	loc_height = locHeight;
79 
80 	//----------------------------------------------//
81 
82 	if( saveAreaToBuf )
83 		save_image_buf = mem_add( sizeof(short)*2 + image_width * image_height );	// 2 <short> for width & height info
84 	else
85 		save_image_buf = NULL;
86 
87    just_drawn_flag = 0;
88 
89 	//---------------------------------------------//
90 
91 	loc_matrix = NULL;
92 
93 	top_x_loc = 0;
94 	top_y_loc = 0;
95 
96 	cur_x_loc = -1;
97 	cur_y_loc = -1;
98 }
99 //------------- End of function Matrix::init -----------//
100 
101 
102 //----------- Begin of function Matrix::~Matrix ----------//
103 
~Matrix()104 Matrix::~Matrix()
105 {
106 	if( save_image_buf )
107 		mem_del( save_image_buf );
108 
109 	if( own_matrix && loc_matrix )       // the matrix is allocated by us
110 		mem_del( loc_matrix );
111 }
112 //------------- End of function Matrix::~Matrix -----------//
113 
114 
115 //----------- Begin of function Matrix::assign_map -----------//
116 //
117 // Instead of loading the map file, we can assign a pre-loaded
118 // map to it.
119 //
assign_map(Matrix * matrixPtr)120 void Matrix::assign_map(Matrix* matrixPtr)
121 {
122 	own_matrix = 0;
123 
124 	loc_matrix = matrixPtr->loc_matrix;
125 
126 	max_x_loc  = matrixPtr->max_x_loc;
127 	max_y_loc  = matrixPtr->max_y_loc;
128 
129 	init_var();
130 
131 	top_x_loc  = 0;
132 	top_y_loc  = 0;
133 
134 	cur_x_loc = 0;
135    cur_y_loc = 0;
136 }
137 //------------- End of function Matrix::assign_map -----------//
138 
139 
140 //----------- Begin of function Matrix::assign_map -----------//
141 //
142 // Instead of loading the map file, we can assign a pre-loaded
143 // map to it.
144 //
assign_map(Location * locMatrix,int maxXLoc,int maxYLoc)145 void Matrix::assign_map(Location* locMatrix, int maxXLoc, int maxYLoc )
146 {
147 	own_matrix = 0;
148 
149    loc_matrix = locMatrix;
150 
151    max_x_loc  = maxXLoc;
152    max_y_loc  = maxYLoc;
153 
154    init_var();
155 
156    cur_x_loc = 0;
157 	cur_y_loc = 0;
158 }
159 //------------- End of function Matrix::assign_map -----------//
160 
161 
162 //-------- Begin of function Matrix::init_var ---------//
163 //
164 // Called by assign_map() & MatrixMap::set_view_map()
165 //
init_var()166 void Matrix::init_var()
167 {
168    disp_x_loc = image_width/loc_width;
169    if( disp_x_loc > max_x_loc )
170       disp_x_loc = max_x_loc;
171 
172 	disp_y_loc = image_height/loc_height;
173    if( disp_y_loc > max_y_loc )
174       disp_y_loc = max_y_loc;
175 }
176 //------------ End of function Matrix::init_var -----------//
177 
178 
179 //----------- Begin of function Matrix::paint ------------//
180 //
181 // Paint world window and scroll bars
182 //
paint()183 void Matrix::paint()
184 {
185 }
186 //----------- End of function Matrix::paint ------------//
187 
188 
189 //---------- Begin of function Matrix::draw ------------//
190 //
191 // Draw world zoom
192 //
draw()193 void Matrix::draw()
194 {
195 	int       i=0, x, y, xLoc, yLoc;
196 	Location* locPtr;
197 
198 	int maxXLoc = top_x_loc + disp_x_loc;        // divide by 2 for world_info
199 	int maxYLoc = top_y_loc + disp_y_loc;
200 
201 	//----------------------------------------------------//
202 
203 	for( y=image_y1,yLoc=top_y_loc ; yLoc<maxYLoc ; yLoc++, y+=loc_height )
204 	{
205 		if( (i++)%10==0 )
206 			sys.yield();
207 
208 		locPtr = get_loc(top_x_loc,yLoc);
209 
210 		for( x=image_x1,xLoc=top_x_loc ; xLoc<maxXLoc ; xLoc++, x+=loc_width, locPtr++ )
211 			draw_loc( x, y, xLoc, yLoc, locPtr );
212 	}
213 
214 	//---- derived function for ZoomMatrix & MapMatrix ----//
215 
216 	post_draw();	// if they have anything to draw after the basic terrain (e.g.firms)
217 
218 	//---------------------------------------------------//
219 
220 	if( save_image_buf )
221 	{
222 		vga_back.read_bitmap( image_x1, image_y1, image_x2, image_y2, save_image_buf );
223 		just_drawn_flag = 1;
224 	}
225 }
226 //------------ End of function Matrix::draw ------------//
227 
228 
229 //----------- Begin of function Matrix::disp ------------//
230 //
231 // Display the drawn world zoom on screen
232 //
disp()233 void Matrix::disp()
234 {
235 	if( !just_drawn_flag )		// if the map has just been drawn in draw()
236 	{
237 		if( save_image_buf )
238 		{
239 			err_when( image_width%4 != 0 );
240 #ifdef DEBUG_TIMING
241 			unsigned long start_time, elapsed_time;
242 			int i = 0;
243 			start_time = misc.get_time();
244 			for( i = 0; i < 10; ++i)
245 #endif
246 			vga_back.put_bitmap_dw( image_x1, image_y1, save_image_buf );
247 #ifdef DEBUG_TIMING
248 			elapsed_time = misc.get_time() - start_time;
249 			// dummy
250 			start_time = 0;
251 #endif
252 		}
253 		else
254 			draw();
255 	}
256 
257 	just_drawn_flag=0;
258 }
259 //----------- End of function Matrix::disp ------------//
260 
261 
262 //--------- Begin of function Matrix::refresh ------------//
263 //
refresh()264 void Matrix::refresh()
265 {
266 	if( save_image_buf )	// redraw the background, so disp() won't use the old background
267 		draw();
268 
269 	disp();
270 }
271 //----------- End of function Matrix::refresh ------------//
272 
273 
274 //----------- Begin of function Matrix::valid_cur_box ------------//
275 //
276 // Validate the position of the zoom area box, scroll window if necessary
277 // called by detect_area()
278 //
279 // Call valid_cur_box() if current highlight box is specified,
280 //                      adjust window area to fit it
281 //
282 // Call valid_disp_area() if window display area is specified,
283 //                        adjust highlight box to fit it
284 //
285 // [int] = callRefresh = call refresh() if scrolled
286 //                       (default : 1)
287 //
288 // return : <int> whether the window is scrolled
289 //
valid_cur_box(int callRefresh)290 int Matrix::valid_cur_box(int callRefresh)
291 {
292 	int scrolledFlag=0;
293 
294 	//------- valid current highlight box first --------//
295 
296 	if( cur_x_loc < 0 )
297 		cur_x_loc = 0;
298 
299 	if( cur_y_loc < 0 )
300 		cur_y_loc = 0;
301 
302 	if( cur_x_loc+cur_cargo_width > max_x_loc )
303 		cur_x_loc = max_x_loc-cur_cargo_width;
304 
305 	if( cur_y_loc+cur_cargo_height > max_y_loc )
306 		cur_y_loc = max_y_loc-cur_cargo_height;
307 
308 
309 	//--- scroll the display area to fit the current highlight ---//
310 
311 	if( cur_x_loc < top_x_loc ||
312 		 cur_x_loc >= top_x_loc + disp_x_loc )
313 	{
314 		top_x_loc = cur_x_loc - disp_x_loc/2;
315 
316 		if( top_x_loc < 0 )
317 			top_x_loc = 0;
318 
319 		if( top_x_loc + disp_x_loc > max_x_loc )
320 			top_x_loc = max_x_loc - disp_x_loc;
321 
322 		scrolledFlag=1;
323 	}
324 
325 	if( cur_y_loc < top_y_loc ||
326 		 cur_y_loc >= top_y_loc + disp_y_loc )
327 	{
328 		top_y_loc = cur_y_loc - disp_y_loc/2;
329 
330 		if( top_y_loc < 0 )
331 			top_y_loc = 0;
332 
333 		if( top_y_loc + disp_y_loc > max_y_loc )
334 			top_y_loc = max_y_loc - disp_y_loc;
335 
336 		scrolledFlag=1;
337 	}
338 
339 	return scrolledFlag;
340 }
341 //----------- End of function Matrix::valid_cur_box ------------//
342 
343 
344 //--------- Begin of function Matrix::valid_disp_area ------//
345 //
346 // Validate the current location, adjust it if it is out of border
347 //
348 // Call valid_cur_box() if current highlight box is specified,
349 //                  adjust window area to fit it
350 //
351 // Call valid_disp_area() if window display area is specified,
352 //                      adjust highlight box to fit it
353 //
354 // [int] fitInBox = whether must fit in current box into the
355 //                  display area (default : 0)
356 //
valid_disp_area(int fitInBox)357 void Matrix::valid_disp_area(int fitInBox)
358 {
359 	//------- valid display area first ---------//
360 
361 	if( top_x_loc < 0 )
362 		top_x_loc = 0;
363 
364 	if( top_y_loc < 0 )
365 		top_y_loc = 0;
366 
367 	if( top_x_loc + disp_x_loc > max_x_loc )
368 		top_x_loc = max_x_loc - disp_x_loc;
369 
370 	if( top_y_loc + disp_y_loc > max_y_loc )
371 		top_y_loc = max_y_loc - disp_y_loc;
372 
373 	//--- if the current highlighted location is outside the display area, then reposition it ----//
374 
375 	if( fitInBox )
376 	{
377 		if( cur_x_loc < top_x_loc )
378 			cur_x_loc = top_x_loc;
379 
380 		if( cur_x_loc >= top_x_loc + disp_x_loc )
381 			cur_x_loc = top_x_loc + disp_x_loc - 1;
382 
383 		if( cur_y_loc < top_y_loc )
384 			cur_y_loc = top_y_loc;
385 
386 		if( cur_y_loc >= top_y_loc + disp_y_loc )
387 			cur_y_loc = top_y_loc + disp_y_loc - 1;
388 	}
389 }
390 //--------- End of function Matrix::valid_disp_area ------//
391 
392 
393 //---------- Begin of function Matrix::scroll -----------//
394 //
395 // <int> xScroll - horizontal scroll step (negative:left, positive:right)
396 // <int> yScroll - vertical scroll step   (negative:left, positive:right)
397 //
scroll(int xScroll,int yScroll)398 void Matrix::scroll(int xScroll, int yScroll)
399 {
400 	top_x_loc += xScroll;
401 	top_y_loc += yScroll;
402 
403 	valid_disp_area();
404 }
405 //----------- End of function Matrix::scroll ------------//
406 
407 
408 // ------- Begin of function Location::walkable_reset -----/
walkable_reset()409 void Location::walkable_reset()
410 {
411 	if( loc_flag & LOCATE_BLOCK_MASK )
412 	{
413 		walkable_off();
414 	}
415 	else
416 	{
417 		if( terrain_res[terrain_id]->average_type == TERRAIN_OCEAN)
418 		{
419 			loc_flag |= LOCATE_WALK_SEA;
420 		}
421 		else
422 		{
423 			loc_flag |= LOCATE_WALK_LAND;
424 		}
425 	}
426 }
427 // ----------- End of function Location::walkable_reset -------//
428 
429 
430 // ----------- Begin of function Location::is_plateau ---------//
is_plateau()431 int Location::is_plateau()
432 {
433 	return terrain_res[terrain_id]->average_type == TERRAIN_DARK_DIRT;		//**BUGHERE, to be changed to TERRAIN_HILL when the no. of terrain type has been reduced to 4 from 7
434 }
435 // ----------- End of function Location::is_plateau ---------//
436 
437 
438 //---------- Begin of function Location::set_site ------------//
439 //
set_site(int siteRecno)440 void Location::set_site(int siteRecno)
441 {
442 	err_when( !can_build_site() );
443 
444 	loc_flag = loc_flag & ~LOCATE_SITE_MASK | LOCATE_HAS_SITE;
445 	// loc_flag |= LOCATION_HAS_SITE;
446 
447 	extra_para = siteRecno;
448 }
449 //------------ End of function Location::set_site ------------//
450 
451 
452 //---------- Begin of function Location::remove_site ------------//
453 //
remove_site()454 void Location::remove_site()
455 {
456 	err_when( !has_site() );
457 
458 	loc_flag &= ~LOCATE_SITE_MASK;
459 
460 	extra_para  = 0;
461 }
462 //------------ End of function Location::remove_site ------------//
463 
464 
465 //------------ Begin of function Location::set_wall_timeout ------------//
set_wall_timeout(int initTimeout)466 void Location::set_wall_timeout(int initTimeout)
467 {
468 	err_when((!can_build_site() && !had_wall()) || initTimeout <= 0);
469 	loc_flag = (loc_flag & ~LOCATE_SITE_MASK) | LOCATE_HAD_WALL;
470 	extra_para = (unsigned char) initTimeout;
471 }
472 //------------ End of function Location::set_wall_timeout ------------//
473 
474 
475 //------------ Begin of function Location::dec_wall_timeout ------------//
476 // return : true if the timeout drop to zero, and is removed
dec_wall_timeout(int t)477 int Location::dec_wall_timeout(int t)
478 {
479 	err_when( !had_wall() );
480 	if( (extra_para -= t) <= 0)
481 	{
482 		remove_wall_timeout();
483 		return 1;
484 	}
485 	return 0;
486 }
487 //------------ End of function Location::dec_wall_timeout ------------//
488 
489 
490 //------------ Begin of function Location::remove_wall_timeout ------------//
remove_wall_timeout()491 void Location::remove_wall_timeout()
492 {
493 	err_when( !had_wall() );
494 	loc_flag &= ~LOCATE_SITE_MASK;
495 	extra_para = 0;
496 }
497 //------------ End of function Location::remove_wall_timeout ------------//
498 
499 
500 //---------- Begin of function Location::set_dirt ------------//
501 //
set_dirt(int dirtRecno)502 void Location::set_dirt(int dirtRecno)
503 {
504 	err_when( !can_add_dirt() );
505 
506 	loc_flag = loc_flag & ~LOCATE_SITE_MASK | LOCATE_HAS_DIRT;
507 
508 	extra_para = dirtRecno;
509 }
510 //------------ End of function Location::set_dirt ------------//
511 
512 
513 //---------- Begin of function Location::remove_dirt ------------//
514 //
remove_dirt()515 void Location::remove_dirt()
516 {
517 	err_when( !has_dirt() );
518 
519 	loc_flag &= ~LOCATE_SITE_MASK;
520 
521 	extra_para  = 0;
522 }
523 //------------ End of function Location::remove_dirt ------------//
524 
525 
526 //---------- Begin of function Location::set_firm ------------//
527 //
set_firm(int firmRecno)528 void Location::set_firm(int firmRecno)
529 {
530 	// can't check the terrain type here
531 	err_when( !can_build_firm() && !firmRecno );
532 
533 	walkable_off();
534 	loc_flag = (loc_flag & ~LOCATE_BLOCK_MASK) | LOCATE_IS_FIRM;
535 
536 	cargo_recno = firmRecno;
537 }
538 //------------ End of function Location::set_firm ------------//
539 
540 
541 //---------- Begin of function Location::remove_firm ------------//
542 //
remove_firm()543 void Location::remove_firm()
544 {
545 	err_when( !is_firm() );
546 
547 	loc_flag &= ~LOCATE_BLOCK_MASK;
548 	cargo_recno = 0;
549 	walkable_reset();
550 
551 	err_when(is_firm());
552 }
553 //------------ End of function Location::remove_firm ------------//
554 
555 
556 //---------- Begin of function Location::set_town ------------//
557 //
set_town(int townRecno)558 void Location::set_town(int townRecno)
559 {
560 	err_when( !can_build_town() || !townRecno );
561 
562 	walkable_off();
563 	loc_flag = loc_flag & ~LOCATE_BLOCK_MASK | LOCATE_IS_TOWN;
564 
565 	cargo_recno = townRecno;
566 }
567 //------------ End of function Location::set_town ------------//
568 
569 
570 //---------- Begin of function Location::remove_town ------------//
571 //
remove_town()572 void Location::remove_town()
573 {
574 	err_when( !is_town() );
575 
576 	loc_flag &= ~LOCATE_BLOCK_MASK;
577 	cargo_recno = 0;
578 	walkable_reset();
579 
580 	err_when(is_firm());
581 }
582 //------------ End of function Location::remove_town ------------//
583 
584 
585 //---------- Begin of function Location::set_hill ------------//
586 // set hillId to hill_id1 (cargo_recno) or hill_id2 (extra_para)
587 // depend on the priority of the hill block
set_hill(int hillId)588 void Location::set_hill(int hillId)
589 {
590 	err_when( !can_add_hill() || !hillId );
591 	err_when( !hill_res[hillId] );
592 
593 	// clear LOCATE_WALK_LAND and LOCATE_WALK_SEA bits
594 	walkable_off();
595 
596 	if( has_hill() )
597 	{
598 		// already has a hill block
599 		// compare which is on the top, swap if necessary
600 		if(hill_res[cargo_recno]->priority <= hill_res[hillId]->priority)
601 		{
602 			err_when(cargo_recno >= 256);
603 			extra_para = (unsigned char) cargo_recno;
604 			cargo_recno = hillId;
605 		}
606 		else
607 		{
608 			// if two hill blocks there, the lower one get replaced
609 			err_when( hillId >= 256);
610 			extra_para = (unsigned char) hillId;
611 		}
612 	}
613 	else
614 	{
615 		// no existing hill block
616 		loc_flag = loc_flag & ~(LOCATE_BLOCK_MASK | LOCATE_SITE_MASK )
617 			| (LOCATE_IS_HILL | LOCATE_SITE_RESERVED);
618 		cargo_recno = hillId;
619 		extra_para = 0;
620 	}
621 }
622 //------------ End of function Location::set_hill ------------//
623 
624 
625 //---------- Begin of function Location::remove_hill ------------//
remove_hill()626 void Location::remove_hill()
627 {
628 	err_when( !has_hill() );
629 
630 	loc_flag &= ~(LOCATE_BLOCK_MASK | LOCATE_SITE_MASK);
631 
632 	extra_para  = 0;
633 	cargo_recno = 0;
634 	// err_when(is_firm());
635 	// BUGHERE : need to call walkable_reset();
636 }
637 //------------ End of function Location::remove_hill ------------//
638 
639 
640 //---------- Begin of function Location::set_wall ------------//
641 //
642 // <int> wallId	 = the id. of the wall
643 // <int> townRecno = recno of the town which the wall belongs to
644 // <int> hitPoints = hit points remained for the wall
645 //
set_wall(int wallId,int townRecno,int hitPoints)646 void Location::set_wall(int wallId, int townRecno, int hitPoints)
647 {
648 	err_when( !can_build_wall() || !wallId );
649 
650 	walkable_off();
651 	loc_flag = loc_flag & ~(LOCATE_BLOCK_MASK | LOCATE_SITE_MASK )
652 		| (LOCATE_IS_WALL | LOCATE_SITE_RESERVED);
653 
654 	extra_para  = wallId;
655 	cargo_recno = (hitPoints<<8) + townRecno;
656 }
657 //------------ End of function Location::set_wall ------------//
658 
659 
660 //------------ Begin of function Location::set_wall_creating ------------//
set_wall_creating()661 void Location::set_wall_creating()
662 {
663 	err_when( !is_wall() );
664 	int hp = wall_hit_point();
665 	if( hp < 0)
666 		hp = -hp;
667 	cargo_recno = (hp << 8) | wall_town_recno();
668 }
669 //------------ End of function Location::set_wall_creating ------------//
670 
671 
672 //------------ Begin of function Location::set_wall_destructing------------//
set_wall_destructing()673 void Location::set_wall_destructing()
674 {
675 	err_when( !is_wall() );
676 	int hp = wall_hit_point();
677 	if( hp > 0)
678 		hp = -hp;
679 	cargo_recno = (hp << 8) | wall_town_recno();
680 }
681 //------------ End of function Location::set_wall_desctructing ------------//
682 
683 
684 //------------ Begin of function Location::inc_wall_hit_point ------------//
inc_wall_hit_point(int grow)685 int Location::inc_wall_hit_point(int grow)
686 {
687 	err_when( !is_wall() );
688 	int hp = wall_hit_point();
689 	if( hp < 0 && hp > -grow)
690 	{
691 		hp = 0;
692 	}
693 	else if( hp > 100-grow)
694 	{
695 		hp = 100;
696 	}
697 	else
698 		hp += grow;
699 	cargo_recno = (hp << 8) | wall_town_recno();
700 	return hp;
701 }
702 //------------ End of function Location::inc_wall_hit_point ------------//
703 
704 
705 //------------ Begin of function Location::attack_wall ------------//
706 //
707 // attack wall
708 // int damage       damage to a wall
709 // note : if the return value is 0, call world.correct_wall to
710 //        correct the shape of the adjacent squares
711 //
attack_wall(int damage)712 int Location::attack_wall(int damage)
713 {
714 	err_when( !is_wall() );
715 
716 	if(damage >= WALL_DEFENCE + MIN_WALL_DAMAGE)    // damage >= 8, damage -= 5
717 		damage -= WALL_DEFENCE;
718 	else if( damage >= MIN_WALL_DAMAGE )            // 3 <= damage < 8, damage = 3
719 		damage = MIN_WALL_DAMAGE;
720 	else if( damage <= 0)                           // 0 < damage < 3, no change to
721 		return wall_hit_point();                     // no change to hit point to damage
722 
723 	int hp = wall_hit_point();
724 	if( hp > 0)
725 	{
726 		hp-= damage;
727 		if( hp <= 0)
728 		{
729 			hp = 0;
730 			remove_wall();
731 			return 0;
732 		}
733 	}
734 	else if( hp < 0)
735 	{
736 		hp+= damage;
737 		if( hp >= 0)
738 		{
739 			hp = 0;
740 			remove_wall();
741 			return 0;
742 		}
743 	}
744 	cargo_recno = (hp << 8) | wall_town_recno();
745 	return hp;
746 }
747 //------------ End of function Location::attack_wall ------------//
748 
749 
750 //---------- Begin of function Location::remove_wall ------------//
751 //
752 // <int> setTimeOut   call set_wall_timeout to refuse building wall at the same place
753 //                    0 to disable timeout, -1 to take default: 10
754 //
remove_wall(int setTimeOut)755 void Location::remove_wall(int setTimeOut)
756 {
757 	err_when( !is_wall() );
758 
759 	loc_flag &= ~(LOCATE_BLOCK_MASK | LOCATE_SITE_MASK);
760 	extra_para  = 0;
761 	cargo_recno = 0;
762 	walkable_reset();
763 
764 	if( setTimeOut < 0)
765 		set_wall_timeout( DEFAULT_WALL_TIMEOUT );
766 	else if( setTimeOut > 0)
767 	{
768 		err_when( setTimeOut > 255 );
769 		set_wall_timeout( setTimeOut );
770 	}
771 
772 
773 	err_when(is_firm());
774 }
775 //------------ End of function Location::remove_wall ------------//
776 
777 
778 //---------- Begin of function Location::set_plant ------------//
779 //
set_plant(int plantId,int offsetX,int offsetY)780 void Location::set_plant(int plantId, int offsetX, int offsetY)
781 {
782 	err_when( !can_add_plant() || !plantId );
783 
784 	walkable_off();
785 	loc_flag = loc_flag & ~(LOCATE_BLOCK_MASK | LOCATE_SITE_MASK )
786 		| (LOCATE_IS_PLANT | LOCATE_SITE_RESERVED);
787 
788 	extra_para  = plantId;
789 	cargo_recno = (offsetY<<8) + offsetX;
790 	err_when(cargo_recno==0 || is_firm());
791 }
792 //------------ End of function Location::set_plant ------------//
793 
794 
795 //---------- Begin of function Location::remove_plant ------------//
796 //
remove_plant()797 void Location::remove_plant()
798 {
799 	err_when( !is_plant() );
800 
801 	loc_flag &= ~(LOCATE_BLOCK_MASK | LOCATE_SITE_MASK);
802 	extra_para  = 0;
803 	cargo_recno = 0;
804 	walkable_reset();
805 
806 	err_when(is_firm());
807 }
808 //------------ End of function Location::remove_plant ------------//
809 
810 
811 //---------- Begin of function Location::set_rock ------------//
812 //
set_rock(short rockArrayRecno)813 void Location::set_rock(short rockArrayRecno)
814 {
815 	err_when( !can_add_rock(3) || !rockArrayRecno );
816 	walkable_off();
817 	loc_flag = loc_flag & ~LOCATE_BLOCK_MASK | LOCATE_IS_ROCK;
818 
819 	cargo_recno = rockArrayRecno;
820 }
821 //------------ End of function Location::set_rock ------------//
822 
823 
824 //---------- Begin of function Location::remove_rock ------------//
825 //
remove_rock()826 void Location::remove_rock()
827 {
828 	err_when( !is_rock() );
829 
830 	loc_flag &= ~LOCATE_BLOCK_MASK;
831 	cargo_recno = 0;
832 	walkable_reset();
833 }
834 //------------ End of function Location::remove_rock ------------//
835 
836 
837 //-------- Begin of function Location::has_unit --------//
838 // return 0 or unit recno
has_unit(int mobileType)839 int Location::has_unit(int mobileType)
840 {
841 	switch(mobileType)
842 	{
843 		// #### patch begin Gilbert 5/8 #######//
844 		case UNIT_LAND:
845 			if( walkable() )
846 				return cargo_recno;
847 			break;
848 
849 		case UNIT_SEA:
850 			if( sailable() )
851 				return cargo_recno;
852 			break;
853 
854 		case UNIT_AIR:
855 			return air_cargo_recno;
856 			break;
857 		// #### patch end Gilbert 5/8 #######//
858 	}
859 
860 	return 0;
861 }
862 //-------- End of function Location::has_unit --------//
863 
864 
865 //-------- Begin of function Location::has_any_unit --------//
866 // <int> mobileType - (default: UNIT_LAND)
867 //
868 // return the mobile_type if there is any unit here
869 // return 0 otherwise
870 //
has_any_unit(int mobileType)871 int Location::has_any_unit(int mobileType)
872 {
873 	if(mobileType==UNIT_LAND)
874 	{
875 		if(air_cargo_recno)
876 			return UNIT_AIR;
877 		else if(walkable() && cargo_recno)
878 			return UNIT_LAND;
879 		else if(sailable() && cargo_recno)
880 			return UNIT_SEA;
881 	}
882 	else
883 	{
884 		if(walkable() && cargo_recno)
885 			return UNIT_LAND;
886 		else if(sailable() && cargo_recno)
887 			return UNIT_SEA;
888 		else if(air_cargo_recno)
889 			return UNIT_AIR;
890 	}
891 
892 	return 0;
893 }
894 //-------- End of function Location::has_any_unit --------//
895 
896 
897 //-------- Begin of function Location::get_any_unit --------//
898 //
899 // <int&> mobileType - var for returning the mobile type of
900 //								unit in the location.
901 //
902 // return: <int> unit recno of the unit.
903 //
get_any_unit(int & mobileType)904 int Location::get_any_unit(int& mobileType)
905 {
906 	if(air_cargo_recno)
907 	{
908 		mobileType = UNIT_AIR;
909 		return air_cargo_recno;
910 	}
911 	else if(walkable() && cargo_recno)
912 	{
913 		mobileType = UNIT_LAND;
914 		return cargo_recno;
915 	}
916 	else if(sailable() && cargo_recno)
917 	{
918 		mobileType = UNIT_SEA;
919 		return cargo_recno;
920 	}
921 
922 	return 0;
923 }
924 //-------- End of function Location::get_any_unit --------//
925 
926 
927 //-------- Begin of function Location::is_unit_group_accessible --------//
928 //
929 // Return whether the location can be accessed by the unit of the specific
930 // unit group id.
931 //
932 // return : <int> whether the location can be accessed by the unit of
933 //						the specific unit group id.
934 //
is_unit_group_accessible(int mobileType,uint32_t curGroupId)935 int Location::is_unit_group_accessible(int mobileType, uint32_t curGroupId)
936 {
937 	if(is_accessible(mobileType))
938 	{
939 		int unitRecno = unit_recno(mobileType);
940 
941 		return unitRecno==0 || unit_array[unitRecno]->unit_group_id == curGroupId;
942 	}
943 
944 	return 0;
945 }
946 //-------- End of function Location::is_unit_group_accessible --------//
947 
948 //### begin alex 24/6 ###//
949 //-------- Begin of function Location::set_power_on --------//
set_power_on()950 void Location::set_power_on()
951 {
952 	loc_flag &= ~LOCATE_POWER_OFF;
953 }
954 //-------- End of function Location::set_power_on --------//
955 
956 
957 //-------- Begin of function Location::set_power_off --------//
set_power_off()958 void Location::set_power_off()
959 {
960 	loc_flag |= LOCATE_POWER_OFF;
961 }
962 //-------- End of function Location::set_power_off --------//
963 
964 
965 //-------- Begin of function Location::is_power_off --------//
is_power_off()966 int Location::is_power_off()
967 {
968 	return (loc_flag & LOCATE_POWER_OFF);
969 }
970 //-------- End of function Location::is_power_off --------//
971 //#### end alex 24/6 ####//
972