starting playing the wherigo

Signed-off-by: Peter Siegmund <mars3142@noreply.mars3142.dev>
This commit is contained in:
2026-02-13 02:41:12 +01:00
parent 273e169281
commit c3b247c420
35 changed files with 5401 additions and 84 deletions

275
main/src/app.cpp Normal file
View File

@@ -0,0 +1,275 @@
#include "app.h"
#include "lua/game_engine.h"
#include "lua/media_manager.h"
#include "lua/persistence.h"
#include "lua/wherigo.h"
#include "lua/wherigo_completion.h"
#include "ui/start_screen.h"
#include <cartridge/parser.h>
#include <wx/dir.h>
#include <wx/filename.h>
#include <wx/stdpaths.h>
extern "C" {
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
}
bool cApp::OnInit()
{
// Initialize image handlers for JPEG, PNG, GIF, etc.
wxInitAllImageHandlers();
// Show start frame
auto *startFrame = new cStartScreen();
startFrame->Show(true);
return true;
}
bool cApp::loadCartridge(const std::string &filePath) {
// Unload previous cartridge if any
unloadCartridge();
m_cartridgePath = filePath;
// Parse cartridge
m_cartridge = cartridge::parseFile(filePath);
if (!m_cartridge) {
wxLogError("Failed to parse cartridge: %s", filePath);
return false;
}
return initLuaState();
}
bool cApp::initLuaState() {
auto luac = m_cartridge->luac();
if (!luac) {
wxLogError("No Lua bytecode in cartridge");
return false;
}
m_luaState = luaL_newstate();
if (!m_luaState) {
wxLogError("Failed to create Lua state");
return false;
}
luaL_openlibs(m_luaState);
// Reset media counter before loading cartridge
wherigo::resetMediaCounter();
// Register Wherigo module
wherigo::luaopen_Wherigo(m_luaState);
lua_pop(m_luaState, 1);
const auto &bytecode = luac->getData();
int result = luaL_loadbuffer(m_luaState,
reinterpret_cast<const char *>(bytecode.data()),
bytecode.size(),
"cartridge");
if (result != 0) {
const char *err = lua_tostring(m_luaState, -1);
wxLogError("Lua load error: %s", err);
lua_close(m_luaState);
m_luaState = nullptr;
return false;
}
// Execute the loaded chunk
if (lua_pcall(m_luaState, 0, 0, 0) != 0) {
const char *err = lua_tostring(m_luaState, -1);
wxLogError("Lua exec error: %s", err);
lua_close(m_luaState);
m_luaState = nullptr;
return false;
}
// Find the cartridge object by searching for ClassName = "ZCartridge"
m_cartridgeRef = LUA_NOREF;
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)) {
const char *className = lua_tostring(m_luaState, -1);
if (strcmp(className, "ZCartridge") == 0) {
lua_pop(m_luaState, 1); // pop ClassName
m_cartridgeRef = luaL_ref(m_luaState, LUA_REGISTRYINDEX); // store reference, pops table
lua_pop(m_luaState, 1); // pop key
break;
}
}
lua_pop(m_luaState, 1); // pop ClassName
}
lua_pop(m_luaState, 1); // pop value
}
lua_pop(m_luaState, 1); // pop _G
// Initialize media manager
wherigo::MediaManager::getInstance().init(m_luaState, m_cartridge.get());
if (m_cartridgeRef == LUA_NOREF) {
wxLogError("No ZCartridge object found!");
return false;
}
// Initialize the game engine (but don't start yet)
wherigo::GameEngine::getInstance().init(m_luaState, m_cartridgeRef);
return true;
}
void cApp::startGame() {
if (!m_luaState || m_cartridgeRef == LUA_NOREF) {
wxLogError("No cartridge loaded");
return;
}
// Call OnStart callback
lua_rawgeti(m_luaState, LUA_REGISTRYINDEX, m_cartridgeRef);
lua_getfield(m_luaState, -1, "OnStart");
if (lua_isfunction(m_luaState, -1)) {
lua_pushvalue(m_luaState, -2); // push cartridge as self
if (lua_pcall(m_luaState, 1, 0, 0) != 0) {
const char *err = lua_tostring(m_luaState, -1);
wxLogError("OnStart error: %s", err);
lua_pop(m_luaState, 1);
}
} else {
lua_pop(m_luaState, 1);
}
lua_pop(m_luaState, 1); // pop cartridge
// Start the game engine
wherigo::GameEngine::getInstance().start();
}
void cApp::unloadCartridge() {
// Shutdown the game engine
wherigo::GameEngine::getInstance().shutdown();
if (m_cartridgeRef != LUA_NOREF && m_luaState) {
luaL_unref(m_luaState, LUA_REGISTRYINDEX, m_cartridgeRef);
m_cartridgeRef = LUA_NOREF;
}
if (m_luaState) {
lua_close(m_luaState);
m_luaState = nullptr;
}
m_cartridge.reset();
m_cartridgePath.clear();
}
std::string cApp::getAutoSavePath() const {
if (m_cartridge) {
wxStandardPaths& stdPaths = wxStandardPaths::Get();
wxString userDataDir = stdPaths.GetUserDataDir();
// Create save directory if it doesn't exist
if (!wxDir::Exists(userDataDir)) {
wxFileName::Mkdir(userDataDir, wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL);
}
// Generate save filename from cartridge name
wxString cartName = wxString::FromUTF8(m_cartridge->cartridgeName());
cartName.Replace(" ", "_");
cartName.Replace("/", "_");
wxString savePath = userDataDir + wxFileName::GetPathSeparator() + cartName + ".save";
return savePath.ToStdString();
}
return "";
}
bool cApp::saveGameState(const std::string &saveFilePath) {
if (!m_luaState) {
wxLogError("No Lua state to save");
return false;
}
std::string savePath = saveFilePath.empty() ? getAutoSavePath() : saveFilePath;
if (savePath.empty()) {
wxLogError("No save path available");
return false;
}
bool success = wherigo::LuaPersistence::saveState(m_luaState, savePath);
if (success) {
wxLogMessage("Game saved to: %s", savePath);
}
return success;
}
bool cApp::loadGameState(const std::string &saveFilePath) {
if (!m_luaState) {
wxLogError("No Lua state to load into");
return false;
}
std::string loadPath = saveFilePath.empty() ? getAutoSavePath() : saveFilePath;
if (loadPath.empty() || !wxFileExists(loadPath)) {
wxLogError("Save file not found: %s", loadPath);
return false;
}
bool success = wherigo::LuaPersistence::loadState(m_luaState, loadPath);
if (success) {
wxLogMessage("Game loaded from: %s", loadPath);
// Notify game engine of state change
wherigo::GameEngine::getInstance().notifyStateChanged();
}
return success;
}
std::string cApp::getCompletionLogPath() const {
if (m_cartridge && !m_cartridgePath.empty()) {
// Use the same directory as the GWC file
wxFileName gwcFile(m_cartridgePath);
wxString directory = gwcFile.GetPath();
// Generate completion log filename from cartridge name
wxString cartName = wxString::FromUTF8(m_cartridge->cartridgeName());
cartName.Replace(" ", "_");
cartName.Replace("/", "_");
wxString logPath = directory + wxFileName::GetPathSeparator() + cartName + ".gwl";
return logPath.ToStdString();
}
return "";
}
bool cApp::generateCompletionLog(const std::string &logFilePath) {
if (!m_luaState) {
wxLogError("No Lua state for completion log");
return false;
}
std::string logPath = logFilePath.empty() ? getCompletionLogPath() : logFilePath;
if (logPath.empty()) {
wxLogError("No completion log path available");
return false;
}
bool success = wherigo::WherigoCompletion::generateCompletionLog(m_luaState, logPath, "Player");
if (success) {
wxLogMessage("Completion log generated: %s", logPath);
}
return success;
}
int cApp::OnExit()
{
unloadCartridge();
return wxApp::OnExit();
}