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