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 : OUNITAT3.CPP
22 //Description : Object Unit's decision making functions for attacking same or different type of target and reactivating
23 // idle unit that are ordered to attack
24 //Owner : Alex
25
26 #include <ALL.h>
27 #include <OWORLD.h>
28 #include <OUNIT.h>
29 #include <OGAME.h>
30
31 #ifdef NO_DEBUG_UNIT
32 #undef err_when
33 #undef err_here
34 #undef err_if
35 #undef err_else
36 #undef err_now
37 #define err_when(cond)
38 #define err_here()
39 #define err_if(cond)
40 #define err_else
41 #define err_now(msg)
42 #undef DEBUG
43 #endif
44
45 //--------- Begin of function Unit::move_try_to_range_attack ---------//
46 // return 1 if it is possible to reach a location to attack the target
47 // return 0 otherwise
48 //
49 // <Unit*> targetUnit - pointer to target unit
50 //
move_try_to_range_attack(Unit * targetUnit)51 int Unit::move_try_to_range_attack(Unit* targetUnit)
52 {
53 int curXLoc = next_x_loc();
54 int curYLoc = next_y_loc();
55 int targetXLoc = targetUnit->next_x_loc();
56 int targetYLoc = targetUnit->next_y_loc();
57
58 if(world.get_loc(curXLoc, curYLoc)->region_id==world.get_loc(targetXLoc, targetYLoc)->region_id)
59 {
60 //------------ for same region id, search now ---------------//
61 if(search(targetXLoc, targetYLoc, 1, SEARCH_MODE_TO_ATTACK, action_para))
62 return 1;
63 else // search failure,
64 {
65 stop2(KEEP_DEFENSE_MODE);
66 return 0;
67 }
68 }
69 else
70 {
71 //--------------- different territory ------------------//
72 int targetWidth = targetUnit->sprite_info->loc_width;
73 int targetHeight = targetUnit->sprite_info->loc_height;
74 int maxRange = max_attack_range();
75
76 if(possible_place_for_range_attack(targetXLoc, targetYLoc, targetWidth, targetHeight, maxRange))
77 {
78 //---------------------------------------------------------------------------------//
79 // space is found, attack target now
80 //---------------------------------------------------------------------------------//
81 if(move_to_range_attack(targetXLoc, targetYLoc, targetUnit->sprite_id, SEARCH_MODE_ATTACK_UNIT_BY_RANGE, maxRange))
82 return 1;
83 else
84 {
85 stop2(KEEP_DEFENSE_MODE);
86 return 0;
87 }
88 return 1;
89 }
90 else
91 {
92 //---------------------------------------------------------------------------------//
93 // unable to find location to attack the target, stop or move to the target
94 //---------------------------------------------------------------------------------//
95 if(action_mode2!=ACTION_AUTO_DEFENSE_ATTACK_TARGET && action_mode2!=ACTION_DEFEND_TOWN_ATTACK_TARGET &&
96 action_mode2!=ACTION_MONSTER_DEFEND_ATTACK_TARGET)
97 move_to(targetXLoc, targetYLoc, 1); // abort attacking, just call move_to() instead
98 else
99 stop2(KEEP_DEFENSE_MODE);
100 return 0;
101 }
102 }
103
104 return 0;
105 }
106 //----------- End of function Unit::move_try_to_range_attack -----------//
107
108
109 //--------- Begin of function Unit::move_to_range_attack ---------//
110 // search and attack target
111 //
112 // <int> targetXLoc - target x location
113 // <int> targetYLoc - target y location
114 // <short> miscNo - is sprite_id if target is a unit
115 // is firm_id if target is a firm
116 // is 0 if target is a town or a wall
117 // <short> searchMode - search mode being used
118 // <short> maxRange - MAX attack range of this unit
119 //
move_to_range_attack(int targetXLoc,int targetYLoc,short miscNo,short searchMode,short maxRange)120 int Unit::move_to_range_attack(int targetXLoc, int targetYLoc, short miscNo, short searchMode, short maxRange)
121 {
122 //---------------------------------------------------------------------------------//
123 // part 1, searching
124 //---------------------------------------------------------------------------------//
125 seek_path.set_attack_range_para(maxRange);
126 search(targetXLoc, targetYLoc, 1, searchMode, miscNo);
127 seek_path.reset_attack_range_para();
128 //search(targetXLoc, targetYLoc, 1, searchMode, maxRange);
129
130 if(result_node_array==NULL || result_node_count==0)
131 return 0;
132
133 //---------------------------------------------------------------------------------//
134 // part 2, editing result path
135 //---------------------------------------------------------------------------------//
136 Location *locPtr = world.get_loc(next_x_loc(), next_y_loc());
137 err_when(!locPtr);
138
139 int regionId = locPtr->region_id; // the region_id this unit in
140
141 //----------------------------------------------------//
142 err_when(result_node_count<2);
143 ResultNode* editNode1 = result_node_array + result_node_count - 1;
144 ResultNode* editNode2 = editNode1-1;
145 int vecX = editNode1->node_x - editNode2->node_x;
146 int vecY = editNode1->node_y - editNode2->node_y;
147
148 if(vecX)
149 vecX = ((vecX>0) ? 1 : -1)*move_step_magn();
150 if(vecY)
151 vecY = ((vecY>0) ? 1 : -1)*move_step_magn();
152
153 int x = editNode1->node_x;
154 int y = editNode1->node_y;
155 int i, found=0, removedStep=0, preX, preY;
156
157 for(i=result_node_count; i>1; i--)
158 {
159 while(x!=editNode2->node_x || y!=editNode2->node_y)
160 {
161 locPtr = world.get_loc(x, y);
162 if(locPtr->region_id == regionId)
163 {
164 found = i;
165 preX = x;
166 preY = y;
167 break;
168 }
169
170 x -= vecX;
171 y -= vecY;
172 removedStep++;
173 }
174
175 if(found)
176 break;
177
178 editNode1 = editNode2;
179 editNode2--;
180
181 vecX = editNode1->node_x - editNode2->node_x;
182 vecY = editNode1->node_y - editNode2->node_y;
183 if(vecX)
184 vecX = ((vecX>0) ? 1 : -1)*move_step_magn();
185 if(vecY)
186 vecY = ((vecY>0) ? 1 : -1)*move_step_magn();
187
188 x = editNode1->node_x;
189 y = editNode1->node_y;
190 }
191
192 //---------------------------------------------------------------------------//
193 // update unit parameters
194 //---------------------------------------------------------------------------//
195 if(found)
196 {
197 result_node_count = found;
198 ResultNode* lastNode = result_node_array + result_node_count - 1;
199 int goX = go_x>>ZOOM_X_SHIFT_COUNT;
200 int goY = go_y>>ZOOM_Y_SHIFT_COUNT;
201
202 //---------------------------------------------------------------------//
203 // note: build?Loc-1, build?Loc+width, build?Loc+height may <0 or
204 // >MAX_WORLD_?_LOC. To prevent errors from occuring, goX, goY
205 // must not be outside the map boundary
206 //---------------------------------------------------------------------//
207 if(goX==editNode1->node_x && goY==editNode1->node_y)
208 {
209 go_x = preX*ZOOM_LOC_WIDTH;
210 go_y = preY*ZOOM_LOC_HEIGHT;
211 }
212 else if(result_node_count==2)
213 {
214 int magnCG = misc.points_distance(cur_x, cur_y, go_x, go_y);
215 int magnNG = misc.points_distance(next_x, next_y, go_x, go_y);
216 err_when(magnCG==0 && magnNG==0);
217
218 if(magnCG && magnNG)
219 {
220 //---------- lie on the same line -----------//
221 if( (go_x-cur_x)/magnCG==(go_x-next_x)/magnNG && (go_y-cur_y)/magnCG==(go_y-next_y)/magnNG )
222 {
223 go_x = preX*ZOOM_LOC_WIDTH;
224 go_y = preY*ZOOM_LOC_HEIGHT;
225 }
226 }
227 }
228
229 lastNode->node_x = preX;
230 lastNode->node_y = preY;
231 move_to_x_loc = lastNode->node_x;
232 move_to_y_loc = lastNode->node_y;
233
234 result_path_dist -= (removedStep)*move_step_magn();
235
236 err_when((cur_x!=next_x || cur_y!=next_y) && // is not blocked
237 (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)));
238 }
239
240 return found;
241 }
242 //----------- End of function Unit::move_to_range_attack -----------//
243
244
245 //--------- Begin of function Unit::can_attack_different_type_target ---------//
246 // return 1 if able to use range_attack
247 // return 0 otherwise
248 //
can_attack_different_target_type()249 int Unit::can_attack_different_target_type()
250 {
251 int maxRange = max_attack_range();
252 if(mobile_type==UNIT_LAND && !maxRange)
253 return 0; // unable to do range attack or cannot attack
254
255 if(maxRange>1)
256 return maxRange;
257 else
258 return 0;
259 }
260 //----------- End of function Unit::can_attack_different_type_target -----------//
261
262
263 //--------- Begin of function Unit::possible_place_for_range_attack ---------//
264 // check whether there is any place for this unit to attack the target
265 //
266 // <int> targetXLoc - target x location
267 // <int> targetYLoc - target y location
268 // <int> targetWidth - target width
269 // <int> targetHeight - target height
270 // <int> maxRange - MAX attack range of this unit
271 //
272 // return 1 if place found
273 // return 0 otherwise
274 //
possible_place_for_range_attack(int targetXLoc,int targetYLoc,int targetWidth,int targetHeight,int maxRange)275 int Unit::possible_place_for_range_attack(int targetXLoc, int targetYLoc, int targetWidth, int targetHeight, int maxRange)
276 {
277 err_when(targetXLoc<0 || targetXLoc>=MAX_WORLD_X_LOC || targetYLoc<0 || targetYLoc>=MAX_WORLD_Y_LOC);
278 err_when(maxRange==0);
279
280 if(mobile_type==UNIT_AIR)
281 return 1; // air unit can reach any region
282
283 int curXLoc = next_x_loc();
284 int curYLoc = next_y_loc();
285
286 if(abs(curXLoc-targetXLoc)<=maxRange && abs(curYLoc-targetYLoc)<=maxRange) // inside the attack range
287 return 1;
288
289 //----------------- init parameters -----------------//
290 Location *locPtr = world.get_loc(curXLoc, curYLoc);
291 int regionId = locPtr->region_id;
292 int xLoc1 = MAX(targetXLoc-maxRange, 0);
293 int yLoc1 = MAX(targetYLoc-maxRange, 0);
294 int xLoc2 = MIN(targetXLoc+targetWidth-1+maxRange, MAX_WORLD_X_LOC-1);
295 int yLoc2 = MIN(targetYLoc+targetHeight-1+maxRange, MAX_WORLD_Y_LOC-1);
296 int checkXLoc, checkYLoc;
297
298 //--------- do adjustment for UNIT_SEA and UNIT_AIR ---------//
299 if(mobile_type!=UNIT_LAND)
300 {
301 if(xLoc1%2)
302 xLoc1++;
303 if(yLoc1%2)
304 yLoc1++;
305 if(xLoc2%2)
306 xLoc2--;
307 if(yLoc2%2)
308 yLoc2--;
309 }
310
311 //-------- checking for surrounding location ----------//
312 switch(mobile_type)
313 {
314 case UNIT_LAND:
315 for(checkXLoc=xLoc1; checkXLoc<=xLoc2; checkXLoc++)
316 {
317 locPtr = world.get_loc(checkXLoc, yLoc1);
318 if(locPtr->region_id==regionId && locPtr->is_accessible(mobile_type))
319 return 1;
320
321 locPtr = world.get_loc(checkXLoc, yLoc2);
322 if(locPtr->region_id==regionId && locPtr->is_accessible(mobile_type))
323 return 1;
324 }
325
326 for(checkYLoc=yLoc1+1; checkYLoc<yLoc2; checkYLoc++)
327 {
328 locPtr = world.get_loc(xLoc1, checkYLoc);
329 if(locPtr->region_id==regionId && locPtr->is_accessible(mobile_type))
330 return 1;
331
332 locPtr = world.get_loc(xLoc2, checkYLoc);
333 if(locPtr->region_id==regionId && locPtr->is_accessible(mobile_type))
334 return 1;
335 }
336 break;
337
338 case UNIT_SEA:
339 for(checkXLoc=xLoc1; checkXLoc<=xLoc2; checkXLoc++)
340 {
341 if(checkXLoc%2==0 && yLoc1%2==0)
342 {
343 locPtr = world.get_loc(checkXLoc, yLoc1);
344 if(locPtr->region_id==regionId && locPtr->is_accessible(mobile_type))
345 return 1;
346 }
347
348 if(checkXLoc%2==0 && yLoc2%2==0)
349 {
350 locPtr = world.get_loc(checkXLoc, yLoc2);
351 if(locPtr->region_id==regionId && locPtr->is_accessible(mobile_type))
352 return 1;
353 }
354 }
355
356 for(checkYLoc=yLoc1+1; checkYLoc<yLoc2; checkYLoc++)
357 {
358 if(xLoc1%2==0 && checkYLoc%2==0)
359 {
360 locPtr = world.get_loc(xLoc1, checkYLoc);
361 if(locPtr->region_id==regionId && locPtr->is_accessible(mobile_type))
362 return 1;
363 }
364
365 if(xLoc2%2==0 && checkYLoc%2==0)
366 {
367 locPtr = world.get_loc(xLoc2, checkYLoc);
368 if(locPtr->region_id==regionId && locPtr->is_accessible(mobile_type))
369 return 1;
370 }
371 }
372 break;
373
374 case UNIT_AIR:
375 for(checkXLoc=xLoc1; checkXLoc<=xLoc2; checkXLoc++)
376 {
377 if(checkXLoc%2==0 && yLoc1%2==0)
378 {
379 locPtr = world.get_loc(checkXLoc, yLoc1);
380 if(locPtr->is_accessible(mobile_type))
381 return 1;
382 }
383
384 if(checkXLoc%2==0 && yLoc2%2==0)
385 {
386 locPtr = world.get_loc(checkXLoc, yLoc2);
387 if(locPtr->is_accessible(mobile_type))
388 return 1;
389 }
390 }
391
392 for(checkYLoc=yLoc1+1; checkYLoc<yLoc2; checkYLoc++)
393 {
394 if(xLoc1%2==0 && checkYLoc%2==0)
395 {
396 locPtr = world.get_loc(xLoc1, checkYLoc);
397 if(locPtr->is_accessible(mobile_type))
398 return 1;
399 }
400
401 if(xLoc2%2==0 && checkYLoc%2==0)
402 {
403 locPtr = world.get_loc(xLoc2, checkYLoc);
404 if(locPtr->is_accessible(mobile_type))
405 return 1;
406 }
407 }
408 break;
409
410 default: err_here();
411 break;
412 }
413
414 return 0;
415 }
416 //----------- End of function Unit::possible_place_for_range_attack -----------//
417
418
419 //=====================================================================================//
420 //--------- Begin of function Unit::space_for_attack ---------//
421 // check whether there is any place for the unit to attack target.
422 //
423 // <int> targetXLoc - target x location
424 // <int> targetYLoc - target y location
425 // <char> targetMobileType - target mobile type
426 // <int> targetWidth - target width
427 // <int> targetHeight - target height
428 //
space_for_attack(int targetXLoc,int targetYLoc,char targetMobileType,int targetWidth,int targetHeight)429 int Unit::space_for_attack(int targetXLoc, int targetYLoc, char targetMobileType, int targetWidth, int targetHeight)
430 {
431 if(mobile_type==UNIT_LAND && targetMobileType==UNIT_LAND)
432 return space_around_target(targetXLoc, targetYLoc, targetWidth, targetHeight);
433
434 if((mobile_type==UNIT_SEA && targetMobileType==UNIT_SEA) ||
435 (mobile_type==UNIT_AIR && targetMobileType==UNIT_AIR))
436 return space_around_target_ver2(targetXLoc, targetYLoc, targetWidth, targetHeight);
437
438 //-------------------------------------------------------------------------//
439 // mobile_type is differet from that of target unit
440 //-------------------------------------------------------------------------//
441 Location *locPtr = world.get_loc(next_x_loc(), next_y_loc());
442 if(mobile_type==UNIT_LAND && targetMobileType==UNIT_SEA &&
443 !can_attack_different_target_type() &&
444 ship_surr_has_free_land(targetXLoc, targetYLoc, locPtr->region_id))
445 return 1;
446
447 int maxRange = max_attack_range();
448 if(maxRange==1)
449 return 0;
450
451 if(free_space_for_range_attack(targetXLoc, targetYLoc, targetWidth, targetHeight, targetMobileType, maxRange))
452 return 1;
453
454 return 0;
455 }
456 //----------- End of function Unit::space_for_attack -----------//
457
458
459 //--------- Begin of function Unit::space_around_target ---------//
460 // check the surroundung location around a square, and the result is
461 // stored in the blocked_edge[] by bit
462 //
463 // <int> squareXLoc - upper left x location of target
464 // <int> squareYLoc - upper left y location of target
465 // <int> width - target width
466 // <int> height - target height
467 //
468 // return 1 if the surrounding location that can_move is not equal to
469 // the result in the blocked_edge stored previously.
470 // return 0 otherwise (i.e. all location situation is same as before)
471 //
space_around_target(int squareXLoc,int squareYLoc,int width,int height)472 int Unit::space_around_target(int squareXLoc, int squareYLoc, int width, int height)
473 {
474 err_when(width<=0 || height<=0);
475 // edge 1
476 // 1 1 4
477 // edge 2 2 x 4 edge 4
478 // 2 3 3
479 // edge3
480
481 Location *locPtr;
482 Unit *unitPtr;
483 char sum, locWeight;
484 int testXLoc, testYLoc, i, equal=1;
485
486 //------------------ top edge ---------------//
487 sum = 0;
488 if((testYLoc=squareYLoc-1) >= 0)
489 {
490 if(squareXLoc>=1) // have upper left corner
491 {
492 i=-1;
493 locWeight = 1;
494 }
495 else
496 {
497 i = 0;
498 locWeight = 2;
499 }
500
501 for(; i<width; i++, locWeight<<=1)
502 {
503 locPtr = world.get_loc(squareXLoc+i, testYLoc);
504 if(locPtr->can_move(mobile_type))
505 sum ^= locWeight;
506 else if(locPtr->has_unit(mobile_type))
507 {
508 unitPtr = unit_array[locPtr->unit_recno(mobile_type)];
509 if(unitPtr->cur_action!=SPRITE_ATTACK)
510 sum ^= locWeight;
511 }
512 }
513 }
514
515 if(blocked_edge[0]!=sum)
516 {
517 blocked_edge[0] = sum;
518 equal = 0;
519 }
520
521 //----------------- left edge -----------------//
522 sum = 0;
523 if((testXLoc=squareXLoc-1) >= 0)
524 {
525 if(squareYLoc+height<=MAX_WORLD_Y_LOC-1) // have lower left corner
526 {
527 i = height;
528 locWeight = 1;
529 }
530 else
531 {
532 i = height - 1;
533 locWeight = 2;
534 }
535
536 for(; i>=0; i--, locWeight<<=1)
537 {
538 locPtr = world.get_loc(testXLoc, squareYLoc+i);
539 if(locPtr->can_move(mobile_type))
540 sum ^= locWeight;
541 else if(locPtr->has_unit(mobile_type))
542 {
543 unitPtr = unit_array[locPtr->unit_recno(mobile_type)];
544 if(unitPtr->cur_action!=SPRITE_ATTACK)
545 sum ^= locWeight;
546 }
547 }
548 }
549
550 if(blocked_edge[1]!=sum)
551 {
552 blocked_edge[1] = sum;
553 equal = 0;
554 }
555
556 //------------------- bottom edge ------------------//
557 sum = 0;
558 if((testYLoc=squareYLoc+height) <= MAX_WORLD_Y_LOC-1)
559 {
560 if(squareXLoc+width<=MAX_WORLD_X_LOC-1) // have lower right corner
561 {
562 i = width;
563 locWeight = 1;
564 }
565 else
566 {
567 i = width - 1;
568 locWeight = 2;
569 }
570
571 for(; i>=0; i--, locWeight<<=1)
572 {
573 locPtr = world.get_loc(squareXLoc+i, testYLoc);
574 if(locPtr->can_move(mobile_type))
575 sum ^= locWeight;
576 else if(locPtr->has_unit(mobile_type))
577 {
578 unitPtr = unit_array[locPtr->unit_recno(mobile_type)];
579 if(unitPtr->cur_action!=SPRITE_ATTACK)
580 sum ^= locWeight;
581 }
582 }
583 }
584
585 if(blocked_edge[2]!=sum)
586 {
587 blocked_edge[2] = sum;
588 equal = 0;
589 }
590
591 //---------------------- right edge ----------------------//
592 sum = 0;
593 if((testXLoc=squareXLoc+width) <= MAX_WORLD_X_LOC-1)
594 {
595 if(squareYLoc>=1) // have upper right corner
596 {
597 i = -1;
598 locWeight = 1;
599 }
600 else
601 {
602 i = 0;
603 locWeight = 2;
604 }
605
606 for(; i<height; i++, locWeight<<=1)
607 {
608 locPtr = world.get_loc(testXLoc, squareYLoc+i);
609 if(locPtr->can_move(mobile_type))
610 sum ^= locWeight;
611 else if(locPtr->has_unit(mobile_type))
612 {
613 unitPtr = unit_array[locPtr->unit_recno(mobile_type)];
614 if(unitPtr->cur_action!=SPRITE_ATTACK)
615 sum ^= locWeight;
616 }
617 }
618 }
619
620 if(blocked_edge[3]!=sum)
621 {
622 blocked_edge[3] = sum;
623 equal = 0;
624 }
625
626 return !equal;
627 }
628 //----------- End of function Unit::space_around_target -----------//
629
630
631 //--------- Begin of function Unit::space_around_target_ver2 ---------//
632 // similar function as space_around_target()
633 // This version is for sea unit and air unit only
634 //
space_around_target_ver2(int targetXLoc,int targetYLoc,int targetWidth,int targetHeight)635 int Unit::space_around_target_ver2(int targetXLoc, int targetYLoc, int targetWidth, int targetHeight)
636 {
637 err_when(targetWidth<=0 || targetHeight<=0);
638
639 Location *locPtr;
640 Unit *unitPtr;
641 char sum, locWeight;
642 int xLoc1, yLoc1, xLoc2, yLoc2;
643 int i, equal=1;
644 //int testXLoc, testYLoc,
645
646 xLoc1 = targetXLoc%2 ? targetXLoc-1 : targetXLoc-2;
647 yLoc1 = targetYLoc%2 ? targetYLoc-1 : targetYLoc-2;
648 xLoc2 = (targetXLoc+targetWidth-1)%2 ? targetXLoc+targetWidth : targetXLoc+targetWidth+1;
649 yLoc2 = (targetYLoc+targetHeight-1)%2 ? targetYLoc+targetHeight : targetYLoc+targetHeight+1;
650
651 //------------------------ top edge ------------------------//
652 sum = 0;
653 if(yLoc1>=0)
654 {
655 if(xLoc1>=0)
656 {
657 i = xLoc1;
658 locWeight = 1;
659 }
660 else
661 {
662 i = xLoc1 + 2;
663 err_when(i<0);
664 locWeight = 2;
665 }
666
667 for(; i<=xLoc2; i+=2, locWeight<<=1)
668 {
669 locPtr = world.get_loc(i, yLoc1);
670 if(locPtr->can_move(mobile_type))
671 sum ^= locWeight;
672 else if(locPtr->has_unit(mobile_type))
673 {
674 unitPtr = unit_array[locPtr->unit_recno(mobile_type)];
675 if(unitPtr->cur_action!=SPRITE_ATTACK)
676 sum ^= locWeight;
677 }
678 }
679 }
680
681 if(blocked_edge[0]!=sum)
682 {
683 blocked_edge[0] = sum;
684 equal = 0;
685 }
686
687 //---------------------- left edge -----------------------//
688 sum = 0;
689 if(xLoc1>=0)
690 {
691 if(yLoc2<=MAX_WORLD_Y_LOC-1)
692 {
693 i = yLoc2;
694 locWeight = 1;
695 }
696 else
697 {
698 i = yLoc2-2;
699 err_when(i>=MAX_WORLD_Y_LOC);
700 locWeight = 2;
701 }
702
703 for(; i>yLoc1; i-=2, locWeight<<=1)
704 {
705 locPtr = world.get_loc(xLoc1, i);
706 if(locPtr->can_move(mobile_type))
707 sum ^= locWeight;
708 else if(locPtr->has_unit(mobile_type))
709 {
710 unitPtr = unit_array[locPtr->unit_recno(mobile_type)];
711 if(unitPtr->cur_action!=SPRITE_ATTACK)
712 sum ^= locWeight;
713 }
714 }
715 }
716
717 if(blocked_edge[1]!=sum)
718 {
719 blocked_edge[1] = sum;
720 equal = 0;
721 }
722
723 //----------------------- bottom edge ---------------------------//
724 sum = 0;
725 if(yLoc2<=MAX_WORLD_Y_LOC-1)
726 {
727 if(xLoc2<=MAX_WORLD_X_LOC-1)
728 {
729 i = xLoc2;
730 locWeight = 1;
731 }
732 else
733 {
734 i = xLoc2-2;
735 err_when(i>=MAX_WORLD_X_LOC);
736 locWeight = 2;
737 }
738
739 for(; i>xLoc1; i-=2, locWeight<<=1)
740 {
741 locPtr = world.get_loc(i, yLoc2);
742 if(locPtr->can_move(mobile_type))
743 sum ^= locWeight;
744 else if(locPtr->has_unit(mobile_type))
745 {
746 unitPtr = unit_array[locPtr->unit_recno(mobile_type)];
747 if(unitPtr->cur_action!=SPRITE_ATTACK)
748 sum ^= locWeight;
749 }
750 }
751 }
752
753 if(blocked_edge[2]!=sum)
754 {
755 blocked_edge[2] = sum;
756 equal = 0;
757 }
758
759 //---------------------- right edge ------------------------//
760 sum = 0;
761 if(xLoc2<=MAX_WORLD_X_LOC-1)
762 {
763 if(yLoc1>=0)
764 {
765 i = yLoc1;
766 locWeight = 1;
767 }
768 else
769 {
770 i = yLoc1+2;
771 err_when(i<0);
772 locWeight = 2;
773 }
774
775 for(; i<yLoc2; i+=2, locWeight<<=1)
776 {
777 locPtr = world.get_loc(xLoc2, i);
778 if(locPtr->can_move(mobile_type))
779 sum ^= locWeight;
780 else if(locPtr->has_unit(mobile_type))
781 {
782 unitPtr = unit_array[locPtr->unit_recno(mobile_type)];
783 if(unitPtr->cur_action!=SPRITE_ATTACK)
784 sum ^= locWeight;
785 }
786 }
787 }
788
789 if(blocked_edge[3]!=sum)
790 {
791 blocked_edge[3] = sum;
792 equal = 0;
793 }
794
795 return !equal;
796 }
797 //----------- End of function Unit::space_around_target_ver2 -----------//
798
799
800 //--------- Begin of function Unit::ship_surr_has_free_land ---------//
801 // check surrounding place for close attack by land units
802 //
803 // <int> targetXLoc - target x loc
804 // <int> targetYLoc - target y loc
805 // <uint8_t> regionId - region id
806 //
807 // return 1 if there is space for the land unit to move to ship surrounding for close attack
808 // return 0 otherwise
809 //
ship_surr_has_free_land(int targetXLoc,int targetYLoc,uint8_t regionId)810 int Unit::ship_surr_has_free_land(int targetXLoc, int targetYLoc, uint8_t regionId)
811 {
812 err_when(mobile_type!=UNIT_LAND);
813 Location *locPtr;
814 int xShift, yShift, checkXLoc, checkYLoc;
815
816 for(int i=2; i<9; i++)
817 {
818 misc.cal_move_around_a_point(i, 3, 3, xShift, yShift);
819 checkXLoc = targetXLoc+xShift;
820 checkYLoc = targetYLoc+yShift;
821
822 if(checkXLoc<0 || checkXLoc>=MAX_WORLD_X_LOC || checkYLoc<0 || checkYLoc>=MAX_WORLD_Y_LOC)
823 continue;
824
825 locPtr = world.get_loc(checkXLoc, checkYLoc);
826 if(locPtr->region_id==regionId && locPtr->can_move(mobile_type))
827 return 1;
828 }
829
830 return 0;
831 }
832 //----------- End of function Unit::ship_surr_has_free_land -----------//
833
834
835 //--------- Begin of function Unit::free_space_for_range_attack ---------//
836 // similar to possible_place_for_range_attack() but checking can_move() rather than is_accessible()
837 //
free_space_for_range_attack(int targetXLoc,int targetYLoc,int targetWidth,int targetHeight,int targetMobileType,int maxRange)838 int Unit::free_space_for_range_attack(int targetXLoc, int targetYLoc, int targetWidth, int targetHeight, int targetMobileType, int maxRange)
839 {
840 err_when(targetXLoc<0 || targetXLoc>=MAX_WORLD_X_LOC || targetYLoc<0 || targetYLoc>=MAX_WORLD_Y_LOC);
841 err_when(maxRange==0);
842
843 //if(mobile_type==UNIT_AIR)
844 // return 1; // air unit can reach any region
845
846 int curXLoc = next_x_loc();
847 int curYLoc = next_y_loc();
848
849 if(abs(curXLoc-targetXLoc)<=maxRange && abs(curYLoc-targetYLoc)<=maxRange) // inside the attack range
850 return 1;
851
852 Location *locPtr = world.get_loc(curXLoc, curYLoc);
853 int regionId = locPtr->region_id;
854 int xLoc1 = MAX(targetXLoc-maxRange, 0);
855 int yLoc1 = MAX(targetYLoc-maxRange, 0);
856 int xLoc2 = MIN(targetXLoc+targetWidth-1+maxRange, MAX_WORLD_X_LOC-1);
857 int yLoc2 = MIN(targetYLoc+targetHeight-1+maxRange, MAX_WORLD_Y_LOC-1);
858 int checkXLoc, checkYLoc;
859
860 //--------- do adjustment for UNIT_SEA and UNIT_AIR ---------//
861 if(mobile_type!=UNIT_LAND)
862 {
863 if(xLoc1%2)
864 xLoc1++;
865 if(yLoc1%2)
866 yLoc1++;
867 if(xLoc2%2)
868 xLoc2--;
869 if(yLoc2%2)
870 yLoc2--;
871 }
872
873 //-------- checking for surrounding location ----------//
874 switch(mobile_type)
875 {
876 case UNIT_LAND:
877 for(checkXLoc=xLoc1; checkXLoc<=xLoc2; checkXLoc++)
878 {
879 locPtr = world.get_loc(checkXLoc, yLoc1);
880 if(locPtr->region_id==regionId && locPtr->can_move(mobile_type))
881 return 1;
882
883 locPtr = world.get_loc(checkXLoc, yLoc2);
884 if(locPtr->region_id==regionId && locPtr->can_move(mobile_type))
885 return 1;
886 }
887
888 for(checkYLoc=yLoc1+1; checkYLoc<yLoc2; checkYLoc++)
889 {
890 locPtr = world.get_loc(xLoc1, checkYLoc);
891 if(locPtr->region_id==regionId && locPtr->can_move(mobile_type))
892 return 1;
893
894 locPtr = world.get_loc(xLoc2, checkYLoc);
895 if(locPtr->region_id==regionId && locPtr->can_move(mobile_type))
896 return 1;
897 }
898 break;
899
900 case UNIT_SEA:
901 for(checkXLoc=xLoc1; checkXLoc<=xLoc2; checkXLoc++)
902 {
903 if(checkXLoc%2==0 && yLoc1%2==0)
904 {
905 locPtr = world.get_loc(checkXLoc, yLoc1);
906 if(locPtr->region_id==regionId && locPtr->can_move(mobile_type))
907 return 1;
908 }
909
910 if(checkXLoc%2==0 && yLoc2%2==0)
911 {
912 locPtr = world.get_loc(checkXLoc, yLoc2);
913 if(locPtr->region_id==regionId && locPtr->can_move(mobile_type))
914 return 1;
915 }
916 }
917
918 for(checkYLoc=yLoc1+1; checkYLoc<yLoc2; checkYLoc++)
919 {
920 if(xLoc1%2==0 && checkYLoc%2==0)
921 {
922 locPtr = world.get_loc(xLoc1, checkYLoc);
923 if(locPtr->region_id==regionId && locPtr->can_move(mobile_type))
924 return 1;
925 }
926
927 if(xLoc2%2==0 && checkYLoc%2==0)
928 {
929 locPtr = world.get_loc(xLoc2, checkYLoc);
930 if(locPtr->region_id==regionId && locPtr->can_move(mobile_type))
931 return 1;
932 }
933 }
934 break;
935
936 case UNIT_AIR:
937 for(checkXLoc=xLoc1; checkXLoc<=xLoc2; checkXLoc++)
938 {
939 if(checkXLoc%2==0 && yLoc1%2==0)
940 {
941 locPtr = world.get_loc(checkXLoc, yLoc1);
942 if(locPtr->can_move(mobile_type))
943 return 1;
944 }
945
946 if(checkXLoc%2==0 && yLoc2%2==0)
947 {
948 locPtr = world.get_loc(checkXLoc, yLoc2);
949 if(locPtr->can_move(mobile_type))
950 return 1;
951 }
952 }
953
954 for(checkYLoc=yLoc1+1; checkYLoc<yLoc2; checkYLoc++)
955 {
956 if(xLoc1%2==0 && checkYLoc%2==0)
957 {
958 locPtr = world.get_loc(xLoc1, checkYLoc);
959 if(locPtr->can_move(mobile_type))
960 return 1;
961 }
962
963 if(xLoc2%2==0 && checkYLoc%2==0)
964 {
965 locPtr = world.get_loc(xLoc2, checkYLoc);
966 if(locPtr->can_move(mobile_type))
967 return 1;
968 }
969 }
970 break;
971
972 default: err_here();
973 break;
974 }
975
976 return 0;
977 }
978 //----------- End of function Unit::free_space_for_range_attack -----------//