diff --git a/luprex/core/cpp/luastack.hpp b/luprex/core/cpp/luastack.hpp index 58da7010..e34e99eb 100644 --- a/luprex/core/cpp/luastack.hpp +++ b/luprex/core/cpp/luastack.hpp @@ -391,6 +391,8 @@ public: void makeclass(LuaSlot tab, const char *name) const; void makeclass(LuaSlot tab, const std::string &name) const; std::string classname(LuaSlot tab); + // There's no 'isclass' operator, but 'classname' will return empty + // string if tab is not a valid class. void movesortablekey(LuaSlot val, LuaStack &other, LuaSlot otherslot); diff --git a/luprex/core/cpp/main.cpp b/luprex/core/cpp/main.cpp index 9532a649..8b2df45d 100644 --- a/luprex/core/cpp/main.cpp +++ b/luprex/core/cpp/main.cpp @@ -126,7 +126,6 @@ public: int main(int argc, char **argv) { - //TextGame tg; - TNTest4 tg; + TextGame tg; driver_drive(&tg); } diff --git a/luprex/core/cpp/textgame.cpp b/luprex/core/cpp/textgame.cpp index d41c0899..6df69ad3 100644 --- a/luprex/core/cpp/textgame.cpp +++ b/luprex/core/cpp/textgame.cpp @@ -46,7 +46,9 @@ static void l_message(const char *msg) } void TextGame::do_lua(const std::string &exp) { + assert(world_->stack_is_clear()); lua_State *L = world_->state(); + // push the compiled function. int status = luaL_loadbuffer(L, exp.c_str(), exp.size(), "=stdin"); assert(status == LUA_OK); globalL = L; @@ -67,6 +69,7 @@ void TextGame::do_lua(const std::string &exp) { lua_pop(L, 1); lua_gc(L, LUA_GCCOLLECT, 0); } + assert(world_->stack_is_clear()); } void TextGame::do_view_command(const StringVec &cmd) { @@ -138,6 +141,17 @@ void TextGame::do_rollback_command(const StringVec &cmd) { world_->rollback(); } +void TextGame::do_tick_command(const StringVec &cmd) { + int64_t clock; + if (cmd.size() == 2) { + clock = util::strtoint(cmd[1], -1); + } else { + std::cerr << "t command (tick) expects a time value" << std::endl; + return; + } + world_->run_scheduled_threads(clock); +} + void TextGame::do_quit_command(const StringVec &cmd) { if (cmd.size() != 1) { std::cerr << "q command (quit) takes no arguments" << std::endl; @@ -153,6 +167,7 @@ void TextGame::do_command(const StringVec &words) { else if (words[0] == "q") do_quit_command(words); else if (words[0] == "s") do_snapshot_command(words); else if (words[0] == "r") do_rollback_command(words); + else if (words[0] == "t") do_tick_command(words); else if (util::validinteger(words[0])) do_choose_command(words); else { std::cerr << "Unknown command: " << words[0] << std::endl; diff --git a/luprex/core/cpp/textgame.hpp b/luprex/core/cpp/textgame.hpp index 5e7b07da..bdc9ba93 100644 --- a/luprex/core/cpp/textgame.hpp +++ b/luprex/core/cpp/textgame.hpp @@ -22,6 +22,7 @@ private: void do_quit_command(const StringVec &cmd); void do_snapshot_command(const StringVec &cmd); void do_rollback_command(const StringVec &cmd); + void do_tick_command(const StringVec &cmd); void do_lua(const std::string &exp); void do_command(const StringVec &exp); diff --git a/luprex/core/cpp/world-accessor.cpp b/luprex/core/cpp/world-accessor.cpp index edd7e5ec..f7a31194 100644 --- a/luprex/core/cpp/world-accessor.cpp +++ b/luprex/core/cpp/world-accessor.cpp @@ -40,7 +40,11 @@ LuaDefine(tangible_setclass, "c") { LuaStack LS(L, tanobj, classname, classtab, mt); World *w = World::fetch_global_pointer(L); w->tangible_get(LS, tanobj); - LS.getclass(classtab, classname); + if (LS.classname(classname) != "") { + LS.set(classtab, classname); + } else { + LS.getclass(classtab, classname); + } LS.getmetatable(mt, tanobj); LS.rawset(mt, "__index", classtab); return LS.result(); diff --git a/luprex/core/cpp/world-core.cpp b/luprex/core/cpp/world-core.cpp index 1cc30926..93fb7310 100644 --- a/luprex/core/cpp/world-core.cpp +++ b/luprex/core/cpp/world-core.cpp @@ -403,10 +403,14 @@ void World::invoke_plan(int64_t actor_id, int64_t place_id, const std::string &a // Create a new thread, set up function and parameters. lua_State *CO = LS.newthread(thread); + + // Push the function to be invoked and its arguments. lua_pushvalue(L, func.index()); lua_pushvalue(L, actor.index()); lua_pushvalue(L, place.index()); lua_pushvalue(L, invdata.index()); + + // Move actor, place, function and args to new thread. lua_xmove(L, CO, 4); // Store the thread into place's thread table. @@ -454,7 +458,7 @@ void World::run_scheduled_threads(int64_t clk) { // Resume the coroutine. lua_State *CO = LS.ckthread(thread); int top = lua_gettop(CO); - int status = lua_resume(CO, nullptr, (top > 0) ? (top - 1) : 0); + int status = lua_resume(CO, nullptr, (top >= 4) ? 3 : 0); // Three possible outcomes: finished, yielded, or errored. if (status == LUA_YIELD) { diff --git a/luprex/core/cpp/world.hpp b/luprex/core/cpp/world.hpp index b8812dd9..e180b969 100644 --- a/luprex/core/cpp/world.hpp +++ b/luprex/core/cpp/world.hpp @@ -199,19 +199,20 @@ public: void snapshot(); void rollback(); -private: // Run any threads which according to the scheduler queue are ready. // void run_scheduled_threads(int64_t clk); - // Store a pointer to a world model into a lua registry. - // - static void store_global_pointer(lua_State *L, World *w); - // Check that the main thread has nothing on the stack // bool stack_is_clear() const { return lua_gettop(state()) == 0; } +private: + + // Store a pointer to a world model into a lua registry. + // + static void store_global_pointer(lua_State *L, World *w); + // Invoke a plan. // void invoke_plan(int64_t actor_id, int64_t place_id, const std::string &action, const InvocationData &idata);