mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +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:
parent
218a3beaf6
commit
e1d6ff54d7
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -462,8 +462,8 @@ void CHeroWindow::deactivate()
|
||||
portraitArea->deactivate();
|
||||
expArea->deactivate();
|
||||
spellPointsArea->deactivate();
|
||||
morale->activate();
|
||||
luck->activate();
|
||||
morale->deactivate();
|
||||
luck->deactivate();
|
||||
|
||||
garInt->deactivate();
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
battleInt->deactivate();
|
||||
|
||||
CStack *stack = cb->battleGetStackByID(action->stackNumber);
|
||||
char txt[400];
|
||||
|
||||
if(action->actionType == 1)
|
||||
{
|
||||
if(action->side)
|
||||
@ -2090,47 +2086,36 @@ 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);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(txt, CGI->generaltexth->allTexts[121].c_str(), stack->creature->namePl.c_str(), 0);
|
||||
}
|
||||
LOCPLINT->battleInt->console->addText(txt);
|
||||
}
|
||||
else
|
||||
{
|
||||
tlog1<<"Somthing wrong with stackNumber in actionStarted -> actionType 3"<<std::endl;
|
||||
}
|
||||
tlog1<<"Something wrong with stackNumber in actionStarted"<<std::endl;
|
||||
return;
|
||||
}
|
||||
if(action->actionType == 8) //wait
|
||||
|
||||
int txtid = 0;
|
||||
switch(action->actionType)
|
||||
{
|
||||
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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
@ -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
|
||||
|
77
ChangeLog
77
ChangeLog
@ -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
|
||||
* /Data and /Sprites subfolders can be used for adding files not present in .lod archives
|
||||
* 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
|
||||
@ -27,26 +56,26 @@ BATTLES
|
||||
* spell effect animation displaying improvements
|
||||
* positive/negative spells cannot be cast on hostile/our stacks
|
||||
* showing spell effects affecting stack in creature info window
|
||||
* more appropriate coloring of stack amount box when stack is affected by a spell
|
||||
* more appropriate coloring of stack amount box when stack is affected by a spell
|
||||
* battle console displays notifications about wait/defend commands
|
||||
* several reported bugs fixed
|
||||
* new spells supported:
|
||||
a) Haste
|
||||
b) lightning bolt
|
||||
c) ice bolt
|
||||
d) slow
|
||||
e) implosion
|
||||
f) forgetfulness
|
||||
g) shield
|
||||
h) air shield
|
||||
i) bless
|
||||
j) curse
|
||||
k) bloodlust
|
||||
l) weakness
|
||||
m) stone skin
|
||||
n) prayer
|
||||
o) frenzy
|
||||
|
||||
a) Haste
|
||||
b) lightning bolt
|
||||
c) ice bolt
|
||||
d) slow
|
||||
e) implosion
|
||||
f) forgetfulness
|
||||
g) shield
|
||||
h) air shield
|
||||
i) bless
|
||||
j) curse
|
||||
k) bloodlust
|
||||
l) weakness
|
||||
m) stone skin
|
||||
n) prayer
|
||||
o) frenzy
|
||||
|
||||
AI PLAYER:
|
||||
* Genius AI (first VCMI AI) will control computer creatures during the combat.
|
||||
|
||||
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
{
|
||||
messageID++;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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};
|
||||
|
||||
|
@ -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;
|
||||
|
5
map.cpp
5
map.cpp
@ -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
5
map.h
@ -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:
|
||||
|
@ -311,14 +311,49 @@ void CGameHandler::startBattle(CCreatureSet army1, CCreatureSet army2, int3 tile
|
||||
CStack *next;
|
||||
while(!battleResult.get() && (next=gs->curB->getNextStack()))
|
||||
{
|
||||
BattleSetActiveStack sas;
|
||||
sas.stack = next->ID;
|
||||
sendAndApply(&sas);
|
||||
boost::unique_lock<boost::mutex> lock(battleMadeAction.mx);
|
||||
while(!battleMadeAction.data && !battleResult.get()) //active stack hasn't made its action and battle is still going
|
||||
battleMadeAction.cond.wait(lock);
|
||||
battleMadeAction.data = false;
|
||||
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;
|
||||
sendAndApply(&sas);
|
||||
boost::unique_lock<boost::mutex> lock(battleMadeAction.mx);
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user