feat: Implement GetNearest* routines

This commit is contained in:
Vsevolod Kremianskii 2020-12-29 15:31:00 +07:00
parent f8ada74c47
commit 85ba198dc4
7 changed files with 114 additions and 10 deletions

View file

@ -1001,6 +1001,25 @@ shared_ptr<Object> Area::createObject(ObjectType type, const string &blueprintRe
return move(object);
}
shared_ptr<SpatialObject> Area::getNearestObject(const glm::vec3 &origin, int nth, const std::function<bool(const std::shared_ptr<SpatialObject> &)> &predicate) {
vector<pair<shared_ptr<SpatialObject>, float>> candidates;
for (auto &object : _objects) {
if (predicate(object)) {
candidates.push_back(make_pair(object, object->distanceTo(origin)));
}
}
sort(candidates.begin(), candidates.end(), [](auto &left, auto &right) { return left.second < right.second; });
int numCandidates = static_cast<int>(candidates.size());
if (nth >= numCandidates) {
warn(boost::format("Area: getNearestObject: nth is out of bounds: %d/%d") % nth % numCandidates);
return nullptr;
}
return candidates[nth].first;
}
} // namespace game
} // namespace reone

View file

@ -106,6 +106,13 @@ public:
ObjectList &getObjectsByType(ObjectType type);
/**
* Find the nth nearest object for which the specified predicate returns true.
*
* @param nth a 0-based object index
*/
std::shared_ptr<SpatialObject> getNearestObject(const glm::vec3 &origin, int nth, const std::function<bool(const std::shared_ptr<SpatialObject> &)> &predicate);
// END Objects
// Cameras

View file

@ -37,6 +37,7 @@ enum class ObjectType {
Area = 0x1001,
Camera = 0x1002,
All = 0x7fff,
Invalid = 0x7fff
};

View file

@ -179,6 +179,11 @@ private:
script::Variable getLocked(const VariablesList &args, script::ExecutionContext &ctx);
script::Variable getModule(const VariablesList &args, script::ExecutionContext &ctx);
script::Variable getName(const VariablesList &args, script::ExecutionContext &ctx);
script::Variable getNearestCreature(const VariablesList &args, script::ExecutionContext &ctx);
script::Variable getNearestCreatureToLocation(const VariablesList &args, script::ExecutionContext &ctx);
script::Variable getNearestObject(const VariablesList &args, script::ExecutionContext &ctx);
script::Variable getNearestObjectByTag(const VariablesList &args, script::ExecutionContext &ctx);
script::Variable getNearestObjectToLocation(const VariablesList &args, script::ExecutionContext &ctx);
script::Variable getNextItemInInventory(const VariablesList &args, script::ExecutionContext &ctx);
script::Variable getObjectByTag(const VariablesList &args, script::ExecutionContext &ctx);
script::Variable getObjectType(const VariablesList &args, script::ExecutionContext &ctx);

View file

@ -76,7 +76,7 @@ void Routines::addKotorRoutines() {
add("ActionPutDownItem", Void, { Object }, &Routines::actionPutDownItem);
add("GetLastAttacker", Object, { Object });
add("ActionAttack", Void, { Object, Int }, &Routines::actionAttack);
add("GetNearestCreature", Object, { Int, Int, Object, Int, Int, Int, Int, Int });
add("GetNearestCreature", Object, { Int, Int, Object, Int, Int, Int, Int, Int }, &Routines::getNearestCreature);
add("ActionSpeakString", Void, { String, Int }, &Routines::actionSpeakString);
add("ActionPlayAnimation", Void, { Int, Float, Float }, &Routines::actionPlayAnimation);
add("GetDistanceToObject", Float, { Object }, &Routines::getDistanceToObject);
@ -264,10 +264,10 @@ void Routines::addKotorRoutines() {
add("GetPositionFromLocation", TVector, { Location }, &Routines::getPositionFromLocation);
add("EffectBodyFuel", Effect, { }, &Routines::effectBodyFuel);
add("GetFacingFromLocation", Float, { Location }, &Routines::getFacingFromLocation);
add("GetNearestCreatureToLocation", Object, { Int, Int, Location, Int, Int, Int, Int, Int });
add("GetNearestObject", Object, { Int, Object, Int });
add("GetNearestObjectToLocation", Object, { Int, Location, Int });
add("GetNearestObjectByTag", Object, { String, Object, Int });
add("GetNearestCreatureToLocation", Object, { Int, Int, Location, Int, Int, Int, Int, Int }, &Routines::getNearestCreatureToLocation);
add("GetNearestObject", Object, { Int, Object, Int }, &Routines::getNearestObject);
add("GetNearestObjectToLocation", Object, { Int, Location, Int }, &Routines::getNearestObjectToLocation);
add("GetNearestObjectByTag", Object, { String, Object, Int }, &Routines::getNearestObjectByTag);
add("IntToFloat", Float, { Int }, &Routines::intToFloat);
add("FloatToInt", Int, { Float }, &Routines::floatToInt);
add("StringToInt", Int, { String }, &Routines::stringToInt);

View file

@ -513,6 +513,78 @@ Variable Routines::createObject(const VariablesList &args, ExecutionContext &ctx
return static_pointer_cast<ScriptObject>(_game->module()->area()->createObject(objectType, blueprintResRef, location));
}
Variable Routines::getNearestCreature(const VariablesList &args, ExecutionContext &ctx) {
int firstCriteriaType = getInt(args, 0);
int firstCriteriaValue = getInt(args, 1);
auto target = getSpatialObjectOrCaller(args, 2, ctx);
int nth = getInt(args, 3, 1);
int secondCriteriaType = getInt(args, 4, -1);
int secondCriteriaValue = getInt(args, 5, -1);
int thirdCriteriaType = getInt(args, 6, -1);
int thirdCriteriaValue = getInt(args, 7, -1);
// TODO: handle criterias
shared_ptr<SpatialObject> object(_game->module()->area()->getNearestObject(target->position(), nth - 1, [](auto &object) {
return object->type() == ObjectType::Creature;
}));
return static_pointer_cast<ScriptObject>(object);
}
Variable Routines::getNearestCreatureToLocation(const VariablesList &args, ExecutionContext &ctx) {
int firstCriteriaType = getInt(args, 0);
int firstCriteriaValue = getInt(args, 1);
auto location = getLocationEngineType(args, 2);
int nth = getInt(args, 3, 1);
int secondCriteriaType = getInt(args, 4, -1);
int secondCriteriaValue = getInt(args, 5, -1);
int thirdCriteriaType = getInt(args, 6, -1);
int thirdCriteriaValue = getInt(args, 7, -1);
// TODO: handle criterias
shared_ptr<SpatialObject> object(_game->module()->area()->getNearestObject(location->position(), nth - 1, [](auto &object) {
return object->type() == ObjectType::Creature;
}));
return static_pointer_cast<ScriptObject>(object);
}
Variable Routines::getNearestObject(const VariablesList &args, ExecutionContext &ctx) {
auto objectType = static_cast<ObjectType>(getInt(args, 0, static_cast<int>(ObjectType::All)));
auto target = getSpatialObjectOrCaller(args, 1, ctx);
int nth = getInt(args, 2, 1);
shared_ptr<SpatialObject> object(_game->module()->area()->getNearestObject(target->position(), nth - 1, [&objectType](auto &object) {
return object->type() == objectType;
}));
return static_pointer_cast<ScriptObject>(object);
}
Variable Routines::getNearestObjectToLocation(const VariablesList &args, ExecutionContext &ctx) {
auto objectType = static_cast<ObjectType>(getInt(args, 0));
auto location = getLocationEngineType(args, 1);
int nth = getInt(args, 2, 1);
shared_ptr<SpatialObject> object(_game->module()->area()->getNearestObject(location->position(), nth - 1, [&objectType](auto &object) {
return object->type() == objectType;
}));
return static_pointer_cast<ScriptObject>(object);
}
Variable Routines::getNearestObjectByTag(const VariablesList &args, ExecutionContext &ctx) {
string tag(boost::to_lower_copy(getString(args, 0)));
auto target = getSpatialObjectOrCaller(args, 1, ctx);
int nth = getInt(args, 2, 1);
shared_ptr<SpatialObject> object(_game->module()->area()->getNearestObject(target->position(), nth - 1, [&tag](auto &object) {
return object->tag() == tag;
}));
return static_pointer_cast<ScriptObject>(object);
}
} // namespace game
} // namespace reone

View file

@ -76,7 +76,7 @@ void Routines::addTslRoutines() {
add("ActionPutDownItem", Void, { Object }, &Routines::actionPutDownItem);
add("GetLastAttacker", Object, { Object });
add("ActionAttack", Void, { Object, Int }, &Routines::actionAttack);
add("GetNearestCreature", Object, { Int, Int, Object, Int, Int, Int, Int, Int });
add("GetNearestCreature", Object, { Int, Int, Object, Int, Int, Int, Int, Int }, &Routines::getNearestCreature);
add("ActionSpeakString", Void, { String, Int }, &Routines::actionSpeakString);
add("ActionPlayAnimation", Void, { Int, Float, Float }, &Routines::actionPlayAnimation);
add("GetDistanceToObject", Float, { Object }, &Routines::getDistanceToObject);
@ -264,10 +264,10 @@ void Routines::addTslRoutines() {
add("GetPositionFromLocation", TVector, { Location }, &Routines::getPositionFromLocation);
add("EffectBodyFuel", Effect, { }, &Routines::effectBodyFuel);
add("GetFacingFromLocation", Float, { Location }, &Routines::getFacingFromLocation);
add("GetNearestCreatureToLocation", Object, { Int, Int, Location, Int, Int, Int, Int, Int });
add("GetNearestObject", Object, { Int, Object, Int });
add("GetNearestObjectToLocation", Object, { Int, Location, Int });
add("GetNearestObjectByTag", Object, { String, Object, Int });
add("GetNearestCreatureToLocation", Object, { Int, Int, Location, Int, Int, Int, Int, Int }, &Routines::getNearestCreatureToLocation);
add("GetNearestObject", Object, { Int, Object, Int }, &Routines::getNearestObject);
add("GetNearestObjectToLocation", Object, { Int, Location, Int }, &Routines::getNearestObjectToLocation);
add("GetNearestObjectByTag", Object, { String, Object, Int }, &Routines::getNearestObjectByTag);
add("IntToFloat", Float, { Int }, &Routines::intToFloat);
add("FloatToInt", Int, { Float }, &Routines::floatToInt);
add("StringToInt", Int, { String }, &Routines::stringToInt);