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

Merge tag '0.99'

# Conflicts:
#	debian/changelog
#	lib/GameConstants.h
This commit is contained in:
AlexVinS 2016-11-01 22:12:57 +03:00
commit 258202d682
435 changed files with 28715 additions and 17458 deletions

8
.gitignore vendored
View File

@ -13,6 +13,9 @@
*.layout
*.pro.user
*.pro.user.*
*.swp
*.h.gch
*~
/CMakeLists.txt.user
CMakeCache.txt
CMakeFiles
@ -28,3 +31,8 @@ ui_*.h
/CPackSourceConfig.cmake
build-*
CMakeLists.txt.user.*
Doxyfile
doc/*
VCMI_VS11.sdf
*.ipch
VCMI_VS11.opensdf

26
.travis.linux Normal file
View File

@ -0,0 +1,26 @@
#!/bin/sh
#new Clang
sudo add-apt-repository --yes ppa:h-rayflood/llvm
#new SDL2
sudo add-apt-repository --yes ppa:zoogie/sdl2-snapshots
#new Qt
sudo add-apt-repository --yes ppa:beineri/opt-qt57-trusty
#new CMake
sudo add-apt-repository --yes ppa:george-edison55/cmake-3.x
sudo apt-get update -qq
sudo apt-get install -qq $SUPPORT
sudo apt-get install -qq $PACKAGE
sudo apt-get install -qq cmake libboost1.54-all-dev zlib1g-dev
sudo apt-get install -qq libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev
sudo apt-get install -qq libavformat-dev libswscale-dev
sudo apt-get install -qq qt57declarative
#setup compiler
source /opt/qt57/bin/qt57-env.sh
export CC=${REAL_CC} CXX=${REAL_CXX}

17
.travis.osx Normal file
View File

@ -0,0 +1,17 @@
#!/bin/sh
# https://gist.github.com/vmarkovtsev/3f2dd98e56cb63098027
brew unlink boost
brew install boost smpeg2 innoextract libpng freetype sdl2 sdl2_ttf sdl2_image qt5 ffmpeg
brew install sdl2_mixer --with-smpeg2
sudo sed -i.bak 's/106200/106900/g' /usr/local/Cellar/cmake/*/share/cmake/Modules/FindBoost.cmake
export CMAKE_PREFIX_PATH="/usr/local/opt/qt5:$CMAKE_PREFIX_PATH"
sparkle_version=$(curl -L https://github.com/sparkle-project/Sparkle/releases/latest | grep '<span class="css-truncate-target">' | sed -E 's|^.*([1-9]\.[0-9]+\.[0-9]+).*$|\1|g')
wget https://github.com/sparkle-project/Sparkle/releases/download/$sparkle_version/Sparkle-$sparkle_version.tar.bz2
mkdir sparkle && cd sparkle
tar -xf ../Sparkle-*.tar.bz2
sudo mv Sparkle.framework /Library/Frameworks/
cd .. && rm -rf sparkle

View File

@ -1,39 +1,22 @@
language: cpp
os:
- linux
- osx
dist: trusty
sudo: required
before_install:
#new boost
- sudo add-apt-repository --yes ppa:boost-latest/ppa
#new GCC
- sudo add-apt-repository --yes ppa:ubuntu-toolchain-r/test
#new Clang
- sudo add-apt-repository --yes ppa:h-rayflood/llvm
#new SDL2
- sudo add-apt-repository --yes ppa:zoogie/sdl2-snapshots
#new Qt
- sudo add-apt-repository --yes ppa:beineri/opt-qt532
#new CMake
- sudo add-apt-repository --yes ppa:andykimpe/cmake
- sudo apt-get update -qq
- sudo apt-get install -qq $SUPPORT
- sudo apt-get install -qq $PACKAGE
- sudo apt-get install -qq cmake libboost1.55-all-dev zlib1g-dev
- sudo apt-get install -qq libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev
- sudo apt-get install -qq libavformat-dev libswscale-dev
- sudo apt-get install -qq qt53declarative
#setup compiler
- source /opt/qt53/bin/qt53-env.sh
- export CC=${REAL_CC} CXX=${REAL_CXX}
- if [[ $TRAVIS_OS_NAME == 'linux' ]]; then . .travis.linux; fi
- if [[ $TRAVIS_OS_NAME == 'osx' ]]; then . .travis.osx; fi
before_script:
- mkdir build
- cd build
- cmake ..
- cmake -G "Unix Makefiles" ..
script:
- make
- if [[ $TRAVIS_OS_NAME == 'osx' ]]; then cd ..; xcodebuild -project osx/osx-vcmibuilder/vcmibuilder.xcodeproj/ -configuration Release CONFIGURATION_BUILD_DIR=..; cd build; fi
- make -j2
env:
- ignore=this
@ -42,16 +25,19 @@ matrix:
exclude:
- env: ignore=this
include:
- compiler: clang # fails all the time - missing packages?
env: REAL_CC=clang-3.2 REAL_CXX=clang++-3.2 PACKAGE=clang-3.2 SUPPORT=g++-4.8
- compiler: clang
env: REAL_CC=clang-3.3 REAL_CXX=clang++-3.3 PACKAGE=clang-3.3 SUPPORT=g++-4.8
- compiler: clang
env: REAL_CC=clang-3.4 REAL_CXX=clang++-3.4 PACKAGE=clang-3.4 SUPPORT=g++-4.8
#- compiler: gcc # fails due to running out of memory - vcmi need too much of it for successfull compilation
# env: REAL_CC=gcc-4.7 REAL_CXX=g++-4.7 PACKAGE=g++-4.7 SUPPORT=
#- compiler: gcc # same as 4.7
# env: REAL_CC=gcc-4.8 REAL_CXX=g++-4.8 PACKAGE=g++-4.8 SUPPORT=
- os: linux
compiler: clang
env: REAL_CC=clang-3.4 REAL_CXX=clang++-3.4 PACKAGE=clang-3.4 SUPPORT=libstdc++-4.8-dev
- os: linux
compiler: clang
env: REAL_CC=clang-3.5 REAL_CXX=clang++-3.5 PACKAGE=clang-3.5 SUPPORT=libstdc++-4.8-dev
- os: linux
compiler: clang
env: REAL_CC=clang-3.6 REAL_CXX=clang++-3.6 PACKAGE=clang-3.6 SUPPORT=libstdc++-4.8-dev
- os: linux
compiler: gcc
env: REAL_CC=gcc-4.8 REAL_CXX=g++-4.8 PACKAGE=g++-4.8 SUPPORT=
- os: osx
notifications:
email:

View File

@ -6,43 +6,23 @@
<Option pch_mode="2" />
<Option compiler="gcc" />
<Build>
<Target title="Debug-win32-SDL2">
<Target title="Debug-win32">
<Option platforms="Windows;" />
<Option output="../BattleAI" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Debug/" />
<Option object_output="obj/Debug/x86/" />
<Option type="3" />
<Option compiler="gcc" />
<Compiler>
<Add option="-g" />
</Compiler>
</Target>
<Target title="Release-win32-SDL2">
<Option platforms="Windows;" />
<Option output="../BattleAI" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Release/" />
<Option type="3" />
<Option compiler="gcc" />
<Compiler>
<Add option="-O2" />
</Compiler>
<Linker>
<Add option="-s" />
<Add directory="$(#boost.lib32)" />
</Linker>
</Target>
<Target title="Debug-win32-SDL1">
<Target title="Release-win32">
<Option platforms="Windows;" />
<Option output="../BattleAI" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Debug/" />
<Option type="3" />
<Option compiler="gcc" />
<Compiler>
<Add option="-g" />
</Compiler>
</Target>
<Target title="Release-win32-SDL1">
<Option platforms="Windows;" />
<Option output="../BattleAI" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Release/" />
<Option object_output="obj/Release/x86/" />
<Option type="3" />
<Option compiler="gcc" />
<Compiler>
@ -50,6 +30,20 @@
</Compiler>
<Linker>
<Add option="-s" />
<Add directory="$(#boost.lib32)" />
</Linker>
</Target>
<Target title="Debug-win64">
<Option platforms="Windows;" />
<Option output="../BattleAI" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Debug/x64/" />
<Option type="3" />
<Option compiler="gnu_gcc_compiler_x64" />
<Compiler>
<Add option="-g" />
</Compiler>
<Linker>
<Add directory="$(#boost.lib64)" />
</Linker>
</Target>
</Build>
@ -57,6 +51,7 @@
<Add option="-pedantic" />
<Add option="-Wextra" />
<Add option="-Wall" />
<Add option="-std=gnu++11" />
<Add option="-fexceptions" />
<Add option="-Wpointer-arith" />
<Add option="-Wno-switch" />
@ -69,12 +64,12 @@
<Linker>
<Add option="-lboost_system$(#boost.libsuffix)" />
<Add option="-lVCMI_lib" />
<Add directory="$(#boost.lib32)" />
<Add directory="../.." />
</Linker>
<Unit filename="BattleAI.cpp" />
<Unit filename="BattleAI.h" />
<Unit filename="StdInc.h">
<Option compile="1" />
<Option weight="0" />
</Unit>
<Unit filename="main.cpp" />

View File

@ -8,7 +8,7 @@
#include "../../lib/VCMI_Lib.h"
using boost::optional;
static shared_ptr<CBattleCallback> cbc;
static std::shared_ptr<CBattleCallback> cbc;
#define LOGL(text) print(text)
#define LOGFL(text, formattingEl) print(boost::str(boost::format(text) % formattingEl))
@ -91,7 +91,7 @@ CBattleAI::~CBattleAI(void)
}
}
void CBattleAI::init(shared_ptr<CBattleCallback> CB)
void CBattleAI::init(std::shared_ptr<CBattleCallback> CB)
{
print("init called, saving ptr to IBattleCallback");
cbc = cb = CB;
@ -103,11 +103,6 @@ void CBattleAI::init(shared_ptr<CBattleCallback> CB)
CB->unlockGsWhenWaiting = false;
}
static bool thereRemainsEnemy()
{
return !cbc->battleIsFinished();
}
BattleAction CBattleAI::activeStack( const CStack * stack )
{
LOG_TRACE_PARAMS(logAi, "stack: %s", stack->nodeName()) ;
@ -136,21 +131,20 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
if(cb->battleCanCastSpell())
attemptCastingSpell();
if(!thereRemainsEnemy())
return BattleAction();
if(auto ret = cbc->battleIsFinished())
{
//spellcast may finish battle
//send special preudo-action
BattleAction cancel;
cancel.actionType = Battle::CANCEL;
return cancel;
}
if(auto action = considerFleeingOrSurrendering())
return *action;
if(cb->battleGetStacks(CBattleInfoEssentials::ONLY_ENEMY).empty())
{
//We apparently won battle by casting spell, return defend... (accessing cb may cause trouble)
return BattleAction::makeDefend(stack);
}
PotentialTargets targets(stack);
if(targets.possibleAttacks.size())
{
auto hlp = targets.bestAction();
@ -165,7 +159,7 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
{
ThreatMap threatsToUs(stack);
auto dists = cbc->battleGetDistances(stack);
const EnemyInfo &ei= *range::min_element(targets.unreachableEnemies, std::bind(isCloser, _1, _2, std::ref(dists)));
const EnemyInfo &ei= *range::min_element(targets.unreachableEnemies, std::bind(isCloser, _1, _2, std::ref(dists)));
if(distToNearestNeighbour(ei.s->position, dists) < GameConstants::BFIELD_SIZE)
{
return goTowards(stack, ei.s->position);
@ -179,7 +173,7 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
}
catch(std::exception &e)
{
logAi->errorStream() << "Exception occurred in " << __FUNCTION__ << " " << e.what();
logAi->error("Exception occurred in %s %s",__FUNCTION__, e.what());
}
return BattleAction::makeDefend(stack);
@ -268,7 +262,7 @@ void CBattleAI::battleStacksRemoved(const BattleStacksRemoved & bsr)
void CBattleAI::print(const std::string &text) const
{
logAi->traceStream() << "CBattleAI [" << this <<"]: " << text;
logAi->trace("CBattleAI [%p]: %s", this, text);
}
BattleAction CBattleAI::goTowards(const CStack * stack, BattleHex destination)
@ -283,7 +277,7 @@ BattleAction CBattleAI::goTowards(const CStack * stack, BattleHex destination)
auto destNeighbours = destination.neighbouringTiles();
if(vstd::contains_if(destNeighbours, [&](BattleHex n) { return stack->coversPos(destination); }))
{
logAi->warnStream() << "Warning: already standing on neighbouring tile!";
logAi->warn("Warning: already standing on neighbouring tile!");
//We shouldn't even be here...
return BattleAction::makeDefend(stack);
}
@ -358,6 +352,7 @@ struct PossibleSpellcast
{
const CSpell *spell;
BattleHex dest;
si32 value;
};
struct CurrentOffensivePotential
@ -430,9 +425,9 @@ void CBattleAI::attemptCastingSpell()
std::vector<PossibleSpellcast> possibleCasts;
for(auto spell : possibleSpells)
{
for(auto hex : getTargetsToConsider(spell))
for(auto hex : getTargetsToConsider(spell, hero))
{
PossibleSpellcast ps = {spell, hex};
PossibleSpellcast ps = {spell, hex, 0};
possibleCasts.push_back(ps);
}
}
@ -457,8 +452,8 @@ void CBattleAI::attemptCastingSpell()
case OFFENSIVE_SPELL:
{
int damageDealt = 0, damageReceived = 0;
auto stacksSuffering = ps.spell->getAffectedStacks(cb.get(), ECastingMode::HERO_CASTING, playerID, skillLevel, ps.dest, hero);
auto stacksSuffering = ps.spell->getAffectedStacks(cb.get(), ECastingMode::HERO_CASTING, hero, skillLevel, ps.dest);
if(stacksSuffering.empty())
return -1;
@ -472,41 +467,52 @@ void CBattleAI::attemptCastingSpell()
damageDealt += dmg;
}
const int damageDiff = damageDealt - damageReceived;
const int damageDiff = damageDealt - damageReceived * 10;
LOGFL("Casting %s on hex %d would deal %d damage points among %d stacks.",
ps.spell->name % ps.dest % damageDiff % stacksSuffering.size());
LOGFL("Casting %s on hex %d would deal { %d %d } damage points among %d stacks.",
ps.spell->name % ps.dest % damageDealt % damageReceived % stacksSuffering.size());
//TODO tactic effect too
return damageDiff;
}
case TIMED_EFFECT:
{
StackWithBonuses swb;
swb.stack = cb->battleGetStackByPos(ps.dest);
if(!swb.stack)
auto stacksAffected = ps.spell->getAffectedStacks(cb.get(), ECastingMode::HERO_CASTING, hero, skillLevel, ps.dest);
if(stacksAffected.empty())
return -1;
Bonus pseudoBonus;
pseudoBonus.sid = ps.spell->id;
pseudoBonus.val = skillLevel;
pseudoBonus.turnsRemain = 1; //TODO
CStack::stackEffectToFeature(swb.bonusesToAdd, pseudoBonus);
int totalGain = 0;
HypotheticChangesToBattleState state;
state.bonusesOfStacks[swb.stack] = &swb;
for(const CStack * sta : stacksAffected)
{
StackWithBonuses swb;
swb.stack = sta;
PotentialTargets pt(swb.stack, state);
auto newValue = pt.bestActionValue();
auto oldValue = valueOfStack[swb.stack];
auto gain = newValue - oldValue;
if(swb.stack->owner != playerID) //enemy
gain = -gain;
Bonus pseudoBonus;
pseudoBonus.sid = ps.spell->id;
pseudoBonus.val = skillLevel;
pseudoBonus.turnsRemain = 1; //TODO
CStack::stackEffectToFeature(swb.bonusesToAdd, pseudoBonus);
LOGFL("Casting %s on %s would improve the stack by %d points (from %d to %d)",
ps.spell->name % swb.stack->nodeName() % gain % (oldValue) % (newValue));
HypotheticChangesToBattleState state;
state.bonusesOfStacks[swb.stack] = &swb;
return gain;
PotentialTargets pt(swb.stack, state);
auto newValue = pt.bestActionValue();
auto oldValue = valueOfStack[swb.stack];
auto gain = newValue - oldValue;
if(swb.stack->owner != playerID) //enemy
gain = -gain;
LOGFL("Casting %s on %s would improve the stack by %d points (from %d to %d)",
ps.spell->name % sta->nodeName() % (gain) % (oldValue) % (newValue));
totalGain += gain;
}
LOGFL("Total gain of cast %s at hex %d is %d", ps.spell->name % (ps.dest.hex) % (totalGain));
return totalGain;
}
default:
assert(0);
@ -514,7 +520,15 @@ void CBattleAI::attemptCastingSpell()
}
};
auto castToPerform = *vstd::maxElementByFun(possibleCasts, evaluateSpellcast);
for(PossibleSpellcast & psc : possibleCasts)
psc.value = evaluateSpellcast(psc);
auto pscValue = [] (const PossibleSpellcast &ps) -> int
{
return ps.value;
};
auto castToPerform = *vstd::maxElementByFun(possibleCasts, pscValue);
LOGFL("Best spell is %s. Will cast.", castToPerform.spell->name);
BattleAction spellcast;
@ -527,24 +541,60 @@ void CBattleAI::attemptCastingSpell()
cb->battleMakeAction(&spellcast);
}
std::vector<BattleHex> CBattleAI::getTargetsToConsider( const CSpell *spell ) const
std::vector<BattleHex> CBattleAI::getTargetsToConsider(const CSpell * spell, const ISpellCaster * caster) const
{
if(spell->getTargetType() == CSpell::NO_TARGET)
const CSpell::TargetInfo targetInfo(spell, caster->getSpellSchoolLevel(spell));
std::vector<BattleHex> ret;
if(targetInfo.massive || targetInfo.type == CSpell::NO_TARGET)
{
//Spell can be casted anywhere, all hexes are potentially considerable.
std::vector<BattleHex> ret;
for(int i = 0; i < GameConstants::BFIELD_SIZE; i++)
if(BattleHex(i).isAvailable())
ret.push_back(i);
return ret;
ret.push_back(BattleHex());
}
else
{
//TODO when massive effect -> doesn't matter where cast
return cbc->battleGetPossibleTargets(playerID, spell);
switch(targetInfo.type)
{
case CSpell::CREATURE:
{
for(const CStack * stack : cbc->battleAliveStacks())
{
bool immune = ESpellCastProblem::OK != spell->isImmuneByStack(caster, stack);
bool casterStack = stack->owner == caster->getOwner();
if(!immune)
switch (spell->positiveness)
{
case CSpell::POSITIVE:
if(casterStack || targetInfo.smart)
ret.push_back(stack->position);
break;
case CSpell::NEUTRAL:
ret.push_back(stack->position);
break;
case CSpell::NEGATIVE:
if(!casterStack || targetInfo.smart)
ret.push_back(stack->position);
break;
}
}
}
break;
case CSpell::LOCATION:
{
for(int i = 0; i < GameConstants::BFIELD_SIZE; i++)
if(BattleHex(i).isAvailable())
ret.push_back(i);
}
break;
default:
break;
}
}
return ret;
}
boost::optional<BattleAction> CBattleAI::considerFleeingOrSurrendering()
@ -610,13 +660,14 @@ ThreatMap::ThreatMap(const CStack *Endangered) : endangered(Endangered)
const TBonusListPtr StackWithBonuses::getAllBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root /*= nullptr*/, const std::string &cachingStr /*= ""*/) const
{
TBonusListPtr ret = make_shared<BonusList>();
TBonusListPtr ret = std::make_shared<BonusList>();
const TBonusListPtr originalList = stack->getAllBonuses(selector, limit, root, cachingStr);
range::copy(*originalList, std::back_inserter(*ret));
for(auto &bonus : bonusesToAdd)
{
if(selector(&bonus) && (!limit || !limit(&bonus)))
ret->push_back(&bonus);
auto b = std::make_shared<Bonus>(bonus);
if(selector(b.get()) && (!limit || !limit(b.get())))
ret->push_back(b);
}
//TODO limiters?
@ -643,7 +694,7 @@ AttackPossibility AttackPossibility::evaluate(const BattleAttackInfo &AttackInfo
auto attacker = AttackInfo.attacker;
auto enemy = AttackInfo.defender;
const int remainingCounterAttacks = getValOr(state.counterAttacksLeft, enemy, enemy->counterAttacks);
const int remainingCounterAttacks = getValOr(state.counterAttacksLeft, enemy, enemy->counterAttacksRemaining());
const bool counterAttacksBlocked = attacker->hasBonusOfType(Bonus::BLOCKS_RETALIATION) || enemy->hasBonusOfType(Bonus::NO_RETALIATION);
const int totalAttacks = 1 + AttackInfo.attackerBonuses->getBonuses(Selector::type(Bonus::ADDITIONAL_ATTACK), (Selector::effectRange (Bonus::NO_LIMIT).Or(Selector::effectRange(Bonus::ONLY_MELEE_FIGHT))))->totalValue();
@ -653,7 +704,7 @@ AttackPossibility AttackPossibility::evaluate(const BattleAttackInfo &AttackInfo
for(int i = 0; i < totalAttacks; i++)
{
std::pair<ui32, ui32> retaliation(0,0);
auto attackDmg = cbc->battleEstimateDamage(curBai, &retaliation);
auto attackDmg = cbc->battleEstimateDamage(CRandomGenerator::getDefault(), curBai, &retaliation);
ap.damageDealt = (attackDmg.first + attackDmg.second) / 2;
ap.damageReceived = (retaliation.first + retaliation.second) / 2;
@ -737,7 +788,7 @@ int PotentialTargets::bestActionValue() const
void EnemyInfo::calcDmg(const CStack * ourStack)
{
TDmgRange retal, dmg = cbc->battleEstimateDamage(ourStack, s, &retal);
TDmgRange retal, dmg = cbc->battleEstimateDamage(CRandomGenerator::getDefault(), ourStack, s, &retal);
adi = (dmg.first + dmg.second) / 2;
adr = (retal.first + retal.second) / 2;
}

View File

@ -51,11 +51,11 @@ static bool willSecondHexBlockMoreEnemyShooters(const BattleHex &h1, const Battl
struct ThreatMap
{
{
std::array<std::vector<BattleAttackInfo>, GameConstants::BFIELD_SIZE> threatMap; // [hexNr] -> enemies able to strike
const CStack *endangered;
std::array<int, GameConstants::BFIELD_SIZE> sufferedDamage;
const CStack *endangered;
std::array<int, GameConstants::BFIELD_SIZE> sufferedDamage;
ThreatMap(const CStack *Endangered);
};
@ -89,7 +89,7 @@ const Val getValOr(const std::map<Key, Val> &Map, const Key &key, const Val2 def
auto i = Map.find(key);
if(i != Map.end())
return i->second;
else
else
return defaultValue;
}
@ -110,9 +110,9 @@ struct PotentialTargets
class CBattleAI : public CBattleGameInterface
{
int side;
shared_ptr<CBattleCallback> cb;
//Previous setting of cb
std::shared_ptr<CBattleCallback> cb;
//Previous setting of cb
bool wasWaitingForRealize, wasUnlockingGs;
void print(const std::string &text) const;
@ -120,7 +120,7 @@ public:
CBattleAI(void);
~CBattleAI(void);
void init(shared_ptr<CBattleCallback> CB) override;
void init(std::shared_ptr<CBattleCallback> CB) override;
void actionFinished(const BattleAction &action) override;//occurs AFTER every action taken by any stack or by the hero
void actionStarted(const BattleAction &action) override;//occurs BEFORE every action taken by any stack or by the hero
BattleAction activeStack(const CStack * stack) override; //called when it's turn of that stack
@ -148,6 +148,6 @@ public:
boost::optional<BattleAction> considerFleeingOrSurrendering();
void attemptCastingSpell();
std::vector<BattleHex> getTargetsToConsider(const CSpell *spell) const;
std::vector<BattleHex> getTargetsToConsider(const CSpell *spell, const ISpellCaster * caster) const;
};

View File

@ -1,12 +1,12 @@
project(battleAI)
cmake_minimum_required(VERSION 2.6)
include_directories(${Boost_INCLUDE_DIRS} ${CMAKE_HOME_DIRECTORY} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_HOME_DIRECTORY}/lib)
include_directories(${Boost_INCLUDE_DIRS} ${CMAKE_HOME_DIRECTORY} ${CMAKE_HOME_DIRECTORY}/include ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_HOME_DIRECTORY}/lib)
set(battleAI_SRCS
StdInc.cpp
BattleAI.cpp
main.cpp
BattleAI.cpp
main.cpp
)
add_library(BattleAI SHARED ${battleAI_SRCS})

View File

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

View File

@ -25,7 +25,7 @@ extern "C" DLL_EXPORT void GetAiName(char* name)
strcpy_s(name, strlen(g_cszAiName) + 1, g_cszAiName);
}
extern "C" DLL_EXPORT void GetNewBattleAI(shared_ptr<CBattleGameInterface> &out)
extern "C" DLL_EXPORT void GetNewBattleAI(std::shared_ptr<CBattleGameInterface> &out)
{
out = make_shared<CBattleAI>();
out = std::make_shared<CBattleAI>();
}

View File

@ -1,9 +1,15 @@
project(AI)
cmake_minimum_required(VERSION 2.8)
find_package(Fuzzylite)
option(FORCE_BUNDLED_FL "Force to use FuzzyLite included into VCMI's source tree" OFF)
if(NOT MSVC)
if (NOT FORCE_BUNDLED_FL)
find_package(Fuzzylite)
else()
set(FL_FOUND FALSE)
endif()
if (NOT MSVC)
add_definitions(-DFL_CPP11)
set(FL_CPP11 ON CACHE BOOL "")
endif()
@ -16,4 +22,4 @@ endif()
add_subdirectory(BattleAI)
add_subdirectory(StupidAI)
add_subdirectory(EmptyAI)
add_subdirectory(VCAI)
add_subdirectory(VCAI)

View File

@ -3,12 +3,11 @@
#include "../../lib/CRandomGenerator.h"
void CEmptyAI::init(shared_ptr<CCallback> CB)
void CEmptyAI::init(std::shared_ptr<CCallback> CB)
{
cb = CB;
human=false;
playerID = *cb->getMyColor();
//logAi->infoStream() << "EmptyAI initialized.";
}
void CEmptyAI::yourTurn()
{
@ -30,7 +29,7 @@ void CEmptyAI::showBlockingDialog(const std::string &text, const std::vector<Com
cb->selectionMade(0, askID);
}
void CEmptyAI::showTeleportDialog(TeleportChannelID channel, std::vector<ObjectInstanceID> exits, bool impassable, QueryID askID)
void CEmptyAI::showTeleportDialog(TeleportChannelID channel, TTeleportExitsList exits, bool impassable, QueryID askID)
{
cb->selectionMade(0, askID);
}

View File

@ -7,15 +7,15 @@ struct HeroMoveDetails;
class CEmptyAI : public CGlobalAI
{
shared_ptr<CCallback> cb;
std::shared_ptr<CCallback> cb;
public:
void init(shared_ptr<CCallback> CB) override;
void init(std::shared_ptr<CCallback> CB) override;
void yourTurn() override;
void heroGotLevel(const CGHeroInstance *hero, PrimarySkill::PrimarySkill pskill, std::vector<SecondarySkill> &skills, QueryID queryID) override;
void commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, QueryID queryID) override;
void showBlockingDialog(const std::string &text, const std::vector<Component> &components, QueryID askID, const int soundID, bool selection, bool cancel) override;
void showTeleportDialog(TeleportChannelID channel, std::vector<ObjectInstanceID> exits, bool impassable, QueryID askID) override;
void showTeleportDialog(TeleportChannelID channel, TTeleportExitsList exits, bool impassable, QueryID askID) override;
void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, QueryID queryID) override;
};

View File

@ -1,11 +1,11 @@
project(emptyAI)
cmake_minimum_required(VERSION 2.6)
include_directories(${Boost_INCLUDE_DIRS} ${CMAKE_HOME_DIRECTORY} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_HOME_DIRECTORY}/lib)
include_directories(${Boost_INCLUDE_DIRS} ${CMAKE_HOME_DIRECTORY} ${CMAKE_HOME_DIRECTORY}/include ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_HOME_DIRECTORY}/lib)
set(emptyAI_SRCS
CEmptyAI.cpp
exp_funcs.cpp
CEmptyAI.cpp
exp_funcs.cpp
)
add_library(EmptyAI SHARED ${emptyAI_SRCS})

View File

@ -6,58 +6,50 @@
<Option pch_mode="2" />
<Option compiler="gcc" />
<Build>
<Target title="Debug-win32-SDL2">
<Target title="Debug-win32">
<Option platforms="Windows;" />
<Option output="../EmptyAI" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Debug/" />
<Option object_output="obj/Debug/x86/" />
<Option type="3" />
<Option compiler="gcc" />
<Compiler>
<Add option="-ggdb" />
</Compiler>
</Target>
<Target title="Release-win32-SDL2">
<Option platforms="Windows;" />
<Option output="../EmptyAI" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Release/" />
<Option type="3" />
<Option compiler="gcc" />
<Compiler>
<Add option="-fomit-frame-pointer" />
<Add option="-O3" />
</Compiler>
<Linker>
<Add option="-s" />
<Add directory="$(#boost.lib32)" />
</Linker>
</Target>
<Target title="Debug-win32-SDL1">
<Target title="Release-win32">
<Option platforms="Windows;" />
<Option output="../EmptyAI" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Debug/" />
<Option object_output="obj/Release/x86/" />
<Option type="3" />
<Option compiler="gcc" />
<Compiler>
<Add option="-O2" />
</Compiler>
<Linker>
<Add directory="$(#boost.lib32)" />
</Linker>
</Target>
<Target title="Debug-win64">
<Option platforms="Windows;" />
<Option output="../EmptyAI" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Debug/x64/" />
<Option type="3" />
<Option compiler="gnu_gcc_compiler_x64" />
<Compiler>
<Add option="-ggdb" />
</Compiler>
</Target>
<Target title="Release-win32-SDL1">
<Option platforms="Windows;" />
<Option output="../EmptyAI" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Release/" />
<Option type="3" />
<Option compiler="gcc" />
<Compiler>
<Add option="-fomit-frame-pointer" />
<Add option="-O3" />
</Compiler>
<Linker>
<Add option="-s" />
<Add directory="$(#boost.lib64)" />
</Linker>
</Target>
</Build>
<Compiler>
<Add option="-Wextra" />
<Add option="-Wall" />
<Add option="-std=gnu++11" />
<Add option="-fexceptions" />
<Add option="-Wpointer-arith" />
<Add option="-Wno-switch" />
@ -71,12 +63,12 @@
<Linker>
<Add option="-lboost_system$(#boost.libsuffix)" />
<Add option="-lVCMI_lib" />
<Add directory="$(#boost.lib32)" />
<Add directory="../.." />
</Linker>
<Unit filename="CEmptyAI.cpp" />
<Unit filename="CEmptyAI.h" />
<Unit filename="StdInc.h">
<Option compile="1" />
<Option weight="0" />
</Unit>
<Unit filename="exp_funcs.cpp" />

View File

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

View File

@ -13,7 +13,7 @@ extern "C" DLL_EXPORT void GetAiName(char* name)
strcpy(name,NAME);
}
extern "C" DLL_EXPORT void GetNewAI(shared_ptr<CGlobalAI> &out)
extern "C" DLL_EXPORT void GetNewAI(std::shared_ptr<CGlobalAI> &out)
{
out = make_shared<CEmptyAI>();
}
out = std::make_shared<CEmptyAI>();
}

View File

@ -6,23 +6,24 @@
<Option pch_mode="2" />
<Option compiler="gcc" />
<Build>
<Target title="Debug-win32-SDL2">
<Target title="Debug-win32">
<Option platforms="Windows;" />
<Option output="bin/Debug/FuzzyLite" prefix_auto="1" extension_auto="1" />
<Option output="../FuzzyLite" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="obj/Debug/" />
<Option object_output="obj/Debug/x86/" />
<Option type="2" />
<Option compiler="gcc" />
<Option createDefFile="1" />
<Compiler>
<Add option="-Og" />
<Add option="-g" />
</Compiler>
</Target>
<Target title="Release-win32-SDL2">
<Target title="Release-win32">
<Option platforms="Windows;" />
<Option output="bin/Release/FuzzyLite" prefix_auto="1" extension_auto="1" />
<Option output="../FuzzyLite" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="obj/Release/" />
<Option object_output="obj/Release/x86/" />
<Option type="2" />
<Option compiler="gcc" />
<Option createDefFile="1" />
@ -34,38 +35,24 @@
<Add option="-s" />
</Linker>
</Target>
<Target title="Debug-win32-SDL1">
<Target title="Debug-win64">
<Option platforms="Windows;" />
<Option output="bin/Debug/FuzzyLite" prefix_auto="1" extension_auto="1" />
<Option output="../FuzzyLite" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="obj/Debug/" />
<Option object_output="obj/Debug/x64/" />
<Option type="2" />
<Option compiler="gcc" />
<Option compiler="gnu_gcc_compiler_x64" />
<Option createDefFile="1" />
<Compiler>
<Add option="-Og" />
<Add option="-g" />
</Compiler>
</Target>
<Target title="Release-win32-SDL1">
<Option platforms="Windows;" />
<Option output="bin/Release/FuzzyLite" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="obj/Release/" />
<Option type="2" />
<Option compiler="gcc" />
<Option createDefFile="1" />
<Compiler>
<Add option="-fomit-frame-pointer" />
<Add option="-O2" />
</Compiler>
<Linker>
<Add option="-s" />
</Linker>
</Target>
</Build>
<Compiler>
<Add option="-Wextra" />
<Add option="-Wall" />
<Add option="-std=gnu++11" />
<Add option="-fexceptions" />
<Add option="-Wpointer-arith" />
<Add option="-Wno-switch" />
@ -74,7 +61,6 @@
<Add option="-Wno-overloaded-virtual" />
<Add option="-DFL_CPP11" />
<Add option="-DFL_WINDOWS" />
<Add directory="$(#boost.include)" />
<Add directory="fuzzylite" />
</Compiler>
<Unit filename="fuzzylite/fl/Console.h" />

View File

@ -251,7 +251,7 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">
<OutDir>..</OutDir>
<IncludePath>$(IncludePath)</IncludePath>
<IncludePath>$(SolutionDir)\AI\FuzzyLite\fuzzylite;$(IncludePath)</IncludePath>
<LibraryPath>$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RD|x64'">

View File

@ -1,12 +1,12 @@
project(stupidAI)
cmake_minimum_required(VERSION 2.6)
include_directories(${Boost_INCLUDE_DIRS} ${CMAKE_HOME_DIRECTORY} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_HOME_DIRECTORY}/lib)
include_directories(${Boost_INCLUDE_DIRS} ${CMAKE_HOME_DIRECTORY} ${CMAKE_HOME_DIRECTORY}/include ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_HOME_DIRECTORY}/lib)
set(stupidAI_SRCS
StdInc.cpp
StupidAI.cpp
main.cpp
StupidAI.cpp
main.cpp
)
add_library(StupidAI SHARED ${stupidAI_SRCS})

View File

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

View File

@ -6,44 +6,20 @@
<Option pch_mode="2" />
<Option compiler="gcc" />
<Build>
<Target title="Debug-win32-SDL2">
<Target title="Debug-win32">
<Option platforms="Windows;" />
<Option output="../StupidAI" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Debug/" />
<Option object_output="obj/Debug/x86" />
<Option type="3" />
<Option compiler="gcc" />
<Compiler>
<Add option="-ggdb" />
</Compiler>
</Target>
<Target title="Release-win32-SDL2">
<Target title="Release-win32">
<Option platforms="Windows;" />
<Option output="../StupidAI" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Release/" />
<Option type="3" />
<Option compiler="gcc" />
<Compiler>
<Add option="-fomit-frame-pointer" />
<Add option="-O3" />
</Compiler>
<Linker>
<Add option="-s" />
</Linker>
</Target>
<Target title="Debug-win32-SDL1">
<Option platforms="Windows;" />
<Option output="../StupidAI" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Debug/" />
<Option type="3" />
<Option compiler="gcc" />
<Compiler>
<Add option="-ggdb" />
</Compiler>
</Target>
<Target title="Release-win32-SDL1">
<Option platforms="Windows;" />
<Option output="../StupidAI" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Release/" />
<Option object_output="obj/Release/x86" />
<Option type="3" />
<Option compiler="gcc" />
<Compiler>
@ -59,6 +35,7 @@
<Add option="-pedantic" />
<Add option="-Wextra" />
<Add option="-Wall" />
<Add option="-std=gnu++11" />
<Add option="-fexceptions" />
<Add option="-Wpointer-arith" />
<Add option="-Wno-switch" />
@ -77,6 +54,7 @@
<Add directory="../.." />
</Linker>
<Unit filename="StdInc.h">
<Option compile="1" />
<Option weight="0" />
</Unit>
<Unit filename="StupidAI.cpp" />

View File

@ -5,7 +5,7 @@
#include "../../CCallback.h"
#include "../../lib/CCreatureHandler.h"
static shared_ptr<CBattleCallback> cbc;
static std::shared_ptr<CBattleCallback> cbc;
CStupidAI::CStupidAI(void)
: side(-1)
@ -19,7 +19,7 @@ CStupidAI::~CStupidAI(void)
print("destroyed");
}
void CStupidAI::init(shared_ptr<CBattleCallback> CB)
void CStupidAI::init(std::shared_ptr<CBattleCallback> CB)
{
print("init called, saving ptr to IBattleCallback");
cbc = cb = CB;
@ -44,7 +44,7 @@ struct EnemyInfo
{}
void calcDmg(const CStack * ourStack)
{
TDmgRange retal, dmg = cbc->battleEstimateDamage(ourStack, s, &retal);
TDmgRange retal, dmg = cbc->battleEstimateDamage(CRandomGenerator::getDefault(), ourStack, s, &retal);
adi = (dmg.first + dmg.second) / 2;
adr = (retal.first + retal.second) / 2;
}
@ -108,7 +108,7 @@ BattleAction CStupidAI::activeStack( const CStack * stack )
if(stack->type->idNumber == CreatureID::CATAPULT)
{
BattleAction attack;
static const std::vector<int> wallHexes = {50, 183, 182, 130, 62, 29, 12, 95};
static const std::vector<int> wallHexes = {50, 183, 182, 130, 78, 29, 12, 95};
attack.destinationTile = *RandomGeneratorUtil::nextItem(wallHexes, CRandomGenerator::getDefault());
attack.actionType = Battle::CATAPULT;
@ -153,6 +153,12 @@ BattleAction CStupidAI::activeStack( const CStack * stack )
}
}
for ( auto & enemy : enemiesReachable )
enemy.calcDmg( stack );
for ( auto & enemy : enemiesShootable )
enemy.calcDmg( stack );
if(enemiesShootable.size())
{
const EnemyInfo &ei= *std::max_element(enemiesShootable.begin(), enemiesShootable.end(), isMoreProfitable);
@ -255,7 +261,7 @@ void CStupidAI::battleStacksRemoved(const BattleStacksRemoved & bsr)
void CStupidAI::print(const std::string &text) const
{
logAi->traceStream() << "CStupidAI [" << this <<"]: " << text;
logAi->trace("CStupidAI [%p]: %s", this, text);
}
BattleAction CStupidAI::goTowards(const CStack * stack, BattleHex destination)
@ -270,7 +276,7 @@ BattleAction CStupidAI::goTowards(const CStack * stack, BattleHex destination)
auto destNeighbours = destination.neighbouringTiles();
if(vstd::contains_if(destNeighbours, [&](BattleHex n) { return stack->coversPos(destination); }))
{
logAi->warnStream() << "Warning: already standing on neighbouring tile!";
logAi->warn("Warning: already standing on neighbouring tile!");
//We shouldn't even be here...
return BattleAction::makeDefend(stack);
}
@ -321,13 +327,13 @@ BattleAction CStupidAI::goTowards(const CStack * stack, BattleHex destination)
}
}
void CStupidAI::saveGame(COSer & h, const int version)
void CStupidAI::saveGame(BinarySerializer & h, const int version)
{
//TODO to be implemented with saving/loading during the battles
assert(0);
}
void CStupidAI::loadGame(CISer & h, const int version)
void CStupidAI::loadGame(BinaryDeserializer & h, const int version)
{
//TODO to be implemented with saving/loading during the battles
assert(0);

View File

@ -5,14 +5,14 @@
class CStupidAI : public CBattleGameInterface
{
int side;
shared_ptr<CBattleCallback> cb;
std::shared_ptr<CBattleCallback> cb;
void print(const std::string &text) const;
public:
CStupidAI(void);
~CStupidAI(void);
void init(shared_ptr<CBattleCallback> CB) override;
void init(std::shared_ptr<CBattleCallback> CB) override;
void actionFinished(const BattleAction &action) override;//occurs AFTER every action taken by any stack or by the hero
void actionStarted(const BattleAction &action) override;//occurs BEFORE every action taken by any stack or by the hero
BattleAction activeStack(const CStack * stack) override; //called when it's turn of that stack
@ -36,8 +36,8 @@ public:
BattleAction goTowards(const CStack * stack, BattleHex hex );
virtual void saveGame(COSer & h, const int version) override;
virtual void loadGame(CISer & h, const int version) override;
virtual void saveGame(BinarySerializer & h, const int version) override;
virtual void loadGame(BinaryDeserializer & h, const int version) override;
};

View File

@ -25,7 +25,7 @@ extern "C" DLL_EXPORT void GetAiName(char* name)
strcpy_s(name, strlen(g_cszAiName) + 1, g_cszAiName);
}
extern "C" DLL_EXPORT void GetNewBattleAI(shared_ptr<CBattleGameInterface> &out)
extern "C" DLL_EXPORT void GetNewBattleAI(std::shared_ptr<CBattleGameInterface> &out)
{
out = make_shared<CStupidAI>();
out = std::make_shared<CStupidAI>();
}

View File

@ -7,6 +7,10 @@
#include "../../lib/CConfigHandler.h"
#include "../../lib/CHeroHandler.h"
#include "../../lib/mapObjects/CBank.h"
#include "../../lib/mapObjects/CGTownInstance.h"
#include "../../lib/mapObjects/CQuest.h"
#include "../../lib/CPathfinder.h"
#include "../../lib/mapping/CMapDefines.h"
/*
* AIUtility.cpp, part of VCMI engine
@ -150,7 +154,7 @@ void foreach_neighbour(const int3 &pos, std::function<void(const int3& pos)> foo
{
CCallback * cbp = cb.get(); // avoid costly retrieval of thread-specific pointer
for(const int3 &dir : dirs)
for(const int3 &dir : int3::getDirs())
{
const int3 n = pos + dir;
if(cbp->isInTheMap(n))
@ -160,7 +164,7 @@ void foreach_neighbour(const int3 &pos, std::function<void(const int3& pos)> foo
void foreach_neighbour(CCallback * cbp, const int3 &pos, std::function<void(CCallback * cbp, const int3& pos)> foo)
{
for(const int3 &dir : dirs)
for(const int3 &dir : int3::getDirs())
{
const int3 n = pos + dir;
if(cbp->isInTheMap(n))
@ -335,7 +339,7 @@ bool isSafeToVisit(HeroPtr h, crint3 tile)
{
if(heroStrength / SAFE_ATTACK_CONSTANT > dangerStrength)
{
logAi->traceStream() << boost::format("It's safe for %s to visit tile %s") % h->name % tile;
logAi->trace("It's safe for %s to visit tile %s", h->name, tile());
return true;
}
else
@ -356,10 +360,10 @@ bool canBeEmbarkmentPoint(const TerrainTile *t, bool fromWater)
int3 whereToExplore(HeroPtr h)
{
TimeCheck tc ("where to explore");
int radius = h->getSightRadious();
int radius = h->getSightRadius();
int3 hpos = h->visitablePos();
SectorMap sm(h);
auto sm = ai->getCachedSectorMap(h);
//look for nearby objs -> visit them if they're close enouh
const int DIST_LIMIT = 3;
@ -372,9 +376,9 @@ int3 whereToExplore(HeroPtr h)
{
int3 op = obj->visitablePos();
CGPath p;
ai->myCb->getPathsInfo(h.get())->getPath(op, p);
ai->myCb->getPathsInfo(h.get())->getPath(p, op);
if (p.nodes.size() && p.endPos() == op && p.nodes.size() <= DIST_LIMIT)
if (ai->isGoodForVisit(obj, h, sm))
if (ai->isGoodForVisit(obj, h, *sm))
nearbyVisitableObjs.push_back(obj);
}
}
@ -432,7 +436,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;
@ -505,8 +509,10 @@ bool compareArtifacts(const CArtifactInstance *a1, const CArtifactInstance *a2)
auto art1 = a1->artType;
auto art2 = a2->artType;
if (art1->valOfBonuses(Bonus::PRIMARY_SKILL) > art2->valOfBonuses(Bonus::PRIMARY_SKILL))
if(art1->price == art2->price)
return art1->valOfBonuses(Bonus::PRIMARY_SKILL) > art2->valOfBonuses(Bonus::PRIMARY_SKILL);
else if(art1->price > art2->price)
return true;
else
return art1->price > art2->price;
}
return false;
}

View File

@ -5,11 +5,9 @@
#include "../../lib/CCreatureHandler.h"
#include "../../lib/CTownHandler.h"
#include "../../lib/spells/CSpellHandler.h"
#include "../../lib/Connection.h"
#include "../../lib/CGameState.h"
#include "../../lib/mapping/CMap.h"
#include "../../lib/NetPacks.h"
#include "../../lib/CStopWatch.h"
#include "../../lib/mapObjects/CObjectHandler.h"
#include "../../lib/mapObjects/CGHeroInstance.h"
/*
* AIUtility.h, part of VCMI engine
@ -21,10 +19,11 @@
*
*/
class CCallback;
typedef const int3& crint3;
typedef const std::string& crstring;
const int HERO_GOLD_COST = 2500;
const int GOLD_MINE_PRODUCTION = 1000, WOOD_ORE_MINE_PRODUCTION = 2, RESOURCE_MINE_PRODUCTION = 1;
const int ACTUAL_RESOURCE_COUNT = 7;
const int ALLOWED_ROAMING_HEROES = 8;
@ -44,7 +43,7 @@ struct HeroPtr
public:
std::string name;
HeroPtr();
HeroPtr(const CGHeroInstance *H);
~HeroPtr();
@ -107,7 +106,7 @@ struct TimeCheck
~TimeCheck()
{
logAi->traceStream() << boost::format("Time of %s was %d ms.") % txt % time.getDiff();
logAi->trace("Time of %s was %d ms.",txt,time.getDiff());
}
};
@ -131,10 +130,10 @@ private:
template<int id>
bool objWithID(const CGObjectInstance *obj)
{
return obj->ID == id;
return obj->ID == id;
}
std::string strFromInt3(int3 pos);
std::string strFromInt3(int3 pos);//todo: remove
void foreach_tile_pos(std::function<void(const int3& pos)> foo);
void foreach_tile_pos(CCallback * cbp, std::function<void(CCallback * cbp, const int3& pos)> foo); // avoid costly retrieval of thread-specific pointer
void foreach_neighbour(const int3 &pos, std::function<void(const int3& pos)> foo);

View File

@ -2,18 +2,19 @@ project(VCAI)
cmake_minimum_required(VERSION 2.6)
if (FL_FOUND)
include_directories(${Boost_INCLUDE_DIRS} ${CMAKE_HOME_DIRECTORY} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_HOME_DIRECTORY}/lib ${FL_INCLUDE_DIRS})
include_directories(${FL_INCLUDE_DIRS})
else()
include_directories(${Boost_INCLUDE_DIRS} ${CMAKE_HOME_DIRECTORY} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_HOME_DIRECTORY}/lib ${CMAKE_HOME_DIRECTORY}/AI/FuzzyLite/fuzzylite)
include_directories(${CMAKE_HOME_DIRECTORY}/AI/FuzzyLite/fuzzylite)
endif()
include_directories(${Boost_INCLUDE_DIRS} ${CMAKE_HOME_DIRECTORY} ${CMAKE_HOME_DIRECTORY}/include ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_HOME_DIRECTORY}/lib)
set(VCAI_SRCS
StdInc.cpp
VCAI.cpp
Goals.cpp
AIUtility.cpp
main.cpp
Fuzzy.cpp
StdInc.cpp
VCAI.cpp
Goals.cpp
AIUtility.cpp
main.cpp
Fuzzy.cpp
)
add_library(VCAI SHARED ${VCAI_SRCS})

View File

@ -5,6 +5,8 @@
#include "../../lib/mapObjects/MapObjects.h"
#include "../../lib/mapObjects/CommonConstructors.h"
#include "../../lib/CCreatureHandler.h"
#include "../../lib/CPathfinder.h"
#include "../../lib/CGameStateFwd.h"
#include "../../lib/VCMI_Lib.h"
#include "../../CCallback.h"
#include "VCAI.h"
@ -29,7 +31,6 @@ class Engine;
class InputVariable;
class CGTownInstance;
using namespace vstd;
//using namespace Goals;
FuzzyHelper *fh;
@ -45,7 +46,7 @@ engineBase::engineBase()
void engineBase::configure()
{
engine.configure("Minimum", "Maximum", "Minimum", "AlgebraicSum", "Centroid");
logAi->infoStream() << engine.toString();
logAi->info(engine.toString());
}
void engineBase::addRule(const std::string &txt)
@ -83,7 +84,7 @@ armyStructure evaluateArmyStructure (const CArmedInstance * army)
if (walker)
walkersStrenght += s.second->getPower();
amax (maxSpeed, s.second->type->valOfBonuses(Bonus::STACKS_SPEED));
vstd::amax(maxSpeed, s.second->type->valOfBonuses(Bonus::STACKS_SPEED));
}
armyStructure as;
as.walkers = walkersStrenght / totalStrenght;
@ -148,7 +149,7 @@ void FuzzyHelper::initTacticalAdvantage()
{
fl::Rectangle* none = new fl::Rectangle("NONE", CGTownInstance::NONE, CGTownInstance::NONE + (CGTownInstance::FORT - CGTownInstance::NONE) * 0.5f);
ta.castleWalls->addTerm(none);
fl::Trapezoid* medium = new fl::Trapezoid("MEDIUM", (CGTownInstance::FORT - CGTownInstance::NONE) * 0.5f, CGTownInstance::FORT,
CGTownInstance::CITADEL, CGTownInstance::CITADEL + (CGTownInstance::CASTLE - CGTownInstance::CITADEL) * 0.5f);
ta.castleWalls->addTerm(medium);
@ -159,7 +160,7 @@ void FuzzyHelper::initTacticalAdvantage()
ta.castleWalls->setRange(CGTownInstance::NONE, CGTownInstance::CASTLE);
}
ta.bankPresent = new fl::InputVariable("Bank");
ta.engine.addInputVariable(ta.bankPresent);
@ -200,7 +201,7 @@ void FuzzyHelper::initTacticalAdvantage()
}
catch (fl::Exception & pe)
{
logAi->errorStream() << "initTacticalAdvantage " << ": " << pe.getWhat();
logAi->error("initTacticalAdvantage: %s", pe.getWhat());
}
}
@ -261,7 +262,7 @@ float FuzzyHelper::getTacticalAdvantage (const CArmedInstance *we, const CArmedI
}
catch (fl::Exception & fe)
{
logAi->errorStream() << "getTacticalAdvantage " << ": " << fe.getWhat();
logAi->error("getTacticalAdvantage: %s ",fe.getWhat());
}
if (output < 0 || (output != output))
@ -272,7 +273,7 @@ float FuzzyHelper::getTacticalAdvantage (const CArmedInstance *we, const CArmedI
for (int i = 0; i < boost::size(tab); i++)
log << names[i] << ": " << tab[i]->getInputValue() << " ";
logAi->errorStream() << log.str();
logAi->error(log.str());
assert(false);
}
@ -295,13 +296,15 @@ FuzzyHelper::TacticalAdvantage::~TacticalAdvantage()
delete threat;
}
//shared_ptr<AbstractGoal> chooseSolution (std::vector<shared_ptr<AbstractGoal>> & vec)
//std::shared_ptr<AbstractGoal> chooseSolution (std::vector<std::shared_ptr<AbstractGoal>> & vec)
Goals::TSubgoal FuzzyHelper::chooseSolution (Goals::TGoalVec vec)
{
if (vec.empty()) //no possibilities found
return sptr(Goals::Invalid());
ai->cachedSectorMaps.clear();
//a trick to switch between heroes less often - calculatePaths is costly
auto sortByHeroes = [](const Goals::TSubgoal & lhs, const Goals::TSubgoal & rhs) -> bool
{
@ -407,7 +410,7 @@ void FuzzyHelper::initVisitTile()
}
catch (fl::Exception & fe)
{
logAi->errorStream() << "visitTile " << ": " << fe.getWhat();
logAi->error("visitTile: %s",fe.getWhat());
}
}
@ -419,7 +422,7 @@ float FuzzyHelper::evaluate (Goals::VisitTile & g)
//assert(cb->isInTheMap(g.tile));
float turns = 0;
float distance = cb->getMovementCost(g.hero.h, g.tile);
float distance = CPathfinderHelper::getMovementCost(g.hero.h, g.tile);
if (!distance) //we stand on that tile
turns = 0;
else
@ -452,11 +455,10 @@ float FuzzyHelper::evaluate (Goals::VisitTile & g)
}
catch (fl::Exception & fe)
{
logAi->errorStream() << "evaluate VisitTile " << ": " << fe.getWhat();
logAi->error("evaluate VisitTile: %s",fe.getWhat());
}
assert (g.priority >= 0);
return g.priority;
}
float FuzzyHelper::evaluate (Goals::VisitHero & g)
{
@ -465,7 +467,7 @@ float FuzzyHelper::evaluate (Goals::VisitHero & g)
return -100; //hero died in the meantime
//TODO: consider direct copy (constructor?)
g.setpriority(Goals::VisitTile(obj->visitablePos()).sethero(g.hero).setisAbstract(g.isAbstract).accept(this));
return g.priority;
return g.priority;
}
float FuzzyHelper::evaluate (Goals::GatherArmy & g)
{
@ -480,8 +482,7 @@ float FuzzyHelper::evaluate (Goals::ClearWayTo & g)
if (!g.hero.h)
throw cannotFulfillGoalException("ClearWayTo called without hero!");
SectorMap sm(g.hero);
int3 t = sm.firstTileToGet(g.hero, g.tile);
int3 t = ai->getCachedSectorMap(g.hero)->firstTileToGet(g.hero, g.tile);
if (t.valid())
{
@ -523,7 +524,7 @@ float FuzzyHelper::evaluate (Goals::Invalid & g)
}
float FuzzyHelper::evaluate (Goals::AbstractGoal & g)
{
logAi->warnStream() << boost::format("Cannot evaluate goal %s") % g.name();
logAi->warn("Cannot evaluate goal %s", g.name());
return g.priority;
}
void FuzzyHelper::setPriority (Goals::TSubgoal & g)

View File

@ -15,6 +15,7 @@
class VCAI;
class CArmedInstance;
class CBank;
struct SectorMap;
class engineBase
{
@ -54,6 +55,8 @@ class FuzzyHelper
~EvalVisitTile();
} vt;
public:
enum RuleBlocks {BANK_DANGER, TACTICAL_ADVANTAGE, VISIT_TILE};
//blocks should be initialized in this order, which may be confusing :/
@ -80,5 +83,5 @@ public:
float getTacticalAdvantage (const CArmedInstance *we, const CArmedInstance *enemy); //returns factor how many times enemy is stronger than us
Goals::TSubgoal chooseSolution (Goals::TGoalVec vec);
//shared_ptr<AbstractGoal> chooseSolution (std::vector<shared_ptr<AbstractGoal>> & vec);
//std::shared_ptr<AbstractGoal> chooseSolution (std::vector<std::shared_ptr<AbstractGoal>> & vec);
};

View File

@ -3,6 +3,7 @@
#include "VCAI.h"
#include "Fuzzy.h"
#include "../../lib/mapping/CMap.h" //for victory conditions
#include "../../lib/CPathfinder.h"
/*
* Goals.cpp, part of VCMI engine
@ -18,12 +19,11 @@ extern boost::thread_specific_ptr<CCallback> cb;
extern boost::thread_specific_ptr<VCAI> ai;
extern FuzzyHelper * fh; //TODO: this logic should be moved inside VCAI
using namespace vstd;
using namespace Goals;
TSubgoal Goals::sptr(const AbstractGoal & tmp)
{
shared_ptr<AbstractGoal> ptr;
std::shared_ptr<AbstractGoal> ptr;
ptr.reset(tmp.clone());
return ptr;
}
@ -154,8 +154,8 @@ bool Goals::AbstractGoal::operator== (AbstractGoal &g)
//TODO: find out why the following are not generated automatically on MVS?
namespace Goals
{
namespace Goals
{
template <>
void CGoal<Win>::accept (VCAI * ai)
{
@ -182,8 +182,8 @@ namespace Goals
//TSubgoal AbstractGoal::whatToDoToAchieve()
//{
// logAi->debugStream() << boost::format("Decomposing goal of type %s") % name();
// return sptr (Goals::Explore());
// logAi->debug("Decomposing goal of type %s",name());
// return sptr (Goals::Explore());
//}
TSubgoal Win::whatToDoToAchieve()
@ -275,7 +275,7 @@ TSubgoal Win::whatToDoToAchieve()
// 0.85 -> radius now 2 tiles
// 0.95 -> 1 tile radius, position is fully known
// AFAIK H3 AI does something like this
int3 grailPos = cb->getGrailPos(ratio);
int3 grailPos = cb->getGrailPos(&ratio);
if(ratio > 0.99)
{
return sptr (Goals::DigAtTile(grailPos));
@ -367,7 +367,7 @@ TSubgoal FindObj::whatToDoToAchieve()
std::string GetObj::completeMessage() const
{
return "hero " + hero.get()->name + " captured Object ID = " + boost::lexical_cast<std::string>(objid);
return "hero " + hero.get()->name + " captured Object ID = " + boost::lexical_cast<std::string>(objid);
}
TSubgoal GetObj::whatToDoToAchieve()
@ -409,7 +409,7 @@ bool GetObj::fulfillsMe (TSubgoal goal)
std::string VisitHero::completeMessage() const
{
return "hero " + hero.get()->name + " visited hero " + boost::lexical_cast<std::string>(objid);
return "hero " + hero.get()->name + " visited hero " + boost::lexical_cast<std::string>(objid);
}
TSubgoal VisitHero::whatToDoToAchieve()
@ -422,7 +422,7 @@ TSubgoal VisitHero::whatToDoToAchieve()
if (hero && ai->isAccessibleForHero(pos, hero, true) && isSafeToVisit(hero, pos)) //enemy heroes can get reinforcements
{
if (hero->pos == pos)
logAi->errorStream() << "Hero " << hero.name << " tries to visit himself.";
logAi->error("Hero %s tries to visit himself.", hero.name);
else
{
//can't use VISIT_TILE here as tile appears blocked by target hero
@ -435,10 +435,17 @@ TSubgoal VisitHero::whatToDoToAchieve()
bool VisitHero::fulfillsMe (TSubgoal goal)
{
if (goal->goalType == Goals::VISIT_TILE && cb->getObj(ObjectInstanceID(objid))->visitablePos() == goal->tile)
return true;
else
if (goal->goalType != Goals::VISIT_TILE)
{
return false;
}
auto obj = cb->getObj(ObjectInstanceID(objid));
if (!obj)
{
logAi->error("Hero %s: VisitHero::fulfillsMe at %s: object %d not found", hero.name, goal->tile, objid);
return false;
}
return obj->visitablePos() == goal->tile;
}
TSubgoal GetArtOfType::whatToDoToAchieve()
@ -454,11 +461,11 @@ TSubgoal ClearWayTo::whatToDoToAchieve()
assert(cb->isInTheMap(tile)); //set tile
if(!cb->isVisible(tile))
{
logAi->errorStream() << "Clear way should be used with visible tiles!";
logAi->error("Clear way should be used with visible tiles!");
return sptr (Goals::Explore());
}
return (fh->chooseSolution(getAllPossibleSubgoals()));
return (fh->chooseSolution(getAllPossibleSubgoals()));
}
TGoalVec ClearWayTo::getAllPossibleSubgoals()
@ -483,9 +490,9 @@ TGoalVec ClearWayTo::getAllPossibleSubgoals()
//if our hero is trapped, make sure we request clearing the way from OUR perspective
SectorMap sm(h);
auto sm = ai->getCachedSectorMap(h);
int3 tileToHit = sm.firstTileToGet(h, tile);
int3 tileToHit = sm->firstTileToGet(h, tile);
if (!tileToHit.valid())
continue;
@ -505,7 +512,7 @@ TGoalVec ClearWayTo::getAllPossibleSubgoals()
if (topObj->ID == Obj::HERO && cb->getPlayerRelations(h->tempOwner, topObj->tempOwner) != PlayerRelations::ENEMIES)
if (topObj != hero.get(true)) //the hero we want to free
logAi->errorStream() << boost::format("%s stands in the way of %s") % topObj->getObjectName() % h->getObjectName();
logAi->error("%s stands in the way of %s", topObj->getObjectName(), h->getObjectName());
if (topObj->ID == Obj::QUEST_GUARD || topObj->ID == Obj::BORDERGUARD)
{
if (shouldVisit(h, topObj))
@ -517,11 +524,11 @@ TGoalVec ClearWayTo::getAllPossibleSubgoals()
else
{
//TODO: we should be able to return apriopriate quest here (VCAI::striveToQuest)
logAi->debugStream() << "Quest guard blocks the way to " + tile();
logAi->debug("Quest guard blocks the way to %s", tile());
continue; //do not access quets guard if we can't complete the quest
}
}
}
if (isSafeToVisit(h, tileToHit)) //this makes sense only if tile is guarded, but there i no quest object
{
ret.push_back (sptr (Goals::VisitTile(tileToHit).sethero(h)));
@ -537,7 +544,7 @@ TGoalVec ClearWayTo::getAllPossibleSubgoals()
if (ret.empty())
{
logAi->warnStream() << "There is no known way to clear the way to tile " + tile();
logAi->warn("There is no known way to clear the way to tile %s",tile());
throw goalFulfilledException (sptr(Goals::ClearWayTo(tile))); //make sure asigned hero gets unlocked
}
@ -574,7 +581,7 @@ TGoalVec Explore::getAllPossibleSubgoals()
{
//heroes = ai->getUnblockedHeroes();
heroes = cb->getHeroesInfo();
erase_if (heroes, [](const HeroPtr h)
vstd::erase_if(heroes, [](const HeroPtr h)
{
if (ai->getGoal(h)->goalType == Goals::EXPLORE) //do not reassign hero who is already explorer
return true;
@ -633,11 +640,11 @@ TGoalVec Explore::getAllPossibleSubgoals()
for (auto h : heroes)
{
SectorMap sm(h);
auto sm = ai->getCachedSectorMap(h);
for (auto obj : objs) //double loop, performance risk?
{
auto t = sm.firstTileToGet(h, obj->visitablePos()); //we assume that no more than one tile on the way is guarded
auto t = sm->firstTileToGet(h, obj->visitablePos()); //we assume that no more than one tile on the way is guarded
if (ai->isTileNotReserved(h, t))
ret.push_back (sptr(Goals::ClearWayTo(obj->visitablePos(), h).setisAbstract(true)));
}
@ -692,8 +699,8 @@ TSubgoal RecruitHero::whatToDoToAchieve()
if(!t)
return sptr (Goals::BuildThis(BuildingID::TAVERN));
if(cb->getResourceAmount(Res::GOLD) < HERO_GOLD_COST)
return sptr (Goals::CollectRes(Res::GOLD, HERO_GOLD_COST));
if(cb->getResourceAmount(Res::GOLD) < GameConstants::HERO_GOLD_COST)
return sptr (Goals::CollectRes(Res::GOLD, GameConstants::HERO_GOLD_COST));
return iAmElementar();
}
@ -746,10 +753,10 @@ TGoalVec VisitTile::getAllPossibleSubgoals()
if (ai->canRecruitAnyHero())
ret.push_back (sptr(Goals::RecruitHero()));
}
if (ret.empty())
if(ret.empty())
{
auto obj = frontOrNull(cb->getVisitableObjs(tile));
if (obj && obj->ID == Obj::HERO && obj->tempOwner == ai->playerID) //our own hero stands on that tile
auto obj = vstd::frontOrNull(cb->getVisitableObjs(tile));
if(obj && obj->ID == Obj::HERO && obj->tempOwner == ai->playerID) //our own hero stands on that tile
{
if (hero.get(true) && hero->id == obj->id) //if it's assigned hero, visit tile. If it's different hero, we can't visit tile now
ret.push_back(sptr(Goals::VisitTile(tile).sethero(dynamic_cast<const CGHeroInstance *>(obj)).setisElementar(true)));
@ -766,7 +773,7 @@ TGoalVec VisitTile::getAllPossibleSubgoals()
TSubgoal DigAtTile::whatToDoToAchieve()
{
const CGObjectInstance *firstObj = frontOrNull(cb->getVisitableObjs(tile));
const CGObjectInstance *firstObj = vstd::frontOrNull(cb->getVisitableObjs(tile));
if(firstObj && firstObj->ID == Obj::HERO && firstObj->tempOwner == ai->playerID) //we have hero at dest
{
const CGHeroInstance *h = dynamic_cast<const CGHeroInstance *>(firstObj);
@ -862,7 +869,7 @@ TSubgoal GatherTroops::whatToDoToAchieve()
{
auto creatures = vstd::tryAt(t->town->creatures, creature->level - 1);
if(!creatures)
continue;
continue;
int upgradeNumber = vstd::find_pos(*creatures, creature->idNumber);
if(upgradeNumber < 0)
@ -957,13 +964,13 @@ TGoalVec Conquer::getAllPossibleSubgoals()
std::vector<const CGObjectInstance *> objs;
for (auto obj : ai->visitableObjs)
{
if (conquerable(obj))
if (conquerable(obj))
objs.push_back (obj);
}
for (auto h : cb->getHeroesInfo())
{
SectorMap sm(h);
auto sm = ai->getCachedSectorMap(h);
std::vector<const CGObjectInstance *> ourObjs(objs); //copy common objects
for (auto obj : ai->reservedHeroesMap[h]) //add objects reserved by this hero
@ -971,11 +978,30 @@ TGoalVec Conquer::getAllPossibleSubgoals()
if (conquerable(obj))
ourObjs.push_back(obj);
}
for (auto obj : ourObjs) //double loop, performance risk?
for (auto obj : ourObjs)
{
auto t = sm.firstTileToGet(h, obj->visitablePos()); //we assume that no more than one tile on the way is guarded
if (ai->isTileNotReserved(h, t))
ret.push_back (sptr(Goals::ClearWayTo(obj->visitablePos(), h).setisAbstract(true)));
int3 dest = obj->visitablePos();
auto t = sm->firstTileToGet(h, dest); //we assume that no more than one tile on the way is guarded
if (t.valid()) //we know any path at all
{
if (ai->isTileNotReserved(h, t)) //no other hero wants to conquer that tile
{
if (isSafeToVisit(h, dest))
{
if (dest != t) //there is something blocking our way
ret.push_back(sptr(Goals::ClearWayTo(dest, h).setisAbstract(true)));
else
{
if (obj->ID.num == Obj::HERO) //enemy hero may move to other position
ret.push_back(sptr(Goals::VisitHero(obj->id.getNum()).sethero(h).setisAbstract(true)));
else //just visit that tile
ret.push_back(sptr(Goals::VisitTile(dest).sethero(h).setisAbstract(true)));
}
}
else //we need to get army in order to conquer that place
ret.push_back(sptr(Goals::GatherArmy(evaluateDanger(dest, h) * SAFE_ATTACK_CONSTANT).sethero(h).setisAbstract(true)));
}
}
}
}
if (!objs.empty() && ai->canRecruitAnyHero()) //probably no point to recruit hero if we see no objects to capture
@ -1008,11 +1034,15 @@ TSubgoal GatherArmy::whatToDoToAchieve()
return fh->chooseSolution (getAllPossibleSubgoals()); //find dwelling. use current hero to prevent him from doing nothing.
}
static const BuildingID unitsSource[] = { BuildingID::DWELL_LVL_1, BuildingID::DWELL_LVL_2, BuildingID::DWELL_LVL_3,
BuildingID::DWELL_LVL_4, BuildingID::DWELL_LVL_5, BuildingID::DWELL_LVL_6, BuildingID::DWELL_LVL_7};
TGoalVec GatherArmy::getAllPossibleSubgoals()
{
//get all possible towns, heroes and dwellings we may use
TGoalVec ret;
//TODO: include evaluation of monsters gather in calculation
for (auto t : cb->getTownsInfo())
{
@ -1033,7 +1063,7 @@ TGoalVec GatherArmy::getAllPossibleSubgoals()
auto otherHeroes = cb->getHeroesInfo();
auto heroDummy = hero;
erase_if(otherHeroes, [heroDummy](const CGHeroInstance * h)
vstd::erase_if(otherHeroes, [heroDummy](const CGHeroInstance * h)
{
return (h == heroDummy.h || !ai->isAccessibleForHero(heroDummy->visitablePos(), h, true)
|| !ai->canGetArmy(heroDummy.h, h) || ai->getGoal(h)->goalType == Goals::GATHER_ARMY);
@ -1074,11 +1104,11 @@ TGoalVec GatherArmy::getAllPossibleSubgoals()
}
for(auto h : cb->getHeroesInfo())
{
SectorMap sm(h);
auto sm = ai->getCachedSectorMap(h);
for (auto obj : objs)
{ //find safe dwelling
auto pos = obj->visitablePos();
if (ai->isGoodForVisit(obj, h, sm))
if (ai->isGoodForVisit(obj, h, *sm))
ret.push_back (sptr (Goals::VisitTile(pos).sethero(h)));
}
}
@ -1098,7 +1128,7 @@ TGoalVec GatherArmy::getAllPossibleSubgoals()
//TSubgoal AbstractGoal::whatToDoToAchieve()
//{
// logAi->debugStream() << boost::format("Decomposing goal of type %s") % name();
// logAi->debug("Decomposing goal of type %s",name());
// return sptr (Goals::Explore());
//}

View File

@ -21,7 +21,7 @@ class FuzzyHelper;
namespace Goals
{
struct AbstractGoal;
class AbstractGoal;
class VisitTile;
typedef std::shared_ptr<Goals::AbstractGoal> TSubgoal;
typedef std::vector<TSubgoal> TGoalVec;
@ -86,8 +86,10 @@ public:
value = 0;
aid = -1;
resID = -1;
objid = -1;
tile = int3(-1, -1, -1);
town = nullptr;
bid = -1;
}
virtual ~AbstractGoal(){};
//FIXME: abstract goal should be abstract, but serializer fails to instantiate subgoals in such case
@ -107,7 +109,7 @@ public:
static TSubgoal tryRecruitHero();
///Visitor pattern
//TODO: make accept work for shared_ptr... somehow
//TODO: make accept work for std::shared_ptr... somehow
virtual void accept (VCAI * ai); //unhandled goal will report standard error
virtual float accept (FuzzyHelper * f);
@ -134,6 +136,7 @@ public:
isAbstract = false;
value = 0;
aid = -1;
objid = -1;
resID = -1;
tile = int3(-1, -1, -1);
town = nullptr;
@ -161,7 +164,7 @@ public:
TSubgoal iAmElementar()
{
setisElementar(true);
shared_ptr<AbstractGoal> ptr;
std::shared_ptr<AbstractGoal> ptr;
ptr.reset(clone());
return ptr;
}
@ -300,7 +303,7 @@ public:
VisitHero(int hid) : CGoal (Goals::VISIT_HERO){objid = hid; priority = 4;};
TGoalVec getAllPossibleSubgoals() override {return TGoalVec();};
TSubgoal whatToDoToAchieve() override;
//bool operator== (VisitHero &g) {return g.objid == objid;}
bool operator== (VisitHero &g) { return g.goalType == goalType && g.objid == objid; }
bool fulfillsMe (TSubgoal goal) override;
std::string completeMessage() const override;
};
@ -322,7 +325,7 @@ public:
VisitTile(int3 Tile) : CGoal (Goals::VISIT_TILE) {tile = Tile; priority = 5;};
TGoalVec getAllPossibleSubgoals() override;
TSubgoal whatToDoToAchieve() override;
//bool operator== (VisitTile &g) {return g.tile == tile;}
bool operator== (VisitTile &g) { return g.goalType == goalType && g.tile == tile; }
std::string completeMessage() const override;
};
class ClearWayTo : public CGoal<ClearWayTo>
@ -334,7 +337,7 @@ public:
ClearWayTo(int3 Tile, HeroPtr h) : CGoal (Goals::CLEAR_WAY_TO) {tile = Tile; hero = h; priority = 5;};
TGoalVec getAllPossibleSubgoals() override;
TSubgoal whatToDoToAchieve() override;
bool operator== (ClearWayTo &g) {return g.tile == tile;}
bool operator== (ClearWayTo &g) { return g.goalType == goalType && g.tile == tile; }
};
class DigAtTile : public CGoal<DigAtTile>
//elementar with hero on tile
@ -345,7 +348,7 @@ public:
DigAtTile(int3 Tile) : CGoal (Goals::DIG_AT_TILE) {tile = Tile; priority = 20;};
TGoalVec getAllPossibleSubgoals() override {return TGoalVec();};
TSubgoal whatToDoToAchieve() override;
bool operator== (DigAtTile &g) {return g.tile == tile;}
bool operator== (DigAtTile &g) { return g.goalType == goalType && g.tile == tile; }
};
class CIssueCommand : public CGoal<CIssueCommand>

View File

@ -6,23 +6,25 @@
<Option pch_mode="2" />
<Option compiler="gcc" />
<Build>
<Target title="Debug-win32-SDL2">
<Target title="Debug-win32">
<Option platforms="Windows;" />
<Option output="../VCAI" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Debug/" />
<Option object_output="obj/Debug/x86" />
<Option type="3" />
<Option compiler="gcc" />
<Compiler>
<Add option="-Og" />
<Add option="-g" />
</Compiler>
<Linker>
<Add directory="../FuzzyLite/bin/Debug" />
<Add directory="../" />
<Add directory="$(#boost.lib32)" />
</Linker>
</Target>
<Target title="Release-win32-SDL2">
<Target title="Release-win32">
<Option platforms="Windows;" />
<Option output="../VCAI" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Release/" />
<Option object_output="obj/Release/x86" />
<Option type="3" />
<Option compiler="gcc" />
<Compiler>
@ -31,35 +33,23 @@
</Compiler>
<Linker>
<Add option="-s" />
<Add directory="../FuzzyLite/bin/Release" />
<Add directory="../" />
<Add directory="$(#boost.lib32)" />
</Linker>
</Target>
<Target title="Debug-win32-SDL1">
<Target title="Debug-win64">
<Option platforms="Windows;" />
<Option output="../VCAI" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Debug/" />
<Option object_output="obj/Debug/x64" />
<Option type="3" />
<Option compiler="gcc" />
<Option compiler="gnu_gcc_compiler_x64" />
<Compiler>
<Add option="-Og" />
<Add option="-g" />
</Compiler>
<Linker>
<Add directory="../FuzzyLite/bin/Debug" />
</Linker>
</Target>
<Target title="Release-win32-SDL1">
<Option platforms="Windows;" />
<Option output="../VCAI" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Release/" />
<Option type="3" />
<Option compiler="gcc" />
<Compiler>
<Add option="-fomit-frame-pointer" />
<Add option="-O3" />
</Compiler>
<Linker>
<Add option="-s" />
<Add directory="../FuzzyLite/bin/Release" />
<Add directory="../" />
<Add directory="$(#boost.lib64)" />
</Linker>
</Target>
</Build>
@ -67,6 +57,7 @@
<Add option="-pedantic" />
<Add option="-Wextra" />
<Add option="-Wall" />
<Add option="-std=gnu++11" />
<Add option="-fexceptions" />
<Add option="-Wpointer-arith" />
<Add option="-Wno-switch" />
@ -86,7 +77,6 @@
<Add option="-lboost_thread$(#boost.libsuffix)" />
<Add option="-lboost_chrono$(#boost.libsuffix)" />
<Add option="-lVCMI_lib" />
<Add directory="$(#boost.lib32)" />
<Add directory="../.." />
</Linker>
<Unit filename="AIUtility.cpp" />
@ -96,6 +86,7 @@
<Unit filename="Goals.cpp" />
<Unit filename="Goals.h" />
<Unit filename="StdInc.h">
<Option compile="1" />
<Option weight="0" />
</Unit>
<Unit filename="VCAI.cpp" />

File diff suppressed because it is too large Load Diff

View File

@ -12,11 +12,8 @@
#include "../../lib/CBuildingHandler.h"
#include "../../lib/CCreatureHandler.h"
#include "../../lib/CTownHandler.h"
#include "../../lib/mapObjects/MiscObjects.h"
#include "../../lib/spells/CSpellHandler.h"
#include "../../lib/Connection.h"
#include "../../lib/CGameState.h"
#include "../../lib/mapping/CMap.h"
#include "../../lib/NetPacks.h"
#include "../../lib/CondSh.h"
struct QuestInfo;
@ -81,7 +78,7 @@ struct SectorMap
int id;
std::vector<int3> tiles;
std::vector<int3> embarkmentPoints; //tiles of other sectors onto which we can (dis)embark
std::vector<const CGObjectInstance *> subterraneanGates;
std::vector<const CGObjectInstance *> visitableObjs;
bool water; //all tiles of sector are land or water
Sector()
{
@ -95,6 +92,7 @@ struct SectorMap
//std::vector<std::vector<std::vector<unsigned char>>> pathfinderSector;
std::map<int, Sector> infoOnSectors;
std::shared_ptr<boost::multi_array<TerrainTile*, 3>> visibleTiles;
SectorMap();
SectorMap(HeroPtr h);
@ -103,7 +101,11 @@ struct SectorMap
void exploreNewSector(crint3 pos, int num, CCallback * cbp);
void write(crstring fname);
bool markIfBlocked(ui8 &sec, crint3 pos, const TerrainTile *t);
bool markIfBlocked(ui8 &sec, crint3 pos);
unsigned char &retreiveTile(crint3 pos);
TerrainTile* getTile(crint3 pos) const;
std::vector<const CGObjectInstance *> getNearbyObjs(HeroPtr h, bool sectorsAround);
void makeParentBFS(crint3 source);
@ -111,20 +113,6 @@ struct SectorMap
int3 findFirstVisitableTile(HeroPtr h, crint3 dst);
};
//Set of buildings for different goals. Does not include any prerequisites.
const BuildingID essential[] = {BuildingID::TAVERN, BuildingID::TOWN_HALL};
const BuildingID goldSource[] = {BuildingID::TOWN_HALL, BuildingID::CITY_HALL, BuildingID::CAPITOL};
const BuildingID unitsSource[] = { BuildingID::DWELL_LVL_1, BuildingID::DWELL_LVL_2, BuildingID::DWELL_LVL_3,
BuildingID::DWELL_LVL_4, BuildingID::DWELL_LVL_5, BuildingID::DWELL_LVL_6, BuildingID::DWELL_LVL_7};
const BuildingID unitsUpgrade[] = { BuildingID::DWELL_LVL_1_UP, BuildingID::DWELL_LVL_2_UP, BuildingID::DWELL_LVL_3_UP,
BuildingID::DWELL_LVL_4_UP, BuildingID::DWELL_LVL_5_UP, BuildingID::DWELL_LVL_6_UP, BuildingID::DWELL_LVL_7_UP};
const BuildingID unitGrowth[] = { BuildingID::FORT, BuildingID::CITADEL, BuildingID::CASTLE, BuildingID::HORDE_1,
BuildingID::HORDE_1_UPGR, BuildingID::HORDE_2, BuildingID::HORDE_2_UPGR};
const BuildingID spells[] = {BuildingID::MAGES_GUILD_1, BuildingID::MAGES_GUILD_2, BuildingID::MAGES_GUILD_3,
BuildingID::MAGES_GUILD_4, BuildingID::MAGES_GUILD_5};
const BuildingID extra[] = {BuildingID::RESOURCE_SILO, BuildingID::SPECIAL_1, BuildingID::SPECIAL_2, BuildingID::SPECIAL_3,
BuildingID::SPECIAL_4, BuildingID::SHIPYARD}; // all remaining buildings
class VCAI : public CAdventureAI
{
public:
@ -141,9 +129,10 @@ public:
friend class FuzzyHelper;
std::map<TeleportChannelID, shared_ptr<TeleportChannel> > knownTeleportChannels;
std::map<TeleportChannelID, std::shared_ptr<TeleportChannel> > knownTeleportChannels;
std::map<const CGObjectInstance *, const CGObjectInstance *> knownSubterraneanGates;
ObjectInstanceID destinationTeleport;
int3 destinationTeleportPos;
std::vector<ObjectInstanceID> teleportChannelProbingList; //list of teleport channel exits that not visible and need to be (re-)explored
//std::vector<const CGObjectInstance *> visitedThisWeek; //only OPWs
std::map<HeroPtr, std::set<const CGTownInstance *> > townVisitsThisWeek;
@ -157,17 +146,19 @@ public:
std::set<const CGObjectInstance *> alreadyVisited;
std::set<const CGObjectInstance *> reservedObjs; //to be visited by specific hero
std::map <HeroPtr, std::shared_ptr<SectorMap>> cachedSectorMaps; //TODO: serialize? not necessary
TResources saving;
AIStatus status;
std::string battlename;
shared_ptr<CCallback> myCb;
std::shared_ptr<CCallback> myCb;
unique_ptr<boost::thread> makingTurn;
std::unique_ptr<boost::thread> makingTurn;
VCAI(void);
~VCAI(void);
virtual ~VCAI(void);
//TODO: use only smart pointers?
void tryRealize(Goals::Explore & g);
@ -189,16 +180,16 @@ public:
virtual std::string getBattleAIName() const override;
virtual void init(shared_ptr<CCallback> CB) override;
virtual void init(std::shared_ptr<CCallback> CB) override;
virtual void yourTurn() override;
virtual void heroGotLevel(const CGHeroInstance *hero, PrimarySkill::PrimarySkill pskill, std::vector<SecondarySkill> &skills, QueryID queryID) override; //pskill is gained primary skill, interface has to choose one of given skills and call callback with selection id
virtual void commanderGotLevel (const CCommanderInstance * commander, std::vector<ui32> skills, QueryID queryID) override; //TODO
virtual void showBlockingDialog(const std::string &text, const std::vector<Component> &components, QueryID askID, const int soundID, bool selection, bool cancel) override; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID.
virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, QueryID queryID) override; //all stacks operations between these objects become allowed, interface has to call onEnd when done
virtual void showTeleportDialog(TeleportChannelID channel, std::vector<ObjectInstanceID> exits, bool impassable, QueryID askID) override;
virtual void saveGame(COSer & h, const int version) override; //saving
virtual void loadGame(CISer & h, const int version) override; //loading
virtual void showTeleportDialog(TeleportChannelID channel, TTeleportExitsList exits, bool impassable, QueryID askID) override;
virtual void saveGame(BinarySerializer & h, const int version) override; //saving
virtual void loadGame(BinaryDeserializer & h, const int version) override; //loading
virtual void finish() override;
virtual void availableCreaturesChanged(const CGDwelling *town) override;
@ -268,7 +259,6 @@ public:
void recruitHero(const CGTownInstance * t, bool throwing = false);
bool isGoodForVisit(const CGObjectInstance *obj, HeroPtr h, SectorMap &sm);
std::vector<const CGObjectInstance *> getPossibleDestinations(HeroPtr h);
void buildStructure(const CGTownInstance * t);
//void recruitCreatures(const CGTownInstance * t);
void recruitCreatures(const CGDwelling * d, const CArmedInstance * recruiter);
@ -292,7 +282,7 @@ public:
void markHeroUnableToExplore (HeroPtr h);
void markHeroAbleToExplore (HeroPtr h);
bool isAbleToExplore (HeroPtr h);
void clearHeroesUnableToExplore();
void clearPathsInfo();
void validateObject(const CGObjectInstance *obj); //checks if object is still visible and if not, removes references to it
void validateObject(ObjectIdRef obj); //checks if object is still visible and if not, removes references to it
@ -307,6 +297,8 @@ public:
const CGObjectInstance *getUnvisitedObj(const std::function<bool(const CGObjectInstance *)> &predicate);
bool isAccessibleForHero(const int3 & pos, HeroPtr h, bool includeAllies = false) const;
//optimization - use one SM for every hero call
std::shared_ptr<SectorMap> getCachedSectorMap(HeroPtr h);
const CGTownInstance *findTownWithTavern() const;
bool canRecruitAnyHero(const CGTownInstance * t = NULL) const;

View File

@ -23,7 +23,7 @@ extern "C" DLL_EXPORT void GetAiName(char* name)
strcpy_s(name, strlen(g_cszAiName) + 1, g_cszAiName);
}
extern "C" DLL_EXPORT void GetNewAI(shared_ptr<CGlobalAI> &out)
extern "C" DLL_EXPORT void GetNewAI(std::shared_ptr<CGlobalAI> &out)
{
out = make_shared<VCAI>();
out = std::make_shared<VCAI>();
}

View File

@ -5,7 +5,7 @@ Michał Urbańczyk aka Tow, <impono@gmail.com>
maintenance, reverse engineering, general support.
Mateusz B. aka Tow dragon, <matcio1@gmail.com>
* general suport, battle support, support for many Heroes 3 config files, reverse engineering, ERM/VERM parser and interpreter
* general support, battle support, support for many Heroes 3 config files, reverse engineering, ERM/VERM parser and interpreter
Stefan Pavlov aka Ste, <mailste@gmail.com>
* minor fixes in pregame
@ -52,5 +52,8 @@ Alexey aka Macron1Robot, <>
Alexander Shishkin aka alexvins,
* MinGW platform support, modding related programming
Arseniy Shestakov aka SXX,
Arseniy Shestakov aka SXX, <me@arseniyshestakov.com>
* pathfinding improvements, programming
Vadim Markovtsev, <gmarkhor@gmail.com>
* resolving problems with macOS, bug fixes

View File

@ -12,18 +12,12 @@
#include "lib/mapObjects/CObjectClassesHandler.h"
#include "lib/CGeneralTextHandler.h"
#include "lib/CHeroHandler.h"
#include "lib/Connection.h"
#include "lib/NetPacks.h"
#include "client/mapHandler.h"
#include "lib/spells/CSpellHandler.h"
#include "lib/CArtHandler.h"
#include "lib/GameConstants.h"
#ifdef min
#undef min
#endif
#ifdef max
#undef max
#endif
#include "lib/CPlayerState.h"
#include "lib/UnlockGuard.h"
/*
@ -60,7 +54,7 @@ int CCallback::selectionMade(int selection, QueryID queryID)
ASSERT_IF_CALLED_WITH_PLAYER
if(queryID == QueryID(-1))
{
logGlobal->errorStream() << "Cannot answer the query -1!";
logGlobal->errorStream() << "Cannot answer the query -1!";
return false;
}
@ -71,7 +65,8 @@ int CCallback::selectionMade(int selection, QueryID queryID)
void CCallback::recruitCreatures(const CGDwelling *obj, const CArmedInstance * dst, CreatureID ID, ui32 amount, si32 level/*=-1*/)
{
if(player!=obj->tempOwner && obj->ID != Obj::WAR_MACHINE_FACTORY)
// TODO exception for neutral dwellings shouldn't be hardcoded
if(player != obj->tempOwner && obj->ID != Obj::WAR_MACHINE_FACTORY && obj->ID != Obj::REFUGEE_CAMP)
return;
RecruitCreatures pack(obj->id, dst->id, ID, amount, level);
@ -80,7 +75,7 @@ void CCallback::recruitCreatures(const CGDwelling *obj, const CArmedInstance * d
bool CCallback::dismissCreature(const CArmedInstance *obj, SlotID stackPos)
{
if(((player>=0) && obj->tempOwner != player) || (obj->stacksCount()<2 && obj->needsLastStack()))
if((player && obj->tempOwner != player) || (obj->stacksCount()<2 && obj->needsLastStack()))
return false;
DisbandCreature pack(stackPos,obj->id);
@ -97,7 +92,7 @@ bool CCallback::upgradeCreature(const CArmedInstance *obj, SlotID stackPos, Crea
void CCallback::endTurn()
{
logGlobal->traceStream() << "Player " << *player << " ended his turn.";
logGlobal->traceStream() << "Player " << *player << " ended his turn.";
EndTurn pack;
sendRequest(&pack); //report that we ended turn
}
@ -189,7 +184,7 @@ int CBattleCallback::sendRequest(const CPack *request)
int requestID = cl->sendRequest(request, *player);
if(waitTillRealize)
{
logGlobal->traceStream() << boost::format("We'll wait till request %d is answered.\n") % requestID;
logGlobal->traceStream() << boost::format("We'll wait till request %d is answered.\n") % requestID;
auto gsUnlocker = vstd::makeUnlockSharedGuardIf(getGsMutex(), unlockGsWhenWaiting);
cl->waitingRequest.waitWhileContains(requestID);
}
@ -230,7 +225,6 @@ void CCallback::trade(const CGObjectInstance *market, EMarketMode::EMarketMode m
void CCallback::setFormation(const CGHeroInstance * hero, bool tight)
{
const_cast<CGHeroInstance*>(hero)-> formation = tight;
SetFormation pack(hero->id,tight);
sendRequest(&pack);
}
@ -290,11 +284,6 @@ bool CCallback::canMoveBetween(const int3 &a, const int3 &b)
return gs->checkForVisitableDir(a, b) && gs->checkForVisitableDir(b, a);
}
int CCallback::getMovementCost(const CGHeroInstance * hero, int3 dest)
{
return gs->getMovementCost(hero, hero->visitablePos(), dest, hero->hasBonusOfType (Bonus::FLYING_MOVEMENT), hero->movement);
}
const CPathsInfo * CCallback::getPathsInfo(const CGHeroInstance *h)
{
return cl->getPathsInfo(h);
@ -331,6 +320,8 @@ void CCallback::castSpell(const CGHeroInstance *hero, SpellID spellID, const int
void CCallback::unregisterAllInterfaces()
{
for (auto& pi : cl->playerint)
pi.second->finish();
cl->playerint.clear();
cl->battleints.clear();
}
@ -343,22 +334,22 @@ int CCallback::mergeOrSwapStacks(const CArmedInstance *s1, const CArmedInstance
return swapCreatures(s1, s2, p1, p2);
}
void CCallback::registerGameInterface(shared_ptr<IGameEventsReceiver> gameEvents)
void CCallback::registerGameInterface(std::shared_ptr<IGameEventsReceiver> gameEvents)
{
cl->additionalPlayerInts[*player].push_back(gameEvents);
}
void CCallback::registerBattleInterface(shared_ptr<IBattleEventsReceiver> battleEvents)
void CCallback::registerBattleInterface(std::shared_ptr<IBattleEventsReceiver> battleEvents)
{
cl->additionalBattleInts[*player].push_back(battleEvents);
}
void CCallback::unregisterGameInterface(shared_ptr<IGameEventsReceiver> gameEvents)
void CCallback::unregisterGameInterface(std::shared_ptr<IGameEventsReceiver> gameEvents)
{
cl->additionalPlayerInts[*player] -= gameEvents;
}
void CCallback::unregisterBattleInterface(shared_ptr<IBattleEventsReceiver> battleEvents)
void CCallback::unregisterBattleInterface(std::shared_ptr<IBattleEventsReceiver> battleEvents)
{
cl->additionalBattleInts[*player] -= battleEvents;
}

View File

@ -104,49 +104,48 @@ public:
//client-specific functionalities (pathfinding)
virtual bool canMoveBetween(const int3 &a, const int3 &b);
virtual int getMovementCost(const CGHeroInstance * hero, int3 dest);
virtual int3 getGuardingCreaturePosition(int3 tile);
virtual const CPathsInfo * getPathsInfo(const CGHeroInstance *h);
virtual void calculatePaths(const CGHeroInstance *hero, CPathsInfo &out);
//Set of metrhods that allows adding more interfaces for this player that'll receive game event call-ins.
void registerGameInterface(shared_ptr<IGameEventsReceiver> gameEvents);
void registerBattleInterface(shared_ptr<IBattleEventsReceiver> battleEvents);
void unregisterGameInterface(shared_ptr<IGameEventsReceiver> gameEvents);
void unregisterBattleInterface(shared_ptr<IBattleEventsReceiver> battleEvents);
void registerGameInterface(std::shared_ptr<IGameEventsReceiver> gameEvents);
void registerBattleInterface(std::shared_ptr<IBattleEventsReceiver> battleEvents);
void unregisterGameInterface(std::shared_ptr<IGameEventsReceiver> gameEvents);
void unregisterBattleInterface(std::shared_ptr<IBattleEventsReceiver> battleEvents);
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

@ -13,15 +13,20 @@ endif()
# VCMI version
set(VCMI_VERSION_MAJOR 0)
set(VCMI_VERSION_MINOR 98)
set(VCMI_VERSION_MINOR 99)
set(VCMI_VERSION_PATCH 0)
option(ENABLE_ERM "Enable compilation of ERM scripting module" OFF)
option(ENABLE_EDITOR "Enable compilation of map editor" OFF)
option(ENABLE_LAUNCHER "Enable compilation of launcher" ON)
option(ENABLE_TEST "Enable compilation of unit tests" OFF)
option(ENABLE_TEST "Enable compilation of unit tests" ON)
option(ENABLE_PCH "Enable compilation using precompiled headers" ON)
option(ENABLE_SDL2 "Use SDL2 for compilation instead of SDL 1.2" ON)
############################################
# Documentation section #
############################################
include(UseDoxygen OPTIONAL)
############################################
# Building section #
@ -59,7 +64,7 @@ endif()
if (WIN32)
add_definitions(-DBOOST_THREAD_USE_LIB)
add_definitions(-D_WIN32_WINNT=0x0501)
set(SYSTEM_LIBS ${SYSTEM_LIBS} ole32 oleaut32 ws2_32 mswsock)
set(SYSTEM_LIBS ${SYSTEM_LIBS} ole32 oleaut32 ws2_32 mswsock dbghelp)
#delete lib prefix for dlls (libvcmi -> vcmi)
set(CMAKE_SHARED_LIBRARY_PREFIX "")
@ -110,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)
@ -118,26 +123,20 @@ if (MINIZIP_FOUND)
add_definitions(-DUSE_SYSTEM_MINIZIP)
endif()
if (ENABLE_SDL2)
find_package(SDL2 REQUIRED)
find_package(SDL2_image REQUIRED)
find_package(SDL2_mixer REQUIRED)
find_package(SDL2_ttf REQUIRED)
find_package(SDL2 REQUIRED)
find_package(SDL2_image REQUIRED)
find_package(SDL2_mixer REQUIRED)
find_package(SDL2_ttf REQUIRED)
set(SDL_INCLUDE_DIR "${SDL2_INCLUDE_DIR}")
set(SDLTTF_INCLUDE_DIR "${SDL2_TTF_INCLUDE_DIR}")
set(SDLIMAGE_INCLUDE_DIR "${SDL2_IMAGE_INCLUDE_DIR}")
set(SDLMIXER_INCLUDE_DIR "${SDL2_MIXER_INCLUDE_DIR}")
set(SDL_LIBRARY "${SDL2_LIBRARY}")
set(SDLTTF_LIBRARY "${SDL2_TTF_LIBRARY}")
set(SDLIMAGE_LIBRARY "${SDL2_IMAGE_LIBRARY}")
set(SDLMIXER_LIBRARY "${SDL2_MIXER_LIBRARY}")
set(SDL_INCLUDE_DIR "${SDL2_INCLUDE_DIR}")
set(SDLTTF_INCLUDE_DIR "${SDL2_TTF_INCLUDE_DIR}")
set(SDLIMAGE_INCLUDE_DIR "${SDL2_IMAGE_INCLUDE_DIR}")
set(SDLMIXER_INCLUDE_DIR "${SDL2_MIXER_INCLUDE_DIR}")
set(SDL_LIBRARY "${SDL2_LIBRARY}")
set(SDLTTF_LIBRARY "${SDL2_TTF_LIBRARY}")
set(SDLIMAGE_LIBRARY "${SDL2_IMAGE_LIBRARY}")
set(SDLMIXER_LIBRARY "${SDL2_MIXER_LIBRARY}")
else()
find_package(SDL REQUIRED)
find_package(SDL_image REQUIRED)
find_package(SDL_mixer REQUIRED)
find_package(SDL_ttf REQUIRED)
endif()
include(cotire)
if (ENABLE_EDITOR OR ENABLE_LAUNCHER)
@ -151,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
@ -236,7 +235,7 @@ endif()
# Installation section #
#######################################
# For apple this files will be already inside vcmiclient bundle
# For apple these files will be already inside vcmiclient bundle
if (NOT APPLE)
# copy whole directory but .svn control files
install(DIRECTORY config DESTINATION ${DATA_DIR} PATTERN ".svn" EXCLUDE)
@ -343,3 +342,6 @@ endif()
INCLUDE(CPack)
include(GetGitRevisionDescription)
get_git_head_revision(GIT_REFSPEC GIT_SHA1)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/Version.cpp.in" "${CMAKE_BINARY_DIR}/Version.cpp" @ONLY)

View File

@ -1,14 +1,39 @@
0.98 -> 0.next
0.98 -> 0.99
GENERAL:
* New Bonus NO_TERRAIN_PENALTY
* Nomads will remove Sand movement penalty from army
* Flying and water walking is now supported in pathfinder
* New artifacts supported
- Angel Wings
- Boots of Levitation
* Implemented rumors in tavern window
* New cheat codes:
- vcmiglaurung - gives 5000 crystal dragons into each slot
- vcmiungoliant - conceal fog of war for current player
* New console commands:
- gosolo - AI take control over human players and vice versa
- controlai - give control of one or all AIs to player
- set hideSystemMessages on/off - supress server messages in chat
BATTLES:
* Drawbridge mechanics implemented (animation still missing)
* Merging of town and visiting hero armies on siege implemented
* Hero info tooltip for skills and mana implemented
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
* AI heroes with patrol enabled won't leave patrol area anymore
RANDOM MAP GENERATOR:
* Changed fractalization algorithm so it can create cycles
* Zones will not have straight paths anymore, they are totally random
* Generated zones will have different size depending on template setting
* Added Thieves Guild random object (1 per zone)
* Added Seer Huts with quests that match OH3
* RMG will guarantee at least 100 pairs of Monoliths are available even if there are not enough different defs
0.97 -> 0.98
GENERAL:

View File

@ -55,13 +55,13 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
# define VCMI_UNIX
# define VCMI_XDG
# ifdef __ANDROID__
# define VCMI_ANDROID
# define VCMI_ANDROID
# endif
#elif defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
# 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
@ -93,8 +93,25 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
#ifdef VCMI_WINDOWS
# define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers - delete this line if something is missing.
# define NOMINMAX // Exclude min/max macros from <Windows.h>. Use std::[min/max] from <algorithm> instead.
# define _NO_W32_PSEUDO_MODIFIERS // Exclude more macros for compiling with MinGW on Linux.
#endif
/* ---------------------------------------------------------------------------- */
/* A macro to force inlining some of our functions */
/* ---------------------------------------------------------------------------- */
// Compiler (at least MSVC) is not so smart here-> without that displaying is MUCH slower
#ifdef _MSC_VER
# define STRONG_INLINE __forceinline
#elif __GNUC__
# define STRONG_INLINE inline __attribute__((always_inline))
#else
# define STRONG_INLINE inline
#endif
#define TO_STRING_HELPER(x) #x
#define TO_STRING(x) TO_STRING_HELPER(x)
#define LINE_IN_FILE __FILE__ ":" TO_STRING(__LINE__)
#define _USE_MATH_DEFINES
#include <cstdio>
@ -133,6 +150,10 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
#define BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE 1
#define BOOST_BIND_NO_PLACEHOLDERS
#if defined(_MSC_VER) && (_MSC_VER == 1900)
#define BOOST_NO_CXX11_VARIADIC_TEMPLATES //Variadic templates are buggy in VS2015, so turn this off to avoid compile errors
#endif
#include <boost/algorithm/string.hpp>
#include <boost/cstdint.hpp>
#include <boost/current_function.hpp>
@ -150,6 +171,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>
@ -157,6 +179,7 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
#include <boost/thread.hpp>
#include <boost/variant.hpp>
#include <boost/math/special_functions/round.hpp>
#include <boost/multi_array.hpp>
#ifndef M_PI
# define M_PI 3.14159265358979323846
@ -165,9 +188,6 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
/* ---------------------------------------------------------------------------- */
/* Usings */
/* ---------------------------------------------------------------------------- */
using std::shared_ptr;
using std::unique_ptr;
using std::make_shared;
using namespace std::placeholders;
namespace range = boost::range;
@ -206,7 +226,6 @@ typedef boost::lock_guard<boost::recursive_mutex> TLockGuardRec;
# define DLL_IMPORT __attribute__ ((visibility("default")))
# define DLL_EXPORT __attribute__ ((visibility("default")))
# define ELF_VISIBILITY __attribute__ ((visibility("default")))
# define ELF_VISIBILITY __attribute__ ((visibility("default")))
# endif
#endif
@ -230,7 +249,8 @@ template<typename T, size_t N> char (&_ArrayCountObj(const T (&)[N]))[N];
/* ---------------------------------------------------------------------------- */
/* VCMI standard library */
/* ---------------------------------------------------------------------------- */
#include "lib/logging/CLogger.h"
#include <vstd/CLoggerBase.h>
#include "lib/logging/CLogger.h" //todo: remove
void inline handleException()
{
@ -240,15 +260,15 @@ void inline handleException()
}
catch(const std::exception & ex)
{
logGlobal->errorStream() << ex.what();
logGlobal->error(ex.what());
}
catch(const std::string & ex)
{
logGlobal->errorStream() << ex;
logGlobal->error(ex);
}
catch(...)
{
logGlobal->errorStream() << "Sorry, caught unknown exception type. No more info available.";
logGlobal->error("Sorry, caught unknown exception type. No more info available.");
}
}
@ -273,7 +293,7 @@ std::ostream & operator<<(std::ostream & out, const std::vector<T> & container)
namespace vstd
{
// combine hashes. Present in boost but not in std
template <class T>
inline void hash_combine(std::size_t& seed, const T& v)
@ -281,7 +301,7 @@ namespace vstd
std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
}
//returns true if container c contains item i
template <typename Container, typename Item>
bool contains(const Container & c, const Item &i)
@ -493,7 +513,7 @@ namespace vstd
void erase_if(std::set<Elem> &setContainer, Predicate pred)
{
auto itr = setContainer.begin();
auto endItr = setContainer.end();
auto endItr = setContainer.end();
while(itr != endItr)
{
auto tmpItr = itr++;
@ -507,7 +527,7 @@ namespace vstd
void erase_if(std::map<Key, Val> &container, Predicate pred)
{
auto itr = container.begin();
auto endItr = container.end();
auto endItr = container.end();
while(itr != endItr)
{
auto tmpItr = itr++;
@ -542,7 +562,7 @@ namespace vstd
return vf(lhs) < vf(rhs);
});
}
//Returns iterator to the element for which the value of ValueFunction is maximal
template<class ForwardRange, class ValueFunction>
auto maxElementByFun(const ForwardRange& rng, ValueFunction vf) -> decltype(std::begin(rng))
@ -615,7 +635,7 @@ namespace vstd
{
if(index < r.size())
return r[index];
return defaultValue;
}
@ -656,12 +676,12 @@ namespace vstd
boost::sort(vec);
vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
}
template <typename T>
void concatenate(std::vector<T> &dest, const std::vector<T> &src)
{
dest.reserve(dest.size() + src.size());
dest.insert(dest.end(), src.begin(), src.end());
dest.insert(dest.end(), src.begin(), src.end());
}
template <typename T>

View File

@ -0,0 +1,7 @@
{
"basepath" : "mapFormatIcons/",
"images" :
[
{ "group" : 1, "frame" : 0, "file" : "vcmi1.png"}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -20,7 +20,7 @@ To compile, the following packages (and their development counterparts) are need
* zlib and zlib-devel
* (optional) Qt 5, widget and network modules
* the ffmpeg libraries (libavformat and libswscale). Their name could be libavformat-devel and libswscale-devel, or ffmpeg-libs-devel or similar names.
* boost c++ libraries v1.48+ (www.boost.org):
* boost c++ libraries v1.50+ (www.boost.org):
- program-options
- filesystem
- system
@ -28,11 +28,17 @@ To compile, the following packages (and their development counterparts) are need
- locale
On Debian-based systems (e.g. Ubuntu) run:
sudo apt-get install cmake g++ libsdl1.2debian libsdl-image1.2-dev libsdl-ttf2.0-dev libsdl-mixer1.2-dev zlib1g-dev libavformat-dev libswscale-dev libboost-dev libboost-filesystem-dev libboost-system-dev libboost-thread-dev libboost-program-options-dev libboost-locale-dev qtbase5-dev
sudo apt-get install cmake g++ libsdl2-dev libsdl2-image-dev libsdl2-ttf-dev libsdl2-mixer-dev zlib1g-dev libavformat-dev libswscale-dev libboost-dev libboost-filesystem-dev libboost-system-dev libboost-thread-dev libboost-program-options-dev libboost-locale-dev libboost-test-dev qtbase5-dev
On RPM-based distributions (e.g. Fedora) run:
sudo yum install cmake gcc-c++ SDL2-devel SDL2_image-devel SDL2_ttf-devel SDL2_mixer-devel boost boost-devel boost-filesystem boost-system boost-thread boost-program-options boost-locale zlib-devel ffmpeg-devel ffmpeg-libs qt5-qtbase-devel
On Arch-based distributions, there is a development package available for VCMI on the AUR. It can be found at:
https://aur.archlinux.org/packages/vcmi-git/
Information about building packages from the Arch User Repository (AUR) can be
found at the Arch wiki.
II. Getting the sources
VCMI is still in development. We recommend the following initial directory structure:
@ -93,3 +99,14 @@ Go to /LIB_PATH/vcmi/AI, and type:
Go to /DATA_PATH/vcmi, and type:
ln -s .../trunk/source/config
ln -s .../trunk/source/Mods
IV. Compiling documentation
To compile using Doxygen, the UseDoxygen CMake module must be installed. It can
be fetched from: http://tobias.rautenkranz.ch/cmake/doxygen/
Once UseDoxygen is installed, run:
cmake .
make doc
The built documentation will be available from ./doc

View File

@ -1,3 +1,4 @@
[![Build Status](https://travis-ci.org/vcmi/vcmi.svg?branch=develop)](https://travis-ci.org/vcmi/vcmi)
# VCMI Project
VCMI is work-in-progress attempt to recreate engine for Heroes III, giving it new and extended possibilities. To use VCMI you need to own original data files.
@ -18,4 +19,4 @@ For building from source see project wiki at http://wiki.vcmi.eu/
VCMI Project source code is licensed under GPL version 2 or later.
VCMI Project assets are licensed under CC-BY-SA 4.0. Assets sources and information about contributors are available under following link: [https://github.com/vcmi/vcmi-assets]
Copyright (C) 2007-2015 VCMI Team (check AUTHORS file for the contributors list)
Copyright (C) 2007-2016 VCMI Team (check AUTHORS file for the contributors list)

View File

@ -7,7 +7,7 @@
<PropertyGroup>
<_PropertySheetDisplayName>VCMI_global</_PropertySheetDisplayName>
<LibraryPath>$(SolutionDir)..\libs\$(PlatformShortName);$(VCMI_Out);$(LibraryPath)</LibraryPath>
<IncludePath>$(SolutionDir)..\include;$(IncludePath)</IncludePath>
<IncludePath>$(SolutionDir)..\include;$(SolutionDir)include;$(IncludePath)</IncludePath>
<OutDir>$(VCMI_Out)\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup>

6
Version.cpp.in Normal file
View File

@ -0,0 +1,6 @@
#include "Version.h"
namespace GameConstants
{
const char GIT_SHA1[] = "@GIT_SHA1@";
}

4
Version.h Normal file
View File

@ -0,0 +1,4 @@
namespace GameConstants
{
extern const char GIT_SHA1[];
}

View File

@ -1,11 +1,9 @@
#include "StdInc.h"
#include "../lib/filesystem/Filesystem.h"
#include "../lib/filesystem/CFileInfo.h"
#include "SDL.h"
#include "SDL_image.h"
#include "CBitmapHandler.h"
#include "CDefHandler.h"
#include "gui/SDL_Extensions.h"
#include "../lib/vcmi_endian.h"
@ -19,6 +17,14 @@
*
*/
namespace BitmapHandler
{
SDL_Surface * loadH3PCX(ui8 * data, size_t size);
SDL_Surface * loadBitmapFromDir(std::string path, std::string fname, bool setKey=true);
}
bool isPCX(const ui8 *header)//check whether file can be PCX according to header
{
int fSize = read_le_u32(header + 0);
@ -70,7 +76,7 @@ SDL_Surface * BitmapHandler::loadH3PCX(ui8 * pcx, size_t size)
tp.r = pcx[it++];
tp.g = pcx[it++];
tp.b = pcx[it++];
CSDL_Ext::colorSetAlpha(tp,SDL_ALPHA_OPAQUE);
tp.a = SDL_ALPHA_OPAQUE;
ret->format->palette->colors[i] = tp;
}
}
@ -102,7 +108,7 @@ SDL_Surface * BitmapHandler::loadBitmapFromDir(std::string path, std::string fna
{
if(!fname.size())
{
logGlobal->warnStream() << "Call to loadBitmap with void fname!";
logGlobal->warnStream() << "Call to loadBitmap with void fname!";
return nullptr;
}
if (!CResourceHandler::get()->existsResource(ResourceID(path + fname, EResType::IMAGE)))
@ -142,13 +148,13 @@ SDL_Surface * BitmapHandler::loadBitmapFromDir(std::string path, std::string fna
{
//set correct value for alpha\unused channel
for (int i=0; i < ret->format->palette->ncolors; i++)
CSDL_Ext::colorSetAlpha(ret->format->palette->colors[i],SDL_ALPHA_OPAQUE);
ret->format->palette->colors[i].a = SDL_ALPHA_OPAQUE;
}
}
else
{
logGlobal->errorStream()<<"Failed to open "<<fname<<" via SDL_Image";
logGlobal->errorStream()<<"Reason: " << IMG_GetError();
logGlobal->errorStream() << "Failed to open " << fname << " via SDL_Image";
logGlobal->errorStream() << "Reason: " << IMG_GetError();
return nullptr;
}
}
@ -174,7 +180,9 @@ SDL_Surface * BitmapHandler::loadBitmap(std::string fname, bool setKey)
if (!(bitmap = loadBitmapFromDir("DATA/", fname, setKey)) &&
!(bitmap = loadBitmapFromDir("SPRITES/", fname, setKey)))
logGlobal->errorStream()<<"Error: Failed to find file "<<fname;
{
logGlobal->errorStream() << "Error: Failed to find file " << fname;
}
return bitmap;
}

View File

@ -14,9 +14,6 @@ struct SDL_Surface;
namespace BitmapHandler
{
SDL_Surface * loadH3PCX(ui8 * data, size_t size);
//Load file from specific LOD
SDL_Surface * loadBitmapFromDir(std::string path, std::string fname, bool setKey=true);
//Load file from any LODs
//Load file from /DATA or /SPRITES
SDL_Surface * loadBitmap(std::string fname, bool setKey=true);
}

View File

@ -67,7 +67,7 @@ void CDefHandler::openFromMemory(ui8 *table, const std::string & name)
palette[it].r = de.palette[it].R;
palette[it].g = de.palette[it].G;
palette[it].b = de.palette[it].B;
CSDL_Ext::colorSetAlpha(palette[it],SDL_ALPHA_OPAQUE);
palette[it].a = SDL_ALPHA_OPAQUE;
}
// The SDefEntryBlock starts just after the SDefEntry
@ -122,12 +122,6 @@ void CDefHandler::openFromMemory(ui8 *table, const std::string & name)
}
}
void CDefHandler::expand(ui8 N,ui8 & BL, ui8 & BR)
{
BL = (N & 0xE0) >> 5;
BR = N & 0x1F;
}
SDL_Surface * CDefHandler::getSprite (int SIndex, const ui8 * FDef, const SDL_Color * palette) const
{
SDL_Surface * ret=nullptr;
@ -180,24 +174,11 @@ SDL_Surface * CDefHandler::getSprite (int SIndex, const ui8 * FDef, const SDL_Co
BaseOffset += sizeof(SSpriteDef);
int BaseOffsetor = BaseOffset;
#ifdef VCMI_SDL1
for(int i=0; i<256; ++i)
{
SDL_Color pr;
pr.r = palette[i].r;
pr.g = palette[i].g;
pr.b = palette[i].b;
pr.unused = palette[i].unused;
(*(ret->format->palette->colors+i))=pr;
}
#else
if(SDL_SetPaletteColors(ret->format->palette,palette,0,256) != 0)
{
throw std::runtime_error("Unable to set palette");
}
#endif
SDL_Palette * p = SDL_AllocPalette(256);
SDL_SetPaletteColors(p, palette, 0, 256);
SDL_SetSurfacePalette(ret, p);
SDL_FreePalette(p);
int ftcp=0;
@ -363,13 +344,8 @@ SDL_Surface * CDefHandler::getSprite (int SIndex, const ui8 * FDef, const SDL_Co
}
SDL_Color ttcol = ret->format->palette->colors[0];
#ifdef VCMI_SDL1
Uint32 keycol = SDL_MapRGBA(ret->format, ttcol.r, ttcol.b, ttcol.g, ttcol.unused);
SDL_SetColorKey(ret, SDL_SRCCOLORKEY, keycol);
#else
Uint32 keycol = SDL_MapRGBA(ret->format, ttcol.r, ttcol.b, ttcol.g, ttcol.a);
SDL_SetColorKey(ret, SDL_TRUE, keycol);
#endif // 0
return ret;
}

View File

@ -85,7 +85,9 @@ private:
int group;
} ;
std::vector<SEntry> SEntries ;
void openFromMemory(ui8 * table, const std::string & name);
SDL_Surface * getSprite (int SIndex, const ui8 * FDef, const SDL_Color * palette) const;
public:
int width, height; //width and height
std::string defName;
@ -94,9 +96,7 @@ public:
CDefHandler(); //c-tor
~CDefHandler(); //d-tor
SDL_Surface * getSprite (int SIndex, const ui8 * FDef, const SDL_Color * palette) const; //saves picture with given number to "testtt.bmp"
static void expand(ui8 N,ui8 & BL, ui8 & BR);
void openFromMemory(ui8 * table, const std::string & name);
CDefEssential * essentialize();
static CDefHandler * giveDef(const std::string & defName);

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,5 @@
#pragma once
#ifndef VCMI_SDL1
#include <SDL_render.h>
extern SDL_Texture * screenTexture;
@ -8,8 +7,6 @@ extern SDL_Texture * screenTexture;
extern SDL_Window * mainWindow;
extern SDL_Renderer * mainRenderer;
#endif // VCMI_SDL2
extern SDL_Surface *screen; // main screen surface
extern SDL_Surface *screen2; // and hlp surface (used to store not-active interfaces layer)
extern SDL_Surface *screenBuf; // points to screen (if only advmapint is present) or screen2 (else) - should be used when updating controls which are not regularly redrawed
@ -17,4 +14,4 @@ extern SDL_Surface *screenBuf; // points to screen (if only advmapint is present
extern bool gNoGUI; //if true there is no client window and game is silently played between AIs
void handleQuit();
void handleQuit(bool ask = true);

View File

@ -1,7 +1,7 @@
project(vcmiclient)
cmake_minimum_required(VERSION 2.6)
include_directories(${CMAKE_HOME_DIRECTORY} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_HOME_DIRECTORY}/lib)
include_directories(${CMAKE_HOME_DIRECTORY} ${CMAKE_HOME_DIRECTORY}/include ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_HOME_DIRECTORY}/lib)
include_directories(${SDL_INCLUDE_DIR} ${SDLIMAGE_INCLUDE_DIR} ${SDLMIXER_INCLUDE_DIR} ${SDLTTF_INCLUDE_DIR})
include_directories(${Boost_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIR} ${FFMPEG_INCLUDE_DIRS})
@ -57,6 +57,7 @@ set(client_SRCS
Graphics.cpp
mapHandler.cpp
NetPacksClient.cpp
SDLRWwrapper.cpp
)
set(client_HEADERS
@ -102,7 +103,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,9 +111,10 @@ 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})
elseif(WIN32)
add_executable(vcmiclient ${client_SRCS} VCMI_client.rc)

View File

@ -15,7 +15,6 @@
#include "CGameInfo.h"
#include "gui/SDL_Extensions.h"
#include "../lib/CGeneralTextHandler.h"
#include "Graphics.h"
#include "windows/GUIClasses.h"
#include "../lib/CConfigHandler.h"
#include "CBitmapHandler.h"
@ -45,7 +44,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

@ -3,6 +3,7 @@
#include "CMusicHandler.h"
#include "CGameInfo.h"
#include "SDLRWwrapper.h"
#include "../lib/CCreatureHandler.h"
#include "../lib/spells/CSpellHandler.h"
#include "../lib/JsonNode.h"
@ -51,7 +52,7 @@ void CAudioBase::init()
if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 1024)==-1)
{
logGlobal->errorStream() << "Mix_OpenAudio error: " << Mix_GetError();
logGlobal->errorStream() << "Mix_OpenAudio error: " << Mix_GetError();
return;
}
@ -86,7 +87,7 @@ CSoundHandler::CSoundHandler():
listener(std::bind(&CSoundHandler::onVolumeChange, this, _1));
// Vectors for helper(s)
pickupSounds =
pickupSounds =
{
soundBase::pickup01, soundBase::pickup02, soundBase::pickup03,
soundBase::pickup04, soundBase::pickup05, soundBase::pickup06, soundBase::pickup07
@ -127,8 +128,8 @@ void CSoundHandler::release()
for (auto &chunk : soundChunks)
{
if (chunk.second)
Mix_FreeChunk(chunk.second);
if (chunk.second.first)
Mix_FreeChunk(chunk.second.first);
}
}
@ -141,20 +142,20 @@ Mix_Chunk *CSoundHandler::GetSoundChunk(std::string &sound, bool cache)
try
{
if (cache && soundChunks.find(sound) != soundChunks.end())
return soundChunks[sound];
return soundChunks[sound].first;
auto data = CResourceHandler::get()->load(ResourceID(std::string("SOUNDS/") + sound, EResType::SOUND))->readAll();
SDL_RWops *ops = SDL_RWFromMem(data.first.release(), data.second);
SDL_RWops *ops = SDL_RWFromMem(data.first.get(), data.second);
Mix_Chunk *chunk = Mix_LoadWAV_RW(ops, 1); // will free ops
if (cache)
soundChunks.insert(std::pair<std::string, Mix_Chunk *>(sound, chunk));
soundChunks.insert(std::pair<std::string, CachedChunk>(sound, std::make_pair (chunk, std::move (data.first))));
return chunk;
}
catch(std::exception &e)
{
logGlobal->warnStream() << "Cannot get sound " << sound << " chunk: " << e.what();
logGlobal->warnStream() << "Cannot get sound " << sound << " chunk: " << e.what();
return nullptr;
}
}
@ -182,7 +183,7 @@ int CSoundHandler::playSound(std::string sound, int repeats, bool cache)
channel = Mix_PlayChannel(-1, chunk, repeats);
if (channel == -1)
{
logGlobal->errorStream() << "Unable to play sound file " << sound << " , error " << Mix_GetError();
logGlobal->errorStream() << "Unable to play sound file " << sound << " , error " << Mix_GetError();
if (!cache)
Mix_FreeChunk(chunk);
}
@ -303,7 +304,7 @@ void CMusicHandler::release()
void CMusicHandler::playMusic(std::string musicURI, bool loop)
{
if (current && current->isTrack( musicURI))
if (current && current->isTrack(musicURI))
return;
queueNext(this, "", musicURI, loop);
@ -314,7 +315,7 @@ void CMusicHandler::playMusicFromSet(std::string whichSet, bool loop)
auto selectedSet = musicsSet.find(whichSet);
if (selectedSet == musicsSet.end())
{
logGlobal->errorStream() << "Error: playing music from non-existing set: " << whichSet;
logGlobal->errorStream() << "Error: playing music from non-existing set: " << whichSet;
return;
}
@ -331,25 +332,25 @@ void CMusicHandler::playMusicFromSet(std::string whichSet, int entryID, bool loo
auto selectedSet = musicsSet.find(whichSet);
if (selectedSet == musicsSet.end())
{
logGlobal->errorStream() << "Error: playing music from non-existing set: " << whichSet;
logGlobal->errorStream() << "Error: playing music from non-existing set: " << whichSet;
return;
}
auto selectedEntry = selectedSet->second.find(entryID);
if (selectedEntry == selectedSet->second.end())
{
logGlobal->errorStream() << "Error: playing non-existing entry " << entryID << " from set: " << whichSet;
logGlobal->errorStream() << "Error: playing non-existing entry " << entryID << " from set: " << whichSet;
return;
}
if (current && current->isTrack( selectedEntry->second))
if (current && current->isTrack(selectedEntry->second))
return;
// in this mode - play specific track from set
queueNext(this, "", selectedEntry->second, loop);
}
void CMusicHandler::queueNext(unique_ptr<MusicEntry> queued)
void CMusicHandler::queueNext(std::unique_ptr<MusicEntry> queued)
{
if (!initialized)
return;
@ -421,12 +422,11 @@ void CMusicHandler::musicFinishedCallback(void)
MusicEntry::MusicEntry(CMusicHandler *owner, std::string setName, std::string musicURI, bool looped):
owner(owner),
music(nullptr),
musicFile(nullptr),
loop(looped ? -1 : 1),
setName(setName)
setName(std::move(setName))
{
if (!musicURI.empty())
load(musicURI);
load(std::move(musicURI));
}
MusicEntry::~MusicEntry()
{
@ -448,33 +448,15 @@ void MusicEntry::load(std::string musicURI)
logGlobal->traceStream()<<"Loading music file "<<musicURI;
data = CResourceHandler::get()->load(ResourceID(musicURI, EResType::MUSIC))->readAll();
musicFile = SDL_RWFromConstMem(data.first.get(), data.second);
#ifdef VCMI_SDL1
music = Mix_LoadMUS_RW(musicFile);
auto musicFile = MakeSDLRWops(CResourceHandler::get()->load(ResourceID(std::move(musicURI), EResType::MUSIC)));
music = Mix_LoadMUS_RW(musicFile, SDL_TRUE);
if(!music)
{
SDL_FreeRW(musicFile);
musicFile = nullptr;
logGlobal->warnStream() << "Warning: Cannot open " << currentName << ": " << Mix_GetError();
return;
}
#else
music = Mix_LoadMUS_RW(musicFile, SDL_FALSE);
if(!music)
{
SDL_FreeRW(musicFile);
musicFile = nullptr;
logGlobal->warnStream() << "Warning: Cannot open " << currentName << ": " << Mix_GetError();
return;
}
#endif // 0
}
bool MusicEntry::play()
@ -488,10 +470,10 @@ bool MusicEntry::play()
load(RandomGeneratorUtil::nextItem(set, CRandomGenerator::getDefault())->second);
}
logGlobal->traceStream()<<"Playing music file "<<currentName;
logGlobal->traceStream()<<"Playing music file "<<currentName;
if(Mix_PlayMusic(music, 1) == -1)
{
logGlobal->errorStream() << "Unable to play music (" << Mix_GetError() << ")";
logGlobal->errorStream() << "Unable to play music (" << Mix_GetError() << ")";
return false;
}
return true;
@ -501,7 +483,7 @@ bool MusicEntry::stop(int fade_ms)
{
if (Mix_PlayingMusic())
{
logGlobal->traceStream()<<"Stoping music file "<<currentName;
logGlobal->traceStream()<<"Stoping music file "<<currentName;
loop = 0;
Mix_FadeOutMusic(fade_ms);
return true;

View File

@ -41,7 +41,8 @@ private:
SettingsListener listener;
void onVolumeChange(const JsonNode &volumeNode);
std::map<std::string, Mix_Chunk *> soundChunks;
using CachedChunk = std::pair<Mix_Chunk *, std::unique_ptr<ui8[]>>;
std::map<std::string, CachedChunk> soundChunks;
Mix_Chunk *GetSoundChunk(std::string &sound, bool cache);
@ -52,10 +53,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);
@ -80,10 +81,8 @@ class CMusicHandler;
//Class for handling one music file
class MusicEntry
{
std::pair<std::unique_ptr<ui8[]>, size_t> data;
CMusicHandler *owner;
Mix_Music *music;
SDL_RWops *musicFile;
int loop; // -1 = indefinite
//if not null - set from which music will be randomly selected
@ -114,11 +113,11 @@ private:
SettingsListener listener;
void onVolumeChange(const JsonNode &volumeNode);
unique_ptr<MusicEntry> current;
unique_ptr<MusicEntry> next;
std::unique_ptr<MusicEntry> current;
std::unique_ptr<MusicEntry> next;
void queueNext(CMusicHandler *owner, std::string setName, std::string musicURI, bool looped);
void queueNext(unique_ptr<MusicEntry> queued);
void queueNext(std::unique_ptr<MusicEntry> queued);
std::map<std::string, std::map<int, std::string> > musicsSet;
public:
@ -127,9 +126,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);

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,10 @@
#pragma once
//#include "../lib/CondSh.h"
#include "../lib/FunctionList.h"
#include "../lib/CGameInterface.h"
#include "../lib/NetPacksBase.h"
#include "gui/CIntObject.h"
//#include "../lib/CGameState.h"
#ifdef __GNUC__
#define sprintf_s snprintf
@ -29,12 +27,9 @@
*
*/
class CDefEssential;
class CButton;
class CToggleGroup;
class CDefHandler;
struct TryMoveHero;
class CDefEssential;
class CGHeroInstance;
class CAdvMapInt;
class CCastleInterface;
@ -76,20 +71,22 @@ enum
{
/*CHANGE_SCREEN_RESOLUTION = 1,*/
RETURN_TO_MAIN_MENU = 2,
STOP_CLIENT = 3,
RESTART_GAME,
//STOP_CLIENT = 3,
RESTART_GAME = 4,
RETURN_TO_MENU_LOAD,
FULLSCREEN_TOGGLED,
PREPARE_RESTART_CAMPAIGN
PREPARE_RESTART_CAMPAIGN,
FORCE_QUIT //quit client without question
};
/// Central class for managing user interface logic
class CPlayerInterface : public CGameInterface, public ILockedUpdatable
class CPlayerInterface : public CGameInterface, public IUpdateable
{
const CArmedInstance * currentSelection;
public:
bool observerInDuelMode;
ObjectInstanceID destinationTeleport; //contain -1 or object id if teleportation
int3 destinationTeleportPos;
//minor interfaces
CondSh<bool> *showingDialog; //indicates if dialog box is displayed
@ -105,7 +102,7 @@ public:
static CBattleInterface * battleInt; //nullptr if no battle
CInGameConsole * cingconsole;
shared_ptr<CCallback> cb; //to communicate with engine
std::shared_ptr<CCallback> cb; //to communicate with engine
const BattleAction *curAction; //during the battle - action currently performed by active stack (or nullptr)
std::list<CInfoWindow *> dialogs; //queue of dialogs awaiting to be shown (not currently shown!)
@ -116,7 +113,7 @@ public:
std::vector<const CGHeroInstance *> sleepingHeroes; //if hero is in here, he's sleeping
//During battle is quick combat mode is used
shared_ptr<CBattleGameInterface> autofightingAI; //AI that makes decisions
std::shared_ptr<CBattleGameInterface> autofightingAI; //AI that makes decisions
bool isAutoFightOn; //Flag, switch it to stop quick combat. Don't touch if there is no battle interface.
const CArmedInstance * getSelection();
@ -135,7 +132,6 @@ public:
} spellbookSettings;
void update() override;
void runLocked(std::function<void()> functor) override;
void initializeHeroTownList();
int getLastIndex(std::string namePrefix);
@ -148,11 +144,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;
@ -169,7 +165,7 @@ public:
void showRecruitmentDialog(const CGDwelling *dwelling, const CArmedInstance *dst, int level) override;
void showShipyardDialog(const IShipyard *obj) override; //obj may be town or shipyard;
void showBlockingDialog(const std::string &text, const std::vector<Component> &components, QueryID askID, int soundID, bool selection, bool cancel) override; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID.
void showTeleportDialog(TeleportChannelID channel, std::vector<ObjectInstanceID> exits, bool impassable, QueryID askID) override;
void showTeleportDialog(TeleportChannelID channel, TTeleportExitsList exits, bool impassable, QueryID askID) override;
void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, QueryID queryID) override;
void showPuzzleMap() override;
void viewWorldMap() override;
@ -196,9 +192,9 @@ public:
void gameOver(PlayerColor player, const EVictoryLossCheckResult & victoryLossCheckResult) override;
void playerStartsTurn(PlayerColor player) override; //called before yourTurn on active itnerface
void showComp(const Component &comp, std::string message) override; //display component in the advmapint infobox
void saveGame(COSer & h, const int version) override; //saving
void loadGame(CISer & h, const int version) override; //loading
void showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions) override;
void saveGame(BinarySerializer & h, const int version) override; //saving
void loadGame(BinaryDeserializer & h, const int version) override; //loading
void showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions) override;
//for battles
void actionFinished(const BattleAction& action) override;//occurs AFTER action taken by active stack or by the hero
@ -221,6 +217,7 @@ public:
void battleCatapultAttacked(const CatapultAttack & ca) override; //called when catapult makes an attack
void battleStacksRemoved(const BattleStacksRemoved & bsr) override; //called when certain stack is completely removed from battlefield
void battleObstaclePlaced(const CObstacleInstance &obstacle) override;
void battleGateStateChanged(const EGateState state) override;
void yourTacticPhase(int distance) override;
//-------------//
@ -237,7 +234,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(std::shared_ptr<CCallback> CB) override;
int3 repairScreenPos(int3 pos); //returns position closest to pos we can center screen on
// show dialogs
@ -260,7 +257,6 @@ public:
void tryDiggging(const CGHeroInstance *h);
void showShipyardDialogOrProblemPopup(const IShipyard *obj); //obj may be town or shipyard;
void requestReturningToMainMenu();
void requestStoppingClient();
void sendCustomEvent(int code);
void proposeLoadingGame();
@ -270,10 +266,6 @@ public:
CPlayerInterface(PlayerColor Player);//c-tor
~CPlayerInterface();//d-tor
static CondSh<bool> terminate_cond; // confirm termination
private:
template <typename Handler> void serializeTempl(Handler &h, const int version);
@ -299,9 +291,9 @@ private:
bool duringMovement;
bool ignoreEvents;
bool locked;
void doMoveHero(const CGHeroInstance *h, CGPath path);
void setMovementStatus(bool value);
void askToAssembleArtifact(const ArtifactLocation &al);
};
extern CPlayerInterface * LOCPLINT;

View File

@ -2,14 +2,12 @@
#include "CPreGame.h"
#include "../lib/filesystem/Filesystem.h"
#include "../lib/filesystem/CFileInfo.h"
#include "../lib/filesystem/CCompressedStream.h"
#include "../lib/CStopWatch.h"
#include "gui/SDL_Extensions.h"
#include "CGameInfo.h"
#include "gui/CCursorHandler.h"
#include "CDefHandler.h"
#include "../lib/CGeneralTextHandler.h"
#include "../lib/CTownHandler.h"
#include "../lib/CHeroHandler.h"
@ -19,7 +17,8 @@
#include "CMusicHandler.h"
#include "CVideoHandler.h"
#include "Graphics.h"
#include "../lib/Connection.h"
#include "../lib/serializer/Connection.h"
#include "../lib/serializer/CTypeList.h"
#include "../lib/VCMIDirs.h"
#include "../lib/mapping/CMap.h"
#include "windows/GUIClasses.h"
@ -45,8 +44,8 @@
#include "widgets/TextControls.h"
#include "windows/InfoWindows.h"
#include "../lib/mapping/CMapService.h"
#include "../lib/mapping/CMap.h"
#include "../lib/CRandomGenerator.h"
#include "../lib/CondSh.h"
/*
* CPreGame.cpp, part of VCMI engine
@ -206,7 +205,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);
@ -216,7 +215,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);
@ -306,10 +305,10 @@ void CMenuScreen::switchToTab(size_t index)
//funciton for std::string -> std::function conversion for main menu
static std::function<void()> genCommand(CMenuScreen* menu, std::vector<std::string> menuType, const std::string &string)
{
static const std::vector<std::string> commandType =
static const std::vector<std::string> commandType =
{"to", "campaigns", "start", "load", "exit", "highscores"};
static const std::vector<std::string> gameType =
static const std::vector<std::string> gameType =
{"single", "multi", "campaign", "tutorial"};
std::list<std::string> commands;
@ -368,7 +367,7 @@ static std::function<void()> genCommand(CMenuScreen* menu, std::vector<std::stri
}
}
}
logGlobal->errorStream()<<"Failed to parse command: "<<string;
logGlobal->errorStream()<<"Failed to parse command: "<<string;
return std::function<void()>();
}
@ -504,19 +503,20 @@ void CGPreGame::loadGraphics()
OBJ_CONSTRUCTION_CAPTURING_ALL;
new CFilledTexture("DIBOXBCK", pos);
victory = CDefHandler::giveDef("SCNRVICT.DEF");
loss = CDefHandler::giveDef("SCNRLOSS.DEF");
victoryIcons = std::make_shared<CAnimation>("SCNRVICT.DEF");
victoryIcons->load();
lossIcons = std::make_shared<CAnimation>("SCNRLOSS.DEF");
lossIcons->load();
}
void CGPreGame::disposeGraphics()
{
delete victory;
delete loss;
victoryIcons->unload();
lossIcons->unload();
}
void CGPreGame::update()
{
boost::unique_lock<boost::recursive_mutex> lock(*CPlayerInterface::pim);
if(CGP != this) //don't update if you are not a main interface
return;
@ -538,15 +538,6 @@ void CGPreGame::update()
// /FIXME: find out why GH.listInt is empty to begin with
if (GH.topInt() != nullptr)
GH.topInt()->show(screen);
if (settings["general"]["showfps"].Bool())
GH.drawFPSCounter();
}
void CGPreGame::runLocked(std::function<void()> cb)
{
boost::unique_lock<boost::recursive_mutex> lock(*CPlayerInterface::pim);
cb();
}
void CGPreGame::openCampaignScreen(std::string name)
@ -563,6 +554,8 @@ CGPreGame *CGPreGame::create()
{
if(!CGP)
CGP = new CGPreGame();
GH.terminate_cond.set(false);
return CGP;
}
@ -708,7 +701,10 @@ CSelectionScreen::CSelectionScreen(CMenuScreen::EState Type, CMenuScreen::EMulti
if(isHost())
{
assert(playerNames.size() == 1 && vstd::contains(playerNames, 1)); //TODO hot-seat/network combo
serv = sh->connectToServer();
if(CServerHandler::DO_NOT_START_SERVER)
serv = CServerHandler::justConnectToServer(Address, Port);
else
serv = sh->connectToServer();
*serv << (ui8) 4;
myNameID = 1;
}
@ -949,7 +945,7 @@ void CSelectionScreen::handleConnection()
{
CPackForSelectionScreen *pack = nullptr;
*serv >> pack;
logNetwork->traceStream() << "Received a pack of type " << typeid(*pack).name();
logNetwork->traceStream() << "Received a pack of type " << typeid(*pack).name();
assert(pack);
if(QuitMenuWithoutStarting *endingPack = dynamic_cast<QuitMenuWithoutStarting *>(pack))
{
@ -1012,7 +1008,7 @@ void CSelectionScreen::processPacks()
{
CPackForSelectionScreen *pack = upcomingPacks.front();
upcomingPacks.pop_front();
CBaseForPGApply *apply = applier->apps[typeList.getTypeID(pack)]; //find the applier
CBaseForPGApply *apply = applier->getApplier(typeList.getTypeID(pack)); //find the applier
apply->applyOnPG(this, pack);
delete pack;
}
@ -1105,6 +1101,10 @@ void SelectionTab::filter( int size, bool selectFirst )
std::unordered_set<ResourceID> SelectionTab::getFiles(std::string dirURI, int resType)
{
boost::to_upper(dirURI);
CResourceHandler::get()->updateFilteredFiles([&](const std::string & mount)
{
return boost::algorithm::starts_with(mount, dirURI);
});
std::unordered_set<ResourceID> ret = CResourceHandler::get()->getFilteredFiles([&](const ResourceID & ident)
{
@ -1117,6 +1117,7 @@ std::unordered_set<ResourceID> SelectionTab::getFiles(std::string dirURI, int re
void SelectionTab::parseMaps(const std::unordered_set<ResourceID> &files)
{
logGlobal->debug("Parsing %d maps", files.size());
allItems.clear();
for(auto & file : files)
{
@ -1125,13 +1126,14 @@ void SelectionTab::parseMaps(const std::unordered_set<ResourceID> &files)
CMapInfo mapInfo;
mapInfo.mapInit(file.getName());
// ignore unsupported map versions (e.g. WoG maps without WoG
if (mapInfo.mapHeader->version <= CGI->modh->settings.data["textData"]["mapVersion"].Float())
// ignore unsupported map versions (e.g. WoG maps without WoG)
// but accept VCMI maps
if((mapInfo.mapHeader->version >= EMapFormat::VCMI) || (mapInfo.mapHeader->version <= CGI->modh->settings.data["textData"]["mapVersion"].Float()))
allItems.push_back(std::move(mapInfo));
}
catch(std::exception & e)
{
logGlobal->errorStream() << "Map " << file.getName() << " is invalid. Message: " << e.what();
logGlobal->errorStream() << "Map " << file.getName() << " is invalid. Message: " << e.what();
}
}
}
@ -1142,7 +1144,7 @@ void SelectionTab::parseGames(const std::unordered_set<ResourceID> &files, bool
{
try
{
CLoadFile lf(*CResourceHandler::get()->getResourceName(file), minSupportedVersion);
CLoadFile lf(*CResourceHandler::get()->getResourceName(file), MINIMAL_SERIALIZATION_VERSION);
lf.checkMagicBytes(SAVEGAME_MAGIC);
// ui8 sign[8];
// lf >> sign;
@ -1154,11 +1156,11 @@ void SelectionTab::parseGames(const std::unordered_set<ResourceID> &files, bool
// Create the map info object
CMapInfo mapInfo;
mapInfo.mapHeader = make_unique<CMapHeader>();
mapInfo.scenarioOpts = new StartInfo;
mapInfo.scenarioOpts = nullptr;//to be created by serialiser
lf >> *(mapInfo.mapHeader.get()) >> mapInfo.scenarioOpts;
mapInfo.fileURI = file.getName();
mapInfo.countPlayers();
std::time_t time = CFileInfo(*CResourceHandler::get()->getResourceName(file)).getDate();
std::time_t time = boost::filesystem::last_write_time(*CResourceHandler::get()->getResourceName(file));
mapInfo.date = std::asctime(std::localtime(&time));
// If multi mode then only multi games, otherwise single
@ -1171,7 +1173,7 @@ void SelectionTab::parseGames(const std::unordered_set<ResourceID> &files, bool
}
catch(const std::exception & e)
{
logGlobal->errorStream() << "Error: Failed to process " << file.getName() <<": " << e.what();
logGlobal->errorStream() << "Error: Failed to process " << file.getName() <<": " << e.what();
}
}
}
@ -1291,7 +1293,9 @@ SelectionTab::SelectionTab(CMenuScreen::EState Type, const std::function<void(CM
slider = new CSlider(Point(372, 86), tabType != CMenuScreen::saveGame ? 480 : 430, std::bind(&SelectionTab::sliderMove, this, _1), positions, curItems.size(), 0, false, CSlider::BLUE);
slider->addUsedEvents(WHEEL);
format = CDefHandler::giveDef("SCSELC.DEF");
formatIcons = std::make_shared<CAnimation>("SCSELC.DEF");
formatIcons->load();
sortingBy = _format;
ascending = true;
@ -1320,7 +1324,7 @@ SelectionTab::SelectionTab(CMenuScreen::EState Type, const std::function<void(CM
SelectionTab::~SelectionTab()
{
delete format;
formatIcons->unload();
}
void SelectionTab::sortBy( int criteria )
@ -1369,9 +1373,9 @@ void SelectionTab::select( int position )
if(txt)
{
std::string filename = *CResourceHandler::get("local")->getResourceName(
auto filename = *CResourceHandler::get("local")->getResourceName(
ResourceID(curItems[py]->fileURI, EResType::CLIENT_SAVEGAME));
txt->setText(CFileInfo(filename).getBaseName());
txt->setText(filename.stem().string());
}
onSelect(curItems[py]);
@ -1445,33 +1449,51 @@ void SelectionTab::printMaps(SDL_Surface *to)
}
printAtMiddleLoc(temp2, 70, 128 + line * 25, FONT_SMALL, itemColor, to);
int temp=-1;
int frame = -1, group = 0;
switch (currentItem->mapHeader->version)
{
case EMapFormat::ROE:
temp=0;
frame = 0;
break;
case EMapFormat::AB:
temp=1;
frame = 1;
break;
case EMapFormat::SOD:
temp=2;
frame = 2;
break;
case EMapFormat::WOG:
temp=3;
frame = 3;
break;
case EMapFormat::VCMI:
frame = 0;
group = 1;
break;
default:
// Unknown version. Be safe and ignore that map
logGlobal->warnStream() << "Warning: " << currentItem->fileURI << " has wrong version!";
logGlobal->warnStream() << "Warning: " << currentItem->fileURI << " has wrong version!";
continue;
}
blitAtLoc(format->ourImages[temp].bitmap, 88, 117 + line * 25, to);
IImage * icon = formatIcons->getImage(frame,group);
if(icon)
{
icon->draw(to, pos.x + 88, pos.y + 117 + line * 25);
icon->decreaseRef();
}
//victory conditions
blitAtLoc(CGP->victory->ourImages[currentItem->mapHeader->victoryIconIndex].bitmap, 306, 117 + line * 25, to);
icon = CGP->victoryIcons->getImage(currentItem->mapHeader->victoryIconIndex,0);
if(icon)
{
icon->draw(to, pos.x + 306, pos.y + 117 + line * 25);
icon->decreaseRef();
}
//loss conditions
blitAtLoc(CGP->loss->ourImages[currentItem->mapHeader->defeatIconIndex].bitmap, 339, 117 + line * 25, to);
icon = CGP->lossIcons->getImage(currentItem->mapHeader->defeatIconIndex,0);
if(icon)
{
icon->draw(to, pos.x + 339, pos.y + 117 + line * 25);
icon->decreaseRef();
}
}
else //if campaign
{
@ -1494,8 +1516,8 @@ void SelectionTab::printMaps(SDL_Surface *to)
}
else
{
name = CFileInfo(*CResourceHandler::get("local")->getResourceName(
ResourceID(currentItem->fileURI, EResType::CLIENT_SAVEGAME))).getBaseName();
name = CResourceHandler::get("local")->getResourceName(
ResourceID(currentItem->fileURI, EResType::CLIENT_SAVEGAME))->stem().string();
}
//print name
@ -1671,7 +1693,7 @@ CRandomMapTab::CRandomMapTab()
{
mapGenOptions.setPlayerCount(btnId);
deactivateButtonsFrom(teamsCntGroup, btnId);
deactivateButtonsFrom(compOnlyPlayersCntGroup, 8 - btnId + 1);
deactivateButtonsFrom(compOnlyPlayersCntGroup, btnId);
validatePlayersCnt(btnId);
if(!SEL->isGuest())
updateMapInfo();
@ -1694,7 +1716,6 @@ CRandomMapTab::CRandomMapTab()
compOnlyPlayersCntGroup->pos.y += 285;
compOnlyPlayersCntGroup->pos.x += BTNS_GROUP_LEFT_MARGIN;
addButtonsWithRandToGroup(compOnlyPlayersCntGroup, numberDefs, 0, 7, NUMBERS_WIDTH, 224, 232);
compOnlyPlayersCntGroup->setSelected(0);
compOnlyPlayersCntGroup->addCallback([&](int btnId)
{
mapGenOptions.setCompOnlyPlayerCount(btnId);
@ -1808,9 +1829,9 @@ void CRandomMapTab::validatePlayersCnt(int playersCnt)
mapGenOptions.setTeamCount(playersCnt - 1);
teamsCntGroup->setSelected(mapGenOptions.getTeamCount());
}
if(mapGenOptions.getCompOnlyPlayerCount() > 8 - playersCnt)
if(mapGenOptions.getCompOnlyPlayerCount() >= playersCnt)
{
mapGenOptions.setCompOnlyPlayerCount(8 - playersCnt);
mapGenOptions.setCompOnlyPlayerCount(playersCnt - 1);
compOnlyPlayersCntGroup->setSelected(mapGenOptions.getCompOnlyPlayerCount());
}
@ -1883,9 +1904,9 @@ void CRandomMapTab::updateMapInfo()
// Generate player information
mapInfo->mapHeader->players.clear();
int playersToGen = (mapGenOptions.getPlayerCount() == CMapGenOptions::RANDOM_SIZE
|| mapGenOptions.getCompOnlyPlayerCount() == CMapGenOptions::RANDOM_SIZE)
? 8 : mapGenOptions.getPlayerCount() + mapGenOptions.getCompOnlyPlayerCount();
int playersToGen = PlayerColor::PLAYER_LIMIT_I;
if(mapGenOptions.getPlayerCount() != CMapGenOptions::RANDOM_SIZE)
playersToGen = mapGenOptions.getPlayerCount();
mapInfo->mapHeader->howManyTeams = playersToGen;
for(int i = 0; i < playersToGen; ++i)
@ -1893,7 +1914,8 @@ void CRandomMapTab::updateMapInfo()
PlayerInfo player;
player.isFactionRandom = true;
player.canComputerPlay = true;
if(i >= mapGenOptions.getPlayerCount() && mapGenOptions.getPlayerCount() != CMapGenOptions::RANDOM_SIZE)
if(mapGenOptions.getCompOnlyPlayerCount() != CMapGenOptions::RANDOM_SIZE &&
i >= mapGenOptions.getHumanOnlyPlayerCount())
{
player.canHumanPlay = false;
}
@ -1925,7 +1947,7 @@ const CMapGenOptions & CRandomMapTab::getMapGenOptions() const
return mapGenOptions;
}
void CRandomMapTab::setMapGenOptions(shared_ptr<CMapGenOptions> opts)
void CRandomMapTab::setMapGenOptions(std::shared_ptr<CMapGenOptions> opts)
{
mapSizeBtnGroup->setSelected(vstd::find_pos(getPossibleMapSizes(), opts->getWidth()));
twoLevelsBtn->setSelected(opts->getHasTwoLevels());
@ -1973,8 +1995,8 @@ void CChatBox::addNewMessage(const std::string &text)
}
InfoCard::InfoCard( bool Network )
: bg(nullptr), network(Network), chatOn(false), chat(nullptr), playerListBg(nullptr),
difficulty(nullptr), sizes(nullptr), sFlags(nullptr)
: sizes(nullptr), bg(nullptr), network(Network), chatOn(false), chat(nullptr), playerListBg(nullptr),
difficulty(nullptr)
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
CIntObject::type |= REDRAW_PARENT;
@ -2000,8 +2022,11 @@ InfoCard::InfoCard( bool Network )
parent->children.pop_back();
pos.w = bg->pos.w;
pos.h = bg->pos.h;
sizes = CDefHandler::giveDef("SCNRMPSZ.DEF");
sFlags = CDefHandler::giveDef("ITGFLAGS.DEF");
sizes = new CAnimImage("SCNRMPSZ", 4, 0, 318, 22);//let it be custom size (frame 4) by default
sizes->recActions &= ~(SHOWALL | UPDATE);//explicit draw
sFlags = std::make_shared<CAnimation>("ITGFLAGS.DEF");
sFlags->load();
difficulty = new CToggleGroup(0);
{
static const char *difButns[] = {"GSPBUT3.DEF", "GSPBUT4.DEF", "GSPBUT5.DEF", "GSPBUT6.DEF", "GSPBUT7.DEF"};
@ -2026,12 +2051,16 @@ InfoCard::InfoCard( bool Network )
}
}
victory = new CAnimImage("SCNRVICT",0, 0, 24, 302);
victory->recActions &= ~(SHOWALL | UPDATE);//explicit draw
loss = new CAnimImage("SCNRLOSS", 0, 0, 24, 359);
loss->recActions &= ~(SHOWALL | UPDATE);//explicit draw
}
InfoCard::~InfoCard()
{
delete sizes;
delete sFlags;
if(sFlags)
sFlags->unload();
}
void InfoCard::showAll(SDL_Surface * to)
@ -2079,27 +2108,17 @@ void InfoCard::showAll(SDL_Surface * to)
{
if(SEL->screenType != CMenuScreen::campaignList)
{
int temp = -1;
if(!chatOn)
{
CDefHandler * loss = CGP ? CGP->loss : CDefHandler::giveDef("SCNRLOSS.DEF");
CDefHandler * victory = CGP ? CGP->victory : CDefHandler::giveDef("SCNRVICT.DEF");
CMapHeader * header = SEL->current->mapHeader.get();
//victory conditions
printAtLoc(header->victoryMessage, 60, 307, FONT_SMALL, Colors::WHITE, to);
blitAtLoc(victory->ourImages[header->victoryIconIndex].bitmap, 24, 302, to); //victory cond descr
victory->setFrame(header->victoryIconIndex);
victory->showAll(to);
//loss conditoins
printAtLoc(header->defeatMessage, 60, 366, FONT_SMALL, Colors::WHITE, to);
blitAtLoc(loss->ourImages[header->defeatIconIndex].bitmap, 24, 359, to); //loss cond
if (!CGP)
{
delete loss;
delete victory;
}
loss->setFrame(header->defeatIconIndex);
loss->showAll(to);
}
//difficulty
@ -2111,23 +2130,22 @@ void InfoCard::showAll(SDL_Surface * to)
switch (SEL->current->mapHeader->width)
{
case 36:
temp=0;
sizes->setFrame(0);
break;
case 72:
temp=1;
sizes->setFrame(1);
break;
case 108:
temp=2;
sizes->setFrame(2);
break;
case 144:
temp=3;
sizes->setFrame(3);
break;
default:
temp=4;
sizes->setFrame(4);
break;
}
blitAtLoc(sizes->ourImages[temp].bitmap, 318, 22, to);
sizes->showAll(to);
if(SEL->screenType == CMenuScreen::loadGame)
printToLoc((static_cast<const CMapInfo*>(SEL->current))->date,308,34, FONT_SMALL, Colors::WHITE, to);
@ -2146,8 +2164,10 @@ void InfoCard::showAll(SDL_Surface * to)
for (auto i = SEL->sInfo.playerInfos.cbegin(); i != SEL->sInfo.playerInfos.cend(); i++)
{
int *myx = ((i->first == playerColor || SEL->current->mapHeader->players[i->first.getNum()].team == myT) ? &fx : &ex);
blitAtLoc(sFlags->ourImages[i->first.getNum()].bitmap, *myx, 399, to);
*myx += sFlags->ourImages[i->first.getNum()].bitmap->w;
IImage * flag = sFlags->getImage(i->first.getNum(),0);
flag->draw(to, pos.x + *myx, pos.y + 399);
*myx += flag->width();
flag->decreaseRef();
}
std::string tob;
@ -2242,7 +2262,9 @@ void InfoCard::showTeamsPopup()
int curx = 128 - 9*flags.size();
for(auto & flag : flags)
{
blitAt(sFlags->ourImages[flag].bitmap, curx, 75 + 50*i, bmp);
IImage * icon = sFlags->getImage(flag,0);
icon->draw(bmp, curx, 75 + 50*i);
icon->decreaseRef();
curx += 18;
}
}
@ -3124,14 +3146,17 @@ void CMultiMode::hostTCP()
Settings name = settings.write["general"]["playerName"];
name->String() = txt->text;
GH.popIntTotally(this);
GH.pushInt(new CSelectionScreen(CMenuScreen::newGame, CMenuScreen::MULTI_NETWORK_HOST));
if(CServerHandler::DO_NOT_START_SERVER)
GH.pushInt(new CSimpleJoinScreen(CMenuScreen::MULTI_NETWORK_HOST));
else
GH.pushInt(new CSelectionScreen(CMenuScreen::newGame, CMenuScreen::MULTI_NETWORK_HOST));
}
void CMultiMode::joinTCP()
{
Settings name = settings.write["general"]["playerName"];
name->String() = txt->text;
GH.pushInt(new CSimpleJoinScreen);
GH.pushInt(new CSimpleJoinScreen(CMenuScreen::MULTI_NETWORK_GUEST));
}
CHotSeatPlayers::CHotSeatPlayers(const std::string &firstPlayer)
@ -3226,7 +3251,8 @@ void CBonusSelection::init()
graphics->fonts[FONT_BIG]->renderTextLeft(background, CGI->generaltexth->allTexts[508], Colors::YELLOW, Point(481, 28));
//map size icon
sizes = CDefHandler::giveDef("SCNRMPSZ.DEF");
sizes = new CAnimImage("SCNRMPSZ",4,0,735, 26);
sizes->recActions &= ~(SHOWALL | UPDATE);//explicit draw
//campaign description
graphics->fonts[FONT_SMALL]->renderTextLeft(background, CGI->generaltexth->allTexts[38], Colors::YELLOW, Point(481, 63));
@ -3277,14 +3303,10 @@ void CBonusSelection::init()
graphics->fonts[FONT_MEDIUM]->renderTextLeft(background, difficulty.back(), Colors::WHITE, Point(689, 432));
//difficulty pics
for (int b=0; b<ARRAY_COUNT(diffPics); ++b)
for (size_t b=0; b < diffPics.size(); ++b)
{
CDefEssential * cde = CDefHandler::giveDefEss("GSPBUT" + boost::lexical_cast<std::string>(b+3) + ".DEF");
SDL_Surface * surfToDuplicate = cde->ourImages[0].bitmap;
diffPics[b] = SDL_ConvertSurface(surfToDuplicate, surfToDuplicate->format,
surfToDuplicate->flags);
delete cde;
diffPics[b] = new CAnimImage("GSPBUT" + boost::lexical_cast<std::string>(b+3) + ".DEF", 0, 0, 709, 455);
diffPics[b]->recActions &= ~(SHOWALL | UPDATE);//explicit draw
}
//difficulty selection buttons
@ -3295,30 +3317,26 @@ void CBonusSelection::init()
}
//load miniflags
sFlags = CDefHandler::giveDef("ITGFLAGS.DEF");
sFlags = std::make_shared<CAnimation>("ITGFLAGS.DEF");
sFlags->load();
}
CBonusSelection::CBonusSelection(shared_ptr<CCampaignState> _ourCampaign) : ourCampaign(_ourCampaign)
CBonusSelection::CBonusSelection(std::shared_ptr<CCampaignState> _ourCampaign) : ourCampaign(_ourCampaign)
{
init();
}
CBonusSelection::CBonusSelection(const std::string & campaignFName)
{
ourCampaign = make_shared<CCampaignState>(CCampaignHandler::getCampaign(campaignFName));
ourCampaign = std::make_shared<CCampaignState>(CCampaignHandler::getCampaign(campaignFName));
init();
}
CBonusSelection::~CBonusSelection()
{
SDL_FreeSurface(background);
delete sizes;
delete ourHeader;
delete sFlags;
for (auto & elem : diffPics)
{
SDL_FreeSurface(elem);
}
sFlags->unload();
}
void CBonusSelection::goBack()
@ -3417,8 +3435,6 @@ void CBonusSelection::selectMap(int mapNr, bool initialSelect)
void CBonusSelection::show(SDL_Surface * to)
{
//blitAt(background, pos.x, pos.y, to);
//map name
std::string mapName = ourHeader->name;
@ -3452,7 +3468,8 @@ void CBonusSelection::show(SDL_Surface * to)
temp=4;
break;
}
blitAtLoc(sizes->ourImages[temp].bitmap, 735, 26, to);
sizes->setFrame(temp);
sizes->showAll(to);
//flags
int fx = 496 + graphics->fonts[FONT_SMALL]->getStringWidth(CGI->generaltexth->allTexts[390]);
@ -3462,12 +3479,15 @@ void CBonusSelection::show(SDL_Surface * to)
for (auto i = startInfo.playerInfos.cbegin(); i != startInfo.playerInfos.cend(); i++)
{
int *myx = ((i->first == playerColor || ourHeader->players[i->first.getNum()].team == myT) ? &fx : &ex);
blitAtLoc(sFlags->ourImages[i->first.getNum()].bitmap, *myx, 405, to);
*myx += sFlags->ourImages[i->first.getNum()].bitmap->w;
IImage * flag = sFlags->getImage(i->first.getNum(),0);
flag->draw(to, pos.x + *myx, pos.y + 405);
*myx += flag->width();
flag->decreaseRef();
}
//difficulty
blitAtLoc(diffPics[startInfo.difficulty], 709, 455, to);
diffPics[startInfo.difficulty]->showAll(to);
CIntObject::show(to);
}
@ -3651,7 +3671,7 @@ void CBonusSelection::updateBonusSelection()
if (picNumber != -1)
picName += ":" + boost::lexical_cast<std::string>(picNumber);
auto anim = new CAnimation();
auto anim = std::make_shared<CAnimation>();
anim->setCustom(picName, 0);
bonusButton->setImage(anim);
const SDL_Color brightYellow = { 242, 226, 110, 0 };
@ -4268,7 +4288,7 @@ void CPrologEpilogVideo::clickLeft( tribool down, bool previousState )
exitCb();
}
CSimpleJoinScreen::CSimpleJoinScreen()
CSimpleJoinScreen::CSimpleJoinScreen(CMenuScreen::EMultiMode mode)
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
bg = new CPicture("MUDIALOG.bmp"); // address background
@ -4284,7 +4304,7 @@ CSimpleJoinScreen::CSimpleJoinScreen()
port->cb += std::bind(&CSimpleJoinScreen::onChange, this, _1);
port->filters += std::bind(&CTextInput::numberFilter, _1, _2, 0, 65535);
ok = new CButton(Point( 26, 142), "MUBCHCK.DEF", CGI->generaltexth->zelp[560], std::bind(&CSimpleJoinScreen::enterSelectionScreen, this), SDLK_RETURN);
ok = new CButton(Point( 26, 142), "MUBCHCK.DEF", CGI->generaltexth->zelp[560], std::bind(&CSimpleJoinScreen::enterSelectionScreen, this, mode), SDLK_RETURN);
cancel = new CButton(Point(142, 142), "MUBCANC.DEF", CGI->generaltexth->zelp[561], std::bind(&CGuiHandler::popIntTotally, std::ref(GH), this), SDLK_ESCAPE);
bar = new CGStatusBar(new CPicture(Rect(7, 186, 218, 18), 0));
@ -4293,15 +4313,15 @@ CSimpleJoinScreen::CSimpleJoinScreen()
address->giveFocus();
}
void CSimpleJoinScreen::enterSelectionScreen()
void CSimpleJoinScreen::enterSelectionScreen(CMenuScreen::EMultiMode mode)
{
std::string textAddress = address->text;
std::string textPort = port->text;
GH.popIntTotally(this);
GH.pushInt(new CSelectionScreen(CMenuScreen::newGame, CMenuScreen::MULTI_NETWORK_GUEST, nullptr, textAddress, textPort));
}
GH.pushInt(new CSelectionScreen(CMenuScreen::newGame, mode, nullptr, textAddress, textPort));
}
void CSimpleJoinScreen::onChange(const std::string & newText)
{
ok->block(address->text.empty() || port->text.empty());

View File

@ -1,6 +1,5 @@
#pragma once
//#include "../lib/filesystem/Filesystem.h"
#include "../lib/StartInfo.h"
#include "../lib/FunctionList.h"
#include "../lib/mapping/CMapInfo.h"
@ -36,7 +35,11 @@ class CMultiLineLabel;
class CToggleButton;
class CToggleGroup;
class CTabbedInt;
class IImage;
class CAnimation;
class CAnimImage;
class CButton;
class CLabel;
class CSlider;
namespace boost{ class thread; class recursive_mutex;}
@ -75,10 +78,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 +103,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,13 +118,15 @@ public:
CChatBox(const Rect &rect);
void keyPressed(const SDL_KeyboardEvent & key);
void keyPressed(const SDL_KeyboardEvent & key) override;
void addNewMessage(const std::string &text);
};
class InfoCard : public CIntObject
{
CAnimImage * victory, * loss, *sizes;
std::shared_ptr<CAnimation> sFlags;
public:
CPicture *bg;
CMenuScreen::EState type;
@ -133,11 +138,10 @@ public:
CPicture *playerListBg;
CToggleGroup *difficulty;
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);
@ -149,9 +153,9 @@ public:
class SelectionTab : public CIntObject
{
private:
CDefHandler *format; //map size
std::shared_ptr<CAnimation> formatIcons;
void parseMaps(const std::unordered_set<ResourceID> &files);
void parseMaps(const std::unordered_set<ResourceID> &files);
void parseGames(const std::unordered_set<ResourceID> &files, bool multi);
void parseCampaigns(const std::unordered_set<ResourceID> & files );
std::unordered_set<ResourceID> getFiles(std::string dirURI, int resType);
@ -184,10 +188,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 +239,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 +258,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 +286,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,12 +299,12 @@ 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;
const CMapGenOptions & getMapGenOptions() const;
void setMapGenOptions(shared_ptr<CMapGenOptions> opts);
void setMapGenOptions(std::shared_ptr<CMapGenOptions> opts);
private:
void addButtonsToGroup(CToggleGroup * group, const std::vector<std::string> & defs, int startIndex, int endIndex, int btnWidth, int helpStartIndex) const;
@ -316,7 +320,7 @@ private:
* compOnlyTeamsCntGroup, * waterContentGroup, * monsterStrengthGroup;
CButton * showRandMaps;
CMapGenOptions mapGenOptions;
unique_ptr<CMapInfo> mapInfo;
std::unique_ptr<CMapInfo> mapInfo;
CFunctionList<void(const CMapInfo *)> mapInfoChanged;
};
@ -385,7 +389,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 +458,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
@ -463,7 +467,7 @@ class CBonusSelection : public CIntObject
{
public:
CBonusSelection(const std::string & campaignFName);
CBonusSelection(shared_ptr<CCampaignState> _ourCampaign);
CBonusSelection(std::shared_ptr<CCampaignState> _ourCampaign);
~CBonusSelection();
void showAll(SDL_Surface * to) override;
@ -498,9 +502,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();
@ -526,13 +530,13 @@ private:
std::vector<CRegion *> regions;
CRegion * highlightedRegion;
CToggleGroup * bonuses;
SDL_Surface * diffPics[5]; //pictures of difficulties, user-selectable (or not if campaign locks this)
std::array<CAnimImage *, 5> diffPics; //pictures of difficulties, user-selectable (or not if campaign locks this)
CButton * diffLb, * diffRb; //buttons for changing difficulty
CDefHandler * sizes; //icons of map sizes
CDefHandler * sFlags;
CAnimImage * sizes;//icons of map sizes
std::shared_ptr<CAnimation> sFlags;
// Data
shared_ptr<CCampaignState> ourCampaign;
std::shared_ptr<CCampaignState> ourCampaign;
int selectedMap;
boost::optional<int> selectedBonus;
StartInfo startInfo;
@ -560,12 +564,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 +582,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,...
@ -597,7 +601,7 @@ private:
};
/// Handles background screen, loads graphics for victory/loss condition and random town or hero selection
class CGPreGame : public CIntObject, public ILockedUpdatable
class CGPreGame : public CIntObject, public IUpdateable
{
void loadGraphics();
void disposeGraphics();
@ -607,11 +611,10 @@ class CGPreGame : public CIntObject, public ILockedUpdatable
public:
CMenuScreen * menu;
CDefHandler *victory, *loss;
std::shared_ptr<CAnimation> victoryIcons, lossIcons;
~CGPreGame();
void update() override;
void runLocked(std::function<void()> cb) override;
void openSel(CMenuScreen::EState type, CMenuScreen::EMultiMode multi = CMenuScreen::SINGLE_PLAYER);
void openCampaignScreen(std::string name);
@ -630,7 +633,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.
@ -643,10 +646,10 @@ class CSimpleJoinScreen : public CIntObject
CTextInput * address;
CTextInput * port;
void enterSelectionScreen();
void enterSelectionScreen(CMenuScreen::EMultiMode mode);
void onChange(const std::string & newText);
public:
CSimpleJoinScreen();
CSimpleJoinScreen(CMenuScreen::EMultiMode mode);
};
extern ISelectionScreenInfo *SEL;

View File

@ -53,11 +53,7 @@ CVideoPlayer::CVideoPlayer()
frame = nullptr;
codec = nullptr;
sws = nullptr;
#ifdef VCMI_SDL1
overlay = nullptr;
#else
texture = nullptr;
#endif
dest = nullptr;
context = nullptr;
@ -108,11 +104,7 @@ bool CVideoPlayer::open(std::string fname, bool loop, bool useOverlay, bool scal
return false;
}
// Retrieve stream information
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(53, 17, 0)
if (av_find_stream_info(format) < 0)
#else
if (avformat_find_stream_info(format, nullptr) < 0)
#endif
return false;
// Find the first video stream
@ -143,22 +135,16 @@ bool CVideoPlayer::open(std::string fname, bool loop, bool useOverlay, bool scal
}
// Open codec
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(53, 6, 0)
if ( avcodec_open(codecContext, codec) < 0 )
#else
if ( avcodec_open2(codecContext, codec, nullptr) < 0 )
#endif
{
// Could not open codec
codec = nullptr;
return false;
}
// Allocate video frame
frame = avcodec_alloc_frame();
frame = av_frame_alloc();
//setup scaling
if(scale)
{
pos.w = screen->w;
@ -173,13 +159,7 @@ bool CVideoPlayer::open(std::string fname, bool loop, bool useOverlay, bool scal
// Allocate a place to put our YUV image on that screen
if (useOverlay)
{
#ifdef VCMI_SDL1
overlay = SDL_CreateYUVOverlay(pos.w, pos.h,
SDL_YV12_OVERLAY, screen);
#else
texture = SDL_CreateTexture( mainRenderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STATIC, pos.w, pos.h);
#endif
}
else
{
@ -188,34 +168,28 @@ bool CVideoPlayer::open(std::string fname, bool loop, bool useOverlay, bool scal
destRect.w = pos.w;
destRect.h = pos.h;
}
#ifdef VCMI_SDL1
if (overlay == nullptr && dest == nullptr)
return false;
if (overlay)
#else
if (texture == nullptr && dest == nullptr)
return false;
if (texture)
#endif
{ // Convert the image into YUV format that SDL uses
sws = sws_getContext(codecContext->width, codecContext->height, codecContext->pix_fmt,
pos.w, pos.h, PIX_FMT_YUV420P,
pos.w, pos.h,
AV_PIX_FMT_YUV420P,
SWS_BICUBIC, nullptr, nullptr, nullptr);
}
else
{
PixelFormat screenFormat = PIX_FMT_NONE;
AVPixelFormat screenFormat = AV_PIX_FMT_NONE;
if (screen->format->Bshift > screen->format->Rshift)
{
// this a BGR surface
switch (screen->format->BytesPerPixel)
{
case 2: screenFormat = PIX_FMT_BGR565; break;
case 3: screenFormat = PIX_FMT_BGR24; break;
case 4: screenFormat = PIX_FMT_BGR32; break;
case 2: screenFormat = AV_PIX_FMT_BGR565; break;
case 3: screenFormat = AV_PIX_FMT_BGR24; break;
case 4: screenFormat = AV_PIX_FMT_BGR32; break;
default: return false;
}
}
@ -224,9 +198,9 @@ bool CVideoPlayer::open(std::string fname, bool loop, bool useOverlay, bool scal
// this a RGB surface
switch (screen->format->BytesPerPixel)
{
case 2: screenFormat = PIX_FMT_RGB565; break;
case 3: screenFormat = PIX_FMT_RGB24; break;
case 4: screenFormat = PIX_FMT_RGB32; break;
case 2: screenFormat = AV_PIX_FMT_RGB565; break;
case 3: screenFormat = AV_PIX_FMT_RGB24; break;
case 4: screenFormat = AV_PIX_FMT_RGB32; break;
default: return false;
}
}
@ -284,23 +258,6 @@ bool CVideoPlayer::nextFrame()
{
AVPicture pict;
#ifdef VCMI_SDL1
if (overlay) {
SDL_LockYUVOverlay(overlay);
pict.data[0] = overlay->pixels[0];
pict.data[1] = overlay->pixels[2];
pict.data[2] = overlay->pixels[1];
pict.linesize[0] = overlay->pitches[0];
pict.linesize[1] = overlay->pitches[2];
pict.linesize[2] = overlay->pitches[1];
sws_scale(sws, frame->data, frame->linesize,
0, codecContext->height, pict.data, pict.linesize);
SDL_UnlockYUVOverlay(overlay);
#else
if (texture) {
avpicture_alloc(&pict, AV_PIX_FMT_YUV420P, pos.w, pos.h);
@ -311,7 +268,6 @@ bool CVideoPlayer::nextFrame()
pict.data[1], pict.linesize[1],
pict.data[2], pict.linesize[2]);
avpicture_free(&pict);
#endif
}
else
{
@ -387,22 +343,12 @@ void CVideoPlayer::close()
sws = nullptr;
}
#ifdef VCMI_SDL1
if (overlay)
{
SDL_FreeYUVOverlay(overlay);
overlay = nullptr;
}
#else
if (texture)
{
SDL_DestroyTexture(texture);
texture = nullptr;
}
#endif
if (dest)
{
SDL_FreeSurface(dest);
@ -411,8 +357,7 @@ void CVideoPlayer::close()
if (frame)
{
av_free(frame);
frame = nullptr;
av_frame_free(&frame);//will be set to null
}
if (codec)
@ -424,12 +369,7 @@ void CVideoPlayer::close()
if (format)
{
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(53, 17, 0)
av_close_input_file(format);
format = nullptr;
#else
avformat_close_input(&format);
#endif
}
if (context)
@ -455,13 +395,8 @@ bool CVideoPlayer::playVideo(int x, int y, SDL_Surface *dst, bool stopOnKey)
if(stopOnKey && keyDown())
return false;
#ifdef VCMI_SDL1
SDL_DisplayYUVOverlay(overlay, &pos);
#else
SDL_RenderCopy(mainRenderer, texture, NULL, &pos);
SDL_RenderPresent(mainRenderer);
#endif
// Wait 3 frames
GH.mainFPSmng->framerateDelay();

View File

@ -47,45 +47,53 @@ public:
#include <SDL.h>
#include <SDL_video.h>
#if SDL_VERSION_ATLEAST(1,3,0) && !SDL_VERSION_ATLEAST(2,0,0)
#include <SDL_compat.h>
#endif
extern "C" {
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
// compatibility with different versions od libavutil
#if (LIBAVUTIL_VERSION_INT < AV_VERSION_INT(51, 42, 0)) || \
(LIBAVUTIL_VERSION_INT == AV_VERSION_INT(51, 73, 101))
#define AV_PIX_FMT_NONE PIX_FMT_NONE
#define AV_PIX_FMT_NV12 PIX_FMT_NV12
#define AV_PIX_FMT_YUV420P PIX_FMT_YUV420P
#define AV_PIX_FMT_UYVY422 PIX_FMT_UYVY422
#define AV_PIX_FMT_YUYV422 PIX_FMT_YUYV422
#endif
}
//compatibility for libav 9.18 in ubuntu 14.04, 52.66.100 is ffmpeg 2.2.3
#if (LIBAVUTIL_VERSION_INT < AV_VERSION_INT(52, 66, 100))
inline AVFrame * av_frame_alloc()
{
return avcodec_alloc_frame();
}
inline void av_frame_free(AVFrame ** frame)
{
av_free(*frame);
*frame = nullptr;
}
#endif // VCMI_USE_OLD_AVUTIL
//fix for travis-ci
#if (LIBAVUTIL_VERSION_INT < AV_VERSION_INT(52, 0, 0))
#define AVPixelFormat PixelFormat
#define AV_PIX_FMT_NONE PIX_FMT_NONE
#define AV_PIX_FMT_YUV420P PIX_FMT_YUV420P
#define AV_PIX_FMT_BGR565 PIX_FMT_BGR565
#define AV_PIX_FMT_BGR24 PIX_FMT_BGR24
#define AV_PIX_FMT_BGR32 PIX_FMT_BGR32
#define AV_PIX_FMT_RGB565 PIX_FMT_RGB565
#define AV_PIX_FMT_RGB24 PIX_FMT_RGB24
#define AV_PIX_FMT_RGB32 PIX_FMT_RGB32
#endif
class CVideoPlayer : public IMainVideoPlayer
{
int stream; // stream index in video
AVFormatContext *format;
AVCodecContext *codecContext; // codec context for stream
AVCodec *codec;
AVFrame *frame;
AVFrame *frame;
struct SwsContext *sws;
AVIOContext * context;
// Destination. Either overlay or dest.
#ifdef VCMI_SDL1
SDL_Overlay * overlay;
#else
SDL_Texture *texture;
#endif
SDL_Texture *texture;
SDL_Surface *dest;
SDL_Rect destRect; // valid when dest is used
SDL_Rect pos; // destination on screen
@ -109,7 +117,7 @@ public:
void show(int x, int y, SDL_Surface *dst, bool update = true) override; //blit current frame
void redraw(int x, int y, SDL_Surface *dst, bool update = true) override; //reblits buffer
void update(int x, int y, SDL_Surface *dst, bool forceRedraw, bool update = true) override; //moves to next frame if appropriate, and blits it or blits only if redraw parameter is set true
// Opens video, calls playVideo, closes video; returns playVideo result (if whole video has been played)
bool openAndPlayVideo(std::string name, int x, int y, SDL_Surface *dst, bool stopOnKey = false, bool scale = false) override;

View File

@ -19,7 +19,9 @@
#include "../lib/CTownHandler.h"
#include "../lib/CBuildingHandler.h"
#include "../lib/spells/CSpellHandler.h"
#include "../lib/Connection.h"
#include "../lib/serializer/CTypeList.h"
#include "../lib/serializer/Connection.h"
#include "../lib/serializer/CLoadIntegrityValidator.h"
#ifndef VCMI_ANDROID
#include "../lib/Interprocess.h"
#endif
@ -30,7 +32,6 @@
#include "../lib/JsonNode.h"
#include "mapHandler.h"
#include "../lib/CConfigHandler.h"
#include "Client.h"
#include "CPreGame.h"
#include "battle/CBattleInterface.h"
#include "../lib/CThreadHelper.h"
@ -59,8 +60,8 @@ template <typename T> class CApplyOnCL;
class CBaseForCLApply
{
public:
virtual void applyOnClAfter(CClient *cl, void *pack) const =0;
virtual void applyOnClBefore(CClient *cl, void *pack) const =0;
virtual void applyOnClAfter(CClient *cl, void *pack) const =0;
virtual void applyOnClBefore(CClient *cl, void *pack) const =0;
virtual ~CBaseForCLApply(){}
template<typename U> static CBaseForCLApply *getApplier(const U * t=nullptr)
@ -72,12 +73,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 +88,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,14 +141,17 @@ 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&)
{
logNetwork->debugStream() << "Wait for move thread was interrupted and no action will be send. Was a battle ended by spell?";
logNetwork->debugStream() << "Wait for move thread was interrupted and no action will be send. Was a battle ended by spell?";
return;
}
catch(...)
@ -155,7 +159,7 @@ void CClient::waitForMoveAndSend(PlayerColor color)
handleException();
return;
}
logNetwork->errorStream() << "We should not be here!";
logNetwork->errorStream() << "We should not be here!";
}
void CClient::run()
@ -166,8 +170,8 @@ void CClient::run()
while(!terminate)
{
CPack *pack = serv->retreivePack(); //get the package from the server
if (terminate)
if (terminate)
{
vstd::clear_pointer(pack);
break;
@ -175,15 +179,15 @@ void CClient::run()
handlePack(pack);
}
}
}
//catch only asio exceptions
catch (const boost::system::system_error& e)
{
logNetwork->errorStream() << "Lost connection to server, ending listening thread!";
logNetwork->errorStream() << e.what();
{
logNetwork->errorStream() << "Lost connection to server, ending listening thread!";
logNetwork->errorStream() << e.what();
if(!terminate) //rethrow (-> boom!) only if closing connection was unexpected
{
logNetwork->errorStream() << "Something wrong, lost connection while game is still ongoing...";
logNetwork->errorStream() << "Something wrong, lost connection while game is still ongoing...";
throw;
}
}
@ -193,7 +197,7 @@ void CClient::save(const std::string & fname)
{
if(gs->curB)
{
logNetwork->errorStream() << "Game cannot be saved during battle!";
logNetwork->errorStream() << "Game cannot be saved during battle!";
return;
}
@ -201,33 +205,35 @@ void CClient::save(const std::string & fname)
sendRequest((CPackForClient*)&save_game, PlayerColor::NEUTRAL);
}
void CClient::endGame( bool closeConnection /*= true*/ )
void CClient::endGame(bool closeConnection /*= true*/)
{
//suggest interfaces to finish their stuff (AI should interrupt any bg working threads)
for(auto i : playerint)
for (auto& i : playerint)
i.second->finish();
// Game is ending
// Tell the network thread to reach a stable state
if(closeConnection)
if (closeConnection)
stopConnection();
logNetwork->infoStream() << "Closed connection.";
logNetwork->infoStream() << "Closed connection.";
GH.curInt = nullptr;
{
boost::unique_lock<boost::recursive_mutex> un(*LOCPLINT->pim);
logNetwork->infoStream() << "Ending current game!";
logNetwork->infoStream() << "Ending current game!";
if(GH.topInt())
{
GH.topInt()->deactivate();
}
GH.listInt.clear();
GH.objsToBlit.clear();
GH.statusbar = nullptr;
logNetwork->infoStream() << "Removed GUI.";
logNetwork->infoStream() << "Removed GUI.";
vstd::clear_pointer(const_cast<CGameInfo*>(CGI)->mh);
vstd::clear_pointer(gs);
logNetwork->infoStream() << "Deleted mapHandler and gameState.";
logNetwork->infoStream() << "Deleted mapHandler and gameState.";
LOCPLINT = nullptr;
}
@ -235,30 +241,39 @@ void CClient::endGame( bool closeConnection /*= true*/ )
battleints.clear();
callbacks.clear();
battleCallbacks.clear();
logNetwork->infoStream() << "Deleted playerInts.";
logNetwork->infoStream() << "Client stopped.";
CGKeys::reset();
CGMagi::reset();
CGObelisk::reset();
logNetwork->infoStream() << "Deleted playerInts.";
logNetwork->infoStream() << "Client stopped.";
}
#if 1
void CClient::loadGame(const std::string & fname, const bool server, const std::vector<int>& humanplayerindices, const int loadNumPlayers, int player_, const std::string & ipaddr, const std::string & port)
{
PlayerColor player(player_); //intentional shadowing
PlayerColor player(player_); //intentional shadowing
logNetwork->infoStream() << "Loading procedure started!";
logNetwork->infoStream() <<"Loading procedure started!";
std::string realPort;
if(settings["testing"]["enabled"].Bool())
realPort = settings["testing"]["port"].String();
else if(port.size())
realPort = port;
else
realPort = boost::lexical_cast<std::string>(settings["server"]["port"].Float());
CServerHandler sh;
if(server)
sh.startServer();
else
serv = sh.justConnectToServer(ipaddr,port=="" ? "3030" : port);
if(server)
sh.startServer();
else
serv = sh.justConnectToServer(ipaddr, realPort);
CStopWatch tmh;
unique_ptr<CLoadFile> loader;
std::unique_ptr<CLoadFile> loader;
try
{
std::string clientSaveName = *CResourceHandler::get("local")->getResourceName(ResourceID(fname, EResType::CLIENT_SAVEGAME));
std::string controlServerSaveName;
boost::filesystem::path clientSaveName = *CResourceHandler::get("local")->getResourceName(ResourceID(fname, EResType::CLIENT_SAVEGAME));
boost::filesystem::path controlServerSaveName;
if (CResourceHandler::get("local")->existsResource(ResourceID(fname, EResType::SERVER_SAVEGAME)))
{
@ -266,26 +281,26 @@ void CClient::loadGame(const std::string & fname, const bool server, const std::
}
else// create entry for server savegame. Triggered if save was made after launch and not yet present in res handler
{
controlServerSaveName = clientSaveName.substr(0, clientSaveName.find_last_of(".")) + ".vsgm1";
CResourceHandler::get("local")->createResource(controlServerSaveName, true);
controlServerSaveName = boost::filesystem::path(clientSaveName).replace_extension(".vsgm1");
CResourceHandler::get("local")->createResource(controlServerSaveName.string(), true);
}
if(clientSaveName.empty())
throw std::runtime_error("Cannot open client part of " + fname);
if(controlServerSaveName.empty())
if(controlServerSaveName.empty() || !boost::filesystem::exists(controlServerSaveName))
throw std::runtime_error("Cannot open server part of " + fname);
{
CLoadIntegrityValidator checkingLoader(clientSaveName, controlServerSaveName, minSupportedVersion);
CLoadIntegrityValidator checkingLoader(clientSaveName, controlServerSaveName, MINIMAL_SERIALIZATION_VERSION);
loadCommonState(checkingLoader);
loader = checkingLoader.decay();
}
logNetwork->infoStream() << "Loaded common part of save " << tmh.getDiff();
logNetwork->infoStream() << "Loaded common part of save " << tmh.getDiff();
const_cast<CGameInfo*>(CGI)->mh = new CMapHandler();
const_cast<CGameInfo*>(CGI)->mh->map = gs->map;
pathInfo = make_unique<CPathsInfo>(getMapSize());
CGI->mh->init();
logNetwork->infoStream() <<"Initing maphandler: "<<tmh.getDiff();
logNetwork->infoStream() <<"Initing maphandler: "<<tmh.getDiff();
}
catch(std::exception &e)
{
@ -298,53 +313,53 @@ void CClient::loadGame(const std::string & fname, const bool server, const std::
player = PlayerColor(player_);
*/
std::set<PlayerColor> clientPlayers;
if(server)
serv = sh.connectToServer();
std::set<PlayerColor> clientPlayers;
if(server)
serv = sh.connectToServer();
//*loader >> *this;
if(server)
{
tmh.update();
ui8 pom8;
*serv << ui8(3) << ui8(loadNumPlayers); //load game; one client if single-player
*serv << fname;
*serv >> pom8;
if(pom8)
throw std::runtime_error("Server cannot open the savegame!");
else
logNetwork->infoStream() << "Server opened savegame properly.";
}
if(server)
{
tmh.update();
ui8 pom8;
*serv << ui8(3) << ui8(loadNumPlayers); //load game; one client if single-player
*serv << fname;
*serv >> pom8;
if(pom8)
throw std::runtime_error("Server cannot open the savegame!");
else
logNetwork->infoStream() << "Server opened savegame properly.";
}
if(server)
{
for(auto & elem : gs->scenarioOps->playerInfos)
if(!std::count(humanplayerindices.begin(),humanplayerindices.end(),elem.first.getNum()) || elem.first==player)
{
clientPlayers.insert(elem.first);
}
clientPlayers.insert(PlayerColor::NEUTRAL);
}
else
{
clientPlayers.insert(player);
}
if(server)
{
for(auto & elem : gs->scenarioOps->playerInfos)
{
if(!std::count(humanplayerindices.begin(),humanplayerindices.end(),elem.first.getNum()) || elem.first==player)
clientPlayers.insert(elem.first);
}
clientPlayers.insert(PlayerColor::NEUTRAL);
}
else
{
clientPlayers.insert(player);
}
std::cout << "CLIENTPLAYERS:\n";
for(auto x : clientPlayers)
std::cout << x << std::endl;
std::cout << "ENDCLIENTPLAYERS\n";
std::cout << "CLIENTPLAYERS:\n";
for(auto x : clientPlayers)
std::cout << x << std::endl;
std::cout << "ENDCLIENTPLAYERS\n";
serialize(loader->serializer,0,clientPlayers);
*serv << ui32(clientPlayers.size());
for(auto & elem : clientPlayers)
*serv << ui8(elem.getNum());
serv->addStdVecItems(gs); /*why is this here?*/
serialize(loader->serializer,0,clientPlayers);
*serv << ui32(clientPlayers.size());
for(auto & elem : clientPlayers)
*serv << ui8(elem.getNum());
serv->addStdVecItems(gs); /*why is this here?*/
//*loader >> *this;
logNetwork->infoStream() << "Loaded client part of save " << tmh.getDiff();
logNetwork->infoStream() << "Loaded client part of save " << tmh.getDiff();
logNetwork->infoStream() <<"Sent info to server: "<<tmh.getDiff();
logNetwork->infoStream() <<"Sent info to server: "<<tmh.getDiff();
//*serv << clientPlayers;
serv->enableStackSendingByID();
@ -366,7 +381,7 @@ void CClient::newGame( CConnection *con, StartInfo *si )
{
enum {SINGLE, HOST, GUEST} networkMode = SINGLE;
if (con == nullptr)
if (con == nullptr)
{
CServerHandler sh;
serv = sh.connectToServer();
@ -393,7 +408,7 @@ void CClient::newGame( CConnection *con, StartInfo *si )
}
c >> si;
logNetwork->infoStream() <<"\tSending/Getting info to/from the server: "<<tmh.getDiff();
logNetwork->infoStream() <<"\tSending/Getting info to/from the server: "<<tmh.getDiff();
c.enableStackSendingByID();
c.disableSmartPointerSerialization();
@ -403,7 +418,7 @@ void CClient::newGame( CConnection *con, StartInfo *si )
gs->scenarioOps = si;
gs->init(si);
logNetwork->infoStream() <<"Initializing GameState (together): "<<tmh.getDiff();
logNetwork->infoStream() <<"Initializing GameState (together): "<<tmh.getDiff();
// Now after possible random map gen, we know exact player count.
// Inform server about how many players client handles
@ -426,10 +441,10 @@ void CClient::newGame( CConnection *con, StartInfo *si )
{
const_cast<CGameInfo*>(CGI)->mh = new CMapHandler();
CGI->mh->map = gs->map;
logNetwork->infoStream() <<"Creating mapHandler: "<<tmh.getDiff();
logNetwork->infoStream() << "Creating mapHandler: " << tmh.getDiff();
CGI->mh->init();
pathInfo = make_unique<CPathsInfo>(getMapSize());
logNetwork->infoStream() <<"Initializing mapHandler (together): "<<tmh.getDiff();
logNetwork->infoStream() << "Initializing mapHandler (together): " << tmh.getDiff();
}
int humanPlayers = 0;
@ -440,7 +455,7 @@ void CClient::newGame( CConnection *con, StartInfo *si )
if(!vstd::contains(myPlayers, color))
continue;
logNetwork->traceStream() << "Preparing interface for player " << color;
logNetwork->traceStream() << "Preparing interface for player " << color;
if(si->mode != StartInfo::DUEL)
{
if(elem.second.playerID == PlayerSettings::PLAYER_AI)
@ -449,9 +464,9 @@ void CClient::newGame( CConnection *con, StartInfo *si )
logNetwork->infoStream() << boost::format("Player %s will be lead by %s") % color % AiToGive;
installNewPlayerInterface(CDynLibHandler::getNewAI(AiToGive), color);
}
else
else
{
installNewPlayerInterface(make_shared<CPlayerInterface>(color), color);
installNewPlayerInterface(std::make_shared<CPlayerInterface>(color), color);
humanPlayers++;
}
}
@ -467,7 +482,7 @@ void CClient::newGame( CConnection *con, StartInfo *si )
if(!gNoGUI)
{
boost::unique_lock<boost::recursive_mutex> un(*LOCPLINT->pim);
auto p = make_shared<CPlayerInterface>(PlayerColor::NEUTRAL);
auto p = std::make_shared<CPlayerInterface>(PlayerColor::NEUTRAL);
p->observerInDuelMode = true;
installNewPlayerInterface(p, boost::none);
GH.curInt = p.get();
@ -492,15 +507,15 @@ void CClient::newGame( CConnection *con, StartInfo *si )
// nm->giveActionCB(this);
// nm->giveInfoCB(this);
// nm->init();
//
//
// erm = nm; //something tells me that there'll at most one module and it'll be ERM
// }
}
void CClient::serialize(COSer & h, const int version)
void CClient::serialize(BinarySerializer & h, const int version)
{
assert(h.saving);
h & hotSeat;
h & hotSeat;
{
ui8 players = playerint.size();
h & players;
@ -510,12 +525,12 @@ void CClient::serialize(COSer & h, const int version)
LOG_TRACE_PARAMS(logGlobal, "Saving player %s interface", i->first);
assert(i->first == i->second->playerID);
h & i->first & i->second->dllName & i->second->human;
i->second->saveGame(h, version);
i->second->saveGame(h, version);
}
}
}
void CClient::serialize(CISer & h, const int version)
void CClient::serialize(BinaryDeserializer & h, const int version)
{
assert(!h.saving);
h & hotSeat;
@ -526,19 +541,19 @@ void CClient::serialize(CISer & h, const int version)
for(int i=0; i < players; i++)
{
std::string dllname;
PlayerColor pid;
PlayerColor pid;
bool isHuman = false;
h & pid & dllname & isHuman;
LOG_TRACE_PARAMS(logGlobal, "Loading player %s interface", pid);
shared_ptr<CGameInterface> nInt;
std::shared_ptr<CGameInterface> nInt;
if(dllname.length())
{
if(pid == PlayerColor::NEUTRAL)
{
installNewBattleInterface(CDynLibHandler::getNewBattleAI(dllname), pid);
//TODO? consider serialization
//TODO? consider serialization
continue;
}
else
@ -550,7 +565,7 @@ void CClient::serialize(CISer & h, const int version)
else
{
assert(isHuman);
nInt = make_shared<CPlayerInterface>(pid);
nInt = std::make_shared<CPlayerInterface>(pid);
}
nInt->dllName = dllname;
@ -566,7 +581,7 @@ void CClient::serialize(CISer & h, const int version)
}
}
void CClient::serialize(COSer & h, const int version, const std::set<PlayerColor> & playerIDs)
void CClient::serialize(BinarySerializer & h, const int version, const std::set<PlayerColor> & playerIDs)
{
assert(h.saving);
h & hotSeat;
@ -579,12 +594,12 @@ void CClient::serialize(COSer & h, const int version, const std::set<PlayerColor
LOG_TRACE_PARAMS(logGlobal, "Saving player %s interface", i->first);
assert(i->first == i->second->playerID);
h & i->first & i->second->dllName & i->second->human;
i->second->saveGame(h, version);
i->second->saveGame(h, version);
}
}
}
void CClient::serialize(CISer & h, const int version, const std::set<PlayerColor> & playerIDs)
void CClient::serialize(BinaryDeserializer & h, const int version, const std::set<PlayerColor> & playerIDs)
{
assert(!h.saving);
h & hotSeat;
@ -595,20 +610,20 @@ void CClient::serialize(CISer & h, const int version, const std::set<PlayerColor
for(int i=0; i < players; i++)
{
std::string dllname;
PlayerColor pid;
PlayerColor pid;
bool isHuman = false;
h & pid & dllname & isHuman;
LOG_TRACE_PARAMS(logGlobal, "Loading player %s interface", pid);
shared_ptr<CGameInterface> nInt;
std::shared_ptr<CGameInterface> nInt;
if(dllname.length())
{
if(pid == PlayerColor::NEUTRAL)
{
if(playerIDs.count(pid))
installNewBattleInterface(CDynLibHandler::getNewBattleAI(dllname), pid);
//TODO? consider serialization
if(playerIDs.count(pid))
installNewBattleInterface(CDynLibHandler::getNewBattleAI(dllname), pid);
//TODO? consider serialization
continue;
}
else
@ -620,49 +635,55 @@ void CClient::serialize(CISer & h, const int version, const std::set<PlayerColor
else
{
assert(isHuman);
nInt = make_shared<CPlayerInterface>(pid);
nInt = std::make_shared<CPlayerInterface>(pid);
}
nInt->dllName = dllname;
nInt->human = isHuman;
nInt->playerID = pid;
if(playerIDs.count(pid))
installNewPlayerInterface(nInt, pid);
if(playerIDs.count(pid))
installNewPlayerInterface(nInt, pid);
nInt->loadGame(h, version);
nInt->loadGame(h, version);
}
if(playerIDs.count(PlayerColor::NEUTRAL))
loadNeutralBattleAI();
loadNeutralBattleAI();
}
}
void CClient::handlePack( CPack * pack )
{
CBaseForCLApply *apply = applier->apps[typeList.getTypeID(pack)]; //find the applier
if(pack == nullptr)
{
logNetwork->error("Dropping nullptr CPack! You should check whether client and server ABI matches.");
return;
}
CBaseForCLApply *apply = applier->getApplier(typeList.getTypeID(pack)); //find the applier
if(apply)
{
boost::unique_lock<boost::recursive_mutex> guiLock(*LOCPLINT->pim);
apply->applyOnClBefore(this,pack);
logNetwork->traceStream() << "\tMade first apply on cl";
apply->applyOnClBefore(this, pack);
logNetwork->trace("\tMade first apply on cl");
gs->apply(pack);
logNetwork->traceStream() << "\tApplied on gs";
apply->applyOnClAfter(this,pack);
logNetwork->traceStream() << "\tMade second apply on cl";
logNetwork->trace("\tApplied on gs");
apply->applyOnClAfter(this, pack);
logNetwork->trace("\tMade second apply on cl");
}
else
{
logNetwork->errorStream() << "Message cannot be applied, cannot find applier! TypeID " << typeList.getTypeID(pack);
logNetwork->error("Message cannot be applied, cannot find applier! type %d - %s",
pack->type, typeList.getTypeInfo(pack)->name());
}
delete pack;
}
void CClient::finishCampaign( shared_ptr<CCampaignState> camp )
void CClient::finishCampaign( std::shared_ptr<CCampaignState> camp )
{
}
void CClient::proposeNextMission(shared_ptr<CCampaignState> camp)
void CClient::proposeNextMission(std::shared_ptr<CCampaignState> camp)
{
GH.pushInt(new CBonusSelection(camp));
}
@ -673,11 +694,11 @@ void CClient::stopConnection()
if (serv) //request closing connection
{
logNetwork->infoStream() << "Connection has been requested to be closed.";
logNetwork->infoStream() << "Connection has been requested to be closed.";
boost::unique_lock<boost::mutex>(*serv->wmx);
CloseServer close_server;
sendRequest(&close_server, PlayerColor::NEUTRAL);
logNetwork->infoStream() << "Sent closing signal to the server";
logNetwork->infoStream() << "Sent closing signal to the server";
}
if(connectionHandler)//end connection handler
@ -685,7 +706,7 @@ void CClient::stopConnection()
if(connectionHandler->get_id() != boost::this_thread::get_id())
connectionHandler->join();
logNetwork->infoStream() << "Connection handler thread joined";
logNetwork->infoStream() << "Connection handler thread joined";
delete connectionHandler;
connectionHandler = nullptr;
@ -696,7 +717,7 @@ void CClient::stopConnection()
serv->close();
delete serv;
serv = nullptr;
logNetwork->warnStream() << "Our socket has been closed.";
logNetwork->warnStream() << "Our socket has been closed.";
}
}
@ -704,7 +725,7 @@ void CClient::battleStarted(const BattleInfo * info)
{
for(auto &battleCb : battleCallbacks)
{
if(vstd::contains_if(info->sides, [&](const SideInBattle& side) {return side.color == battleCb.first; })
if(vstd::contains_if(info->sides, [&](const SideInBattle& side) {return side.color == battleCb.first; })
|| battleCb.first >= PlayerColor::PLAYER_LIMIT)
{
battleCb.second->setBattle(info);
@ -714,7 +735,7 @@ void CClient::battleStarted(const BattleInfo * info)
// if(battleCallbacks.count(side))
// battleCallbacks[side]->setBattle(info);
shared_ptr<CPlayerInterface> att, def;
std::shared_ptr<CPlayerInterface> att, def;
auto &leftSide = info->sides[0], &rightSide = info->sides[1];
@ -732,7 +753,7 @@ void CClient::battleStarted(const BattleInfo * info)
{
boost::unique_lock<boost::recursive_mutex> un(*LOCPLINT->pim);
auto bi = new CBattleInterface(leftSide.armyObject, rightSide.armyObject, leftSide.hero, rightSide.hero,
Rect((screen->w - 800)/2,
Rect((screen->w - 800)/2,
(screen->h - 600)/2, 800, 600), att, def);
GH.pushInt(bi);
@ -780,7 +801,7 @@ PlayerColor CClient::getLocalPlayer() const
return getCurrentPlayer();
}
void CClient::commenceTacticPhaseForInt(shared_ptr<CBattleGameInterface> battleInt)
void CClient::commenceTacticPhaseForInt(std::shared_ptr<CBattleGameInterface> battleInt)
{
setThreadName("CClient::commenceTacticPhaseForInt");
try
@ -795,7 +816,7 @@ void CClient::commenceTacticPhaseForInt(shared_ptr<CBattleGameInterface> battleI
catch(...)
{
handleException();
}
}
}
void CClient::invalidatePaths()
@ -821,7 +842,7 @@ int CClient::sendRequest(const CPack *request, PlayerColor player)
static ui32 requestCounter = 0;
ui32 requestID = requestCounter++;
logNetwork->traceStream() << boost::format("Sending a request \"%s\". It'll have an ID=%d.")
logNetwork->traceStream() << boost::format("Sending a request \"%s\". It'll have an ID=%d.")
% typeid(*request).name() % requestID;
waitingRequest.pushBack(requestID);
@ -832,7 +853,7 @@ int CClient::sendRequest(const CPack *request, PlayerColor player)
return requestID;
}
void CClient::campaignMapFinished( shared_ptr<CCampaignState> camp )
void CClient::campaignMapFinished( std::shared_ptr<CCampaignState> camp )
{
endGame(false);
@ -855,7 +876,7 @@ void CClient::campaignMapFinished( shared_ptr<CCampaignState> camp )
}
}
void CClient::installNewPlayerInterface(shared_ptr<CGameInterface> gameInterface, boost::optional<PlayerColor> color)
void CClient::installNewPlayerInterface(std::shared_ptr<CGameInterface> gameInterface, boost::optional<PlayerColor> color)
{
boost::unique_lock<boost::recursive_mutex> un(*LOCPLINT->pim);
PlayerColor colorUsed = color.get_value_or(PlayerColor::UNFLAGGABLE);
@ -866,7 +887,7 @@ void CClient::installNewPlayerInterface(shared_ptr<CGameInterface> gameInterface
playerint[colorUsed] = gameInterface;
logGlobal->traceStream() << boost::format("\tInitializing the interface for player %s") % colorUsed;
auto cb = make_shared<CCallback>(gs, color, this);
auto cb = std::make_shared<CCallback>(gs, color, this);
callbacks[colorUsed] = cb;
battleCallbacks[colorUsed] = cb;
gameInterface->init(cb);
@ -874,12 +895,12 @@ void CClient::installNewPlayerInterface(shared_ptr<CGameInterface> gameInterface
installNewBattleInterface(gameInterface, color, false);
}
void CClient::installNewBattleInterface(shared_ptr<CBattleGameInterface> battleInterface, boost::optional<PlayerColor> color, bool needCallback /*= true*/)
void CClient::installNewBattleInterface(std::shared_ptr<CBattleGameInterface> battleInterface, boost::optional<PlayerColor> color, bool needCallback /*= true*/)
{
boost::unique_lock<boost::recursive_mutex> un(*LOCPLINT->pim);
PlayerColor colorUsed = color.get_value_or(PlayerColor::UNFLAGGABLE);
if(!color)
if(!color)
privilagedBattleEventReceivers.push_back(battleInterface);
battleints[colorUsed] = battleInterface;
@ -887,7 +908,7 @@ void CClient::installNewBattleInterface(shared_ptr<CBattleGameInterface> battleI
if(needCallback)
{
logGlobal->traceStream() << boost::format("\tInitializing the battle interface for player %s") % *color;
auto cbc = make_shared<CBattleCallback>(gs, color, this);
auto cbc = std::make_shared<CBattleCallback>(gs, color, this);
battleCallbacks[colorUsed] = cbc;
battleInterface->init(cbc);
}
@ -915,17 +936,25 @@ std::string CClient::aiNameForPlayer(const PlayerSettings &ps, bool battleAI)
return goodAI;
}
bool CServerHandler::DO_NOT_START_SERVER = false;
void CServerHandler::startServer()
{
if(DO_NOT_START_SERVER)
return;
th.update();
serverThread = new boost::thread(&CServerHandler::callServer, this); //runs server executable;
if(verbose)
logNetwork->infoStream() << "Setting up thread calling server: " << th.getDiff();
logNetwork->infoStream() << "Setting up thread calling server: " << th.getDiff();
}
void CServerHandler::waitForServer()
{
if(DO_NOT_START_SERVER)
return;
if(!serverThread)
startServer();
@ -938,7 +967,7 @@ void CServerHandler::waitForServer()
}
#endif
if(verbose)
logNetwork->infoStream() << "Waiting for server: " << th.getDiff();
logNetwork->infoStream() << "Waiting for server: " << th.getDiff();
}
CConnection * CServerHandler::connectToServer()
@ -951,11 +980,11 @@ CConnection * CServerHandler::connectToServer()
#endif
th.update(); //put breakpoint here to attach to server before it does something stupid
CConnection *ret = justConnectToServer(settings["server"]["server"].String(), port);
if(verbose)
logNetwork->infoStream()<<"\tConnecting to the server: "<<th.getDiff();
logNetwork->infoStream()<<"\tConnecting to the server: "<<th.getDiff();
return ret;
}
@ -964,7 +993,10 @@ CServerHandler::CServerHandler(bool runServer /*= false*/)
{
serverThread = nullptr;
shared = nullptr;
port = boost::lexical_cast<std::string>(settings["server"]["port"].Float());
if(settings["testing"]["enabled"].Bool())
port = settings["testing"]["port"].String();
else
port = boost::lexical_cast<std::string>(settings["server"]["port"].Float());
verbose = true;
#ifndef VCMI_ANDROID
@ -972,13 +1004,13 @@ CServerHandler::CServerHandler(bool runServer /*= false*/)
try
{
shared = new SharedMem();
}
catch(...)
{
logNetwork->error("Cannot open interprocess memory.");
handleException();
throw;
}
}
catch(...)
{
logNetwork->error("Cannot open interprocess memory.");
handleException();
throw;
}
#endif
}
@ -995,30 +1027,38 @@ void CServerHandler::callServer()
const std::string comm = VCMIDirs::get().serverPath().string() + " --port=" + port + " > \"" + logName + '\"';
int result = std::system(comm.c_str());
if (result == 0)
logNetwork->infoStream() << "Server closed correctly";
logNetwork->infoStream() << "Server closed correctly";
else
{
logNetwork->errorStream() << "Error: server failed to close correctly or crashed!";
logNetwork->errorStream() << "Check " << logName << " for more info";
logNetwork->errorStream() << "Error: server failed to close correctly or crashed!";
logNetwork->errorStream() << "Check " << logName << " for more info";
exit(1);// exit in case of error. Othervice without working server VCMI will hang
}
}
CConnection * CServerHandler::justConnectToServer(const std::string &host, const std::string &port)
{
std::string realPort;
if(settings["testing"]["enabled"].Bool())
realPort = settings["testing"]["port"].String();
else if(port.size())
realPort = port;
else
realPort = boost::lexical_cast<std::string>(settings["server"]["port"].Float());
CConnection *ret = nullptr;
while(!ret)
{
try
{
logNetwork->infoStream() << "Establishing connection...";
ret = new CConnection( host.size() ? host : settings["server"]["server"].String(),
port.size() ? port : boost::lexical_cast<std::string>(settings["server"]["port"].Float()),
logNetwork->infoStream() << "Establishing connection...";
ret = new CConnection( host.size() ? host : settings["server"]["server"].String(),
realPort,
NAME);
}
catch(...)
{
logNetwork->errorStream() << "\nCannot establish connection! Retrying within 2 seconds";
logNetwork->errorStream() << "\nCannot establish connection! Retrying within 2 seconds";
SDL_Delay(2000);
}
}

View File

@ -16,7 +16,7 @@
*
*/
class CPack;
struct CPack;
class CCampaignState;
class CBattleCallback;
class IGameEventsReceiver;
@ -32,8 +32,8 @@ struct SharedMem;
class CClient;
class CScriptingModule;
struct CPathsInfo;
class CISer;
class COSer;
class BinaryDeserializer;
class BinarySerializer;
namespace boost { class thread; }
/// structure to handle running server and connecting to it
@ -42,6 +42,8 @@ class CServerHandler
private:
void callServer(); //calls server via system(), should be called as thread
public:
static bool DO_NOT_START_SERVER;
CStopWatch th;
boost::thread *serverThread; //thread that called system to run server
SharedMem *shared; //interprocess memory (for waiting for server)
@ -57,7 +59,7 @@ public:
static CConnection * justConnectToServer(const std::string &host = "", const std::string &port = ""); //connects to given host without taking any other actions (like setting up server)
CServerHandler(bool runServer = false);
~CServerHandler();
virtual ~CServerHandler();
};
template<typename T>
@ -70,7 +72,6 @@ class ThreadSafeVector
boost::condition_variable cond;
public:
void pushBack(const T &item)
{
TLock lock(mx);
@ -115,17 +116,17 @@ public:
/// Class which handles client - server logic
class CClient : public IGameCallback
{
unique_ptr<CPathsInfo> pathInfo;
std::unique_ptr<CPathsInfo> pathInfo;
public:
std::map<PlayerColor,shared_ptr<CCallback> > callbacks; //callbacks given to player interfaces
std::map<PlayerColor,shared_ptr<CBattleCallback> > battleCallbacks; //callbacks given to player interfaces
std::vector<shared_ptr<IGameEventsReceiver>> privilagedGameEventReceivers; //scripting modules, spectator interfaces
std::vector<shared_ptr<IBattleEventsReceiver>> privilagedBattleEventReceivers; //scripting modules, spectator interfaces
std::map<PlayerColor, shared_ptr<CGameInterface>> playerint;
std::map<PlayerColor, shared_ptr<CBattleGameInterface>> battleints;
std::map<PlayerColor,std::shared_ptr<CCallback> > callbacks; //callbacks given to player interfaces
std::map<PlayerColor,std::shared_ptr<CBattleCallback> > battleCallbacks; //callbacks given to player interfaces
std::vector<std::shared_ptr<IGameEventsReceiver>> privilagedGameEventReceivers; //scripting modules, spectator interfaces
std::vector<std::shared_ptr<IBattleEventsReceiver>> privilagedBattleEventReceivers; //scripting modules, spectator interfaces
std::map<PlayerColor, std::shared_ptr<CGameInterface>> playerint;
std::map<PlayerColor, std::shared_ptr<CBattleGameInterface>> battleints;
std::map<PlayerColor,std::vector<shared_ptr<IGameEventsReceiver>>> additionalPlayerInts;
std::map<PlayerColor,std::vector<shared_ptr<IBattleEventsReceiver>>> additionalBattleInts;
std::map<PlayerColor,std::vector<std::shared_ptr<IGameEventsReceiver>>> additionalPlayerInts;
std::map<PlayerColor,std::vector<std::shared_ptr<IBattleEventsReceiver>>> additionalBattleInts;
bool hotSeat;
CConnection *serv;
@ -146,8 +147,8 @@ public:
void newGame(CConnection *con, StartInfo *si); //con - connection to server
void loadNeutralBattleAI();
void installNewPlayerInterface(shared_ptr<CGameInterface> gameInterface, boost::optional<PlayerColor> color);
void installNewBattleInterface(shared_ptr<CBattleGameInterface> battleInterface, boost::optional<PlayerColor> color, bool needCallback = true);
void installNewPlayerInterface(std::shared_ptr<CGameInterface> gameInterface, boost::optional<PlayerColor> color);
void installNewBattleInterface(std::shared_ptr<CBattleGameInterface> battleInterface, boost::optional<PlayerColor> color, bool needCallback = true);
std::string aiNameForPlayer(const PlayerSettings &ps, bool battleAI); //empty means no AI -> human
void endGame(bool closeConnection = true);
@ -155,9 +156,9 @@ public:
void save(const std::string & fname);
void loadGame(const std::string & fname, const bool server = true, const std::vector<int>& humanplayerindices = std::vector<int>(), const int loadnumplayers = 1, int player_ = -1, const std::string & ipaddr = "", const std::string & port = "");
void run();
void campaignMapFinished( shared_ptr<CCampaignState> camp );
void finishCampaign( shared_ptr<CCampaignState> camp );
void proposeNextMission(shared_ptr<CCampaignState> camp);
void campaignMapFinished( std::shared_ptr<CCampaignState> camp );
void finishCampaign( std::shared_ptr<CCampaignState> camp );
void proposeNextMission(std::shared_ptr<CCampaignState> camp);
void invalidatePaths();
const CPathsInfo * getPathsInfo(const CGHeroInstance *h);
@ -175,9 +176,9 @@ public:
void setBlockVis(ObjectInstanceID objid, bool bv) override {};
void setOwner(const CGObjectInstance * obj, PlayerColor owner) override {};
void changePrimSkill(const CGHeroInstance * hero, PrimarySkill::PrimarySkill which, si64 val, bool abs=false) override {};
void changeSecSkill(const CGHeroInstance * hero, SecondarySkill which, int val, bool abs=false) override {};
void changeSecSkill(const CGHeroInstance * hero, SecondarySkill which, int val, bool abs=false) override {};
void showBlockingDialog(BlockingDialog *iw) override {};
void showBlockingDialog(BlockingDialog *iw) override {};
void showGarrisonDialog(ObjectInstanceID upobj, ObjectInstanceID hid, bool removableUnits) override {};
void showTeleportDialog(TeleportDialog *iw) override {};
void showThievesGuildWindow(PlayerColor player, ObjectInstanceID requestingObjId) override {};
@ -186,20 +187,20 @@ public:
void giveCreatures(const CArmedInstance * objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove) override {};
void takeCreatures(ObjectInstanceID objid, const std::vector<CStackBasicDescriptor> &creatures) override {};
bool changeStackType(const StackLocation &sl, CCreature *c) override {return false;};
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 {}
bool moveStack(const StackLocation &src, const StackLocation &dst, TQuantity count = -1) override {return false;}
void removeAfterVisit(const CGObjectInstance *object) override {};
void giveHeroNewArtifact(const CGHeroInstance *h, const CArtifact *artType, ArtifactPosition pos) override {};
void giveHeroArtifact(const CGHeroInstance *h, const CArtifactInstance *a, ArtifactPosition pos) override {};
void putArtifact(const ArtifactLocation &al, const CArtifactInstance *a) override {};
void putArtifact(const ArtifactLocation &al, const CArtifactInstance *a) override {};
void removeArtifact(const ArtifactLocation &al) override {};
bool moveArtifact(const ArtifactLocation &al1, const ArtifactLocation &al2) override {return false;};
void synchronizeArtifactHandlerLists() override {};
@ -207,8 +208,6 @@ public:
void showCompInfo(ShowInInfobox * comp) override {};
void heroVisitCastle(const CGTownInstance * obj, const CGHeroInstance * hero) override {};
void stopHeroVisitCastle(const CGTownInstance * obj, const CGHeroInstance * hero) override {};
//void giveHeroArtifact(int artid, int hid, int position){};
//void giveNewArtifact(int hid, int position){};
void startBattlePrimary(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank = false, const CGTownInstance *town = nullptr) override {}; //use hero=nullptr for no hero
void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, bool creatureBank = false) override {}; //if any of armies is hero, hero will be used
void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, bool creatureBank = false) override {}; //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle
@ -233,16 +232,16 @@ public:
void handlePack( CPack * pack ); //applies the given pack and deletes it
void battleStarted(const BattleInfo * info);
void commenceTacticPhaseForInt(shared_ptr<CBattleGameInterface> battleInt); //will be called as separate thread
void commenceTacticPhaseForInt(std::shared_ptr<CBattleGameInterface> battleInt); //will be called as separate thread
void commitPackage(CPackForClient *pack) override;
//////////////////////////////////////////////////////////////////////////
void serialize(COSer &h, const int version);
void serialize(CISer &h, const int version);
void serialize(COSer &h, const int version, const std::set<PlayerColor>& playerIDs);
void serialize(CISer &h, const int version, const std::set<PlayerColor>& playerIDs);
void serialize(BinarySerializer & h, const int version);
void serialize(BinaryDeserializer & h, const int version);
void serialize(BinarySerializer & h, const int version, const std::set<PlayerColor>& playerIDs);
void serialize(BinaryDeserializer & h, const int version, const std::set<PlayerColor>& playerIDs);
void battleFinished();
};

View File

@ -5,6 +5,7 @@
#include "../lib/filesystem/CBinaryReader.h"
#include "CDefHandler.h"
#include "gui/SDL_Extensions.h"
#include "gui/CAnimation.h"
#include <SDL_ttf.h>
#include "../lib/CThreadHelper.h"
#include "CGameInfo.h"
@ -19,9 +20,9 @@
#include "../lib/CGameState.h"
#include "../lib/JsonNode.h"
#include "../lib/vcmi_endian.h"
#include "../lib/GameConstants.h"
#include "../lib/CStopWatch.h"
#include "../lib/mapObjects/CObjectClassesHandler.h"
#include "../lib/mapObjects/CObjectHandler.h"
using namespace CSDL_Ext;
#ifdef min
@ -58,7 +59,7 @@ void Graphics::loadPaletteAndColors()
col.r = pals[startPoint++];
col.g = pals[startPoint++];
col.b = pals[startPoint++];
CSDL_Ext::colorSetAlpha(col,SDL_ALPHA_OPAQUE);
col.a = SDL_ALPHA_OPAQUE;
startPoint++;
playerColorPalette[i] = col;
}
@ -74,32 +75,35 @@ void Graphics::loadPaletteAndColors()
neutralColorPalette[i].g = reader.readUInt8();
neutralColorPalette[i].b = reader.readUInt8();
reader.readUInt8(); // this is "flags" entry, not alpha
CSDL_Ext::colorSetAlpha(neutralColorPalette[i], SDL_ALPHA_OPAQUE);
neutralColorPalette[i].a = SDL_ALPHA_OPAQUE;
}
//colors initialization
SDL_Color colors[] = {
{0xff,0, 0, SDL_ALPHA_OPAQUE},
SDL_Color colors[] = {
{0xff,0, 0, SDL_ALPHA_OPAQUE},
{0x31,0x52,0xff,SDL_ALPHA_OPAQUE},
{0x9c,0x73,0x52,SDL_ALPHA_OPAQUE},
{0x42,0x94,0x29,SDL_ALPHA_OPAQUE},
{0xff,0x84,0, SDL_ALPHA_OPAQUE},
{0x8c,0x29,0xa5,SDL_ALPHA_OPAQUE},
{0x09,0x9c,0xa5,SDL_ALPHA_OPAQUE},
{0xc6,0x7b,0x8c,SDL_ALPHA_OPAQUE}};
{0xc6,0x7b,0x8c,SDL_ALPHA_OPAQUE}};
for(int i=0;i<8;i++)
{
playerColors[i] = colors[i];
}
neutralColor->r = 0x84; neutralColor->g = 0x84; neutralColor->b = 0x84; //gray
CSDL_Ext::colorSetAlpha(*neutralColor,SDL_ALPHA_OPAQUE);
//gray
neutralColor->r = 0x84;
neutralColor->g = 0x84;
neutralColor->b = 0x84;
neutralColor->a = SDL_ALPHA_OPAQUE;
}
void Graphics::initializeBattleGraphics()
{
const JsonNode config(ResourceID("config/battles_graphics.json"));
// Reserve enough space for the terrains
int idx = config["backgrounds"].Vector().size();
battleBacks.resize(idx+1); // 1 to idx, 0 is unused
@ -120,11 +124,20 @@ void Graphics::initializeBattleGraphics()
}
battleACToDef[ACid] = toAdd;
}
}
}
Graphics::Graphics()
{
#if 0
#define GET_DATA(TYPE,DESTINATION,FUNCTION_TO_GET) \
(std::bind(&setData<TYPE>,&DESTINATION,FUNCTION_TO_GET))
#define GET_DEF_ESS(DESTINATION, DEF_NAME) \
(GET_DATA \
(CDefEssential*,DESTINATION,\
std::function<CDefEssential*()>(std::bind(CDefHandler::giveDefEss,DEF_NAME))))
std::vector<Task> tasks; //preparing list of graphics to load
tasks += std::bind(&Graphics::loadFonts,this);
tasks += std::bind(&Graphics::loadPaletteAndColors,this);
@ -132,8 +145,6 @@ Graphics::Graphics()
tasks += std::bind(&Graphics::initializeBattleGraphics,this);
tasks += std::bind(&Graphics::loadErmuToPicture,this);
tasks += std::bind(&Graphics::initializeImageLists,this);
tasks += GET_DEF_ESS(resources32,"RESOURCE.DEF");
tasks += GET_DEF_ESS(heroMoveArrows,"ADAG.DEF");
CThreadHelper th(&tasks,std::max((ui32)1,boost::thread::hardware_concurrency()));
th.run();
@ -144,20 +155,23 @@ Graphics::Graphics()
initializeBattleGraphics();
loadErmuToPicture();
initializeImageLists();
resources32 = CDefHandler::giveDefEss("RESOURCE.DEF");
heroMoveArrows = CDefHandler::giveDefEss("ADAG.DEF");
#endif
for(auto & elem : heroMoveArrows->ourImages)
{
CSDL_Ext::alphaTransform(elem.bitmap);
}
//(!) do not load any CAnimation here
}
void Graphics::load()
{
heroMoveArrows = std::make_shared<CAnimation>("ADAG");
heroMoveArrows->preload();
loadHeroAnims();
}
void Graphics::loadHeroAnims()
{
//first - group number to be rotated1, second - group number after rotation1
std::vector<std::pair<int,int> > rotations =
std::vector<std::pair<int,int> > rotations =
{
{6,10}, {7,11}, {8,12}, {1,13},
{2,14}, {3,15}
@ -219,11 +233,11 @@ void Graphics::loadHeroFlagsDetail(std::pair<std::vector<CDefEssential *> Graphi
for(int i=0;i<8;i++)
(this->*pr.first).push_back(CDefHandler::giveDefEss(pr.second[i]));
//first - group number to be rotated1, second - group number after rotation1
std::vector<std::pair<int,int> > rotations =
std::vector<std::pair<int,int> > rotations =
{
{6,10}, {7,11}, {8,12}
};
for(int q=0; q<8; ++q)
{
std::vector<Cimage> &curImgs = (this->*pr.first)[q]->ourImages;
@ -266,9 +280,7 @@ void Graphics::loadHeroFlagsDetail(std::pair<std::vector<CDefEssential *> Graphi
for(auto & curImg : curImgs)
{
CSDL_Ext::setDefaultColorKey(curImg.bitmap);
#ifndef VCMI_SDL1
SDL_SetSurfaceBlendMode(curImg.bitmap,SDL_BLENDMODE_NONE);
#endif
}
}
}
@ -279,15 +291,15 @@ void Graphics::loadHeroFlags()
std::pair<std::vector<CDefEssential *> Graphics::*, std::vector<const char *> > pr[4] =
{
{
&Graphics::flags1,
&Graphics::flags1,
{"ABF01L.DEF","ABF01G.DEF","ABF01R.DEF","ABF01D.DEF","ABF01B.DEF",
"ABF01P.DEF","ABF01W.DEF","ABF01K.DEF"}
"ABF01P.DEF","ABF01W.DEF","ABF01K.DEF"}
},
{
&Graphics::flags2,
{"ABF02L.DEF","ABF02G.DEF","ABF02R.DEF","ABF02D.DEF","ABF02B.DEF",
"ABF02P.DEF","ABF02W.DEF","ABF02K.DEF"}
},
{
&Graphics::flags3,
@ -298,7 +310,7 @@ void Graphics::loadHeroFlags()
&Graphics::flags4,
{"AF00.DEF","AF01.DEF","AF02.DEF","AF03.DEF","AF04.DEF",
"AF05.DEF","AF06.DEF","AF07.DEF"}
}
}
};
#if 0
@ -314,7 +326,7 @@ void Graphics::loadHeroFlags()
loadHeroFlagsDetail(p,true);
}
#endif
logGlobal->infoStream() << "Loading and transforming heroes' flags: "<<th.getDiff();
logGlobal->infoStream() << "Loading and transforming heroes' flags: "<<th.getDiff();
}
void Graphics::blueToPlayersAdv(SDL_Surface * sur, PlayerColor player)
@ -332,7 +344,7 @@ void Graphics::blueToPlayersAdv(SDL_Surface * sur, PlayerColor player)
}
else
{
logGlobal->errorStream() << "Wrong player id in blueToPlayersAdv (" << player << ")!";
logGlobal->errorStream() << "Wrong player id in blueToPlayersAdv (" << player << ")!";
return;
}
SDL_SetColors(sur, palette, 224, 32);
@ -372,11 +384,21 @@ void Graphics::loadFonts()
CDefEssential * Graphics::getDef( const CGObjectInstance * obj )
{
if (obj->appearance.animationFile.empty())
{
logGlobal->warnStream() << boost::format("Def name for obj %d (%d,%d) is empty!") % obj->id % obj->ID % obj->subID;
return nullptr;
}
return advmapobjGraphics[obj->appearance.animationFile];
}
CDefEssential * Graphics::getDef( const ObjectTemplate & info )
{
if (info.animationFile.empty())
{
logGlobal->warnStream() << boost::format("Def name for obj (%d,%d) is empty!") % info.id % info.subid;
return nullptr;
}
return advmapobjGraphics[info.animationFile];
}
@ -448,12 +470,12 @@ void Graphics::initializeImageLists()
addImageListEntry(info.icons[1][1] + 2, "ITPA", info.iconSmall[1][1]);
}
}
for(const CSpell * spell : CGI->spellh->objects)
{
addImageListEntry(spell->id, "SPELLS", spell->iconBook);
addImageListEntry(spell->id+1, "SPELLINT", spell->iconEffect);
addImageListEntry(spell->id, "SPELLBON", spell->iconScenarioBonus);
addImageListEntry(spell->id, "SPELLSCR", spell->iconScroll);
addImageListEntry(spell->id, "SPELLSCR", spell->iconScroll);
}
}

View File

@ -38,20 +38,30 @@ class Graphics
{
void addImageListEntry(size_t index, std::string listName, std::string imageName);
void initializeBattleGraphics();
void loadPaletteAndColors();
void loadHeroFlags();
void loadHeroFlagsDetail(std::pair<std::vector<CDefEssential *> Graphics::*, std::vector<const char *> > &pr, bool mode);
void loadHeroAnims();
CDefEssential * loadHeroAnim(const std::string &name, const std::vector<std::pair<int,int> > &rotations);
void loadErmuToPicture();
void loadFonts();
void initializeImageLists();
public:
//Fonts
static const int FONTS_NUMBER = 9;
IFont * fonts[FONTS_NUMBER];
//various graphics
SDL_Color * playerColors; //array [8]
SDL_Color * neutralColor;
SDL_Color * playerColorPalette; //palette to make interface colors good - array of size [256]
SDL_Color * neutralColorPalette;
SDL_Color * neutralColorPalette;
std::vector<CDefEssential *> flags1, flags2, flags3, flags4; //flags blitted on heroes when ,
CDefEssential * resources32; //resources 32x32
CDefEssential * heroMoveArrows;
std::shared_ptr<CAnimation> heroMoveArrows;
std::map<std::string, CDefEssential *> heroAnims; // [hero class def name] //added group 10: up - left, 11 - left and 12 - left down // 13 - up-left standing; 14 - left standing; 15 - left down standing
std::vector<CDefEssential *> boatAnims; // [boat type: 0 - 3] //added group 10: up - left, 11 - left and 12 - left down // 13 - up-left standing; 14 - left standing; 15 - left down standing
CDefHandler * FoWfullHide; //for Fog of War
@ -68,18 +78,11 @@ public:
std::vector< std::vector< std::string > > battleBacks; //battleBacks[terType] - vector of possible names for certain terrain type
std::map< int, std::vector < std::string > > battleACToDef; //maps AC format to vector of appropriate def names
//functions
Graphics();
void initializeBattleGraphics();
void loadPaletteAndColors();
void loadHeroFlags();
void loadHeroFlagsDetail(std::pair<std::vector<CDefEssential *> Graphics::*, std::vector<const char *> > &pr, bool mode);
void loadHeroAnims();
CDefEssential * loadHeroAnim(const std::string &name, const std::vector<std::pair<int,int> > &rotations);
void loadErmuToPicture();
void blueToPlayersAdv(SDL_Surface * sur, PlayerColor player); //replaces blue interface colour with a color of player
Graphics();
void loadFonts();
void initializeImageLists();
void load();
void blueToPlayersAdv(SDL_Surface * sur, PlayerColor player); //replaces blue interface colour with a color of player
};
extern Graphics * graphics;

View File

@ -2,12 +2,13 @@
#include "../lib/NetPacks.h"
#include "../lib/filesystem/Filesystem.h"
#include "../lib/filesystem/CFileInfo.h"
#include "../lib/filesystem/FileInfo.h"
#include "../CCallback.h"
#include "Client.h"
#include "CPlayerInterface.h"
#include "CGameInfo.h"
#include "../lib/Connection.h"
#include "../lib/serializer/Connection.h"
#include "../lib/serializer/BinarySerializer.h"
#include "../lib/CGeneralTextHandler.h"
#include "../lib/CHeroHandler.h"
#include "../lib/VCMI_Lib.h"
@ -25,6 +26,7 @@
#include "../lib/CGameState.h"
#include "../lib/BattleState.h"
#include "../lib/GameConstants.h"
#include "../lib/CPlayerState.h"
#include "gui/CGuiHandler.h"
#include "widgets/MiscWidgets.h"
#include "widgets/AdventureMapClasses.h"
@ -104,39 +106,39 @@
*
*/
void SetResources::applyCl( CClient *cl )
void SetResources::applyCl(CClient *cl)
{
INTERFACE_CALL_IF_PRESENT(player,receivedResource,-1,-1);
}
void SetResource::applyCl( CClient *cl )
void SetResource::applyCl(CClient *cl)
{
INTERFACE_CALL_IF_PRESENT(player,receivedResource,resid,val);
}
void SetPrimSkill::applyCl( CClient *cl )
void SetPrimSkill::applyCl(CClient *cl)
{
const CGHeroInstance *h = cl->getHero(id);
if(!h)
{
logNetwork->errorStream() << "Cannot find hero with ID " << id.getNum();
logNetwork->errorStream() << "Cannot find hero with ID " << id.getNum();
return;
}
INTERFACE_CALL_IF_PRESENT(h->tempOwner,heroPrimarySkillChanged,h,which,val);
}
void SetSecSkill::applyCl( CClient *cl )
void SetSecSkill::applyCl(CClient *cl)
{
const CGHeroInstance *h = cl->getHero(id);
if(!h)
{
logNetwork->errorStream() << "Cannot find hero with ID " << id;
logNetwork->errorStream() << "Cannot find hero with ID " << id;
return;
}
INTERFACE_CALL_IF_PRESENT(h->tempOwner,heroSecondarySkillChanged,h,which,val);
}
void HeroVisitCastle::applyCl( CClient *cl )
void HeroVisitCastle::applyCl(CClient *cl)
{
const CGHeroInstance *h = cl->getHero(hid);
@ -146,25 +148,25 @@ void HeroVisitCastle::applyCl( CClient *cl )
}
}
void ChangeSpells::applyCl( CClient *cl )
void ChangeSpells::applyCl(CClient *cl)
{
//TODO: inform interface?
}
void SetMana::applyCl( CClient *cl )
void SetMana::applyCl(CClient *cl)
{
const CGHeroInstance *h = cl->getHero(hid);
INTERFACE_CALL_IF_PRESENT(h->tempOwner, heroManaPointsChanged, h);
}
void SetMovePoints::applyCl( CClient *cl )
void SetMovePoints::applyCl(CClient *cl)
{
const CGHeroInstance *h = cl->getHero(hid);
cl->invalidatePaths();
INTERFACE_CALL_IF_PRESENT(h->tempOwner, heroMovePointsChanged, h);
}
void FoWChange::applyCl( CClient *cl )
void FoWChange::applyCl(CClient *cl)
{
for(auto &i : cl->playerint)
{
@ -183,85 +185,85 @@ void FoWChange::applyCl( CClient *cl )
cl->invalidatePaths();
}
void SetAvailableHeroes::applyCl( CClient *cl )
void SetAvailableHeroes::applyCl(CClient *cl)
{
//TODO: inform interface?
}
void ChangeStackCount::applyCl( CClient *cl )
void ChangeStackCount::applyCl(CClient *cl)
{
INTERFACE_CALL_IF_PRESENT(sl.army->tempOwner, stackChagedCount, sl, count, absoluteValue);
}
void SetStackType::applyCl( CClient *cl )
void SetStackType::applyCl(CClient *cl)
{
INTERFACE_CALL_IF_PRESENT(sl.army->tempOwner, stackChangedType, sl, *type);
}
void EraseStack::applyCl( CClient *cl )
void EraseStack::applyCl(CClient *cl)
{
INTERFACE_CALL_IF_PRESENT(sl.army->tempOwner, stacksErased, sl);
}
void SwapStacks::applyCl( CClient *cl )
void SwapStacks::applyCl(CClient *cl)
{
INTERFACE_CALL_IF_PRESENT(sl1.army->tempOwner, stacksSwapped, sl1, sl2);
if(sl1.army->tempOwner != sl2.army->tempOwner)
INTERFACE_CALL_IF_PRESENT(sl2.army->tempOwner, stacksSwapped, sl1, sl2);
}
void InsertNewStack::applyCl( CClient *cl )
void InsertNewStack::applyCl(CClient *cl)
{
INTERFACE_CALL_IF_PRESENT(sl.army->tempOwner,newStackInserted,sl, *sl.getStack());
}
void RebalanceStacks::applyCl( CClient *cl )
void RebalanceStacks::applyCl(CClient *cl)
{
INTERFACE_CALL_IF_PRESENT(src.army->tempOwner, stacksRebalanced, src, dst, count);
if(src.army->tempOwner != dst.army->tempOwner)
INTERFACE_CALL_IF_PRESENT(dst.army->tempOwner,stacksRebalanced, src, dst, count);
}
void PutArtifact::applyCl( CClient *cl )
void PutArtifact::applyCl(CClient *cl)
{
INTERFACE_CALL_IF_PRESENT(al.owningPlayer(), artifactPut, al);
}
void EraseArtifact::applyCl( CClient *cl )
void EraseArtifact::applyCl(CClient *cl)
{
INTERFACE_CALL_IF_PRESENT(al.owningPlayer(), artifactRemoved, al);
}
void MoveArtifact::applyCl( CClient *cl )
void MoveArtifact::applyCl(CClient *cl)
{
INTERFACE_CALL_IF_PRESENT(src.owningPlayer(), artifactMoved, src, dst);
if(src.owningPlayer() != dst.owningPlayer())
INTERFACE_CALL_IF_PRESENT(dst.owningPlayer(), artifactMoved, src, dst);
}
void AssembledArtifact::applyCl( CClient *cl )
void AssembledArtifact::applyCl(CClient *cl)
{
INTERFACE_CALL_IF_PRESENT(al.owningPlayer(), artifactAssembled, al);
}
void DisassembledArtifact::applyCl( CClient *cl )
void DisassembledArtifact::applyCl(CClient *cl)
{
INTERFACE_CALL_IF_PRESENT(al.owningPlayer(), artifactDisassembled, al);
}
void HeroVisit::applyCl( CClient *cl )
void HeroVisit::applyCl(CClient *cl)
{
assert(hero);
INTERFACE_CALL_IF_PRESENT(player, heroVisit, hero, obj, starting);
}
void NewTurn::applyCl( CClient *cl )
void NewTurn::applyCl(CClient *cl)
{
cl->invalidatePaths();
}
void GiveBonus::applyCl( CClient *cl )
void GiveBonus::applyCl(CClient *cl)
{
cl->invalidatePaths();
switch(who)
@ -281,13 +283,13 @@ void GiveBonus::applyCl( CClient *cl )
}
}
void ChangeObjPos::applyFirstCl( CClient *cl )
void ChangeObjPos::applyFirstCl(CClient *cl)
{
CGObjectInstance *obj = GS(cl)->getObjInstance(objid);
if(flags & 1)
CGI->mh->hideObject(obj);
}
void ChangeObjPos::applyCl( CClient *cl )
void ChangeObjPos::applyCl(CClient *cl)
{
CGObjectInstance *obj = GS(cl)->getObjInstance(objid);
if(flags & 1)
@ -296,12 +298,12 @@ void ChangeObjPos::applyCl( CClient *cl )
cl->invalidatePaths();
}
void PlayerEndsGame::applyCl( CClient *cl )
void PlayerEndsGame::applyCl(CClient *cl)
{
CALL_IN_ALL_INTERFACES(gameOver, player, victoryLossCheckResult);
}
void RemoveBonus::applyCl( CClient *cl )
void RemoveBonus::applyCl(CClient *cl)
{
cl->invalidatePaths();
switch(who)
@ -321,7 +323,7 @@ void RemoveBonus::applyCl( CClient *cl )
}
}
void UpdateCampaignState::applyCl( CClient *cl )
void UpdateCampaignState::applyCl(CClient *cl)
{
cl->stopConnection();
cl->campaignMapFinished(camp);
@ -332,7 +334,7 @@ void PrepareForAdvancingCampaign::applyCl(CClient *cl)
cl->serv->prepareForSendingHeroes();
}
void RemoveObject::applyFirstCl( CClient *cl )
void RemoveObject::applyFirstCl(CClient *cl)
{
const CGObjectInstance *o = cl->getObj(id);
@ -346,12 +348,12 @@ void RemoveObject::applyFirstCl( CClient *cl )
}
}
void RemoveObject::applyCl( CClient *cl )
void RemoveObject::applyCl(CClient *cl)
{
cl->invalidatePaths();
}
void TryMoveHero::applyFirstCl( CClient *cl )
void TryMoveHero::applyFirstCl(CClient *cl)
{
CGHeroInstance *h = GS(cl)->getHero(id);
@ -374,7 +376,7 @@ void TryMoveHero::applyFirstCl( CClient *cl )
CGI->mh->printObject(h->boat);
}
void TryMoveHero::applyCl( CClient *cl )
void TryMoveHero::applyCl(CClient *cl)
{
const CGHeroInstance *h = cl->getHero(id);
cl->invalidatePaths();
@ -410,13 +412,11 @@ void TryMoveHero::applyCl( CClient *cl )
}
}
void NewStructures::applyCl( CClient *cl )
void NewStructures::applyCl(CClient *cl)
{
CGTownInstance *town = GS(cl)->getTown(tid);
for(const auto & id : bid)
{
town->updateAppearance();
if(vstd::contains(cl->playerint,town->tempOwner))
cl->playerint[town->tempOwner]->buildChanged(town,id,1);
}
@ -426,14 +426,12 @@ void RazeStructures::applyCl (CClient *cl)
CGTownInstance *town = GS(cl)->getTown(tid);
for(const auto & id : bid)
{
town->updateAppearance();
if(vstd::contains (cl->playerint,town->tempOwner))
cl->playerint[town->tempOwner]->buildChanged (town,id,2);
}
}
void SetAvailableCreatures::applyCl( CClient *cl )
void SetAvailableCreatures::applyCl(CClient *cl)
{
const CGDwelling *dw = static_cast<const CGDwelling*>(cl->getObj(tid));
@ -448,28 +446,28 @@ void SetAvailableCreatures::applyCl( CClient *cl )
INTERFACE_CALL_IF_PRESENT(p, availableCreaturesChanged, dw);
}
void SetHeroesInTown::applyCl( CClient *cl )
void SetHeroesInTown::applyCl(CClient *cl)
{
CGTownInstance *t = GS(cl)->getTown(tid);
CGHeroInstance *hGarr = GS(cl)->getHero(this->garrison);
CGHeroInstance *hVisit = GS(cl)->getHero(this->visiting);
std::set<PlayerColor> playersToNotify;
//inform all players that see this object
for(auto i = cl->playerint.cbegin(); i != cl->playerint.cend(); ++i)
{
if(i->first >= PlayerColor::PLAYER_LIMIT)
continue;
if(vstd::contains(cl->playerint,t->tempOwner)) // our town
playersToNotify.insert(t->tempOwner);
if (hGarr && vstd::contains(cl->playerint, hGarr->tempOwner))
playersToNotify.insert(hGarr->tempOwner);
if (hVisit && vstd::contains(cl->playerint, hVisit->tempOwner))
playersToNotify.insert(hVisit->tempOwner);
for(auto playerID : playersToNotify)
cl->playerint[playerID]->heroInGarrisonChange(t);
if(GS(cl)->isVisible(t, i->first) ||
(hGarr && GS(cl)->isVisible(hGarr, i->first)) ||
(hVisit && GS(cl)->isVisible(hVisit, i->first)))
{
cl->playerint[i->first]->heroInGarrisonChange(t);
}
}
}
// void SetHeroArtifacts::applyCl( CClient *cl )
// void SetHeroArtifacts::applyCl(CClient *cl)
// {
// // CGHeroInstance *h = GS(cl)->getHero(hid);
// // CGameInterface *player = (vstd::contains(cl->playerint,h->tempOwner) ? cl->playerint[h->tempOwner] : nullptr);
@ -489,37 +487,43 @@ void SetHeroesInTown::applyCl( CClient *cl )
// // }
// }
void HeroRecruited::applyCl( CClient *cl )
void HeroRecruited::applyCl(CClient *cl)
{
CGHeroInstance *h = GS(cl)->map->heroesOnMap.back();
if(h->subID != hid)
{
logNetwork->errorStream() << "Something wrong with hero recruited!";
logNetwork->errorStream() << "Something wrong with hero recruited!";
}
CGI->mh->printObject(h);
if(vstd::contains(cl->playerint,h->tempOwner))
bool needsPrinting = true;
if(vstd::contains(cl->playerint, h->tempOwner))
{
cl->playerint[h->tempOwner]->heroCreated(h);
if(const CGTownInstance *t = GS(cl)->getTown(tid))
{
cl->playerint[h->tempOwner]->heroInGarrisonChange(t);
needsPrinting = false;
}
}
if (needsPrinting)
{
CGI->mh->printObject(h);
}
}
void GiveHero::applyCl( CClient *cl )
void GiveHero::applyCl(CClient *cl)
{
CGHeroInstance *h = GS(cl)->getHero(id);
CGI->mh->printObject(h);
cl->playerint[h->tempOwner]->heroCreated(h);
}
void GiveHero::applyFirstCl( CClient *cl )
void GiveHero::applyFirstCl(CClient *cl)
{
CGI->mh->hideObject(GS(cl)->getHero(id));
}
void InfoWindow::applyCl( CClient *cl )
void InfoWindow::applyCl(CClient *cl)
{
std::vector<Component*> comps;
for(auto & elem : components)
@ -532,10 +536,10 @@ void InfoWindow::applyCl( CClient *cl )
if(vstd::contains(cl->playerint,player))
cl->playerint.at(player)->showInfoDialog(str,comps,(soundBase::soundID)soundID);
else
logNetwork->warnStream() << "We received InfoWindow for not our player...";
logNetwork->warnStream() << "We received InfoWindow for not our player...";
}
void SetObjectProperty::applyCl( CClient *cl )
void SetObjectProperty::applyCl(CClient *cl)
{
//inform all players that see this object
for(auto it = cl->playerint.cbegin(); it != cl->playerint.cend(); ++it)
@ -545,7 +549,7 @@ void SetObjectProperty::applyCl( CClient *cl )
}
}
void HeroLevelUp::applyCl( CClient *cl )
void HeroLevelUp::applyCl(CClient *cl)
{
//INTERFACE_CALL_IF_PRESENT(h->tempOwner, heroGotLevel, h, primskill, skills, id);
if(vstd::contains(cl->playerint,hero->tempOwner))
@ -556,7 +560,7 @@ void HeroLevelUp::applyCl( CClient *cl )
// cb->selectionMade(0, queryID);
}
void CommanderLevelUp::applyCl( CClient *cl )
void CommanderLevelUp::applyCl(CClient *cl)
{
const CCommanderInstance * commander = hero->commander;
assert (commander);
@ -567,7 +571,7 @@ void CommanderLevelUp::applyCl( CClient *cl )
}
}
void BlockingDialog::applyCl( CClient *cl )
void BlockingDialog::applyCl(CClient *cl)
{
std::string str;
text.toString(str);
@ -575,7 +579,7 @@ void BlockingDialog::applyCl( CClient *cl )
if(vstd::contains(cl->playerint,player))
cl->playerint.at(player)->showBlockingDialog(str,components,queryID,(soundBase::soundID)soundID,selection(),cancel());
else
logNetwork->warnStream() << "We received YesNoDialog for not our player...";
logNetwork->warnStream() << "We received YesNoDialog for not our player...";
}
void GarrisonDialog::applyCl(CClient *cl)
@ -595,12 +599,12 @@ void ExchangeDialog::applyCl(CClient *cl)
INTERFACE_CALL_IF_PRESENT(heroes[0]->tempOwner, heroExchangeStarted, heroes[0]->id, heroes[1]->id, queryID);
}
void TeleportDialog::applyCl( CClient *cl )
void TeleportDialog::applyCl(CClient *cl)
{
CALL_ONLY_THAT_INTERFACE(hero->tempOwner,showTeleportDialog,channel,exits,impassable,queryID);
}
void BattleStart::applyFirstCl( CClient *cl )
void BattleStart::applyFirstCl(CClient *cl)
{
//Cannot use the usual macro because curB is not set yet
CALL_ONLY_THAT_BATTLE_INTERFACE(info->sides[0].color, battleStartBefore, info->sides[0].armyObject, info->sides[1].armyObject,
@ -611,7 +615,7 @@ void BattleStart::applyFirstCl( CClient *cl )
info->tile, info->sides[0].hero, info->sides[1].hero);
}
void BattleStart::applyCl( CClient *cl )
void BattleStart::applyCl(CClient *cl)
{
cl->battleStarted(info);
}
@ -621,30 +625,30 @@ void BattleNextRound::applyFirstCl(CClient *cl)
BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(battleNewRoundFirst,round);
}
void BattleNextRound::applyCl( CClient *cl )
void BattleNextRound::applyCl(CClient *cl)
{
BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(battleNewRound,round);
}
void BattleSetActiveStack::applyCl( CClient *cl )
void BattleSetActiveStack::applyCl(CClient *cl)
{
if(!askPlayerInterface)
return;
const CStack * activated = GS(cl)->curB->battleGetStackByID(stack);
const CStack *activated = GS(cl)->curB->battleGetStackByID(stack);
PlayerColor playerToCall; //player that will move activated stack
if( activated->hasBonusOfType(Bonus::HYPNOTIZED) )
if (activated->hasBonusOfType(Bonus::HYPNOTIZED))
{
playerToCall = ( GS(cl)->curB->sides[0].color == activated->owner
? GS(cl)->curB->sides[1].color
: GS(cl)->curB->sides[0].color );
playerToCall = (GS(cl)->curB->sides[0].color == activated->owner
? GS(cl)->curB->sides[1].color
: GS(cl)->curB->sides[0].color);
}
else
{
playerToCall = activated->owner;
}
if( vstd::contains(cl->battleints, playerToCall) )
boost::thread( std::bind(&CClient::waitForMoveAndSend, cl, playerToCall) );
if (vstd::contains(cl->battleints, playerToCall))
boost::thread(std::bind(&CClient::waitForMoveAndSend, cl, playerToCall));
}
void BattleTriggerEffect::applyCl(CClient * cl)
@ -657,20 +661,25 @@ void BattleObstaclePlaced::applyCl(CClient * cl)
BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(battleObstaclePlaced, *obstacle);
}
void BattleResult::applyFirstCl( CClient *cl )
void BattleUpdateGateState::applyFirstCl(CClient * cl)
{
BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(battleGateStateChanged, state);
}
void BattleResult::applyFirstCl(CClient *cl)
{
BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(battleEnd,this);
cl->battleFinished();
}
void BattleStackMoved::applyFirstCl( CClient *cl )
void BattleStackMoved::applyFirstCl(CClient *cl)
{
const CStack * movedStack = GS(cl)->curB->battleGetStackByID(stack);
BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(battleStackMoved,movedStack,tilesToMove,distance);
}
//void BattleStackAttacked::( CClient *cl )
void BattleStackAttacked::applyFirstCl( CClient *cl )
//void BattleStackAttacked::(CClient *cl)
void BattleStackAttacked::applyFirstCl(CClient *cl)
{
std::vector<BattleStackAttacked> bsa;
bsa.push_back(*this);
@ -678,7 +687,7 @@ void BattleStackAttacked::applyFirstCl( CClient *cl )
BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(battleStacksAttacked,bsa);
}
void BattleAttack::applyFirstCl( CClient *cl )
void BattleAttack::applyFirstCl(CClient *cl)
{
BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(battleAttack,this);
for (auto & elem : bsa)
@ -690,34 +699,34 @@ void BattleAttack::applyFirstCl( CClient *cl )
}
}
void BattleAttack::applyCl( CClient *cl )
void BattleAttack::applyCl(CClient *cl)
{
BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(battleStacksAttacked,bsa);
}
void StartAction::applyFirstCl( CClient *cl )
void StartAction::applyFirstCl(CClient *cl)
{
cl->curbaction = ba;
BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(actionStarted, ba);
}
void BattleSpellCast::applyCl( CClient *cl )
void BattleSpellCast::applyCl(CClient *cl)
{
BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(battleSpellCast,this);
}
void SetStackEffect::applyCl( CClient *cl )
void SetStackEffect::applyCl(CClient *cl)
{
//informing about effects
BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(battleStacksEffectsSet,*this);
}
void StacksInjured::applyCl( CClient *cl )
void StacksInjured::applyCl(CClient *cl)
{
BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(battleStacksAttacked,stacks);
}
void BattleResultsApplied::applyCl( CClient *cl )
void BattleResultsApplied::applyCl(CClient *cl)
{
INTERFACE_CALL_IF_PRESENT(player1, battleResultsApplied);
INTERFACE_CALL_IF_PRESENT(player2, battleResultsApplied);
@ -728,7 +737,7 @@ void BattleResultsApplied::applyCl( CClient *cl )
}
}
void StacksHealedOrResurrected::applyCl( CClient *cl )
void StacksHealedOrResurrected::applyCl(CClient *cl)
{
std::vector<std::pair<ui32, ui32> > shiftedHealed;
for(auto & elem : healedStacks)
@ -738,63 +747,63 @@ void StacksHealedOrResurrected::applyCl( CClient *cl )
BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(battleStacksHealedRes, shiftedHealed, lifeDrain, tentHealing, drainedFrom);
}
void ObstaclesRemoved::applyCl( CClient *cl )
void ObstaclesRemoved::applyCl(CClient *cl)
{
//inform interfaces about removed obstacles
BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(battleObstaclesRemoved, obstacles);
}
void CatapultAttack::applyCl( CClient *cl )
void CatapultAttack::applyCl(CClient *cl)
{
//inform interfaces about catapult attack
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);
}
void BattleStackAdded::applyCl( CClient *cl )
void BattleStackAdded::applyCl(CClient *cl)
{
BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(battleNewStackAppeared, GS(cl)->curB->stacks.back());
}
CGameState* CPackForClient::GS( CClient *cl )
CGameState* CPackForClient::GS(CClient *cl)
{
return cl->gs;
}
void EndAction::applyCl( CClient *cl )
void EndAction::applyCl(CClient *cl)
{
BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(actionFinished, *cl->curbaction);
cl->curbaction.reset();
}
void PackageApplied::applyCl( CClient *cl )
void PackageApplied::applyCl(CClient *cl)
{
INTERFACE_CALL_IF_PRESENT(player, requestRealized, this);
if(!cl->waitingRequest.tryRemovingElement(requestID))
logNetwork->warnStream() << "Surprising server message!";
logNetwork->warnStream() << "Surprising server message!";
}
void SystemMessage::applyCl( CClient *cl )
void SystemMessage::applyCl(CClient *cl)
{
std::ostringstream str;
str << "System message: " << text;
logNetwork->errorStream() << str.str(); // usually used to receive error messages from server
if(LOCPLINT)
logNetwork->errorStream() << str.str(); // usually used to receive error messages from server
if(LOCPLINT && !settings["session"]["hideSystemMessages"].Bool())
LOCPLINT->cingconsole->print(str.str());
}
void PlayerBlocked::applyCl( CClient *cl )
void PlayerBlocked::applyCl(CClient *cl)
{
INTERFACE_CALL_IF_PRESENT(player,playerBlocked,reason, startOrEnd==BLOCKADE_STARTED);
}
void YourTurn::applyCl( CClient *cl )
void YourTurn::applyCl(CClient *cl)
{
CALL_IN_ALL_INTERFACES(playerStartsTurn, player);
CALL_ONLY_THAT_INTERFACE(player,yourTurn);
@ -802,27 +811,27 @@ void YourTurn::applyCl( CClient *cl )
void SaveGame::applyCl(CClient *cl)
{
CFileInfo info(fname);
CResourceHandler::get("local")->createResource(info.getStem() + ".vcgm1");
const auto stem = FileInfo::GetPathStem(fname);
CResourceHandler::get("local")->createResource(stem.to_string() + ".vcgm1");
try
{
CSaveFile save(*CResourceHandler::get()->getResourceName(ResourceID(info.getStem(), EResType::CLIENT_SAVEGAME)));
CSaveFile save(*CResourceHandler::get()->getResourceName(ResourceID(stem.to_string(), EResType::CLIENT_SAVEGAME)));
cl->saveCommonState(save);
save << *cl;
}
catch(std::exception &e)
{
logNetwork->errorStream() << "Failed to save game:" << e.what();
logNetwork->errorStream() << "Failed to save game:" << e.what();
}
}
void PlayerMessage::applyCl(CClient *cl)
{
std::ostringstream str;
str << "Player "<< player <<" sends a message: " << text;
logNetwork->debugStream() << "Player "<< player <<" sends a message: " << text;
logNetwork->debugStream() << str.str();
std::ostringstream str;
str << cl->getPlayer(player)->nodeName() <<": " << text;
if(LOCPLINT)
LOCPLINT->cingconsole->print(str.str());
}
@ -955,6 +964,6 @@ void TradeComponents::applyCl(CClient *cl)
case Obj::TRADING_POST_SNOW:
break;
default:
logNetwork->warnStream() << "Shop type not supported!";
logNetwork->warnStream() << "Shop type not supported!";
}
}

95
client/SDLRWwrapper.cpp Normal file
View File

@ -0,0 +1,95 @@
/*
* SDLRWwrapper.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "SDLRWwrapper.h"
#include "../lib/filesystem/CInputStream.h"
#include <SDL_rwops.h>
static inline CInputStream* get_stream(SDL_RWops* context)
{
return static_cast<CInputStream*>(context->hidden.unknown.data1);
}
static Sint64 impl_size(SDL_RWops* context)
{
return get_stream(context)->getSize();
}
static Sint64 impl_seek(SDL_RWops* context, Sint64 offset, int whence)
{
auto stream = get_stream(context);
switch (whence)
{
case RW_SEEK_SET:
return stream->seek(offset);
break;
case RW_SEEK_CUR:
return stream->seek(stream->tell() + offset);
break;
case RW_SEEK_END:
return stream->seek(stream->getSize() + offset);
break;
default:
return -1;
}
}
static std::size_t impl_read(SDL_RWops* context, void *ptr, size_t size, size_t maxnum)
{
auto stream = get_stream(context);
auto oldpos = stream->tell();
auto count = stream->read(static_cast<ui8*>(ptr), size*maxnum);
if (count != 0 && count != size*maxnum)
{
// if not a whole amount of objects of size has been read, we need to seek
stream->seek(oldpos + size * (count / size));
}
return count / size;
}
static std::size_t impl_write(SDL_RWops* context, const void *ptr, size_t size, size_t num)
{
// writing is not supported
return 0;
}
static int impl_close(SDL_RWops* context)
{
if (context == nullptr)
return 0;
delete get_stream(context);
SDL_FreeRW(context);
return 0;
}
SDL_RWops* MakeSDLRWops(std::unique_ptr<CInputStream> in)
{
SDL_RWops* result = SDL_AllocRW();
if (!result)
return nullptr;
result->size = &impl_size;
result->seek = &impl_seek;
result->read = &impl_read;
result->write = &impl_write;
result->close = &impl_close;
result->type = SDL_RWOPS_UNKNOWN;
result->hidden.unknown.data1 = in.release();
return result;
}

16
client/SDLRWwrapper.h Normal file
View File

@ -0,0 +1,16 @@
#pragma once
/*
* SDLRWwrapper.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
struct SDL_RWops;
class CInputStream;
SDL_RWops* MakeSDLRWops(std::unique_ptr<CInputStream> in);

View File

@ -6,105 +6,78 @@
<Option pch_mode="2" />
<Option compiler="gcc" />
<Build>
<Target title="Debug-win32-SDL2">
<Target title="Debug-win32">
<Option platforms="Windows;" />
<Option output="../VCMI_client" prefix_auto="1" extension_auto="1" />
<Option working_dir="../" />
<Option object_output="../obj/Debug/" />
<Option object_output="../obj/Client/Debug/x86" />
<Option type="1" />
<Option compiler="gcc" />
<Compiler>
<Add option="-Og" />
<Add option="-g" />
<Add directory="$(#sdl2.include)" />
</Compiler>
<Linker>
<Add option="-lSDL2.dll" />
<Add option="-lSDL2_image.dll" />
<Add option="-lSDL2_mixer.dll" />
<Add option="-lSDL2_ttf.dll" />
<Add directory="$(#sdl2.lib)" />
<Add directory="$(#boost.lib32)" />
<Add directory="$(#ffmpeg.lib32)" />
</Linker>
</Target>
<Target title="Release-win32-SDL2">
<Target title="Release-win32">
<Option platforms="Windows;" />
<Option output="../VCMI_client" prefix_auto="1" extension_auto="1" />
<Option working_dir="../" />
<Option object_output="../obj/Release/" />
<Option object_output="../obj/Client/Release/x86" />
<Option type="1" />
<Option compiler="gcc" />
<Compiler>
<Add option="-fomit-frame-pointer" />
<Add option="-O2" />
<Add directory="$(#sdl2.include)" />
</Compiler>
<Linker>
<Add option="-s" />
<Add option="-lSDL2.dll" />
<Add option="-lSDL2_image.dll" />
<Add option="-lSDL2_mixer.dll" />
<Add option="-lSDL2_ttf.dll" />
<Add directory="$(#sdl2.lib)" />
<Add directory="$(#boost.lib32)" />
<Add directory="$(#ffmpeg.lib32)" />
</Linker>
</Target>
<Target title="Debug-win32-SDL1">
<Target title="Debug-win64">
<Option platforms="Windows;" />
<Option output="../VCMI_client" prefix_auto="1" extension_auto="1" />
<Option working_dir="../" />
<Option object_output="../obj/Debug/" />
<Option object_output="../obj/Client/Debug/x64" />
<Option type="1" />
<Option compiler="gcc" />
<Option compiler="gnu_gcc_compiler_x64" />
<Compiler>
<Add option="-Og" />
<Add option="-g" />
<Add directory="$(#sdl.include)" />
</Compiler>
<Linker>
<Add option="-lSDL" />
<Add option="-lSDL_image" />
<Add option="-lSDL_mixer" />
<Add option="-lSDL_ttf" />
<Add directory="$(#sdl.lib)" />
</Linker>
</Target>
<Target title="Release-win32-SDL1">
<Option platforms="Windows;" />
<Option output="../VCMI_client" prefix_auto="1" extension_auto="1" />
<Option working_dir="../" />
<Option object_output="../obj/Release/" />
<Option type="1" />
<Option compiler="gcc" />
<Compiler>
<Add option="-fomit-frame-pointer" />
<Add option="-O2" />
<Add directory="$(#sdl.include)" />
</Compiler>
<Linker>
<Add option="-s" />
<Add option="-lSDL" />
<Add option="-lSDL_image" />
<Add option="-lSDL_mixer" />
<Add option="-lSDL_ttf" />
<Add directory="$(#sdl.lib)" />
<Add directory="$(#sdl2.lib64)" />
<Add directory="$(#boost.lib64)" />
<Add directory="$(#ffmpeg.lib64)" />
</Linker>
</Target>
</Build>
<Compiler>
<Add option="-Wextra" />
<Add option="-Wall" />
<Add option="-std=gnu++11" />
<Add option="-fexceptions" />
<Add option="-Wpointer-arith" />
<Add option="-Wno-switch" />
<Add option="-Wno-sign-compare" />
<Add option="-Wno-unused-parameter" />
<Add option="-Wno-overloaded-virtual" />
<Add option="-fpermissive" />
<Add option="-isystem $(#boost.include)" />
<Add option="-DBOOST_THREAD_USE_LIB" />
<Add option="-DBOOST_SYSTEM_NO_DEPRECATED" />
<Add option="-D_WIN32_WINNT=0x0501" />
<Add directory="$(#boost.include)" />
<Add directory="../include" />
<Add option="-D_WIN32" />
<Add directory="../client" />
<Add directory="$(#ffmpeg.include)" />
<Add directory="$(#sdl2.include)" />
<Add directory="../include" />
</Compiler>
<Linker>
<Add option="-lole32" />
@ -120,9 +93,11 @@
<Add option="-lavformat.dll" />
<Add option="-lswscale.dll" />
<Add option="-lavutil.dll" />
<Add directory="$(#boost.lib32)" />
<Add option="-lSDL2.dll" />
<Add option="-lSDL2_image.dll" />
<Add option="-lSDL2_mixer.dll" />
<Add option="-lSDL2_ttf.dll" />
<Add directory="../" />
<Add directory="$(#ffmpeg.lib)" />
</Linker>
<Unit filename="../CCallback.cpp" />
<Unit filename="../CCallback.h" />
@ -150,7 +125,10 @@
<Unit filename="Graphics.h" />
<Unit filename="NetPacksClient.cpp" />
<Unit filename="SDLMain.h" />
<Unit filename="SDLRWwrapper.cpp" />
<Unit filename="SDLRWwrapper.h" />
<Unit filename="StdInc.h">
<Option compile="1" />
<Option weight="0" />
</Unit>
<Unit filename="VCMI_client.rc">

View File

@ -203,6 +203,7 @@
<ClCompile Include="gui\SDL_Extensions.cpp" />
<ClCompile Include="mapHandler.cpp" />
<ClCompile Include="NetPacksClient.cpp" />
<ClCompile Include="SDLRWwrapper.cpp" />
<ClCompile Include="StdInc.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">Create</PrecompiledHeader>
</ClCompile>
@ -256,6 +257,7 @@
<ClInclude Include="mapHandler.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="SDLMain.h" />
<ClInclude Include="SDLRWwrapper.h" />
<ClInclude Include="StdInc.h" />
<ClInclude Include="widgets\AdventureMapClasses.h" />
<ClInclude Include="widgets\Buttons.h" />

View File

@ -233,8 +233,9 @@ std::string CDefenceAnimation::getMySound()
if(killed)
return battle_sound(stack->getCreature(), killed);
if (stack->valOfBonuses(Selector::durationType(Bonus::STACK_GETS_TURN)))
if (vstd::contains(stack->state, EBattleStackState::DEFENDING_ANIM))
return battle_sound(stack->getCreature(), defend);
return battle_sound(stack->getCreature(), wince);
}
@ -242,9 +243,10 @@ CCreatureAnim::EAnimType CDefenceAnimation::getMyAnimType()
{
if(killed)
return CCreatureAnim::DEATH;
if (stack->valOfBonuses(Selector::durationType(Bonus::STACK_GETS_TURN).And(Selector::typeSubtype(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE))))
if (vstd::contains(stack->state, EBattleStackState::DEFENDING_ANIM))
return CCreatureAnim::DEFENCE;
return CCreatureAnim::HITTED;
}
@ -281,7 +283,9 @@ void CDefenceAnimation::endAnim()
CDummyAnimation::CDummyAnimation(CBattleInterface * _owner, int howManyFrames)
: CBattleAnimation(_owner), counter(0), howMany(howManyFrames)
{}
{
logAnim->debugStream() << "Created dummy animation for " << howManyFrames <<" frames";
}
bool CDummyAnimation::init()
{
@ -357,7 +361,7 @@ bool CMeleeAttackAnimation::init()
group = mutPosToGroup[mutPos];
break;
default:
logGlobal->errorStream()<<"Critical Error! Wrong dest in stackAttacking! dest: "<<dest<<" attacking stack pos: "<<attackingStackPosBeforeReturn<<" mutual pos: "<<mutPos;
logGlobal->errorStream()<<"Critical Error! Wrong dest in stackAttacking! dest: "<<dest<<" attacking stack pos: "<<attackingStackPosBeforeReturn<<" mutual pos: "<<mutPos;
group = CCreatureAnim::ATTACK_FRONT;
break;
}
@ -778,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);

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,12 @@
#pragma once
//#include "../../lib/CCreatureSet.h"
#include "../../lib/ConstTransitivePtr.h" //may be reundant
#include "../../lib/GameConstants.h"
#include "CBattleAnimations.h"
#include "../../lib/spells/CSpellHandler.h" //CSpell::TAnimation
/*
* CBattleInterface.h, part of VCMI engine
*
@ -53,10 +53,10 @@ class CBattleGameInterface;
/// Small struct which contains information about the id of the attacked stack, the damage dealt,...
struct StackAttackedInfo
{
const CStack * defender; //attacked stack
const CStack *defender; //attacked stack
unsigned int dmg; //damage dealt
unsigned int amountKilled; //how many creatures in stack has been killed
const CStack * attacker; //attacking stack
const CStack *attacker; //attacking stack
bool indirectAttack; //if true, stack was attacked indirectly - spell or ranged attack
bool killed; //if true, stack has been killed
bool rebirth; //if true, play rebirth animation after all
@ -69,7 +69,7 @@ struct BattleEffect
int x, y; //position on the screen
float currentFrame;
int maxFrame;
CDefHandler * anim; //animation to display
CDefHandler *anim; //animation to display
int effectID; //uniqueID equal ot ID of appropriate CSpellEffectAnim
BattleHex position; //Indicates if effect which hex the effect is drawn on
};
@ -77,9 +77,9 @@ struct BattleEffect
struct BattleObjectsByHex
{
typedef std::vector<int> TWallList;
typedef std::vector<const CStack * > TStackList;
typedef std::vector<const CStack *> TStackList;
typedef std::vector<const BattleEffect *> TEffectList;
typedef std::vector<shared_ptr<const CObstacleInstance> > TObstacleList;
typedef std::vector<std::shared_ptr<const CObstacleInstance>> TObstacleList;
struct HexData
{
@ -114,23 +114,24 @@ class CBattleInterface : public CIntObject
INVALID = -1, CREATURE_INFO,
MOVE_TACTICS, CHOOSE_TACTICS_STACK,
MOVE_STACK, ATTACK, WALK_AND_ATTACK, ATTACK_AND_RETURN, SHOOT, //OPEN_GATE, //we can open castle gate during siege
NO_LOCATION, ANY_LOCATION, FRIENDLY_CREATURE_SPELL, HOSTILE_CREATURE_SPELL, RISING_SPELL, ANY_CREATURE, OBSTACLE, TELEPORT, SACRIFICE, RANDOM_GENIE_SPELL,
NO_LOCATION, ANY_LOCATION, OBSTACLE, TELEPORT, SACRIFICE, RANDOM_GENIE_SPELL,
FREE_LOCATION, //used with Force Field and Fire Wall - all tiles affected by spell must be free
CATAPULT, HEAL, RISE_DEMONS
CATAPULT, HEAL, RISE_DEMONS,
AIMED_SPELL_CREATURE
};
private:
SDL_Surface * background, * menu, * amountNormal, * amountNegative, * amountPositive, * amountEffNeutral, * cellBorders, * backgroundWithHexes;
CButton * bOptions, * bSurrender, * bFlee, * bAutofight, * bSpell,
* bWait, * bDefence, * bConsoleUp, * bConsoleDown, *btactNext, *btactEnd;
CBattleConsole * console;
CBattleHero * attackingHero, * defendingHero; //fighting heroes
SDL_Surface *background, *menu, *amountNormal, *amountNegative, *amountPositive, *amountEffNeutral, *cellBorders, *backgroundWithHexes;
CButton *bOptions, *bSurrender, *bFlee, *bAutofight, *bSpell,
* bWait, *bDefence, *bConsoleUp, *bConsoleDown, *btactNext, *btactEnd;
CBattleConsole *console;
CBattleHero *attackingHero, *defendingHero; //fighting heroes
CStackQueue *queue;
const CCreatureSet *army1, *army2; //copy of initial armies (for result window)
const CGHeroInstance * attackingHeroInstance, * defendingHeroInstance;
std::map< int, CCreatureAnimation * > creAnims; //animations of creatures from fighting armies (order by BattleInfo's stacks' ID)
std::map< int, CDefHandler * > idToProjectile; //projectiles of creatures (creatureID, defhandler)
std::map< int, CDefHandler * > idToObstacle; //obstacles located on the battlefield
std::map< int, SDL_Surface * > idToAbsoluteObstacle; //obstacles located on the battlefield
const CGHeroInstance *attackingHeroInstance, *defendingHeroInstance;
std::map<int, CCreatureAnimation *> creAnims; //animations of creatures from fighting armies (order by BattleInfo's stacks' ID)
std::map<int, CDefHandler *> idToProjectile; //projectiles of creatures (creatureID, defhandler)
std::map<int, CDefHandler *> idToObstacle; //obstacles located on the battlefield
std::map<int, SDL_Surface *> idToAbsoluteObstacle; //obstacles located on the battlefield
//TODO these should be loaded only when needed (and freed then) but I believe it's rather work for resource manager,
//so I didn't implement that (having ongoing RM development)
@ -139,28 +140,27 @@ private:
CDefHandler *fireWall;
CDefHandler *smallForceField[2], *bigForceField[2]; // [side]
std::map< int, bool > creDir; // <creatureID, if false reverse creature's animation> //TODO: move it to battle callback
std::map<int, bool> creDir; // <creatureID, if false reverse creature's animation> //TODO: move it to battle callback
ui8 animCount;
const CStack * activeStack; //number of active stack; nullptr - no one
const CStack * mouseHoveredStack; // stack below mouse pointer, used for border animation
const CStack * stackToActivate; //when animation is playing, we should wait till the end to make the next stack active; nullptr of none
const CStack * selectedStack; //for Teleport / Sacrifice
const CStack *activeStack; //number of active stack; nullptr - no one
const CStack *mouseHoveredStack; // stack below mouse pointer, used for border animation
const CStack *stackToActivate; //when animation is playing, we should wait till the end to make the next stack active; nullptr of none
const CStack *selectedStack; //for Teleport / Sacrifice
void activateStack(); //sets activeStack to stackToActivate etc. //FIXME: No, it's not clear at all
std::vector<BattleHex> occupyableHexes, //hexes available for active stack
attackableHexes; //hexes attackable by active stack
bool stackCountOutsideHexes[GameConstants::BFIELD_SIZE]; // hexes that when in front of a unit cause it's amount box to move back
bool stackCountOutsideHexes[GameConstants::BFIELD_SIZE]; // hexes that when in front of a unit cause it's amount box to move back
BattleHex previouslyHoveredHex; //number of hex that was hovered by the cursor a while ago
BattleHex currentlyHoveredHex; //number of hex that is supposed to be hovered (for a while it may be inappropriately set, but will be renewed soon)
int attackingHex; //hex from which the stack would perform attack with current cursor
shared_ptr<CPlayerInterface> tacticianInterface; //used during tactics mode, points to the interface of player with higher tactics (can be either attacker or defender in hot-seat), valid onloy for human players
std::shared_ptr<CPlayerInterface> tacticianInterface; //used during tactics mode, points to the interface of player with higher tactics (can be either attacker or defender in hot-seat), valid onloy for human players
bool tacticsMode;
bool stackCanCastSpell; //if true, active stack could possibly cats some target spell
bool stackCanCastSpell; //if true, active stack could possibly cast some target spell
bool creatureCasting; //if true, stack currently aims to cats a spell
bool spellDestSelectMode; //if true, player is choosing destination for his spell - only for GUI / console
PossibleActions spellSelMode;
BattleAction * spellToCast; //spell for which player is choosing destination
const CSpell * sp; //spell pointer for convenience
BattleAction *spellToCast; //spell for which player is choosing destination
const CSpell *sp; //spell pointer for convenience
si32 creatureSpellToCast;
std::vector<PossibleActions> possibleActions; //all actions possible to call at the moment by player
std::vector<PossibleActions> localActions; //actions possible to take on hovered hex
@ -169,15 +169,18 @@ private:
PossibleActions selectedAction; //last action chosen (and saved) by player
PossibleActions illegalAction; //most likely action that can't be performed here
void setActiveStack(const CStack * stack);
void setHoveredStack(const CStack * stack);
void setActiveStack(const CStack *stack);
void setHoveredStack(const CStack *stack);
void requestAutofightingAIToTakeAction();
void getPossibleActionsForStack (const CStack * stack); //called when stack gets its turn
void getPossibleActionsForStack (const CStack *stack, const bool forceCast); //called when stack gets its turn
void endCastingSpell(); //ends casting spell (eg. when spell has been cast or canceled)
void printConsoleAttacked(const CStack * defender, int dmg, int killed, const CStack * attacker, bool Multiple);
//force active stack to cast a spell if possible
void enterCreatureCastingMode();
void printConsoleAttacked(const CStack *defender, int dmg, int killed, const CStack *attacker, bool Multiple);
std::list<ProjectileInfo> projectiles; //projectiles flying on battlefield
void giveCommand(Battle::ActionType action, BattleHex tile, ui32 stackID, si32 additional=-1, si32 selectedStack = -1);
@ -191,66 +194,83 @@ private:
{
private:
SDL_Surface* walls[18];
const CBattleInterface * owner;
const CBattleInterface *owner;
public:
const CGTownInstance * town; //besieged town
SiegeHelper(const CGTownInstance * siegeTown, const CBattleInterface * _owner); //c-tor
const CGTownInstance *town; //besieged town
SiegeHelper(const CGTownInstance *siegeTown, const CBattleInterface *_owner); //c-tor
~SiegeHelper(); //d-tor
//filename getters
//what: 0 - background, 1 - background wall, 2 - keep, 3 - bottom tower, 4 - bottom wall,
// 5 - below gate, 6 - over gate, 7 - upper wall, 8 - upper tower, 9 - gate,
// 10 - gate arch, 11 - bottom static 12 - upper static, 13 - moat, 14 - moat background,
// 15 - keep battlement, 16 - bottom battlement, 17 - upper battlement;
// state uses EWallState enum
std::string getSiegeName(ui16 what) const;
std::string getSiegeName(ui16 what, int state) const;
std::string getSiegeName(ui16 what, int state) const; // state uses EWallState enum
void printPartOfWall(SDL_Surface * to, int what);//what: 1 - background wall, 2 - keep, 3 - bottom tower, 4 - bottom wall, 5 - below gate, 6 - over gate, 7 - upper wall, 8 - uppert tower, 9 - gate, 10 - gate arch, 11 - bottom static wall, 12 - upper static wall, 15 - keep creature cover, 16 - bottom turret creature cover, 17 - upper turret creature cover
void printPartOfWall(SDL_Surface *to, int what);
enum EWallVisual
{
BACKGROUND = 0,
BACKGROUND_WALL = 1,
KEEP,
BOTTOM_TOWER,
BOTTOM_WALL,
WALL_BELLOW_GATE,
WALL_OVER_GATE,
UPPER_WALL,
UPPER_TOWER,
GATE,
GATE_ARCH,
BOTTOM_STATIC_WALL,
UPPER_STATIC_WALL,
MOAT,
BACKGROUND_MOAT,
KEEP_BATTLEMENT,
BOTTOM_BATTLEMENT,
UPPER_BATTLEMENT
};
friend class CBattleInterface;
} * siegeH;
} *siegeH;
shared_ptr<CPlayerInterface> attackerInt, defenderInt; //because LOCPLINT is not enough in hotSeat
shared_ptr<CPlayerInterface> curInt; //current player interface
const CGHeroInstance * getActiveHero(); //returns hero that can currently cast a spell
std::shared_ptr<CPlayerInterface> attackerInt, defenderInt; //because LOCPLINT is not enough in hotSeat
std::shared_ptr<CPlayerInterface> curInt; //current player interface
const CGHeroInstance *getActiveHero(); //returns hero that can currently cast a spell
/** Methods for displaying battle screen */
void showBackground(SDL_Surface * to);
void showBackground(SDL_Surface *to);
void showBackgroundImage(SDL_Surface * to);
void showAbsoluteObstacles(SDL_Surface * to);
void showHighlightedHexes(SDL_Surface * to);
void showHighlightedHex(SDL_Surface * to, BattleHex hex);
void showInterface(SDL_Surface * to);
void showBackgroundImage(SDL_Surface *to);
void showAbsoluteObstacles(SDL_Surface *to);
void showHighlightedHexes(SDL_Surface *to);
void showHighlightedHex(SDL_Surface *to, BattleHex hex);
void showInterface(SDL_Surface *to);
void showBattlefieldObjects(SDL_Surface * to);
void showBattlefieldObjects(SDL_Surface *to);
void showAliveStacks(SDL_Surface * to, std::vector<const CStack *> stacks);
void showStacks(SDL_Surface * to, std::vector<const CStack *> stacks);
void showObstacles(SDL_Surface *to, std::vector<shared_ptr<const CObstacleInstance> > &obstacles);
void showPiecesOfWall(SDL_Surface * to, std::vector<int> pieces);
void showAliveStacks(SDL_Surface *to, std::vector<const CStack *> stacks);
void showStacks(SDL_Surface *to, std::vector<const CStack *> stacks);
void showObstacles(SDL_Surface *to, std::vector<std::shared_ptr<const CObstacleInstance>> &obstacles);
void showPiecesOfWall(SDL_Surface *to, std::vector<int> pieces);
void showBattleEffects(SDL_Surface *to, const std::vector<const BattleEffect *> &battleEffects);
void showProjectiles(SDL_Surface * to);
void showProjectiles(SDL_Surface *to);
BattleObjectsByHex sortObjectsByHex();
void updateBattleAnimations();
SDL_Surface *getObstacleImage(const CObstacleInstance &oi);
Point getObstaclePosition(SDL_Surface *image, const CObstacleInstance &obstacle);
void redrawBackgroundWithHexes(const CStack * activeStack);
void redrawBackgroundWithHexes(const CStack *activeStack);
/** End of battle screen blitting methods */
PossibleActions getCasterAction(const CSpell *spell, const ISpellCaster *caster, ECastingMode::ECastingMode mode) const;
public:
std::list<std::pair<CBattleAnimation *, bool> > pendingAnims; //currently displayed animations <anim, initialized>
void addNewAnim(CBattleAnimation * anim); //adds new anim to pendingAnims
std::list<std::pair<CBattleAnimation *, bool>> pendingAnims; //currently displayed animations <anim, initialized>
void addNewAnim(CBattleAnimation *anim); //adds new anim to pendingAnims
ui32 animIDhelper; //for giving IDs for animations
static CondSh<bool> animsAreDisplayed; //for waiting with the end of battle for end of anims
CBattleInterface(const CCreatureSet * army1, const CCreatureSet * army2, const CGHeroInstance *hero1, const CGHeroInstance *hero2, const SDL_Rect & myRect, shared_ptr<CPlayerInterface> att, shared_ptr<CPlayerInterface> defen); //c-tor
~CBattleInterface(); //d-tor
CBattleInterface(const CCreatureSet *army1, const CCreatureSet *army2, const CGHeroInstance *hero1, const CGHeroInstance *hero2, const SDL_Rect & myRect, std::shared_ptr<CPlayerInterface> att, std::shared_ptr<CPlayerInterface> defen); //c-tor
virtual ~CBattleInterface(); //d-tor
//std::vector<TimeInterested*> timeinterested; //animation handling
void setPrintCellBorders(bool set); //if true, cell borders will be printed
@ -258,18 +278,18 @@ public:
void setPrintMouseShadow(bool set); //if true, hex under mouse will be shaded
void setAnimSpeed(int set); //speed of animation; range 1..100
int getAnimSpeed() const; //speed of animation; range 1..100
CPlayerInterface * getCurrentPlayerInterface() const;
CPlayerInterface *getCurrentPlayerInterface() const;
std::vector<CClickableHex*> bfield; //11 lines, 17 hexes on each
SDL_Surface * cellBorder, * cellShade;
SDL_Surface *cellBorder, *cellShade;
CondSh<BattleAction *> *givenCommand; //data != nullptr if we have i.e. moved current unit
bool myTurn; //if true, interface is active (commands can be ordered)
CBattleResultWindow * resWindow; //window of end of battle
CBattleResultWindow *resWindow; //window of end of battle
bool moveStarted; //if true, the creature that is already moving is going to make its first step
int moveSoundHander; // sound handler used when moving a unit
const BattleResult * bresult; //result of a battle; if non-zero then display when all animations end
const BattleResult *bresult; //result of a battle; if non-zero then display when all animations end
// block all UI elements, e.g. during enemy turn
// unlike activate/deactivate this method will correctly grey-out all elements
@ -291,59 +311,65 @@ 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);
void newStack(const CStack * stack); //new stack appeared on battlefield
void newStack(const CStack *stack); //new stack appeared on battlefield
void stackRemoved(int stackID); //stack disappeared from batlefiled
void stackActivated(const CStack * stack); //active stack has been changed
void stackMoved(const CStack * stack, std::vector<BattleHex> destHex, int distance); //stack with id number moved to destHex
void stackActivated(const CStack *stack); //active stack has been changed
void stackMoved(const CStack *stack, std::vector<BattleHex> destHex, int distance); //stack with id number moved to destHex
void waitForAnims();
void stacksAreAttacked(std::vector<StackAttackedInfo> attackedInfos); //called when a certain amount of stacks has been attacked
void stackAttacking(const CStack * attacker, BattleHex dest, const CStack * attacked, bool shooting); //called when stack with id ID is attacking something on hex dest
void stackAttacking(const CStack *attacker, BattleHex dest, const CStack *attacked, bool shooting); //called when stack with id ID is attacking something on hex dest
void newRoundFirst( int round );
void newRound(int number); //caled when round is ended; number is the number of round
void hexLclicked(int whichOne); //hex only call-in
void stackIsCatapulting(const CatapultAttack & ca); //called when a stack is attacking walls
void battleFinished(const BattleResult& br); //called when battle is finished - battleresult window should be printed
void displayBattleFinished(); //displays battle result
void spellCast(const BattleSpellCast * sc); //called when a hero casts a spell
void spellCast(const BattleSpellCast *sc); //called when a hero casts a spell
void battleStacksEffectsSet(const SetStackEffect & sse); //called when a specific effect is set to stacks
void castThisSpell(SpellID spellID); //called when player has chosen a spell from spellbook
void displayEffect(ui32 effect, int destTile, bool areaEffect = true); //displays custom effect on the battlefield
void displaySpellEffect(SpellID spellID, BattleHex destinationTile, bool areaEffect = true); //displays spell`s affected animation
void displaySpellHit(SpellID spellID, BattleHex destinationTile, bool areaEffect = true); //displays spell`s affected animation
void displayEffect(ui32 effect, int destTile); //displays custom effect on the battlefield
void displaySpellCast(SpellID spellID, BattleHex destinationTile); //displays spell`s cast animation
void displaySpellEffect(SpellID spellID, BattleHex destinationTile); //displays spell`s affected animation
void displaySpellHit(SpellID spellID, BattleHex destinationTile); //displays spell`s affected animation
void displaySpellAnimation(const CSpell::TAnimation & animation, BattleHex destinationTile);
void battleTriggerEffect(const BattleTriggerEffect & bte);
void setBattleCursor(const int myNumber); //really complex and messy, sets attackingHex
void endAction(const BattleAction* action);
void hideQueue();
void showQueue();
PossibleActions selectionTypeByPositiveness(const CSpell & spell);
Rect hexPosition(BattleHex hex) const;
void handleHex(BattleHex myNumber, int eventType);
bool isCastingPossibleHere (const CStack * sactive, const CStack * shere, BattleHex myNumber);
bool canStackMoveHere (const CStack * sactive, BattleHex MyNumber); //TODO: move to BattleState / callback
bool isCastingPossibleHere (const CStack *sactive, const CStack *shere, BattleHex myNumber);
bool canStackMoveHere (const CStack *sactive, BattleHex MyNumber); //TODO: move to BattleState / callback
BattleHex fromWhichHexAttack(BattleHex myNumber);
void obstaclePlaced(const CObstacleInstance & oi);
const CGHeroInstance * currentHero() const;
void gateStateChanged(const EGateState state);
const CGHeroInstance *currentHero() const;
InfoAboutHero enemyHero() const;
friend class CPlayerInterface;
friend class CButton;
friend class CInGameConsole;
friend class CBattleResultWindow;
friend class CBattleHero;
friend class CSpellEffectAnimation;

View File

@ -29,6 +29,7 @@
#include "../../lib/NetPacks.h"
#include "../../lib/StartInfo.h"
#include "../../lib/CondSh.h"
#include "../../lib/mapObjects/CGTownInstance.h"
/*
* CBattleInterfaceClasses.cpp, part of VCMI engine
@ -69,6 +70,7 @@ void CBattleConsole::showAll(SDL_Surface * to)
bool CBattleConsole::addText(const std::string & text)
{
logGlobal->traceStream() <<"CBattleConsole message: "<<text;
if(text.size()>70)
return false; //text too long!
int firstInToken = 0;
@ -175,6 +177,15 @@ void CBattleHero::setPhase(int newPhase)
nextPhase = 0;
}
void CBattleHero::hover(bool on)
{
//TODO: Make lines below work properly
if (on)
CCS->curh->changeGraphic(ECursor::COMBAT, 5);
else
CCS->curh->changeGraphic(ECursor::COMBAT, 0);
}
void CBattleHero::clickLeft(tribool down, bool previousState)
{
if(myOwner->spellDestSelectMode) //we are casting a spell
@ -189,8 +200,26 @@ void CBattleHero::clickLeft(tribool down, bool previousState)
}
CCS->curh->changeGraphic(ECursor::ADVENTURE, 0);
auto spellWindow = new CSpellWindow(genRect(595, 620, (screen->w - 620)/2, (screen->h - 595)/2), myHero, myOwner->getCurrentPlayerInterface());
GH.pushInt(spellWindow);
GH.pushInt(new CSpellWindow(myHero, myOwner->getCurrentPlayerInterface()));
}
}
void CBattleHero::clickRight(tribool down, bool previousState)
{
Point windowPosition;
windowPosition.x = (!flip) ? myOwner->pos.topLeft().x + 1 : myOwner->pos.topRight().x - 79;
windowPosition.y = myOwner->pos.y + 135;
InfoAboutHero targetHero;
if (down && myOwner->myTurn)
{
if (myHero != nullptr)
targetHero.initFromHero(myHero, InfoAboutHero::EInfoLevel::INBATTLE);
else
targetHero = myOwner->enemyHero();
GH.pushInt(new CHeroInfoWindow(targetHero, &windowPosition));
}
}
@ -245,7 +274,7 @@ CBattleHero::CBattleHero(const std::string & defName, bool flipG, PlayerColor pl
CSDL_Ext::alphaTransform(elem.bitmap);
graphics->blueToPlayersAdv(elem.bitmap, player);
}
addUsedEvents(LCLICK);
addUsedEvents(LCLICK | RCLICK | HOVER);
switchToNextPhase();
}
@ -350,7 +379,7 @@ CBattleResultWindow::CBattleResultWindow(const BattleResult &br, const SDL_Rect
auto heroInfo = owner.cb->battleGetHeroInfo(i);
const int xs[] = {21, 392};
if(heroInfo.portrait >= 0) //attacking hero
if(heroInfo.portrait >= 0) //attacking hero
{
new CAnimImage("PortraitsLarge", heroInfo.portrait, 0, xs[i], 38);
sideNames[i] = heroInfo.name;
@ -418,7 +447,7 @@ CBattleResultWindow::CBattleResultWindow(const BattleResult &br, const SDL_Rect
boost::algorithm::replace_first(str,"%s",ourHero->name);
boost::algorithm::replace_first(str,"%d",boost::lexical_cast<std::string>(br.exp[weAreAttacker?0:1]));
}
new CTextBox(str, Rect(69, 203, 330, 68), 0, FONT_SMALL, CENTER, Colors::WHITE);
}
else // we lose
@ -479,7 +508,7 @@ void CBattleResultWindow::bExitf()
if(dynamic_cast<CBattleInterface*>(GH.topInt()))
GH.popInts(1); //pop battle interface if present
//Result window and battle interface are gone. We requested all dialogs to be closed before opening the battle,
//Result window and battle interface are gone. We requested all dialogs to be closed before opening the battle,
//so we can be sure that there is no dialogs left on GUI stack.
intTmp.showingDialog->setn(false);
CCS->videoh->close();
@ -502,7 +531,7 @@ Point CClickableHex::getXYUnitAnim(BattleHex hexNum, const CStack * stack, CBatt
break;
case -4: //upper turret
ret = cbi->siegeH->town->town->clientInfo.siegePositions[20];
break;
break;
}
}
else
@ -612,6 +641,47 @@ void CClickableHex::clickRight(tribool down, bool previousState)
}
}
CHeroInfoWindow::CHeroInfoWindow(const InfoAboutHero &hero, Point *position) : CWindowObject(RCLICK_POPUP | SHADOW_DISABLED, "CHRPOP")
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
if (position != nullptr)
moveTo(*position);
background->colorize(hero.owner); //maybe add this functionality to base class?
int attack = hero.details->primskills[0];
int defense = hero.details->primskills[1];
int power = hero.details->primskills[2];
int knowledge = hero.details->primskills[3];
int morale = hero.details->morale;
int luck = hero.details->luck;
int currentSpellPoints = hero.details->mana;
int maxSpellPoints = hero.details->manaLimit;
new CAnimImage("PortraitsLarge", hero.portrait, 0, 10, 6);
//primary stats
new CLabel(9, 75, EFonts::FONT_TINY, EAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[380] + ":");
new CLabel(9, 87, EFonts::FONT_TINY, EAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[381] + ":");
new CLabel(9, 99, EFonts::FONT_TINY, EAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[382] + ":");
new CLabel(9, 111, EFonts::FONT_TINY, EAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[383] + ":");
new CLabel(69, 87, EFonts::FONT_TINY, EAlignment::BOTTOMRIGHT, Colors::WHITE, std::to_string(attack));
new CLabel(69, 99, EFonts::FONT_TINY, EAlignment::BOTTOMRIGHT, Colors::WHITE, std::to_string(defense));
new CLabel(69, 111, EFonts::FONT_TINY, EAlignment::BOTTOMRIGHT, Colors::WHITE, std::to_string(power));
new CLabel(69, 123, EFonts::FONT_TINY, EAlignment::BOTTOMRIGHT, Colors::WHITE, std::to_string(knowledge));
//morale+luck
new CLabel(9, 131, EFonts::FONT_TINY, EAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[384] + ":");
new CLabel(9, 143, EFonts::FONT_TINY, EAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[385] + ":");
new CAnimImage("IMRL22", morale + 3, 0, 47, 131);
new CAnimImage("ILCK22", luck + 3, 0, 47, 143);
//spell points
new CLabel(39, 174, EFonts::FONT_TINY, EAlignment::CENTER, Colors::WHITE, CGI->generaltexth->allTexts[387]);
new CLabel(39, 186, EFonts::FONT_TINY, EAlignment::CENTER, Colors::WHITE, std::to_string(currentSpellPoints) + "/" + std::to_string(maxSpellPoints));
}
void CStackQueue::update()
{
stacksSorted.clear();

View File

@ -2,6 +2,7 @@
#include "../gui/CIntObject.h"
#include "../../lib/BattleHex.h"
#include "../windows/CWindowObject.h"
struct SDL_Surface;
class CDefHandler;
@ -38,7 +39,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,13 +61,21 @@ 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 hover(bool on) override;
void clickLeft(tribool down, bool previousState) override; //call-in
void clickRight(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
};
class CHeroInfoWindow : public CWindowObject
{
public:
CHeroInfoWindow(const InfoAboutHero &hero, Point *position);
};
/// Class which manages the battle options window
class CBattleOptionsWindow : public CIntObject
{
@ -96,8 +105,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 +123,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 +141,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 +159,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

@ -8,7 +8,6 @@
#include "../../lib/filesystem/CBinaryReader.h"
#include "../../lib/filesystem/CMemoryStream.h"
#include "../gui/SDL_Extensions.h"
#include "../gui/SDL_Pixels.h"
/*
@ -164,7 +163,9 @@ CCreatureAnimation::CCreatureAnimation(std::string name, TSpeedController contro
pixelDataSize = data.second;
}
CBinaryReader reader(new CMemoryStream(pixelData.get(), pixelDataSize));
CMemoryStream stm(pixelData.get(), pixelDataSize);
CBinaryReader reader(&stm);
reader.readInt32(); // def type, unused
@ -178,7 +179,7 @@ CCreatureAnimation::CCreatureAnimation(std::string name, TSpeedController contro
elem.r = reader.readUInt8();
elem.g = reader.readUInt8();
elem.b = reader.readUInt8();
CSDL_Ext::colorSetAlpha(elem,0);
elem.a = SDL_ALPHA_OPAQUE;
}
for (int i=0; i<totalBlocks; i++)
@ -267,11 +268,7 @@ static SDL_Color genShadow(ui8 alpha)
static SDL_Color genBorderColor(ui8 alpha, const SDL_Color & base)
{
#ifdef VCMI_SDL1
return CSDL_Ext::makeColor(base.r, base.g, base.b, ui8(base.unused * alpha / 256));
#else
return CSDL_Ext::makeColor(base.r, base.g, base.b, ui8(base.a * alpha / 256));
#endif
}
static ui8 mixChannels(ui8 c1, ui8 c2, ui8 a1, ui8 a2)
@ -281,22 +278,12 @@ static ui8 mixChannels(ui8 c1, ui8 c2, ui8 a1, ui8 a2)
static SDL_Color addColors(const SDL_Color & base, const SDL_Color & over)
{
#ifdef VCMI_SDL1
return CSDL_Ext::makeColor(
mixChannels(over.r, base.r, over.unused, base.unused),
mixChannels(over.g, base.g, over.unused, base.unused),
mixChannels(over.b, base.b, over.unused, base.unused),
ui8(over.unused + base.unused * (255 - over.unused) / 256)
);
#else
return CSDL_Ext::makeColor(
mixChannels(over.r, base.r, over.a, base.a),
mixChannels(over.g, base.g, over.a, base.a),
mixChannels(over.b, base.b, over.a, base.a),
ui8(over.a + base.a * (255 - over.a) / 256)
);
#endif // VCMI_SDL1
}
std::array<SDL_Color, 8> CCreatureAnimation::genSpecialPalette()
@ -322,7 +309,9 @@ void CCreatureAnimation::nextFrameT(SDL_Surface * dest, bool rotate)
ui32 offset = dataOffsets.at(type).at(floor(currentFrame));
CBinaryReader reader(new CMemoryStream(pixelData.get(), pixelDataSize));
CMemoryStream stm(pixelData.get(), pixelDataSize);
CBinaryReader reader(&stm);
reader.getStream()->seek(offset);
@ -397,7 +386,7 @@ void CCreatureAnimation::nextFrame(SDL_Surface *dest, bool attacker)
case 3: return nextFrameT<3>(dest, !attacker);
case 4: return nextFrameT<4>(dest, !attacker);
default:
logGlobal->errorStream() << (int)dest->format->BitsPerPixel << " bpp is not supported!!!";
logGlobal->errorStream() << (int)dest->format->BitsPerPixel << " bpp is not supported!!!";
}
}
@ -427,11 +416,7 @@ inline void CCreatureAnimation::putPixel(ui8 * dest, const SDL_Color & color, si
if (index < 8)
{
const SDL_Color & pal = special[index];
#ifdef VCMI_SDL1
ColorPutter<bpp, 0>::PutColor(dest, pal.r, pal.g, pal.b, pal.unused);
#else
ColorPutter<bpp, 0>::PutColor(dest, pal.r, pal.g, pal.b, pal.a);
#endif // 0
}
else
{

View File

@ -66,7 +66,7 @@ private:
//animation raw data
//TODO: use vector instead?
unique_ptr<ui8[]> pixelData;
std::unique_ptr<ui8[]> pixelData;
size_t pixelDataSize;
// speed of animation, measure in frames per second

View File

@ -51,11 +51,11 @@ class CompImageLoader
ui8 *position;
ui8 *entry;
ui32 currentLine;
inline ui8 typeOf(ui8 color);
inline void NewEntry(ui8 color, size_t size);
inline void NewEntry(const ui8 * &data, size_t size);
public:
//load size raw pixels from data
inline void Load(size_t size, const ui8 * data);
@ -75,29 +75,26 @@ class CFileCache
static const int cacheSize = 50; //Max number of cached files
struct FileData
{
ResourceID name;
size_t size;
ui8 * data;
ResourceID name;
size_t size;
std::unique_ptr<ui8[]> data;
ui8 * getCopy()
std::unique_ptr<ui8[]> getCopy()
{
auto ret = new ui8[size];
std::copy(data, data + size, ret);
auto ret = std::unique_ptr<ui8[]>(new ui8[size]);
std::copy(data.get(), data.get() + size, ret.get());
return ret;
}
FileData():
size(0),
data(nullptr)
FileData(ResourceID name_, size_t size_, std::unique_ptr<ui8[]> data_):
name{std::move(name_)},
size{size_},
data{std::move(data_)}
{}
~FileData()
{
delete [] data;
}
};
std::list<FileData> cache;
std::deque<FileData> cache;
public:
ui8 * getCachedFile(ResourceID && rid)
std::unique_ptr<ui8[]> getCachedFile(ResourceID rid)
{
for(auto & file : cache)
{
@ -107,12 +104,10 @@ public:
// Still here? Cache miss
if (cache.size() > cacheSize)
cache.pop_front();
cache.push_back(FileData());
auto data = CResourceHandler::get()->load(rid)->readAll();
cache.back().name = ResourceID(rid);
cache.back().size = data.second;
cache.back().data = data.first.release();
cache.emplace_back(std::move(rid), data.second, std::move(data.first));
return cache.back().getCopy();
}
@ -132,8 +127,8 @@ CDefFile::CDefFile(std::string Name):
static SDL_Color H3Palette[8] =
{
{ 0, 0, 0, 0},// 100% - transparency
{ 0, 0, 0, 64},// 75% - shadow border,
{ 0, 0, 0, 128},// TODO: find exact value
{ 0, 0, 0, 32},// 75% - shadow border,
{ 0, 0, 0, 64},// TODO: find exact value
{ 0, 0, 0, 128},// TODO: for transparency
{ 0, 0, 0, 128},// 50% - shadow body
{ 0, 0, 0, 0},// 100% - selection highlight
@ -142,15 +137,15 @@ CDefFile::CDefFile(std::string Name):
};
data = animationCache.getCachedFile(ResourceID(std::string("SPRITES/") + Name, EResType::ANIMATION));
palette = new SDL_Color[256];
palette = std::unique_ptr<SDL_Color[]>(new SDL_Color[256]);
int it = 0;
ui32 type = read_le_u32(data + it);
ui32 type = read_le_u32(data.get() + it);
it+=4;
//int width = read_le_u32(data + it); it+=4;//not used
//int height = read_le_u32(data + it); it+=4;
it+=8;
ui32 totalBlocks = read_le_u32(data + it);
ui32 totalBlocks = read_le_u32(data.get() + it);
it+=4;
for (ui32 i= 0; i<256; i++)
@ -158,18 +153,18 @@ CDefFile::CDefFile(std::string Name):
palette[i].r = data[it++];
palette[i].g = data[it++];
palette[i].b = data[it++];
CSDL_Ext::colorSetAlpha(palette[i],255);
palette[i].a = SDL_ALPHA_OPAQUE;
}
if (type == 71 || type == 64)//Buttons/buildings don't have shadows\semi-transparency
memset(palette, 0, sizeof(SDL_Color)*2);
memset(palette.get(), 0, sizeof(SDL_Color)*2);
else
memcpy(palette, H3Palette, sizeof(SDL_Color)*8);//initialize shadow\selection colors
memcpy(palette.get(), H3Palette, sizeof(SDL_Color)*8);//initialize shadow\selection colors
for (ui32 i=0; i<totalBlocks; i++)
{
size_t blockID = read_le_u32(data + it);
size_t blockID = read_le_u32(data.get() + it);
it+=4;
size_t totalEntries = read_le_u32(data + it);
size_t totalEntries = read_le_u32(data.get() + it);
it+=12;
//8 unknown bytes - skipping
@ -178,7 +173,7 @@ CDefFile::CDefFile(std::string Name):
for (ui32 j=0; j<totalEntries; j++)
{
size_t currOffset = read_le_u32(data + it);
size_t currOffset = read_le_u32(data.get() + it);
offset[blockID].push_back(currOffset);
it += 4;
}
@ -192,7 +187,7 @@ void CDefFile::loadFrame(size_t frame, size_t group, ImageLoader &loader) const
it = offset.find(group);
assert (it != offset.end());
const ui8 * FDef = data+it->second[frame];
const ui8 * FDef = data.get()+it->second[frame];
const SSpriteDef sd = * reinterpret_cast<const SSpriteDef *>(FDef);
SSpriteDef sprite;
@ -210,7 +205,7 @@ void CDefFile::loadFrame(size_t frame, size_t group, ImageLoader &loader) const
loader.init(Point(sprite.width, sprite.height),
Point(sprite.leftMargin, sprite.topMargin),
Point(sprite.fullWidth, sprite.fullHeight), palette);
Point(sprite.fullWidth, sprite.fullHeight), palette.get());
switch (sprite.format)
{
@ -274,7 +269,7 @@ void CDefFile::loadFrame(size_t frame, size_t group, ImageLoader &loader) const
if (code==7)//Raw data
{
loader.Load(length, FDef[currentOffset]);
loader.Load(length, FDef + currentOffset);
currentOffset += length;
}
else//RLE
@ -316,16 +311,12 @@ void CDefFile::loadFrame(size_t frame, size_t group, ImageLoader &loader) const
break;
}
default:
logGlobal->errorStream()<<"Error: unsupported format of def file: "<<sprite.format;
logGlobal->errorStream()<<"Error: unsupported format of def file: "<<sprite.format;
break;
}
};
CDefFile::~CDefFile()
{
delete[] data;
delete[] palette;
}
CDefFile::~CDefFile() = default;
const std::map<size_t, size_t > CDefFile::getEntries() const
{
@ -355,7 +346,11 @@ void SDLImageLoader::init(Point SpriteSize, Point Margins, Point FullSize, SDL_C
image->fullSize = FullSize;
//Prepare surface
SDL_SetColors(image->surf, pal, 0, 256);
SDL_Palette * p = SDL_AllocPalette(256);
SDL_SetPaletteColors(p, pal, 0, 256);
SDL_SetSurfacePalette(image->surf, p);
SDL_FreePalette(p);
SDL_LockSurface(image->surf);
lineStart = position = (ui8*)image->surf->pixels;
}
@ -387,19 +382,19 @@ inline void SDLImageLoader::EndLine()
SDLImageLoader::~SDLImageLoader()
{
SDL_UnlockSurface(image->surf);
SDL_SetColorKey(image->surf, SDL_SRCCOLORKEY, 0);
SDL_SetColorKey(image->surf, SDL_TRUE, 0);
//TODO: RLE if compressed and bpp>1
}
////////////////////////////////////////////////////////////////////////////////
CompImageLoader::CompImageLoader(CompImage * Img):
image(Img),
position(nullptr),
entry(nullptr),
currentLine(0)
{
}
void CompImageLoader::init(Point SpriteSize, Point Margins, Point FullSize, SDL_Color *pal)
@ -444,14 +439,10 @@ inline ui8 CompImageLoader::typeOf(ui8 color)
{
if (color == 0)
return 0;
#ifdef VCMI_SDL1
if (image->palette[color].unused != 255)
return 1;
#else
if (image->palette[color].a != 255)
return 1;
#endif // 0
return 2;
}
@ -489,7 +480,7 @@ inline void CompImageLoader::Load(size_t size, const ui8 * data)
ui8 type = typeOf(color);
ui8 color2;
ui8 type2;
if (size > 1)
{
do
@ -616,7 +607,7 @@ SDLImage::SDLImage(std::string filename, bool compressed):
if (surf == nullptr)
{
logGlobal->errorStream() << "Error: failed to load image "<<filename;
logGlobal->errorStream() << "Error: failed to load image "<<filename;
return;
}
else
@ -628,22 +619,11 @@ SDLImage::SDLImage(std::string filename, bool compressed):
{
SDL_Surface *temp = surf;
// add RLE flag
#ifdef VCMI_SDL1
if (surf->format->palette)
{
const SDL_Color &c = temp->format->palette->colors[0];
SDL_SetColorKey(temp, (SDL_SRCCOLORKEY | SDL_RLEACCEL),
SDL_MapRGB(temp -> format, c.r, c.g, c.b));
}
else
SDL_SetColorKey(temp, SDL_RLEACCEL, 0);
#else
if (surf->format->palette)
{
CSDL_Ext::setColorKey(temp,temp->format->palette->colors[0]);
}
SDL_SetSurfaceRLE(temp, SDL_RLEACCEL);
#endif
SDL_SetSurfaceRLE(temp, SDL_RLEACCEL);
// convert surface to enable RLE
surf = SDL_ConvertSurface(temp, temp->format, temp->flags);
@ -651,10 +631,11 @@ SDLImage::SDLImage(std::string filename, bool compressed):
}
}
void SDLImage::draw(SDL_Surface *where, int posX, int posY, Rect *src, ui8 rotation) const
void SDLImage::draw(SDL_Surface *where, int posX, int posY, Rect *src, ui8 alpha) const
{
if (!surf)
return;
Rect sourceRect(margins.x, margins.y, surf->w, surf->h);
//TODO: rotation and scaling
if (src)
@ -664,7 +645,21 @@ void SDLImage::draw(SDL_Surface *where, int posX, int posY, Rect *src, ui8 rotat
Rect destRect(posX, posY, surf->w, surf->h);
destRect += sourceRect.topLeft();
sourceRect -= margins;
CSDL_Ext::blitSurface(surf, &sourceRect, where, &destRect);
if(surf->format->BitsPerPixel == 8)
{
CSDL_Ext::blit8bppAlphaTo24bpp(surf, &sourceRect, where, &destRect);
}
else if(surf->format->Amask == 0)
{
SDL_BlitSurface(surf, &sourceRect, where, &destRect);
}
else
{
SDL_SetSurfaceBlendMode(surf, SDL_BLENDMODE_BLEND);
SDL_BlitSurface(surf, &sourceRect, where, &destRect);
SDL_SetSurfaceBlendMode(surf, SDL_BLENDMODE_NONE);
}
}
void SDLImage::playerColored(PlayerColor player)
@ -691,7 +686,7 @@ CompImage::CompImage(const CDefFile *data, size_t frame, size_t group):
surf(nullptr),
line(nullptr),
palette(nullptr)
{
CompImageLoader loader(this);
data->loadFrame(frame, group, loader);
@ -749,7 +744,7 @@ void CompImage::draw(SDL_Surface *where, int posX, int posY, Rect *src, ui8 alph
currX = 0;
ui8 bpp = where->format->BytesPerPixel;
//Calculate position for blitting: pixels + Y + X
ui8* blitPos = (ui8*) where->pixels;
if (rotation & 4)
@ -780,7 +775,7 @@ void CompImage::draw(SDL_Surface *where, int posX, int posY, Rect *src, ui8 alph
void CompImage::BlitBlockWithBpp(ui8 bpp, ui8 type, ui8 size, ui8 *&data, ui8 *&dest, ui8 alpha, bool rotated) const
{
assert(bpp>1 && bpp<5);
if (rotated)
switch (bpp)
{
@ -811,21 +806,13 @@ void CompImage::BlitBlock(ui8 type, ui8 size, ui8 *&data, ui8 *&dest, ui8 alpha)
for (size_t i=0; i<size; i++)
{
SDL_Color col = palette[*(data++)];
#ifdef VCMI_SDL1
col.unused = (ui32)col.unused*alpha/255;
#else
col.a = (ui32)col.a*alpha/255;
#endif // 0
ColorPutter<bpp, 1>::PutColorAlpha(dest, col);
}
return;
}
#ifdef VCMI_SDL1
if (palette[color].unused == 255)
#else
if (palette[color].a == 255)
#endif // 0
{
//Put row of RGB data
for (size_t i=0; i<size; i++)
@ -836,25 +823,12 @@ void CompImage::BlitBlock(ui8 type, ui8 size, ui8 *&data, ui8 *&dest, ui8 alpha)
//Put row of RGBA data
for (size_t i=0; i<size; i++)
ColorPutter<bpp, 1>::PutColorAlpha(dest, palette[*(data++)]);
}
}
//RLE-d sequence
else
{
#ifdef VCMI_SDL1
if (alpha != 255 && palette[type].unused !=0)//Per-surface alpha is set
{
SDL_Color col = palette[type];
col.unused = (int)col.unused*(255-alpha)/255;
for (size_t i=0; i<size; i++)
ColorPutter<bpp, 1>::PutColorAlpha(dest, col);
return;
}
switch (palette[type].unused)
#else
if (alpha != 255 && palette[type].a !=0)//Per-surface alpha is set
{
SDL_Color col = palette[type];
@ -863,9 +837,8 @@ void CompImage::BlitBlock(ui8 type, ui8 size, ui8 *&data, ui8 *&dest, ui8 alpha)
ColorPutter<bpp, 1>::PutColorAlpha(dest, col);
return;
}
switch (palette[type].a)
#endif // 0
{
case 0:
{
@ -991,7 +964,7 @@ bool CAnimation::loadFrame(CDefFile * file, size_t frame, size_t group)
else //load from separate file
{
std::string filename = source[group][frame].Struct().find("file")->second.String();
IImage * img = getFromExtraDef(filename);
if (!img)
img = new SDLImage(filename, compressed);
@ -1092,13 +1065,14 @@ CDefFile * CAnimation::getFile() const
void CAnimation::printError(size_t frame, size_t group, std::string type) const
{
logGlobal->errorStream() << type <<" error: Request for frame not present in CAnimation! "
<<"\tFile name: "<<name<<" Group: "<<group<<" Frame: "<<frame;
logGlobal->errorStream() << type << " error: Request for frame not present in CAnimation! "
<< "\tFile name: " << name << " Group: " << group << " Frame: " << frame;
}
CAnimation::CAnimation(std::string Name, bool Compressed):
name(Name),
compressed(Compressed)
compressed(Compressed),
preloaded(false)
{
size_t dotPos = name.find_last_of('.');
if ( dotPos!=-1 )
@ -1107,27 +1081,28 @@ CAnimation::CAnimation(std::string Name, bool Compressed):
CDefFile * file = getFile();
init(file);
delete file;
loadedAnims.insert(this);
}
CAnimation::CAnimation():
name(""),
compressed(false)
compressed(false),
preloaded(false)
{
init(nullptr);
loadedAnims.insert(this);
}
CAnimation::~CAnimation()
{
if (!images.empty())
if(preloaded)
unload();
if(!images.empty())
{
logGlobal->warnStream()<<"Warning: not all frames were unloaded from "<<name;
logGlobal->warnStream()<<"Warning: not all frames were unloaded from "<<name;
for (auto & elem : images)
for (auto & _image : elem.second)
delete _image.second;
}
loadedAnims.erase(this);
}
void CAnimation::setCustom(std::string filename, size_t frame, size_t group)
@ -1171,6 +1146,12 @@ void CAnimation::unload()
}
void CAnimation::preload()
{
preloaded = true;
load();
}
void CAnimation::loadGroup(size_t group)
{
CDefFile * file = getFile();
@ -1209,21 +1190,6 @@ size_t CAnimation::size(size_t group) const
return 0;
}
std::set<CAnimation*> CAnimation::loadedAnims;
void CAnimation::getAnimInfo()
{
logGlobal->errorStream()<<"Animation stats: Loaded "<<loadedAnims.size()<<" total";
for (auto anim : loadedAnims)
{
logGlobal->errorStream()<<"Name: "<<anim->name<<" Groups: "<<anim->images.size();
if (!anim->images.empty())
logGlobal->errorStream()<<", "<<anim->images.begin()->second.size()<<" image loaded in group "<< anim->images.begin()->first;
}
}
float CFadeAnimation::initialCounter() const
{
if (fadingMode == EMode::OUT)
@ -1235,12 +1201,12 @@ void CFadeAnimation::update()
{
if (!fading)
return;
if (fadingMode == EMode::OUT)
fadingCounter -= delta;
else
fadingCounter += delta;
if (isFinished())
{
fading = false;
@ -1269,7 +1235,7 @@ CFadeAnimation::CFadeAnimation()
CFadeAnimation::~CFadeAnimation()
{
if (fadingSurface && shouldFreeSurface)
SDL_FreeSurface(fadingSurface);
SDL_FreeSurface(fadingSurface);
}
void CFadeAnimation::init(EMode mode, SDL_Surface * sourceSurface, bool freeSurfaceAtEnd /* = false */, float animDelta /* = DEFAULT_DELTA */)
@ -1280,17 +1246,17 @@ void CFadeAnimation::init(EMode mode, SDL_Surface * sourceSurface, bool freeSurf
// (alternatively, we could just return here to ignore the new fade request until this one finished (but we'd need to free the passed bitmap to avoid leaks))
logGlobal->warnStream() << "Tried to init fading animation that is already running.";
if (fadingSurface && shouldFreeSurface)
SDL_FreeSurface(fadingSurface);
}
SDL_FreeSurface(fadingSurface);
}
if (animDelta <= 0.0f)
{
logGlobal->warnStream() << "Fade anim: delta should be positive; " << animDelta << " given.";
animDelta = DEFAULT_DELTA;
}
if (sourceSurface)
fadingSurface = sourceSurface;
delta = animDelta;
fadingMode = mode;
fadingCounter = initialCounter();
@ -1299,13 +1265,13 @@ void CFadeAnimation::init(EMode mode, SDL_Surface * sourceSurface, bool freeSurf
}
void CFadeAnimation::draw(SDL_Surface * targetSurface, const SDL_Rect * sourceRect, SDL_Rect * destRect)
{
{
if (!fading || !fadingSurface || fadingMode == EMode::NONE)
{
fading = false;
return;
}
CSDL_Ext::setAlpha(fadingSurface, fadingCounter * 255);
SDL_BlitSurface(fadingSurface, const_cast<SDL_Rect *>(sourceRect), targetSurface, destRect); //FIXME
CSDL_Ext::setAlpha(fadingSurface, 255);

View File

@ -39,8 +39,8 @@ private:
//offset[group][frame] - offset of frame data in file
std::map<size_t, std::vector <size_t> > offset;
ui8 * data;
SDL_Color * palette;
std::unique_ptr<ui8[]> data;
std::unique_ptr<SDL_Color[]> palette;
public:
CDefFile(std::string Name);
@ -98,10 +98,11 @@ 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 +145,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;
};
@ -169,6 +170,8 @@ private:
//if true all frames will be stored in compressed (RLE) state
const bool compressed;
bool preloaded;
//loader, will be called by load(), require opened def file for loading from it. Returns true if image is loaded
bool loadFrame(CDefFile * file, size_t frame, size_t group);
@ -195,10 +198,6 @@ public:
CAnimation();
~CAnimation();
//static method for debugging - print info about loaded animations
static void getAnimInfo();
static std::set<CAnimation*> loadedAnims;
//add custom surface to the selected position.
void setCustom(std::string filename, size_t frame, size_t group=0);
@ -208,6 +207,7 @@ public:
//all available frames
void load ();
void unload();
void preload();
//all frames from group
void loadGroup (size_t group);
@ -236,7 +236,7 @@ private:
bool fading;
float fadingCounter;
bool shouldFreeSurface;
float initialCounter() const;
bool isFinished() const;
public:

View File

@ -27,10 +27,8 @@ void CCursorHandler::initCursor()
currentCursor = nullptr;
help = CSDL_Ext::newSurface(40,40);
#ifndef VCMI_SDL1
//No blending. Ensure, that we are copying pixels during "screen restore draw"
SDL_SetSurfaceBlendMode(help,SDL_BLENDMODE_NONE);
#endif // VCMI_SDL1
SDL_ShowCursor(SDL_DISABLE);
changeGraphic(ECursor::ADVENTURE, 0);

View File

@ -1,5 +1,6 @@
#include "StdInc.h"
#include "CGuiHandler.h"
#include "../lib/CondSh.h"
#include <SDL.h>
@ -15,9 +16,10 @@
extern std::queue<SDL_Event> events;
extern boost::mutex eventsM;
CondSh<bool> CGuiHandler::terminate_cond;
boost::thread_specific_ptr<bool> inGuiThread;
SObjectConstruction::SObjectConstruction( CIntObject *obj )
SObjectConstruction::SObjectConstruction(CIntObject *obj)
:myObj(obj)
{
GH.createdObj.push_front(obj);
@ -63,10 +65,7 @@ void CGuiHandler::processLists(const ui16 activityFlag, std::function<void (std:
processList(CIntObject::TIME,activityFlag,&timeinterested,cb);
processList(CIntObject::WHEEL,activityFlag,&wheelInterested,cb);
processList(CIntObject::DOUBLECLICK,activityFlag,&doubleClickInterested,cb);
#ifndef VCMI_SDL1
processList(CIntObject::TEXTINPUT,activityFlag,&textInterested,cb);
#endif // VCMI_SDL1
}
void CGuiHandler::handleElementActivate(CIntObject * elem, ui16 activityFlag)
@ -87,7 +86,7 @@ void CGuiHandler::handleElementDeActivate(CIntObject * elem, ui16 activityFlag)
elem->active_m &= ~activityFlag;
}
void CGuiHandler::popInt( IShowActivatable *top )
void CGuiHandler::popInt(IShowActivatable *top)
{
assert(listInt.front() == top);
top->deactivate();
@ -98,7 +97,7 @@ void CGuiHandler::popInt( IShowActivatable *top )
totalRedraw();
}
void CGuiHandler::popIntTotally( IShowActivatable *top )
void CGuiHandler::popIntTotally(IShowActivatable *top)
{
assert(listInt.front() == top);
popInt(top);
@ -106,7 +105,7 @@ void CGuiHandler::popIntTotally( IShowActivatable *top )
fakeMouseMove();
}
void CGuiHandler::pushInt( IShowActivatable *newInt )
void CGuiHandler::pushInt(IShowActivatable *newInt)
{
assert(newInt);
assert(boost::range::find(listInt, newInt) == listInt.end()); // do not add same object twice
@ -122,7 +121,7 @@ void CGuiHandler::pushInt( IShowActivatable *newInt )
totalRedraw();
}
void CGuiHandler::popInts( int howMany )
void CGuiHandler::popInts(int howMany)
{
if(!howMany) return; //senseless but who knows...
@ -196,10 +195,8 @@ void CGuiHandler::handleEvent(SDL_Event *sEvent)
//translate numpad keys
if(key.keysym.sym == SDLK_KP_ENTER)
{
key.keysym.sym = (SDLKey)SDLK_RETURN;
#ifndef VCMI_SDL1
key.keysym.sym = SDLK_RETURN;
key.keysym.scancode = SDL_SCANCODE_RETURN;
#endif // VCMI_SDL1
}
bool keysCaptured = false;
@ -270,27 +267,18 @@ void CGuiHandler::handleEvent(SDL_Event *sEvent)
}
}
}
#ifdef VCMI_SDL1 //SDL1x only events
else if(sEvent->button.button == SDL_BUTTON_WHEELDOWN || sEvent->button.button == SDL_BUTTON_WHEELUP)
{
std::list<CIntObject*> hlp = wheelInterested;
for(auto i=hlp.begin(); i != hlp.end() && current; i++)
{
if(!vstd::contains(wheelInterested,*i)) continue;
(*i)->wheelScrolled(sEvent->button.button == SDL_BUTTON_WHEELDOWN, isItIn(&(*i)->pos,sEvent->motion.x,sEvent->motion.y));
}
}
#endif
}
#ifndef VCMI_SDL1 //SDL2x only events
else if (sEvent->type == SDL_MOUSEWHEEL)
{
std::list<CIntObject*> hlp = wheelInterested;
for(auto i=hlp.begin(); i != hlp.end() && current; i++)
{
if(!vstd::contains(wheelInterested,*i)) continue;
(*i)->wheelScrolled(sEvent->wheel.y < 0, isItIn(&(*i)->pos,sEvent->motion.x,sEvent->motion.y));
}
// SDL doesn't have the proper values for mouse positions on SDL_MOUSEWHEEL, refetch them
int x = 0, y = 0;
SDL_GetMouseState(&x, &y);
(*i)->wheelScrolled(sEvent->wheel.y < 0, isItIn(&(*i)->pos, x, y));
}
}
else if(sEvent->type == SDL_TEXTINPUT)
{
@ -307,7 +295,6 @@ void CGuiHandler::handleEvent(SDL_Event *sEvent)
}
}
//todo: muiltitouch
#endif // VCMI_SDL1
else if ((sEvent->type==SDL_MOUSEBUTTONUP) && (sEvent->button.button == SDL_BUTTON_LEFT))
{
std::list<CIntObject*> hlp = lclickable;
@ -341,7 +328,6 @@ void CGuiHandler::handleEvent(SDL_Event *sEvent)
}
}
current = nullptr;
} //event end
void CGuiHandler::handleMouseMotion(SDL_Event *sEvent)
@ -378,7 +364,7 @@ void CGuiHandler::simpleRedraw()
objsToBlit.back()->show(screen); //blit active interface/window
}
void CGuiHandler::handleMoveInterested( const SDL_MouseMotionEvent & motion )
void CGuiHandler::handleMoveInterested(const SDL_MouseMotionEvent & motion)
{
//sending active, MotionInterested objects mouseMoved() call
std::list<CIntObject*> miCopy = motioninterested;
@ -394,12 +380,9 @@ void CGuiHandler::handleMoveInterested( const SDL_MouseMotionEvent & motion )
void CGuiHandler::fakeMouseMove()
{
SDL_Event evnt;
#ifdef VCMI_SDL1
SDL_MouseMotionEvent sme = {SDL_MOUSEMOTION, 0, 0, 0, 0, 0, 0};
#else
SDL_MouseMotionEvent sme = {SDL_MOUSEMOTION, 0, 0, 0, 0, 0, 0, 0, 0};
#endif
int x, y;
sme.state = SDL_GetMouseState(&x, &y);
sme.x = x;
sme.y = y;
@ -411,29 +394,37 @@ void CGuiHandler::fakeMouseMove()
void CGuiHandler::renderFrame()
{
auto doUpdate = [this]()
// Updating GUI requires locking pim mutex (that protects screen and GUI state).
// During game:
// When ending the game, the pim mutex might be hold by other thread,
// that will notify us about the ending game by setting terminate_cond flag.
//in PreGame terminate_cond stay false
bool acquiredTheLockOnPim = false; //for tracking whether pim mutex locking succeeded
while(!terminate_cond.get() && !(acquiredTheLockOnPim = CPlayerInterface::pim->try_lock())) //try acquiring long until it succeeds or we are told to terminate
boost::this_thread::sleep(boost::posix_time::milliseconds(15));
if(acquiredTheLockOnPim)
{
// If we are here, pim mutex has been successfully locked - let's store it in a safe RAII lock.
boost::unique_lock<boost::recursive_mutex> un(*CPlayerInterface::pim, boost::adopt_lock);
if(nullptr != curInt)
{
curInt -> update();
}
curInt->update();
if (settings["general"]["showfps"].Bool())
drawFPSCounter();
// draw the mouse cursor and update the screen
CCS->curh->render();
#ifndef VCMI_SDL1
if(0 != SDL_RenderCopy(mainRenderer, screenTexture, nullptr, nullptr))
logGlobal->errorStream() << __FUNCTION__ << " SDL_RenderCopy " << SDL_GetError();
SDL_RenderPresent(mainRenderer);
#endif
};
if(curInt)
curInt->runLocked(doUpdate);
else
doUpdate();
SDL_RenderPresent(mainRenderer);
}
mainFPSmng->framerateDelay(); // holds a constant FPS
}
@ -448,6 +439,8 @@ CGuiHandler::CGuiHandler()
// Creates the FPS manager and sets the framerate to 48 which is doubled the value of the original Heroes 3 FPS rate
mainFPSmng = new CFramerateManager(48);
//do not init CFramerateManager here --AVS
terminate_cond.set(false);
}
CGuiHandler::~CGuiHandler()
@ -470,23 +463,8 @@ void CGuiHandler::drawFPSCounter()
graphics->fonts[FONT_BIG]->renderTextLeft(screen, fps, yellow, Point(10, 10));
}
SDLKey CGuiHandler::arrowToNum( SDLKey key )
SDL_Keycode CGuiHandler::arrowToNum(SDL_Keycode key)
{
#ifdef VCMI_SDL1
switch(key)
{
case SDLK_DOWN:
return SDLK_KP2;
case SDLK_UP:
return SDLK_KP8;
case SDLK_LEFT:
return SDLK_KP4;
case SDLK_RIGHT:
return SDLK_KP6;
default:
throw std::runtime_error("Wrong key!");assert(0);
}
#else
switch(key)
{
case SDLK_DOWN:
@ -500,20 +478,14 @@ SDLKey CGuiHandler::arrowToNum( SDLKey key )
default:
throw std::runtime_error("Wrong key!");
}
#endif // 0
}
SDLKey CGuiHandler::numToDigit( SDLKey key )
SDL_Keycode CGuiHandler::numToDigit(SDL_Keycode key)
{
#ifdef VCMI_SDL1
if(key >= SDLK_KP0 && key <= SDLK_KP9)
return SDLKey(key - SDLK_KP0 + SDLK_0);
#endif // 0
#define REMOVE_KP(keyName) case SDLK_KP_ ## keyName : return SDLK_ ## keyName;
switch(key)
{
#ifndef VCMI_SDL1
REMOVE_KP(0)
REMOVE_KP(1)
REMOVE_KP(2)
@ -524,7 +496,6 @@ SDLKey CGuiHandler::numToDigit( SDLKey key )
REMOVE_KP(7)
REMOVE_KP(8)
REMOVE_KP(9)
#endif // VCMI_SDL1
REMOVE_KP(PERIOD)
REMOVE_KP(MINUS)
REMOVE_KP(PLUS)
@ -542,22 +513,15 @@ SDLKey CGuiHandler::numToDigit( SDLKey key )
#undef REMOVE_KP
}
bool CGuiHandler::isNumKey( SDLKey key, bool number )
bool CGuiHandler::isNumKey(SDL_Keycode key, bool number)
{
#ifdef VCMI_SDL1
if(number)
return key >= SDLK_KP0 && key <= SDLK_KP9;
else
return key >= SDLK_KP0 && key <= SDLK_KP_EQUALS;
#else
if(number)
return key >= SDLK_KP_1 && key <= SDLK_KP_0;
else
return (key >= SDLK_KP_1 && key <= SDLK_KP_0) || key == SDLK_KP_MINUS || key == SDLK_KP_PLUS || key == SDLK_KP_EQUALS;
#endif // 0
}
bool CGuiHandler::isArrowKey( SDLKey key )
bool CGuiHandler::isArrowKey(SDL_Keycode key)
{
return key == SDLK_UP || key == SDLK_DOWN || key == SDLK_LEFT || key == SDLK_RIGHT;
}
@ -580,6 +544,8 @@ CFramerateManager::CFramerateManager(int rate)
this->rate = rate;
this->rateticks = (1000.0 / rate);
this->fps = 0;
this->accumulatedFrames = 0;
this->accumulatedTime = 0;
}
void CFramerateManager::init()
@ -591,18 +557,28 @@ void CFramerateManager::framerateDelay()
{
ui32 currentTicks = SDL_GetTicks();
timeElapsed = currentTicks - lastticks;
// FPS is higher than it should be, then wait some time
if (timeElapsed < rateticks)
{
SDL_Delay(ceil(this->rateticks) - timeElapsed);
}
accumulatedTime += timeElapsed;
accumulatedFrames++;
if(accumulatedFrames >= 100)
{
//about 2 second should be passed
fps = ceil(1000.0 / (accumulatedTime/accumulatedFrames));
accumulatedTime = 0;
accumulatedFrames = 0;
};
currentTicks = SDL_GetTicks();
fps = ceil(1000.0 / timeElapsed);
// recalculate timeElapsed for external calls via getElapsed()
// limit it to 1000 ms to avoid breaking animation in case of huge lag (e.g. triggered breakpoint)
timeElapsed = std::min<ui32>(currentTicks - lastticks, 1000);
lastticks = SDL_GetTicks();
}

View File

@ -8,9 +8,9 @@ class CFramerateManager;
class CGStatusBar;
class CIntObject;
class IUpdateable;
class ILockedUpdatable;
class IShowActivatable;
class IShowable;
template <typename T> struct CondSh;
/*
* CGuiHandler.h, part of VCMI engine
@ -29,7 +29,7 @@ private:
double rateticks;
ui32 lastticks, timeElapsed;
int rate;
ui32 accumulatedTime,accumulatedFrames;
public:
int fps; // the actual fps value
@ -58,10 +58,9 @@ private:
motioninterested,
timeinterested,
wheelInterested,
doubleClickInterested;
#ifndef VCMI_SDL1
CIntObjectList textInterested;
#endif // VCMI_SDL1
doubleClickInterested,
textInterested;
void processLists(const ui16 activityFlag, std::function<void (std::list<CIntObject*> *)> cb);
public:
@ -73,7 +72,7 @@ public:
std::vector<IShowable*> objsToBlit;
SDL_Event * current; //current event - can be set to nullptr to stop handling event
ILockedUpdatable *curInt;
IUpdateable *curInt;
Point lastClick;
unsigned lastClickTime;
@ -104,12 +103,14 @@ public:
ui8 captureChildren; //all newly created objects will get their parents from stack and will be added to parents children list
std::list<CIntObject *> createdObj; //stack of objs being created
static SDLKey arrowToNum(SDLKey key); //converts arrow key to according numpad key
static SDLKey numToDigit(SDLKey key);//converts numpad digit key to normal digit key
static bool isNumKey(SDLKey key, bool number = true); //checks if key is on numpad (numbers - check only for numpad digits)
static bool isArrowKey(SDLKey key);
static SDL_Keycode arrowToNum(SDL_Keycode key); //converts arrow key to according numpad key
static SDL_Keycode numToDigit(SDL_Keycode key);//converts numpad digit key to normal digit key
static bool isNumKey(SDL_Keycode key, bool number = true); //checks if key is on numpad (numbers - check only for numpad digits)
static bool isArrowKey(SDL_Keycode key);
static bool amIGuiThread();
static void pushSDLEvent(int type, int usercode = 0);
static CondSh<bool> terminate_cond; // confirm termination
};
extern CGuiHandler GH; //global gui handler

View File

@ -15,8 +15,8 @@
#include "../Graphics.h"
struct SDL_Surface;
class CPicture;
class CGuiHandler;
class CPicture;
struct SDL_KeyboardEvent;
@ -38,13 +38,6 @@ public:
virtual ~IUpdateable(){}; //d-tor
};
class ILockedUpdatable: public IUpdateable
{
public:
virtual void runLocked(std::function<void()> cb) = 0;
virtual ~ILockedUpdatable(){}; //d-tor
};
// Defines a show method
class IShowable
{
@ -97,11 +90,6 @@ public:
*/
std::vector<CIntObject *> children;
//FIXME: workaround
void deactivateKeyboard()
{
deactivate(KEYBOARD);
}
/*
* Public interface
@ -133,10 +121,8 @@ public:
virtual void keyPressed(const SDL_KeyboardEvent & key){}
virtual bool captureThisEvent(const SDL_KeyboardEvent & key); //allows refining captureAllKeys against specific events (eg. don't capture ENTER)
#ifndef VCMI_SDL1
virtual void textInputed(const SDL_TextInputEvent & event){};
virtual void textEdited(const SDL_TextEditingEvent & event){};
#endif // VCMI_SDL1
//mouse movement handling
bool strongInterest; //if true - report all mouse movements, if not - only when hovered
@ -166,15 +152,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};
@ -221,5 +207,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

@ -13,13 +13,6 @@
*
*/
#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif
struct SDL_MouseMotionEvent;
// A point with x/y coordinate, used mostly for graphic rendering

View File

@ -13,23 +13,12 @@
#include <SDL_version.h>
#if (SDL_MAJOR_VERSION == 2)
#define VCMI_SDL2
#include <SDL_keycode.h>
typedef int SDLX_Coord;
typedef int SDLX_Size;
typedef SDL_Keycode SDLKey;
#define SDL_SRCCOLORKEY SDL_TRUE
#define SDL_FULLSCREEN SDL_WINDOW_FULLSCREEN
#elif (SDL_MAJOR_VERSION == 1)
#define VCMI_SDL1
//SDL 1.x
typedef Sint16 SDLX_Coord;
typedef Uint16 SDLX_Size;
#else
#error "unknown or unsupported SDL version"
#endif

View File

@ -4,7 +4,6 @@
#include "../CGameInfo.h"
#include "../CMessage.h"
#include "../CDefHandler.h"
#include "../Graphics.h"
#include "../CMT.h"
@ -14,7 +13,6 @@ const SDL_Color Colors::METALLIC_GOLD = { 173, 142, 66, 0 };
const SDL_Color Colors::GREEN = { 0, 255, 0, 0 };
const SDL_Color Colors::DEFAULT_KEY_COLOR = {0, 255, 255, 0};
#if (SDL_MAJOR_VERSION == 2)
void SDL_UpdateRect(SDL_Surface *surface, int x, int y, int w, int h)
{
Rect rect(x,y,w,h);
@ -24,10 +22,9 @@ void SDL_UpdateRect(SDL_Surface *surface, int x, int y, int w, int h)
SDL_RenderClear(mainRenderer);
if(0 != SDL_RenderCopy(mainRenderer, screenTexture, NULL, NULL))
logGlobal->errorStream() << __FUNCTION__ << "SDL_RenderCopy " << SDL_GetError();
SDL_RenderPresent(mainRenderer);
SDL_RenderPresent(mainRenderer);
}
#endif // VCMI_SDL1
SDL_Surface * CSDL_Ext::newSurface(int w, int h, SDL_Surface * mod) //creates new surface, with flags/format same as in surface given
{
@ -171,7 +168,7 @@ void CSDL_Ext::alphaTransform(SDL_Surface *src)
SDL_Color & palColor = src->format->palette->colors[i];
palColor = colors[i];
}
SDL_SetColorKey(src, SDL_SRCCOLORKEY, 0);
SDL_SetColorKey(src, SDL_TRUE, 0);
}
static void prepareOutRect(SDL_Rect *src, SDL_Rect *dst, const SDL_Rect & clip_rect)
@ -460,11 +457,7 @@ int CSDL_Ext::blit8bppAlphaTo24bppT(const SDL_Surface * src, const SDL_Rect * sr
for(int x = w; x; x--)
{
const SDL_Color &tbc = colors[*color++]; //color to blit
#ifdef VCMI_SDL1
ColorPutter<bpp, +1>::PutColorAlphaSwitch(p, tbc.r, tbc.g, tbc.b, tbc.unused);
#else
ColorPutter<bpp, +1>::PutColorAlphaSwitch(p, tbc.r, tbc.g, tbc.b, tbc.a);
#endif // 0
}
}
SDL_UnlockSurface(dst);
@ -481,7 +474,7 @@ int CSDL_Ext::blit8bppAlphaTo24bpp(const SDL_Surface * src, const SDL_Rect * src
case 3: return blit8bppAlphaTo24bppT<3>(src, srcRect, dst, dstRect);
case 4: return blit8bppAlphaTo24bppT<4>(src, srcRect, dst, dstRect);
default:
logGlobal->errorStream() << (int)dst->format->BitsPerPixel << " bpp is not supported!!!";
logGlobal->errorStream() << (int)dst->format->BitsPerPixel << " bpp is not supported!!!";
return -1;
}
}
@ -489,11 +482,7 @@ int CSDL_Ext::blit8bppAlphaTo24bpp(const SDL_Surface * src, const SDL_Rect * src
Uint32 CSDL_Ext::colorToUint32(const SDL_Color * color)
{
Uint32 ret = 0;
#ifdef VCMI_SDL1
ret+=color->unused;
#else
ret+=color->a;
#endif // 0
ret<<=8; //*=256
ret+=color->b;
ret<<=8; //*=256
@ -505,15 +494,10 @@ Uint32 CSDL_Ext::colorToUint32(const SDL_Color * color)
void CSDL_Ext::update(SDL_Surface * what)
{
#ifdef VCMI_SDL1
if(what)
SDL_UpdateRect(what, 0, 0, what->w, what->h);
#else
if(!what)
return;
if(0 !=SDL_UpdateTexture(screenTexture, nullptr, what->pixels, what->pitch))
logGlobal->errorStream() << __FUNCTION__ << "SDL_UpdateTexture " << SDL_GetError();
#endif // VCMI_SDL1
logGlobal->errorStream() << __FUNCTION__ << "SDL_UpdateTexture " << SDL_GetError();
}
void CSDL_Ext::drawBorder(SDL_Surface * sur, int x, int y, int w, int h, const int3 &color)
{
@ -571,7 +555,7 @@ void CSDL_Ext::setPlayerColor(SDL_Surface * sur, PlayerColor player)
SDL_SetColors(sur, color, 5, 1);
}
else
logGlobal->warnStream() << "Warning, setPlayerColor called on not 8bpp surface!";
logGlobal->warnStream() << "Warning, setPlayerColor called on not 8bpp surface!";
}
TColorPutter CSDL_Ext::getPutterFor(SDL_Surface * const &dest, int incrementing)
@ -592,7 +576,7 @@ case BytesPerPixel: \
CASE_BPP(3)
CASE_BPP(4)
default:
logGlobal->errorStream() << (int)dest->format->BitsPerPixel << "bpp is not supported!";
logGlobal->errorStream() << (int)dest->format->BitsPerPixel << "bpp is not supported!";
return nullptr;
}
@ -606,7 +590,7 @@ TColorPutterAlpha CSDL_Ext::getPutterAlphaFor(SDL_Surface * const &dest, int inc
CASE_BPP(3)
CASE_BPP(4)
default:
logGlobal->errorStream() << (int)dest->format->BitsPerPixel << "bpp is not supported!";
logGlobal->errorStream() << (int)dest->format->BitsPerPixel << "bpp is not supported!";
return nullptr;
}
#undef CASE_BPP
@ -632,22 +616,14 @@ bool CSDL_Ext::isTransparent( SDL_Surface * srf, int x, int y )
return true;
SDL_Color color;
#ifdef VCMI_SDL1
SDL_GetRGBA(SDL_GetPixel(srf, x, y), srf->format, &color.r, &color.g, &color.b, &color.unused);
#else
SDL_GetRGBA(SDL_GetPixel(srf, x, y), srf->format, &color.r, &color.g, &color.b, &color.a);
#endif // 0
// color is considered transparent here if
// a) image has aplha: less than 50% transparency
// b) no alpha: color is cyan
if (srf->format->Amask)
#ifdef VCMI_SDL1
return color.unused < 128; // almost transparent
#else
return color.a < 128; // almost transparent
#endif // 0
else
return (color.r == 0 && color.g == 255 && color.b == 255);
}
@ -698,7 +674,7 @@ BlitterWithRotationVal CSDL_Ext::getBlitterWithRotation(SDL_Surface *dest)
case 3: return blitWithRotateClipVal<3>;
case 4: return blitWithRotateClipVal<4>;
default:
logGlobal->errorStream() << (int)dest->format->BitsPerPixel << " bpp is not supported!!!";
logGlobal->errorStream() << (int)dest->format->BitsPerPixel << " bpp is not supported!!!";
break;
}
@ -714,7 +690,7 @@ BlitterWithRotationVal CSDL_Ext::getBlitterWithRotationAndAlpha(SDL_Surface *des
case 3: return blitWithRotateClipValWithAlpha<3>;
case 4: return blitWithRotateClipValWithAlpha<4>;
default:
logGlobal->errorStream() << (int)dest->format->BitsPerPixel << " bpp is not supported!!!";
logGlobal->errorStream() << (int)dest->format->BitsPerPixel << " bpp is not supported!!!";
break;
}
@ -988,42 +964,34 @@ SDL_Color CSDL_Ext::makeColor(ui8 r, ui8 g, ui8 b, ui8 a)
void CSDL_Ext::startTextInput(SDL_Rect * where)
{
#ifndef VCMI_SDL1
if (SDL_IsTextInputActive() == SDL_FALSE)
{
SDL_StartTextInput();
}
if (SDL_IsTextInputActive() == SDL_FALSE)
{
SDL_StartTextInput();
}
SDL_SetTextInputRect(where);
#endif
}
void CSDL_Ext::stopTextInput()
{
#ifndef VCMI_SDL1
if (SDL_IsTextInputActive() == SDL_TRUE)
{
SDL_StopTextInput();
}
#endif
{
SDL_StopTextInput();
}
}
STRONG_INLINE static uint32_t mapColor(SDL_Surface * surface, SDL_Color color)
{
#ifdef VCMI_SDL1
return SDL_MapRGB(surface->format, color.r, color.g, color.b);
#else
return SDL_MapRGBA(surface->format, color.r, color.g, color.b, color.a);
#endif
return SDL_MapRGBA(surface->format, color.r, color.g, color.b, color.a);
}
void CSDL_Ext::setColorKey(SDL_Surface * surface, SDL_Color color)
{
uint32_t key = mapColor(surface,color);
SDL_SetColorKey(surface, SDL_SRCCOLORKEY, key);
SDL_SetColorKey(surface, SDL_TRUE, key);
}
void CSDL_Ext::setDefaultColorKey(SDL_Surface * surface)
{
{
setColorKey(surface, Colors::DEFAULT_KEY_COLOR);
}
@ -1034,7 +1002,7 @@ void CSDL_Ext::setDefaultColorKeyPresize(SDL_Surface * surface)
// set color key only if exactly such color was found
if (color.r == Colors::DEFAULT_KEY_COLOR.r && color.g == Colors::DEFAULT_KEY_COLOR.g && color.b == Colors::DEFAULT_KEY_COLOR.b)
SDL_SetColorKey(surface, SDL_SRCCOLORKEY, key);
SDL_SetColorKey(surface, SDL_TRUE, key);
}

View File

@ -10,35 +10,14 @@
#pragma once
#include <SDL_version.h>
#ifndef VCMI_SDL1
#include <SDL_render.h>
#endif
#include <SDL_video.h>
#include <SDL_events.h>
#include "../../lib/int3.h"
//#include "../Graphics.h"
#include "Geometries.h"
#include "../../lib/GameConstants.h"
//A macro to force inlining some of our functions. Compiler (at least MSVC) is not so smart here-> without that displaying is MUCH slower
#ifdef _MSC_VER
#define STRONG_INLINE __forceinline
#elif __GNUC__
#define STRONG_INLINE inline __attribute__((always_inline))
#else
#define STRONG_INLINE inline
#endif
#if SDL_VERSION_ATLEAST(1,3,0)
#define SDL_GetKeyState SDL_GetKeyboardState
#endif
//SDL2 support
#if (SDL_MAJOR_VERSION == 2)
extern SDL_Window * mainWindow;
extern SDL_Renderer * mainRenderer;
extern SDL_Texture * screenTexture;
@ -54,64 +33,35 @@ inline void SDL_WarpMouse(int x, int y)
}
void SDL_UpdateRect(SDL_Surface *surface, int x, int y, int w, int h);
#endif
inline bool isCtrlKeyDown()
{
#ifdef VCMI_SDL1
return SDL_GetKeyState(nullptr)[SDLK_LCTRL] || SDL_GetKeyState(nullptr)[SDLK_RCTRL];
#else
return SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_LCTRL] || SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_RCTRL];
#endif
}
inline bool isAltKeyDown()
{
#ifdef VCMI_SDL1
return SDL_GetKeyState(nullptr)[SDLK_LALT] || SDL_GetKeyState(nullptr)[SDLK_RALT];
#else
return SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_LALT] || SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_RALT];
#endif
}
inline bool isShiftKeyDown()
{
#ifdef VCMI_SDL1
return SDL_GetKeyState(nullptr)[SDLK_LSHIFT] || SDL_GetKeyState(nullptr)[SDLK_RSHIFT];
#else
return SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_LSHIFT] || SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_RSHIFT];
#endif
}
namespace CSDL_Ext
{
STRONG_INLINE void colorSetAlpha(SDL_Color & color, Uint8 alpha)
{
#ifdef VCMI_SDL1
color.unused = alpha;
#else
color.a = alpha;
#endif
}
//todo: should this better be assignment operator?
STRONG_INLINE void colorAssign(SDL_Color & dest, const SDL_Color & source)
{
dest.r = source.r;
dest.g = source.g;
dest.b = source.b;
#ifdef VCMI_SDL1
dest.unused = source.unused;
#else
dest.a = source.a;
#endif
}
inline void setAlpha(SDL_Surface * bg, int value)
{
#ifdef VCMI_SDL1
SDL_SetAlpha(bg, SDL_SRCALPHA, value);
#else
SDL_SetSurfaceAlphaMod(bg, value);
#endif
}
}
struct Rect;
@ -154,7 +104,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

@ -135,11 +135,7 @@ struct ColorPutter<2, incrementPtr>
template<int bpp, int incrementPtr>
STRONG_INLINE void ColorPutter<bpp, incrementPtr>::PutColorAlpha(Uint8 *&ptr, const SDL_Color & Color)
{
#ifdef VCMI_SDL1
PutColor(ptr, Color.r, Color.g, Color.b, Color.unused);
#else
PutColor(ptr, Color.r, Color.g, Color.b, Color.a);
#endif
}
template<int bpp, int incrementPtr>
@ -268,11 +264,7 @@ STRONG_INLINE void ColorPutter<2, incrementPtr>::PutColor(Uint8 *&ptr, const Uin
template <int incrementPtr>
STRONG_INLINE void ColorPutter<2, incrementPtr>::PutColorAlpha(Uint8 *&ptr, const SDL_Color & Color)
{
#ifdef VCMI_SDL1
PutColor(ptr, Color.r, Color.g, Color.b, Color.unused);
#else
PutColor(ptr, Color.r, Color.g, Color.b, Color.a);
#endif
}
template <int incrementPtr>

View File

@ -528,7 +528,7 @@ CMapHandler::CMapNormalBlitter::CMapNormalBlitter(CMapHandler * parent)
defaultTileRect = Rect(0, 0, tileSize, tileSize);
}
SDL_Surface * CMapHandler::CMapWorldViewBlitter::objectToIcon(Obj id, si32 subId, PlayerColor owner) const
IImage * CMapHandler::CMapWorldViewBlitter::objectToIcon(Obj id, si32 subId, PlayerColor owner) const
{
int ownerIndex = 0;
if(owner < PlayerColor::PLAYER_LIMIT)
@ -539,27 +539,27 @@ SDL_Surface * CMapHandler::CMapWorldViewBlitter::objectToIcon(Obj id, si32 subId
{
ownerIndex = PlayerColor::PLAYER_LIMIT.getNum() * 19;
}
switch(id)
{
case Obj::MONOLITH_ONE_WAY_ENTRANCE:
case Obj::MONOLITH_ONE_WAY_EXIT:
case Obj::MONOLITH_TWO_WAY:
return info->iconsDef->ourImages[(int)EWorldViewIcon::TELEPORT].bitmap;
return info->icons->getImage((int)EWorldViewIcon::TELEPORT);
case Obj::SUBTERRANEAN_GATE:
return info->iconsDef->ourImages[(int)EWorldViewIcon::GATE].bitmap;
return info->icons->getImage((int)EWorldViewIcon::GATE);
case Obj::ARTIFACT:
return info->iconsDef->ourImages[(int)EWorldViewIcon::ARTIFACT].bitmap;
return info->icons->getImage((int)EWorldViewIcon::ARTIFACT);
case Obj::TOWN:
return info->iconsDef->ourImages[(int)EWorldViewIcon::TOWN + ownerIndex].bitmap;
return info->icons->getImage((int)EWorldViewIcon::TOWN + ownerIndex);
case Obj::HERO:
return info->iconsDef->ourImages[(int)EWorldViewIcon::HERO + ownerIndex].bitmap;
return info->icons->getImage((int)EWorldViewIcon::HERO + ownerIndex);
case Obj::MINE:
return info->iconsDef->ourImages[(int)EWorldViewIcon::MINE_WOOD + subId + ownerIndex].bitmap;
return info->icons->getImage((int)EWorldViewIcon::MINE_WOOD + subId + ownerIndex);
case Obj::RESOURCE:
return info->iconsDef->ourImages[(int)EWorldViewIcon::RES_WOOD + subId + ownerIndex].bitmap;
}
return nullptr;
return info->icons->getImage((int)EWorldViewIcon::RES_WOOD + subId + ownerIndex);
}
return nullptr;
}
void CMapHandler::CMapWorldViewBlitter::calculateWorldViewCameraPos()
@ -645,13 +645,13 @@ void CMapHandler::CMapWorldViewBlitter::drawTileOverlay(SDL_Surface * targetSurf
{
auto drawIcon = [this,targetSurf](Obj id, si32 subId, PlayerColor owner)
{
SDL_Surface * wvIcon = this->objectToIcon(id, subId, owner);
IImage * wvIcon = this->objectToIcon(id, subId, owner);
if (nullptr != wvIcon)
if(nullptr != wvIcon)
{
// centering icon on the object
Rect destRect(realPos.x + tileSize / 2 - wvIcon->w / 2, realPos.y + tileSize / 2 - wvIcon->h / 2, wvIcon->w, wvIcon->h);
CSDL_Ext::blitSurface(wvIcon, nullptr, targetSurf, &destRect);
Point dest(realPos.x + tileSize / 2 - wvIcon->width() / 2, realPos.y + tileSize / 2 - wvIcon->height() / 2);
wvIcon->draw(targetSurf, dest.x, dest.y);
}
};
@ -660,7 +660,7 @@ void CMapHandler::CMapWorldViewBlitter::drawTileOverlay(SDL_Surface * targetSurf
{
const CGObjectInstance * obj = object.obj;
const bool sameLevel = obj->pos.z == pos.z;
const bool sameLevel = obj->pos.z == pos.z;
const bool isVisible = (*info->visibilityMap)[pos.x][pos.y][pos.z];
const bool isVisitable = obj->visitableAt(pos.x, pos.y);
@ -673,31 +673,31 @@ void CMapHandler::CMapWorldViewBlitter::drawOverlayEx(SDL_Surface * targetSurf)
{
if(nullptr == info->additionalIcons)
return;
const int3 bottomRight = pos + tileCount;
for(const ObjectPosInfo & iconInfo : *(info->additionalIcons))
{
if( iconInfo.pos.z != pos.z)
continue;
if((iconInfo.pos.x < topTile.x) || (iconInfo.pos.y < topTile.y))
continue;
if((iconInfo.pos.x > bottomRight.x) || (iconInfo.pos.y > bottomRight.y))
continue;
continue;
realPos.x = initPos.x + (iconInfo.pos.x - topTile.x) * tileSize;
realPos.y = initPos.x + (iconInfo.pos.y - topTile.y) * tileSize;
SDL_Surface * wvIcon = this->objectToIcon(iconInfo.id, iconInfo.subId, iconInfo.owner);
if (nullptr != wvIcon)
IImage * wvIcon = this->objectToIcon(iconInfo.id, iconInfo.subId, iconInfo.owner);
if(nullptr != wvIcon)
{
// centering icon on the object
Rect destRect(realPos.x + tileSize / 2 - wvIcon->w / 2, realPos.y + tileSize / 2 - wvIcon->h / 2, wvIcon->w, wvIcon->h);
CSDL_Ext::blitSurface(wvIcon, nullptr, targetSurf, &destRect);
}
Point dest(realPos.x + tileSize / 2 - wvIcon->width() / 2, realPos.y + tileSize / 2 - wvIcon->height() / 2);
wvIcon->draw(targetSurf, dest.x, dest.y);
}
}
}
@ -778,8 +778,8 @@ void CMapHandler::CMapPuzzleViewBlitter::drawObjects(SDL_Surface * targetSurf, c
// grail X mark
if(pos.x == info->grailPos.x && pos.y == info->grailPos.y)
{
Rect destRect(realTileRect);
CSDL_Ext::blit8bppAlphaTo24bpp(graphics->heroMoveArrows->ourImages[0].bitmap, nullptr, targetSurf, &destRect);
const IImage * mark = graphics->heroMoveArrows->getImage(0);
mark->draw(targetSurf,realTileRect.x,realTileRect.y);
}
}
@ -837,7 +837,7 @@ void CMapHandler::CMapBlitter::drawObjects(SDL_Surface * targetSurf, const Terra
for(auto & object : objects)
{
if (object.fadeAnimKey >= 0)
{
{
auto fadeIter = parent->fadeAnims.find(object.fadeAnimKey);
if (fadeIter != parent->fadeAnims.end())
{
@ -850,27 +850,34 @@ void CMapHandler::CMapBlitter::drawObjects(SDL_Surface * targetSurf, const Terra
logGlobal->errorStream() << "Fading map object with missing fade anim : " << object.fadeAnimKey;
continue;
}
const CGObjectInstance * obj = object.obj;
if (!obj)
{
logGlobal->errorStream() << "Stray map object that isn't fading";
continue;
}
if (!graphics->getDef(obj))
processDef(obj->appearance);
if (!graphics->getDef(obj) && !obj->appearance.animationFile.empty())
logGlobal->errorStream() << "Failed to load image " << obj->appearance.animationFile;
if (!graphics->getDef(obj))
{
if (!obj->appearance.animationFile.empty())
logGlobal->errorStream() << "Failed to load image " << obj->appearance.animationFile;
else
logGlobal->warnStream() << boost::format("Def name for obj %d (%d,%d) is empty!") % obj->id % obj->ID % obj->subID;
continue;
}
if (!canDrawObject(obj))
continue;
auto objData = findObjectBitmap(obj, info->anim);
if (objData.objBitmap)
{
{
Rect srcRect(object.rect.x, object.rect.y, tileSize, tileSize);
drawObject(targetSurf, objData.objBitmap, &srcRect, objData.isMoving);
if (objData.flagBitmap)
{
@ -883,7 +890,7 @@ void CMapHandler::CMapBlitter::drawObjects(SDL_Surface * targetSurf, const Terra
else if (obj->pos.x == pos.x && obj->pos.y == pos.y)
{
Rect dstRect(realPos.x - 2 * tileSize, realPos.y - tileSize, 3 * tileSize, 2 * tileSize);
drawHeroFlag(targetSurf, objData.flagBitmap, nullptr, &dstRect, false);
drawHeroFlag(targetSurf, objData.flagBitmap, nullptr, &dstRect, false);
}
}
}
@ -939,7 +946,7 @@ void CMapHandler::CMapBlitter::blit(SDL_Surface * targetSurf, const MapDrawingIn
{
if (pos.y < 0 || pos.y >= parent->sizes.y)
continue;
const bool isVisible = canDrawCurrentTile();
realTileRect.x = realPos.x;
@ -948,13 +955,13 @@ void CMapHandler::CMapBlitter::blit(SDL_Surface * targetSurf, const MapDrawingIn
const TerrainTile2 & tile = parent->ttiles[pos.x][pos.y][pos.z];
const TerrainTile & tinfo = parent->map->getTile(pos);
const TerrainTile * tinfoUpper = pos.y > 0 ? &parent->map->getTile(int3(pos.x, pos.y - 1, pos.z)) : nullptr;
if(isVisible || info->showAllTerrain)
{
drawTileTerrain(targetSurf, tinfo, tile);
if (tinfo.riverType)
drawRiver(targetSurf, tinfo);
drawRoad(targetSurf, tinfo, tinfoUpper);
drawRoad(targetSurf, tinfo, tinfoUpper);
}
if(isVisible)
@ -1010,8 +1017,8 @@ void CMapHandler::CMapBlitter::blit(SDL_Surface * targetSurf, const MapDrawingIn
}
}
}
drawOverlayEx(targetSurf);
drawOverlayEx(targetSurf);
// drawDebugGrid()
if (settings["session"]["showGrid"].Bool())
@ -1084,10 +1091,10 @@ CMapHandler::AnimBitmapHolder CMapHandler::CMapBlitter::findBoatBitmap(const CGB
}
SDL_Surface * CMapHandler::CMapBlitter::findFlagBitmap(const CGHeroInstance * hero, int anim, const PlayerColor * color, int indexOffset) const
{
{
if (!hero)
return nullptr;
if (hero->boat)
return findBoatFlagBitmap(hero->boat, anim, color, indexOffset, hero->moveDir);
return findHeroFlagBitmap(hero, anim, color, indexOffset);
@ -1114,8 +1121,8 @@ SDL_Surface * CMapHandler::CMapBlitter::findBoatFlagBitmap(const CGBoat * boat,
SDL_Surface * CMapHandler::CMapBlitter::findFlagBitmapInternal(const CDefEssential * def, int anim, int indexOffset, ui8 dir, bool moving) const
{
if (moving)
return def->ourImages[indexOffset + anim % FRAMES_PER_MOVE_ANIM_GROUP].bitmap;
return def->ourImages[getHeroFrameNum(dir, false) * FRAMES_PER_MOVE_ANIM_GROUP + (anim / 4) % FRAMES_PER_MOVE_ANIM_GROUP].bitmap;
return def->ourImages[indexOffset + anim % FRAMES_PER_MOVE_ANIM_GROUP].bitmap;
return def->ourImages[getHeroFrameNum(dir, false) * FRAMES_PER_MOVE_ANIM_GROUP + (anim / 4) % FRAMES_PER_MOVE_ANIM_GROUP].bitmap;
}
int CMapHandler::CMapBlitter::findAnimIndexByGroup(const CDefEssential * def, int groupNum) const
@ -1134,9 +1141,9 @@ CMapHandler::AnimBitmapHolder CMapHandler::CMapBlitter::findObjectBitmap(const C
return findHeroBitmap(static_cast<const CGHeroInstance*>(obj), anim);
if (obj->ID == Obj::BOAT)
return findBoatBitmap(static_cast<const CGBoat*>(obj), anim);
// normal object
// normal object
const std::vector<Cimage> &ourImages = graphics->getDef(obj)->ourImages;
SDL_Surface *bitmap = ourImages[(anim + getPhaseShift(obj)) % ourImages.size()].bitmap;
@ -1207,14 +1214,14 @@ std::pair<SDL_Surface *, bool> CMapHandler::CMapBlitter::getVisBitmap() const
}
bool CMapHandler::updateObjectsFade()
{
{
for (auto iter = fadeAnims.begin(); iter != fadeAnims.end(); )
{
int3 pos = (*iter).second.first;
CFadeAnimation * anim = (*iter).second.second;
anim->update();
if (anim->isFading())
++iter;
else // fade finished
@ -1223,7 +1230,7 @@ bool CMapHandler::updateObjectsFade()
for (auto objIter = objs.begin(); objIter != objs.end(); ++objIter)
{
if ((*objIter).fadeAnimKey == (*iter).first)
{
{
logAnim->traceStream() << "Fade anim finished for obj at " << pos << "; remaining: " << (fadeAnims.size() - 1);
if (anim->fadingMode == CFadeAnimation::EMode::OUT)
objs.erase(objIter); // if this was fadeout, remove the object from the map
@ -1232,10 +1239,11 @@ bool CMapHandler::updateObjectsFade()
break;
}
}
delete (*iter).second.second;
iter = fadeAnims.erase(iter);
}
}
return !fadeAnims.empty();
}
@ -1243,7 +1251,7 @@ bool CMapHandler::startObjectFade(TerrainTileObject & obj, bool in, int3 pos)
{
SDL_Surface * fadeBitmap;
assert(obj.obj);
auto objData = normalBlitter->findObjectBitmap(obj.obj, 0);
if (objData.objBitmap)
{
@ -1252,7 +1260,7 @@ bool CMapHandler::startObjectFade(TerrainTileObject & obj, bool in, int3 pos)
logAnim->debugStream() << "Ignoring fade of moving object";
return false;
}
fadeBitmap = CSDL_Ext::newSurface(32, 32); // TODO cache these bitmaps instead of creating new ones?
Rect objSrcRect(obj.rect.x, obj.rect.y, 32, 32);
CSDL_Ext::blit8bppAlphaTo24bpp(objData.objBitmap, &objSrcRect, fadeBitmap, nullptr);
@ -1268,12 +1276,12 @@ bool CMapHandler::startObjectFade(TerrainTileObject & obj, bool in, int3 pos)
anim->init(in ? CFadeAnimation::EMode::IN : CFadeAnimation::EMode::OUT, fadeBitmap, true);
fadeAnims[++fadeAnimCounter] = std::pair<int3, CFadeAnimation*>(pos, anim);
obj.fadeAnimKey = fadeAnimCounter;
logAnim->traceStream() << "Fade anim started for obj " << obj.obj->ID
logAnim->traceStream() << "Fade anim started for obj " << obj.obj->ID
<< " at " << pos << "; anim count: " << fadeAnims.size();
return true;
}
return false;
}
@ -1296,17 +1304,17 @@ bool CMapHandler::printObject(const CGObjectInstance *obj, bool fadein /* = fals
cr.x = fx*32;
cr.y = fy*32;
TerrainTileObject toAdd(obj, cr);
if((obj->pos.x + fx - tilesW+1)>=0 && (obj->pos.x + fx - tilesW+1)<ttiles.size()-frameW && (obj->pos.y + fy - tilesH+1)>=0 && (obj->pos.y + fy - tilesH+1)<ttiles[0].size()-frameH)
{
int3 pos(obj->pos.x + fx - tilesW + 1, obj->pos.y + fy - tilesH + 1, obj->pos.z);
TerrainTile2 & curt = ttiles[pos.x][pos.y][pos.z];
TerrainTile2 & curt = ttiles[pos.x][pos.y][pos.z];
if (fadein && ADVOPT.objectFading)
{
startObjectFade(toAdd, true, pos);
}
auto i = curt.objects.begin();
for(; i != curt.objects.end(); i++)
{
@ -1322,22 +1330,54 @@ bool CMapHandler::printObject(const CGObjectInstance *obj, bool fadein /* = fals
curt.objects.insert(i, toAdd);
}
} // for(int fy=0; fy<tilesH; ++fy)
} //for(int fx=0; fx<tilesW; ++fx)
}
}
return true;
}
bool CMapHandler::hideObject(const CGObjectInstance *obj, bool fadeout /* = false */)
{
// do we actually need to search through the whole map for this?
for (size_t i=0; i<map->width; i++)
//optimized version which reveals weird bugs with missing def name
//auto pos = obj->pos;
//for (size_t i = pos.x; i > pos.x - obj->getWidth(); i--)
//{
// for (size_t j = pos.y; j > pos.y - obj->getHeight(); j--)
// {
// int3 t(i, j, pos.z);
// if (!map->isInTheMap(t))
// continue;
// auto &objs = ttiles[i][j][pos.z].objects;
// for (size_t x = 0; x < objs.size(); x++)
// {
// auto ourObj = objs[x].obj;
// if (ourObj && ourObj->id == obj->id)
// {
// if (fadeout && ADVOPT.objectFading) // object should be faded == erase is delayed until the end of fadeout
// {
// if (startObjectFade(objs[x], false, t))
// objs[x].obj = nullptr; //set original pointer to null
// else
// objs.erase(objs.begin() + x);
// }
// else
// objs.erase(objs.begin() + x);
// break;
// }
// }
// }
//}
for (size_t i = 0; i<map->width; i++)
{
for (size_t j=0; j<map->height; j++)
for (size_t j = 0; j<map->height; j++)
{
for (size_t k=0; k<(map->twoLevel ? 2 : 1); k++)
for (size_t k = 0; k<(map->twoLevel ? 2 : 1); k++)
{
auto &objs = ttiles[i][j][k].objects;
for(size_t x=0; x < objs.size(); x++)
for (size_t x = 0; x < objs.size(); x++)
{
if (objs[x].obj && objs[x].obj->id == obj->id)
{
@ -1356,6 +1396,7 @@ bool CMapHandler::hideObject(const CGObjectInstance *obj, bool fadeout /* = fals
}
}
}
return true;
}
bool CMapHandler::removeObject(CGObjectInstance *obj, bool fadeout /* = false */)
@ -1503,7 +1544,7 @@ CMapHandler::~CMapHandler()
for(int j=0; j < elem.size(); ++j)
SDL_FreeSurface(elem[j]);
}
for (auto & elem : fadeAnims)
{
delete elem.second.second;
@ -1536,10 +1577,16 @@ void CMapHandler::getTerrainDescr( const int3 &pos, std::string & out, bool terN
}
}
if(t.hasFavourableWinds())
if(t.hasFavorableWinds())
out = CGI->objtypeh->getObjectName(Obj::FAVORABLE_WINDS);
else if(terName)
{
out = CGI->generaltexth->terrainNames[t.terType];
if(t.getDiggingStatus(false) == EDiggingStatus::CAN_DIG)
{
out = boost::str(boost::format("%s %s") % out % CGI->generaltexth->allTexts[330]); /// digging ok
}
}
}
void CMapHandler::discardWorldViewCache()

View File

@ -26,6 +26,8 @@ struct TerrainTile;
struct SDL_Surface;
struct SDL_Rect;
class CDefEssential;
class CAnimation;
class IImage;
class CFadeAnimation;
class PlayerColor;
@ -71,7 +73,7 @@ struct TerrainTileObject
const CGObjectInstance *obj;
SDL_Rect rect;
int fadeAnimKey;
TerrainTileObject(const CGObjectInstance *obj_, SDL_Rect rect_);
~TerrainTileObject();
};
@ -90,7 +92,7 @@ struct MapDrawingInfo
int3 &topTile; // top-left tile in viewport [in tiles]
const std::vector< std::vector< std::vector<ui8> > > * visibilityMap;
SDL_Rect * drawBounds; // map rect drawing bounds on screen
CDefHandler * iconsDef; // holds overlay icons for world view mode
std::shared_ptr<CAnimation> icons; // holds overlay icons for world view mode
float scale; // map scale for world view mode (only if scaled == true)
bool otherheroAnim;
@ -101,17 +103,17 @@ struct MapDrawingInfo
bool puzzleMode;
int3 grailPos; // location of grail for puzzle mode [in tiles]
const std::vector<ObjectPosInfo> * additionalIcons;
bool showAllTerrain; //for expert viewEarth
MapDrawingInfo(int3 &topTile_, const std::vector< std::vector< std::vector<ui8> > > * visibilityMap_, SDL_Rect * drawBounds_, CDefHandler * iconsDef_ = nullptr)
MapDrawingInfo(int3 &topTile_, const std::vector< std::vector< std::vector<ui8> > > * visibilityMap_, SDL_Rect * drawBounds_, std::shared_ptr<CAnimation> icons_ = nullptr)
: scaled(false),
topTile(topTile_),
visibilityMap(visibilityMap_),
drawBounds(drawBounds_),
iconsDef(iconsDef_),
icons(icons_),
scale(1.0f),
otherheroAnim(false),
anim(0u),
@ -188,14 +190,14 @@ class CMapHandler
SDL_Surface * cacheWorldViewEntry(EMapCacheType type, intptr_t key, SDL_Surface * entry);
intptr_t genKey(intptr_t realPtr, ui8 mod);
};
/// helper struct to pass around resolved bitmaps of an object; surfaces can be nullptr if object doesn't have bitmap of that type
struct AnimBitmapHolder
{
SDL_Surface * objBitmap; // main object bitmap
SDL_Surface * flagBitmap; // flag bitmap for the object (probably only for heroes and boats with heroes)
bool isMoving; // indicates if the object is moving (again, heroes/boats only)
AnimBitmapHolder(SDL_Surface * objBitmap_ = nullptr, SDL_Surface * flagBitmap_ = nullptr, bool moving = false)
: objBitmap(objBitmap_),
flagBitmap(flagBitmap_),
@ -205,7 +207,7 @@ class CMapHandler
class CMapBlitter
{
{
protected:
const int FRAMES_PER_MOVE_ANIM_GROUP = 8;
CMapHandler * parent; // ptr to enclosing map handler; generally for legacy reasons, probably could/should be refactored out of here
@ -267,16 +269,16 @@ class CMapHandler
virtual bool canDrawObject(const CGObjectInstance * obj) const;
virtual bool canDrawCurrentTile() const;
// internal helper methods to choose correct bitmap(s) for object; called internally by findObjectBitmap
AnimBitmapHolder findHeroBitmap(const CGHeroInstance * hero, int anim) const;
AnimBitmapHolder findBoatBitmap(const CGBoat * hero, int anim) const;
AnimBitmapHolder findBoatBitmap(const CGBoat * hero, int anim) const;
SDL_Surface * findFlagBitmap(const CGHeroInstance * obj, int anim, const PlayerColor * color, int indexOffset) const;
SDL_Surface * findHeroFlagBitmap(const CGHeroInstance * obj, int anim, const PlayerColor * color, int indexOffset) const;
SDL_Surface * findBoatFlagBitmap(const CGBoat * obj, int anim, const PlayerColor * color, int indexOffset, ui8 dir) const;
SDL_Surface * findFlagBitmapInternal(const CDefEssential * def, int anim, int indexOffset, ui8 dir, bool moving) const;
int findAnimIndexByGroup(const CDefEssential * def, int groupNum) const;
public:
CMapBlitter(CMapHandler * p) : parent(p) {}
virtual ~CMapBlitter(){}
@ -303,7 +305,7 @@ class CMapHandler
class CMapWorldViewBlitter : public CMapBlitter
{
private:
SDL_Surface * objectToIcon(Obj id, si32 subId, PlayerColor owner) const;
IImage * objectToIcon(Obj id, si32 subId, PlayerColor owner) const;
protected:
void drawElement(EMapCacheType cacheType, SDL_Surface * sourceSurf, SDL_Rect * sourceRect,
SDL_Surface * targetSurf, SDL_Rect * destRect, bool alphaBlit = false, ui8 rotationInfo = 0u) const override;
@ -312,7 +314,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;
@ -344,7 +346,7 @@ class CMapHandler
CMapBlitter * normalBlitter;
CMapBlitter * worldViewBlitter;
CMapBlitter * puzzleViewBlitter;
std::map<int, std::pair<int3, CFadeAnimation*>> fadeAnims;
int fadeAnimCounter;
@ -386,7 +388,7 @@ public:
void getTerrainDescr(const int3 &pos, std::string & out, bool terName); //if tername == false => empty string when tile is clear
CGObjectInstance * createObject(int id, int subid, int3 pos, int owner=254); //creates a new object with a certain id and subid
bool printObject(const CGObjectInstance * obj, bool fadein = false); //puts appropriate things to ttiles, so obj will be visible on map
bool printObject(const CGObjectInstance * obj, bool fadein = false); //puts appropriate things to tiles, so obj will be visible on map
bool hideObject(const CGObjectInstance * obj, bool fadeout = false); //removes appropriate things from ttiles, so obj will be no longer visible on map (but still will exist)
bool removeObject(CGObjectInstance * obj, bool fadeout = false); //removes object from each place in VCMI (I hope)
void init();

View File

@ -17,6 +17,8 @@
#include "../gui/CGuiHandler.h"
#include "../gui/SDL_Pixels.h"
#include "../widgets/Images.h"
#include "../windows/InfoWindows.h"
#include "../windows/CAdvmapInterface.h"
#include "../windows/GUIClasses.h"
@ -1121,24 +1123,11 @@ void CInGameConsole::keyPressed (const SDL_KeyboardEvent & key)
}
default:
{
#ifdef VCMI_SDL1
if(enteredText.size() > 0 && enteredText.size() < conf.go()->ac.inputLineLength)
{
if( key.keysym.unicode < 0x80 && key.keysym.unicode > 0 )
{
enteredText[enteredText.size()-1] = (char)key.keysym.unicode;
enteredText += "_";
refreshEnteredText();
}
}
#endif // VCMI_SDL1
break;
}
}
}
#ifndef VCMI_SDL1
void CInGameConsole::textInputed(const SDL_TextInputEvent & event)
{
if(!captureAllKeys || enteredText.size() == 0)
@ -1156,8 +1145,6 @@ void CInGameConsole::textEdited(const SDL_TextEditingEvent & event)
//do nothing here
}
#endif // VCMI_SDL1
void CInGameConsole::startEnteringText()
{
CSDL_Ext::startTextInput(&pos);
@ -1219,14 +1206,9 @@ void CInGameConsole::refreshEnteredText()
CInGameConsole::CInGameConsole() : prevEntDisp(-1), defaultTimeout(10000), maxDisplayedTexts(10)
{
#ifdef VCMI_SDL1
addUsedEvents(KEYBOARD);
#else
addUsedEvents(KEYBOARD | TEXTINPUT);
#endif
}
CAdvMapPanel::CAdvMapPanel(SDL_Surface * bg, Point position)
: CIntObject(),
background(bg)
@ -1276,11 +1258,11 @@ void CAdvMapPanel::addChildToPanel(CIntObject * obj, ui8 actions /* = 0 */)
addChild(obj, false);
}
CAdvMapWorldViewPanel::CAdvMapWorldViewPanel(SDL_Surface * bg, Point position, int spaceBottom, const PlayerColor &color)
: CAdvMapPanel(bg, position)
CAdvMapWorldViewPanel::CAdvMapWorldViewPanel(std::shared_ptr<CAnimation> _icons, SDL_Surface * bg, Point position, int spaceBottom, const PlayerColor &color)
: CAdvMapPanel(bg, position), icons(_icons)
{
fillerHeight = bg ? spaceBottom - pos.y - pos.h : 0;
if (fillerHeight > 0)
{
tmpBackgroundFiller = CMessage::drawDialogBox(pos.w, fillerHeight, color);
@ -1295,23 +1277,16 @@ CAdvMapWorldViewPanel::~CAdvMapWorldViewPanel()
SDL_FreeSurface(tmpBackgroundFiller);
}
void CAdvMapWorldViewPanel::recolorIcons(const PlayerColor &color, const CDefHandler *def, int indexOffset)
void CAdvMapWorldViewPanel::recolorIcons(const PlayerColor &color, int indexOffset)
{
for (auto &pic : currentIcons)
{
removeChild(pic);
delete pic;
}
currentIcons.clear();
assert(iconsData.size() == currentIcons.size());
for (auto &data : iconsData)
for(size_t idx = 0; idx < iconsData.size(); idx++)
{
auto pic = new CPicture(def->ourImages[data.first + indexOffset].bitmap, data.second.x, data.second.y, false);
pic->recActions |= SHOWALL;
currentIcons.push_back(pic);
addChildToPanel(pic);
const auto & data = iconsData.at(idx);
currentIcons[idx]->setFrame(data.first + indexOffset);
}
if (fillerHeight > 0)
{
if (tmpBackgroundFiller)
@ -1320,18 +1295,17 @@ void CAdvMapWorldViewPanel::recolorIcons(const PlayerColor &color, const CDefHan
}
}
void CAdvMapWorldViewPanel::addChildIcon(std::pair<int, Point> data, const CDefHandler *def, int indexOffset)
void CAdvMapWorldViewPanel::addChildIcon(std::pair<int, Point> data, int indexOffset)
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
iconsData.push_back(data);
auto pic = new CPicture(def->ourImages[data.first + indexOffset].bitmap, data.second.x, data.second.y, false);
currentIcons.push_back(pic);
addChildToPanel(pic);
currentIcons.push_back(new CAnimImage(icons, data.first + indexOffset, 0, data.second.x, data.second.y));
}
void CAdvMapWorldViewPanel::showAll(SDL_Surface * to)
{
if (tmpBackgroundFiller)
{
{
blitAt(tmpBackgroundFiller, pos.x, pos.y + pos.h, to);
}

View File

@ -4,6 +4,8 @@
#include "../../lib/FunctionList.h"
class CArmedInstance;
class CAnimation;
class CAnimImage;
class CShowableAnim;
class CGGarrison;
class CGObjectInstance;
@ -37,9 +39,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 +120,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 +154,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 +197,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 +215,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 +234,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 +258,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 +285,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 +333,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
@ -340,18 +342,19 @@ class CAdvMapWorldViewPanel : public CAdvMapPanel
/// data that allows reconstruction of panel info icons
std::vector<std::pair<int, Point>> iconsData;
/// ptrs to child-pictures constructed from iconsData
std::vector<CPicture *> currentIcons;
std::vector<CAnimImage *> currentIcons;
/// temporary surface drawn below world view panel on higher resolutions (won't be needed when world view panel is configured for extraResolutions mod)
SDL_Surface * tmpBackgroundFiller;
int fillerHeight;
std::shared_ptr<CAnimation> icons;
public:
CAdvMapWorldViewPanel(SDL_Surface * bg, Point position, int spaceBottom, const PlayerColor &color);
CAdvMapWorldViewPanel(std::shared_ptr<CAnimation> _icons, SDL_Surface * bg, Point position, int spaceBottom, const PlayerColor &color);
virtual ~CAdvMapWorldViewPanel();
void addChildIcon(std::pair<int, Point> data, const CDefHandler *def, int indexOffset);
void addChildIcon(std::pair<int, Point> data, 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 recolorIcons(const PlayerColor &color, int indexOffset);
void showAll(SDL_Surface * to) override;
};
class CInGameConsole : public CIntObject
@ -365,14 +368,12 @@ 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
#ifndef VCMI_SDL1
void textInputed(const SDL_TextInputEvent & event) override;
void textEdited(const SDL_TextEditingEvent & event) override;
#endif // VCMI_SDL1
void startEnteringText();
void endEnteringText(bool printEnteredText);

View File

@ -209,10 +209,10 @@ void CButton::hover (bool on)
setState(PRESSED);*/
std::string name = hoverTexts[getState()].empty()
? hoverTexts[getState()]
: hoverTexts[0];
? hoverTexts[0]
: hoverTexts[getState()];
if(!name.empty() && !isBlocked()) //if there is no name, there is nohing to display also
if(!name.empty() && !isBlocked()) //if there is no name, there is nothing to display also
{
if (LOCPLINT && LOCPLINT->battleInt) //for battle buttons
{
@ -272,10 +272,11 @@ void CButton::setIndex(size_t index, bool playerColoredButton)
if (index == currentImage || index>=imageNames.size())
return;
currentImage = index;
setImage(new CAnimation(imageNames[index]), playerColoredButton);
auto anim = std::make_shared<CAnimation>(imageNames[index]);
setImage(anim, playerColoredButton);
}
void CButton::setImage(CAnimation* anim, bool playerColoredButton, int animFlags)
void CButton::setImage(std::shared_ptr<CAnimation> anim, bool playerColoredButton, int animFlags)
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
@ -294,14 +295,9 @@ void CButton::setPlayerColor(PlayerColor player)
void CButton::showAll(SDL_Surface * to)
{
CIntObject::showAll(to);
#ifdef VCMI_SDL1
if (borderColor && borderColor->unused == 0)
CSDL_Ext::drawBorder(to, pos.x-1, pos.y-1, pos.w+2, pos.h+2, int3(borderColor->r, borderColor->g, borderColor->b));
#else
if (borderColor && borderColor->a == 0)
CSDL_Ext::drawBorder(to, pos.x-1, pos.y-1, pos.w+2, pos.h+2, int3(borderColor->r, borderColor->g, borderColor->b));
#endif // 0
}
std::pair<std::string, std::string> CButton::tooltip()
@ -424,8 +420,8 @@ void CToggleGroup::addToggle(int identifier, CToggleBase* bt)
buttons[identifier] = bt;
}
CToggleGroup::CToggleGroup(const CFunctionList<void(int)> &OnChange, bool musicLikeButtons)
: onChange(OnChange), selectedID(-2), musicLike(musicLikeButtons)
CToggleGroup::CToggleGroup(const CFunctionList<void(int)> &OnChange)
: onChange(OnChange), selectedID(-2)
{}
void CToggleGroup::setSelected(int id)
@ -452,26 +448,86 @@ void CToggleGroup::selectionChanged(int to)
parent->redraw();
}
void CToggleGroup::show(SDL_Surface * to)
CVolumeSlider::CVolumeSlider(const Point &position, const std::string &defName, const int value,
const std::pair<std::string, std::string> * const help) :
value(value),
helpHandlers(help)
{
if (musicLike)
{
if (auto intObj = dynamic_cast<CIntObject*>(buttons[selectedID])) // hack-ish workagound to avoid diamond problem with inheritance
intObj->show(to);
}
else
CIntObject::show(to);
OBJ_CONSTRUCTION_CAPTURING_ALL;
animImage = new CAnimImage(std::make_shared<CAnimation>(defName), 0, 0, position.x, position.y),
assert(!defName.empty());
addUsedEvents(LCLICK | RCLICK | WHEEL);
pos.x += position.x;
pos.y += position.y;
pos.w = (animImage->pos.w + 1) * animImage->size();
pos.h = animImage->pos.h;
type |= REDRAW_PARENT;
setVolume(value);
}
void CToggleGroup::showAll(SDL_Surface * to)
void CVolumeSlider::setVolume(int value_)
{
if (musicLike)
value = value_;
moveTo(value * static_cast<double>(animImage->size()) / 100.0);
}
void CVolumeSlider::moveTo(int id)
{
vstd::abetween(id, 0, animImage->size() - 1);
animImage->setFrame(id);
animImage->moveTo(Point(pos.x + (animImage->pos.w + 1) * id, pos.y));
if (active)
redraw();
}
void CVolumeSlider::addCallback(std::function<void(int)> callback)
{
onChange += callback;
}
void CVolumeSlider::clickLeft(tribool down, bool previousState)
{
if (down)
{
if (auto intObj = dynamic_cast<CIntObject*>(buttons[selectedID])) // hack-ish workagound to avoid diamond problem with inheritance
intObj->showAll(to);
double px = GH.current->motion.x - pos.x;
double rx = px / static_cast<double>(pos.w);
// setVolume is out of 100
setVolume(rx * 100);
// Volume config is out of 100, set to increments of 5ish roughly based on the half point of the indicator
// 0.0 -> 0, 0.05 -> 5, 0.09 -> 5,...,
// 0.1 -> 10, ..., 0.19 -> 15, 0.2 -> 20, ...,
// 0.28 -> 25, 0.29 -> 30, 0.3 -> 30, ...,
// 0.85 -> 85, 0.86 -> 90, ..., 0.87 -> 90,...,
// 0.95 -> 95, 0.96 -> 100, 0.99 -> 100
int volume = 5 * int(rx * (2 * animImage->size() + 1));
onChange(volume);
}
}
void CVolumeSlider::clickRight(tribool down, bool previousState)
{
if (down)
{
double px = GH.current->motion.x - pos.x;
int index = px / static_cast<double>(pos.w) * animImage->size();
std::string hoverText = helpHandlers[index].first;
std::string helpBox = helpHandlers[index].second;
if(!helpBox.empty())
CRClickPopup::createAndPush(helpBox);
if(GH.statusbar)
GH.statusbar->setText(helpBox);
}
}
void CVolumeSlider::wheelScrolled(bool down, bool in)
{
if (in)
{
int volume = value + 3 * (down ? 1 : -1);
vstd::abetween(volume, 0, 100);
setVolume(volume);
onChange(volume);
}
else
CIntObject::showAll(to);
}
void CSlider::sliderClicked()

View File

@ -10,7 +10,6 @@ struct Rect;
class CAnimImage;
class CLabel;
class CAnimation;
class CDefHandler;
namespace config
{
@ -111,7 +110,7 @@ public:
/// Appearance modifiers
void setIndex(size_t index, bool playerColoredButton=false);
void setImage(CAnimation* anim, bool playerColoredButton=false, int animFlags=0);
void setImage(std::shared_ptr<CAnimation> anim, bool playerColoredButton=false, int animFlags=0);
void setPlayerColor(PlayerColor player);
/// CIntObject overrides
@ -178,12 +177,11 @@ class CToggleGroup : public CIntObject
CFunctionList<void(int)> onChange; //called when changing selected button with new button's id
int selectedID;
bool musicLike; //determines the behaviour of this group
void selectionChanged(int to);
public:
std::map<int, CToggleBase*> buttons;
CToggleGroup(const CFunctionList<void(int)> & OnChange, bool musicLikeButtons = false);
CToggleGroup(const CFunctionList<void(int)> & OnChange);
void addCallback(std::function<void(int)> callback);
@ -191,9 +189,32 @@ public:
void addToggle(int index, CToggleBase * button);
/// Changes selection to specific value. Will select toggle with this ID, if present
void setSelected(int id);
};
void show(SDL_Surface * to);
void showAll(SDL_Surface * to);
/// A typical slider for volume with an animated indicator
class CVolumeSlider : public CIntObject
{
int value;
CFunctionList<void(int)> onChange;
CAnimImage * animImage;
const std::pair<std::string, std::string> * const helpHandlers;
void setVolume(const int v);
public:
/// @param position coordinates of slider
/// @param defName name of def animation for slider
/// @param value initial value for volume
/// @param help pointer to first helptext of slider
CVolumeSlider(const Point &position, const std::string &defName, const int value,
const std::pair<std::string, std::string> * const help);
void moveTo(int id);
void addCallback(std::function<void(int)> callback);
void clickLeft(tribool down, bool previousState) override;
void clickRight(tribool down, bool previousState) override;
void wheelScrolled(bool down, bool in) override;
};
/// A typical slider which can be orientated horizontally/vertically.
@ -242,20 +263,18 @@ 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
* @param Moved, function that will be called whenever slider moves
* @param Capacity, maximal number of visible at once elements
* @param Amount, total amount of elements, including not visible
* @param Value, starting position
*/
/// @param position coordinates of slider
/// @param length length of slider ribbon, including left/right buttons
/// @param Moved function that will be called whenever slider moves
/// @param Capacity maximal number of visible at once elements
/// @param Amount total amount of elements, including not visible
/// @param Value starting position
CSlider(Point position, int length, std::function<void(int)> Moved, int Capacity, int Amount,
int Value=0, bool Horizontal=true, EStyle style = BROWN);
~CSlider();

View File

@ -32,7 +32,7 @@
*/
CArtPlace::CArtPlace(Point position, const CArtifactInstance * Art):
locked(false), picked(false), marked(false), ourArt(Art)
locked(false), picked(false), marked(false), ourArt(Art)
{
pos += position;
pos.w = pos.h = 44;
@ -123,10 +123,7 @@ void CArtPlace::clickLeft(tribool down, bool previousState)
if(ourArt && !down && previousState && !ourOwner->commonInfo->src.AOH)
{
if(ourArt->artType->id == ArtifactID::SPELLBOOK)
{
auto spellWindow = new CSpellWindow(genRect(595, 620, (screen->w - 620)/2, (screen->h - 595)/2), ourOwner->curHero, LOCPLINT, LOCPLINT->battleInt);
GH.pushInt(spellWindow);
}
GH.pushInt(new CSpellWindow(ourOwner->curHero, LOCPLINT, LOCPLINT->battleInt));
}
if (!down && previousState)
@ -180,7 +177,7 @@ void CArtPlace::clickLeft(tribool down, bool previousState)
if(srcInBackpack && srcInSameHero)
{
if(!ourArt //cannot move from backpack to AFTER backpack -> combined with vstd::amin above it will guarantee that dest is at most the last artifact
|| ourOwner->commonInfo->src.slotID < ourOwner->commonInfo->dst.slotID) //rearranging arts in backpack after taking src artifact, the dest id will be shifted
|| ourOwner->commonInfo->src.slotID < ourOwner->commonInfo->dst.slotID) //rearranging arts in backpack after taking src artifact, the dest id will be shifted
vstd::advance(ourOwner->commonInfo->dst.slotID, -1);
}
if(srcInSameHero && ourOwner->commonInfo->dst.slotID == ourOwner->commonInfo->src.slotID) //we came to src == dst
@ -214,6 +211,34 @@ void CArtPlace::clickLeft(tribool down, bool previousState)
}
}
bool CArtPlace::askToAssemble(const CArtifactInstance *art, ArtifactPosition slot,
const CGHeroInstance *hero)
{
assert(art != nullptr);
assert(hero != nullptr);
std::vector<const CArtifact *> assemblyPossibilities = art->assemblyPossibilities(hero);
// If the artifact can be assembled, display dialog.
for(const CArtifact *combination : assemblyPossibilities)
{
LOCPLINT->showArtifactAssemblyDialog(
art->artType->id,
combination->id,
true,
std::bind(&CCallback::assembleArtifacts, LOCPLINT->cb.get(), hero, slot, true, combination->id),
0);
if(assemblyPossibilities.size() > 2)
{
logGlobal->warnStream() << boost::format(
"More than one possibility of assembling on %s... taking only first")
% art->artType->Name();
}
return true;
}
return false;
}
void CArtPlace::clickRight(tribool down, bool previousState)
{
if(down && ourArt && !locked && text.size() && !picked) //if there is no description or it's a lock, do nothing ;]
@ -225,20 +250,8 @@ void CArtPlace::clickRight(tribool down, bool previousState)
std::vector<const CArtifact *> assemblyPossibilities = ourArt->assemblyPossibilities(ourOwner->curHero);
// If the artifact can be assembled, display dialog.
for(const CArtifact *combination : assemblyPossibilities)
if (askToAssemble(ourArt, slotID, ourOwner->curHero))
{
LOCPLINT->showArtifactAssemblyDialog(
ourArt->artType->id,
combination->id,
true,
std::bind(&CCallback::assembleArtifacts, LOCPLINT->cb.get(), ourOwner->curHero, slotID, true, combination->id),
0);
if(assemblyPossibilities.size() > 2)
{
logGlobal->warnStream() << "More than one possibility of assembling... taking only first";
break;
}
return;
}
@ -303,10 +316,10 @@ void CArtPlace::deselect ()
for(int i = 0; i < GameConstants::BACKPACK_START; i++)
{
auto place = ourOwner->getArtPlace(i);
if(nullptr != place)//getArtPlace may return null
place->pickSlot(false);
}
}
}
CCS->curh->dragAndDropCursor(nullptr);
@ -372,70 +385,36 @@ void CArtPlace::setArtifact(const CArtifactInstance *art)
image->disable();
text = std::string();
hoverText = CGI->generaltexth->allTexts[507];
return;
}
image->enable();
image->setFrame(locked ? ArtifactID::ART_LOCK : art->artType->iconIndex);
text = art->getEffectiveDescription(ourOwner->curHero);
if(art->artType->id == ArtifactID::SPELL_SCROLL)
{
int spellID = art->getGivenSpellID();
if(spellID >= 0)
{
//add spell component info (used to provide a pic in r-click popup)
baseType = CComponent::spell;
type = spellID;
bonusValue = 0;
}
}
else
{
image->enable();
image->setFrame(locked ? ArtifactID::ART_LOCK : art->artType->iconIndex);
std::string artDesc = ourArt->artType->Description();
if (vstd::contains (artDesc, '{'))
text = artDesc;
else
text = '{' + ourArt->artType->Name() + "}\n\n" + artDesc; //workaround for new artifacts with single name, turns it to H3-style
if(art->artType->id == ArtifactID::SPELL_SCROLL)
{
// we expect scroll description to be like this: This scroll contains the [spell name] spell which is added into your spell book for as long as you carry the scroll.
// so we want to replace text in [...] with a spell name
// however other language versions don't have name placeholder at all, so we have to be careful
int spellID = art->getGivenSpellID();
size_t nameStart = text.find_first_of('[');
size_t nameEnd = text.find_first_of(']', nameStart);
if(spellID >= 0)
{
if(nameStart != std::string::npos && nameEnd != std::string::npos)
text = text.replace(nameStart, nameEnd - nameStart + 1, CGI->spellh->objects[spellID]->name);
//add spell component info (used to provide a pic in r-click popup)
baseType = CComponent::spell;
type = spellID;
bonusValue = 0;
}
}
else
{
baseType = CComponent::artifact;
type = art->artType->id;
bonusValue = 0;
}
if (art->artType->constituents) //display info about components of combined artifact
{
//TODO
}
else if (art->artType->constituentOf.size()) //display info about set
{
std::string artList;
auto combinedArt = art->artType->constituentOf[0];
text += "\n\n";
text += "{" + combinedArt->Name() + "}";
int wornArtifacts = 0;
for (auto a : *combinedArt->constituents) //TODO: can the artifact be a part of more than one set?
{
artList += "\n" + a->Name();
if (ourOwner->curHero->hasArt(a->id, true))
wornArtifacts++;
}
text += " (" + boost::str(boost::format("%d") % wornArtifacts) + " / " +
boost::str(boost::format("%d") % combinedArt->constituents->size()) + ")" + artList;
//TODO: fancy colors and fonts for this text
}
if (locked) // Locks should appear as empty.
hoverText = CGI->generaltexth->allTexts[507];
else
hoverText = boost::str(boost::format(CGI->generaltexth->heroscrn[1]) % ourArt->artType->Name());
baseType = CComponent::artifact;
type = art->artType->id;
bonusValue = 0;
}
if (locked) // Locks should appear as empty.
hoverText = CGI->generaltexth->allTexts[507];
else
hoverText = boost::str(boost::format(CGI->generaltexth->heroscrn[1]) % ourArt->artType->Name());
}
void CArtifactsOfHero::SCommonPart::reset()
@ -454,12 +433,12 @@ void CArtifactsOfHero::setHero(const CGHeroInstance * hero)
backpackPos = 0;
// Fill the slots for worn artifacts and backpack.
for(auto p : artWorn)
{
setSlotData(p.second, p.first);
}
scrollBackpack(0);
}
@ -587,8 +566,8 @@ void CArtifactsOfHero::setSlotData(CArtPlace* artPlace, ArtifactPosition slotID)
if(const ArtSlotInfo *asi = curHero->getSlot(slotID))
{
artPlace->setArtifact(asi->artifact);
artPlace->lockSlot(asi->locked);
artPlace->setArtifact(asi->artifact);
}
else
artPlace->setArtifact(nullptr);
@ -615,7 +594,7 @@ CArtifactsOfHero::CArtifactsOfHero(std::map<ArtifactPosition, CArtPlace *> ArtWo
{
if(createCommonPart)
{
commonInfo = new CArtifactsOfHero::SCommonPart;
commonInfo = std::make_shared<CArtifactsOfHero::SCommonPart>();
commonInfo->participants.insert(this);
}
@ -642,7 +621,7 @@ CArtifactsOfHero::CArtifactsOfHero(const Point& position, bool createCommonPart
{
if(createCommonPart)
{
commonInfo = new CArtifactsOfHero::SCommonPart;
commonInfo = std::make_shared<CArtifactsOfHero::SCommonPart>();
commonInfo->participants.insert(this);
}
@ -797,7 +776,7 @@ void CArtifactsOfHero::artifactMoved(const ArtifactLocation &src, const Artifact
}
else if(src.slot >= GameConstants::BACKPACK_START &&
src.slot < commonInfo->src.slotID &&
src.isHolder(commonInfo->src.AOH->curHero)) //artifact taken from before currently picked one
src.isHolder(commonInfo->src.AOH->curHero)) //artifact taken from before currently picked one
{
//int fixedSlot = src.hero->getArtPos(commonInfo->src.art);
vstd::advance(commonInfo->src.slotID, -1);
@ -811,14 +790,14 @@ void CArtifactsOfHero::artifactMoved(const ArtifactLocation &src, const Artifact
}
updateParentWindow();
int shift = 0;
int shift = 0;
// if(dst.slot >= Arts::BACKPACK_START && dst.slot - Arts::BACKPACK_START < backpackPos)
// shift++;
//
if(src.slot < GameConstants::BACKPACK_START && dst.slot - GameConstants::BACKPACK_START < backpackPos)
if(src.slot < GameConstants::BACKPACK_START && dst.slot - GameConstants::BACKPACK_START < backpackPos)
shift++;
if(dst.slot < GameConstants::BACKPACK_START && src.slot - GameConstants::BACKPACK_START < backpackPos)
shift--;
shift--;
if( (isCurHeroSrc && src.slot >= GameConstants::BACKPACK_START)
|| (isCurHeroDst && dst.slot >= GameConstants::BACKPACK_START) )
@ -853,7 +832,7 @@ CArtPlace * CArtifactsOfHero::getArtPlace(int slot)
for(CArtPlace *ap : backpack)
if(ap->slotID == slot)
return ap;
return nullptr;
return nullptr;
}
}

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