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