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 : OUNITAAT.CPP
22 //Description : Object UnitArray - part 2
23
24 #include <ALL.h>
25 #include <OVGA.h>
26 #include <OSYS.h>
27 #include <OSTR.h>
28 #include <OREMOTE.h>
29 #include <OWORLD.h>
30 #include <ONATION.h>
31 #include <OFIRM.h>
32 #include <OTOWN.h>
33 #include <OTERRAIN.h>
34 #include <OU_MARI.h>
35
36 #ifdef NO_DEBUG_UNIT
37 #undef err_when
38 #undef err_here
39 #undef err_if
40 #undef err_else
41 #undef err_now
42 #define err_when(cond)
43 #define err_here()
44 #define err_if(cond)
45 #define err_else
46 #define err_now(msg)
47 #undef DEBUG
48 #endif
49
50 //------ static variables for attacking ------//
51 // ATTACK_DIR is defined in OUNIT.H
52 #define MAX_TARGET_SIZE 4
53 #define MAX_UNIT_SURROUND_SIZE MAX_TARGET_SIZE+2 // handle the case up to target size 4x4
54 #define SHIFT_ADJUST 1 // since the upper left offset position is (-1, -1)
55 static short *unit_processed_array; // store those processed unit sprite_recno
56 static short unit_processed_count; // count the number processed units
57 static short *dir_array_ptr[ATTACK_DIR]; // store units' sprite_recno in each direction
58 static short dir_array_count[ATTACK_DIR]; // num of unit in each direction
59 static char unreachable_table[MAX_UNIT_SURROUND_SIZE][MAX_UNIT_SURROUND_SIZE]; // table shared for all attackers
60
61 //************* debug ***************//
62 #ifdef DEBUG
63 //--------------------------------------------------------------------------------//
64 // <int> resultNum - the num of free space around the target
65 // <int> width - width of target
66 // <int> height - height of target
67 //--------------------------------------------------------------------------------//
debug_analyse_result_check(int resultNum,int width,int height)68 static void debug_analyse_result_check(int resultNum, int width, int height)
69 {
70 int count=0, i, j;
71 for(i=0; i<width+2; i++)
72 {
73 if(unreachable_table[i][0]==0)
74 count++;
75 }
76
77 i = width+1;
78 for(j=1; j<height+2; j++)
79 {
80 if(unreachable_table[i][j]==0)
81 count++;
82 }
83
84 for(j=1; j<height+2; j++)
85 {
86 if(unreachable_table[0][j]==0)
87 count++;
88 }
89
90 j = height+1;
91 for(i=1; i<width+1; i++)
92 {
93 if(unreachable_table[i][j]==0)
94 count++;
95 }
96
97 err_when(count!=resultNum);
98 }
99 #endif
100
101 #ifdef DEBUG
102 #define debug_result_check(resultNum, width, height) debug_analyse_result_check(resultNum, width, height)
103 #else
104 #define debug_result_check(resultNum, width, height)
105 #endif
106 //************* debug ***************//
107
108
109 //--------- Begin of function UnitArray::get_target_surround_loc ---------//
110 // <int> targetWidth - target width
111 // <int> targetHeight - target height
112 //
get_target_surround_loc(int targetWidth,int targetHeight)113 char UnitArray::get_target_surround_loc(int targetWidth, int targetHeight)
114 {
115 static char surround_loc[MAX_TARGET_SIZE][MAX_TARGET_SIZE] // width, height
116 = { { 8, 10, 12, 14}, {10, 12, 14, 16}, {12, 14, 16, 18}, {14, 16, 18, 20}};
117
118 return surround_loc[targetWidth-1][targetHeight-1];
119 }
120 //----------- End of function UnitArray::get_target_surround_loc -----------//
121
122
123 //--------- Begin of function UnitArray::update_unreachable_table ---------//
124 // check target surroundig to drop those unreachable location
125 //
126 // <int> targetXLoc - target x location
127 // <int> targetYLoc - target y location
128 // <int> targetWidth - target width
129 // <int> targetHeight - target height
130 // <char> mobileType - mobile type of the attacker
131 // <int&> analyseResult - reference for returning num of reachable location
132 //
update_unreachable_table(int targetXLoc,int targetYLoc,int targetWidth,int targetHeight,char mobileType,int & analyseResult)133 void UnitArray::update_unreachable_table(int targetXLoc, int targetYLoc, int targetWidth, int targetHeight,
134 char mobileType, int &analyseResult)
135 {
136 int xLoc1, yLoc1, xLoc2, yLoc2, i;
137
138 //----------------------------------------------------------------------//
139 // checking for left & right edges, calculate location and counter
140 //----------------------------------------------------------------------//
141 xLoc1 = targetXLoc-1;
142 xLoc2 = targetXLoc+targetWidth;
143
144 if(targetYLoc==0)
145 {
146 i = targetHeight+1;
147 yLoc1=targetYLoc;
148 }
149 else
150 {
151 i = targetHeight+2;
152 yLoc1=targetYLoc-1;
153 }
154
155 if(targetYLoc+targetHeight>=MAX_WORLD_Y_LOC)
156 i--;
157
158 for(yLoc2=yLoc1-targetYLoc+SHIFT_ADJUST; i>0; i--, yLoc1++, yLoc2++)
159 {
160 //---- left edge ----//
161 if(xLoc1>=0 && !unreachable_table[0][yLoc2] && !world.get_loc(xLoc1, yLoc1)->can_move(mobileType))
162 {
163 unreachable_table[0][yLoc2] = 1;
164 analyseResult--;
165 }
166
167 //----- right edge -----//
168 if(xLoc2<MAX_WORLD_X_LOC && !unreachable_table[targetWidth+1][yLoc2] &&
169 !world.get_loc(xLoc2, yLoc1)->can_move(mobileType))
170 {
171 unreachable_table[targetWidth+1][yLoc2] = 1;
172 analyseResult--;
173 }
174
175 if(!analyseResult)
176 return;
177 }
178
179 //----------------------------------------------------------------------//
180 // checking for the top and bottom edges
181 //----------------------------------------------------------------------//
182 yLoc1 = targetYLoc-1;
183 yLoc2 = targetYLoc+targetHeight;
184 for(i=0, xLoc1=targetXLoc, xLoc2=xLoc1-targetXLoc+SHIFT_ADJUST; i<targetWidth; i++, xLoc1++, xLoc2++)
185 {
186 //---- top edge ----//
187 if(yLoc1>=0 && !unreachable_table[xLoc2][0] && !world.get_loc(xLoc1, yLoc1)->can_move(mobileType))
188 {
189 unreachable_table[xLoc2][0] = 1;
190 analyseResult--;
191 }
192
193 //----- bottom edge -----//
194 if(yLoc2<MAX_WORLD_Y_LOC && !unreachable_table[xLoc2][targetHeight+1] &&
195 !world.get_loc(xLoc1, yLoc2)->can_move(mobileType))
196 {
197 unreachable_table[xLoc2][targetHeight+1] = 1;
198 analyseResult--;
199 }
200
201 if(!analyseResult)
202 return;
203 }
204
205 debug_result_check(analyseResult, targetWidth, targetHeight);
206 err_when(analyseResult<0);
207 }
208 //----------- End of function UnitArray::update_unreachable_table -----------//
209
210
211 //--------- Begin of function UnitArray::attack ---------//
212 //
213 // Order the unit to attack a specific location.
214 //
215 // <int> targetXLoc, targetYLoc - target location
216 // <int> divided - whether the units are divided
217 // <short*> selectedUnitArray - an array of recno of selected units.
218 // <int> selectedCount - no. of selected units.
219 // [char] remoteAction - whether this is an action carried out by a remote machine or not.
220 // (default: 0)
221 // <int> targetUnitRecno - if it is unit, pass the unit recno, otherwise 0
222 //
attack(int targetXLoc,int targetYLoc,int divided,short * selectedUnitArray,int selectedCount,char remoteAction,int targetUnitRecno)223 void UnitArray::attack(int targetXLoc, int targetYLoc, int divided, short* selectedUnitArray, int selectedCount, char remoteAction, int targetUnitRecno)
224 {
225 err_when(targetXLoc<0 || targetYLoc<0 || targetXLoc>=MAX_WORLD_X_LOC || targetYLoc>=MAX_WORLD_Y_LOC);
226
227 // ######## patch begin Gilbert 5/8 #########//
228
229 int targetNationRecno = 0;
230
231 if( targetUnitRecno == 0 )
232 {
233 // unit determined from the location
234
235 int tmpMobileType;
236 Location* locPtr = world.get_loc(targetXLoc, targetYLoc);
237 targetUnitRecno = locPtr->get_any_unit(tmpMobileType) ;
238 }
239 else
240 {
241 // location determined by the unit
242 Unit *unitPtr;
243 if( !unit_array.is_deleted(targetUnitRecno)
244 && (unitPtr = unit_array[targetUnitRecno])
245 && unitPtr->is_visible() )
246 {
247 targetXLoc = unitPtr->next_x_loc();
248 targetYLoc = unitPtr->next_y_loc();
249 if( unitPtr->unit_id != UNIT_EXPLOSIVE_CART ) // attacking own porcupine is allowed
250 targetNationRecno = unitPtr->nation_recno;
251 }
252 else
253 targetUnitRecno = 0;
254 }
255
256 if( targetUnitRecno == 0 )
257 {
258 //--- set the target coordination to the top left position of the town/firm ---//
259
260 Location* locPtr = world.get_loc(targetXLoc, targetYLoc);
261
262 //---- if there is a firm on this location -----//
263
264 if( locPtr->is_firm() )
265 {
266 Firm* firmPtr = firm_array[locPtr->firm_recno()];
267
268 targetXLoc = firmPtr->loc_x1;
269 targetYLoc = firmPtr->loc_y1;
270 targetNationRecno = firmPtr->nation_recno;
271 }
272
273 //---- if there is a town on this location -----//
274
275 else if( locPtr->is_town() )
276 {
277 Town* townPtr = town_array[locPtr->town_recno()];
278
279 targetXLoc = townPtr->loc_x1;
280 targetYLoc = townPtr->loc_y1;
281 targetNationRecno = townPtr->nation_recno;
282 }
283
284 else
285 return;
286 }
287 // ######## patch end Gilbert 5/8 #########//
288
289 //--------- AI debug code ---------//
290
291 //--- AI attacking a nation which its NationRelation::should_attack is 0 ---//
292
293 Unit* attackUnit = unit_array[ selectedUnitArray[0] ];
294
295 if( attackUnit->nation_recno && targetNationRecno )
296 {
297 if( nation_array[attackUnit->nation_recno]->get_relation(targetNationRecno)->should_attack==0 )
298 return;
299 }
300
301 //-------- if it's a multiplayer game --------//
302 if( !remoteAction && remote.is_enable() )
303 {
304 short* shortPtr = (short*) remote.new_send_queue_msg(MSG_UNIT_ATTACK, sizeof(short) * (5+selectedCount) );
305
306 shortPtr[0] = targetXLoc;
307 shortPtr[1] = targetYLoc;
308 shortPtr[2] = targetUnitRecno;
309 shortPtr[3] = selectedCount;
310 shortPtr[4] = divided;
311
312 memcpy( shortPtr+5, selectedUnitArray, sizeof(short) * selectedCount );
313 }
314 else
315 {
316 if(!divided)
317 {
318 divide_array(targetXLoc, targetYLoc, selectedUnitArray, selectedCount, 1); // 1 for excluding the recno in target location
319
320 Location* locPtr = world.get_loc(targetXLoc, targetYLoc);
321 int targetMobileType = locPtr->has_any_unit();
322
323 if(selected_land_unit_count)
324 attack_call(targetXLoc, targetYLoc, UNIT_LAND, targetMobileType, 1, selected_land_unit_array, selected_land_unit_count, targetUnitRecno);
325
326 if(selected_sea_unit_count)
327 attack_call(targetXLoc, targetYLoc, UNIT_SEA, targetMobileType, 1, selected_sea_unit_array, selected_sea_unit_count, targetUnitRecno);
328
329 if(selected_air_unit_count)
330 attack_call(targetXLoc, targetYLoc, UNIT_AIR, targetMobileType, 1, selected_air_unit_array, selected_air_unit_count, targetUnitRecno);
331
332 selected_land_unit_count = selected_sea_unit_count = selected_air_unit_count = 0;
333 mem_del(selected_land_unit_array);
334 mem_del(selected_sea_unit_array);
335 mem_del(selected_air_unit_array);
336 return;
337 }
338 else
339 err_here();
340 }
341 }
342 //----------- End of function UnitArray::attack -----------//
343
344
345 //--------- Begin of function UnitArray::attack_call ---------//
346 // <int> targetXLoc - target x location
347 // <int> targetYLoc - target y location
348 // <char> mobileType - attacker's mobile type
349 // <char> targetMobileType - target mobile type
350 // <int> divided - whether the units are divided
351 // <short*> selectedUnitArray - selected units' recno.
352 // <int> selectedCount - num of selected units
353 //
attack_call(int targetXLoc,int targetYLoc,char mobileType,char targetMobileType,int divided,short * selectedUnitArray,int selectedCount,int targetUnitRecno)354 void UnitArray::attack_call(int targetXLoc, int targetYLoc, char mobileType, char targetMobileType, int divided, short* selectedUnitArray, int selectedCount, int targetUnitRecno)
355 {
356 //------------- attack now -------------//
357 err_when( selectedCount > 10000 );
358
359 Location* locPtr = world.get_loc(targetXLoc, targetYLoc);
360 err_when(!locPtr);
361
362 // ##### patch begin Gilbert 5/8 ######//
363 //if(targetMobileType)
364 if( targetUnitRecno && !unit_array.is_deleted(targetUnitRecno) )
365 {
366 //---------------- attack unit --------------//
367 //Unit *targetUnit = unit_array[locPtr->unit_recno(targetMobileType)];
368 Unit *targetUnit = unit_array[targetUnitRecno];
369 if(!targetUnit->is_visible() || targetUnit->hit_points<=0)
370 return;
371
372 // short targetUnitRecno = targetUnit->sprite_recno;
373 attack_unit(targetXLoc, targetYLoc, targetUnitRecno, selectedUnitArray, selectedCount);
374 }
375 // ##### patch end Gilbert 5/8 ######//
376 else if(locPtr->is_firm())
377 {
378 //------------------ attack firm -------------------//
379 Firm *firmPtr = firm_array[locPtr->firm_recno()];
380 err_when(!firmPtr);
381 if(firmPtr->hit_points<=0)
382 return;
383
384 attack_firm(targetXLoc, targetYLoc, firmPtr->firm_recno, selectedUnitArray, selectedCount);
385 }
386 else if(locPtr->is_town())
387 {
388 //-------------------- attack town -------------------//
389 Town *townPtr = town_array[locPtr->town_recno()];
390 err_when(!townPtr);
391 attack_town(targetXLoc, targetYLoc, townPtr->town_recno, selectedUnitArray, selectedCount);
392 }
393 else if(locPtr->is_wall())
394 {
395 //------------------ attack wall ---------------------//
396 attack_wall(targetXLoc, targetYLoc, selectedUnitArray, selectedCount);
397 }
398 else
399 return; // no target for attacking
400 }
401 //----------- End of function UnitArray::attack_call -----------//
402
403
404 //--------- Begin of function UnitArray::attack_unit ---------//
405 // <int> targetXLoc, targetYLoc - the unit upper left location
406 // <short> targetunitRecno - the unit recno
407 //
408 // Note : this attack function only for attackers with size 1x1.
409 //
attack_unit(int targetXLoc,int targetYLoc,short targetUnitRecno,short * selectedUnitArray,int selectedCount)410 void UnitArray::attack_unit(int targetXLoc, int targetYLoc, short targetUnitRecno, short* selectedUnitArray, int selectedCount)
411 {
412 err_when(selectedCount<=0);
413 if(selectedCount==1)
414 {
415 Unit *unitPtr = (Unit*) get_ptr(selectedUnitArray[0]);
416 unitPtr->unit_group_id = unit_array.cur_group_id++;
417 unitPtr->attack_unit(targetXLoc, targetYLoc);
418 return;
419 }
420
421 //********************** improve later begin **************************//
422 //---------------------------------------------------------------------//
423 // codes for differnt territory or different mobile_type attacking should
424 // be added in the future.
425 //---------------------------------------------------------------------//
426 Unit *firstUnitPtr = unit_array[selectedUnitArray[0]];
427 Unit *targetPtr2 = unit_array[targetUnitRecno];
428 if( (world.get_loc(targetXLoc, targetYLoc)->region_id !=
429 world.get_loc(firstUnitPtr->next_x_loc(), firstUnitPtr->next_y_loc())->region_id) ||
430 (targetPtr2->mobile_type!=firstUnitPtr->mobile_type) )
431 {
432 Unit *unitPtr;
433 set_group_id(selectedUnitArray, selectedCount);
434
435 for(int i=0; i<selectedCount; i++)
436 {
437 unitPtr = (Unit*) get_ptr(selectedUnitArray[i]);
438 unitPtr->attack_unit(targetXLoc, targetYLoc);
439 }
440 return;
441 }
442 //*********************** improve later end ***************************//
443
444 //----------- initialize local parameters ------------//
445 Unit *targetPtr = unit_array[targetUnitRecno];
446 int targetWidth = targetPtr->sprite_info->loc_width;
447 int targetHeight = targetPtr->sprite_info->loc_height;
448 int targetXLoc2 = targetXLoc + targetWidth - 1;
449 int targetYLoc2 = targetYLoc + targetHeight - 1;
450 char surroundLoc = get_target_surround_loc(targetWidth, targetHeight);
451 char *xOffsetPtr = get_target_x_offset(targetWidth, targetHeight, 0);
452 char *yOffsetPtr = get_target_y_offset(targetWidth, targetHeight, 0);
453
454 //---------------------------------------------------------------------//
455 // construct data structure
456 //---------------------------------------------------------------------//
457 int tempVar = sizeof(short)*selectedCount;
458
459 memset(dir_array_count, 0, sizeof(dir_array_count));
460 int count;
461 for(count=0; count<ATTACK_DIR; count++)
462 {
463 dir_array_ptr[count] = (short*) mem_add(tempVar);
464 memset(dir_array_ptr[count], 0, tempVar);
465 }
466
467 unit_processed_array = (short *)mem_add(tempVar);
468 unit_processed_count = 0;
469
470 //---------------------------------------------------------------------//
471 // divide the units into each region
472 //---------------------------------------------------------------------//
473 Unit *unitPtr = (Unit*) get_ptr(selectedUnitArray[0]);
474 err_when(!unitPtr);
475 uint32_t groupId = unit_array.cur_group_id++;
476 arrange_units_in_group(targetXLoc, targetYLoc, targetXLoc2, targetYLoc2, selectedUnitArray, selectedCount, groupId, 1);
477
478 //---------------------------------------------------------------------//
479 // now the attackers are divided into 8 groups to attack the target
480 //---------------------------------------------------------------------//
481 int xLoc, yLoc; // actual target surrounding location to move to
482 int xOffset, yOffset; // offset location of the target
483 int unprocessed; // number of units in this group
484 int dist, xDist, yDist, minDist;
485 int destCount;
486 short unitPos; // store the position of the unit with minDist
487 short *curArrayPtr;
488
489 int i;
490 for(i=0; i<MAX_UNIT_SURROUND_SIZE; i++)
491 memset(unreachable_table[i], 0, sizeof(char)*MAX_UNIT_SURROUND_SIZE);
492
493 //---------------------------------------------------------------------//
494 // anaylse the surrounding location of the target
495 //---------------------------------------------------------------------//
496 int analyseResult = analyse_surround_location(targetXLoc, targetYLoc, targetWidth, targetHeight, targetPtr->mobile_type);
497 debug_result_check(analyseResult, targetWidth, targetHeight);
498 err_when(analyseResult<0);
499
500 if(!analyseResult) // 0 if all surround location is not accessible
501 {
502 //------------------------------------------------------------//
503 // special handling for this case
504 //------------------------------------------------------------//
505 handle_attack_target_totally_blocked(targetXLoc, targetYLoc, targetUnitRecno, selectedUnitArray, selectedCount, 1);
506
507 for(count=0; count<ATTACK_DIR; count++)
508 mem_del(dir_array_ptr[count]);
509
510 mem_del(unit_processed_array);
511 return;
512 }
513
514 //---------------------------------------------------------------------//
515 // let the units move to the rest accessible location
516 //---------------------------------------------------------------------//
517 for(count=0; count<ATTACK_DIR; count++) // for each array/group
518 {
519 //--------- initialize for each group --------//
520 unprocessed = dir_array_count[count]; // get the number of units in this region
521 if(!unprocessed)
522 continue;
523
524 destCount = surroundLoc-1;
525 curArrayPtr = dir_array_ptr[count]; // get the recno of units in this region
526
527 xOffsetPtr = get_target_x_offset(targetWidth, targetHeight, count);
528 yOffsetPtr = get_target_y_offset(targetWidth, targetHeight, count);
529 xOffset = *xOffsetPtr;
530 yOffset = *yOffsetPtr;
531
532 //-----------------------------------------------------------------//
533 // determine a suitable location for the attacker to move to
534 //-----------------------------------------------------------------//
535 while(unprocessed)
536 {
537 //-----------------------------------------------------//
538 // find a reachable location, or not searched location
539 //-----------------------------------------------------//
540 err_when(analyseResult<0);
541 if(!analyseResult)
542 {
543 handle_attack_target_totally_blocked(targetXLoc, targetYLoc, targetUnitRecno, selectedUnitArray, selectedCount, 1);
544
545 for(count=0; count<ATTACK_DIR; count++)
546 mem_del(dir_array_ptr[count]);
547
548 mem_del(unit_processed_array);
549 return;
550 }
551 else
552 {
553 for(i=0; i<surroundLoc; i++)
554 {
555 if((++destCount)>=surroundLoc)
556 {
557 destCount = 0;
558 xOffsetPtr = get_target_x_offset(targetWidth, targetHeight, count);
559 yOffsetPtr = get_target_y_offset(targetWidth, targetHeight, count);
560 xOffset = *xOffsetPtr;
561 yOffset = *yOffsetPtr;
562 }
563 else
564 {
565 xOffset = *(++xOffsetPtr);
566 yOffset = *(++yOffsetPtr);
567 }
568
569 if(!unreachable_table[xOffset+SHIFT_ADJUST][yOffset+SHIFT_ADJUST])
570 break;
571 }
572 }
573
574 err_when(unreachable_table[xOffset+SHIFT_ADJUST][yOffset+SHIFT_ADJUST]);
575
576 //------------------------------------------------------------//
577 // find the closest attacker
578 //------------------------------------------------------------//
579 err_when(unprocessed>2000 || unprocessed <0);
580 xLoc = targetXLoc + xOffset;
581 yLoc = targetYLoc + yOffset;
582 err_when(!world.get_loc(xLoc, yLoc)->can_move(targetPtr->mobile_type));
583
584 for(i=0, minDist=0x7FFFFFF; i<unprocessed; i++)
585 {
586 unitPtr = (Unit*) get_ptr(curArrayPtr[i]);
587 xDist = abs(xLoc-unitPtr->next_x_loc());
588 yDist = abs(yLoc-unitPtr->next_y_loc());
589 dist = (xDist >= yDist) ? xDist*10+yDist : yDist*10+xDist;
590
591 if(dist < minDist)
592 {
593 minDist = dist;
594 unitPos = i;
595 }
596 }
597
598 unitPtr = (Unit*) get_ptr(curArrayPtr[unitPos]);
599 curArrayPtr[unitPos] = curArrayPtr[--unprocessed]; // move the units in the back to the front
600
601 err_when(unitPtr->action_mode2!=ACTION_ATTACK_WALL &&
602 unitPtr->cur_action==SPRITE_ATTACK && unitPtr->action_para==0);
603 seek_path.set_status(PATH_WAIT);
604 err_when(seek_path.path_status==PATH_NODE_USED_UP);
605 unitPtr->attack_unit(targetXLoc, targetYLoc, xOffset, yOffset);
606
607 //------------------------------------------------------------//
608 // store the unit sprite_recno in the array
609 //------------------------------------------------------------//
610 unit_processed_array[unit_processed_count++] = unitPtr->sprite_recno;
611
612 //------------------------------------------------------------//
613 // set the flag if unreachable
614 //------------------------------------------------------------//
615 if(seek_path.path_status==PATH_NODE_USED_UP)
616 {
617 unreachable_table[xLoc-targetXLoc+SHIFT_ADJUST][yLoc-targetYLoc+SHIFT_ADJUST] = 1;
618 analyseResult--;
619 debug_result_check(analyseResult, targetWidth, targetHeight);
620 err_when(analyseResult<0);
621
622 //------------------------------------------------------------//
623 // the nearby location should also be unreachable
624 //------------------------------------------------------------//
625 check_nearby_location(targetXLoc, targetYLoc, xOffset, yOffset, targetWidth, targetHeight,
626 targetPtr->mobile_type, analyseResult);
627 }
628
629 update_unreachable_table(targetXLoc, targetYLoc, targetWidth, targetHeight, unitPtr->mobile_type, analyseResult);
630
631 #ifdef DEBUG
632 for(int di=0; di<targetWidth+2; di++)
633 {
634 for(int dj=0; dj<targetHeight+2; dj++)
635 {
636 if(di>=1 && di<=targetWidth && dj>=1 && dj<=targetHeight)
637 continue;
638
639 int debugXLoc = targetXLoc+di-SHIFT_ADJUST;
640 int debugYLoc = targetYLoc+dj-SHIFT_ADJUST;
641 if(debugXLoc<0 || debugXLoc>=MAX_WORLD_X_LOC || debugYLoc<0 || debugYLoc>=MAX_WORLD_Y_LOC)
642 continue;
643
644 Location *dlPtr = world.get_loc(debugXLoc, debugYLoc);
645
646 err_when(!dlPtr->can_move(targetPtr->mobile_type) && unreachable_table[di][dj]==0);
647 }
648 }
649 #endif
650 }
651 }
652
653 //---------------------------------------------------------------------//
654 // set the unreachable flag for each units
655 //---------------------------------------------------------------------//
656 //-************** codes here ***************-//
657
658 //---------------------------------------------------------------------//
659 // destruct data structure
660 //---------------------------------------------------------------------//
661 for(count=0; count<ATTACK_DIR; count++)
662 mem_del(dir_array_ptr[count]);
663
664 mem_del(unit_processed_array);
665 }
666 //----------- End of function UnitArray::attack_unit -----------//
667
668
669 //--------- Begin of function UnitArray::attack_firm ---------//
670 // <int> targetXLoc, targetYLoc - the firm upper left location
671 // <short> firmRecno - the firm recno
672 //
673 // try to calculate the best location for each unit to move to the
674 // surrounding of the firm for attacking
675 //
attack_firm(int targetXLoc,int targetYLoc,short firmRecno,short * selectedUnitArray,int selectedCount)676 void UnitArray::attack_firm(int targetXLoc, int targetYLoc, short firmRecno, short* selectedUnitArray, int selectedCount)
677 {
678 err_when(selectedCount<=0);
679 if(selectedCount==1)
680 {
681 Unit *unitPtr = (Unit*) get_ptr(selectedUnitArray[0]);
682 unitPtr->unit_group_id = unit_array.cur_group_id++;
683 unitPtr->attack_firm(targetXLoc, targetYLoc);
684 return;
685 }
686
687 //********************** improve later begin **************************//
688 //---------------------------------------------------------------------//
689 // codes for differnt territory or different mobile_type attacking should
690 // be added in the future.
691 //---------------------------------------------------------------------//
692 Unit *firstUnitPtr = unit_array[selectedUnitArray[0]];
693 if(world.get_loc(targetXLoc, targetYLoc)->region_id !=
694 world.get_loc(firstUnitPtr->next_x_loc(), firstUnitPtr->next_y_loc())->region_id)
695 {
696 Unit *unitPtr;
697 set_group_id(selectedUnitArray, selectedCount);
698
699 for(int i=0; i<selectedCount; i++)
700 {
701 unitPtr = (Unit*) get_ptr(selectedUnitArray[i]);
702 unitPtr->attack_firm(targetXLoc, targetYLoc);
703 }
704 return;
705 }
706 //*********************** improve later end ***************************//
707
708 //----------- initialize local parameters ------------//
709 Firm *firmPtr = firm_array[firmRecno];
710 FirmInfo *firmInfo = firm_res[firmPtr->firm_id];
711 int firmWidth = firmInfo->loc_width;
712 int firmHeight = firmInfo->loc_height;
713 int targetXLoc2 = targetXLoc + firmWidth - 1; // the lower right corner of the firm
714 int targetYLoc2 = targetYLoc + firmHeight -1;
715 char *xOffsetPtr, *yOffsetPtr;
716
717 //---------------------------------------------------------------------//
718 // construct data structure
719 //---------------------------------------------------------------------//
720 int tempVar = sizeof(short)*selectedCount;
721
722 memset(dir_array_count, 0, sizeof(dir_array_count));
723 int count;
724 for(count=0; count<ATTACK_DIR; count++)
725 {
726 dir_array_ptr[count] = (short*) mem_add(tempVar);
727 memset(dir_array_ptr[count], 0, tempVar);
728 }
729
730 unit_processed_array = (short *)mem_add(tempVar);
731 unit_processed_count = 0;
732
733 //---------------------------------------------------------------------//
734 // divide the units into each region
735 //---------------------------------------------------------------------//
736 Unit *unitPtr = (Unit*) get_ptr(selectedUnitArray[0]);
737 err_when(!unitPtr);
738 uint32_t groupId = unit_array.cur_group_id++;
739 arrange_units_in_group(targetXLoc, targetYLoc, targetXLoc2, targetYLoc2, selectedUnitArray, selectedCount, groupId, 2);
740
741 //---------------------------------------------------------------------//
742 // now the attackers are divided into 8 groups to attack the target
743 //---------------------------------------------------------------------//
744 int xLoc, yLoc; // actual target surrounding location to move to
745 int xOffset, yOffset; // offset location of the target
746 int unprocessed; // number of units in this group
747 int destCount;
748 int dist, xDist, yDist, minDist;
749 short unitPos; // store the position of the unit with minDist
750 short *curArrayPtr;
751 char surroundLoc = get_target_surround_loc(firmWidth, firmHeight);
752
753 int i;
754 for(i=0; i<MAX_UNIT_SURROUND_SIZE; i++)
755 memset(unreachable_table[i], 0, sizeof(char)*MAX_UNIT_SURROUND_SIZE);
756
757 //---------------------------------------------------------------------//
758 // analyse the surrounding location of the target
759 //---------------------------------------------------------------------//
760 int analyseResult = analyse_surround_location(targetXLoc, targetYLoc, firmWidth, firmHeight, unitPtr->mobile_type);
761 debug_result_check(analyseResult, firmWidth, firmHeight);
762 err_when(analyseResult<0);
763
764 if(!analyseResult) // 0 if all surround location is not accessible
765 {
766 //------------------------------------------------------------//
767 // special handling for this case
768 //------------------------------------------------------------//
769 handle_attack_target_totally_blocked(targetXLoc, targetYLoc, firmRecno, selectedUnitArray, selectedCount, 2);
770
771 for(count=0; count<ATTACK_DIR; count++)
772 mem_del(dir_array_ptr[count]);
773
774 mem_del(unit_processed_array);
775 return;
776 }
777
778 //---------------------------------------------------------------------//
779 // let the units move to the rest accessible location
780 //---------------------------------------------------------------------//
781 for(count=0; count<ATTACK_DIR; count++) // for each array/group
782 {
783 //--------- initialize for each group --------//
784 unprocessed = dir_array_count[count]; // get the number of units in this region
785 curArrayPtr = dir_array_ptr[count]; // get the recno of units in this region
786 destCount = surroundLoc - 1;
787 xOffsetPtr = get_target_x_offset(firmWidth, firmHeight, count);
788 yOffsetPtr = get_target_y_offset(firmWidth, firmHeight, count);
789 xOffset = *xOffsetPtr;
790 yOffset = *yOffsetPtr;
791
792 //-----------------------------------------------------------------//
793 // determine a suitable location for the attacker to move to
794 //-----------------------------------------------------------------//
795 err_when(unprocessed>2000 || unprocessed <0);
796 while(unprocessed)
797 {
798 //-----------------------------------------------------//
799 // find a reachable location, or not searched location
800 //-----------------------------------------------------//
801 err_when(analyseResult<0);
802
803 if(!analyseResult)
804 {
805 handle_attack_target_totally_blocked(targetXLoc, targetYLoc, firmRecno, selectedUnitArray, selectedCount, 2);
806
807 for(count=0; count<ATTACK_DIR; count++)
808 mem_del(dir_array_ptr[count]);
809
810 mem_del(unit_processed_array);
811 return;
812 }
813 else
814 {
815 for(i=0; i<surroundLoc; i++)
816 {
817 if((++destCount)>=surroundLoc)
818 {
819 destCount = 0;
820 xOffsetPtr = get_target_x_offset(firmWidth, firmHeight, count);
821 yOffsetPtr = get_target_y_offset(firmWidth, firmHeight, count);
822 xOffset = *xOffsetPtr;
823 yOffset = *yOffsetPtr;
824 }
825 else
826 {
827 xOffset = *(++xOffsetPtr);
828 yOffset = *(++yOffsetPtr);
829 }
830
831 if(!unreachable_table[xOffset+SHIFT_ADJUST][yOffset+SHIFT_ADJUST])
832 break;
833 }
834 }
835
836 err_when(unreachable_table[xOffset+SHIFT_ADJUST][yOffset+SHIFT_ADJUST]);
837
838 //------------------------------------------------------------//
839 // find the closest attacker
840 //------------------------------------------------------------//
841 err_when(unprocessed>2000 || unprocessed <0);
842 xLoc = targetXLoc + xOffset;
843 yLoc = targetYLoc + yOffset;
844 err_when(!world.get_loc(xLoc, yLoc)->can_move(unitPtr->mobile_type));
845
846 for(i=0, minDist=0x7FFFFFF; i<unprocessed; i++)
847 {
848 unitPtr = (Unit*) get_ptr(curArrayPtr[i]);
849 xDist = abs(xLoc-unitPtr->next_x_loc());
850 yDist = abs(yLoc-unitPtr->next_y_loc());
851 dist = (xDist >= yDist) ? xDist*10+yDist : yDist*10+xDist;
852
853 if(dist < minDist)
854 {
855 minDist = dist;
856 unitPos = i;
857 }
858 }
859
860 unitPtr = (Unit*) get_ptr(curArrayPtr[unitPos]);
861 curArrayPtr[unitPos] = curArrayPtr[--unprocessed]; // move the units in the back to the front
862
863 err_when(unitPtr->action_mode2!=ACTION_ATTACK_WALL &&
864 unitPtr->cur_action==SPRITE_ATTACK && unitPtr->action_para==0);
865 seek_path.set_status(PATH_WAIT);
866 err_when(seek_path.path_status==PATH_NODE_USED_UP);
867 unitPtr->attack_firm(targetXLoc, targetYLoc, xOffset, yOffset);
868
869 //------------------------------------------------------------//
870 // set the flag if unreachable
871 //------------------------------------------------------------//
872 if(seek_path.path_status==PATH_NODE_USED_UP)
873 {
874 unreachable_table[xOffset+SHIFT_ADJUST][yOffset+SHIFT_ADJUST] = 1;
875 analyseResult--;
876 debug_result_check(analyseResult, firmWidth, firmHeight);
877 err_when(analyseResult<0);
878
879 //------------------------------------------------------------//
880 // the nearby location should also be unreachable
881 //------------------------------------------------------------//
882 check_nearby_location(targetXLoc, targetYLoc, xOffset, yOffset, firmWidth, firmHeight,
883 unitPtr->mobile_type, analyseResult);
884 }
885
886 update_unreachable_table(targetXLoc, targetYLoc, firmWidth, firmHeight, unitPtr->mobile_type, analyseResult);
887
888 #ifdef DEBUG
889 for(int di=0; di<firmWidth+2; di++)
890 {
891 for(int dj=0; dj<firmHeight+2; dj++)
892 {
893 if(di>=1 && di<=firmWidth && dj>=1 && dj<=firmHeight)
894 continue;
895
896 int debugXLoc = targetXLoc+di-SHIFT_ADJUST;
897 int debugYLoc = targetYLoc+dj-SHIFT_ADJUST;
898 if(debugXLoc<0 || debugXLoc>=MAX_WORLD_X_LOC || debugYLoc<0 || debugYLoc>=MAX_WORLD_Y_LOC)
899 continue;
900
901 Location *dlPtr = world.get_loc(debugXLoc, debugYLoc);
902
903 err_when(!dlPtr->can_move(unitPtr->mobile_type) && unreachable_table[di][dj]==0);
904 }
905 }
906 #endif
907 }
908 }
909
910 //---------------------------------------------------------------------//
911 // set the unreachable flag for each units
912 //---------------------------------------------------------------------//
913 //-************** codes here ***************-//
914
915 //---------------------------------------------------------------------//
916 // destruct data structure
917 //---------------------------------------------------------------------//
918 for(count=0; count<ATTACK_DIR; count++)
919 mem_del(dir_array_ptr[count]);
920
921 mem_del(unit_processed_array);
922 }
923 //----------- End of function UnitArray::attack_firm -----------//
924
925
926 //--------- Begin of function UnitArray::attack_town ---------//
927 // <int> targetXLoc, targetYLoc - the town upper left location
928 // <short> townRecno - the town recno
929 //
930 // try to calculate the best location for each unit to move to the
931 // surrounding of the town for attacking
932 //
attack_town(int targetXLoc,int targetYLoc,short townRecno,short * selectedUnitArray,int selectedCount)933 void UnitArray::attack_town(int targetXLoc, int targetYLoc, short townRecno, short* selectedUnitArray, int selectedCount)
934 {
935 err_when(selectedCount<=0);
936 if(selectedCount==1)
937 {
938 Unit *unitPtr = (Unit*) get_ptr(selectedUnitArray[0]);
939 unitPtr->unit_group_id = unit_array.cur_group_id++;
940 unitPtr->attack_town(targetXLoc, targetYLoc);
941 return;
942 }
943
944 //********************** improve later begin **************************//
945 //---------------------------------------------------------------------//
946 // codes for differnt territory or different mobile_type attacking should
947 // be added in the future.
948 //---------------------------------------------------------------------//
949 Unit *firstUnitPtr = unit_array[selectedUnitArray[0]];
950 if(world.get_loc(targetXLoc, targetYLoc)->region_id !=
951 world.get_loc(firstUnitPtr->next_x_loc(), firstUnitPtr->next_y_loc())->region_id)
952 {
953 Unit *unitPtr;
954 set_group_id(selectedUnitArray, selectedCount);
955
956 for(int i=0; i<selectedCount; i++)
957 {
958 unitPtr = (Unit*) get_ptr(selectedUnitArray[i]);
959 unitPtr->attack_town(targetXLoc, targetYLoc);
960 }
961 return;
962 }
963 //*********************** improve later end ***************************//
964
965 //----------- initialize local parameters ------------//
966 int targetXLoc2 = targetXLoc + STD_TOWN_LOC_WIDTH - 1; // the lower right corner of the firm
967 int targetYLoc2 = targetYLoc + STD_TOWN_LOC_HEIGHT - 1;
968 char *xOffsetPtr, *yOffsetPtr;
969
970 //---------------------------------------------------------------------//
971 // construct data structure
972 //---------------------------------------------------------------------//
973 int tempVar = sizeof(short)*selectedCount;
974
975 memset(dir_array_count, 0, sizeof(dir_array_count));
976 int count;
977 for(count=0; count<ATTACK_DIR; count++)
978 {
979 dir_array_ptr[count] = (short*) mem_add(tempVar);
980 memset(dir_array_ptr[count], 0, tempVar);
981 }
982
983 unit_processed_array = (short *)mem_add(tempVar);
984 unit_processed_count = 0;
985
986 //---------------------------------------------------------------------//
987 // divide the units into each region
988 //---------------------------------------------------------------------//
989 Unit *unitPtr = (Unit*) get_ptr(selectedUnitArray[0]);
990 err_when(!unitPtr);
991 uint32_t groupId = unit_array.cur_group_id++;
992 arrange_units_in_group(targetXLoc, targetYLoc, targetXLoc2, targetYLoc2, selectedUnitArray, selectedCount, groupId, 3);
993
994 //---------------------------------------------------------------------//
995 // now the attackers are divided into 8 groups to attack the target
996 //---------------------------------------------------------------------//
997 int xLoc, yLoc; // actual target surrounding location to move to
998 int xOffset, yOffset; // offset location of the target
999 int unprocessed; // number of units in this group
1000 int dist, xDist, yDist, minDist;
1001 int destCount;
1002 short unitPos; // store the position of the unit with minDist
1003 short *curArrayPtr;
1004 char surroundLoc = get_target_surround_loc(STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT);
1005
1006 int i;
1007 for(i=0; i<MAX_UNIT_SURROUND_SIZE; i++)
1008 memset(unreachable_table[i], 0, sizeof(char)*MAX_UNIT_SURROUND_SIZE);
1009
1010 //---------------------------------------------------------------------//
1011 // analyse the surrounding location of the target
1012 //---------------------------------------------------------------------//
1013 int analyseResult = analyse_surround_location(targetXLoc, targetYLoc, STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT, unitPtr->mobile_type);
1014 debug_result_check(analyseResult, STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT);
1015 err_when(analyseResult<0);
1016
1017 if(!analyseResult) // 0 if all surround location is not accessible
1018 {
1019 //------------------------------------------------------------//
1020 // special handling for this case
1021 //------------------------------------------------------------//
1022 handle_attack_target_totally_blocked(targetXLoc, targetYLoc, townRecno, selectedUnitArray, selectedCount, 3);
1023
1024 for(count=0; count<ATTACK_DIR; count++)
1025 mem_del(dir_array_ptr[count]);
1026
1027 mem_del(unit_processed_array);
1028 return;
1029 }
1030
1031 //---------------------------------------------------------------------//
1032 // let the units move to the rest accessible location
1033 //---------------------------------------------------------------------//
1034 for(count=0; count<ATTACK_DIR; count++) // for each array/group
1035 {
1036 //--------- initialize for each group --------//
1037 unprocessed = dir_array_count[count]; // get the number of units in this region
1038 curArrayPtr = dir_array_ptr[count]; // get the recno of units in this region
1039 destCount = surroundLoc-1;
1040 xOffsetPtr = get_target_x_offset(STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT, count);
1041 yOffsetPtr = get_target_y_offset(STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT, count);
1042 xOffset = *xOffsetPtr;
1043 yOffset = *yOffsetPtr;
1044
1045 //-----------------------------------------------------------------//
1046 // determine a suitable location for the attacker to move to
1047 //-----------------------------------------------------------------//
1048 while(unprocessed)
1049 {
1050 //-----------------------------------------------------//
1051 // find a reachable location, or not searched location
1052 //-----------------------------------------------------//
1053 if(!analyseResult)
1054 {
1055 handle_attack_target_totally_blocked(targetXLoc, targetYLoc, townRecno, selectedUnitArray, selectedCount, 3);
1056
1057 for(count=0; count<ATTACK_DIR; count++)
1058 mem_del(dir_array_ptr[count]);
1059
1060 mem_del(unit_processed_array);
1061 return;
1062 }
1063 else
1064 {
1065 for(i=0; i<surroundLoc; i++)
1066 {
1067 if((++destCount)>=surroundLoc)
1068 {
1069 destCount = 0;
1070 xOffsetPtr = get_target_x_offset(STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT, count);
1071 yOffsetPtr = get_target_y_offset(STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT, count);
1072 xOffset = *xOffsetPtr;
1073 yOffset = *yOffsetPtr;
1074 }
1075 else
1076 {
1077 xOffset = *(++xOffsetPtr);
1078 yOffset = *(++yOffsetPtr);
1079 }
1080
1081 if(!unreachable_table[xOffset+SHIFT_ADJUST][yOffset+SHIFT_ADJUST])
1082 break;
1083 }
1084 }
1085
1086 err_when(unreachable_table[xOffset+SHIFT_ADJUST][yOffset+SHIFT_ADJUST]);
1087
1088 //------------------------------------------------------------//
1089 // find the closest attacker
1090 //------------------------------------------------------------//
1091 err_when(unprocessed>2000 || unprocessed <0);
1092 xLoc = targetXLoc + xOffset;
1093 yLoc = targetYLoc + yOffset;
1094 err_when(!world.get_loc(xLoc, yLoc)->can_move(unitPtr->mobile_type));
1095
1096 for(i=0, minDist=0x7FFFFFF; i<unprocessed; i++)
1097 {
1098 unitPtr = (Unit*) get_ptr(curArrayPtr[i]);
1099 xDist = abs(xLoc-unitPtr->next_x_loc());
1100 yDist = abs(yLoc-unitPtr->next_y_loc());
1101 dist = (xDist >= yDist) ? xDist*10+yDist : yDist*10+xDist;
1102
1103 if(dist < minDist)
1104 {
1105 minDist = dist;
1106 unitPos = i;
1107 }
1108 }
1109
1110 unitPtr = (Unit*) get_ptr(curArrayPtr[unitPos]);
1111 curArrayPtr[unitPos] = curArrayPtr[--unprocessed]; // move the units in the back to the front
1112
1113 err_when(unitPtr->action_mode2!=ACTION_ATTACK_WALL &&
1114 unitPtr->cur_action==SPRITE_ATTACK && unitPtr->action_para==0);
1115 seek_path.set_status(PATH_WAIT);
1116 err_when(seek_path.path_status==PATH_NODE_USED_UP);
1117 unitPtr->attack_town(targetXLoc, targetYLoc, xOffset, yOffset);
1118
1119 //------------------------------------------------------------//
1120 // set the flag if unreachable
1121 //------------------------------------------------------------//
1122 if(seek_path.path_status==PATH_NODE_USED_UP)
1123 {
1124 unreachable_table[xOffset+SHIFT_ADJUST][yOffset+SHIFT_ADJUST] = 1;
1125 analyseResult--;
1126 debug_result_check(analyseResult, STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT);
1127 err_when(analyseResult<0);
1128
1129 //------------------------------------------------------------//
1130 // the nearby location should also be unreachable
1131 //------------------------------------------------------------//
1132 check_nearby_location(targetXLoc, targetYLoc, xOffset, yOffset, STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT,
1133 unitPtr->mobile_type, analyseResult);
1134 }
1135
1136 update_unreachable_table(targetXLoc, targetYLoc, STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT, unitPtr->mobile_type, analyseResult);
1137
1138 #ifdef DEBUG
1139 Location *dlPtr;
1140 for(int di=0; di<STD_TOWN_LOC_WIDTH+2; di++)
1141 {
1142 for(int dj=0; dj<STD_TOWN_LOC_HEIGHT+2; dj++)
1143 {
1144 if(di>=1 && di<=STD_TOWN_LOC_WIDTH && dj>=1 && dj<=STD_TOWN_LOC_HEIGHT)
1145 continue;
1146
1147 int debugXLoc = targetXLoc+di-SHIFT_ADJUST;
1148 int debugYLoc = targetYLoc+dj-SHIFT_ADJUST;
1149 if(debugXLoc<0 || debugXLoc>=MAX_WORLD_X_LOC || debugYLoc<0 || debugYLoc>=MAX_WORLD_Y_LOC)
1150 continue;
1151
1152 dlPtr = world.get_loc(debugXLoc, debugYLoc);
1153
1154 err_when(!dlPtr->can_move(unitPtr->mobile_type) && unreachable_table[di][dj]==0);
1155 }
1156 }
1157 #endif
1158 }
1159 }
1160
1161 //---------------------------------------------------------------------//
1162 // set the unreachable flag for each units
1163 //---------------------------------------------------------------------//
1164 //-************** codes here ***************-//
1165
1166 //---------------------------------------------------------------------//
1167 // destruct data structure
1168 //---------------------------------------------------------------------//
1169 for(count=0; count<ATTACK_DIR; count++)
1170 mem_del(dir_array_ptr[count]);
1171
1172 mem_del(unit_processed_array);
1173 }
1174 //----------- End of function UnitArray::attack_town -----------//
1175
1176
1177 //--------- Begin of function UnitArray::attack_wall ---------//
1178 // <int> targetXLoc - x location of the wall
1179 // <int> targetYLoc - y location of the wall
1180 //
attack_wall(int targetXLoc,int targetYLoc,short * selectedUnitArray,int selectedCount)1181 void UnitArray::attack_wall(int targetXLoc, int targetYLoc, short* selectedUnitArray, int selectedCount)
1182 {
1183 err_when(selectedCount<=0);
1184 if(selectedCount==1)
1185 {
1186 Unit *unitPtr = (Unit*) get_ptr(selectedUnitArray[0]);
1187 unitPtr->unit_group_id = unit_array.cur_group_id++;
1188 unitPtr->attack_wall(targetXLoc, targetYLoc);
1189 return;
1190 }
1191
1192 //********************** improve later begin **************************//
1193 //---------------------------------------------------------------------//
1194 // codes for differnt territory or different mobile_type attacking should
1195 // be added in the future.
1196 //---------------------------------------------------------------------//
1197 Unit *firstUnitPtr = unit_array[selectedUnitArray[0]];
1198 if(world.get_loc(targetXLoc, targetYLoc)->region_id !=
1199 world.get_loc(firstUnitPtr->next_x_loc(), firstUnitPtr->next_y_loc())->region_id)
1200 {
1201 Unit *unitPtr;
1202 set_group_id(selectedUnitArray, selectedCount);
1203
1204 for(int i=0; i<selectedCount; i++)
1205 {
1206 unitPtr = (Unit*) get_ptr(selectedUnitArray[i]);
1207 unitPtr->attack_wall(targetXLoc, targetYLoc);
1208 }
1209 return;
1210 }
1211 //*********************** improve later end ***************************//
1212
1213 //----------- initialize local parameters ------------//
1214 char *xOffsetPtr, *yOffsetPtr;
1215
1216 //---------------------------------------------------------------------//
1217 // construct data structure
1218 //---------------------------------------------------------------------//
1219 int tempVar = sizeof(short)*selectedCount;
1220
1221 memset(dir_array_count, 0, sizeof(dir_array_count));
1222 int count;
1223 for(count=0; count<ATTACK_DIR; count++)
1224 {
1225 dir_array_ptr[count] = (short*) mem_add(tempVar);
1226 memset(dir_array_ptr[count], 0, tempVar);
1227 }
1228
1229 unit_processed_array = (short *)mem_add(tempVar);
1230 unit_processed_count = 0;
1231
1232 //---------------------------------------------------------------------//
1233 // divide the units into each region
1234 //---------------------------------------------------------------------//
1235 Unit *unitPtr = (Unit*) get_ptr(selectedUnitArray[0]);
1236 err_when(!unitPtr);
1237 uint32_t groupId = unit_array.cur_group_id++;
1238 arrange_units_in_group(targetXLoc, targetYLoc, targetXLoc, targetYLoc, selectedUnitArray, selectedCount, groupId, 0);
1239
1240 //---------------------------------------------------------------------//
1241 // now the attackers are divided into 8 groups to attack the target
1242 //---------------------------------------------------------------------//
1243 int xLoc, yLoc; // actual target surrounding location to move to
1244 int xOffset, yOffset; // offset location of the target
1245 int unprocessed; // number of units in this group
1246 int dist, xDist, yDist, minDist;
1247 int destCount;
1248 short unitPos; // store the position of the unit with minDist
1249 short *curArrayPtr;
1250 char surroundLoc = get_target_surround_loc(1, 1);
1251
1252 int i;
1253 for(i=0; i<MAX_UNIT_SURROUND_SIZE; i++)
1254 memset(unreachable_table[i], 0, sizeof(char)*MAX_UNIT_SURROUND_SIZE);
1255
1256 //---------------------------------------------------------------------//
1257 // analyse the surrounding location of the target
1258 //---------------------------------------------------------------------//
1259 int analyseResult = analyse_surround_location(targetXLoc, targetYLoc, 1, 1, unitPtr->mobile_type);
1260 debug_result_check(analyseResult, 1, 1);
1261 err_when(analyseResult<0);
1262
1263 if(!analyseResult) // 0 if all surround location is not accessible
1264 {
1265 //------------------------------------------------------------//
1266 // special handling for this case
1267 //------------------------------------------------------------//
1268 handle_attack_target_totally_blocked(targetXLoc, targetYLoc, 0, selectedUnitArray, selectedCount, 0);
1269
1270 for(count=0; count<ATTACK_DIR; count++)
1271 mem_del(dir_array_ptr[count]);
1272
1273 mem_del(unit_processed_array);
1274 return;
1275 }
1276
1277 //---------------------------------------------------------------------//
1278 // let the units move to the rest accessible location
1279 //---------------------------------------------------------------------//
1280 for(count=0; count<ATTACK_DIR; count++) // for each array/group
1281 {
1282 //--------- initialize for each group --------//
1283 unprocessed = dir_array_count[count]; // get the number of units in this region
1284 curArrayPtr = dir_array_ptr[count]; // get the recno of units in this region
1285 destCount = surroundLoc-1;
1286 xOffsetPtr = get_target_x_offset(1, 1, count);
1287 yOffsetPtr = get_target_y_offset(1, 1, count);
1288 xOffset = *xOffsetPtr;
1289 yOffset = *yOffsetPtr;
1290
1291 //-----------------------------------------------------------------//
1292 // determine a suitable location for the attacker to move to
1293 //-----------------------------------------------------------------//
1294 while(unprocessed)
1295 {
1296 //-----------------------------------------------------//
1297 // find a reachable location, or not searched location
1298 //-----------------------------------------------------//
1299 if(!analyseResult)
1300 {
1301 handle_attack_target_totally_blocked(targetXLoc, targetYLoc, 0, selectedUnitArray, selectedCount, 0);
1302
1303 for(count=0; count<ATTACK_DIR; count++)
1304 mem_del(dir_array_ptr[count]);
1305
1306 mem_del(unit_processed_array);
1307 return;
1308 }
1309 else
1310 {
1311 for(i=0; i<surroundLoc; i++)
1312 {
1313 if((++destCount)>=surroundLoc)
1314 {
1315 destCount = 0;
1316 xOffsetPtr = get_target_x_offset(1, 1, count);
1317 yOffsetPtr = get_target_y_offset(1, 1, count);
1318 xOffset = *xOffsetPtr;
1319 yOffset = *yOffsetPtr;
1320 }
1321 else
1322 {
1323 xOffset = *(++xOffsetPtr);
1324 yOffset = *(++yOffsetPtr);
1325 }
1326
1327 if(!unreachable_table[xOffset+SHIFT_ADJUST][yOffset+SHIFT_ADJUST])
1328 break;
1329 }
1330 }
1331
1332 err_when(unreachable_table[xOffset+SHIFT_ADJUST][yOffset+SHIFT_ADJUST]);
1333
1334 //------------------------------------------------------------//
1335 // find the closest attacker
1336 //------------------------------------------------------------//
1337 err_when(unprocessed>2000 || unprocessed <0);
1338 xLoc = targetXLoc + xOffset;
1339 yLoc = targetYLoc + yOffset;
1340 err_when(!world.get_loc(xLoc, yLoc)->can_move(unitPtr->mobile_type));
1341
1342 for(i=0, minDist=0x7FFFFFF; i<unprocessed; i++)
1343 {
1344 unitPtr = (Unit*) get_ptr(curArrayPtr[i]);
1345 xDist = abs(xLoc-unitPtr->next_x_loc());
1346 yDist = abs(yLoc-unitPtr->next_y_loc());
1347 dist = (xDist >= yDist) ? xDist*10+yDist : yDist*10+xDist;
1348
1349 if(dist < minDist)
1350 {
1351 minDist = dist;
1352 unitPos = i;
1353 }
1354 }
1355
1356 unitPtr = (Unit*) get_ptr(curArrayPtr[unitPos]);
1357 curArrayPtr[unitPos] = curArrayPtr[--unprocessed]; // move the units in the back to the front
1358
1359 err_when(unitPtr->action_mode2!=ACTION_ATTACK_WALL &&
1360 unitPtr->cur_action==SPRITE_ATTACK && unitPtr->action_para==0);
1361 seek_path.set_status(PATH_WAIT);
1362 err_when(seek_path.path_status==PATH_NODE_USED_UP);
1363 unitPtr->attack_wall(targetXLoc, targetYLoc, xOffset, yOffset);
1364
1365 //------------------------------------------------------------//
1366 // set the flag if unreachable
1367 //------------------------------------------------------------//
1368 if(seek_path.path_status==PATH_NODE_USED_UP)
1369 {
1370 unreachable_table[xOffset+SHIFT_ADJUST][yOffset+SHIFT_ADJUST] = 1;
1371 analyseResult--;
1372 debug_result_check(analyseResult, 1, 1);
1373 err_when(analyseResult<0);
1374 //------------------------------------------------------------//
1375 // the nearby location should also be unreachable
1376 //------------------------------------------------------------//
1377 check_nearby_location(targetXLoc, targetYLoc, xOffset, yOffset, 1, 1, unitPtr->mobile_type, analyseResult);
1378 }
1379
1380 update_unreachable_table(targetXLoc, targetYLoc, 1, 1, unitPtr->mobile_type, analyseResult);
1381
1382 #ifdef DEBUG
1383 for(int di=0; di<3; di++)
1384 {
1385 for(int dj=0; dj<3; dj++)
1386 {
1387 if(di==1 && dj==1)
1388 continue;
1389
1390 int debugXLoc = targetXLoc+di-SHIFT_ADJUST;
1391 int debugYLoc = targetYLoc+dj-SHIFT_ADJUST;
1392 if(debugXLoc<0 || debugXLoc>=MAX_WORLD_X_LOC || debugYLoc<0 || debugYLoc>=MAX_WORLD_Y_LOC)
1393 continue;
1394
1395 Location *dlPtr = world.get_loc(debugXLoc, debugYLoc);
1396
1397 err_when(!dlPtr->can_move(unitPtr->mobile_type) && unreachable_table[di][dj]==0);
1398 }
1399 }
1400 #endif
1401 }
1402 }
1403
1404 //---------------------------------------------------------------------//
1405 // set the unreachable flag for each units
1406 //---------------------------------------------------------------------//
1407 //-************** codes here ***************-//
1408
1409 //---------------------------------------------------------------------//
1410 // destruct data structure
1411 //---------------------------------------------------------------------//
1412 for(count=0; count<ATTACK_DIR; count++)
1413 mem_del(dir_array_ptr[count]);
1414
1415 mem_del(unit_processed_array);
1416 }
1417 //----------- End of function UnitArray::attack_wall -----------//
1418
1419
1420 //--------- Begin of function UnitArray::arrange_units_in_group ---------//
1421 // <int> xLoc1 - top left x location of the target
1422 // <int> yLoc1 - top left y location of the target
1423 // <int> xLoc2 - bottom right x location of the target
1424 // <int> yLoc2 - bottom right y location of the target
1425 // <short*> selectedUnitArray - recno. of selected units
1426 // <int> selectedCount - count of selected units
1427 // <uint32_t> unitGroupId - group id for the selected units
1428 //
1429 // <int> targetType - 0 for wall, 1 for unit, 2 for firm, 3 for town
1430 //
arrange_units_in_group(int xLoc1,int yLoc1,int xLoc2,int yLoc2,short * selectedUnitArray,int selectedCount,uint32_t unitGroupId,int targetType)1431 void UnitArray::arrange_units_in_group(int xLoc1, int yLoc1, int xLoc2, int yLoc2, short* selectedUnitArray,
1432 int selectedCount, uint32_t unitGroupId, int targetType)
1433 {
1434 Unit *unitPtr;
1435 int curXLoc, curYLoc;
1436
1437 for(int i=0; i<selectedCount; i++)
1438 {
1439 unitPtr = (Unit*) get_ptr(selectedUnitArray[i]);
1440 err_when(!unitPtr);
1441
1442 unitPtr->unit_group_id = unitGroupId; // set unit_group_id
1443 err_when(unitPtr->cur_action==SPRITE_IDLE && (unitPtr->cur_x!=unitPtr->next_x || unitPtr->cur_y!=unitPtr->next_y));
1444 if(unitPtr->cur_action==SPRITE_IDLE)
1445 unitPtr->set_ready();
1446
1447 curXLoc = unitPtr->next_x_loc();
1448 curYLoc = unitPtr->next_y_loc();
1449 if(curXLoc>=xLoc1-1 && curXLoc<=xLoc2+1 && curYLoc>=yLoc1-1 && curYLoc<=yLoc2+1)
1450 {
1451 //------------- already in the target surrounding ----------------//
1452 switch(targetType)
1453 {
1454 case 0: unitPtr->attack_wall(xLoc1, yLoc1);
1455 break;
1456
1457 case 1: unitPtr->attack_unit(xLoc1, yLoc1);
1458 break;
1459
1460 case 2: unitPtr->attack_firm(xLoc1, yLoc1);
1461 break;
1462
1463 case 3: unitPtr->attack_town(xLoc1, yLoc1);
1464 break;
1465 }
1466 continue;
1467 }
1468
1469 //---- the attacker need to call searching to reach the target ----//
1470 if(curXLoc < xLoc1)
1471 {
1472 if(curYLoc < yLoc1) // 8
1473 dir_array_ptr[7][dir_array_count[7]++] = selectedUnitArray[i];
1474 else if(curYLoc > yLoc2)// 2
1475 dir_array_ptr[1][dir_array_count[1]++] = selectedUnitArray[i];
1476 else // 1
1477 dir_array_ptr[0][dir_array_count[0]++] = selectedUnitArray[i];
1478 }
1479 else if(curXLoc > xLoc2)
1480 {
1481 if(curYLoc < yLoc1) // 6
1482 dir_array_ptr[5][dir_array_count[5]++] = selectedUnitArray[i];
1483 else if(curYLoc > yLoc2)// 4
1484 dir_array_ptr[3][dir_array_count[3]++] = selectedUnitArray[i];
1485 else // 5
1486 dir_array_ptr[4][dir_array_count[4]++] = selectedUnitArray[i];
1487 }
1488 else // curXLoc==targetXLoc2
1489 {
1490 if(curYLoc < yLoc1) // 7
1491 dir_array_ptr[6][dir_array_count[6]++] = selectedUnitArray[i];
1492 else if(curYLoc > yLoc2)// 3
1493 dir_array_ptr[2][dir_array_count[2]++] = selectedUnitArray[i];
1494 else // curXLoc==xLoc2 && curYLoc==yLoc2
1495 {
1496 // target is one of the selected unit, error
1497 err_here();
1498 }
1499 }
1500 }
1501 }
1502 //----------- End of function UnitArray::arrange_units_in_group -----------//
1503
1504
1505 //--------- Begin of function UnitArray::analyse_surround_location ---------//
1506 // return the number of accessible surrounding location of the target
1507 //
1508 // <int> targetXLoc - target x location
1509 // <int> targetYLoc - target y location
1510 // <int> targetWidth - target width
1511 // <int> targetHeight - target height
1512 // <char> mobileType - target mobile type
1513 //
analyse_surround_location(int targetXLoc,int targetYLoc,int targetWidth,int targetHeight,char mobileType)1514 int UnitArray::analyse_surround_location(int targetXLoc, int targetYLoc, int targetWidth, int targetHeight, char mobileType)
1515 {
1516 static char xIncreTable[4] = { 1, 0, -1, 0};
1517 static char yIncreTable[4] = { 0, 1, 0, -1};
1518
1519 err_when(targetWidth<1 || targetWidth>4);
1520 Location *locPtr;
1521 int xLoc = targetXLoc-1;
1522 int yLoc = targetYLoc-1;
1523 int targetXLoc2 = targetXLoc + targetWidth - 1;
1524 int targetYLoc2 = targetYLoc + targetHeight - 1;
1525 int bound = 2*(targetWidth + targetHeight) + 4; // (x+2)*(y+2) - xy
1526 int increCount=4, xIncre, yIncre, found=0;
1527
1528 err_when(targetWidth==3 && targetHeight==3 && bound!=16);
1529
1530 for(int i=0; i<bound; i++)
1531 {
1532 if(xLoc<0 || xLoc>=MAX_WORLD_X_LOC || yLoc<0 || yLoc>=MAX_WORLD_Y_LOC)
1533 unreachable_table[xLoc-targetXLoc+SHIFT_ADJUST][yLoc-targetYLoc+SHIFT_ADJUST] = 1;
1534 else
1535 {
1536 locPtr = world.get_loc(xLoc, yLoc);
1537 if(!locPtr->can_move(mobileType))
1538 unreachable_table[xLoc-targetXLoc+SHIFT_ADJUST][yLoc-targetYLoc+SHIFT_ADJUST] = 1;
1539 else
1540 found++;
1541 }
1542
1543 if((xLoc==targetXLoc-1 || xLoc==targetXLoc2+1) && (yLoc==targetYLoc-1 || yLoc==targetYLoc2+1)) // at the corner
1544 {
1545 if((++increCount)>=4)
1546 increCount = 0;
1547
1548 xIncre = xIncreTable[increCount];
1549 yIncre = yIncreTable[increCount];
1550 }
1551
1552 xLoc += xIncre;
1553 yLoc += yIncre;
1554 }
1555
1556 return found;
1557 }
1558 //----------- End of function UnitArray::analyse_surround_location -----------//
1559
1560
1561 //--------- Begin of function UnitArray::check_nearby_location ---------//
1562 // check the target location to find out how many of its surrounding location
1563 // is not blocked
1564 //
1565 // <int> targetXLoc - target x location
1566 // <int> targetYLoc - target y location
1567 // <char> xOffset - x offset from target x location
1568 // <char> yOffset - y offset from target y location
1569 // <int> targetWidth - target width
1570 // <int> targetHeight - target height
1571 // <char> targetMobileType - target mobile type
1572 // <int&> analyseResult - reference for returning
1573 //
check_nearby_location(int targetXLoc,int targetYLoc,char xOffset,char yOffset,int targetWidth,int targetHeight,char targetMobileType,int & analyseResult)1574 void UnitArray::check_nearby_location(int targetXLoc, int targetYLoc, char xOffset, char yOffset,
1575 int targetWidth, int targetHeight, char targetMobileType, int& analyseResult)
1576 {
1577 #ifdef DEBUG
1578 int backupAnalyseResult = analyseResult;
1579 char debugUnreachableTable[MAX_UNIT_SURROUND_SIZE][MAX_UNIT_SURROUND_SIZE];
1580 memcpy(debugUnreachableTable, unreachable_table, sizeof(char)*MAX_UNIT_SURROUND_SIZE*MAX_UNIT_SURROUND_SIZE);
1581 #endif
1582 debug_result_check(analyseResult, targetWidth, targetHeight);
1583
1584 static char leftXIncreTable[4] = { 1, 0, -1, 0};
1585 static char leftYIncreTable[4] = { 0, 1, 0, -1};
1586 static char rightXIncreTable[4] = { -1, 0, 1, 0};
1587 static char rightYIncreTable[4] = { 0, 1, 0, -1};
1588
1589 err_when(targetWidth<1 || targetWidth>4);
1590 Location *locPtr;
1591 int targetXLoc2 = targetXLoc + targetWidth - 1;
1592 int targetYLoc2 = targetYLoc + targetHeight - 1;
1593 int bound = 2*(targetWidth + targetHeight) + 4; // (x+2)*(y+2) - xy
1594
1595 int leftXLoc ,leftYLoc, leftContinue=1;
1596 int leftXIncre, leftYIncre, leftIncreCount;
1597 int rightXLoc, rightYLoc, rightContinue=1;
1598 int rightXIncre, rightYIncre, rightIncreCount=1;
1599
1600 bool haveValidSituation = true;
1601
1602 //-------------------------------------------------------------------------------------//
1603 // determine the initial situation
1604 //-------------------------------------------------------------------------------------//
1605 if((xOffset==-1 || xOffset==targetWidth) && (yOffset==-1 || yOffset==targetHeight)) // at the corner
1606 {
1607 if(xOffset==-1)
1608 {
1609 if(yOffset==-1) // upper left corner
1610 {
1611 leftXIncre = 1;
1612 leftYIncre = 0;
1613 leftIncreCount = 0;
1614
1615 rightXIncre = 0;
1616 rightYIncre = 1;
1617 rightIncreCount = 1;
1618 }
1619 else // lower left corner
1620 {
1621 leftXIncre = 0;
1622 leftYIncre = -1;
1623 leftIncreCount = 3;
1624
1625 rightXIncre = 1;
1626 rightYIncre = 0;
1627 rightIncreCount = 2;
1628 }
1629 }
1630 else
1631 {
1632 if(yOffset==-1) // upper right corner
1633 {
1634 leftXIncre = 0;
1635 leftYIncre = 1;
1636 leftIncreCount = 1;
1637
1638 rightXIncre = -1;
1639 rightYIncre = 0;
1640 rightIncreCount = 0;
1641 }
1642 else // lower right corner
1643 {
1644 leftXIncre = -1;
1645 leftYIncre = 0;
1646 leftIncreCount = 2;
1647
1648 rightXIncre = 0;
1649 rightYIncre = -1;
1650 rightIncreCount = 3;
1651 }
1652 }
1653 }
1654 else // at the edge
1655 {
1656 if(xOffset==-1) // left edge
1657 {
1658 leftXIncre = 0;
1659 leftYIncre = -1;
1660 leftIncreCount = 3;
1661
1662 rightXIncre = 0;
1663 rightYIncre = 1;
1664 rightIncreCount = 1;
1665 }
1666 else if(xOffset==targetWidth) // right edge
1667 {
1668 leftXIncre = 0;
1669 leftYIncre = 1;
1670 leftIncreCount = 1;
1671
1672 rightXIncre = 0;
1673 rightYIncre = -1;
1674 rightIncreCount = 3;
1675 }
1676 else if(yOffset==-1) // upper edge
1677 {
1678 leftXIncre = 1;
1679 leftYIncre = 0;
1680 leftIncreCount = 0;
1681
1682 rightXIncre = -1;
1683 rightYIncre = 0;
1684 rightIncreCount = 0;
1685 }
1686 else if(yOffset==targetHeight) // lower edge
1687 {
1688 leftXIncre = -1;
1689 leftYIncre = 0;
1690 leftIncreCount = 2;
1691
1692 rightXIncre = 1;
1693 rightYIncre = 0;
1694 rightIncreCount = 2;
1695 }
1696 else {
1697 haveValidSituation = false;
1698 }
1699 }
1700
1701 err_when( !haveValidSituation );
1702
1703 leftXLoc = rightXLoc = targetXLoc + xOffset;
1704 leftYLoc = rightYLoc = targetYLoc + yOffset;
1705 int canReach;
1706 int outBoundary; // true if out of map boundary
1707
1708 //-------------------------------------------------------------------------------------//
1709 // count the reachable location
1710 //-------------------------------------------------------------------------------------//
1711 for(int i=1; i<bound; i++) // exclude the starting location
1712 {
1713 debug_result_check(analyseResult, targetWidth, targetHeight);
1714 #ifdef DEBUG
1715 int debugLeftXLoc = leftXLoc;
1716 int debugLeftYloc = leftYLoc;
1717 int debugRightXLoc = rightXLoc;
1718 int debugRightYLoc = rightYLoc;
1719 int debugLeftIncreCount = leftIncreCount;
1720 int debugRightIncreCount = rightIncreCount;
1721 char debugUnreachableTable2[MAX_UNIT_SURROUND_SIZE][MAX_UNIT_SURROUND_SIZE];
1722 memcpy(debugUnreachableTable2, unreachable_table, sizeof(char)*MAX_UNIT_SURROUND_SIZE*MAX_UNIT_SURROUND_SIZE);
1723 for(int k=0; k<MAX_UNIT_SURROUND_SIZE; k++)
1724 {
1725 for(int j=0; j<MAX_UNIT_SURROUND_SIZE; j++)
1726 {
1727 if(debugUnreachableTable2[k][j] && debugUnreachableTable2[k][j]==1)
1728 debugUnreachableTable2[k][j] = 2; // plus 1 to distinguish the original table
1729 }
1730 }
1731 #endif
1732
1733 //------------------------------------------------------------//
1734 // process left hand side checking
1735 //------------------------------------------------------------//
1736 if(leftContinue)
1737 {
1738 canReach = 0;
1739 outBoundary = 0;
1740
1741 leftXLoc += leftXIncre;
1742 leftYLoc += leftYIncre;
1743 if((leftXLoc==targetXLoc-1 || leftXLoc==targetXLoc2+1) && (leftYLoc==targetYLoc-1 || leftYLoc==targetYLoc2+1))
1744 {
1745 if((++leftIncreCount)>=4)
1746 leftIncreCount = 0;
1747
1748 leftXIncre = leftXIncreTable[leftIncreCount];
1749 leftYIncre = leftYIncreTable[leftIncreCount];
1750 }
1751
1752 if(leftXLoc>=0 && leftXLoc<MAX_WORLD_X_LOC && leftYLoc>=0 && leftYLoc<MAX_WORLD_Y_LOC)
1753 {
1754 if(unreachable_table[leftXLoc-targetXLoc+SHIFT_ADJUST][leftYLoc-targetYLoc+SHIFT_ADJUST])
1755 canReach = 1; // concept incorrect, but it is used to terminate this part of checking
1756 else
1757 {
1758 locPtr = world.get_loc(leftXLoc, leftYLoc);
1759 if(locPtr->can_move(targetMobileType))
1760 canReach = 1;
1761 }
1762 }
1763 else
1764 outBoundary = 1;
1765
1766 if(canReach)
1767 leftContinue = 0;
1768 else if(!outBoundary)
1769 {
1770 err_when(unreachable_table[leftXLoc-targetXLoc+SHIFT_ADJUST][leftYLoc-targetYLoc+SHIFT_ADJUST]);
1771 unreachable_table[leftXLoc-targetXLoc+SHIFT_ADJUST][leftYLoc-targetYLoc+SHIFT_ADJUST] = 1;
1772 analyseResult--;
1773 debug_result_check(analyseResult, targetWidth, targetHeight);
1774 err_when(analyseResult<0);
1775 }
1776 #ifdef DEBUG
1777 else
1778 err_when(!unreachable_table[leftXLoc-targetXLoc+SHIFT_ADJUST][leftYLoc-targetYLoc+SHIFT_ADJUST]);
1779 #endif
1780
1781 i++;
1782 }
1783
1784 //------------------------------------------------------------//
1785 // process right hand side checking
1786 //------------------------------------------------------------//
1787 if(rightContinue)
1788 {
1789 canReach = 0;
1790 outBoundary = 0;
1791
1792 rightXLoc += rightXIncre;
1793 rightYLoc += rightYIncre;
1794 if((rightXLoc==targetXLoc-1 || rightXLoc==targetXLoc2+1) && (rightYLoc==targetYLoc-1 || rightYLoc==targetYLoc2+1))
1795 {
1796 if((++rightIncreCount)>=4)
1797 rightIncreCount = 0;
1798
1799 rightXIncre = rightXIncreTable[rightIncreCount];
1800 rightYIncre = rightYIncreTable[rightIncreCount];
1801 }
1802
1803 if(rightXLoc>=0 && rightXLoc<MAX_WORLD_X_LOC && rightYLoc>=0 && rightYLoc<MAX_WORLD_Y_LOC)
1804 {
1805 if(unreachable_table[rightXLoc-targetXLoc+SHIFT_ADJUST][rightYLoc-targetYLoc+SHIFT_ADJUST])
1806 canReach = 1; // concept incorrect, but it is used to terminate this part of checking
1807 else
1808 {
1809 locPtr = world.get_loc(rightXLoc, rightYLoc);
1810 if(locPtr->can_move(targetMobileType))
1811 canReach = 1;
1812 }
1813 }
1814 else
1815 outBoundary = 1;
1816
1817 if(canReach)
1818 rightContinue = 0;
1819 else if(!outBoundary)
1820 {
1821 err_when(unreachable_table[rightXLoc-targetXLoc+SHIFT_ADJUST][rightYLoc-targetYLoc+SHIFT_ADJUST]);
1822 unreachable_table[rightXLoc-targetXLoc+SHIFT_ADJUST][rightYLoc-targetYLoc+SHIFT_ADJUST] = 1;
1823 analyseResult--;
1824 debug_result_check(analyseResult, targetWidth, targetHeight);
1825 err_when(analyseResult<0);
1826 }
1827 #ifdef DEBUG
1828 else
1829 err_when(!unreachable_table[rightXLoc-targetXLoc+SHIFT_ADJUST][rightYLoc-targetYLoc+SHIFT_ADJUST]);
1830 #endif
1831 }
1832
1833 if(!leftContinue && !rightContinue)
1834 break;
1835 }
1836 }
1837 //----------- End of function UnitArray::check_nearby_location -----------//
1838
1839
1840 //--------- Begin of function UnitArray::handle_attack_target_totally_blocked ---------//
1841 // handle attacking while the target is totally blocked
1842 //
1843 // <int> targetXLoc - target x loc
1844 // <int> targetYLoc - target y loc
1845 // <short> targetRecno - target recno
1846 // <short*> selectedUnitArray - selected units' recno
1847 // <short> selectedCount - num of selected unit
1848 // <int> targetType - 0 for wall, 1 for unit, 2 for firm, 3 for town
1849 //
handle_attack_target_totally_blocked(int targetXLoc,int targetYLoc,short targetRecno,short * selectedUnitArray,short selectedCount,int targetType)1850 void UnitArray::handle_attack_target_totally_blocked(int targetXLoc, int targetYLoc, short targetRecno,
1851 short *selectedUnitArray, short selectedCount, int targetType)
1852 {
1853 if(unit_processed_count>0) // some units can reach the target surrounding
1854 {
1855 Unit *processedPtr, *unitPtr;
1856 int proCount = unit_processed_count - 1;
1857 int unproCount = selectedCount - proCount - 1; // number of unprocessed
1858 int sCount = selectedCount-1;
1859 int found, i, recno;
1860 #ifdef DEBUG
1861 int debugCount;
1862 #endif
1863
1864 //------------------------------------------------------------------------------------//
1865 // use the result of those processed units as a reference of those unprocessed units
1866 //------------------------------------------------------------------------------------//
1867 while(unproCount)
1868 {
1869 err_when(unit_array.is_deleted(unit_processed_array[proCount]));
1870 processedPtr = (Unit*) get_ptr(unit_processed_array[proCount]);
1871 #ifdef DEBUG
1872 debugCount = 0;
1873 #endif
1874
1875 err_when(sCount<0);
1876 do
1877 {
1878 #ifdef DEBUG
1879 debugCount++;
1880 err_when(debugCount>1000);
1881 #endif
1882
1883 found = 0;
1884 recno = selectedUnitArray[sCount];
1885 for(i=0; i<unit_processed_count; i++)
1886 {
1887 if(unit_processed_array[i]==recno)
1888 {
1889 found++;
1890 break;
1891 }
1892 }
1893
1894 err_when(sCount<0 || sCount>selectedCount);
1895 sCount--;
1896 }while(found);
1897
1898 unitPtr = (Unit *) get_ptr(recno);
1899 unitPtr->move_to(processedPtr->move_to_x_loc, processedPtr->move_to_y_loc);
1900
1901 switch(targetType)
1902 {
1903 case 0: // wall
1904 unitPtr->action_mode = unitPtr->action_mode2 = ACTION_ATTACK_WALL;
1905 err_when(targetRecno);
1906 break;
1907
1908 case 1: // unit
1909 unitPtr->action_mode = unitPtr->action_mode2 = ACTION_ATTACK_UNIT;
1910 err_when(!targetRecno);
1911 break;
1912
1913 case 2: // firm
1914 unitPtr->action_mode = unitPtr->action_mode2 = ACTION_ATTACK_FIRM;
1915 err_when(!targetRecno);
1916 break;
1917
1918 case 3: // town
1919 unitPtr->action_mode = unitPtr->action_mode2 = ACTION_ATTACK_TOWN;
1920 err_when(!targetRecno);
1921 break;
1922 }
1923 unitPtr->action_para = unitPtr->action_para2 = targetRecno;
1924 unitPtr->action_x_loc = unitPtr->action_x_loc2 = targetXLoc;
1925 unitPtr->action_y_loc = unitPtr->action_y_loc2 = targetYLoc;
1926
1927 proCount--;
1928 if(proCount<0)
1929 proCount = unit_processed_count - 1;
1930
1931 unproCount--;
1932 }
1933 }
1934 else // none of the units reaches the target surrounding
1935 {
1936 //----------------------------------------------------------------//
1937 // handle the case for 1x1 units now, no 2x2 units
1938 //----------------------------------------------------------------//
1939 //-*********** improve later ************-//
1940 int unprocessed = selectedCount;
1941 Unit *firstPtr = (Unit *) get_ptr(selectedUnitArray[unprocessed-1]);
1942
1943 switch(targetType)
1944 {
1945 case 0: firstPtr->attack_wall(targetXLoc, targetYLoc);
1946 break;
1947
1948 case 1: firstPtr->attack_unit(targetXLoc, targetYLoc);
1949 break;
1950
1951 case 2: firstPtr->attack_firm(targetXLoc, targetYLoc);
1952 break;
1953
1954 case 3: firstPtr->attack_town(targetXLoc, targetYLoc);
1955 break;
1956 }
1957
1958 int moveToXLoc = firstPtr->move_to_x_loc;
1959 int moveToYLoc = firstPtr->move_to_y_loc;
1960
1961 /*if(seek_path.path_status==PATH_NODE_USED_UP)
1962 {
1963 int debug = 0;
1964 }*/
1965
1966 Unit *unitPtr;
1967
1968 while(unprocessed)
1969 {
1970 unitPtr = (Unit *) get_ptr(selectedUnitArray[unprocessed-1]);
1971 unitPtr->move_to(moveToXLoc, moveToYLoc);
1972
1973 switch(targetType)
1974 {
1975 case 0: // wall
1976 unitPtr->action_mode = unitPtr->action_mode2 = ACTION_ATTACK_WALL;
1977 unitPtr->action_para = unitPtr->action_para2 = 0;
1978 break;
1979
1980 case 1: // unit
1981 unitPtr->action_mode = unitPtr->action_mode2 = ACTION_ATTACK_UNIT;
1982 unitPtr->action_para = unitPtr->action_para2 = targetRecno;
1983 break;
1984
1985 case 2: // firm
1986 unitPtr->action_mode = unitPtr->action_mode2 = ACTION_ATTACK_FIRM;
1987 unitPtr->action_para = unitPtr->action_para2 = targetRecno;
1988 break;
1989
1990 case 3: // town
1991 unitPtr->action_mode = unitPtr->action_mode2 = ACTION_ATTACK_TOWN;
1992 unitPtr->action_para = unitPtr->action_para2 = targetRecno;
1993 break;
1994 }
1995 unitPtr->action_x_loc = unitPtr->action_x_loc2 = targetXLoc;
1996 unitPtr->action_y_loc = unitPtr->action_y_loc2 = targetYLoc;
1997
1998 unprocessed--;
1999 }
2000 }
2001 }
2002 //----------- End of function UnitArray::handle_attack_target_totally_blocked -----------//
2003