diff --git a/lua-scripts/data.lua b/lua-scripts/data.lua index 3eb02bd..06d801e 100644 --- a/lua-scripts/data.lua +++ b/lua-scripts/data.lua @@ -656,6 +656,29 @@ setup_handler(function(event, trigger_entity, what_entity) end end) +setup_action_handler("talk", { + count = 0, + activate = function(this) + this._narration("Booo!! Lua...", {"One", "Two", "Three"}) + end, + event = function(this, event) + this.count = this.count + 1 + if event == "narration_progress" then + this.count = this.count + 1 + this._narration("Booo!!!", {}) + end + if event == "narration_answered" then + this.count = this.count + 1 + this._narration("Booo!!!_", {}) + end + if this.count > 10 then + this._finish() + end + end, + finish = function(this) + this.count = 0 + end, +}) --[[ active_dialogues = {} setup_action_handler("talk", function(town, index, word) diff --git a/src/gamedata/CharacterManagerModule.cpp b/src/gamedata/CharacterManagerModule.cpp index 9c1a83e..af97015 100644 --- a/src/gamedata/CharacterManagerModule.cpp +++ b/src/gamedata/CharacterManagerModule.cpp @@ -12,21 +12,11 @@ namespace ECS { -struct TownNPCs { - struct NPCData { - flecs::entity e; - nlohmann::json props; - Ogre::Vector3 position; - Ogre::Quaternion orientation; - Ogre::String model; - }; - - std::map npcs; -}; -struct LivesIn {}; void createNPCActionNodes(flecs::entity town, flecs::entity e, int index) { NPCActionNodes &anodes = e.get_mut(); + const TownNPCs &npcs = town.get(); + nlohmann::json npcprops = npcs.npcs.at(index).props; const CharacterBase &ch = e.get(); Ogre::Vector3 characterPos = ch.mBodyNode->_getDerivedPosition(); Ogre::Quaternion characterRot = ch.mBodyNode->_getDerivedOrientation(); @@ -66,6 +56,7 @@ void createNPCActionNodes(flecs::entity town, flecs::entity e, int index) anode.props["height"] = anode.height; anode.props["town"] = town.id(); anode.props["index"] = index; + anode.props["npc"] = npcprops; anodes.anodes.push_back(anode); } { @@ -86,6 +77,7 @@ void createNPCActionNodes(flecs::entity town, flecs::entity e, int index) anode.props["height"] = anode.height; anode.props["town"] = town.id(); anode.props["index"] = index; + anode.props["npc"] = npcprops; anodes.anodes.push_back(anode); } e.modified(); diff --git a/src/gamedata/CharacterManagerModule.h b/src/gamedata/CharacterManagerModule.h index e425d09..016d5e1 100644 --- a/src/gamedata/CharacterManagerModule.h +++ b/src/gamedata/CharacterManagerModule.h @@ -1,9 +1,22 @@ #ifndef _CHARACTER_MANAGER_MODULE_ #define _CHARACTER_MANAGER_MODULE_ #include +#include namespace ECS { struct TownCharacterHolder{int index;}; +struct TownNPCs { + struct NPCData { + flecs::entity e; + nlohmann::json props; + Ogre::Vector3 position; + Ogre::Quaternion orientation; + Ogre::String model; + }; + + std::map npcs; +}; +struct LivesIn {}; struct CharacterManagerModule { std::set characters; flecs::entity player; diff --git a/src/gamedata/GUIModuleCommon.h b/src/gamedata/GUIModuleCommon.h index caf5d51..a89e0d9 100644 --- a/src/gamedata/GUIModuleCommon.h +++ b/src/gamedata/GUIModuleCommon.h @@ -2,6 +2,7 @@ #define __GUIMODULECOMMON_H__ #include #include +#include #include "Components.h" #include "GameData.h" namespace ECS @@ -21,6 +22,7 @@ struct GUI { Ogre::String mnarrationText; std::vector mchoices; int narration_answer; + nlohmann::json props; private: bool complete; @@ -91,6 +93,18 @@ struct GUI { event(ev); } virtual ~NarrationHandler() {} + void setProperties(const Ogre::String &properties) + { + props = nlohmann::json::parse(properties); + } + Ogre::String getProperties() const + { + return props.dump(); + } + const nlohmann::json &getPropsJSON() const + { + return props; + } }; static void setWindowGrab(bool g = true) diff --git a/src/gamedata/LuaData.cpp b/src/gamedata/LuaData.cpp index baad72f..7a5d05f 100644 --- a/src/gamedata/LuaData.cpp +++ b/src/gamedata/LuaData.cpp @@ -302,7 +302,10 @@ LuaData::LuaData() lua_setglobal(L, "setup_handler"); lua_pushcfunction(L, [](lua_State *L) -> int { luaL_checktype(L, 1, LUA_TSTRING); - luaL_checktype(L, 2, LUA_TFUNCTION); + if (lua_type(L, 2) == LUA_TFUNCTION) + luaL_checktype(L, 2, LUA_TFUNCTION); + else + luaL_checktype(L, 2, LUA_TTABLE); ECS::get_mut().setupLuaActionHandler(L); ECS::modified(); return 0; diff --git a/src/gamedata/PlayerActionModule.cpp b/src/gamedata/PlayerActionModule.cpp index e3ca39e..0d395a8 100644 --- a/src/gamedata/PlayerActionModule.cpp +++ b/src/gamedata/PlayerActionModule.cpp @@ -72,7 +72,8 @@ struct TestNarrativeHandler : GUI::NarrationHandler { } void activate() override { - _narration("Dialogue...", {}); + _narration("Greetings...", {}); + std::cout << getPropsJSON().dump(4) << std::endl; count = 0; } void event(const Ogre::String &evt) override @@ -101,11 +102,119 @@ struct TestNarrativeHandler : GUI::NarrationHandler { << std::endl; } }; +struct LuaNarrationHandler : GUI::NarrationHandler { + int ref; + lua_State *L; + LuaNarrationHandler(lua_State *L, int ref) + : ref(ref) + , L(L) + { + lua_rawgeti(L, LUA_REGISTRYINDEX, ref); + lua_pushlightuserdata(L, this); + lua_pushcclosure( + L, + [](lua_State *L) { + luaL_checktype(L, 1, LUA_TSTRING); + luaL_checktype(L, 2, LUA_TTABLE); + LuaNarrationHandler *handler = + static_cast( + lua_touserdata( + L, + lua_upvalueindex(1))); + Ogre::String event = lua_tostring(L, 1); + std::vector choices; + int choicesLen = (int)lua_rawlen(L, 2); + choices.reserve(choicesLen); + for (int i = 1; i <= choicesLen; ++i) { + lua_rawgeti(L, 2, i); + if (lua_isstring(L, -1)) + choices.push_back( + lua_tostring(L, -1)); + lua_pop(L, 1); + } + handler->_narration(event, choices); + return 0; + }, + 1); + lua_setfield(L, -2, "_narration"); + lua_pushlightuserdata(L, this); + lua_pushcclosure( + L, + [](lua_State *L) { + LuaNarrationHandler *handler = + static_cast( + lua_touserdata( + L, + lua_upvalueindex(1))); + handler->_finish(); + return 0; + }, + 1); + lua_setfield(L, -2, "_finish"); + lua_pop(L, 1); + } + void finish() override + { + lua_rawgeti(L, LUA_REGISTRYINDEX, ref); + int type = lua_getfield(L, -1, "finish"); + OgreAssert(type == LUA_TFUNCTION, "bad finish()"); + lua_insert(L, -2); + if (lua_pcall(L, 1, 0, 0) != 0) { + std::cerr << lua_tostring(L, -1) << std::endl; + OgreAssert(false, "lua error"); + lua_pop(L, 1); + } + _clear_narration(); + } + void activate() override + { + lua_rawgeti(L, LUA_REGISTRYINDEX, ref); + int type = lua_getfield(L, -1, "activate"); + OgreAssert(type == LUA_TFUNCTION, "bad activate()"); + lua_insert(L, -2); + if (lua_pcall(L, 1, 0, 0) != 0) { + std::cerr << lua_tostring(L, -1) << std::endl; + OgreAssert(false, "lua error"); + lua_pop(L, 1); + } + // _narration("Greetings...", {}); + // std::cout << getPropsJSON().dump(4) << std::endl; + } + void event(const Ogre::String &evt) override + { + lua_rawgeti(L, LUA_REGISTRYINDEX, ref); + int type = lua_getfield(L, -1, "event"); + OgreAssert(type == LUA_TFUNCTION, "bad event()"); + lua_insert(L, -2); + lua_pushstring(L, evt.c_str()); + if (lua_pcall(L, 2, 0, 0) != 0) { + std::cerr << lua_tostring(L, -1) << std::endl; + OgreAssert(false, "lua error"); + lua_pop(L, 1); + } + } +}; + struct SimpleWordHandler : PlayerActionModule::ActionWordHandler { void operator()(flecs::entity town, int index, const Ogre::String &word) override { TestNarrativeHandler *handle = OGRE_NEW TestNarrativeHandler(); + const TownNPCs::NPCData &npc = + town.get().npcs.at(index); + flecs::entity e = npc.e; + for (const auto &anode : e.get().anodes) { + if (anode.action == word) { + nlohmann::json props = anode.props; + props["initiator"] = + ECS::get() + .getPlayer() + .id(); + props["recipient"] = e.id(); + handle->setProperties(props.dump()); + break; + } + } ECS::get_mut().addNarrationHandler(handle); ECS::modified(); } @@ -205,8 +314,8 @@ PlayerActionModule::PlayerActionModule(flecs::world &ecs) if (!ECS::get().enabled) list.busy = false; }); - SimpleWordHandler *handler = OGRE_NEW SimpleWordHandler; - addWordHandler("talk", handler); + // SimpleWordHandler *handler = OGRE_NEW SimpleWordHandler; + // addWordHandler("talk", handler); } void PlayerActionModule::addWordHandler(const Ogre::String &word, @@ -233,13 +342,39 @@ struct LuaWordHandler : PlayerActionModule::ActionWordHandler { const Ogre::String &word) override { lua_rawgeti(L, LUA_REGISTRYINDEX, ref); - lua_pushinteger(L, town.id()); - lua_pushinteger(L, index); - lua_pushstring(L, word.c_str()); - if (lua_pcall(L, 3, 0, 0)) { - Ogre::LogManager::getSingleton().stream() - << lua_tostring(L, -1); - OgreAssert(false, "Lua error"); + if (lua_type(L, -1) == LUA_TFUNCTION) { + luaL_checktype(L, -1, LUA_TFUNCTION); + lua_pushinteger(L, town.id()); + lua_pushinteger(L, index); + lua_pushstring(L, word.c_str()); + if (lua_pcall(L, 3, 0, 0)) { + Ogre::LogManager::getSingleton().stream() + << lua_tostring(L, -1); + OgreAssert(false, "Lua error"); + } + } else if (lua_type(L, -1) == LUA_TTABLE) { + luaL_checktype(L, -1, LUA_TTABLE); + lua_pop(L, 1); + LuaNarrationHandler *handle = + OGRE_NEW LuaNarrationHandler(L, ref); + const TownNPCs::NPCData &npc = + town.get().npcs.at(index); + flecs::entity e = npc.e; + for (const auto &anode : + e.get().anodes) { + if (anode.action == word) { + nlohmann::json props = anode.props; + props["initiator"] = + ECS::get() + .getPlayer() + .id(); + props["recipient"] = e.id(); + handle->setProperties(props.dump()); + break; + } + } + ECS::get_mut().addNarrationHandler(handle); + ECS::modified(); } } }; @@ -268,11 +403,19 @@ void PlayerActionModule::removeLuaWordHandler(const Ogre::String &word, int PlayerActionModule::setupLuaActionHandler(lua_State *L) { luaL_checktype(L, 1, LUA_TSTRING); - luaL_checktype(L, 2, LUA_TFUNCTION); - Ogre::String word = lua_tostring(L, 1); - lua_pushvalue(L, 2); - int ref = luaL_ref(L, LUA_REGISTRYINDEX); - addLuaWordHandler(word, L, ref); + if (lua_type(L, 2) == LUA_TFUNCTION) { + luaL_checktype(L, 2, LUA_TFUNCTION); + Ogre::String word = lua_tostring(L, 1); + lua_pushvalue(L, 2); + int ref = luaL_ref(L, LUA_REGISTRYINDEX); + addLuaWordHandler(word, L, ref); + } else if (lua_type(L, 2) == LUA_TTABLE) { + luaL_checktype(L, 2, LUA_TTABLE); + Ogre::String word = lua_tostring(L, 1); + lua_pushvalue(L, 2); + int ref = luaL_ref(L, LUA_REGISTRYINDEX); + addLuaWordHandler(word, L, ref); + } return 0; } diff --git a/src/gamedata/items/town.cpp b/src/gamedata/items/town.cpp index b01a1ef..c8f0d73 100644 --- a/src/gamedata/items/town.cpp +++ b/src/gamedata/items/town.cpp @@ -2134,6 +2134,8 @@ bool editNPCs(nlohmann::json &npcs) if (ImGui::SmallButton("Add NPC")) { nlohmann::json npc; npc["lastName"] = Ogre::String(lastName); + npc["firstName"] = Ogre::String(firstName); + npc["tags"] = Ogre::String(tags); Ogre::Vector3 npcPosition = ECS::get().sceneNode->_getDerivedPosition(); Ogre::Quaternion npcOrientation = @@ -2142,6 +2144,8 @@ bool editNPCs(nlohmann::json &npcs) to_json(npc["position"], npcPosition); to_json(npc["orientation"], npcOrientation); npc["sex"] = selection; + npc["health"] = 100; + npc["stamina"] = 100; npcs.push_back(npc); changed = true; }