/*
* Seven Kingdoms: Ancient Adversaries
*
* Copyright 1997,1998 Enlight Software Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
//Filename : OU_MONS.CPP
//Description: Unit Monster
#include
#include
#include
#include
#include
#include
#include
//--------- Begin of function UnitMonster::UnitMonster --------//
UnitMonster::UnitMonster()
{
monster_action_mode = MONSTER_ACTION_STOP;
}
//---------- End of function UnitMonster::UnitMonster --------//
//--------- Begin of function UnitMonster::set_monster_action_mode --------//
void UnitMonster::set_monster_action_mode(char monsterActionMode)
{
monster_action_mode = monsterActionMode;
}
//---------- End of function UnitMonster::set_monster_action_mode --------//
//--------- Begin of function UnitMonster::unit_name ---------//
//
// [int] withTitle - whether return a string with the title of the unit
// or not. (default: 1)
//
char* UnitMonster::unit_name(int withTitle)
{
static String str;
char* monsterName = monster_res[get_monster_id()]->name; // contribution is used for storing the monster id. temporary
str = monsterName;
switch( rank_id )
{
case RANK_KING:
#if(defined(SPANISH))
str = "Gran Todo ";
str += monsterName;
#elif(defined(FRENCH))
str = "Tout Puissant ";
str += monsterName;
#elif(defined(GERMAN))
str = "Hochkönig ";
str += monsterName;
#else
// GERMAN US
str = "All High ";
str += monsterName;
#endif
break;
case RANK_GENERAL:
#if(defined(SPANISH) || defined(FRENCH))
str = "Ordo ";
str += monsterName;
#else
// GERMAN US
str += " Ordo";
#endif
break;
}
return str;
}
//--------- End of function UnitMonster::unit_name ---------//
//--------- Begin of function UnitMonster::process_ai --------//
//
void UnitMonster::process_ai()
{
//----- when it is idle -------//
if( !is_visible() || !is_ai_all_stop() )
return;
if( info.game_date%15 == sprite_recno%15 )
{
random_attack(); // randomly attacking targets
/*
switch(m.random(2))
{
case 0:
random_attack(); // randomly attacking targets
break;
case 1:
assign_to_firm(); // assign the monsters to other monster structures
break;
}
*/
}
}
//---------- End of function UnitMonster::process_ai --------//
//------- Begin of function UnitMonster::die -------//
//
void UnitMonster::die()
{
if( !is_visible() )
return;
//--- check if the location where the unit dies already has an item ---//
int xLoc = cur_x_loc();
int yLoc = cur_y_loc();
if( !world.get_loc(xLoc, yLoc)->can_build_site() )
{
int txLoc, tyLoc, foundFlag=0;
for( tyLoc=max(yLoc-1,0) ; tyLoc<=min(yLoc+1,MAX_WORLD_Y_LOC-1) && !foundFlag ; tyLoc++ )
{
for( txLoc=max(xLoc-1,0) ; txLoc<=min(xLoc+1,MAX_WORLD_X_LOC-1) ; txLoc++ )
{
if( world.get_loc(txLoc,tyLoc)->can_build_site() )
{
xLoc = txLoc;
yLoc = tyLoc;
foundFlag = 1;
break;
}
}
}
if( !foundFlag )
return;
}
//--- when a general monster is killed, it leaves gold coins ---//
if( !nation_recno && get_monster_id() != 0) // to skip monster_res[ get_monster_id() ] error in test game 2
{
MonsterInfo* monsterInfo = monster_res[ get_monster_id() ];
if( rank_id == RANK_GENERAL )
{
int goldAmount = 2 * max_hit_points * monsterInfo->level * (100+m.random(30)) / 100;
site_array.add_site( xLoc, yLoc, SITE_GOLD_COIN, goldAmount );
site_array.ai_get_site_object(); // ask AI units to get the gold coins
}
//--- when a king monster is killed, it leaves a scroll of power ---//
else if( rank_id == RANK_KING )
{
king_leave_scroll();
}
}
//---------- add news ----------//
if( rank_id == RANK_KING )
news_array.monster_king_killed( get_monster_id(), next_x_loc(), next_y_loc() );
}
//-------- End of function UnitMonster::die -------//
//------- Begin of function UnitMonster::king_leave_scroll -------//
//
void UnitMonster::king_leave_scroll()
{
#define SCROLL_SCAN_RANGE 10
int xOffset, yOffset;
int xLoc, yLoc;
Location* locPtr;
int curXLoc = next_x_loc(), curYLoc = next_y_loc();
BYTE regionId = world.get_region_id(curXLoc, curYLoc);
short raceCountArray[MAX_RACE];
memset( raceCountArray, 0, sizeof(raceCountArray) );
int i;
for( i=2 ; ihas_unit(UNIT_LAND) )
{
Unit* unitPtr = unit_array[locPtr->unit_recno(UNIT_LAND)];
raceCountArray[ unitPtr->race_id-1 ]++;
}
}
//------ find out which race is most populated in the area -----//
int maxRaceCount=0, bestRaceId=0;
for( i=0 ; i maxRaceCount )
{
maxRaceCount = raceCountArray[i];
bestRaceId = i+1;
}
}
if( !bestRaceId )
bestRaceId = m.random(MAX_RACE)+1; // if there is no human units nearby (perhaps just using weapons)
//------ locate for space to add the scroll -------//
#define ADD_SITE_RANGE 5
for( i=1 ; ican_build_site() && locPtr->region_id==regionId )
{
int scrollGodId = bestRaceId;
site_array.add_site( xLoc, yLoc, SITE_SCROLL, scrollGodId );
site_array.ai_get_site_object(); // ask AI units to get the scroll
break;
}
}
}
//-------- End of function UnitMonster::king_leave_scroll -------//
//--------- Begin of function UnitMonster::random_attack --------//
//
// Randomly pick an object to attack.
//
int UnitMonster::random_attack()
{
#define ATTACK_SCAN_RANGE 100
int xOffset, yOffset;
int xLoc, yLoc;
Location* locPtr;
int curXLoc = next_x_loc(), curYLoc = next_y_loc();
BYTE regionId = world.get_region_id(curXLoc, curYLoc);
int rc;
for( int i=2 ; iregion_id != regionId )
continue;
rc = 0;
//----- if there is a unit on the location ------//
if( locPtr->has_unit(UNIT_LAND) )
{
int unitRecno = locPtr->unit_recno(UNIT_LAND);
if( unit_array.is_deleted(unitRecno) )
continue;
rc = 1;
}
//----- if there is a firm on the location ------//
if( !rc && locPtr->is_firm() )
{
int firmRecno = locPtr->firm_recno();
if( firm_array.is_deleted(firmRecno) )
continue;
rc = 1;
}
//----- if there is a town on the location ------//
if( !rc && locPtr->is_town() )
{
int townRecno = locPtr->town_recno();
if( town_array.is_deleted(townRecno) )
continue;
rc = 1;
}
//-------------------------------------//
if( rc )
{
group_order_monster(xLoc, yLoc, 1); // 1-the action is attack
return 1;
}
}
return 0;
}
//---------- End of function UnitMonster::random_attack --------//
//--------- Begin of function UnitMonster::assign_to_firm --------//
//
int UnitMonster::assign_to_firm()
{
int i, firmCount=firm_array.size();
Firm* firmPtr;
int curXLoc = next_x_loc(), curYLoc = next_y_loc();
BYTE regionId = world.get_region_id(curXLoc, curYLoc);
int firmRecno = m.random(firm_array.size())+1;
for( i=0 ; i firmCount )
firmRecno = 1;
if( firm_array.is_deleted(firmRecno) )
continue;
firmPtr = firm_array[firmRecno];
if( firmPtr->region_id != regionId )
continue;
if( firmPtr->firm_id == FIRM_MONSTER )
{
if( ((FirmMonster*)firmPtr)->can_assign_monster(sprite_recno) )
{
group_order_monster(firmPtr->loc_x1, firmPtr->loc_y1, 2); // 2-the action is assign
return 1;
}
}
}
return 0;
}
//---------- End of function UnitMonster::assign_to_firm --------//
//--------- Begin of function UnitMonster::group_order_monster --------//
//
// destXLoc, destYLoc - location of the destination.
// actionType - 1-attack, 2-assign.
//
void UnitMonster::group_order_monster(int destXLoc, int destYLoc, int actionType)
{
#define GROUP_ACTION_RANGE 30 // only notify units within this range
#define MAX_MONSTER_GROUP_COUNT 15
int curXLoc = next_x_loc(), curYLoc = next_y_loc();
BYTE regionId = world.get_region_id(curXLoc, curYLoc);
short unitOrderedArray[MAX_MONSTER_GROUP_COUNT];
int unitOrderedCount=0;
int xOffset, yOffset;
int xLoc, yLoc;
Location* locPtr;
Unit* unitPtr;
//----------------------------------------------//
for( int i=1 ; ihas_unit(UNIT_LAND) )
continue;
//------------------------------//
int unitRecno = locPtr->unit_recno(UNIT_LAND);
if( unit_array.is_deleted(unitRecno) )
continue;
unitPtr = unit_array[unitRecno];
if( unit_res[unitPtr->unit_id]->unit_class != UNIT_CLASS_MONSTER )
continue;
unitOrderedArray[unitOrderedCount] = unitRecno;
if( ++unitOrderedCount >= MAX_MONSTER_GROUP_COUNT )
break;
}
if( unitOrderedCount == 0 )
return;
//---------------------------------------//
if( actionType==1 ) // attack
{
// ##### patch begin Gilbert 5/8 ######//
unit_array.attack( destXLoc, destYLoc, 0, unitOrderedArray, unitOrderedCount, COMMAND_AI, 0 );
// ##### patch end Gilbert 5/8 ######//
}
else
{
unit_array.assign( destXLoc, destYLoc, 0, COMMAND_AI, unitOrderedArray, unitOrderedCount);
}
}
//---------- End of function UnitMonster::group_order_monster --------//