00001
00002
00003
00004
00005
00006
00007
00008
00009
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00030
00031
00032
00033
00034
00035 #include <stdio.h>
00036 #include <string.h>
00037 #include <signal.h>
00038
00039 #include "stratagus.h"
00040
00041 #include "unittype.h"
00042 #include "iolib.h"
00043 #include "iocompat.h"
00044 #include "script.h"
00045 #include "missile.h"
00046 #include "upgrade.h"
00047 #include "construct.h"
00048 #include "map.h"
00049 #include "ui.h"
00050 #include "interface.h"
00051 #include "ai.h"
00052 #include "trigger.h"
00053 #include "editor.h"
00054 #include "sound.h"
00055 #include "netconnect.h"
00056 #include "network.h"
00057 #include "spells.h"
00058 #include "actions.h"
00059 #include "video.h"
00060 #include "upgrade_structs.h"
00061 #include "player.h"
00062 #include "replay.h"
00063
00064
00065
00066
00067
00068 lua_State *Lua;
00069
00070 std::string CclStartFile;
00071 std::string UserDirectory;
00072 int CclInConfigFile;
00073 bool SaveGameLoading;
00074 std::string CurrentLuaFile;
00075
00076 int NoRandomPlacementMultiplayer = 0;
00077
00078
00079
00080
00081
00085 static void lstop(lua_State *l, lua_Debug *ar)
00086 {
00087 (void)ar;
00088 lua_sethook(l, NULL, 0, 0);
00089 luaL_error(l, "interrupted!");
00090 }
00091
00095 static void laction(int i)
00096 {
00097
00098
00099 signal(i, SIG_DFL);
00100 lua_sethook(Lua, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
00101 }
00102
00110 static void l_message(const char *pname, const char *msg, bool exit)
00111 {
00112 if (pname) {
00113 fprintf(stderr, "%s: ", pname);
00114 }
00115 fprintf(stderr, "%s\n", msg);
00116 if (exit) {
00117 ::exit(1);
00118 }
00119 }
00120
00130 static int report(int status, bool exitOnError)
00131 {
00132 const char *msg;
00133
00134 if (status) {
00135 msg = lua_tostring(Lua, -1);
00136 if (msg == NULL) {
00137 msg = "(error with no message)";
00138 }
00139 l_message(NULL, msg, exitOnError);
00140 lua_pop(Lua, 1);
00141 }
00142 return status;
00143 }
00144
00145 static int luatraceback(lua_State *L)
00146 {
00147 lua_pushliteral(L, "debug");
00148 lua_gettable(L, LUA_GLOBALSINDEX);
00149 if (!lua_istable(L, -1)) {
00150 lua_pop(L, 1);
00151 return 1;
00152 }
00153 lua_pushliteral(L, "traceback");
00154 lua_gettable(L, -2);
00155 if (!lua_isfunction(L, -1)) {
00156 lua_pop(L, 2);
00157 return 1;
00158 }
00159 lua_pushvalue(L, 1);
00160 lua_pushnumber(L, 2);
00161 lua_call(L, 2, 1);
00162 return 1;
00163 }
00164
00174 int LuaCall(int narg, int clear, bool exitOnError)
00175 {
00176 int status;
00177 int base;
00178
00179 base = lua_gettop(Lua) - narg;
00180 lua_pushcfunction(Lua, luatraceback);
00181 lua_insert(Lua, base);
00182 signal(SIGINT, laction);
00183 status = lua_pcall(Lua, narg, (clear ? 0 : LUA_MULTRET), base);
00184 signal(SIGINT, SIG_DFL);
00185 lua_remove(Lua, base);
00186
00187 return report(status, exitOnError);
00188 }
00189
00193 static void LuaLoadBuffer(const std::string &file, std::string &buffer)
00194 {
00195 CFile fp;
00196 int size;
00197 int oldsize;
00198 int location;
00199 int read;
00200 char *buf;
00201
00202 buffer.clear();
00203
00204 if (fp.open(file.c_str(), CL_OPEN_READ) == -1) {
00205 fprintf(stderr, "Can't open file '%s': %s\n",
00206 file.c_str(), strerror(errno));
00207 return;
00208 }
00209
00210 size = 10000;
00211 buf = new char[size];
00212 if (!buf) {
00213 fprintf(stderr, "Out of memory\n");
00214 ExitFatal(-1);
00215 }
00216 location = 0;
00217 for (;;) {
00218 read = fp.read(&buf[location], size - location);
00219 if (read != size - location) {
00220 location += read;
00221 break;
00222 }
00223 location += read;
00224 oldsize = size;
00225 size = size * 2;
00226 char *newb = new char[size];
00227 if (!newb) {
00228 fprintf(stderr, "Out of memory\n");
00229 ExitFatal(-1);
00230 }
00231 memcpy(newb, buf, oldsize);
00232 delete[] buf;
00233 buf = newb;
00234 }
00235 fp.close();
00236
00237 buffer.assign(buf, location);
00238 delete[] buf;
00239 }
00240
00248 int LuaLoadFile(const std::string &file)
00249 {
00250 int status;
00251 std::string PreviousLuaFile;
00252 std::string buf;
00253
00254 PreviousLuaFile = CurrentLuaFile;
00255 CurrentLuaFile = file;
00256
00257 LuaLoadBuffer(file, buf);
00258 if (buf.empty()) {
00259 return -1;
00260 }
00261
00262 if (!(status = luaL_loadbuffer(Lua, buf.c_str(), buf.size(), file.c_str()))) {
00263 LuaCall(0, 1);
00264 } else {
00265 report(status, true);
00266 }
00267 CurrentLuaFile = PreviousLuaFile;
00268
00269 return status;
00270 }
00271
00275 static int CclGetCurrentLuaPath(lua_State *l)
00276 {
00277 LuaCheckArgs(l, 0);
00278
00279 std::string path = CurrentLuaFile;
00280 size_t index = path.rfind('/');
00281
00282 if (index != std::string::npos) {
00283 path = path.substr(0, index);
00284 lua_pushstring(l, path.c_str());
00285 } else {
00286 lua_pushstring(l, "");
00287 }
00288 return 1;
00289 }
00290
00296 static int CclSavePreferences(lua_State *l)
00297 {
00298 LuaCheckArgs(l, 0);
00299 SavePreferences();
00300 return 0;
00301 }
00302
00310 static int CclLoad(lua_State *l)
00311 {
00312 char buf[1024];
00313
00314 LuaCheckArgs(l, 1);
00315 LibraryFileName(LuaToString(l, 1), buf, sizeof(buf));
00316 if (LuaLoadFile(buf) == -1) {
00317 DebugPrint("Load failed: %s\n" _C_ LuaToString(l, 1));
00318 }
00319 return 0;
00320 }
00321
00329 static int CclLoadBuffer(lua_State *l)
00330 {
00331 char file[1024];
00332 std::string buf;
00333
00334 LuaCheckArgs(l, 1);
00335 LibraryFileName(LuaToString(l, 1), file, sizeof(file));
00336 LuaLoadBuffer(file, buf);
00337 if (!buf.empty()) {
00338 lua_pushstring(l, buf.c_str());
00339 return 1;
00340 }
00341 return 0;
00342 }
00343
00349 static int CclSavedGameInfo(lua_State *l)
00350 {
00351 const char *value;
00352
00353 LuaCheckArgs(l, 1);
00354 if (!lua_istable(l, 1)) {
00355 LuaError(l, "incorrect argument");
00356 }
00357
00358 lua_pushnil(l);
00359 while (lua_next(l, 1)) {
00360 value = LuaToString(l, -2);
00361
00362 if (!strcmp(value, "SaveFile")) {
00363 if (strcpy_s(CurrentMapPath, sizeof(CurrentMapPath), LuaToString(l, -1)) != 0) {
00364 LuaError(l, "SaveFile too long");
00365 }
00366 std::string buf = StratagusLibPath;
00367 buf += "/";
00368 buf += LuaToString(l, -1);
00369 if (LuaLoadFile(buf) == -1) {
00370 DebugPrint("Load failed: %s\n" _C_ value);
00371 }
00372 } else if (!strcmp(value, "SyncHash")) {
00373 SyncHash = LuaToNumber(l, -1);
00374 } else if (!strcmp(value, "SyncRandSeed")) {
00375 SyncRandSeed = LuaToNumber(l, -1);
00376 } else {
00377 LuaError(l, "Unsupported tag: %s" _C_ value);
00378 }
00379 lua_pop(l, 1);
00380 }
00381
00382 return 0;
00383 }
00384
00396 const char *LuaToString(lua_State *l, int narg)
00397 {
00398 luaL_checktype(l, narg, LUA_TSTRING);
00399 return lua_tostring(l, narg);
00400 }
00401
00411 int LuaToNumber(lua_State *l, int narg)
00412 {
00413 luaL_checktype(l, narg, LUA_TNUMBER);
00414 return static_cast<int>(lua_tonumber(l, narg));
00415 }
00416
00426 bool LuaToBoolean(lua_State *l, int narg)
00427 {
00428 luaL_checktype(l, narg, LUA_TBOOLEAN);
00429 return lua_toboolean(l, narg) != 0;
00430 }
00431
00437 void CclGarbageCollect(int fast)
00438 {
00439 DebugPrint("Garbage collect (before): %d\n" _C_
00440 lua_gc(Lua, LUA_GCCOUNT, 0));
00441
00442 lua_gc(Lua, LUA_GCCOLLECT, 0);
00443
00444 DebugPrint("Garbage collect (after): %d\n" _C_
00445 lua_gc(Lua, LUA_GCCOUNT, 0));
00446 }
00447
00448
00449
00450
00451
00459 static int CclStratagusLibraryPath(lua_State *l)
00460 {
00461 lua_pushstring(l, StratagusLibPath.c_str());
00462 return 1;
00463 }
00464
00468 static int CclFilteredListDirectory(lua_State *l, int type, int mask)
00469 {
00470 char directory[256];
00471 const char *userdir;
00472 std::vector<FileList> flp;
00473 int n;
00474 int i;
00475 int j;
00476 int pathtype;
00477
00478 LuaCheckArgs(l, 1);
00479 userdir = lua_tostring(l, 1);
00480 n = strlen(userdir);
00481
00482 pathtype = 0;
00483 if (n > 0 && *userdir == '~') {
00484
00485 pathtype = 1;
00486 }
00487
00488
00489 if (strpbrk(userdir, ":*?\"<>|") != 0 || strstr(userdir, "..") != 0) {
00490 LuaError(l, "Forbidden directory");
00491 }
00492
00493 if (pathtype == 1) {
00494 ++userdir;
00495 sprintf_s(directory, sizeof(directory), "%s/%s", UserDirectory.c_str(), userdir);
00496 } else {
00497 sprintf_s(directory, sizeof(directory), "%s/%s", StratagusLibPath.c_str(), userdir);
00498 }
00499 lua_pop(l, 1);
00500 lua_newtable(l);
00501 n = ReadDataDirectory(directory, NULL, flp);
00502 for (i = 0, j = 0; i < n; ++i) {
00503 if ((flp[i].type & mask) == type) {
00504 lua_pushnumber(l, j + 1);
00505 lua_pushstring(l, flp[i].name);
00506 lua_settable(l, 1);
00507 ++j;
00508 }
00509 delete[] flp[i].name;
00510 }
00511
00512 return 1;
00513 }
00514
00518 static int CclListDirectory(lua_State *l)
00519 {
00520 return CclFilteredListDirectory(l, 0, 0);
00521 }
00522
00526 static int CclListFilesInDirectory(lua_State *l)
00527 {
00528 return CclFilteredListDirectory(l, 0x1, 0x1);
00529 }
00530
00534 static int CclListDirsInDirectory(lua_State *l)
00535 {
00536 return CclFilteredListDirectory(l, 0x0, 0x1);
00537 }
00538
00544 static int CclSetLocalPlayerName(lua_State *l)
00545 {
00546 LuaCheckArgs(l, 1);
00547 LocalPlayerName = LuaToString(l, 1);
00548 return 0;
00549 }
00550
00556 static int CclGetLocalPlayerName(lua_State *l)
00557 {
00558 LuaCheckArgs(l, 0);
00559 lua_pushstring(l, LocalPlayerName.c_str());
00560 return 1;
00561 }
00562
00568 static int CclNoRandomPlacementMultiplayer(lua_State *l)
00569 {
00570 LuaCheckArgs(l, 0);
00571 NoRandomPlacementMultiplayer = 1;
00572 return 0;
00573 }
00574
00580 static int CclSetGodMode(lua_State *l)
00581 {
00582 LuaCheckArgs(l, 1);
00583 GodMode = LuaToBoolean(l, 1);
00584 return 0;
00585 }
00586
00594 static int CclGetGodMode(lua_State *l)
00595 {
00596 LuaCheckArgs(l, 0);
00597 lua_pushboolean(l, GodMode);
00598 return 1;
00599 }
00600
00606 static int CclSetSpeedBuild(lua_State *l)
00607 {
00608 LuaCheckArgs(l, 1);
00609 SpeedBuild = LuaToNumber(l, 1);
00610 return 0;
00611 }
00612
00620 static int CclGetSpeedBuild(lua_State *l)
00621 {
00622 LuaCheckArgs(l, 0);
00623 lua_pushnumber(l, SpeedBuild);
00624 return 1;
00625 }
00626
00632 static int CclSetSpeedTrain(lua_State *l)
00633 {
00634 LuaCheckArgs(l, 1);
00635 SpeedTrain = LuaToNumber(l, 1);
00636 return 0;
00637 }
00638
00646 static int CclGetSpeedTrain(lua_State *l)
00647 {
00648 LuaCheckArgs(l, 0);
00649 lua_pushnumber(l, SpeedTrain);
00650 return 1;
00651 }
00652
00658 static int CclSetSpeeds(lua_State *l)
00659 {
00660 LuaCheckArgs(l, 1);
00661 SpeedBuild = SpeedTrain = LuaToNumber(l, 1);
00662 return 0;
00663 }
00664
00670 static int CclDefineDefaultResourceNames(lua_State *l)
00671 {
00672 int i;
00673 int args;
00674
00675 for (i = 0; i < MaxCosts; ++i) {
00676 DefaultResourceNames[i].clear();
00677 }
00678 args = lua_gettop(l);
00679 for (i = 0; i < MaxCosts && i < args; ++i) {
00680 DefaultResourceNames[i] = LuaToString(l, i + 1);
00681 }
00682 return 0;
00683 }
00684
00690 static int CclGetCompileFeature(lua_State *l)
00691 {
00692 const char *str;
00693
00694 LuaCheckArgs(l, 1);
00695
00696 str = LuaToString(l, 1);
00697 if (CompileOptions.find(str) != std::string::npos) {
00698 lua_pushboolean(l, 1);
00699 } else {
00700 lua_pushboolean(l, 0);
00701 }
00702
00703 return 1;
00704 }
00705
00706
00707
00708
00709
00716 int CclCommand(const std::string &command, bool exitOnError)
00717 {
00718 int status;
00719
00720 if (!(status = luaL_loadbuffer(Lua, command.c_str(), command.size(), command.c_str()))) {
00721 LuaCall(0, 1, exitOnError);
00722 } else {
00723 report(status, exitOnError);
00724 }
00725 return status;
00726 }
00727
00728
00729
00730
00731
00732 extern int tolua_stratagus_open(lua_State *tolua_S);
00733
00737 static void InitLua()
00738 {
00739
00740 static const luaL_Reg lualibs[] = {
00741 {"", luaopen_base},
00742
00743 {LUA_TABLIBNAME, luaopen_table},
00744
00745
00746 {LUA_STRLIBNAME, luaopen_string},
00747 {LUA_MATHLIBNAME, luaopen_math},
00748 {LUA_DBLIBNAME, luaopen_debug},
00749 {NULL, NULL}
00750 };
00751
00752 Lua = luaL_newstate();
00753
00754 for (const luaL_Reg *lib = lualibs; lib->func; ++lib) {
00755 lua_pushcfunction(Lua, lib->func);
00756 lua_pushstring(Lua, lib->name);
00757 lua_call(Lua, 1, 0);
00758 }
00759
00760 tolua_stratagus_open(Lua);
00761 lua_settop(Lua, 0);
00762 }
00763
00767 void InitCcl(void)
00768 {
00769 InitLua();
00770
00771 lua_register(Lua, "CompileFeature", CclGetCompileFeature);
00772 lua_register(Lua, "LibraryPath", CclStratagusLibraryPath);
00773 lua_register(Lua, "ListDirectory", CclListDirectory);
00774 lua_register(Lua, "ListFilesInDirectory", CclListFilesInDirectory);
00775 lua_register(Lua, "ListDirsInDirectory", CclListDirsInDirectory);
00776 lua_register(Lua, "SetLocalPlayerName", CclSetLocalPlayerName);
00777 lua_register(Lua, "GetLocalPlayerName", CclGetLocalPlayerName);
00778 lua_register(Lua, "SetGodMode", CclSetGodMode);
00779 lua_register(Lua, "GetGodMode", CclGetGodMode);
00780
00781 lua_register(Lua, "SetSpeedBuild", CclSetSpeedBuild);
00782 lua_register(Lua, "GetSpeedBuild", CclGetSpeedBuild);
00783 lua_register(Lua, "SetSpeedTrain", CclSetSpeedTrain);
00784 lua_register(Lua, "GetSpeedTrain", CclGetSpeedTrain);
00785 lua_register(Lua, "SetSpeeds", CclSetSpeeds);
00786
00787 lua_register(Lua, "DefineDefaultResourceNames", CclDefineDefaultResourceNames);
00788 lua_register(Lua, "NoRandomPlacementMultiplayer", CclNoRandomPlacementMultiplayer);
00789
00790 lua_register(Lua, "SavePreferences", CclSavePreferences);
00791 lua_register(Lua, "Load", CclLoad);
00792 lua_register(Lua, "LoadBuffer", CclLoadBuffer);
00793 lua_register(Lua, "GetCurrentLuaPath", CclGetCurrentLuaPath);
00794 lua_register(Lua, "SavedGameInfo", CclSavedGameInfo);
00795
00796 ReplayCclRegister();
00797 IconCclRegister();
00798 MissileCclRegister();
00799 PlayerCclRegister();
00800 MapCclRegister();
00801 ConstructionCclRegister();
00802 DecorationCclRegister();
00803 UnitTypeCclRegister();
00804 UpgradesCclRegister();
00805 SelectionCclRegister();
00806 GroupCclRegister();
00807 UnitCclRegister();
00808 SoundCclRegister();
00809 UserInterfaceCclRegister();
00810 AiCclRegister();
00811 TriggerCclRegister();
00812 SpellCclRegister();
00813 }
00814
00815 static char *LuaEscape(const char *str)
00816 {
00817 const unsigned char *src;
00818 char *dst;
00819 char *escapedString;
00820 int size = 0;
00821
00822 for (src = (const unsigned char *)str; *src; ++src) {
00823 if (*src == '"' || *src == '\\') {
00824 size += 2;
00825 } else if (*src < 32 || *src > 127) {
00826 size += 4;
00827 } else {
00828 ++size;
00829 }
00830 }
00831
00832 escapedString = new char[size + 1];
00833 for (src = (const unsigned char *)str, dst = escapedString; *src; ++src) {
00834 if (*src == '"' || *src == '\\') {
00835 *dst++ = '\\';
00836 *dst++ = *src;
00837 } else if (*src < 32 || *src > 127) {
00838 *dst++ = '\\';
00839 sprintf_s(dst, (size + 1) - (dst - escapedString), "%03d", *src);
00840 dst += 3;
00841 } else {
00842 *dst++ = *src;
00843 }
00844 }
00845 *dst = '\0';
00846
00847 return escapedString;
00848 }
00849
00860 char *SaveGlobal(lua_State *l, bool is_root)
00861 {
00862 int type_key;
00863 int type_value;
00864 const char *sep;
00865 const char *key;
00866 char *value;
00867 char *res;
00868 bool first;
00869 char *tmp;
00870 int b;
00871
00872
00873 first = true;
00874 res = NULL;
00875 if (is_root) {
00876 lua_pushstring(l, "_G");
00877 lua_gettable(l, LUA_GLOBALSINDEX);
00878 }
00879 sep = is_root ? "" : ", ";
00880 Assert(lua_istable(l, -1));
00881 lua_pushnil(l);
00882 while (lua_next(l, -2)) {
00883 type_key = lua_type(l, -2);
00884 type_value = lua_type(l, -1);
00885 key = (type_key == LUA_TSTRING) ? lua_tostring(l, -2) : "";
00886 if (!strcmp(key, "_G") || (is_root &&
00887 (!strcmp(key, "assert") || !strcmp(key, "gcinfo") || !strcmp(key, "getfenv") ||
00888 !strcmp(key, "unpack") || !strcmp(key, "tostring") || !strcmp(key, "tonumber") ||
00889 !strcmp(key, "setmetatable") || !strcmp(key, "require") || !strcmp(key, "pcall") ||
00890 !strcmp(key, "rawequal") || !strcmp(key, "collectgarbage") || !strcmp(key, "type") ||
00891 !strcmp(key, "getmetatable") || !strcmp(key, "next") || !strcmp(key, "print") ||
00892 !strcmp(key, "xpcall") || !strcmp(key, "rawset") || !strcmp(key, "setfenv") ||
00893 !strcmp(key, "rawget") || !strcmp(key, "newproxy") || !strcmp(key, "ipairs") ||
00894 !strcmp(key, "loadstring") || !strcmp(key, "dofile") || !strcmp(key, "_TRACEBACK") ||
00895 !strcmp(key, "_VERSION") || !strcmp(key, "pairs") || !strcmp(key, "__pow") ||
00896 !strcmp(key, "error") || !strcmp(key, "loadfile") || !strcmp(key, "arg") ||
00897 !strcmp(key, "_LOADED") || !strcmp(key, "loadlib") || !strcmp(key, "string") ||
00898 !strcmp(key, "os") || !strcmp(key, "io") || !strcmp(key, "debug") ||
00899 !strcmp(key, "coroutine") || !strcmp(key, "Icons") || !strcmp(key, "Upgrades") ||
00900 !strcmp(key, "Fonts") || !strcmp(key, "FontColors")
00901
00902 ))) {
00903 lua_pop(l, 1);
00904 continue;
00905 }
00906 switch (type_value) {
00907 case LUA_TNIL:
00908 value = new_strdup("nil");
00909 break;
00910 case LUA_TNUMBER:
00911 value = new_strdup(lua_tostring(l, -1));
00912 break;
00913 case LUA_TBOOLEAN:
00914 b = lua_toboolean(l, -1);
00915 value = new_strdup(b ? "true" : "false");
00916 break;
00917 case LUA_TSTRING:
00918 {
00919 char *escapedString = LuaEscape(lua_tostring(l, -1));
00920 value = strdcat3("\"", escapedString, "\"");
00921 delete[] escapedString;
00922 break;
00923 }
00924 case LUA_TTABLE:
00925 lua_pushvalue(l, -1);
00926 tmp = SaveGlobal(l, false);
00927 value = NULL;
00928 if (tmp != NULL) {
00929 value = strdcat3("{", tmp, "}");
00930 delete[] tmp;
00931 }
00932 break;
00933 case LUA_TFUNCTION:
00934
00935
00936
00937 value = NULL;
00938 break;
00939 case LUA_TUSERDATA:
00940 case LUA_TTHREAD:
00941 case LUA_TLIGHTUSERDATA:
00942 case LUA_TNONE:
00943 default :
00944 value = NULL;
00945 break;
00946 }
00947 lua_pop(l, 1);
00948
00949
00950 if (type_key == LUA_TSTRING) {
00951 for (int i = 0; key[i]; ++i) {
00952 if (!isalnum(key[i]) && key[i] != '_') {
00953 delete[] value;
00954 value = NULL;
00955 break;
00956 }
00957 }
00958 }
00959 if (value == NULL) {
00960 if (!is_root) {
00961 lua_pop(l, 2);
00962 Assert(res == NULL);
00963 delete[] res;
00964 return NULL;
00965 }
00966 continue;
00967 }
00968 if (type_key == LUA_TSTRING && !strcmp(key, value)) {
00969 continue;
00970 }
00971 if (first) {
00972 first = false;
00973 if (type_key == LUA_TSTRING) {
00974 res = strdcat3(key, "=", value);
00975 delete[] value;
00976 } else {
00977 res = value;
00978 }
00979 } else {
00980 if (type_key == LUA_TSTRING) {
00981 tmp = value;
00982 value = strdcat3(key, "=", value);
00983 delete[] tmp;
00984 tmp = res;
00985 res = strdcat3(res, sep, value);
00986 delete[] tmp;
00987 delete[] value;
00988 } else {
00989 tmp = res;
00990 res = strdcat3(res, sep, value);
00991 delete[] tmp;
00992 delete[] value;
00993 }
00994 }
00995 tmp = res;
00996 res = strdcat3("", res, "\n");
00997 delete[] tmp;
00998 }
00999 lua_pop(l, 1);
01000
01001 if (!res) {
01002 res = new char[1];
01003 res[0] = '\0';
01004 }
01005 return res;
01006 }
01007
01013 void CreateUserDirectories(void)
01014 {
01015 std::string directory;
01016 UserDirectory = "";
01017
01018 #ifndef USE_WIN32
01019 std::string s;
01020 s = getenv("HOME");
01021 if (!s.empty()) {
01022 UserDirectory = s + "/";
01023 }
01024 #endif
01025
01026 UserDirectory += STRATAGUS_HOME_PATH;
01027 makedir(UserDirectory.c_str(), 0777);
01028
01029
01030 directory = UserDirectory + "logs/";
01031 makedir(directory.c_str(), 0777);
01032 directory = UserDirectory + "save/";
01033 makedir(directory.c_str(), 0777);
01034 directory = UserDirectory + "patches/";
01035 makedir(directory.c_str(), 0777);
01036 }
01037
01041 void SavePreferences(void)
01042 {
01043 FILE *fd;
01044 std::string path;
01045
01046 lua_pushstring(Lua, "preferences");
01047 lua_gettable(Lua, LUA_GLOBALSINDEX);
01048 if (lua_type(Lua, -1) == LUA_TTABLE) {
01049 path = UserDirectory + "preferences.lua";
01050
01051 fd = fopen(path.c_str(), "w");
01052 if (!fd) {
01053 return;
01054 }
01055
01056 char *s = SaveGlobal(Lua, false);
01057 fprintf(fd, "preferences = {\n%s}\n", s);
01058 delete[] s;
01059
01060 fclose(fd);
01061 }
01062 }
01063
01067 void LoadCcl(void)
01068 {
01069 char buf[PATH_MAX];
01070
01071
01072
01073
01074 CclInConfigFile = 1;
01075 LibraryFileName(CclStartFile.c_str(), buf, sizeof(buf));
01076 if (access(buf, R_OK)) {
01077 fprintf(stderr, "Maybe you need to specify another gamepath with '-d /path/to/datadir'?\n");
01078 ExitFatal(-1);
01079 }
01080
01081 ShowLoadProgress("Script %s\n", buf);
01082 LuaLoadFile(buf);
01083 CclInConfigFile = 0;
01084 CclGarbageCollect(0);
01085 }
01086
01092 void SaveCcl(CFile *file)
01093 {
01094 file->printf("SetGodMode(%s)\n", GodMode ? "true" : "false");
01095
01096 file->printf("SetSpeedBuild(%d)\n", SpeedBuild);
01097 file->printf("SetSpeedTrain(%d)\n", SpeedTrain);
01098 }
01099