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