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		:	OSPREUSE.CPP
22 //Description	:	Object SeekPathReuse
23 //Owner			:	Alex
24 
25 #include <OSPREUSE.h>
26 #include <OSPATH.h>
27 #include <ALL.h>
28 #include <OWORLD.h>
29 #include <OUNIT.h>
30 #include <OSYS.h>
31 
32 #ifdef NO_DEBUG_SEARCH
33 #undef err_when
34 #undef err_here
35 #undef err_if
36 #undef err_else
37 #undef err_now
38 #define err_when(cond)
39 #define err_here()
40 #define err_if(cond)
41 #define err_else
42 #define err_now(msg)
43 #undef debug_reuse_check_sub_mode_node
44 #define debug_reuse_check_sub_mode_node(x, y)
45 #undef DEBUG
46 #endif
47 
48 //--------------------------------------------------------//
49 // define static variables
50 //--------------------------------------------------------//
51 int	SeekPathReuse::max_node;
52 short SeekPathReuse::total_num_of_path;
53 short SeekPathReuse::cur_path_num;
54 short SeekPathReuse::unit_size;
55 uint32_t SeekPathReuse::cur_group_id;
56 char	SeekPathReuse::mobile_type;
57 char	SeekPathReuse::unit_nation_recno;
58 short SeekPathReuse::move_scale;
59 short SeekPathReuse::search_mode;
60 short SeekPathReuse::reuse_mode;
61 short SeekPathReuse::reuse_path_status;
62 short SeekPathReuse::reuse_path_dist;
63 short *SeekPathReuse::reuse_node_matrix=NULL;
64 
65 char SeekPathReuse::reuse_nation_passable[MAX_NATION+1] = {0};
66 char SeekPathReuse::reuse_search_sub_mode;
67 
68 //----------------- backup leader path(reference path) ----------------------//
69 short	SeekPathReuse::leader_path_num;
70 ResultNode *SeekPathReuse::reuse_leader_path_backup;
71 int SeekPathReuse::reuse_leader_path_node_num;
72 int SeekPathReuse::leader_path_start_x;
73 int SeekPathReuse::leader_path_start_y;
74 int SeekPathReuse::leader_path_dest_x;
75 int SeekPathReuse::leader_path_dest_y;
76 
77 //----------- decide which offset method is used ----------//
78 int SeekPathReuse::start_x_offset;
79 int SeekPathReuse::start_y_offset;
80 int SeekPathReuse::dest_x_offset;
81 int SeekPathReuse::dest_y_offset;
82 int SeekPathReuse::x_offset;
83 int SeekPathReuse::y_offset;
84 int SeekPathReuse::formation_x_offset;
85 int SeekPathReuse::formation_y_offset;
86 int SeekPathReuse::start_x;
87 int SeekPathReuse::start_y;
88 int SeekPathReuse::dest_x;
89 int SeekPathReuse::dest_y;
90 int SeekPathReuse::vir_dest_x;
91 int SeekPathReuse::vir_dest_y;
92 
93 //---------- the current constructing result path --------//
94 ResultNode *SeekPathReuse::path_reuse_result_node_ptr;
95 int SeekPathReuse::num_of_result_node;
96 ResultNode *SeekPathReuse::cur_result_node_ptr;
97 
98 short SeekPathReuse::result_node_array_def_size;
99 short SeekPathReuse::result_node_array_reset_amount;
100 
101 //-- determine the current offset difference(leader path information) --//
102 ResultNode *SeekPathReuse::cur_leader_node_ptr;
103 int SeekPathReuse::cur_leader_node_num;
104 
105 short SeekPathReuse::leader_vec_x;
106 short SeekPathReuse::leader_vec_y;
107 
108 //----------- for smoothing the result path --------------//
109 short SeekPathReuse::vec_x;
110 short SeekPathReuse::vec_y;
111 short SeekPathReuse::new_vec_x;
112 short SeekPathReuse::new_vec_y;
113 int SeekPathReuse::vec_magn;
114 int SeekPathReuse::new_vec_magn;
115 int SeekPathReuse::result_vec_x;
116 int SeekPathReuse::result_vec_y;
117 
118 
119 //-------- Begin of function SeekPathReuse::init ---------//
init(int maxNode)120 void SeekPathReuse::init(int maxNode)
121 {
122 	//------------------ initialize parameters ----------------//
123 	incomplete_search		= 0;
124 	max_node					= maxNode;
125 
126 	total_num_of_path		= 0;
127 	cur_path_num			= 0;
128 	cur_group_id			= 0;
129 	mobile_type				= 0;
130 	search_mode				= 0;
131 	reuse_mode				= 0;
132 	reuse_path_status		= 0;
133 
134 	reuse_leader_path_backup	= NULL;
135 	reuse_leader_path_node_num = 0;
136 	leader_path_start_x			= 0;
137 	leader_path_start_y			= 0;
138 	leader_path_dest_x			= 0;
139 	leader_path_dest_y			= 0;
140 
141 	start_x_offset			= 0;
142 	start_y_offset			= 0;
143 	dest_x_offset			= 0;
144 	dest_y_offset			= 0;
145 	x_offset					= 0;
146 	y_offset					= 0;
147 	vir_dest_x				= 0;
148 	vir_dest_y				= 0;
149 
150 	num_of_result_node					= 0;
151 	result_node_array_def_size			= 0;
152 	result_node_array_reset_amount	= 10;		// dafault value is 10
153 	cur_result_node_ptr					= NULL;
154 	path_reuse_result_node_ptr			= NULL;
155 
156 	cur_leader_node_ptr	= NULL;
157 	cur_leader_node_num	= 0;
158 	leader_path_num		= -1;	// valid value is not less than 0
159 	leader_vec_x			= 0;
160 	leader_vec_y			= 0;
161 
162 	init_reuse_node_matrix();	// initialize node matrix for setting offset path
163 }
164 //--------- End of function SeekPathReuse::init ---------//
165 
166 
167 //-------- Begin of function SeekPathReuse::deinit ---------//
deinit()168 void SeekPathReuse::deinit()
169 {
170 	deinit_reuse_search();			// destruct data structure
171 
172 	if(reuse_node_matrix)
173 	{
174 		mem_del(reuse_node_matrix);
175 		reuse_node_matrix = NULL;
176 	}
177 }
178 //--------- End of function SeekPathReuse::deinit ---------//
179 
180 
181 //-------- Begin of function SeekPathReuse::init_reuse_node_matrix ---------//
init_reuse_node_matrix()182 void SeekPathReuse::init_reuse_node_matrix()
183 {
184 	reuse_node_matrix = (short*) mem_add(sizeof(short)*MAX_WORLD_X_LOC*MAX_WORLD_Y_LOC/4);
185 }
186 //--------- End of function SeekPathReuse::init_reuse_node_matrix ---------//
187 
188 
189 //-------- Begin of function SeekPathReuse::deinit_reuse_search ---------//
190 // destruct data structure
191 //
deinit_reuse_search()192 void SeekPathReuse::deinit_reuse_search()
193 {
194 	if(reuse_leader_path_backup!=NULL)
195 	{
196 		mem_del(reuse_leader_path_backup);
197 		reuse_leader_path_backup = NULL;
198 	}
199 
200 	err_when(reuse_leader_path_backup!=NULL);
201 	reuse_leader_path_node_num = 0;
202 	leader_path_start_x = 0;
203 	leader_path_start_y = 0;
204 	leader_path_dest_x = 0;
205 	leader_path_dest_y = 0;
206 }
207 //--------- End of function SeekPathReuse::deinit_reuse_search ---------//
208 
209 
210 //-------- Begin of function SeekPathReuse::init_reuse_search ---------//
211 // re-construct data structure and re-initialzie parameters
212 //
init_reuse_search()213 void SeekPathReuse::init_reuse_search()
214 {
215 	incomplete_search				= 0;
216 
217 	cur_path_num					= 0;
218 	result_node_array_def_size	= 0;
219 	leader_path_num				= -1;	// set to invalid value -1 after each initialization
220 	cur_result_node_ptr			= NULL;
221 	path_reuse_result_node_ptr	= NULL;
222 	num_of_result_node			= 0;
223 
224 	deinit_reuse_search();
225 
226 	reuse_leader_path_backup	= NULL;
227 	reuse_leader_path_node_num	= 0;
228 	leader_path_start_x			= 0;
229 	leader_path_start_y			= 0;
230 	leader_path_dest_x			= 0;
231 	leader_path_dest_y			= 0;
232 }
233 //--------- End of function SeekPathReuse::init_reuse_search ---------//
234 
235 
236 //-------- Begin of function SeekPathReuse::get_reuse_path_status ---------//
get_reuse_path_status()237 char SeekPathReuse::get_reuse_path_status()
238 {
239 	return (char) reuse_path_status;
240 }
241 //--------- End of function SeekPathReuse::get_reuse_path_status ---------//
242 
243 
244 //-------- Begin of function SeekPathReuse::bound_check_x ---------//
245 /*inline void SeekPathReuse::bound_check_x(int& x)
246 {
247 	if(x<0)
248 		x = 0;
249 	else if(x>=MAX_WORLD_X_LOC)
250 		x = MAX_WORLD_X_LOC-move_scale;
251 }*/
252 //--------- End of function SeekPathReuse::bound_check_x ---------//
253 
254 
255 //-------- Begin of function SeekPathReuse::bound_check_y ---------//
256 /*inline void SeekPathReuse::bound_check_y(int& y)
257 {
258 	if(y<0)
259 		y = 0;
260 	else if(y>=MAX_WORLD_X_LOC)
261 		y = MAX_WORLD_X_LOC-move_scale;
262 }*/
263 //--------- End of function SeekPathReuse::bound_check_y ---------//
264 
265 
266 //-------- Begin of function SeekPathReuse::call_seek ---------//
267 /*inline ResultNode* SeekPathReuse::call_seek(int sx, int sy, int dx, int dy, DWORD groupId, char mobileType,
268 														  short searchMode, int& nodeCount)
269 {
270 	err_when(unit_size!=1);
271 	seek_path.seek(sx, sy, dx, dy, groupId, mobileType, searchMode);
272 	return seek_path.get_result(nodeCount, reuse_path_dist);
273 }*/
274 //--------- End of function SeekPathReuse::call_seek ---------//
275 
276 
277 //-------- Begin of function SeekPathReuse::set_offset_condition ---------//
278 // store the starting location, destination, offset of each path
279 //
set_offset_condition(int startX,int startY,int destX,int destY)280 void SeekPathReuse::set_offset_condition(int startX, int startY, int destX, int destY)
281 {
282 	//-------------------------------------------------------------//
283 	// the offset is used to determine what the methods is used to
284 	// do the path-reuse
285 	//-------------------------------------------------------------//
286 	err_when(leader_path_num>=cur_path_num);
287 
288 	if(cur_path_num>0)
289 	{
290 		//---- the following value is useless if no valid leader path -------//
291 		start_x_offset	= startX - leader_path_start_x;
292 		start_y_offset	= startY - leader_path_start_y;
293 		dest_x_offset	= destX - leader_path_dest_x;
294 		dest_y_offset	= destY - leader_path_dest_y;
295 	}
296 	else		// no leader path is available
297 	{
298 		err_when(reuse_path_status != REUSE_PATH_FIRST_SEEK);
299 
300 		start_x_offset	= start_y_offset = dest_x_offset = dest_y_offset = 0;
301 		leader_path_start_x = startX;
302 		leader_path_start_y = startY;
303 		leader_path_dest_x = destX;
304 		leader_path_dest_y = destY;
305 
306 		leader_path_num = cur_path_num;
307 	}
308 }
309 //--------- End of function SeekPathReuse::set_offset_condition ---------//
310 
311 
312 //-------- Begin of function SeekPathReuse::set_next_cur_path_num ---------//
313 //	This function may be called outside by Unit::move_to
314 //
set_next_cur_path_num()315 void SeekPathReuse::set_next_cur_path_num()
316 {
317 	cur_path_num++;
318 }
319 //--------- End of function SeekPathReuse::set_next_cur_path_num ---------//
320 
321 
322 //-------- Begin of function SeekPathReuse::is_node_avail_empty ---------//
323 // return 1 if node available for search is zero
324 // return 0 otherwise
325 //
is_node_avail_empty()326 int SeekPathReuse::is_node_avail_empty()
327 {
328 	err_when(unit_size!=1);
329 	return seek_path.total_node_avail<MIN_BACKGROUND_NODE_USED_UP;
330 }
331 //--------- End of function SeekPathReuse::is_node_avail_empty ---------//
332 
333 
334 //-------- Begin of function SeekPathReuse::is_leader_path_valid ---------//
335 // return 1 leader path is valid
336 // return 0 otherwise
337 //
is_leader_path_valid()338 int SeekPathReuse::is_leader_path_valid()
339 {
340 	if(leader_path_num<0 || reuse_leader_path_node_num<2)
341 	{
342 		//---------------------------------------------------------------//
343 		// if no leader path of if the number of node in the leader path < 2.
344 		// A new one will be chosed to be the leader-path.
345 		//---------------------------------------------------------------//
346 		if(reuse_leader_path_backup!=NULL)
347 		{
348 			mem_del(reuse_leader_path_backup);
349 			reuse_leader_path_backup = NULL;
350 		}
351 
352 		err_when(reuse_leader_path_backup!=NULL);
353 
354 		//start_x_offset	= start_y_offset = dest_x_offset = dest_y_offset = 0;
355 		leader_path_start_x = start_x;
356 		leader_path_start_y = start_y;
357 		leader_path_dest_x = dest_x;
358 		leader_path_dest_y = dest_y;
359 
360 		leader_path_num = cur_path_num;	// set leader path number
361 		if(is_node_avail_empty())
362 		{
363 			incomplete_search++;
364 			reuse_path_status = REUSE_PATH_INCOMPLETE_SEARCH;
365 			return 0;
366 		}
367 
368 		path_reuse_result_node_ptr = call_seek(start_x, start_y, vir_dest_x, vir_dest_y, cur_group_id, mobile_type,
369 															SEARCH_MODE_IN_A_GROUP, num_of_result_node);
370 
371 		//------------------------------------------------------------------------//
372 		// checking for incomplete searching
373 		//------------------------------------------------------------------------//
374 		if(!path_reuse_result_node_ptr || !num_of_result_node)
375 		{
376 			incomplete_search = 1;
377 			reuse_path_status = REUSE_PATH_INCOMPLETE_SEARCH;
378 			return 0;
379 		}
380 
381 		err_when(!path_reuse_result_node_ptr || !num_of_result_node);
382 		ResultNode *lastNodePtr = path_reuse_result_node_ptr + num_of_result_node - 1;
383 		if(lastNodePtr->node_x!=vir_dest_x || lastNodePtr->node_y!=vir_dest_y)
384 		{
385 			err_when(unit_size!=1);
386 			if(seek_path.path_status==PATH_NODE_USED_UP)
387 			{
388 				incomplete_search++;
389 				reuse_path_status = REUSE_PATH_INCOMPLETE_SEARCH;
390 			}
391 		}
392 
393 		return 0;
394 	}
395 
396 	return 1;
397 }
398 //--------- End of function SeekPathReuse::is_leader_path_valid ---------//
399 
400 
401 //-------- Begin of function SeekPathReuse::set_nation_passable ---------//
set_nation_passable(char nationPassable[])402 void SeekPathReuse::set_nation_passable(char nationPassable[])
403 {
404 	memcpy(reuse_nation_passable+1, nationPassable, sizeof(char)*MAX_NATION);
405 }
406 //--------- End of function SeekPathReuse::set_nation_passable ---------//
407 
408 
409 //-------- Begin of function SeekPathReuse::set_sub_mode ---------//
set_sub_mode(char subMode)410 void SeekPathReuse::set_sub_mode(char subMode)
411 {
412 	reuse_search_sub_mode = subMode;
413 }
414 //--------- End of function SeekPathReuse::set_sub_mode ---------//
415 
416 
417 //-------- Begin of function SeekPathReuse::set_status ---------//
set_status(char newStatus)418 void SeekPathReuse::set_status(char newStatus)
419 {
420 	reuse_path_status = newStatus;
421 }
422 //--------- End of function SeekPathReuse::set_status ---------//
423 
424 
425 //-------- Begin of function SeekPathReuse::count_path_dist ---------//
count_path_dist(ResultNode * nodeArray,int nodeNum)426 short SeekPathReuse::count_path_dist(ResultNode* nodeArray, int nodeNum)
427  {
428  	if(!nodeArray || !nodeNum)
429  		return 0;
430 
431  	err_when(nodeNum<2);
432 
433  	ResultNode *preNode = nodeArray;
434 	ResultNode *curNode = preNode+1;
435 	int processed = 1;
436 	int xDist, yDist;
437  	short pathDist = 0;
438 
439  	while(processed++ < nodeNum)
440 	{
441 		xDist = abs(preNode->node_x - curNode->node_x);
442 		yDist = abs((preNode++)->node_y - (curNode++)->node_y);
443 		err_when((!xDist && !yDist) || (xDist && yDist && xDist!=yDist));
444 
445 		pathDist += (xDist) ? xDist : yDist;
446 	}
447 
448 	err_when(mobile_type!=UNIT_LAND && pathDist%2);
449 	return pathDist;
450 }
451 //--------- End of function SeekPathReuse::count_path_dist ---------//
452 
453 
454 //-------- Begin of function SeekPathReuse::add_result ---------//
455 // add the result node in the reuse result node array and resize
456 // the array size if default size is not large enough to hold the
457 // data
458 //
add_result(int x,int y)459 void SeekPathReuse::add_result(int x, int y)
460 {
461 	debug_reuse_check_sub_mode_node(x, y);
462 
463 	if(num_of_result_node>=result_node_array_def_size)	// the array is not enough to hold the data
464 	{
465 		result_node_array_def_size += result_node_array_reset_amount;
466 		path_reuse_result_node_ptr = (ResultNode*) mem_resize(path_reuse_result_node_ptr, sizeof(ResultNode)* result_node_array_def_size);
467 		cur_result_node_ptr = path_reuse_result_node_ptr+num_of_result_node;
468 	}
469 
470 	cur_result_node_ptr->node_x = x;
471 	cur_result_node_ptr->node_y = y;
472 	cur_result_node_ptr++;
473 	num_of_result_node++;
474 }
475 //--------- End of function SeekPathReuse::add_result ---------//
476 
477 
478 //-------- Begin of function SeekPathReuse::set_index_in_node_matrix ---------//
479 // Generally speaking, the value of the node in node matrix is less than max_node.
480 // In order to set a offset path in the node matrix and not conflict the shortest
481 // path searching, value > max_node is chosed.
482 //
483 // In this method, 4 value(max_node+k, where k is 1,..,4) is used for 2x2 node.
484 // The value k indicate which point in the node will be chosen to be the connection
485 // point to the offset path.
486 //
set_index_in_node_matrix(int xLoc,int yLoc)487 void SeekPathReuse::set_index_in_node_matrix(int xLoc, int yLoc)
488 {
489 	short *curLocInNodeMatrix;
490 	int x = xLoc;
491 	int y = yLoc;
492 
493 	//-------------------- boundary checking ---------------//
494 	bound_check_x(x);
495 	bound_check_y(y);
496 
497 	err_when(unit_size!=1);
498 	curLocInNodeMatrix = reuse_node_matrix + MAX_WORLD_X_LOC/2*(y/2) + (x/2);
499 	//-------------------------------------------------------------------------//
500 	// the location is changed into 2x2 node format.
501 	//		 -- --		In fact, the location is in one of the 4 points in the node.
502 	//		|1	|2	|		The value k is shown in the figure.  The value in the
503 	//		 -- --		node_matrix is set to max_node+k.
504 	//		|3	|4	|
505 	//		 -- --		The value will be set again if two points is available in the
506 	//						node and the last one will be chosen.
507 	//-------------------------------------------------------------------------//
508 	if(mobile_type==UNIT_LAND)
509 		*curLocInNodeMatrix = max_node + 1 + (x%2) + 2*(y%2);
510 	else
511 		*curLocInNodeMatrix = max_node + 1 + (x%4!=0) + 2*(y%4!=0);
512 }
513 //--------- End of function SeekPathReuse::set_index_in_node_matrix ---------//
514 
515 
516 //-------- Begin of function SeekPathReuse::move_within_map ---------//
517 // locations (preX, preY) and (curX, curY) both are inside the map
518 //
519 // add one point
520 //
move_within_map(int preX,int preY,int curX,int curY)521 void SeekPathReuse::move_within_map(int preX, int preY, int curX, int curY)
522 {
523 	err_when(preX<0 || preX>=MAX_WORLD_X_LOC || preY<0 || preY>=MAX_WORLD_Y_LOC);
524 	err_when(curX<0 || curX>=MAX_WORLD_X_LOC || curY<0 || curY>=MAX_WORLD_Y_LOC);
525 	add_result(curX, curY);
526 }
527 //--------- End of function SeekPathReuse::move_within_map ---------//
528 
529 
530 //-------- Begin of function SeekPathReuse::move_outside_map ---------//
531 // location (preX, preY) is inside the map while location (curX, curY)
532 // is outside the map
533 //
534 // add one/two points
535 //
move_outside_map(int preX,int preY,int curX,int curY)536 void SeekPathReuse::move_outside_map(int preX, int preY, int curX, int curY)
537 {
538 	err_when(preX<0 || preX>=MAX_WORLD_X_LOC || preY<0 || preY>=MAX_WORLD_Y_LOC);
539 	err_when(curX>=0 && curX<MAX_WORLD_X_LOC && curY>=0 && curY<MAX_WORLD_Y_LOC);
540 
541 	int vecX = curX-preX;
542 	int vecY = curY-preY;
543 	if(vecX!=0) vecX /= abs(vecX);
544 	if(vecY!=0) vecY /= abs(vecY);
545 
546 	int vertical=0;		// 1 for upper edge, 2 for lower edge
547 	int horizontal=0;		// 1 for left edge, 2 for right edge
548 	int xStep, yStep;
549 	if(curX<0)
550 	{
551 		xStep = preX;
552 		horizontal = 1;
553 	}
554 	else if(curX>=MAX_WORLD_X_LOC)
555 	{
556 		xStep = MAX_WORLD_X_LOC-preX-1;
557 		horizontal = 2;
558 	}
559 	else
560 		err_here();
561 
562 	if(curY<0)
563 	{
564 		yStep = preY;
565 		vertical = 1;
566 	}
567 	else if(curY>=MAX_WORLD_Y_LOC)
568 	{
569 		yStep = MAX_WORLD_Y_LOC-preY-1;
570 		vertical = 2;
571 	}
572 	else
573 		err_here();
574 
575 	err_when(xStep!=yStep);
576 	int addXLoc = preX+xStep*vecX;
577 	int addYLoc = preY+yStep*vecY;
578 	add_result(addXLoc, addYLoc); // add the first point
579 
580 	//-*************** codes here ***************-//
581 	//---------------------------------------------------------------//
582 	// may add the second point if exit at the edge of the map
583 	//---------------------------------------------------------------//
584 	/*if((addXLoc==0 && addYLoc==0) ||
585 		(addXLoc==0 && addYLoc==MAX_WORLD_Y_LOC-1) ||
586 		(addXLoc==MAX_WORLD_X_LOC-1 && addYLoc==0) ||
587 		(addXLoc==MAX_WORLD_X_LOC-1 && addYLoc==MAX_WORLD_Y_LOC-1))
588 	{
589 		err_when(!vertical || !horizontal);
590 		return; // exit at corner
591 	}*/
592 }
593 //--------- End of function SeekPathReuse::move_outside_map ---------//
594 
595 
596 //-------- Begin of function SeekPathReuse::move_inside_map ---------//
597 // location (preX, preY) is outside the map and location (curX, curY)
598 // is insode the map
599 //
600 // add one/two points
601 //
move_inside_map(int preX,int preY,int curX,int curY)602 void SeekPathReuse::move_inside_map(int preX, int preY, int curX, int curY)
603 {
604 	err_when(preX>=0 && preX<MAX_WORLD_X_LOC && preY>=0 && preY<MAX_WORLD_Y_LOC);
605 	err_when(curX<0 || curX>=MAX_WORLD_X_LOC || curY<0 || curY>=MAX_WORLD_Y_LOC);
606 	//-*************** codes here ***************-//
607 }
608 //--------- End of function SeekPathReuse::move_inside_map ---------//
609 
610 
611 //-------- Begin of function SeekPathReuse::move_beyond_map ---------//
612 // locations (preX, preY) and (curX, curY) are both outside the map
613 //
614 // add one/two points
move_beyond_map(int preX,int preY,int curX,int curY)615 void SeekPathReuse::move_beyond_map(int preX, int preY, int curX, int curY)
616 {
617 	err_when(preX>=0 && preX<MAX_WORLD_X_LOC && preY>=0 && preY<MAX_WORLD_Y_LOC);
618 	err_when(curX>=0 && curX<MAX_WORLD_X_LOC && curY>=0 && curY<MAX_WORLD_Y_LOC);
619 	//-*************** codes here ***************-//
620 }
621 //--------- End of function SeekPathReuse::move_beyond_map ---------//
622 
623 
624 //-------- Begin of function SeekPathReuse::seek ---------//
625 //	searchMode	should be 4	(i.e. path reuse searching mode)
626 //	reuseMode	GENERAL_GROUP_MOVEMENT for general group movement
627 //					FORMATION_MOVEMENT for formation movement
628 //
629 //	miscNo == target record no if searchMode==SEARCH_MODE_TO_ATTACK
630 //			 == firm ID if searchMode==SEARCH_MODE_TO_FIRM
631 //
seek(int sx,int sy,int dx,int dy,short unitSize,uint32_t groupId,char mobileType,short searchMode,short miscID,short numOfPath,short reuseMode,short pathReuseStatus,int maxTries,int borderX1,int borderY1,int borderX2,int borderY2)632 int SeekPathReuse::seek(int sx,int sy,int dx,int dy,short unitSize, uint32_t groupId, char mobileType,
633 								short searchMode, short miscID,
634 								short numOfPath, short reuseMode, short pathReuseStatus,
635 								int maxTries,int borderX1, int borderY1, int borderX2, int borderY2)
636 {
637 	//---------------------- error checking ---------------------//
638 	err_when(numOfPath<0 || searchMode!=4 || numOfPath<1);
639 	err_when(pathReuseStatus!=REUSE_PATH_INITIAL && numOfPath!=total_num_of_path);
640 
641 	//-------------------------------------------------------------//
642 	// initialize parameters
643 	//-------------------------------------------------------------//
644 	total_num_of_path		= numOfPath;
645 	reuse_path_status		= pathReuseStatus;
646 
647 	if(reuse_path_status == REUSE_PATH_INITIAL)
648 	{
649 		//-------- initialize data structure and then return ---------//
650 		init_reuse_search();
651 		return 1;
652 	}
653 
654 	start_x					= sx;
655 	start_y					= sy;
656 	dest_x					= dx;
657 	dest_y					= dy;
658 	vir_dest_x				= dest_x;
659 	vir_dest_y				= dest_y;
660 
661 	unit_size				= unitSize;
662 	cur_group_id			= groupId;
663 	mobile_type				= mobileType;
664 	search_mode				= searchMode;
665 	reuse_mode				= reuseMode;
666 	move_scale				= (mobile_type==UNIT_LAND) ? 1 : 2;
667 
668 	unit_nation_recno		= unit_array[world.get_unit_recno(start_x, start_y, mobile_type)]->nation_recno;
669 
670 	result_node_array_def_size	= 0;
671 	num_of_result_node			= 0;
672 	cur_result_node_ptr			= NULL;
673 	path_reuse_result_node_ptr	= NULL;
674 
675 	//-------------------------------------------------------------//
676 	set_offset_condition(sx, sy, dx, dy);
677 
678 	//-------------------------------------------------------------//
679 	if(reuse_path_status == REUSE_PATH_FIRST_SEEK)	// first seeking, usually choose to be leader path
680 	{
681 		err_when(cur_path_num != 0);
682 		path_reuse_result_node_ptr = call_seek(sx, sy, dx, dy, cur_group_id, mobileType, SEARCH_MODE_IN_A_GROUP, num_of_result_node);
683 	}
684 	else	// it should be REUSE_PATH_SEARCH
685 	{
686 		//-------------------------------------------------------------//
687 		// reuse_mode = GENERAL_GROUP_MOVEMENT
688 		//-------------------------------------------------------------//
689 		if(start_x_offset==dest_x_offset && start_y_offset==dest_y_offset)
690 		{
691 			//----------------------------------------------------------//
692 			// optimal case, starting offset==ending offset, thus, using
693 			// offset method to find the shortest path directly
694 			//----------------------------------------------------------//
695 			x_offset = start_x_offset;
696 			y_offset = start_y_offset;
697 
698 			err_when(cur_path_num==leader_path_num);
699 			seek_path_offset();
700 		}
701 		else
702 		{
703 			//-------------------------------------------------------------//
704 			// the starting location is not the correct offset location,
705 			// using the join-offset-path method
706 			//-------------------------------------------------------------//
707 			x_offset = dest_x_offset;
708 			y_offset = dest_y_offset;
709 			seek_path_join_offset();
710 		}
711 	}
712 
713 	//-------------------------------------------------------------//
714 	// backup the ResultNode of this path
715 	//-------------------------------------------------------------//
716 	if(num_of_result_node && path_reuse_result_node_ptr)
717 	{
718 		#ifdef DEBUG
719 			if(mobile_type==UNIT_LAND && reuse_search_sub_mode==SEARCH_SUB_MODE_PASSABLE && num_of_result_node>1)
720 			{
721 				err_when(mobile_type!=UNIT_LAND);
722 				debug_reuse_check_sub_mode(path_reuse_result_node_ptr, num_of_result_node);
723 			}
724 		#endif
725 
726 		path_reuse_result_node_ptr = smooth_reuse_path(path_reuse_result_node_ptr, num_of_result_node);
727 
728 		#ifdef DEBUG
729 			if(mobile_type==UNIT_LAND && reuse_search_sub_mode==SEARCH_SUB_MODE_PASSABLE && num_of_result_node>1)
730 			{
731 				err_when(mobile_type!=UNIT_LAND);
732 				debug_reuse_check_sub_mode(path_reuse_result_node_ptr, num_of_result_node);
733 			}
734 		#endif
735 
736 		if(leader_path_num==cur_path_num)
737 		{
738 			err_when(num_of_result_node>0 && path_reuse_result_node_ptr==NULL);
739 			reuse_leader_path_backup = (ResultNode*) mem_add(sizeof(ResultNode)*num_of_result_node);
740 			memcpy(reuse_leader_path_backup, path_reuse_result_node_ptr, sizeof(ResultNode)* num_of_result_node);
741 			reuse_leader_path_node_num = num_of_result_node;
742 		}
743 	}
744 	else
745 	{
746 		path_reuse_result_node_ptr = NULL;
747 		num_of_result_node = 0;
748 
749 		if(leader_path_num==cur_path_num)
750 		{
751 			reuse_leader_path_backup = NULL;
752 			reuse_leader_path_node_num = 0;
753 		}
754 	}
755 
756 	set_next_cur_path_num();
757 	err_when(cur_path_num>total_num_of_path+3);
758 
759 	return 1;
760 }
761 //--------- End of function SeekPathReuse::seek ---------//
762 
763 
764 //-------- Begin of function SeekPathReuse::get_result ---------//
765 // return the final result node path
766 //ResultNode* SeekPathReuse::get_result(int& resultNodeCount)
767 //
get_result(int & resultNodeCount,short & pathDist)768 ResultNode* SeekPathReuse::get_result(int& resultNodeCount, short& pathDist)
769 {
770 	if(reuse_path_status == REUSE_PATH_FIRST_SEEK)
771 	{
772 		resultNodeCount = num_of_result_node;
773  		reuse_path_dist = count_path_dist(path_reuse_result_node_ptr, num_of_result_node);
774  		pathDist = reuse_path_dist;
775 		return path_reuse_result_node_ptr;
776 	}
777 	else
778 	{
779 		err_when(reuse_path_status!=REUSE_PATH_SEARCH && reuse_path_status!=REUSE_PATH_INCOMPLETE_SEARCH);
780 
781 		if(path_reuse_result_node_ptr!=NULL && num_of_result_node>0)
782 		{
783 			sys_yield(); // update cursor position
784 			if(num_of_result_node<2)
785 			{
786 				mem_del(path_reuse_result_node_ptr);
787 				path_reuse_result_node_ptr = NULL;
788 				num_of_result_node = 0;
789 			}
790 
791 			sys_yield(); // update cursor position
792 
793 			resultNodeCount = num_of_result_node;
794  			reuse_path_dist = count_path_dist(path_reuse_result_node_ptr, num_of_result_node);
795  			pathDist = reuse_path_dist;
796 		}
797 		else
798 		{
799 			num_of_result_node = 0;
800 			if(path_reuse_result_node_ptr!=NULL)
801 			{
802 				mem_del(path_reuse_result_node_ptr);
803 				path_reuse_result_node_ptr = NULL;
804 			}
805 
806 			err_when(num_of_result_node!=0 || path_reuse_result_node_ptr!=NULL);
807 		}
808 
809 		//******************* debug **********************//
810 		#ifdef DEBUG
811 			err_when(mobile_type!=UNIT_LAND && pathDist%2);
812 			if(!path_reuse_result_node_ptr && num_of_result_node>0)
813 			{
814 				//---------------------------------------------------------//
815 				// final checking, error free for the result_path
816 				//---------------------------------------------------------//
817 				ResultNode*	debugResultPtr = path_reuse_result_node_ptr;
818 				ResultNode*	debugStartNode = path_reuse_result_node_ptr;
819 				ResultNode*	debugEndNode = debugStartNode + 1;
820 				int			debugCount = num_of_result_node;
821 				int			dvX, dvY;	// vector direction
822 				int			dXLoc, dYLoc;
823 
824 				err_when(mobile_type!=UNIT_LAND && (debugStartNode->node_x%2 || debugStartNode->node_y%2));
825 				for(int d=1; d<debugCount; d++)
826 				{
827 					//------- check x, y vector magnitude ---------//
828 					debugStartNode = path_reuse_result_node_ptr + d-1;
829 					debugEndNode = debugStartNode + d;
830 					err_when(mobile_type!=UNIT_LAND && (debugEndNode->node_x%2 || debugEndNode->node_y%2));
831 					dvX = debugEndNode->node_x - debugStartNode->node_x;
832 					dvY = debugEndNode->node_y - debugStartNode->node_y;
833 
834 					err_when(dvX!=0 && dvY!=0 && abs(dvX)!=abs(dvY));
835 					if(dvX)	dvX /= abs(dvX);
836 					if(dvY)	dvY /= abs(dvY);
837 					dXLoc = debugStartNode->node_x;
838 					dYLoc = debugStartNode->node_y;
839 
840 					//-------- check accessible ---------//
841 					while(dXLoc!=debugEndNode->node_x || dYLoc!=debugEndNode->node_y)
842 					{
843 						dXLoc += dvX;
844 						dYLoc += dvY;
845 						err_when(unit_size==1 && !can_walk(dXLoc, dYLoc));
846 						err_when(unit_size==2 && !can_walk_s2(dXLoc, dYLoc));
847 					}
848 				}
849 			}
850 		#endif
851 		//******************* debug **********************//
852 
853 		return path_reuse_result_node_ptr;
854 	}
855 }
856 //--------- End of function SeekPathReuse::get_result ---------//
857