| 182 | } |
| 183 | |
| 184 | void ItemDrop::update(float dt, uint64_t) { |
| 185 | m_dropAge.update(world()->epochTime()); |
| 186 | |
| 187 | if (isMaster()) { |
| 188 | if (m_owningEntity.get() != NullEntityId) { |
| 189 | updateTaken(true); |
| 190 | } else { |
| 191 | // Rarely, check for other drops near us and combine with them if possible. |
| 192 | if (canTake() && m_mode.get() == Mode::Available && Random::randf() < m_combineChance) { |
| 193 | world()->findEntity(RectF::withCenter(position(), Vec2F::filled(m_combineRadius)), [&](EntityPtr const& entity) { |
| 194 | if (auto closeDrop = as<ItemDrop>(entity)) { |
| 195 | // Make sure not to try to merge with ourselves here. |
| 196 | if (closeDrop.get() != this && closeDrop->canTake() |
| 197 | && vmag(position() - closeDrop->position()) < m_combineRadius) { |
| 198 | if (m_item->couldStack(closeDrop->item()) == closeDrop->item()->count()) { |
| 199 | m_item->stackWith(closeDrop->take()); |
| 200 | m_dropAge.setElapsedTime(min(m_dropAge.elapsedTime(), closeDrop->m_dropAge.elapsedTime())); |
| 201 | |
| 202 | // Average the position and velocity of the drop we merged |
| 203 | // with |
| 204 | m_movementController.setPosition(m_movementController.position() |
| 205 | + world()->geometry().diff(closeDrop->position(), m_movementController.position()) / 2.0f); |
| 206 | m_movementController.setVelocity((m_movementController.velocity() + closeDrop->velocity()) / 2.0f); |
| 207 | return true; |
| 208 | } |
| 209 | } |
| 210 | } |
| 211 | return false; |
| 212 | }); |
| 213 | } |
| 214 | |
| 215 | MovementParameters parameters; |
| 216 | parameters.collisionEnabled = true; |
| 217 | parameters.gravityEnabled = true; |
| 218 | m_movementController.applyParameters(parameters); |
| 219 | } |
| 220 | |
| 221 | m_movementController.tickMaster(dt); |
| 222 | |
| 223 | m_intangibleTimer.tick(dt); |
| 224 | m_ageItemsTimer.update(world()->epochTime()); |
| 225 | |
| 226 | if ((m_mode.get() == Mode::Intangible || m_mode.get() == Mode::Available) && m_movementController.atWorldLimit()) |
| 227 | m_mode.set(Mode::Dead); |
| 228 | if (m_mode.get() == Mode::Intangible && m_intangibleTimer.ready()) |
| 229 | m_mode.set(Mode::Available); |
| 230 | if (!m_eternal && m_mode.get() == Mode::Available && m_dropAge.elapsedTime() > m_item->timeToLive()) |
| 231 | m_mode.set(Mode::Dead); |
| 232 | if (m_mode.get() == Mode::Taken && m_dropAge.elapsedTime() > m_afterTakenLife) |
| 233 | m_mode.set(Mode::Dead); |
| 234 | |
| 235 | if (m_mode.get() <= Mode::Available && m_ageItemsTimer.elapsedTime() > m_ageItemsEvery) { |
| 236 | if (Root::singleton().itemDatabase()->ageItem(m_item, m_ageItemsTimer.elapsedTime())) { |
| 237 | m_itemDescriptor.set(m_item->descriptor()); |
| 238 | updateCollisionPoly(); |
| 239 | } |
| 240 | m_ageItemsTimer.setElapsedTime(0.0); |
| 241 | } |
nothing calls this directly
no test coverage detected