-
Notifications
You must be signed in to change notification settings - Fork 61
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Externals: Split up into different files
- Loading branch information
Showing
9 changed files
with
1,535 additions
and
1,111 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,378 @@ | ||
#include "Externals_AI.h" | ||
#include <components/VobClasses.h> | ||
#include <daedalus/DaedalusStdlib.h> | ||
#include <daedalus/DaedalusVM.h> | ||
#include <debugdraw/debugdraw.h> | ||
#include <engine/GameEngine.h> | ||
#include <logic/DialogManager.h> | ||
#include <logic/PlayerController.h> | ||
#include <logic/ScriptEngine.h> | ||
#include <logic/visuals/ModelVisual.h> | ||
#include <ui/PrintScreenMessages.h> | ||
#include <utils/logger.h> | ||
|
||
using namespace Logic; | ||
|
||
void ScriptExternals::registerEngineExternals_ai(World::WorldInstance& world, Daedalus::DaedalusVM* vm, bool verbose) | ||
{ | ||
Engine::BaseEngine* engine = world.getEngine(); | ||
World::WorldInstance* pWorld = &world; | ||
using Daedalus::GameState::ItemHandle; | ||
using Daedalus::GameState::NpcHandle; | ||
|
||
auto isSymInstanceValid = [vm](size_t instance) { | ||
return vm->getDATFile().getSymbolByIndex(instance).instanceDataHandle.isValid(); | ||
}; | ||
|
||
// TODO: Refractor | ||
auto getNPCByInstance = [vm, engine](size_t instance) { | ||
assert(vm->getDATFile().getSymbolByIndex(instance).instanceDataClass == Daedalus::EInstanceClass::IC_Npc); | ||
|
||
NpcHandle hnpc = ZMemory::handleCast<NpcHandle>(vm->getDATFile().getSymbolByIndex(instance).instanceDataHandle); | ||
|
||
if (!hnpc.isValid()) | ||
{ | ||
//LogWarn() << "Invalid handle in instance: " << instance << " (" << vm->getDATFile().getSymbolByIndex(instance).name << ")"; | ||
//LogWarn() << "Callstack: " << vm->getCallStack(); | ||
|
||
VobTypes::NpcVobInformation vob; | ||
vob.entity.invalidate(); | ||
return vob; | ||
} | ||
|
||
// Get data of npc this belongs to | ||
Daedalus::GEngineClasses::C_Npc& npcData = vm->getGameState().getNpc(hnpc); | ||
VobTypes::ScriptInstanceUserData* userData = reinterpret_cast<VobTypes::ScriptInstanceUserData*>(npcData.userPtr); | ||
|
||
if (userData) | ||
{ | ||
World::WorldInstance& world = engine->getWorldInstance(userData->world); | ||
VobTypes::NpcVobInformation vob = VobTypes::asNpcVob(world, userData->vobEntity); | ||
|
||
return vob; | ||
} | ||
else | ||
{ | ||
LogWarn() << "No userptr on npc: " << npcData.name[0]; | ||
|
||
VobTypes::NpcVobInformation vob; | ||
vob.entity.invalidate(); | ||
|
||
return vob; | ||
} | ||
}; | ||
|
||
auto getItemByInstance = [vm, engine](size_t instance) { | ||
auto& parSymbol = vm->getDATFile().getSymbolByIndex(instance); | ||
Daedalus::GameState::ItemHandle hitem = ZMemory::handleCast<Daedalus::GameState::ItemHandle>(parSymbol.instanceDataHandle); | ||
|
||
if (hitem.isValid()) | ||
{ | ||
// Get data of npc this belongs to | ||
Daedalus::GEngineClasses::C_Item& itemData = vm->getGameState().getItem(hitem); | ||
VobTypes::ScriptInstanceUserData* userData = reinterpret_cast<VobTypes::ScriptInstanceUserData*>(itemData.userPtr); | ||
|
||
if (userData) | ||
{ | ||
World::WorldInstance& world = engine->getWorldInstance(userData->world); | ||
Vob::VobInformation vob = Vob::asVob(world, userData->vobEntity); | ||
|
||
return vob; | ||
} | ||
else | ||
{ | ||
LogWarn() << "No userptr on item: " << itemData.name; | ||
} | ||
} | ||
else | ||
{ | ||
LogWarn() << "could not get item handle from ParSymbol: " << parSymbol.name; | ||
} | ||
Vob::VobInformation vob; | ||
vob.entity.invalidate(); | ||
return vob; | ||
}; | ||
|
||
vm->registerExternalFunction("ai_teleport", [=](Daedalus::DaedalusVM& vm) { | ||
std::string waypoint = vm.popString(); | ||
int32_t self = vm.popVar(); | ||
|
||
const auto waypointIndex = World::Waynet::getWaypointIndex(pWorld->getWaynet(), waypoint); | ||
VobTypes::NpcVobInformation npcVob = getNPCByInstance(self); | ||
if (waypointIndex != World::Waynet::INVALID_WAYPOINT || npcVob.isValid()) | ||
npcVob.playerController->teleportToWaypoint(waypointIndex); | ||
}); | ||
|
||
vm->registerExternalFunction("ai_turntonpc", [=](Daedalus::DaedalusVM& vm) { | ||
uint32_t arr_n1; | ||
int32_t target = vm.popVar(arr_n1); | ||
if (verbose) LogInfo() << "target: " << target; | ||
uint32_t arr_n0; | ||
int32_t self = vm.popVar(arr_n0); | ||
if (verbose) LogInfo() << "self: " << self; | ||
|
||
if (!isSymInstanceValid(self) || !isSymInstanceValid(target)) | ||
return; | ||
|
||
VobTypes::NpcVobInformation selfvob = getNPCByInstance(self); | ||
VobTypes::NpcVobInformation targetvob = getNPCByInstance(target); | ||
|
||
// Fill turn message | ||
EventMessages::MovementMessage msg; | ||
msg.subType = EventMessages::MovementMessage::ST_TurnToVob; | ||
msg.targetVob = targetvob.entity; | ||
|
||
// Push the message | ||
selfvob.playerController->getEM().onMessage(msg); | ||
}); | ||
|
||
vm->registerExternalFunction("ai_standup", [=](Daedalus::DaedalusVM& vm) { | ||
uint32_t self = vm.popVar(); | ||
|
||
VobTypes::NpcVobInformation npc = getNPCByInstance(self); | ||
|
||
if (npc.isValid()) | ||
{ | ||
// Fill standup message | ||
EventMessages::MovementMessage msg; | ||
msg.subType = EventMessages::MovementMessage::ST_Standup; | ||
msg.targetMode = 1; // Play transition-anis | ||
|
||
// Push the message | ||
npc.playerController->getEM().onMessage(msg); | ||
} | ||
}); | ||
|
||
vm->registerExternalFunction("ai_standupquick", [=](Daedalus::DaedalusVM& vm) { | ||
uint32_t self = vm.popVar(); | ||
|
||
VobTypes::NpcVobInformation npc = getNPCByInstance(self); | ||
|
||
if (npc.isValid()) | ||
{ | ||
// Fill standup message | ||
EventMessages::MovementMessage msg; | ||
msg.subType = EventMessages::MovementMessage::ST_Standup; | ||
msg.targetMode = 0; // No transitions | ||
|
||
// Push the message | ||
npc.playerController->getEM().onMessage(msg); | ||
} | ||
}); | ||
|
||
vm->registerExternalFunction("ai_gotowp", [=](Daedalus::DaedalusVM& vm) { | ||
std::string wp = vm.popString(); | ||
int32_t self = vm.popVar(); | ||
|
||
if (!World::Waynet::waypointExists(pWorld->getWaynet(), wp)) | ||
return; | ||
|
||
VobTypes::NpcVobInformation npc = getNPCByInstance(self); | ||
|
||
if (npc.isValid()) | ||
{ | ||
EventMessages::MovementMessage sm; | ||
sm.subType = EventMessages::MovementMessage::ST_GotoVob; | ||
sm.targetVobName = wp; | ||
|
||
npc.playerController->getEM().onMessage(sm); | ||
//npc.playerController->gotoWaypoint(World::Waynet::getWaypointIndex(pWorld->getWaynet(), wp)); | ||
} | ||
}); | ||
|
||
vm->registerExternalFunction("ai_gotonextfp", [=](Daedalus::DaedalusVM& vm) { | ||
std::string fpname = vm.popString(true); | ||
int32_t self = vm.popVar(); | ||
|
||
// FIXME: Same as ai_gotofp. What's the exact difference between them? | ||
VobTypes::NpcVobInformation npc = getNPCByInstance(self); | ||
|
||
if (npc.isValid()) | ||
{ | ||
// Find closest fp | ||
std::vector<Handle::EntityHandle> fp = pWorld->getFreepointsInRange(npc.position->m_WorldMatrix.Translation(), 20.0f, fpname, true); | ||
|
||
if (!fp.empty()) | ||
{ | ||
EventMessages::MovementMessage sm; | ||
sm.subType = EventMessages::MovementMessage::ST_GotoFP; | ||
sm.targetVob = fp.front(); | ||
npc.playerController->getEM().onMessage(sm); | ||
} | ||
} | ||
}); | ||
|
||
vm->registerExternalFunction("ai_gotofp", [=](Daedalus::DaedalusVM& vm) { | ||
std::string fpname = vm.popString(true); | ||
int32_t self = vm.popVar(); | ||
|
||
VobTypes::NpcVobInformation npc = getNPCByInstance(self); | ||
|
||
if (npc.isValid()) | ||
{ | ||
// Find closest fp | ||
std::vector<Handle::EntityHandle> fp = pWorld->getFreepointsInRange(npc.position->m_WorldMatrix.Translation(), 20.0f, fpname, true); | ||
|
||
if (!fp.empty()) | ||
{ | ||
EventMessages::MovementMessage sm; | ||
sm.subType = EventMessages::MovementMessage::ST_GotoFP; | ||
sm.targetVob = fp.front(); | ||
npc.playerController->getEM().onMessage(sm); | ||
} | ||
} | ||
}); | ||
|
||
vm->registerExternalFunction("ai_gotonpc", [=](Daedalus::DaedalusVM& vm) { | ||
uint32_t other = vm.popVar(); | ||
uint32_t self = vm.popVar(); | ||
|
||
VobTypes::NpcVobInformation nself = getNPCByInstance(self); | ||
VobTypes::NpcVobInformation nother = getNPCByInstance(other); | ||
|
||
if (nself.isValid()) | ||
{ | ||
EventMessages::MovementMessage sm; | ||
sm.subType = EventMessages::MovementMessage::ST_GotoVob; | ||
sm.targetVob = nother.entity; | ||
|
||
nself.playerController->getEM().onMessage(sm); | ||
//npc.playerController->gotoWaypoint(World::Waynet::getWaypointIndex(pWorld->getWaynet(), wp)); | ||
} | ||
}); | ||
|
||
vm->registerExternalFunction("ai_startstate", [=](Daedalus::DaedalusVM& vm) { | ||
std::string wpname = vm.popString(); | ||
int32_t statebehaviour = vm.popDataValue(); | ||
uint32_t fnSym = vm.popVar(); | ||
int32_t self = vm.popVar(); | ||
|
||
VobTypes::NpcVobInformation npc = getNPCByInstance(self); | ||
|
||
if (npc.isValid()) | ||
{ | ||
EventMessages::StateMessage sm; | ||
sm.subType = EventMessages::StateMessage::EV_StartState; | ||
sm.wpname = wpname; | ||
sm.functionSymbol = fnSym; | ||
sm.other = pWorld->getScriptEngine().getNPCFromSymbol("other"); | ||
sm.victim = pWorld->getScriptEngine().getNPCFromSymbol("victim"); | ||
|
||
npc.playerController->getEM().onMessage(sm); | ||
} | ||
}); | ||
|
||
vm->registerExternalFunction("ai_wait", [=](Daedalus::DaedalusVM& vm) { | ||
float duration = vm.popFloatValue(); | ||
int32_t self = vm.popVar(); | ||
|
||
VobTypes::NpcVobInformation npc = getNPCByInstance(self); | ||
|
||
if (npc.isValid()) | ||
{ | ||
EventMessages::StateMessage sm; | ||
sm.subType = EventMessages::StateMessage::EV_Wait; | ||
sm.waitTime = duration; | ||
|
||
npc.playerController->getEM().onMessage(sm); | ||
} | ||
}); | ||
|
||
vm->registerExternalFunction("ai_playani", [=](Daedalus::DaedalusVM& vm) { | ||
std::string ani = vm.popString(); | ||
uint32_t self = vm.popVar(); | ||
|
||
VobTypes::NpcVobInformation npc = getNPCByInstance(self); | ||
|
||
if (npc.isValid()) | ||
{ | ||
EventMessages::ConversationMessage sm; | ||
sm.subType = EventMessages::ConversationMessage::ST_PlayAni; | ||
sm.animation = ani; | ||
|
||
// Don't schedule random animations when the npc is the target of the dialog manager | ||
// Should not be necessary since npc should be in ZS_TALK state. Remove when state issue is resolved | ||
NpcHandle npcHandle = npc.playerController->getScriptHandle(); | ||
auto& dialogManager = pWorld->getDialogManager(); | ||
if (dialogManager.isDialogActive() && dialogManager.getTarget() == npcHandle) | ||
{ | ||
//LogInfo() << "Animation got canceled (DialogActive): npc = " << npc.playerController->getScriptInstance().name[0] << ", ani = " << ani; | ||
} | ||
else | ||
{ | ||
npc.playerController->getEM().onMessage(sm); | ||
} | ||
} | ||
}); | ||
|
||
vm->registerExternalFunction("ai_setwalkmode", [=](Daedalus::DaedalusVM& vm) { | ||
using EventMessages::MovementMessage; | ||
|
||
int32_t walkmode = vm.popDataValue(); | ||
uint32_t self = vm.popVar(); | ||
|
||
VobTypes::NpcVobInformation npc = getNPCByInstance(self); | ||
|
||
if (npc.isValid()) | ||
{ | ||
MovementMessage msg; | ||
msg.subType = MovementMessage::ST_SetWalkMode; | ||
msg.walkMode = static_cast<MovementMessage::WalkMode>(walkmode); | ||
|
||
npc.playerController->getEM().onMessage(msg); | ||
} | ||
}); | ||
|
||
vm->registerExternalFunction("ai_stopprocessinfos", [=](Daedalus::DaedalusVM& vm) { | ||
// the self argument is the NPC, the player is talking with | ||
uint32_t self = vm.popVar(); | ||
NpcHandle hself = ZMemory::handleCast<NpcHandle>(vm.getDATFile().getSymbolByIndex(self).instanceDataHandle); | ||
|
||
// Notify DialogManager | ||
pWorld->getDialogManager().queueDialogEndEvent(hself); | ||
}); | ||
|
||
vm->registerExternalFunction("ai_output", [=](Daedalus::DaedalusVM& vm) { | ||
std::string outputname = vm.popString(); | ||
uint32_t target = vm.popVar(); | ||
uint32_t self = vm.popVar(); | ||
|
||
NpcHandle hself = ZMemory::handleCast<NpcHandle>(vm.getDATFile().getSymbolByIndex(self).instanceDataHandle); | ||
NpcHandle htarget = ZMemory::handleCast<NpcHandle>(vm.getDATFile().getSymbolByIndex(target).instanceDataHandle); | ||
|
||
auto& dialogManager = pWorld->getDialogManager(); | ||
auto& message = dialogManager.getScriptDialogManager()->getMessageLib().getMessageByName(outputname); | ||
dialogManager.onAIOutput(hself, htarget, message); | ||
}); | ||
|
||
vm->registerExternalFunction("ai_outputsvm", [=](Daedalus::DaedalusVM& vm) { | ||
std::string svmname = vm.popString(); | ||
int32_t target = vm.popVar(); | ||
int32_t self = vm.popVar(); | ||
|
||
NpcHandle hself = ZMemory::handleCast<NpcHandle>(vm.getDATFile().getSymbolByIndex(self).instanceDataHandle); | ||
NpcHandle htarget = ZMemory::handleCast<NpcHandle>(vm.getDATFile().getSymbolByIndex(target).instanceDataHandle); | ||
Daedalus::GEngineClasses::C_Npc& cSelf = vm.getGameState().getNpc(hself); | ||
|
||
std::string messageName = "SVM_" + std::to_string(cSelf.voice) + "_" + svmname.substr(1); | ||
|
||
auto& dialogManager = pWorld->getDialogManager(); | ||
auto& messageLib = dialogManager.getScriptDialogManager()->getMessageLib(); | ||
if (!messageLib.messageExists(messageName)) | ||
{ | ||
LogError() << "Error: SVM file not found: " + messageName; // happens for Character Helper (voice=15) in g2 | ||
return; | ||
} | ||
auto& message = messageLib.getMessageByName(messageName); | ||
dialogManager.onAIOutput(hself, htarget, message); | ||
}); | ||
|
||
vm->registerExternalFunction("AI_ProcessInfos", [=](Daedalus::DaedalusVM& vm) { | ||
uint32_t self = vm.popVar(); | ||
|
||
NpcHandle hself = ZMemory::handleCast<NpcHandle>(vm.getDATFile().getSymbolByIndex(self).instanceDataHandle); | ||
|
||
auto player = VobTypes::asNpcVob(engine->getMainWorld().get(), engine->getMainWorld().get().getScriptEngine().getPlayerEntity()); | ||
pWorld->getDialogManager().startDialog(hself, player.playerController->getScriptHandle()); | ||
}); | ||
} |
Oops, something went wrong.