From cae990b65ec077ff0480b43717908b68b9f57ea4 Mon Sep 17 00:00:00 2001 From: Alexander Batalov Date: Sat, 27 May 2023 17:11:46 +0300 Subject: [PATCH] Refactor --- src/game.cc | 6 + src/party_member.cc | 29 +-- src/party_member.h | 3 +- src/sfall_arrays.cc | 501 ++++++++++++++++++++++++------------------- src/sfall_arrays.h | 33 +-- src/sfall_opcodes.cc | 51 ++--- 6 files changed, 345 insertions(+), 278 deletions(-) diff --git a/src/game.cc b/src/game.cc index c3e44f5..b7bfe0a 100644 --- a/src/game.cc +++ b/src/game.cc @@ -349,6 +349,11 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int a4 return -1; } + if (!sfallArraysInit()) { + debugPrint("Failed on sfallArraysInit"); + return -1; + } + messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_MISC, &gMiscMessageList); return 0; @@ -405,6 +410,7 @@ void gameExit() debugPrint("\nGame Exit\n"); // SFALL + sfallArraysExit(); sfallListsExit(); sfallGlobalVarsExit(); premadeCharactersExit(); diff --git a/src/party_member.cc b/src/party_member.cc index e860a71..16aabc6 100644 --- a/src/party_member.cc +++ b/src/party_member.cc @@ -912,19 +912,6 @@ int _getPartyMemberCount() return count; } -std::vector get_all_party_members_objects(bool include_hidden) -{ - std::vector value; - for (int index = 0; index < gPartyMembersLength; index++) { - auto p_object = gPartyMembers[index].object; - bool is_not_hidden = PID_TYPE(p_object->pid) == OBJ_TYPE_CRITTER && !critterIsDead(p_object) && !((p_object->flags & OBJECT_HIDDEN) != 0); - if (include_hidden || is_not_hidden) { - value.push_back(p_object); - } - } - return value; -} - // 0x495070 static int _partyMemberNewObjID() { @@ -1683,4 +1670,20 @@ int partyGetMaxWoundToHealByRest() return maxWound; } +std::vector get_all_party_members_objects(bool include_hidden) +{ + std::vector value; + value.reserve(gPartyMembersLength); + for (int index = 0; index < gPartyMembersLength; index++) { + auto object = gPartyMembers[index].object; + if (include_hidden + || (PID_TYPE(object->pid) == OBJ_TYPE_CRITTER + && !critterIsDead(object) + && (object->flags & OBJECT_HIDDEN) == 0)) { + value.push_back(object); + } + } + return value; +} + } // namespace fallout diff --git a/src/party_member.h b/src/party_member.h index 4e832c0..7129749 100644 --- a/src/party_member.h +++ b/src/party_member.h @@ -1,10 +1,11 @@ #ifndef PARTY_MEMBER_H #define PARTY_MEMBER_H +#include + #include "db.h" #include "obj_types.h" #include "scripts.h" -#include namespace fallout { diff --git a/src/sfall_arrays.cc b/src/sfall_arrays.cc index 2c0e603..5ee78cf 100644 --- a/src/sfall_arrays.cc +++ b/src/sfall_arrays.cc @@ -1,25 +1,20 @@ #include "sfall_arrays.h" -#include "interpreter.h" + +#include +#include #include -#include -#include #include #include -#include -#include #include #include #include -/* -Used https://gist.github.com/phobos2077/6bf357c49caaf515371a13f9a2d74a41 for testing -*/ +#include "interpreter.h" namespace fallout { -static ArrayId nextArrayID = 1; -static ArrayId stackArrayId = 0; +static constexpr ArrayId kInitialArrayId = 1; #define ARRAY_MAX_STRING (255) // maximum length of string to be stored as array key or value #define ARRAY_MAX_SIZE (100000) // maximum number of array elements, @@ -70,46 +65,26 @@ enum class ArrayElementType { * */ class ArrayElement { -private: - ArrayElementType type; - union { - int integerValue; - float floatValue; - char* stringValue; - void* pointerValue; - } value; - - void init_from_string(const char* str, int sLen) - { - type = ArrayElementType::STRING; - - if (sLen == -1) sLen = strlen(str); - if (sLen >= ARRAY_MAX_STRING) sLen = ARRAY_MAX_STRING - 1; // memory safety - - value.stringValue = (char*)malloc(sLen + 1); - memcpy(value.stringValue, str, sLen); - value.stringValue[sLen] = '\0'; - } - public: ArrayElement() : type(ArrayElementType::INT) - , value( - { 0 }) { - // Nothing here - }; + , value({ 0 }) + { + } ArrayElement(const ArrayElement& other) = delete; + ArrayElement& operator=(const ArrayElement& rhs) = delete; - ArrayElement(ArrayElement&& other) + + ArrayElement(ArrayElement&& other) noexcept : type(ArrayElementType::INT) - , value( - { 0 }) + , value({ 0 }) { std::swap(type, other.type); std::swap(value, other.value); - }; - ArrayElement& operator=(ArrayElement&& other) + } + + ArrayElement& operator=(ArrayElement&& other) noexcept { std::swap(type, other.type); std::swap(value, other.value); @@ -133,19 +108,23 @@ public: break; case VALUE_TYPE_STRING: case VALUE_TYPE_DYNAMIC_STRING: - auto str = programGetString(program, programValue.opcode, programValue.integerValue); - init_from_string(str, -1); + setString(programGetString(program, programValue.opcode, programValue.integerValue), -1); + break; + default: + type = ArrayElementType::INT; + value.integerValue = 0; break; } } ArrayElement(const char* str) { - init_from_string(str, -1); + setString(str, -1); } - ArrayElement(const char* str, int sLen) + + ArrayElement(const char* str, size_t sLen) { - init_from_string(str, sLen); + setString(str, sLen); } ProgramValue toValue(Program* program) const @@ -155,29 +134,29 @@ public: case ArrayElementType::INT: out.opcode = VALUE_TYPE_INT; out.integerValue = value.integerValue; - return out; + break; case ArrayElementType::FLOAT: out.opcode = VALUE_TYPE_FLOAT; out.floatValue = value.floatValue; - return out; + break; case ArrayElementType::POINTER: out.opcode = VALUE_TYPE_PTR; out.pointerValue = value.pointerValue; - return out; + break; case ArrayElementType::STRING: out.opcode = VALUE_TYPE_DYNAMIC_STRING; out.integerValue = programPushString(program, value.stringValue); - return out; - default: - throw(std::exception()); + break; } + return out; } bool operator<(ArrayElement const& other) const { if (type != other.type) { return type < other.type; - }; + } + switch (type) { case ArrayElementType::INT: return value.integerValue < other.value.integerValue; @@ -188,14 +167,16 @@ public: case ArrayElementType::STRING: return strcmp(value.stringValue, other.value.stringValue) < 0; default: - throw(std::exception()); + return false; } } + bool operator==(ArrayElement const& other) const { if (type != other.type) { return false; - }; + } + switch (type) { case ArrayElementType::INT: return value.integerValue == other.value.integerValue; @@ -206,7 +187,7 @@ public: case ArrayElementType::STRING: return strcmp(value.stringValue, other.value.stringValue) == 0; default: - throw(std::exception()); + return false; } } @@ -214,68 +195,103 @@ public: { if (type == ArrayElementType::STRING) { free(value.stringValue); - }; + } } + +private: + void setString(const char* str, size_t sLen) + { + type = ArrayElementType::STRING; + + if (sLen == -1) { + sLen = strlen(str); + } + + if (sLen >= ARRAY_MAX_STRING) { + sLen = ARRAY_MAX_STRING - 1; // memory safety + } + + value.stringValue = (char*)malloc(sLen + 1); + memcpy(value.stringValue, str, sLen); + value.stringValue[sLen] = '\0'; + } + + ArrayElementType type; + union { + int integerValue; + float floatValue; + char* stringValue; + void* pointerValue; + } value; }; class SFallArray { -protected: - uint32_t mFlags; - public: - virtual int size() = 0; + SFallArray(unsigned int flags) + : flags(flags) + { + } + virtual ~SFallArray() = default; virtual ProgramValue GetArrayKey(int index, Program* program) = 0; virtual ProgramValue GetArray(const ProgramValue& key, Program* program) = 0; virtual void SetArray(const ProgramValue& key, const ProgramValue& val, bool allowUnset, Program* program) = 0; virtual void SetArray(const ProgramValue& key, ArrayElement&& val, bool allowUnset) = 0; virtual void ResizeArray(int newLen) = 0; virtual ProgramValue ScanArray(const ProgramValue& value, Program* program) = 0; + virtual int size() = 0; - virtual ~SFallArray() = default; + bool isReadOnly() const + { + return (flags & SFALL_ARRAYFLAG_CONSTVAL) != 0; + } + +protected: + unsigned int flags; }; class SFallArrayList : public SFallArray { -private: - std::vector values; - public: SFallArrayList() = delete; - SFallArrayList(unsigned int len, uint32_t flags) + SFallArrayList(unsigned int len, unsigned int flags) + : SFallArray(flags) { values.resize(len); - mFlags = flags; } int size() { - return values.size(); + return static_cast(values.size()); } ProgramValue GetArrayKey(int index, Program* program) { if (index < -1 || index > size()) { return ProgramValue(0); - }; + } + if (index == -1) { // special index to indicate if array is associative return ProgramValue(0); - }; + } + return ProgramValue(index); } ProgramValue GetArray(const ProgramValue& key, Program* program) { - auto element_index = key.asInt(); - if (element_index < 0 || element_index >= size()) { + auto index = key.asInt(); + if (index < 0 || index >= size()) { return ProgramValue(0); - }; - return values[element_index].toValue(program); + } + + return values[index].toValue(program); } void SetArray(const ProgramValue& key, const ProgramValue& val, bool allowUnset, Program* program) { SetArray(key, ArrayElement { val, program }, allowUnset); } + void SetArray(const ProgramValue& key, ArrayElement&& val, bool allowUnset) { if (key.isInt()) { @@ -290,11 +306,14 @@ public: { if (newLen == -1 || size() == newLen) { return; - }; + } + if (newLen == 0) { values.clear(); } else if (newLen > 0) { - if (newLen > ARRAY_MAX_SIZE) newLen = ARRAY_MAX_SIZE; // safety + if (newLen > ARRAY_MAX_SIZE) { + newLen = ARRAY_MAX_SIZE; // safety + } values.resize(newLen); } else if (newLen >= ARRAY_ACTION_SHUFFLE) { @@ -304,156 +323,190 @@ public: ProgramValue ScanArray(const ProgramValue& value, Program* program) { - auto arrValue = ArrayElement { value, program }; - for (size_t i = 0; i < size(); i++) { - if (arrValue == values[i]) { + auto element = ArrayElement { value, program }; + for (int i = 0; i < size(); i++) { + if (element == values[i]) { return ProgramValue(i); } } return ProgramValue(-1); } + +private: + std::vector values; }; class SFallArrayAssoc : public SFallArray { -private: - std::vector keys; - std::map map; - - void MapSort(int newLen); - public: SFallArrayAssoc() = delete; - SFallArrayAssoc(uint32_t flags) + SFallArrayAssoc(unsigned int flags) + : SFallArray(flags) { - mFlags = flags; } int size() { - return keys.size(); + return static_cast(pairs.size()); } ProgramValue GetArrayKey(int index, Program* program) { if (index < -1 || index > size()) { return ProgramValue(0); - }; + } + if (index == -1) { // special index to indicate if array is associative return ProgramValue(1); - }; + } - return keys[index].toValue(program); + return pairs[index].key.toValue(program); } ProgramValue GetArray(const ProgramValue& key, Program* program) { - auto iter = map.find(ArrayElement { key, program }); - if (iter == map.end()) { - return ProgramValue(0); - }; + auto keyEl = ArrayElement { key, program }; + auto it = std::find_if(pairs.begin(), pairs.end(), [&keyEl](const KeyValuePair& pair) -> bool { + return pair.key == keyEl; + }); - return iter->second.toValue(program); + if (it == pairs.end()) { + return ProgramValue(0); + } + + auto index = it - pairs.begin(); + return pairs[index].value.toValue(program); } void SetArray(const ProgramValue& key, const ProgramValue& val, bool allowUnset, Program* program) { auto keyEl = ArrayElement { key, program }; + auto it = std::find_if(pairs.begin(), pairs.end(), [&keyEl](const KeyValuePair& pair) -> bool { + return pair.key == keyEl; + }); - auto iter = map.find(keyEl); - - bool lookupMap = (mFlags & SFALL_ARRAYFLAG_CONSTVAL) != 0; - - if (iter != map.end() && lookupMap) { + if (it != pairs.end() && isReadOnly()) { // don't update value of key return; } - if (allowUnset && !lookupMap && val.isInt() && val.asInt() == 0) { + if (allowUnset && !isReadOnly() && val.isInt() && val.asInt() == 0) { // after assigning zero to a key, no need to store it, because "get_array" returns 0 for non-existent keys: try unset - if (iter != map.end()) { - map.erase(iter); - - if (keys.size() == 0) { - throw(std::exception()); - } - auto it = std::find(keys.begin(), - keys.end(), keyEl); - if (it == keys.end()) { - throw(std::exception()); - }; - keys.erase(it); + if (it != pairs.end()) { + pairs.erase(it); } } else { - if (iter == map.end()) { + if (it == pairs.end()) { // size check - if (size() >= ARRAY_MAX_SIZE) return; + if (size() >= ARRAY_MAX_SIZE) { + return; + } - keys.push_back(std::move(keyEl)); - - // Not very good that we copy string into map key and into keys array - map.emplace(ArrayElement { key, program }, ArrayElement { val, program }); + pairs.push_back(KeyValuePair { std::move(keyEl), ArrayElement { val, program } }); } else { - auto newValue = ArrayElement { val, program }; - std::swap(map.at(keyEl), newValue); + auto index = it - pairs.begin(); + std::swap(pairs[index].value, ArrayElement { val, program }); } } } + void SetArray(const ProgramValue& key, ArrayElement&& val, bool allowUnset) { - throw std::invalid_argument("This method is not used for associative arrays thus it is not implemented"); + assert(false && "This method is not used for associative arrays thus it is not implemented"); } + void ResizeArray(int newLen) { if (newLen == -1 || size() == newLen) { return; - }; + } // only allow to reduce number of elements (adding range of elements is meaningless for maps) if (newLen >= 0 && newLen < size()) { - for (size_t i = newLen; i < size(); i++) { - map.erase(keys[i]); - }; - keys.resize(newLen); + pairs.resize(newLen); } else if (newLen < 0) { if (newLen < (ARRAY_ACTION_SHUFFLE - 2)) return; MapSort(newLen); } - }; + } ProgramValue ScanArray(const ProgramValue& value, Program* program) { auto valueEl = ArrayElement { value, program }; - for (const auto& pair : map) { - if (valueEl == pair.second) { - return pair.first.toValue(program); - } + auto it = std::find_if(pairs.begin(), pairs.end(), [&valueEl](const KeyValuePair& pair) { + return pair.value == valueEl; + }); + + if (it == pairs.end()) { + return ProgramValue(-1); } - return ProgramValue(-1); + + return it->key.toValue(program); } + +private: + struct KeyValuePair { + ArrayElement key; + ArrayElement value; + }; + + void MapSort(int type) + { + bool sortByValue = false; + if (type < ARRAY_ACTION_SHUFFLE) { + type += 4; + sortByValue = true; + } + + if (sortByValue) { + ListSort(pairs, type, [](const KeyValuePair& a, const KeyValuePair& b) -> bool { + return a.value < b.value; + }); + } else { + ListSort(pairs, type, [](const KeyValuePair& a, const KeyValuePair& b) -> bool { + return a.key < b.key; + }); + } + } + + std::vector pairs; }; -void SFallArrayAssoc::MapSort(int type) +struct SfallArraysState { + std::unordered_map> arrays; + std::unordered_set temporaryArrayIds; + int nextArrayId = kInitialArrayId; +}; + +static SfallArraysState* _state = nullptr; + +bool sfallArraysInit() { - bool sortByValue = false; - if (type < ARRAY_ACTION_SHUFFLE) { - type += 4; - sortByValue = true; + _state = new (std::nothrow) SfallArraysState(); + if (_state == nullptr) { + return false; } - if (sortByValue) { - ListSort(keys, type, [this](const ArrayElement& a, const ArrayElement& b) -> bool { - return map.at(a) < map.at(b); - }); - } else { - ListSort(keys, type, std::less()); + return true; +} + +void sfallArraysReset() +{ + if (_state != nullptr) { + _state->arrays.clear(); + _state->temporaryArrayIds.clear(); + _state->nextArrayId = kInitialArrayId; } } -std::unordered_map> arrays; -std::unordered_set temporaryArrays; +void sfallArraysExit() +{ + if (_state != nullptr) { + delete _state; + } +} -ArrayId CreateArray(int len, uint32_t flags) +ArrayId CreateArray(int len, unsigned int flags) { flags = (flags & ~1); // reset 1 bit @@ -461,151 +514,148 @@ ArrayId CreateArray(int len, uint32_t flags) flags |= SFALL_ARRAYFLAG_ASSOC; } else if (len > ARRAY_MAX_SIZE) { len = ARRAY_MAX_SIZE; // safecheck - }; + } - ArrayId array_id = nextArrayID++; - stackArrayId = array_id; + ArrayId arrayId = _state->nextArrayId++; if (flags & SFALL_ARRAYFLAG_ASSOC) { - arrays.emplace(std::make_pair(array_id, std::make_unique(flags))); + _state->arrays.emplace(std::make_pair(arrayId, std::make_unique(flags))); } else { - arrays.emplace(std::make_pair(array_id, std::make_unique(len, flags))); + _state->arrays.emplace(std::make_pair(arrayId, std::make_unique(len, flags))); } - return array_id; + return arrayId; } -ArrayId CreateTempArray(int len, uint32_t flags) +ArrayId CreateTempArray(int len, unsigned int flags) { - ArrayId array_id = CreateArray(len, flags); - temporaryArrays.insert(array_id); - return array_id; + ArrayId arrayId = CreateArray(len, flags); + _state->temporaryArrayIds.insert(arrayId); + return arrayId; } -SFallArray* get_array_by_id(ArrayId array_id) +SFallArray* get_array_by_id(ArrayId arrayId) { - auto it = arrays.find(array_id); - if (it == arrays.end()) { + auto it = _state->arrays.find(arrayId); + if (it == _state->arrays.end()) { return nullptr; - } else { - return it->second.get(); } + + return it->second.get(); } -ProgramValue GetArrayKey(ArrayId array_id, int index, Program* program) +ProgramValue GetArrayKey(ArrayId arrayId, int index, Program* program) { - auto arr = get_array_by_id(array_id); - if (!arr) { + auto arr = get_array_by_id(arrayId); + if (arr == nullptr) { return ProgramValue(0); - }; + } + return arr->GetArrayKey(index, program); } -int LenArray(ArrayId array_id) +int LenArray(ArrayId arrayId) { - auto arr = get_array_by_id(array_id); - if (!arr) { + auto arr = get_array_by_id(arrayId); + if (arr == nullptr) { return -1; - }; + } return arr->size(); } -ProgramValue GetArray(ArrayId array_id, const ProgramValue& key, Program* program) +ProgramValue GetArray(ArrayId arrayId, const ProgramValue& key, Program* program) { - auto arr = get_array_by_id(array_id); - - if (!arr) { + auto arr = get_array_by_id(arrayId); + if (arr == nullptr) { return ProgramValue(0); - }; + } return arr->GetArray(key, program); } -void SetArray(ArrayId array_id, const ProgramValue& key, const ProgramValue& val, bool allowUnset, Program* program) +void SetArray(ArrayId arrayId, const ProgramValue& key, const ProgramValue& val, bool allowUnset, Program* program) { - auto arr = get_array_by_id(array_id); - if (!arr) { + auto arr = get_array_by_id(arrayId); + if (arr == nullptr) { return; } arr->SetArray(key, val, allowUnset, program); } -void FreeArray(ArrayId array_id) +void FreeArray(ArrayId arrayId) { // TODO: remove from saved_arrays - arrays.erase(array_id); + _state->arrays.erase(arrayId); } -void FixArray(ArrayId id) +void FixArray(ArrayId arrayId) { - temporaryArrays.erase(id); + _state->temporaryArrayIds.erase(arrayId); } void DeleteAllTempArrays() { - for (auto it = temporaryArrays.begin(); it != temporaryArrays.end(); ++it) { + for (auto it = _state->temporaryArrayIds.begin(); it != _state->temporaryArrayIds.end(); ++it) { FreeArray(*it); } - temporaryArrays.clear(); + _state->temporaryArrayIds.clear(); } -void sfallArraysReset() +void ResizeArray(ArrayId arrayId, int newLen) { - temporaryArrays.clear(); - arrays.clear(); - nextArrayID = 1; - stackArrayId = 0; -} - -void ResizeArray(ArrayId array_id, int newLen) -{ - auto arr = get_array_by_id(array_id); - if (!arr) { + auto arr = get_array_by_id(arrayId); + if (arr == nullptr) { return; - }; + } + arr->ResizeArray(newLen); } int StackArray(const ProgramValue& key, const ProgramValue& val, Program* program) { - if (stackArrayId == 0) { + // CE: Sfall uses eponymous global variable which is always the id of the + // last created array. + ArrayId stackArrayId = _state->nextArrayId - 1; + + auto arr = get_array_by_id(stackArrayId); + if (arr == nullptr) { return 0; } - auto arr = get_array_by_id(stackArrayId); - if (!arr) { - return 0; - }; - auto size = arr->size(); - if (size >= ARRAY_MAX_SIZE) return 0; - if (key.asInt() >= size) arr->ResizeArray(size + 1); + if (size >= ARRAY_MAX_SIZE) { + return 0; + } + + if (key.asInt() >= size) { + arr->ResizeArray(size + 1); + } SetArray(stackArrayId, key, val, false, program); return 0; } -ProgramValue ScanArray(ArrayId array_id, const ProgramValue& val, Program* program) +ProgramValue ScanArray(ArrayId arrayId, const ProgramValue& val, Program* program) { - auto arr = get_array_by_id(array_id); - if (!arr) { + auto arr = get_array_by_id(arrayId); + if (arr == nullptr) { return ProgramValue(-1); - }; + } return arr->ScanArray(val, program); } ArrayId StringSplit(const char* str, const char* split) { - int splitLen = strlen(split); + size_t splitLen = strlen(split); - ArrayId array_id = CreateTempArray(0, 0); - auto arr = get_array_by_id(array_id); + ArrayId arrayId = CreateTempArray(0, 0); + auto arr = get_array_by_id(arrayId); - if (!splitLen) { - int count = strlen(str); + if (splitLen == 0) { + int count = static_cast(strlen(str)); arr->ResizeArray(count); for (int i = 0; i < count; i++) { @@ -613,30 +663,35 @@ ArrayId StringSplit(const char* str, const char* split) } } else { int count = 1; - const char *ptr = str, *newptr; + const char* ptr = str; while (true) { - newptr = strstr(ptr, split); - if (!newptr) break; + const char* newptr = strstr(ptr, split); + if (newptr == nullptr) { + break; + } + count++; ptr = newptr + splitLen; } arr->ResizeArray(count); - ptr = str; count = 0; + ptr = str; while (true) { - newptr = strstr(ptr, split); - int len = (newptr) ? newptr - ptr : strlen(ptr); + const char* newptr = strstr(ptr, split); + size_t len = (newptr != nullptr) ? newptr - ptr : strlen(ptr); - arr->SetArray(ProgramValue { count++ }, ArrayElement { ptr, len }, false); + arr->SetArray(ProgramValue { count }, ArrayElement { ptr, len }, false); - if (!newptr) { + if (newptr == nullptr) { break; } + + count++; ptr = newptr + splitLen; } } - return array_id; + return arrayId; } -} \ No newline at end of file +} diff --git a/src/sfall_arrays.h b/src/sfall_arrays.h index 9f4f2ca..52a1304 100644 --- a/src/sfall_arrays.h +++ b/src/sfall_arrays.h @@ -1,9 +1,7 @@ -#ifndef SFALL_ARRAYS -#define SFALL_ARRAYS +#ifndef FALLOUT_SFALL_ARRAYS_H_ +#define FALLOUT_SFALL_ARRAYS_H_ #include "interpreter.h" -#include "object.h" -#include namespace fallout { @@ -13,21 +11,24 @@ namespace fallout { using ArrayId = unsigned int; -ArrayId CreateArray(int len, uint32_t flags); -ArrayId CreateTempArray(int len, uint32_t flags); -ProgramValue GetArrayKey(ArrayId array_id, int index, Program* program); -int LenArray(ArrayId array_id); -ProgramValue GetArray(ArrayId array_id, const ProgramValue& key, Program* program); -void SetArray(ArrayId array_id, const ProgramValue& key, const ProgramValue& val, bool allowUnset, Program* program); -void FreeArray(ArrayId array_id); -void FixArray(ArrayId id); -void ResizeArray(ArrayId array_id, int newLen); -void DeleteAllTempArrays(); +bool sfallArraysInit(); void sfallArraysReset(); +void sfallArraysExit(); +ArrayId CreateArray(int len, unsigned int flags); +ArrayId CreateTempArray(int len, unsigned int flags); +ProgramValue GetArrayKey(ArrayId arrayId, int index, Program* program); +int LenArray(ArrayId arrayId); +ProgramValue GetArray(ArrayId arrayId, const ProgramValue& key, Program* program); +void SetArray(ArrayId arrayId, const ProgramValue& key, const ProgramValue& val, bool allowUnset, Program* program); +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); -ProgramValue ScanArray(ArrayId array_id, const ProgramValue& val, Program* program); +ProgramValue ScanArray(ArrayId arrayId, const ProgramValue& val, Program* program); ArrayId StringSplit(const char* str, const char* split); } -#endif /* SFALL_ARRAYS */ \ No newline at end of file + +#endif /* FALLOUT_SFALL_ARRAYS_H_ */ diff --git a/src/sfall_opcodes.cc b/src/sfall_opcodes.cc index 1d4f08a..d03ee54 100644 --- a/src/sfall_opcodes.cc +++ b/src/sfall_opcodes.cc @@ -1,5 +1,7 @@ #include "sfall_opcodes.h" +#include + #include "animation.h" #include "art.h" #include "combat.h" @@ -22,8 +24,6 @@ #include "svga.h" #include "tile.h" #include "worldmap.h" -#include -#include namespace fallout { @@ -470,8 +470,11 @@ static void opSubstr(Program* program) if (startPos < 0) { startPos += len; // start from end - if (startPos < 0) startPos = 0; + if (startPos < 0) { + startPos = 0; + } } + if (length < 0) { length += len - startPos; // cutoff at end if (length == 0) { @@ -480,17 +483,21 @@ static void opSubstr(Program* program) } length = abs(length); // length can't be negative } + // check position if (startPos >= len) { // start position is out of string length, return empty string programStackPushString(program, buf); return; - }; + } + if (length == 0 || length + startPos > len) { length = len - startPos; // set the correct length, the length of characters goes beyond the end of the string } - if (length > sizeof(buf) - 1) length = sizeof(buf) - 1; + if (length > sizeof(buf) - 1) { + length = sizeof(buf) - 1; + } memcpy(buf, &str[startPos], length); buf[length] = '\0'; @@ -543,8 +550,8 @@ static void opCreateArray(Program* program) { auto flags = programStackPopInteger(program); auto len = programStackPopInteger(program); - auto array_id = CreateArray(len, flags); - programStackPushInteger(program, array_id); + auto arrayId = CreateArray(len, flags); + programStackPushInteger(program, arrayId); } // temp_array @@ -552,15 +559,15 @@ static void opTempArray(Program* program) { auto flags = programStackPopInteger(program); auto len = programStackPopInteger(program); - auto array_id = CreateTempArray(len, flags); - programStackPushInteger(program, array_id); + auto arrayId = CreateTempArray(len, flags); + programStackPushInteger(program, arrayId); } // fix_array static void opFixArray(Program* program) { - auto array_id = programStackPopInteger(program); - FixArray(array_id); + auto arrayId = programStackPopInteger(program); + FixArray(arrayId); } // string_split @@ -568,10 +575,8 @@ static void opStringSplit(Program* program) { auto split = programStackPopString(program); auto str = programStackPopString(program); - - auto returnValue = StringSplit(str, split); - - programStackPushInteger(program, returnValue); + auto arrayId = StringSplit(str, split); + programStackPushInteger(program, arrayId); } // set_array @@ -580,7 +585,6 @@ static void opSetArray(Program* program) auto value = programStackPopValue(program); auto key = programStackPopValue(program); auto arrayId = programStackPopInteger(program); - SetArray(arrayId, key, value, true, program); } @@ -598,7 +602,6 @@ static void opScanArray(Program* program) { auto value = programStackPopValue(program); auto arrayId = programStackPopInteger(program); - auto returnValue = ScanArray(arrayId, value, program); programStackPushValue(program, returnValue); } @@ -607,16 +610,14 @@ static void opScanArray(Program* program) static void opGetArray(Program* program) { auto key = programStackPopValue(program); - auto arrayId = programStackPopValue(program); + if (arrayId.isInt()) { auto value = GetArray(arrayId.integerValue, key, program); programStackPushValue(program, value); } else if (arrayId.isString() && key.isInt()) { - - auto& strVal = arrayId; auto pos = key.asInt(); - auto str = programGetString(program, strVal.opcode, strVal.integerValue); + auto str = programGetString(program, arrayId.opcode, arrayId.integerValue); char buf[2] = { 0 }; if (pos < strlen(str)) { @@ -655,11 +656,11 @@ static void opPartyMemberList(Program* program) { auto includeHidden = programStackPopInteger(program); auto objects = get_all_party_members_objects(includeHidden); - auto array_id = CreateTempArray(objects.size(), SFALL_ARRAYFLAG_RESERVED); - for (int i = 0; i < LenArray(array_id); i++) { - SetArray(array_id, ProgramValue { i }, ProgramValue { objects[i] }, false, program); + auto arrayId = CreateTempArray(objects.size(), SFALL_ARRAYFLAG_RESERVED); + for (int i = 0; i < LenArray(arrayId); i++) { + SetArray(arrayId, ProgramValue { i }, ProgramValue { objects[i] }, false, program); } - programStackPushInteger(program, array_id); + programStackPushInteger(program, arrayId); } // type_of