mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +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
@ -832,10 +832,8 @@ void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector
|
||||
{
|
||||
waitWhileDialog();
|
||||
boost::unique_lock<boost::recursive_mutex> 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<SComponent*> & components, CFunctionList<void()> onYes, CFunctionList<void()> onNo, bool DelComps)
|
||||
{
|
||||
boost::unique_lock<boost::recursive_mutex> 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<boost::recursive_mutex> un(*pim);
|
||||
|
||||
|
||||
stopMovement();
|
||||
CGI->soundh->playSound(static_cast<soundBase::soundID>(soundID));
|
||||
|
||||
if(!selection && cancel) //simple yes/no dialog
|
||||
@ -1942,3 +1943,9 @@ void CPlayerInterface::battleNewRoundFirst( int round )
|
||||
boost::unique_lock<boost::recursive_mutex> 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
|
||||
}
|
@ -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<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 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
|
||||
|
@ -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<ui32,si32> &casualties = battleResult.casualties[!battleResult.winner];
|
||||
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.
|
||||
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<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.
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include <boost/mpl/int.hpp>
|
||||
#include <boost/mpl/identity.hpp>
|
||||
|
||||
const ui32 version = 720;
|
||||
const ui32 version = 721;
|
||||
class CConnection;
|
||||
class CGObjectInstance;
|
||||
class CGameState;
|
||||
|
@ -332,10 +332,18 @@ namespace Selector
|
||||
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;
|
||||
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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user