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 : OFIRM.CPP
22 //Description : Object Firm
23
24 #include <string.h>
25 #include <OVGA.h>
26 #include <ODATE.h>
27 #include <OMLINK.h>
28 #include <OWORLD.h>
29 #include <OPOWER.h>
30 #include <OCONFIG.h>
31 #include <OGAME.h>
32 #include <OUNIT.h>
33 #include <ONEWS.h>
34 #include <OSYS.h>
35 #include <OSPY.h>
36 #include <OSITE.h>
37 #include <OINFO.h>
38 #include <ONEWS.h>
39 #include <ONATION.h>
40 #include <OFIRM.h>
41 #include <ORACERES.h>
42 #include <OTOWN.h>
43 #include <OSPRITE.h>
44 #include <OFIRMRES.h>
45 #include <OF_MARK.h>
46 #include <OREMOTE.h>
47 #include <OF_CAMP.h>
48 #include <OF_HARB.h>
49 #include <OSERES.h>
50 #include <OREBEL.h>
51 // ###### begin Gilbert 2/10 ######//
52 #include <OFIRMDIE.h>
53 // ###### end Gilbert 2/10 ######//
54 #include <OUNITRES.h>
55 #include <locale.h>
56 #include "gettext.h"
57
58
59 //---------- define static member vars -------------//
60
61 char Firm::firm_menu_mode=FIRM_MENU_MAIN; // whether the firm is in spy menu mode
62 short Firm::action_spy_recno;
63 char Firm::bribe_result=BRIBE_NONE;
64 char Firm::assassinate_result=0;
65
66 //----------- define static parameters -------------//
67
68 static int remove_firm = 0; // true only when the firm is to be removed from the firm_array
69
70 //--------- Begin of function Firm::Firm --------//
71 //
72 // After created a Firm, you must either call Firm::set_world_matrix()
73 // to set the record no. of the firm in the matrix or set it yourself
74 //
75 // NOTE : this function will be called by firm_array.read_file()
76 // it CANNOT change any settings in nation_array
77 //
Firm()78 Firm::Firm()
79 {
80 firm_id = 0;
81 firm_build_id = 0;
82 firm_recno = 0;
83 firm_ai = 0;
84 ai_processed = 0;
85 ai_status = 0;
86 ai_link_checked = 0;
87 ai_sell_flag = 0;
88 race_id = 0;
89 nation_recno = 0;
90 closest_town_name_id = 0;
91 firm_name_instance_id = 0;
92 loc_x1 = loc_y1 = loc_x2 = loc_y2 = 0;
93 abs_x1 = abs_y1 = abs_x2 = abs_y2 = 0;
94 center_x = center_y = 0;
95 region_id = 0;
96 cur_frame = 0;
97 remain_frame_delay = 0;
98 hit_points = 0.0f;
99 max_hit_points = 0.0f;
100 under_construction = 0;
101 firm_skill_id = 0;
102 overseer_recno = 0;
103 overseer_town_recno = 0;
104 builder_recno = 0;
105 builder_region_id = 0;
106 productivity = 0.0f;
107 worker_array = NULL;
108 worker_count = 0;
109 selected_worker_id = 0;
110 player_spy_count = 0;
111 sabotage_level = 0;
112 linked_firm_count = 0;
113 linked_town_count = 0;
114 memset(linked_firm_array, 0, sizeof(short) * MAX_LINKED_FIRM_FIRM);
115 memset(linked_town_array, 0, sizeof(short) * MAX_LINKED_FIRM_TOWN);
116 memset(linked_firm_enable_array, 0, MAX_LINKED_FIRM_FIRM);
117 memset(linked_town_enable_array, 0, MAX_LINKED_FIRM_TOWN);
118 last_year_income = 0.0f;
119 cur_year_income = 0.0f;
120 setup_date = 0;
121 should_set_power = 0;
122 last_attacked_date = 0;
123 should_close_flag = 0;
124 no_neighbor_space = 0;
125 ai_should_build_factory_count = 0;
126 }
127 //----------- End of function Firm::Firm ---------//
128
129
130 //--------- Begin of function Firm::~Firm --------//
131 //
132 // Two ways to terminate a Firm :
133 //
134 // 1.call Firm::deinit() first and then delete the firm
135 // 2.delete the firm directly
136 //
~Firm()137 Firm::~Firm()
138 {
139 deinit();
140 }
141 //----------- End of function Firm::~Firm --------//
142
143
144 //--------- Begin of function Firm::init --------//
145 //
146 // It will initialize vars, and set the world matrix.
147 // Before calling init(), firm_recno should be set
148 //
149 // Note : it will set world matrix regardless the existing location content,
150 // so you must ensure that the location is clean by calling
151 // world.zoom_matrix->add_firm_test()
152 //
153 // <int> xLoc, yLoc = the location of firm in the world map
154 // <int> nationRecno = the recno of nation which build this firm
155 // <int> firmId = id(type) of the firm
156 // [char*] buildCode = the build code of the firm, no need to give if the firm just have one build type
157 // [short] builderRecno = recno of the builder unit
158 //
init(int xLoc,int yLoc,int nationRecno,int firmId,const char * buildCode,short builderRecno)159 void Firm::init(int xLoc, int yLoc, int nationRecno, int firmId, const char* buildCode, short builderRecno)
160 {
161 FirmInfo* firmInfo = firm_res[firmId];
162
163 firm_id = firmId;
164
165 if( buildCode )
166 firm_build_id = firmInfo->get_build_id(buildCode);
167 else
168 firm_build_id = firmInfo->first_build_id;
169
170 //----------- set vars -------------//
171
172 nation_recno = nationRecno;
173 setup_date = info.game_date;
174
175 overseer_recno = 0;
176
177 if( firmInfo->need_worker )
178 worker_array = (Worker*) mem_add( MAX_WORKER * sizeof(Worker) );
179 else
180 worker_array = NULL;
181
182 //----- set the firm's absolute positions on the map -----//
183
184 FirmBuild* firmBuild = firm_res.get_build(firm_build_id);
185
186 race_id = firmBuild->race_id;
187
188 loc_x1 = xLoc;
189 loc_y1 = yLoc;
190 loc_x2 = loc_x1 + firmBuild->loc_width - 1;
191 loc_y2 = loc_y1 + firmBuild->loc_height - 1;
192
193 center_x = (loc_x1 + loc_x2) / 2;
194 center_y = (loc_y1 + loc_y2) / 2;
195
196 region_id = world.get_region_id( center_x, center_y );
197
198 abs_x1 = xLoc * ZOOM_LOC_WIDTH + firmBuild->min_offset_x;
199 abs_y1 = yLoc * ZOOM_LOC_HEIGHT + firmBuild->min_offset_y;
200 abs_x2 = abs_x1 + firmBuild->max_bitmap_width - 1;
201 abs_y2 = abs_y1 + firmBuild->max_bitmap_height - 1;
202
203 //--------- set animation frame vars ---------//
204
205 if( firmBuild->animate_full_size )
206 cur_frame = 1;
207 else
208 {
209 cur_frame = 2; // start with the 2nd frame as the 1st frame is the common frame
210 err_when( firmBuild->frame_count <=2 ); // for segmented animation, the minimum no. of frames must be 3, as the first one is the common frame
211 }
212
213 remain_frame_delay = (char) firmBuild->frame_delay(cur_frame);
214
215 //--------- initialize gaming vars ----------//
216
217 hit_points = (float) 0;
218 max_hit_points = firmInfo->max_hit_points;
219
220 //------ set construction and builder -------//
221
222 under_construction = firmInfo->buildable; // whether the firm is under construction, if the firm is not buildable it is completed in the first place
223
224 if( !under_construction ) // if this firm doesn't been to be constructed, set its hit points to the maximum
225 hit_points = max_hit_points;
226
227 if( builderRecno )
228 set_builder(builderRecno);
229 else
230 builder_recno = 0;
231
232 //------ update firm counter -------//
233
234 firmInfo->total_firm_count++;
235
236 if( nation_recno )
237 firmInfo->inc_nation_firm_count(nation_recno);
238
239 //-------------------------------------------//
240
241 if( nation_recno > 0 )
242 {
243 Nation* nationPtr = nation_array[nation_recno];
244
245 firm_ai = nationPtr->is_ai();
246 ai_processed = 1;
247
248 //--------- increase firm counter -----------//
249
250 nationPtr->nation_firm_count++;
251
252 //-------- update last build date ------------//
253
254 nationPtr->last_build_firm_date = info.game_date;
255 }
256 else
257 {
258 firm_ai = 0;
259 ai_processed = 0;
260 }
261
262 ai_status = FIRM_WITHOUT_ACTION;
263 ai_link_checked = 1; // check the connected firms if ai_link_checked = 0;
264
265 //--------------------------------------------//
266
267 setup_link();
268
269 set_world_matrix();
270
271 init_name();
272
273 //----------- init AI -----------//
274
275 if( firm_ai )
276 nation_array[nation_recno]->add_firm_info(firm_id, firm_recno);
277
278 //-------- init derived ---------//
279
280 init_derived(); // init_derived() before set_world_matrix() so that init_derived has access to the original land info.
281 }
282 //----------- End of function Firm::init ---------//
283
284
285 //--------- Begin of function Firm::deinit --------//
286 //
deinit()287 void Firm::deinit()
288 {
289 if( !firm_recno ) // already deleted
290 return;
291
292 deinit_derived();
293
294 remove_firm = 1; // set static parameter
295
296 //------- delete AI info ----------//
297
298 if(firm_ai)
299 {
300 Nation* nationPtr = nation_array[nation_recno];
301
302 if( should_close_flag )
303 nationPtr->firm_should_close_array[firm_id-1]--;
304
305 err_when( nationPtr->firm_should_close_array[firm_id-1] < 0 );
306
307 nationPtr->del_firm_info(firm_id, firm_recno);
308 }
309
310 //--------- clean up related stuff -----------//
311
312 restore_world_matrix();
313 release_link();
314
315 //------ all workers and the overseer resign ------//
316
317 if( !sys.signal_exit_flag )
318 {
319 // ##### begin Gilbert 28/10 ########//
320 if( !under_construction )
321 {
322 // -------- create a firm die record ------//
323 // can be called as soon as restore_world_matrix
324 FirmDie firmDie;
325 firmDie.init(this);
326 firm_die_array.add(&firmDie);
327 }
328 // ##### end Gilbert 28/10 ########//
329
330 assign_overseer(0); // this function must be called before restore_world_matrix(), otherwise the power area can't be completely reset
331
332 if( worker_array )
333 {
334 resign_all_worker(); // the workers in the firm will be killed if there is no space for creating the workers
335 mem_del( worker_array );
336 worker_array = NULL;
337 }
338
339 if(builder_recno)
340 mobilize_builder(builder_recno);
341 }
342 else
343 {
344 if(builder_recno)
345 kill_builder(builder_recno);
346
347 kill_overseer();
348
349 if(worker_array)
350 {
351 kill_all_worker();
352 mem_del(worker_array);
353 worker_array = NULL;
354 }
355 }
356
357 //--------- decrease firm counter -----------//
358
359 if( nation_recno )
360 nation_array[nation_recno]->nation_firm_count--;
361
362 //------ update firm counter -------//
363
364 FirmInfo* firmInfo = firm_res[firm_id];
365
366 firmInfo->total_firm_count--;
367
368 if( nation_recno )
369 firmInfo->dec_nation_firm_count(nation_recno);
370
371 //------- update town border ---------//
372
373 loc_x1 = -1; // mark deleted
374
375 //------- if the current firm is the selected -----//
376
377 if( firm_array.selected_recno == firm_recno )
378 {
379 firm_array.selected_recno = 0;
380 info.disp();
381 }
382
383 //-------------------------------------------------//
384
385 firm_recno = 0;
386 remove_firm = 0; // reset static parameter
387 }
388 //----------- End of function Firm::deinit ---------//
389
390
391 //--------- Begin of function Firm::init_name --------//
392 //
393 // Set the name of this firm. Name related vars are set.
394 //
init_name()395 void Firm::init_name()
396 {
397 char t=firm_res[firm_id]->short_name[0];
398
399 if( t==' ' || !t ) // if this firm does not have any short name, display the full name without displaying the town name together
400 return;
401
402 //---- find the closest town and set closest_town_name_id -----//
403
404 closest_town_name_id = get_closest_town_name_id();
405
406 //--------- set firm_name_instance_id -----------//
407
408 char usedInstanceArray[256];
409 Firm* firmPtr;
410
411 memset( usedInstanceArray, 0, sizeof(usedInstanceArray) );
412
413 int i;
414 for( i=firm_array.size() ; i>0 ; i-- )
415 {
416 if( firm_array.is_deleted(i) )
417 continue;
418
419 firmPtr = firm_array[i];
420
421 if( firmPtr->firm_id == firm_id &&
422 firmPtr->closest_town_name_id == closest_town_name_id &&
423 firmPtr->firm_name_instance_id )
424 {
425 usedInstanceArray[firmPtr->firm_name_instance_id-1] = 1;
426 }
427 }
428
429 for( i=0 ; i<256 ; i++ ) // get the smallest id. which are not used by existing firms
430 {
431 if( !usedInstanceArray[i] )
432 {
433 firm_name_instance_id = i+1;
434 break;
435 }
436 }
437 }
438 //--------- End of function Firm::init_name --------//
439
440
441 //------- Begin of function Firm::get_closest_town_name_id -----------//
442 //
443 // return the name id. of the closest town.
444 //
get_closest_town_name_id()445 int Firm::get_closest_town_name_id()
446 {
447 //---- find the closest town and set closest_town_name_id -----//
448
449 int townDistance, minTownDistance=0x7FFF;
450 int closestTownNameId=0;
451 Town* townPtr;
452
453 for( int i=town_array.size() ; i>0 ; i-- )
454 {
455 if( town_array.is_deleted(i) )
456 continue;
457
458 townPtr = town_array[i];
459
460 townDistance = misc.points_distance( townPtr->center_x, townPtr->center_y,
461 center_x, center_y );
462
463 if( townDistance < minTownDistance )
464 {
465 minTownDistance = townDistance;
466 closestTownNameId = townPtr->town_name_id;
467 }
468 }
469
470 return closestTownNameId;
471 }
472 //--------- End of function Firm::get_closest_town_name_id -----------//
473
474
475 //------- Begin of function Firm::firm_name -----------//
476 //
firm_name()477 char* Firm::firm_name()
478 {
479 static String str;
480
481 if( !closest_town_name_id )
482 {
483 str = _(firm_res[firm_id]->name);
484 }
485 else
486 {
487 if( firm_name_instance_id > 1 )
488 {
489 // display number when there are multiple linked firms of the same type
490 // TRANSLATORS: <Town> <Short Firm Name> <Firm #>
491 // This is the name of the firm when there are multiple linked firms to a town.
492 snprintf( str, MAX_STR_LEN+1, pgettext ("FirmUI|Name", "%s %s %d"), town_res.get_name(closest_town_name_id), _(firm_res[firm_id]->short_name), firm_name_instance_id );
493 }
494 else
495 {
496 // TRANSLATORS: <Town> <Short Firm Name>
497 // This is the name of the firm.
498 snprintf( str, MAX_STR_LEN+1, pgettext ("FirmUI|Name", "%s %s"), town_res.get_name(closest_town_name_id), _(firm_res[firm_id]->short_name) );
499 }
500 }
501
502 return str;
503 }
504 //--------- End of function Firm::firm_name -----------//
505
506
507 //------- Begin of function Firm::complete_construction -----------//
508 //
509 // Complete construction instantly.
510 //
complete_construction()511 void Firm::complete_construction()
512 {
513 if( under_construction )
514 {
515 hit_points = max_hit_points;
516 under_construction = 0;
517 }
518 }
519 //--------- End of function Firm::complete_construction -----------//
520
521
522 //------- Begin of function Firm::assign_unit -----------//
523 //
assign_unit(int unitRecno)524 void Firm::assign_unit(int unitRecno)
525 {
526 err_when( !unitRecno );
527
528 Unit* unitPtr = unit_array[unitRecno];
529
530 //------- if this is a construction worker -------//
531
532 if( unitPtr->skill.skill_id == SKILL_CONSTRUCTION )
533 {
534 set_builder(unitRecno);
535 return;
536 }
537
538 //---- if the unit does not belong to the firm's nation ----//
539
540 if( unitPtr->nation_recno != nation_recno )
541 {
542 // can no longer capture a firm with a normal unit - must use spy
543
544 //----- capture this firm if there is nobody here -----//
545 /*
546 if( worker_array && worker_count==0 && overseer_recno==0 && // if the firm is empty, assign to take over the firm
547 unitPtr->skill.skill_id == firm_skill_id ) // the takeover unit must have the skill of this firm
548 {
549 change_nation(unitPtr->nation_recno);
550 }
551 else
552 */ return; // if cannot capture, the nations are not the same, return now. This will happen if the unit's nation was changed during his moving to the firm.
553 }
554
555 //-- if there isn't any overseer in this firm or this unit's skill is higher than the current overseer's skill --//
556
557 //### begin alex 18/10 ###//
558 unitPtr->group_select_id = 0; // clear group select id
559 //#### end alex 18/10 ####//
560
561 FirmInfo* firmInfo = firm_res[firm_id];
562
563 if( firmInfo->need_overseer &&
564 ( !overseer_recno ||
565 ( unitPtr->skill.skill_id == firm_skill_id &&
566 unit_array[overseer_recno]->skill.skill_id != firm_skill_id ) || // the current overseer does not have the required skill
567 ( unitPtr->skill.skill_id == firm_skill_id &&
568 unitPtr->skill.skill_level > unit_array[overseer_recno]->skill.skill_level )
569 ) )
570 {
571 assign_overseer(unitRecno);
572 }
573 else if( firmInfo->need_worker )
574 {
575 assign_worker(unitRecno);
576 sort_worker();
577 }
578 }
579 //--------- End of function Firm::assign_unit -----------//
580
581
582 //--------- Begin of function Firm::assign_overseer --------//
583 //
584 // Assign an unit as the overseer of this firm
585 //
586 // <int> newOverseerRecno - recno of the new overseer unit.
587 // 0 means resign the current overseer
588 //
589 // Note: If a new overseer is assigned to the firm, there should be
590 // space for the old overseer to initialize and appear in the
591 // map (the space the new overseer occupied).
592 //
593 // ** If the newOverseerRecno==0, there may be no space for
594 // creating the old overseer. Then, the old overseer will be
595 // deleted. **
596 // ** else there must be space for creating the old overseer,
597 // at least the space occupied by the new overseer **
598 //
assign_overseer(int newOverseerRecno)599 void Firm::assign_overseer(int newOverseerRecno)
600 {
601 if( !firm_res[firm_id]->need_overseer )
602 return;
603
604 if( !newOverseerRecno && !overseer_recno )
605 return;
606
607 //--- if the new overseer's nation is not the same as the firm's nation, don't assign ---//
608
609 if( newOverseerRecno && unit_array[newOverseerRecno]->nation_recno != nation_recno )
610 return;
611
612 //------------------------------------------//
613
614 int oldOverseerRecno = overseer_recno;
615
616 if(!newOverseerRecno)
617 {
618 //------------------------------------------------------------------------------------------------//
619 // the old overseer may be kept in firm or killed if remove_firm is true
620 //------------------------------------------------------------------------------------------------//
621 err_when(!overseer_recno);
622 Unit *oldUnitPtr = unit_array[overseer_recno];
623 SpriteInfo *spriteInfo = sprite_res[unit_res[oldUnitPtr->unit_id]->sprite_id];
624 int xLoc = loc_x1;
625 int yLoc = loc_y1;
626
627 if(!locate_space(remove_firm, xLoc, yLoc, loc_x2, loc_y2, spriteInfo->loc_width, spriteInfo->loc_height))
628 {
629 if(remove_firm)
630 kill_overseer();
631 }
632 else
633 {
634 //------ there should be space for creating the overseer -----//
635
636 mobilize_overseer();
637 /*
638 //-- if the overseer is resigned without successor, mobilize a worker as overseer --//
639 if(!newOverseerRecno && worker_array)
640 {
641 int bestWorkerId = best_worker_id(); // find the most skilled worker
642 if( bestWorkerId )
643 newOverseerRecno = mobilize_worker(bestWorkerId,1);
644 }
645 */
646 }
647 }
648 else
649 {
650 //----------- there should be space for creating the overseer ---------//
651 err_when(!newOverseerRecno);
652
653 Unit *unitPtr = unit_array[newOverseerRecno];
654
655 int originalXLoc = unitPtr->next_x_loc();
656 int originalYLoc = unitPtr->next_y_loc();
657
658 err_when( unitPtr->hit_points <= 0 );
659
660 unitPtr->deinit_sprite();
661
662 //----------------------------------------------------------------------------------------//
663 // There should be at least one location (occupied by the new overseer) for creating the old
664 // overseer.
665 //
666 // 1) If a town is already created, the new overseer settle down there, free its space for
667 // creating the new overseer.
668 // 2) If the overseer and the workers live in the firm, no town will be created. Thus, the
669 // space occupied by the old overseer is free for creating the new overseer.
670 // 3) If the overseer and the workers need live in town, and a town is created. i.e. there
671 // is no overseer or worker in the firm, so just assign the new overseer in the firm
672 //----------------------------------------------------------------------------------------//
673
674 if(!overseer_recno && !worker_count)
675 {
676 //------------------------------------------------------------------------------------------------//
677 // the firm is empty
678 //------------------------------------------------------------------------------------------------//
679 if(firm_res[firm_id]->live_in_town)
680 {
681 overseer_town_recno = assign_settle(unitPtr->race_id, unitPtr->loyalty, 1); // the overseer settles down
682 if(!overseer_town_recno)
683 return; // no space for creating the town, just return without assigning
684 }
685
686 //------- set the unit to overseer mode and deinit the sprite ------//
687 overseer_recno = newOverseerRecno;
688 Unit *unitPtr = unit_array[overseer_recno];
689 unitPtr->set_mode(UNIT_MODE_OVERSEE, firm_recno);
690 unitPtr->deinit_sprite(); // hide the unit from the world map
691
692 //--------- if the unit is a spy -----------//
693
694 if( unitPtr->spy_recno )
695 spy_array[unitPtr->spy_recno]->set_place( SPY_FIRM, firm_recno );
696 /*
697 //------ capture the firm if the overseer is from another nation ---//
698 if(unit_array[overseer_recno]->nation_recno != nation_recno)
699 change_nation(unit_array[overseer_recno]->nation_recno);
700 */
701 }
702 else
703 {
704 //------------------------------------------------------------------------------------------------//
705 // a town should exist if the overseer need live in town
706 //------------------------------------------------------------------------------------------------//
707 if(firm_res[firm_id]->live_in_town)
708 {
709 overseer_town_recno = assign_settle(unitPtr->race_id, unitPtr->loyalty, 1); // the overseer settles down
710
711 if(!overseer_town_recno)
712 return; // reach MAX population and no space to create town, return without assigning
713 }
714
715 Unit *unitPtr = unit_array[newOverseerRecno];
716 unitPtr->deinit_sprite();
717
718 if(overseer_recno)
719 mobilize_overseer();
720
721 overseer_recno = newOverseerRecno;
722 unitPtr->set_mode(UNIT_MODE_OVERSEE, firm_recno);
723
724 //--------- if the unit is a spy -----------//
725
726 if( unitPtr->spy_recno )
727 spy_array[unitPtr->spy_recno]->set_place( SPY_FIRM, firm_recno );
728 /*
729 //------ capture the firm if the overseer is from another nation ---//
730 if(unit_array[overseer_recno]->nation_recno != nation_recno)
731 change_nation(unit_array[overseer_recno]->nation_recno);
732 */
733 }
734 }
735
736 //------- update loyalty -------//
737
738 if( newOverseerRecno && !unit_array.is_deleted(newOverseerRecno) )
739 unit_array[newOverseerRecno]->update_loyalty();
740
741 //----------- refresh display if this firm is selected ----------//
742
743 if(firm_array.selected_recno == firm_recno)
744 info.disp();
745 }
746 //----------- End of function Firm::assign_overseer --------//
747
748
749 //--------- Begin of function Firm::mobilize_overseer --------//
750 //
mobilize_overseer()751 int Firm::mobilize_overseer()
752 {
753 if( !overseer_recno )
754 return 0;
755
756 //--------- restore overseer's harmony ---------//
757
758 int overseerRecno = overseer_recno;
759
760 Unit* unitPtr = unit_array[overseer_recno];
761
762 //-------- if the overseer is a spy -------//
763
764 if( unitPtr->spy_recno )
765 spy_array[unitPtr->spy_recno]->set_place(SPY_MOBILE, unitPtr->sprite_recno);
766
767 //---- cancel the overseer's presence in the town -----//
768
769 if( firm_res[firm_id]->live_in_town )
770 town_array[overseer_town_recno]->dec_pop(unitPtr->race_id, 1);
771
772 //----- get this overseer out of the firm -----//
773
774 SpriteInfo* spriteInfo = sprite_res[unit_res[unitPtr->unit_id]->sprite_id];
775 int xLoc=loc_x1, yLoc=loc_y1; // xLoc & yLoc are used for returning results
776
777 int spaceFound = locate_space(remove_firm, xLoc, yLoc, loc_x2, loc_y2, spriteInfo->loc_width, spriteInfo->loc_height);
778
779 if(spaceFound)
780 {
781 unitPtr->init_sprite(xLoc, yLoc);
782 unitPtr->set_mode(0); // reset overseen firm recno
783 }
784 else
785 {
786 unit_array.del(overseer_recno); // delete it when there is no space for the unit
787 return 0;
788 }
789
790 //--------- reset overseer_recno -------------//
791
792 overseer_recno = 0;
793 overseer_town_recno = 0;
794
795 //------- update loyalty -------//
796
797 if( overseerRecno && !unit_array.is_deleted(overseerRecno) )
798 unit_array[overseerRecno]->update_loyalty();
799
800 return overseerRecno;
801 }
802 //----------- End of function Firm::mobilize_overseer --------//
803
804
805 //--------- Begin of function Firm::mobilize_builder --------//
mobilize_builder(short recno)806 int Firm::mobilize_builder(short recno)
807 {
808 //----------- mobilize the builder -------------//
809 Unit* unitPtr = unit_array[recno];
810
811 SpriteInfo *spriteInfo = unitPtr->sprite_info;
812 int xLoc=loc_x1, yLoc=loc_y1;
813
814 if(!locate_space(remove_firm, xLoc, yLoc, loc_x2, loc_y2, spriteInfo->loc_width, spriteInfo->loc_height, UNIT_LAND, builder_region_id) &&
815 !world.locate_space(&xLoc, &yLoc, loc_x2, loc_y2, spriteInfo->loc_width, spriteInfo->loc_height, UNIT_LAND, builder_region_id))
816 {
817 kill_builder(recno);
818 return 0;
819 }
820
821 unitPtr->init_sprite(xLoc, yLoc);
822 unitPtr->stop2(); // clear all previously defined action
823
824 err_when(unitPtr->unit_mode != UNIT_MODE_CONSTRUCT);
825
826 unitPtr->set_mode(0);
827 return 1;
828 }
829 //----------- End of function Firm::mobilize_builder --------//
830
831
832 //--------- Begin of function Firm::best_worker_id --------//
833 //
best_worker_id()834 int Firm::best_worker_id()
835 {
836 int bestWorkerId=0, maxWorkerSkill=0;
837 char rankId;
838 int liveInTown = firm_res[firm_id]->live_in_town;
839
840 err_when( !worker_array ); // this function shouldn't be called if this firm does not need worker
841
842 for( int i=0 ; i<worker_count ; i++ )
843 {
844 //--- if the town the worker lives and the firm are of the same nation ---//
845
846 if( !liveInTown || town_array[ worker_array[i].town_recno ]->nation_recno == nation_recno )
847 {
848 if(firm_id==FIRM_CAMP)
849 {
850 rankId = worker_array[i].rank_id;
851 if(rankId!=RANK_GENERAL && rankId!=RANK_KING)
852 continue;
853 }
854
855 if( worker_array[i].skill_level > maxWorkerSkill )
856 {
857 maxWorkerSkill = worker_array[i].skill_level;
858 bestWorkerId = i+1;
859 }
860 }
861 }
862
863 return bestWorkerId;
864 }
865 //----------- End of function Firm::best_worker_id --------//
866
867
868 //--------- Begin of function Firm::free_worker_room --------//
869 //
870 // Resign the worst worker from the firm to free up a room for
871 // a new worker.
872 //
free_worker_room()873 void Firm::free_worker_room()
874 {
875 err_when( !worker_array ); // this function shouldn't be called if this firm does not need worker
876
877 //---- if there is space for one more worker, demote the overseer to worker ----//
878
879 if( worker_count < MAX_WORKER || worker_count==0 )
880 return;
881
882 //---- if all worker space are full, resign the worst worker to release one worker space for the overseer ----//
883
884 int worestWorkerId=0, minWorkerSkill=0x7FFF;
885
886 for( int i=0 ; i<MAX_WORKER ; i++ )
887 {
888 if( worker_array[i].skill_level < minWorkerSkill )
889 {
890 minWorkerSkill = worker_array[i].skill_level;
891 worestWorkerId = i+1;
892 }
893 }
894
895 if( worestWorkerId )
896 resign_worker(worestWorkerId);
897
898 err_here();
899 }
900 //----------- End of function Firm::free_worker_room --------//
901
902
903 //--------- Begin of function Firm::assign_worker --------//
904 //
905 // Assign an unit as one of the workers of this firm
906 //
assign_worker(int workerUnitRecno)907 void Firm::assign_worker(int workerUnitRecno)
908 {
909 err_when( !worker_array ); // this function shouldn't be called if this firm does not need worker
910
911 //-- if the unit is a spy, only allow assign when there is room in the firm --//
912
913 Unit* unitPtr = unit_array[workerUnitRecno];
914
915 if( unitPtr->true_nation_recno() != nation_recno &&
916 worker_count == MAX_WORKER )
917 {
918 return;
919 }
920
921 //---- if all worker space are full, resign the worst worker to release one worker space for the overseer ----//
922
923 err_when( unitPtr->rank_id == RANK_KING );
924 err_when( unitPtr->hit_points <= 0 );
925
926 int unitXLoc= -1, unitYLoc;
927
928 if( worker_count == MAX_WORKER )
929 {
930 int worstWorkerId=0, minWorkerSkill=0x7FFF, workerSkill;
931
932 for(int i=0; i<MAX_WORKER; i++)
933 {
934 workerSkill = worker_array[i].skill_level;
935
936 if( workerSkill < minWorkerSkill)
937 {
938 minWorkerSkill = workerSkill;
939 worstWorkerId = i+1;
940 }
941 }
942
943 err_when(worstWorkerId<1 || worstWorkerId>MAX_WORKER);
944
945 unitXLoc = unitPtr->next_x_loc(); // save the location for later init_sprite() if the assign settle action failed
946 unitYLoc = unitPtr->next_y_loc();
947
948 unitPtr->deinit_sprite(); // free the location for creating the worst unit
949
950 #ifdef DEBUG
951 int oldWorkerCount = worker_count;
952 int resignResult = resign_worker(worstWorkerId);
953 err_when(!resignResult && oldWorkerCount==worker_count);
954 #else
955 resign_worker(worstWorkerId);
956 #endif
957 }
958
959 // err_when( worker_count >= MAX_WORKER );
960
961 //---------- there is room for the new worker ------------//
962
963 Worker* workerPtr = worker_array + worker_count;
964
965 memset( workerPtr, 0, sizeof(Worker) );
966
967 if( firm_res[firm_id]->live_in_town )
968 {
969 workerPtr->town_recno = assign_settle(unitPtr->race_id, unitPtr->loyalty, 0); // the worker settles down
970
971 if( !workerPtr->town_recno )
972 {
973 //--- the unit was deinit_sprite(), and now the assign settle action failed, we need to init_sprite() to restore it ---//
974
975 if( unitXLoc>=0 && !unitPtr->is_visible() )
976 unitPtr->init_sprite(unitXLoc, unitYLoc);
977
978 return;
979 }
980 }
981 else
982 {
983 workerPtr->town_recno = 0;
984 workerPtr->worker_loyalty = unitPtr->loyalty;
985 }
986
987 //------- add the worker to the firm -------//
988
989 worker_count++;
990
991 err_when( worker_count > MAX_WORKER );
992
993 workerPtr->name_id = unitPtr->name_id;
994 workerPtr->race_id = unitPtr->race_id;
995 workerPtr->unit_id = unitPtr->unit_id;
996 workerPtr->rank_id = unitPtr->rank_id;
997
998 workerPtr->skill_id = firm_skill_id;
999 workerPtr->skill_level = unitPtr->skill.get_skill(firm_skill_id);
1000
1001 if( workerPtr->skill_level == 0 && workerPtr->race_id )
1002 workerPtr->skill_level = CITIZEN_SKILL_LEVEL;
1003
1004 err_when( workerPtr->skill_level<0 );
1005 err_when( workerPtr->skill_level>100 );
1006
1007 /*#ifdef DEBUG2
1008 if(unit_res[unitPtr->unit_id]->unit_class==UNIT_CLASS_HUMAN)
1009 {
1010 unitPtr->skill.combat_level = 60;
1011 unitPtr->hit_points = unitPtr->skill.combat_level*2;
1012 unitPtr->max_hit_points = unitPtr->hit_points;
1013 }
1014 #endif*/
1015
1016 workerPtr->combat_level = unitPtr->skill.combat_level;
1017 workerPtr->hit_points = (int) unitPtr->hit_points;
1018
1019 err_when( workerPtr->combat_level <= 0 || workerPtr->combat_level > 100 );
1020
1021 err_when( workerPtr->hit_points < 0 );
1022
1023 if( workerPtr->hit_points == 0 ) // 0.? will become 0 in (float) to (int) conversion
1024 workerPtr->hit_points = 1;
1025
1026 if( unit_res[unitPtr->unit_id]->unit_class == UNIT_CLASS_WEAPON )
1027 {
1028 workerPtr->extra_para = unitPtr->get_weapon_version();
1029 }
1030 else if( unitPtr->race_id )
1031 {
1032 workerPtr->extra_para = unitPtr->cur_power;
1033 }
1034 else
1035 {
1036 workerPtr->extra_para = 0;
1037 }
1038
1039 workerPtr->init_potential();
1040
1041 //------ if the recruited worker is a spy -----//
1042
1043 if( unitPtr->spy_recno )
1044 {
1045 spy_array[unitPtr->spy_recno]->set_place( SPY_FIRM, firm_recno );
1046
1047 workerPtr->spy_recno = unitPtr->spy_recno;
1048 unitPtr->spy_recno = 0; // reset it now so Unit::deinit() won't delete the Spy in spy_array
1049 }
1050
1051 //--------- the unit disappear in firm -----//
1052
1053 if( !firm_res[firm_id]->live_in_town ) // if the unit does not live in town, increase the unit count now
1054 unit_res[unitPtr->unit_id]->inc_nation_unit_count(nation_recno);
1055
1056 unit_array.disappear_in_firm(workerUnitRecno);
1057 }
1058 //----------- End of function Firm::assign_worker --------//
1059
1060
1061 //--------- Begin of function Firm::assign_settle --------//
1062 //
1063 // The newly assigned overseer / worker settles down.
1064 //
1065 // <int> raceId - race id. of the unit
1066 // <int> unitLoyalty - loyalty of the unit
1067 // <int> isOverseer - whether the unit is an overseer, if not,
1068 // it is then a worker.
1069 //
1070 // return: <int> townRecno - the home town of the overseer/worker
1071 // 0 - no space to settle.
1072 //
assign_settle(int raceId,int unitLoyalty,int isOverseer)1073 int Firm::assign_settle(int raceId, int unitLoyalty, int isOverseer)
1074 {
1075 err_when( !firm_res[firm_id]->live_in_town );
1076 err_when( unitLoyalty < 0 || unitLoyalty > 100 );
1077
1078 //--- if there is a town of our nation within the effective distance ---//
1079
1080 int townRecno = find_settle_town();
1081
1082 if( townRecno )
1083 {
1084 town_array[townRecno]->inc_pop(raceId, 1, unitLoyalty);
1085 return townRecno;
1086 }
1087
1088 //--- should create a town near the this firm, if there is no other town in the map ---//
1089
1090 int xLoc=loc_x1, yLoc=loc_y1; // xLoc & yLoc are used for returning results
1091
1092 if( world.locate_space( &xLoc, &yLoc, loc_x2, loc_y2, STD_TOWN_LOC_WIDTH,
1093 STD_TOWN_LOC_HEIGHT, UNIT_LAND, region_id, 1 ) ) // the town must be in the same region as this firm.
1094 {
1095 if( misc.points_distance( center_x, center_y, xLoc+(STD_TOWN_LOC_WIDTH-1)/2,
1096 yLoc+(STD_TOWN_LOC_HEIGHT-1)/2 ) <= EFFECTIVE_FIRM_TOWN_DISTANCE )
1097 {
1098 int townRecno = town_array.add_town( nation_recno, raceId, xLoc, yLoc );
1099
1100 Town* townPtr = town_array[townRecno];
1101
1102 townPtr->init_pop( raceId, 1, unitLoyalty, 1 ); // 1st 1 - population, 2nd 1 - the unit has a job already
1103
1104 townPtr->auto_set_layout();
1105
1106 return townRecno;
1107 }
1108 }
1109
1110 //---- not able to find a space for a new town within the effective distance ----//
1111
1112 return 0;
1113 }
1114 //----------- End of function Firm::assign_settle --------//
1115
1116
1117 //--------- Begin of function Firm::find_settle_town --------//
1118 //
1119 // Find a suitable town for the unit to settle.
1120 //
find_settle_town()1121 int Firm::find_settle_town()
1122 {
1123 int townDistance, minDistance=0x7FFF, nearestTownRecno=0;
1124 Town* townPtr;
1125 Nation* nationPtr = nation_array[nation_recno];
1126
1127 //-------- scan for our own town first -----------//
1128
1129 for( int i=0 ; i<linked_town_count ; i++ )
1130 {
1131 townPtr = town_array[ linked_town_array[i] ];
1132
1133 if( townPtr->population>=MAX_TOWN_POPULATION )
1134 continue;
1135
1136 if( townPtr->nation_recno != nation_recno )
1137 continue;
1138
1139 townDistance = misc.points_distance( townPtr->center_x, townPtr->center_y, center_x, center_y );
1140
1141 if( townDistance < minDistance )
1142 {
1143 minDistance = townDistance;
1144 nearestTownRecno = townPtr->town_recno;
1145 }
1146 }
1147
1148 if( nearestTownRecno )
1149 return nearestTownRecno;
1150 else
1151 return 0;
1152 }
1153 //----------- End of function Firm::find_settle_town --------//
1154
1155
1156 //--------- Begin of function Firm::set_world_matrix --------//
1157 //
1158 // Set the cargo id of current firm int he world matrix
1159 //
set_world_matrix()1160 void Firm::set_world_matrix()
1161 {
1162 //--- if a nation set up a firm in a location that the player has explored, contact between the nation and the player is established ---//
1163
1164 int xLoc, yLoc;
1165
1166 for( yLoc=loc_y1 ; yLoc<=loc_y2 ; yLoc++ )
1167 {
1168 for( xLoc=loc_x1 ; xLoc<=loc_x2 ; xLoc++ )
1169 {
1170 world.get_loc(xLoc, yLoc)->set_firm(firm_recno);
1171 }
1172 }
1173
1174 //--- if a nation set up a town in a location that the player has explored, contact between the nation and the player is established ---//
1175
1176 establish_contact_with_player();
1177
1178 //------------ reveal new land ----------//
1179
1180 if( nation_recno == nation_array.player_recno ||
1181 (nation_recno && nation_array[nation_recno]->is_allied_with_player) )
1182 {
1183 world.unveil( loc_x1, loc_y1, loc_x2, loc_y2 );
1184 world.visit( loc_x1, loc_y1, loc_x2, loc_y2, EXPLORE_RANGE-1 );
1185 }
1186
1187 //-------- set should_set_power --------//
1188
1189 should_set_power = get_should_set_power();
1190
1191 //---- set this town's influence on the map ----//
1192
1193 if( should_set_power )
1194 world.set_power(loc_x1, loc_y1, loc_x2, loc_y2, nation_recno);
1195
1196 //---- if the newly built firm is visual in the zoom window, redraw the zoom buffer ----//
1197
1198 if( is_in_zoom_win() )
1199 sys.zoom_need_redraw = 1; // set the flag on so it will be redrawn in the next frame
1200 }
1201 //----------- End of function Firm::set_world_matrix --------//
1202
1203
1204 //--------- Begin of function Firm::get_should_set_power --------//
1205 //
get_should_set_power()1206 int Firm::get_should_set_power()
1207 {
1208 int shouldSetPower = 1;
1209
1210 if( firm_id == FIRM_HARBOR ) // don't set power for harbors
1211 {
1212 shouldSetPower = 0;
1213 }
1214 else if( firm_id == FIRM_MARKET )
1215 {
1216 //--- don't set power for a market if it's linked to another nation's town ---//
1217
1218 Town *townPtr;
1219
1220 shouldSetPower = 0;
1221
1222 //--- only set the shouldSetPower to 1 if the market is linked to a firm of ours ---//
1223
1224 for( int i=0 ; i<linked_town_count ; i++ )
1225 {
1226 townPtr = town_array[ linked_town_array[i] ];
1227
1228 if( townPtr->nation_recno == nation_recno )
1229 {
1230 shouldSetPower = 1;
1231 break;
1232 }
1233 }
1234 }
1235
1236 return shouldSetPower;
1237 }
1238 //----------- End of function Firm::get_should_set_power --------//
1239
1240
1241 //------- Begin of function Firm::establish_contact_with_player --------//
1242 //
1243 // See if the town's location is an explored area, establish contact
1244 // with the player.
1245 //
establish_contact_with_player()1246 void Firm::establish_contact_with_player()
1247 {
1248 if( !nation_recno )
1249 return;
1250
1251 int xLoc, yLoc;
1252 Location* locPtr;
1253
1254 for( yLoc=loc_y1 ; yLoc<=loc_y2 ; yLoc++ )
1255 {
1256 for( xLoc=loc_x1 ; xLoc<=loc_x2 ; xLoc++ )
1257 {
1258 locPtr = world.get_loc(xLoc, yLoc);
1259
1260 locPtr->set_firm(firm_recno);
1261
1262 if( locPtr->explored() && nation_array.player_recno )
1263 {
1264 NationRelation *relation = (~nation_array)->get_relation(nation_recno);
1265
1266 if( !remote.is_enable() )
1267 {
1268 relation->has_contact = 1;
1269 }
1270 else
1271 {
1272 if( !relation->has_contact && !relation->contact_msg_flag )
1273 {
1274 // packet structure : <player nation> <explored nation>
1275 short *shortPtr = (short *)remote.new_send_queue_msg(MSG_NATION_CONTACT, 2*sizeof(short));
1276 *shortPtr = nation_array.player_recno;
1277 shortPtr[1] = nation_recno;
1278 relation->contact_msg_flag = 1;
1279 }
1280 }
1281 }
1282 }
1283 }
1284 }
1285 //-------- End of function Firm::establish_contact_with_player --------//
1286
1287
1288 //--------- Begin of function Firm::restore_world_matrix --------//
1289 //
1290 // When the firm is destroyed, restore the original land id
1291 //
restore_world_matrix()1292 void Firm::restore_world_matrix()
1293 {
1294 int xLoc, yLoc;
1295
1296 for( yLoc=loc_y1 ; yLoc<=loc_y2 ; yLoc++ )
1297 {
1298 for( xLoc=loc_x1 ; xLoc<=loc_x2 ; xLoc++ )
1299 {
1300 err_when( world.get_loc(xLoc,yLoc)->firm_recno() != firm_recno );
1301
1302 world.get_loc(xLoc,yLoc)->remove_firm();
1303 }
1304 }
1305
1306 //---- restore this town's influence on the map ----//
1307
1308 if( should_set_power ) // no power region for harbor as it build on coast which cannot be set with power region
1309 world.restore_power(loc_x1, loc_y1, loc_x2, loc_y2, 0, firm_recno);
1310
1311 //---- if the newly built firm is visual in the zoom window, redraw the zoom buffer ----//
1312
1313 if( is_in_zoom_win() )
1314 sys.zoom_need_redraw = 1;
1315 }
1316 //----------- End of function Firm::restore_world_matrix --------//
1317
1318
1319 //---------- Begin of function Firm::own_firm --------//
1320 //
own_firm()1321 int Firm::own_firm()
1322 {
1323 return nation_recno == nation_array.player_recno;
1324 }
1325 //----------- End of function Firm::own_firm ---------//
1326
1327
1328 //---------- Begin of function Firm::process_animation --------//
1329 //
process_animation()1330 void Firm::process_animation()
1331 {
1332 //-------- process animation ----------//
1333
1334 FirmBuild* firmBuild = firm_res.get_build(firm_build_id);
1335 int frameCount = firmBuild->frame_count;
1336
1337 if( frameCount==1 ) // no animation for this firm
1338 return;
1339
1340 //---------- next frame -----------//
1341
1342 if( --remain_frame_delay==0 ) // if it is in the delay between frames
1343 {
1344 remain_frame_delay = (char) firmBuild->frame_delay(cur_frame);
1345
1346 if( ++cur_frame > frameCount )
1347 {
1348 if( firmBuild->animate_full_size )
1349 cur_frame = 1;
1350 else
1351 {
1352 cur_frame = 2; // start with the 2nd frame as the 1st frame is the common frame
1353 err_when( frameCount <=2 ); // for segmented animation, the minimum no. of frames must be 3, as the first one is the common frame
1354 }
1355 }
1356 }
1357 }
1358 //---------- End of function Firm::process_animation --------//
1359
1360
1361 //---------- Begin of function Firm::process_construction --------//
1362 //
process_construction()1363 void Firm::process_construction()
1364 {
1365 err_when(firm_id!=FIRM_MONSTER && builder_recno<=0);
1366 if(firm_id==FIRM_MONSTER)
1367 {
1368 //--------- process construction for monster firm ----------//
1369 hit_points++;
1370
1371 #ifdef DEBUG
1372 if( config.fast_build && nation_recno==nation_array.player_recno )
1373 hit_points += 10;
1374 #endif
1375
1376 if(hit_points>=max_hit_points)
1377 {
1378 hit_points = max_hit_points;
1379 under_construction = 0;
1380 }
1381 return;
1382 }
1383
1384 err_when(firm_id==FIRM_MONSTER);
1385
1386 if( !under_construction )
1387 return;
1388
1389 //--- can only do construction when the firm is not under attack ---//
1390
1391 if( info.game_date <= last_attacked_date+1 )
1392 return;
1393
1394 if( sys.frame_count%2!=0 ) // one build every 2 frames
1395 return;
1396
1397 //------ increase the construction progress ------//
1398
1399 Unit *unitPtr = unit_array[builder_recno];
1400
1401 if( unitPtr->skill.skill_id == SKILL_CONSTRUCTION ) // if builder unit has construction skill
1402 hit_points += 1+unitPtr->skill.skill_level/30;
1403 else
1404 hit_points++;
1405
1406 if( config.fast_build && nation_recno==nation_array.player_recno )
1407 hit_points += 10;
1408
1409 //----- increase skill level of the builder unit -----//
1410
1411 if( unitPtr->skill.skill_id == SKILL_CONSTRUCTION ) // if builder unit has construction skill
1412 {
1413 if( ++unitPtr->skill.skill_level_minor > 100 )
1414 {
1415 unitPtr->skill.skill_level_minor = 0;
1416
1417 if( unitPtr->skill.skill_level < 100 )
1418 unitPtr->skill.skill_level++;
1419 }
1420 }
1421
1422 //------- when the construction is complete ----------//
1423
1424 if( hit_points >= max_hit_points ) // finished construction
1425 {
1426 hit_points = max_hit_points;
1427
1428 int needAssignUnit=0;
1429
1430 under_construction = 0;
1431
1432 // ##### begin Gilbert 10/10 #######//
1433 if( nation_recno == nation_array.player_recno )
1434 se_res.far_sound(center_x, center_y, 1, 'S', unitPtr->sprite_id,
1435 "FINS", 'F', firm_id);
1436 // ##### end Gilbert 10/10 #######//
1437
1438 err_when(builder_recno<=0 || unit_array.is_deleted(builder_recno));
1439 err_when(unitPtr->nation_recno!=nation_recno);
1440
1441 FirmInfo* firmInfo=firm_res[firm_id];
1442
1443 if( (firmInfo->need_overseer || firmInfo->need_worker) &&
1444 (firmInfo->firm_skill_id==0 || firmInfo->firm_skill_id == (unitPtr->skill).skill_id) ) // the builder with the skill required
1445 {
1446 unitPtr->set_mode(0); // reset it from UNIT_MODE_CONSTRUCT
1447
1448 needAssignUnit=1;
1449 }
1450 else
1451 {
1452 set_builder(0);
1453 }
1454
1455 //---------------------------------------------------------------------------------------//
1456 // should call assign_unit() first before calling action_finished(...UNDER_CONSTRUCTION)
1457 //---------------------------------------------------------------------------------------//
1458
1459 if( needAssignUnit )
1460 {
1461 assign_unit(builder_recno);
1462 //------------------------------------------------------------------------------//
1463 // Note: there may be chance the unit cannot be assigned into the firm
1464 //------------------------------------------------------------------------------//
1465 if(!worker_count && !overseer_recno) // no assignment, can't assign
1466 {
1467 //------- init_sprite or delete the builder ---------//
1468 int xLoc=loc_x1, yLoc=loc_y1; // xLoc & yLoc are used for returning results
1469 SpriteInfo *spriteInfo = unitPtr->sprite_info;
1470 if(!locate_space(remove_firm, xLoc, yLoc, loc_x2, loc_y2, spriteInfo->loc_width, spriteInfo->loc_height))
1471 unit_array.disappear_in_firm(builder_recno); // kill the unit
1472 else
1473 unitPtr->init_sprite(xLoc, yLoc); // restore the unit
1474 }
1475 }
1476
1477 // ##### begin Gilbert 10/10 #######//
1478 //if( nation_recno == nation_array.player_recno )
1479 // se_res.far_sound(center_x, center_y, 1, 'S', unitPtr->sprite_id,
1480 // "FINS", 'F', firm_id);
1481 // ##### end Gilbert 10/10 #######//
1482
1483 builder_recno = 0;
1484 }
1485
1486 err_when (hit_points < 0 || hit_points > max_hit_points );
1487 }
1488 //---------- End of function Firm::process_construction --------//
1489
1490
1491 //---------- Begin of function Firm::set_builder --------//
1492 //
1493 // <short> newBuilderRecno - >0 the recno of the new builder unit.
1494 // 0 just remove the existing builder, do not assign new one.
1495 //
1496 // return: <int> 0-the old builder is killed
1497 // 1-the builder is changed successfully.
1498 //
set_builder(short newBuilderRecno)1499 int Firm::set_builder(short newBuilderRecno)
1500 {
1501 err_when( under_construction && newBuilderRecno==0 ); // can't remove the construction worker when the firm is under construction
1502
1503 //------------------------------------//
1504
1505 short oldBuilderRecno = builder_recno; // store the old builder recno
1506
1507 builder_recno = newBuilderRecno;
1508
1509 //-------- assign the new builder ---------//
1510
1511 if(builder_recno)
1512 {
1513 Unit* unitPtr = unit_array[builder_recno];
1514 //### begin alex 18/10 ###//
1515 unitPtr->group_select_id = 0; // clear group select id
1516 //#### end alex 18/10 ####//
1517 if(unitPtr->is_visible()) // is visible if the unit is not inside the firm location
1518 {
1519 builder_region_id = world.get_region_id( unitPtr->cur_x_loc(), unitPtr->cur_y_loc() );
1520 unitPtr->deinit_sprite();
1521
1522 if( unitPtr->selected_flag )
1523 {
1524 unitPtr->selected_flag = 0;
1525 unit_array.selected_count--;
1526 }
1527 }
1528
1529 err_when( unitPtr->unit_mode != 0 );
1530 unitPtr->set_mode( UNIT_MODE_CONSTRUCT, firm_recno );
1531 }
1532
1533 if(oldBuilderRecno)
1534 mobilize_builder(oldBuilderRecno);
1535
1536 return 1;
1537 }
1538 //---------- End of function Firm::set_builder --------//
1539
1540
1541 //---------- Begin of function Firm::next_day --------//
1542 //
next_day()1543 void Firm::next_day()
1544 {
1545 if( !nation_recno )
1546 return;
1547
1548 //------ think about updating link status -------//
1549 //
1550 // This part must be done here instead of in
1551 // process_ai() because it will be too late to do
1552 // it in process_ai() as the next_day() will call
1553 // first and some wrong goods may be input to markets.
1554 //
1555 //-----------------------------------------------//
1556
1557 if( firm_ai )
1558 {
1559 if( info.game_date%30==firm_recno%30 || !ai_link_checked ) // once 30 days or when the link has been changed.
1560 {
1561 ai_update_link_status();
1562 ai_link_checked = 1;
1563 }
1564 }
1565
1566 //-------- pay expenses ----------//
1567
1568 pay_expense();
1569
1570 //------- update loyalty --------//
1571
1572 if( info.game_date%30 == firm_recno%30 )
1573 update_loyalty();
1574
1575 //-------- consume food --------//
1576
1577 if( !firm_res[firm_id]->live_in_town && worker_count>0 )
1578 consume_food();
1579
1580 //------ think worker migration -------//
1581
1582 if( worker_array && info.game_date%30 == firm_recno%30 )
1583 think_worker_migrate();
1584
1585 //--------- repairing ----------//
1586
1587 process_repair();
1588
1589 //------ catching spies -------//
1590
1591 if( info.game_date%30 == firm_recno%30 )
1592 spy_array.catch_spy(SPY_FIRM, firm_recno);
1593
1594 //----- process workers from other town -----//
1595
1596 if( firm_res[firm_id]->live_in_town )
1597 {
1598 process_independent_town_worker();
1599 }
1600
1601 //--- recheck no_neighbor_space after a period, there may be new space available now ---//
1602
1603 if( no_neighbor_space && info.game_date%180 == firm_recno%180 )
1604 {
1605 short buildXLoc, buildYLoc;
1606
1607 if( nation_array[nation_recno]->find_best_firm_loc(FIRM_INN, loc_x1, loc_y1, buildXLoc, buildYLoc) ) // whether it's FIRM_INN or not really doesn't matter, just any firm type will do
1608 no_neighbor_space = 0;
1609 }
1610
1611 //-------- debug code ---------//
1612
1613 #ifdef DEBUG
1614 err_when( builder_recno && unit_array.is_deleted(builder_recno) );
1615
1616 if( worker_array )
1617 {
1618 for( int i=0 ; i<worker_count ; i++ )
1619 err_when( worker_array[i].hit_points <= 0 );
1620 }
1621
1622 if( overseer_recno )
1623 {
1624 err_when( unit_array[overseer_recno]->rank_id == RANK_SOLDIER );
1625 }
1626 #endif
1627 }
1628 //----------- End of function Firm::next_day ---------//
1629
1630
1631 //---------- Begin of function Firm::next_month --------//
1632 //
next_month()1633 void Firm::next_month()
1634 {
1635 //------ update nation power recno ------//
1636
1637 int newShouldSetPower = get_should_set_power();
1638
1639 if( newShouldSetPower == should_set_power )
1640 return;
1641
1642 if( should_set_power )
1643 world.restore_power(loc_x1, loc_y1, loc_x2, loc_y2, 0, firm_recno);
1644
1645 should_set_power = newShouldSetPower;
1646
1647 if( should_set_power )
1648 world.set_power(loc_x1, loc_y1, loc_x2, loc_y2, nation_recno);
1649 }
1650 //----------- End of function Firm::next_month ---------//
1651
1652
1653 //---------- Begin of function Firm::next_year --------//
1654 //
next_year()1655 void Firm::next_year()
1656 {
1657 //------- post income data --------//
1658
1659 last_year_income = cur_year_income;
1660 cur_year_income = (float) 0;
1661 }
1662 //----------- End of function Firm::next_year ---------//
1663
1664
1665 //---------- Begin of function Firm::update_loyalty --------//
1666 //
update_loyalty()1667 void Firm::update_loyalty()
1668 {
1669 if( firm_res[firm_id]->live_in_town ) // only for those who do not live in town
1670 return;
1671
1672 //----- update loyalty of the soldiers -----//
1673
1674 Worker* workerPtr = worker_array;
1675
1676 for( int i=0 ; i<worker_count ; i++, workerPtr++ )
1677 {
1678 int targetLoyalty = workerPtr->target_loyalty(firm_recno);
1679
1680 if( targetLoyalty > workerPtr->worker_loyalty )
1681 {
1682 int incValue = (targetLoyalty - workerPtr->worker_loyalty)/10;
1683
1684 int newLoyalty = (int) workerPtr->worker_loyalty + MAX(1, incValue);
1685
1686 if( newLoyalty > targetLoyalty )
1687 newLoyalty = targetLoyalty;
1688
1689 workerPtr->worker_loyalty = newLoyalty;
1690 }
1691 else if( targetLoyalty < workerPtr->worker_loyalty )
1692 {
1693 workerPtr->worker_loyalty--;
1694 }
1695 }
1696 }
1697 //----------- End of function Firm::update_loyalty ---------//
1698
1699
1700 //---------- Begin of function Firm::process_repair --------//
1701 //
process_repair()1702 void Firm::process_repair()
1703 {
1704 if( nation_array[nation_recno]->cash < 0 ) // if you don't have cash, the repair workers will not work
1705 return;
1706
1707 if( !builder_recno )
1708 return;
1709
1710 Unit *unitPtr = unit_array[builder_recno];
1711
1712 //--- can only do construction when the firm is not under attack ---//
1713
1714 if( info.game_date <= last_attacked_date+1 )
1715 {
1716 //---- if the construction worker is a spy, it will damage the building when the building is under attack ----//
1717
1718 if( unitPtr->spy_recno &&
1719 unitPtr->true_nation_recno() != nation_recno )
1720 {
1721 hit_points -= (float) spy_array[unitPtr->spy_recno]->spy_skill / 30;
1722
1723 if( hit_points < 0 )
1724 hit_points = (float) 0;
1725 }
1726
1727 return;
1728 }
1729
1730 //------- repair now - only process once every 3 days -----//
1731
1732 if( hit_points >= max_hit_points )
1733 return;
1734
1735 err_when( unitPtr->skill.skill_id != SKILL_CONSTRUCTION );
1736
1737 int dayInterval = (100-unitPtr->skill.skill_level)/20+1; // repair once every 1 to 6 days, depending on the skill level of the construction worker
1738
1739 if( firm_recno % dayInterval == info.game_date % dayInterval )
1740 {
1741 hit_points++;
1742
1743 if( hit_points > max_hit_points )
1744 hit_points = max_hit_points;
1745 }
1746 }
1747 //----------- End of function Firm::process_repair ---------//
1748
1749
1750 //---------- Begin of function Firm::pay_expense --------//
1751 //
pay_expense()1752 void Firm::pay_expense()
1753 {
1754 if( !nation_recno )
1755 return;
1756
1757 Nation* nationPtr = nation_array[nation_recno];
1758
1759 //-------- fixed expenses ---------//
1760
1761 float dayExpense = (float) firm_res[firm_id]->year_cost / 365;
1762
1763 if( nationPtr->cash >= dayExpense )
1764 {
1765 nationPtr->add_expense( EXPENSE_FIRM, dayExpense, 1 );
1766 }
1767 else
1768 {
1769 if( hit_points > 0 )
1770 hit_points--;
1771
1772 if( hit_points < 0 )
1773 hit_points = (float) 0;
1774
1775 //--- when the hit points drop to zero and the firm is destroyed ---//
1776
1777 if( hit_points==0 && nation_recno == nation_array.player_recno )
1778 news_array.firm_worn_out(firm_recno);
1779 }
1780
1781 //----- paying salary to workers from other nations -----//
1782
1783 if( worker_array && firm_res[firm_id]->live_in_town )
1784 {
1785 int townNationRecno, payWorkerCount=0;
1786 Worker* workerPtr;
1787
1788 for( int i=worker_count-1 ; i>=0 ; i-- )
1789 {
1790 workerPtr = worker_array+i;
1791
1792 townNationRecno = town_array[workerPtr->town_recno]->nation_recno;
1793
1794 if( townNationRecno != nation_recno )
1795 {
1796 //--- if we don't have cash to pay the foreign workers, resign them ---//
1797
1798 if( nationPtr->cash < 0 )
1799 {
1800 resign_worker(i+1);
1801 }
1802 else //----- pay salaries to the foreign workers now -----//
1803 {
1804 payWorkerCount++;
1805
1806 if( townNationRecno ) // the nation of the worker will get income
1807 nation_array[townNationRecno]->add_income( INCOME_FOREIGN_WORKER, (float) WORKER_YEAR_SALARY / 365, 1 );
1808 }
1809 }
1810 }
1811
1812 nationPtr->add_expense( EXPENSE_FOREIGN_WORKER, (float) WORKER_YEAR_SALARY * payWorkerCount / 365, 1 );
1813 }
1814 }
1815 //----------- End of function Firm::pay_expense ---------//
1816
1817
1818 //--------- Begin of function Firm::consume_food ---------//
1819 //
consume_food()1820 void Firm::consume_food()
1821 {
1822 if( nation_array[nation_recno]->food > 0 )
1823 {
1824 int humanUnitCount=0;
1825
1826 for( int i=0 ; i<worker_count ; i++ )
1827 {
1828 if( worker_array[i].race_id )
1829 humanUnitCount++;
1830 }
1831
1832 nation_array[nation_recno]->consume_food((float) humanUnitCount * PERSON_FOOD_YEAR_CONSUMPTION / 365);
1833 }
1834 else //--- decrease loyalty if the food has been run out ---//
1835 {
1836 if( info.game_date%NO_FOOD_LOYALTY_DECREASE_INTERVAL == 0 ) // decrease 1 loyalty point every 2 days
1837 {
1838 for( int i=0 ; i<worker_count ; i++ )
1839 {
1840 if( worker_array[i].race_id )
1841 worker_array[i].change_loyalty(-1);
1842 }
1843 }
1844 }
1845 }
1846 //----------- End of function Firm::consume_food -----------//
1847
1848
1849 //---------- Begin of function Firm::add_income --------//
1850 //
add_income(int incomeType,float incomeAmt)1851 void Firm::add_income(int incomeType, float incomeAmt)
1852 {
1853 cur_year_income += incomeAmt;
1854
1855 nation_array[nation_recno]->add_income(incomeType, incomeAmt, 1);
1856 }
1857 //----------- End of function Firm::add_income ---------//
1858
1859
1860 //--------- Begin of function Firm::year_expense ---------//
1861 //
1862 // Return the yearly expense for this firm.
1863 //
year_expense()1864 int Firm::year_expense()
1865 {
1866 int totalExpense = firm_res[firm_id]->year_cost;
1867
1868 //---- pay salary to workers from foreign towns ----//
1869
1870 int payWorkerCount=0;
1871
1872 if( worker_array && firm_res[firm_id]->live_in_town )
1873 {
1874 int payWorkerCount=0;
1875 Worker* workerPtr = worker_array;
1876
1877 for( int i=0 ; i<worker_count ; i++, workerPtr++ )
1878 {
1879 if( town_array[workerPtr->town_recno]->nation_recno != nation_recno )
1880 payWorkerCount++;
1881 }
1882
1883 totalExpense += WORKER_YEAR_SALARY * payWorkerCount;
1884 }
1885
1886 return totalExpense;
1887 }
1888 //----------- End of function Firm::year_expense -----------//
1889
1890
1891 //--------- Begin of function Firm::sell_firm ---------//
1892
sell_firm(char remoteAction)1893 void Firm::sell_firm(char remoteAction)
1894 {
1895 if( !remoteAction && remote.is_enable() )
1896 {
1897 // packet structure : <firm recno>
1898 short *shortPtr = (short *)remote.new_send_queue_msg(MSG_FIRM_SELL, sizeof(short));
1899 *shortPtr = firm_recno;
1900 return;
1901 }
1902 //------- sell at 50% of the original cost -------//
1903
1904 Nation* nationPtr = nation_array[nation_recno];
1905
1906 int sellIncome = firm_res[firm_id]->setup_cost / 2 * (int) hit_points / (int) max_hit_points;
1907
1908 nationPtr->add_income(INCOME_SELL_FIRM, (float)sellIncome);
1909
1910 se_res.sound(center_x, center_y, 1, 'F', firm_id, "SELL" );
1911
1912 firm_array.del_firm(firm_recno);
1913 }
1914 //----------- End of function Firm::sell_firm -----------//
1915
1916
1917 //--------- Begin of function Firm::destruct_firm ---------//
1918
destruct_firm(char remoteAction)1919 void Firm::destruct_firm(char remoteAction)
1920 {
1921 if( !remoteAction && remote.is_enable() )
1922 {
1923 // packet structure : <firm recno>
1924 short *shortPtr = (short *)remote.new_send_queue_msg(MSG_FIRM_DESTRUCT, sizeof(short));
1925 *shortPtr = firm_recno;
1926 return;
1927 }
1928
1929 se_res.sound(center_x, center_y, 1, 'F', firm_id, "DEST" );
1930
1931 firm_array.del_firm(firm_recno);
1932 }
1933 //----------- End of function Firm::destruct_firm -----------//
1934
1935
1936 //--------- Begin of function Firm::cancel_construction ---------//
1937 //
1938 // Cancel construction
1939 //
cancel_construction(char remoteAction)1940 void Firm::cancel_construction(char remoteAction)
1941 {
1942 if( !remoteAction && remote.is_enable())
1943 {
1944 short *shortPtr = (short *)remote.new_send_queue_msg(MSG_FIRM_CANCEL, sizeof(short));
1945 shortPtr[0] = firm_recno;
1946 return;
1947 }
1948 //------ get half of the construction cost back -------//
1949
1950 Nation* nationPtr = nation_array[nation_recno];
1951
1952 nationPtr->add_expense( EXPENSE_FIRM, (float) -firm_res[firm_id]->setup_cost/2 );
1953
1954 firm_array.del_firm(firm_recno);
1955 }
1956 //----------- End of function Firm::cancel_construction -----------//
1957
1958
1959 //---------- Begin of function Firm::recruit_worker --------//
1960 //
recruit_worker()1961 void Firm::recruit_worker()
1962 {
1963 if( MAX_WORKER==worker_count )
1964 return;
1965
1966 if( info.game_date%5 != firm_recno%5 ) // update population once 10 days
1967 return;
1968
1969 err_when( worker_count > MAX_WORKER );
1970
1971 //-------- pull from neighbor towns --------//
1972
1973 int i;
1974 Town* townPtr;
1975 Nation* nationPtr = nation_array[nation_recno];
1976
1977 for( i=0 ; i<linked_town_count ; i++ )
1978 {
1979 if( linked_town_enable_array[i] != LINK_EE )
1980 continue;
1981
1982 townPtr = town_array[linked_town_array[i]];
1983
1984 //--- don't hire foreign workers if we don't have cash to pay them ---//
1985
1986 if( nationPtr->cash < 0 && nation_recno != townPtr->nation_recno )
1987 continue;
1988
1989 //-------- if the town has any unit ready for jobs -------//
1990
1991 if( townPtr->jobless_population == 0 )
1992 continue;
1993
1994 //---- if nation of the town is not hositle to this firm's nation ---//
1995
1996 if( pull_town_people(townPtr->town_recno, COMMAND_AUTO) )
1997 return;
1998 }
1999 }
2000 //----------- End of function Firm::recruit_worker ---------//
2001
2002
2003 //---------- Begin of function Firm::pull_town_people --------//
2004 //
2005 // Pull people from the town. Also called by Town::draw_detect_link_line()
2006 //
2007 // <int> townRecno - the town recno which the people are pulled from.
2008 // [int] raceId - the race of the people to be pulled.
2009 // if not given, pick one randomly.
2010 // [int] forcePull - force pull people to to the firm.
2011 // (default: 0)
2012 //
pull_town_people(int townRecno,char remoteAction,int raceId,int forcePull)2013 int Firm::pull_town_people(int townRecno, char remoteAction, int raceId, int forcePull)
2014 {
2015 if( worker_count == MAX_WORKER ) // this can happen in a multiplayer game as Town::draw_detect_link_line() still have the old worker_count and thus allow this function being called.
2016 return 0;
2017
2018 err_when( worker_count > MAX_WORKER );
2019 err_when( !worker_array ); // this function shouldn't be called if this firm does not need worker
2020
2021 if(!remoteAction && remote.is_enable() )
2022 {
2023 // packet structure : <firm recno> <town recno> <race Id or 0> <force Pull>
2024 short *shortPtr = (short *)remote.new_send_queue_msg(MSG_FIRM_PULL_TOWN_PEOPLE, 4*sizeof(short));
2025 shortPtr[0] = firm_recno;
2026 shortPtr[1] = townRecno;
2027 shortPtr[2] = raceId;
2028 // if raceId == 0, let each player choose the race by random number,
2029 // to sychronize the random number
2030 shortPtr[3] = forcePull;
2031 return 0;
2032 }
2033
2034 //---- people in the town go to work for the firm ---//
2035
2036 Town* townPtr = town_array[townRecno];
2037 int i, popAdded=0;
2038
2039 //---- if doesn't specific a race, randomly pick one ----//
2040
2041 if( !raceId )
2042 raceId = misc.random(MAX_RACE)+1;
2043
2044 //----------- scan the races -----------//
2045
2046 for( i=0 ; i<MAX_RACE ; i++ ) // maximum 8 tries
2047 {
2048 //---- see if there is any population of this race to move to the firm ----//
2049
2050 int recruitableCount = townPtr->recruitable_race_pop(raceId,1); // 1-allow recruiting spies
2051
2052 if( recruitableCount > 0 )
2053 {
2054 //----- if the unit is forced to move to the firm ---//
2055
2056 if( forcePull ) // right-click to force pulling a worker from the village
2057 {
2058 if( townPtr->race_loyalty_array[raceId-1] < MIN_RECRUIT_LOYALTY )
2059 return 0;
2060
2061 townPtr->recruit_dec_loyalty(raceId);
2062 }
2063 else //--- see if the unit will voluntarily move to the firm ---//
2064 {
2065 //--- the higher the loyalty is, the higher the chance of working for the firm ---//
2066
2067 if( townPtr->nation_recno )
2068 {
2069 if( misc.random( (100-(int)townPtr->race_loyalty_array[raceId-1])/10 ) > 0 )
2070 return 0;
2071 }
2072 else
2073 {
2074 if( misc.random( (100-(int)townPtr->race_resistance_array[raceId-1][nation_recno-1])/10 ) > 0 )
2075 return 0;
2076 }
2077 }
2078
2079 //----- get the chance of getting people to your command base is higher when the loyalty is higher ----//
2080
2081 if( firm_res[firm_id]->live_in_town )
2082 {
2083 townPtr->jobless_race_pop_array[raceId-1]--; // decrease the town's population
2084 townPtr->jobless_population--;
2085
2086 err_when( townPtr->recruitable_race_pop(raceId,1) < 0 );
2087 err_when( townPtr->jobless_population < 0 );
2088 }
2089 else
2090 {
2091 townPtr->dec_pop(raceId, 0);
2092 }
2093
2094 //------- add the worker to the firm -----//
2095
2096 worker_count++;
2097
2098 err_when( worker_count > MAX_WORKER );
2099
2100 Worker* workerPtr = worker_array + worker_count - 1;
2101
2102 memset( workerPtr, 0, sizeof(Worker) );
2103
2104 workerPtr->race_id = raceId;
2105 workerPtr->rank_id = RANK_SOLDIER;
2106 workerPtr->unit_id = (char) race_res[raceId]->basic_unit_id;
2107 workerPtr->worker_loyalty = (char) townPtr->race_loyalty_array[raceId-1];
2108
2109 if( firm_res[firm_id]->live_in_town )
2110 workerPtr->town_recno = townRecno;
2111
2112 workerPtr->combat_level = CITIZEN_COMBAT_LEVEL;
2113 workerPtr->hit_points = CITIZEN_HIT_POINTS;
2114
2115 workerPtr->skill_id = firm_skill_id;
2116 workerPtr->skill_level = CITIZEN_SKILL_LEVEL;
2117
2118 workerPtr->init_potential();
2119
2120 //--------- if this is a military camp ---------//
2121 //
2122 // Increase armed unit count of the race of the worker assigned,
2123 // as when a unit is assigned to a camp, Unit::deinit() will decrease
2124 // the counter, so we need to increase it back here.
2125 //
2126 //---------------------------------------------------//
2127
2128 if( !firm_res[firm_id]->live_in_town )
2129 unit_res[workerPtr->unit_id]->inc_nation_unit_count(nation_recno);
2130
2131 //------ if the recruited worker is a spy -----//
2132
2133 int spyCount = townPtr->race_spy_count_array[raceId-1];
2134
2135 if( spyCount >= misc.random(recruitableCount)+1 )
2136 {
2137 int spyRecno = spy_array.find_town_spy(townRecno, raceId, misc.random(spyCount)+1 ); // the 3rd parameter is which spy to recruit
2138
2139 err_when( !spyRecno );
2140
2141 workerPtr->spy_recno = spyRecno;
2142
2143 spy_array[spyRecno]->set_place(SPY_FIRM, firm_recno);
2144 }
2145
2146 return 1;
2147 }
2148
2149 if( ++raceId > MAX_RACE )
2150 raceId = 1;
2151 }
2152
2153 return 0;
2154 }
2155 //----------- End of function Firm::pull_town_people ---------//
2156
2157
2158 //------ Begin of function Firm::process_independent_town_worker -----//
2159 //
2160 // Process workers from independent towns.
2161 //
2162 // When workers work for a foreign firm, the overall resistance of
2163 // the worker's town towards that nation decreases.
2164 //
process_independent_town_worker()2165 void Firm::process_independent_town_worker()
2166 {
2167 if( firm_recno%15 != info.game_date%15 )
2168 return;
2169
2170 #define RESISTANCE_DECREASE_PER_WORKER float(0.2) // resistance decrease per month every 15 days
2171
2172 Town* townPtr;
2173
2174 for( int i=0 ; i<worker_count ; i++ )
2175 {
2176 err_when( !worker_array[i].town_recno );
2177
2178 townPtr = town_array[ worker_array[i].town_recno ];
2179
2180 if( townPtr->nation_recno==0 ) // if it's an independent town
2181 {
2182 townPtr->race_resistance_array[worker_array[i].race_id-1][nation_recno-1] -= RESISTANCE_DECREASE_PER_WORKER;
2183
2184 if( townPtr->race_resistance_array[worker_array[i].race_id-1][nation_recno-1] < 0 )
2185 townPtr->race_resistance_array[worker_array[i].race_id-1][nation_recno-1] = (float) 0;
2186 }
2187 }
2188 }
2189 //------- End of function Firm::process_independent_town_worker ------//
2190
2191
2192 //---------- Begin of function Worker::init_potential --------//
2193 //
init_potential()2194 void Worker::init_potential()
2195 {
2196 if( misc.random(10)==0 ) // 1 out of 10 has a higher than normal potential in this skill
2197 {
2198 skill_potential = 50+misc.random(51); // 50 to 100 potential
2199 }
2200 }
2201 //----------- End of function Worker::init_potential ---------//
2202
2203
2204 //---------- Begin of function Firm::calc_productivity --------//
2205 //
2206 // Calculate the productivity of the firm.
2207 //
calc_productivity()2208 void Firm::calc_productivity()
2209 {
2210 err_when( !worker_array ); // this function shouldn't be called if this firm does not need worker
2211
2212 #define RACE_SKILL_MULTIPLE (float)2.0
2213
2214 productivity = (float) 0;
2215
2216 //------- calculate the productivity of the workers -----------//
2217
2218 int i;
2219 float totalSkill=(float)0;
2220 Worker* workerPtr = worker_array;
2221
2222 for( i=0 ; i<worker_count ; i++, workerPtr++ )
2223 {
2224 totalSkill += (int) workerPtr->skill_level
2225 * workerPtr->hit_points / workerPtr->max_hit_points();
2226 }
2227
2228 //----- include skill in the calculation ------//
2229
2230 productivity = totalSkill / MAX_WORKER - sabotage_level;
2231
2232 if( productivity < 0 )
2233 productivity = (float) 0;
2234 }
2235 //----------- End of function Firm::calc_productivity ---------//
2236
2237
2238 //---------- Begin of function Firm::average_worker_skill --------//
2239 //
2240 // Return the average skill level of the workers in this firm.
2241 //
average_worker_skill()2242 int Firm::average_worker_skill()
2243 {
2244 err_when( !worker_array ); // this function shouldn't be called if this firm does not need worker
2245
2246 if( worker_count==0 )
2247 return 0;
2248
2249 //------- calculate the productivity of the workers -----------//
2250
2251 int i;
2252 int totalSkill = 0;
2253 Worker* workerPtr = worker_array;
2254
2255 for( i=0 ; i<worker_count ; i++, workerPtr++ )
2256 totalSkill += workerPtr->skill_level;
2257
2258 //----- include skill in the calculation ------//
2259
2260 return totalSkill / worker_count;
2261 }
2262 //----------- End of function Firm::average_worker_skill ---------//
2263
2264
2265 //---------- Begin of function Firm::update_worker --------//
2266 //
update_worker()2267 void Firm::update_worker()
2268 {
2269 err_when( !worker_array ); // this function shouldn't be called if this firm does not need worker
2270
2271 if( info.game_date%15 != firm_recno%15 )
2272 return;
2273
2274 if( worker_count==0 )
2275 return;
2276
2277 //------- update the worker's para ---------//
2278
2279 int incValue, levelMinor;
2280 Worker* workerPtr = worker_array;
2281
2282 for( int i=0 ; i<worker_count ; i++, workerPtr++ )
2283 {
2284 //------- increase worker skill -----------//
2285
2286 if( is_operating() && workerPtr->skill_level < 100 ) // only train when the workers are working
2287 {
2288 err_when(workerPtr->skill_level<0 || workerPtr->skill_level>100);
2289
2290 incValue = MAX(10, 100-workerPtr->skill_level)
2291 * workerPtr->hit_points / workerPtr->max_hit_points()
2292 * (100+workerPtr->skill_potential) / 100 / 2;
2293
2294 //-------- increase level minor now --------//
2295
2296 levelMinor = workerPtr->skill_level_minor + incValue * (75+misc.random(50)) / 100; // with random factors, resulting in 75% to 125% of the original
2297
2298 int loopCount=0;
2299
2300 while( levelMinor >= 100 )
2301 {
2302 levelMinor -= 100;
2303 workerPtr->skill_level++;
2304
2305 err_when( loopCount++ > 1000 );
2306 }
2307
2308 workerPtr->skill_level_minor = levelMinor;
2309 }
2310
2311 //------- increase worker hit points --------//
2312
2313 int maxHitPoints = workerPtr->max_hit_points();
2314
2315 err_when( maxHitPoints <= 0 );
2316
2317 if( workerPtr->hit_points < maxHitPoints )
2318 {
2319 workerPtr->hit_points += 2; // units in firms recover twice as fast as they are mobile
2320
2321 if( workerPtr->hit_points > maxHitPoints )
2322 workerPtr->hit_points = maxHitPoints;
2323 }
2324 }
2325
2326 sort_worker();
2327 }
2328 //----------- End of function Firm::update_worker ---------//
2329
2330
2331 //---------- Begin of function Firm::create_unit --------//
2332 //
2333 // Create an unit and place it below the firm.
2334 //
2335 // <int> unitId - id. of the unit
2336 // [int] townRecno - recno of the town from which the unit comes from
2337 // if given, it means the unit comes from the town and
2338 // should decrease the town population.
2339 // (default: 0)
2340 // [int] unitHasJob - whether the unit current has a job or not
2341 // (default: 0)
2342 //
2343 // return : <int> unitRecno - the recno of the unit created
2344 //
create_unit(int unitId,int townRecno,int unitHasJob)2345 int Firm::create_unit(int unitId, int townRecno, int unitHasJob)
2346 {
2347 //----look for an empty locatino for the unit to stand ----//
2348 //--- scan for the 5 rows right below the building ---//
2349
2350 SpriteInfo* spriteInfo = sprite_res[unit_res[unitId]->sprite_id];
2351 int xLoc=loc_x1, yLoc=loc_y1; // xLoc & yLoc are used for returning results
2352
2353 if(!locate_space(remove_firm, xLoc, yLoc, loc_x2, loc_y2, spriteInfo->loc_width, spriteInfo->loc_height))
2354 return 0;
2355
2356 //------------ add the unit now ----------------//
2357
2358 int unitNationRecno;
2359
2360 if( townRecno )
2361 unitNationRecno = town_array[townRecno]->nation_recno;
2362 else
2363 unitNationRecno = nation_recno;
2364
2365 int unitRecno = unit_array.add_unit( unitId, unitNationRecno, RANK_SOLDIER, 0, xLoc, yLoc );
2366
2367 //----- update the population of the town ------//
2368
2369 if( townRecno )
2370 town_array[townRecno]->dec_pop(unit_array[unitRecno]->race_id, unitHasJob);
2371
2372 return unitRecno;
2373 }
2374 //----------- End of function Firm::create_unit ---------//
2375
2376
2377 //--------- Begin of function Firm::mobilize_worker ---------//
2378 //
2379 // Promote a firm worker as a unit.
2380 //
2381 // return: <int> the recno of the unit created.
2382 //
mobilize_worker(int workerId,char remoteAction)2383 int Firm::mobilize_worker(int workerId, char remoteAction)
2384 {
2385 err_when( workerId<1 || workerId>worker_count );
2386
2387 Worker *workerPtr = worker_array+workerId-1;
2388
2389 if( remoteAction <= COMMAND_REMOTE && !workerPtr->is_nation(firm_recno, nation_recno) )
2390 {
2391 // cannot order mobilization of foreign workers
2392 return 0;
2393 }
2394
2395 if(!remoteAction && remote.is_enable() )
2396 {
2397 // packet strcture : <firm_recno> <workerId>
2398 short *shortPtr = (short *)remote.new_send_queue_msg(MSG_FIRM_MOBL_WORKER, 2*sizeof(short) );
2399 shortPtr[0] = firm_recno;
2400 shortPtr[1] = workerId;
2401 return 0;
2402 }
2403
2404 err_when( !worker_array ); // this function shouldn't be called if this firm does not need worker
2405
2406 //------------- resign worker --------------//
2407
2408 Worker thisWorker = *workerPtr;
2409
2410 int oldWorkerCount = worker_count;
2411
2412 int unitRecno2 = resign_worker(workerId);
2413
2414 if(!unitRecno2 && worker_count==oldWorkerCount)
2415 return 0;
2416
2417 //------ create a mobile unit -------//
2418
2419 int unitRecno=0;
2420
2421 if( firm_res[firm_id]->live_in_town ) // if does not live_in_town, resign_worker() create the unit already, so don't create it again here.
2422 {
2423 unitRecno = create_worker_unit(thisWorker);
2424
2425 if( !unitRecno ) // no space for creating units
2426 return 0;
2427 }
2428
2429 //------------------------------------//
2430
2431 err_when( unitRecno2 && unitRecno ); // only one of them should have value
2432 err_when( !unitRecno2 && !unitRecno ); // one of them must have a value
2433
2434 sort_worker();
2435
2436 if( unitRecno )
2437 return unitRecno;
2438 else
2439 return unitRecno2;
2440 }
2441 //----------- End of function Firm::mobilize_worker -----------//
2442
2443
2444 //--------- Begin of function Firm::create_worker_unit ---------//
2445 //
create_worker_unit(Worker & thisWorker)2446 int Firm::create_worker_unit(Worker& thisWorker)
2447 {
2448 //--------- copy the worker's info --------//
2449
2450 int unitLoyalty = thisWorker.loyalty();
2451
2452 //------------ create an unit --------------//
2453
2454 int unitId = thisWorker.unit_id;
2455 int unitRecno = create_unit( unitId, thisWorker.town_recno, 0 ); // this worker no longer has a job as it has been resigned
2456
2457 if( !unitRecno )
2458 return 0;
2459
2460 Unit* unitPtr = unit_array[unitRecno];
2461 UnitInfo *unitInfo = unit_res[unitId];
2462
2463 //------- set the unit's parameters --------//
2464
2465 unitPtr->skill.skill_id = thisWorker.skill_id;
2466 unitPtr->skill.skill_level = thisWorker.skill_level;
2467 unitPtr->skill.skill_level_minor = thisWorker.skill_level_minor;
2468
2469 err_when( unitPtr->skill.skill_level<0 || unitPtr->skill.skill_level>100 );
2470
2471 unitPtr->set_combat_level(thisWorker.combat_level);
2472 unitPtr->skill.combat_level_minor = thisWorker.combat_level_minor;
2473
2474 err_when( unitPtr->skill.combat_level<=0 || unitPtr->skill.combat_level>100 );
2475
2476 unitPtr->loyalty = unitLoyalty;
2477 unitPtr->hit_points = thisWorker.hit_points;
2478 unitPtr->rank_id = thisWorker.rank_id;
2479
2480 if( unit_res[unitPtr->unit_id]->unit_class == UNIT_CLASS_WEAPON )
2481 {
2482 unitPtr->set_weapon_version( thisWorker.extra_para ); // restore nation contribution
2483 }
2484 else if( unitPtr->race_id )
2485 {
2486 unitPtr->cur_power = thisWorker.extra_para;
2487
2488 if( unitPtr->cur_power < 0 )
2489 unitPtr->cur_power = 0;
2490
2491 if( unitPtr->cur_power > 150 )
2492 unitPtr->cur_power = 150;
2493 }
2494
2495 err_when( unitPtr->hit_points <= 0 );
2496
2497 unitPtr->fix_attack_info();
2498
2499 //if( unitInfo->unit_class == UNIT_CLASS_WEAPON )
2500 //{
2501 // switch( unitId )
2502 // {
2503 // case UNIT_BALLISTA:
2504 // unitPtr->attack_count = 2;
2505 // break;
2506 // case UNIT_EXPLOSIVE_CART:
2507 // unitPtr->attack_count = 0;
2508 // break;
2509 // default:
2510 // unitPtr->attack_count = 1;
2511 //}
2512 // if( unitPtr->attack_count > 0)
2513 // {
2514 // unitPtr->attack_info_array = unit_res.attack_info_array
2515 // + unitInfo->first_attack-1
2516 // + (thisWorker.extra_para -1) * unitPtr->attack_count; // extra para keeps the weapon version
2517 // }
2518 // else
2519 // {
2520 // // no attack like explosive cart
2521 // unitPtr->attack_info_array = NULL;
2522 // }
2523 // }
2524
2525 if( thisWorker.name_id && thisWorker.race_id ) // if this worker is formerly an unit who has a name
2526 unitPtr->set_name(thisWorker.name_id);
2527
2528 err_when( !unitPtr->is_visible() );
2529
2530 //------ if the unit is a spy -------//
2531
2532 if( thisWorker.spy_recno )
2533 {
2534 Spy* spyPtr = spy_array[thisWorker.spy_recno];
2535
2536 unitPtr->spy_recno = thisWorker.spy_recno;
2537 unitPtr->ai_unit = spyPtr->cloaked_nation_recno &&
2538 nation_array[spyPtr->cloaked_nation_recno]->is_ai();
2539
2540 unitPtr->set_name(spyPtr->name_id); // set the name id. of this unit
2541
2542 spyPtr->set_place(SPY_MOBILE, unitRecno);
2543 }
2544
2545 //--- decrease the nation unit count as the Unit has already increased it ----//
2546
2547 if( !firm_res[firm_id]->live_in_town ) // if the unit does not live in town, increase the unit count now
2548 unit_res[unitPtr->unit_id]->dec_nation_unit_count(nation_recno);
2549
2550 return unitRecno;
2551 }
2552 //----------- End of function Firm::create_worker_unit -----------//
2553
2554
2555 //--------- Begin of function Firm::mobilize_all_workers ---------//
2556 //
2557 // mobilize as many as workers if there is space for creating the
2558 // workers
2559 //
mobilize_all_workers(char remoteAction)2560 void Firm::mobilize_all_workers(char remoteAction)
2561 {
2562 if( !remoteAction && remote.is_enable() )
2563 {
2564 // packet strcture : <firm_recno>
2565 short *shortPtr = (short *)remote.new_send_queue_msg(MSG_FIRM_MOBL_ALL_WORKERS, sizeof(short) );
2566 shortPtr[0] = firm_recno;
2567 return;
2568 }
2569
2570 if (nation_recno == nation_array.player_recno)
2571 power.reset_selection();
2572
2573 err_when( !worker_array ); // this function shouldn't be called if this firm does not need worker
2574
2575 //------- detect buttons on hiring firm workers -------//
2576
2577 #ifdef DEBUG
2578 int loopCount = 0;
2579 #endif
2580
2581 short unitRecno;
2582 int mobileWorkerId = 1;
2583
2584 err_when( worker_count > MAX_WORKER );
2585
2586 while( worker_count > 0 && mobileWorkerId <= worker_count )
2587 {
2588 err_when(++loopCount > 100);
2589
2590 Worker *workerPtr = worker_array+mobileWorkerId-1;
2591
2592 if( !workerPtr->is_nation(firm_recno, nation_recno) )
2593 {
2594 // prohibit mobilizing workers not under your color
2595 mobileWorkerId++;
2596 continue;
2597 }
2598
2599 unitRecno = mobilize_worker(mobileWorkerId, COMMAND_AUTO); // always record 1 as the workers info are moved forward from the back to the front
2600
2601 if(!unitRecno)
2602 break; // keep the rest workers as there is no space for creating the unit
2603
2604 Unit* unitPtr = unit_array[unitRecno];
2605 unitPtr->team_id = unit_array.cur_team_id;
2606
2607 if( nation_recno == nation_array.player_recno )
2608 {
2609 unitPtr->selected_flag = 1;
2610 unit_array.selected_count++;
2611 if ( !unit_array.selected_recno )
2612 unit_array.selected_recno = unitRecno; // set first worker as selected
2613 }
2614 }
2615
2616 unit_array.cur_team_id++;
2617
2618 if( nation_recno == nation_array.player_recno ) // for player, mobilize_all_workers can only be called when the player presses the button.
2619 info.disp();
2620 }
2621 //----------- End of function Firm::mobilize_all_workers -----------//
2622
2623
2624 //--------- Begin of function Firm::resign_all_worker ---------//
2625 //
2626 // Resign all workers in the firm.
2627 //
2628 // [int] disappearFlag - whether the worker should disappear after
2629 // resigning, and does not go back to the town.
2630 //
resign_all_worker(int disappearFlag)2631 void Firm::resign_all_worker(int disappearFlag)
2632 {
2633 err_when( !worker_array ); // this function shouldn't be called if this firm does not need worker
2634
2635 //------- detect buttons on hiring firm workers -------//
2636
2637 int loopCount=0, townRecno, raceId;
2638 int oldWorkerCount;
2639
2640 while( worker_count > 0 )
2641 {
2642 err_when(++loopCount > 100);
2643
2644 townRecno = worker_array[0].town_recno;
2645 raceId = worker_array[0].race_id;
2646
2647 oldWorkerCount = worker_count;
2648
2649 if(!resign_worker(1))
2650 {
2651 if(oldWorkerCount==worker_count)
2652 break; // no space to resign the worker, keep them in firm
2653 }
2654
2655 if( disappearFlag && townRecno )
2656 town_array[townRecno]->dec_pop(raceId, 0);
2657 }
2658 }
2659 //----------- End of function Firm::resign_all_worker -----------//
2660
2661
2662 //--------- Begin of function Firm::resign_worker ---------//
2663 //
2664 // Resign the worker from the firm.
2665 //
2666 // return: <int> recno of the mobile unit created if there is one created.
2667 //
resign_worker(int workerId)2668 int Firm::resign_worker(int workerId)
2669 {
2670 err_when( !worker_array ); // this function shouldn't be called if this firm does not need worker
2671
2672 err_when( workerId<1 || workerId>worker_count );
2673
2674 //------- decrease worker no. and create an unit -----//
2675
2676 Worker* workerPtr = worker_array+workerId-1;
2677 int unitRecno = 0;
2678
2679 if( workerPtr->race_id && workerPtr->name_id )
2680 race_res[workerPtr->race_id]->free_name_id(workerPtr->name_id);
2681
2682 if( workerPtr->town_recno ) // town_recno is 0 if the workers in the firm do not live in towns
2683 {
2684 Town* townPtr = town_array[workerPtr->town_recno];
2685
2686 err_when(workerPtr->race_id < 1);
2687 townPtr->jobless_race_pop_array[workerPtr->race_id-1]++; // move into jobless population
2688 townPtr->jobless_population++;
2689
2690 //------ put the spy in the town -------//
2691
2692 if( workerPtr->spy_recno )
2693 spy_array[workerPtr->spy_recno]->set_place(SPY_TOWN, workerPtr->town_recno);
2694 }
2695 else
2696 {
2697 Worker thisWorker = worker_array[workerId-1];
2698
2699 unitRecno = create_worker_unit(thisWorker); // if he is a spy, create_worker_unit wil call set_place(SPY_MOBILE)
2700
2701 if(!unitRecno)
2702 return 0; // return 0 eg there is no space to create the unit
2703 }
2704
2705 //------- delete the record from the worker_array ------//
2706
2707 err_when( worker_count > MAX_WORKER );
2708 err_when( selected_worker_id > worker_count );
2709
2710 misc.del_array_rec(worker_array, worker_count, sizeof(Worker), workerId);
2711
2712 if( selected_worker_id > workerId || selected_worker_id == worker_count )
2713 selected_worker_id--;
2714
2715 worker_count--;
2716
2717 err_when( worker_count < 0 );
2718 err_when( selected_worker_id > worker_count );
2719
2720 return unitRecno;
2721 }
2722 //----------- End of function Firm::resign_worker -----------//
2723
2724
2725 //------- Begin of function Firm::think_worker_migrate ---------//
2726 //
2727 // Let the workers think if they want to worker_migrate or not.
2728 //
think_worker_migrate()2729 void Firm::think_worker_migrate()
2730 {
2731 #define MIN_MIGRATE_ATTRACT_LEVEL 30
2732
2733 if( worker_count==0 || !firm_res[firm_id]->live_in_town )
2734 return;
2735
2736 int townPtrCount = town_array.size();
2737 int townRecno = misc.random(townPtrCount)+1;
2738 int firmXLoc = center_x, firmYLoc = center_y;
2739 int i, j, raceId, workerId;
2740 Town *townPtr, *workerTownPtr;
2741 Worker *workerPtr;
2742
2743 int curBaseAttractLevel, targetBaseAttractLevel, curAttractLevel, targetAttractLevel;
2744
2745 for( i=townPtrCount ; i>0 ; i-- )
2746 {
2747 if( ++townRecno > townPtrCount )
2748 townRecno=1;
2749
2750 if( town_array.is_deleted(townRecno) )
2751 continue;
2752
2753 townPtr = town_array[townRecno];
2754
2755 if(townPtr->population>=MAX_TOWN_POPULATION)
2756 continue;
2757
2758 //------ check if this town is linked to the current firm -----//
2759
2760 for( j=townPtr->linked_firm_count-1 ; j>=0 ; j-- )
2761 {
2762 if( townPtr->linked_firm_array[j] == firm_recno &&
2763 townPtr->linked_firm_enable_array[j] )
2764 {
2765 break;
2766 }
2767 }
2768
2769 if( j<0 )
2770 continue;
2771
2772 //------------------------------------------------//
2773 //
2774 // Calculate the attractive factor, it is based on:
2775 //
2776 // - the reputation of the target nation (+0 to 100)
2777 // - the racial harmony of the race in the target town (+0 to 100)
2778 // - the no. of people of the race in the target town
2779 // - distance between the current town and the target town (-0 to 100)
2780 //
2781 // Attractiveness level range: 0 to 200
2782 //
2783 //------------------------------------------------//
2784
2785 targetBaseAttractLevel = 0;
2786
2787 if( townPtr->nation_recno )
2788 targetBaseAttractLevel += (int) nation_array[townPtr->nation_recno]->reputation;
2789
2790 //---- scan all workers, see if any of them want to worker_migrate ----//
2791
2792 workerId=misc.random(worker_count)+1;
2793
2794 for(j=0 ; j<worker_count ; j++ )
2795 {
2796 if( ++workerId > worker_count )
2797 workerId = 1;
2798
2799 workerPtr = worker_array+workerId-1;
2800
2801 if( workerPtr->town_recno == townRecno )
2802 continue;
2803
2804 //-- do not migrate if the target town's population of that race is less than half of the population of the current town --//
2805
2806 raceId = workerPtr->race_id;
2807 workerTownPtr = town_array[workerPtr->town_recno];
2808
2809 if( townPtr->race_pop_array[raceId-1] < workerTownPtr->race_pop_array[raceId-1]/2 )
2810 continue;
2811
2812 //------ calc the current and target attractiveness level ------//
2813
2814 workerTownPtr = town_array[workerPtr->town_recno];
2815
2816 if( workerTownPtr->nation_recno )
2817 curBaseAttractLevel = (int) nation_array[workerTownPtr->nation_recno]->reputation;
2818 else
2819 curBaseAttractLevel = 0;
2820
2821 targetAttractLevel = targetBaseAttractLevel +
2822 townPtr->race_harmony(raceId);
2823
2824 if( targetAttractLevel < MIN_MIGRATE_ATTRACT_LEVEL )
2825 continue;
2826
2827 curAttractLevel = curBaseAttractLevel +
2828 workerTownPtr->race_harmony(raceId) +
2829 ((int)workerPtr->loyalty() - 40); // loyalty > 40 is considered as positive force, < 40 is considered as negative force
2830
2831 if( targetAttractLevel > curAttractLevel )
2832 {
2833 int newLoyalty = MAX( REBEL_LOYALTY+1, targetAttractLevel/2 );
2834
2835 worker_migrate(workerId, townRecno, newLoyalty);
2836 return;
2837 }
2838 }
2839 }
2840 }
2841 //-------- End of function Firm::think_worker_migrate -----------//
2842
2843
2844 //------- Begin of function Firm::worker_migrate ---------//
2845 //
2846 // Worker worker_migrate from one town to another.
2847 //
2848 // <int> workerId - id. of the worker
2849 // <int> destTownRecno - recno of the destination town.
2850 // <int> newLoyalty - loyalty of the unit in the target town.
2851 //
worker_migrate(int workerId,int destTownRecno,int newLoyalty)2852 void Firm::worker_migrate(int workerId, int destTownRecno, int newLoyalty)
2853 {
2854 err_when( !worker_array ); // this function shouldn't be called if this firm does not need worker
2855
2856 err_when( !firm_res[firm_id]->live_in_town );
2857
2858 Worker* workerPtr = worker_array+workerId-1;
2859
2860 int raceId = workerPtr->race_id;
2861 Town* srcTown = town_array[workerPtr->town_recno];
2862 Town* destTown = town_array[destTownRecno];
2863
2864 err_when( !raceId );
2865 err_when( misc.points_distance( center_x, center_y, destTown->center_x,
2866 destTown->center_y ) > EFFECTIVE_FIRM_TOWN_DISTANCE );
2867
2868 //------------- add news --------------//
2869
2870 if( srcTown->nation_recno==nation_array.player_recno ||
2871 destTown->nation_recno==nation_array.player_recno )
2872 {
2873 if( srcTown->nation_recno != destTown->nation_recno ) // don't add news for migrating between own towns
2874 news_array.migrate(srcTown->town_recno, destTownRecno, raceId, 1, firm_recno);
2875 }
2876
2877 //--------- migrate now ----------//
2878
2879 int keepJob = 1;
2880
2881 workerPtr->town_recno = destTownRecno;
2882
2883 //--------- decrease the population of the home town ------//
2884
2885 srcTown->dec_pop(raceId, keepJob);
2886
2887 //--------- increase the population of the target town ------//
2888
2889 destTown->inc_pop(raceId, keepJob, newLoyalty);
2890 }
2891 //-------- End of function Firm::worker_migrate -----------//
2892
2893
2894 //-------- Begin of function Firm::set_worker_home_town --------//
2895 //
2896 // This function has two purposes.
2897 //
2898 // If the worker's home town is already the given one,
2899 // then resign the worker.
2900 //
2901 // Otherwise, set the worker's home town to the new onel.
2902 //
2903 // <int> townRecno - the new home town recno
2904 // [int] workerId - the id. of the worker to be set to a new home town
2905 // (default: the currently selected worker, selected_worker_id)
2906 //
set_worker_home_town(int townRecno,char remoteAction,int workerId)2907 void Firm::set_worker_home_town(int townRecno, char remoteAction, int workerId)
2908 {
2909 if( !workerId )
2910 workerId = selected_worker_id;
2911
2912 if( !workerId || workerId > worker_count )
2913 return;
2914
2915 Town *townPtr = town_array[townRecno];
2916 Worker* workerPtr = worker_array+workerId-1;
2917
2918 if( workerPtr->town_recno != townRecno )
2919 {
2920 if( !workerPtr->is_nation(firm_recno, nation_recno) )
2921 return;
2922 if( townPtr->population >= MAX_TOWN_POPULATION )
2923 return;
2924 }
2925
2926 if(!remoteAction && remote.is_enable() )
2927 {
2928 // packet structure : <firm recno> <town recno> <workderId>
2929 short *shortPtr = (short *)remote.new_send_queue_msg(MSG_FIRM_SET_WORKER_HOME, 3*sizeof(short));
2930 shortPtr[0] = firm_recno;
2931 shortPtr[1] = townRecno;
2932 shortPtr[2] = workerId;
2933 return;
2934 }
2935
2936 //-------------------------------------------------//
2937
2938 err_when( !workerPtr->race_id );
2939
2940 if( workerPtr->town_recno == townRecno )
2941 {
2942 resign_worker(workerId);
2943 }
2944
2945 //--- otherwise, set the worker's home town to the new one ---//
2946
2947 else if( workerPtr->is_nation(firm_recno, nation_recno) &&
2948 townPtr->nation_recno == nation_recno ) // only allow when the worker lives in a town belonging to the same nation and moving domestically
2949 {
2950 int workerLoyalty = workerPtr->loyalty();
2951
2952 town_array[workerPtr->town_recno]->dec_pop(workerPtr->race_id, 1);
2953 townPtr->inc_pop(workerPtr->race_id, 1, workerLoyalty);
2954
2955 workerPtr->town_recno = townRecno;
2956 }
2957 }
2958 //-------- End of function Firm::set_worker_home_town --------//
2959
2960
2961 //------- Begin of function Worker::loyalty ---------//
2962 //
loyalty()2963 int Worker::loyalty()
2964 {
2965 if( town_recno ) // if the worker lives in a town
2966 return (int) town_array[town_recno]->race_loyalty_array[race_id-1];
2967 else
2968 return (int) worker_loyalty;
2969 }
2970 //-------- End of function Worker::loyalty -----------//
2971
2972
2973 //------- Begin of function Worker::target_loyalty ---------//
2974 //
target_loyalty(int firmRecno)2975 int Worker::target_loyalty(int firmRecno)
2976 {
2977 if( town_recno ) // if the worker lives in a town
2978 {
2979 return (int) town_array[town_recno]->race_loyalty_array[race_id-1];
2980 }
2981 else
2982 {
2983 Firm* firmPtr = firm_array[firmRecno];
2984
2985 if( firmPtr->overseer_recno )
2986 {
2987 Unit* overseerUnit = unit_array[firmPtr->overseer_recno];
2988
2989 int overseerSkill = overseerUnit->skill.get_skill(SKILL_LEADING);
2990 int targetLoyalty = 30 + overseerSkill/2;
2991
2992 //---------------------------------------------------//
2993 //
2994 // Soldiers with higher combat and leadership skill
2995 // will get discontented if they are led by a general
2996 // with low leadership.
2997 //
2998 //---------------------------------------------------//
2999
3000 targetLoyalty -= combat_level/2;
3001
3002 if( skill_level > overseerSkill )
3003 targetLoyalty -= skill_level - overseerSkill;
3004
3005 if( overseerUnit->rank_id == RANK_KING )
3006 targetLoyalty += 20;
3007
3008 if( race_res.is_same_race(race_id, overseerUnit->race_id) )
3009 targetLoyalty += 20;
3010
3011 if( targetLoyalty < 0 )
3012 targetLoyalty = 0;
3013
3014 if( targetLoyalty > 100 )
3015 targetLoyalty = 100;
3016
3017 return targetLoyalty;
3018 }
3019 else //-- if there is no overseer, just return the current loyalty --//
3020 {
3021 return worker_loyalty;
3022 }
3023 }
3024 }
3025 //-------- End of function Worker::target_loyalty -----------//
3026
3027
3028 //------- Begin of function Firm::setup_link ---------//
3029 //
setup_link()3030 void Firm::setup_link()
3031 {
3032 //-----------------------------------------------------------------------------//
3033 // check the connected firms location and structure if ai_link_checked is true
3034 //-----------------------------------------------------------------------------//
3035
3036 if(firm_ai)
3037 ai_link_checked = 0;
3038
3039 //----- build firm-to-firm link relationship -------//
3040
3041 int firmRecno, defaultLinkStatus;
3042 Firm* firmPtr;
3043 FirmInfo* firmInfo = firm_res[firm_id];
3044
3045 linked_firm_count = 0;
3046
3047 for( firmRecno=firm_array.size() ; firmRecno>0 ; firmRecno-- )
3048 {
3049 if( firm_array.is_deleted(firmRecno) || firmRecno==firm_recno )
3050 continue;
3051
3052 firmPtr = firm_array[firmRecno];
3053
3054 //---- do not allow links between firms of different nation ----//
3055
3056 if( firmPtr->nation_recno != nation_recno )
3057 continue;
3058
3059 //---------- check if the firm is close enough to this firm -------//
3060
3061 if( misc.points_distance( firmPtr->center_x, firmPtr->center_y,
3062 center_x, center_y ) > EFFECTIVE_FIRM_FIRM_DISTANCE )
3063 {
3064 continue;
3065 }
3066
3067 //------ check if both are on the same terrain type ------//
3068
3069 if( world.get_loc(firmPtr->center_x, firmPtr->center_y)->is_plateau()
3070 != world.get_loc(center_x, center_y)->is_plateau() )
3071 {
3072 continue;
3073 }
3074
3075 //----- if the firms are linkable to each other -----//
3076
3077 if( !firmInfo->is_linkable_to_firm(firmPtr->firm_id) )
3078 continue;
3079
3080 //------- determine the default link status ------//
3081
3082 if( firmPtr->nation_recno == nation_recno ) // if the two firms are of the same nation, get the default link status which is based on the types of the firms
3083 defaultLinkStatus = firmInfo->default_link_status(firmPtr->firm_id);
3084 else
3085 defaultLinkStatus = LINK_DD; // if the two firms are of different nations, default link status is both side disabled
3086
3087 //-------- add the link now -------//
3088
3089 if( linked_firm_count < MAX_LINKED_FIRM_FIRM )
3090 {
3091 linked_firm_array[linked_firm_count] = firmRecno;
3092 linked_firm_enable_array[linked_firm_count] = defaultLinkStatus;
3093
3094 linked_firm_count++;
3095 }
3096 else // we must link it as it is linked both sides, if one side is linked and the other is not, that will cause a bug
3097 {
3098 err_here();
3099 }
3100
3101 if( firmPtr->linked_firm_count < MAX_LINKED_FIRM_FIRM )
3102 {
3103 if( defaultLinkStatus==LINK_ED ) // Reverse the link status for the opposite linker
3104 defaultLinkStatus=LINK_DE;
3105
3106 else if( defaultLinkStatus==LINK_DE )
3107 defaultLinkStatus=LINK_ED;
3108
3109 firmPtr->linked_firm_array[firmPtr->linked_firm_count] = firm_recno;
3110 firmPtr->linked_firm_enable_array[firmPtr->linked_firm_count] = defaultLinkStatus;
3111
3112 firmPtr->linked_firm_count++;
3113 if(firmPtr->firm_ai)
3114 firmPtr->ai_link_checked = 0;
3115
3116 if(firmPtr->firm_id==FIRM_HARBOR)
3117 {
3118 FirmHarbor *harborPtr = (FirmHarbor*) firmPtr;
3119 harborPtr->link_checked = 0;
3120 }
3121 }
3122 else
3123 {
3124 err_here();
3125 }
3126 }
3127
3128 //----- build firm-to-town link relationship -------//
3129
3130 linked_town_count = 0;
3131
3132 if( !firmInfo->is_linkable_to_town )
3133 return;
3134
3135 int townRecno;
3136 Town* townPtr;
3137
3138 for( townRecno=town_array.size() ; townRecno>0 ; townRecno-- )
3139 {
3140 if( town_array.is_deleted(townRecno) )
3141 continue;
3142
3143 townPtr = town_array[townRecno];
3144
3145 //------ check if the town is close enough to this firm -------//
3146
3147 if( misc.points_distance( townPtr->center_x, townPtr->center_y,
3148 center_x, center_y ) > EFFECTIVE_FIRM_TOWN_DISTANCE )
3149 {
3150 continue;
3151 }
3152
3153 //------ check if both are on the same terrain type ------//
3154
3155 if( (world.get_loc(townPtr->center_x, townPtr->center_y)->is_plateau()==1)
3156 != (world.get_loc(center_x, center_y)->is_plateau()==1) )
3157 {
3158 continue;
3159 }
3160
3161 //------- determine the default link status ------//
3162
3163 if( townPtr->nation_recno == nation_recno ) // if the two firms are of the same nation, get the default link status which is based on the types of the firms
3164 defaultLinkStatus = LINK_EE;
3165 else
3166 defaultLinkStatus = LINK_DD; // if the two firms are of different nations, default link status is both side disabled
3167
3168 //---------------------------------------------------//
3169 //
3170 // If this is a camp, it can be linked to the town when
3171 // either the town is an independent one or the town
3172 // is not linked to any camps of its own.
3173 //
3174 //---------------------------------------------------//
3175
3176 if( firm_id==FIRM_CAMP )
3177 {
3178 if( townPtr->nation_recno==0 || !townPtr->has_linked_own_camp )
3179 defaultLinkStatus = LINK_EE;
3180 }
3181
3182 //-------- add the link now -------//
3183
3184 if( linked_town_count < MAX_LINKED_FIRM_TOWN )
3185 {
3186 linked_town_array[linked_town_count] = townRecno;
3187 linked_town_enable_array[linked_town_count] = defaultLinkStatus;
3188
3189 linked_town_count++;
3190 }
3191 else
3192 {
3193 err_here();
3194 }
3195
3196 if( townPtr->linked_firm_count < MAX_LINKED_FIRM_TOWN )
3197 {
3198 if( defaultLinkStatus==LINK_ED ) // Reverse the link status for the opposite linker
3199 defaultLinkStatus=LINK_DE;
3200
3201 else if( defaultLinkStatus==LINK_DE )
3202 defaultLinkStatus=LINK_ED;
3203
3204 townPtr->linked_firm_array[townPtr->linked_firm_count] = firm_recno;
3205 townPtr->linked_firm_enable_array[townPtr->linked_firm_count] = defaultLinkStatus;
3206
3207 townPtr->linked_firm_count++;
3208 if(townPtr->ai_town)
3209 townPtr->ai_link_checked = 0;
3210 }
3211 else
3212 {
3213 err_here();
3214 }
3215 }
3216 }
3217 //-------- End of function Firm::setup_link -----------//
3218
3219
3220 //------- Begin of function Firm::release_link ---------//
3221 //
release_link()3222 void Firm::release_link()
3223 {
3224 int i;
3225 Firm *firmPtr;
3226 Town *townPtr;
3227
3228 //------ release linked firms ------//
3229
3230 for( i=0 ; i<linked_firm_count ; i++ )
3231 {
3232 firmPtr = firm_array[linked_firm_array[i]];
3233 firmPtr->release_firm_link(firm_recno);
3234
3235 if(firmPtr->firm_ai)
3236 firmPtr->ai_link_checked = 0;
3237 }
3238
3239 //------ release linked towns ------//
3240
3241 for( i=0 ; i<linked_town_count ; i++ )
3242 {
3243 townPtr = town_array[linked_town_array[i]];
3244 townPtr->release_firm_link(firm_recno);
3245
3246 if(townPtr->ai_town)
3247 townPtr->ai_link_checked = 0;
3248 }
3249 }
3250 //-------- End of function Firm::release_link -----------//
3251
3252
3253 //------- Begin of function Firm::release_firm_link ---------//
3254 //
release_firm_link(int releaseFirmRecno)3255 void Firm::release_firm_link(int releaseFirmRecno)
3256 {
3257 //-----------------------------------------------------------------------------//
3258 // check the connected firms location and structure if ai_link_checked is true
3259 //-----------------------------------------------------------------------------//
3260 if(firm_ai)
3261 ai_link_checked = 0;
3262
3263 for( int i=0 ; i<linked_firm_count ; i++ )
3264 {
3265 if( linked_firm_array[i] == releaseFirmRecno )
3266 {
3267 err_when( linked_firm_count > MAX_LINKED_FIRM_FIRM );
3268
3269 misc.del_array_rec( linked_firm_array, linked_firm_count, sizeof(linked_firm_array[0]), i+1 );
3270 misc.del_array_rec( linked_firm_enable_array, linked_firm_count, sizeof(linked_firm_enable_array[0]), i+1 );
3271 linked_firm_count--;
3272 return;
3273 }
3274 }
3275
3276 err_here();
3277 }
3278 //------- End of function Firm::release_firm_link ---------//
3279
3280
3281 //------- Begin of function Firm::release_town_link ---------//
3282 //
release_town_link(int releaseTownRecno)3283 void Firm::release_town_link(int releaseTownRecno)
3284 {
3285 //-----------------------------------------------------------------------------//
3286 // check the connected firms location and structure if ai_link_checked is true
3287 //-----------------------------------------------------------------------------//
3288
3289 if(firm_ai)
3290 ai_link_checked = 0;
3291
3292 for( int i=0 ; i<linked_town_count ; i++ )
3293 {
3294 if( linked_town_array[i] == releaseTownRecno )
3295 {
3296 err_when( linked_town_count > MAX_LINKED_FIRM_TOWN );
3297
3298 misc.del_array_rec( linked_town_array, linked_town_count, sizeof(linked_town_array[0]), i+1 );
3299 misc.del_array_rec( linked_town_enable_array, linked_town_count, sizeof(linked_town_enable_array[0]), i+1 );
3300 linked_town_count--;
3301 return;
3302 }
3303 }
3304
3305 err_here();
3306 }
3307 //------- End of function Firm::release_town_link ---------//
3308
3309
3310 //--------- Begin of function Firm::capture_firm --------//
3311 //
3312 // The firm is being captured by another nation.
3313 //
capture_firm(int newNationRecno)3314 void Firm::capture_firm(int newNationRecno)
3315 {
3316 if( nation_recno == nation_array.player_recno )
3317 news_array.firm_captured(firm_recno, newNationRecno, 0); // 0 - the capturer is not a spy
3318
3319 //-------- if this is an AI firm --------//
3320
3321 if( firm_ai )
3322 ai_firm_captured(newNationRecno);
3323
3324 //------------------------------------------//
3325 //
3326 // If there is an overseer in this firm, then the only
3327 // unit who can capture this firm will be the overseer only,
3328 // so calling its betray() function will capture the whole
3329 // firm already.
3330 //
3331 //------------------------------------------//
3332
3333 if( overseer_recno && unit_array[overseer_recno]->spy_recno )
3334 unit_array[overseer_recno]->spy_change_nation(newNationRecno, COMMAND_AUTO);
3335 else
3336 change_nation(newNationRecno);
3337 }
3338 //--------- End of function Firm::capture_firm --------//
3339
3340
3341 //------- Begin of function Firm::change_nation ---------//
3342 //
change_nation(int newNationRecno)3343 void Firm::change_nation(int newNationRecno)
3344 {
3345 if( nation_recno == newNationRecno )
3346 return;
3347
3348 //---------- stop all attack actions to this firm ----------//
3349 unit_array.stop_attack_firm(firm_recno);
3350 rebel_array.stop_attack_firm(firm_recno);
3351
3352 Nation *oldNationPtr = nation_array[nation_recno];
3353 Nation *newNationPtr = nation_array[newNationRecno];
3354
3355 //------ if there is a builder in this firm, change its nation also ----//
3356
3357 if( builder_recno )
3358 {
3359 Unit* unitPtr = unit_array[builder_recno];
3360
3361 unitPtr->change_nation(newNationRecno);
3362
3363 //--- if this is a spy, chance its cloak ----//
3364
3365 if( unitPtr->spy_recno )
3366 spy_array[unitPtr->spy_recno]->cloaked_nation_recno = newNationRecno;
3367 }
3368
3369 //---------- stop all actions attacking this firm --------//
3370
3371 unit_array.stop_attack_firm(firm_recno);
3372
3373 //------ clear defense mode for military camp -----//
3374
3375 if(firm_id==FIRM_CAMP)
3376 ((FirmCamp*)this)->clear_defense_mode();
3377
3378 //---- update nation_unit_count_array[] ----//
3379
3380 FirmInfo* firmInfo = firm_res[firm_id];
3381
3382 if( nation_recno )
3383 firmInfo->dec_nation_firm_count(nation_recno);
3384
3385 if( newNationRecno )
3386 firmInfo->inc_nation_firm_count(newNationRecno);
3387
3388 //---- reset should_close_flag -----//
3389
3390 if( firm_ai )
3391 {
3392 if( should_close_flag )
3393 {
3394 oldNationPtr->firm_should_close_array[firm_id-1]--;
3395 should_close_flag = 0;
3396
3397 err_when( oldNationPtr->firm_should_close_array[firm_id-1] < 0 );
3398 }
3399 }
3400
3401 //------- update player_spy_count -------//
3402
3403 spy_array.update_firm_spy_count(firm_recno);
3404
3405 //--- update the cloaked_nation_recno of all spies in the firm ---//
3406
3407 spy_array.change_cloaked_nation(SPY_FIRM, firm_recno, nation_recno, newNationRecno); // check the cloaked nation recno of all spies in the firm
3408
3409 //-----------------------------------------//
3410
3411 if(firm_ai)
3412 oldNationPtr->del_firm_info(firm_id, firm_recno);
3413
3414 //------ update power nation recno ----------//
3415
3416 if( should_set_power )
3417 world.restore_power(loc_x1, loc_y1, loc_x2, loc_y2, 0, firm_recno);
3418
3419 should_set_power = get_should_set_power();
3420
3421 if( should_set_power )
3422 world.set_power(loc_x1, loc_y1, loc_x2, loc_y2, newNationRecno); // set power of the new nation
3423
3424 //------------ update link --------------//
3425
3426 release_link(); // need to update link because firms are only linked to firms of the same nation
3427
3428 nation_recno = newNationRecno;
3429
3430 setup_link();
3431
3432 //---------------------------------------//
3433
3434 firm_ai = nation_array[nation_recno]->is_ai();
3435
3436 if(firm_ai)
3437 newNationPtr->add_firm_info(firm_id, firm_recno);
3438
3439 //--- if a nation set up a town in a location that the player has explored, contact between the nation and the player is established ---//
3440
3441 establish_contact_with_player();
3442
3443 //---- reset the action mode of all spies in this town ----//
3444
3445 spy_array.set_action_mode( SPY_FIRM, firm_recno, SPY_IDLE ); // we need to reset it. e.g. when we have captured an enemy town, SPY_SOW_DISSENT action must be reset to SPY_IDLE
3446
3447 //-- refresh display if this firm is currently selected --//
3448
3449 if( firm_array.selected_recno == firm_recno )
3450 info.disp();
3451 }
3452 //-------- End of function Firm::change_nation ---------//
3453
3454
3455 //------- Begin of function Firm::toggle_firm_link ---------//
3456 //
3457 // Toggle the firm link of the current firm.
3458 //
3459 // <int> linkId - id. of the link
3460 // <int> toggleFlag - 1-enable, 0-disable
3461 // [int] setBoth - if this is 1, it will set the link to either LINK_EE or LINK_DD (and no LINK_ED or LINK_DD)
3462 // if this is -1, the only one side will be set even though the nation recno of the firm and town are the same
3463 // (default: 0)
3464 //
toggle_firm_link(int linkId,int toggleFlag,char remoteAction,int setBoth)3465 void Firm::toggle_firm_link(int linkId, int toggleFlag, char remoteAction, int setBoth)
3466 {
3467 if( !remoteAction && remote.is_enable() )
3468 {
3469 // packet structure : <firm recno> <link Id> <toggle Flag>
3470 short *shortPtr = (short *)remote.new_send_queue_msg(MSG_FIRM_TOGGLE_LINK_FIRM, 3*sizeof(short));
3471 shortPtr[0] = firm_recno;
3472 shortPtr[1] = linkId;
3473 shortPtr[2] = toggleFlag;
3474 return;
3475 }
3476
3477 int linkedNationRecno = firm_array[linked_firm_array[linkId-1]]->nation_recno;
3478
3479 int sameNation = linkedNationRecno == nation_recno || // if one of the linked end is an indepdendent firm/nation, consider this link as a single nation link
3480 linkedNationRecno == 0 ||
3481 nation_recno == 0;
3482
3483 if( toggleFlag )
3484 {
3485 if( (sameNation && setBoth==0) || setBoth==1 )
3486 linked_firm_enable_array[linkId-1] = LINK_EE;
3487 else
3488 linked_firm_enable_array[linkId-1] |= LINK_ED;
3489 }
3490 else
3491 {
3492 if( (sameNation && setBoth==0) || setBoth==1 )
3493 linked_firm_enable_array[linkId-1] = LINK_DD;
3494 else
3495 linked_firm_enable_array[linkId-1] &= ~LINK_ED;
3496 }
3497
3498 //---------- if this firm is harbor, set FirmHarbor's parameter link_checked to 0
3499
3500 if(firm_id == FIRM_HARBOR)
3501 {
3502 FirmHarbor *harborPtr = (FirmHarbor*) this;
3503 harborPtr->link_checked = 0;
3504 }
3505
3506 //------ set the linked flag of the opposite firm -----//
3507
3508 Firm* firmPtr = firm_array[ linked_firm_array[linkId-1] ];
3509
3510 //---------- if firm is harbor, set FirmHarbor's parameter link_checked to 0
3511
3512 if(firmPtr->firm_id==FIRM_HARBOR)
3513 {
3514 FirmHarbor *harborPtr = (FirmHarbor*) firmPtr;
3515 harborPtr->link_checked = 0;
3516 }
3517
3518 int i;
3519
3520 for( i=0 ; i<firmPtr->linked_firm_count ; i++ )
3521 {
3522 if( firmPtr->linked_firm_array[i] == firm_recno )
3523 {
3524 if( toggleFlag )
3525 {
3526 if( (sameNation && setBoth==0) || setBoth==1 )
3527 firmPtr->linked_firm_enable_array[i] = LINK_EE;
3528 else
3529 firmPtr->linked_firm_enable_array[i] |= LINK_DE;
3530 }
3531 else
3532 {
3533 if( (sameNation && setBoth==0) || setBoth==1 )
3534 firmPtr->linked_firm_enable_array[i] = LINK_DD;
3535 else
3536 firmPtr->linked_firm_enable_array[i] &= ~LINK_DE;
3537 }
3538
3539 break;
3540 }
3541 }
3542 }
3543 //-------- End of function Firm::toggle_firm_link ---------//
3544
3545
3546 //------- Begin of function Firm::toggle_town_link ---------//
3547 //
3548 // Toggle the town link of the current firm.
3549 //
3550 // <int> linkId - id. of the link
3551 // <int> toggleFlag - 1-enable, 0-disable
3552 // [int] setBoth - if this is 1, it will set the link to either LINK_EE or LINK_DD (and no LINK_ED or LINK_DD)
3553 // if this is -1, the only one side will be set even though the nation recno of the firm and town are the same
3554 // (default: 0)
3555 //
toggle_town_link(int linkId,int toggleFlag,char remoteAction,int setBoth)3556 void Firm::toggle_town_link(int linkId, int toggleFlag, char remoteAction, int setBoth)
3557 {
3558 if( !remoteAction && remote.is_enable() )
3559 {
3560 // packet structure : <firm recno> <link Id> <toggle Flag>
3561 short *shortPtr = (short *)remote.new_send_queue_msg(MSG_FIRM_TOGGLE_LINK_TOWN, 3*sizeof(short));
3562 shortPtr[0] = firm_recno;
3563 shortPtr[1] = linkId;
3564 shortPtr[2] = toggleFlag;
3565 return;
3566 }
3567
3568 int linkedNationRecno = town_array[linked_town_array[linkId-1]]->nation_recno;
3569
3570 int sameNation = linkedNationRecno == nation_recno || // if one of the linked end is an indepdendent firm/nation, consider this link as a single nation link
3571 firm_id==FIRM_BASE; // town cannot decide whether it wants to link to Command Base or not, it is the Command Base which influences the town.
3572
3573 if( toggleFlag )
3574 {
3575 if( (sameNation && setBoth==0) || setBoth==1 )
3576 linked_town_enable_array[linkId-1] = LINK_EE;
3577 else
3578 linked_town_enable_array[linkId-1] |= LINK_ED;
3579 }
3580 else
3581 {
3582 if( (sameNation && setBoth==0) || setBoth==1 )
3583 linked_town_enable_array[linkId-1] = LINK_DD;
3584 else
3585 linked_town_enable_array[linkId-1] &= ~LINK_ED;
3586 }
3587
3588 //------ set the linked flag of the opposite town -----//
3589
3590 Town* townPtr = town_array[ linked_town_array[linkId-1] ];
3591 int i;
3592
3593 for( i=0 ; i<townPtr->linked_firm_count ; i++ )
3594 {
3595 if( townPtr->linked_firm_array[i] == firm_recno )
3596 {
3597 if( toggleFlag )
3598 {
3599 if( (sameNation && setBoth==0) || setBoth==1 )
3600 townPtr->linked_firm_enable_array[i] = LINK_EE;
3601 else
3602 townPtr->linked_firm_enable_array[i] |= LINK_DE;
3603 }
3604 else
3605 {
3606 if( (sameNation && setBoth==0) || setBoth==1 )
3607 townPtr->linked_firm_enable_array[i] = LINK_DD;
3608 else
3609 townPtr->linked_firm_enable_array[i] &= ~LINK_DE;
3610 }
3611
3612 break;
3613 }
3614 }
3615
3616 //-------- update the town's influence --------//
3617
3618 if( townPtr->nation_recno==0 )
3619 townPtr->update_target_resistance();
3620
3621 //--- redistribute demand if a link to market place has been toggled ---//
3622
3623 if( firm_id == FIRM_MARKET )
3624 town_array.distribute_demand();
3625 }
3626 //-------- End of function Firm::toggle_town_link ---------//
3627
3628
3629 //------- Begin of function Firm::auto_defense -----------//
auto_defense(short targetRecno)3630 void Firm::auto_defense(short targetRecno)
3631 {
3632 //--------------------------------------------------------//
3633 // if the firm_id is FIRM_CAMP, send the units to defense
3634 // the firm
3635 //--------------------------------------------------------//
3636 if(firm_id == FIRM_CAMP)
3637 {
3638 FirmCamp *campPtr = cast_to_FirmCamp();
3639 campPtr->defend_target_recno = targetRecno;
3640 campPtr->defense(targetRecno);
3641 }
3642
3643 Town *townPtr;
3644
3645 for(int i=linked_town_count-1; i>=0; i--)
3646 {
3647 if(!linked_town_array[i] || town_array.is_deleted(linked_town_array[i]))
3648 continue;
3649
3650 townPtr = town_array[linked_town_array[i]];
3651
3652 //-------------------------------------------------------//
3653 // find whether military camp is linked to this town. If
3654 // so, defense for this firm
3655 //-------------------------------------------------------//
3656 if(townPtr->nation_recno == nation_recno)
3657 townPtr->auto_defense(targetRecno);
3658
3659 //-------------------------------------------------------//
3660 // some linked town may be deleted after calling auto_defense().
3661 // Also, the data in the linked_town_array may also be changed.
3662 //-------------------------------------------------------//
3663 if(i>linked_town_count)
3664 i = linked_town_count;
3665 }
3666 }
3667 //--------- End of function Firm::auto_defense -----------//
3668
3669
3670 //------- Begin of function Worker::Worker -----------//
3671 //
Worker()3672 Worker::Worker()
3673 {
3674 race_id = 0;
3675 unit_id = 0;
3676 town_recno = 0;
3677 name_id = 0;
3678 skill_id = 0;
3679 skill_level = 0;
3680 skill_level_minor = 0;
3681 skill_potential = 0;
3682 combat_level = 0;
3683 combat_level_minor = 0;
3684 spy_recno = 0;
3685 rank_id = 0;
3686 worker_loyalty = 0;
3687 hit_points = 0;
3688 extra_para = 0;
3689 }
3690 //--------- End of function Worker::Worker -----------//
3691
3692
3693 //------- Begin of function Worker::max_hit_points -----------//
3694 //
max_hit_points()3695 short Worker::max_hit_points()
3696 {
3697 err_when( combat_level <= 0 );
3698 err_when( combat_level > 100 );
3699
3700 return (int) unit_res[unit_id]->hit_points * combat_level / 100;
3701 }
3702 //--------- End of function Worker::max_hit_points -----------//
3703
3704
3705 //--------- Begin of function Worker::max_attack_range ---------//
max_attack_range()3706 int Worker::max_attack_range()
3707 {
3708 int maxRange=0;
3709 AttackInfo *attackInfo = unit_res.get_attack_info(unit_res[unit_id]->first_attack);
3710 int attackCount = unit_res[unit_id]->attack_count;
3711
3712 for(int i=0; i<attackCount; i++, attackInfo++)
3713 {
3714 if(combat_level >= attackInfo->combat_level &&
3715 attackInfo->attack_range>maxRange)
3716 maxRange = attackInfo->attack_range;
3717 }
3718
3719 return maxRange;
3720 }
3721 //--------- End of function Worker::max_attack_range -----------//
3722
3723
3724 //--------- Begin of function Worker::is_nation ---------//
3725 //
3726 // Whether this worker belongs to the specific nation.
3727 //
3728 // <int> firmRecno - the recno of the firm the worker works in
3729 // <int> nationRecno - the recno of the nation to check against.
3730 // <int> checkSpy - check spy against true nation (default : 0)
3731 //
is_nation(int firmRecno,int nationRecno,int checkSpy)3732 int Worker::is_nation(int firmRecno, int nationRecno, int checkSpy)
3733 {
3734 if( checkSpy && spy_recno )
3735 return spy_array[spy_recno]->true_nation_recno == nationRecno;
3736
3737 if( town_recno )
3738 return town_array[town_recno]->nation_recno == nationRecno;
3739 else
3740 return firm_array[firmRecno]->nation_recno == nationRecno;
3741 }
3742 //----------- End of function Worker::is_nation ---------//
3743
3744
3745 //-------- Begin of function Firm::can_assign_capture ------//
3746 //
3747 // Return whether new units assigned to this firm can capture
3748 // this firm.
3749 //
can_assign_capture()3750 int Firm::can_assign_capture()
3751 {
3752 return (overseer_recno==0 && worker_count==0);
3753 }
3754 //----------- End of function Worker::can_assign_capture ---------//
3755
3756
3757 //-------- Begin of function Firm::should_show_info ------//
3758 //
3759 // Whether information of this firm should be shown.
3760 //
should_show_info()3761 int Firm::should_show_info()
3762 {
3763 if( config.show_ai_info || nation_recno==nation_array.player_recno ||
3764 player_spy_count > 0 )
3765 {
3766 return 1;
3767 }
3768
3769 //------ if the builder is a spy of the player ------//
3770
3771 if( builder_recno )
3772 {
3773 if( unit_array[builder_recno]->true_nation_recno() == nation_array.player_recno )
3774 return 1;
3775 }
3776
3777 //----- if any of the workers belong to the player, show the info of this firm -----//
3778
3779 if( have_own_workers(1) )
3780 return 1;
3781
3782 //---- if there is a phoenix of the player over this firm ----//
3783
3784 if( nation_array.player_recno && (~nation_array)->revealed_by_phoenix(loc_x1, loc_y1) )
3785 return 1;
3786
3787 return 0;
3788 }
3789 //---------- End of function Firm::should_show_info --------//
3790
3791
3792 //-------- Begin of function Firm::majority_race ------//
3793 //
majority_race()3794 char Firm::majority_race()
3795 {
3796 //--- if there is a overseer, return the overseer's race ---//
3797
3798 if( overseer_recno )
3799 return unit_array[overseer_recno]->race_id;
3800
3801 if( worker_count==0 )
3802 return 0;
3803
3804 //----- count the no. people in each race ------//
3805
3806 char raceCountArray[MAX_RACE];
3807
3808 memset( raceCountArray, 0, sizeof(raceCountArray) );
3809
3810 int i;
3811 for( i=0 ; i<worker_count ; i++ )
3812 {
3813 if( worker_array[i].race_id )
3814 raceCountArray[ worker_array[i].race_id-1 ]++;
3815 }
3816
3817 //---------------------------------------------//
3818
3819 int mostRaceCount=0, mostRaceId=0;
3820
3821 for( i=0 ; i<MAX_RACE ; i++ )
3822 {
3823 if( raceCountArray[i] > mostRaceCount )
3824 {
3825 mostRaceCount = raceCountArray[i];
3826 mostRaceId = i+1;
3827 }
3828 }
3829
3830 return mostRaceId;
3831 }
3832 //---------- End of function Firm::majority_race --------//
3833
3834
3835 //---------- Begin of function Worker::small_icon_ptr --------//
3836
small_icon_ptr()3837 char* Worker::small_icon_ptr()
3838 {
3839 // ###### begin Gilbert 17/10 ########//
3840 return unit_res[unit_id]->get_small_icon_ptr(rank_id);
3841 // ###### end Gilbert 17/10 ########//
3842 }
3843 //---------- End of function Worker::small_icon_ptr --------//
3844
3845
3846 //---------- Begin of function Worker::change_loyalty --------//
3847
change_loyalty(int loyaltyChange)3848 void Worker::change_loyalty(int loyaltyChange)
3849 {
3850 if( town_recno ) // for those live in town, their loyalty are based on town people loyalty.
3851 return;
3852
3853 int newLoyalty = worker_loyalty + loyaltyChange;
3854
3855 newLoyalty = MIN( 100, newLoyalty );
3856 worker_loyalty = MAX( 0, newLoyalty );
3857 }
3858 //---------- End of function Worker::change_loyalty --------//
3859
3860
3861 //---------- Begin of function Worker::change_hit_points --------//
3862
change_hit_points(int changePoints)3863 void Worker::change_hit_points(int changePoints)
3864 {
3865 err_when( town_recno ); // for those live in town, their loyalty are based on town people loyalty.
3866
3867 int newHitPoints = hit_points + changePoints;
3868 int maxHitPoints = max_hit_points();
3869
3870 newHitPoints = MIN( maxHitPoints, newHitPoints );
3871 hit_points = MAX( 0, newHitPoints );
3872 }
3873 //---------- End of function Worker::change_hit_points --------//
3874
3875
3876 //-------- Begin of function Firm::is_worker_full ------//
3877 //
is_worker_full()3878 int Firm::is_worker_full()
3879 {
3880 return worker_count == MAX_WORKER;
3881 }
3882 //----------- End of function Firm::is_worker_full ---------//
3883
3884
3885 //--------- Begin of function Firm::reward ---------//
3886 //
3887 // Only military camp has the "reward" option and not the other firms also
3888 // because workers in other firms live in the towns and their loyalty
3889 // are based on the town they live. Military camp is not linked to a town.
3890 //
3891 // <int> workerId - 0 - commander, >0 - id. of the soldier
3892 // <int> remoteAction - either COMMAND_PLAYER or COMMAND_REMOTE
3893 //
reward(int workerId,int remoteAction)3894 void Firm::reward(int workerId, int remoteAction)
3895 {
3896 if( remoteAction==COMMAND_PLAYER && remote.is_enable() )
3897 {
3898 if( !remoteAction && remote.is_enable() )
3899 {
3900 // packet structure : <firm recno> <worker id>
3901 short *shortPtr = (short *)remote.new_send_queue_msg(MSG_FIRM_REWARD, 2*sizeof(short) );
3902 *shortPtr = firm_recno;
3903 shortPtr[1] = workerId;
3904 }
3905 }
3906 else
3907 {
3908 if( workerId == 0 )
3909 {
3910 if( overseer_recno )
3911 unit_array[overseer_recno]->reward(nation_recno);
3912 }
3913 else
3914 {
3915 err_when( workerId < 1 || workerId > worker_count );
3916
3917 worker_array[workerId-1].change_loyalty( REWARD_LOYALTY_INCREASE );
3918
3919 nation_array[nation_recno]->add_expense( EXPENSE_REWARD_UNIT, (float)REWARD_COST);
3920 }
3921 }
3922 }
3923 //----------- End of function Firm::reward -----------//
3924
3925
3926 //--------- Begin of function Firm::have_own_workers ---------//
3927 //
3928 // if player has any workers in the building
3929 //
3930 // <int> checkSpy - optionally check for cloaked spies as well (default : 0)
3931 //
have_own_workers(int checkSpy)3932 int Firm::have_own_workers(int checkSpy)
3933 {
3934 Worker* workerPtr = worker_array;
3935
3936 for( int i=0 ; i<worker_count ; i++, workerPtr++ )
3937 {
3938 if( workerPtr->is_nation(firm_recno, nation_array.player_recno, checkSpy) )
3939 return 1;
3940 }
3941 return 0;
3942 }
3943 //----------- End of function Firm::have_own_workers -----------//
3944
3945