From 6f7bda65b444281da7c73329292f90639531049e Mon Sep 17 00:00:00 2001 From: DjWarmonger Date: Wed, 24 Dec 2014 15:07:20 +0100 Subject: [PATCH 1/3] Better obstacle shapes inside zones. --- lib/rmg/CRmgTemplateZone.cpp | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/rmg/CRmgTemplateZone.cpp b/lib/rmg/CRmgTemplateZone.cpp index 9aaa271e0..70b03fdf1 100644 --- a/lib/rmg/CRmgTemplateZone.cpp +++ b/lib/rmg/CRmgTemplateZone.cpp @@ -412,7 +412,7 @@ void CRmgTemplateZone::fractalize(CMapGenerator* gen) int totalDensity = 0; for (auto ti : treasureInfo) totalDensity =+ ti.density; - const float minDistance = totalDensity * 3; //squared + const float minDistance = totalDensity * 4; //squared for (auto tile : tileinfo) { @@ -481,7 +481,27 @@ void CRmgTemplateZone::fractalize(CMapGenerator* gen) freePaths.insert(tile); } - + //now block most distant tiles away from passages + + float blockDistance = minDistance * 0.6f; + + for (auto tile : possibleTiles) + { + bool closeTileFound = false; + + for (auto clearTile : freePaths) + { + float distance = tile.dist2dSQ(clearTile); + + if (distance < blockDistance) + { + closeTileFound = true; + break; + } + } + if (!closeTileFound) //this tile is far enough from passages + gen->setOccupied(tile, ETileType::BLOCKED); + } if (0) //enable to debug { From 3c39ef477f62af637aa64f2c83e2015916c3c068 Mon Sep 17 00:00:00 2001 From: DjWarmonger Date: Wed, 24 Dec 2014 23:53:56 +0100 Subject: [PATCH 2/3] Implemented original stack splitting algorithms proposed by AlexSpl. Save format changed. --- lib/mapObjects/MiscObjects.cpp | 88 +++++++++++++++++++++++----------- lib/mapObjects/MiscObjects.h | 7 ++- 2 files changed, 64 insertions(+), 31 deletions(-) diff --git a/lib/mapObjects/MiscObjects.cpp b/lib/mapObjects/MiscObjects.cpp index 6249c1d3e..422edf3ba 100644 --- a/lib/mapObjects/MiscObjects.cpp +++ b/lib/mapObjects/MiscObjects.cpp @@ -200,7 +200,6 @@ void CGCreature::initObj() amount = 1; } } - formation.randomFormation = cb->gameState()->getRandomGenerator().nextInt(); temppower = stacks[SlotID(0)]->count * 1000; refusedJoining = false; @@ -367,33 +366,8 @@ void CGCreature::fight( const CGHeroInstance *h ) const int basicType = stacks.begin()->second->type->idNumber; cb->setObjProperty(id, ObjProperty::MONSTER_RESTORE_TYPE, basicType); //store info about creature stack - double relativePower = static_cast(h->getTotalStrength()) / getArmyStrength(); - int stacksCount; - //TODO: number depends on tile type - if (relativePower < 0.5) - { - stacksCount = 7; - } - else if (relativePower < 0.67) - { - stacksCount = 7; - } - else if (relativePower < 1) - { - stacksCount = 6; - } - else if (relativePower < 1.5) - { - stacksCount = 5; - } - else if (relativePower < 2) - { - stacksCount = 4; - } - else - { - stacksCount = 3; - } + int stacksCount = getNumberOfStacks(h); + SlotID sourceSlot = stacks.begin()->first; SlotID destSlot; for (int stacksLeft = stacksCount; stacksLeft > 1; --stacksLeft) @@ -413,7 +387,7 @@ void CGCreature::fight( const CGHeroInstance *h ) const } if (stacksCount > 1) { - if (formation.randomFormation % 100 < 50) //upgrade + if (containsUpgradedStack()) //upgrade { SlotID slotId = SlotID(stacks.size() / 2); const auto & upgrades = getStack(slotId).type->upgrades; @@ -489,6 +463,62 @@ void CGCreature::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) assert(0); } +bool CGCreature::containsUpgradedStack() const +{ + //source http://heroescommunity.com/viewthread.php3?TID=27539&PID=830557#focus + + float a = 2992.911117; + float b = 14174.264968; + float c = 5325.181015; + float d = 32788.727920; + + int val = std::floor (a*pos.x + b*pos.y + c*pos.z + d); + return ((val % 32768) % 100) < 50; +} + +int CGCreature::getNumberOfStacks(const CGHeroInstance *hero) const +{ + //source http://heroescommunity.com/viewthread.php3?TID=27539&PID=1266094#focus + + float strengthRatio = hero->getArmyStrength() / getArmyStrength(); + int split = 1; + + if (strengthRatio < 0.5f) + split = 7; + else if (strengthRatio < 0.67f) + split = 6; + else if (strengthRatio < 1) + split = 5; + else if (strengthRatio < 1.5f) + split = 4; + else if (strengthRatio < 2) + split = 3; + else + split = 2; + + int a = 1550811371; + int b = -935900487; + int c = 1943276003; + int d = -1120346418; + + int R1 = a * pos.x + b * pos.y + c * pos.z + d; + int R2 = R1 / 65536; + int R3 = R2 % 32768; + if (R3 < 0) + R3 += 32767; //is it ever needed if we do modulo calculus? + int R4 = R3 % 100 + 1; + + if (R4 <= 20) + split -= 1; + else if (R4 >= 80) + split += 1; + + vstd::amin(split, getStack(SlotID(0)).count); //can't divide into more stacks than creatures total + vstd::amin(split, 7); //can't have more than 7 stacks + + return split; +} + void CGMine::onHeroVisit( const CGHeroInstance * h ) const { int relations = cb->gameState()->getPlayerRelations(h->tempOwner, tempOwner); diff --git a/lib/mapObjects/MiscObjects.h b/lib/mapObjects/MiscObjects.h index c1e730e8d..bed4498c0 100644 --- a/lib/mapObjects/MiscObjects.h +++ b/lib/mapObjects/MiscObjects.h @@ -56,14 +56,17 @@ public: void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override; void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override; + //stack formation depends on position, + bool containsUpgradedStack() const; + int getNumberOfStacks(const CGHeroInstance *hero) const; struct DLL_LINKAGE formationInfo // info about merging stacks after battle back into one { si32 basicType; - ui32 randomFormation; //random seed used to determine number of stacks and is there's upgraded stack + ui8 upgrade; //random seed used to determine number of stacks and is there's upgraded stack template void serialize(Handler &h, const int version) { - h & basicType & randomFormation; + h & basicType & upgrade; } } formation; From e46f03fabe4992513102f2b1b8d7a6ca5e5a73b4 Mon Sep 17 00:00:00 2001 From: DjWarmonger Date: Thu, 25 Dec 2014 10:21:39 +0100 Subject: [PATCH 3/3] Upgrades, stack splitting. Results now are identical to OH3. --- ChangeLog | 5 +++++ lib/mapObjects/MiscObjects.cpp | 37 +++++++++++++++++----------------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8922d3709..8b226e5b5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +0.97 -> 0.98 + +BATTLES: +* Implemented OH3 stack split / upgrade formulas according to AlexSpl + 0.96 -> 0.97 (Nov 01 2014) GENERAL: * (windows) Moved VCMI data directory from '%userprofile%\vcmi' to '%userprofile%\Documents\My Games\vcmi' diff --git a/lib/mapObjects/MiscObjects.cpp b/lib/mapObjects/MiscObjects.cpp index 422edf3ba..09c268532 100644 --- a/lib/mapObjects/MiscObjects.cpp +++ b/lib/mapObjects/MiscObjects.cpp @@ -367,34 +367,35 @@ void CGCreature::fight( const CGHeroInstance *h ) const cb->setObjProperty(id, ObjProperty::MONSTER_RESTORE_TYPE, basicType); //store info about creature stack int stacksCount = getNumberOfStacks(h); + //source: http://heroescommunity.com/viewthread.php3?TID=27539&PID=1266335#focus + + int amount = getStackCount(SlotID(0)); + int m = amount / stacksCount; + int b = stacksCount * (m + 1) - amount; + int a = stacksCount - b; SlotID sourceSlot = stacks.begin()->first; - SlotID destSlot; - for (int stacksLeft = stacksCount; stacksLeft > 1; --stacksLeft) + for (int slotID = 1; slotID < a; ++slotID) { - int stackSize = stacks.begin()->second->count / stacksLeft; - if (stackSize) - { - if ((destSlot = getFreeSlot()).validSlot()) - cb->moveStack(StackLocation(this, sourceSlot), StackLocation(this, destSlot), stackSize); - else - { - logGlobal->warnStream() <<"Warning! Not enough empty slots to split stack!"; - break; - } - } - else break; + int stackSize = m + 1; + cb->moveStack(StackLocation(this, sourceSlot), StackLocation(this, SlotID(slotID)), stackSize); + } + for (int slotID = a; slotID < stacksCount; ++slotID) + { + int stackSize = m; + if (slotID) //don't do this when a = 0 -> stack is single + cb->moveStack(StackLocation(this, sourceSlot), StackLocation(this, SlotID(slotID)), stackSize); } if (stacksCount > 1) { if (containsUpgradedStack()) //upgrade { - SlotID slotId = SlotID(stacks.size() / 2); - const auto & upgrades = getStack(slotId).type->upgrades; + SlotID slotID = SlotID(std::floor((float)stacks.size() / 2)); + const auto & upgrades = getStack(slotID).type->upgrades; if(!upgrades.empty()) { auto it = RandomGeneratorUtil::nextItem(upgrades, cb->gameState()->getRandomGenerator()); - cb->changeStackType(StackLocation(this, slotId), VLC->creh->creatures[*it]); + cb->changeStackType(StackLocation(this, slotID), VLC->creh->creatures[*it]); } } } @@ -480,7 +481,7 @@ int CGCreature::getNumberOfStacks(const CGHeroInstance *hero) const { //source http://heroescommunity.com/viewthread.php3?TID=27539&PID=1266094#focus - float strengthRatio = hero->getArmyStrength() / getArmyStrength(); + double strengthRatio = (double)hero->getArmyStrength() / getArmyStrength(); int split = 1; if (strengthRatio < 0.5f)