1 /*
2 * Copyright 2010-2014 OpenXcom Developers.
3 *
4 * This file is part of OpenXcom.
5 *
6 * OpenXcom is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * OpenXcom 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
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with OpenXcom. If not, see <http://www.gnu.org/licenses/>.
18 */
19 #include "Tile.h"
20 #include "../Ruleset/MapData.h"
21 #include "../Ruleset/MapDataSet.h"
22 #include "../Engine/SurfaceSet.h"
23 #include "../Engine/Surface.h"
24 #include "../Engine/RNG.h"
25 #include "../Engine/Exception.h"
26 #include "BattleUnit.h"
27 #include "BattleItem.h"
28 #include "../Ruleset/RuleItem.h"
29 #include "../Ruleset/Armor.h"
30 #include "SerializationHelper.h"
31
32 namespace OpenXcom
33 {
34
35 /// How many bytes various fields use in a serialized tile. See header.
36 Tile::SerializationKey Tile::serializationKey =
37 {4, // index
38 2, // _mapDataSetID, four of these
39 2, // _mapDataID, four of these
40 1, // _fire
41 1, // _smoke
42 1, // one 8-bit bool field
43 4 + 2*4 + 2*4 + 1 + 1 + 1 // total bytes to save one tile
44 };
45
46 /**
47 * constructor
48 * @param pos Position.
49 */
Tile(const Position & pos)50 Tile::Tile(const Position& pos): _smoke(0), _fire(0), _explosive(0), _pos(pos), _unit(0), _animationOffset(0), _markerColor(0), _visible(false), _preview(-1), _TUMarker(0), _overlaps(0), _danger(false)
51 {
52 for (int i = 0; i < 4; ++i)
53 {
54 _objects[i] = 0;
55 _mapDataID[i] = -1;
56 _mapDataSetID[i] = -1;
57 _currentFrame[i] = 0;
58 }
59 for (int layer = 0; layer < LIGHTLAYERS; layer++)
60 {
61 _light[layer] = 0;
62 _lastLight[layer] = -1;
63 }
64 for (int i = 0; i < 3; ++i)
65 {
66 _discovered[i] = false;
67 }
68 }
69
70 /**
71 * destructor
72 */
~Tile()73 Tile::~Tile()
74 {
75 _inventory.clear();
76 }
77
78 /**
79 * Load the tile from a YAML node.
80 * @param node YAML node.
81 */
load(const YAML::Node & node)82 void Tile::load(const YAML::Node &node)
83 {
84 //_position = node["position"].as<Position>(_position);
85 for (int i = 0; i < 4; i++)
86 {
87 _mapDataID[i] = node["mapDataID"][i].as<int>(_mapDataID[i]);
88 _mapDataSetID[i] = node["mapDataSetID"][i].as<int>(_mapDataSetID[i]);
89 }
90 _fire = node["fire"].as<int>(_fire);
91 _smoke = node["smoke"].as<int>(_smoke);
92 for (int i = 0; i < 3; i++)
93 {
94 _discovered[i] = node["discovered"][i].as<bool>();
95 }
96 if (node["openDoorWest"])
97 {
98 _currentFrame[1] = 7;
99 }
100 if (node["openDoorNorth"])
101 {
102 _currentFrame[2] = 7;
103 }
104 }
105
106 /**
107 * Load the tile from binary.
108 * @param buffer Pointer to buffer.
109 * @param serKey Serialization key.
110 */
loadBinary(Uint8 * buffer,Tile::SerializationKey & serKey)111 void Tile::loadBinary(Uint8 *buffer, Tile::SerializationKey& serKey)
112 {
113 _mapDataID[0] = unserializeInt(&buffer, serKey._mapDataID);
114 _mapDataID[1] = unserializeInt(&buffer, serKey._mapDataID);
115 _mapDataID[2] = unserializeInt(&buffer, serKey._mapDataID);
116 _mapDataID[3] = unserializeInt(&buffer, serKey._mapDataID);
117 _mapDataSetID[0] = unserializeInt(&buffer, serKey._mapDataSetID);
118 _mapDataSetID[1] = unserializeInt(&buffer, serKey._mapDataSetID);
119 _mapDataSetID[2] = unserializeInt(&buffer, serKey._mapDataSetID);
120 _mapDataSetID[3] = unserializeInt(&buffer, serKey._mapDataSetID);
121
122 _smoke = unserializeInt(&buffer, serKey._smoke);
123 _fire = unserializeInt(&buffer, serKey._fire);
124
125 Uint8 boolFields = unserializeInt(&buffer, serKey.boolFields);
126 _discovered[0] = (boolFields & 1) ? true : false;
127 _discovered[1] = (boolFields & 2) ? true : false;
128 _discovered[2] = (boolFields & 4) ? true : false;
129 _currentFrame[1] = (boolFields & 8) ? 7 : 0;
130 _currentFrame[2] = (boolFields & 0x10) ? 7 : 0;
131 }
132
133
134 /**
135 * Saves the tile to a YAML node.
136 * @return YAML node.
137 */
save() const138 YAML::Node Tile::save() const
139 {
140 YAML::Node node;
141 node["position"] = _pos;
142 for (int i = 0; i < 4; i++)
143 {
144 node["mapDataID"].push_back(_mapDataID[i]);
145 node["mapDataSetID"].push_back(_mapDataSetID[i]);
146 }
147 if (_smoke)
148 node["smoke"] = _smoke;
149 if (_fire)
150 node["fire"] = _fire;
151 if (_discovered[0] || _discovered[1] || _discovered[2])
152 {
153 for (int i = 0; i < 3; i++)
154 {
155 node["discovered"].push_back(_discovered[i]);
156 }
157 }
158 if (isUfoDoorOpen(1))
159 {
160 node["openDoorWest"] = true;
161 }
162 if (isUfoDoorOpen(2))
163 {
164 node["openDoorNorth"] = true;
165 }
166 return node;
167 }
168
169 /**
170 * Saves the tile to binary.
171 * @param buffer pointer to buffer.
172 */
saveBinary(Uint8 ** buffer) const173 void Tile::saveBinary(Uint8** buffer) const
174 {
175 serializeInt(buffer, serializationKey._mapDataID, _mapDataID[0]);
176 serializeInt(buffer, serializationKey._mapDataID, _mapDataID[1]);
177 serializeInt(buffer, serializationKey._mapDataID, _mapDataID[2]);
178 serializeInt(buffer, serializationKey._mapDataID, _mapDataID[3]);
179 serializeInt(buffer, serializationKey._mapDataSetID, _mapDataSetID[0]);
180 serializeInt(buffer, serializationKey._mapDataSetID, _mapDataSetID[1]);
181 serializeInt(buffer, serializationKey._mapDataSetID, _mapDataSetID[2]);
182 serializeInt(buffer, serializationKey._mapDataSetID, _mapDataSetID[3]);
183
184 serializeInt(buffer, serializationKey._smoke, _smoke);
185 serializeInt(buffer, serializationKey._fire, _fire);
186
187 Uint8 boolFields = (_discovered[0]?1:0) + (_discovered[1]?2:0) + (_discovered[2]?4:0);
188 boolFields |= isUfoDoorOpen(1) ? 8 : 0; // west
189 boolFields |= isUfoDoorOpen(2) ? 0x10 : 0; // north?
190 serializeInt(buffer, serializationKey.boolFields, boolFields);
191 }
192
193 /**
194 * Set the MapData references of part 0 to 3.
195 * @param dat pointer to the data object
196 * @param mapDataID
197 * @param mapDataSetID
198 * @param part the part number
199 */
setMapData(MapData * dat,int mapDataID,int mapDataSetID,int part)200 void Tile::setMapData(MapData *dat, int mapDataID, int mapDataSetID, int part)
201 {
202 _objects[part] = dat;
203 _mapDataID[part] = mapDataID;
204 _mapDataSetID[part] = mapDataSetID;
205 }
206
207 /**
208 * get the MapData references of part 0 to 3.
209 * @param mapDataID
210 * @param mapDataSetID
211 * @param part the part number
212 * @return the object ID
213 */
getMapData(int * mapDataID,int * mapDataSetID,int part) const214 void Tile::getMapData(int *mapDataID, int *mapDataSetID, int part) const
215 {
216 *mapDataID = _mapDataID[part];
217 *mapDataSetID = _mapDataSetID[part];
218 }
219
220 /**
221 * Gets whether this tile has no objects. Note that we can have a unit or smoke on this tile.
222 * @return bool True if there is nothing but air on this tile.
223 */
isVoid() const224 bool Tile::isVoid() const
225 {
226 return _objects[0] == 0 && _objects[1] == 0 && _objects[2] == 0 && _objects[3] == 0 && _smoke == 0 && _inventory.empty();
227 }
228
229 /**
230 * Get the TU cost to walk over a certain part of the tile.
231 * @param part
232 * @param movementType
233 * @return TU cost
234 */
getTUCost(int part,MovementType movementType) const235 int Tile::getTUCost(int part, MovementType movementType) const
236 {
237 if (_objects[part])
238 {
239 if (_objects[part]->isUFODoor() && _currentFrame[part] == 7)
240 return 0;
241 if (_objects[part]->getBigWall() >= 4)
242 return 0;
243 return _objects[part]->getTUCost(movementType);
244 }
245 else
246 return 0;
247 }
248
249 /**
250 * Whether this tile has a floor or not. If no object defined as floor, it has no floor.
251 * @param tileBelow
252 * @return bool
253 */
hasNoFloor(Tile * tileBelow) const254 bool Tile::hasNoFloor(Tile *tileBelow) const
255 {
256 if (tileBelow != 0 && tileBelow->getTerrainLevel() == -24)
257 return false;
258 if (_objects[MapData::O_FLOOR])
259 return _objects[MapData::O_FLOOR]->isNoFloor();
260 else
261 return true;
262 }
263
264 /**
265 * Whether this tile has a big wall.
266 * @return bool
267 */
isBigWall() const268 bool Tile::isBigWall() const
269 {
270 if (_objects[MapData::O_OBJECT])
271 return (_objects[MapData::O_OBJECT]->getBigWall() != 0);
272 else
273 return false;
274 }
275
276 /**
277 * If an object stand on this tile, this returns how high the unit is it standing.
278 * @return the level in pixels
279 */
getTerrainLevel() const280 int Tile::getTerrainLevel() const
281 {
282 int level = 0;
283
284 if (_objects[MapData::O_FLOOR])
285 level = _objects[MapData::O_FLOOR]->getTerrainLevel();
286 if (_objects[MapData::O_OBJECT])
287 level += _objects[MapData::O_OBJECT]->getTerrainLevel();
288
289 return level;
290 }
291
292 /**
293 * Gets the tile's footstep sound.
294 * @param tileBelow
295 * @return sound ID
296 */
getFootstepSound(Tile * tileBelow) const297 int Tile::getFootstepSound(Tile *tileBelow) const
298 {
299 int sound = 0;
300
301 if (_objects[MapData::O_FLOOR])
302 sound = _objects[MapData::O_FLOOR]->getFootstepSound();
303 if (_objects[MapData::O_OBJECT] && _objects[MapData::O_OBJECT]->getBigWall() == 0)
304 sound = _objects[MapData::O_OBJECT]->getFootstepSound();
305 if (!_objects[MapData::O_FLOOR] && !_objects[MapData::O_OBJECT] && tileBelow != 0 && tileBelow->getTerrainLevel() == -24)
306 sound = tileBelow->getMapData(MapData::O_OBJECT)->getFootstepSound();
307
308 return sound;
309 }
310
311
312 /**
313 * Open a door on this tile.
314 * @param part
315 * @param unit
316 * @param reserve
317 * @return a value: 0(normal door), 1(ufo door) or -1 if no door opened or 3 if ufo door(=animated) is still opening 4 if not enough TUs
318 */
openDoor(int part,BattleUnit * unit,BattleActionType reserve)319 int Tile::openDoor(int part, BattleUnit *unit, BattleActionType reserve)
320 {
321 if (!_objects[part]) return -1;
322
323 if (_objects[part]->isDoor())
324 {
325 if (unit && unit->getTimeUnits() < _objects[part]->getTUCost(unit->getArmor()->getMovementType()) + unit->getActionTUs(reserve, unit->getMainHandWeapon(false)))
326 return 4;
327 if (_unit && _unit != unit && _unit->getPosition() != getPosition())
328 return -1;
329 setMapData(_objects[part]->getDataset()->getObjects()->at(_objects[part]->getAltMCD()), _objects[part]->getAltMCD(), _mapDataSetID[part],
330 _objects[part]->getDataset()->getObjects()->at(_objects[part]->getAltMCD())->getObjectType());
331 setMapData(0, -1, -1, part);
332 return 0;
333 }
334 if (_objects[part]->isUFODoor() && _currentFrame[part] == 0) // ufo door part 0 - door is closed
335 {
336 if (unit && unit->getTimeUnits() < _objects[part]->getTUCost(unit->getArmor()->getMovementType()) + unit->getActionTUs(reserve, unit->getMainHandWeapon(false)))
337 return 4;
338 _currentFrame[part] = 1; // start opening door
339 return 1;
340 }
341 if (_objects[part]->isUFODoor() && _currentFrame[part] != 7) // ufo door != part 7 - door is still opening
342 {
343 return 3;
344 }
345 return -1;
346 }
347
closeUfoDoor()348 int Tile::closeUfoDoor()
349 {
350 int retval = 0;
351
352 for (int part = 0; part < 4; part++)
353 {
354 if (isUfoDoorOpen(part))
355 {
356 _currentFrame[part] = 0;
357 retval = 1;
358 }
359 }
360
361 return retval;
362 }
363
364 /**
365 * Sets the tile's cache flag. - TODO: set this for each object separately?
366 * @param flag true/false
367 * @param part 0-2 westwall/northwall/content+floor
368 */
setDiscovered(bool flag,int part)369 void Tile::setDiscovered(bool flag, int part)
370 {
371 if (_discovered[part] != flag)
372 {
373 _discovered[part] = flag;
374 if (part == 2 && flag == true)
375 {
376 _discovered[0] = true;
377 _discovered[1] = true;
378 }
379 // if light on tile changes, units and objects on it change light too
380 if (_unit != 0)
381 {
382 _unit->setCache(0);
383 }
384 }
385 }
386
387 /**
388 * Get the black fog of war state of this tile.
389 * @param part 0-2 westwall/northwall/content+floor
390 * @return bool True = discovered the tile.
391 */
isDiscovered(int part) const392 bool Tile::isDiscovered(int part) const
393 {
394 return _discovered[part];
395 }
396
397
398 /**
399 * Reset the light amount on the tile. This is done before a light level recalculation.
400 * @param layer Light is separated in 3 layers: Ambient, Static and Dynamic.
401 */
resetLight(int layer)402 void Tile::resetLight(int layer)
403 {
404 _light[layer] = 0;
405 _lastLight[layer] = _light[layer];
406 }
407
408 /**
409 * Add the light amount on the tile. Only add light if the current light is lower.
410 * @param light Amount of light to add.
411 * @param layer Light is separated in 3 layers: Ambient, Static and Dynamic.
412 */
addLight(int light,int layer)413 void Tile::addLight(int light, int layer)
414 {
415 if (_light[layer] < light)
416 _light[layer] = light;
417 }
418
419 /**
420 * Gets the tile's shade amount 0-15. It returns the brightest of all light layers.
421 * Shade level is the inverse of light level. So a maximum amount of light (15) returns shade level 0.
422 * @return shade
423 */
getShade() const424 int Tile::getShade() const
425 {
426 int light = 0;
427
428 for (int layer = 0; layer < LIGHTLAYERS; layer++)
429 {
430 if (_light[layer] > light)
431 light = _light[layer];
432 }
433
434 return 15 - light;
435 }
436
437 /**
438 * Destroy a part on this tile. We first remove the old object, then replace it with the destroyed one.
439 * This is because the object type of the old and new one are not necessarily the same.
440 * If the destroyed part is an explosive, set the tile's explosive value, which will trigger a chained explosion.
441 * @param part
442 * @return bool Return true objective was destroyed
443 */
destroy(int part)444 bool Tile::destroy(int part)
445 {
446 bool _objective = false;
447 if (_objects[part])
448 {
449 if (_objects[part]->isGravLift())
450 return false;
451 _objective = _objects[part]->getSpecialType() == MUST_DESTROY;
452 MapData *originalPart = _objects[part];
453 int originalMapDataSetID = _mapDataSetID[part];
454 setMapData(0, -1, -1, part);
455 if (originalPart->getDieMCD())
456 {
457 MapData *dead = originalPart->getDataset()->getObjects()->at(originalPart->getDieMCD());
458 setMapData(dead, originalPart->getDieMCD(), originalMapDataSetID, dead->getObjectType());
459 }
460 if (originalPart->getExplosive())
461 {
462 setExplosive(originalPart->getExplosive());
463 }
464 }
465 /* check if the floor on the lowest level is gone */
466 if (part == MapData::O_FLOOR && getPosition().z == 0 && _objects[MapData::O_FLOOR] == 0)
467 {
468 /* replace with scorched earth */
469 setMapData(MapDataSet::getScorchedEarthTile(), 1, 0, MapData::O_FLOOR);
470 }
471 return _objective;
472 }
473
474 /**
475 * damage terrain - check against armor
476 * @param part Part to check.
477 * @param power Power of the damage.
478 * @return bool Return true objective was destroyed
479 */
damage(int part,int power)480 bool Tile::damage(int part, int power)
481 {
482 bool objective = false;
483 if (power >= _objects[part]->getArmor())
484 objective = destroy(part);
485 return objective;
486 }
487
488 /**
489 * Set a "virtual" explosive on this tile. We mark a tile this way to detonate it later.
490 * We do it this way, because the same tile can be visited multiple times by an "explosion ray".
491 * The explosive power on the tile is some kind of moving MAXIMUM of the explosive rays that passes it.
492 * @param power Power of the damage.
493 * @param force Force damage.
494 */
setExplosive(int power,bool force)495 void Tile::setExplosive(int power, bool force)
496 {
497 if (force || _explosive < power)
498 {
499 _explosive = power;
500 }
501 }
502
503 /**
504 * Get explosive on this tile.
505 * @return explosive
506 */
getExplosive() const507 int Tile::getExplosive() const
508 {
509 return _explosive;
510 }
511
512 /*
513 * Flammability of a tile is the lowest flammability of it's objects.
514 * @return Flammability : the lower the value, the higher the chance the tile/object catches fire.
515 */
getFlammability() const516 int Tile::getFlammability() const
517 {
518 int flam = 255;
519
520 if (_objects[3])
521 {
522 flam = _objects[3]->getFlammable();
523 }
524 else if (_objects[0])
525 {
526 flam = _objects[0]->getFlammable();
527 }
528
529 return flam;
530 }
531
532 /*
533 * Fuel of a tile is the lowest flammability of its objects.
534 * @return how long to burn.
535 */
getFuel() const536 int Tile::getFuel() const
537 {
538 int fuel = 0;
539
540 if (_objects[3])
541 {
542 fuel = _objects[3]->getFuel();
543 }
544 else if (_objects[0])
545 {
546 fuel = _objects[0]->getFuel();
547 }
548
549 return fuel;
550 }
551 /*
552 * Ignite starts fire on a tile, it will burn <fuel> rounds. Fuel of a tile is the highest fuel of its objects.
553 * NOT the sum of the fuel of the objects!
554 */
ignite(int power)555 void Tile::ignite(int power)
556 {
557 if (getFlammability() != 255)
558 {
559 power = power - (getFlammability() / 10) + 15;
560 if (power < 0)
561 {
562 power = 0;
563 }
564 if (RNG::percent(power))
565 {
566 if (_fire == 0)
567 {
568 _smoke = 15 - std::max(1, std::min((getFlammability() / 10), 12));
569 _overlaps = 1;
570 _fire = getFuel() + 1;
571 _animationOffset = RNG::generate(0,3);
572 }
573 }
574 }
575 }
576
577 /**
578 * Animate the tile. This means to advance the current frame for every object.
579 * Ufo doors are a bit special, they animated only when triggered.
580 * When ufo doors are on frame 0(closed) or frame 7(open) they are not animated further.
581 */
animate()582 void Tile::animate()
583 {
584 int newframe;
585 for (int i=0; i < 4; ++i)
586 {
587 if (_objects[i])
588 {
589 if (_objects[i]->isUFODoor() && (_currentFrame[i] == 0 || _currentFrame[i] == 7)) // ufo door is static
590 {
591 continue;
592 }
593 newframe = _currentFrame[i] + 1;
594 if (_objects[i]->isUFODoor() && _objects[i]->getSpecialType() == START_POINT && newframe == 3)
595 {
596 newframe = 7;
597 }
598 if (newframe == 8)
599 {
600 newframe = 0;
601 }
602 _currentFrame[i] = newframe;
603 }
604 }
605 }
606
607 /**
608 * Get the sprite of a certain part of the tile.
609 * @param part
610 * @return Pointer to the sprite.
611 */
getSprite(int part) const612 Surface *Tile::getSprite(int part) const
613 {
614 if (_objects[part] == 0)
615 return 0;
616
617 return _objects[part]->getDataset()->getSurfaceset()->getFrame(_objects[part]->getSprite(_currentFrame[part]));
618 }
619
620 /**
621 * Set a unit on this tile.
622 * @param unit
623 * @param tileBelow
624 */
setUnit(BattleUnit * unit,Tile * tileBelow)625 void Tile::setUnit(BattleUnit *unit, Tile *tileBelow)
626 {
627 if (unit != 0)
628 {
629 unit->setTile(this, tileBelow);
630 }
631 _unit = unit;
632 }
633
634 /**
635 * Set the amount of turns this tile is on fire. 0 = no fire.
636 * @param fire : amount of turns this tile is on fire.
637 */
setFire(int fire)638 void Tile::setFire(int fire)
639 {
640 _fire = fire;
641 _animationOffset = RNG::generate(0,3);
642 }
643
644 /**
645 * Get the amount of turns this tile is on fire. 0 = no fire.
646 * @return fire : amount of turns this tile is on fire.
647 */
getFire() const648 int Tile::getFire() const
649 {
650 return _fire;
651 }
652
653 /**
654 * Set the amount of turns this tile is smoking. 0 = no smoke.
655 * @param smoke : amount of turns this tile is smoking.
656 */
addSmoke(int smoke)657 void Tile::addSmoke(int smoke)
658 {
659 if (_fire == 0)
660 {
661 if (_overlaps == 0)
662 {
663 _smoke = std::max(1, std::min(_smoke + smoke, 15));
664 }
665 else
666 {
667 _smoke += smoke;
668 }
669 _animationOffset = RNG::generate(0,3);
670 addOverlap();
671 }
672 }
673
674 /**
675 * Set the amount of turns this tile is smoking. 0 = no smoke.
676 * @param smoke : amount of turns this tile is smoking.
677 */
setSmoke(int smoke)678 void Tile::setSmoke(int smoke)
679 {
680 _smoke = smoke;
681 _animationOffset = RNG::generate(0,3);
682 }
683
684
685 /**
686 * Get the amount of turns this tile is smoking. 0 = no smoke.
687 * @return smoke : amount of turns this tile is smoking.
688 */
getSmoke() const689 int Tile::getSmoke() const
690 {
691 return _smoke;
692 }
693
694 /**
695 * Get the number of frames the fire or smoke animation is off-sync.
696 * To void fire and smoke animations of different tiles moving nice in sync - it looks fake.
697 * @return offset
698 */
getAnimationOffset() const699 int Tile::getAnimationOffset() const
700 {
701 return _animationOffset;
702 }
703
704 /**
705 * Add an item on the tile.
706 * @param item
707 * @param ground
708 */
addItem(BattleItem * item,RuleInventory * ground)709 void Tile::addItem(BattleItem *item, RuleInventory *ground)
710 {
711 item->setSlot(ground);
712 _inventory.push_back(item);
713 item->setTile(this);
714 }
715
716 /**
717 * Remove an item from the tile.
718 * @param item
719 */
removeItem(BattleItem * item)720 void Tile::removeItem(BattleItem *item)
721 {
722 for (std::vector<BattleItem*>::iterator i = _inventory.begin(); i != _inventory.end(); ++i)
723 {
724 if ((*i) == item)
725 {
726 _inventory.erase(i);
727 break;
728 }
729 }
730 item->setTile(0);
731 }
732
733 /**
734 * Get the topmost item sprite to draw on the battlescape.
735 * @return item sprite ID in floorob, or -1 when no item
736 */
getTopItemSprite()737 int Tile::getTopItemSprite()
738 {
739 int biggestWeight = -1;
740 int biggestItem = -1;
741 for (std::vector<BattleItem*>::iterator i = _inventory.begin(); i != _inventory.end(); ++i)
742 {
743 if ((*i)->getRules()->getWeight() > biggestWeight)
744 {
745 biggestWeight = (*i)->getRules()->getWeight();
746 biggestItem = (*i)->getRules()->getFloorSprite();
747 }
748 }
749 return biggestItem;
750 }
751
752 /**
753 * New turn preparations.
754 * average out any smoke added by the number of overlaps.
755 * apply fire/smoke damage to units as applicable.
756 */
prepareNewTurn()757 void Tile::prepareNewTurn()
758 {
759 // we've recieved new smoke in this turn, but we're not on fire, average out the smoke.
760 if ( _overlaps != 0 && _smoke != 0 && _fire == 0)
761 {
762 _smoke = std::max(0, std::min((_smoke / _overlaps)- 1, 15));
763 }
764 // if we still have smoke/fire
765 if (_smoke)
766 {
767 if (_unit && !_unit->isOut())
768 {
769 if (_fire)
770 {
771 // this is how we avoid hitting the same unit multiple times.
772 if (_unit->getArmor()->getSize() == 1 || !_unit->tookFireDamage())
773 {
774 _unit->toggleFireDamage();
775 // _smoke becomes our damage value
776 _unit->damage(Position(0, 0, 0), _smoke, DT_IN, true);
777 // try to set the unit on fire.
778 if (RNG::percent(40 * _unit->getArmor()->getDamageModifier(DT_IN)))
779 {
780 int burnTime = RNG::generate(0, int(5 * _unit->getArmor()->getDamageModifier(DT_IN)));
781 if (_unit->getFire() < burnTime)
782 {
783 _unit->setFire(burnTime);
784 }
785 }
786 }
787 }
788 // no fire: must be smoke
789 else
790 {
791 // aliens don't breathe
792 if (_unit->getOriginalFaction() != FACTION_HOSTILE)
793 {
794 // try to knock this guy out.
795 if (_unit->getArmor()->getDamageModifier(DT_SMOKE) > 0.0 && _unit->getArmor()->getSize() == 1)
796 {
797 _unit->damage(Position(0,0,0), (_smoke / 4) + 1, DT_SMOKE, true);
798 }
799 }
800 }
801 }
802 }
803 _overlaps = 0;
804 _danger = false;
805 }
806
807 /**
808 * Get the inventory on this tile.
809 * @return pointer to a vector of battleitems.
810 */
getInventory()811 std::vector<BattleItem *> *Tile::getInventory()
812 {
813 return &_inventory;
814 }
815
816
817 /**
818 * Set the marker color on this tile.
819 * @param color
820 */
setMarkerColor(int color)821 void Tile::setMarkerColor(int color)
822 {
823 _markerColor = color;
824 }
825
826 /**
827 * Get the marker color on this tile.
828 * @return color
829 */
getMarkerColor()830 int Tile::getMarkerColor()
831 {
832 return _markerColor;
833 }
834
835 /**
836 * Set the tile visible flag.
837 * @param visibility
838 */
setVisible(int visibility)839 void Tile::setVisible(int visibility)
840 {
841 _visible += visibility;
842 }
843
844 /**
845 * Get the tile visible flag.
846 * @return visibility
847 */
getVisible()848 int Tile::getVisible()
849 {
850 return _visible;
851 }
852
853 /**
854 * set the direction used for path previewing.
855 * @param dir
856 */
setPreview(int dir)857 void Tile::setPreview(int dir)
858 {
859 _preview = dir;
860 }
861
862 /**
863 * retrieve the direction stored by the pathfinding.
864 * @return preview
865 */
getPreview() const866 int Tile::getPreview() const
867 {
868 return _preview;
869 }
870
871 /**
872 * set the number to be displayed for pathfinding preview.
873 * @param tu
874 */
setTUMarker(int tu)875 void Tile::setTUMarker(int tu)
876 {
877 _TUMarker = tu;
878 }
879
880 /**
881 * get the number to be displayed for pathfinding preview.
882 * @return marker
883 */
getTUMarker() const884 int Tile::getTUMarker() const
885 {
886 return _TUMarker;
887 }
888
889 /**
890 * get the overlap value of this tile.
891 * @return overlap
892 */
getOverlaps() const893 int Tile::getOverlaps() const
894 {
895 return _overlaps;
896 }
897
898 /**
899 * increment the overlap value on this tile.
900 */
addOverlap()901 void Tile::addOverlap()
902 {
903 ++_overlaps;
904 }
905
906 /**
907 * set the danger flag on this tile.
908 */
setDangerous()909 void Tile::setDangerous()
910 {
911 _danger = true;
912 }
913
914 /**
915 * get the danger flag on this tile.
916 * @return the danger flag for this tile.
917 */
getDangerous()918 bool Tile::getDangerous()
919 {
920 return _danger;
921 }
922
923 }
924