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 : OTOWNIF.CPP
22 //Description : Town interface routines
23
24 #include <OINFO.h>
25 #include <OBOX.h>
26 #include <OVGA.h>
27 #include <vga_util.h>
28 #include <OSYS.h>
29 #include <OHELP.h>
30 #include <OSPY.h>
31 #include <OSTR.h>
32 #include <OFONT.h>
33 #include <OMOUSE.h>
34 #include <OVBROWIF.h>
35 #include <OGAME.h>
36 #include <ONATION.h>
37 #include <OBUTT3D.h>
38 #include <OIMGRES.h>
39 #include <ORAWRES.h>
40 #include <ORACERES.h>
41 #include <OWORLD.h>
42 #include <OUNIT.h>
43 #include <OTOWN.h>
44 #include <OREMOTE.h>
45 #include <OSE.h>
46 #include <OSERES.h>
47 #include <OBUTTCUS.h>
48 #include "gettext.h"
49
50
51 //------------- Define coordinations -----------//
52
53 enum { RACE_BROWSE_X1 = INFO_X1,
54 RACE_BROWSE_Y1 = INFO_Y1+48,
55 RACE_BROWSE_X2 = INFO_X2,
56 RACE_BROWSE_Y2 = RACE_BROWSE_Y1+130,
57 };
58
59 enum { BUTTON_X1 = INFO_X1,
60 BUTTON_Y1 = RACE_BROWSE_Y2+28,
61 BUTTON_X2 = INFO_X2,
62 BUTTON_Y2 = BUTTON_Y1+50,
63 };
64
65 //---------- Define constant ------------//
66
67 enum { TOWN_MENU_MAIN,
68 TOWN_MENU_TRAIN,
69 TOWN_MENU_SPY,
70 TOWN_MENU_VIEW_SECRET,
71 TOWN_MENU_SET_AUTO_COLLECT_TAX,
72 TOWN_MENU_SET_AUTO_GRANT,
73 };
74
75 #define BUTTON_LOYALTY_COUNT 8
76 #define COUNT_BUTTON_OFFSET_X 165
77 #define COUNT_BUTTON_OFFSET_Y 5
78 #define COUNT_BUTTON_WIDTH 32
79 #define COUNT_BUTTON_HEIGHT 32
80
81 //----------- Define static variables ----------//
82
83 static VBrowseIF browse_race, browse_spy;
84 static Button3D button_recruit, button_train, button_tax, button_grant;
85 static Button3D button_spy, button_cancel, button_spy_mobilize,
86 button_spy_reward, button_spy_action, button_spy_view_secret;
87 static Button3D button_cancel_training;
88 static ButtonCustom button_cancel3;
89 static Button button_loyalty_array[BUTTON_LOYALTY_COUNT];
90 static Button button_loyalty_disabled;
91 static Button button_cancel2;
92 static ButtonCustom button_skill[MAX_TRAINABLE_SKILL];
93 static ButtonCustom button_queue_skill[MAX_TRAINABLE_SKILL];
94 static int queue_train_selected;
95 static short browse_race_recno=1, browse_race_town_recno=0; // the town which the browse_race displays its info
96 static short recruit_race_count;
97 static short spy_count;
98 static short last_town_recno=0, last_rebel_recno=0;
99 static char last_has_linked_own_camp;
100 static char town_menu_mode=TOWN_MENU_MAIN;
101 static char disable_refresh=0;
102 static short action_spy_recno; // recno of the spy that is doing the bribing or viewing secret reports of other nations
103
104 //-------- Define static class member var ------//
105
106 short Town::if_town_recno = 0;
107
108 //----------- Define static functions ----------//
109
110 static int race_filter(int recNo=0);
111 static int spy_filter(int recNo=0);
112 static void put_race_rec(int recNo, int x, int y, int refreshFlag);
113 static void put_spy_rec(int recNo, int x, int y, int refreshFlag);
114 // ###### begin Gilbert 12/9 ########//
115 static void i_disp_skill_button(ButtonCustom *button, int);
116 static void i_disp_queue_skill_button(ButtonCustom *button, int);
117 // ###### end Gilbert 12/9 ########//
118
119
120 //--------- Begin of function Town::disp_info ---------//
121 //
disp_info(int refreshFlag)122 void Town::disp_info(int refreshFlag)
123 {
124 if_town_recno = town_recno;
125
126 if( town_recno != last_town_recno ||
127 (refreshFlag==INFO_REPAINT && !disable_refresh) )
128 {
129 if( town_recno != last_town_recno )
130 browse_race_recno = 1;
131
132 town_menu_mode = TOWN_MENU_MAIN;
133 last_town_recno = town_recno;
134 }
135
136 //-----------------------------------------//
137
138 int needRepaint=0;
139
140 if( last_rebel_recno != rebel_recno )
141 {
142 last_rebel_recno = rebel_recno;
143 needRepaint = 1;
144 }
145
146 if( last_has_linked_own_camp != has_linked_own_camp )
147 {
148 last_has_linked_own_camp = has_linked_own_camp;
149 needRepaint = 1;
150 }
151
152 if( needRepaint && refreshFlag == INFO_UPDATE )
153 {
154 info.disp();
155 return;
156 }
157
158 //-----------------------------------//
159
160 switch( town_menu_mode )
161 {
162 case TOWN_MENU_MAIN:
163 disp_main_menu(refreshFlag);
164 break;
165
166 case TOWN_MENU_TRAIN:
167 disp_train_menu(refreshFlag);
168 break;
169
170 case TOWN_MENU_SPY:
171 disp_spy_menu(refreshFlag);
172 break;
173
174 case TOWN_MENU_VIEW_SECRET:
175 spy_array.disp_view_secret_menu(action_spy_recno, refreshFlag);
176 break;
177
178 case TOWN_MENU_SET_AUTO_COLLECT_TAX:
179 if( refreshFlag == INFO_REPAINT )
180 disp_auto_menu(1);
181 break;
182
183 case TOWN_MENU_SET_AUTO_GRANT:
184 if( refreshFlag == INFO_REPAINT )
185 disp_auto_menu(0);
186 break;
187 }
188 }
189 //----------- End of function Town::disp_info -----------//
190
191
192 //--------- Begin of function Town::detect_info ---------//
193 //
detect_info()194 void Town::detect_info()
195 {
196 if_town_recno = town_recno;
197
198 switch( town_menu_mode )
199 {
200 case TOWN_MENU_MAIN:
201 if( detect_main_menu() )
202 return;
203 break;
204
205 case TOWN_MENU_TRAIN:
206 if( detect_train_menu() )
207 return;
208 break;
209
210 case TOWN_MENU_SPY:
211 if( detect_spy_menu() )
212 return;
213 break;
214
215 case TOWN_MENU_VIEW_SECRET:
216 if( spy_array.detect_view_secret_menu(action_spy_recno, nation_recno) )
217 {
218 town_menu_mode = TOWN_MENU_MAIN;
219 info.disp();
220 return;
221 }
222 break;
223
224 case TOWN_MENU_SET_AUTO_COLLECT_TAX:
225 if( detect_auto_menu(1) )
226 return;
227 break;
228
229 case TOWN_MENU_SET_AUTO_GRANT:
230 if( detect_auto_menu(0) )
231 return;
232 break;
233 }
234
235 if( ISKEY(KEYEVENT_OBJECT_PREV) )
236 {
237 town_array.disp_next(-1, 0); // previous same object type of any nation
238 return;
239 }
240
241 if( ISKEY(KEYEVENT_OBJECT_NEXT) )
242 {
243 town_array.disp_next(1, 0); // next same object type of any nation
244 return;
245 }
246
247 if( ISKEY(KEYEVENT_NATION_OBJECT_PREV) )
248 {
249 town_array.disp_next(-1, 1); // prevous same object type of the same nation
250 return;
251 }
252
253 if( ISKEY(KEYEVENT_NATION_OBJECT_NEXT) )
254 {
255 town_array.disp_next(1, 1); // next same object type of the same nation
256 return;
257 }
258 }
259 //----------- End of function Town::detect_info -----------//
260
261
262 //--------- Begin of function Town::disp_main_menu ---------//
263 //
disp_main_menu(int refreshFlag)264 void Town::disp_main_menu(int refreshFlag)
265 {
266 static short lastTownNationRecno;
267
268 //--- if the town's owner nation has just been changed ---//
269
270 if( lastTownNationRecno != nation_recno )
271 {
272 lastTownNationRecno = nation_recno;
273 info.disp();
274 return;
275 }
276
277 //--------- display basic info --------//
278
279 disp_basic_info(refreshFlag);
280
281 //---------- paint controls -----------//
282
283 if( refreshFlag == INFO_REPAINT )
284 {
285 recruit_race_count = race_filter();
286
287 //------ display browser field description -------//
288
289 int x=RACE_BROWSE_X1+2;
290 int y=RACE_BROWSE_Y1-23;
291
292 vga_util.d3_panel_up( RACE_BROWSE_X1, y, RACE_BROWSE_X2, RACE_BROWSE_Y1-3 );
293
294 font_san.put( x+2 , y+4, _("Population") );
295 font_san.put( x+70 , y+4, _("Peasants") );
296
297 if( nation_recno ) // only display loyalty if this town is controlled by a nation
298 font_san.put( x+132, y+4, _("Loyalty") );
299 else
300 {
301 #ifdef GERMAN
302 font_san.put( x+128, y+4, "Resistance" );
303 #else
304 font_san.put( x+132, y+4, _("Resistance") );
305 #endif
306 }
307
308 //------------ create browser ------------//
309
310 browse_race.init( RACE_BROWSE_X1, RACE_BROWSE_Y1, RACE_BROWSE_X2, RACE_BROWSE_Y2,
311 0, 25, recruit_race_count, put_race_rec );
312
313 browse_race.open(browse_race_recno);
314
315 browse_race_town_recno = town_recno; // the town which browse_race displays
316
317 //---------- paint total section ----------//
318
319 vga_util.d3_panel_up( RACE_BROWSE_X1, RACE_BROWSE_Y2+3, RACE_BROWSE_X2, RACE_BROWSE_Y2+23 );
320
321 font_san.put( RACE_BROWSE_X1+5, RACE_BROWSE_Y2+7, _("Total") );
322 font_san.put( RACE_BROWSE_X1+128, RACE_BROWSE_Y2+7, _("Avg") );
323 }
324 else
325 {
326 //---------- update controls -----------//
327
328 if( recruit_race_count != race_filter() )
329 {
330 info.disp();
331 return;
332 }
333
334 browse_race.update();
335 }
336
337 browse_race_recno = browse_race.recno();
338
339 //----------- display total -----------//
340
341 font_mid.put( RACE_BROWSE_X1+52, RACE_BROWSE_Y2+6, population, 1 );
342 font_mid.put( RACE_BROWSE_X1+94, RACE_BROWSE_Y2+6, jobless_population, 1 );
343
344 if( nation_recno )
345 font_mid.put( RACE_BROWSE_X1+165, RACE_BROWSE_Y2+6, average_loyalty(), 1 );
346 else
347 font_mid.put( RACE_BROWSE_X1+165, RACE_BROWSE_Y2+6, average_resistance(nation_array.player_recno), 1 );
348
349 //------ if this town is controlled by a rebel group -----//
350
351 int x=BUTTON_X1, y=BUTTON_Y1;
352
353 if( rebel_recno )
354 {
355 if( refreshFlag == INFO_REPAINT )
356 font_san.d3_put( BUTTON_X1, y-1, BUTTON_X2, y+19, _("Controlled by Rebels") );
357
358 y+=23;
359 }
360
361 //----------- create the paint button ----------//
362
363 if( nation_recno==nation_array.player_recno )
364 {
365 if( refreshFlag == INFO_REPAINT )
366 {
367 button_recruit.paint( BUTTON_X1, y, 'A', "RECRUIT" );
368
369 if( has_linked_own_camp )
370 {
371 button_train.paint( BUTTON_X1+BUTTON_ACTION_WIDTH, y, 'A', "TRAIN" );
372 button_tax.paint( BUTTON_X1+BUTTON_ACTION_WIDTH*2, y, 'A', "COLLTAX" );
373 button_grant.paint( BUTTON_X1+BUTTON_ACTION_WIDTH*3, y, 'A', "GRANT" );
374
375 disp_auto_loyalty();
376 }
377 else
378 {
379 button_train.reset();
380 button_tax.reset();
381 button_grant.reset();
382 }
383
384 #ifdef DEBUG
385 if(debug2_enable_flag)
386 {
387 font_san.d3_put( INFO_X1, INFO_Y2-30, INFO_X2, INFO_Y2, "" );
388 font_san.field( INFO_X1+10, INFO_Y2-20, " ", INFO_X1+20, town_recno, 1, INFO_X2-10, refreshFlag);
389 font_san.field( INFO_X1+40, INFO_Y2-20, " ", INFO_X1+50, loc_x1, 1, INFO_X2-10, refreshFlag);
390 font_san.field( INFO_X1+70, INFO_Y2-20, " ", INFO_X1+80, loc_y1, 1, INFO_X2-10, refreshFlag);
391 font_san.field( INFO_X1+100, INFO_Y2-20, " ", INFO_X1+110, ai_link_checked, 1, INFO_X2-10, refreshFlag);
392 }
393 #endif
394 }
395
396 if( has_linked_own_camp ) // a whole row is used for displaying buttons, so additional buttons will be displayed in the next row
397 y += BUTTON_ACTION_HEIGHT;
398 else
399 x += BUTTON_ACTION_WIDTH; // only one button "Recruit", new button displayed next to it.
400
401 //-------- enable/disable the train button -----------//
402
403 int raceId = race_filter(browse_race.recno());
404
405 if( can_recruit(raceId) )
406 button_recruit.enable();
407 else
408 button_recruit.disable();
409
410 if( button_train.init_flag )
411 {
412 if( can_train(raceId) )
413 button_train.enable();
414 else
415 button_train.disable();
416 }
417
418 if( button_tax.init_flag )
419 {
420 // ###### patch begin Gilbert 5/8 ######//
421 // if( average_loyalty() >= 1 )
422 if( average_loyalty() > COLLECT_TAX_LOYALTY_DECREASE )
423 // ###### end begin Gilbert 5/8 ######//
424 button_tax.enable();
425 else
426 button_tax.disable();
427 }
428
429 if( button_grant.init_flag )
430 {
431 if( nation_recno && nation_array[nation_recno]->cash > 0 )
432 button_grant.enable();
433 else
434 button_grant.disable();
435 }
436
437 //--------- display train info --------//
438
439 if( train_unit_recno ) // display the progress of the current training process
440 disp_train_info(refreshFlag);
441 }
442
443 //------ grant to an independent town ------//
444
445 else if( nation_array.player_recno &&
446 can_grant_to_non_own_town(nation_array.player_recno) )
447 {
448 if( refreshFlag == INFO_REPAINT )
449 button_grant.paint( BUTTON_X1, y, 'A', "GRANT2" );
450
451 if( button_grant.init_flag )
452 {
453 if( nation_array[nation_array.player_recno]->cash > 0 )
454 button_grant.enable();
455 else
456 button_grant.disable();
457 }
458
459 x += BUTTON_ACTION_WIDTH;
460 }
461
462 //---------- display the spy button ----------//
463
464 int spyFlag = spy_filter() > 0;
465
466 if( refreshFlag == INFO_REPAINT )
467 {
468 if( spyFlag ) // only display the spy button for non-player towns
469 button_spy.paint( x, y, 'A', "SPYMENU" );
470 else
471 button_spy.reset();
472 }
473 else
474 {
475 if( spyFlag != button_spy.init_flag ) // if the button availability has just changed
476 {
477 if(spyFlag) // only display the spy button for non-player towns
478 button_spy.paint( x, y, 'A', "SPYMENU" );
479 else // remove the button from the screen
480 button_spy.hide();
481 }
482 }
483
484 //-------- display debug info ----------//
485
486 if( sys.debug_session || sys.testing_session )
487 disp_debug_resistance(refreshFlag);
488 }
489 //----------- End of function Town::disp_main_menu -----------//
490
491
492 //--------- Begin of function Town::disp_auto_loyalty ---------//
493 //
disp_auto_loyalty()494 void Town::disp_auto_loyalty()
495 {
496 if( auto_collect_tax_loyalty )
497 {
498 vga_front.bar( button_tax.x1+8, button_tax.y1+10, button_tax.x2-12, button_tax.y2-15, V_WHITE );
499 vga_front.rect( button_tax.x1+8, button_tax.y1+10, button_tax.x2-12, button_tax.y2-15, 1, V_BLACK );
500
501 font_mid.center_put( button_tax.x1+8, button_tax.y1+10, button_tax.x2-12, button_tax.y2-15,
502 misc.format(auto_collect_tax_loyalty) );
503 }
504
505 if( auto_grant_loyalty )
506 {
507 vga_front.bar( button_grant.x1+8, button_grant.y1+10, button_grant.x2-12, button_grant.y2-15, V_WHITE );
508 vga_front.rect( button_grant.x1+8, button_grant.y1+10, button_grant.x2-12, button_grant.y2-15, 1, V_BLACK );
509
510 font_mid.center_put( button_grant.x1+8, button_grant.y1+10, button_grant.x2-12, button_grant.y2-15,
511 misc.format(auto_grant_loyalty) );
512 }
513 }
514 //----------- End of function Town::disp_auto_loyalty -----------//
515
516
517 //--------- Begin of function Town::detect_main_menu ---------//
518 //
detect_main_menu()519 int Town::detect_main_menu()
520 {
521 //--- detect clicking on the name area to center the map on it ---//
522
523 if( mouse.single_click(INFO_X1, INFO_Y1, INFO_X2, INFO_Y1+21) )
524 {
525 world.go_loc( center_x, center_y );
526 return 1;
527 }
528
529 //-------- detect browsers ---------//
530
531 if( browse_race.detect() )
532 {
533 browse_race_recno = browse_race.recno();
534 // ##### begin patch Gilbert 21/1 #######//
535 if( sys.debug_session || sys.testing_session )
536 disp_debug_resistance(INFO_UPDATE);
537 // ##### end patch Gilbert 21/1 #######//
538 return 1;
539 }
540
541 if( button_spy.detect() ) // switch to the spy menu
542 {
543 town_menu_mode = TOWN_MENU_SPY;
544 disable_refresh = 1; // static var for disp_info() only
545 info.disp();
546 disable_refresh = 0;
547 return 1;
548 }
549
550 //----- detect granting to an independent town ---//
551
552 if( nation_array.player_recno &&
553 can_grant_to_non_own_town(nation_array.player_recno) )
554 {
555 if( button_grant.detect() )
556 {
557 se_ctrl.immediate_sound("TURN_ON");
558
559 grant_to_non_own_town(nation_array.player_recno, COMMAND_PLAYER);
560 return 1;
561 }
562 }
563
564 //---------- buttons for player town only --------//
565
566 if( nation_recno!=nation_array.player_recno )
567 return 0;
568
569 //------ update button status ------//
570
571 if( browse_race.recno() > race_filter() )
572 return 0;
573
574 int raceId = race_filter(browse_race.recno());
575
576 if( can_recruit(raceId) )
577 button_recruit.enable();
578 else
579 button_recruit.disable();
580
581 if( can_train(raceId) )
582 button_train.enable();
583 else
584 button_train.disable();
585
586 //------- detect buttons --------//
587
588 if( button_recruit.detect(GETKEY(KEYEVENT_TOWN_RECRUIT)) )
589 {
590 recruit(-1, 0, COMMAND_PLAYER);
591 return 1;
592 }
593
594 if( button_train.detect(GETKEY(KEYEVENT_TOWN_TRAIN)) )
595 {
596 town_menu_mode = TOWN_MENU_TRAIN;
597 disable_refresh = 1; // static var for disp_info() only
598 info.disp();
599 disable_refresh = 0;
600 return 1;
601 }
602
603 int rc;
604
605 if( (rc=button_tax.detect(0, 0, 1)) > 0 ) // 1-detect right-clicking
606 {
607 disp_auto_loyalty();
608
609 // ##### begin Gilbert 26/9 ########//
610 se_ctrl.immediate_sound("TURN_ON");
611 // ##### end Gilbert 26/9 ########//
612
613 if( rc==1 )
614 {
615 town_array[town_recno]->collect_tax(COMMAND_PLAYER);
616 }
617 else if( rc==2 ) // right click
618 {
619 town_menu_mode = TOWN_MENU_SET_AUTO_COLLECT_TAX;
620 disable_refresh = 1; // static var for disp_info() only
621 info.disp();
622 disable_refresh = 0;
623 }
624 return 1;
625 }
626
627 if( (rc=button_grant.detect(0, 0, 1)) > 0 )
628 {
629 disp_auto_loyalty();
630
631 // ##### begin Gilbert 26/9 ########//
632 se_ctrl.immediate_sound("TURN_ON");
633 // ##### end Gilbert 26/9 ########//
634
635 if( rc==1 )
636 {
637 town_array[town_recno]->reward(COMMAND_PLAYER);
638 }
639 else if( rc==2 ) // right click
640 {
641 town_menu_mode = TOWN_MENU_SET_AUTO_GRANT;
642 disable_refresh = 1; // static var for disp_info() only
643 info.disp();
644 disable_refresh = 0;
645 }
646 return 1;
647 }
648
649 if(train_unit_recno)
650 {
651 if((rc = button_cancel_training.detect()))
652 {
653 if( !remote.is_enable() )
654 {
655 cancel_train_unit();
656 info.disp();
657 }
658 else
659 {
660 short *shortPtr = (short *)remote.new_send_queue_msg(MSG_TOWN_SKIP_RECRUIT, sizeof(short));
661 shortPtr[0] = town_recno;
662 }
663 return 1;
664 }
665 }
666
667 return 0;
668 }
669 //----------- End of function Town::detect_main_menu -----------//
670
671
672 //--------- Begin of function Town::disp_basic_info ---------//
673 //
disp_basic_info(int refreshFlag)674 void Town::disp_basic_info(int refreshFlag)
675 {
676 if( refreshFlag == INFO_REPAINT )
677 {
678 vga_util.d3_panel_up( INFO_X1, INFO_Y1, INFO_X2, INFO_Y1+21 );
679
680 if( nation_recno )
681 {
682 font_san.center_put( INFO_X1+21, INFO_Y1, INFO_X2-2, INFO_Y1+21, town_name() );
683
684 char *nationPict = image_button.get_ptr("V_COLCOD");
685
686 vga_front.put_bitmap_trans_remap_decompress(INFO_X1+3, INFO_Y1+2, nationPict, game.get_color_remap_table(nation_recno, 0) );
687 }
688 else
689 {
690 font_san.center_put( INFO_X1, INFO_Y1, INFO_X2-2, INFO_Y1+21, town_name() );
691 }
692 }
693 }
694 //----------- End of function Town::disp_basic_info -----------//
695
696
697 //--------- Begin of function Town::disp_train_info ---------//
698 //
disp_train_info(int refreshFlag)699 void Town::disp_train_info(int refreshFlag)
700 {
701 if( !train_unit_recno || nation_recno!=nation_array.player_recno )
702 return;
703
704 int dispY1 = INFO_Y1+26;
705
706 Unit* unitPtr = unit_array[train_unit_recno];
707 int x=MSG_X1+4, y=MSG_Y1+4;
708
709 if( refreshFlag == INFO_REPAINT )
710 {
711 vga_util.d3_panel_up( MSG_X1, MSG_Y1, MSG_X2, MSG_Y2 );
712
713 vga_util.d3_panel_down(x, y, x+RACE_ICON_WIDTH+3, y+RACE_ICON_HEIGHT+3 );
714 vga_front.put_bitmap(x+2, y+2, race_res[unitPtr->race_id]->icon_bitmap_ptr );
715
716 // vga_util.d3_panel_down(x+RACE_ICON_WIDTH+6, y, MSG_X2-4, MSG_Y2-4 );
717 }
718
719 int totalDays;
720
721 if( config.fast_build && nation_recno==nation_array.player_recno )
722 totalDays = TOTAL_TRAIN_DAYS/2;
723 else
724 totalDays = TOTAL_TRAIN_DAYS;
725
726 vga_front.indicator( 0, x+RACE_ICON_WIDTH+6, y, float(sys.frame_count-start_train_frame_no),
727 float(totalDays * FRAMES_PER_DAY), VGA_GRAY );
728
729 button_cancel_training.paint(MSG_X2-27, MSG_Y1+2, "V_X-U", "V_X-D");
730 button_cancel_training.set_help_code( "CANCELTRA" );
731 }
732 //----------- End of function Town::disp_train_info -----------//
733
734
735 //------ Begin of function Town::browse_selected_race_id ------//
736 //
737 // Return the id. of the race selected in the town's race browser.
738 //
browse_selected_race_id()739 int Town::browse_selected_race_id()
740 {
741 err_when( town_recno != town_array.selected_recno ); // the current town must be the selected one when this function is called
742
743 if( browse_race_town_recno != town_recno ) // the browser still hasn't displayed this town yet. This happens when the selected town is just changed, and this function is called before the town interface is refreshed
744 return 0;
745
746 if( browse_race.none_record )
747 return 0;
748
749 int raceCount = race_filter();
750
751 if( raceCount != browse_race.total_rec() ||
752 raceCount != recruit_race_count )
753 {
754 info.disp();
755 }
756
757 err_when( browse_race.recno() < 1 );
758 err_when( browse_race.recno() > raceCount );
759 err_when( browse_race.recno() > browse_race.total_rec() );
760
761 return race_filter(browse_race.recno());
762 }
763 //------ End of function Town::browse_selected_race_id ------//
764
765
766 //--------- Begin of function race_filter ---------//
767 //
768 // Filter those races that are in the town and can be trained.
769 //
race_filter(int recNo)770 static int race_filter(int recNo)
771 {
772 err_when( recNo && recNo < 1 );
773 err_when( recNo && recNo > recruit_race_count );
774 err_when( recNo && recNo > browse_race.total_rec() );
775
776 int i, recCount=0;
777 Town* townPtr = town_array[Town::if_town_recno];
778
779 for( i=0 ; i<MAX_RACE ; i++ )
780 {
781 if( townPtr->race_pop_array[i] > 0 )
782 recCount++;
783
784 if( recNo && recCount==recNo )
785 return i+1;
786 }
787
788 err_when( recNo );
789
790 return recCount;
791 }
792 //----------- End of function race_filter -----------//
793
794
795 //-------- Begin of static function put_race_rec --------//
796 //
put_race_rec(int recNo,int x,int y,int refreshFlag)797 static void put_race_rec(int recNo, int x, int y, int refreshFlag)
798 {
799 //-------- display race icon -------//
800
801 int raceId = race_filter(recNo);
802 RaceInfo* raceInfo = race_res[raceId];
803
804 if( refreshFlag == INFO_REPAINT )
805 {
806 vga_util.d3_panel_down(x+1, y+1, x+RACE_ICON_WIDTH+4, y+RACE_ICON_HEIGHT+4 );
807 vga_front.put_bitmap(x+3, y+3, raceInfo->icon_bitmap_ptr);
808 }
809
810 //--------- set help parameters --------//
811
812 if( mouse.in_area(x+1, y+1, x+RACE_ICON_WIDTH+4, y+RACE_ICON_HEIGHT+4) )
813 help.set_unit_help( raceInfo->basic_unit_id, 0, x+1, y+1, x+RACE_ICON_WIDTH+4, y+RACE_ICON_HEIGHT+4 );
814
815 //-------- display race name --------//
816
817 Town* townPtr = town_array[Town::if_town_recno];
818
819 font_mid.put( x+46, y+6, townPtr->race_pop_array[raceId-1],1, x+87 );
820 font_mid.put( x+88, y+6, townPtr->jobless_race_pop_array[raceId-1], 1, x+129 );
821
822 //---- only display loyalty if this town is controlled by a nation ----//
823
824 int curLoyalty, targetLoyalty;
825 int x2 = x+browse_race.rec_width-1;
826
827 if( townPtr->nation_recno )
828 {
829 curLoyalty = (int) townPtr->race_loyalty_array[raceId-1];
830 targetLoyalty = (int) townPtr->race_target_loyalty_array[raceId-1];
831 }
832 else
833 {
834 curLoyalty = (int) townPtr->race_resistance_array[raceId-1][nation_array.player_recno-1];
835 targetLoyalty = (int) townPtr->race_target_resistance_array[raceId-1][nation_array.player_recno-1];
836
837 if( targetLoyalty > curLoyalty ) // resistance only decrease, won't increase
838 targetLoyalty = -1; // don't display the decrease target
839 }
840
841 //---------- display loyalty/resistance ------------//
842
843 int dispArrow=0;
844 String str;
845
846 if( curLoyalty == targetLoyalty || targetLoyalty == -1 ) // only display up and down arrow for independent town's resistance
847 {
848 str = curLoyalty;
849 }
850 else
851 {
852 str = curLoyalty;
853 str += " ";
854 str += targetLoyalty;
855
856 dispArrow=1;
857 }
858
859 x2 = font_mid.center_put( x+110, y+6, x2, y+5+font_mid.height(), str, 1 );
860
861 //--------- display up/down arrow -----------//
862
863 if( dispArrow )
864 {
865 x = x2-font_mid.text_width( misc.format(targetLoyalty) ) - 8;
866
867 if( (int) targetLoyalty > (int) curLoyalty )
868 image_icon.put_join( x+1, y+9, "ARROWUP" );
869
870 else if( (int) targetLoyalty < (int) curLoyalty )
871 image_icon.put_join( x+1, y+9, "ARROWDWN" );
872 }
873 }
874 //----------- End of static function put_race_rec -----------//
875
876
877 //--------- Begin of function Town::disp_train_menu ---------//
878 //
disp_train_menu(int refreshFlag)879 void Town::disp_train_menu(int refreshFlag)
880 {
881 // ####### begin Gilbert 13/9 ########//
882 if( refreshFlag == INFO_UPDATE )
883 {
884 for( int i=1; i<=MAX_TRAINABLE_SKILL; i++)
885 {
886 button_skill[i-1].paint(-1,0);
887 // button_queue_skill[i] is called by automatically
888 }
889 }
890 else if( refreshFlag == INFO_REPAINT )
891 {
892 font_san.d3_put( INFO_X1, INFO_Y1, INFO_X2, INFO_Y1+18, _("Train (Cost: $30, Skill: 20)") );
893 int x=INFO_X1, y=INFO_Y1+24;
894
895 for(int i=1; i<=MAX_TRAINABLE_SKILL; i++)
896 {
897 button_queue_skill[i-1].create(INFO_X1+COUNT_BUTTON_OFFSET_X,
898 y+COUNT_BUTTON_OFFSET_Y,
899 INFO_X1+COUNT_BUTTON_OFFSET_X+COUNT_BUTTON_WIDTH-1,
900 y+COUNT_BUTTON_OFFSET_Y+COUNT_BUTTON_HEIGHT-1,
901 i_disp_queue_skill_button, ButtonCustomPara(this,i));
902
903 button_skill[i-1].paint(INFO_X1, y,
904 INFO_X2, y+BUTTON_ACTION_HEIGHT-1,
905 i_disp_skill_button, ButtonCustomPara(&button_queue_skill[i-1],i) );
906
907 y += BUTTON_ACTION_HEIGHT;
908 }
909
910 button_cancel3.paint( INFO_X1, y, INFO_X2, y+BUTTON_ACTION_HEIGHT*3/4-1,
911 ButtonCustom::disp_text_button_func, ButtonCustomPara((void*)_("Done"),0) );
912 }
913 // ####### end Gilbert 13/9 ########//
914 }
915 //----------- End of function Town::disp_train_menu -----------//
916
917 // ######### begin Gilbert 13/9 #########//
918
919 //-------- Begin of function i_disp_skill_button --------//
920 //
i_disp_skill_button(ButtonCustom * button,int repaintBody)921 static void i_disp_skill_button(ButtonCustom *button, int repaintBody)
922 {
923 int x1 = button->x1;
924 int y1 = button->y1;
925 int x2 = button->x2;
926 int y2 = button->y2;
927 if( !button->pushed_flag )
928 {
929 if( repaintBody )
930 {
931 vga_util.blt_buf(x1, y1, x2, y2, 0);
932 vga_util.d3_panel2_up( x1, y1, x2, y2, 1 );
933 }
934 x2--;
935 y2--;
936 }
937 else
938 {
939 if( repaintBody )
940 {
941 vga_util.blt_buf(x1, y1, x2, y2, 0);
942 vga_util.d3_panel2_down( x1, y1, x2, y2, 1 );
943 }
944 x1++;
945 y1++;
946 }
947
948 ButtonCustom *queueButton = (ButtonCustom *)button->custom_para.ptr;
949 if( repaintBody)
950 {
951 // display skill large icon
952 short skillId = button->custom_para.value;
953 char str[9] = "U_";
954 strcat( str, Skill::skill_code_array[skillId-1] );
955 char *bitmapPtr = image_button.get_ptr(str);
956
957 vga_front.put_bitmap_trans_decompress(x1, y1+4, bitmapPtr);
958
959 // put name
960 String str2;
961
962 str2 = "";
963
964 if( skillId == queue_train_selected )
965 str2 += ">";
966
967 if( skillId == SKILL_MFT )
968 str2 += _("Manufacturing"); // the string in skill_str_array[] is "Manufacture".
969 else
970 str2 += _(Skill::skill_str_array[skillId-1]);
971
972 if( skillId == queue_train_selected )
973 str2 += "<";
974
975 font_bible.put(x1+50, y1+11, str2);
976 }
977
978 // display small button
979 queueButton->paint(-1, repaintBody);
980 }
981 //--------- End of static function i_disp_skill_button ---------//
982
983 //-------- Begin of static function i_disp_queue_skill_button --------//
984 //
i_disp_queue_skill_button(ButtonCustom * button,int repaintBody)985 static void i_disp_queue_skill_button(ButtonCustom *button, int repaintBody)
986 {
987 Town *townPtr= (Town *)button->custom_para.ptr;
988
989 int x1 = button->x1;
990 int y1 = button->y1;
991 int x2 = button->x2;
992 int y2 = button->y2;
993 if( !button->pushed_flag )
994 {
995 if( repaintBody )
996 {
997 vga_util.blt_buf(x1, y1, x2, y2, 0);
998 vga_util.d3_panel2_up( x1, y1, x2, y2, 1, 1);
999 }
1000 x2--;
1001 y2--;
1002 }
1003 else
1004 {
1005 if( repaintBody )
1006 {
1007 vga_util.blt_buf(x1, y1, x2, y2, 0);
1008 vga_util.d3_panel2_down( x1, y1, x2, y2, 1, 1);
1009 }
1010 x1++;
1011 y1++;
1012 }
1013
1014 //----- count the no. of units queued for this skill ------//
1015
1016 short skillId = button->custom_para.value;
1017 int queuedCount=0;
1018 for( int i=0 ; i<townPtr->train_queue_count ; i++ )
1019 {
1020 if( townPtr->train_queue_skill_array[i] == skillId )
1021 queuedCount++;
1022 }
1023 if(townPtr->train_unit_recno)
1024 {
1025 Unit *unitPtr = unit_array[townPtr->train_unit_recno];
1026 // ##### begin Gilbert 10/10 #######//
1027 if(unitPtr->skill.skill_id==skillId
1028 //### begin alex 17/3 ###//
1029 //|| (unitPtr->spy_recno && skillId == SKILL_SPYING) )
1030 || (skillId == SKILL_SPYING && unitPtr->spy_recno && unitPtr->skill.skill_id == 0) ) // 0 for spying-training
1031 //#### end alex 17/3 ####//
1032 queuedCount++;
1033 // ##### end Gilbert 10/10 #######//
1034 }
1035
1036 font_mid.center_put( x1+3, y1+3, x2-3, y2-3, misc.format(queuedCount), 1);
1037 }
1038 //--------- End of static function i_disp_queue_skill_button ---------//
1039 // ######### end Gilbert 13/9 #########//
1040
1041 //--------- Begin of function Town::detect_train_menu ---------//
1042 //
detect_train_menu()1043 int Town::detect_train_menu()
1044 {
1045 int x=INFO_X1+2, y=INFO_Y1+24, rc, quitFlag, waitFlag;
1046
1047 waitFlag = 0;
1048 for(int b=1; b<=MAX_TRAINABLE_SKILL; ++b)
1049 {
1050 // ###### begin Gilbert 10/9 ########//
1051 //------ detect pressing on the small queue count button -------//
1052 rc = 0;
1053 if( (rc = button_queue_skill[b-1].detect(0,0,2)) != 0)
1054 {
1055 quitFlag = 0; // don't quit the menu right after pressing the button
1056 }
1057 //------ detect pressing on the big button -------//
1058 // but defer to the queue button if clicked over that
1059 else if( !button_queue_skill[b-1].button_wait && ((rc= button_skill[b-1].detect(0,0,2)) != 0) )
1060 {
1061 quitFlag = 1; // quit the menu right after pressing the button
1062 }
1063 // ###### end Gilbert 10/9 ########//
1064
1065 if( button_queue_skill[b-1].button_wait || button_skill[b-1].button_wait )
1066 waitFlag = 1;
1067
1068 int shiftPressed = mouse.event_skey_state & SHIFT_KEY_MASK;
1069
1070 //------- process the action --------//
1071 if( rc > 0 )
1072 {
1073 // Holding shift will use batches of FIRMWAR_BUILD_BATCH_COUNT
1074 int trainCancelAmount = shiftPressed ? TOWN_TRAIN_BATCH_COUNT : 1;
1075
1076 if( rc==1 ) // left button
1077 {
1078 if( remote.is_enable() )
1079 {
1080 // packet structure : <town recno> <skill id> <race id> <amount>
1081 short *shortPtr = (short *)remote.new_send_queue_msg(MSG_TOWN_RECRUIT, 4*sizeof(short) );
1082 shortPtr[0] = town_recno;
1083 shortPtr[1] = b;
1084 shortPtr[2] = race_filter(browse_race.recno());
1085 shortPtr[3] = (short)trainCancelAmount;
1086 }
1087 else
1088 add_queue(b, race_filter(browse_race.recno()), trainCancelAmount);
1089 // ##### begin Gilbert 26/9 ########//
1090 se_ctrl.immediate_sound("TURN_ON");
1091 // ##### end Gilbert 26/9 ########//
1092 }
1093 else // right button - remove queue
1094 {
1095 if( remote.is_enable() )
1096 {
1097 // packet structure : <town recno> <skill id> <race id> <amount>
1098 short *shortPtr = (short *)remote.new_send_queue_msg(MSG_TOWN_RECRUIT, 4*sizeof(short) );
1099 shortPtr[0] = town_recno;
1100 shortPtr[1] = b;
1101 shortPtr[2] = -1; // -1 race_id represent remove queue
1102 shortPtr[3] = (short)trainCancelAmount;
1103 }
1104 else
1105 remove_queue(b, trainCancelAmount);
1106 // ##### begin Gilbert 26/9 ########//
1107 se_ctrl.immediate_sound("TURN_OFF");
1108 // ##### end Gilbert 26/9 ########//
1109 }
1110
1111 if( quitFlag )
1112 info.disp(); // info.disp() will call put_info() which will switch mode back to the main menu mode
1113 // ####### begin Gilbert 10/9 ######//
1114 else
1115 info.update();
1116 // ####### end Gilbert 10/9 ######//
1117
1118 return 1;
1119 }
1120
1121 y += BUTTON_ACTION_HEIGHT;
1122 }
1123 //------ detect the cancel button --------//
1124
1125 if( button_cancel3.detect() || (!waitFlag && mouse.any_click(1)) ) // press the cancel button or right click
1126 {
1127 // ##### begin Gilbert 26/9 ########//
1128 se_ctrl.immediate_sound("TURN_OFF");
1129 // ##### end Gilbert 26/9 ########//
1130 town_menu_mode = TOWN_MENU_MAIN;
1131 info.disp();
1132 return 1;
1133 }
1134
1135 //------ detect production selecting hotkeys --------//
1136
1137 if( ISKEY(KEYEVENT_MANUF_QUEUE_UP) )
1138 {
1139 queue_train_selected--;
1140 if( queue_train_selected <= 0 )
1141 queue_train_selected = MAX_TRAINABLE_SKILL;
1142 disp_train_menu(INFO_REPAINT);
1143 return 1;
1144 }
1145
1146 if( ISKEY(KEYEVENT_MANUF_QUEUE_DOWN) )
1147 {
1148 queue_train_selected++;
1149 if( queue_train_selected > MAX_TRAINABLE_SKILL )
1150 queue_train_selected = 1;
1151 disp_train_menu(INFO_REPAINT);
1152 return 1;
1153 }
1154
1155 if( queue_train_selected && ISKEY(KEYEVENT_MANUF_QUEUE_ADD) )
1156 {
1157 if( remote.is_enable() )
1158 {
1159 // packet structure : <town recno> <skill id> <race id> <amount>
1160 short *shortPtr = (short *)remote.new_send_queue_msg(MSG_TOWN_RECRUIT, 4*sizeof(short) );
1161 shortPtr[0] = town_recno;
1162 shortPtr[1] = queue_train_selected;
1163 shortPtr[2] = race_filter(browse_race.recno());
1164 shortPtr[3] = 1;
1165 }
1166 else
1167 add_queue(queue_train_selected, race_filter(browse_race.recno()), 1);
1168 se_ctrl.immediate_sound("TURN_ON");
1169 return 1;
1170 }
1171
1172 if( queue_train_selected && ISKEY(KEYEVENT_MANUF_QUEUE_ADD_BATCH) )
1173 {
1174 if( remote.is_enable() )
1175 {
1176 // packet structure : <town recno> <skill id> <race id> <amount>
1177 short *shortPtr = (short *)remote.new_send_queue_msg(MSG_TOWN_RECRUIT, 4*sizeof(short) );
1178 shortPtr[0] = town_recno;
1179 shortPtr[1] = queue_train_selected;
1180 shortPtr[2] = race_filter(browse_race.recno());
1181 shortPtr[3] = TOWN_TRAIN_BATCH_COUNT;
1182 }
1183 else
1184 add_queue(queue_train_selected, race_filter(browse_race.recno()), TOWN_TRAIN_BATCH_COUNT);
1185 se_ctrl.immediate_sound("TURN_ON");
1186 return 1;
1187 }
1188
1189 if( queue_train_selected && ISKEY(KEYEVENT_MANUF_QUEUE_REMOVE) )
1190 {
1191 if( remote.is_enable() )
1192 {
1193 // packet structure : <town recno> <skill id> <race id> <amount>
1194 short *shortPtr = (short *)remote.new_send_queue_msg(MSG_TOWN_RECRUIT, 4*sizeof(short) );
1195 shortPtr[0] = town_recno;
1196 shortPtr[1] = queue_train_selected;
1197 shortPtr[2] = -1; // -1 race_id represent remove queue
1198 shortPtr[3] = 1;
1199 }
1200 else
1201 remove_queue(queue_train_selected, 1);
1202 se_ctrl.immediate_sound("TURN_OFF");
1203 return 1;
1204 }
1205
1206 if( queue_train_selected && ISKEY(KEYEVENT_MANUF_QUEUE_REMOVE_BATCH) )
1207 {
1208 if( remote.is_enable() )
1209 {
1210 // packet structure : <town recno> <skill id> <race id> <amount>
1211 short *shortPtr = (short *)remote.new_send_queue_msg(MSG_TOWN_RECRUIT, 4*sizeof(short) );
1212 shortPtr[0] = town_recno;
1213 shortPtr[1] = queue_train_selected;
1214 shortPtr[2] = -1; // -1 race_id represent remove queue
1215 shortPtr[3] = TOWN_TRAIN_BATCH_COUNT;
1216 }
1217 else
1218 remove_queue(queue_train_selected, TOWN_TRAIN_BATCH_COUNT);
1219 se_ctrl.immediate_sound("TURN_OFF");
1220 return 1;
1221 }
1222
1223 return 0;
1224 }
1225 //----------- End of function Town::detect_train_menu -----------//
1226
1227
1228 //--------- Begin of function Town::disp_auto_menu ---------//
1229 //
disp_auto_menu(int modeCollectTax)1230 void Town::disp_auto_menu(int modeCollectTax)
1231 {
1232 int curAutoLoyalty;
1233
1234 Nation* nationPtr = nation_array[nation_recno];
1235
1236 if( modeCollectTax )
1237 curAutoLoyalty = auto_collect_tax_loyalty;
1238 else
1239 curAutoLoyalty = auto_grant_loyalty;
1240
1241 //---------- paint buttons ------------//
1242
1243 String headingStr;
1244
1245 if( modeCollectTax )
1246 headingStr = _("Automatically Collect Tax from Villagers when their Loyalty reaches:");
1247 else
1248 headingStr = _("Automatically Grant Money to Villagers when their Loyalty drops below:");
1249
1250 headingStr += "\n";
1251 headingStr += _("(Left-click below to apply to this village. Right-click below to apply to all your villages.)");
1252
1253 vga_util.d3_panel_up( INFO_X1, INFO_Y1, INFO_X2, INFO_Y1+110 );
1254
1255 font_san.put_paragraph( INFO_X1+7, INFO_Y1+8, INFO_X2-7, INFO_Y2-5, headingStr );
1256
1257 int i, loyaltyLevel, y=INFO_Y1+114;
1258
1259 for( i=0, loyaltyLevel=30 ; i<BUTTON_LOYALTY_COUNT ; loyaltyLevel+=10, i++, y+=20 )
1260 button_loyalty_array[i].paint_text( INFO_X1, y, INFO_X2, y+18, misc.format(loyaltyLevel), 0, loyaltyLevel==curAutoLoyalty );
1261
1262 button_loyalty_disabled.paint_text( INFO_X1, y, INFO_X2, y+18, _("Disabled"), 0, curAutoLoyalty==0 );
1263 y+=20;
1264
1265 button_cancel2.paint_text( INFO_X1, y, INFO_X2, y+18, _("Cancel") );
1266 }
1267 //----------- End of function Town::disp_auto_menu -----------//
1268
1269
1270 //--------- Begin of function Town::detect_auto_menu ---------//
1271 //
detect_auto_menu(int modeCollectTax)1272 int Town::detect_auto_menu(int modeCollectTax)
1273 {
1274 int i, rc=0, loyaltyLevel;
1275
1276 for( i=0, loyaltyLevel=30 ; i<BUTTON_LOYALTY_COUNT ; loyaltyLevel+=10, i++ )
1277 {
1278 rc = button_loyalty_array[i].detect(0, 0, 1);
1279
1280 if( rc )
1281 break;
1282 }
1283
1284 if( !rc )
1285 {
1286 rc = button_loyalty_disabled.detect(0, 0, 1);
1287 loyaltyLevel = 0;
1288 }
1289
1290 //------ set new settings now -------//
1291
1292 if( rc==1 )
1293 {
1294 if( modeCollectTax )
1295 {
1296 if( !remote.is_enable() )
1297 {
1298 set_auto_collect_tax_loyalty(loyaltyLevel);
1299 }
1300 else
1301 {
1302 // packet structure <town recno> <loyalty level>
1303 short *shortPtr = (short *)remote.new_send_queue_msg(MSG_TOWN_AUTO_TAX, 2*sizeof(short) );
1304 *shortPtr = town_recno;
1305 shortPtr[1] = loyaltyLevel;
1306 }
1307 }
1308 else
1309 {
1310 if( !remote.is_enable() )
1311 {
1312 set_auto_grant_loyalty(loyaltyLevel);
1313 }
1314 else
1315 {
1316 // packet structure <town recno> <loyalty level>
1317 short *shortPtr = (short *)remote.new_send_queue_msg(MSG_TOWN_AUTO_GRANT, 2*sizeof(short) );
1318 *shortPtr = town_recno;
1319 shortPtr[1] = loyaltyLevel;
1320 }
1321 }
1322 }
1323 else if( rc==2 )
1324 {
1325 // ####### begin Gilbert 11/9 ########//
1326 //----- set the national policy -----//
1327 if( !remote.is_enable() )
1328 {
1329 Nation* nationPtr = nation_array[nation_recno];
1330
1331 if( modeCollectTax )
1332 nationPtr->set_auto_collect_tax_loyalty(loyaltyLevel);
1333 else
1334 nationPtr->set_auto_grant_loyalty(loyaltyLevel);
1335
1336 //----- update individual towns -----//
1337
1338 Town* townPtr;
1339
1340 for( i=town_array.size() ; i>0 ; i-- )
1341 {
1342 if( town_array.is_deleted(i) )
1343 continue;
1344
1345 townPtr = town_array[i];
1346 if( townPtr->nation_recno == nation_recno )
1347 {
1348 if( modeCollectTax )
1349 townPtr->set_auto_collect_tax_loyalty(loyaltyLevel);
1350 else
1351 townPtr->set_auto_grant_loyalty(loyaltyLevel);
1352 }
1353 }
1354 }
1355 else
1356 {
1357 err_when(!nation_recno);
1358 if( modeCollectTax )
1359 {
1360 // packet structure <-nation recno> <loyalty level>
1361 short *shortPtr = (short *)remote.new_send_queue_msg(MSG_TOWN_AUTO_TAX, 2*sizeof(short) );
1362 *shortPtr = -nation_recno;
1363 shortPtr[1] = loyaltyLevel;
1364 }
1365 else
1366 {
1367 // packet structure <-nation recno> <loyalty level>
1368 short *shortPtr = (short *)remote.new_send_queue_msg(MSG_TOWN_AUTO_GRANT, 2*sizeof(short) );
1369 *shortPtr = -nation_recno;
1370 shortPtr[1] = loyaltyLevel;
1371 }
1372 }
1373 // ####### end Gilbert 11/9 ########//
1374 }
1375
1376 //--------------------------------------//
1377
1378 if( button_cancel2.detect() || rc )
1379 {
1380 // ##### begin Gilbert 26/9 ########//
1381 se_ctrl.immediate_sound("TURN_OFF");
1382 // ##### begin Gilbert 26/9 ########//
1383 town_menu_mode = TOWN_MENU_MAIN;
1384 info.disp();
1385 return 1;
1386 }
1387
1388 return 0;
1389 }
1390 //----------- End of function Town::detect_auto_menu -----------//
1391
1392
1393 //--------- Begin of function Town::disp_spy_menu ---------//
1394 //
disp_spy_menu(int refreshFlag)1395 void Town::disp_spy_menu(int refreshFlag)
1396 {
1397 disp_basic_info(refreshFlag);
1398
1399 //---------- paint controls -----------//
1400
1401 if( refreshFlag == INFO_REPAINT )
1402 {
1403 spy_count = spy_filter();
1404
1405 //------ display browser field description -------//
1406
1407 int x=RACE_BROWSE_X1+2;
1408 int y=RACE_BROWSE_Y1-23;
1409
1410 vga_util.d3_panel_up( RACE_BROWSE_X1, y, RACE_BROWSE_X2, RACE_BROWSE_Y1-3 );
1411
1412 font_san.put( x+4 , y+4, _("Spy Skill") );
1413 font_san.put( x+70 , y+4, _("Loyalty") );
1414 font_san.put( x+130, y+4, _("Action") );
1415
1416 //------------ create browser ------------//
1417
1418 browse_spy.init( RACE_BROWSE_X1, RACE_BROWSE_Y1, RACE_BROWSE_X2, RACE_BROWSE_Y2,
1419 0, 25, spy_count, put_spy_rec );
1420
1421 browse_spy.open(1);
1422 }
1423 else
1424 {
1425 //---------- update controls -----------//
1426
1427 if( spy_count != spy_filter() )
1428 {
1429 spy_count = spy_filter();
1430
1431 if( spy_count>0 )
1432 {
1433 disable_refresh = 1; // stay in the spy menu mode if disable_refresh is 1
1434 info.disp();
1435 disable_refresh = 0;
1436 }
1437 else
1438 info.disp(); // reset to the main menu mode if disable_refresh is 0
1439
1440 return;
1441 }
1442 else
1443 browse_spy.update();
1444 }
1445
1446 //----------- create the paint button ----------//
1447
1448 if( refreshFlag == INFO_REPAINT )
1449 {
1450 int x=BUTTON_X1, y=RACE_BROWSE_Y2+5;
1451
1452 button_spy_mobilize.paint( x, y, 'A', "MOBILSPY" );
1453 x+=BUTTON_ACTION_WIDTH;
1454
1455 //--------- reward spy button --------//
1456
1457 button_spy_reward.paint( x, y, 'A', "REWARD" );
1458 x+=BUTTON_ACTION_WIDTH;
1459
1460 if( nation_recno != nation_array.player_recno ) // if the spy is in another nation's town
1461 {
1462 button_spy_action.paint( x, y, 'A', "SPYCHACT" );
1463 x+=BUTTON_ACTION_WIDTH;
1464 }
1465
1466 if( nation_recno && nation_recno != nation_array.player_recno )
1467 {
1468 button_spy_view_secret.paint( x, y, 'A', "VSECRET" );
1469 x+=BUTTON_ACTION_WIDTH;
1470
1471 if( x+BUTTON_ACTION_WIDTH-5 > INFO_X2 )
1472 {
1473 x = BUTTON_X1;
1474 y += BUTTON_ACTION_HEIGHT;
1475 }
1476 }
1477
1478 button_cancel.paint( x, y, 'A', "PREVMENU" );
1479 }
1480 }
1481 //----------- End of function Town::disp_spy_menu -----------//
1482
1483
1484 //--------- Begin of function Town::detect_spy_menu ---------//
1485 //
detect_spy_menu()1486 int Town::detect_spy_menu()
1487 {
1488 browse_spy.detect();
1489
1490 Spy* spyPtr = spy_array[ spy_filter( browse_spy.recno() ) ];
1491
1492 //------- mobilize spy --------//
1493
1494 if( button_spy_mobilize.detect() )
1495 {
1496 if( !remote.is_enable() )
1497 {
1498 if( spyPtr->mobilize_town_spy() )
1499 {
1500 spyPtr->notify_cloaked_nation_flag = 0; // reset it so the player can control it
1501 disp_spy_menu( INFO_UPDATE );
1502 }
1503 }
1504 else
1505 {
1506 // packet structure <spy recno>
1507 short *shortPtr = (short *)remote.new_send_queue_msg(MSG_SPY_LEAVE_TOWN, sizeof(short) );
1508 *shortPtr = spyPtr->spy_recno;
1509 }
1510 return 1;
1511 }
1512
1513 //------ reward spy ---------//
1514
1515 else if( button_spy_reward.detect() )
1516 {
1517 spyPtr->reward(COMMAND_PLAYER);
1518 return 1;
1519 }
1520
1521 //----- change spy action --------//
1522
1523 if( nation_recno != nation_array.player_recno ) // if the spy is in another nation's town
1524 {
1525 if( button_spy_action.detect() ) // set action mode
1526 {
1527 if( !remote.is_enable() )
1528 {
1529 spyPtr->set_next_action_mode();
1530 disp_spy_menu( INFO_UPDATE );
1531 }
1532 else
1533 {
1534 // packet structure <spy recno>
1535 short *shortPtr = (short *)remote.new_send_queue_msg(MSG_SPY_CYCLE_ACTION, sizeof(short) );
1536 *shortPtr = spyPtr->spy_recno;
1537 }
1538 return 1;
1539 }
1540 }
1541
1542 //----- view secret report ------/
1543
1544 if( nation_recno && nation_recno != nation_array.player_recno )
1545 {
1546 if( button_spy_view_secret.detect() )
1547 {
1548 action_spy_recno = spyPtr->spy_recno;
1549 town_menu_mode = TOWN_MENU_VIEW_SECRET;
1550 disable_refresh = 1;
1551 info.disp();
1552 disable_refresh = 0;
1553 return 1;
1554 }
1555 }
1556
1557 //--------- cancel -----------//
1558
1559 if( button_cancel.detect() || mouse.any_click(1) ) // right click to cancel
1560 {
1561 info.disp();
1562 return 1;
1563 }
1564
1565 return 0;
1566 }
1567 //----------- End of function Town::detect_spy_menu -----------//
1568
1569
1570 //--------- Begin of function Town::has_player_spy ---------//
1571 //
1572 // Whether this town has any player spies.
1573 //
has_player_spy()1574 int Town::has_player_spy()
1575 {
1576 int i;
1577 for( i=0 ; i<MAX_RACE ; i++ )
1578 {
1579 if( race_spy_count_array[i] > 0 )
1580 break;
1581 }
1582
1583 if( i==MAX_RACE ) // no spies in this nation
1584 return 0;
1585
1586 //----- look for player spy in the spy_array -----//
1587
1588 Spy* spyPtr;
1589
1590 for( i=spy_array.size() ; i>=1 ; i-- )
1591 {
1592 if( spy_array.is_deleted(i) )
1593 continue;
1594
1595 spyPtr = spy_array[i];
1596
1597 if( spyPtr->spy_place==SPY_TOWN &&
1598 spyPtr->spy_place_para==town_recno &&
1599 spyPtr->true_nation_recno==nation_array.player_recno )
1600 {
1601 return 1;
1602 }
1603 }
1604
1605 return 0;
1606 }
1607 //----------- End of function Town::has_player_spy -----------//
1608
1609
1610 //--------- Begin of function spy_filter ---------//
1611 //
spy_filter(int recNo)1612 static int spy_filter(int recNo)
1613 {
1614 Spy* spyPtr;
1615 int recCount=0;
1616
1617 for( int i=spy_array.size() ; i>=1 ; i-- )
1618 {
1619 if( spy_array.is_deleted(i) )
1620 continue;
1621
1622 spyPtr = spy_array[i];
1623
1624 if( spyPtr->spy_place==SPY_TOWN &&
1625 spyPtr->spy_place_para==Town::if_town_recno &&
1626 spyPtr->true_nation_recno==nation_array.player_recno )
1627 {
1628 recCount++;
1629 }
1630
1631 if( recNo && recCount==recNo )
1632 return i;
1633 }
1634
1635 err_when( recNo );
1636
1637 return recCount;
1638 }
1639 //----------- End of function spy_filter -----------//
1640
1641
1642 //-------- Begin of static function put_spy_rec --------//
1643 //
put_spy_rec(int recNo,int x,int y,int refreshFlag)1644 static void put_spy_rec(int recNo, int x, int y, int refreshFlag)
1645 {
1646 int x2 = x+browse_spy.rec_width-1;
1647
1648 //-------- display icon of the spy unit -----//
1649
1650 Spy* spyPtr = spy_array[ spy_filter(recNo) ];
1651
1652 if( refreshFlag == INFO_REPAINT )
1653 {
1654 vga_util.d3_panel_down(x+1, y+1, x+RACE_ICON_WIDTH+4, y+RACE_ICON_HEIGHT+4 );
1655 vga_front.put_bitmap(x+3, y+3, race_res[spyPtr->race_id]->icon_bitmap_ptr);
1656 }
1657
1658 //--------- set help parameters --------//
1659
1660 if( mouse.in_area(x+1, y+1, x+RACE_ICON_WIDTH+4, y+RACE_ICON_HEIGHT+4) )
1661 {
1662 int unitId = race_res[spyPtr->race_id]->basic_unit_id;
1663
1664 help.set_unit_help( unitId, 0, x+1, y+1, x+RACE_ICON_WIDTH+4, y+RACE_ICON_HEIGHT+4 );
1665 }
1666
1667 //-------- display spy skill -------//
1668
1669 font_san.put( x+40, y+6, spyPtr->spy_skill, 1, x+66 );
1670
1671 //-------- display spy loyalty -------//
1672
1673 font_san.put( x+67, y+6, spyPtr->spy_loyalty, 1, x+94 );
1674
1675 //------ display the action mode of the spy ------//
1676
1677 vga_util.blt_buf( x+95, y+6, x2, y+5+font_san.height(), 0 );
1678
1679 font_san.center_put( x+95, y+6, x2, y+5+font_san.height(), spyPtr->action_str() );
1680 }
1681 //----------- End of static function put_spy_rec -----------//
1682
1683
1684 //--------- Begin of function Town::recruit ---------//
1685 //
1686 // <int> trainSkillId = -1 - non-trained unit
1687 // >=1 - skill id. of the unit to be trained.
1688 //
1689 // [int] raceId = the race id. of the unit to be recruited
1690 // (default: the currently selected race)
1691 //
1692 // return: <int> recno of the recruited unit
1693 //
recruit(int trainSkillId,int raceId,char remoteAction)1694 int Town::recruit(int trainSkillId, int raceId, char remoteAction)
1695 {
1696 //---- we can't train a new one when there is one currently under training ---//
1697
1698 if( trainSkillId >= 1 && train_unit_recno )
1699 return 0;
1700
1701 //--------------------------------------------//
1702
1703 if( !raceId )
1704 {
1705 if( browse_race.recno() > race_filter() )
1706 return 0;
1707
1708 raceId = race_filter(browse_race.recno());
1709 }
1710
1711 if( !remoteAction && remote.is_enable() )
1712 {
1713 // packet structure : <town recno> <skill id> <race id>
1714 short *shortPtr = (short *)remote.new_send_queue_msg(MSG_TOWN_RECRUIT, 3*sizeof(short));
1715 shortPtr[0] = town_recno;
1716 shortPtr[1] = trainSkillId;
1717 shortPtr[2] = raceId;
1718 return 0;
1719 }
1720
1721 //---- check if there are units of the race ready for training ----//
1722
1723 int recruitableCount = recruitable_race_pop(raceId, 1);
1724
1725 if( recruitableCount == 0 )
1726 return 0;
1727
1728 err_when( recruitableCount < 0 ); // 1-allow recruiting spies
1729
1730 //-------- create an unit ------//
1731
1732 int townRecno = town_recno;
1733 int nationRecno = nation_recno; // save this town's info that is needed as promote_pop() will delete Town if all population of the town are promoted
1734
1735 //--- if there are spies in this town, chances are that they will be mobilized ---//
1736
1737 int shouldTrainSpy = race_spy_count_array[raceId-1] >= misc.random(recruitableCount)+1; // 1-allow recruiting spies
1738
1739 //---- if we are trying to train an enemy to our spy, then... -----//
1740
1741 if( shouldTrainSpy && trainSkillId == SKILL_SPYING )
1742 {
1743 //-- if there are other non-spy units in the town, then train the other and don't train the spy --//
1744
1745 if( recruitableCount > race_spy_count_array[raceId-1] )
1746 {
1747 shouldTrainSpy = 0;
1748 }
1749 //--- if all remaining units are spies, when you try to train one, all of them will become mobilized ---//
1750
1751 else
1752 {
1753 int spyRecno = spy_array.find_town_spy(town_recno, raceId, 1);
1754
1755 err_when( !spyRecno );
1756
1757 Spy* spyPtr = spy_array[spyRecno];
1758
1759 if( !spyPtr->mobilize_town_spy() )
1760 return 0;
1761
1762 spyPtr->change_cloaked_nation( spyPtr->true_nation_recno );
1763
1764 return 0;
1765 }
1766 }
1767
1768 //------- if we should train a spy --------//
1769
1770 int unitRecno=0;
1771
1772 if( shouldTrainSpy )
1773 {
1774 int spyCount = spy_array.size();
1775 int spyRecno = misc.random(spyCount)+1;
1776 Spy* spyPtr;
1777
1778 //-----------------------------------------------------//
1779 // Spies from other nations will first be mobilized,
1780 // when all peasants and spies are mobilized and
1781 // the only ones left in the town are spies from our
1782 // nation, then mobilize them finally.
1783 //-----------------------------------------------------//
1784
1785 for( int mobileNationType=1 ; unitRecno==0 && mobileNationType<=2 ; mobileNationType++ )
1786 {
1787 if( mobileNationType==2 ) // only mobilize our own spies are there are the only ones in the town
1788 {
1789 if( recruitable_race_pop(raceId,1) > race_spy_count_array[raceId-1] ) // 1-allow recruiting spies
1790 break;
1791 }
1792
1793 for( int i=0 ; i<spyCount ; i++ )
1794 {
1795 if( ++spyRecno > spyCount )
1796 spyRecno = 1;
1797
1798 if( spy_array.is_deleted(spyRecno) )
1799 continue;
1800
1801 spyPtr = spy_array[spyRecno];
1802
1803 if( spyPtr->spy_place == SPY_TOWN
1804 && spyPtr->spy_place_para == town_recno
1805 // ##### patch begin Gilbert 9/4 ######//
1806 && spyPtr->race_id == raceId
1807 // ##### patch end Gilbert 9/4 ######//
1808 )
1809 {
1810 if( mobileNationType==1 ) // only mobilize spies from other nations, don't mobilize spies of our own nation
1811 {
1812 if( spyPtr->true_nation_recno == nation_recno )
1813 continue;
1814 }
1815
1816 unitRecno = spyPtr->mobilize_town_spy(trainSkillId== -1); // the parameter is whether decreasing the population immediately, if decrease immediately in recruit mode, not in training mode, 1-mobilize spies
1817 break;
1818 }
1819 }
1820 }
1821 }
1822
1823 //-------- mobilize normal peasant units -------//
1824
1825 if( !unitRecno )
1826 unitRecno = mobilize_town_people(raceId, trainSkillId== -1, 0 ); // the 2nd parameter is whether decreasing the population immediately, if decrease immediately in recruit mode, not in training mode, 2nd para 0-don't mobilize spies
1827
1828 if( !unitRecno )
1829 return 0;
1830
1831 err_when(unitRecno<=0 || unit_array.is_deleted(unitRecno));
1832
1833 if( !unitRecno )
1834 return 0;
1835
1836 Unit* unitPtr = unit_array[unitRecno];
1837
1838 //-------- training skill -----------//
1839
1840 if( trainSkillId > 0 )
1841 {
1842 if( trainSkillId == SKILL_SPYING )
1843 {
1844 unitPtr->spy_recno = spy_array.add_spy(unitRecno, TRAIN_SKILL_LEVEL);
1845 }
1846 else
1847 {
1848 if( trainSkillId == SKILL_LEADING ) // also increase the combat level for leadership skill training
1849 unitPtr->set_combat_level(TRAIN_SKILL_LEVEL);
1850
1851 unitPtr->skill.skill_id = trainSkillId;
1852 unitPtr->skill.skill_level = TRAIN_SKILL_LEVEL;
1853 }
1854
1855 nation_array[nationRecno]->add_expense( EXPENSE_TRAIN_UNIT, (float) TRAIN_SKILL_COST );
1856 }
1857 else
1858 {
1859 //------ recruitment without training decreases loyalty --------//
1860
1861 recruit_dec_loyalty(raceId);
1862
1863 if( unitPtr->is_own() )
1864 {
1865 se_res.far_sound(unitPtr->cur_x_loc(), unitPtr->cur_y_loc(), 1,
1866 'S', unitPtr->sprite_id, "RDY" );
1867 }
1868 }
1869
1870 //---- training solider or skilled unit takes time ----//
1871
1872 if( trainSkillId >= 0 )
1873 {
1874 err_when(unitRecno<=0 || unit_array.is_deleted(unitRecno));
1875
1876 err_when( train_unit_recno ); // if there is already a unit under training
1877
1878 train_unit_recno = unitRecno;
1879 start_train_frame_no = sys.frame_count; // as an offset for displaying the progress bar correctly
1880
1881 unitPtr->deinit_sprite();
1882 unitPtr->unit_mode = UNIT_MODE_UNDER_TRAINING;
1883 unitPtr->unit_mode_para = town_recno;
1884 }
1885
1886 //--- mobilize_pop() will delete the current Town if population goes down to 0 ---//
1887
1888 if( town_recno == town_array.selected_recno )
1889 {
1890 if( town_array.is_deleted(townRecno) )
1891 info.disp();
1892 }
1893
1894 return unitRecno;
1895 }
1896 //----------- End of function Town::recruit -----------//
1897
1898
1899 //--------- Begin of function Town::recruit_dec_loyalty ---------//
1900 //
1901 // Decrease loyalty when an unit is recruited.
1902 // This function is called by recruit() and Firm::pull_town_people()
1903 //
1904 // <int> raceId - the race to be recruited
1905 // <int> decNow - decrease now, if it is 0, just return the
1906 // loyalty to be decreased without actual decreasing.
1907 // (default: 1)
1908 //
1909 // return: <int> - the loyalty decreased or to be decreased.
1910 //
recruit_dec_loyalty(int raceId,int decNow)1911 int Town::recruit_dec_loyalty(int raceId, int decNow)
1912 {
1913 float loyaltyDec = MIN( 5, (float) MAX_TOWN_POPULATION / race_pop_array[raceId-1] );
1914
1915 //------ recruitment without training decreases loyalty --------//
1916
1917 if( decNow )
1918 {
1919 loyaltyDec += accumulated_recruit_penalty/5;
1920
1921 loyaltyDec = MIN(loyaltyDec, 10);
1922
1923 accumulated_recruit_penalty += 5;
1924
1925 //-------------------------------------//
1926
1927 race_loyalty_array[raceId-1] -= loyaltyDec;
1928
1929 if( race_loyalty_array[raceId-1] < 0 )
1930 race_loyalty_array[raceId-1] = (float) 0;
1931 }
1932
1933 return (int) loyaltyDec;
1934 }
1935 //----------- End of function Town::recruit_dec_loyalty -----------//
1936
1937
1938 //--------- Begin of function Town::process_train ---------//
process_train()1939 void Town::process_train()
1940 {
1941 err_when( !train_unit_recno );
1942
1943 Unit* unitPtr = unit_array[train_unit_recno];
1944 int raceId = unitPtr->race_id;
1945
1946 //---- if the unit being trained was killed -----//
1947
1948 int cancelFlag = 0;
1949
1950 err_when( jobless_race_pop_array[raceId-1] < 0 );
1951
1952 if( jobless_race_pop_array[raceId-1]==0 ) // the unit being trained was killed
1953 {
1954 cancelFlag = 1;
1955 }
1956
1957 //-----------------------------------------------------------------//
1958 //
1959 // If after start training the unit (non-spy unit), a unit has been
1960 // mobilized, resulting that the spy count >= jobless_race,
1961 // we must cancel the training, otherwise when training finishes,
1962 // and dec_pop is called, spy count will > jobless count and cause error.
1963 //
1964 //-----------------------------------------------------------------//
1965
1966 err_when( race_spy_count_array[raceId-1] > jobless_race_pop_array[raceId-1] );
1967
1968 if( race_spy_count_array[raceId-1] == jobless_race_pop_array[raceId-1] )
1969 cancelFlag = 1;
1970
1971 if( cancelFlag )
1972 {
1973 unit_array.disappear_in_town(train_unit_recno, town_recno);
1974 train_unit_recno = 0;
1975 return;
1976 }
1977
1978 //------------- process training ---------------//
1979
1980 int totalDays;
1981
1982 if( config.fast_build && nation_recno==nation_array.player_recno )
1983 totalDays = TOTAL_TRAIN_DAYS/2;
1984 else
1985 totalDays = TOTAL_TRAIN_DAYS;
1986
1987 if( (int)(sys.frame_count-start_train_frame_no) / FRAMES_PER_DAY >= totalDays )
1988 {
1989 finish_train(unitPtr);
1990 }
1991 }
1992 //----------- End of function Town::process_train -----------//
1993
1994
1995 //--------- Begin of function Town::finish_train ---------//
1996
finish_train(Unit * unitPtr)1997 void Town::finish_train(Unit* unitPtr)
1998 {
1999 err_when(train_unit_recno<=0 || unit_array.is_deleted(train_unit_recno));
2000 SpriteInfo* spriteInfo = unitPtr->sprite_info;
2001 int xLoc=loc_x1; // xLoc & yLoc are used for returning results
2002 int yLoc=loc_y1;
2003
2004 if( !world.locate_space(&xLoc, &yLoc, loc_x2, loc_y2, spriteInfo->loc_width, spriteInfo->loc_height) )
2005 return;
2006
2007 unitPtr->init_sprite(xLoc, yLoc);
2008
2009 if( unitPtr->is_own() )
2010 se_res.far_sound( xLoc, yLoc, 1, 'S', unitPtr->sprite_id, "RDY");
2011
2012 unitPtr->unit_mode = 0; // reset it to 0 from UNIT_MODE_UNDER_TRAINING
2013 train_unit_recno = 0;
2014
2015 int townRecno = town_recno; // save the recno as it can be deleted in dec_pop()
2016
2017 dec_pop(unitPtr->race_id, 0); // decrease the population now as the recruit() does do so
2018
2019 //---- if this trained unit is tied to an AI action ----//
2020
2021 if( train_unit_action_id )
2022 {
2023 nation_array[nation_recno]->process_action_id(train_unit_action_id);
2024 train_unit_action_id = 0;
2025 }
2026
2027 //----- refresh if this town is currently selected ------//
2028
2029 if(townRecno==town_array.selected_recno)
2030 {
2031 if(town_menu_mode==TOWN_MENU_MAIN)
2032 {
2033 info.disp();
2034 }
2035 else
2036 {
2037 disable_refresh = 1;
2038 info.disp();
2039 disable_refresh = 0;
2040 }
2041 }
2042 }
2043 //----------- End of function Town::finish_train -----------//
2044
2045
2046 //--------- Begin of function Town::process_queue ---------//
process_queue()2047 void Town::process_queue()
2048 {
2049 if(train_queue_count==0)
2050 return;
2051
2052 if(jobless_population==0)
2053 return;
2054
2055 err_when(train_queue_count > MAX_TRAIN_QUEUE);
2056
2057 char queueCount = train_queue_count;
2058 char skillId, raceId;
2059 char i;
2060 for(i=0; i<queueCount; ++i)
2061 {
2062 if(can_train(train_queue_race_array[i]))
2063 {
2064 skillId = train_queue_skill_array[i];
2065 raceId = train_queue_race_array[i];
2066 err_when(train_queue_count-i-1 < 0 || train_queue_count-i-1 > MAX_TRAIN_QUEUE);
2067 memmove(train_queue_skill_array, train_queue_skill_array+i+1,
2068 sizeof(train_queue_skill_array[0])*(train_queue_count-i-1));
2069 memmove(train_queue_race_array, train_queue_race_array+i+1,
2070 sizeof(train_queue_race_array[0])*(train_queue_count-i-1));
2071 train_queue_count -= i+1;
2072 recruit(skillId, raceId, COMMAND_AUTO);
2073 break;
2074 }
2075 }
2076
2077 if(i==queueCount)
2078 train_queue_count = 0;
2079
2080 if(town_menu_mode==TOWN_MENU_MAIN)
2081 info.disp();
2082 }
2083 //----------- End of function Town::process_queue -----------//
2084
2085
2086 //--------- Begin of function Town::add_queue ---------//
add_queue(char skillId,char raceId,int amount)2087 void Town::add_queue(char skillId, char raceId, int amount)
2088 {
2089 err_when(amount < 0);
2090 if (amount < 0) return;
2091
2092 int queueSpace = MAX_TRAIN_QUEUE - train_queue_count - (train_unit_recno>0);
2093 int enqueueAmount = MIN(queueSpace, amount);
2094
2095 for (int i = 0; i < enqueueAmount; ++i)
2096 {
2097 train_queue_skill_array[train_queue_count] = skillId;
2098 train_queue_race_array[train_queue_count++] = raceId;
2099 }
2100
2101 if( !train_unit_recno )
2102 process_queue();
2103 }
2104 //----------- End of function Town::add_queue -----------//
2105
2106
2107 //--------- Begin of function Town::remove_queue ---------//
remove_queue(char skillId,int amount)2108 void Town::remove_queue(char skillId, int amount)
2109 {
2110 err_when(amount < 1);
2111 if (amount < 1) return;
2112
2113 for(int i=train_queue_count-1; i>=0; i--)
2114 {
2115 if(train_queue_skill_array[i] == skillId)
2116 {
2117 err_when(train_queue_count > MAX_TRAIN_QUEUE);
2118
2119 misc.del_array_rec(train_queue_skill_array, train_queue_count, sizeof(train_queue_skill_array[0]), i+1);
2120 misc.del_array_rec(train_queue_race_array, train_queue_count, sizeof(train_queue_race_array[0]), i+1);
2121 train_queue_count--;
2122 amount--;
2123
2124 if (amount <= 0) return;
2125 }
2126 }
2127
2128 // If there were less trained of skillId in the queue than were requested to be removed then
2129 // also cancel currently trained unit
2130 if(train_unit_recno)
2131 {
2132 Unit *unitPtr = unit_array[train_unit_recno];
2133 if((unitPtr->skill).skill_id==skillId)
2134 cancel_train_unit();
2135 }
2136 }
2137 //----------- End of function Town::remove_queue -----------//
2138
2139
2140 //--------- Begin of function Town::disp_debug_resistance ---------//
2141 //
disp_debug_resistance(int refreshFlag)2142 void Town::disp_debug_resistance(int refreshFlag)
2143 {
2144 if( nation_recno == nation_array.player_recno ) // not for player's own town
2145 return;
2146
2147 if( refreshFlag==INFO_REPAINT )
2148 vga_util.d3_panel_up( INFO_X1, INFO_Y2-50, INFO_X2, INFO_Y2 );
2149
2150 //------ display resistance (only for independent town) -----//
2151
2152 int x=INFO_X1+10, y=INFO_Y2-47;
2153
2154 if( nation_recno ==0 )
2155 {
2156 int raceId = race_filter(browse_race.recno());
2157
2158 for( int i=1 ; i<=nation_array.size() ; i++, x+=28 )
2159 {
2160 if( nation_array.is_deleted(i) )
2161 continue;
2162
2163 if( refreshFlag==INFO_REPAINT )
2164 vga_front.bar( x, y, x+18, y+16, nation_array[i]->nation_color );
2165
2166 font_san.put( x, y+18, (int) race_resistance_array[raceId-1][i-1], 1, x+19 );
2167 font_san.put( x, y+32, (int) race_target_resistance_array[raceId-1][i-1], 1, x+19 );
2168 }
2169 }
2170 else
2171 {
2172 //------ if this town is the nation's base town -----//
2173
2174 String str;
2175
2176 str = "Base: ";
2177 str += is_base_town;
2178
2179 font_san.put( INFO_X1+10, y, str );
2180
2181 str = "Town recno: ";
2182 str += town_recno;
2183
2184 font_san.put( INFO_X1+70, y, str );
2185
2186 str = "no_neighbor_space: ";
2187 str += no_neighbor_space;
2188
2189 font_san.put( INFO_X1+10, y+16, str );
2190
2191 str = "quality of life: ";
2192 str += quality_of_life;
2193
2194 font_san.disp( INFO_X1+10, y+32, str, INFO_X2-10 );
2195 }
2196 }
2197 //----------- End of function Town::disp_debug_resistance -----------//
2198
2199
2200 //--------- Begin of function Town::get_elected_race ---------//
get_selected_race()2201 int Town::get_selected_race()
2202 {
2203 if(browse_race.recno() > race_filter())
2204 return 0;
2205
2206 return race_filter(browse_race.recno());
2207 }
2208 //----------- End of function Town::get_elected_race -----------//
2209