diff --git a/AI/VCAI/AIUtility.cpp b/AI/VCAI/AIUtility.cpp index 37ad79386..887f4757a 100644 --- a/AI/VCAI/AIUtility.cpp +++ b/AI/VCAI/AIUtility.cpp @@ -1,6 +1,7 @@ #include "StdInc.h" #include "AIUtility.h" #include "VCAI.h" +#include "Fuzzy.h" #include "../../lib/UnlockGuard.h" #include "../../lib/CConfigHandler.h" diff --git a/AI/VCAI/Goals.cpp b/AI/VCAI/Goals.cpp index adb4e35bb..b4929f180 100644 --- a/AI/VCAI/Goals.cpp +++ b/AI/VCAI/Goals.cpp @@ -66,7 +66,7 @@ std::string Goals::AbstractGoal::name() const //TODO: virtualize { auto obj = cb->getObjInstance(ObjectInstanceID(objid)); if (obj) - desc = "GET OBJ " + obj->getHoverText(); + desc = "GET OBJ " + obj->getObjectName(); } case FIND_OBJ: desc = "FIND OBJ " + boost::lexical_cast(objid); @@ -75,7 +75,7 @@ std::string Goals::AbstractGoal::name() const //TODO: virtualize { auto obj = cb->getObjInstance(ObjectInstanceID(objid)); if (obj) - desc = "VISIT HERO " + obj->getHoverText(); + desc = "VISIT HERO " + obj->getObjectName(); } break; case GET_ART_TYPE: @@ -493,7 +493,7 @@ TGoalVec ClearWayTo::getAllPossibleSubgoals() if (topObj->ID == Obj::HERO && cb->getPlayerRelations(h->tempOwner, topObj->tempOwner) != PlayerRelations::ENEMIES) if (topObj != hero.get(true)) //the hero we want to free - logAi->errorStream() << boost::format("%s stands in the way of %s") % topObj->getHoverText() % h->getHoverText(); + logAi->errorStream() << boost::format("%s stands in the way of %s") % topObj->getObjectName() % h->getObjectName(); if (topObj->ID == Obj::QUEST_GUARD || topObj->ID == Obj::BORDERGUARD) { if (shouldVisit(h, topObj)) diff --git a/AI/VCAI/StdInc.h b/AI/VCAI/StdInc.h index 6448c2288..e0eeaf0aa 100644 --- a/AI/VCAI/StdInc.h +++ b/AI/VCAI/StdInc.h @@ -1,4 +1,2 @@ #pragma once #include "../../Global.h" - -#include "Fuzzy.h" diff --git a/AI/VCAI/VCAI.cpp b/AI/VCAI/VCAI.cpp index ba857730b..b0477fcf8 100644 --- a/AI/VCAI/VCAI.cpp +++ b/AI/VCAI/VCAI.cpp @@ -1,10 +1,13 @@ #include "StdInc.h" #include "VCAI.h" #include "Goals.h" +#include "Fuzzy.h" + #include "../../lib/UnlockGuard.h" #include "../../lib/mapObjects/MapObjects.h" #include "../../lib/CConfigHandler.h" #include "../../lib/CHeroHandler.h" +#include "../../lib/CModHandler.h" /* @@ -81,7 +84,7 @@ struct ObjInfo ObjInfo(){} ObjInfo(const CGObjectInstance *obj): pos(obj->pos), - name(obj->getHoverText()) + name(obj->getObjectName()) { } }; @@ -195,7 +198,7 @@ void VCAI::showShipyardDialog(const IShipyard *obj) void VCAI::gameOver(PlayerColor player, const EVictoryLossCheckResult & victoryLossCheckResult) { - LOG_TRACE_PARAMS(logAi, "victoryLossCheckResult '%s'", victoryLossCheckResult); + LOG_TRACE_PARAMS(logAi, "victoryLossCheckResult '%s'", victoryLossCheckResult.messageToSelf); NET_EVENT_HANDLER; logAi->debugStream() << boost::format("Player %d: I heard that player %d %s.") % playerID % player.getNum() % (victoryLossCheckResult.victory() ? "won" : "lost"); if(player == playerID) @@ -241,7 +244,7 @@ void VCAI::artifactDisassembled(const ArtifactLocation &al) void VCAI::heroVisit(const CGHeroInstance *visitor, const CGObjectInstance *visitedObj, bool start) { - LOG_TRACE_PARAMS(logAi, "start '%i'; obj '%s'", start % (visitedObj ? visitedObj->hoverName : std::string("n/a"))); + LOG_TRACE_PARAMS(logAi, "start '%i'; obj '%s'", start % (visitedObj ? visitedObj->getObjectName() : std::string("n/a"))); NET_EVENT_HANDLER; if(start) { @@ -780,13 +783,13 @@ void VCAI::makeTurnInternal() bool VCAI::goVisitObj(const CGObjectInstance * obj, HeroPtr h) { int3 dst = obj->visitablePos(); - logAi->debugStream() << boost::format("%s will try to visit %s at (%s)") % h->name % obj->getHoverText() % strFromInt3(dst); + logAi->debugStream() << boost::format("%s will try to visit %s at (%s)") % h->name % obj->getObjectName() % strFromInt3(dst); return moveHeroToTile(dst, h); } void VCAI::performObjectInteraction(const CGObjectInstance * obj, HeroPtr h) { - LOG_TRACE_PARAMS(logAi, "Hero %s and object %s at %s", h->name % obj->getHoverText() % obj->pos); + LOG_TRACE_PARAMS(logAi, "Hero %s and object %s at %s", h->name % obj->getObjectName() % obj->pos); switch (obj->ID) { case Obj::CREATURE_GENERATOR1: @@ -1434,7 +1437,7 @@ void VCAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int assert(playerID > PlayerColor::PLAYER_LIMIT || status.getBattle() == UPCOMING_BATTLE); status.setBattle(ONGOING_BATTLE); const CGObjectInstance *presumedEnemy = backOrNull(cb->getVisitableObjs(tile)); //may be nullptr in some very are cases -> eg. visited monolith and fighting with an enemy at the FoW covered exit - battlename = boost::str(boost::format("Starting battle of %s attacking %s at %s") % (hero1 ? hero1->name : "a army") % (presumedEnemy ? presumedEnemy->hoverName : "unknown enemy") % tile); + battlename = boost::str(boost::format("Starting battle of %s attacking %s at %s") % (hero1 ? hero1->name : "a army") % (presumedEnemy ? presumedEnemy->getObjectName() : "unknown enemy") % tile); CAdventureAI::battleStart(army1, army2, tile, hero1, hero2, side); } @@ -1468,7 +1471,7 @@ void VCAI::reserveObject(HeroPtr h, const CGObjectInstance *obj) { reservedObjs.insert(obj); reservedHeroesMap[h].insert(obj); - logAi->debugStream() << "reserved object id=" << obj->id << "; address=" << (intptr_t)obj << "; name=" << obj->getHoverText(); + logAi->debugStream() << "reserved object id=" << obj->id << "; address=" << (intptr_t)obj << "; name=" << obj->getObjectName(); } void VCAI::unreserveObject(HeroPtr h, const CGObjectInstance *obj) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e92f75aa..48d4bed38 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,7 @@ endif() # VCMI version set(VCMI_VERSION_MAJOR 0) -set(VCMI_VERSION_MINOR 95) +set(VCMI_VERSION_MINOR 96) set(VCMI_VERSION_PATCH 0) option(ENABLE_ERM "Enable compilation of ERM scripting module" OFF) diff --git a/ChangeLog b/ChangeLog index 1be4238e5..64ba175f1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,7 @@ GENERAL: * (linux) now VCMI follows XDG specifications. See http://forum.vcmi.eu/viewtopic.php?t=858 ADVENTURE AI: +* Optimized speed and removed various bottlenecks. ADVENTURE MAP: * Heroes auto-level primary and secondary skill levels according to experience @@ -13,6 +14,14 @@ BATTLES: SPELLS: * New configuration format: http://wiki.vcmi.eu/index.php?title=Spell_Format +RANDOM MAP GENERATOR +* Towns form mods cna be used +* Reading connections, terrains, towns and mines from template +* Zone placement +* Zone borders and connections, fractalized paths inside zones +* Guard generation +* Treasue piles generation (so far only few removable objects) + MODS: * Support for submods - mod may have their own "submods" located in /Mods directory * Mods may provide their own changelogs and screenshots that will be visible in Launcher diff --git a/Global.h b/Global.h index a9c81fe59..def02d647 100644 --- a/Global.h +++ b/Global.h @@ -152,9 +152,11 @@ typedef boost::lock_guard TLockGuardRec; # else # define DLL_EXPORT __declspec(dllexport) # endif +# define ELF_VISIBILITY #else # ifdef __GNUC__ -# define DLL_EXPORT __attribute__ ((visibility("default"))) +# define DLL_EXPORT __attribute__ ((visibility("default"))) +# define ELF_VISIBILITY __attribute__ ((visibility("default"))) # endif #endif @@ -164,9 +166,11 @@ typedef boost::lock_guard TLockGuardRec; # else # define DLL_IMPORT __declspec(dllimport) # endif +# define ELF_VISIBILITY #else # ifdef __GNUC__ # define DLL_IMPORT __attribute__ ((visibility("default"))) +# define ELF_VISIBILITY __attribute__ ((visibility("default"))) # endif #endif diff --git a/README b/README.md similarity index 100% rename from README rename to README.md diff --git a/client/AdventureMapClasses.cpp b/client/AdventureMapClasses.cpp index 648a3222c..f7c01b093 100644 --- a/client/AdventureMapClasses.cpp +++ b/client/AdventureMapClasses.cpp @@ -317,7 +317,7 @@ void CTownList::CTownItem::showTooltip() std::string CTownList::CTownItem::getHoverText() { - return town->hoverName; + return town->getObjectName(); } CTownList::CTownList(int size, Point position, std::string btnUp, std::string btnDown): diff --git a/client/CAdvmapInterface.cpp b/client/CAdvmapInterface.cpp index e6e44d561..c96708b86 100644 --- a/client/CAdvmapInterface.cpp +++ b/client/CAdvmapInterface.cpp @@ -1130,17 +1130,19 @@ void CAdvMapInt::endingTurn() LOCPLINT->cb->endTurn(); } -const CGObjectInstance* CAdvMapInt::getBlockingObject(const int3 &mapPos) +const CGObjectInstance* CAdvMapInt::getActiveObject(const int3 &mapPos) { std::vector < const CGObjectInstance * > bobjs = LOCPLINT->cb->getBlockingObjs(mapPos); //blocking objects at tile if (bobjs.empty()) return nullptr; + return *boost::range::max_element(bobjs, &CMapHandler::compareObjectBlitOrder); +/* if (bobjs.back()->ID == Obj::HERO) return bobjs.back(); else - return bobjs.front(); + return bobjs.front();*/ } void CAdvMapInt::tileLClicked(const int3 &mapPos) @@ -1150,7 +1152,7 @@ void CAdvMapInt::tileLClicked(const int3 &mapPos) const TerrainTile *tile = LOCPLINT->cb->getTile(mapPos); - const CGObjectInstance *topBlocking = getBlockingObject(mapPos); + const CGObjectInstance *topBlocking = getActiveObject(mapPos); int3 selPos = selection->getSightCenter(); if(spellBeingCasted && isInScreenRange(selPos, mapPos)) @@ -1235,12 +1237,11 @@ void CAdvMapInt::tileHovered(const int3 &mapPos) statusbar.clear(); return; } - const CGObjectInstance *objAtTile = getBlockingObject(mapPos); + const CGObjectInstance *objAtTile = getActiveObject(mapPos); - //std::vector temp = LOCPLINT->cb->getObjDescriptions(mapPos); if (objAtTile) { - std::string text = objAtTile->getHoverText(); + std::string text = curHero() ? objAtTile->getHoverText(curHero()) : objAtTile->getHoverText(LOCPLINT->playerID); boost::replace_all(text,"\n"," "); statusbar.setText(text); } @@ -1436,7 +1437,7 @@ void CAdvMapInt::tileRClicked(const int3 &mapPos) return; } - const CGObjectInstance * obj = getBlockingObject(mapPos); + const CGObjectInstance * obj = getActiveObject(mapPos); if(!obj) { // Bare or undiscovered terrain diff --git a/client/CAdvmapInterface.h b/client/CAdvmapInterface.h index 793c393ff..cf7f785a9 100644 --- a/client/CAdvmapInterface.h +++ b/client/CAdvmapInterface.h @@ -85,8 +85,8 @@ public: /// can get to the towns and heroes. class CAdvMapInt : public CIntObject { - //get top selectable object at tile - const CGObjectInstance *getBlockingObject(const int3 &tile); + //Return object that must be active at this tile (=clickable) + const CGObjectInstance *getActiveObject(const int3 &tile); public: CAdvMapInt(); diff --git a/client/CKingdomInterface.cpp b/client/CKingdomInterface.cpp index 83f730515..2c6dfb235 100644 --- a/client/CKingdomInterface.cpp +++ b/client/CKingdomInterface.cpp @@ -500,7 +500,7 @@ void CKingdomInterface::generateObjectsList(const std::vectorsubID]; if (info.count++ == 0) { - info.hoverText = object->getHoverText(); + info.hoverText = object->getObjectName(); info.imageID = object->subID; } } @@ -511,7 +511,7 @@ void CKingdomInterface::generateObjectsList(const std::vectorsecond]; if (info.count++ == 0) { - info.hoverText = object->hoverName; + info.hoverText = object->getObjectName(); info.imageID = iter->second; } } diff --git a/client/CMT.cpp b/client/CMT.cpp index 7de8eed78..b62a7cfb0 100644 --- a/client/CMT.cpp +++ b/client/CMT.cpp @@ -627,7 +627,7 @@ void processCommand(const std::string &message) } else if(cn == "bonuses") { - std::cout << "Bonuses of " << adventureInt->selection->getHoverText() << std::endl + std::cout << "Bonuses of " << adventureInt->selection->getObjectName() << std::endl << adventureInt->selection->getBonusList() << std::endl; std::cout << "\nInherited bonuses:\n"; diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index 4e82d52bd..1afbef2fd 100644 --- a/client/CPlayerInterface.cpp +++ b/client/CPlayerInterface.cpp @@ -91,15 +91,10 @@ CondSh stillMoveHero; //used during hero movement int CPlayerInterface::howManyPeople = 0; - -struct OCM_HLP_CGIN +static bool objectBlitOrderSorter(const std::pair & a, const std::pair & b) { - bool inline operator ()(const std::pair & a, const std::pair & b) const - { - return (*a.first)<(*b.first); - } -} ocmptwo_cgin ; - + return CMapHandler::compareObjectBlitOrder(a.first, b.first); +} CPlayerInterface::CPlayerInterface(PlayerColor Player) { @@ -1645,14 +1640,14 @@ void CPlayerInterface::initMovement( const TryMoveHero &details, const CGHeroIns subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 33, 33), ho->id); subRect(hp.x, hp.y, hp.z, genRect(32, 32, 65, 33), ho->id); - std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y-2][hp.z].objects.end(), ocmptwo_cgin); - std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.end(), ocmptwo_cgin); - std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.end(), ocmptwo_cgin); - std::stable_sort(CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.end(), ocmptwo_cgin); + std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y-2][hp.z].objects.end(), objectBlitOrderSorter); + std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.end(), objectBlitOrderSorter); + std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.end(), objectBlitOrderSorter); + std::stable_sort(CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.end(), objectBlitOrderSorter); - std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.end(), ocmptwo_cgin); + std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.end(), objectBlitOrderSorter); - std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.end(), ocmptwo_cgin); + std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.end(), objectBlitOrderSorter); } else if(details.end.x == details.start.x && details.end.y+1 == details.start.y) //t { @@ -1670,9 +1665,9 @@ void CPlayerInterface::initMovement( const TryMoveHero &details, const CGHeroIns subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 32, 33), ho->id); subRect(hp.x, hp.y, hp.z, genRect(32, 32, 64, 33), ho->id); - std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.end(), ocmptwo_cgin); - std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.end(), ocmptwo_cgin); - std::stable_sort(CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.end(), ocmptwo_cgin); + std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.end(), objectBlitOrderSorter); + std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.end(), objectBlitOrderSorter); + std::stable_sort(CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.end(), objectBlitOrderSorter); } else if(details.end.x-1 == details.start.x && details.end.y+1 == details.start.y) //tr { @@ -1693,14 +1688,14 @@ void CPlayerInterface::initMovement( const TryMoveHero &details, const CGHeroIns subRect(hp.x, hp.y, hp.z, genRect(32, 32, 63, 33), ho->id); CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 95, 33))); - std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.end(), ocmptwo_cgin); - std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.end(), ocmptwo_cgin); - std::stable_sort(CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.end(), ocmptwo_cgin); - std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y-2][hp.z].objects.end(), ocmptwo_cgin); + std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y-2][hp.z].objects.end(), objectBlitOrderSorter); + std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y-2][hp.z].objects.end(), objectBlitOrderSorter); + std::stable_sort(CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y-2][hp.z].objects.end(), objectBlitOrderSorter); + std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y-2][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y-2][hp.z].objects.end(), objectBlitOrderSorter); - std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.end(), ocmptwo_cgin); + std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.end(), objectBlitOrderSorter); - std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.end(), ocmptwo_cgin); + std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.end(), objectBlitOrderSorter); } else if(details.end.x-1 == details.start.x && details.end.y == details.start.y) //r { @@ -1716,9 +1711,9 @@ void CPlayerInterface::initMovement( const TryMoveHero &details, const CGHeroIns subRect(hp.x, hp.y, hp.z, genRect(32, 32, 63, 32), ho->id); CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 95, 32))); - std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.end(), ocmptwo_cgin); + std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.end(), objectBlitOrderSorter); - std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.end(), ocmptwo_cgin); + std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.end(), objectBlitOrderSorter); } else if(details.end.x-1 == details.start.x && details.end.y-1 == details.start.y) //br { @@ -1739,14 +1734,14 @@ void CPlayerInterface::initMovement( const TryMoveHero &details, const CGHeroIns CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 63, 63))); CGI->mh->ttiles[hp.x+1][hp.y+1][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 95, 63))); - std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.end(), ocmptwo_cgin); + std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y-1][hp.z].objects.end(), objectBlitOrderSorter); - std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.end(), ocmptwo_cgin); + std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y][hp.z].objects.end(), objectBlitOrderSorter); - std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.end(), ocmptwo_cgin); - std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.end(), ocmptwo_cgin); - std::stable_sort(CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.end(), ocmptwo_cgin); - std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y+1][hp.z].objects.end(), ocmptwo_cgin); + std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.end(), objectBlitOrderSorter); + std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.end(), objectBlitOrderSorter); + std::stable_sort(CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.end(), objectBlitOrderSorter); + std::stable_sort(CGI->mh->ttiles[hp.x+1][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x+1][hp.y+1][hp.z].objects.end(), objectBlitOrderSorter); } else if(details.end.x == details.start.x && details.end.y-1 == details.start.y) //b { @@ -1764,9 +1759,9 @@ void CPlayerInterface::initMovement( const TryMoveHero &details, const CGHeroIns CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 32, 63))); CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 64, 63))); - std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.end(), ocmptwo_cgin); - std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.end(), ocmptwo_cgin); - std::stable_sort(CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.end(), ocmptwo_cgin); + std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.end(), objectBlitOrderSorter); + std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.end(), objectBlitOrderSorter); + std::stable_sort(CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.end(), objectBlitOrderSorter); } else if(details.end.x+1 == details.start.x && details.end.y-1 == details.start.y) //bl { @@ -1787,14 +1782,14 @@ void CPlayerInterface::initMovement( const TryMoveHero &details, const CGHeroIns CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 33, 63))); CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.push_back(std::make_pair(ho, genRect(32, 32, 65, 63))); - std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.end(), ocmptwo_cgin); + std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.end(), objectBlitOrderSorter); - std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.end(), ocmptwo_cgin); + std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.end(), objectBlitOrderSorter); - std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y+1][hp.z].objects.end(), ocmptwo_cgin); - std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.end(), ocmptwo_cgin); - std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.end(), ocmptwo_cgin); - std::stable_sort(CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.end(), ocmptwo_cgin); + std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y+1][hp.z].objects.end(), objectBlitOrderSorter); + std::stable_sort(CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-2][hp.y+1][hp.z].objects.end(), objectBlitOrderSorter); + std::stable_sort(CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-1][hp.y+1][hp.z].objects.end(), objectBlitOrderSorter); + std::stable_sort(CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x][hp.y+1][hp.z].objects.end(), objectBlitOrderSorter); } else if(details.end.x+1 == details.start.x && details.end.y == details.start.y) //l { @@ -1810,9 +1805,9 @@ void CPlayerInterface::initMovement( const TryMoveHero &details, const CGHeroIns subRect(hp.x-1, hp.y, hp.z, genRect(32, 32, 33, 32), ho->id); subRect(hp.x, hp.y, hp.z, genRect(32, 32, 65, 32), ho->id); - std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.end(), ocmptwo_cgin); + std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y-1][hp.z].objects.end(), objectBlitOrderSorter); - std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.end(), ocmptwo_cgin); + std::stable_sort(CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.begin(), CGI->mh->ttiles[hp.x-3][hp.y][hp.z].objects.end(), objectBlitOrderSorter); } } @@ -2042,13 +2037,13 @@ void CPlayerInterface::finishMovement( const TryMoveHero &details, const int3 &h subRect(details.end.x, details.end.y, details.end.z, genRect(32, 32, 64, 32), ho->id); //restoring good order of objects - std::stable_sort(CGI->mh->ttiles[details.end.x-2][details.end.y-1][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x-2][details.end.y-1][details.end.z].objects.end(), ocmptwo_cgin); - std::stable_sort(CGI->mh->ttiles[details.end.x-1][details.end.y-1][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x-1][details.end.y-1][details.end.z].objects.end(), ocmptwo_cgin); - std::stable_sort(CGI->mh->ttiles[details.end.x][details.end.y-1][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x][details.end.y-1][details.end.z].objects.end(), ocmptwo_cgin); + std::stable_sort(CGI->mh->ttiles[details.end.x-2][details.end.y-1][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x-2][details.end.y-1][details.end.z].objects.end(), objectBlitOrderSorter); + std::stable_sort(CGI->mh->ttiles[details.end.x-1][details.end.y-1][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x-1][details.end.y-1][details.end.z].objects.end(), objectBlitOrderSorter); + std::stable_sort(CGI->mh->ttiles[details.end.x][details.end.y-1][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x][details.end.y-1][details.end.z].objects.end(), objectBlitOrderSorter); - std::stable_sort(CGI->mh->ttiles[details.end.x-2][details.end.y][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x-2][details.end.y][details.end.z].objects.end(), ocmptwo_cgin); - std::stable_sort(CGI->mh->ttiles[details.end.x-1][details.end.y][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x-1][details.end.y][details.end.z].objects.end(), ocmptwo_cgin); - std::stable_sort(CGI->mh->ttiles[details.end.x][details.end.y][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x][details.end.y][details.end.z].objects.end(), ocmptwo_cgin); + std::stable_sort(CGI->mh->ttiles[details.end.x-2][details.end.y][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x-2][details.end.y][details.end.z].objects.end(), objectBlitOrderSorter); + std::stable_sort(CGI->mh->ttiles[details.end.x-1][details.end.y][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x-1][details.end.y][details.end.z].objects.end(), objectBlitOrderSorter); + std::stable_sort(CGI->mh->ttiles[details.end.x][details.end.y][details.end.z].objects.begin(), CGI->mh->ttiles[details.end.x][details.end.y][details.end.z].objects.end(), objectBlitOrderSorter); } void CPlayerInterface::gameOver(PlayerColor player, const EVictoryLossCheckResult & victoryLossCheckResult ) diff --git a/client/CQuestLog.cpp b/client/CQuestLog.cpp index 1eb621ce4..05cf409c4 100644 --- a/client/CQuestLog.cpp +++ b/client/CQuestLog.cpp @@ -140,7 +140,7 @@ void CQuestLog::init() MetaString text; quests[i].quest->getRolloverText (text, false); if (quests[i].obj) - text.addReplacement (quests[i].obj->getHoverText()); //get name of the object + text.addReplacement (quests[i].obj->getObjectName()); //get name of the object CQuestLabel * label = new CQuestLabel (Rect(28, 199 + i * 24, 172,30), FONT_SMALL, TOPLEFT, Colors::WHITE, text.toString()); label->callback = boost::bind(&CQuestLog::selectQuest, this, i); labels.push_back(label); diff --git a/client/Client.h b/client/Client.h index 8ebb49d98..ed16a87c6 100644 --- a/client/Client.h +++ b/client/Client.h @@ -170,7 +170,6 @@ public: bool removeObject(const CGObjectInstance * obj) override {return false;}; void setBlockVis(ObjectInstanceID objid, bool bv) override {}; void setOwner(const CGObjectInstance * obj, PlayerColor owner) override {}; - void setHoverName(const CGObjectInstance * obj, MetaString * name) override {}; void changePrimSkill(const CGHeroInstance * hero, PrimarySkill::PrimarySkill which, si64 val, bool abs=false) override {}; void changeSecSkill(const CGHeroInstance * hero, SecondarySkill which, int val, bool abs=false) override {}; @@ -218,6 +217,9 @@ public: void sendAndApply(CPackForClient * info) override {}; void heroExchange(ObjectInstanceID hero1, ObjectInstanceID hero2) override {}; + void changeFogOfWar(int3 center, ui32 radius, PlayerColor player, bool hide) override {} + void changeFogOfWar(std::unordered_set &tiles, PlayerColor player, bool hide) override {} + ////////////////////////////////////////////////////////////////////////// friend class CCallback; //handling players actions friend class CBattleCallback; //handling players actions diff --git a/client/GUIClasses.cpp b/client/GUIClasses.cpp index 1d2b8fa91..8d43ddfdb 100644 --- a/client/GUIClasses.cpp +++ b/client/GUIClasses.cpp @@ -1848,7 +1848,7 @@ CObjectListWindow::CObjectListWindow(const std::vector &_items, CIntObject items.reserve(_items.size()); for(int id : _items) { - items.push_back(std::make_pair(id, CGI->mh->map->objects[id]->hoverName)); + items.push_back(std::make_pair(id, CGI->mh->map->objects[id]->getObjectName())); } init(titlePic, _title, _descr); @@ -2614,7 +2614,7 @@ CMarketplaceWindow::CMarketplaceWindow(const IMarket *Market, const CGHeroInstan break; case Obj::BLACK_MARKET: title = CGI->generaltexth->allTexts[349]; break; case Obj::TRADING_POST: title = CGI->generaltexth->allTexts[159]; break; case Obj::TRADING_POST_SNOW: title = CGI->generaltexth->allTexts[159]; - break; default: title = market->o->getHoverText(); + break; default: title = market->o->getObjectName(); } } @@ -4573,7 +4573,7 @@ void CHeroArea::clickRight(tribool down, bool previousState) void CHeroArea::hover(bool on) { if (on && hero) - GH.statusbar->setText(hero->hoverName); + GH.statusbar->setText(hero->getObjectName()); else GH.statusbar->clear(); } @@ -5636,7 +5636,7 @@ CHillFortWindow::CHillFortWindow(const CGHeroInstance *visitor, const CGObjectIn slotsCount=7; resources = CDefHandler::giveDefEss("SMALRES.DEF"); - new CLabel(325, 32, FONT_BIG, CENTER, Colors::YELLOW, fort->hoverName);//Hill Fort + new CLabel(325, 32, FONT_BIG, CENTER, Colors::YELLOW, fort->getObjectName());//Hill Fort heroPic = new CHeroArea(30, 60, hero); @@ -6183,7 +6183,12 @@ void CRClickPopup::createAndPush(const CGObjectInstance *obj, const Point &p, EA if(iWin) GH.pushInt(iWin); else - CRClickPopup::createAndPush(obj->getHoverText()); + { + if (adventureInt->curHero()) + CRClickPopup::createAndPush(obj->getHoverText(adventureInt->curHero())); + else + CRClickPopup::createAndPush(obj->getHoverText(LOCPLINT->playerID)); + } } CRClickPopup::CRClickPopup() diff --git a/client/NetPacksClient.cpp b/client/NetPacksClient.cpp index 1cd5fc384..d23038a6b 100644 --- a/client/NetPacksClient.cpp +++ b/client/NetPacksClient.cpp @@ -15,6 +15,7 @@ #include "../lib/VCMIDirs.h" #include "../lib/CSpellHandler.h" #include "../lib/CSoundBase.h" +#include "../lib/StartInfo.h" #include "mapHandler.h" #include "GUIClasses.h" #include "../lib/CConfigHandler.h" diff --git a/client/VCMI_client.cbp b/client/VCMI_client.cbp index d10236d21..5a563e035 100644 --- a/client/VCMI_client.cbp +++ b/client/VCMI_client.cbp @@ -152,7 +152,6 @@ - diff --git a/client/VCMI_client.vcxproj b/client/VCMI_client.vcxproj index 6bc9b673d..7b1226997 100644 --- a/client/VCMI_client.vcxproj +++ b/client/VCMI_client.vcxproj @@ -229,7 +229,6 @@ - diff --git a/client/VCMI_client.vcxproj.filters b/client/VCMI_client.vcxproj.filters index 89dd439e0..ab9f794a4 100644 --- a/client/VCMI_client.vcxproj.filters +++ b/client/VCMI_client.vcxproj.filters @@ -78,7 +78,6 @@ - diff --git a/client/battle/CBattleInterfaceClasses.cpp b/client/battle/CBattleInterfaceClasses.cpp index fcf3d878e..cbfa489bc 100644 --- a/client/battle/CBattleInterfaceClasses.cpp +++ b/client/battle/CBattleInterfaceClasses.cpp @@ -17,6 +17,7 @@ #include "../../lib/NetPacks.h" #include "../../lib/CCreatureHandler.h" #include "../../lib/BattleState.h" +#include "../../lib/StartInfo.h" #include "../CMusicHandler.h" #include "../CVideoHandler.h" #include "../../lib/CTownHandler.h" diff --git a/client/mapHandler.cpp b/client/mapHandler.cpp index 7c7ac0575..2d4a4271c 100644 --- a/client/mapHandler.cpp +++ b/client/mapHandler.cpp @@ -75,21 +75,10 @@ std::string nameFromType (int typ) return std::string(); } -struct OCM_HLP +static bool objectBlitOrderSorter(const std::pair & a, const std::pair & b) { - bool operator ()(const std::pair & a, const std::pair & b) - { - return (*a.first)<(*b.first); - } -} ocmptwo ; - -// void alphaTransformDef(CGDefInfo * defInfo) -// { -// for(int yy=0; yyhandler->ourImages.size(); ++yy) -// { -// CSDL_Ext::alphaTransform(defInfo->handler->ourImages[yy].bitmap); -// } -// } + return CMapHandler::compareObjectBlitOrder(a.first, b.first); +} void CMapHandler::prepareFOWDefs() { @@ -308,7 +297,7 @@ void CMapHandler::initObjectRects() { for(int iz=0; izID == Obj::HOLE) //Hole { - out = elem.first->hoverName; + out = elem.first->getObjectName(); return; } } @@ -1092,3 +1081,25 @@ ui8 CMapHandler::getPhaseShift(const CGObjectInstance *object) const TerrainTile2::TerrainTile2() :terbitmap(nullptr) {} + +bool CMapHandler::compareObjectBlitOrder(const CGObjectInstance * a, const CGObjectInstance * b) +{ + if (a->appearance.printPriority != b->appearance.printPriority) + return a->appearance.printPriority > b->appearance.printPriority; + + if(a->pos.y != b->pos.y) + return a->pos.y < b->pos.y; + + if(b->ID==Obj::HERO && a->ID!=Obj::HERO) + return true; + if(b->ID!=Obj::HERO && a->ID==Obj::HERO) + return false; + + if(!a->isVisitable() && b->isVisitable()) + return true; + if(!b->isVisitable() && a->isVisitable()) + return false; + if(a->pos.x < b->pos.x) + return true; + return false; +} diff --git a/client/mapHandler.h b/client/mapHandler.h index 09d4eaae9..7700c47a5 100644 --- a/client/mapHandler.h +++ b/client/mapHandler.h @@ -108,7 +108,6 @@ public: std::pair getVisBitmap(const int3 & pos, const std::vector< std::vector< std::vector > > & visibilityMap) const; //returns appropriate bitmap and info if alpha blitting is necessary ui8 getPhaseShift(const CGObjectInstance *object) const; - std::vector< std::string > getObjDescriptions(int3 pos); //returns desriptions of objects blocking given position void getTerrainDescr(const int3 &pos, std::string & out, bool terName); //if tername == false => empty string when tile is clear CGObjectInstance * createObject(int id, int subid, int3 pos, int owner=254); //creates a new object with a certain id and subid bool printObject(const CGObjectInstance * obj); //puts appropriate things to ttiles, so obj will be visible on map @@ -127,4 +126,6 @@ public: void validateRectTerr(SDL_Rect * val, const SDL_Rect * ext); //terrainRect helper static ui8 getDir(const int3 & a, const int3 & b); //returns direction number in range 0 - 7 (0 is left top, clockwise) [direction: form a to b] + static bool compareObjectBlitOrder(const CGObjectInstance * a, const CGObjectInstance * b); + }; diff --git a/config/objects/creatureBanks.json b/config/objects/creatureBanks.json index 6cba397be..e1ad6f6e9 100644 --- a/config/objects/creatureBanks.json +++ b/config/objects/creatureBanks.json @@ -526,7 +526,7 @@ "combat_value": 154, "reward" : { "value": 3200, - "creatures": [ { "amount": 4, "type": "vyvern" } ] + "creatures": [ { "amount": 4, "type": "wyvern" } ] } }, { @@ -541,7 +541,7 @@ "combat_value": 230, "reward" : { "value": 4800, - "creatures": [ { "amount": 6, "type": "vyvern" } ] + "creatures": [ { "amount": 6, "type": "wyvern" } ] } }, { @@ -556,7 +556,7 @@ "combat_value": 307, "reward" : { "value": 6400, - "creatures": [ { "amount": 8, "type": "vyvern" } ] + "creatures": [ { "amount": 8, "type": "wyvern" } ] } }, { @@ -571,7 +571,7 @@ "combat_value": 461, "reward" : { "value": 9600, - "creatures": [ { "amount": 12, "type": "vyvern" } ] + "creatures": [ { "amount": 12, "type": "wyvern" } ] } } ] diff --git a/config/objects/generic.json b/config/objects/generic.json index bc1e1dcf8..c92a6d97a 100644 --- a/config/objects/generic.json +++ b/config/objects/generic.json @@ -8,126 +8,299 @@ "prison" : { "index" : 0 } } }, + + "altarOfSacrifice" : { "index" :2, "handler": "market", "types" : { "object" : { "index" : 0} } }, + "tradingPost" : { "index" :221, "handler": "market", "types" : { "object" : { "index" : 0} } }, + "tradingPostDUPLICATE" : { "index" :99, "handler": "market", "types" : { "object" : { "index" : 0} } }, + "freelancersGuild" : { "index" :213, "handler": "market", "types" : { "object" : { "index" : 0} } }, + + "blackMarket" : { "index" :7, "handler": "blackMarket", "types" : { "object" : { "index" : 0} } }, + + "pandoraBox" : { "index" :6, "handler": "pandora", "types" : { "object" : { "index" : 0} } }, + "event" : { "index" :26, "handler": "event", "types" : { "object" : { "index" : 0} } }, + + "redwoodObservatory" : { "index" :58, "handler": "observatory", "types" : { "object" : { "index" : 0} } }, + "pillarOfFire" : { "index" :60, "handler": "observatory", "types" : { "object" : { "index" : 0} } }, + "coverOfDarkness" : { "index" :15, "handler": "observatory", "types" : { "object" : { "index" : 0} } }, - "altarOfSacrifice" : { "index" :2, "handler": "market" }, - "tradingPost" : { "index" :221, "handler": "market" }, - "tradingPostDUPLICATE" : { "index" :99, "handler": "market" }, - "freelancersGuild" : { "index" :213, "handler": "market" }, + "whirlpool" : { "index" :111, "handler": "teleport", "types" : { "object" : { "index" : 0} } }, + "subterraneanGate" : { + "index" :103, + "handler": "teleport", + "types" : { + "object" : { "index" : 0 }, + "objectWoG" : { "index" : 1 } // WoG object? Present on VCMI Test 2011b + } + }, - "blackMarket" : { "index" :7, "handler": "blackMarket" }, + "refugeeCamp" : { "index" :78, "handler": "dwelling", "types" : { "object" : { "index" : 0} } }, + "warMachineFactory" : { "index" :106, "handler": "dwelling", "types" : { "object" : { "index" : 0} } }, - "pandoraBox" : { "index" :6, "handler": "pandora" }, - "event" : { "index" :26, "handler": "event" }, + "shrineOfMagicLevel1" : { "index" :88, "handler": "shrine", "types" : { "object" : { "index" : 0} } }, + "shrineOfMagicLevel2" : { "index" :89, "handler": "shrine", "types" : { "object" : { "index" : 0} } }, + "shrineOfMagicLevel3" : { "index" :90, "handler": "shrine", "types" : { "object" : { "index" : 0} } }, - "redwoodObservatory" : { "index" :58, "handler": "observatory" }, - "pillarOfFire" : { "index" :60, "handler": "observatory" }, - "coverOfDarkness" : { "index" :15, "handler": "observatory" }, - - "subterraneanGate" : { "index" :103, "handler": "teleport" }, - "whirlpool" : { "index" :111, "handler": "teleport" }, + "eyeOfTheMagi" : { "index" :27, "handler": "magi", "types" : { "object" : { "index" : 0} } }, + "hutOfTheMagi" : { "index" :37, "handler": "magi", "types" : { "object" : { "index" : 0} } }, - "refugeeCamp" : { "index" :78, "handler": "dwelling" }, - "warMachineFactory" : { "index" :106, "handler": "dwelling" }, - - "shrineOfMagicLevel1" : { "index" :88, "handler": "shrine" }, - "shrineOfMagicLevel2" : { "index" :89, "handler": "shrine" }, - "shrineOfMagicLevel3" : { "index" :90, "handler": "shrine" }, - - "eyeOfTheMagi" : { "index" :27, "handler": "magi" }, - "hutOfTheMagi" : { "index" :37, "handler": "magi" }, - - "lighthouse" : { "index" :42, "handler": "lighthouse" }, - "magicWell" : { "index" :49, "handler": "magicWell" }, - "obelisk" : { "index" :57, "handler": "obelisk" }, - "oceanBottle" : { "index" :59, "handler": "sign" }, - "scholar" : { "index" :81, "handler": "scholar" }, - "shipyard" : { "index" :87, "handler": "shipyard" }, - "sign" : { "index" :91, "handler": "sign" }, - "sirens" : { "index" :92, "handler": "siren" }, - "denOfThieves" : { "index" :97, "handler": "denOfThieves" }, - "university" : { "index" :104, "handler": "university" }, - "witchHut" : { "index" :113, "handler": "witch" }, - "questGuard" : { "index" :215, "handler": "questGuard" }, + "lighthouse" : { "index" :42, "handler": "lighthouse", "types" : { "object" : { "index" : 0} } }, + "obelisk" : { "index" :57, "handler": "obelisk", "types" : { "object" : { "index" : 0} } }, + "oceanBottle" : { "index" :59, "handler": "sign", "types" : { "object" : { "index" : 0} } }, + "scholar" : { "index" :81, "handler": "scholar", "types" : { "object" : { "index" : 0} } }, + "shipyard" : { "index" :87, "handler": "shipyard", "types" : { "object" : { "index" : 0} } }, + "sign" : { "index" :91, "handler": "sign", "types" : { "object" : { "index" : 0} } }, + "sirens" : { "index" :92, "handler": "siren", "types" : { "object" : { "index" : 0} } }, + "denOfThieves" : { "index" :97, "handler": "denOfThieves", "types" : { "object" : { "index" : 0} } }, + "university" : { "index" :104, "handler": "university", "types" : { "object" : { "index" : 0} } }, + "witchHut" : { "index" :113, "handler": "witch", "types" : { "object" : { "index" : 0} } }, + "questGuard" : { "index" :215, "handler": "questGuard", "types" : { "object" : { "index" : 0} } }, + "magicWell" : { + "index" :49, + "handler": "magicWell", + "types" : { + "object" : { "index" : 0}, + "objectWoG" : { "index" : 1} // WoG object? Present on VCMI_Test 2011b + } + }, /// Random objects - "randomResource" : { "index" :76, "handler": "resource" }, - "randomTown" : { "index" :77, "handler": "town" }, - "randomHero" : { "index" :70, "handler": "hero" }, - - "randomDwelling" : { "index" :216, "handler": "dwelling" }, + "randomTown" : { "index" :77, "handler": "randomTown", "types" : { "object" : { "index" : 0} } }, + "randomHero" : { "index" :70, "handler": "randomHero", "types" : { "object" : { "index" : 0} } }, + "randomDwelling" : { "index" :216, "handler": "randomDwelling", "types" : { "object" : { "index" : 0} } }, - "randomArtifact" : { "index" :65, "handler": "artifact" }, - "randomArtifactTreasure" : { "index" :66, "handler": "artifact" }, - "randomArtifactMinor" : { "index" :67, "handler": "artifact" }, - "randomArtifactMajor" : { "index" :68, "handler": "artifact" }, - "randomArtifactRelic" : { "index" :69, "handler": "artifact" }, + "randomResource" : { + "index" :76, + "handler": "randomResource", + "types" : { + "object" : { + "index" : 0, + "templates" : { + "normal" : { "animation" : "AVTrndm0", "visitableFrom" : [ "+++", "+-+", "+++" ], "mask" : [ "VV", "VA"] } + } + } + } + }, - "randomMonster" : { "index" :71, "handler": "monster" }, - "randomMonsterLevel1" : { "index" :72, "handler": "monster" }, - "randomMonsterLevel2" : { "index" :73, "handler": "monster" }, - "randomMonsterLevel3" : { "index" :74, "handler": "monster" }, - "randomMonsterLevel4" : { "index" :75, "handler": "monster" }, - "randomMonsterLevel5" : { "index" :162, "handler": "monster" }, - "randomMonsterLevel6" : { "index" :163, "handler": "monster" }, - "randomMonsterLevel7" : { "index" :164, "handler": "monster" }, + "randomArtifact" : { + "index" :65, + "handler": "randomArtifact", + "types" : { + "object" : { + "index" : 0, + "templates" : { + "normal" : { "animation" : "AVArand", "visitableFrom" : [ "+++", "+-+", "+++" ], "mask" : [ "VV", "VA"] } + } + } + } + }, + "randomArtifactTreasure" : { + "index" :66, + "handler": "randomArtifact", + "types" : { + "object" : { + "index" : 0, + "templates" : { + "normal" : { "animation" : "AVArnd1", "visitableFrom" : [ "+++", "+-+", "+++" ], "mask" : [ "VV", "VA"] } + } + } + } + }, + "randomArtifactMinor" : { + "index" :67, + "handler": "randomArtifact", + "types" : { + "object" : { + "index" : 0, + "templates" : { + "normal" : { "animation" : "AVArnd2", "visitableFrom" : [ "+++", "+-+", "+++" ], "mask" : [ "VV", "VA"] } + } + } + } + }, + "randomArtifactMajor" : { + "index" :68, + "handler": "randomArtifact", + "types" : { + "object" : { + "index" : 0, + "templates" : { + "normal" : { "animation" : "AVArnd3", "visitableFrom" : [ "+++", "+-+", "+++" ], "mask" : [ "VV", "VA"] } + } + } + } + }, + "randomArtifactRelic" : { + "index" :69, + "handler": "randomArtifact", + "types" : { + "object" : { + "index" : 0, + "templates" : { + "normal" : { "animation" : "AVArnd4", "visitableFrom" : [ "+++", "+-+", "+++" ], "mask" : [ "VV", "VA"] } + } + } + } + }, + + "randomMonster" : { + "index" :71, + "handler": "randomMonster", + "types" : { + "object" : { + "index" : 0, + "templates" : { + "normal" : { "animation" : "AVWmrnd0", "visitableFrom" : [ "+++", "+-+", "+++" ], "mask" : [ "VV", "VA"] } + } + } + } + }, + "randomMonsterLevel1" : { + "index" :72, + "handler": "randomMonster", + "types" : { + "object" : { + "index" : 0, + "templates" : { + "normal" : { "animation" : "AVWmon1", "visitableFrom" : [ "+++", "+-+", "+++" ], "mask" : [ "VV", "VA"] } + } + } + } + }, + "randomMonsterLevel2" : { + "index" :73, + "handler": "randomMonster", + "types" : { + "object" : { + "index" : 0, + "templates" : { + "normal" : { "animation" : "AVWmon2", "visitableFrom" : [ "+++", "+-+", "+++" ], "mask" : [ "VV", "VA"] } + } + } + } + }, + "randomMonsterLevel3" : { + "index" :74, + "handler": "randomMonster", + "types" : { + "object" : { + "index" : 0, + "templates" : { + "normal" : { "animation" : "AVWmon3", "visitableFrom" : [ "+++", "+-+", "+++" ], "mask" : [ "VV", "VA"] } + } + } + } + }, + "randomMonsterLevel4" : { + "index" :75, + "handler": "randomMonster", + "types" : { + "object" : { + "index" : 0, + "templates" : { + "normal" : { "animation" : "AVWmon4", "visitableFrom" : [ "+++", "+-+", "+++" ], "mask" : [ "VV", "VA"] } + } + } + } + }, + "randomMonsterLevel5" : { + "index" :162, + "handler": "randomMonster", + "types" : { + "object" : { + "index" : 0, + "templates" : { + "normal" : { "animation" : "AVWmon5", "visitableFrom" : [ "+++", "+-+", "+++" ], "mask" : [ "VV", "VA"] } + } + } + } + }, + "randomMonsterLevel6" : { + "index" :163, + "handler": "randomMonster", + "types" : { + "object" : { + "index" : 0, + "templates" : { + "normal" : { "animation" : "AVWmon6", "visitableFrom" : [ "+++", "+-+", "+++" ], "mask" : [ "VV", "VA"] } + } + } + } + }, + "randomMonsterLevel7" : { + "index" :164, + "handler": "randomMonster", + "types" : { + "object" : { + "index" : 0, + "templates" : { + "normal" : { "animation" : "AVWmon7", "visitableFrom" : [ "+++", "+-+", "+++" ], "mask" : [ "VV", "VA"] } + } + } + } + }, /// Classes without dedicated object - "hillFort" : { "index" :35, "handler": "generic" }, - "grail" : { "index" :36, "handler": "generic" }, - "tavern" : { "index" :95, "handler": "generic" }, - "sanctuary" : { "index" :80, "handler": "generic" }, + "hillFort" : { "index" :35, "handler": "generic", "types" : { "object" : { "index" : 0} } }, + "grail" : { "index" :36, "handler": "generic", "types" : { "object" : { "index" : 0} } }, + "tavern" : { "index" :95, "handler": "generic", "types" : { "object" : { "index" : 0} } }, + "sanctuary" : { "index" :80, "handler": "generic", "types" : { "object" : { "index" : 0} } }, /// Passive objects, terrain overlays - "cursedGround" : { "index" :21, "handler": "generic" }, - "magicPlains" : { "index" :46, "handler": "generic" }, - "swampFoliage" : { "index" :211, "handler": "generic" }, - "cloverField" : { "index" :222, "handler": "generic" }, - "cursedGroundDUPLICATE" : { "index" :223, "handler": "generic" }, - "evilFog" : { "index" :224, "handler": "generic" }, - "favorableWinds" : { "index" :225, "handler": "generic" }, - "fieryFields" : { "index" :226, "handler": "generic" }, - "holyGround" : { "index" :227, "handler": "generic" }, - "lucidPools" : { "index" :228, "handler": "generic" }, - "magicClouds" : { "index" :229, "handler": "generic" }, - "magicPlainsDUPLICATE" : { "index" :230, "handler": "generic" }, - "rocklands" : { "index" :231, "handler": "generic" }, + "cursedGround" : { "index" :21, "handler": "generic", "types" : { "object" : { "index" : 0} } }, + "magicPlains" : { "index" :46, "handler": "generic", "types" : { "object" : { "index" : 0} } }, + "swampFoliage" : { "index" :211, "handler": "generic", "types" : { "object" : { "index" : 0} } }, + "cloverField" : { "index" :222, "handler": "generic", "types" : { "object" : { "index" : 0} } }, + "cursedGroundDUPLICATE" : { "index" :223, "handler": "generic", "types" : { "object" : { "index" : 0} } }, + "evilFog" : { "index" :224, "handler": "generic", "types" : { "object" : { "index" : 0} } }, + "favorableWinds" : { "index" :225, "handler": "generic", "types" : { "object" : { "index" : 0} } }, + "fieryFields" : { "index" :226, "handler": "generic", "types" : { "object" : { "index" : 0} } }, + "holyGround" : { "index" :227, "handler": "generic", "types" : { "object" : { "index" : 0} } }, + "lucidPools" : { "index" :228, "handler": "generic", "types" : { "object" : { "index" : 0} } }, + "magicClouds" : { "index" :229, "handler": "generic", "types" : { "object" : { "index" : 0} } }, + "magicPlainsDUPLICATE" : { "index" :230, "handler": "generic", "types" : { "object" : { "index" : 0} } }, + "rocklands" : { "index" :231, "handler": "generic", "types" : { "object" : { "index" : 0} } }, /// Decorations - "cactus" : { "index" :116, "handler": "static" }, - "canyon" : { "index" :117, "handler": "static" }, - "crater" : { "index" :118, "handler": "static" }, - "deadVegetation" : { "index" :119, "handler": "static" }, - "flowers" : { "index" :120, "handler": "static" }, - "frozenLake" : { "index" :121, "handler": "static" }, - "hole" : { "index" :124, "handler": "static" }, - "kelp" : { "index" :125, "handler": "static" }, - "lake" : { "index" :126, "handler": "static" }, - "lavaFlow" : { "index" :127, "handler": "static" }, - "lavaLake" : { "index" :128, "handler": "static" }, - "mushrooms" : { "index" :129, "handler": "static" }, - "log" : { "index" :130, "handler": "static" }, - "mandrake" : { "index" :131, "handler": "static" }, - "moss" : { "index" :132, "handler": "static" }, - "mound" : { "index" :133, "handler": "static" }, - "mountain" : { "index" :134, "handler": "static" }, - "oakTrees" : { "index" :135, "handler": "static" }, - "outcropping" : { "index" :136, "handler": "static" }, - "pineTrees" : { "index" :137, "handler": "static" }, - "riverDelta" : { "index" :143, "handler": "static" }, - "rock" : { "index" :147, "handler": "static" }, - "sandDune" : { "index" :148, "handler": "static" }, - "sandPit" : { "index" :149, "handler": "static" }, - "shrub" : { "index" :150, "handler": "static" }, - "skull" : { "index" :151, "handler": "static" }, - "stump" : { "index" :153, "handler": "static" }, - "trees" : { "index" :155, "handler": "static" }, - "volcano" : { "index" :158, "handler": "static" }, - "reef" : { "index" :161, "handler": "static" }, - "lakeDUPLICATE" : { "index" :177, "handler": "static" }, - "treesDUPLICATE" : { "index" :199, "handler": "static" }, - "desertHills" : { "index" :206, "handler": "static" }, - "dirtHills" : { "index" :207, "handler": "static" }, - "grassHills" : { "index" :208, "handler": "static" }, - "roughHills" : { "index" :209, "handler": "static" }, - "subterraneanRocks" : { "index" :210, "handler": "static" } + "cactus" : { "index" :116, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "canyon" : { "index" :117, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "crater" : { "index" :118, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "deadVegetation" : { "index" :119, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "flowers" : { "index" :120, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "frozenLake" : { "index" :121, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "hole" : { "index" :124, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "kelp" : { "index" :125, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "lake" : { "index" :126, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "lavaFlow" : { "index" :127, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "lavaLake" : { "index" :128, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "mushrooms" : { "index" :129, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "log" : { "index" :130, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "mandrake" : { "index" :131, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "moss" : { "index" :132, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "mound" : { "index" :133, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "mountain" : { "index" :134, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "oakTrees" : { "index" :135, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "outcropping" : { "index" :136, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "pineTrees" : { "index" :137, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "riverDelta" : { "index" :143, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "rock" : { "index" :147, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "sandDune" : { "index" :148, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "sandPit" : { "index" :149, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "shrub" : { "index" :150, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "skull" : { "index" :151, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "stump" : { "index" :153, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "trees" : { "index" :155, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "volcano" : { "index" :158, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "reef" : { "index" :161, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "lakeDUPLICATE" : { "index" :177, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "treesDUPLICATE" : { "index" :199, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "desertHills" : { "index" :206, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "dirtHills" : { "index" :207, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "grassHills" : { "index" :208, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "roughHills" : { "index" :209, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "subterraneanRocks" : { "index" :210, "handler": "static", "types" : { "object" : { "index" : 0} } }, + + //These are WoG objects? They are not available in H3 + "frozenLakeDUPLICATE" : { "index" :172, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "oakTreesDUPLICATE" : { "index" :186, "handler": "static", "types" : { "object" : { "index" : 0} } }, + "plant" : { "index" :189, "handler": "static", "types" : { "object" : { "index" : 0} } } } diff --git a/config/objects/moddables.json b/config/objects/moddables.json index b03c5f6a5..1f460b3c1 100644 --- a/config/objects/moddables.json +++ b/config/objects/moddables.json @@ -189,20 +189,99 @@ "garrisonVertical" : { "index" :219, "handler": "garrison" }, // Subtype: paired monoliths - "monolithOneWayEntrance" : { "index" :43, "handler": "teleport" }, - "monolithOneWayExit" : { "index" :44, "handler": "teleport" }, - "monolithTwoWay" : { "index" :45, "handler": "teleport" }, + "monolithOneWayEntrance" : { + "index" :43, + "handler": "teleport", + "types" : { + "monolith1" : { "index" : 0 }, + "monolith2" : { "index" : 1 }, + "monolith3" : { "index" : 2 }, + "monolith4" : { "index" : 3 }, + "monolith5" : { "index" : 4 }, + "monolith6" : { "index" : 5 }, + "monolith7" : { "index" : 6 }, + "monolith8" : { "index" : 7 } + } + }, + "monolithOneWayExit" : { + "index" :44, + "handler": "teleport", + "types" : { + "monolith1" : { "index" : 0 }, + "monolith2" : { "index" : 1 }, + "monolith3" : { "index" : 2 }, + "monolith4" : { "index" : 3 }, + "monolith5" : { "index" : 4 }, + "monolith6" : { "index" : 5 }, + "monolith7" : { "index" : 6 }, + "monolith8" : { "index" : 7 } + } + }, + "monolithTwoWay" : { + "index" :45, + "handler": "teleport", + "types" : { + "monolith1" : { "index" : 0 }, + "monolith2" : { "index" : 1 }, + "monolith3" : { "index" : 2 }, + "monolith4" : { "index" : 3 }, + "monolith5" : { "index" : 4 }, + "monolith6" : { "index" : 5 }, + "monolith7" : { "index" : 6 }, + "monolith8" : { "index" : 7 } + } + }, // subtype: different appearance. That's all? "seerHut" : { "index" :83, "handler": "seerHut" }, // subtype: level - "randomDwellingLvl" : { "index" :217, "handler": "dwelling" }, + "randomDwellingLvl" : { + "index" :217, "handler": "randomDwelling", + "types" : { + "objectLvl1" : { "index" : 0}, + "objectLvl2" : { "index" : 1}, + "objectLvl3" : { "index" : 2}, + "objectLvl4" : { "index" : 3}, + "objectLvl5" : { "index" : 4}, + "objectLvl6" : { "index" : 5}, + "objectLvl7" : { "index" : 6} + } + }, // subtype: faction ID - "randomDwellingFaction" : { "index" :218, "handler": "dwelling" }, + "randomDwellingFaction" : { + "index" :218, + "handler": "randomDwelling", + "types" : { + "objectCastle" : { "index" : 0}, + "objectRampart" : { "index" : 1}, + "objectTower" : { "index" : 2}, + "objectInferno" : { "index" : 3}, + "objectNecropolis" : { "index" : 4}, + "objectDungeon" : { "index" : 5}, + "objectStronghold" : { "index" : 6}, + "objectFortress" : { "index" : 7}, + "objectConflux" : { "index" : 8}, + } + }, // don't have subtypes (at least now), but closely connected to this objects - "spellScroll" : { "index" :93, "handler": "artifact" }, - "heroPlaceholder" : { "index" :214, "handler": "heroPlaceholder" } + "spellScroll" : { + "index" :93, + "handler": "artifact", + "types" : { + "object" : { + "index" : 0, + "templates" : { + "normal" : { + "visitableFrom" : [ "+++", "+-+", "+++" ], + "mask" : [ "VA" ], + "animation" : "AVA0001.def" + } + } + } + } + }, + "heroPlaceholder" : { "index" :214, "handler": "heroPlaceholder", "types" : { "object" : { "index" : 0 } } } } diff --git a/config/objects/rewardable.json b/config/objects/rewardable.json index 7b6a06984..b0847471e 100644 --- a/config/objects/rewardable.json +++ b/config/objects/rewardable.json @@ -1,44 +1,51 @@ { /// These are objects that covered by concept of "configurable object" /// Most or even all of their configuration located in this file - "magicSpring" : { "index" :48, "handler": "magicSpring" }, + "magicSpring" : { "index" :48, "handler": "magicSpring", "types" : { "object" : { "index" : 0} } }, - "mysticalGarden" : { "index" :55, "handler": "oncePerWeek" }, - "windmill" : { "index" :112, "handler": "oncePerWeek" }, - "waterWheel" : { "index" :109, "handler": "oncePerWeek" }, + "mysticalGarden" : { "index" :55, "handler": "oncePerWeek", "types" : { "object" : { "index" : 0} } }, + "windmill" : { "index" :112, "handler": "oncePerWeek", "types" : { "object" : { "index" : 0} } }, + "waterWheel" : { "index" :109, "handler": "oncePerWeek", "types" : { "object" : { "index" : 0} } }, - "leanTo" : { "index" :39, "handler": "onceVisitable" }, - "corpse" : { "index" :22, "handler": "onceVisitable" }, - "wagon" : { "index" :105, "handler": "onceVisitable" }, - "warriorTomb" : { "index" :108, "handler": "onceVisitable" }, + "leanTo" : { "index" :39, "handler": "onceVisitable", "types" : { "object" : { "index" : 0} } }, + "corpse" : { "index" :22, "handler": "onceVisitable", "types" : { "object" : { "index" : 0} } }, + "wagon" : { "index" :105, "handler": "onceVisitable", "types" : { "object" : { "index" : 0} } }, + "warriorTomb" : { "index" :108, "handler": "onceVisitable", "types" : { "object" : { "index" : 0} } }, - "campfire" : { "index" :12, "handler": "pickable" }, - "flotsam" : { "index" :29, "handler": "pickable" }, - "seaChest" : { "index" :82, "handler": "pickable" }, - "shipwreckSurvivor" : { "index" :86, "handler": "pickable" }, - "treasureChest" : { "index" :101, "handler": "pickable" }, + "campfire" : { "index" :12, "handler": "pickable", "types" : { "object" : { "index" : 0} } }, + "flotsam" : { "index" :29, "handler": "pickable", "types" : { "object" : { "index" : 0} } }, + "seaChest" : { "index" :82, "handler": "pickable", "types" : { "object" : { "index" : 0} } }, + "shipwreckSurvivor" : { "index" :86, "handler": "pickable", "types" : { "object" : { "index" : 0} } }, + "treasureChest" : { "index" :101, "handler": "pickable", "types" : { "object" : { "index" : 0} } }, - "arena" : { "index" :4, "handler": "oncePerHero" }, - "marlettoTower" : { "index" :23, "handler": "oncePerHero" }, - "gardenOfRevelation" : { "index" :32, "handler": "oncePerHero" }, - "libraryOfEnlightenment" : { "index" :41, "handler": "oncePerHero" }, - "mercenaryCamp" : { "index" :51, "handler": "oncePerHero" }, - "starAxis" : { "index" :61, "handler": "oncePerHero" }, - "learningStone" : { "index" :100, "handler": "oncePerHero" }, - "treeOfKnowledge" : { "index" :102, "handler": "oncePerHero" }, - "schoolOfMagic" : { "index" :47, "handler": "oncePerHero" }, - "schoolOfWar" : { "index" :107, "handler": "oncePerHero" }, - - "buoy" : { "index" :11, "handler": "bonusingObject" }, - "swanPond" : { "index" :14, "handler": "bonusingObject" }, - "faerieRing" : { "index" :28, "handler": "bonusingObject" }, - "fountainOfFortune" : { "index" :30, "handler": "bonusingObject" }, - "fountainOfYouth" : { "index" :31, "handler": "bonusingObject" }, - "idolOfFortune" : { "index" :38, "handler": "bonusingObject" }, - "mermaids" : { "index" :52, "handler": "bonusingObject" }, - "oasis" : { "index" :56, "handler": "bonusingObject" }, - "stables" : { "index" :94, "handler": "bonusingObject" }, - "temple" : { "index" :96, "handler": "bonusingObject" }, - "rallyFlag" : { "index" :64, "handler": "bonusingObject" }, - "wateringHole" : { "index" :110, "handler": "bonusingObject" }, + "arena" : { "index" :4, "handler": "oncePerHero", "types" : { "object" : { "index" : 0} } }, + "marlettoTower" : { "index" :23, "handler": "oncePerHero", "types" : { "object" : { "index" : 0} } }, + "gardenOfRevelation" : { "index" :32, "handler": "oncePerHero", "types" : { "object" : { "index" : 0} } }, + "libraryOfEnlightenment" : { "index" :41, "handler": "oncePerHero", "types" : { "object" : { "index" : 0} } }, + "mercenaryCamp" : { "index" :51, "handler": "oncePerHero", "types" : { "object" : { "index" : 0} } }, + "starAxis" : { "index" :61, "handler": "oncePerHero", "types" : { "object" : { "index" : 0} } }, + "treeOfKnowledge" : { "index" :102, "handler": "oncePerHero", "types" : { "object" : { "index" : 0} } }, + "schoolOfMagic" : { "index" :47, "handler": "oncePerHero", "types" : { "object" : { "index" : 0} } }, + "schoolOfWar" : { "index" :107, "handler": "oncePerHero", "types" : { "object" : { "index" : 0} } }, + "learningStone" : { + "index" :100, + "handler": "oncePerHero", + "types" : { + "object" : { "index" : 0}, + "objectWoG" : { "index" : 1} // WoG object? Present on VCMI_Tests 2011 + } + }, + + "buoy" : { "index" :11, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } }, + "swanPond" : { "index" :14, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } }, + "faerieRing" : { "index" :28, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } }, + "fountainOfFortune" : { "index" :30, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } }, + "fountainOfYouth" : { "index" :31, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } }, + "idolOfFortune" : { "index" :38, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } }, + "mermaids" : { "index" :52, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } }, + "oasis" : { "index" :56, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } }, + "stables" : { "index" :94, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } }, + "temple" : { "index" :96, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } }, + "rallyFlag" : { "index" :64, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } }, + "wateringHole" : { "index" :110, "handler": "bonusingObject", "types" : { "object" : { "index" : 0} } } } diff --git a/config/rmg.json b/config/rmg.json index 9df21b1b8..8ad5fd895 100644 --- a/config/rmg.json +++ b/config/rmg.json @@ -63,7 +63,7 @@ }, "Upgrade" : { - "minSize" : "m", "maxSize" : "m", + "minSize" : "s", "maxSize" : "m", "players" : "2", "zones" : { @@ -126,7 +126,7 @@ }, "Golden Ring" : { - "minSize" : "m", "maxSize" : "m", + "minSize" : "m", "maxSize" : "l", "players" : "3", "zones" : { diff --git a/config/schemas/mod.json b/config/schemas/mod.json index be0e5b9fd..8206b04d0 100644 --- a/config/schemas/mod.json +++ b/config/schemas/mod.json @@ -87,6 +87,11 @@ "description": "List of configuration files for heroes", "items": { "type":"string", "format" : "textFile" } }, + "objects": { + "type":"array", + "description": "List of configuration files for objects", + "items": { "type":"string", "format" : "textFile" } + }, "spells": { "type":"array", "description": "List of configuration files for spells", diff --git a/debian/changelog b/debian/changelog index 3dde14aad..0405893dd 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +vcmi (0.96) trusty; urgency=low + + * New upstream release + + -- Ivan Savenko Tue, 01 Jul 2014 20:57:29 +0300 + vcmi (0.95) precise; urgency=low * New upstream release diff --git a/lib/BattleState.cpp b/lib/BattleState.cpp index 8b8395157..fb2b1eeff 100644 --- a/lib/BattleState.cpp +++ b/lib/BattleState.cpp @@ -365,13 +365,11 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, ETerrainType terrain, BFieldTyp if(town) { curB->town = town; - curB->siege = town->fortLevel(); curB->terrainType = VLC->townh->factions[town->subID]->nativeTerrain; } else { curB->town = nullptr; - curB->siege = CGTownInstance::NONE; curB->terrainType = terrain; } @@ -574,13 +572,13 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, ETerrainType terrain, BFieldTyp } - if (curB->siege == CGTownInstance::CITADEL || curB->siege == CGTownInstance::CASTLE) + if (curB->town && curB->town->fortLevel() >= CGTownInstance::CITADEL) { // keep tower CStack * stack = curB->generateNewStack(CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), false, SlotID(255), -2); stacks.push_back(stack); - if (curB->siege == CGTownInstance::CASTLE) + if (curB->town->fortLevel() >= CGTownInstance::CASTLE) { // lower tower + upper tower CStack * stack = curB->generateNewStack(CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), false, SlotID(255), -4); diff --git a/lib/BattleState.h b/lib/BattleState.h index 3d8ac4587..4eb774f4d 100644 --- a/lib/BattleState.h +++ b/lib/BattleState.h @@ -4,8 +4,8 @@ #include "BattleHex.h" #include "HeroBonus.h" #include "CCreatureSet.h" -#include "mapObjects/CGTownInstance.h" -#include "mapObjects/CGHeroInstance.h" +#include "mapObjects/CArmedInstance.h" // for army serialization +#include "mapObjects/CGHeroInstance.h" // for commander serialization #include "CCreatureHandler.h" #include "CObstacleInstance.h" #include "ConstTransitivePtr.h" @@ -83,8 +83,7 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallb { std::array sides; //sides[0] - attacker, sides[1] - defender si32 round, activeStack, selectedStack; - CGTownInstance::EFortLevel siege; - const CGTownInstance * town; //used during town siege - id of attacked town; -1 if not town defence + const CGTownInstance * town; //used during town siege, nullptr if this is not a siege (note that fortless town IS also a siege) int3 tile; //for background and bonuses std::vector stacks; std::vector > obstacles; @@ -99,7 +98,7 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallb template void serialize(Handler &h, const int version) { h & sides; - h & round & activeStack & selectedStack & siege & town & tile & stacks & obstacles + h & round & activeStack & selectedStack & town & tile & stacks & obstacles & si & battlefieldType & terrainType; h & tacticsSide & tacticDistance; h & static_cast(*this); diff --git a/lib/CArtHandler.h b/lib/CArtHandler.h index 592e1de58..805cc6aeb 100644 --- a/lib/CArtHandler.h +++ b/lib/CArtHandler.h @@ -2,8 +2,8 @@ #include "../lib/HeroBonus.h" -#include "../lib/ConstTransitivePtr.h" -#include "JsonNode.h" +//#include "../lib/ConstTransitivePtr.h" +//#include "JsonNode.h" #include "GameConstants.h" #include "IHandlerBase.h" diff --git a/lib/CBattleCallback.cpp b/lib/CBattleCallback.cpp index 1744ca27a..10692aa8d 100644 --- a/lib/CBattleCallback.cpp +++ b/lib/CBattleCallback.cpp @@ -409,7 +409,7 @@ ui8 CBattleInfoEssentials::playerToSide(PlayerColor player) const ui8 CBattleInfoEssentials::battleGetSiegeLevel() const { RETURN_IF_NOT_BATTLE(0); - return getBattle()->siege; + return getBattle()->town ? getBattle()->town->fortLevel() : CGTownInstance::NONE; } bool CBattleInfoEssentials::battleCanSurrender(PlayerColor player) const @@ -429,7 +429,7 @@ bool CBattleInfoEssentials::battleHasHero(ui8 side) const si8 CBattleInfoEssentials::battleGetWallState(int partOfWall) const { RETURN_IF_NOT_BATTLE(0); - if(getBattle()->siege == CGTownInstance::NONE) + if(getBattle()->town == nullptr || getBattle()->town->fortLevel() == CGTownInstance::NONE) return EWallState::NONE; assert(partOfWall >= 0 && partOfWall < EWallPart::PARTS_COUNT); diff --git a/lib/CCreatureSet.cpp b/lib/CCreatureSet.cpp index f33019a81..7dea9f9f0 100644 --- a/lib/CCreatureSet.cpp +++ b/lib/CCreatureSet.cpp @@ -224,6 +224,7 @@ ui64 CCreatureSet::getPower (SlotID slot) const { return getStack(slot).getPower(); } + std::string CCreatureSet::getRoughAmount (SlotID slot) const { int quantity = CCreature::getQuantityID(getStackCount(slot)); diff --git a/lib/CGameInfoCallback.cpp b/lib/CGameInfoCallback.cpp index eb62696ff..2f249dec8 100644 --- a/lib/CGameInfoCallback.cpp +++ b/lib/CGameInfoCallback.cpp @@ -16,6 +16,7 @@ #include "StartInfo.h" // for StartInfo #include "BattleState.h" // for BattleInfo #include "NetPacks.h" // for InfoWindow +#include "CModHandler.h" //TODO make clean #define ERROR_VERBOSE_OR_NOT_RET_VAL_IF(cond, verbose, txt, retVal) do {if(cond){if(verbose)logGlobal->errorStream() << BOOST_CURRENT_FUNCTION << ": " << txt; return retVal;}} while(0) @@ -260,18 +261,6 @@ int CGameInfoCallback::getDate(Date::EDateType mode) const //boost::shared_lock lock(*gs->mx); return gs->getDate(mode); } -std::vector < std::string > CGameInfoCallback::getObjDescriptions(int3 pos) const -{ - //boost::shared_lock lock(*gs->mx); - std::vector ret; - const TerrainTile *t = getTile(pos); - ERROR_RET_VAL_IF(!t, "Not a valid tile given!", ret); - - - for(const CGObjectInstance * obj : t->blockingObjects) - ret.push_back(obj->getHoverText()); - return ret; -} bool CGameInfoCallback::isVisible(int3 pos, boost::optional Player) const { diff --git a/lib/CGameInfoCallback.h b/lib/CGameInfoCallback.h index aeade6a56..ae740b29d 100644 --- a/lib/CGameInfoCallback.h +++ b/lib/CGameInfoCallback.h @@ -83,7 +83,6 @@ public: std::vector getVisitableObjs(int3 pos, bool verbose = true)const; std::vector getFlaggableObjects(int3 pos) const; const CGObjectInstance * getTopObj (int3 pos) const; - std::vector getObjDescriptions(int3 pos)const; //returns descriptions of objects at pos in order from the lowest to the highest PlayerColor getOwner(ObjectInstanceID heroID) const; const CGObjectInstance *getObjByQuestIdentifier(int identifier) const; //nullptr if object has been removed (eg. killed) diff --git a/lib/CGameState.cpp b/lib/CGameState.cpp index 45b1510a0..031082994 100644 --- a/lib/CGameState.cpp +++ b/lib/CGameState.cpp @@ -256,7 +256,7 @@ DLL_LINKAGE void MetaString::toString(std::string &dst) const boost::replace_first(dst, "%+d", '+' + boost::lexical_cast(numbers[nums++])); break; default: - logGlobal->errorStream() << "MetaString processing error!"; + logGlobal->errorStream() << "MetaString processing error! Received message of type " << int(elem); break; } } @@ -313,7 +313,7 @@ DLL_LINKAGE std::string MetaString::buildList () const lista.replace (lista.find("%d"), 2, boost::lexical_cast(numbers[nums++])); break; default: - logGlobal->errorStream() << "MetaString processing error!"; + logGlobal->errorStream() << "MetaString processing error! Received message of type " << int(message[i]); } } @@ -1053,7 +1053,6 @@ void CGameState::randomizeMapObjects() if(!obj) continue; randomizeObject(obj); - obj->hoverName = VLC->objtypeh->getObjectName(obj->ID); //handle Favouring Winds - mark tiles under it if(obj->ID == Obj::FAVORABLE_WINDS) @@ -1637,7 +1636,7 @@ void CGameState::initFogOfWar() if(!obj || !vstd::contains(elem.second.players, obj->tempOwner)) continue; //not a flagged object std::unordered_set tiles; - obj->getSightTiles(tiles); + getTilesInRange(tiles, obj->getSightCenter(), obj->getSightRadious(), obj->tempOwner, 1); for(int3 tile : tiles) { elem.second.fogOfWarMap[tile.x][tile.y][tile.z] = 1; @@ -1900,6 +1899,13 @@ void CGameState::initVisitingAndGarrisonedHeroes() } } } + for (auto hero : map->heroesOnMap) + { + if (hero->visitedTown) + { + assert (hero->visitedTown->visitingHero == hero); + } + } } BFieldType CGameState::battleGetBattlefieldType(int3 tile) @@ -2980,7 +2986,7 @@ void InfoAboutArmy::initFromArmy(const CArmedInstance *Army, bool detailed) { army = ArmyDescriptor(Army, detailed); owner = Army->tempOwner; - name = Army->getHoverText(); + name = Army->getObjectName(); } void InfoAboutHero::assign(const InfoAboutHero & iah) @@ -3510,59 +3516,6 @@ CPathfinder::CPathfinder(CPathsInfo &_out, CGameState *_gs, const CGHeroInstance allowEmbarkAndDisembark = true; } -EVictoryLossCheckResult::EVictoryLossCheckResult() : - intValue(0) -{ -} - -EVictoryLossCheckResult::EVictoryLossCheckResult(si32 intValue, std::string toSelf, std::string toOthers) : - messageToSelf(toSelf), - messageToOthers(toOthers), - intValue(intValue) -{ -} - -bool EVictoryLossCheckResult::operator==(EVictoryLossCheckResult const & other) const -{ - return intValue == other.intValue; -} - -bool EVictoryLossCheckResult::operator!=(EVictoryLossCheckResult const & other) const -{ - return intValue != other.intValue; -} - -bool EVictoryLossCheckResult::victory() const -{ - return intValue == VICTORY; -} - -bool EVictoryLossCheckResult::loss() const -{ - return intValue == DEFEAT; -} - -EVictoryLossCheckResult EVictoryLossCheckResult::invert() -{ - return EVictoryLossCheckResult(-intValue, messageToOthers, messageToSelf); -} - -EVictoryLossCheckResult EVictoryLossCheckResult::victory(std::string toSelf, std::string toOthers) -{ - return EVictoryLossCheckResult(VICTORY, toSelf, toOthers); -} - -EVictoryLossCheckResult EVictoryLossCheckResult::defeat(std::string toSelf, std::string toOthers) -{ - return EVictoryLossCheckResult(DEFEAT, toSelf, toOthers); -} - -std::ostream & operator<<(std::ostream & os, const EVictoryLossCheckResult & victoryLossCheckResult) -{ - os << victoryLossCheckResult.messageToSelf; - return os; -} - CRandomGenerator & CGameState::getRandomGenerator() { return rand; diff --git a/lib/CGameState.h b/lib/CGameState.h index 0d8a8c8f2..222e9ce76 100644 --- a/lib/CGameState.h +++ b/lib/CGameState.h @@ -15,6 +15,7 @@ #include "ResourceSet.h" #include "int3.h" #include "CRandomGenerator.h" +#include "CGameStateFwd.h" /* * CGameState.h, part of VCMI engine @@ -355,39 +356,6 @@ public: struct BattleInfo; -class DLL_LINKAGE EVictoryLossCheckResult -{ -public: - static EVictoryLossCheckResult victory(std::string toSelf, std::string toOthers); - static EVictoryLossCheckResult defeat(std::string toSelf, std::string toOthers); - - EVictoryLossCheckResult(); - bool operator==(EVictoryLossCheckResult const & other) const; - bool operator!=(EVictoryLossCheckResult const & other) const; - bool victory() const; - bool loss() const; - - EVictoryLossCheckResult invert(); - - std::string messageToSelf; - std::string messageToOthers; - - template void serialize(Handler &h, const int version) - { - h & intValue & messageToSelf & messageToOthers; - } -private: - enum EResult - { - DEFEAT = -1, - INGAME = 0, - VICTORY= +1 - }; - - EVictoryLossCheckResult(si32 intValue, std::string toSelf, std::string toOthers); - si32 intValue; // uses EResult -}; - DLL_LINKAGE std::ostream & operator<<(std::ostream & os, const EVictoryLossCheckResult & victoryLossCheckResult); class DLL_LINKAGE CGameState : public CNonConstInfoCallback @@ -533,35 +501,3 @@ private: friend class CMapHandler; friend class CGameHandler; }; - -struct DLL_LINKAGE QuestInfo //universal interface for human and AI -{ - const CQuest * quest; - const CGObjectInstance * obj; //related object, most likely Seer Hut - int3 tile; - - QuestInfo(){}; - QuestInfo (const CQuest * Quest, const CGObjectInstance * Obj, int3 Tile) : - quest (Quest), obj (Obj), tile (Tile){}; - - //FIXME: assignment operator should return QuestInfo & - bool operator= (const QuestInfo &qi) - { - quest = qi.quest; - obj = qi.obj; - tile = qi.tile; - return true; - } - - bool operator== (const QuestInfo & qi) const - { - return (quest == qi.quest && obj == qi.obj); - } - - //std::vector > texts //allow additional info for quest log? - - template void serialize(Handler &h, const int version) - { - h & quest & obj & tile; - } -}; diff --git a/lib/CGameStateFwd.h b/lib/CGameStateFwd.h new file mode 100644 index 000000000..b284373e3 --- /dev/null +++ b/lib/CGameStateFwd.h @@ -0,0 +1,120 @@ +#pragma once + +/* + * CGameStateFwd.h, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ + +class CQuest; +class CGObjectInstance; + +class DLL_LINKAGE EVictoryLossCheckResult +{ +public: + static EVictoryLossCheckResult victory(std::string toSelf, std::string toOthers) + { + return EVictoryLossCheckResult(VICTORY, toSelf, toOthers); + } + + static EVictoryLossCheckResult defeat(std::string toSelf, std::string toOthers) + { + return EVictoryLossCheckResult(DEFEAT, toSelf, toOthers); + } + + EVictoryLossCheckResult(): + intValue(0) + { + } + + bool operator==(EVictoryLossCheckResult const & other) const + { + return intValue == other.intValue; + } + + bool operator!=(EVictoryLossCheckResult const & other) const + { + return intValue != other.intValue; + } + + bool victory() const + { + return intValue == VICTORY; + } + bool loss() const + { + return intValue == DEFEAT; + } + + EVictoryLossCheckResult invert() + { + return EVictoryLossCheckResult(-intValue, messageToOthers, messageToSelf); + } + + std::string messageToSelf; + std::string messageToOthers; + + template void serialize(Handler &h, const int version) + { + h & intValue & messageToSelf & messageToOthers; + } +private: + enum EResult + { + DEFEAT = -1, + INGAME = 0, + VICTORY= +1 + }; + + EVictoryLossCheckResult(si32 intValue, std::string toSelf, std::string toOthers): + messageToSelf(toSelf), + messageToOthers(toOthers), + intValue(intValue) + { + } + + si32 intValue; // uses EResult +}; + +/*static std::ostream & operator<<(std::ostream & os, const EVictoryLossCheckResult & victoryLossCheckResult) +{ + os << victoryLossCheckResult.messageToSelf; + return os; +}*/ + +struct DLL_LINKAGE QuestInfo //universal interface for human and AI +{ + const CQuest * quest; + const CGObjectInstance * obj; //related object, most likely Seer Hut + int3 tile; + + QuestInfo(){}; + QuestInfo (const CQuest * Quest, const CGObjectInstance * Obj, int3 Tile) : + quest (Quest), obj (Obj), tile (Tile){}; + + //FIXME: assignment operator should return QuestInfo & + bool operator= (const QuestInfo &qi) + { + quest = qi.quest; + obj = qi.obj; + tile = qi.tile; + return true; + } + + bool operator== (const QuestInfo & qi) const + { + return (quest == qi.quest && obj == qi.obj); + } + + //std::vector > texts //allow additional info for quest log? + + template void serialize(Handler &h, const int version) + { + h & quest & obj & tile; + } +}; + diff --git a/lib/CHeroHandler.cpp b/lib/CHeroHandler.cpp index 1a8414dbd..25c43d4a4 100644 --- a/lib/CHeroHandler.cpp +++ b/lib/CHeroHandler.cpp @@ -199,7 +199,7 @@ void CHeroClassHandler::loadObject(std::string scope, std::string name, const Js VLC->modh->identifiers.requestIdentifier(scope, "object", "hero", [=](si32 index) { - JsonNode classConf; + JsonNode classConf = data["mapObject"]; classConf["heroClass"].String() = name; classConf.setMeta(scope); VLC->objtypeh->loadSubObject(name, classConf, index, object->id); diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index f426a13a6..62764080e 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -82,6 +82,7 @@ set(lib_SRCS ResourceSet.cpp VCMI_Lib.cpp VCMIDirs.cpp + IHandlerBase.cpp IGameCallback.cpp CGameInfoCallback.cpp @@ -118,8 +119,8 @@ set(lib_HEADERS GameConstants.h StringConstants.h IGameEventsReceiver.h - IHandlerBase.h int3.h + CGameStateFwd.h Interprocess.h NetPacks.h NetPacksBase.h diff --git a/lib/CModHandler.cpp b/lib/CModHandler.cpp index 9cd4b8072..9f5422566 100644 --- a/lib/CModHandler.cpp +++ b/lib/CModHandler.cpp @@ -310,6 +310,7 @@ bool CContentHandler::ContentTypeHandler::preloadModData(std::string modName, st if (remoteName == modName) logGlobal->warnStream() << "Redundant namespace definition for " << objectName; + logGlobal->traceStream() << "Patching object " << objectName << " (" << remoteName << ") from " << modName; JsonNode & remoteConf = modData[remoteName].patches[objectName]; JsonUtils::merge(remoteConf, entry.second); diff --git a/lib/CTownHandler.cpp b/lib/CTownHandler.cpp index a31d0a65e..edb3e92b9 100644 --- a/lib/CTownHandler.cpp +++ b/lib/CTownHandler.cpp @@ -688,7 +688,19 @@ void CTownHandler::loadObject(std::string scope, std::string name, const JsonNod JsonNode config = data["town"]["mapObject"]; config["faction"].String() = object->identifier; config["faction"].meta = scope; + if (config.meta.empty())// MODS COMPATIBILITY FOR 0.96 + config.meta = scope; VLC->objtypeh->loadSubObject(object->identifier, config, index, object->index); + + // MODS COMPATIBILITY FOR 0.96 + auto & advMap = data["town"]["adventureMap"]; + if (!advMap.isNull()) + { + logGlobal->warnStream() << "Outdated town mod. Will try to generate valid templates out of fort"; + JsonNode config; + config["animation"] = advMap["castle"]; + VLC->objtypeh->getHandlerFor(index, object->index)->addTemplate(config); + } }); } @@ -717,15 +729,6 @@ void CTownHandler::loadObject(std::string scope, std::string name, const JsonNod config["faction"].String() = object->identifier; config["faction"].meta = scope; VLC->objtypeh->loadSubObject(object->identifier, config, index, object->index); - - // MODS COMPATIBILITY FOR 0.96 - auto & advMap = data["town"]["adventureMap"]; - if (!advMap["fort"].isNull()) - { - JsonNode config; - config["appearance"] = advMap["fort"]; - VLC->objtypeh->getHandlerFor(index, object->index)->addTemplate(config); - } }); } diff --git a/lib/Connection.h b/lib/Connection.h index cfb51deb8..2b976d26b 100644 --- a/lib/Connection.h +++ b/lib/Connection.h @@ -27,7 +27,7 @@ #include "mapping/CCampaignHandler.h" //for CCampaignState #include "rmg/CMapGenerator.h" // for CMapGenOptions -const ui32 version = 749; +const ui32 version = 750; const ui32 minSupportedVersion = version; class CConnection; diff --git a/lib/GameConstants.h b/lib/GameConstants.h index 62f483114..386600c89 100644 --- a/lib/GameConstants.h +++ b/lib/GameConstants.h @@ -14,7 +14,7 @@ namespace GameConstants { - const std::string VCMI_VERSION = "VCMI 0.95b"; + const std::string VCMI_VERSION = "VCMI 0.96"; const int BFIELD_WIDTH = 17; const int BFIELD_HEIGHT = 11; diff --git a/lib/IGameCallback.cpp b/lib/IGameCallback.cpp index 98bcf2c4a..7712b192b 100644 --- a/lib/IGameCallback.cpp +++ b/lib/IGameCallback.cpp @@ -15,9 +15,12 @@ #include "CSpellHandler.h" // for CSpell #include "NetPacks.h" #include "CBonusTypeHandler.h" +#include "CModHandler.h" #include "Connection.h" // for SAVEGAME_MAGIC #include "mapObjects/CObjectClassesHandler.h" +#include "StartInfo.h" +#include "CGameState.h" void CPrivilagedInfoCallback::getFreeTiles (std::vector &tiles) const { diff --git a/lib/IGameCallback.h b/lib/IGameCallback.h index e6183e2b2..abbb5d64b 100644 --- a/lib/IGameCallback.h +++ b/lib/IGameCallback.h @@ -48,7 +48,6 @@ public: virtual bool removeObject(const CGObjectInstance * obj)=0; virtual void setBlockVis(ObjectInstanceID objid, bool bv)=0; virtual void setOwner(const CGObjectInstance * objid, PlayerColor owner)=0; - virtual void setHoverName(const CGObjectInstance * obj, MetaString * name)=0; virtual void changePrimSkill(const CGHeroInstance * hero, PrimarySkill::PrimarySkill which, si64 val, bool abs=false)=0; virtual void changeSecSkill(const CGHeroInstance * hero, SecondarySkill which, int val, bool abs=false)=0; virtual void showBlockingDialog(BlockingDialog *iw) =0; @@ -93,6 +92,8 @@ public: virtual void sendAndApply(CPackForClient * info)=0; virtual void heroExchange(ObjectInstanceID hero1, ObjectInstanceID hero2)=0; //when two heroes meet on adventure map virtual void addQuest(int player, QuestInfo & quest){}; + virtual void changeFogOfWar(int3 center, ui32 radius, PlayerColor player, bool hide) = 0; + virtual void changeFogOfWar(std::unordered_set &tiles, PlayerColor player, bool hide) = 0; }; class DLL_LINKAGE CNonConstInfoCallback : public CPrivilagedInfoCallback diff --git a/lib/IHandlerBase.cpp b/lib/IHandlerBase.cpp new file mode 100644 index 000000000..bddbae3ba --- /dev/null +++ b/lib/IHandlerBase.cpp @@ -0,0 +1,19 @@ +/* + * IHandlerBase.cpp, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ + +#include "StdInc.h" +#include "IHandlerBase.h" +#include "CModHandler.h" + + +void IHandlerBase::registerObject(std::string scope, std::string type_name, std::string name, si32 index) +{ + return VLC->modh->identifiers.registerObject(scope, type_name, name, index); +} diff --git a/lib/IHandlerBase.h b/lib/IHandlerBase.h index 2ae74235e..c26b6f944 100644 --- a/lib/IHandlerBase.h +++ b/lib/IHandlerBase.h @@ -11,7 +11,7 @@ */ #include "../lib/ConstTransitivePtr.h" #include "VCMI_Lib.h" - #include "CModHandler.h" + //#include "CModHandler.h" class JsonNode; @@ -22,6 +22,9 @@ class DLL_LINKAGE IHandlerBase // Object * loadFromJson(const JsonNode & json); // where Object is type of data loaded by handler // primary used in loadObject methods +protected: + /// Calls modhandler. Mostly needed to avoid large number of includes in headers + void registerObject(std::string scope, std::string type_name, std::string name, si32 index); public: /// loads all original game data in vector of json nodes @@ -48,7 +51,6 @@ public: virtual ~IHandlerBase(){} }; - template class CHandlerBase: public IHandlerBase { public: @@ -68,7 +70,7 @@ public: objects.push_back(object); - VLC->modh->identifiers.registerObject(scope, type_name, name, object->id); + registerObject(scope, type_name, name, object->id); } void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override { @@ -80,7 +82,7 @@ public: assert(objects[index] == nullptr); // ensure that this id was not loaded before objects[index] = object; - VLC->modh->identifiers.registerObject(scope,type_name, name, object->id); + registerObject(scope,type_name, name, object->id); } diff --git a/lib/NetPacks.h b/lib/NetPacks.h index 0ed966ad4..97639cf12 100644 --- a/lib/NetPacks.h +++ b/lib/NetPacks.h @@ -3,16 +3,18 @@ #include "NetPacksBase.h" #include "BattleAction.h" -#include "HeroBonus.h" +//#include "HeroBonus.h" #include "mapObjects/CGHeroInstance.h" -#include "CCreatureSet.h" -#include "mapping/CMapInfo.h" -#include "StartInfo.h" +//#include "CCreatureSet.h" +//#include "mapping/CMapInfo.h" +//#include "StartInfo.h" #include "ConstTransitivePtr.h" #include "int3.h" #include "ResourceSet.h" +//#include "CObstacleInstance.h" +#include "CGameStateFwd.h" +#include "mapping/CMap.h" #include "CObstacleInstance.h" -#include "CGameState.h" /* * NetPacks.h, part of VCMI engine @@ -37,7 +39,8 @@ class CArtifactInstance; struct StackLocation; struct ArtSlotInfo; struct QuestInfo; - +class CMapInfo; +class StartInfo; struct CPackForClient : public CPack @@ -1046,21 +1049,6 @@ struct SetObjectProperty : public CPackForClient//1001 } }; -struct SetHoverName : public CPackForClient//1002 -{ - DLL_LINKAGE void applyGs(CGameState *gs); - - ObjectInstanceID id; - MetaString name; - SetHoverName(){type = 1002;} - SetHoverName(ObjectInstanceID ID, MetaString& Name):id(ID),name(Name){type = 1002;} - - template void serialize(Handler &h, const int version) - { - h & id & name; - } -}; - struct ChangeObjectVisitors : public CPackForClient // 1003 { enum VisitMode @@ -1528,7 +1516,8 @@ struct ObstaclesRemoved : public CPackForClient //3014 } }; -struct CatapultAttack : public CPackForClient //3015 +struct ELF_VISIBILITY CatapultAttack : public CPackForClient //3015 + { struct AttackInfo { @@ -2137,26 +2126,14 @@ struct PlayerJoined : public CPregamePackToHost } }; -struct SelectMap : public CPregamePackToPropagate +struct ELF_VISIBILITY SelectMap : public CPregamePackToPropagate { const CMapInfo *mapInfo; - bool free; + bool free;//local flag, do not serialize - SelectMap(const CMapInfo &src) - { - mapInfo = &src; - free = false; - } - SelectMap() - { - mapInfo = nullptr; - free = true; - } - ~SelectMap() - { - if(free) - delete mapInfo; - } + DLL_LINKAGE SelectMap(const CMapInfo &src); + DLL_LINKAGE SelectMap(); + DLL_LINKAGE ~SelectMap(); void apply(CSelectionScreen *selScreen); //that functions are implemented in CPreGame.cpp @@ -2167,28 +2144,16 @@ struct SelectMap : public CPregamePackToPropagate }; -struct UpdateStartOptions : public CPregamePackToPropagate +struct ELF_VISIBILITY UpdateStartOptions : public CPregamePackToPropagate { StartInfo *options; - bool free; + bool free;//local flag, do not serialize void apply(CSelectionScreen *selScreen); //that functions are implemented in CPreGame.cpp - UpdateStartOptions(StartInfo &src) - { - options = &src; - free = false; - } - UpdateStartOptions() - { - options = nullptr; - free = true; - } - ~UpdateStartOptions() - { - if(free) - delete options; - } + DLL_LINKAGE UpdateStartOptions(StartInfo &src); + DLL_LINKAGE UpdateStartOptions(); + DLL_LINKAGE ~UpdateStartOptions(); template void serialize(Handler &h, const int version) { diff --git a/lib/NetPacksLib.cpp b/lib/NetPacksLib.cpp index 50df1a5a9..c2f0ef924 100644 --- a/lib/NetPacksLib.cpp +++ b/lib/NetPacksLib.cpp @@ -14,6 +14,8 @@ #include "CGameState.h" #include "BattleState.h" #include "CTownHandler.h" +#include "mapping/CMapInfo.h" +#include "StartInfo.h" /* * NetPacksLib.cpp, part of VCMI engine @@ -60,6 +62,41 @@ DLL_LINKAGE void SetSecSkill::applyGs( CGameState *gs ) hero->setSecSkillLevel(which, val, abs); } + +DLL_LINKAGE SelectMap::SelectMap(const CMapInfo &src) +{ + mapInfo = &src; + free = false; +} +DLL_LINKAGE SelectMap::SelectMap() +{ + mapInfo = nullptr; + free = true; +} + +DLL_LINKAGE SelectMap::~SelectMap() +{ + if(free) + delete mapInfo; +} + +DLL_LINKAGE UpdateStartOptions::UpdateStartOptions(StartInfo &src) +{ + options = &src; + free = false; +} +DLL_LINKAGE UpdateStartOptions::UpdateStartOptions() +{ + options = nullptr; + free = true; +} + +DLL_LINKAGE UpdateStartOptions::~UpdateStartOptions() +{ + if(free) + delete options; +} + DLL_LINKAGE void SetCommanderProperty::applyGs(CGameState *gs) { CCommanderInstance * commander = gs->getHero(heroid)->commander; @@ -126,6 +163,7 @@ DLL_LINKAGE void HeroVisitCastle::applyGs( CGameState *gs ) assert(h); assert(t); + if(start()) t->setVisitingHero(h); else @@ -177,7 +215,7 @@ DLL_LINKAGE void FoWChange::applyGs( CGameState *gs ) case Obj::TOWN: case Obj::ABANDONED_MINE: if(vstd::contains(team->players, o->tempOwner)) //check owned observators - o->getSightTiles(tilesRevealed); + gs->getTilesInRange(tiles, o->getSightCenter(), o->getSightRadious(), o->tempOwner, 1); break; } } @@ -302,7 +340,7 @@ DLL_LINKAGE void RemoveObject::applyGs( CGameState *gs ) { CGObjectInstance *obj = gs->getObjInstance(id); - logGlobal->debugStream() << "removing object id=" << id << "; address=" << (intptr_t)obj << "; name=" << obj->getHoverText(); + logGlobal->debugStream() << "removing object id=" << id << "; address=" << (intptr_t)obj << "; name=" << obj->getObjectName(); //unblock tiles gs->map->removeBlockVisTiles(obj); @@ -608,14 +646,13 @@ DLL_LINKAGE void NewObject::applyGs( CGameState *gs ) const TerrainTile &t = gs->map->getTile(pos); o->appearance = VLC->objtypeh->getHandlerFor(o->ID, o->subID)->getTemplates(t.terType).front(); id = o->id = ObjectInstanceID(gs->map->objects.size()); - o->hoverName = VLC->objtypeh->getObjectName(ID); gs->map->objects.push_back(o); gs->map->addBlockVisTiles(o); o->initObj(); gs->map->calculateGuardingGreaturePositions(); - logGlobal->debugStream() << "added object id=" << id << "; address=" << (intptr_t)o << "; name=" << o->getHoverText(); + logGlobal->debugStream() << "added object id=" << id << "; address=" << (intptr_t)o << "; name=" << o->getObjectName(); } DLL_LINKAGE void NewArtifact::applyGs( CGameState *gs ) @@ -1012,11 +1049,6 @@ DLL_LINKAGE void SetObjectProperty::applyGs( CGameState *gs ) } } -DLL_LINKAGE void SetHoverName::applyGs( CGameState *gs ) -{ - name.toString(gs->getObj(id)->hoverName); -} - DLL_LINKAGE void HeroLevelUp::applyGs( CGameState *gs ) { CGHeroInstance * h = gs->getHero(hero->id); @@ -1507,7 +1539,7 @@ DLL_LINKAGE CatapultAttack::~CatapultAttack() DLL_LINKAGE void CatapultAttack::applyGs( CGameState *gs ) { - if(gs->curB && gs->curB->siege != CGTownInstance::NONE) //if there is a battle and it's a siege + if(gs->curB && gs->curB->town && gs->curB->town->fortLevel() != CGTownInstance::NONE) //if there is a battle and it's a siege { for(const auto &it :attackedParts) { diff --git a/lib/VCMI_lib.cbp b/lib/VCMI_lib.cbp index 843390d99..5090a46b3 100644 --- a/lib/VCMI_lib.cbp +++ b/lib/VCMI_lib.cbp @@ -149,6 +149,7 @@ + @@ -169,6 +170,7 @@ + diff --git a/lib/VCMI_lib.vcxproj b/lib/VCMI_lib.vcxproj index 18e150ee1..5e7da453f 100644 --- a/lib/VCMI_lib.vcxproj +++ b/lib/VCMI_lib.vcxproj @@ -135,8 +135,7 @@ - /Oy- %(AdditionalOptions) /bigobj - /Zm150 + /Oy- /bigobj /Zm150 VCMI_DLL;%(PreprocessorDefinitions) StdInc.h Use @@ -177,13 +176,11 @@ - - @@ -202,8 +199,24 @@ + + + + + + + + + + + + + + + + @@ -216,6 +229,7 @@ + @@ -259,13 +273,12 @@ - + - @@ -293,6 +306,22 @@ + + + + + + + + + + + + + + + + diff --git a/lib/VCMI_lib.vcxproj.filters b/lib/VCMI_lib.vcxproj.filters index 4650865c0..9e1ec4ec5 100644 --- a/lib/VCMI_lib.vcxproj.filters +++ b/lib/VCMI_lib.vcxproj.filters @@ -23,6 +23,9 @@ {927d9b6e-3dc5-4370-b603-1b9887095509} + + {ee24c7f7-f4e2-4d35-b994-94a6e29ea92f} + @@ -30,10 +33,8 @@ - - @@ -157,6 +158,53 @@ + + mapObjects + + + mapObjects + + + mapObjects + + + mapObjects + + + mapObjects + + + mapObjects + + + mapObjects + + + mapObjects + + + mapObjects + + + mapObjects + + + mapObjects + + + mapObjects + + + mapObjects + + + mapObjects + + + mapObjects + + + @@ -201,18 +249,12 @@ Header Files - - Header Files - Header Files Header Files - - Header Files - Header Files @@ -399,5 +441,56 @@ rmg + + mapObjects + + + mapObjects + + + mapObjects + + + mapObjects + + + mapObjects + + + mapObjects + + + mapObjects + + + mapObjects + + + mapObjects + + + mapObjects + + + mapObjects + + + mapObjects + + + mapObjects + + + mapObjects + + + mapObjects + + + mapObjects + + + Header Files + \ No newline at end of file diff --git a/lib/int3.h b/lib/int3.h index b094654d8..41a8dd908 100644 --- a/lib/int3.h +++ b/lib/int3.h @@ -155,4 +155,22 @@ struct ShashInt3 }; static const int3 dirs[] = { int3(0,1,0),int3(0,-1,0),int3(-1,0,0),int3(+1,0,0), - int3(1,1,0),int3(-1,1,0),int3(1,-1,0),int3(-1,-1,0) }; \ No newline at end of file + int3(1,1,0),int3(-1,1,0),int3(1,-1,0),int3(-1,-1,0) }; + +//FIXME: make sure it's container and not just any +template +int3 findClosestTile (Container & container, int3 dest) +{ + int3 result(-1,-1,-1); + ui32 distance = std::numeric_limits::max(); + for (int3 tile : container) + { + ui32 currentDistance = dest.dist2dSQ(tile); + if (currentDistance < distance) + { + result = tile; + distance = currentDistance; + } + } + return result; +} \ No newline at end of file diff --git a/lib/mapObjects/CArmedInstance.cpp b/lib/mapObjects/CArmedInstance.cpp index 050c10f38..72be9775f 100644 --- a/lib/mapObjects/CArmedInstance.cpp +++ b/lib/mapObjects/CArmedInstance.cpp @@ -1,4 +1,4 @@ -/* +/* * CArmedInstance.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder diff --git a/lib/mapObjects/CArmedInstance.h b/lib/mapObjects/CArmedInstance.h index f85b8a07e..9b58332ca 100644 --- a/lib/mapObjects/CArmedInstance.h +++ b/lib/mapObjects/CArmedInstance.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "CObjectHandler.h" #include "../CCreatureSet.h" @@ -13,6 +13,9 @@ * */ +class BattleInfo; +class CGameState; + class DLL_LINKAGE CArmedInstance: public CGObjectInstance, public CBonusSystemNode, public CCreatureSet { public: diff --git a/lib/mapObjects/CBank.cpp b/lib/mapObjects/CBank.cpp index 8f4f52582..f80d740b9 100644 --- a/lib/mapObjects/CBank.cpp +++ b/lib/mapObjects/CBank.cpp @@ -1,4 +1,4 @@ -/* +/* * CBank.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder @@ -16,6 +16,8 @@ #include "../CSoundBase.h" #include "CommonConstructors.h" #include "../CSpellHandler.h" +#include "../IGameCallback.h" +#include "../CGameState.h" using namespace boost::assign; @@ -41,11 +43,10 @@ void CBank::initObj() VLC->objtypeh->getHandlerFor(ID, subID)->configureObject(this, cb->gameState()->getRandomGenerator()); } -const std::string & CBank::getHoverText() const +std::string CBank::getHoverText(PlayerColor player) const { - bool visited = (bc == nullptr); - hoverName = visitedTxt(visited); // FIXME: USE BANK_SPECIFIC NAMES - return hoverName; + // TODO: record visited players + return getObjectName() + " " + visitedTxt(bc == nullptr); } void CBank::setConfig(const BankConfig & config) @@ -125,8 +126,8 @@ void CBank::onHeroVisit (const CGHeroInstance * h) const bd.player = h->getOwner(); bd.soundID = soundID; bd.text.addTxt(MetaString::ADVOB_TXT, banktext); - //if (ID == Obj::CREATURE_BANK) - // bd.text.addReplacement(VLC->objh->creBanksNames[index]); // FIXME: USE BANK SPECIFIC NAMES + if (ID == Obj::CREATURE_BANK) + bd.text.addReplacement(getObjectName()); cb->showBlockingDialog (&bd); } else @@ -146,7 +147,7 @@ void CBank::onHeroVisit (const CGHeroInstance * h) const else { iw.text << VLC->generaltexth->advobtxt[33];// This was X, now is completely empty - //iw.text.addReplacement(VLC->objh->creBanksNames[index]); // FIXME: USE BANK SPECIFIC NAMES + iw.text.addReplacement(getObjectName()); } cb->showInfoDialog(&iw); } diff --git a/lib/mapObjects/CBank.h b/lib/mapObjects/CBank.h index c8f8471aa..cfecdf20c 100644 --- a/lib/mapObjects/CBank.h +++ b/lib/mapObjects/CBank.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "CObjectHandler.h" #include "CArmedInstance.h" @@ -32,7 +32,7 @@ public: void setConfig(const BankConfig & bc); void initObj() override; - const std::string & getHoverText() const override; + std::string getHoverText(PlayerColor player) const override; void newTurn() const override; bool wasVisited (PlayerColor player) const override; void onHeroVisit(const CGHeroInstance * h) const override; diff --git a/lib/mapObjects/CGHeroInstance.cpp b/lib/mapObjects/CGHeroInstance.cpp index 61e5da8c5..96a98826c 100644 --- a/lib/mapObjects/CGHeroInstance.cpp +++ b/lib/mapObjects/CGHeroInstance.cpp @@ -1,4 +1,4 @@ -/* +/* * CGHeroInstance.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder @@ -14,10 +14,13 @@ #include "../NetPacks.h" #include "../CGeneralTextHandler.h" #include "../CHeroHandler.h" +#include "../CModHandler.h" #include "../CSoundBase.h" #include "../CSpellHandler.h" #include "CObjectClassesHandler.h" - +#include "../IGameCallback.h" +#include "../CGameState.h" +#include "../CCreatureHandler.h" using namespace boost::assign; @@ -418,19 +421,17 @@ void CGHeroInstance::onHeroVisit(const CGHeroInstance * h) const } } -const std::string & CGHeroInstance::getHoverText() const +std::string CGHeroInstance::getObjectName() const { if(ID != Obj::PRISON) { - hoverName = VLC->generaltexth->allTexts[15]; + std::string hoverName = VLC->generaltexth->allTexts[15]; boost::algorithm::replace_first(hoverName,"%s",name); boost::algorithm::replace_first(hoverName,"%s", type->heroClass->name); return hoverName; } else - hoverName = VLC->objtypeh->getObjectName(ID); - - return hoverName; + return CGObjectInstance::getObjectName(); } const std::string & CGHeroInstance::getBiography() const @@ -472,9 +473,12 @@ void CGHeroInstance::initObj() skillsInfo.resetMagicSchoolCounter(); skillsInfo.resetWisdomCounter(); - auto customApp = VLC->objtypeh->getHandlerFor(ID, type->heroClass->id)->getOverride(cb->gameState()->getTile(visitablePos())->terType, this); - if (customApp) - appearance = customApp.get(); + if (ID != Obj::PRISON) + { + auto customApp = VLC->objtypeh->getHandlerFor(ID, type->heroClass->id)->getOverride(cb->gameState()->getTile(visitablePos())->terType, this); + if (customApp) + appearance = customApp.get(); + } for(const auto &spec : type->spec) //TODO: unfity with bonus system { @@ -999,11 +1003,11 @@ void CGHeroInstance::showNecromancyDialog(const CStackBasicDescriptor &raisedSta cb->showInfoDialog(&iw); } - +/* int3 CGHeroInstance::getSightCenter() const { return getPosition(false); -} +}*/ int CGHeroInstance::getSightRadious() const { diff --git a/lib/mapObjects/CGHeroInstance.h b/lib/mapObjects/CGHeroInstance.h index 327c0725b..87abc77c7 100644 --- a/lib/mapObjects/CGHeroInstance.h +++ b/lib/mapObjects/CGHeroInstance.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "CObjectHandler.h" #include "CArmedInstance.h" @@ -18,6 +18,8 @@ class CHero; class CGBoat; +class CGTownInstance; +class TerrainTile; class CGHeroPlaceholder : public CGObjectInstance { @@ -113,7 +115,7 @@ public: } } skillsInfo; - int3 getSightCenter() const; //"center" tile from which the sight distance is calculated + //int3 getSightCenter() const; //"center" tile from which the sight distance is calculated int getSightRadious() const; //sight distance (should be used if player-owned structure) ////////////////////////////////////////////////////////////////////////// @@ -205,7 +207,7 @@ public: void initObj() override; void onHeroVisit(const CGHeroInstance * h) const override; - const std::string & getHoverText() const override; + std::string getObjectName() const override; protected: void setPropertyDer(ui8 what, ui32 val) override;//synchr diff --git a/lib/mapObjects/CGMarket.cpp b/lib/mapObjects/CGMarket.cpp index 98205974e..13fdfea11 100644 --- a/lib/mapObjects/CGMarket.cpp +++ b/lib/mapObjects/CGMarket.cpp @@ -1,4 +1,4 @@ -/* +/* * * CGMarket.cpp, part of VCMI engine * @@ -14,6 +14,9 @@ #include "../NetPacks.h" #include "../CGeneralTextHandler.h" +#include "../IGameCallback.h" +#include "../CCreatureHandler.h" +#include "../CGameState.h" using namespace boost::assign; diff --git a/lib/mapObjects/CGMarket.h b/lib/mapObjects/CGMarket.h index 8f010a705..8858c3a66 100644 --- a/lib/mapObjects/CGMarket.h +++ b/lib/mapObjects/CGMarket.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "CObjectHandler.h" diff --git a/lib/mapObjects/CGPandoraBox.cpp b/lib/mapObjects/CGPandoraBox.cpp index 8f102e0a0..b4fa8c98d 100644 --- a/lib/mapObjects/CGPandoraBox.cpp +++ b/lib/mapObjects/CGPandoraBox.cpp @@ -1,4 +1,4 @@ -/* +/* * CGPandoraBox.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder @@ -15,6 +15,8 @@ #include "../CSoundBase.h" #include "../CSpellHandler.h" +#include "../StartInfo.h" +#include "../IGameCallback.h" using namespace boost::assign; diff --git a/lib/mapObjects/CGPandoraBox.h b/lib/mapObjects/CGPandoraBox.h index 227615cdf..c2ad87dde 100644 --- a/lib/mapObjects/CGPandoraBox.h +++ b/lib/mapObjects/CGPandoraBox.h @@ -1,7 +1,8 @@ -#pragma once +#pragma once #include "CObjectHandler.h" #include "CArmedInstance.h" +#include "../ResourceSet.h" /* * CGPandoraBox.h, part of VCMI engine @@ -13,6 +14,8 @@ * */ +class InfoWindow; + class DLL_LINKAGE CGPandoraBox : public CArmedInstance { public: diff --git a/lib/mapObjects/CGTownInstance.cpp b/lib/mapObjects/CGTownInstance.cpp index db903cbb9..3bff6cefa 100644 --- a/lib/mapObjects/CGTownInstance.cpp +++ b/lib/mapObjects/CGTownInstance.cpp @@ -1,4 +1,4 @@ -/* +/* * CGTownInstance.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder @@ -14,6 +14,9 @@ #include "../NetPacks.h" #include "../CGeneralTextHandler.h" +#include "../CModHandler.h" +#include "../IGameCallback.h" +#include "../CGameState.h" using namespace boost::assign; @@ -55,7 +58,7 @@ void CGDwelling::initObj() } } -void CGDwelling::setProperty(ui8 what, ui32 val) +void CGDwelling::setPropertyDer(ui8 what, ui32 val) { switch (what) { @@ -77,8 +80,8 @@ void CGDwelling::setProperty(ui8 what, ui32 val) creatures[0].second[0] = CreatureID(val); break; } - CGObjectInstance::setProperty(what,val); } + void CGDwelling::onHeroVisit( const CGHeroInstance * h ) const { if(ID == Obj::REFUGEE_CAMP && !creatures[0].first) //Refugee Camp, no available cres @@ -520,14 +523,25 @@ void CGTownInstance::onHeroVisit(const CGHeroInstance * h) const void CGTownInstance::onHeroLeave(const CGHeroInstance * h) const { - cb->stopHeroVisitCastle(this, h); + //FIXME: find out why this issue appears on random maps + if (visitingHero == h) + { + cb->stopHeroVisitCastle(this, h); + logGlobal->warnStream() << h->name << " correctly left town " << name; + } + else + logGlobal->warnStream() << "Warning, " << h->name << " tries to leave the town " << name << " but hero is not inside."; +} + +std::string CGTownInstance::getObjectName() const +{ + return name + ", " + town->faction->name; } void CGTownInstance::initObj() ///initialize town structures { blockVisit = true; - hoverName = name + ", " + town->faction->name; if (subID == ETownType::DUNGEON) creatures.resize(GameConstants::CREATURES_PER_TOWN+1);//extra dwelling for Dungeon @@ -644,25 +658,22 @@ void CGTownInstance::newTurn() const } } } - +/* int3 CGTownInstance::getSightCenter() const { return pos - int3(2,0,0); } - -ui8 CGTownInstance::getPassableness() const +*/ +bool CGTownInstance::passableFor(PlayerColor color) const { if (!armedGarrison())//empty castle - anyone can visit - return GameConstants::ALL_PLAYERS; + return true; if ( tempOwner == PlayerColor::NEUTRAL )//neutral guarded - no one can visit - return 0; + return false; - ui8 mask = 0; - TeamState * ts = cb->gameState()->getPlayerTeam(tempOwner); - for(PlayerColor it : ts->players) - mask |= 1<getPlayerRelations(tempOwner, color) != PlayerRelations::ENEMIES) + return true; + return false; } void CGTownInstance::getOutOffsets( std::vector &offsets ) const @@ -903,7 +914,13 @@ bool CGTownInstance::addBonusIfBuilt(BuildingID building, Bonus::BonusType type, void CGTownInstance::setVisitingHero(CGHeroInstance *h) { - assert(!!visitingHero == !h); + if (!(!!visitingHero == !h)) + { + logGlobal->warnStream() << boost::format("Hero visiting town %s is %s ") % name % (visitingHero.get() ? visitingHero->name : "NULL"); + logGlobal->warnStream() << boost::format("New hero will be %s ") % (h ? h->name : "NULL"); + assert(!!visitingHero == !h); + } + if(h) { PlayerState *p = cb->gameState()->getPlayer(h->tempOwner); @@ -1010,7 +1027,7 @@ void CGTownInstance::battleFinished(const CGHeroInstance *hero, const BattleResu FoWChange fw; fw.player = hero->tempOwner; fw.mode = 1; - getSightTiles (fw.tiles); //update visibility for castle structures + cb->getTilesInRange(fw.tiles, getSightCenter(), getSightRadious(), tempOwner, 1); cb->sendAndApply (&fw); } } diff --git a/lib/mapObjects/CGTownInstance.h b/lib/mapObjects/CGTownInstance.h index fda070a30..fd105365f 100644 --- a/lib/mapObjects/CGTownInstance.h +++ b/lib/mapObjects/CGTownInstance.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "CObjectHandler.h" #include "CGMarket.h" // For IMarket interface @@ -17,6 +17,7 @@ */ class CCastleEvent; +class CGTownInstance; class DLL_LINKAGE CSpecObjInfo { @@ -59,7 +60,7 @@ public: void initObj() override; void onHeroVisit(const CGHeroInstance * h) const override; void newTurn() const override; - void setProperty(ui8 what, ui32 val) override; + void setPropertyDer(ui8 what, ui32 val) override; void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override; void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override; @@ -200,8 +201,8 @@ public: ////////////////////////////////////////////////////////////////////////// - ui8 getPassableness() const; //bitmap - if the bit is set the corresponding player can pass through the visitable tiles of object, even if it's blockvis; if not set - default properties from definfo are used - int3 getSightCenter() const override; //"center" tile from which the sight distance is calculated + bool passableFor(PlayerColor color) const; + //int3 getSightCenter() const override; //"center" tile from which the sight distance is calculated int getSightRadious() const override; //returns sight distance int getBoatType() const; //0 - evil (if a ship can be evil...?), 1 - good, 2 - neutral void getOutOffsets(std::vector &offsets) const; //offsets to obj pos when we boat can be placed @@ -243,6 +244,7 @@ public: void onHeroLeave(const CGHeroInstance * h) const override; void initObj() override; void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override; + std::string getObjectName() const override; protected: void setPropertyDer(ui8 what, ui32 val) override; }; diff --git a/lib/mapObjects/CObjectClassesHandler.cpp b/lib/mapObjects/CObjectClassesHandler.cpp index 122068eb6..8c276e05a 100644 --- a/lib/mapObjects/CObjectClassesHandler.cpp +++ b/lib/mapObjects/CObjectClassesHandler.cpp @@ -1,9 +1,9 @@ -#include "StdInc.h" +#include "StdInc.h" #include "CObjectClassesHandler.h" #include "../filesystem/Filesystem.h" #include "../filesystem/CBinaryReader.h" -#include "../lib/VCMI_Lib.h" +#include "../VCMI_Lib.h" #include "../GameConstants.h" #include "../StringConstants.h" #include "../CGeneralTextHandler.h" @@ -40,6 +40,13 @@ CObjectClassesHandler::CObjectClassesHandler() SET_HANDLER_CLASS("static", CObstacleConstructor); SET_HANDLER_CLASS("", CObstacleConstructor); + SET_HANDLER("randomArtifact", CGArtifact); + SET_HANDLER("randomHero", CGHeroInstance); + SET_HANDLER("randomResource", CGResource); + SET_HANDLER("randomTown", CGTownInstance); + SET_HANDLER("randomMonster", CGCreature); + SET_HANDLER("randomDwelling", CGDwelling); + SET_HANDLER("generic", CGObjectInstance); SET_HANDLER("market", CGMarket); SET_HANDLER("cartographer", CCartographer); @@ -67,6 +74,7 @@ CObjectClassesHandler::CObjectClassesHandler() SET_HANDLER("pandora", CGPandoraBox); SET_HANDLER("pickable", CGPickable); SET_HANDLER("prison", CGHeroInstance); + SET_HANDLER("prison", CGHeroInstance); SET_HANDLER("questGuard", CGQuestGuard); SET_HANDLER("resource", CGResource); SET_HANDLER("scholar", CGScholar); @@ -109,6 +117,17 @@ std::vector CObjectClassesHandler::loadLegacyData(size_t dataSize) ret[i]["name"].String() = namesParser.readString(); namesParser.endLine(); } + + CLegacyConfigParser cregen1Parser("data/crgen1"); + do + customNames[Obj::CREATURE_GENERATOR1].push_back(cregen1Parser.readString()); + while(cregen1Parser.endLine()); + + CLegacyConfigParser cregen4Parser("data/crgen4"); + do + customNames[Obj::CREATURE_GENERATOR4].push_back(cregen4Parser.readString()); + while(cregen4Parser.endLine()); + return ret; } @@ -121,7 +140,7 @@ si32 selectNextID(const JsonNode & fixedID, const Map & map, si32 defaultID) if (map.empty()) return defaultID; // no objects loaded, keep gap for H3M objects - if (map.rbegin()->first > defaultID) + if (map.rbegin()->first >= defaultID) return map.rbegin()->first + 1; // some modded objects loaded, return next available return defaultID; // some H3M objects loaded, first modded found @@ -134,12 +153,16 @@ void CObjectClassesHandler::loadObjectEntry(const JsonNode & entry, ObjectContai logGlobal->errorStream() << "Handler with name " << obj->handlerName << " was not found!"; return; } - auto handler = handlerConstructors.at(obj->handlerName)(); - handler->init(entry); - si32 id = selectNextID(entry["index"], obj->objects, 1000); + + auto handler = handlerConstructors.at(obj->handlerName)(); handler->setType(obj->id, id); + if (customNames.count(obj->id) && customNames.at(obj->id).size() > id) + handler->init(entry, customNames.at(obj->id).at(id)); + else + handler->init(entry); + if (handler->getTemplates().empty()) { auto range = legacyTemplates.equal_range(std::make_pair(obj->id, id)); @@ -149,9 +172,10 @@ void CObjectClassesHandler::loadObjectEntry(const JsonNode & entry, ObjectContai } legacyTemplates.erase(range.first, range.second); } - - obj->objects[id] = handler; + logGlobal->debugStream() << "Loaded object " << obj->id << ":" << id; + assert(!obj->objects.count(id)); // DO NOT override + obj->objects[id] = handler; } CObjectClassesHandler::ObjectContainter * CObjectClassesHandler::loadFromJson(const JsonNode & json) @@ -200,6 +224,7 @@ void CObjectClassesHandler::loadSubObject(std::string name, JsonNode config, si3 std::string oldMeta = config.meta; // FIXME: move into inheritNode? JsonUtils::inherit(config, objects.at(ID)->base); config.setMeta(oldMeta); + loadObjectEntry(config, objects[ID]); } @@ -276,8 +301,21 @@ void CObjectClassesHandler::afterLoadFinalization() std::string CObjectClassesHandler::getObjectName(si32 type) const { - assert(objects.count(type)); - return objects.at(type)->name; + if (objects.count(type)) + return objects.at(type)->name; + logGlobal->errorStream() << "Access to non existing object of type " << type; + return ""; +} + +std::string CObjectClassesHandler::getObjectName(si32 type, si32 subtype) const +{ + if (knownSubObjects(type).count(subtype)) + { + auto name = getHandlerFor(type, subtype)->getCustomName(); + if (name) + return name.get(); + } + return getObjectName(type); } void AObjectTypeHandler::setType(si32 type, si32 subtype) @@ -294,7 +332,7 @@ static ui32 loadJsonOrMax(const JsonNode & input) return input.Float(); } -void AObjectTypeHandler::init(const JsonNode & input) +void AObjectTypeHandler::init(const JsonNode & input, boost::optional name) { base = input["base"]; @@ -318,6 +356,12 @@ void AObjectTypeHandler::init(const JsonNode & input) tmpl.readJson(entry.second); templates.push_back(tmpl); } + + if (input["name"].isNull()) + objectName = name; + else + objectName.reset(input["name"].String()); + initTypeData(input); } @@ -328,6 +372,12 @@ bool AObjectTypeHandler::objectFilter(const CGObjectInstance *, const ObjectTemp void AObjectTypeHandler::initTypeData(const JsonNode & input) { + // empty implementation for overrides +} + +boost::optional AObjectTypeHandler::getCustomName() const +{ + return objectName; } void AObjectTypeHandler::addTemplate(ObjectTemplate templ) diff --git a/lib/mapObjects/CObjectClassesHandler.h b/lib/mapObjects/CObjectClassesHandler.h index 95b32fc49..30a4ef88f 100644 --- a/lib/mapObjects/CObjectClassesHandler.h +++ b/lib/mapObjects/CObjectClassesHandler.h @@ -1,10 +1,11 @@ -#pragma once +#pragma once #include "ObjectTemplate.h" #include "../GameConstants.h" #include "../ConstTransitivePtr.h" #include "../IHandlerBase.h" +#include "../JsonNode.h" /* * CObjectClassesHandler.h, part of VCMI engine @@ -20,7 +21,7 @@ class JsonNode; class CRandomGenerator; /// Structure that describes placement rules for this object in random map -struct RandomMapInfo +struct DLL_LINKAGE RandomMapInfo { /// How valuable this object is, 1k = worthless, 10k = Utopia-level ui32 value; @@ -47,7 +48,7 @@ struct RandomMapInfo } }; -class IObjectInfo +class DLL_LINKAGE IObjectInfo { public: struct CArmyStructure @@ -64,7 +65,7 @@ public: walkersStrength(0) {} - bool operator <(const CArmyStructure & other) + bool operator <(const CArmyStructure & other) const { return this->totalStrength < other.totalStrength; } @@ -97,6 +98,9 @@ class DLL_LINKAGE AObjectTypeHandler : public boost::noncopyable { RandomMapInfo rmgInfo; + /// Human-readable name of this object, used for objects like banks and dwellings, if set + boost::optional objectName; + si32 type; si32 subtype; @@ -115,7 +119,10 @@ public: void setType(si32 type, si32 subtype); /// loads generic data from Json structure and passes it towards type-specific constructors - void init(const JsonNode & input); + void init(const JsonNode & input, boost::optional name = boost::optional()); + + /// Returns object-specific name, if set + boost::optional getCustomName() const; void addTemplate(ObjectTemplate templ); void addTemplate(JsonNode config); @@ -147,7 +154,7 @@ public: template void serialize(Handler &h, const int version) { - h & type & subtype & templates & rmgInfo; + h & type & subtype & templates & rmgInfo & objectName; } }; @@ -173,8 +180,6 @@ class DLL_LINKAGE CObjectClassesHandler : public IHandlerBase } }; - typedef std::multimap, ObjectTemplate> TTemplatesContainer; - /// list of object handlers, each of them handles only one type std::map objects; @@ -182,8 +187,13 @@ class DLL_LINKAGE CObjectClassesHandler : public IHandlerBase std::map > handlerConstructors; /// container with H3 templates, used only during loading, no need to serialize it + typedef std::multimap, ObjectTemplate> TTemplatesContainer; TTemplatesContainer legacyTemplates; + /// contains list of custom names for H3 objects (e.g. Dwellings), used to load H3 data + /// format: customNames[primaryID][secondaryID] -> name + std::map> customNames; + void loadObjectEntry(const JsonNode & entry, ObjectContainter * obj); ObjectContainter * loadFromJson(const JsonNode & json); public: @@ -210,6 +220,7 @@ public: TObjectTypeHandler getHandlerFor(si32 type, si32 subtype) const; std::string getObjectName(si32 type) const; + std::string getObjectName(si32 type, si32 subtype) const; template void serialize(Handler &h, const int version) { diff --git a/lib/mapObjects/CObjectHandler.cpp b/lib/mapObjects/CObjectHandler.cpp index bdc06a286..eea0b1b5a 100644 --- a/lib/mapObjects/CObjectHandler.cpp +++ b/lib/mapObjects/CObjectHandler.cpp @@ -1,4 +1,4 @@ -/* +/* * CObjectHandler.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder @@ -15,6 +15,9 @@ #include "../CGeneralTextHandler.h" #include "../CHeroHandler.h" #include "../CSoundBase.h" +#include "../filesystem/ResourceID.h" +#include "../IGameCallback.h" +#include "../CGameState.h" #include "CObjectClassesHandler.h" @@ -53,12 +56,6 @@ static void showInfoDialog(const CGHeroInstance* h, const ui32 txtID, const ui16 showInfoDialog(playerID,txtID,soundID); } -static std::string & visitedTxt(const bool visited) -{ - int id = visited ? 352 : 353; - return VLC->generaltexth->allTexts[id]; -} - ///IObjectInterface void IObjectInterface::onHeroVisit(const CGHeroInstance * h) const {} @@ -137,21 +134,11 @@ CGObjectInstance::CGObjectInstance(): } CGObjectInstance::~CGObjectInstance() { - //if (state) - // delete state; - //state=nullptr; } -const std::string & CGObjectInstance::getHoverText() const -{ - return hoverName; -} void CGObjectInstance::setOwner(PlayerColor ow) { - //if (state) - // state->owner = ow; - //else - tempOwner = ow; + tempOwner = ow; } int CGObjectInstance::getWidth() const//returns width of object graphic in tiles { @@ -191,39 +178,7 @@ std::set CGObjectInstance::getBlockedPos() const std::set CGObjectInstance::getBlockedOffsets() const { - std::set ret; - for(int w=0; w cmp.appearance.printPriority; - - if(pos.y != cmp.pos.y) - return pos.y < cmp.pos.y; - - if(cmp.ID==Obj::HERO && ID!=Obj::HERO) - return true; - if(cmp.ID!=Obj::HERO && ID==Obj::HERO) - return false; - - if(!isVisitable() && cmp.isVisitable()) - return true; - if(!cmp.isVisitable() && isVisitable()) - return false; - if(this->pos.x &tiles) const //returns reference to the set -{ - cb->getTilesInRange(tiles, getSightCenter(), getSightRadious(), tempOwner, 1); -} -void CGObjectInstance::hideTiles(PlayerColor ourplayer, int radius) const -{ - for (auto i = cb->gameState()->teams.begin(); i != cb->gameState()->teams.end(); i++) - { - if ( !vstd::contains(i->second.players, ourplayer ))//another team - { - for (auto & elem : i->second.players) - if ( cb->getPlayer(elem)->status == EPlayerStatus::INGAME )//seek for living player (if any) - { - FoWChange fw; - fw.mode = 0; - fw.player = elem; - cb->getTilesInRange (fw.tiles, pos, radius, (elem), -1); - cb->sendAndApply (&fw); - break; - } - } - } -} + int3 CGObjectInstance::getVisitableOffset() const { for(int y = 0; y < appearance.getHeight(); y++) @@ -317,21 +246,10 @@ int3 CGObjectInstance::getVisitableOffset() const if (appearance.isVisitableAt(x, y)) return int3(x,y,0); - logGlobal->warnStream() << "Warning: getVisitableOffset called on non-visitable obj!"; + //logGlobal->warnStream() << "Warning: getVisitableOffset called on non-visitable obj!"; return int3(0,0,0); } -void CGObjectInstance::getNameVis( std::string &hname ) const -{ - const CGHeroInstance *h = cb->getSelectedHero(cb->getCurrentPlayer()); - hname = VLC->objtypeh->getObjectName(ID); - if(h) - { - const bool visited = h->hasBonusFrom(Bonus::OBJECT,ID); - hname + " " + visitedTxt(visited); - } -} - void CGObjectInstance::giveDummyBonus(ObjectInstanceID heroID, ui8 duration) const { GiveBonus gbonus; @@ -343,6 +261,21 @@ void CGObjectInstance::giveDummyBonus(ObjectInstanceID heroID, ui8 duration) con cb->giveHeroBonus(&gbonus); } +std::string CGObjectInstance::getObjectName() const +{ + return VLC->objtypeh->getObjectName(ID, subID); +} + +std::string CGObjectInstance::getHoverText(PlayerColor player) const +{ + return getObjectName(); +} + +std::string CGObjectInstance::getHoverText(const CGHeroInstance * hero) const +{ + return getHoverText(hero->tempOwner); +} + void CGObjectInstance::onHeroVisit( const CGHeroInstance * h ) const { switch(ID) @@ -366,11 +299,6 @@ void CGObjectInstance::onHeroVisit( const CGHeroInstance * h ) const } } -ui8 CGObjectInstance::getPassableness() const -{ - return 0; -} - int3 CGObjectInstance::visitablePos() const { return pos - getVisitableOffset(); @@ -383,7 +311,7 @@ bool CGObjectInstance::isVisitable() const bool CGObjectInstance::passableFor(PlayerColor color) const { - return getPassableness() & 1< &tiles) const; //returns reference to the set PlayerColor getOwner() const; void setOwner(PlayerColor ow); + + /** APPEARANCE ACCESSORS **/ + int getWidth() const; //returns width of object graphic in tiles int getHeight() const; //returns height of object graphic in tiles - virtual bool visitableAt(int x, int y) const; //returns true if object is visitable at location (x, y) (h3m pos) - virtual int3 getVisitableOffset() const; //returns (x,y,0) offset to first visitable tile from bottom right obj tile (0,0,0) (h3m pos) + bool visitableAt(int x, int y) const; //returns true if object is visitable at location (x, y) (h3m pos) int3 visitablePos() const; bool blockingAt(int x, int y) const; //returns true if object is blocking location (x, y) (h3m pos) bool coveringAt(int x, int y) const; //returns true if object covers with picture location (x, y) (h3m pos) std::set getBlockedPos() const; //returns set of positions blocked by this object std::set getBlockedOffsets() const; //returns set of relative positions blocked by this object bool isVisitable() const; //returns true if object is visitable - bool operator<(const CGObjectInstance & cmp) const; //screen printing priority comparing - void hideTiles(PlayerColor ourplayer, int radius) const; - CGObjectInstance(); - virtual ~CGObjectInstance(); - //CGObjectInstance(const CGObjectInstance & right); - //CGObjectInstance& operator=(const CGObjectInstance & right); - virtual const std::string & getHoverText() const; + /** VIRTUAL METHODS **/ + + /// Returns true if player can pass through visitable tiles of this object + virtual bool passableFor(PlayerColor color) const; + /// Range of revealed map around this object, counting from getSightCenter() + virtual int getSightRadious() const; + /// returns (x,y,0) offset to a visitable tile of object + virtual int3 getVisitableOffset() const; + /// Called mostly during map randomization to turn random object into a regular one (e.g. "Random Monster" into "Pikeman") virtual void setType(si32 ID, si32 subID); - ///IObjectInterface + /// returns text visible in status bar with specific hero/player active. + + /// Returns generic name of object, without any player-specific info + virtual std::string getObjectName() const; + + /// Returns hover name for situation when there are no selected heroes. Default = object name + virtual std::string getHoverText(PlayerColor player) const; + /// Returns hero-specific hover name, including visited/not visited info. Default = player-specific name + virtual std::string getHoverText(const CGHeroInstance * hero) const; + + /** OVERRIDES OF IObjectInterface **/ + void initObj() override; void onHeroVisit(const CGHeroInstance * h) const override; - void setProperty(ui8 what, ui32 val) override;//synchr - - friend class CGameHandler; + /// method for synchronous update. Note: For new properties classes should override setPropertyDer instead + void setProperty(ui8 what, ui32 val) override final; + //friend class CGameHandler; template void serialize(Handler &h, const int version) { - h & hoverName & pos & ID & subID & id & tempOwner & blockVisit & appearance; + h & pos & ID & subID & id & tempOwner & blockVisit & appearance; //definfo is handled by map serializer } protected: - virtual void setPropertyDer(ui8 what, ui32 val);//synchr + /// virtual method that allows synchronously update object state on server and all clients + virtual void setPropertyDer(ui8 what, ui32 val); - void getNameVis(std::string &hname) const; + /// Gives dummy bonus from this object to hero. Can be used to track visited state void giveDummyBonus(ObjectInstanceID heroID, ui8 duration = Bonus::ONE_DAY) const; }; diff --git a/lib/mapObjects/CQuest.cpp b/lib/mapObjects/CQuest.cpp index c899b4071..ad301eb61 100644 --- a/lib/mapObjects/CQuest.cpp +++ b/lib/mapObjects/CQuest.cpp @@ -17,6 +17,8 @@ #include "../CGeneralTextHandler.h" #include "../CHeroHandler.h" #include "CObjectClassesHandler.h" +#include "../IGameCallback.h" +#include "../CGameState.h" using namespace boost::assign; @@ -434,25 +436,15 @@ void CGSeerHut::getRolloverText (MetaString &text, bool onHover) const text.addReplacement(seerName); } -const std::string & CGSeerHut::getHoverText() const +std::string CGSeerHut::getHoverText(PlayerColor player) const { - switch (ID) + std::string hoverName = getObjectName(); + if (ID == Obj::SEER_HUT && quest->progress != CQuest::NOT_ACTIVE) { - case Obj::SEER_HUT: - if (quest->progress != CQuest::NOT_ACTIVE) - { - hoverName = VLC->generaltexth->allTexts[347]; - boost::algorithm::replace_first(hoverName,"%s", seerName); - } - else //just seer hut - hoverName = VLC->objtypeh->getObjectName(ID); - break; - case Obj::QUEST_GUARD: - hoverName = VLC->objtypeh->getObjectName(ID); - break; - default: - logGlobal->debugStream() << "unrecognized quest object"; + hoverName = VLC->generaltexth->allTexts[347]; + boost::algorithm::replace_first(hoverName,"%s", seerName); } + if (quest->progress & quest->missionType) //rollover when the quest is active { MetaString ms; @@ -757,19 +749,14 @@ bool CGKeys::wasMyColorVisited (PlayerColor player) const return false; } -const std::string& CGKeys::getHoverText() const +std::string CGKeys::getHoverText(PlayerColor player) const { - bool visited = wasMyColorVisited (cb->getLocalPlayer()); - hoverName = getName() + "\n" + visitedTxt(visited); - return hoverName; + return getObjectName() + "\n" + visitedTxt(wasMyColorVisited(player)); } - -const std::string CGKeys::getName() const +std::string CGKeys::getObjectName() const { - std::string name; - name = VLC->generaltexth->tentColors[subID] + " " + VLC->objtypeh->getObjectName(ID); - return name; + return VLC->generaltexth->tentColors[subID] + " " + CGObjectInstance::getObjectName(); } bool CGKeymasterTent::wasVisited (PlayerColor player) const @@ -853,10 +840,7 @@ void CGBorderGate::onHeroVisit( const CGHeroInstance * h ) const //TODO: passabi } } -ui8 CGBorderGate::getPassableness() const +bool CGBorderGate::passableFor(PlayerColor color) const { - ui8 ret = 0; - for (int i = 0; i < PlayerColor::PLAYER_LIMIT_I; i++) - ret |= wasMyColorVisited(PlayerColor(i))< > playerKeyMap; //[players][keysowned] //SubID 0 - lightblue, 1 - green, 2 - red, 3 - darkblue, 4 - brown, 5 - purple, 6 - white, 7 - black - const std::string getName() const; //depending on color bool wasMyColorVisited (PlayerColor player) const; - const std::string & getHoverText() const override; + std::string getObjectName() const override; //depending on color + std::string getHoverText(PlayerColor player) const override; template void serialize(Handler &h, const int version) { @@ -189,7 +191,7 @@ public: CGBorderGate() : CGBorderGuard(){}; void onHeroVisit(const CGHeroInstance * h) const override; - ui8 getPassableness() const override; + bool passableFor(PlayerColor color) const override; template void serialize(Handler &h, const int version) { diff --git a/lib/mapObjects/CRewardableConstructor.cpp b/lib/mapObjects/CRewardableConstructor.cpp index e5b02e0c9..3835733b7 100644 --- a/lib/mapObjects/CRewardableConstructor.cpp +++ b/lib/mapObjects/CRewardableConstructor.cpp @@ -5,6 +5,7 @@ #include "../StringConstants.h" #include "../CCreatureHandler.h" #include "JsonRandom.h" +#include "../IGameCallback.h" /* * CRewardableConstructor.cpp, part of VCMI engine @@ -95,7 +96,8 @@ void CRandomRewardObjectInfo::configureObject(CRewardableObject * object, CRando info.reward.movePoints = JsonRandom::loadValue(reward["movePoints"], rng); info.reward.movePercentage = JsonRandom::loadValue(reward["movePercentage"], rng, -1); - info.reward.bonuses = JsonRandom::loadBonuses(reward["bonuses"]); + //FIXME: compile this line on Visual + //info.reward.bonuses = JsonRandom::loadBonuses(reward["bonuses"]); info.reward.primary = JsonRandom::loadPrimary(reward["primary"], rng); info.reward.secondary = JsonRandom::loadSecondary(reward["secondary"], rng); diff --git a/lib/mapObjects/CRewardableConstructor.h b/lib/mapObjects/CRewardableConstructor.h index 171b5a6ca..25b9a5501 100644 --- a/lib/mapObjects/CRewardableConstructor.h +++ b/lib/mapObjects/CRewardableConstructor.h @@ -15,7 +15,7 @@ * */ -class CRandomRewardObjectInfo : public IObjectInfo +class DLL_LINKAGE CRandomRewardObjectInfo : public IObjectInfo { JsonNode parameters; public: @@ -42,7 +42,7 @@ public: void init(const JsonNode & objectConfig); }; -class CRewardableConstructor : public AObjectTypeHandler +class DLL_LINKAGE CRewardableConstructor : public AObjectTypeHandler { CRandomRewardObjectInfo objectInfo; diff --git a/lib/mapObjects/CRewardableObject.cpp b/lib/mapObjects/CRewardableObject.cpp index 5fc3731ff..33516a0d9 100644 --- a/lib/mapObjects/CRewardableObject.cpp +++ b/lib/mapObjects/CRewardableObject.cpp @@ -15,6 +15,8 @@ #include "../CGeneralTextHandler.h" #include "../CSoundBase.h" #include "../NetPacks.h" +#include "../IGameCallback.h" +#include "../CGameState.h" #include "CObjectClassesHandler.h" @@ -74,8 +76,10 @@ std::vector CRewardableObject::getAvailableRewards(const CGHeroInstance * { const CVisitInfo & visit = info[i]; - if (visit.numOfGrants < visit.limiter.numOfGrants && visit.limiter.heroAllowed(hero)) + if ((visit.limiter.numOfGrants == 0 || visit.numOfGrants < visit.limiter.numOfGrants) // reward has unlimited uses or some are still available + && visit.limiter.heroAllowed(hero)) { + logGlobal->debugStream() << "Reward " << i << " is allowed"; ret.push_back(i); } } @@ -86,7 +90,7 @@ void CRewardableObject::onHeroVisit(const CGHeroInstance *h) const { auto grantRewardWithMessage = [&](int index) -> void { - grantReward(index, h); + logGlobal->debugStream() << "Granting reward " << index << ". Message says: " << info[index].message.toString(); // show message only if it is not empty if (!info[index].message.toString().empty()) { @@ -97,6 +101,8 @@ void CRewardableObject::onHeroVisit(const CGHeroInstance *h) const info[index].reward.loadComponents(iw.components); cb->showInfoDialog(&iw); } + // grant reward afterwards. Note that it may remove object + grantReward(index, h); }; auto selectRewardsMessage = [&](std::vector rewards) -> void { @@ -112,6 +118,7 @@ void CRewardableObject::onHeroVisit(const CGHeroInstance *h) const if (!wasVisited(h)) { auto rewards = getAvailableRewards(h); + logGlobal->debugStream() << "Visiting object with " << rewards.size() << " possible rewards"; switch (rewards.size()) { case 0: // no available rewards, e.g. empty flotsam @@ -153,6 +160,7 @@ void CRewardableObject::onHeroVisit(const CGHeroInstance *h) const } else { + logGlobal->debugStream() << "Revisiting already visited object"; InfoWindow iw; iw.player = h->tempOwner; iw.soundID = soundID; @@ -176,7 +184,6 @@ void CRewardableObject::blockingDialogAnswered(const CGHeroInstance *hero, ui32 if (answer > 0 && answer-1 < info.size()) { - //NOTE: this relies on assumption that there won't be any changes in player/hero during blocking dialog auto list = getAvailableRewards(hero); grantReward(list[answer - 1], hero); } @@ -263,7 +270,10 @@ void CRewardableObject::grantRewardAfterLevelup(const CVisitInfo & info, const C for (const Bonus & bonus : info.reward.bonuses) { + assert(bonus.source == Bonus::OBJECT); + assert(bonus.sid == ID); GiveBonus gb; + gb.who = GiveBonus::HERO; gb.bonus = bonus; gb.id = hero->id.getNum(); cb->giveHeroBonus(&gb); @@ -298,8 +308,9 @@ bool CRewardableObject::wasVisited (PlayerColor player) const switch (visitMode) { case VISIT_UNLIMITED: + case VISIT_BONUS: return false; - case VISIT_ONCE: + case VISIT_ONCE: // FIXME: hide this info deeper and return same as player? for (auto & visit : info) { if (visit.numOfGrants != 0) @@ -308,7 +319,7 @@ bool CRewardableObject::wasVisited (PlayerColor player) const case VISIT_HERO: return false; case VISIT_PLAYER: - return vstd::contains(cb->getPlayer(player)->visitedObjects, ObjectInstanceID(ID)); + return vstd::contains(cb->getPlayer(player)->visitedObjects, ObjectInstanceID(id)); default: return false; } @@ -318,8 +329,12 @@ bool CRewardableObject::wasVisited (const CGHeroInstance * h) const { switch (visitMode) { + case VISIT_UNLIMITED: + return false; + case VISIT_BONUS: + return h->hasBonusFrom(Bonus::OBJECT, ID); case VISIT_HERO: - return vstd::contains(h->visitedObjects, ObjectInstanceID(ID)) || h->hasBonusFrom(Bonus::OBJECT, ID); + return h->visitedObjects.count(ObjectInstanceID(id)); default: return wasVisited(h->tempOwner); } @@ -330,12 +345,6 @@ void CRewardInfo::loadComponents(std::vector & comps) const for (auto comp : extraComponents) comps.push_back(comp); - for (size_t i=0; i & comps) const for (auto & entry : creatures) comps.push_back(Component(Component::CREATURE, entry.type->idNumber, entry.count, 0)); + + for (size_t i=0; igeneraltexth->allTexts[id]; } -const std::string & CRewardableObject::getHoverText() const +std::string CRewardableObject::getHoverText(PlayerColor player) const { - const CGHeroInstance *h = cb->getSelectedHero(cb->getCurrentPlayer()); - hoverName = VLC->objtypeh->getObjectName(ID); - if(visitMode != VISIT_UNLIMITED) - { - bool visited = wasVisited(cb->getCurrentPlayer()); - if (h) - visited |= wasVisited(h); + if(visitMode == VISIT_PLAYER || visitMode == VISIT_ONCE) + return getObjectName() + " " + visitedTxt(wasVisited(player)); + return getObjectName(); +} - hoverName += " " + visitedTxt(visited); - } - return hoverName; +std::string CRewardableObject::getHoverText(const CGHeroInstance * hero) const +{ + if(visitMode != VISIT_UNLIMITED) + return getObjectName() + " " + visitedTxt(wasVisited(hero)); + return getObjectName(); } void CRewardableObject::setPropertyDer(ui8 what, ui32 val) @@ -458,7 +472,7 @@ void CGPickable::initObj() blockVisit = true; switch(ID) { - case Obj::CAMPFIRE: //FIXME: campfire is not functioning correctly in game (no visible message) + case Obj::CAMPFIRE: { soundID = soundBase::experience; int givenRes = cb->gameState()->getRandomGenerator().nextInt(5); @@ -600,7 +614,7 @@ void CGPickable::initObj() CGBonusingObject::CGBonusingObject() { - visitMode = VISIT_UNLIMITED; + visitMode = VISIT_BONUS; selectMode = SELECT_FIRST; } @@ -644,7 +658,7 @@ void CGBonusingObject::initObj() break; case Obj::FAERIE_RING: configureMessage(info[0], 49, 50, soundBase::LUCK); - configureBonus(info[0], Bonus::LUCK, 2, 71); + configureBonus(info[0], Bonus::LUCK, 1, 71); break; case Obj::FOUNTAIN_OF_FORTUNE: selectMode = SELECT_RANDOM; @@ -652,8 +666,10 @@ void CGBonusingObject::initObj() for (int i=0; i<5; i++) { configureBonus(info[i], Bonus::LUCK, i-1, 69); //NOTE: description have %d that should be replaced with value - configureMessage(info[i], 55, 56, soundBase::LUCK); + info[i].message.addTxt(MetaString::ADVOB_TXT, 55); + soundID = soundBase::LUCK; } + onVisited.addTxt(MetaString::ADVOB_TXT, 56); break; case Obj::IDOL_OF_FORTUNE: @@ -662,8 +678,10 @@ void CGBonusingObject::initObj() { info[i].limiter.dayOfWeek = i+1; configureBonus(info[i], i%2 ? Bonus::MORALE : Bonus::LUCK, 1, 68); - configureMessage(info[i], 62, 63, soundBase::experience); + info[i].message.addTxt(MetaString::ADVOB_TXT, 62); + soundID = soundBase::experience; } + onVisited.addTxt(MetaString::ADVOB_TXT, 63); info.back().limiter.dayOfWeek = 7; configureBonus(info.back(), Bonus::MORALE, 1, 68); // on last day of week configureBonus(info.back(), Bonus::LUCK, 1, 68); @@ -692,8 +710,10 @@ void CGBonusingObject::initObj() configureBonus(info[0], Bonus::MORALE, 2, 96); configureBonus(info[1], Bonus::MORALE, 1, 97); - configureMessage(info[0], 140, 141, soundBase::temple); - configureMessage(info[1], 140, 141, soundBase::temple); + info[0].message.addTxt(MetaString::ADVOB_TXT, 140); + info[1].message.addTxt(MetaString::ADVOB_TXT, 140); + onVisited.addTxt(MetaString::ADVOB_TXT, 141); + soundID = soundBase::temple; break; case Obj::WATERING_HOLE: configureMessage(info[0], 166, 167, soundBase::MORALE); @@ -918,6 +938,8 @@ void CGVisitableOPH::initObj() info.resize(2); info[0].reward.primary[PrimarySkill::SPELL_POWER] = 1; info[1].reward.primary[PrimarySkill::KNOWLEDGE] = 1; + info[0].reward.resources[Res::GOLD] = -1000; + info[1].reward.resources[Res::GOLD] = -1000; onSelect.addTxt(MetaString::ADVOB_TXT, 71); onVisited.addTxt(MetaString::ADVOB_TXT, 72); onEmpty.addTxt(MetaString::ADVOB_TXT, 73); @@ -928,6 +950,8 @@ void CGVisitableOPH::initObj() info.resize(2); info[0].reward.primary[PrimarySkill::ATTACK] = 1; info[1].reward.primary[PrimarySkill::DEFENSE] = 1; + info[0].reward.resources[Res::GOLD] = -1000; + info[1].reward.resources[Res::GOLD] = -1000; onSelect.addTxt(MetaString::ADVOB_TXT, 158); onVisited.addTxt(MetaString::ADVOB_TXT, 159); onEmpty.addTxt(MetaString::ADVOB_TXT, 160); @@ -937,59 +961,6 @@ void CGVisitableOPH::initObj() } } -//TODO: re-enable. Probably in some different form but still necessary -/* -const std::string & CGVisitableOPH::getHoverText() const -{ - int pom = -1; - switch(ID) - { - case Obj::ARENA: - pom = -1; - break; - case Obj::MERCENARY_CAMP: - pom = 8; - break; - case Obj::MARLETTO_TOWER: - pom = 7; - break; - case Obj::STAR_AXIS: - pom = 11; - break; - case Obj::GARDEN_OF_REVELATION: - pom = 4; - break; - case Obj::LEARNING_STONE: - pom = 5; - break; - case Obj::TREE_OF_KNOWLEDGE: - pom = 18; - break; - case Obj::LIBRARY_OF_ENLIGHTENMENT: - break; - case Obj::SCHOOL_OF_MAGIC: - pom = 9; - break; - case Obj::SCHOOL_OF_WAR: - pom = 10; - break; - default: - throw std::runtime_error("Wrong CGVisitableOPH object ID!\n"); - } - hoverName = VLC->objtypeh->getObjectName(ID); - if(pom >= 0) - hoverName += ("\n" + VLC->generaltexth->xtrainfo[pom]); - const CGHeroInstance *h = cb->getSelectedHero (cb->getCurrentPlayer()); - if(h) - { - hoverName += "\n\n"; - bool visited = vstd::contains (visitors, h->id); - hoverName += visitedTxt (visited); - } - return hoverName; -} -*/ - /////////////////////////////////////////////////////////////////////////////////////////////////// CGVisitableOPW::CGVisitableOPW() diff --git a/lib/mapObjects/CRewardableObject.h b/lib/mapObjects/CRewardableObject.h index 58d83c2c0..163890e6a 100644 --- a/lib/mapObjects/CRewardableObject.h +++ b/lib/mapObjects/CRewardableObject.h @@ -4,6 +4,7 @@ #include "CArmedInstance.h" #include "../NetPacksBase.h" +#include "../ResourceSet.h" /* * CRewardableObject.h, part of VCMI engine @@ -47,7 +48,7 @@ public: std::vector creatures; CRewardLimiter(): - numOfGrants(1), + numOfGrants(0), dayOfWeek(0), minLevel(0), primary(4, 0) @@ -128,7 +129,7 @@ public: } }; -class CVisitInfo +class DLL_LINKAGE CVisitInfo { public: CRewardLimiter limiter; @@ -176,6 +177,7 @@ protected: VISIT_UNLIMITED, // any number of times. Side effect - object hover text won't contain visited/not visited text VISIT_ONCE, // only once, first to visit get all the rewards VISIT_HERO, // every hero can visit object once + VISIT_BONUS, // can be visited by any hero that don't have bonus from this object VISIT_PLAYER // every player can visit object once }; @@ -209,7 +211,8 @@ protected: public: void setPropertyDer(ui8 what, ui32 val) override; - const std::string & getHoverText() const override; + std::string getHoverText(PlayerColor player) const override; + std::string getHoverText(const CGHeroInstance * hero) const override; /// Visitability checks. Note that hero check includes check for hero owner (returns true if object was visited by player) bool wasVisited (PlayerColor player) const override; diff --git a/lib/mapObjects/CommonConstructors.cpp b/lib/mapObjects/CommonConstructors.cpp index 14f45fd9c..7fb4ce5ff 100644 --- a/lib/mapObjects/CommonConstructors.cpp +++ b/lib/mapObjects/CommonConstructors.cpp @@ -8,6 +8,8 @@ #include "../CHeroHandler.h" #include "../CCreatureHandler.h" #include "JsonRandom.h" +#include "../CModHandler.h" +#include "../IGameCallback.h" /* * CommonConstructors.cpp, part of VCMI engine @@ -193,8 +195,11 @@ void CDwellingInstanceConstructor::configureObject(CGObjectInstance * object, CR if (guards.getType() == JsonNode::DATA_BOOL) { - const CCreature * crea = availableCreatures.at(0).at(0); - dwelling->putStack(SlotID(0), new CStackInstance(crea->idNumber, crea->growth * 3 )); + if (guards.Bool()) + { + const CCreature * crea = availableCreatures.at(0).at(0); + dwelling->putStack(SlotID(0), new CStackInstance(crea->idNumber, crea->growth * 3 )); + } } else for (auto & stack : JsonRandom::loadCreatures(guards, rng)) { diff --git a/lib/mapObjects/JsonRandom.cpp b/lib/mapObjects/JsonRandom.cpp index e57b2483e..88a5577d0 100644 --- a/lib/mapObjects/JsonRandom.cpp +++ b/lib/mapObjects/JsonRandom.cpp @@ -206,7 +206,14 @@ namespace JsonRandom return ret; } - std::vector loadBonuses(const JsonNode & value) + //std::vector loadComponents(const JsonNode & value) + //{ + // std::vector ret; + // return ret; + // //TODO + //} + + std::vector DLL_LINKAGE loadBonuses(const JsonNode & value) { std::vector ret; for (const JsonNode & entry : value.Vector()) @@ -218,8 +225,4 @@ namespace JsonRandom return ret; } - std::vector loadComponents(const JsonNode & value) - { - //TODO - } } diff --git a/lib/mapObjects/JsonRandom.h b/lib/mapObjects/JsonRandom.h index 80feeff20..dad95988d 100644 --- a/lib/mapObjects/JsonRandom.h +++ b/lib/mapObjects/JsonRandom.h @@ -46,5 +46,5 @@ namespace JsonRandom DLL_LINKAGE std::vector evaluateCreatures(const JsonNode & value); DLL_LINKAGE std::vector loadBonuses(const JsonNode & value); - DLL_LINKAGE std::vector loadComponents(const JsonNode & value); + //DLL_LINKAGE std::vector loadComponents(const JsonNode & value); } diff --git a/lib/mapObjects/MiscObjects.cpp b/lib/mapObjects/MiscObjects.cpp index a3a9c820a..9d4a88a32 100644 --- a/lib/mapObjects/MiscObjects.cpp +++ b/lib/mapObjects/MiscObjects.cpp @@ -14,9 +14,12 @@ #include "../NetPacks.h" #include "../CGeneralTextHandler.h" #include "../CSoundBase.h" +#include "../CModHandler.h" #include "CObjectClassesHandler.h" #include "../CSpellHandler.h" +#include "../IGameCallback.h" +#include "../CGameState.h" using namespace boost::assign; @@ -78,17 +81,16 @@ bool CPlayersVisited::wasVisited( TeamID team ) const return false; } -const std::string & CGCreature::getHoverText() const +std::string CGCreature::getHoverText(PlayerColor player) const { if(stacks.empty()) { - static const std::string errorValue("!!!INVALID_STACK!!!"); - //should not happen... logGlobal->errorStream() << "Invalid stack at tile " << pos << ": subID=" << subID << "; id=" << id; - return errorValue; // references to temporary are illegal - use pre-constructed string + return "!!!INVALID_STACK!!!"; } + std::string hoverName; MetaString ms; int pom = stacks.begin()->second->getQuantityID(); pom = 172 + 3*pom; @@ -96,30 +98,34 @@ const std::string & CGCreature::getHoverText() const ms << " " ; ms.addTxt(MetaString::CRE_PL_NAMES,subID); ms.toString(hoverName); - - if(const CGHeroInstance *selHero = cb->getSelectedHero(cb->getCurrentPlayer())) - { - const JsonNode & texts = VLC->generaltexth->localizedTexts["adventureMap"]["monsterThreat"]; - - hoverName += texts["title"].String(); - int choice; - double ratio = ((double)getArmyStrength() / selHero->getTotalStrength()); - if (ratio < 0.1) choice = 0; - else if (ratio < 0.25) choice = 1; - else if (ratio < 0.6) choice = 2; - else if (ratio < 0.9) choice = 3; - else if (ratio < 1.1) choice = 4; - else if (ratio < 1.3) choice = 5; - else if (ratio < 1.8) choice = 6; - else if (ratio < 2.5) choice = 7; - else if (ratio < 4) choice = 8; - else if (ratio < 8) choice = 9; - else if (ratio < 20) choice = 10; - else choice = 11; - hoverName += texts["levels"].Vector()[choice].String(); - } return hoverName; } + +std::string CGCreature::getHoverText(const CGHeroInstance * hero) const +{ + std::string hoverName = getHoverText(hero->tempOwner); + + const JsonNode & texts = VLC->generaltexth->localizedTexts["adventureMap"]["monsterThreat"]; + + hoverName += texts["title"].String(); + int choice; + double ratio = ((double)getArmyStrength() / hero->getTotalStrength()); + if (ratio < 0.1) choice = 0; + else if (ratio < 0.25) choice = 1; + else if (ratio < 0.6) choice = 2; + else if (ratio < 0.9) choice = 3; + else if (ratio < 1.1) choice = 4; + else if (ratio < 1.3) choice = 5; + else if (ratio < 1.8) choice = 6; + else if (ratio < 2.5) choice = 7; + else if (ratio < 4) choice = 8; + else if (ratio < 8) choice = 9; + else if (ratio < 20) choice = 10; + else choice = 11; + hoverName += texts["levels"].Vector()[choice].String(); + return hoverName; +} + void CGCreature::onHeroVisit( const CGHeroInstance * h ) const { int action = takenAction(h); @@ -443,21 +449,6 @@ void CGCreature::battleFinished(const CGHeroInstance *hero, const BattleResult & } else { - //int killedAmount=0; - //for(std::set >::iterator i=result->casualties[1].begin(); i!=result->casualties[1].end(); i++) - // if(i->first == subID) - // killedAmount += i->second; - //cb->setAmount(id, slots.find(0)->second.second - killedAmount); - - /* - MetaString ms; - int pom = slots.find(0)->second.getQuantityID(); - pom = 174 + 3*pom + 1; - ms << std::pair(6,pom) << " " << std::pair(7,subID); - cb->setHoverName(id,&ms); - cb->setObjProperty(id, 11, slots.begin()->second.count * 1000); - */ - //merge stacks into one TSlots::const_iterator i; CCreature * cre = VLC->creh->creatures[formation.basicType]; @@ -554,38 +545,48 @@ void CGMine::initObj() assert(!possibleResources.empty()); producedResource = *RandomGeneratorUtil::nextItem(possibleResources, cb->gameState()->getRandomGenerator()); tempOwner = PlayerColor::NEUTRAL; - hoverName = VLC->generaltexth->mines[7].first + "\n" + VLC->generaltexth->allTexts[202] + " " + troglodytes->getQuantityTXT(false) + " " + troglodytes->type->namePl; } else { producedResource = static_cast(subID); - - MetaString ms; - ms << std::pair(9,producedResource); if(tempOwner >= PlayerColor::PLAYER_LIMIT) tempOwner = PlayerColor::NEUTRAL; - else - ms << " (" << std::pair(6,23+tempOwner.getNum()) << ")"; - ms.toString(hoverName); } producedQuantity = defaultResProduction(); } +std::string CGMine::getObjectName() const +{ + return VLC->generaltexth->mines.at(subID).first; +} + +std::string CGMine::getHoverText(PlayerColor player) const +{ + + std::string hoverName = getObjectName(); // Sawmill + + if (tempOwner != PlayerColor::NEUTRAL) + { + hoverName += "\n"; + hoverName += VLC->generaltexth->arraytxt[23 + tempOwner.getNum()]; // owned by Red Player + hoverName += "\n(" + VLC->generaltexth->restypes[producedResource] + ")"; + } + + for (auto & slot : Slots()) // guarded by a few Pikeman + { + hoverName += "\n"; + hoverName += getRoughAmount(slot.first); + hoverName += getCreature(slot.first)->namePl; + } + return hoverName; +} + void CGMine::flagMine(PlayerColor player) const { assert(tempOwner != player); cb->setOwner(this, player); //not ours? flag it! - MetaString ms; - ms << std::pair(9,subID) << "\n(" << std::pair(6,23+player.getNum()) << ")"; - if(subID == 7) - { - ms << "(%s)"; - ms.addReplacement(MetaString::RES_NAMES, producedResource); - } - cb->setHoverName(this,&ms); - InfoWindow iw; iw.soundID = soundBase::FLAGMINE; iw.text.addTxt(MetaString::MINE_EVNTS,producedResource); //not use subID, abandoned mines uses default mine texts @@ -626,10 +627,14 @@ void CGMine::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) con cb->startBattleI(hero, this); } +std::string CGResource::getHoverText(PlayerColor player) const +{ + return VLC->generaltexth->restypes[subID]; +} + void CGResource::initObj() { blockVisit = true; - hoverName = VLC->generaltexth->restypes[subID]; if(!amount) { @@ -866,7 +871,6 @@ void CGArtifact::initObj() blockVisit = true; if(ID == Obj::ARTIFACT) { - hoverName = VLC->arth->artifacts[subID]->Name(); if(!storedArtifact->artType) storedArtifact->setType(VLC->arth->artifacts[subID]); } @@ -879,6 +883,11 @@ void CGArtifact::initObj() //assert(storedArtifact->artType->id == subID); //this does not stop desync } +std::string CGArtifact::getObjectName() const +{ + return VLC->arth->artifacts[subID]->Name(); +} + void CGArtifact::onHeroVisit( const CGHeroInstance * h ) const { if(!stacksCount()) @@ -985,20 +994,25 @@ void CGWitchHut::onHeroVisit( const CGHeroInstance * h ) const cb->showInfoDialog(&iw); } -const std::string & CGWitchHut::getHoverText() const +std::string CGWitchHut::getHoverText(PlayerColor player) const { - hoverName = VLC->objtypeh->getObjectName(ID); - if(wasVisited(cb->getLocalPlayer())) + std::string hoverName = getObjectName(); + if(wasVisited(player)) { hoverName += "\n" + VLC->generaltexth->allTexts[356]; // + (learn %s) boost::algorithm::replace_first(hoverName,"%s",VLC->generaltexth->skillName[ability]); - const CGHeroInstance *h = cb->getSelectedHero(cb->getCurrentPlayer()); - if(h && h->getSecSkillLevel(SecondarySkill(ability))) //hero knows that ability - hoverName += "\n\n" + VLC->generaltexth->allTexts[357]; // (Already learned) } return hoverName; } +std::string CGWitchHut::getHoverText(const CGHeroInstance * hero) const +{ + std::string hoverName = getHoverText(hero->tempOwner); + if(hero->getSecSkillLevel(SecondarySkill(ability))) //hero knows that ability + hoverName += "\n\n" + VLC->generaltexth->allTexts[357]; // (Already learned) + return hoverName; +} + void CGMagicWell::onHeroVisit( const CGHeroInstance * h ) const { int message; @@ -1020,10 +1034,9 @@ void CGMagicWell::onHeroVisit( const CGHeroInstance * h ) const showInfoDialog(h,message,soundBase::faerie); } -const std::string & CGMagicWell::getHoverText() const +std::string CGMagicWell::getHoverText(const CGHeroInstance * hero) const { - getNameVis(hoverName); - return hoverName; + return getObjectName() + " " + visitedTxt(hero->hasBonusFrom(Bonus::OBJECT,ID)); } void CGObservatory::onHeroVisit( const CGHeroInstance * h ) const @@ -1048,7 +1061,12 @@ void CGObservatory::onHeroVisit( const CGHeroInstance * h ) const case Obj::COVER_OF_DARKNESS: { iw.text.addTxt (MetaString::ADVOB_TXT, 31); - hideTiles(h->tempOwner, 20); + for (auto & player : cb->gameState()->players) + { + if (cb->getPlayerStatus(player.first) == EPlayerStatus::INGAME && + cb->getPlayerRelations(player.first, h->tempOwner) == PlayerRelations::ENEMIES) + cb->changeFogOfWar(visitablePos(), 20, player.first, true); + } break; } } @@ -1115,20 +1133,25 @@ void CGShrine::initObj() } } -const std::string & CGShrine::getHoverText() const +std::string CGShrine::getHoverText(PlayerColor player) const { - hoverName = VLC->objtypeh->getObjectName(ID); - if(wasVisited(cb->getCurrentPlayer())) //TODO: use local player, not current + std::string hoverName = getObjectName(); + if(wasVisited(player)) { hoverName += "\n" + VLC->generaltexth->allTexts[355]; // + (learn %s) boost::algorithm::replace_first(hoverName,"%s", spell.toSpell()->name); - const CGHeroInstance *h = cb->getSelectedHero(cb->getCurrentPlayer()); - if(h && vstd::contains(h->spells,spell)) //hero knows that ability - hoverName += "\n\n" + VLC->generaltexth->allTexts[354]; // (Already learned) } return hoverName; } +std::string CGShrine::getHoverText(const CGHeroInstance * hero) const +{ + std::string hoverName = getHoverText(hero->tempOwner); + if(vstd::contains(hero->spells, spell)) //hero knows that spell + hoverName += "\n\n" + VLC->generaltexth->allTexts[354]; // (Already learned) + return hoverName; +} + void CGSignBottle::initObj() { //if no text is set than we pick random from the predefined ones @@ -1250,19 +1273,18 @@ void CGGarrison::onHeroVisit (const CGHeroInstance *h) const cb->showGarrisonDialog(id, h->id, removableUnits); } -ui8 CGGarrison::getPassableness() const +bool CGGarrison::passableFor(PlayerColor player) const { + //FIXME: identical to same method in CGTownInstance + if ( !stacksCount() )//empty - anyone can visit - return GameConstants::ALL_PLAYERS; + return true; if ( tempOwner == PlayerColor::NEUTRAL )//neutral guarded - no one can visit - return 0; + return false; - ui8 mask = 0; - TeamState * ts = cb->gameState()->getPlayerTeam(tempOwner); - for(PlayerColor it : ts->players) - mask |= 1<getPlayerRelations(tempOwner, player) != PlayerRelations::ENEMIES) + return true; + return false; } void CGGarrison::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const @@ -1326,10 +1348,9 @@ void CGSirens::initObj() blockVisit = true; } -const std::string & CGSirens::getHoverText() const +std::string CGSirens::getHoverText(const CGHeroInstance * hero) const { - getNameVis(hoverName); - return hoverName; + return getObjectName() + " " + visitedTxt(hero->hasBonusFrom(Bonus::OBJECT,ID)); } void CGSirens::onHeroVisit( const CGHeroInstance * h ) const @@ -1500,11 +1521,9 @@ void CGObelisk::initObj() obeliskCount++; } -const std::string & CGObelisk::getHoverText() const +std::string CGObelisk::getHoverText(PlayerColor player) const { - bool visited = wasVisited(cb->getLocalPlayer()); - hoverName = VLC->objtypeh->getObjectName(ID) + " " + visitedTxt(visited); - return hoverName; + return getObjectName() + " " + visitedTxt(wasVisited(player)); } void CGObelisk::setPropertyDer( ui8 what, ui32 val ) @@ -1554,11 +1573,10 @@ void CGLighthouse::initObj() } } -const std::string & CGLighthouse::getHoverText() const +std::string CGLighthouse::getHoverText(PlayerColor player) const { - hoverName = VLC->objtypeh->getObjectName(ID); //TODO: owned by %s player - return hoverName; + return getObjectName(); } void CGLighthouse::giveBonusTo( PlayerColor player ) const diff --git a/lib/mapObjects/MiscObjects.h b/lib/mapObjects/MiscObjects.h index c53db75d7..ca1601c6a 100644 --- a/lib/mapObjects/MiscObjects.h +++ b/lib/mapObjects/MiscObjects.h @@ -2,6 +2,7 @@ #include "CObjectHandler.h" #include "CArmedInstance.h" +#include "../ResourceSet.h" /* * MiscObjects.h, part of VCMI engine @@ -48,7 +49,8 @@ public: bool refusedJoining; void onHeroVisit(const CGHeroInstance * h) const override; - const std::string & getHoverText() const override; + std::string getHoverText(PlayerColor player) const override; + std::string getHoverText(const CGHeroInstance * hero) const override; void initObj() override; void newTurn() const override; void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override; @@ -106,7 +108,8 @@ public: std::vector allowedAbilities; ui32 ability; - const std::string & getHoverText() const override; + std::string getHoverText(PlayerColor player) const override; + std::string getHoverText(const CGHeroInstance * hero) const override; void onHeroVisit(const CGHeroInstance * h) const override; void initObj() override; template void serialize(Handler &h, const int version) @@ -138,7 +141,7 @@ class DLL_LINKAGE CGGarrison : public CArmedInstance public: bool removableUnits; - ui8 getPassableness() const; + bool passableFor(PlayerColor color) const override; void onHeroVisit(const CGHeroInstance * h) const override; void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override; @@ -159,6 +162,8 @@ public: void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override; void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override; + std::string getObjectName() const override; + void pick( const CGHeroInstance * h ) const; void initObj() override; @@ -179,6 +184,7 @@ public: void initObj() override; void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override; void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override; + std::string getHoverText(PlayerColor player) const override; void collectRes(PlayerColor player) const; @@ -195,7 +201,8 @@ public: SpellID spell; //id of spell or NONE if random void onHeroVisit(const CGHeroInstance * h) const override; void initObj() override; - const std::string & getHoverText() const override; + std::string getHoverText(PlayerColor player) const override; + std::string getHoverText(const CGHeroInstance * hero) const override; template void serialize(Handler &h, const int version) { @@ -217,6 +224,10 @@ public: void flagMine(PlayerColor player) const; void newTurn() const override; void initObj() override; + + std::string getObjectName() const override; + std::string getHoverText(PlayerColor player) const override; + template void serialize(Handler &h, const int version) { h & static_cast(*this); @@ -245,7 +256,7 @@ class DLL_LINKAGE CGMagicWell : public CGObjectInstance //objects giving bonuses { public: void onHeroVisit(const CGHeroInstance * h) const override; - const std::string & getHoverText() const override; + std::string getHoverText(const CGHeroInstance * hero) const override; template void serialize(Handler &h, const int version) { @@ -257,7 +268,7 @@ class DLL_LINKAGE CGSirens : public CGObjectInstance { public: void onHeroVisit(const CGHeroInstance * h) const override; - const std::string & getHoverText() const override; + std::string getHoverText(const CGHeroInstance * hero) const override; void initObj() override; template void serialize(Handler &h, const int version) @@ -352,7 +363,7 @@ public: void onHeroVisit(const CGHeroInstance * h) const override; void initObj() override; - const std::string & getHoverText() const override; + std::string getHoverText(PlayerColor player) const override; template void serialize(Handler &h, const int version) { @@ -367,7 +378,7 @@ class DLL_LINKAGE CGLighthouse : public CGObjectInstance public: void onHeroVisit(const CGHeroInstance * h) const override; void initObj() override; - const std::string & getHoverText() const override; + std::string getHoverText(PlayerColor player) const override; template void serialize(Handler &h, const int version) { diff --git a/lib/mapObjects/ObjectTemplate.cpp b/lib/mapObjects/ObjectTemplate.cpp index 6cec38ba1..b8955b84a 100644 --- a/lib/mapObjects/ObjectTemplate.cpp +++ b/lib/mapObjects/ObjectTemplate.cpp @@ -3,7 +3,7 @@ #include "../filesystem/Filesystem.h" #include "../filesystem/CBinaryReader.h" -#include "../lib/VCMI_Lib.h" +#include "../VCMI_Lib.h" #include "../GameConstants.h" #include "../StringConstants.h" #include "../CGeneralTextHandler.h" @@ -308,6 +308,33 @@ bool ObjectTemplate::isBlockedAt(si32 X, si32 Y) const return false; } +std::set ObjectTemplate::getBlockedOffsets() const +{ + std::set ret; + for(int w = 0; w < getWidth(); ++w) + { + for(int h = 0; h < getHeight(); ++h) + { + if (isBlockedAt(w, h)) + ret.insert(int3(-w, -h, 0)); + } + } + return ret; +} + +int3 ObjectTemplate::getBlockMapOffset() const +{ + for(int w = 0; w < getWidth(); ++w) + { + for(int h = 0; h < getHeight(); ++h) + { + if (isBlockedAt(w, h)) + return int3(-w, -h, 0); + } + } + return int3(-1,-1,-1); +} + bool ObjectTemplate::isVisitableFrom(si8 X, si8 Y) const { // visitDir uses format diff --git a/lib/mapObjects/ObjectTemplate.h b/lib/mapObjects/ObjectTemplate.h index 89353b26c..62320363e 100644 --- a/lib/mapObjects/ObjectTemplate.h +++ b/lib/mapObjects/ObjectTemplate.h @@ -15,6 +15,7 @@ class CBinaryReader; class CLegacyConfigParser; class JsonNode; +class int3; class DLL_LINKAGE ObjectTemplate { @@ -56,6 +57,8 @@ public: bool isVisitableAt(si32 X, si32 Y) const; bool isVisibleAt(si32 X, si32 Y) const; bool isBlockedAt(si32 X, si32 Y) const; + std::set getBlockedOffsets() const; + int3 getBlockMapOffset() const; //bottom-right corner when firts blocked tile is // Checks if object is visitable from certain direction. X and Y must be between -1..+1 bool isVisitableFrom(si8 X, si8 Y) const; diff --git a/lib/mapping/CMap.cpp b/lib/mapping/CMap.cpp index 15e66c26e..1d53f8d88 100644 --- a/lib/mapping/CMap.cpp +++ b/lib/mapping/CMap.cpp @@ -432,7 +432,7 @@ const CGObjectInstance * CMap::getObjectiveObjectFrom(int3 pos, Obj::EObj type) } assert(bestMatch != nullptr); // if this happens - victory conditions or map itself is very, very broken - logGlobal->errorStream() << "Will use " << bestMatch->getHoverText() << " from " << bestMatch->pos; + logGlobal->errorStream() << "Will use " << bestMatch->getObjectName() << " from " << bestMatch->pos; return bestMatch; } diff --git a/lib/mapping/MapFormatH3M.cpp b/lib/mapping/MapFormatH3M.cpp index f064cc70a..5e7694528 100644 --- a/lib/mapping/MapFormatH3M.cpp +++ b/lib/mapping/MapFormatH3M.cpp @@ -1063,56 +1063,6 @@ void CMapLoaderH3M::readObjects() nobj = readHero(idToBeGiven); break; } - case Obj::ARENA: - case Obj::MERCENARY_CAMP: - case Obj::MARLETTO_TOWER: - case Obj::STAR_AXIS: - case Obj::GARDEN_OF_REVELATION: - case Obj::LEARNING_STONE: - case Obj::TREE_OF_KNOWLEDGE: - case Obj::LIBRARY_OF_ENLIGHTENMENT: - case Obj::SCHOOL_OF_MAGIC: - case Obj::SCHOOL_OF_WAR: - { - nobj = new CGVisitableOPH(); - break; - } - case Obj::MYSTICAL_GARDEN: - case Obj::WINDMILL: - case Obj::WATER_WHEEL: - { - nobj = new CGVisitableOPW(); - break; - } - case Obj::MONOLITH_ONE_WAY_ENTRANCE: - case Obj::MONOLITH_ONE_WAY_EXIT: - case Obj::MONOLITH_TWO_WAY: - case Obj::SUBTERRANEAN_GATE: - case Obj::WHIRLPOOL: - { - nobj = new CGTeleport(); - break; - } - case Obj::CAMPFIRE: - case Obj::FLOTSAM: - case Obj::SEA_CHEST: - case Obj::SHIPWRECK_SURVIVOR: - { - nobj = new CGPickable(); - break; - } - case Obj::TREASURE_CHEST: - if(objTempl.subid == 0) - { - nobj = new CGPickable(); - } - else - { - //WoG pickable object - //TODO: possible special handling - nobj = new CGObjectInstance(); - } - break; case Obj::MONSTER: //Monster case Obj::RANDOM_MONSTER: case Obj::RANDOM_MONSTER_L1: @@ -1330,12 +1280,6 @@ void CMapLoaderH3M::readObjects() reader.skip(3); break; } - case Obj::REFUGEE_CAMP: - case Obj::WAR_MACHINE_FACTORY: - { - nobj = new CGDwelling(); - break; - } case Obj::SHRINE_OF_MAGIC_INCANTATION: case Obj::SHRINE_OF_MAGIC_GESTURE: case Obj::SHRINE_OF_MAGIC_THOUGHT: @@ -1458,52 +1402,6 @@ void CMapLoaderH3M::readObjects() nobj = guard; break; } - case Obj::FAERIE_RING: - case Obj::SWAN_POND: - case Obj::IDOL_OF_FORTUNE: - case Obj::FOUNTAIN_OF_FORTUNE: - case Obj::RALLY_FLAG: - case Obj::OASIS: - case Obj::TEMPLE: - case Obj::WATERING_HOLE: - case Obj::FOUNTAIN_OF_YOUTH: - case Obj::BUOY: - case Obj::MERMAID: - case Obj::STABLES: - { - nobj = new CGBonusingObject(); - break; - } - case Obj::MAGIC_WELL: - { - nobj = new CGMagicWell(); - break; - } - case Obj::COVER_OF_DARKNESS: - case Obj::REDWOOD_OBSERVATORY: - case Obj::PILLAR_OF_FIRE: - { - nobj = new CGObservatory(); - break; - } - case Obj::CORPSE: - case Obj::LEAN_TO: - case Obj::WAGON: - case Obj::WARRIORS_TOMB: - { - nobj = new CGOnceVisitable(); - break; - } - case Obj::BOAT: - { - nobj = new CGBoat(); - break; - } - case Obj::SIRENS: - { - nobj = new CGSirens(); - break; - } case Obj::SHIPYARD: { nobj = new CGShipyard(); @@ -1531,11 +1429,6 @@ void CMapLoaderH3M::readObjects() hp->power = 0; } - break; - } - case Obj::KEYMASTER: - { - nobj = new CGKeymasterTent(); break; } case Obj::BORDERGUARD: @@ -1550,21 +1443,6 @@ void CMapLoaderH3M::readObjects() map->addQuest (nobj); break; } - case Obj::EYE_OF_MAGI: - case Obj::HUT_OF_MAGI: - { - nobj = new CGMagi(); - break; - } - case Obj::CREATURE_BANK: - case Obj::DERELICT_SHIP: - case Obj::DRAGON_UTOPIA: - case Obj::CRYPT: - case Obj::SHIPWRECK: - { - nobj = new CBank(); - break; - } case Obj::PYRAMID: //Pyramid of WoG object { if(objTempl.subid == 0) @@ -1579,53 +1457,24 @@ void CMapLoaderH3M::readObjects() } break; } - case Obj::CARTOGRAPHER: - { - nobj = new CCartographer(); - break; - } - case Obj::MAGIC_SPRING: - { - nobj = new CGMagicSpring(); - break; - } - case Obj::DEN_OF_THIEVES: - { - nobj = new CGDenOfthieves(); - break; - } - case Obj::OBELISK: - { - nobj = new CGObelisk(); - break; - } case Obj::LIGHTHOUSE: //Lighthouse { nobj = new CGLighthouse(); nobj->tempOwner = PlayerColor(reader.readUInt32()); break; } - case Obj::ALTAR_OF_SACRIFICE: - case Obj::TRADING_POST: - case Obj::FREELANCERS_GUILD: - case Obj::TRADING_POST_SNOW: - { - nobj = new CGMarket(); - break; - } - case Obj::UNIVERSITY: - { - nobj = new CGUniversity(); - break; - } - case Obj::BLACK_MARKET: - { - nobj = new CGBlackMarket(); - break; - } default: //any other object { - nobj = new CGObjectInstance(); + if (VLC->objtypeh->knownSubObjects(objTempl.id).count(objTempl.subid)) + { + nobj = VLC->objtypeh->getHandlerFor(objTempl.id, objTempl.subid)->create(objTempl); + } + else + { + logGlobal->warnStream() << "Unrecognized object: " << objTempl.id << ":" << objTempl.subid << " at " << objPos + << " on map " << map->name; + nobj = new CGObjectInstance(); + } break; } } diff --git a/lib/registerTypes/RegisterTypes.h b/lib/registerTypes/RegisterTypes.h index dd7467108..8f44d5446 100644 --- a/lib/registerTypes/RegisterTypes.h +++ b/lib/registerTypes/RegisterTypes.h @@ -12,6 +12,7 @@ #include "../mapObjects/CRewardableConstructor.h" #include "../mapObjects/CommonConstructors.h" #include "../mapObjects/MapObjects.h" +#include "../CObstacleInstance.h" /* * RegisterTypes.h, part of VCMI engine @@ -96,6 +97,7 @@ void registerTypesMapObjectTypes(Serializer &s) REGISTER_GENERIC_HANDLER(CGBorderGuard); REGISTER_GENERIC_HANDLER(CGCreature); REGISTER_GENERIC_HANDLER(CGDenOfthieves); + REGISTER_GENERIC_HANDLER(CGDwelling); REGISTER_GENERIC_HANDLER(CGEvent); REGISTER_GENERIC_HANDLER(CGGarrison); REGISTER_GENERIC_HANDLER(CGHeroPlaceholder); @@ -121,6 +123,7 @@ void registerTypesMapObjectTypes(Serializer &s) REGISTER_GENERIC_HANDLER(CGSignBottle); REGISTER_GENERIC_HANDLER(CGSirens); REGISTER_GENERIC_HANDLER(CGTeleport); + REGISTER_GENERIC_HANDLER(CGTownInstance); REGISTER_GENERIC_HANDLER(CGUniversity); REGISTER_GENERIC_HANDLER(CGVisitableOPH); REGISTER_GENERIC_HANDLER(CGVisitableOPW); @@ -234,7 +237,6 @@ void registerTypesClientPacks1(Serializer &s) s.template registerType(); s.template registerType(); s.template registerType(); - s.template registerType(); s.template registerType(); s.template registerType(); s.template registerType(); diff --git a/lib/rmg/CMapGenerator.cpp b/lib/rmg/CMapGenerator.cpp index 79324a684..3ef5e15bf 100644 --- a/lib/rmg/CMapGenerator.cpp +++ b/lib/rmg/CMapGenerator.cpp @@ -23,8 +23,8 @@ void CMapGenerator::foreach_neighbour(const int3 &pos, std::function mapGenOptions, int randomSeed /*= std::time(nullptr)*/) : - mapGenOptions(mapGenOptions), randomSeed(randomSeed), monolithIndex(0) +CMapGenerator::CMapGenerator(shared_ptr mapGenOptions, int RandomSeed /*= std::time(nullptr)*/) : + mapGenOptions(mapGenOptions), randomSeed(RandomSeed), monolithIndex(0) { rand.setSeed(randomSeed); } @@ -50,12 +50,13 @@ void CMapGenerator::initTiles() CMapGenerator::~CMapGenerator() { - //FIXME: what if map is not present anymore? - if (tiles && map) + if (tiles) { - for (int i=0; i < map->width; i++) + int width = mapGenOptions->getWidth(); + int height = mapGenOptions->getHeight(); + for (int i=0; i < width; i++) { - for(int j=0; j < map->height; j++) + for(int j=0; j < height; j++) { delete [] tiles[i][j]; } @@ -80,6 +81,7 @@ std::unique_ptr CMapGenerator::generate() genZones(); map->calculateGuardingGreaturePositions(); //clear map so that all tiles are unguarded fillZones(); + //updated fuarded tiles will be calculated in CGameState::initMapObjects() } catch (rmgException &e) { @@ -251,8 +253,8 @@ void CMapGenerator::createConnections() setOccupied (guardPos, ETileType::FREE); //just in case monster is too weak to spawn zoneA->addMonster (this, guardPos, connection.getGuardStrength()); //TODO: set value according to template //zones can make paths only in their own area - zoneA->crunchPath (this, guardPos, zoneA->getPos(), zoneA->getId()); //make connection towards our zone center - zoneB->crunchPath (this, guardPos, zoneB->getPos(), zoneB->getId()); //make connection towards other zone center + zoneA->crunchPath (this, guardPos, zoneA->getPos(), zoneA->getId(), zoneA->getFreePaths()); //make connection towards our zone center + zoneB->crunchPath (this, guardPos, zoneB->getPos(), zoneB->getId(), zoneB->getFreePaths()); //make connection towards other zone center break; //we're done with this connection } } diff --git a/lib/rmg/CMapGenerator.h b/lib/rmg/CMapGenerator.h index 9b56c11d2..81586eb78 100644 --- a/lib/rmg/CMapGenerator.h +++ b/lib/rmg/CMapGenerator.h @@ -51,7 +51,7 @@ public: class DLL_LINKAGE CMapGenerator { public: - explicit CMapGenerator(shared_ptr mapGenOptions, int randomSeed = std::time(nullptr)); + explicit CMapGenerator(shared_ptr mapGenOptions, int RandomSeed = std::time(nullptr)); ~CMapGenerator(); // required due to unique_ptr std::unique_ptr generate(); diff --git a/lib/rmg/CRmgTemplateZone.cpp b/lib/rmg/CRmgTemplateZone.cpp index 2a1a8a6ae..a0fc0dba4 100644 --- a/lib/rmg/CRmgTemplateZone.cpp +++ b/lib/rmg/CRmgTemplateZone.cpp @@ -314,6 +314,11 @@ std::vector CRmgTemplateZone::getTreasureInfo() return treasureInfo; } +std::set* CRmgTemplateZone::getFreePaths() +{ + return &freePaths; +} + float3 CRmgTemplateZone::getCenter() const { return center; @@ -756,7 +761,7 @@ void CRmgTemplateZone::initTownType (CMapGenerator* gen) playerInfo.allowedFactions.clear(); playerInfo.allowedFactions.insert (townType); playerInfo.hasMainTown = true; - playerInfo.posOfMainTown = town->pos - int3(2, 0, 0); + playerInfo.posOfMainTown = town->pos - town->getVisitableOffset(); playerInfo.generateHeroAtMainTown = true; //now create actual towns @@ -957,20 +962,49 @@ void CRmgTemplateZone::createTreasures(CMapGenerator* gen) void CRmgTemplateZone::createObstacles(CMapGenerator* gen) { + //get all possible obstacles for this terrain + for (auto primaryID : VLC->objtypeh->knownObjects()) + { + for (auto secondaryID : VLC->objtypeh->knownSubObjects(primaryID)) + { + auto handler = VLC->objtypeh->getHandlerFor(primaryID, secondaryID); + if (handler->isStaticObject()) + { + for (auto temp : handler->getTemplates()) + { + if (temp.canBePlacedAt(terrainType) && temp.getBlockMapOffset().valid()) + possibleObstacles.push_back(temp); + } + } + } + } + auto sel = gen->editManager->getTerrainSelection(); sel.clearSelection(); + + auto tryToPlaceObstacleHere = [this, gen](int3& tile)-> bool + { + auto temp = *RandomGeneratorUtil::nextItem(possibleObstacles, gen->rand); + int3 obstaclePos = tile + temp.getBlockMapOffset(); + if (canObstacleBePlacedHere(gen, temp, obstaclePos)) //can be placed here + { + auto obj = VLC->objtypeh->getHandlerFor(temp.id, temp.subid)->create(temp); + placeObject(gen, obj, obstaclePos); + return true; + } + return false; + }; + for (auto tile : tileinfo) { - //test code - block all the map to show paths clearly - //if (gen->isPossible(tile)) - // gen->setOccupied(tile, ETileType::BLOCKED); - if (gen->shouldBeBlocked(tile)) //fill tiles that should be blocked with obstacles { - auto obj = new CGObjectInstance(); - obj->ID = static_cast(130); - obj->subID = 0; - placeObject(gen, obj, tile); + while (!tryToPlaceObstacleHere(tile)); + } + else if (gen->isPossible(tile)) + { + //try to place random obstacle once - if not possible, leave it clear + tryToPlaceObstacleHere(tile); } } } @@ -1026,6 +1060,23 @@ bool CRmgTemplateZone::findPlaceForTreasurePile(CMapGenerator* gen, si32 min_dis return result; } +bool CRmgTemplateZone::canObstacleBePlacedHere(CMapGenerator* gen, ObjectTemplate &temp, int3 &pos) +{ + auto tilesBlockedByObject = temp.getBlockedOffsets(); + + bool allTilesAvailable = true; + for (auto blockingTile : tilesBlockedByObject) + { + int3 t = pos + blockingTile; + if (!gen->map->isInTheMap(t) || !(gen->isPossible(t) || gen->shouldBeBlocked(t))) + { + allTilesAvailable = false; //if at least one tile is not possible, object can't be placed here + break; + } + } + return allTilesAvailable; +} + bool CRmgTemplateZone::findPlaceForObject(CMapGenerator* gen, CGObjectInstance* obj, si32 min_dist, int3 &pos) { //we need object apperance to deduce free tiles @@ -1213,8 +1264,11 @@ bool CRmgTemplateZone::guardObject(CMapGenerator* gen, CGObjectInstance* object, gen->setOccupied (guardTile, ETileType::USED); } - else - gen->setOccupied (guardTile, ETileType::FREE); + else //allow no guard or other object in front of this object + { + for (auto tile : tiles) + gen->setOccupied (tile, ETileType::FREE); + } return true; } diff --git a/lib/rmg/CRmgTemplateZone.h b/lib/rmg/CRmgTemplateZone.h index 2ebd79589..03532719d 100644 --- a/lib/rmg/CRmgTemplateZone.h +++ b/lib/rmg/CRmgTemplateZone.h @@ -21,6 +21,7 @@ class CMapGenerator; class CTileInfo; class int3; class CGObjectInstance; +class ObjectTemplate; namespace ETemplateZoneType { @@ -149,6 +150,7 @@ public: std::vector getConnections() const; void addTreasureInfo(CTreasureInfo & info); std::vector getTreasureInfo(); + std::set* getFreePaths(); ObjectInfo getRandomObject (CMapGenerator* gen, ui32 value); @@ -172,6 +174,7 @@ private: ui16 totalDensity; std::vector treasureInfo; std::vector possibleObjects; + std::vector possibleObstacles; //content info std::vector> requiredObjects; @@ -182,12 +185,13 @@ private: float3 center; std::set tileinfo; //irregular area assined to zone std::vector connections; //list of adjacent zones - std::map alreadyConnected; //TODO: allow multiple connections between two zones? + std::set freePaths; //core paths of free tiles that all other objects will be linked to bool pointIsIn(int x, int y); void addAllPossibleObjects (CMapGenerator* gen); //add objects, including zone-specific, to possibleObjects bool findPlaceForObject(CMapGenerator* gen, CGObjectInstance* obj, si32 min_dist, int3 &pos); bool findPlaceForTreasurePile(CMapGenerator* gen, si32 min_dist, int3 &pos); + bool canObstacleBePlacedHere(CMapGenerator* gen, ObjectTemplate &temp, int3 &pos); void checkAndPlaceObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos); void placeObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos); bool guardObject(CMapGenerator* gen, CGObjectInstance* object, si32 str); diff --git a/scripting/erm/ERM.cbp b/scripting/erm/ERM.cbp index 47b15783f..279b417b6 100644 --- a/scripting/erm/ERM.cbp +++ b/scripting/erm/ERM.cbp @@ -48,7 +48,7 @@ - + @@ -58,7 +58,6 @@ - diff --git a/scripting/erm/ERMInterpreter.cpp b/scripting/erm/ERMInterpreter.cpp index e769ddc14..9119ad153 100644 --- a/scripting/erm/ERMInterpreter.cpp +++ b/scripting/erm/ERMInterpreter.cpp @@ -2,11 +2,14 @@ #include "ERMInterpreter.h" #include -#include "../../lib/CObjectHandler.h" +#include "../../lib/mapObjects/CObjectHandler.h" +#include "../../lib/mapObjects/MapObjects.h" #include "../../lib/CHeroHandler.h" #include "../../lib/CCreatureHandler.h" #include "../../lib/VCMIDirs.h" #include "../../lib/IGameCallback.h" +#include "../../lib/mapObjects/CGHeroInstance.h" +#include "../../lib/mapObjects/MiscObjects.h" /* * ERMInterpreter.cpp, part of VCMI engine diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 98255ea42..fdfb85d2c 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -1351,9 +1351,13 @@ void CGameHandler::newTurn() } if (t->hasBonusOfType (Bonus::DARKNESS)) { - t->hideTiles(t->getOwner(), t->getBonusLocalFirst(Selector::type(Bonus::DARKNESS))->val); + for (auto & player : gameState()->players) + { + if (getPlayerStatus(player.first) == EPlayerStatus::INGAME && + getPlayerRelations(player.first, t->tempOwner) == PlayerRelations::ENEMIES) + changeFogOfWar(t->visitablePos(), t->getBonusLocalFirst(Selector::type(Bonus::DARKNESS))->val, player.first, true); + } } - //unhiding what shouldn't be hidden? //that's handled in netpacks client } if(newMonth) @@ -1845,12 +1849,6 @@ void CGameHandler::setOwner(const CGObjectInstance * obj, PlayerColor owner) } } -void CGameHandler::setHoverName(const CGObjectInstance * obj, MetaString* name) -{ - SetHoverName shn(obj->id, *name); - sendAndApply(&shn); -} - void CGameHandler::showBlockingDialog( BlockingDialog *iw ) { auto dialogQuery = make_shared(*iw); @@ -2523,7 +2521,7 @@ bool CGameHandler::buildStructure( ObjectInstanceID tid, BuildingID requestedID, FoWChange fw; fw.player = t->tempOwner; fw.mode = 1; - t->getSightTiles(fw.tiles); + getTilesInRange(fw.tiles, t->getSightCenter(), t->getSightRadious(), t->tempOwner, 1); sendAndApply(&fw); if(t->visitingHero) @@ -4988,7 +4986,7 @@ bool CGameHandler::isAllowedExchange( ObjectInstanceID id1, ObjectInstanceID id2 void CGameHandler::objectVisited( const CGObjectInstance * obj, const CGHeroInstance * h ) { - logGlobal->traceStream() << h->nodeName() << " visits " << obj->getHoverText(); + logGlobal->debugStream() << h->nodeName() << " visits " << obj->getObjectName() << "(" << obj->ID << ":" << obj->subID << ")"; auto visitQuery = make_shared(obj, h, obj->visitablePos()); queries.addQuery(visitQuery); //TODO real visit pos @@ -5227,7 +5225,7 @@ void CGameHandler::checkVictoryLossConditionsForPlayer(PlayerColor player) } } -void CGameHandler::getVictoryLossMessage(PlayerColor player, EVictoryLossCheckResult victoryLossCheckResult, InfoWindow & out) const +void CGameHandler::getVictoryLossMessage(PlayerColor player, const EVictoryLossCheckResult & victoryLossCheckResult, InfoWindow & out) const { out.player = player; out.text.clear(); @@ -6252,6 +6250,37 @@ void CGameHandler::removeAfterVisit(const CGObjectInstance *object) assert("This function needs to be called during the object visit!"); } +void CGameHandler::changeFogOfWar(int3 center, ui32 radius, PlayerColor player, bool hide) +{ + std::unordered_set tiles; + getTilesInRange(tiles, center, radius, player, hide? -1 : 1); + if (hide) + { + std::unordered_set observedTiles; //do not hide tiles observed by heroes. May lead to disastrous AI problems + auto p = gs->getPlayer(player); + for (auto h : p->heroes) + { + getTilesInRange(observedTiles, h->getSightCenter(), h->getSightRadious(), h->tempOwner, -1); + } + for (auto t : p->towns) + { + getTilesInRange(observedTiles, t->getSightCenter(), t->getSightRadious(), t->tempOwner, -1); + } + for (auto tile : observedTiles) + vstd::erase_if_present (tiles, tile); + } + changeFogOfWar(tiles, player, hide); +} + +void CGameHandler::changeFogOfWar(std::unordered_set &tiles, PlayerColor player, bool hide) +{ + FoWChange fow; + fow.tiles = tiles; + fow.player = player; + fow.mode = hide? 0 : 1; + sendAndApply(&fow); +} + bool CGameHandler::isVisitCoveredByAnotherQuery(const CGObjectInstance *obj, const CGHeroInstance *hero) { if(auto topQuery = queries.topQuery(hero->getOwner())) diff --git a/server/CGameHandler.h b/server/CGameHandler.h index 36798d519..1a3791522 100644 --- a/server/CGameHandler.h +++ b/server/CGameHandler.h @@ -127,7 +127,6 @@ public: bool removeObject(const CGObjectInstance * obj) override; void setBlockVis(ObjectInstanceID objid, bool bv) override; void setOwner(const CGObjectInstance * obj, PlayerColor owner) override; - void setHoverName(const CGObjectInstance * objid, MetaString * name) override; void changePrimSkill(const CGHeroInstance * hero, PrimarySkill::PrimarySkill which, si64 val, bool abs=false) override; void changeSecSkill(const CGHeroInstance * hero, SecondarySkill which, int val, bool abs=false) override; //void showInfoDialog(InfoWindow *iw) override; @@ -174,6 +173,8 @@ public: void changeObjPos(ObjectInstanceID objid, int3 newPos, ui8 flags) override; void heroExchange(ObjectInstanceID hero1, ObjectInstanceID hero2) override; + void changeFogOfWar(int3 center, ui32 radius, PlayerColor player, bool hide) override; + void changeFogOfWar(std::unordered_set &tiles, PlayerColor player, bool hide) override; bool isVisitCoveredByAnotherQuery(const CGObjectInstance *obj, const CGHeroInstance *hero) override; @@ -289,7 +290,7 @@ public: private: std::list generatePlayerTurnOrder() const; void makeStackDoNothing(const CStack * next); - void getVictoryLossMessage(PlayerColor player, EVictoryLossCheckResult victoryLossCheckResult, InfoWindow & out) const; + void getVictoryLossMessage(PlayerColor player, const EVictoryLossCheckResult & victoryLossCheckResult, InfoWindow & out) const; // Check for victory and loss conditions void checkVictoryLossConditionsForPlayer(PlayerColor player); diff --git a/server/CQuery.cpp b/server/CQuery.cpp index e7ecb0355..45bffae79 100644 --- a/server/CQuery.cpp +++ b/server/CQuery.cpp @@ -322,7 +322,7 @@ CHeroLevelUpDialogQuery::CHeroLevelUpDialogQuery(const HeroLevelUp &Hlu) void CHeroLevelUpDialogQuery::onRemoval(CGameHandler *gh, PlayerColor color) { assert(answer); - logGlobal->traceStream() << "Completing hero level-up query. " << hlu.hero->getHoverText() << " gains skill " << *answer; + logGlobal->traceStream() << "Completing hero level-up query. " << hlu.hero->getObjectName() << " gains skill " << *answer; gh->levelUpHero(hlu.hero, hlu.skills[*answer]); } @@ -340,7 +340,7 @@ CCommanderLevelUpDialogQuery::CCommanderLevelUpDialogQuery(const CommanderLevelU void CCommanderLevelUpDialogQuery::onRemoval(CGameHandler *gh, PlayerColor color) { assert(answer); - logGlobal->traceStream() << "Completing commander level-up query. Commander of hero " << clu.hero->getHoverText() << " gains skill " << *answer; + logGlobal->traceStream() << "Completing commander level-up query. Commander of hero " << clu.hero->getObjectName() << " gains skill " << *answer; gh->levelUpCommander(clu.hero->commander, clu.skills[*answer]); }