1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-06 09:09:40 +02:00

vcmi: massive refactoring v1

This commit is contained in:
Konstantin
2023-04-05 03:26:29 +03:00
parent ee489f18d2
commit 11b237a23c
129 changed files with 803 additions and 762 deletions

View File

@@ -230,8 +230,8 @@ creInfo infoFromDC(const dwellingContent & dc)
ci.creID = dc.second.size() ? dc.second.back() : CreatureID(-1); //should never be accessed
if (ci.creID != -1)
{
ci.cre = VLC->creh->objects[ci.creID];
ci.level = ci.cre->level; //this is cretaure tier, while tryRealize expects dwelling level. Ignore.
ci.cre = VLC->creatures()->getById(ci.creID);
ci.level = ci.cre->getLevel(); //this is creature tier, while tryRealize expects dwelling level. Ignore.
}
else
{

View File

@@ -152,7 +152,7 @@ struct creInfo
{
int count;
CreatureID creID;
CCreature * cre;
const Creature * cre;
int level;
};
creInfo infoFromDC(const dwellingContent & dc);

View File

@@ -36,9 +36,10 @@ std::vector<SlotInfo> ArmyManager::getSortedSlots(const CCreatureSet * target, c
{
for(auto & i : armyPtr->Slots())
{
auto & slotInfp = creToPower[i.second->type];
auto cre = dynamic_cast<const CCreature*>(i.second->type);
auto & slotInfp = creToPower[cre];
slotInfp.creature = i.second->type;
slotInfp.creature = cre;
slotInfp.power += i.second->getPower();
slotInfp.count += i.second->count;
}
@@ -59,8 +60,8 @@ std::vector<SlotInfo>::iterator ArmyManager::getWeakestCreature(std::vector<Slot
{
auto weakest = boost::min_element(army, [](const SlotInfo & left, const SlotInfo & right) -> bool
{
if(left.creature->level != right.creature->level)
return left.creature->level < right.creature->level;
if(left.creature->getLevel() != right.creature->getLevel())
return left.creature->getLevel() < right.creature->getLevel();
return left.creature->Speed() > right.creature->Speed();
});
@@ -120,7 +121,7 @@ ui64 ArmyManager::howManyReinforcementsCanBuy(const CCreatureSet * h, const CGDw
if(!ci.count || ci.creID == -1)
continue;
vstd::amin(ci.count, availableRes / ci.cre->cost); //max count we can afford
vstd::amin(ci.count, availableRes / ci.cre->getFullRecruitCost()); //max count we can afford
if(ci.count && ci.creID != -1) //valid creature at this level
{
@@ -135,8 +136,8 @@ ui64 ArmyManager::howManyReinforcementsCanBuy(const CCreatureSet * h, const CGDw
}
//we found matching occupied or free slot
aivalue += ci.count * ci.cre->AIValue;
availableRes -= ci.cre->cost * ci.count;
aivalue += ci.count * ci.cre->getAIValue();
availableRes -= ci.cre->getFullRecruitCost() * ci.count;
}
}

View File

@@ -64,13 +64,13 @@ armyStructure evaluateArmyStructure(const CArmedInstance * army)
for(auto s : army->Slots())
{
bool walker = true;
const CCreature * creature = s.second->type;
if(creature->hasBonus(selectorSHOOTER, keySHOOTER))
auto bearer = s.second->getType()->getBonusBearer();
if(bearer->hasBonus(selectorSHOOTER, keySHOOTER))
{
shootersStrength += s.second->getPower();
walker = false;
}
if(creature->hasBonus(selectorFLYING, keyFLYING))
if(bearer->hasBonus(selectorFLYING, keyFLYING))
{
flyersStrength += s.second->getPower();
walker = false;
@@ -78,7 +78,7 @@ armyStructure evaluateArmyStructure(const CArmedInstance * army)
if(walker)
walkersStrength += s.second->getPower();
vstd::amax(maxSpeed, creature->valOfBonuses(selectorSTACKS_SPEED, keySTACKS_SPEED));
vstd::amax(maxSpeed, bearer->valOfBonuses(selectorSTACKS_SPEED, keySTACKS_SPEED));
}
armyStructure as;
as.walkers = static_cast<float>(walkersStrength / totalStrength);

View File

@@ -35,7 +35,7 @@ TSubgoal BuyArmy::whatToDoToAchieve()
{
//TODO: calculate the actual cost of units instead
TResources price;
price[Res::GOLD] = static_cast<int>(value * 0.4f); //some approximate value
price[EGameResID::GOLD] = static_cast<int>(value * 0.4f); //some approximate value
return ai->ah->whatToDo(price, iAmElementar()); //buy right now or gather resources
}

View File

@@ -46,7 +46,7 @@ TGoalVec CollectRes::getAllPossibleSubgoals()
switch (obj->ID.num)
{
case Obj::TREASURE_CHEST:
return resID == Res::GOLD;
return resID == GameResID(EGameResID::GOLD);
break;
case Obj::RESOURCE:
return obj->subID == resID;
@@ -59,24 +59,24 @@ TGoalVec CollectRes::getAllPossibleSubgoals()
return true; //contains all resources
break;
case Obj::WINDMILL:
switch (resID)
switch (GameResID(resID).toEnum())
{
case Res::GOLD:
case Res::WOOD:
case EGameResID::GOLD:
case EGameResID::WOOD:
return false;
}
break;
case Obj::WATER_WHEEL:
if (resID != Res::GOLD)
if (resID != GameResID(EGameResID::GOLD))
return false;
break;
case Obj::MYSTICAL_GARDEN:
if ((resID != Res::GOLD) && (resID != Res::GEMS))
if ((resID != GameResID(EGameResID::GOLD)) && (resID != GameResID(EGameResID::GEMS)))
return false;
break;
case Obj::LEAN_TO:
case Obj::WAGON:
if (resID != Res::GOLD)
if (resID != GameResID(EGameResID::GOLD))
return false;
break;
default:
@@ -170,12 +170,12 @@ TSubgoal CollectRes::whatToDoToTrade()
const IMarket * m = markets.back();
//attempt trade at back (best prices)
int howManyCanWeBuy = 0;
for (Res::ERes i = Res::WOOD; i <= Res::GOLD; vstd::advance(i, 1))
for (auto i = EGameResID::WOOD; i <= EGameResID::GOLD; vstd::advance(i, 1))
{
if (i == resID)
if (GameResID(i) == resID)
continue;
int toGive = -1, toReceive = -1;
m->getOffer(i, resID, toGive, toReceive, EMarketMode::RESOURCE_RESOURCE);
m->getOffer(GameResID(i), resID, toGive, toReceive, EMarketMode::RESOURCE_RESOURCE);
assert(toGive > 0 && toReceive > 0);
howManyCanWeBuy += toReceive * (ai->ah->freeResources()[i] / toGive);
}
@@ -191,7 +191,7 @@ TSubgoal CollectRes::whatToDoToTrade()
}
else //either it's our town, or we have hero there
{
return sptr(Trade(resID, value, objid).setisElementar(true)); //we can do this immediately
return sptr(Trade(static_cast<EGameResID>(resID), value, objid).setisElementar(true)); //we can do this immediately
}
}
}

View File

@@ -24,10 +24,10 @@ namespace Goals
: CGoal(Goals::COLLECT_RES)
{
}
CollectRes(int rid, int val)
CollectRes(GameResID rid, int val)
: CGoal(Goals::COLLECT_RES)
{
resID = rid;
resID = rid.getNum();
value = val;
priority = 2;
}

View File

@@ -172,7 +172,7 @@ TGoalVec CompleteQuest::missionArmy() const
for(auto creature : q.quest->m6creatures)
{
solutions.push_back(sptr(GatherTroops(creature.type->idNumber, creature.count)));
solutions.push_back(sptr(GatherTroops(creature.type->getId(), creature.count)));
}
return solutions;
@@ -235,7 +235,7 @@ TGoalVec CompleteQuest::missionResources() const
for(int i = 0; i < q.quest->m7resources.size(); ++i)
{
if(q.quest->m7resources[i])
solutions.push_back(sptr(CollectRes(i, q.quest->m7resources[i])));
solutions.push_back(sptr(CollectRes(static_cast<EGameResID>(i), q.quest->m7resources[i])));
}
}
}

View File

@@ -159,7 +159,7 @@ TGoalVec GatherArmy::getAllPossibleSubgoals()
for(auto & creatureID : creLevel.second)
{
auto creature = VLC->creh->objects[creatureID];
if(ai->ah->freeResources().canAfford(creature->cost))
if(ai->ah->freeResources().canAfford(creature->getFullRecruitCost()))
objs.push_back(obj); //TODO: reserve resources?
}
}

View File

@@ -93,21 +93,21 @@ TGoalVec GatherTroops::getAllPossibleSubgoals()
continue;
}
auto creature = VLC->creh->objects[objid];
if(t->subID == creature->faction) //TODO: how to force AI to build unupgraded creatures? :O
auto creature = VLC->creatures()->getByIndex(objid);
if(t->subID == creature->getFactionIndex()) //TODO: how to force AI to build unupgraded creatures? :O
{
auto creatures = vstd::tryAt(t->town->creatures, creature->level - 1);
auto creatures = vstd::tryAt(t->town->creatures, creature->getLevel() - 1);
if(!creatures)
continue;
int upgradeNumber = vstd::find_pos(*creatures, creature->idNumber);
int upgradeNumber = vstd::find_pos(*creatures, creature->getId());
if(upgradeNumber < 0)
continue;
BuildingID bid(BuildingID::DWELL_FIRST + creature->level - 1 + upgradeNumber * GameConstants::CREATURES_PER_TOWN);
if(t->hasBuilt(bid) && ai->ah->freeResources().canAfford(creature->cost)) //this assumes only creatures with dwellings are assigned to faction
BuildingID bid(BuildingID::DWELL_FIRST + creature->getLevel() - 1 + upgradeNumber * GameConstants::CREATURES_PER_TOWN);
if(t->hasBuilt(bid) && ai->ah->freeResources().canAfford(creature->getFullRecruitCost())) //this assumes only creatures with dwellings are assigned to faction
{
solutions.push_back(sptr(BuyArmy(t, creature->AIValue * this->value).setobjid(objid)));
solutions.push_back(sptr(BuyArmy(t, creature->getAIValue() * this->value).setobjid(objid)));
}
/*else //disable random building requests for now - this code needs to know a lot of town/resource context to do more good than harm
{
@@ -129,7 +129,7 @@ TGoalVec GatherTroops::getAllPossibleSubgoals()
{
for(auto type : creature.second)
{
if(type == objid && ai->ah->freeResources().canAfford(VLC->creh->objects[type]->cost))
if(type == objid && ai->ah->freeResources().canAfford(VLC->creatures()->getById(type)->getFullRecruitCost()))
vstd::concatenate(solutions, ai->ah->howToVisitObj(obj));
}
}

View File

@@ -33,6 +33,6 @@ TSubgoal RecruitHero::whatToDoToAchieve()
return sptr(BuildThis(BuildingID::TAVERN).setpriority(2));
TResources res;
res[Res::GOLD] = GameConstants::HERO_GOLD_COST;
res[EGameResID::GOLD] = GameConstants::HERO_GOLD_COST;
return ai->ah->whatToDo(res, iAmElementar()); //either buy immediately, or collect res
}

View File

@@ -24,10 +24,10 @@ namespace Goals
: CGoal(Goals::TRADE)
{
}
Trade(int rid, int val, int Objid)
Trade(GameResID rid, int val, int Objid)
: CGoal(Goals::TRADE)
{
resID = rid;
resID = rid.getNum();
value = val;
objid = Objid;
priority = 3; //trading is instant, but picking resources is free

View File

@@ -154,7 +154,7 @@ TSubgoal Win::whatToDoToAchieve()
case EventCondition::HAVE_RESOURCES:
//TODO mines? piles? marketplace?
//save?
return sptr(CollectRes(static_cast<Res::ERes>(goal.objectType), goal.value));
return sptr(CollectRes(static_cast<EGameResID>(goal.objectType), goal.value));
case EventCondition::HAVE_CREATURES:
return sptr(GatherTroops(goal.objectType, goal.value));
case EventCondition::TRANSPORT:

View File

@@ -73,8 +73,8 @@ boost::optional<int> MapObjectsEvaluator::getObjectValue(const CGObjectInstance
{
for(auto & creatureID : creLevel.second)
{
auto creature = VLC->creh->objects[creatureID];
aiValue += (creature->AIValue * creature->growth);
auto creature = VLC->creatures()->getById(creatureID);
aiValue += (creature->getAIValue() * creature->getGrowth());
}
}
return aiValue;

View File

@@ -58,15 +58,15 @@ TResources ResourceManager::estimateIncome() const
{
if (obj->ID == Obj::MINE)
{
switch (obj->subID)
auto mine = dynamic_cast<const CGMine*>(obj);
switch (mine->producedResource.toEnum())
{
case Res::WOOD:
case Res::ORE:
case EGameResID::WOOD:
case EGameResID::ORE:
ret[obj->subID] += WOOD_ORE_MINE_PRODUCTION;
break;
case Res::GOLD:
case 7: //abandoned mine -> also gold
ret[Res::GOLD] += GOLD_MINE_PRODUCTION;
case EGameResID::GOLD:
ret[EGameResID::GOLD] += GOLD_MINE_PRODUCTION;
break;
default:
ret[obj->subID] += RESOURCE_MINE_PRODUCTION;
@@ -90,11 +90,11 @@ Goals::TSubgoal ResourceManager::collectResourcesForOurGoal(ResourceObjective &o
{
auto allResources = cb->getResourceAmount();
auto income = estimateIncome();
Res::ERes resourceType = Res::INVALID;
GameResID resourceType = EGameResID::INVALID;
TResource amountToCollect = 0;
typedef std::pair<Res::ERes, TResource> resPair;
std::map<Res::ERes, TResource> missingResources;
using resPair = std::pair<GameResID, TResource>;
std::map<GameResID, TResource> missingResources;
//TODO: unit test for complex resource sets
@@ -102,10 +102,10 @@ Goals::TSubgoal ResourceManager::collectResourcesForOurGoal(ResourceObjective &o
for (auto it = queue.ordered_begin(); it != queue.ordered_end(); it++)
{
//choose specific resources we need for this goal (not 0)
for (auto r = Res::ResourceSet::nziterator(o.resources); r.valid(); r++)
for (auto r = ResourceSet::nziterator(o.resources); r.valid(); r++)
missingResources[r->resType] += it->resources[r->resType]; //goal it costs r units of resType
}
for (auto it = Res::ResourceSet::nziterator(o.resources); it.valid(); it++)
for (auto it = ResourceSet::nziterator(o.resources); it.valid(); it++)
{
missingResources[it->resType] -= allResources[it->resType]; //missing = (what we need) - (what we have)
vstd::amax(missingResources[it->resType], 0); // if we have more resources than reserved, we don't need them
@@ -129,11 +129,11 @@ Goals::TSubgoal ResourceManager::collectResourcesForOurGoal(ResourceObjective &o
break;
}
}
if (resourceType == Res::INVALID) //no needed resources has 0 income,
if (resourceType == EGameResID::INVALID) //no needed resources has 0 income,
{
//find the one which takes longest to collect
typedef std::pair<Res::ERes, float> timePair;
std::map<Res::ERes, float> daysToEarn;
using timePair = std::pair<GameResID, float>;
std::map<GameResID, float> daysToEarn;
for (auto it : missingResources)
daysToEarn[it.first] = (float)missingResources[it.first] / income[it.first];
auto incomeComparer = [](const timePair & lhs, const timePair & rhs) -> bool
@@ -345,7 +345,7 @@ TResources ResourceManager::freeResources() const
TResource ResourceManager::freeGold() const
{
return freeResources()[Res::GOLD];
return freeResources()[EGameResID::GOLD];
}
TResources ResourceManager::allResources() const
@@ -355,5 +355,5 @@ TResources ResourceManager::allResources() const
TResource ResourceManager::allGold() const
{
return cb->getResourceAmount()[Res::GOLD];
return cb->getResourceAmount()[EGameResID::GOLD];
}

View File

@@ -1235,7 +1235,7 @@ void VCAI::recruitCreatures(const CGDwelling * d, const CArmedInstance * recruit
int count = d->creatures[i].first;
CreatureID creID = d->creatures[i].second.back();
vstd::amin(count, ah->freeResources() / VLC->creh->objects[creID]->cost);
vstd::amin(count, ah->freeResources() / VLC->creatures()->getById(creID)->getFullRecruitCost());
if(count > 0)
cb->recruitCreatures(d, recruiter, creID, count, i);
}
@@ -1314,7 +1314,7 @@ bool VCAI::canRecruitAnyHero(const CGTownInstance * t) const
t = findTownWithTavern();
if(!t)
return false;
if(cb->getResourceAmount(Res::GOLD) < GameConstants::HERO_GOLD_COST) //TODO: use ResourceManager
if(cb->getResourceAmount(EGameResID::GOLD) < GameConstants::HERO_GOLD_COST) //TODO: use ResourceManager
return false;
if(cb->getHeroesInfo().size() >= ALLOWED_ROAMING_HEROES)
return false;
@@ -1434,7 +1434,7 @@ void VCAI::wander(HeroPtr h)
}
break;
}
else if(cb->getResourceAmount(Res::GOLD) >= GameConstants::HERO_GOLD_COST)
else if(cb->getResourceAmount(EGameResID::GOLD) >= GameConstants::HERO_GOLD_COST)
{
std::vector<const CGTownInstance *> towns = cb->getTownsInfo();
vstd::erase_if(towns, [&](const CGTownInstance * t) -> bool
@@ -2117,10 +2117,10 @@ void VCAI::tryRealize(Goals::Trade & g) //trade
if(const IMarket * m = IMarket::castFrom(obj, false))
{
auto freeRes = ah->freeResources(); //trade only resources which are not reserved
for(auto it = Res::ResourceSet::nziterator(freeRes); it.valid(); it++)
for(auto it = ResourceSet::nziterator(freeRes); it.valid(); it++)
{
auto res = it->resType;
if(res == g.resID) //sell any other resource
if(res.getNum() == g.resID) //sell any other resource
continue;
int toGive, toGet;
@@ -2174,7 +2174,7 @@ void VCAI::tryRealize(Goals::BuyArmy & g)
|| t->getUpperArmy()->getSlotFor(ci.creID) == SlotID())
continue;
vstd::amin(ci.count, res / ci.cre->cost); //max count we can afford
vstd::amin(ci.count, res / ci.cre->getFullRecruitCost()); //max count we can afford
if(!ci.count)
continue;
@@ -2190,15 +2190,15 @@ void VCAI::tryRealize(Goals::BuyArmy & g)
*boost::max_element(creaturesInDwellings, [](const creInfo & lhs, const creInfo & rhs)
{
//max value of creatures we can buy with our res
int value1 = lhs.cre->AIValue * lhs.count,
value2 = rhs.cre->AIValue * rhs.count;
int value1 = lhs.cre->getAIValue() * lhs.count,
value2 = rhs.cre->getAIValue() * rhs.count;
return value1 < value2;
});
cb->recruitCreatures(t, t->getUpperArmy(), ci.creID, ci.count, ci.level);
valueBought += ci.count * ci.cre->AIValue;
valueBought += ci.count * ci.cre->getAIValue();
}
throw goalFulfilledException(sptr(g)); //we bought as many creatures as we wanted
@@ -2820,7 +2820,7 @@ bool shouldVisit(HeroPtr h, const CGObjectInstance * obj)
{
for(auto slot : h->Slots())
{
if(slot.second->type->upgrades.size())
if(slot.second->type->hasUpgrades())
return true; //TODO: check price?
}
return false;
@@ -2844,7 +2844,7 @@ bool shouldVisit(HeroPtr h, const CGObjectInstance * obj)
case Obj::TREE_OF_KNOWLEDGE:
{
TResources myRes = ai->ah->freeResources();
if(myRes[Res::GOLD] < 2000 || myRes[Res::GEMS] < 10)
if(myRes[EGameResID::GOLD] < 2000 || myRes[EGameResID::GEMS] < 10)
return false;
break;
}