mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	New bonus system. Unified HeroBonus and StackFeature. Still early version, will need improvements and development.
If you encounter any new crashes / bugs / unacceptable slowdowns, please PM me.
This commit is contained in:
		| @@ -41,7 +41,7 @@ ui8 side; //who made this action: false - left, true - right player | ||||
| /** | ||||
|  *	Implementation of CBattleLogic class. | ||||
|  */ | ||||
| CBattleLogic::CBattleLogic(ICallback *cb,  CCreatureSet *army1, CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side) : | ||||
| CBattleLogic::CBattleLogic(ICallback *cb,  const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side) : | ||||
| 	m_iCurrentTurn(-2), | ||||
| 	m_bIsAttacker(!side), | ||||
| 	m_cb(cb), | ||||
| @@ -121,23 +121,24 @@ void CBattleLogic::MakeStatistics(int currentCreatureId) | ||||
| 	for (map_stacks::const_iterator it = allStacks.begin(); it != allStacks.end(); ++it) | ||||
| 	{ | ||||
| 		const CStack *st = &it->second; | ||||
| 		const int stackHP = st->valOfBonuses(Bonus::STACK_HEALTH); | ||||
|  | ||||
| 		if ((it->second.attackerOwned != 0) != m_bIsAttacker) | ||||
| 		{ | ||||
| 			int id = it->first; | ||||
| 			if (st->amount < 1) | ||||
| 			if (st->count < 1) | ||||
| 			{ | ||||
| 				continue; | ||||
| 			} | ||||
| 			// make stats | ||||
| 			int hitPoints = st->amount * st->creature->hitPoints - (st->creature->hitPoints - st->firstHPleft); | ||||
| 			int hitPoints = st->count * stackHP - (stackHP - st->firstHPleft); | ||||
|  | ||||
| 			m_statMaxDamage.push_back(std::pair<int, int>(id, st->creature->damageMax * st->amount)); | ||||
| 			m_statMinDamage.push_back(std::pair<int, int>(id, st->creature->damageMin * st->amount)); | ||||
| 			m_statMaxDamage.push_back(std::pair<int, int>(id, st->type->damageMax * st->count)); | ||||
| 			m_statMinDamage.push_back(std::pair<int, int>(id, st->type->damageMin * st->count)); | ||||
| 			m_statHitPoints.push_back(std::pair<int, int>(id, hitPoints)); | ||||
| 			m_statMaxSpeed.push_back(std::pair<int, int>(id, st->creature->speed)); | ||||
| 			m_statMaxSpeed.push_back(std::pair<int, int>(id, stackHP)); | ||||
|  | ||||
| 			totalEnemyDamage += (st->creature->damageMax + st->creature->damageMin) * st->amount / 2; | ||||
| 			totalEnemyDamage += (st->type->damageMax + st->type->damageMin) * st->count / 2; | ||||
| 			totalEnemyHitPoints += hitPoints; | ||||
|  | ||||
| 			// calculate casualties | ||||
| @@ -174,32 +175,32 @@ void CBattleLogic::MakeStatistics(int currentCreatureId) | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			cs.damage_max = (int)(currentStack->creature->damageMax * currentStack->amount * damageFactor); | ||||
| 			cs.damage_max = (int)(currentStack->type->damageMax * currentStack->count * damageFactor); | ||||
| 			if (cs.damage_max > hitPoints) | ||||
| 			{ | ||||
| 				cs.damage_max = hitPoints; | ||||
| 			} | ||||
|  | ||||
| 			cs.damage_min = (int)(currentStack->creature->damageMin * currentStack->amount * damageFactor); | ||||
| 			cs.damage_min = (int)(currentStack->type->damageMin * currentStack->count * damageFactor); | ||||
| 			if (cs.damage_min > hitPoints) | ||||
| 			{ | ||||
| 				cs.damage_min = hitPoints; | ||||
| 			} | ||||
|  | ||||
| 			cs.amount_max = cs.damage_max / st->creature->hitPoints; | ||||
| 			cs.amount_min = cs.damage_min / st->creature->hitPoints; | ||||
| 			cs.amount_max = cs.damage_max / stackHP; | ||||
| 			cs.amount_min = cs.damage_min / stackHP; | ||||
|  | ||||
| 			cs.leftHitPoints_for_max = (hitPoints - cs.damage_max) % st->creature->hitPoints; | ||||
| 			cs.leftHitPoint_for_min = (hitPoints - cs.damage_min) % st->creature->hitPoints; | ||||
| 			cs.leftHitPoints_for_max = (hitPoints - cs.damage_max) % stackHP; | ||||
| 			cs.leftHitPoint_for_min = (hitPoints - cs.damage_min) % stackHP; | ||||
|  | ||||
| 			m_statCasualties.push_back(std::pair<int, SCreatureCasualties>(id, cs)); | ||||
|  | ||||
| 			if (st->creature->isShooting() && st->shots > 0) | ||||
| 			if (st->type->isShooting() && st->shots > 0) | ||||
| 			{ | ||||
| 				m_statDistanceFromShooters.push_back(std::pair<int, int>(id, m_battleHelper.GetShortestDistance(currentStack->position, st->position))); | ||||
| 			} | ||||
|  | ||||
| 			if (currentStack->hasFeatureOfType(StackFeature::FLYING) || (currentStack->creature->isShooting() && currentStack->shots > 0)) | ||||
| 			if (currentStack->hasBonusOfType(Bonus::FLYING) || (currentStack->type->isShooting() && currentStack->shots > 0)) | ||||
| 			{ | ||||
| 				m_statDistance.push_back(std::pair<int, int>(id, m_battleHelper.GetShortestDistance(currentStack->position, st->position))); | ||||
| 			} | ||||
| @@ -210,13 +211,13 @@ void CBattleLogic::MakeStatistics(int currentCreatureId) | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			if (st->amount < 1) | ||||
| 			if (st->count < 1) | ||||
| 			{ | ||||
| 				continue; | ||||
| 			} | ||||
| 			int hitPoints = st->amount * st->creature->hitPoints - (st->creature->hitPoints - st->firstHPleft); | ||||
| 			int hitPoints = st->count * stackHP - (stackHP - st->firstHPleft); | ||||
|  | ||||
| 			totalDamage += (st->creature->damageMax + st->creature->damageMin) * st->amount / 2; | ||||
| 			totalDamage += (st->type->damageMax + st->type->damageMin) * st->count / 2; | ||||
| 			totalHitPoints += hitPoints; | ||||
| 		} | ||||
| 	} | ||||
| @@ -258,7 +259,7 @@ void CBattleLogic::MakeStatistics(int currentCreatureId) | ||||
| BattleAction CBattleLogic::MakeDecision(int stackID) | ||||
| { | ||||
| 	const CStack *currentStack = m_cb->battleGetStackByID(stackID); | ||||
| 	if(currentStack->position < 0 || currentStack->creature->idNumber == 147) //turret or first aid kit | ||||
| 	if(currentStack->position < 0 || currentStack->type->idNumber == 147) //turret or first aid kit | ||||
| 	{ | ||||
| 		return MakeDefend(stackID); | ||||
| 	} | ||||
| @@ -318,8 +319,8 @@ std::vector<int> CBattleLogic::GetAvailableHexesForAttacker(const CStack *defend | ||||
| { | ||||
| 	int x = m_battleHelper.DecodeXPosition(defender->position); | ||||
| 	int y = m_battleHelper.DecodeYPosition(defender->position); | ||||
| 	bool defenderIsDW = defender->hasFeatureOfType(StackFeature::DOUBLE_WIDE); | ||||
| 	bool attackerIsDW = attacker->hasFeatureOfType(StackFeature::DOUBLE_WIDE); | ||||
| 	bool defenderIsDW = defender->doubleWide(); | ||||
| 	bool attackerIsDW = attacker->doubleWide(); | ||||
| 	// TOTO: should be std::vector<int> but for debug purpose std::pair is used | ||||
| 	typedef std::pair<int, int> hexPoint; | ||||
| 	std::list<hexPoint> candidates; | ||||
| @@ -424,7 +425,7 @@ std::vector<int> CBattleLogic::GetAvailableHexesForAttacker(const CStack *defend | ||||
| 		int new_pos = m_battleHelper.GetBattleFieldPosition(it->first, it->second); | ||||
| 		const CStack *st = m_cb->battleGetStackByPos(new_pos); | ||||
|  | ||||
| 		if (st == NULL || st->amount < 1) | ||||
| 		if (st == NULL || st->count < 1) | ||||
| 		{ | ||||
| 			if (attackerIsDW) | ||||
| 			{ | ||||
| @@ -449,7 +450,7 @@ std::vector<int> CBattleLogic::GetAvailableHexesForAttacker(const CStack *defend | ||||
| 				} | ||||
| 				assert(tail_pos >= 0 && "Error during calculation position of double wide creature"); | ||||
| 				//CStack *tailStack = m_cb->battleGetStackByPos(tail_pos); | ||||
| 				if (st != NULL && st->amount >= 1) | ||||
| 				if (st != NULL && st->count >= 1) | ||||
| 				{ | ||||
| 					continue; | ||||
| 				} | ||||
| @@ -572,7 +573,7 @@ BattleAction CBattleLogic::MakeAttack(int attackerID, int destinationID) | ||||
|  | ||||
| 		// if double wide calculate tail | ||||
| 		int tail_pos = -1; | ||||
| 		if (attackerStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE)) | ||||
| 		if (attackerStack->doubleWide()) | ||||
| 		{ | ||||
| 			int x_pos = m_battleHelper.DecodeXPosition(attackerStack->position); | ||||
| 			int y_pos = m_battleHelper.DecodeYPosition(attackerStack->position); | ||||
| @@ -657,7 +658,7 @@ list<int> CBattleLogic::PerformBerserkAttack(int stackID, int &additionalInfo) | ||||
| 			} | ||||
| 			for (creature_stat::const_iterator it2 = m_statDistance.begin(); it2 != m_statDistance.end(); ++it2) | ||||
| 			{ | ||||
| 				if (it2->first == it->first && it2->second - 1 <= c.speed) | ||||
| 				if (it2->first == it->first && it2->second - 1 <= c.valOfBonuses(Bonus::STACKS_SPEED)) | ||||
| 				{ | ||||
| 					creatures.push_front(it->first); | ||||
| 				} | ||||
| @@ -761,9 +762,9 @@ void CBattleLogic::PrintBattleAction(const BattleAction &action) // for debug pu | ||||
| 		message += ", " + boost::lexical_cast<std::string>(m_battleHelper.DecodeYPosition(action.additionalInfo)); | ||||
| 		message += ", creature - "; | ||||
| 		const CStack *c = m_cb->battleGetStackByPos(action.additionalInfo); | ||||
| 		if (c && c->creature) | ||||
| 		if (c && c->type) | ||||
| 		{ | ||||
| 			message += c->creature->nameRef; | ||||
| 			message += c->type->nameRef; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
|   | ||||
| @@ -63,7 +63,7 @@ private: | ||||
| 		int leftHitPoint_for_min; // scenario | ||||
| 	}; | ||||
| public: | ||||
| 	CBattleLogic(ICallback *cb, CCreatureSet *army1, CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side); | ||||
| 	CBattleLogic(ICallback *cb, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side); | ||||
| 	~CBattleLogic(); | ||||
|  | ||||
| 	void SetCurrentTurn(int turn); | ||||
| @@ -77,8 +77,8 @@ private: | ||||
| 	int m_iCurrentTurn; | ||||
| 	bool m_bIsAttacker; | ||||
| 	ICallback *m_cb; | ||||
| 	CCreatureSet *m_army1; | ||||
| 	CCreatureSet *m_army2; | ||||
| 	const CCreatureSet *m_army1; | ||||
| 	const CCreatureSet *m_army2; | ||||
| 	int3 m_tile; | ||||
| 	CGHeroInstance *m_hero1; | ||||
| 	CGHeroInstance *m_hero2; | ||||
|   | ||||
| @@ -61,7 +61,7 @@ CGeniusAI::HypotheticalGameState::TownModel::TownModel( | ||||
| { | ||||
| 	hasBuilt = static_cast<bool>(t->builded); | ||||
| 	creaturesToRecruit = t->creatures; | ||||
| 	creaturesInGarrison = t->army; | ||||
| 	creaturesInGarrison = t->getArmy(); | ||||
| } | ||||
|  | ||||
| CGeniusAI::HypotheticalGameState::HypotheticalGameState(CGeniusAI& ai) | ||||
| @@ -295,7 +295,7 @@ float CGeniusAI::TownObjective::getValue() const | ||||
| 	  case recruitCreatures: | ||||
|       // Buy upgraded if possible. | ||||
| 		  ID = whichTown->creaturesToRecruit[which].second.back(); | ||||
| 		  creature = &VLC->creh->creatures[ID]; | ||||
| 		  creature = VLC->creh->creatures[ID]; | ||||
| 		  howMany = whichTown->creaturesToRecruit[which].first; | ||||
|       creatures_max = 0; // Max creatures you can recruit of this type. | ||||
|        | ||||
| @@ -316,8 +316,8 @@ float CGeniusAI::TownObjective::getValue() const | ||||
|  | ||||
| 	  case upgradeCreatures: | ||||
| 		  UpgradeInfo ui = AI->m_cb->getUpgradeInfo(whichTown->t,which); | ||||
| 		  ID = whichTown->creaturesInGarrison.slots[which].type->idNumber; | ||||
| 		  howMany = whichTown->creaturesInGarrison.slots[which].count; | ||||
| 		  ID = whichTown->creaturesInGarrison.getCreature(which)->idNumber; | ||||
| 		  howMany = whichTown->creaturesInGarrison.getAmount(which); | ||||
|  | ||||
| 		  newID = ui.newID.back(); | ||||
| 		  int upgrade_serial = ui.newID.size() - 1; | ||||
| @@ -388,7 +388,7 @@ void CGeniusAI::TownObjective::print() const | ||||
| 	  case recruitCreatures: | ||||
|       // Buy upgraded if possible. | ||||
| 		  ID = whichTown->creaturesToRecruit[which].second.back(); | ||||
| 		  creature = &VLC->creh->creatures[ID]; | ||||
| 		  creature = VLC->creh->creatures[ID]; | ||||
| 		  howMany = whichTown->creaturesToRecruit[which].first; | ||||
|       creatures_max = 0; | ||||
|  | ||||
| @@ -424,8 +424,8 @@ void CGeniusAI::TownObjective::print() const | ||||
|  | ||||
| 		  case upgradeCreatures: | ||||
| 			  UpgradeInfo ui = AI->m_cb->getUpgradeInfo(whichTown->t,which); | ||||
| 			  ID = whichTown->creaturesInGarrison.slots[which].type->idNumber; | ||||
| 			  cout << "upgrade " << VLC->creh->creatures[ID].namePl; | ||||
| 			  ID = whichTown->creaturesInGarrison.getCreature(which)->idNumber; | ||||
| 			  cout << "upgrade " << VLC->creh->creatures[ID]->namePl; | ||||
| 			  //ui.cost	 | ||||
| 		  break; | ||||
| 	} // switch(type) | ||||
| @@ -734,10 +734,10 @@ void CGeniusAI::HeroObjective::fulfill(CGeniusAI& cg, | ||||
|   if (town && object->getOwner() == cg.m_cb->getMyColor()) { | ||||
| 	  //upgrade hero's units | ||||
| 	  cout << "visiting town" << endl; | ||||
| 	  CCreatureSet hcreatures = h->h->army; | ||||
| 	  CCreatureSet hcreatures = h->h->getArmy(); | ||||
| 	  for (TSlots::const_iterator | ||||
|          i = hcreatures.slots.begin(); | ||||
|          i != hcreatures.slots.end(); | ||||
|          i = hcreatures.Slots().begin(); | ||||
|          i != hcreatures.Slots().end(); | ||||
|          i++) { // For each hero slot. | ||||
| 		  UpgradeInfo ui = cg.m_cb->getUpgradeInfo(h->h,i->first); | ||||
|  | ||||
| @@ -763,13 +763,13 @@ void CGeniusAI::HeroObjective::fulfill(CGeniusAI& cg, | ||||
| 	  } | ||||
|  | ||||
| 	  // Give town's units to hero. | ||||
| 	  CCreatureSet tcreatures = town->army; | ||||
| 	  CCreatureSet tcreatures = town->getArmy(); | ||||
| 	  int weakestCreatureStack; | ||||
| 	  int weakestCreatureAIValue = 99999; // TODO: Wtf?? | ||||
|  | ||||
| 	  for (TSlots::const_iterator | ||||
|          i = tcreatures.slots.begin(); | ||||
|          i != tcreatures.slots.end(); | ||||
|          i = tcreatures.Slots().begin(); | ||||
|          i != tcreatures.Slots().end(); | ||||
|          i++) { | ||||
| 		  if (i->second.type->AIValue <  | ||||
|           weakestCreatureAIValue) { | ||||
| @@ -778,10 +778,10 @@ void CGeniusAI::HeroObjective::fulfill(CGeniusAI& cg, | ||||
| 		  } | ||||
|     } | ||||
| 	  for (TSlots::const_iterator | ||||
|         i = tcreatures.slots.begin(); | ||||
|         i != tcreatures.slots.end(); | ||||
|         i = tcreatures.Slots().begin(); | ||||
|         i != tcreatures.Slots().end(); | ||||
|         i++) { // For each town slot. | ||||
| 		  hcreatures = h->h->army; | ||||
| 		  hcreatures = h->h->getArmy(); | ||||
| 		  int hSlot = hcreatures.getSlotFor(i->second.type->idNumber); | ||||
|  | ||||
| 		  if (hSlot == -1) | ||||
| @@ -789,7 +789,7 @@ void CGeniusAI::HeroObjective::fulfill(CGeniusAI& cg, | ||||
| 		  cout << "giving hero " | ||||
|            << i->second.type->namePl | ||||
|            << endl; | ||||
| 		  if (hcreatures.slots.find(hSlot) != hcreatures.slots.end()) { | ||||
| 		  if (!hcreatures.slotEmpty(hSlot)) { | ||||
|         // Can't take garrisonHero's last unit. | ||||
| 			  if ( (i->first == weakestCreatureStack) | ||||
|             && (town->garrisonHero != NULL) ) | ||||
| @@ -855,22 +855,22 @@ void CGeniusAI::addTownObjectives(HypotheticalGameState::TownModel& t, | ||||
| 		 | ||||
|     int ID = t.creaturesToRecruit[i].second.back(); | ||||
|     // m_cb->getCCreatureByID(ID); | ||||
| 		const CCreature *creature = &VLC->creh->creatures[ID]; | ||||
| 		const CCreature *creature = VLC->creh->creatures[ID]; | ||||
| 		bool canAfford = true; | ||||
| 		for (int ii = 0; ii < creature->cost.size(); ii++) | ||||
| 			if (creature->cost[ii] > hgs.resourceAmounts[ii]) | ||||
| 				canAfford = false; // Can we afford at least one creature? | ||||
| 		if (!canAfford) continue; | ||||
| 				 | ||||
| 		//cout << "town has " << t.t->creatures[i].first  << " "<< creature->namePl << " (AI Strength " << creature->AIValue << ")." << endl; | ||||
| 		//cout << "town has " << t.t->creatures[i]->first  << " "<< creature->namePl << " (AI Strength " << creature->AIValue << ")." << endl; | ||||
| 		TownObjective to(hgs, AIObjective::recruitCreatures, &t, i, this); | ||||
| 		currentTownObjectives.insert(to); | ||||
| 	} | ||||
|  | ||||
|   // Upgrade creatures. | ||||
| 	for (TSlots::iterator | ||||
|       i = t.creaturesInGarrison.slots.begin(); | ||||
|       i != t.creaturesInGarrison.slots.end(); | ||||
| 	for (TSlots::const_iterator | ||||
|       i = t.creaturesInGarrison.Slots().begin(); | ||||
|       i != t.creaturesInGarrison.Slots().end(); | ||||
|       i++) { | ||||
| 		UpgradeInfo ui = m_cb->getUpgradeInfo(t.t, i->first); | ||||
| 		if (ui.newID.size() != 0) { | ||||
| @@ -927,7 +927,7 @@ void CGeniusAI::TownObjective::fulfill(CGeniusAI& cg, | ||||
| 	case recruitCreatures: | ||||
|     // Buy upgraded if possible. | ||||
| 		ID = whichTown->creaturesToRecruit[which].second.back(); | ||||
| 		creature = &VLC->creh->creatures[ID]; | ||||
| 		creature = VLC->creh->creatures[ID]; | ||||
| 		howMany = whichTown->creaturesToRecruit[which].first; | ||||
| 		for (int i = 0; i < creature->cost.size(); i++) | ||||
|       // TODO: rewrite. | ||||
| @@ -942,11 +942,11 @@ void CGeniusAI::TownObjective::fulfill(CGeniusAI& cg, | ||||
|  | ||||
| 	case upgradeCreatures: | ||||
| 		UpgradeInfo ui = cg.m_cb->getUpgradeInfo(whichTown->t, which); | ||||
| 		ID = whichTown->creaturesInGarrison.slots[which].type->idNumber; | ||||
| 		ID = whichTown->creaturesInGarrison.getCreature(which)->idNumber; | ||||
| 		newID = ui.newID.back(); | ||||
|     // TODO: reduce resources in hgs | ||||
| 		cg.m_cb->upgradeCreature(whichTown->t, which, newID); | ||||
| 		cout << "upgrading " << VLC->creh->creatures[ID].namePl << endl; | ||||
| 		cout << "upgrading " << VLC->creh->creatures[ID]->namePl << endl; | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
| @@ -1077,7 +1077,7 @@ void CGeniusAI::startFirstTurn() | ||||
| 		if (hgs.townModels.front().creaturesToRecruit[i].first == 0) | ||||
|       continue; | ||||
| 		int ID = hgs.townModels.front().creaturesToRecruit[i].second.back(); | ||||
| 		const CCreature *creature = &VLC->creh->creatures[ID]; | ||||
| 		const CCreature *creature = VLC->creh->creatures[ID]; | ||||
| 		bool canAfford = true; | ||||
|     for (int ii = 0; ii < creature->cost.size(); ii++) { | ||||
| 			if (creature->cost[ii] > hgs.resourceAmounts[ii]) | ||||
| @@ -1246,7 +1246,7 @@ void CGeniusAI::battleStacksAttacked(std::set<BattleStackAttacked>& bsa) | ||||
| /** | ||||
|  * called by engine when battle starts; side=0 - left, side=1 - right | ||||
|  */ | ||||
| void CGeniusAI::battleStart(CCreatureSet *army1, CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side) | ||||
| void CGeniusAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side) | ||||
| { | ||||
|   // TODO: Battle logic what... | ||||
| 	assert(!m_battleLogic); | ||||
| @@ -1275,7 +1275,7 @@ void CGeniusAI::battleEnd(BattleResult* br) | ||||
| 	for (std::map<ui32,si32>::iterator i = br->casualties[0].begin();\ | ||||
|        i != br->casualties[0].end(); | ||||
|        i++) | ||||
| 		cout << i->second << " " << VLC->creh->creatures[i->first].namePl << endl; | ||||
| 		cout << i->second << " " << VLC->creh->creatures[i->first]->namePl << endl; | ||||
| 				 | ||||
| 	delete m_battleLogic; | ||||
| 	m_battleLogic = NULL; | ||||
|   | ||||
| @@ -208,7 +208,7 @@ public: | ||||
| 	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(SpellCast *sc); | ||||
| 	virtual void battleStart(CCreatureSet *army1, CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side); //called by engine when battle starts; side=0 - left, side=1 - right | ||||
| 	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 battleStackMoved(int ID, int dest, bool startMoving, bool endMoving); | ||||
|   | ||||
| @@ -68,7 +68,7 @@ void CCallback::recruitCreatures(const CGObjectInstance *obj, ui32 ID, ui32 amou | ||||
|  | ||||
| bool CCallback::dismissCreature(const CArmedInstance *obj, int stackPos) | ||||
| { | ||||
| 	if(((player>=0)  &&  obj->tempOwner != player) || (obj->army.slots.size()<2  && obj->needsLastStack())) | ||||
| 	if(((player>=0)  &&  obj->tempOwner != player) || (obj->stacksCount()<2  && obj->needsLastStack())) | ||||
| 		return false; | ||||
|  | ||||
| 	DisbandCreature pack(stackPos,obj->id); | ||||
| @@ -379,7 +379,7 @@ const CCreatureSet* CCallback::getGarrison(const CGObjectInstance *obj) const | ||||
| 	if(!armi) | ||||
| 		return NULL; | ||||
| 	else  | ||||
| 		return &armi->army; | ||||
| 		return armi; | ||||
| } | ||||
|  | ||||
| int CCallback::swapCreatures(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2) | ||||
| @@ -560,7 +560,7 @@ CCreature CCallback::battleGetCreature(int number) | ||||
| 	for(size_t h=0; h<gs->curB->stacks.size(); ++h) | ||||
| 	{ | ||||
| 		if(gs->curB->stacks[h]->ID == number) //creature found | ||||
| 			return *(gs->curB->stacks[h]->creature); | ||||
| 			return *(gs->curB->stacks[h]->type); | ||||
| 	} | ||||
| #ifndef __GNUC__ | ||||
| 	throw new std::exception("Cannot find the creature"); | ||||
| @@ -776,7 +776,7 @@ void CCallback::trade( int mode, int id1, int id2, int val1 ) | ||||
|  | ||||
| void CCallback::setFormation(const CGHeroInstance * hero, bool tight) | ||||
| { | ||||
| 	const_cast<CGHeroInstance*>(hero)->army.formation = tight; | ||||
| 	const_cast<CGHeroInstance*>(hero)-> formation = tight; | ||||
| 	SetFormation pack(hero->id,tight); | ||||
| 	sendRequest(&pack); | ||||
| } | ||||
| @@ -939,12 +939,12 @@ void CCallback::dig( const CGObjectInstance *hero ) | ||||
|  | ||||
| si8 CCallback::battleGetStackMorale( int stackID ) | ||||
| { | ||||
| 	return gs->curB->Morale( gs->curB->getStack(stackID) ); | ||||
| 	return gs->curB->getStack(stackID)->MoraleVal(); | ||||
| } | ||||
|  | ||||
| si8 CCallback::battleGetStackLuck( int stackID ) | ||||
| { | ||||
| 	return gs->curB->Luck( gs->curB->getStack(stackID) ); | ||||
| 	return gs->curB->getStack(stackID)->LuckVal(); | ||||
| } | ||||
|  | ||||
| void CCallback::castSpell(const CGHeroInstance *hero, int spellID, const int3 &pos) | ||||
| @@ -987,7 +987,7 @@ InfoAboutTown::~InfoAboutTown() | ||||
| void InfoAboutTown::initFromTown( const CGTownInstance *t, bool detailed ) | ||||
| { | ||||
| 	obj = t; | ||||
| 	army = t->army; | ||||
| 	army = t->getArmy(); | ||||
| 	built = t->builded; | ||||
| 	fortLevel = t->fortLevel(); | ||||
| 	name = t->name; | ||||
| @@ -1006,7 +1006,7 @@ void InfoAboutTown::initFromTown( const CGTownInstance *t, bool detailed ) | ||||
| 	/*else | ||||
| 	{ | ||||
| 		//hide info about hero stacks counts | ||||
| 		for(std::map<si32,std::pair<ui32,si32> >::iterator i = army.slots.begin(); i != army.slots.end(); ++i) | ||||
| 		for(std::map<si32,std::pair<ui32,si32> >::iterator i = slots.begin(); i != slots.end(); ++i) | ||||
| 		{ | ||||
| 			i->second.second = 0; | ||||
| 		} | ||||
| @@ -1017,7 +1017,7 @@ void InfoAboutTown::initFromGarrison(const CGGarrison *garr, bool detailed) | ||||
| { | ||||
| 	obj = garr; | ||||
| 	fortLevel = 0; | ||||
| 	army = garr->army; | ||||
| 	army = garr->getArmy(); | ||||
| 	name = CGI->generaltexth->names[33]; // "Garrison" | ||||
| 	owner = garr->tempOwner; | ||||
| 	built = false; | ||||
|   | ||||
| @@ -36,7 +36,7 @@ struct BattleAttack; | ||||
| struct BattleStackAttacked; | ||||
| struct SpellCast; | ||||
| struct SetStackEffect; | ||||
| struct HeroBonus; | ||||
| struct Bonus; | ||||
| struct PackageApplied; | ||||
| struct SetObjectProperty; | ||||
| struct CatapultAttack; | ||||
| @@ -53,17 +53,6 @@ class CObstacle | ||||
| 	//TODO: add some kind of the blockmap | ||||
| }; | ||||
|  | ||||
| struct StackState | ||||
| { | ||||
| 	StackState(){attackBonus=defenseBonus=healthBonus=speedBonus=morale=luck=shotsLeft=currentHealth=0;}; | ||||
| 	int attackBonus, defenseBonus, healthBonus, speedBonus; | ||||
| 	int currentHealth; | ||||
| 	int shotsLeft; | ||||
| 	std::set<int> effects; //IDs of spells affecting stack | ||||
| 	int morale, luck; | ||||
| 	int dmgMultiplier; //for ballista dmg bonus handling | ||||
| }; | ||||
|  | ||||
| class CGameInterface | ||||
| { | ||||
| public: | ||||
| @@ -98,8 +87,8 @@ public: | ||||
| 	virtual void yourTurn(){}; | ||||
| 	virtual void centerView (int3 pos, int focusTime){}; | ||||
| 	virtual void availableCreaturesChanged(const CGDwelling *town){}; | ||||
| 	virtual void heroBonusChanged(const CGHeroInstance *hero, const HeroBonus &bonus, bool gain){};//if gain hero received bonus, else he lost it | ||||
| 	virtual void playerBonusChanged(const HeroBonus &bonus, bool gain){};//if gain hero received bonus, else he lost it | ||||
| 	virtual void heroBonusChanged(const CGHeroInstance *hero, const Bonus &bonus, bool gain){};//if gain hero received bonus, else he lost it | ||||
| 	virtual void playerBonusChanged(const Bonus &bonus, bool gain){};//if gain hero received bonus, else he lost it | ||||
| 	virtual void requestRealized(PackageApplied *pa){}; | ||||
| 	virtual void heroExchangeStarted(si32 hero1, si32 hero2){}; | ||||
| 	virtual void objectPropertyChanged(const SetObjectProperty * sop){}; //eg. mine has been flagged | ||||
| @@ -121,7 +110,7 @@ public: | ||||
| 	virtual void battleStackMoved(int ID, int dest, int distance, bool end){}; | ||||
| 	virtual void battleSpellCast(SpellCast *sc){}; | ||||
| 	virtual void battleStacksEffectsSet(SetStackEffect & sse){};//called when a specific effect is set to stacks | ||||
| 	virtual void battleStart(CCreatureSet *army1, CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side){}; //called by engine when battle starts; side=0 - left, side=1 - right | ||||
| 	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 battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks){}; //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 | ||||
|   | ||||
| @@ -1898,7 +1898,7 @@ void CAdvMapInt::tileHovered(const int3 &tile) | ||||
| 						const CGTownInstance* townObj = dynamic_cast<const CGTownInstance*>(objAtTile); | ||||
|  | ||||
| 						// Show movement cursor for unguarded enemy towns, otherwise attack cursor. | ||||
| 						if (townObj && townObj->army.slots.empty()) | ||||
| 						if (townObj && !townObj->stacksCount()) | ||||
| 							CGI->curh->changeGraphic(0, 9 + turns*6); | ||||
| 						else | ||||
| 							CGI->curh->changeGraphic(0, 5 + turns*6); | ||||
| @@ -1938,7 +1938,7 @@ void CAdvMapInt::tileHovered(const int3 &tile) | ||||
| 					const CGGarrison* garrObj = dynamic_cast<const CGGarrison*>(objAtTile); //TODO evil evil cast! | ||||
|  | ||||
| 					// Show battle cursor for guarded enemy garrisons, otherwise movement cursor. | ||||
| 					if (garrObj  &&  garrObj->tempOwner != LOCPLINT->playerID  &&  !garrObj->army.slots.empty()) | ||||
| 					if (garrObj  &&  garrObj->tempOwner != LOCPLINT->playerID  &&  garrObj->stacksCount()) | ||||
| 						CGI->curh->changeGraphic(0, 5 + turns*6); | ||||
| 					else | ||||
| 						CGI->curh->changeGraphic(0, 9 + turns*6); | ||||
|   | ||||
| @@ -216,7 +216,7 @@ bool CSpellEffectAnim::init() | ||||
| 			} | ||||
|  | ||||
| 			// Correction for 2-hex creatures. | ||||
| 			if (destStack != NULL && destStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE)) | ||||
| 			if (destStack != NULL && destStack->doubleWide()) | ||||
| 				be.x += (destStack->attackerOwned ? -1 : 1)*tilePos.w/2; | ||||
|  | ||||
| 			owner->battleEffects.push_back(be); | ||||
| @@ -376,7 +376,7 @@ void CReverseAnim::nextFrame() | ||||
| 			owner->creAnims[stackID]->pos.x = coords.x; | ||||
| 			//creAnims[stackID]->pos.y = coords.second; | ||||
|  | ||||
| 			if(curs->hasFeatureOfType(StackFeature::DOUBLE_WIDE)) | ||||
| 			if(curs->doubleWide()) | ||||
| 			{ | ||||
| 				if(curs->attackerOwned) | ||||
| 				{ | ||||
| @@ -445,7 +445,7 @@ bool CDefenceAnim::init() | ||||
| 		if(IDby != -1) | ||||
| 		{ | ||||
| 			int attackerAnimType = owner->creAnims[IDby]->getType(); | ||||
| 			if( attackerAnimType == 11 && attackerAnimType == 12 && attackerAnimType == 13 && owner->creAnims[IDby]->getFrame() < attacker->creature->attackClimaxFrame ) | ||||
| 			if( attackerAnimType == 11 && attackerAnimType == 12 && attackerAnimType == 13 && owner->creAnims[IDby]->getFrame() < attacker->type->attackClimaxFrame ) | ||||
| 				return false; | ||||
| 		} | ||||
|  | ||||
| @@ -465,7 +465,7 @@ bool CDefenceAnim::init() | ||||
| 	const CStack * attacked = owner->curInt->cb->battleGetStackByID(stackID, false); | ||||
|  | ||||
| 	//reverse unit if necessary | ||||
| 	if(attacker && isToReverse(attacked->position, attacker->position, owner->creDir[stackID], attacker->hasFeatureOfType(StackFeature::DOUBLE_WIDE), owner->creDir[IDby])) | ||||
| 	if(attacker && isToReverse(attacked->position, attacker->position, owner->creDir[stackID], attacker->doubleWide(), owner->creDir[IDby])) | ||||
| 	{ | ||||
| 		owner->addNewAnim(new CReverseAnim(owner, stackID, attacked->position, true)); | ||||
| 		return false; | ||||
| @@ -476,7 +476,7 @@ bool CDefenceAnim::init() | ||||
| 	{		 | ||||
| 		for(std::list<SProjectileInfo>::const_iterator it = owner->projectiles.begin(); it != owner->projectiles.end(); ++it) | ||||
| 		{ | ||||
| 			if(it->creID == attacker->creature->idNumber) | ||||
| 			if(it->creID == attacker->type->idNumber) | ||||
| 			{ | ||||
| 				return false; | ||||
| 			} | ||||
| @@ -488,13 +488,13 @@ bool CDefenceAnim::init() | ||||
| 		 | ||||
| 	if(killed) | ||||
| 	{ | ||||
| 		CGI->soundh->playSound(battle_sound(attacked->creature, killed)); | ||||
| 		CGI->soundh->playSound(battle_sound(attacked->type, killed)); | ||||
| 		owner->creAnims[stackID]->setType(5); //death | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		// TODO: this block doesn't seems correct if the unit is defending. | ||||
| 		CGI->soundh->playSound(battle_sound(attacked->creature, wince)); | ||||
| 		CGI->soundh->playSound(battle_sound(attacked->type, wince)); | ||||
| 		owner->creAnims[stackID]->setType(3); //getting hit | ||||
| 	} | ||||
|  | ||||
| @@ -572,7 +572,7 @@ bool CBattleStackMoved::init() | ||||
| 		endAnim(); | ||||
| 		return false; | ||||
| 	} | ||||
| 	bool twoTiles = movedStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE); | ||||
| 	bool twoTiles = movedStack->doubleWide(); | ||||
| 	 | ||||
| 	Point begPosition = CBattleHex::getXYUnitAnim(curStackPos, movedStack->attackerOwned, movedStack, owner); | ||||
| 	Point endPosition = CBattleHex::getXYUnitAnim(destHex, movedStack->attackerOwned, movedStack, owner); | ||||
| @@ -598,11 +598,11 @@ bool CBattleStackMoved::init() | ||||
| 	//unit reversed | ||||
|  | ||||
| 	if(owner->moveSh <= 0) | ||||
| 		owner->moveSh = CGI->soundh->playSound(battle_sound(movedStack->creature, move), -1); | ||||
| 		owner->moveSh = CGI->soundh->playSound(battle_sound(movedStack->type, move), -1); | ||||
|  | ||||
| 	//step shift calculation | ||||
| 	posX = owner->creAnims[stackID]->pos.x, posY = owner->creAnims[stackID]->pos.y; // for precise calculations ;] | ||||
| 	if(mutPos == -1 && movedStack->hasFeatureOfType(StackFeature::FLYING))  | ||||
| 	if(mutPos == -1 && movedStack->hasBonusOfType(Bonus::FLYING))  | ||||
| 	{ | ||||
| 		steps *= distance; | ||||
| 		steps /= 2; //to make animation faster | ||||
| @@ -668,7 +668,7 @@ void CBattleStackMoved::endAnim() | ||||
|  | ||||
| 	if(movedStack) | ||||
| 	{ | ||||
| 		bool twoTiles = movedStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE); | ||||
| 		bool twoTiles = movedStack->doubleWide(); | ||||
|  | ||||
| 		if(endMoving) | ||||
| 		{ | ||||
| @@ -714,7 +714,7 @@ bool CBattleMoveStart::init() | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	CGI->soundh->playSound(battle_sound(movedStack->creature, startMoving)); | ||||
| 	CGI->soundh->playSound(battle_sound(movedStack->type, startMoving)); | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
| @@ -759,7 +759,7 @@ bool CBattleMoveEnd::init() | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	CGI->soundh->playSound(battle_sound(movedStack->creature, endMoving)); | ||||
| 	CGI->soundh->playSound(battle_sound(movedStack->type, endMoving)); | ||||
|  | ||||
| 	owner->creAnims[stackID]->setType(21); | ||||
|  | ||||
| @@ -800,9 +800,9 @@ void CBattleAttack::nextFrame() | ||||
| 	if(owner->creAnims[stackID]->onFirstFrameInGroup()) | ||||
| 	{ | ||||
| 		if(shooting) | ||||
| 			CGI->soundh->playSound(battle_sound(attackingStack->creature, shoot)); | ||||
| 			CGI->soundh->playSound(battle_sound(attackingStack->type, shoot)); | ||||
| 		else | ||||
| 			CGI->soundh->playSound(battle_sound(attackingStack->creature, attack)); | ||||
| 			CGI->soundh->playSound(battle_sound(attackingStack->type, attack)); | ||||
| 	} | ||||
| 	else if(owner->creAnims[stackID]->onLastFrameInGroup()) | ||||
| 	{ | ||||
| @@ -824,7 +824,7 @@ CBattleAttack::CBattleAttack(CBattleInterface * _owner, int _stackID, int _dest, | ||||
| 	attackingStack = owner->curInt->cb->battleGetStackByID(_stackID, false); | ||||
|  | ||||
| 	assert(attackingStack && "attackingStack is NULL in CBattleAttack::CBattleAttack !\n"); | ||||
| 	if(attackingStack->creature->idNumber != 145) //catapult is allowed to attack not-creature | ||||
| 	if(attackingStack->type->idNumber != 145) //catapult is allowed to attack not-creature | ||||
| 	{ | ||||
| 		assert(attackedStack && "attackedStack is NULL in CBattleAttack::CBattleAttack !\n"); | ||||
| 	} | ||||
| @@ -857,7 +857,7 @@ bool CMeleeAttack::init() | ||||
| 	int reversedShift = 0; //shift of attacking stack's position due to reversing | ||||
| 	if(attackingStack->attackerOwned) | ||||
| 	{ | ||||
| 		if(attackingStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE) && BattleInfo::mutualPosition(attackingStackPosBeforeReturn, dest) == -1) | ||||
| 		if(attackingStack->doubleWide() && BattleInfo::mutualPosition(attackingStackPosBeforeReturn, dest) == -1) | ||||
| 		{ | ||||
| 			if(BattleInfo::mutualPosition(attackingStackPosBeforeReturn + (attackingStack->attackerOwned ? -1 : 1), dest) >= 0) //if reversing stack will make its position adjacent to dest | ||||
| 			{ | ||||
| @@ -867,7 +867,7 @@ bool CMeleeAttack::init() | ||||
| 	} | ||||
| 	else //if(astack->attackerOwned) | ||||
| 	{ | ||||
| 		if(attackingStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE) && BattleInfo::mutualPosition(attackingStackPosBeforeReturn, dest) == -1) | ||||
| 		if(attackingStack->doubleWide() && BattleInfo::mutualPosition(attackingStackPosBeforeReturn, dest) == -1) | ||||
| 		{ | ||||
| 			if(BattleInfo::mutualPosition(attackingStackPosBeforeReturn + (attackingStack->attackerOwned ? -1 : 1), dest) >= 0) //if reversing stack will make its position adjacent to dest | ||||
| 			{ | ||||
| @@ -878,7 +878,7 @@ bool CMeleeAttack::init() | ||||
| 	} | ||||
|  | ||||
| 	//reversing stack if necessary | ||||
| 	if(isToReverse(attackingStackPosBeforeReturn, dest, owner->creDir[stackID], attackedStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE), owner->creDir[attackedStack->ID])) | ||||
| 	if(isToReverse(attackingStackPosBeforeReturn, dest, owner->creDir[stackID], attackedStack->doubleWide(), owner->creDir[attackedStack->ID])) | ||||
| 	{ | ||||
| 		owner->addNewAnim(new CReverseAnim(owner, stackID, attackingStackPosBeforeReturn, true)); | ||||
| 		return false; | ||||
| @@ -953,7 +953,7 @@ bool CShootingAnim::init() | ||||
| 		projectileAngle = -projectileAngle; | ||||
|  | ||||
| 	SProjectileInfo spi; | ||||
| 	spi.creID = shooter->creature->idNumber; | ||||
| 	spi.creID = shooter->type->idNumber; | ||||
| 	spi.reverse = !shooter->attackerOwned; | ||||
|  | ||||
| 	spi.step = 0; | ||||
| @@ -975,18 +975,18 @@ bool CShootingAnim::init() | ||||
|  | ||||
| 	if(projectileAngle > straightAngle) //upper shot | ||||
| 	{ | ||||
| 		spi.x = xycoord.x + 200 + shooter->creature->upperRightMissleOffsetX; | ||||
| 		spi.y = xycoord.y + 100 - shooter->creature->upperRightMissleOffsetY; | ||||
| 		spi.x = xycoord.x + 200 + shooter->type->upperRightMissleOffsetX; | ||||
| 		spi.y = xycoord.y + 100 - shooter->type->upperRightMissleOffsetY; | ||||
| 	} | ||||
| 	else if(projectileAngle < -straightAngle) //lower shot | ||||
| 	{ | ||||
| 		spi.x = xycoord.x + 200 + shooter->creature->lowerRightMissleOffsetX; | ||||
| 		spi.y = xycoord.y + 150 - shooter->creature->lowerRightMissleOffsetY; | ||||
| 		spi.x = xycoord.x + 200 + shooter->type->lowerRightMissleOffsetX; | ||||
| 		spi.y = xycoord.y + 150 - shooter->type->lowerRightMissleOffsetY; | ||||
| 	} | ||||
| 	else //straight shot | ||||
| 	{ | ||||
| 		spi.x = xycoord.x + 200 + shooter->creature->rightMissleOffsetX; | ||||
| 		spi.y = xycoord.y + 125 - shooter->creature->rightMissleOffsetY; | ||||
| 		spi.x = xycoord.x + 200 + shooter->type->rightMissleOffsetX; | ||||
| 		spi.y = xycoord.y + 125 - shooter->type->rightMissleOffsetY; | ||||
| 	} | ||||
| 	spi.lastStep = sqrt((float)((destcoord.x - spi.x)*(destcoord.x - spi.x) + (destcoord.y - spi.y) * (destcoord.y - spi.y))) / 40; | ||||
| 	if(spi.lastStep == 0) | ||||
| @@ -1003,7 +1003,7 @@ bool CShootingAnim::init() | ||||
| 		spi.frameNum = ((M_PI/2.0f - projectileAngle) / (2.0f *M_PI) + 1/((float)(2*(owner->idToProjectile[spi.creID]->ourImages.size()-1)))) * (owner->idToProjectile[spi.creID]->ourImages.size()-1); | ||||
| 	} | ||||
| 	//set delay | ||||
| 	spi.animStartDelay = CGI->creh->creatures[spi.creID].attackClimaxFrame; | ||||
| 	spi.animStartDelay = CGI->creh->creatures[spi.creID]->attackClimaxFrame; | ||||
| 	owner->projectiles.push_back(spi); | ||||
|  | ||||
| 	//attack aniamtion | ||||
| @@ -1064,7 +1064,7 @@ void CBattleInterface::addNewAnim(CBattleAnimation * anim) | ||||
| 	animsAreDisplayed.setn(true); | ||||
| } | ||||
|  | ||||
| CBattleInterface::CBattleInterface(CCreatureSet * army1, CCreatureSet * army2, CGHeroInstance *hero1, CGHeroInstance *hero2, const SDL_Rect & myRect, CPlayerInterface * att, CPlayerInterface * defen) | ||||
| CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSet * army2, CGHeroInstance *hero1, CGHeroInstance *hero2, const SDL_Rect & myRect, CPlayerInterface * att, CPlayerInterface * defen) | ||||
| 	: attackingHeroInstance(hero1), defendingHeroInstance(hero2), animCount(0), activeStack(-1), stackToActivate(-1), | ||||
| 	  mouseHoveredStack(-1), previouslyHoveredHex(-1), currentlyHoveredHex(-1), spellDestSelectMode(false), | ||||
| 	  spellToCast(NULL), givenCommand(NULL), myTurn(false), resWindow(NULL), animIDhelper(0), | ||||
| @@ -1228,25 +1228,25 @@ CBattleInterface::CBattleInterface(CCreatureSet * army1, CCreatureSet * army2, C | ||||
| 	//loading projectiles for units | ||||
| 	for(std::map<int, CStack>::iterator g = stacks.begin(); g != stacks.end(); ++g) | ||||
| 	{ | ||||
| 		int creID = (g->second.creature->idNumber == 149) ? CGI->creh->factionToTurretCreature[siegeH->town->town->typeID] : g->second.creature->idNumber; //id of creature whose shots should be loaded | ||||
| 		if(g->second.creature->isShooting() && CGI->creh->idToProjectile[creID] != std::string()) | ||||
| 		int creID = (g->second.type->idNumber == 149) ? CGI->creh->factionToTurretCreature[siegeH->town->town->typeID] : g->second.type->idNumber; //id of creature whose shots should be loaded | ||||
| 		if(g->second.type->isShooting() && CGI->creh->idToProjectile[creID] != std::string()) | ||||
| 		{	 | ||||
| 			idToProjectile[g->second.creature->idNumber] = CDefHandler::giveDef(CGI->creh->idToProjectile[creID]); | ||||
| 			idToProjectile[g->second.type->idNumber] = CDefHandler::giveDef(CGI->creh->idToProjectile[creID]); | ||||
|  | ||||
| 			if(idToProjectile[g->second.creature->idNumber]->ourImages.size() > 2) //add symmetric images | ||||
| 			if(idToProjectile[g->second.type->idNumber]->ourImages.size() > 2) //add symmetric images | ||||
| 			{ | ||||
| 				for(int k = idToProjectile[g->second.creature->idNumber]->ourImages.size()-2; k > 1; --k) | ||||
| 				for(int k = idToProjectile[g->second.type->idNumber]->ourImages.size()-2; k > 1; --k) | ||||
| 				{ | ||||
| 					Cimage ci; | ||||
| 					ci.bitmap = CSDL_Ext::rotate01(idToProjectile[g->second.creature->idNumber]->ourImages[k].bitmap); | ||||
| 					ci.bitmap = CSDL_Ext::rotate01(idToProjectile[g->second.type->idNumber]->ourImages[k].bitmap); | ||||
| 					ci.groupNumber = 0; | ||||
| 					ci.imName = std::string(); | ||||
| 					idToProjectile[g->second.creature->idNumber]->ourImages.push_back(ci); | ||||
| 					idToProjectile[g->second.type->idNumber]->ourImages.push_back(ci); | ||||
| 				} | ||||
| 			} | ||||
| 			for(int s=0; s<idToProjectile[g->second.creature->idNumber]->ourImages.size(); ++s) //alpha transforming | ||||
| 			for(int s=0; s<idToProjectile[g->second.type->idNumber]->ourImages.size(); ++s) //alpha transforming | ||||
| 			{ | ||||
| 				CSDL_Ext::alphaTransform(idToProjectile[g->second.creature->idNumber]->ourImages[s].bitmap); | ||||
| 				CSDL_Ext::alphaTransform(idToProjectile[g->second.type->idNumber]->ourImages[s].bitmap); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| @@ -1589,7 +1589,7 @@ void CBattleInterface::show(SDL_Surface * to) | ||||
| 		{ | ||||
| 			int curStackID = stackAliveByHex[b][v]; | ||||
| 			 | ||||
| 			if(!stacks[curStackID].hasFeatureOfType(StackFeature::FLYING) || creAnims[curStackID]->getType() != 0) | ||||
| 			if(!stacks[curStackID].hasBonusOfType(Bonus::FLYING) || creAnims[curStackID]->getType() != 0) | ||||
| 				showAliveStack(curStackID, stacks, to); | ||||
| 			else | ||||
| 				flyingStacks.push_back(curStackID); | ||||
| @@ -1733,7 +1733,7 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent) | ||||
| 				{ | ||||
| 					if(shere->owner == curInt->playerID) //our stack | ||||
| 					{ | ||||
| 						if(sactive->hasFeatureOfType(StackFeature::HEALER)) | ||||
| 						if(sactive->hasBonusOfType(Bonus::HEALER)) | ||||
| 						{ | ||||
| 							//display the possibility to heal this creature | ||||
| 							CGI->curh->changeGraphic(1,17); | ||||
| @@ -1745,7 +1745,7 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent) | ||||
| 						} | ||||
| 						//setting console text | ||||
| 						char buf[500]; | ||||
| 						sprintf(buf, CGI->generaltexth->allTexts[297].c_str(), shere->amount == 1 ? shere->creature->nameSing.c_str() : shere->creature->namePl.c_str()); | ||||
| 						sprintf(buf, CGI->generaltexth->allTexts[297].c_str(), shere->count == 1 ? shere->type->nameSing.c_str() : shere->type->namePl.c_str()); | ||||
| 						console->alterTxt = buf; | ||||
| 						console->whoSetAlter = 0; | ||||
| 						mouseHoveredStack = shere->ID; | ||||
| @@ -1773,7 +1773,7 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent) | ||||
| 						std::ostringstream estDmg; | ||||
| 						estDmg << estimatedDmg.first << " - " << estimatedDmg.second; | ||||
| 						//printing | ||||
| 						sprintf(buf, CGI->generaltexth->allTexts[296].c_str(), shere->amount == 1 ? shere->creature->nameSing.c_str() : shere->creature->namePl.c_str(), sactive->shots, estDmg.str().c_str()); | ||||
| 						sprintf(buf, CGI->generaltexth->allTexts[296].c_str(), shere->count == 1 ? shere->type->nameSing.c_str() : shere->type->namePl.c_str(), sactive->shots, estDmg.str().c_str()); | ||||
| 						console->alterTxt = buf; | ||||
| 						console->whoSetAlter = 0; | ||||
| 					} | ||||
| @@ -1797,7 +1797,7 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent) | ||||
| 						sectorCursor.push_back(12); | ||||
| 						sectorCursor.push_back(7); | ||||
|  | ||||
| 						const bool doubleWide = curInt->cb->battleGetStackByID(activeStack)->hasFeatureOfType(StackFeature::DOUBLE_WIDE); | ||||
| 						const bool doubleWide = curInt->cb->battleGetStackByID(activeStack)->doubleWide(); | ||||
| 						bool aboveAttackable = true, belowAttackable = true; | ||||
|  | ||||
| 						// Exclude directions which cannot be attacked from. | ||||
| @@ -1923,7 +1923,7 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent) | ||||
| 						std::ostringstream estDmg; | ||||
| 						estDmg << estimatedDmg.first << " - " << estimatedDmg.second; | ||||
| 						//printing | ||||
| 						sprintf(buf, CGI->generaltexth->allTexts[36].c_str(), shere->amount == 1 ? shere->creature->nameSing.c_str() : shere->creature->namePl.c_str(), estDmg.str().c_str()); | ||||
| 						sprintf(buf, CGI->generaltexth->allTexts[36].c_str(), shere->count == 1 ? shere->type->nameSing.c_str() : shere->type->namePl.c_str(), estDmg.str().c_str()); | ||||
| 						console->alterTxt = buf; | ||||
| 						console->whoSetAlter = 0; | ||||
| 					} | ||||
| @@ -1934,7 +1934,7 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent) | ||||
| 						console->whoSetAlter = 0; | ||||
| 					} | ||||
| 				} | ||||
| 				else if( sactive && sactive->hasFeatureOfType(StackFeature::CATAPULT) && isCatapultAttackable(myNumber) ) //catapulting | ||||
| 				else if( sactive && sactive->hasBonusOfType(Bonus::CATAPULT) && isCatapultAttackable(myNumber) ) //catapulting | ||||
| 				{ | ||||
| 					CGI->curh->changeGraphic(1,16); | ||||
| 					console->alterTxt = ""; | ||||
| @@ -1954,15 +1954,15 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent) | ||||
| 				if(sactive) //there can be a moment when stack is dead ut next is not yet activated | ||||
| 				{ | ||||
| 					char buf[500]; | ||||
| 					if(sactive->hasFeatureOfType(StackFeature::FLYING)) | ||||
| 					if(sactive->hasBonusOfType(Bonus::FLYING)) | ||||
| 					{ | ||||
| 						CGI->curh->changeGraphic(1,2); | ||||
| 						sprintf(buf, CGI->generaltexth->allTexts[295].c_str(), sactive->amount == 1 ? sactive->creature->nameSing.c_str() : sactive->creature->namePl.c_str()); | ||||
| 						sprintf(buf, CGI->generaltexth->allTexts[295].c_str(), sactive->count == 1 ? sactive->type->nameSing.c_str() : sactive->type->namePl.c_str()); | ||||
| 					} | ||||
| 					else | ||||
| 					{ | ||||
| 						CGI->curh->changeGraphic(1,1); | ||||
| 						sprintf(buf, CGI->generaltexth->allTexts[294].c_str(), sactive->amount == 1 ? sactive->creature->nameSing.c_str() : sactive->creature->namePl.c_str()); | ||||
| 						sprintf(buf, CGI->generaltexth->allTexts[294].c_str(), sactive->count == 1 ? sactive->type->nameSing.c_str() : sactive->type->namePl.c_str()); | ||||
| 					} | ||||
|  | ||||
| 					console->alterTxt = buf; | ||||
| @@ -1994,7 +1994,7 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent) | ||||
| 			//get dead stack if we cast resurrection or animate dead | ||||
| 			const CStack * stackUnder = curInt->cb->battleGetStackByPos(myNumber, spellToCast->additionalInfo != 38 && spellToCast->additionalInfo != 39); | ||||
|  | ||||
| 			if(stackUnder && spellToCast->additionalInfo == 39 && !stackUnder->hasFeatureOfType(StackFeature::UNDEAD)) //animate dead can be cast only on undead creatures | ||||
| 			if(stackUnder && spellToCast->additionalInfo == 39 && !stackUnder->hasBonusOfType(Bonus::UNDEAD)) //animate dead can be cast only on undead creatures | ||||
| 				stackUnder = NULL; | ||||
|  | ||||
| 			bool whichCase; //for cases 1, 2 and 3 | ||||
| @@ -2027,7 +2027,7 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent) | ||||
| 					CGI->curh->changeGraphic(3, 0); | ||||
| 					//setting console text | ||||
| 					char buf[500]; | ||||
| 					std::string creName = stackUnder->amount > 1 ? stackUnder->creature->namePl : stackUnder->creature->nameSing; | ||||
| 					std::string creName = stackUnder->count > 1 ? stackUnder->type->namePl : stackUnder->type->nameSing; | ||||
| 						sprintf(buf, CGI->generaltexth->allTexts[27].c_str(), CGI->spellh->spells[spellToCast->additionalInfo].name.c_str(), creName.c_str()); | ||||
| 					console->alterTxt = buf; | ||||
| 					console->whoSetAlter = 0; | ||||
| @@ -2182,12 +2182,12 @@ void CBattleInterface::newStack(int stackID) | ||||
|  | ||||
| 	if(newStack->position < 0) //turret | ||||
| 	{ | ||||
| 		const CCreature & turretCreature = CGI->creh->creatures[ CGI->creh->factionToTurretCreature[siegeH->town->town->typeID] ]; | ||||
| 		const CCreature & turretCreature = *CGI->creh->creatures[ CGI->creh->factionToTurretCreature[siegeH->town->town->typeID] ]; | ||||
| 		creAnims[stackID] = new CCreatureAnimation(turretCreature.animDefName);	 | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		creAnims[stackID] = new CCreatureAnimation(newStack->creature->animDefName);	 | ||||
| 		creAnims[stackID] = new CCreatureAnimation(newStack->type->animDefName);	 | ||||
| 	} | ||||
| 	creAnims[stackID]->setType(2); | ||||
| 	creAnims[stackID]->pos = Rect(coords.x, coords.y, creAnims[newStack->ID]->fullWidth, creAnims[newStack->ID]->fullHeight); | ||||
| @@ -2239,13 +2239,13 @@ void CBattleInterface::newRound(int number) | ||||
| 	std::map<int, CStack> stacks = curInt->cb->battleGetStacks(); | ||||
| 	for(std::map<int, CStack>::const_iterator it = stacks.begin(); it != stacks.end(); ++it) | ||||
| 	{ | ||||
| 		if( it->second.hasFeatureOfType(StackFeature::HP_REGENERATION) && it->second.alive() ) | ||||
| 		if( it->second.hasBonusOfType(Bonus::HP_REGENERATION) && it->second.alive() ) | ||||
| 			displayEffect(74, it->second.position); | ||||
|  | ||||
| 		if( it->second.hasFeatureOfType(StackFeature::FULL_HP_REGENERATION, 0) && it->second.alive() ) | ||||
| 		if( it->second.hasBonusOfType(Bonus::FULL_HP_REGENERATION, 0) && it->second.alive() ) | ||||
| 			displayEffect(4, it->second.position); | ||||
|  | ||||
| 		if( it->second.hasFeatureOfType(StackFeature::FULL_HP_REGENERATION, 1) && it->second.alive() ) | ||||
| 		if( it->second.hasBonusOfType(Bonus::FULL_HP_REGENERATION, 1) && it->second.alive() ) | ||||
| 			displayEffect(74, it->second.position); | ||||
| 	} | ||||
| } | ||||
| @@ -2317,7 +2317,7 @@ void CBattleInterface::hexLclicked(int whichOne) | ||||
| { | ||||
| 	const CStack * actSt = curInt->cb->battleGetStackByID(activeStack); | ||||
| 	if( ((whichOne%BFIELD_WIDTH)!=0 && (whichOne%BFIELD_WIDTH)!=(BFIELD_WIDTH-1)) //if player is trying to attack enemey unit or move creature stack | ||||
| 		|| (actSt->hasFeatureOfType(StackFeature::CATAPULT) && !spellDestSelectMode ) | ||||
| 		|| (actSt->hasBonusOfType(Bonus::CATAPULT) && !spellDestSelectMode ) | ||||
| 		) | ||||
| 	{ | ||||
| 		if(!myTurn) | ||||
| @@ -2362,7 +2362,7 @@ void CBattleInterface::hexLclicked(int whichOne) | ||||
| 				if(std::find(shadedHexes.begin(),shadedHexes.end(),whichOne)!=shadedHexes.end())// and it's in our range | ||||
| 				{ | ||||
| 					CGI->curh->changeGraphic(1, 6); //cursor should be changed | ||||
| 					if(curInt->cb->battleGetStackByID(activeStack)->hasFeatureOfType(StackFeature::DOUBLE_WIDE)) | ||||
| 					if(curInt->cb->battleGetStackByID(activeStack)->doubleWide()) | ||||
| 					{ | ||||
| 						std::vector<int> acc = curInt->cb->battleGetAvailableHexes(activeStack, false); | ||||
| 						int shiftedDest = whichOne + (curInt->cb->battleGetStackByID(activeStack)->attackerOwned ? 1 : -1); | ||||
| @@ -2376,7 +2376,7 @@ void CBattleInterface::hexLclicked(int whichOne) | ||||
| 						giveCommand(2,whichOne,activeStack); | ||||
| 					} | ||||
| 				} | ||||
| 				else if(actSt->hasFeatureOfType(StackFeature::CATAPULT) && isCatapultAttackable(whichOne)) //attacking (catapult) | ||||
| 				else if(actSt->hasBonusOfType(Bonus::CATAPULT) && isCatapultAttackable(whichOne)) //attacking (catapult) | ||||
| 				{ | ||||
| 					giveCommand(9,whichOne,activeStack); | ||||
| 				} | ||||
| @@ -2395,7 +2395,7 @@ void CBattleInterface::hexLclicked(int whichOne) | ||||
| 				{ | ||||
| 				case 12: //from bottom right | ||||
| 					{ | ||||
| 						bool doubleWide = actStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE); | ||||
| 						bool doubleWide = actStack->doubleWide(); | ||||
| 						int destHex = whichOne + ( (whichOne/BFIELD_WIDTH)%2 ? BFIELD_WIDTH : BFIELD_WIDTH+1 ) + | ||||
| 							(actStack->attackerOwned && doubleWide ? 1 : 0); | ||||
| 						if(vstd::contains(shadedHexes, destHex)) | ||||
| @@ -2431,7 +2431,7 @@ void CBattleInterface::hexLclicked(int whichOne) | ||||
| 					} | ||||
| 				case 8: //from left | ||||
| 					{ | ||||
| 						if(actStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE) && !actStack->attackerOwned) | ||||
| 						if(actStack->doubleWide() && !actStack->attackerOwned) | ||||
| 						{ | ||||
| 							std::vector<int> acc = curInt->cb->battleGetAvailableHexes(activeStack, false); | ||||
| 							if(vstd::contains(acc, whichOne)) | ||||
| @@ -2464,7 +2464,7 @@ void CBattleInterface::hexLclicked(int whichOne) | ||||
| 					} | ||||
| 				case 10: //from top right | ||||
| 					{ | ||||
| 						bool doubleWide = actStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE); | ||||
| 						bool doubleWide = actStack->doubleWide(); | ||||
| 						int destHex = whichOne - ( (whichOne/BFIELD_WIDTH)%2 ? BFIELD_WIDTH : BFIELD_WIDTH-1 ) + | ||||
| 							(actStack->attackerOwned && doubleWide ? 1 : 0); | ||||
| 						if(vstd::contains(shadedHexes, destHex)) | ||||
| @@ -2483,7 +2483,7 @@ void CBattleInterface::hexLclicked(int whichOne) | ||||
| 					} | ||||
| 				case 11: //from right | ||||
| 					{ | ||||
| 						if(actStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE) && actStack->attackerOwned) | ||||
| 						if(actStack->doubleWide() && actStack->attackerOwned) | ||||
| 						{ | ||||
| 							std::vector<int> acc = curInt->cb->battleGetAvailableHexes(activeStack, false); | ||||
| 							if(vstd::contains(acc, whichOne)) | ||||
| @@ -2541,7 +2541,7 @@ void CBattleInterface::hexLclicked(int whichOne) | ||||
| 				} | ||||
|  | ||||
| 			} | ||||
| 			else if (actSt->hasFeatureOfType(StackFeature::HEALER) && actSt->owner == dest->owner) //friendly creature we can heal | ||||
| 			else if (actSt->hasBonusOfType(Bonus::HEALER) && actSt->owner == dest->owner) //friendly creature we can heal | ||||
| 			{ | ||||
| 				giveCommand(12, whichOne, activeStack); //command healing | ||||
|  | ||||
| @@ -2689,7 +2689,7 @@ void CBattleInterface::spellCast(SpellCast * sc) | ||||
| 			boost::algorithm::replace_first(text, "%s", "Creature"); //TODO: better fix | ||||
| 		} | ||||
| 		boost::algorithm::replace_first(text, "%s", CGI->spellh->spells[sc->id].name); | ||||
| 		boost::algorithm::replace_first(text, "%s", curInt->cb->battleGetStackByID(*sc->affectedCres.begin(), false)->creature->namePl ); | ||||
| 		boost::algorithm::replace_first(text, "%s", curInt->cb->battleGetStackByID(*sc->affectedCres.begin(), false)->type->namePl ); | ||||
| 		console->addText(text); | ||||
| 	} | ||||
| 	else | ||||
| @@ -2900,14 +2900,14 @@ void CBattleInterface::showAliveStack(int ID, const std::map<int, CStack> & stac | ||||
| 	creAnims[ID]->nextFrame(to, creAnims[ID]->pos.x, creAnims[ID]->pos.y, creDir[ID], animCount, incrementFrame, ID==activeStack, ID==mouseHoveredStack); //increment always when moving, never if stack died | ||||
|  | ||||
| 	//printing amount | ||||
| 	if(curStack.amount > 0 //don't print if stack is not alive | ||||
| 	if(curStack.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  ||  curStack.position != curInt->curAction->additionalInfo) //nor if it's an object of attack | ||||
| 				&& (curInt->curAction->destinationTile != curStack.position) //nor if it's on destination tile for current action | ||||
| 				) | ||||
| 			) | ||||
| 			&& !curStack.hasFeatureOfType(StackFeature::SIEGE_WEAPON) //and not a war machine... | ||||
| 			&& !curStack.hasBonusOfType(Bonus::SIEGE_WEAPON) //and not a war machine... | ||||
| 	) | ||||
| 	{ | ||||
| 		int xAdd = curStack.attackerOwned ? 220 : 202; | ||||
| @@ -2941,7 +2941,7 @@ void CBattleInterface::showAliveStack(int ID, const std::map<int, CStack> & stac | ||||
| 		SDL_BlitSurface(amountBG, NULL, to, &genRect(amountNormal->h, amountNormal->w, creAnims[ID]->pos.x + xAdd, creAnims[ID]->pos.y + 260)); | ||||
| 		//blitting amount | ||||
| 		CSDL_Ext::printAtMiddle( | ||||
| 			makeNumberShort(curStack.amount), | ||||
| 			makeNumberShort(curStack.count), | ||||
| 			creAnims[ID]->pos.x + xAdd + 15, | ||||
| 			creAnims[ID]->pos.y + 260 + 5, | ||||
| 			FONT_TINY, | ||||
| @@ -3045,18 +3045,18 @@ void CBattleInterface::printConsoleAttacked(int ID, int dmg, int killed, int IDb | ||||
| 	char tabh[200]; | ||||
| 	const CStack * attacker = curInt->cb->battleGetStackByID(IDby, false); | ||||
| 	const CStack * defender = curInt->cb->battleGetStackByID(ID, false); | ||||
| 	int end = sprintf(tabh, CGI->generaltexth->allTexts[attacker->amount > 1 ? 377 : 376].c_str(), | ||||
| 		(attacker->amount > 1 ? attacker->creature->namePl.c_str() : attacker->creature->nameSing.c_str()), | ||||
| 	int end = sprintf(tabh, CGI->generaltexth->allTexts[attacker->count > 1 ? 377 : 376].c_str(), | ||||
| 		(attacker->count > 1 ? attacker->type->namePl.c_str() : attacker->type->nameSing.c_str()), | ||||
| 		dmg); | ||||
| 	if(killed > 0) | ||||
| 	{ | ||||
| 		if(killed > 1) | ||||
| 		{ | ||||
| 			sprintf(tabh + end, CGI->generaltexth->allTexts[379].c_str(), killed, defender->creature->namePl.c_str()); | ||||
| 			sprintf(tabh + end, CGI->generaltexth->allTexts[379].c_str(), killed, defender->type->namePl.c_str()); | ||||
| 		} | ||||
| 		else //killed == 1 | ||||
| 		{ | ||||
| 			sprintf(tabh + end, CGI->generaltexth->allTexts[378].c_str(), defender->creature->nameSing.c_str()); | ||||
| 			sprintf(tabh + end, CGI->generaltexth->allTexts[378].c_str(), defender->type->nameSing.c_str()); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @@ -3219,14 +3219,14 @@ void CBattleInterface::startAction(const BattleAction* action) | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	if(txtid > 0  &&  stack->amount != 1) | ||||
| 	if(txtid > 0  &&  stack->count != 1) | ||||
| 		txtid++; //move to plural text | ||||
| 	else if(txtid < 0) | ||||
| 		txtid = -txtid; | ||||
|  | ||||
| 	if(txtid) | ||||
| 	{ | ||||
| 		sprintf(txt, CGI->generaltexth->allTexts[txtid].c_str(),  (stack->amount != 1) ? stack->creature->namePl.c_str() : stack->creature->nameSing.c_str(), 0); | ||||
| 		sprintf(txt, CGI->generaltexth->allTexts[txtid].c_str(),  (stack->count != 1) ? stack->type->namePl.c_str() : stack->type->nameSing.c_str(), 0); | ||||
| 		console->addText(txt); | ||||
| 	} | ||||
|  | ||||
| @@ -3386,7 +3386,7 @@ Point CBattleHex::getXYUnitAnim(const int & hexNum, const bool & attacker, const | ||||
| 	Point ret(-500, -500); //returned value | ||||
| 	if(stack->position < 0) //creatures in turrets | ||||
| 	{ | ||||
| 		const CCreature & turretCreature = CGI->creh->creatures[ CGI->creh->factionToTurretCreature[cbi->siegeH->town->town->typeID] ]; | ||||
| 		const CCreature & turretCreature = *CGI->creh->creatures[ CGI->creh->factionToTurretCreature[cbi->siegeH->town->town->typeID] ]; | ||||
| 		int xShift = turretCreature.isDoubleWide() ? 44 : 0; | ||||
|  | ||||
| 		switch(stack->position) | ||||
| @@ -3415,7 +3415,7 @@ Point CBattleHex::getXYUnitAnim(const int & hexNum, const bool & attacker, const | ||||
| 			ret.x = -219 + 22 * ( ((hexNum/BFIELD_WIDTH) + 1)%2 ) + 44 * (hexNum % BFIELD_WIDTH); | ||||
| 		} | ||||
| 		//shifting position for double - hex creatures | ||||
| 		if(stack && stack->hasFeatureOfType(StackFeature::DOUBLE_WIDE)) | ||||
| 		if(stack && stack->doubleWide()) | ||||
| 		{ | ||||
| 			if(attacker) | ||||
| 			{ | ||||
| @@ -3483,7 +3483,7 @@ void CBattleHex::mouseMoved(const SDL_MouseMotionEvent &sEvent) | ||||
| 		{ | ||||
| 			char tabh[160]; | ||||
| 			const CStack * attackedStack = myInterface->curInt->cb->battleGetStackByPos(myNumber); | ||||
| 			const std::string & attackedName = attackedStack->amount == 1 ? attackedStack->creature->nameSing : attackedStack->creature->namePl; | ||||
| 			const std::string & attackedName = attackedStack->count == 1 ? attackedStack->type->nameSing : attackedStack->type->namePl; | ||||
| 			sprintf(tabh, CGI->generaltexth->allTexts[220].c_str(), attackedName.c_str()); | ||||
| 			myInterface->console->alterTxt = std::string(tabh); | ||||
| 			setAlterText = true; | ||||
| @@ -3511,32 +3511,10 @@ void CBattleHex::clickRight(tribool down, bool previousState) | ||||
| 	{ | ||||
| 		const CStack & myst = *myInterface->curInt->cb->battleGetStackByID(stID); //stack info | ||||
| 		if(!myst.alive()) return; | ||||
| 		StackState *pom = NULL; | ||||
| 		if(down) | ||||
| 		{ | ||||
| 			pom = new StackState(); | ||||
| 			const CGHeroInstance *h = myst.owner == myInterface->attackingHeroInstance->tempOwner ? myInterface->attackingHeroInstance : myInterface->defendingHeroInstance; | ||||
|  | ||||
| 			pom->attackBonus = myst.Attack() - myst.creature->attack; | ||||
| 			pom->defenseBonus = myst.Defense() - myst.creature->defence; | ||||
| 			pom->luck = myInterface->curInt->cb->battleGetStackLuck(myst.ID); | ||||
| 			pom->morale = myInterface->curInt->cb->battleGetStackMorale(myst.ID); | ||||
| 			pom->speedBonus = myst.Speed() - myst.creature->speed; | ||||
| 			pom->healthBonus = myst.MaxHealth() - myst.creature->hitPoints; | ||||
| 			if(myst.hasFeatureOfType(StackFeature::SIEGE_WEAPON)) | ||||
| 				pom->dmgMultiplier = h->getPrimSkillLevel(0) + 1; | ||||
| 			else | ||||
| 				pom->dmgMultiplier = 1; | ||||
|  | ||||
| 			pom->shotsLeft = myst.shots; | ||||
| 			for(int vb=0; vb<myst.effects.size(); ++vb) | ||||
| 			{ | ||||
| 				pom->effects.insert(myst.effects[vb].id); | ||||
| 			} | ||||
| 			pom->currentHealth = myst.firstHPleft; | ||||
| 			GH.pushInt(new CCreInfoWindow(myst.creature->idNumber, 0, myst.amount, pom, 0, 0, NULL)); | ||||
| 			GH.pushInt(new CCreInfoWindow(myst)); | ||||
| 		} | ||||
| 		delete pom; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -3660,7 +3638,7 @@ CBattleResultWindow::CBattleResultWindow(const BattleResult &br, const SDL_Rect | ||||
| 	{ | ||||
| 		int bestMonsterID = -1; | ||||
| 		int bestPower = 0; | ||||
| 		for(TSlots::const_iterator it = owner->army1->slots.begin(); it!=owner->army1->slots.end(); ++it) | ||||
| 		for(TSlots::const_iterator it = owner->army1->Slots().begin(); it!=owner->army1->Slots().end(); ++it) | ||||
| 		{ | ||||
| 			if( it->second.type->AIValue > bestPower) | ||||
| 			{ | ||||
| @@ -3670,7 +3648,7 @@ CBattleResultWindow::CBattleResultWindow(const BattleResult &br, const SDL_Rect | ||||
| 		} | ||||
| 		SDL_BlitSurface(graphics->bigImgs[bestMonsterID], NULL, background, &genRect(64, 58, 21, 38)); | ||||
| 		//setting attackerName | ||||
| 		attackerName =  CGI->creh->creatures[bestMonsterID].namePl; | ||||
| 		attackerName =  CGI->creh->creatures[bestMonsterID]->namePl; | ||||
| 	} | ||||
| 	if(owner->defendingHeroInstance) //a hero defended | ||||
| 	{ | ||||
| @@ -3682,7 +3660,7 @@ CBattleResultWindow::CBattleResultWindow(const BattleResult &br, const SDL_Rect | ||||
| 	{ | ||||
| 		int bestMonsterID = -1; | ||||
| 		int bestPower = 0; | ||||
| 		for(TSlots::const_iterator it = owner->army2->slots.begin(); it!=owner->army2->slots.end(); ++it) | ||||
| 		for(TSlots::const_iterator it = owner->army2->Slots().begin(); it!=owner->army2->Slots().end(); ++it) | ||||
| 		{ | ||||
| 			if( it->second.type->AIValue > bestPower) | ||||
| 			{ | ||||
| @@ -3692,7 +3670,7 @@ CBattleResultWindow::CBattleResultWindow(const BattleResult &br, const SDL_Rect | ||||
| 		} | ||||
| 		SDL_BlitSurface(graphics->bigImgs[bestMonsterID], NULL, background, &genRect(64, 58, 391, 38)); | ||||
| 		//setting defenderName | ||||
| 		defenderName =  CGI->creh->creatures[bestMonsterID].namePl; | ||||
| 		defenderName =  CGI->creh->creatures[bestMonsterID]->namePl; | ||||
| 	} | ||||
|  | ||||
| 	//printing attacker and defender's names | ||||
| @@ -4124,16 +4102,16 @@ void CStackQueue::StackBox::showAll( SDL_Surface *to ) | ||||
| 		//SDL_UpdateRect(bg, 0, 0, 0, 0); | ||||
| 		CSDL_Ext::blit8bppAlphaTo24bpp(bg, NULL, to, &genRect(bg->h, bg->w, pos.x, pos.y)); | ||||
| 		//blitAt(bg, pos, to); | ||||
| 		blitAt(graphics->bigImgs[my->creature->idNumber], pos.x +9, pos.y + 1, to); | ||||
| 		printAtMiddleLoc(makeNumberShort(my->amount), pos.w/2, pos.h - 12, FONT_MEDIUM, zwykly, to); | ||||
| 		blitAt(graphics->bigImgs[my->type->idNumber], pos.x +9, pos.y + 1, to); | ||||
| 		printAtMiddleLoc(makeNumberShort(my->count), pos.w/2, pos.h - 12, FONT_MEDIUM, zwykly, to); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		blitAt(graphics->smallImgs[-2], pos, to); | ||||
| 		blitAt(graphics->smallImgs[my->creature->idNumber], pos, to); | ||||
| 		blitAt(graphics->smallImgs[my->type->idNumber], pos, to); | ||||
| 		const SDL_Color &ownerColor = (my->owner == 255 ? *graphics->neutralColor : graphics->playerColors[my->owner]); | ||||
| 		CSDL_Ext::drawBorder(to, pos, int3(ownerColor.r, ownerColor.g, ownerColor.b)); | ||||
| 		printAtMiddleLoc(makeNumberShort(my->amount), pos.w/2, pos.h - 8, FONT_TINY, zwykly, to); | ||||
| 		printAtMiddleLoc(makeNumberShort(my->count), pos.w/2, pos.h - 8, FONT_TINY, zwykly, to); | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -382,7 +382,7 @@ private: | ||||
| 	CBattleConsole * console; | ||||
| 	CBattleHero * attackingHero, * defendingHero; //fighting heroes | ||||
| 	CStackQueue *queue; | ||||
| 	CCreatureSet * army1, * army2; //fighting armies | ||||
| 	const CCreatureSet * army1, * army2; //fighting armies | ||||
| 	CGHeroInstance * attackingHeroInstance, * defendingHeroInstance; | ||||
| 	std::map< int, CCreatureAnimation * > creAnims; //animations of creatures from fighting armies (order by BattleInfo's stacks' ID) | ||||
| 	std::map< int, CDefHandler * > idToProjectile; //projectiles of creatures (creatureID, defhandler) | ||||
| @@ -445,7 +445,7 @@ public: | ||||
| 	unsigned int animIDhelper; //for giving IDs for animations | ||||
| 	static CondSh<bool> animsAreDisplayed; //for waiting with the end of battle for end of anims | ||||
|  | ||||
| 	CBattleInterface(CCreatureSet * army1, CCreatureSet * army2, CGHeroInstance *hero1, CGHeroInstance *hero2, const SDL_Rect & myRect, CPlayerInterface * att, CPlayerInterface * defen); //c-tor | ||||
| 	CBattleInterface(const CCreatureSet * army1, const CCreatureSet * army2, CGHeroInstance *hero1, CGHeroInstance *hero2, const SDL_Rect & myRect, CPlayerInterface * att, CPlayerInterface * defen); //c-tor | ||||
| 	~CBattleInterface(); //d-tor | ||||
|  | ||||
| 	//std::vector<TimeInterested*> timeinterested; //animation handling | ||||
|   | ||||
| @@ -287,7 +287,7 @@ void CHeroGSlot::clickLeft(tribool down, bool previousState) | ||||
| 					LOCPLINT->showInfoDialog(tmp,std::vector<SComponent*>(), soundBase::sound_todo); | ||||
| 					allow = false; | ||||
| 				} | ||||
| 				else if(!other->hero->army.slots.size()) //hero has no creatures - strange, but if we have appropriate error message... | ||||
| 				else if(!other->hero->stacksCount()) //hero has no creatures - strange, but if we have appropriate error message... | ||||
| 				{ | ||||
| 					LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[19],std::vector<SComponent*>(), soundBase::sound_todo); //This hero has no creatures.  A hero must have creatures before he can brave the dangers of the countryside. | ||||
| 					allow = false; | ||||
| @@ -986,7 +986,7 @@ void CCastleInterface::recreateBuildings() | ||||
| 			Structure * st = CGI->townh->structures[town->subID][20]; | ||||
| 			buildings.push_back(new CBuildingRect(st)); | ||||
| 			s.insert(std::pair<int,int>(st->group,st->ID)); | ||||
| 			isThereShip = true; | ||||
| 			isThereShip = true;  | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @@ -1110,7 +1110,7 @@ void CCastleInterface::CCreaInfo::hover(bool on) | ||||
| 	if(on) | ||||
| 	{ | ||||
| 		std::string descr=CGI->generaltexth->allTexts[588]; | ||||
| 		boost::algorithm::replace_first(descr,"%s",CGI->creh->creatures[crid].namePl); | ||||
| 		boost::algorithm::replace_first(descr,"%s",CGI->creh->creatures[crid]->namePl); | ||||
| 		GH.statusbar->print(descr); | ||||
| 	} | ||||
| 	else | ||||
| @@ -1142,12 +1142,12 @@ void CCastleInterface::CCreaInfo::clickRight(tribool down, bool previousState) | ||||
| 		int summ=0, cnt=0; | ||||
| 		int level=(bid-30)%CREATURES_PER_TOWN; | ||||
| 		std::string descr=CGI->generaltexth->allTexts[589];//Growth of creature is number | ||||
| 		boost::algorithm::replace_first(descr,"%s",CGI->creh->creatures[crid].nameSing); | ||||
| 		boost::algorithm::replace_first(descr,"%s",CGI->creh->creatures[crid]->nameSing); | ||||
| 		boost::algorithm::replace_first(descr,"%d", boost::lexical_cast<std::string>( | ||||
| 			ci->town->creatureGrowth(level))); | ||||
|  | ||||
| 		descr +="\n"+CGI->generaltexth->allTexts[590]; | ||||
| 		summ = CGI->creh->creatures[crid].growth; | ||||
| 		summ = CGI->creh->creatures[crid]->growth; | ||||
| 		boost::algorithm::replace_first(descr,"%d", boost::lexical_cast<std::string>(summ)); | ||||
| 		 | ||||
|  | ||||
| @@ -1159,19 +1159,19 @@ void CCastleInterface::CCreaInfo::clickRight(tribool down, bool previousState) | ||||
| 		if(ci->town->town->hordeLvl[0]==level)//horde, x to summ | ||||
| 		if((bld.find(18)!=bld.end()) || (bld.find(19)!=bld.end())) | ||||
| 			summ+=AddToString(CGI->buildh->buildings[ci->town->subID][18]->Name()+" %+d",descr, | ||||
| 				CGI->creh->creatures[crid].hordeGrowth); | ||||
| 				CGI->creh->creatures[crid]->hordeGrowth); | ||||
|  | ||||
| 		if(ci->town->town->hordeLvl[1]==level)//horde, x to summ | ||||
| 		if((bld.find(24)!=bld.end()) || (bld.find(25)!=bld.end())) | ||||
| 			summ+=AddToString(CGI->buildh->buildings[ci->town->subID][24]->Name()+" %+d",descr, | ||||
| 				CGI->creh->creatures[crid].hordeGrowth); | ||||
| 				CGI->creh->creatures[crid]->hordeGrowth); | ||||
|  | ||||
| 		cnt = 0; | ||||
| 		int creaLevel = (bid-30)%CREATURES_PER_TOWN;//dwellings have unupgraded units | ||||
|  | ||||
| 		for (std::vector<CGDwelling*>::const_iterator it = CGI->state->players[ci->town->tempOwner].dwellings.begin(); | ||||
| 			it !=CGI->state->players[ci->town->tempOwner].dwellings.end(); ++it) | ||||
| 				if (CGI->creh->creatures[ci->town->town->basicCreatures[level]].idNumber == (*it)->creatures[0].second[0]) | ||||
| 				if (CGI->creh->creatures[ci->town->town->basicCreatures[level]]->idNumber == (*it)->creatures[0].second[0]) | ||||
| 					cnt++;//external dwellings count to summ | ||||
| 		summ+=AddToString(CGI->generaltexth->allTexts[591],descr,cnt); | ||||
|  | ||||
| @@ -1180,9 +1180,9 @@ void CCastleInterface::CCreaInfo::clickRight(tribool down, bool previousState) | ||||
| 		{ | ||||
| 			if(ch) | ||||
| 			{ | ||||
| 				for(std::list<HeroBonus>::const_iterator i=ch->bonuses.begin(); i != ch->bonuses.end(); i++) | ||||
| 					if(i->type == HeroBonus::CREATURE_GROWTH && i->subtype == level) | ||||
| 						if (i->source == HeroBonus::ARTIFACT) | ||||
| 				for(std::list<Bonus>::const_iterator i=ch->bonuses.begin(); i != ch->bonuses.end(); i++) | ||||
| 					if(i->type == Bonus::CREATURE_GROWTH && i->subtype == level) | ||||
| 						if (i->source == Bonus::ARTIFACT) | ||||
| 							summ+=AddToString(CGI->arth->artifacts[i->id].Name()+" %+d",descr,i->val); | ||||
| 			}; | ||||
| 			ch = ci->town->visitingHero; | ||||
| @@ -1810,7 +1810,7 @@ void CFortScreen::draw( CCastleInterface * owner, bool first) | ||||
| 	{ | ||||
| 		bool upgraded = owner->town->creatureDwelling(i,true); | ||||
| 		bool present = owner->town->creatureDwelling(i,false); | ||||
| 		CCreature *c = &CGI->creh->creatures[upgraded ? owner->town->town->upgradedCreatures[i] : owner->town->town->basicCreatures[i]]; | ||||
| 		CCreature *c = CGI->creh->creatures[upgraded ? owner->town->town->upgradedCreatures[i] : owner->town->town->basicCreatures[i]]; | ||||
| 		printAtMiddle(c->namePl,positions[i].x+79,positions[i].y+10,FONT_SMALL,zwykly,bg); //cr. name | ||||
| 		blitAt(owner->bicons->ourImages[30+i+upgraded*7].bitmap,positions[i].x+4,positions[i].y+21,bg); //dwelling pic | ||||
| 		printAtMiddle(CGI->buildh->buildings[owner->town->subID][30+i+upgraded*7]->Name(),positions[i].x+79,positions[i].y+100,FONT_SMALL,zwykly,bg); //dwelling name | ||||
| @@ -1823,12 +1823,12 @@ void CFortScreen::draw( CCastleInterface * owner, bool first) | ||||
|  | ||||
| 		//attack | ||||
| 		printAt(CGI->generaltexth->allTexts[190],positions[i].x+288,positions[i].y+5,FONT_SMALL,zwykly,bg); | ||||
| 		SDL_itoa(c->attack,buf,10); | ||||
| 		SDL_itoa(c->Attack(),buf,10); | ||||
| 		printTo(buf,positions[i].x+381,positions[i].y+21,FONT_SMALL,zwykly,bg); | ||||
|  | ||||
| 		//defense | ||||
| 		printAt(CGI->generaltexth->allTexts[191],positions[i].x+288,positions[i].y+25,FONT_SMALL,zwykly,bg); | ||||
| 		SDL_itoa(c->defence,buf,10); | ||||
| 		SDL_itoa(c->Defense(),buf,10); | ||||
| 		printTo(buf,positions[i].x+381,positions[i].y+41,FONT_SMALL,zwykly,bg); | ||||
|  | ||||
| 		//damage | ||||
| @@ -1845,12 +1845,12 @@ void CFortScreen::draw( CCastleInterface * owner, bool first) | ||||
|  | ||||
| 		//health | ||||
| 		printAt(CGI->generaltexth->zelp[439].first,positions[i].x+288,positions[i].y+66,FONT_SMALL,zwykly,bg); | ||||
| 		SDL_itoa(c->hitPoints,buf,10); | ||||
| 		SDL_itoa(c->MaxHealth(),buf,10); | ||||
| 		printTo(buf,positions[i].x+381,positions[i].y+82,FONT_SMALL,zwykly,bg); | ||||
|  | ||||
| 		//speed | ||||
| 		printAt(CGI->generaltexth->zelp[441].first,positions[i].x+288,positions[i].y+87,FONT_SMALL,zwykly,bg); | ||||
| 		SDL_itoa(c->speed,buf,10); | ||||
| 		SDL_itoa(c->valOfBonuses(Bonus::STACKS_SPEED), buf,10); | ||||
| 		printTo(buf,positions[i].x+381,positions[i].y+103,FONT_SMALL,zwykly,bg); | ||||
|  | ||||
| 		if(present)//growth | ||||
| @@ -2016,10 +2016,10 @@ CBlacksmithDialog::CBlacksmithDialog(bool possible, int creMachineID, int aid, i | ||||
| 	blitAt(bg2,64,50,bmp); | ||||
| 	SDL_FreeSurface(bg2); | ||||
|  | ||||
| 	CCreatureAnimation cra(CGI->creh->creatures[creMachineID].animDefName); | ||||
| 	CCreatureAnimation cra(CGI->creh->creatures[creMachineID]->animDefName); | ||||
| 	cra.nextFrameMiddle(bmp,170,120,true,0,false); | ||||
| 	char pom[75]; | ||||
| 	sprintf(pom,CGI->generaltexth->allTexts[274].c_str(),CGI->creh->creatures[creMachineID].nameSing.c_str()); //build a new ... | ||||
| 	sprintf(pom,CGI->generaltexth->allTexts[274].c_str(),CGI->creh->creatures[creMachineID]->nameSing.c_str()); //build a new ... | ||||
| 	printAtMiddle(pom,165,28,FONT_MEDIUM,tytulowy,bmp); | ||||
| 	printAtMiddle(CGI->generaltexth->jktexts[43],165,218,FONT_MEDIUM,zwykly,bmp); //resource cost | ||||
| 	SDL_itoa(CGI->arth->artifacts[aid].price,pom,10); | ||||
|   | ||||
| @@ -286,7 +286,7 @@ void CHeroWindow::setHero(const CGHeroInstance *hero) | ||||
|  | ||||
| 	//setting formations | ||||
| 	formations->onChange = 0; | ||||
| 	formations->select(hero->army.formation,true); | ||||
| 	formations->select(hero->formation,true); | ||||
| 	formations->onChange = boost::bind(&CCallback::setFormation, LOCPLINT->cb, hero, _1); | ||||
|  | ||||
| 	morale->set(true, hero); | ||||
| @@ -451,8 +451,8 @@ void CHeroWindow::redrawCurBack() | ||||
| 	} | ||||
|  | ||||
| 	//morale and luck printing | ||||
| 	blitAt(graphics->luck42->ourImages[curHero->getCurrentLuck()+3].bitmap, 239, 182, curBack); | ||||
| 	blitAt(graphics->morale42->ourImages[curHero->getCurrentMorale()+3].bitmap, 181, 182, curBack); | ||||
| 	blitAt(graphics->luck42->ourImages[curHero->LuckVal()+3].bitmap, 239, 182, curBack); | ||||
| 	blitAt(graphics->morale42->ourImages[curHero->MoraleVal()+3].bitmap, 181, 182, curBack); | ||||
|  | ||||
| 	blitAt(flags->ourImages[player].bitmap, 606, 8, curBack); | ||||
|  | ||||
|   | ||||
| @@ -142,7 +142,7 @@ CKingdomInterface::CKingdomInterface() | ||||
| 				if ( obj->ID == 17 )//dwelling, text is a plural name of a creature | ||||
| 				{ | ||||
| 					objList[obj->subID].first += 1; | ||||
| 					objList[obj->subID].second = & CGI->creh->creatures[CGI->objh->cregens[obj->subID]].namePl; | ||||
| 					objList[obj->subID].second = & CGI->creh->creatures[CGI->objh->cregens[obj->subID]]->namePl; | ||||
| 				} | ||||
| 				else if (addObjects.find(curElm) != addObjects.end()) | ||||
| 				{//object from addObjects map, text is name of the object | ||||
| @@ -552,11 +552,11 @@ void CKingdomInterface::CTownItem::setTown(const CGTownInstance * newTown) | ||||
| 			crid = town->town->basicCreatures[i]; | ||||
|  | ||||
| 		std::string descr=CGI->generaltexth->allTexts[588]; | ||||
| 		boost::algorithm::replace_first(descr,"%s",CGI->creh->creatures[crid].namePl); | ||||
| 		boost::algorithm::replace_first(descr,"%s",CGI->creh->creatures[crid]->namePl); | ||||
| 		creaGrowth[i]->hoverText = descr; | ||||
|  | ||||
| 		descr=CGI->generaltexth->heroscrn[1]; | ||||
| 		boost::algorithm::replace_first(descr,"%s",CGI->creh->creatures[crid].namePl); | ||||
| 		boost::algorithm::replace_first(descr,"%s",CGI->creh->creatures[crid]->namePl); | ||||
| 		creaCount[i]->hoverText = descr; | ||||
| 		creaCount[i]->town = town; | ||||
| 	} | ||||
| @@ -910,12 +910,12 @@ void CKingdomInterface::CHeroItem::showAll(SDL_Surface * to) | ||||
| 								(i<4)?(pos.y+26):(pos.y+6),to); | ||||
| 		if (i>3) continue;//primary skills text | ||||
| 		std::ostringstream str; | ||||
| 		str << (hero->primSkills[i]); | ||||
| 		str << (hero->getPrimSkillLevel(i)); | ||||
| 		CSDL_Ext::printAtMiddle(str.str(),pos.x+94+36*i,pos.y+66,FONT_SMALL,zwykly,to); | ||||
| 	} | ||||
| 	{//luck and morale pics, experience and mana text | ||||
| 		blitAt(graphics->luck30->ourImages[hero->getCurrentLuck()+3].bitmap,pos.x+222,pos.y+30,to); | ||||
| 		blitAt(graphics->morale30->ourImages[hero->getCurrentMorale()+3].bitmap,pos.x+222,pos.y+54,to); | ||||
| 		blitAt(graphics->luck30->ourImages[hero->LuckVal()+3].bitmap,pos.x+222,pos.y+30,to); | ||||
| 		blitAt(graphics->morale30->ourImages[hero->MoraleVal()+3].bitmap,pos.x+222,pos.y+54,to); | ||||
| 		std::ostringstream str; | ||||
| 		str << (hero->exp); | ||||
| 		CSDL_Ext::printAtMiddle(str.str(),(pos.x+348),(pos.y+31),FONT_TINY,zwykly,to); | ||||
| @@ -1100,7 +1100,7 @@ void CKingdomInterface::CTownItem::CCreaPlace::clickRight(tribool down, bool pre | ||||
| 			crid = town->town->upgradedCreatures[type]; | ||||
| 		else | ||||
| 			crid = town->town->basicCreatures[type]; | ||||
| 		GH.pushInt(new CCreInfoWindow(crid, 0, town->creatures[type].first, NULL, 0, 0, NULL)); | ||||
| 		GH.pushInt(new CCreInfoWindow(crid, 0, town->creatures[type].first)); | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -436,7 +436,7 @@ void CPlayerInterface::heroInGarrisonChange(const CGTownInstance *town) | ||||
| 		c->garr->highlighted = NULL; | ||||
| 		c->hslotup.hero = town->garrisonHero; | ||||
| 		c->garr->odown = c->hslotdown.hero = town->visitingHero; | ||||
| 		c->garr->set2 = town->visitingHero ? &town->visitingHero->army : NULL; | ||||
| 		c->garr->set2 = town->visitingHero; | ||||
| 		c->garr->recreateSlots(); | ||||
| 	} | ||||
| 	GH.totalRedraw(); | ||||
| @@ -499,7 +499,7 @@ void CPlayerInterface::buildChanged(const CGTownInstance *town, int buildingID, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CPlayerInterface::battleStart(CCreatureSet *army1, CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side) //called by engine when battle starts; side=0 - left, side=1 - right | ||||
| void CPlayerInterface::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side) | ||||
| { | ||||
| 	if(LOCPLINT != this) | ||||
| 	{ //another local interface should do this | ||||
| @@ -639,7 +639,7 @@ BattleAction CPlayerInterface::activeStack(int stackID) //called when it's turn | ||||
| 		if(vstd::contains(stack->state,MOVED)) //this stack has moved and makes second action -> high morale | ||||
| 		{ | ||||
| 			std::string hlp = CGI->generaltexth->allTexts[33]; | ||||
| 			boost::algorithm::replace_first(hlp,"%s",(stack->amount != 1) ? stack->creature->namePl : stack->creature->nameSing); | ||||
| 			boost::algorithm::replace_first(hlp,"%s",(stack->count != 1) ? stack->type->namePl : stack->type->nameSing); | ||||
| 			battleInt->displayEffect(20,stack->position); | ||||
| 			battleInt->console->addText(hlp); | ||||
| 		} | ||||
| @@ -748,7 +748,7 @@ void CPlayerInterface::battleAttack(BattleAttack *ba) | ||||
| 	{ | ||||
| 		const CStack *stack = cb->battleGetStackByID(ba->stackAttacking); | ||||
| 		std::string hlp = CGI->generaltexth->allTexts[45]; | ||||
| 		boost::algorithm::replace_first(hlp,"%s",(stack->amount != 1) ? stack->creature->namePl.c_str() : stack->creature->nameSing.c_str()); | ||||
| 		boost::algorithm::replace_first(hlp,"%s",(stack->count != 1) ? stack->type->namePl.c_str() : stack->type->nameSing.c_str()); | ||||
| 		battleInt->console->addText(hlp); | ||||
| 		battleInt->displayEffect(18,stack->position); | ||||
| 	} | ||||
| @@ -926,9 +926,9 @@ void CPlayerInterface::availableCreaturesChanged( const CGDwelling *town ) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CPlayerInterface::heroBonusChanged( const CGHeroInstance *hero, const HeroBonus &bonus, bool gain ) | ||||
| void CPlayerInterface::heroBonusChanged( const CGHeroInstance *hero, const Bonus &bonus, bool gain ) | ||||
| { | ||||
| 	if(bonus.type == HeroBonus::NONE)	return; | ||||
| 	if(bonus.type == Bonus::NONE)	return; | ||||
| 	boost::unique_lock<boost::recursive_mutex> un(*pim); | ||||
| 	updateInfo(hero); | ||||
| } | ||||
| @@ -1092,7 +1092,7 @@ void CPlayerInterface::objectPropertyChanged(const SetObjectProperty * sop) | ||||
| { | ||||
| 	//redraw minimap if owner changed | ||||
| 	boost::unique_lock<boost::recursive_mutex> un(*pim); | ||||
| 	if(sop->what == 1) | ||||
| 	if(sop->what == ObjProperty::OWNER) | ||||
| 	{ | ||||
| 		const CGObjectInstance * obj = cb->getObjectInfo(sop->id); | ||||
| 		std::set<int3> pos = obj->getBlockedPos(); | ||||
| @@ -1725,7 +1725,7 @@ void CPlayerInterface::gameOver(ui8 player, bool victory ) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CPlayerInterface::playerBonusChanged( const HeroBonus &bonus, bool gain ) | ||||
| void CPlayerInterface::playerBonusChanged( const Bonus &bonus, bool gain ) | ||||
| { | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -166,8 +166,8 @@ public: | ||||
| 	void newObject(const CGObjectInstance * obj); | ||||
| 	void yourTurn(); | ||||
| 	void availableCreaturesChanged(const CGDwelling *town); | ||||
| 	void heroBonusChanged(const CGHeroInstance *hero, const HeroBonus &bonus, bool gain);//if gain hero received bonus, else he lost it | ||||
| 	void playerBonusChanged(const HeroBonus &bonus, bool gain); | ||||
| 	void heroBonusChanged(const CGHeroInstance *hero, const Bonus &bonus, bool gain);//if gain hero received bonus, else he lost it | ||||
| 	void playerBonusChanged(const Bonus &bonus, bool gain); | ||||
| 	void requestRealized(PackageApplied *pa); | ||||
| 	void heroExchangeStarted(si32 hero1, si32 hero2); | ||||
| 	void centerView (int3 pos, int focusTime); | ||||
| @@ -189,7 +189,7 @@ public: | ||||
| 	void battleSpellCast(SpellCast *sc); | ||||
| 	void battleStacksEffectsSet(SetStackEffect & sse); //called when a specific effect is set to stacks | ||||
| 	void battleStacksAttacked(std::vector<BattleStackAttacked> & bsa); | ||||
| 	void battleStart(CCreatureSet *army1, CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side); //called by engine when battle starts; side=0 - left, side=1 - right | ||||
| 	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 battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks); //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 | ||||
|   | ||||
| @@ -1995,7 +1995,7 @@ void OptionsTab::SelectedBox::clickRight( tribool down, bool previousState ) | ||||
| 		{ | ||||
| 			int c = t.basicCreatures[i]; | ||||
| 			blitAt(graphics->smallImgs[c], x, y, bmp); | ||||
| 			CSDL_Ext::printAtMiddleWB(CGI->creh->creatures[c].nameSing, x + 16, y + 45, FONT_TINY, 10, zwykly, bmp); | ||||
| 			CSDL_Ext::printAtMiddleWB(CGI->creh->creatures[c]->nameSing, x + 16, y + 45, FONT_TINY, 10, zwykly, bmp); | ||||
|  | ||||
| 			if(i == 2) | ||||
| 			{ | ||||
|   | ||||
| @@ -157,7 +157,7 @@ void CClient::run() | ||||
| 	}  | ||||
| 	catch (const std::exception& e) | ||||
| 	{	 | ||||
| 		tlog3 << "Lost connection to server, ending listening thread!\n";					 | ||||
| 		tlog3 << "Lost connection to server, ending listening thread!\n"; | ||||
| 		tlog1 << e.what() << std::endl; | ||||
| 		if(!terminate) //rethrow (-> boom!) only if closing connection was unexpected | ||||
| 		{ | ||||
|   | ||||
| @@ -45,6 +45,7 @@ | ||||
| #include "../hch/CVideoHandler.h" | ||||
| #include "../StartInfo.h" | ||||
| #include "CPreGame.h" | ||||
| #include "../lib/HeroBonus.h" | ||||
|  | ||||
| /* | ||||
|  * GUIClasses.cpp, part of VCMI engine | ||||
| @@ -68,25 +69,6 @@ CFocusable * CFocusable::inputWithFocus; | ||||
| #undef min | ||||
| #undef max | ||||
|  | ||||
| static StackState* getStackState(const CGObjectInstance *obj, int pos, bool town) | ||||
| { | ||||
| 	const CGHeroInstance *h = dynamic_cast<const CGHeroInstance *>(obj); | ||||
| 	if(!h) return NULL; | ||||
|  | ||||
| 	StackState *pom = new StackState(); | ||||
| 	pom->shotsLeft = -1; | ||||
| 	pom->healthBonus = h->valOfBonuses(HeroBonus::STACK_HEALTH); | ||||
| 	pom->currentHealth = 0; | ||||
| 	pom->attackBonus = h->getPrimSkillLevel(0); | ||||
| 	pom->defenseBonus = h->getPrimSkillLevel(1); | ||||
| 	pom->luck = h->getCurrentLuck(); | ||||
| 	pom->morale = h->getCurrentMorale(pos,town); | ||||
| 	pom->speedBonus = h->valOfBonuses(HeroBonus::STACKS_SPEED); | ||||
| 	pom->dmgMultiplier = 1; | ||||
| 	return pom; | ||||
| } | ||||
|  | ||||
|  | ||||
| void CGarrisonSlot::hover (bool on) | ||||
| { | ||||
| 	////Hoverable::hover(on); | ||||
| @@ -143,7 +125,7 @@ void CGarrisonSlot::hover (bool on) | ||||
| 			{ | ||||
| 				const CArmedInstance *highl = owner->highlighted->getObj();  | ||||
| 				if(  highl->needsLastStack()		//we are moving stack from hero's | ||||
| 				  && highl->army.slots.size() == 1	//it's only stack | ||||
| 				  && highl->stacksCount() == 1	//it's only stack | ||||
| 				  && owner->highlighted->upg != upg	//we're moving it to the other garrison | ||||
| 				  ) | ||||
| 				{ | ||||
| @@ -175,12 +157,8 @@ const CArmedInstance * CGarrisonSlot::getObj() | ||||
|  | ||||
| void CGarrisonSlot::clickRight(tribool down, bool previousState) | ||||
| { | ||||
| 	StackState *pom = getStackState(getObj(),ID, GH.topInt() == LOCPLINT->castleInt); | ||||
| 	if(down && creature) | ||||
| 	{ | ||||
| 		GH.pushInt(new CCreInfoWindow(creature->idNumber, 0, count, pom, 0, 0, NULL)); | ||||
| 	} | ||||
| 	delete pom; | ||||
| 		GH.pushInt(new CCreInfoWindow(*myStack)); | ||||
| } | ||||
| void CGarrisonSlot::clickLeft(tribool down, bool previousState) | ||||
| { | ||||
| @@ -196,7 +174,6 @@ void CGarrisonSlot::clickLeft(tribool down, bool previousState) | ||||
| 		{ | ||||
| 			if(owner->highlighted == this) //view info | ||||
| 			{ | ||||
| 				StackState *pom2 = getStackState(getObj(), ID, GH.topInt() == LOCPLINT->castleInt); | ||||
| 				UpgradeInfo pom = LOCPLINT->cb->getUpgradeInfo(getObj(), ID); | ||||
|  | ||||
| 				CCreInfoWindow *creWindow = NULL; | ||||
| @@ -204,14 +181,14 @@ void CGarrisonSlot::clickLeft(tribool down, bool previousState) | ||||
| 				{ | ||||
|  | ||||
| 					creWindow = new CCreInfoWindow( | ||||
| 						creature->idNumber, 1, count, pom2, | ||||
| 						*myStack, 1,  | ||||
| 						boost::bind(&CCallback::upgradeCreature, LOCPLINT->cb, getObj(), ID, pom.newID[0]), //bind upgrade function | ||||
| 						boost::bind(&CCallback::dismissCreature, LOCPLINT->cb, getObj(), ID), &pom); | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					creWindow = new CCreInfoWindow( | ||||
| 						creature->idNumber, 1, count, pom2, 0,  | ||||
| 						*myStack, 1, 0,  | ||||
| 						boost::bind(&CCallback::dismissCreature, LOCPLINT->cb, getObj(), ID), NULL); | ||||
| 				} | ||||
|  | ||||
| @@ -225,7 +202,6 @@ void CGarrisonSlot::clickLeft(tribool down, bool previousState) | ||||
|  | ||||
| 				show(screen2); | ||||
| 				refr = true; | ||||
| 				delete pom2; | ||||
| 			} | ||||
| 			else  | ||||
| 			{ | ||||
| @@ -250,12 +226,12 @@ void CGarrisonSlot::clickLeft(tribool down, bool previousState) | ||||
| 						int last = -1; | ||||
| 						if(upg != owner->highlighted->upg) //not splitting within same army | ||||
| 						{ | ||||
| 							if(owner->highlighted->getObj()->army.slots.size() == 1 //we're splitting away the last stack | ||||
| 							if(owner->highlighted->getObj()->stacksCount() == 1 //we're splitting away the last stack | ||||
| 								&& owner->highlighted->getObj()->needsLastStack() ) | ||||
| 							{ | ||||
| 								last = 0; | ||||
| 							} | ||||
| 							if(getObj()->army.slots.size() == 1 //destination army can't be emptied, unless we're rebalancing two stacks of same creature | ||||
| 							if(getObj()->stacksCount() == 1 //destination army can't be emptied, unless we're rebalancing two stacks of same creature | ||||
| 								&& owner->highlighted->creature == creature | ||||
| 								&& getObj()->needsLastStack() ) | ||||
| 							{ | ||||
| @@ -323,13 +299,15 @@ void CGarrisonSlot::deactivate() | ||||
| 	deactivateRClick(); | ||||
| 	deactivateHover(); | ||||
| } | ||||
| CGarrisonSlot::CGarrisonSlot(CGarrisonInt *Owner, int x, int y, int IID, int Upg, const CCreature * Creature, int Count) | ||||
| CGarrisonSlot::CGarrisonSlot(CGarrisonInt *Owner, int x, int y, int IID, int Upg, const CStackInstance * Creature) | ||||
| { | ||||
| 	//assert(Creature == CGI->creh->creatures[Creature->idNumber]); | ||||
| 	active = false; | ||||
| 	upg = Upg; | ||||
| 	count = Count; | ||||
| 	ID = IID; | ||||
| 	creature = Creature; | ||||
| 	myStack = Creature; | ||||
| 	creature = Creature ? Creature->type : NULL; | ||||
| 	count = Creature ? Creature->count : 0; | ||||
| 	pos.x = x; | ||||
| 	pos.y = y; | ||||
| 	if(Owner->smallIcons) | ||||
| @@ -487,12 +465,12 @@ void CGarrisonInt::createSlots() | ||||
| 	if(set1) | ||||
| 	{ | ||||
| 		sup = new std::vector<CGarrisonSlot*>(7,(CGarrisonSlot *)(NULL)); | ||||
| 		for(TSlots::const_iterator i=set1->slots.begin(); i!=set1->slots.end(); i++) | ||||
| 			(*sup)[i->first] =	new CGarrisonSlot(this, pos.x + (i->first*(w+interx)), pos.y, i->first, 0, i->second.type,i->second.count); | ||||
| 		for(TSlots::const_iterator i=set1->Slots().begin(); i!=set1->Slots().end(); i++) | ||||
| 			(*sup)[i->first] =	new CGarrisonSlot(this, pos.x + (i->first*(w+interx)), pos.y, i->first, 0, &i->second); | ||||
|  | ||||
| 		for(int i=0; i<sup->size(); i++) | ||||
| 			if((*sup)[i] == NULL) | ||||
| 				(*sup)[i] = new CGarrisonSlot(this, pos.x + (i*(w+interx)), pos.y,i,0,NULL, 0); | ||||
| 				(*sup)[i] = new CGarrisonSlot(this, pos.x + (i*(w+interx)), pos.y,i,0,NULL); | ||||
|  | ||||
| 		if (shiftPos) | ||||
| 			for (int i=shiftPos; i<sup->size(); i++) | ||||
| @@ -504,14 +482,14 @@ void CGarrisonInt::createSlots() | ||||
| 	if(set2) | ||||
| 	{ | ||||
| 		sdown = new std::vector<CGarrisonSlot*>(7,(CGarrisonSlot *)(NULL)); | ||||
| 		for(TSlots::const_iterator i=set2->slots.begin(); i!=set2->slots.end(); i++) | ||||
| 		for(TSlots::const_iterator i=set2->Slots().begin(); i!=set2->Slots().end(); i++) | ||||
| 		{ | ||||
| 			(*sdown)[i->first] = | ||||
| 				new CGarrisonSlot(this, pos.x + (i->first*(w+interx)) + garOffset.x, pos.y + garOffset.y,i->first,1, i->second.type,i->second.count); | ||||
| 				new CGarrisonSlot(this, pos.x + (i->first*(w+interx)) + garOffset.x, pos.y + garOffset.y,i->first,1, &i->second); | ||||
| 		} | ||||
| 		for(int i=0; i<sdown->size(); i++) | ||||
| 			if((*sdown)[i] == NULL) | ||||
| 				(*sdown)[i] = new CGarrisonSlot(this, pos.x + (i*(w+interx)) + garOffset.x,	pos.y + garOffset.y,i,1, NULL, 0); | ||||
| 				(*sdown)[i] = new CGarrisonSlot(this, pos.x + (i*(w+interx)) + garOffset.x,	pos.y + garOffset.y,i,1, NULL); | ||||
| 		if (shiftPos) | ||||
| 			for (int i=shiftPos; i<sup->size(); i++) | ||||
| 			{ | ||||
| @@ -906,7 +884,7 @@ void SComponent::init(Etype Type, int Subtype, int Val) | ||||
| 		subtitle = CGI->spellh->spells[Subtype].name; | ||||
| 		break; | ||||
| 	case creature: | ||||
| 		subtitle = boost::lexical_cast<std::string>(Val) + " " + CGI->creh->creatures[Subtype].*(Val != 1 ? &CCreature::namePl : &CCreature::nameSing); | ||||
| 		subtitle = boost::lexical_cast<std::string>(Val) + " " + CGI->creh->creatures[Subtype]->*(Val != 1 ? &CCreature::namePl : &CCreature::nameSing); | ||||
| 		break; | ||||
| 	case experience: | ||||
| 		description = CGI->generaltexth->allTexts[241]; | ||||
| @@ -1835,7 +1813,7 @@ void CRecruitmentWindow::Max() | ||||
| void CRecruitmentWindow::Buy() | ||||
| { | ||||
| 	int crid = creatures[which].ID, | ||||
| 		dstslot = dst->army.getSlotFor(crid); | ||||
| 		dstslot = dst-> getSlotFor(crid); | ||||
|  | ||||
| 	if(dstslot < 0) //no available slot | ||||
| 	{ | ||||
| @@ -1843,7 +1821,7 @@ void CRecruitmentWindow::Buy() | ||||
| 		if(dst->ID == HEROI_TYPE) | ||||
| 		{ | ||||
| 			txt = CGI->generaltexth->allTexts[425]; //The %s would join your hero, but there aren't enough provisions to support them. | ||||
| 			boost::algorithm::replace_first(txt, "%s", slider->value > 1 ? CGI->creh->creatures[crid].namePl : CGI->creh->creatures[crid].nameSing); | ||||
| 			boost::algorithm::replace_first(txt, "%s", slider->value > 1 ? CGI->creh->creatures[crid]->namePl : CGI->creh->creatures[crid]->nameSing); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| @@ -1908,7 +1886,7 @@ void CRecruitmentWindow::clickRight(tribool down, bool previousState) | ||||
| 			const int sCREATURE_WIDTH = CREATURE_WIDTH; // gcc -O0 workaround | ||||
| 			if(isItIn(&genRect(132,sCREATURE_WIDTH,pos.x+curx,pos.y+64),GH.current->motion.x,GH.current->motion.y)) | ||||
| 			{ | ||||
| 				CCreInfoWindow *popup = new CCreInfoWindow(creatures[i].ID, 0, 0, NULL, NULL, NULL, NULL); | ||||
| 				CCreInfoWindow *popup = new CCreInfoWindow(creatures[i].ID, 0, 0); | ||||
| 				GH.pushInt(popup); | ||||
| 				break; | ||||
| 			} | ||||
| @@ -1952,7 +1930,7 @@ void CRecruitmentWindow::show(SDL_Surface * to) | ||||
| 	printAtMiddle(pom,pos.x+205,pos.y+254,FONT_SMALL,zwykly,to); | ||||
| 	SDL_itoa(slider->value,pom,10); //recruit | ||||
| 	printAtMiddle(pom,pos.x+279,pos.y+254,FONT_SMALL,zwykly,to); | ||||
| 	printAtMiddle(CGI->generaltexth->allTexts[16] + " " + CGI->creh->creatures[creatures[which].ID].namePl,pos.x+243,pos.y+32,FONT_BIG,tytulowy,to); //eg "Recruit Dragon flies" | ||||
| 	printAtMiddle(CGI->generaltexth->allTexts[16] + " " + CGI->creh->creatures[creatures[which].ID]->namePl,pos.x+243,pos.y+32,FONT_BIG,tytulowy,to); //eg "Recruit Dragon flies" | ||||
|  | ||||
| 	int curx = pos.x+115-creatures[which].res.size()*16; | ||||
| 	for(int i=0;i<creatures[which].res.size();i++) | ||||
| @@ -2059,7 +2037,7 @@ void CRecruitmentWindow::initCres() | ||||
|  | ||||
| 			cur.amount = dwelling->creatures[i].first; | ||||
| 			cur.ID = dwelling->creatures[i].second[j]; | ||||
| 			const CCreature *cre = &CGI->creh->creatures[cur.ID]; | ||||
| 			const CCreature *cre = CGI->creh->creatures[cur.ID]; | ||||
| 			cur.pic = new CCreaturePic(cre); | ||||
|  | ||||
| 			for(int k=0; k<cre->cost.size(); k++) | ||||
| @@ -2105,11 +2083,11 @@ CSplitWindow::CSplitWindow(int cid, int max, CGarrisonInt *Owner, int Last, int | ||||
| 	slider = new CSlider(pos.x+21,pos.y+194,257,boost::bind(&CSplitWindow::sliderMoved,this,_1),0,sliderPositions,val,true); | ||||
| 	a1 = max-val; | ||||
| 	a2 = val; | ||||
| 	anim = new CCreaturePic(&CGI->creh->creatures[cid]); | ||||
| 	anim = new CCreaturePic(CGI->creh->creatures[cid]); | ||||
| 	anim->anim->setType(1); | ||||
|  | ||||
| 	std::string title = CGI->generaltexth->allTexts[256]; | ||||
| 	boost::algorithm::replace_first(title,"%s",CGI->creh->creatures[cid].namePl); | ||||
| 	boost::algorithm::replace_first(title,"%s",CGI->creh->creatures[cid]->namePl); | ||||
| 	printAtMiddle(title,150,34,FONT_BIG,tytulowy,bitmap); | ||||
| } | ||||
|  | ||||
| @@ -2226,7 +2204,7 @@ void CSplitWindow::clickLeft(tribool down, bool previousState) | ||||
| void CCreInfoWindow::show(SDL_Surface * to) | ||||
| { | ||||
| 	char pom[15]; | ||||
| 	blitAt(bitmap,pos.x,pos.y,to); | ||||
| 	blitAt(*bitmap,pos.x,pos.y,to); | ||||
| 	anim->blitPic(to,pos.x+21,pos.y+48,(type) && !(anf%4)); | ||||
| 	if(++anf==4)  | ||||
| 		anf=0; | ||||
| @@ -2240,130 +2218,11 @@ void CCreInfoWindow::show(SDL_Surface * to) | ||||
| 		ok->show(to); | ||||
| } | ||||
|  | ||||
| CCreInfoWindow::CCreInfoWindow(int Cid, int Type, int creatureCount, StackState *State, boost::function<void()> Upg, boost::function<void()> Dsm, UpgradeInfo *ui) | ||||
| CCreInfoWindow::CCreInfoWindow(const CStackInstance &st, int Type, boost::function<void()> Upg, boost::function<void()> Dsm, UpgradeInfo *ui) | ||||
| 	: type(Type), dsm(Dsm), dismiss(0), upgrade(0), ok(0) | ||||
| { | ||||
| 	//active = false; | ||||
| 	anf = 0; | ||||
| 	c = &CGI->creh->creatures[Cid]; | ||||
| 	SDL_Surface *hhlp = BitmapHandler::loadBitmap("CRSTKPU.bmp"); | ||||
| 	graphics->blueToPlayersAdv(hhlp,LOCPLINT->playerID); | ||||
| 	bitmap = SDL_ConvertSurface(hhlp,screen->format,0); | ||||
| 	SDL_SetColorKey(bitmap,SDL_SRCCOLORKEY,SDL_MapRGB(bitmap->format,0,255,255)); | ||||
| 	SDL_FreeSurface(hhlp); | ||||
| 	pos.x = screen->w/2 - bitmap->w/2; | ||||
| 	pos.y = screen->h/2 - bitmap->h/2; | ||||
| 	pos.w = bitmap->w; | ||||
| 	pos.h = bitmap->h; | ||||
| 	anim = new CCreaturePic(c); | ||||
| 	if(!type) anim->anim->setType(2); | ||||
|  | ||||
| 	char pom[75];int hlp=0; | ||||
|  | ||||
| 	if(creatureCount) | ||||
| 	{ | ||||
| 		SDL_itoa(creatureCount,pom,10); | ||||
| 		count = pom; | ||||
| 	} | ||||
|  | ||||
| 	printAtMiddle(c->namePl,149,30,FONT_SMALL,tytulowy,bitmap); //creature name | ||||
|  | ||||
| 	//atttack | ||||
| 	printAt(CGI->generaltexth->primarySkillNames[0],155,48,FONT_SMALL,zwykly,bitmap); | ||||
| 	SDL_itoa(c->attack,pom,10); | ||||
| 	if(State && State->attackBonus) | ||||
| 	{ | ||||
| 		int hlp; | ||||
| 		if(c->attack > 0) | ||||
| 			hlp = log10f(c->attack)+2; | ||||
| 		else | ||||
| 			hlp = 2; | ||||
| 		pom[hlp-1] = ' '; pom[hlp] = '('; | ||||
| 		SDL_itoa(c->attack+State->attackBonus,pom+hlp+1,10); | ||||
| 		hlp += 2+(int)log10f(State->attackBonus+c->attack); | ||||
| 		pom[hlp] = ')'; pom[hlp+1] = '\0'; | ||||
| 	} | ||||
| 	printTo(pom,276,61,FONT_SMALL,zwykly,bitmap); | ||||
|  | ||||
| 	//defense | ||||
| 	printAt(CGI->generaltexth->primarySkillNames[1],155,67,FONT_SMALL,zwykly,bitmap); | ||||
| 	SDL_itoa(c->defence,pom,10); | ||||
| 	if(State && State->defenseBonus) | ||||
| 	{ | ||||
| 		int hlp; | ||||
| 		if(c->defence > 0) | ||||
| 			hlp = log10f(c->defence)+2; | ||||
| 		else | ||||
| 			hlp = 2; | ||||
| 		pom[hlp-1] = ' '; pom[hlp] = '('; | ||||
| 		SDL_itoa(c->defence+State->defenseBonus,pom+hlp+1,10); | ||||
| 		hlp += 2+(int)log10f(State->defenseBonus+c->defence); | ||||
| 		pom[hlp] = ')'; pom[hlp+1] = '\0'; | ||||
| 	} | ||||
| 	printTo(pom,276,80,FONT_SMALL,zwykly,bitmap); | ||||
|  | ||||
| 	//shots | ||||
| 	if(c->shots) | ||||
| 	{ | ||||
| 		printAt(CGI->generaltexth->allTexts[198], 155, 86, FONT_SMALL, zwykly, bitmap); | ||||
| 		if(State  &&  State->shotsLeft >= 0) | ||||
| 			sprintf(pom,"%d (%d)", c->shots, State->shotsLeft); | ||||
| 		else | ||||
| 			SDL_itoa(c->shots, pom, 10); | ||||
| 		printTo(pom, 276, 99, FONT_SMALL, zwykly, bitmap); | ||||
| 	} | ||||
|  | ||||
| 	//damage | ||||
| 	int dmgMin = c->damageMin * (State ? State->dmgMultiplier : 1); | ||||
| 	int dmgMax = c->damageMax * (State ? State->dmgMultiplier : 1); | ||||
|  | ||||
| 	printAt(CGI->generaltexth->allTexts[199], 155, 105, FONT_SMALL, zwykly, bitmap); | ||||
| 	SDL_itoa(dmgMin, pom, 10); | ||||
| 	if(dmgMin > 0) | ||||
| 		hlp = log10f(dmgMin) + 2; | ||||
| 	else | ||||
| 		hlp = 2; | ||||
| 	pom[hlp-1]=' '; pom[hlp]='-'; pom[hlp+1]=' '; | ||||
| 	SDL_itoa(dmgMax, pom+hlp+2, 10); | ||||
| 	printTo(pom, 276, 118, FONT_SMALL, zwykly, bitmap); | ||||
|  | ||||
| 	//health | ||||
| 	printAt(CGI->generaltexth->allTexts[388],155,124,FONT_SMALL,zwykly,bitmap); | ||||
| 	if(State  &&  State->healthBonus) | ||||
| 		sprintf(pom,"%d (%d)",c->hitPoints, c->hitPoints + State->healthBonus); | ||||
| 	else | ||||
| 		SDL_itoa(c->hitPoints,pom,10); | ||||
| 	printTo(pom,276,137,FONT_SMALL,zwykly,bitmap); | ||||
|  | ||||
| 	//remaining health | ||||
| 	if(State && State->currentHealth) | ||||
| 	{ | ||||
| 		printAt(CGI->generaltexth->allTexts[200],155,143,FONT_SMALL,zwykly,bitmap); | ||||
| 		SDL_itoa(State->currentHealth,pom,10); | ||||
| 		printTo(pom,276,156,FONT_SMALL,zwykly,bitmap); | ||||
| 	} | ||||
|  | ||||
| 	//speed | ||||
| 	printAt(CGI->generaltexth->zelp[441].first,155,162,FONT_SMALL,zwykly,bitmap); | ||||
| 	SDL_itoa(c->speed,pom,10); | ||||
| 	if(State && State->speedBonus) | ||||
| 	{ | ||||
| 		int hlp; | ||||
| 		if(c->speed > 0) | ||||
| 			hlp = log10f(c->speed)+2; | ||||
| 		else | ||||
| 			hlp = 2; | ||||
| 		pom[hlp-1] = ' '; pom[hlp] = '('; | ||||
| 		SDL_itoa(c->speed + State->speedBonus, pom+hlp+1, 10); | ||||
| 		hlp += 2+(int)log10f(c->speed + State->speedBonus); | ||||
| 		pom[hlp] = ')'; pom[hlp+1] = '\0'; | ||||
| 	} | ||||
| 	printTo(pom,276,175,FONT_SMALL,zwykly,bitmap); | ||||
|  | ||||
|  | ||||
| 	//luck and morale | ||||
| 	blitAt(graphics->morale42->ourImages[(State)?(State->morale+3):(3)].bitmap,24,189,bitmap); | ||||
| 	blitAt(graphics->luck42->ourImages[(State)?(State->luck+3):(3)].bitmap,77,189,bitmap); | ||||
| 	OBJ_CONSTRUCTION_CAPTURING_ALL; | ||||
| 	init(st.type, &st, st.count); | ||||
|  | ||||
| 	//print abilities text - if r-click popup | ||||
| 	if(type) | ||||
| @@ -2373,9 +2232,9 @@ CCreInfoWindow::CCreInfoWindow(int Cid, int Type, int creatureCount, StackState | ||||
| 			bool enough = true; | ||||
| 			for(std::set<std::pair<int,int> >::iterator i=ui->cost[0].begin(); i!=ui->cost[0].end(); i++) //calculate upgrade cost | ||||
| 			{ | ||||
| 				if(LOCPLINT->cb->getResourceAmount(i->first) < i->second*creatureCount) | ||||
| 				if(LOCPLINT->cb->getResourceAmount(i->first) < i->second*st.count) | ||||
| 					enough = false; | ||||
| 				upgResCost.push_back(new SComponent(SComponent::resource,i->first,i->second*creatureCount));  | ||||
| 				upgResCost.push_back(new SComponent(SComponent::resource,i->first,i->second*st.count));  | ||||
| 			} | ||||
|  | ||||
| 			if(enough) | ||||
| @@ -2385,11 +2244,11 @@ CCreInfoWindow::CCreInfoWindow(int Cid, int Type, int creatureCount, StackState | ||||
| 				fs[0] += boost::bind(&CCreInfoWindow::close,this); | ||||
| 				CFunctionList<void()> cfl; | ||||
| 				cfl = boost::bind(&CPlayerInterface::showYesNoDialog,LOCPLINT,CGI->generaltexth->allTexts[207],boost::ref(upgResCost),fs[0],fs[1],false); | ||||
| 				upgrade = new AdventureMapButton("",CGI->generaltexth->zelp[446].second,cfl,pos.x+76,pos.y+237,"IVIEWCR.DEF",SDLK_u); | ||||
| 				upgrade = new AdventureMapButton("",CGI->generaltexth->zelp[446].second,cfl,76,237,"IVIEWCR.DEF",SDLK_u); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				upgrade = new AdventureMapButton("",CGI->generaltexth->zelp[446].second,boost::function<void()>(),pos.x+76,pos.y+237,"IVIEWCR.DEF"); | ||||
| 				upgrade = new AdventureMapButton("",CGI->generaltexth->zelp[446].second,boost::function<void()>(),76,237,"IVIEWCR.DEF"); | ||||
| 				upgrade->callback.funcs.clear(); | ||||
| 				upgrade->bitmapOffset = 2; | ||||
| 			} | ||||
| @@ -2403,53 +2262,124 @@ CCreInfoWindow::CCreInfoWindow(int Cid, int Type, int creatureCount, StackState | ||||
| 			fs[0] += boost::bind(&CCreInfoWindow::close,this);//close this window | ||||
| 			CFunctionList<void()> cfl; | ||||
| 			cfl = boost::bind(&CPlayerInterface::showYesNoDialog,LOCPLINT,CGI->generaltexth->allTexts[12],std::vector<SComponent*>(),fs[0],fs[1],false); | ||||
| 			dismiss = new AdventureMapButton("",CGI->generaltexth->zelp[445].second,cfl,pos.x+21,pos.y+237,"IVIEWCR2.DEF",SDLK_d); | ||||
| 			dismiss = new AdventureMapButton("",CGI->generaltexth->zelp[445].second,cfl,21,237,"IVIEWCR2.DEF",SDLK_d); | ||||
| 		} | ||||
| 		ok = new AdventureMapButton("",CGI->generaltexth->zelp[445].second,boost::bind(&CCreInfoWindow::close,this),pos.x+216,pos.y+237,"IOKAY.DEF",SDLK_RETURN); | ||||
| 		ok = new AdventureMapButton("",CGI->generaltexth->zelp[445].second,boost::bind(&CCreInfoWindow::close,this),216,237,"IOKAY.DEF",SDLK_RETURN); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		printAtWB(c->abilityText,17,231,FONT_SMALL,35,zwykly,bitmap); | ||||
| 		printAtWB(c->abilityText,17,231,FONT_SMALL,35,zwykly,*bitmap); | ||||
| 	} | ||||
|  | ||||
| 	//spell effects | ||||
| 	if(State) | ||||
| 	//if we are displying window fo r stack in battle, there are several more things that we need to display | ||||
| 	if(const CStack *battleStack = dynamic_cast<const CStack*>(&st)) | ||||
| 	{ | ||||
| 		//spell effects | ||||
| 		int printed=0; //how many effect pics have been printed | ||||
| 		for(std::set<int>::const_iterator it = State->effects.begin(); it!=State->effects.end(); ++it) | ||||
| 		BOOST_FOREACH(const CStack::StackEffect &effect, battleStack->effects) | ||||
| 		{ | ||||
| 			blitAt(graphics->spellEffectsPics->ourImages[*it + 1].bitmap, 127 + 52 * printed, 186, bitmap);  | ||||
| 			blitAt(graphics->spellEffectsPics->ourImages[effect.id + 1].bitmap, 127 + 52 * printed, 186, *bitmap);  | ||||
| 			++printed; | ||||
| 			if(printed >= 3) | ||||
| 			{ | ||||
| 			if(printed >= 3) //we can fit only 3 effects | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		//print current health | ||||
| 		printLine(5, CGI->generaltexth->allTexts[200], battleStack->firstHPleft); | ||||
| 	} | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| void CCreInfoWindow::printLine(int nr, const std::string &text, int baseVal, int val/*=-1*/, bool range/*=false*/) | ||||
| { | ||||
| 	printAt(text, 155, 48 + nr*19, FONT_SMALL, zwykly, *bitmap); | ||||
|  | ||||
| 	std::string hlp; | ||||
| 	if(range && baseVal != val) | ||||
| 		hlp = boost::str(boost::format("%d - %d") % baseVal % val); | ||||
| 	else if(baseVal != val && val>=0) | ||||
| 		hlp = boost::str(boost::format("%d (%d)") % baseVal % val); | ||||
| 	else | ||||
| 		hlp = boost::lexical_cast<std::string>(baseVal); | ||||
|  | ||||
| 	printTo(hlp, 276, 61 + nr*19, FONT_SMALL, zwykly, *bitmap); | ||||
| } | ||||
|  | ||||
| void CCreInfoWindow::init(const CCreature *cre, const CStackInstance *stack, int creatureCount) | ||||
| { | ||||
| 	const CBonusSystemNode *finalNode = NULL; | ||||
| 	if(stack) | ||||
| 		finalNode = stack; | ||||
| 	else | ||||
| 		finalNode = cre; | ||||
|  | ||||
| 	anf = 0; | ||||
| 	c = cre; | ||||
|  | ||||
| 	bitmap = new CPicture("CRSTKPU.bmp"); | ||||
| 	graphics->blueToPlayersAdv(*bitmap, LOCPLINT->playerID); | ||||
| 	bitmap->convertToScreenBPP(); | ||||
| 	pos = bitmap->center(); | ||||
|  | ||||
| 	{ | ||||
| 		BLOCK_CAPTURING; | ||||
| 		anim = new CCreaturePic(c); | ||||
| 	} | ||||
|  | ||||
| 	if(!type) anim->anim->setType(2); | ||||
|  | ||||
| 	count = boost::lexical_cast<std::string>(creatureCount); | ||||
|  | ||||
|  | ||||
| 	printAtMiddle(c->namePl,149,30,FONT_SMALL,tytulowy,*bitmap); //creature name | ||||
| 	 | ||||
| 	printLine(0, CGI->generaltexth->primarySkillNames[0], cre->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK), finalNode->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK)); | ||||
| 	printLine(1, CGI->generaltexth->primarySkillNames[0], cre->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE), finalNode->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE)); | ||||
| 	if(c->shots) | ||||
| 		printLine(2, CGI->generaltexth->allTexts[198], c->shots); | ||||
|  | ||||
| 	//TODO | ||||
| 	int dmgMultiply = 1; | ||||
| 	if(stack && stack->hasBonusOfType(Bonus::SIEGE_WEAPON)) | ||||
| 		dmgMultiply += stack->armyObj->Attack();  | ||||
|  | ||||
| 	printLine(3, CGI->generaltexth->allTexts[199], c->damageMin * dmgMultiply, c->damageMax * dmgMultiply, true); | ||||
| 	printLine(4, CGI->generaltexth->allTexts[388], cre->valOfBonuses(Bonus::STACK_HEALTH), finalNode->valOfBonuses(Bonus::STACK_HEALTH)); | ||||
| 	printLine(6, CGI->generaltexth->zelp[441].first, cre->valOfBonuses(Bonus::STACKS_SPEED), finalNode->valOfBonuses(Bonus::STACKS_SPEED)); | ||||
|  | ||||
| 	//luck and morale | ||||
| 	int luck = 3, morale = 3; | ||||
| 	if(stack) | ||||
| 	{ | ||||
| 		//add modifiers | ||||
| 		luck += stack->LuckVal(); | ||||
| 		morale += stack->MoraleVal(); | ||||
| 	} | ||||
|  | ||||
| 	blitAt(graphics->morale42->ourImages[morale].bitmap, 24, 189, *bitmap); | ||||
| 	blitAt(graphics->luck42->ourImages[luck].bitmap, 77, 189, *bitmap); | ||||
| } | ||||
|  | ||||
| CCreInfoWindow::CCreInfoWindow(int Cid, int Type, int creatureCount) | ||||
| { | ||||
| 	OBJ_CONSTRUCTION_CAPTURING_ALL; | ||||
| 	const CCreature *cre = CGI->creh->creatures[Cid]; | ||||
| 	init(cre, NULL, creatureCount); | ||||
| } | ||||
|  | ||||
| CCreInfoWindow::~CCreInfoWindow() | ||||
| { | ||||
| 	SDL_FreeSurface(bitmap); | ||||
| 	delete anim; | ||||
| 	delete upgrade; | ||||
| 	delete ok; | ||||
| 	delete dismiss; | ||||
| 	for(int i=0; i<upgResCost.size();i++) | ||||
| 		delete upgResCost[i]; | ||||
| } | ||||
|  | ||||
| void CCreInfoWindow::activate() | ||||
| { | ||||
| 	//if(active) return; | ||||
| 	//active = true; | ||||
| 	CIntObject::activate(); | ||||
| 	if(!type) | ||||
| 		activateRClick(); | ||||
| 	if(ok) | ||||
| 		ok->activate(); | ||||
| 	if(dismiss) | ||||
| 		dismiss->activate(); | ||||
| 	if(upgrade) | ||||
| 		upgrade->activate(); | ||||
| } | ||||
|  | ||||
| void CCreInfoWindow::close() | ||||
| @@ -2475,16 +2405,9 @@ void CCreInfoWindow::keyPressed (const SDL_KeyboardEvent & key) | ||||
|  | ||||
| void CCreInfoWindow::deactivate() | ||||
| { | ||||
| 	//if(!active) return; | ||||
| 	//active = false; | ||||
| 	if(!type) | ||||
| 		deactivateRClick(); | ||||
| 	if(ok) | ||||
| 		ok->deactivate(); | ||||
| 	if(dismiss) | ||||
| 		dismiss->deactivate(); | ||||
| 	if(upgrade) | ||||
| 		upgrade->deactivate(); | ||||
| 	CIntObject::deactivate(); | ||||
| } | ||||
|  | ||||
| void CLevelWindow::close() | ||||
| @@ -4511,10 +4434,10 @@ void CExchangeWindow::prepareBackground() | ||||
| 		printAtMiddle( makeNumberShort(heroInst[b]->mana), 155 + 490*b, 71, FONT_SMALL, zwykly, bg ); | ||||
|  | ||||
| 		//setting morale | ||||
| 		blitAt(graphics->morale30->ourImages[heroInst[b]->getCurrentMorale()+3].bitmap, 177 + 490*b, 45, bg); | ||||
| 		blitAt(graphics->morale30->ourImages[heroInst[b]->MoraleVal()+3].bitmap, 177 + 490*b, 45, bg); | ||||
|  | ||||
| 		//setting luck | ||||
| 		blitAt(graphics->luck30->ourImages[heroInst[b]->getCurrentLuck()+3].bitmap, 213 + 490*b, 45, bg); | ||||
| 		blitAt(graphics->luck30->ourImages[heroInst[b]->LuckVal()+3].bitmap, 213 + 490*b, 45, bg); | ||||
| 	} | ||||
|  | ||||
| 	//printing portraits | ||||
| @@ -5096,16 +5019,16 @@ CThievesGuildWindow::~CThievesGuildWindow() | ||||
|  | ||||
|  | ||||
|  | ||||
| void MoraleLuckBox::set( bool morale, const CGHeroInstance *hero, int slot /*= -1*/ ) | ||||
| void MoraleLuckBox::set(bool morale, const CGHeroInstance *hero) | ||||
| { | ||||
| 	int mrlv = -9, mrlt = -9; | ||||
| 	std::vector<std::pair<int,std::string> > mrl; | ||||
| 	TModDescr mrl; | ||||
|  | ||||
| 	if(morale) | ||||
| 	{ | ||||
| 		//setting morale | ||||
| 		mrl = hero->getCurrentMoraleModifiers(slot); | ||||
| 		mrlv = hero->getCurrentMorale(slot); | ||||
| 		hero->getModifiersWDescr(mrl, Bonus::MORALE); | ||||
| 		mrlv = hero->MoraleVal(); | ||||
| 		mrlt = (mrlv>0)-(mrlv<0); //signum: -1 - bad morale, 0 - neutral, 1 - good | ||||
| 		hoverText = CGI->generaltexth->heroscrn[4 - mrlt]; | ||||
| 		baseType = SComponent::morale; | ||||
| @@ -5121,8 +5044,8 @@ void MoraleLuckBox::set( bool morale, const CGHeroInstance *hero, int slot /*= - | ||||
| 	else | ||||
| 	{ | ||||
| 		//setting luck | ||||
| 		mrl = hero->getCurrentLuckModifiers(slot); | ||||
| 		mrlv = hero->getCurrentLuck(slot); | ||||
| 		hero->getModifiersWDescr(mrl, Bonus::LUCK); | ||||
| 		mrlv = hero->LuckVal(); | ||||
| 		mrlt = (mrlv>0)-(mrlv<0); //signum: -1 - bad luck, 0 - neutral, 1 - good | ||||
| 		hoverText = CGI->generaltexth->heroscrn[7 - mrlt]; | ||||
| 		baseType = SComponent::luck; | ||||
|   | ||||
| @@ -64,6 +64,7 @@ class CArtifactsOfHero; | ||||
| class CResDataBar; | ||||
| struct SPuzzleInfo; | ||||
| class CGGarrison; | ||||
| class CStackInstance; | ||||
|  | ||||
| extern SDL_Color tytulowy, tlo, zwykly ; | ||||
|  | ||||
| @@ -199,7 +200,8 @@ class CGarrisonSlot : public CIntObject | ||||
| { | ||||
| public: | ||||
| 	CGarrisonInt *owner; | ||||
| 	const CCreature * creature; //creature in slot | ||||
| 	const CStackInstance *myStack; //NULL if slot is empty | ||||
| 	const CCreature *creature; | ||||
| 	int count; //number of creatures | ||||
| 	int upg; //0 - up garrison, 1 - down garrison | ||||
| 	bool active; //TODO: comment me | ||||
| @@ -211,7 +213,7 @@ public: | ||||
| 	void activate(); | ||||
| 	void deactivate(); | ||||
| 	void show(SDL_Surface * to); | ||||
| 	CGarrisonSlot(CGarrisonInt *Owner, int x, int y, int IID, int Upg=0, const CCreature * Creature=NULL, int Count=0); | ||||
| 	CGarrisonSlot(CGarrisonInt *Owner, int x, int y, int IID, int Upg=0, const CStackInstance * Creature=NULL); | ||||
| 	~CGarrisonSlot(); //d-tor | ||||
| }; | ||||
|  | ||||
| @@ -700,7 +702,7 @@ class MoraleLuckBox : public LRClickableAreaWTextComp | ||||
| { | ||||
| public: | ||||
| 	 | ||||
| 	void set(bool morale, const CGHeroInstance *hero, int slot = -1); //slot -1 means only hero modifiers | ||||
| 	void set(bool morale, const CGHeroInstance *hero); | ||||
| }; | ||||
|  | ||||
| class LRClickableAreaOpenHero: public LRClickableAreaWTextComp | ||||
| @@ -725,19 +727,22 @@ class CCreInfoWindow : public CIntObject | ||||
| public: | ||||
| 	//bool active; //TODO: comment me | ||||
| 	int type;//0 - rclick popup; 1 - normal window | ||||
| 	SDL_Surface *bitmap; //background | ||||
| 	CPicture *bitmap; //background | ||||
| 	char anf; //animation counter | ||||
| 	std::string count; //creature count in text format | ||||
|  | ||||
| 	boost::function<void()> dsm; //dismiss button callback | ||||
| 	CCreaturePic *anim; //related creature's animation | ||||
| 	CCreature *c; //related creature | ||||
| 	const CCreature *c; //related creature | ||||
| 	std::vector<SComponent*> upgResCost; //cost of upgrade (if not possible then empty) | ||||
|  | ||||
| 	//MoraleLuckBox *luck, *morale; | ||||
|  | ||||
| 	AdventureMapButton *dismiss, *upgrade, *ok; | ||||
| 	CCreInfoWindow(int Cid, int Type, int creatureCount, StackState *State, boost::function<void()> Upg, boost::function<void()> Dsm, UpgradeInfo *ui); //c-tor | ||||
| 	CCreInfoWindow(const CStackInstance &st, int Type = 0, boost::function<void()> Upg = 0, boost::function<void()> Dsm = 0, UpgradeInfo *ui = NULL); //c-tor | ||||
| 	CCreInfoWindow(int Cid, int Type, int creatureCount); //c-tor | ||||
| 	void init(const CCreature *cre, const CStackInstance *stack, int creatureCount); | ||||
| 	void printLine(int nr, const std::string &text, int baseVal, int val=-1, bool range=false); | ||||
| 	~CCreInfoWindow(); //d-tor | ||||
| 	void activate(); | ||||
| 	void close(); | ||||
|   | ||||
| @@ -51,7 +51,7 @@ SDL_Surface * Graphics::drawHeroInfoWin(const InfoAboutHero &curh) | ||||
| 	blitAt(graphics->portraitLarge[curh.portrait],11,12,ret); //portrait | ||||
|  | ||||
| 	//army | ||||
| 	for (TSlots::const_iterator i = curh.army.slots.begin(); i!=curh.army.slots.end();i++) | ||||
| 	for (TSlots::const_iterator i = curh.army.Slots().begin(); i!=curh.army.Slots().end();i++) | ||||
| 	{ | ||||
| 		blitAt(graphics->smallImgs[(*i).second.type->idNumber],slotsPos[(*i).first].first+1,slotsPos[(*i).first].second+1,ret); | ||||
| 		if(curh.details) | ||||
| @@ -108,7 +108,7 @@ SDL_Surface * Graphics::drawTownInfoWin( const InfoAboutTown & curh ) | ||||
| 	int pom = curh.fortLevel - 1; if(pom<0) pom = 3; //fort pic id | ||||
| 	blitAt(forts->ourImages[pom].bitmap,115,42,ret); //fort | ||||
|  | ||||
| 	for (TSlots::const_iterator i=curh.army.slots.begin(); i!=curh.army.slots.end();i++) | ||||
| 	for (TSlots::const_iterator i=curh.army.Slots().begin(); i!=curh.army.Slots().end();i++) | ||||
| 	{ | ||||
| 		//if(!i->second.second) | ||||
| 		//	continue; | ||||
|   | ||||
| @@ -314,11 +314,11 @@ void SetHeroArtifacts::applyCl( CClient *cl ) | ||||
|  | ||||
| 	player->heroArtifactSetChanged(h); | ||||
|  | ||||
| 	BOOST_FOREACH(HeroBonus *bonus, gained) | ||||
| 	BOOST_FOREACH(Bonus *bonus, gained) | ||||
| 	{ | ||||
| 		player->heroBonusChanged(h,*bonus,true); | ||||
| 	} | ||||
| 	BOOST_FOREACH(HeroBonus *bonus, lost) | ||||
| 	BOOST_FOREACH(Bonus *bonus, lost) | ||||
| 	{ | ||||
| 		player->heroBonusChanged(h,*bonus,false); | ||||
| 	} | ||||
| @@ -427,13 +427,13 @@ void BattleStart::applyCl( CClient *cl ) | ||||
| 		def = NULL; | ||||
|  | ||||
|  | ||||
| 	new CBattleInterface(&info->army1, &info->army2, info->heroes[0], info->heroes[1], genRect(600, 800, (conf.cc.resx - 800)/2, (conf.cc.resy - 600)/2), att, def); | ||||
| 	new CBattleInterface(info->belligerents[0], info->belligerents[1], info->heroes[0], info->heroes[1], genRect(600, 800, (conf.cc.resx - 800)/2, (conf.cc.resy - 600)/2), att, def); | ||||
|  | ||||
| 	if(vstd::contains(cl->playerint,info->side1)) | ||||
| 		cl->playerint[info->side1]->battleStart(&info->army1, &info->army2, info->tile, info->heroes[0], info->heroes[1], 0); | ||||
| 		cl->playerint[info->side1]->battleStart(info->belligerents[0], info->belligerents[1], info->tile, info->heroes[0], info->heroes[1], 0); | ||||
|  | ||||
| 	if(vstd::contains(cl->playerint,info->side2)) | ||||
| 		cl->playerint[info->side2]->battleStart(&info->army1, &info->army2, info->tile, info->heroes[0], info->heroes[1], 1); | ||||
| 		cl->playerint[info->side2]->battleStart(info->belligerents[0], info->belligerents[1], info->tile, info->heroes[0], info->heroes[1], 1); | ||||
| } | ||||
|  | ||||
| void BattleNextRound::applyCl( CClient *cl ) | ||||
| @@ -448,7 +448,7 @@ void BattleSetActiveStack::applyCl( CClient *cl ) | ||||
| { | ||||
| 	CStack * activated = GS(cl)->curB->getStack(stack); | ||||
| 	int playerToCall = -1; //player that will move activated stack | ||||
| 	if( activated->hasFeatureOfType(StackFeature::HYPNOTIZED) ) | ||||
| 	if( activated->hasBonusOfType(Bonus::HYPNOTIZED) ) | ||||
| 	{ | ||||
| 		playerToCall = ( GS(cl)->curB->side1 == activated->owner ? GS(cl)->curB->side2 : GS(cl)->curB->side1 ); | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										1
									
								
								global.h
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								global.h
									
									
									
									
									
								
							| @@ -297,7 +297,6 @@ void delNull(T* &ptr) //deleted pointer and sets it to NULL | ||||
| 	ptr = NULL; | ||||
| } | ||||
|  | ||||
| #include "lib/CCreatureSet.h" | ||||
| #include "CConsoleHandler.h" | ||||
| extern DLL_EXPORT std::ostream *logfile; | ||||
| extern DLL_EXPORT CConsoleHandler *console; | ||||
|   | ||||
| @@ -318,21 +318,21 @@ void CArtHandler::sortArts() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CArtHandler::giveArtBonus( int aid, HeroBonus::BonusType type, int val, int subtype ) | ||||
| void CArtHandler::giveArtBonus( int aid, Bonus::BonusType type, int val, int subtype, int valType ) | ||||
| { | ||||
| 	artifacts[aid].bonuses.push_back(HeroBonus(HeroBonus::PERMANENT,type,HeroBonus::ARTIFACT,val,aid,subtype)); | ||||
|  | ||||
| 	if(type == HeroBonus::MORALE || HeroBonus::LUCK || HeroBonus::MORALE_AND_LUCK) | ||||
| 		artifacts[aid].bonuses.back().description = "\n" + artifacts[aid].Name()  + (val > 0 ? " +" : " ") 	 | ||||
| 													+ boost::lexical_cast<std::string>(val); | ||||
| 	Bonus added(Bonus::PERMANENT,type,Bonus::ARTIFACT,val,aid,subtype); | ||||
| 	added.valType = valType; | ||||
| 	if(type == Bonus::MORALE || Bonus::LUCK) | ||||
| 		added.description = "\n" + artifacts[aid].Name()  + (val > 0 ? " +" : " ") + boost::lexical_cast<std::string>(val); | ||||
| 	artifacts[aid].bonuses.push_back(added); | ||||
| } | ||||
|  | ||||
| void CArtHandler::addBonuses() | ||||
| { | ||||
| 	#define ART_PRIM_SKILL(ID, whichSkill, val) giveArtBonus(ID,HeroBonus::PRIMARY_SKILL,val,whichSkill) | ||||
| 	#define ART_MORALE(ID, val) giveArtBonus(ID,HeroBonus::MORALE,val) | ||||
| 	#define ART_LUCK(ID, val) giveArtBonus(ID,HeroBonus::LUCK,val) | ||||
| 	#define ART_MORALE_AND_LUCK(ID, val) giveArtBonus(ID,HeroBonus::MORALE_AND_LUCK,val) | ||||
| 	#define ART_PRIM_SKILL(ID, whichSkill, val) giveArtBonus(ID,Bonus::PRIMARY_SKILL,val,whichSkill) | ||||
| 	#define ART_MORALE(ID, val) giveArtBonus(ID,Bonus::MORALE,val) | ||||
| 	#define ART_LUCK(ID, val) giveArtBonus(ID,Bonus::LUCK,val) | ||||
| 	#define ART_MORALE_AND_LUCK(ID, val) giveArtBonus(ID,Bonus::MORALE_AND_LUCK,val) | ||||
| 	#define ART_ALL_PRIM_SKILLS(ID, val) ART_PRIM_SKILL(ID,0,val); ART_PRIM_SKILL(ID,1,val); ART_PRIM_SKILL(ID,2,val); ART_PRIM_SKILL(ID,3,val) | ||||
| 	#define ART_ATTACK_AND_DEFENSE(ID, val) ART_PRIM_SKILL(ID,0,val); ART_PRIM_SKILL(ID,1,val) | ||||
| 	#define ART_POWER_AND_KNOWLEDGE(ID, val) ART_PRIM_SKILL(ID,2,val); ART_PRIM_SKILL(ID,3,val) | ||||
| @@ -400,185 +400,187 @@ void CArtHandler::addBonuses() | ||||
| 	ART_LUCK(47,+1); //Cards of Prophecy | ||||
| 	ART_LUCK(48,+1); //Ladybird of Luck | ||||
| 	ART_MORALE(49,+1); //Badge of Courage -> +1 morale and immunity to hostile mind spells: | ||||
| 	giveArtBonus(49,HeroBonus::SPELL_IMMUNITY,50);//sorrow | ||||
| 	giveArtBonus(49,HeroBonus::SPELL_IMMUNITY,59);//berserk | ||||
| 	giveArtBonus(49,HeroBonus::SPELL_IMMUNITY,60);//hypnotize | ||||
| 	giveArtBonus(49,HeroBonus::SPELL_IMMUNITY,61);//forgetfulness | ||||
| 	giveArtBonus(49,HeroBonus::SPELL_IMMUNITY,62);//blind | ||||
| 	giveArtBonus(49,Bonus::SPELL_IMMUNITY,50);//sorrow | ||||
| 	giveArtBonus(49,Bonus::SPELL_IMMUNITY,59);//berserk | ||||
| 	giveArtBonus(49,Bonus::SPELL_IMMUNITY,60);//hypnotize | ||||
| 	giveArtBonus(49,Bonus::SPELL_IMMUNITY,61);//forgetfulness | ||||
| 	giveArtBonus(49,Bonus::SPELL_IMMUNITY,62);//blind | ||||
| 	ART_MORALE(50,+1); //Crest of Valor | ||||
| 	ART_MORALE(51,+1); //Glyph of Gallantry | ||||
|  | ||||
| 	giveArtBonus(52,HeroBonus::SIGHT_RADIOUS,+1);//Speculum | ||||
| 	giveArtBonus(53,HeroBonus::SIGHT_RADIOUS,+1);//Spyglass | ||||
| 	giveArtBonus(52,Bonus::SIGHT_RADIOUS,+1);//Speculum | ||||
| 	giveArtBonus(53,Bonus::SIGHT_RADIOUS,+1);//Spyglass | ||||
|  | ||||
| 	//necromancy bonus | ||||
| 	giveArtBonus(54,HeroBonus::SECONDARY_SKILL_PREMY,+5,12);//Amulet of the Undertaker | ||||
| 	giveArtBonus(55,HeroBonus::SECONDARY_SKILL_PREMY,+10,12);//Vampire's Cowl | ||||
| 	giveArtBonus(56,HeroBonus::SECONDARY_SKILL_PREMY,+15,12);//Dead Man's Boots | ||||
| 	giveArtBonus(54,Bonus::SECONDARY_SKILL_PREMY,+5,12);//Amulet of the Undertaker | ||||
| 	giveArtBonus(55,Bonus::SECONDARY_SKILL_PREMY,+10,12);//Vampire's Cowl | ||||
| 	giveArtBonus(56,Bonus::SECONDARY_SKILL_PREMY,+15,12);//Dead Man's Boots | ||||
|  | ||||
| 	giveArtBonus(57,HeroBonus::MAGIC_RESISTANCE,+5);//Garniture of Interference | ||||
| 	giveArtBonus(58,HeroBonus::MAGIC_RESISTANCE,+10);//Surcoat of Counterpoise | ||||
| 	giveArtBonus(59,HeroBonus::MAGIC_RESISTANCE,+15);//Boots of Polarity | ||||
| 	giveArtBonus(57,Bonus::MAGIC_RESISTANCE,+5);//Garniture of Interference | ||||
| 	giveArtBonus(58,Bonus::MAGIC_RESISTANCE,+10);//Surcoat of Counterpoise | ||||
| 	giveArtBonus(59,Bonus::MAGIC_RESISTANCE,+15);//Boots of Polarity | ||||
|  | ||||
| 	//archery bonus | ||||
| 	giveArtBonus(60,HeroBonus::SECONDARY_SKILL_PREMY,+5,1);//Bow of Elven Cherrywood | ||||
| 	giveArtBonus(61,HeroBonus::SECONDARY_SKILL_PREMY,+10,1);//Bowstring of the Unicorn's Mane | ||||
| 	giveArtBonus(62,HeroBonus::SECONDARY_SKILL_PREMY,+15,1);//Angel Feather Arrows | ||||
| 	giveArtBonus(60,Bonus::SECONDARY_SKILL_PREMY,+5,1);//Bow of Elven Cherrywood | ||||
| 	giveArtBonus(61,Bonus::SECONDARY_SKILL_PREMY,+10,1);//Bowstring of the Unicorn's Mane | ||||
| 	giveArtBonus(62,Bonus::SECONDARY_SKILL_PREMY,+15,1);//Angel Feather Arrows | ||||
|  | ||||
| 	//eagle eye bonus | ||||
| 	giveArtBonus(63,HeroBonus::SECONDARY_SKILL_PREMY,+5,11);//Bird of Perception | ||||
| 	giveArtBonus(64,HeroBonus::SECONDARY_SKILL_PREMY,+10,11);//Stoic Watchman | ||||
| 	giveArtBonus(65,HeroBonus::SECONDARY_SKILL_PREMY,+15,11);//Emblem of Cognizance | ||||
| 	giveArtBonus(63,Bonus::SECONDARY_SKILL_PREMY,+5,11);//Bird of Perception | ||||
| 	giveArtBonus(64,Bonus::SECONDARY_SKILL_PREMY,+10,11);//Stoic Watchman | ||||
| 	giveArtBonus(65,Bonus::SECONDARY_SKILL_PREMY,+15,11);//Emblem of Cognizance | ||||
|  | ||||
| 	//reducing cost of surrendering | ||||
| 	giveArtBonus(66,HeroBonus::SURRENDER_DISCOUNT,+10);//Statesman's Medal | ||||
| 	giveArtBonus(67,HeroBonus::SURRENDER_DISCOUNT,+10);//Diplomat's Ring | ||||
| 	giveArtBonus(68,HeroBonus::SURRENDER_DISCOUNT,+10);//Ambassador's Sash | ||||
| 	giveArtBonus(66,Bonus::SURRENDER_DISCOUNT,+10);//Statesman's Medal | ||||
| 	giveArtBonus(67,Bonus::SURRENDER_DISCOUNT,+10);//Diplomat's Ring | ||||
| 	giveArtBonus(68,Bonus::SURRENDER_DISCOUNT,+10);//Ambassador's Sash | ||||
|  | ||||
| 	giveArtBonus(69,HeroBonus::STACKS_SPEED,+1);//Ring of the Wayfarer | ||||
| 	giveArtBonus(69,Bonus::STACKS_SPEED,+1);//Ring of the Wayfarer | ||||
|  | ||||
| 	giveArtBonus(70,HeroBonus::LAND_MOVEMENT,+300);//Equestrian's Gloves | ||||
| 	giveArtBonus(71,HeroBonus::SEA_MOVEMENT,+1000);//Necklace of Ocean Guidance | ||||
| 	giveArtBonus(72,HeroBonus::FLYING_MOVEMENT,+1);//Angel Wings | ||||
| 	giveArtBonus(70,Bonus::LAND_MOVEMENT,+300);//Equestrian's Gloves | ||||
| 	giveArtBonus(71,Bonus::SEA_MOVEMENT,+1000);//Necklace of Ocean Guidance | ||||
| 	giveArtBonus(72,Bonus::FLYING_MOVEMENT,+1);//Angel Wings | ||||
|  | ||||
| 	giveArtBonus(73,HeroBonus::MANA_REGENERATION,+1);//Charm of Mana | ||||
| 	giveArtBonus(74,HeroBonus::MANA_REGENERATION,+2);//Talisman of Mana | ||||
| 	giveArtBonus(75,HeroBonus::MANA_REGENERATION,+3);//Mystic Orb of Mana | ||||
| 	giveArtBonus(73,Bonus::MANA_REGENERATION,+1);//Charm of Mana | ||||
| 	giveArtBonus(74,Bonus::MANA_REGENERATION,+2);//Talisman of Mana | ||||
| 	giveArtBonus(75,Bonus::MANA_REGENERATION,+3);//Mystic Orb of Mana | ||||
|  | ||||
| 	giveArtBonus(76,HeroBonus::SPELL_DURATION,+1);//Collar of Conjuring | ||||
| 	giveArtBonus(77,HeroBonus::SPELL_DURATION,+2);//Ring of Conjuring | ||||
| 	giveArtBonus(78,HeroBonus::SPELL_DURATION,+3);//Cape of Conjuring | ||||
| 	giveArtBonus(76,Bonus::SPELL_DURATION,+1);//Collar of Conjuring | ||||
| 	giveArtBonus(77,Bonus::SPELL_DURATION,+2);//Ring of Conjuring | ||||
| 	giveArtBonus(78,Bonus::SPELL_DURATION,+3);//Cape of Conjuring | ||||
|  | ||||
| 	giveArtBonus(79,HeroBonus::AIR_SPELL_DMG_PREMY,+50);//Orb of the Firmament | ||||
| 	giveArtBonus(80,HeroBonus::EARTH_SPELL_DMG_PREMY,+50);//Orb of Silt | ||||
| 	giveArtBonus(81,HeroBonus::FIRE_SPELL_DMG_PREMY,+50);//Orb of Tempestuous Fire | ||||
| 	giveArtBonus(82,HeroBonus::WATER_SPELL_DMG_PREMY,+50);//Orb of Driving Rain | ||||
| 	giveArtBonus(79,Bonus::AIR_SPELL_DMG_PREMY,+50);//Orb of the Firmament | ||||
| 	giveArtBonus(80,Bonus::EARTH_SPELL_DMG_PREMY,+50);//Orb of Silt | ||||
| 	giveArtBonus(81,Bonus::FIRE_SPELL_DMG_PREMY,+50);//Orb of Tempestuous Fire | ||||
| 	giveArtBonus(82,Bonus::WATER_SPELL_DMG_PREMY,+50);//Orb of Driving Rain | ||||
|  | ||||
| 	giveArtBonus(83,HeroBonus::BLOCK_SPELLS_ABOVE_LEVEL,3);//Recanter's Cloak | ||||
| 	giveArtBonus(84,HeroBonus::BLOCK_MORALE,0);//Spirit of Oppression | ||||
| 	giveArtBonus(85,HeroBonus::BLOCK_LUCK,0);//Hourglass of the Evil Hour | ||||
| 	giveArtBonus(83,Bonus::BLOCK_SPELLS_ABOVE_LEVEL,3);//Recanter's Cloak | ||||
| 	giveArtBonus(84,Bonus::BLOCK_MORALE,0);//Spirit of Oppression | ||||
| 	giveArtBonus(85,Bonus::BLOCK_LUCK,0);//Hourglass of the Evil Hour | ||||
|  | ||||
| 	giveArtBonus(86,HeroBonus::FIRE_SPELLS,0);//Tome of Fire Magic | ||||
| 	giveArtBonus(87,HeroBonus::AIR_SPELLS,0);//Tome of Air Magic | ||||
| 	giveArtBonus(88,HeroBonus::WATER_SPELLS,0);//Tome of Water Magic | ||||
| 	giveArtBonus(89,HeroBonus::EARTH_SPELLS,0);//Tome of Earth Magic | ||||
| 	giveArtBonus(86,Bonus::FIRE_SPELLS,0);//Tome of Fire Magic | ||||
| 	giveArtBonus(87,Bonus::AIR_SPELLS,0);//Tome of Air Magic | ||||
| 	giveArtBonus(88,Bonus::WATER_SPELLS,0);//Tome of Water Magic | ||||
| 	giveArtBonus(89,Bonus::EARTH_SPELLS,0);//Tome of Earth Magic | ||||
|  | ||||
| 	giveArtBonus(90,HeroBonus::WATER_WALKING,0);//Boots of Levitation | ||||
| 	giveArtBonus(91,HeroBonus::NO_SHOTING_PENALTY,0);//Golden Bow | ||||
| 	giveArtBonus(92,HeroBonus::SPELL_IMMUNITY,35);//Sphere of Permanence | ||||
| 	giveArtBonus(93,HeroBonus::NEGATE_ALL_NATURAL_IMMUNITIES,0);//Orb of Vulnerability | ||||
| 	giveArtBonus(90,Bonus::WATER_WALKING,0);//Boots of Levitation | ||||
| 	giveArtBonus(91,Bonus::NO_SHOTING_PENALTY,0);//Golden Bow | ||||
| 	giveArtBonus(92,Bonus::SPELL_IMMUNITY,35);//Sphere of Permanence | ||||
| 	giveArtBonus(93,Bonus::NEGATE_ALL_NATURAL_IMMUNITIES,0);//Orb of Vulnerability | ||||
|  | ||||
| 	giveArtBonus(94,HeroBonus::STACK_HEALTH,+1);//Ring of Vitality | ||||
| 	giveArtBonus(95,HeroBonus::STACK_HEALTH,+1);//Ring of Life | ||||
| 	giveArtBonus(96,HeroBonus::STACK_HEALTH,+2);//Vial of Lifeblood | ||||
| 	giveArtBonus(94,Bonus::STACK_HEALTH,+1);//Ring of Vitality | ||||
| 	giveArtBonus(95,Bonus::STACK_HEALTH,+1);//Ring of Life | ||||
| 	giveArtBonus(96,Bonus::STACK_HEALTH,+2);//Vial of Lifeblood | ||||
|  | ||||
| 	giveArtBonus(97,HeroBonus::STACKS_SPEED,+1);//Necklace of Swiftness | ||||
| 	giveArtBonus(98,HeroBonus::LAND_MOVEMENT,+600);//Boots of Speed | ||||
| 	giveArtBonus(99,HeroBonus::STACKS_SPEED,+2);//Cape of Velocity | ||||
| 	giveArtBonus(97,Bonus::STACKS_SPEED,+1);//Necklace of Swiftness | ||||
| 	giveArtBonus(98,Bonus::LAND_MOVEMENT,+600);//Boots of Speed | ||||
| 	giveArtBonus(99,Bonus::STACKS_SPEED,+2);//Cape of Velocity | ||||
|  | ||||
| 	giveArtBonus(100,HeroBonus::SPELL_IMMUNITY,59);//Pendant of Dispassion | ||||
| 	giveArtBonus(101,HeroBonus::SPELL_IMMUNITY,62);//Pendant of Second Sight | ||||
| 	giveArtBonus(102,HeroBonus::SPELL_IMMUNITY,42);//Pendant of Holiness | ||||
| 	giveArtBonus(103,HeroBonus::SPELL_IMMUNITY,24);//Pendant of Life | ||||
| 	giveArtBonus(104,HeroBonus::SPELL_IMMUNITY,25);//Pendant of Death | ||||
| 	giveArtBonus(105,HeroBonus::SPELL_IMMUNITY,60);//Pendant of Free Will | ||||
| 	giveArtBonus(106,HeroBonus::SPELL_IMMUNITY,17);//Pendant of Negativity | ||||
| 	giveArtBonus(107,HeroBonus::SPELL_IMMUNITY,61);//Pendant of Total Recall | ||||
| 	giveArtBonus(108,HeroBonus::MORALE_AND_LUCK,+3);//Pendant of Courage | ||||
| 	giveArtBonus(100,Bonus::SPELL_IMMUNITY,59);//Pendant of Dispassion | ||||
| 	giveArtBonus(101,Bonus::SPELL_IMMUNITY,62);//Pendant of Second Sight | ||||
| 	giveArtBonus(102,Bonus::SPELL_IMMUNITY,42);//Pendant of Holiness | ||||
| 	giveArtBonus(103,Bonus::SPELL_IMMUNITY,24);//Pendant of Life | ||||
| 	giveArtBonus(104,Bonus::SPELL_IMMUNITY,25);//Pendant of Death | ||||
| 	giveArtBonus(105,Bonus::SPELL_IMMUNITY,60);//Pendant of Free Will | ||||
| 	giveArtBonus(106,Bonus::SPELL_IMMUNITY,17);//Pendant of Negativity | ||||
| 	giveArtBonus(107,Bonus::SPELL_IMMUNITY,61);//Pendant of Total Recall | ||||
| 	giveArtBonus(108,Bonus::MORALE,+3);//Pendant of Courage | ||||
| 	giveArtBonus(108,Bonus::LUCK,+3);//Pendant of Courage | ||||
|  | ||||
| 	giveArtBonus(109,HeroBonus::GENERATE_RESOURCE,+1,4); //Everflowing Crystal Cloak | ||||
| 	giveArtBonus(110,HeroBonus::GENERATE_RESOURCE,+1,5); //Ring of Infinite Gems | ||||
| 	giveArtBonus(111,HeroBonus::GENERATE_RESOURCE,+1,1); //Everpouring Vial of Mercury | ||||
| 	giveArtBonus(112,HeroBonus::GENERATE_RESOURCE,+1,2); //Inexhaustible Cart of Ore | ||||
| 	giveArtBonus(113,HeroBonus::GENERATE_RESOURCE,+1,3); //Eversmoking Ring of Sulfur | ||||
| 	giveArtBonus(114,HeroBonus::GENERATE_RESOURCE,+1,0); //Inexhaustible Cart of Lumber | ||||
| 	giveArtBonus(115,HeroBonus::GENERATE_RESOURCE,+1000,6); //Endless Sack of Gold | ||||
| 	giveArtBonus(116,HeroBonus::GENERATE_RESOURCE,+750,6); //Endless Bag of Gold | ||||
| 	giveArtBonus(117,HeroBonus::GENERATE_RESOURCE,+500,6); //Endless Purse of Gold | ||||
| 	giveArtBonus(109,Bonus::GENERATE_RESOURCE,+1,4); //Everflowing Crystal Cloak | ||||
| 	giveArtBonus(110,Bonus::GENERATE_RESOURCE,+1,5); //Ring of Infinite Gems | ||||
| 	giveArtBonus(111,Bonus::GENERATE_RESOURCE,+1,1); //Everpouring Vial of Mercury | ||||
| 	giveArtBonus(112,Bonus::GENERATE_RESOURCE,+1,2); //Inexhaustible Cart of Ore | ||||
| 	giveArtBonus(113,Bonus::GENERATE_RESOURCE,+1,3); //Eversmoking Ring of Sulfur | ||||
| 	giveArtBonus(114,Bonus::GENERATE_RESOURCE,+1,0); //Inexhaustible Cart of Lumber | ||||
| 	giveArtBonus(115,Bonus::GENERATE_RESOURCE,+1000,6); //Endless Sack of Gold | ||||
| 	giveArtBonus(116,Bonus::GENERATE_RESOURCE,+750,6); //Endless Bag of Gold | ||||
| 	giveArtBonus(117,Bonus::GENERATE_RESOURCE,+500,6); //Endless Purse of Gold | ||||
|  | ||||
| 	giveArtBonus(118,HeroBonus::CREATURE_GROWTH,+5,1); //Legs of Legion | ||||
| 	giveArtBonus(119,HeroBonus::CREATURE_GROWTH,+4,2); //Loins of Legion | ||||
| 	giveArtBonus(120,HeroBonus::CREATURE_GROWTH,+3,3); //Torso of Legion | ||||
| 	giveArtBonus(121,HeroBonus::CREATURE_GROWTH,+2,4); //Arms of Legion | ||||
| 	giveArtBonus(122,HeroBonus::CREATURE_GROWTH,+1,5); //Head of Legion | ||||
| 	giveArtBonus(118,Bonus::CREATURE_GROWTH,+5,1); //Legs of Legion | ||||
| 	giveArtBonus(119,Bonus::CREATURE_GROWTH,+4,2); //Loins of Legion | ||||
| 	giveArtBonus(120,Bonus::CREATURE_GROWTH,+3,3); //Torso of Legion | ||||
| 	giveArtBonus(121,Bonus::CREATURE_GROWTH,+2,4); //Arms of Legion | ||||
| 	giveArtBonus(122,Bonus::CREATURE_GROWTH,+1,5); //Head of Legion | ||||
|  | ||||
| 	//Sea Captain's Hat  | ||||
| 	giveArtBonus(123,HeroBonus::WHIRLPOOL_PROTECTION,0);  | ||||
| 	giveArtBonus(123,HeroBonus::SEA_MOVEMENT,+500);  | ||||
| 	giveArtBonus(123,HeroBonus::SPELL,3,0);  | ||||
| 	giveArtBonus(123,HeroBonus::SPELL,3,1);  | ||||
| 	giveArtBonus(123,Bonus::WHIRLPOOL_PROTECTION,0);  | ||||
| 	giveArtBonus(123,Bonus::SEA_MOVEMENT,+500);  | ||||
| 	giveArtBonus(123,Bonus::SPELL,3,0);  | ||||
| 	giveArtBonus(123,Bonus::SPELL,3,1);  | ||||
|  | ||||
| 	giveArtBonus(124,HeroBonus::SPELLS_OF_LEVEL,3,1); //Spellbinder's Hat | ||||
| 	giveArtBonus(125,HeroBonus::ENEMY_CANT_ESCAPE,0); //Shackles of War | ||||
| 	giveArtBonus(126,HeroBonus::BLOCK_SPELLS_ABOVE_LEVEL,0);//Orb of Inhibition | ||||
| 	giveArtBonus(124,Bonus::SPELLS_OF_LEVEL,3,1); //Spellbinder's Hat | ||||
| 	giveArtBonus(125,Bonus::ENEMY_CANT_ESCAPE,0); //Shackles of War | ||||
| 	giveArtBonus(126,Bonus::BLOCK_SPELLS_ABOVE_LEVEL,0);//Orb of Inhibition | ||||
|  | ||||
| 	//Armageddon's Blade | ||||
| 	giveArtBonus(128, HeroBonus::SPELL, 3, 26); | ||||
| 	giveArtBonus(128, HeroBonus::SPELL_IMMUNITY, 26); | ||||
| 	giveArtBonus(128, Bonus::SPELL, 3, 26); | ||||
| 	giveArtBonus(128, Bonus::SPELL_IMMUNITY, 26); | ||||
| 	ART_ATTACK_AND_DEFENSE(128, +3); | ||||
| 	ART_PRIM_SKILL(128, 2, +3); | ||||
| 	ART_PRIM_SKILL(128, 3, +6); | ||||
|  | ||||
| 	//Angelic Alliance | ||||
| 	ART_ALL_PRIM_SKILLS(129, +21); | ||||
| 	giveArtBonus(129, HeroBonus::NONEVIL_ALIGNMENT_MIX, 0); | ||||
| 	giveArtBonus(129, HeroBonus::OPENING_BATTLE_SPELL, 10, 29); // Prayer | ||||
| 	giveArtBonus(129, Bonus::NONEVIL_ALIGNMENT_MIX, 0); | ||||
| 	giveArtBonus(129, Bonus::OPENING_BATTLE_SPELL, 10, 29); // Prayer | ||||
|  | ||||
| 	//Cloak of the Undead King | ||||
| 	giveArtBonus(130, HeroBonus::SECONDARY_SKILL_PREMY, +30, 12); | ||||
| 	giveArtBonus(130, HeroBonus::SECONDARY_SKILL_PREMY, +30, 12); | ||||
| 	giveArtBonus(130, HeroBonus::IMPROVED_NECROMANCY, 0); | ||||
| 	giveArtBonus(130, Bonus::SECONDARY_SKILL_PREMY, +30, 12); | ||||
| 	giveArtBonus(130, Bonus::SECONDARY_SKILL_PREMY, +30, 12); | ||||
| 	giveArtBonus(130, Bonus::IMPROVED_NECROMANCY, 0); | ||||
|  | ||||
| 	//Elixir of Life | ||||
| 	giveArtBonus(131, HeroBonus::STACK_HEALTH, +4); | ||||
| 	giveArtBonus(131, HeroBonus::STACK_HEALTH_PERCENT, +25); | ||||
| 	giveArtBonus(131, HeroBonus::HP_REGENERATION, +50); | ||||
| 	giveArtBonus(131, Bonus::STACK_HEALTH, +4); | ||||
| 	giveArtBonus(131, Bonus::STACK_HEALTH, +25, -1, Bonus::PERCENT_TO_BASE); | ||||
| 	giveArtBonus(131, Bonus::HP_REGENERATION, +50); | ||||
|  | ||||
| 	//Armor of the Damned | ||||
| 	ART_ATTACK_AND_DEFENSE(132, +3); | ||||
| 	ART_POWER_AND_KNOWLEDGE(132, +2); | ||||
| 	giveArtBonus(132, HeroBonus::OPENING_BATTLE_SPELL, 50, 54); // Slow | ||||
| 	giveArtBonus(132, HeroBonus::OPENING_BATTLE_SPELL, 50, 47); // Disrupting Ray | ||||
| 	giveArtBonus(132, HeroBonus::OPENING_BATTLE_SPELL, 50, 45); // Weakness | ||||
| 	giveArtBonus(132, HeroBonus::OPENING_BATTLE_SPELL, 50, 52); // Misfortune | ||||
| 	giveArtBonus(132, Bonus::OPENING_BATTLE_SPELL, 50, 54); // Slow | ||||
| 	giveArtBonus(132, Bonus::OPENING_BATTLE_SPELL, 50, 47); // Disrupting Ray | ||||
| 	giveArtBonus(132, Bonus::OPENING_BATTLE_SPELL, 50, 45); // Weakness | ||||
| 	giveArtBonus(132, Bonus::OPENING_BATTLE_SPELL, 50, 52); // Misfortune | ||||
|  | ||||
| 	// Statue of Legion - gives only 50% growth | ||||
| 	giveArtBonus(133, HeroBonus::CREATURE_GROWTH_PERCENT, 50); | ||||
| 	giveArtBonus(133, Bonus::CREATURE_GROWTH_PERCENT, 50); | ||||
|  | ||||
| 	//Power of the Dragon Father | ||||
| 	ART_ALL_PRIM_SKILLS(134, +16); | ||||
| 	giveArtBonus(134, HeroBonus::MORALE_AND_LUCK, +1); | ||||
| 	giveArtBonus(134, HeroBonus::LEVEL_SPELL_IMMUNITY, 4); | ||||
| 	giveArtBonus(134, Bonus::MORALE, +1); | ||||
| 	giveArtBonus(134, Bonus::LUCK, +1); | ||||
| 	giveArtBonus(134, Bonus::LEVEL_SPELL_IMMUNITY, 4); | ||||
|  | ||||
| 	//Titan's Thunder | ||||
| 	// should also add a permanent spell book, somehow. | ||||
| 	ART_ATTACK_AND_DEFENSE(135, +9); | ||||
| 	ART_POWER_AND_KNOWLEDGE(135, +8); | ||||
| 	giveArtBonus(135, HeroBonus::SPELL, 3, 57); | ||||
| 	giveArtBonus(135, Bonus::SPELL, 3, 57); | ||||
|  | ||||
| 	//Admiral's Hat | ||||
| 	giveArtBonus(136, HeroBonus::SEA_MOVEMENT, +1500); | ||||
| 	giveArtBonus(136, HeroBonus::WHIRLPOOL_PROTECTION, 0); | ||||
| 	giveArtBonus(136, HeroBonus::SPELL, 3, 0); | ||||
| 	giveArtBonus(136, HeroBonus::SPELL, 3, 1); | ||||
| 	giveArtBonus(136, HeroBonus::FREE_SHIP_BOARDING, 0); | ||||
| 	giveArtBonus(136, Bonus::SEA_MOVEMENT, +1500); | ||||
| 	giveArtBonus(136, Bonus::WHIRLPOOL_PROTECTION, 0); | ||||
| 	giveArtBonus(136, Bonus::SPELL, 3, 0); | ||||
| 	giveArtBonus(136, Bonus::SPELL, 3, 1); | ||||
| 	giveArtBonus(136, Bonus::FREE_SHIP_BOARDING, 0); | ||||
|  | ||||
| 	//Bow of the Sharpshooter | ||||
| 	giveArtBonus(137, HeroBonus::SECONDARY_SKILL_PREMY, +30, 1); | ||||
| 	giveArtBonus(137, HeroBonus::NO_SHOTING_PENALTY, 0); | ||||
| 	giveArtBonus(137, HeroBonus::FREE_SHOOTING, 0); | ||||
| 	giveArtBonus(137, Bonus::SECONDARY_SKILL_PREMY, +30, 1); | ||||
| 	giveArtBonus(137, Bonus::NO_SHOTING_PENALTY, 0); | ||||
| 	giveArtBonus(137, Bonus::FREE_SHOOTING, 0); | ||||
|  | ||||
| 	//Wizard's Well | ||||
| 	giveArtBonus(138, HeroBonus::FULL_MANA_REGENERATION, 0); | ||||
| 	giveArtBonus(138, Bonus::FULL_MANA_REGENERATION, 0); | ||||
|  | ||||
| 	//Ring of the Magi | ||||
| 	giveArtBonus(139, HeroBonus::SPELL_DURATION, +56); | ||||
| 	giveArtBonus(139, Bonus::SPELL_DURATION, +56); | ||||
|  | ||||
| 	//Cornucopia | ||||
| 	giveArtBonus(140, HeroBonus::GENERATE_RESOURCE, +5, 1); | ||||
| 	giveArtBonus(140, HeroBonus::GENERATE_RESOURCE, +5, 3); | ||||
| 	giveArtBonus(140, HeroBonus::GENERATE_RESOURCE, +5, 4); | ||||
| 	giveArtBonus(140, HeroBonus::GENERATE_RESOURCE, +5, 5); | ||||
| 	giveArtBonus(140, Bonus::GENERATE_RESOURCE, +5, 1); | ||||
| 	giveArtBonus(140, Bonus::GENERATE_RESOURCE, +5, 3); | ||||
| 	giveArtBonus(140, Bonus::GENERATE_RESOURCE, +5, 4); | ||||
| 	giveArtBonus(140, Bonus::GENERATE_RESOURCE, +5, 5); | ||||
| } | ||||
|  | ||||
| void CArtHandler::clear() | ||||
|   | ||||
| @@ -35,7 +35,7 @@ public: | ||||
| 	std::vector<ui32> * constituentOf; // Reverse map of constituents. | ||||
| 	EartClass aClass; | ||||
| 	ui32 id; | ||||
| 	std::list<HeroBonus> bonuses; //bonuses given by artifact | ||||
| 	std::list<Bonus> bonuses; //bonuses given by artifact | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| @@ -45,7 +45,7 @@ public: | ||||
|  | ||||
| class DLL_EXPORT CArtHandler //handles artifacts | ||||
| { | ||||
| 	void giveArtBonus(int aid, HeroBonus::BonusType type, int val, int subtype = -1); | ||||
| 	void giveArtBonus(int aid, Bonus::BonusType type, int val, int subtype = -1, int valType = Bonus::BASE_NUMBER); | ||||
| public: | ||||
| 	std::vector<CArtifact*> treasures, minors, majors, relics; | ||||
| 	std::vector<CArtifact> artifacts; | ||||
|   | ||||
| @@ -5,6 +5,7 @@ | ||||
| #include <sstream> | ||||
| #include <boost/assign/std/set.hpp> | ||||
| #include <boost/assign/std/vector.hpp> | ||||
| #include <boost/assign/std/list.hpp> | ||||
| #include <boost/assign/list_of.hpp> | ||||
| #include <boost/algorithm/string.hpp> | ||||
| #include <boost/algorithm/string/find.hpp> | ||||
| @@ -70,22 +71,22 @@ int CCreature::getQuantityID(const int & quantity) | ||||
|  | ||||
| bool CCreature::isDoubleWide() const | ||||
| { | ||||
| 	return vstd::contains(abilities, StackFeature::DOUBLE_WIDE); | ||||
| 	return doubleWide; | ||||
| } | ||||
|  | ||||
| bool CCreature::isFlying() const | ||||
| { | ||||
| 	return vstd::contains(abilities, StackFeature::FLYING); | ||||
| 	return vstd::contains(bonuses, Bonus::FLYING); | ||||
| } | ||||
|  | ||||
| bool CCreature::isShooting() const | ||||
| { | ||||
| 	return vstd::contains(abilities, StackFeature::SHOOTER); | ||||
| 	return vstd::contains(bonuses, Bonus::SHOOTER); | ||||
| } | ||||
|  | ||||
| bool CCreature::isUndead() const | ||||
| { | ||||
| 	return vstd::contains(abilities, StackFeature::UNDEAD); | ||||
| 	return vstd::contains(bonuses, Bonus::UNDEAD); | ||||
| } | ||||
|  | ||||
| /** | ||||
| @@ -116,6 +117,17 @@ si32 CCreature::maxAmount(const std::vector<si32> &res) const //how many creatur | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| CCreature::CCreature() | ||||
| { | ||||
| 	doubleWide = false; | ||||
| } | ||||
|  | ||||
| void CCreature::addBonus(int val, int type, int subtype /*= -1*/) | ||||
| { | ||||
| 	Bonus added(Bonus::PERMANENT, type, Bonus::CREATURE_ABILITY, val, idNumber, subtype, Bonus::BASE_NUMBER); | ||||
| 	bonuses.push_back(added); | ||||
| } | ||||
|  | ||||
| int readNumber(int & befi, int & i, int andame, std::string & buf) //helper function for void CCreatureHandler::loadCreatures() and loadUnitAnimInfo() | ||||
| { | ||||
| 	befi=i; | ||||
| @@ -199,7 +211,8 @@ void CCreatureHandler::loadCreatures() | ||||
|  | ||||
| 	while(i<buf.size()) | ||||
| 	{ | ||||
| 		CCreature ncre; | ||||
| 		CCreature &ncre = *new CCreature; | ||||
| 		ncre.idNumber = creatures.size(); | ||||
| 		ncre.cost.resize(RESOURCE_QUANTITY); | ||||
| 		ncre.level=0; | ||||
|  | ||||
| @@ -229,12 +242,18 @@ void CCreatureHandler::loadCreatures() | ||||
| 		ncre.AIValue = readNumber(befi, i, andame, buf); | ||||
| 		ncre.growth = readNumber(befi, i, andame, buf); | ||||
| 		ncre.hordeGrowth = readNumber(befi, i, andame, buf); | ||||
|  | ||||
| 		ncre.hitPoints = readNumber(befi, i, andame, buf); | ||||
| 		ncre.addBonus(ncre.hitPoints, Bonus::STACK_HEALTH); | ||||
| 		ncre.speed = readNumber(befi, i, andame, buf); | ||||
| 		ncre.addBonus(ncre.speed, Bonus::STACKS_SPEED); | ||||
| 		ncre.attack = readNumber(befi, i, andame, buf); | ||||
| 		ncre.addBonus(ncre.attack, Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK); | ||||
| 		ncre.defence = readNumber(befi, i, andame, buf); | ||||
| 		ncre.addBonus(ncre.defence, Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE); | ||||
| 		ncre.damageMin = readNumber(befi, i, andame, buf); | ||||
| 		ncre.damageMax = readNumber(befi, i, andame, buf); | ||||
|  | ||||
| 		ncre.shots = readNumber(befi, i, andame, buf); | ||||
| 		ncre.spells = readNumber(befi, i, andame, buf); | ||||
| 		ncre.ammMin = readNumber(befi, i, andame, buf); | ||||
| @@ -260,64 +279,69 @@ void CCreatureHandler::loadCreatures() | ||||
| 		if(useCreAbilsFromZCRTRAIT) | ||||
| 		{ //adding abilities from ZCRTRAIT.TXT | ||||
| 			if(boost::algorithm::find_first(ncre.abilityRefs, "DOUBLE_WIDE")) | ||||
| 				ncre.abilities.push_back(makeCreatureAbility(StackFeature::DOUBLE_WIDE, 0)); | ||||
| 				ncre.doubleWide = true; | ||||
| 			if(boost::algorithm::find_first(ncre.abilityRefs, "FLYING_ARMY")) | ||||
| 				ncre.abilities.push_back(makeCreatureAbility(StackFeature::FLYING, 0)); | ||||
| 				ncre.addBonus(0, Bonus::FLYING); | ||||
| 			if(boost::algorithm::find_first(ncre.abilityRefs, "SHOOTING_ARMY")) | ||||
| 				ncre.abilities.push_back(makeCreatureAbility(StackFeature::SHOOTER, 0)); | ||||
| 				ncre.addBonus(0, Bonus::SHOOTER); | ||||
| 			if(boost::algorithm::find_first(ncre.abilityRefs, "SIEGE_WEAPON")) | ||||
| 				ncre.abilities.push_back(makeCreatureAbility(StackFeature::SIEGE_WEAPON, 0)); | ||||
| 				ncre.addBonus(0, Bonus::SIEGE_WEAPON); | ||||
| 			if(boost::algorithm::find_first(ncre.abilityRefs, "const_two_attacks")) | ||||
| 				ncre.abilities.push_back(makeCreatureAbility(StackFeature::ADDITIONAL_ATTACK, 1)); | ||||
| 				ncre.addBonus(1, Bonus::ADDITIONAL_ATTACK); | ||||
| 			if(boost::algorithm::find_first(ncre.abilityRefs, "const_free_attack")) | ||||
| 				ncre.abilities.push_back(makeCreatureAbility(StackFeature::BLOCKS_RETALIATION, 0)); | ||||
| 				ncre.addBonus(0, Bonus::BLOCKS_RETALIATION); | ||||
| 			if(boost::algorithm::find_first(ncre.abilityRefs, "IS_UNDEAD")) | ||||
| 				ncre.abilities.push_back(makeCreatureAbility(StackFeature::UNDEAD, 0)); | ||||
| 				ncre.addBonus(0, Bonus::UNDEAD); | ||||
| 			if(boost::algorithm::find_first(ncre.abilityRefs, "const_no_melee_penalty")) | ||||
| 				ncre.abilities.push_back(makeCreatureAbility(StackFeature::NO_MELEE_PENALTY, 0)); | ||||
| 				ncre.addBonus(0, Bonus::NO_MELEE_PENALTY); | ||||
| 			if(boost::algorithm::find_first(ncre.abilityRefs, "const_jousting")) | ||||
| 				ncre.abilities.push_back(makeCreatureAbility(StackFeature::JOUSTING, 0)); | ||||
| 				ncre.addBonus(0, Bonus::JOUSTING); | ||||
| 			if(boost::algorithm::find_first(ncre.abilityRefs, "const_raises_morale")) | ||||
| 				ncre.abilities.push_back(makeCreatureAbility(StackFeature::RAISING_MORALE, 1)); | ||||
| 			{ | ||||
| 				ncre.addBonus(+1, Bonus::MORALE);; | ||||
| 				ncre.bonuses.back().effectRange = Bonus::ONLY_ALLIED_ARMY; | ||||
| 			} | ||||
| 			if(boost::algorithm::find_first(ncre.abilityRefs, "const_lowers_morale")) | ||||
| 				ncre.abilities.push_back(makeCreatureAbility(StackFeature::ENEMY_MORALE_DECREASING, 1)); | ||||
| 			{ | ||||
| 				ncre.addBonus(-1, Bonus::MORALE);; | ||||
| 				ncre.bonuses.back().effectRange = Bonus::ONLY_ENEMY_ARMY; | ||||
| 			} | ||||
| 			if(boost::algorithm::find_first(ncre.abilityRefs, "KING_1")) | ||||
| 				ncre.abilities.push_back(makeCreatureAbility(StackFeature::KING1, 0)); | ||||
| 				ncre.addBonus(0, Bonus::KING1); | ||||
| 			if(boost::algorithm::find_first(ncre.abilityRefs, "KING_2")) | ||||
| 				ncre.abilities.push_back(makeCreatureAbility(StackFeature::KING2, 0)); | ||||
| 				ncre.addBonus(0, Bonus::KING2); | ||||
| 			if(boost::algorithm::find_first(ncre.abilityRefs, "KING_3")) | ||||
| 				ncre.abilities.push_back(makeCreatureAbility(StackFeature::KING3, 0)); | ||||
| 				ncre.addBonus(0, Bonus::KING3); | ||||
| 			if(boost::algorithm::find_first(ncre.abilityRefs, "const_no_wall_penalty")) | ||||
| 				ncre.abilities.push_back(makeCreatureAbility(StackFeature::NO_WALL_PENALTY, 0)); | ||||
| 				ncre.addBonus(0, Bonus::NO_WALL_PENALTY); | ||||
| 			if(boost::algorithm::find_first(ncre.abilityRefs, "CATAPULT")) | ||||
| 				ncre.abilities.push_back(makeCreatureAbility(StackFeature::CATAPULT, 0)); | ||||
| 				ncre.addBonus(0, Bonus::CATAPULT); | ||||
| 			if(boost::algorithm::find_first(ncre.abilityRefs, "MULTI_HEADED")) | ||||
| 				ncre.abilities.push_back(makeCreatureAbility(StackFeature::ATTACKS_ALL_ADJACENT, 0)); | ||||
| 				ncre.addBonus(0, Bonus::ATTACKS_ALL_ADJACENT); | ||||
|  | ||||
| 			if(boost::algorithm::find_first(ncre.abilityRefs, "IMMUNE_TO_MIND_SPELLS")) | ||||
| 			{ | ||||
| 				std::vector<int> mindSpells = getMindSpells(); | ||||
| 				for(int g=0; g<mindSpells.size(); ++g) | ||||
| 				{ | ||||
| 					creatures[40].abilities += makeCreatureAbility(StackFeature::SPELL_IMMUNITY, 0, mindSpells[g]); //giants are immune to mind spells | ||||
| 				} | ||||
| 					ncre.addBonus(0, Bonus::SPELL_IMMUNITY, mindSpells[g]); //giants are immune to mind spells | ||||
| 			} | ||||
| 			if(boost::algorithm::find_first(ncre.abilityRefs, "IMMUNE_TO_FIRE_SPELLS")) | ||||
| 				ncre.abilities.push_back(makeCreatureAbility(StackFeature::FIRE_IMMUNITY, 0)); | ||||
| 				ncre.addBonus(0, Bonus::FIRE_IMMUNITY); | ||||
| 			if(boost::algorithm::find_first(ncre.abilityRefs, "HAS_EXTENDED_ATTACK")) | ||||
| 				ncre.abilities.push_back(makeCreatureAbility(StackFeature::TWO_HEX_ATTACK_BREATH, 0)); | ||||
| 				ncre.addBonus(0, Bonus::TWO_HEX_ATTACK_BREATH);; | ||||
| 		} | ||||
|  | ||||
| 		if(ncre.nameSing!=std::string("") && ncre.namePl!=std::string("")) | ||||
| 		{ | ||||
| 			ncre.idNumber = creatures.size(); | ||||
| 			creatures.push_back(ncre); | ||||
| 			creatures.push_back(&ncre); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Map types names | ||||
| #define VCMI_CREATURE_ABILITY_NAME(x) ( #x, StackFeature::x ) | ||||
| 	static const std::map<std::string, int> type_list = map_list_of VCMI_CREATURE_ABILITY_LIST; | ||||
| #undef VCMI_CREATURE_ABILITY_NAME | ||||
| #define BONUS_NAME(x) ( #x, Bonus::x ) | ||||
| 	static const std::map<std::string, int> type_list = map_list_of BONUS_LIST; | ||||
| #undef BONUS_NAME | ||||
|  | ||||
| 	////second part of reading cr_abils.txt//// | ||||
| 	bool contReading = true; | ||||
| @@ -332,28 +356,45 @@ void CCreatureHandler::loadCreatures() | ||||
| 		case '+': //add new ability | ||||
| 			{ | ||||
| 				int creatureID; | ||||
| 				StackFeature nsf; | ||||
| 				Bonus nsf; | ||||
| 				si32 buf; | ||||
| 				std::string type; | ||||
|  | ||||
| 				reader >> creatureID; | ||||
|  | ||||
| 				reader >> type; | ||||
|  | ||||
| 				std::map<std::string, int>::const_iterator it = type_list.find(type); | ||||
| 				if (it == type_list.end()) { | ||||
| 					tlog1 << "Error: invalid type " << type << " in cr_abils.txt" << std::endl; | ||||
| 				CCreature *cre = creatures[creatureID]; | ||||
|  | ||||
| 				if (it == type_list.end())  | ||||
| 				{ | ||||
| 					if(type == "DOUBLE_WIDE") | ||||
| 						cre->doubleWide = true; | ||||
| 					else if(type == "ENEMY_MORALE_DECREASING") | ||||
| 					{ | ||||
| 						cre->addBonus(-1, Bonus::MORALE);; | ||||
| 						cre->bonuses.back().effectRange = Bonus::ONLY_ENEMY_ARMY; | ||||
| 					} | ||||
| 					else if(type == "ENEMY_LUCK_DECREASING") | ||||
| 					{ | ||||
| 						cre->addBonus(-1, Bonus::LUCK);; | ||||
| 						cre->bonuses.back().effectRange = Bonus::ONLY_ENEMY_ARMY; | ||||
| 					} | ||||
| 					else | ||||
| 						tlog1 << "Error: invalid type " << type << " in cr_abils.txt" << std::endl; | ||||
| 					break; | ||||
| 				} | ||||
| 				nsf.type = it->second; | ||||
|  | ||||
| 				reader >> buf; nsf.value = buf; | ||||
| 				reader >> buf; nsf.val = buf; | ||||
| 				reader >> buf; nsf.subtype = buf; | ||||
| 				reader >> buf; nsf.additionalInfo = buf; | ||||
| 				nsf.source = StackFeature::CREATURE_ABILITY; | ||||
| 				nsf.duration = StackFeature::WHOLE_BATTLE; | ||||
| 				nsf.source = Bonus::CREATURE_ABILITY; | ||||
| 				nsf.id = cre->idNumber; | ||||
| 				nsf.duration = Bonus::ONE_BATTLE; | ||||
| 				nsf.turnsRemain = 0; | ||||
|  | ||||
| 				creatures[creatureID].abilities += nsf; | ||||
| 				cre->bonuses += nsf; | ||||
| 				break; | ||||
| 			} | ||||
| 		case '-': //remove ability | ||||
| @@ -365,14 +406,17 @@ void CCreatureHandler::loadCreatures() | ||||
| 				std::map<std::string, int>::const_iterator it = type_list.find(type); | ||||
| 				if (it == type_list.end()) | ||||
| 				{ | ||||
| 					tlog1 << "Error: invalid type " << type << " in cr_abils.txt" << std::endl; | ||||
| 					if(type == "DOUBLE_WIDE") | ||||
| 						creatures[creatureID]->doubleWide = false; | ||||
| 					else | ||||
| 						tlog1 << "Error: invalid type " << type << " in cr_abils.txt" << std::endl; | ||||
| 					break; | ||||
| 				} | ||||
| 				int typeNo = it->second; | ||||
|  | ||||
| 				StackFeature::ECombatFeatures ecf = static_cast<StackFeature::ECombatFeatures>(typeNo); | ||||
| 				Bonus::BonusType ecf = static_cast<Bonus::BonusType>(typeNo); | ||||
|  | ||||
| 				creatures[creatureID].abilities -= ecf; | ||||
| 				creatures[creatureID]->bonuses -= ecf; | ||||
| 				break; | ||||
| 			} | ||||
| 		case '0': //end reading | ||||
| @@ -401,7 +445,7 @@ void CCreatureHandler::loadCreatures() | ||||
| 		if (tempi>=creatures.size()) | ||||
| 			break; | ||||
| 		boost::assign::insert(nameToID)(temps,tempi); | ||||
| 		creatures[tempi].nameRef=temps; | ||||
| 		creatures[tempi]->nameRef=temps; | ||||
| 	} | ||||
| 	ifs.close(); | ||||
| 	ifs.clear(); | ||||
| @@ -417,8 +461,8 @@ void CCreatureHandler::loadCreatures() | ||||
| 			ifs >> id >> lvl; | ||||
| 			if(lvl>0) | ||||
| 			{ | ||||
| 				creatures[id].level = lvl; | ||||
| 				levelCreatures[lvl].push_back(&(creatures[id])); | ||||
| 				creatures[id]->level = lvl; | ||||
| 				levelCreatures[lvl].push_back(creatures[id]); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| @@ -431,7 +475,7 @@ void CCreatureHandler::loadCreatures() | ||||
| 	{ | ||||
| 		int id, fact; | ||||
| 		ifs >> id >> fact; | ||||
| 		creatures[id].faction = fact; | ||||
| 		creatures[id]->faction = fact; | ||||
| 	} | ||||
| 	ifs.close(); | ||||
| 	ifs.clear(); | ||||
| @@ -442,7 +486,7 @@ void CCreatureHandler::loadCreatures() | ||||
| 	{ | ||||
| 		int id, up; | ||||
| 		ifs >> id >> up; | ||||
| 		creatures[id].upgrades.insert(up); | ||||
| 		creatures[id]->upgrades.insert(up); | ||||
| 	} | ||||
| 	ifs.close(); | ||||
| 	ifs.clear(); | ||||
| @@ -489,7 +533,7 @@ void CCreatureHandler::loadCreatures() | ||||
| 				break; | ||||
| 		} | ||||
| 		std::string defName = buf.substr(befi, i-befi); | ||||
| 		creatures[s].animDefName = defName; | ||||
| 		creatures[s]->animDefName = defName; | ||||
| 	} | ||||
| 	tlog5 << "\t\tReading CRANIM.TXT.txt" << std::endl; | ||||
| 	loadAnimationInfo(); | ||||
| @@ -546,7 +590,7 @@ void CCreatureHandler::loadAnimationInfo() | ||||
| 	for(int dd=0; dd<creatures.size(); ++dd) | ||||
| 	{ | ||||
| 		//tlog5 << "\t\t\tReading animation info for creature " << dd << std::endl; | ||||
| 		loadUnitAnimInfo(creatures[dd], buf, i); | ||||
| 		loadUnitAnimInfo(*creatures[dd], buf, i); | ||||
| 	} | ||||
| 	return; | ||||
| } | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
| #include <set> | ||||
|  | ||||
| #include "CSoundBase.h" | ||||
| #include "../lib/StackFeature.h" | ||||
| #include "../lib/HeroBonus.h" | ||||
|  | ||||
| /* | ||||
|  * CCreatureHandler.h, part of VCMI engine | ||||
| @@ -20,14 +20,16 @@ | ||||
|  */ | ||||
|  | ||||
| class CLodHandler; | ||||
| class CCreatureHandler; | ||||
|  | ||||
| class DLL_EXPORT CCreature | ||||
| class DLL_EXPORT CCreature : public CBonusSystemNode | ||||
| { | ||||
| 	ui32 hitPoints, speed, attack, defence; | ||||
| public: | ||||
| 	std::string namePl, nameSing, nameRef; //name in singular and plural form; and reference name | ||||
| 	std::vector<ui32> cost; //cost[res_id] - amount of that resource | ||||
| 	std::set<ui32> upgrades; // IDs of creatures to which this creature can be upgraded | ||||
| 	ui32 fightValue, AIValue, growth, hordeGrowth, hitPoints, speed, attack, defence, shots, spells; | ||||
| 	ui32 fightValue, AIValue, growth, hordeGrowth, shots, spells; | ||||
| 	ui32 damageMin, damageMax; | ||||
| 	ui32 ammMin, ammMax; | ||||
| 	ui8 level; // 0 - unknown | ||||
| @@ -35,8 +37,8 @@ public: | ||||
| 	std::string abilityRefs; //references to abilities, in textformat | ||||
| 	std::string animDefName; | ||||
| 	ui32 idNumber; | ||||
| 	std::vector<StackFeature> abilities; | ||||
| 	si8 faction; //-1 = neutral | ||||
| 	ui8 doubleWide; | ||||
|  | ||||
| 	///animation info | ||||
| 	float timeBetweenFidgets, walkAnimationTime, attackAnimationTime, flightAnimationDistance; | ||||
| @@ -54,6 +56,8 @@ public: | ||||
| 	si32 maxAmount(const std::vector<si32> &res) const; //how many creatures can be bought | ||||
| 	static int getQuantityID(const int & quantity); //0 - a few, 1 - several, 2 - pack, 3 - lots, 4 - horde, 5 - throng, 6 - swarm, 7 - zounds, 8 - legion | ||||
|  | ||||
| 	void addBonus(int val, int type, int subtype = -1); | ||||
|  | ||||
| 	template<typename RanGen> | ||||
| 	int getRandomAmount(RanGen &ranGen) | ||||
| 	{ | ||||
| @@ -65,12 +69,13 @@ public: | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & static_cast<CBonusSystemNode&>(*this); | ||||
| 		h & namePl & nameSing & nameRef | ||||
| 			& cost & upgrades  | ||||
| 			& fightValue & AIValue & growth & hordeGrowth & hitPoints & speed & attack & defence & shots & spells | ||||
| 			& damageMin & damageMax & ammMin & ammMax & level | ||||
| 			& abilityText & abilityRefs & animDefName | ||||
| 			& idNumber & abilities & faction | ||||
| 			& idNumber & faction | ||||
|  | ||||
| 			& timeBetweenFidgets & walkAnimationTime & attackAnimationTime & flightAnimationDistance | ||||
| 			& upperRightMissleOffsetX & rightMissleOffsetX & lowerRightMissleOffsetX & upperRightMissleOffsetY & rightMissleOffsetY & lowerRightMissleOffsetY | ||||
| @@ -82,6 +87,10 @@ public: | ||||
| 			h & snd; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	CCreature(); | ||||
| 	friend CCreatureHandler; | ||||
| }; | ||||
|  | ||||
|  | ||||
| @@ -89,7 +98,7 @@ class DLL_EXPORT CCreatureHandler | ||||
| { | ||||
| public: | ||||
| 	std::set<int> notUsedMonsters; | ||||
| 	std::vector<CCreature> creatures; //creature ID -> creature info | ||||
| 	std::vector<CCreature*> creatures; //creature ID -> creature info | ||||
| 	std::map<int,std::vector<CCreature*> > levelCreatures; //level -> list of creatures | ||||
| 	std::map<std::string,int> nameToID; | ||||
| 	std::map<int,std::string> idToProjectile; | ||||
| @@ -111,14 +120,7 @@ public: | ||||
| 	{ | ||||
| 		//TODO: should be optimized, not all these informations needs to be serialized (same for ccreature) | ||||
| 		h & notUsedMonsters & creatures & nameToID & idToProjectile & idToProjectileSpin & factionToTurretCreature; | ||||
|  | ||||
| 		if(!h.saving) | ||||
| 		{ | ||||
| 			for (int i=0; i<creatures.size(); i++) //recreate levelCreatures map | ||||
| 			{ | ||||
| 				levelCreatures[creatures[i].level].push_back(&creatures[i]); | ||||
| 			} | ||||
| 		} | ||||
| 		h & levelCreatures;		 | ||||
| 	} | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -148,7 +148,7 @@ soundBase::soundID CSoundHandler::getSoundID(std::string &fileName) | ||||
| 		return it->second; | ||||
| } | ||||
|  | ||||
| void CSoundHandler::initCreaturesSounds(std::vector<CCreature> &creatures) | ||||
| void CSoundHandler::initCreaturesSounds(std::vector<CCreature*> &creatures) | ||||
| { | ||||
| 	tlog5 << "\t\tReading config/cr_sounds.txt" << std::endl; | ||||
| 	std::ifstream ifs(DATA_DIR "/config/cr_sounds.txt"); | ||||
|   | ||||
| @@ -5,6 +5,7 @@ | ||||
|  | ||||
| #include "CSoundBase.h" | ||||
| #include "CMusicBase.h" | ||||
| #include "CCreatureHandler.h" | ||||
|  | ||||
|  | ||||
| /* | ||||
| @@ -79,7 +80,7 @@ public: | ||||
| 	void init(); | ||||
| 	void release(); | ||||
|  | ||||
| 	void initCreaturesSounds(std::vector<CCreature> &creatures); | ||||
| 	void initCreaturesSounds(std::vector<CCreature*> &creatures); | ||||
| 	void initSpellsSounds(std::vector<CSpell> &spells); | ||||
| 	void setVolume(unsigned int percent); | ||||
|  | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -13,6 +13,7 @@ | ||||
| #include "CTownHandler.h" | ||||
| #include "../lib/VCMI_Lib.h" | ||||
| #endif | ||||
| #include "../lib/CCreatureSet.h" | ||||
|  | ||||
| /* | ||||
|  * CObjectHandler.h, part of VCMI engine | ||||
| @@ -24,6 +25,7 @@ | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| class BattleInfo; | ||||
| class IGameCallback; | ||||
| struct BattleResult; | ||||
| class CCPPObjectScript; | ||||
| @@ -46,6 +48,7 @@ struct Component; | ||||
| struct BankConfig; | ||||
| class CGBoat; | ||||
|  | ||||
|  | ||||
| class DLL_EXPORT CCastleEvent | ||||
| { | ||||
| public: | ||||
| @@ -141,7 +144,7 @@ class DLL_EXPORT CGObjectInstance : public IObjectInterface | ||||
| { | ||||
| protected: | ||||
| 	void getNameVis(std::string &hname) const; | ||||
| 	void giveDummyBonus(int heroID, ui8 duration = HeroBonus::ONE_DAY) const; | ||||
| 	void giveDummyBonus(int heroID, ui8 duration = Bonus::ONE_DAY) const; | ||||
| public: | ||||
| 	mutable std::string hoverName; | ||||
| 	int3 pos; //h3m pos | ||||
| @@ -216,23 +219,31 @@ public: | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| class DLL_EXPORT CArmedInstance: public CGObjectInstance | ||||
| class DLL_EXPORT CArmedInstance: public CGObjectInstance, public CBonusSystemNode, public CCreatureSet | ||||
| { | ||||
| public: | ||||
| 	CCreatureSet army; //army | ||||
| 	virtual bool needsLastStack() const; //true if last stack cannot be taken | ||||
| 	int getArmyStrength() const; //sum of AI values of creatures | ||||
| 	ui64 getPower (TSlot slot) const; //value of specific stack | ||||
| 	std::string getRoughAmount (TSlot slot) const; //rought size of specific stack | ||||
| 	BattleInfo *battle; //set to the current battle, if engaged | ||||
|  | ||||
| 	void setArmy(const CCreatureSet &src); | ||||
| 	CCreatureSet getArmy() const; | ||||
| 	void randomizeArmy(int type); | ||||
|  | ||||
| 	////////////////////////////////////////////////////////////////////////// | ||||
| 	void getParents(TCNodes &out, const CBonusSystemNode *root = NULL) const; | ||||
| 	void getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root = NULL) const; | ||||
| 	////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| 	CArmedInstance(); | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & static_cast<CGObjectInstance&>(*this); | ||||
| 		h & army; | ||||
| 		h & static_cast<CBonusSystemNode&>(*this); | ||||
| 		h & static_cast<CCreatureSet&>(*this); | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| class DLL_EXPORT CGHeroInstance : public CArmedInstance, public IBoatGenerator, public CBonusSystemNode | ||||
| class DLL_EXPORT CGHeroInstance : public CArmedInstance, public IBoatGenerator | ||||
| { | ||||
| public: | ||||
| 	////////////////////////////////////////////////////////////////////////// | ||||
| @@ -251,7 +262,6 @@ public: | ||||
| 	std::string biography; //if custom | ||||
| 	si32 portrait; //may be custom | ||||
| 	si32 mana; // remaining spell points | ||||
| 	std::vector<si32> primSkills; //0-attack, 1-defence, 2-spell power, 3-knowledge | ||||
| 	std::vector<std::pair<ui8,ui8> > secSkills; //first - ID of skill, second - level of skill (1 - basic, 2 - adv., 3 - expert); if hero has ability (-1, -1) it meansthat it should have default secondary abilities | ||||
| 	si32 movement; //remaining movement points | ||||
| 	ui8 sex; | ||||
| @@ -280,7 +290,7 @@ public: | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & static_cast<CArmedInstance&>(*this); | ||||
| 		h & exp & level & name & biography & portrait & mana & primSkills & secSkills & movement | ||||
| 		h & exp & level & name & biography & portrait & mana & secSkills & movement | ||||
| 			& sex & inTownGarrison & artifacts & artifWorn & spells & patrol & bonuses | ||||
| 			& moveDir; | ||||
|  | ||||
| @@ -288,11 +298,11 @@ public: | ||||
| 		//visitied town pointer will be restored by map serialization method | ||||
| 	} | ||||
| 	////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| 	void getParents(TCNodes &out, const CBonusSystemNode *root = NULL) const; | ||||
| 	void getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root = NULL) const; | ||||
| 	////////////////////////////////////////////////////////////////////////// | ||||
| 	int3 getSightCenter() const; //"center" tile from which the sight distance is calculated | ||||
| 	int getSightRadious() const; //sight distance (should be used if player-owned structure) | ||||
|  | ||||
|  | ||||
| 	////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| 	int getBoatType() const; //0 - evil (if a ship can be evil...?), 1 - good, 2 - neutral | ||||
| @@ -311,12 +321,9 @@ public: | ||||
| 	int getCurrentLuck(int stack=-1, bool town=false) const; | ||||
| 	int getSpellCost(const CSpell *sp) const; //do not use during battles -> bonuses from army would be ignored | ||||
|  | ||||
|  | ||||
| 	void getParents(TCNodes &out, const CBonusSystemNode *source = NULL) const; | ||||
|  | ||||
| 	std::vector<std::pair<int,std::string> > getCurrentLuckModifiers(int stack=-1, bool town=false) const; //args as above | ||||
| 	TModDescr getCurrentLuckModifiers(int stack=-1, bool town=false) const; //args as above | ||||
| 	int getCurrentMorale(int stack=-1, bool town=false) const; //if stack - position of creature, if -1 then morale for hero is calculated; town - if bonuses from town (tavern) should be considered | ||||
| 	std::vector<std::pair<int,std::string> > getCurrentMoraleModifiers(int stack=-1, bool town=false) const; //args as above | ||||
| 	TModDescr getCurrentMoraleModifiers(int stack=-1, bool town=false) const; //args as above | ||||
| 	int getPrimSkillLevel(int id) const; //0-attack, 1-defence, 2-spell power, 3-knowledge | ||||
| 	ui8 getSecSkillLevel(const int & ID) const; //0 - no skill | ||||
| 	int maxMovePoints(bool onLand) const; | ||||
| @@ -342,6 +349,7 @@ public: | ||||
| 	void recreateArtBonuses(); | ||||
| 	void giveArtifact (ui32 aid); | ||||
| 	void initHeroDefInfo(); | ||||
| 	void pushPrimSkill(int which, int val); | ||||
|  | ||||
| 	CGHeroInstance(); | ||||
| 	virtual ~CGHeroInstance(); | ||||
| @@ -472,7 +480,9 @@ public: | ||||
| 		h & town; | ||||
| 		//garrison/visiting hero pointers will be restored in the map serialization | ||||
| 	} | ||||
|  | ||||
| 	////////////////////////////////////////////////////////////////////////// | ||||
| 	void getParents(TCNodes &out, const CBonusSystemNode *root = NULL) const; | ||||
| 	void getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root = NULL) const; | ||||
| 	////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| 	ui8 getPassableness() const; //bitmap - if the bit is set the corresponding player can pass through the visitable tiles of object, even if it's blockvis; if not set - default properties from definfo are used | ||||
| @@ -541,7 +551,7 @@ public: | ||||
| 	{ | ||||
| 		h & static_cast<CArmedInstance&>(*this); | ||||
| 		h & message & gainedExp & manaDiff & moraleDiff & luckDiff & resources & primskills | ||||
| 			& abilities & abilityLevels & artifacts & spells & creatures & army; | ||||
| 			& abilities & abilityLevels & artifacts & spells & creatures; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| @@ -558,7 +568,7 @@ public: | ||||
| 		h & static_cast<CArmedInstance&>(*this); | ||||
| 		h & message & gainedExp & manaDiff & moraleDiff & luckDiff & resources & primskills | ||||
| 			& abilities & abilityLevels & artifacts & spells & creatures & availableFor  | ||||
| 			& computerActivate & humanActivate & army; | ||||
| 			& computerActivate & humanActivate; | ||||
| 	} | ||||
| 	 | ||||
| 	void onHeroVisit(const CGHeroInstance * h) const; | ||||
|   | ||||
| @@ -3,6 +3,10 @@ | ||||
| #include "../hch/CCreatureHandler.h" | ||||
| #include "VCMI_Lib.h" | ||||
| #include <assert.h> | ||||
| #include "../hch/CObjectHandler.h" | ||||
| #include "IGameCallback.h" | ||||
| #include "CGameState.h" | ||||
| #include "../hch/CGeneralTextHandler.h" | ||||
|  | ||||
| const CStackInstance CCreatureSet::operator[](TSlot slot) const | ||||
| { | ||||
| @@ -28,7 +32,7 @@ bool CCreatureSet::setCreature(TSlot slot, TCreature type, TQuantity quantity) / | ||||
| 	if (quantity == 0) | ||||
| 		slots.erase(slot); | ||||
|  | ||||
| 	if (slots.size() > 7)  | ||||
| 	if (slots.size() > ARMY_SIZE)  | ||||
| 		return false; | ||||
| 	else  | ||||
| 		return true; | ||||
| @@ -62,12 +66,12 @@ int CCreatureSet::getAmount(TSlot slot) const | ||||
| 		return 0; //TODO? consider issuing a warning | ||||
| } | ||||
|  | ||||
| bool CCreatureSet::mergableStacks(std::pair<TSlot, TSlot> &out, TSlot preferable /*= -1*/) /*looks for two same stacks, returns slot positions */ | ||||
| bool CCreatureSet::mergableStacks(std::pair<TSlot, TSlot> &out, TSlot preferable /*= -1*/) const /*looks for two same stacks, returns slot positions */ | ||||
| { | ||||
| 	//try to match creature to our preferred stack | ||||
| 	if(preferable >= 0  &&  vstd::contains(slots, preferable)) | ||||
| 	{ | ||||
| 		const CCreature *cr = slots[preferable].type; | ||||
| 		const CCreature *cr = slots.find(preferable)->second.type; | ||||
| 		for(TSlots::const_iterator j=slots.begin(); j!=slots.end(); ++j) | ||||
| 		{ | ||||
| 			if(cr == j->second.type && j->first != preferable) | ||||
| @@ -107,18 +111,24 @@ void CCreatureSet::sweep() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CCreatureSet::addToSlot(TSlot slot, TCreature cre, TQuantity count) | ||||
| void CCreatureSet::addToSlot(TSlot slot, TCreature cre, TQuantity count, bool allowMerging/* = true*/) | ||||
| { | ||||
| 	assert(slot >= 0); | ||||
| 	const CCreature *c = &VLC->creh->creatures[cre]; | ||||
| 	assert(!vstd::contains(slots, slot) || slots[slot].type == c); //that slot was empty or contained same type creature | ||||
| 	const CCreature *c = VLC->creh->creatures[cre]; | ||||
| 	assert(!vstd::contains(slots, slot) || slots[slot].type == c && allowMerging); //that slot was empty or contained same type creature | ||||
| 	slots[slot].type = c; | ||||
| 	slots[slot].count += count; | ||||
|  | ||||
| 	//TODO | ||||
| 	const CArmedInstance *armedObj = dynamic_cast<const CArmedInstance *>(this); | ||||
| 	if(armedObj && !slots[slot].armyObj) | ||||
| 		slots[slot].armyObj = armedObj; | ||||
| } | ||||
|  | ||||
| void CCreatureSet::addToSlot(TSlot slot, const CStackInstance &stack) | ||||
| void CCreatureSet::addToSlot(TSlot slot, const CStackInstance &stack, bool allowMerging/* = true*/) | ||||
| { | ||||
| 	addToSlot(slot, stack.type->idNumber, stack.count); | ||||
| 	assert(stack.type == VLC->creh->creatures[stack.type->idNumber]); | ||||
| 	addToSlot(slot, stack.type->idNumber, stack.count, allowMerging	); | ||||
| } | ||||
|  | ||||
| bool CCreatureSet::validTypes(bool allowUnrandomized /*= false*/) const | ||||
| @@ -129,7 +139,7 @@ bool CCreatureSet::validTypes(bool allowUnrandomized /*= false*/) const | ||||
| 		if(!isRand) | ||||
| 		{ | ||||
| 			assert(i->second.type); | ||||
| 			assert(i->second.type == &VLC->creh->creatures[i->second.type->idNumber]); | ||||
| 			assert(i->second.type == VLC->creh->creatures[i->second.type->idNumber]); | ||||
| 		} | ||||
| 		else | ||||
| 			assert(allowUnrandomized); | ||||
| @@ -137,16 +147,94 @@ bool CCreatureSet::validTypes(bool allowUnrandomized /*= false*/) const | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| bool CCreatureSet::slotEmpty(TSlot slot) const | ||||
| { | ||||
| 	return !vstd::contains(slots, slot); | ||||
| } | ||||
|  | ||||
| bool CCreatureSet::needsLastStack() const | ||||
| { | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| int CCreatureSet::getArmyStrength() const | ||||
| { | ||||
| 	int ret = 0; | ||||
| 	for(TSlots::const_iterator i = slots.begin(); i != slots.end(); i++) | ||||
| 		ret += i->second.type->AIValue * i->second.count; | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| ui64 CCreatureSet::getPower (TSlot slot) const | ||||
| { | ||||
| 	return getCreature(slot)->AIValue * getAmount(slot); | ||||
| } | ||||
| std::string CCreatureSet::getRoughAmount (TSlot slot) const | ||||
| { | ||||
| 	return VLC->generaltexth->arraytxt[174 + 3*CCreature::getQuantityID(getAmount(slot))]; | ||||
| } | ||||
|  | ||||
| int CCreatureSet::stacksCount() const | ||||
| { | ||||
| 	return slots.size(); | ||||
| } | ||||
|  | ||||
| void CCreatureSet::addStack(TSlot slot, const CStackInstance &stack) | ||||
| { | ||||
| 	addToSlot(slot, stack, false); | ||||
| } | ||||
|  | ||||
| void CCreatureSet::setFormation(bool tight) | ||||
| { | ||||
| 	formation = tight; | ||||
| } | ||||
|  | ||||
| void CCreatureSet::setStackCount(TSlot slot, TQuantity count) | ||||
| { | ||||
| 	assert(vstd::contains(slots, slot)); | ||||
| 	slots[slot].count = count; | ||||
| } | ||||
|  | ||||
| void CCreatureSet::clear() | ||||
| { | ||||
| 	slots.clear(); | ||||
| } | ||||
|  | ||||
| const CStackInstance& CCreatureSet::getStack(TSlot slot) const | ||||
| { | ||||
| 	assert(vstd::contains(slots, slot)); | ||||
| 	return slots.find(slot)->second; | ||||
| } | ||||
|  | ||||
| void CCreatureSet::eraseStack(TSlot slot) | ||||
| { | ||||
| 	assert(vstd::contains(slots, slot)); | ||||
| 	slots.erase(slot); | ||||
| } | ||||
|  | ||||
| bool CCreatureSet::contains(const CStackInstance *stack) const | ||||
| { | ||||
| 	if(!stack)  | ||||
| 		return false; | ||||
|  | ||||
| 	for(TSlots::const_iterator i = slots.begin(); i != slots.end(); ++i) | ||||
| 		if(&i->second == stack) | ||||
| 			return true; | ||||
|  | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| CStackInstance::CStackInstance() | ||||
| { | ||||
| 	init(); | ||||
| } | ||||
|  | ||||
| CStackInstance::CStackInstance(TCreature id, TQuantity Count) | ||||
| CStackInstance::CStackInstance(TCreature id, TQuantity Count, const CArmedInstance *ArmyObj) | ||||
| { | ||||
| 	init(); | ||||
| 	setType(id); | ||||
| 	count = Count; | ||||
| 	armyObj = ArmyObj; | ||||
| } | ||||
|  | ||||
| CStackInstance::CStackInstance(const CCreature *cre, TQuantity Count) | ||||
| @@ -162,6 +250,7 @@ void CStackInstance::init() | ||||
| 	count = 0; | ||||
| 	type = NULL; | ||||
| 	idRand = -1; | ||||
| 	armyObj = NULL; | ||||
| } | ||||
|  | ||||
| int CStackInstance::getQuantityID() const  | ||||
| @@ -171,5 +260,18 @@ int CStackInstance::getQuantityID() const | ||||
|  | ||||
| void CStackInstance::setType(int creID) | ||||
| { | ||||
| 	type = &VLC->creh->creatures[creID]; | ||||
| 	type = VLC->creh->creatures[creID]; | ||||
| } | ||||
|  | ||||
| void CStackInstance::getParents(TCNodes &out, const CBonusSystemNode *source /*= NULL*/) const | ||||
| { | ||||
| 	out.insert(type); | ||||
|  | ||||
| 	if(source && source != this) //we should be root, if not - do not inherit anything | ||||
| 		return; | ||||
|  | ||||
| 	if(armyObj) | ||||
| 		out.insert(armyObj); | ||||
| 	else | ||||
| 		out.insert(&IObjectInterface::cb->gameState()->globalEffects); | ||||
| } | ||||
| @@ -3,20 +3,26 @@ | ||||
|  | ||||
| #include "../global.h" | ||||
| #include <map> | ||||
| #include "HeroBonus.h" | ||||
|  | ||||
| class CCreature; | ||||
| class CGHeroInstance; | ||||
| class CArmedInstance; | ||||
|  | ||||
| //a few typedefs for CCreatureSet | ||||
| typedef si32 TSlot; | ||||
| typedef si32 TQuantity;  | ||||
| typedef ui32 TCreature; //creature id | ||||
|  | ||||
| const int ARMY_SIZE = 7; | ||||
|  | ||||
| class DLL_EXPORT CStackInstance | ||||
|  | ||||
| class DLL_EXPORT CStackInstance : public CBonusSystemNode | ||||
| { | ||||
| public: | ||||
| 	int idRand; //hlp variable used during loading game -> "id" placeholder for randomization | ||||
|  | ||||
| 	const CArmedInstance *armyObj; //stack must be part of some army, army must be part of some object | ||||
| 	const CCreature *type; | ||||
| 	TQuantity count; | ||||
| 	ui32 experience; //TODO: handle | ||||
| @@ -24,13 +30,17 @@ public: | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h/* & owner*/ & type & count & experience; | ||||
| 		h & static_cast<CBonusSystemNode&>(*this); | ||||
| 		h & armyObj & type & count & experience; | ||||
| 	} | ||||
|  | ||||
| 	//overrides CBonusSystemNode | ||||
| 	void getParents(TCNodes &out, const CBonusSystemNode *source = NULL) const;  //retrieves list of parent nodes (nodes to inherit bonuses from), source is the prinary asker | ||||
|  | ||||
| 	int getQuantityID() const; | ||||
| 	void init(); | ||||
| 	CStackInstance(); | ||||
| 	CStackInstance(TCreature id, TQuantity count); | ||||
| 	CStackInstance(TCreature id, TQuantity count, const CArmedInstance *ArmyObj = NULL); | ||||
| 	CStackInstance(const CCreature *cre, TQuantity count); | ||||
| 	void setType(int creID); | ||||
| }; | ||||
| @@ -38,6 +48,8 @@ public: | ||||
|  | ||||
| typedef std::map<TSlot, CStackInstance> TSlots; | ||||
|  | ||||
|  | ||||
|  | ||||
| class DLL_EXPORT CCreatureSet //seven combined creatures | ||||
| { | ||||
| public: | ||||
| @@ -46,15 +58,31 @@ public: | ||||
|  | ||||
| 	const CStackInstance operator[](TSlot slot) const;  | ||||
|  | ||||
| 	void addToSlot(TSlot slot, TCreature cre, TQuantity count); //Adds stack to slot. Slot must be empty or with same type creature | ||||
| 	void addToSlot(TSlot slot, const CStackInstance &stack); //Adds stack to slot. Slot must be empty or with same type creature | ||||
| 	const TSlots &Slots() const {return slots;} | ||||
|  | ||||
| 	void addToSlot(TSlot slot, TCreature cre, TQuantity count, bool allowMerging = true); //Adds stack to slot. Slot must be empty or with same type creature | ||||
| 	void addToSlot(TSlot slot, const CStackInstance &stack, bool allowMerging = true); //Adds stack to slot. Slot must be empty or with same type creature | ||||
| 	void addStack(TSlot slot, const CStackInstance &stack); //adds new stack to the army, slot must be empty | ||||
| 	bool setCreature (TSlot slot, TCreature type, TQuantity quantity); //slots 0 to 6, if quantity=0, erases stack | ||||
| 	void clear(); | ||||
| 	void setFormation(bool tight); | ||||
| 	void setStackCount(TSlot slot, TQuantity count); //stack must exist! | ||||
| 	void eraseStack(TSlot slot); | ||||
| 	 | ||||
| 	const CStackInstance& getStack(TSlot slot) const;  | ||||
| 	const CCreature* getCreature(TSlot slot) const; //workaround of map issue; | ||||
| 	int getAmount (TSlot slot) const; | ||||
| 	bool setCreature (TSlot slot, TCreature type, TQuantity quantity); //slots 0 to 6 | ||||
| 	TSlot getSlotFor(TCreature creature, ui32 slotsAmount=7) const; //returns -1 if no slot available | ||||
| 	bool mergableStacks(std::pair<TSlot, TSlot> &out, TSlot preferable = -1); //looks for two same stacks, returns slot positions; | ||||
| 	TSlot getSlotFor(TCreature creature, ui32 slotsAmount=ARMY_SIZE) const; //returns -1 if no slot available | ||||
| 	bool mergableStacks(std::pair<TSlot, TSlot> &out, TSlot preferable = -1) const; //looks for two same stacks, returns slot positions; | ||||
| 	bool validTypes(bool allowUnrandomized = false) const; //checks if all types of creatures are set properly | ||||
| 	bool slotEmpty(TSlot slot) const; | ||||
| 	int stacksCount() const; | ||||
| 	virtual bool needsLastStack() const; //true if last stack cannot be taken | ||||
| 	int getArmyStrength() const; //sum of AI values of creatures | ||||
| 	ui64 getPower (TSlot slot) const; //value of specific stack | ||||
| 	std::string getRoughAmount (TSlot slot) const; //rought size of specific stack | ||||
| 	 | ||||
| 	bool contains(const CStackInstance *stack) const; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
|   | ||||
| @@ -166,7 +166,7 @@ void MetaString::getLocalString(const std::pair<ui8,ui32> &txt, std::string &dst | ||||
| 	} | ||||
| 	else if(type == CRE_PL_NAMES) | ||||
| 	{ | ||||
| 		dst = VLC->creh->creatures[ser].namePl; | ||||
| 		dst = VLC->creh->creatures[ser]->namePl; | ||||
| 	} | ||||
| 	else if(type == MINE_NAMES) | ||||
| 	{ | ||||
| @@ -182,7 +182,7 @@ void MetaString::getLocalString(const std::pair<ui8,ui32> &txt, std::string &dst | ||||
| 	} | ||||
| 	else if(type == CRE_SING_NAMES) | ||||
| 	{ | ||||
| 		dst = VLC->creh->creatures[ser].nameSing; | ||||
| 		dst = VLC->creh->creatures[ser]->nameSing; | ||||
| 	} | ||||
| 	else if(type == ART_DESCR) | ||||
| 	{ | ||||
| @@ -394,8 +394,8 @@ CStack * BattleInfo::getStackT(int tileID, bool onlyAlive) | ||||
| 	for(unsigned int g=0; g<stacks.size(); ++g) | ||||
| 	{ | ||||
| 		if(stacks[g]->position == tileID  | ||||
| 			|| (stacks[g]->hasFeatureOfType(StackFeature::DOUBLE_WIDE) && stacks[g]->attackerOwned && stacks[g]->position-1 == tileID) | ||||
| 			|| (stacks[g]->hasFeatureOfType(StackFeature::DOUBLE_WIDE) && !stacks[g]->attackerOwned && stacks[g]->position+1 == tileID)) | ||||
| 			|| (stacks[g]->doubleWide() && stacks[g]->attackerOwned && stacks[g]->position-1 == tileID) | ||||
| 			|| (stacks[g]->doubleWide() && !stacks[g]->attackerOwned && stacks[g]->position+1 == tileID)) | ||||
| 		{ | ||||
| 			if(!onlyAlive || stacks[g]->alive()) | ||||
| 			{ | ||||
| @@ -428,7 +428,7 @@ void BattleInfo::getAccessibilityMap(bool *accessibility, bool twoHex, bool atta | ||||
| 			continue; | ||||
|  | ||||
| 		accessibility[stacks[g]->position] = false; | ||||
| 		if(stacks[g]->hasFeatureOfType(StackFeature::DOUBLE_WIDE)) //if it's a double hex creature | ||||
| 		if(stacks[g]->doubleWide()) //if it's a double hex creature | ||||
| 		{ | ||||
| 			if(stacks[g]->attackerOwned) | ||||
| 				accessibility[stacks[g]->position-1] = false; | ||||
| @@ -561,12 +561,12 @@ std::vector<int> BattleInfo::getAccessibility(int stackID, bool addOccupiable) c | ||||
|  | ||||
| 	std::set<int> occupyable; | ||||
|  | ||||
| 	getAccessibilityMap(ac, s->hasFeatureOfType(StackFeature::DOUBLE_WIDE), s->attackerOwned, addOccupiable, occupyable, s->hasFeatureOfType(StackFeature::FLYING), stackID); | ||||
| 	getAccessibilityMap(ac, s->doubleWide(), s->attackerOwned, addOccupiable, occupyable, s->hasBonusOfType(Bonus::FLYING), stackID); | ||||
|  | ||||
| 	int pr[BFIELD_SIZE], dist[BFIELD_SIZE]; | ||||
| 	makeBFS(s->position, ac, pr, dist, s->hasFeatureOfType(StackFeature::DOUBLE_WIDE), s->attackerOwned, s->hasFeatureOfType(StackFeature::FLYING), false); | ||||
| 	makeBFS(s->position, ac, pr, dist, s->doubleWide(), s->attackerOwned, s->hasBonusOfType(Bonus::FLYING), false); | ||||
|  | ||||
| 	if(s->hasFeatureOfType(StackFeature::DOUBLE_WIDE)) | ||||
| 	if(s->doubleWide()) | ||||
| 	{ | ||||
| 		if(!addOccupiable) | ||||
| 		{ | ||||
| @@ -597,7 +597,7 @@ std::vector<int> BattleInfo::getAccessibility(int stackID, bool addOccupiable) c | ||||
| 	 | ||||
| 	for (int i=0; i < BFIELD_SIZE ; ++i) { | ||||
| 		if( | ||||
| 			( ( !addOccupiable && dist[i] <= s->Speed() && ac[i] ) || ( addOccupiable && dist[i] <= s->Speed() && isAccessible(i, ac, s->hasFeatureOfType(StackFeature::DOUBLE_WIDE), s->attackerOwned, s->hasFeatureOfType(StackFeature::FLYING), true) ) )//we can reach it | ||||
| 			( ( !addOccupiable && dist[i] <= s->Speed() && ac[i] ) || ( addOccupiable && dist[i] <= s->Speed() && isAccessible(i, ac, s->doubleWide(), s->attackerOwned, s->hasBonusOfType(Bonus::FLYING), true) ) )//we can reach it | ||||
| 			|| (vstd::contains(occupyable, i) && ( dist[ i + (s->attackerOwned ? 1 : -1 ) ] <= s->Speed() ) && | ||||
| 				ac[i + (s->attackerOwned ? 1 : -1 )] ) //it's occupyable and we can reach adjacent hex | ||||
| 			) | ||||
| @@ -611,7 +611,7 @@ std::vector<int> BattleInfo::getAccessibility(int stackID, bool addOccupiable) c | ||||
| bool BattleInfo::isStackBlocked(int ID) | ||||
| { | ||||
| 	CStack *our = getStack(ID); | ||||
| 	if(our->hasFeatureOfType(StackFeature::SIEGE_WEAPON)) //siege weapons cannot be blocked | ||||
| 	if(our->hasBonusOfType(Bonus::SIEGE_WEAPON)) //siege weapons cannot be blocked | ||||
| 		return false; | ||||
|  | ||||
| 	for(unsigned int i=0; i<stacks.size();i++) | ||||
| @@ -620,7 +620,7 @@ bool BattleInfo::isStackBlocked(int ID) | ||||
| 			|| stacks[i]->owner==our->owner | ||||
| 		  ) | ||||
| 			continue; //we omit dead and allied stacks | ||||
| 		if(stacks[i]->hasFeatureOfType(StackFeature::DOUBLE_WIDE)) | ||||
| 		if(stacks[i]->doubleWide()) | ||||
| 		{ | ||||
| 			if( mutualPosition(stacks[i]->position, our->position) >= 0   | ||||
| 			  || mutualPosition(stacks[i]->position + (stacks[i]->attackerOwned ? -1 : 1), our->position) >= 0) | ||||
| @@ -689,72 +689,32 @@ std::pair< std::vector<int>, int > BattleInfo::getPath(int start, int dest, bool | ||||
| 	return std::make_pair(path, dist[dest]); | ||||
| } | ||||
|  | ||||
| int CStack::valOfFeatures(StackFeature::ECombatFeatures type, int subtype, int turn) const | ||||
| CStack::CStack(const CStackInstance *base, int O, int I, bool AO, int S) | ||||
| 	: CStackInstance(*base), ID(I), owner(O), slot(S), attackerOwned(AO), position(-1),    | ||||
| 	counterAttacks(1) | ||||
| { | ||||
| 	int ret = 0; | ||||
| 	if(subtype == -1024) //any subtype | ||||
| 	{ | ||||
| 		for(std::vector<StackFeature>::const_iterator i=features.begin(); i != features.end(); i++) | ||||
| 			if(i->type == type	&&  (!turn || i->turnsRemain > turn)) | ||||
| 				ret += i->value; | ||||
| 	} | ||||
| 	else //given subtype | ||||
| 	{ | ||||
| 		for(std::vector<StackFeature>::const_iterator i=features.begin(); i != features.end(); i++) | ||||
| 			if(i->type == type && i->subtype == subtype && (!turn || i->turnsRemain > turn)) | ||||
| 				ret += i->value; | ||||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
| 	baseAmount = base->count; | ||||
| 	firstHPleft = valOfBonuses(Bonus::STACK_HEALTH); | ||||
| 	shots = type->shots; | ||||
| 	counterAttacks += valOfBonuses(Bonus::ADDITIONAL_RETALIATION); | ||||
|  | ||||
| bool CStack::hasFeatureOfType(StackFeature::ECombatFeatures type, int subtype, int turn) const | ||||
| { | ||||
| 	if(subtype == -1024) //any subtype | ||||
| 	{ | ||||
| 		for(std::vector<StackFeature>::const_iterator i=features.begin(); i != features.end(); i++) | ||||
| 			if(i->type == type && (!turn || i->turnsRemain > turn)) | ||||
| 				return true; | ||||
| 	} | ||||
| 	else //given subtype | ||||
| 	{ | ||||
| 		for(std::vector<StackFeature>::const_iterator i=features.begin(); i != features.end(); i++) | ||||
| 			if(i->type == type && i->subtype == subtype && (!turn || i->turnsRemain > turn)) | ||||
| 				return true; | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| CStack::CStack(CCreature * C, int A, int O, int I, bool AO, int S) | ||||
| 	:ID(I), creature(C), amount(A), baseAmount(A), firstHPleft(C->hitPoints), owner(O), slot(S), attackerOwned(AO), position(-1),    | ||||
| 	counterAttacks(1), shots(C->shots), features(C->abilities) | ||||
| { | ||||
| 	//additional retaliations | ||||
| 	for(int h=0; h<C->abilities.size(); ++h) | ||||
| 	{ | ||||
| 		if(C->abilities[h].type == StackFeature::ADDITIONAL_RETALIATION) | ||||
| 		{ | ||||
| 			counterAttacks += C->abilities[h].value; | ||||
| 		} | ||||
| 	} | ||||
| 	//alive state indication | ||||
| 	state.insert(ALIVE); | ||||
| } | ||||
|  | ||||
| ui32 CStack::Speed( int turn /*= 0*/ ) const | ||||
| { | ||||
| 	if(hasFeatureOfType(StackFeature::SIEGE_WEAPON, -1024, turn)) //war machnes cannot move | ||||
| 	if(hasBonus(Selector::type(Bonus::SIEGE_WEAPON) && Selector::turns(turn))) //war machines cannot move | ||||
| 		return 0; | ||||
|  | ||||
| 	int speed = creature->speed; | ||||
|  | ||||
| 	speed += valOfFeatures(StackFeature::SPEED_BONUS, -1024, turn); | ||||
| 	int speed = valOfBonuses(Selector::type(Bonus::STACKS_SPEED) && Selector::turns(turn)); | ||||
|  | ||||
| 	int percentBonus = 0; | ||||
| 	for(int g=0; g<features.size(); ++g) | ||||
| 	BOOST_FOREACH(const Bonus &b, bonuses) | ||||
| 	{ | ||||
| 		if(features[g].type == StackFeature::SPEED_BONUS) | ||||
| 		if(b.type == Bonus::STACKS_SPEED) | ||||
| 		{ | ||||
| 			percentBonus += features[g].additionalInfo; | ||||
| 			percentBonus += b.additionalInfo; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @@ -789,39 +749,6 @@ ui8 CStack::howManyEffectsSet(ui16 id) const | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| si32 CStack::Attack() const | ||||
| { | ||||
| 	si32 ret = creature->attack; //value to be returned | ||||
|  | ||||
| 	if(hasFeatureOfType(StackFeature::IN_FRENZY)) //frenzy for attacker | ||||
| 	{ | ||||
| 		ret += si32(VLC->spellh->spells[56].powers[getEffect(56)->level]/100.0) * Defense(false); | ||||
| 	} | ||||
|  | ||||
| 	ret += valOfFeatures(StackFeature::ATTACK_BONUS); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| si32 CStack::Defense(bool withFrenzy /*= true*/) const | ||||
| { | ||||
| 	si32 ret = creature->defence; | ||||
|  | ||||
| 	if(withFrenzy && getEffect(56)) //frenzy for defender | ||||
| 	{ | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	ret += valOfFeatures(StackFeature::DEFENCE_BONUS); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| ui16 CStack::MaxHealth() const | ||||
| { | ||||
| 	return creature->hitPoints + valOfFeatures(StackFeature::HP_BONUS); | ||||
| } | ||||
|  | ||||
| bool CStack::willMove(int turn /*= 0*/) const | ||||
| { | ||||
| 	return ( turn ? true : !vstd::contains(state, DEFENDING) ) | ||||
| @@ -832,7 +759,7 @@ bool CStack::willMove(int turn /*= 0*/) const | ||||
| bool CStack::canMove( int turn /*= 0*/ ) const | ||||
| { | ||||
| 	return alive() | ||||
| 		&& !hasFeatureOfType(StackFeature::NOT_ACTIVE, -1024, turn); //eg. Ammo Cart | ||||
| 		&& !hasBonus(Selector::type(Bonus::NOT_ACTIVE) && Selector::turns(turn)); //eg. Ammo Cart or blinded creature | ||||
| } | ||||
|  | ||||
| bool CStack::moved( int turn /*= 0*/ ) const | ||||
| @@ -843,6 +770,11 @@ bool CStack::moved( int turn /*= 0*/ ) const | ||||
| 		return false; | ||||
| } | ||||
|  | ||||
| bool CStack::doubleWide() const | ||||
| { | ||||
| 	return type->doubleWide; | ||||
| } | ||||
|  | ||||
| CGHeroInstance * CGameState::HeroesPool::pickHeroFor(bool native, int player, const CTown *town, std::map<ui32,CGHeroInstance *> &available) const | ||||
| { | ||||
| 	CGHeroInstance *ret = NULL; | ||||
| @@ -1135,24 +1067,6 @@ std::pair<int,int> CGameState::pickObject (CGObjectInstance *obj) | ||||
| 	return std::pair<int,int>(-1,-1); | ||||
| } | ||||
|  | ||||
| void randomizeArmy(CArmedInstance * army, int type) | ||||
| { | ||||
| 	int max = VLC->creh->creatures.size(); | ||||
| 	for (TSlots::iterator j=army->army.slots.begin(); j!=army->army.slots.end();j++) | ||||
| 	{ | ||||
| 		if(j->second.idRand > max) | ||||
| 		{ | ||||
| 			if(j->second.idRand % 2) | ||||
| 				j->second.setType(VLC->townh->towns[type].basicCreatures[(j->second.idRand-197) / 2 -1]); | ||||
| 			else | ||||
| 				j->second.setType(VLC->townh->towns[type].upgradedCreatures[(j->second.idRand-197) / 2 -1]); | ||||
|  | ||||
| 			j->second.idRand = -1; | ||||
| 		} | ||||
| 	} | ||||
| 	return; | ||||
| } | ||||
|  | ||||
| void CGameState::randomizeObject(CGObjectInstance *cur) | ||||
| {		 | ||||
| 	std::pair<int,int> ran = pickObject(cur); | ||||
| @@ -1178,7 +1092,7 @@ void CGameState::randomizeObject(CGObjectInstance *cur) | ||||
| 		cur->ID = ran.first; | ||||
| 		h->portrait = cur->subID = ran.second; | ||||
| 		h->type = VLC->heroh->heroes[ran.second]; | ||||
| 		randomizeArmy(h, h->type->heroType/2); | ||||
| 		h->randomizeArmy(h->type->heroType/2); | ||||
| 		map->heroes.push_back(h); | ||||
| 		return; //TODO: maybe we should do something with definfo? | ||||
| 	} | ||||
| @@ -1195,7 +1109,7 @@ void CGameState::randomizeObject(CGObjectInstance *cur) | ||||
| 			t->defInfo = forts[t->subID]; | ||||
| 		else | ||||
| 			t->defInfo = villages[t->subID];  | ||||
| 		randomizeArmy(t, t->subID); | ||||
| 		t->randomizeArmy(t->subID); | ||||
| 		map->towns.push_back(t); | ||||
| 		return; | ||||
| 	} | ||||
| @@ -1655,8 +1569,8 @@ bool CGameState::battleCanFlee(int player) | ||||
| 	if(!curB) //there is no battle | ||||
| 		return false; | ||||
|  | ||||
| 	if(curB->heroes[0]->hasBonusOfType(HeroBonus::ENEMY_CANT_ESCAPE) //eg. one of heroes is wearing shakles of war | ||||
| 		|| curB->heroes[0]->hasBonusOfType(HeroBonus::ENEMY_CANT_ESCAPE)) | ||||
| 	if(curB->heroes[0]->hasBonusOfType(Bonus::ENEMY_CANT_ESCAPE) //eg. one of heroes is wearing shakles of war | ||||
| 		|| curB->heroes[0]->hasBonusOfType(Bonus::ENEMY_CANT_ESCAPE)) | ||||
| 		return false; | ||||
|  | ||||
| 	return true; | ||||
| @@ -1669,7 +1583,7 @@ int CGameState::battleGetStack(int pos, bool onlyAlive) | ||||
| 	for(unsigned int g=0; g<curB->stacks.size(); ++g) | ||||
| 	{ | ||||
| 		if((curB->stacks[g]->position == pos  | ||||
| 			  || (curB->stacks[g]->hasFeatureOfType(StackFeature::DOUBLE_WIDE)  | ||||
| 			  || (curB->stacks[g]->doubleWide()  | ||||
| 					&&( (curB->stacks[g]->attackerOwned && curB->stacks[g]->position-1 == pos)  | ||||
| 					||	(!curB->stacks[g]->attackerOwned && curB->stacks[g]->position+1 == pos)	) | ||||
| 			 )) | ||||
| @@ -1758,7 +1672,7 @@ const CGHeroInstance * CGameState::battleGetOwner(int stackID) | ||||
| UpgradeInfo CGameState::getUpgradeInfo(const CArmedInstance *obj, int stackPos) | ||||
| { | ||||
| 	UpgradeInfo ret; | ||||
| 	const CCreature *base = obj->army.slots.find(stackPos)->second.type; | ||||
| 	const CCreature *base = obj->getCreature(stackPos); | ||||
| 	if((obj->ID == TOWNI_TYPE)  ||  ((obj->ID == HEROI_TYPE) && static_cast<const CGHeroInstance*>(obj)->visitedTown)) | ||||
| 	{ | ||||
| 		const CGTownInstance * t; | ||||
| @@ -1777,7 +1691,7 @@ UpgradeInfo CGameState::getUpgradeInfo(const CArmedInstance *obj, int stackPos) | ||||
| 					ret.cost.push_back(std::set<std::pair<int,int> >()); | ||||
| 					for(int j=0;j<RESOURCE_QUANTITY;j++) | ||||
| 					{ | ||||
| 						int dif = VLC->creh->creatures[nid].cost[j] - base->cost[j]; | ||||
| 						int dif = VLC->creh->creatures[nid]->cost[j] - base->cost[j]; | ||||
| 						if(dif) | ||||
| 							ret.cost[ret.cost.size()-1].insert(std::make_pair(j,dif)); | ||||
| 					} | ||||
| @@ -2378,10 +2292,10 @@ bool CGameState::checkForVisitableDir( const int3 & src, const TerrainTile *pom, | ||||
| std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge, bool lucky ) | ||||
| { | ||||
| 	float additiveBonus=1.0f, multBonus=1.0f, | ||||
| 		minDmg = attacker->creature->damageMin * attacker->amount,  | ||||
| 		maxDmg = attacker->creature->damageMax * attacker->amount; | ||||
| 		minDmg = attacker->type->damageMin * attacker->count,  | ||||
| 		maxDmg = attacker->type->damageMax * attacker->count; | ||||
|  | ||||
| 	if(attacker->creature->idNumber == 149) //arrow turret | ||||
| 	if(attacker->type->idNumber == 149) //arrow turret | ||||
| 	{ | ||||
| 		switch(attacker->position) | ||||
| 		{ | ||||
| @@ -2396,16 +2310,16 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if(attacker->hasFeatureOfType(StackFeature::SIEGE_WEAPON) && attacker->creature->idNumber != 149) //any siege weapon, but only ballista can attack (second condition - not arrow turret) | ||||
| 	if(attacker->hasBonusOfType(Bonus::SIEGE_WEAPON) && attacker->type->idNumber != 149) //any siege weapon, but only ballista can attack (second condition - not arrow turret) | ||||
| 	{ //minDmg and maxDmg are multiplied by hero attack + 1 | ||||
| 		minDmg *= attackerHero->getPrimSkillLevel(0) + 1;  | ||||
| 		maxDmg *= attackerHero->getPrimSkillLevel(0) + 1;  | ||||
| 	} | ||||
|  | ||||
| 	int attackDefenceDifference = 0; | ||||
| 	if(attacker->hasFeatureOfType(StackFeature::GENERAL_ATTACK_REDUCTION)) | ||||
| 	if(attacker->hasBonusOfType(Bonus::GENERAL_ATTACK_REDUCTION)) | ||||
| 	{ | ||||
| 		float multAttackReduction = attacker->valOfFeatures(StackFeature::GENERAL_ATTACK_REDUCTION, -1024) / 100.0f; | ||||
| 		float multAttackReduction = attacker->valOfBonuses(Bonus::GENERAL_ATTACK_REDUCTION, -1024) / 100.0f; | ||||
| 		attackDefenceDifference = attacker->Attack() * multAttackReduction; | ||||
| 	} | ||||
| 	else | ||||
| @@ -2413,9 +2327,9 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con | ||||
| 		attackDefenceDifference = attacker->Attack(); | ||||
| 	} | ||||
|  | ||||
| 	if(attacker->hasFeatureOfType(StackFeature::ENEMY_DEFENCE_REDUCTION)) | ||||
| 	if(attacker->hasBonusOfType(Bonus::ENEMY_DEFENCE_REDUCTION)) | ||||
| 	{ | ||||
| 		float multDefenceReduction = (100.0f - attacker->valOfFeatures(StackFeature::ENEMY_DEFENCE_REDUCTION, -1024)) / 100.0f; | ||||
| 		float multDefenceReduction = (100.0f - attacker->valOfBonuses(Bonus::ENEMY_DEFENCE_REDUCTION, -1024)) / 100.0f; | ||||
| 		attackDefenceDifference -= defender->Defense() * multDefenceReduction; | ||||
| 	} | ||||
| 	else | ||||
| @@ -2425,15 +2339,11 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con | ||||
|  | ||||
| 	//calculating total attack/defense skills modifier | ||||
|  | ||||
| 	if(!shooting && attacker->hasFeatureOfType(StackFeature::ATTACK_BONUS, 0)) //bloodlust handling (etc.) | ||||
| 	{ | ||||
| 		attackDefenceDifference += attacker->valOfFeatures(StackFeature::ATTACK_BONUS, 0); | ||||
| 	} | ||||
| 	if(shooting) //precision handling (etc.) | ||||
| 		attackDefenceDifference += attacker->getBonuses(Selector::typeSybtype(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK), Selector::effectRange(Bonus::ONLY_DISTANCE_FIGHT)).totalValue(); | ||||
| 	else //bloodlust handling (etc.) | ||||
| 		attackDefenceDifference += attacker->getBonuses(Selector::typeSybtype(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK), Selector::effectRange(Bonus::ONLY_MELEE_FIGHT)).totalValue(); | ||||
|  | ||||
| 	if(shooting && attacker->hasFeatureOfType(StackFeature::ATTACK_BONUS, 1)) //precision handling (etc.) | ||||
| 	{ | ||||
| 		attackDefenceDifference += attacker->valOfFeatures(StackFeature::ATTACK_BONUS, 1); | ||||
| 	} | ||||
|  | ||||
| 	if(attacker->getEffect(55)) //slayer handling | ||||
| 	{ | ||||
| @@ -2442,11 +2352,11 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con | ||||
|  | ||||
| 		for(int g = 0; g < VLC->creh->creatures.size(); ++g) | ||||
| 		{ | ||||
| 			for (int d=0; d<VLC->creh->creatures[g].abilities.size(); ++d) | ||||
| 			BOOST_FOREACH(const Bonus &b, VLC->creh->creatures[g]->bonuses) | ||||
| 			{ | ||||
| 				if ( (VLC->creh->creatures[g].abilities[d].type == StackFeature::KING3 && spLevel >= 3) || //expert | ||||
| 					(VLC->creh->creatures[g].abilities[d].type == StackFeature::KING2 && spLevel >= 2) || //adv + | ||||
| 					(VLC->creh->creatures[g].abilities[d].type == StackFeature::KING1 && spLevel >= 0) ) //none or basic + | ||||
| 				if ( (b.type == Bonus::KING3 && spLevel >= 3) || //expert | ||||
| 					(b.type == Bonus::KING2 && spLevel >= 2) || //adv + | ||||
| 					(b.type == Bonus::KING1 && spLevel >= 0) ) //none or basic + | ||||
| 				{ | ||||
| 					affectedIds.push_back(g); | ||||
| 					break; | ||||
| @@ -2456,7 +2366,7 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con | ||||
|  | ||||
| 		for(unsigned int g=0; g<affectedIds.size(); ++g) | ||||
| 		{ | ||||
| 			if(defender->creature->idNumber == affectedIds[g]) | ||||
| 			if(defender->type->idNumber == affectedIds[g]) | ||||
| 			{ | ||||
| 				attackDefenceDifference += VLC->spellh->spells[55].powers[attacker->getEffect(55)->level]; | ||||
| 				break; | ||||
| @@ -2492,7 +2402,7 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con | ||||
| 	 | ||||
|  | ||||
| 	//applying jousting bonus | ||||
| 	if( attacker->hasFeatureOfType(StackFeature::JOUSTING) && !defender->hasFeatureOfType(StackFeature::CHARGE_IMMUNITY) ) | ||||
| 	if( attacker->hasBonusOfType(Bonus::JOUSTING) && !defender->hasBonusOfType(Bonus::CHARGE_IMMUNITY) ) | ||||
| 		additiveBonus += charge * 0.05f; | ||||
|  | ||||
| 	 | ||||
| @@ -2517,7 +2427,7 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con | ||||
| 			if(attackerHero->getSecSkillLevel(1) > 0) //non-none level | ||||
| 			{ | ||||
| 				//apply artifact premy to archery | ||||
| 				additiveBonus += attackerHero->valOfBonuses(HeroBonus::SECONDARY_SKILL_PREMY, 1) / 100.0f; | ||||
| 				additiveBonus += attackerHero->valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, 1) / 100.0f; | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| @@ -2554,7 +2464,7 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con | ||||
| 	} | ||||
|  | ||||
| 	//handling hate effect | ||||
| 	if( attacker->hasFeatureOfType(StackFeature::HATE, defender->creature->idNumber) ) | ||||
| 	if( attacker->hasBonusOfType(Bonus::HATE, defender->type->idNumber) ) | ||||
| 		additiveBonus += 0.5f; | ||||
|  | ||||
| 	//luck bonus | ||||
| @@ -2564,13 +2474,13 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con | ||||
| 	} | ||||
|  | ||||
| 	//handling spell effects | ||||
| 	if(!shooting && defender->hasFeatureOfType(StackFeature::GENERAL_DAMAGE_REDUCTION, 0)) //eg. shield | ||||
| 	if(!shooting && defender->hasBonusOfType(Bonus::GENERAL_DAMAGE_REDUCTION, 0)) //eg. shield | ||||
| 	{ | ||||
| 		multBonus *= float(defender->valOfFeatures(StackFeature::GENERAL_DAMAGE_REDUCTION, 0)) / 100.0f; | ||||
| 		multBonus *= float(defender->valOfBonuses(Bonus::GENERAL_DAMAGE_REDUCTION, 0)) / 100.0f; | ||||
| 	} | ||||
| 	else if(shooting && defender->hasFeatureOfType(StackFeature::GENERAL_DAMAGE_REDUCTION, 1)) //eg. air shield | ||||
| 	else if(shooting && defender->hasBonusOfType(Bonus::GENERAL_DAMAGE_REDUCTION, 1)) //eg. air shield | ||||
| 	{ | ||||
| 		multBonus *= float(defender->valOfFeatures(StackFeature::GENERAL_DAMAGE_REDUCTION, 1)) / 100.0f; | ||||
| 		multBonus *= float(defender->valOfBonuses(Bonus::GENERAL_DAMAGE_REDUCTION, 1)) / 100.0f; | ||||
| 	} | ||||
| 	if(attacker->getEffect(42)) //curse handling (partial, the rest is below) | ||||
| 	{ | ||||
| @@ -2636,7 +2546,7 @@ ui32 BattleInfo::calculateDmg( const CStack* attacker, const CStack* defender, c | ||||
| 	if(range.first != range.second) | ||||
| 	{ | ||||
| 		int valuesToAverage[10]; | ||||
| 		int howManyToAv = std::min<ui32>(10, attacker->amount); | ||||
| 		int howManyToAv = std::min<ui32>(10, attacker->count); | ||||
| 		for (int g=0; g<howManyToAv; ++g) | ||||
| 		{ | ||||
| 			valuesToAverage[g] = range.first  +  rand() % (range.second - range.first + 1); | ||||
| @@ -2653,10 +2563,10 @@ void BattleInfo::calculateCasualties( std::map<ui32,si32> *casualties ) const | ||||
| 	for(unsigned int i=0; i<stacks.size();i++)//setting casualties | ||||
| 	{ | ||||
| 		const CStack * const st = stacks[i]; | ||||
| 		si32 killed = (st->alive() ? st->baseAmount - st->amount : st->baseAmount); | ||||
| 		si32 killed = (st->alive() ? st->baseAmount - st->count : st->baseAmount); | ||||
| 		amax(killed, 0); | ||||
| 		if(killed) | ||||
| 			casualties[!st->attackerOwned][st->creature->idNumber] += killed; | ||||
| 			casualties[!st->attackerOwned][st->type->idNumber] += killed; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -2673,16 +2583,16 @@ si8 CGameState::battleMaxSpellLevel() | ||||
| 	const CGHeroInstance *h1 =  curB->heroes[0]; | ||||
| 	if(h1) | ||||
| 	{ | ||||
| 		for(std::list<HeroBonus>::const_iterator i = h1->bonuses.begin(); i != h1->bonuses.end(); i++) | ||||
| 			if(i->type == HeroBonus::BLOCK_SPELLS_ABOVE_LEVEL) | ||||
| 		for(std::list<Bonus>::const_iterator i = h1->bonuses.begin(); i != h1->bonuses.end(); i++) | ||||
| 			if(i->type == Bonus::BLOCK_SPELLS_ABOVE_LEVEL) | ||||
| 				amin(levelLimit, i->val); | ||||
| 	} | ||||
|  | ||||
| 	const CGHeroInstance *h2 = curB->heroes[1]; | ||||
| 	if(h2) | ||||
| 	{ | ||||
| 		for(std::list<HeroBonus>::const_iterator i = h2->bonuses.begin(); i != h2->bonuses.end(); i++) | ||||
| 			if(i->type == HeroBonus::BLOCK_SPELLS_ABOVE_LEVEL) | ||||
| 		for(std::list<Bonus>::const_iterator i = h2->bonuses.begin(); i != h2->bonuses.end(); i++) | ||||
| 			if(i->type == Bonus::BLOCK_SPELLS_ABOVE_LEVEL) | ||||
| 				amin(levelLimit, i->val); | ||||
| 	} | ||||
|  | ||||
| @@ -2700,8 +2610,8 @@ std::set<CStack*> BattleInfo::getAttackedCreatures( const CSpell * s, int skillL | ||||
| 	{ | ||||
| 		for(int it=0; it<stacks.size(); ++it) | ||||
| 		{ | ||||
| 			if((s->id == 24 && !stacks[it]->creature->isUndead()) //death ripple | ||||
| 				|| (s->id == 25 && stacks[it]->creature->isUndead()) //destroy undead | ||||
| 			if((s->id == 24 && !stacks[it]->type->isUndead()) //death ripple | ||||
| 				|| (s->id == 25 && stacks[it]->type->isUndead()) //destroy undead | ||||
| 				|| (s->id == 26) //Armageddon | ||||
| 				) | ||||
| 			{ | ||||
| @@ -2761,51 +2671,21 @@ int BattleInfo::calculateSpellDuration(const CSpell * spell, const CGHeroInstanc | ||||
| 	case 56: //frenzy | ||||
| 		return 1; | ||||
| 	default: //other spells | ||||
| 		return caster->getPrimSkillLevel(2) + caster->valOfBonuses(HeroBonus::SPELL_DURATION); | ||||
| 		return caster->getPrimSkillLevel(2) + caster->valOfBonuses(Bonus::SPELL_DURATION); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| CStack * BattleInfo::generateNewStack(const CGHeroInstance * owner, int creatureID, int amount, int stackID, bool attackerOwned, int slot, int /*TerrainTile::EterrainType*/ terrain, int position) const | ||||
| CStack * BattleInfo::generateNewStack(const CStackInstance &base, int stackID, bool attackerOwned, int slot, int /*TerrainTile::EterrainType*/ terrain, int position) const | ||||
| { | ||||
| 	CStack * ret = new CStack(&VLC->creh->creatures[creatureID], amount, attackerOwned ? side1 : side2, stackID, attackerOwned, slot); | ||||
| 	if(owner) | ||||
| 	{ | ||||
| 		ret->features.push_back(makeFeature(StackFeature::SPEED_BONUS, StackFeature::WHOLE_BATTLE, 0, owner->valOfBonuses(HeroBonus::STACKS_SPEED), StackFeature::BONUS_FROM_HERO)); | ||||
| 		//base luck/morale calculations | ||||
| 		ret->morale = owner->getCurrentMorale(slot, false); | ||||
| 		ret->luck = owner->getCurrentLuck(slot, false); | ||||
| 		//other bonuses | ||||
| 		ret->features.push_back(makeFeature(StackFeature::ATTACK_BONUS, StackFeature::WHOLE_BATTLE, 0, owner->getPrimSkillLevel(0), StackFeature::BONUS_FROM_HERO)); | ||||
| 		ret->features.push_back(makeFeature(StackFeature::DEFENCE_BONUS, StackFeature::WHOLE_BATTLE, 0, owner->getPrimSkillLevel(1), StackFeature::BONUS_FROM_HERO)); | ||||
|  | ||||
| 		if ( owner->hasBonusOfType(HeroBonus::STACK_HEALTH_PERCENT) ) // e.g. Elixir of Life | ||||
| 			ret->features.push_back(makeFeature(StackFeature::HP_BONUS, StackFeature::WHOLE_BATTLE, 0,  | ||||
| 				(ret->creature->hitPoints * owner->valOfBonuses(HeroBonus::STACK_HEALTH_PERCENT)) / 100,  | ||||
| 				StackFeature::BONUS_FROM_HERO)); | ||||
| 		if (owner->hasBonusOfType(HeroBonus::HP_REGENERATION)) // e.g. Elixir of Life | ||||
| 			ret->features.push_back(makeFeature(StackFeature::HP_REGENERATION, StackFeature::WHOLE_BATTLE, 0, | ||||
| 				owner->valOfBonuses(HeroBonus::HP_REGENERATION), StackFeature::BONUS_FROM_HERO)); | ||||
|  | ||||
| 		if (owner->hasBonusOfType(HeroBonus::LEVEL_SPELL_IMMUNITY)) // e.g. Power of the Dragon Father | ||||
| 			ret->features.push_back(makeFeature(StackFeature::LEVEL_SPELL_IMMUNITY, StackFeature::WHOLE_BATTLE, 0, | ||||
| 				owner->valOfBonuses(HeroBonus::LEVEL_SPELL_IMMUNITY), StackFeature::BONUS_FROM_HERO)); | ||||
|  | ||||
| 		ret->features.push_back(makeFeature(StackFeature::HP_BONUS, StackFeature::WHOLE_BATTLE, 0, owner->valOfBonuses(HeroBonus::STACK_HEALTH), StackFeature::BONUS_FROM_HERO)); | ||||
| 		ret->firstHPleft = ret->MaxHealth(); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		ret->morale = 0; | ||||
| 		ret->luck = 0; | ||||
| 	} | ||||
| 	CStack * ret = new CStack(&base, attackerOwned ? side1 : side2, stackID, attackerOwned, slot); | ||||
|  | ||||
| 	//native terrain bonuses | ||||
| 	int faction = ret->creature->faction; | ||||
| 	int faction = ret->type->faction; | ||||
| 	if(faction >= 0 && VLC->heroh->nativeTerrains[faction] == terrain) | ||||
| 	{ | ||||
| 		ret->features.push_back(makeFeature(StackFeature::SPEED_BONUS, StackFeature::WHOLE_BATTLE, 0, 1, StackFeature::OTHER_SOURCE)); | ||||
| 		ret->features.push_back(makeFeature(StackFeature::ATTACK_BONUS, StackFeature::WHOLE_BATTLE, 0, 1, StackFeature::OTHER_SOURCE)); | ||||
| 		ret->features.push_back(makeFeature(StackFeature::DEFENCE_BONUS, StackFeature::WHOLE_BATTLE, 0, 1, StackFeature::OTHER_SOURCE)); | ||||
| 		ret->bonuses.push_back(makeFeature(Bonus::STACKS_SPEED, Bonus::ONE_BATTLE, 0, 1, Bonus::TERRAIN_NATIVE)); | ||||
| 		ret->bonuses.push_back(makeFeature(Bonus::PRIMARY_SKILL, Bonus::ONE_BATTLE, PrimarySkill::ATTACK, 1, Bonus::TERRAIN_NATIVE)); | ||||
| 		ret->bonuses.push_back(makeFeature(Bonus::PRIMARY_SKILL, Bonus::ONE_BATTLE, PrimarySkill::DEFENSE, 1, Bonus::TERRAIN_NATIVE)); | ||||
| 	} | ||||
|  | ||||
| 	ret->position = position; | ||||
| @@ -2823,13 +2703,13 @@ ui32 BattleInfo::getSpellCost(const CSpell * sp, const CGHeroInstance * caster) | ||||
| 	si32 manaIncrease = 0; | ||||
| 	for(int g=0; g<stacks.size(); ++g) | ||||
| 	{ | ||||
| 		if( stacks[g]->owner == caster->tempOwner && stacks[g]->hasFeatureOfType(StackFeature::CHANGES_SPELL_COST_FOR_ALLY) ) | ||||
| 		if( stacks[g]->owner == caster->tempOwner && stacks[g]->hasBonusOfType(Bonus::CHANGES_SPELL_COST_FOR_ALLY) ) | ||||
| 		{ | ||||
| 			amin(manaReduction, stacks[g]->valOfFeatures(StackFeature::CHANGES_SPELL_COST_FOR_ALLY)); | ||||
| 			amin(manaReduction, stacks[g]->valOfBonuses(Bonus::CHANGES_SPELL_COST_FOR_ALLY)); | ||||
| 		} | ||||
| 		if( stacks[g]->owner != caster->tempOwner && stacks[g]->hasFeatureOfType(StackFeature::CHANGES_SPELL_COST_FOR_ENEMY) ) | ||||
| 		if( stacks[g]->owner != caster->tempOwner && stacks[g]->hasBonusOfType(Bonus::CHANGES_SPELL_COST_FOR_ENEMY) ) | ||||
| 		{ | ||||
| 			amax(manaIncrease, stacks[g]->valOfFeatures(StackFeature::CHANGES_SPELL_COST_FOR_ENEMY)); | ||||
| 			amax(manaIncrease, stacks[g]->valOfBonuses(Bonus::CHANGES_SPELL_COST_FOR_ENEMY)); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @@ -2866,10 +2746,10 @@ std::pair<const CStack *, int> BattleInfo::getNearestStack(const CStack * closes | ||||
| 	bool ac[BFIELD_SIZE]; | ||||
| 	std::set<int> occupyable; | ||||
|  | ||||
| 	getAccessibilityMap(ac, closest->hasFeatureOfType(StackFeature::DOUBLE_WIDE), closest->attackerOwned, false, occupyable, closest->hasFeatureOfType(StackFeature::FLYING), closest->ID); | ||||
| 	getAccessibilityMap(ac, closest->doubleWide(), closest->attackerOwned, false, occupyable, closest->hasBonusOfType(Bonus::FLYING), closest->ID); | ||||
|  | ||||
| 	int predecessor[BFIELD_SIZE], dist[BFIELD_SIZE]; | ||||
| 	makeBFS(closest->position, ac, predecessor, dist, closest->hasFeatureOfType(StackFeature::DOUBLE_WIDE), closest->attackerOwned, closest->hasFeatureOfType(StackFeature::FLYING), true); | ||||
| 	makeBFS(closest->position, ac, predecessor, dist, closest->doubleWide(), closest->attackerOwned, closest->hasBonusOfType(Bonus::FLYING), true); | ||||
|  | ||||
| 	std::vector< std::pair< std::pair<int, int>, const CStack *> > stackPairs; //pairs <<distance, hex>, stack> | ||||
| 	for(int g=0; g<BFIELD_SIZE; ++g) | ||||
| @@ -2944,59 +2824,59 @@ ui32 BattleInfo::calculateSpellDmg( const CSpell * sp, const CGHeroInstance * ca | ||||
| 		} | ||||
| 	} | ||||
| 	//applying hero bonuses | ||||
| 	if(sp->air && caster && caster->valOfBonuses(HeroBonus::AIR_SPELL_DMG_PREMY) != 0) | ||||
| 	if(sp->air && caster && caster->valOfBonuses(Bonus::AIR_SPELL_DMG_PREMY) != 0) | ||||
| 	{ | ||||
| 		ret *= (100.0f + caster->valOfBonuses(HeroBonus::AIR_SPELL_DMG_PREMY)) / 100.0f; | ||||
| 		ret *= (100.0f + caster->valOfBonuses(Bonus::AIR_SPELL_DMG_PREMY)) / 100.0f; | ||||
| 	} | ||||
| 	else if(sp->fire && caster && caster->valOfBonuses(HeroBonus::FIRE_SPELL_DMG_PREMY) != 0) | ||||
| 	else if(sp->fire && caster && caster->valOfBonuses(Bonus::FIRE_SPELL_DMG_PREMY) != 0) | ||||
| 	{ | ||||
| 		ret *= (100.0f + caster->valOfBonuses(HeroBonus::FIRE_SPELL_DMG_PREMY)) / 100.0f; | ||||
| 		ret *= (100.0f + caster->valOfBonuses(Bonus::FIRE_SPELL_DMG_PREMY)) / 100.0f; | ||||
| 	} | ||||
| 	else if(sp->water && caster && caster->valOfBonuses(HeroBonus::WATER_SPELL_DMG_PREMY) != 0) | ||||
| 	else if(sp->water && caster && caster->valOfBonuses(Bonus::WATER_SPELL_DMG_PREMY) != 0) | ||||
| 	{ | ||||
| 		ret *= (100.0f + caster->valOfBonuses(HeroBonus::WATER_SPELL_DMG_PREMY)) / 100.0f; | ||||
| 		ret *= (100.0f + caster->valOfBonuses(Bonus::WATER_SPELL_DMG_PREMY)) / 100.0f; | ||||
| 	} | ||||
| 	else if(sp->earth && caster && caster->valOfBonuses(HeroBonus::EARTH_SPELL_DMG_PREMY) != 0) | ||||
| 	else if(sp->earth && caster && caster->valOfBonuses(Bonus::EARTH_SPELL_DMG_PREMY) != 0) | ||||
| 	{ | ||||
| 		ret *= (100.0f + caster->valOfBonuses(HeroBonus::EARTH_SPELL_DMG_PREMY)) / 100.0f; | ||||
| 		ret *= (100.0f + caster->valOfBonuses(Bonus::EARTH_SPELL_DMG_PREMY)) / 100.0f; | ||||
| 	} | ||||
|  | ||||
| 	//affected creature-specific part | ||||
| 	if(affectedCreature) | ||||
| 	{ | ||||
| 		//applying protections - when spell has more then one elements, only one protection should be applied (I think) | ||||
| 		if(sp->air && affectedCreature->hasFeatureOfType(StackFeature::SPELL_DAMAGE_REDUCTION, 0)) //air spell & protection from air | ||||
| 		if(sp->air && affectedCreature->hasBonusOfType(Bonus::SPELL_DAMAGE_REDUCTION, 0)) //air spell & protection from air | ||||
| 		{ | ||||
| 			ret *= affectedCreature->valOfFeatures(StackFeature::SPELL_DAMAGE_REDUCTION, 0); | ||||
| 			ret *= affectedCreature->valOfBonuses(Bonus::SPELL_DAMAGE_REDUCTION, 0); | ||||
| 			ret /= 100; | ||||
| 		} | ||||
| 		else if(sp->fire && affectedCreature->hasFeatureOfType(StackFeature::SPELL_DAMAGE_REDUCTION, 1)) //fire spell & protection from fire | ||||
| 		else if(sp->fire && affectedCreature->hasBonusOfType(Bonus::SPELL_DAMAGE_REDUCTION, 1)) //fire spell & protection from fire | ||||
| 		{ | ||||
| 			ret *= affectedCreature->valOfFeatures(StackFeature::SPELL_DAMAGE_REDUCTION, 1); | ||||
| 			ret *= affectedCreature->valOfBonuses(Bonus::SPELL_DAMAGE_REDUCTION, 1); | ||||
| 			ret /= 100; | ||||
| 		} | ||||
| 		else if(sp->water && affectedCreature->hasFeatureOfType(StackFeature::SPELL_DAMAGE_REDUCTION, 2)) //water spell & protection from water | ||||
| 		else if(sp->water && affectedCreature->hasBonusOfType(Bonus::SPELL_DAMAGE_REDUCTION, 2)) //water spell & protection from water | ||||
| 		{ | ||||
| 			ret *= affectedCreature->valOfFeatures(StackFeature::SPELL_DAMAGE_REDUCTION, 2); | ||||
| 			ret *= affectedCreature->valOfBonuses(Bonus::SPELL_DAMAGE_REDUCTION, 2); | ||||
| 			ret /= 100; | ||||
| 		} | ||||
| 		else if (sp->earth && affectedCreature->hasFeatureOfType(StackFeature::SPELL_DAMAGE_REDUCTION, 3)) //earth spell & protection from earth | ||||
| 		else if (sp->earth && affectedCreature->hasBonusOfType(Bonus::SPELL_DAMAGE_REDUCTION, 3)) //earth spell & protection from earth | ||||
| 		{ | ||||
| 			ret *= affectedCreature->valOfFeatures(StackFeature::SPELL_DAMAGE_REDUCTION, 3); | ||||
| 			ret *= affectedCreature->valOfBonuses(Bonus::SPELL_DAMAGE_REDUCTION, 3); | ||||
| 			ret /= 100; | ||||
| 		} | ||||
|  | ||||
| 		//general spell dmg reduction | ||||
| 		if(sp->air && affectedCreature->hasFeatureOfType(StackFeature::SPELL_DAMAGE_REDUCTION, -1)) //air spell & protection from air | ||||
| 		if(sp->air && affectedCreature->hasBonusOfType(Bonus::SPELL_DAMAGE_REDUCTION, -1)) //air spell & protection from air | ||||
| 		{ | ||||
| 			ret *= affectedCreature->valOfFeatures(StackFeature::SPELL_DAMAGE_REDUCTION, -1); | ||||
| 			ret *= affectedCreature->valOfBonuses(Bonus::SPELL_DAMAGE_REDUCTION, -1); | ||||
| 			ret /= 100; | ||||
| 		} | ||||
|  | ||||
| 		//dmg increasing | ||||
| 		if( affectedCreature->hasFeatureOfType(StackFeature::MORE_DAMAGE_FROM_SPELL, sp->id) ) | ||||
| 		if( affectedCreature->hasBonusOfType(Bonus::MORE_DAMAGE_FROM_SPELL, sp->id) ) | ||||
| 		{ | ||||
| 			ret *= 100 + affectedCreature->valOfFeatures(StackFeature::MORE_DAMAGE_FROM_SPELL, sp->id); | ||||
| 			ret *= 100 + affectedCreature->valOfBonuses(Bonus::MORE_DAMAGE_FROM_SPELL, sp->id); | ||||
| 			ret /= 100; | ||||
| 		} | ||||
| 	} | ||||
| @@ -3016,16 +2896,16 @@ bool CGameState::battleCanShoot(int ID, int dest) | ||||
|  | ||||
| 	const CGHeroInstance * ourHero = battleGetOwner(our->ID); | ||||
|  | ||||
| 	if(our->hasFeatureOfType(StackFeature::FORGETFULL)) //forgetfulness | ||||
| 	if(our->hasBonusOfType(Bonus::FORGETFULL)) //forgetfulness | ||||
| 		return false; | ||||
|  | ||||
| 	if(our->creature->idNumber == 145 && dst) //catapult cannot attack creatures | ||||
| 	if(our->type->idNumber == 145 && dst) //catapult cannot attack creatures | ||||
| 		return false; | ||||
|  | ||||
| 	if(our->hasFeatureOfType(StackFeature::SHOOTER)//it's shooter | ||||
| 	if(our->hasBonusOfType(Bonus::SHOOTER)//it's shooter | ||||
| 		&& our->owner != dst->owner | ||||
| 		&& dst->alive() | ||||
| 		&& (!curB->isStackBlocked(ID)  ||  NBonus::hasOfType(ourHero, HeroBonus::FREE_SHOOTING)) | ||||
| 		&& (!curB->isStackBlocked(ID)  ||  NBonus::hasOfType(ourHero, Bonus::FREE_SHOOTING)) | ||||
| 		&& our->shots | ||||
| 		) | ||||
| 		return true; | ||||
| @@ -3062,7 +2942,7 @@ int CGameState::victoryCheck( ui8 player ) const | ||||
| 						&& map->objects[i]->tempOwner == player //object controlled by player | ||||
| 						&&  (ai = dynamic_cast<const CArmedInstance*>(map->objects[i]))) //contains army | ||||
| 					{ | ||||
| 						for(TSlots::const_iterator i=ai->army.slots.begin(); i!=ai->army.slots.end(); ++i) //iterate through army | ||||
| 						for(TSlots::const_iterator i=ai->Slots().begin(); i!=ai->Slots().end(); ++i) //iterate through army | ||||
| 							if(i->second.type->idNumber == map->victoryCondition.ID) //it's searched creature | ||||
| 								total += i->second.count; | ||||
| 					} | ||||
| @@ -3291,7 +3171,7 @@ void CGameState::obtainPlayersStats(SThievesGuildInfo & tgi, int level) | ||||
| 			const CGHeroInstance * best = statsHLP::findBestHero(this, g->second.color); | ||||
| 			InfoAboutHero iah; | ||||
| 			iah.initFromHero(best, level >= 8); | ||||
| 			iah.army.slots.clear(); | ||||
| 			iah.army.clear(); | ||||
| 			tgi.colorToBestHero[g->second.color] = iah; | ||||
| 		} | ||||
| 	} | ||||
| @@ -3354,10 +3234,10 @@ void CGameState::obtainPlayersStats(SThievesGuildInfo & tgi, int level) | ||||
| 			int bestCre = -1; //best creature's ID | ||||
| 			for(int b=0; b<g->second.heroes.size(); ++b) | ||||
| 			{ | ||||
| 				for(TSlots::const_iterator it = g->second.heroes[b]->army.slots.begin(); it != g->second.heroes[b]->army.slots.end(); ++it) | ||||
| 				for(TSlots::const_iterator it = g->second.heroes[b]->Slots().begin(); it != g->second.heroes[b]->Slots().end(); ++it) | ||||
| 				{ | ||||
| 					int toCmp = it->second.type->idNumber; //ID of creature we should compare with the best one | ||||
| 					if(bestCre == -1 || VLC->creh->creatures[bestCre].AIValue < VLC->creh->creatures[toCmp].AIValue) | ||||
| 					if(bestCre == -1 || VLC->creh->creatures[bestCre]->AIValue < VLC->creh->creatures[toCmp]->AIValue) | ||||
| 					{ | ||||
| 						bestCre = toCmp; | ||||
| 					} | ||||
| @@ -3508,7 +3388,7 @@ void BattleInfo::getStackQueue( std::vector<const CStack *> &out, int howMany, i | ||||
| 			else | ||||
| 				p = 3; | ||||
| 		} | ||||
| 		else if(s->creature->idNumber == 145  ||  s->creature->idNumber == 149) //catapult and turrets are first | ||||
| 		else if(s->type->idNumber == 145  ||  s->type->idNumber == 149) //catapult and turrets are first | ||||
| 		{ | ||||
| 			p = 0; | ||||
| 		} | ||||
| @@ -3566,77 +3446,6 @@ void BattleInfo::getStackQueue( std::vector<const CStack *> &out, int howMany, i | ||||
| 	} | ||||
| } | ||||
|  | ||||
| si8 BattleInfo::Morale( const CStack * st ) const | ||||
| { | ||||
| 	si8 ret = st->morale; | ||||
|  | ||||
| 	if(st->hasFeatureOfType(StackFeature::NON_LIVING) || st->hasFeatureOfType(StackFeature::UNDEAD) || | ||||
| 		st->hasFeatureOfType(StackFeature::NO_MORALE) || st->hasFeatureOfType(StackFeature::SIEGE_WEAPON)) | ||||
| 		return 0; | ||||
|  | ||||
| 	ret += st->valOfFeatures(StackFeature::MORALE_BONUS); //mirth & sorrow & other | ||||
|  | ||||
| 	//decreasing / increasing morale from  other stacks | ||||
| 	for (int g=0; g<stacks.size(); ++g) | ||||
| 	{ | ||||
| 		if (stacks[g]->owner == st->owner) //ally | ||||
| 		{ | ||||
| 			if (stacks[g]->hasFeatureOfType(StackFeature::RAISING_MORALE)) | ||||
| 			{ | ||||
| 				ret += stacks[g]->valOfFeatures(StackFeature::RAISING_MORALE); | ||||
| 			} | ||||
| 		} | ||||
| 		else //enemy | ||||
| 		{ | ||||
| 			if (stacks[g]->hasFeatureOfType(StackFeature::ENEMY_MORALE_DECREASING)) | ||||
| 			{ | ||||
| 				ret -= stacks[g]->valOfFeatures(StackFeature::ENEMY_MORALE_DECREASING); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if(st->hasFeatureOfType(StackFeature::SELF_MORALE)) //eg. minotaur | ||||
| 	{ | ||||
| 		ret = std::max<si8>(ret, +1); | ||||
| 	} | ||||
|  | ||||
| 	if(ret > 3) ret = 3; | ||||
| 	if(ret < -3) ret = -3; | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| si8 BattleInfo::Luck( const CStack * st ) const | ||||
| { | ||||
| 	si8 ret = st->luck; | ||||
|  | ||||
| 	if(st->hasFeatureOfType(StackFeature::NO_LUCK)) | ||||
| 		return 0; | ||||
|  | ||||
| 	ret += st->valOfFeatures(StackFeature::LUCK_BONUS); //fortune & misfortune & other | ||||
|  | ||||
| 	//decreasing / increasing morale from  other stacks | ||||
| 	for (int g=0; g<stacks.size(); ++g) | ||||
| 	{ | ||||
| 		if (stacks[g]->owner == st->owner) //ally | ||||
| 		{ | ||||
| 			//no such feature (yet) | ||||
| 		} | ||||
| 		else //enemy | ||||
| 		{ | ||||
| 			ret -= stacks[g]->valOfFeatures(StackFeature::ENEMY_LUCK_DECREASING); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if(st->hasFeatureOfType(StackFeature::SELF_LUCK)) //eg. halfling | ||||
| 	{ | ||||
| 		ret = std::max<si8>(ret, +1); | ||||
| 	} | ||||
|  | ||||
| 	if(ret > 3) ret = 3; | ||||
| 	if(ret < -3) ret = -3; | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| si8 BattleInfo::hasDistancePenalty( int stackID, int destHex ) | ||||
| { | ||||
| 	const CStack * stack = getStack(stackID); | ||||
| @@ -3644,7 +3453,7 @@ si8 BattleInfo::hasDistancePenalty( int stackID, int destHex ) | ||||
| 	int distance = std::abs(destHex % BFIELD_WIDTH - stack->position % BFIELD_WIDTH); | ||||
|  | ||||
| 	//I hope it's approximately correct | ||||
| 	return distance > 8 && !stack->hasFeatureOfType(StackFeature::NO_DISTANCE_PENALTY); | ||||
| 	return distance > 8 && !stack->hasBonusOfType(Bonus::NO_DISTANCE_PENALTY); | ||||
| } | ||||
|  | ||||
| si8 BattleInfo::hasWallPenalty( int stackID, int destHex ) | ||||
| @@ -3654,7 +3463,7 @@ si8 BattleInfo::hasWallPenalty( int stackID, int destHex ) | ||||
| 		return false; | ||||
| 	} | ||||
| 	const CStack * stack = getStack(stackID); | ||||
| 	if (stack->hasFeatureOfType(StackFeature::NO_WALL_PENALTY)); | ||||
| 	if (stack->hasBonusOfType(Bonus::NO_WALL_PENALTY)); | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
| @@ -3667,6 +3476,28 @@ si8 BattleInfo::hasWallPenalty( int stackID, int destHex ) | ||||
| 	return stackLeft != destLeft; | ||||
| } | ||||
|  | ||||
| void BattleInfo::getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root /*= NULL*/) const | ||||
| { | ||||
| 	CBonusSystemNode::getBonuses(out, selector, root); | ||||
|  | ||||
| 	const CStack *dest = dynamic_cast<const CStack*>(root); | ||||
| 	if (!dest) | ||||
| 		return; | ||||
|  | ||||
|  | ||||
| 	//TODO: make it in clean way | ||||
| 	if(Selector::matchesType(selector, Bonus::MORALE) || Selector::matchesType(selector, Bonus::LUCK)) | ||||
| 	{ | ||||
| 		BOOST_FOREACH(const CStack *s, stacks) | ||||
| 		{ | ||||
| 			if(s->owner == dest->owner) | ||||
| 				s->getBonuses(out, selector, Selector::effectRange(Bonus::ONLY_ALLIED_ARMY), this); | ||||
| 			else | ||||
| 				s->getBonuses(out, selector, Selector::effectRange(Bonus::ONLY_ENEMY_ARMY), this); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int3 CPath::startPos() const | ||||
| { | ||||
| 	return nodes[nodes.size()-1].coord; | ||||
| @@ -3766,7 +3597,7 @@ bool CMP_stack::operator()( const CStack* a, const CStack* b ) | ||||
| 	switch(phase) | ||||
| 	{ | ||||
| 	case 0: //catapult moves after turrets | ||||
| 		return a->creature->idNumber < b->creature->idNumber; //catapult is 145 and turrets are 149 | ||||
| 		return a->type->idNumber < b->type->idNumber; //catapult is 145 and turrets are 149 | ||||
| 		//TODO? turrets order | ||||
| 	case 1: //fastest first, upper slot first | ||||
| 		{ | ||||
| @@ -3805,6 +3636,11 @@ PlayerState::PlayerState() | ||||
|  | ||||
| } | ||||
|  | ||||
| void PlayerState::getParents(TCNodes &out, const CBonusSystemNode *root /*= NULL*/) const | ||||
| { | ||||
| 	//TODO: global effects | ||||
| } | ||||
|  | ||||
| InfoAboutHero::InfoAboutHero() | ||||
| { | ||||
| 	details = NULL; | ||||
| @@ -3830,14 +3666,14 @@ void InfoAboutHero::initFromHero( const CGHeroInstance *h, bool detailed ) | ||||
| 	hclass = h->type->heroClass; | ||||
| 	name = h->name; | ||||
| 	portrait = h->portrait; | ||||
| 	army = h->army;  | ||||
| 	army = h->getArmy();  | ||||
|  | ||||
| 	if(detailed)  | ||||
| 	{ | ||||
| 		//include details about hero | ||||
| 		details = new Details; | ||||
| 		details->luck = h->getCurrentLuck(); | ||||
| 		details->morale = h->getCurrentMorale(); | ||||
| 		details->luck = h->LuckVal(); | ||||
| 		details->morale = h->MoraleVal(); | ||||
| 		details->mana = h->mana; | ||||
| 		details->primskills.resize(PRIMARY_SKILLS); | ||||
|  | ||||
| @@ -3849,9 +3685,9 @@ void InfoAboutHero::initFromHero( const CGHeroInstance *h, bool detailed ) | ||||
| 	else | ||||
| 	{ | ||||
| 		//hide info about hero stacks counts using descriptives names ids | ||||
| 		for(TSlots::iterator i = army.slots.begin(); i != army.slots.end(); ++i) | ||||
| 		for(TSlots::const_iterator i = army.Slots().begin(); i != army.Slots().end(); ++i) | ||||
| 		{ | ||||
| 			i->second.count = i->second.getQuantityID(); | ||||
| 			army.setStackCount(i->first, i->second.getQuantityID()); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -2,22 +2,26 @@ | ||||
| #define __CGAMESTATE_H__ | ||||
| #include "../global.h" | ||||
| #include <cassert> | ||||
|  | ||||
| #ifndef _MSC_VER | ||||
| #include "../hch/CCreatureHandler.h" | ||||
| #include "VCMI_Lib.h" | ||||
| #include "map.h" | ||||
| #endif | ||||
|  | ||||
| #include <set> | ||||
| #include <vector> | ||||
| #include <list> | ||||
| #include "StackFeature.h" | ||||
| #include "HeroBonus.h" | ||||
| #include "CCreatureSet.h" | ||||
|  | ||||
| #ifdef _WIN32 | ||||
| #include <tchar.h> | ||||
| #else | ||||
| #include "../tchar_amigaos4.h" | ||||
| #endif | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * CGameState.h, part of VCMI engine | ||||
|  * | ||||
| @@ -123,11 +127,13 @@ public: | ||||
| 	ui8 daysWithoutCastle; | ||||
|  | ||||
| 	PlayerState(); | ||||
| 	virtual void getParents(TCNodes &out, const CBonusSystemNode *root = NULL) const; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & color & serial & human & currentSelection & fogOfWarMap & resources & status; | ||||
| 		h & heroes & towns & availableHeroes & dwellings & bonuses & status & daysWithoutCastle; | ||||
| 		h & static_cast<CBonusSystemNode&>(*this); | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| @@ -153,7 +159,7 @@ struct DLL_EXPORT SiegeInfo | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| struct DLL_EXPORT BattleInfo | ||||
| struct DLL_EXPORT BattleInfo : public CBonusSystemNode | ||||
| { | ||||
| 	ui8 side1, side2; //side1 - attacker, side2 - defender | ||||
| 	si32 round, activeStack; | ||||
| @@ -161,7 +167,7 @@ struct DLL_EXPORT BattleInfo | ||||
| 	si32 tid; //used during town siege - id of attacked town; -1 if not town defence | ||||
| 	int3 tile; //for background and bonuses | ||||
| 	CGHeroInstance *heroes[2]; | ||||
| 	CCreatureSet army1, army2; | ||||
| 	CArmedInstance *belligerents[2]; //may be same as heroes | ||||
| 	std::vector<CStack*> stacks; | ||||
| 	std::vector<CObstacleInstance> obstacles; | ||||
| 	ui8 castSpells[2]; //[0] - attacker, [1] - defender | ||||
| @@ -169,10 +175,16 @@ struct DLL_EXPORT BattleInfo | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & side1 & side2 & round & activeStack & siege & tid & tile & stacks & army1 & army2 & obstacles | ||||
| 		h & side1 & side2 & round & activeStack & siege & tid & tile & stacks & belligerents & obstacles | ||||
| 			& castSpells & si; | ||||
| 		h & heroes; | ||||
| 		h & static_cast<CBonusSystemNode&>(*this); | ||||
| 	} | ||||
|  | ||||
| 	////////////////////////////////////////////////////////////////////////// | ||||
| 	void getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root = NULL) const; | ||||
| 	////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| 	const CStack * getNextStack() const; //which stack will have turn after current one | ||||
| 	void getStackQueue(std::vector<const CStack *> &out, int howMany, int turn = 0, int lastMoved = -1) const; //returns stack in order of their movement action | ||||
| 	CStack * getStack(int stackID, bool onlyAlive = true); | ||||
| @@ -185,9 +197,6 @@ struct DLL_EXPORT BattleInfo | ||||
| 	std::pair< std::vector<int>, int > getPath(int start, int dest, bool*accessibility, bool flyingCreature, bool twoHex, bool attackerOwned); //returned value: pair<path, length>; length may be different than number of elements in path since flying vreatures jump between distant hexes | ||||
| 	std::vector<int> getAccessibility(int stackID, bool addOccupiable) const; //returns vector of accessible tiles (taking into account the creature range) | ||||
|  | ||||
| 	si8 Morale(const CStack * st) const; //get morale of stack with all modificators | ||||
| 	si8 Luck(const CStack * st) const; //get luck of stack with all modificators | ||||
|  | ||||
| 	bool isStackBlocked(int ID); //returns true if there is neighboring enemy stack | ||||
| 	static signed char mutualPosition(int hex1, int hex2); //returns info about mutual position of given hexes (-1 - they're distant, 0 - left top, 1 - right top, 2 - right, 3 - right bottom, 4 - left bottom, 5 - left) | ||||
| 	static std::vector<int> neighbouringTiles(int hex); | ||||
| @@ -196,7 +205,7 @@ struct DLL_EXPORT BattleInfo | ||||
| 	void calculateCasualties(std::map<ui32,si32> *casualties) const; //casualties are array of maps size 2 (attacker, defeneder), maps are (crid => amount) | ||||
| 	std::set<CStack*> getAttackedCreatures(const CSpell * s, int skillLevel, ui8 attackerOwner, int destinationTile); //calculates stack affected by given spell | ||||
| 	static int calculateSpellDuration(const CSpell * spell, const CGHeroInstance * caster); | ||||
| 	CStack * generateNewStack(const CGHeroInstance * owner, int creatureID, int amount, int stackID, bool attackerOwned, int slot, int /*TerrainTile::EterrainType*/ terrain, int position) const; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield | ||||
| 	CStack * generateNewStack(const CStackInstance &base, int stackID, bool attackerOwned, int slot, int /*TerrainTile::EterrainType*/ terrain, int position) const; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield | ||||
| 	ui32 getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const; //returns cost of given spell | ||||
| 	int hexToWallPart(int hex) const; //returns part of destructible wall / gate / keep under given hex or -1 if not found | ||||
| 	int lineToWallHex(int line) const; //returns hex with wall in given line | ||||
| @@ -206,27 +215,24 @@ struct DLL_EXPORT BattleInfo | ||||
| 	si8 hasWallPenalty(int stackID, int destHex); //determines if given stack has wall penalty shooting given pos | ||||
| }; | ||||
|  | ||||
| class DLL_EXPORT CStack | ||||
| class DLL_EXPORT CStack : public CStackInstance | ||||
| {  | ||||
| public: | ||||
| 	ui32 ID; //unique ID of stack | ||||
| 	CCreature * creature; | ||||
| 	ui32 amount, baseAmount; | ||||
| 	ui32 baseAmount; | ||||
| 	ui32 firstHPleft; //HP of first creature in stack | ||||
| 	ui8 owner, slot;  //owner - player colour (255 for neutrals), slot - position in garrison (may be 255 for neutrals/called creatures) | ||||
| 	ui8 attackerOwned; //if true, this stack is owned by attakcer (this one from left hand side of battle) | ||||
| 	si16 position; //position on battlefield; -2 - keep, -3 - lower tower, -4 - upper tower | ||||
| 	ui8 counterAttacks; //how many counter attacks can be performed more in this turn (by default set at the beginning of the round to 1) | ||||
| 	si16 shots; //how many shots left | ||||
| 	si8 morale, luck; //base stack luck/morale | ||||
|  | ||||
| 	std::vector<StackFeature> features; | ||||
| 	std::set<ECombatInfo> state; | ||||
| 	struct StackEffect | ||||
| 	{ | ||||
| 		ui16 id; //spell id | ||||
| 		ui8 level; //skill level | ||||
| 		ui16 turnsRemain;  | ||||
| 		si16 turnsRemain;  | ||||
| 		template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 		{ | ||||
| 			h & id & level & turnsRemain; | ||||
| @@ -234,39 +240,25 @@ public: | ||||
| 	}; | ||||
| 	std::vector<StackEffect> effects; | ||||
|  | ||||
| 	int valOfFeatures(StackFeature::ECombatFeatures type, int subtype = -1024, int turn = 0) const;//subtype -> subtype of bonus, if -1024 then any | ||||
| 	bool hasFeatureOfType(StackFeature::ECombatFeatures type, int subtype = -1024, int turn = 0) const; //determines if stack has a bonus of given type (and optionally subtype) | ||||
| 	//overrides | ||||
| 	const CCreature* getCreature() const {return type;} | ||||
|  | ||||
| 	CStack(CCreature * C, int A, int O, int I, bool AO, int S); //c-tor | ||||
| 	CStack() : ID(-1), creature(NULL), amount(-1), baseAmount(-1), firstHPleft(-1), owner(255), slot(255), attackerOwned(true), position(-1), counterAttacks(1) {} //c-tor | ||||
| 	CStack(const CStackInstance *base, int O, int I, bool AO, int S); //c-tor | ||||
| 	CStack() : ID(-1), baseAmount(-1), firstHPleft(-1), owner(255), slot(255), attackerOwned(true), position(-1), counterAttacks(1) {} //c-tor | ||||
| 	const StackEffect * getEffect(ui16 id, int turn = 0) const; //effect id (SP) | ||||
| 	ui8 howManyEffectsSet(ui16 id) const; //returns amount of effects with given id set for this stack | ||||
| 	bool willMove(int turn = 0) const; //if stack has remaining move this turn | ||||
| 	bool moved(int turn = 0) const; //if stack was already moved this turn | ||||
| 	bool canMove(int turn = 0) const; //if stack can move | ||||
| 	ui32 Speed(int turn = 0) const; //get speed of creature with all modificators | ||||
| 	si32 Attack() const; //get attack of stack with all modificators | ||||
| 	si32 Defense(bool withFrenzy = true) const; //get defense of stack with all modificators | ||||
| 	ui16 MaxHealth() const; //get max HP of stack with all modifiers | ||||
| 	template <typename Handler> void save(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & creature->idNumber; | ||||
| 	} | ||||
| 	template <typename Handler> void load(Handler &h, const int version) | ||||
| 	{ | ||||
| 		ui32 id; | ||||
| 		h & id; | ||||
| 		creature = &VLC->creh->creatures[id]; | ||||
| 		//features = creature->abilities; | ||||
| 	} | ||||
|  | ||||
| 	bool doubleWide() const; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & ID & amount & baseAmount & firstHPleft & owner & slot & attackerOwned & position & state & counterAttacks | ||||
| 			& shots & morale & luck & features; | ||||
| 		if(h.saving) | ||||
| 			save(h,version); | ||||
| 		else | ||||
| 			load(h,version); | ||||
| 		h & static_cast<CStackInstance&>(*this); | ||||
| 		h & ID & baseAmount & firstHPleft & owner & slot & attackerOwned & position & state & counterAttacks | ||||
| 			& shots; | ||||
| 	} | ||||
| 	bool alive() const //determines if stack is alive | ||||
| 	{ | ||||
| @@ -363,6 +355,7 @@ public: | ||||
| 	std::map<ui8, PlayerState> players; //ID <-> player state | ||||
| 	std::map<int, CGDefInfo*> villages, forts, capitols; //def-info for town graphics | ||||
| 	std::vector<ui32> resVals; //default values of resources in gold | ||||
| 	CBonusSystemNode globalEffects; | ||||
|  | ||||
| 	struct DLL_EXPORT HeroesPool | ||||
| 	{ | ||||
| @@ -378,7 +371,6 @@ public: | ||||
| 	} hpool; //we have here all heroes available on this map that are not hired | ||||
|  | ||||
| 	boost::shared_mutex *mx; | ||||
|  | ||||
| 	PlayerState *getPlayer(ui8 color, bool verbose = true); | ||||
| 	const PlayerState *getPlayer(ui8 color, bool verbose = true) const; | ||||
| 	void init(StartInfo * si, Mapa * map, int Seed); | ||||
| @@ -424,7 +416,7 @@ public: | ||||
| 	int getDate(int mode=0) const; //mode=0 - total days in game, mode=1 - day of week, mode=2 - current week, mode=3 - current month | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & scenarioOps & seed & currentPlayer & day & map & players & resVals & hpool; | ||||
| 		h & scenarioOps & seed & currentPlayer & day & map & players & resVals & hpool & globalEffects; | ||||
| 		if(!h.saving) | ||||
| 		{ | ||||
| 			loadTownDInfos(); | ||||
|   | ||||
| @@ -14,6 +14,8 @@ | ||||
| #include "CGameState.h" | ||||
| #include "map.h" | ||||
| #include "../hch/CObjectHandler.h" | ||||
| #include "../hch/CCreatureHandler.h" | ||||
| #include "VCMI_Lib.h" | ||||
|  | ||||
|  | ||||
| /* | ||||
| @@ -202,6 +204,7 @@ void CConnection::close() | ||||
| 	} | ||||
| } | ||||
|  | ||||
|  | ||||
| CGObjectInstance *CConnection::loadObject() | ||||
| { | ||||
| 	assert(gs); | ||||
| @@ -218,6 +221,20 @@ void CConnection::saveObject( const CGObjectInstance *data ) | ||||
| 	*this << data->id; | ||||
| } | ||||
|  | ||||
| CCreature * CConnection::loadCreature() | ||||
| { | ||||
| 	si32 id; | ||||
| 	*this >> id; | ||||
| 	assert(id >= 0 && id < VLC->creh->creatures.size()); | ||||
| 	return VLC->creh->creatures[id]; | ||||
| } | ||||
|  | ||||
| void CConnection::saveCreature(const CCreature *data) | ||||
| { | ||||
| 	assert(data); | ||||
| 	*this << data->idNumber; | ||||
| } | ||||
|  | ||||
| void CConnection::setGS( CGameState *state ) | ||||
| { | ||||
| 	gs = state; | ||||
|   | ||||
| @@ -25,6 +25,7 @@ const ui32 version = 719; | ||||
| class CConnection; | ||||
| class CGObjectInstance; | ||||
| class CGameState; | ||||
| class CCreature; | ||||
| namespace mpl = boost::mpl; | ||||
|  | ||||
| /* | ||||
| @@ -740,6 +741,8 @@ public: | ||||
|  | ||||
| 	CGObjectInstance *loadObject(); //reads id from net and returns that obj | ||||
| 	void saveObject(const CGObjectInstance *data); | ||||
| 	CCreature *loadCreature(); //reads id from net and returns that obj | ||||
| 	void saveCreature(const CCreature *data); | ||||
|  | ||||
|  | ||||
| 	template<typename T> | ||||
| @@ -751,6 +754,14 @@ public: | ||||
| 		} | ||||
| 	}; | ||||
| 	template<typename T> | ||||
| 	struct loadCreatureHelper | ||||
| 	{ | ||||
| 		static void invoke(CConnection &s, T &data, ui16 tid) | ||||
| 		{ | ||||
| 			data = static_cast<T>(s.loadCreature()); | ||||
| 		} | ||||
| 	}; | ||||
| 	template<typename T> | ||||
| 	struct loadRestHelper | ||||
| 	{ | ||||
| 		static void invoke(CConnection &s, T &data, ui16 tid) | ||||
| @@ -768,6 +779,15 @@ public: | ||||
| 		} | ||||
| 	}; | ||||
| 	template<typename T> | ||||
| 	struct saveCreatureHelper | ||||
| 	{ | ||||
| 		static void invoke(CConnection &s, const T &data, ui16 tid) | ||||
| 		{ | ||||
| 			//CGObjectInstance *&hlp = const_cast<CGObjectInstance*&>(data); //for loading pointer to const obj we must remove the qualifier | ||||
| 			s.saveCreature(data); | ||||
| 		} | ||||
| 	}; | ||||
| 	template<typename T> | ||||
| 	struct saveRestHelper | ||||
| 	{ | ||||
| 		static void invoke(CConnection &s, const T &data, ui16 tid) | ||||
| @@ -785,9 +805,12 @@ public: | ||||
| 			//if | ||||
| 			mpl::eval_if< boost::is_base_of<CGObjectInstance, typename boost::remove_pointer<T>::type>, | ||||
| 			mpl::identity<loadObjectHelper<T> >, | ||||
| 			//else if | ||||
| 			mpl::eval_if< boost::is_base_of<CCreature, typename boost::remove_pointer<T>::type>, | ||||
| 			mpl::identity<loadCreatureHelper<T> >, | ||||
| 			//else | ||||
| 			mpl::identity<loadRestHelper<T> > | ||||
| 			>::type typex; | ||||
| 			> >::type typex; | ||||
| 		typex::invoke(*this, data, tid); | ||||
| 	} | ||||
|  | ||||
| @@ -799,9 +822,12 @@ public: | ||||
| 			//if | ||||
| 			mpl::eval_if< boost::is_base_of<CGObjectInstance, typename boost::remove_pointer<T>::type>, | ||||
| 				mpl::identity<saveObjectHelper<T> >, | ||||
| 			//else if | ||||
| 			mpl::eval_if< boost::is_base_of<CCreature, typename boost::remove_pointer<T>::type>, | ||||
| 			mpl::identity<saveCreatureHelper<T> >, | ||||
| 			//else | ||||
| 				mpl::identity<saveRestHelper<T> > | ||||
| 			>::type typex; | ||||
| 			> >::type typex; | ||||
| 		typex::invoke(*this, data, tid); | ||||
| 	} | ||||
| }; | ||||
|   | ||||
| @@ -1,156 +1,265 @@ | ||||
| #define VCMI_DLL | ||||
| #include "HeroBonus.h" | ||||
| #include <boost/foreach.hpp> | ||||
| #include "VCMI_Lib.h" | ||||
| #include "../hch/CSpellHandler.h" | ||||
| #include <sstream> | ||||
| #include "../hch/CCreatureHandler.h" | ||||
|  | ||||
| #define FOREACH_PARENT(pname) 	TCNodes parents; getParents(parents); BOOST_FOREACH(const CBonusSystemNode *pname, parents) | ||||
| #define FOREACH_CONST_PARENT(pname, source) 	TCNodes parents; getParents(parents, source); BOOST_FOREACH(const CBonusSystemNode *pname, parents) | ||||
| #define FOREACH_PARENT(pname, source) 	TNodes parents; getParents(parents, source); BOOST_FOREACH(CBonusSystemNode *pname, parents) | ||||
|  | ||||
| int BonusList::valOfBonuses( HeroBonus::BonusType type, int subtype /*= -1*/ ) const /*subtype -> subtype of bonus, if -1 then any */ | ||||
| int DLL_EXPORT BonusList::totalValue() const | ||||
| { | ||||
| 	if(!this) //to avoid null-checking in maany places -> no bonus list means 0 bonus value | ||||
| 		return 0; | ||||
| 	int base = 0; | ||||
| 	int percentToBase = 0; | ||||
| 	int percentToAll = 0; | ||||
| 	int additive = 0; | ||||
|  | ||||
| 	int ret = 0; | ||||
| 	if(subtype == -1) | ||||
| 	for(const_iterator i = begin(); i != end(); i++) | ||||
| 	{ | ||||
| 		for(const_iterator i = begin(); i != end(); i++) | ||||
| 			if(i->type == type) | ||||
| 				ret += i->val; | ||||
| 		switch(i->valType) | ||||
| 		{ | ||||
| 		case Bonus::BASE_NUMBER: | ||||
| 			base += i->val; | ||||
| 			break; | ||||
| 		case Bonus::PERCENT_TO_ALL: | ||||
| 			percentToAll += i->val; | ||||
| 			break; | ||||
| 		case Bonus::PERCENT_TO_BASE: | ||||
| 			percentToBase += i->val; | ||||
| 			break; | ||||
| 		case Bonus::ADDITIVE_VALUE: | ||||
| 			additive += i->val; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		for(const_iterator i = begin(); i != end(); i++) | ||||
| 			if(i->type == type && i->subtype == subtype) | ||||
| 				ret += i->val; | ||||
| 	} | ||||
| 	return ret; | ||||
| 	int modifiedBase = base + (base * percentToBase) / 100; | ||||
| 	modifiedBase += additive; | ||||
| 	return (modifiedBase * (100 + percentToAll)) / 100; | ||||
| } | ||||
|  | ||||
| bool BonusList::hasBonusOfType( HeroBonus::BonusType type, int subtype /*= -1*/ ) const  | ||||
| const DLL_EXPORT Bonus * BonusList::getFirst(const CSelector &selector) const | ||||
| { | ||||
| 	if(!this) //to avoid null-checking in maany places -> no bonus list means there is no searched bonus | ||||
| 		return 0; | ||||
|  | ||||
| 	if(subtype == -1) //any subtype | ||||
| 	{ | ||||
| 		for(const_iterator i = begin(); i != end(); i++) | ||||
| 			if(i->type == type) | ||||
| 				return true; | ||||
| 	} | ||||
| 	else //given subtype | ||||
| 	{ | ||||
| 		for(const_iterator i = begin(); i != end(); i++) | ||||
| 			if(i->type == type && i->subtype == subtype) | ||||
| 				return true; | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| const HeroBonus * BonusList::getBonus( int from, int id ) const | ||||
| { | ||||
| 	if(!this) //to avoid null-checking in maany places -> no bonus list means bonus cannot be retreived | ||||
| 		return NULL; | ||||
|  | ||||
| 	for (const_iterator i = begin(); i != end(); i++) | ||||
| 		if(i->source == from  &&  i->id == id) | ||||
| 		if(selector(*i)) | ||||
| 			return &*i; | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| void BonusList::getModifiersWDescr( std::vector<std::pair<int,std::string> > &out, HeroBonus::BonusType type, int subtype /*= -1 */ ) const | ||||
| DLL_EXPORT Bonus * BonusList::getFirst(const CSelector &select) | ||||
| { | ||||
| 	if(!this) //to avoid null-checking in maany places -> no bonus list means nothing has to be done here | ||||
| 		return; | ||||
|  | ||||
| 	if(subtype == -1) | ||||
| 	{ | ||||
| 		for(const_iterator i = begin(); i != end(); i++) | ||||
| 			if(i->type == type) | ||||
| 				out.push_back(std::make_pair(i->val, i->description)); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		for(const_iterator i = begin(); i != end(); i++) | ||||
| 			if(i->type == type && i->subtype == subtype) | ||||
| 				out.push_back(std::make_pair(i->val, i->description)); | ||||
| 	} | ||||
| 	for (iterator i = begin(); i != end(); i++) | ||||
| 		if(select(*i)) | ||||
| 			return &*i; | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| int CBonusSystemNode::valOfBonuses(HeroBonus::BonusType type, int subtype /*= -1*/) const | ||||
| void DLL_EXPORT BonusList::getModifiersWDescr(TModDescr &out) const | ||||
| { | ||||
| 	int ret = bonuses.valOfBonuses(type, subtype); | ||||
|  | ||||
| 	FOREACH_PARENT(p) | ||||
| 		ret += p->valOfBonuses(type, subtype); | ||||
|  | ||||
| 	return ret; | ||||
| 	for(const_iterator i = begin(); i != end(); i++) | ||||
| 		out.push_back(std::make_pair(i->val, i->Description())); | ||||
| } | ||||
|  | ||||
| bool CBonusSystemNode::hasBonusOfType(HeroBonus::BonusType type, int subtype /*= -1*/) const | ||||
| void DLL_EXPORT BonusList::getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *source /*= NULL*/) const | ||||
| { | ||||
| 	if(!this) //to allow calls on NULL and avoid checking duplication | ||||
| 		return false; //if hero doesn't exist then bonus neither can | ||||
|  | ||||
| 	if(bonuses.hasBonusOfType(type, subtype)) | ||||
| 		return true; | ||||
|  | ||||
| 	FOREACH_PARENT(p) | ||||
| 		if(p->hasBonusOfType(type, subtype)) | ||||
| 			return true; | ||||
|  | ||||
| 	return false; | ||||
| 	for(const_iterator i = begin(); i != end(); i++) | ||||
| 		if(selector(*i) && i->effectRange == Bonus::NO_LIMIT) | ||||
| 			out.push_back(*i); | ||||
| } | ||||
|  | ||||
| const HeroBonus * CBonusSystemNode::getBonus(int from, int id) const | ||||
| void DLL_EXPORT BonusList::getBonuses(BonusList &out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *source /*= NULL*/) const | ||||
| { | ||||
| 	return bonuses.getBonus(from, id); | ||||
| 	for(const_iterator i = begin(); i != end(); i++) | ||||
| 		if(selector(*i) && (!limit || limit(*i))) | ||||
| 			out.push_back(*i); | ||||
| } | ||||
|  | ||||
| void CBonusSystemNode::getModifiersWDescr(std::vector<std::pair<int,std::string> > &out, HeroBonus::BonusType type, int subtype /*= -1 */) const | ||||
| int CBonusSystemNode::valOfBonuses(Bonus::BonusType type, int subtype /*= -1*/) const | ||||
| { | ||||
| 	bonuses.getModifiersWDescr(out, type, subtype); | ||||
| 	CSelector s = Selector::type(type); | ||||
| 	if(subtype != -1) | ||||
| 		s = s && Selector::subtype(subtype); | ||||
|  | ||||
| 	FOREACH_PARENT(p) | ||||
| 		p->getModifiersWDescr(out, type, subtype); | ||||
| 	return valOfBonuses(s); | ||||
| } | ||||
|  | ||||
| int CBonusSystemNode::valOfBonuses(Bonus::BonusType type, const CSelector &selector) const | ||||
| { | ||||
| 	return valOfBonuses(Selector::type(type) && selector); | ||||
| } | ||||
|  | ||||
| int CBonusSystemNode::valOfBonuses(const CSelector &selector, const CBonusSystemNode *root/* = NULL*/) const | ||||
| { | ||||
| 	BonusList hlp; | ||||
| 	getBonuses(hlp, selector, root); | ||||
| 	return hlp.totalValue(); | ||||
| } | ||||
|  | ||||
| bool CBonusSystemNode::hasBonus(const CSelector &selector, const CBonusSystemNode *root/* = NULL*/) const | ||||
| { | ||||
| 	return getBonuses(selector).size() > 0; | ||||
| } | ||||
|  | ||||
| bool CBonusSystemNode::hasBonusOfType(Bonus::BonusType type, int subtype /*= -1*/) const | ||||
| { | ||||
| 	CSelector s = Selector::type(type); | ||||
| 	if(subtype != -1) | ||||
| 		s = s && Selector::subtype(subtype); | ||||
|  | ||||
| 	return hasBonus(s); | ||||
| } | ||||
|  | ||||
| Bonus * CBonusSystemNode::getBonus(const CSelector &selector) | ||||
| { | ||||
| 	Bonus *ret = bonuses.getFirst(selector); | ||||
| 	if(ret) | ||||
| 		return ret; | ||||
|  | ||||
| 	FOREACH_PARENT(p, this) | ||||
| 		if(ret = p->getBonus(selector)) | ||||
| 			return ret; | ||||
|  | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| void CBonusSystemNode::getModifiersWDescr(TModDescr &out, Bonus::BonusType type, int subtype /*= -1 */) const | ||||
| { | ||||
| 	getModifiersWDescr(out, Selector::typeSybtype(type, subtype)); | ||||
| } | ||||
|  | ||||
| void CBonusSystemNode::getModifiersWDescr(TModDescr &out, const CSelector &selector, const CBonusSystemNode *root /*= NULL*/) const | ||||
| { | ||||
| 	getBonuses(selector).getModifiersWDescr(out); | ||||
| } | ||||
| int CBonusSystemNode::getBonusesCount(int from, int id) const | ||||
| { | ||||
| 	int ret = 0; | ||||
|  | ||||
| 	BOOST_FOREACH(const HeroBonus &hb, bonuses) | ||||
| 		if(hb.source == from  &&  hb.id == id) | ||||
| 			ret++; | ||||
|  | ||||
| 	return ret; | ||||
| 	return getBonusesCount(Selector::source(from, id)); | ||||
| } | ||||
|  | ||||
| void CBonusSystemNode::getParents(TCNodes &out, const CBonusSystemNode *source) const /*retreives list of parent nodes (nodes to inherit bonuses from) */ | ||||
| int CBonusSystemNode::getBonusesCount(const CSelector &selector, const CBonusSystemNode *root/* = NULL*/) const | ||||
| { | ||||
| 	return getBonuses(selector, root).size(); | ||||
| } | ||||
|  | ||||
| void CBonusSystemNode::getParents(TCNodes &out, const CBonusSystemNode *root) const /*retreives list of parent nodes (nodes to inherit bonuses from) */ | ||||
| { | ||||
| 	return; | ||||
| } | ||||
|  | ||||
| int NBonus::valOf(const CBonusSystemNode *obj, HeroBonus::BonusType type, int subtype /*= -1*/) | ||||
| void CBonusSystemNode::getParents(TNodes &out, const CBonusSystemNode *root /*= NULL*/) | ||||
| { | ||||
| 	//de-constify above | ||||
| 	TCNodes hlp; | ||||
| 	getParents(hlp, root); | ||||
| 	BOOST_FOREACH(const CBonusSystemNode *pname, hlp) | ||||
| 		out.insert(const_cast<CBonusSystemNode*>(pname)); | ||||
| } | ||||
|  | ||||
| void CBonusSystemNode::getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root /*= NULL*/) const | ||||
| { | ||||
| 	bonuses.getBonuses(out, selector); | ||||
| 	FOREACH_CONST_PARENT(p, root ? root : this) | ||||
| 		p->getBonuses(out, selector, root ? root : this); | ||||
| } | ||||
|  | ||||
| BonusList CBonusSystemNode::getBonuses(const CSelector &selector, const CBonusSystemNode *root /*= NULL*/) const | ||||
| { | ||||
| 	BonusList ret; | ||||
| 	getBonuses(ret, selector, root); | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| void CBonusSystemNode::getBonuses(BonusList &out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root /*= NULL*/) const | ||||
| { | ||||
| 	bonuses.getBonuses(out, selector, limit); | ||||
| 	FOREACH_CONST_PARENT(p, root ? root : this) | ||||
| 		p->getBonuses(out, selector, limit, root ? root : this); | ||||
| } | ||||
|  | ||||
| BonusList CBonusSystemNode::getBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root /*= NULL*/) const | ||||
| { | ||||
| 	BonusList ret; | ||||
| 	getBonuses(ret, selector, limit, root); | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| bool CBonusSystemNode::hasBonusFrom(ui8 source, ui32 sourceID) const | ||||
| { | ||||
| 	return hasBonus(Selector::source(source,sourceID)); | ||||
| } | ||||
|  | ||||
| int CBonusSystemNode::MoraleVal() const | ||||
| { | ||||
| 	if(hasBonusOfType(Bonus::NON_LIVING) || hasBonusOfType(Bonus::UNDEAD) || | ||||
| 		hasBonusOfType(Bonus::NO_MORALE) || hasBonusOfType(Bonus::SIEGE_WEAPON)) | ||||
| 		return 0; | ||||
|  | ||||
| 	int ret = valOfBonuses(Selector::type(Bonus::MORALE)); | ||||
|  | ||||
| 	if(hasBonusOfType(Bonus::SELF_MORALE)) //eg. minotaur | ||||
| 		amax(ret, +1); | ||||
|  | ||||
| 	return abetw(ret, -3, +3); | ||||
| } | ||||
|  | ||||
| int CBonusSystemNode::LuckVal() const | ||||
| { | ||||
| 	if(hasBonusOfType(Bonus::NO_LUCK)) | ||||
| 		return 0; | ||||
|  | ||||
| 	int ret = valOfBonuses(Selector::type(Bonus::LUCK)); | ||||
| 	 | ||||
| 	if(hasBonusOfType(Bonus::SELF_LUCK)) //eg. halfling | ||||
| 		amax(ret, +1); | ||||
|  | ||||
| 	return abetw(ret, -3, +3); | ||||
| } | ||||
|  | ||||
| si32 CBonusSystemNode::Attack() const | ||||
| { | ||||
| 	si32 ret = valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK); | ||||
|  | ||||
| 	if(int frenzyPower = valOfBonuses(Bonus::IN_FRENZY)) //frenzy for attacker | ||||
| 	{ | ||||
| 		ret += frenzyPower * Defense(false); | ||||
| 	} | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| si32 CBonusSystemNode::Defense(bool withFrenzy /*= true*/) const | ||||
| { | ||||
| 	si32 ret = valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE); | ||||
|  | ||||
| 	if(withFrenzy && hasBonusOfType(Bonus::IN_FRENZY)) //frenzy for defender | ||||
| 	{ | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| ui16 CBonusSystemNode::MaxHealth() const | ||||
| { | ||||
| 	return valOfBonuses(Bonus::STACK_HEALTH); | ||||
| } | ||||
|  | ||||
| int NBonus::valOf(const CBonusSystemNode *obj, Bonus::BonusType type, int subtype /*= -1*/) | ||||
| { | ||||
| 	if(obj) | ||||
| 		return obj->valOfBonuses(type, subtype); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| bool NBonus::hasOfType(const CBonusSystemNode *obj, HeroBonus::BonusType type, int subtype /*= -1*/) | ||||
| bool NBonus::hasOfType(const CBonusSystemNode *obj, Bonus::BonusType type, int subtype /*= -1*/) | ||||
| { | ||||
| 	if(obj) | ||||
| 		return obj->hasBonusOfType(type, subtype); | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| const HeroBonus * NBonus::get(const CBonusSystemNode *obj, int from, int id) | ||||
| { | ||||
| 	if(obj) | ||||
| 		return obj->getBonus(from, id); | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| void NBonus::getModifiersWDescr(const CBonusSystemNode *obj, std::vector<std::pair<int,std::string> > &out, HeroBonus::BonusType type, int subtype /*= -1 */) | ||||
| void NBonus::getModifiersWDescr(const CBonusSystemNode *obj, TModDescr &out, Bonus::BonusType type, int subtype /*= -1 */) | ||||
| { | ||||
| 	if(obj) | ||||
| 		return obj->getModifiersWDescr(out, type, subtype); | ||||
| @@ -161,4 +270,72 @@ int NBonus::getCount(const CBonusSystemNode *obj, int from, int id) | ||||
| 	if(obj) | ||||
| 		return obj->getBonusesCount(from, id); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| const CSpell * Bonus::sourceSpell() const | ||||
| { | ||||
| 	if(source == SPELL_EFFECT) | ||||
| 		return &VLC->spellh->spells[id]; | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| std::string Bonus::Description() const | ||||
| { | ||||
| 	if(description.size()) | ||||
| 		return description; | ||||
|  | ||||
| 	std::ostringstream str; | ||||
| 	if(val < 0) | ||||
| 		str << '-'; | ||||
| 	else if(val > 0) | ||||
| 		str << '+'; | ||||
|  | ||||
| 	str << val << " "; | ||||
|  | ||||
| 	switch(source) | ||||
| 	{ | ||||
| 	case CREATURE_ABILITY: | ||||
| 		str << VLC->creh->creatures[id]->namePl; | ||||
| 		break; | ||||
| 	} | ||||
| 	 | ||||
| 	return str.str(); | ||||
| } | ||||
|  | ||||
| CSelector DLL_EXPORT operator&&(const CSelector &first, const CSelector &second) | ||||
| { | ||||
| 	return CSelectorsConjunction(first, second); | ||||
| } | ||||
|  | ||||
|  | ||||
| namespace Selector | ||||
| { | ||||
| 	DLL_EXPORT CSelectFieldEqual<TBonusType> type(&Bonus::type, 0); | ||||
| 	DLL_EXPORT CSelectFieldEqual<TBonusSubtype> subtype(&Bonus::subtype, 0); | ||||
| 	DLL_EXPORT CSelectFieldEqual<si32> info(&Bonus::additionalInfo, 0); | ||||
| 	DLL_EXPORT CSelectFieldEqual<ui8> sourceType(&Bonus::source, 0); | ||||
| 	DLL_EXPORT CSelectFieldEqual<ui8> effectRange(&Bonus::effectRange, Bonus::NO_LIMIT); | ||||
| 	DLL_EXPORT CWillLastTurns turns;; | ||||
|  | ||||
| 	CSelector DLL_EXPORT typeSybtype(TBonusType Type, TBonusSubtype Subtype) | ||||
| 	{ | ||||
| 		return type(Type) && subtype(Subtype); | ||||
| 	} | ||||
|  | ||||
| 	CSelector DLL_EXPORT typeSybtypeInfo(TBonusType type, TBonusSubtype subtype, si32 info) | ||||
| 	{ | ||||
| 		return CSelectFieldEqual<TBonusType>(&Bonus::type, type) && CSelectFieldEqual<TBonusSubtype>(&Bonus::subtype, subtype) && CSelectFieldEqual<si32>(&Bonus::additionalInfo, info); | ||||
| 	} | ||||
|  | ||||
| 	CSelector DLL_EXPORT source(ui8 source, ui32 sourceID) | ||||
| 	{ | ||||
| 		return CSelectFieldEqual<ui8>(&Bonus::source, source) && CSelectFieldEqual<ui32>(&Bonus::id, sourceID); | ||||
| 	} | ||||
|  | ||||
| 	bool matchesType(const CSelector &sel, TBonusType type) | ||||
| 	{ | ||||
| 		Bonus dummy; | ||||
| 		dummy.type = type; | ||||
| 		return sel(dummy); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										451
									
								
								lib/HeroBonus.h
									
									
									
									
									
								
							
							
						
						
									
										451
									
								
								lib/HeroBonus.h
									
									
									
									
									
								
							| @@ -2,6 +2,8 @@ | ||||
| #include "../global.h" | ||||
| #include <string> | ||||
| #include <list> | ||||
| #include <set> | ||||
| #include <boost/function.hpp> | ||||
|  | ||||
| /* | ||||
|  * HeroBonus.h, part of VCMI engine | ||||
| @@ -13,68 +15,226 @@ | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| struct DLL_EXPORT HeroBonus | ||||
|  | ||||
| typedef ui8 TBonusType; | ||||
| typedef si32 TBonusSubtype; | ||||
|  | ||||
|  | ||||
| class CSpell; | ||||
| struct Bonus; | ||||
| class CBonusSystemNode; | ||||
|  | ||||
| typedef std::vector<std::pair<int,std::string> > TModDescr; //modifiers values and their descriptions | ||||
| typedef std::set<CBonusSystemNode*> TNodes; | ||||
| typedef std::set<const CBonusSystemNode*> TCNodes; | ||||
| typedef boost::function<bool(const Bonus&)> CSelector; | ||||
|  | ||||
|  | ||||
| namespace PrimarySkill | ||||
| { | ||||
| 	enum { ATTACK, DEFENSE, SPELL_POWER, KNOWLEDGE}; | ||||
| } | ||||
|  | ||||
| #define BONUS_LIST										\ | ||||
| 	BONUS_NAME(NONE) 									\ | ||||
| 	BONUS_NAME(MOVEMENT) /*both water/land*/			\ | ||||
| 	BONUS_NAME(LAND_MOVEMENT) \ | ||||
| 	BONUS_NAME(SEA_MOVEMENT) \ | ||||
| 	BONUS_NAME(MORALE) \ | ||||
| 	BONUS_NAME(LUCK) \ | ||||
| 	BONUS_NAME(PRIMARY_SKILL) /*uses subtype to pick skill; additional info if set: 1 - only melee, 2 - only distance*/  \ | ||||
| 	BONUS_NAME(SIGHT_RADIOUS) \ | ||||
| 	BONUS_NAME(MANA_REGENERATION) /*points per turn apart from normal (1 + mysticism)*/  \ | ||||
| 	BONUS_NAME(FULL_MANA_REGENERATION) /*all mana points are replenished every day*/  \ | ||||
| 	BONUS_NAME(NONEVIL_ALIGNMENT_MIX) /*good and neutral creatures can be mixed without morale penalty*/  \ | ||||
| 	BONUS_NAME(SECONDARY_SKILL_PREMY) /*%*/  \ | ||||
| 	BONUS_NAME(SURRENDER_DISCOUNT) /*%*/  \ | ||||
| 	BONUS_NAME(STACKS_SPEED)  /*additional info - percent of speed bonus applied after direct bonuses; >0 - added, <0 - substracted to this part*/ \ | ||||
| 	BONUS_NAME(FLYING_MOVEMENT) \ | ||||
| 	BONUS_NAME(SPELL_DURATION) \ | ||||
| 	BONUS_NAME(AIR_SPELL_DMG_PREMY) \ | ||||
| 	BONUS_NAME(EARTH_SPELL_DMG_PREMY) \ | ||||
| 	BONUS_NAME(FIRE_SPELL_DMG_PREMY) \ | ||||
| 	BONUS_NAME(WATER_SPELL_DMG_PREMY) \ | ||||
| 	BONUS_NAME(BLOCK_SPELLS_ABOVE_LEVEL) \ | ||||
| 	BONUS_NAME(WATER_WALKING) \ | ||||
| 	BONUS_NAME(NO_SHOTING_PENALTY) \ | ||||
| 	BONUS_NAME(DISPEL_IMMUNITY) \ | ||||
| 	BONUS_NAME(NEGATE_ALL_NATURAL_IMMUNITIES) \ | ||||
| 	BONUS_NAME(STACK_HEALTH) \ | ||||
| 	BONUS_NAME(BLOCK_MORALE) \ | ||||
| 	BONUS_NAME(BLOCK_LUCK) \ | ||||
| 	BONUS_NAME(FIRE_SPELLS) \ | ||||
| 	BONUS_NAME(AIR_SPELLS) \ | ||||
| 	BONUS_NAME(WATER_SPELLS) \ | ||||
| 	BONUS_NAME(EARTH_SPELLS) \ | ||||
| 	BONUS_NAME(GENERATE_RESOURCE) /*daily value, uses subtype (resource type)*/  \ | ||||
| 	BONUS_NAME(CREATURE_GROWTH) /*for legion artifacts: value - week growth bonus, subtype - monster level*/  \ | ||||
| 	BONUS_NAME(WHIRLPOOL_PROTECTION) /*hero won't lose army when teleporting through whirlpool*/  \ | ||||
| 	BONUS_NAME(SPELL) /*hero knows spell, val - skill level (0 - 3), subtype - spell id*/  \ | ||||
| 	BONUS_NAME(SPELLS_OF_LEVEL) /*hero knows all spells of given level, val - skill level; subtype - level*/  \ | ||||
| 	BONUS_NAME(ENEMY_CANT_ESCAPE) /*for shackles of war*/ \ | ||||
| 	BONUS_NAME(MAGIC_SCHOOL_SKILL) /* //eg. for magic plains terrain, subtype: school of magic (0 - all, 1 - fire, 2 - air, 4 - water, 8 - earth), value - level*/ \ | ||||
| 	BONUS_NAME(FREE_SHOOTING) /*stacks can shoot even if otherwise blocked (sharpshooter's bow effect)*/ \ | ||||
| 	BONUS_NAME(OPENING_BATTLE_SPELL) /*casts a spell at expert level at beginning of battle, val - spell power, subtype - spell id*/ \ | ||||
| 	BONUS_NAME(IMPROVED_NECROMANCY) /*allows Necropolis units other than skeletons to be raised by necromancy*/ \ | ||||
| 	BONUS_NAME(CREATURE_GROWTH_PERCENT) /*increases growth of all units in all towns, val - percentage*/ \ | ||||
| 	BONUS_NAME(FREE_SHIP_BOARDING) /*movement points preserved with ship boarding and landing*/  \ | ||||
| 	BONUS_NAME(NO_TYPE)									\ | ||||
| 	BONUS_NAME(FLYING)									\ | ||||
| 	BONUS_NAME(SHOOTER)									\ | ||||
| 	BONUS_NAME(CHARGE_IMMUNITY)							\ | ||||
| 	BONUS_NAME(ADDITIONAL_ATTACK)						\ | ||||
| 	BONUS_NAME(UNLIMITED_RETALIATIONS)					\ | ||||
| 	BONUS_NAME(NO_MELEE_PENALTY)						\ | ||||
| 	BONUS_NAME(JOUSTING) /*for champions*/				\ | ||||
| 	BONUS_NAME(HATE) /*eg. angels hate devils, subtype - ID of hated creature*/ \ | ||||
| 	BONUS_NAME(KING1)									\ | ||||
| 	BONUS_NAME(KING2)									\ | ||||
| 	BONUS_NAME(KING3)									\ | ||||
| 	BONUS_NAME(MAGIC_RESISTANCE) /*in % (value)*/		\ | ||||
| 	BONUS_NAME(CHANGES_SPELL_COST_FOR_ALLY) /*in mana points (value) , eg. mage*/ \ | ||||
| 	BONUS_NAME(CHANGES_SPELL_COST_FOR_ENEMY) /*in mana points (value) , eg. pegasus */ \ | ||||
| 	BONUS_NAME(SPELL_AFTER_ATTACK) /* subtype - spell id, value - spell level, (additional info)%1000 - chance in %; eg. dendroids, (additional info)/1000 -> [0 - all attacks, 1 - shot only, 2 - melee only*/ \ | ||||
| 	BONUS_NAME(SPELL_RESISTANCE_AURA) /*eg. unicorns, value - resistance bonus in % for adjacent creatures*/ \ | ||||
| 	BONUS_NAME(LEVEL_SPELL_IMMUNITY) /*creature is immune to all spell with level below or equal to value of this bonus*/ \ | ||||
| 	BONUS_NAME(TWO_HEX_ATTACK_BREATH) /*eg. dragons*/	\ | ||||
| 	BONUS_NAME(SPELL_DAMAGE_REDUCTION) /*eg. golems; value - reduction in %, subtype - spell school; -1 - all, 0 - air, 1 - fire, 2 - water, 3 - earth*/ \ | ||||
| 	BONUS_NAME(NO_WALL_PENALTY)							\ | ||||
| 	BONUS_NAME(NON_LIVING) /*eg. gargoyle*/				\ | ||||
| 	BONUS_NAME(RANDOM_GENIE_SPELLCASTER) /*eg. master genie*/ \ | ||||
| 	BONUS_NAME(BLOCKS_RETALIATION) /*eg. naga*/			\ | ||||
| 	BONUS_NAME(SPELL_IMMUNITY) /*subid - spell id*/		\ | ||||
| 	BONUS_NAME(MANA_CHANNELING) /*value in %, eg. familiar*/ \ | ||||
| 	BONUS_NAME(SPELL_LIKE_ATTACK) /*value - spell id; range is taken from spell, but damage from creature; eg. magog*/ \ | ||||
| 	BONUS_NAME(THREE_HEADED_ATTACK) /*eg. cerberus*/	\ | ||||
| 	BONUS_NAME(DAEMON_SUMMONING) /*pit lord*/			\ | ||||
| 	BONUS_NAME(FIRE_IMMUNITY)							\ | ||||
| 	BONUS_NAME(FIRE_SHIELD)								\ | ||||
| 	BONUS_NAME(UNDEAD)									\ | ||||
| 	BONUS_NAME(HP_REGENERATION) /*creature regenerates val HP every new round*/					\ | ||||
| 	BONUS_NAME(FULL_HP_REGENERATION) /*first creature regenerates all HP every new round; subtype 0 - animation 4 (trolllike), 1 - animation 47 (wightlike)*/		\ | ||||
| 	BONUS_NAME(MANA_DRAIN) /*value - spell points per turn*/ \ | ||||
| 	BONUS_NAME(LIFE_DRAIN)								\ | ||||
| 	BONUS_NAME(DOUBLE_DAMAGE_CHANCE) /*value in %, eg. dread knight*/ \ | ||||
| 	BONUS_NAME(RETURN_AFTER_STRIKE)						\ | ||||
| 	BONUS_NAME(SELF_MORALE) /*eg. minotaur*/			\ | ||||
| 	BONUS_NAME(SPELLCASTER) /*subtype - spell id, value - level of school, additional info - spell power*/ \ | ||||
| 	BONUS_NAME(CATAPULT)								\ | ||||
| 	BONUS_NAME(ENEMY_DEFENCE_REDUCTION) /*in % (value) eg. behemots*/ \ | ||||
| 	BONUS_NAME(GENERAL_DAMAGE_REDUCTION) /* shield / air shield effect */ \ | ||||
| 	BONUS_NAME(GENERAL_ATTACK_REDUCTION) /*eg. while stoned or blinded - in %, subtype: -1 - any damage, 0 - melee damage, 1 - ranged damage*/ \ | ||||
| 	BONUS_NAME(ATTACKS_ALL_ADJACENT) /*eg. hydra*/		\ | ||||
| 	BONUS_NAME(MORE_DAMAGE_FROM_SPELL) /*value - damage increase in %, subtype - spell id*/ \ | ||||
| 	BONUS_NAME(CASTS_SPELL_WHEN_KILLED) /*similar to spell after attack*/ \ | ||||
| 	BONUS_NAME(FEAR)									\ | ||||
| 	BONUS_NAME(FEARLESS)								\ | ||||
| 	BONUS_NAME(NO_DISTANCE_PENALTY)						\ | ||||
| 	BONUS_NAME(NO_OBSTACLES_PENALTY)					\ | ||||
| 	BONUS_NAME(SELF_LUCK) /*halfling*/					\ | ||||
| 	BONUS_NAME(ENCHANTER)								\ | ||||
| 	BONUS_NAME(HEALER)									\ | ||||
| 	BONUS_NAME(SIEGE_WEAPON)							\ | ||||
| 	BONUS_NAME(HYPNOTIZED)								\ | ||||
| 	BONUS_NAME(ADDITIONAL_RETALIATION) /*value - number of additional retaliations*/ \ | ||||
| 	BONUS_NAME(MAGIC_MIRROR) /* value - chance of redirecting in %*/ \ | ||||
| 	BONUS_NAME(ALWAYS_MINIMUM_DAMAGE) /*unit does its minimum damage from range; subtype: -1 - any attack, 0 - melee, 1 - ranged, value: additional damage, additional info - multiplicative anti-bonus for dmg in % [eg 20 means that creature will inflict 80% of normal dmg]*/ \ | ||||
| 	BONUS_NAME(ALWAYS_MAXIMUM_DAMAGE) /*eg. bless effect, subtype: -1 - any attack, 0 - melee, 1 - ranged, value: additional damage, additional info - multiplicative bonus for dmg in %*/ \ | ||||
| 	BONUS_NAME(ATTACKS_NEAREST_CREATURE) /*while in berserk*/ \ | ||||
| 	BONUS_NAME(IN_FRENZY) /*value - level*/				\ | ||||
| 	BONUS_NAME(SLAYER) /*value - level*/				\ | ||||
| 	BONUS_NAME(FORGETFULL) /*forgetfulness spell effect, value - level*/ \ | ||||
| 	BONUS_NAME(NOT_ACTIVE)								\ | ||||
| 	BONUS_NAME(NO_LUCK) /*eg. when fighting on cursed ground*/	\ | ||||
| 	BONUS_NAME(NO_MORALE) /*eg. when fighting on cursed ground*/ | ||||
|  | ||||
| struct DLL_EXPORT Bonus | ||||
| { | ||||
| 	enum BonusType | ||||
| 	{ | ||||
| 		//handled | ||||
| 		NONE,  | ||||
| 		MOVEMENT, //both water/land | ||||
| 		LAND_MOVEMENT,  | ||||
| 		SEA_MOVEMENT,  | ||||
| 		MORALE,  | ||||
| 		LUCK,  | ||||
| 		MORALE_AND_LUCK,  | ||||
| 		PRIMARY_SKILL, //uses subtype to pick skill | ||||
| 		SIGHT_RADIOUS,  | ||||
| 		MANA_REGENERATION, //points per turn apart from normal (1 + mysticism) | ||||
| 		FULL_MANA_REGENERATION, //all mana points are replenished every day | ||||
| 		NONEVIL_ALIGNMENT_MIX, //good and neutral creatures can be mixed without morale penalty | ||||
| 		HP_REGENERATION, //regenerates a certain amount of hp for the top of each stack every turn, val - hp regained | ||||
| 		LEVEL_SPELL_IMMUNITY, //val - spell level creatures become immune to and below | ||||
| 		//might not be handled yet: | ||||
| 		MAGIC_RESISTANCE, // % | ||||
| 		SECONDARY_SKILL_PREMY, //% | ||||
| 		SURRENDER_DISCOUNT, //% | ||||
| 		STACKS_SPEED, | ||||
| 		FLYING_MOVEMENT, SPELL_DURATION, AIR_SPELL_DMG_PREMY, EARTH_SPELL_DMG_PREMY, FIRE_SPELL_DMG_PREMY,  | ||||
| 		WATER_SPELL_DMG_PREMY, BLOCK_SPELLS_ABOVE_LEVEL, WATER_WALKING, NO_SHOTING_PENALTY, DISPEL_IMMUNITY,  | ||||
| 		NEGATE_ALL_NATURAL_IMMUNITIES, STACK_HEALTH, STACK_HEALTH_PERCENT, //the second one of stack health - value in % of base HP to be added to overall stack HP | ||||
| 		SPELL_IMMUNITY, BLOCK_MORALE, BLOCK_LUCK, FIRE_SPELLS, | ||||
| 		AIR_SPELLS, WATER_SPELLS, EARTH_SPELLS,  | ||||
| 		GENERATE_RESOURCE, //daily value, uses subtype (resource type) | ||||
| 		CREATURE_GROWTH, //for legion artifacts: value - week growth bonus, subtype - monster level | ||||
| 		WHIRLPOOL_PROTECTION, //hero won't lose army when teleporting through whirlpool | ||||
| 		SPELL, //hero knows spell, val - skill level (0 - 3), subtype - spell id | ||||
| 		SPELLS_OF_LEVEL, //hero knows all spells of given level, val - skill level; subtype - level | ||||
| 		ENEMY_CANT_ESCAPE, //for shackles of war | ||||
| 		MAGIC_SCHOOL_SKILL, //eg. for magic plains terrain, subtype: school of magic (0 - all, 1 - fire, 2 - air, 4 - water, 8 - earth), value - level | ||||
| 		FREE_SHOOTING, //stacks can shoot even if otherwise blocked (sharpshooter's bow effect) | ||||
| 		OPENING_BATTLE_SPELL, //casts a spell at expert level at beginning of battle, val - spell power, subtype - spell id | ||||
| 		IMPROVED_NECROMANCY, //allows Necropolis units other than skeletons to be raised by necromancy | ||||
| 		CREATURE_GROWTH_PERCENT, //increases growth of all units in all towns, val - percentage | ||||
| 		FREE_SHIP_BOARDING //movement points preserved with ship boarding and landing | ||||
| #define BONUS_NAME(x) x, | ||||
| 		BONUS_LIST | ||||
| #undef BONUS_NAME | ||||
| 	}; | ||||
| 	enum BonusDuration //when bonus is automatically removed | ||||
| 	{ | ||||
| 		PERMANENT = 1, | ||||
| 		ONE_BATTLE = 2, //at the end of battle  | ||||
| 		ONE_DAY = 4,   //at the end of day | ||||
| 		ONE_WEEK = 8, //at the end of week (bonus lasts till the end of week, thats NOT 7 days | ||||
| 		N_TURNS = 16, //used during battles, after battle bonus is always removed | ||||
| 		N_DAYS = 32, | ||||
| 		UNITL_BEING_ATTACKED = 64,/*removed after attack and counterattacks are performed*/ | ||||
| 		UNTIL_ATTACK = 128 /*removed after attack and counterattacks are performed*/ | ||||
| 	}; | ||||
| 	enum BonusSource | ||||
| 	{ | ||||
| 		ARTIFACT,  | ||||
| 		OBJECT,  | ||||
| 		CASTED_SPELL, | ||||
| 		CREATURE_ABILITY, | ||||
| 		TERRAIN_NATIVE, | ||||
| 		TERRAIN_OVERLAY, | ||||
| 		SPELL_EFFECT, | ||||
| 		TOWN_STRUCTURE, | ||||
| 		HERO_BASE_SKILL, | ||||
| 		SECONDARY_SKILL, | ||||
| 		ARMY | ||||
| 	}; | ||||
|  | ||||
| 	enum LimitEffect | ||||
| 	{ | ||||
| 		NO_LIMIT = 0,  | ||||
| 		ONLY_DISTANCE_FIGHT=1, ONLY_MELEE_FIGHT, //used to mark bonuses for attack/defense primary skills from spells like Precision (distance only) | ||||
| 		ONLY_ALLIED_ARMY, ONLY_ENEMY_ARMY | ||||
| 	}; | ||||
|  | ||||
| 	enum ValueType | ||||
| 	{ | ||||
| 		ADDITIVE_VALUE, | ||||
| 		BASE_NUMBER, | ||||
| 		PERCENT_TO_ALL, | ||||
| 		PERCENT_TO_BASE | ||||
| 	}; | ||||
| 	enum BonusDuration{PERMANENT, ONE_BATTLE, ONE_DAY, ONE_WEEK}; | ||||
| 	enum BonusSource{ARTIFACT, OBJECT, CASTED_SPELL}; | ||||
|  | ||||
| 	ui8 duration; //uses BonusDuration values | ||||
| 	ui8 type; //uses BonusType values - says to what is this bonus | ||||
| 	si32 subtype; //-1 if not applicable | ||||
| 	ui8 source;//uses BonusSource values - what gave that bonus | ||||
| 	si32 val;//for morale/luck [-3,+3], others any | ||||
| 	ui32 id; //id of object/artifact | ||||
| 	si16 turnsRemain; //used if duration is N_TURNS or N_DAYS | ||||
|  | ||||
| 	TBonusType type; //uses BonusType values - says to what is this bonus - 1 byte | ||||
| 	TBonusSubtype subtype; //-1 if not applicable - 4 bytes | ||||
|  | ||||
| 	ui8 source;//source type" uses BonusSource values - what gave that bonus | ||||
| 	ui32 id; //source id: id of object/artifact/spell | ||||
|  | ||||
| 	ui8 valType;  | ||||
| 	si32 val; | ||||
| 	si32 additionalInfo; | ||||
| 	ui8 effectRange; //if not NO_LIMIT, bonus will be ommitted by default | ||||
|  | ||||
| 	std::string description;  | ||||
|  | ||||
| 	HeroBonus(ui8 Dur, ui8 Type, ui8 Src, si32 Val, ui32 ID, std::string Desc, si32 Subtype=-1) | ||||
| 	Bonus(ui8 Dur, ui8 Type, ui8 Src, si32 Val, ui32 ID, std::string Desc, si32 Subtype=-1) | ||||
| 		:duration(Dur), type(Type), subtype(Subtype), source(Src), val(Val), id(ID), description(Desc)  | ||||
| 	{} | ||||
| 	HeroBonus(ui8 Dur, ui8 Type, ui8 Src, si32 Val, ui32 ID, si32 Subtype=-1) | ||||
| 		:duration(Dur), type(Type), subtype(Subtype), source(Src), val(Val), id(ID)  | ||||
| 	{} | ||||
| 	HeroBonus() | ||||
| 	{ | ||||
| 		additionalInfo = -1; | ||||
| 		turnsRemain = 0; | ||||
| 		valType = ADDITIVE_VALUE; | ||||
| 		effectRange = NO_LIMIT; | ||||
| 	} | ||||
| 	Bonus(ui8 Dur, ui8 Type, ui8 Src, si32 Val, ui32 ID, si32 Subtype=-1, ui8 ValType = ADDITIVE_VALUE) | ||||
| 		:duration(Dur), type(Type), subtype(Subtype), source(Src), val(Val), id(ID), valType(ValType) | ||||
| 	{ | ||||
| 		additionalInfo = -1; | ||||
| 		turnsRemain = 0; | ||||
| 		effectRange = NO_LIMIT; | ||||
| 	} | ||||
| 	Bonus() | ||||
| 	{ | ||||
| 		subtype = -1; | ||||
| 		additionalInfo = -1; | ||||
| 		turnsRemain = 0; | ||||
| 		valType = ADDITIVE_VALUE; | ||||
| 		effectRange = NO_LIMIT; | ||||
| 	} | ||||
|  | ||||
| // 	//comparison | ||||
| @@ -91,47 +251,57 @@ struct DLL_EXPORT HeroBonus | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & duration & type & subtype & source & val & id & description; | ||||
| 		h & duration & type & subtype & source & val & id & description & additionalInfo & turnsRemain & valType & effectRange; | ||||
| 	} | ||||
|  | ||||
| 	static bool OneDay(const HeroBonus &hb) | ||||
| 	static bool OneDay(const Bonus &hb) | ||||
| 	{ | ||||
| 		return hb.duration==HeroBonus::ONE_DAY; | ||||
| 		return hb.duration & Bonus::ONE_DAY; | ||||
| 	} | ||||
| 	static bool OneWeek(const HeroBonus &hb) | ||||
| 	static bool OneWeek(const Bonus &hb) | ||||
| 	{ | ||||
| 		return hb.duration==HeroBonus::ONE_WEEK; | ||||
| 		return hb.duration & Bonus::ONE_WEEK; | ||||
| 	} | ||||
| 	static bool OneBattle(const HeroBonus &hb) | ||||
| 	static bool OneBattle(const Bonus &hb) | ||||
| 	{ | ||||
| 		return hb.duration==HeroBonus::ONE_BATTLE; | ||||
| 		return hb.duration & Bonus::ONE_BATTLE; | ||||
| 	} | ||||
| 	static bool IsFrom(const HeroBonus &hb, ui8 source, ui32 id) //if id==0xffffff then id doesn't matter | ||||
| 	static bool UntilAttack(const Bonus &hb) | ||||
| 	{ | ||||
| 		return hb.duration & Bonus::UNTIL_ATTACK; | ||||
| 	} | ||||
| 	static bool UntilBeingAttacked(const Bonus &hb) | ||||
| 	{ | ||||
| 		return hb.duration & Bonus::UNITL_BEING_ATTACKED; | ||||
| 	} | ||||
| 	static bool IsFrom(const Bonus &hb, ui8 source, ui32 id) //if id==0xffffff then id doesn't matter | ||||
| 	{ | ||||
| 		return hb.source==source && (id==0xffffff  ||  hb.id==id); | ||||
| 	} | ||||
|  	inline bool operator == (const BonusType & cf) const | ||||
|  	{ | ||||
|  		return type == cf; | ||||
|  	} | ||||
| 	const CSpell * sourceSpell() const; | ||||
|  | ||||
| 	std::string Description() const; | ||||
| }; | ||||
|  | ||||
| class CBonusSystemNode; | ||||
|  | ||||
| static const HeroBonus::BonusType MORALE_AFFECTING[] =  {HeroBonus::MORALE, HeroBonus::MORALE_AND_LUCK}; | ||||
| static const HeroBonus::BonusType LUCK_AFFECTING[] =  {HeroBonus::LUCK, HeroBonus::MORALE_AND_LUCK}; | ||||
| typedef std::vector<std::pair<int,std::string> > TModDescr; //modifiers values and their descriptions | ||||
| typedef std::list<CBonusSystemNode*> TNodes; | ||||
| typedef std::list<const CBonusSystemNode*> TCNodes; | ||||
|  | ||||
| class BonusList : public std::list<HeroBonus> | ||||
| class BonusList : public std::list<Bonus> | ||||
| { | ||||
| public: | ||||
| 	int DLL_EXPORT valOfBonuses(HeroBonus::BonusType type, int subtype = -1) const; //subtype -> subtype of bonus, if -1 then any | ||||
| 	bool DLL_EXPORT hasBonusOfType(HeroBonus::BonusType type, int subtype = -1) const; | ||||
| 	const DLL_EXPORT HeroBonus * getBonus( int from, int id ) const; | ||||
| 	void DLL_EXPORT getModifiersWDescr( std::vector<std::pair<int,std::string> > &out, HeroBonus::BonusType type, int subtype = -1 ) const; | ||||
| 	int DLL_EXPORT totalValue() const; //subtype -> subtype of bonus, if -1 then any | ||||
| 	void DLL_EXPORT getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *source = NULL) const; | ||||
| 	void DLL_EXPORT getBonuses(BonusList &out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *source = NULL) const; | ||||
| 	void DLL_EXPORT getModifiersWDescr(TModDescr &out) const; | ||||
|  | ||||
| 	//special find functions | ||||
| 	DLL_EXPORT Bonus * getFirst(const CSelector &select); | ||||
| 	DLL_EXPORT const Bonus * getFirst(const CSelector &select) const; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & static_cast<std::list<HeroBonus>&>(*this); | ||||
| 		h & static_cast<std::list<Bonus>&>(*this); | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| @@ -140,19 +310,39 @@ class DLL_EXPORT CBonusSystemNode | ||||
| public: | ||||
| 	BonusList bonuses; | ||||
|  | ||||
| 	virtual void getParents(TCNodes &out, const CBonusSystemNode *source = NULL) const;  //retreives list of parent nodes (nodes to inherit bonuses from), source is the prinary asker | ||||
| 	//new bonusing node interface | ||||
| 	// * selector is predicate that tests if HeroBonus matches our criteria | ||||
| 	// * root is node on which call was made (NULL will be replaced with this) | ||||
| 	virtual void getParents(TCNodes &out, const CBonusSystemNode *root = NULL) const;  //retrieves list of parent nodes (nodes to inherit bonuses from), source is the prinary asker | ||||
| 	virtual void getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root = NULL) const; | ||||
|  | ||||
| 	int valOfBonuses(HeroBonus::BonusType type, int subtype = -1) const; //subtype -> subtype of bonus, if -1 then any | ||||
| 	bool hasBonusOfType(HeroBonus::BonusType type, int subtype = -1) const;//determines if hero has a bonus of given type (and optionally subtype) | ||||
| 	const HeroBonus * getBonus( int from, int id ) const; | ||||
| 	void getModifiersWDescr( std::vector<std::pair<int,std::string> > &out, HeroBonus::BonusType type, int subtype = -1 ) const;  //out: pairs<modifier value, modifier description> | ||||
| 	void getBonuses(BonusList &out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = NULL) const; | ||||
| 	BonusList getBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = NULL) const; | ||||
| 	BonusList getBonuses(const CSelector &selector, const CBonusSystemNode *root = NULL) const; | ||||
| 	int getBonusesCount(const CSelector &selector, const CBonusSystemNode *root = NULL) const; | ||||
| 	int valOfBonuses(const CSelector &selector, const CBonusSystemNode *root = NULL) const; | ||||
| 	bool hasBonus(const CSelector &selector, const CBonusSystemNode *root = NULL) const; | ||||
| 	void getModifiersWDescr(TModDescr &out, const CSelector &selector, const CBonusSystemNode *root = NULL) const;  //out: pairs<modifier value, modifier description> | ||||
|  | ||||
| 	////////////////////////////////////////////////////////////////////////// | ||||
| 	//legacy interface  | ||||
| 	int valOfBonuses(Bonus::BonusType type, const CSelector &selector) const; | ||||
| 	int valOfBonuses(Bonus::BonusType type, int subtype = -1) const; //subtype -> subtype of bonus, if -1 then any | ||||
| 	bool hasBonusOfType(Bonus::BonusType type, int subtype = -1) const;//determines if hero has a bonus of given type (and optionally subtype) | ||||
| 	bool hasBonusFrom(ui8 source, ui32 sourceID) const; | ||||
| 	void getModifiersWDescr( TModDescr &out, Bonus::BonusType type, int subtype = -1 ) const;  //out: pairs<modifier value, modifier description> | ||||
| 	int getBonusesCount(int from, int id) const; | ||||
|  | ||||
| 	template<int N> void getModifiersWDescr(std::vector<std::pair<int,std::string> > &out, const HeroBonus::BonusType (&types)[N]) const //retreive array of types | ||||
| 	{ | ||||
| 		for (int i = 0; i < N; i++) | ||||
| 			getModifiersWDescr(out, types[i]); | ||||
| 	} | ||||
| 	int MoraleVal() const; //range [-3, +3] | ||||
| 	int LuckVal() const; //range [-3, +3] | ||||
| 	si32 Attack() const; //get attack of stack with all modificators | ||||
| 	si32 Defense(bool withFrenzy = true) const; //get defense of stack with all modificators | ||||
| 	ui16 MaxHealth() const; //get max HP of stack with all modifiers | ||||
|  | ||||
|  | ||||
| 	//non-const interface | ||||
| 	void getParents(TNodes &out, const CBonusSystemNode *root = NULL);  //retrieves list of parent nodes (nodes to inherit bonuses from), source is the prinary asker | ||||
| 	Bonus *getBonus(const CSelector &selector); | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| @@ -163,9 +353,94 @@ public: | ||||
| namespace NBonus | ||||
| { | ||||
| 	//set of methods that may be safely called with NULL objs | ||||
| 	DLL_EXPORT int valOf(const CBonusSystemNode *obj, HeroBonus::BonusType type, int subtype = -1); //subtype -> subtype of bonus, if -1 then any | ||||
| 	DLL_EXPORT bool hasOfType(const CBonusSystemNode *obj, HeroBonus::BonusType type, int subtype = -1);//determines if hero has a bonus of given type (and optionally subtype) | ||||
| 	DLL_EXPORT const HeroBonus * get(const CBonusSystemNode *obj, int from, int id ); | ||||
| 	DLL_EXPORT void getModifiersWDescr(const CBonusSystemNode *obj, std::vector<std::pair<int,std::string> > &out, HeroBonus::BonusType type, int subtype = -1 );  //out: pairs<modifier value, modifier description> | ||||
| 	DLL_EXPORT int valOf(const CBonusSystemNode *obj, Bonus::BonusType type, int subtype = -1); //subtype -> subtype of bonus, if -1 then any | ||||
| 	DLL_EXPORT bool hasOfType(const CBonusSystemNode *obj, Bonus::BonusType type, int subtype = -1);//determines if hero has a bonus of given type (and optionally subtype) | ||||
| 	//DLL_EXPORT const HeroBonus * get(const CBonusSystemNode *obj, int from, int id ); | ||||
| 	DLL_EXPORT void getModifiersWDescr(const CBonusSystemNode *obj, TModDescr &out, Bonus::BonusType type, int subtype = -1 );  //out: pairs<modifier value, modifier description> | ||||
| 	DLL_EXPORT int getCount(const CBonusSystemNode *obj, int from, int id); | ||||
| }; | ||||
| }; | ||||
|  | ||||
| //generates HeroBonus from given data | ||||
| inline Bonus makeFeature(Bonus::BonusType type, ui8 duration, si16 subtype, si32 value, Bonus::BonusSource source, ui16 turnsRemain = 0, si32 additionalInfo = 0) | ||||
| { | ||||
| 	Bonus sf; | ||||
| 	sf.type = type; | ||||
| 	sf.duration = duration; | ||||
| 	sf.source = source; | ||||
| 	sf.turnsRemain = turnsRemain; | ||||
| 	sf.subtype = subtype; | ||||
| 	sf.val = value; | ||||
| 	sf.additionalInfo = additionalInfo; | ||||
|  | ||||
| 	return sf; | ||||
| } | ||||
|  | ||||
| class DLL_EXPORT CSelectorsConjunction | ||||
| { | ||||
| 	const CSelector first, second; | ||||
| public: | ||||
| 	CSelectorsConjunction(const CSelector &First, const CSelector &Second) | ||||
| 		:first(First), second(Second) | ||||
| 	{ | ||||
| 	} | ||||
| 	bool operator()(const Bonus &bonus) const | ||||
| 	{ | ||||
| 		return first(bonus) && second(bonus); | ||||
| 	} | ||||
| }; | ||||
| CSelector DLL_EXPORT operator&&(const CSelector &first, const CSelector &second); | ||||
|  | ||||
|  | ||||
| template<typename T> | ||||
| class CSelectFieldEqual | ||||
| { | ||||
| 	T Bonus::*ptr; | ||||
| 	T val; | ||||
| public: | ||||
| 	CSelectFieldEqual(T Bonus::*Ptr, const T &Val) | ||||
| 		: ptr(Ptr), val(Val) | ||||
| 	{ | ||||
| 	} | ||||
| 	bool operator()(const Bonus &bonus) const | ||||
| 	{ | ||||
| 		return bonus.*ptr == val; | ||||
| 	} | ||||
| 	CSelectFieldEqual& operator()(const T &setVal) | ||||
| 	{ | ||||
| 		val = setVal; | ||||
| 		return *this; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| class CWillLastTurns | ||||
| { | ||||
| public: | ||||
| 	int turnsRequested; | ||||
|  | ||||
| 	bool operator()(const Bonus &bonus) const | ||||
| 	{ | ||||
| 		return !turnsRequested  | ||||
| 				||   bonus.turnsRemain > turnsRequested  &&  bonus.duration == Bonus::N_TURNS; | ||||
| 	} | ||||
| 	CWillLastTurns& operator()(const int &setVal) | ||||
| 	{ | ||||
| 		turnsRequested = setVal; | ||||
| 		return *this; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| namespace Selector | ||||
| { | ||||
| 	extern DLL_EXPORT CSelectFieldEqual<TBonusType> type; | ||||
| 	extern DLL_EXPORT CSelectFieldEqual<TBonusSubtype> subtype; | ||||
| 	extern DLL_EXPORT CSelectFieldEqual<si32> info; | ||||
| 	extern DLL_EXPORT CSelectFieldEqual<ui8> sourceType; | ||||
| 	extern DLL_EXPORT CSelectFieldEqual<ui8> effectRange; | ||||
| 	extern DLL_EXPORT CWillLastTurns turns; | ||||
|  | ||||
| 	CSelector DLL_EXPORT typeSybtype(TBonusType Type, TBonusSubtype Subtype); | ||||
| 	CSelector DLL_EXPORT typeSybtypeInfo(TBonusType type, TBonusSubtype subtype, si32 info); | ||||
| 	CSelector DLL_EXPORT source(ui8 source, ui32 sourceID); | ||||
|  | ||||
| 	bool DLL_EXPORT matchesType(const CSelector &sel, TBonusType type); | ||||
| } | ||||
| @@ -5,6 +5,7 @@ | ||||
| #include <vector> | ||||
| #include <set> | ||||
| #include "../client/FunctionList.h" | ||||
| #include "CCreatureSet.h" | ||||
|  | ||||
| /* | ||||
|  * IGameCallback.h, part of VCMI engine | ||||
|   | ||||
| @@ -5,6 +5,7 @@ | ||||
| #include "BattleAction.h" | ||||
| #include "HeroBonus.h" | ||||
| #include <set> | ||||
| #include "CCreatureSet.h" | ||||
|  | ||||
| /* | ||||
|  * NetPacks.h, part of VCMI engine | ||||
| @@ -77,7 +78,7 @@ public: | ||||
|  | ||||
| 	std::vector<ui8> message; //vector of EMessage | ||||
|  | ||||
| 	std::vector<std::pair<ui8,ui32> > localStrings; //pairs<text handler type, text number>; types: 1 - generaltexthandler->all; 2 - objh->xtrainfo; 3 - objh->names; 4 - objh->restypes; 5 - arth->artifacts[id].name; 6 - generaltexth->arraytxt; 7 - creh->creatures[os->subID].namePl; 8 - objh->creGens; 9 - objh->mines[ID].first; 10 - objh->mines[ID].second; 11 - objh->advobtxt | ||||
| 	std::vector<std::pair<ui8,ui32> > localStrings; //pairs<text handler type, text number>; types: 1 - generaltexthandler->all; 2 - objh->xtrainfo; 3 - objh->names; 4 - objh->restypes; 5 - arth->artifacts[id].name; 6 - generaltexth->arraytxt; 7 - creh->creatures[os->subID].namePl; 8 - objh->creGens; 9 - objh->mines[ID]->first; 10 - objh->mines[ID]->second; 11 - objh->advobtxt | ||||
| 	std::vector<std::string> exactStrings; | ||||
| 	std::vector<si32> numbers; | ||||
|  | ||||
| @@ -370,7 +371,7 @@ struct GiveBonus :  public CPackForClient //115 | ||||
| 	enum {HERO, PLAYER}; | ||||
| 	ui8 who; //who receives bonus, uses enum above | ||||
| 	ui32 id; //hero or player id | ||||
| 	HeroBonus bonus; | ||||
| 	Bonus bonus; | ||||
| 	MetaString bdescr; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| @@ -440,7 +441,7 @@ struct RemoveBonus :  public CPackForClient //118 | ||||
| 	ui32 id; //source id | ||||
|  | ||||
| 	//used locally: copy of removed bonus | ||||
| 	HeroBonus bonus; | ||||
| 	Bonus bonus; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| @@ -573,7 +574,7 @@ struct SetHeroArtifacts : public CPackForClient //509 | ||||
| 		h & hid & artifacts & artifWorn; | ||||
| 	} | ||||
|  | ||||
| 	std::vector<HeroBonus*> gained, lost; //used locally as hlp when applying | ||||
| 	std::vector<Bonus*> gained, lost; //used locally as hlp when applying | ||||
| };    | ||||
|  | ||||
| struct HeroRecruited : public CPackForClient //515 | ||||
| @@ -712,6 +713,12 @@ struct InfoWindow : public CPackForClient //103  - displays simple info window | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| namespace ObjProperty | ||||
| { | ||||
| 	//TODO: move non general properties out to the appropriate objs classes | ||||
| 	enum {OWNER = 1, BLOCKVIS = 2, PRIMARY_STACK_COUNT = 3, VISITORS = 4, VISITED = 5, ID = 6}; | ||||
| } | ||||
|  | ||||
| struct SetObjectProperty : public CPackForClient//1001 | ||||
| { | ||||
| 	DLL_EXPORT void applyGs(CGameState *gs); | ||||
|   | ||||
| @@ -52,12 +52,17 @@ DLL_EXPORT void SetResource::applyGs( CGameState *gs ) | ||||
| DLL_EXPORT void SetPrimSkill::applyGs( CGameState *gs ) | ||||
| { | ||||
| 	CGHeroInstance *hero = gs->getHero(id); | ||||
| 	assert(hero); | ||||
|  | ||||
| 	if(which <4) | ||||
| 	{ | ||||
| 		Bonus *skill = hero->getBonus(Selector::type(Bonus::PRIMARY_SKILL) && Selector::subtype(which) && Selector::sourceType(Bonus::HERO_BASE_SKILL)); | ||||
| 		assert(skill); | ||||
| 		 | ||||
| 		if(abs) | ||||
| 			hero->primSkills[which] = val; | ||||
| 			skill->val = val; | ||||
| 		else | ||||
| 			hero->primSkills[which] += val; | ||||
| 			skill->val += val; | ||||
| 	} | ||||
| 	else if(which == 4) //XP | ||||
| 	{ | ||||
| @@ -171,16 +176,16 @@ DLL_EXPORT void SetAvailableHeroes::applyGs( CGameState *gs ) | ||||
| 	gs->getPlayer(player)->availableHeroes.push_back(h); | ||||
| 	if(h  &&  flags & 1) | ||||
| 	{ | ||||
| 		h->army.slots.clear(); | ||||
| 		h->army.slots[0] = CStackInstance(VLC->creh->nameToID[h->type->refTypeStack[0]],1); | ||||
| 		h->clear(); | ||||
| 		h->addStack(0, CStackInstance(VLC->creh->nameToID[h->type->refTypeStack[0]],1)); | ||||
| 	} | ||||
|  | ||||
| 	h = (hid2>=0 ?  gs->hpool.heroesPool[hid2] : NULL); | ||||
| 	gs->getPlayer(player)->availableHeroes.push_back(h); | ||||
| 	if(flags & 2) | ||||
| 	{ | ||||
| 		h->army.slots.clear(); | ||||
| 		h->army.slots[0] = CStackInstance(VLC->creh->nameToID[h->type->refTypeStack[0]],1); | ||||
| 		h->clear(); | ||||
| 		h->addStack(0, CStackInstance(VLC->creh->nameToID[h->type->refTypeStack[0]],1)); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -209,8 +214,8 @@ DLL_EXPORT void GiveBonus::applyGs( CGameState *gs ) | ||||
| 	std::string &descr = bonuses->back().description; | ||||
|  | ||||
| 	if(!bdescr.message.size()  | ||||
| 		&& bonus.source == HeroBonus::OBJECT  | ||||
| 		&& (bonus.type == HeroBonus::LUCK || bonus.type == HeroBonus::MORALE || bonus.type == HeroBonus::MORALE_AND_LUCK) | ||||
| 		&& bonus.source == Bonus::OBJECT  | ||||
| 		&& (bonus.type == Bonus::LUCK || bonus.type == Bonus::MORALE) | ||||
| 		&& gs->map->objects[bonus.id]->ID == EVENTI_TYPE) //it's morale/luck bonus from an event without description | ||||
| 	{ | ||||
| 		descr = VLC->generaltexth->arraytxt[bonus.val > 0 ? 110 : 109]; //+/-%d Temporary until next battle" | ||||
| @@ -243,9 +248,9 @@ DLL_EXPORT void PlayerEndsGame::applyGs( CGameState *gs ) | ||||
|  | ||||
| DLL_EXPORT void RemoveBonus::applyGs( CGameState *gs ) | ||||
| { | ||||
| 	std::list<HeroBonus> &bonuses = (who == HERO ? gs->getHero(whoID)->bonuses : gs->getPlayer(whoID)->bonuses); | ||||
| 	std::list<Bonus> &bonuses = (who == HERO ? gs->getHero(whoID)->bonuses : gs->getPlayer(whoID)->bonuses); | ||||
|  | ||||
| 	for(std::list<HeroBonus>::iterator i = bonuses.begin(); i != bonuses.end(); i++) | ||||
| 	for(std::list<Bonus>::iterator i = bonuses.begin(); i != bonuses.end(); i++) | ||||
| 	{ | ||||
| 		if(i->source == source && i->id == id) | ||||
| 		{ | ||||
| @@ -377,14 +382,14 @@ DLL_EXPORT void SetGarrisons::applyGs( CGameState *gs ) | ||||
| 	for(std::map<ui32,CCreatureSet>::iterator i = garrs.begin(); i!=garrs.end(); i++) | ||||
| 	{ | ||||
| 		CArmedInstance *ai = static_cast<CArmedInstance*>(gs->map->objects[i->first]); | ||||
| 		ai->army = i->second; | ||||
| 		ai->setArmy(i->second); | ||||
| 		if(ai->ID==TOWNI_TYPE && (static_cast<CGTownInstance*>(ai))->garrisonHero) //if there is a hero in garrison then we must update also his army | ||||
| 			const_cast<CGHeroInstance*>((static_cast<CGTownInstance*>(ai))->garrisonHero)->army = i->second; | ||||
| 			const_cast<CGHeroInstance*>((static_cast<CGTownInstance*>(ai))->garrisonHero)->setArmy(i->second); | ||||
| 		else if(ai->ID==HEROI_TYPE) | ||||
| 		{ | ||||
| 			CGHeroInstance *h =  static_cast<CGHeroInstance*>(ai); | ||||
| 			if(h->visitedTown && h->inTownGarrison) | ||||
| 				h->visitedTown->army = i->second; | ||||
| 				h->visitedTown->setArmy(i->second); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -456,7 +461,7 @@ DLL_EXPORT void SetHeroArtifacts::applyGs( CGameState *gs ) | ||||
| 			continue; | ||||
|  | ||||
| 		CArtifact &art = VLC->arth->artifacts[id]; | ||||
| 		for(std::list<HeroBonus>::iterator i = art.bonuses.begin(); i != art.bonuses.end(); i++) | ||||
| 		for(std::list<Bonus>::iterator i = art.bonuses.begin(); i != art.bonuses.end(); i++) | ||||
| 		{ | ||||
| 			gained.push_back(&*i); | ||||
| 			h->bonuses.push_back(*i); | ||||
| @@ -476,7 +481,7 @@ DLL_EXPORT void SetHeroArtifacts::applyGs( CGameState *gs ) | ||||
|  | ||||
| 		while(1) | ||||
| 		{ | ||||
| 			std::list<HeroBonus>::iterator hlp = std::find_if(h->bonuses.begin(),h->bonuses.end(),boost::bind(HeroBonus::IsFrom,_1,HeroBonus::ARTIFACT,id)); | ||||
| 			std::list<Bonus>::iterator hlp = std::find_if(h->bonuses.begin(),h->bonuses.end(),boost::bind(Bonus::IsFrom,_1,Bonus::ARTIFACT,id)); | ||||
| 			if(hlp != h->bonuses.end()) | ||||
| 			{ | ||||
| 				lost.push_back(&*hlp); | ||||
| @@ -613,11 +618,11 @@ DLL_EXPORT void NewTurn::applyGs( CGameState *gs ) | ||||
| 		t->builded = 0; | ||||
|  | ||||
| 	BOOST_FOREACH(CGHeroInstance *h, gs->map->heroes) | ||||
| 		h->bonuses.remove_if(HeroBonus::OneDay); | ||||
| 		h->bonuses.remove_if(Bonus::OneDay); | ||||
|  | ||||
| 	if(gs->getDate(1) == 7) //new week | ||||
| 		BOOST_FOREACH(CGHeroInstance *h, gs->map->heroes) | ||||
| 			h->bonuses.remove_if(HeroBonus::OneWeek); | ||||
| 			h->bonuses.remove_if(Bonus::OneWeek); | ||||
|  | ||||
| 	//count days without town | ||||
| 	for( std::map<ui8, PlayerState>::iterator i=gs->players.begin() ; i!=gs->players.end();i++) | ||||
| @@ -627,9 +632,9 @@ DLL_EXPORT void NewTurn::applyGs( CGameState *gs ) | ||||
| 		else | ||||
| 			i->second.daysWithoutCastle++; | ||||
|  | ||||
| 		i->second.bonuses.remove_if(HeroBonus::OneDay); | ||||
| 		i->second.bonuses.remove_if(Bonus::OneDay); | ||||
| 		if(gs->getDate(1) == 7) //new week | ||||
| 			i->second.bonuses.remove_if(HeroBonus::OneWeek); | ||||
| 			i->second.bonuses.remove_if(Bonus::OneWeek); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -642,7 +647,7 @@ DLL_EXPORT void SetObjectProperty::applyGs( CGameState *gs ) | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	if(what == 1) | ||||
| 	if(what == ObjProperty::OWNER) | ||||
| 	{ | ||||
| 		if(obj->ID == TOWNI_TYPE) | ||||
| 		{ | ||||
| @@ -672,6 +677,7 @@ DLL_EXPORT void HeroLevelUp::applyGs( CGameState *gs ) | ||||
| DLL_EXPORT void BattleStart::applyGs( CGameState *gs ) | ||||
| { | ||||
| 	gs->curB = info; | ||||
| 	info->belligerents[0]->battle = info->belligerents[1]->battle = info; | ||||
| } | ||||
|  | ||||
| DLL_EXPORT void BattleNextRound::applyGs( CGameState *gs ) | ||||
| @@ -685,12 +691,12 @@ DLL_EXPORT void BattleNextRound::applyGs( CGameState *gs ) | ||||
| 		s->state -= WAITING; | ||||
| 		s->state -= MOVED; | ||||
| 		s->state -= HAD_MORALE; | ||||
| 		s->counterAttacks = 1 + s->valOfFeatures(StackFeature::ADDITIONAL_RETALIATION); | ||||
| 		s->counterAttacks = 1 + s->valOfBonuses(Bonus::ADDITIONAL_RETALIATION); | ||||
|  | ||||
| 		//regeneration | ||||
| 		if( s->hasFeatureOfType(StackFeature::HP_REGENERATION) && s->alive() ) | ||||
| 			s->firstHPleft = std::min<ui32>( s->MaxHealth(), s->valOfFeatures(StackFeature::HP_REGENERATION) ); | ||||
| 		if( s->hasFeatureOfType(StackFeature::FULL_HP_REGENERATION) && s->alive() ) | ||||
| 		if( s->hasBonusOfType(Bonus::HP_REGENERATION) && s->alive() ) | ||||
| 			s->firstHPleft = std::min<ui32>( s->MaxHealth(), s->valOfBonuses(Bonus::HP_REGENERATION) ); | ||||
| 		if( s->hasBonusOfType(Bonus::FULL_HP_REGENERATION) && s->alive() ) | ||||
| 			s->firstHPleft = s->MaxHealth(); | ||||
|  | ||||
| 		//remove effects and restore only those with remaining turns in duration | ||||
| @@ -704,19 +710,20 @@ DLL_EXPORT void BattleNextRound::applyGs( CGameState *gs ) | ||||
| 		} | ||||
|  | ||||
| 		//the same as above for features | ||||
| 		std::vector<StackFeature> tmpFeatures = s->features; | ||||
| 		s->features.clear(); | ||||
| 		for(int i=0; i < tmpFeatures.size(); i++) | ||||
| 		BonusList tmpFeatures = s->bonuses; | ||||
| 		s->bonuses.clear(); | ||||
|  | ||||
| 		BOOST_FOREACH(Bonus &b, tmpFeatures) | ||||
| 		{ | ||||
| 			if((tmpFeatures[i].duration & StackFeature::N_TURNS) != 0) | ||||
| 			if((b.duration & Bonus::N_TURNS) != 0) | ||||
| 			{ | ||||
| 				tmpFeatures[i].turnsRemain--; | ||||
| 				if(tmpFeatures[i].turnsRemain > 0) | ||||
| 					s->features.push_back(tmpFeatures[i]); | ||||
| 				b.turnsRemain--; | ||||
| 				if(b.turnsRemain > 0) | ||||
| 					s->bonuses.push_back(b); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				s->features.push_back(tmpFeatures[i]); | ||||
| 				s->bonuses.push_back(b); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| @@ -739,12 +746,13 @@ void BattleResult::applyGs( CGameState *gs ) | ||||
| 	CGHeroInstance *h; | ||||
| 	h = gs->curB->heroes[0]; | ||||
| 	if(h) | ||||
| 		h->bonuses.remove_if(HeroBonus::OneBattle); | ||||
| 		h->bonuses.remove_if(Bonus::OneBattle); | ||||
|  | ||||
| 	h = gs->curB->heroes[1]; | ||||
| 	if(h)  | ||||
| 		h->bonuses.remove_if(HeroBonus::OneBattle); | ||||
| 		h->bonuses.remove_if(Bonus::OneBattle); | ||||
|  | ||||
| 	gs->curB->belligerents[0]->battle = gs->curB->belligerents[1]->battle = NULL; | ||||
| 	delete gs->curB; | ||||
| 	gs->curB = NULL; | ||||
| } | ||||
| @@ -757,7 +765,7 @@ void BattleStackMoved::applyGs( CGameState *gs ) | ||||
| DLL_EXPORT void BattleStackAttacked::applyGs( CGameState *gs ) | ||||
| { | ||||
| 	CStack * at = gs->curB->getStack(stackAttacked); | ||||
| 	at->amount = newAmount; | ||||
| 	at->count = newAmount; | ||||
| 	at->firstHPleft = newHP; | ||||
| 	if(killed()) | ||||
| 		at->state -= ALIVE; | ||||
| @@ -773,27 +781,12 @@ DLL_EXPORT void BattleAttack::applyGs( CGameState *gs ) | ||||
| 	BOOST_FOREACH(BattleStackAttacked stackAttacked, bsa) | ||||
| 		stackAttacked.applyGs(gs); | ||||
|  | ||||
| 	for(int g=0; g<attacker->features.size(); ++g) | ||||
| 	{ | ||||
| 		if((attacker->features[g].duration & StackFeature::UNTIL_ATTACK) != 0) | ||||
| 		{ | ||||
| 			attacker->features.erase(attacker->features.begin() + g); | ||||
| 			g = 0; | ||||
| 		} | ||||
| 	} | ||||
| 	attacker->bonuses.remove_if(Bonus::UntilAttack); | ||||
|  | ||||
| 	for(std::vector<BattleStackAttacked>::const_iterator it = bsa.begin(); it != bsa.end(); ++it) | ||||
| 	{ | ||||
| 		CStack * stack = gs->curB->getStack(it->stackAttacked, false); | ||||
|  | ||||
| 		for(int g=0; g<stack->features.size(); ++g) | ||||
| 		{ | ||||
| 			if((stack->features[g].duration & StackFeature::UNITL_BEING_ATTACKED) != 0) | ||||
| 			{ | ||||
| 				stack->features.erase(stack->features.begin() + g); | ||||
| 				g = 0; | ||||
| 			} | ||||
| 		} | ||||
| 		stack->bonuses.remove_if(Bonus::UntilBeingAttacked); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -823,6 +816,7 @@ DLL_EXPORT void StartAction::applyGs( CGameState *gs ) | ||||
|  | ||||
| DLL_EXPORT void SpellCast::applyGs( CGameState *gs ) | ||||
| { | ||||
| 	assert(gs->curB); | ||||
| 	CGHeroInstance *h = (side) ? gs->curB->heroes[1] : gs->curB->heroes[0]; | ||||
| 	if(h) | ||||
| 	{ | ||||
| @@ -844,7 +838,7 @@ DLL_EXPORT void SpellCast::applyGs( CGameState *gs ) | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	if(gs->curB && (id == 35 || id == 78)) //dispel and dispel helpful spells | ||||
| 	if(id == 35 || id == 78) //dispel and dispel helpful spells | ||||
| 	{ | ||||
| 		bool onlyHelpful = id == 78; | ||||
| 		for(std::set<ui32>::const_iterator it = affectedCres.begin(); it != affectedCres.end(); ++it) | ||||
| @@ -865,14 +859,13 @@ DLL_EXPORT void SpellCast::applyGs( CGameState *gs ) | ||||
| 				s->effects = remainingEff; //assigning effects that should remain | ||||
|  | ||||
| 				//removing all features from spells | ||||
| 				std::vector<StackFeature> tmpFeatures = s->features; | ||||
| 				s->features.clear(); | ||||
| 				for(int i=0; i < tmpFeatures.size(); i++) | ||||
| 				BonusList tmpFeatures = s->bonuses; | ||||
| 				s->bonuses.clear(); | ||||
| 				BOOST_FOREACH(Bonus &b, tmpFeatures) | ||||
| 				{ | ||||
| 					if(tmpFeatures[i].source != StackFeature::SPELL_EFFECT || tmpFeatures[i].positiveness != 1) | ||||
| 					{ | ||||
| 						s->features.push_back(tmpFeatures[i]); | ||||
| 					} | ||||
| 					const CSpell *sp = b.sourceSpell(); | ||||
| 					if(sp && sp->positiveness != 1) //if(b.source != HeroBonus::SPELL_EFFECT || b.positiveness != 1) | ||||
| 						s->bonuses.push_back(b); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| @@ -904,8 +897,8 @@ DLL_EXPORT void SpellCast::applyGs( CGameState *gs ) | ||||
|  | ||||
| 		bool ac[BFIELD_SIZE]; | ||||
| 		std::set<int> occupyable; | ||||
| 		bool twoHex = vstd::contains(VLC->creh->creatures[creID].abilities, StackFeature::DOUBLE_WIDE); | ||||
| 		bool flying = vstd::contains(VLC->creh->creatures[creID].abilities, StackFeature::FLYING); | ||||
| 		bool twoHex = VLC->creh->creatures[creID]->isDoubleWide(); | ||||
| 		bool flying = vstd::contains(VLC->creh->creatures[creID]->bonuses, Bonus::FLYING); | ||||
| 		gs->curB->getAccessibilityMap(ac, twoHex, !side, true, occupyable, flying); | ||||
| 		for(int g=0; g<BFIELD_SIZE; ++g) | ||||
| 		{ | ||||
| @@ -916,121 +909,126 @@ DLL_EXPORT void SpellCast::applyGs( CGameState *gs ) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		CStack * summonedStack = gs->curB->generateNewStack(h, creID, h->getPrimSkillLevel(2) * VLC->spellh->spells[id].powers[skill], gs->curB->stacks.size(), !side, 255, ter, pos); | ||||
| 		summonedStack->features.push_back( makeFeature(StackFeature::SUMMONED, StackFeature::WHOLE_BATTLE, 0, 0, StackFeature::BONUS_FROM_HERO) ); | ||||
| 		CStack * summonedStack = gs->curB->generateNewStack(CStackInstance(creID, h->getPrimSkillLevel(2) * VLC->spellh->spells[id].powers[skill], h), gs->curB->stacks.size(), !side, 255, ter, pos); | ||||
| 		summonedStack->state.insert(SUMMONED); | ||||
| 		//summonedStack->bonuses.push_back( makeFeature(HeroBonus::SUMMONED, HeroBonus::ONE_BATTLE, 0, 0, HeroBonus::BONUS_FROM_HERO) ); | ||||
|  | ||||
| 		gs->curB->stacks.push_back(summonedStack); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static inline StackFeature featureGenerator(StackFeature::ECombatFeatures type, si16 subtype, si32 value, ui16 turnsRemain, si32 additionalInfo = 0) | ||||
| static inline Bonus featureGenerator(Bonus::BonusType type, si16 subtype, si32 value, ui16 turnsRemain, si32 additionalInfo = 0, si32 limit = Bonus::NO_LIMIT) | ||||
| { | ||||
| 	return makeFeature(type, StackFeature::N_TURNS, subtype, value, StackFeature::SPELL_EFFECT, turnsRemain, additionalInfo); | ||||
| 	Bonus hb(makeFeature(type, Bonus::N_TURNS, subtype, value, Bonus::SPELL_EFFECT, turnsRemain, additionalInfo)); | ||||
| 	hb.effectRange = limit; | ||||
| 	return hb; | ||||
| } | ||||
|  | ||||
| static std::vector<StackFeature> stackEffectToFeature(const CStack::StackEffect & sse) | ||||
| static inline Bonus featureGeneratorVT(Bonus::BonusType type, si16 subtype, si32 value, ui16 turnsRemain, ui8 valType) | ||||
| { | ||||
| 	std::vector<StackFeature> sf; | ||||
| 	Bonus ret(makeFeature(type, Bonus::N_TURNS, subtype, value, Bonus::SPELL_EFFECT, turnsRemain)); | ||||
| 	ret.valType = valType; | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| static BonusList stackEffectToFeature(const CStack::StackEffect & sse) | ||||
| { | ||||
| 	BonusList sf; | ||||
| 	si32 power = VLC->spellh->spells[sse.id].powers[sse.level]; | ||||
| 	switch(sse.id) | ||||
| 	{ | ||||
| 	case 27: //shield  | ||||
| 		sf.push_back(featureGenerator(StackFeature::GENERAL_DAMAGE_REDUCTION, 0, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); | ||||
| 		sf.push_back(featureGenerator(Bonus::GENERAL_DAMAGE_REDUCTION, 0, power, sse.turnsRemain)); | ||||
| 		break; | ||||
| 	case 28: //air shield | ||||
| 		sf.push_back(featureGenerator(StackFeature::GENERAL_DAMAGE_REDUCTION, 1, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); | ||||
| 		sf.push_back(featureGenerator(Bonus::GENERAL_DAMAGE_REDUCTION, 1, power, sse.turnsRemain)); | ||||
| 		break; | ||||
| 	case 29: //fire shield | ||||
| 		sf.push_back(featureGenerator(StackFeature::FIRE_SHIELD, 0, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); | ||||
| 		sf.push_back(featureGenerator(Bonus::FIRE_SHIELD, 0, power, sse.turnsRemain)); | ||||
| 		break; | ||||
| 	case 30: //protection from air | ||||
| 		sf.push_back(featureGenerator(StackFeature::SPELL_DAMAGE_REDUCTION, 0, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); | ||||
| 		sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 0, power, sse.turnsRemain)); | ||||
| 		break; | ||||
| 	case 31: //protection from fire | ||||
| 		sf.push_back(featureGenerator(StackFeature::SPELL_DAMAGE_REDUCTION, 1, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); | ||||
| 		sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 1, power, sse.turnsRemain)); | ||||
| 		break; | ||||
| 	case 32: //protection from water | ||||
| 		sf.push_back(featureGenerator(StackFeature::SPELL_DAMAGE_REDUCTION, 2, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); | ||||
| 		sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 2, power, sse.turnsRemain)); | ||||
| 		break; | ||||
| 	case 33: //protection from earth | ||||
| 		sf.push_back(featureGenerator(StackFeature::SPELL_DAMAGE_REDUCTION, 3, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); | ||||
| 		sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 3, power, sse.turnsRemain)); | ||||
| 		break; | ||||
| 	case 34: //anti-magic | ||||
| 		sf.push_back(featureGenerator(StackFeature::LEVEL_SPELL_IMMUNITY, 0, VLC->spellh->spells[sse.id].powers[sse.level] - 1, sse.turnsRemain)); | ||||
| 		sf.push_back(featureGenerator(Bonus::LEVEL_SPELL_IMMUNITY, 0, power - 1, sse.turnsRemain)); | ||||
| 		break; | ||||
| 	case 41: //bless | ||||
| 		sf.push_back(featureGenerator(StackFeature::ALWAYS_MAXIMUM_DAMAGE, -1, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); | ||||
| 		sf.push_back(featureGenerator(Bonus::ALWAYS_MAXIMUM_DAMAGE, -1, power, sse.turnsRemain)); | ||||
| 		break; | ||||
| 	case 42: //curse | ||||
| 		sf.push_back(featureGenerator(StackFeature::ALWAYS_MINIMUM_DAMAGE, -1, -1 * VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain, sse.level >= 2 ? 20 : 0)); | ||||
| 		sf.push_back(featureGenerator(Bonus::ALWAYS_MINIMUM_DAMAGE, -1, -1 * power, sse.turnsRemain, sse.level >= 2 ? 20 : 0)); | ||||
| 		break; | ||||
| 	case 43: //bloodlust | ||||
| 		sf.push_back(featureGenerator(StackFeature::ATTACK_BONUS, 0, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); | ||||
| 		sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain, 0, Bonus::ONLY_MELEE_FIGHT)); | ||||
| 		break; | ||||
| 	case 44: //precision | ||||
| 		sf.push_back(featureGenerator(StackFeature::ATTACK_BONUS, 1, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); | ||||
| 		sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain, 0, Bonus::ONLY_DISTANCE_FIGHT)); | ||||
| 		break; | ||||
| 	case 45: //weakness | ||||
| 		sf.push_back(featureGenerator(StackFeature::ATTACK_BONUS, -1, -1 * VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); | ||||
| 		sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, -1 * power, sse.turnsRemain)); | ||||
| 		break; | ||||
| 	case 46: //stone skin | ||||
| 		sf.push_back(featureGenerator(StackFeature::DEFENCE_BONUS, -1, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); | ||||
| 		sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, power, sse.turnsRemain)); | ||||
| 		break; | ||||
| 	case 47: //disrupting ray | ||||
| 		sf.push_back(featureGenerator(StackFeature::DEFENCE_BONUS, -1, -1 * VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); | ||||
| 		sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, -1 * power, sse.turnsRemain)); | ||||
| 		break; | ||||
| 	case 48: //prayer | ||||
| 		sf.push_back(featureGenerator(StackFeature::ATTACK_BONUS, 0, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); | ||||
| 		sf.push_back(featureGenerator(StackFeature::DEFENCE_BONUS, 0, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); | ||||
| 		sf.push_back(featureGenerator(StackFeature::SPEED_BONUS, 0, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); | ||||
| 		sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain)); | ||||
| 		sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, power, sse.turnsRemain)); | ||||
| 		sf.push_back(featureGenerator(Bonus::STACKS_SPEED, 0, power, sse.turnsRemain)); | ||||
| 		break; | ||||
| 	case 49: //mirth | ||||
| 		sf.push_back(featureGenerator(StackFeature::MORALE_BONUS, 0, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); | ||||
| 		sf.push_back(featureGenerator(Bonus::MORALE, 0, power, sse.turnsRemain)); | ||||
| 		break; | ||||
| 	case 50: //sorrow | ||||
| 		sf.push_back(featureGenerator(StackFeature::MORALE_BONUS, 0, -1 * VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); | ||||
| 		sf.push_back(featureGenerator(Bonus::MORALE, 0, -1 * power, sse.turnsRemain)); | ||||
| 		break; | ||||
| 	case 51: //fortune | ||||
| 		sf.push_back(featureGenerator(StackFeature::LUCK_BONUS, 0, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); | ||||
| 		sf.push_back(featureGenerator(Bonus::LUCK, 0, power, sse.turnsRemain)); | ||||
| 		break; | ||||
| 	case 52: //misfortune | ||||
| 		sf.push_back(featureGenerator(StackFeature::LUCK_BONUS, 0, -1 * VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); | ||||
| 		sf.push_back(featureGenerator(Bonus::LUCK, 0, -1 * power, sse.turnsRemain)); | ||||
| 		break; | ||||
| 	case 53: //haste | ||||
| 		sf.push_back(featureGenerator(StackFeature::SPEED_BONUS, 0, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); | ||||
| 		sf.push_back(featureGenerator(Bonus::STACKS_SPEED, 0, power, sse.turnsRemain)); | ||||
| 		break; | ||||
| 	case 54: //slow | ||||
| 		sf.push_back(featureGenerator(StackFeature::SPEED_BONUS, 0, 0, sse.turnsRemain, -1 * ( 100 - VLC->spellh->spells[sse.id].powers[sse.level] ) )); | ||||
| 		sf.push_back(featureGeneratorVT(Bonus::STACKS_SPEED, 0, -1 * ( 100 - power ), sse.turnsRemain, Bonus::PERCENT_TO_ALL)); | ||||
| 		break; | ||||
| 	case 55: //slayer | ||||
| 		sf.push_back(featureGenerator(StackFeature::SLAYER, 0, sse.level, sse.turnsRemain)); | ||||
| 		sf.push_back(featureGenerator(Bonus::SLAYER, 0, sse.level, sse.turnsRemain)); | ||||
| 		break; | ||||
| 	case 56: //frenzy | ||||
| 		sf.push_back(featureGenerator(StackFeature::IN_FRENZY, 0, sse.level, sse.turnsRemain)); | ||||
| 		sf.push_back(featureGenerator(Bonus::IN_FRENZY, 0, VLC->spellh->spells[56].powers[sse.level]/100.0, sse.turnsRemain)); | ||||
| 		break; | ||||
| 	case 58: //counterstrike | ||||
| 		sf.push_back(featureGenerator(StackFeature::ADDITIONAL_RETALIATION, 0, VLC->spellh->spells[sse.id].powers[sse.level], sse.turnsRemain)); | ||||
| 		sf.push_back(featureGenerator(Bonus::ADDITIONAL_RETALIATION, 0, power, sse.turnsRemain)); | ||||
| 		break; | ||||
| 	case 59: //bersek | ||||
| 		sf.push_back(featureGenerator(StackFeature::ATTACKS_NEAREST_CREATURE, 0, sse.level, sse.turnsRemain)); | ||||
| 		sf.push_back(featureGenerator(Bonus::ATTACKS_NEAREST_CREATURE, 0, sse.level, sse.turnsRemain)); | ||||
| 		break; | ||||
| 	case 60: //hypnotize | ||||
| 		sf.push_back(featureGenerator(StackFeature::HYPNOTIZED, 0, sse.level, sse.turnsRemain)); | ||||
| 		sf.push_back(featureGenerator(Bonus::HYPNOTIZED, 0, sse.level, sse.turnsRemain)); | ||||
| 		break; | ||||
| 	case 61: //forgetfulness | ||||
| 		sf.push_back(featureGenerator(StackFeature::FORGETFULL, 0, sse.level, sse.turnsRemain)); | ||||
| 		sf.push_back(featureGenerator(Bonus::FORGETFULL, 0, sse.level, sse.turnsRemain)); | ||||
| 		break; | ||||
| 	case 62: //blind | ||||
| 		sf.push_back(makeFeature(StackFeature::NOT_ACTIVE, StackFeature::UNITL_BEING_ATTACKED | StackFeature::N_TURNS, 0, 0, StackFeature::SPELL_EFFECT, sse.turnsRemain, 0)); | ||||
| 		sf.push_back(makeFeature(StackFeature::GENERAL_ATTACK_REDUCTION, StackFeature::UNTIL_ATTACK | StackFeature::N_TURNS, 0, VLC->spellh->spells[sse.id].powers[sse.level], StackFeature::SPELL_EFFECT, sse.turnsRemain, 0)); | ||||
| 		sf.push_back(makeFeature(Bonus::NOT_ACTIVE, Bonus::UNITL_BEING_ATTACKED | Bonus::N_TURNS, 0, 0, Bonus::SPELL_EFFECT, sse.turnsRemain)); | ||||
| 		sf.push_back(makeFeature(Bonus::GENERAL_ATTACK_REDUCTION, Bonus::UNTIL_ATTACK | Bonus::N_TURNS, 0, power, Bonus::SPELL_EFFECT, sse.turnsRemain)); | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	//setting positiveness | ||||
| 	for(int g=0; g<sf.size(); ++g) | ||||
| 	{ | ||||
| 		sf[g].positiveness = VLC->spellh->spells[sse.id].positiveness; | ||||
| 	} | ||||
|  | ||||
| 	return sf; | ||||
| } | ||||
|  | ||||
| @@ -1045,14 +1043,15 @@ void actualizeEffect(CStack * s, CStack::StackEffect & ef) | ||||
| 		} | ||||
| 	} | ||||
| 	//actualizing features vector | ||||
| 	std::vector<StackFeature> sf = stackEffectToFeature(ef); | ||||
| 	for(int b=0; b<sf.size(); ++b) | ||||
| 	BonusList sf = stackEffectToFeature(ef); | ||||
|  | ||||
| 	BOOST_FOREACH(const Bonus &fromEffect, sf) | ||||
| 	{ | ||||
| 		for(int g=0; g<s->features.size(); ++g) | ||||
| 		BOOST_FOREACH(Bonus &stackBonus, s->bonuses) | ||||
| 		{ | ||||
| 			if(s->features[g].source == StackFeature::SPELL_EFFECT && s->features[g].type == sf[b].type && s->features[g].subtype == sf[b].subtype) | ||||
| 			if(stackBonus.source == Bonus::SPELL_EFFECT && stackBonus.type == fromEffect.type && stackBonus.subtype == fromEffect.subtype) | ||||
| 			{ | ||||
| 				s->features[g].turnsRemain = std::max(s->features[g].turnsRemain, ef.turnsRemain); | ||||
| 				stackBonus.turnsRemain = std::max(stackBonus.turnsRemain, ef.turnsRemain); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| @@ -1079,10 +1078,10 @@ DLL_EXPORT void SetStackEffect::applyGs( CGameState *gs ) | ||||
| 			if(effect.id == 42 || !containsEff(s->effects, effect.id))//disrupting ray or not on the list - just add | ||||
| 			{ | ||||
| 				s->effects.push_back(effect); | ||||
| 				std::vector<StackFeature> sf = stackEffectToFeature(effect); | ||||
| 				for(int n=0; n<sf.size(); ++n) | ||||
| 				BonusList sf = stackEffectToFeature(effect); | ||||
| 				BOOST_FOREACH(const Bonus &fromEffect, sf) | ||||
| 				{ | ||||
| 					s->features.push_back(sf[n]); | ||||
| 					s->bonuses.push_back(fromEffect); | ||||
| 				} | ||||
| 			} | ||||
| 			else //just actualize | ||||
| @@ -1115,8 +1114,8 @@ DLL_EXPORT void StacksHealedOrResurrected::applyGs( CGameState *gs ) | ||||
| 		for(int h=0; h<access.size(); ++h) | ||||
| 			acc[access[h]] = true; | ||||
| 		if(!changedStack->alive() && !gs->curB->isAccessible(changedStack->position, acc, | ||||
| 			changedStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE), changedStack->attackerOwned, | ||||
| 			changedStack->hasFeatureOfType(StackFeature::FLYING), true)) | ||||
| 			changedStack->doubleWide(), changedStack->attackerOwned, | ||||
| 			changedStack->hasBonusOfType(Bonus::FLYING), true)) | ||||
| 			return; //position is already occupied | ||||
|  | ||||
| 		//applying changes | ||||
| @@ -1125,18 +1124,19 @@ DLL_EXPORT void StacksHealedOrResurrected::applyGs( CGameState *gs ) | ||||
| 		{ | ||||
| 			changedStack->state.insert(ALIVE); | ||||
| 			if(healedStacks[g].lowLevelResurrection) | ||||
| 				changedStack->features.push_back( makeFeature(StackFeature::SUMMONED, StackFeature::WHOLE_BATTLE, 0, 0, StackFeature::BONUS_FROM_HERO) ); | ||||
| 				changedStack->state.insert(SUMMONED); | ||||
| 				//changedStack->bonuses.push_back( makeFeature(HeroBonus::SUMMONED, HeroBonus::ONE_BATTLE, 0, 0, HeroBonus::BONUS_FROM_HERO) ); | ||||
| 		} | ||||
| 		int missingHPfirst = changedStack->MaxHealth() - changedStack->firstHPleft; | ||||
| 		int res = std::min( healedStacks[g].healedHP / changedStack->MaxHealth() , changedStack->baseAmount - changedStack->amount ); | ||||
| 		changedStack->amount += res; | ||||
| 		int res = std::min( healedStacks[g].healedHP / changedStack->MaxHealth() , changedStack->baseAmount - changedStack->count ); | ||||
| 		changedStack->count += res; | ||||
| 		changedStack->firstHPleft += healedStacks[g].healedHP - res * changedStack->MaxHealth(); | ||||
| 		if(changedStack->firstHPleft > changedStack->MaxHealth()) | ||||
| 		{ | ||||
| 			changedStack->firstHPleft -= changedStack->MaxHealth(); | ||||
| 			if(changedStack->baseAmount > changedStack->amount) | ||||
| 			if(changedStack->baseAmount > changedStack->count) | ||||
| 			{ | ||||
| 				changedStack->amount += 1; | ||||
| 				changedStack->count += 1; | ||||
| 			} | ||||
| 		} | ||||
| 		amin(changedStack->firstHPleft, changedStack->MaxHealth()); | ||||
| @@ -1152,13 +1152,15 @@ DLL_EXPORT void StacksHealedOrResurrected::applyGs( CGameState *gs ) | ||||
| 			} | ||||
| 			 | ||||
| 			//removing all features from negative spells | ||||
| 			std::vector<StackFeature> tmpFeatures = changedStack->features; | ||||
| 			changedStack->features.clear(); | ||||
| 			for(int i=0; i < tmpFeatures.size(); i++) | ||||
| 			BonusList tmpFeatures = changedStack->bonuses; | ||||
| 			changedStack->bonuses.clear(); | ||||
|  | ||||
| 			BOOST_FOREACH(Bonus &b, tmpFeatures) | ||||
| 			{ | ||||
| 				if(tmpFeatures[i].source != StackFeature::SPELL_EFFECT || tmpFeatures[i].positiveness >= 0) | ||||
| 				const CSpell *s = b.sourceSpell(); | ||||
| 				if(s && s->positiveness >= 0) | ||||
| 				{ | ||||
| 					changedStack->features.push_back(tmpFeatures[i]); | ||||
| 					changedStack->bonuses.push_back(b); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|   | ||||
| @@ -1,153 +0,0 @@ | ||||
| #ifndef __STACK_FEATURE_H__ | ||||
| #define __STACK_FEATURE_H__ | ||||
|  | ||||
| struct StackFeature | ||||
| { | ||||
| #define VCMI_CREATURE_ABILITY_LIST										\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(NO_TYPE)									\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(DOUBLE_WIDE)								\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(FLYING)									\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(SHOOTER)									\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(CHARGE_IMMUNITY)							\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(ADDITIONAL_ATTACK)						\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(UNLIMITED_RETALIATIONS)					\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(NO_MELEE_PENALTY)						\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(JOUSTING) /*for champions*/				\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(RAISING_MORALE) /*value - how much raises*/ \ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(HATE) /*eg. angels hate devils, subtype - ID of hated creature*/ \ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(KING1)									\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(KING2)									\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(KING3)									\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(MAGIC_RESISTANCE) /*in % (value)*/		\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(CHANGES_SPELL_COST_FOR_ALLY) /*in mana points (value) , eg. mage*/ \ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(CHANGES_SPELL_COST_FOR_ENEMY) /*in mana points (value) , eg. pegasus */ \ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(SPELL_AFTER_ATTACK) /* subtype - spell id, value - spell level, (additional info)%1000 - chance in %; eg. dendroids, (additional info)/1000 -> [0 - all attacks, 1 - shot only, 2 - melee only*/ \ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(SPELL_RESISTANCE_AURA) /*eg. unicorns, value - resistance bonus in % for adjacent creatures*/ \ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(LEVEL_SPELL_IMMUNITY) /*creature is immune to all spell with level below or equal to value of this bonus*/ \ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(TWO_HEX_ATTACK_BREATH) /*eg. dragons*/	\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(SPELL_DAMAGE_REDUCTION) /*eg. golems; value - reduction in %, subtype - spell school; -1 - all, 0 - air, 1 - fire, 2 - water, 3 - earth*/ \ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(NO_WALL_PENALTY)							\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(NON_LIVING) /*eg. gargoyle*/				\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(RANDOM_GENIE_SPELLCASTER) /*eg. master genie*/ \ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(BLOCKS_RETALIATION) /*eg. naga*/			\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(SPELL_IMMUNITY) /*subid - spell id*/		\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(MANA_CHANNELING) /*value in %, eg. familiar*/ \ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(SPELL_LIKE_ATTACK) /*value - spell id; range is taken from spell, but damage from creature; eg. magog*/ \ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(THREE_HEADED_ATTACK) /*eg. cerberus*/	\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(DAEMON_SUMMONING) /*pit lord*/			\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(FIRE_IMMUNITY)							\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(FIRE_SHIELD)								\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(ENEMY_MORALE_DECREASING) /*value - how much it decreases*/ \ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(ENEMY_LUCK_DECREASING)					\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(UNDEAD)									\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(HP_REGENERATION) /*creature regenerates val HP every new round*/					\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(FULL_HP_REGENERATION) /*first creature regenerates all HP every new round; subtype 0 - animation 4 (trolllike), 1 - animation 47 (wightlike)*/		\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(MANA_DRAIN) /*value - spell points per turn*/ \ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(LIFE_DRAIN)								\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(DOUBLE_DAMAGE_CHANCE) /*value in %, eg. dread knight*/ \ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(RETURN_AFTER_STRIKE)						\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(SELF_MORALE) /*eg. minotaur*/			\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(SPELLCASTER) /*subtype - spell id, value - level of school, additional info - spell power*/ \ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(CATAPULT)								\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(ENEMY_DEFENCE_REDUCTION) /*in % (value) eg. behemots*/ \ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(GENERAL_DAMAGE_REDUCTION) /* shield / air shield effect */ \ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(GENERAL_ATTACK_REDUCTION) /*eg. while stoned or blinded - in %, subtype: -1 - any damage, 0 - melee damage, 1 - ranged damage*/ \ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(ATTACKS_ALL_ADJACENT) /*eg. hydra*/		\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(MORE_DAMAGE_FROM_SPELL) /*value - damage increase in %, subtype - spell id*/ \ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(CASTS_SPELL_WHEN_KILLED) /*similar to spell after attack*/ \ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(FEAR)									\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(FEARLESS)								\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(NO_DISTANCE_PENALTY)						\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(NO_OBSTACLES_PENALTY)					\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(SELF_LUCK) /*halfling*/					\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(ATTACK_BONUS) /*subtype: -1 - any attack, 0 - melee, 1 - ranged*/ \ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(DEFENCE_BONUS) /*subtype: -1 - any attack, 0 - melee, 1 - ranged*/ \ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(SPEED_BONUS) /*additional info - percent of speed bonus applied after direct bonuses; >0 - added, <0 - substracted to this part*/ \ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(HP_BONUS)								\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(ENCHANTER)								\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(HEALER)									\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(SIEGE_WEAPON)							\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(LUCK_BONUS)								\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(MORALE_BONUS)							\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(HYPNOTIZED)								\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(ADDITIONAL_RETALIATION) /*value - number of additional retaliations*/ \ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(MAGIC_MIRROR) /* value - chance of redirecting in %*/ \ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(SUMMONED)								\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(ALWAYS_MINIMUM_DAMAGE) /*unit does its minimum damage from range; subtype: -1 - any attack, 0 - melee, 1 - ranged, value: additional damage, additional info - multiplicative anti-bonus for dmg in % [eg 20 means that creature will inflict 80% of normal dmg]*/ \ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(ALWAYS_MAXIMUM_DAMAGE) /*eg. bless effect, subtype: -1 - any attack, 0 - melee, 1 - ranged, value: additional damage, additional info - multiplicative bonus for dmg in %*/ \ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(ATTACKS_NEAREST_CREATURE) /*while in berserk*/ \ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(IN_FRENZY) /*value - level*/				\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(SLAYER) /*value - level*/				\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(FORGETFULL) /*forgetfullnes spell effect, value - level*/ \ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(CLONED)									\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(NOT_ACTIVE)								\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(NO_LUCK) /*eg. when fighting on cursed ground*/	\ | ||||
| 	VCMI_CREATURE_ABILITY_NAME(NO_MORALE) /*eg. when fighting on cursed ground*/ | ||||
| 	 | ||||
| 	//general list of stack abilities and effects | ||||
| 	enum ECombatFeatures | ||||
| 	{ | ||||
| #define VCMI_CREATURE_ABILITY_NAME(x) x, | ||||
| 		VCMI_CREATURE_ABILITY_LIST | ||||
| #undef VCMI_CREATURE_ABILITY_NAME | ||||
| 	}; | ||||
|  | ||||
| 	enum EDuration | ||||
| 	{ | ||||
| 		WHOLE_BATTLE = 1, | ||||
| 		N_TURNS = 2, | ||||
| 		UNITL_BEING_ATTACKED = 4,/*removed after attack and counterattacks are performed*/ | ||||
| 		UNTIL_ATTACK = 8 /*removed after attack and counterattacks are performed*/ | ||||
| 	}; | ||||
|  | ||||
| 	enum ESource | ||||
| 	{ | ||||
| 		CREATURE_ABILITY, | ||||
| 		BONUS_FROM_HERO, | ||||
| 		SPELL_EFFECT, | ||||
| 		OTHER_SOURCE /*eg. bonus from terrain if native*/ | ||||
| 	}; | ||||
|  | ||||
| 	ui8 type;//ECombatFeatures | ||||
| 	ui8 duration;//EDuration //bitfield | ||||
| 	ui8 source;//ESource | ||||
| 	si8 positiveness; //+1 - positive, 0 - neutral, -1 - negative; used mostly for spell features | ||||
| 	ui16 turnsRemain; //if duration is N_TURNS it describes how long the effect will last | ||||
| 	si16 subtype; //subtype of bonus/feature | ||||
| 	si32 value; | ||||
| 	si32 additionalInfo; | ||||
|  | ||||
| 	inline bool operator == (const ECombatFeatures & cf) const | ||||
| 	{ | ||||
| 		return type == cf; | ||||
| 	} | ||||
| 	StackFeature() : type(NO_TYPE) | ||||
| 	{} | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & type & duration & source & positiveness & turnsRemain & subtype & value & additionalInfo; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| //generates StackFeature from given data | ||||
| inline StackFeature makeFeature(StackFeature::ECombatFeatures type, ui8 duration, si16 subtype, si32 value, StackFeature::ESource source, ui16 turnsRemain = 0, si32 additionalInfo = 0) | ||||
| { | ||||
| 	StackFeature sf; | ||||
| 	sf.type = type; | ||||
| 	sf.duration = duration; | ||||
| 	sf.source = source; | ||||
| 	sf.turnsRemain = turnsRemain; | ||||
| 	sf.subtype = subtype; | ||||
| 	sf.value = value; | ||||
| 	sf.additionalInfo = additionalInfo; | ||||
|  | ||||
| 	return sf; | ||||
| } | ||||
|  | ||||
| inline StackFeature makeCreatureAbility(StackFeature::ECombatFeatures type, si32 value, si16 subtype = 0, si32 additionalInfo = 0) | ||||
| { | ||||
| 	return makeFeature(type, StackFeature::WHOLE_BATTLE, subtype, value, StackFeature::CREATURE_ABILITY, 0, additionalInfo); | ||||
| } | ||||
|  | ||||
| #endif //__STACK_FEATURE_H__ | ||||
							
								
								
									
										42
									
								
								lib/map.cpp
									
									
									
									
									
								
							
							
						
						
									
										42
									
								
								lib/map.cpp
									
									
									
									
									
								
							| @@ -152,18 +152,21 @@ static CCreatureSet readCreatureSet(const unsigned char * bufor, int &i, int num | ||||
| 	{ | ||||
| 		int creID = readNormalNr(bufor,i+ir*bytesPerCre, idBytes); | ||||
| 		int count = readNormalNr(bufor,i+ir*bytesPerCre+idBytes, 2); | ||||
|  | ||||
| 		if(creID == maxID) //empty slot | ||||
| 			continue; | ||||
|  | ||||
| 		CStackInstance hlp; | ||||
| 		hlp.count = count; | ||||
|  | ||||
| 		if(creID > maxID - 0xf) | ||||
| 		{ | ||||
| 			creID = maxID + 1 - creID + VLC->creh->creatures.size();//this will happen when random object has random army | ||||
| 			ret.slots[ir].idRand = creID; | ||||
| 			hlp.idRand = creID; | ||||
| 		} | ||||
| 		else | ||||
| 			ret.slots[ir].setType(creID); | ||||
| 			hlp.setType(creID); | ||||
|  | ||||
| 		ret.slots[ir].count = count; | ||||
| 		ret.slots[ir] = hlp; | ||||
| 	} | ||||
| 	i+=number*bytesPerCre; | ||||
| 	 | ||||
| @@ -704,8 +707,8 @@ void Mapa::loadTown( CGObjectInstance * &nobj, const unsigned char * bufor, int | ||||
| 	if(readChar(bufor,i)) //has name | ||||
| 		nt->name = readString(bufor,i); | ||||
| 	if(readChar(bufor,i))//true if garrison isn't empty | ||||
| 		nt->army = readCreatureSet(bufor,i,7,(version>RoE)); | ||||
| 	nt->army.formation = bufor[i]; ++i; | ||||
| 		nt->setArmy(readCreatureSet(bufor, i, 7, version > RoE)); | ||||
| 	nt->formation = bufor[i]; ++i; | ||||
| 	if(readChar(bufor,i)) //custom buildings info | ||||
| 	{ | ||||
| 		//built buildings | ||||
| @@ -889,9 +892,9 @@ void Mapa::loadHero( CGObjectInstance * &nobj, const unsigned char * bufor, int | ||||
| 		} | ||||
| 	} | ||||
| 	if(readChar(bufor,i))//true if hero has nonstandard garrison | ||||
| 		nhi->army = readCreatureSet(bufor,i,7,(version>RoE)); | ||||
| 		nhi->setArmy(readCreatureSet(bufor, i, 7, version > RoE)); | ||||
|  | ||||
| 	nhi->army.formation =bufor[i]; ++i; //formation | ||||
| 	nhi->formation =bufor[i]; ++i; //formation | ||||
| 	bool artSet = bufor[i]; ++i; //true if artifact set is not default (hero has some artifacts) | ||||
| 	int artmask = version == RoE ? 0xff : 0xffff; | ||||
| 	int artidlen = version == RoE ? 1 : 2; | ||||
| @@ -988,9 +991,8 @@ void Mapa::loadHero( CGObjectInstance * &nobj, const unsigned char * bufor, int | ||||
| 	{ | ||||
| 		if(readChar(bufor,i))//customPrimSkills | ||||
| 		{ | ||||
| 			nhi->primSkills.resize(4); | ||||
| 			for(int xx=0;xx<4;xx++) | ||||
| 				nhi->primSkills[xx] = bufor[i++]; | ||||
| 				nhi->pushPrimSkill(xx, bufor[i++]); | ||||
| 		} | ||||
| 	} | ||||
| 	i+=16; | ||||
| @@ -1197,9 +1199,8 @@ void Mapa::readPredefinedHeroes( const unsigned char * bufor, int &i) | ||||
| 				} | ||||
| 				if(readChar(bufor,i))//customPrimSkills | ||||
| 				{ | ||||
| 					cgh->primSkills.resize(4); | ||||
| 					for(int xx=0;xx<4;xx++) | ||||
| 						cgh->primSkills[xx] = bufor[i++]; | ||||
| 						cgh->pushPrimSkill(xx, bufor[i++]); | ||||
| 				} | ||||
| 				predefinedHeroes.push_back(cgh); | ||||
| 			} | ||||
| @@ -1375,7 +1376,7 @@ void Mapa::readObjects( const unsigned char * bufor, int &i) | ||||
| 					} | ||||
| 					if(bufor[i++]) | ||||
| 					{ | ||||
| 						evnt->army = readCreatureSet(bufor,i,7,(version>RoE));  | ||||
| 						evnt->setArmy(readCreatureSet(bufor, i, 7, version > RoE));  | ||||
| 					} | ||||
| 					i+=4; | ||||
| 				} | ||||
| @@ -1485,7 +1486,12 @@ void Mapa::readObjects( const unsigned char * bufor, int &i) | ||||
| 					cre->identifier = readNormalNr(bufor,i); i+=4; | ||||
| 					monsters[cre->identifier] = cre; | ||||
| 				} | ||||
| 				cre->army.slots[0].count = readNormalNr(bufor,i, 2); i+=2; | ||||
|  | ||||
| 				CStackInstance hlp; | ||||
| 				hlp.count =  readNormalNr(bufor,i, 2); i+=2; | ||||
| 				//type will be set during initialization | ||||
| 				cre->slots[0] = hlp; | ||||
|  | ||||
| 				cre->character = bufor[i]; ++i; | ||||
| 				bool isMesTre = bufor[i]; ++i; //true if there is message or treasury | ||||
| 				if(isMesTre) | ||||
| @@ -1575,7 +1581,7 @@ void Mapa::readObjects( const unsigned char * bufor, int &i) | ||||
| 				nobj = gar; | ||||
| 				nobj->setOwner(bufor[i++]); | ||||
| 				i+=3; | ||||
| 				gar->army = readCreatureSet(bufor,i,7,(version>RoE)); | ||||
| 				gar->setArmy(readCreatureSet(bufor, i, 7, version > RoE)); | ||||
| 				if(version > RoE) | ||||
| 				{ | ||||
| 					gar->removableUnits = bufor[i]; ++i; | ||||
| @@ -1599,7 +1605,7 @@ void Mapa::readObjects( const unsigned char * bufor, int &i) | ||||
| 					bool areGuards = bufor[i]; ++i; | ||||
| 					if(areGuards) | ||||
| 					{ | ||||
| 						art->army = readCreatureSet(bufor,i,7,(version>RoE)); | ||||
| 						art->setArmy(readCreatureSet(bufor, i, 7, version > RoE)); | ||||
| 					} | ||||
| 					i+=4; | ||||
| 				} | ||||
| @@ -1621,7 +1627,7 @@ void Mapa::readObjects( const unsigned char * bufor, int &i) | ||||
| 					res->message = readString(bufor,i); | ||||
| 					if(bufor[i++]) | ||||
| 					{ | ||||
| 						res->army = readCreatureSet(bufor,i,7,(version>RoE)); | ||||
| 						res->setArmy(readCreatureSet(bufor, i, 7, version > RoE)); | ||||
| 					} | ||||
| 					i+=4; | ||||
| 				} | ||||
| @@ -1675,7 +1681,7 @@ void Mapa::readObjects( const unsigned char * bufor, int &i) | ||||
| 					box->message = readString(bufor,i); | ||||
| 					if(bufor[i++]) | ||||
| 					{ | ||||
| 						box->army = readCreatureSet(bufor,i,7,(version>RoE)); | ||||
| 						box->setArmy(readCreatureSet(bufor, i, 7, version > RoE)); | ||||
| 					} | ||||
| 					i+=4; | ||||
| 				} | ||||
|   | ||||
| @@ -101,7 +101,7 @@ static void giveExp(BattleResult &r) | ||||
| 	r.exp[1] = 0; | ||||
| 	for(std::map<ui32,si32>::iterator i = r.casualties[!r.winner].begin(); i!=r.casualties[!r.winner].end(); i++) | ||||
| 	{ | ||||
| 		r.exp[r.winner] += VLC->creh->creatures[i->first].hitPoints * i->second; | ||||
| 		r.exp[r.winner] += VLC->creh->creatures[i->first]->valOfBonuses(Bonus::STACK_HEALTH) * i->second; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -302,19 +302,20 @@ static CCreatureSet takeCasualties(int color, const CCreatureSet &set, BattleInf | ||||
| { | ||||
| 	if(color == 254) | ||||
| 		color = 255; | ||||
|  | ||||
| 	CCreatureSet ret(set); | ||||
| 	for(int i=0; i<bat->stacks.size();i++) | ||||
| 	{ | ||||
| 		if(bat->stacks[i]->hasFeatureOfType(StackFeature::SUMMONED)) //don't take into account sumoned stacks | ||||
| 		CStack *st = bat->stacks[i]; | ||||
| 		if(vstd::contains(st->state, SUMMONED)) //don't take into account sumoned stacks | ||||
| 			continue; | ||||
|  | ||||
| 		CStack *st = bat->stacks[i]; | ||||
| 		if(st->owner==color && vstd::contains(set.slots,st->slot) && st->amount < set.slots.find(st->slot)->second.count) | ||||
| 		if(st->owner==color && !set.slotEmpty(st->slot) && st->count < set.getAmount(st->slot)) | ||||
| 		{ | ||||
| 			if(st->alive()) | ||||
| 				ret.slots[st->slot].count = st->amount; | ||||
| 				ret.setStackCount(st->slot, st->count); | ||||
| 			else | ||||
| 				ret.slots.erase(st->slot); | ||||
| 				ret.eraseStack(st->slot); | ||||
| 		} | ||||
| 	} | ||||
| 	return ret; | ||||
| @@ -331,7 +332,7 @@ void CGameHandler::startBattle(const CArmedInstance *army1, const CArmedInstance | ||||
| 		curB->side2 = army2->tempOwner; | ||||
| 		if(curB->side2 == 254)  | ||||
| 			curB->side2 = 255; | ||||
| 		setupBattle(curB, tile, army1->army, army2->army, hero1, hero2, creatureBank, town); //initializes stacks, places creatures on battlefield, blocks and informs player interfaces | ||||
| 		setupBattle(curB, tile, army1, army2, hero1, hero2, creatureBank, town); //initializes stacks, places creatures on battlefield, blocks and informs player interfaces | ||||
| 	} | ||||
|  | ||||
| 	NEW_ROUND; | ||||
| @@ -360,11 +361,12 @@ void CGameHandler::startBattle(const CArmedInstance *army1, const CArmedInstance | ||||
| 		{ | ||||
|  | ||||
| 			//check for bad morale => freeze | ||||
| 			if( curB.Morale(next) < 0 && | ||||
| 				!(NBonus::hasOfType(hero1, HeroBonus::BLOCK_MORALE) || NBonus::hasOfType(hero2, HeroBonus::BLOCK_MORALE)) //checking if heroes have (or don't have) morale blocking bonuses) | ||||
| 			int nextStackMorale = next->MoraleVal(); | ||||
| 			if( nextStackMorale < 0 && | ||||
| 				!(NBonus::hasOfType(hero1, Bonus::BLOCK_MORALE) || NBonus::hasOfType(hero2, Bonus::BLOCK_MORALE)) //checking if heroes have (or don't have) morale blocking bonuses) | ||||
| 				) | ||||
| 			{ | ||||
| 				if( rand()%24   <   (-curB.Morale(next))*2 ) | ||||
| 				if( rand()%24   <   -2 * nextStackMorale) | ||||
| 				{ | ||||
| 					//unit loses its turn - empty freeze action | ||||
| 					BattleAction ba; | ||||
| @@ -379,7 +381,7 @@ void CGameHandler::startBattle(const CArmedInstance *army1, const CArmedInstance | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			if(next->hasFeatureOfType(StackFeature::ATTACKS_NEAREST_CREATURE)) //while in berserk | ||||
| 			if(next->hasBonusOfType(Bonus::ATTACKS_NEAREST_CREATURE)) //while in berserk | ||||
| 			{ | ||||
| 				std::pair<const CStack *, int> attackInfo = curB.getNearestStack(next, boost::logic::indeterminate); | ||||
| 				if(attackInfo.first != NULL) | ||||
| @@ -402,7 +404,7 @@ void CGameHandler::startBattle(const CArmedInstance *army1, const CArmedInstance | ||||
| 			const CGHeroInstance * curOwner = gs->battleGetOwner(next->ID); | ||||
|  | ||||
| 			if( (next->position < 0 && (!curOwner || curOwner->getSecSkillLevel(10) == 0)) //arrow turret, hero has no ballistics | ||||
| 				|| (next->creature->idNumber == 146 && curOwner->getSecSkillLevel(20) == 0)) //ballista, hero has no artillery | ||||
| 				|| (next->type->idNumber == 146 && curOwner->getSecSkillLevel(20) == 0)) //ballista, hero has no artillery | ||||
| 			{ | ||||
| 				BattleAction attack; | ||||
| 				attack.actionType = 7; | ||||
| @@ -424,7 +426,7 @@ void CGameHandler::startBattle(const CArmedInstance *army1, const CArmedInstance | ||||
| 				continue; | ||||
| 			} | ||||
|  | ||||
| 			if(next->creature->idNumber == 145 && (!curOwner || curOwner->getSecSkillLevel(10) == 0)) //catapult, hero has no ballistics | ||||
| 			if(next->type->idNumber == 145 && (!curOwner || curOwner->getSecSkillLevel(10) == 0)) //catapult, hero has no ballistics | ||||
| 			{ | ||||
| 				BattleAction attack; | ||||
| 				static const int wallHexes[] = {50, 183, 182, 130, 62, 29, 12, 95}; | ||||
| @@ -439,7 +441,7 @@ void CGameHandler::startBattle(const CArmedInstance *army1, const CArmedInstance | ||||
| 				continue; | ||||
| 			} | ||||
|  | ||||
| 			if(next->creature->idNumber == 147 && (!curOwner || curOwner->getSecSkillLevel(27) == 0)) //first aid tent, hero has no first aid | ||||
| 			if(next->type->idNumber == 147 && (!curOwner || curOwner->getSecSkillLevel(27) == 0)) //first aid tent, hero has no first aid | ||||
| 			{ | ||||
| 				BattleAction heal; | ||||
|  | ||||
| @@ -503,14 +505,15 @@ askInterfaceForMove: | ||||
| 			checkForBattleEnd(stacks); //check if this action ended the battle | ||||
|  | ||||
| 			//check for good morale | ||||
| 			nextStackMorale = next->MoraleVal(); | ||||
| 			if(!vstd::contains(next->state,HAD_MORALE)  //only one extra move per turn possible | ||||
| 				&& !vstd::contains(next->state,DEFENDING) | ||||
| 				&& !vstd::contains(next->state,WAITING) | ||||
| 				&&  next->alive() | ||||
| 				&&  curB.Morale(next) > 0 | ||||
| 				&& !(NBonus::hasOfType(hero1, HeroBonus::BLOCK_MORALE) || NBonus::hasOfType(hero2, HeroBonus::BLOCK_MORALE)) //checking if heroes have (or don't have) morale blocking bonuses | ||||
| 				&&  nextStackMorale > 0 | ||||
| 				&& !(NBonus::hasOfType(hero1, Bonus::BLOCK_MORALE) || NBonus::hasOfType(hero2, Bonus::BLOCK_MORALE)) //checking if heroes have (or don't have) morale blocking bonuses | ||||
| 			) | ||||
| 				if(rand()%24 < curB.Morale(next)) //this stack hasn't got morale this turn | ||||
| 				if(rand()%24 < nextStackMorale) //this stack hasn't got morale this turn | ||||
| 					goto askInterfaceForMove; //move this stack once more | ||||
| 		} | ||||
| 	} | ||||
| @@ -533,8 +536,8 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance *hero1, const CGHer | ||||
|  | ||||
| 	//casualties among heroes armies | ||||
| 	SetGarrisons sg; | ||||
| 	sg.garrs[bEndArmy1->id] = takeCasualties(bEndArmy1->tempOwner, bEndArmy1->army, gs->curB); | ||||
| 	sg.garrs[bEndArmy2->id] = takeCasualties(bEndArmy2->tempOwner, bEndArmy2->army, gs->curB); | ||||
| 	sg.garrs[bEndArmy1->id] = takeCasualties(bEndArmy1->tempOwner, *bEndArmy1, gs->curB); | ||||
| 	sg.garrs[bEndArmy2->id] = takeCasualties(bEndArmy2->tempOwner, *bEndArmy2, gs->curB); | ||||
| 	sendAndApply(&sg); | ||||
|  | ||||
| 	ui8 sides[2]; | ||||
| @@ -581,17 +584,18 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance *hero1, const CGHer | ||||
| 		// Give raised units to winner and show dialog, if any were raised. | ||||
| 		if (raisedStack.type)  | ||||
| 		{ | ||||
| 			int slot = winnerHero->army.getSlotFor(raisedStack.type->idNumber); | ||||
| 			int slot = winnerHero->getSlotFor(raisedStack.type->idNumber); | ||||
|  | ||||
| 			if (slot != -1)  | ||||
| 			{ | ||||
| 				SetGarrisons sg; | ||||
| 				sg.garrs[winnerHero->id] = winnerHero->getArmy(); | ||||
| 				sg.garrs[winnerHero->id].addToSlot(slot, raisedStack); | ||||
|  | ||||
| 				sg.garrs[winnerHero->id] = winnerHero->army; | ||||
| 				if (vstd::contains(winnerHero->army.slots, slot)) // Add to existing stack. | ||||
| 					sg.garrs[winnerHero->id].slots[slot].count += raisedStack.count; | ||||
| 				else // Create a new stack. | ||||
| 					sg.garrs[winnerHero->id].slots[slot] = raisedStack; | ||||
| // 				if (vstd::contains(winnerHero->slots, slot)) // Add to existing stack. | ||||
| // 					sg.garrs[winnerHero->id].slots[slot].count += raisedStack.count; | ||||
| // 				else // Create a new stack. | ||||
| // 					sg.garrs[winnerHero->id].slots[slot] = raisedStack; | ||||
| 				winnerHero->showNecromancyDialog(raisedStack); | ||||
| 				sendAndApply(&sg); | ||||
| 			} | ||||
| @@ -617,15 +621,15 @@ void CGameHandler::prepareAttacked(BattleStackAttacked &bsa, const CStack *def) | ||||
| 		bsa.newHP = def->firstHPleft - damageFirst; | ||||
| 	} | ||||
|  | ||||
| 	if(def->amount <= bsa.killedAmount) //stack killed | ||||
| 	if(def->count <= bsa.killedAmount) //stack killed | ||||
| 	{ | ||||
| 		bsa.newAmount = 0; | ||||
| 		bsa.flags |= 1; | ||||
| 		bsa.killedAmount = def->amount; //we cannot kill more creatures than we have | ||||
| 		bsa.killedAmount = def->count; //we cannot kill more creatures than we have | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		bsa.newAmount = def->amount - bsa.killedAmount; | ||||
| 		bsa.newAmount = def->count - bsa.killedAmount; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -637,7 +641,8 @@ void CGameHandler::prepareAttack(BattleAttack &bat, const CStack *att, const CSt | ||||
| 	BattleStackAttacked *bsa = &bat.bsa.back(); | ||||
| 	bsa->stackAttacked = def->ID; | ||||
| 	bsa->attackerID = att->ID; | ||||
| 	if(gs->curB->Luck(att) > 0  &&  rand()%24 < gs->curB->Luck(att)) | ||||
| 	int attackerLuck = att->LuckVal(); | ||||
| 	if(attackerLuck > 0  &&  rand()%24 < attackerLuck) //TODO?: negative luck option? | ||||
| 	{ | ||||
| 		bsa->damageAmount *= 2; | ||||
| 		bat.flags |= 4; | ||||
| @@ -650,7 +655,7 @@ void CGameHandler::prepareAttack(BattleAttack &bat, const CStack *att, const CSt | ||||
| 	prepareAttacked(*bsa, def); | ||||
|  | ||||
| 	//fire shield handling | ||||
| 	if ( !bat.shot() && def->hasFeatureOfType(StackFeature::FIRE_SHIELD) && !bsa->killed() ) | ||||
| 	if ( !bat.shot() && def->hasBonusOfType(Bonus::FIRE_SHIELD) && !bsa->killed() ) | ||||
| 	{ | ||||
| 		bat.bsa.push_back(BattleStackAttacked()); | ||||
| 		BattleStackAttacked *bsa = &bat.bsa.back(); | ||||
| @@ -659,7 +664,7 @@ void CGameHandler::prepareAttack(BattleAttack &bat, const CStack *att, const CSt | ||||
| 		bsa->flags |= 2; | ||||
| 		bsa->effect = 11; | ||||
|  | ||||
| 		bsa->damageAmount = (dmg * def->valOfFeatures(StackFeature::FIRE_SHIELD)) / 100; | ||||
| 		bsa->damageAmount = (dmg * def->valOfBonuses(Bonus::FIRE_SHIELD)) / 100; | ||||
| 		prepareAttacked(*bsa, att); | ||||
| 	} | ||||
| } | ||||
| @@ -739,7 +744,7 @@ int CGameHandler::moveStack(int stack, int dest) | ||||
| 	} | ||||
|  | ||||
| 	//shifting destination (if we have double wide stack and we can occupy dest but not be exactly there) | ||||
| 	if(!stackAtEnd && curStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE) && !accessibility[dest]) | ||||
| 	if(!stackAtEnd && curStack->doubleWide() && !accessibility[dest]) | ||||
| 	{ | ||||
| 		if(curStack->attackerOwned) | ||||
| 		{ | ||||
| @@ -770,11 +775,11 @@ int CGameHandler::moveStack(int stack, int dest) | ||||
| 	//if(dists[dest] > curStack->creature->speed && !(stackAtEnd && dists[dest] == curStack->creature->speed+1)) //we can attack a stack if we can go to adjacent hex | ||||
| 	//	return false; | ||||
|  | ||||
| 	std::pair< std::vector<int>, int > path = gs->curB->getPath(curStack->position, dest, accessibilityWithOccupyable, curStack->hasFeatureOfType(StackFeature::FLYING), curStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE), curStack->attackerOwned); | ||||
| 	std::pair< std::vector<int>, int > path = gs->curB->getPath(curStack->position, dest, accessibilityWithOccupyable, curStack->hasBonusOfType(Bonus::FLYING), curStack->doubleWide(), curStack->attackerOwned); | ||||
|  | ||||
| 	ret = path.second; | ||||
|  | ||||
| 	if(curStack->hasFeatureOfType(StackFeature::FLYING)) | ||||
| 	if(curStack->hasBonusOfType(Bonus::FLYING)) | ||||
| 	{ | ||||
| 		if(path.second <= curStack->Speed() && path.first.size() > 0) | ||||
| 		{ | ||||
| @@ -912,8 +917,8 @@ void CGameHandler::newTurn() | ||||
| 					break; | ||||
| 				} | ||||
|  | ||||
| 				for(std::list<HeroBonus>::iterator  j = h->bonuses.begin(); j != h->bonuses.end(); j++) | ||||
| 					if(j->type == HeroBonus::GENERATE_RESOURCE) | ||||
| 				for(std::list<Bonus>::iterator  j = h->bonuses.begin(); j != h->bonuses.end(); j++) | ||||
| 					if(j->type == Bonus::GENERATE_RESOURCE) | ||||
| 						n.res[i->first][j->subtype] += j->val; | ||||
|  | ||||
| 				//TODO player bonuses | ||||
| @@ -939,7 +944,7 @@ void CGameHandler::newTurn() | ||||
| 				{ | ||||
| 					sac.creatures[k].first += (**j).creatureGrowth(k); | ||||
| 					if(!gs->getDate(0)) //first day of game: use only basic growths | ||||
| 						amin(sac.creatures[k].first, VLC->creh->creatures[(*j)->town->basicCreatures[k]].growth); | ||||
| 						amin(sac.creatures[k].first, VLC->creh->creatures[(*j)->town->basicCreatures[k]]->growth); | ||||
| 				} | ||||
| 			} | ||||
| 			n.cres.push_back(sac); | ||||
| @@ -1007,7 +1012,8 @@ void CGameHandler::newTurn() | ||||
| 	} | ||||
| } | ||||
| void CGameHandler::run(bool resume) | ||||
| {	 | ||||
| { | ||||
| 	using namespace boost::posix_time; | ||||
| 	BOOST_FOREACH(CConnection *cc, conns) | ||||
| 	{//init conn. | ||||
| 		ui8 quantity, pom; | ||||
| @@ -1050,7 +1056,6 @@ void CGameHandler::run(bool resume) | ||||
| 		resume = false; | ||||
| 		for(; i != gs->players.end(); i++) | ||||
| 		{ | ||||
|  | ||||
| 			if(i->second.towns.size()==0 && i->second.heroes.size()==0 | ||||
| 				|| i->second.color<0  | ||||
| 				|| i->first>=PLAYER_LIMIT   | ||||
| @@ -1070,8 +1075,7 @@ void CGameHandler::run(bool resume) | ||||
| 			boost::unique_lock<boost::mutex> lock(states.mx); | ||||
| 			while(states.players[i->first].makingTurn && !end2) | ||||
| 			{ | ||||
| 				boost::posix_time::time_duration p; | ||||
| 				p = boost::posix_time::milliseconds(200); | ||||
| 				static time_duration p = milliseconds(200); | ||||
| 				states.cv.timed_wait(lock,p);  | ||||
| 			} | ||||
| 		} | ||||
| @@ -1099,14 +1103,14 @@ namespace CGH | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet &army1, const CCreatureSet &army2, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool creatureBank, const CGTownInstance *town) | ||||
| void CGameHandler::setupBattle(BattleInfo * curB, int3 tile, const CArmedInstance *army1, const CArmedInstance *army2, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool creatureBank, const CGTownInstance *town) | ||||
| { | ||||
| 	battleResult.set(NULL); | ||||
| 	std::vector<CStack*> & stacks = (curB->stacks); | ||||
|  | ||||
| 	curB->tile = tile; | ||||
| 	curB->army1=army1; | ||||
| 	curB->army2=army2; | ||||
| 	curB->belligerents[0] = const_cast<CArmedInstance*>(army1); | ||||
| 	curB->belligerents[1] = const_cast<CArmedInstance*>(army2); | ||||
| 	curB->heroes[0] = const_cast<CGHeroInstance*>(hero1); | ||||
| 	curB->heroes[1] = const_cast<CGHeroInstance*>(hero2); | ||||
| 	curB->round = -2; | ||||
| @@ -1150,42 +1154,42 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet | ||||
| 	//battleStartpos read | ||||
|  | ||||
| 	int k = 0; //stack serial  | ||||
| 	for(TSlots::const_iterator i = army1.slots.begin(); i!=army1.slots.end(); i++, k++) | ||||
| 	for(TSlots::const_iterator i = army1->Slots().begin(); i!=army1->Slots().end(); i++, k++) | ||||
| 	{ | ||||
| 		int pos; | ||||
| 		if(creatureBank) | ||||
| 			pos = attackerCreBank[army1.slots.size()-1][k]; | ||||
| 		else if(army1.formation) | ||||
| 			pos = attackerTight[army1.slots.size()-1][k]; | ||||
| 			pos = attackerCreBank[army1->stacksCount()-1][k]; | ||||
| 		else if(army1->formation) | ||||
| 			pos = attackerTight[army1->stacksCount()-1][k]; | ||||
| 		else | ||||
| 			pos = attackerLoose[army1.slots.size()-1][k]; | ||||
| 			pos = attackerLoose[army1->stacksCount()-1][k]; | ||||
|  | ||||
| 		CStack * stack = curB->generateNewStack(hero1, i->second.type->idNumber, i->second.count, stacks.size(), true, i->first, gs->map->terrain[tile.x][tile.y][tile.z].tertype, pos); | ||||
| 		CStack * stack = curB->generateNewStack(i->second, stacks.size(), true, i->first, gs->map->terrain[tile.x][tile.y][tile.z].tertype, pos); | ||||
| 		stacks.push_back(stack); | ||||
| 	} | ||||
| 	 | ||||
| 	k = 0; | ||||
| 	for(TSlots::const_iterator i = army2.slots.begin(); i!=army2.slots.end(); i++, k++) | ||||
| 	for(TSlots::const_iterator i = army2->Slots().begin(); i!=army2->Slots().end(); i++, k++) | ||||
| 	{ | ||||
| 		int pos; | ||||
| 		if(creatureBank) | ||||
| 			pos = defenderCreBank[army2.slots.size()-1][k]; | ||||
| 		else if(army2.formation) | ||||
| 			pos = defenderTight[army2.slots.size()-1][k]; | ||||
| 			pos = defenderCreBank[army2->stacksCount()-1][k]; | ||||
| 		else if(army2->formation) | ||||
| 			pos = defenderTight[army2->stacksCount()-1][k]; | ||||
| 		else | ||||
| 			pos = defenderLoose[army2.slots.size()-1][k]; | ||||
| 			pos = defenderLoose[army2->stacksCount()-1][k]; | ||||
|  | ||||
| 		CStack * stack = curB->generateNewStack(hero2, i->second.type->idNumber, i->second.count, stacks.size(), false, i->first, gs->map->terrain[tile.x][tile.y][tile.z].tertype, pos); | ||||
| 		CStack * stack = curB->generateNewStack(i->second, stacks.size(), false, i->first, gs->map->terrain[tile.x][tile.y][tile.z].tertype, pos); | ||||
| 		stacks.push_back(stack); | ||||
| 	} | ||||
|  | ||||
| 	for(unsigned g=0; g<stacks.size(); ++g) //shifting positions of two-hex creatures | ||||
| 	{ | ||||
| 		if((stacks[g]->position%17)==1 && stacks[g]->hasFeatureOfType(StackFeature::DOUBLE_WIDE) && stacks[g]->attackerOwned) | ||||
| 		if((stacks[g]->position%17)==1 && stacks[g]->doubleWide() && stacks[g]->attackerOwned) | ||||
| 		{ | ||||
| 			stacks[g]->position += 1; | ||||
| 		} | ||||
| 		else if((stacks[g]->position%17)==15 && stacks[g]->hasFeatureOfType(StackFeature::DOUBLE_WIDE) && !stacks[g]->attackerOwned) | ||||
| 		else if((stacks[g]->position%17)==15 && stacks[g]->doubleWide() && !stacks[g]->attackerOwned) | ||||
| 		{ | ||||
| 			stacks[g]->position -= 1; | ||||
| 		} | ||||
| @@ -1196,17 +1200,17 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet | ||||
| 	{ | ||||
| 		if(hero1->getArt(13)) //ballista | ||||
| 		{ | ||||
| 			CStack * stack = curB->generateNewStack(hero1, 146, 1, stacks.size(), true, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 52); | ||||
| 			CStack * stack = curB->generateNewStack(CStackInstance(146, 1, hero1), stacks.size(), true, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 52); | ||||
| 			stacks.push_back(stack); | ||||
| 		} | ||||
| 		if(hero1->getArt(14)) //ammo cart | ||||
| 		{ | ||||
| 			CStack * stack = curB->generateNewStack(hero1, 148, 1, stacks.size(), true, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 18); | ||||
| 			CStack * stack = curB->generateNewStack(CStackInstance(148, 1, hero1), stacks.size(), true, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 18); | ||||
| 			stacks.push_back(stack); | ||||
| 		} | ||||
| 		if(hero1->getArt(15)) //first aid tent | ||||
| 		{ | ||||
| 			CStack * stack = curB->generateNewStack(hero1, 147, 1, stacks.size(), true, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 154); | ||||
| 			CStack * stack = curB->generateNewStack(CStackInstance(147, 1, hero1), stacks.size(), true, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 154); | ||||
| 			stacks.push_back(stack); | ||||
| 		} | ||||
| 	} | ||||
| @@ -1214,23 +1218,23 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet | ||||
| 	{ | ||||
| 		if(hero2->getArt(13)) //ballista | ||||
| 		{ | ||||
| 			CStack * stack = curB->generateNewStack(hero2, 146, 1, stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 66); | ||||
| 			CStack * stack = curB->generateNewStack(CStackInstance(146, 1, hero2),  stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 66); | ||||
| 			stacks.push_back(stack); | ||||
| 		} | ||||
| 		if(hero2->getArt(14)) //ammo cart | ||||
| 		{ | ||||
| 			CStack * stack = curB->generateNewStack(hero2, 148, 1, stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 32); | ||||
| 			CStack * stack = curB->generateNewStack(CStackInstance(148, 1, hero1), stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 32); | ||||
| 			stacks.push_back(stack); | ||||
| 		} | ||||
| 		if(hero2->getArt(15)) //first aid tent | ||||
| 		{ | ||||
| 			CStack * stack = curB->generateNewStack(hero2, 147, 1, stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 168); | ||||
| 			CStack * stack = curB->generateNewStack(CStackInstance(147, 1, hero2), stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 168); | ||||
| 			stacks.push_back(stack); | ||||
| 		} | ||||
| 	} | ||||
| 	if(town && hero1 && town->hasFort()) //catapult | ||||
| 	{ | ||||
| 		CStack * stack = curB->generateNewStack(hero1, 145, 1, stacks.size(), true, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 120); | ||||
| 		CStack * stack = curB->generateNewStack(CStackInstance(145, 1, hero1), stacks.size(), true, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 120); | ||||
| 		stacks.push_back(stack); | ||||
| 	} | ||||
| 	//war machines added | ||||
| @@ -1240,14 +1244,14 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet | ||||
| 		 | ||||
| 	case 3: //castle | ||||
| 		{//lower tower / upper tower | ||||
| 			CStack * stack = curB->generateNewStack(hero2, 149, 1, stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, -4); | ||||
| 			CStack * stack = curB->generateNewStack(CStackInstance(149, 1, hero2), stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, -4); | ||||
| 			stacks.push_back(stack); | ||||
| 			stack = curB->generateNewStack(hero2, 149, 1, stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, -3); | ||||
| 			stack = curB->generateNewStack(CStackInstance(149, 1, hero2), stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, -3); | ||||
| 			stacks.push_back(stack); | ||||
| 		} | ||||
| 	case 2: //citadel | ||||
| 		{//main tower | ||||
| 			CStack * stack = curB->generateNewStack(hero2, 149, 1, stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, -2); | ||||
| 			CStack * stack = curB->generateNewStack(CStackInstance(149, 1, hero2), stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, -2); | ||||
| 			stacks.push_back(stack); | ||||
| 		} | ||||
| 	} | ||||
| @@ -1335,7 +1339,7 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet | ||||
| 				if (val) | ||||
| 				{ | ||||
| 					GiveBonus gs; | ||||
| 					gs.bonus = HeroBonus(HeroBonus::ONE_BATTLE, HeroBonus::PRIMARY_SKILL, HeroBonus::OBJECT, val, -1, "", i); | ||||
| 					gs.bonus = Bonus(Bonus::ONE_BATTLE, Bonus::PRIMARY_SKILL, Bonus::OBJECT, val, -1, "", i); | ||||
| 					gs.id = hero2->id; | ||||
| 					sendAndApply(&gs); | ||||
| 				} | ||||
| @@ -1345,15 +1349,15 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet | ||||
| 		{ | ||||
| 			if(town->subID == 0  &&  vstd::contains(town->builtBuildings,22)) //castle, brotherhood of sword built | ||||
| 				for(int g=0; g<stacks.size(); ++g) | ||||
| 					stacks[g]->features.push_back(makeFeature(StackFeature::MORALE_BONUS, StackFeature::WHOLE_BATTLE, 0, 2, StackFeature::OTHER_SOURCE)); | ||||
| 					stacks[g]->bonuses.push_back(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, 2, Bonus::TOWN_STRUCTURE)); | ||||
|  | ||||
| 			else if(vstd::contains(town->builtBuildings,5)) //tavern is built | ||||
| 				for(int g=0; g<stacks.size(); ++g) | ||||
| 					stacks[g]->features.push_back(makeFeature(StackFeature::MORALE_BONUS, StackFeature::WHOLE_BATTLE, 0, 1, StackFeature::OTHER_SOURCE)); | ||||
| 					stacks[g]->bonuses.push_back(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, 1, Bonus::TOWN_STRUCTURE)); | ||||
|  | ||||
| 			if(town->subID == 1  &&  vstd::contains(town->builtBuildings,21)) //rampart, fountain of fortune is present | ||||
| 				for(int g=0; g<stacks.size(); ++g) | ||||
| 					stacks[g]->features.push_back(makeFeature(StackFeature::LUCK_BONUS, StackFeature::WHOLE_BATTLE, 0, 2, StackFeature::OTHER_SOURCE)); | ||||
| 					stacks[g]->bonuses.push_back(makeFeature(Bonus::LUCK, Bonus::ONE_BATTLE, 0, 2, Bonus::TOWN_STRUCTURE)); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @@ -1393,7 +1397,7 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet | ||||
| 				if(cHero == NULL) continue; | ||||
|  | ||||
| 				GiveBonus gs; | ||||
| 				gs.bonus = HeroBonus(HeroBonus::ONE_BATTLE, HeroBonus::MAGIC_SCHOOL_SKILL, HeroBonus::OBJECT, 3, -1, "", bonusSubtype); | ||||
| 				gs.bonus = Bonus(Bonus::ONE_BATTLE, Bonus::MAGIC_SCHOOL_SKILL, Bonus::OBJECT, 3, -1, "", bonusSubtype); | ||||
| 				gs.id = cHero->id; | ||||
|  | ||||
| 				sendAndApply(&gs); | ||||
| @@ -1406,10 +1410,10 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet | ||||
| 		{ | ||||
| 			for(int g=0; g<stacks.size(); ++g) //+1 morale bonus for good creatures, -1 morale bonus for evil creatures | ||||
| 			{ | ||||
| 				if (stacks[g]->creature->isGood()) | ||||
| 					stacks[g]->features.push_back(makeFeature(StackFeature::MORALE_BONUS, StackFeature::WHOLE_BATTLE, 0, 1, StackFeature::OTHER_SOURCE)); | ||||
| 				else if (stacks[g]->creature->isEvil()) | ||||
| 					stacks[g]->features.push_back(makeFeature(StackFeature::MORALE_BONUS, StackFeature::WHOLE_BATTLE, 0, -1, StackFeature::OTHER_SOURCE)); | ||||
| 				if (stacks[g]->type->isGood()) | ||||
| 					stacks[g]->bonuses.push_back(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, 1, Bonus::TERRAIN_OVERLAY)); | ||||
| 				else if (stacks[g]->type->isEvil()) | ||||
| 					stacks[g]->bonuses.push_back(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, -1, Bonus::TERRAIN_OVERLAY)); | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| @@ -1417,9 +1421,9 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet | ||||
| 		{ | ||||
| 			for(int g=0; g<stacks.size(); ++g) | ||||
| 			{ | ||||
| 				if(stacks[g]->creature->faction == -1) //+2 luck bonus for neutral creatures | ||||
| 				if(stacks[g]->type->faction == -1) //+2 luck bonus for neutral creatures | ||||
| 				{ | ||||
| 					stacks[g]->features.push_back(makeFeature(StackFeature::LUCK_BONUS, StackFeature::WHOLE_BATTLE, 0, 2, StackFeature::OTHER_SOURCE)); | ||||
| 					stacks[g]->bonuses.push_back(makeFeature(Bonus::LUCK, Bonus::ONE_BATTLE, 0, 2, Bonus::TERRAIN_OVERLAY)); | ||||
| 				} | ||||
| 			} | ||||
| 			break; | ||||
| @@ -1428,10 +1432,10 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet | ||||
| 		{ | ||||
| 			for(int g=0; g<stacks.size(); ++g) //-1 morale bonus for good creatures, +1 morale bonus for evil creatures | ||||
| 			{ | ||||
| 				if (stacks[g]->creature->isGood()) | ||||
| 					stacks[g]->features.push_back(makeFeature(StackFeature::MORALE_BONUS, StackFeature::WHOLE_BATTLE, 0, -1, StackFeature::OTHER_SOURCE)); | ||||
| 				else if (stacks[g]->creature->isEvil()) | ||||
| 					stacks[g]->features.push_back(makeFeature(StackFeature::MORALE_BONUS, StackFeature::WHOLE_BATTLE, 0, 1, StackFeature::OTHER_SOURCE)); | ||||
| 				if (stacks[g]->type->isGood()) | ||||
| 					stacks[g]->bonuses.push_back(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, -1, Bonus::TERRAIN_OVERLAY)); | ||||
| 				else if (stacks[g]->type->isEvil()) | ||||
| 					stacks[g]->bonuses.push_back(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, 1, Bonus::TERRAIN_OVERLAY)); | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| @@ -1439,8 +1443,8 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet | ||||
| 		{ | ||||
| 			for(int g=0; g<stacks.size(); ++g) //no luck nor morale | ||||
| 			{ | ||||
| 				stacks[g]->features.push_back(makeFeature(StackFeature::NO_MORALE, StackFeature::WHOLE_BATTLE, 0, 0, StackFeature::OTHER_SOURCE)); | ||||
| 				stacks[g]->features.push_back(makeFeature(StackFeature::NO_LUCK, StackFeature::WHOLE_BATTLE, 0, 0, StackFeature::OTHER_SOURCE)); | ||||
| 				stacks[g]->bonuses.push_back(makeFeature(Bonus::NO_MORALE, Bonus::ONE_BATTLE, 0, 0, Bonus::TERRAIN_OVERLAY)); | ||||
| 				stacks[g]->bonuses.push_back(makeFeature(Bonus::NO_LUCK, Bonus::ONE_BATTLE, 0, 0, Bonus::TERRAIN_OVERLAY)); | ||||
| 			} | ||||
|  | ||||
| 			const CGHeroInstance * cHero = NULL; | ||||
| @@ -1452,7 +1456,7 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet | ||||
| 				if(cHero == NULL) continue; | ||||
|  | ||||
| 				GiveBonus gs; | ||||
| 				gs.bonus = HeroBonus(HeroBonus::ONE_BATTLE, HeroBonus::BLOCK_SPELLS_ABOVE_LEVEL, HeroBonus::OBJECT, 1, -1, "", bonusSubtype); | ||||
| 				gs.bonus = Bonus(Bonus::ONE_BATTLE, Bonus::BLOCK_SPELLS_ABOVE_LEVEL, Bonus::OBJECT, 1, -1, "", bonusSubtype); | ||||
| 				gs.id = cHero->id; | ||||
|  | ||||
| 				sendAndApply(&gs); | ||||
| @@ -1478,7 +1482,7 @@ void CGameHandler::checkForBattleEnd( std::vector<CStack*> &stacks ) | ||||
| 	hasStack[0] = hasStack[1] = false; | ||||
| 	for(int b = 0; b<stacks.size(); ++b) | ||||
| 	{ | ||||
| 		if(stacks[b]->alive() && !stacks[b]->hasFeatureOfType(StackFeature::SIEGE_WEAPON)) | ||||
| 		if(stacks[b]->alive() && !stacks[b]->hasBonusOfType(Bonus::SIEGE_WEAPON)) | ||||
| 		{ | ||||
| 			hasStack[1-stacks[b]->attackerOwned] = true; | ||||
| 		} | ||||
| @@ -1772,19 +1776,19 @@ void CGameHandler::giveResource(int player, int which, int val) | ||||
| } | ||||
| void CGameHandler::giveCreatures (int objid, const CGHeroInstance * h, CCreatureSet creatures) | ||||
| { | ||||
| 	if (creatures.slots.size() <= 0) | ||||
| 	if (creatures.stacksCount() <= 0) | ||||
| 		return; | ||||
| 	CCreatureSet heroArmy = h->army; | ||||
| 	while (creatures.slots.size() > 0) | ||||
| 	CCreatureSet heroArmy = h->getArmy(); | ||||
| 	while (creatures.stacksCount() > 0) | ||||
| 	{ | ||||
| 		int slot = heroArmy.getSlotFor(creatures.slots.begin()->second.type->idNumber); | ||||
| 		int slot = heroArmy.getSlotFor(creatures.Slots().begin()->second.type->idNumber); | ||||
| 		if (slot < 0) | ||||
| 			break; | ||||
| 		heroArmy.addToSlot(slot, creatures.slots.begin()->second); | ||||
| 		creatures.slots.erase (creatures.slots.begin()); | ||||
| 	} | ||||
|  | ||||
| 	if (creatures.slots.size() == 0) //all creatures can be moved to hero army - do that | ||||
| 	if (creatures.stacksCount() == 0) //all creatures can be moved to hero army - do that | ||||
| 	{ | ||||
| 		SetGarrisons sg; | ||||
| 		sg.garrs[h->id] = heroArmy; | ||||
| @@ -1804,7 +1808,7 @@ void CGameHandler::takeCreatures (int objid, TSlots creatures) //probably we cou | ||||
| 	if (creatures.size() <= 0) | ||||
| 		return; | ||||
| 	const CArmedInstance* obj = static_cast<const CArmedInstance*>(getObj(objid)); | ||||
| 	CCreatureSet newArmy = obj->army; | ||||
| 	CCreatureSet newArmy = obj->getArmy(); | ||||
| 	while (creatures.size() > 0) | ||||
| 	{ | ||||
| 		int slot = newArmy.getSlotFor(creatures.begin()->second.type->idNumber); | ||||
| @@ -2227,7 +2231,7 @@ bool CGameHandler::arrangeStacks( si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, | ||||
| { | ||||
| 	CArmedInstance *s1 = static_cast<CArmedInstance*>(gs->map->objects[id1]), | ||||
| 		*s2 = static_cast<CArmedInstance*>(gs->map->objects[id2]); | ||||
| 	CCreatureSet temp1 = s1->army, temp2 = s2->army, | ||||
| 	CCreatureSet temp1 = s1->getArmy(), temp2 = s2->getArmy(), | ||||
| 		&S1 = temp1, &S2 = (s1!=s2)?(temp2):(temp1); | ||||
|  | ||||
| 	if(!isAllowedExchange(id1,id2)) | ||||
| @@ -2295,8 +2299,8 @@ bool CGameHandler::arrangeStacks( si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, | ||||
| 		if(!S1.slots[p1].count) //if we've moved all creatures | ||||
| 			S1.slots.erase(p1); | ||||
| 	} | ||||
| 	if((s1->needsLastStack() && !S1.slots.size()) //it's not allowed to take last stack from hero army! | ||||
| 		|| (s2->needsLastStack() && !S2.slots.size()) | ||||
| 	if((s1->needsLastStack() && !S1.stacksCount()) //it's not allowed to take last stack from hero army! | ||||
| 		|| (s2->needsLastStack() && !S2.stacksCount()) | ||||
| 	) | ||||
| 	{ | ||||
| 		complain("Cannot take the last stack!"); | ||||
| @@ -2339,14 +2343,14 @@ int CGameHandler::getPlayerAt( CConnection *c ) const | ||||
| bool CGameHandler::disbandCreature( si32 id, ui8 pos ) | ||||
| { | ||||
| 	CArmedInstance *s1 = static_cast<CArmedInstance*>(gs->map->objects[id]); | ||||
| 	if(!vstd::contains(s1->army.slots,pos)) | ||||
| 	if(!vstd::contains(s1->slots,pos)) | ||||
| 	{ | ||||
| 		complain("Illegal call to disbandCreature - no such stack in army!"); | ||||
| 		return false; | ||||
| 	} | ||||
| 	s1->army.slots.erase(pos); | ||||
| 	s1->slots.erase(pos); | ||||
| 	SetGarrisons sg; | ||||
| 	sg.garrs[id] = s1->army; | ||||
| 	sg.garrs[id] = s1->getArmy(); | ||||
| 	sendAndApply(&sg); | ||||
| 	return true; | ||||
| } | ||||
| @@ -2398,7 +2402,7 @@ bool CGameHandler::buildStructure( si32 tid, si32 bid ) | ||||
| 		SetAvailableCreatures ssi; | ||||
| 		ssi.tid = tid; | ||||
| 		ssi.creatures = t->creatures; | ||||
| 		ssi.creatures[bid-30].first = VLC->creh->creatures[crid].growth; | ||||
| 		ssi.creatures[bid-30].first = VLC->creh->creatures[crid]->growth; | ||||
| 		ssi.creatures[bid-30].second.push_back(crid); | ||||
| 		sendAndApply(&ssi); | ||||
| 	} | ||||
| @@ -2495,10 +2499,10 @@ bool CGameHandler::recruitCreatures( si32 objid, ui32 crid, ui32 cram ) | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	int slot = dst->army.getSlotFor(crid); | ||||
| 	int slot = dst-> getSlotFor(crid); | ||||
|  | ||||
| 	if(!found && complain("Cannot recruit: no such creatures!") | ||||
| 		|| cram > VLC->creh->creatures[crid].maxAmount(gs->getPlayer(dst->tempOwner)->resources) && complain("Cannot recruit: lack of resources!") | ||||
| 		|| cram > VLC->creh->creatures[crid]->maxAmount(gs->getPlayer(dst->tempOwner)->resources) && complain("Cannot recruit: lack of resources!") | ||||
| 		|| cram<=0	&& complain("Cannot recruit: cram <= 0!") | ||||
| 		|| slot<0  && complain("Cannot recruit: no available slot!"))  | ||||
| 	{ | ||||
| @@ -2509,7 +2513,7 @@ bool CGameHandler::recruitCreatures( si32 objid, ui32 crid, ui32 cram ) | ||||
| 	SetResources sr; | ||||
| 	sr.player = dst->tempOwner; | ||||
| 	for(int i=0;i<RESOURCE_QUANTITY;i++) | ||||
| 		sr.res[i]  =  gs->getPlayer(dst->tempOwner)->resources[i] - (VLC->creh->creatures[crid].cost[i] * cram); | ||||
| 		sr.res[i]  =  gs->getPlayer(dst->tempOwner)->resources[i] - (VLC->creh->creatures[crid]->cost[i] * cram); | ||||
|  | ||||
| 	SetAvailableCreatures sac; | ||||
| 	sac.tid = objid; | ||||
| @@ -2517,7 +2521,7 @@ bool CGameHandler::recruitCreatures( si32 objid, ui32 crid, ui32 cram ) | ||||
| 	sac.creatures[level].first -= cram; | ||||
|  | ||||
| 	SetGarrisons sg; | ||||
| 	sg.garrs[dst->id] = dst->army; | ||||
| 	sg.garrs[dst->id] = dst->getArmy(); | ||||
| 	sg.garrs[dst->id] .addToSlot(slot, crid, cram); | ||||
|  | ||||
| 	sendAndApply(&sr);  | ||||
| @@ -2531,7 +2535,7 @@ bool CGameHandler::upgradeCreature( ui32 objid, ui8 pos, ui32 upgID ) | ||||
| 	CArmedInstance *obj = static_cast<CArmedInstance*>(gs->map->objects[objid]); | ||||
| 	UpgradeInfo ui = gs->getUpgradeInfo(obj,pos); | ||||
| 	int player = obj->tempOwner; | ||||
| 	int crQuantity = obj->army.slots[pos].count; | ||||
| 	int crQuantity = obj->slots[pos].count; | ||||
|  | ||||
| 	//check if upgrade is possible | ||||
| 	if((ui.oldID<0 || !vstd::contains(ui.newID,upgID)) && complain("That upgrade is not possible!"))  | ||||
| @@ -2567,7 +2571,7 @@ bool CGameHandler::upgradeCreature( ui32 objid, ui8 pos, ui32 upgID ) | ||||
|  | ||||
| 	//upgrade creature | ||||
| 	SetGarrisons sg; | ||||
| 	sg.garrs[objid] = obj->army; | ||||
| 	sg.garrs[objid] = obj->getArmy(); | ||||
| 	sg.garrs[objid].slots[pos].setType(upgID); | ||||
| 	sendAndApply(&sg);	 | ||||
| 	return true; | ||||
| @@ -2578,7 +2582,7 @@ bool CGameHandler::garrisonSwap( si32 tid ) | ||||
| 	CGTownInstance *town = gs->getTown(tid); | ||||
| 	if(!town->garrisonHero && town->visitingHero) //visiting => garrison, merge armies: town army => hero army | ||||
| 	{ | ||||
| 		CCreatureSet csn = town->visitingHero->army, cso = town->army; | ||||
| 		CCreatureSet csn = town->visitingHero->getArmy(), cso = town->getArmy(); | ||||
| 		while(!cso.slots.empty())//while there are unmoved creatures | ||||
| 		{ | ||||
| 			int pos = csn.getSlotFor(cso.slots.begin()->second.type->idNumber); | ||||
| @@ -2645,8 +2649,8 @@ bool CGameHandler::garrisonSwap( si32 tid ) | ||||
| 	else if (town->garrisonHero && town->visitingHero) //swap visiting and garrison hero | ||||
| 	{ | ||||
| 		SetGarrisons sg; | ||||
| 		sg.garrs[town->id] = town->visitingHero->army; | ||||
| 		sg.garrs[town->garrisonHero->id] = town->garrisonHero->army; | ||||
| 		sg.garrs[town->id] = town->visitingHero->getArmy();; | ||||
| 		sg.garrs[town->garrisonHero->id] = town->garrisonHero->getArmy(); | ||||
|  | ||||
| 		SetHeroesInTown intown; | ||||
| 		intown.tid = tid; | ||||
| @@ -2915,7 +2919,7 @@ bool CGameHandler::tradeResources( ui32 val, ui8 player, ui32 id1, ui32 id2 ) | ||||
|  | ||||
| bool CGameHandler::setFormation( si32 hid, ui8 formation ) | ||||
| { | ||||
| 	gs->getHero(hid)->army.formation = formation; | ||||
| 	gs->getHero(hid)-> formation = formation; | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| @@ -3032,12 +3036,12 @@ bool CGameHandler::makeBattleAction( BattleAction &ba ) | ||||
| 				*stackAtEnd = gs->curB->getStackT(ba.additionalInfo); | ||||
|  | ||||
| 			if(curStack->position != ba.destinationTile //we wasn't able to reach destination tile | ||||
| 				&& !(curStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE) | ||||
| 				&& !(curStack->doubleWide() | ||||
| 					&&  ( curStack->position == ba.destinationTile + (curStack->attackerOwned ?  +1 : -1 ) ) | ||||
| 						) //nor occupy specified hex | ||||
| 				)  | ||||
| 			{ | ||||
| 				std::string problem = "We cannot move this stack to its destination " + curStack->creature->namePl; | ||||
| 				std::string problem = "We cannot move this stack to its destination " + curStack->type->namePl; | ||||
| 				tlog3 << problem << std::endl; | ||||
| 				complain(problem); | ||||
| 				ok = false; | ||||
| @@ -3068,11 +3072,11 @@ bool CGameHandler::makeBattleAction( BattleAction &ba ) | ||||
|  | ||||
| 			if( !( | ||||
| 				(BattleInfo::mutualPosition(curpos, enemypos) >= 0)						//front <=> front | ||||
| 				|| (curStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE)									//back <=> front | ||||
| 				|| (curStack->doubleWide()									//back <=> front | ||||
| 					&& BattleInfo::mutualPosition(curpos + (curStack->attackerOwned ? -1 : 1), enemypos) >= 0) | ||||
| 				|| (stackAtEnd->hasFeatureOfType(StackFeature::DOUBLE_WIDE)									//front <=> back | ||||
| 				|| (stackAtEnd->doubleWide()									//front <=> back | ||||
| 					&& BattleInfo::mutualPosition(curpos, enemypos + (stackAtEnd->attackerOwned ? -1 : 1)) >= 0) | ||||
| 				|| (stackAtEnd->hasFeatureOfType(StackFeature::DOUBLE_WIDE) && curStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE)//back <=> back | ||||
| 				|| (stackAtEnd->doubleWide() && curStack->doubleWide()//back <=> back | ||||
| 					&& BattleInfo::mutualPosition(curpos + (curStack->attackerOwned ? -1 : 1), enemypos + (stackAtEnd->attackerOwned ? -1 : 1)) >= 0) | ||||
| 				) | ||||
| 				) | ||||
| @@ -3089,11 +3093,11 @@ bool CGameHandler::makeBattleAction( BattleAction &ba ) | ||||
| 			handleAfterAttackCasting(bat); | ||||
|  | ||||
| 			//counterattack | ||||
| 			if(!curStack->hasFeatureOfType(StackFeature::BLOCKS_RETALIATION) | ||||
| 			if(!curStack->hasBonusOfType(Bonus::BLOCKS_RETALIATION) | ||||
| 				&& stackAtEnd->alive() | ||||
| 				&& ( stackAtEnd->counterAttacks > 0 || stackAtEnd->hasFeatureOfType(StackFeature::UNLIMITED_RETALIATIONS) ) | ||||
| 				&& !stackAtEnd->hasFeatureOfType(StackFeature::SIEGE_WEAPON) | ||||
| 				&& !stackAtEnd->hasFeatureOfType(StackFeature::HYPNOTIZED)) | ||||
| 				&& ( stackAtEnd->counterAttacks > 0 || stackAtEnd->hasBonusOfType(Bonus::UNLIMITED_RETALIATIONS) ) | ||||
| 				&& !stackAtEnd->hasBonusOfType(Bonus::SIEGE_WEAPON) | ||||
| 				&& !stackAtEnd->hasBonusOfType(Bonus::HYPNOTIZED)) | ||||
| 			{ | ||||
| 				prepareAttack(bat, stackAtEnd, curStack, 0); | ||||
| 				bat.flags |= 2; | ||||
| @@ -3102,8 +3106,8 @@ bool CGameHandler::makeBattleAction( BattleAction &ba ) | ||||
| 			} | ||||
|  | ||||
| 			//second attack | ||||
| 			if(curStack->valOfFeatures(StackFeature::ADDITIONAL_ATTACK) > 0 | ||||
| 				&& !curStack->hasFeatureOfType(StackFeature::SHOOTER) | ||||
| 			if(curStack->valOfBonuses(Bonus::ADDITIONAL_ATTACK) > 0 | ||||
| 				&& !curStack->hasBonusOfType(Bonus::SHOOTER) | ||||
| 				&& curStack->alive() | ||||
| 				&& stackAtEnd->alive()  ) | ||||
| 			{ | ||||
| @@ -3114,7 +3118,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba ) | ||||
| 			} | ||||
|  | ||||
| 			//return | ||||
| 			if(curStack->hasFeatureOfType(StackFeature::RETURN_AFTER_STRIKE) && startingPos != curStack->position && curStack->alive()) | ||||
| 			if(curStack->hasBonusOfType(Bonus::RETURN_AFTER_STRIKE) && startingPos != curStack->position && curStack->alive()) | ||||
| 			{ | ||||
| 				moveStack(ba.stackNumber, startingPos); | ||||
| 				//NOTE: curStack->ID == ba.stackNumber (rev 1431) | ||||
| @@ -3136,7 +3140,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba ) | ||||
| 			bat.flags |= 1; | ||||
| 			sendAndApply(&bat); | ||||
|  | ||||
| 			if(curStack->valOfFeatures(StackFeature::ADDITIONAL_ATTACK) > 0 //if unit shots twice let's make another shot | ||||
| 			if(curStack->valOfBonuses(Bonus::ADDITIONAL_ATTACK) > 0 //if unit shots twice let's make another shot | ||||
| 				&& curStack->alive() | ||||
| 				&& destStack->alive() | ||||
| 				&& curStack->shots | ||||
| @@ -3260,7 +3264,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba ) | ||||
| 			CStack *healer = gs->curB->getStack(ba.stackNumber), | ||||
| 				*destStack = gs->curB->getStackT(ba.destinationTile); | ||||
|  | ||||
| 			if(healer == NULL || destStack == NULL || !healer->hasFeatureOfType(StackFeature::HEALER)) | ||||
| 			if(healer == NULL || destStack == NULL || !healer->hasBonusOfType(Bonus::HEALER)) | ||||
| 			{ | ||||
| 				complain("There is either no healer, no destination, or healer cannot heal :P"); | ||||
| 			} | ||||
| @@ -3337,24 +3341,30 @@ void CGameHandler::playerMessage( ui8 player, const std::string &message ) | ||||
| 	} | ||||
| 	else if(message == "vcmiainur") //gives 5 archangels into each slot | ||||
| 	{ | ||||
| 		SetGarrisons sg; | ||||
| 		CGHeroInstance *hero = gs->getHero(gs->getPlayer(player)->currentSelection); | ||||
| 		if(!hero) return; | ||||
| 		sg.garrs[hero->id] = hero->army; | ||||
| 		for(int i=0;i<7;i++) | ||||
| 			if(!vstd::contains(sg.garrs[hero->id].slots,i)) | ||||
| 				sg.garrs[hero->id].slots[i] = CStackInstance(13,5); | ||||
|  | ||||
| 		SetGarrisons sg; | ||||
| 		CCreatureSet &newArmy = sg.garrs[hero->id]; | ||||
|  | ||||
| 		newArmy = hero->getArmy(); | ||||
| 		for(int i=0; i<ARMY_SIZE; i++) | ||||
| 			if(newArmy.slotEmpty(i)) | ||||
| 				newArmy.addToSlot(i, CStackInstance(13,5)); | ||||
| 		sendAndApply(&sg); | ||||
| 	} | ||||
| 	else if(message == "vcmiangband") //gives 10 black knight into each slot | ||||
| 	{ | ||||
| 		SetGarrisons sg; | ||||
| 		CGHeroInstance *hero = gs->getHero(gs->getPlayer(player)->currentSelection); | ||||
| 		if(!hero) return; | ||||
| 		sg.garrs[hero->id] = hero->army; | ||||
| 		for(int i=0;i<7;i++) | ||||
| 			if(!vstd::contains(sg.garrs[hero->id].slots,i)) | ||||
| 				sg.garrs[hero->id].slots[i] = CStackInstance(66,10); | ||||
|  | ||||
| 		SetGarrisons sg; | ||||
| 		CCreatureSet &newArmy = sg.garrs[hero->id]; | ||||
|  | ||||
| 		newArmy = hero->getArmy(); | ||||
| 		for(int i=0; i<ARMY_SIZE; i++) | ||||
| 			if(newArmy.slotEmpty(i)) | ||||
| 				newArmy.addToSlot(i, CStackInstance(66,10)); | ||||
| 		sendAndApply(&sg); | ||||
| 	} | ||||
| 	else if(message == "vcminoldor") //all war machines | ||||
| @@ -3447,9 +3457,9 @@ static std::vector<ui32> calculateResistedStacks(const CSpell * sp, const CGHero | ||||
| 	std::vector<ui32> ret; | ||||
| 	for(std::set<CStack*>::const_iterator it = affectedCreatures.begin(); it != affectedCreatures.end(); ++it) | ||||
| 	{ | ||||
| 		if ((*it)->hasFeatureOfType(StackFeature::SPELL_IMMUNITY, sp->id) //100% sure spell immunity | ||||
| 			|| ( (*it)->hasFeatureOfType(StackFeature::LEVEL_SPELL_IMMUNITY) && | ||||
| 				(*it)->valOfFeatures(StackFeature::LEVEL_SPELL_IMMUNITY) >= sp->level) ) //some creature abilities have level 0 | ||||
| 		if ((*it)->hasBonusOfType(Bonus::SPELL_IMMUNITY, sp->id) //100% sure spell immunity | ||||
| 			|| ( (*it)->hasBonusOfType(Bonus::LEVEL_SPELL_IMMUNITY) && | ||||
| 				(*it)->valOfBonuses(Bonus::LEVEL_SPELL_IMMUNITY) >= sp->level) ) //some creature abilities have level 0 | ||||
| 		{ | ||||
| 			ret.push_back((*it)->ID); | ||||
| 			continue; | ||||
| @@ -3465,11 +3475,11 @@ static std::vector<ui32> calculateResistedStacks(const CSpell * sp, const CGHero | ||||
| 		else | ||||
| 			bonusHero = hero2; | ||||
|  | ||||
| 		int prob = (*it)->valOfFeatures(StackFeature::MAGIC_RESISTANCE); //probability of resistance in % | ||||
| 		int prob = (*it)->valOfBonuses(Bonus::MAGIC_RESISTANCE); //probability of resistance in % | ||||
| 		if(bonusHero) | ||||
| 		{ | ||||
| 			//bonusHero's resistance support (secondary skils and artifacts) | ||||
| 			prob += bonusHero->valOfBonuses(HeroBonus::MAGIC_RESISTANCE); | ||||
| 			prob += bonusHero->valOfBonuses(Bonus::MAGIC_RESISTANCE); | ||||
|  | ||||
| 			switch(bonusHero->getSecSkillLevel(26)) //resistance | ||||
| 			{ | ||||
| @@ -3496,8 +3506,8 @@ static std::vector<ui32> calculateResistedStacks(const CSpell * sp, const CGHero | ||||
| 	{ | ||||
| 		for(std::set<CStack*>::const_iterator it = affectedCreatures.begin(); it != affectedCreatures.end(); ++it) | ||||
| 		{ | ||||
| 			if( (*it)->hasFeatureOfType(StackFeature::SPELL_IMMUNITY, sp->id) //100% sure spell immunity | ||||
| 				|| ( (*it)->amount - 1 ) * (*it)->MaxHealth() + (*it)->firstHPleft  | ||||
| 			if( (*it)->hasBonusOfType(Bonus::SPELL_IMMUNITY, sp->id) //100% sure spell immunity | ||||
| 				|| ( (*it)->count - 1 ) * (*it)->MaxHealth() + (*it)->firstHPleft  | ||||
| 				>  | ||||
| 				caster->getPrimSkillLevel(2) * 25 + sp->powers[caster->getSpellSchoolLevel(sp)] | ||||
| 			) | ||||
| @@ -3630,7 +3640,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, int destinatio | ||||
| 			for(std::set<CStack*>::iterator it = attackedCres.begin(); it != attackedCres.end(); ++it) | ||||
| 			{ | ||||
| 				if(vstd::contains(sc.resisted, (*it)->ID) //this creature resisted the spell | ||||
| 					|| (spellID == 39 && !(*it)->hasFeatureOfType(StackFeature::UNDEAD)) //we try to cast animate dead on living stack | ||||
| 					|| (spellID == 39 && !(*it)->hasBonusOfType(Bonus::UNDEAD)) //we try to cast animate dead on living stack | ||||
| 					)  | ||||
| 					continue; | ||||
| 				StacksHealedOrResurrected::HealInfo hi; | ||||
| @@ -3690,7 +3700,7 @@ bool CGameHandler::makeCustomAction( BattleAction &ba ) | ||||
| 				|| (h->mana < gs->curB->getSpellCost(s, h)) //not enough mana | ||||
| 				|| (ba.additionalInfo < 10) //it's adventure spell (not combat) | ||||
| 				|| (gs->curB->castSpells[ba.side]) //spell has been cast | ||||
| 				|| (NBonus::hasOfType(secondHero, HeroBonus::SPELL_IMMUNITY, s->id)) //non - casting hero provides immunity for this spell  | ||||
| 				|| (NBonus::hasOfType(secondHero, Bonus::SPELL_IMMUNITY, s->id)) //non - casting hero provides immunity for this spell  | ||||
| 				|| (gs->battleMaxSpellLevel() < s->level) //non - casting hero stops caster from casting this spell | ||||
| 				) | ||||
| 			{ | ||||
| @@ -4159,12 +4169,12 @@ bool CGameHandler::dig( const CGHeroInstance *h ) | ||||
| void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat ) | ||||
| { | ||||
| 	const CStack * attacker = gs->curB->getStack(bat.stackAttacking); | ||||
| 	if( attacker->hasFeatureOfType(StackFeature::SPELL_AFTER_ATTACK) ) | ||||
| 	if( attacker->hasBonusOfType(Bonus::SPELL_AFTER_ATTACK) ) | ||||
| 	{ | ||||
| 		for (int it=0; it<attacker->features.size(); ++it) | ||||
|  | ||||
| 		BOOST_FOREACH(const Bonus & sf, attacker->bonuses) | ||||
| 		{ | ||||
| 			const StackFeature & sf = attacker->features[it]; | ||||
| 			if (sf.type == StackFeature::SPELL_AFTER_ATTACK) | ||||
| 			if (sf.type == Bonus::SPELL_AFTER_ATTACK) | ||||
| 			{ | ||||
| 				const CStack * oneOfAttacked = NULL; | ||||
| 				for(int g=0; g<bat.bsa.size(); ++g) | ||||
| @@ -4179,7 +4189,7 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat ) | ||||
| 					return; | ||||
|  | ||||
| 				int spellID = sf.subtype; | ||||
| 				int spellLevel = sf.value; | ||||
| 				int spellLevel = sf.val; | ||||
| 				int chance = sf.additionalInfo % 1000; | ||||
| 				int meleeRanged = sf.additionalInfo / 1000; | ||||
| 				int destination = oneOfAttacked->position; | ||||
| @@ -4188,7 +4198,7 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat ) | ||||
| 					continue; | ||||
|  | ||||
| 				//casting | ||||
| 				handleSpellCasting(spellID, spellLevel, destination, !attacker->attackerOwned, attacker->owner, NULL, NULL, attacker->amount); | ||||
| 				handleSpellCasting(spellID, spellLevel, destination, !attacker->attackerOwned, attacker->owner, NULL, NULL, attacker->count); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| @@ -4304,7 +4314,7 @@ bool CGameHandler::castSpell(const CGHeroInstance *h, int spellID, const int3 &p | ||||
| 				COMPLAIN_RET("Destination tile doesn't exist!"); | ||||
| 			if(!h->movement) | ||||
| 				COMPLAIN_RET("Hero needs movement points to cast Dimension Door!"); | ||||
| 			if(h->getBonusesCount(HeroBonus::CASTED_SPELL, Spells::DIMENSION_DOOR) >= s->powers[schoolLevel]) //limit casts per turn | ||||
| 			if(h->getBonusesCount(Bonus::CASTED_SPELL, Spells::DIMENSION_DOOR) >= s->powers[schoolLevel]) //limit casts per turn | ||||
| 			{ | ||||
| 				InfoWindow iw; | ||||
| 				iw.player = h->tempOwner; | ||||
| @@ -4316,7 +4326,7 @@ bool CGameHandler::castSpell(const CGHeroInstance *h, int spellID, const int3 &p | ||||
|  | ||||
| 			GiveBonus gb; | ||||
| 			gb.id = h->id; | ||||
| 			gb.bonus = HeroBonus(HeroBonus::ONE_DAY, HeroBonus::NONE, HeroBonus::CASTED_SPELL, 0, Spells::DIMENSION_DOOR); | ||||
| 			gb.bonus = Bonus(Bonus::ONE_DAY, Bonus::NONE, Bonus::CASTED_SPELL, 0, Spells::DIMENSION_DOOR); | ||||
| 			sendAndApply(&gb); | ||||
| 			 | ||||
| 			if(!dest->isClear(curr)) //wrong dest tile | ||||
|   | ||||
| @@ -101,7 +101,7 @@ public: | ||||
| 	void prepareAttack(BattleAttack &bat, const CStack *att, const CStack *def, int distance); //distance - number of hexes travelled before attacking | ||||
| 	void prepareAttacked(BattleStackAttacked &bsa, const CStack *def); | ||||
| 	void checkForBattleEnd( std::vector<CStack*> &stacks ); | ||||
| 	void setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet &army1, const CCreatureSet &army2, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool creatureBank, const CGTownInstance *town); | ||||
| 	void setupBattle( BattleInfo * curB, int3 tile, const CArmedInstance *army1, const CArmedInstance *army2, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool creatureBank, const CGTownInstance *town); | ||||
|  | ||||
| 	CGameHandler(void); | ||||
| 	~CGameHandler(void); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user