parent
fa11122f87
commit
e0e0a1ee7d
|
@ -271,6 +271,8 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
|
|||
"src/sfall_config.h"
|
||||
"src/sfall_global_vars.cc"
|
||||
"src/sfall_global_vars.h"
|
||||
"src/sfall_lists.cc"
|
||||
"src/sfall_lists.h"
|
||||
"src/sfall_opcodes.cc"
|
||||
"src/sfall_opcodes.h"
|
||||
)
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
#include "settings.h"
|
||||
#include "sfall_config.h"
|
||||
#include "sfall_global_vars.h"
|
||||
#include "sfall_lists.h"
|
||||
#include "skill.h"
|
||||
#include "skilldex.h"
|
||||
#include "stat.h"
|
||||
|
@ -352,6 +353,11 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int a4
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (!sfallListsInit()) {
|
||||
debugPrint("Failed on sfallListsInit");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -395,6 +401,7 @@ void gameReset()
|
|||
|
||||
// SFALL
|
||||
sfallGlobalVarsReset();
|
||||
sfallListsReset();
|
||||
}
|
||||
|
||||
// 0x442C34
|
||||
|
@ -403,6 +410,7 @@ void gameExit()
|
|||
debugPrint("\nGame Exit\n");
|
||||
|
||||
// SFALL
|
||||
sfallListsExit();
|
||||
sfallGlobalVarsExit();
|
||||
premadeCharactersExit();
|
||||
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
#include "sfall_lists.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "object.h"
|
||||
#include "scripts.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
// Due to bad design of |ListType| it's |LIST_ITEMS| and |LIST_CRITTERS| do not
|
||||
// match |OBJ_TYPE_CRITTER| and |OBJ_TYPE_ITEM|.
|
||||
static constexpr int kObjectTypeToListType[] = {
|
||||
/* OBJ_TYPE_ITEM */ LIST_ITEMS,
|
||||
/* OBJ_TYPE_CRITTER */ LIST_CRITTERS,
|
||||
/* OBJ_TYPE_SCENERY */ LIST_SCENERY,
|
||||
/* OBJ_TYPE_WALL */ LIST_WALLS,
|
||||
/* OBJ_TYPE_TILE */ LIST_TILES,
|
||||
/* OBJ_TYPE_MISC */ LIST_MISC,
|
||||
};
|
||||
|
||||
static constexpr int kObjectTypeToListTypeSize = sizeof(kObjectTypeToListType) / sizeof(kObjectTypeToListType[0]);
|
||||
|
||||
// As in Sfall.
|
||||
static constexpr int kInitialListId = 0xCCCCCC;
|
||||
|
||||
// Loosely based on [sList] from Sfall.
|
||||
struct List {
|
||||
std::vector<Object*> objects;
|
||||
size_t pos = 0;
|
||||
};
|
||||
|
||||
struct State {
|
||||
std::unordered_map<int, List> lists;
|
||||
int nextListId = kInitialListId;
|
||||
};
|
||||
|
||||
static State* _state = nullptr;
|
||||
|
||||
bool sfallListsInit()
|
||||
{
|
||||
_state = new (std::nothrow) State();
|
||||
if (_state == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void sfallListsReset()
|
||||
{
|
||||
_state->nextListId = kInitialListId;
|
||||
_state->lists.clear();
|
||||
}
|
||||
|
||||
void sfallListsExit()
|
||||
{
|
||||
if (_state != nullptr) {
|
||||
delete _state;
|
||||
_state = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
int sfallListsCreate(int listType)
|
||||
{
|
||||
int listId = _state->nextListId++;
|
||||
List& list = _state->lists[listId];
|
||||
|
||||
if (listType == LIST_TILES) {
|
||||
// For unknown reason this list type is not implemented in Sfall.
|
||||
} else if (listType == LIST_SPATIAL) {
|
||||
for (int elevation = 0; elevation < ELEVATION_COUNT; elevation++) {
|
||||
Script* script = scriptGetFirstSpatialScript(elevation);
|
||||
while (script != nullptr) {
|
||||
Object* obj = script->owner;
|
||||
if (obj == nullptr) {
|
||||
obj = scriptGetSelf(script->program);
|
||||
}
|
||||
list.objects.push_back(obj);
|
||||
script = scriptGetNextSpatialScript();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// CE: Implementation is slightly different. Sfall manually loops thru
|
||||
// elevations (3) and hexes (40000) and use |objectFindFirstAtLocation|
|
||||
// (originally |obj_find_first_at_tile|) to obtain next object. This
|
||||
// functionality is already implemented in |objectFindFirst| and
|
||||
// |objectFindNext|.
|
||||
//
|
||||
// As a small optimization |LIST_ALL| is handled separately since there
|
||||
// is no need to check object type.
|
||||
if (listType == LIST_ALL) {
|
||||
Object* obj = objectFindFirst();
|
||||
while (obj != nullptr) {
|
||||
list.objects.push_back(obj);
|
||||
obj = objectFindNext();
|
||||
}
|
||||
} else {
|
||||
Object* obj = objectFindFirst();
|
||||
while (obj != nullptr) {
|
||||
int objectType = PID_TYPE(obj->pid);
|
||||
if (objectType < kObjectTypeToListTypeSize && kObjectTypeToListType[objectType] == listType) {
|
||||
list.objects.push_back(obj);
|
||||
}
|
||||
obj = objectFindNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return listId;
|
||||
}
|
||||
|
||||
Object* sfallListsGetNext(int listId)
|
||||
{
|
||||
auto it = _state->lists.find(listId);
|
||||
if (it != _state->lists.end()) {
|
||||
List& list = it->second;
|
||||
if (list.pos < list.objects.size()) {
|
||||
return list.objects[list.pos++];
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void sfallListsDestroy(int listId)
|
||||
{
|
||||
auto it = _state->lists.find(listId);
|
||||
if (it != _state->lists.end()) {
|
||||
_state->lists.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fallout
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef FALLOUT_SFALL_LISTS_H_
|
||||
#define FALLOUT_SFALL_LISTS_H_
|
||||
|
||||
#include "obj_types.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
enum ListType {
|
||||
LIST_CRITTERS = 0,
|
||||
LIST_ITEMS = 1,
|
||||
LIST_SCENERY = 2,
|
||||
LIST_WALLS = 3,
|
||||
LIST_TILES = 4,
|
||||
LIST_MISC = 5,
|
||||
LIST_SPATIAL = 6,
|
||||
LIST_ALL = 9,
|
||||
};
|
||||
|
||||
bool sfallListsInit();
|
||||
void sfallListsReset();
|
||||
void sfallListsExit();
|
||||
int sfallListsCreate(int listType);
|
||||
Object* sfallListsGetNext(int listId);
|
||||
void sfallListsDestroy(int listId);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* FALLOUT_SFALL_LISTS_H_ */
|
|
@ -7,6 +7,7 @@
|
|||
#include "mouse.h"
|
||||
#include "object.h"
|
||||
#include "sfall_global_vars.h"
|
||||
#include "sfall_lists.h"
|
||||
#include "stat.h"
|
||||
#include "svga.h"
|
||||
|
||||
|
@ -67,6 +68,29 @@ static void opGetGlobalInt(Program* program)
|
|||
programStackPushInteger(program, value);
|
||||
}
|
||||
|
||||
// list_begin
|
||||
static void opListBegin(Program* program)
|
||||
{
|
||||
int listType = programStackPopInteger(program);
|
||||
int listId = sfallListsCreate(listType);
|
||||
programStackPushInteger(program, listId);
|
||||
}
|
||||
|
||||
// list_next
|
||||
static void opListNext(Program* program)
|
||||
{
|
||||
int listId = programStackPopInteger(program);
|
||||
Object* obj = sfallListsGetNext(listId);
|
||||
programStackPushPointer(program, obj);
|
||||
}
|
||||
|
||||
// list_end
|
||||
static void opListEnd(Program* program)
|
||||
{
|
||||
int listId = programStackPopInteger(program);
|
||||
sfallListsDestroy(listId);
|
||||
}
|
||||
|
||||
// get_weapon_ammo_pid
|
||||
static void opGetWeaponAmmoPid(Program* program)
|
||||
{
|
||||
|
@ -205,6 +229,9 @@ void sfallOpcodesInit()
|
|||
interpreterRegisterOpcode(0x8193, opGetCurrentHand);
|
||||
interpreterRegisterOpcode(0x819D, opSetGlobalVar);
|
||||
interpreterRegisterOpcode(0x819E, opGetGlobalInt);
|
||||
interpreterRegisterOpcode(0x820D, opListBegin);
|
||||
interpreterRegisterOpcode(0x820E, opListNext);
|
||||
interpreterRegisterOpcode(0x820F, opListEnd);
|
||||
interpreterRegisterOpcode(0x8217, opGetWeaponAmmoPid);
|
||||
interpreterRegisterOpcode(0x8219, opGetWeaponAmmoCount);
|
||||
interpreterRegisterOpcode(0x821A, opSetWeaponAmmoCount);
|
||||
|
|
Loading…
Reference in New Issue