1 /***************************************************************************
2  *   Copyright (C) 2005-2019 by the FIFE team                              *
3  *   http://www.fifengine.net                                              *
4  *   This file is part of FIFE.                                            *
5  *                                                                         *
6  *   FIFE is free software; you can redistribute it and/or                 *
7  *   modify it under the terms of the GNU Lesser General Public            *
8  *   License as published by the Free Software Foundation; either          *
9  *   version 2.1 of the License, or (at your option) any later version.    *
10  *                                                                         *
11  *   This library is distributed in the hope that it will be useful,       *
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
14  *   Lesser General Public License for more details.                       *
15  *                                                                         *
16  *   You should have received a copy of the GNU Lesser General Public      *
17  *   License along with this library; if not, write to the                 *
18  *   Free Software Foundation, Inc.,                                       *
19  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
20  ***************************************************************************/
21 
22 // Standard C++ library includes
23 
24 // 3rd party library includes
25 
26 // FIFE includes
27 // These includes are split up in two parts, separated by one empty line
28 // First block: files included from the FIFE root src directory
29 // Second block: files included from the same folder
30 #include "util/log/logger.h"
31 #include "view/visual.h"
32 
33 #include "cell.h"
34 #include "cellcache.h"
35 #include "instance.h"
36 #include "layer.h"
37 
38 namespace FIFE {
39 
40 	static Logger _log(LM_STRUCTURES);
41 
Cell(int32_t coordint,ModelCoordinate coordinate,Layer * layer)42 	Cell::Cell(int32_t coordint, ModelCoordinate coordinate, Layer* layer):
43 		m_coordId(coordint),
44 		m_coordinate(coordinate),
45 		m_layer(layer),
46 		m_zone(NULL),
47 		m_transition(NULL),
48 		m_inserted(false),
49 		m_protect(false) {
50 	}
51 
~Cell()52 	Cell::~Cell() {
53 		// calls CellDeleteListener, e.g. for transition
54 		if (!m_deleteListeners.empty()) {
55 			std::vector<CellDeleteListener*>::iterator it = m_deleteListeners.begin();
56 			for (; it != m_deleteListeners.end(); ++it) {
57 				if (*it) {
58 					(*it)->onCellDeleted(this);
59 				}
60 			}
61 		}
62 		// remove cell from zone
63 		if (m_zone) {
64 			m_zone->removeCell(this);
65 		}
66 		// delete m_transition;
67 		if (m_transition) {
68 			deleteTransition();
69 		}
70 		// remove cell from cache (costs, narrow, area)
71 		m_layer->getCellCache()->removeCell(this);
72 	}
73 
addInstances(const std::list<Instance * > & instances)74 	void Cell::addInstances(const std::list<Instance*>& instances) {
75 		CellCache* cache = m_layer->getCellCache();
76 		for (std::list<Instance*>::const_iterator it = instances.begin(); it != instances.end(); ++it) {
77 			std::pair<std::set<Instance*>::iterator, bool> ret = m_instances.insert(*it);
78 			if (ret.second) {
79 				if ((*it)->isSpecialCost()) {
80 					cache->registerCost((*it)->getCostId(), (*it)->getCost());
81 					cache->addCellToCost((*it)->getCostId(), this);
82 				}
83 				if ((*it)->isSpecialSpeed()) {
84 					cache->setSpeedMultiplier(this, (*it)->getSpeed());
85 				}
86 				if ((*it)->getObject()->getArea() != "") {
87 					cache->addCellToArea((*it)->getObject()->getArea(), this);
88 				}
89 				callOnInstanceEntered(*it);
90 			}
91 		}
92 		updateCellBlockingInfo();
93 	}
94 
addInstance(Instance * instance)95 	void Cell::addInstance(Instance* instance) {
96 		std::pair<std::set<Instance*>::iterator, bool> ret = m_instances.insert(instance);
97 		if (ret.second) {
98 			CellCache* cache = m_layer->getCellCache();
99 			if (instance->isSpecialCost()) {
100 				cache->registerCost(instance->getCostId(), instance->getCost());
101 				cache->addCellToCost(instance->getCostId(), this);
102 			}
103 			if (instance->isSpecialSpeed()) {
104 				cache->setSpeedMultiplier(this, instance->getSpeed());
105 			}
106 			if (instance->getObject()->getArea() != "") {
107 				cache->addCellToArea(instance->getObject()->getArea(), this);
108 			}
109 			callOnInstanceEntered(instance);
110 			updateCellBlockingInfo();
111 		}
112 	}
113 
changeInstance(Instance * instance)114 	void Cell::changeInstance(Instance* instance) {
115 		updateCellBlockingInfo();
116 	}
117 
removeInstance(Instance * instance)118 	void Cell::removeInstance(Instance* instance) {
119 		if (m_instances.erase(instance) == 0) {
120 			FL_ERR(_log, "Tried to remove an instance from cell, but given instance could not be found.");
121 			return;
122 		}
123 		CellCache* cache = m_layer->getCellCache();
124 		if (instance->isSpecialCost()) {
125 			cache->removeCellFromCost(instance->getCostId(), this);
126 		}
127 		if (instance->isSpecialSpeed()) {
128 			cache->resetSpeedMultiplier(this);
129 			// try to find other speed value
130 			if (!m_instances.empty()) {
131 				std::set<Instance*>::iterator it = m_instances.begin();
132 				for (; it != m_instances.end(); ++it) {
133 					if ((*it)->isSpecialSpeed()) {
134 						cache->setSpeedMultiplier(this, (*it)->getSpeed());
135 						break;
136 					}
137 				}
138 			}
139 		}
140 		if (instance->getObject()->getArea() != "") {
141 			cache->removeCellFromArea(instance->getObject()->getArea(), this);
142 		}
143 		callOnInstanceExited(instance);
144 		updateCellBlockingInfo();
145 	}
146 
isNeighbor(Cell * cell)147 	bool Cell::isNeighbor(Cell* cell) {
148 		std::vector<Cell*>::iterator it = m_neighbors.begin();
149 		for (; it != m_neighbors.end(); ++it) {
150 			if (*it == cell) {
151 				return true;
152 			}
153 		}
154 		return false;
155 	}
156 
updateCellBlockingInfo()157 	void Cell::updateCellBlockingInfo() {
158 		CellTypeInfo old_type = m_type;
159 		m_coordinate.z = MIN_CELL_Z;
160 		if (!m_instances.empty()) {
161 			int32_t pos = -1;
162 			bool cellblock = (m_type == CTYPE_CELL_NO_BLOCKER || m_type == CTYPE_CELL_BLOCKER);
163 			for (std::set<Instance*>::iterator it = m_instances.begin(); it != m_instances.end(); ++it) {
164 				if (cellblock) {
165 					continue;
166 				}
167 				uint8_t stackpos = (*it)->getCellStackPosition();
168 				if (stackpos < pos) {
169 					continue;
170 				}
171 				// update cell z
172 				if (m_coordinate.z < (*it)->getLocationRef().getLayerCoordinates().z && (*it)->getObject()->isStatic()) {
173 					m_coordinate.z = (*it)->getLocationRef().getLayerCoordinates().z;
174 				}
175 				if ((*it)->getCellStackPosition() > pos) {
176 					pos = (*it)->getCellStackPosition();
177 					if ((*it)->isBlocking()) {
178 						if (!(*it)->getObject()->isStatic()) {
179 							m_type = CTYPE_DYNAMIC_BLOCKER;
180 						} else {
181 							m_type = CTYPE_STATIC_BLOCKER;
182 						}
183 					} else {
184 						m_type = CTYPE_NO_BLOCKER;
185 					}
186 				} else {
187 					// if positions are equal then static_blockers win
188 					if ((*it)->isBlocking() && m_type != CTYPE_STATIC_BLOCKER) {
189 						if (!(*it)->getObject()->isStatic()) {
190 							m_type = CTYPE_DYNAMIC_BLOCKER;
191 						} else {
192 							m_type = CTYPE_STATIC_BLOCKER;
193 						}
194 					}
195 				}
196 			}
197 		} else {
198 			if (m_type == CTYPE_STATIC_BLOCKER || m_type == CTYPE_DYNAMIC_BLOCKER) {
199 				m_type = CTYPE_NO_BLOCKER;
200 			}
201 		}
202 		if (Mathd::Equal(m_coordinate.z, MIN_CELL_Z)) {
203 			m_coordinate.z = 0;
204 		}
205 
206 		if (old_type != m_type) {
207 			bool block = (m_type == CTYPE_STATIC_BLOCKER ||
208 				m_type == CTYPE_DYNAMIC_BLOCKER || m_type == CTYPE_CELL_BLOCKER);
209 			m_layer->getCellCache()->setBlockingUpdate(true);
210 			callOnBlockingChanged(block);
211 		}
212 	}
213 
updateCellInfo()214 	void Cell::updateCellInfo() {
215 		updateCellBlockingInfo();
216 
217 		if (!m_deleteListeners.empty()) {
218 			m_deleteListeners.erase(
219 				std::remove(m_deleteListeners.begin(), m_deleteListeners.end(),
220 				(CellDeleteListener*)NULL),	m_deleteListeners.end());
221 		}
222 		if (!m_changeListeners.empty()) {
223 			m_changeListeners.erase(
224 				std::remove(m_changeListeners.begin(), m_changeListeners.end(),
225 				(CellChangeListener*)NULL),	m_changeListeners.end());
226 		}
227 	}
228 
defaultCost()229 	bool Cell::defaultCost() {
230 		return m_layer->getCellCache()->isDefaultCost(this);
231 	}
232 
setCostMultiplier(double multi)233 	void Cell::setCostMultiplier(double multi) {
234 		m_layer->getCellCache()->setCostMultiplier(this, multi);
235 	}
236 
getCostMultiplier()237 	double Cell::getCostMultiplier() {
238 		return m_layer->getCellCache()->getCostMultiplier(this);
239 	}
240 
resetCostMultiplier()241 	void Cell::resetCostMultiplier() {
242 		m_layer->getCellCache()->resetCostMultiplier(this);
243 	}
244 
defaultSpeed()245 	bool Cell::defaultSpeed() {
246 		return m_layer->getCellCache()->isDefaultSpeed(this);
247 	}
248 
setSpeedMultiplier(double multi)249 	void Cell::setSpeedMultiplier(double multi) {
250 		m_layer->getCellCache()->setSpeedMultiplier(this, multi);
251 	}
252 
getSpeedMultiplier()253 	double Cell::getSpeedMultiplier() {
254 		return m_layer->getCellCache()->getSpeedMultiplier(this);
255 	}
256 
resetSpeedMultiplier()257 	void Cell::resetSpeedMultiplier() {
258 		m_layer->getCellCache()->resetSpeedMultiplier(this);
259 	}
260 
getZone()261 	Zone* Cell::getZone() {
262 		return m_zone;
263 	}
264 
setZone(Zone * zone)265 	void Cell::setZone(Zone* zone) {
266 		m_zone = zone;
267 	}
268 
resetZone()269 	void Cell::resetZone() {
270 		m_inserted = false;
271 		m_zone = NULL;
272 	}
273 
isInserted()274 	bool Cell::isInserted() {
275 		return m_inserted;
276 	}
277 
setInserted(bool inserted)278 	void Cell::setInserted(bool inserted) {
279 		m_inserted = inserted;
280 	}
281 
isZoneProtected()282 	bool Cell::isZoneProtected() {
283 		return m_protect;
284 	}
285 
setZoneProtected(bool protect)286 	void Cell::setZoneProtected(bool protect) {
287 		m_protect = protect;
288 	}
289 
getCellType()290 	CellTypeInfo Cell::getCellType() {
291 		return m_type;
292 	}
293 
setCellType(CellTypeInfo type)294 	void Cell::setCellType(CellTypeInfo type) {
295 		m_type = type;
296 	}
297 
getInstances()298 	const std::set<Instance*>& Cell::getInstances() {
299 		return m_instances;
300 	}
301 
setCellId(int32_t id)302 	void Cell::setCellId(int32_t id) {
303 		m_coordId = id;
304 	}
305 
getCellId()306 	int32_t Cell::getCellId() {
307 		return m_coordId;
308 	}
309 
getLayerCoordinates() const310 	const ModelCoordinate Cell::getLayerCoordinates() const {
311 		return m_coordinate;
312 	}
313 
addNeighbor(Cell * cell)314 	void Cell::addNeighbor(Cell* cell) {
315 		m_neighbors.push_back(cell);
316 	}
317 
getNeighbors()318 	const std::vector<Cell*>& Cell::getNeighbors() {
319 		return m_neighbors;
320 	}
321 
resetNeighbors()322 	void Cell::resetNeighbors() {
323 		m_neighbors.clear();
324 		if (m_transition) {
325 			CellCache* cache = m_transition->m_layer->getCellCache();
326 			if (cache) {
327 				Cell* cell = cache->getCell(m_transition->m_mc);
328 				if (cell) {
329 					m_neighbors.push_back(cell);
330 				}
331 			}
332 		}
333 	}
334 
getLayer()335 	Layer* Cell::getLayer() {
336 		return m_layer;
337 	}
338 
createTransition(Layer * layer,const ModelCoordinate & mc,bool immediate)339 	void Cell::createTransition(Layer* layer, const ModelCoordinate& mc, bool immediate) {
340 		TransitionInfo* trans = new TransitionInfo(layer);
341 		// if layers are the same then it's a portal
342 		if (layer != m_layer) {
343 			trans->m_difflayer = true;
344 		}
345 		trans->m_immediate = immediate;
346 		trans->m_mc = mc;
347 
348 		deleteTransition();
349 
350 		m_transition = trans;
351 
352 		Cell* c = layer->getCellCache()->getCell(mc);
353 		if (c) {
354 			m_neighbors.push_back(c);
355 			c->addDeleteListener(this);
356 			m_layer->getCellCache()->addTransition(this);
357 		} else {
358 			delete m_transition;
359 			m_transition = NULL;
360 		}
361 	}
362 
deleteTransition()363 	void Cell::deleteTransition() {
364 		if (m_transition) {
365 			Cell* oldc = m_transition->m_layer->getCellCache()->getCell(m_transition->m_mc);
366 			std::vector<Cell*>::iterator it = m_neighbors.begin();
367 			for (; it != m_neighbors.end(); ++it) {
368 				if (*it == oldc) {
369 					m_neighbors.erase(it);
370 					break;
371 				}
372 			}
373 			oldc->removeDeleteListener(this);
374 			m_layer->getCellCache()->removeTransition(this);
375 			delete m_transition;
376 			m_transition = NULL;
377 		}
378 	}
379 
getTransition()380 	TransitionInfo* Cell::getTransition() {
381 		return m_transition;
382 	}
383 
addDeleteListener(CellDeleteListener * listener)384 	void Cell::addDeleteListener(CellDeleteListener* listener) {
385 		m_deleteListeners.push_back(listener);
386 	}
387 
removeDeleteListener(CellDeleteListener * listener)388 	void Cell::removeDeleteListener(CellDeleteListener* listener) {
389 		std::vector<CellDeleteListener*>::iterator it = m_deleteListeners.begin();
390 		for (; it != m_deleteListeners.end(); ++it) {
391 			if (*it == listener) {
392 				*it = NULL;
393 				break;
394 			}
395 		}
396 	}
397 
onCellDeleted(Cell * cell)398 	void Cell::onCellDeleted(Cell* cell) {
399 		std::vector<Cell*>::iterator it = m_neighbors.begin();
400 		for (; it != m_neighbors.end(); ++it) {
401 			if (*it == cell) {
402 				deleteTransition();
403 				break;
404 			}
405 		}
406 	}
407 
addChangeListener(CellChangeListener * listener)408 	void Cell::addChangeListener(CellChangeListener* listener) {
409 		m_changeListeners.push_back(listener);
410 	}
411 
removeChangeListener(CellChangeListener * listener)412 	void Cell::removeChangeListener(CellChangeListener* listener) {
413 		std::vector<CellChangeListener*>::iterator it = m_changeListeners.begin();
414 		for (; it != m_changeListeners.end(); ++it) {
415 			if (*it == listener) {
416 				*it = NULL;
417 				break;
418 			}
419 		}
420 	}
421 
callOnInstanceEntered(Instance * instance)422 	void Cell::callOnInstanceEntered(Instance* instance) {
423 		if (m_changeListeners.empty()) {
424 			return;
425 		}
426 
427 		std::vector<CellChangeListener*>::iterator i = m_changeListeners.begin();
428 		while (i != m_changeListeners.end()) {
429 			if (*i) {
430 				(*i)->onInstanceEnteredCell(this, instance);
431 			}
432 			++i;
433 		}
434 	}
435 
callOnInstanceExited(Instance * instance)436 	void Cell::callOnInstanceExited(Instance* instance) {
437 		if (m_changeListeners.empty()) {
438 			return;
439 		}
440 
441 		std::vector<CellChangeListener*>::iterator i = m_changeListeners.begin();
442 		while (i != m_changeListeners.end()) {
443 			if (*i) {
444 				(*i)->onInstanceExitedCell(this, instance);
445 			}
446 			++i;
447 		}
448 	}
449 
callOnBlockingChanged(bool blocks)450 	void Cell::callOnBlockingChanged(bool blocks) {
451 		if (m_changeListeners.empty()) {
452 			return;
453 		}
454 
455 		std::vector<CellChangeListener*>::iterator i = m_changeListeners.begin();
456 		while (i != m_changeListeners.end()) {
457 			if (*i) {
458 				(*i)->onBlockingChangedCell(this, m_type, blocks);
459 			}
460 			++i;
461 		}
462 	}
463 } // FIFE
464