mirror of
https://github.com/fallout2-ce/fallout2-ce.git
synced 2026-07-27 16:47:11 -07:00
mapper: save map to TXT
This commit is contained in:
+47
-2
@@ -447,9 +447,54 @@ void artRender(int fid, unsigned char* dest, int width, int height, int pitch)
|
||||
// mapper2.exe: 0x40A03C
|
||||
int art_list_str(int fid, char* name)
|
||||
{
|
||||
// TODO: Incomplete.
|
||||
if (fid == -1 || name == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
int objectType = (fid & 0xF000000) >> 24;
|
||||
int index = fid & 0xFFF;
|
||||
|
||||
const char* typeName = artGetObjectTypeName(objectType);
|
||||
if (typeName == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
char path[260];
|
||||
snprintf(path, sizeof(path), "%s%s%s\\%s.lst", _cd_path_base, "art\\", typeName, typeName);
|
||||
|
||||
File* stream = fileOpen(path, "rt");
|
||||
if (stream == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
char buffer[260];
|
||||
int line = 0;
|
||||
bool found = false;
|
||||
while (fileReadString(buffer, sizeof(buffer), stream) != nullptr) {
|
||||
if (line == index) {
|
||||
char* p = buffer;
|
||||
while (*p) {
|
||||
if (*p == ' ' || *p == '\n') {
|
||||
*p = '\0';
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
char* dst = name;
|
||||
const char* src = buffer;
|
||||
do {
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
} while (dst[-2] != '\0' || dst[-1] != '\0');
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
line++;
|
||||
}
|
||||
|
||||
fileClose(stream);
|
||||
|
||||
return found ? 0 : -1;
|
||||
}
|
||||
|
||||
int artListIndex(int objectType, const char* name)
|
||||
|
||||
+231
-11
@@ -15,6 +15,7 @@
|
||||
#include "mapper/mp_proto.h"
|
||||
#include "obj_types.h"
|
||||
#include "object.h"
|
||||
#include "proto.h"
|
||||
#include "scripts.h"
|
||||
#include "settings.h"
|
||||
#include "text_font.h"
|
||||
@@ -23,17 +24,238 @@
|
||||
|
||||
namespace fallout {
|
||||
|
||||
// Stub implementations for text-format save functions.
|
||||
// These will be fully implemented in future rounds.
|
||||
static int scrSaveText(File* stream)
|
||||
// Forward declarations for save functions.
|
||||
static int obj_save_obj_text(File* stream, Object* obj);
|
||||
// Functions to build path strings for PID/FID (maps to original pid_to_string/fid_to_string)
|
||||
static const char* pid_to_string(int pid);
|
||||
static const char* fid_to_string(int fid);
|
||||
|
||||
static const char* pid_to_string(int pid)
|
||||
{
|
||||
xfilePrintFormatted(stream, "/* Scripts not implemented in text format yet */\n");
|
||||
static char pidStr[COMPAT_MAX_PATH];
|
||||
|
||||
if (_proto_list_str(pid, pidStr) == -1) {
|
||||
return "";
|
||||
}
|
||||
|
||||
char* dot = strchr(pidStr, '.');
|
||||
if (dot != nullptr) {
|
||||
*dot = '\0';
|
||||
}
|
||||
|
||||
return pidStr;
|
||||
}
|
||||
|
||||
static const char* fid_to_string(int fid)
|
||||
{
|
||||
static char fidStr[COMPAT_MAX_PATH];
|
||||
|
||||
if (art_list_str(fid, fidStr) == -1) {
|
||||
return "";
|
||||
}
|
||||
|
||||
char* dot = strchr(fidStr, '.');
|
||||
if (dot != nullptr) {
|
||||
*dot = '\0';
|
||||
}
|
||||
|
||||
return fidStr;
|
||||
}
|
||||
|
||||
static int scr_save_text(File* stream)
|
||||
{
|
||||
if (stream == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int scriptType = 0; scriptType < SCRIPT_TYPE_COUNT; scriptType++) {
|
||||
ScriptList* scriptList = &gScriptLists[scriptType];
|
||||
|
||||
int scriptCount = scriptList->length * SCRIPT_LIST_EXTENT_SIZE;
|
||||
if (scriptList->tail != nullptr) {
|
||||
scriptCount += scriptList->tail->length - SCRIPT_LIST_EXTENT_SIZE;
|
||||
}
|
||||
|
||||
xfilePrintFormatted(stream, "scr_num: %d\n", scriptCount);
|
||||
|
||||
if (scriptList->head == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ScriptListExtent* scriptExtent = scriptList->head;
|
||||
while (scriptExtent != nullptr) {
|
||||
xfilePrintFormatted(stream, "\n[[SCRIPT]]\n\n");
|
||||
for (int index = 0; index < scriptExtent->length; index++) {
|
||||
Script* script = &scriptExtent->scripts[index];
|
||||
|
||||
xfilePrintFormatted(stream, "scr_id: %u\n", script->sid);
|
||||
xfilePrintFormatted(stream, "scr_next: %u\n", script->field_4);
|
||||
xfilePrintFormatted(stream, "scr_flags: %d\n", script->flags);
|
||||
xfilePrintFormatted(stream, "scr_script_idx: %d\n", script->index);
|
||||
xfilePrintFormatted(stream, "scr_oid: %u\n", script->ownerId);
|
||||
xfilePrintFormatted(stream, "scr_local_var_offset: %u\n", script->localVarsOffset);
|
||||
xfilePrintFormatted(stream, "scr_num_local_vars: %u\n\n", script->localVarsCount);
|
||||
|
||||
if (scriptType == SCRIPT_TYPE_SPATIAL) {
|
||||
xfilePrintFormatted(stream, "scr_udata.sp.built_tile: %d\n\n", script->sp.built_tile);
|
||||
xfilePrintFormatted(stream, "scr_udata.sp.radius: %d\n\n", script->sp.radius);
|
||||
} else if (scriptType == SCRIPT_TYPE_TIMED) {
|
||||
xfilePrintFormatted(stream, "scr_udata.tm.time: %d\n\n", script->tm.time);
|
||||
}
|
||||
}
|
||||
scriptExtent = scriptExtent->next;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int objSaveText(File* stream)
|
||||
static int obj_save_text(File* stream)
|
||||
{
|
||||
xfilePrintFormatted(stream, "/* Objects not implemented in text format yet */\n");
|
||||
if (stream == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
xfilePrintFormatted(stream, "[[OBJECTS BEGIN]]\n\n");
|
||||
|
||||
for (int elevation = 0; elevation < ELEVATION_COUNT; elevation++) {
|
||||
for (int tile = 0; tile < HEX_GRID_SIZE; tile++) {
|
||||
for (ObjectListNode* objectListNode = gObjectListHeadByTile[tile]; objectListNode != nullptr; objectListNode = objectListNode->next) {
|
||||
Object* obj = objectListNode->obj;
|
||||
if (obj->elevation != elevation) {
|
||||
continue;
|
||||
}
|
||||
if ((obj->flags & OBJECT_NO_SAVE) == 0) {
|
||||
obj_save_obj_text(stream, obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xfilePrintFormatted(stream, "[[OBJECTS END]]\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int obj_save_obj_text(File* stream, Object* obj)
|
||||
{
|
||||
if (stream == nullptr || obj == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
xfilePrintFormatted(stream, "[OBJECT BEGIN]\n");
|
||||
xfilePrintFormatted(stream, "obj_id: %d\n", obj->id);
|
||||
xfilePrintFormatted(stream, "obj_tile_num: %d\n", obj->tile);
|
||||
xfilePrintFormatted(stream, "obj_x: %d\n", obj->x);
|
||||
xfilePrintFormatted(stream, "obj_y: %d\n", obj->y);
|
||||
xfilePrintFormatted(stream, "obj_sx: %d\n", obj->sx);
|
||||
xfilePrintFormatted(stream, "obj_sy: %d\n", obj->sy);
|
||||
xfilePrintFormatted(stream, "obj_cur_frm: %u\n", obj->frame);
|
||||
xfilePrintFormatted(stream, "obj_cur_rot: %u\n", obj->rotation);
|
||||
xfilePrintFormatted(stream, "obj_pid: %u %s\n", obj->pid, pid_to_string(obj->pid));
|
||||
xfilePrintFormatted(stream, "obj_fid: %u %s\n", obj->fid, fid_to_string(obj->fid));
|
||||
xfilePrintFormatted(stream, "obj_flags: %u\n", obj->flags);
|
||||
xfilePrintFormatted(stream, "obj_elev: %d\n", obj->elevation);
|
||||
xfilePrintFormatted(stream, "obj_cid: %u\n", obj->cid);
|
||||
xfilePrintFormatted(stream, "obj_light_distance: %d\n", obj->lightDistance);
|
||||
xfilePrintFormatted(stream, "obj_light_intensity: %d\n", obj->lightIntensity);
|
||||
xfilePrintFormatted(stream, "obj_outline: %d\n", obj->outline);
|
||||
xfilePrintFormatted(stream, "obj_sid: %u\n", obj->sid);
|
||||
xfilePrintFormatted(stream, "obj_pud.inv_size: %d\n", obj->data.inventory.length);
|
||||
xfilePrintFormatted(stream, "obj_pud.inv_max: %d\n", obj->data.inventory.capacity);
|
||||
|
||||
int pidType = PID_TYPE(obj->pid);
|
||||
|
||||
if (pidType == OBJ_TYPE_CRITTER) {
|
||||
xfilePrintFormatted(stream, "obj_pud.reaction_to_pc: %d\n", obj->data.critter.reaction);
|
||||
xfilePrintFormatted(stream, "obj_pud.curr_hp: %d\n", obj->data.critter.hp);
|
||||
xfilePrintFormatted(stream, "obj_pud.curr_rad: %d\n", obj->data.critter.radiation);
|
||||
xfilePrintFormatted(stream, "obj_pud.curr_poison: %d\n", obj->data.critter.poison);
|
||||
xfilePrintFormatted(stream, "obj_pud.combat_data.curr_mp: %d\n", obj->data.critter.combat.ap);
|
||||
xfilePrintFormatted(stream, "obj_pud.combat_data.damage_last_turn: %d\n", obj->data.critter.combat.damageLastTurn);
|
||||
xfilePrintFormatted(stream, "obj_pud.combat_data.results: %d\n", obj->data.critter.combat.results);
|
||||
xfilePrintFormatted(stream, "obj_pud.combat_data.ai_packet: %d\n", obj->data.critter.combat.aiPacket);
|
||||
xfilePrintFormatted(stream, "obj_pud.combat_data.team_num: %d\n", obj->data.critter.combat.team);
|
||||
if (obj->data.critter.combat.whoHitMe != nullptr) {
|
||||
xfilePrintFormatted(stream, "obj_pud.combat_data.who_hit_me: %d\n", obj->data.critter.combat.whoHitMeCid);
|
||||
} else {
|
||||
xfilePrintFormatted(stream, "obj_pud.combat_data.who_hit_me: -1\n");
|
||||
}
|
||||
} else {
|
||||
xfilePrintFormatted(stream, "obj_pudg.updated_flags: %d\n", obj->data.flags);
|
||||
|
||||
Proto* proto;
|
||||
if (protoGetProto(obj->pid, &proto) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get subtype from proto type field (same offset for ItemProto and SceneryProto)
|
||||
int protoSubtype = static_cast<int>(proto->item.type);
|
||||
|
||||
switch (pidType) {
|
||||
case OBJ_TYPE_ITEM:
|
||||
switch (protoSubtype) {
|
||||
case ITEM_TYPE_WEAPON:
|
||||
xfilePrintFormatted(stream, "obj_pudg.pudweapon.cur_ammo_quantity: %d\n", obj->data.item.weapon.ammoQuantity);
|
||||
xfilePrintFormatted(stream, "obj_pudg.pudweapon.cur_ammo_type_pid: %d\n", obj->data.item.weapon.ammoTypePid);
|
||||
break;
|
||||
case ITEM_TYPE_AMMO:
|
||||
xfilePrintFormatted(stream, "obj_pudg.pudammo.cur_ammo_quantity: %d\n", obj->data.item.ammo.quantity);
|
||||
break;
|
||||
case ITEM_TYPE_MISC:
|
||||
xfilePrintFormatted(stream, "obj_pudg.pudmisc_item.curr_charges: %d\n", obj->data.item.misc.charges);
|
||||
break;
|
||||
case ITEM_TYPE_KEY:
|
||||
xfilePrintFormatted(stream, "obj_pudg.pudkey_item.cur_key_code: %d\n", obj->data.item.key.keyCode);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case OBJ_TYPE_SCENERY:
|
||||
switch (protoSubtype) {
|
||||
case SCENERY_TYPE_DOOR:
|
||||
xfilePrintFormatted(stream, "obj_pudg.pudportal.cur_open_flags: %d\n", obj->data.scenery.door.openFlags);
|
||||
break;
|
||||
case SCENERY_TYPE_STAIRS:
|
||||
xfilePrintFormatted(stream, "obj_pudg.pudstairs.destMap: %d\n", obj->data.scenery.stairs.destinationMap);
|
||||
xfilePrintFormatted(stream, "obj_pudg.pudstairs.destBuiltTile: %d\n", obj->data.scenery.stairs.destinationBuiltTile);
|
||||
break;
|
||||
case SCENERY_TYPE_ELEVATOR:
|
||||
xfilePrintFormatted(stream, "obj_pudg.pudelevator.elevType: %d\n", obj->data.scenery.elevator.type);
|
||||
xfilePrintFormatted(stream, "obj_pudg.pudelevator.elevLevel: %d\n", obj->data.scenery.elevator.level);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (obj->data.inventory.length == 0) {
|
||||
xfilePrintFormatted(stream, "[OBJECT END]\n\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
xfilePrintFormatted(stream, "obj_pud.[BEGIN INVEN ITEMS]:\n");
|
||||
|
||||
if (obj->data.inventory.length <= 0) {
|
||||
xfilePrintFormatted(stream, "obj_pud.[END INVEN ITEMS]:\n");
|
||||
xfilePrintFormatted(stream, "[OBJECT END]\n\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < obj->data.inventory.length; i++) {
|
||||
InventoryItem* item = &obj->data.inventory.items[i];
|
||||
xfilePrintFormatted(stream, "obj_pud.inven_item: %d\n", i);
|
||||
xfilePrintFormatted(stream, "obj_pud.inv.count: %d\n", item->quantity);
|
||||
if (obj_save_obj_text(stream, item->item) == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
xfilePrintFormatted(stream, "obj_pud.[END INVEN ITEMS]:\n");
|
||||
xfilePrintFormatted(stream, "[OBJECT END]\n\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -158,9 +380,7 @@ void map_save_text()
|
||||
for (int elev = 0; elev < ELEVATION_COUNT; elev++) {
|
||||
if ((gMapHeader.flags & _map_data_elev_flags[elev]) == 0) {
|
||||
xfilePrintFormatted(stream, "\nsquare_elev: %d\n\n", elev);
|
||||
for (int tile = 0; tile < SQUARE_GRID_SIZE; tile++) {
|
||||
int tileData = _square[elev]->field_0[tile];
|
||||
|
||||
for (int tileData : _square[elev]->field_0) {
|
||||
xfilePrintFormatted(stream, "sq: %u ", tileData);
|
||||
|
||||
// Floor tile art file path.
|
||||
@@ -206,7 +426,7 @@ void map_save_text()
|
||||
// Save scripts in text format.
|
||||
xfilePrintFormatted(stream, "\n>>>>>>>>>>: SCRIPTS <<<<<<<<<<\n\n");
|
||||
xfilePrintFormatted(stream, "\nSCRS:\n");
|
||||
int scrResult = scrSaveText(stream);
|
||||
int scrResult = scr_save_text(stream);
|
||||
if (scrResult == -1) {
|
||||
char msg[80];
|
||||
snprintf(msg, sizeof(msg), "Error saving scripts in %s--TEXT", gMapHeader.name);
|
||||
@@ -215,7 +435,7 @@ void map_save_text()
|
||||
|
||||
// Save objects in text format.
|
||||
xfilePrintFormatted(stream, "\n>>>>>>>>>>: OBJECTS <<<<<<<<<<\n\n");
|
||||
int objResult = objSaveText(stream);
|
||||
int objResult = obj_save_text(stream);
|
||||
if (objResult == -1) {
|
||||
char msg[80];
|
||||
snprintf(msg, sizeof(msg), "Error saving objects in %s--TEXT", gMapHeader.name);
|
||||
|
||||
+2
-2
@@ -242,7 +242,7 @@ static Rect gObjectsUpdateAreaPixelBounds;
|
||||
// Contains objects that are bounded to tiles.
|
||||
//
|
||||
// 0x639DA0
|
||||
static ObjectListNode* gObjectListHeadByTile[HEX_GRID_SIZE];
|
||||
ObjectListNode* gObjectListHeadByTile[HEX_GRID_SIZE];
|
||||
|
||||
// 0x660EA0
|
||||
static unsigned char _glassGrayTable[256];
|
||||
@@ -2308,7 +2308,7 @@ Object* objectFindNextAtLocation()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 0x0x48B66C
|
||||
// 0x48B66C
|
||||
void objectGetRect(Object* obj, Rect* rect)
|
||||
{
|
||||
if (obj == nullptr) {
|
||||
|
||||
@@ -20,6 +20,7 @@ extern Object* _moveBlockObj;
|
||||
extern unsigned char _commonGrayTable[256];
|
||||
extern Object* gEgg;
|
||||
extern Object* gDude;
|
||||
extern ObjectListNode* gObjectListHeadByTile[HEX_GRID_SIZE];
|
||||
|
||||
int objectsInit(unsigned char* buf, int width, int height, int pitch);
|
||||
void objectsReset();
|
||||
|
||||
+1
-18
@@ -45,8 +45,6 @@
|
||||
|
||||
namespace fallout {
|
||||
|
||||
#define SCRIPT_LIST_EXTENT_SIZE 16
|
||||
|
||||
// SFALL: Increase number of message lists for scripted dialogs.
|
||||
// CE: In Sfall this increase is configurable with `BoostScriptDialogLimit`.
|
||||
#define SCRIPT_DIALOG_MESSAGE_LIST_CAPACITY 10000
|
||||
@@ -56,21 +54,6 @@ typedef struct ScriptsListEntry {
|
||||
int local_vars_num;
|
||||
} ScriptsListEntry;
|
||||
|
||||
typedef struct ScriptListExtent {
|
||||
Script scripts[SCRIPT_LIST_EXTENT_SIZE];
|
||||
// Number of scripts in the extent
|
||||
int length;
|
||||
struct ScriptListExtent* next;
|
||||
} ScriptListExtent;
|
||||
|
||||
typedef struct ScriptList {
|
||||
ScriptListExtent* head;
|
||||
ScriptListExtent* tail;
|
||||
// Number of extents in the script list.
|
||||
int length;
|
||||
int nextScriptId;
|
||||
} ScriptList;
|
||||
|
||||
static Program* scriptsCreateProgramByName(const char* name);
|
||||
static void _doBkProcesses();
|
||||
static void _script_chk_critters();
|
||||
@@ -116,7 +99,7 @@ static int gScriptsEnumerationElevation = 0;
|
||||
static bool gSpatialsEnabled = true;
|
||||
|
||||
// 0x51C6C0
|
||||
static ScriptList gScriptLists[SCRIPT_TYPE_COUNT];
|
||||
ScriptList gScriptLists[SCRIPT_TYPE_COUNT];
|
||||
|
||||
// 0x51C710
|
||||
static const char* gScriptsBasePath = "scripts\\";
|
||||
|
||||
+18
-2
@@ -79,7 +79,7 @@ typedef enum ScriptProc {
|
||||
SCRIPT_PROC_COUNT,
|
||||
} ScriptProc;
|
||||
|
||||
typedef struct Script {
|
||||
struct Script {
|
||||
// scr_id
|
||||
int sid;
|
||||
|
||||
@@ -146,8 +146,24 @@ typedef struct Script {
|
||||
int field_DC;
|
||||
|
||||
Object* overriddenSelf;
|
||||
} Script;
|
||||
};
|
||||
|
||||
#define SCRIPT_LIST_EXTENT_SIZE (16)
|
||||
|
||||
struct ScriptListExtent {
|
||||
Script scripts[SCRIPT_LIST_EXTENT_SIZE];
|
||||
int length;
|
||||
ScriptListExtent* next;
|
||||
};
|
||||
|
||||
struct ScriptList {
|
||||
ScriptListExtent* head;
|
||||
ScriptListExtent* tail;
|
||||
int length;
|
||||
int nextScriptId;
|
||||
};
|
||||
|
||||
extern ScriptList gScriptLists[SCRIPT_TYPE_COUNT];
|
||||
extern const char* gScriptProcNames[SCRIPT_PROC_COUNT];
|
||||
|
||||
unsigned int gameTimeGetTime();
|
||||
|
||||
Reference in New Issue
Block a user