Implement creature perception (sight and hearing)

This commit is contained in:
Vsevolod Kremianskii 2021-03-23 15:01:25 +07:00
parent 9c5be9b87a
commit 6d35fdb455
24 changed files with 483 additions and 148 deletions

View file

@ -499,6 +499,7 @@ set(GAME_HEADERS
src/game/party.h
src/game/path.h
src/game/pathfinder.h
src/game/perception.h
src/game/player.h
src/game/portrait.h
src/game/portraitutil.h
@ -615,6 +616,7 @@ set(GAME_SOURCES
src/game/party.cpp
src/game/path.cpp
src/game/pathfinder.cpp
src/game/perception.cpp
src/game/player.cpp
src/game/portraitutil.cpp
src/game/reputes.cpp
@ -637,6 +639,7 @@ set(GAME_SOURCES
src/game/script/routines_math.cpp
src/game/script/routines_rp.cpp
src/game/script/routines_party.cpp
src/game/script/routines_perception.cpp
src/game/script/routines_time.cpp
src/game/script/routines_tsl.cpp
src/game/script/routines_vars.cpp

View file

@ -73,6 +73,7 @@ void CreatureBlueprint::load(Creature &creature) {
loadItems(creature);
loadSoundSet(creature);
loadBodyBag(creature);
loadPerception(creature);
}
int CreatureBlueprint::getAppearanceFromUtc() const {
@ -131,6 +132,7 @@ void CreatureBlueprint::loadScripts(Creature &creature) {
creature._onSpawn = boost::to_lower_copy(_utc->getString("ScriptSpawn"));
creature._onDeath = boost::to_lower_copy(_utc->getString("ScriptDeath"));
creature._onUserDefined = boost::to_lower_copy(_utc->getString("ScriptUserDefine"));
creature._onNotice = boost::to_lower_copy(_utc->getString("ScriptOnNotice"));
}
void CreatureBlueprint::loadItems(Creature &creature) {
@ -155,6 +157,13 @@ void CreatureBlueprint::loadSoundSet(Creature &creature) {
void CreatureBlueprint::loadBodyBag(Creature &creature) {
}
void CreatureBlueprint::loadPerception(Creature &creature) {
int rangeIdx = _utc->getInt("PerceptionRange", 0);
shared_ptr<TwoDA> ranges(Resources::instance().get2DA("ranges"));
creature._perception.sightRange = ranges->getFloat(rangeIdx, "primaryrange");
creature._perception.hearingRange = ranges->getFloat(rangeIdx, "secondaryrange");
}
void StaticCreatureBlueprint::load(Creature &creature) {
creature._appearance = _appearance;
creature._attributes = _attributes;

View file

@ -60,6 +60,7 @@ private:
void loadItems(Creature &creature);
void loadSoundSet(Creature &creature);
void loadBodyBag(Creature &creature);
void loadPerception(Creature &creature);
};
/**

View file

@ -82,7 +82,8 @@ Area::Area(uint32_t id, Game *game) :
_combat(game),
_map(game),
_heartbeatTimer(kHeartbeatInterval),
_creatureFinder(this) {
_creatureFinder(this),
_perception(this) {
init();
}
@ -659,6 +660,7 @@ void Area::update(float dt) {
}
}
_perception.update(dt);
_combat.update(dt);
updateHeartbeat(dt);

View file

@ -41,6 +41,7 @@
#include "../map.h"
#include "../objectselect.h"
#include "../pathfinder.h"
#include "../perception.h"
#include "../script/runner.h"
#include "../types.h"
@ -196,6 +197,7 @@ private:
bool _unescapable { false };
CreatureFinder _creatureFinder;
Grass _grass;
Perception _perception;
// Scripts

View file

@ -563,6 +563,40 @@ void Creature::stopTalking() {
}
}
void Creature::onObjectSeen(const shared_ptr<SpatialObject> &object) {
_perception.seen.insert(object);
_perception.lastPerception = PerceptionType::Seen;
_perception.lastPerceived = object;
runOnNoticeScript();
}
void Creature::runOnNoticeScript() {
if (!_onNotice.empty()) {
_scriptRunner->run(_onNotice, _id, _perception.lastPerceived->id());
}
}
void Creature::onObjectVanished(const shared_ptr<SpatialObject> &object) {
_perception.seen.erase(object);
_perception.lastPerception = PerceptionType::Vanished;
_perception.lastPerceived = object;
runOnNoticeScript();
}
void Creature::onObjectHeard(const shared_ptr<SpatialObject> &object) {
_perception.heard.insert(move(object));
_perception.lastPerception = PerceptionType::Heard;
_perception.lastPerceived = object;
runOnNoticeScript();
}
void Creature::onObjectInaudible(const shared_ptr<SpatialObject> &object) {
_perception.heard.erase(object);
_perception.lastPerception = PerceptionType::Inaudible;
_perception.lastPerceived = object;
runOnNoticeScript();
}
} // namespace game
} // namespace reone

View file

@ -19,6 +19,7 @@
#include <atomic>
#include <functional>
#include <set>
#include "../../audio/stream.h"
#include "../../render/lip/lipanimation.h"
@ -80,6 +81,15 @@ public:
bool corpse { false };
};
struct Perception {
float sightRange { 0.0f };
float hearingRange { 0.0f };
std::set<std::shared_ptr<SpatialObject>> seen;
std::set<std::shared_ptr<SpatialObject>> heard;
PerceptionType lastPerception { PerceptionType::Seen };
std::shared_ptr<SpatialObject> lastPerceived;
};
Creature(
uint32_t id,
ObjectFactory *objectFactory,
@ -162,6 +172,17 @@ public:
// END Pathfinding
// Perception
void onObjectSeen(const std::shared_ptr<SpatialObject> &object);
void onObjectVanished(const std::shared_ptr<SpatialObject> &object);
void onObjectHeard(const std::shared_ptr<SpatialObject> &object);
void onObjectInaudible(const std::shared_ptr<SpatialObject> &object);
const Perception &perception() const { return _perception; }
// END Perception
// Scripts
void runSpawnScript();
@ -190,6 +211,7 @@ private:
int _xp { 0 };
std::shared_ptr<SoundSet> _soundSet;
BodyBag _bodyBag;
Perception _perception;
// Animation
@ -205,13 +227,15 @@ private:
std::string _onSpawn;
std::string _onDeath;
std::string _onNotice;
// END Scripts
void updateModel();
void updateHealth();
void runDeathScript();
inline void runDeathScript();
inline void runOnNoticeScript();
ModelType parseModelType(const std::string &s) const;

90
src/game/perception.cpp Normal file
View file

@ -0,0 +1,90 @@
/*
* Copyright (c) 2020-2021 The reone project contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "perception.h"
#include <set>
#include <stdexcept>
#include "object/creature.h"
#include "object/area.h"
using namespace std;
namespace reone {
namespace game {
static constexpr float kUpdateInterval = 1.0f; // seconds
Perception::Perception(Area *area) : _area(area) {
if (!area) {
throw invalid_argument("area must not be null");
}
}
void Perception::update(float dt) {
if (_updateTimer.advance(dt)) {
doUpdate();
_updateTimer.reset(kUpdateInterval);
}
}
void Perception::doUpdate() {
// For each creature, determine a list of creatures it sees
ObjectList &creatures = _area->getObjectsByType(ObjectType::Creature);
for (auto &object : creatures) {
// Skip dead creatures
if (object->isDead()) continue;
auto creature = static_pointer_cast<Creature>(object);
float sightRange2 = creature->perception().sightRange * creature->perception().sightRange;
float hearingRange2 = creature->perception().hearingRange * creature->perception().hearingRange;
for (auto &other : creatures) {
bool seen = false;
bool heard = false;
float distance2 = creature->getDistanceTo2(*object);
if (distance2 <= sightRange2) {
// TODO: check line-of-sight
seen = true;
}
if (distance2 <= hearingRange2) {
heard = true;
}
bool wasSeen = creature->perception().seen.count(other) > 0;
if (!wasSeen && seen) {
creature->onObjectSeen(other);
} else if (wasSeen && !seen) {
creature->onObjectVanished(other);
}
bool wasHeard = creature->perception().heard.count(other) > 0;
if (!wasHeard && heard) {
creature->onObjectHeard(other);
} else if (wasHeard && !heard) {
creature->onObjectInaudible(other);
}
}
}
}
} // namespace game
} // namespace reone

47
src/game/perception.h Normal file
View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2020-2021 The reone project contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "../common/timer.h"
namespace reone {
namespace game {
class Area;
/**
* Creature perception routines, i.e. sight and hearing.
*/
class Perception {
public:
Perception(Area *area);
void update(float dt);
private:
Area *_area;
Timer _updateTimer;
void doUpdate();
};
} // namespace game
} // namespace reone

View file

@ -493,6 +493,16 @@ private:
script::Variable setTime(const VariablesList &args, script::ExecutionContext &ctx);
// END Time
// Perception
script::Variable getLastPerceived(const VariablesList &args, script::ExecutionContext &ctx);
script::Variable getLastPerceptionSeen(const VariablesList &args, script::ExecutionContext &ctx);
script::Variable getLastPerceptionVanished(const VariablesList &args, script::ExecutionContext &ctx);
script::Variable getLastPerceptionHeard(const VariablesList &args, script::ExecutionContext &ctx);
script::Variable getLastPerceptionInaudible(const VariablesList &args, script::ExecutionContext &ctx);
// END Perception
};
} // namespace game

View file

@ -53,7 +53,7 @@ Variable Routines::assignCommand(const VariablesList &args, ExecutionContext &ct
auto action = make_unique<CommandAction>(getAction(args, 1));
subject->actionQueue().add(move(action));
} else {
warn("Routines: assignCommand: subject is invalid");
warn("Script: assignCommand: subject is invalid");
}
return Variable();
}
@ -78,7 +78,7 @@ Variable Routines::actionMoveToObject(const VariablesList &args, ExecutionContex
subject->actionQueue().add(move(action));
} else {
warn("Routines: actionMoveToObject: moveTo is invalid");
warn("Script: actionMoveToObject: moveTo is invalid");
}
return Variable();
@ -99,7 +99,7 @@ Variable Routines::actionStartConversation(const VariablesList &args, ExecutionC
subject->actionQueue().add(move(action));
} else {
warn("Routines: actionStartConversation: objectToConverse is invalid");
warn("Script: actionStartConversation: objectToConverse is invalid");
}
return Variable();
@ -130,7 +130,7 @@ Variable Routines::actionOpenDoor(const VariablesList &args, ExecutionContext &c
auto subject = getCaller(ctx);
subject->actionQueue().add(move(action));
} else {
warn("Routines: actionOpenDoor: door is invalid");
warn("Script: actionOpenDoor: door is invalid");
}
return Variable();
@ -143,7 +143,7 @@ Variable Routines::actionCloseDoor(const VariablesList &args, ExecutionContext &
auto subject = getCaller(ctx);
subject->actionQueue().add(move(action));
} else {
warn("Routines: actionCloseDoor: door is invalid");
warn("Script: actionCloseDoor: door is invalid");
}
return Variable();
@ -162,7 +162,7 @@ Variable Routines::actionJumpToObject(const VariablesList &args, ExecutionContex
auto subject = getCaller(ctx);
subject->actionQueue().add(move(action));
} else {
warn("Routines: actionJumpToObject: toJumpTo is invalid");
warn("Script: actionJumpToObject: toJumpTo is invalid");
}
return Variable();
@ -175,7 +175,7 @@ Variable Routines::actionJumpToLocation(const VariablesList &args, ExecutionCont
auto subject = getCaller(ctx);
subject->actionQueue().add(move(action));
} else {
warn("Routines: actionJumpToLocation: location is invalid");
warn("Script: actionJumpToLocation: location is invalid");
}
return Variable();
@ -192,7 +192,7 @@ Variable Routines::actionForceMoveToObject(const VariablesList &args, ExecutionC
subject->actionQueue().add(move(action));
} else {
warn("Routines: actionForceMoveToObject: moveTo is invalid");
warn("Script: actionForceMoveToObject: moveTo is invalid");
}
return Variable();
@ -205,7 +205,7 @@ Variable Routines::actionForceMoveToLocation(const VariablesList &args, Executio
auto subject = getCaller(ctx);
subject->actionQueue().add(move(action));
} else {
warn("Routines: actionForceMoveToLocation: destination is invalid");
warn("Script: actionForceMoveToLocation: destination is invalid");
}
return Variable();
@ -221,7 +221,7 @@ Variable Routines::jumpToObject(const VariablesList &args, ExecutionContext &ctx
subject->actionQueue().add(move(action));
} else {
warn("Routines: jumpToObject: toJumpTo is invalid");
warn("Script: jumpToObject: toJumpTo is invalid");
}
return Variable();
@ -237,7 +237,7 @@ Variable Routines::jumpToLocation(const VariablesList &args, ExecutionContext &c
subject->actionQueue().add(move(action));
} else {
warn("Routines: jumpToLocation: location is invalid");
warn("Script: jumpToLocation: location is invalid");
}
return Variable();
@ -249,7 +249,7 @@ Variable Routines::actionRandomWalk(const VariablesList &args, ExecutionContext
auto action = make_unique<Action>(ActionType::RandomWalk);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionRandomWalk: caller is invalid");
warn("Script: actionRandomWalk: caller is invalid");
}
return Variable();
}
@ -262,7 +262,7 @@ Variable Routines::actionMoveToLocation(const VariablesList &args, ExecutionCont
auto action = make_unique<MoveToLocationAction>(destination, run);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionMoveToLocation: caller is invalid");
warn("Script: actionMoveToLocation: caller is invalid");
}
return Variable();
}
@ -274,7 +274,7 @@ Variable Routines::actionMoveAwayFromObject(const VariablesList &args, Execution
auto action = make_unique<Action>(ActionType::MoveAwayFromObject);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionMoveAwayFromObject: caller is invalid");
warn("Script: actionMoveAwayFromObject: caller is invalid");
}
return Variable();
}
@ -286,7 +286,7 @@ Variable Routines::actionEquipItem(const VariablesList &args, ExecutionContext &
auto action = make_unique<Action>(ActionType::EquipItem);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionEquipItem: caller is invalid");
warn("Script: actionEquipItem: caller is invalid");
}
return Variable();
}
@ -298,7 +298,7 @@ Variable Routines::actionUnequipItem(const VariablesList &args, ExecutionContext
auto action = make_unique<Action>(ActionType::UnequipItem);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionUnequipItem: caller is invalid");
warn("Script: actionUnequipItem: caller is invalid");
}
return Variable();
}
@ -310,7 +310,7 @@ Variable Routines::actionPickUpItem(const VariablesList &args, ExecutionContext
auto action = make_unique<Action>(ActionType::PickUpItem);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionPickUpItem: caller is invalid");
warn("Script: actionPickUpItem: caller is invalid");
}
return Variable();
}
@ -322,7 +322,7 @@ Variable Routines::actionPutDownItem(const VariablesList &args, ExecutionContext
auto action = make_unique<Action>(ActionType::DropItem);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionPutDownItem: caller is invalid");
warn("Script: actionPutDownItem: caller is invalid");
}
return Variable();
}
@ -330,12 +330,12 @@ Variable Routines::actionPutDownItem(const VariablesList &args, ExecutionContext
Variable Routines::actionAttack(const VariablesList &args, ExecutionContext &ctx) {
auto caller = getCallerAsCreature(ctx);
if (!caller) {
warn("Routines: actionAttack: caller is invalid");
warn("Script: actionAttack: caller is invalid");
return Variable();
}
auto attackee = getSpatialObject(args, 0);
if (!attackee) {
warn("Routines: actionAttack: attackee is invalid");
warn("Script: actionAttack: attackee is invalid");
return Variable();
}
auto action = make_unique<AttackAction>(attackee);
@ -351,7 +351,7 @@ Variable Routines::actionSpeakString(const VariablesList &args, ExecutionContext
auto action = make_unique<Action>(ActionType::SpeakString);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionSpeakString: caller is invalid");
warn("Script: actionSpeakString: caller is invalid");
}
return Variable();
}
@ -366,7 +366,7 @@ Variable Routines::actionPlayAnimation(const VariablesList &args, ExecutionConte
auto action = make_unique<PlayAnimationAction>(animation, speed, duration);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionPlayAnimation: caller is invalid");
warn("Script: actionPlayAnimation: caller is invalid");
}
return Variable();
}
@ -378,7 +378,7 @@ Variable Routines::actionCastSpellAtObject(const VariablesList &args, ExecutionC
auto action = make_unique<Action>(ActionType::CastSpellAtObject);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionCastSpellAtObject: caller is invalid");
warn("Script: actionCastSpellAtObject: caller is invalid");
}
return Variable();
}
@ -390,7 +390,7 @@ Variable Routines::actionGiveItem(const VariablesList &args, ExecutionContext &c
auto action = make_unique<Action>(ActionType::GiveItem);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionGiveItem: caller is invalid");
warn("Script: actionGiveItem: caller is invalid");
}
return Variable();
}
@ -402,7 +402,7 @@ Variable Routines::actionTakeItem(const VariablesList &args, ExecutionContext &c
auto action = make_unique<Action>(ActionType::TakeItem);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionTakeItem: caller is invalid");
warn("Script: actionTakeItem: caller is invalid");
}
return Variable();
}
@ -414,7 +414,7 @@ Variable Routines::actionForceFollowObject(const VariablesList &args, ExecutionC
auto action = make_unique<Action>(ActionType::ForceFollowObject);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionForceFollowObject: caller is invalid");
warn("Script: actionForceFollowObject: caller is invalid");
}
return Variable();
}
@ -426,7 +426,7 @@ Variable Routines::actionWait(const VariablesList &args, ExecutionContext &ctx)
auto action = make_unique<WaitAction>(seconds);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionWait: caller is invalid");
warn("Script: actionWait: caller is invalid");
}
return Variable();
}
@ -438,7 +438,7 @@ Variable Routines::actionCastSpellAtLocation(const VariablesList &args, Executio
auto action = make_unique<Action>(ActionType::CastSpellAtLocation);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionCastSpellAtLocation: caller is invalid");
warn("Script: actionCastSpellAtLocation: caller is invalid");
}
return Variable();
}
@ -450,7 +450,7 @@ Variable Routines::actionSpeakStringByStrRef(const VariablesList &args, Executio
auto action = make_unique<Action>(ActionType::SpeakStringByStrRef);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionSpeakStringByStrRef: caller is invalid");
warn("Script: actionSpeakStringByStrRef: caller is invalid");
}
return Variable();
}
@ -462,7 +462,7 @@ Variable Routines::actionUseFeat(const VariablesList &args, ExecutionContext &ct
auto action = make_unique<Action>(ActionType::UseFeat);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionUseFeat: caller is invalid");
warn("Script: actionUseFeat: caller is invalid");
}
return Variable();
}
@ -474,7 +474,7 @@ Variable Routines::actionUseSkill(const VariablesList &args, ExecutionContext &c
auto action = make_unique<Action>(ActionType::UseSkill);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionUseSkill: caller is invalid");
warn("Script: actionUseSkill: caller is invalid");
}
return Variable();
}
@ -486,7 +486,7 @@ Variable Routines::actionUseTalentOnObject(const VariablesList &args, ExecutionC
auto action = make_unique<Action>(ActionType::UseTalentOnObject);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionUseSkill: caller is invalid");
warn("Script: actionUseSkill: caller is invalid");
}
return Variable();
}
@ -498,7 +498,7 @@ Variable Routines::actionUseTalentAtLocation(const VariablesList &args, Executio
auto action = make_unique<Action>(ActionType::UseTalentAtLocation);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionUseTalentAtLocation: caller is invalid");
warn("Script: actionUseTalentAtLocation: caller is invalid");
}
return Variable();
}
@ -510,7 +510,7 @@ Variable Routines::actionInteractObject(const VariablesList &args, ExecutionCont
auto action = make_unique<Action>(ActionType::InteractObject);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionInteractObject: caller is invalid");
warn("Script: actionInteractObject: caller is invalid");
}
return Variable();
}
@ -522,7 +522,7 @@ Variable Routines::actionMoveAwayFromLocation(const VariablesList &args, Executi
auto action = make_unique<Action>(ActionType::MoveAwayFromLocation);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionMoveAwayFromLocation: caller is invalid");
warn("Script: actionMoveAwayFromLocation: caller is invalid");
}
return Variable();
}
@ -534,7 +534,7 @@ Variable Routines::actionSurrenderToEnemies(const VariablesList &args, Execution
auto action = make_unique<Action>(ActionType::SurrenderToEnemies);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionSurrenderToEnemies: caller is invalid");
warn("Script: actionSurrenderToEnemies: caller is invalid");
}
return Variable();
}
@ -546,7 +546,7 @@ Variable Routines::actionEquipMostDamagingMelee(const VariablesList &args, Execu
auto action = make_unique<Action>(ActionType::EquipMostDamagingMelee);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionEquipMostDamagingMelee: caller is invalid");
warn("Script: actionEquipMostDamagingMelee: caller is invalid");
}
return Variable();
}
@ -558,7 +558,7 @@ Variable Routines::actionEquipMostDamagingRanged(const VariablesList &args, Exec
auto action = make_unique<Action>(ActionType::EquipMostDamagingRanged);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionEquipMostDamagingRanged: caller is invalid");
warn("Script: actionEquipMostDamagingRanged: caller is invalid");
}
return Variable();
}
@ -570,7 +570,7 @@ Variable Routines::actionEquipMostEffectiveArmor(const VariablesList &args, Exec
auto action = make_unique<Action>(ActionType::EquipMostEffectiveArmor);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionEquipMostEffectiveArmor: caller is invalid");
warn("Script: actionEquipMostEffectiveArmor: caller is invalid");
}
return Variable();
}
@ -582,7 +582,7 @@ Variable Routines::actionUnlockObject(const VariablesList &args, ExecutionContex
auto action = make_unique<Action>(ActionType::UnlockObject);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionUnlockObject: caller is invalid");
warn("Script: actionUnlockObject: caller is invalid");
}
return Variable();
}
@ -594,7 +594,7 @@ Variable Routines::actionLockObject(const VariablesList &args, ExecutionContext
auto action = make_unique<Action>(ActionType::LockObject);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionLockObject: caller is invalid");
warn("Script: actionLockObject: caller is invalid");
}
return Variable();
}
@ -606,7 +606,7 @@ Variable Routines::actionCastFakeSpellAtObject(const VariablesList &args, Execut
auto action = make_unique<Action>(ActionType::CastFakeSpellAtObject);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionCastFakeSpellAtObject: caller is invalid");
warn("Script: actionCastFakeSpellAtObject: caller is invalid");
}
return Variable();
}
@ -618,7 +618,7 @@ Variable Routines::actionCastFakeSpellAtLocation(const VariablesList &args, Exec
auto action = make_unique<Action>(ActionType::CastFakeSpellAtLocation);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionCastFakeSpellAtLocation: caller is invalid");
warn("Script: actionCastFakeSpellAtLocation: caller is invalid");
}
return Variable();
}
@ -630,7 +630,7 @@ Variable Routines::actionBarkString(const VariablesList &args, ExecutionContext
auto action = make_unique<Action>(ActionType::BarkString);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionBarkString: caller is invalid");
warn("Script: actionBarkString: caller is invalid");
}
return Variable();
}
@ -642,7 +642,7 @@ Variable Routines::actionFollowLeader(const VariablesList &args, ExecutionContex
auto action = make_unique<Action>(ActionType::FollowLeader);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionFollowLeader: caller is invalid");
warn("Script: actionFollowLeader: caller is invalid");
}
return Variable();
}
@ -654,7 +654,7 @@ Variable Routines::actionFollowOwner(const VariablesList &args, ExecutionContext
auto action = make_unique<Action>(ActionType::FollowOwner);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionFollowOwner: caller is invalid");
warn("Script: actionFollowOwner: caller is invalid");
}
return Variable();
}
@ -666,7 +666,7 @@ Variable Routines::actionSwitchWeapons(const VariablesList &args, ExecutionConte
auto action = make_unique<Action>(ActionType::SwitchWeapons);
caller->actionQueue().add(move(action));
} else {
warn("Routines: actionSwitchWeapons: caller is invalid");
warn("Script: actionSwitchWeapons: caller is invalid");
}
return Variable();
}

View file

@ -245,7 +245,7 @@ Variable Routines::executeScript(const VariablesList &args, ExecutionContext &ct
_game->setRunScriptVar(scriptVar);
_game->scriptRunner().run(script, target->id());
} else {
warn("Routines: executeScript: target is invalid");
warn("Script: executeScript: target is invalid");
}
return Variable();

View file

@ -490,7 +490,7 @@ Variable Routines::applyEffectToObject(const VariablesList &args, ExecutionConte
if (target) {
target->applyEffect(effect, durationType, duration);
} else {
warn("Routines: applyEffectToObject: target is invalid");
warn("Script: applyEffectToObject: target is invalid");
}
return Variable();

View file

@ -33,7 +33,7 @@ namespace game {
Variable Routines::getFacingFromLocation(const VariablesList &args, ExecutionContext &ctx) {
auto location = getLocationEngineType(args, 0);
if (!location) {
warn("Routines: getFacingFromLocation: location is invalid");
warn("Script: getFacingFromLocation: location is invalid");
return -1.0f;
}
return location->facing();
@ -49,7 +49,7 @@ Variable Routines::getLocation(const VariablesList &args, ExecutionContext &ctx)
float facing = object->facing();
result.engineType = make_shared<Location>(move(position), facing);
} else {
warn("Routines: getLocation: object is invalid");
warn("Script: getLocation: object is invalid");
}
return move(result);
@ -58,7 +58,7 @@ Variable Routines::getLocation(const VariablesList &args, ExecutionContext &ctx)
Variable Routines::getPositionFromLocation(const VariablesList &args, ExecutionContext &ctx) {
auto location = getLocationEngineType(args, 0);
if (!location) {
warn("Routines: getPositionFromLocation: location is invalid");
warn("Script: getPositionFromLocation: location is invalid");
return glm::vec3(0.0f);
}
return location->position();
@ -75,12 +75,12 @@ Variable Routines::location(const VariablesList &args, ExecutionContext &ctx) {
Variable Routines::getDistanceBetweenLocations(const VariablesList &args, ExecutionContext &ctx) {
auto locationA = getLocationEngineType(args, 0);
if (!locationA) {
warn("Routines: getDistanceBetweenLocations: locationA is invalid");
warn("Script: getDistanceBetweenLocations: locationA is invalid");
return 0.0f;
}
auto locationB = getLocationEngineType(args, 1);
if (!locationB) {
warn("Routines: getDistanceBetweenLocations: locationB is invalid");
warn("Script: getDistanceBetweenLocations: locationB is invalid");
return 0.0f;
}
return glm::distance(locationA->position(), locationB->position());
@ -89,12 +89,12 @@ Variable Routines::getDistanceBetweenLocations(const VariablesList &args, Execut
Variable Routines::getDistanceBetweenLocations2D(const VariablesList &args, ExecutionContext &ctx) {
auto locationA = getLocationEngineType(args, 0);
if (!locationA) {
warn("Routines: getDistanceBetweenLocations2D: locationA is invalid");
warn("Script: getDistanceBetweenLocations2D: locationA is invalid");
return 0.0f;
}
auto locationB = getLocationEngineType(args, 1);
if (!locationB) {
warn("Routines: getDistanceBetweenLocations2D: locationB is invalid");
warn("Script: getDistanceBetweenLocations2D: locationB is invalid");
return 0.0f;
}
return glm::distance(glm::vec2(locationA->position()), glm::vec2(locationB->position()));

View file

@ -44,10 +44,10 @@ Variable Routines::signalEvent(const VariablesList &args, ExecutionContext &ctx)
debug(boost::format("Event signalled: %s %s") % object->tag() % toRun->number(), 2);
_game->scriptRunner().run(object->getOnUserDefined(), object->id(), kObjectInvalid, toRun->number());
} else {
warn("Routines: signalEvent: toRun is invalid");
warn("Script: signalEvent: toRun is invalid");
}
} else {
warn("Routines: signalEvent: object is invalid");
warn("Script: signalEvent: object is invalid");
}
return Variable();
}

View file

@ -40,7 +40,7 @@ Variable Routines::getItemInSlot(const VariablesList &args, ExecutionContext &ct
int slot = getInt(args, 0);
result.object = creature->getEquippedItem(slot);
} else {
warn("Routines: getItemInSlot: creature is invalid");
warn("Script: getItemInSlot: creature is invalid");
}
return move(result);
@ -59,10 +59,10 @@ Variable Routines::createItemOnObject(const VariablesList &args, ExecutionContex
int stackSize = getInt(args, 2, 1);
result.object = target->addItem(itemTemplate, stackSize, true);
} else {
warn("Routines: createItemOnObject: itemTemplate is invalid");
warn("Script: createItemOnObject: itemTemplate is invalid");
}
} else {
warn("Routines: createItemOnObject: target is invalid");
warn("Script: createItemOnObject: target is invalid");
}
return move(result);
@ -79,7 +79,7 @@ Variable Routines::getFirstItemInInventory(const VariablesList &args, ExecutionC
result.object = move(item);
}
} else {
warn("Routines: getFirstItemInInventory: target is invalid");
warn("Script: getFirstItemInInventory: target is invalid");
}
return move(result);
@ -96,7 +96,7 @@ Variable Routines::getNextItemInInventory(const VariablesList &args, ExecutionCo
result.object = move(item);
}
} else {
warn("Routines: getNextItemInInventory: target is invalid");
warn("Script: getNextItemInInventory: target is invalid");
}
return move(result);
@ -105,7 +105,7 @@ Variable Routines::getNextItemInInventory(const VariablesList &args, ExecutionCo
Variable Routines::getItemStackSize(const VariablesList &args, ExecutionContext &ctx) {
auto item = getItem(args, 0);
if (!item) {
warn("Routines: getItemStackSize: item is invalid");
warn("Script: getItemStackSize: item is invalid");
return 0;
}
return item->stackSize();
@ -117,7 +117,7 @@ Variable Routines::setItemStackSize(const VariablesList &args, ExecutionContext
int stackSize = getInt(args, 1);
item->setStackSize(stackSize);
} else {
warn("Routines: setItemStackSize: item is invalid");
warn("Script: setItemStackSize: item is invalid");
}
return Variable();
}
@ -125,7 +125,7 @@ Variable Routines::setItemStackSize(const VariablesList &args, ExecutionContext
Variable Routines::getIdentified(const VariablesList &args, ExecutionContext &ctx) {
auto item = getItem(args, 0);
if (!item) {
warn("Routines: getIdentified: item is invalid");
warn("Script: getIdentified: item is invalid");
return 0;
}
return item->isIdentified() ? 1 : 0;
@ -137,7 +137,7 @@ Variable Routines::setIdentified(const VariablesList &args, ExecutionContext &ct
bool identified = getBool(args, 1);
item->setIdentified(identified);
} else {
warn("Routines: setIdentified: item is invalid");
warn("Script: setIdentified: item is invalid");
}
return Variable();
}

View file

@ -294,12 +294,12 @@ void Routines::addKotorRoutines() {
add("GetName", String, { Object }, &Routines::getName);
add("GetLastSpeaker", Object, { });
add("BeginConversation", Int, { String, Object });
add("GetLastPerceived", Object, { });
add("GetLastPerceptionHeard", Int, { });
add("GetLastPerceptionInaudible", Int, { });
add("GetLastPerceptionSeen", Int, { });
add("GetLastPerceived", Object, { }, &Routines::getLastPerceived);
add("GetLastPerceptionHeard", Int, { }, &Routines::getLastPerceptionHeard);
add("GetLastPerceptionInaudible", Int, { }, &Routines::getLastPerceptionInaudible);
add("GetLastPerceptionSeen", Int, { }, &Routines::getLastPerceptionSeen);
add("GetLastClosedBy", Object, { });
add("GetLastPerceptionVanished", Int, { });
add("GetLastPerceptionVanished", Int, { }, &Routines::getLastPerceptionVanished);
add("GetFirstInPersistentObject", Object, { Object, Int, Int });
add("GetNextInPersistentObject", Object, { Object, Int, Int });
add("GetAreaOfEffectCreator", Object, { Object });

View file

@ -39,7 +39,7 @@ Variable Routines::destroyObject(const VariablesList &args, ExecutionContext &ct
if (destroy) {
_game->module()->area()->destroyObject(*destroy);
} else {
warn("Routines: destroyObject: destroy is invalid");
warn("Script: destroyObject: destroy is invalid");
}
return Variable();
}
@ -88,7 +88,7 @@ Variable Routines::setLocked(const VariablesList &args, ExecutionContext &ctx) {
bool locked = getBool(args, 1);
target->setLocked(locked);
} else {
warn("Routines: setLocked: target is invalid");
warn("Script: setLocked: target is invalid");
}
return Variable();
}
@ -96,7 +96,7 @@ Variable Routines::setLocked(const VariablesList &args, ExecutionContext &ctx) {
Variable Routines::getLocked(const VariablesList &args, ExecutionContext &ctx) {
auto target = getDoor(args, 0);
if (!target) {
warn("Routines: getLocked: target is invalid");
warn("Script: getLocked: target is invalid");
return 0;
}
return target->isLocked() ? 1 : 0;
@ -111,7 +111,7 @@ Variable Routines::getTag(const VariablesList &args, ExecutionContext &ctx) {
auto object = getObject(args, 0);
if (!object) {
warn("Routines: getTag: object is invalid");
warn("Script: getTag: object is invalid");
return empty;
}
@ -121,12 +121,12 @@ Variable Routines::getTag(const VariablesList &args, ExecutionContext &ctx) {
Variable Routines::getDistanceToObject(const VariablesList &args, ExecutionContext &ctx) {
auto caller = getCallerAsSpatial(ctx);
if (!caller) {
warn("Routines: getDistanceToObject: caller is invalid");
warn("Script: getDistanceToObject: caller is invalid");
return -1.0f;
}
auto object = getSpatialObject(args, 0);
if (!object) {
warn("Routines: getDistanceToObject: object is invalid");
warn("Script: getDistanceToObject: object is invalid");
return -1.0f;
}
@ -136,12 +136,12 @@ Variable Routines::getDistanceToObject(const VariablesList &args, ExecutionConte
Variable Routines::getDistanceToObject2D(const VariablesList &args, ExecutionContext &ctx) {
auto caller = getCallerAsSpatial(ctx);
if (!caller) {
warn("Routines: getDistanceToObject2D: caller is invalid");
warn("Script: getDistanceToObject2D: caller is invalid");
return -1.0f;
}
auto object = getSpatialObject(args, 0);
if (!object) {
warn("Routines: getDistanceToObject2D: object is invalid");
warn("Script: getDistanceToObject2D: object is invalid");
return -1.0f;
}
@ -155,7 +155,7 @@ Variable Routines::getExitingObject(const VariablesList &args, ExecutionContext
Variable Routines::getFacing(const VariablesList &args, ExecutionContext &ctx) {
auto target = getSpatialObject(args, 0);
if (!target) {
warn("Routines: getFacing: target is invalid");
warn("Script: getFacing: target is invalid");
return -1.0f;
}
return glm::degrees(target->facing());
@ -164,7 +164,7 @@ Variable Routines::getFacing(const VariablesList &args, ExecutionContext &ctx) {
Variable Routines::getPosition(const VariablesList &args, ExecutionContext &ctx) {
auto target = getSpatialObject(args, 0);
if (!target) {
warn("Routines: getPosition: target is invalid");
warn("Script: getPosition: target is invalid");
return glm::vec3(0.0f);
}
return target->position();
@ -175,7 +175,7 @@ Variable Routines::soundObjectPlay(const VariablesList &args, ExecutionContext &
if (sound) {
sound->play();
} else {
warn("Routines: soundObjectPlay: sound is invalid");
warn("Script: soundObjectPlay: sound is invalid");
}
return Variable();
}
@ -185,7 +185,7 @@ Variable Routines::soundObjectStop(const VariablesList &args, ExecutionContext &
if (sound) {
sound->stop();
} else {
warn("Routines: soundObjectStop: sound is invalid");
warn("Script: soundObjectStop: sound is invalid");
}
return Variable();
}
@ -193,12 +193,12 @@ Variable Routines::soundObjectStop(const VariablesList &args, ExecutionContext &
Variable Routines::getDistanceBetween(const VariablesList &args, ExecutionContext &ctx) {
auto objectA = getSpatialObject(args, 0);
if (!objectA) {
warn("Routines: getDistanceBetween: objectA is invalid");
warn("Script: getDistanceBetween: objectA is invalid");
return -1.0f;
}
auto objectB = getSpatialObject(args, 1);
if (!objectB) {
warn("Routines: getDistanceBetween: objectB is invalid");
warn("Script: getDistanceBetween: objectB is invalid");
return -1.0f;
}
@ -208,12 +208,12 @@ Variable Routines::getDistanceBetween(const VariablesList &args, ExecutionContex
Variable Routines::getDistanceBetween2D(const VariablesList &args, ExecutionContext &ctx) {
auto objectA = getSpatialObject(args, 0);
if (!objectA) {
warn("Routines: getDistanceBetween2D: objectA is invalid");
warn("Script: getDistanceBetween2D: objectA is invalid");
return 0.0f;
}
auto objectB = getSpatialObject(args, 1);
if (!objectB) {
warn("Routines: getDistanceBetween2D: objectB is invalid");
warn("Script: getDistanceBetween2D: objectB is invalid");
return 0.0f;
}
return objectA->getDistanceTo(glm::vec2(objectB->position()));
@ -222,7 +222,7 @@ Variable Routines::getDistanceBetween2D(const VariablesList &args, ExecutionCont
Variable Routines::getIsDead(const VariablesList &args, ExecutionContext &ctx) {
auto creature = getCreature(args, 0);
if (!creature) {
warn("Routines: getIsDead: creature is invalid");
warn("Script: getIsDead: creature is invalid");
return false;
}
return creature->isDead();
@ -231,7 +231,7 @@ Variable Routines::getIsDead(const VariablesList &args, ExecutionContext &ctx) {
Variable Routines::getIsInCombat(const VariablesList &args, ExecutionContext &ctx) {
auto creature = getCreatureOrCaller(args, 0, ctx);
if (!creature) {
warn("Routines: getIsInCombat: creature is invalid");
warn("Script: getIsInCombat: creature is invalid");
return false;
}
return creature->isInCombat();
@ -240,7 +240,7 @@ Variable Routines::getIsInCombat(const VariablesList &args, ExecutionContext &ct
Variable Routines::getIsOpen(const VariablesList &args, ExecutionContext &ctx) {
auto object = getSpatialObject(args, 0);
if (!object) {
warn("Routines: getIsOpen: object is invalid");
warn("Script: getIsOpen: object is invalid");
return false;
}
return object->isOpen();
@ -252,7 +252,7 @@ Variable Routines::setFacing(const VariablesList &args, ExecutionContext &ctx) {
float direction = getFloat(args, 0);
caller->setFacing(glm::radians(direction));
} else {
warn("Routines: setFacing: caller is invalid");
warn("Script: setFacing: caller is invalid");
}
return Variable();
}
@ -263,7 +263,7 @@ Variable Routines::setFacingPoint(const VariablesList &args, ExecutionContext &c
glm::vec3 target(getVector(args, 0));
caller->face(target);
} else {
warn("Routines: setFacingPoint: caller is invalid");
warn("Script: setFacingPoint: caller is invalid");
}
return Variable();
}
@ -273,7 +273,7 @@ Variable Routines::getName(const VariablesList &args, ExecutionContext &ctx) {
auto object = getObject(args, 0);
if (!object) {
warn("Routines: getName: object is invalid");
warn("Script: getName: object is invalid");
return empty;
}
@ -283,7 +283,7 @@ Variable Routines::getName(const VariablesList &args, ExecutionContext &ctx) {
Variable Routines::getObjectType(const VariablesList &args, ExecutionContext &ctx) {
auto target = getObject(args, 0);
if (!target) {
warn("Routines: getObjectType: target is invalid");
warn("Script: getObjectType: target is invalid");
return static_cast<int>(ObjectType::Invalid);
}
return static_cast<int>(target->type());
@ -292,7 +292,7 @@ Variable Routines::getObjectType(const VariablesList &args, ExecutionContext &ct
Variable Routines::getPlotFlag(const VariablesList &args, ExecutionContext &ctx) {
auto target = getObjectOrCaller(args, 0, ctx);
if (!target) {
warn("Routines: getPlotFlag: target is invalid");
warn("Script: getPlotFlag: target is invalid");
return 0;
}
return target->plotFlag();
@ -304,7 +304,7 @@ Variable Routines::setPlotFlag(const VariablesList &args, ExecutionContext &ctx)
int plotFlag = getInt(args, 1);
target->setPlotFlag(plotFlag);
} else {
warn("Routines: setPlotFlag: target is invalid");
warn("Script: setPlotFlag: target is invalid");
}
return Variable();
}
@ -312,12 +312,12 @@ Variable Routines::setPlotFlag(const VariablesList &args, ExecutionContext &ctx)
Variable Routines::faceObjectAwayFromObject(const VariablesList &args, ExecutionContext &ctx) {
auto facer = getSpatialObject(args, 0);
if (!facer) {
warn("Routines: faceObjectAwayFromObject: facer is invalid");
warn("Script: faceObjectAwayFromObject: facer is invalid");
return Variable();
}
auto objectToFaceAwayFrom = getSpatialObject(args, 1);
if (!objectToFaceAwayFrom) {
warn("Routines: faceObjectAwayFromObject: objectToFaceAwayFrom is invalid");
warn("Script: faceObjectAwayFromObject: objectToFaceAwayFrom is invalid");
return Variable();
}
facer->faceAwayFrom(*objectToFaceAwayFrom);
@ -328,7 +328,7 @@ Variable Routines::faceObjectAwayFromObject(const VariablesList &args, Execution
Variable Routines::getCommandable(const VariablesList &args, ExecutionContext &ctx) {
auto target = getObjectOrCaller(args, 0, ctx);
if (!target) {
warn("Routines: getCommandable: target is invalid");
warn("Script: getCommandable: target is invalid");
return 0;
}
return target->isCommandable() ? 1 : 0;
@ -340,7 +340,7 @@ Variable Routines::setCommandable(const VariablesList &args, ExecutionContext &c
bool commandable = getBool(args, 0);
target->setCommandable(commandable);
} else {
warn("Routines: setCommandable: target is invalid");
warn("Script: setCommandable: target is invalid");
}
return Variable();
}
@ -355,7 +355,7 @@ Variable Routines::playAnimation(const VariablesList &args, ExecutionContext &ct
properties.speed = speed;
caller->playAnimation(animType, move(properties));
} else {
warn("Routines: playAnimation: caller is invalid");
warn("Script: playAnimation: caller is invalid");
}
return Variable();
}
@ -377,12 +377,12 @@ Variable Routines::setAreaUnescapable(const VariablesList &args, ExecutionContex
Variable Routines::cutsceneAttack(const VariablesList &args, ExecutionContext &ctx) {
auto caller = getCallerAsCreature(ctx);
if (!caller) {
warn("Routines: cutsceneAttack: caller is invalid");
warn("Script: cutsceneAttack: caller is invalid");
return Variable();
}
auto target = getSpatialObject(args, 0);
if (!target) {
warn("Routines: cutsceneAttack: target is invalid");
warn("Script: cutsceneAttack: target is invalid");
return Variable();
}
int animation = getInt(args, 1);
@ -496,7 +496,7 @@ Variable Routines::getCurrentAction(const VariablesList &args, ExecutionContext
shared_ptr<Action> action(object->actionQueue().getCurrentAction());
result = Variable(static_cast<int>(action ? action->type() : ActionType::QueueEmpty));
} else {
warn("Routines: getCurrentAction: object is invalid");
warn("Script: getCurrentAction: object is invalid");
}
return move(result);

View file

@ -63,7 +63,7 @@ Variable Routines::showPartySelectionGUI(const VariablesList &args, ExecutionCon
Variable Routines::getIsPC(const VariablesList &args, ExecutionContext &ctx) {
auto creature = getCreature(args, 0);
if (!creature) {
warn("Routines: getIsPC: creature is invalid");
warn("Script: getIsPC: creature is invalid");
return 0;
}
auto player = _game->party().player();
@ -79,7 +79,7 @@ Variable Routines::isAvailableCreature(const VariablesList &args, ExecutionConte
Variable Routines::isObjectPartyMember(const VariablesList &args, ExecutionContext &ctx) {
auto creature = getCreature(args, 0);
if (!creature) {
warn("Routines: isObjectPartyMember: creature is invalid");
warn("Script: isObjectPartyMember: creature is invalid");
return 0;
}
return _game->party().isMember(*creature) ? 1 : 0;
@ -109,7 +109,7 @@ Variable Routines::setPartyLeader(const VariablesList &args, ExecutionContext &c
Variable Routines::addPartyMember(const VariablesList &args, ExecutionContext &ctx) {
auto creature = getCreature(args, 1);
if (!creature) {
warn("Routines: addPartyMember: creature is invalid");
warn("Script: addPartyMember: creature is invalid");
return 0;
}
int npc = getInt(args, 0);

View file

@ -0,0 +1,105 @@
/*
* Copyright (c) 2020-2021 The reone project contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "routines.h"
#include "../../common/log.h"
#include "../object/creature.h"
#include "../types.h"
using namespace std;
using namespace reone::script;
namespace reone {
namespace game {
Variable Routines::getLastPerceived(const VariablesList &args, ExecutionContext &ctx) {
Variable result;
result.type = VariableType::Object;
auto caller = getCallerAsCreature(ctx);
if (caller) {
result.object = caller->perception().lastPerceived;
} else {
warn("Script: getLastPerceived: invalid caller");
}
return move(result);
}
Variable Routines::getLastPerceptionSeen(const VariablesList &args, ExecutionContext &ctx) {
Variable result;
result.type = VariableType::Int;
auto caller = getCallerAsCreature(ctx);
if (caller) {
result.intValue = caller->perception().lastPerception == PerceptionType::Seen;
} else {
warn("Script: getLastPerceptionSeen: invalid caller");
}
return move(result);
}
Variable Routines::getLastPerceptionVanished(const VariablesList &args, ExecutionContext &ctx) {
Variable result;
result.type = VariableType::Int;
auto caller = getCallerAsCreature(ctx);
if (caller) {
result.intValue = caller->perception().lastPerception == PerceptionType::Vanished;
} else {
warn("Script: getLastPerceptionVanished: invalid caller");
}
return move(result);
}
Variable Routines::getLastPerceptionHeard(const VariablesList &args, ExecutionContext &ctx) {
Variable result;
result.type = VariableType::Int;
auto caller = getCallerAsCreature(ctx);
if (caller) {
result.intValue = caller->perception().lastPerception == PerceptionType::Heard;
} else {
warn("Script: getLastPerceptionHeard: invalid caller");
}
return move(result);
}
Variable Routines::getLastPerceptionInaudible(const VariablesList &args, ExecutionContext &ctx) {
Variable result;
result.type = VariableType::Int;
auto caller = getCallerAsCreature(ctx);
if (caller) {
result.intValue = caller->perception().lastPerception == PerceptionType::Inaudible;
} else {
warn("Script: getLastPerceptionInaudible: invalid caller");
}
return move(result);
}
} // namespace game
} // namespace reone

View file

@ -34,7 +34,7 @@ namespace game {
Variable Routines::getGender(const VariablesList &args, ExecutionContext &ctx) {
auto creature = getCreature(args, 0);
if (!creature) {
warn("Routines: getGender: creature is invalid");
warn("Script: getGender: creature is invalid");
return static_cast<int>(Gender::None);
}
return static_cast<int>(creature->gender());
@ -43,7 +43,7 @@ Variable Routines::getGender(const VariablesList &args, ExecutionContext &ctx) {
Variable Routines::getHitDice(const VariablesList &args, ExecutionContext &ctx) {
auto creature = getCreature(args, 0);
if (!creature) {
warn("Routines: getGender: creature is invalid");
warn("Script: getGender: creature is invalid");
return static_cast<int>(Gender::None);
}
return static_cast<int>(creature->attributes().getAggregateLevel());
@ -52,7 +52,7 @@ Variable Routines::getHitDice(const VariablesList &args, ExecutionContext &ctx)
Variable Routines::getClassByPosition(const VariablesList &args, ExecutionContext &ctx) {
auto creature = getCreatureOrCaller(args, 1, ctx);
if (!creature) {
warn("Routines: getClassByPosition: creature is invalid");
warn("Script: getClassByPosition: creature is invalid");
return static_cast<int>(ClassType::Invalid);
}
int position = getInt(args, 0);
@ -62,7 +62,7 @@ Variable Routines::getClassByPosition(const VariablesList &args, ExecutionContex
Variable Routines::getLevelByClass(const VariablesList &args, ExecutionContext &ctx) {
auto creature = getCreatureOrCaller(args, 1, ctx);
if (!creature) {
warn("Routines: getLevelByClass: creature is invalid");
warn("Script: getLevelByClass: creature is invalid");
return 0;
}
ClassType clazz = static_cast<ClassType>(getInt(args, 0));
@ -72,7 +72,7 @@ Variable Routines::getLevelByClass(const VariablesList &args, ExecutionContext &
Variable Routines::getHasSkill(const VariablesList &args, ExecutionContext &ctx) {
auto creature = getCreatureOrCaller(args, 1, ctx);
if (!creature) {
warn("Routines: getHasSkill: creature is invalid");
warn("Script: getHasSkill: creature is invalid");
return 0;
}
Skill skill = static_cast<Skill>(getInt(args, 0));
@ -82,7 +82,7 @@ Variable Routines::getHasSkill(const VariablesList &args, ExecutionContext &ctx)
Variable Routines::getCurrentHitPoints(const VariablesList &args, ExecutionContext &ctx) {
auto object = getObjectOrCaller(args, 0, ctx);
if (!object) {
warn("Routines: getCurrentHitPoints: object is invalid");
warn("Script: getCurrentHitPoints: object is invalid");
return 0;
}
return object->currentHitPoints();
@ -91,7 +91,7 @@ Variable Routines::getCurrentHitPoints(const VariablesList &args, ExecutionConte
Variable Routines::getMaxHitPoints(const VariablesList &args, ExecutionContext &ctx) {
auto object = getObjectOrCaller(args, 0, ctx);
if (!object) {
warn("Routines: getMaxHitPoints: object is invalid");
warn("Script: getMaxHitPoints: object is invalid");
return 0;
}
return object->maxHitPoints();
@ -100,7 +100,7 @@ Variable Routines::getMaxHitPoints(const VariablesList &args, ExecutionContext &
Variable Routines::getMinOneHP(const VariablesList &args, ExecutionContext &ctx) {
auto object = getObject(args, 0);
if (!object) {
warn("Routines: getMinOneHP: object is invalid");
warn("Script: getMinOneHP: object is invalid");
return 0;
}
return object->isMinOneHP() ? 1 : 0;
@ -109,7 +109,7 @@ Variable Routines::getMinOneHP(const VariablesList &args, ExecutionContext &ctx)
Variable Routines::setMaxHitPoints(const VariablesList &args, ExecutionContext &ctx) {
auto object = getObject(args, 0);
if (!object) {
warn("Routines: setMaxHitPoints: object is invalid");
warn("Script: setMaxHitPoints: object is invalid");
return 0;
}
int maxHP = getInt(args, 1);
@ -121,7 +121,7 @@ Variable Routines::setMaxHitPoints(const VariablesList &args, ExecutionContext &
Variable Routines::setMinOneHP(const VariablesList &args, ExecutionContext &ctx) {
auto object = getObject(args, 0);
if (!object) {
warn("Routines: setMinOneHP: object is invalid");
warn("Script: setMinOneHP: object is invalid");
return 0;
}
bool minOneHP = getBool(args, 1);
@ -133,12 +133,12 @@ Variable Routines::setMinOneHP(const VariablesList &args, ExecutionContext &ctx)
Variable Routines::changeFaction(const VariablesList &args, ExecutionContext &ctx) {
auto objectToChangeFaction = getCreature(args, 0);
if (!objectToChangeFaction) {
warn("Routines: changeFaction: objectToChangeFaction is invalid");
warn("Script: changeFaction: objectToChangeFaction is invalid");
return Variable();
}
auto memberOfFactionToJoin = getCreature(args, 1);
if (!memberOfFactionToJoin) {
warn("Routines: changeFaction: memberOfFactionToJoin is invalid");
warn("Script: changeFaction: memberOfFactionToJoin is invalid");
return Variable();
}
objectToChangeFaction->setFaction(memberOfFactionToJoin->faction());
@ -152,7 +152,7 @@ Variable Routines::changeToStandardFaction(const VariablesList &args, ExecutionC
Faction faction = static_cast<Faction>(getInt(args, 1));
creatureToChange->setFaction(faction);
} else {
warn("Routines: changeToStandardFaction: creatureToChange is invalid");
warn("Script: changeToStandardFaction: creatureToChange is invalid");
}
return Variable();
}
@ -160,12 +160,12 @@ Variable Routines::changeToStandardFaction(const VariablesList &args, ExecutionC
Variable Routines::getFactionEqual(const VariablesList &args, ExecutionContext &ctx) {
auto firstObject = getCreature(args, 0);
if (!firstObject) {
warn("Routines: getStandardFaction: firstObject is invalid");
warn("Script: getStandardFaction: firstObject is invalid");
return 0;
}
auto secondObject = getCreatureOrCaller(args, 1, ctx);
if (!secondObject) {
warn("Routines: getStandardFaction: secondObject is invalid");
warn("Script: getStandardFaction: secondObject is invalid");
return 0;
}
return firstObject->faction() == secondObject->faction() ? 1 : 0;
@ -174,7 +174,7 @@ Variable Routines::getFactionEqual(const VariablesList &args, ExecutionContext &
Variable Routines::getStandardFaction(const VariablesList &args, ExecutionContext &ctx) {
auto object = getCreature(args, 0);
if (!object) {
warn("Routines: getStandardFaction: object is invalid");
warn("Script: getStandardFaction: object is invalid");
return static_cast<int>(Faction::Invalid);
}
return static_cast<int>(object->faction());
@ -183,12 +183,12 @@ Variable Routines::getStandardFaction(const VariablesList &args, ExecutionContex
Variable Routines::getIsEnemy(const VariablesList &args, ExecutionContext &ctx) {
auto target = getCreature(args, 0);
if (!target) {
warn("Routines: getIsEnemy: target is invalid");
warn("Script: getIsEnemy: target is invalid");
return 0;
}
auto source = getCreatureOrCaller(args, 1, ctx);
if (!source) {
warn("Routines: getIsEnemy: source is invalid");
warn("Script: getIsEnemy: source is invalid");
return 0;
}
return Reputes::instance().getIsEnemy(*target, *source);
@ -197,12 +197,12 @@ Variable Routines::getIsEnemy(const VariablesList &args, ExecutionContext &ctx)
Variable Routines::getIsFriend(const VariablesList &args, ExecutionContext &ctx) {
auto target = getCreature(args, 0);
if (!target) {
warn("Routines: getIsFriend: target is invalid");
warn("Script: getIsFriend: target is invalid");
return 0;
}
auto source = getCreatureOrCaller(args, 1, ctx);
if (!source) {
warn("Routines: getIsFriend: source is invalid");
warn("Script: getIsFriend: source is invalid");
return 0;
}
return Reputes::instance().getIsFriend(*target, *source);
@ -211,12 +211,12 @@ Variable Routines::getIsFriend(const VariablesList &args, ExecutionContext &ctx)
Variable Routines::getIsNeutral(const VariablesList &args, ExecutionContext &ctx) {
auto target = getCreature(args, 0);
if (!target) {
warn("Routines: getIsNeutral: target is invalid");
warn("Script: getIsNeutral: target is invalid");
return 0;
}
auto source = getCreatureOrCaller(args, 1, ctx);
if (!source) {
warn("Routines: getIsNeutral: source is invalid");
warn("Script: getIsNeutral: source is invalid");
return 0;
}
return Reputes::instance().getIsNeutral(*target, *source);
@ -225,7 +225,7 @@ Variable Routines::getIsNeutral(const VariablesList &args, ExecutionContext &ctx
Variable Routines::getAbilityScore(const VariablesList &args, ExecutionContext &ctx) {
auto creature = getCreature(args, 0);
if (!creature) {
warn("Routines: getAbilityScore: creature is invalid");
warn("Script: getAbilityScore: creature is invalid");
return 0;
}
Ability type = static_cast<Ability>(getInt(args, 1));
@ -236,7 +236,7 @@ Variable Routines::getAbilityScore(const VariablesList &args, ExecutionContext &
Variable Routines::getLevelByPosition(const VariablesList &args, ExecutionContext &ctx) {
auto creature = getCreatureOrCaller(args, 1, ctx);
if (!creature) {
warn("Routines: getLevelByPosition: creature is invalid");
warn("Script: getLevelByPosition: creature is invalid");
return 0;
}
int position = getInt(args, 0);
@ -247,7 +247,7 @@ Variable Routines::getLevelByPosition(const VariablesList &args, ExecutionContex
Variable Routines::getSkillRank(const VariablesList &args, ExecutionContext &ctx) {
auto object = getCreatureOrCaller(args, 1, ctx);
if (!object) {
warn("Routines: getSkillRank: object is invalid");
warn("Script: getSkillRank: object is invalid");
return 0;
}
Skill skill = static_cast<Skill>(getInt(args, 0));
@ -258,7 +258,7 @@ Variable Routines::getSkillRank(const VariablesList &args, ExecutionContext &ctx
Variable Routines::getXP(const VariablesList &args, ExecutionContext &ctx) {
auto creature = getCreature(args, 0);
if (!creature) {
warn("Routines: getXP: creature is invalid");
warn("Script: getXP: creature is invalid");
return 0;
}
return creature->xp();
@ -270,7 +270,7 @@ Variable Routines::setXP(const VariablesList &args, ExecutionContext &ctx) {
int xpAmount = getInt(args, 1);
creature->setXP(xpAmount);
} else {
warn("Routines: setXP: creature is invalid");
warn("Script: setXP: creature is invalid");
}
return Variable();
}
@ -281,7 +281,7 @@ Variable Routines::giveXPToCreature(const VariablesList &args, ExecutionContext
int xpAmount = getInt(args, 1);
creature->giveXP(xpAmount);
} else {
warn("Routines: giveXPToCreature: creature is invalid");
warn("Script: giveXPToCreature: creature is invalid");
}
return Variable();
}

View file

@ -1,3 +1,4 @@
/*
* Copyright (c) 2020-2021 The reone project contributors
*
@ -294,12 +295,12 @@ void Routines::addTslRoutines() {
add("GetName", String, { Object }, &Routines::getName);
add("GetLastSpeaker", Object, { });
add("BeginConversation", Int, { String, Object });
add("GetLastPerceived", Object, { });
add("GetLastPerceptionHeard", Int, { });
add("GetLastPerceptionInaudible", Int, { });
add("GetLastPerceptionSeen", Int, { });
add("GetLastPerceived", Object, { }, &Routines::getLastPerceived);
add("GetLastPerceptionHeard", Int, { }, &Routines::getLastPerceptionHeard);
add("GetLastPerceptionInaudible", Int, { }, &Routines::getLastPerceptionInaudible);
add("GetLastPerceptionSeen", Int, { }, &Routines::getLastPerceptionSeen);
add("GetLastClosedBy", Object, { });
add("GetLastPerceptionVanished", Int, { });
add("GetLastPerceptionVanished", Int, { }, &Routines::getLastPerceptionVanished);
add("GetFirstInPersistentObject", Object, { Object, Int, Int });
add("GetNextInPersistentObject", Object, { Object, Int, Int });
add("GetAreaOfEffectCreator", Object, { Object });

View file

@ -48,7 +48,7 @@ Variable Routines::getGlobalString(const VariablesList &args, ExecutionContext &
Variable Routines::getLocalBoolean(const VariablesList &args, ExecutionContext &ctx) {
auto object = getObject(args, 0);
if (!object) {
warn("Routines: getLocalBoolean: object is invalid");
warn("Script: getLocalBoolean: object is invalid");
return false;
}
int index = getInt(args, 1);
@ -59,7 +59,7 @@ Variable Routines::getLocalBoolean(const VariablesList &args, ExecutionContext &
Variable Routines::getLocalNumber(const VariablesList &args, ExecutionContext &ctx) {
auto object = getObject(args, 0);
if (!object) {
warn("Routines: getLocalNumber: object is invalid");
warn("Script: getLocalNumber: object is invalid");
return false;
}
int index = getInt(args, 1);
@ -97,7 +97,7 @@ Variable Routines::setGlobalString(const VariablesList &args, ExecutionContext &
Variable Routines::setLocalBoolean(const VariablesList &args, ExecutionContext &ctx) {
auto object = getObject(args, 0);
if (!object) {
warn("Routines: setLocalBoolean: object is invalid");
warn("Script: setLocalBoolean: object is invalid");
return false;
}
int index = getInt(args, 1);
@ -110,7 +110,7 @@ Variable Routines::setLocalBoolean(const VariablesList &args, ExecutionContext &
Variable Routines::setLocalNumber(const VariablesList &args, ExecutionContext &ctx) {
auto object = getObject(args, 0);
if (!object) {
warn("Routines: setLocalNumber: object is invalid");
warn("Script: setLocalNumber: object is invalid");
return false;
}
int index = getInt(args, 1);
@ -131,7 +131,7 @@ Variable Routines::setGlobalLocation(const VariablesList &args, ExecutionContext
if (value) {
_game->setGlobalLocation(id, value);
} else {
warn("Routines: setGlobalLocation: value is invalid");
warn("Script: setGlobalLocation: value is invalid");
}
return Variable();
}

View file

@ -833,6 +833,13 @@ enum class ReputationType {
Neutral = 2
};
enum class PerceptionType {
Seen,
Vanished,
Heard,
Inaudible
};
struct InventorySlot {
static constexpr int head = 0;
static constexpr int body = 1;