From bb80d4bc027034e63f540de8a9300eb31206ff4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20W=2E=20Urba=C5=84czyk?= Date: Fri, 14 May 2010 02:18:37 +0000 Subject: [PATCH] * support for build grail victory condition * improved formula for necromancy to match better OH3 * Support for new town structures: - Lighthouse - Colossus - Guardian Spirit - Necromancy Amplifier - Soul Prison --- client/CPlayerInterface.cpp | 17 ++++++++---- client/CPlayerInterface.h | 2 +- hch/CObjectHandler.cpp | 52 +++++++++++++++++++++++++++++++------ lib/CGameState.cpp | 12 ++++++--- lib/CGameState.h | 5 +++- lib/Connection.h | 2 +- lib/HeroBonus.cpp | 10 ++++++- lib/HeroBonus.h | 4 ++- server/CGameHandler.cpp | 3 ++- 9 files changed, 84 insertions(+), 23 deletions(-) diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index ac6ac153f..6e7f1f1ab 100644 --- a/client/CPlayerInterface.cpp +++ b/client/CPlayerInterface.cpp @@ -832,10 +832,8 @@ void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector { waitWhileDialog(); boost::unique_lock un(*pim); - - if(stillMoveHero.get() == DURING_MOVE)//if we are in the middle of hero movement - stillMoveHero.setn(STOP_MOVE); //after showing dialog movement will be stopped - + + stopMovement(); CInfoWindow *temp = CInfoWindow::create(text, playerID, &components); if(makingTurn && GH.listInt.size() && LOCPLINT == this) { @@ -852,6 +850,8 @@ void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector void CPlayerInterface::showYesNoDialog(const std::string &text, const std::vector & components, CFunctionList onYes, CFunctionList onNo, bool DelComps) { boost::unique_lock un(*pim); + + stopMovement(); LOCPLINT->showingDialog->setn(true); CInfoWindow::showYesNoDialog(text, &components, onYes, onNo, DelComps, playerID); } @@ -860,7 +860,8 @@ void CPlayerInterface::showBlockingDialog( const std::string &text, const std::v { waitWhileDialog(); boost::unique_lock un(*pim); - + + stopMovement(); CGI->soundh->playSound(static_cast(soundID)); if(!selection && cancel) //simple yes/no dialog @@ -1942,3 +1943,9 @@ void CPlayerInterface::battleNewRoundFirst( int round ) boost::unique_lock un(*pim); battleInt->newRoundFirst(round); } + +void CPlayerInterface::stopMovement() +{ + if(stillMoveHero.get() == DURING_MOVE)//if we are in the middle of hero movement + stillMoveHero.setn(STOP_MOVE); //after showing dialog movement will be stopped +} \ No newline at end of file diff --git a/client/CPlayerInterface.h b/client/CPlayerInterface.h index a24d16518..b9f9f51c3 100644 --- a/client/CPlayerInterface.h +++ b/client/CPlayerInterface.h @@ -213,7 +213,7 @@ public: int3 repairScreenPos(int3 pos); //returns position closest to pos we can center screen on void showInfoDialog(const std::string &text, const std::vector & components = std::vector(), int soundID = 0); void showYesNoDialog(const std::string &text, const std::vector & components, CFunctionList onYes, CFunctionList onNo, bool DelComps); //deactivateCur - whether current main interface should be deactivated; delComps - if components will be deleted on window close - + void stopMovement(); bool moveHero(const CGHeroInstance *h, CGPath path); void initMovement(const TryMoveHero &details, const CGHeroInstance * ho, const int3 &hp );//initializing objects and performing first step of move void movementPxStep( const TryMoveHero &details, int i, const int3 &hp, const CGHeroInstance * ho );//performing step of movement diff --git a/hch/CObjectHandler.cpp b/hch/CObjectHandler.cpp index a2def2cf1..575ebb88c 100644 --- a/hch/CObjectHandler.cpp +++ b/hch/CObjectHandler.cpp @@ -960,23 +960,27 @@ CStackInstance CGHeroInstance::calculateNecromancy (const BattleResult &battleRe const ui8 necromancyLevel = getSecSkillLevel(12); // Hero knows necromancy. - if (necromancyLevel > 0) { + if (necromancyLevel > 0) + { double necromancySkill = necromancyLevel*0.1 + valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, 12)/100.0; + amin(necromancySkill, 1.0); //it's impossible to raise more creatures than all... const std::map &casualties = battleResult.casualties[!battleResult.winner]; ui32 raisedUnits = 0; - // Get lost enemy hit points convertible to units. - for (std::map::const_iterator it = casualties.begin(); it != casualties.end(); it++) - raisedUnits += VLC->creh->creatures[it->first]->valOfBonuses(Bonus::STACK_HEALTH) * it->second; - raisedUnits *= necromancySkill; - // Figure out what to raise and how many. const ui32 creatureTypes[] = {56, 58, 60, 64}; // IDs for Skeletons, Walking Dead, Wights and Liches respectively. const bool improvedNecromancy = hasBonusOfType(Bonus::IMPROVED_NECROMANCY); - CCreature *raisedUnitType = VLC->creh->creatures[creatureTypes[improvedNecromancy ? necromancyLevel : 0]]; + const CCreature *raisedUnitType = VLC->creh->creatures[creatureTypes[improvedNecromancy ? necromancyLevel : 0]]; + const ui32 raisedUnitHP = raisedUnitType->valOfBonuses(Bonus::STACK_HEALTH); - raisedUnits /= raisedUnitType->valOfBonuses(Bonus::STACK_HEALTH); + //calculate creatures raised from each defeated stack + for (std::map::const_iterator it = casualties.begin(); it != casualties.end(); it++) + { + // Get lost enemy hit points convertible to units. + const ui32 raisedHP = VLC->creh->creatures[it->first]->valOfBonuses(Bonus::STACK_HEALTH) * it->second * necromancySkill; + raisedUnits += std::min(raisedHP / raisedUnitHP, it->second * necromancySkill); //limit to % of HP and % of original stack count + } // Make room for new units. int slot = getSlotFor(raisedUnitType->idNumber); @@ -1144,6 +1148,19 @@ void CGHeroInstance::getBonuses(BonusList &out, const CSelector &selector, const //luck skill if(int luckSkill = getSecSkillLevel(9)) out.push_back(Bonus(Bonus::PERMANENT, Bonus::LUCK, Bonus::SECONDARY_SKILL, luckSkill, 9, VLC->generaltexth->arraytxt[73+luckSkill])); + + //guardian spirit + BOOST_FOREACH(const CGTownInstance *t, cb->getPlayerState(tempOwner)->towns) + if(t->subID ==1 && vstd::contains(t->builtBuildings,26)) //rampart with grail + out.push_back(Bonus(Bonus::PERMANENT, Bonus::LUCK, Bonus::TOWN_STRUCTURE, +2, 26, VLC->generaltexth->buildings[1][26].first + " +2")); + } + + if(Selector::matchesType(selector, Bonus::SEA_MOVEMENT)) + { + //lighthouses + BOOST_FOREACH(const CGTownInstance *t, cb->getPlayerState(tempOwner)->towns) + if(t->subID == 0 && vstd::contains(t->builtBuildings,17)) //castle + out.push_back(Bonus(Bonus::PERMANENT, Bonus::SEA_MOVEMENT, Bonus::TOWN_STRUCTURE, +500, 17, VLC->generaltexth->buildings[0][17].first + " +500")); } if(Selector::matchesType(selector, Bonus::MORALE)) @@ -1151,6 +1168,25 @@ void CGHeroInstance::getBonuses(BonusList &out, const CSelector &selector, const //leadership if(int moraleSkill = getSecSkillLevel(6)) out.push_back(Bonus(Bonus::PERMANENT, Bonus::MORALE, Bonus::SECONDARY_SKILL, moraleSkill, 6, VLC->generaltexth->arraytxt[104+moraleSkill])); + + //colossus + BOOST_FOREACH(const CGTownInstance *t, cb->getPlayerState(tempOwner)->towns) + if(t->subID == 0 && vstd::contains(t->builtBuildings,26)) //castle + out.push_back(Bonus(Bonus::PERMANENT, Bonus::MORALE, Bonus::TOWN_STRUCTURE, +2, 26, VLC->generaltexth->buildings[0][26].first + " +2")); + } + + if(Selector::matchesTypeSubtype(selector, Bonus::SECONDARY_SKILL_PREMY, 12)) //necromancy + { + BOOST_FOREACH(const CGTownInstance *t, cb->getPlayerState(tempOwner)->towns) + { + if(t->subID == 4) //necropolis + { + if(vstd::contains(t->builtBuildings,21)) //necromancy amplifier + out.push_back(Bonus(Bonus::PERMANENT, Bonus::SECONDARY_SKILL_PREMY, Bonus::TOWN_STRUCTURE, +10, 21, VLC->generaltexth->buildings[4][21].first + " +10%", 12)); + if(vstd::contains(t->builtBuildings,26)) //grail - Soul prison + out.push_back(Bonus(Bonus::PERMANENT, Bonus::SECONDARY_SKILL_PREMY, Bonus::TOWN_STRUCTURE, +20, 26, VLC->generaltexth->buildings[4][26].first + " +20%", 12)); + } + } } } diff --git a/lib/CGameState.cpp b/lib/CGameState.cpp index 0b7b365ef..f9ce48d6a 100644 --- a/lib/CGameState.cpp +++ b/lib/CGameState.cpp @@ -3061,10 +3061,10 @@ int CGameState::victoryCheck( ui8 player ) const break; case buildGrail: - for(size_t i = 0; i < map->towns.size(); i++) - if(map->towns[i]->pos == map->victoryCondition.pos - && map->towns[i]->tempOwner == player - && vstd::contains(map->towns[i]->builtBuildings, 26)) + BOOST_FOREACH(const CGTownInstance *t, map->towns) + if((t == map->victoryCondition.obj || !map->victoryCondition.obj) + && t->tempOwner == player + && vstd::contains(t->builtBuildings, 26)) return 1; break; @@ -3760,6 +3760,10 @@ void PlayerState::getParents(TCNodes &out, const CBonusSystemNode *root /*= NULL //TODO: global effects } +void PlayerState::getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root /*= NULL*/) const +{ +} + InfoAboutHero::InfoAboutHero() { details = NULL; diff --git a/lib/CGameState.h b/lib/CGameState.h index b6f94e922..1d8dad889 100644 --- a/lib/CGameState.h +++ b/lib/CGameState.h @@ -128,7 +128,10 @@ public: ui8 daysWithoutCastle; PlayerState(); - virtual void getParents(TCNodes &out, const CBonusSystemNode *root = NULL) const; + + //override + void getParents(TCNodes &out, const CBonusSystemNode *root = NULL) const; + void getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root = NULL) const; template void serialize(Handler &h, const int version) { diff --git a/lib/Connection.h b/lib/Connection.h index f6c761003..d67b71f05 100644 --- a/lib/Connection.h +++ b/lib/Connection.h @@ -21,7 +21,7 @@ #include #include -const ui32 version = 720; +const ui32 version = 721; class CConnection; class CGObjectInstance; class CGameState; diff --git a/lib/HeroBonus.cpp b/lib/HeroBonus.cpp index d04dd6332..fb138be65 100644 --- a/lib/HeroBonus.cpp +++ b/lib/HeroBonus.cpp @@ -332,10 +332,18 @@ namespace Selector return CSelectFieldEqual(&Bonus::source, source) && CSelectFieldEqual(&Bonus::id, sourceID); } - bool matchesType(const CSelector &sel, TBonusType type) + bool DLL_EXPORT matchesType(const CSelector &sel, TBonusType type) { Bonus dummy; dummy.type = type; return sel(dummy); } + + bool DLL_EXPORT matchesTypeSubtype(const CSelector &sel, TBonusType type, TBonusSubtype subtype) + { + Bonus dummy; + dummy.type = type; + dummy.subtype = subtype; + return sel(dummy); + } } \ No newline at end of file diff --git a/lib/HeroBonus.h b/lib/HeroBonus.h index efd23b08c..f9846ee14 100644 --- a/lib/HeroBonus.h +++ b/lib/HeroBonus.h @@ -186,7 +186,8 @@ struct DLL_EXPORT Bonus { NO_LIMIT = 0, ONLY_DISTANCE_FIGHT=1, ONLY_MELEE_FIGHT, //used to mark bonuses for attack/defense primary skills from spells like Precision (distance only) - ONLY_ALLIED_ARMY, ONLY_ENEMY_ARMY + ONLY_ALLIED_ARMY, ONLY_ENEMY_ARMY, + PLAYR_HEROES }; enum ValueType @@ -443,4 +444,5 @@ namespace Selector CSelector DLL_EXPORT source(ui8 source, ui32 sourceID); bool DLL_EXPORT matchesType(const CSelector &sel, TBonusType type); + bool DLL_EXPORT matchesTypeSubtype(const CSelector &sel, TBonusType type, TBonusSubtype subtype); } diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 79268bb03..6d99d4816 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -2482,7 +2482,8 @@ bool CGameHandler::buildStructure( si32 tid, si32 bid ) vistiCastleObjects (t, t->visitingHero); if(t->garrisonHero) vistiCastleObjects (t, t->garrisonHero); - + + checkLossVictory(t->tempOwner); return true; } bool CGameHandler::razeStructure (si32 tid, si32 bid)