Compare commits

..
Author SHA1 Message Date
Mike Klaas 3a9433c0f1 Bump versions for v1.4.0 release 2026-04-01 20:42:11 -07:00
Mike Klaas b97c9864aa Fix global script loading on non-Windows (#347)
* Fix global script loading on non-Windows

Previously, global scripts in .dats and in local FS didn't work due to path separator confusion.

Now:
 * Hardcode global script path to "scripts\gl*.int" (windows separator)
 * Use Windows fpattern matching inside of dFile (.dats, which always use windows separators)
 * Use \-paths when listing found global scripts

The awkward part is having to vendor a copy of fpattern to force it to use "windows mode".  It's possible that we could use this everywhere since windows allows / as separator, but that could cause bugs where we're using fpattern on the native FS.  For now keeping the dFile implementation separate makes sense.
2026-04-01 20:20:57 -07:00
Vlad Kandgithub-actions[bot] 8d0009aa45 Nested array expressions (#346)
* Nested array expressions

* chore: auto-format with clang-format

* Code review fixes

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-31 20:18:38 +00:00
24 changed files with 1251 additions and 179 deletions
+3 -2
View File
@@ -373,8 +373,8 @@ if(APPLE)
endif()
set(MACOSX_BUNDLE_GUI_IDENTIFIER "com.alexbatalov.fallout2-ce")
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "1.3.0")
set(MACOSX_BUNDLE_BUNDLE_VERSION "1.3.0")
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "1.4.0")
set(MACOSX_BUNDLE_BUNDLE_VERSION "1.4.0")
endif()
if((NOT ${CMAKE_SYSTEM_NAME} MATCHES "Emscripten"))
@@ -434,6 +434,7 @@ endif()
add_subdirectory("third_party/fpattern")
target_link_libraries(${EXECUTABLE_NAME} fpattern::fpattern)
target_link_libraries(${EXECUTABLE_NAME} fpattern_windows::fpattern_windows)
target_link_libraries(${EXECUTABLE_NAME} ${ZLIB_LIBRARIES})
target_include_directories(${EXECUTABLE_NAME} PRIVATE ${ZLIB_INCLUDE_DIRS})
+1 -1
View File
@@ -38,7 +38,7 @@ See [`https://sfall-team.github.io/sfall/`](https://sfall-team.github.io/sfall/)
| Hooks / Hook functions | init_hook<br>get_sfall_arg<br>get_sfall_args<br>get_sfall_arg_at<br>set_sfall_return<br>set_sfall_arg<br>register_hook<br>register_hook_proc<br>register_hook_proc_spec | âś… except init_hook | See below for implemented hooks. `init_hook` is deprecated and will not be implemented. register_hook_proc and register_hook_proc_spec both add hooks to the *end* of the hook list, instead of beginning and end, respectively. |
| Arrays / Array functions | create_array<br>temp_array<br>fix_array<br>get/set_array<br>resize_array<br>free_array<br>scan_array<br>len_array<br>save/load_array<br>array_key<br>arrayexpr | âś… except save_array, load_array | - |
| Perks and traits / NPC perks | set_fake_perk_npc<br>set_fake_trait_npc<br>set_selectable_perk_npc<br>has_fake_perk_npc<br>has_fake_trait_npc | not implemented | - |
| Global scripts / Global script functions | set_global_script_repeat<br>set_global_script_type<br>available_global_script_types | implemented: all except available_global_script_types | `GlobalScriptPaths` masks now match archive-backed scripts regardless of `/` vs `\` separators, matching Windows-style `.dat` contents on non-Windows hosts. |
| Global scripts / Global script functions | set_global_script_repeat<br>set_global_script_type<br>available_global_script_types | implemented: all except available_global_script_types | - |
| Combat | attack_is_aimed<br>block_combat<br>force_aimed_shots<br>disable_aimed_shots<br>get_attack_type<br>get/set_bodypart_hit_modifier<br>combat_data<br>get/set/reset_critical_table<br>get_last_target<br>get_last_attacker<br>set_critter_burst_disable<br>get/set_critter_current_ap<br>set_spray_settings<br>get/set_combat_free_move | implemented: only get_attack_type, get_bodypart_hit_modifier, combat_data, set_bodypart_hit_modifier | - |
| Car | set_car_current_town<br>car_gas_amount<br>set_car_intface_art | implemented: all except set_car_intface_art | - |
| Interface / Windows and images | art_frame_data<br>interface_art_draw<br>interface_print<br>draw_image<br>draw_image_scaled<br>get_window_under_mouse<br>create_win<br>get_window_attribute<br>message_box<br>set_window_flag<br>win_fill_color<br>interface_overlay<br>dialog_message<br>get_text_width<br>hide_window<br>show_window | implemented: only message_box, get_text_width, show_window | - |
-5
View File
@@ -197,11 +197,6 @@ NumbersInDialogue=0
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[Scripts]
;Comma-separated list of masked paths to load global scripts from
;Only use single backslash \ as the directory separator
;Paths outside of scripts folder are supported
;GlobalScriptPaths=scripts\gl_*.int,scripts\sfall\gl*.int
;Uncomment the option to specify an additional directory for ini files used by scripts
;The game will search for ini files first relative to this directory and then relative to the root directory if not found
;The path length is limited to 61 characters
+2 -2
View File
@@ -9,8 +9,8 @@ android {
applicationId 'com.alexbatalov.fallout2ce'
minSdk 21
targetSdk 32
versionCode 4
versionName '1.3.0'
versionCode 5
versionName '1.4.0'
externalNativeBuild {
cmake {
arguments '-DANDROID_STL=c++_static'
+2 -2
View File
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.alexbatalov.fallout2ce"
android:versionCode="1"
android:versionName="1.0.0"
android:versionCode="5"
android:versionName="1.4.0"
android:installLocation="auto">
<!-- OpenGL ES 2.0 -->
+2 -14
View File
@@ -30,22 +30,10 @@ compile.exe -q -p -l -O2 -d -s -n -I<sfall_headers_id> <script_name.ssl>
- Install [VSCode Extension](https://marketplace.visualstudio.com/items?itemName=BGforge.bgforge-mls)
## Run test script
1. Move compiled `.int` file into game folder as `data/scripts/gl_<script_name>.int`
1. Move compiled `.int` file into game folder as `scripts/gl_<script_name>.int`
2. Change `ddraw.ini` and add this section:
```ini
[Scripts]
GlobalScriptPaths=data/scripts/gl*.int
```
(or add new path using comma as separator)
Note that on non-Windows it have to be `/` as folder separator
3. Run game, check that game displays message about tests
2. Run game, check that game displays message about tests
+6
View File
@@ -164,6 +164,12 @@ procedure array_test_suite begin
call assertEquals("saved arrays 3", len_array(list_saved_arrays), len_array(arr2) - 1);
*/
display_msg("Testing nested expressions...");
arr := [["one", "two"]];
call assertEquals("nested 1", arr[0][1], "two");
arr := [["one", "two"], {"three": ["four", -1]}];
call assertEquals("nested 2", arr[1].three[0], "four");
display_msg("All tests finished with "+test_suite_errors+" errors.");
call report_test_results("arrays");
+1 -1
View File
@@ -641,7 +641,7 @@ int fileNameListInit(const char* pattern, char*** fileNameListPtr)
char dir[COMPAT_MAX_DIR];
char fileName[COMPAT_MAX_FNAME];
char extension[COMPAT_MAX_EXT];
compat_path_to_native(name);
compat_windows_path_to_native(name);
compat_splitpath(name, nullptr, dir, fileName, extension);
if (!isWildcard || *dir == '\0' || (strchr(dir, '\\') == nullptr && strchr(dir, '/') == nullptr)) {
+6 -27
View File
@@ -7,7 +7,7 @@
#include <algorithm>
#include <fpattern/fpattern.h>
#include "fpattern_windows.h"
#include "platform_compat.h"
@@ -42,7 +42,6 @@ static DFile* dfileOpenInternal(DBase* dbase, const char* filename, const char*
static int dfileReadCharInternal(DFile* stream);
static bool dfileReadCompressed(DFile* stream, void* ptr, size_t size);
static void dfileUngetCompressed(DFile* stream, int ch);
static bool dfilePathMatchesPattern(const char* pattern, const char* path);
// Reads .DAT file contents.
//
@@ -202,15 +201,12 @@ bool dbaseClose(DBase* dbase)
// 0x4E5308
bool dbaseFindFirstEntry(DBase* dbase, DFileFindData* findFileData, const char* pattern)
{
// fpattern-matching requires native-separators
assert(pattern != nullptr);
compat_strlcpy(findFileData->pattern, pattern, sizeof(findFileData->pattern));
compat_path_to_native(findFileData->pattern);
// .dat files always have windows style paths
for (int index = 0; index < dbase->entriesLength; index++) {
DBaseEntry* entry = &(dbase->entries[index]);
if (dfilePathMatchesPattern(findFileData->pattern, entry->path)) {
if (fpattern_windows_match(pattern, entry->path)) {
strcpy(findFileData->fileName, entry->path);
strcpy(findFileData->pattern, pattern);
findFileData->index = index;
return true;
}
@@ -224,7 +220,7 @@ bool dbaseFindNextEntry(DBase* dbase, DFileFindData* findFileData)
{
for (int index = findFileData->index + 1; index < dbase->entriesLength; index++) {
DBaseEntry* entry = &(dbase->entries[index]);
if (dfilePathMatchesPattern(findFileData->pattern, entry->path)) {
if (fpattern_windows_match(findFileData->pattern, entry->path)) {
strcpy(findFileData->fileName, entry->path);
findFileData->index = index;
return true;
@@ -643,15 +639,7 @@ static int dbaseFindEntryByFilePath(const void* file, const void* entryName)
// 0x4E5D9C
static DFile* dfileOpenInternal(DBase* dbase, const char* filePath, const char* mode, DFile* dfile)
{
assert(filePath != nullptr);
// .dat files contain windows path separators
char normalizedFilePath[COMPAT_MAX_PATH];
compat_strlcpy(normalizedFilePath, filePath, sizeof(normalizedFilePath));
compat_path_to_windows(normalizedFilePath);
DBaseEntry* entry;
entry = (DBaseEntry*)bsearch(normalizedFilePath, dbase->entries, dbase->entriesLength, sizeof(*dbase->entries), dbaseFindEntryByFilePath);
DBaseEntry* entry = (DBaseEntry*)bsearch(filePath, dbase->entries, dbase->entriesLength, sizeof(*dbase->entries), dbaseFindEntryByFilePath);
if (entry == nullptr) {
goto err;
}
@@ -873,13 +861,4 @@ static void dfileUngetCompressed(DFile* stream, int ch)
stream->position--;
}
// pattern must be normalized to native paths, since that's what fpattern requires
static bool dfilePathMatchesPattern(const char* pattern, const char* path)
{
char normalizedPath[COMPAT_MAX_PATH];
compat_strlcpy(normalizedPath, path, sizeof(normalizedPath));
compat_path_to_native(normalizedPath);
return fpattern_match(pattern, normalizedPath);
}
} // namespace fallout
+16
View File
@@ -0,0 +1,16 @@
#ifndef FALLOUT_FPATTERN_WINDOWS_H_
#define FALLOUT_FPATTERN_WINDOWS_H_
#ifdef __cplusplus
extern "C" {
#endif
int fpattern_windows_isvalid(const char* pat);
int fpattern_windows_match(const char* pat, const char* fname);
int fpattern_windows_matchn(const char* pat, const char* fname);
#ifdef __cplusplus
}
#endif
#endif
+2 -2
View File
@@ -132,7 +132,7 @@ bool gameConfigInit(bool isMapper, int argc, char** argv)
// CE: Detect alternative default music directory.
char alternativeMusicPath[COMPAT_MAX_PATH];
strcpy(alternativeMusicPath, "data\\sound\\music\\*.acm");
compat_path_to_native(alternativeMusicPath);
compat_windows_path_to_native(alternativeMusicPath);
compat_resolve_path(alternativeMusicPath);
char** acms;
@@ -260,7 +260,7 @@ static void gameConfigResolvePath(const char* section, const char* key)
{
char* path;
configGetString(&gGameConfig, section, key, &path);
compat_path_to_native(path);
compat_windows_path_to_native(path);
compat_resolve_path(path);
}
+13 -50
View File
@@ -1,6 +1,5 @@
#include "platform_compat.h"
#include <assert.h>
#include <string.h>
#ifdef _WIN32
@@ -39,23 +38,6 @@ int compat_strnicmp(const char* string1, const char* string2, size_t size)
return SDL_strncasecmp(string1, string2, size);
}
size_t compat_strlcpy(char* dest, const char* src, size_t size)
{
size_t srcLength = strlen(src);
if (size != 0) {
size_t copyLength = srcLength;
if (copyLength >= size) {
copyLength = size - 1;
}
memcpy(dest, src, copyLength);
dest[copyLength] = '\0';
}
return srcLength;
}
char* compat_strupr(char* string)
{
return SDL_strupr(string);
@@ -223,7 +205,7 @@ int compat_mkdir(const char* path)
{
char nativePath[COMPAT_MAX_PATH];
strcpy(nativePath, path);
compat_path_to_native(nativePath);
compat_windows_path_to_native(nativePath);
compat_resolve_path(nativePath);
#ifdef _WIN32
@@ -248,7 +230,7 @@ FILE* compat_fopen(const char* path, const char* mode)
{
char nativePath[COMPAT_MAX_PATH];
strcpy(nativePath, path);
compat_path_to_native(nativePath);
compat_windows_path_to_native(nativePath);
compat_resolve_path(nativePath);
return fopen(nativePath, mode);
}
@@ -257,7 +239,7 @@ gzFile compat_gzopen(const char* path, const char* mode)
{
char nativePath[COMPAT_MAX_PATH];
strcpy(nativePath, path);
compat_path_to_native(nativePath);
compat_windows_path_to_native(nativePath);
compat_resolve_path(nativePath);
return gzopen(nativePath, mode);
}
@@ -296,7 +278,7 @@ int compat_remove(const char* path)
{
char nativePath[COMPAT_MAX_PATH];
strcpy(nativePath, path);
compat_path_to_native(nativePath);
compat_windows_path_to_native(nativePath);
compat_resolve_path(nativePath);
return remove(nativePath);
}
@@ -305,47 +287,28 @@ int compat_rename(const char* oldFileName, const char* newFileName)
{
char nativeOldFileName[COMPAT_MAX_PATH];
strcpy(nativeOldFileName, oldFileName);
compat_path_to_native(nativeOldFileName);
compat_windows_path_to_native(nativeOldFileName);
compat_resolve_path(nativeOldFileName);
char nativeNewFileName[COMPAT_MAX_PATH];
strcpy(nativeNewFileName, newFileName);
compat_path_to_native(nativeNewFileName);
compat_windows_path_to_native(nativeNewFileName);
compat_resolve_path(nativeNewFileName);
return rename(nativeOldFileName, nativeNewFileName);
}
void compat_path_to_native(char* path)
void compat_windows_path_to_native(char* path)
{
#ifndef _WIN32
char* pch = path;
while (*pch != '\0') {
if (
#ifdef _WIN32
*pch == '/'
#else
*pch == '\\'
#endif
) {
#ifdef _WIN32
*pch = '\\';
#else
if (*pch == '\\') {
*pch = '/';
}
pch++;
}
#endif
}
pch++;
}
}
void compat_path_to_windows(char* path)
{
char* pch = path;
while (*pch != '\0') {
if (*pch == '/') {
*pch = '\\';
}
pch++;
}
}
void compat_resolve_path(char* path)
@@ -406,7 +369,7 @@ int compat_access(const char* path, int mode)
{
char nativePath[COMPAT_MAX_PATH];
strcpy(nativePath, path);
compat_path_to_native(nativePath);
compat_windows_path_to_native(nativePath);
compat_resolve_path(nativePath);
return access(nativePath, mode);
}
+1 -3
View File
@@ -24,7 +24,6 @@ namespace fallout {
int compat_stricmp(const char* string1, const char* string2);
int compat_strnicmp(const char* string1, const char* string2, size_t size);
size_t compat_strlcpy(char* dest, const char* src, size_t size);
char* compat_strupr(char* string);
char* compat_strlwr(char* string);
char* compat_itoa(int value, char* buffer, int radix);
@@ -40,8 +39,7 @@ char* compat_fgets(char* buffer, int maxCount, FILE* stream);
char* compat_gzgets(gzFile stream, char* buffer, int maxCount);
int compat_remove(const char* path);
int compat_rename(const char* oldFileName, const char* newFileName);
void compat_path_to_native(char* path);
void compat_path_to_windows(char* path);
void compat_windows_path_to_native(char* path);
void compat_resolve_path(char* path);
int compat_access(const char* path, int mode);
char* compat_strdup(const char* string);
+44 -9
View File
@@ -476,7 +476,14 @@ private:
struct SfallArraysState {
std::unordered_map<ArrayId, std::unique_ptr<SFallArray>> arrays;
std::unordered_set<ArrayId> temporaryArrayIds;
// auto-incremented ID
int nextArrayId = kInitialArrayId;
// special array ID for array expressions, contains the ID number of the currently created array
ArrayId expressionArrayId = 0;
// special stack for array expressions, contains ID numbers of the currently created arrays
std::vector<ArrayId> arrayExpressionStack;
};
static SfallArraysState* _state = nullptr;
@@ -525,6 +532,21 @@ ArrayId CreateArray(int len, unsigned int flags)
_state->arrays.emplace(std::make_pair(arrayId, std::make_unique<SFallArrayList>(len, flags)));
}
if ((flags & SFALL_ARRAYFLAG_EXPR_PUSH) != 0) {
// When creating array for sub-expression, make sure to add array for base expression to stack
// This is messy, but required to support older scripts:
// - We must always assign expressionArrayId for one-layer expressions from older scripts to work like they did before
// - We can't directly push first arrayID into stack b/c no way to distinguish between start of an expression and normal temp_array call
// - Compiler will only add this flag for temp_array call generated from a sub-expression
// - So only on this second call we know we are in expression and expressionArrayId definitely contains arrayId of the first layer
auto& expressionStack = _state->arrayExpressionStack;
if (expressionStack.empty() && _state->expressionArrayId != 0) {
expressionStack.push_back(_state->expressionArrayId);
}
expressionStack.push_back(arrayId);
}
_state->expressionArrayId = arrayId;
return arrayId;
}
@@ -614,28 +636,41 @@ void ResizeArray(ArrayId arrayId, int newLen)
arr->ResizeArray(newLen);
}
int StackArray(const ProgramValue& key, const ProgramValue& val, Program* program)
void SetArrayFromExpression(const ProgramValue& key, const ProgramValue& val, Program* program)
{
// CE: Sfall uses eponymous global variable which is always the id of the
// last created array.
ArrayId stackArrayId = _state->nextArrayId - 1;
ArrayId arrayId = !_state->arrayExpressionStack.empty()
? _state->arrayExpressionStack.back()
: _state->expressionArrayId;
auto arr = get_array_by_id(stackArrayId);
auto arr = get_array_by_id(arrayId);
if (arr == nullptr) {
return 0;
return;
}
auto size = arr->size();
if (size >= ARRAY_MAX_SIZE) {
return 0;
return;
}
if (key.asInt() >= size) {
arr->ResizeArray(size + 1);
}
SetArray(stackArrayId, key, val, false, program);
return 0;
SetArray(arrayId, key, val, false, program);
}
void PopExpressionArray()
{
auto& expressionStack = _state->arrayExpressionStack;
if (expressionStack.empty()) return;
expressionStack.pop_back();
// Reversing the hack from CreateArray
if (expressionStack.size() == 1) {
_state->expressionArrayId = expressionStack.back();
expressionStack.pop_back();
}
}
ProgramValue ScanArray(ArrayId arrayId, const ProgramValue& val, Program* program)
+4 -1
View File
@@ -8,6 +8,8 @@ namespace fallout {
#define SFALL_ARRAYFLAG_ASSOC (1) // is map
#define SFALL_ARRAYFLAG_CONSTVAL (2) // don't update value of key if the key exists in map
#define SFALL_ARRAYFLAG_RESERVED (4) // has no significance in sfall or CE
#define SFALL_ARRAYFLAG_EXPR_PUSH (32) // is created as part of array sub-expression
#define SFALL_ARRAYFLAG_EXPR_POP (64) // is used to indicate end of array sub-expression, not used in actual array
using ArrayId = unsigned int;
@@ -24,7 +26,8 @@ void FreeArray(ArrayId arrayId);
void FixArray(ArrayId id);
void ResizeArray(ArrayId arrayId, int newLen);
void DeleteAllTempArrays();
int StackArray(const ProgramValue& key, const ProgramValue& val, Program* program);
void SetArrayFromExpression(const ProgramValue& key, const ProgramValue& val, Program* program);
void PopExpressionArray();
ProgramValue ScanArray(ArrayId arrayId, const ProgramValue& val, Program* program);
ArrayId ListAsArray(int type);
-2
View File
@@ -62,8 +62,6 @@ bool sfallConfigInit(int argc, char** argv)
configSetBool(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_CITIES_LIMIT_FIX, true);
configSetString(&gSfallConfig, SFALL_CONFIG_SCRIPTS_KEY, SFALL_CONFIG_INI_CONFIG_FOLDER, "");
configSetString(&gSfallConfig, SFALL_CONFIG_SCRIPTS_KEY, SFALL_CONFIG_GLOBAL_SCRIPT_PATHS, "scripts\\gl_*.int"); // TODO: remove
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_PIPBOY_AVAILABLE_AT_GAMESTART, 0);
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_USE_WALK_DISTANCE, 5);
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_AUTO_OPEN_DOORS, 0);
-1
View File
@@ -71,7 +71,6 @@ namespace fallout {
#define SFALL_CONFIG_EXTRA_MESSAGE_LISTS_KEY "ExtraGameMsgFileList"
#define SFALL_CONFIG_NUMBERS_IS_DIALOG_KEY "NumbersInDialogue"
#define SFALL_CONFIG_INI_CONFIG_FOLDER "IniConfigFolder"
#define SFALL_CONFIG_GLOBAL_SCRIPT_PATHS "GlobalScriptPaths"
#define SFALL_CONFIG_AUTO_QUICK_SAVE "AutoQuickSave"
#define SFALL_CONFIG_VERSION_STRING "VersionString"
#define SFALL_CONFIG_CONFIG_FILE "ConfigFile"
+10 -43
View File
@@ -1,7 +1,5 @@
#include "sfall_global_scripts.h"
#include <assert.h>
#include <algorithm>
#include <cstring>
#include <string>
@@ -9,7 +7,6 @@
#include "animation.h"
#include "db.h"
#include "debug.h"
#include "input.h"
#include "platform_compat.h"
#include "scripts.h"
@@ -40,47 +37,22 @@ bool sfall_gl_scr_init()
return false;
}
char* paths;
configGetString(&gSfallConfig, SFALL_CONFIG_SCRIPTS_KEY, SFALL_CONFIG_GLOBAL_SCRIPT_PATHS, &paths);
char* curr = paths;
while (curr != nullptr && *curr != '\0') {
char* end = strchr(curr, ',');
if (end != nullptr) {
*end = '\0';
}
char normalizedPattern[COMPAT_MAX_PATH];
compat_strlcpy(normalizedPattern, curr, sizeof(normalizedPattern));
compat_path_to_native(normalizedPattern);
char drive[COMPAT_MAX_DRIVE];
char dir[COMPAT_MAX_DIR];
compat_splitpath(normalizedPattern, drive, dir, nullptr, nullptr);
char** files = nullptr;
int filesLength = fileNameListInit(normalizedPattern, &files);
debugPrint("GlobalScriptPaths mask %s matched %d script(s)\n", curr, filesLength);
if (filesLength != 0) {
for (int index = 0; index < filesLength; index++) {
char path[COMPAT_MAX_PATH];
compat_makepath(path, drive, dir, files[index], nullptr);
state->paths.emplace_back(path);
}
// CE: always use "scripts\gl*.int" as global script path
const char* scriptPath = "scripts\\gl*.int";
const char* dir = "scripts";
char** files;
int filesLength = fileNameListInit(scriptPath, &files);
if (filesLength != 0) {
for (int index = 0; index < filesLength; index++) {
char path[COMPAT_MAX_PATH];
snprintf(path, sizeof(path), "%s\\%s", dir, files[index]);
state->paths.push_back(std::string { path });
}
fileNameListFree(&files, 0);
if (end != nullptr) {
*end = ',';
curr = end + 1;
} else {
curr = nullptr;
}
}
std::sort(state->paths.begin(), state->paths.end());
debugPrint("GlobalScriptPaths resolved %d script path(s)\n", static_cast<int>(state->paths.size()));
return true;
}
@@ -104,8 +76,6 @@ void sfall_gl_scr_exit()
void sfall_gl_scr_exec_start_proc()
{
int loadedScripts = 0;
for (auto& path : state->paths) {
Program* program = programCreateByPath(path.c_str());
if (program != nullptr) {
@@ -117,14 +87,11 @@ void sfall_gl_scr_exec_start_proc()
}
state->globalScripts.push_back(std::move(scr));
loadedScripts++;
programInterpret(program, -1);
}
}
debugPrint("Loaded %d global script(s)\n", loadedScripts);
tickersAdd(sfall_gl_scr_process_input);
}
+14 -4
View File
@@ -957,6 +957,14 @@ static void op_temp_array(Program* program)
{
auto flags = programStackPopInteger(program);
auto len = programStackPopInteger(program);
// Special case for array sub-expressions.
if ((flags & SFALL_ARRAYFLAG_EXPR_POP) != 0) {
PopExpressionArray();
programStackPushInteger(program, 0);
return;
}
auto arrayId = CreateTempArray(len, flags);
programStackPushInteger(program, arrayId);
}
@@ -986,13 +994,15 @@ static void op_set_array(Program* program)
SetArray(arrayId, key, value, true, program);
}
// This special opcode is used to implement array expressions.
// It should always push 0 on the stack.
// arrayexpr
static void op_stack_array(Program* program)
static void op_arrayexpr(Program* program)
{
auto value = programStackPopValue(program);
auto key = programStackPopValue(program);
auto returnValue = StackArray(key, value, program);
programStackPushInteger(program, returnValue);
SetArrayFromExpression(key, value, program);
programStackPushInteger(program, 0);
}
// scan_array
@@ -1654,7 +1664,7 @@ void sfallOpcodesInit()
// 0x8256 - int array_key(int array, int index)
interpreterRegisterOpcode(0x8256, op_get_array_key);
// 0x8257 - int arrayexpr(any key, any value)
interpreterRegisterOpcode(0x8257, op_stack_array);
interpreterRegisterOpcode(0x8257, op_arrayexpr);
// 0x81a0 - void set_pickpocket_max(int percentage)
// 0x81a1 - void set_hit_chance_max(int percentage)
+2 -2
View File
@@ -563,7 +563,7 @@ static bool xlistEnumerate(const char* pattern, XListEnumerationHandler* handler
char nativePattern[COMPAT_MAX_PATH];
strcpy(nativePattern, pattern);
compat_path_to_native(nativePattern);
compat_windows_path_to_native(nativePattern);
char drive[COMPAT_MAX_DRIVE];
char dir[COMPAT_MAX_DIR];
@@ -615,7 +615,7 @@ static bool xlistEnumerate(const char* pattern, XListEnumerationHandler* handler
} else {
char path[COMPAT_MAX_PATH];
snprintf(path, sizeof(path), "%s\\%s", xbase->path, pattern);
compat_path_to_native(path);
compat_windows_path_to_native(path);
if (fileFindFirst(path, &directoryFileFindData)) {
do {

Some files were not shown because too many files have changed in this diff Show More