Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/game/interfaces/StarWorld.cpp
diff options
context:
space:
mode:
authorKae <80987908+Novaenia@users.noreply.github.com>2023-06-20 14:33:09 +1000
committerKae <80987908+Novaenia@users.noreply.github.com>2023-06-20 14:33:09 +1000
commit6352e8e3196f78388b6c771073f9e03eaa612673 (patch)
treee23772f79a7fbc41bc9108951e9e136857484bf4 /source/game/interfaces/StarWorld.cpp
parent6741a057e5639280d85d0f88ba26f000baa58f61 (diff)
everything everywhere
all at once
Diffstat (limited to 'source/game/interfaces/StarWorld.cpp')
-rw-r--r--source/game/interfaces/StarWorld.cpp153
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;
+}
+
+}