35 #define RENDER_CREATURE_BEHIND 0
43 m_localPlayer(nullptr)
51 for(
const auto& ground : m_ground) {
52 ground->draw(dest - m_drawElevation * scaleFactor, scaleFactor,
true, reDrawFlags, lightView);
53 m_drawElevation += ground->getElevation();
61 for(
const auto& item : m_bottomItems) {
62 item->draw(dest - m_drawElevation * scaleFactor, scaleFactor,
true, reDrawFlags, lightView);
64 m_drawElevation += item->getElevation();
69 for(
auto it = m_commonItems.rbegin(); it != m_commonItems.rend(); ++it) {
70 const auto& item = *it;
72 item->draw(dest - m_drawElevation * scaleFactor, scaleFactor,
true, reDrawFlags, lightView);
74 m_drawElevation += item->getElevation();
79 #if RENDER_CREATURE_BEHIND == 1
80 for(
const auto& creature : m_walkingCreatures) {
83 dest.
x + ((creature->getPosition().x - m_position.
x) *
Otc::TILE_PIXELS - m_drawElevation) * scaleFactor,
84 dest.
y + ((creature->getPosition().y - m_position.
y) *
Otc::TILE_PIXELS - m_drawElevation) * scaleFactor
85 ), scaleFactor, reDrawFlags, lightView);
88 for(
auto it = m_creatures.rbegin(); it != m_creatures.rend(); ++it) {
89 const auto& creature = *it;
90 if(creature->isWalking())
continue;
91 creature->draw(dest - m_drawElevation * scaleFactor, scaleFactor, reDrawFlags, lightView);
94 for(
const auto& creature : m_creatures) {
95 if(creature->isWalking())
continue;
96 creature->draw(dest - m_drawElevation * scaleFactor, scaleFactor, reDrawFlags, lightView);
99 for(
const auto& creature : m_walkingCreatures) {
102 dest.
x + ((creature->getPosition().x - m_position.
x) *
Otc::TILE_PIXELS - m_drawElevation) * scaleFactor,
103 dest.
y + ((creature->getPosition().y - m_position.
y) *
Otc::TILE_PIXELS - m_drawElevation) * scaleFactor
104 ), scaleFactor, reDrawFlags, lightView);
111 for(
const auto& effect : m_effects) {
112 effect->drawEffect(dest - m_drawElevation * scaleFactor, scaleFactor, reDrawFlags, lightView);
115 for(
const auto& item : m_topItems) {
116 item->draw(dest, scaleFactor,
true, reDrawFlags, lightView);
122 drawGround(dest, scaleFactor, reDrawFlags, lightView);
123 drawBottom(dest, scaleFactor, reDrawFlags, lightView);
124 drawTop(dest, scaleFactor, reDrawFlags, lightView);
129 m_bottomItems.clear();
132 m_commonItems.clear();
141 m_walkingCreatures.push_back(creature);
146 const auto it = std::find(m_walkingCreatures.begin(), m_walkingCreatures.end(), creature);
147 if(it != m_walkingCreatures.end())
148 m_walkingCreatures.erase(it);
158 if(thing->isEffect()) {
162 for(
const EffectPtr& firstEffect : m_effects) {
163 if(effect->getId() == firstEffect->getId()) {
164 effect->waitFor(firstEffect);
168 if(effect->isTopEffect())
169 m_effects.insert(m_effects.begin(), effect);
171 m_effects.push_back(effect);
174 thing->setPosition(m_position);
179 const uint8_t size = m_things.size();
180 uint8_t originalStack = stackPos;
189 if(stackPos < 0 || stackPos == 255) {
190 const int priority = thing->getStackPriority();
199 append = priority <= 3;
206 for(stackPos = 0; stackPos < size; ++stackPos) {
207 const int otherPriority = m_things[stackPos]->getStackPriority();
208 if((append && otherPriority > priority) || (!append && otherPriority >= priority))
211 }
else if(stackPos >
static_cast<int>(size))
214 m_things.insert(m_things.begin() + stackPos, thing);
216 if(thing->isCreature()) {
218 m_creatures.push_back(creature);
219 if(thing->isLocalPlayer()) m_localPlayer = creature;
221 const auto& item = thing->static_self_cast<
Item>();
223 if(item->hasAnimationPhases()) m_animatedItems.push_back(item);
225 if(thing->isGroundBorder() || thing->isGround()) {
226 m_ground.push_back(item);
227 }
else if(thing->isOnTop()) {
228 m_topItems.push_back(item);
229 }
else if(thing->isOnBottom()) {
230 m_bottomItems.push_back(item);
232 originalStack -= m_ground.size() + m_bottomItems.size() + m_creatures.size();
234 if(originalStack > m_commonItems.size()) {
235 m_commonItems.push_back(item);
237 m_commonItems.insert(m_commonItems.begin() + originalStack, item);
247 thing->setPosition(m_position);
250 if(thing->isTranslucent())
251 checkTranslucentLight();
257 if(!thing)
return false;
259 if(thing->isEffect()) {
261 const auto it = std::find(m_effects.begin(), m_effects.end(), effect);
262 if(it == m_effects.end())
271 const auto it = std::find(m_things.begin(), m_things.end(), thing);
272 if(it == m_things.end())
277 if(thing->isCreature()) {
278 const auto subIt = std::find(m_creatures.begin(), m_creatures.end(), thing->static_self_cast<
Creature>());
279 if(subIt != m_creatures.end()) {
280 if(thing->isLocalPlayer()) m_localPlayer =
nullptr;
281 m_creatures.erase(subIt);
284 const ItemPtr& item = thing->static_self_cast<
Item>();
287 const auto& subIt = std::find(m_animatedItems.begin(), m_animatedItems.end(), item);
288 if(subIt != m_animatedItems.end()) m_animatedItems.erase(subIt);
291 if(thing->isGroundBorder() || thing->isGround()) {
292 const auto& subIt = std::find(m_ground.begin(), m_ground.end(), item);
293 if(subIt != m_ground.end()) m_ground.erase(subIt);
294 }
else if(thing->isOnTop()) {
295 const auto& subIt = std::find(m_topItems.begin(), m_topItems.end(), item);
296 if(subIt != m_topItems.end()) m_topItems.erase(subIt);
297 }
else if(thing->isOnBottom()) {
298 const auto& subIt = std::find(m_bottomItems.begin(), m_bottomItems.end(), item);
299 if(subIt != m_bottomItems.end()) m_bottomItems.erase(subIt);
301 const auto& subIt = std::find(m_commonItems.begin(), m_commonItems.end(), item);
302 if(subIt != m_commonItems.end()) m_commonItems.erase(subIt);
308 thing->onDisappear();
310 if(thing->isTranslucent())
311 checkTranslucentLight();
318 if(stackPos >= 0 && stackPos <
static_cast<int>(m_things.size()))
319 return m_things[stackPos];
326 for(
int stackpos = -1, s = m_things.size(); ++stackpos < s;) {
327 if(thing == m_things[stackpos])
return stackpos;
335 return std::find(m_things.begin(), m_things.end(), thing) != m_things.end();
343 if(!m_commonItems.empty())
return m_commonItems.front();
345 return m_things[m_things.size() - 1];
350 std::vector<ItemPtr> items;
352 for(
const ThingPtr& thing : m_things) {
354 items.push_back(thing->static_self_cast<
Item>());
362 if(m_ground.empty())
return nullptr;
364 return m_ground.front();
370 if(effect->getId() ==
id)
379 return ground->getGroundSpeed();
386 if(m_minimapColor != 0)
387 return m_minimapColor;
389 if(!m_topItems.empty()) {
390 const uint8 c = m_topItems.back()->getMinimapColor();
394 if(!m_bottomItems.empty()) {
395 const uint8 c = m_bottomItems.back()->getMinimapColor();
401 const uint8 c = ground->getMinimapColor();
412 for(
auto it = m_topItems.rbegin(); it != m_topItems.rend(); ++it) {
417 if(!m_creatures.empty())
return m_creatures.back();
419 for(
const auto& item : m_commonItems) {
420 if(!item->isIgnoreLook())
return item;
423 for(
auto it = m_bottomItems.rbegin(); it != m_bottomItems.rend(); ++it) {
428 for(
auto it = m_ground.rbegin(); it != m_ground.rend(); ++it) {
440 for(
const auto& item : m_commonItems) {
441 if(item->isForceUse())
return item;
444 for(
auto it = m_bottomItems.rbegin(); it != m_bottomItems.rend(); ++it) {
449 for(
auto it = m_ground.rbegin(); it != m_ground.rend(); ++it) {
454 if(!m_topItems.empty())
return m_topItems.back();
455 if(!m_commonItems.empty())
return m_commonItems.front();
456 if(!m_bottomItems.empty())
return m_bottomItems.back();
458 return m_ground.front();
464 if(!m_creatures.empty())
465 return m_creatures.back();
467 if(!m_walkingCreatures.empty())
468 return m_walkingCreatures.back();
472 for(
int xi = -1; xi <= 1; ++xi) {
473 for(
int yi = -1; yi <= 1; ++yi) {
475 if(pos == m_position)
481 if(c->isWalking() && c->getLastStepFromPosition() == m_position && c->getStepProgress() < 0.75f) {
497 for(
const ThingPtr& thing : m_commonItems) {
498 if(!thing->isNotMoveable())
return thing;
513 for(
const ThingPtr& thing : m_commonItems) {
514 if(thing->isForceUse())
return thing;
517 for(
auto it = m_bottomItems.rbegin(); it != m_bottomItems.rend(); ++it) {
522 if(!m_commonItems.empty())
return m_commonItems.front();
523 if(!m_bottomItems.empty())
return m_bottomItems.back();
525 return m_ground.front();
530 if(m_countFlag.notWalkable > 0 || m_ground.empty()) {
534 if(!ignoreCreatures) {
536 if(!creature->isPassable() && creature->canBeSeen())
546 return m_countFlag.notPathable == 0;
551 return m_countFlag.fullGround > 0;
561 return m_countFlag.notSingleDimension == 0 && m_walkingCreatures.empty();
566 return m_countFlag.blockProjectile == 0;
571 return getTopLookThing() && (!m_ground.empty() || !m_bottomItems.empty());
576 return m_things.empty();
581 return m_walkingCreatures.empty() && m_effects.empty() &&
isEmpty() && m_flags == 0 && m_minimapColor == 0;
586 return !
isEmpty() || !m_walkingCreatures.empty() || !m_effects.empty();
591 for(
const ItemPtr& thing : m_bottomItems)
592 if(thing->isHookEast())
600 for(
const ItemPtr& thing : m_bottomItems)
601 if(thing->isHookSouth())
609 return !m_creatures.empty();
616 return firstThing && (firstThing->isGround() || (isFreeView ? firstThing->isOnBottom() && firstThing->blockProjectile() : firstThing->isOnBottom()));
621 return m_countFlag.elevation;
631 return m_countFlag.hasLight > 0;
634 void Tile::checkTranslucentLight()
640 if(!downPos.
down())
return;
646 for(
const ThingPtr& thing : m_things) {
647 if(thing->isTranslucent() || thing->hasLensHelp()) {
658 if(m_animatedItems.empty())
return;
660 for(
const ItemPtr& item : m_animatedItems)
661 item->cancelListenerPainter();
663 m_animatedItems.clear();
668 const int value = add ? 1 : -1;
670 if(thing->hasLight())
671 m_countFlag.hasLight += value;
673 if(thing->hasDisplacement())
674 m_countFlag.hasDisplacement += value;
676 if(thing->isEffect())
return;
681 m_countFlag.notSingleDimension += value;
683 if(thing->hasLight())
684 m_countFlag.hasLight += value;
686 if(!thing->isItem())
return;
688 if(thing->isNotWalkable())
689 m_countFlag.notWalkable += value;
691 if(thing->isNotPathable())
692 m_countFlag.notPathable += value;
694 if(thing->blockProjectile())
695 m_countFlag.blockProjectile += value;
697 if(thing->isHookEast())
698 m_countFlag.mustHookEast += value;
700 if(thing->isHookSouth())
701 m_countFlag.mustHookSouth += value;
703 m_countFlag.totalElevation += thing->getElevation() * value;
705 if(thing->isFullGround())
706 m_countFlag.fullGround += value;
708 if(thing->hasElevation())
709 m_countFlag.elevation += value;
711 if(thing->isOpaque())
712 m_countFlag.opaque += value;
715 if(thing->isOpaque() && !thing->isOnTop() && !thing->isGround() && !thing->isGroundBorder()) {
716 const int commonSize = m_commonItems.size();
717 if(m_countFlag.elevation > (add ? 3 : 2) && commonSize > 2) {
718 const ItemPtr& subItem = m_commonItems[1];
721 const ItemPtr& item = thing->static_self_cast<
Item>();
723 if(!thing->isOnBottom()) {
724 for(
const ItemPtr& subItem : m_commonItems) {
725 if(subItem != item) {
726 if(subItem->hasElevation() || subItem->isOpaque())
return;
728 if(subItem->getWidth() == 1 && subItem->getHeight() == 1) {
735 for(
auto it = m_bottomItems.rbegin(); it != m_bottomItems.rend(); ++it) {
737 if(subItem != item) {
746 for(
const ItemPtr& subItem : m_ground) {
747 if(subItem->hasElevation())
return;
749 if(subItem->getWidth() == 1 && subItem->getHeight() == 1) {
750 subItem->canDraw(!add);