mirror of
https://github.com/1dot13/source.git
synced 2026-08-05 14:00:23 +02:00
************************************************************
* Merged Source Code from Development Trunk: Revision 4063 * ************************************************************ - Source Code is merged from: https://81.169.133.124/source/ja2/branches/Wanne/JA2%201.13%20MP - This will be the Source for the Beta 2011 Test git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@4064 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
+297
-75
@@ -4,9 +4,9 @@
|
||||
|
||||
#include "UndergroundInit.h"
|
||||
#include "Campaign Init.h"
|
||||
#include "Campaign Types.h"
|
||||
#include "FileMan.h"
|
||||
#include "GameSettings.h"
|
||||
#include "Game Clock.h"
|
||||
|
||||
extern "C" {
|
||||
#include "lua.h"
|
||||
@@ -14,107 +14,318 @@ extern "C" {
|
||||
#include "lualib.h"
|
||||
}
|
||||
|
||||
#include "lua_state.h"
|
||||
#include "lua_table.h"
|
||||
#include "lua_function.h"
|
||||
#include "connect.h"
|
||||
|
||||
extern UNDERGROUND_SECTORINFO* NewUndergroundNode( UINT8 ubSectorX, UINT8 ubSectorY, UINT8 ubSectorZ );
|
||||
// externals
|
||||
UNDERGROUND_SECTORINFO* NewUndergroundNode( UINT8 ubSectorX, UINT8 ubSectorY, UINT8 ubSectorZ );
|
||||
extern BOOLEAN gfGettingNameFromSaveLoadScreen;
|
||||
|
||||
static int l_addSector(lua_State *L);
|
||||
static int lh_getIntegerFromTable(lua_State *L, char * fieldname);
|
||||
static std::string lh_getStringFromTable(lua_State *L, char * fieldname);
|
||||
static std::wstring lh_getWStringFromTable(lua_State *L, char * fieldname);
|
||||
static bool locationStringToCoordinates(std::string loc, UINT8* x, UINT8* y, UINT8* z);
|
||||
// helper functions
|
||||
static std::string XYZtoString(INT16 x, INT16 y, INT16 z);
|
||||
|
||||
using namespace std;
|
||||
// keystroke savers
|
||||
#define LF vfs::Log::endl
|
||||
#define ON LuaLogger::ON
|
||||
#define OFF LuaLogger::OFF
|
||||
|
||||
// global
|
||||
LuaUnderground g_luaUnderground;
|
||||
|
||||
|
||||
BOOLEAN LetLuaBuildUndergroundSectorInfoList()
|
||||
template <>
|
||||
bool LuaTable::getValue<UINT8>(const char * index, UINT8& value)
|
||||
{
|
||||
char * filename = "scripts\\initunderground.lua";
|
||||
UINT32 size, bytesRead;
|
||||
char* buffer;
|
||||
int dummy;
|
||||
|
||||
bool b = getValue(index, dummy);
|
||||
if (b)
|
||||
{
|
||||
value = static_cast<UINT8>(dummy);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calls into Lua script to let build underground sector list.
|
||||
BOOLEAN LuaUnderground::InitializeSectorList()
|
||||
{
|
||||
// WANNE: Skip initialization in a multiplayer game, because some variables are not yet set
|
||||
// No problem: Underground sectors are not currently used in a multiplayer game
|
||||
if (!is_networked || gGameOptions.ubDifficultyLevel > 0)
|
||||
{
|
||||
LuaState L = GetLuaState();
|
||||
|
||||
LuaFunction initsectorlist_func(L, "BuildUndergroundSectorList");
|
||||
|
||||
initsectorlist_func
|
||||
.TableOpen()
|
||||
.TParam("difficultyLevel", int(gGameOptions.ubDifficultyLevel))
|
||||
.TParam("gameStyle", int(gGameOptions.ubGameStyle))
|
||||
.TableClose();
|
||||
|
||||
SGP_THROW_IFFALSE(initsectorlist_func.Call(1), "call to lua function BuildUndergroundSectorList failed");
|
||||
|
||||
LuaTable result(L, -1);
|
||||
if (result.is_valid())
|
||||
{
|
||||
int len = result.length();
|
||||
for (int i = 1; i <= result.length(); ++i)
|
||||
{
|
||||
LuaTable sectorData(result, i);
|
||||
if (sectorData.is_valid())
|
||||
{
|
||||
std::string location;
|
||||
sectorData.getValue("location", location);
|
||||
|
||||
UINT8 x, y, z;
|
||||
if (locationStringToCoordinates(location, &x, &y, &z))
|
||||
{
|
||||
UNDERGROUND_SECTORINFO* s = NewUndergroundNode(x, y, z);
|
||||
|
||||
sectorData.getValue("numAdmins", s->ubNumAdmins);
|
||||
sectorData.getValue("numTroops", s->ubNumTroops);
|
||||
sectorData.getValue("numElites", s->ubNumElites);
|
||||
|
||||
sectorData.getValue("numBloodcats", s->ubNumBloodcats);
|
||||
sectorData.getValue("numCreatures", s->ubNumCreatures);
|
||||
sectorData.getValue("creatureHabitat", s->ubCreatureHabitat);
|
||||
|
||||
sectorData.getValue("music", s->ubMusicMode);
|
||||
if (s->ubMusicMode < CM_COMPAT || CM_ALWAYS < s->ubMusicMode)
|
||||
s->ubMusicMode = CM_COMPAT;
|
||||
|
||||
// logging only
|
||||
{
|
||||
m_log << "adding sector: " << location << LF;
|
||||
m_log << "\t- Enemy garrison" << LF;
|
||||
m_log << "\t\tAdmins: " << static_cast<int>(s->ubNumAdmins) << LF;
|
||||
m_log << "\t\tTroops: " << static_cast<int>(s->ubNumTroops) << LF;
|
||||
m_log << "\t\tElites: " << static_cast<int>(s->ubNumElites) << LF;
|
||||
m_log << "\t- Creature population" << LF;
|
||||
m_log << "\t\tBloodcats: " << static_cast<int>(s->ubNumBloodcats) << LF;
|
||||
m_log << "\t\tCrepitus: " << static_cast<int>(s->ubNumCreatures) << LF;
|
||||
m_log << "\t\t- Habitat: " << static_cast<int>(s->ubCreatureHabitat) << LF;
|
||||
m_log << "\t\t- Music mode: ";
|
||||
switch (s->ubMusicMode)
|
||||
{
|
||||
case CM_COMPAT: m_log << "compat" << LF; break;
|
||||
case CM_AUTO: m_log << "auto" << LF; break;
|
||||
case CM_NEVER: m_log << "never" << LF; break;
|
||||
case CM_ALWAYS: m_log << "always" << LF; break;
|
||||
}
|
||||
m_log << LF;
|
||||
}
|
||||
}
|
||||
else
|
||||
m_log << "WARNING: ignoring invalid location ID: '" << location << "'" << LF;
|
||||
|
||||
m_log.Flush();
|
||||
}
|
||||
|
||||
lua_pop(L(), 1); // sectorData
|
||||
}
|
||||
}
|
||||
lua_pop(L(), 1); // result
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
// Calls into Lua script to get the loadscreen for a given sector.
|
||||
void LuaUnderground::GetLoadscreen(INT16 x, INT16 y, INT16 z, std::string& loadscreen, std::string& format)
|
||||
{
|
||||
const std::string strSector = XYZtoString(x, y, z);
|
||||
|
||||
LuaState L = GetLuaState();
|
||||
LuaFunction getLoadscreen_func(L, "GetLoadscreen");
|
||||
|
||||
getLoadscreen_func
|
||||
.Param(strSector)
|
||||
.Param(int(GetWorldMinutesInDay()));
|
||||
|
||||
SGP_THROW_IFFALSE(getLoadscreen_func.Call(2), "call to lua function GetLoadscreen failed");
|
||||
|
||||
|
||||
{
|
||||
if (lua_isstring(L(), -1))
|
||||
{
|
||||
format.append(lua_tostring(L(), -1));
|
||||
}
|
||||
else
|
||||
m_log << "ERROR: GetLoadscreen('" << strSector << "'): return value #2 is not a valid string object" << LF;
|
||||
lua_pop(L(), 1);
|
||||
|
||||
if (lua_isstring(L(), -1))
|
||||
{
|
||||
loadscreen.append(lua_tostring(L(), -1));
|
||||
}
|
||||
else
|
||||
m_log << "ERROR: GetLoadscreen('" << strSector << "'): return value #1 is not a valid string object" << LF;
|
||||
lua_pop(L(), 1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Calls into Lua script in order to request a sector name for a given sector.
|
||||
// pSector can be null, e.g. when saveloadscreen requests sector names;
|
||||
// in this case we didn't initialize the sector list nor have we loaded it from savegame yet.
|
||||
void LuaUnderground::GetSectorName(INT16 x, INT16 y, INT16 z, const UNDERGROUND_SECTORINFO* pSector, STR16 buffer, ::size_t bufSizeInWChar, BOOLEAN fDetailed)
|
||||
{
|
||||
const std::string coords = XYZtoString(x, y, z);
|
||||
LuaState L = GetLuaState();
|
||||
|
||||
LuaFunction getSectorName_func(L, "GetSectorName");
|
||||
|
||||
getSectorName_func
|
||||
.Param(coords)
|
||||
.TableOpen()
|
||||
.TParam("visited", gfGettingNameFromSaveLoadScreen || (pSector && pSector->fVisited))
|
||||
.TParam("creaturesPresent", pSector && pSector->ubNumCreatures > 0)
|
||||
.TParam("detailed", !!fDetailed) // conversion to C++ bool
|
||||
.TableClose();
|
||||
|
||||
SGP_THROW_IFFALSE(getSectorName_func.Call(1), "call to lua func GetSectorName failed");
|
||||
|
||||
|
||||
// TODO: check if this still makes a whole lot of sense now
|
||||
{
|
||||
memset(buffer, 0, bufSizeInWChar * sizeof(CHAR16));
|
||||
|
||||
if (lua_isstring(L(), -1))
|
||||
{
|
||||
const char * utf8 = lua_tostring(L(), -1);
|
||||
int result = MultiByteToWideChar(CP_UTF8, 0, lua_tostring(L(), -1), -1, buffer, bufSizeInWChar-1);
|
||||
if (result == 0)
|
||||
{
|
||||
// Houston, we have a problem...
|
||||
buffer[bufSizeInWChar-1] = L'\0';
|
||||
|
||||
DWORD errorcode = GetLastError();
|
||||
if (errorcode == ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
// quick note on logging:
|
||||
// we explicitly turn logging off once we encounter an error
|
||||
// since this function gets called a lot (every frame or so)
|
||||
m_log << "'" << utf8 << "': wchar representation too long" << LF << OFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log << "'" << utf8 << "': illegal unicode data" << LF << OFF;;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
m_log << "ERROR: requesting sector name for '" << coords << "' failed, no valid string object has been returned" << LF << OFF;
|
||||
|
||||
lua_pop(L(), 1); // return value
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Parse the scripts, set everything up.
|
||||
void LuaUnderground::LoadScript(const char * langPrefix)
|
||||
{
|
||||
LuaState L = GetLuaState();
|
||||
|
||||
// #1: builds strategic underground layout
|
||||
char * initunderground = "scripts\\initunderground.lua";
|
||||
|
||||
// #2: provides sector names; this is localized, build actual filename at runtime
|
||||
char * sectornamesfile = "undergroundsectornames.lua";
|
||||
std::string sectornames("scripts\\");
|
||||
if (langPrefix != NULL)
|
||||
sectornames.append(langPrefix);
|
||||
sectornames.append(sectornamesfile);
|
||||
|
||||
// we don't use L.EvalFile because the lua parser dislikes UTF-8 BOMs (gonna strip them first)
|
||||
RunScript(L, sectornames.c_str());
|
||||
RunScript(L, initunderground);
|
||||
|
||||
// TODO: see if we can make this better
|
||||
{
|
||||
lua_getglobal(L(), "logging");
|
||||
if (lua_isboolean(L(), -1) && lua_toboolean(L(), -1))
|
||||
m_log << ON;
|
||||
lua_pop(L(), -1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Loads a Lua script and let the interpreter process it.
|
||||
// Returns true if successful.
|
||||
// Throws an exception if file not found.
|
||||
bool LuaUnderground::RunScript(LuaState& L, const char * szFileName)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
// stupid file opening functions don't use const parameters...
|
||||
vector<char> filenamebuffer(strlen(szFileName)+1);
|
||||
strcpy(&filenamebuffer[0], szFileName);
|
||||
char * filename = &filenamebuffer[0];
|
||||
|
||||
|
||||
UINT32 size, bytesRead;
|
||||
HWFILE file = FileOpen(filename, FILE_ACCESS_READ, FALSE);
|
||||
|
||||
if (!file)
|
||||
return false;
|
||||
{
|
||||
string msg("Cannot open file: ");
|
||||
msg.append(filename);
|
||||
|
||||
m_log << msg << LF;
|
||||
m_log.Flush();
|
||||
|
||||
//throw sgp::Exception(msg.c_str(), __LINE__, _FUNCTION_FORMAT_, __FILE__);
|
||||
SGP_THROW(msg);
|
||||
}
|
||||
|
||||
size = FileSize(filename);
|
||||
buffer = new char[size+1];
|
||||
buffer[size] = 0;
|
||||
FileRead(file, buffer, size, &bytesRead);
|
||||
vector<char> buffer = vector<char>(size);
|
||||
FileRead(file, &buffer[0], size, &bytesRead);
|
||||
FileClose(file);
|
||||
|
||||
|
||||
lua_State *L = lua_open();
|
||||
luaL_openlibs(L);
|
||||
|
||||
lua_register(L, "addSector", l_addSector);
|
||||
|
||||
lua_pushinteger(L, gGameOptions.ubDifficultyLevel);
|
||||
lua_setglobal(L, "difficultyLevel");
|
||||
|
||||
lua_pushinteger(L, gGameOptions.ubGameStyle);
|
||||
lua_setglobal(L, "gameStyle");
|
||||
|
||||
if (luaL_dostring(L, buffer))
|
||||
// simple UTF8 BOM check:
|
||||
// replace with blanks if necessary since Lua HATES byte order marks
|
||||
const unsigned char bom[] = { 0xEF, 0xBB, 0xBF };
|
||||
if (memcmp(&buffer[0], bom, 3) == 0)
|
||||
{
|
||||
// oh noes, error
|
||||
// TODO: write to log or something
|
||||
return false;
|
||||
buffer[0] = buffer[1] = buffer[2] = ' ';
|
||||
}
|
||||
|
||||
lua_close(L);
|
||||
|
||||
delete[] buffer;
|
||||
|
||||
return true;
|
||||
return L.EvalString(&buffer[0], buffer.size(), szFileName);
|
||||
}
|
||||
|
||||
|
||||
static int l_addSector(lua_State *L)
|
||||
LuaUnderground::LuaUnderground()
|
||||
: m_log("initunderground.log", false, true, vfs::Log::FLUSH_BUFFER)
|
||||
{
|
||||
UNDERGROUND_SECTORINFO* curr = NULL;
|
||||
|
||||
std::string sector_id = lh_getStringFromTable(L, "location");
|
||||
|
||||
UINT8 x, y, z;
|
||||
if (locationStringToCoordinates(sector_id, &x, &y, &z))
|
||||
{
|
||||
curr = NewUndergroundNode(x, y, z);
|
||||
|
||||
curr->ubNumAdmins = lh_getIntegerFromTable(L, "numAdmins");
|
||||
curr->ubNumTroops = lh_getIntegerFromTable(L, "numTroops");
|
||||
curr->ubNumElites = lh_getIntegerFromTable(L, "numElites");
|
||||
|
||||
curr->ubCreatureHabitat = lh_getIntegerFromTable(L, "creatureHabitat");
|
||||
curr->ubNumCreatures = lh_getIntegerFromTable(L, "numCreatures");
|
||||
|
||||
curr->ubNumBloodcats = lh_getIntegerFromTable(L, "numBloodcats");
|
||||
}
|
||||
|
||||
return 0; // number of results
|
||||
}
|
||||
|
||||
|
||||
static int lh_getIntegerFromTable(lua_State *L, char * fieldname)
|
||||
LuaUnderground::~LuaUnderground()
|
||||
{
|
||||
lua_getfield(L, -1, fieldname);
|
||||
int i = lua_tointeger(L, -1);
|
||||
lua_pop(L, 1);
|
||||
return i;
|
||||
// WANNE: Disabled, because it leads to an unhandled exception when shutting down ja2 1.13
|
||||
/*m_log.Flush();*/
|
||||
}
|
||||
|
||||
|
||||
static std::string lh_getStringFromTable(lua_State *L, char * fieldname)
|
||||
{
|
||||
lua_getfield(L, -1, fieldname);
|
||||
string s = lua_tostring(L, -1);
|
||||
lua_pop(L, 1);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
// extract x,y,z from strings like "D13-1"
|
||||
static bool locationStringToCoordinates(std::string loc, UINT8* x, UINT8* y, UINT8* z)
|
||||
BOOLEAN locationStringToCoordinates(std::string loc, UINT8* x, UINT8* y, UINT8* z)
|
||||
{
|
||||
int length = loc.length();
|
||||
|
||||
@@ -132,7 +343,7 @@ static bool locationStringToCoordinates(std::string loc, UINT8* x, UINT8* y, UIN
|
||||
|
||||
// gather column
|
||||
loc = loc.substr(1);
|
||||
stringstream ss = stringstream();
|
||||
std::stringstream ss;
|
||||
if (loc[0] >= '0' && loc[0] <= '9')
|
||||
{
|
||||
ss << loc[0];
|
||||
@@ -159,3 +370,14 @@ static bool locationStringToCoordinates(std::string loc, UINT8* x, UINT8* y, UIN
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::string XYZtoString(INT16 x, INT16 y, INT16 z)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
stringstream ss;
|
||||
ss << static_cast<char>(y+'A'-1) << x << '-' << z;
|
||||
string tmp;
|
||||
ss >> tmp;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user