216 lines
5.9 KiB
C++
216 lines
5.9 KiB
C++
#include "lua/game_engine.h"
|
|
|
|
extern "C" {
|
|
#include <lua.h>
|
|
#include <lauxlib.h>
|
|
}
|
|
|
|
#include <wx/log.h>
|
|
|
|
namespace wherigo {
|
|
|
|
// Define the custom event
|
|
wxDEFINE_EVENT(EVT_GAME_STATE_CHANGED, GameStateEvent);
|
|
|
|
wxBEGIN_EVENT_TABLE(GameEngine, wxEvtHandler)
|
|
EVT_TIMER(wxID_ANY, GameEngine::onGameTick)
|
|
wxEND_EVENT_TABLE()
|
|
|
|
GameEngine& GameEngine::getInstance() {
|
|
static GameEngine instance;
|
|
return instance;
|
|
}
|
|
|
|
GameEngine::GameEngine() : m_gameTimer(this) {
|
|
}
|
|
|
|
GameEngine::~GameEngine() {
|
|
shutdown();
|
|
}
|
|
|
|
void GameEngine::init(lua_State *L, int cartridgeRef) {
|
|
m_luaState = L;
|
|
m_cartridgeRef = cartridgeRef;
|
|
wxLogDebug("GameEngine initialized");
|
|
}
|
|
|
|
void GameEngine::shutdown() {
|
|
stop();
|
|
m_luaState = nullptr;
|
|
m_cartridgeRef = -1;
|
|
}
|
|
|
|
void GameEngine::start() {
|
|
if (m_running) return;
|
|
|
|
m_running = true;
|
|
m_gameTimer.Start(1000); // 1 second tick
|
|
wxLogDebug("GameEngine started");
|
|
}
|
|
|
|
void GameEngine::stop() {
|
|
if (!m_running) return;
|
|
|
|
m_gameTimer.Stop();
|
|
m_running = false;
|
|
wxLogDebug("GameEngine stopped");
|
|
}
|
|
|
|
void GameEngine::updatePlayerPosition(double lat, double lng, double alt) {
|
|
m_playerLat = lat;
|
|
m_playerLng = lng;
|
|
m_playerAlt = alt;
|
|
|
|
if (!m_luaState) return;
|
|
|
|
// Update Player.ObjectLocation in Lua
|
|
lua_getglobal(m_luaState, "Player");
|
|
if (lua_istable(m_luaState, -1)) {
|
|
lua_newtable(m_luaState);
|
|
lua_pushnumber(m_luaState, lat);
|
|
lua_setfield(m_luaState, -2, "latitude");
|
|
lua_pushnumber(m_luaState, lng);
|
|
lua_setfield(m_luaState, -2, "longitude");
|
|
lua_pushnumber(m_luaState, alt);
|
|
lua_setfield(m_luaState, -2, "altitude");
|
|
lua_setfield(m_luaState, -2, "ObjectLocation");
|
|
}
|
|
lua_pop(m_luaState, 1);
|
|
|
|
checkZones();
|
|
}
|
|
|
|
void GameEngine::onGameTick(wxTimerEvent& event) {
|
|
if (!m_luaState || !m_running) return;
|
|
|
|
checkTimers();
|
|
|
|
// Notify listeners of potential state changes
|
|
notifyStateChanged();
|
|
}
|
|
|
|
void GameEngine::checkTimers() {
|
|
if (!m_luaState) return;
|
|
|
|
// Iterate through all global variables to find running timers
|
|
lua_getglobal(m_luaState, "_G");
|
|
lua_pushnil(m_luaState);
|
|
|
|
while (lua_next(m_luaState, -2) != 0) {
|
|
if (lua_istable(m_luaState, -1)) {
|
|
lua_getfield(m_luaState, -1, "ClassName");
|
|
if (lua_isstring(m_luaState, -1) && strcmp(lua_tostring(m_luaState, -1), "ZTimer") == 0) {
|
|
lua_pop(m_luaState, 1); // pop ClassName
|
|
|
|
lua_getfield(m_luaState, -1, "Running");
|
|
bool running = lua_toboolean(m_luaState, -1);
|
|
lua_pop(m_luaState, 1);
|
|
|
|
if (running) {
|
|
// Get timer info
|
|
lua_getfield(m_luaState, -1, "Name");
|
|
const char *name = lua_isstring(m_luaState, -1) ? lua_tostring(m_luaState, -1) : "(unnamed)";
|
|
lua_pop(m_luaState, 1);
|
|
|
|
lua_getfield(m_luaState, -1, "Remaining");
|
|
lua_Number remaining = lua_isnumber(m_luaState, -1) ? lua_tonumber(m_luaState, -1) : -1;
|
|
lua_pop(m_luaState, 1);
|
|
|
|
// If Remaining not set, initialize from Duration
|
|
if (remaining < 0) {
|
|
lua_getfield(m_luaState, -1, "Duration");
|
|
remaining = lua_isnumber(m_luaState, -1) ? lua_tonumber(m_luaState, -1) : 0;
|
|
lua_pop(m_luaState, 1);
|
|
}
|
|
|
|
// Decrement remaining time
|
|
remaining -= 1.0;
|
|
lua_pushnumber(m_luaState, remaining);
|
|
lua_setfield(m_luaState, -2, "Remaining");
|
|
|
|
// Call OnTick if exists
|
|
lua_getfield(m_luaState, -1, "OnTick");
|
|
if (lua_isfunction(m_luaState, -1)) {
|
|
lua_pushvalue(m_luaState, -2); // push timer as self
|
|
if (lua_pcall(m_luaState, 1, 0, 0) != 0) {
|
|
wxLogError("Timer OnTick error: %s", lua_tostring(m_luaState, -1));
|
|
lua_pop(m_luaState, 1);
|
|
}
|
|
} else {
|
|
lua_pop(m_luaState, 1);
|
|
}
|
|
|
|
// Check if elapsed
|
|
if (remaining <= 0) {
|
|
wxLogDebug("Timer elapsed: %s", name);
|
|
|
|
// Stop the timer
|
|
lua_pushboolean(m_luaState, 0);
|
|
lua_setfield(m_luaState, -2, "Running");
|
|
|
|
// Call OnElapsed if exists
|
|
lua_getfield(m_luaState, -1, "OnElapsed");
|
|
if (lua_isfunction(m_luaState, -1)) {
|
|
lua_pushvalue(m_luaState, -2); // push timer as self
|
|
if (lua_pcall(m_luaState, 1, 0, 0) != 0) {
|
|
wxLogError("Timer OnElapsed error: %s", lua_tostring(m_luaState, -1));
|
|
lua_pop(m_luaState, 1);
|
|
}
|
|
} else {
|
|
lua_pop(m_luaState, 1);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
lua_pop(m_luaState, 1); // pop ClassName
|
|
}
|
|
}
|
|
lua_pop(m_luaState, 1); // pop value
|
|
}
|
|
lua_pop(m_luaState, 1); // pop _G
|
|
}
|
|
|
|
void GameEngine::checkZones() {
|
|
if (!m_luaState) return;
|
|
|
|
// Iterate through all global variables to find zones
|
|
lua_getglobal(m_luaState, "_G");
|
|
lua_pushnil(m_luaState);
|
|
|
|
while (lua_next(m_luaState, -2) != 0) {
|
|
if (lua_istable(m_luaState, -1)) {
|
|
lua_getfield(m_luaState, -1, "ClassName");
|
|
if (lua_isstring(m_luaState, -1) && strcmp(lua_tostring(m_luaState, -1), "Zone") == 0) {
|
|
lua_pop(m_luaState, 1); // pop ClassName
|
|
|
|
lua_getfield(m_luaState, -1, "Active");
|
|
bool active = lua_toboolean(m_luaState, -1);
|
|
lua_pop(m_luaState, 1);
|
|
|
|
if (active) {
|
|
// TODO: Check if player is inside zone using Points
|
|
// For now, just log that we would check
|
|
lua_getfield(m_luaState, -1, "Name");
|
|
const char *name = lua_isstring(m_luaState, -1) ? lua_tostring(m_luaState, -1) : "(unnamed)";
|
|
lua_pop(m_luaState, 1);
|
|
|
|
// This is where you would implement point-in-polygon check
|
|
// and call OnEnter/OnExit callbacks
|
|
}
|
|
} else {
|
|
lua_pop(m_luaState, 1); // pop ClassName
|
|
}
|
|
}
|
|
lua_pop(m_luaState, 1); // pop value
|
|
}
|
|
lua_pop(m_luaState, 1); // pop _G
|
|
}
|
|
|
|
void GameEngine::notifyStateChanged() {
|
|
GameStateEvent event(EVT_GAME_STATE_CHANGED);
|
|
ProcessEvent(event);
|
|
}
|
|
|
|
} // namespace wherigo
|
|
|