From d0d3b96fa90e3cdad6de5a0e44713ce397e15e7d Mon Sep 17 00:00:00 2001 From: Laserlicht <13953785+Laserlicht@users.noreply.github.com> Date: Fri, 20 Jun 2025 01:51:10 +0200 Subject: [PATCH 1/7] add battle animation --- client/mapView/IMapRendererContext.h | 3 +++ client/mapView/MapRenderer.cpp | 6 ++++++ client/mapView/MapRendererContext.cpp | 14 ++++++++++++++ client/mapView/MapRendererContext.h | 1 + client/renderSDL/RenderHandler.cpp | 10 ++++++++++ lib/callback/CBattleCallback.cpp | 5 +++++ lib/callback/CBattleCallback.h | 1 + 7 files changed, 40 insertions(+) diff --git a/client/mapView/IMapRendererContext.h b/client/mapView/IMapRendererContext.h index e1ae49f47..23315257f 100644 --- a/client/mapView/IMapRendererContext.h +++ b/client/mapView/IMapRendererContext.h @@ -56,6 +56,9 @@ public: /// returns true if specified object is the currently active hero virtual bool isActiveHero(const CGObjectInstance* obj) const = 0; + /// returns true if specified object is a monster and currently attacked + virtual bool isMonsterAttacked(const CGObjectInstance * obj) 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 9c157b264..7028a7dfd 100644 --- a/client/mapView/MapRenderer.cpp +++ b/client/mapView/MapRenderer.cpp @@ -465,6 +465,12 @@ std::shared_ptr MapRendererObjects::getImage(IMapRendererContext & conte if(animation->size(groupIndex) == 0) return nullptr; + + if(context.isMonsterAttacked(obj)) + { + auto img = ENGINE->renderHandler().loadImage(ImagePath::builtin("AvWattak:0:0"), EImageBlitMode::SIMPLE); + return img; + } size_t frameIndex = context.objectImageIndex(obj->id, animation->size(groupIndex)); diff --git a/client/mapView/MapRendererContext.cpp b/client/mapView/MapRendererContext.cpp index 9c5f66a31..2f5432ed6 100644 --- a/client/mapView/MapRendererContext.cpp +++ b/client/mapView/MapRendererContext.cpp @@ -25,6 +25,8 @@ #include "../../lib/spells/CSpellHandler.h" #include "../../lib/mapping/CMap.h" #include "../../lib/pathfinder/CGPathNode.h" +#include "../../lib/battle/CPlayerBattleCallback.h" +#include "../../lib/battle/IBattleState.h" MapRendererBaseContext::MapRendererBaseContext(const MapRendererContextState & viewState) : viewState(viewState) @@ -85,6 +87,18 @@ bool MapRendererBaseContext::isActiveHero(const CGObjectInstance * obj) const return false; } +bool MapRendererBaseContext::isMonsterAttacked(const CGObjectInstance * obj) const +{ + if(obj->ID != Obj::MONSTER) + return false; + + for(auto & battle : GAME->interface()->cb->getActiveBattles()) + if(obj->pos == battle.second->getBattle()->getLocation()) + return true; + + return false; +} + bool MapRendererBaseContext::tileAnimated(const int3 & coordinates) const { return false; diff --git a/client/mapView/MapRendererContext.h b/client/mapView/MapRendererContext.h index b956f1f09..f7c169d43 100644 --- a/client/mapView/MapRendererContext.h +++ b/client/mapView/MapRendererContext.h @@ -36,6 +36,7 @@ public: bool tileAnimated(const int3 & coordinates) const override; bool isActiveHero(const CGObjectInstance* obj) const override; + bool isMonsterAttacked(const CGObjectInstance * obj) const override; const TerrainTile & getMapTile(const int3 & coordinates) const override; const MapObjectsList & getObjects(const int3 & coordinates) const override; diff --git a/client/renderSDL/RenderHandler.cpp b/client/renderSDL/RenderHandler.cpp index fa49ee327..1afebdb20 100644 --- a/client/renderSDL/RenderHandler.cpp +++ b/client/renderSDL/RenderHandler.cpp @@ -354,6 +354,16 @@ std::shared_ptr RenderHandler::loadImage(const AnimationPath & path, int std::shared_ptr RenderHandler::loadImage(const ImagePath & path, EImageBlitMode mode) { + auto name = path.getOriginalName(); + + std::vector splitted; + boost::split(splitted, name, boost::is_any_of(":")); + if(splitted.size() == 3) + { + ImageLocator locator = getLocatorForAnimationFrame(AnimationPath::builtin(splitted[0]), std::stoi(splitted[2]), std::stoi(splitted[1]), 1, mode); + return loadImage(locator); + } + ImageLocator locator(path, mode); return loadImage(locator); } diff --git a/lib/callback/CBattleCallback.cpp b/lib/callback/CBattleCallback.cpp index a603f4bfd..5908fe6e9 100644 --- a/lib/callback/CBattleCallback.cpp +++ b/lib/callback/CBattleCallback.cpp @@ -79,6 +79,11 @@ void CBattleCallback::onBattleEnded(const BattleID & battleID) activeBattles.erase(battleID); } +std::map> CBattleCallback::getActiveBattles() +{ + return activeBattles; +} + void CBattleCallback::battleMakeSpellAction(const BattleID & battleID, const BattleAction & action) { assert(action.actionType == EActionType::HERO_SPELL); diff --git a/lib/callback/CBattleCallback.h b/lib/callback/CBattleCallback.h index c34110788..0d524fec6 100644 --- a/lib/callback/CBattleCallback.h +++ b/lib/callback/CBattleCallback.h @@ -39,6 +39,7 @@ public: void onBattleStarted(const IBattleInfo * info); void onBattleEnded(const BattleID & battleID); + std::map> getActiveBattles(); }; VCMI_LIB_NAMESPACE_END From e1adbde5ac5dd3b6bed2001daf20c2d9ee12c915 Mon Sep 17 00:00:00 2001 From: Laserlicht <13953785+Laserlicht@users.noreply.github.com> Date: Fri, 20 Jun 2025 03:02:43 +0200 Subject: [PATCH 2/7] direction & image functionality --- client/mapView/IMapRendererContext.h | 4 ++-- client/mapView/MapRenderer.cpp | 11 ++++++++--- client/mapView/MapRendererContext.cpp | 8 ++++---- client/mapView/MapRendererContext.h | 2 +- config/schemas/creature.json | 10 ++++++++++ lib/CCreatureHandler.cpp | 2 ++ lib/CCreatureHandler.h | 2 ++ 7 files changed, 29 insertions(+), 10 deletions(-) diff --git a/client/mapView/IMapRendererContext.h b/client/mapView/IMapRendererContext.h index 23315257f..964e44f5d 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 true if specified object is a monster and currently attacked - virtual bool isMonsterAttacked(const CGObjectInstance * obj) const = 0; + /// returns pos of attacker if specified object is a monster and currently attacked + virtual std::optional monsterAttacked(const CGObjectInstance * obj) 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 7028a7dfd..0f66a5338 100644 --- a/client/mapView/MapRenderer.cpp +++ b/client/mapView/MapRenderer.cpp @@ -466,10 +466,15 @@ std::shared_ptr MapRendererObjects::getImage(IMapRendererContext & conte if(animation->size(groupIndex) == 0) return nullptr; - if(context.isMonsterAttacked(obj)) + if(auto attackerPos = context.monsterAttacked(obj)) { - auto img = ENGINE->renderHandler().loadImage(ImagePath::builtin("AvWattak:0:0"), EImageBlitMode::SIMPLE); - return img; + const auto * creature = dynamic_cast(obj); + ImagePath imgPath = (*attackerPos).x < obj->pos.x ? (*creature->getCreatureMap().begin()).first->mapAttackFromLeft : (*creature->getCreatureMap().begin()).first->mapAttackFromRight; + if(!imgPath.empty()) + { + auto img = ENGINE->renderHandler().loadImage(imgPath, EImageBlitMode::SIMPLE); + return img; + } } size_t frameIndex = context.objectImageIndex(obj->id, animation->size(groupIndex)); diff --git a/client/mapView/MapRendererContext.cpp b/client/mapView/MapRendererContext.cpp index 2f5432ed6..c5f10bf37 100644 --- a/client/mapView/MapRendererContext.cpp +++ b/client/mapView/MapRendererContext.cpp @@ -87,16 +87,16 @@ bool MapRendererBaseContext::isActiveHero(const CGObjectInstance * obj) const return false; } -bool MapRendererBaseContext::isMonsterAttacked(const CGObjectInstance * obj) const +std::optional MapRendererBaseContext::monsterAttacked(const CGObjectInstance * obj) const { if(obj->ID != Obj::MONSTER) - return false; + return std::nullopt; for(auto & battle : GAME->interface()->cb->getActiveBattles()) if(obj->pos == battle.second->getBattle()->getLocation()) - return true; + return battle.second->getBattle()->getSideHero(BattleSide::ATTACKER)->pos; - return false; + return std::nullopt; } bool MapRendererBaseContext::tileAnimated(const int3 & coordinates) const diff --git a/client/mapView/MapRendererContext.h b/client/mapView/MapRendererContext.h index f7c169d43..67b620084 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; - bool isMonsterAttacked(const CGObjectInstance * obj) const override; + std::optional monsterAttacked(const CGObjectInstance * obj) const override; const TerrainTile & getMapTile(const int3 & coordinates) const override; const MapObjectsList & getObjects(const int3 & coordinates) const override; diff --git a/config/schemas/creature.json b/config/schemas/creature.json index 19c218a39..dee7b063b 100644 --- a/config/schemas/creature.json +++ b/config/schemas/creature.json @@ -153,6 +153,16 @@ "items" : { "type" : "string" }, "description" : "Object mask that describes on which tiles object is visible/blocked/activatable" }, + "mapAttackFromLeft" : { + "type" : "string", + "description" : "Adventure map creature image when attacked from left", + "format" : "imageFile" + }, + "mapAttackFromRight" : { + "type" : "string", + "description" : "Adventure map creature image when attacked from right", + "format" : "imageFile" + }, "iconLarge" : { "type" : "string", "description" : "Large icon for this creature, used for example in town screen", diff --git a/lib/CCreatureHandler.cpp b/lib/CCreatureHandler.cpp index 5ce9fe00f..d1a300b55 100644 --- a/lib/CCreatureHandler.cpp +++ b/lib/CCreatureHandler.cpp @@ -901,6 +901,8 @@ void CCreatureHandler::loadJsonAnimation(CCreature * cre, const JsonNode & graph void CCreatureHandler::loadCreatureJson(CCreature * creature, const JsonNode & config) const { creature->animDefName = AnimationPath::fromJson(config["graphics"]["animation"]); + creature->mapAttackFromLeft = ImagePath::fromJson(config["graphics"]["mapAttackFromLeft"]); + creature->mapAttackFromRight = ImagePath::fromJson(config["graphics"]["mapAttackFromRight"]); //FIXME: MOD COMPATIBILITY if (config["abilities"].getType() == JsonNode::JsonType::DATA_STRUCT) diff --git a/lib/CCreatureHandler.h b/lib/CCreatureHandler.h index 4ba246eef..3ee4879c4 100644 --- a/lib/CCreatureHandler.h +++ b/lib/CCreatureHandler.h @@ -67,6 +67,8 @@ public: std::set upgrades; // IDs of creatures to which this creature can be upgraded AnimationPath animDefName; // creature animation used during battles + ImagePath mapAttackFromLeft; // adventure map creature image when attacked from left + ImagePath mapAttackFromRight; // adventure map creature image when attacked from right si32 iconIndex = -1; // index of icon in files like twcrport, used in tests now. /// names of files with appropriate icons. Used only during loading From 0cb74bc719f69c828486339a9948f1304c5d556e Mon Sep 17 00:00:00 2001 From: Laserlicht <13953785+Laserlicht@users.noreply.github.com> Date: Fri, 20 Jun 2025 03:25:44 +0200 Subject: [PATCH 3/7] config change --- config/creatures/castle.json | 28 ++++++++++++++++++++++++++++ config/creatures/conflux.json | 28 ++++++++++++++++++++++++++++ config/creatures/dungeon.json | 28 ++++++++++++++++++++++++++++ config/creatures/fortress.json | 28 ++++++++++++++++++++++++++++ config/creatures/inferno.json | 28 ++++++++++++++++++++++++++++ config/creatures/necropolis.json | 28 ++++++++++++++++++++++++++++ config/creatures/neutral.json | 30 ++++++++++++++++++++++++++++++ config/creatures/rampart.json | 28 ++++++++++++++++++++++++++++ config/creatures/stronghold.json | 28 ++++++++++++++++++++++++++++ config/creatures/tower.json | 28 ++++++++++++++++++++++++++++ 10 files changed, 282 insertions(+) diff --git a/config/creatures/castle.json b/config/creatures/castle.json index a703d486d..b1960d7c9 100644 --- a/config/creatures/castle.json +++ b/config/creatures/castle.json @@ -14,6 +14,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:0", + "mapAttackFromLeft": "AvWattak.def:0:1", "animation": "CPKMAN.DEF" }, "sound" : @@ -39,6 +41,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:2", + "mapAttackFromLeft": "AvWattak.def:0:3", "animation": "CHALBD.DEF" }, "sound" : @@ -66,6 +70,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:4", + "mapAttackFromLeft": "AvWattak.def:0:5", "animation": "CLCBOW.DEF", "missile" : { @@ -103,6 +109,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:6", + "mapAttackFromLeft": "AvWattak.def:0:7", "animation": "CHCBOW.DEF", "missile" : { @@ -140,6 +148,8 @@ "hasDoubleWeek": true, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:8", + "mapAttackFromLeft": "AvWattak.def:0:9", "animation": "CGRIFF.DEF" }, "sound" : @@ -169,6 +179,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:10", + "mapAttackFromLeft": "AvWattak.def:0:11", "animation": "CRGRIF.DEF" }, "sound" : @@ -188,6 +200,8 @@ "upgrades": ["crusader"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:12", + "mapAttackFromLeft": "AvWattak.def:0:13", "animation": "CSWORD.DEF" }, "sound" : @@ -214,6 +228,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:14", + "mapAttackFromLeft": "AvWattak.def:0:15", "animation": "CCRUSD.DEF" }, "sound" : @@ -240,6 +256,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:16", + "mapAttackFromLeft": "AvWattak.def:0:17", "animation": "CMONKK.DEF", "missile" : { @@ -273,6 +291,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:18", + "mapAttackFromLeft": "AvWattak.def:0:19", "animation": "CZEALT.DEF", "missile" : { @@ -306,6 +326,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:20", + "mapAttackFromLeft": "AvWattak.def:0:21", "animation": "CCAVLR.DEF" }, "sound" : @@ -333,6 +355,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:22", + "mapAttackFromLeft": "AvWattak.def:0:23", "animation": "CCHAMP.DEF" }, "sound" : @@ -384,6 +408,8 @@ "upgrades": ["archangel"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:24", + "mapAttackFromLeft": "AvWattak.def:0:25", "animation": "CANGEL.DEF" }, "sound" : @@ -451,6 +477,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:26", + "mapAttackFromLeft": "AvWattak.def:0:27", "animation": "CRANGL.DEF" }, "sound" : diff --git a/config/creatures/conflux.json b/config/creatures/conflux.json index 78cb70ec1..505f8f59c 100755 --- a/config/creatures/conflux.json +++ b/config/creatures/conflux.json @@ -15,6 +15,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:236", + "mapAttackFromLeft": "AvWattak.def:0:237", "animation": "CPIXIE.DEF" }, "sound" : @@ -44,6 +46,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:238", + "mapAttackFromLeft": "AvWattak.def:0:239", "animation": "CSPRITE.DEF" }, "sound" : @@ -111,6 +115,8 @@ "upgrades": ["stormElemental"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:224", + "mapAttackFromLeft": "AvWattak.def:0:225", "animation": "CAELEM.DEF" }, "sound" : @@ -196,6 +202,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:254", + "mapAttackFromLeft": "AvWattak.def:0:255", "animation": "CSTORM.DEF", "missile" : { @@ -285,6 +293,8 @@ "upgrades": ["iceElemental"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:230", + "mapAttackFromLeft": "AvWattak.def:0:231", "animation": "CWELEM.DEF" }, "sound" : @@ -388,6 +398,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:246", + "mapAttackFromLeft": "AvWattak.def:0:247", "animation": "CICEE.DEF", "missile" : { @@ -452,6 +464,8 @@ "upgrades": ["energyElemental"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:228", + "mapAttackFromLeft": "AvWattak.def:0:229", "animation": "CFELEM.DEF" }, "sound" : @@ -530,6 +544,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:258", + "mapAttackFromLeft": "AvWattak.def:0:259", "animation": "CNRG.DEF" }, "sound" : @@ -593,6 +609,8 @@ "upgrades": ["magmaElemental"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:226", + "mapAttackFromLeft": "AvWattak.def:0:227", "animation": "CEELEM.DEF" }, "sound" : @@ -671,6 +689,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:250", + "mapAttackFromLeft": "AvWattak.def:0:251", "animation": "CSTONE.DEF" }, "sound" : @@ -710,6 +730,8 @@ "upgrades": ["magicElemental"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:240", + "mapAttackFromLeft": "AvWattak.def:0:241", "animation": "CPSYEL.DEF" }, "sound" : @@ -749,6 +771,8 @@ "doubleWide" : false, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:242", + "mapAttackFromLeft": "AvWattak.def:0:243", "animation": "CMAGEL.DEF" }, "sound" : @@ -790,6 +814,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:260", + "mapAttackFromLeft": "AvWattak.def:0:261", "animation": "CFBIRD.DEF" }, "sound" : @@ -840,6 +866,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:262", + "mapAttackFromLeft": "AvWattak.def:0:263", "animation": "CPHX.DEF" }, "sound" : diff --git a/config/creatures/dungeon.json b/config/creatures/dungeon.json index f49aaebfa..d8959059e 100644 --- a/config/creatures/dungeon.json +++ b/config/creatures/dungeon.json @@ -21,6 +21,8 @@ "hasDoubleWeek": true, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:140", + "mapAttackFromLeft": "AvWattak.def:0:141", "animation": "CTROGL.DEF" }, "sound" : @@ -52,6 +54,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:142", + "mapAttackFromLeft": "AvWattak.def:0:143", "animation": "CITROG.DEF" }, "sound" : @@ -83,6 +87,8 @@ "hasDoubleWeek": true, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:144", + "mapAttackFromLeft": "AvWattak.def:0:145", "animation": "CHARPY.DEF" }, "sound" : @@ -116,6 +122,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:146", + "mapAttackFromLeft": "AvWattak.def:0:147", "animation": "CHARPH.DEF" }, "sound" : @@ -148,6 +156,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:148", + "mapAttackFromLeft": "AvWattak.def:0:149", "animation": "CBEHOL.DEF", "missile" : { @@ -190,6 +200,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:150", + "mapAttackFromLeft": "AvWattak.def:0:151", "animation": "CEVEYE.DEF", "missile" : { @@ -241,6 +253,8 @@ "upgrades": ["medusaQueen"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:152", + "mapAttackFromLeft": "AvWattak.def:0:153", "animation": "CMEDUS.DEF", "missile" : { @@ -284,6 +298,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:154", + "mapAttackFromLeft": "AvWattak.def:0:155", "animation": "CMEDUQ.DEF", "missile" : { @@ -317,6 +333,8 @@ "upgrades": ["minotaurKing"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:156", + "mapAttackFromLeft": "AvWattak.def:0:157", "animation": "CMINOT.DEF" }, "sound" : @@ -344,6 +362,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:158", + "mapAttackFromLeft": "AvWattak.def:0:159", "animation": "CMINOK.DEF" }, "sound" : @@ -372,6 +392,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:160", + "mapAttackFromLeft": "AvWattak.def:0:161", "animation": "CMCORE.DEF" }, "sound" : @@ -405,6 +427,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:162", + "mapAttackFromLeft": "AvWattak.def:0:163", "animation": "CCMCOR.DEF" }, "sound" : @@ -451,6 +475,8 @@ "upgrades": ["blackDragon"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:164", + "mapAttackFromLeft": "AvWattak.def:0:165", "animation": "CRDRGN.DEF" }, "sound" : @@ -501,6 +527,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:166", + "mapAttackFromLeft": "AvWattak.def:0:167", "animation": "CBDRGN.DEF" }, "sound" : diff --git a/config/creatures/fortress.json b/config/creatures/fortress.json index f834f993a..c9d2d093b 100644 --- a/config/creatures/fortress.json +++ b/config/creatures/fortress.json @@ -7,6 +7,8 @@ "upgrades": ["gnollMarauder"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:196", + "mapAttackFromLeft": "AvWattak.def:0:197", "animation": "CGNOLL.DEF" }, "sound" : @@ -25,6 +27,8 @@ "faction": "fortress", "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:198", + "mapAttackFromLeft": "AvWattak.def:0:199", "animation": "CGNOLM.DEF" }, "sound" : @@ -54,6 +58,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:200", + "mapAttackFromLeft": "AvWattak.def:0:201", "animation": "CPLIZA.DEF", "missile" : { @@ -85,6 +91,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:202", + "mapAttackFromLeft": "AvWattak.def:0:203", "animation": "CALIZA.DEF", "missile" : { @@ -124,6 +132,8 @@ "hasDoubleWeek": true, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:208", + "mapAttackFromLeft": "AvWattak.def:0:209", "animation": "CDRFLY.DEF" }, "sound" : @@ -161,6 +171,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:210", + "mapAttackFromLeft": "AvWattak.def:0:211", "animation": "CDRFIR.DEF" }, "sound" : @@ -191,6 +203,8 @@ "upgrades": ["greaterBasilisk"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:212", + "mapAttackFromLeft": "AvWattak.def:0:213", "animation": "CBASIL.DEF" }, "sound" : @@ -219,6 +233,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:214", + "mapAttackFromLeft": "AvWattak.def:0:215", "animation": "CGBASI.DEF" }, "sound" : @@ -239,6 +255,8 @@ "doubleWide" : true, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:204", + "mapAttackFromLeft": "AvWattak.def:0:205", "animation": "CCGORG.DEF" }, "sound" : @@ -267,6 +285,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:206", + "mapAttackFromLeft": "AvWattak.def:0:207", "animation": "CBGOG.DEF" }, "sound" : @@ -294,6 +314,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:216", + "mapAttackFromLeft": "AvWattak.def:0:217", "animation": "CWYVER.DEF" }, "sound" : @@ -326,6 +348,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:218", + "mapAttackFromLeft": "AvWattak.def:0:219", "animation": "CWYVMN.DEF" }, "sound" : @@ -362,6 +386,8 @@ "upgrades": ["chaosHydra"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:220", + "mapAttackFromLeft": "AvWattak.def:0:221", "animation": "CHYDRA.DEF" }, "sound" : @@ -397,6 +423,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:222", + "mapAttackFromLeft": "AvWattak.def:0:223", "animation": "CCHYDR.DEF" }, "sound" : diff --git a/config/creatures/inferno.json b/config/creatures/inferno.json index 87c8e5a7c..3a3fb5e90 100755 --- a/config/creatures/inferno.json +++ b/config/creatures/inferno.json @@ -7,6 +7,8 @@ "upgrades": ["familiar"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:84", + "mapAttackFromLeft": "AvWattak.def:0:85", "animation": "CIMP.DEF" }, "sound" : @@ -33,6 +35,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:86", + "mapAttackFromLeft": "AvWattak.def:0:87", "animation": "CFAMIL.DEF" }, "sound" : @@ -61,6 +65,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:88", + "mapAttackFromLeft": "AvWattak.def:0:89", "animation": "CGOG.DEF", "missile" : { @@ -97,6 +103,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:90", + "mapAttackFromLeft": "AvWattak.def:0:91", "animation": "CMAGOG.DEF", "missile" : { @@ -122,6 +130,8 @@ "doubleWide" : true, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:92", + "mapAttackFromLeft": "AvWattak.def:0:93", "animation": "CHHOUN.DEF" }, "sound" : @@ -152,6 +162,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:94", + "mapAttackFromLeft": "AvWattak.def:0:95", "animation": "CCERBU.DEF" }, "sound" : @@ -171,6 +183,8 @@ "upgrades": ["hornedDemon"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:96", + "mapAttackFromLeft": "AvWattak.def:0:97", "animation": "COHDEM.DEF" }, "sound" : @@ -189,6 +203,8 @@ "faction": "inferno", "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:98", + "mapAttackFromLeft": "AvWattak.def:0:99", "animation": "CTHDEM.DEF" }, "sound" : @@ -208,6 +224,8 @@ "upgrades": ["pitLord"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:100", + "mapAttackFromLeft": "AvWattak.def:0:101", "animation": "CPFIEN.DEF" }, "sound" : @@ -246,6 +264,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:102", + "mapAttackFromLeft": "AvWattak.def:0:103", "animation": "CPFOE.DEF" }, "sound" : @@ -289,6 +309,8 @@ "upgrades": ["efreetSultan"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:104", + "mapAttackFromLeft": "AvWattak.def:0:105", "animation": "CEFREE.DEF" }, "sound" : @@ -336,6 +358,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:106", + "mapAttackFromLeft": "AvWattak.def:0:107", "animation": "CEFRES.DEF" }, "sound" : @@ -396,6 +420,8 @@ "upgrades": ["archDevil"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:108", + "mapAttackFromLeft": "AvWattak.def:0:109", "animation": "CDEVIL.DEF" }, "sound" : @@ -456,6 +482,8 @@ "graphics" : { "missile" : null, + "mapAttackFromRight": "AvWattak.def:0:110", + "mapAttackFromLeft": "AvWattak.def:0:111", "animation": "CADEVL.DEF" }, "sound" : diff --git a/config/creatures/necropolis.json b/config/creatures/necropolis.json index 7e98d6ff2..50da678f0 100644 --- a/config/creatures/necropolis.json +++ b/config/creatures/necropolis.json @@ -14,6 +14,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:112", + "mapAttackFromLeft": "AvWattak.def:0:113", "animation": "CSKELE.DEF" }, "sound" : @@ -39,6 +41,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:114", + "mapAttackFromLeft": "AvWattak.def:0:115", "animation": "CWSKEL.DEF" }, "sound" : @@ -66,6 +70,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:116", + "mapAttackFromLeft": "AvWattak.def:0:117", "animation": "CZOMBI.DEF" }, "sound" : @@ -84,6 +90,8 @@ "faction": "necropolis", "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:118", + "mapAttackFromLeft": "AvWattak.def:0:119", "animation": "CZOMLO.DEF" }, "sound" : @@ -133,6 +141,8 @@ "hasDoubleWeek": true, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:120", + "mapAttackFromLeft": "AvWattak.def:0:121", "animation": "CWIGHT.DEF" }, "sound" : @@ -172,6 +182,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:122", + "mapAttackFromLeft": "AvWattak.def:0:123", "animation": "CWRAIT.DEF" }, "sound" : @@ -206,6 +218,8 @@ "upgrades": ["vampireLord"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:124", + "mapAttackFromLeft": "AvWattak.def:0:125", "animation": "CVAMP.DEF" }, "sound" : @@ -246,6 +260,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:126", + "mapAttackFromLeft": "AvWattak.def:0:127", "animation": "CNOSFE.DEF" }, "sound" : @@ -285,6 +301,8 @@ "upgrades": ["powerLich"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:128", + "mapAttackFromLeft": "AvWattak.def:0:129", "animation": "CLICH.DEF", "missile" : { @@ -325,6 +343,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:130", + "mapAttackFromLeft": "AvWattak.def:0:131", "animation": "CPLICH.DEF", "missile" : { @@ -363,6 +383,8 @@ "upgrades": ["dreadKnight"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:132", + "mapAttackFromLeft": "AvWattak.def:0:133", "animation": "CBKNIG.DEF" }, "sound" : @@ -400,6 +422,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:134", + "mapAttackFromLeft": "AvWattak.def:0:135", "animation": "CBLORD.DEF" }, "sound" : @@ -450,6 +474,8 @@ "upgrades": ["ghostDragon"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:136", + "mapAttackFromLeft": "AvWattak.def:0:137", "animation": "CNDRGN.DEF" }, "sound" : @@ -505,6 +531,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:138", + "mapAttackFromLeft": "AvWattak.def:0:139", "animation": "CHDRGN.DEF" }, "sound" : diff --git a/config/creatures/neutral.json b/config/creatures/neutral.json index 0e25c5231..b7debdf14 100644 --- a/config/creatures/neutral.json +++ b/config/creatures/neutral.json @@ -20,6 +20,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:232", + "mapAttackFromLeft": "AvWattak.def:0:233", "animation": "CGGOLE.DEF" }, "sound" : @@ -51,6 +53,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:234", + "mapAttackFromLeft": "AvWattak.def:0:235", "animation": "CDGOLE.DEF" }, "sound" : @@ -104,6 +108,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:264", + "mapAttackFromLeft": "AvWattak.def:0:265", "animation": "CADRGN.DEF" }, "sound" : @@ -145,6 +151,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:266", + "mapAttackFromLeft": "AvWattak.def:0:267", "animation": "CCDRGN.DEF" }, "sound" : @@ -252,6 +260,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:268", + "mapAttackFromLeft": "AvWattak.def:0:269", "animation": "CFDRGN.DEF" }, "sound" : @@ -305,6 +315,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:270", + "mapAttackFromLeft": "AvWattak.def:0:271", "animation": "CRSDGN.DEF" }, "sound" : @@ -388,6 +400,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:272", + "mapAttackFromLeft": "AvWattak.def:0:273", "animation": "Cench.DEF", "missile" : { @@ -429,6 +443,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:274", + "mapAttackFromLeft": "AvWattak.def:0:275", "animation": "CSHARP.DEF", "missile" : { @@ -466,6 +482,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:276", + "mapAttackFromLeft": "AvWattak.def:0:277", "animation": "CHALF.DEF", "missile" : { @@ -489,6 +507,8 @@ "faction": "neutral", "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:278", + "mapAttackFromLeft": "AvWattak.def:0:279", "animation": "CPEAS.DEF" }, "sound" : @@ -508,6 +528,8 @@ "doubleWide" : true, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:280", + "mapAttackFromLeft": "AvWattak.def:0:281", "animation": "CBOAR.DEF" }, "sound" : @@ -539,6 +561,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:282", + "mapAttackFromLeft": "AvWattak.def:0:283", "animation": "CMUMMY.DEF" }, "sound" : @@ -567,6 +591,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:284", + "mapAttackFromLeft": "AvWattak.def:0:285", "animation": "CNOMAD.DEF" }, "sound" : @@ -612,6 +638,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:286", + "mapAttackFromLeft": "AvWattak.def:0:287", "animation": "CROGUE.DEF" }, "sound" : @@ -638,6 +666,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:288", + "mapAttackFromLeft": "AvWattak.def:0:289", "animation": "CTROLL.DEF" }, "sound" : diff --git a/config/creatures/rampart.json b/config/creatures/rampart.json index 63b4595a1..d3bc698a3 100644 --- a/config/creatures/rampart.json +++ b/config/creatures/rampart.json @@ -10,6 +10,8 @@ "graphics" : { "missile" : null, + "mapAttackFromRight": "AvWattak.def:0:28", + "mapAttackFromLeft": "AvWattak.def:0:29", "animation": "CCENTR.DEF" }, "sound" : @@ -31,6 +33,8 @@ "graphics" : { "missile" : null, + "mapAttackFromRight": "AvWattak.def:0:30", + "mapAttackFromLeft": "AvWattak.def:0:31", "animation": "CECENT.DEF" }, "sound" : @@ -58,6 +62,8 @@ "upgrades": ["battleDwarf"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:32", + "mapAttackFromLeft": "AvWattak.def:0:33", "animation": "CDWARF.DEF" }, "sound" : @@ -84,6 +90,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:34", + "mapAttackFromLeft": "AvWattak.def:0:35", "animation": "CBDWAR.DEF" }, "sound" : @@ -111,6 +119,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:36", + "mapAttackFromLeft": "AvWattak.def:0:37", "animation": "CELF.DEF", "missile" : { @@ -149,6 +159,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:38", + "mapAttackFromLeft": "AvWattak.def:0:39", "animation": "CGRELF.DEF", "missile" : { @@ -187,6 +199,8 @@ "hasDoubleWeek": true, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:40", + "mapAttackFromLeft": "AvWattak.def:0:41", "animation": "CPEGAS.DEF" }, "sound" : @@ -218,6 +232,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:42", + "mapAttackFromLeft": "AvWattak.def:0:43", "animation": "CAPEGS.DEF" }, "sound" : @@ -246,6 +262,8 @@ "upgrades": ["dendroidSoldier"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:44", + "mapAttackFromLeft": "AvWattak.def:0:45", "animation": "CTREE.DEF" }, "sound" : @@ -273,6 +291,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:46", + "mapAttackFromLeft": "AvWattak.def:0:47", "animation": "CBTREE.DEF" }, "sound" : @@ -308,6 +328,8 @@ "upgrades": ["warUnicorn"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:48", + "mapAttackFromLeft": "AvWattak.def:0:49", "animation": "CUNICO.DEF" }, "sound" : @@ -342,6 +364,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:50", + "mapAttackFromLeft": "AvWattak.def:0:51", "animation": "CWUNIC.DEF" }, "sound" : @@ -388,6 +412,8 @@ "upgrades": ["goldDragon"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:52", + "mapAttackFromLeft": "AvWattak.def:0:53", "animation": "CGDRAG.DEF" }, "sound" : @@ -432,6 +458,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:54", + "mapAttackFromLeft": "AvWattak.def:0:55", "animation": "CDDRAG.DEF" }, "sound" : diff --git a/config/creatures/stronghold.json b/config/creatures/stronghold.json index 7824a2b58..f85ebf420 100644 --- a/config/creatures/stronghold.json +++ b/config/creatures/stronghold.json @@ -8,6 +8,8 @@ "upgrades": ["hobgoblin"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:168", + "mapAttackFromLeft": "AvWattak.def:0:169", "animation": "CGOBLI.DEF" }, "sound" : @@ -27,6 +29,8 @@ "hasDoubleWeek": true, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:170", + "mapAttackFromLeft": "AvWattak.def:0:171", "animation": "CHGOBL.DEF" }, "sound" : @@ -48,6 +52,8 @@ "hasDoubleWeek": true, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:172", + "mapAttackFromLeft": "AvWattak.def:0:173", "animation": "CBWLFR.DEF" }, "sound" : @@ -75,6 +81,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:174", + "mapAttackFromLeft": "AvWattak.def:0:175", "animation": "CUWLFR.DEF" }, "sound" : @@ -102,6 +110,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:176", + "mapAttackFromLeft": "AvWattak.def:0:177", "animation": "CORC.DEF", "missile" : { @@ -133,6 +143,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:178", + "mapAttackFromLeft": "AvWattak.def:0:179", "animation": "CORCCH.DEF", "missile" : { @@ -157,6 +169,8 @@ "upgrades": ["ogreMage"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:180", + "mapAttackFromLeft": "AvWattak.def:0:181", "animation": "COGRE.DEF" }, "sound" : @@ -194,6 +208,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:182", + "mapAttackFromLeft": "AvWattak.def:0:183", "animation": "COGMAG.DEF" }, "sound" : @@ -222,6 +238,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:184", + "mapAttackFromLeft": "AvWattak.def:0:185", "animation": "CROC.DEF" }, "sound" : @@ -260,6 +278,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:186", + "mapAttackFromLeft": "AvWattak.def:0:187", "animation": "CTBIRD.DEF" }, "sound" : @@ -292,6 +312,8 @@ "upgrades": ["cyclopKing"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:188", + "mapAttackFromLeft": "AvWattak.def:0:189", "animation": "CCYCLR.DEF", "missile" : { @@ -335,6 +357,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:190", + "mapAttackFromLeft": "AvWattak.def:0:191", "animation": "CCYCLLOR.DEF", "missile" : { @@ -373,6 +397,8 @@ "upgrades": ["ancientBehemoth"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:192", + "mapAttackFromLeft": "AvWattak.def:0:193", "animation": "CYBEHE.DEF" }, "sound" : @@ -405,6 +431,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:194", + "mapAttackFromLeft": "AvWattak.def:0:195", "animation": "CABEHE.DEF" }, "sound" : diff --git a/config/creatures/tower.json b/config/creatures/tower.json index 99781a907..84bcef6e6 100644 --- a/config/creatures/tower.json +++ b/config/creatures/tower.json @@ -9,6 +9,8 @@ "hasDoubleWeek": true, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:56", + "mapAttackFromLeft": "AvWattak.def:0:57", "animation": "CGREMA.DEF" }, "sound" : @@ -36,6 +38,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:58", + "mapAttackFromLeft": "AvWattak.def:0:59", "animation": "CGREMM.DEF", "missile" : { @@ -71,6 +75,8 @@ "upgrades": ["obsidianGargoyle"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:60", + "mapAttackFromLeft": "AvWattak.def:0:61", "animation": "CGARGO.DEF" }, "sound" : @@ -100,6 +106,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:62", + "mapAttackFromLeft": "AvWattak.def:0:63", "animation": "COGARG.DEF" }, "sound" : @@ -132,6 +140,8 @@ "upgrades": ["stoneGolem"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:64", + "mapAttackFromLeft": "AvWattak.def:0:65", "animation": "CSGOLE.DEF" }, "sound" : @@ -163,6 +173,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:66", + "mapAttackFromLeft": "AvWattak.def:0:67", "animation": "CIGOLE.DEF" }, "sound" : @@ -199,6 +211,8 @@ "upgrades": ["archMage"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:68", + "mapAttackFromLeft": "AvWattak.def:0:69", "animation": "CMAGE.DEF", "missile" : { @@ -243,6 +257,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:70", + "mapAttackFromLeft": "AvWattak.def:0:71", "animation": "CAMAGE.DEF", "missile" : { @@ -294,6 +310,8 @@ "upgrades": ["masterGenie"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:72", + "mapAttackFromLeft": "AvWattak.def:0:73", "animation": "CGENIE.DEF" }, "sound" : @@ -346,6 +364,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:74", + "mapAttackFromLeft": "AvWattak.def:0:75", "animation": "CSULTA.DEF" }, "sound" : @@ -374,6 +394,8 @@ "upgrades": ["nagaQueen"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:76", + "mapAttackFromLeft": "AvWattak.def:0:77", "animation": "CNAGA.DEF" }, "sound" : @@ -400,6 +422,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:78", + "mapAttackFromLeft": "AvWattak.def:0:79", "animation": "CNAGAG.DEF" }, "sound" : @@ -431,6 +455,8 @@ "upgrades": ["titan"], "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:80", + "mapAttackFromLeft": "AvWattak.def:0:81", "animation": "CLTITA.DEF" }, "sound" : @@ -476,6 +502,8 @@ }, "graphics" : { + "mapAttackFromRight": "AvWattak.def:0:82", + "mapAttackFromLeft": "AvWattak.def:0:83", "animation": "CGTITA.DEF", "missile" : { From eef3e00f42eb4ef2d4a0a86c8ff027f8bbd069af Mon Sep 17 00:00:00 2001 From: Laserlicht <13953785+Laserlicht@users.noreply.github.com> Date: Fri, 20 Jun 2025 03:45:11 +0200 Subject: [PATCH 4/7] fix direction --- client/mapView/IMapRendererContext.h | 4 ++-- client/mapView/MapRenderer.cpp | 6 ++++-- client/mapView/MapRendererContext.cpp | 8 ++++---- client/mapView/MapRendererContext.h | 2 +- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/client/mapView/IMapRendererContext.h b/client/mapView/IMapRendererContext.h index 964e44f5d..1c5f9e6ee 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 pos of attacker if specified object is a monster and currently attacked - virtual std::optional monsterAttacked(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; 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 0f66a5338..2dbb99d76 100644 --- a/client/mapView/MapRenderer.cpp +++ b/client/mapView/MapRenderer.cpp @@ -466,10 +466,12 @@ std::shared_ptr MapRendererObjects::getImage(IMapRendererContext & conte if(animation->size(groupIndex) == 0) return nullptr; - if(auto attackerPos = context.monsterAttacked(obj)) + auto attackerPos = context.monsterAttacked(obj); + if(attackerPos != -1) { const auto * creature = dynamic_cast(obj); - ImagePath imgPath = (*attackerPos).x < obj->pos.x ? (*creature->getCreatureMap().begin()).first->mapAttackFromLeft : (*creature->getCreatureMap().begin()).first->mapAttackFromRight; + auto dir = std::vector({1, 2, 7, 8}); + ImagePath imgPath = std::count(dir.begin(), dir.end(), attackerPos) ? (*creature->getCreatureMap().begin()).first->mapAttackFromRight : (*creature->getCreatureMap().begin()).first->mapAttackFromLeft; if(!imgPath.empty()) { auto img = ENGINE->renderHandler().loadImage(imgPath, EImageBlitMode::SIMPLE); diff --git a/client/mapView/MapRendererContext.cpp b/client/mapView/MapRendererContext.cpp index c5f10bf37..3fa9811da 100644 --- a/client/mapView/MapRendererContext.cpp +++ b/client/mapView/MapRendererContext.cpp @@ -87,16 +87,16 @@ bool MapRendererBaseContext::isActiveHero(const CGObjectInstance * obj) const return false; } -std::optional MapRendererBaseContext::monsterAttacked(const CGObjectInstance * obj) const +int MapRendererBaseContext::monsterAttacked(const CGObjectInstance * obj) const { if(obj->ID != Obj::MONSTER) - return std::nullopt; + return -1; for(auto & battle : GAME->interface()->cb->getActiveBattles()) if(obj->pos == battle.second->getBattle()->getLocation()) - return battle.second->getBattle()->getSideHero(BattleSide::ATTACKER)->pos; + return battle.second->getBattle()->getSideHero(BattleSide::ATTACKER)->moveDir; - return std::nullopt; + return -1; } bool MapRendererBaseContext::tileAnimated(const int3 & coordinates) const diff --git a/client/mapView/MapRendererContext.h b/client/mapView/MapRendererContext.h index 67b620084..35d891cc5 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; - std::optional monsterAttacked(const CGObjectInstance * obj) const override; + int monsterAttacked(const CGObjectInstance * obj) const override; const TerrainTile & getMapTile(const int3 & coordinates) const override; const MapObjectsList & getObjects(const int3 & coordinates) const override; From a8af226ec5e160d8260bb5c9bc3b08e2114db230 Mon Sep 17 00:00:00 2001 From: Laserlicht <13953785+Laserlicht@users.noreply.github.com> Date: Fri, 20 Jun 2025 03:46:27 +0200 Subject: [PATCH 5/7] format fix --- client/renderSDL/RenderHandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/renderSDL/RenderHandler.cpp b/client/renderSDL/RenderHandler.cpp index 1afebdb20..6f9bb8aa9 100644 --- a/client/renderSDL/RenderHandler.cpp +++ b/client/renderSDL/RenderHandler.cpp @@ -357,7 +357,7 @@ std::shared_ptr RenderHandler::loadImage(const ImagePath & path, EImageB auto name = path.getOriginalName(); std::vector splitted; - boost::split(splitted, name, boost::is_any_of(":")); + boost::split(splitted, name, boost::is_any_of(":")); if(splitted.size() == 3) { ImageLocator locator = getLocatorForAnimationFrame(AnimationPath::builtin(splitted[0]), std::stoi(splitted[2]), std::stoi(splitted[1]), 1, mode); From b95293f254eb0e311bbb3dc11b94b0a28099a869 Mon Sep 17 00:00:00 2001 From: Laserlicht <13953785+Laserlicht@users.noreply.github.com> Date: Fri, 20 Jun 2025 12:10:35 +0200 Subject: [PATCH 6/7] better approach --- client/mapView/MapRenderer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/mapView/MapRenderer.cpp b/client/mapView/MapRenderer.cpp index 2dbb99d76..b0462cf60 100644 --- a/client/mapView/MapRenderer.cpp +++ b/client/mapView/MapRenderer.cpp @@ -470,8 +470,9 @@ std::shared_ptr MapRendererObjects::getImage(IMapRendererContext & conte if(attackerPos != -1) { const auto * creature = dynamic_cast(obj); + auto const & creatureType = LIBRARY->creh->objects[creature->appearance->subid]; auto dir = std::vector({1, 2, 7, 8}); - ImagePath imgPath = std::count(dir.begin(), dir.end(), attackerPos) ? (*creature->getCreatureMap().begin()).first->mapAttackFromRight : (*creature->getCreatureMap().begin()).first->mapAttackFromLeft; + ImagePath imgPath = std::count(dir.begin(), dir.end(), attackerPos) ? creatureType->mapAttackFromRight : creatureType->mapAttackFromLeft; if(!imgPath.empty()) { auto img = ENGINE->renderHandler().loadImage(imgPath, EImageBlitMode::SIMPLE); From 30521bbc8f511822857530b7e7de14ea06adf125 Mon Sep 17 00:00:00 2001 From: Laserlicht <13953785+Laserlicht@users.noreply.github.com> Date: Tue, 24 Jun 2025 13:48:36 +0200 Subject: [PATCH 7/7] code review --- client/mapView/IMapRendererContext.h | 4 +-- client/mapView/MapRenderer.cpp | 28 +++++++++++++------ client/mapView/MapRenderer.h | 4 ++- client/mapView/MapRendererContext.cpp | 6 ++-- client/mapView/MapRendererContext.h | 2 +- .../Entities_Format/Creature_Format.md | 4 +++ 6 files changed, 32 insertions(+), 16 deletions(-) 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