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    : OUNITAM.CPP
22 //Description : Object UnitArray - part 2
23 //
24 // For the detail, see ounitam.txt
25 
26 #include <math.h>
27 
28 #include <ALL.h>
29 #include <OVGA.h>
30 #include <OSYS.h>
31 #include <OSTR.h>
32 #include <OREMOTE.h>
33 #include <OWORLD.h>
34 #include <OTERRAIN.h>
35 #include <OUNIT.h>
36 #include <dbglog.h>
37 
38 DBGLOG_DEFAULT_CHANNEL(Unit);
39 
40 #ifdef NO_DEBUG_UNIT
41 #undef err_when
42 #undef err_here
43 #undef err_if
44 #undef err_else
45 #undef err_now
46 #define err_when(cond)
47 #define err_here()
48 #define err_if(cond)
49 #define err_else
50 #define err_now(msg)
51 #undef DEBUG
52 #endif
53 
54 //----------- Define static variables -----------//
55 
56 //------ static variables for all actions -------//
57 short	UnitArray::selected_land_unit_count;
58 short	UnitArray::selected_sea_unit_count;
59 short	UnitArray::selected_air_unit_count;
60 short	*UnitArray::selected_land_unit_array=NULL;
61 short	*UnitArray::selected_sea_unit_array=NULL;
62 short	*UnitArray::selected_air_unit_array=NULL;
63 
64 //------ static variables for movement -------//
65 static short		square_size, not_tested_loc, rec_height, rec_width;
66 static int			move_scale; // use integer for intrgral division
67 static int			x, y;
68 static short		lower_right_case, upper_left_case;	// indicate which case should be used
69 static int			*distance, *sorted_member, *sorted_distance;
70 static char			*done_flag;
71 
72 //static int			rec_x1, rec_y1, rec_x2, rec_y2; // for bondary, corner improvement
73 
74 static short		*filtering_unit_array;
75 static int			filtering_unit_count;
76 static short		*filtered_unit_array;
77 static int			filtered_unit_count;
78 
79 //-------------- define static functions -------------//
cal_rectangle_lower_right_x(int refXLoc)80 static int cal_rectangle_lower_right_x(int refXLoc)
81 {
82 	// the rule:	refXLoc + (rec_width/(move_scale*2))*move_scale
83 	if(move_scale==1)
84 		return refXLoc + rec_width/2;
85 	else // move_scale == 2
86 		return refXLoc + (rec_width/4)*2;
87 }
88 
cal_rectangle_lower_right_y(int refYLoc)89 static int cal_rectangle_lower_right_y(int refYLoc)
90 {
91 	// the rule:	refYLoc + ((rec_height-move_scale)/(move_scale*2))*move_scale
92 	if(move_scale==1)
93 		return refYLoc + (rec_height-1)/2;
94 	else // move_scale == 2
95 		return refYLoc + ((rec_height-2)/4)*2;
96 }
97 
cal_rectangle_upper_left_x(int refXLoc)98 static int cal_rectangle_upper_left_x(int refXLoc)
99 {
100 	// the rule:	refXLoc - ((rec_width-move_scale)/(move_scale*2))*move_scale
101 	if(move_scale==1)
102 		return refXLoc - (rec_width-1)/2;
103 	else // move_scale == 2
104 		return refXLoc - ((rec_width-2)/4)*2;
105 }
106 
cal_rectangle_upper_left_y(int refYLoc)107 static int cal_rectangle_upper_left_y(int refYLoc)
108 {
109 	// the rule:	refYLoc - (rec_height/(move_scale*2))*move_scale
110 	if(move_scale==1)
111 		return refYLoc - rec_height/2;
112 	else // move_scale == 2
113 		return refYLoc - (rec_height/4)*2;
114 }
115 
116 //--------- Begin of function UnitArray::move_to ---------//
117 //
118 // Order the unit to move to a specific location following the
119 // shortest path.
120 //
121 // <int> 	destXLoc, destYLoc - the location of the destination.
122 // <int>		divided				 - whether the units are divided by their mobile type
123 // <short*> selectedUnitArray  - an array of recno of selected units.
124 // <int>    selectedCount 		 - no. of selected units.
125 // [char]   remoteAction 	    - whether this is an action carried out by a remote machine or not.
126 //											(default: 0)
127 //
128 // Note: the caller function must make sure all units in selectedUnitArray are validate (non-deleted)
129 //
move_to(int destXLoc,int destYLoc,int divided,short * selectedUnitArray,int selectedCount,char remoteAction)130 void UnitArray::move_to(int destXLoc, int destYLoc, int divided, short* selectedUnitArray, int selectedCount, char remoteAction)
131 {
132 	err_when(destXLoc<0 || destYLoc<0 || destXLoc>MAX_WORLD_X_LOC-1 || destYLoc>MAX_WORLD_Y_LOC-1);
133 
134 	//-------- if it's a multiplayer game --------//
135 	if( !remoteAction && remote.is_enable() )
136 	{
137 		short* shortPtr = (short*) remote.new_send_queue_msg(MSG_UNIT_MOVE,
138 								sizeof(short) * (4+selectedCount) );
139 
140 		shortPtr[0] = destXLoc;
141 		shortPtr[1] = destYLoc;
142 		shortPtr[2] = selectedCount;
143 		shortPtr[3] = divided;
144 
145 		memcpy( shortPtr+4, selectedUnitArray, sizeof(short) * selectedCount );
146 	}
147 	else
148 	{
149 		err_when( selectedCount > 10000 );		// error
150 
151 		if(!divided)
152 		{
153 			//----------- divide units ------------//
154 			divide_array(destXLoc, destYLoc, selectedUnitArray, selectedCount);
155 
156 			//---------- process group move --------------//
157 			// ##### patch begin Gilbert 18/8 ######//
158 			if(selected_land_unit_count)
159 				move_to(destXLoc, destYLoc, 1, selected_land_unit_array, selected_land_unit_count, COMMAND_AUTO);
160 
161 			if(selected_sea_unit_count)
162 			{
163 				Location *locPtr = world.get_loc(destXLoc, destYLoc);
164 				if(terrain_res[locPtr->terrain_id]->average_type == TERRAIN_OCEAN)
165 					move_to(destXLoc, destYLoc, 1, selected_sea_unit_array, selected_sea_unit_count, COMMAND_AUTO);
166 				else
167 					ship_to_beach(destXLoc, destYLoc, 1, selected_sea_unit_array, selected_sea_unit_count, COMMAND_AUTO);
168 			}
169 
170 			if(selected_air_unit_count)
171 				move_to(destXLoc, destYLoc, 1, selected_air_unit_array, selected_air_unit_count, COMMAND_AUTO);
172 			// ##### patch end Gilbert 18/8 ######//
173 
174 			//---------------- deinit static parameters ------------------//
175 			selected_land_unit_count = selected_sea_unit_count = selected_air_unit_count = 0;
176 			mem_del(selected_land_unit_array);
177 			mem_del(selected_sea_unit_array);
178 			mem_del(selected_air_unit_array);
179 			return;
180 		}
181 		else
182 		{
183 			//---------------------------------------------------------//
184 			// set the unit_group_id
185 			//---------------------------------------------------------//
186 			Unit* unitPtr;
187 			uint32_t curGroupId = unit_array.cur_group_id++;
188 
189 			for(int k=0; k<selectedCount; k++)
190 			{
191 				unitPtr = (Unit*) get_ptr(selectedUnitArray[k]);
192 				err_when(!unitPtr);
193 				err_when(!unitPtr->is_visible() || unitPtr->hit_points<=0);
194 
195 				unitPtr->unit_group_id = curGroupId;
196 
197 				unitPtr->action_mode = ACTION_MOVE;
198 				unitPtr->action_para = 0;
199 
200 				if(unitPtr->action_mode2!=ACTION_MOVE)
201 				{
202 					unitPtr->action_mode2 = ACTION_MOVE;
203 					unitPtr->action_para2 = 0;
204 					unitPtr->action_x_loc2 = unitPtr->action_y_loc2 = -1;
205 				}// else keep the data to check whether same action mode is ordered
206 			}
207 
208 			//--------------------------------------------------------------//
209 			// if only the leader unit is moving, no need to use formation
210 			// movement although the button is pushed
211 			//--------------------------------------------------------------//
212 			if(selectedCount==1)
213 			{
214 				unitPtr = (Unit*) get_ptr(selectedUnitArray[0]);
215 				unitPtr->move_to(destXLoc, destYLoc, 1);
216 			}
217 			else
218 			{
219 				Unit *firstUnitPtr = operator[](selectedUnitArray[0]);
220 
221 				if(firstUnitPtr->mobile_type==UNIT_LAND)
222 				{
223 					move_to_now_with_filter(destXLoc, destYLoc, selectedUnitArray, selectedCount);
224 					seek_path.set_sub_mode(); // reset sub_mode searching
225 					seek_path_reuse.set_sub_mode(); //------ reset sub mode of path reuse searching
226 				}
227 				else
228 					move_to_now_with_filter(destXLoc, destYLoc, selectedUnitArray, selectedCount);
229 			}
230 		}
231 	}
232 }
233 //----------- End of function UnitArray::move_to -----------//
234 
235 
236 //----------Begin of function UnitArray::move_to_now_with_filter------------//
237 // the selected units may be in different territory. Group them by their region id
238 // and process searching for each group
239 //
240 // <int>		destX					- the x location to move to
241 // <int>		destY					- the y location to move to
242 // <short*>	selectedUnitArray	- recno. of selected units
243 // <int>		selectedCount		- num of selected units
244 //
move_to_now_with_filter(int destX,int destY,short * selectedUnitArray,int selectedCount)245 void UnitArray::move_to_now_with_filter(int destX, int destY, short* selectedUnitArray, int selectedCount)
246 {
247 	int destRegionId = world.get_loc(destX, destY)->region_id;
248 	Unit *unitPtr = operator[](selectedUnitArray[0]);
249 
250 	//-------------- no filtering for unit air --------------------------//
251 	if(unitPtr->mobile_type==UNIT_AIR)
252 	{
253 		move_to_now(destX, destY, selectedUnitArray, selectedCount);
254 		return;
255 	}
256 
257 	//----------------- init data structure --------------//
258 	int arraySize = sizeof(short)*selectedCount;
259 	filtered_unit_array = (short*) mem_add(arraySize);
260 	filtering_unit_array = (short*) mem_add(arraySize);
261 	memcpy(filtering_unit_array, selectedUnitArray, arraySize);
262 	filtering_unit_count = selectedCount;
263 
264 	int unprocessCount = selectedCount;
265 	int filterRegionId = destRegionId;
266 	int filterDestX = destX, filterDestY = destY;
267 	int loopCount, filteringCount, i;
268 
269 	//-------------------------------------------------------------------------------//
270 	// group the unit by their region id and process group searching for each group
271 	//-------------------------------------------------------------------------------//
272 	for(loopCount=0; loopCount<=unprocessCount; loopCount++) // checking for unprocessCount+1, plus one for the case that unit not on the same territory of destination
273 	{
274 		memset(filtered_unit_array, 0, arraySize);
275 		filtered_unit_count = 0;
276 		filteringCount = filtering_unit_count;
277 		filtering_unit_count = 0;
278 
279 		//-------------- filter for filterRegionId --------------//
280 		for(i=0; i<filteringCount; i++)
281 		{
282 			unitPtr = operator[](filtering_unit_array[i]);
283 			if(world.get_loc(unitPtr->next_x_loc(), unitPtr->next_y_loc())->region_id==filterRegionId)
284 				filtered_unit_array[filtered_unit_count++] = filtering_unit_array[i];
285 			else
286 				filtering_unit_array[filtering_unit_count++] = filtering_unit_array[i];
287 		}
288 
289 		//---- process for filtered_unit_array and prepare for looping ----//
290 		if(filtered_unit_count)
291 			move_to_now(filterDestX, filterDestY, filtered_unit_array, filtered_unit_count);
292 
293 		if(!filtering_unit_count)
294 			break;
295 
296 		//---------------- update parameters for next checking ------------------//
297 		unitPtr = operator[](filtering_unit_array[0]);
298 		filterRegionId = world.get_loc(unitPtr->next_x_loc(), unitPtr->next_y_loc())->region_id;
299 		filterDestX = destX;
300 		filterDestY = destY;
301 		unitPtr->different_territory_destination(filterDestX, filterDestY); // reference parameters to get the location the units should move to
302 	}
303 
304 	mem_del(filtered_unit_array);
305 	mem_del(filtering_unit_array);
306 }
307 //----------- End of function UnitArray::move_to_now_with_filter -----------//
308 
309 
310 //--------- Begin of function UnitArray::move_to_now ---------//
311 //
312 // Order the unit to move to a specific location following the
313 // shortest path.
314 //
315 // <int> 	destXLoc, destYLoc - the location of the destination.
316 // <short*> selectedUnitArray  - an array of recno of selected units.
317 // <int>    selectedCount 		 - no. of selected units.
318 //
move_to_now(int destXLoc,int destYLoc,short * selectedUnitArray,int selectedCount)319 void UnitArray::move_to_now(int destXLoc, int destYLoc, short* selectedUnitArray, int selectedCount)
320 {
321 	err_when(destXLoc<0 || destYLoc<0 || destXLoc>=MAX_WORLD_X_LOC || destYLoc>=MAX_WORLD_Y_LOC);
322 	err_when( selectedCount > 10000 );
323 
324 	//------------ define vars -----------------------//
325 	int		unprocessCount;// = selectedCount;		// num. of unprocessed sprite
326 	int		k;													// for counting
327 	short		vecX, vecY;										// used to reset x, y
328 	short		oddCount, evenCount;
329 	int		j;
330 	Unit*		unitPtr = unit_array[selectedUnitArray[0]];
331 	uint32_t		curGroupId = unitPtr->unit_group_id;
332 	int		mobileType = unitPtr->mobile_type;
333 	Location	*worldLocMatrix=world.loc_matrix, *locPtr;
334 	//int		sizeOneSelectedCount=0, sizeTwoSelectedCount=0;
335 	int		sizeOneSelectedCount = selectedCount;
336 
337 	//---------- set Unit::unit_group_id and count the unit by size ----------//
338 	int i;
339 	for( i=0 ; i<selectedCount ; i++ )
340 	{
341 		unitPtr = operator[](selectedUnitArray[i]);
342 		err_when(unitPtr->cur_action==SPRITE_IDLE && (unitPtr->cur_x!=unitPtr->next_x || unitPtr->cur_y!=unitPtr->next_y));
343 		err_when(unitPtr->action_para); // action_para should be set to zero in move_to()
344 
345 		if(unitPtr->cur_action==SPRITE_ATTACK)
346 			unitPtr->stop();
347 
348 		err_when(unitPtr->cur_action==SPRITE_ATTACK && unitPtr->action_para==0);
349 		if(unitPtr->cur_action==SPRITE_IDLE)
350 			unitPtr->set_ready();
351 
352 		/*switch(unitPtr->sprite_info->loc_width)
353 		{
354 			case 1:	sizeOneSelectedCount++;
355 						break;
356 
357 			case 2:	sizeTwoSelectedCount++;
358 						break;
359 
360 			default:	err_here();
361 						break;
362 		}*/
363 	}
364 	unprocessCount = sizeOneSelectedCount;
365 
366 	//---- construct array to store size one selected unit ----//
367 	short* selectedSizeOneUnitArray;
368 	if(sizeOneSelectedCount)
369 	{
370 		selectedSizeOneUnitArray = (short*)mem_add(sizeof(short)*sizeOneSelectedCount);
371 		memset(selectedSizeOneUnitArray, 0, sizeof(short)*sizeOneSelectedCount);
372 		for(i=0, k=0; i<selectedCount && unprocessCount; i++)
373 		{
374 			unitPtr = operator[](selectedUnitArray[i]);
375 			if(unitPtr->sprite_info->loc_width==1)
376 			{
377 				selectedSizeOneUnitArray[k++] = selectedUnitArray[i];
378 				unprocessCount--;
379 			}
380 		}
381 	}
382 	unprocessCount = sizeOneSelectedCount;
383 
384 	//----------- variables initialization ---------------//
385 	int destX, destY;
386 	if(mobileType==UNIT_LAND)
387 	{
388 		x = destX = destXLoc;
389 		y = destY = destYLoc;
390 		move_scale = 1;
391 	}
392 	else // UNIT_AIR, UNIT_SEA
393 	{
394 		x = destX = (destXLoc/2)*2;
395 		y = destY = (destYLoc/2)*2;
396 		move_scale = 2;
397 	}
398 
399 	//if(sizeOneSelectedCount)
400 	//{
401 		//----- initialize parameters and construct data structure -----//
402 		oddCount =1;
403 		evenCount = 3;
404 		square_size = not_tested_loc = lower_right_case = upper_left_case = 0;
405 
406 		distance = (int*)mem_add(sizeof(int)*sizeOneSelectedCount);		// used in the function construct_sorted_array and this function,
407 		memset(distance, 0, sizeof(int)*sizeOneSelectedCount);				// and allocate/free the memory in this function
408 
409 		sorted_distance = (int*)mem_add(sizeof(int)*sizeOneSelectedCount);
410 		memset(sorted_distance, 0, sizeof(int)*sizeOneSelectedCount);
411 
412 		sorted_member = (int*)mem_add(sizeof(int)*sizeOneSelectedCount);
413 		memset(sorted_member, 0, sizeof(int)*sizeOneSelectedCount);
414 
415 		done_flag = (char*)mem_add(sizeof(char)*sizeOneSelectedCount);
416 		memset(done_flag, 0, sizeof(char)*sizeOneSelectedCount);
417 
418 		//--- calculate the rectangle size used to allocate space for the sprites----//
419 		unprocessCount = sizeOneSelectedCount;
420 		while(unprocessCount)
421 		{
422 			//=============================
423 			// process odd size square
424 			//=============================
425 			vecX = short(oddCount/4)*move_scale;
426 			vecY = vecX;
427 			k = 0;
428 
429 			for(j=0; j<oddCount && unprocessCount; j++)
430 			{
431 				x = destX+vecX;
432 				y = destY+vecY;
433 
434 				if(x>=0 && y>=0 && x<MAX_WORLD_X_LOC && y<MAX_WORLD_Y_LOC)
435 				{
436 					if( worldLocMatrix[y*MAX_WORLD_X_LOC+x].is_unit_group_accessible(mobileType, curGroupId) )
437 						unprocessCount--;
438 				}
439 
440 				if(k++ < int(oddCount/2))	// reset vecX, vecY
441 					vecX -= move_scale;
442 				else
443 					vecY -= move_scale;
444 			}
445 			square_size+=move_scale;
446 			if(j<oddCount)
447 				not_tested_loc = oddCount-j;
448 			oddCount+=4;
449 
450 			if(unprocessCount)
451 			{
452 				//=============================
453 				// process even size square
454 				//=============================
455 				vecY = (-short(evenCount/4)-1)*move_scale;
456 				vecX = vecY+move_scale;
457 				k = 0;
458 
459 				for(j=0; j<evenCount && unprocessCount; j++)
460 				{
461 					x = destX+vecX;
462 					y = destY+vecY;
463 
464 					if(x>=0 && y>=0 && x<MAX_WORLD_X_LOC && y<MAX_WORLD_Y_LOC)
465 					{
466 						if(worldLocMatrix[y*MAX_WORLD_X_LOC+x].is_unit_group_accessible(mobileType, curGroupId) )
467 							unprocessCount--;
468 					}
469 
470 					if(k++ < int(evenCount/2))	// reset vecX, vecY
471 						vecX += move_scale;
472 					else
473 						vecY += move_scale;
474 				}
475 				square_size+=move_scale;
476 				if(j<evenCount)
477 					not_tested_loc = evenCount-j;
478 				evenCount+=4;
479 			}
480 		}
481 
482 		rec_height = rec_width = square_size;	// get the height and width of the rectangle
483 		if(not_tested_loc >= (square_size/move_scale))
484 			rec_width -= move_scale;
485 
486 		//--- decide to use upper_left_case or lower_right_case, however, it maybe changed for boundary improvement----//
487 		x = cal_rectangle_lower_right_x(destX);
488 		y = cal_rectangle_lower_right_y(destY);
489 
490 		for(i=0; i<sizeOneSelectedCount; i++)
491 		{
492 			unitPtr = (Unit*) get_ptr(selectedSizeOneUnitArray[i]);
493 
494 			if(unitPtr->next_y_loc()<y)		// lower_right_case or upper_left_case
495 				lower_right_case++;
496 			else if(unitPtr->next_y_loc()>y)
497 				upper_left_case++;
498 		}
499 
500 		if(lower_right_case==upper_left_case) // in case both values are equal, check by upper_left_case
501 		{
502 			x = cal_rectangle_upper_left_x(destX);
503 			y = cal_rectangle_upper_left_y(destY);
504 
505 			lower_right_case = upper_left_case = 0;
506 			for(i=0; i<sizeOneSelectedCount; i++)
507 			{
508 				unitPtr = (Unit*) get_ptr(selectedSizeOneUnitArray[i]);
509 
510 				if(unitPtr->next_y_loc()<y)		// lower_right_case or upper_left_case
511 					lower_right_case++;
512 				else if(unitPtr->next_y_loc()>y)
513 					upper_left_case++;
514 			}
515 		}
516 
517 		//------------ determine x, y and lower_right_case/upper_left_case-----------//
518 		determine_position_to_construct_table(selectedCount, destX, destY, mobileType);
519 		err_when(x<0 || y<0 || x>=MAX_WORLD_X_LOC || y>=MAX_WORLD_Y_LOC);
520 
521 		//------------ construct a table to store distance -------//
522 		construct_sorted_array(selectedSizeOneUnitArray, sizeOneSelectedCount);	// distance and sorted_member should be initialized first
523 		err_when(x<0 || y<0 || x>=MAX_WORLD_X_LOC || y>=MAX_WORLD_Y_LOC);
524 
525 		//------------ process the movement -----------//
526 		unprocessCount = sizeOneSelectedCount;//selectedCount;
527 		k=0;
528 
529 		//-******************* auto correct ***********************-//
530 		int autoCorrectStartX = x;
531 		int autoCorrectStartY = y;
532 		//-******************* auto correct ***********************-//
533 
534 		if(lower_right_case >= upper_left_case)
535 		{
536 			while(unprocessCount)
537 			{
538 				locPtr = worldLocMatrix+y*MAX_WORLD_X_LOC+x;
539 				for(i=x; i>x-rec_width && unprocessCount; i-=move_scale, locPtr-=move_scale)
540 				{
541 					if(locPtr->is_unit_group_accessible(mobileType, curGroupId))
542 					{
543 						do
544 						{
545 							unitPtr = (Unit*) get_ptr(selectedSizeOneUnitArray[sorted_member[k++]]);
546 						}while(unitPtr->sprite_info->loc_width>1);
547 
548 						err_when(k>sizeOneSelectedCount);
549 						if(sizeOneSelectedCount>1)
550 						{
551 							if(unprocessCount==sizeOneSelectedCount) // the first unit to move
552 							{
553 								unitPtr->move_to(i, y, 1, 4, 0, sizeOneSelectedCount, GENERAL_GROUP_MOVEMENT, REUSE_PATH_INITIAL);
554 								if(unitPtr->mobile_type==UNIT_LAND && unitPtr->nation_recno)
555 									unitPtr->select_search_sub_mode(unitPtr->next_x_loc(), unitPtr->next_y_loc(), i, y, unitPtr->nation_recno, SEARCH_MODE_REUSE);
556 								unitPtr->move_to(i, y, 1, 4, 0, sizeOneSelectedCount, GENERAL_GROUP_MOVEMENT, REUSE_PATH_FIRST_SEEK);
557 							}
558 							else
559 							{
560 								err_when(unprocessCount==sizeOneSelectedCount);
561 								if(unitPtr->mobile_type==UNIT_LAND && unitPtr->nation_recno)
562 									unitPtr->select_search_sub_mode(unitPtr->next_x_loc(), unitPtr->next_y_loc(), i, y, unitPtr->nation_recno, SEARCH_MODE_REUSE);
563 								unitPtr->move_to(i, y, 1, 4, 0, sizeOneSelectedCount, GENERAL_GROUP_MOVEMENT, REUSE_PATH_SEARCH);
564 							}
565 						}
566 						else
567 							unitPtr->move_to(i, y, 1);
568 						unprocessCount--;
569 					}
570 				}
571 				y-=move_scale;
572 				//-******************* auto correct ***********************-//
573 				#ifdef DEBUG
574 				err_when(unprocessCount && y<0);
575 				#else
576 				if(unprocessCount && y<0)
577 					y = autoCorrectStartY;
578 				#endif
579 				//-******************* auto correct ***********************-//
580 			}
581 		}
582 		else // upper_left_case
583 		{
584 			while(unprocessCount)
585 			{
586 				locPtr = worldLocMatrix+y*MAX_WORLD_X_LOC+x;
587 				for(i=x; i<x+rec_width && unprocessCount; i+=move_scale, locPtr+=move_scale)
588 				{
589 					if(locPtr->is_unit_group_accessible(mobileType, curGroupId))
590 					{
591 						do
592 						{
593 							unitPtr = (Unit*) get_ptr(selectedSizeOneUnitArray[sorted_member[k++]]);
594 						}while(unitPtr->sprite_info->loc_width>1);
595 						err_when(k>sizeOneSelectedCount);
596 
597 						if(sizeOneSelectedCount>1)
598 						{
599 							if(unprocessCount==sizeOneSelectedCount) // the first unit to move
600 							{
601 								unitPtr->move_to(i, y, 1, 4, 0, sizeOneSelectedCount, GENERAL_GROUP_MOVEMENT, REUSE_PATH_INITIAL);
602 								if(unitPtr->mobile_type==UNIT_LAND && unitPtr->nation_recno)
603 									unitPtr->select_search_sub_mode(unitPtr->next_x_loc(), unitPtr->next_y_loc(), i, y, unitPtr->nation_recno, SEARCH_MODE_REUSE);
604 								unitPtr->move_to(i, y, 1, 4, 0, sizeOneSelectedCount, GENERAL_GROUP_MOVEMENT, REUSE_PATH_FIRST_SEEK);
605 							}
606 							else
607 							{
608 								err_when(unprocessCount==sizeOneSelectedCount);
609 								if(unitPtr->mobile_type==UNIT_LAND && unitPtr->nation_recno)
610 									unitPtr->select_search_sub_mode(unitPtr->next_x_loc(), unitPtr->next_y_loc(), i, y, unitPtr->nation_recno, SEARCH_MODE_REUSE);
611 								unitPtr->move_to(i, y, 1, 4, 0, sizeOneSelectedCount, GENERAL_GROUP_MOVEMENT, REUSE_PATH_SEARCH);
612 							}
613 						}
614 						else
615 							unitPtr->move_to(i, y, 1);
616 						unprocessCount--;
617 					}
618 				}
619 				y+=move_scale;
620 				//-******************* auto correct ***********************-//
621 				if(unprocessCount && y>=MAX_WORLD_Y_LOC)
622 				{
623 					MSG("Unit attempted to walk off map...correcting.\n");
624 					y = autoCorrectStartY;
625 				}
626 				//-******************* auto correct ***********************-//
627 			}
628 		}
629 		//---------------- destruct data structure --------------//
630 		mem_del(done_flag);
631 		mem_del(sorted_distance);
632 		mem_del(sorted_member);
633 		mem_del(distance);
634 		mem_del(selectedSizeOneUnitArray);
635 	//}// end if (sizeOneSelectedCount)
636 	/*
637 	//=============================================================================//
638 	//----- order sprite with size two to move to a specified position ------------//
639 	//=============================================================================//
640 
641 	int sizeTwoUnprocessCount = sizeTwoSelectedCount;
642 	int surX, surY, suaCount=0;
643 	char w, h, blocked=0;
644 
645 	if(sizeOneSelectedCount)	// mix, size one units have processed
646 	{
647 		if(rec_width>square_size)
648 			square_size = rec_width;
649 		if(rec_height>square_size)
650 			square_size = rec_height;
651 		square_size = ((square_size+1)/2)<<1;	// change to multiply of two
652 		rec_width = rec_height = square_size;
653 
654 		x = destX-rec_width/2+1;
655 		y = destY-rec_height/2;
656 	}
657 	else	// all are size 2 units
658 	{
659 		//-***************** testing ********************-//
660 		err_here();
661 		//-***************** testing ********************-//
662 
663 		square_size = rec_width = rec_height = 2;
664 		x = destX;
665 		y = destY;
666 
667 		if(x<0)
668 			x = 0;
669 		else if(x>=MAX_WORLD_X_LOC-1)
670 			x = MAX_WORLD_X_LOC-2;
671 
672 		if(y<0)
673 			y = 0;
674 		else if(y>=MAX_WORLD_Y_LOC-1)
675 			y = MAX_WORLD_Y_LOC-2;
676 
677 		blocked = 0;
678 		for(h=0, surY=y; h<2 && !blocked; h++, surY++)
679 		{
680 			for(w=0, surX=x; w<2 && !blocked; w++, surX++)
681 			{
682 				locPtr = worldLocMatrix+surY*MAX_WORLD_X_LOC+surX;
683 				blocked = !locPtr->is_unit_group_accessible(mobileType, curGroupId);
684 			}
685 		}
686 
687 		if(!blocked)
688 		{
689 			do
690 			{
691 				unitPtr = (Unit*) get_ptr(selectedUnitArray[suaCount++]);
692 			}while(unitPtr->sprite_info->loc_width<2);
693 
694 			if(sizeTwoSelectedCount>1)
695 			{
696 				unitPtr->move_to(x, y, 1, 4, 0, sizeTwoSelectedCount, GENERAL_GROUP_MOVEMENT, REUSE_PATH_INITIAL);
697 				unitPtr->move_to(x, y, 1, 4, 0, sizeTwoSelectedCount, GENERAL_GROUP_MOVEMENT, REUSE_PATH_FIRST_SEEK);
698 			}
699 			else
700 				unitPtr->move_to(x, y, 1);
701 			sizeTwoUnprocessCount--;
702 		}
703 	}
704 
705 	while(sizeTwoUnprocessCount)
706 	{
707 		//-***************** testing ********************-//
708 		err_here();
709 		//-***************** testing ********************-//
710 
711 		int moveToX, moveToY;
712 		int boundedX, boundedY;
713 
714 		//------------- upper edge --------------//
715 		moveToY = y-2;
716 		moveToX = x;
717 		if(moveToY>=0)
718 		{
719 			if(x+rec_width+2 > MAX_WORLD_X_LOC-2)
720 				boundedX = MAX_WORLD_X_LOC-1;
721 			else
722 				boundedX = x+rec_width+2;
723 
724 			while(moveToX<boundedX && sizeTwoUnprocessCount)
725 			{
726 				//--------------- is the position blocked? ----------//
727 				if(moveToX>=MAX_WORLD_X_LOC-1 || moveToY>=MAX_WORLD_Y_LOC-1)
728 					blocked = 1;
729 				else
730 				{
731 					blocked = 0;
732 					for(h=0, surY=moveToY; h<2 && !blocked; h++, surY++)
733 					{
734 						for(w=0, surX=moveToX; w<2 && !blocked; w++, surX++)
735 						{
736 							locPtr = worldLocMatrix+surY*MAX_WORLD_X_LOC+surX;
737 							blocked = !locPtr->is_unit_group_accessible(mobileType, curGroupId);
738 						}
739 					}
740 				}
741 
742 				if(!blocked)
743 				{
744 					do
745 					{
746 						unitPtr = (Unit*) get_ptr(selectedUnitArray[suaCount++]);
747 					}while(unitPtr->sprite_info->loc_width<2);
748 
749 					if(sizeTwoSelectedCount>1)
750 					{
751 						if(sizeTwoUnprocessCount==sizeTwoSelectedCount) // the first unit to move
752 						{
753 							unitPtr->move_to(moveToX, moveToY, 1, 4, 0, sizeTwoSelectedCount, GENERAL_GROUP_MOVEMENT, REUSE_PATH_INITIAL);
754 							unitPtr->move_to(moveToX, moveToY, 1, 4, 0, sizeTwoSelectedCount, GENERAL_GROUP_MOVEMENT, REUSE_PATH_FIRST_SEEK);
755 						}
756 						else
757 						{
758 							err_if(sizeTwoUnprocessCount==sizeTwoSelectedCount)
759 								err_here();
760 
761 							unitPtr->move_to(moveToX, moveToY, 1, 4, 0, sizeTwoSelectedCount, GENERAL_GROUP_MOVEMENT, REUSE_PATH_SEARCH);
762 						}
763 					}
764 					else
765 						unitPtr->move_to(moveToX, moveToY, 1);
766 					sizeTwoUnprocessCount--;
767 				}
768 				moveToX+=2;
769 			}
770 		}
771 
772 		//------------- right edge --------------//
773 		moveToX = x+rec_width;
774 		moveToY = y;
775 		if(moveToX<MAX_WORLD_X_LOC-1)
776 		{
777 			if(y+rec_height+2 > MAX_WORLD_Y_LOC-2)
778 				boundedY = MAX_WORLD_Y_LOC-1;
779 			else
780 				boundedY = y+rec_height+2;
781 
782 			while(moveToY<boundedY && sizeTwoUnprocessCount)
783 			{
784 				//--------------- is the position blocked? ----------//
785 				if(moveToX>=MAX_WORLD_X_LOC-1 || moveToY>=MAX_WORLD_Y_LOC-1)
786 					blocked = 1;
787 				else
788 				{
789 					blocked = 0;
790 					for(h=0, surY=moveToY; h<2 && !blocked; h++, surY++)
791 					{
792 						for(w=0, surX=moveToX; w<2 && !blocked; w++, surX++)
793 						{
794 							locPtr = worldLocMatrix+surY*MAX_WORLD_X_LOC+surX;
795 							blocked = !locPtr->is_unit_group_accessible(mobileType, curGroupId);
796 						}
797 					}
798 				}
799 
800 				if(!blocked)
801 				{
802 					do
803 					{
804 						unitPtr = (Unit*) get_ptr(selectedUnitArray[suaCount++]);
805 					}while(unitPtr->sprite_info->loc_width<2);
806 
807 					if(sizeTwoSelectedCount>1)
808 					{
809 						if(sizeTwoUnprocessCount==sizeTwoSelectedCount) // the first unit to move
810 						{
811 							unitPtr->move_to(moveToX, moveToY, 1, 4, 0, sizeTwoSelectedCount, GENERAL_GROUP_MOVEMENT, REUSE_PATH_INITIAL);
812 							unitPtr->move_to(moveToX, moveToY, 1, 4, 0, sizeTwoSelectedCount, GENERAL_GROUP_MOVEMENT, REUSE_PATH_FIRST_SEEK);
813 						}
814 						else
815 						{
816 							err_if(sizeTwoUnprocessCount==sizeTwoSelectedCount)
817 								err_here();
818 
819 							unitPtr->move_to(moveToX, moveToY, 1, 4, 0, sizeTwoSelectedCount, GENERAL_GROUP_MOVEMENT, REUSE_PATH_SEARCH);
820 						}
821 					}
822 					else
823 						unitPtr->move_to(moveToX, moveToY, 1);
824 					sizeTwoUnprocessCount--;
825 				}
826 				moveToY+=2;
827 			}
828 		}
829 
830 		//------------- lower edge ----------------//
831 		moveToX = x+rec_width-2;
832 		moveToY = y+rec_height;
833 		if(moveToY<MAX_WORLD_Y_LOC-1)
834 		{
835 			if(x-3 < 0)
836 				boundedX = -1;
837 			else
838 				boundedX = x-3;
839 
840 			while(moveToX>boundedX && sizeTwoUnprocessCount)
841 			{
842 				//--------------- is the position blocked? ----------//
843 				if(moveToX>=MAX_WORLD_X_LOC-1 || moveToY>=MAX_WORLD_Y_LOC-1)
844 					blocked = 1;
845 				else
846 				{
847 					blocked = 0;
848 					for(h=0, surY=moveToY; h<2 && !blocked; h++, surY++)
849 					{
850 						for(w=0, surX=moveToX; w<2 && !blocked; w++, surX++)
851 						{
852 							locPtr = worldLocMatrix+surY*MAX_WORLD_X_LOC+surX;
853 							blocked = !locPtr->is_unit_group_accessible(mobileType, curGroupId);
854 						}
855 					}
856 				}
857 
858 				if(!blocked)
859 				{
860 					do
861 					{
862 						unitPtr = (Unit*) get_ptr(selectedUnitArray[suaCount++]);
863 					}while(unitPtr->sprite_info->loc_width<2);
864 					if(sizeTwoSelectedCount>1)
865 					{
866 						if(sizeTwoUnprocessCount==sizeTwoSelectedCount) // the first unit to move
867 						{
868 							unitPtr->move_to(moveToX, moveToY, 1, 4, 0, sizeTwoSelectedCount, GENERAL_GROUP_MOVEMENT, REUSE_PATH_INITIAL);
869 							unitPtr->move_to(moveToX, moveToY, 1, 4, 0, sizeTwoSelectedCount, GENERAL_GROUP_MOVEMENT, REUSE_PATH_FIRST_SEEK);
870 						}
871 						else
872 						{
873 							err_if(sizeTwoUnprocessCount==sizeTwoSelectedCount)
874 								err_here();
875 
876 							unitPtr->move_to(moveToX, moveToY, 1, 4, 0, sizeTwoSelectedCount, GENERAL_GROUP_MOVEMENT, REUSE_PATH_SEARCH);
877 						}
878 					}
879 					else
880 						unitPtr->move_to(moveToX, moveToY, 1);
881 					sizeTwoUnprocessCount--;
882 				}
883 				moveToX-=2;
884 			}
885 		}
886 
887 		//------------- left edge ---------------//
888 		moveToX = x-2;
889 		moveToY = y+rec_height-2;
890 		if(moveToX>=0)
891 		{
892 			if(y-3 < 0)
893 				boundedY = -1;
894 			else
895 				boundedY = y-3;
896 
897 			while(moveToY>boundedY && sizeTwoUnprocessCount)
898 			{
899 				//--------------- is the position blocked? ----------//
900 				if(moveToX>=MAX_WORLD_X_LOC-1 || moveToY>=MAX_WORLD_Y_LOC-1)
901 					blocked = 1;
902 				else
903 				{
904 					blocked = 0;
905 					for(h=0, surY=moveToY; h<2 && !blocked; h++, surY++)
906 					{
907 						for(w=0, surX=moveToX; w<2 && !blocked; w++, surX++)
908 						{
909 							locPtr = worldLocMatrix+surY*MAX_WORLD_X_LOC+surX;
910 							blocked = !locPtr->is_unit_group_accessible(mobileType, curGroupId);
911 						}
912 					}
913 				}
914 
915 				if(!blocked)
916 				{
917 					do
918 					{
919 						unitPtr = (Unit*) get_ptr(selectedUnitArray[suaCount++]);
920 					}while(unitPtr->sprite_info->loc_width<2);
921 
922 					if(sizeTwoSelectedCount>1)
923 					{
924 						if(sizeTwoUnprocessCount==sizeTwoSelectedCount) // the first unit to move
925 						{
926 							unitPtr->move_to(moveToX, moveToY, 1, 4, 0, sizeTwoSelectedCount, GENERAL_GROUP_MOVEMENT, REUSE_PATH_INITIAL);
927 							unitPtr->move_to(moveToX, moveToY, 1, 4, 0, sizeTwoSelectedCount, GENERAL_GROUP_MOVEMENT, REUSE_PATH_FIRST_SEEK);
928 						}
929 						else
930 						{
931 							err_if(sizeTwoUnprocessCount==sizeTwoSelectedCount)
932 								err_here();
933 
934 							unitPtr->move_to(moveToX, moveToY, 1, 4, 0, sizeTwoSelectedCount, GENERAL_GROUP_MOVEMENT, REUSE_PATH_SEARCH);
935 						}
936 					}
937 					else
938 						unitPtr->move_to(moveToX, moveToY, 1);
939 					sizeTwoUnprocessCount--;
940 				}
941 				moveToY-=2;
942 			}
943 		}
944 
945 		//------- reset square_size, rec_width, rec_height -----------//
946 		rec_width+=4;
947 		rec_height+=4;
948 		x-=2;
949 		y-=2;
950 	}*/
951 }
952 //----------- End of function UnitArray::move_to_now -----------//
953 
954 
955 //----------Begin of function UnitArray::construct_sorted_array------------//
956 //
957 // construct a table to store the d(x,y) value from the reference(rectangule
958 // starting) point in group movement control
959 //
960 // For the detail, see ounitam.txt
961 //
962 //
963 // <short*> selectedUnitArray  - an array of recno of selected units.
964 // <int>    selectedCount 		 - no. of selected units.
965 //
construct_sorted_array(short * selectedUnitArray,int selectedCount)966 void UnitArray::construct_sorted_array(short* selectedUnitArray, int selectedCount)
967 {
968 	Unit*			unitPtr;
969 	int			MIN, dist;		// for comparison
970 	int			i, j, k;
971 	const int	c = 1000;		// c value for the d(x,y) function
972 
973 	if(lower_right_case >= upper_left_case)
974 	{
975 		for(i=0; i<selectedCount; i++)
976 		{
977 			unitPtr = (Unit*) get_ptr(selectedUnitArray[i]);
978 			// d(x,y)=x+c*|y|
979 			distance[i] = MAX_WORLD_X_LOC;	// to aviod -ve no. in the following line
980 			distance[i] += (x-unitPtr->cur_x_loc()+c*abs(unitPtr->cur_y_loc()-y)); // plus/minus x coord difference
981 		}
982 	}
983 	else	// upper_left_case
984 	{
985 		for(i=0; i<selectedCount; i++)
986 		{
987 			unitPtr = (Unit*) get_ptr(selectedUnitArray[i]);
988 			// d(x,y)=x+c*|y|
989 			distance[i] = MAX_WORLD_X_LOC;	// to aviod -ve no. in the following line
990 			distance[i] += (unitPtr->cur_x_loc()-x+c*abs(unitPtr->cur_y_loc()-y)); // plus/minus x coord difference
991 		}
992 	}
993 
994 	//---------------------------------------------------------------//
995 	// this part of code using a technique to adjust the distance value
996 	// such that the selected group can change from lower right form
997 	// to upper left form or upper left form to lower right form in a
998 	// better way.
999 	//---------------------------------------------------------------//
1000 	//------ sorting the distance and store in sortedDistance Array -------//
1001 	for(j=0; j<selectedCount; j++)
1002 	{
1003 		MIN = 0xFFFFFF;
1004 		for(i=0; i<selectedCount; i++)
1005 		{
1006 			if(done_flag[i]==0 && (dist = distance[i])<MIN)
1007 			{
1008 				MIN = dist;
1009 				k = i;
1010 			}
1011 		}
1012 		sorted_distance[j] = k;
1013 		done_flag[k] = 1;
1014 	}
1015 
1016 	//----------------- find the minimum value --------------//
1017 	#ifdef DEBUG
1018 		MIN = 0xFFFFFF;
1019 		for(j=0; j<selectedCount; j++)
1020 		{
1021 			if((dist = distance[j])<MIN)
1022 				MIN = dist;
1023 		}
1024 
1025 		err_when(MIN!=distance[sorted_distance[0]]);
1026 	#else
1027 		MIN = distance[sorted_distance[0]];
1028 	#endif
1029 
1030 	int defArraySize		= 5;	//****** BUGHERE, 5 is chosen arbitrary
1031 	int *leftQuotZ  = (int*) mem_add(defArraySize*sizeof(int));
1032 	int *rightQuotZ = (int*) mem_add(defArraySize*sizeof(int));
1033 	int remainder = MIN%c;
1034 	int index;
1035 
1036 	//-- adjust the value to allow changing form between upper left and lower right shape --//
1037 
1038 	for(j=0; j<defArraySize; j++)
1039 		leftQuotZ[j] = rightQuotZ[j] = MIN-remainder;
1040 
1041 	for(j=0; j<selectedCount; j++)
1042 	{
1043 		if((dist = distance[sorted_distance[j]]%c) < remainder)
1044 		{
1045 			if((index = remainder-dist) <= defArraySize)	// the case can be handled by this array size
1046 			{
1047 				distance[sorted_distance[j]] = leftQuotZ[index-1] + dist;
1048 				leftQuotZ[index-1] += c;
1049 			}
1050 		}
1051 		else
1052 		{
1053 			if(dist>=remainder)
1054 			{
1055 				if((index = dist-remainder) < defArraySize)	// the case can be handled by this array size
1056 				{
1057 					distance[sorted_distance[j]] = rightQuotZ[index] + dist;
1058 					rightQuotZ[index] += c;
1059 				}
1060 			}
1061 		}
1062 	}
1063 
1064 	mem_del(leftQuotZ);
1065 	mem_del(rightQuotZ);
1066 
1067 	//---------- sorting -------------//
1068 	for(j=0; j<selectedCount; j++)
1069 	{
1070 		MIN = 0xFFFFFF;
1071 		for(i=0; i<selectedCount; i++)
1072 		{
1073 			if((dist = distance[i])<MIN)
1074 			{
1075 				MIN = dist;
1076 				k = i;
1077 			}
1078 		}
1079 		sorted_member[j] = k;
1080 		distance[k] = 0xFFFFFF;
1081 	}
1082 }
1083 //--------End of function UnitArray::construct_sorted_array----------------//
1084 
1085 
1086 //--- Begin of function UnitArray::determine_position_to_construct_table ---//
1087 //
1088 // determine the position of the rectangule starting point in the two forms
1089 //	(i.e. upper left case or lower right case). This point is used to indicate
1090 // the direction to fill the rectangle
1091 //
1092 // <int> 	destXLoc, destYLoc - the location of the destination.
1093 // <int>    selectedCount 		 - no. of selected units.
1094 //
determine_position_to_construct_table(int selectedCount,int destXLoc,int destYLoc,char mobileType)1095 void UnitArray::determine_position_to_construct_table(int selectedCount, int destXLoc, int destYLoc, char mobileType)
1096 {
1097 	//======================================================================//
1098 	// boundary, corner improvement
1099 	//======================================================================//
1100 	int sqrtValue;
1101 
1102 	//======================================================================//
1103 	// lower right case
1104 	//======================================================================//
1105 	if(lower_right_case>=upper_left_case)
1106 	{
1107 		//--------- calculate x, y location for lower right case ---------//
1108 		x = cal_rectangle_lower_right_x(destXLoc);
1109 		y = cal_rectangle_lower_right_y(destYLoc);
1110 
1111 		if(x<rec_width)
1112 		{
1113 			//================== left edge =================//
1114 			sqrtValue = (int)sqrt((float)selectedCount);
1115 			if(sqrtValue*sqrtValue != selectedCount)
1116 				sqrtValue++;
1117 			if(mobileType!=UNIT_LAND)
1118 				sqrtValue = sqrtValue<<1; // change to scale 2
1119 			rec_width = rec_height = sqrtValue;
1120 
1121 			//------------- top left corner --------------//
1122 			if(y<rec_height)
1123 			{
1124 				upper_left_case = lower_right_case+1;
1125 				x = y = 0;
1126 			}
1127 			//------------ bottom left corner ---------------//
1128 			else if(y>=MAX_WORLD_Y_LOC-move_scale)
1129 			{
1130 				if(not_tested_loc>=square_size/move_scale)
1131 					rec_width -= move_scale;
1132 
1133 				x = rec_width-move_scale;
1134 				y = MAX_WORLD_Y_LOC-move_scale;
1135 			}
1136 			//------------- just left edge -------------//
1137 			else
1138 				x = rec_width-move_scale;
1139 		}
1140 		else if(x>=MAX_WORLD_X_LOC-move_scale)
1141 		{
1142 			//============== right edge ==============//
1143 
1144 			//----------- top right corner -----------//
1145 			if(y<rec_height)
1146 			{
1147 				sqrtValue = (int)sqrt((float)selectedCount);
1148 				if(sqrtValue*sqrtValue != selectedCount)
1149 					sqrtValue++;
1150 				if(mobileType!=UNIT_LAND)
1151 					sqrtValue = sqrtValue<<1; // change to scale 2
1152 				rec_width = rec_height = sqrtValue;
1153 
1154 				upper_left_case = lower_right_case+1;
1155 				x = MAX_WORLD_X_LOC-rec_width;
1156 				y = 0;
1157 			}
1158 			//---------- bottom right corner ------------//
1159 			else if(y>=MAX_WORLD_Y_LOC-move_scale)
1160 			{
1161 				y = MAX_WORLD_Y_LOC-move_scale;
1162 				x = MAX_WORLD_X_LOC-move_scale;
1163 			}
1164 			//---------- just right edge ---------------//
1165 			else
1166 			{
1167 				int squareSize = square_size/move_scale;
1168 				if(squareSize*(squareSize-1)>=selectedCount)
1169 					rec_width -= move_scale;
1170 				x = MAX_WORLD_X_LOC-move_scale;
1171 			}
1172 		}
1173 		else if(y<rec_height)
1174 		{
1175 			//================= top edge ===============//
1176 			sqrtValue = (int)sqrt((float)selectedCount);
1177 			if(sqrtValue*sqrtValue != selectedCount)
1178 				sqrtValue++;
1179 			if(mobileType!=UNIT_LAND)
1180 				sqrtValue = sqrtValue<<1; // change to scale 2
1181 			rec_width = rec_height = sqrtValue;
1182 
1183 			upper_left_case = lower_right_case+1;
1184 			//if(mobileType==UNIT_LAND)
1185 			//	x = destXLoc-((rec_width-1)/2);
1186 			//else
1187 			//	x = destXLoc-(rec_width/4)*2;
1188 			x = cal_rectangle_upper_left_x(destXLoc);
1189 			y = 0;
1190 		}
1191 		else if(y>=MAX_WORLD_Y_LOC-move_scale)
1192 		{
1193 			//================== bottom edge ====================//
1194 			if(not_tested_loc>=square_size/move_scale)
1195 				rec_width += move_scale;
1196 
1197 			//if(mobileType==UNIT_LAND)
1198 			//	x = destXLoc+(rec_width/2);
1199 			//else
1200 			//	x = destXLoc+(rec_width/4)*2;
1201 			x = cal_rectangle_lower_right_x(destXLoc);
1202 			y = MAX_WORLD_Y_LOC-move_scale;
1203 		}
1204 	}
1205 	//======================================================================//
1206 	// upper left case
1207 	//======================================================================//
1208 	else
1209 	{
1210 		//--------- calculate x, y location for upper left case ---------//
1211 		x = cal_rectangle_upper_left_x(destXLoc);
1212 		y = cal_rectangle_upper_left_y(destYLoc);
1213 
1214 		if(x<0)
1215 		{
1216 			//================= left edge ==================//
1217 
1218 			//------------- top left corner --------------//
1219 			if(y<0)
1220 			{
1221 				sqrtValue = (int)sqrt((float)selectedCount);
1222 				if(sqrtValue*sqrtValue != selectedCount)
1223 					sqrtValue++;
1224 				if(mobileType!=UNIT_LAND)
1225 					sqrtValue = sqrtValue<<1; // change to scale 2
1226 				rec_width = rec_height = sqrtValue;
1227 				x = y = 0;
1228 			}
1229 			//------------- bottom left corner --------------//
1230 			else if(y+rec_height>=MAX_WORLD_Y_LOC-move_scale)
1231 			{
1232 				lower_right_case = upper_left_case+1;
1233 				x = rec_width-move_scale;
1234 				y = MAX_WORLD_Y_LOC-move_scale;
1235 			}
1236 			//------------- just left edge ------------------//
1237 			else
1238 			{
1239 				sqrtValue = (int)sqrt((float)selectedCount);
1240 				if(sqrtValue*sqrtValue != selectedCount)
1241 					sqrtValue++;
1242 				if(mobileType!=UNIT_LAND)
1243 					sqrtValue = sqrtValue<<1; // change to scale 2
1244 				rec_width = rec_height = sqrtValue;
1245 				x = 0;
1246 			}
1247 		}
1248 		//================ right edge ================//
1249 		else if(x+rec_width>=MAX_WORLD_X_LOC-move_scale)
1250 		{
1251 			//------------- top right corner ------------------//
1252 			if(y<0)
1253 			{
1254 				sqrtValue = (int)sqrt((float)selectedCount);
1255 				if(sqrtValue*sqrtValue != selectedCount)
1256 					sqrtValue++;
1257 				if(mobileType!=UNIT_LAND)
1258 					sqrtValue = sqrtValue<<1; // change to scale 2
1259 				rec_width = rec_height = sqrtValue;
1260 				x = MAX_WORLD_X_LOC-rec_width;
1261 				y = 0;
1262 			}
1263 			//------------- bottom right corner ------------------//
1264 			else if(y+rec_height>=MAX_WORLD_Y_LOC-move_scale)
1265 			{
1266 				lower_right_case = upper_left_case+1;
1267 				x = MAX_WORLD_X_LOC-move_scale;
1268 				y = MAX_WORLD_Y_LOC-move_scale;
1269 			}
1270 			//------------- just right edge ------------------//
1271 			else
1272 			{
1273 				sqrtValue = (int)sqrt((float)selectedCount);
1274 				if(sqrtValue*sqrtValue != selectedCount)
1275 					sqrtValue++;
1276 				if(mobileType!=UNIT_LAND)
1277 					sqrtValue = sqrtValue<<1; // change to scale 2
1278 				rec_width = rec_height = sqrtValue;
1279 
1280 				int squareSize = square_size/move_scale;
1281 				if(squareSize*(squareSize-1)>=selectedCount)
1282 					rec_width -= move_scale;
1283 				lower_right_case = upper_left_case+1;
1284 				x = MAX_WORLD_X_LOC-move_scale;
1285 				//if(mobileType==UNIT_LAND)
1286 				//	y = destYLoc+((rec_height-1)/2);
1287 				//else
1288 				//	y = destYLoc+((rec_height-2)/4)*2;
1289 				y = cal_rectangle_lower_right_y(destYLoc);
1290 			}
1291 		}
1292 		//================= top edge ================//
1293 		else if(y<0)
1294 		{
1295 			sqrtValue = (int)sqrt((float)selectedCount);
1296 			if(sqrtValue*sqrtValue != selectedCount)
1297 				sqrtValue++;
1298 
1299 			rec_width = rec_height = sqrtValue;
1300 			y = 0;
1301 		}
1302 		//================= bottom edge ================//
1303 		else if(y+rec_height>=MAX_WORLD_Y_LOC-move_scale)
1304 		{
1305 			if(not_tested_loc>=square_size)
1306 				rec_width += move_scale;
1307 			y = MAX_WORLD_Y_LOC-move_scale;
1308 		}
1309 	}
1310 
1311 	/*if(lower_right_case>=upper_left_case)
1312 	{
1313 		x = cal_rectangle_lower_right_x(destXLoc);
1314 		y = cal_rectangle_lower_right_y(destYLoc);
1315 
1316 		rec_x1 = x - rec_width + move_scale;
1317 		rec_y1 = y - rec_height + move_scale;
1318 		rec_x2 = x;
1319 		rec_y2 = y;
1320 	}
1321 	else
1322 	{
1323 		x = cal_rectangle_upper_left_x(destXLoc);
1324 		y = cal_rectangle_upper_left_y(destYLoc);
1325 	}*/
1326 }
1327 //--- End of function UnitArray::determine_position_to_construct_table -----//
1328