1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-04-09 07:13:54 +02:00

Merge branch 'develop' into mutexRelax

This commit is contained in:
DjWarmonger 2015-10-24 18:30:43 +02:00
commit a6ea0981b6
105 changed files with 1747 additions and 1311 deletions

View File

@ -531,7 +531,7 @@ std::vector<BattleHex> CBattleAI::getTargetsToConsider( const CSpell *spell ) co
{
if(spell->getTargetType() == CSpell::NO_TARGET)
{
//Spell can be casted anywhere, all hexes are potentially considerable.
//Spell can be cast anywhere, all hexes are potentially considerable.
std::vector<BattleHex> ret;
for(int i = 0; i < GameConstants::BFIELD_SIZE; i++)

View File

@ -432,7 +432,7 @@ bool boundaryBetweenTwoPoints (int3 pos1, int3 pos2, CCallback * cbp) //determin
for (int y = yMin; y <= yMax; ++y)
{
int3 tile = int3(x, y, pos1.z); //use only on same level, ofc
if (abs(pos1.dist2d(tile) - pos2.dist2d(tile)) < 1.5)
if (std::abs(pos1.dist2d(tile) - pos2.dist2d(tile)) < 1.5)
{
if (!(cbp->isVisible(tile) && cbp->getTile(tile)->blocked)) //if there's invisible or unblocked tile between, it's good
return false;
@ -509,4 +509,4 @@ bool compareArtifacts(const CArtifactInstance *a1, const CArtifactInstance *a2)
return true;
else
return art1->price > art2->price;
}
}

View File

@ -119,34 +119,34 @@ public:
void unregisterAllInterfaces(); //stops delivering information about game events to player interfaces -> can be called ONLY after victory/loss
//commands
bool moveHero(const CGHeroInstance *h, int3 dst, bool transit = false); //dst must be free, neighbouring tile (this function can move hero only by one tile)
bool moveHero(const CGHeroInstance *h, int3 dst, bool transit = false) override; //dst must be free, neighbouring tile (this function can move hero only by one tile)
bool teleportHero(const CGHeroInstance *who, const CGTownInstance *where);
int selectionMade(int selection, QueryID queryID);
int swapCreatures(const CArmedInstance *s1, const CArmedInstance *s2, SlotID p1, SlotID p2);
int mergeOrSwapStacks(const CArmedInstance *s1, const CArmedInstance *s2, SlotID p1, SlotID p2); //first goes to the second
int mergeStacks(const CArmedInstance *s1, const CArmedInstance *s2, SlotID p1, SlotID p2); //first goes to the second
int splitStack(const CArmedInstance *s1, const CArmedInstance *s2, SlotID p1, SlotID p2, int val);
bool dismissHero(const CGHeroInstance * hero);
int selectionMade(int selection, QueryID queryID) override;
int swapCreatures(const CArmedInstance *s1, const CArmedInstance *s2, SlotID p1, SlotID p2) override;
int mergeOrSwapStacks(const CArmedInstance *s1, const CArmedInstance *s2, SlotID p1, SlotID p2) override; //first goes to the second
int mergeStacks(const CArmedInstance *s1, const CArmedInstance *s2, SlotID p1, SlotID p2) override; //first goes to the second
int splitStack(const CArmedInstance *s1, const CArmedInstance *s2, SlotID p1, SlotID p2, int val) override;
bool dismissHero(const CGHeroInstance * hero) override;
//bool swapArtifacts(const CGHeroInstance * hero1, ui16 pos1, const CGHeroInstance * hero2, ui16 pos2);
bool swapArtifacts(const ArtifactLocation &l1, const ArtifactLocation &l2);
bool swapArtifacts(const ArtifactLocation &l1, const ArtifactLocation &l2) override;
//bool moveArtifact(const CGHeroInstance * hero, ui16 src, const CStackInstance * stack, ui16 dest); // TODO: unify classes
//bool moveArtifact(const CStackInstance * stack, ui16 src , const CGHeroInstance * hero, ui16 dest); // TODO: unify classes
bool assembleArtifacts(const CGHeroInstance * hero, ArtifactPosition artifactSlot, bool assemble, ArtifactID assembleTo);
bool assembleArtifacts(const CGHeroInstance * hero, ArtifactPosition artifactSlot, bool assemble, ArtifactID assembleTo) override;
bool buildBuilding(const CGTownInstance *town, BuildingID buildingID) override;
void recruitCreatures(const CGDwelling * obj, const CArmedInstance * dst, CreatureID ID, ui32 amount, si32 level=-1);
bool dismissCreature(const CArmedInstance *obj, SlotID stackPos);
void recruitCreatures(const CGDwelling * obj, const CArmedInstance * dst, CreatureID ID, ui32 amount, si32 level=-1) override;
bool dismissCreature(const CArmedInstance *obj, SlotID stackPos) override;
bool upgradeCreature(const CArmedInstance *obj, SlotID stackPos, CreatureID newID=CreatureID::NONE) override;
void endTurn();
void swapGarrisonHero(const CGTownInstance *town);
void endTurn() override;
void swapGarrisonHero(const CGTownInstance *town) override;
void buyArtifact(const CGHeroInstance *hero, ArtifactID aid) override;
void trade(const CGObjectInstance *market, EMarketMode::EMarketMode mode, int id1, int id2, int val1, const CGHeroInstance *hero = nullptr);
void setFormation(const CGHeroInstance * hero, bool tight);
void recruitHero(const CGObjectInstance *townOrTavern, const CGHeroInstance *hero);
void save(const std::string &fname);
void sendMessage(const std::string &mess, const CGObjectInstance * currentObject = nullptr);
void buildBoat(const IShipyard *obj);
void dig(const CGObjectInstance *hero);
void castSpell(const CGHeroInstance *hero, SpellID spellID, const int3 &pos = int3(-1, -1, -1));
void trade(const CGObjectInstance *market, EMarketMode::EMarketMode mode, int id1, int id2, int val1, const CGHeroInstance *hero = nullptr) override;
void setFormation(const CGHeroInstance * hero, bool tight) override;
void recruitHero(const CGObjectInstance *townOrTavern, const CGHeroInstance *hero) override;
void save(const std::string &fname) override;
void sendMessage(const std::string &mess, const CGObjectInstance * currentObject = nullptr) override;
void buildBoat(const IShipyard *obj) override;
void dig(const CGObjectInstance *hero) override;
void castSpell(const CGHeroInstance *hero, SpellID spellID, const int3 &pos = int3(-1, -1, -1)) override;
//friends
friend class CClient;

View File

@ -115,7 +115,7 @@ endif()
set(SYSTEM_LIBS ${SYSTEM_LIBS} ${CMAKE_DL_LIBS})
set(FFmpeg_FIND_COMPONENTS AVFORMAT SWSCALE)
find_package(Boost 1.48.0 COMPONENTS filesystem locale program_options system thread REQUIRED)
find_package(Boost 1.48.0 COMPONENTS date_time filesystem locale program_options system thread REQUIRED)
find_package(ZLIB REQUIRED)
find_package(FFmpeg REQUIRED)
find_package(Minizip)
@ -150,7 +150,7 @@ endif()
if(ENABLE_TEST)
# find_package overwrites BOOST_* variables which are already set, so all components have to be included again
find_package(Boost 1.48.0 COMPONENTS program_options filesystem system thread locale unit_test_framework REQUIRED)
find_package(Boost 1.48.0 COMPONENTS date_time program_options filesystem system thread locale unit_test_framework REQUIRED)
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR NOT WIN32) #so far all *nix compilers support such parameters

View File

@ -3,7 +3,7 @@
ADVETURE AI:
* Fixed AI trying to go through underground rock
* Fixed several cases causing AI wandering aimlessly
* AI can again pick bets artifacts and exchange artifacts between heroes
* AI can again pick best artifacts and exchange artifacts between heroes
RANDOM MAP GENERATOR:
* Changed fractalization algorithm so it can create cycles

View File

@ -61,7 +61,7 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
# define VCMI_UNIX
# define VCMI_XDG
# define VCMI_FREEBSD
#elif defined(__GNU__) || defined(__gnu_hurd__) || (defined(__MACH__) && !defined(__APPLE))
#elif defined(__GNU__) || defined(__gnu_hurd__) || (defined(__MACH__) && !defined(__APPLE__))
# define VCMI_UNIX
# define VCMI_XDG
# define VCMI_HURD
@ -150,6 +150,7 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
#endif
#include <boost/logic/tribool.hpp>
#include <boost/optional.hpp>
#include <boost/optional/optional_io.hpp>
#include <boost/program_options.hpp>
#include <boost/range/adaptor/filtered.hpp>
#include <boost/range/adaptor/reversed.hpp>

View File

@ -102,7 +102,7 @@ if(APPLE)
cp -r ${CMAKE_HOME_DIRECTORY}/osx/vcmibuilder.app ${BUNDLE_PATH}/MacOS/vcmibuilder.app &&
# Copy frameworks
cp -r ${CMAKE_HOME_DIRECTORY}/${CMAKE_FRAMEWORK_PATH} ${BUNDLE_PATH}/Frameworks/ &&
sh -c 'cp -r ${CMAKE_HOME_DIRECTORY}/${CMAKE_FRAMEWORK_PATH} ${BUNDLE_PATH}/Frameworks/ || true' &&
# Copy vcmi data
mkdir -p ${BUNDLE_PATH}/Data &&
@ -110,7 +110,8 @@ if(APPLE)
mkdir -p ${BUNDLE_PATH}/Data/launcher &&
cp -r ${CMAKE_HOME_DIRECTORY}/config/ ${BUNDLE_PATH}/Data/config/ &&
cp -r ${CMAKE_HOME_DIRECTORY}/Mods/vcmi/ ${BUNDLE_PATH}/Data/Mods/vcmi/ &&
cp -r ${CMAKE_HOME_DIRECTORY}/Mods/WoG/ ${BUNDLE_PATH}/Data/Mods/WoG/ &&
sh -c 'cp -r ${CMAKE_HOME_DIRECTORY}/Mods/WoG/ ${BUNDLE_PATH}/Data/Mods/WoG/ || echo "Download WoG mod from http://wiki.vcmi.eu/index.php?title=Mod_list"' &&
sh -c 'cp -r ${CMAKE_HOME_DIRECTORY}/Mods/hota/ ${BUNDLE_PATH}/Data/Mods/hota/ || echo "Download HOTA mod from http://wiki.vcmi.eu/index.php?title=Mod_list"' &&
cp -r ${CMAKE_HOME_DIRECTORY}/launcher/icons/ ${BUNDLE_PATH}/Data/launcher/icons/)
add_custom_command(TARGET vcmiclient POST_BUILD COMMAND ${MakeVCMIBundle})

View File

@ -45,7 +45,7 @@ public:
CComponent *comp;
//blit component with image centered at this position
void showAll(SDL_Surface * to);
void showAll(SDL_Surface * to) override;
//ComponentResolved(); //c-tor
ComponentResolved(CComponent *Comp); //c-tor

View File

@ -52,10 +52,10 @@ private:
public:
CSoundHandler();
void init();
void release();
void init() override;
void release() override;
void setVolume(ui32 percent);
void setVolume(ui32 percent) override;
// Sounds
int playSound(soundBase::soundID soundID, int repeats=0);
@ -127,9 +127,9 @@ public:
/// add entry with URI musicURI in set. Track will have ID musicID
void addEntryToSet(std::string set, int musicID, std::string musicURI);
void init();
void release();
void setVolume(ui32 percent);
void init() override;
void release() override;
void setVolume(ui32 percent) override;
/// play track by URI, if loop = true music will be looped
void playMusic(std::string musicURI, bool loop);

View File

@ -772,7 +772,8 @@ BattleAction CPlayerInterface::activeStack(const CStack * stack) //called when i
{
THREAD_CREATED_BY_CLIENT;
logGlobal->traceStream() << "Awaiting command for " << stack->nodeName();
auto stackId = stack->ID;
auto stackName = stack->nodeName();
if(autofightingAI)
{
if(isAutoFightOn)
@ -806,17 +807,23 @@ BattleAction CPlayerInterface::activeStack(const CStack * stack) //called when i
while(!b->givenCommand->data)
{
b->givenCommand->cond.wait(lock);
if(!battleInt) //batle ended while we were waiting for movement (eg. because of spell)
if(!battleInt) //battle ended while we were waiting for movement (eg. because of spell)
throw boost::thread_interrupted(); //will shut the thread peacefully
}
//tidy up
BattleAction ret = *(b->givenCommand->data);
delete b->givenCommand->data;
b->givenCommand->data = nullptr;
//return command
logGlobal->traceStream() << "Giving command for " << stack->nodeName();
vstd::clear_pointer(b->givenCommand->data);
if(ret.actionType == Battle::CANCEL)
{
if(stackId != ret.stackNumber)
logGlobal->error("Not current active stack action canceled");
logGlobal->traceStream() << "Canceled command for " << stackName;
}
else
logGlobal->traceStream() << "Giving command for " << stackName;
return ret;
}

View File

@ -147,11 +147,11 @@ public:
void newStackInserted(const StackLocation &location, const CStackInstance &stack) override; //new stack inserted at given (previously empty position)
void stacksRebalanced(const StackLocation &src, const StackLocation &dst, TQuantity count) override; //moves creatures from src stack to dst slot, may be used for merging/splittint/moving stacks
void artifactPut(const ArtifactLocation &al);
void artifactRemoved(const ArtifactLocation &al);
void artifactMoved(const ArtifactLocation &src, const ArtifactLocation &dst);
void artifactAssembled(const ArtifactLocation &al);
void artifactDisassembled(const ArtifactLocation &al);
void artifactPut(const ArtifactLocation &al) override;
void artifactRemoved(const ArtifactLocation &al) override;
void artifactMoved(const ArtifactLocation &src, const ArtifactLocation &dst) override;
void artifactAssembled(const ArtifactLocation &al) override;
void artifactDisassembled(const ArtifactLocation &al) override;
void heroCreated(const CGHeroInstance* hero) override;
void heroGotLevel(const CGHeroInstance *hero, PrimarySkill::PrimarySkill pskill, std::vector<SecondarySkill> &skills, QueryID queryID) override;
@ -236,7 +236,7 @@ public:
void openTownWindow(const CGTownInstance * town); //shows townscreen
void openHeroWindow(const CGHeroInstance * hero); //shows hero window with given hero
void updateInfo(const CGObjectInstance * specific);
void init(shared_ptr<CCallback> CB);
void init(shared_ptr<CCallback> CB) override;
int3 repairScreenPos(int3 pos); //returns position closest to pos we can center screen on
// show dialogs

View File

@ -207,7 +207,7 @@ public:
template <typename T> class CApplyOnPG : public CBaseForPGApply
{
public:
void applyOnPG(CSelectionScreen *selScr, void *pack) const
void applyOnPG(CSelectionScreen *selScr, void *pack) const override
{
T *ptr = static_cast<T*>(pack);
ptr->apply(selScr);
@ -217,7 +217,7 @@ public:
template <> class CApplyOnPG<CPack> : public CBaseForPGApply
{
public:
void applyOnPG(CSelectionScreen *selScr, void *pack) const
void applyOnPG(CSelectionScreen *selScr, void *pack) const override
{
logGlobal->errorStream() << "Cannot apply on PG plain CPack!";
assert(0);

View File

@ -75,10 +75,10 @@ public:
};
CMenuScreen(const JsonNode& configNode);
void showAll(SDL_Surface * to);
void show(SDL_Surface * to);
void activate();
void deactivate();
void showAll(SDL_Surface * to) override;
void show(SDL_Surface * to) override;
void activate() override;
void deactivate() override;
void switchToTab(size_t index);
};
@ -100,10 +100,10 @@ class CreditsScreen : public CIntObject
public:
CreditsScreen();
void show(SDL_Surface * to);
void show(SDL_Surface * to) override;
void clickLeft(tribool down, bool previousState);
void clickRight(tribool down, bool previousState);
void clickLeft(tribool down, bool previousState) override;
void clickRight(tribool down, bool previousState) override;
};
/// Implementation of the chat box
@ -115,7 +115,7 @@ public:
CChatBox(const Rect &rect);
void keyPressed(const SDL_KeyboardEvent & key);
void keyPressed(const SDL_KeyboardEvent & key) override;
void addNewMessage(const std::string &text);
};
@ -136,8 +136,8 @@ public:
CDefHandler *sizes, *sFlags;
void changeSelection(const CMapInfo *to);
void showAll(SDL_Surface * to);
void clickRight(tribool down, bool previousState);
void showAll(SDL_Surface * to) override;
void clickRight(tribool down, bool previousState) override;
void showTeamsPopup();
void toggleChat();
void setChat(bool activateChat);
@ -184,10 +184,10 @@ public:
void selectFName(std::string fname);
const CMapInfo * getSelectedMapInfo() const;
void showAll(SDL_Surface * to);
void clickLeft(tribool down, bool previousState);
void keyPressed(const SDL_KeyboardEvent & key);
void onDoubleClick();
void showAll(SDL_Surface * to) override;
void clickLeft(tribool down, bool previousState) override;
void keyPressed(const SDL_KeyboardEvent & key) override;
void onDoubleClick() override;
SelectionTab(CMenuScreen::EState Type, const std::function<void(CMapInfo *)> &OnSelect, CMenuScreen::EMultiMode MultiPlayer = CMenuScreen::SINGLE_PLAYER);
~SelectionTab();
};
@ -235,7 +235,7 @@ public:
CLabel *subtitle;
SelectedBox(Point position, PlayerSettings & settings, SelType type);
void clickRight(tribool down, bool previousState);
void clickRight(tribool down, bool previousState) override;
void update();
};
@ -254,7 +254,7 @@ public:
PlayerOptionsEntry(OptionsTab *owner, PlayerSettings &S);
void selectButtons(); //hides unavailable buttons
void showAll(SDL_Surface * to);
void showAll(SDL_Surface * to) override;
void update();
};
@ -282,7 +282,7 @@ public:
void recreate();
OptionsTab();
~OptionsTab();
void showAll(SDL_Surface * to);
void showAll(SDL_Surface * to) override;
int nextAllowedHero(PlayerColor player, int min, int max, int incl, int dir );
@ -295,7 +295,7 @@ class CRandomMapTab : public CIntObject
public:
CRandomMapTab();
void showAll(SDL_Surface * to);
void showAll(SDL_Surface * to) override;
void updateMapInfo();
CFunctionList<void (const CMapInfo *)> & getMapInfoChanged();
const CMapInfo * getMapInfo() const;
@ -385,7 +385,7 @@ public:
void postRequest(ui8 what, ui8 dir) override;
void postChatMessage(const std::string &txt) override;
void propagateNames();
void showAll(SDL_Surface *to);
void showAll(SDL_Surface *to) override;
};
/// Save game screen
@ -454,8 +454,8 @@ class CPrologEpilogVideo : public CWindowObject
public:
CPrologEpilogVideo(CCampaignScenario::SScenarioPrologEpilog _spe, std::function<void()> callback);
void clickLeft(tribool down, bool previousState);
void show(SDL_Surface * to);
void clickLeft(tribool down, bool previousState) override;
void show(SDL_Surface * to) override;
};
/// Campaign screen where you can choose one out of three starting bonuses
@ -498,9 +498,9 @@ private:
CRegion(CBonusSelection * _owner, bool _accessible, bool _selectable, int _myNumber);
~CRegion();
void clickLeft(tribool down, bool previousState);
void clickRight(tribool down, bool previousState);
void show(SDL_Surface * to);
void clickLeft(tribool down, bool previousState) override;
void clickRight(tribool down, bool previousState) override;
void show(SDL_Surface * to) override;
};
void init();
@ -560,12 +560,12 @@ private:
std::string video; // the resource name of the video
std::string hoverText;
void clickLeft(tribool down, bool previousState);
void hover(bool on);
void clickLeft(tribool down, bool previousState) override;
void hover(bool on) override;
public:
CCampaignButton(const JsonNode &config );
void show(SDL_Surface * to);
void show(SDL_Surface * to) override;
};
CButton *back;
@ -578,7 +578,7 @@ public:
enum CampaignSet {ROE, AB, SOD, WOG};
CCampaignScreen(const JsonNode &config);
void showAll(SDL_Surface *to);
void showAll(SDL_Surface *to) override;
};
/// Manages the configuration of pregame GUI elements like campaign screen, main menu, loading screen,...
@ -629,7 +629,7 @@ public:
CLoadingScreen(std::function<void()> loader);
~CLoadingScreen();
void showAll(SDL_Surface *to);
void showAll(SDL_Surface *to) override;
};
/// Simple window to enter the server's address.

View File

@ -72,12 +72,12 @@ public:
template <typename T> class CApplyOnCL : public CBaseForCLApply
{
public:
void applyOnClAfter(CClient *cl, void *pack) const
void applyOnClAfter(CClient *cl, void *pack) const override
{
T *ptr = static_cast<T*>(pack);
ptr->applyCl(cl);
}
void applyOnClBefore(CClient *cl, void *pack) const
void applyOnClBefore(CClient *cl, void *pack) const override
{
T *ptr = static_cast<T*>(pack);
ptr->applyFirstCl(cl);
@ -87,12 +87,12 @@ public:
template <> class CApplyOnCL<CPack> : public CBaseForCLApply
{
public:
void applyOnClAfter(CClient *cl, void *pack) const
void applyOnClAfter(CClient *cl, void *pack) const override
{
logGlobal->errorStream() << "Cannot apply on CL plain CPack!";
assert(0);
}
void applyOnClBefore(CClient *cl, void *pack) const
void applyOnClBefore(CClient *cl, void *pack) const override
{
logGlobal->errorStream() << "Cannot apply on CL plain CPack!";
assert(0);
@ -140,9 +140,12 @@ void CClient::waitForMoveAndSend(PlayerColor color)
setThreadName("CClient::waitForMoveAndSend");
assert(vstd::contains(battleints, color));
BattleAction ba = battleints[color]->activeStack(gs->curB->battleGetStackByID(gs->curB->activeStack, false));
logNetwork->traceStream() << "Send battle action to server: " << ba;
MakeAction temp_action(ba);
sendRequest(&temp_action, color);
if(ba.actionType != Battle::CANCEL)
{
logNetwork->traceStream() << "Send battle action to server: " << ba;
MakeAction temp_action(ba);
sendRequest(&temp_action, color);
}
return;
}
catch(boost::thread_interrupted&)

View File

@ -189,7 +189,7 @@ public:
bool changeStackType(const StackLocation &sl, const CCreature *c) override {return false;};
bool changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue = false) override {return false;};
bool insertNewStack(const StackLocation &sl, const CCreature *c, TQuantity count) override {return false;};
bool eraseStack(const StackLocation &sl, bool forceRemoval = false){return false;};
bool eraseStack(const StackLocation &sl, bool forceRemoval = false) override{return false;};
bool swapStacks(const StackLocation &sl1, const StackLocation &sl2) override {return false;}
bool addToSlot(const StackLocation &sl, const CCreature *c, TQuantity count) override {return false;}
void tryJoiningArmy(const CArmedInstance *src, const CArmedInstance *dst, bool removeObjWhenFinished, bool allowMerging) override {}

View File

@ -750,7 +750,7 @@ void CatapultAttack::applyCl( CClient *cl )
BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(battleCatapultAttacked, *this);
}
void BattleStacksRemoved::applyCl( CClient *cl )
void BattleStacksRemoved::applyFirstCl(CClient * cl)
{
//inform interfaces about removed stacks
BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(battleStacksRemoved, *this);

View File

@ -782,7 +782,7 @@ bool CShootingAnimation::init()
spi.catapultInfo.reset(new CatapultProjectileInfo(Point(spi.x, spi.y), destPos));
double animSpeed = AnimationControls::getProjectileSpeed() / 10;
spi.lastStep = abs((destPos.x - spi.x) / animSpeed);
spi.lastStep = std::abs((destPos.x - spi.x) / animSpeed);
spi.dx = animSpeed;
spi.dy = 0;

View File

@ -59,8 +59,8 @@ protected:
const CStack *attackingStack;
int attackingStackPosBeforeReturn; //for stacks with return_after_strike feature
public:
void nextFrame();
void endAnim();
void nextFrame() override;
void endAnim() override;
bool checkInitialConditions();
CAttackAnimation(CBattleInterface *_owner, const CStack *attacker, BattleHex _dest, const CStack *defender);
@ -80,9 +80,9 @@ class CDefenceAnimation : public CBattleStackAnimation
float timeToWait; // for how long this animation should be paused
public:
bool init();
void nextFrame();
void endAnim();
bool init() override;
void nextFrame() override;
void endAnim() override;
CDefenceAnimation(StackAttackedInfo _attackedInfo, CBattleInterface * _owner);
virtual ~CDefenceAnimation(){};
@ -94,9 +94,9 @@ private:
int counter;
int howMany;
public:
bool init();
void nextFrame();
void endAnim();
bool init() override;
void nextFrame() override;
void endAnim() override;
CDummyAnimation(CBattleInterface * _owner, int howManyFrames);
virtual ~CDummyAnimation(){}
@ -106,8 +106,8 @@ public:
class CMeleeAttackAnimation : public CAttackAnimation
{
public:
bool init();
void endAnim();
bool init() override;
void endAnim() override;
CMeleeAttackAnimation(CBattleInterface * _owner, const CStack * attacker, BattleHex _dest, const CStack * _attacked);
virtual ~CMeleeAttackAnimation(){};
@ -133,9 +133,9 @@ private:
public:
BattleHex nextHex; // next hex, to which creature move right now
bool init();
void nextFrame();
void endAnim();
bool init() override;
void nextFrame() override;
void endAnim() override;
CMovementAnimation(CBattleInterface *_owner, const CStack *_stack, std::vector<BattleHex> _destTiles, int _distance);
virtual ~CMovementAnimation(){};
@ -147,8 +147,8 @@ class CMovementEndAnimation : public CBattleStackAnimation
private:
BattleHex destinationTile;
public:
bool init();
void endAnim();
bool init() override;
void endAnim() override;
CMovementEndAnimation(CBattleInterface * _owner, const CStack * _stack, BattleHex destTile);
virtual ~CMovementEndAnimation(){};
@ -158,8 +158,8 @@ public:
class CMovementStartAnimation : public CBattleStackAnimation
{
public:
bool init();
void endAnim();
bool init() override;
void endAnim() override;
CMovementStartAnimation(CBattleInterface * _owner, const CStack * _stack);
virtual ~CMovementStartAnimation(){};
@ -171,12 +171,12 @@ class CReverseAnimation : public CBattleStackAnimation
BattleHex hex;
public:
bool priority; //true - high, false - low
bool init();
bool init() override;
static void rotateStack(CBattleInterface * owner, const CStack * stack, BattleHex hex);
void setupSecondPart();
void endAnim();
void endAnim() override;
CReverseAnimation(CBattleInterface * _owner, const CStack * stack, BattleHex dest, bool _priority);
virtual ~CReverseAnimation(){};
@ -204,9 +204,9 @@ class CShootingAnimation : public CAttackAnimation
private:
int catapultDamage;
public:
bool init();
void nextFrame();
void endAnim();
bool init() override;
void nextFrame() override;
void endAnim() override;
//last two params only for catapult attacks
CShootingAnimation(CBattleInterface * _owner, const CStack * attacker, BattleHex _dest,
@ -225,9 +225,9 @@ private:
bool Vflip;
bool alignToBottom;
public:
bool init();
void nextFrame();
void endAnim();
bool init() override;
void nextFrame() override;
void endAnim() override;
CSpellEffectAnimation(CBattleInterface * _owner, ui32 _effect, BattleHex _destTile, int _dx = 0, int _dy = 0, bool _Vflip = false, bool _alignToBottom = false);
CSpellEffectAnimation(CBattleInterface * _owner, std::string _customAnim, int _x, int _y, int _dx = 0, int _dy = 0, bool _Vflip = false, bool _alignToBottom = false);

View File

@ -1005,11 +1005,22 @@ void CBattleInterface::newStack(const CStack * stack)
void CBattleInterface::stackRemoved(int stackID)
{
if(activeStack != nullptr)
{
if(activeStack->ID == stackID)
{
BattleAction * action = new BattleAction();
action->side = defendingHeroInstance ? (curInt->playerID == defendingHeroInstance->tempOwner) : false;
action->actionType = Battle::CANCEL;
action->stackNumber = activeStack->ID;
givenCommand->setn(action);
setActiveStack(nullptr);
}
}
delete creAnims[stackID];
creAnims.erase(stackID);
creDir.erase(stackID);
//FIXME: what if currently removed stack is active one (Sacrifice)?
redrawBackgroundWithHexes(activeStack);
queue->update();
}
@ -1091,10 +1102,6 @@ void CBattleInterface::newRoundFirst( int round )
void CBattleInterface::newRound(int number)
{
console->addText(CGI->generaltexth->allTexts[412]);
//unlock spellbook
//bSpell->block(!curInt->cb->battleCanCastSpell());
//don't unlock spellbook - this should be done when we have axctive creature
}
void CBattleInterface::giveCommand(Battle::ActionType action, BattleHex tile, ui32 stackID, si32 additional, si32 selected)
@ -1379,7 +1386,7 @@ void CBattleInterface::castThisSpell(SpellID spellID)
sp = spellID.toSpell();
spellSelMode = ANY_LOCATION;
const CSpell::TargetInfo ti = sp->getTargetInfo(castingHero->getSpellSchoolLevel(sp));
const CSpell::TargetInfo ti(sp, castingHero->getSpellSchoolLevel(sp));
if(ti.massive || ti.type == CSpell::NO_TARGET)
spellSelMode = NO_LOCATION;
@ -2103,9 +2110,9 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
{
ui8 skill = 0;
if (creatureCasting)
skill = sactive->getSpellSchoolLevel(SpellID(SpellID::TELEPORT).toSpell());
skill = sactive->getEffectLevel(SpellID(SpellID::TELEPORT).toSpell());
else
skill = getActiveHero()->getSpellSchoolLevel (CGI->spellh->objects[spellToCast->additionalInfo]);
skill = getActiveHero()->getEffectLevel(SpellID(SpellID::TELEPORT).toSpell());
//TODO: explicitely save power, skill
if (curInt->cb->battleCanTeleportTo(selectedStack, myNumber, skill))
legalAction = true;
@ -2470,11 +2477,19 @@ bool CBattleInterface::isCastingPossibleHere (const CStack * sactive, const CSta
if (sp)
{
if (creatureCasting)
isCastingPossible = (curInt->cb->battleCanCreatureCastThisSpell (sp, myNumber) == ESpellCastProblem::OK);
const ISpellCaster * caster = creatureCasting ? dynamic_cast<const ISpellCaster *>(sactive) : dynamic_cast<const ISpellCaster *>(curInt->cb->battleGetMyHero());
if(caster == nullptr)
{
isCastingPossible = false;//just in case
}
else
isCastingPossible = (curInt->cb->battleCanCastThisSpell (sp, myNumber) == ESpellCastProblem::OK);
{
const ECastingMode::ECastingMode mode = creatureCasting ? ECastingMode::CREATURE_ACTIVE_CASTING : ECastingMode::HERO_CASTING;
isCastingPossible = (curInt->cb->battleCanCastThisSpellHere(caster, sp, mode, myNumber) == ESpellCastProblem::OK);
}
}
else
isCastingPossible = false;
if(!myNumber.isAvailable() && !shere) //empty tile outside battlefield (or in the unavailable border column)
isCastingPossible = false;

View File

@ -291,14 +291,14 @@ public:
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 keyPressed(const SDL_KeyboardEvent & key);
void mouseMoved(const SDL_MouseMotionEvent &sEvent);
void clickRight(tribool down, bool previousState);
void activate() override;
void deactivate() override;
void keyPressed(const SDL_KeyboardEvent & key) override;
void mouseMoved(const SDL_MouseMotionEvent &sEvent) override;
void clickRight(tribool down, bool previousState) override;
void show(SDL_Surface *to);
void showAll(SDL_Surface *to);
void show(SDL_Surface *to) override;
void showAll(SDL_Surface *to) override;
//call-ins
void startAction(const BattleAction* action);

View File

@ -38,7 +38,7 @@ public:
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();
void showAll(SDL_Surface * to = 0);
void showAll(SDL_Surface * to = 0) override;
bool addText(const std::string &text); //adds text at the last position; returns false if failed (e.g. text longer than 70 characters)
void alterText(const std::string &text); //place string at alterTxt
void eraseText(ui32 pos); //erases added text at position pos
@ -60,9 +60,9 @@ public:
int nextPhase; //stage of animation to be set after current phase is fully displayed
int currentFrame, firstFrame, lastFrame; //frame of animation
ui8 flagAnim, animCount; //for flag animation
void show(SDL_Surface * to); //prints next frame of animation to to
void show(SDL_Surface * to) override; //prints next frame of animation to to
void setPhase(int newPhase); //sets phase of hero animation
void clickLeft(tribool down, bool previousState); //call-in
void clickLeft(tribool down, bool previousState) override; //call-in
CBattleHero(const std::string &defName, bool filpG, PlayerColor player, const CGHeroInstance *hero, const CBattleInterface *owner); //c-tor
~CBattleHero(); //d-tor
};
@ -96,8 +96,8 @@ public:
void bExitf(); //exit button callback
void activate();
void show(SDL_Surface * to = 0);
void activate() override;
void show(SDL_Surface * to = 0) override;
};
/// Class which stands for a single hex field on a battlefield
@ -114,10 +114,10 @@ public:
static Point getXYUnitAnim(BattleHex hexNum, const CStack * creature, CBattleInterface * cbi); //returns (x, y) of left top corner of animation
//for user interactions
void hover (bool on);
void mouseMoved (const SDL_MouseMotionEvent &sEvent);
void clickLeft(tribool down, bool previousState);
void clickRight(tribool down, bool previousState);
void hover (bool on) override;
void mouseMoved (const SDL_MouseMotionEvent &sEvent) override;
void clickLeft(tribool down, bool previousState) override;
void clickRight(tribool down, bool previousState) override;
CClickableHex();
};
@ -132,7 +132,7 @@ class CStackQueue : public CIntObject
const CStack *stack;
bool small;
void showAll(SDL_Surface * to);
void showAll(SDL_Surface * to) override;
void setStack(const CStack *nStack);
StackBox(bool small);
};
@ -150,6 +150,6 @@ public:
CStackQueue(bool Embedded, CBattleInterface * _owner);
~CStackQueue();
void update();
void showAll(SDL_Surface *to);
void showAll(SDL_Surface *to) override;
void blitBg(SDL_Surface * to);
};

View File

@ -98,10 +98,10 @@ public:
SDLImage(SDL_Surface * from, bool extraRef);
~SDLImage();
void draw(SDL_Surface *where, int posX=0, int posY=0, Rect *src=nullptr, ui8 alpha=255) const;
void playerColored(PlayerColor player);
int width() const;
int height() const;
void draw(SDL_Surface *where, int posX=0, int posY=0, Rect *src=nullptr, ui8 alpha=255) const override;
void playerColored(PlayerColor player) override;
int width() const override;
int height() const override;
friend class SDLImageLoader;
};
@ -144,10 +144,10 @@ public:
CompImage(SDL_Surface * surf);
~CompImage();
void draw(SDL_Surface *where, int posX=0, int posY=0, Rect *src=nullptr, ui8 alpha=255) const;
void playerColored(PlayerColor player);
int width() const;
int height() const;
void draw(SDL_Surface *where, int posX=0, int posY=0, Rect *src=nullptr, ui8 alpha=255) const override;
void playerColored(PlayerColor player) override;
int width() const override;
int height() const override;
friend class CompImageLoader;
};

View File

@ -157,15 +157,15 @@ public:
// activate or deactivate object. Inactive object won't receive any input events (keyboard\mouse)
// usually used automatically by parent
void activate();
void deactivate();
void activate() override;
void deactivate() override;
//called each frame to update screen
void show(SDL_Surface * to);
void show(SDL_Surface * to) override;
//called on complete redraw only
void showAll(SDL_Surface * to);
void showAll(SDL_Surface * to) override;
//request complete redraw of this object
void redraw();
void redraw() override;
enum EAlignment {TOPLEFT, CENTER, BOTTOMRIGHT};
@ -212,5 +212,5 @@ public:
CKeyShortcut();
CKeyShortcut(int key);
CKeyShortcut(std::set<int> Keys);
virtual void keyPressed(const SDL_KeyboardEvent & key); //call-in
virtual void keyPressed(const SDL_KeyboardEvent & key) override; //call-in
};

View File

@ -113,7 +113,7 @@ template<typename IntType>
std::string makeNumberShort(IntType number, IntType maxLength = 3) //the output is a string containing at most 5 characters [4 if positive] (eg. intead 10000 it gives 10k)
{
IntType max = pow(10, maxLength);
if (abs(number) < max)
if (std::abs(number) < max)
return boost::lexical_cast<std::string>(number);
std::string symbols = " kMGTPE";

View File

@ -312,7 +312,7 @@ class CMapHandler
void drawHeroFlag(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, SDL_Rect * destRect, bool moving) const override;
void drawObject(SDL_Surface * targetSurf, SDL_Surface * sourceSurf, SDL_Rect * sourceRect, bool moving) const override;
void drawFrame(SDL_Surface * targetSurf) const override {}
void drawOverlayEx(SDL_Surface * targetSurf);
void drawOverlayEx(SDL_Surface * targetSurf) override;
void init(const MapDrawingInfo * info) override;
SDL_Rect clip(SDL_Surface * targetSurf) const override;

View File

@ -37,9 +37,9 @@ protected:
CListItem(CList * parent);
~CListItem();
void clickRight(tribool down, bool previousState);
void clickLeft(tribool down, bool previousState);
void hover(bool on);
void clickRight(tribool down, bool previousState) override;
void clickLeft(tribool down, bool previousState) override;
void hover(bool on) override;
void onSelect(bool on);
/// create object with selection rectangle
@ -118,12 +118,12 @@ class CHeroList : public CList
CHeroItem(CHeroList *parent, const CGHeroInstance * hero);
CIntObject * genSelection();
CIntObject * genSelection() override;
void update();
void select(bool on);
void open();
void showTooltip();
std::string getHoverText();
void select(bool on) override;
void open() override;
void showTooltip() override;
std::string getHoverText() override;
};
CIntObject * createHeroItem(size_t index);
@ -152,12 +152,12 @@ class CTownList : public CList
CTownItem(CTownList *parent, const CGTownInstance * town);
CIntObject * genSelection();
CIntObject * genSelection() override;
void update();
void select(bool on);
void open();
void showTooltip();
std::string getHoverText();
void select(bool on) override;
void open() override;
void showTooltip() override;
std::string getHoverText() override;
};
CIntObject * createTownItem(size_t index);
@ -195,7 +195,7 @@ public:
CMinimapInstance(CMinimap * parent, int level);
~CMinimapInstance();
void showAll(SDL_Surface *to);
void showAll(SDL_Surface *to) override;
void tileToPixels (const int3 &tile, int &x, int &y,int toX = 0, int toY = 0);
void refreshTile(const int3 &pos);
@ -213,10 +213,10 @@ protected:
//to initialize colors
std::map<int, std::pair<SDL_Color, SDL_Color> > loadColors(std::string from);
void clickLeft(tribool down, bool previousState);
void clickRight(tribool down, bool previousState);
void hover (bool on);
void mouseMoved (const SDL_MouseMotionEvent & sEvent);
void clickLeft(tribool down, bool previousState) override;
void clickRight(tribool down, bool previousState) override;
void hover (bool on) override;
void mouseMoved (const SDL_MouseMotionEvent & sEvent) override;
void moveAdvMapSelection();
@ -232,7 +232,7 @@ public:
void setLevel(int level);
void setAIRadar(bool on);
void showAll(SDL_Surface * to);
void showAll(SDL_Surface * to) override;
void hideTile(const int3 &pos); //puts FoW
void showTile(const int3 &pos); //removes FoW
@ -256,7 +256,7 @@ class CInfoBar : public CIntObject
public:
CVisibleInfo(Point position);
void show(SDL_Surface *to);
void show(SDL_Surface *to) override;
//functions that must be called only once
void loadHero(const CGHeroInstance * hero);
@ -283,11 +283,11 @@ class CInfoBar : public CIntObject
//removes all information about current state, deactivates timer (if any)
void reset(EState newState);
void tick();
void tick() override;
void clickLeft(tribool down, bool previousState);
void clickRight(tribool down, bool previousState);
void hover(bool on);
void clickLeft(tribool down, bool previousState) override;
void clickRight(tribool down, bool previousState) override;
void hover(bool on) override;
public:
CInfoBar(const Rect & pos);
@ -331,7 +331,7 @@ public:
/// recolors all buttons to given player color
void setPlayerColor(const PlayerColor & clr);
void showAll(SDL_Surface * to);
void showAll(SDL_Surface * to) override;
};
/// specialized version of CAdvMapPanel that handles recolorable def-based pictures for world view info panel
@ -351,7 +351,7 @@ public:
void addChildIcon(std::pair<int, Point> data, const CDefHandler *def, int indexOffset);
/// recreates all pictures from given def to recolor them according to current player color
void recolorIcons(const PlayerColor &color, const CDefHandler *def, int indexOffset);
void showAll(SDL_Surface * to);
void showAll(SDL_Surface * to) override;
};
class CInGameConsole : public CIntObject
@ -365,9 +365,9 @@ private:
int maxDisplayedTexts; //hiw many texts can be displayed simultaneously
public:
std::string enteredText;
void show(SDL_Surface * to);
void show(SDL_Surface * to) override;
void print(const std::string &txt);
void keyPressed (const SDL_KeyboardEvent & key); //call-in
void keyPressed (const SDL_KeyboardEvent & key) override; //call-in
void textInputed(const SDL_TextInputEvent & event) override;
void textEdited(const SDL_TextEditingEvent & event) override;

View File

@ -215,7 +215,7 @@ public:
void clickLeft(tribool down, bool previousState) override;
void clickRight(tribool down, bool previousState) override;
void wheelScrolled(bool down, bool in);
void wheelScrolled(bool down, bool in) override;
};
/// A typical slider which can be orientated horizontally/vertically.
@ -264,11 +264,11 @@ public:
void addCallback(std::function<void(int)> callback);
void keyPressed(const SDL_KeyboardEvent & key);
void wheelScrolled(bool down, bool in);
void clickLeft(tribool down, bool previousState);
void mouseMoved (const SDL_MouseMotionEvent & sEvent);
void showAll(SDL_Surface * to);
void keyPressed(const SDL_KeyboardEvent & key) override;
void wheelScrolled(bool down, bool in) override;
void clickLeft(tribool down, bool previousState) override;
void mouseMoved (const SDL_MouseMotionEvent & sEvent) override;
void showAll(SDL_Surface * to) override;
/// @param position coordinates of slider
/// @param length length of slider ribbon, including left/right buttons

View File

@ -35,10 +35,10 @@ class CWindowWithArtifacts : public CArtifactHolder
public:
std::vector<CArtifactsOfHero *> artSets;
void artifactRemoved(const ArtifactLocation &artLoc);
void artifactMoved(const ArtifactLocation &artLoc, const ArtifactLocation &destLoc);
void artifactDisassembled(const ArtifactLocation &artLoc);
void artifactAssembled(const ArtifactLocation &artLoc);
void artifactRemoved(const ArtifactLocation &artLoc) override;
void artifactMoved(const ArtifactLocation &artLoc, const ArtifactLocation &destLoc) override;
void artifactDisassembled(const ArtifactLocation &artLoc) override;
void artifactAssembled(const ArtifactLocation &artLoc) override;
};
/// Artifacts can be placed there. Gets shown at the hero window
@ -65,11 +65,11 @@ public:
const CArtifactInstance * ourArt; // should be changed only with setArtifact()
CArtPlace(Point position, const CArtifactInstance * Art = nullptr); //c-tor
void clickLeft(tribool down, bool previousState);
void clickRight(tribool down, bool previousState);
void clickLeft(tribool down, bool previousState) override;
void clickRight(tribool down, bool previousState) override;
void select ();
void deselect ();
void showAll(SDL_Surface * to);
void showAll(SDL_Surface * to) override;
bool fitsHere (const CArtifactInstance * art) const; //returns true if given artifact can be placed here
void setMeAsDest(bool backpackAsVoid = true);

View File

@ -57,7 +57,7 @@ public:
CComponent(Etype Type, int Subtype, int Val = 0, ESize imageSize=large);//c-tor
CComponent(const Component &c, ESize imageSize=large); //c-tor
void clickRight(tribool down, bool previousState); //call-in
void clickRight(tribool down, bool previousState) override; //call-in
};
/// component that can be selected or deselected
@ -68,10 +68,10 @@ public:
bool selected; //if true, this component is selected
std::function<void()> onSelect; //function called on selection change
void showAll(SDL_Surface * to);
void showAll(SDL_Surface * to) override;
void select(bool on);
void clickLeft(tribool down, bool previousState); //call-in
void clickLeft(tribool down, bool previousState) override; //call-in
CSelectableComponent(Etype Type, int Sub, int Val, ESize imageSize=large, std::function<void()> OnSelect = nullptr); //c-tor
CSelectableComponent(const Component &c, std::function<void()> OnSelect = nullptr); //c-tor
};

View File

@ -293,27 +293,30 @@ void CGarrisonSlot::clickLeft(tribool down, bool previousState)
redraw();
refr = true;
}
// we want to split
else if( (owner->getSplittingMode() || LOCPLINT->shiftPressed())
&& (!creature || creature == selection->creature) )
refr = split();
// swap
else if(creature != selection->creature)
{
const CArmedInstance * selectedObj = owner->armedObjs[selection->upg];
if (!creature && selectedObj->stacksCount() == 1)
LOCPLINT->cb->splitStack(selectedObj, owner->armedObjs[upg], selection->ID, ID, selection->myStack->count - 1);
else
LOCPLINT->cb->swapCreatures(owner->armedObjs[upg], owner->armedObjs[selection->upg], ID, selection->ID);
}
// merge
else
{
const CArmedInstance * selectedObj = owner->armedObjs[selection->upg];
if (selectedObj->stacksCount() == 1)
LOCPLINT->cb->splitStack(owner->armedObjs[upg], selectedObj, selection->ID, ID, 1);
else
LOCPLINT->cb->mergeStacks(owner->armedObjs[selection->upg], owner->armedObjs[upg], selection->ID, ID);
bool lastHeroStackSelected = false;
if(selectedObj->stacksCount() == 1
&& owner->getSelection()->upg != upg
&& dynamic_cast<const CGHeroInstance*>(selectedObj))
{
lastHeroStackSelected = true;
}
if((owner->getSplittingMode() || LOCPLINT->shiftPressed()) // split window
&& (!creature || creature == selection->creature))
{
refr = split();
}
else if(!creature && lastHeroStackSelected) // split all except last creature
LOCPLINT->cb->splitStack(selectedObj, owner->armedObjs[upg], selection->ID, ID, selection->myStack->count - 1);
else if(creature != selection->creature) // swap
LOCPLINT->cb->swapCreatures(owner->armedObjs[upg], selectedObj, ID, selection->ID);
else if(lastHeroStackSelected) // merge last stack to other hero stack
refr = split();
else // merge
LOCPLINT->cb->mergeStacks(selectedObj, owner->armedObjs[upg], selection->ID, ID);
}
if(refr)
{

View File

@ -47,12 +47,12 @@ class CGarrisonSlot : public CIntObject
void setHighlight(bool on);
public:
virtual void hover (bool on); //call-in
virtual void hover (bool on) override; //call-in
const CArmedInstance * getObj() const;
bool our() const;
bool ally() const;
void clickRight(tribool down, bool previousState);
void clickLeft(tribool down, bool previousState);
void clickRight(tribool down, bool previousState) override;
void clickLeft(tribool down, bool previousState) override;
void update();
CGarrisonSlot(CGarrisonInt *Owner, int x, int y, SlotID IID, EGarrisonType Upg=EGarrisonType::UP, const CStackInstance * Creature=nullptr);
@ -132,7 +132,7 @@ class CWindowWithGarrison : public virtual CGarrisonHolder
{
public:
CGarrisonInt *garr;
virtual void updateGarrisons();
virtual void updateGarrisons() override;
};
/// Garrison window where you can take creatures out of the hero to place it on the garrison

View File

@ -49,8 +49,8 @@ public:
void scaleTo(Point size);
void createSimpleRect(const Rect &r, bool screenFormat, ui32 color);
void show(SDL_Surface * to);
void showAll(SDL_Surface * to);
void show(SDL_Surface * to) override;
void showAll(SDL_Surface * to) override;
void convertToScreenBPP();
void colorizeAndConvert(PlayerColor player);
void colorize(PlayerColor player);
@ -64,7 +64,7 @@ class CFilledTexture : CIntObject
public:
CFilledTexture(std::string imageName, Rect position);
~CFilledTexture();
void showAll(SDL_Surface *to);
void showAll(SDL_Surface *to) override;
};
/// Class for displaying one image from animation
@ -94,7 +94,7 @@ public:
//makes image player-colored
void playerColored(PlayerColor player);
void showAll(SDL_Surface * to);
void showAll(SDL_Surface * to) override;
};
/// Base class for displaying animation, used as superclass for different animations
@ -155,8 +155,8 @@ public:
virtual void reset();
//show current frame and increase counter
void show(SDL_Surface * to);
void showAll(SDL_Surface * to);
void show(SDL_Surface * to) override;
void showAll(SDL_Surface * to) override;
};
/// Creature-dependend animations like attacking, moving,...
@ -210,7 +210,7 @@ private:
public:
//change anim to next if queue is not empty, call callback othervice
void reset();
void reset() override;
//add sequence to the end of queue
void addLast(EAnimType newType);

View File

@ -28,7 +28,7 @@ class CHoverableArea: public virtual CIntObject
public:
std::string hoverText;
virtual void hover (bool on);
virtual void hover (bool on) override;
CHoverableArea();
virtual ~CHoverableArea();
@ -45,8 +45,8 @@ public:
virtual ~LRClickableAreaWText();
void init();
virtual void clickLeft(tribool down, bool previousState);
virtual void clickRight(tribool down, bool previousState);
virtual void clickLeft(tribool down, bool previousState) override;
virtual void clickRight(tribool down, bool previousState) override;
};
/// base class for hero/town/garrison tooltips
@ -88,7 +88,7 @@ private:
CCreatureAnim *anim; //displayed animation
CLabel * amount;
void show(SDL_Surface *to);
void show(SDL_Surface *to) override;
public:
CCreaturePic(int x, int y, const CCreature *cre, bool Big=true, bool Animated=true); //c-tor
@ -100,8 +100,8 @@ class CMinorResDataBar : public CIntObject
{
public:
SDL_Surface *bg; //background bitmap
void show(SDL_Surface * to);
void showAll(SDL_Surface * to);
void show(SDL_Surface * to) override;
void showAll(SDL_Surface * to) override;
CMinorResDataBar(); //c-tor
~CMinorResDataBar(); //d-tor
};
@ -114,9 +114,9 @@ public:
CHeroArea(int x, int y, const CGHeroInstance * _hero);
void clickLeft(tribool down, bool previousState);
void clickRight(tribool down, bool previousState);
void hover(bool on);
void clickLeft(tribool down, bool previousState) override;
void clickRight(tribool down, bool previousState) override;
void hover(bool on) override;
};
/// Can interact on left and right mouse clicks
@ -125,8 +125,8 @@ class LRClickableAreaWTextComp: public LRClickableAreaWText
public:
int baseType;
int bonusValue, type;
virtual void clickLeft(tribool down, bool previousState);
virtual void clickRight(tribool down, bool previousState);
virtual void clickLeft(tribool down, bool previousState) override;
virtual void clickRight(tribool down, bool previousState) override;
LRClickableAreaWTextComp(const Rect &Pos = Rect(0,0,0,0), int BaseType = -1);
CComponent * createComponent() const;
@ -137,8 +137,8 @@ class LRClickableAreaOpenTown: public LRClickableAreaWTextComp
{
public:
const CGTownInstance * town;
void clickLeft(tribool down, bool previousState);
void clickRight(tribool down, bool previousState);
void clickLeft(tribool down, bool previousState) override;
void clickRight(tribool down, bool previousState) override;
LRClickableAreaOpenTown();
};

View File

@ -52,7 +52,7 @@ public:
CLabel(int x=0, int y=0, EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT,
const SDL_Color &Color = Colors::WHITE, const std::string &Text = "");
void showAll(SDL_Surface * to); //shows statusbar (with current text)
void showAll(SDL_Surface * to) override; //shows statusbar (with current text)
};
/// Small helper class to manage group of similar labels
@ -85,8 +85,8 @@ public:
CMultiLineLabel(Rect position, EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT, const SDL_Color &Color = Colors::WHITE, const std::string &Text = "");
void setText(const std::string &Txt);
void showAll(SDL_Surface * to);
void setText(const std::string &Txt) override;
void showAll(SDL_Surface * to) override;
void setVisibleSize(Rect visibleSize);
// scrolls text visible in widget. Positive value will move text up
@ -125,7 +125,7 @@ public:
void clear();//clears statusbar and refreshes
void setText(const std::string & Text) override; //prints text and refreshes statusbar
void show(SDL_Surface * to); //shows statusbar (with current text)
void show(SDL_Surface * to) override; //shows statusbar (with current text)
CGStatusBar(CPicture *BG, EFonts Font = FONT_SMALL, EAlignment Align = CENTER, const SDL_Color &Color = Colors::WHITE); //given CPicture will be captured by created sbar and it's pos will be used as pos for sbar
CGStatusBar(int x, int y, std::string name, int maxw=-1);

View File

@ -65,13 +65,13 @@ public:
CTerrainRect();
virtual ~CTerrainRect();
CGPath * currentPath;
void deactivate();
void clickLeft(tribool down, bool previousState);
void clickRight(tribool down, bool previousState);
void hover(bool on);
void mouseMoved (const SDL_MouseMotionEvent & sEvent);
void show(SDL_Surface * to);
void showAll(SDL_Surface * to);
void deactivate() override;
void clickLeft(tribool down, bool previousState) override;
void clickRight(tribool down, bool previousState) override;
void hover(bool on) override;
void mouseMoved (const SDL_MouseMotionEvent & sEvent) override;
void show(SDL_Surface * to) override;
void showAll(SDL_Surface * to) override;
void showAnim(SDL_Surface * to);
void showPath(const SDL_Rect * extRect, SDL_Surface * to);
int3 whichTileIsIt(const int & x, const int & y); //x,y are cursor position
@ -92,14 +92,14 @@ public:
std::vector<std::pair<int,int> > txtpos;
std::string datetext;
void clickRight(tribool down, bool previousState);
void clickRight(tribool down, bool previousState) override;
CResDataBar();
CResDataBar(const std::string &defname, int x, int y, int offx, int offy, int resdist, int datedist);
~CResDataBar();
void draw(SDL_Surface * to);
void show(SDL_Surface * to);
void showAll(SDL_Surface * to);
void show(SDL_Surface * to) override;
void showAll(SDL_Surface * to) override;
};
/// That's a huge class which handles general adventure map actions and
@ -197,11 +197,11 @@ public:
void fnextHero();
void fendTurn();
void activate();
void deactivate();
void activate() override;
void deactivate() override;
void show(SDL_Surface * to); //redraws terrain
void showAll(SDL_Surface * to); //shows and activates adv. map interface
void show(SDL_Surface * to) override; //redraws terrain
void showAll(SDL_Surface * to) override; //shows and activates adv. map interface
void select(const CArmedInstance *sel, bool centerView = true);
void selectionChanged();
@ -209,8 +209,8 @@ public:
void centerOn(const CGObjectInstance *obj, bool fade = false);
int3 verifyPos(int3 ver);
void handleRightClick(std::string text, tribool down);
void keyPressed(const SDL_KeyboardEvent & key);
void mouseMoved (const SDL_MouseMotionEvent & sEvent);
void keyPressed(const SDL_KeyboardEvent & key) override;
void mouseMoved (const SDL_MouseMotionEvent & sEvent) override;
bool isActive();
bool isHeroSleeping(const CGHeroInstance *hero);

View File

@ -768,7 +768,7 @@ void CCastleBuildings::enterCastleGate()
return;//only visiting hero can use castle gates
}
std::vector <int> availableTowns;
std::vector <const CGTownInstance*> Towns = LOCPLINT->cb->getTownsInfo(false);
std::vector <const CGTownInstance*> Towns = LOCPLINT->cb->getTownsInfo(true);
for(auto & Town : Towns)
{
const CGTownInstance *t = Town;

View File

@ -51,12 +51,12 @@ public:
CBuildingRect(CCastleBuildings * Par, const CGTownInstance *Town, const CStructure *Str); //c-tor
~CBuildingRect(); //d-tor
bool operator<(const CBuildingRect & p2) const;
void hover(bool on);
void clickLeft(tribool down, bool previousState);
void clickRight(tribool down, bool previousState);
void mouseMoved (const SDL_MouseMotionEvent & sEvent);
void show(SDL_Surface * to);
void showAll(SDL_Surface * to);
void hover(bool on) override;
void clickLeft(tribool down, bool previousState) override;
void clickRight(tribool down, bool previousState) override;
void mouseMoved (const SDL_MouseMotionEvent & sEvent) override;
void show(SDL_Surface * to) override;
void showAll(SDL_Surface * to) override;
};
/// Dwelling info box - right-click screen for dwellings
@ -88,10 +88,10 @@ public:
void setHighlight(bool on);
void set(const CGHeroInstance *newHero);
void hover (bool on);
void clickLeft(tribool down, bool previousState);
void clickRight(tribool down, bool previousState);
void deactivate();
void hover (bool on) override;
void clickLeft(tribool down, bool previousState) override;
void clickRight(tribool down, bool previousState) override;
void deactivate() override;
CHeroGSlot(int x, int y, int updown, const CGHeroInstance *h, HeroSlots * Owner); //c-tor
~CHeroGSlot(); //d-tor
};
@ -150,8 +150,8 @@ public:
void addBuilding(BuildingID building);
void removeBuilding(BuildingID building);//FIXME: not tested!!!
void show(SDL_Surface * to);
void showAll(SDL_Surface * to);
void show(SDL_Surface * to) override;
void showAll(SDL_Surface * to) override;
};
/// Creature info window
@ -172,9 +172,9 @@ public:
CCreaInfo(Point position, const CGTownInstance *Town, int Level, bool compact=false, bool showAvailable=false);
void update();
void hover(bool on);
void clickLeft(tribool down, bool previousState);
void clickRight(tribool down, bool previousState);
void hover(bool on) override;
void clickLeft(tribool down, bool previousState) override;
void clickRight(tribool down, bool previousState) override;
};
/// Town hall and fort icons for town screen
@ -187,8 +187,8 @@ public:
//if (townHall) hall-capital else fort - castle
CTownInfo(int posX, int posY, const CGTownInstance* town, bool townHall);
void hover(bool on);
void clickRight(tribool down, bool previousState);
void hover(bool on) override;
void clickRight(tribool down, bool previousState) override;
};
/// Class which manages the castle window
@ -226,7 +226,7 @@ public:
void castleTeleport(int where);
void townChange();
void keyPressed(const SDL_KeyboardEvent & key);
void keyPressed(const SDL_KeyboardEvent & key) override;
void close();
void addBuilding(BuildingID bid);
void removeBuilding(BuildingID bid);
@ -251,9 +251,9 @@ class CHallInterface : public CWindowObject
public:
CBuildingBox(int x, int y, const CGTownInstance * Town, const CBuilding * Building);
void hover(bool on);
void clickLeft(tribool down, bool previousState);
void clickRight(tribool down, bool previousState);
void hover(bool on) override;
void clickLeft(tribool down, bool previousState) override;
void clickRight(tribool down, bool previousState) override;
};
const CGTownInstance * town;
@ -294,7 +294,7 @@ class LabeledValue : public CIntObject
public:
LabeledValue(Rect size, std::string name, std::string descr, int min, int max);
LabeledValue(Rect size, std::string name, std::string descr, int val);
void hover(bool on);
void hover(bool on) override;
};
/// The fort screen where you can afford units
@ -321,9 +321,9 @@ class CFortScreen : public CWindowObject
RecruitArea(int posX, int posY, const CGTownInstance *town, int level);
void creaturesChanged();
void hover(bool on);
void clickLeft(tribool down, bool previousState);
void clickRight(tribool down, bool previousState);
void hover(bool on) override;
void clickLeft(tribool down, bool previousState) override;
void clickRight(tribool down, bool previousState) override;
};
CLabel *title;
std::vector<RecruitArea*> recAreas;
@ -349,9 +349,9 @@ class CMageGuildScreen : public CWindowObject
public:
Scroll(Point position, const CSpell *Spell);
void clickLeft(tribool down, bool previousState);
void clickRight(tribool down, bool previousState);
void hover(bool on);
void clickLeft(tribool down, bool previousState) override;
void clickRight(tribool down, bool previousState) override;
void hover(bool on) override;
};
CPicture *window;
CButton *exit;

View File

@ -35,7 +35,7 @@ class CHeroSwitcher : public CIntObject
const CGHeroInstance * hero;
CAnimImage *image;
public:
virtual void clickLeft(tribool down, bool previousState);
virtual void clickLeft(tribool down, bool previousState) override;
CHeroSwitcher(Point pos, const CGHeroInstance * hero);
};
@ -85,7 +85,7 @@ public:
CHeroWindow(const CGHeroInstance *hero); //c-tor
void update(const CGHeroInstance * hero, bool redrawNeeded = false); //sets main displayed hero
void showAll(SDL_Surface * to);
void showAll(SDL_Surface * to) override;
void dismissCurrent(); //dissmissed currently displayed hero (curHero)
void questlog(); //show quest log in hero window

View File

@ -74,8 +74,8 @@ public:
InfoBox(Point position, InfoPos Pos, InfoSize Size, IInfoBoxData *Data);
~InfoBox();
void clickRight(tribool down, bool previousState);
void clickLeft(tribool down, bool previousState);
void clickRight(tribool down, bool previousState) override;
void clickLeft(tribool down, bool previousState) override;
//Update object if data may have changed
//void update();
@ -121,13 +121,13 @@ protected:
public:
InfoBoxAbstractHeroData(InfoType Type);
std::string getValueText();
std::string getNameText();
std::string getImageName(InfoBox::InfoSize size);
std::string getHoverText();
size_t getImageIndex();
std::string getValueText() override;
std::string getNameText() override;
std::string getImageName(InfoBox::InfoSize size) override;
std::string getHoverText() override;
size_t getImageIndex() override;
bool prepareMessage(std::string &text, CComponent **comp);
bool prepareMessage(std::string &text, CComponent **comp) override;
};
class InfoBoxHeroData : public InfoBoxAbstractHeroData
@ -135,17 +135,17 @@ class InfoBoxHeroData : public InfoBoxAbstractHeroData
const CGHeroInstance * hero;
int index;//index of data in hero (0-7 for sec. skill, 0-3 for pr. skill)
int getSubID();
si64 getValue();
int getSubID() override;
si64 getValue() override;
public:
InfoBoxHeroData(InfoType Type, const CGHeroInstance *Hero, int Index=0);
//To get a bit different texts for hero window
std::string getHoverText();
std::string getValueText();
std::string getHoverText() override;
std::string getValueText() override;
bool prepareMessage(std::string &text, CComponent **comp);
bool prepareMessage(std::string &text, CComponent **comp) override;
};
class InfoBoxCustomHeroData : public InfoBoxAbstractHeroData
@ -153,8 +153,8 @@ class InfoBoxCustomHeroData : public InfoBoxAbstractHeroData
int subID;//subID of data (0=attack...)
si64 value;//actual value of data, 64-bit to fit experience and negative values
int getSubID();
si64 getValue();
int getSubID() override;
si64 getValue() override;
public:
InfoBoxCustomHeroData(InfoType Type, int subID, si64 value);
@ -171,13 +171,13 @@ public:
InfoBoxCustom(std::string ValueText, std::string NameText, std::string ImageName, size_t ImageIndex, std::string HoverText="");
std::string getValueText();
std::string getNameText();
std::string getImageName(InfoBox::InfoSize size);
std::string getHoverText();
size_t getImageIndex();
std::string getValueText() override;
std::string getNameText() override;
std::string getImageName(InfoBox::InfoSize size) override;
std::string getHoverText() override;
size_t getImageIndex() override;
bool prepareMessage(std::string &text, CComponent **comp);
bool prepareMessage(std::string &text, CComponent **comp) override;
};
//TODO!!!
@ -191,11 +191,11 @@ public:
InfoBoxTownData(InfoType Type, const CGTownInstance * Town, int Index);
InfoBoxTownData(InfoType Type, int SubID, int Value);
std::string getValueText();
std::string getNameText();
std::string getImageName(InfoBox::InfoSize size);
std::string getHoverText();
size_t getImageIndex();
std::string getValueText() override;
std::string getNameText() override;
std::string getImageName(InfoBox::InfoSize size) override;
std::string getHoverText() override;
size_t getImageIndex() override;
};
////////////////////////////////////////////////////////////////////////////////
@ -250,11 +250,11 @@ public:
CKingdomInterface();
void townChanged(const CGTownInstance *town);
void updateGarrisons();
void artifactRemoved(const ArtifactLocation &artLoc);
void artifactMoved(const ArtifactLocation &artLoc, const ArtifactLocation &destLoc);
void artifactDisassembled(const ArtifactLocation &artLoc);
void artifactAssembled(const ArtifactLocation &artLoc);
void updateGarrisons() override;
void artifactRemoved(const ArtifactLocation &artLoc) override;
void artifactMoved(const ArtifactLocation &artLoc, const ArtifactLocation &destLoc) override;
void artifactDisassembled(const ArtifactLocation &artLoc) override;
void artifactAssembled(const ArtifactLocation &artLoc) override;
};
/// List item with town
@ -277,7 +277,7 @@ public:
CTownItem(const CGTownInstance* town);
void updateGarrisons();
void updateGarrisons() override;
void update();
};
@ -325,7 +325,7 @@ private:
public:
CKingdHeroList(size_t maxSize);
void updateGarrisons();
void updateGarrisons() override;
};
/// Tab with all town-specific data
@ -344,5 +344,5 @@ public:
CKingdTownList(size_t maxSize);
void townChanged(const CGTownInstance *town);
void updateGarrisons();
void updateGarrisons() override;
};

View File

@ -41,8 +41,8 @@ public:
CQuestLabel (Rect position, EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT, const SDL_Color &Color = Colors::WHITE, const std::string &Text = "")
: CMultiLineLabel (position, FONT_SMALL, TOPLEFT, Colors::WHITE, Text){};
void clickLeft(tribool down, bool previousState);
void showAll(SDL_Surface * to);
void clickLeft(tribool down, bool previousState) override;
void showAll(SDL_Surface * to) override;
};
class CQuestIcon : public CAnimImage
@ -52,17 +52,17 @@ public:
CQuestIcon (const std::string &defname, int index, int x=0, int y=0);
void clickLeft(tribool down, bool previousState);
void showAll(SDL_Surface * to);
void clickLeft(tribool down, bool previousState) override;
void showAll(SDL_Surface * to) override;
};
class CQuestMinimap : public CMinimap
{
std::vector <shared_ptr<CQuestIcon>> icons;
void clickLeft(tribool down, bool previousState){}; //minimap ignores clicking on its surface
void clickLeft(tribool down, bool previousState) override{}; //minimap ignores clicking on its surface
void iconClicked();
void mouseMoved (const SDL_MouseMotionEvent & sEvent){};
void mouseMoved (const SDL_MouseMotionEvent & sEvent) override{};
public:
@ -73,7 +73,7 @@ public:
void update();
void addQuestMarks (const QuestInfo * q);
void showAll(SDL_Surface * to);
void showAll(SDL_Surface * to) override;
};
class CQuestLog : public CWindowObject
@ -106,5 +106,5 @@ public:
void recreateLabelList();
void recreateQuestList (int pos);
void toggleComplete(bool on);
void showAll (SDL_Surface * to);
void showAll (SDL_Surface * to) override;
};

View File

@ -50,10 +50,10 @@ public:
void showAllAt(const Point &dstPos, const std::string &customSub, SDL_Surface * to);
void clickRight(tribool down, bool previousState);
void hover (bool on);
void showAll(SDL_Surface * to);
void clickLeft(tribool down, bool previousState);
void clickRight(tribool down, bool previousState) override;
void hover (bool on) override;
void showAll(SDL_Surface * to) override;
void clickLeft(tribool down, bool previousState) override;
std::string getName(int number = -1) const;
CTradeableItem(Point pos, EType Type, int ID, bool Left, int Serial);
};
@ -74,7 +74,7 @@ public:
CTradeWindow(std::string bgName, const IMarket *Market, const CGHeroInstance *Hero, EMarketMode::EMarketMode Mode); //c
void showAll(SDL_Surface * to);
void showAll(SDL_Surface * to) override;
void initSubs(bool Left);
void initTypes();
@ -109,19 +109,19 @@ public:
void setMax();
void sliderMoved(int to);
void makeDeal();
void selectionChanged(bool side); //true == left
void selectionChanged(bool side) override; //true == left
CMarketplaceWindow(const IMarket *Market, const CGHeroInstance *Hero = nullptr, EMarketMode::EMarketMode Mode = EMarketMode::RESOURCE_RESOURCE); //c-tor
~CMarketplaceWindow(); //d-tor
Point selectionOffset(bool Left) const;
std::string selectionSubtitle(bool Left) const;
Point selectionOffset(bool Left) const override;
std::string selectionSubtitle(bool Left) const override;
void garrisonChanged(); //removes creatures with count 0 from the list (apparently whole stack has been sold)
void artifactsChanged(bool left);
void garrisonChanged() override; //removes creatures with count 0 from the list (apparently whole stack has been sold)
void artifactsChanged(bool left) override;
void resourceChanged(int type, int val);
void getBaseForPositions(EType type, int &dx, int &dy, int &x, int &y, int &h, int &w, bool Right, int &leftToRightOffset) const;
void getBaseForPositions(EType type, int &dx, int &dy, int &x, int &y, int &h, int &w, bool Right, int &leftToRightOffset) const override;
void updateTraderText();
};
@ -141,24 +141,24 @@ public:
CLabel *expToLevel, *expOnAltar;
void selectionChanged(bool side); //true == left
void selectionChanged(bool side) override; //true == left
void SacrificeAll();
void SacrificeBackpack();
void putOnAltar(int backpackIndex);
bool putOnAltar(CTradeableItem* altarSlot, const CArtifactInstance *art);
void makeDeal();
void showAll(SDL_Surface * to);
void showAll(SDL_Surface * to) override;
void blockTrade();
void sliderMoved(int to);
void getBaseForPositions(EType type, int &dx, int &dy, int &x, int &y, int &h, int &w, bool Right, int &leftToRightOffset) const;
void getBaseForPositions(EType type, int &dx, int &dy, int &x, int &y, int &h, int &w, bool Right, int &leftToRightOffset) const override;
void mimicCres();
Point selectionOffset(bool Left) const;
std::string selectionSubtitle(bool Left) const;
void garrisonChanged();
void artifactsChanged(bool left);
Point selectionOffset(bool Left) const override;
std::string selectionSubtitle(bool Left) const override;
void garrisonChanged() override;
void artifactsChanged(bool left) override;
void calcTotalExp();
void setExpToLevel();
void updateRight(CTradeableItem *toUpdate);

View File

@ -39,9 +39,9 @@ protected:
//Simple function with call to GH.popInt
void close();
//Used only if RCLICK_POPUP was set
void clickRight(tribool down, bool previousState);
void clickRight(tribool down, bool previousState) override;
//To display border
void showAll(SDL_Surface *to);
void showAll(SDL_Surface *to) override;
//change or set background image
void setBackground(std::string filename);
void updateShadow();

View File

@ -43,9 +43,9 @@ class CRecruitmentWindow : public CWindowObject
CCreaturePic *pic; //creature's animation
bool selected;
void clickLeft(tribool down, bool previousState);
void clickRight(tribool down, bool previousState);
void showAll(SDL_Surface *to);
void clickLeft(tribool down, bool previousState) override;
void clickRight(tribool down, bool previousState) override;
void showAll(SDL_Surface *to) override;
public:
const CCreature * creature;
si32 amount;
@ -88,7 +88,7 @@ class CRecruitmentWindow : public CWindowObject
void buy();
void sliderMoved(int to);
void showAll(SDL_Surface *to);
void showAll(SDL_Surface *to) override;
public:
const CGDwelling * const dwelling;
CRecruitmentWindow(const CGDwelling *Dwelling, int Level, const CArmedInstance *Dst, const std::function<void(CreatureID,int)> & Recruit, int y_offset = 0); //creatures - pairs<creature_ID,amount> //c-tor
@ -153,7 +153,7 @@ class CObjectListWindow : public CWindowObject
CItem(CObjectListWindow *parent, size_t id, std::string text);
void select(bool on);
void clickLeft(tribool down, bool previousState);
void clickLeft(tribool down, bool previousState) override;
};
std::function<void(int)> onSelect;//called when OK button is pressed, returns id of selected item.
@ -180,7 +180,7 @@ public:
CIntObject *genItem(size_t index);
void elementSelected();//call callback and close this window
void changeSelection(size_t which);
void keyPressed (const SDL_KeyboardEvent & key);
void keyPressed (const SDL_KeyboardEvent & key) override;
};
class CSystemOptionsWindow : public CWindowObject
@ -232,9 +232,9 @@ public:
std::string description; // "XXX is a level Y ZZZ with N artifacts"
const CGHeroInstance *h;
void clickLeft(tribool down, bool previousState);
void clickRight(tribool down, bool previousState);
void hover (bool on);
void clickLeft(tribool down, bool previousState) override;
void clickRight(tribool down, bool previousState) override;
void hover (bool on) override;
HeroPortrait(int &sel, int id, int x, int y, const CGHeroInstance *H);
private:
@ -255,7 +255,7 @@ public:
void recruitb();
void thievesguildb();
void show(SDL_Surface * to);
void show(SDL_Surface * to) override;
};
class CExchangeWindow : public CWindowObject, public CWindowWithGarrison, public CWindowWithArtifacts
@ -319,8 +319,8 @@ private:
ui8 currentAlpha;
public:
void showAll(SDL_Surface * to);
void show(SDL_Surface * to);
void showAll(SDL_Surface * to) override;
void show(SDL_Surface * to) override;
CPuzzleWindow(const int3 &grailPos, double discoveredRatio);
};
@ -339,7 +339,7 @@ public:
CAnimImage *icon;
void move();
void clickLeft(tribool down, bool previousState);
void clickLeft(tribool down, bool previousState) override;
void update();
CItem(CTransformerWindow * parent, int size, int id);
};
@ -353,7 +353,7 @@ public:
CGStatusBar *bar;
void makeDeal();
void addAll();
void updateGarrisons();
void updateGarrisons() override;
CTransformerWindow(const CGHeroInstance * _hero, const CGTownInstance * _town); //c-tor
};
@ -365,10 +365,10 @@ class CUniversityWindow : public CWindowObject
int ID;//id of selected skill
CUniversityWindow * parent;
void showAll(SDL_Surface * to);
void clickLeft(tribool down, bool previousState);
void clickRight(tribool down, bool previousState);
void hover(bool on);
void showAll(SDL_Surface * to) override;
void clickLeft(tribool down, bool previousState) override;
void clickRight(tribool down, bool previousState) override;
void hover(bool on) override;
int state();//0=can't learn, 1=learned, 2=can learn
CItem(CUniversityWindow * _parent, int _ID, int X, int Y);
};
@ -419,12 +419,12 @@ public:
CHillFortWindow(const CGHeroInstance *visitor, const CGObjectInstance *object); //c-tor
void showAll (SDL_Surface *to);
void showAll (SDL_Surface *to) override;
std::string getDefForSlot(SlotID slot);//return def name for this slot
std::string getTextForSlot(SlotID slot);//return hover text for this slot
void makeDeal(SlotID slot);//-1 for upgrading all creatures
int getState(SlotID slot); //-1 = no creature 0=can't upgrade, 1=upgraded, 2=can upgrade
void updateGarrisons();//update buttons after garrison changes
void updateGarrisons() override;//update buttons after garrison changes
};
class CThievesGuildWindow : public CWindowObject

View File

@ -31,7 +31,7 @@ class CSimpleWindow : public CIntObject
{
public:
SDL_Surface * bitmap; //background
virtual void show(SDL_Surface * to);
virtual void show(SDL_Surface * to) override;
CSimpleWindow():bitmap(nullptr){}; //c-tor
virtual ~CSimpleWindow(); //d-tor
};
@ -53,8 +53,8 @@ public:
void setDelComps(bool DelComps);
virtual void close();
void show(SDL_Surface * to);
void showAll(SDL_Surface * to);
void show(SDL_Surface * to) override;
void showAll(SDL_Surface * to) override;
void sliderMoved(int to);
CInfoWindow(std::string Text, PlayerColor player, const TCompsInfo &comps = TCompsInfo(), const TButtonsInfo &Buttons = TButtonsInfo(), bool delComps = true); //c-tor
@ -76,7 +76,7 @@ class CRClickPopup : public CIntObject
{
public:
virtual void close();
void clickRight(tribool down, bool previousState);
void clickRight(tribool down, bool previousState) override;
CRClickPopup();
virtual ~CRClickPopup(); //d-tor
@ -94,8 +94,8 @@ public:
IShowActivatable *inner;
bool delInner;
void show(SDL_Surface * to);
void showAll(SDL_Surface * to);
void show(SDL_Surface * to) override;
void showAll(SDL_Surface * to) override;
CRClickPopupInt(IShowActivatable *our, bool deleteInt); //c-tor
virtual ~CRClickPopupInt(); //d-tor
};
@ -105,8 +105,8 @@ class CInfoPopup : public CRClickPopup
public:
bool free; //TODO: comment me
SDL_Surface * bitmap; //popup background
void close();
void show(SDL_Surface * to);
void close() override;
void show(SDL_Surface * to) override;
CInfoPopup(SDL_Surface * Bitmap, int x, int y, bool Free=false); //c-tor
CInfoPopup(SDL_Surface * Bitmap, const Point &p, EAlignment alignment, bool Free=false); //c-tor
CInfoPopup(SDL_Surface * Bitmap = nullptr, bool Free = false); //default c-tor

View File

@ -1313,7 +1313,8 @@
"subtype" : 35,
"type" : "SPELL_IMMUNITY",
"val" : 0,
"valueType" : "BASE_NUMBER"
"valueType" : "BASE_NUMBER",
"addInfo" : 1
}
],
"index" : 92,
@ -1324,10 +1325,17 @@
"bonuses" : [
{
"type" : "NEGATE_ALL_NATURAL_IMMUNITIES",
"subtype" : 0,
"val" : 0,
"valueType" : "BASE_NUMBER",
"propagator": "BATTLE_WIDE"
}
},
{
"type" : "NEGATE_ALL_NATURAL_IMMUNITIES",
"subtype" : 1,
"val" : 0,
"valueType" : "BASE_NUMBER"
}
],
"index" : 93,
"type" : ["HERO"]
@ -1812,7 +1820,8 @@
"subtype" : "spell.armageddon",
"type" : "SPELL_IMMUNITY",
"val" : 0,
"valueType" : "BASE_NUMBER"
"valueType" : "BASE_NUMBER",
"addInfo" : 1
},
{
"subtype" : "primSkill.attack",

View File

@ -368,6 +368,11 @@
"icon": "zvs/Lib1.res/E_OBST"
}
},
"NO_TERRAIN_PENALTY":
{
"hidden": true
},
"NON_LIVING":
{

View File

@ -1,6 +1,6 @@
// macros:
// ${val} - value of bonuses; Selector: type,subtype
// ${subtype.creature} - creature name
// ${subtype.creature} - creature name
// ${subtype.spell} - spell name
// ${MR} - magic resistance of bearer
@ -11,19 +11,19 @@
"name": "Double Strike",
"description": "Attacks twice"
},
"ADDITIONAL_RETALIATION":
{
"name": "Additional retaliations",
"description": "May Retaliate ${val} extra times"
},
"AIR_IMMUNITY":
{
"name": "Immune to Air",
"description": ""
"name": "Air immunity",
"description": "Immune to all Air school spells"
},
"ATTACKS_ALL_ADJACENT":
{
"name": "Attack all around",
@ -35,19 +35,19 @@
"name": "No retaliation",
"description": "Enemy cannot Retaliate"
},
"CATAPULT":
{
"name": "Catapult",
"description": "Attacks siege walls"
},
},
"CHANGES_SPELL_COST_FOR_ALLY":
{
"name": "Reduce Casting Cost (${val})",
"description": "Reduce Casting Cost for hero"
},
"CHANGES_SPELL_COST_FOR_ENEMY":
{
"name": "Magic Damper (${val})",
@ -59,31 +59,31 @@
"name": "Immune to Charge",
"description": "Immune to Champion charge"
},
"DAEMON_SUMMONING":
{
"name": "Summoner (${subtype.creature})",
"description": "Can rise creatures from corpses"
"description": "Can rise creatures from corpses"
},
"DARKNESS":
"DARKNESS":
{
"name": "Darness cover",
"description": "Adds ${val} darkness radius"
},
"DEATH_STARE":
{
"name": "Death Stare (${val}%)",
"description": "${val}% chance to kill single creature"
},
},
"DEFENSIVE_STANCE":
{
"name": "Defense Bonus",
"description": "+${val} Defense when defending"
},
"DOUBLE_DAMAGE_CHANCE":
{
"name": "Death Blow",
@ -95,7 +95,7 @@
"name": "Dragon",
"description": "Creature has a Dragon Nature"
},
"DIRECT_DAMAGE_IMMUNITY":
{
"name": "Direct Damage Immunity",
@ -104,62 +104,63 @@
"EARTH_IMMUNITY":
{
"name": "Immune to Earth",
"description": ""
"name": "Earth immunity",
"description": "Immune to all Earth school spells"
},
"ENCHANTER":
{
"name": "Enchanter",
"description": "Can cast mass ${subtype.spell} every turn"
},
"ENCHANTED":
{
"name": "Enchanted",
"description": "Affected by permanent ${subtype.spell}"
},
},
"ENEMY_DEFENCE_REDUCTION":
{
"name": "Reduce Enemy Defense (${val}%)",
"description": "Reduces Defense for one attack"
},
"GENERAL_DAMAGE_REDUCTION":
{
"name": "Reduce Damage (${val}%)",
"description": "Reduces physical damage"
},
"FIRE_IMMUNITY":
{
"name": "Immune to Fire",
"description": ""
"name": "Fire immunity",
"description": "Immune to all Fire school spells"
},
"FIRE_SHIELD":
{
"name": "Fire Shield (${val}%)",
"description": "Reflects melee damage"
"description": "Reflects melee damage"
},
"FEAR":
{
"name": "Fear",
"description": "Causes Fear on an enemy stack"
},
"FEARLESS":
{
"name": "Fearless",
"description": "Immune to Fear ability"
},
"FLYING":
{
"name": "Fly",
"description": "Can Fly (ignores obstacles)"
},
},
"FREE_SHOOTING":
{
@ -172,51 +173,55 @@
"name": "Regeneration",
"description": "May Regenerate full Health"
},
"HATE":
{
"name": "Hates ${subtype.creature}",
"description": "Does ${val}% more damage"
},
"HEALER":
{
"name": "Healer",
"description": "Heals allied units"
},
"HP_REGENERATION":
{
"name": "Regeneration",
"description": "Heals ${val} hit points every round"
},
"JOUSTING":
{
"name": "Champion Charge",
"description": "+5% damage per hex travelled"
},
"KING1":
{
"name": "King1"
"name": "King1",
"description": "Vulnerable to basic SLAYER"
},
"KING2":
{
"name": "King2"
"name": "King2",
"description": "Vulnerable to adv. SLAYER"
},
"KING3":
{
"name": "King3"
"name": "King3",
"description":"Vulnerable to expert SLAYER"
},
"LEVEL_SPELL_IMMUNITY":
{
"name": "Spell immunity 1-${val}",
"description": "Immune to spells levels 1-${val}"
},
"LIFE_DRAIN":
{
"name": "Drain life (${val}%)",
@ -228,6 +233,7 @@
"name": "Magic Channel ${val}%",
"description": "Gives mana spent by enemy"
},
"MANA_DRAIN":
{
"name": "Mana Drain",
@ -257,19 +263,19 @@
"name": "No distance penalty",
"description": "Full damage from any distance"
},
"NO_MELEE_PENALTY":
{
"name": "No melee penalty",
"description": "Creature has no Melee Penalty"
},
"NO_MORALE":
{
},
},
"NO_WALL_PENALTY":
{
"name": "No wall penalty",
@ -280,7 +286,7 @@
{
"name": "Non living",
"description": "Immunity to many effects"
},
},
"RANDOM_SPELLCASTER":
{
@ -298,48 +304,49 @@
"name": "Rebirth (${val}%)",
"description": "${val}% of stack will rise after death"
},
"RETURN_AFTER_STRIKE":
{
"name": "Attack and Return",
"description": "Returns after melee attack"
},
"SELF_LUCK":
{
"name": "Positive luck",
"description": "Always has Positive Luck"
},
"SELF_MORALE":
{
"name": "Positive morale",
"description": "Always has Positive Morale"
},
"SHOOTER":
{
"name": "Ranged",
"description": "Creature can shoot"
},
},
"SPELLCASTER":
{
"name": "Spellcaster",
"description": "Can cast ${subtype.spell}"
},
"SPELL_AFTER_ATTACK":
{
"name": "Caster - ${subtype.spell}",
"description": "${val}% chance to cast after attack"
"name": "After attack cast",
"description": "${val}% to cast ${subtype.spell} after attack"
},
"SPELL_BEFORE_ATTACK":
{
"name": "Caster - ${subtype.spell}",
"description": "${val}% chance to cast before attack"
"name": "Before attack cast",
"description": "${val}% to cast ${subtype.spell} before attack"
},
"SPELL_DAMAGE_REDUCTION":
{
"name": "Spell Resistance",
@ -348,17 +355,16 @@
"SPELL_IMMUNITY":
{
"name": "Immune to ${subtype.spell}",
"description": ""
"name": "Spell immunity",
"description": "Immune to ${subtype.spell}"
},
"SPELL_LIKE_ATTACK":
{
"name": "Spell-like attack",
"description": "Attacks with ${subtype.spell}"
},
"SPELL_RESISTANCE_AURA":
{
"name": "Aura of Resistance",
@ -371,8 +377,6 @@
"description": "Breath Attack (2-hex range)"
},
"THREE_HEADED_ATTACK":
{
"name": "Three-headed attack",
@ -384,14 +388,16 @@
"name": "Undead",
"description": "Creature is Undead"
},
"UNLIMITED_RETALIATIONS":
{
"name": "Unlimited retaliations",
"description": "Retaliate any number of attacks"
},
"WATER_IMMUNITY":
{
"name": "Immune to Water",
"description": ""
"name": "Water immunity",
"description": "Immune to all Water school spells"
}
}

View File

@ -9,12 +9,14 @@
"blindImmunity" :
{
"type" : "SPELL_IMMUNITY",
"subtype" : "spell.blind"
"subtype" : "spell.blind",
"addInfo" : 1
},
"petrifyImmunity" :
{
"type" : "SPELL_IMMUNITY",
"subtype" : "spell.stoneGaze"
"subtype" : "spell.stoneGaze",
"addInfo" : 1
}
},
"upgrades": ["infernalTroglodyte"],
@ -42,12 +44,14 @@
"blindImmunity" :
{
"type" : "SPELL_IMMUNITY",
"subtype" : "spell.blind"
"subtype" : "spell.blind",
"addInfo" : 1
},
"petrifyImmunity" :
{
"type" : "SPELL_IMMUNITY",
"subtype" : "spell.stoneGaze"
"subtype" : "spell.stoneGaze",
"addInfo" : 1
}
},
"graphics" :

View File

@ -475,6 +475,15 @@
"index": 142,
"level": 3,
"faction": "neutral",
"abilities":
{
"sandWalker" :
{
"type" : "NO_TERRAIN_PENALTY",
"subtype" : 1,
"propagator" : "HERO"
}
},
"doubleWide" : true,
"graphics" :
{

View File

@ -564,7 +564,7 @@
"subtype" : "primSkill.defence",
"val" : -3,
"valueType" : "ADDITIVE_VALUE",
"duration" : "N_TURNS"
"duration" : "PERMANENT"
}
}
},

View File

@ -1170,6 +1170,17 @@ bool CStack::canBeHealed() const
&& !hasBonusOfType(Bonus::SIEGE_WEAPON);
}
ui32 CStack::calculateHealedHealthPoints(ui32 toHeal, const bool resurrect) const
{
if(!resurrect && !alive())
{
logGlobal->warnStream() <<"Attempt to heal corpse detected.";
return 0;
}
return std::min<ui32>(toHeal, MaxHealth() - firstHPleft + (resurrect ? (baseAmount - count) * MaxHealth() : 0));
}
ui8 CStack::getSpellSchoolLevel(const CSpell * spell, int * outSelectedSchool) const
{
int skill = valOfBonuses(Selector::typeSubtype(Bonus::SPELLCASTER, spell->id));
@ -1181,10 +1192,39 @@ ui8 CStack::getSpellSchoolLevel(const CSpell * spell, int * outSelectedSchool) c
ui32 CStack::getSpellBonus(const CSpell * spell, ui32 base, const CStack * affectedStack) const
{
//stacks does not have spellpower etc. (yet?)
//stacks does not have sorcery-like bonuses (yet?)
return base;
}
int CStack::getEffectLevel(const CSpell * spell) const
{
return getSpellSchoolLevel(spell);
}
int CStack::getEffectPower(const CSpell * spell) const
{
return valOfBonuses(Bonus::CREATURE_SPELL_POWER) * count / 100;
}
int CStack::getEnchantPower(const CSpell * spell) const
{
int res = valOfBonuses(Bonus::CREATURE_ENCHANT_POWER);
if(res<=0)
res = 3;//default for creatures
return res;
}
int CStack::getEffectValue(const CSpell * spell) const
{
return valOfBonuses(Bonus::SPECIFIC_SPELL_POWER, spell->id.toEnum()) * count;
}
const PlayerColor CStack::getOwner() const
{
return owner;
}
bool CMP_stack::operator()( const CStack* a, const CStack* b )
{
switch(phase)

View File

@ -203,6 +203,8 @@ public:
bool waited(int turn = 0) const;
bool canMove(int turn = 0) const; //if stack can move
bool canBeHealed() const; //for first aid tent - only harmed stacks that are not war machines
///returns actual heal value based on internal state
ui32 calculateHealedHealthPoints(ui32 toHeal, const bool resurrect) const;
ui32 level() const;
si32 magicResistance() const override; //include aura of resistance
static void stackEffectToFeature(std::vector<Bonus> & sf, const Bonus & sse);
@ -233,6 +235,20 @@ public:
///ISpellCaster
ui8 getSpellSchoolLevel(const CSpell * spell, int *outSelectedSchool = nullptr) const override;
ui32 getSpellBonus(const CSpell * spell, ui32 base, const CStack * affectedStack) const override;
///default spell school level for effect calculation
int getEffectLevel(const CSpell * spell) const override;
///default spell-power for damage/heal calculation
int getEffectPower(const CSpell * spell) const override;
///default spell-power for timed effects duration
int getEnchantPower(const CSpell * spell) const override;
///damage/heal override(ignores spell configuration, effect level and effect power)
int getEffectValue(const CSpell * spell) const override;
const PlayerColor getOwner() const override;
template <typename Handler> void serialize(Handler &h, const int version)
{

View File

@ -577,10 +577,12 @@ bool CArtHandler::legalArtifact(ArtifactID id)
{
auto art = artifacts[id];
//assert ( (!art->constituents) || art->constituents->size() ); //artifacts is not combined or has some components
return (art->possibleSlots[ArtBearer::HERO].size() ||
(art->possibleSlots[ArtBearer::COMMANDER].size() && VLC->modh->modules.COMMANDERS) ||
(art->possibleSlots[ArtBearer::CREATURE].size() && VLC->modh->modules.STACK_ARTIFACT)) &&
!(art->constituents); //no combo artifacts spawning
return ((art->possibleSlots[ArtBearer::HERO].size() ||
(art->possibleSlots[ArtBearer::COMMANDER].size() && VLC->modh->modules.COMMANDERS) ||
(art->possibleSlots[ArtBearer::CREATURE].size() && VLC->modh->modules.STACK_ARTIFACT)) &&
!(art->constituents) && //no combo artifacts spawning
art->aClass >= CArtifact::ART_TREASURE &&
art->aClass <= CArtifact::ART_RELIC);
}
bool CArtHandler::isTradableArtifact(ArtifactID id) const
@ -609,17 +611,12 @@ void CArtHandler::initAllowedArtifactsList(const std::vector<bool> &allowed)
for (ArtifactID i=ArtifactID::SPELLBOOK; i<ArtifactID::ART_SELECTION; i.advance(1))
{
//check artifacts allowed on a map
//TODO: This line will be different when custom map format is implemented
if (allowed[i] && legalArtifact(i))
allowedArtifacts.push_back(artifacts[i]);
}
if (VLC->modh->modules.COMMANDERS) //allow all commander artifacts for testing
{
for (int i = 146; i <= 155; ++i)
{
allowedArtifacts.push_back(artifacts[i]);
}
}
for (int i = GameConstants::ARTIFACTS_QUANTITY; i < artifacts.size(); ++i) //allow all new artifacts by default
for (ArtifactID i = ArtifactID::ART_SELECTION; i<ArtifactID(artifacts.size()); i.advance(1)) //try to allow all artifacts added by mods
{
if (legalArtifact(ArtifactID(i)))
allowedArtifacts.push_back(artifacts[i]);

View File

@ -93,7 +93,7 @@ public:
std::vector <std::pair <ui16, Bonus> > bonusesPerLevel; //bonus given each n levels
std::vector <std::pair <ui16, Bonus> > thresholdBonuses; //after certain level they will be added once
void levelUpArtifact (CArtifactInstance * art);
void levelUpArtifact (CArtifactInstance * art) override;
template <typename Handler> void serialize(Handler &h, const int version)
{

View File

@ -335,6 +335,11 @@ int CBattleInfoEssentials::battleCastSpells(ui8 side) const
return getBattle()->sides[side].castSpellsCount;
}
const IBonusBearer * CBattleInfoEssentials::getBattleNode() const
{
return getBattle();
}
ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastSpell(PlayerColor player, ECastingMode::ECastingMode mode) const
{
RETURN_IF_NOT_BATTLE(ESpellCastProblem::INVALID);
@ -1587,9 +1592,15 @@ std::vector<BattleHex> CBattleInfoCallback::getAttackableBattleHexes() const
return attackableBattleHexes;
}
ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell( PlayerColor player, const CSpell * spell, ECastingMode::ECastingMode mode ) const
ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell(const ISpellCaster * caster, const CSpell * spell, ECastingMode::ECastingMode mode) const
{
RETURN_IF_NOT_BATTLE(ESpellCastProblem::INVALID);
if(caster == nullptr)
{
logGlobal->errorStream() << "CBattleInfoCallback::battleCanCastThisSpell: no spellcaster.";
return ESpellCastProblem::INVALID;
}
const PlayerColor player = caster->getOwner();
const ui8 side = playerToSide(player);
if(!battleDoWeKnowAbout(side))
return ESpellCastProblem::INVALID;
@ -1598,16 +1609,11 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell
if(genProblem != ESpellCastProblem::OK)
return genProblem;
//Casting hero, set only if he is an actual caster.
const CGHeroInstance *castingHero = mode == ECastingMode::HERO_CASTING
? battleGetFightingHero(side)
: nullptr;
switch(mode)
{
case ECastingMode::HERO_CASTING:
{
const CGHeroInstance * castingHero = dynamic_cast<const CGHeroInstance *>(caster);//todo: unify hero|creature spell cost
assert(castingHero);
if(!castingHero->canCastThisSpell(spell))
return ESpellCastProblem::HERO_DOESNT_KNOW_SPELL;
@ -1617,11 +1623,10 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell
break;
}
if(!spell->combatSpell)
return ESpellCastProblem::ADVMAP_SPELL_INSTEAD_OF_BATTLE_SPELL;
const ESpellCastProblem::ESpellCastProblem specificProblem = spell->canBeCasted(this, player);
const ESpellCastProblem::ESpellCastProblem specificProblem = spell->canBeCast(this, player);
if(specificProblem != ESpellCastProblem::OK)
return specificProblem;
@ -1634,7 +1639,7 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell
auto stacks = spell->isNegative() ? battleAliveStacks(!side) : battleAliveStacks();
for(auto stack : stacks)
{
if(ESpellCastProblem::OK == spell->isImmuneByStack(castingHero, stack))
if(ESpellCastProblem::OK == spell->isImmuneByStack(caster, stack))
{
allStacksImmune = false;
break;
@ -1645,7 +1650,7 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell
return ESpellCastProblem::NO_APPROPRIATE_TARGET;
}
if(battleMaxSpellLevel() < spell->level) //effect like Recanter's Cloak or Orb of Inhibition
if(battleMaxSpellLevel(side) < spell->level) //effect like Recanter's Cloak or Orb of Inhibition
return ESpellCastProblem::SPELL_LEVEL_LIMIT_EXCEEDED;
//checking if there exists an appropriate target
@ -1654,8 +1659,7 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell
case CSpell::CREATURE:
if(mode == ECastingMode::HERO_CASTING)
{
const CGHeroInstance * caster = battleGetFightingHero(side);
const CSpell::TargetInfo ti = spell->getTargetInfo(caster->getSpellSchoolLevel(spell));
const CSpell::TargetInfo ti(spell, caster->getSpellSchoolLevel(spell));
bool targetExists = false;
for(const CStack * stack : battleGetAllStacks()) //dead stacks will be immune anyway
@ -1710,7 +1714,7 @@ std::vector<BattleHex> CBattleInfoCallback::battleGetPossibleTargets(PlayerColor
case CSpell::CREATURE:
{
const CGHeroInstance * caster = battleGetFightingHero(playerToSide(player)); //TODO
const CSpell::TargetInfo ti = spell->getTargetInfo(caster->getSpellSchoolLevel(spell));
const CSpell::TargetInfo ti(spell, caster->getSpellSchoolLevel(spell));
for(const CStack * stack : battleAliveStacks())
{
@ -1772,10 +1776,16 @@ ui32 CBattleInfoCallback::battleGetSpellCost(const CSpell * sp, const CGHeroInst
return ret - manaReduction + manaIncrease;
}
ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpellHere( PlayerColor player, const CSpell * spell, ECastingMode::ECastingMode mode, BattleHex dest ) const
ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpellHere(const ISpellCaster * caster, const CSpell * spell, ECastingMode::ECastingMode mode, BattleHex dest) const
{
RETURN_IF_NOT_BATTLE(ESpellCastProblem::INVALID);
ESpellCastProblem::ESpellCastProblem moreGeneralProblem = battleCanCastThisSpell(player, spell, mode);
if(caster == nullptr)
{
logGlobal->errorStream() << "CBattleInfoCallback::battleCanCastThisSpellHere: no spellcaster.";
return ESpellCastProblem::INVALID;
}
const PlayerColor player = caster->getOwner();
ESpellCastProblem::ESpellCastProblem moreGeneralProblem = battleCanCastThisSpell(caster, spell, mode);
if(moreGeneralProblem != ESpellCastProblem::OK)
return moreGeneralProblem;
@ -1826,8 +1836,6 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell
{
if(!deadStack && !aliveStack)
return ESpellCastProblem::NO_APPROPRIATE_TARGET;
if(spell->id == SpellID::ANIMATE_DEAD && deadStack && !deadStack->hasBonusOfType(Bonus::UNDEAD))
return ESpellCastProblem::NO_APPROPRIATE_TARGET;
if(deadStack && deadStack->owner != player) //you can resurrect only your own stacks //FIXME: it includes alive stacks as well
return ESpellCastProblem::NO_APPROPRIATE_TARGET;
}
@ -1840,11 +1848,6 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell
if(spell->isPositive() && aliveStack->owner != player)
return ESpellCastProblem::NO_APPROPRIATE_TARGET;
}
const CGHeroInstance * caster = nullptr;
if (mode == ECastingMode::HERO_CASTING)
caster = battleGetFightingHero(playerToSide(player));
return spell->isImmuneAt(this, caster, mode, dest);
}
@ -1927,7 +1930,7 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(const CStack * subject) co
{
if (subject->hasBonusFrom(Bonus::SPELL_EFFECT, spellID)
//TODO: this ability has special limitations
|| battleCanCastThisSpellHere(subject->owner, spellID.toSpell(), ECastingMode::CREATURE_ACTIVE_CASTING, subject->position) != ESpellCastProblem::OK)
|| battleCanCastThisSpellHere(subject, spellID.toSpell(), ECastingMode::CREATURE_ACTIVE_CASTING, subject->position) != ESpellCastProblem::OK)
continue;
switch (spellID)
@ -2060,12 +2063,14 @@ int CBattleInfoCallback::battleGetSurrenderCost(PlayerColor Player) const
return ret;
}
si8 CBattleInfoCallback::battleMaxSpellLevel() const
si8 CBattleInfoCallback::battleMaxSpellLevel(ui8 side) const
{
const CBonusSystemNode *node = nullptr;
if(const CGHeroInstance *h = battleGetFightingHero(battleGetMySide()))
const IBonusBearer *node = nullptr;
if(const CGHeroInstance * h = battleGetFightingHero(side))
node = h;
//TODO else use battle node
else
node = getBattleNode();
if(!node)
return GameConstants::SPELL_LEVELS;
@ -2163,21 +2168,12 @@ ESpellCastProblem::ESpellCastProblem CPlayerBattleCallback::battleCanCastThisSpe
{
RETURN_IF_NOT_BATTLE(ESpellCastProblem::INVALID);
ASSERT_IF_CALLED_WITH_PLAYER
return CBattleInfoCallback::battleCanCastThisSpell(*player, spell, ECastingMode::HERO_CASTING);
}
ESpellCastProblem::ESpellCastProblem CPlayerBattleCallback::battleCanCastThisSpell(const CSpell * spell, BattleHex destination) const
{
RETURN_IF_NOT_BATTLE(ESpellCastProblem::INVALID);
ASSERT_IF_CALLED_WITH_PLAYER
return battleCanCastThisSpellHere(*player, spell, ECastingMode::HERO_CASTING, destination);
}
ESpellCastProblem::ESpellCastProblem CPlayerBattleCallback::battleCanCreatureCastThisSpell(const CSpell * spell, BattleHex destination) const
{
RETURN_IF_NOT_BATTLE(ESpellCastProblem::INVALID);
ASSERT_IF_CALLED_WITH_PLAYER
return battleCanCastThisSpellHere(*player, spell, ECastingMode::CREATURE_ACTIVE_CASTING, destination);
const ISpellCaster * hero = battleGetMyHero();
if(hero == nullptr)
return ESpellCastProblem::INVALID;
else
return CBattleInfoCallback::battleCanCastThisSpell(hero, spell, ECastingMode::HERO_CASTING);
}
bool CPlayerBattleCallback::battleCanFlee() const

View File

@ -15,6 +15,7 @@ class CGameState;
class CGTownInstance;
class CGHeroInstance;
class CStack;
class ISpellCaster;
class CSpell;
struct BattleInfo;
struct CObstacleInstance;
@ -158,6 +159,7 @@ class DLL_LINKAGE CBattleInfoEssentials : public virtual CCallbackBase
{
protected:
bool battleDoWeKnowAbout(ui8 side) const;
const IBonusBearer * getBattleNode() const;
public:
enum EStackOwnership
{
@ -189,7 +191,7 @@ public:
ui8 playerToSide(PlayerColor player) const;
ui8 battleGetSiegeLevel() const; //returns 0 when there is no siege, 1 if fort, 2 is citadel, 3 is castle
bool battleHasHero(ui8 side) const;
int battleCastSpells(ui8 side) const; //how many spells has given side casted
int battleCastSpells(ui8 side) const; //how many spells has given side cast
const CGHeroInstance * battleGetFightingHero(ui8 side) const; //depracated for players callback, easy to get wrong
const CArmedInstance * battleGetArmyObject(ui8 side) const;
InfoAboutHero battleGetHeroInfo(ui8 side) const;
@ -276,12 +278,11 @@ public:
std::vector<BattleHex> getAttackableBattleHexes() const;
//*** MAGIC
si8 battleMaxSpellLevel() const; //calculates minimum spell level possible to be cast on battlefield - takes into account artifacts of both heroes; if no effects are set, 0 is returned
si8 battleMaxSpellLevel(ui8 side) const; //calculates minimum spell level possible to be cast on battlefield - takes into account artifacts of both heroes; if no effects are set, 0 is returned
ui32 battleGetSpellCost(const CSpell * sp, const CGHeroInstance * caster) const; //returns cost of given spell
ESpellCastProblem::ESpellCastProblem battleCanCastSpell(PlayerColor player, ECastingMode::ECastingMode mode) const; //returns true if there are no general issues preventing from casting a spell
ESpellCastProblem::ESpellCastProblem battleCanCastThisSpell(PlayerColor player, const CSpell * spell, ECastingMode::ECastingMode mode) const; //checks if given player can cast given spell
ESpellCastProblem::ESpellCastProblem battleCanCastThisSpellHere(PlayerColor player, const CSpell * spell, ECastingMode::ECastingMode mode, BattleHex dest) const; //checks if given player can cast given spell at given tile in given mode
ESpellCastProblem::ESpellCastProblem battleCanCreatureCastThisSpell(const CSpell * spell, BattleHex destination) const; //determines if creature can cast a spell here
ESpellCastProblem::ESpellCastProblem battleCanCastThisSpell(const ISpellCaster * caster, const CSpell * spell, ECastingMode::ECastingMode mode) const; //checks if given player can cast given spell
ESpellCastProblem::ESpellCastProblem battleCanCastThisSpellHere(const ISpellCaster * caster, const CSpell * spell, ECastingMode::ECastingMode mode, BattleHex dest) const; //checks if given player can cast given spell at given tile in given mode
std::vector<BattleHex> battleGetPossibleTargets(PlayerColor player, const CSpell *spell) const;
SpellID battleGetRandomStackSpell(const CStack * stack, ERandomSpell mode) const;
@ -324,9 +325,8 @@ class DLL_LINKAGE CPlayerBattleCallback : public CBattleInfoCallback
public:
bool battleCanFlee() const; //returns true if caller can flee from the battle
TStacks battleGetStacks(EStackOwnership whose = MINE_AND_ENEMY, bool onlyAlive = true) const; //returns stacks on battlefield
ESpellCastProblem::ESpellCastProblem battleCanCastThisSpell(const CSpell * spell) const; //determines if given spell can be casted (and returns problem description)
ESpellCastProblem::ESpellCastProblem battleCanCastThisSpell(const CSpell * spell, BattleHex destination) const; //if hero can cast spell here
ESpellCastProblem::ESpellCastProblem battleCanCreatureCastThisSpell(const CSpell * spell, BattleHex destination) const; //determines if creature can cast a spell here
ESpellCastProblem::ESpellCastProblem battleCanCastThisSpell(const CSpell * spell) const; //determines if given spell can be cast (and returns problem description)
int battleGetSurrenderCost() const; //returns cost of surrendering battle, -1 if surrendering is not possible
bool battleCanCastSpell(ESpellCastProblem::ESpellCastProblem *outProblem = nullptr) const; //returns true, if caller can cast a spell. If not, if pointer is given via arg, the reason will be written.

View File

@ -853,34 +853,42 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
case 'B': //Blind
b.type = Bonus::SPELL_IMMUNITY;
b.subtype = SpellID::BLIND;
b.additionalInfo = 0;//normal immunity
break;
case 'H': //Hypnotize
b.type = Bonus::SPELL_IMMUNITY;
b.subtype = SpellID::HYPNOTIZE;
b.additionalInfo = 0;//normal immunity
break;
case 'I': //Implosion
b.type = Bonus::SPELL_IMMUNITY;
b.subtype = SpellID::IMPLOSION;
b.additionalInfo = 0;//normal immunity
break;
case 'K': //Berserk
b.type = Bonus::SPELL_IMMUNITY;
b.subtype = SpellID::BERSERK;
b.additionalInfo = 0;//normal immunity
break;
case 'M': //Meteor Shower
b.type = Bonus::SPELL_IMMUNITY;
b.subtype = SpellID::METEOR_SHOWER;
b.additionalInfo = 0;//normal immunity
break;
case 'N': //dispell beneficial spells
b.type = Bonus::SPELL_IMMUNITY;
b.subtype = SpellID::DISPEL_HELPFUL_SPELLS;
b.additionalInfo = 0;//normal immunity
break;
case 'R': //Armageddon
b.type = Bonus::SPELL_IMMUNITY;
b.subtype = SpellID::ARMAGEDDON;
b.additionalInfo = 0;//normal immunity
break;
case 'S': //Slow
b.type = Bonus::SPELL_IMMUNITY;
b.subtype = SpellID::SLOW;
b.additionalInfo = 0;//normal immunity
break;
case '6':
case '7':

View File

@ -199,7 +199,7 @@ public:
/// generates tier-specific bonus tree entries
void buildBonusTreeForTiers();
void afterLoadFinalization();
void afterLoadFinalization() override;
std::vector<JsonNode> loadLegacyData(size_t dataSize) override;

View File

@ -68,7 +68,7 @@ public:
std::string getQuantityTXT(bool capitalized = true) const;
virtual int getExpRank() const;
virtual int getLevel() const; //different for regular stack and commander
si32 magicResistance() const;
si32 magicResistance() const override;
CreatureID getCreatureID() const; //-1 if not available
std::string getName() const; //plural or singular
virtual void init();
@ -104,12 +104,12 @@ public:
CCommanderInstance (CreatureID id);
~CCommanderInstance();
void setAlive (bool alive);
void giveStackExp (TExpType exp);
void giveStackExp (TExpType exp) override;
void levelUp ();
bool gainsLevel() const; //true if commander has lower level than should upon his experience
ui64 getPower() const {return 0;};
int getExpRank() const;
ui64 getPower() const override {return 0;};
int getExpRank() const override;
int getLevel() const override;
ArtBearer::ArtBearer bearerType() const override; //from CArtifactSet

View File

@ -182,7 +182,7 @@ int CGameInfoCallback::estimateSpellDamage(const CSpell * sp, const CGHeroInstan
ERROR_RET_VAL_IF(hero && !canGetFullInfo(hero), "Cannot get info about caster!", -1);
if (hero) //we see hero's spellbook
return sp->calculateDamage(hero, nullptr, hero->getSpellSchoolLevel(sp), hero->getPrimSkillLevel(PrimarySkill::SPELL_POWER));
return sp->calculateDamage(hero, nullptr, hero->getEffectLevel(sp), hero->getEffectPower(sp));
else
return 0; //mage guild
}

View File

@ -127,26 +127,26 @@ public:
virtual std::string getBattleAIName() const = 0; //has to return name of the battle AI to be used
//battle interface
virtual BattleAction activeStack(const CStack * stack);
virtual void yourTacticPhase(int distance);
virtual void battleNewRound(int round);
virtual void battleCatapultAttacked(const CatapultAttack & ca);
virtual void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side);
virtual void battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa);
virtual void actionStarted(const BattleAction &action);
virtual void battleNewRoundFirst(int round);
virtual void actionFinished(const BattleAction &action);
virtual void battleStacksEffectsSet(const SetStackEffect & sse);
virtual BattleAction activeStack(const CStack * stack) override;
virtual void yourTacticPhase(int distance) override;
virtual void battleNewRound(int round) override;
virtual void battleCatapultAttacked(const CatapultAttack & ca) override;
virtual void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side) override;
virtual void battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa) override;
virtual void actionStarted(const BattleAction &action) override;
virtual void battleNewRoundFirst(int round) override;
virtual void actionFinished(const BattleAction &action) override;
virtual void battleStacksEffectsSet(const SetStackEffect & sse) override;
//virtual void battleTriggerEffect(const BattleTriggerEffect & bte);
virtual void battleStacksRemoved(const BattleStacksRemoved & bsr);
virtual void battleObstaclesRemoved(const std::set<si32> & removedObstacles);
virtual void battleNewStackAppeared(const CStack * stack);
virtual void battleStackMoved(const CStack * stack, std::vector<BattleHex> dest, int distance);
virtual void battleAttack(const BattleAttack *ba);
virtual void battleSpellCast(const BattleSpellCast *sc);
virtual void battleEnd(const BattleResult *br);
virtual void battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks, bool lifeDrain, bool tentHeal, si32 lifeDrainFrom);
virtual void battleStacksRemoved(const BattleStacksRemoved & bsr) override;
virtual void battleObstaclesRemoved(const std::set<si32> & removedObstacles) override;
virtual void battleNewStackAppeared(const CStack * stack) override;
virtual void battleStackMoved(const CStack * stack, std::vector<BattleHex> dest, int distance) override;
virtual void battleAttack(const BattleAttack *ba) override;
virtual void battleSpellCast(const BattleSpellCast *sc) override;
virtual void battleEnd(const BattleResult *br) override;
virtual void battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks, bool lifeDrain, bool tentHeal, si32 lifeDrainFrom) override;
virtual void saveGame(COSer & h, const int version); //saving
virtual void loadGame(CISer & h, const int version); //loading
virtual void saveGame(COSer & h, const int version) override; //saving
virtual void loadGame(CISer & h, const int version) override; //loading
};

View File

@ -63,7 +63,7 @@ public:
template <typename T> class CApplyOnGS : public CBaseForGSApply
{
public:
void applyOnGS(CGameState *gs, void *pack) const
void applyOnGS(CGameState *gs, void *pack) const override
{
T *ptr = static_cast<T*>(pack);

View File

@ -159,7 +159,7 @@ void Unicode::trimRight(std::string & text, const size_t amount/* =1 */)
class LocaleWithComma: public std::numpunct<char>
{
protected:
char do_decimal_point() const
char do_decimal_point() const override
{
return ',';
}

View File

@ -178,9 +178,9 @@ public:
void loadObject(std::string scope, std::string name, const JsonNode & data) override;
void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override;
void afterLoadFinalization();
void afterLoadFinalization() override;
std::vector<bool> getDefaultAllowed() const;
std::vector<bool> getDefaultAllowed() const override;
~CHeroClassHandler();
@ -244,7 +244,7 @@ public:
CHeroHandler(); //c-tor
~CHeroHandler(); //d-tor
std::vector<bool> getDefaultAllowed() const;
std::vector<bool> getDefaultAllowed() const override;
/**
* Gets a list of default allowed abilities. OH3 abilities/skills are all allowed by default.

View File

@ -1551,7 +1551,7 @@ public:
void openNextFile(const std::string &fname); //throws!
void clear();
void reportState(CLogger * out);
void reportState(CLogger * out) override;
void putMagicBytes(const std::string &text);
@ -1578,7 +1578,7 @@ public:
void openNextFile(const boost::filesystem::path & fname, int minimalVersion); //throws!
void clear();
void reportState(CLogger * out);
void reportState(CLogger * out) override;
void checkMagicBytes(const std::string & text);
@ -1616,7 +1616,7 @@ class DLL_LINKAGE CConnection
CConnection(void);
void init();
void reportState(CLogger * out);
void reportState(CLogger * out) override;
public:
CISer iser;
COSer oser;

View File

@ -14,7 +14,7 @@
namespace GameConstants
{
const std::string VCMI_VERSION = "VCMI 0.98d";
const std::string VCMI_VERSION = "VCMI 0.98e";
const int BFIELD_WIDTH = 17;
const int BFIELD_HEIGHT = 11;
@ -51,6 +51,7 @@ namespace GameConstants
const int SPELLS_QUANTITY=70;
const int CREATURES_COUNT = 197;
const ui32 BASE_MOVEMENT_COST = 100; //default cost for non-diagonal movement
}
class CArtifact;
@ -414,7 +415,8 @@ namespace ECastingMode
{
HERO_CASTING, AFTER_ATTACK_CASTING, //also includes cast before attack
MAGIC_MIRROR, CREATURE_ACTIVE_CASTING, ENCHANTER_CASTING,
SPELL_LIKE_ATTACK
SPELL_LIKE_ATTACK,
PASSIVE_CASTING//f.e. opening battle spells
};
}
@ -699,6 +701,7 @@ namespace Battle
{
enum ActionType
{
CANCEL = -3,
END_TACTIC_PHASE = -2,
INVALID = -1,
NO_ACTION = 0,
@ -823,6 +826,7 @@ public:
//BLACKSHARD_OF_THE_DEAD_KNIGHT = 8,
TITANS_THUNDER = 135,
//CORNUCOPIA = 140,
//FIXME: the following is only true if WoG is enabled. Otherwise other mod artifacts will take these slots.
ART_SELECTION = 144,
ART_LOCK = 145,
AXE_OF_SMASHING = 146,

View File

@ -504,7 +504,7 @@ const TBonusListPtr IBonusBearer::getSpellBonuses() const
CSelector selector = Selector::sourceType(Bonus::SPELL_EFFECT)
.And(CSelector([](const Bonus * b)->bool
{
return !b->type == Bonus::NONE;
return b->type != Bonus::NONE;
}));
return getBonuses(selector, Selector::anyRange(), cachingStr.str());
}

View File

@ -133,7 +133,7 @@ public:
BONUS_NAME(SPELL_RESISTANCE_AURA) /*eg. unicorns, value - resistance bonus in % for adjacent creatures*/ \
BONUS_NAME(LEVEL_SPELL_IMMUNITY) /*creature is immune to all spell with level below or equal to value of this bonus*/ \
BONUS_NAME(BLOCK_MAGIC_ABOVE) /*blocks casting spells of the level > value */ \
BONUS_NAME(BLOCK_ALL_MAGIC) /*blocks casting spells of the level > value */ \
BONUS_NAME(BLOCK_ALL_MAGIC) /*blocks casting spells*/ \
BONUS_NAME(TWO_HEX_ATTACK_BREATH) /*eg. dragons*/ \
BONUS_NAME(SPELL_DAMAGE_REDUCTION) /*eg. golems; value - reduction in %, subtype - spell school; -1 - all, 0 - air, 1 - fire, 2 - water, 3 - earth*/ \
BONUS_NAME(NO_WALL_PENALTY) \
@ -207,16 +207,18 @@ public:
BONUS_NAME(RECEPTIVE) /*accepts friendly spells even with immunity*/\
BONUS_NAME(DIRECT_DAMAGE_IMMUNITY) /*direct damage spells, that is*/\
BONUS_NAME(CASTS) /*how many times creature can cast activated spell*/ \
BONUS_NAME(SPECIFIC_SPELL_POWER) /* value used for Thunderbolt and Resurrection casted by units, subtype - spell id */\
BONUS_NAME(SPECIFIC_SPELL_POWER) /* value used for Thunderbolt and Resurrection cast by units, subtype - spell id */\
BONUS_NAME(CREATURE_SPELL_POWER) /* value per unit, divided by 100 (so faerie Dragons have 800)*/ \
BONUS_NAME(CREATURE_ENCHANT_POWER) /* total duration of spells casted by creature */ \
BONUS_NAME(CREATURE_ENCHANT_POWER) /* total duration of spells cast by creature */ \
BONUS_NAME(ENCHANTED) /* permanently enchanted with spell subID of level = val, if val > 3 then spell is mass and has level of val-3*/ \
BONUS_NAME(REBIRTH) /* val - percent of life restored, subtype = 0 - regular, 1 - at least one unit (sacred Phoenix) */\
BONUS_NAME(ADDITIONAL_UNITS) /*val of units with id = subtype will be added to hero's army at the beginning of battle */\
BONUS_NAME(SPOILS_OF_WAR) /*val * 10^-6 * gained exp resources of subtype will be given to hero after battle*/\
BONUS_NAME(BLOCK)\
BONUS_NAME(DISGUISED) /* subtype - spell level */\
BONUS_NAME(VISIONS) /* subtype - spell level */
BONUS_NAME(VISIONS) /* subtype - spell level */\
BONUS_NAME(NO_TERRAIN_PENALTY) /* subtype - terrain type */\
/* end of list */
#define BONUS_SOURCE_LIST \
@ -539,7 +541,7 @@ class DLL_LINKAGE CPropagatorNodeType : public IPropagator
public:
CPropagatorNodeType();
CPropagatorNodeType(int NodeType);
bool shouldBeAttached(CBonusSystemNode *dest);
bool shouldBeAttached(CBonusSystemNode *dest) override;
//CBonusSystemNode *getDestNode(CBonusSystemNode *source, CBonusSystemNode *redParent, CBonusSystemNode *redChild) override;
template <typename Handler> void serialize(Handler &h, const int version)
@ -651,7 +653,7 @@ public:
void limitBonuses(const BonusList &allBonuses, BonusList &out) const; //out will bo populed with bonuses that are not limited here
TBonusListPtr limitBonuses(const BonusList &allBonuses) const; //same as above, returns out by val for convienence
const TBonusListPtr getAllBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = nullptr, const std::string &cachingStr = "") const;
const TBonusListPtr getAllBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = nullptr, const std::string &cachingStr = "") const override;
void getParents(TCNodes &out) const; //retrieves list of parent nodes (nodes to inherit bonuses from),
const Bonus *getBonusLocalFirst(const CSelector &selector) const;

View File

@ -167,10 +167,11 @@ struct YourTurn : public CPackForClient //100
DLL_LINKAGE void applyGs(CGameState *gs);
PlayerColor player;
boost::optional<ui8> daysWithoutCastle;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & player;
h & player & daysWithoutCastle;
}
};
@ -986,7 +987,6 @@ struct NewTurn : public CPackForClient //101
std::map<PlayerColor, TResources> res; //player ID => resource value[res_id]
std::map<ObjectInstanceID, SetAvailableCreatures> cres;//creatures to be placed in towns
ui32 day;
bool resetBuilded;
ui8 specialWeek; //weekType
CreatureID creatureid; //for creature weeks
@ -994,7 +994,7 @@ struct NewTurn : public CPackForClient //101
template <typename Handler> void serialize(Handler &h, const int version)
{
h & heroes & cres & res & day & resetBuilded & specialWeek & creatureid;
h & heroes & cres & res & day & specialWeek & creatureid;
}
};
@ -1324,7 +1324,7 @@ struct StacksHealedOrResurrected : public CPackForClient //3013
{
ui32 stackID;
ui32 healedHP;
ui8 lowLevelResurrection; //in case this stack is resurrected by this heal, it will be marked as SUMMONED //TODO: replace with separate counter
bool lowLevelResurrection; //in case this stack is resurrected by this heal, it will be marked as SUMMONED //TODO: replace with separate counter
template <typename Handler> void serialize(Handler &h, const int version)
{
h & stackID & healedHP & lowLevelResurrection;
@ -1503,7 +1503,7 @@ struct BattleSpellCast : public CPackForClient//3009
std::vector<CustomEffect> customEffects;
std::set<ui32> affectedCres; //ids of creatures affected by this spell, generally used if spell does not set any effect (like dispel or cure)
si32 casterStack;// -1 if not cated by creature, >=0 caster stack ID
bool castByHero; //if true - spell has been casted by hero, otherwise by a creature
bool castByHero; //if true - spell has been cast by hero, otherwise by a creature
template <typename Handler> void serialize(Handler &h, const int version)
{
h & dmgToDisplay & side & id & skill & manaGained & tile & customEffects & affectedCres & casterStack & castByHero;
@ -1605,7 +1605,7 @@ struct BattleStacksRemoved : public CPackForClient //3016
BattleStacksRemoved(){type = 3016;}
DLL_LINKAGE void applyGs(CGameState *gs);
void applyCl(CClient *cl);
void applyFirstCl(CClient *cl);//inform client before stack objects are destroyed
std::set<ui32> stackIDs; //IDs of removed stacks

View File

@ -115,7 +115,7 @@ public:
numbers.clear();
}
void toString(std::string &dst) const;
std::string toString() const;
std::string toString() const override;
void getLocalString(const std::pair<ui8,ui32> &txt, std::string &dst) const;
MetaString()

View File

@ -468,6 +468,12 @@ static int getDir(int3 src, int3 dst)
void TryMoveHero::applyGs( CGameState *gs )
{
CGHeroInstance *h = gs->getHero(id);
if (!h)
{
logGlobal->errorStream() << "Attempt ot move unavailable hero " << id;
return;
}
h->movement = movePoints;
if((result == SUCCESS || result == BLOCKING_VISIT || result == EMBARK || result == DISEMBARK) && start != end)
@ -1136,7 +1142,7 @@ DLL_LINKAGE void BattleTriggerEffect::applyGs( CGameState *gs )
}
case Bonus::POISON:
{
Bonus * b = st->getBonusLocalFirst(Selector::source(Bonus::SPELL_EFFECT, 71)
Bonus * b = st->getBonusLocalFirst(Selector::source(Bonus::SPELL_EFFECT, SpellID::POISON)
.And(Selector::type(Bonus::STACK_HEALTH)));
if (b)
b->val = val;
@ -1459,21 +1465,17 @@ DLL_LINKAGE void StacksHealedOrResurrected::applyGs( CGameState *gs )
}
}
vstd::amin(changedStack->firstHPleft, changedStack->MaxHealth());
//removal of negative effects
if(resurrected)
{
//removing all features from negative spells
const BonusList tmpFeatures = changedStack->getBonusList();
//changedStack->bonuses.clear();
for(Bonus *b : tmpFeatures)
//removing all effects from negative spells
auto selector = [](const Bonus * b)
{
const CSpell *s = b->sourceSpell();
if(s && s->isNegative())
{
changedStack->removeBonus(b);
}
}
//Special case: DISRUPTING_RAY is "immune" to dispell
//Other even PERMANENT effects can be removed
return (s != nullptr) && s->isNegative() && (s->id != SpellID::DISRUPTING_RAY);
};
changedStack->popBonuses(selector);
}
}
}
@ -1621,18 +1623,8 @@ DLL_LINKAGE void YourTurn::applyGs( CGameState *gs )
{
gs->currentPlayer = player;
//count days without town
auto & playerState = gs->players[player];
if(playerState.towns.empty())
{
if(playerState.daysWithoutCastle)
++(*playerState.daysWithoutCastle);
else playerState.daysWithoutCastle = 0;
}
else
{
playerState.daysWithoutCastle = boost::none;
}
playerState.daysWithoutCastle = daysWithoutCastle;
}
DLL_LINKAGE Component::Component(const CStackBasicDescriptor &stack)

View File

@ -30,6 +30,7 @@
<Add option="-lboost_thread$(#boost.libsuffix)" />
<Add option="-lboost_chrono$(#boost.libsuffix)" />
<Add option="-lboost_locale$(#boost.libsuffix)" />
<Add option="-lboost_date_time$(#boost.libsuffix)" />
<Add option="-liconv" />
<Add option="-ldbghelp" />
<Add directory="$(#sdl2.lib)" />
@ -59,6 +60,7 @@
<Add option="-lboost_thread$(#boost.libsuffix)" />
<Add option="-lboost_chrono$(#boost.libsuffix)" />
<Add option="-lboost_locale$(#boost.libsuffix)" />
<Add option="-lboost_date_time$(#boost.libsuffix)" />
<Add option="-liconv" />
<Add option="-ldbghelp" />
<Add directory="$(#sdl2.lib)" />
@ -89,6 +91,7 @@
<Add option="-lboost_thread$(#boost.libsuffix)" />
<Add option="-lboost_chrono$(#boost.libsuffix)" />
<Add option="-lboost_locale$(#boost.libsuffix)" />
<Add option="-lboost_date_time$(#boost.libsuffix)" />
<Add option="-liconv" />
<Add option="-ldbghelp" />
<Add directory="$(#sdl2.lib64)" />

View File

@ -42,7 +42,7 @@ public:
bool existsResource(const ResourceID & resourceName) const override;
std::string getMountPoint() const override;
boost::optional<std::string> getResourceName(const ResourceID & resourceName) const override;
std::unordered_set<ResourceID> getFilteredFiles(std::function<bool(const ResourceID &)> filter) const;
std::unordered_set<ResourceID> getFilteredFiles(std::function<bool(const ResourceID &)> filter) const override;
private:
/** A list of files in this map

View File

@ -62,7 +62,7 @@ public:
std::unique_ptr<CInputStream> load(const ResourceID & resourceName) const override;
bool existsResource(const ResourceID & resourceName) const override;
std::string getMountPoint() const override;
std::unordered_set<ResourceID> getFilteredFiles(std::function<bool(const ResourceID &)> filter) const;
std::unordered_set<ResourceID> getFilteredFiles(std::function<bool(const ResourceID &)> filter) const override;
private:
/**

View File

@ -116,7 +116,7 @@ private:
/**
* Decompresses data to ensure that buffer has newSize bytes or end of stream was reached
*/
si64 readMore(ui8 * data, si64 size);
si64 readMore(ui8 * data, si64 size) override;
/** The file stream with compressed data. */
std::unique_ptr<CInputStream> gzipStream;

View File

@ -58,56 +58,49 @@ static int lowestSpeed(const CGHeroInstance * chi)
ui32 CGHeroInstance::getTileCost(const TerrainTile &dest, const TerrainTile &from) const
{
//base move cost
unsigned ret = 100;
unsigned ret = GameConstants::BASE_MOVEMENT_COST;
//if there is road both on dest and src tiles - use road movement cost
if(dest.roadType != ERoadType::NO_ROAD && from.roadType != ERoadType::NO_ROAD)
if(dest.roadType != ERoadType::NO_ROAD && from.roadType != ERoadType::NO_ROAD)
{
int road = std::min(dest.roadType,from.roadType); //used road ID
int road = std::min(dest.roadType,from.roadType); //used road ID
switch(road)
{
case ERoadType::DIRT_ROAD:
case ERoadType::DIRT_ROAD:
ret = 75;
break;
case ERoadType::GRAVEL_ROAD:
case ERoadType::GRAVEL_ROAD:
ret = 65;
break;
case ERoadType::COBBLESTONE_ROAD:
case ERoadType::COBBLESTONE_ROAD:
ret = 50;
break;
default:
logGlobal->errorStream() << "Unknown road type: " << road << "... Something wrong!";
logGlobal->errorStream() << "Unknown road type: " << road << "... Something wrong!";
break;
}
}
else
else if(!hasBonusOfType(Bonus::NO_TERRAIN_PENALTY, from.terType))
{
//FIXME: in H3 presence of Nomad in army will remove terrain penalty for sand. Bonus not implemented in VCMI
// NOTE: in H3 neutral stacks will ignore terrain penalty only if placed as topmost stack(s) in hero army.
// This is clearly bug in H3 however intended behaviour is not clear.
// Current VCMI behaviour will ignore neutrals in calculations so army in VCMI
// will always have best penalty without any influence from player-defined stacks order
bool nativeArmy = true;
for(auto stack : stacks)
{
int nativeTerrain = VLC->townh->factions[stack.second->type->faction]->nativeTerrain;
if (nativeTerrain != -1 && nativeTerrain != from.terType)
if(nativeTerrain != -1 && nativeTerrain != from.terType)
{
nativeArmy = false;
ret = VLC->heroh->terrCosts[from.terType];
ret -= getSecSkillLevel(SecondarySkill::PATHFINDING) * 25;
if(ret < GameConstants::BASE_MOVEMENT_COST)
ret = GameConstants::BASE_MOVEMENT_COST;
break;
}
}
if (!nativeArmy)
{
ret = VLC->heroh->terrCosts[from.terType];
ret-=getSecSkillLevel(SecondarySkill::PATHFINDING)*25;
ret = ret < 100 ? 100 : ret;
}
}
}
return ret;
}
@ -902,6 +895,33 @@ ui32 CGHeroInstance::getSpellBonus(const CSpell * spell, ui32 base, const CStack
return base;
}
int CGHeroInstance::getEffectLevel(const CSpell * spell) const
{
if(hasBonusOfType(Bonus::MAXED_SPELL, spell->id))
return 3;//todo: recheck specialty from where this bonus is. possible bug
else
return getSpellSchoolLevel(spell);
}
int CGHeroInstance::getEffectPower(const CSpell * spell) const
{
return getPrimSkillLevel(PrimarySkill::SPELL_POWER);
}
int CGHeroInstance::getEnchantPower(const CSpell * spell) const
{
return getPrimSkillLevel(PrimarySkill::SPELL_POWER) + valOfBonuses(Bonus::SPELL_DURATION);
}
int CGHeroInstance::getEffectValue(const CSpell * spell) const
{
return 0;
}
const PlayerColor CGHeroInstance::getOwner() const
{
return tempOwner;
}
bool CGHeroInstance::canCastThisSpell(const CSpell * spell) const
{
@ -939,7 +959,7 @@ bool CGHeroInstance::canCastThisSpell(const CSpell * spell) const
{//hero has this spell in spellbook
logGlobal->errorStream() << "Banned spell " << spell->name << " in spellbook.";
}
return specificBonus;
return specificBonus || schoolBonus || levelBonus;
}
else
{

View File

@ -117,18 +117,18 @@ public:
} skillsInfo;
//int3 getSightCenter() const; //"center" tile from which the sight distance is calculated
int getSightRadious() const; //sight distance (should be used if player-owned structure)
int getSightRadious() const override; //sight distance (should be used if player-owned structure)
//////////////////////////////////////////////////////////////////////////
int getBoatType() const; //0 - evil (if a ship can be evil...?), 1 - good, 2 - neutral
void getOutOffsets(std::vector<int3> &offsets) const; //offsets to obj pos when we boat can be placed
int getBoatType() const override; //0 - evil (if a ship can be evil...?), 1 - good, 2 - neutral
void getOutOffsets(std::vector<int3> &offsets) const override; //offsets to obj pos when we boat can be placed
//////////////////////////////////////////////////////////////////////////
bool hasSpellbook() const;
EAlignment::EAlignment getAlignment() const;
const std::string &getBiography() const;
bool needsLastStack()const;
bool needsLastStack()const override;
ui32 getTileCost(const TerrainTile &dest, const TerrainTile &from) const; //move cost - applying pathfinding skill, road and terrain modifiers. NOT includes diagonal move penalty, last move levelling
ui32 getLowestCreatureSpeed() const;
int3 getPosition(bool h3m = false) const; //h3m=true - returns position of hero object; h3m=false - returns position of hero 'manifestation'
@ -177,7 +177,7 @@ public:
//////////////////////////////////////////////////////////////////////////
void setType(si32 ID, si32 subID);
void setType(si32 ID, si32 subID) override;
void initHero();
void initHero(HeroTypeID SUBID);
@ -210,6 +210,20 @@ public:
ui8 getSpellSchoolLevel(const CSpell * spell, int *outSelectedSchool = nullptr) const override;
ui32 getSpellBonus(const CSpell * spell, ui32 base, const CStack * affectedStack) const override;
///default spell school level for effect calculation
int getEffectLevel(const CSpell * spell) const override;
///default spell-power for damage/heal calculation
int getEffectPower(const CSpell * spell) const override;
///default spell-power for timed effects duration
int getEnchantPower(const CSpell * spell) const override;
///damage/heal override(ignores spell configuration, effect level and effect power)
int getEffectValue(const CSpell * spell) const override;
const PlayerColor getOwner() const override;
void deserializationFix();
void initObj() override;

View File

@ -76,7 +76,7 @@ class DLL_LINKAGE CGUniversity : public CGMarket
public:
std::vector<int> skills; //available skills
std::vector<int> availableItemsIds(EMarketMode::EMarketMode mode) const;
std::vector<int> availableItemsIds(EMarketMode::EMarketMode mode) const override;
void initObj() override;//set skills for trade
void onHeroVisit(const CGHeroInstance * h) const override; //open window

View File

@ -184,7 +184,7 @@ void CGDwelling::updateGuards() const
//default condition - creatures are of level 5 or higher
for (auto creatureEntry : creatures)
{
if (VLC->creh->creatures[creatureEntry.second.at(0)]->level >= 5)
if (VLC->creh->creatures[creatureEntry.second.at(0)]->level >= 5 && ID != Obj::REFUGEE_CAMP)
{
guarded = true;
break;

View File

@ -203,21 +203,21 @@ public:
//////////////////////////////////////////////////////////////////////////
bool passableFor(PlayerColor color) const;
bool passableFor(PlayerColor color) const override;
//int3 getSightCenter() const override; //"center" tile from which the sight distance is calculated
int getSightRadious() const override; //returns sight distance
int getBoatType() const; //0 - evil (if a ship can be evil...?), 1 - good, 2 - neutral
void getOutOffsets(std::vector<int3> &offsets) const; //offsets to obj pos when we boat can be placed. Parameter will be cleared
int getBoatType() const override; //0 - evil (if a ship can be evil...?), 1 - good, 2 - neutral
void getOutOffsets(std::vector<int3> &offsets) const override; //offsets to obj pos when we boat can be placed. Parameter will be cleared
int getMarketEfficiency() const override; //=market count
bool allowsTrade(EMarketMode::EMarketMode mode) const;
std::vector<int> availableItemsIds(EMarketMode::EMarketMode mode) const;
bool allowsTrade(EMarketMode::EMarketMode mode) const override;
std::vector<int> availableItemsIds(EMarketMode::EMarketMode mode) const override;
void setType(si32 ID, si32 subID);
void setType(si32 ID, si32 subID) override;
void updateAppearance();
//////////////////////////////////////////////////////////////////////////
bool needsLastStack() const;
bool needsLastStack() const override;
CGTownInstance::EFortLevel fortLevel() const;
int hallLevel() const; // -1 - none, 0 - village, 1 - town, 2 - city, 3 - capitol
int mageGuildLevel() const; // -1 - none, 0 - village, 1 - town, 2 - city, 3 - capitol

View File

@ -156,7 +156,7 @@ protected:
class DLL_LINKAGE CGKeymasterTent : public CGKeys
{
public:
bool wasVisited (PlayerColor player) const;
bool wasVisited (PlayerColor player) const override;
void onHeroVisit(const CGHeroInstance * h) const override;
template <typename Handler> void serialize(Handler &h, const int version)
@ -173,9 +173,9 @@ public:
void onHeroVisit(const CGHeroInstance * h) const override;
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
void getVisitText (MetaString &text, std::vector<Component> &components, bool isCustom, bool FirstVisit, const CGHeroInstance * h = nullptr) const;
void getVisitText (MetaString &text, std::vector<Component> &components, bool isCustom, bool FirstVisit, const CGHeroInstance * h = nullptr) const override;
void getRolloverText (MetaString &text, bool onHover) const;
bool checkQuest (const CGHeroInstance * h) const;
bool checkQuest (const CGHeroInstance * h) const override;
template <typename Handler> void serialize(Handler &h, const int version)
{

View File

@ -313,17 +313,15 @@ void CBankInstanceConstructor::configureObject(CGObjectInstance * object, CRando
si32 selectedChance = rng.nextInt(totalChance - 1);
//logGlobal->debugStream() << "Selected chance for bank config is " << selectedChance;
int cumulativeChance = 0;
for (auto & node : levels)
{
if (selectedChance < node["chance"].Float())
cumulativeChance += node["chance"].Float();
if (selectedChance < cumulativeChance)
{
bank->setConfig(generateConfig(node, rng));
break;
}
else
{
selectedChance -= node["chance"].Float();
}
}
}

View File

@ -39,16 +39,16 @@ protected:
public:
CDefaultObjectTypeHandler(){}
CGObjectInstance * create(ObjectTemplate tmpl) const
CGObjectInstance * create(ObjectTemplate tmpl) const override
{
return createTyped(tmpl);
}
virtual void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const
virtual void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override
{
}
virtual std::unique_ptr<IObjectInfo> getObjectInfo(ObjectTemplate tmpl) const
virtual std::unique_ptr<IObjectInfo> getObjectInfo(ObjectTemplate tmpl) const override
{
return nullptr;
}
@ -58,24 +58,24 @@ class CObstacleConstructor : public CDefaultObjectTypeHandler<CGObjectInstance>
{
public:
CObstacleConstructor();
bool isStaticObject();
bool isStaticObject() override;
};
class CTownInstanceConstructor : public CDefaultObjectTypeHandler<CGTownInstance>
{
JsonNode filtersJson;
protected:
bool objectFilter(const CGObjectInstance *, const ObjectTemplate &) const;
void initTypeData(const JsonNode & input);
bool objectFilter(const CGObjectInstance *, const ObjectTemplate &) const override;
void initTypeData(const JsonNode & input) override;
public:
CFaction * faction;
std::map<std::string, LogicalExpression<BuildingID>> filters;
CTownInstanceConstructor();
CGObjectInstance * create(ObjectTemplate tmpl) const;
void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const;
void afterLoadFinalization();
CGObjectInstance * create(ObjectTemplate tmpl) const override;
void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override;
void afterLoadFinalization() override;
template <typename Handler> void serialize(Handler &h, const int version)
{
@ -88,17 +88,17 @@ class CHeroInstanceConstructor : public CDefaultObjectTypeHandler<CGHeroInstance
{
JsonNode filtersJson;
protected:
bool objectFilter(const CGObjectInstance *, const ObjectTemplate &) const;
void initTypeData(const JsonNode & input);
bool objectFilter(const CGObjectInstance *, const ObjectTemplate &) const override;
void initTypeData(const JsonNode & input) override;
public:
CHeroClass * heroClass;
std::map<std::string, LogicalExpression<HeroTypeID>> filters;
CHeroInstanceConstructor();
CGObjectInstance * create(ObjectTemplate tmpl) const;
void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const;
void afterLoadFinalization();
CGObjectInstance * create(ObjectTemplate tmpl) const override;
void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override;
void afterLoadFinalization() override;
template <typename Handler> void serialize(Handler &h, const int version)
{
@ -114,14 +114,14 @@ class CDwellingInstanceConstructor : public CDefaultObjectTypeHandler<CGDwelling
JsonNode guards;
protected:
bool objectFilter(const CGObjectInstance *, const ObjectTemplate &) const;
void initTypeData(const JsonNode & input);
bool objectFilter(const CGObjectInstance *, const ObjectTemplate &) const override;
void initTypeData(const JsonNode & input) override;
public:
CDwellingInstanceConstructor();
CGObjectInstance * create(ObjectTemplate tmpl) const;
void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const;
CGObjectInstance * create(ObjectTemplate tmpl) const override;
void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override;
bool producesCreature(const CCreature * crea) const;
std::vector<const CCreature *> getProducedCreatures() const;
@ -163,13 +163,13 @@ public:
TPossibleGuards getPossibleGuards() const;
// These functions should try to evaluate minimal possible/max possible guards to give provide information on possible thread to AI
CArmyStructure minGuards() const;
CArmyStructure maxGuards() const;
CArmyStructure minGuards() const override;
CArmyStructure maxGuards() const override;
bool givesResources() const;
bool givesArtifacts() const;
bool givesCreatures() const;
bool givesSpells() const;
bool givesResources() const override;
bool givesArtifacts() const override;
bool givesCreatures() const override;
bool givesSpells() const override;
};
class CBankInstanceConstructor : public CDefaultObjectTypeHandler<CBank>
@ -178,7 +178,7 @@ class CBankInstanceConstructor : public CDefaultObjectTypeHandler<CBank>
JsonVector levels;
protected:
void initTypeData(const JsonNode & input);
void initTypeData(const JsonNode & input) override;
public:
// all banks of this type will be reset N days after clearing,
@ -186,10 +186,10 @@ public:
CBankInstanceConstructor();
CGObjectInstance *create(ObjectTemplate tmpl) const;
void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const;
CGObjectInstance *create(ObjectTemplate tmpl) const override;
void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override;
std::unique_ptr<IObjectInfo> getObjectInfo(ObjectTemplate tmpl) const;
std::unique_ptr<IObjectInfo> getObjectInfo(ObjectTemplate tmpl) const override;
template <typename Handler> void serialize(Handler &h, const int version)
{

View File

@ -19,7 +19,7 @@ class DLL_LINKAGE CPlayersVisited: public CGObjectInstance
public:
std::set<PlayerColor> players; //players that visited this object
bool wasVisited(PlayerColor player) const;
bool wasVisited(PlayerColor player) const override;
bool wasVisited(TeamID team) const;
void setPropertyDer(ui8 what, ui32 val) override;
@ -394,7 +394,7 @@ public:
class CGShipyard : public CGObjectInstance, public IShipyard
{
public:
void getOutOffsets(std::vector<int3> &offsets) const; //offsets to obj pos when we boat can be placed
void getOutOffsets(std::vector<int3> &offsets) const override; //offsets to obj pos when we boat can be placed
CGShipyard();
void onHeroVisit(const CGHeroInstance * h) const override;

View File

@ -50,14 +50,14 @@ public:
*
* @return a unique ptr of the loaded map class
*/
std::unique_ptr<CMap> loadMap();
std::unique_ptr<CMap> loadMap() override;
/**
* Loads the VCMI/H3 map header.
*
* @return a unique ptr of the loaded map header class
*/
std::unique_ptr<CMapHeader> loadMapHeader();
std::unique_ptr<CMapHeader> loadMapHeader() override;
/** true if you want to enable the map loader profiler to see how long a specific part took; default=false */
static const bool IS_PROFILING_ENABLED;

View File

@ -31,20 +31,20 @@ public:
*
* @return a unique ptr of the loaded map class
*/
std::unique_ptr<CMap> loadMap();
std::unique_ptr<CMap> loadMap() override;
/**
* Loads the VCMI/Json map header.
*
* @return a unique ptr of the loaded map header class
*/
std::unique_ptr<CMapHeader> loadMapHeader();
std::unique_ptr<CMapHeader> loadMapHeader() override;
/**
* Modifies supplied map header using Json data
*
*/
void patchMapHeader(std::unique_ptr<CMapHeader> & header);
void patchMapHeader(std::unique_ptr<CMapHeader> & header) override;
private:
/**

View File

@ -93,8 +93,8 @@ void CMapGenerator::initQuestArtsRemaining()
{
for (auto art : VLC->arth->artifacts)
{
if (art->aClass == CArtifact::ART_TREASURE && art->constituentOf.empty()) //don't use parts of combined artifacts
questArtifacts.push_back(art->id);
if (art->aClass == CArtifact::ART_TREASURE && VLC->arth->legalArtifact(art->id) && art->constituentOf.empty()) //don't use parts of combined artifacts
questArtifacts.push_back(art->id);
}
}

View File

@ -28,12 +28,12 @@ public:
const std::map<std::string, CRmgTemplate *> & getTemplates() const;
std::vector<bool> getDefaultAllowed() const;
std::vector<JsonNode> loadLegacyData(size_t dataSize);
std::vector<bool> getDefaultAllowed() const override;
std::vector<JsonNode> loadLegacyData(size_t dataSize) override;
/// loads single object into game. Scope is namespace of this object, same as name of source mod
virtual void loadObject(std::string scope, std::string name, const JsonNode & data);
virtual void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index);
virtual void loadObject(std::string scope, std::string name, const JsonNode & data) override;
virtual void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override;
private:
CRmgTemplate::CSize parseMapTemplateSize(const std::string & text) const;

View File

@ -1506,7 +1506,10 @@ bool CRmgTemplateZone::placeMines (CMapGenerator* gen)
mine->subID = static_cast<si32>(res);
mine->producedResource = res;
mine->producedQuantity = mine->defaultResProduction();
addCloseObject(mine, 1500);
if (!i)
addCloseObject(mine, 1500); //only firts one is close
else
addRequiredObject(mine, 1500);
}
}
for (const auto & res : preciousResources)
@ -1587,7 +1590,12 @@ bool CRmgTemplateZone::createRequiredObjects(CMapGenerator* gen)
// smallest distance to zone center, greatest distance to nearest object
auto isCloser = [this, gen](const int3 & lhs, const int3 & rhs) -> bool
{
return (this->pos.dist2dSQ(lhs) * 0.5f - gen->getNearestObjectDistance(lhs)) < (this->pos.dist2dSQ(rhs) * 0.5f - gen->getNearestObjectDistance(rhs));
float lDist = this->pos.dist2d(lhs);
float rDist = this->pos.dist2d(rhs);
lDist *= (lDist > 12) ? 10 : 1; //objects within 12 tile radius are preferred (smaller distance rating)
rDist *= (rDist > 12) ? 10 : 1;
return (lDist * 0.5f - std::sqrt(gen->getNearestObjectDistance(lhs))) < (rDist * 0.5f - std::sqrt(gen->getNearestObjectDistance(rhs)));
};
boost::sort (tiles, isCloser);

View File

@ -13,6 +13,37 @@
#include "../NetPacks.h"
#include "../BattleState.h"
#include "../mapObjects/CGHeroInstance.h"
///HealingSpellMechanics
void HealingSpellMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
{
EHealLevel healLevel = getHealLevel(parameters.effectLevel);
int hpGained = calculateHealedHP(env, parameters, ctx);
StacksHealedOrResurrected shr;
shr.lifeDrain = false;
shr.tentHealing = false;
const bool resurrect = (healLevel != EHealLevel::HEAL);
for(auto & attackedCre : ctx.attackedCres)
{
StacksHealedOrResurrected::HealInfo hi;
hi.stackID = (attackedCre)->ID;
int stackHPgained = parameters.caster->getSpellBonus(owner, hpGained, attackedCre);
hi.healedHP = attackedCre->calculateHealedHealthPoints(stackHPgained, resurrect);
hi.lowLevelResurrection = (healLevel == EHealLevel::RESURRECT);
shr.healedStacks.push_back(hi);
}
if(!shr.healedStacks.empty())
env->sendAndApply(&shr);
}
int HealingSpellMechanics::calculateHealedHP(const SpellCastEnvironment* env, const BattleSpellCastParameters& parameters, SpellCastContext& ctx) const
{
if(parameters.effectValue != 0)
return parameters.effectValue; //Archangel
return owner->calculateRawEffectValue(parameters.effectLevel, parameters.effectPower); //???
}
///AntimagicMechanics
void AntimagicMechanics::applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const
@ -67,7 +98,7 @@ std::set<const CStack *> ChainLightningMechanics::getAffectedStacks(SpellTargeti
}
///CloneMechanics
void CloneMechanics::applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
void CloneMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
{
const CStack * clonedStack = nullptr;
if(ctx.attackedCres.size())
@ -101,23 +132,21 @@ void CloneMechanics::applyBattleEffects(const SpellCastEnvironment * env, Battle
env->sendAndApply(&ssp);
}
ESpellCastProblem::ESpellCastProblem CloneMechanics::isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const
ESpellCastProblem::ESpellCastProblem CloneMechanics::isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const
{
//can't clone already cloned creature
if(vstd::contains(obj->state, EBattleStackState::CLONED))
return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
if(obj->cloneID != -1)
return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
//TODO: how about stacks casting Clone?
//currently Clone casted by stack is assumed Expert level
ui8 schoolLevel;
if(caster)
{
schoolLevel = caster->getSpellSchoolLevel(owner);
schoolLevel = caster->getEffectLevel(owner);
}
else
{
schoolLevel = 3;
schoolLevel = 3;//todo: remove
}
if(schoolLevel < 3)
@ -146,6 +175,11 @@ void CureMechanics::applyBattle(BattleInfo * battle, const BattleSpellCast * pac
});
}
HealingSpellMechanics::EHealLevel CureMechanics::getHealLevel(int effectLevel) const
{
return EHealLevel::HEAL;
}
///DispellMechanics
void DispellMechanics::applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const
{
@ -153,21 +187,35 @@ void DispellMechanics::applyBattle(BattleInfo * battle, const BattleSpellCast *
doDispell(battle, packet, Selector::sourceType(Bonus::SPELL_EFFECT));
}
ESpellCastProblem::ESpellCastProblem DispellMechanics::isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const
ESpellCastProblem::ESpellCastProblem DispellMechanics::isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const
{
//DISPELL ignores all immunities, so do not call default
std::stringstream cachingStr;
cachingStr << "source_" << Bonus::SPELL_EFFECT;
if(obj->hasBonus(Selector::sourceType(Bonus::SPELL_EFFECT), cachingStr.str()))
{
return ESpellCastProblem::OK;
//just in case
if(!obj->alive())
return ESpellCastProblem::WRONG_SPELL_TARGET;
}
//DISPELL ignores all immunities, except specific absolute immunity
{
//SPELL_IMMUNITY absolute case
std::stringstream cachingStr;
cachingStr << "type_" << Bonus::SPELL_IMMUNITY << "subtype_" << owner->id.toEnum() << "addInfo_1";
if(obj->hasBonus(Selector::typeSubtypeInfo(Bonus::SPELL_IMMUNITY, owner->id.toEnum(), 1), cachingStr.str()))
return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
}
{
std::stringstream cachingStr;
cachingStr << "source_" << Bonus::SPELL_EFFECT;
if(obj->hasBonus(Selector::sourceType(Bonus::SPELL_EFFECT), cachingStr.str()))
{
return ESpellCastProblem::OK;
}
}
return ESpellCastProblem::WRONG_SPELL_TARGET;
//any other immunities are ignored - do not execute default algorithm
}
void DispellMechanics::applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
void DispellMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
{
DefaultSpellMechanics::applyBattleEffects(env, parameters, ctx);
@ -190,15 +238,15 @@ void DispellMechanics::applyBattleEffects(const SpellCastEnvironment * env, Batt
}
///EarthquakeMechanics
void EarthquakeMechanics::applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
void EarthquakeMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
{
if(nullptr == parameters.cb->town)
if(nullptr == parameters.cb->battleGetDefendedTown())
{
env->complain("EarthquakeMechanics: not town siege");
return;
}
if(CGTownInstance::NONE == parameters.cb->town->fortLevel())
if(CGTownInstance::NONE == parameters.cb->battleGetDefendedTown()->fortLevel())
{
env->complain("EarthquakeMechanics: town has no fort");
return;
@ -277,7 +325,7 @@ void EarthquakeMechanics::applyBattleEffects(const SpellCastEnvironment * env, B
env->sendAndApply(&ca);
}
ESpellCastProblem::ESpellCastProblem EarthquakeMechanics::canBeCasted(const CBattleInfoCallback * cb, PlayerColor player) const
ESpellCastProblem::ESpellCastProblem EarthquakeMechanics::canBeCast(const CBattleInfoCallback * cb, PlayerColor player) const
{
if(nullptr == cb->battleGetDefendedTown())
{
@ -288,8 +336,9 @@ ESpellCastProblem::ESpellCastProblem EarthquakeMechanics::canBeCasted(const CBat
{
return ESpellCastProblem::NO_APPROPRIATE_TARGET;
}
if(owner->getTargetInfo(0).smart) //TODO: use real spell level
CSpell::TargetInfo ti(owner, 0);//TODO: use real spell level
if(ti.smart)
{
//if spell targeting is smart, then only attacker can use it
if(cb->playerToSide(player) != 0)
@ -300,15 +349,15 @@ ESpellCastProblem::ESpellCastProblem EarthquakeMechanics::canBeCasted(const CBat
}
///HypnotizeMechanics
ESpellCastProblem::ESpellCastProblem HypnotizeMechanics::isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const
ESpellCastProblem::ESpellCastProblem HypnotizeMechanics::isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const
{
if(nullptr != caster) //do not resist hypnotize casted after attack, for example
//todo: maybe do not resist on passive cast
if(nullptr != caster)
{
//TODO: what with other creatures casting hypnotize, Faerie Dragons style?
ui64 subjectHealth = (obj->count - 1) * obj->MaxHealth() + obj->firstHPleft;
//apply 'damage' bonus for hypnotize, including hero specialty
ui64 maxHealth = caster->getSpellBonus(owner, caster->getPrimSkillLevel(PrimarySkill::SPELL_POWER)
* owner->power + owner->getPower(caster->getSpellSchoolLevel(owner)), obj);
ui64 maxHealth = caster->getSpellBonus(owner, owner->calculateRawEffectValue(caster->getEffectLevel(owner), caster->getEffectPower(owner)), obj);
if (subjectHealth > maxHealth)
return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
}
@ -316,9 +365,9 @@ ESpellCastProblem::ESpellCastProblem HypnotizeMechanics::isImmuneByStack(const C
}
///ObstacleMechanics
void ObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
void ObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
{
auto placeObstacle = [&, this](BattleHex pos)
auto placeObstacle = [&, this](const BattleHex & pos)
{
static int obstacleIdToGive = parameters.cb->obstacles.size()
? (parameters.cb->obstacles.back()->uniqueID+1)
@ -355,8 +404,8 @@ void ObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * env, Bat
obstacle->pos = pos;
obstacle->casterSide = parameters.casterSide;
obstacle->ID = owner->id;
obstacle->spellLevel = parameters.spellLvl;
obstacle->casterSpellPower = parameters.usedSpellPower;
obstacle->spellLevel = parameters.effectLevel;
obstacle->casterSpellPower = parameters.effectPower;
obstacle->uniqueID = obstacleIdToGive++;
BattleObstaclePlaced bop;
@ -364,6 +413,8 @@ void ObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * env, Bat
env->sendAndApply(&bop);
};
const BattleHex destination = parameters.getFirstDestinationHex();
switch(owner->id)
{
case SpellID::QUICKSAND:
@ -388,12 +439,22 @@ void ObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * env, Bat
break;
case SpellID::FORCE_FIELD:
placeObstacle(parameters.destination);
if(!destination.isValid())
{
env->complain("Invalid destination for FORCE_FIELD");
return;
}
placeObstacle(destination);
break;
case SpellID::FIRE_WALL:
{
if(!destination.isValid())
{
env->complain("Invalid destination for FIRE_WALL");
return;
}
//fire wall is build from multiple obstacles - one fire piece for each affected hex
auto affectedHexes = owner->rangeInHexes(parameters.destination, parameters.spellLvl, parameters.casterSide);
auto affectedHexes = owner->rangeInHexes(destination, parameters.spellLvl, parameters.casterSide);
for(BattleHex hex : affectedHexes)
placeObstacle(hex);
}
@ -442,9 +503,9 @@ std::vector<BattleHex> WallMechanics::rangeInHexes(BattleHex centralHex, ui8 sch
}
///RemoveObstacleMechanics
void RemoveObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
void RemoveObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
{
if(auto obstacleToRemove = parameters.cb->battleGetObstacleOnPos(parameters.destination, false))
if(auto obstacleToRemove = parameters.cb->battleGetObstacleOnPos(parameters.getFirstDestinationHex(), false))
{
ObstaclesRemoved obr;
obr.obstacles.insert(obstacleToRemove->uniqueID);
@ -454,20 +515,34 @@ void RemoveObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * en
env->complain("There's no obstacle to remove!");
}
///SpecialRisingSpellMechanics
ESpellCastProblem::ESpellCastProblem SacrificeMechanics::canBeCasted(const CBattleInfoCallback * cb, PlayerColor player) const
HealingSpellMechanics::EHealLevel RisingSpellMechanics::getHealLevel(int effectLevel) const
{
//this may be even distinct class
if((effectLevel <= 1) && (owner->id == SpellID::RESURRECTION))
return EHealLevel::RESURRECT;
return EHealLevel::TRUE_RESURRECT;
}
///SacrificeMechanics
ESpellCastProblem::ESpellCastProblem SacrificeMechanics::canBeCast(const CBattleInfoCallback * cb, PlayerColor player) const
{
// for sacrifice we have to check for 2 targets (one dead to resurrect and one living to destroy)
bool targetExists = false;
bool targetToSacrificeExists = false;
const CGHeroInstance * caster = nullptr; //todo: use ISpellCaster
if(cb->battleHasHero(cb->playerToSide(player)))
caster = cb->battleGetFightingHero(cb->playerToSide(player));
for(const CStack * stack : cb->battleGetAllStacks())
{
//using isImmuneBy directly as this mechanics does not have overridden immunity check
//therefore we do not need to check caster and casting mode
//TODO: check that we really should check immunity for both stacks
ESpellCastProblem::ESpellCastProblem res = owner->isImmuneBy(stack);
ESpellCastProblem::ESpellCastProblem res = owner->internalIsImmune(caster, stack);
const bool immune = ESpellCastProblem::OK != res && ESpellCastProblem::NOT_DECIDED != res;
const bool casterStack = stack->owner == player;
@ -489,39 +564,57 @@ ESpellCastProblem::ESpellCastProblem SacrificeMechanics::canBeCasted(const CBatt
}
void SacrificeMechanics::applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
void SacrificeMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
{
RisingSpellMechanics::applyBattleEffects(env, parameters, ctx);
if(parameters.selectedStack == parameters.cb->battleActiveStack())
//set another active stack than the one removed, or bad things will happen
//TODO: make that part of BattleStacksRemoved? what about client update?
const CStack * victim = nullptr;
if(parameters.destinations.size() == 2)
{
//makeStackDoNothing(gs->curB->getStack (selectedStack));
BattleSetActiveStack sas;
//std::vector<const CStack *> hlp;
//battleGetStackQueue(hlp, 1, selectedStack); //next after this one
//if(hlp.size())
//{
// sas.stack = hlp[0]->ID;
//}
//else
// complain ("No new stack to activate!");
sas.stack = parameters.cb->getNextStack()->ID; //why the hell next stack has same ID as current?
env->sendAndApply(&sas);
victim = parameters.destinations[1].stackValue;
}
else
{
//todo: remove and report error
victim = parameters.selectedStack;
}
if(nullptr == victim)
{
env->complain("SacrificeMechanics: No stack to sacrifice");
return;
}
//resurrect target after basic checks
RisingSpellMechanics::applyBattleEffects(env, parameters, ctx);
//it is safe to remove even active stack
BattleStacksRemoved bsr;
bsr.stackIDs.insert(parameters.selectedStack->ID); //somehow it works for teleport?
bsr.stackIDs.insert(victim->ID);
env->sendAndApply(&bsr);
}
int SacrificeMechanics::calculateHealedHP(const SpellCastEnvironment* env, const BattleSpellCastParameters& parameters, SpellCastContext& ctx) const
{
int res = 0;
const CStack * victim = nullptr;
if(parameters.destinations.size() == 2)
{
victim = parameters.destinations[1].stackValue;
}
else
{
//todo: remove and report error
victim = parameters.selectedStack;
}
if(nullptr == victim)
{
env->complain("SacrificeMechanics: No stack to sacrifice");
return 0;
}
res = (parameters.effectPower + victim->MaxHealth() + owner->getPower(parameters.effectLevel)) * victim->count;
return res;
}
///SpecialRisingSpellMechanics
ESpellCastProblem::ESpellCastProblem SpecialRisingSpellMechanics::isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const
ESpellCastProblem::ESpellCastProblem SpecialRisingSpellMechanics::isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const
{
// following does apply to resurrect and animate dead(?) only
// for sacrifice health calculation and health limit check don't matter
@ -529,18 +622,19 @@ ESpellCastProblem::ESpellCastProblem SpecialRisingSpellMechanics::isImmuneByStac
if(obj->count >= obj->baseAmount)
return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
if(caster) //FIXME: Archangels can cast immune stack
{
auto maxHealth = calculateHealedHP(caster, obj, nullptr);
if (maxHealth < obj->MaxHealth()) //must be able to rise at least one full creature
return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
}
//FIXME: Archangels can cast immune stack and this should be applied for them and not hero
// if(caster)
// {
// auto maxHealth = calculateHealedHP(caster, obj, nullptr);
// if (maxHealth < obj->MaxHealth()) //must be able to rise at least one full creature
// return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
// }
return DefaultSpellMechanics::isImmuneByStack(caster,obj);
}
///SummonMechanics
ESpellCastProblem::ESpellCastProblem SummonMechanics::canBeCasted(const CBattleInfoCallback * cb, PlayerColor player) const
ESpellCastProblem::ESpellCastProblem SummonMechanics::canBeCast(const CBattleInfoCallback * cb, PlayerColor player) const
{
const ui8 side = cb->playerToSide(player);
@ -559,7 +653,7 @@ ESpellCastProblem::ESpellCastProblem SummonMechanics::canBeCasted(const CBattleI
return ESpellCastProblem::OK;
}
void SummonMechanics::applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
void SummonMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
{
BattleStackAdded bsa;
bsa.creID = creatureToSummon;
@ -570,7 +664,7 @@ void SummonMechanics::applyBattleEffects(const SpellCastEnvironment * env, Battl
//TODO stack casting -> probably power will be zero; set the proper number of creatures manually
int percentBonus = parameters.casterHero ? parameters.casterHero->valOfBonuses(Bonus::SPECIFIC_SPELL_DAMAGE, owner->id.toEnum()) : 0;
bsa.amount = parameters.usedSpellPower
bsa.amount = parameters.effectPower
* owner->getPower(parameters.spellLvl)
* (100 + percentBonus) / 100.0; //new feature - percentage bonus
if(bsa.amount)
@ -580,15 +674,46 @@ void SummonMechanics::applyBattleEffects(const SpellCastEnvironment * env, Battl
}
///TeleportMechanics
void TeleportMechanics::applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
void TeleportMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
{
BattleStackMoved bsm;
bsm.distance = -1;
bsm.stack = parameters.selectedStack->ID;
std::vector<BattleHex> tiles;
tiles.push_back(parameters.destination);
bsm.tilesToMove = tiles;
bsm.teleporting = true;
env->sendAndApply(&bsm);
//todo: check legal teleport
if(parameters.destinations.size() == 2)
{
//first destination creature to move
const CStack * target = parameters.destinations[0].stackValue;
if(nullptr == target)
{
env->complain("TeleportMechanics: no stack to teleport");
return;
}
//second destination hex to move to
const BattleHex destination = parameters.destinations[1].hexValue;
if(!destination.isValid())
{
env->complain("TeleportMechanics: invalid teleport destination");
return;
}
BattleStackMoved bsm;
bsm.distance = -1;
bsm.stack = target->ID;
std::vector<BattleHex> tiles;
tiles.push_back(destination);
bsm.tilesToMove = tiles;
bsm.teleporting = true;
env->sendAndApply(&bsm);
}
else
{
//todo: remove and report error
BattleStackMoved bsm;
bsm.distance = -1;
bsm.stack = parameters.selectedStack->ID;
std::vector<BattleHex> tiles;
tiles.push_back(parameters.getFirstDestinationHex());
bsm.tilesToMove = tiles;
bsm.teleporting = true;
env->sendAndApply(&bsm);
}
}

View File

@ -12,6 +12,23 @@
#include "CDefaultSpellMechanics.h"
class DLL_LINKAGE HealingSpellMechanics : public DefaultSpellMechanics
{
public:
enum class EHealLevel
{
HEAL,
RESURRECT,
TRUE_RESURRECT
};
HealingSpellMechanics(CSpell * s): DefaultSpellMechanics(s){};
protected:
void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
virtual int calculateHealedHP(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const;
virtual EHealLevel getHealLevel(int effectLevel) const = 0;
};
class DLL_LINKAGE AntimagicMechanics : public DefaultSpellMechanics
{
public:
@ -31,44 +48,46 @@ class DLL_LINKAGE CloneMechanics : public DefaultSpellMechanics
{
public:
CloneMechanics(CSpell * s): DefaultSpellMechanics(s){};
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const override;
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const override;
protected:
void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
};
class DLL_LINKAGE CureMechanics : public DefaultSpellMechanics
class DLL_LINKAGE CureMechanics : public HealingSpellMechanics
{
public:
CureMechanics(CSpell * s): DefaultSpellMechanics(s){};
CureMechanics(CSpell * s): HealingSpellMechanics(s){};
void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const override final;
EHealLevel getHealLevel(int effectLevel) const override final;
};
class DLL_LINKAGE DispellMechanics : public DefaultSpellMechanics
{
public:
DispellMechanics(CSpell * s): DefaultSpellMechanics(s){};
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const override;
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const override;
void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const override final;
protected:
void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
};
class DLL_LINKAGE EarthquakeMechanics : public DefaultSpellMechanics
{
public:
EarthquakeMechanics(CSpell * s): DefaultSpellMechanics(s){};
ESpellCastProblem::ESpellCastProblem canBeCasted(const CBattleInfoCallback * cb, PlayerColor player) const override;
ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, PlayerColor player) const override;
protected:
void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
};
class DLL_LINKAGE HypnotizeMechanics : public DefaultSpellMechanics
{
public:
HypnotizeMechanics(CSpell * s): DefaultSpellMechanics(s){};
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const override;
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const override;
};
class DLL_LINKAGE ObstacleMechanics : public DefaultSpellMechanics
@ -77,7 +96,7 @@ public:
ObstacleMechanics(CSpell * s): DefaultSpellMechanics(s){};
protected:
void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
};
class DLL_LINKAGE WallMechanics : public ObstacleMechanics
@ -92,15 +111,15 @@ class DLL_LINKAGE RemoveObstacleMechanics : public DefaultSpellMechanics
public:
RemoveObstacleMechanics(CSpell * s): DefaultSpellMechanics(s){};
protected:
void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
};
///all rising spells
class DLL_LINKAGE RisingSpellMechanics : public DefaultSpellMechanics
class DLL_LINKAGE RisingSpellMechanics : public HealingSpellMechanics
{
public:
RisingSpellMechanics(CSpell * s): DefaultSpellMechanics(s){};
RisingSpellMechanics(CSpell * s): HealingSpellMechanics(s){};
EHealLevel getHealLevel(int effectLevel) const override;
};
class DLL_LINKAGE SacrificeMechanics : public RisingSpellMechanics
@ -108,9 +127,10 @@ class DLL_LINKAGE SacrificeMechanics : public RisingSpellMechanics
public:
SacrificeMechanics(CSpell * s): RisingSpellMechanics(s){};
ESpellCastProblem::ESpellCastProblem canBeCasted(const CBattleInfoCallback * cb, PlayerColor player) const override;
ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, PlayerColor player) const override;
protected:
void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
int calculateHealedHP(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
};
///all rising spells but SACRIFICE
@ -118,7 +138,7 @@ class DLL_LINKAGE SpecialRisingSpellMechanics : public RisingSpellMechanics
{
public:
SpecialRisingSpellMechanics(CSpell * s): RisingSpellMechanics(s){};
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const override;
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const override;
};
class DLL_LINKAGE SummonMechanics : public DefaultSpellMechanics
@ -126,9 +146,9 @@ class DLL_LINKAGE SummonMechanics : public DefaultSpellMechanics
public:
SummonMechanics(CSpell * s, CreatureID cre): DefaultSpellMechanics(s), creatureToSummon(cre){};
ESpellCastProblem::ESpellCastProblem canBeCasted(const CBattleInfoCallback * cb, PlayerColor player) const override;
ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, PlayerColor player) const override;
protected:
void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
private:
CreatureID creatureToSummon;
};
@ -138,5 +158,5 @@ class DLL_LINKAGE TeleportMechanics: public DefaultSpellMechanics
public:
TeleportMechanics(CSpell * s): DefaultSpellMechanics(s){};
protected:
void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
};

View File

@ -139,7 +139,7 @@ void DefaultSpellMechanics::applyBattle(BattleInfo * battle, const BattleSpellCa
//check for each bonus if it should be removed
const bool isSpellEffect = Selector::sourceType(Bonus::SPELL_EFFECT)(b);
const int spellID = isSpellEffect ? b->sid : -1;
//No exceptions, ANY spell can be countered, even if it can`t be dispelled.
return isSpellEffect && vstd::contains(owner->counteredSpells, spellID);
});
}
@ -223,29 +223,35 @@ ESpellCastResult DefaultSpellMechanics::applyAdventureEffects(const SpellCastEnv
void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const
{
logGlobal->debugStream() << "Started spell cast. Spell: "<<owner->name<<"; mode:"<<parameters.mode;
if(nullptr == parameters.caster)
{
env->complain("No spell-caster provided.");
return;
}
BattleSpellCast sc;
sc.side = parameters.casterSide;
sc.id = owner->id;
sc.skill = parameters.spellLvl;
sc.tile = parameters.destination;
sc.dmgToDisplay = 0;
sc.castByHero = nullptr != parameters.casterHero;
sc.casterStack = (parameters.casterStack ? parameters.casterStack->ID : -1);
sc.manaGained = 0;
prepareBattleCast(parameters, sc);
//check it there is opponent hero
const ui8 otherSide = 1-parameters.casterSide;
const CGHeroInstance * otherHero = nullptr;
if(parameters.cb->battleHasHero(otherSide))
otherHero = parameters.cb->battleGetFightingHero(otherSide);
int spellCost = 0;
//calculate spell cost
if(parameters.casterHero)
if(parameters.mode == ECastingMode::HERO_CASTING)
{
spellCost = parameters.cb->battleGetSpellCost(owner, parameters.casterHero);
if(parameters.secHero && parameters.mode == ECastingMode::HERO_CASTING) //handle mana channel
{
if(nullptr != otherHero) //handle mana channel
{
int manaChannel = 0;
for(const CStack * stack : parameters.cb->battleGetAllStacks(true)) //TODO: shouldn't bonus system handle it somehow?
{
if(stack->owner == parameters.secHero->tempOwner)
if(stack->owner == otherHero->tempOwner)
{
vstd::amax(manaChannel, stack->valOfBonuses(Bonus::MANA_CHANNELING));
}
@ -253,53 +259,36 @@ void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleS
sc.manaGained = (manaChannel * spellCost) / 100;
}
}
logGlobal->debugStream() << "spellCost: " << spellCost;
//calculating affected creatures for all spells
//must be vector, as in Chain Lightning order matters
std::vector<const CStack*> attackedCres; //CStack vector is somewhat more suitable than ID vector
auto creatures = owner->getAffectedStacks(parameters.cb, parameters.mode, parameters.casterColor, parameters.spellLvl, parameters.destination, parameters.casterHero);
auto creatures = owner->getAffectedStacks(parameters.cb, parameters.mode, parameters.casterColor, parameters.spellLvl, parameters.getFirstDestinationHex(), parameters.caster);
std::copy(creatures.begin(), creatures.end(), std::back_inserter(attackedCres));
logGlobal->debugStream() << "will affect: " << attackedCres.size() << " stacks";
std::vector <const CStack*> reflected;//for magic mirror
//checking if creatures resist
//resistance/reflection is applied only to negative spells
if(owner->isNegative())
//checking if creatures resist
handleResistance(env, attackedCres, sc);
//it is actual spell and can be reflected to single target, no recurrence
const bool tryMagicMirror = owner->isNegative() && owner->level && owner->getLevelInfo(0).range == "0";
if(tryMagicMirror)
{
//it is actual spell and can be reflected to single target, no recurrence
const bool tryMagicMirror = parameters.mode != ECastingMode::MAGIC_MIRROR && owner->level && owner->getLevelInfo(0).range == "0";
std::vector <const CStack*> resisted;
for(auto s : attackedCres)
{
//magic resistance
const int prob = std::min((s)->magicResistance(), 100); //probability of resistance in %
if(env->getRandomGenerator().nextInt(99) < prob)
{
resisted.push_back(s);
}
//magic mirror
if(tryMagicMirror)
{
const int mirrorChance = (s)->valOfBonuses(Bonus::MAGIC_MIRROR);
if(env->getRandomGenerator().nextInt(99) < mirrorChance)
reflected.push_back(s);
}
const int mirrorChance = (s)->valOfBonuses(Bonus::MAGIC_MIRROR);
if(env->getRandomGenerator().nextInt(99) < mirrorChance)
reflected.push_back(s);
}
vstd::erase_if(attackedCres, [&resisted, reflected](const CStack * s)
vstd::erase_if(attackedCres, [&reflected](const CStack * s)
{
return vstd::contains(resisted, s) || vstd::contains(reflected, s);
return vstd::contains(reflected, s);
});
for(auto s : resisted)
{
BattleSpellCast::CustomEffect effect;
effect.effect = 78;
effect.stack = s->ID;
sc.customEffects.push_back(effect);
}
for(auto s : reflected)
{
BattleSpellCast::CustomEffect effect;
@ -316,13 +305,12 @@ void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleS
StacksInjured si;
SpellCastContext ctx(attackedCres, sc, si);
applyBattleEffects(env, parameters, ctx);
env->sendAndApply(&sc);
//spend mana
if(parameters.casterHero)
if(parameters.mode == ECastingMode::HERO_CASTING)
{
SetMana sm;
sm.absolute = false;
@ -334,9 +322,9 @@ void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleS
if(sc.manaGained > 0)
{
assert(parameters.secHero);
assert(otherHero);
sm.hid = parameters.secHero->id;
sm.hid = otherHero->id;
sm.val = sc.manaGained;
env->sendAndApply(&sm);
}
@ -358,7 +346,7 @@ void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleS
ssp.absolute = false;
env->sendAndApply(&ssp);
}
logGlobal->debugStream() << "Finished spell cast. Spell: "<<owner->name<<"; mode:"<<parameters.mode;
//Magic Mirror effect
for(auto & attackedCre : reflected)
{
@ -373,18 +361,17 @@ void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleS
{
int targetHex = (*RandomGeneratorUtil::nextItem(mirrorTargets, env->getRandomGenerator()))->position;
BattleSpellCastParameters mirrorParameters = parameters;
BattleSpellCastParameters mirrorParameters(parameters.cb, attackedCre, owner);
mirrorParameters.spellLvl = 0;
mirrorParameters.casterSide = 1-parameters.casterSide;
mirrorParameters.casterColor = (attackedCre)->owner;
mirrorParameters.casterHero = nullptr;
mirrorParameters.destination = targetHex;
mirrorParameters.secHero = parameters.casterHero;
mirrorParameters.aimToHex(targetHex);
mirrorParameters.mode = ECastingMode::MAGIC_MIRROR;
mirrorParameters.casterStack = (attackedCre);
mirrorParameters.selectedStack = nullptr;
battleCast(env, mirrorParameters);
mirrorParameters.spellLvl = parameters.spellLvl;
mirrorParameters.effectLevel = parameters.effectLevel;
mirrorParameters.effectPower = parameters.effectPower;
mirrorParameters.effectValue = parameters.effectValue;
mirrorParameters.enchantPower = parameters.enchantPower;
castMagicMirror(env, mirrorParameters);
}
}
}
@ -486,74 +473,21 @@ void DefaultSpellMechanics::battleLogSingleTarget(std::vector<std::string> & log
}
}
int DefaultSpellMechanics::calculateDuration(const CGHeroInstance * caster, int usedSpellPower) const
void DefaultSpellMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
{
if(caster == nullptr)
{
if (!usedSpellPower)
return 3; //default duration of all creature spells
else
return usedSpellPower; //use creature spell power
}
else
return caster->getPrimSkillLevel(PrimarySkill::SPELL_POWER) + caster->valOfBonuses(Bonus::SPELL_DURATION);
}
ui32 DefaultSpellMechanics::calculateHealedHP(const CGHeroInstance* caster, const CStack* stack, const CStack* sacrificedStack) const
{
int healedHealth;
if(!owner->isHealingSpell())
{
logGlobal->errorStream() << "calculateHealedHP called for nonhealing spell "<< owner->name;
return 0;
}
const int spellPowerSkill = caster->getPrimSkillLevel(PrimarySkill::SPELL_POWER);
const int levelPower = owner->getPower(caster->getSpellSchoolLevel(owner));
if (owner->id == SpellID::SACRIFICE && sacrificedStack)
healedHealth = (spellPowerSkill + sacrificedStack->MaxHealth() + levelPower) * sacrificedStack->count;
else
healedHealth = spellPowerSkill * owner->power + levelPower; //???
healedHealth = caster->getSpellBonus(owner, healedHealth, stack);
return std::min<ui32>(healedHealth, stack->MaxHealth() - stack->firstHPleft + (owner->isRisingSpell() ? stack->baseAmount * stack->MaxHealth() : 0));
}
void DefaultSpellMechanics::applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
{
int effectLevel = parameters.spellLvl;
{
//MAXED_SPELL bonus.
if(parameters.casterHero != nullptr)
if(parameters.casterHero->hasBonusOfType(Bonus::MAXED_SPELL, owner->id))
effectLevel = 3;
}
//applying effects
if(owner->isOffensiveSpell())
{
int spellDamage = 0;
if(parameters.casterStack && parameters.mode != ECastingMode::MAGIC_MIRROR)
{
int unitSpellPower = parameters.casterStack->valOfBonuses(Bonus::SPECIFIC_SPELL_POWER, owner->id.toEnum());
if(unitSpellPower)
ctx.sc.dmgToDisplay = spellDamage = parameters.casterStack->count * unitSpellPower; //TODO: handle immunities
else //Faerie Dragon
{
parameters.usedSpellPower = parameters.casterStack->valOfBonuses(Bonus::CREATURE_SPELL_POWER) * parameters.casterStack->count / 100;
ctx.sc.dmgToDisplay = 0;
}
}
int spellDamage = parameters.effectValue;
int chainLightningModifier = 0;
for(auto & attackedCre : ctx.attackedCres)
{
BattleStackAttacked bsa;
if(spellDamage)
bsa.damageAmount = spellDamage >> chainLightningModifier;
if(spellDamage != 0)
bsa.damageAmount = owner->adjustRawDamage(parameters.caster, attackedCre, spellDamage) >> chainLightningModifier;
else
bsa.damageAmount = owner->calculateDamage(parameters.casterHero, attackedCre, effectLevel, parameters.usedSpellPower) >> chainLightningModifier;
bsa.damageAmount = owner->calculateDamage(parameters.caster, attackedCre, parameters.effectLevel, parameters.effectPower) >> chainLightningModifier;
ctx.sc.dmgToDisplay += bsa.damageAmount;
@ -572,19 +506,14 @@ void DefaultSpellMechanics::applyBattleEffects(const SpellCastEnvironment * env,
if(owner->hasEffects())
{
int stackSpellPower = 0;
if(parameters.casterStack && parameters.mode != ECastingMode::MAGIC_MIRROR)
{
stackSpellPower = parameters.casterStack->valOfBonuses(Bonus::CREATURE_ENCHANT_POWER);
}
SetStackEffect sse;
//get default spell duration (spell power with bonuses for heroes)
int duration = calculateDuration(parameters.casterHero, stackSpellPower ? stackSpellPower : parameters.usedSpellPower);
int duration = parameters.enchantPower;
//generate actual stack bonuses
{
int maxDuration = 0;
std::vector<Bonus> tmp;
owner->getEffects(tmp, effectLevel);
owner->getEffects(tmp, parameters.effectLevel);
for(Bonus& b : tmp)
{
//use configured duration if present
@ -664,49 +593,7 @@ void DefaultSpellMechanics::applyBattleEffects(const SpellCastEnvironment * env,
if(!sse.stacks.empty())
env->sendAndApply(&sse);
}
if(owner->isHealingSpell())
{
int hpGained = 0;
if(parameters.casterStack)
{
int unitSpellPower = parameters.casterStack->valOfBonuses(Bonus::SPECIFIC_SPELL_POWER, owner->id.toEnum());
if(unitSpellPower)
hpGained = parameters.casterStack->count * unitSpellPower; //Archangel
else //Faerie Dragon-like effect - unused so far
parameters.usedSpellPower = parameters.casterStack->valOfBonuses(Bonus::CREATURE_SPELL_POWER) * parameters.casterStack->count / 100;
}
StacksHealedOrResurrected shr;
shr.lifeDrain = false;
shr.tentHealing = false;
for(auto & attackedCre : ctx.attackedCres)
{
StacksHealedOrResurrected::HealInfo hi;
hi.stackID = (attackedCre)->ID;
if (parameters.casterStack) //casted by creature
{
const bool resurrect = owner->isRisingSpell();
if (hpGained)
{
//archangel
hi.healedHP = std::min<ui32>(hpGained, attackedCre->MaxHealth() - attackedCre->firstHPleft + (resurrect ? attackedCre->baseAmount * attackedCre->MaxHealth() : 0));
}
else
{
//any typical spell (commander's cure or animate dead)
int healedHealth = parameters.usedSpellPower * owner->power + owner->getPower(effectLevel);
hi.healedHP = std::min<ui32>(healedHealth, attackedCre->MaxHealth() - attackedCre->firstHPleft + (resurrect ? attackedCre->baseAmount * attackedCre->MaxHealth() : 0));
}
}
else
hi.healedHP = calculateHealedHP(parameters.casterHero, attackedCre, parameters.selectedStack); //Casted by hero
hi.lowLevelResurrection = (effectLevel <= 1) && (owner->id != SpellID::ANIMATE_DEAD);
shr.healedStacks.push_back(hi);
}
if(!shr.healedStacks.empty())
env->sendAndApply(&shr);
}
}
}
std::vector<BattleHex> DefaultSpellMechanics::rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool *outDroppedHexes) const
@ -849,24 +736,125 @@ std::set<const CStack *> DefaultSpellMechanics::getAffectedStacks(SpellTargeting
return attackedCres;
}
ESpellCastProblem::ESpellCastProblem DefaultSpellMechanics::canBeCasted(const CBattleInfoCallback * cb, PlayerColor player) const
ESpellCastProblem::ESpellCastProblem DefaultSpellMechanics::canBeCast(const CBattleInfoCallback * cb, PlayerColor player) const
{
//no problems by default, this method is for spell-specific problems
return ESpellCastProblem::OK;
}
ESpellCastProblem::ESpellCastProblem DefaultSpellMechanics::isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const
ESpellCastProblem::ESpellCastProblem DefaultSpellMechanics::isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const
{
//by default use general algorithm
return owner->isImmuneBy(obj);
return owner->internalIsImmune(caster, obj);
}
void DefaultSpellMechanics::doDispell(BattleInfo * battle, const BattleSpellCast * packet, const CSelector & selector) const
{
auto localSelector = [](const Bonus * bonus)
{
const CSpell * sourceSpell = bonus->sourceSpell();
if(sourceSpell != nullptr)
{
//Special case: DISRUPTING_RAY is "immune" to dispell
//Other even PERMANENT effects can be removed (f.e. BIND)
if(sourceSpell->id == SpellID::DISRUPTING_RAY)
return false;
}
return true;
};
for(auto stackID : packet->affectedCres)
{
CStack *s = battle->getStack(stackID);
s->popBonuses(selector);
s->popBonuses(CSelector(localSelector).And(selector));
}
}
void DefaultSpellMechanics::castMagicMirror(const SpellCastEnvironment* env, BattleSpellCastParameters& parameters) const
{
logGlobal->debugStream() << "Started spell cast. Spell: "<<owner->name<<"; mode: MAGIC_MIRROR";
if(parameters.mode != ECastingMode::MAGIC_MIRROR)
{
env->complain("MagicMirror: invalid mode");
return;
}
BattleHex destination = parameters.getFirstDestinationHex();
if(!destination.isValid())
{
env->complain("MagicMirror: invalid destination");
return;
}
BattleSpellCast sc;
prepareBattleCast(parameters, sc);
//calculating affected creatures for all spells
//must be vector, as in Chain Lightning order matters
std::vector<const CStack*> attackedCres; //CStack vector is somewhat more suitable than ID vector
auto creatures = owner->getAffectedStacks(parameters.cb, parameters.mode, parameters.casterColor, parameters.spellLvl, destination, parameters.caster);
std::copy(creatures.begin(), creatures.end(), std::back_inserter(attackedCres));
logGlobal->debugStream() << "will affect: " << attackedCres.size() << " stacks";
handleResistance(env, attackedCres, sc);
for(auto cre : attackedCres)
{
sc.affectedCres.insert(cre->ID);
}
StacksInjured si;
SpellCastContext ctx(attackedCres, sc, si);
applyBattleEffects(env, parameters, ctx);
env->sendAndApply(&sc);
if(!si.stacks.empty()) //after spellcast info shows
env->sendAndApply(&si);
logGlobal->debugStream() << "Finished spell cast. Spell: "<<owner->name<<"; mode: MAGIC_MIRROR";
}
void DefaultSpellMechanics::handleResistance(const SpellCastEnvironment * env, std::vector<const CStack* >& attackedCres, BattleSpellCast& sc) const
{
//checking if creatures resist
//resistance/reflection is applied only to negative spells
if(owner->isNegative())
{
std::vector <const CStack*> resisted;
for(auto s : attackedCres)
{
//magic resistance
const int prob = std::min((s)->magicResistance(), 100); //probability of resistance in %
if(env->getRandomGenerator().nextInt(99) < prob)
{
resisted.push_back(s);
}
}
vstd::erase_if(attackedCres, [&resisted](const CStack * s)
{
return vstd::contains(resisted, s);
});
for(auto s : resisted)
{
BattleSpellCast::CustomEffect effect;
effect.effect = 78;
effect.stack = s->ID;
sc.customEffects.push_back(effect);
}
}
}
void DefaultSpellMechanics::prepareBattleCast(const BattleSpellCastParameters& parameters, BattleSpellCast& sc) const
{
sc.side = parameters.casterSide;
sc.id = owner->id;
sc.skill = parameters.spellLvl;
sc.tile = parameters.getFirstDestinationHex();
sc.dmgToDisplay = 0;
sc.castByHero = parameters.mode == ECastingMode::HERO_CASTING;
sc.casterStack = (parameters.casterStack ? parameters.casterStack->ID : -1);
sc.manaGained = 0;
}

View File

@ -19,7 +19,9 @@ class StacksInjured;
struct SpellCastContext
{
SpellCastContext(std::vector<const CStack *> & attackedCres, BattleSpellCast & sc, StacksInjured & si):
attackedCres(attackedCres), sc(sc), si(si){};
attackedCres(attackedCres), sc(sc), si(si)
{
};
std::vector<const CStack *> & attackedCres;
BattleSpellCast & sc;
StacksInjured & si;
@ -40,26 +42,25 @@ public:
std::vector<BattleHex> rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool * outDroppedHexes = nullptr) const override;
std::set<const CStack *> getAffectedStacks(SpellTargetingContext & ctx) const override;
ESpellCastProblem::ESpellCastProblem canBeCasted(const CBattleInfoCallback * cb, PlayerColor player) const override;
ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, PlayerColor player) const override;
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const override;
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const override;
virtual void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const override;
bool adventureCast(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override final;
void battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const override;
void battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const override final;
void battleLogSingleTarget(std::vector<std::string> & logLines, const BattleSpellCast * packet,
const std::string & casterName, const CStack * attackedStack, bool & displayDamage) const override;
protected:
virtual void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const;
virtual int calculateDuration(const CGHeroInstance * caster, int usedSpellPower) const;
///calculate healed HP for all spells casted by hero
ui32 calculateHealedHP(const CGHeroInstance * caster, const CStack * stack, const CStack * sacrificedStack) const;
virtual void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const;
///actual adventure cast implementation
virtual ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const;
void doDispell(BattleInfo * battle, const BattleSpellCast * packet, const CSelector & selector) const;
private:
void castMagicMirror(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const;
void handleResistance(const SpellCastEnvironment * env, std::vector<const CStack*> & attackedCres, BattleSpellCast & sc) const;
void prepareBattleCast(const BattleSpellCastParameters & parameters, BattleSpellCast & sc) const;
};

View File

@ -23,10 +23,11 @@
#include "../CModHandler.h"
#include "../StringConstants.h"
#include "../mapObjects/CGHeroInstance.h"
#include "../BattleState.h"
#include "../CBattleCallback.h"
#include "../CGameState.h"
#include "../CGameState.h" //todo: remove
#include "../NetPacks.h" //todo: remove
#include "ISpellMechanics.h"
@ -71,13 +72,6 @@ namespace SpellConfig
};
}
BattleSpellCastParameters::BattleSpellCastParameters(const BattleInfo* cb)
: spellLvl(0), destination(BattleHex::INVALID), casterSide(0),casterColor(PlayerColor::CANNOT_DETERMINE),casterHero(nullptr), secHero(nullptr),
usedSpellPower(0),mode(ECastingMode::HERO_CASTING), casterStack(nullptr), selectedStack(nullptr), cb(cb)
{
}
///CSpell::LevelInfo
CSpell::LevelInfo::LevelInfo()
:description(""),cost(0),power(0),AIValue(0),smartTarget(true), clearTarget(false), clearAffected(false), range("0")
@ -121,9 +115,13 @@ bool CSpell::adventureCast(const SpellCastEnvironment * env, AdventureSpellCastP
}
void CSpell::battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const
{
{
assert(env);
if(parameters.destinations.size()<1)
{
env->complain("Spell must have at least one destination");
return;
}
mechanics->battleCast(env, parameters);
}
@ -140,52 +138,15 @@ const CSpell::LevelInfo & CSpell::getLevelInfo(const int level) const
ui32 CSpell::calculateDamage(const ISpellCaster * caster, const CStack * affectedCreature, int spellSchoolLevel, int usedSpellPower) const
{
ui32 ret = 0; //value to return
//check if spell really does damage - if not, return 0
if(!isDamageSpell())
return 0;
ret = usedSpellPower * power;
ret += getPower(spellSchoolLevel);
//affected creature-specific part
if(nullptr != affectedCreature)
{
//applying protections - when spell has more then one elements, only one protection should be applied (I think)
forEachSchool([&](const SpellSchoolInfo & cnf, bool & stop)
{
if(affectedCreature->hasBonusOfType(Bonus::SPELL_DAMAGE_REDUCTION, (ui8)cnf.id))
{
ret *= affectedCreature->valOfBonuses(Bonus::SPELL_DAMAGE_REDUCTION, (ui8)cnf.id);
ret /= 100;
stop = true;//only bonus from one school is used
}
});
//general spell dmg reduction
if(affectedCreature->hasBonusOfType(Bonus::SPELL_DAMAGE_REDUCTION, -1))
{
ret *= affectedCreature->valOfBonuses(Bonus::SPELL_DAMAGE_REDUCTION, -1);
ret /= 100;
}
//dmg increasing
if(affectedCreature->hasBonusOfType(Bonus::MORE_DAMAGE_FROM_SPELL, id))
{
ret *= 100 + affectedCreature->valOfBonuses(Bonus::MORE_DAMAGE_FROM_SPELL, id.toEnum());
ret /= 100;
}
}
if(nullptr != caster) //todo: make sure that caster always present
ret = caster->getSpellBonus(this, ret, affectedCreature);
return ret;
return adjustRawDamage(caster, affectedCreature, calculateRawEffectValue(spellSchoolLevel, usedSpellPower));
}
ESpellCastProblem::ESpellCastProblem CSpell::canBeCasted(const CBattleInfoCallback * cb, PlayerColor player) const
ESpellCastProblem::ESpellCastProblem CSpell::canBeCast(const CBattleInfoCallback * cb, PlayerColor player) const
{
return mechanics->canBeCasted(cb, player);
return mechanics->canBeCast(cb, player);
}
std::vector<BattleHex> CSpell::rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool *outDroppedHexes) const
@ -193,7 +154,7 @@ std::vector<BattleHex> CSpell::rangeInHexes(BattleHex centralHex, ui8 schoolLvl,
return mechanics->rangeInHexes(centralHex,schoolLvl,side,outDroppedHexes);
}
std::set<const CStack *> CSpell::getAffectedStacks(const CBattleInfoCallback * cb, ECastingMode::ECastingMode mode, PlayerColor casterColor, int spellLvl, BattleHex destination, const CGHeroInstance * caster) const
std::set<const CStack *> CSpell::getAffectedStacks(const CBattleInfoCallback * cb, ECastingMode::ECastingMode mode, PlayerColor casterColor, int spellLvl, BattleHex destination, const ISpellCaster * caster) const
{
ISpellMechanics::SpellTargetingContext ctx(this, cb,mode,casterColor,spellLvl,destination);
@ -217,12 +178,6 @@ CSpell::ETargetType CSpell::getTargetType() const
return targetType;
}
CSpell::TargetInfo CSpell::getTargetInfo(const int level) const
{
TargetInfo info(this, level);
return info;
}
void CSpell::forEachSchool(const std::function<void(const SpellSchoolInfo &, bool &)>& cb) const
{
bool stop = false;
@ -351,7 +306,7 @@ void CSpell::getEffects(std::vector<Bonus> & lst, const int level) const
}
}
ESpellCastProblem::ESpellCastProblem CSpell::isImmuneAt(const CBattleInfoCallback * cb, const CGHeroInstance * caster, ECastingMode::ECastingMode mode, BattleHex destination) const
ESpellCastProblem::ESpellCastProblem CSpell::isImmuneAt(const CBattleInfoCallback * cb, const ISpellCaster * caster, ECastingMode::ECastingMode mode, BattleHex destination) const
{
// Get all stacks at destination hex. only alive if not rising spell
TStacks stacks = cb->battleGetStacksIf([=](const CStack * s){
@ -402,7 +357,48 @@ ESpellCastProblem::ESpellCastProblem CSpell::isImmuneAt(const CBattleInfoCallbac
return ESpellCastProblem::OK;
}
ESpellCastProblem::ESpellCastProblem CSpell::isImmuneBy(const IBonusBearer* obj) const
int CSpell::adjustRawDamage(const ISpellCaster * caster, const CStack * affectedCreature, int rawDamage) const
{
int ret = rawDamage;
//affected creature-specific part
if(nullptr != affectedCreature)
{
//applying protections - when spell has more then one elements, only one protection should be applied (I think)
forEachSchool([&](const SpellSchoolInfo & cnf, bool & stop)
{
if(affectedCreature->hasBonusOfType(Bonus::SPELL_DAMAGE_REDUCTION, (ui8)cnf.id))
{
ret *= affectedCreature->valOfBonuses(Bonus::SPELL_DAMAGE_REDUCTION, (ui8)cnf.id);
ret /= 100;
stop = true;//only bonus from one school is used
}
});
//general spell dmg reduction
if(affectedCreature->hasBonusOfType(Bonus::SPELL_DAMAGE_REDUCTION, -1))
{
ret *= affectedCreature->valOfBonuses(Bonus::SPELL_DAMAGE_REDUCTION, -1);
ret /= 100;
}
//dmg increasing
if(affectedCreature->hasBonusOfType(Bonus::MORE_DAMAGE_FROM_SPELL, id))
{
ret *= 100 + affectedCreature->valOfBonuses(Bonus::MORE_DAMAGE_FROM_SPELL, id.toEnum());
ret /= 100;
}
}
if(caster != nullptr)
ret = caster->getSpellBonus(this, ret, affectedCreature);
return ret;
}
int CSpell::calculateRawEffectValue(int effectLevel, int effectPower) const
{
return effectPower * power + getPower(effectLevel);
}
ESpellCastProblem::ESpellCastProblem CSpell::internalIsImmune(const ISpellCaster * caster, const CStack *obj) const
{
//todo: use new bonus API
//1. Check absolute limiters
@ -419,25 +415,46 @@ ESpellCastProblem::ESpellCastProblem CSpell::isImmuneBy(const IBonusBearer* obj)
return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
}
//spell-based spell immunity (only ANTIMAGIC in OH3) is treated as absolute
std::stringstream cachingStr;
cachingStr << "type_" << Bonus::LEVEL_SPELL_IMMUNITY << "source_" << Bonus::SPELL_EFFECT;
TBonusListPtr levelImmunitiesFromSpell = obj->getBonuses(Selector::type(Bonus::LEVEL_SPELL_IMMUNITY).And(Selector::sourceType(Bonus::SPELL_EFFECT)), cachingStr.str());
if(levelImmunitiesFromSpell->size() > 0 && levelImmunitiesFromSpell->totalValue() >= level && level)
{
return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
//spell-based spell immunity (only ANTIMAGIC in OH3) is treated as absolute
std::stringstream cachingStr;
cachingStr << "type_" << Bonus::LEVEL_SPELL_IMMUNITY << "source_" << Bonus::SPELL_EFFECT;
TBonusListPtr levelImmunitiesFromSpell = obj->getBonuses(Selector::type(Bonus::LEVEL_SPELL_IMMUNITY).And(Selector::sourceType(Bonus::SPELL_EFFECT)), cachingStr.str());
if(levelImmunitiesFromSpell->size() > 0 && levelImmunitiesFromSpell->totalValue() >= level && level)
{
return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
}
}
{
//SPELL_IMMUNITY absolute case
std::stringstream cachingStr;
cachingStr << "type_" << Bonus::SPELL_IMMUNITY << "subtype_" << id.toEnum() << "addInfo_1";
if(obj->hasBonus(Selector::typeSubtypeInfo(Bonus::SPELL_IMMUNITY, id.toEnum(), 1), cachingStr.str()))
return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
}
//check receptivity
if (isPositive() && obj->hasBonusOfType(Bonus::RECEPTIVE)) //accept all positive spells
return ESpellCastProblem::OK;
//3. Check negation
//FIXME: Orb of vulnerability mechanics is not such trivial
if(obj->hasBonusOfType(Bonus::NEGATE_ALL_NATURAL_IMMUNITIES)) //Orb of vulnerability
//Orb of vulnerability
//FIXME: Orb of vulnerability mechanics is not such trivial (issue 1791)
const bool battleWideNegation = obj->hasBonusOfType(Bonus::NEGATE_ALL_NATURAL_IMMUNITIES, 0);
const bool heroNegation = obj->hasBonusOfType(Bonus::NEGATE_ALL_NATURAL_IMMUNITIES, 1);
//anyone can cast on artifact holder`s stacks
if(heroNegation)
return ESpellCastProblem::NOT_DECIDED;
//this stack is from other player
//todo: check that caster is always present (not trivial is this case)
//todo: NEGATE_ALL_NATURAL_IMMUNITIES special cases: dispell, chain lightning
else if(battleWideNegation && caster)
{
if(obj->owner != caster->getOwner())
return ESpellCastProblem::NOT_DECIDED;
}
//4. Check negatable limit
for(auto b : limiters)
@ -491,7 +508,7 @@ ESpellCastProblem::ESpellCastProblem CSpell::isImmuneBy(const IBonusBearer* obj)
return ESpellCastProblem::NOT_DECIDED;
}
ESpellCastProblem::ESpellCastProblem CSpell::isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const
ESpellCastProblem::ESpellCastProblem CSpell::isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const
{
const auto immuneResult = mechanics->isImmuneByStack(caster,obj);

View File

@ -30,6 +30,9 @@ struct BattleSpellCast;
class CGameInfoCallback;
class CRandomGenerator;
class CMap;
struct AdventureSpellCastParameters;
struct BattleSpellCastParameters;
class SpellCastEnvironment;
struct SpellSchoolInfo
{
@ -41,45 +44,6 @@ struct SpellSchoolInfo
Bonus::BonusType knoledgeBonus;
};
///callback to be provided by server
class DLL_LINKAGE SpellCastEnvironment
{
public:
virtual ~SpellCastEnvironment(){};
virtual void sendAndApply(CPackForClient * info) const = 0;
virtual CRandomGenerator & getRandomGenerator() const = 0;
virtual void complain(const std::string & problem) const = 0;
virtual const CMap * getMap() const = 0;
virtual const CGameInfoCallback * getCb() const = 0;
virtual bool moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, PlayerColor asker = PlayerColor::NEUTRAL) const =0; //TODO: remove
};
///helper struct
struct DLL_LINKAGE BattleSpellCastParameters
{
public:
BattleSpellCastParameters(const BattleInfo * cb);
int spellLvl;
BattleHex destination;
ui8 casterSide;
PlayerColor casterColor;
const CGHeroInstance * casterHero; //deprecated
const CGHeroInstance * secHero;
int usedSpellPower;
ECastingMode::ECastingMode mode;
const CStack * casterStack;
const CStack * selectedStack;
const BattleInfo * cb;
};
struct DLL_LINKAGE AdventureSpellCastParameters
{
const CGHeroInstance * caster;
int3 pos;
};
enum class VerticalPosition : ui8{TOP, CENTER, BOTTOM};
@ -136,10 +100,10 @@ public:
///displayed on caster.
TAnimationQueue cast;
///displayed on target hex. If spell was casted with no target selection displayed on entire battlefield (f.e. ARMAGEDDON)
///displayed on target hex. If spell was cast with no target selection displayed on entire battlefield (f.e. ARMAGEDDON)
TAnimationQueue hit;
///displayed "between" caster and (first) target. Ignored if spell was casted with no target selection.
///displayed "between" caster and (first) target. Ignored if spell was cast with no target selection.
///use selectProjectile to access
std::vector<ProjectileInfo> projectile;
@ -188,7 +152,7 @@ public:
enum ETargetType {NO_TARGET, CREATURE, OBSTACLE, LOCATION};
enum ESpellPositiveness {NEGATIVE = -1, NEUTRAL = 0, POSITIVE = 1};
struct TargetInfo
struct DLL_LINKAGE TargetInfo
{
ETargetType type;
bool smart;
@ -231,8 +195,6 @@ public:
std::vector<BattleHex> rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool * outDroppedHexes = nullptr ) const; //convert range to specific hexes; last optional out parameter is set to true, if spell would cover unavailable hexes (that are not included in ret)
ETargetType getTargetType() const; //deprecated
CSpell::TargetInfo getTargetInfo(const int level) const;
bool isCombatSpell() const;
bool isAdventureSpell() const;
bool isCreatureAbility() const;
@ -251,17 +213,12 @@ public:
bool hasEffects() const;
void getEffects(std::vector<Bonus> &lst, const int level) const;
///checks for creature immunity / anything that prevent casting *at given hex* - doesn't take into account general problems such as not having spellbook or mana points etc.
ESpellCastProblem::ESpellCastProblem isImmuneAt(const CBattleInfoCallback * cb, const CGHeroInstance * caster, ECastingMode::ECastingMode mode, BattleHex destination) const;
//internal, for use only by Mechanics classes
ESpellCastProblem::ESpellCastProblem isImmuneBy(const IBonusBearer *obj) const;
///calculate spell damage on stack taking caster`s secondary skills and affectedCreature`s bonuses into account
ui32 calculateDamage(const ISpellCaster * caster, const CStack * affectedCreature, int spellSchoolLevel, int usedSpellPower) const;
///selects from allStacks actually affected stacks
std::set<const CStack *> getAffectedStacks(const CBattleInfoCallback * cb, ECastingMode::ECastingMode mode, PlayerColor casterColor, int spellLvl, BattleHex destination, const CGHeroInstance * caster = nullptr) const;
std::set<const CStack *> getAffectedStacks(const CBattleInfoCallback * cb, ECastingMode::ECastingMode mode, PlayerColor casterColor, int spellLvl, BattleHex destination, const ISpellCaster * caster) const;
si32 getCost(const int skillLevel) const;
@ -310,10 +267,13 @@ public:
///internal interface (for callbacks)
///Checks general but spell-specific problems for all casting modes. Use only during battle.
ESpellCastProblem::ESpellCastProblem canBeCasted(const CBattleInfoCallback * cb, PlayerColor player) const;
ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, PlayerColor player) const;
///checks for creature immunity / anything that prevent casting *at given hex* - doesn't take into account general problems such as not having spellbook or mana points etc.
ESpellCastProblem::ESpellCastProblem isImmuneAt(const CBattleInfoCallback * cb, const ISpellCaster * caster, ECastingMode::ECastingMode mode, BattleHex destination) const;
///checks for creature immunity / anything that prevent casting *at given target* - doesn't take into account general problems such as not having spellbook or mana points etc.
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const;
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const;
public:
///Server logic. Has write access to GameState via packets.
///May be executed on client side by (future) non-cheat-proof scripts.
@ -328,11 +288,17 @@ public:
///implementation of BattleSpellCast applying
void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const;
public:
///Client logic.
public://Client logic.
void prepareBattleLog(const CBattleInfoCallback * cb, const BattleSpellCast * packet, std::vector<std::string> & logLines) const;
public://internal, for use only by Mechanics classes
///applies caster`s secondary skills and affectedCreature`s to raw damage
int adjustRawDamage(const ISpellCaster * caster, const CStack * affectedCreature, int rawDamage) const;
///returns raw damage or healed HP
int calculateRawEffectValue(int effectLevel, int effectPower) const;
///generic immunity calculation
ESpellCastProblem::ESpellCastProblem internalIsImmune(const ISpellCaster * caster, const CStack *obj) const;
private:
void setIsOffensive(const bool val);
void setIsRising(const bool val);

View File

@ -16,17 +16,18 @@
#include "../BattleState.h"
///AcidBreathDamageMechanics
void AcidBreathDamageMechanics::applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
void AcidBreathDamageMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
{
//todo: this should be effectValue
//calculating dmg to display
ctx.sc.dmgToDisplay = parameters.usedSpellPower;
ctx.sc.dmgToDisplay = parameters.effectPower;
for(auto & attackedCre : ctx.attackedCres) //no immunities
{
BattleStackAttacked bsa;
bsa.flags |= BattleStackAttacked::SPELL_EFFECT;
bsa.spellID = owner->id;
bsa.damageAmount = parameters.usedSpellPower; //damage times the number of attackers
bsa.damageAmount = parameters.effectPower; //damage times the number of attackers
bsa.stackAttacked = (attackedCre)->ID;
bsa.attackerID = -1;
(attackedCre)->prepareAttacked(bsa, env->getRandomGenerator());
@ -35,10 +36,10 @@ void AcidBreathDamageMechanics::applyBattleEffects(const SpellCastEnvironment *
}
///DeathStareMechanics
void DeathStareMechanics::applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
void DeathStareMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
{
//calculating dmg to display
ctx.sc.dmgToDisplay = parameters.usedSpellPower;
ctx.sc.dmgToDisplay = parameters.effectPower;
if(!ctx.attackedCres.empty())
vstd::amin(ctx.sc.dmgToDisplay, (*ctx.attackedCres.begin())->count); //stack is already reduced after attack
@ -47,7 +48,7 @@ void DeathStareMechanics::applyBattleEffects(const SpellCastEnvironment * env, B
BattleStackAttacked bsa;
bsa.flags |= BattleStackAttacked::SPELL_EFFECT;
bsa.spellID = owner->id;
bsa.damageAmount = parameters.usedSpellPower * (attackedCre)->valOfBonuses(Bonus::STACK_HEALTH);
bsa.damageAmount = parameters.effectPower * (attackedCre)->valOfBonuses(Bonus::STACK_HEALTH);//todo: move here all DeathStare calculation
bsa.stackAttacked = (attackedCre)->ID;
bsa.attackerID = -1;
(attackedCre)->prepareAttacked(bsa, env->getRandomGenerator());
@ -63,7 +64,7 @@ void DispellHelpfulMechanics::applyBattle(BattleInfo * battle, const BattleSpell
doDispell(battle, packet, Selector::positiveSpellEffects);
}
ESpellCastProblem::ESpellCastProblem DispellHelpfulMechanics::isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const
ESpellCastProblem::ESpellCastProblem DispellHelpfulMechanics::isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const
{
TBonusListPtr spellBon = obj->getSpellBonuses();
bool hasPositiveSpell = false;

View File

@ -18,7 +18,7 @@ class DLL_LINKAGE AcidBreathDamageMechanics : public DefaultSpellMechanics
public:
AcidBreathDamageMechanics(CSpell * s): DefaultSpellMechanics(s){};
protected:
void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
};
class DLL_LINKAGE DeathStareMechanics : public DefaultSpellMechanics
@ -26,7 +26,7 @@ class DLL_LINKAGE DeathStareMechanics : public DefaultSpellMechanics
public:
DeathStareMechanics(CSpell * s): DefaultSpellMechanics(s){};
protected:
void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
};
class DLL_LINKAGE DispellHelpfulMechanics : public DefaultSpellMechanics
@ -36,5 +36,5 @@ public:
void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const override final;
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const override;
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const override;
};

View File

@ -11,12 +11,71 @@
#include "StdInc.h"
#include "ISpellMechanics.h"
#include "../BattleState.h"
#include "../NetPacks.h"
#include "CDefaultSpellMechanics.h"
#include "AdventureSpellMechanics.h"
#include "BattleSpellMechanics.h"
#include "CreatureSpellMechanics.h"
BattleSpellCastParameters::Destination::Destination(const CStack * destination):
stackValue(destination),
hexValue(destination->position)
{
}
BattleSpellCastParameters::Destination::Destination(const BattleHex & destination):
stackValue(nullptr),
hexValue(destination)
{
}
BattleSpellCastParameters::BattleSpellCastParameters(const BattleInfo * cb, const ISpellCaster * caster, const CSpell * spell)
: cb(cb), caster(caster), casterColor(caster->getOwner()), casterSide(cb->whatSide(casterColor)),
casterHero(nullptr),
mode(ECastingMode::HERO_CASTING), casterStack(nullptr), selectedStack(nullptr),
spellLvl(-1), effectLevel(-1), effectPower(0), enchantPower(0), effectValue(0)
{
casterStack = dynamic_cast<const CStack *>(caster);
casterHero = dynamic_cast<const CGHeroInstance *>(caster);
prepare(spell);
}
void BattleSpellCastParameters::aimToHex(const BattleHex& destination)
{
destinations.push_back(Destination(destination));
}
void BattleSpellCastParameters::aimToStack(const CStack * destination)
{
destinations.push_back(Destination(destination));
}
BattleHex BattleSpellCastParameters::getFirstDestinationHex() const
{
return destinations.at(0).hexValue;
}
void BattleSpellCastParameters::prepare(const CSpell * spell)
{
spellLvl = caster->getSpellSchoolLevel(spell);
effectLevel = caster->getEffectLevel(spell);
effectPower = caster->getEffectPower(spell);
effectValue = caster->getEffectValue(spell);
enchantPower = caster->getEnchantPower(spell);
vstd::amax(spellLvl, 0);
vstd::amax(effectLevel, 0);
vstd::amax(enchantPower, 0);
vstd::amax(enchantPower, 0);
vstd::amax(effectValue, 0);
}
///ISpellMechanics
ISpellMechanics::ISpellMechanics(CSpell * s):
owner(s)

View File

@ -12,8 +12,75 @@
#include "CSpellHandler.h"
#include "../BattleHex.h"
#include "../BattleState.h"
#include "../NetPacks.h"
///callback to be provided by server
class DLL_LINKAGE SpellCastEnvironment
{
public:
virtual ~SpellCastEnvironment(){};
virtual void sendAndApply(CPackForClient * info) const = 0;
virtual CRandomGenerator & getRandomGenerator() const = 0;
virtual void complain(const std::string & problem) const = 0;
virtual const CMap * getMap() const = 0;
virtual const CGameInfoCallback * getCb() const = 0;
virtual bool moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, PlayerColor asker = PlayerColor::NEUTRAL) const =0; //TODO: remove
};
///all parameters of particular cast event
struct DLL_LINKAGE BattleSpellCastParameters
{
public:
///Single spell destination.
/// (assumes that anything but battle stack can share same hex)
struct DLL_LINKAGE Destination
{
explicit Destination(const CStack * destination);
explicit Destination(const BattleHex & destination);
const CStack * stackValue;
const BattleHex hexValue;
};
BattleSpellCastParameters(const BattleInfo * cb, const ISpellCaster * caster, const CSpell * spell);
void aimToHex(const BattleHex & destination);
void aimToStack(const CStack * destination);
BattleHex getFirstDestinationHex() const;
const BattleInfo * cb;
const ISpellCaster * caster;
const PlayerColor casterColor;
const ui8 casterSide;
std::vector<Destination> destinations;
const CGHeroInstance * casterHero; //deprecated
ECastingMode::ECastingMode mode;
const CStack * casterStack; //deprecated
const CStack * selectedStack;//deprecated
///spell school level
int spellLvl;
///spell school level to use for effects
int effectLevel;
///actual spell-power affecting effect values
int effectPower;
///actual spell-power affecting effect duration
int enchantPower;
///for Archangel-like casting
int effectValue;
private:
void prepare(const CSpell * spell);
};
struct DLL_LINKAGE AdventureSpellCastParameters
{
const CGHeroInstance * caster;
int3 pos;
};
class DLL_LINKAGE ISpellMechanics
{
@ -39,9 +106,9 @@ public:
virtual std::vector<BattleHex> rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool * outDroppedHexes = nullptr) const = 0;
virtual std::set<const CStack *> getAffectedStacks(SpellTargetingContext & ctx) const = 0;
virtual ESpellCastProblem::ESpellCastProblem canBeCasted(const CBattleInfoCallback * cb, PlayerColor player) const = 0;
virtual ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, PlayerColor player) const = 0;
virtual ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const = 0;
virtual ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const = 0;
virtual void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const = 0;
virtual bool adventureCast(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const = 0;

View File

@ -17,6 +17,7 @@
class CSpell;
class CStack;
class PlayerColor;
class DLL_LINKAGE ISpellCaster
{
@ -26,7 +27,22 @@ public:
/// returns level on which given spell would be cast by this(0 - none, 1 - basic etc);
/// caster may not know this spell at all
/// optionally returns number of selected school by arg - 0 - air magic, 1 - fire magic, 2 - water magic, 3 - earth magic
virtual ui8 getSpellSchoolLevel(const CSpell * spell, int *outSelectedSchool = nullptr) const = 0;
virtual ui8 getSpellSchoolLevel(const CSpell * spell, int *outSelectedSchool = nullptr) const = 0;
///applying sorcery secondary skill etc
virtual ui32 getSpellBonus(const CSpell * spell, ui32 base, const CStack * affectedStack) const = 0;
///default spell school level for effect calculation
virtual int getEffectLevel(const CSpell * spell) const = 0;
///default spell-power for damage/heal calculation
virtual int getEffectPower(const CSpell * spell) const = 0;
///default spell-power for timed effects duration
virtual int getEnchantPower(const CSpell * spell) const = 0;
///damage/heal override(ignores spell configuration, effect level and effect power)
virtual int getEffectValue(const CSpell * spell) const = 0;
virtual const PlayerColor getOwner() const = 0;
};

Some files were not shown because too many files have changed in this diff Show More