1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-06 09:09:40 +02:00

* Final commit

This commit is contained in:
beegee1
2011-12-13 21:35:28 +00:00
parent 7f04ed990b
commit cce814c41b
76 changed files with 5877 additions and 4618 deletions

View File

@@ -0,0 +1,51 @@
#include "StdInc.h"
#include "CAttackAnimation.h"
#include "../CMusicHandler.h"
#include "../CGameInfo.h"
#include "CBattleInterface.h"
#include "../CCreatureAnimation.h"
#include "../../lib/BattleState.h"
#include "../CPlayerInterface.h"
#include "../../CCallback.h"
void CAttackAnimation::nextFrame()
{
if(myAnim()->getType() != group)
myAnim()->setType(group);
if(myAnim()->onFirstFrameInGroup())
{
if(shooting)
CCS->soundh->playSound(battle_sound(attackingStack->getCreature(), shoot));
else
CCS->soundh->playSound(battle_sound(attackingStack->getCreature(), attack));
}
else if(myAnim()->onLastFrameInGroup())
{
myAnim()->setType(CCreatureAnim::HOLDING);
endAnim();
return; //execution of endAnim deletes this !!!
}
}
bool CAttackAnimation::checkInitialConditions()
{
return isEarliest(false);
}
CAttackAnimation::CAttackAnimation(CBattleInterface *_owner, const CStack *attacker, SHexField _dest, const CStack *defender)
: CBattleStackAnimation(_owner, attacker), dest(_dest), attackedStack(defender), attackingStack(attacker)
{
assert(attackingStack && "attackingStack is NULL in CBattleAttack::CBattleAttack !\n");
if(attackingStack->getCreature()->idNumber != 145) //catapult is allowed to attack not-creature
{
assert(attackedStack && "attackedStack is NULL in CBattleAttack::CBattleAttack !\n");
}
else //catapult can attack walls only
{
assert(owner->curInt->cb->battleGetWallUnderHex(_dest) >= 0);
}
attackingStackPosBeforeReturn = attackingStack->position;
}

View File

@@ -0,0 +1,35 @@
#pragma once
#include "CBattleStackAnimation.h"
#include "../CAnimation.h"
#include "../../lib/SHexField.h"
class CBattleInterface;
class CStack;
/*
* CAttackAnimation.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
/// This class is responsible for managing the battle attack animation
class CAttackAnimation : public CBattleStackAnimation
{
protected:
SHexField dest; //attacked hex
bool shooting;
CCreatureAnim::EAnimType group; //if shooting is true, print this animation group
const CStack *attackedStack;
const CStack *attackingStack;
int attackingStackPosBeforeReturn; //for stacks with return_after_strike feature
public:
void nextFrame();
bool checkInitialConditions();
CAttackAnimation(CBattleInterface *_owner, const CStack *attacker, SHexField _dest, const CStack *defender);
};

View File

@@ -0,0 +1,49 @@
#include "StdInc.h"
#include "CBattleAnimation.h"
#include "CBattleInterface.h"
#include "../../lib/BattleState.h"
#include "CSpellEffectAnimation.h"
#include "CReverseAnimation.h"
void CBattleAnimation::endAnim()
{
for(std::list<std::pair<CBattleAnimation *, bool> >::iterator it = owner->pendingAnims.begin(); it != owner->pendingAnims.end(); ++it)
{
if(it->first == this)
{
it->first = NULL;
}
}
}
bool CBattleAnimation::isEarliest(bool perStackConcurrency)
{
int lowestMoveID = owner->animIDhelper + 5;
CBattleStackAnimation * thAnim = dynamic_cast<CBattleStackAnimation *>(this);
CSpellEffectAnimation * thSen = dynamic_cast<CSpellEffectAnimation *>(this);
for(std::list<std::pair<CBattleAnimation *, bool> >::iterator it = owner->pendingAnims.begin(); it != owner->pendingAnims.end(); ++it)
{
CBattleStackAnimation * stAnim = dynamic_cast<CBattleStackAnimation *>(it->first);
CSpellEffectAnimation * sen = dynamic_cast<CSpellEffectAnimation *>(it->first);
if(perStackConcurrency && stAnim && thAnim && stAnim->stack->ID != thAnim->stack->ID)
continue;
if(sen && thSen && sen != thSen && perStackConcurrency)
continue;
CReverseAnimation * revAnim = dynamic_cast<CReverseAnimation *>(stAnim);
if(revAnim && thAnim && stAnim && stAnim->stack->ID == thAnim->stack->ID && revAnim->priority)
return false;
if(it->first)
vstd::amin(lowestMoveID, it->first->ID);
}
return (ID == lowestMoveID) || (lowestMoveID == (owner->animIDhelper + 5));
}
CBattleAnimation::CBattleAnimation(CBattleInterface * _owner)
: owner(_owner), ID(_owner->animIDhelper++)
{}

View File

@@ -0,0 +1,30 @@
#pragma once
class CBattleInterface;
/*
* CBattleAnimation.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
/// Base class of battle animations
class CBattleAnimation
{
protected:
CBattleInterface * owner;
public:
virtual bool init()=0; //to be called - if returned false, call again until returns true
virtual void nextFrame()=0; //call every new frame
virtual void endAnim(); //to be called mostly internally; in this class it removes animation from pendingAnims list
bool isEarliest(bool perStackConcurrency); //determines if this animation is earliest of all
ui32 ID; //unique identifier
CBattleAnimation(CBattleInterface * _owner);
};

View File

@@ -0,0 +1,84 @@
#include "StdInc.h"
#include "CBattleConsole.h"
#include "../SDL_Extensions.h"
CBattleConsole::CBattleConsole() : lastShown(-1), alterTxt(""), whoSetAlter(0)
{
}
CBattleConsole::~CBattleConsole()
{
texts.clear();
}
void CBattleConsole::show(SDL_Surface * to)
{
if(ingcAlter.size())
{
CSDL_Ext::printAtMiddleWB(ingcAlter, pos.x + pos.w/2, pos.y + 11, FONT_SMALL, 80, zwykly, to);
}
else if(alterTxt.size())
{
CSDL_Ext::printAtMiddleWB(alterTxt, pos.x + pos.w/2, pos.y + 11, FONT_SMALL, 80, zwykly, to);
}
else if(texts.size())
{
if(texts.size()==1)
{
CSDL_Ext::printAtMiddleWB(texts[0], pos.x + pos.w/2, pos.y + 11, FONT_SMALL, 80, zwykly, to);
}
else
{
CSDL_Ext::printAtMiddleWB(texts[lastShown-1], pos.x + pos.w/2, pos.y + 11, FONT_SMALL, 80, zwykly, to);
CSDL_Ext::printAtMiddleWB(texts[lastShown], pos.x + pos.w/2, pos.y + 27, FONT_SMALL, 80, zwykly, to);
}
}
}
bool CBattleConsole::addText(const std::string & text)
{
if(text.size()>70)
return false; //text too long!
int firstInToken = 0;
for(size_t i = 0; i < text.size(); ++i) //tokenize
{
if(text[i] == 10)
{
texts.push_back( text.substr(firstInToken, i-firstInToken) );
firstInToken = i+1;
}
}
texts.push_back( text.substr(firstInToken, text.size()) );
lastShown = texts.size()-1;
return true;
}
void CBattleConsole::eraseText(ui32 pos)
{
if(pos < texts.size())
{
texts.erase(texts.begin() + pos);
if(lastShown == texts.size())
--lastShown;
}
}
void CBattleConsole::changeTextAt(const std::string & text, ui32 pos)
{
if(pos >= texts.size()) //no such pos
return;
texts[pos] = text;
}
void CBattleConsole::scrollUp(ui32 by)
{
if(lastShown > static_cast<int>(by))
lastShown -= by;
}
void CBattleConsole::scrollDown(ui32 by)
{
if(lastShown + by < texts.size())
lastShown += by;
}

View File

@@ -0,0 +1,35 @@
#pragma once
#include "../GUIBase.h"
struct SDL_Surface;
/*
* CBattleConsole.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
/// Class which shows the console at the bottom of the battle screen and manages the text of the console
class CBattleConsole : public CIntObject
{
private:
std::vector< std::string > texts; //a place where texts are stored
int lastShown; //last shown line of text
public:
std::string alterTxt; //if it's not empty, this text is displayed
std::string ingcAlter; //alternative text set by in-game console - very important!
int whoSetAlter; //who set alter text; 0 - battle interface or none, 1 - button
CBattleConsole(); //c-tor
~CBattleConsole(); //d-tor
void show(SDL_Surface *to = 0);
bool addText(const std::string &text); //adds text at the last position; returns false if failed (e.g. text longer than 70 characters)
void eraseText(ui32 pos); //erases added text at position pos
void changeTextAt(const std::string &text, ui32 pos); //if we have more than pos texts, pos-th is changed to given one
void scrollUp(ui32 by = 1); //scrolls console up by 'by' positions
void scrollDown(ui32 by = 1); //scrolls console up by 'by' positions
};

View File

@@ -0,0 +1,153 @@
#include "StdInc.h"
#include "CBattleHero.h"
#include "CBattleInterface.h"
#include "../CGameInfo.h"
#include "../CDefHandler.h"
#include "../CCursorHandler.h"
#include "../CPlayerInterface.h"
#include "../../CCallback.h"
#include "../SDL_Extensions.h"
#include "../CSpellWindow.h"
#include "../Graphics.h"
#include "../CConfigHandler.h"
void CBattleHero::show(SDL_Surface *to)
{
//animation of flag
if(flip)
{
SDL_Rect temp_rect = genRect(
flag->ourImages[flagAnim].bitmap->h,
flag->ourImages[flagAnim].bitmap->w,
pos.x + 61,
pos.y + 39);
CSDL_Ext::blit8bppAlphaTo24bpp(
flag->ourImages[flagAnim].bitmap,
NULL,
screen,
&temp_rect);
}
else
{
SDL_Rect temp_rect = genRect(
flag->ourImages[flagAnim].bitmap->h,
flag->ourImages[flagAnim].bitmap->w,
pos.x + 72,
pos.y + 39);
CSDL_Ext::blit8bppAlphaTo24bpp(
flag->ourImages[flagAnim].bitmap,
NULL,
screen,
&temp_rect);
}
++flagAnimCount;
if(flagAnimCount%4==0)
{
++flagAnim;
flagAnim %= flag->ourImages.size();
}
//animation of hero
int tick=-1;
for(size_t i = 0; i < dh->ourImages.size(); ++i)
{
if(dh->ourImages[i].groupNumber==phase)
++tick;
if(tick==image)
{
SDL_Rect posb = pos;
CSDL_Ext::blit8bppAlphaTo24bpp(dh->ourImages[i].bitmap, NULL, to, &posb);
if(phase != 4 || nextPhase != -1 || image < 4)
{
if(flagAnimCount%2==0)
{
++image;
}
if(dh->ourImages[(i+1)%dh->ourImages.size()].groupNumber!=phase) //back to appropriate frame
{
image = 0;
}
}
if(phase == 4 && nextPhase != -1 && image == 7)
{
phase = nextPhase;
nextPhase = -1;
image = 0;
}
break;
}
}
}
void CBattleHero::activate()
{
activateLClick();
}
void CBattleHero::deactivate()
{
deactivateLClick();
}
void CBattleHero::setPhase(int newPhase)
{
if(phase != 4)
{
phase = newPhase;
image = 0;
}
else
{
nextPhase = newPhase;
}
}
void CBattleHero::clickLeft(tribool down, bool previousState)
{
if(myOwner->spellDestSelectMode) //we are casting a spell
return;
if(!down && myHero != NULL && myOwner->myTurn && myOwner->curInt->cb->battleCanCastSpell()) //check conditions
{
for(int it=0; it<GameConstants::BFIELD_SIZE; ++it) //do nothing when any hex is hovered - hero's animation overlaps battlefield
{
if(myOwner->bfield[it].hovered && myOwner->bfield[it].strictHovered)
return;
}
CCS->curh->changeGraphic(0,0);
CSpellWindow * spellWindow = new CSpellWindow(genRect(595, 620, (conf.cc.resx - 620)/2, (conf.cc.resy - 595)/2), myHero, myOwner->curInt);
GH.pushInt(spellWindow);
}
}
CBattleHero::CBattleHero(const std::string & defName, int phaseG, int imageG, bool flipG, ui8 player, const CGHeroInstance * hero, const CBattleInterface * owner): flip(flipG), myHero(hero), myOwner(owner), phase(phaseG), nextPhase(-1), image(imageG), flagAnim(0), flagAnimCount(0)
{
dh = CDefHandler::giveDef( defName );
for(size_t i = 0; i < dh->ourImages.size(); ++i) //transforming images
{
if(flip)
{
SDL_Surface * hlp = CSDL_Ext::rotate01(dh->ourImages[i].bitmap);
SDL_FreeSurface(dh->ourImages[i].bitmap);
dh->ourImages[i].bitmap = hlp;
}
CSDL_Ext::alphaTransform(dh->ourImages[i].bitmap);
}
if(flip)
flag = CDefHandler::giveDef("CMFLAGR.DEF");
else
flag = CDefHandler::giveDef("CMFLAGL.DEF");
//coloring flag and adding transparency
for(size_t i = 0; i < flag->ourImages.size(); ++i)
{
CSDL_Ext::alphaTransform(flag->ourImages[i].bitmap);
graphics->blueToPlayersAdv(flag->ourImages[i].bitmap, player);
}
}
CBattleHero::~CBattleHero()
{
delete dh;
delete flag;
}

View File

@@ -0,0 +1,39 @@
#pragma once
#include "../GUIBase.h"
class CBattleInterface;
class CDefHandler;
class CGHeroInstance;
struct SDL_Surface;
/*
* CBattleHero.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
/// Hero battle animation
class CBattleHero : public CIntObject
{
public:
bool flip; //false if it's attacking hero, true otherwise
CDefHandler *dh, *flag; //animation and flag
const CGHeroInstance *myHero; //this animation's hero instance
const CBattleInterface *myOwner; //battle interface to which this animation is assigned
int phase; //stage of animation
int nextPhase; //stage of animation to be set after current phase is fully displayed
int image; //frame of animation
ui8 flagAnim, flagAnimCount; //for flag animation
void show(SDL_Surface *to); //prints next frame of animation to to
void activate();
void deactivate();
void setPhase(int newPhase); //sets phase of hero animation
void clickLeft(tribool down, bool previousState); //call-in
CBattleHero(const std::string &defName, int phaseG, int imageG, bool filpG, ui8 player, const CGHeroInstance *hero, const CBattleInterface *owner); //c-tor
~CBattleHero(); //d-tor
};

View File

@@ -0,0 +1,256 @@
#pragma once
#include "../GUIBase.h"
#include "../../lib/CCreatureSet.h"
#include "../../lib/ConstTransitivePtr.h" //may be reundant
#include "../CAnimation.h"
#include "SStackAttackedInfo.h"
#include "CHexFieldControl.h"
#include "CShootingAnimation.h"
#include "../../lib/SHexField.h"
#include "../../lib/GameConstants.h"
/*
* CBattleInterface.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
class CLabel;
class CCreatureSet;
class CGHeroInstance;
class CDefHandler;
class CStack;
class CCallback;
class AdventureMapButton;
class CHighlightableButton;
class CHighlightableButtonsGroup;
struct BattleResult;
struct BattleSpellCast;
struct CObstacleInstance;
template <typename T> struct CondSh;
struct SetStackEffect;;
struct BattleAction;
class CGTownInstance;
struct CatapultAttack;
class CBattleInterface;
struct SCatapultSProjectileInfo;
struct BattleTriggerEffect;
class CBattleAnimation;
class CBattleHero;
class CBattleConsole;
class CBattleResultWindow;
class CStackQueue;
/// Class which manages the locked hex fields that are blocked e.g. by obstacles
class CBattleObstacle
{
std::vector<int> lockedHexes;
};
/// Struct for battle effect animation e.g. morale, prayer, armageddon, bless,...
struct SBattleEffect
{
int x, y; //position on the screen
int frame, maxFrame;
CDefHandler * anim; //animation to display
int effectID; //uniqueID equal ot ID of appropriate CSpellEffectAnim
};
/// Small struct which is needed for drawing the parabolic trajectory of the catapult cannon
struct SCatapultSProjectileInfo
{
const double facA, facB, facC;
const int fromX, toX;
SCatapultSProjectileInfo() : facA(0), facB(0), facC(0), fromX(0), toX(0) { };
SCatapultSProjectileInfo(double factorA, double factorB, double factorC, int fromXX, int toXX) : facA(factorA), facB(factorB), facC(factorC),
fromX(fromXX), toX(toXX) { };
double calculateY(double x);
};
/// Big class which handles the overall battle interface actions and it is also responsible for
/// drawing everything correctly.
class CBattleInterface : public CIntObject
{
enum SpellSelectionType
{
ANY_LOCATION = 0, FRIENDLY_CREATURE, HOSTILE_CREATURE, ANY_CREATURE, OBSTACLE, TELEPORT, NO_LOCATION = -1, STACK_SPELL_CANCELLED = -2
};
private:
SDL_Surface * background, * menu, * amountNormal, * amountNegative, * amountPositive, * amountEffNeutral, * cellBorders, * backgroundWithHexes;
AdventureMapButton * bOptions, * bSurrender, * bFlee, * bAutofight, * bSpell,
* bWait, * bDefence, * bConsoleUp, * bConsoleDown, *btactNext, *btactEnd;
CBattleConsole * console;
CBattleHero * attackingHero, * defendingHero; //fighting heroes
CStackQueue *queue;
const CCreatureSet *army1, *army2; //copy of initial armies (for result window)
const CGHeroInstance * attackingHeroInstance, * defendingHeroInstance;
std::map< int, CCreatureAnimation * > creAnims; //animations of creatures from fighting armies (order by BattleInfo's stacks' ID)
std::map< int, CDefHandler * > idToProjectile; //projectiles of creatures (creatureID, defhandler)
std::map< int, CDefHandler * > idToObstacle; //obstacles located on the battlefield
std::map< int, bool > creDir; // <creatureID, if false reverse creature's animation>
ui8 animCount;
const CStack * activeStack; //number of active stack; NULL - no one
const CStack * stackToActivate; //when animation is playing, we should wait till the end to make the next stack active; NULL of none
void activateStack(); //sets activeStack to stackToActivate etc.
int mouseHoveredStack; //stack hovered by mouse; if -1 -> none
time_t lastMouseHoveredStackAnimationTime; // time when last mouse hovered animation occurred
static const time_t HOVER_ANIM_DELTA;
std::vector<SHexField> occupyableHexes, //hexes available for active stack
attackableHexes; //hexes attackable by active stack
bool stackCountOutsideHexes[GameConstants::BFIELD_SIZE]; // hexes that when in front of a unit cause it's amount box to move back
int previouslyHoveredHex; //number of hex that was hovered by the cursor a while ago
int currentlyHoveredHex; //number of hex that is supposed to be hovered (for a while it may be inappropriately set, but will be renewed soon)
int attackingHex; //hex from which the stack would perform attack with current cursor
double getAnimSpeedMultiplier() const; //returns multiplier for number of frames in a group
std::map<int, int> standingFrame; //number of frame in standing animation by stack ID, helps in showing 'random moves'
CPlayerInterface *tacticianInterface; //used during tactics mode, points to the interface of player with higher tactics (can be either attacker or defender in hot-seat), valid onloy for human players
bool tacticsMode;
bool stackCanCastSpell; //if true, active stack could possibly cats some target spell
bool spellDestSelectMode; //if true, player is choosing destination for his spell
SpellSelectionType spellSelMode;
BattleAction * spellToCast; //spell for which player is choosing destination
ui32 creatureSpellToCast;
void endCastingSpell(); //ends casting spell (eg. when spell has been cast or canceled)
void showAliveStack(const CStack *stack, SDL_Surface * to); //helper function for function show
void showAliveStacks(std::vector<const CStack *> *aliveStacks, int hex, std::vector<const CStack *> *flyingStacks, SDL_Surface *to); // loops through all stacks at a given hex position
void showPieceOfWall(SDL_Surface * to, int hex, const std::vector<const CStack*> & stacks); //helper function for show
void showObstacles(std::multimap<SHexField, int> *hexToObstacle, std::vector<CObstacleInstance> &obstacles, int hex, SDL_Surface *to); // show all obstacles at a given hex position
void redrawBackgroundWithHexes(const CStack * activeStack);
void printConsoleAttacked(const CStack * defender, int dmg, int killed, const CStack * attacker, bool Multiple);
std::list<SProjectileInfo> projectiles; //projectiles flying on battlefield
void projectileShowHelper(SDL_Surface * to); //prints projectiles present on the battlefield
void giveCommand(ui8 action, SHexField tile, ui32 stack, si32 additional=-1);
bool isTileAttackable(const SHexField & number) const; //returns true if tile 'number' is neighboring any tile from active stack's range or is one of these tiles
bool blockedByObstacle(SHexField hex) const;
bool isCatapultAttackable(SHexField hex) const; //returns true if given tile can be attacked by catapult
std::list<SBattleEffect> battleEffects; //different animations to display on the screen like spell effects
/// Class which is responsible for drawing the wall of a siege during battle
class SiegeHelper
{
private:
static std::string townTypeInfixes[GameConstants::F_NUMBER]; //for internal use only - to build filenames
SDL_Surface* walls[18];
const CBattleInterface * owner;
public:
const CGTownInstance * town; //besieged town
SiegeHelper(const CGTownInstance * siegeTown, const CBattleInterface * _owner); //c-tor
~SiegeHelper(); //d-tor
//filename getters
std::string getSiegeName(ui16 what, ui16 additInfo = 1) const; //what: 0 - background, 1 - background wall, 2 - keep, 3 - bottom tower, 4 - bottom wall, 5 - below gate, 6 - over gate, 7 - upper wall, 8 - uppert tower, 9 - gate, 10 - gate arch, 11 - bottom static wall, 12 - upper static wall, 13 - moat, 14 - mlip, 15 - keep creature cover, 16 - bottom turret creature cover, 17 - upper turret creature cover; additInfo: 1 - intact, 2 - damaged, 3 - destroyed
void printPartOfWall(SDL_Surface * to, int what);//what: 1 - background wall, 2 - keep, 3 - bottom tower, 4 - bottom wall, 5 - below gate, 6 - over gate, 7 - upper wall, 8 - uppert tower, 9 - gate, 10 - gate arch, 11 - bottom static wall, 12 - upper static wall, 15 - keep creature cover, 16 - bottom turret creature cover, 17 - upper turret creature cover
friend class CBattleInterface;
} * siegeH;
CPlayerInterface * attackerInt, * defenderInt; //because LOCPLINT is not enough in hotSeat
const CGHeroInstance * getActiveHero(); //returns hero that can currently cast a spell
public:
CPlayerInterface * curInt; //current player interface
std::list<std::pair<CBattleAnimation *, bool> > pendingAnims; //currently displayed animations <anim, initialized>
void addNewAnim(CBattleAnimation * anim); //adds new anim to pendingAnims
ui32 animIDhelper; //for giving IDs for animations
static CondSh<bool> animsAreDisplayed; //for waiting with the end of battle for end of anims
CBattleInterface(const CCreatureSet * army1, const CCreatureSet * army2, CGHeroInstance *hero1, CGHeroInstance *hero2, const SDL_Rect & myRect, CPlayerInterface * att, CPlayerInterface * defen); //c-tor
~CBattleInterface(); //d-tor
//std::vector<TimeInterested*> timeinterested; //animation handling
void setPrintCellBorders(bool set); //if true, cell borders will be printed
void setPrintStackRange(bool set); //if true,range of active stack will be printed
void setPrintMouseShadow(bool set); //if true, hex under mouse will be shaded
void setAnimSpeed(int set); //speed of animation; 1 - slowest, 2 - medium, 4 - fastest
int getAnimSpeed() const; //speed of animation; 1 - slowest, 2 - medium, 4 - fastest
CHexFieldControl bfield[GameConstants::BFIELD_SIZE]; //11 lines, 17 hexes on each
//std::vector< CBattleObstacle * > obstacles; //vector of obstacles on the battlefield
SDL_Surface * cellBorder, * cellShade;
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 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
//button handle funcs:
void bOptionsf();
void bSurrenderf();
void bFleef();
void reallyFlee(); //performs fleeing without asking player
void reallySurrender(); //performs surrendering without asking player
void bAutofightf();
void bSpellf();
void bWaitf();
void bDefencef();
void bConsoleUpf();
void bConsoleDownf();
void bTacticNextStack();
void bEndTacticPhase();
//end of button handle funcs
//napisz tu klase odpowiadajaca za wyswietlanie bitwy i obsluge uzytkownika, polecenia ma przekazywac callbackiem
void activate();
void deactivate();
void show(SDL_Surface * to);
void keyPressed(const SDL_KeyboardEvent & key);
void mouseMoved(const SDL_MouseMotionEvent &sEvent);
void clickRight(tribool down, bool previousState);
//call-ins
void startAction(const BattleAction* action);
void newStack(const CStack * stack); //new stack appeared on battlefield
void stackRemoved(int stackID); //stack disappeared from batlefiled
void stackActivated(const CStack * stack); //active stack has been changed
void stackMoved(const CStack * stack, std::vector<SHexField> destHex, int distance); //stack with id number moved to destHex
void waitForAnims();
void stacksAreAttacked(std::vector<SStackAttackedInfo> attackedInfos); //called when a certain amount of stacks has been attacked
void stackAttacking(const CStack * attacker, SHexField dest, const CStack * attacked, bool shooting); //called when stack with id ID is attacking something on hex dest
void newRoundFirst( int round );
void newRound(int number); //caled when round is ended; number is the number of round
void hexLclicked(int whichOne); //hex only call-in
void stackIsCatapulting(const CatapultAttack & ca); //called when a stack is attacking walls
void battleFinished(const BattleResult& br); //called when battle is finished - battleresult window should be printed
const BattleResult * bresult; //result of a battle; if non-zero then display when all animations end
void displayBattleFinished(); //displays battle result
void spellCast(const BattleSpellCast * sc); //called when a hero casts a spell
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 battleTriggerEffect(const BattleTriggerEffect & bte);
void setBattleCursor(const int myNumber); //really complex and messy
void endAction(const BattleAction* action);
void hideQueue();
void showQueue();
friend class CPlayerInterface;
friend class AdventureMapButton;
friend class CInGameConsole;
friend class CBattleResultWindow;
friend class CBattleHero;
friend class CSpellEffectAnimation;
friend class CBattleStackAnimation;
friend class CReverseAnimation;
friend class CDefenceAnimation;
friend class CMovementAnimation;
friend class CMovementStartAnimation;
friend class CAttackAnimation;
friend class CMeleeAttackAnimation;
friend class CShootingAnimation;
friend class CHexFieldControl;
};

View File

@@ -0,0 +1,73 @@
#include "StdInc.h"
#include "CBattleOptionsWindow.h"
#include "CBattleInterface.h"
#include "../GUIBase.h"
#include "../GUIClasses.h"
#include "../AdventureMapButton.h"
#include "../CGameInfo.h"
#include "../CPlayerInterface.h"
#include "../../lib/CGeneralTextHandler.h"
CBattleOptionsWindow::CBattleOptionsWindow(const SDL_Rect & position, CBattleInterface *owner): myInt(owner)
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
pos = position;
background = new CPicture("comopbck.bmp");
background->colorize(owner->curInt->playerID);
viewGrid = new CHighlightableButton(boost::bind(&CBattleInterface::setPrintCellBorders, owner, true), boost::bind(&CBattleInterface::setPrintCellBorders, owner, false), boost::assign::map_list_of(0,CGI->generaltexth->zelp[427].first)(3,CGI->generaltexth->zelp[427].first), CGI->generaltexth->zelp[427].second, false, "sysopchk.def", NULL, 25, 56, false);
viewGrid->select(owner->curInt->sysOpts.printCellBorders);
movementShadow = new CHighlightableButton(boost::bind(&CBattleInterface::setPrintStackRange, owner, true), boost::bind(&CBattleInterface::setPrintStackRange, owner, false), boost::assign::map_list_of(0,CGI->generaltexth->zelp[428].first)(3,CGI->generaltexth->zelp[428].first), CGI->generaltexth->zelp[428].second, false, "sysopchk.def", NULL, 25, 89, false);
movementShadow->select(owner->curInt->sysOpts.printStackRange);
mouseShadow = new CHighlightableButton(boost::bind(&CBattleInterface::setPrintMouseShadow, owner, true), boost::bind(&CBattleInterface::setPrintMouseShadow, owner, false), boost::assign::map_list_of(0,CGI->generaltexth->zelp[429].first)(3,CGI->generaltexth->zelp[429].first), CGI->generaltexth->zelp[429].second, false, "sysopchk.def", NULL, 25, 122, false);
mouseShadow->select(owner->curInt->sysOpts.printMouseShadow);
animSpeeds = new CHighlightableButtonsGroup(0);
animSpeeds->addButton(boost::assign::map_list_of(0,CGI->generaltexth->zelp[422].first),CGI->generaltexth->zelp[422].second, "sysopb9.def", 28, 225, 1);
animSpeeds->addButton(boost::assign::map_list_of(0,CGI->generaltexth->zelp[423].first),CGI->generaltexth->zelp[423].second, "sysob10.def", 92, 225, 2);
animSpeeds->addButton(boost::assign::map_list_of(0,CGI->generaltexth->zelp[424].first),CGI->generaltexth->zelp[424].second, "sysob11.def",156, 225, 4);
animSpeeds->select(owner->getAnimSpeed(), 1);
animSpeeds->onChange = boost::bind(&CBattleInterface::setAnimSpeed, owner, _1);
setToDefault = new AdventureMapButton (CGI->generaltexth->zelp[393], boost::bind(&CBattleOptionsWindow::bDefaultf,this), 246, 359, "codefaul.def");
setToDefault->swappedImages = true;
setToDefault->update();
exit = new AdventureMapButton (CGI->generaltexth->zelp[392], boost::bind(&CBattleOptionsWindow::bExitf,this), 357, 359, "soretrn.def",SDLK_RETURN);
exit->swappedImages = true;
exit->update();
//creating labels
labels.push_back(new CLabel(242, 32, FONT_BIG, CENTER, tytulowy, CGI->generaltexth->allTexts[392]));//window title
labels.push_back(new CLabel(122, 214, FONT_MEDIUM, CENTER, tytulowy, CGI->generaltexth->allTexts[393]));//animation speed
labels.push_back(new CLabel(122, 293, FONT_MEDIUM, CENTER, tytulowy, CGI->generaltexth->allTexts[394]));//music volume
labels.push_back(new CLabel(122, 359, FONT_MEDIUM, CENTER, tytulowy, CGI->generaltexth->allTexts[395]));//effects' volume
labels.push_back(new CLabel(353, 66, FONT_MEDIUM, CENTER, tytulowy, CGI->generaltexth->allTexts[396]));//auto - combat options
labels.push_back(new CLabel(353, 265, FONT_MEDIUM, CENTER, tytulowy, CGI->generaltexth->allTexts[397]));//creature info
//auto - combat options
labels.push_back(new CLabel(283, 86, FONT_MEDIUM, TOPLEFT, zwykly, CGI->generaltexth->allTexts[398]));//creatures
labels.push_back(new CLabel(283, 116, FONT_MEDIUM, TOPLEFT, zwykly, CGI->generaltexth->allTexts[399]));//spells
labels.push_back(new CLabel(283, 146, FONT_MEDIUM, TOPLEFT, zwykly, CGI->generaltexth->allTexts[400]));//catapult
labels.push_back(new CLabel(283, 176, FONT_MEDIUM, TOPLEFT, zwykly, CGI->generaltexth->allTexts[151]));//ballista
labels.push_back(new CLabel(283, 206, FONT_MEDIUM, TOPLEFT, zwykly, CGI->generaltexth->allTexts[401]));//first aid tent
//creature info
labels.push_back(new CLabel(283, 285, FONT_MEDIUM, TOPLEFT, zwykly, CGI->generaltexth->allTexts[402]));//all stats
labels.push_back(new CLabel(283, 315, FONT_MEDIUM, TOPLEFT, zwykly, CGI->generaltexth->allTexts[403]));//spells only
//general options
labels.push_back(new CLabel(61, 57, FONT_MEDIUM, TOPLEFT, zwykly, CGI->generaltexth->allTexts[404]));
labels.push_back(new CLabel(61, 90, FONT_MEDIUM, TOPLEFT, zwykly, CGI->generaltexth->allTexts[405]));
labels.push_back(new CLabel(61, 123, FONT_MEDIUM, TOPLEFT, zwykly, CGI->generaltexth->allTexts[406]));
labels.push_back(new CLabel(61, 156, FONT_MEDIUM, TOPLEFT, zwykly, CGI->generaltexth->allTexts[407]));
}
void CBattleOptionsWindow::bDefaultf()
{
}
void CBattleOptionsWindow::bExitf()
{
GH.popIntTotally(this);
}

View File

@@ -0,0 +1,39 @@
#pragma once
#include "../GUIBase.h"
class CBattleInterface;
class CPicture;
class AdventureMapButton;
class CHighlightableButton;
class CHighlightableButtonsGroup;
class CLabel;
struct SDL_Rect;
/*
* CBattleOptionsWindow.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
/// Class which manages the battle options window
class CBattleOptionsWindow : public CIntObject
{
private:
CBattleInterface *myInt;
CPicture *background;
AdventureMapButton *setToDefault, *exit;
CHighlightableButton *viewGrid, *movementShadow, *mouseShadow;
CHighlightableButtonsGroup *animSpeeds;
std::vector<CLabel*> labels;
public:
CBattleOptionsWindow(const SDL_Rect &position, CBattleInterface *owner); //c-tor
void bDefaultf(); //default button callback
void bExitf(); //exit button callback
};

View File

@@ -0,0 +1,216 @@
#include "StdInc.h"
#include "CBattleResultWindow.h"
#include "CBattleInterface.h"
#include "../AdventureMapButton.h"
#include "../CGameInfo.h"
#include "../../lib/CObjectHandler.h"
#include "../../lib/NetPacks.h"
#include "../../lib/CCreatureHandler.h"
#include "../../lib/CGeneralTextHandler.h"
#include "../CMusicHandler.h"
#include "../CPlayerInterface.h"
#include "../Graphics.h"
#include "../../CCallback.h"
#include "../CVideoHandler.h"
#include "../SDL_Extensions.h"
#include "../CBitmapHandler.h"
CBattleResultWindow::CBattleResultWindow(const BattleResult &br, const SDL_Rect & pos, CBattleInterface * _owner)
: owner(_owner)
{
this->pos = pos;
background = BitmapHandler::loadBitmap("CPRESULT.BMP", true);
graphics->blueToPlayersAdv(background, owner->curInt->playerID);
SDL_Surface * pom = SDL_ConvertSurface(background, screen->format, screen->flags);
SDL_FreeSurface(background);
background = pom;
exit = new AdventureMapButton (std::string(), std::string(), boost::bind(&CBattleResultWindow::bExitf,this), 384 + pos.x, 505 + pos.y, "iok6432.def", SDLK_RETURN);
exit->borderColor = Colors::MetallicGold;
exit->borderEnabled = true;
if(br.winner==0) //attacker won
{
CSDL_Ext::printAtMiddle(CGI->generaltexth->allTexts[410], 59, 124, FONT_SMALL, zwykly, background);
CSDL_Ext::printAtMiddle(CGI->generaltexth->allTexts[411], 408, 124, FONT_SMALL, zwykly, background);
}
else //if(br.winner==1)
{
CSDL_Ext::printAtMiddle(CGI->generaltexth->allTexts[411], 59, 124, FONT_SMALL, zwykly, background);
CSDL_Ext::printAtMiddle(CGI->generaltexth->allTexts[410], 412, 124, FONT_SMALL, zwykly, background);
}
CSDL_Ext::printAtMiddle(CGI->generaltexth->allTexts[407], 232, 302, FONT_BIG, tytulowy, background);
CSDL_Ext::printAtMiddle(CGI->generaltexth->allTexts[408], 232, 332, FONT_BIG, zwykly, background);
CSDL_Ext::printAtMiddle(CGI->generaltexth->allTexts[409], 237, 428, FONT_BIG, zwykly, background);
std::string attackerName, defenderName;
if(owner->attackingHeroInstance) //a hero attacked
{
SDL_Rect temp_rect = genRect(64, 58, 21, 38);
SDL_BlitSurface(graphics->portraitLarge[owner->attackingHeroInstance->portrait], NULL, background, &temp_rect);
//setting attackerName
attackerName = owner->attackingHeroInstance->name;
}
else //a monster attacked
{
int bestMonsterID = -1;
ui32 bestPower = 0;
for(TSlots::const_iterator it = owner->army1->Slots().begin(); it!=owner->army1->Slots().end(); ++it)
{
if(it->second->type->AIValue > bestPower)
{
bestPower = it->second->type->AIValue;
bestMonsterID = it->second->type->idNumber;
}
}
SDL_Rect temp_rect = genRect(64, 58, 21, 38);
SDL_BlitSurface(graphics->bigImgs[bestMonsterID], NULL, background, &temp_rect);
//setting attackerName
attackerName = CGI->creh->creatures[bestMonsterID]->namePl;
}
if(owner->defendingHeroInstance) //a hero defended
{
SDL_Rect temp_rect = genRect(64, 58, 392, 38);
SDL_BlitSurface(graphics->portraitLarge[owner->defendingHeroInstance->portrait], NULL, background, &temp_rect);
//setting defenderName
defenderName = owner->defendingHeroInstance->name;
}
else //a monster defended
{
int bestMonsterID = -1;
ui32 bestPower = 0;
for(TSlots::const_iterator it = owner->army2->Slots().begin(); it!=owner->army2->Slots().end(); ++it)
{
if( it->second->type->AIValue > bestPower)
{
bestPower = it->second->type->AIValue;
bestMonsterID = it->second->type->idNumber;
}
}
SDL_Rect temp_rect = genRect(64, 58, 392, 38);
SDL_BlitSurface(graphics->bigImgs[bestMonsterID], NULL, background, &temp_rect);
//setting defenderName
defenderName = CGI->creh->creatures[bestMonsterID]->namePl;
}
//printing attacker and defender's names
CSDL_Ext::printAt(attackerName, 89, 37, FONT_SMALL, zwykly, background);
CSDL_Ext::printTo(defenderName, 381, 53, FONT_SMALL, zwykly, background);
//printing casualities
for(int step = 0; step < 2; ++step)
{
if(br.casualties[step].size()==0)
{
CSDL_Ext::printAtMiddle(CGI->generaltexth->allTexts[523], 235, 360 + 97*step, FONT_SMALL, zwykly, background);
}
else
{
int xPos = 235 - (br.casualties[step].size()*32 + (br.casualties[step].size() - 1)*10)/2; //increment by 42 with each picture
int yPos = 344 + step*97;
for(std::map<ui32,si32>::const_iterator it=br.casualties[step].begin(); it!=br.casualties[step].end(); ++it)
{
blitAt(graphics->smallImgs[it->first], xPos, yPos, background);
std::ostringstream amount;
amount<<it->second;
CSDL_Ext::printAtMiddle(amount.str(), xPos+16, yPos + 42, FONT_SMALL, zwykly, background);
xPos += 42;
}
}
}
//printing result description
bool weAreAttacker = (owner->curInt->playerID == owner->attackingHeroInstance->tempOwner);
if((br.winner == 0 && weAreAttacker) || (br.winner == 1 && !weAreAttacker)) //we've won
{
int text=-1;
switch(br.result)
{
case 0: text = 304; break;
case 1: text = 303; break;
case 2: text = 302; break;
}
CCS->musich->playMusic(musicBase::winBattle);
CCS->videoh->open(VIDEO_WIN);
std::string str = CGI->generaltexth->allTexts[text];
const CGHeroInstance * ourHero = weAreAttacker? owner->attackingHeroInstance : owner->defendingHeroInstance;
if (ourHero)
{
str += CGI->generaltexth->allTexts[305];
boost::algorithm::replace_first(str,"%s",ourHero->name);
boost::algorithm::replace_first(str,"%d",boost::lexical_cast<std::string>(br.exp[weAreAttacker?0:1]));
}
CSDL_Ext::printAtMiddleWB(str, 235, 235, FONT_SMALL, 55, zwykly, background);
}
else // we lose
{
switch(br.result)
{
case 0: //normal victory
{
CCS->musich->playMusic(musicBase::loseCombat);
CCS->videoh->open(VIDEO_LOSE_BATTLE_START);
CSDL_Ext::printAtMiddle(CGI->generaltexth->allTexts[311], 235, 235, FONT_SMALL, zwykly, background);
break;
}
case 1: //flee
{
CCS->musich->playMusic(musicBase::retreatBattle);
CCS->videoh->open(VIDEO_RETREAT_START);
CSDL_Ext::printAtMiddle(CGI->generaltexth->allTexts[310], 235, 235, FONT_SMALL, zwykly, background);
break;
}
case 2: //surrender
{
CCS->musich->playMusic(musicBase::surrenderBattle);
CCS->videoh->open(VIDEO_SURRENDER);
CSDL_Ext::printAtMiddle(CGI->generaltexth->allTexts[309], 235, 220, FONT_SMALL, zwykly, background);
break;
}
}
}
}
CBattleResultWindow::~CBattleResultWindow()
{
SDL_FreeSurface(background);
}
void CBattleResultWindow::activate()
{
owner->curInt->showingDialog->set(true);
exit->activate();
}
void CBattleResultWindow::deactivate()
{
exit->deactivate();
}
void CBattleResultWindow::show(SDL_Surface *to)
{
//evaluating to
if(!to)
to = screen;
CCS->videoh->update(107, 70, background, false, true);
SDL_BlitSurface(background, NULL, to, &pos);
exit->showAll(to);
}
void CBattleResultWindow::bExitf()
{
if(LOCPLINT->cb->getStartInfo()->mode == StartInfo::DUEL)
{
std::exit(0);
}
CPlayerInterface * intTmp = owner->curInt;
GH.popInts(2); //first - we; second - battle interface
intTmp->showingDialog->setn(false);
CCS->videoh->close();
}

View File

@@ -0,0 +1,37 @@
#pragma once
#include "../GUIBase.h"
struct SDL_Surface;
class AdventureMapButton;
class CBattleInterface;
struct SDL_Rect;
struct BattleResult;
/*
* CBattleResultWindow.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
/// Class which is responsible for showing the battle result window
class CBattleResultWindow : public CIntObject
{
private:
SDL_Surface *background;
AdventureMapButton *exit;
CBattleInterface *owner;
public:
CBattleResultWindow(const BattleResult &br, const SDL_Rect &pos, CBattleInterface *_owner); //c-tor
~CBattleResultWindow(); //d-tor
void bExitf(); //exit button callback
void activate();
void deactivate();
void show(SDL_Surface * to = 0);
};

View File

@@ -0,0 +1,57 @@
#include "StdInc.h"
#include "CBattleStackAnimation.h"
#include "CBattleInterface.h"
#include "../../lib/BattleState.h"
CBattleStackAnimation::CBattleStackAnimation(CBattleInterface * _owner, const CStack * _stack)
: CBattleAnimation(_owner), stack(_stack)
{
}
bool CBattleStackAnimation::isToReverseHlp(SHexField hexFrom, SHexField hexTo, bool curDir)
{
int fromMod = hexFrom % GameConstants::BFIELD_WIDTH;
int fromDiv = hexFrom / GameConstants::BFIELD_WIDTH;
int toMod = hexTo % GameConstants::BFIELD_WIDTH;
if(curDir && fromMod < toMod)
return false;
else if(curDir && fromMod > toMod)
return true;
else if(curDir && fromMod == toMod)
{
return fromDiv % 2 == 0;
}
else if(!curDir && fromMod < toMod)
return true;
else if(!curDir && fromMod > toMod)
return false;
else if(!curDir && fromMod == toMod)
{
return fromDiv % 2 == 1;
}
tlog1 << "Catastrope in CBattleStackAnimation::isToReverse!" << std::endl;
return false; //should never happen
}
bool CBattleStackAnimation::isToReverse(SHexField hexFrom, SHexField hexTo, bool curDir, bool toDoubleWide, bool toDir)
{
if(hexTo < 0) //turret
return false;
if(toDoubleWide)
{
return isToReverseHlp(hexFrom, hexTo, curDir) &&
(toDir ? isToReverseHlp(hexFrom, hexTo-1, curDir) : isToReverseHlp(hexFrom, hexTo+1, curDir) );
}
else
{
return isToReverseHlp(hexFrom, hexTo, curDir);
}
}
CCreatureAnimation* CBattleStackAnimation::myAnim()
{
return owner->creAnims[stack->ID];
}

View File

@@ -0,0 +1,31 @@
#pragma once
#include "CBattleAnimation.h"
#include "../../lib/SHexField.h"
class CStack;
class CBattleInterface;
class CCreatureAnimation;
/*
* CBattleStackAnimation.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
/// Sub-class which is responsible for managing the battle stack animation.
class CBattleStackAnimation : public CBattleAnimation
{
public:
const CStack * stack; //id of stack whose animation it is
CBattleStackAnimation(CBattleInterface * _owner, const CStack * _stack);
static bool isToReverseHlp(SHexField hexFrom, SHexField hexTo, bool curDir); //helper for isToReverse
static bool isToReverse(SHexField hexFrom, SHexField hexTo, bool curDir /*if true, creature is in attacker's direction*/, bool toDoubleWide, bool toDir); //determines if creature should be reversed (it stands on hexFrom and should 'see' hexTo)
CCreatureAnimation *myAnim(); //animation for our stack
};

View File

@@ -0,0 +1,139 @@
#include "StdInc.h"
#include "CDefenceAnimation.h"
#include "CBattleInterface.h"
#include "../CGameInfo.h"
#include "../CCreatureAnimation.h"
#include "../CPlayerInterface.h"
#include "../CMusicHandler.h"
#include "../../lib/BattleState.h"
#include "CReverseAnimation.h"
#include "CAttackAnimation.h"
#include "CShootingAnimation.h"
bool CDefenceAnimation::init()
{
//checking initial conditions
//if(owner->creAnims[stackID]->getType() != 2)
//{
// return false;
//}
if(attacker == NULL && owner->battleEffects.size() > 0)
return false;
ui32 lowestMoveID = owner->animIDhelper + 5;
for(std::list<std::pair<CBattleAnimation *, bool> >::iterator it = owner->pendingAnims.begin(); it != owner->pendingAnims.end(); ++it)
{
CDefenceAnimation * defAnim = dynamic_cast<CDefenceAnimation *>(it->first);
if(defAnim && defAnim->stack->ID != stack->ID)
continue;
CAttackAnimation * attAnim = dynamic_cast<CAttackAnimation *>(it->first);
if(attAnim && attAnim->stack->ID != stack->ID)
continue;
if(attacker != NULL)
{
int attackerAnimType = owner->creAnims[attacker->ID]->getType();
if( attackerAnimType == 11 && attackerAnimType == 12 && attackerAnimType == 13 && owner->creAnims[attacker->ID]->getFrame() < attacker->getCreature()->attackClimaxFrame )
return false;
}
CReverseAnimation * animAsRev = dynamic_cast<CReverseAnimation *>(it->first);
if(animAsRev && animAsRev->priority)
return false;
if(it->first)
vstd::amin(lowestMoveID, it->first->ID);
}
if(ID > lowestMoveID)
return false;
//reverse unit if necessary
if(attacker && isToReverse(stack->position, attacker->position, owner->creDir[stack->ID], attacker->doubleWide(), owner->creDir[attacker->ID]))
{
owner->addNewAnim(new CReverseAnimation(owner, stack, stack->position, true));
return false;
}
//unit reversed
if(byShooting) //delay hit animation
{
for(std::list<SProjectileInfo>::const_iterator it = owner->projectiles.begin(); it != owner->projectiles.end(); ++it)
{
if(it->creID == attacker->getCreature()->idNumber)
{
return false;
}
}
}
//initializing
if(killed)
{
CCS->soundh->playSound(battle_sound(stack->getCreature(), killed));
myAnim()->setType(CCreatureAnim::DEATH); //death
}
else
{
// TODO: this block doesn't seems correct if the unit is defending.
CCS->soundh->playSound(battle_sound(stack->getCreature(), wince));
myAnim()->setType(CCreatureAnim::HITTED); //getting hit
}
return true; //initialized successfuly
}
void CDefenceAnimation::nextFrame()
{
if(!killed && myAnim()->getType() != CCreatureAnim::HITTED)
{
myAnim()->setType(CCreatureAnim::HITTED);
}
if(!myAnim()->onLastFrameInGroup())
{
if( myAnim()->getType() == CCreatureAnim::DEATH && (owner->animCount+1)%(4/owner->curInt->sysOpts.animSpeed)==0
&& !myAnim()->onLastFrameInGroup() )
{
myAnim()->incrementFrame();
}
}
else
{
endAnim();
}
}
void CDefenceAnimation::endAnim()
{
//restoring animType
if(myAnim()->getType() == CCreatureAnim::HITTED)
myAnim()->setType(CCreatureAnim::HOLDING);
//printing info to console
//if(attacker!=NULL)
// owner->printConsoleAttacked(stack, dmg, amountKilled, attacker);
//const CStack * attacker = owner->curInt->cb->battleGetStackByID(IDby, false);
//const CStack * attacked = owner->curInt->cb->battleGetStackByID(stackID, false);
CBattleAnimation::endAnim();
delete this;
}
CDefenceAnimation::CDefenceAnimation(SStackAttackedInfo _attackedInfo, CBattleInterface * _owner)
: CBattleStackAnimation(_owner, _attackedInfo.defender), dmg(_attackedInfo.dmg),
amountKilled(_attackedInfo.amountKilled), attacker(_attackedInfo.attacker), byShooting(_attackedInfo.byShooting),
killed(_attackedInfo.killed)
{
}

View File

@@ -0,0 +1,34 @@
#pragma once
#include "CBattleStackAnimation.h"
#include "SStackAttackedInfo.h"
class CStack;
/*
* CDefenceAnimation.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
/// Animation of a defending unit
class CDefenceAnimation : public CBattleStackAnimation
{
private:
//std::vector<SSStackAttackedInfo> attackedInfos;
int dmg; //damage dealt
int amountKilled; //how many creatures in stack has been killed
const CStack * attacker; //attacking stack
bool byShooting; //if true, stack has been attacked by shooting
bool killed; //if true, stack has been killed
public:
bool init();
void nextFrame();
void endAnim();
CDefenceAnimation(SStackAttackedInfo _attackedInfo, CBattleInterface * _owner);
};

View File

@@ -0,0 +1,27 @@
#include "StdInc.h"
#include "CDummyAnimation.h"
#include "CBattleInterface.h"
bool CDummyAnimation::init()
{
return true;
}
void CDummyAnimation::nextFrame()
{
counter++;
if(counter > howMany)
endAnim();
}
void CDummyAnimation::endAnim()
{
CBattleAnimation::endAnim();
delete this;
}
CDummyAnimation::CDummyAnimation(CBattleInterface * _owner, int howManyFrames) : CBattleAnimation(_owner), counter(0), howMany(howManyFrames)
{
}

View File

@@ -0,0 +1,28 @@
#pragma once
#include "CBattleAnimation.h"
class CBattleInterface;
/*
* CDummyAnimation.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
class CDummyAnimation : public CBattleAnimation
{
private:
int counter;
int howMany;
public:
bool init();
void nextFrame();
void endAnim();
CDummyAnimation(CBattleInterface *_owner, int howManyFrames);
};

View File

@@ -0,0 +1,147 @@
#include "StdInc.h"
#include "CHexFieldControl.h"
#include "CBattleInterface.h"
#include "../../lib/BattleState.h"
#include "../CGameInfo.h"
#include "../CPlayerInterface.h"
#include "../../lib/CTownHandler.h"
#include "../Graphics.h"
#include "../../CCallback.h"
#include "../../lib/CGeneralTextHandler.h"
#include "../SDL_Extensions.h"
#include "../GUIClasses.h"
#include "CBattleConsole.h"
Point CHexFieldControl::getXYUnitAnim(const int & hexNum, const bool & attacker, const CStack * stack, const CBattleInterface * cbi)
{
Point ret(-500, -500); //returned value
if(stack && stack->position < 0) //creatures in turrets
{
switch(stack->position)
{
case -2: //keep
ret = graphics->wallPositions[cbi->siegeH->town->town->typeID][17];
break;
case -3: //lower turret
ret = graphics->wallPositions[cbi->siegeH->town->town->typeID][18];
break;
case -4: //upper turret
ret = graphics->wallPositions[cbi->siegeH->town->town->typeID][19];
break;
}
}
else
{
ret.y = -139 + 42 * (hexNum/GameConstants::BFIELD_WIDTH); //counting y
//counting x
if(attacker)
{
ret.x = -160 + 22 * ( ((hexNum/GameConstants::BFIELD_WIDTH) + 1)%2 ) + 44 * (hexNum % GameConstants::BFIELD_WIDTH);
}
else
{
ret.x = -219 + 22 * ( ((hexNum/GameConstants::BFIELD_WIDTH) + 1)%2 ) + 44 * (hexNum % GameConstants::BFIELD_WIDTH);
}
//shifting position for double - hex creatures
if(stack && stack->doubleWide())
{
if(attacker)
{
ret.x -= 44;
}
else
{
ret.x += 45;
}
}
}
//returning
return ret +CPlayerInterface::battleInt->pos;
}
void CHexFieldControl::activate()
{
activateHover();
activateMouseMove();
activateLClick();
activateRClick();
}
void CHexFieldControl::deactivate()
{
deactivateHover();
deactivateMouseMove();
deactivateLClick();
deactivateRClick();
}
void CHexFieldControl::hover(bool on)
{
hovered = on;
//Hoverable::hover(on);
if(!on && setAlterText)
{
myInterface->console->alterTxt = std::string();
setAlterText = false;
}
}
CHexFieldControl::CHexFieldControl() : setAlterText(false), myNumber(-1), accessible(true), hovered(false), strictHovered(false), myInterface(NULL)
{
}
void CHexFieldControl::mouseMoved(const SDL_MouseMotionEvent &sEvent)
{
if(myInterface->cellShade)
{
if(CSDL_Ext::SDL_GetPixel(myInterface->cellShade, sEvent.x-pos.x, sEvent.y-pos.y) == 0) //hovered pixel is outside hex
{
strictHovered = false;
}
else //hovered pixel is inside hex
{
strictHovered = true;
}
}
if(hovered && strictHovered) //print attacked creature to console
{
const CStack * attackedStack = myInterface->curInt->cb->battleGetStackByPos(myNumber);
if(myInterface->console->alterTxt.size() == 0 &&attackedStack != NULL &&
attackedStack->owner != myInterface->curInt->playerID &&
attackedStack->alive())
{
char tabh[160];
const std::string & attackedName = attackedStack->count == 1 ? attackedStack->getCreature()->nameSing : attackedStack->getCreature()->namePl;
sprintf(tabh, CGI->generaltexth->allTexts[220].c_str(), attackedName.c_str());
myInterface->console->alterTxt = std::string(tabh);
setAlterText = true;
}
}
else if(setAlterText)
{
myInterface->console->alterTxt = std::string();
setAlterText = false;
}
}
void CHexFieldControl::clickLeft(tribool down, bool previousState)
{
if(!down && hovered && strictHovered) //we've been really clicked!
{
myInterface->hexLclicked(myNumber);
}
}
void CHexFieldControl::clickRight(tribool down, bool previousState)
{
const CStack * myst = myInterface->curInt->cb->battleGetStackByPos(myNumber); //stack info
if(hovered && strictHovered && myst!=NULL)
{
if(!myst->alive()) return;
if(down)
{
GH.pushInt(createCreWindow(myst));
}
}
}

View File

@@ -0,0 +1,40 @@
#pragma once
#include "../GUIBase.h"
class CBattleInterface;
class CStack;
struct SDL_MouseMotionEvent;
/*
* CHexFieldControl.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
/// Class which stands for a single hex field on a battlefield
class CHexFieldControl : public CIntObject
{
private:
bool setAlterText; //if true, this hex has set alternative text in console and will clean it
public:
ui32 myNumber; //number of hex in commonly used format
bool accessible; //if true, this hex is accessible for units
//CStack * ourStack;
bool hovered, strictHovered; //for determining if hex is hovered by mouse (this is different problem than hex's graphic hovering)
CBattleInterface * myInterface; //interface that owns me
static Point getXYUnitAnim(const int &hexNum, const bool &attacker, const CStack *creature, const CBattleInterface *cbi); //returns (x, y) of left top corner of animation
//for user interactions
void hover (bool on);
void activate();
void deactivate();
void mouseMoved (const SDL_MouseMotionEvent &sEvent);
void clickLeft(tribool down, bool previousState);
void clickRight(tribool down, bool previousState);
CHexFieldControl();
};

View File

@@ -0,0 +1,95 @@
#include "StdInc.h"
#include "CMeleeAttackAnimation.h"
#include "CBattleInterface.h"
#include "../CCreatureAnimation.h"
#include "../../lib/BattleState.h"
#include "CReverseAnimation.h"
bool CMeleeAttackAnimation::init()
{
if( !CAttackAnimation::checkInitialConditions() )
return false;
//if(owner->creAnims[stackID]->getType()!=2)
//{
// return false;
//}
if(!attackingStack || myAnim()->getType() == 5)
{
endAnim();
return false;
}
bool toReverse = isToReverse(attackingStackPosBeforeReturn, dest, owner->creDir[stack->ID], attackedStack->doubleWide(), owner->creDir[attackedStack->ID]);
if(toReverse)
{
owner->addNewAnim(new CReverseAnimation(owner, stack, attackingStackPosBeforeReturn, true));
return false;
}
//reversed
shooting = false;
static const CCreatureAnim::EAnimType mutPosToGroup[] = {CCreatureAnim::ATTACK_UP, CCreatureAnim::ATTACK_UP,
CCreatureAnim::ATTACK_FRONT, CCreatureAnim::ATTACK_DOWN, CCreatureAnim::ATTACK_DOWN, CCreatureAnim::ATTACK_FRONT};
int revShiftattacker = (attackingStack->attackerOwned ? -1 : 1);
int mutPos = SHexField::mutualPosition(attackingStackPosBeforeReturn, dest);
if(mutPos == -1 && attackingStack->doubleWide())
{
mutPos = SHexField::mutualPosition(attackingStackPosBeforeReturn + revShiftattacker, attackedStack->position);
}
if (mutPos == -1 && attackedStack->doubleWide())
{
mutPos = SHexField::mutualPosition(attackingStackPosBeforeReturn, attackedStack->occupiedHex());
}
if (mutPos == -1 && attackedStack->doubleWide() && attackingStack->doubleWide())
{
mutPos = SHexField::mutualPosition(attackingStackPosBeforeReturn + revShiftattacker, attackedStack->occupiedHex());
}
switch(mutPos) //attack direction
{
case 0: case 1: case 2: case 3: case 4: case 5:
group = mutPosToGroup[mutPos];
break;
default:
tlog1<<"Critical Error! Wrong dest in stackAttacking! dest: "<<dest<<" attacking stack pos: "<<attackingStackPosBeforeReturn<<" mutual pos: "<<mutPos<<std::endl;
group = CCreatureAnim::ATTACK_FRONT;
break;
}
return true;
}
void CMeleeAttackAnimation::nextFrame()
{
/*for(std::list<std::pair<CBattleAnimation *, bool> >::const_iterator it = owner->pendingAnims.begin(); it != owner->pendingAnims.end(); ++it)
{
CBattleMoveStart * anim = dynamic_cast<CBattleMoveStart *>(it->first);
CReverseAnim * anim2 = dynamic_cast<CReverseAnim *>(it->first);
if( (anim && anim->stackID == stackID) || (anim2 && anim2->stackID == stackID ) )
return;
}*/
CAttackAnimation::nextFrame();
}
void CMeleeAttackAnimation::endAnim()
{
CBattleAnimation::endAnim();
delete this;
}
CMeleeAttackAnimation::CMeleeAttackAnimation(CBattleInterface * _owner, const CStack * attacker, SHexField _dest, const CStack * _attacked)
: CAttackAnimation(_owner, attacker, _dest, _attacked)
{
}

View File

@@ -0,0 +1,28 @@
#pragma once
#include "CAttackAnimation.h"
class CBattleInterface;
class CStack;
/*
* CMeleeAttackAnimation.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
/// Hand-to-hand attack
class CMeleeAttackAnimation : public CAttackAnimation
{
public:
bool init();
void nextFrame();
void endAnim();
CMeleeAttackAnimation(CBattleInterface *_owner, const CStack *attacker, SHexField _dest, const CStack *_attacked);
};

View File

@@ -0,0 +1,176 @@
#include "StdInc.h"
#include "CMovementAnimation.h"
#include "CBattleInterface.h"
#include "../CCreatureAnimation.h"
#include "../../lib/BattleState.h"
#include "../CGameInfo.h"
#include "../CMusicHandler.h"
#include "CReverseAnimation.h"
#include "CMovementEndAnimation.h"
#include "CHexFieldControl.h"
bool CMovementAnimation::init()
{
if( !isEarliest(false) )
return false;
//a few useful variables
steps = static_cast<int>(myAnim()->framesInGroup(CCreatureAnim::MOVING) * owner->getAnimSpeedMultiplier() - 1);
if(steps == 0) //this creature seems to have no move animation so we can end it immediately
{
endAnim();
return false;
}
whichStep = 0;
int hexWbase = 44, hexHbase = 42;
const CStack * movedStack = stack;
if(!movedStack || myAnim()->getType() == 5)
{
endAnim();
return false;
}
//bool twoTiles = movedStack->doubleWide();
Point begPosition = CHexFieldControl::getXYUnitAnim(curStackPos, movedStack->attackerOwned, movedStack, owner);
Point endPosition = CHexFieldControl::getXYUnitAnim(nextHex, movedStack->attackerOwned, movedStack, owner);
int mutPos = SHexField::mutualPosition(curStackPos, nextHex);
//reverse unit if necessary
if((begPosition.x > endPosition.x) && owner->creDir[stack->ID] == true)
{
owner->addNewAnim(new CReverseAnimation(owner, stack, curStackPos, true));
return false;
}
else if ((begPosition.x < endPosition.x) && owner->creDir[stack->ID] == false)
{
owner->addNewAnim(new CReverseAnimation(owner, stack, curStackPos, true));
return false;
}
if(myAnim()->getType() != CCreatureAnim::MOVING)
{
myAnim()->setType(CCreatureAnim::MOVING);
}
//unit reversed
// if(owner->moveSh <= 0)
// owner->moveSh = CCS->soundh->playSound(battle_sound(movedStack->getCreature(), move), -1);
//step shift calculation
posX = myAnim()->pos.x, posY = myAnim()->pos.y; // for precise calculations ;]
if(mutPos == -1 && movedStack->hasBonusOfType(Bonus::FLYING))
{
steps *= distance;
steps /= 2; //to make animation faster
stepX = (endPosition.x - begPosition.x) / static_cast<double>(steps);
stepY = (endPosition.y - begPosition.y) / static_cast<double>(steps);
}
else
{
switch(mutPos)
{
case 0:
stepX = -1.0 * (hexWbase / (2.0 * steps));
stepY = -1.0 * (hexHbase / (static_cast<double>(steps)));
break;
case 1:
stepX = hexWbase / (2.0 * steps);
stepY = -1.0 * hexHbase / (static_cast<double>(steps));
break;
case 2:
stepX = hexWbase / static_cast<double>(steps);
stepY = 0.0;
break;
case 3:
stepX = hexWbase / (2.0 * steps);
stepY = hexHbase / static_cast<double>(steps);
break;
case 4:
stepX = -1.0 * hexWbase / (2.0 * steps);
stepY = hexHbase / static_cast<double>(steps);
break;
case 5:
stepX = -1.0 * hexWbase / static_cast<double>(steps);
stepY = 0.0;
break;
}
}
//step shifts calculated
return true;
}
void CMovementAnimation::nextFrame()
{
//moving instructions
posX += stepX;
myAnim()->pos.x = static_cast<Sint16>(posX);
posY += stepY;
myAnim()->pos.y = static_cast<Sint16>(posY);
// Increments step count and check if we are finished with current animation
++whichStep;
if(whichStep == steps)
{
// Sets the position of the creature animation sprites
Point coords = CHexFieldControl::getXYUnitAnim(nextHex, owner->creDir[stack->ID], stack, owner);
myAnim()->pos = coords;
// true if creature haven't reached the final destination hex
if ((nextPos + 1) < destTiles.size())
{
// update the next hex field which has to be reached by the stack
nextPos++;
curStackPos = nextHex;
nextHex = destTiles[nextPos];
// update position of double wide creatures
bool twoTiles = stack->doubleWide();
if(twoTiles && bool(stack->attackerOwned) && (owner->creDir[stack->ID] != bool(stack->attackerOwned) )) //big attacker creature is reversed
myAnim()->pos.x -= 44;
else if(twoTiles && (! bool(stack->attackerOwned) ) && (owner->creDir[stack->ID] != bool(stack->attackerOwned) )) //big defender creature is reversed
myAnim()->pos.x += 44;
// re-init animation
for(std::list<std::pair<CBattleAnimation *, bool> >::iterator it = owner->pendingAnims.begin(); it != owner->pendingAnims.end(); ++it)
{
if (it->first == this)
{
it->second = false;
break;
}
}
}
else
endAnim();
}
}
void CMovementAnimation::endAnim()
{
const CStack * movedStack = stack;
CBattleAnimation::endAnim();
if(movedStack)
owner->addNewAnim(new CMovementEndAnimation(owner, stack, nextHex));
if(owner->moveSh >= 0)
{
CCS->soundh->stopSound(owner->moveSh);
owner->moveSh = -1;
}
delete this;
}
CMovementAnimation::CMovementAnimation(CBattleInterface *_owner, const CStack *_stack, std::vector<SHexField> _destTiles, int _distance)
: CBattleStackAnimation(_owner, _stack), destTiles(_destTiles), nextPos(0), distance(_distance), stepX(0.0), stepY(0.0)
{
curStackPos = stack->position;
nextHex = destTiles.front();
}

View File

@@ -0,0 +1,37 @@
#pragma once
#include "CBattleStackAnimation.h"
class CBattleInterface;
class CStack;
/*
* CMovementAnimation.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
/// Move animation of a creature
class CMovementAnimation : public CBattleStackAnimation
{
private:
std::vector<SHexField> destTiles; //destination
SHexField nextHex;
ui32 nextPos;
int distance;
double stepX, stepY; //how far stack is moved in one frame
double posX, posY;
int steps, whichStep;
int curStackPos; //position of stack before move
public:
bool init();
void nextFrame();
void endAnim();
CMovementAnimation(CBattleInterface *_owner, const CStack *_stack, std::vector<SHexField> _destTiles, int _distance);
};

View File

@@ -0,0 +1,52 @@
#include "StdInc.h"
#include "CMovementEndAnimation.h"
#include "../CCreatureAnimation.h"
#include "../CMusicHandler.h"
#include "../CGameInfo.h"
#include "../../lib/BattleState.h"
#include "../CCursorHandler.h"
bool CMovementEndAnimation::init()
{
if( !isEarliest(true) )
return false;
if(!stack || myAnim()->framesInGroup(CCreatureAnim::MOVE_END) == 0 ||
myAnim()->getType() == CCreatureAnim::DEATH)
{
endAnim();
return false;
}
CCS->soundh->playSound(battle_sound(stack->getCreature(), endMoving));
myAnim()->setType(CCreatureAnim::MOVE_END);
return true;
}
void CMovementEndAnimation::nextFrame()
{
if(myAnim()->onLastFrameInGroup())
{
endAnim();
}
}
void CMovementEndAnimation::endAnim()
{
CBattleAnimation::endAnim();
if(myAnim()->getType() != CCreatureAnim::DEATH)
myAnim()->setType(CCreatureAnim::HOLDING); //resetting to default
CCS->curh->show();
delete this;
}
CMovementEndAnimation::CMovementEndAnimation(CBattleInterface * _owner, const CStack * _stack, SHexField destTile)
: CBattleStackAnimation(_owner, _stack), destinationTile(destTile)
{
}

View File

@@ -0,0 +1,30 @@
#pragma once
#include "CBattleStackAnimation.h"
class CBattleInterface;
class CStack;
/*
* CMovementEndAnimation.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
/// Move end animation of a creature
class CMovementEndAnimation : public CBattleStackAnimation
{
private:
SHexField destinationTile;
public:
bool init();
void nextFrame();
void endAnim();
CMovementEndAnimation(CBattleInterface *_owner, const CStack *_stack, SHexField destTile);
};

View File

@@ -0,0 +1,52 @@
#include "StdInc.h"
#include "CMovementStartAnimation.h"
#include "../CMusicHandler.h"
#include "CBattleInterface.h"
#include "../CGameInfo.h"
#include "../CCreatureAnimation.h"
#include "../../lib/BattleState.h"
#include "../CPlayerInterface.h"
bool CMovementStartAnimation::init()
{
if( !isEarliest(false) )
return false;
if(!stack || myAnim()->getType() == 5)
{
CMovementStartAnimation::endAnim();
return false;
}
CCS->soundh->playSound(battle_sound(stack->getCreature(), startMoving));
myAnim()->setType(CCreatureAnim::MOVE_START);
return true;
}
void CMovementStartAnimation::nextFrame()
{
if(myAnim()->onLastFrameInGroup())
{
endAnim();
}
else
{
if((owner->animCount+1)%(4/owner->curInt->sysOpts.animSpeed)==0)
myAnim()->incrementFrame();
}
}
void CMovementStartAnimation::endAnim()
{
CBattleAnimation::endAnim();
delete this;
}
CMovementStartAnimation::CMovementStartAnimation(CBattleInterface * _owner, const CStack * _stack)
: CBattleStackAnimation(_owner, _stack)
{
}

View File

@@ -0,0 +1,27 @@
#pragma once
#include "CBattleStackAnimation.h"
class CBattleInterface;
class CStack;
/*
* CMovementStartAnimation.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
/// Move start animation of a creature
class CMovementStartAnimation : public CBattleStackAnimation
{
public:
bool init();
void nextFrame();
void endAnim();
CMovementStartAnimation(CBattleInterface *_owner, const CStack *_stack);
};

View File

@@ -0,0 +1,100 @@
#include "StdInc.h"
#include "CReverseAnimation.h"
#include "../CCreatureAnimation.h"
#include "../../lib/BattleState.h"
#include "CBattleInterface.h"
#include "CHexFieldControl.h"
bool CReverseAnimation::init()
{
if(myAnim() == NULL || myAnim()->getType() == 5)
{
endAnim();
return false; //there is no such creature
}
if(!priority && !isEarliest(false))
return false;
if(myAnim()->framesInGroup(CCreatureAnim::TURN_R))
myAnim()->setType(CCreatureAnim::TURN_R);
else
setupSecondPart();
return true;
}
void CReverseAnimation::nextFrame()
{
if(partOfAnim == 1) //first part of animation
{
if(myAnim()->onLastFrameInGroup())
{
partOfAnim = 2;
}
}
else if(partOfAnim == 2)
{
if(!secondPartSetup)
{
setupSecondPart();
}
if(myAnim()->onLastFrameInGroup())
{
endAnim();
}
}
}
void CReverseAnimation::endAnim()
{
CBattleAnimation::endAnim();
if( stack->alive() )//don't do that if stack is dead
myAnim()->setType(CCreatureAnim::HOLDING);
delete this;
}
CReverseAnimation::CReverseAnimation(CBattleInterface * _owner, const CStack * stack, SHexField dest, bool _priority)
: CBattleStackAnimation(_owner, stack), partOfAnim(1), secondPartSetup(false), hex(dest), priority(_priority)
{
}
void CReverseAnimation::setupSecondPart()
{
owner->creDir[stack->ID] = !owner->creDir[stack->ID];
if(!stack)
{
endAnim();
return;
}
Point coords = CHexFieldControl::getXYUnitAnim(hex, owner->creDir[stack->ID], stack, owner);
myAnim()->pos.x = coords.x;
//creAnims[stackID]->pos.y = coords.second;
if(stack->doubleWide())
{
if(stack->attackerOwned)
{
if(!owner->creDir[stack->ID])
myAnim()->pos.x -= 44;
}
else
{
if(owner->creDir[stack->ID])
myAnim()->pos.x += 44;
}
}
secondPartSetup = true;
if(myAnim()->framesInGroup(CCreatureAnim::TURN_L))
myAnim()->setType(CCreatureAnim::TURN_L);
else
endAnim();
}

View File

@@ -0,0 +1,34 @@
#pragma once
#include "CBattleStackAnimation.h"
class CStack;
/*
* CReverseAnimation.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
/// Class responsible for animation of stack chaning direction (left <-> right)
class CReverseAnimation : public CBattleStackAnimation
{
private:
int partOfAnim; //1 - first, 2 - second
bool secondPartSetup;
SHexField hex;
public:
bool priority; //true - high, false - low
bool init();
void nextFrame();
void setupSecondPart();
void endAnim();
CReverseAnimation(CBattleInterface *_owner, const CStack *stack, SHexField dest, bool _priority);
};

View File

@@ -0,0 +1,192 @@
#include "StdInc.h"
#include <boost/math/constants/constants.hpp>
#include "CShootingAnimation.h"
#include "../../lib/BattleState.h"
#include "CBattleInterface.h"
#include "../CCreatureAnimation.h"
#include "../CGameInfo.h"
#include "../../lib/CTownHandler.h"
#include "CMovementStartAnimation.h"
#include "CReverseAnimation.h"
#include "CSpellEffectAnimation.h"
#include "CHexFieldControl.h"
bool CShootingAnimation::init()
{
if( !CAttackAnimation::checkInitialConditions() )
return false;
const CStack * shooter = attackingStack;
if(!shooter || myAnim()->getType() == 5)
{
endAnim();
return false;
}
// Create the projectile animation
double projectileAngle; //in radians; if positive, projectiles goes up
double straightAngle = 0.2; //maximal angle in radians between straight horizontal line and shooting line for which shot is considered to be straight (absoulte value)
int fromHex = shooter->position;
projectileAngle = atan2(static_cast<double>(abs(dest - fromHex) / GameConstants::BFIELD_WIDTH), static_cast<double>(abs(dest - fromHex) % GameConstants::BFIELD_WIDTH));
if(fromHex < dest)
projectileAngle = -projectileAngle;
// Get further info about the shooter e.g. relative pos of projectile to unit.
// If the creature id is 149 then it's a arrow tower which has no additional info so get the
// actual arrow tower shooter instead.
const CCreature *shooterInfo = shooter->getCreature();
if (shooterInfo->idNumber == 149)
{
int creID = CGI->creh->factionToTurretCreature[owner->siegeH->town->town->typeID];
shooterInfo = CGI->creh->creatures[creID];
}
SProjectileInfo spi;
spi.creID = shooter->getCreature()->idNumber;
spi.stackID = shooter->ID;
spi.reverse = !shooter->attackerOwned;
spi.step = 0;
spi.frameNum = 0;
if(vstd::contains(CGI->creh->idToProjectileSpin, shooterInfo->idNumber))
spi.spin = CGI->creh->idToProjectileSpin[shooterInfo->idNumber];
else
{
tlog2 << "Warning - no projectile spin for spi.creID " << shooterInfo->idNumber << std::endl;
spi.spin = false;
}
Point xycoord = CHexFieldControl::getXYUnitAnim(shooter->position, true, shooter, owner);
Point destcoord;
// The "master" point where all projectile positions relate to.
static const Point projectileOrigin(181, 252);
if (attackedStack)
{
destcoord = CHexFieldControl::getXYUnitAnim(dest, false, attackedStack, owner);
destcoord.x += 250; destcoord.y += 210; //TODO: find a better place to shoot
// Calculate projectile start position. Offsets are read out of the CRANIM.TXT.
if (projectileAngle > straightAngle)
{
//upper shot
spi.x = xycoord.x + projectileOrigin.x + shooterInfo->upperRightMissleOffsetX;
spi.y = xycoord.y + projectileOrigin.y + shooterInfo->upperRightMissleOffsetY;
}
else if (projectileAngle < -straightAngle)
{
//lower shot
spi.x = xycoord.x + projectileOrigin.x + shooterInfo->lowerRightMissleOffsetX;
spi.y = xycoord.y + projectileOrigin.y + shooterInfo->lowerRightMissleOffsetY;
}
else
{
//straight shot
spi.x = xycoord.x + projectileOrigin.x + shooterInfo->rightMissleOffsetX;
spi.y = xycoord.y + projectileOrigin.y + shooterInfo->rightMissleOffsetY;
}
double animSpeed = 23.0 * owner->getAnimSpeed(); // flight speed of projectile
spi.lastStep = static_cast<int>(sqrt(static_cast<double>((destcoord.x - spi.x) * (destcoord.x - spi.x) + (destcoord.y - spi.y) * (destcoord.y - spi.y))) / animSpeed);
if(spi.lastStep == 0)
spi.lastStep = 1;
spi.dx = (destcoord.x - spi.x) / spi.lastStep;
spi.dy = (destcoord.y - spi.y) / spi.lastStep;
spi.catapultInfo = 0;
}
else
{
// Catapult attack
// These are the values for equations of this kind: f(x) = ax^2 + bx + c
static const std::vector<SCatapultSProjectileInfo*> trajectoryCurves = boost::assign::list_of<SCatapultSProjectileInfo*>(new SCatapultSProjectileInfo(4.309, -3.198, 569.2, -296, 182))
(new SCatapultSProjectileInfo(4.710, -3.11, 558.68, -258, 175))(new SCatapultSProjectileInfo(5.056, -3.003, 546.9, -236, 174))
(new SCatapultSProjectileInfo(4.760, -2.74, 526.47, -216, 215))(new SCatapultSProjectileInfo(4.288, -2.496, 508.98, -223, 274))
(new SCatapultSProjectileInfo(3.683, -3.018, 558.39, -324, 176))(new SCatapultSProjectileInfo(2.884, -2.607, 528.95, -366, 312))
(new SCatapultSProjectileInfo(3.783, -2.364, 501.35, -227, 318));
static std::map<int, int> hexToCurve = boost::assign::map_list_of<int, int>(29, 0)(62, 1)(95, 2)(130, 3)(182, 4)(12, 5)(50, 6)(183, 7);
std::map<int, int>::iterator it = hexToCurve.find(dest.hex);
if (it == hexToCurve.end())
{
tlog1 << "For the hex position " << dest.hex << " is no curve defined.";
endAnim();
return false;
}
else
{
int curveID = it->second;
spi.catapultInfo = trajectoryCurves[curveID];
double animSpeed = 3.318 * owner->getAnimSpeed();
spi.lastStep = static_cast<int>((spi.catapultInfo->toX - spi.catapultInfo->fromX) / animSpeed);
spi.dx = animSpeed;
spi.dy = 0;
spi.x = xycoord.x + projectileOrigin.x + shooterInfo->rightMissleOffsetX + 17.;
spi.y = xycoord.y + projectileOrigin.y + shooterInfo->rightMissleOffsetY + 10.;
// Add explosion anim
int xEnd = static_cast<int>(spi.x + spi.lastStep * spi.dx);
int yEnd = static_cast<int>(spi.catapultInfo->calculateY(xEnd));
owner->addNewAnim( new CSpellEffectAnimation(owner, "SGEXPL.DEF", xEnd - 126, yEnd - 105));
}
}
// Set starting frame
if(spi.spin)
{
spi.frameNum = 0;
}
else
{
double pi = boost::math::constants::pi<double>();
spi.frameNum = static_cast<int>(((pi / 2.0 - projectileAngle) / (2.0 * pi) + 1/(static_cast<double>(2*(owner->idToProjectile[spi.creID]->ourImages.size()-1)))) * (owner->idToProjectile[spi.creID]->ourImages.size()-1));
}
// Set projectile animation start delay which is specified in frames
spi.animStartDelay = shooterInfo->attackClimaxFrame;
owner->projectiles.push_back(spi);
//attack animation
shooting = true;
if(projectileAngle > straightAngle) //upper shot
group = CCreatureAnim::SHOOT_UP;
else if(projectileAngle < -straightAngle) //lower shot
group = CCreatureAnim::SHOOT_DOWN;
else //straight shot
group = CCreatureAnim::SHOOT_FRONT;
return true;
}
void CShootingAnimation::nextFrame()
{
for(std::list<std::pair<CBattleAnimation *, bool> >::const_iterator it = owner->pendingAnims.begin(); it != owner->pendingAnims.end(); ++it)
{
CMovementStartAnimation * anim = dynamic_cast<CMovementStartAnimation *>(it->first);
CReverseAnimation * anim2 = dynamic_cast<CReverseAnimation *>(it->first);
if( (anim && anim->stack->ID == stack->ID) || (anim2 && anim2->stack->ID == stack->ID && anim2->priority ) )
return;
}
CAttackAnimation::nextFrame();
}
void CShootingAnimation::endAnim()
{
CBattleAnimation::endAnim();
delete this;
}
CShootingAnimation::CShootingAnimation(CBattleInterface * _owner, const CStack * attacker, SHexField _dest, const CStack * _attacked, bool _catapult, int _catapultDmg)
: CAttackAnimation(_owner, attacker, _dest, _attacked), catapultDamage(_catapultDmg), catapult(_catapult)
{
}

View File

@@ -0,0 +1,49 @@
#pragma once
#include "CAttackAnimation.h"
#include "../../lib/SHexField.h"
class CBattleInterface;
class CStack;
struct SCatapultSProjectileInfo;
/*
* CShootingAnimation.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
/// Small struct which contains information about the position and the velocity of a projectile
struct SProjectileInfo
{
double x, y; //position on the screen
double dx, dy; //change in position in one step
int step, lastStep; //to know when finish showing this projectile
int creID; //ID of creature that shot this projectile
int stackID; //ID of stack
int frameNum; //frame to display form projectile animation
bool spin; //if true, frameNum will be increased
int animStartDelay; //how many times projectile must be attempted to be shown till it's really show (decremented after hit)
bool reverse; //if true, projectile will be flipped by vertical asix
SCatapultSProjectileInfo *catapultInfo; // holds info about the parabolic trajectory of the cannon
};
/// Shooting attack
class CShootingAnimation : public CAttackAnimation
{
private:
int catapultDamage;
bool catapult;
public:
bool init();
void nextFrame();
void endAnim();
//last param only for catapult attacks
CShootingAnimation(CBattleInterface *_owner, const CStack *attacker,
SHexField _dest, const CStack *_attacked, bool _catapult = false, int _catapultDmg = 0);
};

View File

@@ -0,0 +1,181 @@
#include "StdInc.h"
#include "CSpellEffectAnimation.h"
#include "../Graphics.h"
#include "CBattleInterface.h"
#include "../CDefHandler.h"
#include "../CPlayerInterface.h"
#include "../../CCallback.h"
#include "../../lib/BattleState.h"
#include "../SDL_Extensions.h"
//effect animation
bool CSpellEffectAnimation::init()
{
if(!isEarliest(true))
return false;
if(effect == 12) //armageddon
{
if(effect == -1 || graphics->battleACToDef[effect].size() != 0)
{
CDefHandler * anim;
if(customAnim.size())
anim = CDefHandler::giveDef(customAnim);
else
anim = CDefHandler::giveDef(graphics->battleACToDef[effect][0]);
if (Vflip)
{
for (size_t v = 0; v < anim->ourImages.size(); ++v)
{
CSDL_Ext::VflipSurf(anim->ourImages[v].bitmap);
}
}
for(int i=0; i * anim->width < owner->pos.w ; ++i)
{
for(int j=0; j * anim->height < owner->pos.h ; ++j)
{
SBattleEffect be;
be.effectID = ID;
be.anim = CDefHandler::giveDef(graphics->battleACToDef[effect][0]);
if (Vflip)
{
for (size_t v = 0; v < be.anim->ourImages.size(); ++v)
{
CSDL_Ext::VflipSurf(be.anim->ourImages[v].bitmap);
}
}
be.frame = 0;
be.maxFrame = be.anim->ourImages.size();
be.x = i * anim->width + owner->pos.x;
be.y = j * anim->height + owner->pos.y;
owner->battleEffects.push_back(be);
}
}
}
else //there is nothing to play
{
endAnim();
return false;
}
}
else // Effects targeted at a specific creature/hex.
{
if(effect == -1 || graphics->battleACToDef[effect].size() != 0)
{
const CStack* destStack = owner->curInt->cb->battleGetStackByPos(destTile, false);
Rect &tilePos = owner->bfield[destTile].pos;
SBattleEffect be;
be.effectID = ID;
if(customAnim.size())
be.anim = CDefHandler::giveDef(customAnim);
else
be.anim = CDefHandler::giveDef(graphics->battleACToDef[effect][0]);
if (Vflip)
{
for (size_t v = 0; v < be.anim->ourImages.size(); ++v)
{
CSDL_Ext::VflipSurf(be.anim->ourImages[v].bitmap);
}
}
be.frame = 0;
be.maxFrame = be.anim->ourImages.size();
if(effect == 1)
be.maxFrame = 3;
switch (effect)
{
case -1:
be.x = x;
be.y = y;
break;
case 0: // Prayer and Lightning Bolt.
case 1:
// Position effect with it's bottom center touching the bottom center of affected tile(s).
be.x = tilePos.x + tilePos.w/2 - be.anim->width/2;
be.y = tilePos.y + tilePos.h - be.anim->height;
break;
default:
// Position effect with it's center touching the top center of affected tile(s).
be.x = tilePos.x + tilePos.w/2 - be.anim->width/2;
be.y = tilePos.y - be.anim->height/2;
break;
}
// Correction for 2-hex creatures.
if (destStack != NULL && destStack->doubleWide())
be.x += (destStack->attackerOwned ? -1 : 1)*tilePos.w/2;
owner->battleEffects.push_back(be);
}
else //there is nothing to play
{
endAnim();
return false;
}
}
//battleEffects
return true;
}
void CSpellEffectAnimation::nextFrame()
{
//notice: there may be more than one effect in owner->battleEffects correcponding to this animation (ie. armageddon)
for(std::list<SBattleEffect>::iterator it = owner->battleEffects.begin(); it != owner->battleEffects.end(); ++it)
{
if(it->effectID == ID)
{
++(it->frame);
if(it->frame == it->maxFrame)
{
endAnim();
break;
}
else
{
it->x += dx;
it->y += dy;
}
}
}
}
void CSpellEffectAnimation::endAnim()
{
CBattleAnimation::endAnim();
std::vector<std::list<SBattleEffect>::iterator> toDel;
for(std::list<SBattleEffect>::iterator it = owner->battleEffects.begin(); it != owner->battleEffects.end(); ++it)
{
if(it->effectID == ID)
{
toDel.push_back(it);
}
}
for(size_t b = 0; b < toDel.size(); ++b)
{
delete toDel[b]->anim;
owner->battleEffects.erase(toDel[b]);
}
delete this;
}
CSpellEffectAnimation::CSpellEffectAnimation(CBattleInterface * _owner, ui32 _effect, SHexField _destTile, int _dx, int _dy, bool _Vflip)
:CBattleAnimation(_owner), effect(_effect), destTile(_destTile), customAnim(""), dx(_dx), dy(_dy), Vflip(_Vflip)
{
}
CSpellEffectAnimation::CSpellEffectAnimation(CBattleInterface * _owner, std::string _customAnim, int _x, int _y, int _dx, int _dy, bool _Vflip)
:CBattleAnimation(_owner), effect(-1), destTile(0), customAnim(_customAnim), x(_x), y(_y), dx(_dx), dy(_dy), Vflip(_Vflip)
{
}

View File

@@ -0,0 +1,35 @@
#pragma once
#include "CBattleAnimation.h"
#include "../../lib/SHexField.h"
class CBattleInterface;
/*
* CSpellEffectAnimation.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
/// This class manages a spell effect animation
class CSpellEffectAnimation : public CBattleAnimation
{
private:
ui32 effect;
SHexField destTile;
std::string customAnim;
int x, y, dx, dy;
bool Vflip;
public:
bool init();
void nextFrame();
void endAnim();
CSpellEffectAnimation(CBattleInterface *_owner, ui32 _effect, SHexField _destTile, int _dx = 0, int _dy = 0, bool _Vflip = false);
CSpellEffectAnimation(CBattleInterface *_owner, std::string _customAnim, int _x, int _y, int _dx = 0, int _dy = 0, bool _Vflip = false);
};

View File

@@ -0,0 +1,125 @@
#include "StdInc.h"
#include "CStackQueue.h"
#include "CBattleInterface.h"
#include "../../lib/BattleState.h"
#include "../Graphics.h"
#include "../SDL_Extensions.h"
#include "../CPlayerInterface.h"
#include "../CBitmapHandler.h"
#include "../../CCallback.h"
void CStackQueue::update()
{
stacksSorted.clear();
owner->curInt->cb->getStackQueue(stacksSorted, QUEUE_SIZE);
for (int i = 0; i < QUEUE_SIZE ; i++)
{
stackBoxes[i]->setStack(stacksSorted[i]);
}
}
CStackQueue::CStackQueue(bool Embedded, CBattleInterface * _owner)
:embedded(Embedded), owner(_owner)
{
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 )
{
blitBg(to);
CIntObject::showAll(to);
}
void CStackQueue::blitBg( SDL_Surface * to )
{
if(bg)
{
for (int w = 0; w < pos.w; w += bg->w)
{
blitAtLoc(bg, w, 0, to);
}
}
}
void CStackQueue::StackBox::showAll( SDL_Surface *to )
{
assert(my);
if(bg)
{
graphics->blueToPlayersAdv(bg, my->owner);
//SDL_UpdateRect(bg, 0, 0, 0, 0);
SDL_Rect temp_rect = genRect(bg->h, bg->w, pos.x, pos.y);
CSDL_Ext::blit8bppAlphaTo24bpp(bg, NULL, to, &temp_rect);
//blitAt(bg, pos, to);
blitAt(graphics->bigImgs[my->getCreature()->idNumber], pos.x +9, pos.y + 1, to);
printAtMiddleLoc(makeNumberShort(my->count), pos.w/2, pos.h - 12, FONT_MEDIUM, zwykly, to);
}
else
{
blitAt(graphics->smallImgs[-2], pos, to);
blitAt(graphics->smallImgs[my->getCreature()->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->count), 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)
:my(NULL), bg(BG)
{
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 )
{
}

View File

@@ -0,0 +1,51 @@
#pragma once
#include "../GUIBase.h"
struct SDL_Surface;
class CStack;
class CBattleInterface;
/*
* CStackQueue.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
/// Shows the stack queue
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;
CBattleInterface * owner;
void showAll(SDL_Surface *to);
CStackQueue(bool Embedded, CBattleInterface * _owner);
~CStackQueue();
void update();
void blitBg( SDL_Surface * to );
//void showAll(SDL_Surface *to);
};

View File

@@ -0,0 +1,25 @@
#pragma once
class CStack;
/*
* SStackAttackedInfo.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
/// Small struct which contains information about the id of the attacked stack, the damage dealt,...
struct SStackAttackedInfo
{
const CStack * defender; //attacked stack
int dmg; //damage dealt
int amountKilled; //how many creatures in stack has been killed
const CStack * attacker; //attacking stack
bool byShooting; //if true, stack has been attacked by shooting
bool killed; //if true, stack has been killed
bool rebirth; //if true, play rebirth animation after all
};

View File

@@ -1,597 +0,0 @@
#ifndef __CBATTLEINTERFACE_H__
#define __CBATTLEINTERFACE_H__
#include "../global.h"
#include <list>
#include "GUIBase.h"
#include "../lib/CCreatureSet.h"
#include "../lib/ConstTransitivePtr.h" //may be reundant
#include "CAnimation.h"
/*
* CBattleInterface.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
class CLabel;
class CCreatureSet;
class CGHeroInstance;
class CDefHandler;
class CStack;
class CCallback;
class AdventureMapButton;
class CHighlightableButton;
class CHighlightableButtonsGroup;
struct BattleResult;
struct BattleSpellCast;
struct CObstacleInstance;
template <typename T> struct CondSh;
struct SetStackEffect;;
struct BattleAction;
class CGTownInstance;
struct CatapultAttack;
class CBattleInterface;
struct CatapultProjectileInfo;
struct BattleTriggerEffect;
/// Small struct which contains information about the id of the attacked stack, the damage dealt,...
struct SStackAttackedInfo
{
const CStack * defender; //attacked stack
int dmg; //damage dealt
int amountKilled; //how many creatures in stack has been killed
const CStack * attacker; //attacking stack
bool byShooting; //if true, stack has been attacked by shooting
bool killed; //if true, stack has been killed
bool rebirth; //if true, play rebirth animation after all
};
/// Small struct which contains information about the position and the velocity of a projectile
struct SProjectileInfo
{
double x, y; //position on the screen
double dx, dy; //change in position in one step
int step, lastStep; //to know when finish showing this projectile
int creID; //ID of creature that shot this projectile
int stackID; //ID of stack
int frameNum; //frame to display form projectile animation
bool spin; //if true, frameNum will be increased
int animStartDelay; //how many times projectile must be attempted to be shown till it's really show (decremented after hit)
bool reverse; //if true, projectile will be flipped by vertical asix
CatapultProjectileInfo *catapultInfo; // holds info about the parabolic trajectory of the cannon
};
/// Base class of battle animations
class CBattleAnimation
{
protected:
CBattleInterface * owner;
public:
virtual bool init()=0; //to be called - if returned false, call again until returns true
virtual void nextFrame()=0; //call every new frame
virtual void endAnim(); //to be called mostly internally; in this class it removes animation from pendingAnims list
bool isEarliest(bool perStackConcurrency); //determines if this animation is earliest of all
unsigned int ID; //unique identifier
CBattleAnimation(CBattleInterface * _owner);
};
class CDummyAnim : public CBattleAnimation
{
private:
int counter;
int howMany;
public:
bool init();
void nextFrame();
void endAnim();
CDummyAnim(CBattleInterface * _owner, int howManyFrames);
};
/// This class manages a spell effect animation
class CSpellEffectAnim : public CBattleAnimation
{
private:
ui32 effect;
THex destTile;
std::string customAnim;
int x, y, dx, dy;
bool Vflip;
public:
bool init();
void nextFrame();
void endAnim();
CSpellEffectAnim(CBattleInterface * _owner, ui32 _effect, THex _destTile, int _dx = 0, int _dy = 0, bool _Vflip = false);
CSpellEffectAnim(CBattleInterface * _owner, std::string _customAnim, int _x, int _y, int _dx = 0, int _dy = 0, bool _Vflip = false);
};
/// Sub-class which is responsible for managing the battle stack animation.
class CBattleStackAnimation : public CBattleAnimation
{
public:
const CStack * stack; //id of stack whose animation it is
CBattleStackAnimation(CBattleInterface * _owner, const CStack * _stack);
static bool isToReverseHlp(THex hexFrom, THex hexTo, bool curDir); //helper for isToReverse
static bool isToReverse(THex hexFrom, THex hexTo, bool curDir /*if true, creature is in attacker's direction*/, bool toDoubleWide, bool toDir); //determines if creature should be reversed (it stands on hexFrom and should 'see' hexTo)
CCreatureAnimation *myAnim(); //animation for our stack
};
/// Class responsible for animation of stack chaning direction (left <-> right)
class CReverseAnim : public CBattleStackAnimation
{
private:
int partOfAnim; //1 - first, 2 - second
bool secondPartSetup;
THex hex;
public:
bool priority; //true - high, false - low
bool init();
void nextFrame();
void setupSecondPart();
void endAnim();
CReverseAnim(CBattleInterface * _owner, const CStack * stack, THex dest, bool _priority);
};
/// Animation of a defending unit
class CDefenceAnim : public CBattleStackAnimation
{
private:
//std::vector<SStackAttackedInfo> attackedInfos;
int dmg; //damage dealt
int amountKilled; //how many creatures in stack has been killed
const CStack * attacker; //attacking stack
bool byShooting; //if true, stack has been attacked by shooting
bool killed; //if true, stack has been killed
public:
bool init();
void nextFrame();
void endAnim();
CDefenceAnim(SStackAttackedInfo _attackedInfo, CBattleInterface * _owner);
};
/// Move animation of a creature
class CBattleStackMoved : public CBattleStackAnimation
{
private:
std::vector<THex> destTiles; //destination
THex nextHex;
int nextPos;
int distance;
float stepX, stepY; //how far stack is moved in one frame
float posX, posY;
int steps, whichStep;
int curStackPos; //position of stack before move
public:
bool init();
void nextFrame();
void endAnim();
CBattleStackMoved(CBattleInterface * _owner, const CStack * _stack, std::vector<THex> _destTiles, int _distance);
};
/// Move start animation of a creature
class CBattleMoveStart : public CBattleStackAnimation
{
public:
bool init();
void nextFrame();
void endAnim();
CBattleMoveStart(CBattleInterface * _owner, const CStack * _stack);
};
/// Move end animation of a creature
class CBattleMoveEnd : public CBattleStackAnimation
{
private:
THex destinationTile;
public:
bool init();
void nextFrame();
void endAnim();
CBattleMoveEnd(CBattleInterface * _owner, const CStack * _stack, THex destTile);
};
/// This class is responsible for managing the battle attack animation
class CBattleAttack : public CBattleStackAnimation
{
protected:
THex dest; //atacked hex
bool shooting;
CCreatureAnim::EAnimType group; //if shooting is true, print this animation group
const CStack * attackedStack;
const CStack * attackingStack;
int attackingStackPosBeforeReturn; //for stacks with return_after_strike feature
public:
void nextFrame();
bool checkInitialConditions();
CBattleAttack(CBattleInterface * _owner, const CStack * attacker, THex _dest, const CStack * defender);
};
/// Hand-to-hand attack
class CMeleeAttack : public CBattleAttack
{
public:
bool init();
void nextFrame();
void endAnim();
CMeleeAttack(CBattleInterface * _owner, const CStack * attacker, THex _dest, const CStack * _attacked);
};
/// Shooting attack
class CShootingAnim : public CBattleAttack
{
private:
int catapultDamage;
bool catapult;
public:
bool init();
void nextFrame();
void endAnim();
CShootingAnim(CBattleInterface * _owner, const CStack * attacker, THex _dest, const CStack * _attacked, bool _catapult = false, int _catapultDmg = 0); //last param only for catapult attacks
};
//end of battle animation handlers
/// Hero battle animation
class CBattleHero : public CIntObject
{
public:
bool flip; //false if it's attacking hero, true otherwise
CDefHandler * dh, *flag; //animation and flag
const CGHeroInstance * myHero; //this animation's hero instance
const CBattleInterface * myOwner; //battle interface to which this animation is assigned
int phase; //stage of animation
int nextPhase; //stage of animation to be set after current phase is fully displayed
int image; //frame of animation
unsigned char flagAnim, flagAnimCount; //for flag animation
void show(SDL_Surface * to); //prints next frame of animation to to
void activate();
void deactivate();
void setPhase(int newPhase); //sets phase of hero animation
void clickLeft(tribool down, bool previousState); //call-in
CBattleHero(const std::string & defName, int phaseG, int imageG, bool filpG, unsigned char player, const CGHeroInstance * hero, const CBattleInterface * owner); //c-tor
~CBattleHero(); //d-tor
};
/// Class which stands for a single hex field on a battlefield
class CBattleHex : public CIntObject
{
private:
bool setAlterText; //if true, this hex has set alternative text in console and will clean it
public:
unsigned int myNumber; //number of hex in commonly used format
bool accessible; //if true, this hex is accessible for units
//CStack * ourStack;
bool hovered, strictHovered; //for determining if hex is hovered by mouse (this is different problem than hex's graphic hovering)
CBattleInterface * myInterface; //interface that owns me
static Point getXYUnitAnim(const int & hexNum, const bool & attacker, const CStack * creature, const CBattleInterface * cbi); //returns (x, y) of left top corner of animation
//for user interactions
void hover (bool on);
void activate();
void deactivate();
void mouseMoved (const SDL_MouseMotionEvent & sEvent);
void clickLeft(tribool down, bool previousState);
void clickRight(tribool down, bool previousState);
CBattleHex();
};
/// Class which manages the locked hex fields that are blocked e.g. by obstacles
class CBattleObstacle
{
std::vector<int> lockedHexes;
};
/// Class which shows the console at the bottom of the battle screen and manages the text of the console
class CBattleConsole : public CIntObject
{
private:
std::vector< std::string > texts; //a place where texts are stored
int lastShown; //last shown line of text
public:
std::string alterTxt; //if it's not empty, this text is displayed
std::string ingcAlter; //alternative text set by in-game console - very important!
int whoSetAlter; //who set alter text; 0 - battle interface or none, 1 - button
CBattleConsole(); //c-tor
~CBattleConsole(); //d-tor
void show(SDL_Surface * to = 0);
bool addText(const std::string & text); //adds text at the last position; returns false if failed (e.g. text longer than 70 characters)
void eraseText(unsigned int pos); //erases added text at position pos
void changeTextAt(const std::string & text, unsigned int pos); //if we have more than pos texts, pos-th is changed to given one
void scrollUp(unsigned int by = 1); //scrolls console up by 'by' positions
void scrollDown(unsigned int by = 1); //scrolls console up by 'by' positions
};
/// Class which is responsible for showing the battle result window
class CBattleResultWindow : public CIntObject
{
private:
SDL_Surface * background;
AdventureMapButton * exit;
CBattleInterface * owner;
public:
CBattleResultWindow(const BattleResult & br, const SDL_Rect & pos, CBattleInterface * _owner); //c-tor
~CBattleResultWindow(); //d-tor
void bExitf(); //exit button callback
void activate();
void deactivate();
void show(SDL_Surface * to = 0);
};
/// Class which manages the battle options window
class CBattleOptionsWindow : public CIntObject
{
private:
CBattleInterface * myInt;
CPicture * background;
AdventureMapButton * setToDefault, * exit;
CHighlightableButton * viewGrid, * movementShadow, * mouseShadow;
CHighlightableButtonsGroup * animSpeeds;
std::vector<CLabel*> labels;
public:
CBattleOptionsWindow(const SDL_Rect & position, CBattleInterface * owner); //c-tor
void bDefaultf(); //dafault button callback
void bExitf(); //exit button callback
};
/// Struct for battle effect animation e.g. morale, prayer, armageddon, bless,...
struct SBattleEffect
{
int x, y; //position on the screen
int frame, maxFrame;
CDefHandler * anim; //animation to display
int effectID; //uniqueID equal ot ID of appropriate CSpellEffectAnim
};
/// Shows the stack queue
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;
CBattleInterface * owner;
void showAll(SDL_Surface *to);
CStackQueue(bool Embedded, CBattleInterface * _owner);
~CStackQueue();
void update();
void blitBg( SDL_Surface * to );
//void showAll(SDL_Surface *to);
};
/// Small struct which is needed for drawing the parabolic trajectory of the catapult cannon
struct CatapultProjectileInfo
{
const double facA, facB, facC;
const int fromX, toX;
CatapultProjectileInfo() : facA(0), facB(0), facC(0), fromX(0), toX(0) { };
CatapultProjectileInfo(double factorA, double factorB, double factorC, int fromXX, int toXX) : facA(factorA), facB(factorB), facC(factorC),
fromX(fromXX), toX(toXX) { };
double calculateY(double x);
};
/// Big class which handles the overall battle interface actions and it is also responsible for
/// drawing everything correctly.
class CBattleInterface : public CIntObject
{
enum SpellSelectionType
{
ANY_LOCATION = 0, FRIENDLY_CREATURE, HOSTILE_CREATURE, ANY_CREATURE, OBSTACLE, TELEPORT, NO_LOCATION = -1, STACK_SPELL_CANCELLED = -2
};
private:
SDL_Surface * background, * menu, * amountNormal, * amountNegative, * amountPositive, * amountEffNeutral, * cellBorders, * backgroundWithHexes;
AdventureMapButton * bOptions, * bSurrender, * bFlee, * bAutofight, * bSpell,
* bWait, * bDefence, * bConsoleUp, * bConsoleDown, *btactNext, *btactEnd;
CBattleConsole * console;
CBattleHero * attackingHero, * defendingHero; //fighting heroes
CStackQueue *queue;
const CCreatureSet *army1, *army2; //copy of initial armies (for result window)
const CGHeroInstance * attackingHeroInstance, * defendingHeroInstance;
std::map< int, CCreatureAnimation * > creAnims; //animations of creatures from fighting armies (order by BattleInfo's stacks' ID)
std::map< int, CDefHandler * > idToProjectile; //projectiles of creatures (creatureID, defhandler)
std::map< int, CDefHandler * > idToObstacle; //obstacles located on the battlefield
std::map< int, bool > creDir; // <creatureID, if false reverse creature's animation>
unsigned char animCount;
const CStack * activeStack; //number of active stack; NULL - no one
const CStack * stackToActivate; //when animation is playing, we should wait till the end to make the next stack active; NULL of none
void activateStack(); //sets activeStack to stackToActivate etc.
int mouseHoveredStack; //stack hovered by mouse; if -1 -> none
time_t lastMouseHoveredStackAnimationTime; // time when last mouse hovered animation occurred
static const time_t HOVER_ANIM_DELTA;
std::vector<THex> occupyableHexes, //hexes available for active stack
attackableHexes; //hexes attackable by active stack
bool stackCountOutsideHexes[BFIELD_SIZE]; // hexes that when in front of a unit cause it's amount box to move back
int previouslyHoveredHex; //number of hex that was hovered by the cursor a while ago
int currentlyHoveredHex; //number of hex that is supposed to be hovered (for a while it may be inappropriately set, but will be renewed soon)
int attackingHex; //hex from which the stack would perform attack with current cursor
float getAnimSpeedMultiplier() const; //returns multiplier for number of frames in a group
std::map<int, int> standingFrame; //number of frame in standing animation by stack ID, helps in showing 'random moves'
CPlayerInterface *tacticianInterface; //used during tactics mode, points to the interface of player with higher tactics (can be either attacker or defender in hot-seat), valid onloy for human players
bool tacticsMode;
bool stackCanCastSpell; //if true, active stack could possibly cats some target spell
bool spellDestSelectMode; //if true, player is choosing destination for his spell
SpellSelectionType spellSelMode;
BattleAction * spellToCast; //spell for which player is choosing destination
TSpell creatureSpellToCast;
void endCastingSpell(); //ends casting spell (eg. when spell has been cast or canceled)
void showAliveStack(const CStack *stack, SDL_Surface * to); //helper function for function show
void showAliveStacks(std::vector<const CStack *> *aliveStacks, int hex, std::vector<const CStack *> *flyingStacks, SDL_Surface *to); // loops through all stacks at a given hex position
void showPieceOfWall(SDL_Surface * to, int hex, const std::vector<const CStack*> & stacks); //helper function for show
void showObstacles(std::multimap<THex, int> *hexToObstacle, std::vector<CObstacleInstance> &obstacles, int hex, SDL_Surface *to); // show all obstacles at a given hex position
void redrawBackgroundWithHexes(const CStack * activeStack);
void printConsoleAttacked(const CStack * defender, int dmg, int killed, const CStack * attacker, bool Multiple);
std::list<SProjectileInfo> projectiles; //projectiles flying on battlefield
void projectileShowHelper(SDL_Surface * to); //prints projectiles present on the battlefield
void giveCommand(ui8 action, THex tile, ui32 stack, si32 additional=-1);
bool isTileAttackable(const THex & number) const; //returns true if tile 'number' is neighboring any tile from active stack's range or is one of these tiles
bool blockedByObstacle(THex hex) const;
bool isCatapultAttackable(THex hex) const; //returns true if given tile can be attacked by catapult
std::list<SBattleEffect> battleEffects; //different animations to display on the screen like spell effects
/// Class which is responsible for drawing the wall of a siege during battle
class SiegeHelper
{
private:
static std::string townTypeInfixes[F_NUMBER]; //for internal use only - to build filenames
SDL_Surface * walls[18];
const CBattleInterface * owner;
public:
const CGTownInstance * town; //besieged town
SiegeHelper(const CGTownInstance * siegeTown, const CBattleInterface * _owner); //c-tor
~SiegeHelper(); //d-tor
//filename getters
std::string getSiegeName(ui16 what, ui16 additInfo = 1) const; //what: 0 - background, 1 - background wall, 2 - keep, 3 - bottom tower, 4 - bottom wall, 5 - below gate, 6 - over gate, 7 - upper wall, 8 - uppert tower, 9 - gate, 10 - gate arch, 11 - bottom static wall, 12 - upper static wall, 13 - moat, 14 - mlip, 15 - keep creature cover, 16 - bottom turret creature cover, 17 - upper turret creature cover; additInfo: 1 - intact, 2 - damaged, 3 - destroyed
void printPartOfWall(SDL_Surface * to, int what);//what: 1 - background wall, 2 - keep, 3 - bottom tower, 4 - bottom wall, 5 - below gate, 6 - over gate, 7 - upper wall, 8 - uppert tower, 9 - gate, 10 - gate arch, 11 - bottom static wall, 12 - upper static wall, 15 - keep creature cover, 16 - bottom turret creature cover, 17 - upper turret creature cover
friend class CBattleInterface;
} * siegeH;
CPlayerInterface * attackerInt, * defenderInt; //because LOCPLINT is not enough in hotSeat
const CGHeroInstance * getActiveHero(); //returns hero that can currently cast a spell
public:
CPlayerInterface * curInt; //current player interface
std::list<std::pair<CBattleAnimation *, bool> > pendingAnims; //currently displayed animations <anim, initialized>
void addNewAnim(CBattleAnimation * anim); //adds new anim to pendingAnims
unsigned int animIDhelper; //for giving IDs for animations
static CondSh<bool> animsAreDisplayed; //for waiting with the end of battle for end of anims
CBattleInterface(const CCreatureSet * army1, const CCreatureSet * army2, CGHeroInstance *hero1, CGHeroInstance *hero2, const SDL_Rect & myRect, CPlayerInterface * att, CPlayerInterface * defen); //c-tor
~CBattleInterface(); //d-tor
//std::vector<TimeInterested*> timeinterested; //animation handling
void setPrintCellBorders(bool set); //if true, cell borders will be printed
void setPrintStackRange(bool set); //if true,range of active stack will be printed
void setPrintMouseShadow(bool set); //if true, hex under mouse will be shaded
void setAnimSpeed(int set); //speed of animation; 1 - slowest, 2 - medium, 4 - fastest
int getAnimSpeed() const; //speed of animation; 1 - slowest, 2 - medium, 4 - fastest
CBattleHex bfield[BFIELD_SIZE]; //11 lines, 17 hexes on each
//std::vector< CBattleObstacle * > obstacles; //vector of obstacles on the battlefield
SDL_Surface * cellBorder, * cellShade;
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 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
//button handle funcs:
void bOptionsf();
void bSurrenderf();
void bFleef();
void reallyFlee(); //performs fleeing without asking player
void reallySurrender(); //performs surrendering without asking player
void bAutofightf();
void bSpellf();
void bWaitf();
void bDefencef();
void bConsoleUpf();
void bConsoleDownf();
void bTacticNextStack();
void bEndTacticPhase();
//end of button handle funcs
//napisz tu klase odpowiadajaca za wyswietlanie bitwy i obsluge uzytkownika, polecenia ma przekazywac callbackiem
void activate();
void deactivate();
void show(SDL_Surface * to);
void keyPressed(const SDL_KeyboardEvent & key);
void mouseMoved(const SDL_MouseMotionEvent &sEvent);
void clickRight(tribool down, bool previousState);
//call-ins
void startAction(const BattleAction* action);
void newStack(const CStack * stack); //new stack appeared on battlefield
void stackRemoved(int stackID); //stack disappeared from batlefiled
void stackActivated(const CStack * stack); //active stack has been changed
void stackMoved(const CStack * stack, std::vector<THex> destHex, int distance); //stack with id number moved to destHex
void waitForAnims();
void stacksAreAttacked(std::vector<SStackAttackedInfo> attackedInfos); //called when a certain amount of stacks has been attacked
void stackAttacking(const CStack * attacker, THex dest, const CStack * attacked, bool shooting); //called when stack with id ID is attacking something on hex dest
void newRoundFirst( int round );
void newRound(int number); //caled when round is ended; number is the number of round
void hexLclicked(int whichOne); //hex only call-in
void stackIsCatapulting(const CatapultAttack & ca); //called when a stack is attacking walls
void battleFinished(const BattleResult& br); //called when battle is finished - battleresult window should be printed
const BattleResult * bresult; //result of a battle; if non-zero then display when all animations end
void displayBattleFinished(); //displays battle result
void spellCast(const BattleSpellCast * sc); //called when a hero casts a spell
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 battleTriggerEffect(const BattleTriggerEffect & bte);
void setBattleCursor(const int myNumber); //really complex and messy
void endAction(const BattleAction* action);
void hideQueue();
void showQueue();
friend class CBattleHex;
friend class CBattleResultWindow;
friend class CPlayerInterface;
friend class AdventureMapButton;
friend class CInGameConsole;
friend class CReverseAnim;
friend class CBattleStackAnimation;
friend class CBattleAnimation;
friend class CDefenceAnim;
friend class CBattleStackMoved;
friend class CBattleMoveStart;
friend class CBattleMoveEnd;
friend class CBattleAttack;
friend class CMeleeAttack;
friend class CShootingAnim;
friend class CSpellEffectAnim;
friend class CBattleHero;
};
#endif // __CBATTLEINTERFACE_H__

2
client/StdInc.cpp Normal file
View File

@@ -0,0 +1,2 @@
// Creates the precompiled header
#include "StdInc.h"

325
client/StdInc.h Normal file
View File

@@ -0,0 +1,325 @@
#pragma once
// Standard include file
// Should be treated as a precompiled header file in the compiler settings
// We generate a .PCH file for every project due to simplicity and some annoying bugs in VisualStudio
// This file shouldn't be changed, except if there is a important header file which is missing.
/*
* StdInc.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <cstdio>
#include <stdio.h>
#ifdef _WIN32
#include <tchar.h>
#else
#include "../tchar_amigaos4.h"
#endif
#include <cmath>
#include <cassert>
#include <assert.h>
#include <vector>
#include <string>
#include <map>
#include <queue>
#include <set>
#include <utility>
#include <numeric>
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <algorithm>
#include <memory>
#include <cstdlib>
//filesystem version 3 causes problems (and it's default as of boost 1.46)
#define BOOST_FILESYSTEM_VERSION 2
#include <boost/algorithm/string.hpp>
#include <boost/assert.hpp>
#include <boost/assign.hpp>
#include <boost/bind.hpp>
#include <boost/cstdint.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>
#include <boost/format.hpp>
#include <boost/function.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/logic/tribool.hpp>
#include <boost/program_options.hpp>
#include <boost/thread.hpp>
#include <boost/unordered_set.hpp>
#ifdef ANDROID
#include <android/log.h>
#endif
// Integral data types
typedef boost::uint64_t ui64; //unsigned int 64 bits (8 bytes)
typedef boost::uint32_t ui32; //unsigned int 32 bits (4 bytes)
typedef boost::uint16_t ui16; //unsigned int 16 bits (2 bytes)
typedef boost::uint8_t ui8; //unsigned int 8 bits (1 byte)
typedef boost::int64_t si64; //signed int 64 bits (8 bytes)
typedef boost::int32_t si32; //signed int 32 bits (4 bytes)
typedef boost::int16_t si16; //signed int 16 bits (2 bytes)
typedef boost::int8_t si8; //signed int 8 bits (1 byte)
// Import + Export macro declarations
#ifdef _WIN32
#define DLL_EXPORT __declspec(dllexport)
#else
#if defined(__GNUC__) && __GNUC__ >= 4
#define DLL_EXPORT __attribute__ ((visibility("default")))
#else
#define DLL_EXPORT
#endif
#endif
#ifdef _WIN32
#define DLL_IMPORT __declspec(dllimport)
#else
#if defined(__GNUC__) && __GNUC__ >= 4
#define DLL_IMPORT __attribute__ ((visibility("default")))
#else
#define DLL_IMPORT
#endif
#endif
#ifdef VCMI_DLL
#define DLL_LINKAGE DLL_EXPORT
#else
#define DLL_LINKAGE DLL_IMPORT
#endif
//a normal std::map with a const operator[] for sanity
template<typename KeyT, typename ValT>
class bmap : public std::map<KeyT, ValT>
{
public:
const ValT & operator[](KeyT key) const
{
return find(key)->second;
}
ValT & operator[](KeyT key)
{
return static_cast<std::map<KeyT, ValT> &>(*this)[key];
}
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<std::map<KeyT, ValT> &>(*this);
}
};
namespace vstd
{
//returns true if container c contains item i
template <typename Container, typename Item>
bool contains(const Container & c, const Item &i)
{
return std::find(c.begin(),c.end(),i) != c.end();
}
//returns true if map c contains item i
template <typename V, typename Item, typename Item2>
bool contains(const std::map<Item,V> & c, const Item2 &i)
{
return c.find(i)!=c.end();
}
//returns true if bmap c contains item i
template <typename V, typename Item, typename Item2>
bool contains(const bmap<Item,V> & c, const Item2 &i)
{
return c.find(i)!=c.end();
}
//returns true if unordered set c contains item i
template <typename Item>
bool contains(const boost::unordered_set<Item> & c, const Item &i)
{
return c.find(i)!=c.end();
}
//returns position of first element in vector c equal to s, if there is no such element, -1 is returned
template <typename T1, typename T2>
int find_pos(const std::vector<T1> & c, const T2 &s)
{
for(size_t i=0; i < c.size(); ++i)
if(c[i] == s)
return i;
return -1;
}
//Func(T1,T2) must say if these elements matches
template <typename T1, typename T2, typename Func>
int find_pos(const std::vector<T1> & c, const T2 &s, const Func &f)
{
for(size_t i=0; i < c.size(); ++i)
if(f(c[i],s))
return i;
return -1;
}
//returns iterator to the given element if present in container, end() if not
template <typename Container, typename Item>
typename Container::iterator find(Container & c, const Item &i)
{
return std::find(c.begin(),c.end(),i);
}
//returns const iterator to the given element if present in container, end() if not
template <typename Container, typename Item>
typename Container::const_iterator find(const Container & c, const Item &i)
{
return std::find(c.begin(),c.end(),i);
}
//removes element i from container c, returns false if c does not contain i
template <typename Container, typename Item>
typename Container::size_type operator-=(Container &c, const Item &i)
{
typename Container::iterator itr = find(c,i);
if(itr == c.end())
return false;
c.erase(itr);
return true;
}
//assigns greater of (a, b) to a and returns maximum of (a, b)
template <typename t1, typename t2>
t1 &amax(t1 &a, const t2 &b)
{
if(a >= b)
return a;
else
{
a = b;
return a;
}
}
//assigns smaller of (a, b) to a and returns minimum of (a, b)
template <typename t1, typename t2>
t1 &amin(t1 &a, const t2 &b)
{
if(a <= b)
return a;
else
{
a = b;
return a;
}
}
//makes a to fit the range <b, c>
template <typename t1, typename t2, typename t3>
t1 &abetween(t1 &a, const t2 &b, const t3 &c)
{
amax(a,b);
amin(a,c);
return a;
}
//checks if a is between b and c
template <typename t1, typename t2, typename t3>
bool isbetween(const t1 &a, const t2 &b, const t3 &c)
{
return a > b && a < c;
}
//checks if a is within b and c
template <typename t1, typename t2, typename t3>
bool iswithin(const t1 &a, const t2 &b, const t3 &c)
{
return a >= b && a <= c;
}
template <typename t1, typename t2>
struct assigner
{
public:
t1 &op1;
t2 op2;
assigner(t1 &a1, const t2 & a2)
:op1(a1), op2(a2)
{}
void operator()()
{
op1 = op2;
}
};
// Assigns value a2 to a1. The point of time of the real operation can be controlled
// with the () operator.
template <typename t1, typename t2>
assigner<t1,t2> assigno(t1 &a1, const t2 &a2)
{
return assigner<t1,t2>(a1,a2);
}
//deleted pointer and sets it to NULL
template <typename T>
void clear_pointer(T* &ptr)
{
delete ptr;
ptr = NULL;
}
}
using vstd::operator-=;
// can be used for counting arrays
template<typename T, size_t N> char (&_ArrayCountObj(const T (&)[N]))[N];
#define ARRAY_COUNT(arr) (sizeof(_ArrayCountObj(arr)))
//for explicit overrides
#ifdef _MSC_VER
#define OVERRIDE override
#else
#define OVERRIDE //is there any working counterpart?
#endif
//XXX pls dont - 'debug macros' are usually more trouble than it's worth
#define HANDLE_EXCEPTION \
catch (const std::exception& e) { \
tlog1 << e.what() << std::endl; \
throw; \
} \
catch (const std::exception * e) \
{ \
tlog1 << e->what()<< std::endl; \
throw; \
} \
catch (const std::string& e) { \
tlog1 << e << std::endl; \
throw; \
}
#define HANDLE_EXCEPTIONC(COMMAND) \
catch (const std::exception& e) { \
COMMAND; \
tlog1 << e.what() << std::endl; \
throw; \
} \
catch (const std::string &e) \
{ \
COMMAND; \
tlog1 << e << std::endl; \
throw; \
}
#include "../lib/CLogger.h"