diff --git a/client/mapView/IMapRendererContext.h b/client/mapView/IMapRendererContext.h index 1c5f9e6ee..c1ff9bfc6 100644 --- a/client/mapView/IMapRendererContext.h +++ b/client/mapView/IMapRendererContext.h @@ -56,8 +56,8 @@ public: /// returns true if specified object is the currently active hero virtual bool isActiveHero(const CGObjectInstance* obj) const = 0; - /// returns direction of attacker if specified object is a monster and currently attacked - virtual int monsterAttacked(const CGObjectInstance * obj) const = 0; + /// Returns moveDir of hero that attacked this wandering monster, or -1 on failure + virtual int attackedMonsterDirection(const CGObjectInstance * wanderingMonster) const = 0; virtual size_t objectGroupIndex(ObjectInstanceID objectID) const = 0; virtual Point objectImageOffset(ObjectInstanceID objectID, const int3 & coordinates) const = 0; diff --git a/client/mapView/MapRenderer.cpp b/client/mapView/MapRenderer.cpp index b0462cf60..26a282ceb 100644 --- a/client/mapView/MapRenderer.cpp +++ b/client/mapView/MapRenderer.cpp @@ -420,6 +420,19 @@ std::shared_ptr MapRendererObjects::getAnimation(const AnimationPath return ret; } +std::shared_ptr MapRendererObjects::getImage(const ImagePath & filename) const +{ + auto it = images.find(filename); + + if(it != images.end()) + return it->second; + + auto ret = ENGINE->renderHandler().loadImage(filename, EImageBlitMode::SIMPLE); + images[filename] = ret; + + return ret; +} + std::shared_ptr MapRendererObjects::getFlagAnimation(const CGObjectInstance* obj) { //TODO: relocate to config file? @@ -456,7 +469,7 @@ std::shared_ptr MapRendererObjects::getOverlayAnimation(const CGObje return nullptr; } -std::shared_ptr MapRendererObjects::getImage(IMapRendererContext & context, const CGObjectInstance * obj, const std::shared_ptr& animation) const +std::shared_ptr MapRendererObjects::getImageToRender(IMapRendererContext & context, const CGObjectInstance * obj, const std::shared_ptr& animation) const { if(!animation) return nullptr; @@ -466,7 +479,7 @@ std::shared_ptr MapRendererObjects::getImage(IMapRendererContext & conte if(animation->size(groupIndex) == 0) return nullptr; - auto attackerPos = context.monsterAttacked(obj); + auto attackerPos = context.attackedMonsterDirection(obj); if(attackerPos != -1) { const auto * creature = dynamic_cast(obj); @@ -474,10 +487,7 @@ std::shared_ptr MapRendererObjects::getImage(IMapRendererContext & conte auto dir = std::vector({1, 2, 7, 8}); ImagePath imgPath = std::count(dir.begin(), dir.end(), attackerPos) ? creatureType->mapAttackFromRight : creatureType->mapAttackFromLeft; if(!imgPath.empty()) - { - auto img = ENGINE->renderHandler().loadImage(imgPath, EImageBlitMode::SIMPLE); - return img; - } + return getImage(imgPath); } size_t frameIndex = context.objectImageIndex(obj->id, animation->size(groupIndex)); @@ -516,9 +526,9 @@ void MapRendererObjects::renderImage(IMapRendererContext & context, Canvas & tar void MapRendererObjects::renderObject(IMapRendererContext & context, Canvas & target, const int3 & coordinates, const CGObjectInstance * instance) { - renderImage(context, target, coordinates, instance, getImage(context, instance, getBaseAnimation(instance))); - renderImage(context, target, coordinates, instance, getImage(context, instance, getFlagAnimation(instance))); - renderImage(context, target, coordinates, instance, getImage(context, instance, getOverlayAnimation(instance))); + renderImage(context, target, coordinates, instance, getImageToRender(context, instance, getBaseAnimation(instance))); + renderImage(context, target, coordinates, instance, getImageToRender(context, instance, getFlagAnimation(instance))); + renderImage(context, target, coordinates, instance, getImageToRender(context, instance, getOverlayAnimation(instance))); } void MapRendererObjects::renderTile(IMapRendererContext & context, Canvas & target, const int3 & coordinates) diff --git a/client/mapView/MapRenderer.h b/client/mapView/MapRenderer.h index 085846c63..9a69bc24a 100644 --- a/client/mapView/MapRenderer.h +++ b/client/mapView/MapRenderer.h @@ -73,14 +73,16 @@ public: class MapRendererObjects { std::map> animations; + mutable std::map> images; std::shared_ptr getBaseAnimation(const CGObjectInstance * obj); std::shared_ptr getFlagAnimation(const CGObjectInstance * obj); std::shared_ptr getOverlayAnimation(const CGObjectInstance * obj); std::shared_ptr getAnimation(const AnimationPath & filename, bool generateMovementGroups, bool enableOverlay); + std::shared_ptr getImage(const ImagePath & filename) const; - std::shared_ptr getImage(IMapRendererContext & context, const CGObjectInstance * obj, const std::shared_ptr & animation) const; + std::shared_ptr getImageToRender(IMapRendererContext & context, const CGObjectInstance * obj, const std::shared_ptr & animation) const; void renderImage(IMapRendererContext & context, Canvas & target, const int3 & coordinates, const CGObjectInstance * object, const std::shared_ptr & image); void renderObject(IMapRendererContext & context, Canvas & target, const int3 & coordinates, const CGObjectInstance * obj); diff --git a/client/mapView/MapRendererContext.cpp b/client/mapView/MapRendererContext.cpp index 3fa9811da..f1c23c76a 100644 --- a/client/mapView/MapRendererContext.cpp +++ b/client/mapView/MapRendererContext.cpp @@ -87,13 +87,13 @@ bool MapRendererBaseContext::isActiveHero(const CGObjectInstance * obj) const return false; } -int MapRendererBaseContext::monsterAttacked(const CGObjectInstance * obj) const +int MapRendererBaseContext::attackedMonsterDirection(const CGObjectInstance * wanderingMonster) const { - if(obj->ID != Obj::MONSTER) + if(wanderingMonster->ID != Obj::MONSTER) return -1; for(auto & battle : GAME->interface()->cb->getActiveBattles()) - if(obj->pos == battle.second->getBattle()->getLocation()) + if(wanderingMonster->pos == battle.second->getBattle()->getLocation()) return battle.second->getBattle()->getSideHero(BattleSide::ATTACKER)->moveDir; return -1; diff --git a/client/mapView/MapRendererContext.h b/client/mapView/MapRendererContext.h index 35d891cc5..cc71fbc5d 100644 --- a/client/mapView/MapRendererContext.h +++ b/client/mapView/MapRendererContext.h @@ -36,7 +36,7 @@ public: bool tileAnimated(const int3 & coordinates) const override; bool isActiveHero(const CGObjectInstance* obj) const override; - int monsterAttacked(const CGObjectInstance * obj) const override; + int attackedMonsterDirection(const CGObjectInstance * wanderingMonster) const override; const TerrainTile & getMapTile(const int3 & coordinates) const override; const MapObjectsList & getObjects(const int3 & coordinates) const override; diff --git a/docs/modders/Entities_Format/Creature_Format.md b/docs/modders/Entities_Format/Creature_Format.md index 66cb5a83d..b308e4c7c 100644 --- a/docs/modders/Entities_Format/Creature_Format.md +++ b/docs/modders/Entities_Format/Creature_Format.md @@ -128,6 +128,10 @@ In order to make functional creature you also need: "iconSmall" : "", // Large icon for this creature, used for example in town screen "iconLarge" : "", + + // Optional. Images of creatures when attacked on adventure map + "mapAttackFromRight": "", + "mapAttackFromLeft": "", // animation parameters