mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Merge branch 'develop' into SpellsRefactoring4
This commit is contained in:
commit
eebf65e88f
@ -321,13 +321,13 @@ BattleAction CStupidAI::goTowards(const CStack * stack, BattleHex destination)
|
||||
}
|
||||
}
|
||||
|
||||
void CStupidAI::saveGame(COSer<CSaveFile> &h, const int version)
|
||||
void CStupidAI::saveGame(COSer & h, const int version)
|
||||
{
|
||||
//TODO to be implemented with saving/loading during the battles
|
||||
assert(0);
|
||||
}
|
||||
|
||||
void CStupidAI::loadGame(CISer<CLoadFile> &h, const int version)
|
||||
void CStupidAI::loadGame(CISer & h, const int version)
|
||||
{
|
||||
//TODO to be implemented with saving/loading during the battles
|
||||
assert(0);
|
||||
|
@ -36,8 +36,8 @@ public:
|
||||
|
||||
BattleAction goTowards(const CStack * stack, BattleHex hex );
|
||||
|
||||
virtual void saveGame(COSer<CSaveFile> &h, const int version) override;
|
||||
virtual void loadGame(CISer<CLoadFile> &h, const int version) override;
|
||||
virtual void saveGame(COSer & h, const int version) override;
|
||||
virtual void loadGame(CISer & h, const int version) override;
|
||||
|
||||
};
|
||||
|
||||
|
@ -234,8 +234,11 @@ ui64 evaluateDanger(crint3 tile, const CGHeroInstance *visitor)
|
||||
{
|
||||
//TODO: don't downcast objects AI shouldn't know about!
|
||||
auto armedObj = dynamic_cast<const CArmedInstance*>(dangerousObject);
|
||||
if(armedObj)
|
||||
objectDanger *= fh->getTacticalAdvantage(visitor, armedObj); //this line tends to go infinite for allied towns (?)
|
||||
if (armedObj)
|
||||
{
|
||||
float tacticalAdvantage = fh->getTacticalAdvantage(visitor, armedObj);
|
||||
objectDanger *= tacticalAdvantage; //this line tends to go infinite for allied towns (?)
|
||||
}
|
||||
}
|
||||
if (dangerousObject->ID == Obj::SUBTERRANEAN_GATE)
|
||||
{ //check guard on the other side of the gate
|
||||
|
@ -20,9 +20,11 @@
|
||||
*/
|
||||
|
||||
#define MIN_AI_STRENGHT (0.5f) //lower when combat AI gets smarter
|
||||
#define UNGUARDED_OBJECT (100.0f) //we consider unguarded objects 10 times weaker than us
|
||||
#define UNGUARDED_OBJECT (100.0f) //we consider unguarded objects 100 times weaker than us
|
||||
|
||||
struct BankConfig;
|
||||
class IObjectInfo;
|
||||
class CBankInfo;
|
||||
class Engine;
|
||||
class InputVariable;
|
||||
class CGTownInstance;
|
||||
@ -35,6 +37,22 @@ FuzzyHelper *fh;
|
||||
extern boost::thread_specific_ptr<CCallback> cb;
|
||||
extern boost::thread_specific_ptr<VCAI> ai;
|
||||
|
||||
engineBase::engineBase()
|
||||
{
|
||||
engine.addRuleBlock(&rules);
|
||||
}
|
||||
|
||||
void engineBase::configure()
|
||||
{
|
||||
engine.configure("Minimum", "Maximum", "Minimum", "AlgebraicSum", "Centroid");
|
||||
logAi->infoStream() << engine.toString();
|
||||
}
|
||||
|
||||
void engineBase::addRule(const std::string &txt)
|
||||
{
|
||||
rules.addRule(fl::Rule::parse(txt, &engine));
|
||||
}
|
||||
|
||||
struct armyStructure
|
||||
{
|
||||
float walkers, shooters, flyers;
|
||||
@ -72,45 +90,18 @@ armyStructure evaluateArmyStructure (const CArmedInstance * army)
|
||||
as.shooters = shootersStrenght / totalStrenght;
|
||||
as.flyers = flyersStrenght / totalStrenght;
|
||||
as.maxSpeed = maxSpeed;
|
||||
assert(as.walkers || as.flyers || as.shooters);
|
||||
return as;
|
||||
}
|
||||
|
||||
FuzzyHelper::FuzzyHelper()
|
||||
{
|
||||
initBank();
|
||||
initTacticalAdvantage();
|
||||
ta.configure();
|
||||
initVisitTile();
|
||||
|
||||
engine.configure("AlgebraicProduct", "AlgebraicSum",
|
||||
"AlgebraicProduct", "AlgebraicSum", "Centroid");
|
||||
|
||||
logAi->infoStream() << engine.toString();
|
||||
vt.configure();
|
||||
}
|
||||
|
||||
void FuzzyHelper::initBank()
|
||||
{
|
||||
try
|
||||
{
|
||||
//Trivial bank estimation
|
||||
bankInput = new fl::InputVariable("BankInput");
|
||||
bankDanger = new fl::OutputVariable("BankDanger");
|
||||
bankInput->addTerm(new fl::Rectangle("SET", 0.5 - 5 * fl::fuzzylite::macheps(),
|
||||
0.5 + 5 * fl::fuzzylite::macheps()));
|
||||
|
||||
engine.addInputVariable(bankInput);
|
||||
engine.addOutputVariable(bankDanger);
|
||||
engine.addRuleBlock(&bankBlock);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
bankDanger->addTerm(new fl::Triangle("Bank" + boost::lexical_cast<std::string>(i), 0, 1));
|
||||
bankBlock.addRule(fl::Rule::parse("if BankInput is SET then BankDanger is Bank" + boost::lexical_cast<std::string>(i), &engine));
|
||||
}
|
||||
}
|
||||
catch (fl::Exception & fe)
|
||||
{
|
||||
logAi->errorStream() << "initBank : " << fe.getWhat();
|
||||
}
|
||||
}
|
||||
|
||||
void FuzzyHelper::initTacticalAdvantage()
|
||||
{
|
||||
@ -132,9 +123,10 @@ void FuzzyHelper::initTacticalAdvantage()
|
||||
|
||||
for (auto val : helper)
|
||||
{
|
||||
engine.addInputVariable(val);
|
||||
ta.engine.addInputVariable(val);
|
||||
val->addTerm(new fl::Ramp("FEW", 0.6, 0.0));
|
||||
val->addTerm(new fl::Ramp("MANY", 0.4, 1));
|
||||
val->setRange(0.0, 1.0);
|
||||
}
|
||||
|
||||
ta.ourSpeed = new fl::InputVariable("OurSpeed");
|
||||
@ -144,57 +136,66 @@ void FuzzyHelper::initTacticalAdvantage()
|
||||
|
||||
for (auto val : helper)
|
||||
{
|
||||
engine.addInputVariable(val);
|
||||
ta.engine.addInputVariable(val);
|
||||
val->addTerm(new fl::Ramp("LOW", 6.5, 3));
|
||||
val->addTerm(new fl::Triangle("MEDIUM", 5.5, 10.5));
|
||||
val->addTerm(new fl::Ramp("HIGH", 8.5, 16));
|
||||
val->setRange(0, 25);
|
||||
}
|
||||
|
||||
ta.castleWalls = new fl::InputVariable("CastleWalls");
|
||||
engine.addInputVariable(ta.castleWalls);
|
||||
ta.castleWalls->addTerm(new fl::Rectangle("NONE", CGTownInstance::NONE - 5.0 * fl::fuzzylite::macheps(),
|
||||
CGTownInstance::NONE + 5.0 * fl::fuzzylite::macheps()));
|
||||
ta.engine.addInputVariable(ta.castleWalls);
|
||||
{
|
||||
fl::scalar a = CGTownInstance::FORT, d = 2.5;
|
||||
fl::scalar b = a + (d - a) * 1.0 / 5.0;
|
||||
fl::scalar c = a + (d - a) * 4.0 / 5.0;
|
||||
ta.castleWalls->addTerm(new fl::Trapezoid("MEDIUM", a, b, c, d));
|
||||
fl::Rectangle* none = new fl::Rectangle("NONE", CGTownInstance::NONE, CGTownInstance::NONE + (CGTownInstance::FORT - CGTownInstance::NONE) * 0.5f);
|
||||
ta.castleWalls->addTerm(none);
|
||||
|
||||
fl::Trapezoid* medium = new fl::Trapezoid("MEDIUM", (CGTownInstance::FORT - CGTownInstance::NONE) * 0.5f, CGTownInstance::FORT,
|
||||
CGTownInstance::CITADEL, CGTownInstance::CITADEL + (CGTownInstance::CASTLE - CGTownInstance::CITADEL) * 0.5f);
|
||||
ta.castleWalls->addTerm(medium);
|
||||
|
||||
fl::Ramp* high = new fl::Ramp("HIGH", CGTownInstance::CITADEL - 0.1, CGTownInstance::CASTLE);
|
||||
ta.castleWalls->addTerm(high);
|
||||
|
||||
ta.castleWalls->setRange(CGTownInstance::NONE, CGTownInstance::CASTLE);
|
||||
}
|
||||
|
||||
ta.castleWalls->addTerm(new fl::Ramp("HIGH", CGTownInstance::CITADEL - 0.1, CGTownInstance::CASTLE));
|
||||
|
||||
|
||||
ta.bankPresent = new fl::InputVariable("Bank");
|
||||
engine.addInputVariable(ta.bankPresent);
|
||||
ta.bankPresent->addTerm(new fl::Rectangle("FALSE", 0.0 - 5.0 * fl::fuzzylite::macheps(),
|
||||
0.0 + 5.0 * fl::fuzzylite::macheps()));
|
||||
ta.bankPresent->addTerm(new fl::Rectangle("TRUE", 1.0 - 5.0 * fl::fuzzylite::macheps(),
|
||||
0.0 + 5.0 * fl::fuzzylite::macheps()));
|
||||
ta.engine.addInputVariable(ta.bankPresent);
|
||||
{
|
||||
fl::Rectangle* termFalse = new fl::Rectangle("FALSE", 0.0, 0.5f);
|
||||
ta.bankPresent->addTerm(termFalse);
|
||||
fl::Rectangle* termTrue = new fl::Rectangle("TRUE", 0.5f, 1);
|
||||
ta.bankPresent->addTerm(termTrue);
|
||||
ta.bankPresent->setRange(0, 1);
|
||||
}
|
||||
|
||||
ta.threat = new fl::OutputVariable("Threat");
|
||||
engine.addOutputVariable(ta.threat);
|
||||
ta.engine.addOutputVariable(ta.threat);
|
||||
ta.threat->addTerm(new fl::Ramp("LOW", 1, MIN_AI_STRENGHT));
|
||||
ta.threat->addTerm(new fl::Triangle("MEDIUM", 0.8, 1.2));
|
||||
ta.threat->addTerm(new fl::Ramp("HIGH", 1, 1.5));
|
||||
ta.threat->setRange(MIN_AI_STRENGHT, 1.5);
|
||||
|
||||
engine.addRuleBlock(&ta.tacticalAdvantage);
|
||||
ta.addRule("if OurShooters is MANY and EnemySpeed is LOW then Threat is LOW");
|
||||
ta.addRule("if OurShooters is MANY and EnemyShooters is FEW then Threat is LOW");
|
||||
ta.addRule("if OurSpeed is LOW and EnemyShooters is MANY then Threat is HIGH");
|
||||
ta.addRule("if OurSpeed is HIGH and EnemyShooters is MANY then Threat is LOW");
|
||||
|
||||
ta.tacticalAdvantage.addRule(fl::Rule::parse("if OurShooters is MANY and EnemySpeed is LOW then Threat is LOW", &engine));
|
||||
ta.tacticalAdvantage.addRule(fl::Rule::parse("if OurShooters is MANY and EnemyShooters is FEW then Threat is LOW", &engine));
|
||||
ta.tacticalAdvantage.addRule(fl::Rule::parse("if OurSpeed is LOW and EnemyShooters is MANY then Threat is HIGH", &engine));
|
||||
ta.tacticalAdvantage.addRule(fl::Rule::parse("if OurSpeed is HIGH and EnemyShooters is MANY then Threat is LOW", &engine));
|
||||
|
||||
ta.tacticalAdvantage.addRule(fl::Rule::parse("if OurWalkers is FEW and EnemyShooters is MANY then Threat is somewhat LOW", &engine));
|
||||
ta.tacticalAdvantage.addRule(fl::Rule::parse("if OurShooters is MANY and EnemySpeed is HIGH then Threat is somewhat HIGH", &engine));
|
||||
ta.addRule("if OurWalkers is FEW and EnemyShooters is MANY then Threat is somewhat LOW");
|
||||
ta.addRule("if OurShooters is MANY and EnemySpeed is HIGH then Threat is somewhat HIGH");
|
||||
//just to cover all cases
|
||||
ta.tacticalAdvantage.addRule(fl::Rule::parse("if EnemySpeed is MEDIUM then Threat is MEDIUM", &engine));
|
||||
ta.tacticalAdvantage.addRule(fl::Rule::parse("if EnemySpeed is LOW and OurShooters is FEW then Threat is MEDIUM", &engine));
|
||||
ta.addRule("if OurShooters is FEW and EnemySpeed is HIGH then Threat is MEDIUM");
|
||||
ta.addRule("if EnemySpeed is MEDIUM then Threat is MEDIUM");
|
||||
ta.addRule("if EnemySpeed is LOW and OurShooters is FEW then Threat is MEDIUM");
|
||||
|
||||
ta.tacticalAdvantage.addRule(fl::Rule::parse("if Bank is TRUE and OurShooters is MANY then Threat is somewhat HIGH", &engine));
|
||||
ta.tacticalAdvantage.addRule(fl::Rule::parse("if Bank is TRUE and EnemyShooters is MANY then Threat is LOW", &engine));
|
||||
ta.addRule("if Bank is TRUE and OurShooters is MANY then Threat is somewhat HIGH");
|
||||
ta.addRule("if Bank is TRUE and EnemyShooters is MANY then Threat is LOW");
|
||||
|
||||
ta.tacticalAdvantage.addRule(fl::Rule::parse("if CastleWalls is HIGH and OurWalkers is MANY then Threat is very HIGH", &engine));
|
||||
ta.tacticalAdvantage.addRule(fl::Rule::parse("if CastleWalls is HIGH and OurFlyers is MANY and OurShooters is MANY then Threat is MEDIUM", &engine));
|
||||
ta.tacticalAdvantage.addRule(fl::Rule::parse("if CastleWalls is MEDIUM and OurShooters is MANY and EnemyWalkers is MANY then Threat is LOW", &engine));
|
||||
ta.addRule("if CastleWalls is HIGH and OurWalkers is MANY then Threat is very HIGH");
|
||||
ta.addRule("if CastleWalls is HIGH and OurFlyers is MANY and OurShooters is MANY then Threat is MEDIUM");
|
||||
ta.addRule("if CastleWalls is MEDIUM and OurShooters is MANY and EnemyWalkers is MANY then Threat is LOW");
|
||||
|
||||
}
|
||||
catch (fl::Exception & pe)
|
||||
@ -205,34 +206,20 @@ void FuzzyHelper::initTacticalAdvantage()
|
||||
|
||||
ui64 FuzzyHelper::estimateBankDanger (const CBank * bank)
|
||||
{
|
||||
auto info = VLC->objtypeh->getHandlerFor(bank->ID, bank->subID)->getObjectInfo(bank->appearance);
|
||||
//this one is not fuzzy anymore, just calculate weighted average
|
||||
|
||||
ui64 val = std::numeric_limits<ui64>::max();
|
||||
try
|
||||
{
|
||||
fl::Triangle* bank0 = dynamic_cast<fl::Triangle*> (bankDanger->getTerm("Bank0"));
|
||||
fl::Triangle* bank1 = dynamic_cast<fl::Triangle*> (bankDanger->getTerm("Bank1"));
|
||||
if (bank0 && bank1)
|
||||
{
|
||||
bank0->setVertexA(info->minGuards().totalStrength * 0.5f);
|
||||
bank0->setVertexC(info->minGuards().totalStrength * 1.5f);
|
||||
bank1->setVertexA(info->maxGuards().totalStrength * 0.5f);
|
||||
bank1->setVertexC(info->maxGuards().totalStrength * 1.5f);
|
||||
}
|
||||
auto objectInfo = VLC->objtypeh->getHandlerFor(bank->ID, bank->subID)->getObjectInfo(bank->appearance);
|
||||
|
||||
//comparison purposes
|
||||
//int averageValue = (evaluateBankConfig (VLC->objh->banksInfo[ID][0]) + evaluateBankConfig (VLC->objh->banksInfo[ID][3])) * 0.5;
|
||||
//dynamic_cast<fl::SingletonTerm*>(bankInput->term("SET"))->setValue(0.5);
|
||||
bankInput->setInputValue(0.5);
|
||||
//engine.process(BANK_DANGER);//TODO: Process Bank_Dange only
|
||||
engine.process(); //TODO: Process Bank_Dange only
|
||||
val = bankDanger->getOutputValue(); //some expected value of this bank
|
||||
}
|
||||
catch (fl::Exception & fe)
|
||||
CBankInfo * bankInfo = dynamic_cast<CBankInfo *> (objectInfo.get());
|
||||
|
||||
ui64 totalStrength = 0;
|
||||
ui8 totalChance = 0;
|
||||
for (auto config : bankInfo->getPossibleGuards())
|
||||
{
|
||||
logAi->errorStream() << "estimateBankDanger " << ": " << fe.getWhat();
|
||||
totalStrength += config.second.totalStrength * config.first;
|
||||
totalChance += config.first;
|
||||
}
|
||||
return val;
|
||||
return totalStrength / totalChance;
|
||||
|
||||
}
|
||||
|
||||
@ -269,13 +256,26 @@ float FuzzyHelper::getTacticalAdvantage (const CArmedInstance *we, const CArmedI
|
||||
ta.castleWalls->setInputValue(0);
|
||||
|
||||
//engine.process(TACTICAL_ADVANTAGE);//TODO: Process only Tactical_Advantage
|
||||
engine.process();
|
||||
ta.engine.process();
|
||||
output = ta.threat->getOutputValue();
|
||||
}
|
||||
catch (fl::Exception & fe)
|
||||
{
|
||||
logAi->errorStream() << "getTacticalAdvantage " << ": " << fe.getWhat();
|
||||
}
|
||||
logAi->traceStream() << "getTacticalAdvantage output: " << output;
|
||||
if (output < 0 || (output != output))
|
||||
{
|
||||
fl::InputVariable* tab[] = {ta.bankPresent, ta.castleWalls, ta.ourWalkers, ta.ourShooters, ta.ourFlyers, ta.ourSpeed, ta.enemyWalkers, ta.enemyShooters, ta.enemyFlyers, ta.enemySpeed};
|
||||
std::string names[] = {"bankPresent", "castleWalls", "ourWalkers", "ourShooters", "ourFlyers", "ourSpeed", "enemyWalkers", "enemyShooters", "enemyFlyers", "enemySpeed" };
|
||||
std::stringstream log("Warning! Fuzzy engine doesn't cover this set of parameters: ");
|
||||
|
||||
for (int i = 0; i < boost::size(tab); i++)
|
||||
log << names[i] << ": " << tab[i]->getInputValue() << " ";
|
||||
logAi->errorStream() << log.str();
|
||||
assert(false);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
@ -343,63 +343,67 @@ void FuzzyHelper::initVisitTile()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
vt.strengthRatio = new fl::InputVariable("strengthRatio"); //hero must be strong enough to defeat guards
|
||||
vt.heroStrength = new fl::InputVariable("heroStrength"); //we want to use weakest possible hero
|
||||
vt.turnDistance = new fl::InputVariable("turnDistance"); //we want to use hero who is near
|
||||
vt.missionImportance = new fl::InputVariable("lockedMissionImportance"); //we may want to preempt hero with low-priority mission
|
||||
vt.value = new fl::OutputVariable("Value");
|
||||
vt.value->setMinimum(0);
|
||||
vt.value->setMaximum(5);
|
||||
|
||||
std::vector<fl::InputVariable*> helper = {vt.strengthRatio, vt.heroStrength, vt.turnDistance, vt.missionImportance};
|
||||
for (auto val : helper)
|
||||
{
|
||||
engine.addInputVariable(val);
|
||||
vt.engine.addInputVariable(val);
|
||||
}
|
||||
engine.addOutputVariable(vt.value);
|
||||
vt.engine.addOutputVariable(vt.value);
|
||||
|
||||
vt.strengthRatio->addTerm(new fl::Ramp("LOW", SAFE_ATTACK_CONSTANT, 0));
|
||||
vt.strengthRatio->addTerm(new fl::Ramp("HIGH", SAFE_ATTACK_CONSTANT, SAFE_ATTACK_CONSTANT * 3));
|
||||
vt.strengthRatio->setRange(0, SAFE_ATTACK_CONSTANT * 3 );
|
||||
|
||||
//strength compared to our main hero
|
||||
vt.heroStrength->addTerm(new fl::Ramp("LOW", 0.2, 0));
|
||||
vt.heroStrength->addTerm(new fl::Triangle("MEDIUM", 0.2, 0.8));
|
||||
vt.heroStrength->addTerm(new fl::Ramp("HIGH", 0.5, 1));
|
||||
vt.heroStrength->setRange(0.0, 1.0);
|
||||
|
||||
vt.turnDistance->addTerm(new fl::Ramp("SMALL", 0.5, 0));
|
||||
vt.turnDistance->addTerm(new fl::Triangle("MEDIUM", 0.1, 0.8));
|
||||
vt.turnDistance->addTerm(new fl::Ramp("LONG", 0.5, 3));
|
||||
vt.turnDistance->setRange(0.0, 3.0);
|
||||
|
||||
vt.missionImportance->addTerm(new fl::Ramp("LOW", 2.5, 0));
|
||||
vt.missionImportance->addTerm(new fl::Triangle("MEDIUM", 2, 3));
|
||||
vt.missionImportance->addTerm(new fl::Ramp("HIGH", 2.5, 5));
|
||||
vt.missionImportance->setRange(0.0, 5.0);
|
||||
|
||||
//an issue: in 99% cases this outputs center of mass (2.5) regardless of actual input :/
|
||||
//should be same as "mission Importance" to keep consistency
|
||||
vt.value->addTerm(new fl::Ramp("LOW", 2.5, 0));
|
||||
vt.value->addTerm(new fl::Triangle("MEDIUM", 2, 3)); //can't be center of mass :/
|
||||
vt.value->addTerm(new fl::Ramp("HIGH", 2.5, 5));
|
||||
|
||||
engine.addRuleBlock (&vt.rules);
|
||||
vt.value->setRange(0.0,5.0);
|
||||
|
||||
//use unarmed scouts if possible
|
||||
vt.rules.addRule(fl::Rule::parse("if strengthRatio is HIGH and heroStrength is LOW then Value is very HIGH", &engine));
|
||||
vt.addRule("if strengthRatio is HIGH and heroStrength is LOW then Value is very HIGH");
|
||||
//we may want to use secondary hero(es) rather than main hero
|
||||
vt.rules.addRule(fl::Rule::parse("if strengthRatio is HIGH and heroStrength is MEDIUM then Value is somewhat HIGH", &engine));
|
||||
vt.rules.addRule(fl::Rule::parse("if strengthRatio is HIGH and heroStrength is HIGH then Value is somewhat LOW", &engine));
|
||||
vt.addRule("if strengthRatio is HIGH and heroStrength is MEDIUM then Value is somewhat HIGH");
|
||||
vt.addRule("if strengthRatio is HIGH and heroStrength is HIGH then Value is somewhat LOW");
|
||||
//don't assign targets to heroes who are too weak, but prefer targets of our main hero (in case we need to gather army)
|
||||
vt.rules.addRule(fl::Rule::parse("if strengthRatio is LOW and heroStrength is LOW then Value is very LOW", &engine));
|
||||
vt.addRule("if strengthRatio is LOW and heroStrength is LOW then Value is very LOW");
|
||||
//attempt to arm secondary heroes is not stupid
|
||||
vt.rules.addRule(fl::Rule::parse("if strengthRatio is LOW and heroStrength is MEDIUM then Value is somewhat HIGH", &engine));
|
||||
vt.rules.addRule(fl::Rule::parse("if strengthRatio is LOW and heroStrength is HIGH then Value is LOW", &engine));
|
||||
vt.addRule("if strengthRatio is LOW and heroStrength is MEDIUM then Value is somewhat HIGH");
|
||||
vt.addRule("if strengthRatio is LOW and heroStrength is HIGH then Value is LOW");
|
||||
|
||||
//do not cancel important goals
|
||||
vt.rules.addRule(fl::Rule::parse("if lockedMissionImportance is HIGH then Value is very LOW", &engine));
|
||||
vt.rules.addRule(fl::Rule::parse("if lockedMissionImportance is MEDIUM then Value is somewhat LOW", &engine));
|
||||
vt.rules.addRule(fl::Rule::parse("if lockedMissionImportance is LOW then Value is HIGH", &engine));
|
||||
vt.addRule("if lockedMissionImportance is HIGH then Value is very LOW");
|
||||
vt.addRule("if lockedMissionImportance is MEDIUM then Value is somewhat LOW");
|
||||
vt.addRule("if lockedMissionImportance is LOW then Value is HIGH");
|
||||
//pick nearby objects if it's easy, avoid long walks
|
||||
vt.rules.addRule(fl::Rule::parse("if turnDistance is SMALL then Value is HIGH", &engine));
|
||||
vt.rules.addRule(fl::Rule::parse("if turnDistance is MEDIUM then Value is MEDIUM", &engine));
|
||||
vt.rules.addRule(fl::Rule::parse("if turnDistance is LONG then Value is LOW", &engine));
|
||||
vt.addRule("if turnDistance is SMALL then Value is HIGH");
|
||||
vt.addRule("if turnDistance is MEDIUM then Value is MEDIUM");
|
||||
vt.addRule("if turnDistance is LONG then Value is LOW");
|
||||
}
|
||||
catch (fl::Exception & fe)
|
||||
{
|
||||
@ -442,7 +446,7 @@ float FuzzyHelper::evaluate (Goals::VisitTile & g)
|
||||
vt.turnDistance->setInputValue(turns);
|
||||
vt.missionImportance->setInputValue(missionImportance);
|
||||
|
||||
engine.process();
|
||||
vt.engine.process();
|
||||
//engine.process(VISIT_TILE); //TODO: Process only Visit_Tile
|
||||
g.priority = vt.value->getOutputValue();
|
||||
}
|
||||
@ -450,6 +454,7 @@ float FuzzyHelper::evaluate (Goals::VisitTile & g)
|
||||
{
|
||||
logAi->errorStream() << "evaluate VisitTile " << ": " << fe.getWhat();
|
||||
}
|
||||
assert (g.priority >= 0);
|
||||
return g.priority;
|
||||
|
||||
}
|
||||
@ -493,6 +498,7 @@ float FuzzyHelper::evaluate (Goals::ClearWayTo & g)
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
float FuzzyHelper::evaluate (Goals::BuildThis & g)
|
||||
|
@ -16,17 +16,22 @@ class VCAI;
|
||||
class CArmedInstance;
|
||||
class CBank;
|
||||
|
||||
class engineBase
|
||||
{
|
||||
public:
|
||||
fl::Engine engine;
|
||||
fl::RuleBlock rules;
|
||||
|
||||
engineBase();
|
||||
void configure();
|
||||
void addRule(const std::string &txt);
|
||||
};
|
||||
|
||||
class FuzzyHelper
|
||||
{
|
||||
friend class VCAI;
|
||||
|
||||
fl::Engine engine;
|
||||
|
||||
fl::InputVariable* bankInput;
|
||||
fl::OutputVariable* bankDanger;
|
||||
fl::RuleBlock bankBlock;
|
||||
|
||||
class TacticalAdvantage
|
||||
class TacticalAdvantage : public engineBase
|
||||
{
|
||||
public:
|
||||
fl::InputVariable * ourWalkers, * ourShooters, * ourFlyers, * enemyWalkers, * enemyShooters, * enemyFlyers;
|
||||
@ -34,11 +39,10 @@ class FuzzyHelper
|
||||
fl::InputVariable * bankPresent;
|
||||
fl::InputVariable * castleWalls;
|
||||
fl::OutputVariable * threat;
|
||||
fl::RuleBlock tacticalAdvantage;
|
||||
~TacticalAdvantage();
|
||||
} ta;
|
||||
|
||||
class EvalVisitTile
|
||||
class EvalVisitTile : public engineBase
|
||||
{
|
||||
public:
|
||||
fl::InputVariable * strengthRatio;
|
||||
@ -55,7 +59,6 @@ public:
|
||||
//blocks should be initialized in this order, which may be confusing :/
|
||||
|
||||
FuzzyHelper();
|
||||
void initBank();
|
||||
void initTacticalAdvantage();
|
||||
void initVisitTile();
|
||||
|
||||
|
@ -369,6 +369,9 @@ TSubgoal GetObj::whatToDoToAchieve()
|
||||
const CGObjectInstance * obj = cb->getObj(ObjectInstanceID(objid));
|
||||
if(!obj)
|
||||
return sptr (Goals::Explore());
|
||||
if (obj->tempOwner == ai->playerID) //we can't capture our own object -> move to Win codition
|
||||
throw cannotFulfillGoalException("Cannot capture my own object " + obj->getObjectName());
|
||||
|
||||
int3 pos = obj->visitablePos();
|
||||
if (hero)
|
||||
{
|
||||
@ -377,8 +380,11 @@ TSubgoal GetObj::whatToDoToAchieve()
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ai->isAccessible(obj->pos))
|
||||
return sptr (Goals::VisitTile(pos).sethero(hero)); //we must visit object with same hero, if any
|
||||
for (auto h : cb->getHeroesInfo())
|
||||
{
|
||||
if (ai->isAccessibleForHero(pos, h))
|
||||
return sptr(Goals::VisitTile(pos).sethero(h)); //we must visit object with same hero, if any
|
||||
}
|
||||
}
|
||||
return sptr (Goals::ClearWayTo(pos).sethero(hero));
|
||||
}
|
||||
@ -709,7 +715,12 @@ TGoalVec VisitTile::getAllPossibleSubgoals()
|
||||
{
|
||||
auto obj = frontOrNull(cb->getVisitableObjs(tile));
|
||||
if (obj && obj->ID == Obj::HERO && obj->tempOwner == ai->playerID) //our own hero stands on that tile
|
||||
ret.push_back (sptr(Goals::VisitTile(tile).sethero(dynamic_cast<const CGHeroInstance *>(obj)).setisElementar(true)));
|
||||
{
|
||||
if (hero.get(true) && hero->id == obj->id) //if it's assigned hero, visit tile. If it's different hero, we can't visit tile now
|
||||
ret.push_back(sptr(Goals::VisitTile(tile).sethero(dynamic_cast<const CGHeroInstance *>(obj)).setisElementar(true)));
|
||||
else
|
||||
throw cannotFulfillGoalException("Tile is already occupied by another hero "); //FIXME: we should give up this tile earlier
|
||||
}
|
||||
else
|
||||
ret.push_back (sptr(Goals::ClearWayTo(tile)));
|
||||
}
|
||||
|
@ -598,7 +598,7 @@ void VCAI::showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *do
|
||||
});
|
||||
}
|
||||
|
||||
void VCAI::saveGame(COSer<CSaveFile> &h, const int version)
|
||||
void VCAI::saveGame(COSer & h, const int version)
|
||||
{
|
||||
LOG_TRACE_PARAMS(logAi, "version '%i'", version);
|
||||
NET_EVENT_HANDLER;
|
||||
@ -609,7 +609,7 @@ void VCAI::saveGame(COSer<CSaveFile> &h, const int version)
|
||||
serializeInternal(h, version);
|
||||
}
|
||||
|
||||
void VCAI::loadGame(CISer<CLoadFile> &h, const int version)
|
||||
void VCAI::loadGame(CISer & h, const int version)
|
||||
{
|
||||
LOG_TRACE_PARAMS(logAi, "version '%i'", version);
|
||||
NET_EVENT_HANDLER;
|
||||
|
@ -190,8 +190,8 @@ public:
|
||||
virtual void commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, QueryID queryID) override; //TODO
|
||||
virtual void showBlockingDialog(const std::string &text, const std::vector<Component> &components, QueryID askID, const int soundID, bool selection, bool cancel) override; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID.
|
||||
virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, QueryID queryID) override; //all stacks operations between these objects become allowed, interface has to call onEnd when done
|
||||
virtual void saveGame(COSer<CSaveFile> &h, const int version) override; //saving
|
||||
virtual void loadGame(CISer<CLoadFile> &h, const int version) override; //loading
|
||||
virtual void saveGame(COSer & h, const int version) override; //saving
|
||||
virtual void loadGame(CISer & h, const int version) override; //loading
|
||||
virtual void finish() override;
|
||||
|
||||
virtual void availableCreaturesChanged(const CGDwelling *town) override;
|
||||
|
@ -1278,13 +1278,13 @@ template <typename Handler> void CPlayerInterface::serializeTempl( Handler &h, c
|
||||
h & spellbookSettings;
|
||||
}
|
||||
|
||||
void CPlayerInterface::saveGame( COSer<CSaveFile> &h, const int version )
|
||||
void CPlayerInterface::saveGame( COSer & h, const int version )
|
||||
{
|
||||
EVENT_HANDLER_CALLED_BY_CLIENT;
|
||||
serializeTempl(h,version);
|
||||
}
|
||||
|
||||
void CPlayerInterface::loadGame( CISer<CLoadFile> &h, const int version )
|
||||
void CPlayerInterface::loadGame( CISer & h, const int version )
|
||||
{
|
||||
EVENT_HANDLER_CALLED_BY_CLIENT;
|
||||
serializeTempl(h,version);
|
||||
|
@ -193,8 +193,8 @@ public:
|
||||
void gameOver(PlayerColor player, const EVictoryLossCheckResult & victoryLossCheckResult) override;
|
||||
void playerStartsTurn(PlayerColor player) override; //called before yourTurn on active itnerface
|
||||
void showComp(const Component &comp, std::string message) override; //display component in the advmapint infobox
|
||||
void saveGame(COSer<CSaveFile> &h, const int version) override; //saving
|
||||
void loadGame(CISer<CLoadFile> &h, const int version) override; //loading
|
||||
void saveGame(COSer & h, const int version) override; //saving
|
||||
void loadGame(CISer & h, const int version) override; //loading
|
||||
|
||||
//for battles
|
||||
void actionFinished(const BattleAction& action) override;//occurs AFTER action taken by active stack or by the hero
|
||||
|
@ -2171,6 +2171,10 @@ void InfoCard::changeSelection( const CMapInfo *to )
|
||||
else
|
||||
mapDescription->setText(to->mapHeader->description);
|
||||
|
||||
mapDescription->label->scrollTextTo(0);
|
||||
if (mapDescription->slider)
|
||||
mapDescription->slider->moveToMin();
|
||||
|
||||
if(SEL->screenType != CMenuScreen::newGame && SEL->screenType != CMenuScreen::campaignList) {
|
||||
//difficulty->block(true);
|
||||
difficulty->setSelected(SEL->sInfo.difficulty);
|
||||
|
@ -331,7 +331,7 @@ void CClient::loadGame(const std::string & fname, const bool server, const std::
|
||||
std::cout << x << std::endl;
|
||||
std::cout << "ENDCLIENTPLAYERS\n";
|
||||
|
||||
serialize(*loader,0,clientPlayers);
|
||||
serialize(loader->serializer,0,clientPlayers);
|
||||
*serv << ui32(clientPlayers.size());
|
||||
for(auto & elem : clientPlayers)
|
||||
*serv << ui8(elem.getNum());
|
||||
@ -493,11 +493,10 @@ void CClient::newGame( CConnection *con, StartInfo *si )
|
||||
// }
|
||||
}
|
||||
|
||||
template <typename Handler>
|
||||
void CClient::serialize( Handler &h, const int version )
|
||||
void CClient::serialize(COSer & h, const int version)
|
||||
{
|
||||
h & hotSeat;
|
||||
if(h.saving)
|
||||
assert(h.saving);
|
||||
h & hotSeat;
|
||||
{
|
||||
ui8 players = playerint.size();
|
||||
h & players;
|
||||
@ -507,11 +506,15 @@ void CClient::serialize( Handler &h, const int version )
|
||||
LOG_TRACE_PARAMS(logGlobal, "Saving player %s interface", i->first);
|
||||
assert(i->first == i->second->playerID);
|
||||
h & i->first & i->second->dllName & i->second->human;
|
||||
i->second->saveGame(dynamic_cast<COSer<CSaveFile>&>(h), version);
|
||||
//evil cast that i still like better than sfinae-magic. If I had a "static if"...
|
||||
i->second->saveGame(h, version);
|
||||
}
|
||||
}
|
||||
else
|
||||
}
|
||||
|
||||
void CClient::serialize(CISer & h, const int version)
|
||||
{
|
||||
assert(!h.saving);
|
||||
h & hotSeat;
|
||||
{
|
||||
ui8 players = 0; //fix for uninitialized warning
|
||||
h & players;
|
||||
@ -551,7 +554,7 @@ void CClient::serialize( Handler &h, const int version )
|
||||
nInt->playerID = pid;
|
||||
|
||||
installNewPlayerInterface(nInt, pid);
|
||||
nInt->loadGame(dynamic_cast<CISer<CLoadFile>&>(h), version); //another evil cast, check above
|
||||
nInt->loadGame(h, version); //another evil cast, check above
|
||||
}
|
||||
|
||||
if(!vstd::contains(battleints, PlayerColor::NEUTRAL))
|
||||
@ -559,11 +562,10 @@ void CClient::serialize( Handler &h, const int version )
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Handler>
|
||||
void CClient::serialize( Handler &h, const int version, const std::set<PlayerColor>& playerIDs)
|
||||
void CClient::serialize(COSer & h, const int version, const std::set<PlayerColor> & playerIDs)
|
||||
{
|
||||
assert(h.saving);
|
||||
h & hotSeat;
|
||||
if(h.saving)
|
||||
{
|
||||
ui8 players = playerint.size();
|
||||
h & players;
|
||||
@ -573,11 +575,15 @@ void CClient::serialize( Handler &h, const int version, const std::set<PlayerCol
|
||||
LOG_TRACE_PARAMS(logGlobal, "Saving player %s interface", i->first);
|
||||
assert(i->first == i->second->playerID);
|
||||
h & i->first & i->second->dllName & i->second->human;
|
||||
i->second->saveGame(dynamic_cast<COSer<CSaveFile>&>(h), version);
|
||||
//evil cast that i still like better than sfinae-magic. If I had a "static if"...
|
||||
i->second->saveGame(h, version);
|
||||
}
|
||||
}
|
||||
else
|
||||
}
|
||||
|
||||
void CClient::serialize(CISer & h, const int version, const std::set<PlayerColor> & playerIDs)
|
||||
{
|
||||
assert(!h.saving);
|
||||
h & hotSeat;
|
||||
{
|
||||
ui8 players = 0; //fix for uninitialized warning
|
||||
h & players;
|
||||
@ -620,7 +626,7 @@ void CClient::serialize( Handler &h, const int version, const std::set<PlayerCol
|
||||
if(playerIDs.count(pid))
|
||||
installNewPlayerInterface(nInt, pid);
|
||||
|
||||
nInt->loadGame(dynamic_cast<CISer<CLoadFile>&>(h), version); //another evil cast, check above
|
||||
nInt->loadGame(h, version);
|
||||
}
|
||||
|
||||
if(playerIDs.count(PlayerColor::NEUTRAL))
|
||||
@ -901,8 +907,6 @@ std::string CClient::aiNameForPlayer(const PlayerSettings &ps, bool battleAI)
|
||||
return goodAI;
|
||||
}
|
||||
|
||||
template void CClient::serialize( CISer<CLoadFile> &h, const int version );
|
||||
template void CClient::serialize( COSer<CSaveFile> &h, const int version );
|
||||
|
||||
void CServerHandler::startServer()
|
||||
{
|
||||
|
@ -32,6 +32,8 @@ struct SharedMem;
|
||||
class CClient;
|
||||
class CScriptingModule;
|
||||
struct CPathsInfo;
|
||||
class CISer;
|
||||
class COSer;
|
||||
namespace boost { class thread; }
|
||||
|
||||
/// structure to handle running server and connecting to it
|
||||
@ -236,7 +238,10 @@ public:
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version);
|
||||
template <typename Handler> void serialize(Handler &h, const int version, const std::set<PlayerColor>& playerIDs);
|
||||
void serialize(COSer &h, const int version);
|
||||
void serialize(CISer &h, const int version);
|
||||
|
||||
void serialize(COSer &h, const int version, const std::set<PlayerColor>& playerIDs);
|
||||
void serialize(CISer &h, const int version, const std::set<PlayerColor>& playerIDs);
|
||||
void battleFinished();
|
||||
};
|
||||
|
@ -153,6 +153,7 @@
|
||||
<AdditionalLibraryDirectories>$(FFMPEGDIR)\lib;.;..\..\libs;..</AdditionalLibraryDirectories>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalOptions>/LTCG %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
<CustomBuildStep>
|
||||
<Command>
|
||||
|
@ -479,7 +479,7 @@ void CMinimapInstance::showAll(SDL_Surface *to)
|
||||
blitAtLoc(minimap, 0, 0, to);
|
||||
|
||||
//draw heroes
|
||||
std::vector <const CGHeroInstance *> heroes = LOCPLINT->cb->getHeroesInfo(false);
|
||||
std::vector <const CGHeroInstance *> heroes = LOCPLINT->cb->getHeroesInfo(false); //TODO: do we really need separate function for drawing heroes?
|
||||
for(auto & hero : heroes)
|
||||
{
|
||||
int3 position = hero->getPosition(false);
|
||||
|
@ -744,6 +744,11 @@ void CSlider::keyPressed(const SDL_KeyboardEvent & key)
|
||||
moveTo(moveDest);
|
||||
}
|
||||
|
||||
void CSlider::moveToMin()
|
||||
{
|
||||
moveTo(0);
|
||||
}
|
||||
|
||||
void CSlider::moveToMax()
|
||||
{
|
||||
moveTo(amount);
|
||||
|
@ -230,6 +230,7 @@ public:
|
||||
void moveRight();
|
||||
void moveTo(int value);
|
||||
void moveBy(int amount);
|
||||
void moveToMin();
|
||||
void moveToMax();
|
||||
|
||||
/// Amount modifier
|
||||
|
@ -280,15 +280,20 @@ void CTextBox::resize(Point newSize)
|
||||
|
||||
void CTextBox::setText(const std::string &text)
|
||||
{
|
||||
label->pos.w = pos.w; // reset to default before textSize.y check
|
||||
label->setText(text);
|
||||
if (label->textSize.y <= label->pos.h && slider)
|
||||
if(label->textSize.y <= label->pos.h && slider)
|
||||
{
|
||||
// slider is no longer needed
|
||||
vstd::clear_pointer(slider);
|
||||
label->pos.w = pos.w;
|
||||
}
|
||||
else if(slider)
|
||||
{
|
||||
// decrease width again if slider still used
|
||||
label->pos.w = pos.w - 32;
|
||||
label->setText(text);
|
||||
}
|
||||
else if (label->textSize.y > label->pos.h && !slider)
|
||||
else if(label->textSize.y > label->pos.h)
|
||||
{
|
||||
// create slider and update widget
|
||||
label->pos.w = pos.w - 32;
|
||||
|
@ -109,7 +109,7 @@ const CGObjectInstance* CGameInfoCallback::getObj(ObjectInstanceID objid, bool v
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if(!isVisible(ret, player))
|
||||
if(!isVisible(ret, player) && ret->tempOwner != player)
|
||||
{
|
||||
if(verbose)
|
||||
logGlobal->errorStream() << "Cannot get object with id " << oid << ". Object is not visible.";
|
||||
@ -518,7 +518,8 @@ std::vector < const CGHeroInstance *> CPlayerSpecificInfoCallback::getHeroesInfo
|
||||
std::vector < const CGHeroInstance *> ret;
|
||||
for(auto hero : gs->map->heroesOnMap)
|
||||
{
|
||||
if( !player || (hero->tempOwner == *player) ||
|
||||
// !player || // - why would we even get access to hero not owned by any player?
|
||||
if((hero->tempOwner == *player) ||
|
||||
(isVisible(hero->getPosition(false), player) && !onlyOur) )
|
||||
{
|
||||
ret.push_back(hero);
|
||||
|
@ -243,7 +243,7 @@ void CAdventureAI::yourTacticPhase(int distance)
|
||||
battleAI->yourTacticPhase(distance);
|
||||
}
|
||||
|
||||
void CAdventureAI::saveGame(COSer<CSaveFile> &h, const int version) /*saving */
|
||||
void CAdventureAI::saveGame(COSer & h, const int version) /*saving */
|
||||
{
|
||||
LOG_TRACE_PARAMS(logAi, "version '%i'", version);
|
||||
CGlobalAI::saveGame(h, version);
|
||||
@ -256,7 +256,7 @@ void CAdventureAI::saveGame(COSer<CSaveFile> &h, const int version) /*saving */
|
||||
}
|
||||
}
|
||||
|
||||
void CAdventureAI::loadGame(CISer<CLoadFile> &h, const int version) /*loading */
|
||||
void CAdventureAI::loadGame(CISer & h, const int version) /*loading */
|
||||
{
|
||||
LOG_TRACE_PARAMS(logAi, "version '%i'", version);
|
||||
CGlobalAI::loadGame(h, version);
|
||||
@ -273,10 +273,10 @@ void CAdventureAI::loadGame(CISer<CLoadFile> &h, const int version) /*loading */
|
||||
}
|
||||
}
|
||||
|
||||
void CBattleGameInterface::saveGame(COSer<CSaveFile> &h, const int version)
|
||||
void CBattleGameInterface::saveGame(COSer & h, const int version)
|
||||
{
|
||||
}
|
||||
|
||||
void CBattleGameInterface::loadGame(CISer<CLoadFile> &h, const int version)
|
||||
void CBattleGameInterface::loadGame(CISer & h, const int version)
|
||||
{
|
||||
}
|
||||
|
@ -50,8 +50,8 @@ class CPathsInfo;
|
||||
class CCreature;
|
||||
class CLoadFile;
|
||||
class CSaveFile;
|
||||
template <typename Serializer> class CISer;
|
||||
template <typename Serializer> class COSer;
|
||||
class CISer;
|
||||
class COSer;
|
||||
struct ArtifactLocation;
|
||||
class CScriptingModule;
|
||||
|
||||
@ -69,8 +69,8 @@ public:
|
||||
virtual BattleAction activeStack(const CStack * stack)=0; //called when it's turn of that stack
|
||||
virtual void yourTacticPhase(int distance){}; //called when interface has opportunity to use Tactics skill -> use cb->battleMakeTacticAction from this function
|
||||
|
||||
virtual void saveGame(COSer<CSaveFile> &h, const int version);
|
||||
virtual void loadGame(CISer<CLoadFile> &h, const int version);
|
||||
virtual void saveGame(COSer &h, const int version);
|
||||
virtual void loadGame(CISer &h, const int version);
|
||||
|
||||
};
|
||||
|
||||
@ -142,6 +142,6 @@ public:
|
||||
virtual void battleEnd(const BattleResult *br);
|
||||
virtual void battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks, bool lifeDrain, bool tentHeal, si32 lifeDrainFrom);
|
||||
|
||||
virtual void saveGame(COSer<CSaveFile> &h, const int version); //saving
|
||||
virtual void loadGame(CISer<CLoadFile> &h, const int version); //loading
|
||||
virtual void saveGame(COSer & h, const int version); //saving
|
||||
virtual void loadGame(CISer & h, const int version); //loading
|
||||
};
|
||||
|
@ -878,7 +878,7 @@ void CGameState::initDuel()
|
||||
else
|
||||
{
|
||||
CLoadFile lf(scenarioOps->mapname);
|
||||
lf >> dp;
|
||||
lf.serializer >> dp;
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
@ -2240,6 +2240,10 @@ bool CGameState::isVisible( const CGObjectInstance *obj, boost::optional<PlayerC
|
||||
if(!player)
|
||||
return true;
|
||||
|
||||
//we should always see our own heroes - but sometimes not visible heroes cause crash :?
|
||||
if (player == obj->tempOwner)
|
||||
return true;
|
||||
|
||||
if(*player == PlayerColor::NEUTRAL) //-> TODO ??? needed?
|
||||
return false;
|
||||
//object is visible when at least one blocked tile is visible
|
||||
|
@ -18,14 +18,9 @@
|
||||
using namespace boost;
|
||||
using namespace boost::asio::ip;
|
||||
|
||||
extern template void registerTypes<CISer<CConnection> >(CISer<CConnection>& s);
|
||||
extern template void registerTypes<COSer<CConnection> >(COSer<CConnection>& s);
|
||||
extern template void registerTypes<CISer<CMemorySerializer> >(CISer<CMemorySerializer>& s);
|
||||
extern template void registerTypes<COSer<CMemorySerializer> >(COSer<CMemorySerializer>& s);
|
||||
extern template void registerTypes<CSaveFile>(CSaveFile & s);
|
||||
extern template void registerTypes<CLoadFile>(CLoadFile & s);
|
||||
extern template void registerTypes<CISer>(CISer & s);
|
||||
extern template void registerTypes<COSer>(COSer & s);
|
||||
extern template void registerTypes<CTypeList>(CTypeList & s);
|
||||
extern template void registerTypes<CLoadIntegrityValidator>(CLoadIntegrityValidator & s);
|
||||
|
||||
CTypeList typeList;
|
||||
|
||||
@ -50,8 +45,8 @@ void CConnection::init()
|
||||
|
||||
enableSmartPointerSerializatoin();
|
||||
disableStackSendingByID();
|
||||
registerTypes(static_cast<CISer<CConnection>&>(*this));
|
||||
registerTypes(static_cast<COSer<CConnection>&>(*this));
|
||||
registerTypes(iser);
|
||||
registerTypes(oser);
|
||||
#ifdef LIL_ENDIAN
|
||||
myEndianess = true;
|
||||
#else
|
||||
@ -60,8 +55,8 @@ void CConnection::init()
|
||||
connected = true;
|
||||
std::string pom;
|
||||
//we got connection
|
||||
(*this) << std::string("Aiya!\n") << name << myEndianess; //identify ourselves
|
||||
(*this) >> pom >> pom >> contactEndianess;
|
||||
oser << std::string("Aiya!\n") << name << myEndianess; //identify ourselves
|
||||
iser >> pom >> pom >> contactEndianess;
|
||||
logNetwork->infoStream() << "Established connection with "<<pom;
|
||||
wmx = new boost::mutex;
|
||||
rmx = new boost::mutex;
|
||||
@ -73,7 +68,7 @@ void CConnection::init()
|
||||
}
|
||||
|
||||
CConnection::CConnection(std::string host, std::string port, std::string Name)
|
||||
:io_service(new asio::io_service), name(Name)
|
||||
:iser(this), oser(this), io_service(new asio::io_service), name(Name)
|
||||
{
|
||||
int i;
|
||||
boost::system::error_code error = asio::error::host_not_found;
|
||||
@ -128,12 +123,12 @@ connerror1:
|
||||
throw std::runtime_error("Can't establish connection :(");
|
||||
}
|
||||
CConnection::CConnection(TSocket * Socket, std::string Name )
|
||||
:socket(Socket),io_service(&Socket->get_io_service()), name(Name)//, send(this), rec(this)
|
||||
:iser(this), oser(this), socket(Socket),io_service(&Socket->get_io_service()), name(Name)//, send(this), rec(this)
|
||||
{
|
||||
init();
|
||||
}
|
||||
CConnection::CConnection(TAcceptor * acceptor, boost::asio::io_service *Io_service, std::string Name)
|
||||
: name(Name)//, send(this), rec(this)
|
||||
: iser(this), oser(this), name(Name)//, send(this), rec(this)
|
||||
{
|
||||
boost::system::error_code error = asio::error::host_not_found;
|
||||
socket = new tcp::socket(*io_service);
|
||||
@ -229,7 +224,7 @@ CPack * CConnection::retreivePack()
|
||||
CPack *ret = nullptr;
|
||||
boost::unique_lock<boost::mutex> lock(*rmx);
|
||||
logNetwork->traceStream() << "Listening... ";
|
||||
*this >> ret;
|
||||
iser >> ret;
|
||||
logNetwork->traceStream() << "\treceived server message of type " << typeid(*ret).name() << ", data: " << ret;
|
||||
return ret;
|
||||
}
|
||||
@ -238,37 +233,33 @@ void CConnection::sendPackToServer(const CPack &pack, PlayerColor player, ui32 r
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(*wmx);
|
||||
logNetwork->traceStream() << "Sending to server a pack of type " << typeid(pack).name();
|
||||
*this << player << requestID << &pack; //packs has to be sent as polymorphic pointers!
|
||||
oser << player << requestID << &pack; //packs has to be sent as polymorphic pointers!
|
||||
}
|
||||
|
||||
void CConnection::disableStackSendingByID()
|
||||
{
|
||||
CISer<CConnection>::sendStackInstanceByIds = false;
|
||||
COSer<CConnection>::sendStackInstanceByIds = false;
|
||||
CSerializer::sendStackInstanceByIds = false;
|
||||
}
|
||||
|
||||
void CConnection::enableStackSendingByID()
|
||||
{
|
||||
CISer<CConnection>::sendStackInstanceByIds = true;
|
||||
COSer<CConnection>::sendStackInstanceByIds = true;
|
||||
CSerializer::sendStackInstanceByIds = true;
|
||||
}
|
||||
|
||||
void CConnection::disableSmartPointerSerialization()
|
||||
{
|
||||
CISer<CConnection>::smartPointerSerialization = false;
|
||||
COSer<CConnection>::smartPointerSerialization = false;
|
||||
iser.smartPointerSerialization = oser.smartPointerSerialization = false;
|
||||
}
|
||||
|
||||
void CConnection::enableSmartPointerSerializatoin()
|
||||
{
|
||||
CISer<CConnection>::smartPointerSerialization = true;
|
||||
COSer<CConnection>::smartPointerSerialization = true;
|
||||
iser.smartPointerSerialization = oser.smartPointerSerialization = true;
|
||||
}
|
||||
|
||||
void CConnection::prepareForSendingHeroes()
|
||||
{
|
||||
loadedPointers.clear();
|
||||
savedPointers.clear();
|
||||
iser.loadedPointers.clear();
|
||||
oser.savedPointers.clear();
|
||||
disableSmartVectorMemberSerialization();
|
||||
enableSmartPointerSerializatoin();
|
||||
disableStackSendingByID();
|
||||
@ -276,25 +267,25 @@ void CConnection::prepareForSendingHeroes()
|
||||
|
||||
void CConnection::enterPregameConnectionMode()
|
||||
{
|
||||
loadedPointers.clear();
|
||||
savedPointers.clear();
|
||||
iser.loadedPointers.clear();
|
||||
oser.savedPointers.clear();
|
||||
disableSmartVectorMemberSerialization();
|
||||
disableSmartPointerSerialization();
|
||||
}
|
||||
|
||||
void CConnection::disableSmartVectorMemberSerialization()
|
||||
{
|
||||
smartVectorMembersSerialization = false;
|
||||
CSerializer::smartVectorMembersSerialization = false;
|
||||
}
|
||||
|
||||
void CConnection::enableSmartVectorMemberSerializatoin()
|
||||
{
|
||||
smartVectorMembersSerialization = true;
|
||||
CSerializer::smartVectorMembersSerialization = true;
|
||||
}
|
||||
|
||||
CSaveFile::CSaveFile( const std::string &fname )
|
||||
CSaveFile::CSaveFile( const std::string &fname ): serializer(this)
|
||||
{
|
||||
registerTypes(*this);
|
||||
registerTypes(serializer);
|
||||
openNextFile(fname);
|
||||
}
|
||||
|
||||
@ -320,7 +311,7 @@ void CSaveFile::openNextFile(const std::string &fname)
|
||||
THROW_FORMAT("Error: cannot open to write %s!", fname);
|
||||
|
||||
sfile->write("VCMI",4); //write magic identifier
|
||||
*this << version; //write format version
|
||||
serializer << version; //write format version
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
@ -350,9 +341,9 @@ void CSaveFile::putMagicBytes( const std::string &text )
|
||||
write(text.c_str(), text.length());
|
||||
}
|
||||
|
||||
CLoadFile::CLoadFile(const boost::filesystem::path & fname, int minimalVersion /*= version*/)
|
||||
CLoadFile::CLoadFile(const boost::filesystem::path & fname, int minimalVersion /*= version*/): serializer(this)
|
||||
{
|
||||
registerTypes(*this);
|
||||
registerTypes(serializer);
|
||||
openNextFile(fname, minimalVersion);
|
||||
}
|
||||
|
||||
@ -368,7 +359,7 @@ int CLoadFile::read(void * data, unsigned size)
|
||||
|
||||
void CLoadFile::openNextFile(const boost::filesystem::path & fname, int minimalVersion)
|
||||
{
|
||||
assert(!reverseEndianess);
|
||||
assert(!serializer.reverseEndianess);
|
||||
assert(minimalVersion <= version);
|
||||
|
||||
try
|
||||
@ -386,22 +377,22 @@ void CLoadFile::openNextFile(const boost::filesystem::path & fname, int minimalV
|
||||
if(std::memcmp(buffer,"VCMI",4))
|
||||
THROW_FORMAT("Error: not a VCMI file(%s)!", fName);
|
||||
|
||||
*this >> fileVersion;
|
||||
if(fileVersion < minimalVersion)
|
||||
serializer >> serializer.fileVersion;
|
||||
if(serializer.fileVersion < minimalVersion)
|
||||
THROW_FORMAT("Error: too old file format (%s)!", fName);
|
||||
|
||||
if(fileVersion > version)
|
||||
if(serializer.fileVersion > version)
|
||||
{
|
||||
logGlobal->warnStream() << boost::format("Warning format version mismatch: found %d when current is %d! (file %s)\n") % fileVersion % version % fName;
|
||||
logGlobal->warnStream() << boost::format("Warning format version mismatch: found %d when current is %d! (file %s)\n") % serializer.fileVersion % version % fName;
|
||||
|
||||
auto versionptr = (char*)&fileVersion;
|
||||
auto versionptr = (char*)&serializer.fileVersion;
|
||||
std::reverse(versionptr, versionptr + 4);
|
||||
logGlobal->warnStream() << "Version number reversed is " << fileVersion << ", checking...";
|
||||
logGlobal->warnStream() << "Version number reversed is " << serializer.fileVersion << ", checking...";
|
||||
|
||||
if(fileVersion == version)
|
||||
if(serializer.fileVersion == version)
|
||||
{
|
||||
logGlobal->warnStream() << fname << " seems to have different endianness! Entering reversing mode.";
|
||||
reverseEndianess = true;
|
||||
serializer.reverseEndianess = true;
|
||||
}
|
||||
else
|
||||
THROW_FORMAT("Error: too new file format (%s)!", fName);
|
||||
@ -427,7 +418,7 @@ void CLoadFile::clear()
|
||||
{
|
||||
sfile = nullptr;
|
||||
fName.clear();
|
||||
fileVersion = 0;
|
||||
serializer.fileVersion = 0;
|
||||
}
|
||||
|
||||
void CLoadFile::checkMagicBytes( const std::string &text )
|
||||
@ -579,14 +570,14 @@ void CSerializer::addStdVecItems(CGameState *gs, LibClasses *lib)
|
||||
}
|
||||
|
||||
CLoadIntegrityValidator::CLoadIntegrityValidator( const std::string &primaryFileName, const std::string &controlFileName, int minimalVersion /*= version*/ )
|
||||
: foundDesync(false)
|
||||
: serializer(this), foundDesync(false)
|
||||
{
|
||||
registerTypes(*this);
|
||||
registerTypes(serializer);
|
||||
primaryFile = make_unique<CLoadFile>(primaryFileName, minimalVersion);
|
||||
controlFile = make_unique<CLoadFile>(controlFileName, minimalVersion);
|
||||
|
||||
assert(primaryFile->fileVersion == controlFile->fileVersion);
|
||||
fileVersion = primaryFile->fileVersion;
|
||||
assert(primaryFile->serializer.fileVersion == controlFile->serializer.fileVersion);
|
||||
serializer.fileVersion = primaryFile->serializer.fileVersion;
|
||||
}
|
||||
|
||||
int CLoadIntegrityValidator::read( void * data, unsigned size )
|
||||
@ -615,8 +606,8 @@ int CLoadIntegrityValidator::read( void * data, unsigned size )
|
||||
|
||||
unique_ptr<CLoadFile> CLoadIntegrityValidator::decay()
|
||||
{
|
||||
primaryFile->loadedPointers = this->loadedPointers;
|
||||
primaryFile->loadedPointersTypes = this->loadedPointersTypes;
|
||||
primaryFile->serializer.loadedPointers = this->serializer.loadedPointers;
|
||||
primaryFile->serializer.loadedPointersTypes = this->serializer.loadedPointersTypes;
|
||||
return std::move(primaryFile);
|
||||
}
|
||||
|
||||
@ -647,10 +638,10 @@ int CMemorySerializer::write(const void * data, unsigned size)
|
||||
return size;
|
||||
}
|
||||
|
||||
CMemorySerializer::CMemorySerializer()
|
||||
CMemorySerializer::CMemorySerializer(): iser(this), oser(this)
|
||||
{
|
||||
readPos = 0;
|
||||
registerTypes(static_cast<CISer<CMemorySerializer>&>(*this));
|
||||
registerTypes(static_cast<COSer<CMemorySerializer>&>(*this));
|
||||
registerTypes(iser);
|
||||
registerTypes(oser);
|
||||
}
|
||||
|
||||
|
564
lib/Connection.h
564
lib/Connection.h
@ -30,6 +30,8 @@
|
||||
const ui32 version = 751;
|
||||
const ui32 minSupportedVersion = version;
|
||||
|
||||
class CISer;
|
||||
class COSer;
|
||||
class CConnection;
|
||||
class CGObjectInstance;
|
||||
class CStackInstance;
|
||||
@ -266,140 +268,6 @@ public:
|
||||
|
||||
extern DLL_LINKAGE CTypeList typeList;
|
||||
|
||||
|
||||
template<typename Ser>
|
||||
struct SaveBoolean
|
||||
{
|
||||
static void invoke(Ser &s, const bool &data)
|
||||
{
|
||||
s.saveBoolean(data);
|
||||
}
|
||||
};
|
||||
template<typename Ser>
|
||||
struct LoadBoolean
|
||||
{
|
||||
static void invoke(Ser &s, bool &data)
|
||||
{
|
||||
s.loadBoolean(data);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ser>
|
||||
struct SaveBooleanVector
|
||||
{
|
||||
static void invoke(Ser &s, const std::vector<bool> &data)
|
||||
{
|
||||
s.saveBooleanVector(data);
|
||||
}
|
||||
};
|
||||
template<typename Ser>
|
||||
struct LoadBooleanVector
|
||||
{
|
||||
static void invoke(Ser &s, std::vector<bool> &data)
|
||||
{
|
||||
s.loadBooleanVector(data);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ser,typename T>
|
||||
struct SavePrimitive
|
||||
{
|
||||
static void invoke(Ser &s, const T &data)
|
||||
{
|
||||
s.savePrimitive(data);
|
||||
}
|
||||
};
|
||||
template<typename Ser,typename T>
|
||||
struct SaveSerializable
|
||||
{
|
||||
static void invoke(Ser &s, const T &data)
|
||||
{
|
||||
s.saveSerializable(data);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ser,typename T>
|
||||
struct SaveEnum
|
||||
{
|
||||
static void invoke(Ser &s, const T &data)
|
||||
{
|
||||
s.saveEnum(data);
|
||||
}
|
||||
};
|
||||
template<typename Ser,typename T>
|
||||
struct LoadEnum
|
||||
{
|
||||
static void invoke(Ser &s, T &data)
|
||||
{
|
||||
s.loadEnum(data);
|
||||
}
|
||||
};
|
||||
template<typename Ser,typename T>
|
||||
struct LoadPrimitive
|
||||
{
|
||||
static void invoke(Ser &s, T &data)
|
||||
{
|
||||
s.loadPrimitive(data);
|
||||
}
|
||||
};
|
||||
template<typename Ser,typename T>
|
||||
struct SavePointer
|
||||
{
|
||||
static void invoke(Ser &s, const T &data)
|
||||
{
|
||||
s.savePointer(data);
|
||||
}
|
||||
};
|
||||
template<typename Ser,typename T>
|
||||
struct LoadPointer
|
||||
{
|
||||
static void invoke(Ser &s, T &data)
|
||||
{
|
||||
s.loadPointer(data);
|
||||
}
|
||||
};
|
||||
template<typename Ser,typename T>
|
||||
struct SaveArray
|
||||
{
|
||||
static void invoke(Ser &s, const T &data)
|
||||
{
|
||||
s.saveArray(data);
|
||||
}
|
||||
};
|
||||
template<typename Ser,typename T>
|
||||
struct LoadArray
|
||||
{
|
||||
static void invoke(Ser &s, T &data)
|
||||
{
|
||||
s.loadArray(data);
|
||||
}
|
||||
};
|
||||
template<typename Ser,typename T>
|
||||
struct LoadSerializable
|
||||
{
|
||||
static void invoke(Ser &s, T &data)
|
||||
{
|
||||
s.loadSerializable(data);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ser,typename T>
|
||||
struct SaveWrong
|
||||
{
|
||||
static void invoke(Ser &s, const T &data)
|
||||
{
|
||||
throw std::runtime_error("Wrong save serialization call!");
|
||||
}
|
||||
};
|
||||
template<typename Ser,typename T>
|
||||
struct LoadWrong
|
||||
{
|
||||
static void invoke(Ser &s, const T &data)
|
||||
{
|
||||
throw std::runtime_error("Wrong load serialization call!");
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Variant, typename Source>
|
||||
struct VariantLoaderHelper
|
||||
{
|
||||
@ -570,8 +438,23 @@ public:
|
||||
void addStdVecItems(CGameState *gs, LibClasses *lib = VLC);
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CSaverBase : public virtual CSerializer
|
||||
class IBinaryWriter : public virtual CSerializer
|
||||
{
|
||||
public:
|
||||
virtual int write(const void * data, unsigned size) = 0;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CSaverBase
|
||||
{
|
||||
protected:
|
||||
IBinaryWriter * writer;
|
||||
public:
|
||||
CSaverBase(IBinaryWriter * w): writer(w){};
|
||||
|
||||
inline int write(const void * data, unsigned size)
|
||||
{
|
||||
return writer->write(data, size);
|
||||
};
|
||||
};
|
||||
|
||||
class CBasicPointerSaver
|
||||
@ -581,19 +464,6 @@ public:
|
||||
virtual ~CBasicPointerSaver(){}
|
||||
};
|
||||
|
||||
template <typename Serializer, typename T> class CPointerSaver : public CBasicPointerSaver
|
||||
{
|
||||
public:
|
||||
void savePtr(CSaverBase &ar, const void *data) const
|
||||
{
|
||||
Serializer &s = static_cast<Serializer&>(ar);
|
||||
const T *ptr = static_cast<const T*>(data);
|
||||
|
||||
//T is most derived known type, it's time to call actual serialize
|
||||
const_cast<T&>(*ptr).serialize(s,version);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> //metafunction returning CGObjectInstance if T is its derivate or T elsewise
|
||||
struct VectorisedTypeFor
|
||||
{
|
||||
@ -658,6 +528,7 @@ struct SaveIfStackInstance
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ser>
|
||||
struct SaveIfStackInstance<Ser, CStackInstance *>
|
||||
{
|
||||
@ -676,6 +547,7 @@ struct SaveIfStackInstance<Ser, CStackInstance *>
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ser,typename T>
|
||||
struct LoadIfStackInstance
|
||||
{
|
||||
@ -711,16 +583,101 @@ struct LoadIfStackInstance<Ser, CStackInstance *>
|
||||
|
||||
|
||||
/// The class which manages saving objects.
|
||||
template <typename Serializer> class DLL_LINKAGE COSer : public CSaverBase
|
||||
class DLL_LINKAGE COSer : public CSaverBase
|
||||
{
|
||||
public:
|
||||
|
||||
struct SaveBoolean
|
||||
{
|
||||
static void invoke(COSer &s, const bool &data)
|
||||
{
|
||||
s.saveBoolean(data);
|
||||
}
|
||||
};
|
||||
|
||||
struct SaveBooleanVector
|
||||
{
|
||||
static void invoke(COSer &s, const std::vector<bool> &data)
|
||||
{
|
||||
s.saveBooleanVector(data);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct SavePrimitive
|
||||
{
|
||||
static void invoke(COSer &s, const T &data)
|
||||
{
|
||||
s.savePrimitive(data);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct SaveSerializable
|
||||
{
|
||||
static void invoke(COSer &s, const T &data)
|
||||
{
|
||||
s.saveSerializable(data);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct SaveEnum
|
||||
{
|
||||
static void invoke(COSer &s, const T &data)
|
||||
{
|
||||
s.saveEnum(data);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct SavePointer
|
||||
{
|
||||
static void invoke(COSer &s, const T &data)
|
||||
{
|
||||
s.savePointer(data);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct SaveArray
|
||||
{
|
||||
static void invoke(COSer &s, const T &data)
|
||||
{
|
||||
s.saveArray(data);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct SaveWrong
|
||||
{
|
||||
static void invoke(COSer &s, const T &data)
|
||||
{
|
||||
throw std::runtime_error("Wrong save serialization call!");
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class CPointerSaver : public CBasicPointerSaver
|
||||
{
|
||||
public:
|
||||
void savePtr(CSaverBase &ar, const void *data) const override
|
||||
{
|
||||
COSer &s = static_cast<COSer&>(ar);
|
||||
const T *ptr = static_cast<const T*>(data);
|
||||
|
||||
//T is most derived known type, it's time to call actual serialize
|
||||
const_cast<T&>(*ptr).serialize(s,version);
|
||||
}
|
||||
};
|
||||
|
||||
bool saving;
|
||||
std::map<ui16,CBasicPointerSaver*> savers; // typeID => CPointerSaver<serializer,type>
|
||||
|
||||
std::map<const void*, ui32> savedPointers;
|
||||
bool smartPointerSerialization;
|
||||
|
||||
COSer()
|
||||
COSer(IBinaryWriter * w): CSaverBase(w)
|
||||
{
|
||||
saving=true;
|
||||
smartPointerSerialization = true;
|
||||
@ -738,7 +695,7 @@ public:
|
||||
{
|
||||
auto ID = typeList.getTypeID(t);
|
||||
if(!savers.count(ID))
|
||||
savers[ID] = new CPointerSaver<COSer<Serializer>, T>;
|
||||
savers[ID] = new CPointerSaver<T>;
|
||||
}
|
||||
|
||||
template<typename Base, typename Derived> void registerType(const Base * b = nullptr, const Derived * d = nullptr)
|
||||
@ -748,31 +705,23 @@ public:
|
||||
addSaver(d);
|
||||
}
|
||||
|
||||
Serializer * This()
|
||||
{
|
||||
return static_cast<Serializer*>(this);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Serializer & operator<<(const T &t)
|
||||
COSer & operator<<(const T &t)
|
||||
{
|
||||
this->This()->save(t);
|
||||
return * this->This();
|
||||
this->save(t);
|
||||
return * this;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
COSer & operator&(const T & t)
|
||||
{
|
||||
return * this->This() << t;
|
||||
return * this << t;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int write(const void * data, unsigned size);
|
||||
template <typename T>
|
||||
void savePrimitive(const T &data)
|
||||
{
|
||||
this->This()->write(&data,sizeof(data));
|
||||
this->write(&data,sizeof(data));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -786,23 +735,23 @@ public:
|
||||
if(!hlp)
|
||||
return;
|
||||
|
||||
if(smartVectorMembersSerialization)
|
||||
if(writer->smartVectorMembersSerialization)
|
||||
{
|
||||
typedef typename boost::remove_const<typename boost::remove_pointer<T>::type>::type TObjectType;
|
||||
typedef typename VectorisedTypeFor<TObjectType>::type VType;
|
||||
typedef typename VectorizedIDType<TObjectType>::type IDType;
|
||||
if(const auto *info = getVectorisedTypeInfo<VType, IDType>())
|
||||
if(const auto *info = writer->getVectorisedTypeInfo<VType, IDType>())
|
||||
{
|
||||
IDType id = getIdFromVectorItem<VType>(*info, data);
|
||||
IDType id = writer->getIdFromVectorItem<VType>(*info, data);
|
||||
*this << id;
|
||||
if(id != IDType(-1)) //vector id is enough
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(sendStackInstanceByIds)
|
||||
if(writer->sendStackInstanceByIds)
|
||||
{
|
||||
const bool gotSaved = SaveIfStackInstance<Serializer,T>::invoke(*This(), data);
|
||||
const bool gotSaved = SaveIfStackInstance<COSer,T>::invoke(*this, data);
|
||||
if(gotSaved)
|
||||
return;
|
||||
}
|
||||
@ -830,7 +779,7 @@ public:
|
||||
ui16 tid = typeList.getTypeID(data);
|
||||
*this << tid;
|
||||
|
||||
This()->savePointerHlp(tid, data);
|
||||
this->savePointerHlp(tid, data);
|
||||
}
|
||||
|
||||
//that part of ptr serialization was extracted to allow customization of its behavior in derived classes
|
||||
@ -856,27 +805,27 @@ public:
|
||||
typedef
|
||||
//if
|
||||
typename mpl::eval_if< mpl::equal_to<SerializationLevel<T>,mpl::int_<Boolean> >,
|
||||
mpl::identity<SaveBoolean<Serializer> >,
|
||||
mpl::identity<SaveBoolean>,
|
||||
//else if
|
||||
typename mpl::eval_if< mpl::equal_to<SerializationLevel<T>,mpl::int_<BooleanVector> >,
|
||||
mpl::identity<SaveBooleanVector<Serializer> >,
|
||||
mpl::identity<SaveBooleanVector>,
|
||||
//else if
|
||||
typename mpl::eval_if< mpl::equal_to<SerializationLevel<T>,mpl::int_<Primitive> >,
|
||||
mpl::identity<SavePrimitive<Serializer,T> >,
|
||||
mpl::identity<SavePrimitive<T> >,
|
||||
//else if
|
||||
typename mpl::eval_if<mpl::equal_to<SerializationLevel<T>,mpl::int_<Enum> >,
|
||||
mpl::identity<SaveEnum<Serializer,T> >,
|
||||
mpl::identity<SaveEnum<T> >,
|
||||
//else if
|
||||
typename mpl::eval_if<mpl::equal_to<SerializationLevel<T>,mpl::int_<Pointer> >,
|
||||
mpl::identity<SavePointer<Serializer,T> >,
|
||||
mpl::identity<SavePointer<T> >,
|
||||
//else if
|
||||
typename mpl::eval_if<mpl::equal_to<SerializationLevel<T>,mpl::int_<Array> >,
|
||||
mpl::identity<SaveArray<Serializer,T> >,
|
||||
mpl::identity<SaveArray<T> >,
|
||||
//else if
|
||||
typename mpl::eval_if<mpl::equal_to<SerializationLevel<T>,mpl::int_<Serializable> >,
|
||||
mpl::identity<SaveSerializable<Serializer,T> >,
|
||||
mpl::identity<SaveSerializable<T> >,
|
||||
//else
|
||||
mpl::identity<SaveWrong<Serializer,T> >
|
||||
mpl::identity<SaveWrong<T> >
|
||||
>
|
||||
>
|
||||
>
|
||||
@ -884,7 +833,7 @@ public:
|
||||
>
|
||||
>
|
||||
>::type typex;
|
||||
typex::invoke(* this->This(), data);
|
||||
typex::invoke(* this, data);
|
||||
}
|
||||
template <typename T>
|
||||
void saveSerializable(const T &data)
|
||||
@ -947,7 +896,7 @@ public:
|
||||
void saveSerializable(const std::string &data)
|
||||
{
|
||||
*this << ui32(data.length());
|
||||
this->This()->write(data.c_str(),data.size());
|
||||
this->write(data.c_str(),data.size());
|
||||
}
|
||||
template <typename T1, typename T2>
|
||||
void saveSerializable(const std::pair<T1,T2> &data)
|
||||
@ -974,7 +923,7 @@ public:
|
||||
si32 which = data.which();
|
||||
*this << which;
|
||||
|
||||
VariantVisitorSaver<Serializer> visitor(*this->This());
|
||||
VariantVisitorSaver<COSer> visitor(*this);
|
||||
boost::apply_visitor(visitor, data);
|
||||
}
|
||||
template <typename T>
|
||||
@ -1009,10 +958,24 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class IBinaryReader : public virtual CSerializer
|
||||
{
|
||||
public:
|
||||
virtual int read(void * data, unsigned size) = 0;
|
||||
};
|
||||
|
||||
|
||||
class DLL_LINKAGE CLoaderBase : public virtual CSerializer
|
||||
{};
|
||||
class DLL_LINKAGE CLoaderBase
|
||||
{
|
||||
protected:
|
||||
IBinaryReader * reader;
|
||||
public:
|
||||
CLoaderBase(IBinaryReader * r): reader(r){};
|
||||
|
||||
inline int read(void * data, unsigned size)
|
||||
{
|
||||
return reader->read(data, size);
|
||||
};
|
||||
};
|
||||
|
||||
class CBasicPointerLoader
|
||||
{
|
||||
@ -1040,28 +1003,99 @@ struct ClassObjectCreator<T, typename std::enable_if<std::is_abstract<T>::value>
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Serializer, typename T> class CPointerLoader : public CBasicPointerLoader
|
||||
{
|
||||
public:
|
||||
const std::type_info * loadPtr(CLoaderBase &ar, void *data, ui32 pid) const //data is pointer to the ACTUAL POINTER
|
||||
{
|
||||
Serializer &s = static_cast<Serializer&>(ar);
|
||||
T *&ptr = *static_cast<T**>(data);
|
||||
|
||||
//create new object under pointer
|
||||
typedef typename boost::remove_pointer<T>::type npT;
|
||||
ptr = ClassObjectCreator<npT>::invoke(); //does new npT or throws for abstract classes
|
||||
s.ptrAllocated(ptr, pid);
|
||||
//T is most derived known type, it's time to call actual serialize
|
||||
ptr->serialize(s,version);
|
||||
return &typeid(T);
|
||||
}
|
||||
};
|
||||
|
||||
/// The class which manages loading of objects.
|
||||
template <typename Serializer> class DLL_LINKAGE CISer : public CLoaderBase
|
||||
class DLL_LINKAGE CISer : public CLoaderBase
|
||||
{
|
||||
public:
|
||||
struct LoadBoolean
|
||||
{
|
||||
static void invoke(CISer &s, bool &data)
|
||||
{
|
||||
s.loadBoolean(data);
|
||||
}
|
||||
};
|
||||
|
||||
struct LoadBooleanVector
|
||||
{
|
||||
static void invoke(CISer &s, std::vector<bool> &data)
|
||||
{
|
||||
s.loadBooleanVector(data);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct LoadEnum
|
||||
{
|
||||
static void invoke(CISer &s, T &data)
|
||||
{
|
||||
s.loadEnum(data);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct LoadPrimitive
|
||||
{
|
||||
static void invoke(CISer &s, T &data)
|
||||
{
|
||||
s.loadPrimitive(data);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct LoadPointer
|
||||
{
|
||||
static void invoke(CISer &s, T &data)
|
||||
{
|
||||
s.loadPointer(data);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct LoadArray
|
||||
{
|
||||
static void invoke(CISer &s, T &data)
|
||||
{
|
||||
s.loadArray(data);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct LoadSerializable
|
||||
{
|
||||
static void invoke(CISer &s, T &data)
|
||||
{
|
||||
s.loadSerializable(data);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct LoadWrong
|
||||
{
|
||||
static void invoke(CISer &s, const T &data)
|
||||
{
|
||||
throw std::runtime_error("Wrong load serialization call!");
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> class CPointerLoader : public CBasicPointerLoader
|
||||
{
|
||||
public:
|
||||
const std::type_info * loadPtr(CLoaderBase &ar, void *data, ui32 pid) const override //data is pointer to the ACTUAL POINTER
|
||||
{
|
||||
CISer &s = static_cast<CISer&>(ar);
|
||||
T *&ptr = *static_cast<T**>(data);
|
||||
|
||||
//create new object under pointer
|
||||
typedef typename boost::remove_pointer<T>::type npT;
|
||||
ptr = ClassObjectCreator<npT>::invoke(); //does new npT or throws for abstract classes
|
||||
s.ptrAllocated(ptr, pid);
|
||||
//T is most derived known type, it's time to call actual serialize
|
||||
ptr->serialize(s,version);
|
||||
return &typeid(T);
|
||||
}
|
||||
};
|
||||
|
||||
bool saving;
|
||||
std::map<ui16,CBasicPointerLoader*> loaders; // typeID => CPointerSaver<serializer,type>
|
||||
si32 fileVersion;
|
||||
@ -1073,7 +1107,7 @@ public:
|
||||
|
||||
bool smartPointerSerialization;
|
||||
|
||||
CISer()
|
||||
CISer(IBinaryReader * r): CLoaderBase(r)
|
||||
{
|
||||
saving = false;
|
||||
fileVersion = 0;
|
||||
@ -1094,7 +1128,7 @@ public:
|
||||
{
|
||||
auto ID = typeList.getTypeID(t);
|
||||
if(!loaders.count(ID))
|
||||
loaders[ID] = new CPointerLoader<CISer<Serializer>, T>;
|
||||
loaders[ID] = new CPointerLoader<T>;
|
||||
}
|
||||
|
||||
template<typename Base, typename Derived> void registerType(const Base * b = nullptr, const Derived * d = nullptr)
|
||||
@ -1104,22 +1138,17 @@ public:
|
||||
addLoader(d);
|
||||
}
|
||||
|
||||
Serializer * This()
|
||||
{
|
||||
return static_cast<Serializer*>(this);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Serializer & operator>>(T &t)
|
||||
CISer & operator>>(T &t)
|
||||
{
|
||||
this->This()->load(t);
|
||||
return * this->This();
|
||||
this->load(t);
|
||||
return * this;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
CISer & operator&(T & t)
|
||||
{
|
||||
return * this->This() >> t;
|
||||
return * this >> t;
|
||||
}
|
||||
|
||||
int write(const void * data, unsigned size);
|
||||
@ -1129,27 +1158,27 @@ public:
|
||||
typedef
|
||||
//if
|
||||
typename mpl::eval_if< mpl::equal_to<SerializationLevel<T>,mpl::int_<Boolean> >,
|
||||
mpl::identity<LoadBoolean<Serializer> >,
|
||||
mpl::identity<LoadBoolean>,
|
||||
//else if
|
||||
typename mpl::eval_if< mpl::equal_to<SerializationLevel<T>,mpl::int_<BooleanVector> >,
|
||||
mpl::identity<LoadBooleanVector<Serializer> >,
|
||||
mpl::identity<LoadBooleanVector>,
|
||||
//else if
|
||||
typename mpl::eval_if< mpl::equal_to<SerializationLevel<T>,mpl::int_<Primitive> >,
|
||||
mpl::identity<LoadPrimitive<Serializer,T> >,
|
||||
mpl::identity<LoadPrimitive<T> >,
|
||||
//else if
|
||||
typename mpl::eval_if<mpl::equal_to<SerializationLevel<T>,mpl::int_<Enum> >,
|
||||
mpl::identity<LoadEnum<Serializer,T> >,
|
||||
mpl::identity<LoadEnum<T> >,
|
||||
//else if
|
||||
typename mpl::eval_if<mpl::equal_to<SerializationLevel<T>,mpl::int_<Pointer> >,
|
||||
mpl::identity<LoadPointer<Serializer,T> >,
|
||||
mpl::identity<LoadPointer<T> >,
|
||||
//else if
|
||||
typename mpl::eval_if<mpl::equal_to<SerializationLevel<T>,mpl::int_<Array> >,
|
||||
mpl::identity<LoadArray<Serializer,T> >,
|
||||
mpl::identity<LoadArray<T> >,
|
||||
//else if
|
||||
typename mpl::eval_if<mpl::equal_to<SerializationLevel<T>,mpl::int_<Serializable> >,
|
||||
mpl::identity<LoadSerializable<Serializer,T> >,
|
||||
mpl::identity<LoadSerializable<T> >,
|
||||
//else
|
||||
mpl::identity<LoadWrong<Serializer,T> >
|
||||
mpl::identity<LoadWrong<T> >
|
||||
>
|
||||
>
|
||||
>
|
||||
@ -1157,20 +1186,20 @@ public:
|
||||
>
|
||||
>
|
||||
>::type typex;
|
||||
typex::invoke(* this->This(), data);
|
||||
typex::invoke(* this, data);
|
||||
}
|
||||
template <typename T>
|
||||
void loadPrimitive(T &data)
|
||||
{
|
||||
if(0) //for testing #989
|
||||
{
|
||||
this->This()->read(&data,sizeof(data));
|
||||
this->read(&data,sizeof(data));
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned length = sizeof(data);
|
||||
char* dataPtr = (char*)&data;
|
||||
this->This()->read(dataPtr,length);
|
||||
this->read(dataPtr,length);
|
||||
if(reverseEndianess)
|
||||
std::reverse(dataPtr, dataPtr + length);
|
||||
}
|
||||
@ -1209,26 +1238,26 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
if(smartVectorMembersSerialization)
|
||||
if(reader->smartVectorMembersSerialization)
|
||||
{
|
||||
typedef typename boost::remove_const<typename boost::remove_pointer<T>::type>::type TObjectType; //eg: const CGHeroInstance * => CGHeroInstance
|
||||
typedef typename VectorisedTypeFor<TObjectType>::type VType; //eg: CGHeroInstance -> CGobjectInstance
|
||||
typedef typename VectorizedIDType<TObjectType>::type IDType;
|
||||
if(const auto *info = getVectorisedTypeInfo<VType, IDType>())
|
||||
if(const auto *info = reader->getVectorisedTypeInfo<VType, IDType>())
|
||||
{
|
||||
IDType id;
|
||||
*this >> id;
|
||||
if(id != IDType(-1))
|
||||
{
|
||||
data = static_cast<T>(getVectorItemFromId<VType, IDType>(*info, id));
|
||||
data = static_cast<T>(reader->getVectorItemFromId<VType, IDType>(*info, id));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(sendStackInstanceByIds)
|
||||
if(reader->sendStackInstanceByIds)
|
||||
{
|
||||
bool gotLoaded = LoadIfStackInstance<Serializer,T>::invoke(*This(), data);
|
||||
bool gotLoaded = LoadIfStackInstance<CISer,T>::invoke(* this, data);
|
||||
if(gotLoaded)
|
||||
return;
|
||||
}
|
||||
@ -1252,7 +1281,7 @@ public:
|
||||
//get type id
|
||||
ui16 tid;
|
||||
*this >> tid;
|
||||
This()->loadPointerHlp(tid, data, pid);
|
||||
this->loadPointerHlp(tid, data, pid);
|
||||
}
|
||||
|
||||
//that part of ptr deserialization was extracted to allow customization of its behavior in derived classes
|
||||
@ -1290,7 +1319,7 @@ public:
|
||||
if(length > 500000) \
|
||||
{ \
|
||||
logGlobal->warnStream() << "Warning: very big length: " << length;\
|
||||
reportState(logGlobal); \
|
||||
reader->reportState(logGlobal); \
|
||||
};
|
||||
|
||||
|
||||
@ -1437,7 +1466,7 @@ public:
|
||||
{
|
||||
READ_CHECK_U32(length);
|
||||
data.resize(length);
|
||||
this->This()->read((void*)data.c_str(),length);
|
||||
this->read((void*)data.c_str(),length);
|
||||
}
|
||||
|
||||
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
|
||||
@ -1506,52 +1535,71 @@ public:
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CSaveFile
|
||||
: public COSer<CSaveFile>
|
||||
:public IBinaryWriter
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
COSer serializer;
|
||||
|
||||
std::string fName;
|
||||
unique_ptr<std::ofstream> sfile;
|
||||
|
||||
CSaveFile(const std::string &fname); //throws!
|
||||
~CSaveFile();
|
||||
int write(const void * data, unsigned size);
|
||||
int write(const void * data, unsigned size) override;
|
||||
|
||||
void openNextFile(const std::string &fname); //throws!
|
||||
void clear();
|
||||
void reportState(CLogger * out);
|
||||
|
||||
void putMagicBytes(const std::string &text);
|
||||
|
||||
template<class T>
|
||||
CSaveFile & operator<<(const T &t)
|
||||
{
|
||||
serializer << t;
|
||||
return * this;
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CLoadFile
|
||||
: public CISer<CLoadFile>
|
||||
: public IBinaryReader
|
||||
{
|
||||
|
||||
public:
|
||||
CISer serializer;
|
||||
|
||||
std::string fName;
|
||||
unique_ptr<boost::filesystem::ifstream> sfile;
|
||||
|
||||
CLoadFile(const boost::filesystem::path & fname, int minimalVersion = version); //throws!
|
||||
~CLoadFile();
|
||||
int read(void * data, unsigned size); //throws!
|
||||
int read(void * data, unsigned size) override; //throws!
|
||||
|
||||
void openNextFile(const boost::filesystem::path & fname, int minimalVersion); //throws!
|
||||
void clear();
|
||||
void reportState(CLogger * out);
|
||||
|
||||
void checkMagicBytes(const std::string & text);
|
||||
|
||||
template<class T>
|
||||
CLoadFile & operator>>(T &t)
|
||||
{
|
||||
serializer >> t;
|
||||
return * this;
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CLoadIntegrityValidator : public CISer<CLoadIntegrityValidator>
|
||||
class DLL_LINKAGE CLoadIntegrityValidator
|
||||
: public IBinaryReader
|
||||
{
|
||||
public:
|
||||
CISer serializer;
|
||||
unique_ptr<CLoadFile> primaryFile, controlFile;
|
||||
bool foundDesync;
|
||||
|
||||
CLoadIntegrityValidator(const std::string &primaryFileName, const std::string &controlFileName, int minimalVersion = version); //throws!
|
||||
|
||||
int read( void * data, unsigned size); //throws!
|
||||
int read( void * data, unsigned size) override; //throws!
|
||||
void checkMagicBytes(const std::string &text);
|
||||
|
||||
unique_ptr<CLoadFile> decay(); //returns primary file. CLoadIntegrityValidator stops being usable anymore
|
||||
@ -1561,7 +1609,7 @@ typedef boost::asio::basic_stream_socket < boost::asio::ip::tcp , boost::asio::s
|
||||
typedef boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::socket_acceptor_service<boost::asio::ip::tcp> > TAcceptor;
|
||||
|
||||
class DLL_LINKAGE CConnection
|
||||
: public CISer<CConnection>, public COSer<CConnection>
|
||||
: public IBinaryReader, public IBinaryWriter
|
||||
{
|
||||
//CGameState *gs;
|
||||
CConnection(void);
|
||||
@ -1569,6 +1617,9 @@ class DLL_LINKAGE CConnection
|
||||
void init();
|
||||
void reportState(CLogger * out);
|
||||
public:
|
||||
CISer iser;
|
||||
COSer oser;
|
||||
|
||||
boost::mutex *rmx, *wmx; // read/write mutexes
|
||||
TSocket * socket;
|
||||
bool logging;
|
||||
@ -1586,8 +1637,8 @@ public:
|
||||
CConnection(TAcceptor * acceptor, boost::asio::io_service *Io_service, std::string Name);
|
||||
CConnection(TSocket * Socket, std::string Name); //use immediately after accepting connection into socket
|
||||
|
||||
int write(const void * data, unsigned size);
|
||||
int read(void * data, unsigned size);
|
||||
int write(const void * data, unsigned size) override;
|
||||
int read(void * data, unsigned size) override;
|
||||
void close();
|
||||
bool isOpen() const;
|
||||
template<class T>
|
||||
@ -1606,6 +1657,20 @@ public:
|
||||
|
||||
void prepareForSendingHeroes(); //disables sending vectorised, enables smart pointer serialization, clears saved/loaded ptr cache
|
||||
void enterPregameConnectionMode();
|
||||
|
||||
template<class T>
|
||||
CConnection & operator>>(T &t)
|
||||
{
|
||||
iser >> t;
|
||||
return * this;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
CConnection & operator<<(const T &t)
|
||||
{
|
||||
oser << t;
|
||||
return * this;
|
||||
}
|
||||
};
|
||||
|
||||
DLL_LINKAGE std::ostream &operator<<(std::ostream &str, const CConnection &cpc);
|
||||
@ -1613,14 +1678,17 @@ DLL_LINKAGE std::ostream &operator<<(std::ostream &str, const CConnection &cpc);
|
||||
|
||||
// Serializer that stores objects in the dynamic buffer. Allows performing deep object copies.
|
||||
class DLL_LINKAGE CMemorySerializer
|
||||
: public CISer<CMemorySerializer>, public COSer<CMemorySerializer>
|
||||
: public IBinaryReader, public IBinaryWriter
|
||||
{
|
||||
std::vector<ui8> buffer;
|
||||
|
||||
size_t readPos; //index of the next byte to be read
|
||||
public:
|
||||
int read(void * data, unsigned size); //throws!
|
||||
int write(const void * data, unsigned size);
|
||||
CISer iser;
|
||||
COSer oser;
|
||||
|
||||
int read(void * data, unsigned size) override; //throws!
|
||||
int write(const void * data, unsigned size) override;
|
||||
|
||||
CMemorySerializer();
|
||||
|
||||
@ -1628,10 +1696,10 @@ public:
|
||||
static unique_ptr<T> deepCopy(const T &data)
|
||||
{
|
||||
CMemorySerializer mem;
|
||||
mem << &data;
|
||||
mem.oser << &data;
|
||||
|
||||
unique_ptr<T> ret;
|
||||
mem >> ret;
|
||||
mem.iser >> ret;
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
@ -149,16 +149,16 @@ void CPrivilagedInfoCallback::loadCommonState(Loader &in)
|
||||
StartInfo *si;
|
||||
|
||||
logGlobal->infoStream() <<"\tReading header";
|
||||
in >> dum;
|
||||
in.serializer >> dum;
|
||||
|
||||
logGlobal->infoStream() << "\tReading options";
|
||||
in >> si;
|
||||
in.serializer >> si;
|
||||
|
||||
logGlobal->infoStream() <<"\tReading handlers";
|
||||
in >> *VLC;
|
||||
in.serializer >> *VLC;
|
||||
|
||||
logGlobal->infoStream() <<"\tReading gamestate";
|
||||
in >> gs;
|
||||
in.serializer >> gs;
|
||||
}
|
||||
|
||||
template<typename Saver>
|
||||
@ -167,13 +167,13 @@ void CPrivilagedInfoCallback::saveCommonState(Saver &out) const
|
||||
logGlobal->infoStream() << "Saving lib part of game...";
|
||||
out.putMagicBytes(SAVEGAME_MAGIC);
|
||||
logGlobal->infoStream() <<"\tSaving header";
|
||||
out << static_cast<CMapHeader&>(*gs->map);
|
||||
out.serializer << static_cast<CMapHeader&>(*gs->map);
|
||||
logGlobal->infoStream() << "\tSaving options";
|
||||
out << gs->scenarioOps;
|
||||
out.serializer << gs->scenarioOps;
|
||||
logGlobal->infoStream() << "\tSaving handlers";
|
||||
out << *VLC;
|
||||
out.serializer << *VLC;
|
||||
logGlobal->infoStream() << "\tSaving gamestate";
|
||||
out << gs;
|
||||
out.serializer << gs;
|
||||
}
|
||||
|
||||
// hardly memory usage for `-gdwarf-4` flag
|
||||
|
@ -147,6 +147,7 @@
|
||||
<LinkTimeCodeGeneration>
|
||||
</LinkTimeCodeGeneration>
|
||||
<AdditionalLibraryDirectories>..\..\libs</AdditionalLibraryDirectories>
|
||||
<AdditionalOptions>/LTCG %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='RD|x64'">
|
||||
|
@ -370,6 +370,29 @@ IObjectInfo::CArmyStructure CBankInfo::maxGuards() const
|
||||
return *boost::range::max_element(armies);
|
||||
}
|
||||
|
||||
TPossibleGuards CBankInfo::getPossibleGuards() const
|
||||
{
|
||||
TPossibleGuards out;
|
||||
|
||||
for (const JsonNode & configEntry : config)
|
||||
{
|
||||
const JsonNode & guardsInfo = configEntry["guards"];
|
||||
auto stacks = JsonRandom::evaluateCreatures(configEntry["guards"]);
|
||||
IObjectInfo::CArmyStructure army;
|
||||
|
||||
|
||||
for (auto stack : stacks)
|
||||
{
|
||||
army.totalStrength += stack.allowedCreatures.front()->AIValue * (stack.minAmount + stack.maxAmount) / 2;
|
||||
//TODO: add fields for flyers, walkers etc...
|
||||
}
|
||||
|
||||
ui8 chance = configEntry["chance"].Float();
|
||||
out.push_back(std::make_pair(chance, army));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
bool CBankInfo::givesResources() const
|
||||
{
|
||||
for (const JsonNode & node : config)
|
||||
|
@ -152,14 +152,20 @@ struct BankConfig
|
||||
}
|
||||
};
|
||||
|
||||
class CBankInfo : public IObjectInfo
|
||||
typedef std::vector<std::pair<ui8, IObjectInfo::CArmyStructure>> TPossibleGuards;
|
||||
|
||||
class DLL_LINKAGE CBankInfo : public IObjectInfo
|
||||
{
|
||||
JsonVector config;
|
||||
public:
|
||||
CBankInfo(JsonVector config);
|
||||
|
||||
TPossibleGuards getPossibleGuards() const;
|
||||
|
||||
//I have no idea what do these functions do or were supposed to do - War
|
||||
CArmyStructure minGuards() const;
|
||||
CArmyStructure maxGuards() const;
|
||||
|
||||
bool givesResources() const;
|
||||
bool givesArtifacts() const;
|
||||
bool givesCreatures() const;
|
||||
|
@ -1445,7 +1445,8 @@ void CGShipyard::onHeroVisit( const CGHeroInstance * h ) const
|
||||
|
||||
void CCartographer::onHeroVisit( const CGHeroInstance * h ) const
|
||||
{
|
||||
if (!wasVisited (h->getOwner()) ) //if hero has not visited yet this cartographer
|
||||
//if player has not bought map of this subtype yet and underground exist for stalagmite cartographer
|
||||
if (!wasVisited(h->getOwner()) && (subID != 2 || cb->gameState()->map->twoLevel))
|
||||
{
|
||||
if (cb->getResource(h->tempOwner, Res::GOLD) >= 1000) //if he can afford a map
|
||||
{
|
||||
|
@ -27,15 +27,11 @@
|
||||
// registerTypesServerPacks: 1.3 Gb
|
||||
// registerTypes4: 1.3 Gb
|
||||
|
||||
|
||||
#define DEFINE_EXTERNAL_METHOD(METHODNAME) \
|
||||
extern template DLL_LINKAGE void METHODNAME<CISer<CConnection>>(CISer<CConnection>& s); \
|
||||
extern template DLL_LINKAGE void METHODNAME<COSer<CConnection>>(COSer<CConnection>& s); \
|
||||
extern template DLL_LINKAGE void METHODNAME<CISer<CMemorySerializer>>(CISer<CMemorySerializer>& s); \
|
||||
extern template DLL_LINKAGE void METHODNAME<COSer<CMemorySerializer>>(COSer<CMemorySerializer>& s); \
|
||||
extern template DLL_LINKAGE void METHODNAME<CSaveFile>(CSaveFile & s); \
|
||||
extern template DLL_LINKAGE void METHODNAME<CLoadFile>(CLoadFile & s); \
|
||||
extern template DLL_LINKAGE void METHODNAME<CISer>(CISer & s); \
|
||||
extern template DLL_LINKAGE void METHODNAME<COSer>(COSer & s); \
|
||||
extern template DLL_LINKAGE void METHODNAME<CTypeList>(CTypeList & s); \
|
||||
extern template DLL_LINKAGE void METHODNAME<CLoadIntegrityValidator>(CLoadIntegrityValidator & s);
|
||||
|
||||
//DEFINE_EXTERNAL_METHOD(registerTypesMapObjects)
|
||||
DEFINE_EXTERNAL_METHOD(registerTypesMapObjects1)
|
||||
@ -45,11 +41,6 @@ DEFINE_EXTERNAL_METHOD(registerTypesClientPacks2)
|
||||
DEFINE_EXTERNAL_METHOD(registerTypesServerPacks)
|
||||
DEFINE_EXTERNAL_METHOD(registerTypesPregamePacks)
|
||||
|
||||
template void registerTypes<CISer<CConnection>>(CISer<CConnection>& s);
|
||||
template void registerTypes<COSer<CConnection>>(COSer<CConnection>& s);
|
||||
template void registerTypes<CISer<CMemorySerializer>>(CISer<CMemorySerializer>& s);
|
||||
template void registerTypes<COSer<CMemorySerializer>>(COSer<CMemorySerializer>& s);
|
||||
template void registerTypes<CSaveFile>(CSaveFile & s);
|
||||
template void registerTypes<CLoadFile>(CLoadFile & s);
|
||||
template void registerTypes<CISer>(CISer & s);
|
||||
template void registerTypes<COSer>(COSer & s);
|
||||
template void registerTypes<CTypeList>(CTypeList & s);
|
||||
template void registerTypes<CLoadIntegrityValidator>(CLoadIntegrityValidator & s);
|
||||
|
@ -367,13 +367,10 @@ void registerTypes(Serializer &s)
|
||||
}
|
||||
|
||||
#ifndef INSTANTIATE_REGISTER_TYPES_HERE
|
||||
extern template DLL_LINKAGE void registerTypes<CISer<CConnection>>(CISer<CConnection>& s);
|
||||
extern template DLL_LINKAGE void registerTypes<COSer<CConnection>>(COSer<CConnection>& s);
|
||||
extern template DLL_LINKAGE void registerTypes<CSaveFile>(CSaveFile & s);
|
||||
extern template DLL_LINKAGE void registerTypes<CLoadFile>(CLoadFile & s);
|
||||
|
||||
extern template DLL_LINKAGE void registerTypes<CISer>(CISer & s);
|
||||
extern template DLL_LINKAGE void registerTypes<COSer>(COSer & s);
|
||||
extern template DLL_LINKAGE void registerTypes<CTypeList>(CTypeList & s);
|
||||
extern template DLL_LINKAGE void registerTypes<CLoadIntegrityValidator>(CLoadIntegrityValidator & s);
|
||||
extern template DLL_LINKAGE void registerTypes<CISer<CMemorySerializer>>(CISer<CMemorySerializer> & s);
|
||||
extern template DLL_LINKAGE void registerTypes<COSer<CMemorySerializer>>(COSer<CMemorySerializer> & s);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -19,11 +19,6 @@
|
||||
#include "../mapObjects/CObjectClassesHandler.h"
|
||||
|
||||
|
||||
template void registerTypesClientPacks1<CISer<CConnection>>(CISer<CConnection>& s);
|
||||
template void registerTypesClientPacks1<COSer<CConnection>>(COSer<CConnection>& s);
|
||||
template void registerTypesClientPacks1<CISer<CMemorySerializer>>(CISer<CMemorySerializer>& s);
|
||||
template void registerTypesClientPacks1<COSer<CMemorySerializer>>(COSer<CMemorySerializer>& s);
|
||||
template void registerTypesClientPacks1<CSaveFile>(CSaveFile & s);
|
||||
template void registerTypesClientPacks1<CLoadFile>(CLoadFile & s);
|
||||
template void registerTypesClientPacks1<CISer>(CISer & s);
|
||||
template void registerTypesClientPacks1<COSer>(COSer & s);
|
||||
template void registerTypesClientPacks1<CTypeList>(CTypeList & s);
|
||||
template void registerTypesClientPacks1<CLoadIntegrityValidator>(CLoadIntegrityValidator & s);
|
||||
|
@ -19,11 +19,8 @@
|
||||
#include "../mapObjects/CObjectClassesHandler.h"
|
||||
|
||||
|
||||
template void registerTypesClientPacks2<CISer<CConnection>>(CISer<CConnection>& s);
|
||||
template void registerTypesClientPacks2<COSer<CConnection>>(COSer<CConnection>& s);
|
||||
template void registerTypesClientPacks2<CISer<CMemorySerializer>>(CISer<CMemorySerializer>& s);
|
||||
template void registerTypesClientPacks2<COSer<CMemorySerializer>>(COSer<CMemorySerializer>& s);
|
||||
template void registerTypesClientPacks2<CSaveFile>(CSaveFile & s);
|
||||
template void registerTypesClientPacks2<CLoadFile>(CLoadFile & s);
|
||||
template void registerTypesClientPacks2<CISer>(CISer & s);
|
||||
template void registerTypesClientPacks2<COSer>(COSer & s);
|
||||
template void registerTypesClientPacks2<CTypeList>(CTypeList & s);
|
||||
template void registerTypesClientPacks2<CLoadIntegrityValidator>(CLoadIntegrityValidator & s);
|
||||
|
||||
|
||||
|
@ -18,12 +18,8 @@
|
||||
#include "../NetPacks.h"
|
||||
#include "../mapObjects/CObjectClassesHandler.h"
|
||||
|
||||
template void registerTypesMapObjects1<CISer<CConnection>>(CISer<CConnection>& s);
|
||||
template void registerTypesMapObjects1<COSer<CConnection>>(COSer<CConnection>& s);
|
||||
template void registerTypesMapObjects1<CISer<CMemorySerializer>>(CISer<CMemorySerializer>& s);
|
||||
template void registerTypesMapObjects1<COSer<CMemorySerializer>>(COSer<CMemorySerializer>& s);
|
||||
template void registerTypesMapObjects1<CSaveFile>(CSaveFile & s);
|
||||
template void registerTypesMapObjects1<CLoadFile>(CLoadFile & s);
|
||||
template void registerTypesMapObjects1<CISer>(CISer & s);
|
||||
template void registerTypesMapObjects1<COSer>(COSer & s);
|
||||
template void registerTypesMapObjects1<CTypeList>(CTypeList & s);
|
||||
template void registerTypesMapObjects1<CLoadIntegrityValidator>(CLoadIntegrityValidator & s);
|
||||
|
||||
|
||||
|
@ -19,12 +19,7 @@
|
||||
#include "../mapObjects/CObjectClassesHandler.h"
|
||||
|
||||
|
||||
template void registerTypesMapObjects2<CISer<CConnection>>(CISer<CConnection>& s);
|
||||
template void registerTypesMapObjects2<COSer<CConnection>>(COSer<CConnection>& s);
|
||||
template void registerTypesMapObjects2<CISer<CMemorySerializer>>(CISer<CMemorySerializer>& s);
|
||||
template void registerTypesMapObjects2<COSer<CMemorySerializer>>(COSer<CMemorySerializer>& s);
|
||||
template void registerTypesMapObjects2<CSaveFile>(CSaveFile & s);
|
||||
template void registerTypesMapObjects2<CLoadFile>(CLoadFile & s);
|
||||
template void registerTypesMapObjects2<CISer>(CISer & s);
|
||||
template void registerTypesMapObjects2<COSer>(COSer & s);
|
||||
template void registerTypesMapObjects2<CTypeList>(CTypeList & s);
|
||||
template void registerTypesMapObjects2<CLoadIntegrityValidator>(CLoadIntegrityValidator & s);
|
||||
|
||||
|
@ -18,11 +18,6 @@
|
||||
#include "../NetPacks.h"
|
||||
#include "../mapObjects/CObjectClassesHandler.h"
|
||||
|
||||
template void registerTypesMapObjectTypes<CISer<CConnection>>(CISer<CConnection>& s);
|
||||
template void registerTypesMapObjectTypes<COSer<CConnection>>(COSer<CConnection>& s);
|
||||
template void registerTypesMapObjectTypes<CISer<CMemorySerializer>>(CISer<CMemorySerializer>& s);
|
||||
template void registerTypesMapObjectTypes<COSer<CMemorySerializer>>(COSer<CMemorySerializer>& s);
|
||||
template void registerTypesMapObjectTypes<CSaveFile>(CSaveFile & s);
|
||||
template void registerTypesMapObjectTypes<CLoadFile>(CLoadFile & s);
|
||||
template void registerTypesMapObjectTypes<CISer>(CISer & s);
|
||||
template void registerTypesMapObjectTypes<COSer>(COSer & s);
|
||||
template void registerTypesMapObjectTypes<CTypeList>(CTypeList & s);
|
||||
template void registerTypesMapObjectTypes<CLoadIntegrityValidator>(CLoadIntegrityValidator & s);
|
||||
|
@ -18,11 +18,7 @@
|
||||
#include "../NetPacks.h"
|
||||
#include "../mapObjects/CObjectClassesHandler.h"
|
||||
|
||||
template void registerTypesPregamePacks<CISer<CConnection>>(CISer<CConnection>& s);
|
||||
template void registerTypesPregamePacks<COSer<CConnection>>(COSer<CConnection>& s);
|
||||
template void registerTypesPregamePacks<CISer<CMemorySerializer>>(CISer<CMemorySerializer>& s);
|
||||
template void registerTypesPregamePacks<COSer<CMemorySerializer>>(COSer<CMemorySerializer>& s);
|
||||
template void registerTypesPregamePacks<CSaveFile>(CSaveFile & s);
|
||||
template void registerTypesPregamePacks<CLoadFile>(CLoadFile & s);
|
||||
template void registerTypesPregamePacks<CISer>(CISer & s);
|
||||
template void registerTypesPregamePacks<COSer>(COSer & s);
|
||||
template void registerTypesPregamePacks<CTypeList>(CTypeList & s);
|
||||
template void registerTypesPregamePacks<CLoadIntegrityValidator>(CLoadIntegrityValidator & s);
|
||||
|
||||
|
@ -18,11 +18,6 @@
|
||||
#include "../NetPacks.h"
|
||||
#include "../mapObjects/CObjectClassesHandler.h"
|
||||
|
||||
template void registerTypesServerPacks<CISer<CConnection>>(CISer<CConnection>& s);
|
||||
template void registerTypesServerPacks<COSer<CConnection>>(COSer<CConnection>& s);
|
||||
template void registerTypesServerPacks<CISer<CMemorySerializer>>(CISer<CMemorySerializer>& s);
|
||||
template void registerTypesServerPacks<COSer<CMemorySerializer>>(COSer<CMemorySerializer>& s);
|
||||
template void registerTypesServerPacks<CSaveFile>(CSaveFile & s);
|
||||
template void registerTypesServerPacks<CLoadFile>(CLoadFile & s);
|
||||
template void registerTypesServerPacks<CISer>(CISer & s);
|
||||
template void registerTypesServerPacks<COSer>(COSer & s);
|
||||
template void registerTypesServerPacks<CTypeList>(CTypeList & s);
|
||||
template void registerTypesServerPacks<CLoadIntegrityValidator>(CLoadIntegrityValidator & s);
|
||||
|
@ -74,7 +74,7 @@ void CMapGenerator::initPrisonsRemaining()
|
||||
if (isAllowed)
|
||||
prisonsRemaining++;
|
||||
}
|
||||
prisonsRemaining = std::max<int> (0, prisonsRemaining - 16 * map->players.size()); //so at least 16 heroes will be available for every player
|
||||
prisonsRemaining = std::max<int> (0, prisonsRemaining - 16 * mapGenOptions->getPlayerCount()); //so at least 16 heroes will be available for every player
|
||||
}
|
||||
|
||||
std::unique_ptr<CMap> CMapGenerator::generate(CMapGenOptions * mapGenOptions, int randomSeed /*= std::time(nullptr)*/)
|
||||
|
@ -133,7 +133,6 @@ void CJsonRmgTemplateLoader::loadTemplates()
|
||||
//treasures
|
||||
if (!zoneNode["treasure"].isNull())
|
||||
{
|
||||
int totalDensity = 0;
|
||||
//TODO: parse vector of different treasure settings
|
||||
if (zoneNode["treasure"].getType() == JsonNode::DATA_STRUCT)
|
||||
{
|
||||
@ -143,8 +142,6 @@ void CJsonRmgTemplateLoader::loadTemplates()
|
||||
ti.min = treasureInfo["min"].Float();
|
||||
ti.max = treasureInfo["max"].Float();
|
||||
ti.density = treasureInfo["density"].Float(); //TODO: use me
|
||||
totalDensity += ti.density;
|
||||
ti.threshold = totalDensity;
|
||||
zone->addTreasureInfo(ti);
|
||||
}
|
||||
}
|
||||
@ -156,12 +153,9 @@ void CJsonRmgTemplateLoader::loadTemplates()
|
||||
ti.min = treasureInfo["min"].Float();
|
||||
ti.max = treasureInfo["max"].Float();
|
||||
ti.density = treasureInfo["density"].Float();
|
||||
totalDensity += ti.density;
|
||||
ti.threshold = totalDensity;
|
||||
zone->addTreasureInfo(ti);
|
||||
}
|
||||
}
|
||||
zone->setTotalDensity (totalDensity);
|
||||
}
|
||||
|
||||
zones[zone->getId()] = zone;
|
||||
@ -191,7 +185,6 @@ void CJsonRmgTemplateLoader::loadTemplates()
|
||||
{
|
||||
zone->addTreasureInfo(treasureInfo);
|
||||
}
|
||||
zone->setTotalDensity (zones[zoneNode["treasureLikeZone"].Float()]->getTotalDensity());
|
||||
}
|
||||
|
||||
if (!zoneNode["minesLikeZone"].isNull())
|
||||
|
@ -138,8 +138,7 @@ CRmgTemplateZone::CRmgTemplateZone() :
|
||||
matchTerrainToTown(true),
|
||||
townType(ETownType::NEUTRAL),
|
||||
terrainType (ETerrainType::GRASS),
|
||||
zoneMonsterStrength(EMonsterStrength::ZONE_NORMAL),
|
||||
totalDensity(0)
|
||||
zoneMonsterStrength(EMonsterStrength::ZONE_NORMAL)
|
||||
{
|
||||
terrainTypes = getDefaultTerrainTypes();
|
||||
}
|
||||
@ -303,16 +302,6 @@ void CRmgTemplateZone::setMonsterStrength (EMonsterStrength::EMonsterStrength va
|
||||
zoneMonsterStrength = val;
|
||||
}
|
||||
|
||||
void CRmgTemplateZone::setTotalDensity (ui16 val)
|
||||
{
|
||||
totalDensity = val;
|
||||
}
|
||||
|
||||
ui16 CRmgTemplateZone::getTotalDensity () const
|
||||
{
|
||||
return totalDensity;
|
||||
}
|
||||
|
||||
void CRmgTemplateZone::addTreasureInfo(CTreasureInfo & info)
|
||||
{
|
||||
treasureInfo.push_back(info);
|
||||
@ -420,7 +409,11 @@ void CRmgTemplateZone::fractalize(CMapGenerator* gen)
|
||||
std::set<int3> tilesToIgnore; //will be erased in this iteration
|
||||
|
||||
//the more treasure density, the greater distance between paths. Scaling is experimental.
|
||||
int totalDensity = 0;
|
||||
for (auto ti : treasureInfo)
|
||||
totalDensity =+ ti.density;
|
||||
const float minDistance = std::sqrt(totalDensity * 3);
|
||||
|
||||
for (auto tile : tileinfo)
|
||||
{
|
||||
if (gen->isFree(tile))
|
||||
@ -612,6 +605,10 @@ void CRmgTemplateZone::addRequiredObject(CGObjectInstance * obj, si32 strength)
|
||||
{
|
||||
requiredObjects.push_back(std::make_pair(obj, strength));
|
||||
}
|
||||
void CRmgTemplateZone::addCloseObject(CGObjectInstance * obj, si32 strength)
|
||||
{
|
||||
closeObjects.push_back(std::make_pair(obj, strength));
|
||||
}
|
||||
|
||||
bool CRmgTemplateZone::addMonster(CMapGenerator* gen, int3 &pos, si32 strength, bool clearSurroundingTiles, bool zoneGuard)
|
||||
{
|
||||
@ -686,7 +683,7 @@ bool CRmgTemplateZone::addMonster(CMapGenerator* gen, int3 &pos, si32 strength,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CRmgTemplateZone::createTreasurePile (CMapGenerator* gen, int3 &pos, float minDistance)
|
||||
bool CRmgTemplateZone::createTreasurePile(CMapGenerator* gen, int3 &pos, float minDistance, const CTreasureInfo& treasureInfo)
|
||||
{
|
||||
CTreasurePileInfo info;
|
||||
|
||||
@ -695,25 +692,9 @@ bool CRmgTemplateZone::createTreasurePile (CMapGenerator* gen, int3 &pos, float
|
||||
int3 guardPos (-1,-1,-1);
|
||||
info.nextTreasurePos = pos;
|
||||
|
||||
//default values
|
||||
int maxValue = 5000;
|
||||
int minValue = 1500;
|
||||
int maxValue = treasureInfo.max;
|
||||
int minValue = treasureInfo.min;
|
||||
|
||||
if (treasureInfo.size())
|
||||
{
|
||||
//roulette wheel
|
||||
int r = gen->rand.nextInt (1, totalDensity);
|
||||
|
||||
for (auto t : treasureInfo)
|
||||
{
|
||||
if (r <= t.threshold)
|
||||
{
|
||||
maxValue = t.max;
|
||||
minValue = t.min;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ui32 desiredValue = gen->rand.nextInt(minValue, maxValue);
|
||||
//quantize value to let objects with value equal to max spawn too
|
||||
|
||||
@ -1132,11 +1113,8 @@ bool CRmgTemplateZone::placeMines (CMapGenerator* gen)
|
||||
static const Res::ERes woodOre[] = {Res::ERes::WOOD, Res::ERes::ORE};
|
||||
static const Res::ERes preciousResources[] = {Res::ERes::GEMS, Res::ERes::CRYSTAL, Res::ERes::MERCURY, Res::ERes::SULFUR};
|
||||
|
||||
|
||||
//TODO: factory / copy constructor?
|
||||
for (const auto & res : woodOre)
|
||||
{
|
||||
//TODO: these 2 should be close to town (within 12 tiles radius)
|
||||
for (int i = 0; i < mines[res]; i++)
|
||||
{
|
||||
auto mine = new CGMine();
|
||||
@ -1144,7 +1122,7 @@ bool CRmgTemplateZone::placeMines (CMapGenerator* gen)
|
||||
mine->subID = static_cast<si32>(res);
|
||||
mine->producedResource = res;
|
||||
mine->producedQuantity = mine->defaultResProduction();
|
||||
addRequiredObject(mine, 1500);
|
||||
addCloseObject(mine, 1500);
|
||||
}
|
||||
}
|
||||
for (const auto & res : preciousResources)
|
||||
@ -1189,35 +1167,91 @@ bool CRmgTemplateZone::createRequiredObjects(CMapGenerator* gen)
|
||||
guardObject (gen, obj.first, obj.second, (obj.first->ID == Obj::MONOLITH_TWO_WAY), true);
|
||||
//paths to required objects constitute main paths of zone. otherwise they just may lead to middle and create dead zones
|
||||
}
|
||||
|
||||
for (const auto &obj : closeObjects)
|
||||
{
|
||||
std::vector<int3> tiles(possibleTiles.begin(), possibleTiles.end()); //new tiles vector after each object has been placed
|
||||
|
||||
// smallest distance to zone center, greatest distance to nearest object
|
||||
auto isCloser = [this, gen](const int3 & lhs, const int3 & rhs) -> bool
|
||||
{
|
||||
return (this->pos.dist2dSQ(lhs) * 0.5f - gen->getNearestObjectDistance(lhs)) < (this->pos.dist2dSQ(rhs) * 0.5f - gen->getNearestObjectDistance(rhs));
|
||||
};
|
||||
|
||||
boost::sort (tiles, isCloser);
|
||||
|
||||
setTemplateForObject(gen, obj.first);
|
||||
auto tilesBlockedByObject = obj.first->getBlockedOffsets();
|
||||
bool result = false;
|
||||
|
||||
for (auto tile : tiles)
|
||||
{
|
||||
//object must be accessible from at least one surounding tile
|
||||
if (!isAccessibleFromAnywhere(gen, obj.first->appearance, tile, tilesBlockedByObject))
|
||||
continue;
|
||||
|
||||
//avoid borders
|
||||
if (gen->isPossible(tile))
|
||||
{
|
||||
if (areAllTilesAvailable(gen, obj.first, tile, tilesBlockedByObject))
|
||||
{
|
||||
placeObject(gen, obj.first, tile);
|
||||
guardObject(gen, obj.first, obj.second, (obj.first->ID == Obj::MONOLITH_TWO_WAY), true);
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!result)
|
||||
{
|
||||
logGlobal->errorStream() << boost::format("Failed to fill zone %d due to lack of space") % id;
|
||||
//TODO CLEANUP!
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CRmgTemplateZone::createTreasures(CMapGenerator* gen)
|
||||
{
|
||||
//treasure density is proportional to map siz,e but must be scaled bakc to map size
|
||||
//also, normalize it to zone count - higher count means relative smaller zones
|
||||
auto valueComparator = [](const CTreasureInfo & lhs, const CTreasureInfo & rhs) -> bool
|
||||
{
|
||||
return lhs.max > rhs.max;
|
||||
};
|
||||
|
||||
//this is squared distance for optimization purposes
|
||||
const double minDistance = std::max<float>((600.f * size * size * gen->getZones().size()) /
|
||||
(gen->mapGenOptions->getWidth() * gen->mapGenOptions->getHeight() * totalDensity * (gen->map->twoLevel ? 2 : 1)), 2);
|
||||
//distance lower than 2 causes objects to overlap and crash
|
||||
//place biggest treasures first at large distance, place smaller ones inbetween
|
||||
boost::sort(treasureInfo, valueComparator);
|
||||
|
||||
do {
|
||||
|
||||
//optimization - don't check tiles which are not allowed
|
||||
vstd::erase_if (possibleTiles, [gen](const int3 &tile) -> bool
|
||||
{
|
||||
return !gen->isPossible(tile);
|
||||
});
|
||||
int totalDensity = 0;
|
||||
for (auto t : treasureInfo)
|
||||
{
|
||||
totalDensity += t.density;
|
||||
|
||||
int3 pos;
|
||||
if ( ! findPlaceForTreasurePile(gen, minDistance, pos))
|
||||
{
|
||||
break;
|
||||
}
|
||||
createTreasurePile (gen, pos, minDistance);
|
||||
//treasure density is inversely proportional to zone size but must be scaled back to map size
|
||||
//also, normalize it to zone count - higher count means relatively smaller zones
|
||||
|
||||
} while(true);
|
||||
//this is squared distance for optimization purposes
|
||||
const double minDistance = std::max<float>((450.f * size * size * gen->getZones().size()) /
|
||||
(gen->mapGenOptions->getWidth() * gen->mapGenOptions->getHeight() * totalDensity * (gen->map->twoLevel ? 2 : 1)), 2);
|
||||
//distance lower than 2 causes objects to overlap and crash
|
||||
|
||||
do {
|
||||
//optimization - don't check tiles which are not allowed
|
||||
vstd::erase_if(possibleTiles, [gen](const int3 &tile) -> bool
|
||||
{
|
||||
return !gen->isPossible(tile);
|
||||
});
|
||||
|
||||
int3 pos;
|
||||
if (!findPlaceForTreasurePile(gen, minDistance, pos))
|
||||
{
|
||||
break;
|
||||
}
|
||||
createTreasurePile(gen, pos, minDistance, t);
|
||||
|
||||
} while (true);
|
||||
}
|
||||
}
|
||||
|
||||
void CRmgTemplateZone::createObstacles(CMapGenerator* gen)
|
||||
@ -1451,17 +1485,36 @@ bool CRmgTemplateZone::isAccessibleFromAnywhere (CMapGenerator* gen, ObjectTempl
|
||||
return accessible;
|
||||
}
|
||||
|
||||
bool CRmgTemplateZone::findPlaceForObject(CMapGenerator* gen, CGObjectInstance* obj, si32 min_dist, int3 &pos)
|
||||
void CRmgTemplateZone::setTemplateForObject(CMapGenerator* gen, CGObjectInstance* obj)
|
||||
{
|
||||
//we need object apperance to deduce free tiles
|
||||
if (obj->appearance.id == Obj::NO_OBJ)
|
||||
{
|
||||
auto templates = VLC->objtypeh->getHandlerFor(obj->ID, obj->subID)->getTemplates(gen->map->getTile(getPos()).terType);
|
||||
if (templates.empty())
|
||||
throw rmgException(boost::to_string(boost::format("Did not find graphics for object (%d,%d) at %s") %obj->ID %obj->subID %pos));
|
||||
|
||||
throw rmgException(boost::to_string(boost::format("Did not find graphics for object (%d,%d) at %s") % obj->ID %obj->subID %pos));
|
||||
|
||||
obj->appearance = templates.front();
|
||||
}
|
||||
}
|
||||
|
||||
bool CRmgTemplateZone::areAllTilesAvailable(CMapGenerator* gen, CGObjectInstance* obj, int3& tile, std::set<int3>& tilesBlockedByObject) const
|
||||
{
|
||||
for (auto blockingTile : tilesBlockedByObject)
|
||||
{
|
||||
int3 t = tile + blockingTile;
|
||||
if (!gen->map->isInTheMap(t) || !gen->isPossible(t))
|
||||
{
|
||||
//if at least one tile is not possible, object can't be placed here
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CRmgTemplateZone::findPlaceForObject(CMapGenerator* gen, CGObjectInstance* obj, si32 min_dist, int3 &pos)
|
||||
{
|
||||
//we need object apperance to deduce free tile
|
||||
setTemplateForObject(gen, obj);
|
||||
|
||||
//si32 min_dist = sqrt(tileinfo.size()/density);
|
||||
int best_distance = 0;
|
||||
@ -1484,17 +1537,7 @@ bool CRmgTemplateZone::findPlaceForObject(CMapGenerator* gen, CGObjectInstance*
|
||||
//avoid borders
|
||||
if (gen->isPossible(tile) && (dist >= min_dist) && (dist > best_distance))
|
||||
{
|
||||
bool allTilesAvailable = true;
|
||||
for (auto blockingTile : tilesBlockedByObject)
|
||||
{
|
||||
int3 t = tile + blockingTile;
|
||||
if (!gen->map->isInTheMap(t) || !gen->isPossible(t))
|
||||
{
|
||||
allTilesAvailable = false; //if at least one tile is not possible, object can't be placed here
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (allTilesAvailable)
|
||||
if (areAllTilesAvailable(gen, obj, tile, tilesBlockedByObject))
|
||||
{
|
||||
best_distance = dist;
|
||||
pos = tile;
|
||||
|
@ -63,7 +63,6 @@ public:
|
||||
ui32 min;
|
||||
ui32 max;
|
||||
ui16 density;
|
||||
ui16 threshold; //how much must RNG roll to pick that zone
|
||||
};
|
||||
|
||||
struct DLL_LINKAGE ObjectInfo
|
||||
@ -151,8 +150,9 @@ public:
|
||||
void discardDistantTiles (CMapGenerator* gen, float distance);
|
||||
|
||||
void addRequiredObject(CGObjectInstance * obj, si32 guardStrength=0);
|
||||
void addCloseObject(CGObjectInstance * obj, si32 guardStrength = 0);
|
||||
bool addMonster(CMapGenerator* gen, int3 &pos, si32 strength, bool clearSurroundingTiles = true, bool zoneGuard = false);
|
||||
bool createTreasurePile(CMapGenerator* gen, int3 &pos, float minDistance);
|
||||
bool createTreasurePile(CMapGenerator* gen, int3 &pos, float minDistance, const CTreasureInfo& treasureInfo);
|
||||
bool fill (CMapGenerator* gen);
|
||||
bool placeMines (CMapGenerator* gen);
|
||||
void initTownType (CMapGenerator* gen);
|
||||
@ -166,8 +166,6 @@ public:
|
||||
bool crunchPath (CMapGenerator* gen, const int3 &src, const int3 &dst, TRmgTemplateZoneId zone, std::set<int3>* clearedTiles = nullptr);
|
||||
std::vector<int3> getAccessibleOffsets (CMapGenerator* gen, CGObjectInstance* object);
|
||||
|
||||
void setTotalDensity (ui16 val);
|
||||
ui16 getTotalDensity () const;
|
||||
void addConnection(TRmgTemplateZoneId otherZone);
|
||||
std::vector<TRmgTemplateZoneId> getConnections() const;
|
||||
void addTreasureInfo(CTreasureInfo & info);
|
||||
@ -196,12 +194,12 @@ private:
|
||||
ETerrainType terrainType;
|
||||
|
||||
EMonsterStrength::EMonsterStrength zoneMonsterStrength;
|
||||
ui16 totalDensity;
|
||||
std::vector<CTreasureInfo> treasureInfo;
|
||||
std::vector<ObjectInfo> possibleObjects;
|
||||
|
||||
//content info
|
||||
std::vector<std::pair<CGObjectInstance*, ui32>> requiredObjects;
|
||||
std::vector<std::pair<CGObjectInstance*, ui32>> closeObjects;
|
||||
std::vector<CGObjectInstance*> objects;
|
||||
|
||||
//placement info
|
||||
@ -218,6 +216,8 @@ private:
|
||||
bool findPlaceForObject(CMapGenerator* gen, CGObjectInstance* obj, si32 min_dist, int3 &pos);
|
||||
bool findPlaceForTreasurePile(CMapGenerator* gen, float min_dist, int3 &pos);
|
||||
bool canObstacleBePlacedHere(CMapGenerator* gen, ObjectTemplate &temp, int3 &pos);
|
||||
void setTemplateForObject(CMapGenerator* gen, CGObjectInstance* obj);
|
||||
bool areAllTilesAvailable(CMapGenerator* gen, CGObjectInstance* obj, int3& tile, std::set<int3>& tilesBlockedByObject) const;
|
||||
void checkAndPlaceObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos);
|
||||
void placeObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos, bool updateDistance = true);
|
||||
bool guardObject(CMapGenerator* gen, CGObjectInstance* object, si32 str, bool zoneGuard = false, bool addToFreePaths = false);
|
||||
|
@ -40,12 +40,6 @@ int3 CZonePlacer::cords (const float3 f) const
|
||||
|
||||
void CZonePlacer::placeZones(const CMapGenOptions * mapGenOptions, CRandomGenerator * rand)
|
||||
{
|
||||
//gravity-based algorithm
|
||||
|
||||
float gravityConstant = 1e-2;
|
||||
float zoneScale = 0.5f; //zones starts small and then inflate
|
||||
const float inflateModifier = 1.02;
|
||||
|
||||
logGlobal->infoStream() << "Starting zone placement";
|
||||
|
||||
int width = mapGenOptions->getWidth();
|
||||
@ -54,6 +48,13 @@ void CZonePlacer::placeZones(const CMapGenOptions * mapGenOptions, CRandomGenera
|
||||
auto zones = gen->getZones();
|
||||
bool underground = mapGenOptions->getHasTwoLevels();
|
||||
|
||||
//gravity-based algorithm
|
||||
|
||||
const float gravityConstant = 4e-3;
|
||||
const float stiffnessConstant = 4e-3;
|
||||
float zoneScale = 1.0f / std::sqrt(zones.size()); //zones starts small and then inflate. placing more zones is more difficult
|
||||
const float inflateModifier = 1.02;
|
||||
|
||||
/*
|
||||
let's assume we try to fit N circular zones with radius = size on a map
|
||||
|
||||
@ -69,6 +70,10 @@ void CZonePlacer::placeZones(const CMapGenOptions * mapGenOptions, CRandomGenera
|
||||
bool undergroundFlag = false;
|
||||
|
||||
std::vector<float> totalSize = { 0, 0 }; //make sure that sum of zone sizes on surface and uderground match size of the map
|
||||
|
||||
const float radius = 0.4f;
|
||||
const float pi2 = 6.28f;
|
||||
|
||||
for (auto zone : zonesVector)
|
||||
{
|
||||
//even distribution for surface / underground zones. Surface zones always have priority.
|
||||
@ -87,7 +92,8 @@ void CZonePlacer::placeZones(const CMapGenOptions * mapGenOptions, CRandomGenera
|
||||
}
|
||||
|
||||
totalSize[level] += (zone.second->getSize() * zone.second->getSize());
|
||||
zone.second->setCenter (float3(rand->nextDouble(0.2, 0.8), rand->nextDouble(0.2, 0.8), level)); //start away from borders
|
||||
float randomAngle = rand->nextDouble(0, pi2);
|
||||
zone.second->setCenter(float3(0.5f + std::sin(randomAngle) * radius, 0.5f + std::cos(randomAngle) * radius, level)); //place zones around circle
|
||||
}
|
||||
//prescale zones
|
||||
std::vector<float> prescaler = { 0, 0 };
|
||||
@ -101,6 +107,14 @@ void CZonePlacer::placeZones(const CMapGenOptions * mapGenOptions, CRandomGenera
|
||||
|
||||
//gravity-based algorithm. connected zones attract, intersceting zones and map boundaries push back
|
||||
|
||||
//remember best solution
|
||||
float bestTotalDistance = 1e10;
|
||||
float bestTotalOverlap = 1e10;
|
||||
//float bestRatio = 1e10;
|
||||
std::map<CRmgTemplateZone *, float3> bestSolution;
|
||||
|
||||
const int maxDistanceMovementRatio = zones.size() * zones.size(); //experimental - the more zones, the greater total distance expected
|
||||
|
||||
auto getDistance = [](float distance) -> float
|
||||
{
|
||||
return (distance ? distance * distance : 1e-6);
|
||||
@ -108,6 +122,7 @@ void CZonePlacer::placeZones(const CMapGenOptions * mapGenOptions, CRandomGenera
|
||||
|
||||
std::map <CRmgTemplateZone *, float3> forces;
|
||||
std::map <CRmgTemplateZone *, float> distances;
|
||||
std::map <CRmgTemplateZone *, float> overlaps;
|
||||
while (zoneScale < 1) //until zones reach their desired size and fill the map tightly
|
||||
{
|
||||
for (auto zone : zones)
|
||||
@ -126,11 +141,13 @@ void CZonePlacer::placeZones(const CMapGenOptions * mapGenOptions, CRandomGenera
|
||||
if (distance > minDistance)
|
||||
{
|
||||
//WARNING: compiler used to 'optimize' that line so it never actually worked
|
||||
forceVector += (((otherZoneCenter - pos)*(pos.z != otherZoneCenter.z ? (distance - minDistance) : 1)/ getDistance(distance))); //positive value
|
||||
totalDistance += distance;
|
||||
forceVector += (((otherZoneCenter - pos)*(pos.z == otherZoneCenter.z ? (minDistance/distance) : 1)/ getDistance(distance))) * gravityConstant; //positive value
|
||||
totalDistance += (distance - minDistance);
|
||||
}
|
||||
}
|
||||
distances[zone.second] = totalDistance;
|
||||
|
||||
float totalOverlap = 0;
|
||||
//separate overlaping zones
|
||||
for (auto otherZone : zones)
|
||||
{
|
||||
@ -143,7 +160,8 @@ void CZonePlacer::placeZones(const CMapGenOptions * mapGenOptions, CRandomGenera
|
||||
float minDistance = (zone.second->getSize() + otherZone.second->getSize())/mapSize * zoneScale;
|
||||
if (distance < minDistance)
|
||||
{
|
||||
forceVector -= (((otherZoneCenter - pos)*(minDistance - distance)) / getDistance(distance)); //negative value
|
||||
forceVector -= (((otherZoneCenter - pos)*(minDistance/(distance ? distance : 1e-3))) / getDistance(distance)) * stiffnessConstant; //negative value
|
||||
totalOverlap += (minDistance - distance) / (zoneScale * zoneScale); //overlapping of small zones hurts us more
|
||||
}
|
||||
}
|
||||
|
||||
@ -151,11 +169,12 @@ void CZonePlacer::placeZones(const CMapGenOptions * mapGenOptions, CRandomGenera
|
||||
//do not scale boundary distance - zones tend to get squashed
|
||||
float size = zone.second->getSize() / mapSize;
|
||||
|
||||
auto pushAwayFromBoundary = [&forceVector, pos, &getDistance, size](float x, float y)
|
||||
auto pushAwayFromBoundary = [&forceVector, pos, &getDistance, size, stiffnessConstant, &totalOverlap](float x, float y)
|
||||
{
|
||||
float3 boundary = float3 (x, y, pos.z);
|
||||
float distance = pos.dist2d(boundary);
|
||||
forceVector -= (boundary - pos) * (size - distance) / getDistance(distance); //negative value
|
||||
totalOverlap += distance; //overlapping map boundaries is wrong as well
|
||||
forceVector -= (boundary - pos) * (size - distance) / getDistance(distance) * stiffnessConstant; //negative value
|
||||
};
|
||||
if (pos.x < size)
|
||||
{
|
||||
@ -173,9 +192,9 @@ void CZonePlacer::placeZones(const CMapGenOptions * mapGenOptions, CRandomGenera
|
||||
{
|
||||
pushAwayFromBoundary(pos.x, 1);
|
||||
}
|
||||
|
||||
overlaps[zone.second] = totalOverlap;
|
||||
forceVector.z = 0; //operator - doesn't preserve z coordinate :/
|
||||
forces[zone.second] = forceVector * gravityConstant;
|
||||
forces[zone.second] = forceVector;
|
||||
}
|
||||
//update positions
|
||||
for (auto zone : forces)
|
||||
@ -185,53 +204,99 @@ void CZonePlacer::placeZones(const CMapGenOptions * mapGenOptions, CRandomGenera
|
||||
|
||||
//now perform drastic movement of zone that is completely not linked
|
||||
float maxRatio = 0;
|
||||
CRmgTemplateZone * distantZone = nullptr;
|
||||
CRmgTemplateZone * misplacedZone = nullptr;
|
||||
|
||||
float totalDistance = 0;
|
||||
float totalOverlap = 0;
|
||||
for (auto zone : distances) //find most misplaced zone
|
||||
{
|
||||
totalDistance += zone.second;
|
||||
float ratio = zone.second / forces[zone.first].mag(); //if distance to actual movement is long, the zone is misplaced
|
||||
float overlap = overlaps[zone.first];
|
||||
totalOverlap += overlap;
|
||||
float ratio = (zone.second + overlap) / forces[zone.first].mag(); //if distance to actual movement is long, the zone is misplaced
|
||||
if (ratio > maxRatio)
|
||||
{
|
||||
maxRatio = ratio;
|
||||
distantZone = zone.first;
|
||||
misplacedZone = zone.first;
|
||||
}
|
||||
}
|
||||
logGlobal->traceStream() << boost::format("Total distance between zones in this iteration: %2.2f, Worst distance/movement ratio: %3.2f") % totalDistance % maxRatio;
|
||||
|
||||
if (maxRatio > 100) //TODO: scale?
|
||||
{
|
||||
//find most distant zone that should be attracted and move inside it
|
||||
|
||||
CRmgTemplateZone * targetZone = nullptr;
|
||||
float maxDistance = 0;
|
||||
float3 ourCenter = distantZone->getCenter();
|
||||
for (auto con : distantZone->getConnections())
|
||||
{
|
||||
auto otherZone = zones[con];
|
||||
float distance = otherZone->getCenter().dist2dSQ(ourCenter);
|
||||
if (distance > maxDistance)
|
||||
{
|
||||
maxDistance = distance;
|
||||
targetZone = otherZone;
|
||||
}
|
||||
}
|
||||
float3 vec = targetZone->getCenter() - ourCenter;
|
||||
float newDistanceBetweenZones = (std::max (distantZone->getSize(),targetZone->getSize())) * zoneScale / mapSize;
|
||||
logGlobal->traceStream() << boost::format("Trying to move zone %d %s towards %d %s. Old distance %f") %
|
||||
distantZone->getId() % ourCenter() % targetZone->getId() % targetZone->getCenter()() % maxDistance;
|
||||
logGlobal->traceStream() << boost::format("direction is %s") % vec();
|
||||
logGlobal->traceStream() << boost::format("Total distance between zones in this iteration: %2.4f, Total overlap: %2.4f, Worst misplacement/movement ratio: %3.2f") % totalDistance % totalOverlap % maxRatio;
|
||||
|
||||
distantZone->setCenter(targetZone->getCenter() - vec.unitVector() * newDistanceBetweenZones); //zones should now overlap by half size
|
||||
logGlobal->traceStream() << boost::format("New distance %f") % targetZone->getCenter().dist2d(distantZone->getCenter());
|
||||
//save best solution before drastic jump
|
||||
if (totalDistance + totalOverlap < bestTotalDistance + bestTotalOverlap)
|
||||
{
|
||||
bestTotalDistance = totalDistance;
|
||||
bestTotalOverlap = totalOverlap;
|
||||
//if (maxRatio < bestRatio)
|
||||
//{
|
||||
// bestRatio = maxRatio;
|
||||
for (auto zone : zones)
|
||||
bestSolution[zone.second] = zone.second->getCenter();
|
||||
}
|
||||
|
||||
if (maxRatio > maxDistanceMovementRatio)
|
||||
{
|
||||
CRmgTemplateZone * targetZone = nullptr;
|
||||
float3 ourCenter = misplacedZone->getCenter();
|
||||
|
||||
if (totalDistance > totalOverlap)
|
||||
{
|
||||
//find most distant zone that should be attracted and move inside it
|
||||
float maxDistance = 0;
|
||||
for (auto con : misplacedZone->getConnections())
|
||||
{
|
||||
auto otherZone = zones[con];
|
||||
float distance = otherZone->getCenter().dist2dSQ(ourCenter);
|
||||
if (distance > maxDistance)
|
||||
{
|
||||
maxDistance = distance;
|
||||
targetZone = otherZone;
|
||||
}
|
||||
}
|
||||
float3 vec = targetZone->getCenter() - ourCenter;
|
||||
float newDistanceBetweenZones = (std::max(misplacedZone->getSize(), targetZone->getSize())) * zoneScale / mapSize;
|
||||
logGlobal->traceStream() << boost::format("Trying to move zone %d %s towards %d %s. Old distance %f") %
|
||||
misplacedZone->getId() % ourCenter() % targetZone->getId() % targetZone->getCenter()() % maxDistance;
|
||||
logGlobal->traceStream() << boost::format("direction is %s") % vec();
|
||||
|
||||
misplacedZone->setCenter(targetZone->getCenter() - vec.unitVector() * newDistanceBetweenZones); //zones should now overlap by half size
|
||||
logGlobal->traceStream() << boost::format("New distance %f") % targetZone->getCenter().dist2d(misplacedZone->getCenter());
|
||||
}
|
||||
else
|
||||
{
|
||||
float maxOverlap = 0;
|
||||
for (auto otherZone : zones)
|
||||
{
|
||||
float3 otherZoneCenter = otherZone.second->getCenter();
|
||||
|
||||
if (otherZone.second == misplacedZone || otherZoneCenter.z != ourCenter.z)
|
||||
continue;
|
||||
|
||||
float distance = otherZoneCenter.dist2dSQ(ourCenter);
|
||||
if (distance > maxOverlap)
|
||||
{
|
||||
maxOverlap = distance;
|
||||
targetZone = otherZone.second;
|
||||
}
|
||||
}
|
||||
float3 vec = ourCenter - targetZone->getCenter();
|
||||
float newDistanceBetweenZones = (misplacedZone->getSize() + targetZone->getSize()) * zoneScale / mapSize;
|
||||
logGlobal->traceStream() << boost::format("Trying to move zone %d %s away from %d %s. Old distance %f") %
|
||||
misplacedZone->getId() % ourCenter() % targetZone->getId() % targetZone->getCenter()() % maxOverlap;
|
||||
logGlobal->traceStream() << boost::format("direction is %s") % vec();
|
||||
|
||||
misplacedZone->setCenter(targetZone->getCenter() + vec.unitVector() * newDistanceBetweenZones); //zones should now be just separated
|
||||
logGlobal->traceStream() << boost::format("New distance %f") % targetZone->getCenter().dist2d(misplacedZone->getCenter());
|
||||
}
|
||||
}
|
||||
|
||||
zoneScale *= inflateModifier; //increase size of zones so they
|
||||
}
|
||||
|
||||
logGlobal->traceStream() << boost::format("Best fitness reached: total distance %2.4f, total overlap %2.4f") % bestTotalDistance % bestTotalOverlap;
|
||||
for (auto zone : zones) //finalize zone positions
|
||||
{
|
||||
zone.second->setPos(cords(zone.second->getCenter()));
|
||||
zone.second->setPos (cords (bestSolution[zone.second]));
|
||||
logGlobal->traceStream() << boost::format ("Placed zone %d at relative position %s and coordinates %s") % zone.first % zone.second->getCenter() % zone.second->getPos();
|
||||
}
|
||||
}
|
||||
|
@ -2919,7 +2919,7 @@ bool CGameHandler::buyArtifact( ObjectInstanceID hid, ArtifactID aid )
|
||||
return false;
|
||||
|
||||
giveResource(hero->getOwner(),Res::GOLD,-GameConstants::SPELLBOOK_GOLD_COST);
|
||||
giveHeroNewArtifact(hero, VLC->arth->artifacts[0], ArtifactPosition::SPELLBOOK);
|
||||
giveHeroNewArtifact(hero, VLC->arth->artifacts[ArtifactID::SPELLBOOK], ArtifactPosition::SPELLBOOK);
|
||||
assert(hero->getArt(ArtifactPosition::SPELLBOOK));
|
||||
giveSpells(town,hero);
|
||||
return true;
|
||||
|
@ -142,6 +142,7 @@
|
||||
</LinkTimeCodeGeneration>
|
||||
<ShowProgress>NotSet</ShowProgress>
|
||||
<AdditionalLibraryDirectories>..\..\libs;..</AdditionalLibraryDirectories>
|
||||
<AdditionalOptions>/LTCG %(AdditionalOptions)</AdditionalOptions>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='RD|x64'">
|
||||
|
16
vcmibuilder
16
vcmibuilder
@ -209,17 +209,13 @@ fi
|
||||
|
||||
if [[ -n "$data_dir" ]]
|
||||
then
|
||||
cp -r "$data_dir"/Data "$dest_dir"
|
||||
cp -r "$data_dir"/Maps "$dest_dir"
|
||||
|
||||
# this folder is named differently from time to time
|
||||
# vcmi can handle any case but script can't
|
||||
if [ -d "$data_dir"/MP3 ]
|
||||
then
|
||||
cp -r "$data_dir"/MP3 "$dest_dir"
|
||||
else
|
||||
cp -r "$data_dir"/Mp3 "$dest_dir"
|
||||
fi
|
||||
# bash also has `shopt -s nocaseglob` but we don't want this to
|
||||
# accidentally influence other parts of this script
|
||||
# since the directory names are short, we use this pattern matching
|
||||
cp -r "$data_dir"/[Dd][Aa][Tt][Aa] "$dest_dir"
|
||||
cp -r "$data_dir"/[Mm][Aa][Pp][Ss] "$dest_dir"
|
||||
cp -r "$data_dir"/[Mm][Pp]3 "$dest_dir"
|
||||
fi
|
||||
|
||||
if [[ -n "$download" ]]
|
||||
|
Loading…
Reference in New Issue
Block a user