feat: introduce nextRandom and cellCentre
This commit is contained in:
1 parent
65f36973cf
commit
12285e5542
1 file changed
+157
@@ -0,0 +1,157 @@
|
|||||||
|
#include "vf/Villager.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace vf {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
uint32_t nextRandom(uint32_t& state) {
|
||||||
|
state += 0x9e3779b9u;
|
||||||
|
uint32_t z = state;
|
||||||
|
z = (z ^ (z >> 16)) * 0x85ebca6bu;
|
||||||
|
z = (z ^ (z >> 13)) * 0xc2b2ae35u;
|
||||||
|
return z ^ (z >> 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3 cellCentre(const Vec3i& cell) {
|
||||||
|
return {static_cast<float>(cell.x) + 0.5f, static_cast<float>(cell.y),
|
||||||
|
static_cast<float>(cell.z) + 0.5f};
|
||||||
|
}
|
||||||
|
|
||||||
|
int squaredDistance(const Vec3i& a, const Vec3i& b) {
|
||||||
|
int dx = a.x - b.x;
|
||||||
|
int dy = a.y - b.y;
|
||||||
|
int dz = a.z - b.z;
|
||||||
|
return dx * dx + dy * dy + dz * dz;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int levelThresholds[villagerMaxLevel] = {0, 10, 70, 150, 250};
|
||||||
|
|
||||||
|
const int horizontalOffsets[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
|
||||||
|
|
||||||
|
// A point of interest is worked from the cell on top of it when it is solid,
|
||||||
|
// from its own cell when it is not, or from any walkable neighbour otherwise.
|
||||||
|
bool resolveStandCell(const World& world, const Vec3i& pos, Block block, const PathConfig& config,
|
||||||
|
Vec3i& outStand) {
|
||||||
|
if (!isSolid(block) && isStandable(world, pos, config)) {
|
||||||
|
outStand = pos;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Vec3i above{pos.x, pos.y + 1, pos.z};
|
||||||
|
if (isStandable(world, above, config)) {
|
||||||
|
outStand = above;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (int level = 0; level <= 1; ++level) {
|
||||||
|
for (const auto& offset : horizontalOffsets) {
|
||||||
|
Vec3i candidate{pos.x + offset[0], pos.y + level, pos.z + offset[1]};
|
||||||
|
if (isStandable(world, candidate, config)) {
|
||||||
|
outStand = candidate;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outStand = above;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool poiBlock(Block block) {
|
||||||
|
return block == Block::Bed || block == Block::Bell || isWorkstationBlock(block);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nothing under the feet any more, usually because the workstation the villager
|
||||||
|
// was standing on got mined out: drop it onto the first solid ground below and
|
||||||
|
// throw away the route it was walking.
|
||||||
|
bool settleVillager(const World& world, Villager& villager, const PathConfig& config) {
|
||||||
|
Vec3i cell = villager.cell();
|
||||||
|
if (isStandable(world, cell, config)) return false;
|
||||||
|
for (int drop = 1; drop <= 8; ++drop) {
|
||||||
|
Vec3i below{cell.x, cell.y - drop, cell.z};
|
||||||
|
if (!isStandable(world, below, config)) continue;
|
||||||
|
villager.body.position = cellCentre(below);
|
||||||
|
villager.path.clear();
|
||||||
|
villager.pathCursor = 0;
|
||||||
|
villager.hasGoal = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool withinVillage(const Vec3i& cell, const Vec3i& center, int radius) {
|
||||||
|
return std::abs(cell.x - center.x) <= radius && std::abs(cell.z - center.z) <= radius &&
|
||||||
|
std::abs(cell.y - center.y) <= radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
const char* villagerProfessionName(VillagerProfession profession) {
|
||||||
|
switch (profession) {
|
||||||
|
case VillagerProfession::Unemployed: return "unemployed";
|
||||||
|
case VillagerProfession::Nitwit: return "nitwit";
|
||||||
|
case VillagerProfession::Farmer: return "farmer";
|
||||||
|
case VillagerProfession::Fisherman: return "fisherman";
|
||||||
|
case VillagerProfession::Shepherd: return "shepherd";
|
||||||
|
case VillagerProfession::Fletcher: return "fletcher";
|
||||||
|
case VillagerProfession::Librarian: return "librarian";
|
||||||
|
case VillagerProfession::Cartographer: return "cartographer";
|
||||||
|
case VillagerProfession::Cleric: return "cleric";
|
||||||
|
case VillagerProfession::Armorer: return "armorer";
|
||||||
|
case VillagerProfession::Weaponsmith: return "weaponsmith";
|
||||||
|
case VillagerProfession::Toolsmith: return "toolsmith";
|
||||||
|
case VillagerProfession::Butcher: return "butcher";
|
||||||
|
case VillagerProfession::Leatherworker: return "leatherworker";
|
||||||
|
case VillagerProfession::Mason: return "mason";
|
||||||
|
case VillagerProfession::Count: break;
|
||||||
|
}
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool professionEmployable(VillagerProfession profession) {
|
||||||
|
return profession != VillagerProfession::Unemployed && profession != VillagerProfession::Nitwit;
|
||||||
|
}
|
||||||
|
|
||||||
|
Block workstationForProfession(VillagerProfession profession) {
|
||||||
|
switch (profession) {
|
||||||
|
case VillagerProfession::Farmer: return Block::Composter;
|
||||||
|
case VillagerProfession::Fisherman: return Block::Barrel;
|
||||||
|
case VillagerProfession::Shepherd: return Block::Loom;
|
||||||
|
case VillagerProfession::Fletcher: return Block::CraftingTable;
|
||||||
|
case VillagerProfession::Librarian: return Block::Lectern;
|
||||||
|
case VillagerProfession::Cartographer: return Block::CartographyTable;
|
||||||
|
case VillagerProfession::Cleric: return Block::BrewingStand;
|
||||||
|
case VillagerProfession::Armorer: return Block::Furnace;
|
||||||
|
case VillagerProfession::Weaponsmith: return Block::Grindstone;
|
||||||
|
case VillagerProfession::Toolsmith: return Block::SmithingTable;
|
||||||
|
case VillagerProfession::Butcher: return Block::FurnaceLit;
|
||||||
|
case VillagerProfession::Leatherworker: return Block::Cauldron;
|
||||||
|
case VillagerProfession::Mason: return Block::Stonecutter;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return Block::Air;
|
||||||
|
}
|
||||||
|
|
||||||
|
VillagerProfession professionForWorkstation(Block block) {
|
||||||
|
switch (block) {
|
||||||
|
case Block::Composter: return VillagerProfession::Farmer;
|
||||||
|
case Block::Barrel: return VillagerProfession::Fisherman;
|
||||||
|
case Block::Loom: return VillagerProfession::Shepherd;
|
||||||
|
case Block::CraftingTable: return VillagerProfession::Fletcher;
|
||||||
|
case Block::Lectern: return VillagerProfession::Librarian;
|
||||||
|
case Block::CartographyTable: return VillagerProfession::Cartographer;
|
||||||
|
case Block::BrewingStand: return VillagerProfession::Cleric;
|
||||||
|
case Block::Furnace: return VillagerProfession::Armorer;
|
||||||
|
case Block::Grindstone: return VillagerProfession::Weaponsmith;
|
||||||
|
case Block::SmithingTable: return VillagerProfession::Toolsmith;
|
||||||
|
case Block::FurnaceLit: return VillagerProfession::Butcher;
|
||||||
|
case Block::Cauldron: return VillagerProfession::Leatherworker;
|
||||||
|
case Block::Stonecutter: return VillagerProfession::Mason;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return VillagerProfession::Unemployed;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isWorkstationBlock(Block block) {
|
||||||
|
return professionForWorkstation(block) != VillagerProfession::Unemployed;
|
||||||
|
}
|
||||||
|
|
||||||
Reference in new issue
Block a user