Browse Source

Replaced undescriptive bool true/false with more clear enum for
absolute/relative change via netpacks

Ivan Savenko 5 months ago
parent
commit
456525109e

+ 4 - 4
lib/callback/IGameEventCallback.h

@@ -67,8 +67,8 @@ public:
 	virtual void createBoat(const int3 & visitablePosition, BoatId type, PlayerColor initiator) = 0;
 	virtual void setOwner(const CGObjectInstance * objid, PlayerColor owner)=0;
 	virtual void giveExperience(const CGHeroInstance * hero, TExpType val) =0;
-	virtual void changePrimSkill(const CGHeroInstance * hero, PrimarySkill which, si64 val, bool abs=false)=0;
-	virtual void changeSecSkill(const CGHeroInstance * hero, SecondarySkill which, int val, bool abs=false)=0;
+	virtual void changePrimSkill(const CGHeroInstance * hero, PrimarySkill which, si64 val, ChangeValueMode mode)=0;
+	virtual void changeSecSkill(const CGHeroInstance * hero, SecondarySkill which, int val, ChangeValueMode mode)=0;
 	virtual void showBlockingDialog(const IObjectInterface * caller, BlockingDialog *iw) =0;
 	virtual void showGarrisonDialog(ObjectInstanceID upobj, ObjectInstanceID hid, bool removableUnits) =0; //cb will be called when player closes garrison window
 	virtual void showTeleportDialog(TeleportDialog *iw) =0;
@@ -78,7 +78,7 @@ public:
 
 	virtual void giveCreatures(const CArmedInstance *objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove) =0;
 	virtual void takeCreatures(ObjectInstanceID objid, const std::vector<CStackBasicDescriptor> &creatures, bool forceRemoval = false) =0;
-	virtual bool changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue = false) =0;
+	virtual bool changeStackCount(const StackLocation &sl, TQuantity count, ChangeValueMode mode) =0;
 	virtual bool changeStackType(const StackLocation &sl, const CCreature *c) =0;
 	virtual bool insertNewStack(const StackLocation &sl, const CCreature *c, TQuantity count = -1) =0; //count -1 => moves whole stack
 	virtual bool eraseStack(const StackLocation &sl, bool forceRemoval = false) =0;
@@ -104,7 +104,7 @@ public:
 	virtual bool swapGarrisonOnSiege(ObjectInstanceID tid)=0;
 	virtual void giveHeroBonus(GiveBonus * bonus)=0;
 	virtual void setMovePoints(SetMovePoints * smp)=0;
-	virtual void setMovePoints(ObjectInstanceID hid, int val, bool absolute)=0;
+	virtual void setMovePoints(ObjectInstanceID hid, int val, ChangeValueMode mode)=0;
 	virtual void setManaPoints(ObjectInstanceID hid, int val)=0;
 	virtual void giveHero(ObjectInstanceID id, PlayerColor player, ObjectInstanceID boatId = ObjectInstanceID()) = 0;
 	virtual void changeObjPos(ObjectInstanceID objid, int3 newPos, const PlayerColor & initiator)=0;

+ 6 - 0
lib/constants/Enumerations.h

@@ -259,4 +259,10 @@ enum class EWeekType : int8_t
 	PLAGUE
 };
 
+enum class ChangeValueMode : int8_t
+{
+	RELATIVE,
+	ABSOLUTE
+};
+
 VCMI_LIB_NAMESPACE_END

+ 1 - 1
lib/gameState/CGameStateCampaign.cpp

@@ -361,7 +361,7 @@ void CGameStateCampaign::giveCampaignBonusToHero(CGHeroInstance * hero)
 		}
 		case CampaignBonusType::SECONDARY_SKILL:
 		{
-			hero->setSecSkillLevel(SecondarySkill(curBonus->info2), curBonus->info3, true);
+			hero->setSecSkillLevel(SecondarySkill(curBonus->info2), curBonus->info3, ChangeValueMode::ABSOLUTE);
 			break;
 		}
 	}

+ 6 - 6
lib/gameState/GameStatePackVisitor.cpp

@@ -36,7 +36,7 @@ VCMI_LIB_NAMESPACE_BEGIN
 void GameStatePackVisitor::visitSetResources(SetResources & pack)
 {
 	assert(pack.player.isValidPlayer());
-	if(pack.abs)
+	if(pack.mode == ChangeValueMode::ABSOLUTE)
 		gs.getPlayerState(pack.player)->resources = pack.res;
 	else
 		gs.getPlayerState(pack.player)->resources += pack.res;
@@ -52,13 +52,13 @@ void GameStatePackVisitor::visitSetPrimSkill(SetPrimSkill & pack)
 {
 	CGHeroInstance * hero = gs.getHero(pack.id);
 	assert(hero);
-	hero->setPrimarySkill(pack.which, pack.val, pack.abs);
+	hero->setPrimarySkill(pack.which, pack.val, pack.mode);
 }
 
 void GameStatePackVisitor::visitSetSecSkill(SetSecSkill & pack)
 {
 	CGHeroInstance *hero = gs.getHero(pack.id);
-	hero->setSecSkillLevel(pack.which, pack.val, pack.abs);
+	hero->setSecSkillLevel(pack.which, pack.val, pack.mode);
 }
 
 void GameStatePackVisitor::visitSetCommanderProperty(SetCommanderProperty & pack)
@@ -153,7 +153,7 @@ void GameStatePackVisitor::visitSetMana(SetMana & pack)
 
 	assert(hero);
 
-	if(pack.absolute)
+	if(pack.mode == ChangeValueMode::ABSOLUTE)
 		hero->mana = pack.val;
 	else
 		hero->mana += pack.val;
@@ -167,7 +167,7 @@ void GameStatePackVisitor::visitSetMovePoints(SetMovePoints & pack)
 
 	assert(hero);
 
-	if(pack.absolute)
+	if(pack.mode == ChangeValueMode::ABSOLUTE)
 		hero->setMovementPoints(pack.val);
 	else
 		hero->setMovementPoints(hero->movementPointsRemaining() + pack.val);
@@ -677,7 +677,7 @@ void GameStatePackVisitor::visitChangeStackCount(ChangeStackCount & pack)
 	if(!srcObj)
 		throw std::runtime_error("ChangeStackCount: invalid army object " + std::to_string(pack.army.getNum()) + ", possible game state corruption.");
 
-	if(pack.absoluteValue)
+	if(pack.mode == ChangeValueMode::ABSOLUTE)
 		srcObj->setStackCount(pack.slot, pack.count);
 	else
 		srcObj->changeStackCount(pack.slot, pack.count);

+ 1 - 1
lib/mapObjects/CGDwelling.cpp

@@ -386,7 +386,7 @@ void CGDwelling::updateGuards(IGameEventCallback & gameEvents) const
 				csc.army = this->id;
 				csc.slot = slot;
 				csc.count = crea->getGrowth() * 3;
-				csc.absoluteValue = true;
+				csc.mode = ChangeValueMode::ABSOLUTE;
 				gameEvents.sendAndApply(csc);
 			}
 			else //slot is empty, create whole new stack

+ 6 - 6
lib/mapObjects/CGHeroInstance.cpp

@@ -909,7 +909,7 @@ void CGHeroInstance::spendMana(ServerCallback * server, const int spellCost) con
 	if(spellCost != 0)
 	{
 		SetMana sm;
-		sm.absolute = false;
+		sm.mode = ChangeValueMode::RELATIVE;
 		sm.hid = id;
 		sm.val = -spellCost;
 
@@ -1556,7 +1556,7 @@ std::optional<SecondarySkill> CGHeroInstance::nextSecondarySkill(vstd::RNG & ran
 	return chosenSecondarySkill;
 }
 
-void CGHeroInstance::setPrimarySkill(PrimarySkill primarySkill, si64 value, ui8 abs)
+void CGHeroInstance::setPrimarySkill(PrimarySkill primarySkill, si64 value, ChangeValueMode mode)
 {
 	if(primarySkill < PrimarySkill::EXPERIENCE)
 	{
@@ -1565,7 +1565,7 @@ void CGHeroInstance::setPrimarySkill(PrimarySkill primarySkill, si64 value, ui8
 			.And(Selector::sourceType()(BonusSource::HERO_BASE_SKILL)));
 		assert(skill);
 
-		if(abs)
+		if(mode == ChangeValueMode::ABSOLUTE)
 		{
 			skill->val = static_cast<si32>(value);
 		}
@@ -1577,7 +1577,7 @@ void CGHeroInstance::setPrimarySkill(PrimarySkill primarySkill, si64 value, ui8
 	}
 	else if(primarySkill == PrimarySkill::EXPERIENCE)
 	{
-		if(abs)
+		if(mode == ChangeValueMode::ABSOLUTE)
 		{
 			exp = value;
 		}
@@ -1624,14 +1624,14 @@ void CGHeroInstance::levelUpAutomatically(vstd::RNG & rand)
 	while(gainsLevel())
 	{
 		const auto primarySkill = nextPrimarySkill(rand);
-		setPrimarySkill(primarySkill, 1, false);
+		setPrimarySkill(primarySkill, 1, ChangeValueMode::RELATIVE);
 
 		auto proposedSecondarySkills = getLevelUpProposedSecondarySkills(rand);
 
 		const auto secondarySkill = nextSecondarySkill(rand);
 		if(secondarySkill)
 		{
-			setSecSkillLevel(*secondarySkill, 1, false);
+			setSecSkillLevel(*secondarySkill, 1, ChangeValueMode::RELATIVE);
 		}
 
 		//TODO why has the secondary skills to be passed to the method?

+ 2 - 2
lib/mapObjects/CGHeroInstance.h

@@ -216,8 +216,8 @@ public:
 	bool canLearnSkill() const;
 	bool canLearnSkill(const SecondarySkill & which) const;
 
-	void setPrimarySkill(PrimarySkill primarySkill, si64 value, ui8 abs);
-	void setSecSkillLevel(const SecondarySkill & which, int val, bool abs); // abs == 0 - changes by value; 1 - sets to value
+	void setPrimarySkill(PrimarySkill primarySkill, si64 value, ChangeValueMode mode);
+	void setSecSkillLevel(const SecondarySkill & which, int val, ChangeValueMode mode); // abs == 0 - changes by value; 1 - sets to value
 	void levelUp(const std::vector<SecondarySkill> & skills);
 
 	void setMovementPoints(int points);

+ 2 - 2
lib/mapObjects/MiscObjects.cpp

@@ -568,7 +568,7 @@ void CGWhirlpool::onHeroVisit(IGameEventCallback & gameEvents, const CGHeroInsta
 		iw.text.appendLocalString(EMetaText::ADVOB_TXT, 168);
 		iw.components.emplace_back(ComponentType::CREATURE, h->getCreature(targetstack)->getId(), -countToTake);
 		gameEvents.showInfoDialog(&iw);
-		gameEvents.changeStackCount(StackLocation(h->id, targetstack), -countToTake);
+		gameEvents.changeStackCount(StackLocation(h->id, targetstack), -countToTake, ChangeValueMode::RELATIVE);
 	}
 	else
 	{
@@ -1049,7 +1049,7 @@ void CGSirens::onHeroVisit(IGameEventCallback & gameEvents, const CGHeroInstance
 
 			if(drown)
 			{
-				gameEvents.changeStackCount(StackLocation(h->id, i->first), -drown);
+				gameEvents.changeStackCount(StackLocation(h->id, i->first), -drown, ChangeValueMode::RELATIVE);
 				xp += drown * i->second->getType()->getMaxHealth();
 			}
 		}

+ 16 - 16
lib/networkPacks/PacksForClient.h

@@ -180,13 +180,13 @@ struct DLL_LINKAGE SetResources : public CPackForClient
 {
 	void visitTyped(ICPackVisitor & visitor) override;
 
-	bool abs = true; //false - changes by value; 1 - sets to value
+	ChangeValueMode mode = ChangeValueMode::ABSOLUTE;
 	PlayerColor player;
 	ResourceSet res; //res[resid] => res amount
 
 	template <typename Handler> void serialize(Handler & h)
 	{
-		h & abs;
+		h & mode;
 		h & player;
 		h & res;
 	}
@@ -196,14 +196,14 @@ struct DLL_LINKAGE SetPrimSkill : public CPackForClient
 {
 	void visitTyped(ICPackVisitor & visitor) override;
 
-	ui8 abs = 0; //0 - changes by value; 1 - sets to value
+	ChangeValueMode mode = ChangeValueMode::RELATIVE;
 	ObjectInstanceID id;
 	PrimarySkill which = PrimarySkill::ATTACK;
 	si64 val = 0;
 
 	template <typename Handler> void serialize(Handler & h)
 	{
-		h & abs;
+		h & mode;
 		h & id;
 		h & which;
 		h & val;
@@ -214,14 +214,14 @@ struct DLL_LINKAGE SetSecSkill : public CPackForClient
 {
 	void visitTyped(ICPackVisitor & visitor) override;
 
-	ui8 abs = 0; //0 - changes by value; 1 - sets to value
+	ChangeValueMode mode = ChangeValueMode::RELATIVE;
 	ObjectInstanceID id;
 	SecondarySkill which;
 	ui16 val = 0;
 
 	template <typename Handler> void serialize(Handler & h)
 	{
-		h & abs;
+		h & mode;
 		h & id;
 		h & which;
 		h & val;
@@ -288,36 +288,36 @@ struct DLL_LINKAGE SetMana : public CPackForClient
 	void visitTyped(ICPackVisitor & visitor) override;
 
 	SetMana() = default;
-	SetMana(ObjectInstanceID hid, si32 val, bool absolute)
+	SetMana(ObjectInstanceID hid, si32 val, ChangeValueMode mode)
 		: hid(hid)
 		, val(val)
-		, absolute(absolute)
+		, mode(mode)
 	{}
 
 	ObjectInstanceID hid;
 	si32 val = 0;
-	bool absolute = true;
+	ChangeValueMode mode = ChangeValueMode::RELATIVE;
 
 	template <typename Handler> void serialize(Handler & h)
 	{
 		h & val;
 		h & hid;
-		h & absolute;
+		h & mode;
 	}
 };
 
 struct DLL_LINKAGE SetMovePoints : public CPackForClient
 {
 	SetMovePoints() = default;
-	SetMovePoints(ObjectInstanceID hid, si32 val, bool absolute)
+	SetMovePoints(ObjectInstanceID hid, si32 val, ChangeValueMode mode)
 		: hid(hid)
 		, val(val)
-		, absolute(absolute)
+		, mode(mode)
 	{}
 
 	ObjectInstanceID hid;
 	si32 val = 0;
-	bool absolute = true;
+	ChangeValueMode mode = ChangeValueMode::RELATIVE;
 
 	void visitTyped(ICPackVisitor & visitor) override;
 
@@ -325,7 +325,7 @@ struct DLL_LINKAGE SetMovePoints : public CPackForClient
 	{
 		h & val;
 		h & hid;
-		h & absolute;
+		h & mode;
 	}
 };
 
@@ -789,7 +789,7 @@ struct DLL_LINKAGE ChangeStackCount : CGarrisonOperationPack
 	ObjectInstanceID army;
 	SlotID slot;
 	TQuantity count;
-	bool absoluteValue; //if not -> count will be added (or subtracted if negative)
+	ChangeValueMode mode = ChangeValueMode::RELATIVE;
 
 	void visitTyped(ICPackVisitor & visitor) override;
 
@@ -798,7 +798,7 @@ struct DLL_LINKAGE ChangeStackCount : CGarrisonOperationPack
 		h & army;
 		h & slot;
 		h & count;
-		h & absoluteValue;
+		h & mode;
 	}
 };
 

+ 6 - 6
lib/rewardable/Interface.cpp

@@ -108,17 +108,17 @@ void Rewardable::Interface::grantRewardBeforeLevelup(IGameEventCallback & gameEv
 
 	for(const auto & entry : info.reward.secondary)
 	{
-		auto currentLevel = static_cast<MasteryLevel::Type>(hero->getSecSkillLevel(entry.first));
-		if(currentLevel == MasteryLevel::EXPERT)
-			continue;
+		int currentLevel = hero->getSecSkillLevel(entry.first);
+		int newLevel = currentLevel + entry.second;
+		int newLevelClamped = std::clamp<int>(newLevel, MasteryLevel::NONE, MasteryLevel::EXPERT);
 
-		if(currentLevel != MasteryLevel::NONE || hero->canLearnSkill())
-			gameEvents.changeSecSkill(hero, entry.first, entry.second, false);
+		if(currentLevel != newLevelClamped)
+			gameEvents.changeSecSkill(hero, entry.first, newLevelClamped, ChangeValueMode::ABSOLUTE);
 	}
 
 	for(int i=0; i< info.reward.primary.size(); i++)
 		if (info.reward.primary[i] != 0)
-			gameEvents.changePrimSkill(hero, static_cast<PrimarySkill>(i), info.reward.primary[i], false);
+			gameEvents.changePrimSkill(hero, static_cast<PrimarySkill>(i), info.reward.primary[i], ChangeValueMode::RELATIVE);
 
 	TExpType expToGive = 0;
 

+ 0 - 28
scripting/lua/api/netpacks/SetResources.cpp

@@ -30,8 +30,6 @@ VCMI_REGISTER_SCRIPT_API(SetResourcesProxy, "netpacks.SetResources");
 const std::vector<SetResourcesProxy::CustomRegType> SetResourcesProxy::REGISTER_CUSTOM =
 {
 	{"new", &Wrapper::constructor, true},
-	{"getAbs", &SetResourcesProxy::getAbs, false},
-	{"setAbs", &SetResourcesProxy::setAbs, false},
 	{"getPlayer", &SetResourcesProxy::getPlayer, false},
 	{"setPlayer", &SetResourcesProxy::setPlayer, false},
 	{"setAmount", &SetResourcesProxy::setAmount, false},
@@ -40,32 +38,6 @@ const std::vector<SetResourcesProxy::CustomRegType> SetResourcesProxy::REGISTER_
 	{"toNetpackLight", &PackForClientProxy<SetResourcesProxy>::toNetpackLight, false}
 };
 
-int SetResourcesProxy::getAbs(lua_State * L)
-{
-	LuaStack S(L);
-	std::shared_ptr<SetResources> object;
-	if(!S.tryGet(1, object))
-		return S.retVoid();
-
-	return LuaStack::quickRetBool(L, object->abs);
-}
-
-int SetResourcesProxy::setAbs(lua_State * L)
-{
-	LuaStack S(L);
-
-	std::shared_ptr<SetResources> object;
-	if(!S.tryGet(1, object))
-		return S.retVoid();
-
-
-	bool value = false;
-	if(S.tryGet(2, value))
-		object->abs = value;
-
-	return S.retVoid();
-}
-
 int SetResourcesProxy::getPlayer(lua_State * L)
 {
 	LuaStack S(L);

+ 0 - 2
scripting/lua/api/netpacks/SetResources.h

@@ -30,8 +30,6 @@ public:
 
 	static const std::vector<typename Wrapper::CustomRegType> REGISTER_CUSTOM;
 
-	static int getAbs(lua_State * L);
-	static int setAbs(lua_State * L);
 	static int getPlayer(lua_State * L);
 	static int setPlayer(lua_State * L);
 	static int getAmount(lua_State * L);

+ 22 - 22
server/CGameHandler.cpp

@@ -140,7 +140,7 @@ CVCMIServer & CGameHandler::gameLobby() const
 
 void CGameHandler::levelUpHero(const CGHeroInstance * hero, SecondarySkill skill)
 {
-	changeSecSkill(hero, skill, 1, 0);
+	changeSecSkill(hero, skill, 1, ChangeValueMode::RELATIVE);
 	expGiven(hero);
 }
 
@@ -161,7 +161,7 @@ void CGameHandler::levelUpHero(const CGHeroInstance * hero)
 	SetPrimSkill sps;
 	sps.id = hero->id;
 	sps.which = primarySkill;
-	sps.abs = false;
+	sps.mode = ChangeValueMode::RELATIVE;
 	sps.val = 1;
 	sendAndApply(sps);
 
@@ -369,7 +369,7 @@ void CGameHandler::giveExperience(const CGHeroInstance * hero, TExpType amountTo
 	SetPrimSkill sps;
 	sps.id = hero->id;
 	sps.which = PrimarySkill::EXPERIENCE;
-	sps.abs = false;
+	sps.mode = ChangeValueMode::RELATIVE;
 	sps.val = amountToGain;
 	sendAndApply(sps);
 
@@ -387,17 +387,17 @@ void CGameHandler::giveExperience(const CGHeroInstance * hero, TExpType amountTo
 	expGiven(hero);
 }
 
-void CGameHandler::changePrimSkill(const CGHeroInstance * hero, PrimarySkill which, si64 val, bool abs)
+void CGameHandler::changePrimSkill(const CGHeroInstance * hero, PrimarySkill which, si64 val, ChangeValueMode mode)
 {
 	SetPrimSkill sps;
 	sps.id = hero->id;
 	sps.which = which;
-	sps.abs = abs;
+	sps.mode = mode;
 	sps.val = val;
 	sendAndApply(sps);
 }
 
-void CGameHandler::changeSecSkill(const CGHeroInstance * hero, SecondarySkill which, int val, bool abs)
+void CGameHandler::changeSecSkill(const CGHeroInstance * hero, SecondarySkill which, int val, ChangeValueMode mode)
 {
 	if(!hero)
 	{
@@ -408,7 +408,7 @@ void CGameHandler::changeSecSkill(const CGHeroInstance * hero, SecondarySkill wh
 	sss.id = hero->id;
 	sss.which = which;
 	sss.val = val;
-	sss.abs = abs;
+	sss.mode = mode;
 	sendAndApply(sss);
 
 	if (hero->getVisitedTown())
@@ -1133,7 +1133,7 @@ void CGameHandler::giveResource(PlayerColor player, GameResID which, int val) //
 void CGameHandler::giveResources(PlayerColor player, TResources resources)
 {
 	SetResources sr;
-	sr.abs = false;
+	sr.mode = ChangeValueMode::RELATIVE;
 	sr.player = player;
 	sr.res = resources;
 	sendAndApply(sr);
@@ -1182,7 +1182,7 @@ void CGameHandler::takeCreatures(ObjectInstanceID objid, const std::vector<CStac
 					{
 						// take part of the stack
 						collected = stackToTake.getCount();
-						changeStackCount(StackLocation(army->id, armySlot.first), collected - stackToTake.getCount(), false);
+						changeStackCount(StackLocation(army->id, armySlot.first), collected - stackToTake.getCount(), ChangeValueMode::RELATIVE);
 					}
 					foundSth = true;
 					break;
@@ -1291,12 +1291,12 @@ void CGameHandler::setMovePoints(SetMovePoints * smp)
 	sendAndApply(*smp);
 }
 
-void CGameHandler::setMovePoints(ObjectInstanceID hid, int val, bool absolute)
+void CGameHandler::setMovePoints(ObjectInstanceID hid, int val, ChangeValueMode mode)
 {
 	SetMovePoints smp;
 	smp.hid = hid;
 	smp.val = val;
-	smp.absolute = absolute;
+	smp.mode = mode;
 	sendAndApply(smp);
 }
 
@@ -1305,7 +1305,7 @@ void CGameHandler::setManaPoints(ObjectInstanceID hid, int val)
 	SetMana sm;
 	sm.hid = hid;
 	sm.val = val;
-	sm.absolute = true;
+	sm.mode = ChangeValueMode::ABSOLUTE;
 	sendAndApply(sm);
 }
 
@@ -3143,7 +3143,7 @@ bool CGameHandler::buySecSkill(const IMarket *m, const CGHeroInstance *h, Second
 
 	giveResource(h->tempOwner, EGameResID::GOLD, -GameConstants::SKILL_GOLD_COST);
 
-	changeSecSkill(h, skill, 1, true);
+	changeSecSkill(h, skill, 1, ChangeValueMode::ABSOLUTE);
 	return true;
 }
 
@@ -3198,7 +3198,7 @@ bool CGameHandler::sellCreatures(ui32 count, const IMarket *market, const CGHero
 		assert(0);
 	}
 
-	changeStackCount(StackLocation(hero->id, slot), -(TQuantity)count);
+	changeStackCount(StackLocation(hero->id, slot), -(TQuantity)count, ChangeValueMode::RELATIVE);
 
 	giveResource(hero->tempOwner, resourceID, b2 * units);
 
@@ -3705,7 +3705,7 @@ bool CGameHandler::sacrificeCreatures(const IMarket * market, const CGHeroInstan
 
 		int crid = hero->getStack(slot[i]).getId();
 
-		changeStackCount(StackLocation(hero->id, slot[i]), -(TQuantity)count[i]);
+		changeStackCount(StackLocation(hero->id, slot[i]), -(TQuantity)count[i], ChangeValueMode::RELATIVE);
 
 		int dump;
 		int exp;
@@ -3806,19 +3806,19 @@ bool CGameHandler::eraseStack(const StackLocation &sl, bool forceRemoval)
 	return true;
 }
 
-bool CGameHandler::changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue)
+bool CGameHandler::changeStackCount(const StackLocation &sl, TQuantity count, ChangeValueMode mode)
 {
 	auto army = dynamic_cast<const CArmedInstance*>(getObj(sl.army));
 
 	TQuantity currentCount = army->getStackCount(sl.slot);
-	if ((absoluteValue && count < 0)
-		|| (!absoluteValue && -count > currentCount))
+	if ((mode == ChangeValueMode::RELATIVE && count < 0)
+		|| (mode == ChangeValueMode::RELATIVE && -count > currentCount))
 	{
 		COMPLAIN_RET("Cannot take more stacks than present!");
 	}
 
-	if ((currentCount == -count  &&  !absoluteValue)
-	   || (!count && absoluteValue))
+	if ((currentCount == -count  &&  mode == ChangeValueMode::RELATIVE)
+	   || (count == 0 && mode == ChangeValueMode::ABSOLUTE))
 	{
 		eraseStack(sl);
 	}
@@ -3828,7 +3828,7 @@ bool CGameHandler::changeStackCount(const StackLocation &sl, TQuantity count, bo
 		csc.army = army->id;
 		csc.slot = sl.slot;
 		csc.count = count;
-		csc.absoluteValue = absoluteValue;
+		csc.mode = mode;
 		sendAndApply(csc);
 	}
 	return true;
@@ -3842,7 +3842,7 @@ bool CGameHandler::addToSlot(const StackLocation &sl, const CCreature *c, TQuant
 	if (!slotC) //slot is empty
 		insertNewStack(sl, c, count);
 	else if (c == slotC)
-		changeStackCount(sl, count);
+		changeStackCount(sl, count, ChangeValueMode::RELATIVE);
 	else
 	{
 		COMPLAIN_RET("Cannot add " + c->getNamePluralTranslated() + " to slot " + boost::lexical_cast<std::string>(sl.slot) + "!");

+ 4 - 4
server/CGameHandler.h

@@ -115,8 +115,8 @@ public:
 	bool removeObject(const CGObjectInstance * obj, const PlayerColor & initiator) override;
 	void setOwner(const CGObjectInstance * obj, PlayerColor owner) override;
 	void giveExperience(const CGHeroInstance * hero, TExpType val) override;
-	void changePrimSkill(const CGHeroInstance * hero, PrimarySkill which, si64 val, bool abs=false) override;
-	void changeSecSkill(const CGHeroInstance * hero, SecondarySkill which, int val, bool abs=false) override;
+	void changePrimSkill(const CGHeroInstance * hero, PrimarySkill which, si64 val, ChangeValueMode mode) override;
+	void changeSecSkill(const CGHeroInstance * hero, SecondarySkill which, int val, ChangeValueMode mode) override;
 
 	void showBlockingDialog(const IObjectInterface * caller, BlockingDialog *iw) override;
 	void showTeleportDialog(TeleportDialog *iw) override;
@@ -128,7 +128,7 @@ public:
 	void giveCreatures(const CArmedInstance *objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove) override;
 	void takeCreatures(ObjectInstanceID objid, const std::vector<CStackBasicDescriptor> &creatures, bool forceRemoval) override;
 	bool changeStackType(const StackLocation &sl, const CCreature *c) override;
-	bool changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue = false) override;
+	bool changeStackCount(const StackLocation &sl, TQuantity count, ChangeValueMode mode) override;
 	bool insertNewStack(const StackLocation &sl, const CCreature *c, TQuantity count) override;
 	bool eraseStack(const StackLocation &sl, bool forceRemoval = false) override;
 	bool swapStacks(const StackLocation &sl1, const StackLocation &sl2) override;
@@ -159,7 +159,7 @@ public:
 	bool moveHero(ObjectInstanceID hid, int3 dst, EMovementMode movementMode, bool transit = false, PlayerColor asker = PlayerColor::NEUTRAL) override;
 	void giveHeroBonus(GiveBonus * bonus) override;
 	void setMovePoints(SetMovePoints * smp) override;
-	void setMovePoints(ObjectInstanceID hid, int val, bool absolute) override;
+	void setMovePoints(ObjectInstanceID hid, int val, ChangeValueMode mode) override;
 	void setManaPoints(ObjectInstanceID hid, int val) override;
 	void giveHero(ObjectInstanceID id, PlayerColor player, ObjectInstanceID boatId = ObjectInstanceID()) override;
 	void changeObjPos(ObjectInstanceID objid, int3 newPos, const PlayerColor & initiator) override;

+ 1 - 1
server/battles/BattleResultProcessor.cpp

@@ -148,7 +148,7 @@ void CasualtiesAfterBattle::updateArmy(CGameHandler *gh)
 	for (TStackAndItsNewCount &ncount : newStackCounts)
 	{
 		if (ncount.second > 0)
-			gh->changeStackCount(ncount.first, ncount.second, true);
+			gh->changeStackCount(ncount.first, ncount.second, ChangeValueMode::ABSOLUTE);
 		else
 			gh->eraseStack(ncount.first, true);
 	}

+ 3 - 3
server/processors/NewTurnProcessor.cpp

@@ -386,7 +386,7 @@ void NewTurnProcessor::updateNeutralTownGarrison(const CGTownInstance * t, int c
 			continue;
 
 		StackLocation stackLocation(t->id, slot.first);
-		gameHandler->changeStackCount(stackLocation, creature->getGrowth(), false);
+		gameHandler->changeStackCount(stackLocation, creature->getGrowth(), ChangeValueMode::RELATIVE);
 		takeFromAvailable(creature->getGrowth());
 
 		if (upgradeUnit && !creature->upgrades.empty())
@@ -571,7 +571,7 @@ std::vector<SetMana> NewTurnProcessor::updateHeroesManaPoints()
 			int32_t newMana = h->getManaNewTurn();
 
 			if (newMana != h->mana)
-				result.emplace_back(h->id, newMana, true);
+				result.emplace_back(h->id, newMana, ChangeValueMode::ABSOLUTE);
 		}
 	}
 	return result;
@@ -590,7 +590,7 @@ std::vector<SetMovePoints> NewTurnProcessor::updateHeroesMovementPoints()
 			int32_t newMovementPoints = h->movementPointsLimitCached(gameHandler->gameState().getMap().getTile(h->visitablePos()).isLand(), ti.get());
 
 			if (newMovementPoints != h->movementPointsRemaining())
-				result.emplace_back(h->id, newMovementPoints, true);
+				result.emplace_back(h->id, newMovementPoints, ChangeValueMode::ABSOLUTE);
 		}
 	}
 	return result;

+ 1 - 1
server/processors/PlayerMessageProcessor.cpp

@@ -390,7 +390,7 @@ void PlayerMessageProcessor::cheatGiveSpells(PlayerColor player, const CGHeroIns
 	SetMana sm;
 	sm.hid = hero->id;
 	sm.val = 999;
-	sm.absolute = true;
+	sm.mode = ChangeValueMode::ABSOLUTE;
 	gameHandler->sendAndApply(sm);
 }
 

+ 3 - 3
test/game/CGameStateTest.cpp

@@ -320,10 +320,10 @@ TEST_F(CGameStateTest, DISABLED_battleResurrection)
 
 	ASSERT_NE(attacker->tempOwner, defender->tempOwner);
 
-	attacker->setSecSkillLevel(SecondarySkill::EARTH_MAGIC, 3, true);
+	attacker->setSecSkillLevel(SecondarySkill::EARTH_MAGIC, 3, ChangeValueMode::ABSOLUTE);
 	attacker->addSpellToSpellbook(SpellID::RESURRECTION);
-	attacker->setPrimarySkill(PrimarySkill::SPELL_POWER, 100, true);
-	attacker->setPrimarySkill(PrimarySkill::KNOWLEDGE, 20, true);
+	attacker->setPrimarySkill(PrimarySkill::SPELL_POWER, 100, ChangeValueMode::ABSOLUTE);
+	attacker->setPrimarySkill(PrimarySkill::KNOWLEDGE, 20, ChangeValueMode::ABSOLUTE);
 	attacker->mana = attacker->manaLimit();
 
 	{

+ 4 - 4
test/mock/mock_IGameCallback.h

@@ -51,8 +51,8 @@ public:
 	void createBoat(const int3 & visitablePosition, BoatId type, PlayerColor initiator) override {}
 	void setOwner(const CGObjectInstance * objid, PlayerColor owner) override {}
 	void giveExperience(const CGHeroInstance * hero, TExpType val) override {}
-	void changePrimSkill(const CGHeroInstance * hero, PrimarySkill which, si64 val, bool abs=false) override {}
-	void changeSecSkill(const CGHeroInstance * hero, SecondarySkill which, int val, bool abs=false) override {}
+	void changePrimSkill(const CGHeroInstance * hero, PrimarySkill which, si64 val, ChangeValueMode mode) override {}
+	void changeSecSkill(const CGHeroInstance * hero, SecondarySkill which, int val, ChangeValueMode mode) override {}
 	void showBlockingDialog(const IObjectInterface * caller, BlockingDialog *iw) override {}
 	void showGarrisonDialog(ObjectInstanceID upobj, ObjectInstanceID hid, bool removableUnits) override {} //cb will be called when player closes garrison window
 	void showTeleportDialog(TeleportDialog *iw) override {}
@@ -62,7 +62,7 @@ public:
 
 	void giveCreatures(const CArmedInstance *objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove) override {}
 	void takeCreatures(ObjectInstanceID objid, const std::vector<CStackBasicDescriptor> &creatures, bool forceRemoval) override {}
-	bool changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue = false) override {return false;}
+	bool changeStackCount(const StackLocation &sl, TQuantity count, ChangeValueMode mode) override {return false;}
 	bool changeStackType(const StackLocation &sl, const CCreature *c) override {return false;}
 	bool insertNewStack(const StackLocation &sl, const CCreature *c, TQuantity count = -1) override {return false;} //count -1 => moves whole stack
 	bool eraseStack(const StackLocation &sl, bool forceRemoval = false) override {return false;}
@@ -88,7 +88,7 @@ public:
 	bool swapGarrisonOnSiege(ObjectInstanceID tid) override {return false;}
 	void giveHeroBonus(GiveBonus * bonus) override {}
 	void setMovePoints(SetMovePoints * smp) override {}
-	void setMovePoints(ObjectInstanceID hid, int val, bool absolute) override {};
+	void setMovePoints(ObjectInstanceID hid, int val, ChangeValueMode mode) override {};
 	void setManaPoints(ObjectInstanceID hid, int val) override {}
 	void giveHero(ObjectInstanceID id, PlayerColor player, ObjectInstanceID boatId = ObjectInstanceID()) override {}
 	void changeObjPos(ObjectInstanceID objid, int3 newPos, const PlayerColor & initiator) override {}