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