1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 */ 22 23 #ifndef ULTIMA8_WORLD_CURRENTMAP_H 24 #define ULTIMA8_WORLD_CURRENTMAP_H 25 26 #include "ultima/shared/std/containers.h" 27 #include "ultima/ultima8/usecode/intrinsics.h" 28 #include "ultima/ultima8/misc/direction.h" 29 30 namespace Ultima { 31 namespace Ultima8 { 32 33 class Map; 34 class Item; 35 class UCList; 36 class TeleportEgg; 37 class EggHatcherProcess; 38 39 #define MAP_NUM_CHUNKS 64 40 #define MAP_NUM_TARGET_ITEMS 200 41 42 class CurrentMap { 43 friend class World; 44 public: 45 CurrentMap(); 46 ~CurrentMap(); 47 48 void clear(); 49 void writeback(); 50 void loadMap(Map *map); 51 52 //! sets the currently loaded map, without any processing. 53 //! (Should only be used for loading.) setMap(Map * map)54 void setMap(Map *map) { 55 _currentMap = map; 56 } 57 58 //! Get the map number of the CurrentMap 59 uint32 getNum() const; 60 getChunkSize()61 unsigned int getChunkSize() const { 62 return _mapChunkSize; 63 } 64 65 //! Add an item to the beginning of the item list 66 void addItem(Item *item); 67 68 //! Add an item to the end of the item list 69 void addItemToEnd(Item *item); 70 71 void removeItemFromList(Item *item, int32 oldx, int32 oldy); 72 void removeItem(Item *item); 73 74 //! Add an item to the list of possible targets (in Crusader) 75 void addTargetItem(const Item *item); 76 //! Remove an item from the list of possible targets (in Crusader) 77 void removeTargetItem(const Item *item); 78 //! Find the best target item in the given direction from the given start point. 79 Item *findBestTargetItem(int32 x, int32 y, int32 z, Direction dir, DirectionMode dirmode); 80 81 //! Update the fast area for the cameras position 82 void updateFastArea(int32 from_x, int32 from_y, int32 from_z, int32 to_x, int32 to_y, int32 to_z); 83 84 //! search an area for items matching a loopscript 85 //! \param itemlist the list to return objids in 86 //! \param loopscript the script to check items against 87 //! \param scriptsize the size (in bytes) of the loopscript 88 //! \param item the item around which you want to search, or 0. 89 //! if item is 0, search around (x,y) 90 //! \param range the (square) range to search 91 //! \param recurse if true, search in containers too 92 //! \param x x coordinate of search center if item is 0. 93 //! \param y y coordinate of search center if item is 0. 94 void areaSearch(UCList *itemlist, const uint8 *loopscript, 95 uint32 scriptsize, const Item *item, uint16 range, 96 bool recurse, int32 x = 0, int32 y = 0) const; 97 98 // Surface search: Search above and below an item. 99 void surfaceSearch(UCList *itemlist, const uint8 *loopscript, 100 uint32 scriptsize, const Item *item, bool above, 101 bool below, bool recurse = false) const; 102 103 // Surface search: Search above and below an item. 104 void surfaceSearch(UCList *itemlist, const uint8 *loopscript, 105 uint32 scriptsize, ObjId id, 106 int32 origin[3], int32 dims[2], 107 bool above, bool below, bool recurse = false) const; 108 109 // Collision detection. Returns true if the box [x,y,z]-[x-xd,y-yd,z+zd] 110 // does not collide with any solid items. 111 // Additionally: 112 // * If support is not NULL, *support is set to the item supporting 113 // the given box, or 0 if it isn't supported. 114 // * If roof is not NULL, *roof is set to the roof item with the lowest 115 // z coordinate that's over the box, or 0 if there is no roof above box. 116 // * If blocker is not NULL, *blocker will be set to an item blocking 117 // the whole box if there is one, or 0 if there is no such item. 118 // Ignores collisions which were already occurring at the start position. 119 // NB: isValidPosition doesn't consider item 'item'. 120 bool isValidPosition(int32 x, int32 y, int32 z, 121 int32 startx, int32 starty, int32 startz, 122 int xd, int yd, int zd, uint32 shapeflags, 123 ObjId item, const Item **support = 0, 124 ObjId *roof = 0, const Item **blocker = 0) const; 125 126 // Note that this version of isValidPosition does not look for start 127 // position collisions. 128 bool isValidPosition(int32 x, int32 y, int32 z, 129 int xd, int yd, int zd, uint32 shapeflags, 130 ObjId item, const Item **support = 0, 131 ObjId *roof = 0, const Item **blocker = 0) const; 132 133 // Note that this version of isValidPosition can not take 'flipped' 134 // into account! 135 bool isValidPosition(int32 x, int32 y, int32 z, uint32 shape, 136 ObjId item, const Item **support = 0, 137 ObjId *roof = 0, const Item **blocker = 0) const; 138 139 //! Scan for a valid position for item in directions orthogonal to movedir 140 bool scanForValidPosition(int32 x, int32 y, int32 z, const Item *item, 141 Direction movedir, bool wantsupport, 142 int32 &tx, int32 &ty, int32 &tz); 143 144 struct SweepItem { SweepItemSweepItem145 SweepItem(ObjId it, int32 ht, int32 et, bool touch, 146 bool touchfloor, bool block, uint8 dir) 147 : _item(it), _hitTime(ht), _endTime(et), _touching(touch), 148 _touchingFloor(touchfloor), _blocking(block), _dirs(dir) { } 149 150 ObjId _item; // Item that was hit 151 152 // 153 // The time values here are 'normalized' fixed point values 154 // They range from 0 for the start of the move to 0x4000 for the end of 155 // The move. 156 // 157 // Linear interpolate between the start and end positions using 158 // hit_time to find where the moving item was when the hit occurs 159 // 160 161 int32 _hitTime; // if -1, already hitting when sweep started. 162 int32 _endTime; // if 0x4000, still hitting when sweep finished 163 164 bool _touching; // We are only touching (don't actually overlap) 165 bool _touchingFloor; // touching and directly below the moving item 166 167 bool _blocking; // This item blocks the moving item 168 169 uint8 _dirs; // Directions in which the item is being hit. 170 // Bitmask. Bit 0 is x, 1 is y, 2 is z. 171 172 // Use this func to get the interpolated location of the hit GetInterpolatedCoordsSweepItem173 void GetInterpolatedCoords(int32 out[3], const int32 start[3], const int32 end[3]) const { 174 for (int i = 0; i < 3; i++) 175 out[i] = start[i] + ((end[i] - start[i]) * (_hitTime >= 0 ? _hitTime : 0) + (end[i] > start[i] ? 0x2000 : -0x2000)) / 0x4000; 176 } 177 }; 178 179 //! Perform a sweepTest for an item move 180 //! \param start Start point to sweep from. 181 //! \param end End point to sweep to. 182 //! \param dims Bounding size of item to check. 183 //! \param shapeflags shapeflags of item to check. 184 //! \param item ObjId of the item being checked. This will allow item to 185 //! be skipped from being tested against. Use 0 for no item. 186 //! \param solid_only If true, only test solid items. 187 //! \param hit Pointer to a list to fill with items hit. Items are sorted 188 //! by SweepItem::hit_time 189 //! \return false if no items were hit. 190 //! true if any items were hit. 191 bool sweepTest(const int32 start[3], const int32 end[3], 192 const int32 dims[3], uint32 shapeflags, 193 ObjId item, bool solid_only, Std::list<SweepItem> *hit) const; 194 195 TeleportEgg *findDestination(uint16 id); 196 197 // Not allowed to modify the list. Remember to use const_iterator 198 const Std::list<Item *> *getItemList(int32 gx, int32 gy) const; 199 isChunkFast(int32 cx,int32 cy)200 bool isChunkFast(int32 cx, int32 cy) const { 201 // CONSTANTS! 202 if (cx < 0 || cy < 0 || cx >= MAP_NUM_CHUNKS || cy >= MAP_NUM_CHUNKS) 203 return false; 204 return (_fast[cy][cx / 32] & (1 << (cx & 31))) != 0; 205 } 206 207 // A simple trace to find the top item at a specific xy point 208 const Item *traceTopItem(int32 x, int32 y, int32 ztop, int32 zbot, ObjId ignore, uint32 shflags); 209 210 // Set the entire map as being 'fast' 211 void setWholeMapFast(); 212 213 void save(Common::WriteStream *ws); 214 bool load(Common::ReadStream *rs, uint32 version); 215 216 INTRINSIC(I_canExistAt); 217 INTRINSIC(I_canExistAtPoint); 218 219 private: 220 void loadItems(const Std::list<Item *> &itemlist, bool callCacheIn); 221 void createEggHatcher(); 222 223 //! clip the given map chunk numbers to iterate over them safely 224 static void clipMapChunks(int &minx, int &maxx, int &miny, int &maxy); 225 226 Map *_currentMap; 227 228 // item lists. Lots of them :-) 229 // items[x][y] 230 Std::list<Item *> _items[MAP_NUM_CHUNKS][MAP_NUM_CHUNKS]; 231 232 ProcId _eggHatcher; 233 234 // Fast area bit masks -> fast[ry][rx/32]&(1<<(rx&31)); 235 uint32 _fast[MAP_NUM_CHUNKS][MAP_NUM_CHUNKS / 32]; 236 int32 _fastXMin, _fastYMin, _fastXMax, _fastYMax; 237 238 int _mapChunkSize; 239 240 //! Items that are "targetable" in Crusader. It might be faster to store 241 //! this in a more fancy data structure, but this works fine. 242 ObjId _targets[MAP_NUM_TARGET_ITEMS]; 243 244 void setChunkFast(int32 cx, int32 cy); 245 void unsetChunkFast(int32 cx, int32 cy); 246 }; 247 248 } // End of namespace Ultima8 249 } // End of namespace Ultima 250 251 #endif 252