1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2003 The GemRB Project
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 *
19 */
20
21 #include "TileMap.h"
22
23 #include "Interface.h"
24 #include "Video.h"
25
26 #include "Scriptable/Container.h"
27 #include "Scriptable/Door.h"
28 #include "Scriptable/InfoPoint.h"
29
30 namespace GemRB {
31
TileMap(void)32 TileMap::TileMap(void)
33 {
34 }
35
~TileMap(void)36 TileMap::~TileMap(void)
37 {
38 ClearOverlays();
39
40 for (const InfoPoint *infoPoint : infoPoints) {
41 delete infoPoint;
42 }
43
44 for (const Door *door : doors) {
45 delete door;
46 }
47 }
48
49 //this needs in case of a tileset switch (for extended night)
ClearOverlays()50 void TileMap::ClearOverlays()
51 {
52 for (const TileOverlay *overlay : overlays) {
53 delete overlay;
54 }
55 for (const TileOverlay *rain : rain_overlays) {
56 delete rain;
57 }
58 overlays.clear();
59 rain_overlays.clear();
60 }
61
62 //tiled objects
AddTile(const char * ID,const char * Name,unsigned int Flags,unsigned short * openindices,int opencount,unsigned short * closeindices,int closecount)63 TileObject* TileMap::AddTile(const char *ID, const char* Name, unsigned int Flags,
64 unsigned short* openindices, int opencount, unsigned short* closeindices, int closecount)
65 {
66 TileObject* tile = new TileObject();
67 tile->Flags=Flags;
68 strnspccpy(tile->Name, Name, 32);
69 strnlwrcpy(tile->Tileset, ID, 8);
70 tile->SetOpenTiles( openindices, opencount );
71 tile->SetClosedTiles( closeindices, closecount );
72 tiles.push_back(tile);
73 return tile;
74 }
75
GetTile(unsigned int idx)76 TileObject* TileMap::GetTile(unsigned int idx)
77 {
78 if (idx >= tiles.size()) {
79 return NULL;
80 }
81 return tiles[idx];
82 }
83
84 //doors
AddDoor(const char * ID,const char * Name,unsigned int Flags,int ClosedIndex,unsigned short * indices,int count,DoorTrigger && dt)85 Door* TileMap::AddDoor(const char *ID, const char* Name, unsigned int Flags,
86 int ClosedIndex, unsigned short* indices, int count, DoorTrigger&& dt)
87 {
88 Door* door = new Door(overlays[0], std::move(dt));
89 door->Flags = Flags;
90 door->closedIndex = ClosedIndex;
91 door->SetTiles( indices, count );
92 door->SetName( ID );
93 door->SetScriptName( Name );
94 doors.push_back( door );
95 return door;
96 }
97
GetDoor(size_t idx) const98 Door* TileMap::GetDoor(size_t idx) const
99 {
100 if (idx >= doors.size()) {
101 return NULL;
102 }
103 return doors[idx];
104 }
105
GetDoor(const Point & p) const106 Door* TileMap::GetDoor(const Point &p) const
107 {
108 for (Door* door : doors) {
109 if (door->HitTest(p)) return door;
110 }
111 return NULL;
112 }
113
GetDoorByPosition(const Point & p) const114 Door* TileMap::GetDoorByPosition(const Point &p) const
115 {
116 for (Door *door : doors) {
117 if (door->toOpen[0].x==p.x && door->toOpen[0].y==p.y) {
118 return door;
119 }
120 if (door->toOpen[1].x==p.x && door->toOpen[1].y==p.y) {
121 return door;
122 }
123 }
124 return NULL;
125 }
126
GetDoor(const char * Name) const127 Door* TileMap::GetDoor(const char* Name) const
128 {
129 if (!Name) {
130 return NULL;
131 }
132 for (Door *door : doors) {
133 if (stricmp( door->GetScriptName(), Name ) == 0)
134 return door;
135 }
136 return NULL;
137 }
138
UpdateDoors()139 void TileMap::UpdateDoors()
140 {
141 for (Door *door : doors) {
142 door->SetNewOverlay(overlays[0]);
143 }
144 }
145
146 // used during time compression in bg1 ... but potentially problematic, so we don't enable it elsewhere
AutoLockDoors() const147 void TileMap::AutoLockDoors() const
148 {
149 if (!core->HasFeature(GF_RANDOM_BANTER_DIALOGS)) return;
150
151 for (Door *door : doors) {
152 if (door->CantAutoClose()) continue;
153 if (core->Roll(1, 2, -1)) continue; // just a guess
154 door->SetDoorOpen(false, false, 0);
155 }
156 }
157
158 //overlays, allow pushing of NULL
AddOverlay(TileOverlay * overlay)159 void TileMap::AddOverlay(TileOverlay* overlay)
160 {
161 if (overlay) {
162 if (overlay->w > XCellCount) {
163 XCellCount = overlay->w;
164 }
165 if (overlay->h > YCellCount) {
166 YCellCount = overlay->h;
167 }
168 }
169 overlays.push_back( overlay );
170 }
171
AddRainOverlay(TileOverlay * overlay)172 void TileMap::AddRainOverlay(TileOverlay* overlay)
173 {
174 if (overlay) {
175 if (overlay->w > XCellCount) {
176 XCellCount = overlay->w;
177 }
178 if (overlay->h > YCellCount) {
179 YCellCount = overlay->h;
180 }
181 }
182 rain_overlays.push_back( overlay );
183 }
184
DrawOverlays(const Region & viewport,bool rain,BlitFlags flags)185 void TileMap::DrawOverlays(const Region& viewport, bool rain, BlitFlags flags)
186 {
187 overlays[0]->Draw(viewport, rain ? rain_overlays : overlays, flags);
188 }
189
190 //containers
AddContainer(Container * c)191 void TileMap::AddContainer(Container *c)
192 {
193 containers.push_back(c);
194 }
195
GetContainer(unsigned int idx) const196 Container* TileMap::GetContainer(unsigned int idx) const
197 {
198 if (idx >= containers.size()) {
199 return NULL;
200 }
201 return containers[idx];
202 }
203
GetContainer(const char * Name) const204 Container* TileMap::GetContainer(const char* Name) const
205 {
206 for (Container *container : containers) {
207 if (stricmp(container->GetScriptName(), Name) == 0) {
208 return container;
209 }
210 }
211 return NULL;
212 }
213
214 //look for a container at position
215 //use type = IE_CONTAINER_PILE if you want to find ground piles only
216 //in this case, empty piles won't be found!
GetContainer(const Point & position,int type) const217 Container* TileMap::GetContainer(const Point &position, int type) const
218 {
219 for (Container *container : containers) {
220 if (type != -1 && type != container->Type) {
221 continue;
222 }
223
224 if (!container->BBox.PointInside(position)) continue;
225
226 //IE piles don't have polygons, the bounding box is enough for them
227 if (container->Type == IE_CONTAINER_PILE) {
228 //don't find empty piles if we look for any container
229 //if we looked only for piles, then we still return them
230 if ((type == -1) && !container->inventory.GetSlotCount()) {
231 continue;
232 }
233 return container;
234 } else if (container->outline->PointIn(position)) {
235 return container;
236 }
237 }
238 return NULL;
239 }
240
GetContainerByPosition(const Point & position,int type) const241 Container* TileMap::GetContainerByPosition(const Point &position, int type) const
242 {
243 for (Container *container : containers) {
244 if (type != -1 && type != container->Type) {
245 continue;
246 }
247
248 if (container->Pos.x != position.x || container->Pos.y != position.y) {
249 continue;
250 }
251
252 //IE piles don't have polygons, the bounding box is enough for them
253 if (container->Type == IE_CONTAINER_PILE) {
254 //don't find empty piles if we look for any container
255 //if we looked only for piles, then we still return them
256 if ((type == -1) && !container->inventory.GetSlotCount()) {
257 continue;
258 }
259 return container;
260 }
261 return container;
262 }
263 return NULL;
264 }
265
CleanupContainer(Container * container)266 int TileMap::CleanupContainer(Container *container)
267 {
268 if (container->Type!=IE_CONTAINER_PILE)
269 return 0;
270 if (container->inventory.GetSlotCount())
271 return 0;
272
273 for (size_t i = 0; i < containers.size(); i++) {
274 if (containers[i]==container) {
275 containers.erase(containers.begin()+i);
276 delete container;
277 return 1;
278 }
279 }
280 Log(ERROR, "TileMap", "Invalid container cleanup: %s",
281 container->GetScriptName());
282 return 1;
283 }
284
285 //infopoints
AddInfoPoint(const char * Name,unsigned short Type,std::shared_ptr<Gem_Polygon> outline)286 InfoPoint* TileMap::AddInfoPoint(const char* Name, unsigned short Type, std::shared_ptr<Gem_Polygon> outline)
287 {
288 InfoPoint* ip = new InfoPoint();
289 ip->SetScriptName( Name );
290 switch (Type) {
291 case 0:
292 ip->Type = ST_PROXIMITY;
293 break;
294
295 case 1:
296 ip->Type = ST_TRIGGER;
297 break;
298
299 case 2:
300 ip->Type = ST_TRAVEL;
301 break;
302 //this is just to satisfy whiny compilers
303 default:
304 ip->Type = ST_PROXIMITY;
305 break;
306 }
307 ip->outline = outline;
308 if (ip->outline)
309 ip->BBox = outline->BBox;
310 //ip->Active = true; //set active on creation
311 infoPoints.push_back( ip );
312 return ip;
313 }
314
315 //if detectable is set, then only detectable infopoints will be returned
GetInfoPoint(const Point & p,bool detectable) const316 InfoPoint* TileMap::GetInfoPoint(const Point &p, bool detectable) const
317 {
318 for (InfoPoint *infoPoint : infoPoints) {
319 //these flags disable any kind of user interaction
320 //scripts can still access an infopoint by name
321 if (infoPoint->Flags & (INFO_DOOR | TRAP_DEACTIVATED))
322 continue;
323
324 if (detectable) {
325 if (infoPoint->Type == ST_PROXIMITY && !infoPoint->VisibleTrap(0)) {
326 continue;
327 }
328 // skip portals without PORTAL_CURSOR set
329 if (infoPoint->IsPortal() && !(infoPoint->Trapped & PORTAL_CURSOR)) {
330 continue;
331 }
332 }
333
334 if (!(infoPoint->GetInternalFlag() & IF_ACTIVE))
335 continue;
336
337 if (infoPoint->outline) {
338 if (infoPoint->outline->PointIn(p)) {
339 return infoPoint;
340 }
341 } else if (infoPoint->BBox.PointInside(p)) {
342 return infoPoint;
343 }
344 }
345 return NULL;
346 }
347
GetInfoPoint(const char * Name) const348 InfoPoint* TileMap::GetInfoPoint(const char* Name) const
349 {
350 for (InfoPoint *infoPoint : infoPoints) {
351 if (stricmp(infoPoint->GetScriptName(), Name) == 0) {
352 return infoPoint;
353 }
354 }
355 return NULL;
356 }
357
GetInfoPoint(unsigned int idx) const358 InfoPoint* TileMap::GetInfoPoint(unsigned int idx) const
359 {
360 if (idx >= infoPoints.size()) {
361 return NULL;
362 }
363 return infoPoints[idx];
364 }
365
GetTravelTo(const char * Destination) const366 InfoPoint* TileMap::GetTravelTo(const char* Destination) const
367 {
368 for (InfoPoint *infoPoint : infoPoints) {
369 if (infoPoint->Type != ST_TRAVEL) continue;
370
371 if (strnicmp(infoPoint->Destination, Destination, 8) == 0) {
372 return infoPoint;
373 }
374 }
375 return NULL;
376 }
377
AdjustNearestTravel(Point & p)378 InfoPoint *TileMap::AdjustNearestTravel(Point &p)
379 {
380 int min = -1;
381 InfoPoint *best = NULL;
382
383 for (InfoPoint *infoPoint : infoPoints) {
384 if (infoPoint->Type != ST_TRAVEL) continue;
385
386 unsigned int dist = Distance(p, infoPoint);
387 if (dist<(unsigned int) min) {
388 min = dist;
389 best = infoPoint;
390 }
391 }
392 if (best) {
393 p = best->Pos;
394 }
395 return best;
396 }
397
GetMapSize()398 Size TileMap::GetMapSize()
399 {
400 return Size((XCellCount*64), (YCellCount*64));
401 }
402
403 }
404