1
0
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:
Michał W. Urbańczyk 2010-05-14 02:18:37 +00:00
parent df151cceba
commit bb80d4bc02
9 changed files with 84 additions and 23 deletions

View File

@ -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
}

View File

@ -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

View File

@ -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));
}
}
}
}

View File

@ -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;

View File

@ -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)
{

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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)