bool Tile::removeThing(ThingPtr thing) { if(!thing) return false; bool removed = false; if(thing->isEffect()) { EffectPtr effect = thing->static_self_cast<Effect>(); auto it = std::find(m_effects.begin(), m_effects.end(), effect); if(it != m_effects.end()) { m_effects.erase(it); removed = true; } } else { auto it = std::find(m_things.begin(), m_things.end(), thing); if(it != m_things.end()) { m_things.erase(it); removed = true; } } thing->onDisappear(); if(thing->isTranslucent()) checkTranslucentLight(); return removed; }
void Map::addThing(const ThingPtr& thing, const Position& pos, int stackPos) { if(!thing) return; if(thing->isItem() || thing->isCreature() || thing->isEffect()) { const TilePtr& tile = getOrCreateTile(pos); if(tile) tile->addThing(thing, stackPos); } else { if(thing->isMissile()) { m_floorMissiles[pos.z].push_back(thing->static_self_cast<Missile>()); thing->onAppear(); } else if(thing->isAnimatedText()) { // this code will stack animated texts of the same color AnimatedTextPtr animatedText = thing->static_self_cast<AnimatedText>(); AnimatedTextPtr prevAnimatedText; bool merged = false; for(auto other : m_animatedTexts) { if(other->getPosition() == pos) { prevAnimatedText = other; if(other->merge(animatedText)) { merged = true; break; } } } if(!merged) { if(prevAnimatedText) { Point offset = prevAnimatedText->getOffset(); float t = prevAnimatedText->getTimer().ticksElapsed(); if(t < Otc::ANIMATED_TEXT_DURATION / 4.0) { // didnt move 12 pixels int y = 12 - 48 * t / (float)Otc::ANIMATED_TEXT_DURATION; offset += Point(0, y); } offset.y = std::min<int>(offset.y, 12); animatedText->setOffset(offset); } m_animatedTexts.push_back(animatedText); } } else if(thing->isStaticText()) { StaticTextPtr staticText = thing->static_self_cast<StaticText>(); bool mustAdd = true; for(auto other : m_staticTexts) { // try to combine messages if(other->getPosition() == pos && other->addMessage(staticText->getName(), staticText->getMessageMode(), staticText->getFirstMessage())) { mustAdd = false; break; } } if(mustAdd) m_staticTexts.push_back(staticText); else return; } thing->setPosition(pos); thing->onAppear(); } notificateTileUpdate(pos); }
void Tile::addThing(const ThingPtr& thing, int stackPos) { if(!thing) return; if(thing->isEffect()) { m_effects.push_back(thing->static_self_cast<Effect>()); } else { // priority 854 // 0 - ground, --> --> // 1 - ground borders --> --> // 2 - bottom (walls), --> --> // 3 - on top (doors) --> --> // 4 - creatures, from top to bottom <-- --> // 5 - items, from top to bottom <-- <-- if(stackPos < 0 || stackPos == 255) { int priority = thing->getStackPriority(); // -1 or 255 => auto detect position // -2 => append bool append; if(stackPos == -2) append = true; else { append = (priority <= 3); // newer protocols does not store creatures in reverse order if(g_game.getProtocolVersion() >= 854 && priority == 4) append = !append; } for(stackPos = 0; stackPos < (int)m_things.size(); ++stackPos) { int otherPriority = m_things[stackPos]->getStackPriority(); if((append && otherPriority > priority) || (!append && otherPriority >= priority)) break; } } else if(stackPos > (int)m_things.size()) stackPos = m_things.size(); m_things.insert(m_things.begin() + stackPos, thing); if(m_things.size() > MAX_THINGS) removeThing(m_things[MAX_THINGS]); /* // check stack priorities // this code exists to find stackpos bugs faster int lastPriority = 0; for(const ThingPtr& thing : m_things) { int priority = thing->getStackPriority(); assert(lastPriority <= priority); lastPriority = priority; } */ } thing->setPosition(m_position); thing->onAppear(); if(thing->isTranslucent()) checkTranslucentLight(); }