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	  : OPOWER.CPP
22 //Description : Object Power
23 
24 #include <OMOUSE.h>
25 #include <OMOUSECR.h>
26 #include <OUNIT.h>
27 #include <OFIRM.h>
28 #include <OTOWN.h>
29 #include <OSITE.h>
30 #include <OSYS.h>
31 #include <ONATION.h>
32 #include <OBOX.h>
33 #include <OIMGRES.h>
34 #include <OMOUSECR.h>
35 #include <OWORLD.h>
36 #include <OINFO.h>
37 #include <OU_CARA.h>
38 #include <OU_MARI.h>
39 #include <OPOWER.h>
40 #include <OWALLRES.h>
41 #include <OSERES.h>
42 #include <OREMOTE.h>
43 
44 //-------------- Define constant -----------------//
45 
46 #define DETECT_SPREAD 	3
47 
48 static short nation_divide_order[MAX_NATION+1] = {1, 2, 3, 4, 5, 6, 7, 0};
49 
50 
51 //-------- Begin of static function is_unit_higher_rank --------//
52 //
53 // Determines which unit is more important to be be displayed
54 // in the selection.
55 //
56 // <return> true if recno1 is consider more important than recno2
57 //
58 // ##### Richard Dijk 26-4-2013 #####
59 //
is_unit_higher_rank(int recno1,int recno2)60 static bool is_unit_higher_rank(int recno1, int recno2)
61 {
62 	Unit *unitPtr1 = unit_array[recno1], *unitPtr2 = unit_array[recno2];
63 
64 	if (unitPtr1->rank_id > unitPtr2->rank_id) // RANK_KING > RANK_GENERAL > RANK_SOLDIER
65 		return true;
66 	else if (unitPtr1->rank_id == unitPtr2->rank_id)
67 	{
68 		if (unit_res[unitPtr1->unit_id]->unit_class == UNIT_CLASS_HUMAN &&
69 			unit_res[unitPtr2->unit_id]->unit_class != UNIT_CLASS_HUMAN)	// Favour humans
70 			return true;
71 		else if (unitPtr1->skill.skill_id && !unitPtr2->skill.skill_id)		// Between equal classes, favour the one with a skill
72 			return true;
73 	}
74 	return false;
75 }
76 //--------- End of static function is_unit_higher_rank ---------//
77 
78 
79 //-------- Begin of static function divide_by_nation --------//
divide_by_nation(short * nationUnitCount,short * selectedArray,int selectedCount)80 static void divide_by_nation(short *nationUnitCount, short *selectedArray, int selectedCount)
81 {
82 	short *orderedArray = (short*) mem_add(sizeof(short)*selectedCount);
83 	short *nationOrderPtr = nation_divide_order;
84 	short unitCount = 0;
85 
86 	short *selectedUnitPtr;
87 	Unit	*unitPtr;
88 	int i, j;
89 
90 	for(i=0; i<=MAX_NATION; ++i, nationOrderPtr++)
91 	{
92 		for(j=0, selectedUnitPtr=selectedArray; j<selectedCount; ++j, selectedUnitPtr++)
93 		{
94 			err_when(unit_array.is_deleted(*selectedUnitPtr));
95 			unitPtr = unit_array[*selectedUnitPtr];
96 
97 			if(unitPtr->nation_recno == *nationOrderPtr)
98 				orderedArray[unitCount++] = *selectedUnitPtr;
99 		}
100 
101 		err_when(unitCount>selectedCount);
102 		nationUnitCount[i] = unitCount;
103 		if(i<MAX_NATION && unitCount==selectedCount)
104 		{
105 			for(int k=i+1; k<=MAX_NATION; ++k)
106 				nationUnitCount[k] = selectedCount;
107 
108 			break;
109 		}
110 	}
111 
112 	memcpy(selectedArray, orderedArray, sizeof(short) * selectedCount);
113 	mem_del(orderedArray);
114 	orderedArray = NULL;
115 }
116 //--------- End of static function divide_by_nation ---------//
117 
118 
119 //----------- Begin of function Power::Power -----------//
120 
Power()121 Power::Power()
122 {
123 	memset( this, 0, sizeof(Power) );
124 }
125 //----------- End of function Power::Power -----------//
126 
127 
128 //----------- Begin of function Power::~Power -----------//
129 
~Power()130 Power::~Power()
131 {
132 }
133 //----------- End of function Power::~Power -----------//
134 
135 
136 //----------- Begin of function Power::init -----------//
137 
init()138 void Power::init()
139 {
140 	memset( this, 0, sizeof(Power) );
141 
142 	reset_selection();		// there may be selections left by the previous game.
143 }
144 //----------- End of function Power::init -----------//
145 
146 
147 //-------- Begin of function Power::mouse_handler --------//
148 //
149 // React immediately when the mouse is moved or clicked.
150 //
mouse_handler()151 void Power::mouse_handler()
152 {
153 	if( sys.view_mode == MODE_TRADE )
154 	{
155 		// Setting stops is allowed in the trade report, display cursor
156 		if( command_id == COMMAND_SET_CARAVAN_STOP )
157 		{
158 			mouse_cursor.set_icon(CURSOR_SET_STOP);
159 			return;
160 		}
161 		if( command_id == COMMAND_SET_SHIP_STOP )
162 		{
163 			mouse_cursor.set_icon(CURSOR_SHIP_STOP);
164 			return;
165 		}
166 	}
167 
168 	if( sys.view_mode != MODE_NORMAL && sys.view_mode != MODE_TRADE )
169 	{
170 		mouse_cursor.set_icon(CURSOR_NORMAL);
171 		return;
172 	}
173 
174 	if( !enable_flag || win_opened || Box::opened_flag ||
175 		 sys.signal_exit_flag  )		// a window or box is opened upon the current interface
176 	{
177 		return;
178 	}
179 
180 	//---- if there is an object at where the mouse cursor is pointing at, change the cursor shape ----//
181 
182 	Location *pointingLoc;
183 	short selectedRecno = 0;
184 	ScreenObjectType selectedType = find_selected_type(&selectedRecno);
185 	if( mouse.cur_x >= ZOOM_X1 && mouse.cur_x <= ZOOM_X2 &&
186 		 mouse.cur_y >= ZOOM_Y1 && mouse.cur_y <= ZOOM_Y2 &&
187 		 (pointingLoc = test_detect(mouse.cur_x, mouse.cur_y))!= NULL)
188 	{
189 		// ------- pointing something -------//
190 		short pointingRecno;
191 		ScreenObjectType pointingType = find_pointing_type(pointingLoc, &pointingRecno);
192 		mouse_cursor.set_icon( choose_cursor(mouse.cur_x, mouse.cur_y,
193 			selectedType, selectedRecno, pointingType, pointingRecno) );
194 	}
195 	else
196 		mouse_cursor.set_icon( choose_cursor(mouse.cur_x, mouse.cur_y,
197 			selectedType, selectedRecno, SCREEN_OBJECT_NONE, 0) );
198 
199 	//---- pressing right button in command mode -> cancel command mode ----//
200 
201 	if( mouse.right_press && command_id )
202 	{
203 		command_id = 0;
204 		info.disp();
205 		return;
206 	}
207 /*
208 	//------ detect selecting objects and laying tracks ------//
209 
210 	if( detect_frame() )
211 		return;
212 
213 	//----- detect right mouse button to select defined unit groups -----//
214 
215 	int shiftPressed = GetKeyState(VK_SHIFT) & 0X0100;		// return the current real-time key state
216 
217 	if( mouse.right_press && !shiftPressed )		// shift key to override the standard selection action and go for attacking own units
218 	{
219 		if( mouse.cur_x >= ZOOM_X1 && mouse.cur_x <= ZOOM_X2 &&		// if the mouse is inside the zoom area
220 			 mouse.cur_y >= ZOOM_Y1 && mouse.cur_y <= ZOOM_Y2 )
221 		{
222 			if( detect_select( mouse.cur_x, mouse.cur_y,
223 									 mouse.cur_x, mouse.cur_y, 1 ) )		// 1-recall group
224 			{
225 				return;
226 			}
227 		}
228 	}
229 
230 	//----------- detect action ------------//
231 
232 	// ##### begin Gilbert 29/5 ########//
233 	if( detect_action() && unit_array.selected_recno )
234 	{
235 		if( se_res.mark_command_time() )
236 		{
237 			Unit *unitPtr = unit_array[unit_array.selected_recno];
238 			se_res.far_sound( unitPtr->cur_x_loc(), unitPtr->cur_y_loc(), 1, 'S',
239 				unitPtr->sprite_id, "ACK");
240 		}
241 	}
242 	// ##### end Gilbert 29/5 ########//
243 	*/
244 }
245 //--------- End of function Power::mouse_handler ---------//
246 
247 
248 //-------- Begin of function Power::detect_frame --------//
249 //
250 // Detect selecting objects or laying tracks with the mouse
251 // selection frame.
252 //
253 // return: <int> 1 - objects selected or tracks built.
254 //					  0 - nothing selected or built.
255 //
detect_frame()256 int Power::detect_frame()
257 {
258 	//----- detect left mouse button to activate frame selection -----//
259 
260 	int rc=0, selectedCount=0;
261 	Location* locPtr;
262 
263 	if( mouse.is_mouse_event() )
264 	{
265 		if( mouse.mouse_event_type == LEFT_BUTTON )
266 		{
267 			int mouseX = mouse.click_x(LEFT_BUTTON);
268 			int mouseY = mouse.click_y(LEFT_BUTTON);
269 
270 			if( !mouse_cursor.frame_flag )
271 			{
272 				if( mouseX >= ZOOM_X1 && mouseX <= ZOOM_X2 &&		// if the mouse is inside the zoom area
273 					 mouseY >= ZOOM_Y1 && mouseY <= ZOOM_Y2 )
274 				{
275 					int curXLoc = world.zoom_matrix->top_x_loc + (mouseX-ZOOM_X1)/ZOOM_LOC_WIDTH;
276 					int curYLoc = world.zoom_matrix->top_y_loc + (mouseY-ZOOM_Y1)/ZOOM_LOC_HEIGHT;
277 
278 					locPtr = world.get_loc(curXLoc, curYLoc);
279 
280 					//-------- set boundary of mouse -------//
281 
282 					mouse.set_boundary(ZOOM_X1, ZOOM_Y1, ZOOM_X2, ZOOM_Y2);
283 
284 					//------- activate frame selection --------//
285 
286 					switch(command_id)
287 					{
288 						case COMMAND_BUILD_FIRM:
289 							if(!unit_array.is_deleted(command_unit_recno) && unit_array[command_unit_recno]->is_visible())
290 							{
291 								Unit *cmdUnit = unit_array[command_unit_recno];
292 								if( se_res.mark_command_time() )
293 								{
294 									se_res.far_sound( cmdUnit->cur_x_loc(), cmdUnit->cur_y_loc(), 1,
295 										'S', cmdUnit->sprite_id, "ACK" );
296 								}
297 								cmdUnit->build_firm(curXLoc, curYLoc, command_para, COMMAND_PLAYER);
298 							}
299 							command_id = 0;
300 							rc = 1;
301 							info.disp();
302 							break;
303 
304 						case COMMAND_BURN:
305 							if(!unit_array.is_deleted(command_unit_recno) && unit_array[command_unit_recno]->is_visible())
306 							{
307 								Unit *cmdUnit = unit_array[command_unit_recno];
308 								if( se_res.mark_command_time() )
309 								{
310 									se_res.far_sound( cmdUnit->cur_x_loc(), cmdUnit->cur_y_loc(), 1,
311 										'S', cmdUnit->sprite_id, "ACK" );
312 								}
313 								cmdUnit->burn(curXLoc, curYLoc, COMMAND_PLAYER);
314 							}
315 							command_id = 0;
316 							rc = 1;
317 							break;
318 
319 						case COMMAND_SETTLE:
320 							if( se_res.mark_command_time() )
321 							{
322 								Unit *repUnit = unit_array[unit_array.selected_recno];
323 								se_res.far_sound( repUnit->cur_x_loc(), repUnit->cur_y_loc(), 1,
324 									'S', repUnit->sprite_id, "ACK");
325 							}
326 							if( locPtr->is_town() && town_array[locPtr->town_recno()]->nation_recno == unit_array[unit_array.selected_recno]->nation_recno )
327 							{
328 								Town *townPtr = town_array[locPtr->town_recno()];
329 								unit_array.assign(townPtr->loc_x1, townPtr->loc_y1, 0, COMMAND_PLAYER );		// assign to an existing town
330 							}
331 							else
332 								unit_array.settle(curXLoc, curYLoc, 0, COMMAND_PLAYER);		// settle as a new town
333 							command_id = 0;
334 							rc = 1;
335 							info.disp();
336 							break;
337 
338 						case COMMAND_SET_CARAVAN_STOP:
339 							if(unit_array[command_unit_recno]->is_visible())
340 							{
341 								UnitCaravan* unitPtr = (UnitCaravan*) unit_array[command_unit_recno];
342 								err_when( unitPtr->unit_id != UNIT_CARAVAN );
343 								// find the firm it is pointing
344 								Location *locPtr = world.get_loc(curXLoc, curYLoc);
345 								Firm *firmPtr;
346 								if( locPtr->is_firm() && (firmPtr = firm_array[locPtr->firm_recno()])
347 									&& unitPtr->can_set_stop(firmPtr->firm_recno) )
348 								{
349 									if( se_res.mark_command_time() )
350 									{
351 										se_res.far_sound( unitPtr->cur_x_loc(), unitPtr->cur_y_loc(), 1,
352 											'S', unitPtr->sprite_id, "ACK");
353 									}
354 									unitPtr->set_stop(command_para, curXLoc, curYLoc, COMMAND_PLAYER);		// command_para is the id. of the stop
355 								}
356 							}
357 							command_id = 0;
358 							rc = 1;
359 							break;
360 
361 						case COMMAND_SET_SHIP_STOP:
362 							if(unit_array[command_unit_recno]->is_visible())
363 							{
364 								UnitMarine* unitPtr = (UnitMarine*) unit_array[command_unit_recno];
365 								err_when( unit_res[unitPtr->unit_id]->mobile_type != UNIT_SEA );
366 								// find the firm it is pointing
367 								Location *locPtr = world.get_loc(curXLoc, curYLoc);
368 								Firm *firmPtr;
369 								if( locPtr->is_firm() && (firmPtr = firm_array[locPtr->firm_recno()])
370 									&& unitPtr->can_set_stop(firmPtr->firm_recno) )
371 								{
372 									if( se_res.mark_command_time() )
373 									{
374 										se_res.far_sound( unitPtr->cur_x_loc(), unitPtr->cur_y_loc(), 1,
375 											'S', unitPtr->sprite_id, "ACK");
376 									}
377 									unitPtr->set_stop(command_para, curXLoc, curYLoc, COMMAND_PLAYER);		// command_para is the id. of the stop
378 								}
379 							}
380 							command_id = 0;
381 							rc = 1;
382 							break;
383 
384 						case COMMAND_BUILD_WALL:
385 							world.build_wall_tile(curXLoc, curYLoc, nation_array.player_recno, COMMAND_PLAYER);
386 							rc = 1;
387 							break;
388 
389 						case COMMAND_DESTRUCT_WALL:
390 							world.destruct_wall_tile(curXLoc, curYLoc, nation_array.player_recno, COMMAND_PLAYER);
391 							rc = 1;
392 							break;
393 
394 						case COMMAND_GOD_CAST_POWER:
395 							if(!unit_array.is_deleted(command_unit_recno) && unit_array[command_unit_recno]->is_visible())
396 							{
397 								Unit *cmdUnit = unit_array[command_unit_recno];
398 								if( se_res.mark_command_time() )
399 								{
400 									Unit *repUnit = unit_array[unit_array.selected_recno];
401 									se_res.far_sound( repUnit->cur_x_loc(), repUnit->cur_y_loc(), 1,
402 									'S', repUnit->sprite_id, "ACK");
403 								}
404 								// ###### begin Gilbert 14/10 ########//
405 								cmdUnit->go_cast_power(curXLoc, curYLoc, command_para, COMMAND_PLAYER);
406 								// ###### end Gilbert 14/10 ########//
407 							}
408 							command_id = 0;
409 							rc = 1;
410 							break;
411 
412 						default:
413 							if( !mouse_cursor.frame_flag )
414 							{
415 								mouse_cursor.set_frame(1, 0);
416 								mouse_cursor.process(mouseX, mouseY);
417 							}
418 							else
419 								mouse_cursor.set_frame(1, 0);
420 					}
421 				}
422 			}
423 
424 			if( mouseX >= MAP_X1 && mouseX <= MAP_X2 &&		// if the mouse is inside the zoom area
425 				 mouseY >= MAP_Y1 && mouseY <= MAP_Y2 )
426 			{
427 				mouse.set_boundary(MAP_X1, MAP_Y1, MAP_X2, MAP_Y2);
428 			}
429 
430 		}
431 
432 		//------- the selection action is complete --------//
433 		else if( mouse.mouse_event_type == LEFT_BUTTON_RELEASE)
434 		{
435 			int mouseX = mouse.click_x(LEFT_BUTTON);
436 			int mouseY = mouse.click_y(LEFT_BUTTON);
437 			int mouseReleaseX = mouse.release_x(LEFT_BUTTON);
438 			int mouseReleaseY = mouse.release_y(LEFT_BUTTON);
439 
440 			//-------- reset boundary of mouse -------//
441 			mouse.reset_boundary();
442 
443 			if( mouse_cursor.frame_flag )
444 			{
445 				mouse_cursor.process(mouseReleaseX, mouseReleaseY);
446 				mouse_cursor.set_frame(0);
447 				rc = detect_select( mouse_cursor.frame_x1, mouse_cursor.frame_y1,
448 										  mouse_cursor.frame_x2, mouse_cursor.frame_y2,
449 										  0, mouse.event_skey_state & SHIFT_KEY_MASK);
450 			}
451 		}
452 	}
453 	else
454 	{
455 		// no mouse event but keep pressing left button
456 		if( mouse.left_press )
457 		{
458 			if( mouse_cursor.frame_flag )
459 			{
460 				mouse_cursor.process(mouse.cur_x, mouse.cur_y);
461 			}
462 		}
463 		else
464 		{
465 			mouse_cursor.set_frame(0);
466 		}
467 	}
468 
469 	return rc;
470 }
471 //--------- End of function Power::detect_frame ---------//
472 
473 
474 //-------- Begin of function Power::detect_action --------//
475 //
476 // return: <int> 1 - action executed.
477 //					  0 - no action ordered.
478 //
detect_action()479 int Power::detect_action()
480 {
481 	if( !mouse.has_mouse_event || mouse.mouse_event_type != RIGHT_BUTTON || !nation_array.player_recno)
482 		return 0;
483 
484 	int curXLoc, curYLoc;
485 	// int shiftPressed = GetKeyState(VK_SHIFT) & 0X0100;		// return the current real-time key state
486 	int shiftPressed = mouse.event_skey_state & SHIFT_KEY_MASK;
487 	int mouseX = mouse.click_x(RIGHT_BUTTON);
488 	int mouseY = mouse.click_y(RIGHT_BUTTON);
489 
490 	//--------- if click on the zoom window --------//
491 
492 	if( mouseX >= ZOOM_X1 && mouseX <= ZOOM_X2 &&		// if the mouse is inside the zoom area
493 		 mouseY >= ZOOM_Y1 && mouseY <= ZOOM_Y2 )
494 	{
495 		curXLoc = world.zoom_matrix->top_x_loc + (mouseX-ZOOM_X1)/ZOOM_LOC_WIDTH;
496 		curYLoc = world.zoom_matrix->top_y_loc + (mouseY-ZOOM_Y1)/ZOOM_LOC_HEIGHT;
497 	}
498 
499 	//---------- if click on the map window -----------//
500 
501 	else if( mouseX >= MAP_X1 && mouseX <= MAP_X2 &&		// if the mouse is inside the zoom area
502 				mouseY >= MAP_Y1 && mouseY <= MAP_Y2 )
503 	{
504 		curXLoc = world.map_matrix->top_x_loc + (mouseX-MAP_X1);
505 		curYLoc = world.map_matrix->top_y_loc + (mouseY-MAP_Y1);
506 	}
507 
508 	else
509 	{
510 		return 0;
511 	}
512 
513 	//-------- find out how many units have been selected --------//
514 
515 	int		selectedCount=0;
516 	short*	selectedArray;
517 	Unit*	unitPtr;
518 	Unit*	activeUnit = NULL; // = unit_array[selectedArray[0]];
519 
520 	selectedArray = (short*) mem_add( sizeof(short) * unit_array.size() );
521 
522 	int i;
523 	for( i=unit_array.size() ; i>0 ; i-- )
524 	{
525 		if( unit_array.is_deleted(i) )
526 			continue;
527 
528 		unitPtr = unit_array[i];
529 
530 		if(unitPtr->hit_points<=0 || unitPtr->cur_action==SPRITE_DIE || unitPtr->action_mode==ACTION_DIE)
531 			continue;
532 
533 		if( !unitPtr->selected_flag || !unitPtr->is_visible() )
534 			continue;
535 
536 		if( !unitPtr->is_own() )				// only if the unit belongs to us (a spy is also okay if true_nation_recno is ours)
537 			continue;
538 
539 		if (i == unit_array.selected_recno)		// set the selected unit as the active one if present and it passed the above criteria
540 			activeUnit = unitPtr;
541 
542 		selectedArray[selectedCount++] = i;
543 	}
544 
545 	//### begin alex 16/10 ###//
546 	if((mouse.event_skey_state & ALT_KEY_MASK))
547 	{
548 		unit_array.add_way_point(curXLoc, curYLoc, selectedArray, selectedCount, COMMAND_PLAYER);
549 		mem_del(selectedArray);
550 		return 1;
551 	}
552 	//#### end alex 16/10 ####//
553 
554 	if( selectedCount==0 )		// no unit selected
555 	{
556 		mem_del(selectedArray);
557 		return 0;
558 	}
559 
560 	if ( ! activeUnit)			// default activeUnit to first unit when unit_array.selected_recno is 0 or could not be selected
561 		activeUnit = unit_array[selectedArray[0]];
562 
563 	//----- get the info of the clicked location ------//
564 
565 	Location* locPtr=test_detect(mouse.cur_x, mouse.cur_y);
566 	Unit		 *targetUnit=NULL, *targetShip=NULL, *targetAirUnit=NULL;
567 	Firm*		 targetFirm=NULL;
568 	Town*     targetTown=NULL;
569 	char	 	 targetWall=0;
570 	int		 mobileType = activeUnit->mobile_type;		// mobile type of the selected units
571 	int		 targetMobileType=0;
572 	short		 nationRecno = activeUnit->nation_recno;
573 	int		 retFlag = 0;
574 
575 	if( locPtr )
576 	{
577 		//targetMobileType = locPtr->has_any_unit(mobileType);
578 		targetMobileType = locPtr->has_any_unit();
579 		if(targetMobileType)
580 		{
581 			switch(targetMobileType)
582 			{
583 				case UNIT_LAND:
584 						targetUnit = unit_array[locPtr->unit_recno(targetMobileType)];
585 						err_when(!targetUnit->is_visible());
586 						break;
587 
588 				case UNIT_SEA:
589 						targetShip = unit_array[locPtr->unit_recno(targetMobileType)];
590 						err_when(!targetShip->is_visible());
591 						break;
592 
593 				case UNIT_AIR:
594 						targetAirUnit = unit_array[locPtr->unit_recno(targetMobileType)];
595 						err_when(!targetAirUnit->is_visible());
596 						break;
597 
598 				default: err_here();
599 							break;
600 			}
601 		}
602 		else if( locPtr->is_firm() )
603 			targetFirm = firm_array[locPtr->firm_recno()];
604 		else if( locPtr->is_town() )
605 			targetTown = town_array[locPtr->town_recno()];
606 		else if( locPtr->is_wall() )
607 			targetWall = 1;
608 	}
609 
610 	//--------------- divide by nation ---------------//
611 	static short nationUnitCount[MAX_NATION+1]; // plus one for independent nation
612 	short *nationUnitCountPtr = nationUnitCount;
613 	divide_by_nation(nationUnitCountPtr, selectedArray, selectedCount);
614 
615 	//------------- process action for each nation -------------//
616 	nationUnitCountPtr = nationUnitCount;
617 
618 	Nation	*nationPtr;
619 	short		*nationSelectedArray;
620 	short		nationSelectedCount;
621 	Unit	*preferredActiveUnit = activeUnit;
622 	int		isHuman;
623 
624 	for(int natCount=0, preNatCount=0; natCount<=MAX_NATION; natCount++, nationUnitCountPtr++)
625 	{
626 		if(!(*nationUnitCountPtr) || (*nationUnitCountPtr)==preNatCount)
627 			continue; // no unit in this nation
628 
629 		nationSelectedArray = selectedArray + preNatCount;
630 		nationSelectedCount = *nationUnitCountPtr - preNatCount;
631 		preNatCount = *nationUnitCountPtr;
632 		nationPtr = (nation_divide_order[natCount]) ? nation_array[nation_divide_order[natCount]] : NULL;
633 
634 		//---------- if the target is a unit -----------//
635 		if (preferredActiveUnit->nation_recno != nation_divide_order[natCount]) // only for spies, as detect_select disallows multiple-nation selections
636 			activeUnit = unit_array[select_active_unit(nationSelectedArray, nationSelectedCount)]; // update activeUnit for each nation
637 		else
638 			activeUnit = preferredActiveUnit;
639 		isHuman = unit_res[activeUnit->unit_id]->race_id > 0;		// whether the unit can be assigned to firms and towns
640 
641 		if(targetMobileType)
642 		{
643 			if(targetUnit && targetUnit->hit_points>0)
644 			{
645 				//--- embarking horse/elephants, when targetUnit->nation_recno==0, the unit is an animal ---//
646 				if( unit_res[activeUnit->unit_id]->vehicle_id == targetUnit->unit_id )
647 				{
648 					unit_array.assign(targetUnit->next_x_loc(), targetUnit->next_y_loc(), 0, COMMAND_PLAYER, nationSelectedArray, nationSelectedCount );
649 					retFlag = 1;
650 				}
651 				else if( !targetUnit->is_own() )
652 				{
653 					if( nationPtr && nationPtr->get_relation_should_attack(targetUnit->nation_recno)
654 						 && activeUnit->attack_count > 0 )			// Units like Phoenix that can't attack will call move_to() instead of calling attack()
655 					{
656 						if(nation_array.player_recno==nation_divide_order[natCount])
657 							unit_array.attack(targetUnit->next_x_loc(), targetUnit->next_y_loc(), 0, nationSelectedArray, nationSelectedCount, COMMAND_PLAYER, targetUnit->sprite_recno);
658 					}
659 					else
660 					{
661 						unit_array.move_to(curXLoc, curYLoc, 0, nationSelectedArray, nationSelectedCount, COMMAND_PLAYER);
662 					}
663 					retFlag = 1;
664 				}
665 				else if( targetUnit->is_own() && targetUnit->unit_id == UNIT_EXPLOSIVE_CART && shiftPressed)
666 				{
667 					if(nation_array.player_recno==nation_divide_order[natCount])
668 						unit_array.attack(targetUnit->next_x_loc(), targetUnit->next_y_loc(), 0, nationSelectedArray, nationSelectedCount, COMMAND_PLAYER, targetUnit->sprite_recno);
669 					retFlag = 1;
670 				}
671 				// else, right click on other land unit, it is team select
672 			}
673 			else if(targetShip && targetShip->hit_points>0)
674 			{
675 				if(targetShip->is_own() )
676 				{
677 					if(unit_res[targetShip->unit_id]->carry_unit_capacity>0)
678 					{
679 						// ##### patch begin Gilbert 5/8 #######//
680 						unit_array.assign_to_ship(targetShip->next_x_loc(), targetShip->next_y_loc(), 0, nationSelectedArray, nationSelectedCount, COMMAND_PLAYER, targetShip->sprite_recno );
681 						// ##### patch end Gilbert 5/8 #######//
682 					}
683 				}
684 				else
685 				{
686 					if( nationPtr && nationPtr->get_relation_should_attack(targetShip->nation_recno)
687 						 && activeUnit->attack_count > 0 )			// Units like Phoenix that can't attack will call move_to() instead of calling attack()
688 					{
689 						if(nation_array.player_recno==nation_divide_order[natCount])
690 							unit_array.attack(targetShip->next_x_loc(), targetShip->next_y_loc(), 0, nationSelectedArray, nationSelectedCount, COMMAND_PLAYER, targetShip->sprite_recno);
691 					}
692 					else
693 					{
694 						unit_array.move_to(curXLoc, curYLoc, 0, nationSelectedArray, nationSelectedCount, COMMAND_PLAYER);
695 					}
696 				}
697 				retFlag = 1;
698 			}
699 			else if(targetAirUnit && targetAirUnit->hit_points>0)
700 			{
701 				if( nationPtr && nationPtr->get_relation_should_attack(targetAirUnit->nation_recno)
702 					 && activeUnit->attack_count > 0 )			// Units like Phoenix that can't attack will call move_to() instead of calling attack()
703 				{
704 					if(nation_array.player_recno==nation_divide_order[natCount])
705 						unit_array.attack(targetAirUnit->next_x_loc(), targetAirUnit->next_y_loc(), 0, nationSelectedArray, nationSelectedCount, COMMAND_PLAYER, targetAirUnit->sprite_recno);
706 				}
707 				else
708 				{
709 					unit_array.move_to(curXLoc, curYLoc, 0, nationSelectedArray, nationSelectedCount, COMMAND_PLAYER);
710 				}
711 				retFlag = 1;
712 			}
713 		}
714 		else if(targetFirm && targetFirm->hit_points>0)
715 		{
716 			//-------- if this firm does not belong to the player -------//
717 			int assignedFlag=0;
718 
719 			if( ( ( nationPtr && nationPtr->get_relation_should_attack(targetFirm->nation_recno) )
720 				  || shiftPressed ) && activeUnit->attack_count > 0 )			// Units like Phoenix that can't attack will call move_to() instead of calling attack()
721 			{
722 				//------------ attack the firm -------------//
723 				if(nation_array.player_recno==nation_divide_order[natCount])
724 					unit_array.attack(targetFirm->loc_x1, targetFirm->loc_y1, 0, nationSelectedArray, nationSelectedCount, COMMAND_PLAYER, 0);
725 			}
726 			else
727 			{
728 				//------------ filtering for firm_can_assign() ---------------//
729 				int canAssign;
730 				if(targetFirm->firm_id==FIRM_BASE)
731 				{
732 					canAssign = 0;
733 					Unit *selectedUnit;
734 					for(int i=0; i<nationSelectedCount; i++)
735 					{
736 						selectedUnit = unit_array[nationSelectedArray[i]];
737 						// ####### begin Gilbert 22/10 #########//
738 						// if(selectedUnit->firm_can_assign(targetFirm->firm_recno))
739 						if( unit_can_assign_firm(nationSelectedArray[i], targetFirm->firm_recno, nation_array.player_recno) )
740 						// ####### end Gilbert 22/10 #########//
741 						{
742 							canAssign = 1;
743 							break;
744 						}
745 					}
746 				}
747 				else
748 					// ####### begin Gilbert 22/10 #########//
749 					// canAssign = activeUnit->firm_can_assign(targetFirm->firm_recno);
750 					canAssign = unit_can_assign_firm(activeUnit->sprite_recno, targetFirm->firm_recno, nation_array.player_recno);
751 					// ####### begin Gilbert 22/10 #########//
752 
753 				if( canAssign && (isHuman || targetFirm->firm_id==FIRM_CAMP) )
754 				{
755 					//### begin alex 19/3 ###//
756 					err_when(targetFirm->nation_recno != activeUnit->nation_recno);
757 					//#### end alex 19/3 ####//
758 					//----- if own firm, assign the unit to the firm ----//
759 					if(targetFirm->firm_id==FIRM_CAMP)
760 						unit_array.assign_to_camp(targetFirm->loc_x1, targetFirm->loc_y1, COMMAND_PLAYER, nationSelectedArray, nationSelectedCount);
761 					else
762 						unit_array.assign(targetFirm->loc_x1, targetFirm->loc_y1, 0, COMMAND_PLAYER, nationSelectedArray, nationSelectedCount);
763 				}
764 				//### begin alex 19/3 ###//
765 				//else if( activeUnit->mobile_type == UNIT_SEA && targetFirm->firm_id == FIRM_HARBOR )
766 				else if( canAssign && activeUnit->mobile_type == UNIT_SEA && targetFirm->firm_id == FIRM_HARBOR )
767 				{
768 					err_when(targetFirm->nation_recno != activeUnit->nation_recno);
769 				//#### end alex 19/3 ####//
770 					//----- if the selected are marine units -----//
771 					unit_array.assign(targetFirm->loc_x1, targetFirm->loc_y1, 0, COMMAND_PLAYER, nationSelectedArray, nationSelectedCount);
772 				}
773 				else
774 				{
775 					//------- if no other action executed, move to the clicked location ------//
776 					unit_array.move_to(curXLoc, curYLoc, 0, nationSelectedArray, nationSelectedCount, COMMAND_PLAYER);
777 				}
778 			}
779 
780 			retFlag = 1;
781 		}
782 		else if(targetTown)
783 		{
784 			if( activeUnit->spy_recno && activeUnit->nation_recno == targetTown->nation_recno )
785 			{
786 				//------ if the player is sending a spy into the town ------//
787 				unit_array.assign(targetTown->loc_x1, targetTown->loc_y1, 0, COMMAND_PLAYER, nationSelectedArray, nationSelectedCount);
788 			}
789 			else if( isHuman && targetTown->nation_recno == nation_array.player_recno )			// assign to the firm
790 			{
791 				//----- assign units into a town in a normal operation -----//
792 				//--- divide the array, non-skill peasant units are assigned to towns, skilled, soldiers and generals are not assigned to town, they just move close to the town ---//
793 
794 				short* moveArray   = (short*) mem_add( sizeof(short) * nationSelectedCount );
795 				short* assignArray = (short*) mem_add( sizeof(short) * nationSelectedCount );
796 				int	moveCount=0, assignCount=0;
797 
798 				for( i=0 ; i<nationSelectedCount ; i++ )
799 				{
800 					unitPtr = unit_array[nationSelectedArray[i]];
801 
802 					if(unitPtr->mobile_type==UNIT_LAND && unitPtr->rank_id==RANK_SOLDIER && unitPtr->skill.skill_id<=0
803 							&& !(unitPtr->spy_recno && unitPtr->nation_recno != targetTown->nation_recno))
804 						assignArray[assignCount++] = nationSelectedArray[i];
805 					else
806 						moveArray[moveCount++] = nationSelectedArray[i];
807 				}
808 
809 				if( moveCount > 0 )
810 					unit_array.move_to(targetTown->loc_x1, targetTown->loc_y1, 0, moveArray, moveCount, COMMAND_PLAYER);
811 
812 				if( assignCount > 0 )
813 				{
814 					//### begin alex 19/3 ###//
815 					err_when(targetTown->nation_recno != activeUnit->nation_recno);
816 					//#### end alex 19/3 ####//
817 					unit_array.assign(targetTown->loc_x1, targetTown->loc_y1, 0, COMMAND_PLAYER, assignArray, assignCount);
818 				}
819 
820 				mem_del(moveArray);
821 				mem_del(assignArray);
822 			}
823 			else if( nationPtr && nationPtr->get_relation_should_attack(targetTown->nation_recno)
824 						&& activeUnit->attack_count > 0 )			// Units like Phoenix that can't attack will call move_to() instead of calling attack()
825 			{
826 				//--------- attack the town ------------//
827 				if(nation_array.player_recno==nation_divide_order[natCount])
828 					unit_array.attack(targetTown->loc_x1, targetTown->loc_y1, 0, nationSelectedArray, nationSelectedCount, COMMAND_PLAYER, 0);
829 			}
830 			else
831 				unit_array.move_to(curXLoc, curYLoc, 0, nationSelectedArray, nationSelectedCount, COMMAND_PLAYER);
832 
833 			retFlag = 1;
834 		}
835 		else
836 		{
837 			//--------- if no target selected, just move to the clicked location --------//
838 
839 			//---- if double-click, force move ------//
840 
841 			if( mouse.click_count(RIGHT_BUTTON) > 1 )
842 			{
843 				if( !remote.is_enable() )
844 				{
845 					for( int j=0 ; j<nationSelectedCount ; j++ )
846 						unit_array[ nationSelectedArray[j] ]->force_move_flag = 1;
847 				}
848 				else
849 				{
850 					short *shortPtr = (short *)remote.new_send_queue_msg(MSG_UNIT_SET_FORCE_MOVE, sizeof(short)*(1+nationSelectedCount) );
851 					// packet structure : <unit count> <unit recno>...
852 					*shortPtr = nationSelectedCount;
853 					++shortPtr;
854 					for( int j=0 ; j<nationSelectedCount ; j++, shortPtr++ )
855 						*shortPtr = nationSelectedArray[j];
856 				}
857 			}
858 
859 			//--------- move to now -----------//
860 
861 			unit_array.move_to(curXLoc, curYLoc, 0, nationSelectedArray, nationSelectedCount, COMMAND_PLAYER);
862 			retFlag = 1;
863 		}
864 
865 		//-------- quit checking -------//
866 		if(preNatCount==selectedCount)
867 			break; // all selected Unit is processed
868 
869 		err_when(preNatCount > selectedCount);
870 	}
871 
872 	mem_del(selectedArray);
873 	return retFlag;
874 }
875 //--------- End of function Power::detect_action ---------//
876 
877 
878 //------ Begin of function Power::test_detect -------//
879 //
880 // Test detect if there is an object at where the mouse cursor
881 // is currently pointing at.
882 //
883 // return: <Location*> The pointer to the location with a sprite or firm
884 //							  being detected.
885 //					  		  NULL - no sprite detected.
886 // mobileType          UNIT_AIR or UNIT_LAND (don't return UNIT_SEA)
887 //
test_detect(int curX,int curY,char * mobileType)888 Location* Power::test_detect(int curX, int curY, char *mobileType)
889 {
890 	char dummy, tempMobileType;
891 	if( !mobileType )
892 		mobileType = &dummy;
893 
894 	//---- only proceed if the mouse cursor is inside the zoom map area ---//
895 
896 	if( curX < ZOOM_X1 || curX > ZOOM_X2 ||		// if the mouse is inside the zoom area
897 		 curY < ZOOM_Y1 || curY > ZOOM_Y2 )
898 	{
899 		return NULL;
900 	}
901 
902 	//------ if mouse cursor is pointing at a firm, return now ------//
903 
904 	int curXLoc = world.zoom_matrix->top_x_loc + (curX-ZOOM_X1)/ZOOM_LOC_WIDTH;
905 	int curYLoc = world.zoom_matrix->top_y_loc + (curY-ZOOM_Y1)/ZOOM_LOC_HEIGHT;
906 
907 	Location* locPtr = world.get_loc(curXLoc,curYLoc);
908 
909 	//---- expand the area outwards to cover sprites that are in their way moving into the area
910 
911 	int detectSpread = mouse.skey_state & CONTROL_KEY_MASK ? 0 : DETECT_SPREAD;
912 	int selXLoc1=MAX(0, curXLoc-detectSpread);   	// expand 2 tiles in case of big sprite
913 	int selYLoc1=MAX(0, curYLoc-detectSpread);
914 	int selXLoc2=MIN(MAX_WORLD_X_LOC-1, curXLoc+detectSpread);
915 	int selYLoc2=MIN(MAX_WORLD_Y_LOC-1, curYLoc+detectSpread);
916 
917 	//---------- select sprite --------------//
918 
919 	int 		xLoc, yLoc;
920 	Unit     *unitPtr;
921 	int		absCurX = curX-ZOOM_X1+World::view_top_x;		// the mouse cursor's absolute position on the whole world map
922 	int		absCurY = curY-ZOOM_Y1+World::view_top_y;
923 	Location* retLoc = NULL;
924 
925 	// first pass : scan air unit
926 	for( yLoc=selYLoc1 ; yLoc<=selYLoc2 ; yLoc++ )
927 	{
928 		locPtr = world.get_loc(selXLoc1, yLoc);
929 		for( xLoc=selXLoc1 ; xLoc<=selXLoc2 ; xLoc++, locPtr++ )
930 		{
931 			if( locPtr->has_unit(UNIT_AIR) && !unit_array.is_deleted(locPtr->air_cargo_recno) )	// if the mouse does not click directly on a sprite
932 			{
933 				unitPtr = unit_array[locPtr->air_cargo_recno];
934 				tempMobileType = UNIT_AIR;
935 				err_when(!unitPtr->is_visible());
936 				err_when( unitPtr->mobile_type != UNIT_AIR );
937 			}
938 			else
939 				unitPtr = NULL;
940 
941 			//----- there is a sprite in the location -----//
942 
943 			if( unitPtr && !unitPtr->is_shealth() )
944 			{
945 				unitPtr->update_abs_pos();
946 
947 				if( absCurX >= unitPtr->abs_x1 && absCurY >= unitPtr->abs_y1 &&
948 					 absCurX <= unitPtr->abs_x2 && absCurY <= unitPtr->abs_y2 )
949 				{
950 					retLoc = locPtr;
951 					*mobileType = tempMobileType;
952 				}
953 			}
954 		}
955 	}
956 
957 	if( retLoc )
958 		return retLoc;
959 
960 	// -------- second pass : scan land firm/town/wall --------//
961 
962 	locPtr = world.get_loc(curXLoc, curYLoc);
963 	if( locPtr->is_firm() || locPtr->is_town() || locPtr->is_wall() )
964 	{
965 		*mobileType = UNIT_LAND;
966 		return locPtr;
967 	}
968 
969 	//---------- third pass : scan land unit -------------//
970 
971 	for( yLoc=selYLoc1 ; yLoc<=selYLoc2 ; yLoc++ )
972 	{
973 		locPtr = world.get_loc(selXLoc1,yLoc);
974 		for( xLoc=selXLoc1 ; xLoc<=selXLoc2 ; xLoc++, locPtr++ )
975 		{
976 			if( (locPtr->has_unit(UNIT_LAND) || locPtr->has_unit(UNIT_SEA))
977 				&& !unit_array.is_deleted(locPtr->cargo_recno) )  	// if the mouse does not click directly on a sprite
978 			{
979 				unitPtr = unit_array[locPtr->cargo_recno];
980 				tempMobileType = UNIT_LAND;
981 				err_when(!unitPtr->is_visible());
982 			}
983 			else
984 				unitPtr = NULL;
985 
986 			//----- there is a sprite in the location -----//
987 
988 			if( unitPtr && !unitPtr->is_shealth() )
989 			{
990 				unitPtr->update_abs_pos();
991 
992 				if( absCurX >= unitPtr->abs_x1 && absCurY >= unitPtr->abs_y1 &&
993 					 absCurX <= unitPtr->abs_x2 && absCurY <= unitPtr->abs_y2 )
994 				{
995 					retLoc = locPtr;
996 					*mobileType = tempMobileType;
997 				}
998 			}
999 		}
1000 	}
1001 
1002 	return retLoc;
1003 }
1004 //------ End of function Power::test_detect -------//
1005 
1006 
1007 //------ Begin of function Power::detect_select -------//
1008 //
1009 // This function is called when the mouse has been clicked,
1010 // this function will select the objects inside the mouse selection area,
1011 // and deselect previously selected objects.
1012 //
1013 // <int> selX1, selY1, selX2, selY2 - the positions of the selection box
1014 //
1015 // <int> recallGroup - recall selection of the defined group to which the
1016 //							  selected unit belongs, such as all units that are patrolling
1017 //							  from the same Fort.
1018 //
1019 // <int> shiftSelect - add/remove individual selected unit
1020 //
1021 // return : <int> >0 - no. of units or firms selected
1022 //						0 	- no unit or firm detected in the rectd area.
1023 //
detect_select(int selX1,int selY1,int selX2,int selY2,int recallGroup,int shiftSelect)1024 int Power::detect_select(int selX1, int selY1, int selX2, int selY2, int recallGroup, int shiftSelect)
1025 {
1026 	int topXLoc = world.zoom_matrix->top_x_loc;
1027 	int topYLoc = world.zoom_matrix->top_y_loc;
1028 
1029 	int selXLoc1 = topXLoc + (selX1-ZOOM_X1)/ZOOM_LOC_WIDTH;
1030 	int selYLoc1 = topYLoc + (selY1-ZOOM_Y1)/ZOOM_LOC_HEIGHT;
1031 	int selXLoc2 = topXLoc + (selX2-ZOOM_X1)/ZOOM_LOC_WIDTH;
1032 	int selYLoc2 = topYLoc + (selY2-ZOOM_Y1)/ZOOM_LOC_HEIGHT;
1033 
1034 	int firstXLoc = selXLoc1, firstYLoc = selYLoc1;		// first location to be tested
1035 
1036 	//-- expand the area outwards to cover sprites that are in their way moving into the area
1037 
1038 	selXLoc1=MAX(0, selXLoc1-DETECT_SPREAD);		// expand 2 tiles in case of big sprite
1039 	selYLoc1=MAX(0, selYLoc1-DETECT_SPREAD);
1040 	selXLoc2=MIN(MAX_WORLD_X_LOC-1,selXLoc2+DETECT_SPREAD);
1041 	selYLoc2=MIN(MAX_WORLD_Y_LOC-1,selYLoc2+DETECT_SPREAD);
1042 
1043 	//------ calc absolute positions for fast comparsion ---//
1044 
1045 	int absSelX1 = selX1-ZOOM_X1+World::view_top_x;		// the mouse cursor's absolute position on the whole world map
1046 	int absSelY1 = selY1-ZOOM_Y1+World::view_top_y;
1047 	int absSelX2 = selX2-ZOOM_X1+World::view_top_x;
1048 	int absSelY2 = selY2-ZOOM_Y1+World::view_top_y;
1049 
1050 	// int shiftSelect = GetKeyState(VK_SHIFT) & 0X0100;		// return the current real-time key state
1051 
1052 	int selectOneOnly = abs(selX1-selX2)<=3 && abs(selY1-selY2)<=3;
1053 
1054 	//---------- select sprite --------------//
1055 
1056 	int		selectedCount=0;	// whether any sprite has been selected.
1057 	int 		xLoc, yLoc;
1058 	Location *locPtr;
1059 	Unit		*unitPtr;
1060 	int		i;
1061 	int		selectedSiteRecno=0; //, selectedUnitRecno=0;
1062 	int		selectedWallXLoc= -1, selectedWallYLoc= -1;
1063 	int		selectedFirmRecno=0;
1064 	int		selectedTownRecno=0;
1065 	int		firstTest=0;
1066 	char		selectSound = 0;
1067 
1068 	if( selectOneOnly )
1069 	{
1070 		char pMobileType;
1071 		locPtr = test_detect( selX2, selY2, &pMobileType );
1072 
1073 		if( locPtr )
1074 		{
1075 			if( pMobileType == UNIT_AIR && locPtr->has_unit(pMobileType) &&
1076 				!unit_array.is_deleted(locPtr->air_cargo_recno) &&
1077 				!(unitPtr = unit_array[locPtr->air_cargo_recno])->is_shealth() )
1078 			{
1079 				err_when( unitPtr->mobile_type != UNIT_AIR );
1080 			}
1081 			else if( pMobileType == UNIT_LAND &&
1082 				(locPtr->has_unit(UNIT_LAND) || locPtr->has_unit(UNIT_SEA)) &&
1083 				!unit_array.is_deleted(locPtr->cargo_recno) &&
1084 				!(unitPtr = unit_array[locPtr->cargo_recno])->is_shealth() )
1085 			{
1086 				err_when( unitPtr->mobile_type != UNIT_LAND && unitPtr->mobile_type != UNIT_SEA);
1087 			}
1088 			else if( pMobileType == UNIT_LAND && !recallGroup &&
1089 				locPtr->is_firm() && !firm_array.is_deleted(locPtr->cargo_recno) )
1090 			{
1091 				selectedFirmRecno=locPtr->firm_recno();
1092 				selectedCount++;
1093 				unitPtr = NULL;
1094 			}
1095 			else if( pMobileType == UNIT_LAND && !recallGroup &&
1096 				locPtr->is_town() && !town_array.is_deleted(locPtr->cargo_recno) )
1097 			{
1098 				selectedTownRecno=locPtr->town_recno();
1099 				selectedCount++;
1100 				unitPtr = NULL;
1101 			}
1102 			else
1103 				unitPtr = NULL;
1104 
1105 			if( unitPtr &&
1106 				(!recallGroup || unitPtr->is_own()) ) // skip recallGroup selecting enemy unit, it is attack!
1107 			{
1108 				if( !unitPtr->is_own() )
1109 				{
1110 					err_when( recallGroup );		// press right button on enemy unit is attack, not select
1111 					shiftSelect = 0;
1112 				}
1113 				// when we have a non-own unit selected and are shift-clicking our own unit, clear selected units
1114 				else if ( shiftSelect && unit_array.selected_recno && !unit_array[unit_array.selected_recno]->is_own() )
1115 				{
1116 					shiftSelect = 0;
1117 				}
1118 
1119 				if( recallGroup && unitPtr->team_id )
1120 				{
1121 					uint32_t teamId = unitPtr->team_id;
1122 					char newSelectedFlag = shiftSelect ? (unitPtr->selected_flag ? 0 : 1) : 2;
1123 					for( i=unit_array.size() ; i>0 ; i-- )
1124 					{
1125 						if( unit_array.is_deleted(i) )
1126 							continue;
1127 						Unit *memberUnit = unit_array[i];
1128 
1129 						//---- set Unit::team_id to define the group ----//
1130 
1131 						if( memberUnit->team_id == teamId )
1132 						{
1133 							memberUnit->selected_flag = newSelectedFlag; // a team member is selected is depending on the clicked unit
1134 							selectedCount++;
1135 						}
1136 					}
1137 				}
1138 				else
1139 				{
1140 					char newSelectedFlag = shiftSelect ? (unitPtr->selected_flag ? 0 : 1) : 2;
1141 					unitPtr->selected_flag = newSelectedFlag;
1142 					selectedCount++;
1143 				}
1144 
1145 				if( unitPtr->selected_flag && unitPtr->is_own() && nation_array.player_recno)
1146 				{
1147 					if( se_res.mark_select_object_time() )
1148 					{
1149 						se_res.sound( unitPtr->cur_x_loc(), unitPtr->cur_y_loc(), 1,
1150 							'S', unitPtr->sprite_id, "SEL");
1151 					}
1152 					selectSound = 1;
1153 				}
1154 				// goto label_post_select;
1155 			}
1156 		}
1157 	}
1158 	else
1159 	{
1160 		const unsigned int mobileTypeCount = 3;
1161 		static char mobileTypeList[mobileTypeCount] = { UNIT_AIR, UNIT_LAND, UNIT_SEA };
1162 
1163 		// pass 1 - find if selecting own nation or spy cloaked nation
1164 		short nationSelect = nation_array.player_recno;
1165 		if( shiftSelect && unit_array.selected_recno )
1166 		{
1167 			if( !unit_array.is_deleted(unit_array.selected_recno) )
1168 				nationSelect = unit_array[unit_array.selected_recno]->nation_recno;
1169 			// so if you want to select spy of the same nation from
1170 			// from a crowd of your spy,
1171 			// select any one spy of that nation, shift select the crowd
1172 		}
1173 		else
1174 		{
1175 			unsigned short selectNationCount[MAX_NATION+1];	// count nation of selectable unit
1176 			memset( selectNationCount, 0, sizeof(selectNationCount) );
1177 
1178 			for( yLoc=selYLoc1 ; yLoc<=selYLoc2 ; yLoc++ )
1179 			{
1180 				for( xLoc=selXLoc1 ; xLoc<=selXLoc2 ; xLoc++ )
1181 				{
1182 					locPtr = world.get_loc(xLoc, yLoc);
1183 
1184 					for( int mt = 0; mt < sizeof(mobileTypeList)/sizeof(char); ++mt )
1185 					{
1186 						char mobileType = mobileTypeList[mt];
1187 						if( locPtr->has_unit(mobileType) && !unit_array.is_deleted(locPtr->unit_recno(mobileType))
1188 							&& !(unitPtr = unit_array[locPtr->unit_recno(mobileType)])->is_shealth() )
1189 						{
1190 							if(!unitPtr->is_visible() || unitPtr->hit_points<=0  || unitPtr->is_shealth() ||
1191 								!unitPtr->is_own() )
1192 								continue; // skip this unit
1193 
1194 							unitPtr->update_abs_pos();
1195 
1196 							if( misc.is_touch( absSelX1, absSelY1, absSelX2, absSelY2,
1197 								 unitPtr->abs_x1, unitPtr->abs_y1,
1198 								 unitPtr->abs_x2, unitPtr->abs_y2 ) )
1199 							{
1200 								selectNationCount[unitPtr->nation_recno]++;
1201 							}
1202 						}
1203 					}
1204 				}
1205 			}
1206 
1207 			if( selectNationCount[nation_array.player_recno] == 0 )	// prefer own nation
1208 			{
1209 				nationSelect = -1;		// all nation
1210 			}
1211 		}
1212 
1213 		// recallGroup is ignored
1214 		char newSelectedFlag = shiftSelect ? 1 : 2;		// press shift to include more units
1215 
1216 		for( yLoc=selYLoc1 ; yLoc<=selYLoc2 ; yLoc++ )
1217 		{
1218 			for( xLoc=selXLoc1 ; xLoc<=selXLoc2 ; xLoc++ )
1219 			{
1220 				locPtr = world.get_loc(xLoc, yLoc);
1221 
1222 				for( int mt = 0; mt < sizeof(mobileTypeList)/sizeof(char); ++mt )
1223 				{
1224 					char mobileType = mobileTypeList[mt];
1225 					if( locPtr->has_unit(mobileType) && !unit_array.is_deleted(locPtr->unit_recno(mobileType))
1226 						&& !(unitPtr = unit_array[locPtr->unit_recno(mobileType)])->is_shealth() )
1227 					{
1228 						if(!unitPtr->is_visible() || unitPtr->hit_points<=0  || unitPtr->is_shealth() ||
1229 							!unitPtr->is_own() )
1230 							continue; // skip this unit
1231 
1232 						if( nationSelect != -1 && unitPtr->nation_recno != nationSelect )
1233 							continue;	// skip this unit
1234 
1235 						unitPtr->update_abs_pos();
1236 
1237 						if( misc.is_touch( absSelX1, absSelY1, absSelX2, absSelY2,
1238 							 unitPtr->abs_x1, unitPtr->abs_y1,
1239 							 unitPtr->abs_x2, unitPtr->abs_y2 ) )
1240 						{
1241 							selectedCount++;
1242 							//selectedUnitRecno = unitPtr->sprite_recno;
1243 							//--------- set selected_flag ----------//
1244 
1245 							unitPtr->selected_flag = newSelectedFlag;		// set to 2 as all sprites will be processed below
1246 
1247 							//---- recall selection of the defined group to which the selected unit belongs ----//
1248 						}
1249 					}
1250 				}
1251 			}
1252 		}
1253 	}
1254 
1255 	//-------- detect raw material sites ---------//
1256 
1257 	if( selectedCount==0 && selectOneOnly && !recallGroup )
1258 	{
1259 		int selXLoc = topXLoc + (selX1-ZOOM_X1)/ZOOM_LOC_WIDTH;
1260 		int selYLoc = topYLoc + (selY1-ZOOM_Y1)/ZOOM_LOC_HEIGHT;
1261 
1262 		Location* locPtr = world.get_loc(selXLoc, selYLoc);
1263 
1264 		if( locPtr->has_site() && !locPtr->is_firm() )
1265 		{
1266 			selectedCount++;
1267 			selectedSiteRecno = locPtr->site_recno();
1268 		}
1269 	}
1270 
1271 	//---------- detect city wall ----------//
1272 
1273 	if( selectedCount==0 && selectOneOnly && !recallGroup )
1274 	{
1275 		int selXLoc = topXLoc + (selX1-ZOOM_X1)/ZOOM_LOC_WIDTH;
1276 		int selYLoc = topYLoc + (selY1-ZOOM_Y1)/ZOOM_LOC_HEIGHT;
1277 
1278 		Location* locPtr = world.get_loc(selXLoc, selYLoc);
1279 
1280 		if( locPtr->is_wall() )
1281 		{
1282 			selectedCount++;
1283 			selectedWallXLoc = selXLoc;
1284 			selectedWallYLoc = selYLoc;
1285 		}
1286 	}
1287 
1288 	//------ if any objects have been just selected ------//
1289 
1290 // label_post_select:
1291 
1292 	if( selectedCount )		// reset previously selected flag
1293 	{
1294 		//--- if shift select, don't change the selected flag, but if town or firm is selected, reset all unit selection ---//
1295 
1296 		if( selectedFirmRecno || selectedTownRecno || selectedSiteRecno  || selectedWallXLoc >= 0 || !shiftSelect )
1297 		{
1298 			for( i=unit_array.size() ; i>0 ; i-- )
1299 			{
1300 				if( unit_array.is_deleted(i) )
1301 					continue;
1302 
1303 				unitPtr = unit_array[i];
1304 
1305 				if( unitPtr->selected_flag )
1306 				{
1307 					//---- for group selection (selecting more than 1 unit), only select the player's own units ----//
1308 
1309 					if( selectedCount>1 && !unitPtr->is_own() )
1310 						unitPtr->selected_flag = 0;
1311 					else
1312 						unitPtr->selected_flag--;
1313 					// for newly selected sprite, selected_flag will be changed from 2 to 1
1314 					// for formerly selected sprite, selected_flag will be change from 1 to 0
1315 				}
1316 			}
1317 		}
1318 
1319 		//--------- count the no. of selected units --------//
1320 		//
1321 		// we need to count it instead of using selectedCount as
1322 		// selectedCount only tells the no. of units selected
1323 		// this time, not including previous selected ones for shift selection.
1324 		//
1325 		//--------------------------------------------------//
1326 
1327 		unit_array.selected_count=0;	// reset it now, we will count it below
1328 		int highRankUnitRecno = 0;
1329 
1330 		//--- unit_array.selected_recno should be the unit with the highest rank ---//
1331 		for( i=unit_array.size() ; i>0 ; i-- )
1332 		{
1333 			if( !unit_array.is_deleted(i) && unit_array[i]->selected_flag )
1334 			{
1335 				unit_array.selected_count++;
1336 				if( !highRankUnitRecno || is_unit_higher_rank(i, highRankUnitRecno) )
1337 					highRankUnitRecno = i;
1338 			}
1339 		}
1340 
1341 		unit_array.selected_recno=highRankUnitRecno;		// note no unit may be selected, like pressing shift to de-select unit
1342 		// so selectedCount may not be true
1343 
1344 		if( unit_array.selected_recno && !selectSound &&
1345 			 unit_array[unit_array.selected_recno]->is_own() )
1346 		{
1347 			if( se_res.mark_select_object_time() )
1348 			{
1349 				Unit *headUnit = unit_array[unit_array.selected_recno];
1350 				se_res.sound( headUnit->cur_x_loc(), headUnit->cur_y_loc(), 1, 'S',
1351 					headUnit->sprite_id, "SEL");
1352 			}
1353 			selectSound = 1;
1354 		}
1355 
1356 		if( selectedFirmRecno && !selectSound &&
1357 			firm_array[selectedFirmRecno]->own_firm() )
1358 		{
1359 			if( se_res.mark_select_object_time() )
1360 			{
1361 				Firm *firmPtr = firm_array[selectedFirmRecno];
1362 				se_res.sound(firmPtr->center_x, firmPtr->center_y, 1,
1363 					'F', firmPtr->firm_id, firmPtr->under_construction ? (char*)"SELU" : (char*)"SEL" );
1364 			}
1365 			selectSound = 1;
1366 		}
1367 
1368 		if( selectedTownRecno && !selectSound &&
1369 			town_array[selectedTownRecno]->nation_recno == nation_array.player_recno )
1370 		{
1371 			if( se_res.mark_select_object_time() )
1372 			{
1373 				Town *townPtr = town_array[selectedTownRecno];
1374 				se_res.sound(townPtr->center_x, townPtr->center_y, 1,
1375 					'T', 0, "SEL" );
1376 			}
1377 			selectSound = 1;
1378 		}
1379 
1380 		//--- only set selected_recno for single unit selected, don't do so for nation selection
1381 
1382 		firm_array.selected_recno = selectedFirmRecno;
1383 		town_array.selected_recno = selectedTownRecno;
1384 		site_array.selected_recno = selectedSiteRecno;
1385 		wall_res.selected_x_loc   = selectedWallXLoc;
1386 		wall_res.selected_y_loc   = selectedWallYLoc;
1387 
1388 		reset_command();		// reset current command when a new unit is selected
1389 
1390 		//--- update worker display for selected firm ---//
1391 
1392 		if( selectedFirmRecno )
1393 			firm_array[selectedFirmRecno]->sort_worker();
1394 
1395 		//--- group them automatically if a group of units are selected ---//
1396 
1397 //		if( unit_array.selected_count > 1 )
1398 //			unit_array[unit_array.selected_recno]->define_team();
1399 
1400 		//----- refresh info display of the selected object -----//
1401 
1402 		info.disp();
1403 	}
1404 
1405 	//-----------------------------------------//
1406 
1407 	return selectedCount;
1408 }
1409 //------ End of function Power::detect_select -------//
1410 
1411 
1412 //--------- Begin of function Power::issue_command ---------//
1413 //
1414 // <int> commandId  		  - the id. of the command
1415 // [int] commandUnitRecno - the id. of the unit that issues the command
1416 // [int] commandPara  	  - an extra parameter of the command
1417 //
issue_command(int commandId,int commandUnitRecno,int commandPara)1418 void Power::issue_command(int commandId, int commandUnitRecno, int commandPara)
1419 {
1420 	command_id    		 = commandId;
1421 	command_unit_recno = commandUnitRecno;
1422 	command_para       = commandPara;
1423 }
1424 //----------- End of function Power::issue_command -----------//
1425 
1426 
1427 //--------- Begin of function Power::reset_selection ---------//
1428 //
1429 // Reset selection.
1430 //
reset_selection()1431 void Power::reset_selection()
1432 {
1433 	int i;
1434 
1435 	//----- reset unit selection -------//
1436 
1437 	for(i=1; i <=unit_array.size() ; i++)
1438 	{
1439 		if( unit_array.is_deleted(i) )
1440 			continue;
1441 
1442 		unit_array[i]->selected_flag = 0;
1443 	}
1444 
1445 	unit_array.selected_recno = 0;
1446 	unit_array.selected_count = 0;
1447 
1448 	//---- reset other selection --------//
1449 
1450 	firm_array.selected_recno = 0;
1451 	town_array.selected_recno = 0;
1452 	site_array.selected_recno = 0;
1453 
1454 	wall_res.selected_x_loc = -1;
1455 	wall_res.selected_y_loc = -1;
1456 
1457 	reset_command();		// reset current command when a new unit is selected
1458 }
1459 //----------- End of function Power::reset_selection -----------//
1460 
1461 
1462 //--------- Begin of function Power::get_link_icon ---------//
1463 //
1464 // <char> linkStatus - link status
1465 // <int>  sameNation - whether the two firms are of the same nation
1466 //							  (default: 0)
1467 //
1468 // return: <char*> the bitmap pointer of the link icon
1469 //
get_link_icon(char linkStatus,int sameNation)1470 char* Power::get_link_icon(char linkStatus, int sameNation)
1471 {
1472 	char  goodLinkName[9] = "LINK_EE1";
1473 	goodLinkName[7] = '1'+ (char) (sys.frame_count/2%3);
1474 
1475 	switch( linkStatus )
1476 	{
1477 		case LINK_EE:
1478 			return image_icon.get_ptr(goodLinkName);
1479 
1480 		case LINK_ED:
1481 			return image_icon.get_ptr("LINK_ED");
1482 
1483 		case LINK_DE:
1484 			return image_icon.get_ptr("LINK_DE");
1485 
1486 		case LINK_DD:
1487 			if( sameNation )
1488 				return image_icon.get_ptr("LINK_DE");	// green cross for same nation firms
1489 			else
1490 				return image_icon.get_ptr("LINK_DD");	// red cross for different nation firms
1491 	}
1492 
1493 	err_here();
1494 
1495 	return NULL;
1496 }
1497 //----------- End of function Power::get_link_icon -----------//
1498 
1499 
1500 // ---------- Begin of function Power::choose_cursor --------//
1501 //
choose_cursor(int scrnX,int scrnY,ScreenObjectType selectedObjectType,short selectedObjectRecno,ScreenObjectType pointingObjectType,short pointingObjectRecno)1502 int Power::choose_cursor(int scrnX, int scrnY,
1503 		ScreenObjectType selectedObjectType, short selectedObjectRecno,
1504 		ScreenObjectType pointingObjectType, short pointingObjectRecno)
1505 {
1506 	int selectedObjectId = 0;
1507 	int pointingObjectId = 0;
1508 
1509 	if(command_id)
1510 	{
1511 		if( scrnX >= ZOOM_X1 && scrnX <= ZOOM_X2 &&
1512 			scrnY >= ZOOM_Y1 && scrnY <= ZOOM_Y2)
1513 		{
1514 			switch(command_id)
1515 			{
1516 			case COMMAND_BUILD_FIRM:
1517 				return CURSOR_BUILD;
1518 			case COMMAND_ASSIGN:
1519 				return CURSOR_ASSIGN;
1520 			case COMMAND_BURN:
1521 				return CURSOR_BURN;
1522 			case COMMAND_SETTLE:
1523 				{
1524 					char flagColor = 0;                     // CURSOR_SETTLE + 0 is a valid cursor
1525 					Unit *activeUnit;
1526 					if( nation_array.player_recno
1527 						&& !nation_array.is_deleted(nation_array.player_recno) )
1528 						flagColor = (~nation_array)->color_scheme_id;
1529 					if( command_unit_recno && !unit_array.is_deleted(command_unit_recno)
1530 						&& (activeUnit = unit_array[command_unit_recno]) )
1531 					{
1532 						if( !activeUnit->nation_recno )
1533 							flagColor = 0;                  // independent nation
1534 						else if( !nation_array.is_deleted(activeUnit->nation_recno) )
1535 							flagColor = nation_array[activeUnit->nation_recno]->color_scheme_id;
1536 					}
1537 					return CURSOR_SETTLE + flagColor;
1538 				}
1539 			case COMMAND_SET_CARAVAN_STOP:
1540 				if(
1541 						(
1542 							pointingObjectType == SCREEN_OBJECT_FRIEND_FIRM
1543 						||
1544 							pointingObjectType == SCREEN_OBJECT_ENEMY_FIRM
1545 						)
1546 					&&
1547 						!nation_array.is_deleted(firm_array[pointingObjectRecno]->nation_recno)
1548 					&&
1549 						((UnitCaravan *)unit_array[selectedObjectRecno])->can_set_stop(pointingObjectRecno)
1550 					)
1551 					return CURSOR_SET_STOP;
1552 				return CURSOR_CANT_SET_STOP;
1553 			case COMMAND_SET_SHIP_STOP:
1554 				if(
1555 						(
1556 							pointingObjectType == SCREEN_OBJECT_FRIEND_FIRM
1557 						||
1558 							pointingObjectType == SCREEN_OBJECT_ENEMY_FIRM
1559 						)
1560 					&&
1561 						!nation_array.is_deleted(firm_array[pointingObjectRecno]->nation_recno)
1562 					&&
1563 						((UnitMarine *)unit_array[selectedObjectRecno])->can_set_stop(pointingObjectRecno)
1564 					)
1565 					return CURSOR_SHIP_STOP;
1566 				return CURSOR_CANT_SHIP_STOP;
1567 			case COMMAND_BUILD_WALL:
1568 				return CURSOR_BUILD;
1569 			case COMMAND_DESTRUCT_WALL:
1570 				return CURSOR_DESTRUCT;
1571 			case COMMAND_GOD_CAST_POWER:
1572 				return CURSOR_NORMAL;
1573 			default:
1574 				err_here();
1575 				return CURSOR_NORMAL;
1576 			}
1577 		}
1578 		else
1579 		{
1580 			return CURSOR_NORMAL;
1581 		}
1582 	}
1583 	else
1584 	{
1585 		// power.command_id == 0
1586 		// ------- check cursor inside zoom window -------//
1587 		if( scrnX >= ZOOM_X1 && scrnX <= ZOOM_X2 &&
1588 			scrnY >= ZOOM_Y1 && scrnY <= ZOOM_Y2)
1589 		{
1590 			// ------ inside zoom window, depend on selected and pointing object
1591 			switch(selectedObjectType)
1592 			{
1593 			case SCREEN_OBJECT_NONE:
1594 			case SCREEN_OBJECT_WALL:
1595 			case SCREEN_OBJECT_SITE:
1596 			case SCREEN_OBJECT_ENEMY_UNIT:
1597 				{
1598 					switch( pointingObjectType)
1599 					{
1600 					case SCREEN_OBJECT_NONE:
1601 					case SCREEN_OBJECT_WALL:
1602 					case SCREEN_OBJECT_SITE:
1603 						return CURSOR_NORMAL;
1604 					case SCREEN_OBJECT_FRIEND_UNIT:
1605 					case SCREEN_OBJECT_UNIT_GROUP:
1606 					case SCREEN_OBJECT_FRIEND_TOWN:
1607 					case SCREEN_OBJECT_FRIEND_FIRM:
1608 						return CURSOR_NORMAL_C;
1609 					case SCREEN_OBJECT_ENEMY_UNIT:
1610 					case SCREEN_OBJECT_ENEMY_TOWN:
1611 					case SCREEN_OBJECT_ENEMY_FIRM:
1612 						return CURSOR_NORMAL_O;
1613 					default:
1614 						err_here();
1615 						return CURSOR_NORMAL;
1616 					}
1617 				}
1618 			case SCREEN_OBJECT_SPY_UNIT:
1619 				{
1620 					Unit *unitPtr = unit_array[selectedObjectRecno];
1621 					short nationRecno = unitPtr->nation_recno;
1622 					selectedObjectId = unitPtr->unit_id;
1623 
1624 					switch( pointingObjectType )
1625 					{
1626 					case SCREEN_OBJECT_NONE:
1627 					case SCREEN_OBJECT_WALL:
1628 					case SCREEN_OBJECT_SITE:
1629 						return CURSOR_NORMAL;
1630 
1631 					case SCREEN_OBJECT_FRIEND_UNIT:
1632 					case SCREEN_OBJECT_ENEMY_UNIT:
1633 						{
1634 							Unit *pUnit = unit_array[pointingObjectRecno];
1635 							if( nationRecno == pUnit->nation_recno )
1636 							{
1637 								// same nation
1638 								return choose_cursor_units(selectedObjectRecno, pointingObjectRecno);
1639 							}
1640 							else
1641 							{
1642 								return CURSOR_UNIT_O;
1643 							}
1644 						}
1645 					case SCREEN_OBJECT_FRIEND_TOWN:
1646 					case SCREEN_OBJECT_ENEMY_TOWN:
1647 						{
1648 							Town *pTown = town_array[pointingObjectRecno];
1649 						// determine friend / enemy again
1650 							if( nationRecno == pTown->nation_recno )
1651 							{
1652 								if( unit_res[selectedObjectId]->race_id && unitPtr->rank_id == RANK_SOLDIER )
1653 									return CURSOR_ASSIGN;
1654 								else
1655 									return CURSOR_UNIT_C;
1656 							}
1657 							else
1658 							{
1659 								return CURSOR_UNIT_O;
1660 							}
1661 						}
1662 
1663 					case SCREEN_OBJECT_FRIEND_FIRM:
1664 					case SCREEN_OBJECT_ENEMY_FIRM:
1665 						{
1666 							Firm *pFirm = firm_array[pointingObjectRecno];
1667 							// ##### begin Gilbert 22/10 #########//
1668 							//if( unitPtr->firm_can_assign(pointingObjectRecno) )
1669 							if( unit_can_assign_firm(selectedObjectRecno, pointingObjectRecno, nation_array.player_recno) )
1670 							// ##### end Gilbert 22/10 #########//
1671 								return CURSOR_ASSIGN;
1672 							else
1673 							{
1674 								if( nationRecno == pFirm->nation_recno )
1675 									return CURSOR_UNIT_C;
1676 								else
1677 									return CURSOR_UNIT_O;
1678 							}
1679 						}
1680 					default:
1681 						err_here();
1682 						return CURSOR_NORMAL;
1683 					}
1684 				}
1685 			case SCREEN_OBJECT_FRIEND_UNIT:
1686 				{
1687 					Unit *unitPtr = unit_array[selectedObjectRecno];
1688 					selectedObjectId = unitPtr->unit_id;
1689 					char rankId = unitPtr->rank_id;
1690 
1691 					switch( pointingObjectType)
1692 					{
1693 					case SCREEN_OBJECT_NONE:
1694 					case SCREEN_OBJECT_SITE:
1695 						return CURSOR_UNIT;
1696 					case SCREEN_OBJECT_FRIEND_UNIT:
1697 						return choose_cursor_units(selectedObjectRecno, pointingObjectRecno);
1698 					case SCREEN_OBJECT_UNIT_GROUP:
1699 						err_here();		// impossible to pointing at more than one unit
1700 						return CURSOR_UNIT_C;
1701 					case SCREEN_OBJECT_FRIEND_TOWN:
1702 						// ##### begin Gilbert 18/10 ######//
1703 						if( unitPtr->race_id && rankId == RANK_SOLDIER && !unitPtr->skill.skill_id)
1704 						// ##### end Gilbert 18/10 ######//
1705 							return CURSOR_ASSIGN;
1706 						else
1707 							return CURSOR_UNIT_C;
1708 					case SCREEN_OBJECT_FRIEND_FIRM:
1709 						{
1710 							Firm *firmPtr = firm_array[pointingObjectRecno];
1711 							pointingObjectId = firmPtr->firm_id;
1712 							// ###### begin Gilbert 22/10 #######//
1713 							// if( unitPtr->firm_can_assign(pointingObjectRecno) )
1714 							if( unit_can_assign_firm(selectedObjectRecno, pointingObjectRecno, nation_array.player_recno) )
1715 							// ###### end Gilbert 22/10 #######//
1716 								return CURSOR_ASSIGN;
1717 							return CURSOR_UNIT_C;
1718 						}
1719 					case SCREEN_OBJECT_ENEMY_UNIT:
1720 					case SCREEN_OBJECT_ENEMY_TOWN:
1721 					case SCREEN_OBJECT_ENEMY_FIRM:
1722 						return CURSOR_UNIT_O;
1723 					case SCREEN_OBJECT_WALL:
1724 						return CURSOR_DESTRUCT;
1725 					default:
1726 						err_here();
1727 						return CURSOR_UNIT;
1728 					}
1729 				}
1730 			case SCREEN_OBJECT_UNIT_GROUP:
1731 				{
1732 					int arraySize = unit_array.size();
1733 					int i;
1734 
1735 					switch( pointingObjectType)
1736 					{
1737 					case SCREEN_OBJECT_NONE:
1738 					case SCREEN_OBJECT_SITE:
1739 						return CURSOR_UNIT;
1740 					case SCREEN_OBJECT_FRIEND_UNIT:
1741 						return choose_cursor_unit_group(pointingObjectRecno);
1742 					case SCREEN_OBJECT_UNIT_GROUP:
1743 						err_here();		// impossible to pointing at more than one unit
1744 						return CURSOR_UNIT_C;
1745 					case SCREEN_OBJECT_FRIEND_TOWN:
1746 						for( i = 1; i < arraySize; ++i)
1747 						{
1748 							Unit *unitPtr;
1749 							if( unit_array.is_deleted(i) || !(unitPtr = unit_array[i])->selected_flag )
1750 								continue;
1751 							// ###### begin Gilbert 18/10 ########//
1752 							if( unitPtr->race_id && unitPtr->rank_id == RANK_SOLDIER
1753 								&& !unitPtr->skill.skill_id )
1754 							// ###### end Gilbert 18/10 ########//
1755 								return CURSOR_ASSIGN;
1756 						}
1757 						return CURSOR_UNIT_C;
1758 					case SCREEN_OBJECT_FRIEND_FIRM:
1759 						{
1760 							Firm *firmPtr = firm_array[pointingObjectRecno];
1761 							pointingObjectId = firmPtr->firm_id;
1762 							for( i = 1; i < arraySize; ++i)
1763 							{
1764 								Unit *unitPtr;
1765 								if( unit_array.is_deleted(i) || !(unitPtr = unit_array[i])->selected_flag )
1766 									continue;
1767 								// ##### begin Gilbert 22/10 #######//
1768 								// if( unitPtr->firm_can_assign(pointingObjectRecno) )
1769 								if( unit_can_assign_firm(i, pointingObjectRecno, nation_array.player_recno) )
1770 									return CURSOR_ASSIGN;
1771 								// ##### end Gilbert 22/10 #######//
1772 							}
1773 							return CURSOR_UNIT_C;
1774 						}
1775 					case SCREEN_OBJECT_ENEMY_UNIT:
1776 					case SCREEN_OBJECT_ENEMY_TOWN:
1777 					case SCREEN_OBJECT_ENEMY_FIRM:
1778 						return CURSOR_UNIT_O;
1779 					case SCREEN_OBJECT_WALL:
1780 						return CURSOR_DESTRUCT;
1781 					default:
1782 						err_here();
1783 						return CURSOR_UNIT;
1784 					}
1785 				}
1786 			case SCREEN_OBJECT_FRIEND_TOWN:
1787 				{
1788 					Town *townPtr = town_array[selectedObjectRecno];
1789 
1790 					switch( pointingObjectType)
1791 					{
1792 					case SCREEN_OBJECT_NONE:
1793 					case SCREEN_OBJECT_WALL:
1794 					case SCREEN_OBJECT_SITE:
1795 						return CURSOR_C_TOWN;
1796 					case SCREEN_OBJECT_FRIEND_UNIT:
1797 					case SCREEN_OBJECT_UNIT_GROUP:
1798 						return CURSOR_C_TOWN_C;
1799 					case SCREEN_OBJECT_FRIEND_FIRM:
1800 						{
1801 							Firm *pFirm = firm_array[pointingObjectRecno];
1802 							int centerX = (pFirm->loc_x1 + pFirm->loc_x2 +1)*ZOOM_LOC_WIDTH/2 - World::view_top_x;
1803 							int centerY = (pFirm->loc_y1 + pFirm->loc_y2 +1)*ZOOM_LOC_HEIGHT/2 - World::view_top_y;
1804 							if(misc.points_distance( mouse.cur_x, mouse.cur_y, centerX+ZOOM_X1, centerY+ZOOM_Y1) <= 11
1805 								&& townPtr->can_toggle_firm_link(pointingObjectRecno) )
1806 							{
1807 								return CURSOR_ON_LINK;
1808 							}
1809 						}
1810 						return CURSOR_C_TOWN_C;
1811 					case SCREEN_OBJECT_FRIEND_TOWN:
1812 						if( selectedObjectRecno != pointingObjectRecno )
1813 						{
1814 							// check if the cursor is pointing at the middle of the town
1815 							Town *pTown = town_array[pointingObjectRecno];
1816 							int centerX = (pTown->loc_x1 + pTown->loc_x2 +1)*ZOOM_LOC_WIDTH/2 - World::view_top_x;
1817 							int centerY = (pTown->loc_y1 + pTown->loc_y2 +1)*ZOOM_LOC_HEIGHT/2 - World::view_top_y;
1818 							if(misc.points_distance( mouse.cur_x, mouse.cur_y, centerX+ZOOM_X1, centerY+ZOOM_Y1) <= 11
1819 								&& townPtr->can_migrate(pointingObjectRecno) )
1820 							{
1821 								return CURSOR_ON_LINK;
1822 							}
1823 						}
1824 						return CURSOR_C_TOWN_C;
1825 					case SCREEN_OBJECT_ENEMY_UNIT:
1826 					case SCREEN_OBJECT_ENEMY_TOWN:
1827 						return CURSOR_C_TOWN_O;
1828 					case SCREEN_OBJECT_ENEMY_FIRM:
1829 						{
1830 							Firm *pFirm = firm_array[pointingObjectRecno];
1831 							int centerX = (pFirm->loc_x1 + pFirm->loc_x2 +1)*ZOOM_LOC_WIDTH/2 - World::view_top_x;
1832 							int centerY = (pFirm->loc_y1 + pFirm->loc_y2 +1)*ZOOM_LOC_HEIGHT/2 - World::view_top_y;
1833 							if(misc.points_distance( mouse.cur_x, mouse.cur_y, centerX+ZOOM_X1, centerY+ZOOM_Y1) <= 11
1834 								&& townPtr->can_toggle_firm_link(pointingObjectRecno) )
1835 							{
1836 								return CURSOR_ON_LINK;
1837 							}
1838 						}
1839 						return CURSOR_C_TOWN_O;
1840 					default:
1841 						err_here();
1842 						return CURSOR_C_TOWN;
1843 					}
1844 				}
1845 			case SCREEN_OBJECT_ENEMY_TOWN:
1846 				{
1847 					Town *townPtr = town_array[selectedObjectRecno];
1848 					switch( pointingObjectType)
1849 					{
1850 					case SCREEN_OBJECT_NONE:
1851 					case SCREEN_OBJECT_WALL:
1852 					case SCREEN_OBJECT_SITE:
1853 						return CURSOR_O_TOWN;
1854 					case SCREEN_OBJECT_FRIEND_UNIT:
1855 					case SCREEN_OBJECT_UNIT_GROUP:
1856 					case SCREEN_OBJECT_FRIEND_TOWN:
1857 						return CURSOR_O_TOWN_C;
1858 					case SCREEN_OBJECT_FRIEND_FIRM:
1859 						return CURSOR_O_TOWN_C;
1860 					case SCREEN_OBJECT_ENEMY_UNIT:
1861 					case SCREEN_OBJECT_ENEMY_TOWN:
1862 					case SCREEN_OBJECT_ENEMY_FIRM:
1863 						return CURSOR_O_TOWN_O;
1864 					default:
1865 						err_here();
1866 						return CURSOR_O_TOWN;
1867 					}
1868 				}
1869 			case SCREEN_OBJECT_FRIEND_FIRM:
1870 				{
1871 					Firm *firmPtr = firm_array[selectedObjectRecno];
1872 					switch( pointingObjectType)
1873 					{
1874 					case SCREEN_OBJECT_NONE:
1875 					case SCREEN_OBJECT_WALL:
1876 					case SCREEN_OBJECT_SITE:
1877 						return CURSOR_C_FIRM;
1878 					case SCREEN_OBJECT_FRIEND_UNIT:
1879 					case SCREEN_OBJECT_UNIT_GROUP:
1880 						return CURSOR_C_FIRM_C;
1881 					case SCREEN_OBJECT_FRIEND_TOWN:
1882 						{
1883 							Town *pTown = town_array[pointingObjectRecno];
1884 							int centerX = (pTown->loc_x1 + pTown->loc_x2 +1)*ZOOM_LOC_WIDTH/2 - World::view_top_x;
1885 							int centerY = (pTown->loc_y1 + pTown->loc_y2 +1)*ZOOM_LOC_HEIGHT/2 - World::view_top_y;
1886 							if(misc.points_distance( mouse.cur_x, mouse.cur_y, centerX+ZOOM_X1, centerY+ZOOM_Y1) <= 11
1887 								&& firmPtr->can_toggle_town_link() )
1888 							{
1889 								return CURSOR_ON_LINK;
1890 							}
1891 						}
1892 						return CURSOR_C_FIRM_C;
1893 					case SCREEN_OBJECT_FRIEND_FIRM:
1894 						if( selectedObjectRecno != pointingObjectRecno )
1895 						{
1896 							Firm *pFirm = firm_array[pointingObjectRecno];
1897 							int centerX = (pFirm->loc_x1 + pFirm->loc_x2 +1)*ZOOM_LOC_WIDTH/2 - World::view_top_x;
1898 							int centerY = (pFirm->loc_y1 + pFirm->loc_y2 +1)*ZOOM_LOC_HEIGHT/2 - World::view_top_y;
1899 							if(misc.points_distance( mouse.cur_x, mouse.cur_y, centerX+ZOOM_X1, centerY+ZOOM_Y1) <= 11
1900 								&& firmPtr->can_toggle_firm_link(pointingObjectRecno) )
1901 							{
1902 								return CURSOR_ON_LINK;
1903 							}
1904 						}
1905 						return CURSOR_C_FIRM_C;
1906 					case SCREEN_OBJECT_ENEMY_UNIT:
1907 						return CURSOR_C_FIRM_O;
1908 					case SCREEN_OBJECT_ENEMY_TOWN:
1909 						{
1910 							Town *pTown = town_array[pointingObjectRecno];
1911 							int centerX = (pTown->loc_x1 + pTown->loc_x2 +1)*ZOOM_LOC_WIDTH/2 - World::view_top_x;
1912 							int centerY = (pTown->loc_y1 + pTown->loc_y2 +1)*ZOOM_LOC_HEIGHT/2 - World::view_top_y;
1913 							if(misc.points_distance( mouse.cur_x, mouse.cur_y, centerX+ZOOM_X1, centerY+ZOOM_Y1) <= 11
1914 								&& firmPtr->can_toggle_town_link() )
1915 							{
1916 								return CURSOR_ON_LINK;
1917 							}
1918 						}
1919 						return CURSOR_C_FIRM_O;
1920 					case SCREEN_OBJECT_ENEMY_FIRM:
1921 						{
1922 							Firm *pFirm = firm_array[pointingObjectRecno];
1923 							int centerX = (pFirm->loc_x1 + pFirm->loc_x2 +1)*ZOOM_LOC_WIDTH/2 - World::view_top_x;
1924 							int centerY = (pFirm->loc_y1 + pFirm->loc_y2 +1)*ZOOM_LOC_HEIGHT/2 - World::view_top_y;
1925 							if(misc.points_distance( mouse.cur_x, mouse.cur_y, centerX+ZOOM_X1, centerY+ZOOM_Y1) <= 11
1926 								&& firmPtr->can_toggle_firm_link(pointingObjectRecno) )
1927 							{
1928 								return CURSOR_ON_LINK;
1929 							}
1930 						}
1931 						return CURSOR_C_FIRM_O;
1932 					default:
1933 						err_here();
1934 						return CURSOR_C_FIRM;
1935 					}
1936 				}
1937 			case SCREEN_OBJECT_ENEMY_FIRM:
1938 				{
1939 					switch( pointingObjectType)
1940 					{
1941 					case SCREEN_OBJECT_NONE:
1942 					case SCREEN_OBJECT_WALL:
1943 					case SCREEN_OBJECT_SITE:
1944 						return CURSOR_O_FIRM;
1945 					case SCREEN_OBJECT_FRIEND_UNIT:
1946 					case SCREEN_OBJECT_UNIT_GROUP:
1947 					case SCREEN_OBJECT_FRIEND_FIRM:
1948 						return CURSOR_O_FIRM_C;
1949 					case SCREEN_OBJECT_FRIEND_TOWN:
1950 						return CURSOR_O_FIRM_C;
1951 					case SCREEN_OBJECT_ENEMY_UNIT:
1952 					case SCREEN_OBJECT_ENEMY_TOWN:
1953 					case SCREEN_OBJECT_ENEMY_FIRM:
1954 						return CURSOR_O_FIRM_O;
1955 					default:
1956 						err_here();
1957 						return CURSOR_O_TOWN;
1958 					}
1959 				}
1960 			default:
1961 				err_here();
1962 				return CURSOR_NORMAL;
1963 			}
1964 		}
1965 		else
1966 		{
1967 			// ------ outside zoom area depend on selected object ------//
1968 			switch(selectedObjectType)
1969 			{
1970 			case SCREEN_OBJECT_NONE:
1971 			case SCREEN_OBJECT_WALL:
1972 			case SCREEN_OBJECT_SITE:
1973 			case SCREEN_OBJECT_ENEMY_UNIT:
1974 				return CURSOR_NORMAL;
1975 
1976 			case SCREEN_OBJECT_FRIEND_UNIT:
1977 			case SCREEN_OBJECT_UNIT_GROUP:
1978 			case SCREEN_OBJECT_SPY_UNIT:
1979 				return CURSOR_UNIT;
1980 
1981 			case SCREEN_OBJECT_FRIEND_TOWN:
1982 				return CURSOR_C_TOWN;
1983 
1984 			case SCREEN_OBJECT_ENEMY_TOWN:
1985 				return CURSOR_O_TOWN;
1986 
1987 			case SCREEN_OBJECT_FRIEND_FIRM:
1988 				return CURSOR_C_FIRM;
1989 
1990 			case SCREEN_OBJECT_ENEMY_FIRM:
1991 				return CURSOR_O_FIRM;
1992 
1993 			default:
1994 				err_here();
1995 				return CURSOR_NORMAL;
1996 			}
1997 		}
1998 	}
1999 }
2000 // ---------- End of function Power::choose_cursor --------//
2001 
2002 
2003 // ---------- Begin of function Power::choose_cursor_units --------//
2004 //
choose_cursor_units(short selectedUnitRecno,short pointingUnitRecno)2005 int Power::choose_cursor_units(short selectedUnitRecno, short pointingUnitRecno)
2006 {
2007 	Unit *u1Ptr = unit_array[selectedUnitRecno];
2008 	Unit *u2Ptr = unit_array[pointingUnitRecno];
2009 	int selectedUnitId = u1Ptr->unit_id;
2010 	int pointingUnitId = u2Ptr->unit_id;
2011 	UnitInfo *u1 = unit_res[selectedUnitId];
2012 	UnitInfo *u2 = unit_res[pointingUnitId];
2013 	if(u1 && u2)
2014 	{
2015 		// ------- detect ship that can carry land unit -------//
2016 		if( u1->mobile_type == UNIT_LAND &&
2017 			u2 && u2->carry_unit_capacity > 0)
2018 		{
2019 			return CURSOR_ASSIGN;
2020 		}
2021 		else if( pointingUnitId == UNIT_EXPLOSIVE_CART &&		// check trigger explosive cart
2022 			u1Ptr->max_attack_range() > 1)
2023 		{
2024 			return CURSOR_TRIGGER_EXPLODE;
2025 		}
2026 		else if( u1->vehicle_id == pointingUnitId &&		// can ride on
2027 			u1->solider_id != 0)		// make sure u1 is a rider, not a riding unit
2028 		{
2029 			return CURSOR_ASSIGN;
2030 		}
2031 	}
2032 
2033 	return CURSOR_UNIT_C;
2034 }
2035 // ---------- End of function Power::choose_cursor_units --------//
2036 
2037 
2038 // ---------- Begin of function Power::choose_cursor_unit_group --------//
2039 //
choose_cursor_unit_group(short pointingUnitRecno)2040 int Power::choose_cursor_unit_group(short pointingUnitRecno)
2041 {
2042 	int pointingUnitId = unit_array[pointingUnitRecno]->unit_id;
2043 
2044 	// ----- assume all selected unit are owned by the player ----//
2045 	UnitInfo *u2 = unit_res[pointingUnitId];
2046 	if(u2)
2047 	{
2048 		// ------- detect ship that can carry land unit -------//
2049 		if( u2->carry_unit_capacity > 0)
2050 		{
2051 			// if any land unit in the selected array
2052 			int s = unit_array.size();
2053 			for(int i=1; i <= s; ++i)
2054 			{
2055 				if( !unit_array.is_deleted(i) && unit_array[i]->selected_flag)
2056 				{
2057 					UnitInfo *u1 = unit_res[unit_array[i]->unit_id];
2058 					if( u1->mobile_type == UNIT_LAND)
2059 						return CURSOR_ASSIGN;
2060 				}
2061 			}
2062 		}
2063 		else if( pointingUnitId == UNIT_EXPLOSIVE_CART )
2064 		{
2065 			// if any land unit in the selected array
2066 			int s = unit_array.size();
2067 			for(int i=1; i <= s; ++i)
2068 			{
2069 				Unit *unitPtr;
2070 				if( !unit_array.is_deleted(i) && (unitPtr = unit_array[i])->selected_flag)
2071 				{
2072 					if( unitPtr->max_attack_range() > 1)
2073 						return CURSOR_TRIGGER_EXPLODE;
2074 				}
2075 			}
2076 		}
2077 		else
2078 		{
2079 			// see if pointing unit is vehicle of any of the selected unit
2080 			int s = unit_array.size();
2081 			for(int i=1; i <= s; ++i)
2082 			{
2083 				if( !unit_array.is_deleted(i) && unit_array[i]->selected_flag)
2084 				{
2085 					UnitInfo *u1 = unit_res[unit_array[i]->unit_id];
2086 					if( u1->vehicle_id == pointingUnitId)
2087 						return CURSOR_ASSIGN;
2088 				}
2089 			}
2090 
2091 			//------- check other relationship here -------//
2092 		}
2093 	}
2094 
2095 	return CURSOR_UNIT_C;
2096 }
2097 // ---------- End of function Power::choose_cursor_unit_group --------//
2098 
2099 
2100 // ---------- Begin of function Power::find_selected_type --------//
2101 //
find_selected_type(short * selectedRecno)2102 ScreenObjectType Power::find_selected_type( short *selectedRecno)
2103 {
2104 	short dummyId;
2105 	if( selectedRecno == NULL)
2106 		selectedRecno = &dummyId;
2107 
2108 	if( unit_array.selected_recno )
2109 	{
2110 		// -------- check selected single unit ---------//
2111 
2112 		if( unit_array.selected_count == 1)
2113 		{
2114 			Unit *unitPtr = unit_array[*selectedRecno = unit_array.selected_recno];
2115 			return unitPtr->nation_recno == nation_array.player_recno ?
2116 				SCREEN_OBJECT_FRIEND_UNIT :
2117 				(unitPtr->true_nation_recno() == nation_array.player_recno ?
2118 				SCREEN_OBJECT_SPY_UNIT : SCREEN_OBJECT_ENEMY_UNIT);
2119 		}
2120 
2121 		// -------- check selected a group of units ---------//
2122 
2123 		if( unit_array.selected_count > 1)
2124 		{
2125 			*selectedRecno = unit_array.selected_recno;
2126 			return SCREEN_OBJECT_UNIT_GROUP;
2127 		}
2128 	}
2129 
2130 	// -------- check selected a firm ---------//
2131 
2132 	if( firm_array.selected_recno )
2133 	{
2134 		Firm *firmPtr = firm_array[*selectedRecno = firm_array.selected_recno];
2135 		return firmPtr->nation_recno == nation_array.player_recno ?
2136 			SCREEN_OBJECT_FRIEND_FIRM : SCREEN_OBJECT_ENEMY_FIRM;
2137 	}
2138 
2139 	// -------- check selected a town ---------//
2140 
2141 	if( town_array.selected_recno )
2142 	{
2143 		Town *townPtr = town_array[*selectedRecno = town_array.selected_recno];
2144 		return townPtr->nation_recno == nation_array.player_recno ?
2145 			SCREEN_OBJECT_FRIEND_TOWN : SCREEN_OBJECT_ENEMY_TOWN;
2146 	}
2147 
2148 	// -------- check selected a site ---------//
2149 
2150 	if( site_array.selected_recno )
2151 	{
2152 		Site *sitePtr = site_array[*selectedRecno = site_array.selected_recno];
2153 		return SCREEN_OBJECT_SITE;
2154 	}
2155 
2156 	// -------- check selected a wall ---------//
2157 
2158 	if( wall_res.selected_x_loc >= 0 && wall_res.selected_y_loc >= 0)
2159 	{
2160 		*selectedRecno = world.get_loc(wall_res.selected_x_loc, wall_res.selected_y_loc)->power_nation_recno;
2161 		return SCREEN_OBJECT_WALL;
2162 	}
2163 
2164 	return SCREEN_OBJECT_NONE;
2165 }
2166 // ---------- End of function Power::find_selected_type --------//
2167 
2168 
2169 // ---------- Begin of function Power::find_pointing_type --------//
2170 //
find_pointing_type(Location * locPtr,short * pointingRecno)2171 ScreenObjectType Power::find_pointing_type( Location *locPtr, short *pointingRecno)
2172 {
2173 	short dummyId;
2174 	if( pointingRecno == NULL)
2175 		pointingRecno = &dummyId;
2176 
2177 	// ------- check pointing at unit, always check air unit first -------//
2178 
2179 	if( locPtr->has_unit( UNIT_AIR ) )
2180 	{
2181 		Unit *unitPtr = unit_array[*pointingRecno = locPtr->unit_recno(UNIT_AIR)];
2182 		return unitPtr->nation_recno == nation_array.player_recno ?
2183 			SCREEN_OBJECT_FRIEND_UNIT : SCREEN_OBJECT_ENEMY_UNIT;
2184 	}
2185 
2186 	if( locPtr->has_unit( UNIT_LAND ) )
2187 	{
2188 		Unit *unitPtr = unit_array[*pointingRecno = locPtr->unit_recno(UNIT_LAND)];
2189 		return unitPtr->nation_recno == nation_array.player_recno ?
2190 			SCREEN_OBJECT_FRIEND_UNIT : SCREEN_OBJECT_ENEMY_UNIT;
2191 	}
2192 
2193 	if( locPtr->has_unit( UNIT_SEA ) )
2194 	{
2195 		Unit *unitPtr = unit_array[*pointingRecno = locPtr->unit_recno(UNIT_SEA)];
2196 		return unitPtr->nation_recno == nation_array.player_recno ?
2197 			SCREEN_OBJECT_FRIEND_UNIT : SCREEN_OBJECT_ENEMY_UNIT;
2198 	}
2199 
2200 	// -------- check pointing at firm ---------//
2201 
2202 	if( locPtr->is_firm() )
2203 	{
2204 		Firm *firmPtr = firm_array[*pointingRecno = locPtr->firm_recno()];
2205 		return firmPtr->nation_recno == nation_array.player_recno ?
2206 			SCREEN_OBJECT_FRIEND_FIRM : SCREEN_OBJECT_ENEMY_FIRM;
2207 	}
2208 
2209 	// ------- check pointing at town ---------//
2210 
2211 	if( locPtr->is_town() )
2212 	{
2213 		Town *townPtr = town_array[*pointingRecno = locPtr->town_recno()];
2214 		return townPtr->nation_recno == nation_array.player_recno ?
2215 			SCREEN_OBJECT_FRIEND_TOWN : SCREEN_OBJECT_ENEMY_TOWN;
2216 	}
2217 
2218 	// -------- check pointing a site ---------//
2219 
2220 	if( locPtr->has_site() )
2221 	{
2222 		Site *sitePtr = site_array[*pointingRecno = locPtr->site_recno()];
2223 		return SCREEN_OBJECT_SITE;
2224 	}
2225 
2226 	// -------- check pointing a wall ---------//
2227 
2228 	if( locPtr->is_wall() )
2229 	{
2230 		*pointingRecno = locPtr->power_nation_recno;
2231 		return SCREEN_OBJECT_WALL;
2232 	}
2233 
2234 	return SCREEN_OBJECT_NONE;
2235 }
2236 // ---------- End of function Power::find_pointing_type --------//
2237 
2238 
2239 // ###### begin Gilbert 22/10 #######//
2240 // ---------- Begin of function Power::unit_can_assign_firm --------//
unit_can_assign_firm(int unitRecno,int firmRecno,int ownNationRecno)2241 int Power::unit_can_assign_firm(int unitRecno, int firmRecno, int ownNationRecno)
2242 {
2243 	if(!ownNationRecno || !unitRecno || !firmRecno )
2244 		return 0;
2245 
2246 	if( unit_array.is_deleted(unitRecno) )
2247 		return 0;
2248 	Unit *unitPtr = unit_array[unitRecno];
2249 
2250 	if( firm_array.is_deleted(firmRecno) )
2251 		return 0;
2252 
2253 	Firm *firmPtr = firm_array[firmRecno];
2254 
2255 	int rc = unitPtr->firm_can_assign(firmRecno);
2256 
2257 	if( !rc )
2258 		return 0;
2259 
2260 	//----------------------------------------//
2261 	// If this is a spy, then he can only be
2262 	// assigned to an enemy firm when there is
2263 	// space for the unit.
2264 	//----------------------------------------//
2265 
2266 	if( ownNationRecno != firmPtr->nation_recno )
2267 	{
2268 		switch(rc)
2269 		{
2270 		case 1:				// assign as worker
2271 			if( firmPtr->worker_count == MAX_WORKER )
2272 				return 0;
2273 			break;
2274 		case 2:				// assign as overseer
2275 			if( firmPtr->overseer_recno )
2276 				return 0;
2277 			break;
2278 		case 3:				// assign as construction unit
2279 			if( firmPtr->builder_recno )
2280 				return 0;
2281 			break;
2282 		}
2283 	}
2284 
2285 	return rc;
2286 }
2287 // ---------- End of function Power::unit_can_assign_firm --------//
2288 // ###### end Gilbert 22/10 #######//
2289 
2290 //### begin alex 19/3 ###//
2291 //---------- Begin of function Power::select_active_unit --------//
2292 // choose the most suitable unit to be the active unit
2293 //
2294 // For this version and the situation, unit with ability to attack is
2295 // used instead of selecting the first unit in the array
2296 //
2297 // The full version should consider: 1) whether the unit is human,
2298 // 2) can attack, 3) mobile type, etc.  Or divide the unit once more
2299 // before calling functions in unit_array
2300 //
select_active_unit(short * selectedArray,short selectedCount)2301 short Power::select_active_unit(short *selectedArray, short selectedCount)
2302 {
2303 	Unit *unitPtr;
2304 
2305 	for(short i=0; i<selectedCount; ++i)
2306 	{
2307 		err_when(unit_array.is_deleted(selectedArray[i]));
2308 		unitPtr = unit_array[selectedArray[i]];
2309 
2310 		if(unitPtr->can_attack())
2311 			return selectedArray[i];
2312 	}
2313 
2314 	//------ return the first one if none of them can attack --------//
2315 	return selectedArray[0];
2316 }
2317 //---------- End of function Power::select_active_unit --------//
2318 //#### end alex 19/3 ####//
2319