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 : OF_CAMP.CPP
22 //Description : Firm Military Camp
23
24 #include <OINFO.h>
25 #include <OVGA.h>
26 #include <vga_util.h>
27 #include <ODATE.h>
28 #include <OIMGRES.h>
29 #include <OHELP.h>
30 #include <OSYS.h>
31 #include <OSTR.h>
32 #include <OFONT.h>
33 #include <OMOUSE.h>
34 #include <OBUTTON.h>
35 #include <OBUTT3D.h>
36 #include <OPOWER.h>
37 #include <OUNIT.h>
38 #include <OINFO.h>
39 #include <OGAME.h>
40 #include <OSPY.h>
41 #include <ONATION.h>
42 #include <ORACERES.h>
43 #include <OTERRAIN.h>
44 #include <OWORLD.h>
45 #include <OF_CAMP.h>
46 #include <OREMOTE.h>
47 #include <OSERES.h>
48 #include <OSE.h>
49 #include "gettext.h"
50
51
52 //----------- Define static vars -------------//
53
54 static Button3D button_patrol, button_reward, button_defense;
55
56 //--------- Declare static functions ---------//
57
58 static void disp_debug_info(FirmCamp* firmPtr, int refreshFlag);
59
60 //--------- Begin of function FirmCamp::FirmCamp ---------//
61 //
FirmCamp()62 FirmCamp::FirmCamp()
63 {
64 firm_skill_id = SKILL_LEADING;
65
66 employ_new_worker = 1;
67
68 memset(defense_array, 0, sizeof(DefenseUnit)*(MAX_WORKER+1));
69
70 defend_target_recno = 0;
71 defense_flag = 1;
72
73 is_attack_camp = 0;
74 }
75 //----------- End of function FirmCamp::FirmCamp -----------//
76
77
78 //--------- Begin of function FirmCamp::deinit ---------//
79 //
deinit()80 void FirmCamp::deinit()
81 {
82 int firmRecno = firm_recno; // save the firm_recno first for reset_unit_home_camp()
83
84 Firm::deinit();
85
86 //-------------------------------------------//
87
88 int saveOverseerRecno = overseer_recno;
89
90 overseer_recno = 0; // set overseer_recno to 0 when calling update_influence(), so this base is disregarded.
91
92 update_influence();
93
94 overseer_recno = saveOverseerRecno;
95
96 clear_defense_mode();
97
98 //---- reset all units whose home_camp_firm_recno is this firm ----//
99
100 reset_unit_home_camp(firmRecno); // this must be called at last as Firm::deinit() will create new units.
101
102 //--- if this camp is in the Nation::attack_camp_array[], remove it now ---//
103
104 reset_attack_camp(firmRecno);
105 }
106 //----------- End of function FirmCamp::deinit -----------//
107
108
109 //--------- Begin of function FirmCamp::reset_unit_home_camp ---------//
110 //
reset_unit_home_camp(int firmRecno)111 void FirmCamp::reset_unit_home_camp(int firmRecno)
112 {
113 //---- reset all units whose home_camp_firm_recno is this firm ----//
114
115 Unit* unitPtr;
116
117 for( int i=unit_array.size() ; i>0 ; i-- )
118 {
119 if( unit_array.is_deleted(i) )
120 continue;
121
122 unitPtr = unit_array[i];
123
124 if( unitPtr->home_camp_firm_recno == firmRecno )
125 unitPtr->home_camp_firm_recno = 0;
126 }
127 }
128 //----------- End of function FirmCamp::reset_unit_home_camp -----------//
129
130
131 //--------- Begin of function FirmCamp::reset_attack_camp ---------//
132 //
reset_attack_camp(int firmRecno)133 void FirmCamp::reset_attack_camp(int firmRecno)
134 {
135 //--- if this camp is in the Nation::attack_camp_array[], remove it now ---//
136
137 if( firm_ai )
138 {
139 Nation* nationPtr = nation_array[nation_recno];
140
141 for( int i=0 ; i<nationPtr->attack_camp_count ; i++ )
142 {
143 if( nationPtr->attack_camp_array[i].firm_recno == firmRecno )
144 {
145 misc.del_array_rec(nationPtr->attack_camp_array, nationPtr->attack_camp_count, sizeof(AttackCamp), i+1 );
146 nationPtr->attack_camp_count--;
147 break;
148 }
149 }
150 }
151 }
152 //----------- End of function FirmCamp::reset_attack_camp -----------//
153
154
155 //--------- Begin of function FirmCamp::clear_defense_mode ---------//
clear_defense_mode()156 void FirmCamp::clear_defense_mode()
157 {
158 //------------------------------------------------------------------//
159 // change defense unit's to non-defense mode
160 //------------------------------------------------------------------//
161 Unit *unitPtr;
162 for(int i=unit_array.size(); i>=1; --i)
163 {
164 if(unit_array.is_deleted(i))
165 continue;
166
167 unitPtr = unit_array[i];
168 if(!unitPtr)
169 continue;
170
171 err_when(unitPtr->cur_action==SPRITE_DIE || unitPtr->action_mode==ACTION_DIE || unitPtr->hit_points<=0);
172 if(unitPtr->in_auto_defense_mode() && unitPtr->action_misc==ACTION_MISC_DEFENSE_CAMP_RECNO &&
173 unitPtr->action_misc_para==firm_recno)
174 unitPtr->clear_unit_defense_mode();
175 }
176
177 memset(defense_array, 0, sizeof(DefenseUnit)*(MAX_WORKER+1));
178 }
179 //----------- End of function FirmCamp::clear_defense_mode -----------//
180
181
182 //--------- Begin of function FirmCamp::assign_unit ---------//
183 //
assign_unit(int unitRecno)184 void FirmCamp::assign_unit(int unitRecno)
185 {
186 Unit* unitPtr = unit_array[unitRecno];
187
188 //------- if this is a construction worker -------//
189
190 if( unitPtr->skill.skill_id == SKILL_CONSTRUCTION )
191 {
192 set_builder(unitRecno);
193 return;
194 }
195
196 //-------- assign the unit ----------//
197
198 int rankId = unit_array[unitRecno]->rank_id;
199
200 if( rankId == RANK_GENERAL || rankId==RANK_KING )
201 {
202 assign_overseer(unitRecno);
203 }
204 else
205 {
206 assign_worker(unitRecno);
207 }
208 }
209 //----------- End of function FirmCamp::assign_unit -----------//
210
211
212 //--------- Begin of function FirmCamp::assign_overseer ---------//
213 //
assign_overseer(int overseerRecno)214 void FirmCamp::assign_overseer(int overseerRecno)
215 {
216 //---- reset the team member count of the general ----//
217
218 if( overseerRecno )
219 {
220 Unit* unitPtr = unit_array[overseerRecno];
221
222 err_when( !unitPtr->race_id );
223 err_when( unitPtr->rank_id != RANK_GENERAL && unitPtr->rank_id != RANK_KING );
224 err_when( !unitPtr->team_info );
225
226 unitPtr->team_info->member_count = 0;
227 unitPtr->home_camp_firm_recno = 0;
228 }
229
230 //----- assign the overseer now -------//
231
232 Firm::assign_overseer(overseerRecno);
233
234 //------------- update influence -----------//
235
236 update_influence();
237 }
238 //----------- End of function FirmCamp::assign_overseer -----------//
239
240
241 //--------- Begin of function FirmCamp::assign_worker --------//
242 //
243 // Increase armed unit count of the race of the worker assigned,
244 // as when a unit is assigned to a camp, Unit::deinit() will decrease
245 // the counter, so we need to increase it back here.
246 //
assign_worker(int workerUnitRecno)247 void FirmCamp::assign_worker(int workerUnitRecno)
248 {
249 Firm::assign_worker(workerUnitRecno);
250
251 //--- remove the unit from patrol_unit_array when it returns to the base ---//
252
253 validate_patrol_unit();
254
255 //-------- sort soldiers ---------//
256
257 sort_worker();
258 }
259 //----------- End of function FirmCamp::assign_worker --------//
260
261
262 //------- Begin of function FirmCamp::validate_patrol_unit ---------//
263 //
validate_patrol_unit()264 void FirmCamp::validate_patrol_unit()
265 {
266 int unitRecno;
267 Unit* unitPtr;
268
269 err_when( patrol_unit_count > 9 );
270
271 for( int i=patrol_unit_count ; i>0 ; i-- )
272 {
273 unitRecno = patrol_unit_array[i-1];
274
275 if( unit_array.is_deleted(unitRecno) ||
276 (unitPtr=unit_array[unitRecno])->is_visible()==0 ||
277 unitPtr->nation_recno != nation_recno )
278 {
279 err_when( patrol_unit_count > 9 );
280
281 misc.del_array_rec( patrol_unit_array, patrol_unit_count, sizeof(patrol_unit_array[0]), i );
282
283 err_when( patrol_unit_count==0 ); // it's already 0
284 patrol_unit_count--;
285
286 err_when( patrol_unit_count < 0 );
287 err_when( patrol_unit_count > 9 );
288 }
289 }
290 }
291 //-------- End of function FirmCamp::validate_patrol_unit ---------//
292
293
294 //------- Begin of function FirmCamp::change_nation ---------//
295 //
change_nation(int newNationRecno)296 void FirmCamp::change_nation(int newNationRecno)
297 {
298 //--- update the UnitInfo vars of the workers in this firm ---//
299
300 for( int i=0 ; i<worker_count ; i++ )
301 unit_res[ worker_array[i].unit_id ]->unit_change_nation(newNationRecno, nation_recno, worker_array[i].rank_id );
302
303 //----- reset unit's home camp to this firm -----//
304
305 reset_unit_home_camp(firm_recno);
306
307 //--- if this camp is in the Nation::attack_camp_array[], remove it now ---//
308
309 reset_attack_camp(firm_recno);
310
311 //---- reset AI vars --------//
312
313 ai_capture_town_recno = 0;
314 ai_recruiting_soldier = 0;
315
316 //-------- change the nation of this firm now ----------//
317
318 Firm::change_nation(newNationRecno);
319 }
320 //-------- End of function FirmCamp::change_nation ---------//
321
322
323 //--------- Begin of function FirmCamp::update_influence ---------//
324 //
325 // Update this camp's influence on neighbor towns.
326 //
update_influence()327 void FirmCamp::update_influence()
328 {
329 int i;
330 Town* townPtr;
331
332 for( i=0 ; i<linked_town_count ; i++ )
333 {
334 if(town_array.is_deleted(linked_town_array[i]))
335 continue;
336
337 townPtr = town_array[linked_town_array[i]];
338
339 if( linked_town_enable_array[i] == LINK_EE )
340 {
341 if( townPtr->nation_recno )
342 townPtr->update_target_loyalty();
343 else
344 townPtr->update_target_resistance();
345 }
346 }
347 }
348 //----------- End of function FirmCamp::update_influence -----------//
349
350
351 //--------- Begin of function FirmCamp::put_info ---------//
352 //
put_info(int refreshFlag)353 void FirmCamp::put_info(int refreshFlag)
354 {
355 disp_basic_info(INFO_Y1, refreshFlag);
356
357 if( !should_show_info() )
358 return;
359
360 disp_camp_info(INFO_Y1+54, refreshFlag);
361 disp_worker_list(INFO_Y1+104, refreshFlag);
362 disp_worker_info(INFO_Y1+168, refreshFlag);
363
364 //------ display button -------//
365
366 int x;
367
368 if( own_firm() )
369 {
370 if( refreshFlag==INFO_REPAINT )
371 {
372 button_patrol.paint( INFO_X1, INFO_Y1+242, 'A', "PATROL" );
373 button_reward.paint( INFO_X1+BUTTON_ACTION_WIDTH, INFO_Y1+242, 'A', "REWARDCB" );
374 button_defense.paint( INFO_X2-BUTTON_ACTION_WIDTH, INFO_Y1+242, 'A', defense_flag ? (char*)"DEFENSE1" : (char*)"DEFENSE0" );
375 }
376
377 if( overseer_recno || worker_count )
378 button_patrol.enable();
379 else
380 button_patrol.disable();
381
382 if( nation_array[nation_recno]->cash >= REWARD_COST &&
383 ( (overseer_recno && unit_array[overseer_recno]->rank_id != RANK_KING)
384 || selected_worker_id ) )
385 {
386 button_reward.enable();
387 }
388 else
389 {
390 button_reward.disable();
391 }
392
393 x=INFO_X1+BUTTON_ACTION_WIDTH*2;
394 }
395 else
396 x=INFO_X1;
397
398 disp_spy_button(x, INFO_Y1+242, refreshFlag);
399
400 #ifdef DEBUG
401 if( sys.testing_session || sys.debug_session )
402 disp_debug_info(this, refreshFlag);
403 #endif
404 }
405 //----------- End of function FirmCamp::put_info -----------//
406
407
408 //--------- Begin of function FirmCamp::detect_info ---------//
409 //
detect_info()410 int FirmCamp::detect_info()
411 {
412 if( detect_basic_info() )
413 return 1;
414
415 if( !should_show_info() )
416 return 0;
417
418 //------ detect the overseer button -----//
419
420 int rc = mouse.any_click(INFO_X1+6, INFO_Y1+58, INFO_X1+5+UNIT_LARGE_ICON_WIDTH, INFO_Y1+57+UNIT_LARGE_ICON_HEIGHT, LEFT_BUTTON) ? 1
421 : mouse.any_click(INFO_X1+6, INFO_Y1+58, INFO_X1+5+UNIT_LARGE_ICON_WIDTH, INFO_Y1+57+UNIT_LARGE_ICON_HEIGHT, RIGHT_BUTTON) ? 2 : 0;
422
423 if( rc==1 ) // display this overseer's info
424 {
425 selected_worker_id = 0;
426 disp_camp_info(INFO_Y1+54, INFO_UPDATE);
427 disp_worker_list(INFO_Y1+104, INFO_UPDATE);
428 disp_worker_info(INFO_Y1+168, INFO_UPDATE);
429 return 1;
430 }
431
432 //--------- detect soldier info ---------//
433
434 if( detect_worker_list() )
435 {
436 disp_camp_info(INFO_Y1+54, INFO_UPDATE);
437 disp_worker_list(INFO_Y1+104, INFO_UPDATE);
438 disp_worker_info(INFO_Y1+168, INFO_UPDATE);
439 return 1;
440 }
441
442 //---------- detect spy button ----------//
443
444 if( detect_spy_button() )
445 return 1;
446
447 if( !own_firm() )
448 return 0;
449
450 //------ detect the overseer button -----//
451
452 if( rc==2 )
453 {
454 if(remote.is_enable())
455 {
456 // packet structure : <firm recno>
457 short *shortPtr=(short *)remote.new_send_queue_msg(MSG_FIRM_MOBL_OVERSEER, sizeof(short));
458 shortPtr[0] = firm_recno;
459 }
460 else
461 {
462 assign_overseer(0); // the overseer quits the camp
463 }
464 return 1;
465 }
466
467 //----------- detect patrol -----------//
468
469 if( button_patrol.detect(GETKEY(KEYEVENT_FIRM_PATROL)) )
470 {
471 if(remote.is_enable())
472 {
473 // packet structure : <firm recno>
474 short *shortPtr=(short *)remote.new_send_queue_msg(MSG_F_CAMP_PATROL, sizeof(short));
475 shortPtr[0] = firm_recno;
476 }
477 else
478 {
479 patrol();
480 }
481 return 1;
482 }
483
484 //----------- detect reward -----------//
485
486 if( button_reward.detect() )
487 {
488 reward(selected_worker_id, COMMAND_PLAYER);
489 // ##### begin Gilbert 25/9 ######//
490 se_ctrl.immediate_sound("TURN_ON");
491 // ##### end Gilbert 25/9 ######//
492 return 1;
493 }
494
495 //----- detect defense mode button -------//
496
497 if( button_defense.detect() )
498 {
499 // ##### begin Gilbert 25/9 ######//
500 se_ctrl.immediate_sound( !defense_flag?(char*)"TURN_ON":(char*)"TURN_OFF");
501 // ##### end Gilbert 25/9 ######//
502
503 if( !remote.is_enable() )
504 {
505 // update RemoteMsg::toggle_camp_patrol()
506 defense_flag = !defense_flag;
507 }
508 else
509 {
510 // packet structure : <firm recno> <defense_flag>
511 short *shortPtr=(short *)remote.new_send_queue_msg(MSG_F_CAMP_TOGGLE_PATROL, 2*sizeof(short));
512 shortPtr[0] = firm_recno;
513 shortPtr[1] = !defense_flag;
514 }
515
516 button_defense.update_bitmap( defense_flag ? (char*)"DEFENSE1" : (char*)"DEFENSE0" );
517
518 return 1;
519 }
520
521 return 0;
522 }
523 //----------- End of function FirmCamp::detect_info -----------//
524
525
526 //--------- Begin of function FirmCamp::disp_camp_info ---------//
527 //
disp_camp_info(int dispY1,int refreshFlag)528 void FirmCamp::disp_camp_info(int dispY1, int refreshFlag)
529 {
530 //---------------- paint the panel --------------//
531
532 if( refreshFlag == INFO_REPAINT )
533 vga_util.d3_panel_up( INFO_X1, dispY1, INFO_X2, dispY1+46);
534
535 if( !overseer_recno )
536 return;
537
538 //------------ display overseer info -------------//
539
540 Unit* overseerUnit = unit_array[overseer_recno];
541
542 int x=INFO_X1+6, y=dispY1+4, x1=x+UNIT_LARGE_ICON_WIDTH+8;
543
544 if( selected_worker_id == 0 )
545 {
546 vga_front.rect( x-2, y-2, x+UNIT_LARGE_ICON_WIDTH+1, y+UNIT_LARGE_ICON_HEIGHT+1, 2, V_YELLOW );
547 }
548 else
549 {
550 vga_util.blt_buf( x-2, y-2, x+UNIT_LARGE_ICON_WIDTH+1, y-1, 0 );
551 vga_util.blt_buf( x-2, y+UNIT_LARGE_ICON_HEIGHT+1, x+UNIT_LARGE_ICON_WIDTH+1, y+UNIT_LARGE_ICON_HEIGHT+2, 0 );
552 vga_util.blt_buf( x-2, y-2, x-1, y+UNIT_LARGE_ICON_HEIGHT+2, 0 );
553 vga_util.blt_buf( x+UNIT_LARGE_ICON_WIDTH, y-2, x+UNIT_LARGE_ICON_WIDTH+1, y+UNIT_LARGE_ICON_HEIGHT+2, 0 );
554 }
555
556 //-------------------------------------//
557
558 if( refreshFlag == INFO_REPAINT )
559 {
560 vga_front.put_bitmap(x, y, unit_res[overseerUnit->unit_id]->get_large_icon_ptr(overseerUnit->rank_id) );
561 }
562
563 //-------- set help parameters --------//
564
565 if( mouse.in_area(x, y, x+UNIT_LARGE_ICON_WIDTH+3, y+UNIT_LARGE_ICON_HEIGHT+3) )
566 help.set_unit_help( overseerUnit->unit_id, overseerUnit->rank_id, x, y, x+UNIT_LARGE_ICON_WIDTH+3, y+UNIT_LARGE_ICON_HEIGHT+3);
567
568 //-------------------------------------//
569
570 if( overseerUnit->rank_id == RANK_KING )
571 {
572 if( refreshFlag == INFO_REPAINT )
573 font_san.put( x1, y, _("King") );
574
575 y+=14;
576 }
577
578 if( refreshFlag == INFO_REPAINT )
579 font_san.put( x1, y, overseerUnit->unit_name(0), 0, INFO_X2-2 ); // 0-ask unit_name() not to return the title of the unit
580
581 y+=14;
582
583 //------- display leadership -------//
584
585 String str;
586
587 str = _("Leadership");
588 str += ": ";
589 str += overseerUnit->skill.get_skill(SKILL_LEADING);
590
591 font_san.disp( x1, y, str, INFO_X2-10 );
592 y+=14;
593
594 //--------- display loyalty ----------//
595
596 if( overseerUnit->rank_id != RANK_KING )
597 {
598 str = _("Loyalty");
599 str += ":";
600 x1 = font_san.put( x1, y, str );
601
602 int x2 = info.disp_loyalty( x1, y-1, x1, overseerUnit->loyalty, overseerUnit->target_loyalty, nation_recno, refreshFlag );
603
604 if( overseerUnit->spy_recno )
605 {
606 //------ if this is the player's spy -------//
607
608 if( overseerUnit->true_nation_recno() == nation_array.player_recno )
609 {
610 vga_front.put_bitmap( x2+5, y+1, image_icon.get_ptr("U_SPY") );
611 x2 += 15;
612 }
613 }
614
615 vga_util.blt_buf( x2, y-1, INFO_X2-2, dispY1+44, 0 );
616 }
617 }
618 //----------- End of function FirmCamp::disp_camp_info -----------//
619
620
621 //--------- Begin of function FirmCamp::next_day ---------//
622 //
next_day()623 void FirmCamp::next_day()
624 {
625 //----- call next_day() of the base class -----//
626
627 Firm::next_day();
628
629 //----- update the patrol_unit_array -----//
630
631 validate_patrol_unit();
632
633 //--------------------------------------//
634
635 if( info.game_date%15 == firm_recno%15 ) // once a week
636 {
637 train_unit();
638 recover_hit_point();
639 }
640
641 //--- if there are weapons in the firm, pay for their expenses ---//
642
643 pay_weapon_expense();
644 }
645 //----------- End of function FirmCamp::next_day -----------//
646
647
648 //------- Begin of function FirmCamp::train_unit -------//
649 //
650 // Increase the leadership and combat level of the general and the soldiers.
651 //
train_unit()652 void FirmCamp::train_unit()
653 {
654 if( !overseer_recno )
655 return;
656
657 Unit* overseerUnit = unit_array[overseer_recno];
658
659 if( overseerUnit->skill.skill_id != SKILL_LEADING )
660 return;
661
662 int overseerSkill = overseerUnit->skill.skill_level;
663 RaceInfo* overseerRaceInfo = race_res[overseerUnit->race_id];
664 int incValue;
665
666 //------- increase the commander's leadership ---------//
667
668 if( worker_count > 0 && overseerUnit->skill.skill_level < 100 )
669 {
670 //-- the more soldiers this commander has, the higher the leadership will increase ---//
671
672 incValue = 5 * worker_count
673 * (int) overseerUnit->hit_points / overseerUnit->max_hit_points
674 * (100+overseerUnit->skill.skill_potential*2) / 100;
675
676 overseerUnit->skill.skill_level_minor += incValue;
677
678 if( overseerUnit->skill.skill_level_minor >= 100 )
679 {
680 overseerUnit->skill.skill_level_minor -= 100;
681 overseerUnit->skill.skill_level++;
682 }
683 }
684
685 //------- increase the commander's combat level ---------//
686
687 if( overseerUnit->skill.combat_level < 100 )
688 {
689 incValue = 20 * (int) overseerUnit->hit_points / overseerUnit->max_hit_points
690 * (100+overseerUnit->skill.skill_potential*2) / 100;
691
692 overseerUnit->skill.combat_level_minor += incValue;
693
694 if( overseerUnit->skill.combat_level_minor >= 100 )
695 {
696 overseerUnit->skill.combat_level_minor -= 100;
697
698 overseerUnit->set_combat_level(overseerUnit->skill.combat_level+1);
699 }
700 }
701
702 //------- increase the solider's combat level -------//
703
704 int levelMinor;
705 Worker* workerPtr = worker_array;
706
707 for( int i=0 ; i<worker_count ; i++, workerPtr++ )
708 {
709 if( !workerPtr->race_id )
710 continue;
711
712 //------- increase worker skill -----------//
713
714 if( workerPtr->combat_level < overseerSkill )
715 {
716 incValue = MAX(20, overseerSkill-workerPtr->combat_level)
717 * workerPtr->hit_points / workerPtr->max_hit_points()
718 * (100+workerPtr->skill_potential*2) / 100;
719
720 levelMinor = workerPtr->combat_level_minor + incValue; // with random factors, resulting in 75% to 125% of the original
721
722 while( levelMinor >= 100 )
723 {
724 levelMinor -= 100;
725 workerPtr->combat_level++;
726 }
727
728 workerPtr->combat_level_minor = levelMinor;
729 }
730
731 //-- if the soldier has leadership potential, he learns leadership --//
732
733 if( workerPtr->skill_potential > 0 && workerPtr->skill_level < 100 )
734 {
735 incValue = (int) MAX(50, overseerUnit->skill.skill_level-workerPtr->skill_level)
736 * workerPtr->hit_points / workerPtr->max_hit_points()
737 * workerPtr->skill_potential*2 / 100;
738
739 workerPtr->skill_level_minor += incValue;
740
741 err_when( workerPtr->skill_level >= 100 );
742
743 if( workerPtr->skill_level_minor > 100 )
744 {
745 workerPtr->skill_level++;
746 workerPtr->skill_level_minor -= 100;
747 }
748 }
749 }
750
751 sort_worker();
752 }
753 //-------- End of function FirmCamp::train_unit --------//
754
755
756 //------- Begin of function FirmCamp::recover_hit_point -------//
757 //
758 // Soldiers recover their hit points.
759 //
760 // No need to recover the hit points of the general here as
761 // this is taken care in the Unit class function of the general.
762 //
recover_hit_point()763 void FirmCamp::recover_hit_point()
764 {
765 Worker* workerPtr = worker_array;
766
767 for( int i=0 ; i<worker_count ; i++, workerPtr++ )
768 {
769 //------- increase worker hit points --------//
770
771 if( workerPtr->hit_points < workerPtr->max_hit_points() )
772 workerPtr->hit_points++;
773 }
774 }
775 //------- End of function FirmCamp::recover_hit_point -------//
776
777
778 //------- Begin of function FirmCamp::pay_weapon_expense -------//
779 //
pay_weapon_expense()780 void FirmCamp::pay_weapon_expense()
781 {
782 Worker* workerPtr = worker_array;
783 Nation* nationPtr = nation_array[nation_recno];
784
785 for( int i=1 ; i<=worker_count ; i++, workerPtr++ )
786 {
787 if( workerPtr->unit_id &&
788 unit_res[workerPtr->unit_id]->unit_class == UNIT_CLASS_WEAPON )
789 {
790 if( nationPtr->cash > 0 )
791 {
792 nationPtr->add_expense( EXPENSE_WEAPON, (float) unit_res[workerPtr->unit_id]->year_cost / 365, 1 );
793 }
794 else // decrease hit points if the nation cannot pay the unit
795 {
796 if( workerPtr->hit_points > 0 )
797 workerPtr->hit_points--;
798
799 if( workerPtr->hit_points == 0 )
800 kill_worker(i); // if its hit points is zero, delete it
801
802 err_when( workerPtr->hit_points < 0 );
803 }
804 }
805 }
806 }
807 //------- End of function FirmCamp::pay_weapon_expense -------//
808
809
810
811 //--------- Begin of function FirmCamp::patrol ---------//
812 //
patrol()813 void FirmCamp::patrol()
814 {
815 err_when( !overseer_recno && !worker_count );
816 err_when( firm_ai && ai_capture_town_recno ); // ai_capture_town_recno is set after patrol() is called
817
818 if( nation_recno == nation_array.player_recno )
819 power.reset_selection();
820
821 //------------------------------------------------------------//
822 // If the commander in this camp has units under his lead
823 // outside and he is now going to lead a new team, then
824 // the old team members should be reset.
825 //------------------------------------------------------------//
826
827 if(overseer_recno)
828 {
829 TeamInfo* teamInfo = unit_array[overseer_recno]->team_info;
830
831 if( worker_count>0 && teamInfo->member_count>0 )
832 {
833 int unitRecno;
834
835 for( int i=0 ; i<teamInfo->member_count ; i++ )
836 {
837 unitRecno = teamInfo->member_unit_array[i];
838
839 if( unit_array.is_deleted(unitRecno) )
840 continue;
841
842 unit_array[unitRecno]->leader_unit_recno = 0;
843 }
844 }
845 }
846
847 //------------------------------------------------------------//
848 // mobilize workers first, then the overseer.
849 //------------------------------------------------------------//
850
851 short overseerRecno = overseer_recno;
852
853 if(patrol_all_soldier() && overseer_recno)
854 {
855 Unit* unitPtr = unit_array[overseer_recno];
856
857 err_when(unitPtr->rank_id!=RANK_GENERAL && unitPtr->rank_id!=RANK_KING);
858 unitPtr->team_id = unit_array.cur_team_id-1; // set it to the same team as the soldiers which are defined in mobilize_all_worker()
859
860 if( nation_recno == nation_array.player_recno )
861 {
862 unitPtr->selected_flag = 1;
863 unit_array.selected_recno = overseer_recno;
864 unit_array.selected_count++;
865 }
866 }
867
868 assign_overseer(0);
869
870 //---------------------------------------------------//
871
872 if(overseerRecno && !overseer_recno) // has overseer and the overseer is mobilized
873 {
874 Unit* overseerUnit = unit_array[overseerRecno];
875
876 if(overseerUnit->is_own() )
877 {
878 se_res.sound( overseerUnit->cur_x_loc(), overseerUnit->cur_y_loc(), 1,
879 'S', overseerUnit->sprite_id, "SEL");
880 }
881
882 err_when( patrol_unit_count > MAX_WORKER );
883
884 //--- add the overseer into the patrol_unit_array[] of this camp ---//
885
886 patrol_unit_array[patrol_unit_count++] = overseerRecno;
887
888 err_when( patrol_unit_count > 9 );
889
890 //------- set the team_info of the overseer -------//
891
892 err_when( !overseerUnit->team_info );
893
894 for( int i=0 ; i<patrol_unit_count ; i++ )
895 overseerUnit->team_info->member_unit_array[i] = patrol_unit_array[i];
896
897 overseerUnit->team_info->member_count = patrol_unit_count;
898 }
899
900 //-------- display info --------//
901
902 if( nation_recno == nation_array.player_recno ) // for player's camp, patrol() can only be called when the player presses the button.
903 info.disp();
904
905 err_when( patrol_unit_count < 0 );
906 err_when( patrol_unit_count > 9 );
907 }
908 //----------- End of function FirmCamp::patrol -----------//
909
910
911 //--------- Begin of function FirmCamp::patrol_all_soldier ---------//
912 //
913 // return 1 if there is enough space for patroling all soldiers
914 // return 0 otherwise
915 //
patrol_all_soldier()916 int FirmCamp::patrol_all_soldier()
917 {
918 err_when(!worker_array); // this function shouldn't be called if this firm does not need worker
919
920 //------- detect buttons on hiring firm workers -------//
921
922 err_when(worker_count>MAX_WORKER);
923
924 #ifdef DEBUG
925 int loopCount=0;
926 #endif
927
928 short unitRecno;
929 int mobileWorkerId = 1;
930
931 patrol_unit_count = 0; // reset it, it will be increased later
932
933 while(worker_count>0 && mobileWorkerId<=worker_count)
934 {
935 err_when(++loopCount > 100);
936
937 if(worker_array[mobileWorkerId-1].skill_id==SKILL_LEADING)
938 {
939 unitRecno = mobilize_worker(mobileWorkerId, COMMAND_AUTO);
940
941 patrol_unit_array[patrol_unit_count++] = unitRecno;
942 err_when(patrol_unit_count>MAX_WORKER);
943 }
944 else
945 {
946 mobileWorkerId++;
947 continue;
948 }
949
950 if(!unitRecno)
951 return 0; // keep the rest workers as there is no space for creating the unit
952
953 Unit* unitPtr = unit_array[unitRecno];
954
955 unitPtr->team_id = unit_array.cur_team_id; // define it as a team
956
957 if(overseer_recno)
958 {
959 unitPtr->leader_unit_recno = overseer_recno;
960 unitPtr->update_loyalty(); // the unit is just assigned to a new leader, set its target loyalty
961
962 err_when( unit_array[overseer_recno]->rank_id != RANK_KING &&
963 unit_array[overseer_recno]->rank_id != RANK_GENERAL );
964 }
965
966 if( nation_recno == nation_array.player_recno )
967 {
968 unitPtr->selected_flag = 1;
969 unit_array.selected_count++;
970 if ( !unit_array.selected_recno )
971 unit_array.selected_recno = unitRecno; // set the first soldier as selected; this is also the soldier with the highest leadership (because of sorting)
972 }
973 }
974
975 unit_array.cur_team_id++;
976 return 1;
977 }
978 //----------- End of function FirmCamp::patrol_all_soldier -----------//
979
980
981 //--------- Begin of function FirmCamp::mobilize_overseer --------//
982 //
mobilize_overseer()983 int FirmCamp::mobilize_overseer()
984 {
985 int unitRecno = Firm::mobilize_overseer();
986
987 //--- set the home camp firm recno of the unit for later return ---//
988
989 if( unitRecno )
990 {
991 unit_array[unitRecno]->home_camp_firm_recno = firm_recno;
992 return unitRecno;
993 }
994 else
995 return 0;
996 }
997 //----------- End of function FirmCamp::mobilize_overseer --------//
998
999
1000 //--------- Begin of function FirmCamp::mobilize_worker ---------//
1001 //
mobilize_worker(int workerId,char remoteAction)1002 int FirmCamp::mobilize_worker(int workerId, char remoteAction)
1003 {
1004 int unitRecno = Firm::mobilize_worker(workerId, remoteAction);
1005
1006 //--- set the home camp firm recno of the unit for later return ---//
1007
1008 if( unitRecno )
1009 {
1010 unit_array[unitRecno]->home_camp_firm_recno = firm_recno;
1011 return unitRecno;
1012 }
1013 else
1014 return 0;
1015 }
1016 //----------- End of function FirmCamp::mobilize_worker -----------//
1017
1018
1019 //--------- Begin of function FirmCamp::defense ---------//
1020 //### begin alex 15/10 ###//
1021 //void FirmCamp::defense(short targetRecno)
defense(short targetRecno,int useRangeAttack)1022 void FirmCamp::defense(short targetRecno, int useRangeAttack)
1023 //#### end alex 15/10 ####//
1024 {
1025 //### begin alex 15/10 ###//
1026 //--******* BUGHERE , please provide a reasonable condition to set useRangeAttack to 1
1027 if(unit_array[targetRecno]->mobile_type!=UNIT_LAND)
1028 useRangeAttack = 1;
1029 else
1030 useRangeAttack = 0;
1031 //#### end alex 15/10 ####//
1032
1033 if( !defense_flag )
1034 return;
1035
1036 //--------------- define parameters ------------------//
1037
1038 DefenseUnit *defPtr, *defPtr2;
1039 Unit *unitPtr;
1040 short unitRecno;
1041 int numOfUnitInside = worker_count + (overseer_recno>0);
1042 int i, j;
1043
1044 if(employ_new_worker)
1045 {
1046 //---------- reset unit's parameters in the previous defense -----------//
1047 defPtr = defense_array;
1048 for(int i=0; i<=MAX_WORKER; i++, defPtr++)
1049 {
1050 if(defPtr->status==OUTSIDE_CAMP && defPtr->unit_recno && !unit_array.is_deleted(defPtr->unit_recno))
1051 {
1052 unitPtr = unit_array[defPtr->unit_recno];
1053 if(unitPtr->nation_recno==nation_recno && unitPtr->action_misc==ACTION_MISC_DEFENSE_CAMP_RECNO &&
1054 unitPtr->action_misc_para==firm_recno)
1055 {
1056 unitPtr->clear_unit_defense_mode();
1057 err_when(unitPtr->in_auto_defense_mode());
1058 }
1059 }
1060 }
1061 memset(defense_array, 0, sizeof(DefenseUnit)*(MAX_WORKER+1));
1062 }
1063
1064 //------------------------------------------------------------------//
1065 // check all the exist(not dead) units outside the camp and arrange
1066 // them in the front part of the array.
1067 //------------------------------------------------------------------//
1068 j = 0;
1069 defPtr2 = defense_array;
1070
1071 if(!employ_new_worker) // some soliders may be outside the camp
1072 {
1073 for(i=0, defPtr=defense_array; i<=MAX_WORKER; i++, defPtr++)
1074 {
1075 if(!defPtr->unit_recno)
1076 continue; // a free slot
1077
1078 if(unit_array.is_deleted(defPtr->unit_recno))
1079 {
1080 defPtr->unit_recno = 0;
1081 continue; // unit is dead
1082 }
1083
1084 //----------------------------------------------------------------//
1085 // arrange the recno in the array front part
1086 //----------------------------------------------------------------//
1087 if(defPtr->status==OUTSIDE_CAMP)
1088 {
1089 unitPtr = unit_array[defPtr->unit_recno];
1090
1091 //-------------- ignore this unit if it is dead --------------------//
1092 if(unitPtr->is_unit_dead())
1093 continue;
1094
1095 if(!unitPtr->in_auto_defense_mode())
1096 continue; // the unit is ordered by the player to do other thing, so cannot control it afterwards
1097
1098 //--------------- the unit is in defense mode ----------------//
1099 defPtr2->unit_recno = defPtr->unit_recno;
1100 defPtr2->status = OUTSIDE_CAMP;
1101 j++;
1102 defPtr2++;
1103 }
1104 }
1105
1106 err_when(defPtr2 + (MAX_WORKER-j+1) > defense_array + MAX_WORKER + 1);
1107 memset(defPtr2, 0, sizeof(DefenseUnit)*(MAX_WORKER-j+1));
1108 }
1109
1110 set_employ_worker(0);
1111
1112 //------------------------------------------------------------------//
1113 // the unit outside the camp should be in defense mode and ready to
1114 // attack new target
1115 //------------------------------------------------------------------//
1116 for(i=0, defPtr=defense_array; i<j; i++, defPtr++)
1117 {
1118 //------------------------------------------------------------------//
1119 // order those unit outside the camp to attack the target
1120 //------------------------------------------------------------------//
1121 unitPtr = unit_array[defPtr->unit_recno];
1122 defense_outside_camp(defPtr->unit_recno, targetRecno);
1123 unitPtr->action_misc = ACTION_MISC_DEFENSE_CAMP_RECNO;
1124 unitPtr->action_misc_para = firm_recno;
1125 }
1126
1127 int mobilizePos = 0;
1128 //### begin alex 13/10 ###//
1129 //for(; i<MAX_WORKER && worker_count; i++, defPtr++)
1130 for(; i<MAX_WORKER && mobilizePos<worker_count; i++, defPtr++)
1131 //#### end alex 13/10 ####//
1132 {
1133 err_when(mobilizePos >= worker_count);
1134
1135 //------------------------------------------------------------------//
1136 // order those soldier inside the firm to move to target for attacking
1137 // keep those unable to attack inside the firm
1138 //------------------------------------------------------------------//
1139 //### begin alex 13/10 ###//
1140 //if(worker_array[mobilizePos].unit_id==UNIT_EXPLOSIVE_CART)
1141 if(worker_array[mobilizePos].unit_id==UNIT_EXPLOSIVE_CART ||
1142 (useRangeAttack && worker_array[mobilizePos].max_attack_range()==1))
1143 //#### end alex 13/10 ####//
1144 {
1145 mobilizePos++;
1146 continue;
1147 }
1148
1149 unitRecno = mobilize_worker(mobilizePos+1, COMMAND_AUTO);
1150 //unitRecno = mobilize_worker(1, COMMAND_AUTO); // always record 1 as the workers info are moved forward from the back to the front
1151 if(!unitRecno)
1152 break;
1153
1154 Unit* unitPtr = unit_array[unitRecno];
1155 unitPtr->team_id = unit_array.cur_team_id; // define it as a team
1156 unitPtr->action_misc = ACTION_MISC_DEFENSE_CAMP_RECNO;
1157 unitPtr->action_misc_para = firm_recno; // store the firm_recno for going back camp
1158
1159 if(overseer_recno)
1160 {
1161 unitPtr->leader_unit_recno = overseer_recno;
1162 unitPtr->update_loyalty(); // update target loyalty based on having a leader assigned
1163
1164 err_when( unit_array[overseer_recno]->rank_id != RANK_KING &&
1165 unit_array[overseer_recno]->rank_id != RANK_GENERAL );
1166 }
1167
1168 defense_inside_camp(unitRecno, targetRecno);
1169 defPtr->unit_recno = unitRecno;
1170 defPtr->status = OUTSIDE_CAMP;
1171 }
1172
1173 /*if(overseer_recno>0)
1174 {
1175 //------------------------------------------------------------------//
1176 // order those overseer inside the firm to move to target for attacking
1177 //------------------------------------------------------------------//
1178 unitPtr = unit_array[overseer_recno];
1179 assign_overseer(0);
1180 unitPtr->team_id = unit_array.cur_team_id; // define it as a team
1181 unitPtr->action_misc = ACTION_MISC_DEFENSE_CAMP_RECNO;
1182 unitPtr->action_misc_para = firm_recno; // store the firm_recno for going back camp
1183
1184 defense_inside_camp(unitPtr->sprite_recno, targetRecno);
1185 defPtr->unit_recno = unitPtr->sprite_recno;
1186 defPtr->status = OUTSIDE_CAMP;
1187 }*/
1188
1189 unit_array.cur_team_id++;
1190 }
1191 //----------- End of function FirmCamp::defense -----------//
1192
1193
1194 //--------- Begin of function FirmCamp::defense_inside_camp ---------//
defense_inside_camp(short unitRecno,short targetRecno)1195 void FirmCamp::defense_inside_camp(short unitRecno, short targetRecno)
1196 {
1197 Unit *unitPtr = unit_array[unitRecno];
1198 unitPtr->defense_attack_unit(targetRecno);
1199 // err_when(unitPtr->action_mode2!=ACTION_AUTO_DEFENSE_ATTACK_TARGET);
1200
1201 if(unitPtr->action_mode==ACTION_STOP && !unitPtr->action_para && unitPtr->action_x_loc==-1 && unitPtr->action_y_loc==-1)
1202 unitPtr->defense_detect_target();
1203 }
1204 //----------- End of function FirmCamp::defense_inside_camp -----------//
1205
1206
1207 //--------- Begin of function FirmCamp::defense_outside_camp ---------//
defense_outside_camp(short unitRecno,short targetRecno)1208 void FirmCamp::defense_outside_camp(short unitRecno, short targetRecno)
1209 {
1210 Unit *unitPtr = unit_array[unitRecno];
1211
1212 if(unitPtr->action_mode2==ACTION_AUTO_DEFENSE_DETECT_TARGET || unitPtr->action_mode2==ACTION_AUTO_DEFENSE_BACK_CAMP ||
1213 (unitPtr->action_mode2==ACTION_AUTO_DEFENSE_ATTACK_TARGET && unitPtr->cur_action==SPRITE_IDLE))
1214 {
1215 //----------------- attack new target now -------------------//
1216 unitPtr->defense_attack_unit(targetRecno);
1217 err_when(unitPtr->action_mode2!=ACTION_AUTO_DEFENSE_ATTACK_TARGET && unitPtr->action_mode2!=ACTION_AUTO_DEFENSE_DETECT_TARGET);
1218
1219 if(unitPtr->action_mode==ACTION_STOP && !unitPtr->action_para && unitPtr->action_x_loc==-1 && unitPtr->action_y_loc==-1)
1220 unitPtr->defense_detect_target();
1221 }
1222 }
1223 //----------- End of function FirmCamp::defense_outside_camp -----------//
1224
1225
1226 //--------- Begin of function FirmCamp::set_employ_worker ---------//
set_employ_worker(char flag)1227 void FirmCamp::set_employ_worker(char flag)
1228 {
1229 employ_new_worker = flag;
1230
1231 if(!flag)
1232 ai_status = CAMP_IN_DEFENSE;
1233 else
1234 ai_status = FIRM_WITHOUT_ACTION;
1235 /*
1236 //------- a button should exist for accept new worker or not ---------//
1237 //-*********** codes here **********-//
1238 Town *townPtr;
1239 for(int i=0; i<linked_town_count; i++)
1240 {
1241 err_when(!linked_town_array[i] || town_array.is_deleted(linked_town_array[i]));
1242 townPtr = town_array[linked_town_array[i]];
1243
1244 if(nation_recno == townPtr->nation_recno)
1245 toggle_town_link(i+1, employ_new_worker, COMMAND_AUTO); // enable links if employ_new_worker is true, otherwise disable
1246 }
1247 */
1248 }
1249 //----------- End of function FirmCamp::set_employ_worker -----------//
1250
1251
1252 //--------- Begin of function FirmCamp::update_defense_unit ---------//
update_defense_unit(short unitRecno)1253 void FirmCamp::update_defense_unit(short unitRecno)
1254 {
1255 DefenseUnit *defPtr = defense_array;
1256 int allInCamp = 1;
1257 int found=0;
1258
1259 for(int i=0; i<=MAX_WORKER; i++, defPtr++)
1260 {
1261 if(!defPtr->unit_recno)
1262 continue; // empty slot
1263
1264 if(unit_array.is_deleted(defPtr->unit_recno))
1265 {
1266 defPtr->unit_recno = 0;
1267 defPtr->status = INSIDE_CAMP;
1268 continue;
1269 }
1270
1271 if(defPtr->unit_recno==unitRecno)
1272 {
1273 defPtr->unit_recno = 0;
1274 defPtr->status = INSIDE_CAMP;
1275 Unit *unitPtr = unit_array[unitRecno];
1276 unitPtr->stop2();
1277 unitPtr->reset_action_misc_para();
1278 err_when(unitPtr->in_auto_defense_mode());
1279 found++;
1280 }
1281 else
1282 allInCamp = 0; // some units are still outside camp
1283 }
1284
1285 if(allInCamp)
1286 {
1287 set_employ_worker(1);
1288 memset(defense_array, 0, sizeof(DefenseUnit)*(MAX_WORKER+1));
1289 }
1290
1291 // err_when(!found); //**BUGHERE
1292 }
1293 //----------- End of function FirmCamp::update_defense_unit -----------//
1294
1295
1296 //-------- Begin of function FirmCamp::is_worker_full ------//
1297 //
is_worker_full()1298 int FirmCamp::is_worker_full()
1299 {
1300 return worker_count + patrol_unit_count + coming_unit_count >= MAX_WORKER;
1301 }
1302 //----------- End of function FirmCamp::is_worker_full ---------//
1303
1304
1305 #ifdef DEBUG
1306
1307 //----------- Begin of static function disp_debug_info -----------//
1308
disp_debug_info(FirmCamp * firmPtr,int refreshFlag)1309 static void disp_debug_info(FirmCamp* firmPtr, int refreshFlag)
1310 {
1311 if( refreshFlag == INFO_REPAINT )
1312 vga_util.d3_panel_up( INFO_X1, INFO_Y2-40, INFO_X2, INFO_Y2 );
1313
1314 int x=INFO_X1+3, y=INFO_Y2-37, x2=x+120;
1315
1316 font_san.field( x, y , "patrol unit count", x2, firmPtr->patrol_unit_count, 1, INFO_X2, refreshFlag);
1317 font_san.field( x, y+16, "coming unit count", x2, firmPtr->coming_unit_count, 1, INFO_X2, refreshFlag);
1318
1319 font_san.put( x+180, y, firmPtr->firm_recno );
1320 }
1321 //----------- End of static function disp_debug_info -----------//
1322
1323 #endif
1324