1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-30 08:57:00 +02:00
vcmi/client/CPlayerInterface.cpp
Michał W. Urbańczyk 617e1f962e New files for lib:
* lib/ERMScriptModule.cpp
* lib/ERMScriptModule.h
* lib/CObstacleInstance.h

More jugglery with callbacks. Moving stuff from CGameState to CGameInfoCallback. Work on unified game events interface for player (AI or GUI) and script module. Directing events to ERM interpretetr, first attempts of calling some triggers. Crashy, if there any scripts.
Some other changes, including fighting amount of includes in includes and tracking of hero visits (need further work).
2011-05-09 22:20:47 +00:00

2226 lines
74 KiB
C++

#include "../stdafx.h"
#include "CAdvmapInterface.h"
#include "CBattleInterface.h"
#include "../CCallback.h"
#include "CCastleInterface.h"
#include "CCursorHandler.h"
#include "CGameInfo.h"
#include "CHeroWindow.h"
#include "CMessage.h"
#include "CPlayerInterface.h"
//#include "SDL_Extensions.h"
#include "SDL_Extensions.h"
#include "SDL_framerate.h"
#include "CConfigHandler.h"
#include "CCreatureAnimation.h"
#include "Graphics.h"
#include "../lib/CArtHandler.h"
#include "../lib/CGeneralTextHandler.h"
#include "../lib/CHeroHandler.h"
#include "../lib/CLodHandler.h"
#include "../lib/CObjectHandler.h"
#include "../lib/Connection.h"
#include "../lib/CSpellHandler.h"
#include "../lib/CTownHandler.h"
#include "../lib/BattleState.h"
#include "CMusicHandler.h"
#include "../lib/CondSh.h"
#include "../lib/NetPacks.h"
#include "../lib/map.h"
#include "../lib/VCMIDirs.h"
#include "mapHandler.h"
#include "../timeHandler.h"
#include <boost/lexical_cast.hpp>
#include <boost/format.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/assign/std/vector.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread.hpp>
#include <cmath>
#include <queue>
#include <sstream>
#include <boost/filesystem.hpp>
#include "../StartInfo.h"
#include <boost/foreach.hpp>
#include "../lib/CGameState.h"
#ifdef min
#undef min
#endif
#ifdef max
#undef max
#endif
/*
* CPlayerInterface.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
*
*/
using namespace boost::assign;
using namespace CSDL_Ext;
void processCommand(const std::string &message, CClient *&client);
extern std::queue<SDL_Event*> events;
extern boost::mutex eventsM;
CPlayerInterface * LOCPLINT;
CBattleInterface * CPlayerInterface::battleInt;
enum EMoveState {STOP_MOVE, WAITING_MOVE, CONTINUE_MOVE, DURING_MOVE};
CondSh<EMoveState> stillMoveHero; //used during hero movement
int CPlayerInterface::howManyPeople = 0;
struct OCM_HLP_CGIN
{
bool inline operator ()(const std::pair<const CGObjectInstance*,SDL_Rect> & a, const std::pair<const CGObjectInstance*,SDL_Rect> & b) const
{
return (*a.first)<(*b.first);
}
} ocmptwo_cgin ;
CPlayerInterface::CPlayerInterface(int Player)
{
observerInDuelMode = false;
howManyPeople++;
GH.defActionsDef = 0;
LOCPLINT = this;
curAction = NULL;
playerID=Player;
human=true;
castleInt = NULL;
battleInt = NULL;
//pim = new boost::recursive_mutex;
makingTurn = false;
showingDialog = new CondSh<bool>(false);
sysOpts = GDefaultOptions;
cingconsole = new CInGameConsole;
terminate_cond.set(false);
firstCall = 1; //if loading will be overwritten in serialize
autosaveCount = 0;
}
CPlayerInterface::~CPlayerInterface()
{
howManyPeople--;
//delete pim;
//delNull(pim);
delete showingDialog;
if(adventureInt)
{
if(adventureInt->active & CIntObject::KEYBOARD)
adventureInt->deactivateKeys();
delete adventureInt;
adventureInt = NULL;
}
if(cingconsole->active) //TODO
cingconsole->deactivate();
delete cingconsole;
LOCPLINT = NULL;
}
void CPlayerInterface::init(CCallback * CB)
{
cb = dynamic_cast<CCallback*>(CB);
if(observerInDuelMode)
{
return;
}
if(!adventureInt)
adventureInt = new CAdvMapInt();
if(!towns.size() && !wanderingHeroes.size())
{
recreateHeroTownList();
}
}
void CPlayerInterface::yourTurn()
{
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
boost::unique_lock<boost::mutex> lock(eventsM); //block handling events until interface is ready
LOCPLINT = this;
GH.curInt = this;
adventureInt->selection = NULL;
if(firstCall)
{
if(howManyPeople == 1)
adventureInt->setPlayer(playerID);
autosaveCount = getLastIndex("Autosave_");
if(!GH.listInt.size())
{
GH.pushInt(adventureInt);
adventureInt->activateKeys();
}
if(firstCall > 0) //new game, not loaded
{
int index = getLastIndex("Newgame_Autosave_");
index %= SAVES_COUNT;
cb->save("Newgame_Autosave_" + boost::lexical_cast<std::string>(index + 1));
}
firstCall = 0;
}
else
{
LOCPLINT->cb->save("Autosave_" + boost::lexical_cast<std::string>(autosaveCount++ + 1));
autosaveCount %= 5;
}
if(adventureInt->player != playerID)
adventureInt->setPlayer(playerID);
if(howManyPeople > 1) //hot seat message
{
adventureInt->startHotSeatWait(playerID);
makingTurn = true;
std::string msg = CGI->generaltexth->allTexts[13];
boost::replace_first(msg, "%s", cb->getStartInfo()->playerInfos.find(playerID)->second.name);
std::vector<SComponent*> cmp;
cmp.push_back(new SComponent(SComponent::flag, playerID, 0));
showInfoDialog(msg, cmp);
}
else
{
makingTurn = true;
adventureInt->startTurn();
}
}
acceptTurn();
}
STRONG_INLINE void subRect(const int & x, const int & y, const int & z, const SDL_Rect & r, const int & hid)
{
TerrainTile2 & hlp = CGI->mh->ttiles[x][y][z];
for(int h=0; h<hlp.objects.size(); ++h)
if(hlp.objects[h].first->id==hid)
{
hlp.objects[h].second = r;
return;
}
}
STRONG_INLINE void delObjRect(const int & x, const int & y, const int & z, const int & hid)
{
TerrainTile2 & hlp = CGI->mh->ttiles[x][y][z];
for(int h=0; h<hlp.objects.size(); ++h)
if(hlp.objects[h].first->id==hid)
{
hlp.objects.erase(hlp.objects.begin()+h);
return;
}
}
void CPlayerInterface::heroMoved(const TryMoveHero & details)
{
if(LOCPLINT != this)
return;
boost::unique_lock<boost::recursive_mutex> un(*pim);
const CGHeroInstance * ho = cb->getHero(details.id); //object representing this hero
int3 hp = details.start;
adventureInt->centerOn(ho); //actualizing screen pos
adventureInt->minimap.draw(screen2);
adventureInt->heroList.draw(screen2);
bool directlyAttackingCreature =
CGI->mh->map->isInTheMap(details.attackedFrom)
&& adventureInt->terrain.currentPath //in case if movement has been canceled in the meantime and path was already erased
&& adventureInt->terrain.currentPath->nodes.size() == 3;//FIXME should be 2 but works nevertheless...
if(makingTurn && ho->tempOwner == playerID) //we are moving our hero - we may need to update assigned path
{
if(details.result == TryMoveHero::TELEPORTATION || details.start == details.end)
{
if(adventureInt->terrain.currentPath)
eraseCurrentPathOf(ho);
return; //teleport - no fancy moving animation
//TODO: smooth disappear / appear effect
}
if ((details.result != TryMoveHero::SUCCESS && details.result != TryMoveHero::FAILED) //hero didn't change tile but visit succeeded
|| directlyAttackingCreature) // or creature was attacked from endangering tile.
{
eraseCurrentPathOf(ho);
}
else if(adventureInt->terrain.currentPath && details.result == TryMoveHero::SUCCESS) //&& hero is moving
{
//remove one node from the path (the one we went)
adventureInt->terrain.currentPath->nodes.erase(adventureInt->terrain.currentPath->nodes.end()-1);
if(!adventureInt->terrain.currentPath->nodes.size()) //if it was the last one, remove entire path
eraseCurrentPathOf(ho);
}
}
if (details.result != TryMoveHero::SUCCESS) //hero failed to move
{
ho->isStanding = true;
stillMoveHero.setn(STOP_MOVE);
GH.totalRedraw();
return;
}
initMovement(details, ho, hp);
//first initializing done
GH.mainFPSmng->framerateDelay(); // after first move
//main moving
for(int i=1; i<32; i+=2*sysOpts.heroMoveSpeed)
{
movementPxStep(details, i, hp, ho);
adventureInt->updateScreen = true;
adventureInt->show(screen);
CSDL_Ext::update(screen);
GH.mainFPSmng->framerateDelay(); //for animation purposes
} //for(int i=1; i<32; i+=4)
//main moving done
//finishing move
finishMovement(details, hp, ho);
ho->isStanding = true;
//move finished
adventureInt->minimap.draw(screen2);
adventureInt->heroList.updateMove(ho);
//check if user cancelled movement
{
boost::unique_lock<boost::mutex> un(eventsM);
while(events.size())
{
SDL_Event *ev = events.front();
events.pop();
switch(ev->type)
{
case SDL_MOUSEBUTTONDOWN:
stillMoveHero.setn(STOP_MOVE);
break;
case SDL_KEYDOWN:
if(ev->key.keysym.sym < SDLK_F1 || ev->key.keysym.sym > SDLK_F15)
stillMoveHero.setn(STOP_MOVE);
break;
}
delete ev;
}
}
if(stillMoveHero.get() == WAITING_MOVE)
stillMoveHero.setn(DURING_MOVE);
// Hero attacked creature directly, set direction to face it.
if (directlyAttackingCreature) {
// Get direction to attacker.
int3 posOffset = details.attackedFrom - details.end + int3(2, 1, 0);
static const ui8 dirLookup[3][3] = {
{ 1, 2, 3 },
{ 8, 0, 4 },
{ 7, 6, 5 }
};
// FIXME: Avoid const_cast, make moveDir mutable in some other way?
const_cast<CGHeroInstance *>(ho)->moveDir = dirLookup[posOffset.y][posOffset.x];
}
}
void CPlayerInterface::heroKilled(const CGHeroInstance* hero)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
wanderingHeroes -= hero;
if(vstd::contains(paths, hero))
paths.erase(hero);
adventureInt->heroList.updateHList(hero);
}
void CPlayerInterface::heroCreated(const CGHeroInstance * hero)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
wanderingHeroes.push_back(hero);
adventureInt->heroList.updateHList();
}
void CPlayerInterface::openTownWindow(const CGTownInstance * town)
{
if (castleInt)
GH.popIntTotally(castleInt);
castleInt = new CCastleInterface(town);
GH.pushInt(castleInt);
}
SDL_Surface * CPlayerInterface::infoWin(const CGObjectInstance * specific) //specific=0 => draws info about selected town/hero
{
if(!specific)
specific = adventureInt->selection;
assert(specific);
switch(specific->ID)
{
case HEROI_TYPE:
{
InfoAboutHero iah;
bool gotInfo = LOCPLINT->cb->getHeroInfo(specific, iah);
assert(gotInfo);
return graphics->drawHeroInfoWin(iah);
}
case TOWNI_TYPE:
case 33: // Garrison
case 219:
{
InfoAboutTown iah;
bool gotInfo = LOCPLINT->cb->getTownInfo(specific, iah);
assert(gotInfo);
return graphics->drawTownInfoWin(iah);
}
default:
return NULL;
}
}
int3 CPlayerInterface::repairScreenPos(int3 pos)
{
if(pos.x<-CGI->mh->frameW)
pos.x = -CGI->mh->frameW;
if(pos.y<-CGI->mh->frameH)
pos.y = -CGI->mh->frameH;
if(pos.x>CGI->mh->sizes.x - adventureInt->terrain.tilesw + CGI->mh->frameW)
pos.x = CGI->mh->sizes.x - adventureInt->terrain.tilesw + CGI->mh->frameW;
if(pos.y>CGI->mh->sizes.y - adventureInt->terrain.tilesh + CGI->mh->frameH)
pos.y = CGI->mh->sizes.y - adventureInt->terrain.tilesh + CGI->mh->frameH;
return pos;
}
void CPlayerInterface::heroPrimarySkillChanged(const CGHeroInstance * hero, int which, si64 val)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
if(which == 4)
{
if(CAltarWindow *ctw = dynamic_cast<CAltarWindow *>(GH.topInt()))
ctw->setExpToLevel();
}
else if(which < PRIMARY_SKILLS) //no need to redraw infowin if this is experience (exp is treated as prim skill with id==4)
updateInfo(hero);
}
void CPlayerInterface::heroSecondarySkillChanged(const CGHeroInstance * hero, int which, int val)
{
CUniversityWindow* cuw = dynamic_cast<CUniversityWindow*>(GH.topInt());
if(cuw) //university window is open
{
GH.totalRedraw();
}
}
void CPlayerInterface::heroManaPointsChanged(const CGHeroInstance * hero)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
updateInfo(hero);
}
void CPlayerInterface::heroMovePointsChanged(const CGHeroInstance * hero)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
if(makingTurn && hero->tempOwner == playerID)
adventureInt->heroList.redraw();
}
void CPlayerInterface::receivedResource(int type, int val)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
if(CMarketplaceWindow *mw = dynamic_cast<CMarketplaceWindow *>(GH.topInt()))
mw->resourceChanged(type, val);
GH.totalRedraw();
}
void CPlayerInterface::heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16>& skills, boost::function<void(ui32)> &callback)
{
waitWhileDialog();
CCS->soundh->playSound(soundBase::heroNewLevel);
boost::unique_lock<boost::recursive_mutex> un(*pim);
CLevelWindow *lw = new CLevelWindow(hero,pskill,skills,callback);
GH.pushInt(lw);
}
void CPlayerInterface::heroInGarrisonChange(const CGTownInstance *town)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
updateInfo(town);
if(town->garrisonHero && vstd::contains(wanderingHeroes,town->garrisonHero)) //wandering hero moved to the garrison
{
CGI->mh->hideObject(town->garrisonHero);
wanderingHeroes -= town->garrisonHero;
}
if(town->visitingHero && !vstd::contains(wanderingHeroes,town->visitingHero)) //hero leaves garrison
{
CGI->mh->printObject(town->visitingHero);
wanderingHeroes.push_back(town->visitingHero);
}
if(CCastleInterface *c = castleInt)
{
c->garr->highlighted = NULL;
c->garr->setArmy(town->getUpperArmy(), 0);
c->garr->setArmy(town->visitingHero, 1);
c->garr->recreateSlots();
c->heroes->update();
}
GH.totalRedraw();
}
void CPlayerInterface::heroVisitsTown(const CGHeroInstance* hero, const CGTownInstance * town)
{
if(hero->tempOwner != playerID )
return;
boost::unique_lock<boost::recursive_mutex> un(*pim);
openTownWindow(town);
}
void CPlayerInterface::garrisonChanged( const CGObjectInstance * obj, bool updateInfobox /*= true*/ )
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
if(updateInfobox)
updateInfo(obj);
for(std::list<IShowActivable*>::iterator i = GH.listInt.begin(); i != GH.listInt.end(); i++)
{
if((*i)->type & IShowActivable::WITH_GARRISON)
{
CGarrisonHolder *cgh = dynamic_cast<CGarrisonHolder*>(*i);
cgh->updateGarrisons();
}
else if(CTradeWindow *cmw = dynamic_cast<CTradeWindow*>(*i))
{
if(obj == cmw->hero)
cmw->garrisonChanged();
}
}
GH.totalRedraw();
}
void CPlayerInterface::buildChanged(const CGTownInstance *town, int buildingID, int what) //what: 1 - built, 2 - demolished
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
switch (buildingID)
{
case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 15:
updateInfo(town);
break;
}
if(!castleInt)
return;
if(castleInt->town!=town)
return;
switch(what)
{
case 1:
CCS->soundh->playSound(soundBase::newBuilding);
castleInt->addBuilding(buildingID);
break;
case 2:
castleInt->removeBuilding(buildingID);
break;
}
}
void CPlayerInterface::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side)
{
if(LOCPLINT != this)
{ //another local interface should do this
return;
}
while(showingDialog->get())
SDL_Delay(20);
boost::unique_lock<boost::recursive_mutex> un(*pim);
CCS->musich->playMusicFromSet(CCS->musich->battleMusics, -1);
GH.pushInt(battleInt);
}
void CPlayerInterface::battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks, bool lifeDrain, si32 lifeDrainFrom)
{
if(LOCPLINT != this)
{ //another local interface should do this
return;
}
for(int b=0; b<healedStacks.size(); ++b)
{
const CStack * healed = cb->battleGetStackByID(healedStacks[b].first);
if(battleInt->creAnims[healed->ID]->getType() == CCreatureAnim::DEATH)
{
//stack has been resurrected
battleInt->creAnims[healed->ID]->setType(CCreatureAnim::HOLDING);
}
}
if (lifeDrain)
{
const CStack *attacker = cb->battleGetStackByID(healedStacks[0].first, false);
const CStack *defender = cb->battleGetStackByID(lifeDrainFrom, false);
int textOff = 0;
if (attacker)
{
battleInt->displayEffect(50, attacker->position);
if (attacker->count > 1)
{
textOff += 1;
}
}
//print info about life drain
char textBuf[1000];
sprintf(textBuf, CGI->generaltexth->allTexts[361 + textOff].c_str(), attacker->getCreature()->nameSing.c_str(),
healedStacks[0].second, defender->getCreature()->namePl.c_str());
battleInt->console->addText(textBuf);
}
}
void CPlayerInterface::battleNewStackAppeared(const CStack * stack)
{
if(LOCPLINT != this)
{ //another local interface should do this
return;
}
//changing necessary things in battle interface
battleInt->newStack(stack);
}
void CPlayerInterface::battleObstaclesRemoved(const std::set<si32> & removedObstacles)
{
if(LOCPLINT != this)
{ //another local interface should do this
return;
}
for(std::set<si32>::const_iterator it = removedObstacles.begin(); it != removedObstacles.end(); ++it)
{
for(std::map< int, CDefHandler * >::iterator itBat = battleInt->idToObstacle.begin(); itBat != battleInt->idToObstacle.end(); ++itBat)
{
if(itBat->first == *it) //remove this obstacle
{
battleInt->idToObstacle.erase(itBat);
break;
}
}
}
//update accessible hexes
battleInt->redrawBackgroundWithHexes(battleInt->activeStack);
}
void CPlayerInterface::battleCatapultAttacked(const CatapultAttack & ca)
{
if(LOCPLINT != this)
{ //another local interface should do this
return;
}
boost::unique_lock<boost::recursive_mutex> un(*pim);
battleInt->stackIsCatapulting(ca);
}
void CPlayerInterface::battleStacksRemoved(const BattleStacksRemoved & bsr)
{
if(LOCPLINT != this)
{ //another local interface should do this
return;
}
boost::unique_lock<boost::recursive_mutex> un(*pim);
for(std::set<ui32>::const_iterator it = bsr.stackIDs.begin(); it != bsr.stackIDs.end(); ++it) //for each removed stack
{
battleInt->stackRemoved(LOCPLINT->cb->battleGetStackByID(*it));
}
}
void CPlayerInterface::battleNewRound(int round) //called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
{
if(LOCPLINT != this)
{ //another local interface should do this
return;
}
boost::unique_lock<boost::recursive_mutex> un(*pim);
battleInt->newRound(round);
}
void CPlayerInterface::actionStarted(const BattleAction* action)
{
if(LOCPLINT != this)
{ //another local interface should do this
return;
}
boost::unique_lock<boost::recursive_mutex> un(*pim);
curAction = new BattleAction(*action);
battleInt->startAction(action);
}
void CPlayerInterface::actionFinished(const BattleAction* action)
{
if(LOCPLINT != this)
{ //another local interface should do this
return;
}
boost::unique_lock<boost::recursive_mutex> un(*pim);
delete curAction;
curAction = NULL;
battleInt->endAction(action);
}
BattleAction CPlayerInterface::activeStack(const CStack * stack) //called when it's turn of that stack
{
CBattleInterface *b = battleInt;
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
if(vstd::contains(stack->state,MOVED)) //this stack has moved and makes second action -> high morale
{
std::string hlp = CGI->generaltexth->allTexts[33];
boost::algorithm::replace_first(hlp,"%s",(stack->count != 1) ? stack->getCreature()->namePl : stack->getCreature()->nameSing);
battleInt->displayEffect(20,stack->position);
battleInt->console->addText(hlp);
}
b->stackActivated(stack);
}
//wait till BattleInterface sets its command
boost::unique_lock<boost::mutex> lock(b->givenCommand->mx);
while(!b->givenCommand->data)
b->givenCommand->cond.wait(lock);
//tidy up
BattleAction ret = *(b->givenCommand->data);
delete b->givenCommand->data;
b->givenCommand->data = NULL;
//return command
return ret;
}
void CPlayerInterface::battleEnd(const BattleResult *br)
{
if(LOCPLINT != this)
{ //another local interface should do this
return;
}
boost::unique_lock<boost::recursive_mutex> un(*pim);
battleInt->battleFinished(*br);
}
void CPlayerInterface::battleStackMoved(const CStack * stack, THex dest, int distance, bool end)
{
if(LOCPLINT != this)
{ //another local interface should do this
return;
}
boost::unique_lock<boost::recursive_mutex> un(*pim);
battleInt->stackMoved(stack, dest, end, distance);
}
void CPlayerInterface::battleSpellCast( const BattleSpellCast *sc )
{
if(LOCPLINT != this)
{ //another local interface should do this
return;
}
boost::unique_lock<boost::recursive_mutex> un(*pim);
battleInt->spellCast(sc);
}
void CPlayerInterface::battleStacksEffectsSet( const SetStackEffect & sse )
{
if(LOCPLINT != this)
{ //another local interface should do this
return;
}
boost::unique_lock<boost::recursive_mutex> un(*pim);
battleInt->battleStacksEffectsSet(sse);
}
void CPlayerInterface::battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa)
{
if(LOCPLINT != this)
{ //another local interface should do this
return;
}
tlog5 << "CPlayerInterface::battleStackAttacked - locking...";
boost::unique_lock<boost::recursive_mutex> un(*pim);
tlog5 << "done!\n";
std::vector<SStackAttackedInfo> arg;
for(std::vector<BattleStackAttacked>::const_iterator i = bsa.begin(); i != bsa.end(); i++)
{
const CStack *defender = cb->battleGetStackByID(i->stackAttacked, false);
const CStack *attacker = cb->battleGetStackByID(i->attackerID, false);
if(i->isEffect() && i->effect != 12) //and not armageddon
{
if (defender != NULL)
battleInt->displayEffect(i->effect, defender->position);
}
SStackAttackedInfo to_put = {defender, i->damageAmount, i->killedAmount, attacker, LOCPLINT->curAction->actionType==7, i->killed()};
arg.push_back(to_put);
}
if(bsa.begin()->isEffect() && bsa.begin()->effect == 12) //for armageddon - I hope this condition is enough
{
battleInt->displayEffect(bsa.begin()->effect, -1);
}
battleInt->stacksAreAttacked(arg);
}
void CPlayerInterface::battleAttack(const BattleAttack *ba)
{
if(LOCPLINT != this)
{ //another local interface should do this
return;
}
tlog5 << "CPlayerInterface::battleAttack - locking...";
boost::unique_lock<boost::recursive_mutex> un(*pim);
tlog5 << "done!\n";
assert(curAction);
if(ba->lucky()) //lucky hit
{
const CStack *stack = cb->battleGetStackByID(ba->stackAttacking);
std::string hlp = CGI->generaltexth->allTexts[45];
boost::algorithm::replace_first(hlp,"%s",(stack->count != 1) ? stack->getCreature()->namePl.c_str() : stack->getCreature()->nameSing.c_str());
battleInt->console->addText(hlp);
battleInt->displayEffect(18,stack->position);
}
//TODO: bad luck?
const CStack * attacker = cb->battleGetStackByID(ba->stackAttacking);
if(ba->shot())
{
for(std::vector<BattleStackAttacked>::const_iterator i = ba->bsa.begin(); i != ba->bsa.end(); i++)
{
const CStack * attacked = cb->battleGetStackByID(i->stackAttacked);
battleInt->stackAttacking(attacker, cb->battleGetPos(i->stackAttacked), attacked, true);
}
}
else
{//WARNING: does not support multiple attacked creatures
int shift = 0;
if(ba->counter() && THex::mutualPosition(curAction->destinationTile, attacker->position) < 0)
{
int distp = THex::getDistance(curAction->destinationTile + 1, attacker->position);
int distm = THex::getDistance(curAction->destinationTile - 1, attacker->position);
if( distp < distm )
shift = 1;
else
shift = -1;
}
const CStack * attacked = cb->battleGetStackByID(ba->bsa.begin()->stackAttacked);
battleInt->stackAttacking( attacker, ba->counter() ? curAction->destinationTile + shift : curAction->additionalInfo, attacked, false);
}
}
void CPlayerInterface::showComp(SComponent comp)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
CCS->soundh->playSoundFromSet(CCS->soundh->pickupSounds);
adventureInt->infoBar.showComp(&comp,4000);
}
void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector<Component*> &components, int soundID)
{
std::vector<SComponent*> intComps;
for(int i=0;i<components.size();i++)
intComps.push_back(new SComponent(*components[i]));
showInfoDialog(text,intComps,soundID);
}
void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector<SComponent*> & components, int soundID, bool delComps)
{
waitWhileDialog();
boost::unique_lock<boost::recursive_mutex> un(*pim);
stopMovement();
CInfoWindow *temp = CInfoWindow::create(text, playerID, &components);
temp->setDelComps(delComps);
if(makingTurn && GH.listInt.size() && LOCPLINT == this)
{
CCS->soundh->playSound(static_cast<soundBase::soundID>(soundID));
showingDialog->set(true);
GH.pushInt(temp);
}
else
{
dialogs.push_back(temp);
}
}
void CPlayerInterface::showYesNoDialog(const std::string &text, const std::vector<SComponent*> & components, CFunctionList<void()> onYes, CFunctionList<void()> onNo, bool DelComps)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
stopMovement();
LOCPLINT->showingDialog->setn(true);
CInfoWindow::showYesNoDialog(text, &components, onYes, onNo, DelComps, playerID);
}
void CPlayerInterface::showBlockingDialog( const std::string &text, const std::vector<Component> &components, ui32 askID, int soundID, bool selection, bool cancel )
{
waitWhileDialog();
boost::unique_lock<boost::recursive_mutex> un(*pim);
stopMovement();
CCS->soundh->playSound(static_cast<soundBase::soundID>(soundID));
if(!selection && cancel) //simple yes/no dialog
{
std::vector<SComponent*> intComps;
for(int i=0;i<components.size();i++)
intComps.push_back(new SComponent(components[i])); //will be deleted by close in window
showYesNoDialog(text,intComps,boost::bind(&CCallback::selectionMade,cb,1,askID),boost::bind(&CCallback::selectionMade,cb,0,askID),true);
}
else if(selection)
{
std::vector<CSelectableComponent*> intComps;
for(int i=0;i<components.size();i++)
intComps.push_back(new CSelectableComponent(components[i])); //will be deleted by CSelWindow::close
std::vector<std::pair<std::string,CFunctionList<void()> > > pom;
pom.push_back(std::pair<std::string,CFunctionList<void()> >("IOKAY.DEF",0));
if(cancel)
{
pom.push_back(std::pair<std::string,CFunctionList<void()> >("ICANCEL.DEF",0));
}
int charperline = 35;
if (pom.size() > 1)
charperline = 50;
CSelWindow * temp = new CSelWindow(text, playerID, charperline, intComps, pom, askID);
GH.pushInt(temp);
intComps[0]->clickLeft(true, false);
}
}
void CPlayerInterface::tileRevealed(const boost::unordered_set<int3, ShashInt3> &pos)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
for(boost::unordered_set<int3, ShashInt3>::const_iterator i=pos.begin(); i!=pos.end();i++)
adventureInt->minimap.showTile(*i);
if(pos.size())
GH.totalRedraw();
}
void CPlayerInterface::tileHidden(const boost::unordered_set<int3, ShashInt3> &pos)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
for(boost::unordered_set<int3, ShashInt3>::const_iterator i=pos.begin(); i!=pos.end();i++)
adventureInt->minimap.hideTile(*i);
if(pos.size())
GH.totalRedraw();
}
void CPlayerInterface::openHeroWindow(const CGHeroInstance *hero)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
GH.pushInt(new CHeroWindow(hero));
}
/*
void CPlayerInterface::heroArtifactSetChanged(const CGHeroInstance*hero)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
if(adventureInt->heroWindow->curHero && adventureInt->heroWindow->curHero->id == hero->id) //hero window is opened
{
adventureInt->heroWindow->deactivate();
adventureInt->heroWindow->setHero(hero);
adventureInt->heroWindow->activate();
}
else if(CExchangeWindow* cew = dynamic_cast<CExchangeWindow*>(GH.topInt())) //exchange window is open
{
cew->deactivate();
for(int g=0; g<ARRAY_COUNT(cew->heroInst); ++g)
{
if(cew->heroInst[g]->id == hero->id)
{
cew->heroInst[g] = hero;
cew->artifs[g]->updateState = true;
cew->artifs[g]->setHero(hero);
cew->artifs[g]->updateState = false;
}
}
cew->prepareBackground();
cew->activate();
}
else if(CTradeWindow *caw = dynamic_cast<CTradeWindow*>(GH.topInt()))
{
if(caw->arts)
{
caw->deactivate();
caw->arts->updateState = true;
caw->arts->setHero(hero);
caw->arts->updateState = false;
caw->activate();
}
}
updateInfo(hero);
}*/
void CPlayerInterface::availableCreaturesChanged( const CGDwelling *town )
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
if(castleInt && town->ID == TOWNI_TYPE)
{
CFortScreen *fs = dynamic_cast<CFortScreen*>(GH.topInt());
if(fs)
fs->creaturesChanged();
}
else if(GH.listInt.size() && (town->ID == 17 || town->ID == 20 || town->ID == 106)) //external dwelling
{
CRecruitmentWindow *crw = dynamic_cast<CRecruitmentWindow*>(GH.topInt());
if(crw)
crw->initCres();
}
}
void CPlayerInterface::heroBonusChanged( const CGHeroInstance *hero, const Bonus &bonus, bool gain )
{
if(bonus.type == Bonus::NONE) return;
boost::unique_lock<boost::recursive_mutex> un(*pim);
updateInfo(hero);
if ((bonus.type == Bonus::FLYING_MOVEMENT || bonus.type == Bonus::WATER_WALKING) && !gain)
{
//recalculate paths because hero has lost bonus influencing pathfinding
cb->recalculatePaths();
eraseCurrentPathOf(hero, false);
}
}
template <typename Handler> void CPlayerInterface::serializeTempl( Handler &h, const int version )
{
h & playerID;
h & sysOpts;
h & spellbookSettings;
}
void CPlayerInterface::serialize( COSer<CSaveFile> &h, const int version )
{
serializeTempl(h,version);
}
void CPlayerInterface::serialize( CISer<CLoadFile> &h, const int version )
{
serializeTempl(h,version);
sysOpts.apply();
firstCall = -1;
}
bool CPlayerInterface::moveHero( const CGHeroInstance *h, CGPath path )
{
if (!h)
return false; //can't find hero
eventsM.unlock();
pim->unlock();
bool result = false;
{
path.convert(0);
boost::unique_lock<boost::mutex> un(stillMoveHero.mx);
stillMoveHero.data = CONTINUE_MOVE;
enum TerrainTile::EterrainType currentTerrain = TerrainTile::border; // not init yet
enum TerrainTile::EterrainType newTerrain;
int sh = -1;
const TerrainTile * curTile = cb->getTile(CGHeroInstance::convertPosition(h->pos, false));
for(int i=path.nodes.size()-1; i>0 && (stillMoveHero.data == CONTINUE_MOVE || curTile->blocked); i--)
{
//stop sending move requests if the next node can't be reached at the current turn (hero exhausted his move points)
if(path.nodes[i-1].turns)
{
stillMoveHero.data = STOP_MOVE;
break;
}
// Start a new sound for the hero movement or let the existing one carry on.
#if 0
// TODO
if (hero is flying && sh == -1)
sh = CCS->soundh->playSound(soundBase::horseFlying, -1);
#endif
{
newTerrain = cb->getTile(CGHeroInstance::convertPosition(path.nodes[i].coord, false))->tertype;
if (newTerrain != currentTerrain) {
CCS->soundh->stopSound(sh);
sh = CCS->soundh->playSound(CCS->soundh->horseSounds[newTerrain], -1);
currentTerrain = newTerrain;
}
}
stillMoveHero.data = WAITING_MOVE;
int3 endpos(path.nodes[i-1].coord.x, path.nodes[i-1].coord.y, h->pos.z);
bool guarded = CGI->mh->map->isInTheMap(cb->guardingCreaturePosition(endpos - int3(1, 0, 0)));
cb->moveHero(h,endpos);
while(stillMoveHero.data != STOP_MOVE && stillMoveHero.data != CONTINUE_MOVE)
stillMoveHero.cond.wait(un);
if (guarded) // Abort movement if a guard was fought.
break;
}
CCS->soundh->stopSound(sh);
cb->recalculatePaths();
}
pim->lock();
eventsM.lock();
return result;
}
bool CPlayerInterface::shiftPressed() const
{
return SDL_GetKeyState(NULL)[SDLK_LSHIFT] || SDL_GetKeyState(NULL)[SDLK_RSHIFT];
}
bool CPlayerInterface::altPressed() const
{
return SDL_GetKeyState(NULL)[SDLK_LALT] || SDL_GetKeyState(NULL)[SDLK_RALT];
}
void CPlayerInterface::showGarrisonDialog( const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function<void()> &onEnd )
{
if(stillMoveHero.get() == DURING_MOVE && adventureInt->terrain.currentPath->nodes.size() > 1) //to ignore calls on passing through garrisons
return;
{
boost::unique_lock<boost::mutex> un(showingDialog->mx);
while(showingDialog->data)
showingDialog->cond.wait(un);
}
boost::unique_lock<boost::recursive_mutex> un(*pim);
while(dialogs.size())
{
pim->unlock();
SDL_Delay(20);
pim->lock();
}
CGarrisonWindow *cgw = new CGarrisonWindow(up,down,removableUnits);
cgw->quit->callback += onEnd;
GH.pushInt(cgw);
}
/**
* Shows the dialog that appears when right-clicking an artifact that can be assembled
* into a combinational one on an artifact screen. Does not require the combination of
* artifacts to be legal.
* @param artifactID ID of a constituent artifact.
* @param assembleTo ID of artifact to assemble a constituent into, not used when assemble
* is false.
* @param assemble True if the artifact is to be assembled, false if it is to be disassembled.
*/
void CPlayerInterface::showArtifactAssemblyDialog (ui32 artifactID, ui32 assembleTo, bool assemble, CFunctionList<void()> onYes, CFunctionList<void()> onNo)
{
const CArtifact &artifact = *CGI->arth->artifacts[artifactID];
std::string text = artifact.Description();
text += "\n\n";
std::vector<SComponent*> scs;
if (assemble) {
const CArtifact &assembledArtifact = *CGI->arth->artifacts[assembleTo];
// You possess all of the components to...
text += boost::str(boost::format(CGI->generaltexth->allTexts[732]) % assembledArtifact.Name());
// Picture of assembled artifact at bottom.
SComponent* sc = new SComponent;
sc->type = SComponent::artifact;
sc->subtype = assembledArtifact.id;
sc->description = assembledArtifact.Description();
sc->subtitle = assembledArtifact.Name();
scs.push_back(sc);
} else {
// Do you wish to disassemble this artifact?
text += CGI->generaltexth->allTexts[733];
}
showYesNoDialog(text, scs, onYes, onNo, true);
}
void CPlayerInterface::requestRealized( PackageApplied *pa )
{
if(stillMoveHero.get() == DURING_MOVE)
stillMoveHero.setn(CONTINUE_MOVE);
}
void CPlayerInterface::heroExchangeStarted(si32 hero1, si32 hero2)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
GH.pushInt(new CExchangeWindow(hero1, hero2));
}
void CPlayerInterface::objectPropertyChanged(const SetObjectProperty * sop)
{
//redraw minimap if owner changed
boost::unique_lock<boost::recursive_mutex> un(*pim);
if(sop->what == ObjProperty::OWNER)
{
const CGObjectInstance * obj = cb->getObj(sop->id);
std::set<int3> pos = obj->getBlockedPos();
for(std::set<int3>::const_iterator it = pos.begin(); it != pos.end(); ++it)
{
if(cb->isVisible(*it))
adventureInt->minimap.showTile(*it);
}
if(obj->ID == TOWNI_TYPE)
{
if(obj->tempOwner == playerID)
towns.push_back(static_cast<const CGTownInstance *>(obj));
else
towns -= obj;
}
assert(cb->getTownsInfo().size() == towns.size());
}
}
void CPlayerInterface::recreateHeroTownList()
{
wanderingHeroes.clear();
std::vector<const CGHeroInstance*> heroes = cb->getHeroesInfo();
for(size_t i = 0; i < heroes.size(); i++)
if(!heroes[i]->inTownGarrison)
wanderingHeroes.push_back(heroes[i]);
towns.clear();
std::vector<const CGTownInstance*> townInfo = cb->getTownsInfo();
for(size_t i = 0; i < townInfo.size(); i++)
towns.push_back(townInfo[i]);
}
const CGHeroInstance * CPlayerInterface::getWHero( int pos )
{
if(pos < 0 || pos >= wanderingHeroes.size())
return NULL;
return wanderingHeroes[pos];
}
void CPlayerInterface::showRecruitmentDialog(const CGDwelling *dwelling, const CArmedInstance *dst, int level)
{
waitWhileDialog();
boost::unique_lock<boost::recursive_mutex> un(*pim);
CRecruitmentWindow *cr = new CRecruitmentWindow(dwelling, level, dst, boost::bind(&CCallback::recruitCreatures, cb, dwelling, _1, _2, -1));
GH.pushInt(cr);
}
void CPlayerInterface::waitWhileDialog()
{
boost::unique_lock<boost::mutex> un(showingDialog->mx);
while(showingDialog->data)
showingDialog->cond.wait(un);
}
void CPlayerInterface::showShipyardDialog(const IShipyard *obj)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
int state = obj->state();
std::vector<si32> cost;
obj->getBoatCost(cost);
CShipyardWindow *csw = new CShipyardWindow(cost, state, obj->getBoatType(), boost::bind(&CCallback::buildBoat, cb, obj));
GH.pushInt(csw);
}
void CPlayerInterface::newObject( const CGObjectInstance * obj )
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
CGI->mh->printObject(obj);
//we might have built a boat in shipyard in opened town screen
if(obj->ID == 8
&& LOCPLINT->castleInt
&& obj->pos-obj->getVisitableOffset() == LOCPLINT->castleInt->town->bestLocation())
{
CCS->soundh->playSound(soundBase::newBuilding);
LOCPLINT->castleInt->addBuilding(20);
}
}
void CPlayerInterface::centerView (int3 pos, int focusTime)
{
waitWhileDialog();
adventureInt->centerOn (pos);
if(focusTime)
{
bool activeAdv = (GH.topInt() == adventureInt && adventureInt->isActive());
if(activeAdv)
adventureInt->deactivate();
SDL_Delay(focusTime);
if(activeAdv)
adventureInt->activate();
}
}
void CPlayerInterface::objectRemoved( const CGObjectInstance *obj )
{
if(obj->ID == HEROI_TYPE && obj->tempOwner == playerID)
{
const CGHeroInstance *h = static_cast<const CGHeroInstance*>(obj);
heroKilled(h);
}
}
bool CPlayerInterface::ctrlPressed() const
{
return SDL_GetKeyState(NULL)[SDLK_LCTRL] || SDL_GetKeyState(NULL)[SDLK_RCTRL];
}
void CPlayerInterface::update()
{
while(!terminate_cond.get() && !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(terminate_cond.get())
return;
//if there are any waiting dialogs, show them
if((howManyPeople <= 1 || makingTurn) && dialogs.size() && !showingDialog->get())
{
showingDialog->set(true);
GH.pushInt(dialogs.front());
dialogs.pop_front();
}
//in some conditions we may receive calls before selection is initialized - we must ignore them
if(adventureInt && !adventureInt->selection && GH.topInt() == adventureInt)
return;
// Handles mouse and key input
GH.updateTime();
GH.handleEvents();
if(adventureInt && !adventureInt->isActive() && adventureInt->scrollingDir) //player forces map scrolling though interface is disabled
GH.totalRedraw();
else
GH.simpleRedraw();
if (conf.cc.showFPS)
GH.drawFPSCounter();
// draw the mouse cursor and update the screen
CCS->curh->draw1();
CSDL_Ext::update(screen);
CCS->curh->draw2();
pim->unlock();
}
int CPlayerInterface::getLastIndex( std::string namePrefix)
{
using namespace boost::filesystem;
using namespace boost::algorithm;
std::map<std::time_t, int> dates; //save number => datestamp
directory_iterator enddir;
for (directory_iterator dir(GVCMIDirs.UserPath + "/Games"); dir!=enddir; dir++)
{
if(is_regular(dir->status()))
{
std::string name = dir->path().leaf();
if(starts_with(name, namePrefix) && ends_with(name, ".vlgm1"))
{
char nr = name[namePrefix.size()];
if(std::isdigit(nr))
{
dates[last_write_time(dir->path())] = boost::lexical_cast<int>(nr);
}
}
}
}
if(dates.size())
return (--dates.end())->second; //return latest file number
return 0;
}
void CPlayerInterface::initMovement( const TryMoveHero &details, const CGHeroInstance * ho, const int3 &hp )
{
if(details.end.x+1 == details.start.x && details.end.y+1 == details.start.y) //tl
{
//ho->moveDir = 1;
ho->isStanding = false;
CGI->mh->ttiles[hp.x-3][hp.y-2][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, -31, -31)));
CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 1, -31)));
CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 33, -31)));
CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 65, -31)));
CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, -31, 1)));
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, 1, 1), ho->id);
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 33, 1), ho->id);
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 65, 1), ho->id);
CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, -31, 33)));
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, 1, 33), ho->id);
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 33, 33), ho->id);
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 65, 33), ho->id);
std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y-2][hp.z].objects.end(), ocmptwo_cgin);
std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.end(), ocmptwo_cgin);
std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.end(), ocmptwo_cgin);
std::stable_sort(CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.end(), ocmptwo_cgin);
std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.end(), ocmptwo_cgin);
std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.end(), ocmptwo_cgin);
}
else if(details.end.x == details.start.x && details.end.y+1 == details.start.y) //t
{
//ho->moveDir = 2;
ho->isStanding = false;
CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 0, -31)));
CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 32, -31)));
CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 64, -31)));
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, 0, 1), ho->id);
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 32, 1), ho->id);
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 64, 1), ho->id);
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, 0, 33), ho->id);
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 32, 33), ho->id);
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 64, 33), ho->id);
std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.end(), ocmptwo_cgin);
std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.end(), ocmptwo_cgin);
std::stable_sort(CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.end(), ocmptwo_cgin);
}
else if(details.end.x-1 == details.start.x && details.end.y+1 == details.start.y) //tr
{
//ho->moveDir = 3;
ho->isStanding = false;
CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, -1, -31)));
CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 31, -31)));
CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 63, -31)));
CGI->mh->ttiles[hp.x+1][hp.y-2][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 95, -31)));
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, -1, 1), ho->id);
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 31, 1), ho->id);
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 63, 1), ho->id);
CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 95, 1)));
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, -1, 33), ho->id);
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 31, 33), ho->id);
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 63, 33), ho->id);
CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 95, 33)));
std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.end(), ocmptwo_cgin);
std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.end(), ocmptwo_cgin);
std::stable_sort(CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.end(), ocmptwo_cgin);
std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y-2][hp.z].objects.end(), ocmptwo_cgin);
std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.end(), ocmptwo_cgin);
std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.end(), ocmptwo_cgin);
}
else if(details.end.x-1 == details.start.x && details.end.y == details.start.y) //r
{
//ho->moveDir = 4;
ho->isStanding = false;
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, -1, 0), ho->id);
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 31, 0), ho->id);
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 63, 0), ho->id);
CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 95, 0)));
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, -1, 32), ho->id);
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 31, 32), ho->id);
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 63, 32), ho->id);
CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 95, 32)));
std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.end(), ocmptwo_cgin);
std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.end(), ocmptwo_cgin);
}
else if(details.end.x-1 == details.start.x && details.end.y-1 == details.start.y) //br
{
//ho->moveDir = 5;
ho->isStanding = false;
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, -1, -1), ho->id);
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 31, -1), ho->id);
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 63, -1), ho->id);
CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 95, -1)));
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, -1, 31), ho->id);
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 31, 31), ho->id);
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 63, 31), ho->id);
CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 95, 31)));
CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, -1, 63)));
CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 31, 63)));
CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 63, 63)));
CGI->mh->ttiles[hp.x+1][hp.y+1][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 95, 63)));
std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.end(), ocmptwo_cgin);
std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.end(), ocmptwo_cgin);
std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.end(), ocmptwo_cgin);
std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.end(), ocmptwo_cgin);
std::stable_sort(CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.end(), ocmptwo_cgin);
std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y+1][hp.z].objects.end(), ocmptwo_cgin);
}
else if(details.end.x == details.start.x && details.end.y-1 == details.start.y) //b
{
//ho->moveDir = 6;
ho->isStanding = false;
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, 0, -1), ho->id);
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 32, -1), ho->id);
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 64, -1), ho->id);
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, 0, 31), ho->id);
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 32, 31), ho->id);
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 64, 31), ho->id);
CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 0, 63)));
CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 32, 63)));
CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 64, 63)));
std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.end(), ocmptwo_cgin);
std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.end(), ocmptwo_cgin);
std::stable_sort(CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.end(), ocmptwo_cgin);
}
else if(details.end.x+1 == details.start.x && details.end.y-1 == details.start.y) //bl
{
//ho->moveDir = 7;
ho->isStanding = false;
CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, -31, -1)));
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, 1, -1), ho->id);
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 33, -1), ho->id);
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 65, -1), ho->id);
CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, -31, 31)));
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, 1, 31), ho->id);
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 33, 31), ho->id);
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 65, 31), ho->id);
CGI->mh->ttiles[hp.x-3][hp.y+1][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, -31, 63)));
CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 1, 63)));
CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 33, 63)));
CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 65, 63)));
std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.end(), ocmptwo_cgin);
std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.end(), ocmptwo_cgin);
std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y+1][hp.z].objects.end(), ocmptwo_cgin);
std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.end(), ocmptwo_cgin);
std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.end(), ocmptwo_cgin);
std::stable_sort(CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.end(), ocmptwo_cgin);
}
else if(details.end.x+1 == details.start.x && details.end.y == details.start.y) //l
{
//ho->moveDir = 8;
ho->isStanding = false;
CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, -31, 0)));
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, 1, 0), ho->id);
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 33, 0), ho->id);
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 65, 0), ho->id);
CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, -31, 32)));
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, 1, 32), ho->id);
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 33, 32), ho->id);
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 65, 32), ho->id);
std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.end(), ocmptwo_cgin);
std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.end(), ocmptwo_cgin);
}
}
void CPlayerInterface::movementPxStep( const TryMoveHero &details, int i, const int3 &hp, const CGHeroInstance * ho )
{
if(details.end.x+1 == details.start.x && details.end.y+1 == details.start.y) //tl
{
//setting advmap shift
adventureInt->terrain.moveX = i-32;
adventureInt->terrain.moveY = i-32;
subRect(hp.x-3, hp.y-2, hp.z, genRect(32, 32, -31+i, -31+i), ho->id);
subRect(hp.x-2, hp.y-2, hp.z, genRect(32, 32, 1+i, -31+i), ho->id);
subRect(hp.x-1, hp.y-2, hp.z, genRect(32, 32, 33+i, -31+i), ho->id);
subRect(hp.x, hp.y-2, hp.z, genRect(32, 32, 65+i, -31+i), ho->id);
subRect(hp.x-3, hp.y-1, hp.z, genRect(32, 32, -31+i, 1+i), ho->id);
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, 1+i, 1+i), ho->id);
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 33+i, 1+i), ho->id);
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 65+i, 1+i), ho->id);
subRect(hp.x-3, hp.y, hp.z, genRect(32, 32, -31+i, 33+i), ho->id);
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, 1+i, 33+i), ho->id);
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 33+i, 33+i), ho->id);
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 65+i, 33+i), ho->id);
}
else if(details.end.x == details.start.x && details.end.y+1 == details.start.y) //t
{
//setting advmap shift
adventureInt->terrain.moveY = i-32;
subRect(hp.x-2, hp.y-2, hp.z, genRect(32, 32, 0, -31+i), ho->id);
subRect(hp.x-1, hp.y-2, hp.z, genRect(32, 32, 32, -31+i), ho->id);
subRect(hp.x, hp.y-2, hp.z, genRect(32, 32, 64, -31+i), ho->id);
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, 0, 1+i), ho->id);
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 32, 1+i), ho->id);
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 64, 1+i), ho->id);
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, 0, 33+i), ho->id);
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 32, 33+i), ho->id);
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 64, 33+i), ho->id);
}
else if(details.end.x-1 == details.start.x && details.end.y+1 == details.start.y) //tr
{
//setting advmap shift
adventureInt->terrain.moveX = -i+32;
adventureInt->terrain.moveY = i-32;
subRect(hp.x-2, hp.y-2, hp.z, genRect(32, 32, -1-i, -31+i), ho->id);
subRect(hp.x-1, hp.y-2, hp.z, genRect(32, 32, 31-i, -31+i), ho->id);
subRect(hp.x, hp.y-2, hp.z, genRect(32, 32, 63-i, -31+i), ho->id);
subRect(hp.x+1, hp.y-2, hp.z, genRect(32, 32, 95-i, -31+i), ho->id);
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, -1-i, 1+i), ho->id);
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 31-i, 1+i), ho->id);
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 63-i, 1+i), ho->id);
subRect(hp.x+1, hp.y-1, hp.z, genRect(32, 32, 95-i, 1+i), ho->id);
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, -1-i, 33+i), ho->id);
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 31-i, 33+i), ho->id);
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 63-i, 33+i), ho->id);
subRect(hp.x+1, hp.y, hp.z, genRect(32, 32, 95-i, 33+i), ho->id);
}
else if(details.end.x-1 == details.start.x && details.end.y == details.start.y) //r
{
//setting advmap shift
adventureInt->terrain.moveX = -i+32;
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, -1-i, 0), ho->id);
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 31-i, 0), ho->id);
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 63-i, 0), ho->id);
subRect(hp.x+1, hp.y-1, hp.z, genRect(32, 32, 95-i, 0), ho->id);
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, -1-i, 32), ho->id);
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 31-i, 32), ho->id);
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 63-i, 32), ho->id);
subRect(hp.x+1, hp.y, hp.z, genRect(32, 32, 95-i, 32), ho->id);
}
else if(details.end.x-1 == details.start.x && details.end.y-1 == details.start.y) //br
{
//setting advmap shift
adventureInt->terrain.moveX = -i+32;
adventureInt->terrain.moveY = -i+32;
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, -1-i, -1-i), ho->id);
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 31-i, -1-i), ho->id);
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 63-i, -1-i), ho->id);
subRect(hp.x+1, hp.y-1, hp.z, genRect(32, 32, 95-i, -1-i), ho->id);
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, -1-i, 31-i), ho->id);
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 31-i, 31-i), ho->id);
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 63-i, 31-i), ho->id);
subRect(hp.x+1, hp.y, hp.z, genRect(32, 32, 95-i, 31-i), ho->id);
subRect(hp.x-2, hp.y+1, hp.z, genRect(32, 32, -1-i, 63-i), ho->id);
subRect(hp.x-1, hp.y+1, hp.z, genRect(32, 32, 31-i, 63-i), ho->id);
subRect(hp.x, hp.y+1, hp.z, genRect(32, 32, 63-i, 63-i), ho->id);
subRect(hp.x+1, hp.y+1, hp.z, genRect(32, 32, 95-i, 63-i), ho->id);
}
else if(details.end.x == details.start.x && details.end.y-1 == details.start.y) //b
{
//setting advmap shift
adventureInt->terrain.moveY = -i+32;
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, 0, -1-i), ho->id);
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 32, -1-i), ho->id);
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 64, -1-i), ho->id);
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, 0, 31-i), ho->id);
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 32, 31-i), ho->id);
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 64, 31-i), ho->id);
subRect(hp.x-2, hp.y+1, hp.z, genRect(32, 32, 0, 63-i), ho->id);
subRect(hp.x-1, hp.y+1, hp.z, genRect(32, 32, 32, 63-i), ho->id);
subRect(hp.x, hp.y+1, hp.z, genRect(32, 32, 64, 63-i), ho->id);
}
else if(details.end.x+1 == details.start.x && details.end.y-1 == details.start.y) //bl
{
//setting advmap shift
adventureInt->terrain.moveX = i-32;
adventureInt->terrain.moveY = -i+32;
subRect(hp.x-3, hp.y-1, hp.z, genRect(32, 32, -31+i, -1-i), ho->id);
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, 1+i, -1-i), ho->id);
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 33+i, -1-i), ho->id);
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 65+i, -1-i), ho->id);
subRect(hp.x-3, hp.y, hp.z, genRect(32, 32, -31+i, 31-i), ho->id);
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, 1+i, 31-i), ho->id);
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 33+i, 31-i), ho->id);
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 65+i, 31-i), ho->id);
subRect(hp.x-3, hp.y+1, hp.z, genRect(32, 32, -31+i, 63-i), ho->id);
subRect(hp.x-2, hp.y+1, hp.z, genRect(32, 32, 1+i, 63-i), ho->id);
subRect(hp.x-1, hp.y+1, hp.z, genRect(32, 32, 33+i, 63-i), ho->id);
subRect(hp.x, hp.y+1, hp.z, genRect(32, 32, 65+i, 63-i), ho->id);
}
else if(details.end.x+1 == details.start.x && details.end.y == details.start.y) //l
{
//setting advmap shift
adventureInt->terrain.moveX = i-32;
subRect(hp.x-3, hp.y-1, hp.z, genRect(32, 32, -31+i, 0), ho->id);
subRect(hp.x-2, hp.y-1, hp.z, genRect(32, 32, 1+i, 0), ho->id);
subRect(hp.x-1, hp.y-1, hp.z, genRect(32, 32, 33+i, 0), ho->id);
subRect(hp.x, hp.y-1, hp.z, genRect(32, 32, 65+i, 0), ho->id);
subRect(hp.x-3, hp.y, hp.z, genRect(32, 32, -31+i, 32), ho->id);
subRect(hp.x-2, hp.y, hp.z, genRect(32, 32, 1+i, 32), ho->id);
subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 33+i, 32), ho->id);
subRect(hp.x, hp.y, hp.z, genRect(32, 32, 65+i, 32), ho->id);
}
}
void CPlayerInterface::finishMovement( const TryMoveHero &details, const int3 &hp, const CGHeroInstance * ho )
{
adventureInt->terrain.moveX = adventureInt->terrain.moveY = 0;
if(details.end.x+1 == details.start.x && details.end.y+1 == details.start.y) //tl
{
delObjRect(hp.x, hp.y-2, hp.z, ho->id);
delObjRect(hp.x, hp.y-1, hp.z, ho->id);
delObjRect(hp.x, hp.y, hp.z, ho->id);
delObjRect(hp.x-1, hp.y, hp.z, ho->id);
delObjRect(hp.x-2, hp.y, hp.z, ho->id);
delObjRect(hp.x-3, hp.y, hp.z, ho->id);
}
else if(details.end.x == details.start.x && details.end.y+1 == details.start.y) //t
{
delObjRect(hp.x, hp.y, hp.z, ho->id);
delObjRect(hp.x-1, hp.y, hp.z, ho->id);
delObjRect(hp.x-2, hp.y, hp.z, ho->id);
}
else if(details.end.x-1 == details.start.x && details.end.y+1 == details.start.y) //tr
{
delObjRect(hp.x-2, hp.y-2, hp.z, ho->id);
delObjRect(hp.x-2, hp.y-1, hp.z, ho->id);
delObjRect(hp.x+1, hp.y, hp.z, ho->id);
delObjRect(hp.x, hp.y, hp.z, ho->id);
delObjRect(hp.x-1, hp.y, hp.z, ho->id);
delObjRect(hp.x-2, hp.y, hp.z, ho->id);
}
else if(details.end.x-1 == details.start.x && details.end.y == details.start.y) //r
{
delObjRect(hp.x-2, hp.y-1, hp.z, ho->id);
delObjRect(hp.x-2, hp.y, hp.z, ho->id);
}
else if(details.end.x-1 == details.start.x && details.end.y-1 == details.start.y) //br
{
delObjRect(hp.x-2, hp.y+1, hp.z, ho->id);
delObjRect(hp.x-2, hp.y, hp.z, ho->id);
delObjRect(hp.x+1, hp.y-1, hp.z, ho->id);
delObjRect(hp.x, hp.y-1, hp.z, ho->id);
delObjRect(hp.x-1, hp.y-1, hp.z, ho->id);
delObjRect(hp.x-2, hp.y-1, hp.z, ho->id);
}
else if(details.end.x == details.start.x && details.end.y-1 == details.start.y) //b
{
delObjRect(hp.x, hp.y-1, hp.z, ho->id);
delObjRect(hp.x-1, hp.y-1, hp.z, ho->id);
delObjRect(hp.x-2, hp.y-1, hp.z, ho->id);
}
else if(details.end.x+1 == details.start.x && details.end.y-1 == details.start.y) //bl
{
delObjRect(hp.x, hp.y-1, hp.z, ho->id);
delObjRect(hp.x-1, hp.y-1, hp.z, ho->id);
delObjRect(hp.x-2, hp.y-1, hp.z, ho->id);
delObjRect(hp.x-3, hp.y-1, hp.z, ho->id);
delObjRect(hp.x, hp.y, hp.z, ho->id);
delObjRect(hp.x, hp.y+1, hp.z, ho->id);
}
else if(details.end.x+1 == details.start.x && details.end.y == details.start.y) //l
{
delObjRect(hp.x, hp.y-1, hp.z, ho->id);
delObjRect(hp.x, hp.y, hp.z, ho->id);
}
//restoring good rects
subRect(details.end.x-2, details.end.y-1, details.end.z, genRect(32, 32, 0, 0), ho->id);
subRect(details.end.x-1, details.end.y-1, details.end.z, genRect(32, 32, 32, 0), ho->id);
subRect(details.end.x, details.end.y-1, details.end.z, genRect(32, 32, 64, 0), ho->id);
subRect(details.end.x-2, details.end.y, details.end.z, genRect(32, 32, 0, 32), ho->id);
subRect(details.end.x-1, details.end.y, details.end.z, genRect(32, 32, 32, 32), ho->id);
subRect(details.end.x, details.end.y, details.end.z, genRect(32, 32, 64, 32), ho->id);
//restoring good order of objects
std::stable_sort(CGI->mh->ttiles[details.end.x-2][details.end.y-1][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x-2][details.end.y-1][details.end.z].objects.end(), ocmptwo_cgin);
std::stable_sort(CGI->mh->ttiles[details.end.x-1][details.end.y-1][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x-1][details.end.y-1][details.end.z].objects.end(), ocmptwo_cgin);
std::stable_sort(CGI->mh->ttiles[details.end.x][details.end.y-1][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x][details.end.y-1][details.end.z].objects.end(), ocmptwo_cgin);
std::stable_sort(CGI->mh->ttiles[details.end.x-2][details.end.y][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x-2][details.end.y][details.end.z].objects.end(), ocmptwo_cgin);
std::stable_sort(CGI->mh->ttiles[details.end.x-1][details.end.y][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x-1][details.end.y][details.end.z].objects.end(), ocmptwo_cgin);
std::stable_sort(CGI->mh->ttiles[details.end.x][details.end.y][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x][details.end.y][details.end.z].objects.end(), ocmptwo_cgin);
}
void CPlayerInterface::gameOver(ui8 player, bool victory )
{
if(LOCPLINT != this)
return;
if(player == playerID)
{
if(!victory)
showInfoDialog(CGI->generaltexth->allTexts[95]);
// else
// showInfoDialog("Placeholder message: you won!");
makingTurn = true;
while(showingDialog->get() || dialogs.size()); //wait till all dialogs are displayed and closed
makingTurn = false;
howManyPeople--;
if(!howManyPeople) //all human players eliminated
{
if(cb->getStartInfo()->mode != StartInfo::CAMPAIGN)
requestReturningToMainMenu();
else
requestStoppingClient();
}
}
else
{
if(!victory && cb->getPlayerStatus(playerID) == PlayerState::INGAME) //enemy has lost
{
std::string txt = CGI->generaltexth->allTexts[5]; //%s has been vanquished!
boost::algorithm::replace_first(txt, "%s", CGI->generaltexth->capColors[player]);
showInfoDialog(txt,std::vector<SComponent*>(1, new SComponent(SComponent::flag, player, 0)));
}
}
}
void CPlayerInterface::playerBonusChanged( const Bonus &bonus, bool gain )
{
}
void CPlayerInterface::showPuzzleMap()
{
waitWhileDialog();
boost::unique_lock<boost::recursive_mutex> un(*pim);
//TODO: interface should not know the real position of Grail...
float ratio = 0;
int3 grailPos = cb->getGrailPos(ratio);
GH.pushInt(new CPuzzleWindow(grailPos, ratio));
}
void CPlayerInterface::advmapSpellCast(const CGHeroInstance * caster, int spellID)
{
if (spellID == Spells::FLY || spellID == Spells::WATER_WALK)
{
cb->recalculatePaths();
eraseCurrentPathOf(caster, false);
}
}
void SystemOptions::setMusicVolume( int newVolume )
{
musicVolume = newVolume;
CCS->musich->setVolume(newVolume);
settingsChanged();
}
void SystemOptions::setSoundVolume( int newVolume )
{
soundVolume = newVolume;
CCS->soundh->setVolume(newVolume);
settingsChanged();
}
void SystemOptions::setHeroMoveSpeed( int newSpeed )
{
heroMoveSpeed = newSpeed;
settingsChanged();
}
void SystemOptions::setMapScrollingSpeed( int newSpeed )
{
mapScrollingSpeed = newSpeed;
settingsChanged();
}
void SystemOptions::settingsChanged()
{
CSaveFile settings(GVCMIDirs.UserPath + "/config/sysopts.bin");
if(settings.sfile)
settings << *this;
else
tlog1 << "Cannot save settings to config/sysopts.bin!\n";
}
void SystemOptions::apply()
{
if(CCS->musich->getVolume() != musicVolume)
CCS->musich->setVolume(musicVolume);
if(CCS->soundh->getVolume() != soundVolume)
CCS->soundh->setVolume(soundVolume);
settingsChanged();
}
SystemOptions::SystemOptions()
{
heroMoveSpeed = 2;
mapScrollingSpeed = 2;
musicVolume = 88;
soundVolume = 88;
printCellBorders = true;
printStackRange = true;
animSpeed = 2;
printMouseShadow = true;
showQueue = true;
playerName = "Player";
}
void SystemOptions::setPlayerName(const std::string &newPlayerName)
{
playerName = newPlayerName;
settingsChanged();
}
void CPlayerInterface::eraseCurrentPathOf( const CGHeroInstance * ho, bool checkForExistanceOfPath /*= true */ )
{
if(checkForExistanceOfPath)
{
assert(vstd::contains(paths, ho));
}
else if (!vstd::contains(paths, ho))
{
return;
}
assert(ho == adventureInt->selection);
paths.erase(ho);
adventureInt->terrain.currentPath = NULL;
}
CGPath * CPlayerInterface::getAndVerifyPath(const CGHeroInstance * h)
{
if(vstd::contains(paths,h)) //hero has assigned path
{
CGPath &path = paths[h];
if(!path.nodes.size())
{
tlog3 << "Warning: empty path found...\n";
paths.erase(h);
}
else
{
assert(h->getPosition(false) == path.startPos());
//update the hero path in case of something has changed on map
if(LOCPLINT->cb->getPath2(path.endPos(), path))
return &path;
else
paths.erase(h);
}
}
return NULL;
}
void CPlayerInterface::acceptTurn()
{
waitWhileDialog();
if(howManyPeople > 1)
adventureInt->startTurn();
boost::unique_lock<boost::recursive_mutex> un(*pim);
/* TODO: This isn't quite right. First day in game should play
* NEWDAY. And we don't play NEWMONTH. */
int day = cb->getDate(1);
if (day != 1)
CCS->soundh->playSound(soundBase::newDay);
else
CCS->soundh->playSound(soundBase::newWeek);
adventureInt->infoBar.newDay(day);
//select first hero if available.
//TODO: check if hero is slept
if(wanderingHeroes.size())
adventureInt->select(wanderingHeroes.front());
else
adventureInt->select(towns.front());
adventureInt->showAll(screen);
}
void CPlayerInterface::tryDiggging(const CGHeroInstance *h)
{
std::string hlp;
if(h->movement < h->maxMovePoints(true))
showInfoDialog(CGI->generaltexth->allTexts[56]); //"Digging for artifacts requires a whole day, try again tomorrow."
else if(cb->getTile(h->getPosition(false))->tertype == TerrainTile::water)
showInfoDialog(CGI->generaltexth->allTexts[60]); //Try looking on land!
else
{
const TerrainTile *t = cb->getTile(h->getPosition());
CGI->mh->getTerrainDescr(h->getPosition(false), hlp, false);
if(hlp.length() || t->blockingObjects.size() > 1)
showInfoDialog(CGI->generaltexth->allTexts[97]); //Try searching on clear ground.
else
cb->dig(h);
}
}
void CPlayerInterface::updateInfo(const CGObjectInstance * specific)
{
adventureInt->infoBar.updateSelection(specific);
// if (adventureInt->selection == specific)
// adventureInt->infoBar.showAll(screen);
}
void CPlayerInterface::battleNewRoundFirst( int round )
{
if(LOCPLINT != this)
{ //another local interface should do this
return;
}
boost::unique_lock<boost::recursive_mutex> un(*pim);
battleInt->newRoundFirst(round);
}
void CPlayerInterface::stopMovement()
{
if(stillMoveHero.get() == DURING_MOVE)//if we are in the middle of hero movement
stillMoveHero.setn(STOP_MOVE); //after showing dialog movement will be stopped
}
void CPlayerInterface::showMarketWindow(const IMarket *market, const CGHeroInstance *visitor)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
if(market->o->ID == 2) //Altar
{
//EMarketMode mode = market->availableModes().front();
if(market->allowsTrade(ARTIFACT_EXP) && visitor->getAlignment() != EVIL)
GH.pushInt(new CAltarWindow(market, visitor, ARTIFACT_EXP));
else if(market->allowsTrade(CREATURE_EXP) && visitor->getAlignment() != GOOD)
GH.pushInt(new CAltarWindow(market, visitor, CREATURE_EXP));
}
else
GH.pushInt(new CMarketplaceWindow(market, visitor, market->availableModes().front()));
}
void CPlayerInterface::showUniversityWindow(const IMarket *market, const CGHeroInstance *visitor)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
CUniversityWindow *cuw = new CUniversityWindow(visitor, market);
GH.pushInt(cuw);
}
void CPlayerInterface::showHillFortWindow(const CGObjectInstance *object, const CGHeroInstance *visitor)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
CHillFortWindow *chfw = new CHillFortWindow(visitor, object);
GH.pushInt(chfw);
}
void CPlayerInterface::availableArtifactsChanged(const CGBlackMarket *bm /*= NULL*/)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
if(CMarketplaceWindow *cmw = dynamic_cast<CMarketplaceWindow*>(GH.topInt()))
cmw->artifactsChanged(false);
}
void CPlayerInterface::showTavernWindow(const CGObjectInstance *townOrTavern)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
CTavernWindow *tv = new CTavernWindow(townOrTavern);
GH.pushInt(tv);
}
void CPlayerInterface::showShipyardDialogOrProblemPopup(const IShipyard *obj)
{
if(obj->state())
{
MetaString txt;
obj->getProblemText(txt);
showInfoDialog(txt.toString());
}
else
showShipyardDialog(obj);
}
void CPlayerInterface::requestReturningToMainMenu()
{
sendCustomEvent(2);
}
void CPlayerInterface::requestStoppingClient()
{
sendCustomEvent(3);
}
void CPlayerInterface::sendCustomEvent( int code )
{
SDL_Event event;
event.type = SDL_USEREVENT;
event.user.code = code;
SDL_PushEvent(&event);
}
void CPlayerInterface::stackChagedCount(const StackLocation &location, const TQuantity &change, bool isAbsolute)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
garrisonChanged(location.army);
}
void CPlayerInterface::stackChangedType(const StackLocation &location, const CCreature &newType)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
garrisonChanged(location.army);
}
void CPlayerInterface::stacksErased(const StackLocation &location)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
garrisonChanged(location.army);
}
#define UPDATE_IF(LOC) static_cast<const CArmedInstance*>(adventureInt->infoBar.curSel) == LOC.army.get()
void CPlayerInterface::stacksSwapped(const StackLocation &loc1, const StackLocation &loc2)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
garrisonChanged(loc1.army, UPDATE_IF(loc1));
if(loc2.army != loc1.army)
garrisonChanged(loc2.army, UPDATE_IF(loc2));
}
void CPlayerInterface::newStackInserted(const StackLocation &location, const CStackInstance &stack)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
garrisonChanged(location.army);
}
void CPlayerInterface::stacksRebalanced(const StackLocation &src, const StackLocation &dst, TQuantity count)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
//bool updateInfobox = true;
garrisonChanged(src.army, UPDATE_IF(src));
if(dst.army != src.army)
garrisonChanged(dst.army, UPDATE_IF(dst));
}
#undef UPDATE_IF
void CPlayerInterface::artifactPut(const ArtifactLocation &al)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
}
void CPlayerInterface::artifactRemoved(const ArtifactLocation &al)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
BOOST_FOREACH(IShowActivable *isa, GH.listInt)
{
if(isa->type & IShowActivable::WITH_ARTIFACTS)
{
(dynamic_cast<CWindowWithArtifacts*>(isa))->artifactRemoved(al);
}
}
}
void CPlayerInterface::artifactMoved(const ArtifactLocation &src, const ArtifactLocation &dst)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
BOOST_FOREACH(IShowActivable *isa, GH.listInt)
{
if(isa->type & IShowActivable::WITH_ARTIFACTS)
{
(dynamic_cast<CWindowWithArtifacts*>(isa))->artifactMoved(src, dst);
}
}
}
void CPlayerInterface::artifactAssembled(const ArtifactLocation &al)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
BOOST_FOREACH(IShowActivable *isa, GH.listInt)
{
if(isa->type & IShowActivable::WITH_ARTIFACTS)
{
(dynamic_cast<CWindowWithArtifacts*>(isa))->artifactAssembled(al);
}
}
}
void CPlayerInterface::artifactDisassembled(const ArtifactLocation &al)
{
boost::unique_lock<boost::recursive_mutex> un(*pim);
BOOST_FOREACH(IShowActivable *isa, GH.listInt)
{
if(isa->type & IShowActivable::WITH_ARTIFACTS)
{
(dynamic_cast<CWindowWithArtifacts*>(isa))->artifactAssembled(al);
}
}
}
boost::recursive_mutex * CPlayerInterface::pim = new boost::recursive_mutex;
CPlayerInterface::SpellbookLastSetting::SpellbookLastSetting()
{
spellbookLastPageBattle = spellbokLastPageAdvmap = 0;
spellbookLastTabBattle = spellbookLastTabAdvmap = 4;
}