Refactor
This commit is contained in:
parent
287ed6d49c
commit
cae990b65e
|
@ -349,6 +349,11 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int a4
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!sfallArraysInit()) {
|
||||||
|
debugPrint("Failed on sfallArraysInit");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_MISC, &gMiscMessageList);
|
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_MISC, &gMiscMessageList);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -405,6 +410,7 @@ void gameExit()
|
||||||
debugPrint("\nGame Exit\n");
|
debugPrint("\nGame Exit\n");
|
||||||
|
|
||||||
// SFALL
|
// SFALL
|
||||||
|
sfallArraysExit();
|
||||||
sfallListsExit();
|
sfallListsExit();
|
||||||
sfallGlobalVarsExit();
|
sfallGlobalVarsExit();
|
||||||
premadeCharactersExit();
|
premadeCharactersExit();
|
||||||
|
|
|
@ -912,19 +912,6 @@ int _getPartyMemberCount()
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Object*> get_all_party_members_objects(bool include_hidden)
|
|
||||||
{
|
|
||||||
std::vector<Object*> 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
|
// 0x495070
|
||||||
static int _partyMemberNewObjID()
|
static int _partyMemberNewObjID()
|
||||||
{
|
{
|
||||||
|
@ -1683,4 +1670,20 @@ int partyGetMaxWoundToHealByRest()
|
||||||
return maxWound;
|
return maxWound;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<Object*> get_all_party_members_objects(bool include_hidden)
|
||||||
|
{
|
||||||
|
std::vector<Object*> 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
|
} // namespace fallout
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
#ifndef PARTY_MEMBER_H
|
#ifndef PARTY_MEMBER_H
|
||||||
#define PARTY_MEMBER_H
|
#define PARTY_MEMBER_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "db.h"
|
#include "db.h"
|
||||||
#include "obj_types.h"
|
#include "obj_types.h"
|
||||||
#include "scripts.h"
|
#include "scripts.h"
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace fallout {
|
namespace fallout {
|
||||||
|
|
||||||
|
|
|
@ -1,25 +1,20 @@
|
||||||
#include "sfall_arrays.h"
|
#include "sfall_arrays.h"
|
||||||
#include "interpreter.h"
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdint>
|
|
||||||
#include <map>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <stdexcept>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
/*
|
#include "interpreter.h"
|
||||||
Used https://gist.github.com/phobos2077/6bf357c49caaf515371a13f9a2d74a41 for testing
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace fallout {
|
namespace fallout {
|
||||||
|
|
||||||
static ArrayId nextArrayID = 1;
|
static constexpr ArrayId kInitialArrayId = 1;
|
||||||
static ArrayId stackArrayId = 0;
|
|
||||||
|
|
||||||
#define ARRAY_MAX_STRING (255) // maximum length of string to be stored as array key or value
|
#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,
|
#define ARRAY_MAX_SIZE (100000) // maximum number of array elements,
|
||||||
|
@ -70,46 +65,26 @@ enum class ArrayElementType {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class ArrayElement {
|
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:
|
public:
|
||||||
ArrayElement()
|
ArrayElement()
|
||||||
: type(ArrayElementType::INT)
|
: type(ArrayElementType::INT)
|
||||||
, value(
|
, value({ 0 })
|
||||||
{ 0 }) {
|
{
|
||||||
// Nothing here
|
}
|
||||||
};
|
|
||||||
|
|
||||||
ArrayElement(const ArrayElement& other) = delete;
|
ArrayElement(const ArrayElement& other) = delete;
|
||||||
|
|
||||||
ArrayElement& operator=(const ArrayElement& rhs) = delete;
|
ArrayElement& operator=(const ArrayElement& rhs) = delete;
|
||||||
ArrayElement(ArrayElement&& other)
|
|
||||||
|
ArrayElement(ArrayElement&& other) noexcept
|
||||||
: type(ArrayElementType::INT)
|
: type(ArrayElementType::INT)
|
||||||
, value(
|
, value({ 0 })
|
||||||
{ 0 })
|
|
||||||
{
|
{
|
||||||
std::swap(type, other.type);
|
std::swap(type, other.type);
|
||||||
std::swap(value, other.value);
|
std::swap(value, other.value);
|
||||||
};
|
}
|
||||||
ArrayElement& operator=(ArrayElement&& other)
|
|
||||||
|
ArrayElement& operator=(ArrayElement&& other) noexcept
|
||||||
{
|
{
|
||||||
std::swap(type, other.type);
|
std::swap(type, other.type);
|
||||||
std::swap(value, other.value);
|
std::swap(value, other.value);
|
||||||
|
@ -133,19 +108,23 @@ public:
|
||||||
break;
|
break;
|
||||||
case VALUE_TYPE_STRING:
|
case VALUE_TYPE_STRING:
|
||||||
case VALUE_TYPE_DYNAMIC_STRING:
|
case VALUE_TYPE_DYNAMIC_STRING:
|
||||||
auto str = programGetString(program, programValue.opcode, programValue.integerValue);
|
setString(programGetString(program, programValue.opcode, programValue.integerValue), -1);
|
||||||
init_from_string(str, -1);
|
break;
|
||||||
|
default:
|
||||||
|
type = ArrayElementType::INT;
|
||||||
|
value.integerValue = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayElement(const char* str)
|
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
|
ProgramValue toValue(Program* program) const
|
||||||
|
@ -155,29 +134,29 @@ public:
|
||||||
case ArrayElementType::INT:
|
case ArrayElementType::INT:
|
||||||
out.opcode = VALUE_TYPE_INT;
|
out.opcode = VALUE_TYPE_INT;
|
||||||
out.integerValue = value.integerValue;
|
out.integerValue = value.integerValue;
|
||||||
return out;
|
break;
|
||||||
case ArrayElementType::FLOAT:
|
case ArrayElementType::FLOAT:
|
||||||
out.opcode = VALUE_TYPE_FLOAT;
|
out.opcode = VALUE_TYPE_FLOAT;
|
||||||
out.floatValue = value.floatValue;
|
out.floatValue = value.floatValue;
|
||||||
return out;
|
break;
|
||||||
case ArrayElementType::POINTER:
|
case ArrayElementType::POINTER:
|
||||||
out.opcode = VALUE_TYPE_PTR;
|
out.opcode = VALUE_TYPE_PTR;
|
||||||
out.pointerValue = value.pointerValue;
|
out.pointerValue = value.pointerValue;
|
||||||
return out;
|
break;
|
||||||
case ArrayElementType::STRING:
|
case ArrayElementType::STRING:
|
||||||
out.opcode = VALUE_TYPE_DYNAMIC_STRING;
|
out.opcode = VALUE_TYPE_DYNAMIC_STRING;
|
||||||
out.integerValue = programPushString(program, value.stringValue);
|
out.integerValue = programPushString(program, value.stringValue);
|
||||||
return out;
|
break;
|
||||||
default:
|
|
||||||
throw(std::exception());
|
|
||||||
}
|
}
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator<(ArrayElement const& other) const
|
bool operator<(ArrayElement const& other) const
|
||||||
{
|
{
|
||||||
if (type != other.type) {
|
if (type != other.type) {
|
||||||
return type < other.type;
|
return type < other.type;
|
||||||
};
|
}
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ArrayElementType::INT:
|
case ArrayElementType::INT:
|
||||||
return value.integerValue < other.value.integerValue;
|
return value.integerValue < other.value.integerValue;
|
||||||
|
@ -188,14 +167,16 @@ public:
|
||||||
case ArrayElementType::STRING:
|
case ArrayElementType::STRING:
|
||||||
return strcmp(value.stringValue, other.value.stringValue) < 0;
|
return strcmp(value.stringValue, other.value.stringValue) < 0;
|
||||||
default:
|
default:
|
||||||
throw(std::exception());
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(ArrayElement const& other) const
|
bool operator==(ArrayElement const& other) const
|
||||||
{
|
{
|
||||||
if (type != other.type) {
|
if (type != other.type) {
|
||||||
return false;
|
return false;
|
||||||
};
|
}
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ArrayElementType::INT:
|
case ArrayElementType::INT:
|
||||||
return value.integerValue == other.value.integerValue;
|
return value.integerValue == other.value.integerValue;
|
||||||
|
@ -206,7 +187,7 @@ public:
|
||||||
case ArrayElementType::STRING:
|
case ArrayElementType::STRING:
|
||||||
return strcmp(value.stringValue, other.value.stringValue) == 0;
|
return strcmp(value.stringValue, other.value.stringValue) == 0;
|
||||||
default:
|
default:
|
||||||
throw(std::exception());
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,68 +195,103 @@ public:
|
||||||
{
|
{
|
||||||
if (type == ArrayElementType::STRING) {
|
if (type == ArrayElementType::STRING) {
|
||||||
free(value.stringValue);
|
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 {
|
class SFallArray {
|
||||||
protected:
|
|
||||||
uint32_t mFlags;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual int size() = 0;
|
SFallArray(unsigned int flags)
|
||||||
|
: flags(flags)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
virtual ~SFallArray() = default;
|
||||||
virtual ProgramValue GetArrayKey(int index, Program* program) = 0;
|
virtual ProgramValue GetArrayKey(int index, Program* program) = 0;
|
||||||
virtual ProgramValue GetArray(const ProgramValue& key, 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, const ProgramValue& val, bool allowUnset, Program* program) = 0;
|
||||||
virtual void SetArray(const ProgramValue& key, ArrayElement&& val, bool allowUnset) = 0;
|
virtual void SetArray(const ProgramValue& key, ArrayElement&& val, bool allowUnset) = 0;
|
||||||
virtual void ResizeArray(int newLen) = 0;
|
virtual void ResizeArray(int newLen) = 0;
|
||||||
virtual ProgramValue ScanArray(const ProgramValue& value, Program* program) = 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 {
|
class SFallArrayList : public SFallArray {
|
||||||
private:
|
|
||||||
std::vector<ArrayElement> values;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SFallArrayList() = delete;
|
SFallArrayList() = delete;
|
||||||
|
|
||||||
SFallArrayList(unsigned int len, uint32_t flags)
|
SFallArrayList(unsigned int len, unsigned int flags)
|
||||||
|
: SFallArray(flags)
|
||||||
{
|
{
|
||||||
values.resize(len);
|
values.resize(len);
|
||||||
mFlags = flags;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int size()
|
int size()
|
||||||
{
|
{
|
||||||
return values.size();
|
return static_cast<int>(values.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
ProgramValue GetArrayKey(int index, Program* program)
|
ProgramValue GetArrayKey(int index, Program* program)
|
||||||
{
|
{
|
||||||
if (index < -1 || index > size()) {
|
if (index < -1 || index > size()) {
|
||||||
return ProgramValue(0);
|
return ProgramValue(0);
|
||||||
};
|
}
|
||||||
|
|
||||||
if (index == -1) { // special index to indicate if array is associative
|
if (index == -1) { // special index to indicate if array is associative
|
||||||
return ProgramValue(0);
|
return ProgramValue(0);
|
||||||
};
|
}
|
||||||
|
|
||||||
return ProgramValue(index);
|
return ProgramValue(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
ProgramValue GetArray(const ProgramValue& key, Program* program)
|
ProgramValue GetArray(const ProgramValue& key, Program* program)
|
||||||
{
|
{
|
||||||
auto element_index = key.asInt();
|
auto index = key.asInt();
|
||||||
if (element_index < 0 || element_index >= size()) {
|
if (index < 0 || index >= size()) {
|
||||||
return ProgramValue(0);
|
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)
|
void SetArray(const ProgramValue& key, const ProgramValue& val, bool allowUnset, Program* program)
|
||||||
{
|
{
|
||||||
SetArray(key, ArrayElement { val, program }, allowUnset);
|
SetArray(key, ArrayElement { val, program }, allowUnset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetArray(const ProgramValue& key, ArrayElement&& val, bool allowUnset)
|
void SetArray(const ProgramValue& key, ArrayElement&& val, bool allowUnset)
|
||||||
{
|
{
|
||||||
if (key.isInt()) {
|
if (key.isInt()) {
|
||||||
|
@ -290,11 +306,14 @@ public:
|
||||||
{
|
{
|
||||||
if (newLen == -1 || size() == newLen) {
|
if (newLen == -1 || size() == newLen) {
|
||||||
return;
|
return;
|
||||||
};
|
}
|
||||||
|
|
||||||
if (newLen == 0) {
|
if (newLen == 0) {
|
||||||
values.clear();
|
values.clear();
|
||||||
} else if (newLen > 0) {
|
} 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);
|
values.resize(newLen);
|
||||||
} else if (newLen >= ARRAY_ACTION_SHUFFLE) {
|
} else if (newLen >= ARRAY_ACTION_SHUFFLE) {
|
||||||
|
@ -304,156 +323,190 @@ public:
|
||||||
|
|
||||||
ProgramValue ScanArray(const ProgramValue& value, Program* program)
|
ProgramValue ScanArray(const ProgramValue& value, Program* program)
|
||||||
{
|
{
|
||||||
auto arrValue = ArrayElement { value, program };
|
auto element = ArrayElement { value, program };
|
||||||
for (size_t i = 0; i < size(); i++) {
|
for (int i = 0; i < size(); i++) {
|
||||||
if (arrValue == values[i]) {
|
if (element == values[i]) {
|
||||||
return ProgramValue(i);
|
return ProgramValue(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ProgramValue(-1);
|
return ProgramValue(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<ArrayElement> values;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SFallArrayAssoc : public SFallArray {
|
class SFallArrayAssoc : public SFallArray {
|
||||||
private:
|
|
||||||
std::vector<ArrayElement> keys;
|
|
||||||
std::map<ArrayElement, ArrayElement> map;
|
|
||||||
|
|
||||||
void MapSort(int newLen);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SFallArrayAssoc() = delete;
|
SFallArrayAssoc() = delete;
|
||||||
|
|
||||||
SFallArrayAssoc(uint32_t flags)
|
SFallArrayAssoc(unsigned int flags)
|
||||||
|
: SFallArray(flags)
|
||||||
{
|
{
|
||||||
mFlags = flags;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int size()
|
int size()
|
||||||
{
|
{
|
||||||
return keys.size();
|
return static_cast<int>(pairs.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
ProgramValue GetArrayKey(int index, Program* program)
|
ProgramValue GetArrayKey(int index, Program* program)
|
||||||
{
|
{
|
||||||
if (index < -1 || index > size()) {
|
if (index < -1 || index > size()) {
|
||||||
return ProgramValue(0);
|
return ProgramValue(0);
|
||||||
};
|
}
|
||||||
|
|
||||||
if (index == -1) { // special index to indicate if array is associative
|
if (index == -1) { // special index to indicate if array is associative
|
||||||
return ProgramValue(1);
|
return ProgramValue(1);
|
||||||
};
|
}
|
||||||
|
|
||||||
return keys[index].toValue(program);
|
return pairs[index].key.toValue(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
ProgramValue GetArray(const ProgramValue& key, Program* program)
|
ProgramValue GetArray(const ProgramValue& key, Program* program)
|
||||||
{
|
{
|
||||||
auto iter = map.find(ArrayElement { key, program });
|
auto keyEl = ArrayElement { key, program };
|
||||||
if (iter == map.end()) {
|
auto it = std::find_if(pairs.begin(), pairs.end(), [&keyEl](const KeyValuePair& pair) -> bool {
|
||||||
return ProgramValue(0);
|
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)
|
void SetArray(const ProgramValue& key, const ProgramValue& val, bool allowUnset, Program* program)
|
||||||
{
|
{
|
||||||
auto keyEl = ArrayElement { key, 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);
|
if (it != pairs.end() && isReadOnly()) {
|
||||||
|
|
||||||
bool lookupMap = (mFlags & SFALL_ARRAYFLAG_CONSTVAL) != 0;
|
|
||||||
|
|
||||||
if (iter != map.end() && lookupMap) {
|
|
||||||
// don't update value of key
|
// don't update value of key
|
||||||
return;
|
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
|
// 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()) {
|
if (it != pairs.end()) {
|
||||||
map.erase(iter);
|
pairs.erase(it);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (iter == map.end()) {
|
if (it == pairs.end()) {
|
||||||
// size check
|
// size check
|
||||||
if (size() >= ARRAY_MAX_SIZE) return;
|
if (size() >= ARRAY_MAX_SIZE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
keys.push_back(std::move(keyEl));
|
pairs.push_back(KeyValuePair { std::move(keyEl), ArrayElement { val, program } });
|
||||||
|
|
||||||
// Not very good that we copy string into map key and into keys array
|
|
||||||
map.emplace(ArrayElement { key, program }, ArrayElement { val, program });
|
|
||||||
} else {
|
} else {
|
||||||
auto newValue = ArrayElement { val, program };
|
auto index = it - pairs.begin();
|
||||||
std::swap(map.at(keyEl), newValue);
|
std::swap(pairs[index].value, ArrayElement { val, program });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetArray(const ProgramValue& key, ArrayElement&& val, bool allowUnset)
|
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)
|
void ResizeArray(int newLen)
|
||||||
{
|
{
|
||||||
if (newLen == -1 || size() == newLen) {
|
if (newLen == -1 || size() == newLen) {
|
||||||
return;
|
return;
|
||||||
};
|
}
|
||||||
|
|
||||||
// only allow to reduce number of elements (adding range of elements is meaningless for maps)
|
// only allow to reduce number of elements (adding range of elements is meaningless for maps)
|
||||||
if (newLen >= 0 && newLen < size()) {
|
if (newLen >= 0 && newLen < size()) {
|
||||||
for (size_t i = newLen; i < size(); i++) {
|
pairs.resize(newLen);
|
||||||
map.erase(keys[i]);
|
|
||||||
};
|
|
||||||
keys.resize(newLen);
|
|
||||||
} else if (newLen < 0) {
|
} else if (newLen < 0) {
|
||||||
if (newLen < (ARRAY_ACTION_SHUFFLE - 2)) return;
|
if (newLen < (ARRAY_ACTION_SHUFFLE - 2)) return;
|
||||||
MapSort(newLen);
|
MapSort(newLen);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
ProgramValue ScanArray(const ProgramValue& value, Program* program)
|
ProgramValue ScanArray(const ProgramValue& value, Program* program)
|
||||||
{
|
{
|
||||||
auto valueEl = ArrayElement { value, program };
|
auto valueEl = ArrayElement { value, program };
|
||||||
for (const auto& pair : map) {
|
auto it = std::find_if(pairs.begin(), pairs.end(), [&valueEl](const KeyValuePair& pair) {
|
||||||
if (valueEl == pair.second) {
|
return pair.value == valueEl;
|
||||||
return pair.first.toValue(program);
|
});
|
||||||
}
|
|
||||||
|
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<KeyValuePair> pairs;
|
||||||
};
|
};
|
||||||
|
|
||||||
void SFallArrayAssoc::MapSort(int type)
|
struct SfallArraysState {
|
||||||
|
std::unordered_map<ArrayId, std::unique_ptr<SFallArray>> arrays;
|
||||||
|
std::unordered_set<ArrayId> temporaryArrayIds;
|
||||||
|
int nextArrayId = kInitialArrayId;
|
||||||
|
};
|
||||||
|
|
||||||
|
static SfallArraysState* _state = nullptr;
|
||||||
|
|
||||||
|
bool sfallArraysInit()
|
||||||
{
|
{
|
||||||
bool sortByValue = false;
|
_state = new (std::nothrow) SfallArraysState();
|
||||||
if (type < ARRAY_ACTION_SHUFFLE) {
|
if (_state == nullptr) {
|
||||||
type += 4;
|
return false;
|
||||||
sortByValue = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sortByValue) {
|
return true;
|
||||||
ListSort(keys, type, [this](const ArrayElement& a, const ArrayElement& b) -> bool {
|
}
|
||||||
return map.at(a) < map.at(b);
|
|
||||||
});
|
void sfallArraysReset()
|
||||||
} else {
|
{
|
||||||
ListSort(keys, type, std::less<ArrayElement>());
|
if (_state != nullptr) {
|
||||||
|
_state->arrays.clear();
|
||||||
|
_state->temporaryArrayIds.clear();
|
||||||
|
_state->nextArrayId = kInitialArrayId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_map<ArrayId, std::unique_ptr<SFallArray>> arrays;
|
void sfallArraysExit()
|
||||||
std::unordered_set<ArrayId> temporaryArrays;
|
{
|
||||||
|
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
|
flags = (flags & ~1); // reset 1 bit
|
||||||
|
|
||||||
|
@ -461,151 +514,148 @@ ArrayId CreateArray(int len, uint32_t flags)
|
||||||
flags |= SFALL_ARRAYFLAG_ASSOC;
|
flags |= SFALL_ARRAYFLAG_ASSOC;
|
||||||
} else if (len > ARRAY_MAX_SIZE) {
|
} else if (len > ARRAY_MAX_SIZE) {
|
||||||
len = ARRAY_MAX_SIZE; // safecheck
|
len = ARRAY_MAX_SIZE; // safecheck
|
||||||
};
|
}
|
||||||
|
|
||||||
ArrayId array_id = nextArrayID++;
|
ArrayId arrayId = _state->nextArrayId++;
|
||||||
stackArrayId = array_id;
|
|
||||||
|
|
||||||
if (flags & SFALL_ARRAYFLAG_ASSOC) {
|
if (flags & SFALL_ARRAYFLAG_ASSOC) {
|
||||||
arrays.emplace(std::make_pair(array_id, std::make_unique<SFallArrayAssoc>(flags)));
|
_state->arrays.emplace(std::make_pair(arrayId, std::make_unique<SFallArrayAssoc>(flags)));
|
||||||
} else {
|
} else {
|
||||||
arrays.emplace(std::make_pair(array_id, std::make_unique<SFallArrayList>(len, flags)));
|
_state->arrays.emplace(std::make_pair(arrayId, std::make_unique<SFallArrayList>(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);
|
ArrayId arrayId = CreateArray(len, flags);
|
||||||
temporaryArrays.insert(array_id);
|
_state->temporaryArrayIds.insert(arrayId);
|
||||||
return array_id;
|
return arrayId;
|
||||||
}
|
}
|
||||||
|
|
||||||
SFallArray* get_array_by_id(ArrayId array_id)
|
SFallArray* get_array_by_id(ArrayId arrayId)
|
||||||
{
|
{
|
||||||
auto it = arrays.find(array_id);
|
auto it = _state->arrays.find(arrayId);
|
||||||
if (it == arrays.end()) {
|
if (it == _state->arrays.end()) {
|
||||||
return nullptr;
|
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);
|
auto arr = get_array_by_id(arrayId);
|
||||||
if (!arr) {
|
if (arr == nullptr) {
|
||||||
return ProgramValue(0);
|
return ProgramValue(0);
|
||||||
};
|
}
|
||||||
|
|
||||||
return arr->GetArrayKey(index, program);
|
return arr->GetArrayKey(index, program);
|
||||||
}
|
}
|
||||||
|
|
||||||
int LenArray(ArrayId array_id)
|
int LenArray(ArrayId arrayId)
|
||||||
{
|
{
|
||||||
auto arr = get_array_by_id(array_id);
|
auto arr = get_array_by_id(arrayId);
|
||||||
if (!arr) {
|
if (arr == nullptr) {
|
||||||
return -1;
|
return -1;
|
||||||
};
|
}
|
||||||
|
|
||||||
return arr->size();
|
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);
|
auto arr = get_array_by_id(arrayId);
|
||||||
|
if (arr == nullptr) {
|
||||||
if (!arr) {
|
|
||||||
return ProgramValue(0);
|
return ProgramValue(0);
|
||||||
};
|
}
|
||||||
|
|
||||||
return arr->GetArray(key, program);
|
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);
|
auto arr = get_array_by_id(arrayId);
|
||||||
if (!arr) {
|
if (arr == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
arr->SetArray(key, val, allowUnset, program);
|
arr->SetArray(key, val, allowUnset, program);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FreeArray(ArrayId array_id)
|
void FreeArray(ArrayId arrayId)
|
||||||
{
|
{
|
||||||
// TODO: remove from saved_arrays
|
// 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()
|
void DeleteAllTempArrays()
|
||||||
{
|
{
|
||||||
for (auto it = temporaryArrays.begin(); it != temporaryArrays.end(); ++it) {
|
for (auto it = _state->temporaryArrayIds.begin(); it != _state->temporaryArrayIds.end(); ++it) {
|
||||||
FreeArray(*it);
|
FreeArray(*it);
|
||||||
}
|
}
|
||||||
temporaryArrays.clear();
|
_state->temporaryArrayIds.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void sfallArraysReset()
|
void ResizeArray(ArrayId arrayId, int newLen)
|
||||||
{
|
{
|
||||||
temporaryArrays.clear();
|
auto arr = get_array_by_id(arrayId);
|
||||||
arrays.clear();
|
if (arr == nullptr) {
|
||||||
nextArrayID = 1;
|
|
||||||
stackArrayId = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResizeArray(ArrayId array_id, int newLen)
|
|
||||||
{
|
|
||||||
auto arr = get_array_by_id(array_id);
|
|
||||||
if (!arr) {
|
|
||||||
return;
|
return;
|
||||||
};
|
}
|
||||||
|
|
||||||
arr->ResizeArray(newLen);
|
arr->ResizeArray(newLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
int StackArray(const ProgramValue& key, const ProgramValue& val, Program* program)
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto arr = get_array_by_id(stackArrayId);
|
|
||||||
if (!arr) {
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto size = arr->size();
|
auto size = arr->size();
|
||||||
if (size >= ARRAY_MAX_SIZE) return 0;
|
if (size >= ARRAY_MAX_SIZE) {
|
||||||
if (key.asInt() >= size) arr->ResizeArray(size + 1);
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.asInt() >= size) {
|
||||||
|
arr->ResizeArray(size + 1);
|
||||||
|
}
|
||||||
|
|
||||||
SetArray(stackArrayId, key, val, false, program);
|
SetArray(stackArrayId, key, val, false, program);
|
||||||
return 0;
|
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);
|
auto arr = get_array_by_id(arrayId);
|
||||||
if (!arr) {
|
if (arr == nullptr) {
|
||||||
return ProgramValue(-1);
|
return ProgramValue(-1);
|
||||||
};
|
}
|
||||||
|
|
||||||
return arr->ScanArray(val, program);
|
return arr->ScanArray(val, program);
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayId StringSplit(const char* str, const char* split)
|
ArrayId StringSplit(const char* str, const char* split)
|
||||||
{
|
{
|
||||||
int splitLen = strlen(split);
|
size_t splitLen = strlen(split);
|
||||||
|
|
||||||
ArrayId array_id = CreateTempArray(0, 0);
|
ArrayId arrayId = CreateTempArray(0, 0);
|
||||||
auto arr = get_array_by_id(array_id);
|
auto arr = get_array_by_id(arrayId);
|
||||||
|
|
||||||
if (!splitLen) {
|
if (splitLen == 0) {
|
||||||
int count = strlen(str);
|
int count = static_cast<int>(strlen(str));
|
||||||
|
|
||||||
arr->ResizeArray(count);
|
arr->ResizeArray(count);
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
|
@ -613,30 +663,35 @@ ArrayId StringSplit(const char* str, const char* split)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int count = 1;
|
int count = 1;
|
||||||
const char *ptr = str, *newptr;
|
const char* ptr = str;
|
||||||
while (true) {
|
while (true) {
|
||||||
newptr = strstr(ptr, split);
|
const char* newptr = strstr(ptr, split);
|
||||||
if (!newptr) break;
|
if (newptr == nullptr) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
ptr = newptr + splitLen;
|
ptr = newptr + splitLen;
|
||||||
}
|
}
|
||||||
arr->ResizeArray(count);
|
arr->ResizeArray(count);
|
||||||
|
|
||||||
ptr = str;
|
|
||||||
count = 0;
|
count = 0;
|
||||||
|
ptr = str;
|
||||||
while (true) {
|
while (true) {
|
||||||
newptr = strstr(ptr, split);
|
const char* newptr = strstr(ptr, split);
|
||||||
int len = (newptr) ? newptr - ptr : strlen(ptr);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
count++;
|
||||||
ptr = newptr + splitLen;
|
ptr = newptr + splitLen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return array_id;
|
return arrayId;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,9 +1,7 @@
|
||||||
#ifndef SFALL_ARRAYS
|
#ifndef FALLOUT_SFALL_ARRAYS_H_
|
||||||
#define SFALL_ARRAYS
|
#define FALLOUT_SFALL_ARRAYS_H_
|
||||||
|
|
||||||
#include "interpreter.h"
|
#include "interpreter.h"
|
||||||
#include "object.h"
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
namespace fallout {
|
namespace fallout {
|
||||||
|
|
||||||
|
@ -13,21 +11,24 @@ namespace fallout {
|
||||||
|
|
||||||
using ArrayId = unsigned int;
|
using ArrayId = unsigned int;
|
||||||
|
|
||||||
ArrayId CreateArray(int len, uint32_t flags);
|
bool sfallArraysInit();
|
||||||
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();
|
|
||||||
void sfallArraysReset();
|
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);
|
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);
|
ArrayId StringSplit(const char* str, const char* split);
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif /* SFALL_ARRAYS */
|
|
||||||
|
#endif /* FALLOUT_SFALL_ARRAYS_H_ */
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "sfall_opcodes.h"
|
#include "sfall_opcodes.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "animation.h"
|
#include "animation.h"
|
||||||
#include "art.h"
|
#include "art.h"
|
||||||
#include "combat.h"
|
#include "combat.h"
|
||||||
|
@ -22,8 +24,6 @@
|
||||||
#include "svga.h"
|
#include "svga.h"
|
||||||
#include "tile.h"
|
#include "tile.h"
|
||||||
#include "worldmap.h"
|
#include "worldmap.h"
|
||||||
#include <stdexcept>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
namespace fallout {
|
namespace fallout {
|
||||||
|
|
||||||
|
@ -470,8 +470,11 @@ static void opSubstr(Program* program)
|
||||||
|
|
||||||
if (startPos < 0) {
|
if (startPos < 0) {
|
||||||
startPos += len; // start from end
|
startPos += len; // start from end
|
||||||
if (startPos < 0) startPos = 0;
|
if (startPos < 0) {
|
||||||
|
startPos = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (length < 0) {
|
if (length < 0) {
|
||||||
length += len - startPos; // cutoff at end
|
length += len - startPos; // cutoff at end
|
||||||
if (length == 0) {
|
if (length == 0) {
|
||||||
|
@ -480,17 +483,21 @@ static void opSubstr(Program* program)
|
||||||
}
|
}
|
||||||
length = abs(length); // length can't be negative
|
length = abs(length); // length can't be negative
|
||||||
}
|
}
|
||||||
|
|
||||||
// check position
|
// check position
|
||||||
if (startPos >= len) {
|
if (startPos >= len) {
|
||||||
// start position is out of string length, return empty string
|
// start position is out of string length, return empty string
|
||||||
programStackPushString(program, buf);
|
programStackPushString(program, buf);
|
||||||
return;
|
return;
|
||||||
};
|
}
|
||||||
|
|
||||||
if (length == 0 || length + startPos > len) {
|
if (length == 0 || length + startPos > len) {
|
||||||
length = len - startPos; // set the correct length, the length of characters goes beyond the end of the string
|
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);
|
memcpy(buf, &str[startPos], length);
|
||||||
buf[length] = '\0';
|
buf[length] = '\0';
|
||||||
|
@ -543,8 +550,8 @@ static void opCreateArray(Program* program)
|
||||||
{
|
{
|
||||||
auto flags = programStackPopInteger(program);
|
auto flags = programStackPopInteger(program);
|
||||||
auto len = programStackPopInteger(program);
|
auto len = programStackPopInteger(program);
|
||||||
auto array_id = CreateArray(len, flags);
|
auto arrayId = CreateArray(len, flags);
|
||||||
programStackPushInteger(program, array_id);
|
programStackPushInteger(program, arrayId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// temp_array
|
// temp_array
|
||||||
|
@ -552,15 +559,15 @@ static void opTempArray(Program* program)
|
||||||
{
|
{
|
||||||
auto flags = programStackPopInteger(program);
|
auto flags = programStackPopInteger(program);
|
||||||
auto len = programStackPopInteger(program);
|
auto len = programStackPopInteger(program);
|
||||||
auto array_id = CreateTempArray(len, flags);
|
auto arrayId = CreateTempArray(len, flags);
|
||||||
programStackPushInteger(program, array_id);
|
programStackPushInteger(program, arrayId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// fix_array
|
// fix_array
|
||||||
static void opFixArray(Program* program)
|
static void opFixArray(Program* program)
|
||||||
{
|
{
|
||||||
auto array_id = programStackPopInteger(program);
|
auto arrayId = programStackPopInteger(program);
|
||||||
FixArray(array_id);
|
FixArray(arrayId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// string_split
|
// string_split
|
||||||
|
@ -568,10 +575,8 @@ static void opStringSplit(Program* program)
|
||||||
{
|
{
|
||||||
auto split = programStackPopString(program);
|
auto split = programStackPopString(program);
|
||||||
auto str = programStackPopString(program);
|
auto str = programStackPopString(program);
|
||||||
|
auto arrayId = StringSplit(str, split);
|
||||||
auto returnValue = StringSplit(str, split);
|
programStackPushInteger(program, arrayId);
|
||||||
|
|
||||||
programStackPushInteger(program, returnValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// set_array
|
// set_array
|
||||||
|
@ -580,7 +585,6 @@ static void opSetArray(Program* program)
|
||||||
auto value = programStackPopValue(program);
|
auto value = programStackPopValue(program);
|
||||||
auto key = programStackPopValue(program);
|
auto key = programStackPopValue(program);
|
||||||
auto arrayId = programStackPopInteger(program);
|
auto arrayId = programStackPopInteger(program);
|
||||||
|
|
||||||
SetArray(arrayId, key, value, true, program);
|
SetArray(arrayId, key, value, true, program);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -598,7 +602,6 @@ static void opScanArray(Program* program)
|
||||||
{
|
{
|
||||||
auto value = programStackPopValue(program);
|
auto value = programStackPopValue(program);
|
||||||
auto arrayId = programStackPopInteger(program);
|
auto arrayId = programStackPopInteger(program);
|
||||||
|
|
||||||
auto returnValue = ScanArray(arrayId, value, program);
|
auto returnValue = ScanArray(arrayId, value, program);
|
||||||
programStackPushValue(program, returnValue);
|
programStackPushValue(program, returnValue);
|
||||||
}
|
}
|
||||||
|
@ -607,16 +610,14 @@ static void opScanArray(Program* program)
|
||||||
static void opGetArray(Program* program)
|
static void opGetArray(Program* program)
|
||||||
{
|
{
|
||||||
auto key = programStackPopValue(program);
|
auto key = programStackPopValue(program);
|
||||||
|
|
||||||
auto arrayId = programStackPopValue(program);
|
auto arrayId = programStackPopValue(program);
|
||||||
|
|
||||||
if (arrayId.isInt()) {
|
if (arrayId.isInt()) {
|
||||||
auto value = GetArray(arrayId.integerValue, key, program);
|
auto value = GetArray(arrayId.integerValue, key, program);
|
||||||
programStackPushValue(program, value);
|
programStackPushValue(program, value);
|
||||||
} else if (arrayId.isString() && key.isInt()) {
|
} else if (arrayId.isString() && key.isInt()) {
|
||||||
|
|
||||||
auto& strVal = arrayId;
|
|
||||||
auto pos = key.asInt();
|
auto pos = key.asInt();
|
||||||
auto str = programGetString(program, strVal.opcode, strVal.integerValue);
|
auto str = programGetString(program, arrayId.opcode, arrayId.integerValue);
|
||||||
|
|
||||||
char buf[2] = { 0 };
|
char buf[2] = { 0 };
|
||||||
if (pos < strlen(str)) {
|
if (pos < strlen(str)) {
|
||||||
|
@ -655,11 +656,11 @@ static void opPartyMemberList(Program* program)
|
||||||
{
|
{
|
||||||
auto includeHidden = programStackPopInteger(program);
|
auto includeHidden = programStackPopInteger(program);
|
||||||
auto objects = get_all_party_members_objects(includeHidden);
|
auto objects = get_all_party_members_objects(includeHidden);
|
||||||
auto array_id = CreateTempArray(objects.size(), SFALL_ARRAYFLAG_RESERVED);
|
auto arrayId = CreateTempArray(objects.size(), SFALL_ARRAYFLAG_RESERVED);
|
||||||
for (int i = 0; i < LenArray(array_id); i++) {
|
for (int i = 0; i < LenArray(arrayId); i++) {
|
||||||
SetArray(array_id, ProgramValue { i }, ProgramValue { objects[i] }, false, program);
|
SetArray(arrayId, ProgramValue { i }, ProgramValue { objects[i] }, false, program);
|
||||||
}
|
}
|
||||||
programStackPushInteger(program, array_id);
|
programStackPushInteger(program, arrayId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// type_of
|
// type_of
|
||||||
|
|
Loading…
Reference in New Issue