1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-05-31 22:59:54 +02:00

* New file: lib/HeroBonus.cpp - updated project files for MSVC

* Updated changelog
* Support for Lighthosues and Obelisks
* Bonus system extended on players 
* Army speed won't affect movement points when sailing
* Picking grail position (digging not implemented though, puzzle map only partially)
* Minor improvements
This commit is contained in:
Michał W. Urbańczyk 2010-02-10 02:56:00 +00:00
parent d0bf334394
commit 0fdbe787dc
30 changed files with 638 additions and 148 deletions

View File

@ -317,7 +317,7 @@ std::vector< std::vector< std::vector<unsigned char> > > & CCallback::getVisibil
bool CCallback::isVisible(int3 pos, int Player) const bool CCallback::isVisible(int3 pos, int Player) const
{ {
boost::shared_lock<boost::shared_mutex> lock(*gs->mx); boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
return gs->isVisible(pos, Player); return gs->map->isInTheMap(pos) && gs->isVisible(pos, Player);
} }
std::vector < const CGTownInstance *> CCallback::getTownsInfo(bool onlyOur) const std::vector < const CGTownInstance *> CCallback::getTownsInfo(bool onlyOur) const
@ -905,6 +905,12 @@ void CCallback::calculatePaths( const CGHeroInstance *hero, CPathsInfo &out, int
gs->calculatePaths(hero, out, src, movement); gs->calculatePaths(hero, out, src, movement);
} }
int3 CCallback::getGrailPos( float &outKnownRatio )
{
outKnownRatio = (float)CGObelisk::visited[player] / CGObelisk::obeliskCount;
return gs->map->grailPos;
}
InfoAboutTown::InfoAboutTown() InfoAboutTown::InfoAboutTown()
{ {
tType = NULL; tType = NULL;

View File

@ -114,6 +114,7 @@ public:
virtual int getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const =0; //when called during battle, takes into account creatures' spell cost reduction virtual int getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const =0; //when called during battle, takes into account creatures' spell cost reduction
virtual int estimateSpellDamage(const CSpell * sp) const =0; //estimates damage of given spell; returns 0 if spell causes no dmg virtual int estimateSpellDamage(const CSpell * sp) const =0; //estimates damage of given spell; returns 0 if spell causes no dmg
virtual void getThievesGuildInfo(SThievesGuildInfo & thi, const CGObjectInstance * obj)=0; //get thieves' guild info obtainable while visiting given object virtual void getThievesGuildInfo(SThievesGuildInfo & thi, const CGObjectInstance * obj)=0; //get thieves' guild info obtainable while visiting given object
virtual int3 getGrailPos(float &outKnownRatio)=0;
//hero //hero
virtual int howManyHeroes(bool includeGarrisoned = true)const =0; virtual int howManyHeroes(bool includeGarrisoned = true)const =0;
@ -247,6 +248,7 @@ public:
int getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const; //when called during battle, takes into account creatures' spell cost reduction int getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const; //when called during battle, takes into account creatures' spell cost reduction
int estimateSpellDamage(const CSpell * sp) const; //estimates damage of given spell; returns 0 if spell causes no dmg int estimateSpellDamage(const CSpell * sp) const; //estimates damage of given spell; returns 0 if spell causes no dmg
void getThievesGuildInfo(SThievesGuildInfo & thi, const CGObjectInstance * obj); //get thieves' guild info obtainable while visiting given object void getThievesGuildInfo(SThievesGuildInfo & thi, const CGObjectInstance * obj); //get thieves' guild info obtainable while visiting given object
int3 getGrailPos(float &outKnownRatio); //returns pos and (via arg) percent of discovered obelisks; TODO: relies on fairness of GUI/AI... :/
std::vector < const CGObjectInstance * > getBlockingObjs(int3 pos) const; std::vector < const CGObjectInstance * > getBlockingObjs(int3 pos) const;
std::vector < const CGObjectInstance * > getVisitableObjs(int3 pos) const; std::vector < const CGObjectInstance * > getVisitableObjs(int3 pos) const;

View File

@ -21,7 +21,7 @@ using namespace boost::logic;
class CCallback; class CCallback;
class ICallback; class ICallback;
class CGlobalAI; class CGlobalAI;
class Component; struct Component;
class CSelectableComponent; class CSelectableComponent;
struct TryMoveHero; struct TryMoveHero;
class CGHeroInstance; class CGHeroInstance;
@ -91,6 +91,7 @@ public:
virtual void showShipyardDialog(const IShipyard *obj){} //obj may be town or shipyard; state: 0 - can buid, 1 - lack of resources, 2 - dest tile is blocked, 3 - no water virtual void showShipyardDialog(const IShipyard *obj){} //obj may be town or shipyard; state: 0 - can buid, 1 - lack of resources, 2 - dest tile is blocked, 3 - no water
virtual void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, const int soundID, bool selection, bool cancel) = 0; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID. virtual void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, const int soundID, bool selection, bool cancel) = 0; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID.
virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function<void()> &onEnd) = 0; //all stacks operations between these objects become allowed, interface has to call onEnd when done virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function<void()> &onEnd) = 0; //all stacks operations between these objects become allowed, interface has to call onEnd when done
virtual void showPuzzleMap(){};
virtual void tileHidden(const std::set<int3> &pos){}; virtual void tileHidden(const std::set<int3> &pos){};
virtual void tileRevealed(const std::set<int3> &pos){}; virtual void tileRevealed(const std::set<int3> &pos){};
virtual void newObject(const CGObjectInstance * obj){}; //eg. ship built in shipyard virtual void newObject(const CGObjectInstance * obj){}; //eg. ship built in shipyard
@ -98,6 +99,7 @@ public:
virtual void centerView (int3 pos, int focusTime){}; virtual void centerView (int3 pos, int focusTime){};
virtual void availableCreaturesChanged(const CGDwelling *town){}; virtual void availableCreaturesChanged(const CGDwelling *town){};
virtual void heroBonusChanged(const CGHeroInstance *hero, const HeroBonus &bonus, bool gain){};//if gain hero received bonus, else he lost it virtual void heroBonusChanged(const CGHeroInstance *hero, const HeroBonus &bonus, bool gain){};//if gain hero received bonus, else he lost it
virtual void playerBonusChanged(const HeroBonus &bonus, bool gain){};//if gain hero received bonus, else he lost it
virtual void requestRealized(PackageApplied *pa){}; virtual void requestRealized(PackageApplied *pa){};
virtual void heroExchangeStarted(si32 hero1, si32 hero2){}; virtual void heroExchangeStarted(si32 hero1, si32 hero2){};
virtual void objectPropertyChanged(const SetObjectProperty * sop){}; //eg. mine has been flagged virtual void objectPropertyChanged(const SetObjectProperty * sop){}; //eg. mine has been flagged

View File

@ -1,3 +1,42 @@
0.75 -> 0.8
GENERAL:
* Victory and loss conditions are supported. It's now possible to win or lose the game.
* Kingdom Overview screen is now available.
* Replaced TTF fonts with original ones.
ADVENTURE MAP:
* Implemented rivers animations (thx to GrayFace).
HERO:
* Partial implementation of scholar skill (spell exchange works, but no message).
TOWN:
* New left-bottom info panel functionalities.
TOWNS:
* new town structures supported:
- Ballista Yard
- Blood Obelisk
- Dwarven Treasury
- Glyphs of Fear
- Mystic Pond
- Thieves Guild
OBJECTS:
New objects supported:
- Border gate
- Den of Thieves
- Lighthouse
- Obelisk
- Quest Guard
- Seer hut
A lot of of various bugfixes and improvements:
http://vcmi.antypika.aplus.pl/bugs/view_all_bug_page.php?filter=699
0.74 -> 0.75 (Dec 01 2009) 0.74 -> 0.75 (Dec 01 2009)
GENERAL: GENERAL:
* Implemented "main menu" in-game option. * Implemented "main menu" in-game option.

View File

@ -2060,7 +2060,7 @@ CAdventureOptions::CAdventureOptions()
//viewWorld = new AdventureMapButton("","",boost::bind(&CGuiHandler::popIntTotally, &GH, this), 204, 313, "IOK6432.DEF",SDLK_RETURN); //viewWorld = new AdventureMapButton("","",boost::bind(&CGuiHandler::popIntTotally, &GH, this), 204, 313, "IOK6432.DEF",SDLK_RETURN);
puzzle = new AdventureMapButton("","", boost::bind(&CGuiHandler::popIntTotally, &GH, this), 24, 81, "ADVPUZ.DEF");; puzzle = new AdventureMapButton("","", boost::bind(&CGuiHandler::popIntTotally, &GH, this), 24, 81, "ADVPUZ.DEF");;
puzzle->callback += CAdventureOptions::showPuzzleMap; puzzle->callback += boost::bind(&CPlayerInterface::showPuzzleMap, LOCPLINT);
} }
CAdventureOptions::~CAdventureOptions() CAdventureOptions::~CAdventureOptions()
@ -2070,9 +2070,4 @@ CAdventureOptions::~CAdventureOptions()
void CAdventureOptions::showScenarioInfo() void CAdventureOptions::showScenarioInfo()
{ {
GH.pushInt(new CScenarioInfo(LOCPLINT->cb->getMapHeader(), LOCPLINT->cb->getStartInfo())); GH.pushInt(new CScenarioInfo(LOCPLINT->cb->getMapHeader(), LOCPLINT->cb->getStartInfo()));
} }
void CAdventureOptions::showPuzzleMap()
{
GH.pushInt(new CPuzzleWindow());
}

View File

@ -34,7 +34,6 @@ public:
CAdventureOptions(); CAdventureOptions();
~CAdventureOptions(); ~CAdventureOptions();
static void showScenarioInfo(); static void showScenarioInfo();
static void showPuzzleMap();
}; };

View File

@ -1169,6 +1169,8 @@ void CCastleInterface::CCreaInfo::clickRight(tribool down, bool previousState)
ch = ci->town->visitingHero; ch = ci->town->visitingHero;
}; };
//TODO player bonuses
if(bld.find(26)!=bld.end()) //grail - +50% to ALL growth if(bld.find(26)!=bld.end()) //grail - +50% to ALL growth
summ+=AddToString(CGI->buildh->buildings[ci->town->subID][26]->Name()+" %+d",descr,summ/2); summ+=AddToString(CGI->buildh->buildings[ci->town->subID][26]->Name()+" %+d",descr,summ/2);

View File

@ -230,7 +230,7 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details)
if(makingTurn && ho->tempOwner == playerID) //we are moving our hero - we may need to update assigned path if(makingTurn && ho->tempOwner == playerID) //we are moving our hero - we may need to update assigned path
{ {
if(details.result == TryMoveHero::TELEPORTATION || details.start == details.end) if(details.result == TryMoveHero::TELEPORTATION/* || details.start == details.end*/)
{ {
adventureInt->eraseCurrentPathOf(ho); adventureInt->eraseCurrentPathOf(ho);
return; //teleport - no fancy moving animation return; //teleport - no fancy moving animation
@ -1629,6 +1629,22 @@ void CPlayerInterface::gameOver(ui8 player, bool victory )
} }
} }
void CPlayerInterface::playerBonusChanged( const HeroBonus &bonus, bool gain )
{
}
void CPlayerInterface::showPuzzleMap()
{
waitWhileDialog();
//TODO: interface should not know the real position of Grail...
float ratio = 0;
int3 grailPos = cb->getGrailPos(ratio);
GH.pushInt(new CPuzzleWindow(grailPos, ratio));
}
void SystemOptions::setMusicVolume( int newVolume ) void SystemOptions::setMusicVolume( int newVolume )
{ {
musicVolume = newVolume; musicVolume = newVolume;

View File

@ -159,12 +159,14 @@ public:
void showShipyardDialog(const IShipyard *obj); //obj may be town or shipyard; void showShipyardDialog(const IShipyard *obj); //obj may be town or shipyard;
void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, int soundID, bool selection, bool cancel); //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID. void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, int soundID, bool selection, bool cancel); //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID.
void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function<void()> &onEnd); void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function<void()> &onEnd);
void showPuzzleMap();
void tileHidden(const std::set<int3> &pos); //called when given tiles become hidden under fog of war void tileHidden(const std::set<int3> &pos); //called when given tiles become hidden under fog of war
void tileRevealed(const std::set<int3> &pos); //called when fog of war disappears from given tiles void tileRevealed(const std::set<int3> &pos); //called when fog of war disappears from given tiles
void newObject(const CGObjectInstance * obj); void newObject(const CGObjectInstance * obj);
void yourTurn(); void yourTurn();
void availableCreaturesChanged(const CGDwelling *town); void availableCreaturesChanged(const CGDwelling *town);
void heroBonusChanged(const CGHeroInstance *hero, const HeroBonus &bonus, bool gain);//if gain hero received bonus, else he lost it void heroBonusChanged(const CGHeroInstance *hero, const HeroBonus &bonus, bool gain);//if gain hero received bonus, else he lost it
void playerBonusChanged(const HeroBonus &bonus, bool gain);
void requestRealized(PackageApplied *pa); void requestRealized(PackageApplied *pa);
void heroExchangeStarted(si32 hero1, si32 hero2); void heroExchangeStarted(si32 hero1, si32 hero2);
void centerView (int3 pos, int focusTime); void centerView (int3 pos, int focusTime);

View File

@ -4710,7 +4710,7 @@ CShipyardWindow::CShipyardWindow(const std::vector<si32> &cost, int state, const
printAtMiddle(CGI->generaltexth->jktexts[14], 164, 220, FONT_MEDIUM, zwykly, bg); //Resource cost: printAtMiddle(CGI->generaltexth->jktexts[14], 164, 220, FONT_MEDIUM, zwykly, bg); //Resource cost:
} }
CPuzzleWindow::CPuzzleWindow() CPuzzleWindow::CPuzzleWindow(const int3 &grailPos, float discoveredRatio)
:animCount(0) :animCount(0)
{ {
SDL_Surface * back = BitmapHandler::loadBitmap("PUZZLE.BMP", false); SDL_Surface * back = BitmapHandler::loadBitmap("PUZZLE.BMP", false);
@ -4728,19 +4728,17 @@ CPuzzleWindow::CPuzzleWindow()
//printing necessary thinks to background //printing necessary thinks to background
CGI->mh->terrainRect CGI->mh->terrainRect
(int3(14, 15, 0), LOCPLINT->adventureInt->anim, (grailPos, LOCPLINT->adventureInt->anim,
&LOCPLINT->cb->getVisibilityMap(), true, LOCPLINT->adventureInt->heroAnim, &LOCPLINT->cb->getVisibilityMap(), true, LOCPLINT->adventureInt->heroAnim,
background, &genRect(544, 591, 8, 8), 0, 0, true); background, &genRect(544, 591, 8, 8), 0, 0, true);
float discoveryRatio = 0.5f;
int faction = LOCPLINT->cb->getStartInfo()->playerInfos[LOCPLINT->serialID].castle; int faction = LOCPLINT->cb->getStartInfo()->playerInfos[LOCPLINT->serialID].castle;
std::vector<SPuzzleInfo> puzzlesToPrint; std::vector<SPuzzleInfo> puzzlesToPrint;
for(int g=0; g<PUZZLES_PER_FACTION; ++g) for(int g=0; g<PUZZLES_PER_FACTION; ++g)
{ {
if(CGI->heroh->puzzleInfo[faction][g].whenUncovered >= PUZZLES_PER_FACTION * discoveryRatio) if(CGI->heroh->puzzleInfo[faction][g].whenUncovered > PUZZLES_PER_FACTION * discoveredRatio)
{ {
puzzlesToPrint.push_back(CGI->heroh->puzzleInfo[faction][g]); puzzlesToPrint.push_back(CGI->heroh->puzzleInfo[faction][g]);
} }

View File

@ -825,7 +825,7 @@ public:
void deactivate(); void deactivate();
void show(SDL_Surface * to); void show(SDL_Surface * to);
CPuzzleWindow(); CPuzzleWindow(const int3 &grailPos, float discoveredRatio);
~CPuzzleWindow(); ~CPuzzleWindow();
}; };

View File

@ -109,9 +109,21 @@ void SetAvailableHeroes::applyCl( CClient *cl )
void GiveBonus::applyCl( CClient *cl ) void GiveBonus::applyCl( CClient *cl )
{ {
CGHeroInstance *h = GS(cl)->getHero(hid); switch(who)
if(vstd::contains(cl->playerint,h->tempOwner)) {
cl->playerint[h->tempOwner]->heroBonusChanged(h,h->bonuses.back(),true); case HERO:
{
const CGHeroInstance *h = GS(cl)->getHero(id);
INTERFACE_CALL_IF_PRESENT(h->tempOwner, heroBonusChanged, h, h->bonuses.back(),true);
}
break;
case PLAYER:
{
const PlayerState *p = GS(cl)->getPlayer(id);
INTERFACE_CALL_IF_PRESENT(id, playerBonusChanged, p->bonuses.back(), true);
}
break;
}
} }
void ChangeObjPos::applyFirstCl( CClient *cl ) void ChangeObjPos::applyFirstCl( CClient *cl )
@ -133,6 +145,25 @@ void PlayerEndsGame::applyCl( CClient *cl )
i->second->gameOver(player, victory); i->second->gameOver(player, victory);
} }
void RemoveBonus::applyCl( CClient *cl )
{
switch(who)
{
case HERO:
{
const CGHeroInstance *h = GS(cl)->getHero(id);
INTERFACE_CALL_IF_PRESENT(h->tempOwner, heroBonusChanged, h, bonus,false);
}
break;
case PLAYER:
{
const PlayerState *p = GS(cl)->getPlayer(id);
INTERFACE_CALL_IF_PRESENT(id, playerBonusChanged, bonus, false);
}
break;
}
}
void RemoveObject::applyFirstCl( CClient *cl ) void RemoveObject::applyFirstCl( CClient *cl )
{ {
const CGObjectInstance *o = cl->getObj(id); const CGObjectInstance *o = cl->getObj(id);
@ -635,6 +666,11 @@ void OpenWindow::applyCl(CClient *cl)
GH.pushInt( new CThievesGuildWindow(obj) ); GH.pushInt( new CThievesGuildWindow(obj) );
} }
break; break;
case PUZZLE_MAP:
{
INTERFACE_CALL_IF_PRESENT(id1, showPuzzleMap);
}
break;
} }
} }

View File

@ -253,4 +253,4 @@ GUISettings
ButtonEndTurn: x=1559 y=491 graphic=IAM001.DEF playerColoured=1; ButtonEndTurn: x=1559 y=491 graphic=IAM001.DEF playerColoured=1;
}; };
} }
} }

View File

@ -75,9 +75,10 @@ enum ECombatInfo{ALIVE = 180, SUMMONED, CLONED, HAD_MORALE, WAITING, MOVED, DEFE
class CGameInfo; class CGameInfo;
extern CGameInfo* CGI; extern CGameInfo* CGI;
#define HEROI_TYPE (34) const int HEROI_TYPE = 34,
#define TOWNI_TYPE (98) TOWNI_TYPE = 98,
#define CREI_TYPE (54) CREI_TYPE = 54,
EVENTI_TYPE = 26;
const int F_NUMBER = 9; //factions (town types) quantity const int F_NUMBER = 9; //factions (town types) quantity
const int PLAYER_LIMIT = 8; //player limit per map const int PLAYER_LIMIT = 8; //player limit per map
@ -265,6 +266,7 @@ t1 & amax(t1 &a, const t2 &b) //assigns greater of (a, b) to a and returns maxim
return a; return a;
} }
} }
template <typename t1, typename t2> template <typename t1, typename t2>
t1 & amin(t1 &a, const t2 &b) //assigns smaller of (a, b) to a and returns minimum of (a, b) t1 & amin(t1 &a, const t2 &b) //assigns smaller of (a, b) to a and returns minimum of (a, b)
{ {
@ -276,6 +278,15 @@ t1 & amin(t1 &a, const t2 &b) //assigns smaller of (a, b) to a and returns minim
return a; return a;
} }
} }
template <typename t1, typename t2, typename t3>
t1 & abetw(t1 &a, const t2 &b, const t3 &c) //makes a to fit the range <b, c>
{
amax(a,b);
amin(a,c);
return a;
}
#include "CConsoleHandler.h" #include "CConsoleHandler.h"
extern DLL_EXPORT std::ostream *logfile; extern DLL_EXPORT std::ostream *logfile;
extern DLL_EXPORT CConsoleHandler *console; extern DLL_EXPORT CConsoleHandler *console;

View File

@ -44,6 +44,9 @@ extern boost::rand48 ran;
std::map <ui8, std::set <ui8> > CGKeys::playerKeyMap; std::map <ui8, std::set <ui8> > CGKeys::playerKeyMap;
std::map <si32, std::vector<si32> > CGMagi::eyelist; std::map <si32, std::vector<si32> > CGMagi::eyelist;
BankConfig CGPyramid::pyramidConfig; BankConfig CGPyramid::pyramidConfig;
ui8 CGObelisk::obeliskCount; //how many obelisks are on map
std::map<ui8, ui8> CGObelisk::visited; //map: color_id => how many obelisks has been visited
void IObjectInterface::onHeroVisit(const CGHeroInstance * h) const void IObjectInterface::onHeroVisit(const CGHeroInstance * h) const
{}; {};
@ -429,7 +432,7 @@ void CGObjectInstance::giveDummyBonus(int heroID, ui8 duration) const
{ {
GiveBonus gbonus; GiveBonus gbonus;
gbonus.bonus.type = HeroBonus::NONE; gbonus.bonus.type = HeroBonus::NONE;
gbonus.hid = heroID; gbonus.id = heroID;
gbonus.bonus.duration = duration; gbonus.bonus.duration = duration;
gbonus.bonus.source = HeroBonus::OBJECT; gbonus.bonus.source = HeroBonus::OBJECT;
gbonus.bonus.id = ID; gbonus.bonus.id = ID;
@ -563,10 +566,8 @@ bool CGHeroInstance::canWalkOnSea() const
int CGHeroInstance::getPrimSkillLevel(int id) const int CGHeroInstance::getPrimSkillLevel(int id) const
{ {
int ret = primSkills[id]; int ret = primSkills[id];
for(std::list<HeroBonus>::const_iterator i=bonuses.begin(); i != bonuses.end(); i++) ret += valOfBonuses(HeroBonus::PRIMARY_SKILL, id);
if(i->type == HeroBonus::PRIMARY_SKILL && i->subtype==id) amax(ret, id/2); //minimal value is 0 for attack and defense and 1 for spell power and knowledge
ret += i->val;
amax(ret, id/2);//minimum value for attack and defense is 0 and for spell power and knowledge - 1
return ret; return ret;
} }
ui8 CGHeroInstance::getSecSkillLevel(const int & ID) const ui8 CGHeroInstance::getSecSkillLevel(const int & ID) const
@ -578,13 +579,21 @@ ui8 CGHeroInstance::getSecSkillLevel(const int & ID) const
} }
int CGHeroInstance::maxMovePoints(bool onLand) const int CGHeroInstance::maxMovePoints(bool onLand) const
{ {
static const int moveForSpeed[] = { 1500, 1560, 1630, 1700, 1760, 1830, 1900, 1960, 2000 }; //first element for 3 and lower; last for 11 and more int base = -1;
int index = lowestSpeed(this) - 3; if(onLand)
amin(index, ARRAY_COUNT(moveForSpeed)-1); {
amax(index, 0); static const int moveForSpeed[] = { 1500, 1560, 1630, 1700, 1760, 1830, 1900, 1960, 2000 }; //first element for 3 and lower; last for 11 and more
int index = lowestSpeed(this) - 3;
int ret = moveForSpeed[index], amin(index, ARRAY_COUNT(moveForSpeed)-1);
bonus = valOfBonuses(HeroBonus::MOVEMENT) + (onLand ? valOfBonuses(HeroBonus::LAND_MOVEMENT) : valOfBonuses(HeroBonus::SEA_MOVEMENT)); amax(index, 0);
base = moveForSpeed[index];
}
else
{
base = 1500; //on water base movement is always 1500 (speed of army doesn't matter)
}
int bonus = valOfBonuses(HeroBonus::MOVEMENT) + (onLand ? valOfBonuses(HeroBonus::LAND_MOVEMENT) : valOfBonuses(HeroBonus::SEA_MOVEMENT));
double modifier = 0; double modifier = 0;
if(onLand) if(onLand)
@ -619,7 +628,7 @@ int CGHeroInstance::maxMovePoints(bool onLand) const
break; break;
} }
} }
return int(ret + ret*modifier) + bonus; return int(base + base*modifier) + bonus;
} }
ui32 CGHeroInstance::getArtAtPos(ui16 pos) const ui32 CGHeroInstance::getArtAtPos(ui16 pos) const
@ -879,15 +888,7 @@ std::vector<std::pair<int,std::string> > CGHeroInstance::getCurrentMoraleModifie
{ {
//TODO: check if stack is undead/mechanic/elemental => always neutrl morale //TODO: check if stack is undead/mechanic/elemental => always neutrl morale
std::vector<std::pair<int,std::string> > ret; std::vector<std::pair<int,std::string> > ret;
getModifiersWDescr(ret, MORALE_AFFECTING);
//various morale bonuses (from buildings, artifacts, etc)
for(std::list<HeroBonus>::const_iterator i=bonuses.begin(); i != bonuses.end(); i++)
{
if(i->type == HeroBonus::MORALE || i->type == HeroBonus::MORALE_AND_LUCK)
{
ret.push_back(std::make_pair(i->val, i->description));
}
}
//leadership //leadership
if(getSecSkillLevel(6)) if(getSecSkillLevel(6))
@ -961,42 +962,29 @@ int CGHeroInstance::getCurrentLuck( int stack/*=-1*/, bool town/*=false*/ ) cons
std::vector<std::pair<int,std::string> > mods = getCurrentLuckModifiers(stack,town); std::vector<std::pair<int,std::string> > mods = getCurrentLuckModifiers(stack,town);
for(int i=0; i < mods.size(); i++) for(int i=0; i < mods.size(); i++)
ret += mods[i].first; ret += mods[i].first;
if(ret > 3)
return 3; abetw(ret, -3, 3);
if(ret < -3)
return -3;
return ret; return ret;
} }
std::vector<std::pair<int,std::string> > CGHeroInstance::getCurrentLuckModifiers( int stack/*=-1*/, bool town/*=false*/ ) const std::vector<std::pair<int,std::string> > CGHeroInstance::getCurrentLuckModifiers( int stack/*=-1*/, bool town/*=false*/ ) const
{ {
std::vector<std::pair<int,std::string> > ret; std::vector<std::pair<int,std::string> > ret;
getModifiersWDescr(ret, LUCK_AFFECTING);
//various morale bonuses (from buildings, artifacts, etc)
for(std::list<HeroBonus>::const_iterator i=bonuses.begin(); i != bonuses.end(); i++)
if(i->type == HeroBonus::LUCK || i->type == HeroBonus::MORALE_AND_LUCK)
ret.push_back(std::make_pair(i->val, i->description));
//luck skill //luck skill
if(getSecSkillLevel(9)) if(getSecSkillLevel(9))
ret.push_back(std::make_pair(getSecSkillLevel(9),VLC->generaltexth->arraytxt[73+getSecSkillLevel(9)])); ret.push_back(std::make_pair(getSecSkillLevel(9),VLC->generaltexth->arraytxt[73+getSecSkillLevel(9)]));
if(visitedTown) if(visitedTown && visitedTown->subID == 1 && vstd::contains(visitedTown->builtBuildings,21)) //rampart, fountain of fortune
{ ret.push_back(std::pair<int,std::string>(2,VLC->generaltexth->buildings[1][21].first + " +2"));
if(visitedTown->subID == 1 && vstd::contains(visitedTown->builtBuildings,21)) //castle, brotherhood of sword built
ret.push_back(std::pair<int,std::string>(2,VLC->generaltexth->buildings[1][21].first + " +2"));
}
return ret; return ret;
} }
const HeroBonus * CGHeroInstance::getBonus( int from, int id ) const const HeroBonus * CGHeroInstance::getBonus( int from, int id ) const
{ {
for (std::list<HeroBonus>::const_iterator i=bonuses.begin(); i!=bonuses.end(); i++) return bonuses.getBonus(from, id);
if(i->source == from && i->id == id)
return &*i;
return NULL;
} }
void CGHeroInstance::setPropertyDer( ui8 what, ui32 val ) void CGHeroInstance::setPropertyDer( ui8 what, ui32 val )
@ -1048,26 +1036,16 @@ bool CGHeroInstance::canCastThisSpell(const CSpell * spell) const
if(!getArt(17)) //if hero has no spellbook if(!getArt(17)) //if hero has no spellbook
return false; return false;
if(vstd::contains(spells, spell->id) //hero does not have this spell in spellbook if(vstd::contains(spells, spell->id) //hero has this spell in spellbook
|| (spell->air && hasBonusOfType(HeroBonus::AIR_SPELLS)) // this is air spell and hero can cast all air spells || (spell->air && hasBonusOfType(HeroBonus::AIR_SPELLS)) // this is air spell and hero can cast all air spells
|| (spell->fire && hasBonusOfType(HeroBonus::FIRE_SPELLS)) // this is fire spell and hero can cast all fire spells || (spell->fire && hasBonusOfType(HeroBonus::FIRE_SPELLS)) // this is fire spell and hero can cast all fire spells
|| (spell->water && hasBonusOfType(HeroBonus::WATER_SPELLS)) // this is water spell and hero can cast all water spells || (spell->water && hasBonusOfType(HeroBonus::WATER_SPELLS)) // this is water spell and hero can cast all water spells
|| (spell->earth && hasBonusOfType(HeroBonus::EARTH_SPELLS)) // this is earth spell and hero can cast all earth spells || (spell->earth && hasBonusOfType(HeroBonus::EARTH_SPELLS)) // this is earth spell and hero can cast all earth spells
|| hasBonusOfType(HeroBonus::SPELL, spell->id)
|| hasBonusOfType(HeroBonus::SPELLS_OF_LEVEL, spell->level)
) )
return true; return true;
for(std::list<HeroBonus>::const_iterator it = bonuses.begin(); it != bonuses.end(); ++it)
{
if(it->type == HeroBonus::SPELL && it->subtype == spell->id)
{
return true;
}
if(it->type == HeroBonus::SPELLS_OF_LEVEL && it->subtype == spell->level)
{
return true;
}
}
return false; return false;
} }
@ -1165,40 +1143,15 @@ si32 CGHeroInstance::manaRegain() const
int CGHeroInstance::valOfBonuses( HeroBonus::BonusType type, int subtype /*= -1*/ ) const int CGHeroInstance::valOfBonuses( HeroBonus::BonusType type, int subtype /*= -1*/ ) const
{ {
int ret = 0; return bonuses.valOfBonuses(type, subtype) + ownerBonuses()->valOfBonuses(type, subtype);
if(subtype == -1)
{
for(std::list<HeroBonus>::const_iterator i=bonuses.begin(); i != bonuses.end(); i++)
if(i->type == type)
ret += i->val;
}
else
{
for(std::list<HeroBonus>::const_iterator i=bonuses.begin(); i != bonuses.end(); i++)
if(i->type == type && i->subtype == subtype)
ret += i->val;
}
return ret;
} }
bool CGHeroInstance::hasBonusOfType(HeroBonus::BonusType type, int subtype /*= -1*/) const bool CGHeroInstance::hasBonusOfType(HeroBonus::BonusType type, int subtype /*= -1*/) const
{ {
if(!this) //to allow calls on NULL and avoid checking duplication if(!this) //to allow calls on NULL and avoid checking duplication
return false; //if hero doesn't exist then bonus neither can return false; //if hero doesn't exist then bonus neither can
else
if(subtype == -1) //any subtype return bonuses.hasBonusOfType(type, subtype) || ownerBonuses()->hasBonusOfType(type, subtype);
{
for(std::list<HeroBonus>::const_iterator i=bonuses.begin(); i != bonuses.end(); i++)
if(i->type == type)
return true;
}
else //given subtype
{
for(std::list<HeroBonus>::const_iterator i=bonuses.begin(); i != bonuses.end(); i++)
if(i->type == type && i->subtype == subtype)
return true;
}
return false;
} }
si32 CGHeroInstance::getArtPos(int aid) const si32 CGHeroInstance::getArtPos(int aid) const
@ -1252,6 +1205,21 @@ bool CGHeroInstance::hasArt( ui32 aid ) const
return false; return false;
} }
void CGHeroInstance::getModifiersWDescr( std::vector<std::pair<int,std::string> > &out, HeroBonus::BonusType type, int subtype /*= -1*/ ) const
{
bonuses.getModifiersWDescr(out, type, subtype);
ownerBonuses()->getModifiersWDescr(out, type, subtype);
}
const BonusList * CGHeroInstance::ownerBonuses() const
{
const PlayerState *p = cb->getPlayerState(tempOwner);
if(!p)
return NULL;
else
return &p->bonuses;
}
void CGDwelling::initObj() void CGDwelling::initObj()
{ {
switch(ID) switch(ID)
@ -2166,7 +2134,7 @@ void COPWBonus::onHeroVisit (const CGHeroInstance * h) const
{ {
GiveBonus gb; GiveBonus gb;
gb.bonus = HeroBonus(HeroBonus::ONE_WEEK, HeroBonus::LAND_MOVEMENT, HeroBonus::OBJECT, 600, 94, VLC->generaltexth->arraytxt[100]); gb.bonus = HeroBonus(HeroBonus::ONE_WEEK, HeroBonus::LAND_MOVEMENT, HeroBonus::OBJECT, 600, 94, VLC->generaltexth->arraytxt[100]);
gb.hid = heroID; gb.id = heroID;
cb->giveHeroBonus(&gb); cb->giveHeroBonus(&gb);
iw.text << VLC->generaltexth->allTexts[580]; iw.text << VLC->generaltexth->allTexts[580];
cb->showInfoDialog(&iw); cb->showInfoDialog(&iw);
@ -3632,7 +3600,7 @@ void CGSeerHut::completeQuest (const CGHeroInstance * h) const //reward
HeroBonus hb(HeroBonus::ONE_WEEK, (rewardType == 3 ? HeroBonus::MORALE : HeroBonus::LUCK), HeroBonus hb(HeroBonus::ONE_WEEK, (rewardType == 3 ? HeroBonus::MORALE : HeroBonus::LUCK),
HeroBonus::OBJECT, rVal, h->id, "", -1); HeroBonus::OBJECT, rVal, h->id, "", -1);
GiveBonus gb; GiveBonus gb;
gb.hid = h->id; gb.id = h->id;
gb.bonus = hb; gb.bonus = hb;
//gb.descr = ""; //gb.descr = "";
cb->giveHeroBonus(&gb); cb->giveHeroBonus(&gb);
@ -3752,7 +3720,7 @@ void CGBonusingObject::onHeroVisit( const CGHeroInstance * h ) const
InfoWindow iw; InfoWindow iw;
iw.player = h->tempOwner; iw.player = h->tempOwner;
GiveBonus gbonus; GiveBonus gbonus;
gbonus.hid = h->id; gbonus.id = h->id;
gbonus.bonus.duration = HeroBonus::ONE_BATTLE; gbonus.bonus.duration = HeroBonus::ONE_BATTLE;
gbonus.bonus.source = HeroBonus::OBJECT; gbonus.bonus.source = HeroBonus::OBJECT;
gbonus.bonus.id = ID; gbonus.bonus.id = ID;
@ -4121,7 +4089,7 @@ void CGPandoraBox::giveContents( const CGHeroInstance *h, bool afterBattle ) con
cb->showInfoDialog(&iw); cb->showInfoDialog(&iw);
GiveBonus gb; GiveBonus gb;
gb.bonus = HeroBonus(HeroBonus::ONE_BATTLE,HeroBonus::MORALE,HeroBonus::OBJECT,moraleDiff,id,""); gb.bonus = HeroBonus(HeroBonus::ONE_BATTLE,HeroBonus::MORALE,HeroBonus::OBJECT,moraleDiff,id,"");
gb.hid = h->id; gb.id = h->id;
cb->giveHeroBonus(&gb); cb->giveHeroBonus(&gb);
} }
@ -4132,7 +4100,7 @@ void CGPandoraBox::giveContents( const CGHeroInstance *h, bool afterBattle ) con
cb->showInfoDialog(&iw); cb->showInfoDialog(&iw);
GiveBonus gb; GiveBonus gb;
gb.bonus = HeroBonus(HeroBonus::ONE_BATTLE,HeroBonus::LUCK,HeroBonus::OBJECT,luckDiff,id,""); gb.bonus = HeroBonus(HeroBonus::ONE_BATTLE,HeroBonus::LUCK,HeroBonus::OBJECT,luckDiff,id,"");
gb.hid = h->id; gb.id = h->id;
cb->giveHeroBonus(&gb); cb->giveHeroBonus(&gb);
} }
@ -4688,7 +4656,7 @@ void CGOnceVisitable::searchTomb(const CGHeroInstance *h, ui32 accept) const
{ {
//ruin morale //ruin morale
GiveBonus gb; GiveBonus gb;
gb.hid = h->id; gb.id = h->id;
gb.bonus = HeroBonus(HeroBonus::ONE_BATTLE,HeroBonus::MORALE,HeroBonus::OBJECT,-3,id,""); gb.bonus = HeroBonus(HeroBonus::ONE_BATTLE,HeroBonus::MORALE,HeroBonus::OBJECT,-3,id,"");
gb.bdescr.addTxt(MetaString::ARRAY_TXT,104); //Warrior Tomb Visited -3 gb.bdescr.addTxt(MetaString::ARRAY_TXT,104); //Warrior Tomb Visited -3
cb->giveHeroBonus(&gb); cb->giveHeroBonus(&gb);
@ -4912,7 +4880,7 @@ void CBank::endBattle (const CGHeroInstance *h, const BattleResult *result) cons
{ {
iw.components.push_back (Component (Component::MORALE, 0 , -2, 0)); iw.components.push_back (Component (Component::MORALE, 0 , -2, 0));
GiveBonus gbonus; GiveBonus gbonus;
gbonus.hid = h->id; gbonus.id = h->id;
gbonus.bonus.duration = HeroBonus::ONE_BATTLE; gbonus.bonus.duration = HeroBonus::ONE_BATTLE;
gbonus.bonus.source = HeroBonus::OBJECT; gbonus.bonus.source = HeroBonus::OBJECT;
gbonus.bonus.id = ID; gbonus.bonus.id = ID;
@ -4931,7 +4899,7 @@ void CBank::endBattle (const CGHeroInstance *h, const BattleResult *result) cons
{ {
iw.components.push_back (Component (Component::MORALE, 0 , -1, 0)); iw.components.push_back (Component (Component::MORALE, 0 , -1, 0));
GiveBonus gbonus; GiveBonus gbonus;
gbonus.hid = h->id; gbonus.id = h->id;
gbonus.bonus.duration = HeroBonus::ONE_BATTLE; gbonus.bonus.duration = HeroBonus::ONE_BATTLE;
gbonus.bonus.source = HeroBonus::OBJECT; gbonus.bonus.source = HeroBonus::OBJECT;
gbonus.bonus.id = ID; gbonus.bonus.id = ID;
@ -5077,7 +5045,7 @@ void CGPyramid::onHeroVisit (const CGHeroInstance * h) const
iw.components.push_back (Component (Component::LUCK, 0 , -2, 0)); iw.components.push_back (Component (Component::LUCK, 0 , -2, 0));
GiveBonus gb; GiveBonus gb;
gb.bonus = HeroBonus(HeroBonus::ONE_BATTLE,HeroBonus::LUCK,HeroBonus::OBJECT,-2,id,VLC->generaltexth->arraytxt[70]); gb.bonus = HeroBonus(HeroBonus::ONE_BATTLE,HeroBonus::LUCK,HeroBonus::OBJECT,-2,id,VLC->generaltexth->arraytxt[70]);
gb.hid = h->id; gb.id = h->id;
cb->giveHeroBonus(&gb); cb->giveHeroBonus(&gb);
cb->showInfoDialog(&iw); cb->showInfoDialog(&iw);
} }
@ -5569,4 +5537,114 @@ void CGRefugeeCamp::reset(ui32 val)
void CGDenOfthieves::onHeroVisit (const CGHeroInstance * h) const void CGDenOfthieves::onHeroVisit (const CGHeroInstance * h) const
{ {
cb->showThievesGuildWindow(id); cb->showThievesGuildWindow(id);
}
void CGObelisk::onHeroVisit( const CGHeroInstance * h ) const
{
InfoWindow iw;
iw.player = h->tempOwner;
if(!hasVisited(h->tempOwner))
{
iw.text.addTxt(MetaString::ADVOB_TXT, 96);
cb->sendAndApply(&iw);
cb->setObjProperty(id,20,h->tempOwner); //increment general visited obelisks counter
OpenWindow ow;
ow.id1 = h->tempOwner;
ow.window = OpenWindow::PUZZLE_MAP;
cb->sendAndApply(&ow);
cb->setObjProperty(id,10,h->tempOwner); //mark that particular obelisk as visited
}
else
{
iw.text.addTxt(MetaString::ADVOB_TXT, 97);
cb->sendAndApply(&iw);
}
}
void CGObelisk::initObj()
{
obeliskCount++;
}
const std::string & CGObelisk::getHoverText() const
{
hoverName = VLC->generaltexth->names[ID];
if(hasVisited(cb->getCurrentPlayer()))
hoverName += " " + VLC->generaltexth->allTexts[352]; //not visited
else
hoverName += " " + VLC->generaltexth->allTexts[353]; //visited
return hoverName;
}
void CGObelisk::setPropertyDer( ui8 what, ui32 val )
{
CPlayersVisited::setPropertyDer(what, val);
switch(what)
{
case 20:
assert(val < PLAYER_LIMIT);
visited[val]++;
assert(visited[val] <= obeliskCount);
break;
}
}
void CGLighthouse::onHeroVisit( const CGHeroInstance * h ) const
{
if(h->tempOwner != tempOwner)
{
ui8 oldOwner = tempOwner;
cb->setOwner(id,h->tempOwner); //not ours? flag it!
InfoWindow iw;
iw.player = h->tempOwner;
iw.text.addTxt(MetaString::ADVOB_TXT, 69);
iw.soundID = soundBase::LIGHTHOUSE;
cb->sendAndApply(&iw);
giveBonusTo(h->tempOwner);
if(oldOwner < PLAYER_LIMIT) //remove bonus from old owner
{
RemoveBonus rb(RemoveBonus::PLAYER);
rb.whoID = oldOwner;
rb.source = HeroBonus::OBJECT;
rb.id = id;
cb->sendAndApply(&rb);
}
}
}
void CGLighthouse::initObj()
{
if(tempOwner < PLAYER_LIMIT)
{
giveBonusTo(tempOwner);
}
}
const std::string & CGLighthouse::getHoverText() const
{
hoverName = VLC->generaltexth->names[ID];
//TODO: owned by %s player
return hoverName;
}
void CGLighthouse::giveBonusTo( ui8 player ) const
{
GiveBonus gb(GiveBonus::PLAYER);
gb.bonus.type = HeroBonus::SEA_MOVEMENT;
gb.bonus.val = 500;
gb.id = player;
gb.bonus.duration = HeroBonus::PERMANENT;
gb.bonus.source = HeroBonus::OBJECT;
gb.bonus.id = id;
cb->sendAndApply(&gb);
} }

View File

@ -70,7 +70,7 @@ public:
} }
}; };
class CQuest class DLL_EXPORT CQuest
{ {
public: public:
enum Emission {MISSION_NONE = 0, MISSION_LEVEL = 1, MISSION_PRIMARY_STAT = 2, MISSION_KILL_HERO = 3, MISSION_KILL_CREATURE = 4, enum Emission {MISSION_NONE = 0, MISSION_LEVEL = 1, MISSION_PRIMARY_STAT = 2, MISSION_KILL_HERO = 3, MISSION_KILL_CREATURE = 4,
@ -267,7 +267,7 @@ public:
} }
} patrol; } patrol;
std::list<HeroBonus> bonuses; BonusList bonuses;
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -292,9 +292,7 @@ public:
int getSightRadious() const; //sight distance (should be used if player-owned structure) int getSightRadious() const; //sight distance (should be used if player-owned structure)
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
const HeroBonus *getBonus(int from, int id) const;
int valOfBonuses(HeroBonus::BonusType type, int subtype = -1) const; //subtype -> subtype of bonus, if -1 then any
bool hasBonusOfType(HeroBonus::BonusType type, int subtype = -1) const; //determines if hero has a bonus of given type (and optionally subtype)
const std::string &getBiography() const; const std::string &getBiography() const;
bool needsLastStack()const; bool needsLastStack()const;
unsigned int getTileCost(const TerrainTile &dest, const TerrainTile &from) const; //move cost - applying pathfinding skill, road and terrain modifiers. NOT includes diagonal move penalty, last move levelling unsigned int getTileCost(const TerrainTile &dest, const TerrainTile &from) const; //move cost - applying pathfinding skill, road and terrain modifiers. NOT includes diagonal move penalty, last move levelling
@ -304,6 +302,18 @@ public:
si32 manaRegain() const; //how many points of mana can hero regain "naturally" in one day si32 manaRegain() const; //how many points of mana can hero regain "naturally" in one day
bool canWalkOnSea() const; bool canWalkOnSea() const;
int getCurrentLuck(int stack=-1, bool town=false) const; int getCurrentLuck(int stack=-1, bool town=false) const;
const BonusList *ownerBonuses() const;
const HeroBonus *getBonus(int from, int id) const;
int valOfBonuses(HeroBonus::BonusType type, int subtype = -1) const; //subtype -> subtype of bonus, if -1 then any
bool hasBonusOfType(HeroBonus::BonusType type, int subtype = -1) const; //determines if hero has a bonus of given type (and optionally subtype)
void getModifiersWDescr(std::vector<std::pair<int,std::string> > &out, HeroBonus::BonusType type, int subtype = -1) const; //out: pairs<modifier value, modifier description>
template<int N> void getModifiersWDescr(std::vector<std::pair<int,std::string> > &out, const HeroBonus::BonusType (&types)[N]) const //retreive array of types
{
for (int i = 0; i < N; i++)
getModifiersWDescr(out, types[i]);
}
std::vector<std::pair<int,std::string> > getCurrentLuckModifiers(int stack=-1, bool town=false) const; //args as above std::vector<std::pair<int,std::string> > getCurrentLuckModifiers(int stack=-1, bool town=false) const; //args as above
int getCurrentMorale(int stack=-1, bool town=false) const; //if stack - position of creature, if -1 then morale for hero is calculated; town - if bonuses from town (tavern) should be considered int getCurrentMorale(int stack=-1, bool town=false) const; //if stack - position of creature, if -1 then morale for hero is calculated; town - if bonuses from town (tavern) should be considered
std::vector<std::pair<int,std::string> > getCurrentMoraleModifiers(int stack=-1, bool town=false) const; //args as above std::vector<std::pair<int,std::string> > getCurrentMoraleModifiers(int stack=-1, bool town=false) const; //args as above
@ -1078,6 +1088,37 @@ class DLL_EXPORT CGDenOfthieves : public CGObjectInstance
void onHeroVisit (const CGHeroInstance * h) const; void onHeroVisit (const CGHeroInstance * h) const;
}; };
class DLL_EXPORT CGObelisk : public CPlayersVisited
{
public:
static ui8 obeliskCount; //how many obelisks are on map
static std::map<ui8, ui8> visited; //map: color_id => how many obelisks has been visited
void setPropertyDer (ui8 what, ui32 val);
void onHeroVisit(const CGHeroInstance * h) const;
void initObj();
const std::string & getHoverText() const;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CPlayersVisited&>(*this);;
}
};
class DLL_EXPORT CGLighthouse : public CGObjectInstance
{
public:
void onHeroVisit(const CGHeroInstance * h) const;
void initObj();
const std::string & getHoverText() const;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CGObjectInstance&>(*this);;
}
void giveBonusTo( ui8 player ) const;
};
struct BankConfig struct BankConfig
{ {
BankConfig() {level = chance = upgradeChance = combatValue = value = rewardDifficulty = easiest = 0; }; BankConfig() {level = chance = upgradeChance = combatValue = value = rewardDifficulty = easiest = 0; };

View File

@ -1280,6 +1280,45 @@ void CGameState::init(StartInfo * si, Mapa * map, int Seed)
scenarioOps = si; scenarioOps = si;
this->map = map; this->map = map;
loadTownDInfos(); loadTownDInfos();
//pick grail location
if(map->grailPos.x < 0 || map->grailRadious) //grail not set or set within a radius around some place
{
if(!map->grailRadious) //radius not given -> anywhere on map
map->grailRadious = map->width * 2;
std::vector<int3> allowedPos;
// add all not blocked tiles in range
for (int i = 0; i < map->width ; i++)
{
for (int j = 0; j < map->height ; j++)
{
for (int k = 0; k <= map->twoLevel ; k++)
{
const TerrainTile &t = map->terrain[i][j][k];
if(!t.blocked
&& !t.visitable
&& t.tertype != TerrainTile::water
&& t.tertype != TerrainTile::rock
&& map->grailPos.dist2d(int3(i,j,k)) <= map->grailRadious)
allowedPos.push_back(int3(i,j,k));
}
}
}
//remove tiles with holes
for(unsigned int no=0; no<map->objects.size(); ++no)
if(map->objects[no]->ID == 124)
allowedPos -= map->objects[no]->pos;
if(allowedPos.size())
map->grailPos = allowedPos[ran() % allowedPos.size()];
else
tlog2 << "Warning: Grail cannot be placed, no appropriate tile found!\n";
}
//picking random factions for players //picking random factions for players
for(unsigned int i=0;i<scenarioOps->playerInfos.size();i++) for(unsigned int i=0;i<scenarioOps->playerInfos.size();i++)
{ {
@ -1293,11 +1332,12 @@ void CGameState::init(StartInfo * si, Mapa * map, int Seed)
scenarioOps->playerInfos[i].castle = f; scenarioOps->playerInfos[i].castle = f;
} }
} }
//randomizing objects //randomizing objects
for(unsigned int no=0; no<map->objects.size(); ++no) for(unsigned int no=0; no<map->objects.size(); ++no)
{ {
randomizeObject(map->objects[no]); randomizeObject(map->objects[no]);
if(map->objects[no]->ID==26) if(map->objects[no]->ID==EVENTI_TYPE)
{ {
map->objects[no]->defInfo->handler=NULL; map->objects[no]->defInfo->handler=NULL;
} }
@ -1940,7 +1980,7 @@ void CGameState::apply(CPack *pack)
applierGs->apps[typ]->applyOnGS(this,pack); applierGs->apps[typ]->applyOnGS(this,pack);
} }
PlayerState * CGameState::getPlayer( ui8 color ) PlayerState * CGameState::getPlayer( ui8 color, bool verbose )
{ {
if(vstd::contains(players,color)) if(vstd::contains(players,color))
{ {
@ -1948,14 +1988,15 @@ PlayerState * CGameState::getPlayer( ui8 color )
} }
else else
{ {
tlog2 << "Warning: Cannot find info for player " << int(color) << std::endl; if(verbose)
tlog2 << "Warning: Cannot find info for player " << int(color) << std::endl;
return NULL; return NULL;
} }
} }
const PlayerState * CGameState::getPlayer( ui8 color ) const const PlayerState * CGameState::getPlayer( ui8 color, bool verbose ) const
{ {
return (const_cast<CGameState *>(this))->getPlayer(color); return (const_cast<CGameState *>(this))->getPlayer(color, verbose);
} }
bool CGameState::getPath(int3 src, int3 dest, const CGHeroInstance * hero, CPath &ret) bool CGameState::getPath(int3 src, int3 dest, const CGHeroInstance * hero, CPath &ret)
@ -2163,7 +2204,7 @@ void CGameState::calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, int
node.accessible = CGPathNode::BLOCKVIS; node.accessible = CGPathNode::BLOCKVIS;
break; break;
} }
else if(obj->ID != 26) //pathfinder should ignore placed events else if(obj->ID != EVENTI_TYPE) //pathfinder should ignore placed events
{ {
node.accessible = CGPathNode::VISITABLE; node.accessible = CGPathNode::VISITABLE;
} }

View File

@ -11,6 +11,7 @@
#include <vector> #include <vector>
#include <list> #include <list>
#include "StackFeature.h" #include "StackFeature.h"
#include "HeroBonus.h"
#ifdef _WIN32 #ifdef _WIN32
#include <tchar.h> #include <tchar.h>
#else #else
@ -117,6 +118,7 @@ public:
std::vector<CGTownInstance *> towns; std::vector<CGTownInstance *> towns;
std::vector<CGHeroInstance *> availableHeroes; //heroes available in taverns std::vector<CGHeroInstance *> availableHeroes; //heroes available in taverns
std::vector<CGDwelling *> dwellings; //used for town growth std::vector<CGDwelling *> dwellings; //used for town growth
BonusList bonuses; //player bonuses
ui8 status; //0 - in game, 1 - loser, 2 - winner <- uses EStatus enum ui8 status; //0 - in game, 1 - loser, 2 - winner <- uses EStatus enum
ui8 daysWithoutCastle; ui8 daysWithoutCastle;
@ -126,7 +128,7 @@ public:
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {
h & color & serial & human & currentSelection & fogOfWarMap & resources & status; h & color & serial & human & currentSelection & fogOfWarMap & resources & status;
h & heroes & towns & availableHeroes & dwellings & status & daysWithoutCastle; h & heroes & towns & availableHeroes & dwellings & bonuses & status & daysWithoutCastle;
// ui32 size; // ui32 size;
// if(h.saving) //write subids of available heroes // if(h.saving) //write subids of available heroes
@ -405,8 +407,8 @@ public:
boost::shared_mutex *mx; boost::shared_mutex *mx;
PlayerState *getPlayer(ui8 color); PlayerState *getPlayer(ui8 color, bool verbose = true);
const PlayerState *getPlayer(ui8 color) const; const PlayerState *getPlayer(ui8 color, bool verbose = true) const;
void init(StartInfo * si, Mapa * map, int Seed); void init(StartInfo * si, Mapa * map, int Seed);
void loadTownDInfos(); void loadTownDInfos();
void randomizeObject(CGObjectInstance *cur); void randomizeObject(CGObjectInstance *cur);

73
lib/HeroBonus.cpp Normal file
View File

@ -0,0 +1,73 @@
#define VCMI_DLL
#include "HeroBonus.h"
int BonusList::valOfBonuses( HeroBonus::BonusType type, int subtype /*= -1*/ ) const /*subtype -> subtype of bonus, if -1 then any */
{
if(!this) //to avoid null-checking in maany places -> no bonus list means 0 bonus value
return 0;
int ret = 0;
if(subtype == -1)
{
for(const_iterator i = begin(); i != end(); i++)
if(i->type == type)
ret += i->val;
}
else
{
for(const_iterator i = begin(); i != end(); i++)
if(i->type == type && i->subtype == subtype)
ret += i->val;
}
return ret;
}
bool BonusList::hasBonusOfType( HeroBonus::BonusType type, int subtype /*= -1*/ ) const
{
if(!this) //to avoid null-checking in maany places -> no bonus list means there is no searched bonus
return 0;
if(subtype == -1) //any subtype
{
for(const_iterator i = begin(); i != end(); i++)
if(i->type == type)
return true;
}
else //given subtype
{
for(const_iterator i = begin(); i != end(); i++)
if(i->type == type && i->subtype == subtype)
return true;
}
return false;
}
const HeroBonus * BonusList::getBonus( int from, int id ) const
{
if(!this) //to avoid null-checking in maany places -> no bonus list means bonus cannot be retreived
return NULL;
for (const_iterator i = begin(); i != end(); i++)
if(i->source == from && i->id == id)
return &*i;
return NULL;
}
void BonusList::getModifiersWDescr( std::vector<std::pair<int,std::string> > &out, HeroBonus::BonusType type, int subtype /*= -1 */ ) const
{
if(!this) //to avoid null-checking in maany places -> no bonus list means nothing has to be done here
return;
if(subtype == -1)
{
for(const_iterator i = begin(); i != end(); i++)
if(i->type == type)
out.push_back(std::make_pair(i->val, i->description));
}
else
{
for(const_iterator i = begin(); i != end(); i++)
if(i->type == type && i->subtype == subtype)
out.push_back(std::make_pair(i->val, i->description));
}
}

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "../global.h" #include "../global.h"
#include <string> #include <string>
#include <list>
/* /*
* HeroBonus.h, part of VCMI engine * HeroBonus.h, part of VCMI engine
@ -75,6 +76,19 @@ struct DLL_EXPORT HeroBonus
{ {
subtype = -1; subtype = -1;
} }
// //comparison
// bool operator==(const HeroBonus &other)
// {
// return &other == this;
// //TODO: what is best logic for that?
// }
// bool operator<(const HeroBonus &other)
// {
// return &other < this;
// //TODO: what is best logic for that?
// }
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {
h & duration & type & subtype & source & val & id & description; h & duration & type & subtype & source & val & id & description;
@ -96,4 +110,23 @@ struct DLL_EXPORT HeroBonus
{ {
return hb.source==source && (id==0xffffff || hb.id==id); return hb.source==source && (id==0xffffff || hb.id==id);
} }
}; };
static const HeroBonus::BonusType MORALE_AFFECTING[] = {HeroBonus::LUCK, HeroBonus::MORALE_AND_LUCK};
static const HeroBonus::BonusType LUCK_AFFECTING[] = {HeroBonus::MORALE, HeroBonus::MORALE_AND_LUCK};
typedef std::vector<std::pair<int,std::string> > TModDescr; //modifiers values and their descriptions
class BonusList : public std::list<HeroBonus>
{
public:
int DLL_EXPORT valOfBonuses(HeroBonus::BonusType type, int subtype = -1) const; //subtype -> subtype of bonus, if -1 then any
bool DLL_EXPORT hasBonusOfType(HeroBonus::BonusType type, int subtype = -1) const;
const DLL_EXPORT HeroBonus * getBonus( int from, int id ) const;
void DLL_EXPORT getModifiersWDescr( std::vector<std::pair<int,std::string> > &out, HeroBonus::BonusType type, int subtype = -1 ) const;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<std::list<HeroBonus>&>(*this);
}
};

View File

@ -256,4 +256,9 @@ inline TerrainTile * IGameCallback::getTile( int3 pos )
if(!gs->map->isInTheMap(pos)) if(!gs->map->isInTheMap(pos))
return NULL; return NULL;
return &gs->map->getTile(pos); return &gs->map->getTile(pos);
}
const PlayerState * IGameCallback::getPlayerState( int color )
{
return gs->getPlayer(color, false);
} }

View File

@ -34,6 +34,7 @@ class CArtHandler;
class CArtifact; class CArtifact;
class CArmedInstance; class CArmedInstance;
struct TerrainTile; struct TerrainTile;
struct PlayerState;
class DLL_EXPORT IGameCallback class DLL_EXPORT IGameCallback
{ {
@ -63,6 +64,7 @@ public:
virtual void getAllowedSpells(std::vector<ui16> &out, ui16 level); virtual void getAllowedSpells(std::vector<ui16> &out, ui16 level);
virtual int3 getMapSize(); //returns size of the map virtual int3 getMapSize(); //returns size of the map
virtual TerrainTile * getTile(int3 pos); virtual TerrainTile * getTile(int3 pos);
virtual const PlayerState * getPlayerState(int color);
//do sth //do sth
virtual void changeSpells(int hid, bool give, const std::set<ui32> &spells)=0; virtual void changeSpells(int hid, bool give, const std::set<ui32> &spells)=0;

View File

@ -357,17 +357,24 @@ struct SetAvailableHeroes : public CPackForClient //113
struct GiveBonus : public CPackForClient //115 struct GiveBonus : public CPackForClient //115
{ {
GiveBonus(){type = 115;}; GiveBonus(ui8 Who = 0)
{
who = Who;
type = 115;
}
void applyCl(CClient *cl); void applyCl(CClient *cl);
DLL_EXPORT void applyGs(CGameState *gs); DLL_EXPORT void applyGs(CGameState *gs);
ui32 hid; enum {HERO, PLAYER};
ui8 who; //who receives bonus, uses enum above
ui32 id; //hero or player id
HeroBonus bonus; HeroBonus bonus;
MetaString bdescr; MetaString bdescr;
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {
h & bonus & hid & bdescr; h & bonus & id & bdescr & who;
} }
}; };
@ -408,6 +415,34 @@ struct PlayerEndsGame : public CPackForClient //117
}; };
struct RemoveBonus : public CPackForClient //118
{
RemoveBonus(ui8 Who = 0)
{
who = Who;
type = 118;
}
void applyCl(CClient *cl);
DLL_EXPORT void applyGs(CGameState *gs);
enum {HERO, PLAYER};
ui8 who; //who receives bonus, uses enum above
ui32 whoID; //hero or player id
//vars to identify bonus: its source
ui8 source;
ui32 id; //source id
//used locally: copy of removed bonus
HeroBonus bonus;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & source & id & who & whoID;
}
};
struct RemoveObject : public CPackForClient //500 struct RemoveObject : public CPackForClient //500
{ {
RemoveObject(){type = 500;}; RemoveObject(){type = 500;};
@ -573,7 +608,7 @@ struct OpenWindow : public CPackForClient //517
OpenWindow(){type = 517;}; OpenWindow(){type = 517;};
void applyCl(CClient *cl); void applyCl(CClient *cl);
enum EWindow {EXCHANGE_WINDOW, RECRUITMENT_FIRST, RECRUITMENT_ALL, SHIPYARD_WINDOW, THIEVES_GUILD}; enum EWindow {EXCHANGE_WINDOW, RECRUITMENT_FIRST, RECRUITMENT_ALL, SHIPYARD_WINDOW, THIEVES_GUILD, PUZZLE_MAP};
ui8 window; ui8 window;
ui32 id1, id2; ui32 id1, id2;

View File

@ -186,16 +186,32 @@ DLL_EXPORT void SetAvailableHeroes::applyGs( CGameState *gs )
DLL_EXPORT void GiveBonus::applyGs( CGameState *gs ) DLL_EXPORT void GiveBonus::applyGs( CGameState *gs )
{ {
CGHeroInstance *h = gs->getHero(hid); BonusList *bonuses = NULL;
h->bonuses.push_back(bonus); switch(who)
{
case HERO:
{
CGHeroInstance *h = gs->getHero(id);
assert(h);
bonuses = &h->bonuses;
}
break;
case PLAYER:
{
PlayerState *p = gs->getPlayer(id);
assert(p);
bonuses = &p->bonuses;
}
break;
}
bonuses->push_back(bonus);
std::string &descr = h->bonuses.back().description; std::string &descr = bonuses->back().description;
if(!bdescr.message.size() if(!bdescr.message.size()
&& bonus.source == HeroBonus::OBJECT && bonus.source == HeroBonus::OBJECT
&& (bonus.type == HeroBonus::LUCK || bonus.type == HeroBonus::MORALE || bonus.type == HeroBonus::MORALE_AND_LUCK) && (bonus.type == HeroBonus::LUCK || bonus.type == HeroBonus::MORALE || bonus.type == HeroBonus::MORALE_AND_LUCK)
&& gs->map->objects[bonus.id]->ID == 26) //it's morale/luck bonus from an event without description && gs->map->objects[bonus.id]->ID == EVENTI_TYPE) //it's morale/luck bonus from an event without description
{ {
descr = VLC->generaltexth->arraytxt[bonus.val > 0 ? 110 : 109]; //+/-%d Temporary until next battle" descr = VLC->generaltexth->arraytxt[bonus.val > 0 ? 110 : 109]; //+/-%d Temporary until next battle"
boost::replace_first(descr,"%d",boost::lexical_cast<std::string>(std::abs(bonus.val))); boost::replace_first(descr,"%d",boost::lexical_cast<std::string>(std::abs(bonus.val)));
@ -225,6 +241,21 @@ DLL_EXPORT void PlayerEndsGame::applyGs( CGameState *gs )
p->status = victory ? 2 : 1; p->status = victory ? 2 : 1;
} }
DLL_EXPORT void RemoveBonus::applyGs( CGameState *gs )
{
std::list<HeroBonus> &bonuses = (who == HERO ? gs->getHero(whoID)->bonuses : gs->getPlayer(whoID)->bonuses);
for(std::list<HeroBonus>::iterator i = bonuses.begin(); i != bonuses.end(); i++)
{
if(i->source == source && i->id == id)
{
bonus = *i; //backup bonus (to show to interfaces later)
bonuses.erase(i);
break;
}
}
}
DLL_EXPORT void RemoveObject::applyGs( CGameState *gs ) DLL_EXPORT void RemoveObject::applyGs( CGameState *gs )
{ {
CGObjectInstance *obj = gs->map->objects[id]; CGObjectInstance *obj = gs->map->objects[id];
@ -588,6 +619,10 @@ DLL_EXPORT void NewTurn::applyGs( CGameState *gs )
i->second.daysWithoutCastle = 0; i->second.daysWithoutCastle = 0;
else else
i->second.daysWithoutCastle++; i->second.daysWithoutCastle++;
i->second.bonuses.remove_if(HeroBonus::OneDay);
if(gs->getDate(1) == 7) //new week
i->second.bonuses.remove_if(HeroBonus::OneWeek);
} }
} }

View File

@ -60,6 +60,8 @@ void registerTypes1(Serializer &s)
s.template registerType<CGObjectInstance>(); s.template registerType<CGObjectInstance>();
s.template registerType<COPWBonus>(); s.template registerType<COPWBonus>();
s.template registerType<CGDenOfthieves>(); s.template registerType<CGDenOfthieves>();
s.template registerType<CGObelisk>();
s.template registerType<CGLighthouse>();
} }
template<typename Serializer> DLL_EXPORT template<typename Serializer> DLL_EXPORT
@ -82,6 +84,7 @@ void registerTypes2(Serializer &s)
s.template registerType<GiveBonus>(); s.template registerType<GiveBonus>();
s.template registerType<ChangeObjPos>(); s.template registerType<ChangeObjPos>();
s.template registerType<PlayerEndsGame>(); s.template registerType<PlayerEndsGame>();
s.template registerType<RemoveBonus>();
s.template registerType<RemoveObject>(); s.template registerType<RemoveObject>();
s.template registerType<TryMoveHero>(); s.template registerType<TryMoveHero>();
s.template registerType<SetGarrisons>(); s.template registerType<SetGarrisons>();

View File

@ -270,6 +270,10 @@
RelativePath="..\hch\CBuildingHandler.cpp" RelativePath="..\hch\CBuildingHandler.cpp"
> >
</File> </File>
<File
RelativePath="..\hch\CCampaignHandler.cpp"
>
</File>
<File <File
RelativePath="..\CConsoleHandler.cpp" RelativePath="..\CConsoleHandler.cpp"
> >
@ -314,6 +318,10 @@
RelativePath="..\hch\CTownHandler.cpp" RelativePath="..\hch\CTownHandler.cpp"
> >
</File> </File>
<File
RelativePath=".\HeroBonus.cpp"
>
</File>
<File <File
RelativePath=".\IGameCallback.cpp" RelativePath=".\IGameCallback.cpp"
> >
@ -356,6 +364,10 @@
RelativePath="..\hch\CBuildingHandler.h" RelativePath="..\hch\CBuildingHandler.h"
> >
</File> </File>
<File
RelativePath="..\hch\CCampaignHandler.h"
>
</File>
<File <File
RelativePath="..\CConsoleHandler.h" RelativePath="..\CConsoleHandler.h"
> >

View File

@ -529,6 +529,7 @@ void Mapa::addBlockVisTiles(CGObjectInstance * obj)
} }
} }
Mapa::Mapa(std::string filename) Mapa::Mapa(std::string filename)
:grailPos(-1, -1, -1)
{ {
int mapsize = 0; int mapsize = 0;
@ -1318,7 +1319,7 @@ void Mapa::readDefInfo( const unsigned char * bufor, int &i)
vinya->visitDir = 0xff; vinya->visitDir = 0xff;
} }
if(vinya->id == 26) if(vinya->id == EVENTI_TYPE)
std::memset(vinya->blockMap,255,6); std::memset(vinya->blockMap,255,6);
//calculating coverageMap //calculating coverageMap
@ -1353,7 +1354,7 @@ void Mapa::readObjects( const unsigned char * bufor, int &i)
switch(defInfo->id) switch(defInfo->id)
{ {
case 26: //for event objects case EVENTI_TYPE: //for event objects
{ {
CGEvent *evnt = new CGEvent(); CGEvent *evnt = new CGEvent();
nobj = evnt; nobj = evnt;
@ -1648,7 +1649,6 @@ void Mapa::readObjects( const unsigned char * bufor, int &i)
i+=3; i+=3;
break; break;
} }
case 42: //lighthouse
case 220://mine (?) case 220://mine (?)
{ {
nobj = new CGObjectInstance(); nobj = new CGObjectInstance();
@ -1911,11 +1911,23 @@ void Mapa::readObjects( const unsigned char * bufor, int &i)
nobj = new CGDenOfthieves(); nobj = new CGDenOfthieves();
break; break;
} }
case 57: //Obelisk
{
nobj = new CGObelisk();
break;
}
case 42: //Lighthouse
{
nobj = new CGLighthouse();
nobj->tempOwner = readNormalNr(bufor,i); i+=4;
break;
}
default: //any other object default: //any other object
{ {
nobj = new CGObjectInstance(); nobj = new CGObjectInstance();
break; break;
} }
} //end of main switch } //end of main switch
nobj->pos = pos; nobj->pos = pos;

View File

@ -375,12 +375,13 @@ struct DLL_EXPORT Mapa : public CMapHeader
objects.resize(hlp); objects.resize(hlp);
} }
//static structures //static members
h & CGTeleport::objs; h & CGTeleport::objs;
h & CGTeleport::gates; h & CGTeleport::gates;
h & CGKeys::playerKeyMap; h & CGKeys::playerKeyMap;
h & CGMagi::eyelist; h & CGMagi::eyelist;
h & CGPyramid::pyramidConfig; h & CGPyramid::pyramidConfig;
h & CGObelisk::obeliskCount & CGObelisk::visited;
for(unsigned int i=0; i<objects.size(); i++) for(unsigned int i=0; i<objects.size(); i++)
{ {

View File

@ -301,7 +301,7 @@ void CMapHandler::initObjectRects()
} }
static void processDef (CGDefInfo* def) static void processDef (CGDefInfo* def)
{ {
if(def->id == 26) //if it's event, return from function if(def->id == EVENTI_TYPE)
return; return;
if(!def->handler) //if object has already set handler (eg. heroes) it should not be overwritten if(!def->handler) //if object has already set handler (eg. heroes) it should not be overwritten

View File

@ -856,6 +856,9 @@ void CGameHandler::newTurn()
for(std::list<HeroBonus>::iterator j = h->bonuses.begin(); j != h->bonuses.end(); j++) for(std::list<HeroBonus>::iterator j = h->bonuses.begin(); j != h->bonuses.end(); j++)
if(j->type == HeroBonus::GENERATE_RESOURCE) if(j->type == HeroBonus::GENERATE_RESOURCE)
n.res[i->first][j->subtype] += j->val; n.res[i->first][j->subtype] += j->val;
//TODO player bonuses
} }
} }
//n.res.push_back(r); //n.res.push_back(r);
@ -1276,7 +1279,7 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet
{ {
GiveBonus gs; GiveBonus gs;
gs.bonus = HeroBonus(HeroBonus::ONE_BATTLE, HeroBonus::PRIMARY_SKILL, HeroBonus::OBJECT, val, -1, "", i); gs.bonus = HeroBonus(HeroBonus::ONE_BATTLE, HeroBonus::PRIMARY_SKILL, HeroBonus::OBJECT, val, -1, "", i);
gs.hid = hero2->id; gs.id = hero2->id;
sendAndApply(&gs); sendAndApply(&gs);
} }
} }
@ -1334,7 +1337,7 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet
GiveBonus gs; GiveBonus gs;
gs.bonus = HeroBonus(HeroBonus::ONE_BATTLE, HeroBonus::MAGIC_SCHOOL_SKILL, HeroBonus::OBJECT, 3, -1, "", bonusSubtype); gs.bonus = HeroBonus(HeroBonus::ONE_BATTLE, HeroBonus::MAGIC_SCHOOL_SKILL, HeroBonus::OBJECT, 3, -1, "", bonusSubtype);
gs.hid = cHero->id; gs.id = cHero->id;
sendAndApply(&gs); sendAndApply(&gs);
} }
@ -1393,7 +1396,7 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet
GiveBonus gs; GiveBonus gs;
gs.bonus = HeroBonus(HeroBonus::ONE_BATTLE, HeroBonus::BLOCK_SPELLS_ABOVE_LEVEL, HeroBonus::OBJECT, 1, -1, "", bonusSubtype); gs.bonus = HeroBonus(HeroBonus::ONE_BATTLE, HeroBonus::BLOCK_SPELLS_ABOVE_LEVEL, HeroBonus::OBJECT, 1, -1, "", bonusSubtype);
gs.hid = cHero->id; gs.id = cHero->id;
sendAndApply(&gs); sendAndApply(&gs);
} }
@ -1612,7 +1615,13 @@ bool CGameHandler::moveHero( si32 hid, int3 dst, ui8 instant, ui8 asker /*= 255*
//call objects if they are visited //call objects if they are visited
if(t.visitableObjects.size()) if(t.visitableObjects.size())
objectVisited(t.visitableObjects.back(), h); {
//to prevent self-visiting heroes on space press
if(t.visitableObjects.back() != h)
objectVisited(t.visitableObjects.back(), h);
else if(t.visitableObjects.size() > 1)
objectVisited(*(t.visitableObjects.end()-2),h);
}
// BOOST_FOREACH(CGObjectInstance *obj, t.visitableObjects) // BOOST_FOREACH(CGObjectInstance *obj, t.visitableObjects)
// { // {
// objectVisited(obj, h); // objectVisited(obj, h);