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    : OUNITM.CPP
22 //Description : Object Unit movement
23 //Owner		  : Alex
24 
25 #include <ALL.h>
26 #include <OWORLD.h>
27 #include <OF_HARB.h>
28 #include <OGAME.h>
29 #include <ONATION.h>
30 #include <OU_MARI.h>
31 #include <OSPATH.h>
32 #include <OSPREUSE.h>
33 #include <OSERES.h>
34 #include <OLOG.h>
35 #include <OEFFECT.h>
36 
37 #ifdef NO_DEBUG_UNIT
38 #undef err_when
39 #undef err_here
40 #undef err_if
41 #undef err_else
42 #undef err_now
43 #define err_when(cond)
44 #define err_here()
45 #define err_if(cond)
46 #define err_else
47 #define err_now(msg)
48 #undef DEBUG
49 #endif
50 
51 //-*********** simulate aat ************-//
52 #ifdef DEBUG
53 #include <OSYS.h>
54 #endif
55 //-*********** simulate aat ************-//
56 
57 //--- Define no. of pixels per direction move (N, NE, E, SE, S, SW, W, NW) ---//
58 
59 static short move_x_pixel_array[] = { 0, ZOOM_LOC_WIDTH, ZOOM_LOC_WIDTH, ZOOM_LOC_WIDTH, 0, -ZOOM_LOC_WIDTH, -ZOOM_LOC_WIDTH, -ZOOM_LOC_WIDTH };
60 static short move_y_pixel_array[] = { -ZOOM_LOC_HEIGHT, -ZOOM_LOC_HEIGHT, 0, ZOOM_LOC_HEIGHT, ZOOM_LOC_HEIGHT, ZOOM_LOC_HEIGHT, 0, -ZOOM_LOC_HEIGHT };
61 
62 static short cycle_wait_unit_index;
63 static short *cycle_wait_unit_array;
64 static short cycle_wait_unit_array_def_size;
65 static short cycle_wait_unit_array_multipler;
66 
67 
68 static char	 move_action_call_flag=0; // avoid calling move_to_my_loc() if this function is called from move_to() chain
69 
70 
71 //--------- Begin of function Unit::reset_action_para ---------//
72 // reset action parameters when action is finished or cancelled
73 // for action_mode
74 //
reset_action_para()75 void Unit::reset_action_para()
76 {
77 	action_mode	= ACTION_STOP;
78 	action_x_loc = action_y_loc = -1;
79 	action_para = 0;
80 }
81 //----------- End of function Unit::reset_action_para -----------//
82 
83 
84 //--------- Begin of function Unit::reset_action_para2 ---------//
85 // reset action parameters when action is finished or cancelled
86 //
87 // <int>	keepMode	-	use to keep action
88 //
reset_action_para2(int keepMode)89 void Unit::reset_action_para2(int keepMode)
90 {
91 	if(keepMode!=KEEP_DEFENSE_MODE || !in_any_defense_mode())
92 	{
93 		action_mode2 = ACTION_STOP;
94 		action_para2 = 0;
95 		action_x_loc2 = action_y_loc2 = -1;
96 	}
97 	else
98 	{
99 		switch(unit_mode)
100 		{
101 			case UNIT_MODE_DEFEND_TOWN:
102 					if(action_mode2!=ACTION_AUTO_DEFENSE_DETECT_TARGET)
103 						defend_town_detect_target();
104 					break;
105 
106 			case UNIT_MODE_REBEL:
107 					if(action_mode2!=ACTION_DEFEND_TOWN_DETECT_TARGET)
108 						defense_detect_target();
109 					break;
110 
111 			case UNIT_MODE_MONSTER:
112 					if(action_mode2!=ACTION_MONSTER_DEFEND_DETECT_TARGET)
113 						monster_defend_detect_target();
114 					break;
115 		}
116 	}
117 }
118 //----------- End of function Unit::reset_action_para2 -----------//
119 
120 
121 //--------- Begin of function Unit::reset_action_misc_para ---------//
122 // reset miscellaneous action parameters
123 //
reset_action_misc_para()124 void Unit::reset_action_misc_para()
125 {
126 	action_misc = ACTION_MISC_STOP;
127 	action_misc_para = 0;
128 }
129 //----------- End of function Unit::reset_action_misc_para -----------//
130 
131 
132 //--------- Begin of function Unit::stop ---------//
133 // stop unit action
134 //
135 // [int] preserveAction - preserve the current action or not.
136 //                        (default: 0)
137 //
stop(int preserveAction)138 void Unit::stop(int preserveAction)
139 {
140 	//------------- reset vars ------------//
141 	if(action_mode2!=ACTION_MOVE)
142 		reset_way_point_array();
143 
144    reset_path();
145 	err_when(result_node_array!=NULL);
146 
147 	//-------------- keep action or not --------------//
148 	switch(preserveAction)
149 	{
150 		case 0: case KEEP_DEFENSE_MODE:
151 					reset_action_para();
152 					range_attack_x_loc = range_attack_y_loc = -1; // should set here or reset for attack
153 					break;
154 
155 		case KEEP_PRESERVE_ACTION:
156 					break;
157 
158 		/*case 3:	err_when(action_mode!=ACTION_ATTACK_UNIT);
159 					go_x = next_x;	// combine move_to_attack() into move_to()
160 					go_y = next_y;
161 					move_to_x_loc = next_x_loc();
162 					move_to_y_loc = next_y_loc();
163 					return;*/
164 	}
165 
166 	waiting_term = 0; // for idle_detect_attack(), oscillate between 0 and 1
167 	err_when(cur_dir<0 || cur_dir>MAX_SPRITE_DIR_TYPE);
168 	err_when(final_dir<0 || final_dir>MAX_SPRITE_DIR_TYPE);
169 	UnitMarine *shipPtr;
170 
171 	//----------------- update parameters ----------------//
172 	switch( cur_action )
173    {
174       //----- if the unit is moving right now, ask it to stop as soon as possible -----//
175 
176 		case SPRITE_READY_TO_MOVE:
177 			set_idle();
178 			break;
179 
180 		case SPRITE_TURN:
181 		case SPRITE_WAIT:
182 			go_x = next_x;
183 			go_y = next_y;
184 			move_to_x_loc = next_x_loc();
185 			move_to_y_loc = next_y_loc();
186 			final_dir = cur_dir;
187 			turn_delay = 0;
188 			set_idle();
189 			break;
190 
191 		case SPRITE_SHIP_EXTRA_MOVE:
192 			shipPtr = (UnitMarine*) this;
193 			switch(shipPtr->extra_move_in_beach)
194 			{
195 				case NO_EXTRA_MOVE:
196 						if(cur_x==next_x && cur_y==next_y)
197 						{
198 							go_x = next_x;
199 							go_y = next_y;
200 							move_to_x_loc = next_x_loc();
201 							move_to_y_loc = next_y_loc();
202 							set_idle();
203 							return;
204 						}
205 						break;
206 
207 				case EXTRA_MOVING_IN:
208 						if(cur_x==next_x && cur_y==next_y && (cur_x!=go_x || cur_y!=go_y))
209 						{
210 							shipPtr->extra_move_in_beach = NO_EXTRA_MOVE; // not yet move although location is chosed
211 							err_when(next_x_loc()%2 || next_y_loc()%2); // in even location
212 						}
213 						else
214 							err_when(next_x_loc()%2==0 && next_y_loc()%2==0); // in even location
215 						break;
216 
217 				case EXTRA_MOVING_OUT:
218 						if(cur_x==next_x && cur_y==next_y && (cur_x!=go_x || cur_y!=go_y))
219 						{
220 							shipPtr->extra_move_in_beach = EXTRA_MOVE_FINISH; // not yet move although location is chosed
221 							err_when(next_x_loc()%2==0 && next_y_loc()%2==0); // not in even location
222 						}
223 						else
224 							err_when(next_x_loc()%2 || next_y_loc()%2); // in even location
225 						break;
226 
227 
228 				case EXTRA_MOVE_FINISH:
229 						break;
230 			}
231 
232 			go_x = next_x;
233          go_y = next_y;
234 			move_to_x_loc = next_x_loc();
235 			move_to_y_loc = next_y_loc();
236 			break;
237 
238       case SPRITE_MOVE:
239 			go_x = next_x;
240          go_y = next_y;
241 			move_to_x_loc = next_x_loc();
242 			move_to_y_loc = next_y_loc();
243 			if(cur_x==next_x && cur_y==next_y)
244 				set_idle();
245          break;
246 
247       //--- if its current action is SPRITE_ATTACK, stop immediately ---//
248 
249       case SPRITE_ATTACK:
250 			set_next(cur_x, cur_y, 0, 1);		//********** BUGHERE
251 			go_x = next_x;
252 			go_y = next_y;
253 			move_to_x_loc = next_x_loc();
254 			move_to_y_loc = next_y_loc();
255 			set_idle();
256 
257 			#ifdef DEBUG
258 				char h, w, blocked=0;
259 				short x, y;
260 
261 				for(h=0, y=next_y_loc(); h<sprite_info->loc_height&&!blocked; h++, y++)
262 				{
263 					for(w=0, x=next_x_loc(); w<sprite_info->loc_width&&!blocked; w++, x++)
264 						err_when(world.get_unit_recno(x, y, mobile_type) != sprite_recno);
265 				}
266 			#endif
267 			cur_frame  = 1;
268 			break;
269    }
270 }
271 //----------- End of function Unit::stop -----------//
272 
273 
274 //--------- Begin of function Unit::stop2 ---------//
275 // stop unit action
276 //
277 // preserverAction can be
278 // 0, KEEP_PRESERVE_ACTION, KEEP_DEFENSE_MODE (default 0)
279 //
stop2(int preserveAction)280 void Unit::stop2(int preserveAction)
281 {
282 	stop(preserveAction);
283 	reset_action_para2(preserveAction);
284 
285 	//----------------------------------------------------------//
286 	// set the original location of the attacking target when
287 	// the attack() function is called, action_x_loc2 & action_y_loc2
288 	// will change when the unit move, but these two will not.
289 	//----------------------------------------------------------//
290 
291    //##### begin trevor 13/10 #####//
292 
293 	force_move_flag = 0;
294 	ai_no_suitable_action = 0;
295 
296 	if( preserveAction==0 )
297 	{
298 		original_action_mode = 0;
299 		ai_original_target_x_loc = -1;
300 
301 		if( ai_action_id )
302 			nation_array[nation_recno]->action_failure(ai_action_id, sprite_recno);
303 	}
304 
305 	//##### end trevor 13/10 #####//
306 }
307 //----------- End of function Unit::stop2 -----------//
308 
309 //######## begin trevor 26/4 ###########//
310 
311 //--------- Begin of function Unit::set_search_tries ---------//
312 // used to limit the number of nodes in searching
313 //
314 // <int> tries	-	number of nodes used in searhcing
315 //
set_search_tries(int tries)316 void Unit::set_search_tries(int tries)
317 {
318 	unit_search_tries = tries;
319 	unit_search_tries_flag++;
320 }
321 //----------- End of function Unit::set_search_tries -----------//
322 
323 
324 //--------- Begin of function Unit::reset_search_tries ---------//
325 // reset the number of node to default value
326 //
reset_search_tries()327 void Unit::reset_search_tries()
328 {
329 	unit_search_tries = 0;		// 0 for reset
330 	unit_search_tries_flag = 0;
331 }
332 //----------- End of function Unit::reset_search_tries -----------//
333 
334 //######## end trevor 26/4 ###########//
335 
336 //-------- Begin of function Unit::abort_searching --------//
337 //
338 // <int> reuseSetNext	-	condition flag for updating parameters
339 //									of path_reuse
340 //
abort_searching(int reuseSetNext)341 void	Unit::abort_searching(int reuseSetNext)
342 {
343 	if(reuseSetNext)	// to avoid error in path-reuse
344 		seek_path_reuse.set_next_cur_path_num();
345 
346 	if(unit_search_tries_flag)
347 		reset_search_tries();
348 }
349 //-------- End of function Unit::abort_searching ---------//
350 
351 
352 //--------- Begin of function Unit::enable_force_move ---------//
enable_force_move()353 void Unit::enable_force_move()
354 {
355 	force_move_flag = 1;
356 }
357 //-------- End of function Unit::enable_force_move ---------//
358 
359 
360 //--------- Begin of function Unit::disable_force_move ---------//
disable_force_move()361 void Unit::disable_force_move()
362 {
363 	force_move_flag = 0;
364 }
365 //-------- End of function Unit::disable_force_move ---------//
366 
367 
368 //--------- Begin of function Unit::move_to ---------//
369 // Main function for action_mode = ACTION_MOVE
370 //
371 // Order the unit to move to a specific location following the shortest path.
372 //
373 // <int>		destX					-	x location of the destination
374 // <int>		destY					-	y location of the destination
375 // [int]		preserveAction		-	preserve the current action or not (default: 0)
376 // [short]	searchMode			-	the search mode used (default: SEARCH_MODE_IN_A_GROUP)
377 // [short]	miscNo				-	= target record no if search_mode=SEARCH_MODE_TO_ATTACK
378 //											= firm ID if search_mode=SEARCH_MODE_TO_FIRM (default: 0)
379 //	[short]	numOfPath			-	num of path, used in path reuse, (default: 1)
380 //	[short]	reuseMode			-	path reuse mode (default: GENERAL_GROUP_MOVEMENT)
381 //	[short]	pathReuseStatus	-	path reuse status (default: 0)
382 //
move_to(int destX,int destY,int preserveAction,short searchMode,short miscNo,short numOfPath,short reuseMode,short pathReuseStatus)383 void Unit::move_to(int destX, int destY, int preserveAction, short searchMode, short miscNo, short numOfPath, short reuseMode, short pathReuseStatus)
384 {
385 	err_when(destX<0 || destX>=MAX_WORLD_X_LOC || destY<0 || destY>=MAX_WORLD_Y_LOC);
386 
387 	if(!seek_path.total_node_avail)
388 	{
389 		//-------- insufficient nodes for searching, return now ----------//
390 		stop(KEEP_PRESERVE_ACTION);
391 		action_mode = action_mode2 = ACTION_MOVE;
392 		action_para = action_para2 = 0;
393 		action_x_loc = action_x_loc2 = destX;
394 		action_y_loc = action_y_loc2 = destY;
395 		return; // for later searching
396 	}
397 
398 	//int useClosestNode = (seek_path.total_node_avail>=MIN_BACKGROUND_NODE_USED_UP);
399 
400 	//---------- reset way point array since new action is assigned --------//
401 	if(way_point_count)
402 	{
403 		ResultNode *nodePtr = way_point_array;
404 		if(nodePtr->node_x!=destX || nodePtr->node_y!=destY)
405 			reset_way_point_array();
406 	}
407 
408 	//----------------------------------------------------------------//
409 	// calculate new destination if trying to move to different territory
410 	//----------------------------------------------------------------//
411 	int curXLoc = next_x_loc();
412 	int curYLoc = next_y_loc();
413 	Location *locPtr = world.get_loc(curXLoc, curYLoc);
414 	Location *destLocPtr = world.get_loc(destX, destY);
415 	int destXLoc = destX;
416 	int destYLoc = destY;
417 
418 	if(locPtr->region_id!=destLocPtr->region_id && mobile_type!=UNIT_AIR) // different territory
419 		different_territory_destination(destXLoc, destYLoc);
420 
421 	//----------------------------------------------------------------//
422 	// for path_reuse initialization
423 	//----------------------------------------------------------------//
424 	if(numOfPath!=1 && pathReuseStatus==REUSE_PATH_INITIAL)	// for path-reuse only
425 	{
426 		search(destXLoc, destYLoc, preserveAction, searchMode, miscNo, numOfPath, reuseMode, pathReuseStatus);
427 		return;
428 	}
429 
430 	//----------------------------------------------------------------//
431 	// return if the unit is dead
432 	//----------------------------------------------------------------//
433 	if(is_unit_dead())
434 	{
435 		abort_searching(searchMode==SEARCH_MODE_REUSE && numOfPath>1);
436 		return;
437 	}
438 
439 	//-----------------------------------------------------------------------------------//
440 	// The codes here is used to check for equal action in movement.
441 	//
442 	// mainly checked by action_mode2. If previous action is ACTION_MOVE, action_mode2,
443 	// action_para2, action_x_loc2 and action_x_loc2 need to be kept for this checking.
444 	//
445 	// If calling from unit_array.move_to(), action_mode is set to ACTION_MOVE, action_para
446 	// is set to 0 while action_x_loc and action_y_loc are kept as original value for checking.
447 	// Meanwhile, action_mode2, action_para2, action_x_loc2 and action_y_loc2 are kept if
448 	// the condition is fulfilled (action_mode2==ACTION_MOVE)
449 	//-----------------------------------------------------------------------------------//
450 	if(action_mode2==ACTION_MOVE && action_mode==ACTION_MOVE)
451 	{
452 		//------ previous action is ACTION_MOVE -------//
453 		err_when(action_para2 || action_para);
454 		if(action_x_loc2==destXLoc && action_y_loc2==destYLoc)
455 		{
456 			//-------- equal order --------//
457 			action_x_loc = action_x_loc2;
458 			action_y_loc = action_y_loc2;
459 
460 			if(cur_action!=SPRITE_IDLE)
461 			{
462 				//-------- the old order is processing --------//
463 				abort_searching(searchMode==SEARCH_MODE_REUSE && numOfPath>1);
464 
465 				if(result_node_array==NULL) // cannot move
466 				{
467 					err_when(result_path_dist);
468 					if(unit_res[unit_id]->unit_class==UNIT_CLASS_SHIP)
469 					{
470 						if(cur_action!=SPRITE_SHIP_EXTRA_MOVE)
471 						{
472 							err_when(result_node_count || result_node_recno);
473 							if(cur_x!=next_x || cur_y!=next_y)
474 								set_move();
475 							else
476 								set_idle();
477 						}
478 						//else keep extra_moving
479 					}
480 					else
481 					{
482 						err_when(result_node_count || result_node_recno);
483 						if(cur_x!=next_x || cur_y!=next_y)
484 							set_move();
485 						else
486 							set_idle();
487 					}
488 				}
489 
490 				err_when(action_mode==ACTION_MOVE && (action_x_loc==-1 || action_y_loc==-1));
491 				return;
492 			}//else action is hold due to some problems, re-activiate again
493 		}
494 	}//else, new order or searching is required
495 
496 	move_action_call_flag++; // set flag to avoid calling move_to_my_loc()
497 	seek_path_reuse.set_status(PATH_WAIT);
498 	err_when(seek_path_reuse.get_reuse_path_status()==REUSE_PATH_INCOMPLETE_SEARCH);
499 
500 	action_mode2 = ACTION_MOVE;
501 	action_para2 = 0;
502 
503 	int enoughNode = search(destXLoc, destYLoc, preserveAction, searchMode, miscNo, numOfPath, reuseMode, pathReuseStatus);
504 	move_action_call_flag = 0; // clear the flag
505 
506 	//----------------------------------------------------------------//
507 	// store new order in action parameters
508 	//----------------------------------------------------------------//
509 	action_mode = ACTION_MOVE;
510 	action_para = 0;
511 
512 	if(!enoughNode || (searchMode==SEARCH_MODE_REUSE && seek_path_reuse.get_reuse_path_status()==REUSE_PATH_INCOMPLETE_SEARCH))
513 	{
514 		action_x_loc = action_x_loc2 = destXLoc;
515 		action_y_loc = action_y_loc2 = destYLoc;
516 	}
517 	else // enough node for search
518 	{
519 		action_x_loc = action_x_loc2 = move_to_x_loc;
520 		action_y_loc = action_y_loc2 = move_to_y_loc;
521 	}
522 
523 	#ifdef DEBUG
524 		if(result_node_array && result_node_count)
525 		{
526 			ResultNode *debugPtr = result_node_array + result_node_count - 1;
527 			err_when(debugPtr->node_x != move_to_x_loc || debugPtr->node_y != move_to_y_loc);
528 		}
529 		else
530 		{
531 			UnitInfo* unitInfo = unit_res[unit_id];
532 
533 			if( unitInfo->unit_class == UNIT_CLASS_SHIP )
534 			{
535 				UnitMarine *shipPtr = (UnitMarine*) this;
536 				if(shipPtr->extra_move_in_beach==NO_EXTRA_MOVE)
537 					err_when(curXLoc!=move_to_x_loc || curYLoc!=move_to_y_loc);
538 			}
539 			else
540 			{
541 				err_when(curXLoc!=move_to_x_loc || curYLoc!=move_to_y_loc);
542 			}
543 		}
544 	#endif
545 	err_when(action_mode==ACTION_MOVE && (action_x_loc==-1 || action_y_loc==-1));
546 	err_when(move_to_x_loc<0 || move_to_x_loc>=MAX_WORLD_X_LOC || move_to_y_loc<0 || move_to_y_loc>=MAX_WORLD_Y_LOC);
547 	err_when(cur_action==SPRITE_IDLE && (move_to_x_loc!=next_x_loc() || move_to_y_loc!=next_y_loc()));
548 	err_when(cur_action==SPRITE_IDLE && (cur_x!=next_x || cur_y!=next_y));
549 	err_when(action_mode2==ACTION_MOVE && (action_x_loc2==-1 || action_y_loc2==-1));
550 }
551 //----------- End of function Unit::move_to -----------//
552 
553 
554 //--------- Begin of function Unit::search ---------//
555 // This function is only used to find the shorest path for
556 // searching.  Action parameters should not be changed in
557 // this function.
558 //
559 //	<int>		destX					-	x coordinate of destination
560 //	<int>		destY					-	y coordinate of destination
561 //	<int>		preserveAction		-	used to keep action in calling stop()
562 //	<short>	searchMode			-	search mode being used
563 //	<short>	miscNo				-	see move_to()
564 // <short>	numOfPath			-	num of path
565 //	<short>	reuseMode			-	path reuse mode being used
566 //	<short>	pathReuseStatus	-	path reuse status
567 //
568 // return 1 for normal operation process
569 // return 0 otherwise or  there is not enough node for searching
570 //
search(int destXLoc,int destYLoc,int preserveAction,short searchMode,short miscNo,short numOfPath,short reuseMode,short pathReuseStatus)571 int Unit::search(int destXLoc, int destYLoc, int preserveAction, short searchMode, short miscNo, short numOfPath, short reuseMode, short pathReuseStatus)
572 {
573 	#ifdef DEBUG
574 		err_when(destXLoc<0 || destXLoc>=MAX_WORLD_X_LOC || destYLoc<0 || destYLoc>=MAX_WORLD_Y_LOC);
575 		err_when(searchMode==SEARCH_MODE_TO_FIRM && miscNo!=FIRM_HARBOR && mobile_type!=UNIT_AIR &&
576 					world.get_loc(next_x_loc(), next_y_loc())->region_id!=world.get_loc(destXLoc, destYLoc)->region_id);
577 		err_when(hit_points<=0 || action_mode==ACTION_DIE || cur_action==SPRITE_DIE);
578 	#else
579 		if(destXLoc<0 || destXLoc>=MAX_WORLD_X_LOC || destYLoc<0 || destYLoc>=MAX_WORLD_Y_LOC || hit_points<=0 ||
580 			action_mode==ACTION_DIE || cur_action==SPRITE_DIE || searchMode<=0 || searchMode>MAX_SEARCH_MODE_TYPE)
581 		{
582 			stop2(KEEP_DEFENSE_MODE); //-********** BUGHERE, err_handling for retailed version
583 			return 1;
584 		}
585 	#endif
586 
587 	//----------------------------------------------------------------//
588 	// for path_reuse initialization
589 	//----------------------------------------------------------------//
590 	if(numOfPath!=1 && pathReuseStatus==REUSE_PATH_INITIAL)	// for path-reuse only
591 	{
592 		seek_path_reuse.seek(next_x_loc(), next_y_loc(), move_to_x_loc, move_to_y_loc, sprite_info->loc_width,
593 									unit_group_id, mobile_type, searchMode, miscNo, numOfPath, reuseMode, pathReuseStatus);
594 		return 1;
595 	}
596 
597 	int result=0;
598 	if(unit_res[unit_id]->unit_class==UNIT_CLASS_SHIP)
599 	{
600 		UnitMarine *shipPtr = (UnitMarine*) this;
601 		switch(shipPtr->extra_move_in_beach)
602 		{
603 			case NO_EXTRA_MOVE:
604 					result = searching(destXLoc, destYLoc, preserveAction, searchMode, miscNo, numOfPath, reuseMode, pathReuseStatus);
605 					break;
606 
607 			case EXTRA_MOVING_IN:
608 					err_when(next_x_loc()%2==0 && next_y_loc()%2==0);
609 					if(pathReuseStatus==REUSE_PATH_SEARCH || pathReuseStatus==REUSE_PATH_FIRST_SEEK)
610 						seek_path_reuse.set_next_cur_path_num();
611 					return 0;
612 
613 			case EXTRA_MOVING_OUT:
614 					err_when(next_x_loc()%2 || next_y_loc()%2);
615 					if(pathReuseStatus==REUSE_PATH_SEARCH || pathReuseStatus==REUSE_PATH_FIRST_SEEK)
616 						seek_path_reuse.set_next_cur_path_num();
617 					return 0;
618 
619 			case EXTRA_MOVE_FINISH:
620 					err_when(next_x_loc()%2==0 && next_y_loc()%2==0);
621 					if(pathReuseStatus==REUSE_PATH_SEARCH || pathReuseStatus==REUSE_PATH_FIRST_SEEK)
622 						seek_path_reuse.set_next_cur_path_num();
623 
624 					ship_leave_beach(next_x_loc(), next_y_loc());
625 					break;
626 
627 			default: err_here();
628 						break;
629 		}
630 	}
631 	else
632 		result = searching(destXLoc, destYLoc, preserveAction, searchMode, miscNo, numOfPath, reuseMode, pathReuseStatus);
633 
634 	if(way_point_count && !result_node_array) // can move no more
635 		reset_way_point_array();
636 
637 	if(!result)
638 		return 0; // not enough node or extra_move_in_beach!=NO_EXTRA_MOVE
639 	else
640 		return 1;
641 }
642 //----------- End of function Unit::search -----------//
643 
644 
645 //--------- Begin of function Unit::select_search_sub_mode ---------//
646 // select searching sub_mode
647 //
648 //	<int>		sx				-	start location x
649 //	<int>		sy				-	start location y
650 // <int>		dx				-	x coordinate of destination
651 //	<int>		dy				-	y coordinate of destination
652 //	<short>	nationRecno	-	nation recno of the unit
653 //	<short>	searchMode	-	search mode being used
654 //
select_search_sub_mode(int sx,int sy,int dx,int dy,short nationRecno,short searchMode)655 void Unit::select_search_sub_mode(int sx, int sy, int dx, int dy, short nationRecno, short searchMode)
656 {
657 	//seek_path.set_sub_mode(); // cancel the selection
658 	//return;
659 
660 	err_when(mobile_type!=UNIT_LAND);
661 
662 	if(!nation_recno || ignore_power_nation)
663 	{
664 		seek_path.set_sub_mode(); // always using normal mode for independent unit
665 		seek_path_reuse.set_sub_mode();
666 		return;
667 	}
668 
669 	//--------------------------------------------------------------------------------//
670 	// Checking for starting location and destination to determine sub_mode used
671 	// N - not hostile, H - hostile
672 	// 1) N -> N, using normal mode
673 	// 2) N -> H, H -> N, H -> H, using sub_mode SEARCH_SUB_MODE_PASSABLE
674 	//--------------------------------------------------------------------------------//
675 	Location *startLocPtr = world.get_loc(sx, sy);
676 	Location *destLocPtr = world.get_loc(dx, dy);
677 	Nation *nationPtr = nation_array[nationRecno];
678 	int subModeOn = 1;
679 
680 	if((startLocPtr->power_nation_recno && !nationPtr->get_relation_passable(startLocPtr->power_nation_recno)) ||
681 		(destLocPtr->power_nation_recno && !nationPtr->get_relation_passable(destLocPtr->power_nation_recno)))
682 		subModeOn = 0;
683 
684 	if(subModeOn) // true only when both start and end locations are passable for this nation
685 	{
686 		seek_path.set_nation_passable(nationPtr->relation_passable_array);
687 		seek_path.set_sub_mode(SEARCH_SUB_MODE_PASSABLE);
688 	}
689 	else
690 		seek_path.set_sub_mode(); //----- normal sub mode, normal searching
691 
692 	//----------- set sub_mode of path-reuse if more than one unit are selected -----------//
693 	if(subModeOn && searchMode==SEARCH_MODE_REUSE)
694 	{
695 		seek_path_reuse.set_nation_passable(nationPtr->relation_passable_array);
696 		seek_path_reuse.set_sub_mode(SEARCH_SUB_MODE_PASSABLE);
697 	}
698 	else
699 		seek_path_reuse.set_sub_mode();
700 }
701 //----------- End of function Unit::select_search_sub_mode -----------//
702 
703 
704 //--------- Begin of function Unit::searching ---------//
searching(int destXLoc,int destYLoc,int preserveAction,short searchMode,short miscNo,short numOfPath,short reuseMode,short pathReuseStatus)705 int Unit::searching(int destXLoc, int destYLoc, int preserveAction, short searchMode, short miscNo, short numOfPath, short reuseMode, short pathReuseStatus)
706 {
707 	stop(preserveAction); // stop the unit as soon as possible
708 
709 	int startXLocLoc=next_x_loc();   // next location the sprite is moving towards
710 	int startYLocLoc=next_y_loc();
711 	int totalAvailableNode = seek_path.total_node_avail;
712 
713 	if(!avail_node_enough_for_search(startXLocLoc, startYLocLoc, destXLoc, destYLoc))
714 	{
715 		abort_searching(searchMode==4 && numOfPath>1);
716 		return 0; // not enough node for searching
717 	}
718 
719 	//stop(preserveAction); // stop the unit as soon as possible
720 
721 	//---------------------------------------------------------------------------//
722 	// adjust the destination for unit size
723 	//---------------------------------------------------------------------------//
724 	/*err_when(sprite_info->loc_width!=sprite_info->loc_height);
725 	if(sprite_info->loc_width>1) // not size 1x1
726 	{
727 		destXLoc = move_to_x_loc = MIN(destXLoc, MAX_WORLD_X_LOC-sprite_info->loc_width);
728 		destYLoc = move_to_y_loc = MIN(destYLoc, MAX_WORLD_Y_LOC-sprite_info->loc_height);
729 	}
730 	else
731 	{*/
732 		move_to_x_loc = destXLoc;
733 		move_to_y_loc = destYLoc;
734 	//}
735 
736 	//------------------------------------------------------------//
737 	// fast checking for destination == current location
738 	//------------------------------------------------------------//
739 	//if(startXLocLoc==move_to_x_loc && startYLocLoc==move_to_y_loc) // already here
740 	if(startXLocLoc==destXLoc && startYLocLoc==destYLoc) // already here
741 	{
742 		if(cur_x!=next_x || cur_y!=next_y)
743 			set_move();
744 		else
745 			set_idle();
746 
747 		err_when(move_to_x_loc!=startXLocLoc || move_to_y_loc!=startYLocLoc);
748 		err_when(result_node_array!=NULL);
749 
750 		abort_searching(searchMode==SEARCH_MODE_REUSE && numOfPath>1);
751 		return 1;
752 	}
753 
754 	//------------------------ find the shortest path --------------------------//
755 	//
756 	// Note: seek() will never return PATH_SEEKING as the maxTries==max_node in
757 	//       calling seek()
758 	//
759 	// decide the searching to use according to the unit size
760 	// assume the unit size is always 1x1, 2x2, 3x3 and so on
761 	// i.e. sprite_info->loc_width == sprite_info->loc_height
762 	//--------------------------------------------------------------------------//
763 
764 	result_node_recno = result_node_count = 0;
765 	err_when(result_node_array!=NULL);
766 
767 	seek_path.set_nation_recno(nation_recno);
768 
769 	int seekResult;
770 	#ifdef DEBUG
771 		unsigned long seekPathStartTime = misc.get_time();
772 	#endif
773 	/*switch(sprite_info->loc_width)
774 	{
775 		case 1:*/
776 					if(searchMode!=SEARCH_MODE_REUSE || numOfPath==1)	// no need to call path_reuse
777 					{
778 						if(mobile_type==UNIT_LAND)
779 							select_search_sub_mode(startXLocLoc, startYLocLoc, destXLoc, destYLoc, nation_recno, searchMode);
780 						seekResult = seek_path.seek(startXLocLoc, startYLocLoc, destXLoc, destYLoc, unit_group_id,
781 															mobile_type, searchMode, miscNo, numOfPath, unit_search_tries);
782 
783 						result_node_array = seek_path.get_result(result_node_count, result_path_dist);
784 						seek_path.set_sub_mode(); // reset sub_mode searching
785 					}
786 					else	// use path_reuse
787 					{
788 						err_when(reuseMode!=GENERAL_GROUP_MOVEMENT);
789 						seekResult = seek_path_reuse.seek(startXLocLoc, startYLocLoc, destXLoc, destYLoc, 1, unit_group_id,
790 														mobile_type, searchMode, miscNo, numOfPath, reuseMode, pathReuseStatus);
791 						result_node_array = seek_path_reuse.get_result(result_node_count, result_path_dist);
792 					}
793 	#ifdef DEBUG
794 		seek_path_profile_time = misc.get_time() - seekPathStartTime;
795 	#endif
796 	/*				break;
797 
798 		default: err_here();
799 					break;
800 	}*/
801 
802 	if(seekResult==PATH_IMPOSSIBLE)
803 	{
804 		reset_path();
805 		err_when(result_node_array || result_node_count);
806 	}
807 
808 	//####### begin trevor 15/10 ########//
809 
810 	//-----------------------------------------------------------------------//
811 	// update ignore_power_nation,seek_path_fail_count
812 	//-----------------------------------------------------------------------//
813 
814 	if(ai_unit)
815 	{
816 		//----- set seek_path_fail_count ------//
817 
818 		if( seekResult==PATH_IMPOSSIBLE ||
819 			 (seekResult==PATH_NODE_USED_UP &&    // if all the nodes have been used up and the number of nodes original available is >= VALID_BACKGROUND_SEARCH_NODE
820 			  totalAvailableNode >= VALID_BACKGROUND_SEARCH_NODE) )
821 		{
822 			if( seek_path_fail_count < 100 )		// prevent numeric overflow
823 				seek_path_fail_count++;
824 		}
825 		else
826 			seek_path_fail_count=0;
827 
828 		//------- set ignore_power_nation -------//
829 
830 		if( seekResult==PATH_IMPOSSIBLE )
831 		{
832 			switch(ignore_power_nation)
833 			{
834 				case 0:	ignore_power_nation = 1;
835 							break;
836 				case 1:	ignore_power_nation = 2;
837 							break;
838 				case 2:	break;
839 				default:	err_here();
840 							break;
841 			}
842 		}
843 		else
844 		{
845 			if( ignore_power_nation==1 )
846 				ignore_power_nation = 0;
847 		}
848 	}
849 
850 	//######## end trevor 15/10 ########//
851 
852 	//-----------------------------------------------------------------------//
853 	// if closest node is returned, the destination should not be the real
854 	// location to go to.  Thus, move_to_?_loc should be adjusted
855 	//-----------------------------------------------------------------------//
856 	if(result_node_array && result_node_count)
857 	{
858 		ResultNode* lastNode = result_node_array + result_node_count - 1;
859 		move_to_x_loc = lastNode->node_x; // adjust move_to_?_loc
860 		move_to_y_loc = lastNode->node_y;
861 
862 		result_node_recno = 1;        // skip the first node which is the current location
863 		if(cur_action != SPRITE_MOVE)     // check if the unit is moving right now, wait until it reaches the nearest complete tile.
864 		{
865 			err_when(cur_action!=SPRITE_SHIP_EXTRA_MOVE && (cur_x!=next_x || cur_y!=next_y));
866 			#ifdef DEBUG
867 				int moveToXLoc = move_to_x_loc;
868 				int moveToYLoc = move_to_y_loc;
869 			#endif
870 
871 			ResultNode *nextNode = result_node_array + 1;
872 			//set_dir(next_x_loc(), next_y_loc(), nextNode->node_x, nextNode->node_y);
873 			set_dir(startXLocLoc, startYLocLoc, nextNode->node_x, nextNode->node_y);
874 
875 			next_move();
876 
877 			#ifdef DEBUG
878 			err_when(move_action_call_flag && (moveToXLoc!=move_to_x_loc || moveToYLoc!=move_to_y_loc));
879 			#endif
880 		}
881 	}
882 	else // stay in the current location
883 	{
884 		err_when(result_node_array!=NULL);
885 
886 		move_to_x_loc = startXLocLoc; // adjust move_to_?_loc
887 		move_to_y_loc = startYLocLoc;
888 		err_when(move_to_x_loc!=startXLocLoc || move_to_y_loc!=startYLocLoc);
889 
890 		if(cur_x!=next_x || cur_y!=next_y)
891 			set_move();
892 		else
893 			set_idle();
894 	}
895 
896 	err_when(move_to_x_loc<0 || move_to_x_loc>=MAX_WORLD_X_LOC || move_to_y_loc<0 || move_to_y_loc>=MAX_WORLD_Y_LOC);
897 	err_when(cur_action==SPRITE_IDLE && (move_to_x_loc!=next_x_loc() || move_to_y_loc!=next_y_loc()));
898 	err_when(cur_action==SPRITE_IDLE && (cur_x!=next_x || cur_y!=next_y));
899 
900 	//-------------------------------------------------------//
901 	// PATH_NODE_USED_UP happens when:
902 	// Exceed the object's MAX's node limitation, the closest path
903 	// is returned. Get to the closest path first and continue
904 	// to seek the path in the background.
905 	//-------------------------------------------------------//
906 
907 	return 1;
908 }
909 //----------- End of function Unit::searching -----------//
910 
911 
912 //--------- Begin of function Unit::move_to_firm_surround ---------//
913 // order unit to move to firm surrounding
914 //
915 // <int> destXLoc, destYLoc	- destination
916 // <int> width						- unit width
917 // <int> height					- unit height
918 // <int> miscNo					- the firm id (default 0)
919 // <int>	readyDist				- similar to that in set_move_to_surround()
920 //										  (default 0)
921 //
922 // Note: the firm should exist in the location (destXloc, destYLoc)
923 //			this function can be called by unit with size 1x1, 2x2,
924 //
move_to_firm_surround(int destXLoc,int destYLoc,int width,int height,int miscNo,int readyDist)925 void Unit::move_to_firm_surround(int destXLoc, int destYLoc, int width, int height, int miscNo, int readyDist)
926 {
927 	err_when(destXLoc<0 || destXLoc>=MAX_WORLD_X_LOC || destYLoc<0 || destYLoc>=MAX_WORLD_Y_LOC);
928 
929 	//----------------------------------------------------------------//
930 	// calculate new destination if trying to move to different territory
931 	//----------------------------------------------------------------//
932 	Location *locPtr = world.get_loc(destXLoc, destYLoc);
933 	if(unit_res[unit_id]->unit_class==UNIT_CLASS_SHIP && miscNo==FIRM_HARBOR)
934 	{
935 		err_when(!locPtr->is_firm());
936 		Firm *firmPtr = firm_array[locPtr->firm_recno()];
937 		FirmHarbor *harborPtr = (FirmHarbor*) firmPtr;
938 		if(world.get_loc(next_x_loc(), next_y_loc())->region_id!=harborPtr->sea_region_id)
939 		{
940 			move_to(destXLoc, destYLoc);
941 			return;
942 		}
943 	}
944 	else
945 	{
946 		if(world.get_loc(next_x_loc(), next_y_loc())->region_id!=locPtr->region_id)
947 		{
948 			move_to(destXLoc, destYLoc);
949 			return;
950 		}
951 	}
952 
953 	//----------------------------------------------------------------//
954 	// return if the unit is dead
955 	//----------------------------------------------------------------//
956 	if(is_unit_dead())
957 		return;
958 
959 	//----------------------------------------------------------------//
960 	// check for equal actions
961 	//----------------------------------------------------------------//
962 	if(action_mode2==ACTION_MOVE && action_mode==ACTION_MOVE)
963 	{
964 		//------ previous action is ACTION_MOVE -------//
965 		err_when(action_para2 || action_para);
966 		if(action_x_loc2==destXLoc && action_y_loc2==destYLoc)
967 		{
968 			//-------- equal order --------//
969 			action_x_loc = action_x_loc2;
970 			action_y_loc = action_y_loc2;
971 
972 			if(cur_action!=SPRITE_IDLE)
973 			{
974 				//-------- the old order is processing --------//
975 				if(result_node_array==NULL) // cannot move
976 				{
977 					err_when(result_node_count || result_node_recno);
978 					set_idle();
979 				}
980 
981 				err_when(action_mode==ACTION_MOVE && (action_x_loc==-1 || action_y_loc==-1));
982 				return;
983 			}//else action is hold due to some problems, re-activiate again
984 		}
985 	}//else, new order or searching is required
986 
987 	int destX = MAX(0, ((width>1) ? destXLoc : destXLoc - width + 1));
988 	int destY = MAX(0, ((height>1) ? destYLoc : destYLoc - height + 1));
989 
990 	FirmInfo *firmInfo = firm_res[miscNo];
991 	stop();
992 	set_move_to_surround(destX, destY, firmInfo->loc_width, firmInfo->loc_height, BUILDING_TYPE_FIRM_MOVE_TO, miscNo);
993 
994 	//----------------------------------------------------------------//
995 	// store new order in action parameters
996 	//----------------------------------------------------------------//
997 	action_mode = action_mode2 = ACTION_MOVE;
998 	action_para = action_para2 = 0;
999 	action_x_loc = action_x_loc2 = move_to_x_loc;
1000 	action_y_loc = action_y_loc2 = move_to_y_loc;
1001 
1002 	err_when(action_mode==ACTION_MOVE && (action_x_loc==-1 || action_y_loc==-1));
1003 	err_when(move_to_x_loc<0 || move_to_x_loc>=MAX_WORLD_X_LOC || move_to_y_loc<0 || move_to_y_loc>=MAX_WORLD_Y_LOC);
1004 	err_when(cur_action==SPRITE_IDLE && (move_to_x_loc!=next_x_loc() || move_to_y_loc!=next_y_loc()));
1005 	err_when(cur_action==SPRITE_IDLE && (cur_x!=next_x || cur_y!=next_y));
1006 
1007 	#ifdef DEBUG
1008 	if(unit_res[unit_id]->unit_class!=UNIT_CLASS_SHIP || ((UnitMarine*)this)->extra_move_in_beach==NO_EXTRA_MOVE)
1009 		err_when(result_node_array==NULL && (next_x!=go_x || next_y!=go_y));
1010 	#endif
1011 }
1012 //----------- End of function Unit::move_to_firm_surround -----------//
1013 
1014 
1015 //--------- Begin of function Unit::move_to_town_surround ---------//
1016 // move to town surrounding
1017 //
1018 // <int> destXLoc, destYLoc	- destination
1019 // <int> width						- unit width
1020 // <int> height					- unit height
1021 // <int> miscNo					- reserved (default 0)
1022 // <int>	readyDist				- similar to that in set_move_to_surround()
1023 //										  (default 0)
1024 //
1025 // Note: assume the town exists
1026 //			this function can be called by unit with size 1x1, 2x2,
1027 //
move_to_town_surround(int destXLoc,int destYLoc,int width,int height,int miscNo,int readyDist)1028 void Unit::move_to_town_surround(int destXLoc, int destYLoc, int width, int height, int miscNo, int readyDist)
1029 {
1030 	err_when(destXLoc<0 || destXLoc>=MAX_WORLD_X_LOC || destYLoc<0 || destYLoc>=MAX_WORLD_Y_LOC);
1031 
1032 	//----------------------------------------------------------------//
1033 	// calculate new destination if trying to move to different territory
1034 	//----------------------------------------------------------------//
1035 	Location *locPtr = world.get_loc(destXLoc, destYLoc);
1036 	if(world.get_loc(next_x_loc(), next_y_loc())->region_id!=locPtr->region_id)
1037 	{
1038 		move_to(destXLoc, destYLoc);
1039 		return;
1040 	}
1041 
1042 	//----------------------------------------------------------------//
1043 	// return if the unit is dead
1044 	//----------------------------------------------------------------//
1045 	if(is_unit_dead())
1046 		return;
1047 
1048 	//----------------------------------------------------------------//
1049 	// check for equal actions
1050 	//----------------------------------------------------------------//
1051 	if(action_mode2==ACTION_MOVE && action_mode==ACTION_MOVE)
1052 	{
1053 		//------ previous action is ACTION_MOVE -------//
1054 		err_when(action_para2 || action_para);
1055 		if(action_x_loc2==destXLoc && action_y_loc2==destYLoc)
1056 		{
1057 			//-------- equal order --------//
1058 			action_x_loc = action_x_loc2;
1059 			action_y_loc = action_y_loc2;
1060 
1061 			if(cur_action!=SPRITE_IDLE)
1062 			{
1063 				//-------- the old order is processing --------//
1064 				if(result_node_array==NULL) // cannot move
1065 				{
1066 					err_when(result_node_count || result_node_recno);
1067 					set_idle();
1068 				}
1069 
1070 				err_when(action_mode==ACTION_MOVE && (action_x_loc==-1 || action_y_loc==-1));
1071 				return;
1072 			}//else action is hold due to some problems, re-activiate again
1073 		}
1074 	}//else, new order or searching is required
1075 
1076 	int destX = MAX(0, ((width>1) ? destXLoc : destXLoc - width + 1));
1077 	int destY = MAX(0, ((height>1) ? destYLoc : destYLoc - height + 1));
1078 
1079 	stop();
1080 	set_move_to_surround(destX, destY, STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT, BUILDING_TYPE_TOWN_MOVE_TO);
1081 
1082 	//----------------------------------------------------------------//
1083 	// store new order in action parameters
1084 	//----------------------------------------------------------------//
1085 	action_mode = action_mode2 = ACTION_MOVE;
1086 	action_para = action_para2 = 0;
1087 	action_x_loc = action_x_loc2 = move_to_x_loc;
1088 	action_y_loc = action_y_loc2 = move_to_y_loc;
1089 
1090 	err_when(action_mode==ACTION_MOVE && (action_x_loc==-1 || action_y_loc==-1));
1091 	err_when(move_to_x_loc<0 || move_to_x_loc>=MAX_WORLD_X_LOC || move_to_y_loc<0 || move_to_y_loc>=MAX_WORLD_Y_LOC);
1092 	err_when(cur_action==SPRITE_IDLE && (move_to_x_loc!=next_x_loc() || move_to_y_loc!=next_y_loc()));
1093 	err_when(cur_action==SPRITE_IDLE && (cur_x!=next_x || cur_y!=next_y));
1094 	err_when(result_node_array==NULL && (next_x!=go_x || next_y!=go_y));
1095 }
1096 //----------- End of function Unit::move_to_town_surround -----------//
1097 
1098 
1099 //--------- Begin of function Unit::move_to_wall_surround ---------//
1100 // move to wall surrounding
1101 //
1102 // <int> destXLoc, destYLoc	- destination
1103 // <int> width						- unit width
1104 // <int> height					- unit height
1105 // <int> miscNo					- reserved (default 0)
1106 // <int>	readyDist				- similar to that in set_move_to_surround()
1107 //										  (default 0)
1108 //
1109 // Note: assume the wall exists
1110 //			this function can be called by unit with size 1x1, 2x2,
1111 //
move_to_wall_surround(int destXLoc,int destYLoc,int width,int height,int miscNo,int readyDist)1112 void Unit::move_to_wall_surround(int destXLoc, int destYLoc, int width, int height, int miscNo, int readyDist)
1113 {
1114 	err_when(destXLoc<0 || destXLoc>=MAX_WORLD_X_LOC || destYLoc<0 || destYLoc>=MAX_WORLD_Y_LOC);
1115 
1116 	//----------------------------------------------------------------//
1117 	// calculate new destination if trying to move to different territory
1118 	//----------------------------------------------------------------//
1119 	Location *locPtr = world.get_loc(destXLoc, destYLoc);
1120 	if(world.get_loc(next_x_loc(), next_y_loc())->region_id!=locPtr->region_id)
1121 	{
1122 		move_to(destXLoc, destYLoc);
1123 		return;
1124 	}
1125 
1126 	//----------------------------------------------------------------//
1127 	// return if the unit is dead
1128 	//----------------------------------------------------------------//
1129 	if(is_unit_dead())
1130 		return;
1131 
1132 	//----------------------------------------------------------------//
1133 	// check for equal actions
1134 	//----------------------------------------------------------------//
1135 	if(action_mode2==ACTION_MOVE && action_mode==ACTION_MOVE)
1136 	{
1137 		//------ previous action is ACTION_MOVE -------//
1138 		err_when(action_para2 || action_para);
1139 		if(action_x_loc2==destXLoc && action_y_loc2==destYLoc)
1140 		{
1141 			//-------- equal order --------//
1142 			action_x_loc = action_x_loc2;
1143 			action_y_loc = action_y_loc2;
1144 
1145 			if(cur_action!=SPRITE_IDLE)
1146 			{
1147 				//-------- the old order is processing --------//
1148 				if(result_node_array==NULL) // cannot move
1149 				{
1150 					err_when(result_node_count || result_node_recno);
1151 					set_idle();
1152 				}
1153 
1154 				err_when(action_mode==ACTION_MOVE && (action_x_loc==-1 || action_y_loc==-1));
1155 				return;
1156 			}//else action is hold due to some problems, re-activiate again
1157 		}
1158 	}//else, new order or searching is required
1159 
1160 	int destX = MAX(0, ((width>1) ? destXLoc : destXLoc - width + 1));
1161 	int destY = MAX(0, ((height>1) ? destYLoc : destYLoc - height + 1));
1162 
1163 	stop();
1164 	set_move_to_surround(destX, destY, 1, 1, BUILDING_TYPE_WALL);
1165 
1166 	//----------------------------------------------------------------//
1167 	// store new order in action parameters
1168 	//----------------------------------------------------------------//
1169 	action_mode = action_mode2 = ACTION_MOVE;
1170 	action_para = action_para2 = 0;
1171 	action_x_loc = action_x_loc2 = move_to_x_loc;
1172 	action_y_loc = action_y_loc2 = move_to_y_loc;
1173 
1174 	err_when(action_mode==ACTION_MOVE && (action_x_loc==-1 || action_y_loc==-1));
1175 	err_when(move_to_x_loc<0 || move_to_x_loc>=MAX_WORLD_X_LOC || move_to_y_loc<0 || move_to_y_loc>=MAX_WORLD_Y_LOC);
1176 	err_when(cur_action==SPRITE_IDLE && (move_to_x_loc!=next_x_loc() || move_to_y_loc!=next_y_loc()));
1177 	err_when(cur_action==SPRITE_IDLE && (cur_x!=next_x || cur_y!=next_y));
1178 	err_when(result_node_array==NULL && (next_x!=go_x || next_y!=go_y));
1179 }
1180 //----------- End of function Unit::move_to_wall_surround -----------//
1181 
1182 
1183 //--------- Begin of function Unit::move_to_unit_surround ---------//
1184 // move to unit surrounding
1185 //
1186 // <int> destXLoc, destYLoc	- destination
1187 // <int> width						- unit width
1188 // <int> height					- unit height
1189 // <int> miscNo					- vehicle unit_recno (default 0)
1190 // <int>	readyDist				- similar to that in set_move_to_surround()
1191 //										  (default 0)
1192 //
1193 // Note: assume the vehicle exists
1194 //			this function can be called by unit with size 1x1, 2x2,
1195 //
move_to_unit_surround(int destXLoc,int destYLoc,int width,int height,int miscNo,int readyDist)1196 void Unit::move_to_unit_surround(int destXLoc, int destYLoc, int width, int height, int miscNo, int readyDist)
1197 {
1198 	err_when(destXLoc<0 || destXLoc>=MAX_WORLD_X_LOC || destYLoc<0 || destYLoc>=MAX_WORLD_Y_LOC);
1199 
1200 	//----------------------------------------------------------------//
1201 	// calculate new destination if trying to move to different territory
1202 	//----------------------------------------------------------------//
1203 	Location *locPtr = world.get_loc(destXLoc, destYLoc);
1204 	if(world.get_loc(next_x_loc(), next_y_loc())->region_id!=locPtr->region_id)
1205 	{
1206 		move_to(destXLoc, destYLoc);
1207 		return;
1208 	}
1209 
1210 	//----------------------------------------------------------------//
1211 	// return if the unit is dead
1212 	//----------------------------------------------------------------//
1213 	if(is_unit_dead())
1214 		return;
1215 
1216 	//----------------------------------------------------------------//
1217 	// check for equal actions
1218 	//----------------------------------------------------------------//
1219 	if(action_mode2==ACTION_MOVE && action_mode==ACTION_MOVE)
1220 	{
1221 		//------ previous action is ACTION_MOVE -------//
1222 		err_when(action_para2 || action_para);
1223 		if(action_x_loc2==destXLoc && action_y_loc2==destYLoc)
1224 		{
1225 			//-------- equal order --------//
1226 			action_x_loc = action_x_loc2;
1227 			action_y_loc = action_y_loc2;
1228 
1229 			if(cur_action!=SPRITE_IDLE)
1230 			{
1231 				//-------- the old order is processing --------//
1232 				if(result_node_array==NULL) // cannot move
1233 				{
1234 					err_when(result_node_count || result_node_recno);
1235 					set_idle();
1236 				}
1237 
1238 				err_when(action_mode==ACTION_MOVE && (action_x_loc==-1 || action_y_loc==-1));
1239 				return;
1240 			}//else action is hold due to some problems, re-activiate again
1241 		}
1242 	}//else, new order or searching is required
1243 
1244 	int destX = MAX(0, ((width>1) ? destXLoc : destXLoc - width + 1));
1245 	int destY = MAX(0, ((height>1) ? destYLoc : destYLoc - height + 1));
1246 
1247 	err_when(unit_array.is_deleted(miscNo));
1248 	Unit *unitPtr = unit_array[miscNo];
1249 	SpriteInfo *spriteInfo = unitPtr->sprite_info;
1250 	stop();
1251 	set_move_to_surround(destX, destY, spriteInfo->loc_width, spriteInfo->loc_height, BUILDING_TYPE_VEHICLE);
1252 
1253 	//----------------------------------------------------------------//
1254 	// store new order in action parameters
1255 	//----------------------------------------------------------------//
1256 	action_mode = action_mode2 = ACTION_MOVE;
1257 	action_para = action_para2 = 0;
1258 	action_x_loc = action_x_loc2 = move_to_x_loc;
1259 	action_y_loc = action_y_loc2 = move_to_y_loc;
1260 
1261 	err_when(action_mode==ACTION_MOVE && (action_x_loc==-1 || action_y_loc==-1));
1262 	err_when(move_to_x_loc<0 || move_to_x_loc>=MAX_WORLD_X_LOC || move_to_y_loc<0 || move_to_y_loc>=MAX_WORLD_Y_LOC);
1263 	err_when(cur_action==SPRITE_IDLE && (move_to_x_loc!=next_x_loc() || move_to_y_loc!=next_y_loc()));
1264 	err_when(cur_action==SPRITE_IDLE && (cur_x!=next_x || cur_y!=next_y));
1265 	err_when(result_node_array==NULL && (next_x!=go_x || next_y!=go_y));
1266 }
1267 //----------- End of function Unit::move_to_unit_surround -----------//
1268 
1269 
1270 //--------- Begin of function Unit::different_territory_destination ---------//
1271 // calculate a reachable destination if the unit is ordered to move to unreachable
1272 // location on different territory
1273 //
1274 // <int&> destX, destY	- reference to return destination
1275 //
different_territory_destination(int & destX,int & destY)1276 void Unit::different_territory_destination(int& destX, int& destY)
1277 {
1278 	int curXLoc = next_x_loc();
1279 	int curYLoc = next_y_loc();
1280 
1281 	Location *locPtr = world.get_loc(curXLoc, curYLoc);
1282 	int regionId = locPtr->region_id;
1283 	int xStep = destX-curXLoc;
1284 	int yStep = destY-curYLoc;
1285 	int absXStep = abs(xStep);
1286 	int absYStep = abs(yStep);
1287 	int count = (absXStep>=absYStep) ? absXStep : absYStep;
1288 	int x, y;
1289 	long int sameTerr = 0;
1290 
1291 	//------------------------------------------------------------------------------//
1292 	// draw a line from the unit location to the destination, find the last location
1293 	// with the same region id.
1294 	//------------------------------------------------------------------------------//
1295 	for(long int i=1; i<=count; i++)
1296 	{
1297 		x = curXLoc + int((i*xStep)/count);
1298 		y = curYLoc + int((i*yStep)/count);
1299 
1300 		locPtr = world.get_loc(x, y);
1301 		if(locPtr->region_id==regionId)
1302 			sameTerr = i;
1303 	}
1304 
1305 	if(sameTerr)
1306 	{
1307 		destX = curXLoc + int((sameTerr*xStep)/count);
1308 		destY = curYLoc + int((sameTerr*yStep)/count);
1309 	}
1310 	else
1311 	{
1312 		destX = curXLoc;
1313 		destY = curYLoc;
1314 	}
1315 }
1316 //----------- End of function Unit::different_territory_destination -----------//
1317 
1318 
1319 //--------- Begin of function Unit::next_move ---------//
1320 //
1321 //	If there is unprocessed node(s) in the result_node_array,
1322 // then next unprocessed node will be set to be the next location
1323 // to move to. (i.e. go_? = location of the unprocessed node)
1324 //
next_move()1325 void Unit::next_move()
1326 {
1327 	if(result_node_array == NULL || !result_node_count || !result_node_recno)
1328       return;
1329 
1330    if( ++result_node_recno > result_node_count )
1331    {
1332 		//------------ all nodes are visited --------------//
1333 		err_when(cur_x!=next_x || cur_y!=next_y);
1334 		err_when(next_x_loc()!=move_to_x_loc || next_y_loc()!=move_to_y_loc);
1335 
1336       mem_del(result_node_array);
1337       result_node_array = NULL;
1338 		set_idle();
1339 
1340 		if(action_mode2==ACTION_MOVE) //--------- used to terminate action_mode==ACTION_MOVE
1341 		{
1342 			force_move_flag = 0;
1343 
1344 			//------- reset ACTION_MOVE parameters ------//
1345 			reset_action_para();
1346 			if(move_to_x_loc==action_x_loc2 && move_to_y_loc==action_y_loc2)
1347 				reset_action_para2();
1348 		}
1349       return;
1350    }
1351 
1352    //---- order the unit to move to the next checkpoint following the path ----//
1353 
1354    ResultNode* resultNode = result_node_array+result_node_recno-1;
1355 	#ifdef DEBUG
1356 		err_when(cur_x==move_to_x_loc*ZOOM_LOC_WIDTH && cur_y==move_to_y_loc*ZOOM_LOC_HEIGHT);
1357 		err_when(!resultNode);
1358 	#endif
1359 
1360 	sprite_move( resultNode->node_x*ZOOM_LOC_WIDTH, resultNode->node_y*ZOOM_LOC_HEIGHT );
1361 
1362 	err_when(cur_x==go_x && cur_y==go_y && (cur_x!=next_x || cur_y!=next_y));
1363 }
1364 //----------- End of function Unit::next_move -----------//
1365 
1366 
1367 //--------- Begin of function Unit::reset_path ---------//
1368 // Cancel all movement.
1369 //
reset_path()1370 void Unit::reset_path()
1371 {
1372 	if( result_node_array )
1373 	{
1374 		mem_del(result_node_array);
1375       result_node_array = NULL;
1376 	}
1377 
1378 	result_path_dist = result_node_count = result_node_recno = 0;
1379 }
1380 //----------- End of function Unit::reset_path -----------//
1381 
1382 
1383 //--------- Begin of function Unit::pre_process ---------//
1384 // process unit's action
1385 //
pre_process()1386 void Unit::pre_process()
1387 {
1388 	//-*********** simulate aat ************-//
1389 	#ifdef DEBUG
1390 		if(debug_sim_game_type==2)
1391 		{
1392 			if(hit_points!=max_hit_points)
1393 				hit_points = max_hit_points;
1394 
1395 			Nation *nationPtr = nation_array[nation_recno];
1396 			if(nationPtr->cash<4000)
1397 				nationPtr->cash += 10000;
1398 
1399 			if(nationPtr->food<4000)
1400 				nationPtr->food += 10000;
1401 		}
1402 	#endif
1403 	//-*********** simulate aat ************-//
1404 
1405 	#if defined(DEBUG) && defined(ENABLE_LOG)
1406 		String logStr;
1407 		logStr = " begin unit ";
1408 		logStr += sprite_recno;
1409 		// ########## begin Gilbert 6/9 #######//
1410 		logStr += " nation=";
1411 		logStr += nation_recno;
1412 		logStr += "(";
1413 		logStr += true_nation_recno();
1414 		logStr += ")";
1415 		// ########## end Gilbert 6/9 #######//
1416 		logStr += " pre_process(), action_mode=";
1417 		logStr += action_mode;
1418 		logStr += " action_mode2=";
1419 		logStr += action_mode2;
1420 		LOG_MSG(logStr);
1421 
1422 		logStr = "action_para=";
1423 		logStr += action_para;
1424 		logStr += " action_para2=";
1425 		logStr += action_para2;
1426 		logStr += " cur_action=";
1427 		logStr += cur_action;
1428 		logStr += " cur_x/y=";
1429 		logStr += cur_x;
1430 		logStr += "/";
1431 		logStr += cur_y;
1432 		logStr += " next_x/y=";
1433 		logStr += next_x;
1434 		logStr += "/";
1435 		logStr += next_y;
1436 
1437 		LOG_MSG(logStr);
1438 	#endif
1439 
1440 	//------ if all the hit points are lost, die now ------//
1441 	if(hit_points <= 0 && action_mode != ACTION_DIE)
1442 	{
1443 		set_die();
1444 
1445 		if(ai_action_id)
1446 			nation_array[nation_recno]->action_failure(ai_action_id, sprite_recno);
1447 
1448 		return;
1449 	}
1450 
1451 	#ifdef DEBUG
1452 		int debugActionMode = action_mode;
1453 		int debugActionPatra = action_para;
1454 		int debugCurAction = cur_action;
1455 	#endif
1456 
1457 	if( config.fog_of_war )
1458 	{
1459 		if( is_own() ||
1460 			 (nation_recno && nation_array[nation_recno]->is_allied_with_player) )
1461 		{
1462 			world.visit(next_x_loc(), next_y_loc(), next_x_loc()+sprite_info->loc_width-1,
1463 				next_y_loc()+sprite_info->loc_height-1, unit_res[unit_id]->visual_range,
1464 				unit_res[unit_id]->visual_extend);
1465 		}
1466 	}
1467 
1468 	//--------- process action corresponding to action_mode ----------//
1469 
1470 	#ifdef DEBUG
1471 		unsigned long startTime;
1472 	#endif
1473 
1474 	switch(action_mode)
1475 	{
1476 		case ACTION_ATTACK_UNIT:
1477 
1478 			#ifdef DEBUG
1479 				startTime = misc.get_time();
1480 			#endif
1481 
1482 			//------------------------------------------------------------------//
1483 			// if unit is in defense mode, check situation to follow the target
1484 			// or return back to camp
1485 			//------------------------------------------------------------------//
1486 			if(action_mode!=action_mode2)
1487 			{
1488 				if(action_mode2==ACTION_AUTO_DEFENSE_ATTACK_TARGET)
1489 				{
1490 					if(!defense_follow_target()) // false if abort attacking
1491 						break; // cancel attack and go back to military camp
1492 				}
1493 				else if(action_mode2==ACTION_DEFEND_TOWN_ATTACK_TARGET)
1494 				{
1495 					if(!defend_town_follow_target())
1496 						break;
1497 				}
1498 				else if(action_mode2==ACTION_MONSTER_DEFEND_ATTACK_TARGET)
1499 				{
1500 					if(!monster_defend_follow_target())
1501 						break;
1502 				}
1503 				else
1504 					err_here();
1505 			}
1506 
1507 			process_attack_unit();
1508 
1509 			#ifdef DEBUG
1510 				unit_attack_profile_time += misc.get_time() - startTime;
1511 			#endif
1512 			break;
1513 
1514 		case ACTION_ATTACK_FIRM:
1515 			process_attack_firm();
1516 			break;
1517 
1518 		case ACTION_ATTACK_TOWN:
1519 			process_attack_town();
1520 			break;
1521 
1522 		case ACTION_ATTACK_WALL:
1523 			process_attack_wall();
1524 			break;
1525 
1526 		case ACTION_ASSIGN_TO_FIRM:
1527 		case ACTION_ASSIGN_TO_TOWN:
1528 		case ACTION_ASSIGN_TO_VEHICLE:
1529 			#ifdef DEBUG
1530 				startTime = misc.get_time();
1531 			#endif
1532 			process_assign();
1533 			#ifdef DEBUG
1534 				unit_assign_profile_time += misc.get_time() - startTime;
1535 			#endif
1536 			break;
1537 
1538 		case ACTION_ASSIGN_TO_SHIP:
1539 			process_assign_to_ship();
1540 			break;
1541 
1542 		case ACTION_BUILD_FIRM:
1543 			process_build_firm();
1544 			break;
1545 
1546 		case ACTION_BURN:
1547 			process_burn();
1548 			break;
1549 
1550 		case ACTION_SETTLE:
1551 			process_settle();
1552 			break;
1553 
1554 		case ACTION_SHIP_TO_BEACH:
1555 			process_ship_to_beach();
1556 			break;
1557 
1558 		case ACTION_GO_CAST_POWER:
1559 			process_go_cast_power();
1560 			break;
1561 	}
1562 
1563 	//-****** don't add code here, the unit may be removed after the above function call*******-//
1564 
1565 	// ###### begin Gilbert 20/6 ########//
1566 	#ifdef DEBUG
1567 		// do not read data member
1568 		LOG_MSG( " end Unit::pre_process()" );
1569 		LOG_MSG( misc.get_random_seed() );
1570 	#endif
1571 	// ###### end Gilbert 20/6 ########//
1572 
1573 }
1574 //----------- End of function Unit::pre_process -----------//
1575 
1576 
1577 //--------- Begin of function Unit::process_die ---------//
1578 // process unit die
1579 //
1580 // return 1 if die frame is counting
1581 // return 0 otherwise
1582 //
process_die()1583 int Unit::process_die()
1584 {
1585 	//-*********** simulate aat ************-//
1586 	#ifdef DEBUG
1587 		if(debug_sim_game_type)
1588 		{
1589 			cur_action = SPRITE_IDLE;
1590 			hit_points = max_hit_points;
1591 			stop2();
1592 			return 0;
1593 		}
1594 	#endif
1595 	//-*********** simulate aat ************-//
1596 
1597 	//--------- voice ------------//
1598 	se_res.sound(cur_x_loc(), cur_y_loc(), cur_frame, 'S',sprite_id,"DIE");
1599 
1600 	// ####### begin Gilbert 14/7 ###########//
1601 	//------------- add die effect on first frame --------- //
1602 	if( cur_frame == 1 && unit_res[unit_id]->die_effect_id)
1603 	{
1604 		Effect::create(unit_res[unit_id]->die_effect_id, cur_x, cur_y,
1605 			SPRITE_DIE, cur_dir, mobile_type == UNIT_AIR ? 8 : 2, 0);
1606 	}
1607 	// ####### end Gilbert 14/7 ###########//
1608 
1609 	//--------- next frame ---------//
1610 	if( ++cur_frame > sprite_info->die.frame_count )
1611 		return 1;
1612 
1613 	return 0;
1614 }
1615 //----------- End of function Unit::process_die -----------//
1616 
1617 
1618 //--------- Begin of function Unit::process_rebel ---------//
1619 //
1620 // Unit::process_rebel() is in OREBEL.CPP
1621 //
1622 //----------- End of function Unit::process_rebel ---------//
1623 
1624 
1625 //--------- Begin of function Unit::avail_node_enough_for_search --------//
1626 // decide whether the available number of nodes enough for a valid path searching
1627 //
1628 // <short>	x1, y1	-	start location
1629 // <short>	x2, y2	-	end location
1630 //
1631 // return 1 if num of nodes is enough
1632 // return 0 otherwise
1633 //
avail_node_enough_for_search(short x1,short y1,short x2,short y2)1634 int Unit::avail_node_enough_for_search(short x1, short y1, short x2, short y2)
1635 {
1636 	short dispX = abs(x1-x2);
1637 	short dispY = abs(y1-y2);
1638 
1639 	short majDist = dispX>dispY ? dispX : dispY;
1640 	short minDist = abs(dispX-dispY);
1641 
1642 	int nodeRequire = MIN(VALID_BACKGROUND_SEARCH_NODE, majDist<<5); // *32
1643 	int totalNode = seek_path.total_node_avail;
1644 	if(totalNode < nodeRequire)
1645 	{
1646 		if(totalNode>=MIN_BACKGROUND_NODE_USED_UP)
1647 			seek_path.total_node_avail = MIN_BACKGROUND_NODE_USED_UP-1;
1648 
1649 		return 0;
1650 	}
1651 
1652 	return 1;
1653 }
1654 //----------- End of function Unit::avail_node_enough_for_search -----------//
1655 
1656 
1657 //--------- Begin of function Unit::process_move --------//
1658 // process unit movement
1659 //
process_move()1660 void Unit::process_move()
1661 {
1662 	//----- if the sprite has reach the destintion ----//
1663 
1664 	//--------------------------------------------------------//
1665 	// if the unit reach its destination, then
1666 	// cur_? == next_? == go_?
1667 	//--------------------------------------------------------//
1668 	err_when(cur_x==go_x && cur_y==go_y && (cur_x!=next_x || cur_y!=next_y));
1669 
1670 	if(cur_x==go_x && cur_y==go_y)
1671 	{
1672 		if(result_node_array)
1673 		{
1674 			next_move();
1675 			if( cur_action != SPRITE_MOVE )     // if next_move() is not successful, the movement has been stopped
1676 				return;
1677 
1678 			//---------------------------------------------------------------------------//
1679 			// If (1) the unit is blocked at cur_? == go_? and go_? != destination and
1680 			//		(2) a new path is generated if calling the previous next_move(),
1681 			//	then cur_? still equal to go_?.
1682 			//
1683 			// The following Sprite::process_move() call will set the unit to SPRITE_IDLE
1684 			// since cur_? == go_?. Thus, the unit terminates its move although it has not
1685 			// reached its destination.
1686 			//
1687 			// (note: if it has reached its destination, cur_? == go_? and cur_action =
1688 			//			 SPRITE_IDLE)
1689 			//
1690 			// if the unit is still moving and cur_? == go_?, call next_move() again to reset
1691 			// the go_?.
1692 			//---------------------------------------------------------------------------//
1693 			if(cur_action==SPRITE_MOVE && cur_x==go_x && cur_y==go_y)
1694 				next_move();
1695 		}
1696 	}
1697 
1698 	err_when(result_node_array && result_node_count==result_node_recno &&
1699 				(result_node_array[result_node_count-1].node_x!=go_x>>ZOOM_X_SHIFT_COUNT ||
1700 				result_node_array[result_node_count-1].node_y!=go_y>>ZOOM_Y_SHIFT_COUNT));
1701 
1702 	//--------- process the move, update sprite position ---------//
1703 	//--------------------------------------------------------//
1704 	// if the unit is moving, cur_?!=go_? and
1705 	// if next_? != cur_?, the direction from cur_? to next_?
1706 	// should equal to that from cur_? to go_?
1707 	//--------------------------------------------------------//
1708 	err_when((cur_x%ZOOM_LOC_WIDTH==0 && cur_y%ZOOM_LOC_HEIGHT==0) && (cur_x!=next_x || cur_y!=next_y) &&
1709 				((check_unit_dir1=get_dir(cur_x, cur_y, go_x, go_y))!=(check_unit_dir2=get_dir(cur_x, cur_y, next_x, next_y))));
1710 
1711 	#ifdef DEBUG
1712 		int debugCurX = cur_x;
1713 		int debugCurY = cur_y;
1714 		int debugNextX = next_x;
1715 		int debugNextY = next_y;
1716 		int debugGoX = go_x;
1717 		int debugGoY = go_y;
1718 	#endif
1719 	err_when(cur_x-next_x!=0 && cur_y-next_y!=0 && abs(next_x-cur_x)!=abs(next_y-cur_y));
1720 	err_when(result_path_dist && result_node_array==NULL);
1721 
1722 	Sprite::process_move();
1723 
1724 	err_when( cur_x < 0 || cur_y < 0 || cur_x >= ZOOM_X_PIXELS || cur_y >= ZOOM_Y_PIXELS );
1725 	if(cur_x==go_x && cur_y==go_y && cur_action==SPRITE_IDLE)	// the sprite has reached its destination
1726 	{
1727 		move_to_x_loc = next_x_loc();
1728 		move_to_y_loc = next_y_loc();
1729 	}
1730 
1731 	//--------------------------------------------------------//
1732 	// after Sprite::process_move(), if the unit is blocked, its
1733 	// cur_action is set to SPRITE_WAIT. Otherwise, its cur_action
1734 	// is still SPRITE_MOVE.  Then cur_? != next_? if the unit
1735 	// has not reached its destination.
1736 	//--------------------------------------------------------//
1737 	err_when(cur_action==SPRITE_MOVE && (cur_x!=go_x || cur_y!=go_y) && (cur_x==next_x && cur_y==next_y));
1738 }
1739 //---------- End of function Unit::process_move ----------//
1740 
1741 
1742 //--------- Begin of function Unit::process_wait ---------//
1743 // process unit's waiting
1744 //
process_wait()1745 void Unit::process_wait()
1746 {
1747 	err_when((check_unit_dir1=get_dir(cur_x, cur_y, go_x, go_y))!=final_dir);
1748 	if(!match_dir())
1749 		return;
1750 
1751 	//-----------------------------------------------------//
1752 	// If the unit is moving to the destination and was
1753 	// blocked by something. If it is now no longer blocked,
1754 	// continue the movement.
1755 	//-----------------------------------------------------//
1756    //
1757 	// When this funciton is called:
1758    //
1759 	// (next_x, next_y)==(cur_x, cur_y), it's the location of the sprite.
1760    //
1761    //-----------------------------------------------------//
1762 
1763    //--- find out the next location which the sprite should be moving towards ---//
1764 
1765 	//-----------------------------------------------------//
1766 	// If the unit is waiting,
1767 	//		go_? != cur_?
1768 	//		go_? != next_?
1769 	//
1770 	// If the unit is not under swapping, the next_?_loc()
1771 	//	is always the move_to_?_loc. Thus, the unit is ordered
1772 	//	to stop.
1773 	//-----------------------------------------------------//
1774 	err_when( (go_x>>ZOOM_X_SHIFT_COUNT!=move_to_x_loc || go_y>>ZOOM_Y_SHIFT_COUNT!=move_to_y_loc) &&
1775 				 ( (cur_x==go_x && cur_y==go_y) || (cur_x!=next_x || cur_y!=next_y) ) );
1776 
1777 	if(next_x_loc()==move_to_x_loc && next_y_loc()==move_to_y_loc && !swapping)
1778 	{
1779 		terminate_move();
1780 		return; // terminate since already in destination
1781 	}
1782 
1783    int stepMagn = move_step_magn();
1784 	int nextX = cur_x+stepMagn*move_x_pixel_array[final_dir];
1785    int nextY = cur_y+stepMagn*move_y_pixel_array[final_dir];
1786 
1787 	/*short w, h, blocked=0;
1788 	short x, y, blockedX, blockedY;
1789 	Location* locPtr;
1790 
1791 	//---------- check whether the unit is blocked -----------//
1792 	for(h=0, y=nextY>>ZOOM_Y_SHIFT_COUNT; h<sprite_info->loc_height && !blocked; h++, y++)
1793 	{
1794 		for(w=0, x=nextX>>ZOOM_X_SHIFT_COUNT; w<sprite_info->loc_width && !blocked; w++, x++)
1795 		{
1796 			locPtr = world.get_loc(x, y);
1797 			blocked = ( (!locPtr->is_accessible(mobile_type)) || (locPtr->has_unit(mobile_type) &&
1798 							locPtr->unit_recno(mobile_type)!=sprite_recno) );
1799 
1800 			if(blocked)
1801 			{
1802 				blockedX = x;
1803 				blockedY = y;
1804 			}
1805 		}
1806 	}*/
1807 	short x = nextX>>ZOOM_X_SHIFT_COUNT;
1808 	short y = nextY>>ZOOM_Y_SHIFT_COUNT;
1809 	Location *locPtr = world.get_loc(x, y);
1810 	short blocked = ( (!locPtr->is_accessible(mobile_type)) || (locPtr->has_unit(mobile_type) &&
1811 							locPtr->unit_recno(mobile_type)!=sprite_recno) );
1812 
1813 	if(!blocked || move_action_call_flag)
1814 	{
1815 		//--------- not blocked, continue to move --------//
1816 		waiting_term = 0;
1817 		set_move();
1818 		cur_frame  = 1;
1819 		set_next(nextX, nextY, -stepMagn, 1);
1820 	}
1821 	else
1822 	{
1823 		//------- blocked, call handle_blocked_move() ------//
1824 		//locPtr = world.get_loc(blockedX, blockedY);
1825 		err_when(cur_x!=next_x || cur_y!=next_y);
1826       handle_blocked_move(locPtr);
1827 	}
1828 
1829 	err_when(cur_action==SPRITE_MOVE && (cur_x!=go_x || cur_y!=go_y) && (cur_x==next_x && cur_y==next_y));
1830 	err_when(cur_x==go_x && cur_y==go_y && (cur_x!=next_x || cur_y!=next_y));
1831 }
1832 //----------- End of function Unit::process_wait -----------//
1833 
1834 
1835 //--------- Begin of function Unit::set_next --------//
1836 //	set the next coordinates to move to
1837 //
1838 // <int> newNextX, newNextY	- next coordinate to move to
1839 // <int> para						- used to count the result_path_dist
1840 // <int> blockedChecked			- whether the next location specified is checked to be
1841 //											non-blocked.  1 checked for non-blocked, 0 for not checked
1842 //
set_next(int newNextX,int newNextY,int para,int blockedChecked)1843 void Unit::set_next(int newNextX, int newNextY, int para, int blockedChecked)
1844 {
1845 	int curNextXLoc = next_x_loc();
1846    int curNextYLoc = next_y_loc();
1847 	int newNextXLoc = newNextX >> ZOOM_X_SHIFT_COUNT;
1848 	int newNextYLoc = newNextY >> ZOOM_Y_SHIFT_COUNT;
1849 
1850 	#ifdef DEBUG
1851 		int debugStepMagn = move_step_magn();
1852 		err_when(abs(curNextXLoc-newNextXLoc)>debugStepMagn || abs(curNextYLoc-newNextYLoc)>debugStepMagn);
1853 	#endif
1854 
1855 	if(curNextXLoc!=newNextXLoc || curNextYLoc!=newNextYLoc)
1856 	{
1857 		if(!match_dir())
1858 		{
1859 			set_wait();
1860 			return;
1861 		}
1862 	}
1863 
1864 	//short w, h, blocked=0;
1865 	//short x, y, blockedX, blockedY;
1866 	short w, h, blocked=0;
1867 	short x, y;
1868 
1869 	#ifdef DEBUG
1870 		for(h=0, y=curNextYLoc; h<sprite_info->loc_height; h++, y++)
1871 			for(w=0, x=curNextXLoc; w<sprite_info->loc_width; w++, x++)
1872 				err_when( world.get_unit_recno(x, y, mobile_type) != sprite_recno ); // it must be 0 to put the sprite in this location
1873 	#endif
1874 
1875 	if( curNextXLoc != newNextXLoc || curNextYLoc != newNextYLoc )
1876 	{
1877 		//------- if the next location is blocked ----------//
1878 
1879 		Location* locPtr;
1880 		if(!blockedChecked)
1881 		{
1882 			/*for(h=0, y=newNextYLoc; h<sprite_info->loc_height && !blocked; h++, y++)
1883 			{
1884 				for(w=0, x=newNextXLoc; w<sprite_info->loc_width && !blocked; w++, x++)
1885 				{
1886 					locPtr = world.get_loc(x, y);
1887 					blocked = ( (!locPtr->is_accessible(mobile_type)) || (locPtr->has_unit(mobile_type) &&
1888 									locPtr->unit_recno(mobile_type)!=sprite_recno) );
1889 
1890 					if(blocked)
1891 					{
1892 						blockedX = x;
1893 						blockedY = y;
1894 					}
1895 				}
1896 			}*/
1897 			x = newNextXLoc;
1898 			y = newNextYLoc;
1899 			locPtr = world.get_loc(x, y);
1900 			blocked = ( (!locPtr->is_accessible(mobile_type)) || (locPtr->has_unit(mobile_type) &&
1901 							locPtr->unit_recno(mobile_type)!=sprite_recno) );
1902 		}//else, then blockedChecked = 0
1903 
1904 		//--- no change to next_x & next_y if the new next location is blocked ---//
1905 
1906 		if(blocked)
1907 		{
1908 			set_cur(next_x, next_y);   // align the sprite to 32x32 location when it stops
1909 
1910 			//------ avoid infinitely looping in calling handle_blocked_move() ------//
1911 			if(blocked_by_member || move_action_call_flag)
1912 			{
1913 				set_wait();
1914 				blocked_by_member = 0;
1915 			}
1916 			else
1917 			{
1918 				locPtr = world.get_loc(x, y);
1919 				handle_blocked_move(locPtr);
1920 			}
1921 
1922 		#ifdef DEBUG
1923 			for(h=0, y=next_y_loc(); h<sprite_info->loc_height; h++, y++)
1924 			{
1925 				for(w=0, x=next_x_loc(); w<sprite_info->loc_width; w++, x++)
1926 					err_when( world.get_unit_recno(x, y, mobile_type) != sprite_recno );    // it must be 0 to put the sprite in this location
1927 			}
1928 		#endif
1929 		}
1930 		else
1931 		{
1932 			err_when(mobile_type!=UNIT_LAND && (abs(para)!=2 || result_path_dist%2));
1933 			if(para)
1934 			{
1935 				#ifdef DEBUG
1936 					int count=0, ii;
1937 					int dist;
1938 					int curXLoc = next_x_loc();
1939 					int curYLoc = next_y_loc();
1940 					ResultNode *curNode = result_node_array + result_node_recno -1;
1941 					ResultNode *nextNode;
1942 
1943 					dist = misc.points_distance(curXLoc, curYLoc, curNode->node_x, curNode->node_y);
1944 					if(result_node_recno>1)
1945 						count += dist;
1946 					else
1947 						count -= dist;
1948 
1949 					for(ii=result_node_recno, nextNode=curNode+1; ii<result_node_count; ii++, curNode++, nextNode++)
1950 					{
1951 						dist = misc.points_distance(nextNode->node_x, nextNode->node_y, curNode->node_x, curNode->node_y);
1952 						count += dist;
1953 					}
1954 
1955 					err_when(result_path_dist!=count);
1956 				#endif
1957 
1958 				//----------------------------------------------------------------------------//
1959 				// calculate the result_path_dist as the unit move from one tile to another
1960 				//----------------------------------------------------------------------------//
1961 				result_path_dist += para;
1962 			}
1963 
1964 			next_x = newNextX;
1965          next_y = newNextY;
1966 
1967 			swapping = blocked_by_member = 0;
1968 
1969 			//---- move sprite_recno to the next location ------//
1970 
1971 			for(h=0, y=curNextYLoc; h<sprite_info->loc_height; h++, y++)
1972 			{
1973 				for(w=0, x=curNextXLoc; w<sprite_info->loc_width; w++, x++)
1974 					world.set_unit_recno(x, y, mobile_type, 0);
1975 			}
1976 
1977 			for(h=0, y=next_y_loc(); h<sprite_info->loc_height; h++, y++)
1978 			{
1979 				for(w=0, x=next_x_loc(); w<sprite_info->loc_width; w++, x++)
1980 					world.set_unit_recno(x, y, mobile_type, sprite_recno);
1981 			}
1982 
1983 			//--------- explore land ----------//
1984 
1985 			// ###### begin Gilbert 24/5 ######//
1986 			if( !config.explore_whole_map && is_own() )
1987 			// ###### end Gilbert 24/5 ######//
1988 			{
1989 				int xLoc1 = MAX(0,newNextXLoc-EXPLORE_RANGE);
1990 				int yLoc1 = MAX(0,newNextYLoc-EXPLORE_RANGE);
1991 				int xLoc2 = MIN(MAX_WORLD_X_LOC-1, newNextXLoc+EXPLORE_RANGE);
1992 				int yLoc2 = MIN(MAX_WORLD_Y_LOC-1, newNextYLoc+EXPLORE_RANGE);
1993 				int exploreWidth = move_step_magn()-1;
1994 
1995 				if( newNextYLoc < curNextYLoc )			// if move upwards, explore upper area
1996 					world.explore(xLoc1, yLoc1, xLoc2, yLoc1+exploreWidth);
1997 
1998 				else if( newNextYLoc > curNextYLoc )	// if move downwards, explore lower area
1999 					world.explore(xLoc1, yLoc2-exploreWidth, xLoc2, yLoc2);
2000 
2001 				if( newNextXLoc < curNextXLoc )        // if move towards left, explore left area
2002 					world.explore(xLoc1, yLoc1, xLoc1+exploreWidth, yLoc2);
2003 
2004 				else if( newNextXLoc > curNextXLoc )   // if move towards right, explore right area
2005 					world.explore(xLoc2-exploreWidth, yLoc1, xLoc2, yLoc2);
2006 			}
2007 		}
2008 	}
2009 
2010 	err_when(cur_x!=next_x && cur_y!=next_y &&	// is not blocked
2011 				(check_unit_dir1=get_dir(cur_x, cur_y, next_x, next_y))!=(check_unit_dir2=get_dir(cur_x, cur_y, go_x, go_y)));
2012 }
2013 //---------- End of function Unit::set_next ----------//
2014 
2015 
2016 //------ Begin of function Unit::blocked_move_new_handle -------//
2017 /*int Unit::blocked_move_new_handle()
2018 {
2019 	//------------------------------------------------------------------//
2020 	// new handling for blocked move
2021 	//------------------------------------------------------------------//
2022 	static int counter = 0;
2023 	int checkXLoc1, checkYLoc1, checkXLoc2, checkYLoc2;
2024 	int curXLoc = next_x_loc(), curYLoc = next_y_loc();
2025 	Location *locPtr;
2026 
2027 	counter++;
2028 	switch(final_dir)
2029 	{
2030 		case DIR_N:
2031 				checkXLoc1 = MIN(curXLoc+1, MAX_WORLD_X_LOC-1);
2032 				checkYLoc1 = checkYLoc2 = MAX(curYLoc-1, 0);
2033 				checkXLoc2 = MAX(curXLoc-1, 0);
2034 				break;
2035 
2036 		case DIR_NE:
2037 				checkXLoc1 = MIN(curXLoc+1, MAX_WORLD_X_LOC-1);
2038 				checkYLoc1 = curYLoc;
2039 				checkXLoc2 = curXLoc;
2040 				checkYLoc2 = MAX(curYLoc-1, 0);
2041 				break;
2042 
2043 		case DIR_E:
2044 				checkXLoc1 = checkXLoc2 = MIN(curXLoc+1, MAX_WORLD_X_LOC-1);
2045 				checkYLoc1 = MIN(curYLoc+1, MAX_WORLD_Y_LOC-1);
2046 				checkYLoc2 = MAX(curYLoc-1, 0);
2047 				break;
2048 
2049 		case DIR_SE:
2050 				checkXLoc1 = curXLoc;
2051 				checkYLoc1 = MIN(curYLoc+1, MAX_WORLD_Y_LOC-1);
2052 				checkXLoc2 = MIN(curXLoc+1, MAX_WORLD_X_LOC-1);
2053 				checkYLoc2 = curYLoc;
2054 				break;
2055 
2056 		case DIR_S:
2057 				checkXLoc1 = MAX(curXLoc-1, 0);
2058 				checkYLoc1 = checkYLoc2 = MIN(curYLoc+1, MAX_WORLD_Y_LOC-1);
2059 				checkXLoc2 = MIN(curXLoc+1, MAX_WORLD_X_LOC-1);
2060 				break;
2061 
2062 		case DIR_SW:
2063 				checkXLoc1 = MAX(curXLoc-1, 0);
2064 				checkYLoc1 = curYLoc;
2065 				checkXLoc2 = curXLoc;
2066 				checkYLoc2 = MIN(curYLoc, MAX_WORLD_Y_LOC-1);
2067 				break;
2068 
2069 		case DIR_W:
2070 				checkXLoc1 = checkXLoc2 = MAX(curXLoc-1, 0);
2071 				checkYLoc1 = MAX(curYLoc-1, 0);
2072 				checkYLoc2 = MIN(curYLoc+1, MAX_WORLD_Y_LOC-1);
2073 				break;
2074 
2075 		case DIR_NW:
2076 				checkXLoc1 = curXLoc;
2077 				checkYLoc1 = MAX(curYLoc-1, 0);
2078 				checkXLoc2 = MAX(curXLoc-1, 0);
2079 				checkYLoc2 = curYLoc;
2080 				break;
2081 	}
2082 
2083 	locPtr = world.get_loc(checkXLoc1, checkYLoc1);
2084 	if(locPtr->can_move(mobile_type))
2085 		set_path_to(checkXLoc1, checkYLoc1);
2086 	else
2087 	{
2088 		locPtr = world.get_loc(checkXLoc2, checkYLoc2);
2089 		if(locPtr->can_move(mobile_type))
2090 			set_path_to(checkXLoc2, checkYLoc2);
2091 		else
2092 			return 0;
2093 	}
2094 
2095 	return 1;
2096 }*/
2097 //------- End of function Unit::blocked_move_new_handle --------//
2098 
2099 
2100 //------ Begin of function Unit::set_path_to -------//
2101 /*void Unit::set_path_to(int destXLoc, int destYLoc)
2102 {
2103 	//reset_path();
2104 	terminate_move();
2105 	result_node_array = (ResultNode*) mem_add(2*sizeof(ResultNode));
2106 	ResultNode *curNodePtr = result_node_array;
2107 	curNodePtr->node_x = next_x_loc();
2108 	curNodePtr->node_y = next_y_loc();
2109 	curNodePtr++;
2110 	curNodePtr->node_x = destXLoc;
2111 	curNodePtr->node_y = destYLoc;
2112 
2113 	result_node_count = 2;
2114 	result_node_recno = 1;
2115 	result_path_dist = 1;
2116 	move_to_x_loc = destXLoc;
2117 	move_to_y_loc = destYLoc;
2118 	go_x = destXLoc*ZOOM_LOC_WIDTH;
2119 	go_y = destYLoc*ZOOM_LOC_HEIGHT;
2120 
2121 	//set_dir(cur_x, cur_y, go_x, go_y);
2122 	//set_wait();
2123 	next_move();
2124 }*/
2125 //------- End of function Unit::set_path_to --------//
2126 
2127 
2128 //------ Begin of function Unit::handle_blocked_move -------//
2129 // Note: it assumes the given location is blocked, it makes no
2130 //       further attempt to verify it.
2131 //
2132 // <Location*>	blockedLoc	-	blocked location
2133 //
2134 // return : <int> 1 - handled successfully
2135 //                0 - cannot be handled, the movement must be terminated
2136 //
handle_blocked_move(Location * blockedLoc)2137 void Unit::handle_blocked_move(Location* blockedLoc)
2138 {
2139 	//--- check if the tile we are moving at is blocked by a building ---//
2140 	if(blockedLoc->is_firm() || blockedLoc->is_town() || blockedLoc->is_wall())
2141    {
2142 		//------------------------------------------------//
2143 		// firm/town/wall is on the blocked location
2144 		//------------------------------------------------//
2145 		reset_path();
2146 		search_or_stop(move_to_x_loc, move_to_y_loc, 1);
2147 		//search(move_to_x_loc, move_to_y_loc, 1);
2148       return;
2149    }
2150 
2151 	if(next_x_loc()==move_to_x_loc && next_y_loc()==move_to_y_loc && !swapping)
2152 	{
2153 		terminate_move(); // terminate since already reaching destination
2154 		return;
2155 	}
2156 
2157 	if(!blockedLoc->is_accessible(mobile_type))
2158 	{
2159 		terminate_move();  // the location is not accessible
2160 		err_when(cur_x==go_x && cur_y==go_y && (cur_x!=next_x || cur_y!=next_y));
2161 		return;
2162 	}
2163 
2164 	//-----------------------------------------------------------------------------------//
2165 	// there is another sprite on the move_to location, check the combination of both sizes
2166 	//-----------------------------------------------------------------------------------//
2167 	blocked_by_member = 1;
2168 	err_when(!blockedLoc->unit_recno(mobile_type));
2169 
2170 	Unit* unitPtr = unit_array[blockedLoc->unit_recno(mobile_type)];
2171 	//if(unitPtr->sprite_info->loc_width>1 || sprite_info->loc_width>1)
2172 	//{
2173 	//	set_wait();
2174 	//	return;
2175 	//}
2176 	//else
2177 	handle_blocked_move_s11(unitPtr); //------ both units size 1x1
2178 
2179 	err_when(cur_x==go_x && cur_y==go_y && (cur_x!=next_x || cur_y!=next_y));
2180 	return;
2181 }
2182 //------- End of function Unit::handle_blocked_move --------//
2183 
2184 
2185 //------ Begin of function Unit::handle_blocked_by_idle_unit ---------//
2186 // handle the case blocked by idle unit
2187 //
2188 // <Unit*>	unitPtr -	the unit blocking this unit
2189 //
handle_blocked_by_idle_unit(Unit * unitPtr)2190 void Unit::handle_blocked_by_idle_unit(Unit *unitPtr)
2191 {
2192 	#define TEST_DIMENSION	10
2193 	#define TEST_LIMIT		TEST_DIMENSION*TEST_DIMENSION
2194 
2195 	char notLandUnit = (mobile_type!=UNIT_LAND);
2196 	int unitXLoc = unitPtr->next_x_loc();
2197 	int unitYLoc = unitPtr->next_y_loc();
2198 	int xShift, yShift;
2199 	int checkXLoc, checkYLoc;
2200 	Location *locPtr;
2201 
2202 	int xSign = misc.random(2) ? 1 : -1;
2203 	int ySign = misc.random(2) ? 1 : -1;
2204 
2205 	for(int i=2; i<=TEST_LIMIT; i++)
2206 	{
2207 		misc.cal_move_around_a_point(i, TEST_DIMENSION, TEST_DIMENSION, xShift, yShift);
2208 		xShift *= xSign;
2209 		yShift *= ySign;
2210 
2211 		if(notLandUnit)
2212 		{
2213 			checkXLoc = unitXLoc + xShift*2;
2214 			checkYLoc = unitYLoc + yShift*2;
2215 		}
2216 		else
2217 		{
2218 			checkXLoc = unitXLoc + xShift;
2219 			checkYLoc = unitYLoc + yShift;
2220 		}
2221 
2222 		if(checkXLoc<0 || checkXLoc>=MAX_WORLD_X_LOC || checkYLoc<0 || checkYLoc>=MAX_WORLD_Y_LOC)
2223 			continue;
2224 
2225 		locPtr = world.get_loc(checkXLoc , checkYLoc);
2226 		if(!locPtr->can_move(unitPtr->mobile_type))
2227 			continue;
2228 
2229 		if(on_my_path(checkXLoc, checkYLoc))
2230 			continue;
2231 
2232 		unitPtr->move_to(checkXLoc, checkYLoc);
2233 		set_wait();
2234 		return;
2235 	}
2236 
2237 	stop(KEEP_DEFENSE_MODE);
2238 
2239 	//--------------------------------------------------------------------------------//
2240 	// improved version!!!
2241 	//--------------------------------------------------------------------------------//
2242 	/*int testResult = 0, worstCase=0;
2243 	int worstXLoc=-1, worstYLoc=-1;
2244 	int startCount, endCount;
2245 	int i, j;
2246 
2247 	for(j=0; j<2; j++)
2248 	{
2249 		//----------- set the startCount and endCount ------------//
2250 		if(j==0)
2251 		{
2252 			startCount = 2;
2253 			endCount = 9;
2254 		}
2255 		else
2256 		{
2257 			startCount = 10;
2258 			endCount = TEST_LIMIT;
2259 		}
2260 
2261 		for(i=startCount; i<=endCount; i++)
2262 		{
2263 			misc.cal_move_around_a_point(i, TEST_DIMENSION, TEST_DIMENSION, xShift, yShift);
2264 			if(notLandUnit)
2265 			{
2266 				checkXLoc = unitXLoc + xShift*2;
2267 				checkYLoc = unitYLoc + yShift*2;
2268 			}
2269 			else
2270 			{
2271 				checkXLoc = unitXLoc + xShift;
2272 				checkYLoc = unitYLoc + yShift;
2273 			}
2274 
2275 			if(checkXLoc<0 || checkXLoc>=MAX_WORLD_X_LOC || checkYLoc<0 || checkYLoc>=MAX_WORLD_Y_LOC)
2276 				continue;
2277 
2278 			locPtr = world.get_loc(checkXLoc , checkYLoc);
2279 			if(!locPtr->can_move(unitPtr->mobile_type))
2280 				continue;
2281 
2282 			//-------------------------------------------------------------------//
2283 			// a possible location
2284 			//-------------------------------------------------------------------//
2285 			testResult = on_my_path(checkXLoc, checkYLoc);
2286 			if(testResult)
2287 			{
2288 				if(j==0 && !worstCase)
2289 				{
2290 					worstCase++;
2291 					worstXLoc = checkXLoc;
2292 					worstYLoc = checkYLoc;
2293 				}
2294 				continue;
2295 			}
2296 
2297 			unitPtr->move_to(checkXLoc, checkYLoc):
2298 			set_wait();
2299 			return;
2300 		}
2301 	}
2302 
2303 	//-------------------------------------------------------------------//
2304 	if(worstCase)
2305 	{
2306 		unitPtr->move_to(worstXLoc, worstYLoc);
2307 		set_wait();
2308 	}
2309 	else
2310 		stop(KEEP_DEFENSE_MODE);*/
2311 }
2312 //------- End of function Unit::handle_blocked_by_idle_unit --------//
2313 
2314 
2315 //------ Begin of function Unit::on_my_path ---------//
2316 // This function is used to check whether a location
2317 // (checkXLoc, checkYLoc) is on the unit path, result_node_array.
2318 //
2319 // return 1 if true
2320 // return 0 otherwise
2321 //
on_my_path(short checkXLoc,short checkYLoc)2322 int Unit::on_my_path(short checkXLoc, short checkYLoc)
2323 {
2324 	err_when(result_node_count<2);
2325 	ResultNode* curNodePtr = result_node_array+result_node_recno-2;
2326 	ResultNode* nextNodePtr = curNodePtr+1;
2327 
2328 	for(int i=result_node_recno-1; i<result_node_count; i++, curNodePtr++, nextNodePtr++)
2329 	{
2330 		if((curNodePtr->node_x-checkXLoc)*(checkYLoc-nextNodePtr->node_y)==
2331 			(curNodePtr->node_y-checkYLoc)*(checkXLoc-nextNodePtr->node_x)) // point of division
2332 			return 1;
2333 	}
2334 
2335 	return 0;
2336 }
2337 //------- End of function Unit::on_my_path --------//
2338 
2339 
2340 //------ Begin of function Unit::handle_blocked_wait ---------//
2341 //
2342 //	this function is worked for unit size 1x1 only to handle case that
2343 // blocked by waiting unit
2344 //
2345 // <Unit*>	unitPtr	-	unit blocking this unit
2346 //
handle_blocked_wait(Unit * unitPtr)2347 void Unit::handle_blocked_wait(Unit* unitPtr)
2348 {
2349 	err_when(sprite_info->loc_width>1 || unitPtr->sprite_info->loc_width>1);
2350 
2351 	int			stepMagn = move_step_magn();
2352 	short			cycleWait = 0;
2353 	Location		*locPtr;
2354 
2355 	if(is_dir_correct())
2356 	{
2357 		Unit			*blockedUnitPtr = unitPtr;
2358 		SpriteInfo	*unitSpriteInfo = unitPtr->sprite_info;
2359 		int			nextX, nextY, loop = 0, i;
2360 		short			blocked=0;
2361 
2362 		//---------------------------------------------------------------//
2363 		// construct a cycle_waiting array to store the sprite_recno of
2364 		// those units in cycle_waiting in order to prevent forever looping
2365 		// in the checking
2366 		//---------------------------------------------------------------//
2367 		int arraySize = 20;
2368 		cycle_wait_unit_array_def_size = arraySize;
2369 		cycle_wait_unit_index = 0;
2370 		cycle_wait_unit_array_multipler = 1;
2371 		cycle_wait_unit_array = (short*)mem_add(sizeof(short)*cycle_wait_unit_array_def_size);
2372 		memset(cycle_wait_unit_array, 0, sizeof(short)*cycle_wait_unit_array_def_size);
2373 
2374 		//---------------------------------------------------------------//
2375 		// don't handle the case blocked by size 2x2 unit in this moment
2376 		//---------------------------------------------------------------//
2377 		while(!cycleWait && blockedUnitPtr->cur_action==SPRITE_WAIT)
2378 		{
2379 			if(unitSpriteInfo->loc_width>1)
2380 				break; // don't handle unit size > 1
2381 
2382 			if(!blockedUnitPtr->is_dir_correct())
2383 				break;
2384 
2385 			//----------------------------------------------------------------------------------------//
2386 			// cur_x, cur_y of unit pointed by blockedUnitPtr should be exactly inside a tile
2387 			//----------------------------------------------------------------------------------------//
2388 			nextX = blockedUnitPtr->cur_x+stepMagn*move_x_pixel_array[blockedUnitPtr->final_dir];
2389 			nextY = blockedUnitPtr->cur_y+stepMagn*move_y_pixel_array[blockedUnitPtr->final_dir];
2390 
2391 			//---------- calculate location blocked unit attempts to move to ---------//
2392 			nextX >>= ZOOM_X_SHIFT_COUNT;
2393 			nextY >>= ZOOM_Y_SHIFT_COUNT;
2394 
2395 			locPtr = world.get_loc(nextX, nextY);
2396 			blocked = locPtr->has_unit(mobile_type);
2397 
2398 			//---------------- the unit is also waiting ---------------//
2399 			if(blocked && (blockedUnitPtr->move_to_x_loc!=blockedUnitPtr->cur_x_loc() ||
2400 				blockedUnitPtr->move_to_y_loc!=blockedUnitPtr->cur_y_loc()))
2401 			{
2402 				if(locPtr->unit_recno(mobile_type) == sprite_recno)
2403 					cycleWait = 1;
2404 				else
2405 				{
2406 					for(i=0; i<cycle_wait_unit_index; i++)
2407 					{
2408 						//---------- checking for forever loop ----------------//
2409 						if(cycle_wait_unit_array[i] == blockedUnitPtr->sprite_recno)
2410 						{
2411 							loop = 1;
2412 							break;
2413 						}
2414 					}
2415 
2416 					if(loop)
2417 						break;
2418 
2419 					//------------------------------------------------------//
2420 					// resize array if required size is larger than arraySize
2421 					//------------------------------------------------------//
2422 					if(cycle_wait_unit_index >= arraySize)
2423 					{
2424 						cycle_wait_unit_array_multipler++;
2425 						arraySize = cycle_wait_unit_array_def_size*cycle_wait_unit_array_multipler;
2426 						cycle_wait_unit_array = (short*) mem_resize(cycle_wait_unit_array, sizeof(short)*arraySize);
2427 					}
2428 					else
2429 					{
2430 						//-------- store recno of next blocked unit ----------//
2431 						cycle_wait_unit_array[cycle_wait_unit_index++] = blockedUnitPtr->sprite_recno;
2432 						locPtr = world.get_loc(nextX, nextY);
2433 						err_when(blockedUnitPtr->mobile_type!=mobile_type);
2434 						blockedUnitPtr = unit_array[locPtr->unit_recno(mobile_type)];
2435 						unitSpriteInfo = blockedUnitPtr->sprite_info;
2436 					}
2437 				}
2438 			}
2439 			else
2440 				break;
2441 		}
2442 
2443 		//---------- deinit data structure -------//
2444 		mem_del(cycle_wait_unit_array);
2445 		cycle_wait_unit_array = NULL;
2446 	}
2447 
2448 	if(cycleWait)
2449 	{
2450 		//----------------------------------------------------------------------//
2451 		// shift the recno of all the unit in the cycle
2452 		//----------------------------------------------------------------------//
2453 		err_when(!is_dir_correct());
2454 
2455 		short backupSpriteRecno;
2456 		world.set_unit_recno(cur_x_loc(), cur_y_loc(), mobile_type, 0); // empty the firt node in the cycle
2457 		cycle_wait_shift_recno(this, unitPtr);	// shift all the unit in the cycle
2458 		backupSpriteRecno = world.get_unit_recno(cur_x_loc(), cur_y_loc(), mobile_type);
2459 		world.set_unit_recno(cur_x_loc(), cur_y_loc(), mobile_type, sprite_recno);
2460 		set_next(unitPtr->cur_x, unitPtr->cur_y, -stepMagn, 1);
2461 		set_move();
2462 		world.set_unit_recno(unitPtr->cur_x_loc(), unitPtr->cur_y_loc(), mobile_type, sprite_recno);
2463 		world.set_unit_recno(cur_x_loc(), cur_y_loc(), mobile_type, backupSpriteRecno);
2464 		swapping = 1;
2465 	}
2466 	else // not in a cycle
2467 	{
2468 		set_wait();
2469 
2470 		//if(waiting_term>=MAX_WAITING_TERM_SAME)
2471 		if(waiting_term>=MAX_WAITING_TERM_SAME*move_step_magn())
2472 		{
2473 			//-----------------------------------------------------------------//
2474 			// codes used to speed up frame rate
2475 			//-----------------------------------------------------------------//
2476 			locPtr = world.get_loc(move_to_x_loc, move_to_y_loc);
2477 			if(!locPtr->can_move(mobile_type) && action_mode2!=ACTION_MOVE)
2478 				stop(KEEP_PRESERVE_ACTION); // let reactivate..() call searching later
2479 			else
2480 				search_or_wait();
2481 
2482 			waiting_term = 0;
2483 		}
2484 	}
2485 }
2486 //-------- End of function Unit::handle_blocked_wait ---------//
2487 
2488 
2489 //------ Begin of function Unit::cycle_wait_shift_recno ---------//
2490 // copy recno of curUnit to location where nextUnit on
2491 //
2492 // <Unit*> curUnit	-
2493 // <Unit*> nextUnit	-
2494 //
cycle_wait_shift_recno(Unit * curUnit,Unit * nextUnit)2495 void Unit::cycle_wait_shift_recno(Unit* curUnit, Unit* nextUnit)
2496 {
2497 	err_when(!curUnit->is_dir_correct() || !nextUnit->is_dir_correct());
2498 
2499 	int			stepMagn = move_step_magn();
2500 	Unit			*blockedUnitPtr;
2501 	Location		*locPtr;
2502 
2503 	//----------- find the next location ------------//
2504 	int nextX = nextUnit->cur_x+stepMagn*move_x_pixel_array[nextUnit->final_dir];
2505 	int nextY = nextUnit->cur_y+stepMagn*move_y_pixel_array[nextUnit->final_dir];
2506 
2507 	nextX >>= ZOOM_X_SHIFT_COUNT;
2508 	nextY >>= ZOOM_Y_SHIFT_COUNT;
2509 
2510 	if(nextX != cur_x_loc() || nextY != cur_y_loc())
2511 	{
2512 		locPtr = world.get_loc(nextX, nextY);
2513 		blockedUnitPtr = unit_array[locPtr->unit_recno(nextUnit->mobile_type)];
2514 	}
2515 	else
2516 		blockedUnitPtr = this;
2517 
2518 	err_when(!blockedUnitPtr);
2519 
2520 	if(blockedUnitPtr != this)
2521 	{
2522 		cycle_wait_shift_recno(nextUnit, blockedUnitPtr);
2523 		nextUnit->set_next(blockedUnitPtr->cur_x, blockedUnitPtr->cur_y, -stepMagn, 1);
2524 		nextUnit->set_move();
2525 		world.set_unit_recno(blockedUnitPtr->cur_x_loc(), blockedUnitPtr->cur_y_loc(), nextUnit->mobile_type, nextUnit->sprite_recno);
2526 		world.set_unit_recno(nextUnit->cur_x_loc(), nextUnit->cur_y_loc(), nextUnit->mobile_type, 0);
2527 		nextUnit->swapping = 1;
2528 	}
2529 	else // the cycle shift is ended
2530 	{
2531 		err_when(blockedUnitPtr != this);
2532 		err_when(nextUnit->cur_x!=nextUnit->next_x || nextUnit->cur_y!=nextUnit->next_y);
2533 		err_when(nextUnit->cur_action != SPRITE_WAIT);
2534 
2535 		nextUnit->set_next(cur_x, cur_y, -stepMagn, 1);
2536 		nextUnit->set_move();
2537 		world.set_unit_recno(cur_x_loc(), cur_y_loc(), nextUnit->mobile_type, nextUnit->sprite_recno);
2538 		world.set_unit_recno(nextUnit->cur_x_loc(), nextUnit->cur_y_loc(), nextUnit->mobile_type, 0);
2539 
2540 		nextUnit->swapping = 1;
2541 	}
2542 }
2543 //-------- End of function Unit::cycle_wait_shift_recno ---------//
2544 
2545 
2546 //------ Begin of function Unit::opposite_direction_blocked ---------//
2547 // the two units are oppositely blocked, handle swapping
2548 //
opposite_direction_blocked(short vecX,short vecY,short unitPtrVecX,short unitPtrVecY,Unit * unitPtr)2549 void Unit::opposite_direction_blocked(short vecX, short vecY, short unitPtrVecX, short unitPtrVecY, Unit* unitPtr)
2550 {
2551 	//---------------------------------------------------------------------------//
2552 	// processing swapping only when both units are exactly in the tiles
2553 	//---------------------------------------------------------------------------//
2554 	if(unitPtr->cur_action!=SPRITE_IDLE)
2555 	{
2556 		if(unitPtr->move_to_x_loc!=move_to_x_loc || unitPtr->move_to_y_loc!=move_to_y_loc)
2557 		{
2558 			int stepMagn = move_step_magn();
2559 
2560 			world.set_unit_recno(unitPtr->cur_x_loc(), unitPtr->cur_y_loc(), mobile_type, 0);
2561 			err_when(!is_dir_correct());
2562 			set_next(unitPtr->cur_x, unitPtr->cur_y, -stepMagn, -1);
2563 
2564 			world.set_unit_recno(unitPtr->cur_x_loc(), unitPtr->cur_y_loc(), mobile_type, unitPtr->sprite_recno);
2565 			world.set_unit_recno(cur_x_loc(), cur_y_loc(), unitPtr->mobile_type, 0);
2566 			err_when(!unitPtr->is_dir_correct());
2567 			unitPtr->set_next(cur_x, cur_y, -stepMagn, 1);
2568 
2569 			world.set_unit_recno(unitPtr->cur_x_loc(), unitPtr->cur_y_loc(), mobile_type, sprite_recno);
2570 			world.set_unit_recno(cur_x_loc(), cur_y_loc(), unitPtr->mobile_type, unitPtr->sprite_recno);
2571 
2572 			set_move();
2573 			unitPtr->set_move();
2574 
2575 			swapping = 1;
2576 			unitPtr->swapping = 1;
2577 
2578 		#ifdef DEBUG
2579 			ResultNode* curNode;
2580 			curNode = result_node_array + result_node_count - 1;
2581 			err_when(curNode->node_x!=move_to_x_loc || curNode->node_y!=move_to_y_loc);
2582 			curNode = unitPtr->result_node_array + unitPtr->result_node_count - 1;
2583 			err_when(curNode->node_x!=unitPtr->move_to_x_loc || curNode->node_y!=unitPtr->move_to_y_loc);
2584 		#endif
2585 		}
2586 		else
2587 			terminate_move();
2588 	}
2589 	else
2590 	{
2591 		//----------------------------------------------------------------------//
2592 		// If the unit pointed by unitPtr (unit B) has the same unit_id, rank_id
2593 		//	and both	are in the same group, this unit will order the other unit to
2594 		// move to its location and this unit will occupy the location of the unit B.
2595 		//
2596 		// If the above condition is not fulfilled, swapping is processed.
2597 		//----------------------------------------------------------------------//
2598 		if(unit_id!=unitPtr->unit_id || rank_id!=unitPtr->rank_id || unit_group_id!=unitPtr->unit_group_id)
2599 		{
2600 			if(unitPtr->move_to_x_loc!=move_to_x_loc || unitPtr->move_to_y_loc!=move_to_y_loc)
2601 			{
2602 				//----------------- process swapping ---------------//
2603 				set_wait();
2604 				unitPtr->set_dir(unitPtr->next_x, unitPtr->next_y, next_x, next_y);
2605 				set_dir(next_x, next_y, unitPtr->next_x, unitPtr->next_y);
2606 
2607 				err_when(unitPtr->result_node_array!=NULL);
2608 
2609 				unitPtr->result_node_array = (ResultNode*)mem_add(sizeof(ResultNode)*2);
2610 				ResultNode* nodePtr = unitPtr->result_node_array;
2611 
2612 				err_when(next_x_loc()!= cur_x_loc() || next_y_loc()!=cur_y_loc());
2613 				nodePtr->node_x = next_x_loc();
2614 				nodePtr->node_y = next_y_loc();
2615 				nodePtr++;
2616 				nodePtr->node_x = unitPtr->next_x_loc();
2617 				nodePtr->node_y = unitPtr->next_y_loc();
2618 				unitPtr->result_node_count = 2;
2619 				unitPtr->result_node_recno = 1;
2620 
2621 				unitPtr->set_wait();
2622 				unitPtr->go_x = next_x;
2623 				unitPtr->go_y = next_y;
2624 
2625 				unitPtr->result_path_dist = 2;
2626 
2627 				err_when((check_unit_dir1=get_dir(cur_x, cur_y, go_x, go_y))!=final_dir);
2628 				swapping = 1;
2629 				unitPtr->swapping = 1;
2630 			}
2631 			else
2632 				terminate_move();
2633 		}
2634 		else
2635 		{
2636 			//------------ process move_to_my_loc or terminate the movement -----------//
2637 			if(unitPtr->move_to_x_loc!=move_to_x_loc || unitPtr->move_to_y_loc!=move_to_y_loc)
2638 				move_to_my_loc(unitPtr);
2639 			else
2640 				terminate_move();
2641 		}
2642 
2643 		#ifdef DEBUG
2644 			ResultNode* curNode;
2645 			if(result_node_array!=NULL)
2646 			{
2647 				curNode = result_node_array + result_node_count - 1;
2648 				err_when(curNode->node_x!=move_to_x_loc || curNode->node_y!=move_to_y_loc);
2649 			}
2650 			if(unitPtr->result_node_array!=NULL)
2651 			{
2652 				curNode = unitPtr->result_node_array + unitPtr->result_node_count - 1;
2653 				err_when(curNode->node_x!=unitPtr->move_to_x_loc || curNode->node_y!=unitPtr->move_to_y_loc);
2654 			}
2655 		#endif
2656 	}
2657 }
2658 //-------- End of function Unit::opposite_direction_blocked ---------//
2659 
2660 
2661 //------ Begin of function Unit::terminate_move -------//
2662 //
2663 // When the sprite has finished moving the next tile in
2664 // the path. If the following tile is blocked and the whole
2665 // movement need to be terminated, this function is called.
2666 //
2667 // When SPRITE_IDLE:
2668 //
2669 // (next_x, next_y) must be == (cur_x, cur_y), it's the location of the sprite.
2670 //
terminate_move()2671 void Unit::terminate_move()
2672 {
2673 	#ifdef DEBUG
2674 		err_when( next_x != cur_x || next_y != cur_y );
2675 		short h, y;
2676 		for(h=0, y=cur_y_loc(); h<sprite_info->loc_height; h++, y++)
2677 			for(short w=0, x=cur_x_loc(); w<sprite_info->loc_width; w++, x++)
2678 				err_when( world.get_unit_recno(x, y, mobile_type) != sprite_recno );
2679 	#endif
2680 
2681    go_x = next_x;
2682    go_y = next_y;
2683 
2684 	move_to_x_loc = next_x_loc();
2685 	move_to_y_loc = next_y_loc();
2686 
2687 	#ifdef DEBUG
2688 		char blocked=0;
2689 		for(h=0, y=next_y_loc(); h<sprite_info->loc_height&&!blocked; h++, y++)
2690 			for(short		w=0, x=next_x_loc(); w<sprite_info->loc_width&&!blocked; w++, x++)
2691 				blocked = world.get_unit_recno(x,y,mobile_type) != sprite_recno;
2692 		err_when(blocked);
2693 	#endif
2694 
2695 	cur_frame  = 1;
2696 
2697    reset_path();
2698 	set_idle();
2699 
2700 	err_when(result_node_array!=NULL);
2701 }
2702 //------- End of function Unit::terminate_move --------//
2703 
2704 
2705 //------------- Begin of function Unit::move_to_my_loc --------------//
2706 //
2707 // This function is used as this unit Unit A is blocked by another
2708 // IDLE unit Unit B. Then Unit A will move to the location of Unit B
2709 // and Unit B will move to the location of Unit A want to move to.
2710 //
2711 // Note: action_?_loc2 of both units can be different from their
2712 //			move_to_?_loc
2713 //
move_to_my_loc(Unit * unitPtr)2714 void Unit::move_to_my_loc(Unit* unitPtr)
2715 {
2716 	int unitDestX, unitDestY;
2717 	if(unitPtr->action_mode2==ACTION_MOVE)
2718 	{
2719 		unitDestX = unitPtr->action_x_loc2;
2720 		unitDestY = unitPtr->action_y_loc2;
2721 		err_when(unitDestX==-1 || unitDestY==-1);
2722 	}
2723 	else
2724 	{
2725 		unitDestX = unitPtr->move_to_x_loc;
2726 		unitDestY = unitPtr->move_to_y_loc;
2727 	}
2728 
2729 	//--------------- init parameters ---------------//
2730 	int unitCurX = unitPtr->next_x_loc();
2731 	int unitCurY = unitPtr->next_y_loc();
2732 	int destX = action_x_loc2;
2733 	int destY = action_y_loc2;
2734 	int curX = next_x_loc();
2735 	int curY = next_y_loc();
2736 	int moveScale = move_step_magn();
2737 	err_when(curX != cur_x_loc() || curY != cur_y_loc());
2738 	err_when(mobile_type!=unitPtr->mobile_type);
2739 
2740 	//------------------------------------------------------------------//
2741 	// setting for unit pointed by unitPtr
2742 	//------------------------------------------------------------------//
2743 	if(result_node_array==NULL)	//************BUGHERE
2744 	{
2745 		err_when(unitPtr->cur_action!=SPRITE_IDLE);
2746 		unitPtr->move_to(destX, destY, 1); // unit pointed by unitPtr is idle before calling searching
2747 		err_when(unitPtr->cur_action!=SPRITE_DIE && unitPtr->action_mode2!=ACTION_MOVE);
2748 	}
2749 	else
2750 	{
2751 		err_when(result_node_recno<1 || unitPtr->result_node_array!=NULL);
2752 		ResultNode* resultNode = result_node_array+result_node_recno-1;
2753 		if(go_x == unitPtr->next_x && go_y == unitPtr->next_y)
2754 		{
2755 			//------ Unit B is in one of the node of the result_node_array ---//
2756 			unitPtr->result_node_count = result_node_count-result_node_recno+1;	// at least there are 2 nodes
2757 			unitPtr->result_node_array = (ResultNode*)mem_add(sizeof(ResultNode)*(unitPtr->result_node_count));
2758 			memcpy(unitPtr->result_node_array, resultNode, sizeof(ResultNode)*(unitPtr->result_node_count));
2759 		}
2760 		else
2761 		{
2762 			//----- Unit B is in the middle of two nodes in the result_node_array -----//
2763 			unitPtr->result_node_count = result_node_count-result_node_recno+2;
2764 			unitPtr->result_node_array = (ResultNode*)mem_add(sizeof(ResultNode)*(unitPtr->result_node_count));
2765 			ResultNode* curNode = unitPtr->result_node_array;
2766 			curNode->node_x = unitCurX;
2767 			curNode->node_y = unitCurY;
2768 			curNode++;
2769 			memcpy(curNode, resultNode, sizeof(ResultNode)*(unitPtr->result_node_count-1));
2770 		}
2771 		err_when(unitPtr->result_node_count<2);
2772 
2773 		//--------------- set unit action ---------------//
2774 		if(unitPtr->action_mode2==ACTION_STOP || unitPtr->action_mode2==ACTION_MOVE) // unitPtr is idle now
2775 		{
2776 			//---------- activate unit pointed by unitPtr now ------------//
2777 			unitPtr->action_mode	 = unitPtr->action_mode2 = ACTION_MOVE;
2778 			unitPtr->action_para  = unitPtr->action_para2 = 0;
2779 			if(destX!=-1 && destY!=-1)
2780 			{
2781 				unitPtr->action_x_loc = unitPtr->action_x_loc2 = destX;
2782 				unitPtr->action_y_loc = unitPtr->action_y_loc2 = destY;
2783 			}
2784 			else
2785 			{
2786 				ResultNode *lastNodePtr = unitPtr->result_node_array + unitPtr->result_node_count - 1;
2787 				unitPtr->action_x_loc = unitPtr->action_x_loc2 = lastNodePtr->node_x;
2788 				unitPtr->action_y_loc = unitPtr->action_y_loc2 = lastNodePtr->node_y;
2789 			}
2790 		}
2791 
2792 		//----------------- set unit movement parameters -----------------//
2793 		unitPtr->result_node_recno = 1;
2794 		unitPtr->result_path_dist = result_path_dist-moveScale;
2795 		unitPtr->move_to_x_loc = move_to_x_loc;
2796 		unitPtr->move_to_y_loc = move_to_y_loc;
2797 		err_when( next_x != cur_x || next_y != cur_y );
2798 		unitPtr->next_move();
2799 
2800 		#ifdef DEBUG
2801 			if(unitPtr->result_node_array!=NULL)
2802 			{
2803 				ResultNode* curNode1 = unitPtr->result_node_array + unitPtr->result_node_recno - 1;
2804 				err_when(curNode1->node_x!=unitPtr->go_x>>ZOOM_X_SHIFT_COUNT || curNode1->node_y!=unitPtr->go_y>>ZOOM_Y_SHIFT_COUNT);
2805 			}
2806 		#endif
2807 	}
2808 
2809 	//------------------------------------------------------------------//
2810 	// setting for this unit
2811 	//------------------------------------------------------------------//
2812 	int shouldWait = 0;
2813 	if(next_x==unitPtr->cur_x && next_y==unitPtr->cur_y)
2814 	{
2815 		reset_path();
2816 		result_path_dist = 0;
2817 	}
2818 	else
2819 	{
2820 		terminate_move();
2821 		shouldWait++;
2822 		result_path_dist = moveScale;
2823 	}
2824 
2825 	go_x = unitPtr->cur_x;
2826 	go_y = unitPtr->cur_y;
2827 	move_to_x_loc = unitCurX;
2828 	move_to_y_loc = unitCurY;
2829 
2830 	if(action_mode2==ACTION_MOVE)
2831 	{
2832 		action_x_loc = action_x_loc2 = unitDestX;
2833 		action_y_loc = action_y_loc2 = unitDestY;
2834 	}
2835 
2836 	//---------- note: the cur_dir is already the correct direction ---------------//
2837 	err_when(result_node_array!=NULL);
2838 	result_node_array = (ResultNode*)mem_add(sizeof(ResultNode)*2);
2839 	ResultNode* nodePtr = result_node_array;
2840 	nodePtr->node_x = curX;
2841 	nodePtr->node_y = curY;
2842 	nodePtr++;
2843 	nodePtr->node_x = unitCurX;
2844 	nodePtr->node_y = unitCurY;
2845 	result_node_count = 2;
2846 	result_node_recno = 2;
2847 	if(shouldWait)
2848 		set_wait();	// wait for the blocking unit to move first
2849 
2850 	#ifdef DEBUG
2851 		if(result_node_array!=NULL)
2852 		{
2853 			ResultNode* curNode2 = result_node_array + result_node_recno - 1;
2854 			err_when(curNode2->node_x!=go_x>>ZOOM_X_SHIFT_COUNT || curNode2->node_y!=go_y>>ZOOM_Y_SHIFT_COUNT);
2855 		}
2856 	#endif
2857 
2858 	err_when(cur_action==SPRITE_IDLE && (move_to_x_loc!=next_x_loc() || move_to_y_loc!=next_y_loc()));
2859 	err_when(cur_action==SPRITE_IDLE && (cur_x!=next_x || cur_y!=next_y));
2860 	err_when(unitPtr->cur_action==SPRITE_IDLE && (unitPtr->move_to_x_loc!=unitPtr->next_x_loc() ||
2861 				unitPtr->move_to_y_loc!=unitPtr->next_y_loc()));
2862 }
2863 //----------------- End of function Unit::move_to_my_loc ----------------//
2864 
2865 //###### begin trevor 25/6 #######//
2866 
2867 /*
2868 //------------- Begin of function Unit::change_relation --------------//
2869 void Unit::change_relation(short nation1, short nation2, int relationType)
2870 {
2871 	if(!nation1 || !nation2 || nation1==nation2)
2872 		return; // return if either is neutral nation or same nation
2873 
2874 	nation_array[nation1]->set_relation_status(nation2, relationType);
2875 }
2876 //----------------- End of function Unit::change_relation ----------------//
2877 */
2878 
2879 //####### end trevor 25/6 ########//
2880 
2881 
2882 //------------- Begin of function Unit::set_idle --------------//
2883 // set parameters for unit idle
2884 //
set_idle()2885 void Unit::set_idle()
2886 {
2887 	/*err_when(unit_res[unit_id]->unit_class==UNIT_CLASS_SHIP &&
2888 				(((UnitMarine*)this)->extra_move_in_beach==EXTRA_MOVING_IN ||
2889 				((UnitMarine*)this)->extra_move_in_beach==EXTRA_MOVING_OUT));*/
2890 	err_when(cur_x<0);
2891 	err_when(move_to_x_loc!=next_x_loc() || move_to_y_loc!=next_y_loc());
2892 	err_when(cur_x!=next_x || cur_y!=next_y || next_x!=go_x || next_y!=go_y);
2893 	err_when(cur_x%ZOOM_LOC_WIDTH || cur_y%ZOOM_LOC_HEIGHT);
2894 
2895 	err_when(result_path_dist || result_node_array);
2896 	err_when(cur_dir<0 || cur_dir>MAX_SPRITE_DIR_TYPE);
2897 	final_dir = cur_dir;
2898 	turn_delay = 0;
2899 	cur_action = SPRITE_IDLE;
2900 }
2901 //----------------- End of function Unit::set_idle ----------------//
2902 
2903 
2904 //------------- Begin of function Unit::set_ready --------------//
2905 // set parameters for unit ready to move
2906 //
set_ready()2907 void Unit::set_ready()
2908 {
2909 	err_when(cur_x<0);
2910 	err_when(move_to_x_loc!=next_x_loc() || move_to_y_loc!=next_y_loc());
2911 	err_when(cur_x!=next_x || cur_y!=next_y || next_x!=go_x || next_y!=go_y);
2912 	err_when(cur_x%ZOOM_LOC_WIDTH || cur_y%ZOOM_LOC_HEIGHT);
2913 
2914 	err_when(cur_dir<0 || cur_dir>MAX_SPRITE_DIR_TYPE);
2915 	final_dir = cur_dir;
2916 	turn_delay = 0;
2917 	cur_action = SPRITE_READY_TO_MOVE;
2918 }
2919 //----------------- End of function Unit::set_ready ----------------//
2920 
2921 
2922 //------------- Begin of function Unit::set_move --------------//
2923 // set parameters for unit movement
2924 //
set_move()2925 void Unit::set_move()
2926 {
2927 	err_when(cur_x<0);
2928 	err_when(cur_dir!=final_dir);
2929 	cur_action = SPRITE_MOVE;
2930 }
2931 //----------------- End of function Unit::set_move ----------------//
2932 
2933 
2934 //------------- Begin of function Unit::set_wait --------------//
2935 // Set the unit to waiting status.
2936 // When SPRITE_WAIT:
2937 // (next_x, next_y) must be == (cur_x, cur_y), it's the location of the sprite.
2938 //
set_wait()2939 void Unit::set_wait()
2940 {
2941 	err_when(cur_x<0);
2942 
2943 	#ifdef DEBUG
2944 		err_when(go_x==cur_x && go_y==cur_y);
2945 		err_when( next_x != cur_x || next_y != cur_y );
2946 
2947 		short w, h, x, y;
2948 		for(h=0, y=cur_y_loc(); h<sprite_info->loc_height; h++, y++)
2949 			for(w=0, x=cur_x_loc(); w<sprite_info->loc_width; w++, x++)
2950 				err_when( world.get_unit_recno(x, y, mobile_type) != sprite_recno );
2951 		err_when((check_unit_dir1=get_dir(cur_x, cur_y, go_x, go_y))!=final_dir);
2952 	#endif
2953 
2954 	cur_action = SPRITE_WAIT;
2955    cur_frame  = 1;
2956 	waiting_term++;
2957 }
2958 //----------------- End of function Unit::set_wait ----------------//
2959 
2960 
2961 //------------- Begin of function Unit::set_attack --------------//
2962 // set parameters for unit attack
2963 //
set_attack()2964 void Unit::set_attack()
2965 {
2966 	err_when(cur_x<0);
2967 	err_when(next_x!=cur_x || next_y!=cur_y);
2968 	err_when(cur_dir<0 || cur_dir>=MAX_SPRITE_DIR_TYPE || turn_delay);
2969 	final_dir = cur_dir;
2970 	turn_delay = 0;
2971 	cur_action = SPRITE_ATTACK;
2972 }
2973 //----------------- End of function Unit::set_attack ----------------//
2974 
2975 
2976 //------------- Begin of function Unit::set_turn --------------//
2977 // set parameters for unit turning
2978 //
set_turn()2979 void Unit::set_turn()
2980 {
2981 	err_when(cur_x<0);
2982 	err_when(next_x!=cur_x || next_y!=cur_y);
2983 	cur_action = SPRITE_TURN;
2984 }
2985 //----------------- End of function Unit::set_turn ----------------//
2986 
2987 
2988 //------------- Begin of function Unit::set_ship_extra_move --------------//
2989 // set parameters for ship extra moving in inlet
2990 //
set_ship_extra_move()2991 void Unit::set_ship_extra_move()
2992 {
2993 	err_when(cur_x<0);
2994 	cur_action = SPRITE_SHIP_EXTRA_MOVE;
2995 }
2996 //----------------- End of function Unit::set_ship_extra_move ----------------//
2997 
2998 
2999 //------------- Begin of function Unit::set_die --------------//
3000 // set parameters for unit die
3001 //
set_die()3002 void Unit::set_die()
3003 {
3004 	if( action_mode == ACTION_DIE )
3005 		return;
3006 
3007 	err_when(hit_points>0);
3008 
3009 	action_mode = ACTION_DIE;
3010 	cur_action  = SPRITE_DIE;
3011 	cur_frame   = 1;
3012 
3013    //##### begin trevor 19/7 #####//
3014 
3015 	//---- if this unit is led by a leader, only mobile units has leader_unit_recno assigned to a leader -----//
3016 
3017 	if( leader_unit_recno && !unit_array.is_deleted(leader_unit_recno) )		// the leader unit may have been killed at the same time
3018 	{
3019 		unit_array[leader_unit_recno]->del_team_member(sprite_recno);
3020 		leader_unit_recno = 0;
3021 	}
3022 
3023 	//##### end trevor 19/7 #####//
3024 }
3025 //----------------- End of function Unit::set_die ----------------//
3026 
3027