feat: expand Portal
This commit is contained in:
1 parent
a919a0bfe6
commit
e2cf8b6dcc
1 file changed
+146
@@ -315,3 +315,149 @@ int PortalNetwork::buildPortalNear(DimensionId dimension, const Vec3i& target) {
|
|||||||
bool natural = transit.findSafeSpot(dimension, target, radius, frame.height + 1, spot);
|
bool natural = transit.findSafeSpot(dimension, target, radius, frame.height + 1, spot);
|
||||||
if (!natural) spot = {target.x, cfg.clampY(target.y), target.z};
|
if (!natural) spot = {target.x, cfg.clampY(target.y), target.z};
|
||||||
|
|
||||||
|
if (spot.y - 1 < cfg.floorY || spot.y + frame.height >= cfg.ceilingY - 1) return -1;
|
||||||
|
|
||||||
|
frame.origin = spot;
|
||||||
|
if (!natural || !PortalScan::siteUsable(destination.world(), frame)) {
|
||||||
|
transit.carvePlatform(dimension, spot, 3, frame.height + 2);
|
||||||
|
if (!PortalScan::siteUsable(destination.world(), frame)) return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
PortalScan::buildFrame(destination.world(), frame);
|
||||||
|
if (PortalScan::light(destination.world(), frame) == 0) return -1;
|
||||||
|
return registerPortal(dimension, frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
PortalSearch PortalNetwork::travel(int entityId, int sourcePortalId, DimensionId to) {
|
||||||
|
PortalSearch search;
|
||||||
|
const PortalLink* source = portal(sourcePortalId);
|
||||||
|
if (!source || !source->active) return search;
|
||||||
|
if (!readyToTravel(entityId)) {
|
||||||
|
search.blocked = true;
|
||||||
|
return search;
|
||||||
|
}
|
||||||
|
|
||||||
|
DimensionId from = source->dimension;
|
||||||
|
Vec3i position = source->frame.entry();
|
||||||
|
|
||||||
|
std::vector<Vec3i> candidates;
|
||||||
|
std::vector<int> candidateIds;
|
||||||
|
for (const PortalLink& link : portals) {
|
||||||
|
if (!link.active || link.dimension != to) continue;
|
||||||
|
candidates.push_back(link.frame.entry());
|
||||||
|
candidateIds.push_back(link.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
search.plan = transit.plan(from, to, position, candidates);
|
||||||
|
|
||||||
|
if (!search.plan.needsPortal) {
|
||||||
|
std::size_t index = static_cast<std::size_t>(search.plan.nearestIndex);
|
||||||
|
search.found = true;
|
||||||
|
search.portalId = candidateIds[index];
|
||||||
|
search.position = candidates[index];
|
||||||
|
search.distanceSquared = search.plan.nearestDistanceSquared;
|
||||||
|
} else {
|
||||||
|
int raised = buildPortalNear(to, search.plan.target);
|
||||||
|
if (raised < 0) return search;
|
||||||
|
search.found = true;
|
||||||
|
search.built = true;
|
||||||
|
search.portalId = raised;
|
||||||
|
search.position = portals[static_cast<std::size_t>(raised)].frame.entry();
|
||||||
|
}
|
||||||
|
|
||||||
|
linkPortals(sourcePortalId, search.portalId);
|
||||||
|
startCooldown(entityId);
|
||||||
|
return search;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortalNetwork::tickEntity(int entityId, bool insidePortal) {
|
||||||
|
int& remaining = cooldown[entityId];
|
||||||
|
int& charged = standing[entityId];
|
||||||
|
|
||||||
|
if (remaining > 0) {
|
||||||
|
--remaining;
|
||||||
|
charged = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (insidePortal) ++charged;
|
||||||
|
else charged = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PortalNetwork::standingTicks(int entityId) const {
|
||||||
|
auto it = standing.find(entityId);
|
||||||
|
return it == standing.end() ? 0 : it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PortalNetwork::cooldownTicks(int entityId) const {
|
||||||
|
auto it = cooldown.find(entityId);
|
||||||
|
return it == cooldown.end() ? 0 : it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PortalNetwork::readyToTravel(int entityId) const {
|
||||||
|
return cooldownTicks(entityId) == 0 && standingTicks(entityId) >= standingThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortalNetwork::startCooldown(int entityId) {
|
||||||
|
cooldown[entityId] = cooldownAfterTravel;
|
||||||
|
standing[entityId] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PortalNetwork::buildEndFrame(DimensionId dimension, const Vec3i& center) {
|
||||||
|
World& world = dimensions().dimension(dimension).world();
|
||||||
|
int placed = 0;
|
||||||
|
|
||||||
|
for (const Vec3i& offset : endRingOffsets) {
|
||||||
|
Vec3i slot = center + offset;
|
||||||
|
world.setBlock(slot.x, slot.y, slot.z, Block::EndPortalFrame);
|
||||||
|
++placed;
|
||||||
|
}
|
||||||
|
for (int dx = -1; dx <= 1; ++dx)
|
||||||
|
for (int dz = -1; dz <= 1; ++dz)
|
||||||
|
world.setBlock(center.x + dx, center.y, center.z + dz, Block::Air);
|
||||||
|
return placed;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PortalNetwork::hasEndEye(DimensionId dimension, const Vec3i& framePos) const {
|
||||||
|
const auto& sockets = eyes[dimensionIndex(dimension)];
|
||||||
|
return sockets.find(framePos) != sockets.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PortalNetwork::insertEndEye(DimensionId dimension, const Vec3i& framePos) {
|
||||||
|
World& world = dimensions().dimension(dimension).world();
|
||||||
|
if (world.blockAt(framePos.x, framePos.y, framePos.z) != Block::EndPortalFrame) return false;
|
||||||
|
if (!eyes[dimensionIndex(dimension)].insert(framePos).second) return false;
|
||||||
|
|
||||||
|
for (const Vec3i& offset : endRingOffsets) {
|
||||||
|
Vec3i center{framePos.x - offset.x, framePos.y - offset.y, framePos.z - offset.z};
|
||||||
|
activateEndPortal(dimension, center);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PortalNetwork::endEyeCount(DimensionId dimension, const Vec3i& center) const {
|
||||||
|
const World& world = dimensions().dimension(dimension).world();
|
||||||
|
int filled = 0;
|
||||||
|
|
||||||
|
for (const Vec3i& offset : endRingOffsets) {
|
||||||
|
Vec3i slot = center + offset;
|
||||||
|
if (world.blockAt(slot.x, slot.y, slot.z) != Block::EndPortalFrame) continue;
|
||||||
|
if (hasEndEye(dimension, slot)) ++filled;
|
||||||
|
}
|
||||||
|
return filled;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PortalNetwork::endFrameComplete(DimensionId dimension, const Vec3i& center) const {
|
||||||
|
return endEyeCount(dimension, center) == endFrameSlots;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PortalNetwork::activateEndPortal(DimensionId dimension, const Vec3i& center) {
|
||||||
|
if (!endFrameComplete(dimension, center)) return false;
|
||||||
|
|
||||||
|
World& world = dimensions().dimension(dimension).world();
|
||||||
|
for (int dx = -1; dx <= 1; ++dx)
|
||||||
|
for (int dz = -1; dz <= 1; ++dz)
|
||||||
|
world.setBlock(center.x + dx, center.y, center.z + dz, Block::EndPortal);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace vf
|
||||||
Reference in new issue
Block a user