mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-26 22:57:00 +02:00
* 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
This commit is contained in:
parent
df151cceba
commit
bb80d4bc02
@ -833,9 +833,7 @@ void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector
|
|||||||
waitWhileDialog();
|
waitWhileDialog();
|
||||||
boost::unique_lock<boost::recursive_mutex> un(*pim);
|
boost::unique_lock<boost::recursive_mutex> un(*pim);
|
||||||
|
|
||||||
if(stillMoveHero.get() == DURING_MOVE)//if we are in the middle of hero movement
|
stopMovement();
|
||||||
stillMoveHero.setn(STOP_MOVE); //after showing dialog movement will be stopped
|
|
||||||
|
|
||||||
CInfoWindow *temp = CInfoWindow::create(text, playerID, &components);
|
CInfoWindow *temp = CInfoWindow::create(text, playerID, &components);
|
||||||
if(makingTurn && GH.listInt.size() && LOCPLINT == this)
|
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<SComponent*> & components, CFunctionList<void()> onYes, CFunctionList<void()> onNo, bool DelComps)
|
void CPlayerInterface::showYesNoDialog(const std::string &text, const std::vector<SComponent*> & components, CFunctionList<void()> onYes, CFunctionList<void()> onNo, bool DelComps)
|
||||||
{
|
{
|
||||||
boost::unique_lock<boost::recursive_mutex> un(*pim);
|
boost::unique_lock<boost::recursive_mutex> un(*pim);
|
||||||
|
|
||||||
|
stopMovement();
|
||||||
LOCPLINT->showingDialog->setn(true);
|
LOCPLINT->showingDialog->setn(true);
|
||||||
CInfoWindow::showYesNoDialog(text, &components, onYes, onNo, DelComps, playerID);
|
CInfoWindow::showYesNoDialog(text, &components, onYes, onNo, DelComps, playerID);
|
||||||
}
|
}
|
||||||
@ -861,6 +861,7 @@ void CPlayerInterface::showBlockingDialog( const std::string &text, const std::v
|
|||||||
waitWhileDialog();
|
waitWhileDialog();
|
||||||
boost::unique_lock<boost::recursive_mutex> un(*pim);
|
boost::unique_lock<boost::recursive_mutex> un(*pim);
|
||||||
|
|
||||||
|
stopMovement();
|
||||||
CGI->soundh->playSound(static_cast<soundBase::soundID>(soundID));
|
CGI->soundh->playSound(static_cast<soundBase::soundID>(soundID));
|
||||||
|
|
||||||
if(!selection && cancel) //simple yes/no dialog
|
if(!selection && cancel) //simple yes/no dialog
|
||||||
@ -1942,3 +1943,9 @@ void CPlayerInterface::battleNewRoundFirst( int round )
|
|||||||
boost::unique_lock<boost::recursive_mutex> un(*pim);
|
boost::unique_lock<boost::recursive_mutex> un(*pim);
|
||||||
battleInt->newRoundFirst(round);
|
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
|
||||||
|
}
|
@ -213,7 +213,7 @@ public:
|
|||||||
int3 repairScreenPos(int3 pos); //returns position closest to pos we can center screen on
|
int3 repairScreenPos(int3 pos); //returns position closest to pos we can center screen on
|
||||||
void showInfoDialog(const std::string &text, const std::vector<SComponent*> & components = std::vector<SComponent*>(), int soundID = 0);
|
void showInfoDialog(const std::string &text, const std::vector<SComponent*> & components = std::vector<SComponent*>(), int soundID = 0);
|
||||||
void showYesNoDialog(const std::string &text, const std::vector<SComponent*> & components, CFunctionList<void()> onYes, CFunctionList<void()> onNo, bool DelComps); //deactivateCur - whether current main interface should be deactivated; delComps - if components will be deleted on window close
|
void showYesNoDialog(const std::string &text, const std::vector<SComponent*> & components, CFunctionList<void()> onYes, CFunctionList<void()> 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);
|
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 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
|
void movementPxStep( const TryMoveHero &details, int i, const int3 &hp, const CGHeroInstance * ho );//performing step of movement
|
||||||
|
@ -960,23 +960,27 @@ CStackInstance CGHeroInstance::calculateNecromancy (const BattleResult &battleRe
|
|||||||
const ui8 necromancyLevel = getSecSkillLevel(12);
|
const ui8 necromancyLevel = getSecSkillLevel(12);
|
||||||
|
|
||||||
// Hero knows necromancy.
|
// Hero knows necromancy.
|
||||||
if (necromancyLevel > 0) {
|
if (necromancyLevel > 0)
|
||||||
|
{
|
||||||
double necromancySkill = necromancyLevel*0.1
|
double necromancySkill = necromancyLevel*0.1
|
||||||
+ valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, 12)/100.0;
|
+ valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, 12)/100.0;
|
||||||
|
amin(necromancySkill, 1.0); //it's impossible to raise more creatures than all...
|
||||||
const std::map<ui32,si32> &casualties = battleResult.casualties[!battleResult.winner];
|
const std::map<ui32,si32> &casualties = battleResult.casualties[!battleResult.winner];
|
||||||
ui32 raisedUnits = 0;
|
ui32 raisedUnits = 0;
|
||||||
|
|
||||||
// Get lost enemy hit points convertible to units.
|
|
||||||
for (std::map<ui32,si32>::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.
|
// 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 ui32 creatureTypes[] = {56, 58, 60, 64}; // IDs for Skeletons, Walking Dead, Wights and Liches respectively.
|
||||||
const bool improvedNecromancy = hasBonusOfType(Bonus::IMPROVED_NECROMANCY);
|
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<ui32,si32>::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<ui32>(raisedHP / raisedUnitHP, it->second * necromancySkill); //limit to % of HP and % of original stack count
|
||||||
|
}
|
||||||
|
|
||||||
// Make room for new units.
|
// Make room for new units.
|
||||||
int slot = getSlotFor(raisedUnitType->idNumber);
|
int slot = getSlotFor(raisedUnitType->idNumber);
|
||||||
@ -1144,6 +1148,19 @@ void CGHeroInstance::getBonuses(BonusList &out, const CSelector &selector, const
|
|||||||
//luck skill
|
//luck skill
|
||||||
if(int luckSkill = getSecSkillLevel(9))
|
if(int luckSkill = getSecSkillLevel(9))
|
||||||
out.push_back(Bonus(Bonus::PERMANENT, Bonus::LUCK, Bonus::SECONDARY_SKILL, luckSkill, 9, VLC->generaltexth->arraytxt[73+luckSkill]));
|
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))
|
if(Selector::matchesType(selector, Bonus::MORALE))
|
||||||
@ -1151,6 +1168,25 @@ void CGHeroInstance::getBonuses(BonusList &out, const CSelector &selector, const
|
|||||||
//leadership
|
//leadership
|
||||||
if(int moraleSkill = getSecSkillLevel(6))
|
if(int moraleSkill = getSecSkillLevel(6))
|
||||||
out.push_back(Bonus(Bonus::PERMANENT, Bonus::MORALE, Bonus::SECONDARY_SKILL, moraleSkill, 6, VLC->generaltexth->arraytxt[104+moraleSkill]));
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3061,10 +3061,10 @@ int CGameState::victoryCheck( ui8 player ) const
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case buildGrail:
|
case buildGrail:
|
||||||
for(size_t i = 0; i < map->towns.size(); i++)
|
BOOST_FOREACH(const CGTownInstance *t, map->towns)
|
||||||
if(map->towns[i]->pos == map->victoryCondition.pos
|
if((t == map->victoryCondition.obj || !map->victoryCondition.obj)
|
||||||
&& map->towns[i]->tempOwner == player
|
&& t->tempOwner == player
|
||||||
&& vstd::contains(map->towns[i]->builtBuildings, 26))
|
&& vstd::contains(t->builtBuildings, 26))
|
||||||
return 1;
|
return 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -3760,6 +3760,10 @@ void PlayerState::getParents(TCNodes &out, const CBonusSystemNode *root /*= NULL
|
|||||||
//TODO: global effects
|
//TODO: global effects
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PlayerState::getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root /*= NULL*/) const
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
InfoAboutHero::InfoAboutHero()
|
InfoAboutHero::InfoAboutHero()
|
||||||
{
|
{
|
||||||
details = NULL;
|
details = NULL;
|
||||||
|
@ -128,7 +128,10 @@ public:
|
|||||||
ui8 daysWithoutCastle;
|
ui8 daysWithoutCastle;
|
||||||
|
|
||||||
PlayerState();
|
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 <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
#include <boost/mpl/int.hpp>
|
#include <boost/mpl/int.hpp>
|
||||||
#include <boost/mpl/identity.hpp>
|
#include <boost/mpl/identity.hpp>
|
||||||
|
|
||||||
const ui32 version = 720;
|
const ui32 version = 721;
|
||||||
class CConnection;
|
class CConnection;
|
||||||
class CGObjectInstance;
|
class CGObjectInstance;
|
||||||
class CGameState;
|
class CGameState;
|
||||||
|
@ -332,10 +332,18 @@ namespace Selector
|
|||||||
return CSelectFieldEqual<ui8>(&Bonus::source, source) && CSelectFieldEqual<ui32>(&Bonus::id, sourceID);
|
return CSelectFieldEqual<ui8>(&Bonus::source, source) && CSelectFieldEqual<ui32>(&Bonus::id, sourceID);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool matchesType(const CSelector &sel, TBonusType type)
|
bool DLL_EXPORT matchesType(const CSelector &sel, TBonusType type)
|
||||||
{
|
{
|
||||||
Bonus dummy;
|
Bonus dummy;
|
||||||
dummy.type = type;
|
dummy.type = type;
|
||||||
return sel(dummy);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
@ -186,7 +186,8 @@ struct DLL_EXPORT Bonus
|
|||||||
{
|
{
|
||||||
NO_LIMIT = 0,
|
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_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
|
enum ValueType
|
||||||
@ -443,4 +444,5 @@ namespace Selector
|
|||||||
CSelector DLL_EXPORT source(ui8 source, ui32 sourceID);
|
CSelector DLL_EXPORT source(ui8 source, ui32 sourceID);
|
||||||
|
|
||||||
bool DLL_EXPORT matchesType(const CSelector &sel, TBonusType type);
|
bool DLL_EXPORT matchesType(const CSelector &sel, TBonusType type);
|
||||||
|
bool DLL_EXPORT matchesTypeSubtype(const CSelector &sel, TBonusType type, TBonusSubtype subtype);
|
||||||
}
|
}
|
||||||
|
@ -2483,6 +2483,7 @@ bool CGameHandler::buildStructure( si32 tid, si32 bid )
|
|||||||
if(t->garrisonHero)
|
if(t->garrisonHero)
|
||||||
vistiCastleObjects (t, t->garrisonHero);
|
vistiCastleObjects (t, t->garrisonHero);
|
||||||
|
|
||||||
|
checkLossVictory(t->tempOwner);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool CGameHandler::razeStructure (si32 tid, si32 bid)
|
bool CGameHandler::razeStructure (si32 tid, si32 bid)
|
||||||
|
Loading…
Reference in New Issue
Block a user