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    : OUNITI.CPP
22 //Description : Object Unit idle processing
23 //Owner       : Alex
24 
25 #include <ALL.h>
26 #include <OWORLD.h>
27 #include <OU_MARI.h>
28 #include <ONATION.h>
29 #include <OF_MONS.h>
30 #include <OTOWN.h>
31 #include <OSPY.h>
32 #include <OREBEL.h>
33 #include <OSYS.h>
34 #include <OU_GOD.h>
35 
36 #ifdef NO_DEBUG_UNIT
37 #undef err_when
38 #undef err_here
39 #undef err_if
40 #undef err_else
41 #undef err_now
42 #define err_when(cond)
43 #define err_here()
44 #define err_if(cond)
45 #define err_else
46 #define err_now(msg)
47 #undef DEBUG
48 #endif
49 
50 //-------------- define static variables -----------//
51 static char		idle_detect_has_unit;
52 static char		idle_detect_has_firm;
53 static char		idle_detect_has_town;
54 static char		idle_detect_has_wall;
55 static short	idle_detect_target_unit_recno;
56 static short	idle_detect_target_firm_recno;
57 static short	idle_detect_target_town_recno;
58 static short	idle_detect_target_wall_x1;
59 static short	idle_detect_target_wall_y1;
60 
61 static int		idle_detect_default_mode;
62 
63 static int		help_mode;
64 static short	help_attack_target_recno;
65 
66 //--------- Begin of function Unit::process_idle ---------//
67 // process actions for idle units
68 //
process_idle()69 void Unit::process_idle()
70 {
71 	err_when(result_path_dist || result_node_array);
72 
73    //---- if the unit is defending the town ----//
74 
75    switch( unit_mode )
76    {
77       case UNIT_MODE_REBEL:
78          if(action_mode2==ACTION_STOP)
79          {
80             process_rebel(); // redirect to process_rebel for rebel units
81             return;
82          }
83          break;
84 
85 		case UNIT_MODE_MONSTER:
86 			if(action_mode2==ACTION_STOP)
87 			{
88 				if(unit_mode_para)
89 				{
90 					if(!firm_array.is_deleted(unit_mode_para))
91 					{
92 						//-------- return to monster firm -----------//
93 						FirmMonster *monsterFirmPtr = (FirmMonster*) firm_array[unit_mode_para];
94 						assign(monsterFirmPtr->loc_x1, monsterFirmPtr->loc_y1);
95 						return;
96 					}
97 					else
98 						unit_mode_para = 0;
99 				}
100 			}
101 			break;
102    }
103 
104 	//------------- process way point ------------//
105 	if(action_mode==ACTION_STOP && action_mode2==ACTION_STOP && way_point_count)
106 	{
107 		err_when(way_point_count < 0);
108 		if(way_point_count==1)
109 			reset_way_point_array();
110 		else
111 			process_way_point();
112 		return;
113 	}
114 
115    //-------- randomize direction --------//
116 
117    err_when(result_node_array!=NULL);
118 
119    //-------------------------------------------------------//
120    // when the unit is idle, the following should be always true
121    // move_to_x_loc == next_x_loc()
122    // move_to_y_loc == next_y_loc()
123    //-------------------------------------------------------//
124 
125    err_when(move_to_x_loc!=next_x_loc() || move_to_y_loc!=next_y_loc());
126 	//move_to_x_loc = next_x_loc();     //***************BUGHERE
127    //move_to_y_loc = next_y_loc();
128    err_when(next_x!=cur_x || next_y!=cur_y);
129 
130    if(match_dir())
131    {
132 		if(!is_guarding() && race_id )     // only these units can move
133 		{
134 			if(!misc.random(150))             // change direction randomly
135 				set_dir(misc.random(8));
136 		}
137 	}
138 	else
139 		return;
140 
141 	err_when(turn_delay);
142 	//------- call Sprite::process_idle() -------//
143 
144 	Sprite::process_idle();
145 
146 	//-*********************** simulate ship movment ***************************-//
147 	/*if(unit_res[unit_id]->unit_class==UNIT_CLASS_SHIP)
148 	{
149 		unit_group_id = 1;
150 		if(cur_action==SPRITE_IDLE)
151 		{
152 			if(misc.random(50))
153 				return;
154 		}
155 		else if(cur_action!=SPRITE_READY_TO_MOVE)
156 		{
157 			if(misc.random(30)==0)
158 				return;
159 		}
160 
161 		int xOffset = misc.random(30)*(misc.random(2) ? 1 : -1);
162 		int yOffset = misc.random(30)*(misc.random(2) ? 1 : -1);
163 		int curXLoc = next_x_loc();
164 		int curYLoc = next_y_loc();
165 		int destXLoc = curXLoc+xOffset;
166 		int destYLoc = curYLoc+yOffset;
167 
168 		if(destXLoc<0)	destXLoc = 0;
169 		else if(destXLoc>=MAX_WORLD_X_LOC)	destXLoc = MAX_WORLD_X_LOC-1;
170 		if(destYLoc<0) destYLoc = 0;
171 		else if(destYLoc>=MAX_WORLD_Y_LOC)	destYLoc = MAX_WORLD_Y_LOC-1;
172 
173 		Location *locPtr = world.get_loc(destXLoc, destYLoc);
174 		int tempX, tempY;
175 		if(terrain_res[locPtr->terrain_id]->average_type==TERRAIN_OCEAN)
176 			move_to(destXLoc, destYLoc);
177 		else
178 			ship_to_beach(destXLoc, destYLoc, tempX, tempY);
179 
180 		Nation *nationPtr = nation_array[nation_recno];
181 		if(nationPtr->cash<5000)
182 			nationPtr->cash += 10000;
183 		if(nationPtr->food<5000)
184 			nationPtr->food += 10000;
185 		if(hit_points<max_hit_points)
186 			hit_points = max_hit_points;
187 		return;
188 	}
189 	*/
190 	//-*********************** simulate ship movment ***************************-//
191 
192 	//---------------------------------------------------------------------------//
193 	// reset idle blocked attacking unit.  If the previous condition is totally
194 	// blocked for attacking target, try again now
195 	// Note: reset blocked_edge is essentail for idle unit to reactivate attack
196 	// action
197 	//---------------------------------------------------------------------------//
198 	if(action_mode>=ACTION_ATTACK_UNIT && action_mode<=ACTION_ATTACK_WALL)
199 	{
200 		if(unit_array.idle_blocked_unit_reset_count && *(uint32_t*)blocked_edge)
201 		{
202 			unit_array.idle_blocked_unit_reset_count = 0;
203 			memset(blocked_edge, 0, sizeof(char)*4);
204 			err_when(blocked_edge[0] || blocked_edge[1] || blocked_edge[2] || blocked_edge[3]);
205 		}
206 	}
207 
208    err_when(action_mode==ACTION_STOP && cur_action==SPRITE_ATTACK);
209    err_when(action_mode==ACTION_ATTACK_UNIT && action_para==0);
210 
211 	//--------- reactivate action -----------//
212 
213 	if(reactivate_idle_action())
214    {
215       err_when(action_mode==ACTION_STOP && cur_action==SPRITE_ATTACK);
216       err_when(action_mode==ACTION_ATTACK_UNIT && action_para==0);
217       return; // true if an action is reactivated
218    }
219 
220 	//-**************** simulate aat ********************-//
221 	#ifdef DEBUG
222 		if(debug_sim_game_type==2)
223 		{
224 			//int curXLoc = next_x_loc();
225 			//int curYLoc = next_y_loc();
226 			//int destXLoc, destYLoc;
227 
228 			if(misc.random(30))
229 				move_to(misc.random(MAX_WORLD_X_LOC), misc.random(MAX_WORLD_Y_LOC));
230 
231 			Nation *nationPtr = nation_array[nation_recno];
232 			if(nationPtr->cash<2000)
233 				nationPtr->cash += 8000;
234 			if(nationPtr->food<2000)
235 				nationPtr->food += 8000;
236 			return;
237 		}
238 	#endif
239 	//-**************** simulate aat ********************-//
240 
241    err_when(action_mode==ACTION_STOP && cur_action==SPRITE_ATTACK);
242    err_when(action_mode==ACTION_ATTACK_UNIT && action_para==0);
243 
244 	//----------- for ai unit idle -----------//
245 
246 	if( action_mode != ACTION_STOP || action_mode2 != ACTION_STOP )		// only detect attack when the unit is really idle
247 		return;
248 
249 	if( !can_attack() )
250 		return; // cannot attack
251 
252 	err_when(!can_attack());
253 	err_when(action_mode==ACTION_STOP && cur_action==SPRITE_ATTACK);
254 	err_when(action_mode==ACTION_ATTACK_UNIT && action_para==0);
255 
256 	//--- only detect attack if in aggressive mode or the unit is a monster ---//
257 
258 	UnitInfo* unitInfo = unit_res[unit_id];
259 
260 	if( unitInfo->unit_class == UNIT_CLASS_MONSTER || aggressive_mode  )
261 	{
262 		//----------- detect target to attack -----------//
263 
264 		if( idle_detect_attack() )
265 		{
266 			err_when(action_mode==ACTION_STOP && cur_action==SPRITE_ATTACK);
267 			err_when(action_mode==ACTION_ATTACK_UNIT && action_para==0);
268 			return; // target detected
269 		}
270 
271 		err_when(action_mode==ACTION_STOP && cur_action==SPRITE_ATTACK);
272 		err_when(action_mode==ACTION_ATTACK_UNIT && action_para==0);
273 	}
274 
275 	//------------------------------------------------------------------//
276 	// wander around for monster
277 	//------------------------------------------------------------------//
278 
279 	if( unitInfo->unit_class == UNIT_CLASS_MONSTER )
280 	{
281 		if(misc.random(500)==0)
282 		{
283 			#define WANDER_DIST 20
284 
285 			int xOffset = misc.random(WANDER_DIST)-WANDER_DIST/2;
286 			int yOffset = misc.random(WANDER_DIST)-WANDER_DIST/2;
287 			int destX = next_x_loc()+xOffset;
288 			int destY = next_y_loc()+yOffset;
289 
290 			if(destX<0) destX = 0;
291 			else if(destX>=MAX_WORLD_X_LOC) destX = MAX_WORLD_X_LOC-1;
292 			if(destY<0) destY = 0;
293 			else if(destY>=MAX_WORLD_Y_LOC) destY = MAX_WORLD_Y_LOC-1;
294 			move_to(destX, destY);
295 		}
296 	}
297 }
298 //----------- End of function Unit::process_idle -----------//
299 
300 
301 //--------- Begin of function Unit::reactivate_idle_action --------//
302 // resume actions for idle units
303 //
304 // return 1 if an action is reactivated
305 // return 0 otherwise
306 //
reactivate_idle_action()307 int Unit::reactivate_idle_action()
308 {
309    if(action_mode2==ACTION_STOP)
310       return 0; // return for no idle action
311 
312    if(!is_dir_correct())
313       return 1; // cheating for turning the direction
314 
315 	//------------------- declare parameters ----------------------//
316    Location    *locPtr;
317    Firm        *firmPtr;
318    FirmInfo    *firmInfo;
319    Unit        *unitPtr;
320    UnitMarine  *shipPtr;
321    SpriteInfo  *spriteInfo;
322    int         canMove = 1;
323 
324    int         returnFlag = 0;
325    int         curXLoc = move_to_x_loc;
326    int         curYLoc = move_to_y_loc;
327    int         dummyX, dummyY;
328 
329 	int			hasSearch = 0;
330 	int			validSearch = seek_path.is_valid_searching();
331 
332 	seek_path.set_status(PATH_WAIT);
333 	err_when(seek_path.path_status==PATH_NODE_USED_UP);
334    switch(action_mode2)
335    {
336       case ACTION_STOP:
337       case ACTION_DIE:
338                return 0; // do nothing
339 
340       case ACTION_ATTACK_UNIT:
341                if(unit_array.is_deleted(action_para2))
342                   stop2();
343                else
344                {
345                   unitPtr = unit_array[action_para2];
346                   spriteInfo = unitPtr->sprite_info;
347 
348                   if(space_for_attack(action_x_loc2, action_y_loc2, unitPtr->mobile_type, spriteInfo->loc_width, spriteInfo->loc_height))
349                   {
350 							//------ there should be place for this unit to attack the target, attempts to attack it ------//
351                      attack_unit(action_para2, 0, 0, 0); // last 0 for not reset blocked_edge
352 							hasSearch++;
353                      returnFlag = 1;
354                      break;
355                   }
356                }
357                break;
358 
359       case ACTION_ATTACK_FIRM:
360                locPtr = world.get_loc(action_x_loc2, action_y_loc2);
361                if(!locPtr->is_firm())
362                   stop2(); // stop since target is already destroyed
363                else
364                {
365                   firmPtr = firm_array[action_para2];
366                   firmInfo = firm_res[firmPtr->firm_id];
367 
368                   if(space_for_attack(action_x_loc2, action_y_loc2, UNIT_LAND, firmInfo->loc_width, firmInfo->loc_height))
369                   {
370 							//-------- attack target since space is found for this unit to move to ---------//
371                      attack_firm(action_x_loc2, action_y_loc2, 0, 0, 0); // last 0 for not reset blocked_edge
372 							hasSearch++;
373                      returnFlag = 1;
374                      break;
375                   }
376                }
377                break;
378 
379       case ACTION_ATTACK_TOWN:
380                locPtr = world.get_loc(action_x_loc2, action_y_loc2);
381                if(!locPtr->is_town())
382                   stop2(); // stop since target is deleted
383                else if(space_for_attack(action_x_loc2, action_y_loc2, UNIT_LAND, STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT))
384                {
385 						//---------- attack target --------//
386                   attack_town(action_x_loc2, action_y_loc2, 0, 0, 0); // last 0 for not reset blocked_edge
387 						hasSearch++;
388                   returnFlag = 1;
389                   break;
390                }
391                break;
392 
393       case ACTION_ATTACK_WALL:
394                locPtr = world.get_loc(action_x_loc2, action_y_loc2);
395                if(!locPtr->is_wall())
396                   stop2(); // stop since target doesn't exist
397                else if(space_for_attack(action_x_loc2, action_y_loc2, UNIT_LAND, 1, 1))
398                {
399 						//----------- attack target -----------//
400                   attack_wall(action_x_loc2, action_y_loc2, 0, 0, 0); // last 0 for not reset blocked_edge
401 						hasSearch++;
402                   returnFlag = 1;
403                   break;
404                }
405                break;
406 
407       case ACTION_ASSIGN_TO_FIRM:
408       case ACTION_ASSIGN_TO_TOWN:
409       case ACTION_ASSIGN_TO_VEHICLE:
410 					//---------- resume assign actions -------------//
411 					err_when(action_x_loc2==-1 || action_y_loc2==-1 || !action_para2);
412                assign(action_x_loc2, action_y_loc2);
413 					hasSearch++;
414                waiting_term = 0;
415                returnFlag = 1;
416                break;
417 
418       case ACTION_ASSIGN_TO_SHIP:
419 					//------------ try to assign to marine ------------//
420 					err_when(action_x_loc2==-1 || action_y_loc2==-1 || !action_para2);
421                assign_to_ship(action_x_loc2, action_y_loc2, action_para2);
422 					hasSearch++;
423                waiting_term = 0;
424                returnFlag = 1;
425                break;
426 
427       case ACTION_BUILD_FIRM:
428 					//-------------- build again ----------------//
429 					err_when(action_x_loc2==-1 || action_y_loc2==-1 || !action_para2);
430                build_firm(action_x_loc2, action_y_loc2, action_para2, COMMAND_AUTO);
431 					hasSearch++;
432                waiting_term = 0;
433                returnFlag = 1;
434                break;
435 
436       case ACTION_SETTLE:
437 					//------------- try again to settle -----------//
438 					err_when(action_x_loc2==-1 || action_y_loc2==-1 || action_para2);
439                settle(action_x_loc2, action_y_loc2);
440 					hasSearch++;
441                waiting_term = 0;
442                returnFlag = 1;
443                break;
444 
445       case ACTION_BURN:
446 					//---------------- resume burn action -----------------//
447 					err_when(action_x_loc2==-1 || action_y_loc2==-1 || action_para2);
448                burn(action_x_loc2, action_y_loc2, COMMAND_AUTO);
449 					hasSearch++;
450                waiting_term = 0;
451                returnFlag = 1;
452                break;
453 
454       case ACTION_MOVE:
455                //if(!avail_node_enough_for_search())
456                //{
457                // returnFlag = 1;
458                // break;
459                //}
460 
461                if(move_to_x_loc!=action_x_loc2 || move_to_y_loc!=action_y_loc2)
462                {
463 						//------- move since the unit has not reached its destination --------//
464                   move_to(action_x_loc2, action_y_loc2, 1);
465 						hasSearch++;
466                   returnFlag = 1;
467                   break;
468                }
469 
470                waiting_term = 0;
471                break;
472 
473       case ACTION_AUTO_DEFENSE_ATTACK_TARGET:
474                if(unit_search_node_used<500) // limit the no. of nods to reactivate idle process
475 					{
476 						//---------- resume action -----------//
477                   process_auto_defense_attack_target();
478 						hasSearch++;
479 					}
480 
481                returnFlag = 1;
482                break;
483 
484       case ACTION_AUTO_DEFENSE_DETECT_TARGET:
485                process_auto_defense_detect_target();
486                returnFlag = 1;
487                break;
488 
489       case ACTION_AUTO_DEFENSE_BACK_CAMP:
490                process_auto_defense_back_camp();
491 					hasSearch++;
492                returnFlag = 1;
493                break;
494 
495       case ACTION_DEFEND_TOWN_ATTACK_TARGET:
496                process_defend_town_attack_target();
497 					hasSearch++;
498                returnFlag = 1;
499                break;
500 
501       case ACTION_DEFEND_TOWN_DETECT_TARGET:
502                process_defend_town_detect_target();
503                returnFlag = 1;
504                break;
505 
506       case ACTION_DEFEND_TOWN_BACK_TOWN:
507                process_defend_town_back_town();
508 					hasSearch++;
509                returnFlag = 1;
510                break;
511 
512       case ACTION_MONSTER_DEFEND_ATTACK_TARGET:
513                process_monster_defend_attack_target();
514 					hasSearch++;
515                returnFlag = 1;
516                break;
517 
518       case ACTION_MONSTER_DEFEND_DETECT_TARGET:
519                process_monster_defend_detect_target();
520                returnFlag = 1;
521                break;
522 
523       case ACTION_MONSTER_DEFEND_BACK_FIRM:
524                process_monster_defend_back_firm();
525 					hasSearch++;
526                returnFlag = 1;
527                break;
528 
529       case ACTION_SHIP_TO_BEACH:
530                shipPtr = (UnitMarine*) this;
531                if(!shipPtr->in_beach || shipPtr->extra_move_in_beach==EXTRA_MOVE_FINISH)
532 					{
533 						//----------- the ship has not reached inlet, so move again --------------//
534                   ship_to_beach(action_x_loc2, action_y_loc2, dummyX, dummyY);
535 						hasSearch++;
536 					}
537 
538                returnFlag = 1;
539                break;
540 
541 		case ACTION_GO_CAST_POWER:
542 					go_cast_power(action_x_loc2, action_y_loc2, ((UnitGod*)this)->cast_power_type, COMMAND_AUTO);
543                returnFlag = 1;
544                break;
545 
546       default: err_here();
547                break;
548    }
549 
550 	if(validSearch && hasSearch && seek_path.path_status==PATH_NODE_USED_UP &&
551 		next_x_loc()==move_to_x_loc && next_y_loc()==move_to_y_loc)
552 	{
553 		//-------------------------------------------------------------------------//
554 		// abort actions since the unit trys to move and move no more.
555 		//-------------------------------------------------------------------------//
556 		stop2(KEEP_DEFENSE_MODE);
557 		return 1;
558 	}
559 
560    int abort=0;
561    if(returnFlag)
562    {
563       if(curXLoc==move_to_x_loc && curYLoc==move_to_y_loc && seek_path.path_status==PATH_NODE_USED_UP)
564       {
565 			//---------------------------------------------------------------------------------//
566 			// insufficient nodes for searching
567 			//---------------------------------------------------------------------------------//
568 			if(action_mode2==ACTION_ASSIGN_TO_SHIP || action_mode2==ACTION_SHIP_TO_BEACH || in_any_defense_mode())
569 				return 1;
570 
571          //------- number of nodes is not enough to find the destination -------//
572          if(action_misc!=ACTION_MISC_STOP)
573          {
574             if(action_misc==ACTION_MISC_PRE_SEARCH_NODE_USED_UP)
575             {
576                if(action_misc_para<20)
577                {
578                   action_misc_para++;
579                   return 0;
580                }
581                else
582                    action_misc_para++;
583             }
584 
585             abort++; // assume destination unreachable, abort action
586          }
587          else
588          {
589             action_misc = ACTION_MISC_PRE_SEARCH_NODE_USED_UP;
590             action_misc_para = 0;
591          }
592       }
593       else // action resumed, return true
594          return 1;
595    }
596 
597    if(!returnFlag || abort)
598    {
599       stop2(KEEP_DEFENSE_MODE);
600    }
601 
602    return 0;
603 }
604 //----------- End of function Unit::reactivate_idle_action -----------//
605 
606 
607 //--------- Begin of function Unit::idle_detect_attack --------//
608 // detect target for idle units
609 //
610 // [int] startLoc       -  (default = 0), used to select region of the square
611 //                         for checking
612 // [int] dimensionInput -  (default = 0), the detected size is calculated as
613 //                         2*dimensionInput+1. this unit is located in
614 //                         the center of the square.
615 // [char] defenseMode   -  true for defensive mode on.
616 //
617 // return 1 if any target is detected
618 // return 0 otherwise
619 //
idle_detect_attack(int startLoc,int dimensionInput,char defenseMode)620 int Unit::idle_detect_attack(int startLoc, int dimensionInput, char defenseMode)
621 {
622    err_when(attack_count==0);
623 
624 	//---------------------------------------------------//
625 	// Set detectDelay.
626 	//
627 	// The larger its value, the less CPU time it will takes,
628 	// but it will also take longer to detect enemies.
629 	//---------------------------------------------------//
630 
631 	int detectDelay = 1+unit_array.packed_size()/10;
632 
633 	Location    *locPtr;
634 	Unit			*unitPtr;
635 	//Unit        *unitPtr, *targetUnitPtr;
636 	//Firm        *firmPtr, *targetFirmPtr;
637 	//Town        *townPtr, *targetTownPtr;
638 	//int         targetWallXLoc, targetWallYLoc;
639 	//char        hasUnit=0, hasFirm=0, hasTown=0, hasWall=0;
640 	char        targetMobileType;
641 	int         dimension, countLimit;
642 	short       targetRecno, i;
643 	int         xOffset, yOffset, checkXLoc, checkYLoc;
644 	idle_detect_default_mode = (!startLoc && !dimensionInput && !defenseMode); //----- true when all zero
645 	idle_detect_has_unit = idle_detect_has_firm = idle_detect_has_town = idle_detect_has_wall = 0;
646 	help_mode = HELP_NOTHING;
647 
648 	err_when(idle_detect_default_mode!=0 && idle_detect_default_mode!=1);
649 
650 	//-----------------------------------------------------------------------------------------------//
651 	// adjust waiting_term for default_mode
652 	//-----------------------------------------------------------------------------------------------//
653 	int lowestBit = (++waiting_term)%detectDelay;
654 
655 	if(action_mode2==ACTION_STOP)
656 	{
657 		err_when(action_mode!=ACTION_STOP);
658 		waiting_term = lowestBit;
659 	}
660 
661 	(dimension = (dimensionInput ? dimensionInput : ATTACK_DETECT_DISTANCE)<<1)++;
662 	countLimit = dimension*dimension;
663 	i = startLoc ? startLoc : 1+lowestBit;
664 	int incAmount = (idle_detect_default_mode) ? detectDelay : 1;
665 
666    //-----------------------------------------------------------------------------------------------//
667    // check the location around the unit
668    //
669    // The priority to choose target is (value of targetType)
670    // 1) Unit, 2) firm, 3) wall
671    //-----------------------------------------------------------------------------------------------//
672    err_when(defenseMode && action_mode2!=ACTION_AUTO_DEFENSE_DETECT_TARGET &&
673 				action_mode2!=ACTION_DEFEND_TOWN_DETECT_TARGET && action_mode2!=ACTION_MONSTER_DEFEND_DETECT_TARGET);
674 
675 	err_when(incAmount<1 || incAmount>100000);
676    for(; i<=countLimit; i+=incAmount) // 1 is the self location
677    {
678       misc.cal_move_around_a_point(i, dimension, dimension, xOffset, yOffset);
679       checkXLoc = move_to_x_loc+xOffset;
680       checkYLoc = move_to_y_loc+yOffset;
681       if(checkXLoc<0 || checkXLoc>=MAX_WORLD_X_LOC || checkYLoc<0 || checkYLoc>=MAX_WORLD_Y_LOC)
682          continue;
683 
684 		//------------------ verify location ---------------//
685       locPtr = world.get_loc(checkXLoc, checkYLoc);
686       if(defenseMode && action_mode2!=ACTION_DEFEND_TOWN_DETECT_TARGET)
687       {
688          if(action_mode2==ACTION_AUTO_DEFENSE_DETECT_TARGET)
689             if(locPtr->power_nation_recno!=nation_recno && locPtr->power_nation_recno)
690                continue; // skip this location because it is not neutral nation or our nation
691       }
692 
693       //----------------------------------------------------------------------------//
694       // checking the target type
695       //----------------------------------------------------------------------------//
696       if((targetMobileType=locPtr->has_any_unit(i==1 ? mobile_type : UNIT_LAND)) &&
697          (targetRecno=locPtr->unit_recno(targetMobileType)) && !unit_array.is_deleted(targetRecno))
698       {
699          //=================== is unit ======================//
700          if(idle_detect_has_unit || (action_para==targetRecno && action_mode==ACTION_ATTACK_UNIT &&
701             checkXLoc==action_x_loc && checkYLoc==action_y_loc))
702             continue; // same target as before
703 
704 			unitPtr = unit_array[targetRecno];
705 			if(nation_recno && unitPtr->nation_recno==nation_recno && help_mode!=HELP_ATTACK_UNIT)
706 				idle_detect_helper_attack(targetRecno); // help our troop
707 			else if((help_mode==HELP_ATTACK_UNIT && help_attack_target_recno==targetRecno) ||
708 					  (unitPtr->nation_recno!=nation_recno && idle_detect_unit_checking(targetRecno)))
709 			{
710 				idle_detect_target_unit_recno = targetRecno;
711 				idle_detect_has_unit++;
712 				break; // break with highest priority
713 			}
714       }
715       else if(locPtr->is_firm() && (targetRecno = locPtr->firm_recno()))
716       {
717          //=============== is firm ===============//
718          if(idle_detect_has_firm || (action_para==targetRecno && action_mode==ACTION_ATTACK_FIRM &&
719             action_x_loc==checkXLoc && action_y_loc==checkYLoc))
720 				continue; // same target as before
721 
722          if(idle_detect_firm_checking(targetRecno))
723          {
724 				idle_detect_target_firm_recno = targetRecno;
725 				idle_detect_has_firm++;
726          }
727       }
728       /*else if(locPtr->is_town() && (targetRecno = locPtr->town_recno()))
729       {
730          //=============== is town ===========//
731          if(idle_detect_has_town || (action_para==targetRecno && action_mode==ACTION_ATTACK_TOWN &&
732             action_x_loc==checkXLoc && action_y_loc==checkYLoc))
733             continue; // same target as before
734 
735          if(idle_detect_town_checking(targetRecno))
736          {
737 				idle_detect_target_town_recno = targetRecno;
738 				idle_detect_has_town++;
739          }
740       }
741       else if(locPtr->is_wall())
742       {
743          //================ is wall ==============//
744          if(idle_detect_has_wall || (action_mode==ACTION_ATTACK_WALL && action_para==targetRecno &&
745             action_x_loc==checkXLoc && action_y_loc==checkYLoc))
746             continue; // same target as before
747 
748          if(idle_detect_wall_checking(checkXLoc, checkYLoc))
749          {
750 				idle_detect_target_wall_x1 = checkXLoc;
751 				idle_detect_target_wall_y1 = checkYLoc;
752 				idle_detect_has_wall++;
753          }
754       }*/
755 
756       //if(hasUnit && hasFirm && hasTown && hasWall)
757       //if(hasUnit && hasFirm && hasWall)
758       //  break; // there is target for attacking
759    }
760 
761 	return idle_detect_choose_target(defenseMode);
762 }
763 //----------- End of function Unit::idle_detect_attack -----------//
764 
765 
766 //--------- Begin of function Unit::idle_detect_unit_checking --------//
767 // check whether to attack the unit with recno = targetRecno
768 //
769 // <short>	targetRecno	-	recno of unit being checked
770 //
771 // return 1 if situation is suitable for attacking
772 // return 0 otherwise
773 //
idle_detect_unit_checking(short targetRecno)774 int Unit::idle_detect_unit_checking(short targetRecno)
775 {
776 	Unit *targetUnitPtr = unit_array[targetRecno];
777 
778 	if(targetUnitPtr->unit_id == UNIT_CARAVAN)
779 		return 0;
780 
781 	//###### trevor 15/10 #######//
782 
783 	//-------------------------------------------//
784 	// If the target is moving, don't attack it.
785 	// Only attack when the unit stands still or
786 	// is attacking.
787 	//-------------------------------------------//
788 
789 	if( targetUnitPtr->cur_action != SPRITE_ATTACK &&
790 		 targetUnitPtr->cur_action != SPRITE_IDLE )
791 	{
792 		return 0;
793 	}
794 
795 	//-------------------------------------------//
796 	// If the target is a spy of our own and the
797 	// notification flag is set to 0, then don't
798 	// attack.
799 	//-------------------------------------------//
800 
801 	if( targetUnitPtr->spy_recno )		// if the target unit is our spy, don't attack
802 	{
803 		Spy* spyPtr = spy_array[targetUnitPtr->spy_recno];
804 
805 		if( spyPtr->true_nation_recno == nation_recno &&
806 			 spyPtr->notify_cloaked_nation_flag == 0 )
807 		{
808 			return 0;
809 		}
810 	}
811 
812 	if( spy_recno )			// if this unit is our spy, don't attack own units
813 	{
814 		Spy* spyPtr = spy_array[spy_recno];
815 
816 		if( spyPtr->true_nation_recno == targetUnitPtr->nation_recno &&
817 			 spyPtr->notify_cloaked_nation_flag == 0 )
818 		{
819 			return 0;
820 		}
821 	}
822 
823 	//###### trevor 15/10 #######//
824 
825 	SpriteInfo *spriteInfo = targetUnitPtr->sprite_info;
826 	Nation   *nationPtr = nation_recno ? nation_array[nation_recno] : NULL;
827 	short    targetNationRecno = targetUnitPtr->nation_recno;
828 
829 	//-------------------------------------------------------------------//
830 	// checking nation relationship
831 	//-------------------------------------------------------------------//
832 
833 	if(nation_recno)
834 	{
835 		if(targetNationRecno)
836 		{
837 			//------- don't attack own units and non-hostile units -------//
838 			err_when(targetNationRecno==nation_recno);
839 
840 			//--------------------------------------------------------------//
841 			// if the unit is hostile, only attack if should_attack flag to
842 			// that nation is true or the unit is attacking somebody or something.
843 			//--------------------------------------------------------------//
844 			NationRelation* nationRelation = nationPtr->get_relation(targetNationRecno);
845 
846 			if( nationRelation->status != NATION_HOSTILE || !nationRelation->should_attack )
847 				return 0;
848 		}
849 		else if(!targetUnitPtr->independent_nation_can_attack(nation_recno))
850 			return 0;
851 	}
852 	else if(!independent_nation_can_attack(targetNationRecno)) // independent unit
853 		return 0;
854 
855 	//---------------------------------------------//
856 	if(space_for_attack(targetUnitPtr->next_x_loc(), targetUnitPtr->next_y_loc(), targetUnitPtr->mobile_type,
857 							  spriteInfo->loc_width, spriteInfo->loc_height))
858 		return 1;
859 	else
860 		return 0;
861 }
862 //----------- End of function Unit::idle_detect_unit_checking -----------//
863 
864 
865 //--------- Begin of function Unit::idle_detect_firm_checking --------//
866 // check whether to attack the firm
867 //
868 // <short>	targetRecno	-	recno of the firm being checked
869 //
870 // return 1 if situation is suitable
871 // return 0 otherwise
872 //
idle_detect_firm_checking(short targetRecno)873 int Unit::idle_detect_firm_checking(short targetRecno)
874 {
875    Firm *firmPtr = firm_array[targetRecno];
876 
877 	//------------ code to select firm for attacking -----------//
878 	switch(firmPtr->firm_id)
879 	{
880 		case FIRM_CAMP:case FIRM_BASE: case FIRM_WAR_FACTORY:
881 				break;
882 
883 		default: return 0;
884 	}
885 
886    Nation   *nationPtr = nation_recno ? nation_array[nation_recno] : NULL;
887    short    targetNationRecno = firmPtr->nation_recno;
888    char     targetMobileType = mobile_type==UNIT_SEA ? UNIT_SEA : UNIT_LAND;
889 
890    //-------------------------------------------------------------------------------//
891    // checking nation relationship
892    //-------------------------------------------------------------------------------//
893    if(nation_recno)
894    {
895       if(targetNationRecno)
896       {
897 			//------- don't attack own units and non-hostile units -------//
898 
899 			if( targetNationRecno==nation_recno )
900 				return 0;
901 
902 			//--------------------------------------------------------------//
903 			// if the unit is hostile, only attack if should_attack flag to
904 			// that nation is true or the unit is attacking somebody or something.
905 			//--------------------------------------------------------------//
906 
907 			NationRelation* nationRelation = nationPtr->get_relation(targetNationRecno);
908 
909 			if( nationRelation->status != NATION_HOSTILE || !nationRelation->should_attack )
910 				return 0;
911       }
912       else // independent firm
913       {
914          FirmMonster *monsterFirmPtr = (FirmMonster*) firm_array[targetRecno];
915 
916 			if(!monsterFirmPtr->is_hostile_nation(nation_recno))
917             return 0;
918       }
919    }
920    else if(!independent_nation_can_attack(targetNationRecno)) // independent town
921       return 0;
922 
923    FirmInfo *firmInfo = firm_res[firmPtr->firm_id];
924    if(space_for_attack(firmPtr->loc_x1, firmPtr->loc_y1, UNIT_LAND, firmInfo->loc_width, firmInfo->loc_height))
925       return 1;
926    else
927       return 0;
928 }
929 //----------- End of function Unit::idle_detect_firm_checking -----------//
930 
931 
932 //--------- Begin of function Unit::idle_detect_town_checking --------//
933 // check town to attack
934 //
935 // <short>	targetRecno	-	recno of town
936 //
937 // return 1 if situation is suitable for attacking
938 // return 0 otherwise
939 //
idle_detect_town_checking(short targetRecno)940 int Unit::idle_detect_town_checking(short targetRecno)
941 {
942    Town     *townPtr = town_array[targetRecno];
943    Nation   *nationPtr = nation_recno ? nation_array[nation_recno] : NULL;
944    short    targetNationRecno = townPtr->nation_recno;
945 
946    //-------------------------------------------------------------------------------//
947    // checking nation relationship
948    //-------------------------------------------------------------------------------//
949    if(nation_recno)
950    {
951       if(targetNationRecno)
952       {
953 			//------- don't attack own units and non-hostile units -------//
954 
955 			if( targetNationRecno==nation_recno )
956 				return 0;
957 
958 			//--------------------------------------------------------------//
959 			// if the unit is hostile, only attack if should_attack flag to
960 			// that nation is true or the unit is attacking somebody or something.
961 			//--------------------------------------------------------------//
962 
963 			NationRelation* nationRelation = nationPtr->get_relation(targetNationRecno);
964 
965 			if( nationRelation->status != NATION_HOSTILE || !nationRelation->should_attack )
966 				return 0;
967       }
968 		else if(!townPtr->is_hostile_nation(nation_recno))
969 			return 0; // false if the indepentent unit don't want to attack us
970    }
971    else if(!independent_nation_can_attack(targetNationRecno)) // independent town
972       return 0;
973 
974    if(space_for_attack(townPtr->loc_x1, townPtr->loc_y1, UNIT_LAND, STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT))
975       return 1;
976    else
977       return 0;
978 }
979 //----------- End of function Unit::idle_detect_town_checking -----------//
980 
981 
982 //--------- Begin of function Unit::idle_detect_wall_checking --------//
983 // check wall to attack
984 //
985 // <int>	targetXLoc	-	wall x location
986 //	<int>	targetYLoc	-	wall y location
987 //
988 // return 1 if situation is suitable for attacking
989 // return 0 otherwise
990 //
idle_detect_wall_checking(int targetXLoc,int targetYLoc)991 int Unit::idle_detect_wall_checking(int targetXLoc, int targetYLoc)
992 {
993    Location *locPtr = world.get_loc(targetXLoc, targetYLoc);
994    Nation   *nationPtr = nation_recno ? nation_array[nation_recno] : NULL;
995    short    targetNationRecno = locPtr->wall_nation_recno();
996 
997    //-------------------------------------------------------------------------------//
998    // checking nation relationship
999    //-------------------------------------------------------------------------------//
1000    if(nation_recno)
1001    {
1002       if(targetNationRecno)
1003       {
1004 			//------- don't attack own units and non-hostile units -------//
1005 
1006 			if( targetNationRecno==nation_recno )
1007 				return 0;
1008 
1009 			//--------------------------------------------------------------//
1010 			// if the unit is hostile, only attack if should_attack flag to
1011 			// that nation is true or the unit is attacking somebody or something.
1012 			//--------------------------------------------------------------//
1013 
1014 			NationRelation* nationRelation = nationPtr->get_relation(targetNationRecno);
1015 
1016 			if( nationRelation->status != NATION_HOSTILE || !nationRelation->should_attack )
1017 				return 0;
1018       }
1019       else
1020          return 0;
1021    }
1022    else if(!independent_nation_can_attack(targetNationRecno)) // independent town
1023       return 0;
1024 
1025    if(space_for_attack(targetXLoc, targetYLoc, UNIT_LAND, 1, 1))
1026       return 1;
1027    else
1028       return 0;
1029 }
1030 //----------- End of function Unit::idle_detect_wall_checking -----------//
1031 
1032 
1033 //--------- Begin of function Unit::idle_detect_choose_target --------//
1034 //
1035 // <char>	defenseMode -	indicate whether defensive mode is on
1036 //
idle_detect_choose_target(char defenseMode)1037 int Unit::idle_detect_choose_target(char defenseMode)
1038 {
1039    //-----------------------------------------------------------------------------------------------//
1040    // Decision making for choosing target to attack
1041 	//-----------------------------------------------------------------------------------------------//
1042    if(defenseMode)
1043    {
1044       if(action_mode2==ACTION_AUTO_DEFENSE_DETECT_TARGET)
1045       {
1046 			//----------- defense units allow to attack units and firms -----------//
1047          err_when(!in_auto_defense_mode());
1048 
1049          if(idle_detect_has_unit)
1050             defense_attack_unit(idle_detect_target_unit_recno);
1051          else if(idle_detect_has_firm)
1052 			{
1053 				Firm *targetFirmPtr = firm_array[idle_detect_target_firm_recno];
1054             defense_attack_firm(targetFirmPtr->loc_x1, targetFirmPtr->loc_y1);
1055 			}
1056          /*else if(idle_detect_has_town)
1057 			{
1058 				TownPtr *targetTownPtr = town_array[idle_detect_target_town_recno];
1059             defense_attack_town(targetTownPtr->loc_x1, targetTownPtr->loc_y1);
1060 			}
1061          else if(idle_detect_has_wall)
1062 				defense_attack_wall(idle_detect_target_wall_x1, idle_detect_target_wall_y1);*/
1063          else
1064             return 0;
1065 
1066          return 1;
1067       }
1068       else if(action_mode2==ACTION_DEFEND_TOWN_DETECT_TARGET)
1069       {
1070 			//----------- town units only attack units ------------//
1071          err_when(!in_defend_town_mode());
1072 
1073          if(idle_detect_has_unit)
1074             defend_town_attack_unit(idle_detect_target_unit_recno);
1075          else
1076             return 0;
1077 
1078          return 1;
1079       }
1080       else if(action_mode2==ACTION_MONSTER_DEFEND_DETECT_TARGET)
1081       {
1082 			//---------- monsters can attack units and firms -----------//
1083 			err_when(!in_monster_defend_mode());
1084 
1085          if(idle_detect_has_unit)
1086             monster_defend_attack_unit(idle_detect_target_unit_recno);
1087          else if(idle_detect_has_firm)
1088 			{
1089 				Firm *targetFirmPtr = firm_array[idle_detect_target_firm_recno];
1090             monster_defend_attack_firm(targetFirmPtr->loc_x1, targetFirmPtr->loc_y1);
1091 			}
1092          /*else if(idle_detect_has_town)
1093 			{
1094 				Town *targetTownPtr = town_array[idle_detect_target_town_recno];
1095             monster_defend_attack_town(targetTownPtr->loc_x1, targetTownPtr->loc_y1);
1096 			}
1097          else if(idle_detect_has_wall)
1098             monster_defend_attack_wall(idle_detect_target_wall_x1, idle_detect_target_wall_y1);*/
1099          else
1100             return 0;
1101 
1102 			return 1;
1103 		}
1104 		else
1105 			err_here();
1106 	}
1107 	else // default mode
1108 	{
1109 		//#### begin trevor 9/10 ####//
1110 
1111 		int rc = 0;
1112 
1113 		if(idle_detect_has_unit)
1114 		{
1115 			attack_unit(idle_detect_target_unit_recno);
1116 
1117 			//--- set the original position of the target, so the unit won't chase too far away ---//
1118 
1119 			Unit* unitPtr = unit_array[idle_detect_target_unit_recno];
1120 
1121 			original_target_x_loc = unitPtr->next_x_loc();
1122 			original_target_y_loc = unitPtr->next_y_loc();
1123 
1124 			rc = 1;
1125 		}
1126 
1127 		else if(help_mode==HELP_ATTACK_UNIT)
1128 		{
1129 			attack_unit(help_attack_target_recno);
1130 
1131 			//--- set the original position of the target, so the unit won't chase too far away ---//
1132 
1133 			Unit* unitPtr = unit_array[help_attack_target_recno];
1134 
1135 			original_target_x_loc = unitPtr->next_x_loc();
1136 			original_target_y_loc = unitPtr->next_y_loc();
1137 
1138 			rc = 1;
1139 		}
1140 		else if(idle_detect_has_firm)
1141 		{
1142 			Firm *targetFirmPtr = firm_array[idle_detect_target_firm_recno];
1143 			attack_firm(targetFirmPtr->loc_x1, targetFirmPtr->loc_y1);
1144 		}
1145 		/*else if(idle_detect_has_town)
1146 		{
1147 			Town *targetTownPtr = town_array[idle_detect_target_town_recno];
1148 			attack_town(targetTownPtr->loc_x1, targetTownPtr->loc_y1);
1149 		}
1150 		else if(idle_detect_has_wall)
1151 			attack_wall(idle_detect_target_wall_x1, idle_detect_target_wall_y1);*/
1152 		else
1153 			return 0;
1154 
1155 		//---- set original action vars ----//
1156 
1157 		if( rc && original_action_mode==0 )
1158 		{
1159 			original_action_mode  = ACTION_MOVE;
1160 			original_action_para  = 0;
1161 			original_action_x_loc = next_x_loc();
1162 			original_action_y_loc = next_y_loc();
1163 		}
1164 
1165 		return 1;
1166 
1167 		//#### end trevor 9/10 ####//
1168 	}
1169 
1170 	return 0;
1171 }
1172 //----------- End of function Unit::idle_detect_choose_target -----------//
1173 
1174 
1175 //--------- Begin of function Unit::idle_detect_helper_attack --------//
1176 // check the action_mode of the unit being checked, which has same nation
1177 // recno as this unit. If the unit attacks other unit, this unit help to
1178 // attack the same target.
1179 //
1180 // <short>	unitRecno	-	recno of the unit of nation recno same as this unit
1181 //
idle_detect_helper_attack(short unitRecno)1182 void Unit::idle_detect_helper_attack(short unitRecno)
1183 {
1184 	#define HELP_DISTANCE	15
1185 
1186    Unit *unitPtr = unit_array[unitRecno];
1187    if(unitPtr->unit_id == UNIT_CARAVAN)
1188       return;
1189 
1190 	//char	actionMode;
1191 	short	actionPara;
1192 	//short actionXLoc, actionYLoc;
1193 	char	isUnit = 0;
1194 
1195 	//------------- is the unit attacking other unit ------------//
1196 	switch(unitPtr->action_mode2)
1197 	{
1198 		case ACTION_ATTACK_UNIT:
1199 				actionPara = unitPtr->action_para2;
1200 				isUnit++;
1201 				break;
1202 
1203 		default:
1204 				switch(unitPtr->action_mode)
1205 				{
1206 					case ACTION_ATTACK_UNIT:
1207 							actionPara = unitPtr->action_para;
1208 							isUnit++;
1209 							break;
1210 				}
1211 	}
1212 
1213 	if(isUnit && !unit_array.is_deleted(actionPara))
1214 	{
1215 		Unit *targetUnit = unit_array[actionPara];
1216 
1217 		if(targetUnit->nation_recno==nation_recno)
1218 			return;
1219 
1220 		// the targetUnit this unitPtr is attacking may have entered a
1221 		// building by now due to processing order -- skip this one
1222 		if(!targetUnit->is_visible())
1223 			return;
1224 
1225 		if(misc.points_distance(next_x_loc(), next_y_loc(), targetUnit->next_x_loc(), targetUnit->next_y_loc())<HELP_DISTANCE)
1226 		{
1227 			if(idle_detect_unit_checking(actionPara))
1228 			{
1229 				help_attack_target_recno = actionPara;
1230 				help_mode = HELP_ATTACK_UNIT;
1231 			}
1232 
1233 			memset(blocked_edge, 0, sizeof(blocked_edge));
1234 		}
1235 	}
1236 }
1237 //----------- End of function Unit::idle_detect_helper_attack -----------//
1238