1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-03-25 21:38:59 +02:00

vcmi: allow to configure army movement counter

It is not hardcoded now. MOVEMENT.TXT is still not read,
but ARMY_MOVEMENT updater parameters can be specified in json.
There is a 4 parameters:
1. Base - base value (firstly lowest speed is multiplied by it)
2. Divider - base value is integrally divided by it
3. Multiplier - result value will be multiplied by it
4. Max - maximum allowed movement from army.

Vanilla values is in defaultMods.json

Fixes: https://bugs.vcmi.eu/view.php?id=3209
This commit is contained in:
Konstantin 2023-03-11 23:09:16 +03:00
parent b91d7418dd
commit 0adffc824f
6 changed files with 70 additions and 16 deletions

View File

@ -88,9 +88,11 @@
{
"type" : "MOVEMENT", //Enable army movement bonus
"subtype" : 1,
"val" : 0,
"valueType" : "BASE_NUMBER",
"updater" : "ARMY_MOVEMENT"
"updater" : {
"type" : "ARMY_MOVEMENT",
"parameters" : [ 20, 3, 10, 700]
}
},
{
"type" : "MOVEMENT", //Basic sea movement

View File

@ -2763,13 +2763,32 @@ JsonNode TimesHeroLevelUpdater::toJsonNode() const
return JsonUtils::stringNode("TIMES_HERO_LEVEL");
}
ArmyMovementUpdater::ArmyMovementUpdater():
base(20),
divider(3),
multiplier(10),
max(700)
{
}
ArmyMovementUpdater::ArmyMovementUpdater(int base, int divider, int multiplier, int max):
base(base),
divider(divider),
multiplier(multiplier),
max(max)
{
}
std::shared_ptr<Bonus> ArmyMovementUpdater::createUpdatedBonus(const std::shared_ptr<Bonus> & b, const CBonusSystemNode & context) const
{
if(b->type == Bonus::MOVEMENT && context.getNodeType() == CBonusSystemNode::HERO)
{
auto speed = static_cast<const CGHeroInstance &>(context).getLowestCreatureSpeed();
si32 armySpeed = speed * base / divider;
auto counted = armySpeed * multiplier;
auto newBonus = std::make_shared<Bonus>(*b);
newBonus->source = Bonus::ARMY;
newBonus->val = static_cast<const CGHeroInstance &>(context).getArmyMovementBonus();
newBonus->val = vstd::amin(counted, max);
return newBonus;
}
if(b->type != Bonus::MOVEMENT)
@ -2784,7 +2803,15 @@ std::string ArmyMovementUpdater::toString() const
JsonNode ArmyMovementUpdater::toJsonNode() const
{
return JsonUtils::stringNode("ARMY_MOVEMENT");
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
root["type"].String() = "ARMY_MOVEMENT";
root["parameters"].Vector().push_back(JsonUtils::intNode(base));
root["parameters"].Vector().push_back(JsonUtils::intNode(divider));
root["parameters"].Vector().push_back(JsonUtils::intNode(multiplier));
root["parameters"].Vector().push_back(JsonUtils::intNode(max));
return root;
}
TimesStackLevelUpdater::TimesStackLevelUpdater()

View File

@ -1320,9 +1320,19 @@ public:
class DLL_LINKAGE ArmyMovementUpdater : public IUpdater
{
public:
si32 base;
si32 divider;
si32 multiplier;
si32 max;
ArmyMovementUpdater();
ArmyMovementUpdater(int base, int divider, int multiplier, int max);
template <typename Handler> void serialize(Handler & h, const int version)
{
h & static_cast<IUpdater &>(*this);
h & base;
h & divider;
h & multiplier;
h & max;
}
std::shared_ptr<Bonus> createUpdatedBonus(const std::shared_ptr<Bonus> & b, const CBonusSystemNode & context) const override;

View File

@ -864,6 +864,24 @@ static TUpdaterPtr parseUpdater(const JsonNode & updaterJson)
updater->stepSize = static_cast<int>(param[1].Integer());
return updater;
}
else if (updaterJson["type"].String() == "ARMY_MOVEMENT")
{
std::shared_ptr<ArmyMovementUpdater> updater = std::make_shared<ArmyMovementUpdater>();
if(updaterJson["parameters"].isVector())
{
const auto & param = updaterJson["parameters"].Vector();
if(param.size() < 4)
logMod->warn("Invalid ARMY_MOVEMENT parameters, using default!");
else
{
updater->base = static_cast<si32>(param.at(0).Integer());
updater->divider = static_cast<si32>(param.at(1).Integer());
updater->multiplier = static_cast<si32>(param.at(2).Integer());
updater->max = static_cast<si32>(param.at(3).Integer());
}
return updater;
}
}
else
logMod->warn("Unknown updater type \"%s\"", updaterJson["type"].String());
break;

View File

@ -188,19 +188,17 @@ int CGHeroInstance::maxMovePoints(bool onLand) const
return maxMovePointsCached(onLand, &ti);
}
int CGHeroInstance::getArmyMovementBonus() const
int CGHeroInstance::getLowestCreatureSpeed() const
{
return armyMovementVal;
return lowestCreatureSpeed;
}
void CGHeroInstance::updateArmyMovementBonus(bool onLand, const TurnInfo * ti) const
{
int armySpeed = lowestSpeed(this) * 20 / 3;
auto base = armySpeed * 10; // separate *10 is intentional to receive same rounding as in h3
if(armyMovementVal != vstd::abetween(base, 200, 700)) // army modifier speed is limited by these values
auto realLowestSpeed = lowestSpeed(this);
if(lowestCreatureSpeed != realLowestSpeed)
{
armyMovementVal = base;
lowestCreatureSpeed = realLowestSpeed;
ti->updateHeroBonuses(Bonus::MOVEMENT, Selector::subtype()(!!onLand).And(Selector::sourceTypeSel(Bonus::ARMY)));
}
}
@ -208,7 +206,7 @@ void CGHeroInstance::updateArmyMovementBonus(bool onLand, const TurnInfo * ti) c
int CGHeroInstance::maxMovePointsCached(bool onLand, const TurnInfo * ti) const
{
updateArmyMovementBonus(onLand, ti);
return ti->valOfBonuses(Bonus::MOVEMENT, !!onLand);;
return ti->valOfBonuses(Bonus::MOVEMENT, !!onLand);
}
CGHeroInstance::CGHeroInstance():
@ -222,7 +220,7 @@ CGHeroInstance::CGHeroInstance():
level(1),
exp(UNINITIALIZED_EXPERIENCE),
sex(std::numeric_limits<ui8>::max()),
armyMovementVal(0)
lowestCreatureSpeed(0)
{
setNodeType(HERO);
ID = Obj::HERO;

View File

@ -49,7 +49,7 @@ class DLL_LINKAGE CGHeroInstance : public CArmedInstance, public IBoatGenerator,
private:
std::set<SpellID> spells; //known spells (spell IDs)
mutable int armyMovementVal;
mutable int lowestCreatureSpeed;
public:
@ -171,7 +171,7 @@ public:
ui32 getTileCost(const TerrainTile & dest, const TerrainTile & from, const TurnInfo * ti) const; //move cost - applying pathfinding skill, road and terrain modifiers. NOT includes diagonal move penalty, last move levelling
TerrainId getNativeTerrain() const;
ui32 getLowestCreatureSpeed() const;
int getLowestCreatureSpeed() const;
si32 manaRegain() const; //how many points of mana can hero regain "naturally" in one day
si32 getManaNewTurn() const; //calculate how much mana this hero is going to have the next day
int getCurrentLuck(int stack=-1, bool town=false) const;
@ -213,7 +213,6 @@ public:
int maxMovePointsCached(bool onLand, const TurnInfo * ti) const;
//update army movement bonus
void updateArmyMovementBonus(bool onLand, const TurnInfo * ti) const;
int getArmyMovementBonus() const;
int movementPointsAfterEmbark(int MPsBefore, int basicCost, bool disembark = false, const TurnInfo * ti = nullptr) const;