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 : OUNITAI.CPP
22 //Description : Object Unit AI
23
24 #include <OSYS.h>
25 #include <OSPY.h>
26 #include <OREBEL.h>
27 #include <OUNIT.h>
28 #include <OCONFIG.h>
29 #include <OREGIONS.h>
30 #include <OF_CAMP.h>
31 #include <ONATION.h>
32
33 #ifdef NO_DEBUG_UNIT
34 #undef err_when
35 #undef err_here
36 #undef err_if
37 #undef err_else
38 #undef err_now
39 #define err_when(cond)
40 #define err_here()
41 #define err_if(cond)
42 #define err_else
43 #define err_now(msg)
44 #undef DEBUG
45 #endif
46
47 //--------- Begin of function Unit::process_ai --------//
48 //
49 // [int] forceExecute - whether force execute all AI functions
50 // without checking day interavals.
51 // (default: 0)
52 //
process_ai()53 void Unit::process_ai()
54 {
55 err_when( !nation_recno );
56
57 //-*********** simulate aat ************-//
58 #ifdef DEBUG
59 if(debug_sim_game_type)
60 return;
61 #endif
62 //-*********** simulate aat ************-//
63
64 //------ the aggressive_mode of AI units is always 1 ------//
65
66 aggressive_mode = 1;
67
68 //------- handle Seek Path failures ------//
69
70 if( ai_handle_seek_path_fail() )
71 return;
72
73 //--- if it's a spy from other nation, don't control it ---//
74
75 if( spy_recno && true_nation_recno() != nation_recno )
76 {
77 //--- a random chance of the AI catching the spy and resign it ---//
78
79 if( is_visible() && misc.random(365 * FRAMES_PER_DAY)==0 ) // if the unit stay outside for one year, it will get caught
80 {
81 stop2();
82 resign(COMMAND_AI);
83 return;
84 }
85
86 if( !spy_array[spy_recno]->notify_cloaked_nation_flag ) // if notify_cloaked_nation_flag is 1, the nation will take it as its own spies
87 return;
88 }
89
90 //----- think about rewarding this unit -----//
91
92 if( race_id && rank_id != RANK_KING &&
93 info.game_date%5 == sprite_recno%5 )
94 {
95 think_reward();
96 }
97
98 //-----------------------------------------//
99
100 if( !is_visible() )
101 return;
102
103 //--- if the unit has stopped, but ai_action_id hasn't been reset ---//
104
105 if( cur_action==SPRITE_IDLE && action_mode==ACTION_STOP &&
106 action_mode2==ACTION_STOP && ai_action_id )
107 {
108 nation_array[nation_recno]->action_failure(ai_action_id, sprite_recno);
109
110 err_when( ai_action_id ); // it should have been reset
111 }
112
113 //---- King flees under attack or surrounded by enemy ---//
114
115 if( race_id && rank_id==RANK_KING )
116 {
117 if( think_king_flee() )
118 return;
119 }
120
121 //---- General flees under attack or surrounded by enemy ---//
122
123 if( race_id && rank_id==RANK_GENERAL &&
124 info.game_date%7 == sprite_recno%7 )
125 {
126 if( think_general_flee() )
127 return;
128 }
129
130 //-- let Unit::next_day() process it process original_action_mode --//
131
132 if( original_action_mode )
133 return;
134
135 //------ if the unit is not stop right now ------//
136
137 if( !is_ai_all_stop() )
138 {
139 think_stop_chase();
140 return;
141 }
142
143 //-----------------------------------------//
144
145 if( mobile_type==UNIT_LAND )
146 {
147 if( ai_escape_fire() )
148 return;
149 }
150
151 //---------- if this is your spy --------//
152
153 if( spy_recno && true_nation_recno()==nation_recno )
154 think_spy_action();
155
156 //------ if this unit is from a camp --------//
157
158 if( home_camp_firm_recno )
159 {
160 Firm* firmCamp = firm_array[home_camp_firm_recno];
161 int rc;
162
163 if( rank_id == RANK_SOLDIER )
164 rc = firmCamp->worker_count < MAX_WORKER;
165 else
166 rc = !firmCamp->overseer_recno;
167
168 if( rc )
169 {
170 if( return_camp() )
171 return;
172 }
173
174 home_camp_firm_recno = 0; // the camp is already occupied by somebody
175 }
176
177 //----------------------------------------//
178
179 if( race_id && rank_id==RANK_KING )
180 {
181 think_king_action();
182 }
183 else if( race_id && rank_id==RANK_GENERAL )
184 {
185 think_general_action();
186 }
187 else
188 {
189 if( unit_res[unit_id]->unit_class == UNIT_CLASS_WEAPON )
190 {
191 if( info.game_date%15 == sprite_recno%15 ) // don't call too often as the action may fail and it takes a while to call the function each time
192 {
193 think_weapon_action(); //-- ships AI are called in UnitMarine --//
194 }
195 }
196 else if( race_id )
197 {
198 //--- if previous attempts for new action failed, don't call think_normal_human_action() so frequently then ---//
199
200 if( ai_no_suitable_action )
201 {
202 if( info.game_date%15 != sprite_recno%15 ) // don't call too often as the action may fail and it takes a while to call the function each time
203 return;
204 }
205
206 //---------------------------------//
207
208 if( !think_normal_human_action() )
209 {
210 ai_no_suitable_action = 1; // set this flag so think_normal_human_action() won't be called continously
211
212 if( !leader_unit_recno ) // only when the unit is not led by a commander
213 {
214 resign(COMMAND_AI);
215 }
216 else
217 {
218 ai_move_to_nearby_town();
219 }
220 }
221 }
222 }
223 }
224 //---------- End of function Unit::process_ai --------//
225
226
227 //--------- Begin of function Unit::think_stop_chase --------//
228
think_stop_chase()229 int Unit::think_stop_chase()
230 {
231 //-----------------------------------------------------//
232 //
233 // Stop the chase if the target is being far away from
234 // its original attacking location.
235 //
236 //-----------------------------------------------------//
237
238 if( !(action_mode==ACTION_ATTACK_UNIT && ai_original_target_x_loc>=0) )
239 return 0;
240
241 if( unit_array.is_deleted(action_para) )
242 {
243 stop2();
244 return 1;
245 }
246
247 Unit* targetUnit = unit_array[action_para];
248
249 if( !targetUnit->is_visible() )
250 {
251 stop2();
252 return 1;
253 }
254
255 //----------------------------------------//
256
257 int aiChaseDistance = 10 + nation_array[nation_recno]->pref_military_courage/20; // chase distance: 10 to 15
258
259 int curDistance = misc.points_distance( targetUnit->next_x_loc(), targetUnit->next_y_loc(),
260 ai_original_target_x_loc, ai_original_target_y_loc );
261
262 if( curDistance <= aiChaseDistance )
263 return 0;
264
265 //--------- stop the unit ----------------//
266
267 stop2();
268
269 //--- if this unit leads a troop, stop the action of all troop members as well ---//
270
271 int leaderUnitRecno;
272
273 if( leader_unit_recno )
274 leaderUnitRecno = leader_unit_recno;
275 else
276 leaderUnitRecno = sprite_recno;
277
278 TeamInfo* teamInfo = unit_array[leaderUnitRecno]->team_info;
279
280 if( teamInfo )
281 {
282 for( int i=teamInfo->member_count-1 ; i>=0 ; i-- )
283 {
284 int unitRecno = teamInfo->member_unit_array[i];
285
286 if( unit_array.is_deleted(unitRecno) )
287 continue;
288
289 unit_array[unitRecno]->stop2();
290 }
291 }
292
293 return 1;
294 }
295 //---------- End of function Unit::think_stop_chase --------//
296
297
298 //--------- Begin of function Unit::is_ai_all_stop --------//
299
is_ai_all_stop()300 int Unit::is_ai_all_stop()
301 {
302 return cur_action==SPRITE_IDLE && action_mode==ACTION_STOP &&
303 action_mode2==ACTION_STOP && !ai_action_id;
304 }
305 //---------- End of function Unit::is_ai_all_stop --------//
306
307
308 //--------- Begin of function Unit::ai_move_to_nearby_town --------//
309
ai_move_to_nearby_town()310 void Unit::ai_move_to_nearby_town()
311 {
312 //---- look for towns to assign to -----//
313
314 Nation* ownNation = nation_array[nation_recno];
315 Town *townPtr, *bestTown=NULL;
316 int regionId = world.get_region_id( next_x_loc(), next_y_loc() );
317 int curDistance, curRating, bestRating=0;
318 int curXLoc = next_x_loc(), curYLoc = next_y_loc();
319
320 for( int i=town_array.size() ; i>0 ; i-- ) // can't use ai_town_array[] because this function will be called by Unit::betray() when a unit defected to the player's kingdom
321 {
322 if( town_array.is_deleted(i) )
323 continue;
324
325 townPtr = town_array[i];
326
327 if( townPtr->nation_recno != nation_recno )
328 continue;
329
330 if( townPtr->region_id != regionId )
331 continue;
332
333 //-------------------------------------//
334
335 curDistance = misc.points_distance(curXLoc, curYLoc, townPtr->center_x, townPtr->center_y );
336
337 if( curDistance < 10 ) // no need to move if the unit is already close enough to the town.
338 return;
339
340 curRating = 100 - 100 * curDistance / MAX_WORLD_X_LOC;
341
342 curRating += townPtr->population;
343
344 //-------------------------------------//
345
346 if( curRating > bestRating )
347 {
348 bestRating = curRating;
349 bestTown = townPtr;
350 }
351 }
352
353 if( bestTown )
354 move_to_town_surround(bestTown->loc_x1, bestTown->loc_y1, sprite_info->loc_width, sprite_info->loc_height);
355 }
356 //---------- End of function Unit::ai_move_to_nearby_town --------//
357
358
359 //--------- Begin of function Unit::ai_escape_fire --------//
360 //
361 // Move away if the unit currently stands on a burning ground.
362 //
ai_escape_fire()363 int Unit::ai_escape_fire()
364 {
365 if(cur_action!=SPRITE_IDLE)
366 return 0;
367
368 if(mobile_type!=UNIT_LAND)
369 return 0;
370
371 Location *locPtr = world.get_loc(next_x_loc(), next_y_loc());
372
373 if( !locPtr->fire_str() )
374 return 0;
375
376 //--------------------------------------------//
377
378 int checkLimit = 400; // checking for 400 location
379 int xShift, yShift, checkXLoc, checkYLoc;
380 int curXLoc = next_x_loc();
381 int curYLoc = next_y_loc();
382
383 for(int i=2; i<checkLimit; i++)
384 {
385 misc.cal_move_around_a_point(i, 20, 20, xShift, yShift);
386
387 checkXLoc = curXLoc + xShift;
388 checkYLoc = curYLoc + yShift;
389
390 if(checkXLoc<0 || checkXLoc>=MAX_WORLD_X_LOC || checkYLoc<0 || checkYLoc>=MAX_WORLD_Y_LOC)
391 continue;
392
393 if(!locPtr->can_move(mobile_type))
394 continue;
395
396 locPtr = world.get_loc(checkXLoc, checkYLoc);
397
398 if( locPtr->fire_str()==0 ) // move to a safe place now
399 {
400 move_to(checkXLoc, checkYLoc);
401 return 1;
402 }
403 }
404
405 return 0;
406 }
407 //---------- End of function Unit::ai_escape_fire --------//
408
409
410 //--------- Begin of function Unit::think_spy_action --------//
411
think_spy_action()412 void Unit::think_spy_action()
413 {
414 ai_move_to_nearby_town(); // just move it to one of our towns
415 }
416 //---------- End of function Unit::think_spy_action --------//
417
418
419 //--------- Begin of function Unit::think_king_action --------//
420
think_king_action()421 int Unit::think_king_action()
422 {
423 return think_leader_action();
424 }
425 //---------- End of function Unit::think_king_action --------//
426
427
428 //--------- Begin of function Unit::think_general_action --------//
429
think_general_action()430 int Unit::think_general_action()
431 {
432 if( think_leader_action() )
433 return 1;
434
435 //--- if the general is not assigned to a camp due to its low competency ----//
436
437 Nation* ownNation = nation_array[nation_recno];
438 int rc = 0;
439
440 if( team_info->member_count <= 1 )
441 {
442 rc = 1;
443 }
444
445 //--- if the skill of the general and the number of soldiers he commands is not large enough to justify building a new camp ---//
446
447 else if( skill.skill_level + team_info->member_count*4
448 < 40 + ownNation->pref_keep_general/5 ) // 40 to 60
449 {
450 rc = 1;
451 }
452
453 //-- think about splitting the team and assign them into other forts --//
454
455 else if( ownNation->ai_has_too_many_camp() )
456 {
457 rc = 1;
458 }
459
460 //--------- demote the general to soldier and disband the troop -------//
461
462 if( rc )
463 {
464 set_rank(RANK_SOLDIER);
465 return think_normal_human_action();
466 }
467
468 return 0;
469 }
470 //---------- End of function Unit::think_general_action --------//
471
472
473 //--------- Begin of function Unit::think_leader_action --------//
474 //
475 // Think about the action of a leader (either a general or a king).
476 //
think_leader_action()477 int Unit::think_leader_action()
478 {
479 Nation* nationPtr = nation_array[nation_recno];
480 FirmCamp *firmCamp, *bestCamp=NULL;
481 int curRating, bestRating=10, delActionRecno=0;
482 int curXLoc = next_x_loc(), curYLoc = next_y_loc();
483 int curRegionId = world.get_region_id( curXLoc, curYLoc );
484
485 if( rank_id == RANK_KING ) // if this unit is the king, always assign it to a camp regardless of whether the king is a better commander than the existing one
486 bestRating = -1000;
487
488 err_when( skill.skill_id != SKILL_LEADING );
489
490 //----- think about which camp to move to -----//
491
492 for( int i=nationPtr->ai_camp_count-1 ; i>=0 ; i-- )
493 {
494 firmCamp = (FirmCamp*) firm_array[ nationPtr->ai_camp_array[i] ];
495
496 if( firmCamp->region_id != curRegionId )
497 continue;
498
499 //--- if the commander of this camp is the king, never replace him ---//
500
501 if( firmCamp->overseer_recno == nationPtr->king_unit_recno )
502 continue;
503
504 //-------------------------------------//
505
506 int curLeadership = firmCamp->cur_commander_leadership();
507 int newLeadership = firmCamp->new_commander_leadership(race_id, skill.skill_level);
508
509 curRating = newLeadership - curLeadership;
510
511 //-------------------------------------//
512
513 if( curRating > bestRating )
514 {
515 //--- if there is already somebody being assigned to it ---//
516
517 int actionRecno=0;
518
519 if( rank_id != RANK_KING ) // don't check this if the current unit is the king
520 {
521 actionRecno = nationPtr->is_action_exist(firmCamp->loc_x1, firmCamp->loc_y1,
522 -1, -1, ACTION_AI_ASSIGN_OVERSEER, FIRM_CAMP);
523
524 if( actionRecno && nationPtr->get_action(actionRecno)->processing_instance_count )
525 continue;
526 }
527
528 bestRating = curRating;
529 bestCamp = firmCamp;
530 delActionRecno = actionRecno;
531 }
532 }
533
534 if( !bestCamp )
535 return 0;
536
537 //----- delete an unprocessed queued action if there is any ----//
538
539 if( delActionRecno )
540 nationPtr->del_action(delActionRecno);
541
542 //--------- move to the camp now ---------//
543
544 //-- if there is room in the camp to host all soldiers led by this general --//
545
546 if( team_info->member_count-1 <= MAX_WORKER-bestCamp->worker_count )
547 {
548 validate_team();
549
550 unit_array.assign( bestCamp->loc_x1, bestCamp->loc_y1, 0, COMMAND_AI,
551 team_info->member_unit_array, team_info->member_count );
552 return 1;
553 }
554 else //--- otherwise assign the general only ---//
555 {
556 return nationPtr->add_action(bestCamp->loc_x1, bestCamp->loc_y1, -1, -1, ACTION_AI_ASSIGN_OVERSEER, FIRM_CAMP, 1, sprite_recno);
557 }
558
559 return 0;
560 }
561 //---------- End of function Unit::think_leader_action --------//
562
563
564 //--------- Begin of function Unit::think_normal_human_action --------//
565
think_normal_human_action()566 int Unit::think_normal_human_action()
567 {
568 if( home_camp_firm_recno )
569 return 0;
570
571 if( leader_unit_recno &&
572 unit_array[leader_unit_recno]->is_visible() ) // if the unit is led by a commander, let the commander makes the decision. If the leader has been assigned to a firm, don't consider it as a leader anymore
573 {
574 return 0;
575 }
576
577 err_when( !race_id );
578 err_when( !nation_recno );
579
580 //---- think about assign the unit to a firm that needs workers ----//
581
582 Nation* ownNation = nation_array[nation_recno];
583 Firm *firmPtr, *bestFirm=NULL;
584 int regionId = world.get_region_id( next_x_loc(), next_y_loc() );
585 int skillId = skill.skill_id;
586 int skillLevel = skill.skill_level;
587 int i, curRating, bestRating=0;
588 int curXLoc = next_x_loc(), curYLoc = next_y_loc();
589
590 if( skill.skill_id )
591 {
592 for( i=firm_array.size() ; i>0 ; i-- )
593 {
594 if( firm_array.is_deleted(i) )
595 continue;
596
597 firmPtr = firm_array[i];
598
599 if( firmPtr->nation_recno != nation_recno )
600 continue;
601
602 if( firmPtr->region_id != regionId )
603 continue;
604
605 curRating = 0;
606
607 if( skill.skill_id == SKILL_CONSTRUCTION ) // if this is a construction worker
608 {
609 if( firmPtr->builder_recno ) // assign the construction worker to this firm as an residental builder
610 continue;
611 }
612 else
613 {
614 if( !firmPtr->worker_array ||
615 firmPtr->firm_skill_id != skillId )
616 {
617 continue;
618 }
619
620 //----- if the firm is full of worker ------//
621
622 if( firmPtr->is_worker_full() )
623 {
624 //---- get the lowest skill worker of the firm -----//
625
626 Worker* workerPtr = firmPtr->worker_array;
627 int minSkill=100;
628
629 for( int j=0 ; j<firmPtr->worker_count ; j++, workerPtr++ )
630 {
631 if( workerPtr->skill_level < minSkill )
632 minSkill = workerPtr->skill_level;
633 }
634
635 //------------------------------//
636
637 if( firmPtr->majority_race() == race_id )
638 {
639 if( skill.skill_level < minSkill+10 )
640 continue;
641 }
642 else //-- for different race, only assign if the skill is significantly higher than the existing ones --//
643 {
644 if( skill.skill_level < minSkill+30 )
645 continue;
646 }
647 }
648 else
649 {
650 curRating += 300; // if the firm is not full, rating + 300
651 }
652 }
653
654 //-------- calculate the rating ---------//
655
656 curRating += world.distance_rating( curXLoc, curYLoc, firmPtr->center_x, firmPtr->center_y );
657
658 if( firmPtr->majority_race() == race_id )
659 curRating += 70;
660
661 curRating += (MAX_WORKER - firmPtr->worker_count) * 10;
662
663 //-------------------------------------//
664
665 if( curRating > bestRating )
666 {
667 bestRating = curRating;
668 bestFirm = firmPtr;
669 }
670 }
671
672 if( bestFirm )
673 {
674 assign(bestFirm->loc_x1, bestFirm->loc_y1);
675 return 1;
676 }
677 }
678
679 //---- look for towns to assign to -----//
680
681 bestRating = 0;
682 int hasTownInRegion=0;
683 Town *townPtr, *bestTown=NULL;
684
685 for( i=town_array.size() ; i>0 ; i-- ) // can't use ai_town_array[] because this function will be called by Unit::betray() when a unit defected to the player's kingdom
686 {
687 if( town_array.is_deleted(i) )
688 continue;
689
690 townPtr = town_array[i];
691
692 if( townPtr->nation_recno != nation_recno )
693 continue;
694
695 if( townPtr->region_id != regionId )
696 continue;
697
698 hasTownInRegion = 1;
699
700 if( townPtr->population >= MAX_TOWN_POPULATION || !townPtr->is_base_town )
701 continue;
702
703 //--- only assign to towns of the same race ---//
704
705 if( ownNation->pref_town_harmony > 50 )
706 {
707 if( townPtr->majority_race() != race_id )
708 continue;
709 }
710
711 //-------- calculate the rating ---------//
712
713 curRating = world.distance_rating(curXLoc, curYLoc, townPtr->center_x, townPtr->center_y );
714
715 curRating += 300 * townPtr->race_pop_array[race_id-1] / townPtr->population; // racial homogenous bonus
716
717 curRating += MAX_TOWN_POPULATION - townPtr->population;
718
719 //-------------------------------------//
720
721 if( curRating > bestRating )
722 {
723 bestRating = curRating;
724 bestTown = townPtr;
725 }
726 }
727
728 if( bestTown )
729 {
730 assign(bestTown->loc_x1, bestTown->loc_y1);
731 return 1;
732 }
733
734 //----- if we don't have any existing towns in this region ----//
735
736 if( !hasTownInRegion )
737 {
738
739 // --- if region is too small don't consider this area, stay in the island forever --//
740 if( region_array[regionId]->region_stat_id == 0 )
741 return 0;
742
743 //-- if we also don't have any existing camps in this region --//
744
745 if( region_array.get_region_stat(regionId)->camp_nation_count_array[nation_recno-1]==0 )
746 {
747 //---- try to build one if this unit can ----//
748
749 if( ownNation->cash > firm_res[FIRM_CAMP]->setup_cost &&
750 firm_res[FIRM_CAMP]->can_build(sprite_recno) &&
751 !leader_unit_recno ) // if this unit is commanded by a leader, let the leader build the camp
752 {
753 ai_build_camp();
754 }
755 }
756 else // if there is already a camp in this region, try to settle a new town next to the camp
757 {
758 ai_settle_new_town();
759 }
760
761 return 1; // if we don't have any town in this region, return 1, so this unit won't be resigned and so it can wait for other units to set up camps and villages later ---//
762 }
763
764 return 0;
765 }
766 //---------- End of function Unit::think_normal_human_action --------//
767
768
769 //--------- Begin of function Unit::think_weapon_action --------//
770
think_weapon_action()771 int Unit::think_weapon_action()
772 {
773 //---- first try to assign the weapon to an existing camp ----//
774
775 if( think_assign_weapon_to_camp() )
776 return 1;
777
778 //----- if no camp to assign, build a new one ------//
779
780 if( think_build_camp() )
781 return 1;
782
783 return 0;
784 }
785 //---------- End of function Unit::think_weapon_action --------//
786
787
788 //--------- Begin of function Unit::think_assign_weapon_to_camp --------//
789
think_assign_weapon_to_camp()790 int Unit::think_assign_weapon_to_camp()
791 {
792 Nation *nationPtr = nation_array[nation_recno];
793 FirmCamp *firmCamp, *bestCamp=NULL;
794 int curRating=0, bestRating=0;
795 int regionId = world.get_region_id( next_x_loc(), next_y_loc() );
796 int curXLoc = next_x_loc(), curYLoc = next_y_loc();
797
798 for( int i=0 ; i<nationPtr->ai_camp_count ; i++ )
799 {
800 firmCamp = (FirmCamp*) firm_array[ nationPtr->ai_camp_array[i] ];
801
802 if( firmCamp->region_id != regionId || firmCamp->is_worker_full() )
803 continue;
804
805 //-------- calculate the rating ---------//
806
807 curRating = world.distance_rating(curXLoc, curYLoc, firmCamp->center_x, firmCamp->center_y );
808
809 curRating += (MAX_WORKER - firmCamp->worker_count) * 10;
810
811 //-------------------------------------//
812
813 if( curRating > bestRating )
814 {
815 bestRating = curRating;
816 bestCamp = firmCamp;
817 }
818 }
819
820 //-----------------------------------//
821
822 if( bestCamp )
823 {
824 assign(bestCamp->loc_x1, bestCamp->loc_y1);
825 return 1;
826 }
827
828 return 0;
829 }
830 //---------- End of function Unit::think_assign_weapon_to_camp --------//
831
832
833 //--------- Begin of function Unit::think_build_camp --------//
834 //
835 // Think about building a camp next to the town which is
836 // closest to the unit.
837 //
think_build_camp()838 int Unit::think_build_camp()
839 {
840 //---- select a town to build the camp ---//
841
842 Nation* ownNation = nation_array[nation_recno];
843 Town *townPtr, *bestTown=NULL;
844 int curRating=0, bestRating=0;
845 int regionId = world.get_region_id( next_x_loc(), next_y_loc() );
846 int curXLoc = next_x_loc(), curYLoc = next_y_loc();
847
848 for( int i=ownNation->ai_town_count-1 ; i>=0 ; i-- )
849 {
850 townPtr = town_array[ ownNation->ai_town_array[i] ];
851
852 if( townPtr->region_id != regionId )
853 continue;
854
855 if( !townPtr->is_base_town || townPtr->no_neighbor_space )
856 continue;
857
858 curRating = world.distance_rating(curXLoc, curYLoc, townPtr->center_x, townPtr->center_y );
859
860 if( curRating > bestRating )
861 {
862 bestRating = curRating;
863 bestTown = townPtr;
864 }
865 }
866
867 if( bestTown )
868 return bestTown->ai_build_neighbor_firm(FIRM_CAMP);
869
870 return 0;
871 }
872 //---------- End of function Unit::think_build_camp --------//
873
874
875 //--------- Begin of function Unit::think_reward --------//
876
think_reward()877 int Unit::think_reward()
878 {
879 Nation* ownNation = nation_array[nation_recno];
880
881 //----------------------------------------------------------//
882 // The need to secure high loyalty on this unit is based on:
883 // -its skill
884 // -its combat level
885 // -soldiers commanded by this unit
886 //----------------------------------------------------------//
887
888 if( spy_recno && true_nation_recno() == nation_recno ) // if this is a spy of ours
889 {
890 return 0; // Spy::think_reward() will handle this.
891 }
892
893 int curLoyalty = loyalty;
894 int neededLoyalty;
895
896 //----- if this unit is on a mission ------/
897
898 if( ai_action_id )
899 {
900 neededLoyalty = UNIT_BETRAY_LOYALTY+10;
901 }
902
903 //----- otherwise only reward soldiers and generals ------//
904
905 else if( skill.skill_id == SKILL_LEADING )
906 {
907 //----- calculate the needed loyalty --------//
908
909 neededLoyalty = commanded_soldier_count()*5 + skill.skill_level;
910
911 if( unit_mode == UNIT_MODE_OVERSEE ) // if this unit is an overseer
912 {
913 if( loyalty < UNIT_BETRAY_LOYALTY ) // if this unit's loyalty is < betrayel level, reward immediately
914 {
915 reward(nation_recno); // reward it immediatley if it's an overseer, don't check ai_should_spend()
916 return 1;
917 }
918
919 neededLoyalty += 30;
920 }
921
922 neededLoyalty = MAX( UNIT_BETRAY_LOYALTY+10, neededLoyalty ); // 10 points above the betray loyalty level to prevent betrayal
923 neededLoyalty = MIN( 100, neededLoyalty );
924 }
925 else
926 {
927 return 0;
928 }
929
930 //------- if the loyalty is already high enough ------//
931
932 if( curLoyalty >= neededLoyalty )
933 return 0;
934
935 //---------- see how many cash & profit we have now ---------//
936
937 int rewardNeedRating = neededLoyalty - curLoyalty;
938
939 if( curLoyalty < UNIT_BETRAY_LOYALTY+5 )
940 rewardNeedRating += 50;
941
942 if( ownNation->ai_should_spend(rewardNeedRating) )
943 {
944 reward(nation_recno);
945 return 1;
946 }
947
948 return 0;
949 }
950 //---------- End of function Unit::think_reward --------//
951
952
953
954 //--------- Begin of function Unit::ai_leader_being_attacked --------//
955 //
956 // This function is called when the king is under attack.
957 //
958 // <int> attackerUnitRecno - recno of the attacker unit.
959 //
ai_leader_being_attacked(int attackerUnitRecno)960 void Unit::ai_leader_being_attacked(int attackerUnitRecno)
961 {
962 err_when( !team_info );
963
964 if( unit_array[attackerUnitRecno]->nation_recno == nation_recno ) // this can happen when the unit has just changed nation
965 return;
966
967 //------------------------------------//
968
969 int rc=0, callIntervalDays;
970
971 if( rank_id == RANK_KING )
972 {
973 rc = 1;
974 callIntervalDays = 7;
975 }
976 else if( rank_id == RANK_GENERAL )
977 {
978 rc = skill.skill_level >= 30 + (100-nation_array[nation_recno]->pref_keep_general)/2; // 30 to 80
979 callIntervalDays = 15; // don't call too freqently
980 }
981
982 if( rc )
983 {
984 if( info.game_date > team_info->ai_last_request_defense_date + callIntervalDays )
985 {
986 team_info->ai_last_request_defense_date = info.game_date;
987 nation_array[nation_recno]->ai_defend(attackerUnitRecno);
988 }
989 }
990 }
991 //---------- End of function Unit::ai_leader_being_attacked --------//
992
993
994 //--------- Begin of function Unit::think_king_flee --------//
995 //
996 // Note: we still need to keep think_king_action() because
997 // between these two functions, a number of things
998 // may be done, like returning home camp. We only
999 // carry out actions in this function if the king
1000 // is in danger and urgently need to flee.
1001 //
think_king_flee()1002 int Unit::think_king_flee()
1003 {
1004 if( force_move_flag && cur_action != SPRITE_IDLE ) // the king is already fleeing now
1005 return 1;
1006
1007 //------- if the king is alone --------//
1008
1009 Nation* ownNation = nation_array[nation_recno];
1010
1011 //------------------------------------------------//
1012 // When the king is alone and there is no assigned action OR
1013 // when the king is injured, the king will flee
1014 // back to its camp.
1015 //------------------------------------------------//
1016
1017 if( ( team_info->member_count==0 && !ai_action_id ) ||
1018 hit_points < 125-ownNation->pref_military_courage/4 )
1019 {
1020 //------------------------------------------//
1021 //
1022 // If the king is currently under attack, flee
1023 // to the nearest camp with the maximum protection.
1024 //
1025 //------------------------------------------//
1026
1027 Firm *firmCamp, *bestCamp=NULL;
1028 int curRating, bestRating=0;
1029 int curXLoc = next_x_loc(), curYLoc = next_y_loc();
1030 int curRegionId = world.get_region_id( curXLoc, curYLoc );
1031
1032 if( cur_action == SPRITE_ATTACK )
1033 {
1034 for( int i=ownNation->ai_camp_count-1 ; i>=0 ; i-- )
1035 {
1036 firmCamp = (FirmCamp*) firm_array[ ownNation->ai_camp_array[i] ];
1037
1038 if( firmCamp->region_id != curRegionId )
1039 continue;
1040
1041 if( firmCamp->overseer_recno && rank_id!=RANK_KING ) // if there is already a commander in this camp. However if this is the king, than ingore this
1042 continue;
1043
1044 curRating = world.distance_rating( curXLoc, curYLoc,
1045 firmCamp->center_x, firmCamp->center_y );
1046
1047 if( curRating > bestRating )
1048 {
1049 bestRating = curRating;
1050 bestCamp = firmCamp;
1051 }
1052 }
1053
1054 }
1055 else if( home_camp_firm_recno ) // if there is a home for the king
1056 {
1057 bestCamp = firm_array[home_camp_firm_recno];
1058 }
1059
1060 //------------------------------------//
1061
1062 if( bestCamp )
1063 {
1064 if( config.ai_aggressiveness > OPTION_LOW )
1065 force_move_flag = 1;
1066
1067 assign( bestCamp->loc_x1, bestCamp->loc_y1 );
1068 }
1069 else // if the king is neither under attack or has a home camp, then call the standard think_leader_action()
1070 {
1071 think_leader_action();
1072 }
1073
1074 return cur_action != SPRITE_IDLE;
1075 }
1076
1077 return 0;
1078 }
1079 //---------- End of function Unit::think_king_flee --------//
1080
1081
1082 //--------- Begin of function Unit::think_general_flee --------//
1083
think_general_flee()1084 int Unit::think_general_flee()
1085 {
1086 if( force_move_flag && cur_action != SPRITE_IDLE ) // the general is already fleeing now
1087 return 1;
1088
1089 //------- if the general is alone --------//
1090
1091 Nation* ownNation = nation_array[nation_recno];
1092
1093 //------------------------------------------------//
1094 // When the general is alone and there is no assigned action OR
1095 // when the general is injured, the general will flee
1096 // back to its camp.
1097 //------------------------------------------------//
1098
1099 if( ( team_info->member_count==0 && !ai_action_id ) ||
1100 hit_points < max_hit_points * (75+ownNation->pref_military_courage/2) / 200 ) // 75 to 125 / 200
1101 {
1102 //------------------------------------------//
1103 //
1104 // If the general is currently under attack, flee
1105 // to the nearest camp with the maximum protection.
1106 //
1107 //------------------------------------------//
1108
1109 Firm *firmCamp, *bestCamp=NULL;
1110 int curRating, bestRating=0;
1111 int curXLoc = next_x_loc(), curYLoc = next_y_loc();
1112 int curRegionId = world.get_region_id( curXLoc, curYLoc );
1113
1114 if( cur_action == SPRITE_ATTACK )
1115 {
1116 for( int i=ownNation->ai_camp_count-1 ; i>=0 ; i-- )
1117 {
1118 firmCamp = (FirmCamp*) firm_array[ ownNation->ai_camp_array[i] ];
1119
1120 if( firmCamp->region_id != curRegionId )
1121 continue;
1122
1123 curRating = world.distance_rating( curXLoc, curYLoc,
1124 firmCamp->center_x, firmCamp->center_y );
1125
1126 if( curRating > bestRating )
1127 {
1128 bestRating = curRating;
1129 bestCamp = firmCamp;
1130 }
1131 }
1132
1133 }
1134 else if( home_camp_firm_recno ) // if there is a home for the general
1135 {
1136 bestCamp = firm_array[home_camp_firm_recno];
1137 }
1138
1139 //------------------------------------//
1140
1141 if( bestCamp )
1142 {
1143 if( bestCamp->overseer_recno ) // if there is already an overseer there, just move close to the camp for protection
1144 {
1145 if( config.ai_aggressiveness > OPTION_LOW )
1146 force_move_flag = 1;
1147
1148 move_to( bestCamp->loc_x1, bestCamp->loc_y1 );
1149 }
1150 else
1151 assign( bestCamp->loc_x1, bestCamp->loc_y1 );
1152 }
1153 else // if the general is neither under attack or has a home camp, then call the standard think_leader_action()
1154 {
1155 think_leader_action();
1156 }
1157
1158 return cur_action != SPRITE_IDLE;
1159 }
1160
1161 return 0;
1162 }
1163 //---------- End of function Unit::think_general_flee --------//
1164
1165
1166 //--------- Begin of function Unit::ai_build_camp --------//
1167 //
1168 // Order this unit to build a camp in its region.
1169 //
ai_build_camp()1170 int Unit::ai_build_camp()
1171 {
1172 //--- to prevent building more than one camp at the same time ---//
1173
1174 int curRegionId = region_id();
1175 Nation* ownNation = nation_array[nation_recno];
1176
1177 if( ownNation->is_action_exist( ACTION_AI_BUILD_FIRM, FIRM_CAMP, curRegionId ) )
1178 return 0;
1179
1180 //------- locate a place for the camp --------//
1181
1182 FirmInfo* firmInfo = firm_res[FIRM_CAMP];
1183 int xLoc=0, yLoc=0;
1184 char teraMask = UnitRes::mobile_type_to_mask(UNIT_LAND);
1185
1186 if( world.locate_space_random(xLoc, yLoc, MAX_WORLD_X_LOC-1,
1187 MAX_WORLD_Y_LOC-1, firmInfo->loc_width+2, firmInfo->loc_height+2, // leave at least one location space around the building
1188 MAX_WORLD_X_LOC*MAX_WORLD_Y_LOC, curRegionId, 1, teraMask) )
1189 {
1190 return ownNation->add_action( xLoc, yLoc, -1, -1,
1191 ACTION_AI_BUILD_FIRM, FIRM_CAMP, 1, sprite_recno );
1192 }
1193
1194 return 0;
1195 }
1196 //---------- End of function Unit::ai_build_camp --------//
1197
1198
1199 //--------- Begin of function Unit::ai_settle_new_town --------//
1200 //
1201 // Settle a new village next to one of the camps in this region.
1202 //
ai_settle_new_town()1203 int Unit::ai_settle_new_town()
1204 {
1205 //----- locate a suitable camp for the new town to settle next to ----//
1206
1207 Nation* ownNation = nation_array[nation_recno];
1208 FirmCamp* firmCamp, *bestCamp=NULL;
1209 int curRegionId = region_id();
1210 int curRating, bestRating=0;
1211
1212 for( int i=ownNation->ai_camp_count-1 ; i>=0 ; i-- )
1213 {
1214 firmCamp = (FirmCamp*) firm_array[ ownNation->ai_camp_array[i] ];
1215
1216 if( firmCamp->region_id != curRegionId )
1217 continue;
1218
1219 curRating = firmCamp->total_combat_level();
1220
1221 if( curRating > bestRating )
1222 {
1223 bestRating = curRating;
1224 bestCamp = firmCamp;
1225 }
1226 }
1227
1228 if( !bestCamp )
1229 return 0;
1230
1231 //--------- settle a new town now ---------//
1232
1233 int xLoc=bestCamp->loc_x1;
1234 int yLoc=bestCamp->loc_y1;
1235
1236 if( world.locate_space(&xLoc, &yLoc, bestCamp->loc_x2, bestCamp->loc_y2,
1237 STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT,
1238 UNIT_LAND, curRegionId, 1 ) ) // 1-build flag
1239 {
1240 settle( xLoc, yLoc );
1241 return 1;
1242 }
1243
1244 return 0;
1245 }
1246 //---------- End of function Unit::ai_settle_new_town --------//
1247
1248
1249 //--------- Begin of function Unit::ai_handle_seek_path_fail --------//
1250 //
1251 // This function is used for handling cases when AI units are not
1252 // able to seek a path successfully.
1253 //
ai_handle_seek_path_fail()1254 int Unit::ai_handle_seek_path_fail()
1255 {
1256 if( seek_path_fail_count < 5 ) // wait unit it has failed many times
1257 return 0;
1258
1259 //----- try to move to a new location -----//
1260
1261 if( seek_path_fail_count==5 )
1262 {
1263 stop2(); // stop the unit and think for new action
1264 return 0;
1265 }
1266
1267 //--- if the seek path has failed too many times, resign the unit ---//
1268
1269 int resignFlag = 0;
1270
1271 if( rank_id == RANK_SOLDIER && !leader_unit_recno )
1272 {
1273 if( seek_path_fail_count>=7 )
1274 resignFlag = 1;
1275 }
1276 else if( rank_id == RANK_GENERAL )
1277 {
1278 if( seek_path_fail_count >= 7+skill.skill_level/10 )
1279 resignFlag = 1;
1280 }
1281
1282 if( resignFlag && is_visible() )
1283 {
1284 resign(COMMAND_AI);
1285 return 1;
1286 }
1287 else
1288 return 0;
1289 }
1290 //---------- End of function Unit::ai_handle_seek_path_fail --------//
1291
1292