feat: Implement more engine routines

This commit is contained in:
Vsevolod Kremianskii 2020-08-09 12:40:02 +07:00
parent e17ff6b071
commit b3ceb78771
12 changed files with 157 additions and 44 deletions

View file

@ -469,6 +469,16 @@ void Area::runOnEnterScript() {
ctx.delayCommand = [this](uint32_t timestamp, const ExecutionContext &ctx) {
_delayed.push_back(DelayedAction { timestamp, ctx });
};
ctx.getObjectByTag = [this](const string &tag) {
shared_ptr<Object> object(find(tag));
return object ? object->id() : 0;
};
ctx.startDialog = [this](int objectId, const string &resRef) {
shared_ptr<Object> object(find(objectId));
if (object && _onStartDialog) {
_onStartDialog(*object, resRef);
}
};
}
ScriptExecution(_scripts[ScriptType::OnEnter], ctx).run();
}
@ -789,6 +799,10 @@ void Area::setOnPlayerChanged(const function<void()> &fn) {
_onPlayerChanged = fn;
}
void Area::setOnStartDialog(const function<void(const Object &, const string &)> &fn) {
_onStartDialog = fn;
}
} // namespace game
} // namespace reone

View file

@ -92,9 +92,10 @@ public:
// Callbacks
void setOnModuleTransition(const std::function<void(const std::string &, const std::string &)> &fn);
void setOnPlayerChanged(const std::function<void()> &fn);
void setOnStartDialog(const std::function<void(const Object &, const std::string &)> &fn);
protected:
uint32_t _idCounter { 0 };
uint32_t _idCounter { 2 };
std::map<ObjectType, ObjectList> _objects;
bool _scriptsEnabled { true };
std::function<void()> _onPlayerChanged;
@ -140,6 +141,7 @@ private:
// Callbacks
std::function<void(const std::string &, const std::string &)> _onModuleTransition;
std::function<void(const Object &, const std::string &)> _onStartDialog;
std::shared_ptr<Creature> makeCharacter(const CharacterConfiguration &character, const std::string &tag, const glm::vec3 &position, float heading);
void updateDelayedActions();

View file

@ -176,6 +176,8 @@ void Game::loadDialogGui() {
Creature *prevSpeaker = !from.empty() ? static_cast<Creature *>(_module->area().find(from).get()) : nullptr;
Creature *speaker = !to.empty() ? static_cast<Creature *>(_module->area().find(to).get()) : nullptr;
if (speaker == player) return;
if (prevSpeaker) {
prevSpeaker->playDefaultAnimation();
}
@ -204,9 +206,9 @@ void Game::configureModule() {
_nextModule = name;
_nextEntry = entry;
});
_module->setStartDialog([this](const string &resRef, const string &owner) {
_module->setStartDialog([this](const Object &object, const string &resRef) {
_screen = Screen::Dialog;
_dialog->startDialog(resRef, owner);
_dialog->startDialog(object, resRef);
});
}

View file

@ -153,7 +153,7 @@ void DialogGui::onReplyClicked(int index) {
}
}
void DialogGui::startDialog(const string &resRef, const string &owner) {
void DialogGui::startDialog(const Object &owner, const string &resRef) {
shared_ptr<GffStruct> dlg(ResMan.findGFF(resRef, ResourceType::Conversation));
if (!dlg) {
if (_onDialogFinished) _onDialogFinished();
@ -162,7 +162,7 @@ void DialogGui::startDialog(const string &resRef, const string &owner) {
_dialog.reset(new Dialog());
_dialog->load(resRef, *dlg);
_currentSpeaker = owner;
_currentSpeaker = owner.tag();
if (_onSpeakerChanged) {
_onSpeakerChanged("", _currentSpeaker);
}
@ -182,10 +182,12 @@ void DialogGui::loadStartEntry() {
break;
}
}
if (entryIdx != -1) {
_currentEntry.reset(new Dialog::EntryReply(_dialog->getEntry(entryIdx)));
loadCurrentEntry();
if (entryIdx == -1) {
if (_onDialogFinished) _onDialogFinished();
return;
}
_currentEntry.reset(new Dialog::EntryReply(_dialog->getEntry(entryIdx)));
loadCurrentEntry();
}
bool DialogGui::checkCondition(const string &script) {

View file

@ -22,6 +22,7 @@
#include "../../resources/types.h"
#include "../dialog.h"
#include "../object/object.h"
namespace reone {
@ -32,7 +33,7 @@ public:
DialogGui(const render::GraphicsOptions &opts);
void load(resources::GameVersion version);
void startDialog(const std::string &resRef, const std::string &owner);
void startDialog(const Object &owner, const std::string &resRef);
void setOnSpeakerChanged(const std::function<void(const std::string &, const std::string &)> &fn);
void setOnDialogFinished(const std::function<void()> &fn);

View file

@ -84,6 +84,17 @@ void Module::loadArea(const GffStruct &ifo) {
update3rdPersonCameraTarget();
switchTo3rdPersonCamera();
});
area->setOnStartDialog([this](const Object &object, const string &resRef) {
if (!_startDialog) return;
const Creature &creature = static_cast<const Creature &>(object);
string finalResRef(resRef);
if (resRef.empty()) finalResRef = creature.conversation();
if (resRef.empty()) return;
_startDialog(object, finalResRef);
});
area->load(*are, *git);
_area = move(area);
}
@ -223,7 +234,7 @@ bool Module::handleMouseButtonUp(const SDL_MouseButtonEvent &event) {
if (!creature->conversation().empty() && _startDialog) {
resetInput();
getCamera()->resetInput();
_startDialog(creature->conversation(), creature->tag());
_startDialog(*creature, creature->conversation());
}
}
@ -397,7 +408,7 @@ void Module::setOnModuleTransition(const function<void(const string &, const str
_onModuleTransition = fn;
}
void Module::setStartDialog(const function<void(const string &, const string &)> &fn) {
void Module::setStartDialog(const function<void(const Object &, const string &)> &fn) {
_startDialog = fn;
}

View file

@ -72,7 +72,7 @@ public:
// Callbacks
void setOnCameraChanged(const std::function<void(render::CameraType)> &fn);
void setOnModuleTransition(const std::function<void(const std::string &, const std::string &)> &fn);
void setStartDialog(const std::function<void(const std::string &, const std::string &)> &fn);
void setStartDialog(const std::function<void(const Object &, const std::string &)> &fn);
protected:
resources::GameVersion _version { resources::GameVersion::KotOR };
@ -95,7 +95,7 @@ private:
// Callbacks
std::function<void(render::CameraType)> _onCameraChanged;
std::function<void(const std::string &, const std::string &)> _onModuleTransition;
std::function<void(const std::string &, const std::string &)> _startDialog;
std::function<void(const Object &, const std::string &)> _startDialog;
void loadInfo(const resources::GffStruct &ifo);
void loadArea(const resources::GffStruct &ifo);

View file

@ -105,6 +105,20 @@ Variable RoutineManager::delayCommand(const vector<Variable> &args, ExecutionCon
return Variable();
}
Variable RoutineManager::assignCommand(const vector<Variable> &args, ExecutionContext &ctx) {
assert(
args.size() == 2 &&
args[0].type == VariableType::Object &&
args[1].type == VariableType::Action);
ExecutionContext newCtx(args[1].context);
newCtx.callerId = args[0].objectId;
ctx.delayCommand(SDL_GetTicks(), newCtx);
return Variable();
}
Variable RoutineManager::getEnteringObject(const vector<Variable> &args, ExecutionContext &ctx) {
Variable result(VariableType::Object);
result.objectId = ctx.enteringObjectId;
@ -116,6 +130,61 @@ Variable RoutineManager::getIsPC(const vector<Variable> &args, ExecutionContext
return Variable(args[0].objectId == ctx.playerId);
}
Variable RoutineManager::getIsObjectValid(const vector<Variable> &args, ExecutionContext &ctx) {
assert(!args.empty() && args[0].type == VariableType::Object);
return Variable(args[0].objectId != kObjectInvalid);
}
Variable RoutineManager::getFirstPC(const vector<Variable> &args, ExecutionContext &ctx) {
Variable result(VariableType::Object);
result.objectId = ctx.playerId;
return move(result);
}
Variable RoutineManager::getObjectByTag(const vector<Variable> &args, ExecutionContext &ctx) {
assert(!args.empty() && args[0].type == VariableType::String);
Variable result(VariableType::Object);
result.objectId = ctx.getObjectByTag ? ctx.getObjectByTag(args[0].strValue) : 0;
return move(result);
}
Variable RoutineManager::getLevelByClass(const vector<Variable> &args, ExecutionContext &ctx) {
assert(
!args.empty() &&
args[0].type == VariableType::Int &&
args[1].type == VariableType::Object);
int clazz = args[0].intValue;
int objectId = args.size() < 2 ? 0 : args[1].objectId;
// TODO: return value based on class
return Variable(1);
}
Variable RoutineManager::getGender(const vector<Variable> &args, ExecutionContext &ctx) {
assert(!args.empty() && args[0].type == VariableType::Object);
int objectId = args[0].objectId;
return Variable();
}
Variable RoutineManager::actionStartConversation(const vector<Variable> &args, ExecutionContext &ctx) {
assert(!args.empty() && args[0].type == VariableType::Object);
int objectId = args[0].objectId;
string resRef(args.size() >= 2 ? args[1].strValue : "");
if (ctx.startDialog) {
ctx.startDialog(objectId, resRef);
}
return Variable();
}
} // namespace script
} // namespace reone

View file

@ -69,8 +69,15 @@ private:
// Routine implementations
Variable delayCommand(const std::vector<Variable> &args, ExecutionContext &ctx);
Variable assignCommand(const std::vector<Variable> &args, ExecutionContext &ctx);
Variable getEnteringObject(const std::vector<Variable> &args, ExecutionContext &ctx);
Variable getIsPC(const std::vector<Variable> &args, ExecutionContext &ctx);
Variable getIsObjectValid(const std::vector<Variable> &args, ExecutionContext &ctx);
Variable getFirstPC(const std::vector<Variable> &args, ExecutionContext &ctx);
Variable getObjectByTag(const std::vector<Variable> &args, ExecutionContext &ctx);
Variable getLevelByClass(const std::vector<Variable> &args, ExecutionContext &ctx);
Variable getGender(const std::vector<Variable> &args, ExecutionContext &ctx);
Variable actionStartConversation(const std::vector<Variable> &args, ExecutionContext &ctx);
};
#define RoutineMan script::RoutineManager::instance()

View file

@ -43,7 +43,7 @@ void RoutineManager::addKotorRoutines() {
_routines.emplace_back("FloatToString", String, vector<VariableType> { Float, Int, Int });
_routines.emplace_back("PrintInteger", Void, vector<VariableType> { Int });
_routines.emplace_back("PrintObject", Void, vector<VariableType> { Object });
_routines.emplace_back("AssignCommand", Void, vector<VariableType> { Object, Action });
_routines.emplace_back("AssignCommand", Void, vector<VariableType> { Object, Action }, bind(&RoutineManager::assignCommand, this, _1, _2));
_routines.emplace_back("DelayCommand", Void, vector<VariableType> { Float, Action }, bind(&RoutineManager::delayCommand, this, _1, _2));
_routines.emplace_back("ExecuteScript", Void, vector<VariableType> { String, Object, Int });
_routines.emplace_back("ClearAllActions", Void, vector<VariableType>());
@ -79,7 +79,7 @@ void RoutineManager::addKotorRoutines() {
_routines.emplace_back("ActionSpeakString", Void, vector<VariableType> { String, Int });
_routines.emplace_back("ActionPlayAnimation", Void, vector<VariableType> { Int, Float, Float });
_routines.emplace_back("GetDistanceToObject", Float, vector<VariableType> { Object });
_routines.emplace_back("GetIsObjectValid", Int, vector<VariableType> { Object });
_routines.emplace_back("GetIsObjectValid", Int, vector<VariableType> { Object }, bind(&RoutineManager::getIsObjectValid, this, _1, _2));
_routines.emplace_back("ActionOpenDoor", Void, vector<VariableType> { Object });
_routines.emplace_back("ActionCloseDoor", Void, vector<VariableType> { Object });
_routines.emplace_back("SetCameraFacing", Void, vector<VariableType> { Float });
@ -237,11 +237,11 @@ void RoutineManager::addKotorRoutines() {
_routines.emplace_back("GetWaypointByTag", Object, vector<VariableType> { String });
_routines.emplace_back("GetTransitionTarget", Object, vector<VariableType> { Object });
_routines.emplace_back("EffectLinkEffects", Effect, vector<VariableType> { Effect, Effect });
_routines.emplace_back("GetObjectByTag", Object, vector<VariableType> { String, Int });
_routines.emplace_back("GetObjectByTag", Object, vector<VariableType> { String, Int }, bind(&RoutineManager::getObjectByTag, this, _1, _2));
_routines.emplace_back("AdjustAlignment", Void, vector<VariableType> { Object, Int, Int });
_routines.emplace_back("ActionWait", Void, vector<VariableType> { Float });
_routines.emplace_back("SetAreaTransitionBMP", Void, vector<VariableType> { Int, String });
_routines.emplace_back("ActionStartConversation", Void, vector<VariableType> { Object, String, Int, Int, Int, String, String, String, String, String, String, Int });
_routines.emplace_back("ActionStartConversation", Void, vector<VariableType> { Object, String, Int, Int, Int, String, String, String, String, String, String, Int }, bind(&RoutineManager::actionStartConversation, this, _1, _2));
_routines.emplace_back("ActionPauseConversation", Void, vector<VariableType>());
_routines.emplace_back("ActionResumeConversation", Void, vector<VariableType>());
_routines.emplace_back("EffectBeam", Effect, vector<VariableType> { Int, Object, Int, Int });
@ -380,7 +380,7 @@ void RoutineManager::addKotorRoutines() {
_routines.emplace_back("GetNextItemInInventory", Object, vector<VariableType> { Object });
_routines.emplace_back("GetClassByPosition", Int, vector<VariableType> { Int, Object });
_routines.emplace_back("GetLevelByPosition", Int, vector<VariableType> { Int, Object });
_routines.emplace_back("GetLevelByClass", Int, vector<VariableType> { Int, Object });
_routines.emplace_back("GetLevelByClass", Int, vector<VariableType> { Int, Object }, bind(&RoutineManager::getLevelByClass, this, _1, _2));
_routines.emplace_back("GetDamageDealtByType", Int, vector<VariableType> { Int });
_routines.emplace_back("GetTotalDamageDealt", Int, vector<VariableType>());
_routines.emplace_back("GetLastDamager", Object, vector<VariableType>());
@ -395,7 +395,7 @@ void RoutineManager::addKotorRoutines() {
_routines.emplace_back("VersusAlignmentEffect", Effect, vector<VariableType> { Effect, Int, Int });
_routines.emplace_back("VersusRacialTypeEffect", Effect, vector<VariableType> { Effect, Int });
_routines.emplace_back("VersusTrapEffect", Effect, vector<VariableType> { Effect });
_routines.emplace_back("GetGender", Int, vector<VariableType> { Object });
_routines.emplace_back("GetGender", Int, vector<VariableType> { Object }, bind(&RoutineManager::getGender, this, _1, _2));
_routines.emplace_back("GetIsTalentValid", Int, vector<VariableType> { Talent });
_routines.emplace_back("ActionMoveAwayFromLocation", Void, vector<VariableType> { Location, Int, Float });
_routines.emplace_back("GetAttemptedAttackTarget", Object, vector<VariableType>());
@ -585,8 +585,8 @@ void RoutineManager::addKotorRoutines() {
_routines.emplace_back("GetPlaceableIllumination", Int, vector<VariableType> { Object });
_routines.emplace_back("GetIsPlaceableObjectActionPossible", Int, vector<VariableType> { Object, Int });
_routines.emplace_back("DoPlaceableObjectAction", Void, vector<VariableType> { Object, Int });
_routines.emplace_back("GetFirstPC", Object, vector<VariableType>());
_routines.emplace_back("GetNextPC", Object, vector<VariableType>());
_routines.emplace_back("GetFirstPC", Object, vector<VariableType>(), bind(&RoutineManager::getFirstPC, this, _1, _2));
_routines.emplace_back("GetNextPC", Object, vector<VariableType>(), bind(&RoutineManager::getFirstPC, this, _1, _2));
_routines.emplace_back("SetTrapDetectedBy", Int, vector<VariableType> { Object, Object });
_routines.emplace_back("GetIsTrapped", Int, vector<VariableType> { Object });
_routines.emplace_back("SetEffectIcon", Effect, vector<VariableType> { Effect, Int });

View file

@ -1,19 +1,19 @@
/*
* Copyright © Vsevolod Kremianskii
*
* 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/>.
*/
* Copyright © Vsevolod Kremianskii
*
* 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"
@ -43,7 +43,7 @@ void RoutineManager::addTslRoutines() {
_routines.emplace_back("FloatToString", String, vector<VariableType> { Float, Int, Int });
_routines.emplace_back("PrintInteger", Void, vector<VariableType> { Int });
_routines.emplace_back("PrintObject", Void, vector<VariableType> { Object });
_routines.emplace_back("AssignCommand", Void, vector<VariableType> { Object, Action });
_routines.emplace_back("AssignCommand", Void, vector<VariableType> { Object, Action }, bind(&RoutineManager::assignCommand, this, _1, _2));
_routines.emplace_back("DelayCommand", Void, vector<VariableType> { Float, Action }, bind(&RoutineManager::delayCommand, this, _1, _2));
_routines.emplace_back("ExecuteScript", Void, vector<VariableType> { String, Object, Int });
_routines.emplace_back("ClearAllActions", Void, vector<VariableType>());
@ -79,7 +79,7 @@ void RoutineManager::addTslRoutines() {
_routines.emplace_back("ActionSpeakString", Void, vector<VariableType> { String, Int });
_routines.emplace_back("ActionPlayAnimation", Void, vector<VariableType> { Int, Float, Float });
_routines.emplace_back("GetDistanceToObject", Float, vector<VariableType> { Object });
_routines.emplace_back("GetIsObjectValid", Int, vector<VariableType> { Object });
_routines.emplace_back("GetIsObjectValid", Int, vector<VariableType> { Object }, bind(&RoutineManager::getIsObjectValid, this, _1, _2));
_routines.emplace_back("ActionOpenDoor", Void, vector<VariableType> { Object });
_routines.emplace_back("ActionCloseDoor", Void, vector<VariableType> { Object });
_routines.emplace_back("SetCameraFacing", Void, vector<VariableType> { Float });
@ -237,11 +237,11 @@ void RoutineManager::addTslRoutines() {
_routines.emplace_back("GetWaypointByTag", Object, vector<VariableType> { String });
_routines.emplace_back("GetTransitionTarget", Object, vector<VariableType> { Object });
_routines.emplace_back("EffectLinkEffects", Effect, vector<VariableType> { Effect, Effect });
_routines.emplace_back("GetObjectByTag", Object, vector<VariableType> { String, Int });
_routines.emplace_back("GetObjectByTag", Object, vector<VariableType> { String, Int }, bind(&RoutineManager::getObjectByTag, this, _1, _2));
_routines.emplace_back("AdjustAlignment", Void, vector<VariableType> { Object, Int, Int, Int });
_routines.emplace_back("ActionWait", Void, vector<VariableType> { Float });
_routines.emplace_back("SetAreaTransitionBMP", Void, vector<VariableType> { Int, String });
_routines.emplace_back("ActionStartConversation", Void, vector<VariableType> { Object, String, Int, Int, Int, String, String, String, String, String, String, Int, Int, Int, Int });
_routines.emplace_back("ActionStartConversation", Void, vector<VariableType> { Object, String, Int, Int, Int, String, String, String, String, String, String, Int, Int, Int, Int }, bind(&RoutineManager::actionStartConversation, this, _1, _2));
_routines.emplace_back("ActionPauseConversation", Void, vector<VariableType>());
_routines.emplace_back("ActionResumeConversation", Void, vector<VariableType>());
_routines.emplace_back("EffectBeam", Effect, vector<VariableType> { Int, Object, Int, Int });
@ -380,7 +380,7 @@ void RoutineManager::addTslRoutines() {
_routines.emplace_back("GetNextItemInInventory", Object, vector<VariableType> { Object });
_routines.emplace_back("GetClassByPosition", Int, vector<VariableType> { Int, Object });
_routines.emplace_back("GetLevelByPosition", Int, vector<VariableType> { Int, Object });
_routines.emplace_back("GetLevelByClass", Int, vector<VariableType> { Int, Object });
_routines.emplace_back("GetLevelByClass", Int, vector<VariableType> { Int, Object }, bind(&RoutineManager::getLevelByClass, this, _1, _2));
_routines.emplace_back("GetDamageDealtByType", Int, vector<VariableType> { Int });
_routines.emplace_back("GetTotalDamageDealt", Int, vector<VariableType>());
_routines.emplace_back("GetLastDamager", Object, vector<VariableType>());
@ -395,7 +395,7 @@ void RoutineManager::addTslRoutines() {
_routines.emplace_back("VersusAlignmentEffect", Effect, vector<VariableType> { Effect, Int, Int });
_routines.emplace_back("VersusRacialTypeEffect", Effect, vector<VariableType> { Effect, Int });
_routines.emplace_back("VersusTrapEffect", Effect, vector<VariableType> { Effect });
_routines.emplace_back("GetGender", Int, vector<VariableType> { Object });
_routines.emplace_back("GetGender", Int, vector<VariableType> { Object }, bind(&RoutineManager::getGender, this, _1, _2));
_routines.emplace_back("GetIsTalentValid", Int, vector<VariableType> { Talent });
_routines.emplace_back("ActionMoveAwayFromLocation", Void, vector<VariableType> { Location, Int, Float });
_routines.emplace_back("GetAttemptedAttackTarget", Object, vector<VariableType>());
@ -585,8 +585,8 @@ void RoutineManager::addTslRoutines() {
_routines.emplace_back("GetPlaceableIllumination", Int, vector<VariableType> { Object });
_routines.emplace_back("GetIsPlaceableObjectActionPossible", Int, vector<VariableType> { Object, Int });
_routines.emplace_back("DoPlaceableObjectAction", Void, vector<VariableType> { Object, Int });
_routines.emplace_back("GetFirstPC", Object, vector<VariableType>());
_routines.emplace_back("GetNextPC", Object, vector<VariableType>());
_routines.emplace_back("GetFirstPC", Object, vector<VariableType>(), bind(&RoutineManager::getFirstPC, this, _1, _2));
_routines.emplace_back("GetNextPC", Object, vector<VariableType>(), bind(&RoutineManager::getFirstPC, this, _1, _2));
_routines.emplace_back("SetTrapDetectedBy", Int, vector<VariableType> { Object, Object });
_routines.emplace_back("GetIsTrapped", Int, vector<VariableType> { Object });
_routines.emplace_back("SetEffectIcon", Effect, vector<VariableType> { Effect, Int });

View file

@ -27,6 +27,9 @@ namespace reone {
namespace script {
const uint32_t kObjectSelf = 0;
const uint32_t kObjectInvalid = 1;
class ScriptProgram;
struct Variable;
@ -43,6 +46,8 @@ struct ExecutionContext {
uint32_t playerId { 0xffffffff };
uint32_t enteringObjectId { 0xffffffff };
std::function<void(uint32_t, const ExecutionContext &)> delayCommand;
std::function<uint32_t(const std::string &)> getObjectByTag;
std::function<void(int, const std::string &)> startDialog;
};
} // namespace script