1 #ifndef OPENMW_ESM_CELL_H 2 #define OPENMW_ESM_CELL_H 3 4 #include <string> 5 #include <vector> 6 #include <list> 7 8 #include "esmcommon.hpp" 9 #include "defs.hpp" 10 #include "cellref.hpp" 11 #include "cellid.hpp" 12 13 namespace MWWorld 14 { 15 class ESMStore; 16 } 17 18 namespace ESM 19 { 20 class ESMReader; 21 class ESMWriter; 22 23 /* Moved cell reference tracking object. This mainly stores the target cell 24 of the reference, so we can easily know where it has been moved when another 25 plugin tries to move it independently. 26 Unfortunately, we need to implement this here. 27 */ 28 class MovedCellRef 29 { 30 public: 31 RefNum mRefNum; 32 33 // Coordinates of target exterior cell 34 int mTarget[2]; 35 36 // The content file format does not support moving objects to an interior cell. 37 // The save game format does support moving to interior cells, but uses a different mechanism 38 // (see the MovedRefTracker implementation in MWWorld::CellStore for more details). 39 }; 40 41 /// Overloaded compare operator used to search inside a list of cell refs. 42 bool operator==(const MovedCellRef& ref, const RefNum& refNum); 43 bool operator==(const CellRef& ref, const RefNum& refNum); 44 45 typedef std::list<MovedCellRef> MovedCellRefTracker; 46 typedef std::list<std::pair<CellRef, bool> > CellRefTracker; 47 48 struct CellRefTrackerPredicate 49 { 50 RefNum mRefNum; 51 CellRefTrackerPredicateESM::CellRefTrackerPredicate52 CellRefTrackerPredicate(const RefNum& refNum) : mRefNum(refNum) {} operator ()ESM::CellRefTrackerPredicate53 bool operator() (const std::pair<CellRef, bool>& refdelPair) { return refdelPair.first == mRefNum; } 54 }; 55 56 /* Cells hold data about objects, creatures, statics (rocks, walls, 57 buildings) and landscape (for exterior cells). Cells frequently 58 also has other associated LAND and PGRD records. Combined, all this 59 data can be huge, and we cannot load it all at startup. Instead, 60 the strategy we use is to remember the file position of each cell 61 (using ESMReader::getContext()) and jumping back into place 62 whenever we need to load a given cell. 63 */ 64 struct Cell 65 { 66 static unsigned int sRecordId; 67 /// Return a string descriptor for this record type. Currently used for debugging / error logs only. getRecordTypeESM::Cell68 static std::string getRecordType() { return "Cell"; } 69 70 enum Flags 71 { 72 Interior = 0x01, // Interior cell 73 HasWater = 0x02, // Does this cell have a water surface 74 NoSleep = 0x04, // Is it allowed to sleep here (without a bed) 75 QuasiEx = 0x80 // Behave like exterior (Tribunal+), with 76 // skybox and weather 77 }; 78 79 struct DATAstruct 80 { 81 int mFlags {0}; 82 int mX {0}, mY {0}; 83 }; 84 85 struct AMBIstruct 86 { 87 Color mAmbient {0}, mSunlight {0}, mFog {0}; 88 float mFogDensity {0.f}; 89 }; 90 CellESM::Cell91 Cell() : mName(""), 92 mRegion(""), 93 mHasAmbi(true), 94 mWater(0), 95 mWaterInt(false), 96 mMapColor(0), 97 mRefNumCounter(0) 98 {} 99 100 // Interior cells are indexed by this (it's the 'id'), for exterior 101 // cells it is optional. 102 std::string mName; 103 104 // Optional region name for exterior and quasi-exterior cells. 105 std::string mRegion; 106 107 std::vector<ESM_Context> mContextList; // File position; multiple positions for multiple plugin support 108 DATAstruct mData; 109 CellId mCellId; 110 111 AMBIstruct mAmbi; 112 bool mHasAmbi; 113 114 float mWater; // Water level 115 bool mWaterInt; 116 int mMapColor; 117 // Counter for RefNums. This is only used during content file editing and has no impact on gameplay. 118 // It prevents overwriting previous refNums, even if they were deleted. 119 // as that would collide with refs when a content file is upgraded. 120 int mRefNumCounter; 121 122 // References "leased" from another cell (i.e. a different cell 123 // introduced this ref, and it has been moved here by a plugin) 124 CellRefTracker mLeasedRefs; 125 MovedCellRefTracker mMovedRefs; 126 127 void postLoad(ESMReader &esm); 128 129 // This method is left in for compatibility with esmtool. Parsing moved references currently requires 130 // passing ESMStore, bit it does not know about this parameter, so we do it this way. 131 void load(ESMReader &esm, bool &isDeleted, bool saveContext = true); // Load everything (except references) 132 void loadNameAndData(ESMReader &esm, bool &isDeleted); // Load NAME and DATAstruct 133 void loadCell(ESMReader &esm, bool saveContext = true); // Load everything, except NAME, DATAstruct and references 134 135 void save(ESMWriter &esm, bool isDeleted = false) const; 136 isExteriorESM::Cell137 bool isExterior() const 138 { 139 return !(mData.mFlags & Interior); 140 } 141 getGridXESM::Cell142 int getGridX() const 143 { 144 return mData.mX; 145 } 146 getGridYESM::Cell147 int getGridY() const 148 { 149 return mData.mY; 150 } 151 hasWaterESM::Cell152 bool hasWater() const 153 { 154 return ((mData.mFlags&HasWater) != 0) || isExterior(); 155 } 156 hasAmbientESM::Cell157 bool hasAmbient() const 158 { 159 return mHasAmbi; 160 } 161 setHasAmbientESM::Cell162 void setHasAmbient(bool hasAmbi) 163 { 164 mHasAmbi = hasAmbi; 165 } 166 167 // Restore the given reader to the stored position. Will try to open 168 // the file matching the stored file name. If you want to read from 169 // somewhere other than the file system, you need to pre-open the 170 // ESMReader, and the filename must match the stored filename 171 // exactly. 172 void restore(ESMReader &esm, int iCtx) const; 173 174 std::string getDescription() const; 175 ///< Return a short string describing the cell (mostly used for debugging/logging purpose) 176 177 /* Get the next reference in this cell, if any. Returns false when 178 there are no more references in the cell. 179 180 All fields of the CellRef struct are overwritten. You can safely 181 reuse one memory location without blanking it between calls. 182 */ 183 /// \param ignoreMoves ignore MVRF record and read reference like a regular CellRef. 184 static bool getNextRef(ESMReader &esm, 185 CellRef &ref, 186 bool &isDeleted, 187 bool ignoreMoves = false, 188 MovedCellRef *mref = nullptr); 189 190 /* This fetches an MVRF record, which is used to track moved references. 191 * Since they are comparably rare, we use a separate method for this. 192 */ 193 static bool getNextMVRF(ESMReader &esm, MovedCellRef &mref); 194 195 void blank(); 196 ///< Set record to default state (does not touch the ID/index). 197 198 const CellId& getCellId() const; 199 }; 200 } 201 #endif 202