1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-12 02:28:11 +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 BattleStackAttacked;
struct SpellCasted;
struct HeroBonus;
class CObstacle
{
int ID;
@ -67,6 +68,7 @@ public:
virtual void tileRevealed(const std::set<int3> &pos){};
virtual void yourTurn(){};
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
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 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)
{
if(player<0 || player>=PLAYER_LIMIT)
@ -781,14 +795,14 @@ void CGameState::applyNL(IPack * pack)
{
BattleSetActiveStack *ns = static_cast<BattleSetActiveStack*>(pack);
curB->activeStack = ns->stack;
CStack *st = curB->getStack(ns->stack);
if(vstd::contains(st->state,MOVED))
st->state.insert(HAD_MORALE);
break;
}
case 3003:
{
BattleResult *br = static_cast<BattleResult*>(pack);
//TODO: give exp, artifacts to winner, decrease armies (casualties)
for(unsigned i=0;i<curB->stacks.size();i++)
delete curB->stacks[i];
delete curB;
@ -834,7 +848,7 @@ void CGameState::applyNL(IPack * pack)
case 8:
st->state.insert(WAITING);
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);
break;
}

View File

@ -127,6 +127,7 @@ public:
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)
si16 shots; //how many shots left
si8 morale, luck; //base stack luck/morale
std::set<EAbilities> abilities;
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(){}
const StackEffect * getEffect(ui16 id) const; //effect id (SP)
ui32 speed() const;
si8 Morale() const;
si8 Luck() const;
template <typename Handler> void save(Handler &h, const int version)
{
h & creature->idNumber;
@ -160,7 +163,7 @@ public:
template <typename Handler> void serialize(Handler &h, const int version)
{
h & ID & amount & baseAmount & firstHPleft & owner & slot & attackerOwned & position & state & counterAttacks
& shots;
& shots & morale & luck;
if(h.saving)
save(h,version);
else

View File

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

View File

@ -1887,19 +1887,12 @@ int3 CPlayerInterface::repairScreenPos(int3 pos)
void CPlayerInterface::heroPrimarySkillChanged(const CGHeroInstance * hero, int which, int val)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
SDL_FreeSurface(graphics->heroWins[hero->subID]);//TODO: moznaby zmieniac jedynie fragment bitmapy zwiazany z dana umiejetnoscia
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;
redrawHeroWin(hero);
}
void CPlayerInterface::heroManaPointsChanged(const CGHeroInstance * hero)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
SDL_FreeSurface(graphics->heroWins[hero->subID]);//TODO: moznaby zmieniac jedynie fragment bitmapy zwiazany z dana umiejetnoscia
graphics->heroWins[hero->subID] = infoWin(hero); //a nie przerysowywac calosc. Troche roboty, obecnie chyba nie wartej swieczki.
if (adventureInt->selection == hero)
adventureInt->infoBar.draw();
redrawHeroWin(hero);
}
void CPlayerInterface::heroMovePointsChanged(const CGHeroInstance * hero)
{
@ -2079,10 +2072,13 @@ void CPlayerInterface::actionStarted(const BattleAction* action)
{
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();
}
CStack *stack = cb->battleGetStackByID(action->stackNumber);
char txt[400];
if(action->actionType == 1)
{
if(action->side)
@ -2090,48 +2086,37 @@ void CPlayerInterface::actionStarted(const BattleAction* action)
else
battleInt->attackingHero->setPhase(4);
}
if(action->actionType == 3) //defend
if(!stack)
{
char txt[2000];
CStack * stack = cb->battleGetStackByID(action->stackNumber);
if(stack)
{
if(stack->amount == 1)
{
sprintf(txt, CGI->generaltexth->allTexts[120].c_str(), stack->creature->nameSing.c_str(), 0);
tlog1<<"Something wrong with stackNumber in actionStarted"<<std::endl;
return;
}
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);
}
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)
@ -2156,6 +2141,16 @@ BattleAction CPlayerInterface::activeStack(int stackID) //called when it's turn
CBattleInterface *b = battleInt;
{
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);
}
//wait till BattleInterface sets its command
@ -2215,14 +2210,18 @@ void CPlayerInterface::battleStackAttacked(BattleStackAttacked * bsa)
void CPlayerInterface::battleAttack(BattleAttack *ba)
{
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())
battleInt->stackIsShooting(ba->stackAttacking,cb->battleGetPos(ba->bsa.stackAttacked));
else
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)
{
@ -2359,6 +2358,21 @@ void CPlayerInterface::availableCreaturesChanged( const CGTownInstance *town )
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)
{
bg=BitmapHandler::loadBitmap(name);

View File

@ -380,6 +380,7 @@ public:
void tileRevealed(const std::set<int3> &pos);
void yourTurn();
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
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
@ -396,6 +397,7 @@ public:
//-------------//
void redrawHeroWin(const CGHeroInstance * hero);
void updateWater();
void showComp(SComponent comp);
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:
* move some settings to the config/settings.txt file
* 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
* fixed crashbug occuring when hero levelled above 15 level
* support for non-standard screen resolutions
* F4 toggles between full-screen and windowed mode (experimental)
* splitting stacks the shift+click
* F4 toggles between full-screen and windowed mode
* minor improvements in creature card window
* splitting stacks with the shift+click
* creature card window contains info about modified speed
ADVENTURE INTERFACE:
* smooth map scrolling on hero movement
* added water animation
* speed of scrolling map and hero movement can be adjusted in the System Options Window
* partial handling r-clicks on adventure map
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)
BATTLES
@ -54,9 +83,11 @@ OBJECTS:
* Guardians property for resources is handled
* support for Witch Hut
* support for Arena
* support for Library of Enlightenment
And a lot of minor fixes
0.63 -> 0.64 (Nov 01 2008)
GENERAL:
* sprites from /Sprites folder are handled correctly

View File

@ -212,6 +212,9 @@ void CClient::process(int what)
*serv >> gb;
tlog5 << "Hero receives bonus\n";
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;
}
case 500:

View File

@ -9,6 +9,7 @@
#include "CSpellHandler.h"
#include <boost/bind.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/random/linear_congruential.hpp>
#include "CTownHandler.h"
#include "CArtHandler.h"
@ -611,7 +612,7 @@ std::vector<std::pair<int,std::string> > CGHeroInstance::getCurrentMoraleModifie
//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)
if(i->type == HeroBonus::MORALE || i->type == HeroBonus::MORALE_AND_LUCK)
ret.push_back(std::make_pair(i->val, i->description));
//leadership
@ -688,7 +689,7 @@ std::vector<std::pair<int,std::string> > CGHeroInstance::getCurrentLuckModifiers
//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)
if(i->type == HeroBonus::LUCK || i->type == HeroBonus::MORALE_AND_LUCK)
ret.push_back(std::make_pair(i->val, i->description));
//luck skill
@ -1608,48 +1609,108 @@ void CGBonusingObject::onHeroVisit( const CGHeroInstance * h ) const
{
bool visited = h->getBonus(HeroBonus::OBJECT,ID);
int messageID, bonusType, bonusVal;
int bonusMove = 0;
InfoWindow iw;
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)
{
case 14: //swan pond
messageID = 29;
bonusType = HeroBonus::LUCK;
bonusVal = 2;
gbonus.bonus.type = HeroBonus::LUCK;
gbonus.bonus.val = 2;
gbonus.bdescr << std::pair<ui8,ui32>(6,67);
bonusMove = -h->movement;
break;
case 28: //Faerie Ring
messageID = 49;
bonusType = HeroBonus::LUCK;
bonusVal = 1;
gbonus.bonus.type = HeroBonus::LUCK;
gbonus.bonus.val = 1;
gbonus.bdescr << std::pair<ui8,ui32>(6,71);
break;
case 30: //fountain of fortune
messageID = 55;
bonusType = HeroBonus::LUCK;
bonusVal = rand()%5 - 1;
gbonus.bonus.type = HeroBonus::LUCK;
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;
case 38: //idol of fortune
messageID = 62;
bonusType = HeroBonus::IDOL_OF_FORTUNE_BONUS;
bonusVal = 1;
if(cb->getDate(1) == 7) //7th day of week
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;
}
if(visited)
{
if(ID==64 || ID==96 || ID==56)
messageID--;
else
messageID++;
}
else
{
iw.components.push_back(Component(9,0,1,0));
GiveBonus gbonus;
gbonus.bonus = HeroBonus(HeroBonus::ONE_BATTLE,HeroBonus::LUCK,HeroBonus::OBJECT, bonusVal, ID,"");
gbonus.hid = h->id;
gbonus.bdescr << std::pair<ui8,ui32>(6,71);
if(gbonus.bonus.type == HeroBonus::MORALE || gbonus.bonus.type == HeroBonus::MORALE_AND_LUCK)
iw.components.push_back(Component(8,0,gbonus.bonus.val,0));
if(gbonus.bonus.type == HeroBonus::LUCK || gbonus.bonus.type == HeroBonus::MORALE_AND_LUCK)
iw.components.push_back(Component(9,0,gbonus.bonus.val,0));
cb->giveHeroBonus(&gbonus);
if(ID==14) //swan pond - take all move points
if(bonusMove) //swan pond - take all move points
{
SetMovePoints smp;
smp.hid = h->id;
smp.val = 0;
smp.val = h->movement + bonusMove;
cb->setMovePoints(&smp);
}
}

View File

@ -4,7 +4,7 @@ struct BattleAction
{
ui8 side; //who made this action: false - left, true - right player
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;
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)

View File

@ -4,7 +4,7 @@
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 BonusSource{ARTIFACT, OBJECT};

View File

@ -505,7 +505,7 @@ struct BattleStackAttacked : public CPack<BattleStackAttacked>//3005
{
ui32 stackAttacked;
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
@ -518,6 +518,10 @@ struct BattleStackAttacked : public CPack<BattleStackAttacked>//3005
{
return flags & 2;
}
bool lucky()
{
return flags & 4;
}
template <typename Handler> void serialize(Handler &h, const int version)
{
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 38: //idol 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();
break;

5
map.h
View File

@ -499,6 +499,11 @@ struct DLL_EXPORT Mapa : public CMapHeader
case 14: //Swan pond
case 38: //idol 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);
break;
default:

View File

@ -310,6 +310,29 @@ void CGameHandler::startBattle(CCreatureSet army1, CCreatureSet army2, int3 tile
//stack loop
CStack *next;
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;
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
battleMadeAction.cond.wait(lock);
battleMadeAction.data = false;
}
//we're after action, all results applied
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.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
if(att->Luck() > 0 && rand()%24 < att->Luck())
{
bat.bsa.damageAmount *= 2;
bat.bsa.flags |= 4;
}
prepareAttacked(bat.bsa,def);
}
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++)
{
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;
}
//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];
}
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));
//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)
for(int b=0; b<army2.slots.size(); ++b) //tight