feat: add assignVillagerWorkstation and assignVillagerBed to Villager
This commit is contained in:
1 parent
26f75858ef
commit
f5b4e59834
1 file changed
+164
@@ -309,3 +309,167 @@ Villager makeVillager(int id, const Vec3& position, uint32_t seed) {
|
||||
return villager;
|
||||
}
|
||||
|
||||
bool assignVillagerWorkstation(Villager& villager, PoiRegistry& pois) {
|
||||
if (!villager.alive || villager.profession == VillagerProfession::Nitwit) return false;
|
||||
if (villager.workstationIndex >= 0) return false;
|
||||
int index = pois.nearestFreeWorkstation(villager.cell(), villager.profession);
|
||||
if (index < 0) return false;
|
||||
if (!pois.claim(index, villager.id)) return false;
|
||||
villager.workstationIndex = index;
|
||||
if (villager.profession == VillagerProfession::Unemployed)
|
||||
villager.profession = pois.at(index).profession;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool assignVillagerBed(Villager& villager, PoiRegistry& pois) {
|
||||
if (!villager.alive || villager.bedIndex >= 0) return false;
|
||||
int index = pois.nearestFreeBed(villager.cell());
|
||||
if (index < 0) return false;
|
||||
if (!pois.claim(index, villager.id)) return false;
|
||||
villager.bedIndex = index;
|
||||
return true;
|
||||
}
|
||||
|
||||
void releaseVillagerPois(Villager& villager, PoiRegistry& pois) {
|
||||
pois.release(villager.workstationIndex);
|
||||
pois.release(villager.bedIndex);
|
||||
villager.workstationIndex = -1;
|
||||
villager.bedIndex = -1;
|
||||
villager.targetPoiIndex = -1;
|
||||
}
|
||||
|
||||
bool syncVillagerPois(Villager& villager, PoiRegistry& pois) {
|
||||
bool professionChanged = false;
|
||||
if (villager.workstationIndex >= 0) {
|
||||
const WorkstationPoi& poi = pois.at(villager.workstationIndex);
|
||||
if (!poi.valid || poi.ownerId != villager.id) {
|
||||
villager.workstationIndex = -1;
|
||||
if (villager.level <= 1) {
|
||||
villager.profession = VillagerProfession::Unemployed;
|
||||
villager.experience = 0;
|
||||
professionChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (villager.bedIndex >= 0) {
|
||||
const WorkstationPoi& bed = pois.at(villager.bedIndex);
|
||||
if (!bed.valid || bed.ownerId != villager.id) villager.bedIndex = -1;
|
||||
}
|
||||
return professionChanged;
|
||||
}
|
||||
|
||||
bool grantVillagerExperience(Villager& villager, int amount) {
|
||||
if (amount <= 0) return false;
|
||||
int before = villager.level;
|
||||
villager.experience += amount;
|
||||
villager.level = villagerLevelForExperience(villager.experience);
|
||||
return villager.level > before;
|
||||
}
|
||||
|
||||
void killVillager(Villager& villager, PoiRegistry& pois) {
|
||||
villager.alive = false;
|
||||
villager.health = 0.0f;
|
||||
villager.state = VillagerState::Dead;
|
||||
villager.activity = VillagerActivity::Idle;
|
||||
villager.path.clear();
|
||||
villager.pathCursor = 0;
|
||||
villager.hasGoal = false;
|
||||
releaseVillagerPois(villager, pois);
|
||||
}
|
||||
|
||||
bool damageVillager(Villager& villager, PoiRegistry& pois, float amount) {
|
||||
if (!villager.alive) return false;
|
||||
villager.health -= amount;
|
||||
if (villager.health > 0.0f) return false;
|
||||
killVillager(villager, pois);
|
||||
return true;
|
||||
}
|
||||
|
||||
VillagerActivity VillagerSchedule::activityAt(double dayFraction) const {
|
||||
if (dayFraction < wakeFraction) return VillagerActivity::Sleep;
|
||||
if (dayFraction < workStart) return VillagerActivity::Idle;
|
||||
if (dayFraction < meetStart) return VillagerActivity::Work;
|
||||
if (dayFraction < meetEnd) return VillagerActivity::Meet;
|
||||
if (dayFraction < workEnd) return VillagerActivity::Work;
|
||||
if (dayFraction < sleepStart) return VillagerActivity::Idle;
|
||||
return VillagerActivity::Sleep;
|
||||
}
|
||||
|
||||
VillagerActivity chooseVillagerActivity(const Villager& villager, const VillagerSchedule& schedule,
|
||||
const TimeOfDay& clock, bool villageThreatened) {
|
||||
if (!villager.alive) return VillagerActivity::Idle;
|
||||
if (villageThreatened) return VillagerActivity::Panic;
|
||||
|
||||
VillagerActivity planned = schedule.activityAt(clock.dayFraction());
|
||||
switch (planned) {
|
||||
case VillagerActivity::Work:
|
||||
if (villager.profession == VillagerProfession::Nitwit) return VillagerActivity::Idle;
|
||||
if (villager.workstationIndex < 0) return VillagerActivity::SeekWorkstation;
|
||||
return VillagerActivity::Work;
|
||||
case VillagerActivity::Sleep:
|
||||
if (villager.bedIndex < 0) return VillagerActivity::Idle;
|
||||
return VillagerActivity::Sleep;
|
||||
default:
|
||||
return planned;
|
||||
}
|
||||
}
|
||||
|
||||
bool villagerGoalFor(const Villager& villager, const PoiRegistry& pois, const Vec3i& villageCenter,
|
||||
VillagerActivity activity, Vec3i& outGoal, int& outPoiIndex) {
|
||||
outPoiIndex = -1;
|
||||
switch (activity) {
|
||||
case VillagerActivity::Work:
|
||||
if (villager.workstationIndex < 0) return false;
|
||||
outPoiIndex = villager.workstationIndex;
|
||||
outGoal = pois.at(outPoiIndex).standCell;
|
||||
return true;
|
||||
case VillagerActivity::SeekWorkstation: {
|
||||
int index = pois.nearestFreeWorkstation(villager.cell(), villager.profession);
|
||||
if (index < 0) return false;
|
||||
outPoiIndex = index;
|
||||
outGoal = pois.at(index).standCell;
|
||||
return true;
|
||||
}
|
||||
case VillagerActivity::Meet: {
|
||||
int index = pois.bellIndex();
|
||||
if (index >= 0 && pois.at(index).valid) {
|
||||
outPoiIndex = index;
|
||||
outGoal = pois.at(index).standCell;
|
||||
} else {
|
||||
outGoal = villageCenter;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case VillagerActivity::Sleep:
|
||||
if (villager.bedIndex < 0) return false;
|
||||
outPoiIndex = villager.bedIndex;
|
||||
outGoal = pois.at(outPoiIndex).standCell;
|
||||
return true;
|
||||
case VillagerActivity::Panic:
|
||||
if (villager.bedIndex >= 0 && pois.at(villager.bedIndex).valid) {
|
||||
outPoiIndex = villager.bedIndex;
|
||||
outGoal = pois.at(outPoiIndex).standCell;
|
||||
} else {
|
||||
outGoal = villageCenter;
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool repathVillager(const World& world, Villager& villager, const Vec3i& goal,
|
||||
const PathConfig& config) {
|
||||
std::vector<Vec3i> route = findPath(world, villager.cell(), goal, config);
|
||||
if (route.empty()) {
|
||||
villager.hasGoal = false;
|
||||
return false;
|
||||
}
|
||||
villager.path = std::move(route);
|
||||
villager.pathCursor = 0;
|
||||
villager.goalCell = goal;
|
||||
villager.hasGoal = true;
|
||||
villager.state = villager.path.size() == 1 ? VillagerState::AtTarget : VillagerState::Travelling;
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user