1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-03-25 21:38:59 +02:00

* started making morale/luck system

* basic calculation of hero/stack morale
* displaying morale in hero window
* redone checking if attack is possible (should fix some problems with attacking with 2-hex creatures, at least on server side)
* std::list serialization
* version set to 0.7b
This commit is contained in:
Michał W. Urbańczyk 2009-02-03 05:28:05 +00:00
parent 124e768a99
commit 680993459a
14 changed files with 326 additions and 85 deletions

View File

@ -583,6 +583,13 @@ void CGameState::applyNL(IPack * pack)
}
break;
}
case 115:
{
GiveBonus *rh = static_cast<GiveBonus*>(pack);
CGHeroInstance *h = getHero(rh->hid);
h->bonuses.push_back(CGHeroInstance::Bonus(rh->bduration,rh->btype,rh->bval,rh->bid,toString(rh->bdescr)));
break;
}
case 500:
{
RemoveObject *rh = static_cast<RemoveObject*>(pack);

View File

@ -101,6 +101,12 @@ CHeroWindow::CHeroWindow(int playerColor):
expArea->pos.h = 42;
expArea->hoverText = CGI->generaltexth->heroscrn[9];
morale = new LRClickableAreaWTextComp();
morale->pos = genRect(45,53,pos.x+240,pos.y+187);
luck = new LRClickableAreaWTextComp();
luck->pos = genRect(45,53,pos.x+298,pos.y+187);
spellPointsArea = new LRClickableAreaWText();
spellPointsArea->pos.x = pos.x+227;
spellPointsArea->pos.y = pos.y + 236;
@ -161,6 +167,8 @@ CHeroWindow::~CHeroWindow()
delete portraitArea;
delete expArea;
delete luck;
delete morale;
delete spellPointsArea;
for(size_t v=0; v<primSkillAreas.size(); ++v)
{
@ -339,6 +347,18 @@ void CHeroWindow::setHero(const CGHeroInstance *Hero)
formations->select(hero->army.formation,true);
formations->onChange = boost::bind(&CCallback::setFormation, LOCPLINT->cb, Hero, _1);
std::vector<std::pair<int,std::string> > mrl = hero->getCurrentMoraleModifiers();
int mrlv = hero->getCurrentMorale();
int mrlt = (mrlv>0)-(mrlv<0); //signum: -1 - bad morale, 0 - neutral, 1 - good
morale->hoverText = CGI->generaltexth->heroscrn[4 - mrlt];
morale->baseType = SComponent::morale;
morale->bonus = mrlv;
morale->text = CGI->generaltexth->arraytxt[88];
boost::algorithm::replace_first(morale->text,"%s",CGI->generaltexth->arraytxt[86-mrlt]);
for(int it=0; it < mrl.size(); it++)
morale->text += mrl[it].second;
pos.x += 65;
pos.y += 8;
@ -385,6 +405,8 @@ void CHeroWindow::activate()
portraitArea->activate();
expArea->activate();
spellPointsArea->activate();
morale->activate();
luck->activate();
garInt->activate();
LOCPLINT->statusbar = ourBar;
@ -430,6 +452,8 @@ void CHeroWindow::deactivate()
portraitArea->deactivate();
expArea->deactivate();
spellPointsArea->deactivate();
morale->activate();
luck->activate();
garInt->deactivate();
@ -830,10 +854,6 @@ void LClickableArea::clickLeft(boost::logic::tribool down)
//{
// LOCPLINT->showInfoDialog("TEST TEST AAA", std::vector<SComponent*>());
//}
}
void RClickableArea::activate()
@ -850,10 +870,6 @@ void RClickableArea::clickRight(boost::logic::tribool down)
//{
// LOCPLINT->showInfoDialog("TEST TEST AAA", std::vector<SComponent*>());
//}
}
void LRClickableAreaWText::clickLeft(boost::logic::tribool down)

View File

@ -105,6 +105,8 @@ class CHeroWindow: public IShowActivable, public virtual CIntObject
std::vector<LRClickableAreaWTextComp *> primSkillAreas;
LRClickableAreaWText * expArea;
LRClickableAreaWText * spellPointsArea;
LRClickableAreaWTextComp * luck;
LRClickableAreaWTextComp * morale;
std::vector<LRClickableAreaWTextComp *> secSkillAreas;
public:
AdventureMapButton * quitButton, * dismissButton, * questlogButton, //general

View File

@ -168,7 +168,7 @@ void CGarrisonSlot::clickRight (tribool down)
pom->attackBonus = h->getPrimSkillLevel(0);
pom->defenseBonus = h->getPrimSkillLevel(1);
pom->luck = h->getCurrentLuck();
pom->morale = h->getCurrentMorale();
pom->morale = h->getCurrentMorale(ID);
}
(new CCreInfoWindow(creature->idNumber,0,count,pom,boost::function<void()>(),boost::function<void()>(),NULL))
->activate();
@ -723,6 +723,9 @@ SDL_Surface * SComponent::getImg()
case experience:
return graphics->pskillsb->ourImages[4].bitmap;
break;
case morale:
return graphics->morale82->ourImages[val+3].bitmap;
break;
}
return NULL;
}
@ -1197,7 +1200,14 @@ void CPlayerInterface::heroMoved(const HeroMoveDetails & details)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
adventureInt->centerOn(details.ho->pos); //centering screen on hero
int3 buff = details.ho->pos;
buff.x-=11;
buff.y-=9;
buff = repairScreenPos(buff);
LOCPLINT->adventureInt->position = buff; //actualizing screen pos
if(adventureInt == curint)
adventureInt->minimap.draw();
if(details.style>0)
return;

View File

@ -224,7 +224,7 @@ class SComponent : public ClickableR
public:
enum Etype
{
primskill, secskill, resource, creature, artifact, experience, secskill44, spell
primskill, secskill, resource, creature, artifact, experience, secskill44, spell, morale, luck
} type;
int subtype;
int val;

View File

@ -839,6 +839,7 @@ int MapSel::countWL()
void MapSel::printMaps(int from, int to, int at, bool abs)
{
if (!slid->positionsAmnt) return; //no maps to print
slid->capacity = (CPG->fromnewgame == 2 ? 16 : 18);
if(slid->positionsAmnt < slid->capacity)
from = 0;
int help=-1;
@ -928,7 +929,7 @@ void MapSel::printMaps(int from, int to, int at, bool abs)
else
tlog2 << "Warning: " << curVector()[(i-at)+from].filename << " has wrong version!\n";
if(CPG->fromnewgame)
if(CPG->fromnewgame == 1)
{
if (!(curVector()[(i-at)+from].name.length()))
curVector()[(i-at)+from].name = "Unnamed";
@ -998,7 +999,7 @@ void MapSel::show()
//blit bg
blitAt(bg,3,6);
CSDL_Ext::printAt("Map Sizes",55,60,GEOR13);
CSDL_Ext::printAt(CGI->generaltexth->arraytxt[CPG->fromnewgame ? 229 : 230],110,25,TNRB16); //Select a Scenario to Play : Load a Saved Game
CSDL_Ext::printAt(CGI->generaltexth->arraytxt[CPG->fromnewgame==1 ? 229 : 230],110,25,TNRB16); //Select a Scenario to Play : Load a Saved Game
//size buttons
small.show();
medium.show();
@ -1318,7 +1319,7 @@ void MapSel::printSelectedInfo()
SDL_BlitSurface(CPG->ourScenSel->scenInf,&genRect(399,337,17,23),screen,&genRect(399,337,413,29));
SDL_BlitSurface(CPG->ourScenSel->scenInf,&genRect(50,91,18,447),screen,&genRect(50,91,414,453));
if(CPG->fromnewgame)
if(CPG->fromnewgame==1)
{
SDL_BlitSurface(CPG->ourScenSel->bScens.imgs->ourImages[0].bitmap,NULL,screen,&CPG->ourScenSel->bScens.pos);
SDL_BlitSurface(CPG->ourScenSel->bOptions.imgs->ourImages[0].bitmap,NULL,screen,&CPG->ourScenSel->bOptions.pos);
@ -1471,7 +1472,7 @@ std::string MapSel::gdiff(std::string ss)
CMapInfo & MapSel::selectedMap()
{
if(CPG->fromnewgame)
if(CPG->fromnewgame==1)
return ourMaps[selected];
else
return ourGames[selected];
@ -1480,7 +1481,7 @@ CMapInfo & MapSel::selectedMap()
std::vector<CMapInfo> & MapSel::curVector()
{
if (CPG->fromnewgame)
if (CPG->fromnewgame==1)
return ourMaps;
else
return ourGames;
@ -1581,7 +1582,7 @@ void CPreGame::showScenSel()
SDL_BlitSurface(ourScenSel->bHard.imgs->ourImages[0].bitmap,NULL,screen,&ourScenSel->bHard.pos);
SDL_BlitSurface(ourScenSel->bExpert.imgs->ourImages[0].bitmap,NULL,screen,&ourScenSel->bExpert.pos);
SDL_BlitSurface(ourScenSel->bImpossible.imgs->ourImages[0].bitmap,NULL,screen,&ourScenSel->bImpossible.pos);
SDL_BlitSurface((fromnewgame ? ourScenSel->bBegin : ourScenSel->bLoad).imgs->ourImages[0].bitmap,NULL,screen,&ourScenSel->bBegin.pos);
SDL_BlitSurface((fromnewgame==1 ? ourScenSel->bBegin : ourScenSel->bLoad).imgs->ourImages[0].bitmap,NULL,screen,&ourScenSel->bBegin.pos);
SDL_BlitSurface(ourScenSel->bBack.imgs->ourImages[0].bitmap,NULL,screen,&ourScenSel->bBack.pos);
//blitAt(ourScenSel->bScens.imgs->ourImages[0].bitmap,ourScenSel->bScens.pos.x,ourScenSel->bScens.pos.y);
//blitAt(ourScenSel->bRandom.imgs->ourImages[0].bitmap,414,105);
@ -1592,7 +1593,7 @@ void CPreGame::showScenSel()
//add buttons info
if(first)
{
if(fromnewgame)
if(fromnewgame==1)
{
btns.push_back(&ourScenSel->bEasy);
btns.push_back(&ourScenSel->bNormal);
@ -1605,7 +1606,7 @@ void CPreGame::showScenSel()
}
else
ourScenSel->mapsel.show();
btns.push_back(&(fromnewgame ? ourScenSel->bBegin : ourScenSel->bLoad));
btns.push_back(&(fromnewgame==1 ? ourScenSel->bBegin : ourScenSel->bLoad));
btns.push_back(&ourScenSel->bBack);
ourScenSel->selectedDiff=1;
@ -2468,6 +2469,7 @@ ScenSel::ScenSel()
else
background = BitmapHandler::loadBitmap("ZPIC1001.bmp");
savenameStrip = BitmapHandler::loadBitmap("GSSTRIP.bmp");
scenInf = BitmapHandler::loadBitmap("GSELPOP1.bmp");
randMap = BitmapHandler::loadBitmap("RANMAPBK.bmp");
options = BitmapHandler::loadBitmap("ADVOPTBK.bmp");

View File

@ -221,7 +221,7 @@ public:
bool listShowed;
//RanSel ransel;
MapSel mapsel;
SDL_Surface * background, *scenInf, *scenList, *randMap, *options ;
SDL_Surface * background, *savenameStrip, *scenInf, *scenList, *randMap, *options ;
Button bScens, bOptions, bRandom, bBegin, bLoad, bBack;
IntSelBut bEasy, bNormal, bHard, bExpert, bImpossible;
Button * pressed;
@ -244,7 +244,7 @@ public:
StartInfo ret;
bool run;
bool first; //hasn't we showed the scensel
bool fromnewgame;
int fromnewgame; //1 - new game; 0 - load game; 2 - save game
std::vector<Slider *> interested;
CMusicHandler * mush;
std::vector<HighButton *> btns;

View File

@ -206,6 +206,14 @@ void CClient::process(int what)
gs->apply(&sav);
break;
}
case 115:
{
GiveBonus gb;
*serv >> gb;
tlog5 << "Hero receives bonus\n";
gs->apply(&gb);
break;
}
case 500:
{
RemoveObject rh;

View File

@ -19,7 +19,7 @@ typedef boost::int8_t si8; //signed int 8 bits (1 byte)
#define THC
#endif
#define NAME_VER ("VCMI 0.7")
#define NAME_VER ("VCMI 0.7b")
#define CONSOLE_LOGGING_LEVEL 5
#define FILE_LOGGING_LEVEL 6

View File

@ -330,11 +330,6 @@ int CGHeroInstance::getCurrentLuck() const
//TODO: write it
return 0;
}
int CGHeroInstance::getCurrentMorale() const
{
//TODO: write it
return 0;
}
int CGHeroInstance::getPrimSkillLevel(int id) const
{
return primSkills[id];
@ -601,6 +596,60 @@ void CGHeroInstance::initObj()
blockVisit = true;
}
int CGHeroInstance::getCurrentMorale( int stack, bool town ) const
{
int ret = 0;
std::vector<std::pair<int,std::string> > mods = getCurrentMoraleModifiers(stack,town);
for(int i=0; i < mods.size(); i++)
ret += mods[i].first;
return ret;
}
std::vector<std::pair<int,std::string> > CGHeroInstance::getCurrentMoraleModifiers( int stack/*=-1*/, bool town/*=false*/ ) const
{
//TODO: check if stack is undead/mechanic/elemental => always neutrl morale
std::vector<std::pair<int,std::string> > ret;
//various morale bonuses (from buildings, artifacts, etc)
for(std::list<Bonus>::const_iterator i=bonuses.begin(); i != bonuses.end(); i++)
if(i->type == 2)
ret.push_back(std::make_pair(i->val, i->description));
//leadership
if(getSecSkillLevel(6))
ret.push_back(std::make_pair(getSecSkillLevel(6),VLC->generaltexth->arraytxt[104+getSecSkillLevel(6)]));
//number of alignments and presence of undead
if(stack>=0)
{
std::set<si8> factions;
for(std::map<si32,std::pair<ui32,si32> >::const_iterator i=army.slots.begin(); i!=army.slots.end(); i++)
factions.insert(VLC->creh->creatures[i->second.first].faction);
if(factions.size() == 1)
ret.push_back(std::pair<int,std::string>(1,VLC->generaltexth->arraytxt[115])); //All troops of one alignment +1
else
{
if(VLC->generaltexth->arraytxt[114].length() <= 100)
{
char buf[150];
std::sprintf(buf,VLC->generaltexth->arraytxt[114].c_str(),factions.size(),2-factions.size());
ret.push_back(std::pair<int,std::string>(2-factions.size(),buf)); //Troops of %d alignments %d
}
else
{
ret.push_back(std::pair<int,std::string>(2-factions.size(),"")); //Troops of %d alignments %d
}
}
if(vstd::contains(factions,4))
ret.push_back(std::pair<int,std::string>(-1,VLC->generaltexth->arraytxt[116])); //Undead in group -1
}
return ret;
}
int CGTownInstance::getSightDistance() const //returns sight distance
{
return 10;
@ -1151,10 +1200,8 @@ void CGResource::collectRes( int player ) const
void CGResource::fightForRes(ui32 refusedFight, const CGHeroInstance *h) const
{
if(refusedFight)
return;
cb->startBattleI(h->id,army,pos,boost::bind(&CGResource::endBattle,this,_1,h));
if(!refusedFight)
cb->startBattleI(h->id,army,pos,boost::bind(&CGResource::endBattle,this,_1,h));
}
void CGResource::endBattle( BattleResult *result, const CGHeroInstance *h ) const
@ -1308,15 +1355,51 @@ void CGArtifact::initObj()
void CGArtifact::onHeroVisit( const CGHeroInstance * h ) const
{
cb->giveHeroArtifact(subID,h->id,-2);
cb->removeObject(id);
InfoWindow iw;
iw.player = h->tempOwner;
iw.components.push_back(Component(4,subID,0,0));
iw.text << std::pair<ui8,ui32>(12,subID);
cb->showInfoDialog(&iw);
if(!army.slots.size())
{
InfoWindow iw;
iw.player = h->tempOwner;
iw.components.push_back(Component(4,subID,0,0));
if(message.length())
iw.text << message;
else
iw.text << std::pair<ui8,ui32>(12,subID);
cb->showInfoDialog(&iw);
pick(h);
}
else
{
if(message.size())
{
YesNoDialog ynd;
ynd.player = h->getOwner();
ynd.text << message;
cb->showYesNoDialog(&ynd,boost::bind(&CGArtifact::fightForArt,this,_1,h));
}
else
{
fightForArt(0,h);
}
}
}
void CGArtifact::pick(const CGHeroInstance * h) const
{
cb->giveHeroArtifact(subID,h->id,-2);
cb->removeObject(id);
}
void CGArtifact::fightForArt( ui32 refusedFight, const CGHeroInstance *h ) const
{
if(!refusedFight)
cb->startBattleI(h->id,army,pos,boost::bind(&CGArtifact::endBattle,this,_1,h));
}
void CGArtifact::endBattle( BattleResult *result, const CGHeroInstance *h ) const
{
if(result->winner == 0) //attacker won
pick(h);
}
void CGPickable::initObj()
{
blockVisit = true;
@ -1453,4 +1536,14 @@ void CGWitchHut::onHeroVisit( const CGHeroInstance * h ) const
}
cb->showInfoDialog(&iw);
}
void CGDwelling::onHeroVisit( const CGHeroInstance * h ) const
{
}
void CGDwelling::initObj()
{
}

View File

@ -5,6 +5,7 @@
#include <vector>
#include <set>
#include <map>
#include <list>
#include "CCreatureHandler.h"
#ifndef _MSC_VER
#include "CHeroHandler.h"
@ -165,18 +166,41 @@ public:
si32 movement; //remaining movement points
si32 identifier; //from the map file
ui8 sex;
struct DLL_EXPORT Patrol
{
Patrol(){patrolling=false;patrolRadious=-1;};
bool patrolling;
int patrolRadious;
} patrol;
ui8 inTownGarrison; // if hero is in town garrison
CGTownInstance * visitedTown; //set if hero is visiting town or in the town garrison
std::vector<ui32> artifacts; //hero's artifacts from bag
std::map<ui16,ui32> artifWorn; //map<position,artifact_id>; positions: 0 - head; 1 - shoulders; 2 - neck; 3 - right hand; 4 - left hand; 5 - torso; 6 - right ring; 7 - left ring; 8 - feet; 9 - misc1; 10 - misc2; 11 - misc3; 12 - misc4; 13 - mach1; 14 - mach2; 15 - mach3; 16 - mach4; 17 - spellbook; 18 - misc5
std::set<ui32> spells; //known spells (spell IDs)
struct DLL_EXPORT Patrol
{
Patrol(){patrolling=false;patrolRadious=-1;};
ui8 patrolling;
si32 patrolRadious;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & patrolling & patrolRadious;
}
} patrol;
struct DLL_EXPORT Bonus
{
ui8 duration; //0 - Permanent, 1 - OneBattle, 2 - OneDay, 3 - OneWeek
ui8 type; //0 - none, 1 - movement; 2 - morale; 3 - luck
si32 val;
ui32 id;
std::string description;
Bonus(ui8 Dur, ui8 Type, si32 Val, ui32 ID, std::string Desc)
:duration(Dur), type(Type), val(Val), id(ID), description(Desc)
{}
Bonus(){};
template <typename Handler> void serialize(Handler &h, const int version)
{
h & duration & type & val & id;
}
};
std::list<Bonus> bonuses;
//////////////////////////////////////////////////////////////////////////
@ -184,7 +208,7 @@ public:
{
h & static_cast<CArmedInstance&>(*this);
h & exp & level & name & biography & portrait & mana & primSkills & secSkills & movement
& identifier & sex & inTownGarrison & artifacts & artifWorn & spells;
& identifier & sex & inTownGarrison & artifacts & artifWorn & spells & patrol & bonuses;
ui8 standardType = (VLC->heroh->heroes[subID] == type);
h & standardType;
@ -207,7 +231,8 @@ public:
si32 manaLimit() const; //maximum mana value for this hero (basically 10*knowledge)
bool canWalkOnSea() const;
int getCurrentLuck() const;
int getCurrentMorale() const;
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
int getPrimSkillLevel(int id) const;
ui8 getSecSkillLevel(const int & ID) const; //0 - no skill
int maxMovePoints(bool onLand) const;
@ -217,6 +242,7 @@ public:
int getSpellSecLevel(int spell) const; //returns level of secondary ability (fire, water, earth, air magic) known to this hero and applicable to given spell; -1 if error
static int3 convertPosition(int3 src, bool toh3m); //toh3m=true: manifest->h3m; toh3m=false: h3m->manifest
//////////////////////////////////////////////////////////////////////////
void initHero();
@ -452,6 +478,9 @@ public:
std::string message;
ui32 spell; //if it's spell scroll
void onHeroVisit(const CGHeroInstance * h) const;
void fightForArt(ui32 refusedFight, const CGHeroInstance *h) const;
void endBattle(BattleResult *result, const CGHeroInstance *h) const;
void pick( const CGHeroInstance * h ) const;
void initObj();
template <typename Handler> void serialize(Handler &h, const int version)
@ -583,6 +612,21 @@ public:
}
};
class DLL_EXPORT CGDwelling : public CGObjectInstance //teleports and subterranean gates
{
public:
static std::map<int,std::map<int, std::vector<int> > > objs; //map[ID][subID] => vector of ids
void onHeroVisit(const CGHeroInstance * h) const;
void initObj();
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CGObjectInstance&>(*this);
}
};
class DLL_EXPORT CObjectHandler
{
public:

View File

@ -4,6 +4,7 @@
#include <string>
#include <vector>
#include <set>
#include <list>
#include <boost/type_traits/is_fundamental.hpp>
#include <boost/type_traits/is_enum.hpp>
@ -263,6 +264,15 @@ public:
for(typename std::set<T>::iterator i=d.begin();i!=d.end();i++)
*this << *i;
}
template <typename T>
void saveSerializable(const std::list<T> &data)
{
std::list<T> &d = const_cast<std::list<T> &>(data);
boost::uint32_t length = d.size();
*this << length;
for(typename std::list<T>::iterator i=d.begin();i!=d.end();i++)
*this << *i;
}
void saveSerializable(const std::string &data)
{
*this << ui32(data.length());
@ -383,6 +393,18 @@ public:
data.insert(ins);
}
}
template <typename T>
void loadSerializable(std::list<T> &data)
{
boost::uint32_t length;
*this >> length;
T ins;
for(ui32 i=0;i<length;i++)
{
*this >> ins;
data.push_back(ins);
}
}
template <typename T1, typename T2>
void loadSerializable(std::pair<T1,T2> &data)
{

View File

@ -33,6 +33,41 @@ template <typename T> struct Query
{
ui32 id;
};
struct MetaString : public CPack<MetaString> //2001 helper for object scrips
{
std::vector<std::string> strings;
std::vector<std::pair<ui8,ui32> > texts; //pairs<text handler type, text number>; types: 1 - generaltexthandler->all; 2 - objh->xtrainfo; 3 - objh->names; 4 - objh->restypes; 5 - arth->artifacts[id].name; 6 - generaltexth->arraytxt; 7 - creh->creatures[os->subID].namePl; 8 - objh->creGens; 9 - objh->mines[ID].first; 10 - objh->mines[ID].second; 11 - objh->advobtxt
std::vector<si32> message;
std::vector<std::string> replacements;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & strings & texts & message & replacements;
}
MetaString& operator<<(const std::pair<ui8,ui32> &txt)
{
message.push_back(-((si32)texts.size())-1);
texts.push_back(txt);
return *this;
}
MetaString& operator<<(const std::string &txt)
{
message.push_back(strings.size()+1);
strings.push_back(txt);
return *this;
}
void clear()
{
strings.clear();
texts.clear();
message.clear();
}
MetaString(){type = 2001;};
};
struct SetResources : public CPack<SetResources> //104
{
SetResources(){res.resize(RESOURCE_QUANTITY);type = 104;};
@ -155,6 +190,23 @@ struct SetAvailableHeroes : public CPack<SetAvailableHeroes> //113
}
};
struct GiveBonus : public CPack<GiveBonus> //115
{
GiveBonus(){type = 115;};
ui8 bduration;
ui8 btype;
si32 bval;
ui32 bid;
ui32 hid;
MetaString bdescr;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & bduration & btype & bval & bid & hid & bdescr;
}
};
struct RemoveObject : public CPack<RemoveObject> //500
{
RemoveObject(){type = 500;};
@ -295,39 +347,6 @@ struct NewTurn : public CPack<NewTurn> //101
// h & sac;
// }
//};
struct MetaString : public CPack<MetaString> //2001 helper for object scrips
{
std::vector<std::string> strings;
std::vector<std::pair<ui8,ui32> > texts; //pairs<text handler type, text number>; types: 1 - generaltexthandler->all; 2 - objh->xtrainfo; 3 - objh->names; 4 - objh->restypes; 5 - arth->artifacts[id].name; 6 - generaltexth->arraytxt; 7 - creh->creatures[os->subID].namePl; 8 - objh->creGens; 9 - objh->mines[ID].first; 10 - objh->mines[ID].second; 11 - objh->advobtxt
std::vector<si32> message;
std::vector<std::string> replacements;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & strings & texts & message & replacements;
}
MetaString& operator<<(const std::pair<ui8,ui32> &txt)
{
message.push_back(-((si32)texts.size())-1);
texts.push_back(txt);
return *this;
}
MetaString& operator<<(const std::string &txt)
{
message.push_back(strings.size()+1);
strings.push_back(txt);
return *this;
}
void clear()
{
strings.clear();
texts.clear();
message.clear();
}
MetaString(){type = 2001;};
};
struct Component : public CPack<Component> //2002 helper for object scrips informations
{
ui16 id, subtype; //ids: 0 - primskill; 1 - secskill; 2 - resource; 3 - creature; 4 - artifact; 5 - experience (sub==0 exp points; sub==1 levels)

View File

@ -1136,20 +1136,37 @@ upgend:
tlog3<<"We cannot move this stack to its destination "<<curStack->creature->namePl<<std::endl;
}
if( (BattleInfo::mutualPosition(ba.destinationTile, ba.additionalInfo) < 0 //destination tile is not neighbouring with enemy stack
&& !curStack->creature->isDoubleWide())
|| (curStack->creature->isDoubleWide()
&& (BattleInfo::mutualPosition(ba.destinationTile, ba.additionalInfo) < 0)
&& (BattleInfo::mutualPosition(ba.destinationTile + (curStack->attackerOwned ? -1 : 1), ba.additionalInfo) < 0))
)
if(!stackAtEnd)
{
tlog3 << "There is no stack on " << ba.additionalInfo << " tile (no attack)!";
break;
}
ui16 curpos = curStack->position,
enemypos = stackAtEnd->position;
if( !(
(BattleInfo::mutualPosition(curpos, enemypos) >= 0) //front <=> front
|| (curStack->creature->isDoubleWide() //back <=> front
&& BattleInfo::mutualPosition(curpos + (curStack->attackerOwned ? -1 : 1), enemypos) >= 0)
|| (stackAtEnd->creature->isDoubleWide() //front <=> back
&& BattleInfo::mutualPosition(curpos, enemypos + (stackAtEnd->attackerOwned ? -1 : 1)) >= 0)
|| (stackAtEnd->creature->isDoubleWide() && curStack->creature->isDoubleWide()//back <=> back
&& BattleInfo::mutualPosition(curpos + (curStack->attackerOwned ? -1 : 1), enemypos + (stackAtEnd->attackerOwned ? -1 : 1)) >= 0)
)
)
{
tlog3 << "Attack cannot be performed!";
sendDataToClients(ui16(3008)); //end movement and attack
break;
}
//attack
BattleAttack bat;
prepareAttack(bat,curStack,stackAtEnd);
sendAndApply(&bat);
//counterattack
if(!vstd::contains(curStack->abilities,NO_ENEMY_RETALIATION)
&& stackAtEnd->alive()
@ -1161,6 +1178,7 @@ upgend:
sendAndApply(&bat);
}
//second attack
if(vstd::contains(curStack->abilities,TWICE_ATTACK)
&& curStack->alive()
&& stackAtEnd->alive() )