소스 검색

Merged changes from trunk.

Michał W. Urbańczyk 15 년 전
부모
커밋
f020562570

+ 10 - 11
AI/GeniusAI/AIPriorities.cpp

@@ -100,11 +100,11 @@ void Priorities::fillFeatures(const CGeniusAI::HypotheticalGameState & hgs)
 
 float Priorities::getCost(vector<int> &resourceCosts,const CGHeroInstance * moved,int distOutOfTheWay)
 {
-	if(resourceCosts.size()==0)return -1;
+	if(!resourceCosts.size())return -1;
 	//TODO: replace with ann
 	float cost = resourceCosts[0]/4.0+resourceCosts[1]/2.0+resourceCosts[2]/4.0+resourceCosts[3]/2.0+resourceCosts[4]/2.0+resourceCosts[5]/2.0+resourceCosts[6]/3000.0;
 	
-	if(moved!=NULL)						//TODO: multiply by importance of hero
+	if(moved)						//TODO: multiply by importance of hero
 		cost+=distOutOfTheWay/10000.0;
 	return cost;
 }
@@ -210,25 +210,24 @@ float Priorities::getValue(const CGeniusAI::AIObjective & obj)
 			//objectNetworks[53][hobj->object->subID].feedForward(stateFeatures);
 		case 113://TODO: replace with value of skill for the hero
 			return 0;
-		case 103:case 58://TODO: replace with value of seeing x number of new tiles 
+		case 103: case 58://TODO: replace with value of seeing x number of new tiles 
 			return 0;
 		default:
-			if(objectNetworks[hobj->object->ID].size()!=0)
+			if (objectNetworks[hobj->object->ID].size())
 				return objectNetworks[hobj->object->ID][0].feedForward(stateFeatures);
-			cout << "don't know the value of ";
+			tlog6 << "don't know the value of ";
 			switch(obj.type)
 			{
 			case CGeniusAI::AIObjective::visit:
-				cout << "visiting " << hobj->object->ID;
+				tlog6 << "visiting " << hobj->object->ID;
 				break;
-			case CGeniusAI::AIObjective::attack:
-				cout << "attacking " << hobj->object->ID;
+				tlog6 << "attacking " << hobj->object->ID;
 				break;
 			case CGeniusAI::AIObjective::finishTurn:
 				obj.print();
 				break;
 			}
-			cout << endl;
+			tlog6 << endl;
 		}
 	}
 	else	//town objective
@@ -240,9 +239,9 @@ float Priorities::getValue(const CGeniusAI::AIObjective & obj)
 				return buildingNetworks[tnObj->whichTown->t->subID][tnObj->which].feedForward(stateFeatures);
 			else
 			{
-				cout << "don't know the value of ";
+				tlog6 << "don't know the value of ";
 				obj.print();
-				cout << endl;
+				tlog6 << endl;
 			}
 
 		}

+ 1 - 1
AI/GeniusAI/BattleLogic.cpp

@@ -42,7 +42,7 @@ ui8 side; //who made this action: false - left, true - right player
 /**
  *	Implementation of CBattleLogic class.
  */
-CBattleLogic::CBattleLogic(ICallback *cb,  const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side) :
+CBattleLogic::CBattleLogic(ICallback *cb,  const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side) :
 	m_iCurrentTurn(-2),
 	m_bIsAttacker(!side),
 	m_cb(cb),

+ 3 - 3
AI/GeniusAI/BattleLogic.h

@@ -63,7 +63,7 @@ private:
 		int leftHitPoint_for_min; // scenario
 	};
 public:
-	CBattleLogic(ICallback *cb, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side);
+	CBattleLogic(ICallback *cb, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side);
 	~CBattleLogic();
 
 	void SetCurrentTurn(int turn);
@@ -80,8 +80,8 @@ private:
 	const CCreatureSet *m_army1;
 	const CCreatureSet *m_army2;
 	int3 m_tile;
-	CGHeroInstance *m_hero1;
-	CGHeroInstance *m_hero2;
+	const CGHeroInstance *m_hero1;
+	const CGHeroInstance *m_hero2;
 	bool m_side;
 
 	// statistics

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 349 - 339
AI/GeniusAI/CGeniusAI.cpp


+ 10 - 11
AI/GeniusAI/CGeniusAI.h

@@ -28,11 +28,10 @@ class CGeniusAI : public CGlobalAI
 {
 private:
   // TODO: cb... come back, croach busters!?
-	ICallback*							          m_cb;
+	ICallback*							m_cb;
 	geniusai::BattleAI::CBattleLogic*	m_battleLogic;
 	geniusai::GeneralAI::CGeneralAI		m_generalAI;
-	geniusai::Priorities*				      m_priorities;
-
+	geniusai::Priorities*				m_priorities;
 	
 	CondSh<BattleState> m_state; //are we engaged into battle?
 
@@ -71,7 +70,7 @@ private:
 		void update(CGeniusAI & ai);
 		CGeniusAI * AI;
 		std::vector<const CGHeroInstance *> AvailableHeroesToBuy;
-		std::vector<int> resourceAmounts;
+		std::vector<ui32> resourceAmounts;
 		std::vector<HeroModel> heroModels;
 		std::vector<TownModel> townModels;
 		std::set< AIObjectContainer > knownVisitableObjects;
@@ -110,7 +109,7 @@ private:
 	public:
 		HypotheticalGameState hgs;
 		int3 pos;
-		const CGObjectInstance * object;
+		const CGObjectInstance * object; //interactive object
 		mutable std::vector<HypotheticalGameState::HeroModel*> whoCanAchieve;
 		
 		//HeroObjective(){}
@@ -202,14 +201,14 @@ public:
 	// battle
 	virtual void actionFinished(const BattleAction *action);//occurs AFTER every action taken by any stack or by the hero
 	virtual void actionStarted(const BattleAction *action);//occurs BEFORE every action taken by any stack or by the hero
-	virtual void battleAttack(BattleAttack *ba); //called when stack is performing attack
-	virtual void battleStacksAttacked(std::set<BattleStackAttacked> & bsa); //called when stack receives damage (after battleAttack())
-	virtual void battleEnd(BattleResult *br);
+	virtual void battleAttack(const BattleAttack *ba); //called when stack is performing attack
+	virtual void battleStacksAttacked(const std::set<BattleStackAttacked> & bsa); //called when stack receives damage (after battleAttack())
+	virtual void battleEnd(const BattleResult *br);
 	virtual void battleNewRound(int round); //called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
 	virtual void battleStackMoved(int ID, int dest, int distance, bool end);
-	virtual void battleSpellCast(BattleSpellCast *sc);
-	virtual void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side); //called by engine when battle starts; side=0 - left, side=1 - right
-	virtual void battlefieldPrepared(int battlefieldType, std::vector<CObstacle*> obstacles); //called when battlefield is prepared, prior the battle beginning
+	virtual void battleSpellCast(const BattleSpellCast *sc);
+	virtual void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side); //called by engine when battle starts; side=0 - left, side=1 - right
+	//virtual void battlefieldPrepared(int battlefieldType, std::vector<CObstacle*> obstacles); //called when battlefield is prepared, prior the battle beginning
 	//
 	virtual void battleStackMoved(int ID, int dest, bool startMoving, bool endMoving);
 	virtual void battleStackAttacking(int ID, int dest);

+ 11 - 6
AI/GeniusAI/ExpertSystem.cpp

@@ -45,11 +45,7 @@ template <typename ruleType, typename facts> template <typename cond> void Exper
 								++goalCounter;
 						}
 					}
-					matchedConditions = 0;
 					//modify set until something happens (hopefully!)
-					for (iF = factsToErase.begin(); iF != factsToErase.end(); iF++)
-						factList.erase(knowledge.find(*iF));
-					factsToErase.clear(); //TODO: what if fact is remembered by rule, yet already erased?
 					for (iF = factsToAdd.begin(); iF != factsToAdd.end(); iF++)
 						factList.insert(*iF);
 					if (factsToAdd.size())
@@ -58,6 +54,9 @@ template <typename ruleType, typename facts> template <typename cond> void Exper
 						factWasAdded = true;
 					}
 				}
+				for (iF = factsToErase.begin(); iF != factsToErase.end(); iF++) //remove facts discarded in this run
+						factList.erase(knowledge.find(*iF));
+				factsToErase.clear(); //erase only after all rules had a chance to trigger
 				for (ir = rulesToErase.begin(); ir != rulesToErase.end(); ir++)
 					knowledge.erase(knowledge.find(*ir));
 				rulesToErase.clear();
@@ -89,13 +88,13 @@ void BonusRule::fireRule()
 			case BonusCondition::duration:
 				if (!it->first.functor(it->second->object->duration, it->first.value)) return;
 			break;
-			case BonusCondition::source:
+			case BonusCondition::source: //likely to handle by selector
 				if (!it->first.functor(it->second->object->source, it->first.value)) return;
 			break;
 			case BonusCondition::id:
 				if (!it->first.functor(it->second->object->id, it->first.value)) return;
 			break;
-			case BonusCondition::valType:
+			case BonusCondition::valType: //ever needed?
 				if (!it->first.functor(it->second->object->valType, it->first.value)) return;
 			break;
 			case BonusCondition::additionalInfo:
@@ -110,12 +109,18 @@ void BonusRule::fireRule()
 	}
 	//TODO: add new fact or modify existing one
 }
+//TODO: find out why it does not compile
 //template <typename input, typename conType> void Rule<input, conType>::refreshRule(std::set<conType> &conditionSet)
 //{
 //	cons.clear();
 //	for (std::set<conType>::iterator it = conditionSet.begin(); it != conditionSet.end(); it++)
 //		cons.insert(std::make_pair<conType,input*>(*it, NULL)); //pointer to condition and null fact
 //}
+//template <typename input, typename conType> void Rule<input, conType>::refreshRule()
+//{
+//	for (std::set<std::pair<conType, input*>>::iterator it = cons.begin(); it != cons.end(); it++)
+//		*it->second = NULL;
+//}
 bool BonusCondition::matchesFact(Bonus &fact)
 {
 	if (object(fact)) //Bonus(fact) matches local Selector(object)

+ 44 - 5
AI/GeniusAI/ExpertSystem.h

@@ -53,7 +53,7 @@ public:
 };
 
 template <typename input> class condition
-{//determines selected object parameter with value using functor
+{//compares selected object parameter with value using functor. universal logic handler
 public:
 	input object; //what the fact is, or what it's like (CSelector)
 	si32 value;
@@ -74,9 +74,13 @@ public:
 protected:
 	std::set<std::pair<conType, input*>> cons; //conditions and matching facts
 	input decision;
-	virtual void canBeFired(); //if this data makes any sense for rule
-	virtual void fireRule(std::set<input*> &feed);
+	virtual void canBeFired(); //if this data makes any sense for rule - type check
+	virtual bool checkCondition(); //if condition is true or false
+	virtual bool checkCondition(std::set<input*> &feed);
 	virtual void fireRule(); //use paired conditions and facts by default
+	virtual void fireRule(ExpertSystemShell<input, conType> &system);
+	virtual void fireRule(std::set<input*> &feed);
+	virtual void refreshRule();
 	virtual void refreshRule(std::set<conType> &conditionSet); //in case conditions were erased
 public:
 	Rule(){fired = false; conditionCounter = 0; decision = NULL;};
@@ -124,21 +128,56 @@ public:
 	};
 	bool matchesFact(Bonus &fact);
 };
+
 class BonusHolder : public AIholder<Bonus>
 {
 public:
 	BonusHolder(Bonus &bonus){object = &bonus; aiValue = bonus.val;}
 	BonusHolder(Bonus &bonus, si32 val){object = &bonus; aiValue = val;}
 };
+
 class BonusRule : public Rule <BonusHolder, BonusCondition>
 {
 protected:
 	void fireRule();
 };
 
-bool greaterThan (int prop, si32 val)
+inline bool greaterThan (int prop, si32 val)
 {
 	if ((si32)prop > val)
 		return true;
 	return false;
-}
+}
+inline bool lessThan (int prop, si32 val)
+{
+	if ((si32)prop < val)
+		return true;
+	return false;
+}
+inline bool eqal (int prop, si32 val)
+{
+	if ((si32)prop == val)
+		return true;
+	return false;
+}
+inline bool unequal (int prop, si32 val)
+{
+	if ((si32)prop != val)
+		return true;
+	return false;
+}
+inline bool present (int prop, si32 val=0)
+//inline bool present (int prop) //TODO: can we use function with less arguments?
+{
+	return(prop); //unfixable warning :(
+}
+
+class KnowledgeHandler///I'd opt for one omniscent knowledge manager, so no templates here
+{
+public:
+	std::list<BonusRule> knowledge; //permanent storage of rules
+
+	void parseKnowledge(std::string &filename){};
+	void addKnowledge(ExpertSystemShell<BRule,Bonus> &expert);
+	void addFacts(ExpertSystemShell<BRule,Bonus> &expert);
+};

+ 4 - 0
CConsoleHandler.cpp

@@ -42,6 +42,7 @@
 	#define CONSOLE_YELLOW FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY
 	#define CONSOLE_WHITE FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY
 	#define CONSOLE_GRAY FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
+	#define CONSOLE_TEAL FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY
 #endif
 
 TColor defColor;
@@ -168,6 +169,9 @@ void CConsoleHandler::setColor(int level)
 	case 5:
 		color = CONSOLE_GRAY;
 		break;
+	case -2:
+		color = CONSOLE_TEAL;
+		break;
 	default:
 		color = defColor;
 		break;

+ 7 - 7
CGameInterface.h

@@ -111,17 +111,17 @@ public:
 	virtual void actionFinished(const BattleAction *action){};//occurs AFTER every action taken by any stack or by the hero
 	virtual void actionStarted(const BattleAction *action){};//occurs BEFORE every action taken by any stack or by the hero
 	virtual BattleAction activeStack(int stackID)=0; //called when it's turn of that stack
-	virtual void battleAttack(BattleAttack *ba){}; //called when stack is performing attack
-	virtual void battleStacksAttacked(std::vector<BattleStackAttacked> & bsa){}; //called when stack receives damage (after battleAttack())
-	virtual void battleEnd(BattleResult *br){};
+	virtual void battleAttack(const BattleAttack *ba){}; //called when stack is performing attack
+	virtual void battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa){}; //called when stack receives damage (after battleAttack())
+	virtual void battleEnd(const BattleResult *br){};
 	virtual void battleResultsApplied(){}; //called when all effects of last battle are applied
 	virtual void battleNewRoundFirst(int round){}; //called at the beginning of each turn before changes are applied;
 	virtual void battleNewRound(int round){}; //called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
 	virtual void battleStackMoved(int ID, int dest, int distance, bool end){};
-	virtual void battleSpellCast(BattleSpellCast *sc){};
-	virtual void battleStacksEffectsSet(SetStackEffect & sse){};//called when a specific effect is set to stacks
-	virtual void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side){}; //called by engine when battle starts; side=0 - left, side=1 - right
-	virtual void battlefieldPrepared(int battlefieldType, std::vector<CObstacle*> obstacles){}; //called when battlefield is prepared, prior the battle beginning
+	virtual void battleSpellCast(const BattleSpellCast *sc){};
+	virtual void battleStacksEffectsSet(const SetStackEffect & sse){};//called when a specific effect is set to stacks
+	virtual void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side){}; //called by engine when battle starts; side=0 - left, side=1 - right
+	//virtual void battlefieldPrepared(int battlefieldType, std::vector<CObstacle*> obstacles){}; //called when battlefield is prepared, prior the battle beginning
 	virtual void battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks, bool lifeDrain, si32 lifeDrainFrom){}; //called when stacks are healed / resurrected first element of pair - stack id, second - healed hp
 	virtual void battleNewStackAppeared(int stackID){}; //not called at the beginning of a battle or by resurrection; called eg. when elemental is summoned
 	virtual void battleObstaclesRemoved(const std::set<si32> & removedObstacles){}; //called when a certain set  of obstacles is removed from batlefield; IDs of them are given

+ 11 - 11
client/CBattleInterface.cpp

@@ -2671,7 +2671,7 @@ void CBattleInterface::displayBattleFinished()
 	GH.pushInt(resWindow);
 }
 
-void CBattleInterface::spellCast(BattleSpellCast * sc)
+void CBattleInterface::spellCast( const BattleSpellCast * sc )
 {
 	const CSpell &spell = CGI->spellh->spells[sc->id];
 
@@ -2820,7 +2820,7 @@ void CBattleInterface::battleStacksEffectsSet(const SetStackEffect & sse)
 void CBattleInterface::castThisSpell(int spellID)
 {
 	BattleAction * ba = new BattleAction;
-	ba->actionType = 1;
+	ba->actionType = BattleAction::HERO_SPELL;
 	ba->additionalInfo = spellID; //spell number
 	ba->destinationTile = -1;
 	ba->stackNumber = (attackingHeroInstance->tempOwner == curInt->playerID) ? -1 : -2;
@@ -3010,7 +3010,7 @@ void CBattleInterface::showAliveStack(const CStack *stack, SDL_Surface * to)
 	if(stack->count > 0 //don't print if stack is not alive
 		&& (!curInt->curAction
 			|| (curInt->curAction->stackNumber != ID //don't print if stack is currently taking an action
-				&& (curInt->curAction->actionType != 6  ||  stack->position != curInt->curAction->additionalInfo) //nor if it's an object of attack
+				&& (curInt->curAction->actionType != BattleAction::WALK_AND_ATTACK  ||  stack->position != curInt->curAction->additionalInfo) //nor if it's an object of attack
 				&& (curInt->curAction->destinationTile != stack->position) //nor if it's on destination tile for current action
 				)
 			)
@@ -3230,18 +3230,18 @@ void CBattleInterface::endAction(const BattleAction* action)
 // 	{
 // 		activate();
 // 	}
-	if(action->actionType == 1)
+	if(action->actionType == BattleAction::HERO_SPELL)
 	{
 		if(action->side)
 			defendingHero->setPhase(0);
 		else
 			attackingHero->setPhase(0);
 	}
-	if(action->actionType == 2 && creAnims[action->stackNumber]->getType() != 2) //walk or walk & attack
+	if(action->actionType == BattleAction::WALK && creAnims[action->stackNumber]->getType() != 2) //walk or walk & attack
 	{
 		pendingAnims.push_back(std::make_pair(new CBattleMoveEnd(this, action->stackNumber, action->destinationTile), false));
 	}
-	if(action->actionType == 9) //catapult
+	if(action->actionType == BattleAction::CATAPULT) //catapult
 	{
 	}
 	queue->update();
@@ -3283,11 +3283,11 @@ void CBattleInterface::startAction(const BattleAction* action)
 	}
 	else
 	{
-		assert(action->actionType == 1); //only cast spell is valid action without acting stack number
+		assert(action->actionType == BattleAction::HERO_SPELL); //only cast spell is valid action without acting stack number
 	}
 
-	if(action->actionType == 2 
-		|| (action->actionType == 6 && action->destinationTile != stack->position))
+	if(action->actionType == BattleAction::WALK 
+		|| (action->actionType == BattleAction::WALK_AND_ATTACK && action->destinationTile != stack->position))
 	{
 		moveStarted = true;
 		if(creAnims[action->stackNumber]->framesInGroup(20))
@@ -3301,7 +3301,7 @@ void CBattleInterface::startAction(const BattleAction* action)
 
 	char txt[400];
 
-	if(action->actionType == 1) //when hero casts spell
+	if(action->actionType == BattleAction::HERO_SPELL) //when hero casts spell
 	{
 		if(action->side)
 			defendingHero->setPhase(4);
@@ -3342,7 +3342,7 @@ void CBattleInterface::startAction(const BattleAction* action)
 	}
 
 	//displaying heal animation
-	if (action->actionType == 12)
+	if (action->actionType == BattleAction::STACK_HEAL)
 	{
 		displayEffect(50, action->destinationTile);
 	}

+ 1 - 1
client/CBattleInterface.h

@@ -506,7 +506,7 @@ public:
 	void battleFinished(const BattleResult& br); //called when battle is finished - battleresult window should be printed
 	const BattleResult * bresult; //result of a battle; if non-zero then display when all animations end
 	void displayBattleFinished(); //displays battle result
-	void spellCast(BattleSpellCast * sc); //called when a hero casts a spell
+	void spellCast(const BattleSpellCast * sc); //called when a hero casts a spell
 	void battleStacksEffectsSet(const SetStackEffect & sse); //called when a specific effect is set to stacks
 	void castThisSpell(int spellID); //called when player has chosen a spell from spellbook
 	void displayEffect(ui32 effect, int destTile); //displays effect of a spell on the battlefield; affected: true - attacker. false - defender

+ 5 - 1
client/CMT.cpp

@@ -75,7 +75,6 @@ Point screenLT = Point(0, 0); //position of top left corner of the screen
 Point screenLTmax = Point(0, 0); //,maximal values for screenLT coordinates
 static boost::thread *mainGUIThread;
 
-
 SystemOptions GDefaultOptions; 
 VCMIDirs GVCMIDirs;
 std::queue<SDL_Event*> events;
@@ -428,6 +427,11 @@ void processCommand(const std::string &message)
 	{
 		gOnlyAI = true;
 	}
+	else if (cn == "ai")
+	{
+		VLC->IS_AI_ENABLED = !VLC->IS_AI_ENABLED;
+		tlog4 << "Current AI status: " << (VLC->IS_AI_ENABLED ? "enabled" : "disabled") << std::endl;
+	}
 	else if(cn == "mp" && adventureInt)
 	{
 		if(const CGHeroInstance *h = dynamic_cast<const CGHeroInstance *>(adventureInt->selection))

+ 8 - 11
client/CPlayerInterface.cpp

@@ -538,7 +538,7 @@ void CPlayerInterface::buildChanged(const CGTownInstance *town, int buildingID,
 	}
 }
 
-void CPlayerInterface::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side)
+void CPlayerInterface::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side)
 {
 	if(LOCPLINT != this)
 	{ //another local interface should do this
@@ -553,9 +553,6 @@ void CPlayerInterface::battleStart(const CCreatureSet *army1, const CCreatureSet
 	GH.pushInt(battleInt);
 }
 
-void CPlayerInterface::battlefieldPrepared(int battlefieldType, std::vector<CObstacle*> obstacles) //called when battlefield is prepared, prior the battle beginning
-{
-}
 
 void CPlayerInterface::battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks, bool lifeDrain, si32 lifeDrainFrom)
 {
@@ -719,7 +716,7 @@ BattleAction CPlayerInterface::activeStack(int stackID) //called when it's turn
 	return ret;
 }
 
-void CPlayerInterface::battleEnd(BattleResult *br)
+void CPlayerInterface::battleEnd(const BattleResult *br)
 {
 	if(LOCPLINT != this)
 	{ //another local interface should do this
@@ -740,7 +737,7 @@ void CPlayerInterface::battleStackMoved(int ID, int dest, int distance, bool end
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
 	battleInt->stackMoved(ID, dest, end, distance);
 }
-void CPlayerInterface::battleSpellCast(BattleSpellCast *sc)
+void CPlayerInterface::battleSpellCast( const BattleSpellCast *sc )
 {
 	if(LOCPLINT != this)
 	{ //another local interface should do this
@@ -750,7 +747,7 @@ void CPlayerInterface::battleSpellCast(BattleSpellCast *sc)
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
 	battleInt->spellCast(sc);
 }
-void CPlayerInterface::battleStacksEffectsSet(SetStackEffect & sse)
+void CPlayerInterface::battleStacksEffectsSet( const SetStackEffect & sse )
 {
 	if(LOCPLINT != this)
 	{ //another local interface should do this
@@ -760,7 +757,7 @@ void CPlayerInterface::battleStacksEffectsSet(SetStackEffect & sse)
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
 	battleInt->battleStacksEffectsSet(sse);
 }
-void CPlayerInterface::battleStacksAttacked(std::vector<BattleStackAttacked> & bsa)
+void CPlayerInterface::battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa)
 {
 	if(LOCPLINT != this)
 	{ //another local interface should do this
@@ -773,7 +770,7 @@ void CPlayerInterface::battleStacksAttacked(std::vector<BattleStackAttacked> & b
 
 
 	std::vector<SStackAttackedInfo> arg;
-	for(std::vector<BattleStackAttacked>::iterator i = bsa.begin(); i != bsa.end(); i++)
+	for(std::vector<BattleStackAttacked>::const_iterator i = bsa.begin(); i != bsa.end(); i++)
 	{
 		if(i->isEffect() && i->effect != 12) //and not armageddon
 		{
@@ -793,7 +790,7 @@ void CPlayerInterface::battleStacksAttacked(std::vector<BattleStackAttacked> & b
 
 	battleInt->stacksAreAttacked(arg);
 }
-void CPlayerInterface::battleAttack(BattleAttack *ba)
+void CPlayerInterface::battleAttack(const BattleAttack *ba)
 {
 	if(LOCPLINT != this)
 	{ //another local interface should do this
@@ -816,7 +813,7 @@ void CPlayerInterface::battleAttack(BattleAttack *ba)
 
 	if(ba->shot())
 	{
-		for(std::vector<BattleStackAttacked>::iterator i = ba->bsa.begin(); i != ba->bsa.end(); i++)
+		for(std::vector<BattleStackAttacked>::const_iterator i = ba->bsa.begin(); i != ba->bsa.end(); i++)
 			battleInt->stackIsShooting(ba->stackAttacking,cb->battleGetPos(i->stackAttacked), i->stackAttacked);
 	}
 	else

+ 6 - 7
client/CPlayerInterface.h

@@ -203,17 +203,16 @@ public:
 	void actionFinished(const BattleAction* action);//occurs AFTER action taken by active stack or by the hero
 	void actionStarted(const BattleAction* action);//occurs BEFORE action taken by active stack or by the hero
 	BattleAction activeStack(int stackID); //called when it's turn of that stack
-	void battleAttack(BattleAttack *ba); //stack performs attack
-	void battleEnd(BattleResult *br); //end of battle
+	void battleAttack(const BattleAttack *ba); //stack performs attack
+	void battleEnd(const BattleResult *br); //end of battle
 	//void battleResultQuited();
 	void battleNewRoundFirst(int round); //called at the beginning of each turn before changes are applied; used for HP regen handling
 	void battleNewRound(int round); //called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
 	void battleStackMoved(int ID, int dest, int distance, bool end);
-	void battleSpellCast(BattleSpellCast *sc);
-	void battleStacksEffectsSet(SetStackEffect & sse); //called when a specific effect is set to stacks
-	void battleStacksAttacked(std::vector<BattleStackAttacked> & bsa);
-	void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side); //called by engine when battle starts; side=0 - left, side=1 - right
-	void battlefieldPrepared(int battlefieldType, std::vector<CObstacle*> obstacles); //called when battlefield is prepared, prior the battle beginning
+	void battleSpellCast(const BattleSpellCast *sc);
+	void battleStacksEffectsSet(const SetStackEffect & sse); //called when a specific effect is set to stacks
+	void battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa);
+	void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side); //called by engine when battle starts; side=0 - left, side=1 - right
 	void battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks, bool lifeDrain, si32 lifeDrainFrom); //called when stacks are healed / resurrected
 	void battleNewStackAppeared(int stackID); //not called at the beginning of a battle or by resurrection; called eg. when elemental is summoned
 	void battleObstaclesRemoved(const std::set<si32> & removedObstacles); //called when a certain set  of obstacles is removed from batlefield; IDs of them are given

+ 1 - 1
client/GUIClasses.cpp

@@ -1676,7 +1676,7 @@ void CRecruitmentWindow::Buy()
 	int crid = creatures[which].ID,
 		dstslot = dst-> getSlotFor(crid);
 
-	if(dstslot < 0) //no available slot
+	if(dstslot < 0 && !vstd::contains(CGI->arth->bigArtifacts,CGI->arth->convertMachineID(crid, true))) //no available slot
 	{
 		std::string txt;
 		if(dst->ID == HEROI_TYPE)

+ 1 - 0
global.h

@@ -358,6 +358,7 @@ extern DLL_EXPORT CLogger tlog2; //magenta - major warnings
 extern DLL_EXPORT CLogger tlog3; //yellow - minor warnings
 extern DLL_EXPORT CLogger tlog4; //white - detailed log info
 extern DLL_EXPORT CLogger tlog5; //gray - minor log info
+extern DLL_EXPORT CLogger tlog6; //teal - AI info
 
 //XXX pls dont - 'debug macros' are usually more trouble than it's worth
 #define HANDLE_EXCEPTION  \

+ 4 - 0
lib/BattleAction.h

@@ -15,6 +15,10 @@ struct BattleAction
 {
 	ui8 side; //who made this action: false - left, true - right player
 	ui32 stackNumber;//stack ID, -1 left hero, -2 right hero,
+	enum ActionType
+	{
+		NO_ACTION = 0, HERO_SPELL, WALK, DEFEND, RETREAT, SURRENDER, WALK_AND_ATTACK, SHOOT, WAIT, CATAPULT, MONSTER_SPELL, BAD_MORALE, STACK_HEAL
+	};
 	ui8 actionType; //    0 = No action;   1 = Hero cast a spell   2 = Walk   3 = Defend   4 = Retreat from the battle
 		//5 = Surrender   6 = Walk and Attack   7 = Shoot    8 = Wait   9 = Catapult
 		//10 = Monster casts a spell (i.e. Faerie Dragons)	11 - Bad morale freeze	12 - stacks heals another stack

+ 1 - 1
lib/CCreatureSet.cpp

@@ -365,7 +365,7 @@ bool CCreatureSet::hasStackAtSlot(TSlot slot) const
 CCreatureSet & CCreatureSet::operator=(const CCreatureSet&cs)
 {
 	assert(0);
-	return cs;
+	return *this;
 }
 
 CStackInstance::CStackInstance()

+ 4 - 4
lib/NetPacks.h

@@ -1177,19 +1177,19 @@ struct BattleAttack : public CPackForClient//3006
 	ui32 stackAttacking;
 	ui8 flags;
 
-	bool shot()//distance attack - decrease number of shots
+	bool shot() const//distance attack - decrease number of shots
 	{
 		return flags & 1;
 	}
-	bool counter()//is it counterattack?
+	bool counter() const//is it counterattack?
 	{
 		return flags & 2;
 	}
-	bool lucky()
+	bool lucky() const
 	{
 		return flags & 4;
 	}
-	bool unlucky()
+	bool unlucky() const
 	{
 		//TODO: support?
 		return flags & 8;

+ 6 - 4
lib/NetPacksLib.cpp

@@ -972,18 +972,20 @@ DLL_EXPORT void StartAction::applyGs( CGameState *gs )
 {
 	CStack *st = gs->curB->getStack(ba.stackNumber);
 
-	if(ba.actionType != 1) //don't check for stack if it's custom action by hero
+	if(ba.actionType != BattleAction::HERO_SPELL) //don't check for stack if it's custom action by hero
 		assert(st);
 
 	switch(ba.actionType)
 	{
-	case 3:
+	case BattleAction::DEFEND:
 		st->state.insert(DEFENDING);
 		break;
-	case 8:
+	case BattleAction::WAIT:
 		st->state.insert(WAITING);
 		return;
-	case 0: case 2: case 6: case 7: case 9: case 10: case 11: case 12:
+	case BattleAction::NO_ACTION: case BattleAction::WALK: case BattleAction::WALK_AND_ATTACK:
+	case BattleAction::SHOOT: case BattleAction::CATAPULT: case BattleAction::MONSTER_SPELL:
+	case BattleAction::BAD_MORALE: case BattleAction::STACK_HEAL:
 		st->state.insert(MOVED);
 		break;
 	}

+ 3 - 0
lib/VCMI_Lib.cpp

@@ -34,6 +34,7 @@ DLL_EXPORT CLogger tlog2(2);
 DLL_EXPORT CLogger tlog3(3);
 DLL_EXPORT CLogger tlog4(4);
 DLL_EXPORT CLogger tlog5(5);
+DLL_EXPORT CLogger tlog6(-2);
 
 DLL_EXPORT CConsoleHandler *console = NULL;
 DLL_EXPORT std::ostream *logfile = NULL
@@ -205,6 +206,8 @@ void LibClasses::init()
 	spellh = new CSpellHandler;
 	spellh->loadSpells();
 	tlog0<<"\tSpell handler: "<<pomtime.getDif()<<std::endl;
+
+	IS_AI_ENABLED = true;
 }
 
 void LibClasses::clear()

+ 2 - 1
lib/VCMI_Lib.h

@@ -26,6 +26,7 @@ class CGeneralTextHandler;
 class DLL_EXPORT LibClasses
 {
 public:
+	bool IS_AI_ENABLED; //VLC is teh only object visible from both CMT and GeniusAI
 	CArtHandler * arth;
 	CHeroHandler * heroh;
 	CCreatureHandler * creh;
@@ -45,7 +46,7 @@ public:
 	void callWhenDeserializing(); //should be called only by serialize !!!
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & heroh & arth & creh & townh & objh & dobjinfo & buildh & spellh;
+		h & heroh & arth & creh & townh & objh & dobjinfo & buildh & spellh & IS_AI_ENABLED;;
 		if(!h.saving)
 		{
 			callWhenDeserializing();

+ 24 - 15
server/CGameHandler.cpp

@@ -346,16 +346,15 @@ void CGameHandler::startBattle(const CArmedInstance *army1, const CArmedInstance
 		setupBattle(curB, tile, army1, army2, hero1, hero2, creatureBank, town); //initializes stacks, places creatures on battlefield, blocks and informs player interfaces
 	}
 
-	NEW_ROUND;
 	//TODO: pre-tactic stuff, call scripts etc.
 
 	//tactic round
 	{
-		NEW_ROUND;
 		if( (hero1 && hero1->getSecSkillLevel(19)>0) || 
 			( hero2 && hero2->getSecSkillLevel(19)>0)  )//someone has tactics
 		{
 			//TODO: tactic round (round -1)
+			NEW_ROUND;
 		}
 	}
 
@@ -401,7 +400,7 @@ void CGameHandler::startBattle(const CArmedInstance *army1, const CArmedInstance
 				{
 					//unit loses its turn - empty freeze action
 					BattleAction ba;
-					ba.actionType = 11;
+					ba.actionType = BattleAction::BAD_MORALE;
 					ba.additionalInfo = 1;
 					ba.side = !next->attackerOwned;
 					ba.stackNumber = next->ID;
@@ -418,7 +417,7 @@ void CGameHandler::startBattle(const CArmedInstance *army1, const CArmedInstance
 				if(attackInfo.first != NULL)
 				{
 					BattleAction attack;
-					attack.actionType = 6;
+					attack.actionType = BattleAction::WALK_AND_ATTACK;
 					attack.side = !next->attackerOwned;
 					attack.stackNumber = next->ID;
 
@@ -429,6 +428,10 @@ void CGameHandler::startBattle(const CArmedInstance *army1, const CArmedInstance
 
 					checkForBattleEnd(stacks);
 				}
+				else
+				{
+					makeStackDoNothing(next);
+				}
 				continue;
 			}
 
@@ -438,7 +441,7 @@ void CGameHandler::startBattle(const CArmedInstance *army1, const CArmedInstance
 				|| (next->getCreature()->idNumber == 146 && (!curOwner || curOwner->getSecSkillLevel(20) == 0))) //ballista, hero has no artillery
 			{
 				BattleAction attack;
-				attack.actionType = 7;
+				attack.actionType = BattleAction::SHOOT;
 				attack.side = !next->attackerOwned;
 				attack.stackNumber = next->ID;
 
@@ -463,7 +466,7 @@ void CGameHandler::startBattle(const CArmedInstance *army1, const CArmedInstance
 				static const int wallHexes[] = {50, 183, 182, 130, 62, 29, 12, 95};
 
 				attack.destinationTile = wallHexes[ rand()%ARRAY_COUNT(wallHexes) ];
-				attack.actionType = 9;
+				attack.actionType = BattleAction::CATAPULT;
 				attack.additionalInfo = 0;
 				attack.side = !next->attackerOwned;
 				attack.stackNumber = next->ID;
@@ -489,21 +492,15 @@ void CGameHandler::startBattle(const CArmedInstance *army1, const CArmedInstance
 				if(possibleStacks.size() == 0)
 				{
 					//nothing to heal
-					BattleAction doNothing;
-					doNothing.actionType = 0;
-					doNothing.additionalInfo = 0;
-					doNothing.destinationTile = -1;
-					doNothing.side = !next->attackerOwned;
-					doNothing.stackNumber = next->ID;
-					sendAndApply(&StartAction(doNothing));
-					sendAndApply(&EndAction());
+					makeStackDoNothing(next);
+
 					continue;
 				}
 				else
 				{
 					//heal random creature
 					const CStack * toBeHealed = possibleStacks[ rand()%possibleStacks.size() ];
-					heal.actionType = 12;
+					heal.actionType = BattleAction::STACK_HEAL;
 					heal.additionalInfo = 0;
 					heal.destinationTile = toBeHealed->position;
 					heal.side = !next->attackerOwned;
@@ -5225,6 +5222,18 @@ bool CGameHandler::sacrificeArtifact(const IMarket * m, const CGHeroInstance * h
 	return true;
 }
 
+void CGameHandler::makeStackDoNothing(const CStack * next)
+{
+	BattleAction doNothing;
+	doNothing.actionType = 0;
+	doNothing.additionalInfo = 0;
+	doNothing.destinationTile = -1;
+	doNothing.side = !next->attackerOwned;
+	doNothing.stackNumber = next->ID;
+	sendAndApply(&StartAction(doNothing));
+	sendAndApply(&EndAction());
+}
+
 bool CGameHandler::insertNewStack(const StackLocation &sl, const CCreature *c, TQuantity count)
 {
 	if(sl.army->hasStackAtSlot(sl.slot))

+ 4 - 0
server/CGameHandler.h

@@ -76,6 +76,8 @@ public:
 
 class CGameHandler : public IGameCallback
 {
+private:
+	void makeStackDoNothing(const CStack * next);
 public:
 	CVCMIServer *s;
 	std::map<int,CConnection*> connections; //player color -> connection to client with interface of that player
@@ -237,3 +239,5 @@ public:
 };
 
 #endif // __CGAMEHANDLER_H__
+
+void makeStackDoNothing();

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.