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    : OUNITD.CPP
22 //Description : Object Unit defense functions
23 //Owner		  : Alex
24 
25 #include <ALL.h>
26 #include <OUNIT.h>
27 #include <OWORLD.h>
28 #include <OFIRM.h>
29 #include <ONATION.h>
30 #include <OTOWN.h>
31 #include <OF_CAMP.h>
32 #include <OF_MONS.h>
33 
34 #ifdef NO_DEBUG_UNIT
35 #undef err_when
36 #undef err_here
37 #undef err_if
38 #undef err_else
39 #undef err_now
40 #define err_when(cond)
41 #define err_here()
42 #define err_if(cond)
43 #define err_else
44 #define err_now(msg)
45 #undef DEBUG
46 #endif
47 
48 //=================================================================================================//
49 // Unit's defend mode generalized functions
50 //=================================================================================================//
51 
52 //--------- Begin of function Unit::in_any_defense_mode ---------//
53 // check whether the unit is in defense mode
54 //
55 // return 1 if it is
56 // return 0 otherwise
57 //
in_any_defense_mode()58 int Unit::in_any_defense_mode()
59 {
60 	return (action_mode2>=ACTION_AUTO_DEFENSE_ATTACK_TARGET && action_mode2<=ACTION_MONSTER_DEFEND_BACK_FIRM);
61 }
62 //----------- End of function Unit::in_any_defense_mode -----------//
63 
64 
65 //--------- Begin of function Unit::general_defend_mode_detect_target ---------//
66 // call the appropriate defend function for the current type of defend
67 //
68 // <int> checkDefendMode	-	flag to check defend mode or not
69 //
general_defend_mode_detect_target(int checkDefendMode)70 void Unit::general_defend_mode_detect_target(int checkDefendMode)
71 {
72 	stop();
73 	switch(action_mode2)
74 	{
75 		case ACTION_AUTO_DEFENSE_ATTACK_TARGET:
76 				defense_detect_target();
77 				break;
78 
79 		case ACTION_DEFEND_TOWN_ATTACK_TARGET:
80 				defend_town_detect_target();
81 				break;
82 
83 		case ACTION_MONSTER_DEFEND_ATTACK_TARGET:
84 				monster_defend_detect_target();
85 				break;
86 
87 		default: if(checkDefendMode)
88 						err_here();
89 					break;
90 	}
91 }
92 //----------- End of function Unit::general_defend_mode_detect_target -----------//
93 
94 
95 //--------- Begin of function Unit::general_defend_mode_process_attack_target ---------//
96 // process unit defense action. If target is dead, action_mode changes to detect_mode
97 //
98 // return 1 if action mode changes to detect mode
99 // return 0 otherwise
100 //
general_defend_mode_process_attack_target()101 int Unit::general_defend_mode_process_attack_target()
102 {
103 	Location *locPtr;
104 	Unit *unitPtr;
105 	Town *townPtr;
106 	Firm *firmPtr;
107 	SpriteInfo	*spriteInfo;
108 	FirmInfo		*firmInfo;
109 	int clearToDetect = 0;
110 
111 	//------------------------------------------------------------------------------//
112 	// if the unit's action mode is in defensive attack action, process the corresponding
113 	// checking.
114 	//------------------------------------------------------------------------------//
115 	switch(action_mode)
116 	{
117 		case ACTION_ATTACK_UNIT:
118 				if(unit_array.is_deleted(action_para2))
119 					clearToDetect++;
120 				else
121 				{
122 					err_when(unit_array.is_deleted(action_para2));
123 					unitPtr = unit_array[action_para2];
124 
125 					//if(unitPtr->cur_action==SPRITE_IDLE)
126 					//	clearToDetect++;
127 
128 					if(!nation_can_attack(unitPtr->nation_recno)) // cannot attack this nation
129 						clearToDetect++;
130 				}
131 				break;
132 
133 		case ACTION_ATTACK_FIRM:
134 				if(firm_array.is_deleted(action_para2))
135 					clearToDetect++;
136 				else
137 				{
138 					err_when(firm_array.is_deleted(action_para2));
139 					firmPtr = firm_array[action_para2];
140 
141 					if(!nation_can_attack(firmPtr->nation_recno)) // cannot attack this nation
142 						clearToDetect++;
143 				}
144 				break;
145 
146 		case ACTION_ATTACK_TOWN:
147 				if(town_array.is_deleted(action_para2))
148 					clearToDetect++;
149 				else
150 				{
151 					err_when(town_array.is_deleted(action_para2));
152 					townPtr = town_array[action_para2];
153 
154 					if(!nation_can_attack(townPtr->nation_recno)) // cannot attack this nation
155 						clearToDetect++;
156 				}
157 				break;
158 
159 		case ACTION_ATTACK_WALL:
160 				locPtr = world.get_loc(action_x_loc2, action_y_loc2);
161 
162 				if(!locPtr->is_wall() || !nation_can_attack(locPtr->power_nation_recno))
163 					clearToDetect++;
164 				break;
165 
166 		default: clearToDetect++;
167 					break;
168 	}
169 
170 	//------------------------------------------------------------------------------//
171 	// suitation changed to defensive detecting mode
172 	//------------------------------------------------------------------------------//
173 	if(clearToDetect)
174 	{
175 		//----------------------------------------------------------//
176 		// target is dead, change to detect state for another target
177 		//----------------------------------------------------------//
178 		reset_action_para();
179 		return 1;
180 	}
181 	else if(waiting_term<ATTACK_WAITING_TERM)
182 		waiting_term++;
183 	else
184 	{
185 		//------------------------------------------------------------------------------//
186 		// process the corresponding attacking procedure.
187 		//------------------------------------------------------------------------------//
188 		waiting_term = 0;
189 		switch(action_mode)
190 		{
191 			case ACTION_ATTACK_UNIT:
192 				err_when(unit_array.is_deleted(action_para2) || !unitPtr);
193 				spriteInfo = unitPtr->sprite_info;
194 
195 				//-----------------------------------------------------------------//
196 				// attack the target if able to reach the target surrounding, otherwise
197 				// continue to wait
198 				//-----------------------------------------------------------------//
199 				action_x_loc2 = unitPtr->next_x_loc(); // update target location
200 				action_y_loc2 = unitPtr->next_y_loc();
201 				if(space_for_attack(action_x_loc2, action_y_loc2, unitPtr->mobile_type, spriteInfo->loc_width, spriteInfo->loc_height))
202 					attack_unit(unitPtr->sprite_recno);
203 				break;
204 
205 			case ACTION_ATTACK_FIRM:
206 				err_when(firm_array.is_deleted(action_para2) || !firmPtr);
207 				firmInfo = firm_res[firmPtr->firm_id];
208 
209 				//-----------------------------------------------------------------//
210 				// attack the target if able to reach the target surrounding, otherwise
211 				// continue to wait
212 				//-----------------------------------------------------------------//
213 				attack_firm(action_x_loc2, action_y_loc2);
214 
215 				if(!is_in_surrounding(move_to_x_loc, move_to_y_loc, sprite_info->loc_width, action_x_loc2, action_y_loc2,
216 					firmInfo->loc_width, firmInfo->loc_height))
217 					waiting_term = 0;
218 				break;
219 
220 			case ACTION_ATTACK_TOWN:
221 				err_when(town_array.is_deleted(action_para2) || !townPtr);
222 
223 				//-----------------------------------------------------------------//
224 				// attack the target if able to reach the target surrounding, otherwise
225 				// continue to wait
226 				//-----------------------------------------------------------------//
227 				attack_town(action_x_loc2, action_y_loc2);
228 
229 				if(!is_in_surrounding(move_to_x_loc, move_to_y_loc, sprite_info->loc_width, action_x_loc2, action_y_loc2,
230 					STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT))
231 					waiting_term = 0;
232 				break;
233 
234 			case ACTION_ATTACK_WALL:
235 				err_when(action_para || action_para2);
236 
237 				attack_wall(action_x_loc2, action_y_loc2);
238 				if(!is_in_surrounding(move_to_x_loc, move_to_y_loc, sprite_info->loc_width, action_x_loc2, action_y_loc2, 1, 1))
239 					waiting_term = 0;
240 				break;
241 
242 			default:
243 				err_here();
244 				break;
245 		}
246 	}
247 
248 	return 0;
249 }
250 //----------- End of function Unit::general_defend_mode_process_attack_target -----------//
251 
252 
253 //=================================================================================================//
254 // Unit's defense mode
255 //=================================================================================================//
256 
257 //--------- Begin of function Unit::defense_attack_unit ---------//
258 // defensive attack units
259 //
260 // <short>	targetRecno	-	recno of the target
261 //
defense_attack_unit(short targetRecno)262 void Unit::defense_attack_unit(short targetRecno)
263 {
264 	action_mode2 = ACTION_AUTO_DEFENSE_ATTACK_TARGET;
265 	attack_unit(targetRecno);
266 }
267 //----------- End of function Unit::defense_attack_unit -----------//
268 
269 
270 //--------- Begin of function Unit::defense_attack_firm ---------//
271 // defensive attack firm
272 //
273 // <short>	targetXLoc	-	x location of the firm
274 // <short>	targetYLoc	-	y location of the firm
275 //
defense_attack_firm(int targetXLoc,int targetYLoc)276 void Unit::defense_attack_firm(int targetXLoc, int targetYLoc)
277 {
278 	action_mode2 = ACTION_AUTO_DEFENSE_ATTACK_TARGET;
279 	attack_firm(targetXLoc, targetYLoc);
280 }
281 //----------- End of function Unit::defense_attack_firm -----------//
282 
283 
284 //--------- Begin of function Unit::defense_attack_town ---------//
285 // defensive attack town
286 //
287 // <short>	targetXLoc	-	x location of the town
288 // <short>	targetYLoc	-	y location of the town
289 //
defense_attack_town(int targetXLoc,int targetYLoc)290 void Unit::defense_attack_town(int targetXLoc, int targetYLoc)
291 {
292 	action_mode2 = ACTION_AUTO_DEFENSE_ATTACK_TARGET;
293 	attack_town(targetXLoc, targetYLoc);
294 }
295 //----------- End of function Unit::defense_attack_town -----------//
296 
297 
298 //--------- Begin of function Unit::defense_attack_wall ---------//
299 // defensive attack wall
300 //
301 // <short>	targetXLoc	-	x location of wall
302 // <short>	targetYLoc	-	y location of wall
303 //
defense_attack_wall(int targetXLoc,int targetYLoc)304 void Unit::defense_attack_wall(int targetXLoc, int targetYLoc)
305 {
306 	action_mode2 = ACTION_AUTO_DEFENSE_ATTACK_TARGET;
307 	attack_wall(targetXLoc, targetYLoc);
308 }
309 //----------- End of function Unit::defense_attack_wall -----------//
310 
311 
312 //--------- Begin of function Unit::defense_detect_target ---------//
313 // set parameters for unit's defensive mode
314 //
defense_detect_target()315 void Unit::defense_detect_target()
316 {
317 	action_mode2 = ACTION_AUTO_DEFENSE_DETECT_TARGET;
318 	action_para2 = AUTO_DEFENSE_DETECT_COUNT;
319 	action_x_loc2 = -1;
320 	action_y_loc2 = -1;
321 }
322 //----------- End of function Unit::defense_detect_target -----------//
323 
324 
325 //--------- Begin of function Unit::defense_back_camp ---------//
326 // set parameters for unit's to return camp
327 //
328 // <int>	firmXLoc	-	x location of the firm
329 // <int>	firmYLoc -	y location of the firm
330 //
defense_back_camp(int firmXLoc,int firmYLoc)331 void Unit::defense_back_camp(int firmXLoc, int firmYLoc)
332 {
333 	err_when(firm_array[world.get_loc(firmXLoc, firmYLoc)->firm_recno()]->firm_id!=FIRM_CAMP);
334 	err_when(firm_array[world.get_loc(firmXLoc, firmYLoc)->firm_recno()]->firm_recno!=action_misc_para);
335 
336 	assign(firmXLoc, firmYLoc);
337 	action_mode2 = ACTION_AUTO_DEFENSE_BACK_CAMP;
338 }
339 //----------- End of function Unit::defense_back_camp -----------//
340 
341 
342 //--------- Begin of function Unit::process_auto_defense_attack_target ---------//
343 // process the action for unit's defensive attack
344 //
process_auto_defense_attack_target()345 void Unit::process_auto_defense_attack_target()
346 {
347 	err_when(action_mode2!=ACTION_AUTO_DEFENSE_ATTACK_TARGET);
348 	if(general_defend_mode_process_attack_target())
349 	{
350 		defense_detect_target();
351 		err_when(action_mode!=ACTION_STOP || action_para || action_x_loc!=-1 || action_y_loc!=-1 || cur_action==SPRITE_ATTACK);
352 	}
353 }
354 //----------- End of function Unit::process_auto_defense_attack_target -----------//
355 
356 
357 //--------- Begin of function Unit::process_auto_defense_detect_target ---------//
358 // process action for unit's defensive detecet target
359 //
process_auto_defense_detect_target()360 void Unit::process_auto_defense_detect_target()
361 {
362 	err_when(action_mode2!=ACTION_AUTO_DEFENSE_DETECT_TARGET);
363 	err_when(action_mode!=ACTION_STOP);
364 	err_when(action_para!=0);
365 	err_when(action_x_loc!=-1 || action_y_loc!=-1 || action_x_loc!=-1 || action_y_loc2!=-1);
366 
367 	//----------------------------------------------------------------//
368 	// no target or target is out of detect range, so change state to
369 	// back camp
370 	//----------------------------------------------------------------//
371 	if(!action_para2)
372 	{
373 		err_when(action_misc!=ACTION_MISC_DEFENSE_CAMP_RECNO || !action_misc_para);
374 		int back = 0;
375 		FirmCamp *campPtr;
376 		Unit *targetPtr;
377 
378 		if(firm_array.is_deleted(action_misc_para))
379 			back++;
380 		else
381 		{
382 			campPtr = (FirmCamp*) firm_array[action_misc_para];
383 			if(unit_array.is_deleted(campPtr->defend_target_recno))
384 				back++;
385 			else
386 			{
387 				targetPtr = unit_array[campPtr->defend_target_recno];
388 				if(targetPtr->action_mode!=ACTION_ATTACK_FIRM || targetPtr->action_para!=campPtr->firm_recno)
389 					back++;
390 			}
391 		}
392 
393 		if(!back)
394 		{
395 			//action_mode2 = ACTION_AUTO_DEFENSE_DETECT_TARGET;
396 			action_para2 = AUTO_DEFENSE_DETECT_COUNT;
397 			return;
398 		}
399 
400 		process_auto_defense_back_camp();
401 		return;
402 	}
403 
404 	//----------------------------------------------------------------//
405 	// defense_detecting target algorithm
406 	//----------------------------------------------------------------//
407 	int startLoc;
408 	int dimension;
409 
410 	switch(action_para2%GAME_FRAMES_PER_DAY)
411 	{
412 		case 3:	startLoc = 2;// 1-7, check 224 = 15^2-1
413 					//### begin alex 3/10 ###//
414 					dimension = 7;
415 					//#### end alex 3/10 ####//
416 					break;
417 
418 		case 2:	startLoc = 122;// 6-8, check 168 = 17^2-11^2
419 					dimension = 8;
420 					break;
421 
422 		case 1:	startLoc = 170;// 7-9, check 192 = 19^2-13^2
423 					dimension = EFFECTIVE_AUTO_DEFENSE_DISTANCE;
424 					break;
425 
426 		default: action_para2--;
427 					return;
428 	}
429 
430 	//---------------------------------------------------------------//
431 	// attack the target if target detected, or change the detect region
432 	//---------------------------------------------------------------//
433 	if(!idle_detect_attack(startLoc, dimension, 1)) // defense mode is on
434 		action_para2--;
435 }
436 //----------- End of function Unit::process_auto_defense_detect_target -----------//
437 
438 
439 //--------- Begin of function Unit::process_auto_defense_back_camp ---------//
440 // process action for the units to return camp
441 //
process_auto_defense_back_camp()442 void Unit::process_auto_defense_back_camp()
443 {
444 	int	clearDefenseMode = 0;
445 	if(action_mode!=ACTION_ASSIGN_TO_FIRM) // the unit may become idle or unable to reach firm, reactivate it
446 	{
447 		Firm	*firmPtr;
448 		if(action_misc!=ACTION_MISC_DEFENSE_CAMP_RECNO || !action_misc_para || firm_array.is_deleted(action_misc_para))
449 			clearDefenseMode++;
450 		else
451 		{
452 			firmPtr = firm_array[action_misc_para];
453 			if(firmPtr->firm_id!=FIRM_CAMP || firmPtr->nation_recno!=nation_recno)
454 				clearDefenseMode++;
455 			else
456 			{
457 				defense_back_camp(firmPtr->loc_x1, firmPtr->loc_y1); // go back to the military camp
458 				err_when(action_mode2!=ACTION_AUTO_DEFENSE_BACK_CAMP);
459 				return;
460 			}
461 		}
462 	}
463 	else if(cur_action==SPRITE_IDLE)
464 	{
465 		if(firm_array.is_deleted(action_misc_para))
466 			clearDefenseMode++;
467 		else
468 		{
469 			Firm *firmPtr = firm_array[action_misc_para];
470 			defense_back_camp(firmPtr->loc_x1, firmPtr->loc_y1);
471 			err_when(action_mode2!=ACTION_AUTO_DEFENSE_BACK_CAMP);
472 			return;
473 		}
474 	}
475 
476 	err_when(!clearDefenseMode);
477 	//----------------------------------------------------------------//
478 	// clear order if the camp is deleted
479 	//----------------------------------------------------------------//
480 	stop2();
481 	reset_action_misc_para();
482 	err_when(in_auto_defense_mode());
483 }
484 //----------- End of function Unit::process_auto_defense_back_camp -----------//
485 
486 
487 //------------- Begin of function Unit::in_auto_defense_mode --------------//
488 // check whether the units in auto defense mode
489 //
in_auto_defense_mode()490 int Unit::in_auto_defense_mode()
491 {
492 	return (action_mode2>=ACTION_AUTO_DEFENSE_ATTACK_TARGET && action_mode2<=ACTION_AUTO_DEFENSE_BACK_CAMP);
493 }
494 //----------- End of function Unit::in_auto_defense_mode -----------//
495 
496 
497 //------------- Begin of function Unit::defense_follow_target --------------//
498 // decide whether to follow the target
499 //
500 // return 0 if aborting attack the current target and go back to military camp
501 // return 1 otherwise
502 //
defense_follow_target()503 int Unit::defense_follow_target()
504 {
505 	#define PROB_HOSTILE_RETURN	10
506 	#define PROB_FRIENDLY_RETURN	20
507 	#define PROB_NEUTRAL_RETURN	30
508 
509 	if(unit_array.is_deleted(action_para))
510 		return 1;
511 
512 	if(cur_action==SPRITE_ATTACK)
513 		return 1;
514 
515 	Unit *targetPtr = unit_array[action_para];
516 	Location *locPtr = world.get_loc(action_x_loc, action_y_loc);
517 	if(!locPtr->has_unit(targetPtr->mobile_type))
518 		return 1; // the target may be dead or invisible
519 
520 	int returnFactor, abortAction = 0;
521 
522 	//-----------------------------------------------------------------//
523 	// calculate the chance to go back to military camp in following the
524 	// target
525 	//-----------------------------------------------------------------//
526 	if(locPtr->power_nation_recno==nation_recno)
527 		return 1; // target within our nation
528 	else if(!locPtr->power_nation_recno) // is neutral
529 		returnFactor = PROB_NEUTRAL_RETURN;
530 	else
531 	{
532 		Nation *locNationPtr = nation_array[locPtr->power_nation_recno];
533 		if(locNationPtr->get_relation_status(nation_recno)==NATION_HOSTILE)
534 			returnFactor = PROB_HOSTILE_RETURN;
535 		else
536 			returnFactor = PROB_FRIENDLY_RETURN;
537 	}
538 
539 	if(!abortAction)
540 	{
541 		SpriteInfo *targetSpriteInfo = targetPtr->sprite_info;
542 
543 		//-----------------------------------------------------------------//
544 		// if the target moves faster than this unit, it is more likely for
545 		// this unit to go back to military camp.
546 		//-----------------------------------------------------------------//
547 		//-**** should also consider the combat level and hit_points of both unit ****-//
548 		if(targetSpriteInfo->speed > sprite_info->speed)
549 			returnFactor -= 5;
550 
551 		if(misc.random(returnFactor)==0) // return to camp if true
552 			abortAction++;
553 		else
554 			return 1;
555 	}
556 
557 	err_when(!abortAction);
558 	err_when(action_mode==ACTION_ASSIGN_TO_FIRM); // if so, process_auto_defense_back_camp() cannot process successfully
559 	process_auto_defense_back_camp();
560 	return 0; // cancel attack
561 }
562 //----------- End of function Unit::defense_follow_target -----------//
563 
564 
565 //------------- Begin of function Unit::clear_unit_defense_mode --------------//
566 // clear defensive mode
567 //
clear_unit_defense_mode()568 void Unit::clear_unit_defense_mode()
569 {
570 	//------- cancel defense mode and continue the current action -------//
571 	action_mode2 = action_mode;
572 	action_para2 = action_para;
573 	action_x_loc2 = action_x_loc;
574 	action_y_loc2 = action_y_loc;
575 
576 	reset_action_misc_para();
577 
578 	if( unit_mode == UNIT_MODE_DEFEND_TOWN )
579 		set_mode(0);		// reset unit mode
580 }
581 //----------------- End of function Unit::clear_unit_defense_mode ----------------//
582 
583 
584 //=================================================================================================//
585 // Town unit's defend mode, eg rebel
586 //=================================================================================================//
587 
588 //--------- Begin of function Unit::defend_town_attack_unit ---------//
589 // set to defensive mode
590 //
591 // <short>	targetRecno	-	record of target
592 //
defend_town_attack_unit(short targetRecno)593 void Unit::defend_town_attack_unit(short targetRecno)
594 {
595 	action_mode2 = ACTION_DEFEND_TOWN_ATTACK_TARGET;
596 	attack_unit(targetRecno);
597 }
598 //----------- End of function Unit::defend_town_attack_unit -----------//
599 
600 
601 //------------- Begin of function Unit::defend_town_detect_target --------------//
602 // set to detect mode
603 //
defend_town_detect_target()604 void Unit::defend_town_detect_target()
605 {
606 	action_mode2 = ACTION_DEFEND_TOWN_DETECT_TARGET;
607 	action_para2 = UNIT_DEFEND_TOWN_DETECT_COUNT;
608 	action_x_loc2 = -1;
609 	action_y_loc2 = -1;
610 }
611 //----------- End of function Unit::defend_town_detect_target -----------//
612 
613 
614 //------------- Begin of function Unit::process_defend_town_attack_target --------------//
615 // defend town units is only allowed to attack unit
616 //
process_defend_town_attack_target()617 void Unit::process_defend_town_attack_target()
618 {
619 	err_when(action_mode2!=ACTION_DEFEND_TOWN_ATTACK_TARGET);
620 	if(general_defend_mode_process_attack_target())
621 	{
622 		action_mode2 = ACTION_DEFEND_TOWN_DETECT_TARGET;
623 		action_para2 = UNIT_DEFEND_TOWN_DETECT_COUNT;
624 		action_x_loc2 = action_y_loc2 = -1;
625 		err_when(action_mode!=ACTION_STOP || action_para || action_x_loc!=-1 || action_y_loc!=-1 || cur_action==SPRITE_ATTACK);
626 	}
627 }
628 //----------------- End of function Unit::process_defend_town_attack_target ----------------//
629 
630 
631 //------------- Begin of function Unit::process_defend_town_detect_target --------------//
632 // process detect mode
633 //
process_defend_town_detect_target()634 void Unit::process_defend_town_detect_target()
635 {
636 	err_when(action_mode2!=ACTION_DEFEND_TOWN_DETECT_TARGET);
637 	err_when(action_mode!=ACTION_STOP);
638 	err_when(action_para!=0);
639 	err_when(action_x_loc!=-1 || action_y_loc!=-1 || action_x_loc2!=-1 || action_y_loc2!=-1);
640 
641 	//----------------------------------------------------------------//
642 	// no target or target is out of detect range, so change state to
643 	// back camp
644 	//----------------------------------------------------------------//
645 	if(!action_para2)
646 	{
647 		err_when(action_misc!=ACTION_MISC_DEFEND_TOWN_RECNO || !action_misc_para);
648 		err_when(unit_mode!=UNIT_MODE_DEFEND_TOWN || !unit_mode_para);
649 		int back = 0;
650 		Town *townPtr;
651 		Unit *targetPtr;
652 
653 		if(town_array.is_deleted(action_misc_para))
654 			back++;
655 		else
656 		{
657 			townPtr = town_array[action_misc_para];
658 			if(unit_array.is_deleted(townPtr->defend_target_recno))
659 				back++;
660 			else
661 			{
662 				targetPtr = unit_array[townPtr->defend_target_recno];
663 				if(targetPtr->action_mode!=ACTION_ATTACK_TOWN || targetPtr->action_para!=townPtr->town_recno)
664 					back++;
665 			}
666 		}
667 
668 		if(!back)
669 		{
670 			//action_mode2 = ACTION_DEFEND_TOWN_DETECT_TARGET;
671 			action_para2 = UNIT_DEFEND_TOWN_DETECT_COUNT;
672 			return;
673 		}
674 
675 		process_defend_town_back_town();
676 		return;
677 	}
678 
679 	//----------------------------------------------------------------//
680 	// defense_detecting target algorithm
681 	//----------------------------------------------------------------//
682 	int startLoc;
683 	int dimension;
684 
685 	switch(action_para2%GAME_FRAMES_PER_DAY)
686 	{
687 		case 3:	startLoc = 2;// 1-7, check 224 = 15^2-1
688 					//### begin alex 3/10 ###//
689 					dimension = 7;
690 					//#### end alex 3/10 ####//
691 					break;
692 
693 		case 2:	startLoc = 122;// 6-8, check 168 = 17^2-11^2
694 					dimension = 8;
695 					break;
696 
697 		case 1:	startLoc = 170;// 7-9, check 192 = 19^2-13^2
698 					dimension = EFFECTIVE_DEFEND_TOWN_DISTANCE;
699 					break;
700 
701 		default: action_para2--;
702 					return;
703 	}
704 
705 	//---------------------------------------------------------------//
706 	// attack the target if target detected, or change the detect region
707 	//---------------------------------------------------------------//
708 
709 	if(!idle_detect_attack(startLoc, dimension, 1)) // defense mode is on
710 		action_para2--;
711 }
712 //----------------- End of function Unit::process_defend_town_detect_target ----------------//
713 
714 
715 //------------- Begin of function Unit::process_defend_town_back_town --------------//
716 // process action to go back town
717 //
process_defend_town_back_town()718 void Unit::process_defend_town_back_town()
719 {
720 	int	clearDefenseMode = 0;
721 	if(action_mode!=ACTION_ASSIGN_TO_TOWN) // the unit may become idle or unable to reach town, reactivate it
722 	{
723 		Town	*townPtr;
724 		if(action_misc!=ACTION_MISC_DEFEND_TOWN_RECNO || !action_misc_para || town_array.is_deleted(action_misc_para))
725 			clearDefenseMode++;
726 		else
727 		{
728 			townPtr = town_array[action_misc_para];
729 			if(townPtr->nation_recno!=nation_recno)
730 				clearDefenseMode++;
731 			else
732 			{
733 				defend_town_back_town(action_misc_para); // go back to the town
734 				err_when(action_mode2!=ACTION_DEFEND_TOWN_BACK_TOWN);
735 				return;
736 			}
737 		}
738 	}
739 	else if(cur_action==SPRITE_IDLE)
740 	{
741 		if(town_array.is_deleted(action_misc_para))
742 			clearDefenseMode++;
743 		else
744 		{
745 			defend_town_back_town(action_misc_para);
746 			err_when(action_mode2!=ACTION_DEFEND_TOWN_BACK_TOWN);
747 			return;
748 		}
749 	}
750 
751 	err_when(!clearDefenseMode);
752 	//----------------------------------------------------------------//
753 	// clear order if the town is deleted
754 	//----------------------------------------------------------------//
755 	stop2();
756 	reset_action_misc_para();
757 	err_when(in_defend_town_mode());
758 }
759 //----------------- End of function Unit::process_defend_town_back_town ----------------//
760 
761 
762 //------------- Begin of function Unit::in_defend_town_mode --------------//
763 // check whether the unit is in defend town mode
764 //
in_defend_town_mode()765 int Unit::in_defend_town_mode()
766 {
767 	return (action_mode2>=ACTION_DEFEND_TOWN_ATTACK_TARGET && action_mode2<=ACTION_DEFEND_TOWN_BACK_TOWN);
768 }
769 //----------------- End of function Unit::in_defend_town_mode ----------------//
770 
771 
772 //--------- Begin of function Unit::defend_town_back_town ---------//
773 // set action to back town
774 //
775 // <int>	townRecno	-	recno of the town
776 //
defend_town_back_town(short townRecno)777 void Unit::defend_town_back_town(short townRecno)
778 {
779 	err_when(town_array.is_deleted(townRecno));
780 	Town *townPtr = town_array[townRecno];
781 
782 	assign(townPtr->loc_x1, townPtr->loc_y1);
783 	action_mode2 = ACTION_DEFEND_TOWN_BACK_TOWN;
784 }
785 //----------- End of function Unit::defend_town_back_town -----------//
786 
787 
788 //------------- Begin of function Unit::defend_town_follow_target --------------//
789 // check the unit should follow the target or not
790 //
791 // return 0 if aborting attack the current target and go back to military camp
792 // return 1 otherwise
793 //
defend_town_follow_target()794 int Unit::defend_town_follow_target()
795 {
796 	err_when(unit_mode!=UNIT_MODE_DEFEND_TOWN);
797 
798 	if(cur_action==SPRITE_ATTACK)
799 		return 1;
800 
801 	if(town_array.is_deleted(unit_mode_para))
802 	{
803 		stop2(); //**** BUGHERE
804 		set_mode(0); //***BUGHERE
805 		return 0;
806 	}
807 
808 	int curXLoc = next_x_loc();
809 	int curYLoc = next_y_loc();
810 
811 	Town *townPtr = town_array[unit_mode_para];
812 	if((curXLoc<townPtr->center_x-UNIT_DEFEND_TOWN_DISTANCE) || (curXLoc>townPtr->center_x+UNIT_DEFEND_TOWN_DISTANCE) ||
813 		(curYLoc<townPtr->center_y-UNIT_DEFEND_TOWN_DISTANCE) || (curYLoc>townPtr->center_y+UNIT_DEFEND_TOWN_DISTANCE))
814 	{
815 		defend_town_back_town(unit_mode_para);
816 		return 0;
817 	}
818 
819 	return 1;
820 }
821 //----------- End of function Unit::defend_town_follow_target -----------//
822 
823 
824 //------------- Begin of function Unit::clear_town_defend_mode --------------//
825 // clear defend mode
826 //
clear_town_defend_mode()827 void Unit::clear_town_defend_mode()
828 {
829 	//------- cancel defense mode and continue the current action -------//
830 	action_mode2 = action_mode;
831 	action_para2 = action_para;
832 	action_x_loc2 = action_x_loc;
833 	action_y_loc2 = action_y_loc;
834 
835 	reset_action_misc_para();
836 }
837 //----------------- End of function Unit::clear_town_defend_mode ----------------//
838 
839 
840 //=================================================================================================//
841 // Monster unit's defend mode
842 //=================================================================================================//
843 
844 //--------- Begin of function Unit::monster_defend_attack_unit ---------//
845 // set to attack target
846 //
847 // <short> targetRecno	-	recno of the target
848 //
monster_defend_attack_unit(short targetRecno)849 void Unit::monster_defend_attack_unit(short targetRecno)
850 {
851 	action_mode2 = ACTION_MONSTER_DEFEND_ATTACK_TARGET;
852 	attack_unit(targetRecno);
853 }
854 //----------- End of function Unit::monster_defend_attack_unit -----------//
855 
856 
857 //--------- Begin of function Unit::monster_defend_attack_firm ---------//
858 // set monster to attack firm
859 //
860 // <int>	targetXLoc	-	x location of firm
861 // <int>	targetYLoc	-	y location of firm
862 //
monster_defend_attack_firm(int targetXLoc,int targetYLoc)863 void Unit::monster_defend_attack_firm(int targetXLoc, int targetYLoc)
864 {
865 	action_mode2 = ACTION_MONSTER_DEFEND_ATTACK_TARGET;
866 	attack_firm(targetXLoc, targetYLoc);
867 }
868 //----------- End of function Unit::monster_defend_attack_firm -----------//
869 
870 
871 //--------- Begin of function Unit::monster_defend_attack_town ---------//
872 // set monster to attack town
873 //
874 // <int>	targetXLoc	-	x location of the town
875 // <int>	targetYLoc	-	y location of the town
876 //
monster_defend_attack_town(int targetXLoc,int targetYLoc)877 void Unit::monster_defend_attack_town(int targetXLoc, int targetYLoc)
878 {
879 	action_mode2 = ACTION_MONSTER_DEFEND_ATTACK_TARGET;
880 	attack_town(targetXLoc, targetYLoc);
881 }
882 //----------- End of function Unit::monster_defend_attack_town -----------//
883 
884 
885 //--------- Begin of function Unit::monster_defend_attack_wall ---------//
886 // set monster to attack wall
887 //
888 // <int>	targetXLoc	-	x location of wall
889 // <int>	targetYLoc	-	y location of wall
890 //
monster_defend_attack_wall(int targetXLoc,int targetYLoc)891 void Unit::monster_defend_attack_wall(int targetXLoc, int targetYLoc)
892 {
893 	action_mode2 = ACTION_MONSTER_DEFEND_ATTACK_TARGET;
894 	attack_wall(targetXLoc, targetYLoc);
895 }
896 //----------- End of function Unit::monster_defend_attack_wall -----------//
897 
898 
899 //--------- Begin of function Unit::monster_defend_detect_target ---------//
900 // set to detect mode
901 //
monster_defend_detect_target()902 void Unit::monster_defend_detect_target()
903 {
904 	action_mode2 = ACTION_MONSTER_DEFEND_DETECT_TARGET;
905 	action_para2 = MONSTER_DEFEND_DETECT_COUNT;
906 	action_x_loc2 = -1;
907 	action_y_loc2 = -1;
908 }
909 //----------- End of function Unit::monster_defend_detect_target -----------//
910 
911 
912 //--------- Begin of function Unit::monster_defend_back_firm ---------//
913 // set to return mode
914 //
monster_defend_back_firm(int firmXLoc,int firmYLoc)915 void Unit::monster_defend_back_firm(int firmXLoc, int firmYLoc)
916 {
917 	err_when(firm_array[world.get_loc(firmXLoc, firmYLoc)->firm_recno()]->firm_id!=FIRM_MONSTER);
918 
919 	assign(firmXLoc, firmYLoc);
920 	action_mode2 = ACTION_MONSTER_DEFEND_BACK_FIRM;
921 }
922 //----------- End of function Unit::monster_defend_back_firm -----------//
923 
924 
925 //--------- Begin of function Unit::process_monster_defend_attack_target ---------//
926 // proces attack mode
927 //
process_monster_defend_attack_target()928 void Unit::process_monster_defend_attack_target()
929 {
930 	err_when(action_mode2!=ACTION_MONSTER_DEFEND_ATTACK_TARGET);
931 	if(general_defend_mode_process_attack_target())
932 	{
933 		monster_defend_detect_target();
934 		err_when(action_mode!=ACTION_STOP || action_para || action_x_loc!=-1 || action_y_loc!=-1 || cur_action==SPRITE_ATTACK);
935 	}
936 }
937 //----------- End of function Unit::process_monster_defend_attack_target -----------//
938 
939 
940 //--------- Begin of function Unit::process_monster_defend_detect_target ---------//
941 // process detect mode
942 //
process_monster_defend_detect_target()943 void Unit::process_monster_defend_detect_target()
944 {
945 	err_when(action_mode2!=ACTION_MONSTER_DEFEND_DETECT_TARGET);
946 	err_when(action_mode!=ACTION_STOP);
947 	err_when(action_para!=0);
948 	err_when(action_x_loc!=-1 || action_y_loc!=-1 || action_x_loc!=-1 || action_y_loc2!=-1);
949 
950 	//----------------------------------------------------------------//
951 	// no target or target is out of detect range, so change state to
952 	// back camp
953 	//----------------------------------------------------------------//
954 	if(!action_para2)
955 	{
956 		err_when(action_misc!=ACTION_MISC_MONSTER_DEFEND_FIRM_RECNO || !action_misc_para);
957 		err_when(unit_mode!=UNIT_MODE_MONSTER || !unit_mode_para);
958 		int back = 0;
959 		Unit *targetPtr;
960 		FirmMonster *firmMonsterPtr;
961 
962 		if(firm_array.is_deleted(action_misc_para))
963 			back++;
964 		else
965 		{
966 			firmMonsterPtr = (FirmMonster*) firm_array[action_misc_para];
967 			if(unit_array.is_deleted(firmMonsterPtr->defend_target_recno))
968 				back++;
969 			else
970 			{
971 				targetPtr = unit_array[firmMonsterPtr->defend_target_recno];
972 				if(targetPtr->action_mode!=ACTION_ATTACK_FIRM || targetPtr->action_para!=firmMonsterPtr->firm_recno)
973 					back++;
974 			}
975 		}
976 
977 		if(!back)
978 		{
979 			//action_mode2 = ACTION_MONSTER_DEFEND_DETECT_TARGET;
980 			action_para2 = MONSTER_DEFEND_DETECT_COUNT;
981 			return;
982 		}
983 
984 		process_monster_defend_back_firm();
985 		return;
986 	}
987 
988 	//----------------------------------------------------------------//
989 	// defense_detecting target algorithm
990 	//----------------------------------------------------------------//
991 	int startLoc;
992 	int dimension;
993 
994 	switch(action_para2%GAME_FRAMES_PER_DAY)
995 	{
996 		case 3:	startLoc = 2;// 1-7, check 224 = 15^2-1
997 					//### begin alex 3/10 ###//
998 					dimension = 7;
999 					//#### end alex 3/10 ####//
1000 					break;
1001 
1002 		case 2:	startLoc = 122;// 6-8, check 168 = 17^2-11^2
1003 					dimension = 8;
1004 					break;
1005 
1006 		case 1:	startLoc = 170;// 7-9, check 192 = 19^2-13^2
1007 					dimension = EFFECTIVE_MONSTER_DEFEND_FIRM_DISTANCE;
1008 					break;
1009 
1010 		default: action_para2--;
1011 					return;
1012 	}
1013 
1014 	//---------------------------------------------------------------//
1015 	// attack the target if target detected, or change the detect region
1016 	//---------------------------------------------------------------//
1017 	if(!idle_detect_attack(startLoc, dimension, 1)) // defense mode is on
1018 		action_para2--;
1019 }
1020 //----------- End of function Unit::process_monster_defend_detect_target -----------//
1021 
1022 
1023 //--------- Begin of function Unit::process_monster_defend_back_firm ---------//
1024 // process return mode
1025 //
process_monster_defend_back_firm()1026 void Unit::process_monster_defend_back_firm()
1027 {
1028 	int	clearDefendMode = 0;
1029 	if(action_mode!=ACTION_ASSIGN_TO_FIRM) // the unit may become idle or unable to reach firm, reactivate it
1030 	{
1031 		Firm	*firmPtr;
1032 		if(action_misc!=ACTION_MISC_MONSTER_DEFEND_FIRM_RECNO || !action_misc_para || firm_array.is_deleted(action_misc_para))
1033 			clearDefendMode++;
1034 		else
1035 		{
1036 			firmPtr = firm_array[action_misc_para];
1037 			if(firmPtr->firm_id!=FIRM_MONSTER || firmPtr->nation_recno!=nation_recno)
1038 				clearDefendMode++;
1039 			else
1040 			{
1041 				monster_defend_back_firm(firmPtr->loc_x1, firmPtr->loc_y1); // go back to the military camp
1042 				err_when(action_mode2!=ACTION_MONSTER_DEFEND_BACK_FIRM);
1043 				return;
1044 			}
1045 		}
1046 	}
1047 	else if(cur_action==SPRITE_IDLE)
1048 	{
1049 		if(firm_array.is_deleted(action_misc_para))
1050 			clearDefendMode++;
1051 		else
1052 		{
1053 			Firm *firmPtr = firm_array[action_misc_para];
1054 			monster_defend_back_firm(firmPtr->loc_x1, firmPtr->loc_y1);
1055 			err_when(action_mode2!=ACTION_MONSTER_DEFEND_BACK_FIRM);
1056 			return;
1057 		}
1058 	}
1059 
1060 	err_when(!clearDefendMode);
1061 	//----------------------------------------------------------------//
1062 	// clear order if the camp is deleted
1063 	//----------------------------------------------------------------//
1064 	stop2();
1065 	reset_action_misc_para();
1066 	err_when(in_monster_defend_mode());
1067 }
1068 //----------- End of function Unit::process_monster_defend_back_firm -----------//
1069 
1070 
1071 //------------- Begin of function Unit::in_monster_defend_mode --------------//
1072 // check whether the unit is in defend mode
1073 //
in_monster_defend_mode()1074 int Unit::in_monster_defend_mode()
1075 {
1076 	return (action_mode2>=ACTION_MONSTER_DEFEND_ATTACK_TARGET && action_mode2<=ACTION_MONSTER_DEFEND_BACK_FIRM);
1077 }
1078 //----------- End of function Unit::in_monster_defend_mode -----------//
1079 
1080 
1081 //------------- Begin of function Unit::monster_defend_follow_target --------------//
1082 // make decision to choose to follow target or return
1083 //
1084 // return 0 if aborting attack the current target and go back to military camp
1085 // return 1 otherwise
1086 //
monster_defend_follow_target()1087 int Unit::monster_defend_follow_target()
1088 {
1089 //######## begin trevor 22/8 ##########//
1090 	err_when( unit_mode!=UNIT_MODE_MONSTER || !unit_mode_para );
1091 
1092 	if(cur_action==SPRITE_ATTACK)
1093 		return 1;
1094 /*
1095 	if(firm_array.is_deleted(action_misc_para))
1096 	{
1097 		stop2(); //**** BUGHERE
1098 		//set_mode(0); //***BUGHERE
1099 		if(monster_array.is_deleted(unit_mode_para))
1100 			return 0;
1101 
1102 		Monster *monsterPtr = monster_array[unit_mode_para];
1103 		monsterPtr->firm_recno = 0;
1104 		return 0;
1105 	}
1106 */
1107 //######## end trevor 22/8 ##########//
1108 
1109 	//--------------------------------------------------------------------------------//
1110 	// choose to return to firm
1111 	//--------------------------------------------------------------------------------//
1112 	int curXLoc = next_x_loc();
1113 	int curYLoc = next_y_loc();
1114 
1115 	Firm *firmPtr = firm_array[action_misc_para];
1116 	if((curXLoc<firmPtr->center_x-MONSTER_DEFEND_FIRM_DISTANCE) || (curXLoc>firmPtr->center_x+MONSTER_DEFEND_FIRM_DISTANCE) ||
1117 		(curYLoc<firmPtr->center_y-MONSTER_DEFEND_FIRM_DISTANCE) || (curYLoc>firmPtr->center_y+MONSTER_DEFEND_FIRM_DISTANCE))
1118 	{
1119 		monster_defend_back_firm(firmPtr->loc_x1, firmPtr->loc_y1);
1120 		return 0;
1121 	}
1122 
1123 	return 1;
1124 }
1125 //----------- End of function Unit::monster_defend_follow_target -----------//
1126 
1127 
1128 //------------- Begin of function Unit::clear_monster_defend_mode --------------//
1129 // clear defend mode
1130 //
clear_monster_defend_mode()1131 void Unit::clear_monster_defend_mode()
1132 {
1133 	err_when(!in_monster_defend_mode());
1134 
1135 	//------- cancel defense mode and continue the current action -------//
1136 	action_mode2 = action_mode;
1137 	action_para2 = action_para;
1138 	action_x_loc2 = action_x_loc;
1139 	action_y_loc2 = action_y_loc;
1140 
1141 	reset_action_misc_para();
1142 }
1143 //----------------- End of function Unit::clear_monster_defend_mode ----------------//
1144