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

Version for development release 0.73c

* version set to 0.73c, bumped save format version, updated changelog
* new stack queue for higher resolutions (needs new graphics!)
* improved stack ordering during battle
* many minor fixes
* temporarily disabled AI
This commit is contained in:
Michał W. Urbańczyk 2009-09-20 12:47:40 +00:00
parent 14ee503056
commit ee3c318ed9
24 changed files with 539 additions and 194 deletions

View File

@ -816,6 +816,7 @@ void CGeniusAI::yourTurn()
static boost::mutex mutex;
boost::mutex::scoped_lock lock(mutex);
m_cb->waitTillRealize = true;
m_cb->endTurn();
static int seed = rand();
srand(seed);
if(m_cb->getDate()==1)
@ -843,7 +844,6 @@ void CGeniusAI::yourTurn()
objective->fulfill(*this,trueGameState);
seed = rand();
m_cb->endTurn();
m_cb->waitTillRealize = false;
}

View File

@ -1,4 +1,80 @@
0.72 -> 0.73 (1 Aug 2009) as for r1044
0.73 -> 0.74
GENERAL:
* Scenario Information window
* Save Game window
* VCMI window should start centered
* support for Necromancy and Ballistics secondary skills
* new artifacts supported, including those improving Necromancy, Legion Statue parts, Shackles of War and most of combination artifacts (but not combining)
* Ellipsis won't be split when breaking text on several lines
* split button will be grayed out when no creature is selected
* a few fixes for shipyard window
ADVENTURE INTERFACE:
* Cursor shows if tile is accesible and how many turns away
* moving hero with arrow keys / numpad
* fixed Next Hero button behaviour
* fixed Surface/Underground switch button in higher resolutions
BATTLES:
* partial siege support
* new stack queue for higher resolutions (graphics made by Dru, thx!)
* 'Q' pressing toggles the queue displaying (so it can be enabled/disabled it with single key press)
* more creatures special abilities supported
* stack
* fixed crashes occuring on attacking two hex creatures from back
* even large stack numbers will fit the boxes
* shooters attacking twice (like Grand Elves) won't attack twice in melee
* ballista can shoot even if there's an enemy creature next to it
* improved obstacles placement, so they'll better fit hexes (thx to Ivan!)
* selecting attack directions works as in H3
* estimating damage that will be dealt while choosing stack to be attacked
* modified the positioning of battle effects, they should look about right now.
* after selecting a spell during combat, l-click is locked for any action other than casting.
* new spells supported:
- Anti-Magic
- Cure
- Resurrection
- Animate Dead
- Counterstrike
- Berserk
- Hypnotize
- Blind
- Fire Elemental
- Earth Elemental
- Water Elemental
- Air Elemental
- Remove obstacle
TOWNS:
* enemy castle can be taken over
* garrisoned hero can buy a spellbook
* Lookout Tower supported
* heroes available in tavern sould be always different
* ship bought in town will be correctly placed
HERO WINDOW:
* war machines cannot be unequiped
PREGAME:
* sorting: a second click on the column header sorts in descending order.
* advanced options tab: r-click popups for selected town, hero and bonus
* starting scenario / game by double click
* arrows in options tab are hidden when not available
* subtitles for choosen hero/town/bonus in pregame
OBJECTS:
* fixed pairing Subterranean Gates
New objects supported:
- Borderguard & Keymaster Tent
- Cartographer
- Creature banks
- Eye of the Magi & Hut of the Magi
- Garrison
- Stables
- Pandora Box
0.72 -> 0.73 (1 Aug 2009)
GENERAL:
* infowindow popup will be completely on screen
* fixed possible crash with in game console

View File

@ -1729,7 +1729,8 @@ void CAdvMapInt::centerOn(int3 on)
LOCPLINT->adventureInt->updateScreen=true;
updateMinimap=true;
underground.curimg = on.z; //change underground switch button image
underground.redraw();
if(GH.topInt() == this)
underground.redraw();
}
void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key)
{

View File

@ -25,6 +25,7 @@
#include "../hch/CVideoHandler.h"
#include "../hch/CTownHandler.h"
#include <boost/assign/list_of.hpp>
#include <boost/lexical_cast.hpp>
#ifndef __GNUC__
const double M_PI = 3.14159265358979323846;
#else
@ -100,7 +101,7 @@ bool CBattleAnimation::isEarliest(bool perStackConcurrency)
CReverseAnim * revAnim = dynamic_cast<CReverseAnim *>(stAnim);
if(revAnim && stAnim->stackID == thAnim->stackID && revAnim->priority)
if(revAnim && thAnim && stAnim && stAnim->stackID == thAnim->stackID && revAnim->priority)
return false;
if(it->first)
@ -545,7 +546,8 @@ bool CBattleStackMoved::init()
}
//unit reversed
owner->moveSh = CGI->soundh->playSound(movedStack->creature->sounds.move, -1);
if(owner->moveSh <= 0)
owner->moveSh = CGI->soundh->playSound(movedStack->creature->sounds.move, -1);
//step shift calculation
posX = owner->creAnims[stackID]->pos.x, posY = owner->creAnims[stackID]->pos.y; // for precise calculations ;]
@ -630,6 +632,12 @@ void CBattleStackMoved::endAnim()
owner->creAnims[stackID]->pos.y = coords.second;
}
if(owner->moveSh >= 0)
{
CGI->soundh->stopSound(owner->moveSh);
owner->moveSh = -1;
}
delete this;
}
@ -727,8 +735,6 @@ void CBattleMoveEnd::endAnim()
owner->creAnims[stackID]->setType(2); //resetting to default
CGI->curh->show();
CGI->soundh->stopSound(owner->moveSh);
delete this;
}
@ -1011,13 +1017,29 @@ CBattleInterface::CBattleInterface(CCreatureSet * army1, CCreatureSet * army2, C
: attackingHeroInstance(hero1), defendingHeroInstance(hero2), animCount(0), activeStack(-1), stackToActivate(-1),
mouseHoveredStack(-1), previouslyHoveredHex(-1), currentlyHoveredHex(-1), spellDestSelectMode(false),
spellToCast(NULL), givenCommand(NULL), myTurn(false), resWindow(NULL), animIDhelper(0),
showStackQueue(false), moveStarted(false), moveSh(-1), siegeH(NULL), bresult(NULL)
moveStarted(false), moveSh(-1), siegeH(NULL), bresult(NULL), queue(NULL)
{
ObjectConstruction h__l__p(this);
animsAreDisplayed.setn(false);
pos = myRect;
strongInterest = true;
givenCommand = new CondSh<BattleAction *>(NULL);
//create stack queue
bool embedQueue = screen->h < 700;
queue = new CStackQueue(embedQueue);
if(!embedQueue && settings.showQueue)
{
pos.y += queue->pos.h / 2; //center whole window
queue->moveTo(Point(pos.x, pos.y - queue->pos.h));
// queue->pos.x = pos.x;
// queue->pos.y = pos.y - queue->pos.h;
// pos.h += queue->pos.h;
// center();
}
queue->update();
//preparing siege info
const CGTownInstance * town = LOCPLINT->cb->battleGetDefendedTown();
if(town)
@ -1239,6 +1261,7 @@ CBattleInterface::~CBattleInterface()
delete attackingHero;
delete defendingHero;
delete queue;
SDL_FreeSurface(cellBorder);
SDL_FreeSurface(cellShade);
@ -1297,6 +1320,8 @@ void CBattleInterface::activate()
attackingHero->activate();
if(defendingHero)
defendingHero->activate();
if(settings.showQueue)
queue->activate();
LOCPLINT->cingconsole->activate();
}
@ -1323,6 +1348,8 @@ void CBattleInterface::deactivate()
attackingHero->deactivate();
if(defendingHero)
defendingHero->deactivate();
if(settings.showQueue)
queue->deactivate();
LOCPLINT->cingconsole->deactivate();
}
@ -1337,6 +1364,7 @@ void CBattleInterface::show(SDL_Surface * to)
SDL_Rect buf;
SDL_GetClipRect(to, &buf);
SDL_SetClipRect(to, &pos);
//printing background and hexes
if(activeStack != -1 && creAnims[activeStack]->getType() != 0) //show everything with range
{
@ -1492,11 +1520,6 @@ void CBattleInterface::show(SDL_Surface * to)
{
activateStack();
}
if(pendingAnims.size() == 0 && bresult != NULL)
{
displayBattleFinished();
}
//anims ended
animsAreDisplayed.setn(false);
}
@ -1531,53 +1554,6 @@ void CBattleInterface::show(SDL_Surface * to)
SDL_BlitSurface(bitmapToBlit, NULL, to, &genRect(bitmapToBlit->h, bitmapToBlit->w, pos.x + it->x, pos.y + it->y));
}
}
//showing queue of stacks
if(showStackQueue)
{
const int QUEUE_SIZE = 10;
int xPos = screen->w/2 - ( stacks.size() * 37 )/2;
int yPos = (screen->h - 600)/2 + 10;
std::vector<const CStack *> stacksSorted;
// const CStack *curStack = LOCPLINT->cb->battleGetStackByID(activeStack);
// if(curStack)
// stacksSorted.push_back(curStack);
LOCPLINT->cb->getStackQueue(stacksSorted, QUEUE_SIZE);
for(size_t b=0; b < stacksSorted.size(); ++b)
{
const CStack * s = stacksSorted[b];
SDL_BlitSurface(graphics->smallImgs[-2], NULL, to, &genRect(32, 32, xPos, yPos));
//printing colored border
for(int xFrom = xPos-1; xFrom<xPos+33; ++xFrom)
{
for(int yFrom = yPos-1; yFrom<yPos+33; ++yFrom)
{
if(xFrom == xPos-1 || xFrom == xPos+32 || yFrom == yPos-1 || yFrom == yPos+32)
{
SDL_Color pc;
if(s->owner != 255)
{
pc = graphics->playerColors[s->owner];
}
else
{
pc = *graphics->neutralColor;
}
CSDL_Ext::SDL_PutPixelWithoutRefresh(to, xFrom, yFrom, pc.r, pc.g, pc.b);
}
}
}
//colored border printed
SDL_BlitSurface(graphics->smallImgs[s->creature->idNumber], NULL, to, &genRect(32, 32, xPos, yPos));
xPos += 37;
}
}
SDL_SetClipRect(to, &buf); //restoring previous clip_rect
@ -1594,15 +1570,35 @@ void CBattleInterface::show(SDL_Surface * to)
//showing in-game console
LOCPLINT->cingconsole->show(to);
Rect posWithQueue = Rect(pos.x, pos.y, 800, 600);
if(settings.showQueue)
{
if(!queue->embedded)
{
posWithQueue.y -= queue->pos.h;
posWithQueue.h += queue->pos.h;
}
//showing queue
if(!bresult)
queue->showAll(to);
}
//printing border around interface
if(screen->w != 800 || screen->h !=600)
CMessage::drawBorder(LOCPLINT->playerID,to,828,628,pos.x-14,pos.y-15);
{
CMessage::drawBorder(LOCPLINT->playerID,to,posWithQueue.w + 28, posWithQueue.h + 28, posWithQueue.x-14, posWithQueue.y-15);
}
}
void CBattleInterface::keyPressed(const SDL_KeyboardEvent & key)
{
if(key.keysym.sym == SDLK_q)
if(key.keysym.sym == SDLK_q && key.state == SDL_PRESSED)
{
showStackQueue = key.state==SDL_PRESSED;
if(settings.showQueue) //hide queue
hideQueue();
else
showQueue();
}
else if(key.keysym.sym == SDLK_ESCAPE && spellDestSelectMode)
{
@ -2121,7 +2117,7 @@ void CBattleInterface::newRound(int number)
void CBattleInterface::giveCommand(ui8 action, ui16 tile, ui32 stack, si32 additional)
{
if(!LOCPLINT->cb->battleGetStackByID(stack))
if(!LOCPLINT->cb->battleGetStackByID(stack) && action != 1 && action != 4 && action != 5)
{
return;
}
@ -2406,7 +2402,9 @@ void CBattleInterface::stackIsShooting(int ID, int dest)
void CBattleInterface::battleFinished(const BattleResult& br)
{
bresult = &br;
//animsAreDisplayed.waitUntil(false);
LOCPLINT->pim->unlock();
animsAreDisplayed.waitUntil(false);
LOCPLINT->pim->lock();
displayBattleFinished();
}
@ -2602,6 +2600,7 @@ int CBattleInterface::getAnimSpeed() const
void CBattleInterface::activateStack()
{
activeStack = stackToActivate;
queue->update();
stackToActivate = -1;
myTurn = true;
redrawBackgroundWithHexes(activeStack);
@ -2899,6 +2898,51 @@ void CBattleInterface::projectileShowHelper(SDL_Surface * to)
}
}
void CBattleInterface::endAction(const BattleAction* action)
{
//if((action->actionType==2 || (action->actionType==6 && action->destinationTile!=cb->battleGetPos(action->stackNumber)))) //activating interface when move is finished
{
activate();
}
if(action->actionType == 1)
{
if(action->side)
defendingHero->setPhase(0);
else
attackingHero->setPhase(0);
}
if(action->actionType == 2 && creAnims[action->stackNumber]->getType() != 2) //walk or walk & attack
{
pendingAnims.push_back(std::make_pair(new CBattleMoveEnd(this, action->stackNumber, action->destinationTile), false));
}
}
void CBattleInterface::hideQueue()
{
settings.showQueue = false;
//if(queue->active)
queue->deactivate();
if(!queue->embedded)
{
moveBy(Point(0, -queue->pos.h / 2));
GH.totalRedraw();
}
}
void CBattleInterface::showQueue()
{
settings.showQueue = true;
//if(!queue->active)
queue->activate();
if(!queue->embedded)
{
moveBy(Point(0, +queue->pos.h / 2));
GH.totalRedraw();
}
}
void CBattleHero::show(SDL_Surface *to)
{
//animation of flag
@ -3706,3 +3750,119 @@ void CBattleInterface::SiegeHelper::printPartOfWall(SDL_Surface * to, int what)
blitAt(walls[what], pos.x, pos.y, to);
}
}
void CStackQueue::update()
{
stacksSorted.clear();
LOCPLINT->cb->getStackQueue(stacksSorted, QUEUE_SIZE);
for (int i = 0; i < QUEUE_SIZE ; i++)
{
stackBoxes[i]->setStack(stacksSorted[i]);
}
}
CStackQueue::CStackQueue(bool Embedded)
:embedded(Embedded)
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
if(embedded)
{
box = NULL;
bg = NULL;
pos.w = QUEUE_SIZE * 37;
pos.h = 32; //height of small creature img
pos.x = screen->w/2 - pos.w/2;
pos.y = (screen->h - 600)/2 + 10;
}
else
{
box = BitmapHandler::loadBitmap("CHRROP.pcx");
bg = BitmapHandler::loadBitmap("DIBOXPI.pcx");
pos.w = 600;
pos.h = bg->h;
}
stackBoxes.resize(QUEUE_SIZE);
for (int i = 0; i < QUEUE_SIZE; i++)
{
stackBoxes[i] = new StackBox(box);
stackBoxes[i]->pos.x += 6 + (embedded ? 37 : 79)*i;
}
}
CStackQueue::~CStackQueue()
{
SDL_FreeSurface(box);
}
void CStackQueue::showAll( SDL_Surface *to )
{
if(bg)
{
for (int w = 0; w < pos.w; w += bg->w)
{
blitAtLoc(bg, w, 0, to);
}
}
CIntObject::showAll(to);
}
void CStackQueue::StackBox::showAll( SDL_Surface *to )
{
assert(my);
if(bg)
{
graphics->blueToPlayersAdv(bg, my->owner);
//SDL_UpdateRect(bg, 0, 0, 0, 0);
blitAt(bg, pos, to);
blitAt(graphics->bigImgs[my->creature->idNumber], pos.x +9, pos.y + 1, to);
printAtMiddleLoc(makeNumberShort(my->amount), pos.w/2, pos.h - 12, FONT_MEDIUM, zwykly, to);
}
else
{
blitAt(graphics->smallImgs[-2], pos, to);
blitAt(graphics->smallImgs[my->creature->idNumber], pos, to);
const SDL_Color &ownerColor = (my->owner == 255 ? *graphics->neutralColor : graphics->playerColors[my->owner]);
CSDL_Ext::drawBorder(to, pos, int3(ownerColor.r, ownerColor.g, ownerColor.b));
printAtMiddleLoc(makeNumberShort(my->amount), pos.w/2, pos.h - 8, FONT_TINY, zwykly, to);
}
}
void CStackQueue::StackBox::setStack( const CStack *nStack )
{
my = nStack;
}
CStackQueue::StackBox::StackBox(SDL_Surface *BG)
:bg(BG), my(NULL)
{
if(bg)
{
pos.w = bg->w;
pos.h = bg->h;
}
else
{
pos.w = pos.h = 32;
}
pos.y += 2;
}
CStackQueue::StackBox::~StackBox()
{
}
void CStackQueue::StackBox::hover( bool on )
{
}
BattleSettings::BattleSettings()
{
printCellBorders = true;
printStackRange = true;
animSpeed = 2;
printMouseShadow = true;
showQueue = true;
}

View File

@ -316,22 +316,16 @@ public:
struct BattleSettings
{
BattleSettings()
{
printCellBorders = true;
printStackRange = true;
animSpeed = 2;
printMouseShadow = true;
}
BattleSettings();
bool printCellBorders; //if true, cell borders will be printed
bool printStackRange; //if true,range of active stack will be printed
int animSpeed; //speed of animation; 1 - slowest, 2 - medium, 4 - fastest
bool printMouseShadow; //if true, hex under mouse will be shaded
bool showQueue;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & printCellBorders & printStackRange & animSpeed & printMouseShadow;
h & printCellBorders & printStackRange & animSpeed & printMouseShadow & showQueue;
}
};
@ -343,6 +337,37 @@ struct SBattleEffect
int effectID; //uniqueID equal ot ID of appropriate CSpellEffectAnim
};
class CStackQueue : public CIntObject
{
class StackBox : public CIntObject
{
public:
const CStack *my;
SDL_Surface *bg;
void hover (bool on);
void showAll(SDL_Surface *to);
void setStack(const CStack *nStack);
StackBox(SDL_Surface *BG);
~StackBox();
};
public:
static const int QUEUE_SIZE = 10;
const bool embedded;
std::vector<const CStack *> stacksSorted;
std::vector<StackBox *> stackBoxes;
SDL_Surface *box;
SDL_Surface *bg;
void showAll(SDL_Surface *to);
CStackQueue(bool Embedded);
~CStackQueue();
void update();
//void showAll(SDL_Surface *to);
};
class CBattleInterface : public CIntObject
{
private:
@ -351,6 +376,7 @@ private:
* bWait, * bDefence, * bConsoleUp, * bConsoleDown;
CBattleConsole * console;
CBattleHero * attackingHero, * defendingHero; //fighting heroes
CStackQueue *queue;
CCreatureSet * army1, * army2; //fighting armies
CGHeroInstance * attackingHeroInstance, * defendingHeroInstance;
std::map< int, CCreatureAnimation * > creAnims; //animations of creatures from fighting armies (order by BattleInfo's stacks' ID)
@ -428,7 +454,6 @@ public:
CondSh<BattleAction *> *givenCommand; //data != NULL if we have i.e. moved current unit
bool myTurn; //if true, interface is active (commands can be ordered
CBattleResultWindow * resWindow; //window of end of battle
bool showStackQueue; //if true, queue of stacks will be shown
bool moveStarted; //if true, the creature that is already moving is going to make its first step
int moveSh; // sound handler used when moving a unit
@ -471,6 +496,9 @@ public:
void battleStacksEffectsSet(const SetStackEffect & sse); //called when a specific effect is set to stacks
void castThisSpell(int spellID); //called when player has chosen a spell from spellbook
void displayEffect(ui32 effect, int destTile); //displays effect of a spell on the battlefield; affected: true - attacker. false - defender
void endAction(const BattleAction* action);
void hideQueue();
void showQueue();
friend class CBattleHex;
friend class CBattleResultWindow;

View File

@ -524,6 +524,8 @@ void CCastleInterface::close()
{
if(town->visitingHero)
LOCPLINT->adventureInt->select(town->visitingHero);
else
LOCPLINT->adventureInt->select(town);
LOCPLINT->castleInt = NULL;
GH.popIntTotally(this);
CGI->musich->stopMusic(5000);
@ -906,6 +908,7 @@ void CCastleInterface::recreateBuildings()
}
//ship in shipyard
bool isThereShip = false;
if(vstd::contains(town->builtBuildings,6))
{
std::vector <const CGObjectInstance *> vobjs = LOCPLINT->cb->getVisitableObjs(town->bestLocation());
@ -914,6 +917,7 @@ void CCastleInterface::recreateBuildings()
Structure * st = CGI->townh->structures[town->subID][20];
buildings.push_back(new CBuildingRect(st));
s.insert(std::pair<int,int>(st->group,st->ID));
isThereShip = true;
}
}
@ -943,26 +947,35 @@ void CCastleInterface::recreateBuildings()
}
}
//code for the shipyard in the Castle
else if((town->subID == 0) && (town->builtBuildings.find(6)!=town->builtBuildings.end()))
else if(town->subID == 0)
{
CBuildingRect *shipyard = NULL;
for(size_t i=0;i<buildings.size();i++)
int shipID = 0;
if(isThereShip)
shipID = 20;
else if(vstd::contains(town->builtBuildings, 6))
shipID = 6;
if(shipID)
{
if(buildings[i]->str->ID==6)
CBuildingRect *shipyard = NULL;
for(size_t i=0;i<buildings.size();i++)
{
shipyard=buildings[i];
break;
if(buildings[i]->str->ID==shipID)
{
shipyard=buildings[i];
break;
}
}
if(town->builtBuildings.find(8)!=town->builtBuildings.end()) //there is citadel
{
shipyard->offset = 1;
shipyard->max = shipyard->def->ourImages.size();
}
else
{
shipyard->offset = 0;
shipyard->max = 1;
}
}
if(town->builtBuildings.find(8)!=town->builtBuildings.end()) //there is citadel
{
shipyard->offset = 1;
shipyard->max = shipyard->def->ourImages.size();
}
else
{
shipyard->offset = 0;
shipyard->max = 1;
}
}

View File

@ -1085,22 +1085,7 @@ void CPlayerInterface::actionFinished(const BattleAction* action)
boost::unique_lock<boost::recursive_mutex> un(*pim);
delete curAction;
curAction = NULL;
//if((action->actionType==2 || (action->actionType==6 && action->destinationTile!=cb->battleGetPos(action->stackNumber)))) //activating interface when move is finished
{
battleInt->activate();
}
if(action->actionType == 1)
{
if(action->side)
battleInt->defendingHero->setPhase(0);
else
battleInt->attackingHero->setPhase(0);
}
if(action->actionType == 2 && battleInt->creAnims[action->stackNumber]->getType() != 2) //walk or walk & attack
{
battleInt->pendingAnims.push_back(std::make_pair(new CBattleMoveEnd(battleInt, action->stackNumber, action->destinationTile), false));
}
battleInt->endAction(action);
}
BattleAction CPlayerInterface::activeStack(int stackID) //called when it's turn of that stack

View File

@ -631,6 +631,20 @@ const Rect & CIntObject::center()
return center(pos);
}
void CIntObject::moveBy( const Point &p, bool propagate /*= true*/ )
{
pos.x += p.x;
pos.y += p.y;
if(propagate)
for(size_t i = 0; i < children.size(); i++)
children[i]->moveBy(p, propagate);
}
void CIntObject::moveTo( const Point &p, bool propagate /*= true*/ )
{
moveBy(Point(p.x - pos.x, p.y - pos.y), propagate);
}
CPicture::CPicture( SDL_Surface *BG, int x, int y, bool Free )
{
bg = BG;
@ -647,8 +661,15 @@ CPicture::CPicture( const std::string &bmpname, int x, int y )
freeSurf = true;;
pos.x += x;
pos.y += y;
pos.w = bg->w;
pos.h = bg->h;
if(bg)
{
pos.w = bg->w;
pos.h = bg->h;
}
else
{
pos.w = pos.h = 0;
}
}
CPicture::~CPicture()
@ -659,7 +680,8 @@ CPicture::~CPicture()
void CPicture::showAll( SDL_Surface * to )
{
blitAt(bg, pos, to);
if(bg)
blitAt(bg, pos, to);
}
ObjectConstruction::ObjectConstruction( CIntObject *obj )

View File

@ -191,6 +191,10 @@ struct Rect : public SDL_Rect
y -= p.y;
return *this;
}
template<typename T> Rect operator-(const T &t)
{
return Rect(x + t.x, y + t.y, w, h);
}
Rect operator&(const Rect &p) const //rect intersection
{
bool intersect = true;
@ -355,6 +359,8 @@ public:
bool isItInLoc(const SDL_Rect &rect, const Point &p);
const Rect & center(const Rect &r); //sets pos so that r will be in the center of screen, returns new position
const Rect & center(); //centers when pos.w and pos.h are set, returns new position
void moveBy(const Point &p, bool propagate = true);
void moveTo(const Point &p, bool propagate = true);
};
//class for binding keys to left mouse button clicks

View File

@ -1885,7 +1885,7 @@ CRecruitmentWindow::CRecruitmentWindow(const CGDwelling *Dwelling, int Level, co
max = new AdventureMapButton(CGI->generaltexth->zelp[553],boost::bind(&CRecruitmentWindow::Max,this),pos.x+134,pos.y+313,"IRCBTNS.DEF",SDLK_m);
buy = new AdventureMapButton(CGI->generaltexth->zelp[554],boost::bind(&CRecruitmentWindow::Buy,this),pos.x+212,pos.y+313,"IBY6432.DEF",SDLK_RETURN);
cancel = new AdventureMapButton(CGI->generaltexth->zelp[555],boost::bind(&CRecruitmentWindow::Cancel,this),pos.x+290,pos.y+313,"ICN6432.DEF",SDLK_ESCAPE);
slider = new CSlider(pos.x+176,pos.y+279,135,boost::bind(&CRecruitmentWindow::sliderMoved,this, _1),1,0,0,true);
slider = new CSlider(pos.x+176,pos.y+279,135,boost::bind(&CRecruitmentWindow::sliderMoved,this, _1),0,0,0,true);
initCres();
@ -1990,7 +1990,7 @@ CSplitWindow::CSplitWindow(int cid, int max, CGarrisonInt *Owner, int Last, int
ok = new AdventureMapButton("","",boost::bind(&CSplitWindow::split,this),pos.x+20,pos.y+263,"IOK6432.DEF",SDLK_RETURN);
cancel = new AdventureMapButton("","",boost::bind(&CSplitWindow::close,this),pos.x+214,pos.y+263,"ICN6432.DEF",SDLK_ESCAPE);
int sliderPositions = max - (last>=0) - (last==2);
slider = new CSlider(pos.x+21,pos.y+194,257,boost::bind(&CSplitWindow::sliderMoved,this,_1),1,sliderPositions,val,true);
slider = new CSlider(pos.x+21,pos.y+194,257,boost::bind(&CSplitWindow::sliderMoved,this,_1),0,sliderPositions,val,true);
a1 = max-val;
a2 = val;
anim = new CCreaturePic(&CGI->creh->creatures[cid]);
@ -2875,7 +2875,7 @@ CSystemOptionsWindow::~CSystemOptionsWindow()
void CSystemOptionsWindow::bquitf()
{
LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[578], std::vector<SComponent*>(), boost::bind(exit, 0), boost::bind(&CSystemOptionsWindow::activate, this), false);
LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[578], std::vector<SComponent*>(), boost::bind(exit, 0), 0, false);
}
void CSystemOptionsWindow::breturnf()

View File

@ -527,10 +527,11 @@ void Graphics::blueToPlayersAdv(SDL_Surface * sur, int player)
return;
}
for(int i=0; i<32; ++i)
{
sur->format->palette->colors[224+i] = palette[i];
}
SDL_SetColors(sur, palette, 224, 32);
//for(int i=0; i<32; ++i)
//{
// sur->format->palette->colors[224+i] = palette[i];
//}
}
else if(sur->format->BitsPerPixel == 24) //should never happen in general
{

View File

@ -829,7 +829,7 @@ void CSDL_Ext::update(SDL_Surface * what)
if(what)
SDL_UpdateRect(what, 0, 0, what->w, what->h);
}
void CSDL_Ext::drawBorder(SDL_Surface * sur, int x, int y, int w, int h, int3 color)
void CSDL_Ext::drawBorder(SDL_Surface * sur, int x, int y, int w, int h, const int3 &color)
{
for(int i=0;i<w;i++)
{
@ -842,6 +842,12 @@ void CSDL_Ext::drawBorder(SDL_Surface * sur, int x, int y, int w, int h, int3 co
SDL_PutPixelWithoutRefresh(sur,x+w-1,y+i,color.x,color.y,color.z);
}
}
void CSDL_Ext::drawBorder( SDL_Surface * sur, const SDL_Rect &r, const int3 &color )
{
drawBorder(sur, r.x, r.y, r.w, r.h, color);
}
void CSDL_Ext::setPlayerColor(SDL_Surface * sur, unsigned char player)
{
if(player==254)

View File

@ -124,7 +124,8 @@ namespace CSDL_Ext
void printAtMiddleWB(const std::string & text, int x, int y, EFonts font, int charpr, SDL_Color kolor=tytulowy, SDL_Surface * dst=screen, bool refrsh = false);
void update(SDL_Surface * what = screen); //updates whole surface (default - main screen)
void drawBorder(SDL_Surface * sur, int x, int y, int w, int h, int3 color);
void drawBorder(SDL_Surface * sur, int x, int y, int w, int h, const int3 &color);
void drawBorder(SDL_Surface * sur, const SDL_Rect &r, const int3 &color);
void setPlayerColor(SDL_Surface * sur, unsigned char player); //sets correct color of flags; -1 for neutral
std::string processStr(std::string str, std::vector<std::string> & tor); //replaces %s in string
SDL_Surface * newSurface(int w, int h, SDL_Surface * mod=screen); //creates new surface, with flags/format same as in surface given

View File

@ -167,7 +167,7 @@ Names_of_Units_DEFS_in_order_of_ID
165 ZM165GD.DEF
166 ZM166GD.DEF
167 ZM167GD.DEF
168 ZM168GD.DEF
168 ZM168DG.DEF
169 ZM169ZL.DEF
170 ZM170SW.DEF
171 ZM171SR.DEF

View File

@ -14,6 +14,7 @@ CASTLE 0
37
16
6
20
18
19
34

View File

@ -7,6 +7,9 @@ GROUP
3
4
GROUP
6
20
GROUP
7
8
9

View File

@ -160,6 +160,7 @@
+ 117 SPELL_DAMAGE_REDUCTION 95 -1 0 //diamond golems reduce dmg from spells
+ 121 LEVEL_SPELL_IMMUNITY 5 0 0 //magic elementals are immune to all spells
+ 123 DOUBLE_WIDE 0 0 0 //ice elemental should be treated as double-wide
- 133 FLYING //Crystal Dragons do not fly
+ 140 DOUBLE_WIDE 0 0 0 //boar should be treated as double-wide
+ 142 DOUBLE_WIDE 0 0 0 //nomads should be treated as double-wide
+ 144 FULL_HP_REGENERATION 0 0 0 //troll

View File

@ -20,7 +20,7 @@ typedef boost::int8_t si8; //signed int 8 bits (1 byte)
#define THC
#endif
#define NAME_VER ("VCMI 0.73b")
#define NAME_VER ("VCMI 0.73c")
extern std::string NAME; //full name
extern std::string NAME_AFFIX; //client / server
#define CONSOLE_LOGGING_LEVEL 5

View File

@ -1582,7 +1582,7 @@ int3 CGTownInstance::getSightCenter() const
void CGTownInstance::getOutOffsets( std::vector<int3> &offsets ) const
{
offsets += int3(-1,3,0), int3(-3,3,0);
offsets += int3(-1,2,0), int3(-3,2,0);
}
void CGTownInstance::fightOver( const CGHeroInstance *h, BattleResult *result ) const

View File

@ -661,36 +661,36 @@ std::pair< std::vector<int>, int > BattleInfo::getPath(int start, int dest, bool
return std::make_pair(path, dist[dest]);
}
int CStack::valOfFeatures(StackFeature::ECombatFeatures type, int subtype) const
int CStack::valOfFeatures(StackFeature::ECombatFeatures type, int subtype, int turn) const
{
int ret = 0;
if(subtype == -1024) //any subtype
{
for(std::vector<StackFeature>::const_iterator i=features.begin(); i != features.end(); i++)
if(i->type == type)
if(i->type == type && (!turn || i->turnsRemain > turn))
ret += i->value;
}
else //given subtype
{
for(std::vector<StackFeature>::const_iterator i=features.begin(); i != features.end(); i++)
if(i->type == type && i->subtype == subtype)
if(i->type == type && i->subtype == subtype && (!turn || i->turnsRemain > turn))
ret += i->value;
}
return ret;
}
bool CStack::hasFeatureOfType(StackFeature::ECombatFeatures type, int subtype) const
bool CStack::hasFeatureOfType(StackFeature::ECombatFeatures type, int subtype, int turn) const
{
if(subtype == -1024) //any subtype
{
for(std::vector<StackFeature>::const_iterator i=features.begin(); i != features.end(); i++)
if(i->type == type)
if(i->type == type && (!turn || i->turnsRemain > turn))
return true;
}
else //given subtype
{
for(std::vector<StackFeature>::const_iterator i=features.begin(); i != features.end(); i++)
if(i->type == type && i->subtype == subtype)
if(i->type == type && i->subtype == subtype && (!turn || i->turnsRemain > turn))
return true;
}
return false;
@ -712,19 +712,19 @@ CStack::CStack(CCreature * C, int A, int O, int I, bool AO, int S)
state.insert(ALIVE);
}
ui32 CStack::Speed() const
ui32 CStack::Speed( int turn /*= 0*/ ) const
{
if(hasFeatureOfType(StackFeature::SIEGE_WEAPON)) //war machnes cannot move
if(hasFeatureOfType(StackFeature::SIEGE_WEAPON, -1024, turn)) //war machnes cannot move
return 0;
int speed = creature->speed;
speed += valOfFeatures(StackFeature::SPEED_BONUS);
speed += valOfFeatures(StackFeature::SPEED_BONUS, -1024, turn);
int percentBonus = 0;
for(int g=0; g<features.size(); ++g)
{
if(features[g].type == StackFeature::SPEED_BONUS)
if(features[g].type == StackFeature::SPEED_BONUS, -1024, turn)
{
percentBonus += features[g].additionalInfo;
}
@ -748,11 +748,12 @@ ui32 CStack::Speed() const
return speed;
}
const CStack::StackEffect * CStack::getEffect(ui16 id) const
const CStack::StackEffect * CStack::getEffect( ui16 id, int turn /*= 0*/ ) const
{
for (unsigned int i=0; i< effects.size(); i++)
if(effects[i].id == id)
return &effects[i];
if(!turn || effects[i].turnsRemain > turn)
return &effects[i];
return NULL;
}
@ -838,22 +839,25 @@ ui16 CStack::MaxHealth() const
return creature->hitPoints + valOfFeatures(StackFeature::HP_BONUS);
}
bool CStack::willMove() const
bool CStack::willMove(int turn /*= 0*/) const
{
return !vstd::contains(state, DEFENDING)
&& !moved()
&& canMove();
return ( turn ? true : !vstd::contains(state, DEFENDING) )
&& !moved(turn)
&& canMove(turn);
}
bool CStack::canMove() const
bool CStack::canMove( int turn /*= 0*/ ) const
{
return alive()
&& ! hasFeatureOfType(StackFeature::NOT_ACTIVE); //eg. Ammo Cart
&& !hasFeatureOfType(StackFeature::NOT_ACTIVE, -1024, turn); //eg. Ammo Cart
}
bool CStack::moved() const
bool CStack::moved( int turn /*= 0*/ ) const
{
return vstd::contains(state, MOVED);
if(!turn)
return vstd::contains(state, MOVED);
else
return false;
}
CGHeroInstance * CGameState::HeroesPool::pickHeroFor(bool native, int player, const CTown *town, std::map<ui32,CGHeroInstance *> &available) const
@ -2150,6 +2154,15 @@ void CGameState::calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, int
int cost = getMovementCost(hero, cp->coord, dp.coord, movement);
int remains = movement - cost;
if(remains < 0)
{
//occurs rarely, when hero with low movepoints tries to go leave the road
turn++;
movement = hero->maxMovePoints(ct.tertype != TerrainTile::water);
cost = getMovementCost(hero, cp->coord, dp.coord, movement); //cost must be updated, movement points changed :(
remains = movement - cost;
}
if(dp.turns==0xff //we haven't been here before
|| dp.turns > turn
|| (dp.turns >= turn && dp.moveRemains < remains)) //this route is faster
@ -2760,7 +2773,7 @@ bool CGameState::battleCanShoot(int ID, int dest)
const CStack * BattleInfo::getNextStack() const
{
std::vector<const CStack *> hlp;
getStackQueue(hlp, 1, 2);
getStackQueue(hlp, 1, -1);
if(hlp.size())
return hlp[0];
@ -2768,7 +2781,7 @@ const CStack * BattleInfo::getNextStack() const
return NULL;
}
static const CStack *takeStack(std::vector<const CStack *> &st, int &curside)
static const CStack *takeStack(std::vector<const CStack *> &st, int &curside, int turn)
{
const CStack *ret = NULL;
unsigned i, //fastest stack
@ -2782,7 +2795,7 @@ static const CStack *takeStack(std::vector<const CStack *> &st, int &curside)
return NULL;
const CStack *fastest = st[i], *other = NULL;
int bestSpeed = fastest->Speed();
int bestSpeed = fastest->Speed(turn);
if(fastest->attackerOwned != curside)
{
@ -2793,7 +2806,7 @@ static const CStack *takeStack(std::vector<const CStack *> &st, int &curside)
for(j = i + 1; j < st.size(); j++)
{
if(!st[j]) continue;
if(st[j]->attackerOwned != curside || st[j]->Speed() != bestSpeed)
if(st[j]->attackerOwned != curside || st[j]->Speed(turn) != bestSpeed)
break;
}
@ -2804,7 +2817,7 @@ static const CStack *takeStack(std::vector<const CStack *> &st, int &curside)
else
{
other = st[j];
if(other->Speed() != bestSpeed)
if(other->Speed(turn) != bestSpeed)
ret = fastest;
else
ret = other;
@ -2821,43 +2834,55 @@ static const CStack *takeStack(std::vector<const CStack *> &st, int &curside)
return ret;
}
void BattleInfo::getStackQueue( std::vector<const CStack *> &out, int howMany, int mode, int lastMoved ) const
void BattleInfo::getStackQueue( std::vector<const CStack *> &out, int howMany, int turn /*= 0*/, int lastMoved /*= -1*/ ) const
{
//we'll split creatures with remaining movement to 4 parts
std::vector<const CStack *> phase[4]; //0 - turrets/catapult, 1 - normal (unmoved) creatures, other war machines, 2 - waited cres that had morale, 3 - rest of waited cres
int toMove = 0; //how many stacks still has move
const CStack *active = getStack(activeStack);
//active stack hasn't taken any action yet - must be placed at the beginning of queue, no matter what
if(!turn && active && active->willMove() && !vstd::contains(active->state, WAITING))
{
out.push_back(active);
if(out.size() == howMany)
return;
}
for(unsigned int i=0; i<stacks.size(); ++i)
{
const CStack * const s = stacks[i];
if(mode != 1 && s->willMove()
|| mode == 1 && s->canMove())
if(turn <= 0 && !s->willMove() //we are considering current round and stack won't move
|| turn > 0 && !s->canMove(turn) //stack won't be able to move in later rounds
|| turn <= 0 && s == active) //it's active stack already added at the beginning of queue
{
int p = -1; //in which phase this tack will move?
if(!mode && vstd::contains(s->state, WAITING))
{
if(vstd::contains(s->state, HAD_MORALE))
p = 2;
else
p = 3;
}
else if(vstd::contains(s->state, StackFeature::SIEGE_WEAPON) //catapult and turrets are first
&& (s->creature->idNumber == 145 || s->creature->idNumber == 149))
{
p = 0;
}
else
{
p = 1;
}
phase[p].push_back(s);
toMove++;
continue;
}
int p = -1; //in which phase this tack will move?
if(turn <= 0 && vstd::contains(s->state, WAITING)) //consider waiting state only for ongoing round
{
if(vstd::contains(s->state, HAD_MORALE))
p = 2;
else
p = 3;
}
else if(s->creature->idNumber == 145 || s->creature->idNumber == 149) //catapult and turrets are first
{
p = 0;
}
else
{
p = 1;
}
phase[p].push_back(s);
toMove++;
}
for(int i = 0; i < 4; i++)
std::sort(phase[i].begin(), phase[i].end(), CMP_stack(i));
std::sort(phase[i].begin(), phase[i].end(), CMP_stack(i, turn > 0 ? turn : 0));
for(size_t i = 0; i < phase[0].size() && i < howMany; i++)
out.push_back(phase[0][i]);
@ -2867,12 +2892,12 @@ void BattleInfo::getStackQueue( std::vector<const CStack *> &out, int howMany, i
if(lastMoved == -1)
{
const CStack *current = getStack(activeStack);
if(current)
if(active)
{
lastMoved = !current->attackerOwned;
if(!current->willMove() || mode == 2)
lastMoved = !lastMoved;
if(out.size() && out.front() == active)
lastMoved = active->attackerOwned;
else
lastMoved = active->attackerOwned;
}
else
{
@ -2883,14 +2908,14 @@ void BattleInfo::getStackQueue( std::vector<const CStack *> &out, int howMany, i
int pi = 1;
while(out.size() < howMany)
{
const CStack *hlp = takeStack(phase[pi], lastMoved);
const CStack *hlp = takeStack(phase[pi], lastMoved, turn);
if(!hlp)
{
pi++;
if(pi > 3)
{
if(mode != 2)
getStackQueue(out, howMany, 1, lastMoved);
//if(turn != 2)
getStackQueue(out, howMany, turn + 1, lastMoved);
return;
}
}
@ -3003,7 +3028,7 @@ bool CMP_stack::operator()( const CStack* a, const CStack* b )
//TODO? turrets order
case 1: //fastest first, upper slot first
{
int as = a->Speed(), bs = b->Speed();
int as = a->Speed(turn), bs = b->Speed(turn);
if(as != bs)
return as > bs;
else
@ -3013,7 +3038,7 @@ bool CMP_stack::operator()( const CStack* a, const CStack* b )
//TODO: should be replaced with order of receiving morale!
case 3: //fastest last, upper slot first
{
int as = a->Speed(), bs = b->Speed();
int as = a->Speed(turn), bs = b->Speed(turn);
if(as != bs)
return as < bs;
else
@ -3026,9 +3051,10 @@ bool CMP_stack::operator()( const CStack* a, const CStack* b )
}
CMP_stack::CMP_stack( int Phase /*= 1*/ )
CMP_stack::CMP_stack( int Phase /*= 1*/, int Turn )
{
phase = Phase;
turn = Turn;
}
PlayerState::PlayerState()

View File

@ -138,7 +138,7 @@ struct DLL_EXPORT BattleInfo
& castSpells & si;
}
const CStack * getNextStack() const; //which stack will have turn after current one
void getStackQueue(std::vector<const CStack *> &out, int howMany, int mode = 0, int lastMoved = -1) const; //returns stack in order of their movement action
void getStackQueue(std::vector<const CStack *> &out, int howMany, int turn = 0, int lastMoved = -1) const; //returns stack in order of their movement action
CStack * getStack(int stackID, bool onlyAlive = true);
const CStack * getStack(int stackID, bool onlyAlive = true) const;
CStack * getStackT(int tileID, bool onlyAlive = true);
@ -191,17 +191,17 @@ public:
};
std::vector<StackEffect> effects;
int valOfFeatures(StackFeature::ECombatFeatures type, int subtype = -1024) const;//subtype -> subtype of bonus, if -1024 then any
bool hasFeatureOfType(StackFeature::ECombatFeatures type, int subtype = -1024) const; //determines if stack has a bonus of given type (and optionally subtype)
int valOfFeatures(StackFeature::ECombatFeatures type, int subtype = -1024, int turn = 0) const;//subtype -> subtype of bonus, if -1024 then any
bool hasFeatureOfType(StackFeature::ECombatFeatures type, int subtype = -1024, int turn = 0) const; //determines if stack has a bonus of given type (and optionally subtype)
CStack(CCreature * C, int A, int O, int I, bool AO, int S); //c-tor
CStack() : ID(-1), creature(NULL), amount(-1), baseAmount(-1), firstHPleft(-1), owner(255), slot(255), attackerOwned(true), position(-1), counterAttacks(1) {} //c-tor
const StackEffect * getEffect(ui16 id) const; //effect id (SP)
const StackEffect * getEffect(ui16 id, int turn = 0) const; //effect id (SP)
ui8 howManyEffectsSet(ui16 id) const; //returns amount of effects with given id set for this stack
bool willMove() const; //if stack has remaining move this turn
bool moved() const; //if stack was already moved this turn
bool canMove() const; //if stack can move
ui32 Speed() const; //get speed of creature with all modificators
bool willMove(int turn = 0) const; //if stack has remaining move this turn
bool moved(int turn = 0) const; //if stack was already moved this turn
bool canMove(int turn = 0) const; //if stack can move
ui32 Speed(int turn = 0) const; //get speed of creature with all modificators
si8 Morale() const; //get morale of stack with all modificators
si8 Luck() const; //get luck of stack with all modificators
si32 Attack() const; //get attack of stack with all modificators
@ -236,10 +236,11 @@ public:
class DLL_EXPORT CMP_stack
{
int phase; //rules of which phase will be used
int turn;
public:
bool operator ()(const CStack* a, const CStack* b);
CMP_stack(int Phase = 1);
CMP_stack(int Phase = 1, int Turn = 0);
};
struct UpgradeInfo

View File

@ -19,7 +19,7 @@
#include <boost/mpl/identity.hpp>
#include <boost/type_traits/is_array.hpp>
const ui32 version = 708;
const ui32 version = 709;
class CConnection;
namespace mpl = boost::mpl;

View File

@ -19,6 +19,7 @@
#include <boost/thread/shared_mutex.hpp>
#include <boost/assign/list_of.hpp>
#include <fstream>
#include <boost/system/system_error.hpp>
/*
* CGameHandler.cpp, part of VCMI engine
@ -623,6 +624,11 @@ void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
pack = NULL;
}
}
catch(boost::system::system_error &e) //for boost errors just log, not crash - probably client shut down connection
{
tlog1 << e.what() << std::endl;
end2 = true;
}
HANDLE_EXCEPTION(end2 = true);
handleConEnd:
tlog1 << "Ended handling connection\n";
@ -637,6 +643,9 @@ int CGameHandler::moveStack(int stack, int dest)
CStack *curStack = gs->curB->getStack(stack),
*stackAtEnd = gs->curB->getStackT(dest);
assert(curStack);
assert(dest < BFIELD_SIZE);
//initing necessary tables
bool accessibility[BFIELD_SIZE];
std::vector<int> accessible = gs->curB->getAccessibility(curStack->ID, false);
@ -1393,7 +1402,7 @@ bool CGameHandler::moveHero( si32 hid, int3 dst, ui8 instant, ui8 asker /*= 255*
//OR hero is on land and dest is water and (there is not present only one object - boat)
if((t.tertype == TerrainTile::rock || (t.blocked && !t.visitable))
&& complain("Cannot move hero, destination tile is blocked!")
|| (!h->boat && !h->canWalkOnSea() && t.tertype == TerrainTile::water && (t.visitableObjects.size() != 1 || t.visitableObjects.front()->ID != 8))
|| (!h->boat && !h->canWalkOnSea() && t.tertype == TerrainTile::water && (t.visitableObjects.size() != 1 || (t.visitableObjects.front()->ID != 8 && t.visitableObjects.front()->ID != HEROI_TYPE))) //hero is not on boat/water walking and dst water tile doesn't contain boat/hero (objs visitable from land)
&& complain("Cannot move hero, destination tile is on water!")
|| (h->boat && t.tertype != TerrainTile::water && t.blocked)
&& complain("Cannot disembark hero, tile is blocked!")

View File

@ -258,6 +258,11 @@ int main(int argc, char** argv)
server.start();
}
io_service.run();
} HANDLE_EXCEPTION
}
catch(boost::system::system_error &e) //for boost errors just log, not crash - probably client shut down connection
{
tlog1 << e.what() << std::endl;
end2 = true;
}HANDLE_EXCEPTION
return 0;
}