#pragma once #ifndef _MSC_VER #include "CObjectHandler.h" #include "CDefObjInfoHandler.h" #endif #include "ConstTransitivePtr.h" #include "ResourceSet.h" #include "int3.h" #include "GameConstants.h" /* * map.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 CArtifactInstance; class CGDefInfo; class CGObjectInstance; class CGHeroInstance; class CCommanderInstance; class CGCreature; class CQuest; class CGTownInstance; class IModableArt; class IQuestObject; class CInputStream; typedef std::unique_ptr TInputStreamPtr; /// Struct which describes a single terrain tile struct DLL_LINKAGE TerrainTile { enum EterrainType {border=-1, dirt, sand, grass, snow, swamp, rough, subterranean, lava, water, rock}; enum Eriver {noRiver=0, clearRiver, icyRiver, muddyRiver, lavaRiver}; enum Eroad {dirtRoad=1, grazvelRoad, cobblestoneRoad}; EterrainType tertype; // type of terrain ui8 terview; // look of terrain Eriver nuine; // type of Eriver (0 if there is no river) ui8 rivDir; // direction of Eriver Eroad malle; // type of Eroad (0 if there is no river) ui8 roadDir; // direction of Eroad ui8 siodmyTajemniczyBajt; //first two bits - how to rotate terrain graphic (next two - river graphic, next two - road); 7th bit - whether tile is coastal (allows disembarking if land or block movement if water); 8th bit - Favourable Winds effect bool visitable; //false = not visitable; true = visitable bool blocked; //false = free; true = blocked; std::vector visitableObjects; //pointers to objects hero can visit while being on this tile std::vector blockingObjects; //pointers to objects that are blocking this tile template void serialize(Handler &h, const int version) { h & tertype & terview & nuine & rivDir & malle &roadDir & siodmyTajemniczyBajt & blocked; if(!h.saving) { visitable = false; //these flags (and obj vectors) will be restored in map serialization } } bool entrableTerrain(const TerrainTile *from = NULL) const; //checks if terrain is not a rock. If from is water/land, same type is also required. bool entrableTerrain(bool allowLand, bool allowSea) const; //checks if terrain is not a rock. If from is water/land, same type is also required. bool isClear(const TerrainTile *from = NULL) const; //checks for blocking objs and terraint type (water / land) int topVisitableID() const; //returns ID of the top visitable ovject or -1 if there is none bool isWater() const; bool isCoastal() const; bool hasFavourableWinds() const; }; /// name of starting hero struct DLL_LINKAGE SheroName { int heroID; std::string heroName; template void serialize(Handler &h, const int version) { h & heroID & heroName; } }; /// Player information regarding map. Which factions are allowed, AI tactic setting, main hero name, /// position of main town,... struct DLL_LINKAGE PlayerInfo { si32 p7, p8, p9; ui8 powerPlacehodlers; //q-ty of hero placeholders containing hero type, WARNING: powerPlacehodlers sometimes gives false 0 (eg. even if there is one placeholder), maybe different meaning??? ui8 canHumanPlay; ui8 canComputerPlay; ui32 AITactic; //(00 - random, 01 - warrior, 02 - builder, 03 - explorer) std::set allowedFactions; //set with factions player can play with ui8 isFactionRandom; ui32 mainHeroPortrait; //it's ID of hero with chosen portrait; 255 if standard std::string mainHeroName; std::vector heroesNames; ui8 hasMainTown; ui8 generateHeroAtMainTown; int3 posOfMainTown; ui8 team; ui8 generateHero; PlayerInfo(): p7(0), p8(0), p9(0), canHumanPlay(0), canComputerPlay(0), AITactic(0), isFactionRandom(0), mainHeroPortrait(0), hasMainTown(0), generateHeroAtMainTown(0), team(255), generateHero(0) {}; si8 defaultCastle() const { assert(!allowedFactions.empty()); // impossible? if (allowedFactions.size() == 1) return *allowedFactions.begin(); //only one faction s available - pick it return -1; // set to random } si8 defaultHero() const { if ((generateHeroAtMainTown && hasMainTown) //we will generate hero in front of main town || p8) //random hero return -1; else return -2; } template void serialize(Handler &h, const int version) { h & p7 & p8 & p9 & canHumanPlay & canComputerPlay & AITactic & allowedFactions & isFactionRandom & mainHeroPortrait & mainHeroName & heroesNames & hasMainTown & generateHeroAtMainTown & posOfMainTown & team & generateHero; } }; /// Small struct which holds information about the loss condition struct DLL_LINKAGE LossCondition { ELossConditionType::ELossConditionType typeOfLossCon; int3 pos; si32 timeLimit; // in days; -1 if not used const CGObjectInstance *obj; //set during map parsing: hero/town (depending on typeOfLossCon); NULL if not used template void serialize(Handler &h, const int version) { h & typeOfLossCon & pos & timeLimit & obj; } LossCondition(); }; /// Small struct which holds information about the victory condition struct DLL_LINKAGE CVictoryCondition { EVictoryConditionType::EVictoryConditionType condition; //ID of condition ui8 allowNormalVictory, appliesToAI; int3 pos; //pos of city to upgrade (3); pos of town to build grail, {-1,-1,-1} if not relevant (4); hero pos (5); town pos(6); monster pos (7); destination pos(8) si32 ID; //artifact ID (0); monster ID (1); resource ID (2); needed fort level in upgraded town (3); artifact ID (8) si32 count; //needed count for creatures (1) / resource (2); upgraded town hall level (3); const CGObjectInstance *obj; //object of specific monster / city / hero instance (NULL if not used); set during map parsing CVictoryCondition(); template void serialize(Handler &h, const int version) { h & condition & allowNormalVictory & appliesToAI & pos & ID & count & obj; } }; /// Struct which holds a name and the rumor text struct DLL_LINKAGE Rumor { std::string name, text; template void serialize(Handler &h, const int version) { h & name & text; } }; /// Struct which describes who can hire this hero struct DLL_LINKAGE DisposedHero { ui32 ID; ui16 portrait; //0xFF - default std::string name; ui8 players; //who can hire this hero (bitfield) template void serialize(Handler &h, const int version) { h & ID & portrait & name & players; } }; /// Class which manages map events. class DLL_LINKAGE CMapEvent { public: std::string name, message; TResources resources; //gained / taken resources ui8 players; //affected players ui8 humanAffected; ui8 computerAffected; ui32 firstOccurence; ui32 nextOccurence; //after nextOccurance day event will occur; if it it 0, event occures only one time; template void serialize(Handler &h, const int version) { h & name & message & resources & players & humanAffected & computerAffected & firstOccurence & nextOccurence; } bool operator<(const CMapEvent &b) const { return firstOccurence < b.firstOccurence; } bool operator<=(const CMapEvent &b) const { return firstOccurence <= b.firstOccurence; } }; /// Sub-class derived by CMapEvent; This event can build specific buildings or add /// additional creatures in a town. class DLL_LINKAGE CCastleEvent: public CMapEvent { public: std::set buildings;//build specific buildings std::vector creatures;//additional creatures in i-th level dwelling CGTownInstance * town;//owner of this event template void serialize(Handler &h, const int version) { h & static_cast(*this); h & buildings & creatures; } }; /// Holds information about loss/victory condition, map format, version, players, height, width,... class DLL_LINKAGE CMapHeader { public: enum Eformat {invalid, WoG=0x33, AB=0x15, RoE=0x0e, SoD=0x1c}; Eformat version; // version of map Eformat ui8 areAnyPLayers; // if there are any playable players on map si32 height, width, twoLevel; //sizes std::string name; //name of map std::string description; //and description ui8 difficulty; // 0 easy - 4 impossible ui8 levelLimit; LossCondition lossCondition; CVictoryCondition victoryCondition; //victory conditions std::vector players; // info about players - size 8 ui8 howManyTeams; std::vector allowedHeroes; //allowedHeroes[hero_ID] - if the hero is allowed std::vector placeholdedHeroes; //ID of types of heroes in placeholders void initFromMemory(const ui8 *bufor, int &i); void loadViCLossConditions( const ui8 * bufor, int &i); void loadPlayerInfo( int &pom, const ui8 * bufor, int &i); CMapHeader(const ui8 *map); //an argument is a reference to string described a map (unpacked) CMapHeader(); virtual ~CMapHeader(); template void serialize(Handler &h, const int Version) { h & version & name & description & width & height & twoLevel & difficulty & levelLimit & areAnyPLayers; h & players & lossCondition & victoryCondition & howManyTeams; } }; /// Extends the base class and adds further map information like rumors, disposed heroes, /// allowed spells, artifacts, abilities and such things. struct DLL_LINKAGE Mapa : public CMapHeader { ui32 checksum; TerrainTile*** terrain; std::vector rumors; std::vector disposedHeroes; std::vector > predefinedHeroes; std::vector > defy; // list of .def files with definitions from .h3m (may be custom) std::vector allowedSpell; //allowedSpell[spell_ID] - if the spell is allowed std::vector allowedArtifact; //allowedArtifact[artifact_ID] - if the artifact is allowed std::vector allowedAbilities; //allowedAbilities[ability_ID] - if the ability is allowed std::list > events; int3 grailPos; int grailRadious; std::vector< ConstTransitivePtr > objects; std::vector< ConstTransitivePtr > heroes; std::vector< ConstTransitivePtr > towns; std::vector< ConstTransitivePtr > artInstances; //stores all artifacts std::vector< ConstTransitivePtr > quests; //FIXME: allow to serialize quests not related to objects //std::vector< ConstTransitivePtr > commanders; //bmap > monsters; //bmap > heroesToBeat; bmap questIdentifierToId; void initFromBytes( const ui8 * bufor, size_t size); //creates map from decompressed .h3m data void readEvents( const ui8 * bufor, int &i); void readObjects( const ui8 * bufor, int &i); void loadQuest( IQuestObject * guard, const ui8 * bufor, int & i); void readDefInfo( const ui8 * bufor, int &i); void readTerrain( const ui8 * bufor, int &i); void readPredefinedHeroes( const ui8 * bufor, int &i); void readHeader( const ui8 * bufor, int &i); void readRumors( const ui8 * bufor, int &i); CGObjectInstance *loadHero(const ui8 * bufor, int &i, int idToBeGiven); void loadArtifactsOfHero(const ui8 * bufor, int & i, CGHeroInstance * nhi); bool loadArtifactToSlot(CGHeroInstance *h, int slot, const ui8 * bufor, int &i); void loadTown( CGObjectInstance * &nobj, const ui8 * bufor, int &i, int subid); int loadSeerHut( const ui8 * bufor, int i, CGObjectInstance *& nobj); CArtifactInstance *createArt(int aid, int spellID = -1); void addNewArtifactInstance(CArtifactInstance *art); void addQuest (CGObjectInstance *obj); void eraseArtifactInstance(CArtifactInstance *art); const CGObjectInstance *getObjectiveObjectFrom(int3 pos, bool lookForHero); void checkForObjectives(); void addBlockVisTiles(CGObjectInstance * obj); void removeBlockVisTiles(CGObjectInstance * obj, bool total=false); Mapa(std::string filename); //creates map structure from .h3m file Mapa(); ~Mapa(); TerrainTile &getTile(const int3 & tile); const TerrainTile &getTile(const int3 & tile) const; CGHeroInstance * getHero(int ID, int mode=0); bool isInTheMap(const int3 &pos) const; bool isWaterTile(const int3 &pos) const; //out-of-pos safe static TInputStreamPtr getMapStream(std::string URI); template void serialize(Handler &h, const int formatVersion) { h & static_cast(*this); h & rumors & allowedSpell & allowedAbilities & allowedArtifact & allowedHeroes & events & grailPos; h & artInstances & quests; //hopefully serialization is now automagical? h & questIdentifierToId; //TODO: viccondetails if(h.saving) { //saving terrain for (int i = 0; i < width ; i++) for (int j = 0; j < height ; j++) for (int k = 0; k <= twoLevel ; k++) h & terrain[i][j][k]; } else { //loading terrain terrain = new TerrainTile**[width]; // allocate memory for (int ii=0;ii defs; // // if(h.saving) //create vector with all defs used on map // { // for(ui32 i=0; idefInfo->serial = -1; //set serial to serial -1 - indicates that def is not present in defs vector // // for(ui32 i=0; idefInfo; // if(cur->serial < 0) // { // cur->serial = defs.size(); // defs.push_back(cur); // } // } // } // // h & ((h.saving) ? defs : defy); // //objects // if(h.saving) // { // ui32 hlp = objects.size(); // h & hlp; // } // else // { // ui32 hlp; // h & hlp; // objects.resize(hlp); // } //static members h & CGTeleport::objs; h & CGTeleport::gates; h & CGKeys::playerKeyMap; h & CGMagi::eyelist; h & CGObelisk::obeliskCount & CGObelisk::visited; h & CGTownInstance::merchantArtifacts; // for(ui32 i=0; idefInfo->serial) : shlp); //read / write pos of definfo in defs vector // if(!h.saving) // obj->defInfo = defy[shlp]; // } // } if(!h.saving) { for(ui32 i=0; iID) { case Obj::HERO: heroes.push_back (static_cast(+objects[i])); break; case Obj::TOWN: towns.push_back (static_cast(+objects[i])); break; } addBlockVisTiles(objects[i]); //recreate blockvis map } for(ui32 i=0; ipos; vistile.x++; for(ui32 j=0; jpos) //hero stands on the town entrance { if(heroes[i]->inTownGarrison) { towns[j]->garrisonHero = heroes[i]; removeBlockVisTiles(heroes[i]); } else { towns[j]->visitingHero = heroes[i]; } heroes[i]->visitedTown = towns[j]; break; } } vistile.x -= 2; //manifest pos const TerrainTile &t = getTile(vistile); if(t.tertype != TerrainTile::water) continue; //hero stands on the water - he must be in the boat for(ui32 j = 0; j < t.visitableObjects.size(); j++) { if(t.visitableObjects[j]->ID == Obj::BOAT) { CGBoat *b = static_cast(t.visitableObjects[j]); heroes[i]->boat = b; b->hero = heroes[i]; removeBlockVisTiles(b); break; } } } //heroes loop } //!saving } };