| 178 | } |
| 179 | |
| 180 | void MaterialItem::fire(FireMode mode, bool shifting, bool edgeTriggered) { |
| 181 | if (!initialized() || !ready()) |
| 182 | return; |
| 183 | |
| 184 | auto layer = (mode == FireMode::Primary || !twoHanded() ? TileLayer::Foreground : TileLayer::Background); |
| 185 | TileModificationList modifications; |
| 186 | |
| 187 | float radius = calcRadius(shifting); |
| 188 | |
| 189 | auto geo = world()->geometry(); |
| 190 | auto aimPosition = owner()->aimPosition(); |
| 191 | |
| 192 | if (!m_lastAimPosition) |
| 193 | m_lastAimPosition = aimPosition; |
| 194 | |
| 195 | unsigned steps = 1; |
| 196 | Vec2F diff = {}; |
| 197 | if (*m_lastAimPosition != aimPosition) { |
| 198 | diff = geo.diff(*m_lastAimPosition, aimPosition); |
| 199 | float magnitude = diff.magnitude(); |
| 200 | float limit = max(4.f, 64.f / radius); |
| 201 | if (magnitude > limit) { |
| 202 | diff = diff.normalized() * limit; |
| 203 | magnitude = limit; |
| 204 | } |
| 205 | |
| 206 | steps = (unsigned)ceil(magnitude * (Constants::pi / 2)); |
| 207 | } |
| 208 | |
| 209 | CollisionKind collisionKind = m_collisionOverride != TileCollisionOverride::None |
| 210 | ? collisionKindFromOverride(m_collisionOverride) |
| 211 | : Root::singleton().materialDatabase()->materialCollisionKind(m_material); |
| 212 | |
| 213 | size_t total = 0; |
| 214 | |
| 215 | if (m_blockSwap && owner()->inToolRange(aimPosition)) |
| 216 | total += blockSwap(radius, layer); |
| 217 | |
| 218 | for (unsigned i = 0; i != steps; ++i) { |
| 219 | auto placementOrigin = aimPosition + diff * (1.0f - (static_cast<float>(i) / steps)); |
| 220 | if (!owner()->inToolRange(placementOrigin)) |
| 221 | continue; |
| 222 | |
| 223 | for (Vec2I& pos : tileArea(radius, placementOrigin)) |
| 224 | modifications.emplaceAppend(pos, PlaceMaterial{layer, materialId(), placementHueShift(pos), m_collisionOverride}); |
| 225 | |
| 226 | // Make sure not to make any more modifications than we have consumables. |
| 227 | if (modifications.size() > count()) |
| 228 | modifications.resize(count()); |
| 229 | size_t failed = world()->applyTileModifications(modifications, collisionKind <= CollisionKind::Platform).size(); |
| 230 | if (failed < modifications.size()) { |
| 231 | size_t placed = modifications.size() - failed; |
| 232 | consume(placed); |
| 233 | total += placed; |
| 234 | } |
| 235 | } |
| 236 | |
| 237 | if (total) { |
nothing calls this directly
no test coverage detected