mirror of
https://github.com/fallout2-ce/fallout2-ce.git
synced 2026-07-27 16:47:11 -07:00
Compare commits
12
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a4a929f620 | ||
|
|
f5ba58f27a | ||
|
|
9bd179167c | ||
|
|
9e88b16d71 | ||
|
|
15a4f4275b | ||
|
|
466f12b22e | ||
|
|
26622f3596 | ||
|
|
629d1f2b7b | ||
|
|
1453a3e294 | ||
|
|
b5c0fbdf86 | ||
|
|
948558c64c | ||
|
|
6412d14a28 |
@@ -614,6 +614,8 @@ if((NOT ANDROID) AND (NOT IOS) AND (NOT CMAKE_SYSTEM_NAME MATCHES "Emscripten"))
|
||||
target_sources(mapper-ce PUBLIC
|
||||
${FALLOUT_ENGINE_SOURCES}
|
||||
${FALLOUT_PLATFORM_SOURCES}
|
||||
"src/proto_txt.cc"
|
||||
"src/proto_txt.h"
|
||||
"src/mapper/map_edge_setup.cc"
|
||||
"src/mapper/map_edge_setup.h"
|
||||
"src/mapper/map_func.cc"
|
||||
|
||||
@@ -367,6 +367,12 @@ void artToggleObjectTypeHidden(int objectType)
|
||||
}
|
||||
}
|
||||
|
||||
// art_total
|
||||
int art_total(int objectType)
|
||||
{
|
||||
return objectType >= 0 && objectType < OBJ_TYPE_COUNT ? gArtListDescriptions[objectType].fileNamesLength : 0;
|
||||
}
|
||||
|
||||
// 0x418F7C
|
||||
int artGetFidgetCount(int headFid)
|
||||
{
|
||||
|
||||
@@ -123,6 +123,7 @@ void artExit();
|
||||
char* artGetObjectTypeName(int objectType);
|
||||
int artIsObjectTypeHidden(int objectType);
|
||||
void artToggleObjectTypeHidden(int objectType);
|
||||
int art_total(int objectType);
|
||||
int artGetFidgetCount(int headFid);
|
||||
void artRender(int fid, unsigned char* dest, int width, int height, int pitch);
|
||||
int art_list_str(int fid, char* name);
|
||||
|
||||
@@ -144,6 +144,30 @@ File* fileOpen(const char* filename, const char* mode)
|
||||
return xfileOpen(filename, mode);
|
||||
}
|
||||
|
||||
File* fileOpenDirect(const char* filename, const char* mode)
|
||||
{
|
||||
return xfileOpenDirect(filename, mode);
|
||||
}
|
||||
|
||||
const char* buildDataPath(const char* root, const char* relative)
|
||||
{
|
||||
static char path[COMPAT_MAX_PATH];
|
||||
|
||||
size_t rootLen = strlen(root);
|
||||
bool rootHasSeparator = rootLen > 0 && (root[rootLen - 1] == '\\' || root[rootLen - 1] == '/');
|
||||
snprintf(path, sizeof(path), "%s%s%s", root, rootHasSeparator ? "" : "\\", relative);
|
||||
|
||||
char dir[COMPAT_MAX_PATH];
|
||||
snprintf(dir, sizeof(dir), "%s", path);
|
||||
char* separator = strrchr(dir, '\\');
|
||||
if (separator != nullptr) {
|
||||
*separator = '\0';
|
||||
compat_mkdir_recursive(dir);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
// 0x4C5ED0 db_fprintf
|
||||
int filePrintFormatted(File* stream, const char* format, ...)
|
||||
{
|
||||
|
||||
@@ -18,6 +18,7 @@ int dbGetFileSize(const char* filePath, int* sizePtr);
|
||||
int dbGetFileContents(const char* filePath, void* ptr);
|
||||
int fileClose(File* stream);
|
||||
File* fileOpen(const char* filename, const char* mode);
|
||||
File* fileOpenDirect(const char* filename, const char* mode);
|
||||
int filePrintFormatted(File* stream, const char* format, ...);
|
||||
int fileReadChar(File* stream);
|
||||
char* fileReadString(char* str, size_t size, File* stream);
|
||||
@@ -111,6 +112,10 @@ void fileNameListFree(char*** fileNames, int unused);
|
||||
int fileGetSize(File* stream);
|
||||
void fileSetReadProgressHandler(FileReadProgressHandler* handler, int size);
|
||||
|
||||
// Joins [root] and [relative] into a save path and creates its directory.
|
||||
// Returns a pointer to a static buffer.
|
||||
const char* buildDataPath(const char* root, const char* relative);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* DB_H */
|
||||
|
||||
+28
-53
@@ -723,38 +723,6 @@ const char* mapBuildPath(const char* name)
|
||||
return name;
|
||||
}
|
||||
|
||||
const char* mapBuildDataSavePath(const char* relativePath)
|
||||
{
|
||||
static char path[COMPAT_MAX_PATH];
|
||||
|
||||
// Save root: the validated mapper dev_path when set, otherwise the master patches path.
|
||||
const std::string& devPath = settings.mapper.dev_path;
|
||||
const char* root = !devPath.empty() ? devPath.c_str() : settings.system.master_patches_path.c_str();
|
||||
|
||||
// Join root + relativePath, tolerating a trailing separator on the root.
|
||||
size_t rootLen = strlen(root);
|
||||
bool rootHasSeparator = rootLen > 0 && (root[rootLen - 1] == '\\' || root[rootLen - 1] == '/');
|
||||
snprintf(path, sizeof(path), "%s%s%s", root, rootHasSeparator ? "" : "\\", relativePath);
|
||||
|
||||
// Ensure the directory portion exists.
|
||||
char dir[COMPAT_MAX_PATH];
|
||||
snprintf(dir, sizeof(dir), "%s", path);
|
||||
char* separator = strrchr(dir, '\\');
|
||||
if (separator != nullptr) {
|
||||
*separator = '\0';
|
||||
compat_mkdir_recursive(dir);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
const char* mapBuildSavePath(const char* name)
|
||||
{
|
||||
char relativePath[COMPAT_MAX_PATH];
|
||||
snprintf(relativePath, sizeof(relativePath), "MAPS\\%s", name);
|
||||
return mapBuildDataSavePath(relativePath);
|
||||
}
|
||||
|
||||
// 0x482924
|
||||
int mapSetEnteringLocation(int elevation, int tile_num, int orientation)
|
||||
{
|
||||
@@ -1375,34 +1343,41 @@ static void _map_fix_critter_combat_data()
|
||||
}
|
||||
}
|
||||
|
||||
// map_save
|
||||
// 0x483850
|
||||
int _map_save()
|
||||
// Saves the current map (and its .EDG sidecar) under the given save root,
|
||||
// writing directly to that folder without consulting the xbase database.
|
||||
int mapSaveToRoot(const char* root)
|
||||
{
|
||||
int rc = -1;
|
||||
if (gMapHeader.name[0] != '\0') {
|
||||
const char* mapFilePath = mapBuildSavePath(gMapHeader.name);
|
||||
File* stream = fileOpen(mapFilePath, "wb");
|
||||
if (stream != nullptr) {
|
||||
rc = _map_save_file(stream);
|
||||
fileClose(stream);
|
||||
} else {
|
||||
debugPrint("Unable to open %s to write!", gMapHeader.name);
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
debugPrint("%s saved.", gMapHeader.name);
|
||||
|
||||
// Write the edge (.EDG) sidecar alongside the map.
|
||||
mapEdgeSave(gMapHeader.name);
|
||||
}
|
||||
} else {
|
||||
if (gMapHeader.name[0] == '\0') {
|
||||
debugPrint("\nError: map_save: map header corrupt!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
char relativePath[COMPAT_MAX_PATH];
|
||||
snprintf(relativePath, sizeof(relativePath), "MAPS\\%s", gMapHeader.name);
|
||||
|
||||
int rc = -1;
|
||||
File* stream = fileOpenDirect(buildDataPath(root, relativePath), "wb");
|
||||
if (stream != nullptr) {
|
||||
rc = _map_save_file(stream);
|
||||
fileClose(stream);
|
||||
} else {
|
||||
debugPrint("Unable to open %s to write!", gMapHeader.name);
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
debugPrint("%s saved.", gMapHeader.name);
|
||||
mapEdgeSave(root, gMapHeader.name);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
// 0x483850 map_save
|
||||
int _map_save()
|
||||
{
|
||||
return mapSaveToRoot(settings.system.master_patches_path.c_str());
|
||||
}
|
||||
|
||||
// 0x483980
|
||||
static int _map_save_file(File* stream)
|
||||
{
|
||||
|
||||
@@ -106,12 +106,7 @@ void mapNewMap();
|
||||
int mapLoadByName(char* fileName);
|
||||
int mapLoadById(int map_index);
|
||||
const char* mapBuildPath(const char* name);
|
||||
// Resolves a VFS-relative data path (e.g. "MAPS\\ARROYO.MAP") to a writable path, creating its directory.
|
||||
// Save root is the validated mapper dev_path when set, otherwise the master patches path.
|
||||
const char* mapBuildDataSavePath(const char* relativePath);
|
||||
// Convenience wrapper around mapBuildDataSavePath for files under MAPS\, mirroring
|
||||
// mapBuildPath semantics: name is the bare filename, e.g. "ARROYO.MAP".
|
||||
const char* mapBuildSavePath(const char* name);
|
||||
int mapSaveToRoot(const char* root);
|
||||
int mapLoadSaved(char* fileName);
|
||||
int mapGetLoadedAreaId();
|
||||
int mapSetTransition(MapTransition* transition);
|
||||
|
||||
+5
-3
@@ -337,7 +337,7 @@ static bool writeEdgStream(File* stream)
|
||||
return true;
|
||||
}
|
||||
|
||||
void mapEdgeSave(const char* mapName)
|
||||
void mapEdgeSave(const char* root, const char* mapName)
|
||||
{
|
||||
int totalZones = 0;
|
||||
for (const EdgeElevationData& data : edgeData) {
|
||||
@@ -349,9 +349,11 @@ void mapEdgeSave(const char* mapName)
|
||||
|
||||
char edgName[COMPAT_MAX_PATH];
|
||||
buildEdgeFileName(mapName, edgName, sizeof(edgName));
|
||||
const char* edgPath = mapBuildSavePath(edgName);
|
||||
char relativePath[COMPAT_MAX_PATH];
|
||||
snprintf(relativePath, sizeof(relativePath), "MAPS\\%s", edgName);
|
||||
const char* edgPath = buildDataPath(root, relativePath);
|
||||
|
||||
File* stream = fileOpen(edgPath, "wb");
|
||||
File* stream = fileOpenDirect(edgPath, "wb");
|
||||
if (stream == nullptr) {
|
||||
debugPrint("mapEdgeSave: unable to open %s for writing\n", edgPath);
|
||||
return;
|
||||
|
||||
+3
-3
@@ -46,9 +46,9 @@ struct EdgeElevationData {
|
||||
// Silently does nothing if no .edg file is found.
|
||||
void mapEdgeLoad(const char* mapName);
|
||||
|
||||
// Writes the current in-memory edge data to the map's EDG file (mapper save path).
|
||||
// Does nothing when there are no edge zones. Used by the mapper map-save flow.
|
||||
void mapEdgeSave(const char* mapName);
|
||||
// Writes the current in-memory edge data to the map's EDG file under the given
|
||||
// save root. Does nothing when there are no edge zones.
|
||||
void mapEdgeSave(const char* root, const char* mapName);
|
||||
|
||||
// Mutable access to a single elevation's edge data. Used by the mapper edge editor,
|
||||
// which edits this data in place; the disk write happens later via mapEdgeSave.
|
||||
|
||||
+10
-10
@@ -284,7 +284,7 @@ void map_save_dialog()
|
||||
strcat(newName, ".map");
|
||||
strncpy(gMapHeader.name, newName, sizeof(gMapHeader.name) - 1);
|
||||
gMapHeader.name[sizeof(gMapHeader.name) - 1] = '\0';
|
||||
_map_save();
|
||||
mapSaveToRoot(mapperEditRoot());
|
||||
}
|
||||
|
||||
// map_save_as
|
||||
@@ -292,7 +292,7 @@ int map_save_as(const char* name)
|
||||
{
|
||||
strncpy(gMapHeader.name, name, sizeof(gMapHeader.name) - 1);
|
||||
gMapHeader.name[sizeof(gMapHeader.name) - 1] = '\0';
|
||||
return _map_save();
|
||||
return mapSaveToRoot(mapperEditRoot());
|
||||
}
|
||||
|
||||
// map_get_name
|
||||
@@ -660,8 +660,8 @@ static void copy_object_to_tile_pobj(int srcFid, int dstTile, Object* srcObj, bo
|
||||
|
||||
// Look for an existing duplicate (same tile + same fid) before placing.
|
||||
for (Object* obj = objectFindFirstAtElevation(gElevation);
|
||||
obj != nullptr;
|
||||
obj = objectFindNextAtElevation()) {
|
||||
obj != nullptr;
|
||||
obj = objectFindNextAtElevation()) {
|
||||
if (obj->tile == dstTile
|
||||
&& obj->fid == srcFid
|
||||
&& obj != gGameMouseBouncingCursor
|
||||
@@ -755,8 +755,8 @@ void copyObject(int filterType)
|
||||
if (tile == -1) continue;
|
||||
|
||||
for (Object* obj = objectFindFirstAtElevation(elevation);
|
||||
obj != nullptr;
|
||||
obj = objectFindNextAtElevation()) {
|
||||
obj != nullptr;
|
||||
obj = objectFindNextAtElevation()) {
|
||||
if (obj->tile != tile
|
||||
|| obj == gDude
|
||||
|| obj == gGameMouseBouncingCursor
|
||||
@@ -928,8 +928,8 @@ void eraseObject()
|
||||
// Find topmost (last-rendered) object at gElevation under the mouse.
|
||||
Object* hit = nullptr;
|
||||
for (Object* obj = objectFindFirstAtElevation(gElevation);
|
||||
obj != nullptr;
|
||||
obj = objectFindNextAtElevation()) {
|
||||
obj != nullptr;
|
||||
obj = objectFindNextAtElevation()) {
|
||||
if (obj == gDude) continue;
|
||||
if (PID_TYPE(obj->pid) == OBJ_TYPE_INTERFACE) continue;
|
||||
if ((obj->flags & OBJECT_HIDDEN) != 0) continue;
|
||||
@@ -1016,8 +1016,8 @@ static void mapper_shift_map_once(int dx, int dy)
|
||||
};
|
||||
std::vector<Snap> snap;
|
||||
for (Object* obj = objectFindFirstAtElevation(gElevation);
|
||||
obj != nullptr;
|
||||
obj = objectFindNextAtElevation()) {
|
||||
obj != nullptr;
|
||||
obj = objectFindNextAtElevation()) {
|
||||
if (obj->tile < 0 || obj->tile >= kShiftMapTiles) continue;
|
||||
if (obj == gDude) continue;
|
||||
if (obj == gGameMouseBouncingCursor) continue;
|
||||
|
||||
+35
-11
@@ -13,13 +13,11 @@
|
||||
#include "automap.h"
|
||||
#include "character_editor.h"
|
||||
#include "color.h"
|
||||
#include "config.h"
|
||||
#include "critter.h"
|
||||
#include "db.h"
|
||||
#include "debug.h"
|
||||
#include "draw.h"
|
||||
#include "game.h"
|
||||
#include "game_config.h"
|
||||
#include "game_dialog.h"
|
||||
#include "game_mouse.h"
|
||||
#include "game_movie.h"
|
||||
@@ -776,6 +774,21 @@ static void mapperValidateDevPath()
|
||||
devPath.clear();
|
||||
}
|
||||
|
||||
// Mounts the mapper temp folder (dev_temp_path, default "dev" relative to cwd) as
|
||||
// the highest-priority xbase. Mapper-only artifacts are read from here, and any
|
||||
// incidental relative write lands here instead of cluttering the dev_path mod
|
||||
// folder. Reverts to "dev" if explicitly cleared, and is created if missing.
|
||||
static void mapperMountDevTempPath()
|
||||
{
|
||||
std::string& devTemp = settings.mapper.dev_temp_path;
|
||||
if (devTemp.empty()) {
|
||||
devTemp = "dev";
|
||||
}
|
||||
|
||||
compat_mkdir_recursive(devTemp.c_str());
|
||||
xbaseOpen(devTemp.c_str());
|
||||
}
|
||||
|
||||
static void initMenuBar(const int screenWidth)
|
||||
{
|
||||
int foregroundColor = _colorTable[20052];
|
||||
@@ -1011,6 +1024,7 @@ int mapper_edit_init(int argc, char** argv)
|
||||
target_init();
|
||||
mouseShowCursor();
|
||||
mapperValidateDevPath();
|
||||
mapperMountDevTempPath();
|
||||
mapEdgeSetupInit();
|
||||
mapEdgeSetMapperMode(true);
|
||||
|
||||
@@ -2288,7 +2302,10 @@ void mapper_save_toolbar()
|
||||
if (dot != nullptr) *dot = '\0';
|
||||
strcat(name, ".cfg");
|
||||
|
||||
File* stream = fileOpen(mapBuildPath(name), "wb");
|
||||
char relativePath[COMPAT_MAX_PATH];
|
||||
snprintf(relativePath, sizeof(relativePath), "MAPS\\%s", name);
|
||||
|
||||
File* stream = fileOpenDirect(buildDataPath(mapperTempRoot(), relativePath), "wb");
|
||||
if (stream != nullptr) {
|
||||
fileWrite(toolbar_info, sizeof(ToolbarInfo), 6, stream);
|
||||
fileClose(stream);
|
||||
@@ -2359,7 +2376,7 @@ void update_toolname(int* pid, int type, int id)
|
||||
switch (PID_TYPE(proto->pid)) {
|
||||
case OBJ_TYPE_ITEM:
|
||||
windowDrawText(tool_win,
|
||||
gItemTypeNames[proto->item.type],
|
||||
item_pro_type[proto->item.type],
|
||||
kToolNameWidth,
|
||||
kToolNameX,
|
||||
kToolNameY2,
|
||||
@@ -2713,12 +2730,18 @@ int mapper_mark_exit_grid()
|
||||
// and on editor shutdown if the user quit while still in play mode.
|
||||
static void mapper_remove_tmp_map_files()
|
||||
{
|
||||
remove(mapBuildSavePath(kTmpMapName));
|
||||
remove(mapBuildSavePath("TMP$MAP#.EDG"));
|
||||
char path[COMPAT_MAX_PATH];
|
||||
|
||||
// The play-mode snapshot (.MAP/.EDG) and its toolbar .CFG are all mapper-only
|
||||
// temp artifacts living under the temp root.
|
||||
const char* tempRoot = mapperTempRoot();
|
||||
snprintf(path, sizeof(path), "%s\\MAPS\\%s", tempRoot, kTmpMapName);
|
||||
remove(path);
|
||||
snprintf(path, sizeof(path), "%s\\MAPS\\TMP$MAP#.EDG", tempRoot);
|
||||
remove(path);
|
||||
snprintf(path, sizeof(path), "%s\\MAPS\\TMP$MAP#.CFG", tempRoot);
|
||||
remove(path);
|
||||
|
||||
char cfgPath[COMPAT_MAX_PATH];
|
||||
snprintf(cfgPath, sizeof(cfgPath), "%s\\MAPS\\TMP$MAP#.CFG", settings.system.master_patches_path.c_str());
|
||||
remove(cfgPath);
|
||||
MapDirErase("MAPS\\", "SAV");
|
||||
}
|
||||
|
||||
@@ -2751,10 +2774,11 @@ static void mapper_enter_play_mode(Object** pHlObj1)
|
||||
|
||||
map_toggle_block_obj_viewing(0);
|
||||
|
||||
// Save current map under the temp name so we can restore on exit.
|
||||
// Save current map under the temp name (to the temp root) so we can restore
|
||||
// it on exit. This is mapper-only state, kept out of the dev_path mod folder.
|
||||
strncpy(gMapHeader.name, kTmpMapName, sizeof(gMapHeader.name) - 1);
|
||||
gMapHeader.name[sizeof(gMapHeader.name) - 1] = '\0';
|
||||
_map_save();
|
||||
mapSaveToRoot(mapperTempRoot());
|
||||
|
||||
objectSetLocation(gDude, savedCenterTile, gElevation, nullptr);
|
||||
|
||||
|
||||
+2758
-108
File diff suppressed because it is too large
Load Diff
+13
-14
@@ -8,6 +8,7 @@
|
||||
#include "mapper/mp_proto.h"
|
||||
#include "memory.h"
|
||||
#include "proto.h"
|
||||
#include "settings.h"
|
||||
#include "window_manager_private.h"
|
||||
|
||||
namespace fallout {
|
||||
@@ -25,15 +26,9 @@ typedef struct TargetList {
|
||||
int next_tid;
|
||||
} TargetList;
|
||||
|
||||
// 0x53F354
|
||||
static char default_target_path_base[] = "\\fallout2\\dev\\proto\\";
|
||||
|
||||
// 0x559CC4
|
||||
static TargetList targetlist = { NULL, 0, 0 };
|
||||
|
||||
// 0x559CD0
|
||||
static char* target_path_base = default_target_path_base;
|
||||
|
||||
// 0x559DBC
|
||||
static bool tgt_overriden = false;
|
||||
|
||||
@@ -59,18 +54,22 @@ bool target_overriden()
|
||||
return tgt_overriden;
|
||||
}
|
||||
|
||||
// 0x49B34C
|
||||
// Builds the mapper temp-root proto directory ("<temp>\proto\[<type>]"), creating
|
||||
// it on disk. For pid -1 the path keeps a trailing separator so callers can
|
||||
// append "target.dat"; otherwise it ends at the per-type folder.
|
||||
void target_make_path(char* path, int pid)
|
||||
{
|
||||
if (_cd_path_base[0] != '\0' && _cd_path_base[1] == ':') {
|
||||
strncpy(path, _cd_path_base, 2);
|
||||
strcat(path, target_path_base);
|
||||
} else {
|
||||
strcpy(path, target_path_base);
|
||||
}
|
||||
const char* root = mapperTempRoot();
|
||||
size_t rootLen = strlen(root);
|
||||
const char* separator = (rootLen > 0 && (root[rootLen - 1] == '\\' || root[rootLen - 1] == '/')) ? "" : "\\";
|
||||
|
||||
if (pid != -1) {
|
||||
strcat(path, artGetObjectTypeName(PID_TYPE(pid)));
|
||||
snprintf(path, COMPAT_MAX_PATH, "%s%sproto\\%s", root, separator, artGetObjectTypeName(PID_TYPE(pid)));
|
||||
compat_mkdir_recursive(path);
|
||||
} else {
|
||||
snprintf(path, COMPAT_MAX_PATH, "%s%sproto", root, separator);
|
||||
compat_mkdir_recursive(path);
|
||||
strcat(path, "\\");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#include "mapper/mp_utils.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "art.h"
|
||||
#include "color.h"
|
||||
#include "text_font.h"
|
||||
#include "window_manager_private.h"
|
||||
@@ -21,4 +24,16 @@ void mapperShowMessage(const char* msg)
|
||||
_win_msg(msg, 80, 80, _colorTable[31744] | FONT_SHADOW);
|
||||
}
|
||||
|
||||
void art_name_no_ext(int fid, char* buf)
|
||||
{
|
||||
if (art_list_str(fid, buf) == -1) {
|
||||
strcpy(buf, "None");
|
||||
} else {
|
||||
char* pch = strchr(buf, '.');
|
||||
if (pch != nullptr) {
|
||||
*pch = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -7,6 +7,9 @@ void mapperShowTimedMsg(const char* msg);
|
||||
bool mapperYesNoDialog(const char* msg);
|
||||
void mapperShowMessage(const char* msg);
|
||||
|
||||
// Resolves an art FID to its filename without extension, falling back to "None".
|
||||
void art_name_no_ext(int fid, char* buf);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* FALLOUT_MAPPER_MP_UTILS_H_ */
|
||||
|
||||
@@ -297,6 +297,44 @@ err:
|
||||
return success;
|
||||
}
|
||||
|
||||
// message_insert
|
||||
bool message_insert(MessageList* msg, MessageListItem* entry)
|
||||
{
|
||||
if (msg == nullptr || entry == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return _message_add(msg, entry);
|
||||
}
|
||||
|
||||
// message_save
|
||||
bool message_save(MessageList* msg, const char* path)
|
||||
{
|
||||
if (msg == nullptr || path == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char localized_path[COMPAT_MAX_PATH];
|
||||
snprintf(localized_path, sizeof(localized_path), "%s\\%s\\%s", "text", settings.system.language.c_str(), path);
|
||||
|
||||
File* stream = fileOpen(localized_path, "wt");
|
||||
if (stream == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int index = 0; index < msg->entries_num; index++) {
|
||||
MessageListItem* entry = &(msg->entries[index]);
|
||||
filePrintFormatted(stream, "%c%d%c%c%s%c%c%s%c\n",
|
||||
'{', entry->num, '}',
|
||||
'{', entry->audio, '}',
|
||||
'{', entry->text, '}');
|
||||
}
|
||||
|
||||
fileClose(stream);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x484C30 message_search
|
||||
bool messageListGetItem(MessageList* msg, MessageListItem* entry)
|
||||
{
|
||||
|
||||
@@ -77,6 +77,8 @@ void badwordsExit();
|
||||
bool messageListInit(MessageList* msg);
|
||||
bool messageListFree(MessageList* msg);
|
||||
bool messageListLoad(MessageList* msg, const char* path);
|
||||
bool message_insert(MessageList* msg, MessageListItem* entry);
|
||||
bool message_save(MessageList* msg, const char* path);
|
||||
bool messageListGetItem(MessageList* msg, MessageListItem* entry);
|
||||
bool _message_make_path(char* dest, size_t size, const char* path);
|
||||
char* getmsg(MessageList* msg, MessageListItem* entry, int num);
|
||||
|
||||
+121
-32
@@ -34,7 +34,6 @@ static int protoRead(Proto* buf, File* stream);
|
||||
static int protoItemDataWrite(ItemProtoData* item_data, int type, File* stream);
|
||||
static int protoSceneryDataWrite(SceneryProtoData* scenery_data, int type, File* stream);
|
||||
static int protoWrite(Proto* buf, File* stream);
|
||||
static int _proto_load_pid(int pid, Proto** out_proto);
|
||||
static int _proto_find_free_subnode(int type, Proto** out_ptr);
|
||||
static void _proto_remove_some_list(int type);
|
||||
static void _proto_remove_list(int type);
|
||||
@@ -119,19 +118,19 @@ static int _init_true = 0;
|
||||
static int _retval = 0;
|
||||
|
||||
// 0x66452C mp_perk_code_None
|
||||
static char* _mp_perk_code_None;
|
||||
char* _mp_perk_code_None;
|
||||
|
||||
// 0x664530 mp_perk_code_strs
|
||||
static char* _mp_perk_code_strs[PERK_COUNT];
|
||||
char* _mp_perk_code_strs[PERK_COUNT];
|
||||
|
||||
// 0x66470C mp_critter_stats_list
|
||||
static char* _mp_critter_stats_list;
|
||||
char* _mp_critter_stats_list;
|
||||
|
||||
// 0x664710 critter_stats_list_None
|
||||
static char* _critter_stats_list_None;
|
||||
char* _critter_stats_list_None;
|
||||
|
||||
// 0x664714 critter_stats_list_strs
|
||||
static char* _critter_stats_list_strs[STAT_COUNT];
|
||||
char* _critter_stats_list_strs[STAT_COUNT];
|
||||
|
||||
// Message list by object type
|
||||
// 0 - pro_item.msg
|
||||
@@ -142,13 +141,13 @@ static char* _critter_stats_list_strs[STAT_COUNT];
|
||||
// 5 - pro_misc.msg
|
||||
//
|
||||
// 0x6647AC proto_msg_files
|
||||
static MessageList _proto_msg_files[6];
|
||||
MessageList _proto_msg_files[6];
|
||||
|
||||
// 0x6647DC race_type_strs
|
||||
static char* gRaceTypeNames[RACE_TYPE_COUNT];
|
||||
|
||||
// 0x6647E4 scenery_pro_type
|
||||
static char* gSceneryTypeNames[SCENERY_TYPE_COUNT];
|
||||
char* gSceneryTypeNames[SCENERY_TYPE_COUNT];
|
||||
|
||||
// proto.msg
|
||||
//
|
||||
@@ -156,34 +155,34 @@ static char* gSceneryTypeNames[SCENERY_TYPE_COUNT];
|
||||
MessageList gProtoMessageList;
|
||||
|
||||
// 0x664804 item_pro_material
|
||||
static char* gMaterialTypeNames[MATERIAL_TYPE_COUNT];
|
||||
char* gMaterialTypeNames[MATERIAL_TYPE_COUNT];
|
||||
|
||||
// "<None>" from proto.msg
|
||||
//
|
||||
// 0x664824 proto_none_str
|
||||
char* _proto_none_str;
|
||||
char* proto_none_str;
|
||||
|
||||
// 0x664828 body_type_strs
|
||||
static char* gBodyTypeNames[BODY_TYPE_COUNT];
|
||||
char* body_type_strs[BODY_TYPE_COUNT];
|
||||
|
||||
// 0x664834 item_pro_type
|
||||
char* gItemTypeNames[ITEM_TYPE_COUNT];
|
||||
char* item_pro_type[ITEM_TYPE_COUNT];
|
||||
|
||||
// 0x66484C
|
||||
static char* gDamageTypeNames[DAMAGE_TYPE_COUNT];
|
||||
char* gDamageTypeNames[DAMAGE_TYPE_COUNT];
|
||||
|
||||
// 0x66486C cal_type_strs
|
||||
static char* gCaliberTypeNames[CALIBER_TYPE_COUNT];
|
||||
char* cal_type_strs[CALIBER_TYPE_COUNT];
|
||||
|
||||
// Perk names.
|
||||
//
|
||||
// 0x6648B8 perk_code_strs
|
||||
static char** _perk_code_strs;
|
||||
static char** perk_code_strs;
|
||||
|
||||
// Stat names.
|
||||
//
|
||||
// 0x6648BC critter_stats_list
|
||||
static char** _critter_stats_list;
|
||||
static char** critter_stats_list;
|
||||
|
||||
// 0x49E270 proto_make_path
|
||||
void proto_make_path(char* path, int pid)
|
||||
@@ -334,7 +333,7 @@ int _proto_action_can_pickup(int pid)
|
||||
// 0x49EAA4 proto_get_msg_info
|
||||
char* protoGetMessage(int pid, int message)
|
||||
{
|
||||
char* messageText = _proto_none_str;
|
||||
char* messageText = proto_none_str;
|
||||
|
||||
Proto* proto;
|
||||
if (protoGetProto(pid, &proto) != -1) {
|
||||
@@ -1388,7 +1387,7 @@ int protoInit()
|
||||
}
|
||||
|
||||
_mp_critter_stats_list = _aDrugStatSpecia;
|
||||
_critter_stats_list = _critter_stats_list_strs;
|
||||
critter_stats_list = _critter_stats_list_strs;
|
||||
_critter_stats_list_None = _aNone_1;
|
||||
for (i = 0; i < STAT_COUNT; i++) {
|
||||
_critter_stats_list_strs[i] = statGetName(i);
|
||||
@@ -1399,7 +1398,7 @@ int protoInit()
|
||||
}
|
||||
|
||||
_mp_perk_code_None = _aNone_1;
|
||||
_perk_code_strs = _mp_perk_code_strs;
|
||||
perk_code_strs = _mp_perk_code_strs;
|
||||
for (i = 0; i < PERK_COUNT; i++) {
|
||||
_mp_perk_code_strs[i] = perkGetName(i);
|
||||
if (_mp_perk_code_strs[i] == nullptr) {
|
||||
@@ -1420,7 +1419,7 @@ int protoInit()
|
||||
return -1;
|
||||
}
|
||||
|
||||
_proto_none_str = getmsg(&gProtoMessageList, &messageListItem, 10);
|
||||
proto_none_str = getmsg(&gProtoMessageList, &messageListItem, 10);
|
||||
|
||||
// material type names
|
||||
for (i = 0; i < MATERIAL_TYPE_COUNT; i++) {
|
||||
@@ -1429,7 +1428,7 @@ int protoInit()
|
||||
|
||||
// item type names
|
||||
for (i = 0; i < ITEM_TYPE_COUNT; i++) {
|
||||
gItemTypeNames[i] = getmsg(&gProtoMessageList, &messageListItem, 150 + i);
|
||||
item_pro_type[i] = getmsg(&gProtoMessageList, &messageListItem, 150 + i);
|
||||
}
|
||||
|
||||
// scenery type names
|
||||
@@ -1444,7 +1443,7 @@ int protoInit()
|
||||
|
||||
// caliber types
|
||||
for (i = 0; i < CALIBER_TYPE_COUNT; i++) {
|
||||
gCaliberTypeNames[i] = getmsg(&gProtoMessageList, &messageListItem, 300 + i);
|
||||
cal_type_strs[i] = getmsg(&gProtoMessageList, &messageListItem, 300 + i);
|
||||
}
|
||||
|
||||
// race types
|
||||
@@ -1454,7 +1453,7 @@ int protoInit()
|
||||
|
||||
// body types
|
||||
for (i = 0; i < BODY_TYPE_COUNT; i++) {
|
||||
gBodyTypeNames[i] = getmsg(&gProtoMessageList, &messageListItem, 400 + i);
|
||||
body_type_strs[i] = getmsg(&gProtoMessageList, &messageListItem, 400 + i);
|
||||
}
|
||||
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_PROTO, &gProtoMessageList);
|
||||
@@ -1918,21 +1917,20 @@ static int protoWrite(Proto* proto, File* stream)
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 0x4A1B30 proto_save_pid
|
||||
int _proto_save_pid(int pid)
|
||||
// Writes the proto's binary .pro directly into <root>\proto\<type>\, bypassing
|
||||
// the xbase database so it lands in that exact folder.
|
||||
static int proto_save_pid_to_root(int pid, const char* root)
|
||||
{
|
||||
Proto* proto;
|
||||
if (protoGetProto(pid, &proto) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
char path[260];
|
||||
proto_make_path(path, pid);
|
||||
strcat(path, "\\");
|
||||
char relativePath[COMPAT_MAX_PATH];
|
||||
int len = snprintf(relativePath, sizeof(relativePath), "proto\\%s\\", artGetObjectTypeName(PID_TYPE(pid)));
|
||||
_proto_list_str(pid, relativePath + len);
|
||||
|
||||
_proto_list_str(pid, path + strlen(path));
|
||||
|
||||
File* stream = fileOpen(path, "wb");
|
||||
File* stream = fileOpenDirect(buildDataPath(root, relativePath), "wb");
|
||||
if (stream == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
@@ -1944,8 +1942,21 @@ int _proto_save_pid(int pid)
|
||||
return rc;
|
||||
}
|
||||
|
||||
// 0x4A1B30 proto_save_pid
|
||||
// Runtime/savegame save: protos go to the master patches path.
|
||||
int _proto_save_pid(int pid)
|
||||
{
|
||||
return proto_save_pid_to_root(pid, settings.system.master_patches_path.c_str());
|
||||
}
|
||||
|
||||
// Mapper editing save: edited protos are a shipped asset, saved to the edit root.
|
||||
int proto_save_pid_edit(int pid)
|
||||
{
|
||||
return proto_save_pid_to_root(pid, mapperEditRoot());
|
||||
}
|
||||
|
||||
// 0x4A1C3C proto_load_pid
|
||||
static int _proto_load_pid(int pid, Proto** protoPtr)
|
||||
int _proto_load_pid(int pid, Proto** protoPtr)
|
||||
{
|
||||
char path[COMPAT_MAX_PATH];
|
||||
proto_make_path(path, pid);
|
||||
@@ -2120,6 +2131,84 @@ void _proto_remove_all()
|
||||
}
|
||||
}
|
||||
|
||||
// Free the now-empty tail extent and make the preceding extent the new tail.
|
||||
static void _proto_drop_empty_tail(ProtoList* protoList)
|
||||
{
|
||||
protoList->length--;
|
||||
internal_free(protoList->tail);
|
||||
|
||||
if (protoList->length == 0) {
|
||||
protoList->head = nullptr;
|
||||
protoList->tail = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
ProtoListExtent* prev = protoList->head;
|
||||
while (prev->next != protoList->tail) {
|
||||
prev = prev->next;
|
||||
}
|
||||
prev->next = nullptr;
|
||||
protoList->tail = prev;
|
||||
}
|
||||
|
||||
// proto_remove
|
||||
void proto_remove(int pid)
|
||||
{
|
||||
if (pid == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
int type = PID_TYPE(pid);
|
||||
if (type >= 11) {
|
||||
return;
|
||||
}
|
||||
|
||||
ProtoList* protoList = &(_protoLists[type]);
|
||||
|
||||
ProtoListExtent* extent = protoList->head;
|
||||
int index = 0;
|
||||
while (extent != nullptr) {
|
||||
for (index = 0; index < extent->length; index++) {
|
||||
if (extent->proto[index]->pid == pid) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (index < extent->length) {
|
||||
break;
|
||||
}
|
||||
extent = extent->next;
|
||||
}
|
||||
|
||||
if (extent == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
internal_free(extent->proto[index]);
|
||||
extent->proto[index] = nullptr;
|
||||
|
||||
ProtoListExtent* tail = protoList->tail;
|
||||
if (extent == tail && index + 1 == tail->length) {
|
||||
tail->length--;
|
||||
if (tail->length == 0) {
|
||||
_proto_drop_empty_tail(protoList);
|
||||
}
|
||||
} else {
|
||||
tail->length--;
|
||||
extent->proto[index] = tail->proto[tail->length];
|
||||
if (tail->length != 0) {
|
||||
tail->proto[tail->length] = nullptr;
|
||||
} else {
|
||||
_proto_drop_empty_tail(protoList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// proto_header_save
|
||||
int proto_header_save()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// proto_ptr
|
||||
// 0x4A2108 proto_ptr
|
||||
int protoGetProto(int pid, Proto** protoPtr)
|
||||
|
||||
+18
-2
@@ -4,6 +4,7 @@
|
||||
#include "db.h"
|
||||
#include "message.h"
|
||||
#include "obj_types.h"
|
||||
#include "perk_defs.h"
|
||||
#include "platform_compat.h"
|
||||
#include "proto_types.h"
|
||||
|
||||
@@ -100,8 +101,19 @@ typedef enum PrototypeMessage {
|
||||
extern char _cd_path_base[COMPAT_MAX_PATH];
|
||||
|
||||
extern MessageList gProtoMessageList;
|
||||
extern char* _proto_none_str;
|
||||
extern char* gItemTypeNames[ITEM_TYPE_COUNT];
|
||||
extern MessageList _proto_msg_files[6];
|
||||
extern char* proto_none_str;
|
||||
extern char* item_pro_type[ITEM_TYPE_COUNT];
|
||||
extern char* gMaterialTypeNames[MATERIAL_TYPE_COUNT];
|
||||
extern char* gSceneryTypeNames[SCENERY_TYPE_COUNT];
|
||||
extern char* gDamageTypeNames[DAMAGE_TYPE_COUNT];
|
||||
extern char* body_type_strs[BODY_TYPE_COUNT];
|
||||
extern char* cal_type_strs[CALIBER_TYPE_COUNT];
|
||||
extern char* _mp_perk_code_strs[PERK_COUNT];
|
||||
extern char* _mp_perk_code_None;
|
||||
extern char* _mp_critter_stats_list;
|
||||
extern char* _critter_stats_list_None;
|
||||
extern char* _critter_stats_list_strs[];
|
||||
|
||||
void proto_make_path(char* path, int pid);
|
||||
int _proto_list_str(int pid, char* proto_path);
|
||||
@@ -134,11 +146,15 @@ int protoInit();
|
||||
void protoReset();
|
||||
void protoExit();
|
||||
int _proto_save_pid(int pid);
|
||||
int proto_save_pid_edit(int pid);
|
||||
int proto_new(int* pid, int type);
|
||||
void _proto_remove_all();
|
||||
int protoGetProto(int pid, Proto** protoPtr);
|
||||
int _ResetPlayer();
|
||||
int proto_max_id(int type);
|
||||
void proto_remove(int pid);
|
||||
int proto_header_save();
|
||||
int _proto_load_pid(int pid, Proto** protoPtr);
|
||||
|
||||
static bool isExitGridPid(int pid)
|
||||
{
|
||||
|
||||
@@ -266,7 +266,7 @@ int objectExamineFunc(Object* critter, Object* target, void (*fn)(const char* st
|
||||
|
||||
if (!scriptOverrides) {
|
||||
char* description = objectGetDescription(target);
|
||||
if (description != nullptr && strcmp(description, _proto_none_str) == 0) {
|
||||
if (description != nullptr && strcmp(description, proto_none_str) == 0) {
|
||||
description = nullptr;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user