소스 검색

Separated CStack and CStackInstance.

Michał W. Urbańczyk 15 년 전
부모
커밋
9250cc8adf
12개의 변경된 파일132개의 추가작업 그리고 79개의 파일을 삭제
  1. 6 6
      AI/GeniusAI/BattleLogic.cpp
  2. 1 1
      CCallback.cpp
  3. 42 42
      client/CBattleInterface.cpp
  4. 2 2
      client/CPlayerInterface.cpp
  5. 12 0
      lib/CCreatureSet.cpp
  6. 1 0
      lib/CCreatureSet.h
  7. 21 16
      lib/CGameState.cpp
  8. 19 5
      lib/CGameState.h
  9. 18 0
      lib/HeroBonus.cpp
  10. 5 2
      lib/HeroBonus.h
  11. 1 1
      lib/NetPacksLib.cpp
  12. 4 4
      server/CGameHandler.cpp

+ 6 - 6
AI/GeniusAI/BattleLogic.cpp

@@ -138,7 +138,7 @@ void CBattleLogic::MakeStatistics(int currentCreatureId)
 			m_statHitPoints.push_back(std::pair<int, int>(id, hitPoints));
 			m_statMaxSpeed.push_back(std::pair<int, int>(id, stackHP));
 
-			totalEnemyDamage += (st->type->damageMax + st->type->damageMin) * st->count / 2;
+			totalEnemyDamage += (st->getCreature()->damageMax + st->getCreature()->damageMin) * st->count / 2;
 			totalEnemyHitPoints += hitPoints;
 
 			// calculate casualties
@@ -195,12 +195,12 @@ void CBattleLogic::MakeStatistics(int currentCreatureId)
 
 			m_statCasualties.push_back(std::pair<int, SCreatureCasualties>(id, cs));
 
-			if (st->type->isShooting() && st->shots > 0)
+			if (st->getCreature()->isShooting() && st->shots > 0)
 			{
 				m_statDistanceFromShooters.push_back(std::pair<int, int>(id, m_battleHelper.GetShortestDistance(currentStack->position, st->position)));
 			}
 
-			if (currentStack->hasBonusOfType(Bonus::FLYING) || (currentStack->type->isShooting() && currentStack->shots > 0))
+			if (currentStack->hasBonusOfType(Bonus::FLYING) || (currentStack->getCreature()->isShooting() && currentStack->shots > 0))
 			{
 				m_statDistance.push_back(std::pair<int, int>(id, m_battleHelper.GetShortestDistance(currentStack->position, st->position)));
 			}
@@ -259,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->type->idNumber == 147) //turret or first aid kit
+	if(currentStack->position < 0 || currentStack->getCreature()->idNumber == 147) //turret or first aid kit
 	{
 		return MakeDefend(stackID);
 	}
@@ -762,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->type)
+		if (c && c->getCreature())
 		{
-			message += c->type->nameRef;
+			message += c->getCreature()->nameRef;
 		}
 		else
 		{

+ 1 - 1
CCallback.cpp

@@ -578,7 +578,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]->type);
+			return *(gs->curB->stacks[h]->getCreature());
 	}
 #ifndef __GNUC__
 	throw new std::exception("Cannot find the creature");

+ 42 - 42
client/CBattleInterface.cpp

@@ -475,7 +475,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->type->attackClimaxFrame )
+			if( attackerAnimType == 11 && attackerAnimType == 12 && attackerAnimType == 13 && owner->creAnims[IDby]->getFrame() < attacker->getCreature()->attackClimaxFrame )
 				return false;
 		}
 
@@ -506,7 +506,7 @@ bool CDefenceAnim::init()
 	{		
 		for(std::list<SProjectileInfo>::const_iterator it = owner->projectiles.begin(); it != owner->projectiles.end(); ++it)
 		{
-			if(it->creID == attacker->type->idNumber)
+			if(it->creID == attacker->getCreature()->idNumber)
 			{
 				return false;
 			}
@@ -516,13 +516,13 @@ bool CDefenceAnim::init()
 	//initializing
 	if(killed)
 	{
-		CGI->soundh->playSound(battle_sound(attacked->type, killed));
+		CGI->soundh->playSound(battle_sound(attacked->getCreature(), 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->type, wince));
+		CGI->soundh->playSound(battle_sound(attacked->getCreature(), wince));
 		owner->creAnims[stackID]->setType(3); //getting hit
 	}
 
@@ -626,7 +626,7 @@ bool CBattleStackMoved::init()
 	//unit reversed
 
 	if(owner->moveSh <= 0)
-		owner->moveSh = CGI->soundh->playSound(battle_sound(movedStack->type, move), -1);
+		owner->moveSh = CGI->soundh->playSound(battle_sound(movedStack->getCreature(), move), -1);
 
 	//step shift calculation
 	posX = owner->creAnims[stackID]->pos.x, posY = owner->creAnims[stackID]->pos.y; // for precise calculations ;]
@@ -742,7 +742,7 @@ bool CBattleMoveStart::init()
 		return false;
 	}
 
-	CGI->soundh->playSound(battle_sound(movedStack->type, startMoving));
+	CGI->soundh->playSound(battle_sound(movedStack->getCreature(), startMoving));
 
 	return true;
 }
@@ -787,7 +787,7 @@ bool CBattleMoveEnd::init()
 		return false;
 	}
 
-	CGI->soundh->playSound(battle_sound(movedStack->type, endMoving));
+	CGI->soundh->playSound(battle_sound(movedStack->getCreature(), endMoving));
 
 	owner->creAnims[stackID]->setType(21);
 
@@ -828,9 +828,9 @@ void CBattleAttack::nextFrame()
 	if(owner->creAnims[stackID]->onFirstFrameInGroup())
 	{
 		if(shooting)
-			CGI->soundh->playSound(battle_sound(attackingStack->type, shoot));
+			CGI->soundh->playSound(battle_sound(attackingStack->getCreature(), shoot));
 		else
-			CGI->soundh->playSound(battle_sound(attackingStack->type, attack));
+			CGI->soundh->playSound(battle_sound(attackingStack->getCreature(), attack));
 	}
 	else if(owner->creAnims[stackID]->onLastFrameInGroup())
 	{
@@ -852,7 +852,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->type->idNumber != 145) //catapult is allowed to attack not-creature
+	if(attackingStack->getCreature()->idNumber != 145) //catapult is allowed to attack not-creature
 	{
 		assert(attackedStack && "attackedStack is NULL in CBattleAttack::CBattleAttack !\n");
 	}
@@ -981,7 +981,7 @@ bool CShootingAnim::init()
 		projectileAngle = -projectileAngle;
 
 	SProjectileInfo spi;
-	spi.creID = shooter->type->idNumber;
+	spi.creID = shooter->getCreature()->idNumber;
 	spi.reverse = !shooter->attackerOwned;
 
 	spi.step = 0;
@@ -1009,18 +1009,18 @@ bool CShootingAnim::init()
 
 	if(projectileAngle > straightAngle) //upper shot
 	{
-		spi.x = xycoord.x + 200 + shooter->type->upperRightMissleOffsetX;
-		spi.y = xycoord.y + 100 - shooter->type->upperRightMissleOffsetY;
+		spi.x = xycoord.x + 200 + shooter->getCreature()->upperRightMissleOffsetX;
+		spi.y = xycoord.y + 100 - shooter->getCreature()->upperRightMissleOffsetY;
 	}
 	else if(projectileAngle < -straightAngle) //lower shot
 	{
-		spi.x = xycoord.x + 200 + shooter->type->lowerRightMissleOffsetX;
-		spi.y = xycoord.y + 150 - shooter->type->lowerRightMissleOffsetY;
+		spi.x = xycoord.x + 200 + shooter->getCreature()->lowerRightMissleOffsetX;
+		spi.y = xycoord.y + 150 - shooter->getCreature()->lowerRightMissleOffsetY;
 	}
 	else //straight shot
 	{
-		spi.x = xycoord.x + 200 + shooter->type->rightMissleOffsetX;
-		spi.y = xycoord.y + 125 - shooter->type->rightMissleOffsetY;
+		spi.x = xycoord.x + 200 + shooter->getCreature()->rightMissleOffsetX;
+		spi.y = xycoord.y + 125 - shooter->getCreature()->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)
@@ -1273,25 +1273,25 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
 	//loading projectiles for units
 	for(std::map<int, CStack>::iterator g = stacks.begin(); g != stacks.end(); ++g)
 	{
-		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.find(creID) != CGI->creh->idToProjectile.end())
+		int creID = (g->second.getCreature()->idNumber == 149) ? CGI->creh->factionToTurretCreature[siegeH->town->town->typeID] : g->second.getCreature()->idNumber; //id of creature whose shots should be loaded
+		if(g->second.getCreature()->isShooting() && CGI->creh->idToProjectile.find(creID) != CGI->creh->idToProjectile.end())
 		{	
-			idToProjectile[g->second.type->idNumber] = CDefHandler::giveDef(CGI->creh->idToProjectile.find(creID)->second);
+			idToProjectile[g->second.getCreature()->idNumber] = CDefHandler::giveDef(CGI->creh->idToProjectile.find(creID)->second);
 
-			if(idToProjectile[g->second.type->idNumber]->ourImages.size() > 2) //add symmetric images
+			if(idToProjectile[g->second.getCreature()->idNumber]->ourImages.size() > 2) //add symmetric images
 			{
-				for(int k = idToProjectile[g->second.type->idNumber]->ourImages.size()-2; k > 1; --k)
+				for(int k = idToProjectile[g->second.getCreature()->idNumber]->ourImages.size()-2; k > 1; --k)
 				{
 					Cimage ci;
-					ci.bitmap = CSDL_Ext::rotate01(idToProjectile[g->second.type->idNumber]->ourImages[k].bitmap);
+					ci.bitmap = CSDL_Ext::rotate01(idToProjectile[g->second.getCreature()->idNumber]->ourImages[k].bitmap);
 					ci.groupNumber = 0;
 					ci.imName = std::string();
-					idToProjectile[g->second.type->idNumber]->ourImages.push_back(ci);
+					idToProjectile[g->second.getCreature()->idNumber]->ourImages.push_back(ci);
 				}
 			}
-			for(int s=0; s<idToProjectile[g->second.type->idNumber]->ourImages.size(); ++s) //alpha transforming
+			for(int s=0; s<idToProjectile[g->second.getCreature()->idNumber]->ourImages.size(); ++s) //alpha transforming
 			{
-				CSDL_Ext::alphaTransform(idToProjectile[g->second.type->idNumber]->ourImages[s].bitmap);
+				CSDL_Ext::alphaTransform(idToProjectile[g->second.getCreature()->idNumber]->ourImages[s].bitmap);
 			}
 		}
 	}
@@ -1794,7 +1794,7 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent)
 						}
 						//setting console text
 						char buf[500];
-						sprintf(buf, CGI->generaltexth->allTexts[297].c_str(), shere->count == 1 ? shere->type->nameSing.c_str() : shere->type->namePl.c_str());
+						sprintf(buf, CGI->generaltexth->allTexts[297].c_str(), shere->count == 1 ? shere->getCreature()->nameSing.c_str() : shere->getCreature()->namePl.c_str());
 						console->alterTxt = buf;
 						console->whoSetAlter = 0;
 						mouseHoveredStack = shere->ID;
@@ -1822,7 +1822,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->count == 1 ? shere->type->nameSing.c_str() : shere->type->namePl.c_str(), sactive->shots, estDmg.str().c_str());
+						sprintf(buf, CGI->generaltexth->allTexts[296].c_str(), shere->count == 1 ? shere->getCreature()->nameSing.c_str() : shere->getCreature()->namePl.c_str(), sactive->shots, estDmg.str().c_str());
 						console->alterTxt = buf;
 						console->whoSetAlter = 0;
 					}
@@ -1972,7 +1972,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->count == 1 ? shere->type->nameSing.c_str() : shere->type->namePl.c_str(), estDmg.str().c_str());
+						sprintf(buf, CGI->generaltexth->allTexts[36].c_str(), shere->count == 1 ? shere->getCreature()->nameSing.c_str() : shere->getCreature()->namePl.c_str(), estDmg.str().c_str());
 						console->alterTxt = buf;
 						console->whoSetAlter = 0;
 					}
@@ -2006,12 +2006,12 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent)
 					if(sactive->hasBonusOfType(Bonus::FLYING))
 					{
 						CGI->curh->changeGraphic(1,2);
-						sprintf(buf, CGI->generaltexth->allTexts[295].c_str(), sactive->count == 1 ? sactive->type->nameSing.c_str() : sactive->type->namePl.c_str());
+						sprintf(buf, CGI->generaltexth->allTexts[295].c_str(), sactive->count == 1 ? sactive->getCreature()->nameSing.c_str() : sactive->getCreature()->namePl.c_str());
 					}
 					else
 					{
 						CGI->curh->changeGraphic(1,1);
-						sprintf(buf, CGI->generaltexth->allTexts[294].c_str(), sactive->count == 1 ? sactive->type->nameSing.c_str() : sactive->type->namePl.c_str());
+						sprintf(buf, CGI->generaltexth->allTexts[294].c_str(), sactive->count == 1 ? sactive->getCreature()->nameSing.c_str() : sactive->getCreature()->namePl.c_str());
 					}
 
 					console->alterTxt = buf;
@@ -2076,7 +2076,7 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent)
 					CGI->curh->changeGraphic(3, 0);
 					//setting console text
 					char buf[500];
-					std::string creName = stackUnder->count > 1 ? stackUnder->type->namePl : stackUnder->type->nameSing;
+					std::string creName = stackUnder->count > 1 ? stackUnder->getCreature()->namePl : stackUnder->getCreature()->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;
@@ -2236,7 +2236,7 @@ void CBattleInterface::newStack(int stackID)
 	}
 	else
 	{
-		creAnims[stackID] = new CCreatureAnimation(newStack->type->animDefName);	
+		creAnims[stackID] = new CCreatureAnimation(newStack->getCreature()->animDefName);	
 	}
 	creAnims[stackID]->setType(2);
 	creAnims[stackID]->pos = Rect(coords.x, coords.y, creAnims[newStack->ID]->fullWidth, creAnims[newStack->ID]->fullHeight);
@@ -2779,7 +2779,7 @@ void CBattleInterface::spellCast(BattleSpellCast * 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)->type->namePl );
+		boost::algorithm::replace_first(text, "%s", curInt->cb->battleGetStackByID(*sc->affectedCres.begin(), false)->getCreature()->namePl );
 		console->addText(text);
 	}
 	else
@@ -3154,17 +3154,17 @@ void CBattleInterface::printConsoleAttacked(int ID, int dmg, int killed, int IDb
 	const CStack * attacker = curInt->cb->battleGetStackByID(IDby, false);
 	const CStack * defender = curInt->cb->battleGetStackByID(ID, false);
 	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()),
+		(attacker->count > 1 ? attacker->getCreature()->namePl.c_str() : attacker->getCreature()->nameSing.c_str()),
 		dmg);
 	if(killed > 0)
 	{
 		if(killed > 1)
 		{
-			sprintf(tabh + end, CGI->generaltexth->allTexts[379].c_str(), killed, defender->type->namePl.c_str());
+			sprintf(tabh + end, CGI->generaltexth->allTexts[379].c_str(), killed, defender->getCreature()->namePl.c_str());
 		}
 		else //killed == 1
 		{
-			sprintf(tabh + end, CGI->generaltexth->allTexts[378].c_str(), defender->type->nameSing.c_str());
+			sprintf(tabh + end, CGI->generaltexth->allTexts[378].c_str(), defender->getCreature()->nameSing.c_str());
 		}
 	}
 
@@ -3334,7 +3334,7 @@ void CBattleInterface::startAction(const BattleAction* action)
 
 	if(txtid)
 	{
-		sprintf(txt, CGI->generaltexth->allTexts[txtid].c_str(),  (stack->count != 1) ? stack->type->namePl.c_str() : stack->type->nameSing.c_str(), 0);
+		sprintf(txt, CGI->generaltexth->allTexts[txtid].c_str(),  (stack->count != 1) ? stack->getCreature()->namePl.c_str() : stack->getCreature()->nameSing.c_str(), 0);
 		console->addText(txt);
 	}
 
@@ -3591,7 +3591,7 @@ void CBattleHex::mouseMoved(const SDL_MouseMotionEvent &sEvent)
 		{
 			char tabh[160];
 			const CStack * attackedStack = myInterface->curInt->cb->battleGetStackByPos(myNumber);
-			const std::string & attackedName = attackedStack->count == 1 ? attackedStack->type->nameSing : attackedStack->type->namePl;
+			const std::string & attackedName = attackedStack->count == 1 ? attackedStack->getCreature()->nameSing : attackedStack->getCreature()->namePl;
 			sprintf(tabh, CGI->generaltexth->allTexts[220].c_str(), attackedName.c_str());
 			myInterface->console->alterTxt = std::string(tabh);
 			setAlterText = true;
@@ -3621,7 +3621,7 @@ void CBattleHex::clickRight(tribool down, bool previousState)
 		if(!myst.alive()) return;
 		if(down)
 		{
-			GH.pushInt(new CCreInfoWindow(myst));
+			GH.pushInt(new CCreInfoWindow(*myst.base));
 		}
 	}
 }
@@ -4207,13 +4207,13 @@ 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->type->idNumber], pos.x +9, pos.y + 1, to);
+		blitAt(graphics->bigImgs[my->getCreature()->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->type->idNumber], pos, to);
+		blitAt(graphics->smallImgs[my->getCreature()->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->count), pos.w/2, pos.h - 8, FONT_TINY, zwykly, to);

+ 2 - 2
client/CPlayerInterface.cpp

@@ -698,7 +698,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->count != 1) ? stack->type->namePl : stack->type->nameSing);
+			boost::algorithm::replace_first(hlp,"%s",(stack->count != 1) ? stack->getCreature()->namePl : stack->getCreature()->nameSing);
 			battleInt->displayEffect(20,stack->position);
 			battleInt->console->addText(hlp);
 		}
@@ -808,7 +808,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->count != 1) ? stack->type->namePl.c_str() : stack->type->nameSing.c_str());
+		boost::algorithm::replace_first(hlp,"%s",(stack->count != 1) ? stack->getCreature()->namePl.c_str() : stack->getCreature()->nameSing.c_str());
 		battleInt->console->addText(hlp);
 		battleInt->displayEffect(18,stack->position);
 	}

+ 12 - 0
lib/CCreatureSet.cpp

@@ -225,6 +225,18 @@ bool CCreatureSet::contains(const CStackInstance *stack) const
 	return false;
 }
 
+TSlot CCreatureSet::findStack(const CStackInstance *stack) const
+{
+	if(!stack) 
+		return -1;
+
+	for(TSlots::const_iterator i = slots.begin(); i != slots.end(); ++i)
+		if(&i->second == stack)
+			return i->first;
+
+	return -1;
+}
+
 CStackInstance::CStackInstance()
 {
 	init();

+ 1 - 0
lib/CCreatureSet.h

@@ -73,6 +73,7 @@ public:
 	const CStackInstance& getStack(TSlot slot) const; 
 	const CCreature* getCreature(TSlot slot) const; //workaround of map issue;
 	int getAmount (TSlot slot) const;
+	TSlot findStack(const CStackInstance *stack) const; //-1 if none
 	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

+ 21 - 16
lib/CGameState.cpp

@@ -687,19 +687,24 @@ std::pair< std::vector<int>, int > BattleInfo::getPath(int start, int dest, bool
 	return std::make_pair(path, dist[dest]);
 }
 
-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),   
+CStack::CStack(const CStackInstance *Base, int O, int I, bool AO, int S)
+	: base(Base), ID(I), owner(O), slot(S), attackerOwned(AO), position(-1),   
 	counterAttacks(1)
 {
-	baseAmount = base->count;
+	count = baseAmount = base->count;
 	firstHPleft = valOfBonuses(Bonus::STACK_HEALTH);
-	shots = type->shots;
+	shots = getCreature()->shots;
 	counterAttacks += valOfBonuses(Bonus::ADDITIONAL_RETALIATION);
 
 	//alive state indication
 	state.insert(ALIVE);
 }
 
+CStack::CStack() : base(NULL), ID(-1), baseAmount(-1), firstHPleft(-1), owner(255), slot(255), attackerOwned(true), position(-1), counterAttacks(1)
+{
+
+}
+
 ui32 CStack::Speed( int turn /*= 0*/ ) const
 {
 	if(hasBonus(Selector::type(Bonus::SIEGE_WEAPON) && Selector::turns(turn))) //war machines cannot move
@@ -941,7 +946,7 @@ bool CStack::moved( int turn /*= 0*/ ) const
 
 bool CStack::doubleWide() const
 {
-	return type->doubleWide;
+	return getCreature()->doubleWide;
 }
 
 int CStack::occupiedHex() const
@@ -3079,7 +3084,7 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con
 		minDmg = attacker->getMinDamage() * attacker->count, 
 		maxDmg = attacker->getMaxDamage() * attacker->count;
 
-	if(attacker->type->idNumber == 149) //arrow turret
+	if(attacker->getCreature()->idNumber == 149) //arrow turret
 	{
 		switch(attacker->position)
 		{
@@ -3094,7 +3099,7 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con
 		}
 	}
 
-	if(attacker->hasBonusOfType(Bonus::SIEGE_WEAPON) && attacker->type->idNumber != 149) //any siege weapon, but only ballista can attack (second condition - not arrow turret)
+	if(attacker->hasBonusOfType(Bonus::SIEGE_WEAPON) && attacker->getCreature()->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; 
@@ -3150,7 +3155,7 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con
 
 		for(unsigned int g=0; g<affectedIds.size(); ++g)
 		{
-			if(defender->type->idNumber == affectedIds[g])
+			if(defender->getCreature()->idNumber == affectedIds[g])
 			{
 				attackDefenceDifference += VLC->spellh->spells[55].powers[attacker->getEffect(55)->val];
 				break;
@@ -3209,7 +3214,7 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con
 	}
 
 	//handling hate effect
-	if( attacker->hasBonusOfType(Bonus::HATE, defender->type->idNumber) )
+	if( attacker->hasBonusOfType(Bonus::HATE, defender->getCreature()->idNumber) )
 		additiveBonus += 0.5f;
 
 	//luck bonus
@@ -3316,7 +3321,7 @@ void BattleInfo::calculateCasualties( std::map<ui32,si32> *casualties ) const
 		si32 killed = (st->alive() ? st->baseAmount - st->count : st->baseAmount);
 		amax(killed, 0);
 		if(killed)
-			casualties[!st->attackerOwned][st->type->idNumber] += killed;
+			casualties[!st->attackerOwned][st->getCreature()->idNumber] += killed;
 	}
 }
 
@@ -3361,8 +3366,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]->type->isUndead()) //death ripple
-				|| (s->id == 25 && stacks[it]->type->isUndead()) //destroy undead
+			if((s->id == 24 && !stacks[it]->getCreature()->isUndead()) //death ripple
+				|| (s->id == 25 && stacks[it]->getCreature()->isUndead()) //destroy undead
 				|| (s->id == 26) //Armageddon
 				)
 			{
@@ -3558,7 +3563,7 @@ ui32 BattleInfo::calculateSpellBonus(ui32 baseDamage, const CSpell * sp, const C
 			ret *= (100.0f + caster->valOfBonuses(Bonus::EARTH_SPELL_DMG_PREMY)) / 100.0f;
 
 		if (affectedCreature) //Hero specials like Solmyr, Deemer
-			ret *= (100.f + ((caster->valOfBonuses(Bonus::SPECIAL_SPELL_LEV, sp->id) * caster->level) / affectedCreature->type->level)) / 100.0f;
+			ret *= (100.f + ((caster->valOfBonuses(Bonus::SPECIAL_SPELL_LEV, sp->id) * caster->level) / affectedCreature->getCreature()->level)) / 100.0f;
 	}
 	return ret;
 }
@@ -3659,7 +3664,7 @@ bool CGameState::battleCanShoot(int ID, int dest)
 	if(our->hasBonusOfType(Bonus::FORGETFULL)) //forgetfulness
 		return false;
 
-	if(our->type->idNumber == 145 && dst) //catapult cannot attack creatures
+	if(our->getCreature()->idNumber == 145 && dst) //catapult cannot attack creatures
 		return false;
 
 	if(our->hasBonusOfType(Bonus::SHOOTER)//it's shooter
@@ -4173,7 +4178,7 @@ void BattleInfo::getStackQueue( std::vector<const CStack *> &out, int howMany, i
 			else
 				p = 3;
 		}
-		else if(s->type->idNumber == 145  ||  s->type->idNumber == 149) //catapult and turrets are first
+		else if(s->getCreature()->idNumber == 145  ||  s->getCreature()->idNumber == 149) //catapult and turrets are first
 		{
 			p = 0;
 		}
@@ -4447,7 +4452,7 @@ bool CMP_stack::operator()( const CStack* a, const CStack* b )
 	switch(phase)
 	{
 	case 0: //catapult moves after turrets
-		return a->type->idNumber < b->type->idNumber; //catapult is 145 and turrets are 149
+		return a->getCreature()->idNumber < b->getCreature()->idNumber; //catapult is 145 and turrets are 149
 		//TODO? turrets order
 	case 1: //fastest first, upper slot first
 		{

+ 19 - 5
lib/CGameState.h

@@ -250,10 +250,13 @@ struct DLL_EXPORT BattleInfo : public CBonusSystemNode
 	si8 canTeleportTo(int stackID, int destHex, int telportLevel); //determines if given stack can teleport to given place
 };
 
-class DLL_EXPORT CStack : public CStackInstance
+class DLL_EXPORT CStack : public CBonusSystemNode
 { 
 public:
+	const CStackInstance *base;
+
 	ui32 ID; //unique ID of stack
+	ui32 count;
 	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)
@@ -264,10 +267,10 @@ public:
 
 	std::set<ECombatInfo> state;
 	//overrides
-	const CCreature* getCreature() const {return type;}
+	const CCreature* getCreature() const {return base->type;}
 
 	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
+	CStack(); //c-tor
 	const Bonus * 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
@@ -299,9 +302,20 @@ public:
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & static_cast<CStackInstance&>(*this);
+		TSlot slot = (base ? base->armyObj->findStack(base) : -1);
+		const CArmedInstance *army = (base ? base->armyObj : NULL);
+		if(h.saving)
+		{
+			h & army & slot;
+		}
+		else
+		{
+			h & army & slot;
+			base = &army->getStack(slot);
+		}
+
 		h & ID & baseAmount & firstHPleft & owner & slot & attackerOwned & position & state & counterAttacks
-			& shots;
+			& shots & count;
 	}
 	bool alive() const //determines if stack is alive
 	{

+ 18 - 0
lib/HeroBonus.cpp

@@ -358,6 +358,24 @@ bool CBonusSystemNode::isLimitedOnUs(Bonus *b) const
 	return b->limiter && b->limiter->limit(b, *this);
 }
 
+bool CBonusSystemNode::weActAsBonusSourceOnly() const
+{
+	switch(nodeType)
+	{
+	case CREATURE:
+	case ARTIFACT:
+	case ARTIFACT_INSTANCE:
+		return true;
+	default:
+		return false;
+	}
+}
+
+TNodesVector & CBonusSystemNode::nodesOnWhichWePropagate()
+{
+	return weActAsBonusSourceOnly() ? children : parents;
+}
+
 int NBonus::valOf(const CBonusSystemNode *obj, Bonus::BonusType type, int subtype /*= -1*/)
 {
 	if(obj)

+ 5 - 2
lib/HeroBonus.h

@@ -30,6 +30,7 @@ class IPropagator;
 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 std::vector<CBonusSystemNode *> TNodesVector;
 typedef boost::function<bool(const Bonus*)> CSelector;
 
 namespace PrimarySkill
@@ -361,7 +362,7 @@ public:
 	BonusList bonuses; //wielded bonuses (local and up-propagated here)
 	BonusList exportedBonuses;
 
-	std::vector<CBonusSystemNode *> parents, //parents -> we inherit bonuses from them, we may attach our bonuses to them
+	TNodesVector parents, //parents -> we inherit bonuses from them, we may attach our bonuses to them
 									children;
 
 	ui8 nodeType;
@@ -413,6 +414,8 @@ public:
 	//void addNewBonus(const Bonus &b); //b will copied
 	void removeBonus(Bonus *b);
 
+	TNodesVector &nodesOnWhichWePropagate();
+	bool weActAsBonusSourceOnly() const;
 	bool isLimitedOnUs(Bonus *b) const; //if bonus should be removed from list acquired from this node
 	CBonusSystemNode *whereToPropagate(Bonus *b);
 
@@ -425,7 +428,7 @@ public:
 
 	enum ENodeTypes
 	{
-		UNKNOWN, STACK, SPECIALITY, ARTIFACT, CREATURE
+		UNKNOWN, STACK, SPECIALITY, ARTIFACT, CREATURE, ARTIFACT_INSTANCE
 	};
 };
 

+ 1 - 1
lib/NetPacksLib.cpp

@@ -860,7 +860,7 @@ DLL_EXPORT void BattleAttack::applyGs( CGameState *gs )
 		bool hasAmmoCart = false;
 		BOOST_FOREACH(const CStack * st, gs->curB->stacks)
 		{
-			if(st->owner == attacker->owner && st->type->idNumber == 148 && st->alive())
+			if(st->owner == attacker->owner && st->getCreature()->idNumber == 148 && st->alive())
 			{
 				hasAmmoCart = true;
 				break;

+ 4 - 4
server/CGameHandler.cpp

@@ -436,7 +436,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->type->idNumber == 146 && (!curOwner || curOwner->getSecSkillLevel(20) == 0))) //ballista, hero has no artillery
+				|| (next->getCreature()->idNumber == 146 && (!curOwner || curOwner->getSecSkillLevel(20) == 0))) //ballista, hero has no artillery
 			{
 				BattleAction attack;
 				attack.actionType = 7;
@@ -458,7 +458,7 @@ void CGameHandler::startBattle(const CArmedInstance *army1, const CArmedInstance
 				continue;
 			}
 
-			if(next->type->idNumber == 145 && (!curOwner || curOwner->getSecSkillLevel(10) == 0)) //catapult, hero has no ballistics
+			if(next->getCreature()->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};
@@ -473,7 +473,7 @@ void CGameHandler::startBattle(const CArmedInstance *army1, const CArmedInstance
 				continue;
 			}
 
-			if(next->type->idNumber == 147 && (!curOwner || curOwner->getSecSkillLevel(27) == 0)) //first aid tent, hero has no first aid
+			if(next->getCreature()->idNumber == 147 && (!curOwner || curOwner->getSecSkillLevel(27) == 0)) //first aid tent, hero has no first aid
 			{
 				BattleAction heal;
 
@@ -3751,7 +3751,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
 						) //nor occupy specified hex
 				) 
 			{
-				std::string problem = "We cannot move this stack to its destination " + curStack->type->namePl;
+				std::string problem = "We cannot move this stack to its destination " + curStack->getCreature()->namePl;
 				tlog3 << problem << std::endl;
 				complain(problem);
 				ok = false;