1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-26 22:57:00 +02:00

* morale/luck support in battles

* minor improvements/fixes
* updated changelog
More objects supported:
 *	Faerie Ring
 *	Swan Pond
 *	Idol of Fortune
 *	Fountain of Fortune
 *	Rally Flag
 *	Oasis
 *	Temple
 *	Watering Hole
 *	Fountain of Youth
This commit is contained in:
Michał W. Urbańczyk 2009-02-05 09:49:45 +00:00
parent 218a3beaf6
commit e1d6ff54d7
15 changed files with 325 additions and 113 deletions

View File

@ -23,6 +23,7 @@ struct BattleResult;
struct BattleAttack; struct BattleAttack;
struct BattleStackAttacked; struct BattleStackAttacked;
struct SpellCasted; struct SpellCasted;
struct HeroBonus;
class CObstacle class CObstacle
{ {
int ID; int ID;
@ -67,6 +68,7 @@ public:
virtual void tileRevealed(const std::set<int3> &pos){}; virtual void tileRevealed(const std::set<int3> &pos){};
virtual void yourTurn(){}; virtual void yourTurn(){};
virtual void availableCreaturesChanged(const CGTownInstance *town){}; virtual void availableCreaturesChanged(const CGTownInstance *town){};
virtual void heroBonusChanged(const CGHeroInstance *hero, const HeroBonus &bonus, bool gain){};//if gain hero received bonus, else he lost it
//battle call-ins //battle call-ins
virtual void actionFinished(const BattleAction *action){};//occurs AFTER every action taken by any stack or by the hero virtual void actionFinished(const BattleAction *action){};//occurs AFTER every action taken by any stack or by the hero

View File

@ -362,6 +362,20 @@ const CStack::StackEffect * CStack::getEffect(ui16 id) const
return &effects[i]; return &effects[i];
return NULL; return NULL;
} }
si8 CStack::Morale() const
{
si8 ret = morale;
//premies from spells/other effects
return ret;
}
si8 CStack::Luck() const
{
si8 ret = luck;
//premies from spells/other effects
return ret;
}
CGHeroInstance* CGameState::HeroesPool::pickHeroFor(bool native, int player, const CTown *town, int notThatOne) CGHeroInstance* CGameState::HeroesPool::pickHeroFor(bool native, int player, const CTown *town, int notThatOne)
{ {
if(player<0 || player>=PLAYER_LIMIT) if(player<0 || player>=PLAYER_LIMIT)
@ -781,14 +795,14 @@ void CGameState::applyNL(IPack * pack)
{ {
BattleSetActiveStack *ns = static_cast<BattleSetActiveStack*>(pack); BattleSetActiveStack *ns = static_cast<BattleSetActiveStack*>(pack);
curB->activeStack = ns->stack; curB->activeStack = ns->stack;
CStack *st = curB->getStack(ns->stack);
if(vstd::contains(st->state,MOVED))
st->state.insert(HAD_MORALE);
break; break;
} }
case 3003: case 3003:
{ {
BattleResult *br = static_cast<BattleResult*>(pack); BattleResult *br = static_cast<BattleResult*>(pack);
//TODO: give exp, artifacts to winner, decrease armies (casualties)
for(unsigned i=0;i<curB->stacks.size();i++) for(unsigned i=0;i<curB->stacks.size();i++)
delete curB->stacks[i]; delete curB->stacks[i];
delete curB; delete curB;
@ -834,7 +848,7 @@ void CGameState::applyNL(IPack * pack)
case 8: case 8:
st->state.insert(WAITING); st->state.insert(WAITING);
break; break;
case 2: case 6: case 7: case 9: case 10: case 2: case 6: case 7: case 9: case 10: case 11:
st->state.insert(MOVED); st->state.insert(MOVED);
break; break;
} }

View File

@ -127,6 +127,7 @@ public:
ui16 position; //position on battlefield ui16 position; //position on battlefield
ui8 counterAttacks; //how many counter attacks can be performed more in this turn (by default set at the beginning of the round to 1) ui8 counterAttacks; //how many counter attacks can be performed more in this turn (by default set at the beginning of the round to 1)
si16 shots; //how many shots left si16 shots; //how many shots left
si8 morale, luck; //base stack luck/morale
std::set<EAbilities> abilities; std::set<EAbilities> abilities;
std::set<ECombatInfo> state; std::set<ECombatInfo> state;
@ -146,6 +147,8 @@ public:
CStack() : creature(NULL),amount(-1),owner(255), position(-1), ID(-1), attackerOwned(true), firstHPleft(-1), slot(255), baseAmount(-1), counterAttacks(1), effects(), state(), abilities(){} CStack() : creature(NULL),amount(-1),owner(255), position(-1), ID(-1), attackerOwned(true), firstHPleft(-1), slot(255), baseAmount(-1), counterAttacks(1), effects(), state(), abilities(){}
const StackEffect * getEffect(ui16 id) const; //effect id (SP) const StackEffect * getEffect(ui16 id) const; //effect id (SP)
ui32 speed() const; ui32 speed() const;
si8 Morale() const;
si8 Luck() const;
template <typename Handler> void save(Handler &h, const int version) template <typename Handler> void save(Handler &h, const int version)
{ {
h & creature->idNumber; h & creature->idNumber;
@ -160,7 +163,7 @@ public:
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {
h & ID & amount & baseAmount & firstHPleft & owner & slot & attackerOwned & position & state & counterAttacks h & ID & amount & baseAmount & firstHPleft & owner & slot & attackerOwned & position & state & counterAttacks
& shots; & shots & morale & luck;
if(h.saving) if(h.saving)
save(h,version); save(h,version);
else else

View File

@ -462,8 +462,8 @@ void CHeroWindow::deactivate()
portraitArea->deactivate(); portraitArea->deactivate();
expArea->deactivate(); expArea->deactivate();
spellPointsArea->deactivate(); spellPointsArea->deactivate();
morale->activate(); morale->deactivate();
luck->activate(); luck->deactivate();
garInt->deactivate(); garInt->deactivate();

View File

@ -1887,19 +1887,12 @@ int3 CPlayerInterface::repairScreenPos(int3 pos)
void CPlayerInterface::heroPrimarySkillChanged(const CGHeroInstance * hero, int which, int val) void CPlayerInterface::heroPrimarySkillChanged(const CGHeroInstance * hero, int which, int val)
{ {
boost::unique_lock<boost::recursive_mutex> un(*pim); boost::unique_lock<boost::recursive_mutex> un(*pim);
SDL_FreeSurface(graphics->heroWins[hero->subID]);//TODO: moznaby zmieniac jedynie fragment bitmapy zwiazany z dana umiejetnoscia redrawHeroWin(hero);
graphics->heroWins[hero->subID] = infoWin(hero); //a nie przerysowywac calosc. Troche roboty, obecnie chyba nie wartej swieczki.
if (adventureInt->selection == hero)
adventureInt->infoBar.draw();
return;
} }
void CPlayerInterface::heroManaPointsChanged(const CGHeroInstance * hero) void CPlayerInterface::heroManaPointsChanged(const CGHeroInstance * hero)
{ {
boost::unique_lock<boost::recursive_mutex> un(*pim); boost::unique_lock<boost::recursive_mutex> un(*pim);
SDL_FreeSurface(graphics->heroWins[hero->subID]);//TODO: moznaby zmieniac jedynie fragment bitmapy zwiazany z dana umiejetnoscia redrawHeroWin(hero);
graphics->heroWins[hero->subID] = infoWin(hero); //a nie przerysowywac calosc. Troche roboty, obecnie chyba nie wartej swieczki.
if (adventureInt->selection == hero)
adventureInt->infoBar.draw();
} }
void CPlayerInterface::heroMovePointsChanged(const CGHeroInstance * hero) void CPlayerInterface::heroMovePointsChanged(const CGHeroInstance * hero)
{ {
@ -2079,10 +2072,13 @@ void CPlayerInterface::actionStarted(const BattleAction* action)
{ {
battleInt->creAnims[action->stackNumber]->setType(20); battleInt->creAnims[action->stackNumber]->setType(20);
} }
//if((action->actionType==2 || (action->actionType==6 && action->destinationTile!=cb->battleGetPos(action->stackNumber)))) //deactivating interface when move is started
{
battleInt->deactivate(); battleInt->deactivate();
}
CStack *stack = cb->battleGetStackByID(action->stackNumber);
char txt[400];
if(action->actionType == 1) if(action->actionType == 1)
{ {
if(action->side) if(action->side)
@ -2090,48 +2086,37 @@ void CPlayerInterface::actionStarted(const BattleAction* action)
else else
battleInt->attackingHero->setPhase(4); battleInt->attackingHero->setPhase(4);
} }
if(action->actionType == 3) //defend if(!stack)
{ {
char txt[2000]; tlog1<<"Something wrong with stackNumber in actionStarted"<<std::endl;
CStack * stack = cb->battleGetStackByID(action->stackNumber); return;
if(stack)
{
if(stack->amount == 1)
{
sprintf(txt, CGI->generaltexth->allTexts[120].c_str(), stack->creature->nameSing.c_str(), 0);
} }
else
int txtid = 0;
switch(action->actionType)
{ {
sprintf(txt, CGI->generaltexth->allTexts[121].c_str(), stack->creature->namePl.c_str(), 0); case 3: //defend
txtid = 120;
break;
case 8: //wait
txtid = 136;
break;
case 11: //bad morale
txtid = -34; //negative -> no separate singular/plural form
battleInt->displayEffect(30,stack->position);
break;
} }
if(txtid > 0 && stack->amount != 1)
txtid++; //move to plural text
else if(txtid < 0)
txtid = -txtid;
if(txtid)
{
sprintf(txt, CGI->generaltexth->allTexts[txtid].c_str(), (stack->amount != 1) ? stack->creature->namePl.c_str() : stack->creature->nameSing.c_str(), 0);
LOCPLINT->battleInt->console->addText(txt); LOCPLINT->battleInt->console->addText(txt);
} }
else
{
tlog1<<"Somthing wrong with stackNumber in actionStarted -> actionType 3"<<std::endl;
}
}
if(action->actionType == 8) //wait
{
char txt[2000];
CStack * stack = cb->battleGetStackByID(action->stackNumber);
if(stack)
{
if(stack->amount == 1)
{
sprintf(txt, CGI->generaltexth->allTexts[136].c_str(), stack->creature->nameSing.c_str());
}
else
{
sprintf(txt, CGI->generaltexth->allTexts[137].c_str(), stack->creature->namePl.c_str());
}
LOCPLINT->battleInt->console->addText(txt);
}
else
{
tlog1<<"Somthing wrong with stackNumber in actionStarted -> actionType 8"<<std::endl;
}
}
} }
void CPlayerInterface::actionFinished(const BattleAction* action) void CPlayerInterface::actionFinished(const BattleAction* action)
@ -2156,6 +2141,16 @@ BattleAction CPlayerInterface::activeStack(int stackID) //called when it's turn
CBattleInterface *b = battleInt; CBattleInterface *b = battleInt;
{ {
boost::unique_lock<boost::recursive_mutex> un(*pim); boost::unique_lock<boost::recursive_mutex> un(*pim);
CStack *stack = cb->battleGetStackByID(stackID);
if(vstd::contains(stack->state,MOVED)) //this stack has moved and makes second action -> high morale
{
std::string hlp = CGI->generaltexth->allTexts[33];
boost::algorithm::replace_first(hlp,"%s",(stack->amount != 1) ? stack->creature->namePl : stack->creature->nameSing);
battleInt->displayEffect(20,stack->position);
battleInt->console->addText(hlp);
}
b->stackActivated(stackID); b->stackActivated(stackID);
} }
//wait till BattleInterface sets its command //wait till BattleInterface sets its command
@ -2215,14 +2210,18 @@ void CPlayerInterface::battleStackAttacked(BattleStackAttacked * bsa)
void CPlayerInterface::battleAttack(BattleAttack *ba) void CPlayerInterface::battleAttack(BattleAttack *ba)
{ {
boost::unique_lock<boost::recursive_mutex> un(*pim); boost::unique_lock<boost::recursive_mutex> un(*pim);
if(ba->bsa.lucky()) //lucky hit
{
CStack *stack = cb->battleGetStackByID(ba->stackAttacking);
std::string hlp = CGI->generaltexth->allTexts[45];
boost::algorithm::replace_first(hlp,"%s",(stack->amount != 1) ? stack->creature->namePl.c_str() : stack->creature->nameSing.c_str());
battleInt->console->addText(hlp);
battleInt->displayEffect(18,stack->position);
}
if(ba->shot()) if(ba->shot())
battleInt->stackIsShooting(ba->stackAttacking,cb->battleGetPos(ba->bsa.stackAttacked)); battleInt->stackIsShooting(ba->stackAttacking,cb->battleGetPos(ba->bsa.stackAttacked));
else else
battleInt->stackAttacking( ba->stackAttacking, ba->counter() ? curAction->destinationTile : curAction->additionalInfo ); battleInt->stackAttacking( ba->stackAttacking, ba->counter() ? curAction->destinationTile : curAction->additionalInfo );
/*if(ba->killed())
battleInt->stackKilled(ba->bsa.stackAttacked, ba->bsa.damageAmount, ba->bsa.killedAmount, ba->stackAttacking, ba->shot());
else
battleInt->stackIsAttacked(ba->bsa.stackAttacked, ba->bsa.damageAmount, ba->bsa.killedAmount, ba->stackAttacking, ba->shot());*/
} }
void CPlayerInterface::showComp(SComponent comp) void CPlayerInterface::showComp(SComponent comp)
{ {
@ -2359,6 +2358,21 @@ void CPlayerInterface::availableCreaturesChanged( const CGTownInstance *town )
fs->draw(castleInt,false); fs->draw(castleInt,false);
} }
} }
void CPlayerInterface::heroBonusChanged( const CGHeroInstance *hero, const HeroBonus &bonus, bool gain )
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
redrawHeroWin(hero);
}
void CPlayerInterface::redrawHeroWin(const CGHeroInstance * hero)
{
SDL_FreeSurface(graphics->heroWins[hero->subID]);
graphics->heroWins[hero->subID] = infoWin(hero);
if (adventureInt->selection == hero)
adventureInt->infoBar.draw();
}
CStatusBar::CStatusBar(int x, int y, std::string name, int maxw) CStatusBar::CStatusBar(int x, int y, std::string name, int maxw)
{ {
bg=BitmapHandler::loadBitmap(name); bg=BitmapHandler::loadBitmap(name);

View File

@ -380,6 +380,7 @@ public:
void tileRevealed(const std::set<int3> &pos); void tileRevealed(const std::set<int3> &pos);
void yourTurn(); void yourTurn();
void availableCreaturesChanged(const CGTownInstance *town); void availableCreaturesChanged(const CGTownInstance *town);
void heroBonusChanged(const CGHeroInstance *hero, const HeroBonus &bonus, bool gain);//if gain hero received bonus, else he lost it
//for battles //for battles
void actionFinished(const BattleAction* action);//occurs AFTER action taken by active stack or by the hero void actionFinished(const BattleAction* action);//occurs AFTER action taken by active stack or by the hero
void actionStarted(const BattleAction* action);//occurs BEFORE action taken by active stack or by the hero void actionStarted(const BattleAction* action);//occurs BEFORE action taken by active stack or by the hero
@ -396,6 +397,7 @@ public:
//-------------// //-------------//
void redrawHeroWin(const CGHeroInstance * hero);
void updateWater(); void updateWater();
void showComp(SComponent comp); void showComp(SComponent comp);
void openTownWindow(const CGTownInstance * town); //shows townscreen void openTownWindow(const CGTownInstance * town); //shows townscreen

View File

@ -1,22 +1,51 @@
0.64 -> 0.next (???) [as for r689] 0.7 -> 0.71 (as for r707)
GENERAL:
* morale/luck system and corresponding sec. skills supported
* fixed crash when hero get level and has less than two sec. skills to choose between
ADVENTURE INTERFACE:
* added missing path arrows
* corrected centering on hero's position
BATTLES:
* spell books won't be placed in War Machine slots after battle
TOWN INTERFACE:
* Rampart's Treasury requires Miner's Guild
OBJECTS:
New objects supported:
* Faerie Ring
* Swan Pond
* Idol of Fortune
* Fountain of Fortune
* Rally Flag
* Oasis
* Temple
* Watering Hole
* Fountain of Youth
0.64 -> 0.7 (Feb 01 2009)
GENERAL: GENERAL:
* move some settings to the config/settings.txt file * move some settings to the config/settings.txt file
* partial support for new screen resolutions * partial support for new screen resolutions
* it's possible to set game resolution in pregame (type 'resolution' in the console)
* /Data and /Sprites subfolders can be used for adding files not present in .lod archives * /Data and /Sprites subfolders can be used for adding files not present in .lod archives
* fixed crashbug occuring when hero levelled above 15 level * fixed crashbug occuring when hero levelled above 15 level
* support for non-standard screen resolutions * support for non-standard screen resolutions
* F4 toggles between full-screen and windowed mode (experimental) * F4 toggles between full-screen and windowed mode
* splitting stacks the shift+click
* minor improvements in creature card window * minor improvements in creature card window
* splitting stacks with the shift+click
* creature card window contains info about modified speed
ADVENTURE INTERFACE: ADVENTURE INTERFACE:
* smooth map scrolling on hero movement
* added water animation * added water animation
* speed of scrolling map and hero movement can be adjusted in the System Options Window * speed of scrolling map and hero movement can be adjusted in the System Options Window
* partial handling r-clicks on adventure map * partial handling r-clicks on adventure map
TOWN INTERFACE: TOWN INTERFACE:
* the scroll tab won't remain hanged to our mouse position if we move the mouse away from the scroll bar * the scroll tab won't remain hanged to our mouse position if we move the mouse is away from the scroll bar
* fixed cloning creatures bug in garrisons (and related issues) * fixed cloning creatures bug in garrisons (and related issues)
BATTLES BATTLES
@ -31,21 +60,21 @@ BATTLES
* battle console displays notifications about wait/defend commands * battle console displays notifications about wait/defend commands
* several reported bugs fixed * several reported bugs fixed
* new spells supported: * new spells supported:
a) Haste a) Haste
b) lightning bolt b) lightning bolt
c) ice bolt c) ice bolt
d) slow d) slow
e) implosion e) implosion
f) forgetfulness f) forgetfulness
g) shield g) shield
h) air shield h) air shield
i) bless i) bless
j) curse j) curse
k) bloodlust k) bloodlust
l) weakness l) weakness
m) stone skin m) stone skin
n) prayer n) prayer
o) frenzy o) frenzy
AI PLAYER: AI PLAYER:
* Genius AI (first VCMI AI) will control computer creatures during the combat. * Genius AI (first VCMI AI) will control computer creatures during the combat.
@ -54,9 +83,11 @@ OBJECTS:
* Guardians property for resources is handled * Guardians property for resources is handled
* support for Witch Hut * support for Witch Hut
* support for Arena * support for Arena
* support for Library of Enlightenment
And a lot of minor fixes And a lot of minor fixes
0.63 -> 0.64 (Nov 01 2008) 0.63 -> 0.64 (Nov 01 2008)
GENERAL: GENERAL:
* sprites from /Sprites folder are handled correctly * sprites from /Sprites folder are handled correctly

View File

@ -212,6 +212,9 @@ void CClient::process(int what)
*serv >> gb; *serv >> gb;
tlog5 << "Hero receives bonus\n"; tlog5 << "Hero receives bonus\n";
gs->apply(&gb); gs->apply(&gb);
CGHeroInstance *h = gs->getHero(gb.hid);
if(vstd::contains(playerint,h->tempOwner))
playerint[h->tempOwner]->heroBonusChanged(h,h->bonuses.back(),true);
break; break;
} }
case 500: case 500:

View File

@ -9,6 +9,7 @@
#include "CSpellHandler.h" #include "CSpellHandler.h"
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include <boost/algorithm/string/replace.hpp> #include <boost/algorithm/string/replace.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/random/linear_congruential.hpp> #include <boost/random/linear_congruential.hpp>
#include "CTownHandler.h" #include "CTownHandler.h"
#include "CArtHandler.h" #include "CArtHandler.h"
@ -611,7 +612,7 @@ std::vector<std::pair<int,std::string> > CGHeroInstance::getCurrentMoraleModifie
//various morale bonuses (from buildings, artifacts, etc) //various morale bonuses (from buildings, artifacts, etc)
for(std::list<HeroBonus>::const_iterator i=bonuses.begin(); i != bonuses.end(); i++) for(std::list<HeroBonus>::const_iterator i=bonuses.begin(); i != bonuses.end(); i++)
if(i->type == HeroBonus::MORALE) if(i->type == HeroBonus::MORALE || i->type == HeroBonus::MORALE_AND_LUCK)
ret.push_back(std::make_pair(i->val, i->description)); ret.push_back(std::make_pair(i->val, i->description));
//leadership //leadership
@ -688,7 +689,7 @@ std::vector<std::pair<int,std::string> > CGHeroInstance::getCurrentLuckModifiers
//various morale bonuses (from buildings, artifacts, etc) //various morale bonuses (from buildings, artifacts, etc)
for(std::list<HeroBonus>::const_iterator i=bonuses.begin(); i != bonuses.end(); i++) for(std::list<HeroBonus>::const_iterator i=bonuses.begin(); i != bonuses.end(); i++)
if(i->type == HeroBonus::LUCK) if(i->type == HeroBonus::LUCK || i->type == HeroBonus::MORALE_AND_LUCK)
ret.push_back(std::make_pair(i->val, i->description)); ret.push_back(std::make_pair(i->val, i->description));
//luck skill //luck skill
@ -1608,48 +1609,108 @@ void CGBonusingObject::onHeroVisit( const CGHeroInstance * h ) const
{ {
bool visited = h->getBonus(HeroBonus::OBJECT,ID); bool visited = h->getBonus(HeroBonus::OBJECT,ID);
int messageID, bonusType, bonusVal; int messageID, bonusType, bonusVal;
int bonusMove = 0;
InfoWindow iw; InfoWindow iw;
iw.player = h->tempOwner; iw.player = h->tempOwner;
GiveBonus gbonus;
gbonus.hid = h->id;
gbonus.bonus.duration = HeroBonus::ONE_BATTLE;
gbonus.bonus.source = HeroBonus::OBJECT;
gbonus.bonus.id = ID;
switch(ID) switch(ID)
{ {
case 14: //swan pond case 14: //swan pond
messageID = 29; messageID = 29;
bonusType = HeroBonus::LUCK; gbonus.bonus.type = HeroBonus::LUCK;
bonusVal = 2; gbonus.bonus.val = 2;
gbonus.bdescr << std::pair<ui8,ui32>(6,67);
bonusMove = -h->movement;
break;
case 28: //Faerie Ring case 28: //Faerie Ring
messageID = 49; messageID = 49;
bonusType = HeroBonus::LUCK; gbonus.bonus.type = HeroBonus::LUCK;
bonusVal = 1; gbonus.bonus.val = 1;
gbonus.bdescr << std::pair<ui8,ui32>(6,71);
break; break;
case 30: //fountain of fortune case 30: //fountain of fortune
messageID = 55; messageID = 55;
bonusType = HeroBonus::LUCK; gbonus.bonus.type = HeroBonus::LUCK;
bonusVal = rand()%5 - 1; gbonus.bonus.val = rand()%5 - 1;
gbonus.bdescr << std::pair<ui8,ui32>(6,69);
gbonus.bdescr.replacements.push_back((gbonus.bonus.val<0 ? "-" : "+") + boost::lexical_cast<std::string>(gbonus.bonus.val));
break; break;
case 38: //idol of fortune case 38: //idol of fortune
messageID = 62; messageID = 62;
bonusType = HeroBonus::IDOL_OF_FORTUNE_BONUS; if(cb->getDate(1) == 7) //7th day of week
bonusVal = 1; gbonus.bonus.type = HeroBonus::MORALE_AND_LUCK;
else
gbonus.bonus.type = (cb->getDate(1)%2) ? HeroBonus::LUCK : HeroBonus::MORALE;
gbonus.bonus.val = 1;
gbonus.bdescr << std::pair<ui8,ui32>(6,68);
break;
case 64: //Rally Flag
messageID = 111;
gbonus.bonus.type = HeroBonus::MORALE_AND_LUCK;
gbonus.bonus.val = 1;
gbonus.bdescr << std::pair<ui8,ui32>(6,102);
bonusMove = 400;
break;
case 56: //oasis
messageID = 95;
gbonus.bonus.type = HeroBonus::MORALE;
gbonus.bonus.val = 1;
gbonus.bdescr << std::pair<ui8,ui32>(6,95);
bonusMove = 800;
break;
case 96: //temple
messageID = 140;
gbonus.bonus.type = HeroBonus::MORALE;
if(cb->getDate(1)==7) //sunday
{
gbonus.bonus.val = 2;
gbonus.bdescr << std::pair<ui8,ui32>(6,97);
}
else
{
gbonus.bonus.val = 1;
gbonus.bdescr << std::pair<ui8,ui32>(6,96);
}
break;
case 110://Watering Hole
messageID = 166;
gbonus.bonus.type = HeroBonus::MORALE;
gbonus.bonus.val = 1;
gbonus.bdescr << std::pair<ui8,ui32>(6,100);
bonusMove = 400;
break;
case 31: //Fountain of Youth
messageID = 57;
gbonus.bonus.type = HeroBonus::MORALE;
gbonus.bonus.val = 1;
gbonus.bdescr << std::pair<ui8,ui32>(6,103);
bonusMove = 400;
break; break;
} }
if(visited) if(visited)
{ {
if(ID==64 || ID==96 || ID==56)
messageID--;
else
messageID++; messageID++;
} }
else else
{ {
iw.components.push_back(Component(9,0,1,0)); if(gbonus.bonus.type == HeroBonus::MORALE || gbonus.bonus.type == HeroBonus::MORALE_AND_LUCK)
GiveBonus gbonus; iw.components.push_back(Component(8,0,gbonus.bonus.val,0));
gbonus.bonus = HeroBonus(HeroBonus::ONE_BATTLE,HeroBonus::LUCK,HeroBonus::OBJECT, bonusVal, ID,""); if(gbonus.bonus.type == HeroBonus::LUCK || gbonus.bonus.type == HeroBonus::MORALE_AND_LUCK)
gbonus.hid = h->id; iw.components.push_back(Component(9,0,gbonus.bonus.val,0));
gbonus.bdescr << std::pair<ui8,ui32>(6,71);
cb->giveHeroBonus(&gbonus); cb->giveHeroBonus(&gbonus);
if(ID==14) //swan pond - take all move points if(bonusMove) //swan pond - take all move points
{ {
SetMovePoints smp; SetMovePoints smp;
smp.hid = h->id; smp.hid = h->id;
smp.val = 0; smp.val = h->movement + bonusMove;
cb->setMovePoints(&smp); cb->setMovePoints(&smp);
} }
} }

View File

@ -4,7 +4,7 @@ struct BattleAction
{ {
ui8 side; //who made this action: false - left, true - right player ui8 side; //who made this action: false - left, true - right player
ui32 stackNumber;//stack ID, -1 left hero, -2 right hero, ui32 stackNumber;//stack ID, -1 left hero, -2 right hero,
ui8 actionType; // 0 = Cancel BattleAction 1 = Hero cast a spell 2 = Walk 3 = Defend 4 = Retreat from the battle 5 = Surrender 6 = Walk and Attack 7 = Shoot 8 = Wait 9 = Catapult 10 = Monster casts a spell (i.e. Faerie Dragons) ui8 actionType; // 0 = No action; 1 = Hero cast a spell 2 = Walk 3 = Defend 4 = Retreat from the battle 5 = Surrender 6 = Walk and Attack 7 = Shoot 8 = Wait 9 = Catapult 10 = Monster casts a spell (i.e. Faerie Dragons) 11 - Bad morale freeze
ui16 destinationTile; ui16 destinationTile;
si32 additionalInfo; // e.g. spell number if type is 1 || 10; tile to attack if type is 6 si32 additionalInfo; // e.g. spell number if type is 1 || 10; tile to attack if type is 6
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)

View File

@ -4,7 +4,7 @@
struct DLL_EXPORT HeroBonus struct DLL_EXPORT HeroBonus
{ {
enum BonusType{NONE, MOVEMENT, MORALE, LUCK, IDOL_OF_FORTUNE_BONUS}; enum BonusType{NONE, MOVEMENT, LAND_MOVEMENT, SEA_MOVEMENT, MORALE, LUCK, MORALE_AND_LUCK};
enum BonusDuration{PERMANENT, ONE_BATTLE, ONE_DAY, ONE_WEEK}; enum BonusDuration{PERMANENT, ONE_BATTLE, ONE_DAY, ONE_WEEK};
enum BonusSource{ARTIFACT, OBJECT}; enum BonusSource{ARTIFACT, OBJECT};

View File

@ -505,7 +505,7 @@ struct BattleStackAttacked : public CPack<BattleStackAttacked>//3005
{ {
ui32 stackAttacked; ui32 stackAttacked;
ui32 newAmount, newHP, killedAmount, damageAmount; ui32 newAmount, newHP, killedAmount, damageAmount;
ui8 flags; //1 - is stack killed; 2 - is there special effect to be shown ui8 flags; //1 - is stack killed; 2 - is there special effect to be shown; 4 - lucky hit
ui32 effect; //set only if flag 2 is present ui32 effect; //set only if flag 2 is present
@ -518,6 +518,10 @@ struct BattleStackAttacked : public CPack<BattleStackAttacked>//3005
{ {
return flags & 2; return flags & 2;
} }
bool lucky()
{
return flags & 4;
}
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {
h & stackAttacked & newAmount & newHP & flags & killedAmount & damageAmount & effect; h & stackAttacked & newAmount & newHP & flags & killedAmount & damageAmount & effect;

View File

@ -1781,6 +1781,11 @@ void Mapa::readObjects( unsigned char * bufor, int &i)
case 14: //Swan pond case 14: //Swan pond
case 38: //idol of fortune case 38: //idol of fortune
case 30: //Fountain of Fortune case 30: //Fountain of Fortune
case 64: //Rally Flag
case 56: //oasis
case 96: //temple
case 110://Watering Hole
case 31: //Fountain of Youth
{ {
nobj = new CGBonusingObject(); nobj = new CGBonusingObject();
break; break;

5
map.h
View File

@ -499,6 +499,11 @@ struct DLL_EXPORT Mapa : public CMapHeader
case 14: //Swan pond case 14: //Swan pond
case 38: //idol of fortune case 38: //idol of fortune
case 30: //Fountain of Fortune case 30: //Fountain of Fortune
case 64: //Rally Flag
case 56: //oasis
case 96: //temple
case 110://Watering Hole
case 31: //Fountain of Youth
SERIALIZE(CGBonusingObject); SERIALIZE(CGBonusingObject);
break; break;
default: default:

View File

@ -310,6 +310,29 @@ void CGameHandler::startBattle(CCreatureSet army1, CCreatureSet army2, int3 tile
//stack loop //stack loop
CStack *next; CStack *next;
while(!battleResult.get() && (next=gs->curB->getNextStack())) while(!battleResult.get() && (next=gs->curB->getNextStack()))
{
next->state -= WAITING; //if stack was waiting it'll now make move, so it won't be "waiting" anymore
//check for bad morale => freeze
if(next->Morale() < 0)
{
if( rand()%24 < (-next->Morale())*2 )
{
//unit loses its turn - empty freeze action
BattleAction ba;
ba.actionType = 11;
ba.additionalInfo = 1;
ba.side = !next->attackerOwned;
ba.stackNumber = next->ID;
sendAndApply(&StartAction(ba));
sendDataToClients(ui16(3008));
checkForBattleEnd(stacks); //check if this "action" ended the battle (not likely but who knows...)
continue;
}
}
askInterfaceForMove:
//ask interface and wait for answer
{ {
BattleSetActiveStack sas; BattleSetActiveStack sas;
sas.stack = next->ID; sas.stack = next->ID;
@ -318,7 +341,19 @@ void CGameHandler::startBattle(CCreatureSet army1, CCreatureSet army2, int3 tile
while(!battleMadeAction.data && !battleResult.get()) //active stack hasn't made its action and battle is still going while(!battleMadeAction.data && !battleResult.get()) //active stack hasn't made its action and battle is still going
battleMadeAction.cond.wait(lock); battleMadeAction.cond.wait(lock);
battleMadeAction.data = false; battleMadeAction.data = false;
}
//we're after action, all results applied
checkForBattleEnd(stacks); //check if this action ended the battle checkForBattleEnd(stacks); //check if this action ended the battle
//check for good morale
if(!vstd::contains(next->state,HAD_MORALE) //only one extra move per turn possible
&& !vstd::contains(next->state,DEFENDING)
&& !vstd::contains(next->state,WAITING)
&& next->alive()
&& next->Morale() > 0
)
if(rand()%24 < next->Morale()) //this stack hasn't got morale this turn
goto askInterfaceForMove; //move this stack once more
} }
} }
@ -395,6 +430,11 @@ void CGameHandler::prepareAttack(BattleAttack &bat, CStack *att, CStack *def)
bat.stackAttacking = att->ID; bat.stackAttacking = att->ID;
bat.bsa.stackAttacked = def->ID; bat.bsa.stackAttacked = def->ID;
bat.bsa.damageAmount = BattleInfo::calculateDmg(att, def, gs->getHero(att->attackerOwned ? gs->curB->hero1 : gs->curB->hero2), gs->getHero(def->attackerOwned ? gs->curB->hero1 : gs->curB->hero2), bat.shot());//counting dealt damage bat.bsa.damageAmount = BattleInfo::calculateDmg(att, def, gs->getHero(att->attackerOwned ? gs->curB->hero1 : gs->curB->hero2), gs->getHero(def->attackerOwned ? gs->curB->hero1 : gs->curB->hero2), bat.shot());//counting dealt damage
if(att->Luck() > 0 && rand()%24 < att->Luck())
{
bat.bsa.damageAmount *= 2;
bat.bsa.flags |= 4;
}
prepareAttacked(bat.bsa,def); prepareAttacked(bat.bsa,def);
} }
void CGameHandler::handleConnection(std::set<int> players, CConnection &c) void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
@ -2035,6 +2075,20 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, CCreatureSet &army
for(std::map<si32,std::pair<ui32,si32> >::iterator i = army1.slots.begin(); i!=army1.slots.end(); i++) for(std::map<si32,std::pair<ui32,si32> >::iterator i = army1.slots.begin(); i!=army1.slots.end(); i++)
{ {
stacks.push_back(new CStack(&VLC->creh->creatures[i->second.first],i->second.second,hero1->tempOwner, stacks.size(), true,i->first)); stacks.push_back(new CStack(&VLC->creh->creatures[i->second.first],i->second.second,hero1->tempOwner, stacks.size(), true,i->first));
//base luck/morale calculations
//TODO: check if terrain is native, add bonuses for neutral stacks, bonuses from town
if(hero1)
{
stacks.back()->morale = hero1->getCurrentMorale(i->first,false);
stacks.back()->luck = hero1->getCurrentLuck(i->first,false);
}
else
{
stacks.back()->morale = 0;
stacks.back()->luck = 0;
}
stacks[stacks.size()-1]->ID = stacks.size()-1; stacks[stacks.size()-1]->ID = stacks.size()-1;
} }
//initialization of positions //initialization of positions
@ -2068,7 +2122,21 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, CCreatureSet &army
stacks[b]->position = attackerLoose[army1.slots.size()-1][b]; stacks[b]->position = attackerLoose[army1.slots.size()-1][b];
} }
for(std::map<si32,std::pair<ui32,si32> >::iterator i = army2.slots.begin(); i!=army2.slots.end(); i++) for(std::map<si32,std::pair<ui32,si32> >::iterator i = army2.slots.begin(); i!=army2.slots.end(); i++)
{
stacks.push_back(new CStack(&VLC->creh->creatures[i->second.first],i->second.second,hero2 ? hero2->tempOwner : 255, stacks.size(), false, i->first)); stacks.push_back(new CStack(&VLC->creh->creatures[i->second.first],i->second.second,hero2 ? hero2->tempOwner : 255, stacks.size(), false, i->first));
//base luck/morale calculations
//TODO: check if terrain is native, add bonuses for neutral stacks, bonuses from town
if(hero2)
{
stacks.back()->morale = hero2->getCurrentMorale(i->first,false);
stacks.back()->luck = hero2->getCurrentLuck(i->first,false);
}
else
{
stacks.back()->morale = 0;
stacks.back()->luck = 0;
}
}
if(army2.formation) if(army2.formation)
for(int b=0; b<army2.slots.size(); ++b) //tight for(int b=0; b<army2.slots.size(); ++b) //tight