diff options
author | Kae <80987908+Novaenia@users.noreply.github.com> | 2023-06-20 14:33:09 +1000 |
---|---|---|
committer | Kae <80987908+Novaenia@users.noreply.github.com> | 2023-06-20 14:33:09 +1000 |
commit | 6352e8e3196f78388b6c771073f9e03eaa612673 (patch) | |
tree | e23772f79a7fbc41bc9108951e9e136857484bf4 /source/game/interfaces/StarWorld.cpp | |
parent | 6741a057e5639280d85d0f88ba26f000baa58f61 (diff) |
everything everywhere
all at once
Diffstat (limited to 'source/game/interfaces/StarWorld.cpp')
-rw-r--r-- | source/game/interfaces/StarWorld.cpp | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/source/game/interfaces/StarWorld.cpp b/source/game/interfaces/StarWorld.cpp new file mode 100644 index 0000000..5f416df --- /dev/null +++ b/source/game/interfaces/StarWorld.cpp @@ -0,0 +1,153 @@ +#include "StarWorld.hpp" +#include "StarScriptedEntity.hpp" + +namespace Star { + +bool World::isServer() const { + return connection() == ServerConnectionId; +} + +bool World::isClient() const { + return !isServer(); +} + +List<EntityPtr> World::entityQuery(RectF const& boundBox, EntityFilter selector) const { + List<EntityPtr> list; + forEachEntity(boundBox, [&](EntityPtr const& entity) { + if (!selector || selector(entity)) + list.append(entity); + }); + return list; +} + +List<EntityPtr> World::entityLineQuery(Vec2F const& begin, Vec2F const& end, EntityFilter selector) const { + List<EntityPtr> list; + forEachEntityLine(begin, end, [&](EntityPtr const& entity) { + if (!selector || selector(entity)) + list.append(entity); + }); + return list; +} + +List<TileEntityPtr> World::entitiesAtTile(Vec2I const& pos, EntityFilter selector) const { + List<TileEntityPtr> list; + forEachEntityAtTile(pos, [&](TileEntityPtr entity) { + if (!selector || selector(entity)) + list.append(move(entity)); + }); + return list; +} + +List<Vec2I> World::findEmptyTiles(Vec2I pos, unsigned maxDist, size_t maxAmount, bool excludeEphemeral) const { + List<Vec2I> res; + if (!tileIsOccupied(pos, TileLayer::Foreground, excludeEphemeral)) + res.append(pos); + + if (res.size() >= maxAmount) + return res; + + // searches manhattan distance counterclockwise from right + for (int distance = 1; distance <= (int)maxDist; distance++) { + const int totalSpots = 4 * distance; + int xDiff = distance; + int yDiff = 0; + int dx = -1; + int dy = 1; + for (int i = 0; i < totalSpots; i++) { + if (!tileIsOccupied(pos + Vec2I(xDiff, yDiff), TileLayer::Foreground)) { + res.append(pos + Vec2I(xDiff, yDiff)); + if (res.size() >= maxAmount) { + return res; + } + } + xDiff += dx; + yDiff += dy; + if (abs(xDiff) == distance) + dx *= -1; + if (abs(yDiff) == distance) + dy *= -1; + } + } + + return res; +} + +bool World::canModifyTile(Vec2I const& pos, TileModification const& modification, bool allowEntityOverlap) const { + return !validTileModifications({{pos, modification}}, allowEntityOverlap).empty(); +} + +bool World::modifyTile(Vec2I const& pos, TileModification const& modification, bool allowEntityOverlap) { + return applyTileModifications({{pos, modification}}, allowEntityOverlap).empty(); +} + +TileDamageResult World::damageTile(Vec2I const& tilePosition, TileLayer layer, Vec2F const& sourcePosition, TileDamage const& tileDamage, Maybe<EntityId> sourceEntity) { + return damageTiles({tilePosition}, layer, sourcePosition, tileDamage, sourceEntity); +} + +EntityPtr World::closestEntityInSight(Vec2F const& center, float radius, CollisionSet const& collisionSet, EntityFilter selector) const { + return closestEntity(center, radius, [=](EntityPtr const& entity) { + return selector(entity) && !lineTileCollision(center, entity->position(), collisionSet); + }); +} + +bool World::pointCollision(Vec2F const& point, CollisionSet const& collisionSet) const { + bool collided = false; + + forEachCollisionBlock(RectI::withCenter(Vec2I(point), {3, 3}), [&](CollisionBlock const& block) { + if (collided || !isColliding(block.kind, collisionSet)) + return; + + if (block.poly.contains(point)) + collided = true; + }); + + return collided; +} + +Maybe<pair<Vec2F, Maybe<Vec2F>>> World::lineCollision(Line2F const& line, CollisionSet const& collisionSet) const { + auto geometry = this->geometry(); + Maybe<PolyF> intersectPoly; + Maybe<PolyF::LineIntersectResult> closestIntersection; + + forEachCollisionBlock(RectI::integral(RectF::boundBoxOf(line.min(), line.max()).padded(1)), [&](CollisionBlock const& block) { + if (block.poly.isNull() || !isColliding(block.kind, collisionSet)) + return; + + Vec2F nearMin = geometry.nearestTo(block.poly.center(), line.min()); + auto intersection = block.poly.lineIntersection(Line2F(nearMin, nearMin + line.diff())); + if (intersection && (!closestIntersection || intersection->along < closestIntersection->along)) { + intersectPoly = block.poly; + closestIntersection = intersection; + } + }); + + if (closestIntersection) { + auto point = line.eval(closestIntersection->along); + auto normal = closestIntersection->intersectedSide.apply([&](uint64_t side) { return intersectPoly->normal(side); }); + return make_pair(point, normal); + } + return {}; +} + +bool World::polyCollision(PolyF const& poly, CollisionSet const& collisionSet) const { + auto geometry = this->geometry(); + Vec2F polyCenter = poly.center(); + PolyF translatedPoly; + bool collided = false; + + forEachCollisionBlock(RectI::integral(poly.boundBox()).padded(1), [&](CollisionBlock const& block) { + if (collided || !isColliding(block.kind, collisionSet)) + return; + + Vec2F center = block.poly.center(); + Vec2F newCenter = geometry.nearestTo(polyCenter, center); + translatedPoly = block.poly; + translatedPoly.translate(newCenter - center); + if (poly.intersects(translatedPoly)) + collided = true; + }); + + return collided; +} + +} |