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

Basic version of hero movement on map. Removed old code.

This commit is contained in:
Ivan Savenko 2023-02-16 21:35:15 +02:00
parent d46687a9c8
commit 4501036a04
26 changed files with 401 additions and 1826 deletions

View File

@ -480,10 +480,6 @@ int main(int argc, char * argv[])
CCS->curh = new CursorHandler();
logGlobal->info("Screen handler: %d ms", pomtime.getDiff());
pomtime.getDiff();
graphics->load();//must be after Content loading but should be in main thread
logGlobal->info("Main graphics: %d ms", pomtime.getDiff());
CMessage::init();
logGlobal->info("Message handler: %d ms", pomtime.getDiff());

View File

@ -103,11 +103,6 @@ std::shared_ptr<BattleInterface> CPlayerInterface::battleInt;
enum EMoveState {STOP_MOVE, WAITING_MOVE, CONTINUE_MOVE, DURING_MOVE};
CondSh<EMoveState> stillMoveHero(STOP_MOVE); //used during hero movement
static bool objectBlitOrderSorter(const TerrainTileObject & a, const TerrainTileObject & b)
{
return CMapHandler::compareObjectBlitOrder(a.obj, b.obj);
}
struct HeroObjectRetriever : boost::static_visitor<const CGHeroInstance *>
{
const CGHeroInstance * operator()(const ConstTransitivePtr<CGHeroInstance> &h) const
@ -396,21 +391,9 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details, bool verbose)
return;
const CGHeroInstance * hero = cb->getHero(details.id); //object representing this hero
int3 hp = details.start;
if(!hero)
{
//AI hero left the visible area (we can't obtain info)
//TODO very evil workaround -> retrieve pointer to hero so we could animate it
// TODO -> we should not need full CGHeroInstance structure to display animation or it should not be handled by playerint (but by the client itself)
const TerrainTile2 & tile = CGI->mh->ttiles[hp.z][hp.x - 1][hp.y];
for(auto & elem : tile.objects)
if(elem.obj && elem.obj->id == details.id)
hero = dynamic_cast<const CGHeroInstance *>(elem.obj);
if(!hero) //still nothing...
return;
}
if (!hero)
return;
adventureInt->minimap->updateTile(hero->convertToVisitablePos(details.start));
adventureInt->minimap->updateTile(hero->convertToVisitablePos(details.end));
@ -474,60 +457,24 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details, bool verbose)
return;
}
ui32 speed = 0;
if(settings["session"]["spectate"].Bool())
{
if(!settings["session"]["spectate-hero-speed"].isNull())
speed = static_cast<ui32>(settings["session"]["spectate-hero-speed"].Integer());
}
else if(makingTurn) // our turn, our hero moves
speed = static_cast<ui32>(settings["adventure"]["heroSpeed"].Float());
else
speed = static_cast<ui32>(settings["adventure"]["enemySpeed"].Float());
if(speed == 0)
{
//FIXME: is this a proper solution?
CGI->mh->hideObject(hero);
CGI->mh->printObject(hero);
return; // no animation
}
adventureInt->centerOn(hero); //actualizing screen pos
adventureInt->minimap->redraw();
adventureInt->heroList->redraw();
initMovement(details, hero, hp);
auto waitFrame = [&]()
{
int frameNumber = GH.mainFPSmng->getFrameNumber();
auto unlockPim = vstd::makeUnlockGuard(*pim);
while(frameNumber == GH.mainFPSmng->getFrameNumber())
boost::this_thread::sleep(boost::posix_time::milliseconds(5));
boost::this_thread::sleep(boost::posix_time::milliseconds(1));
};
//first initializing done
//main moving
for(int i = 1; i < 32; i += 2 * speed)
{
movementPxStep(details, i, hp, hero);
#ifndef VCMI_ANDROID
// currently android doesn't seem to be able to handle all these full redraws here, so let's disable it so at least it looks less choppy;
// most likely this is connected with the way that this manual animation+framerate handling is solved
adventureInt->requestRedrawMapOnNextFrame();
#endif
//evil returns here ...
//todo: get rid of it
while (CGI->mh->hasActiveAnimations())
waitFrame(); //for animation purposes
}
//main moving done
//finishing move
finishMovement(details, hp, hero);
hero->isStanding = true;
//move finished
@ -570,6 +517,7 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details, bool verbose)
const_cast<CGHeroInstance *>(hero)->moveDir = dirLookup[posOffset.y][posOffset.x];
}
}
void CPlayerInterface::heroKilled(const CGHeroInstance* hero)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
@ -711,14 +659,12 @@ void CPlayerInterface::heroInGarrisonChange(const CGTownInstance *town)
if (town->garrisonHero) //wandering hero moved to the garrison
{
CGI->mh->hideObject(town->garrisonHero);
if (town->garrisonHero->tempOwner == playerID && vstd::contains(wanderingHeroes,town->garrisonHero)) // our hero
wanderingHeroes -= town->garrisonHero;
}
if (town->visitingHero) //hero leaves garrison
{
CGI->mh->printObject(town->visitingHero);
if (town->visitingHero->tempOwner == playerID && !vstd::contains(wanderingHeroes,town->visitingHero)) // our hero
wanderingHeroes.push_back(town->visitingHero);
}
@ -1748,7 +1694,7 @@ int CPlayerInterface::getLastIndex( std::string namePrefix)
return (--dates.end())->second; //return latest file number
return 0;
}
/*
void CPlayerInterface::initMovement( const TryMoveHero &details, const CGHeroInstance * ho, const int3 &hp )
{
auto subArr = (CGI->mh->ttiles)[hp.z];
@ -1892,7 +1838,7 @@ void CPlayerInterface::finishMovement( const TryMoveHero &details, const int3 &h
//recompute hero sprite positioning using hero's final position
movementPxStep(details, 32, hp, ho);
}
*/
void CPlayerInterface::gameOver(PlayerColor player, const EVictoryLossCheckResult & victoryLossCheckResult )
{
EVENT_HANDLER_CALLED_BY_CLIENT;
@ -2510,9 +2456,6 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance * h, CGPath path)
// (i == 0) means hero went through all the path
adventureInt->updateMoveHero(h, (i != 0));
adventureInt->updateNextHero(h);
// ugly workaround to force instant update of adventure map
adventureInt->animValHitCount = 8;
}
setMovementStatus(false);
@ -2558,13 +2501,10 @@ void CPlayerInterface::updateAmbientSounds(bool resetAll)
{
int dist = pos.dist(tile, int3::DIST_CHEBYSHEV);
// We want sound for every special terrain on tile and not just one on top
for(auto & ttObj : CGI->mh->ttiles[tile.z][tile.x][tile.y].objects)
{
if(ttObj.ambientSound)
updateSounds(ttObj.ambientSound.get(), dist);
}
if(CGI->mh->map->isCoastalTile(tile))
updateSounds("LOOPOCEA", dist);
for(auto & soundName : CGI->mh->getAmbientSounds(tile))
updateSounds(soundName, dist);
}
CCS->soundh->ambientUpdateChannels(currentSounds);
}

View File

@ -256,9 +256,6 @@ public:
void stopMovement();
void moveHero(const CGHeroInstance *h, const CGPath& path);
void initMovement(const TryMoveHero &details, const CGHeroInstance * ho, const int3 &hp );//initializing objects and performing first step of move
void movementPxStep( const TryMoveHero &details, int i, const int3 &hp, const CGHeroInstance * ho );//performing step of movement
void finishMovement( const TryMoveHero &details, const int3 &hp, const CGHeroInstance * ho ); //finish movement
void acceptTurn(); //used during hot seat after your turn message is close
void tryDiggging(const CGHeroInstance *h);

View File

@ -404,11 +404,8 @@ void CClient::initMapHandler()
// During loading CPlayerInterface from serialized state it's depend on MH
if(!settings["session"]["headless"].Bool())
{
const_cast<CGameInfo *>(CGI)->mh = new CMapHandler();
CGI->mh->map = gs->map;
const_cast<CGameInfo *>(CGI)->mh = new CMapHandler(gs->map);
logNetwork->trace("Creating mapHandler: %d ms", CSH->th->getDiff());
CGI->mh->init();
logNetwork->trace("Initializing mapHandler (together): %d ms", CSH->th->getDiff());
}
pathCache.clear();

View File

@ -229,7 +229,7 @@ public:
void setMovePoints(SetMovePoints * smp) override {};
void setManaPoints(ObjectInstanceID hid, int val) override {};
void giveHero(ObjectInstanceID id, PlayerColor player) override {};
void changeObjPos(ObjectInstanceID objid, int3 newPos, ui8 flags) override {};
void changeObjPos(ObjectInstanceID objid, int3 newPos) override {};
void sendAndApply(CPackForClient * pack) override {};
void heroExchange(ObjectInstanceID hero1, ObjectInstanceID hero2) override {};

View File

@ -342,14 +342,14 @@ void ApplyClientNetPackVisitor::visitGiveBonus(GiveBonus & pack)
void ApplyFirstClientNetPackVisitor::visitChangeObjPos(ChangeObjPos & pack)
{
CGObjectInstance *obj = gs.getObjInstance(pack.objid);
if(pack.flags & 1 && CGI->mh)
CGI->mh->hideObject(obj);
if(CGI->mh)
CGI->mh->onObjectFadeOut(obj);
}
void ApplyClientNetPackVisitor::visitChangeObjPos(ChangeObjPos & pack)
{
CGObjectInstance *obj = gs.getObjInstance(pack.objid);
if(pack.flags & 1 && CGI->mh)
CGI->mh->printObject(obj);
if(CGI->mh)
CGI->mh->onObjectFadeIn(obj);
cl.invalidatePaths();
}
@ -416,7 +416,7 @@ void ApplyFirstClientNetPackVisitor::visitRemoveObject(RemoveObject & pack)
const CGObjectInstance *o = cl.getObj(pack.id);
if(CGI->mh)
CGI->mh->hideObject(o, true);
CGI->mh->onObjectFadeOut(o);
//notify interfaces about removal
for(auto i=cl.playerint.begin(); i!=cl.playerint.end(); i++)
@ -443,7 +443,7 @@ void ApplyFirstClientNetPackVisitor::visitTryMoveHero(TryMoveHero & pack)
for(auto i=cl.playerint.begin(); i!=cl.playerint.end(); i++)
{
auto ps = gs.getPlayerState(i->first);
if(ps && (gs.isVisible(pack.start - int3(1, 0, 0), i->first) || gs.isVisible(pack.end - int3(1, 0, 0), i->first)))
if(ps && (gs.isVisible(h->convertToVisitablePos(pack.start), i->first) || gs.isVisible(h->convertToVisitablePos(pack.end), i->first)))
{
if(ps->human)
pack.humanKnows = true;
@ -452,12 +452,6 @@ void ApplyFirstClientNetPackVisitor::visitTryMoveHero(TryMoveHero & pack)
if(!CGI->mh)
return;
if(pack.result == TryMoveHero::TELEPORTATION || pack.result == TryMoveHero::EMBARK || pack.result == TryMoveHero::DISEMBARK || !pack.humanKnows)
CGI->mh->hideObject(h, pack.result == TryMoveHero::EMBARK && pack.humanKnows);
if(pack.result == TryMoveHero::DISEMBARK)
CGI->mh->printObject(h->boat);
}
void ApplyClientNetPackVisitor::visitTryMoveHero(TryMoveHero & pack)
@ -467,11 +461,26 @@ void ApplyClientNetPackVisitor::visitTryMoveHero(TryMoveHero & pack)
if(CGI->mh)
{
if(pack.result == TryMoveHero::TELEPORTATION || pack.result == TryMoveHero::EMBARK || pack.result == TryMoveHero::DISEMBARK)
CGI->mh->printObject(h, pack.result == TryMoveHero::DISEMBARK);
if(pack.result == TryMoveHero::EMBARK)
CGI->mh->hideObject(h->boat);
switch(pack.result)
{
case TryMoveHero::FAILED:
break; // no-op
case TryMoveHero::SUCCESS:
CGI->mh->onHeroMoved(h, pack.start, pack.end);
break;
case TryMoveHero::TELEPORTATION:
CGI->mh->onHeroTeleported(h, pack.start, pack.end);
break;
case TryMoveHero::BLOCKING_VISIT:
CGI->mh->onHeroRotated(h, pack.start, pack.end);
break;
case TryMoveHero::EMBARK:
CGI->mh->onObjectFadeOut(h);
break;
case TryMoveHero::DISEMBARK:
CGI->mh->onObjectFadeIn(h);
break;
}
}
PlayerColor player = h->tempOwner;
@ -485,19 +494,14 @@ void ApplyClientNetPackVisitor::visitTryMoveHero(TryMoveHero & pack)
if(i->first != PlayerColor::SPECTATOR && gs.checkForStandardLoss(i->first)) // Do not notify vanquished pack.player's interface
continue;
if(gs.isVisible(pack.start - int3(1, 0, 0), i->first)
|| gs.isVisible(pack.end - int3(1, 0, 0), i->first))
if(gs.isVisible(h->convertToVisitablePos(pack.start), i->first)
|| gs.isVisible(h->convertToVisitablePos(pack.end), i->first))
{
// pack.src and pack.dst of enemy hero move may be not visible => 'verbose' should be false
const bool verbose = cl.getPlayerRelations(i->first, player) != PlayerRelations::ENEMIES;
i->second->heroMoved(pack, verbose);
}
}
//maphandler didn't get update from playerint, do it now
//TODO: restructure nicely
if(!pack.humanKnows && CGI->mh)
CGI->mh->printObject(h);
}
void ApplyClientNetPackVisitor::visitNewStructures(NewStructures & pack)
@ -569,21 +573,19 @@ void ApplyClientNetPackVisitor::visitHeroRecruited(HeroRecruited & pack)
}
}
if(needsPrinting && CGI->mh)
CGI->mh->printObject(h);
CGI->mh->onObjectInstantAdd(h);
}
void ApplyClientNetPackVisitor::visitGiveHero(GiveHero & pack)
{
CGHeroInstance *h = gs.getHero(pack.id);
if(CGI->mh)
CGI->mh->printObject(h);
CGI->mh->onObjectInstantAdd(h);
callInterfaceIfPresent(cl, h->tempOwner, &IGameEventsReceiver::heroCreated, h);
}
void ApplyFirstClientNetPackVisitor::visitGiveHero(GiveHero & pack)
{
if(CGI->mh)
CGI->mh->hideObject(gs.getHero(pack.id));
}
void ApplyClientNetPackVisitor::visitInfoWindow(InfoWindow & pack)
@ -950,7 +952,7 @@ void ApplyClientNetPackVisitor::visitNewObject(NewObject & pack)
const CGObjectInstance *obj = cl.getObj(pack.id);
if(CGI->mh)
CGI->mh->printObject(obj, true);
CGI->mh->onObjectFadeIn(obj);
for(auto i=cl.playerint.begin(); i!=cl.playerint.end(); i++)
{

View File

@ -90,7 +90,6 @@ CAdvMapInt::CAdvMapInt():
terrain(new CTerrainRect),
state(NA),
spellBeingCasted(nullptr), selection(nullptr),
redrawOnNextFrame(false), anim(0), animValHitCount(0), heroAnim(0), heroAnimValHitCount(0),
activeMapPanel(nullptr), duringAITurn(false), scrollingDir(0), scrollingState(false),
swipeEnabled(settings["general"]["swipe"].Bool()), swipeMovementRequested(false),
swipeTargetPosition(Point(0, 0))
@ -239,9 +238,9 @@ CAdvMapInt::CAdvMapInt():
changeMode(EAdvMapMode::NORMAL);
underground->block(!CGI->mh->map->twoLevel);
questlog->block(!CGI->mh->map->quests.size());
worldViewUnderground->block(!CGI->mh->map->twoLevel);
underground->block(!CGI->mh->getMap()->twoLevel);
questlog->block(!CGI->mh->getMap()->quests.size());
worldViewUnderground->block(!CGI->mh->getMap()->twoLevel);
addUsedEvents(MOVE);
}
@ -254,7 +253,6 @@ void CAdvMapInt::fshowOverview()
void CAdvMapInt::fworldViewBack()
{
changeMode(EAdvMapMode::NORMAL);
CGI->mh->discardWorldViewCache();
auto hero = curHero();
if (hero)
@ -280,7 +278,7 @@ void CAdvMapInt::fworldViewScale4x()
void CAdvMapInt::fswitchLevel()
{
// with support for future multi-level maps :)
int maxLevels = CGI->mh->map->levels();
int maxLevels = CGI->mh->getMap()->levels();
if (maxLevels < 2)
return;
@ -292,7 +290,6 @@ void CAdvMapInt::fswitchLevel()
worldViewUnderground->setIndex(terrain->getLevel(), true);
worldViewUnderground->redraw();
redrawOnNextFrame = true;
minimap->setLevel(terrain->getLevel());
}
@ -322,7 +319,7 @@ void CAdvMapInt::fsleepWake()
void CAdvMapInt::fmoveHero()
{
const CGHeroInstance *h = curHero();
if (!h || !LOCPLINT->paths.hasPath(h) || !CGI->mh->canStartHeroMovement())
if (!h || !LOCPLINT->paths.hasPath(h) || CGI->mh->hasActiveAnimations())
return;
LOCPLINT->moveHero(h, LOCPLINT->paths.getPath(h));
@ -530,7 +527,6 @@ void CAdvMapInt::showAll(SDL_Surface * to)
}
activeMapPanel->showAll(to);
redrawOnNextFrame = true;
minimap->showAll(to);
show(to);
@ -564,20 +560,6 @@ void CAdvMapInt::show(SDL_Surface * to)
if(state != INGAME)
return;
++animValHitCount; //for animations
if(animValHitCount % 2 == 0)
{
++heroAnim;
}
if(animValHitCount >= 8)
{
CGI->mh->updateWater();
animValHitCount = 0;
++anim;
redrawOnNextFrame = true;
}
if(swipeEnabled)
{
handleSwipeUpdate();
@ -596,18 +578,14 @@ void CAdvMapInt::show(SDL_Surface * to)
else
gems[i]->setFrame(LOCPLINT->playerID.getNum());
}
if(redrawOnNextFrame)
{
for(int i = 0; i < 4; i++)
gems[i]->showAll(to);
redrawOnNextFrame=false;
LOCPLINT->cingconsole->show(to);
}
terrain->show(to);
for(int i = 0; i < 4; i++)
gems[i]->showAll(to);
LOCPLINT->cingconsole->show(to);
infoBar->show(to);
statusbar->showAll(to);
}
@ -616,30 +594,28 @@ void CAdvMapInt::handleMapScrollingUpdate()
{
int scrollSpeed = static_cast<int>(settings["adventure"]["scrollSpeed"].Float());
//if advmap needs updating AND (no dialog is shown OR ctrl is pressed)
if((animValHitCount % (4 / scrollSpeed)) == 0)
if(scrollingDir & LEFT)
terrain->moveViewBy(Point(-scrollSpeed, 0));
if(scrollingDir & RIGHT)
terrain->moveViewBy(Point(+scrollSpeed, 0));
if(scrollingDir & UP)
terrain->moveViewBy(Point(0, -scrollSpeed));
if(scrollingDir & DOWN)
terrain->moveViewBy(Point(0, +scrollSpeed));
if(scrollingDir)
{
if(scrollingDir & LEFT)
terrain->moveViewBy(Point(-4, 0));
if(scrollingDir & RIGHT)
terrain->moveViewBy(Point(+4, 0));
if(scrollingDir & UP)
terrain->moveViewBy(Point(0, -4));
if(scrollingDir & DOWN)
terrain->moveViewBy(Point(0, +4));
if(scrollingDir)
{
setScrollingCursor(scrollingDir);
scrollingState = true;
}
else if(scrollingState)
{
CCS->curh->set(Cursor::Map::POINTER);
scrollingState = false;
}
setScrollingCursor(scrollingDir);
scrollingState = true;
}
else if(scrollingState)
{
CCS->curh->set(Cursor::Map::POINTER);
scrollingState = false;
}
}
@ -649,7 +625,6 @@ void CAdvMapInt::handleSwipeUpdate()
{
terrain->setViewCenter(swipeTargetPosition, terrain->getLevel());
CCS->curh->set(Cursor::Map::POINTER);
redrawOnNextFrame = true;
minimap->redraw();
swipeMovementRequested = false;
}
@ -673,7 +648,6 @@ void CAdvMapInt::centerOn(int3 on, bool fade)
terrain->setViewCenter(on);
redrawOnNextFrame=true;
underground->setIndex(on.z,true); //change underground switch button image
underground->redraw();
worldViewUnderground->setIndex(on.z, true);
@ -859,7 +833,7 @@ void CAdvMapInt::keyPressed(const SDL_Keycode & key)
if(!h || !isActive())
return;
if (!CGI->mh->canStartHeroMovement())
if (CGI->mh->hasActiveAnimations())
return;
if(*direction == Point(0,0))
@ -870,7 +844,7 @@ void CAdvMapInt::keyPressed(const SDL_Keycode & key)
int3 dst = h->visitablePos() + int3(direction->x, direction->y, 0);
if(dst != verifyPos(dst))
if (!CGI->mh->isInMap((dst)))
return;
if ( !LOCPLINT->paths.setPath(h, dst))
@ -910,23 +884,6 @@ boost::optional<Point> CAdvMapInt::keyToMoveDirection(const SDL_Keycode & key)
return boost::none;
}
int3 CAdvMapInt::verifyPos(int3 ver)
{
if (ver.x<0)
ver.x=0;
if (ver.y<0)
ver.y=0;
if (ver.z<0)
ver.z=0;
if (ver.x>=CGI->mh->sizes.x)
ver.x=CGI->mh->sizes.x-1;
if (ver.y>=CGI->mh->sizes.y)
ver.y=CGI->mh->sizes.y-1;
if (ver.z>=CGI->mh->sizes.z)
ver.z=CGI->mh->sizes.z-1;
return ver;
}
void CAdvMapInt::select(const CArmedInstance *sel, bool centerView)
{
assert(sel);
@ -1181,7 +1138,7 @@ void CAdvMapInt::tileLClicked(const int3 &mapPos)
if(LOCPLINT->paths.hasPath(currentHero) &&
LOCPLINT->paths.getPath(currentHero).endPos() == mapPos)//we'll be moving
{
if(CGI->mh->canStartHeroMovement())
if(!CGI->mh->hasActiveAnimations())
LOCPLINT->moveHero(currentHero, LOCPLINT->paths.getPath(currentHero));
return;
}
@ -1556,15 +1513,3 @@ void CAdvMapInt::WorldViewOptions::clear()
iconPositions.clear();
}
void CAdvMapInt::WorldViewOptions::adjustDrawingInfo(MapDrawingInfo& info)
{
info.showAllTerrain = showAllTerrain;
info.additionalIcons = &iconPositions;
}
void CAdvMapInt::requestRedrawMapOnNextFrame()
{
redrawOnNextFrame = true;
}

View File

@ -67,7 +67,6 @@ private:
std::vector<ObjectPosInfo> iconPositions;
WorldViewOptions();
void clear();
void adjustDrawingInfo(MapDrawingInfo & info);
};
bool swipeEnabled;
@ -75,15 +74,7 @@ private:
Point swipeTargetPosition;
EGameStates state;
ui8 anim, animValHitCount; //animation frame
ui8 heroAnim, heroAnimValHitCount; //animation frame
/// top left corner of visible map part
//int3 position;
EAdvMapMode mode;
WorldViewOptions worldViewOptions;
/// Currently selected object, can be town, hero or null
@ -166,7 +157,6 @@ private:
boost::optional<Point> keyToMoveDirection(const SDL_Keycode & key);
bool redrawOnNextFrame;
public:
CAdvMapInt();
@ -184,12 +174,9 @@ public:
// public interface
void requestRedrawMapOnNextFrame();
void select(const CArmedInstance *sel, bool centerView = true);
void centerOn(int3 on, bool fade = false);
void centerOn(const CGObjectInstance *obj, bool fade = false);
int3 verifyPos(int3 ver);
bool isHeroSleeping(const CGHeroInstance *hero);
void setHeroSleeping(const CGHeroInstance *hero, bool sleep);

View File

@ -36,7 +36,6 @@
CTerrainRect::CTerrainRect()
: fadeSurface(nullptr)
, lastRedrawStatus(EMapAnimRedrawStatus::OK)
, fadeAnim(std::make_shared<CFadeAnimation>())
, curHoveredTile(-1, -1, -1)
, isSwiping(false)
@ -113,7 +112,7 @@ void CTerrainRect::clickRight(tribool down, bool previousState)
return;
int3 mp = whichTileIsIt();
if(CGI->mh->map->isInTheMap(mp) && down)
if(CGI->mh->isInMap(mp) && down)
adventureInt->tileRClicked(mp);
}
@ -180,18 +179,17 @@ bool CTerrainRect::handleSwipeStateChange(bool btnPressed)
void CTerrainRect::handleHover(const Point & cursorPosition)
{
int3 tHovered = whichTileIsIt(cursorPosition);
int3 pom = adventureInt->verifyPos(tHovered);
if(tHovered != pom) //tile outside the map
if(!CGI->mh->isInMap(tHovered))
{
CCS->curh->set(Cursor::Map::POINTER);
return;
}
if (pom != curHoveredTile)
if (tHovered != curHoveredTile)
{
curHoveredTile = pom;
adventureInt->tileHovered(pom);
curHoveredTile = tHovered;
adventureInt->tileHovered(tHovered);
}
}
@ -205,50 +203,6 @@ void CTerrainRect::hover(bool on)
//Hoverable::hover(on);
}
/*
void CTerrainRect::show(SDL_Surface * to)
{
if (adventureInt->mode == EAdvMapMode::NORMAL)
{
MapDrawingInfo info(adventureInt->position, LOCPLINT->cb->getVisibilityMap(), pos);
info.otherheroAnim = true;
info.anim = adventureInt->anim;
info.heroAnim = adventureInt->heroAnim;
if (ADVOPT.smoothMove)
info.movement = int3(moveX, moveY, 0);
lastRedrawStatus = CGI->mh->drawTerrainRectNew(to, &info);
if (fadeAnim->isFading())
{
Rect r(pos);
fadeAnim->update();
fadeAnim->draw(to, r.topLeft());
}
}
}
void CTerrainRect::showAll(SDL_Surface * to)
{
// world view map is static and doesn't need redraw every frame
if (adventureInt->mode == EAdvMapMode::WORLD_VIEW)
{
MapDrawingInfo info(adventureInt->position, LOCPLINT->cb->getVisibilityMap(), pos, adventureInt->worldViewIcons);
info.scaled = true;
info.scale = adventureInt->worldViewScale;
adventureInt->worldViewOptions.adjustDrawingInfo(info);
CGI->mh->drawTerrainRectNew(to, &info);
}
}
void CTerrainRect::showAnim(SDL_Surface * to)
{
if (!needsAnimUpdate())
return;
if (fadeAnim->isFading() || lastRedrawStatus == EMapAnimRedrawStatus::REDRAW_REQUESTED)
show(to);
}
*/
int3 CTerrainRect::whichTileIsIt(const Point &position)
{
return renderer->getModel()->getTileAtPoint(position - pos);
@ -277,11 +231,6 @@ void CTerrainRect::fadeFromCurrentView()
fadeAnim->init(CFadeAnimation::EMode::OUT, fadeSurface);
}
bool CTerrainRect::needsAnimUpdate()
{
return fadeAnim->isFading() || lastRedrawStatus == EMapAnimRedrawStatus::REDRAW_REQUESTED;
}
void CTerrainRect::setLevel(int level)
{
renderer->setViewCenter(renderer->getModel()->getMapViewCenter(), level);

View File

@ -16,7 +16,6 @@ VCMI_LIB_NAMESPACE_BEGIN
struct CGPath;
VCMI_LIB_NAMESPACE_END
enum class EMapAnimRedrawStatus;
class CFadeAnimation;
class MapView;
@ -26,7 +25,6 @@ class CTerrainRect : public CIntObject
std::shared_ptr<MapView> renderer;
SDL_Surface * fadeSurface;
EMapAnimRedrawStatus lastRedrawStatus;
std::shared_ptr<CFadeAnimation> fadeAnim;
Point swipeInitialViewPos;
@ -48,8 +46,6 @@ class CTerrainRect : public CIntObject
int3 whichTileIsIt(const Point & position); //x,y are cursor position
int3 whichTileIsIt(); //uses current cursor pos
bool needsAnimUpdate();
public:
CTerrainRect();
~CTerrainRect();

View File

@ -326,10 +326,12 @@ std::shared_ptr<CAnimation> MapRendererObjects::getAnimation(const CGObjectInsta
return std::shared_ptr<CAnimation>();
}
return getAnimation(info->animationFile);
bool generateMovementGroups = (info->id == Obj::BOAT) || (info->id == Obj::HERO);
return getAnimation(info->animationFile, generateMovementGroups);
}
std::shared_ptr<CAnimation> MapRendererObjects::getAnimation(const std::string & filename)
std::shared_ptr<CAnimation> MapRendererObjects::getAnimation(const std::string & filename, bool generateMovementGroups)
{
if (animations.count(filename))
return animations[filename];
@ -338,73 +340,27 @@ std::shared_ptr<CAnimation> MapRendererObjects::getAnimation(const std::string &
animations[filename] = ret;
ret->preload();
if (generateMovementGroups)
{
ret->createFlippedGroup(1,13);
ret->createFlippedGroup(2,14);
ret->createFlippedGroup(3,15);
ret->createFlippedGroup(6,10);
ret->createFlippedGroup(7,11);
ret->createFlippedGroup(8,12);
}
return ret;
}
void MapRendererObjects::initializeObjects(const IMapRendererContext & context)
MapRendererObjects::MapRendererObjects(const IMapRendererContext & context)
{
auto mapSize = context.getMapSize();
objects.resize(boost::extents[mapSize.z][mapSize.x][mapSize.y]);
for(const auto & obj : context.getAllObjects())
{
if(!obj)
continue;
if(obj->ID == Obj::HERO && dynamic_cast<const CGHeroInstance *>(obj.get())->inTownGarrison)
continue;
if(obj->ID == Obj::BOAT && dynamic_cast<const CGBoat *>(obj.get())->hero)
continue;
std::shared_ptr<CAnimation> animation = getAnimation(obj);
//no animation at all, e.g. Event
if(!animation)
continue;
//empty animation. Illegal?
assert(animation->size(0) > 0);
if(animation->size(0) == 0)
continue;
auto image = animation->getImage(0, 0);
int imageWidthTiles = (image->width() + 31) / 32;
int imageHeightTiles = (image->height() + 31) / 32;
int objectWidth = std::min(obj->getWidth(), imageWidthTiles);
int objectHeight = std::min(obj->getHeight(), imageHeightTiles);
for(int fx = 0; fx < objectWidth; ++fx)
{
for(int fy = 0; fy < objectHeight; ++fy)
{
int3 currTile(obj->pos.x - fx, obj->pos.y - fy, obj->pos.z);
if(context.isInMap(currTile) && obj->coveringAt(currTile.x, currTile.y))
objects[currTile.z][currTile.x][currTile.y].push_back(obj->id);
}
}
}
for(int z = 0; z < mapSize.z; z++)
{
for(int x = 0; x < mapSize.x; x++)
{
for(int y = 0; y < mapSize.y; y++)
{
auto & array = objects[z][x][y];
std::sort(array.begin(), array.end(), MapObjectsSorter(context));
}
}
}
}
MapRendererObjects::MapRendererObjects(const IMapRendererContext & context)
{
initializeObjects(context);
onObjectInstantAdd(context, obj);
}
std::shared_ptr<CAnimation> MapRendererObjects::getFlagAnimation(const CGObjectInstance* obj)
@ -425,7 +381,7 @@ std::shared_ptr<CAnimation> MapRendererObjects::getFlagAnimation(const CGObjectI
{
assert(dynamic_cast<const CGHeroInstance *>(obj) != nullptr);
assert(obj->tempOwner.isValidPlayer());
return getAnimation(heroFlags[obj->tempOwner.getNum()]);
return getAnimation(heroFlags[obj->tempOwner.getNum()], true);
}
if(obj->ID == Obj::BOAT)
{
@ -435,7 +391,7 @@ std::shared_ptr<CAnimation> MapRendererObjects::getFlagAnimation(const CGObjectI
assert(!boat->hero || boat->hero->tempOwner.isValidPlayer());
if(boat->hero)
return getAnimation(boatFlags[obj->subID][boat->hero->tempOwner.getNum()]);
return getAnimation(boatFlags[obj->subID][boat->hero->tempOwner.getNum()], true);
}
return nullptr;
}
@ -516,14 +472,59 @@ void MapRendererObjects::renderTile(const IMapRendererContext & context, Canvas
}
}
void MapRendererObjects::addObject(const IMapRendererContext & context, const CGObjectInstance * object)
void MapRendererObjects::onObjectInstantAdd(const IMapRendererContext & context, const CGObjectInstance * obj)
{
if(!obj)
return;
if(obj->ID == Obj::HERO && dynamic_cast<const CGHeroInstance *>(obj)->inTownGarrison)
return;
if(obj->ID == Obj::BOAT && dynamic_cast<const CGBoat *>(obj)->hero)
return;
std::shared_ptr<CAnimation> animation = getAnimation(obj);
//no animation at all, e.g. Event
if(!animation)
return;
//empty animation. Illegal?
assert(animation->size(0) > 0);
if(animation->size(0) == 0)
return;
auto image = animation->getImage(0, 0);
int imageWidthTiles = (image->width() + 31) / 32;
int imageHeightTiles = (image->height() + 31) / 32;
int objectWidth = std::min(obj->getWidth(), imageWidthTiles);
int objectHeight = std::min(obj->getHeight(), imageHeightTiles);
for(int fx = 0; fx < objectWidth; ++fx)
{
for(int fy = 0; fy < objectHeight; ++fy)
{
int3 currTile(obj->pos.x - fx, obj->pos.y - fy, obj->pos.z);
if(context.isInMap(currTile) && obj->coveringAt(currTile.x, currTile.y))
{
auto & container = objects[currTile.z][currTile.x][currTile.y];
container.push_back(obj->id);
boost::range::sort(container, MapObjectsSorter(context));
}
}
}
}
void MapRendererObjects::removeObject(const IMapRendererContext & context, const CGObjectInstance * object)
void MapRendererObjects::onObjectInstantRemove(const IMapRendererContext & context, const CGObjectInstance * object)
{
for(int z = 0; z < context.getMapSize().z; z++)
for(int x = 0; x < context.getMapSize().x; x++)
for(int y = 0; y < context.getMapSize().y; y++)
vstd::erase(objects[z][x][y], object->id);
}
void MapRendererDebugGrid::renderTile(const IMapRendererContext & context, Canvas & target, const int3 & coordinates)
@ -656,13 +657,3 @@ void MapRenderer::renderTile(const IMapRendererContext & context, Canvas & targe
}
rendererDebugGrid.renderTile(context, target,coordinates);
}
void MapRenderer::addObject(const IMapRendererContext & context, const CGObjectInstance * object)
{
rendererObjects.addObject(context, object);
}
void MapRenderer::removeObject(const IMapRendererContext & context, const CGObjectInstance * object)
{
rendererObjects.addObject(context, object);
}

View File

@ -9,6 +9,8 @@
*/
#pragma once
#include "MapRendererContext.h"
VCMI_LIB_NAMESPACE_BEGIN
class int3;
@ -20,31 +22,33 @@ VCMI_LIB_NAMESPACE_END
class CAnimation;
class IImage;
class Canvas;
class IMapRendererContext;
class MapObjectsSorter
{
const IMapRendererContext & context;
public:
explicit MapObjectsSorter(const IMapRendererContext & context);
bool operator ()(const ObjectInstanceID & left, const ObjectInstanceID & right) const;
bool operator ()(const CGObjectInstance * left, const CGObjectInstance * right) const;
bool operator()(const ObjectInstanceID & left, const ObjectInstanceID & right) const;
bool operator()(const CGObjectInstance * left, const CGObjectInstance * right) const;
};
class MapTileStorage
{
using TerrainAnimation = std::array<std::unique_ptr<CAnimation>, 4>;
std::vector<TerrainAnimation> animations;
public:
explicit MapTileStorage( size_t capacity);
void load(size_t index, const std::string& filename);
std::shared_ptr<IImage> find(size_t fileIndex, size_t rotationIndex, size_t imageIndex );
explicit MapTileStorage(size_t capacity);
void load(size_t index, const std::string & filename);
std::shared_ptr<IImage> find(size_t fileIndex, size_t rotationIndex, size_t imageIndex);
};
class MapRendererTerrain
{
MapTileStorage storage;
public:
MapRendererTerrain();
void renderTile(const IMapRendererContext & context, Canvas & target, const int3 & coordinates);
@ -53,6 +57,7 @@ public:
class MapRendererRiver
{
MapTileStorage storage;
public:
MapRendererRiver();
void renderTile(const IMapRendererContext & context, Canvas & target, const int3 & coordinates);
@ -61,36 +66,36 @@ public:
class MapRendererRoad
{
MapTileStorage storage;
public:
MapRendererRoad();
void renderTile(const IMapRendererContext & context, Canvas & target, const int3 & coordinates);
};
class MapRendererObjects
class MapRendererObjects : public IMapObjectObserver
{
using MapObject = ObjectInstanceID;
using MapTile = std::vector<MapObject>;
using MapTile = std::vector<MapObject>;
boost::multi_array<MapTile, 3> objects;
std::map<std::string, std::shared_ptr<CAnimation>> animations;
std::shared_ptr<CAnimation> getFlagAnimation(const CGObjectInstance* obj);
std::shared_ptr<CAnimation> getAnimation(const CGObjectInstance* obj);
std::shared_ptr<CAnimation> getAnimation(const std::string & filename);
std::shared_ptr<CAnimation> getFlagAnimation(const CGObjectInstance * obj);
std::shared_ptr<CAnimation> getAnimation(const CGObjectInstance * obj);
std::shared_ptr<CAnimation> getAnimation(const std::string & filename, bool generateMovementGroups);
std::shared_ptr<IImage> getImage(const IMapRendererContext & context, const CGObjectInstance * obj, const std::shared_ptr<CAnimation>& animation) const;
std::shared_ptr<IImage> getImage(const IMapRendererContext & context, const CGObjectInstance * obj, const std::shared_ptr<CAnimation> & animation) const;
size_t getAnimationGroup(const IMapRendererContext & context, const CGObjectInstance * obj) const;
void initializeObjects(const IMapRendererContext & context);
void renderImage(Canvas & target, const int3 & coordinates, const CGObjectInstance * object, const std::shared_ptr<IImage>& image);
void renderImage(Canvas & target, const int3 & coordinates, const CGObjectInstance * object, const std::shared_ptr<IImage> & image);
void renderObject(const IMapRendererContext & context, Canvas & target, const int3 & coordinates, const CGObjectInstance * obj);
void renderObject(const IMapRendererContext & context, Canvas & target, const int3 & coordinates, const CGObjectInstance* obj);
public:
explicit MapRendererObjects(const IMapRendererContext & context);
void renderTile(const IMapRendererContext & context, Canvas & target, const int3 & coordinates);
void addObject(const IMapRendererContext & context, const CGObjectInstance * object);
void removeObject(const IMapRendererContext & context, const CGObjectInstance * object);
void onObjectInstantAdd(const IMapRendererContext & context, const CGObjectInstance * object) final override;
void onObjectInstantRemove(const IMapRendererContext & context, const CGObjectInstance * object) final override;
};
class MapRendererBorder
@ -98,6 +103,7 @@ class MapRendererBorder
std::unique_ptr<CAnimation> animation;
size_t getIndexForTile(const IMapRendererContext & context, const int3 & coordinates);
public:
MapRendererBorder();
void renderTile(const IMapRendererContext & context, Canvas & target, const int3 & coordinates);
@ -120,12 +126,12 @@ class MapRendererPath
void renderImage(Canvas & target, bool reachableToday, size_t imageIndex);
void renderImageCross(Canvas & target, bool reachableToday, const int3 & curr);
void renderImageArrow(Canvas & target, bool reachableToday, const int3 & curr, const int3 & prev, const int3 & next);
public:
MapRendererPath();
void renderTile(const IMapRendererContext & context, Canvas & target, const int3 & coordinates);
};
class MapRendererDebugGrid
{
public:
@ -147,8 +153,4 @@ public:
explicit MapRenderer(const IMapRendererContext & context);
void renderTile(const IMapRendererContext & context, Canvas & target, const int3 & coordinates);
void addObject(const IMapRendererContext & context, const CGObjectInstance * object);
void removeObject(const IMapRendererContext & context, const CGObjectInstance * object);
};

View File

@ -17,6 +17,7 @@ class int3;
class Point;
class ObjectInstanceID;
class CGObjectInstance;
class CGHeroInstance;
struct TerrainTile;
struct CGPath;
@ -27,7 +28,7 @@ class IMapRendererContext
public:
virtual ~IMapRendererContext() = default;
using ObjectsVector = std::vector< ConstTransitivePtr<CGObjectInstance> >;
using ObjectsVector = std::vector<ConstTransitivePtr<CGObjectInstance>>;
/// returns dimensions of current map
virtual int3 getMapSize() const = 0;
@ -42,7 +43,7 @@ public:
virtual ObjectsVector getAllObjects() const = 0;
/// returns specific object by ID, or nullptr if not found
virtual const CGObjectInstance * getObject( ObjectInstanceID objectID ) const = 0;
virtual const CGObjectInstance * getObject(ObjectInstanceID objectID) const = 0;
/// returns path of currently active hero, or nullptr if none
virtual const CGPath * currentPath() const = 0;
@ -62,3 +63,31 @@ public:
/// if true, map grid should be visible on map
virtual bool showGrid() const = 0;
};
class IMapObjectObserver
{
public:
IMapObjectObserver();
virtual ~IMapObjectObserver();
/// Plays fade-in animation and adds object to map
virtual void onObjectFadeIn(const IMapRendererContext & context, const CGObjectInstance * obj) {}
/// Plays fade-out animation and removed object from map
virtual void onObjectFadeOut(const IMapRendererContext & context, const CGObjectInstance * obj) {}
/// Adds object to map instantly, with no animation
virtual void onObjectInstantAdd(const IMapRendererContext & context, const CGObjectInstance * obj) {}
/// Removes object from map instantly, with no animation
virtual void onObjectInstantRemove(const IMapRendererContext & context, const CGObjectInstance * obj) {}
/// Perform hero teleportation animation with terrain fade animation
virtual void onHeroTeleported(const IMapRendererContext & context, const CGHeroInstance * obj, const int3 & from, const int3 & dest) {}
/// Perform hero movement animation, moving hero across terrain
virtual void onHeroMoved(const IMapRendererContext & context, const CGHeroInstance * obj, const int3 & from, const int3 & dest) {}
/// Instantly rotates hero to face destination tile
virtual void onHeroRotated(const IMapRendererContext & context, const CGHeroInstance * obj, const int3 & from, const int3 & dest) {}
};

View File

@ -147,17 +147,17 @@ bool MapRendererContext::isInMap(const int3 & coordinates) const
const TerrainTile & MapRendererContext::getMapTile(const int3 & coordinates) const
{
return CGI->mh->map->getTile(coordinates);
return CGI->mh->getMap()->getTile(coordinates);
}
MapRendererContext::ObjectsVector MapRendererContext::getAllObjects() const
{
return CGI->mh->map->objects;
return CGI->mh->getMap()->objects;
}
const CGObjectInstance * MapRendererContext::getObject(ObjectInstanceID objectID) const
{
return CGI->mh->map->objects.at(objectID.getNum());
return CGI->mh->getMap()->objects.at(objectID.getNum());
}
bool MapRendererContext::isVisible(const int3 & coordinates) const

View File

@ -18,7 +18,7 @@ class MapRenderer;
class MapRendererContext : public IMapRendererContext
{
Point tileSize = Point(32,32);
Point tileSize = Point(32, 32);
uint32_t animationTime = 0;
public:
@ -50,10 +50,11 @@ class MapViewModel
Point viewDimensions;
int mapLevel = 0;
public:
void setTileSize(Point const & newValue);
void setViewCenter(Point const & newValue);
void setViewDimensions(Point const & newValue);
void setTileSize(const Point & newValue);
void setViewCenter(const Point & newValue);
void setViewDimensions(const Point & newValue);
void setLevel(int newLevel);
/// returns current size of map tile in pixels
@ -112,6 +113,7 @@ class MapView : public CIntObject
std::unique_ptr<MapCache> tilesCache;
std::shared_ptr<MapViewModel> createModel(const Point & dimensions) const;
public:
std::shared_ptr<const MapViewModel> getModel() const;
@ -121,6 +123,8 @@ public:
void setViewCenter(const Point & position, int level);
void setTileSize(const Point & tileSize);
void moveHero();
void show(SDL_Surface * to) override;
void showAll(SDL_Surface * to) override;
};

File diff suppressed because it is too large Load Diff

View File

@ -9,12 +9,12 @@
*/
#pragma once
#include "../gui/CIntObject.h"
#include "../../lib/int3.h"
#include "../../lib/spells/ViewSpellInt.h"
#include "../../lib/Rect.h"
#include "../gui/CIntObject.h"
#ifdef IN
#undef IN
@ -40,6 +40,7 @@ class CAnimation;
class IImage;
class CFadeAnimation;
class CMapHandler;
class IMapObjectObserver;
enum class EWorldViewIcon
{
@ -72,12 +73,6 @@ enum class EMapObjectFadingType
OUT
};
enum class EMapAnimRedrawStatus
{
OK,
REDRAW_REQUESTED // map blitter requests quick redraw due to current animation
};
struct TerrainTileObject
{
const CGObjectInstance *obj;
@ -94,319 +89,43 @@ struct TerrainTile2
std::vector<TerrainTileObject> objects; //pointers to objects being on this tile with rects to be easier to blit this tile on screen
};
struct MapDrawingInfo
{
bool scaled;
int3 &topTile; // top-left tile in viewport [in tiles]
std::shared_ptr<const boost::multi_array<ui8, 3>> visibilityMap;
Rect drawBounds; // map rect drawing bounds on screen
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;
ui8 anim;
ui8 heroAnim;
int3 movement; // used for smooth map movement
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_, std::shared_ptr<const boost::multi_array<ui8, 3>> visibilityMap_, const Rect & drawBounds_, std::shared_ptr<CAnimation> icons_ = nullptr)
: scaled(false),
topTile(topTile_),
visibilityMap(visibilityMap_),
drawBounds(drawBounds_),
icons(icons_),
scale(1.0f),
otherheroAnim(false),
anim(0u),
heroAnim(0u),
movement(int3()),
puzzleMode(false),
grailPos(int3()),
additionalIcons(nullptr),
showAllTerrain(false)
{}
ui8 getHeroAnim() const { return otherheroAnim ? anim : heroAnim; }
};
template <typename T> class PseudoV
{
public:
PseudoV() : offset(0) { }
inline T & operator[](const int & n)
{
return inver[n+offset];
}
inline const T & operator[](const int & n) const
{
return inver[n+offset];
}
void resize(int rest, int before, int after)
{
inver.resize(before + rest + after);
offset=before;
}
int size() const
{
return static_cast<int>(inver.size());
}
private:
int offset;
std::vector<T> inver;
};
enum class EMapCacheType : ui8
{
TERRAIN, OBJECTS, ROADS, RIVERS, FOW, HEROES, HERO_FLAGS, FRAME, AFTER_LAST
};
/// temporarily caches rescaled frames for map world view redrawing
class CMapCache
{
std::array< std::map<intptr_t, std::shared_ptr<IImage>>, (ui8)EMapCacheType::AFTER_LAST> data;
float worldViewCachedScale;
public:
CMapCache();
/// destroys all cached data (frees surfaces)
void discardWorldViewCache();
/// updates scale and determines if currently cached data is still valid
void updateWorldViewScale(float scale);
/// asks for cached data; @returns cached data if found, new scaled surface otherwise, may return nullptr in case of scaling error
std::shared_ptr<IImage> requestWorldViewCacheOrCreate(EMapCacheType type, std::shared_ptr<IImage> fullSurface);
};
/// helper struct to pass around resolved bitmaps of an object; images can be nullptr if object doesn't have bitmap of that type
struct AnimBitmapHolder
{
std::shared_ptr<IImage> objBitmap; // main object bitmap
std::shared_ptr<IImage> 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(std::shared_ptr<IImage> objBitmap_ = nullptr, std::shared_ptr<IImage> flagBitmap_ = nullptr, bool moving = false)
: objBitmap(objBitmap_),
flagBitmap(flagBitmap_),
isMoving(moving)
{}
};
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
int tileSize; // size of a tile drawn on map [in pixels]
int halfTileSizeCeil; // half of the tile size, rounded up
int3 tileCount; // number of tiles in current viewport
int3 topTile; // top-left tile of the viewport
int3 initPos; // starting drawing position [in pixels]
int3 pos; // current position [in tiles]
int3 realPos; // current position [in pixels]
Rect realTileRect; // default rect based on current pos: [realPos.x, realPos.y, tileSize, tileSize]
Rect defaultTileRect; // default rect based on 0: [0, 0, tileSize, tileSize]
const MapDrawingInfo * info; // data for drawing passed from outside
/// general drawing method, called internally by more specialized ones
virtual void drawElement(EMapCacheType cacheType, std::shared_ptr<IImage> source, Rect * sourceRect, SDL_Surface * targetSurf, Rect * destRect) const = 0;
// first drawing pass
/// draws terrain bitmap (or custom bitmap if applicable) on current tile
virtual void drawTileTerrain(SDL_Surface * targetSurf, const TerrainTile & tinfo, const TerrainTile2 & tile) const;
/// draws a river segment on current tile
virtual void drawRiver(SDL_Surface * targetSurf, const TerrainTile & tinfo) const;
/// draws a road segment on current tile
virtual void drawRoad(SDL_Surface * targetSurf, const TerrainTile & tinfo, const TerrainTile * tinfoUpper) const;
/// draws all objects on current tile (higher-level logic, unlike other draw*** methods)
virtual void drawObjects(SDL_Surface * targetSurf, const TerrainTile2 & tile) const;
virtual void drawObject(SDL_Surface * targetSurf, std::shared_ptr<IImage> source, Rect * sourceRect, bool moving) const;
virtual void drawHeroFlag(SDL_Surface * targetSurf, std::shared_ptr<IImage> source, Rect * sourceRect, Rect * destRect, bool moving) const;
// second drawing pass
/// current tile: draws overlay over the map, used to draw world view icons
virtual void drawTileOverlay(SDL_Surface * targetSurf, const TerrainTile2 & tile) const = 0;
/// draws fog of war on current tile
virtual void drawFow(SDL_Surface * targetSurf) const;
/// draws map border frame on current position
virtual void drawFrame(SDL_Surface * targetSurf) const;
/// draws additional icons (for VIEW_AIR, VIEW_EARTH spells atm)
virtual void drawOverlayEx(SDL_Surface * targetSurf);
// third drawing pass
/// custom post-processing, if needed (used by puzzle view)
virtual void postProcessing(SDL_Surface * targetSurf) const {}
// misc methods
/// initializes frame-drawing (called at the start of every redraw)
virtual void init(const MapDrawingInfo * drawingInfo) = 0;
/// calculates clip region for map viewport
virtual Rect clip(SDL_Surface * targetSurf) const = 0;
virtual ui8 getHeroFrameGroup(ui8 dir, bool isMoving) const;
virtual ui8 getPhaseShift(const CGObjectInstance *object) const;
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;
std::shared_ptr<IImage> findFlagBitmap(const CGHeroInstance * obj, int anim, const PlayerColor * color, int group) const;
std::shared_ptr<IImage> findHeroFlagBitmap(const CGHeroInstance * obj, int anim, const PlayerColor * color, int group) const;
std::shared_ptr<IImage> findBoatFlagBitmap(const CGBoat * obj, int anim, const PlayerColor * color, int group, ui8 dir) const;
std::shared_ptr<IImage> findFlagBitmapInternal(std::shared_ptr<CAnimation> animation, int anim, int group, ui8 dir, bool moving) const;
public:
CMapBlitter(CMapHandler * p);
virtual ~CMapBlitter();
void blit(SDL_Surface * targetSurf, const MapDrawingInfo * info);
/// helper method that chooses correct bitmap(s) for given object
AnimBitmapHolder findObjectBitmap(const CGObjectInstance * obj, int anim) const;
};
class CMapNormalBlitter : public CMapBlitter
{
protected:
void drawElement(EMapCacheType cacheType, std::shared_ptr<IImage> source, Rect * sourceRect, SDL_Surface * targetSurf, Rect * destRect) const override;
void drawTileOverlay(SDL_Surface * targetSurf,const TerrainTile2 & tile) const override {}
void init(const MapDrawingInfo * info) override;
Rect clip(SDL_Surface * targetSurf) const override;
public:
CMapNormalBlitter(CMapHandler * parent);
virtual ~CMapNormalBlitter(){}
};
class CMapWorldViewBlitter : public CMapBlitter
{
private:
std::shared_ptr<IImage> objectToIcon(Obj id, si32 subId, PlayerColor owner) const;
protected:
void drawElement(EMapCacheType cacheType, std::shared_ptr<IImage> source, Rect * sourceRect, SDL_Surface * targetSurf, Rect * destRect) const override;
void drawTileOverlay(SDL_Surface * targetSurf, const TerrainTile2 & tile) const override;
void drawHeroFlag(SDL_Surface * targetSurf, std::shared_ptr<IImage> source, Rect * sourceRect, Rect * destRect, bool moving) const override;
void drawObject(SDL_Surface * targetSurf, std::shared_ptr<IImage> source, Rect * sourceRect, bool moving) const override;
void drawFrame(SDL_Surface * targetSurf) const override {}
void drawOverlayEx(SDL_Surface * targetSurf) override;
void init(const MapDrawingInfo * info) override;
Rect clip(SDL_Surface * targetSurf) const override;
ui8 getPhaseShift(const CGObjectInstance *object) const override { return 0u; }
void calculateWorldViewCameraPos();
public:
CMapWorldViewBlitter(CMapHandler * parent);
virtual ~CMapWorldViewBlitter(){}
};
class CMapPuzzleViewBlitter : public CMapNormalBlitter
{
std::vector<int> unblittableObjects;
void drawObjects(SDL_Surface * targetSurf, const TerrainTile2 & tile) const override;
void drawFow(SDL_Surface * targetSurf) const override {} // skipping FoW in puzzle view
void postProcessing(SDL_Surface * targetSurf) const override;
bool canDrawObject(const CGObjectInstance * obj) const override;
bool canDrawCurrentTile() const override { return true; }
public:
CMapPuzzleViewBlitter(CMapHandler * parent);
};
class CMapHandler
{
friend class CMapBlitter;
friend class CMapNormalBlitter;
friend class CMapWorldViewBlitter;
CMapCache cache;
CMapBlitter * normalBlitter;
CMapBlitter * worldViewBlitter;
CMapBlitter * puzzleViewBlitter;
std::map<int, std::pair<int3, CFadeAnimation*>> fadeAnims;
int fadeAnimCounter;
CMapBlitter * resolveBlitter(const MapDrawingInfo * info) const;
bool updateObjectsFade();
bool startObjectFade(TerrainTileObject & obj, bool in, int3 pos);
void initObjectRects();
void initBorderGraphics();
void initTerrainGraphics();
void prepareFOWDefs();
public: //TODO: make private
boost::multi_array<TerrainTile2, 3> ttiles; //informations about map tiles [z][x][y]
int3 sizes; //map size (x = width, y = height, z = number of levels)
const CMap * map;
private:
// Max number of tiles that will fit in the map screen. Tiles
// can be partial on each edges.
int tilesW;
int tilesH;
// size of each side of the frame around the whole map, in tiles
int frameH;
int frameW;
// Coord in pixels of the top left corner of the top left tile to
// draw. Values range is [-31..0]. A negative value
// implies that part of the tile won't be displayed.
int offsetX;
int offsetY;
//terrain graphics
//FIXME: unique_ptr should be enough, but fails to compile in MSVS 2013
typedef std::map<std::string, std::array<std::shared_ptr<CAnimation>, 4>> TFlippedAnimations; //[type, rotation]
typedef std::map<std::string, std::vector<std::array<std::shared_ptr<IImage>, 4>>> TFlippedCache;//[type, view type, rotation]
TFlippedAnimations terrainAnimations;//[terrain type, rotation]
TFlippedCache terrainImages;//[terrain type, view type, rotation]
TFlippedAnimations roadAnimations;//[road type, rotation]
TFlippedCache roadImages;//[road type, view type, rotation]
TFlippedAnimations riverAnimations;//[river type, rotation]
TFlippedCache riverImages;//[river type, view type, rotation]
//Fog of War cache (not owned)
std::vector<std::shared_ptr<IImage>> FoWfullHide;
boost::multi_array<ui8, 3> hideBitmap; //frame indexes (in FoWfullHide) of graphic that should be used to fully hide a tile
std::vector<std::shared_ptr<IImage>> FoWpartialHide;
//edge graphics
std::unique_ptr<CAnimation> egdeAnimation;
std::vector<std::shared_ptr<IImage>> egdeImages;//cache of links to egdeAnimation (for faster access)
PseudoV< PseudoV< PseudoV <ui8> > > edgeFrames; //frame indexes (in egdeImages) of tile outside of map
mutable std::map<const CGObjectInstance*, ui8> animationPhase;
std::vector<IMapObjectObserver *> observers;
public:
CMapHandler();
~CMapHandler();
explicit CMapHandler(const CMap * map);
void getTerrainDescr(const int3 & pos, std::string & out, bool isRMB) const; // isRMB = whether Right Mouse Button is clicked
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 hasObjectHole(const int3 & pos) const; // Checks if TerrainTile2 tile has a pit remained after digging.
void init();
const CMap * getMap();
/// returns true if tile is within map bounds
bool isInMap(const int3 & tile);
/// see MapObjectObserver interface
void onObjectFadeIn(const CGObjectInstance * obj);
void onObjectFadeOut(const CGObjectInstance * obj);
void onObjectInstantAdd(const CGObjectInstance * obj);
void onObjectInstantRemove(const CGObjectInstance * obj);
void onHeroTeleported(const CGHeroInstance * obj, const int3 & from, const int3 & dest);
void onHeroMoved(const CGHeroInstance * obj, const int3 & from, const int3 & dest);
void onHeroRotated(const CGHeroInstance * obj, const int3 & from, const int3 & dest);
/// Add object to receive notifications on any changes in visible map state
void addMapObserver(IMapObjectObserver * observer);
void removeMapObserver(IMapObjectObserver * observer);
/// returns string description for terrain interaction
void getTerrainDescr(const int3 & pos, std::string & out, bool isRMB) const;
/// returns list of ambient sounds for specified tile
std::vector<std::string> getAmbientSounds(const int3 & tile);
/// returns true if tile has hole from grail digging attempt
bool hasObjectHole(const int3 & pos) const;
EMapAnimRedrawStatus drawTerrainRectNew(SDL_Surface * targetSurface, const MapDrawingInfo * info, bool redrawOnlyAnim = false);
void updateWater();
/// determines if the map is ready to handle new hero movement (not available during fading animations)
bool canStartHeroMovement();
void discardWorldViewCache();
bool hasActiveAnimations();
static bool compareObjectBlitOrder(const CGObjectInstance * a, const CGObjectInstance * b);
};

View File

@ -159,115 +159,6 @@ Graphics::~Graphics()
delete[] neutralColorPalette;
}
void Graphics::load()
{
heroMoveArrows = std::make_shared<CAnimation>("ADAG");
heroMoveArrows->preload();
loadHeroAnimations();
loadHeroFlagAnimations();
loadFogOfWar();
}
void Graphics::loadHeroAnimations()
{
for(auto & elem : CGI->heroh->classes.objects)
{
for (auto & templ : VLC->objtypeh->getHandlerFor(Obj::HERO, elem->getIndex())->getTemplates())
{
if (!heroAnimations.count(templ->animationFile))
heroAnimations[templ->animationFile] = loadHeroAnimation(templ->animationFile);
}
}
boatAnimations[0] = loadHeroAnimation("AB01_.DEF");
boatAnimations[1] = loadHeroAnimation("AB02_.DEF");
boatAnimations[2] = loadHeroAnimation("AB03_.DEF");
mapObjectAnimations["AB01_.DEF"] = boatAnimations[0];
mapObjectAnimations["AB02_.DEF"] = boatAnimations[1];
mapObjectAnimations["AB03_.DEF"] = boatAnimations[2];
}
void Graphics::loadHeroFlagAnimations()
{
static const std::vector<std::string> HERO_FLAG_ANIMATIONS =
{
"AF00", "AF01","AF02","AF03",
"AF04", "AF05","AF06","AF07"
};
static const std::vector< std::vector<std::string> > BOAT_FLAG_ANIMATIONS =
{
{
"ABF01L", "ABF01G", "ABF01R", "ABF01D",
"ABF01B", "ABF01P", "ABF01W", "ABF01K"
},
{
"ABF02L", "ABF02G", "ABF02R", "ABF02D",
"ABF02B", "ABF02P", "ABF02W", "ABF02K"
},
{
"ABF03L", "ABF03G", "ABF03R", "ABF03D",
"ABF03B", "ABF03P", "ABF03W", "ABF03K"
}
};
for(const auto & name : HERO_FLAG_ANIMATIONS)
heroFlagAnimations.push_back(loadHeroFlagAnimation(name));
for(int i = 0; i < BOAT_FLAG_ANIMATIONS.size(); i++)
for(const auto & name : BOAT_FLAG_ANIMATIONS[i])
boatFlagAnimations[i].push_back(loadHeroFlagAnimation(name));
}
std::shared_ptr<CAnimation> Graphics::loadHeroFlagAnimation(const std::string & name)
{
//first - group number to be rotated, second - group number after rotation
static const std::vector<std::pair<int,int> > rotations =
{
{6,10}, {7,11}, {8,12}, {1,13},
{2,14}, {3,15}
};
std::shared_ptr<CAnimation> anim = std::make_shared<CAnimation>(name);
anim->preload();
for(const auto & rotation : rotations)
{
const int sourceGroup = rotation.first;
const int targetGroup = rotation.second;
anim->createFlippedGroup(sourceGroup, targetGroup);
}
return anim;
}
std::shared_ptr<CAnimation> Graphics::loadHeroAnimation(const std::string &name)
{
//first - group number to be rotated, second - group number after rotation
static const std::vector<std::pair<int,int> > rotations =
{
{6,10}, {7,11}, {8,12}, {1,13},
{2,14}, {3,15}
};
std::shared_ptr<CAnimation> anim = std::make_shared<CAnimation>(name);
anim->preload();
for(const auto & rotation : rotations)
{
const int sourceGroup = rotation.first;
const int targetGroup = rotation.second;
anim->createFlippedGroup(sourceGroup, targetGroup);
}
return anim;
}
void Graphics::blueToPlayersAdv(SDL_Surface * sur, PlayerColor player)
{
if(sur->format->palette)
@ -335,26 +226,6 @@ void Graphics::blueToPlayersAdv(SDL_Surface * sur, PlayerColor player)
}
}
void Graphics::loadFogOfWar()
{
fogOfWarFullHide = std::make_shared<CAnimation>("TSHRC");
fogOfWarFullHide->preload();
fogOfWarPartialHide = std::make_shared<CAnimation>("TSHRE");
fogOfWarPartialHide->preload();
static const int rotations [] = {22, 15, 2, 13, 12, 16, 28, 17, 20, 19, 7, 24, 26, 25, 30, 32, 27};
size_t size = fogOfWarPartialHide->size(0);//group size after next rotation
for(const int rotation : rotations)
{
fogOfWarPartialHide->duplicateImage(0, rotation, 0);
auto image = fogOfWarPartialHide->getImage(size, 0);
image->verticalFlip();
size++;
}
}
void Graphics::loadFonts()
{
const JsonNode config(ResourceID("config/fonts.json"));
@ -378,41 +249,6 @@ void Graphics::loadFonts()
}
}
std::shared_ptr<CAnimation> Graphics::getAnimation(const CGObjectInstance* obj)
{
return getAnimation(obj->appearance);
}
std::shared_ptr<CAnimation> Graphics::getAnimation(std::shared_ptr<const ObjectTemplate> info)
{
//the only(?) invisible object
if(info->id == Obj::EVENT)
{
return std::shared_ptr<CAnimation>();
}
if(info->animationFile.empty())
{
logGlobal->warn("Def name for obj (%d,%d) is empty!", info->id, info->subid);
return std::shared_ptr<CAnimation>();
}
std::shared_ptr<CAnimation> ret = mapObjectAnimations[info->animationFile];
//already loaded
if(ret)
{
ret->preload();
return ret;
}
ret = std::make_shared<CAnimation>(info->animationFile);
mapObjectAnimations[info->animationFile] = ret;
ret->preload();
return ret;
}
void Graphics::loadErmuToPicture()
{
//loading ERMU to picture

View File

@ -39,23 +39,11 @@ enum EFonts : int
class Graphics
{
void addImageListEntry(size_t index, size_t group, const std::string & listName, const std::string & imageName);
void addImageListEntries(const EntityService * service);
void initializeBattleGraphics();
void loadPaletteAndColors();
void loadHeroAnimations();
//loads animation and adds required rotated frames
std::shared_ptr<CAnimation> loadHeroAnimation(const std::string &name);
void loadHeroFlagAnimations();
//loads animation and adds required rotated frames
std::shared_ptr<CAnimation> loadHeroFlagAnimation(const std::string &name);
void loadErmuToPicture();
void loadFogOfWar();
void loadFonts();
void initializeImageLists();
@ -70,23 +58,6 @@ public:
SDL_Color * playerColorPalette; //palette to make interface colors good - array of size [256]
SDL_Color * neutralColorPalette;
std::shared_ptr<CAnimation> heroMoveArrows;
// [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::map< std::string, std::shared_ptr<CAnimation> > heroAnimations;
std::vector< std::shared_ptr<CAnimation> > heroFlagAnimations;
// [boat type: 0 .. 2] //added group 10: up - left, 11 - left and 12 - left down // 13 - up-left standing; 14 - left standing; 15 - left down standing
std::array< std::shared_ptr<CAnimation>, 3> boatAnimations;
std::array< std::vector<std::shared_ptr<CAnimation> >, 3> boatFlagAnimations;
//all other objects (not hero or boat)
std::map< std::string, std::shared_ptr<CAnimation> > mapObjectAnimations;
std::shared_ptr<CAnimation> fogOfWarFullHide;
std::shared_ptr<CAnimation> fogOfWarPartialHide;
std::map<std::string, JsonNode> imageLists;
//towns
@ -98,12 +69,7 @@ public:
Graphics();
~Graphics();
void load();
void blueToPlayersAdv(SDL_Surface * sur, PlayerColor player); //replaces blue interface colour with a color of player
std::shared_ptr<CAnimation> getAnimation(const CGObjectInstance * obj);
std::shared_ptr<CAnimation> getAnimation(std::shared_ptr<const ObjectTemplate> info);
};
extern Graphics * graphics;

View File

@ -21,7 +21,6 @@
#include "../CVideoHandler.h"
#include "../CServerHandler.h"
#include "../adventureMap/mapHandler.h"
#include "../adventureMap/CResDataBar.h"
#include "../battle/BattleInterfaceClasses.h"
#include "../battle/BattleInterface.h"
@ -1159,14 +1158,15 @@ CPuzzleWindow::CPuzzleWindow(const int3 & GrailPos, double discoveredRatio)
void CPuzzleWindow::showAll(SDL_Surface * to)
{
int3 moveInt = int3(8, 9, 0);
Rect mapRect = Rect(Point(pos.x + 8, pos.y + 7), Point(544, 591));
int3 topTile = grailPos - moveInt;
assert(0);
//int3 moveInt = int3(8, 9, 0);
//Rect mapRect = Rect(Point(pos.x + 8, pos.y + 7), Point(544, 591));
//int3 topTile = grailPos - moveInt;
MapDrawingInfo info(topTile, LOCPLINT->cb->getVisibilityMap(), mapRect);
info.puzzleMode = true;
info.grailPos = grailPos;
CGI->mh->drawTerrainRectNew(to, &info);
//MapDrawingInfo info(topTile, LOCPLINT->cb->getVisibilityMap(), mapRect);
//info.puzzleMode = true;
//info.grailPos = grailPos;
//CGI->mh->drawTerrainRectNew(to, &info);
CWindowObject::showAll(to);
}

View File

@ -126,7 +126,7 @@ public:
virtual void setMovePoints(SetMovePoints * smp)=0;
virtual void setManaPoints(ObjectInstanceID hid, int val)=0;
virtual void giveHero(ObjectInstanceID id, PlayerColor player)=0;
virtual void changeObjPos(ObjectInstanceID objid, int3 newPos, ui8 flags)=0;
virtual void changeObjPos(ObjectInstanceID objid, int3 newPos)=0;
virtual void sendAndApply(CPackForClient * pack) = 0;
virtual void heroExchange(ObjectInstanceID hero1, ObjectInstanceID hero2)=0; //when two heroes meet on adventure map
virtual void changeFogOfWar(int3 center, ui32 radius, PlayerColor player, bool hide) = 0;

View File

@ -380,7 +380,6 @@ struct DLL_LINKAGE ChangeObjPos : public CPackForClient
ObjectInstanceID objid;
int3 nPos;
ui8 flags = 0; //bit flags: 1 - redraw
virtual void visitTyped(ICPackVisitor & visitor) override;
@ -388,7 +387,6 @@ struct DLL_LINKAGE ChangeObjPos : public CPackForClient
{
h & objid;
h & nPos;
h & flags;
}
};
@ -583,7 +581,6 @@ struct DLL_LINKAGE TryMoveHero : public CPackForClient
FAILED,
SUCCESS,
TELEPORTATION,
RESERVED_,
BLOCKING_VISIT,
EMBARK,
DISEMBARK

View File

@ -22,11 +22,13 @@ public:
Point()
{
x = y = 0;
};
}
Point(int X, int Y)
:x(X),y(Y)
{};
: x(X)
, y(Y)
{
}
explicit DLL_LINKAGE Point(const int3 &a);

View File

@ -200,7 +200,6 @@ ESpellCastResult SummonBoatMechanics::applyAdventureEffects(SpellCastEnvironment
ChangeObjPos cop;
cop.objid = nearest->id;
cop.nPos = summonPos + int3(1,0,0);
cop.flags = 1;
env->apply(&cop);
}
else if(schoolLevel < 2) //none or basic level -> cannot create boat :(

View File

@ -2773,12 +2773,11 @@ void CGameHandler::giveHero(ObjectInstanceID id, PlayerColor player)
sendAndApply(&gh);
}
void CGameHandler::changeObjPos(ObjectInstanceID objid, int3 newPos, ui8 flags)
void CGameHandler::changeObjPos(ObjectInstanceID objid, int3 newPos)
{
ChangeObjPos cop;
cop.objid = objid;
cop.nPos = newPos;
cop.flags = flags;
sendAndApply(&cop);
}

View File

@ -195,7 +195,7 @@ public:
void setMovePoints(SetMovePoints * smp) override;
void setManaPoints(ObjectInstanceID hid, int val) override;
void giveHero(ObjectInstanceID id, PlayerColor player) override;
void changeObjPos(ObjectInstanceID objid, int3 newPos, ui8 flags) override;
void changeObjPos(ObjectInstanceID objid, int3 newPos) override;
void heroExchange(ObjectInstanceID hero1, ObjectInstanceID hero2) override;
void changeFogOfWar(int3 center, ui32 radius, PlayerColor player, bool hide) override;