mirror of
https://github.com/fallout2-ce/fallout2-ce.git
synced 2026-07-27 16:47:11 -07:00
Compare commits
16
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
27805a6c90 | ||
|
|
74769044a6 | ||
|
|
a3f66539fb | ||
|
|
ff75e13430 | ||
|
|
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"
|
||||
@@ -626,6 +628,8 @@ if((NOT ANDROID) AND (NOT IOS) AND (NOT CMAKE_SYSTEM_NAME MATCHES "Emscripten"))
|
||||
"src/mapper/mp_proto.h"
|
||||
"src/mapper/mp_scrpt.cc"
|
||||
"src/mapper/mp_scrpt.h"
|
||||
"src/mapper/mp_spray.cc"
|
||||
"src/mapper/mp_spray.h"
|
||||
"src/mapper/mp_targt.cc"
|
||||
"src/mapper/mp_targt.h"
|
||||
"src/mapper/mp_utils.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 */
|
||||
|
||||
+33
-55
@@ -287,7 +287,8 @@ void isoExit()
|
||||
// 0x481FB4
|
||||
void mapInit()
|
||||
{
|
||||
if (settings.system.executableIsMapper()) {
|
||||
bool isMapper = settings.system.executableIsMapper();
|
||||
if (isMapper) {
|
||||
_map_scroll_refresh = isoWindowRefreshRectMapper;
|
||||
}
|
||||
|
||||
@@ -304,7 +305,9 @@ void mapInit()
|
||||
|
||||
mapNewMap();
|
||||
tickersAdd(gameMouseRefresh);
|
||||
_gmouse_disable(0);
|
||||
if (!isMapper) {
|
||||
_gmouse_disable(0);
|
||||
}
|
||||
windowShow(gIsoWindow);
|
||||
|
||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_MAP, &gMapMessageList);
|
||||
@@ -723,38 +726,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 +1346,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.
|
||||
|
||||
+22
-65
@@ -18,6 +18,7 @@
|
||||
#include "kb.h"
|
||||
#include "map.h"
|
||||
#include "mapper/mapper.h"
|
||||
#include "mapper/mp_spray.h"
|
||||
#include "mapper/mp_utils.h"
|
||||
#include "memory.h"
|
||||
#include "mouse.h"
|
||||
@@ -284,7 +285,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 +293,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
|
||||
@@ -316,20 +317,6 @@ void map_clear_elevation()
|
||||
}
|
||||
}
|
||||
|
||||
static void showNotImplementedSprayToolMsg()
|
||||
{
|
||||
mapperShowTimedMsg("Spray-tile painting not implemented in CE.");
|
||||
}
|
||||
|
||||
// copy_spray_tile
|
||||
// TODO: porting this requires the spray-tool subsystem (pick_spray_tool / load_spray_tool /
|
||||
// draw_spray_to_win / get_max_spray_tool / `spinfo` global / `map_brush_size` global / a sizable
|
||||
// SprayTool data struct + .spr file I/O). Pending user direction before pulling that in.
|
||||
void copy_spray_tile()
|
||||
{
|
||||
showNotImplementedSprayToolMsg();
|
||||
}
|
||||
|
||||
// pick_hex
|
||||
int pickHex()
|
||||
{
|
||||
@@ -451,41 +438,18 @@ void placeTile(int pid, int fid)
|
||||
return;
|
||||
}
|
||||
|
||||
int newArt = fid & 0xFFF;
|
||||
int* squarePtr = &_square[gElevation]->field_0[squareTile];
|
||||
int oldValue = *squarePtr;
|
||||
|
||||
if (tileRoofIsVisible()) {
|
||||
int oldRoofFid = buildFid(OBJ_TYPE_TILE, (oldValue >> 16) & 0xFFF, 0, 0, 0);
|
||||
if (oldRoofFid == fid) {
|
||||
return;
|
||||
}
|
||||
|
||||
int oldRoofWord = oldValue >> 16;
|
||||
int roofRotation = (oldRoofWord & 0xF000) >> 12;
|
||||
int newRoofWord = roofRotation | newArt;
|
||||
*squarePtr = (newRoofWord << 16) | (oldValue & 0xFFFF);
|
||||
|
||||
int sx, sy;
|
||||
squareTileToRoofScreenXY(squareTile, &sx, &sy, gElevation);
|
||||
Rect rect = { sx, sy, sx + 80, sy + 36 };
|
||||
tileWindowRefreshRect(&rect, gElevation);
|
||||
} else {
|
||||
int oldFloorFid = buildFid(OBJ_TYPE_TILE, oldValue & 0xFFF, 0, 0, 0);
|
||||
if (oldFloorFid == fid) {
|
||||
return;
|
||||
}
|
||||
|
||||
int oldFloorWord = oldValue & 0xFFFF;
|
||||
int floorRotation = (oldFloorWord & 0xF000) >> 12;
|
||||
int newFloorWord = floorRotation | newArt;
|
||||
*squarePtr = (oldValue & 0xFFFF0000) | newFloorWord;
|
||||
|
||||
int sx, sy;
|
||||
squareTileToScreenXY(squareTile, &sx, &sy, gElevation);
|
||||
Rect rect = { sx, sy, sx + 80, sy + 36 };
|
||||
tileWindowRefreshRect(&rect, gElevation);
|
||||
if (!place_tile_at(fid, squareTile)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int sx, sy;
|
||||
if (tileRoofIsVisible()) {
|
||||
squareTileToRoofScreenXY(squareTile, &sx, &sy, gElevation);
|
||||
} else {
|
||||
squareTileToScreenXY(squareTile, &sx, &sy, gElevation);
|
||||
}
|
||||
Rect rect = { sx, sy, sx + 80, sy + 36 };
|
||||
tileWindowRefreshRect(&rect, gElevation);
|
||||
}
|
||||
|
||||
// mpMouseCheckScrolling
|
||||
@@ -660,8 +624,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 +719,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 +892,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;
|
||||
@@ -982,13 +946,6 @@ void mapper_flush_cache()
|
||||
artCacheFlush();
|
||||
}
|
||||
|
||||
// create_spray_tool
|
||||
// Original implementation just returns -1 (the spray-tool authoring path was disabled in the
|
||||
// shipped mapper). We keep the same disabled behavior.
|
||||
void create_spray_tool()
|
||||
{
|
||||
}
|
||||
|
||||
// File-scope constants used by mapper_shift_map_once and its helpers (file-scope so the
|
||||
// inner lambdas don't need to capture them — MSVC won't accept implicit capture of locals
|
||||
// with `[]` even if they're constexpr).
|
||||
@@ -1016,8 +973,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;
|
||||
|
||||
@@ -19,8 +19,6 @@ void map_load_dialog();
|
||||
void map_save_dialog();
|
||||
int map_save_as(const char* name);
|
||||
void map_get_name(char* buf);
|
||||
void create_spray_tool();
|
||||
void copy_spray_tile();
|
||||
// mode = 1 - enable, 0 - disable, -1 - toggle
|
||||
void map_toggle_block_obj_viewing(int mode);
|
||||
void map_clear_elevation();
|
||||
|
||||
+90
-46
@@ -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"
|
||||
@@ -38,6 +36,7 @@
|
||||
#include "mapper/mp_instance.h"
|
||||
#include "mapper/mp_proto.h"
|
||||
#include "mapper/mp_scrpt.h"
|
||||
#include "mapper/mp_spray.h"
|
||||
#include "mapper/mp_targt.h"
|
||||
#include "mapper/mp_text.h"
|
||||
#include "memory.h"
|
||||
@@ -266,6 +265,9 @@ static ToolbarInfo toolbar_info[6];
|
||||
// Currently highlighted art-slot index in the toolbar; -1 = none.
|
||||
static int tool_active = -1;
|
||||
|
||||
// When set, the next toolbar proto click swaps that proto with the active one.
|
||||
static int mapper_copy_proto = 0;
|
||||
|
||||
// Color (palette index) used to draw the selection box around the active slot.
|
||||
static int toolbar_selection_color = 21;
|
||||
|
||||
@@ -565,7 +567,6 @@ constexpr int kBtnMenuHeaderLibrarian = KEY_ALT_J;
|
||||
constexpr int kBtnMenuHeaderSettings = KEY_ALT_X;
|
||||
|
||||
constexpr int kBtnPlayMode = KEY_F8;
|
||||
constexpr int kBtnRebuildProtoList = KEY_F10;
|
||||
constexpr int kBtnF8AsGame = KEY_CTRL_F12;
|
||||
|
||||
constexpr int kBtnMoveMapElev = 4186;
|
||||
@@ -639,21 +640,20 @@ constexpr int kBtnToggleInterruptWalk = KEY_ALT_R;
|
||||
constexpr int kBtnRotation0 = KEY_CTRL_ARROW_UP;
|
||||
constexpr int kBtnRotation3 = KEY_CTRL_ARROW_DOWN;
|
||||
constexpr int kBtnDestroyAllScripts = KEY_UPPERCASE_A;
|
||||
constexpr int kBtnRebuildSprayTools = 0x143;
|
||||
constexpr int kBtnDestroyProtoList = 0x185;
|
||||
constexpr int kBtnHighlightByProto = 0x123;
|
||||
constexpr int kBtnAnimDebugStep = 0x12E;
|
||||
|
||||
// LIBRARIAN menu pulldown keycodes
|
||||
constexpr int kBtnLibrarianRebuildAll = 5545;
|
||||
constexpr int kBtnLibrarianRebuildBinary = 5546;
|
||||
constexpr int kBtnLibrarianArtToProtos = 5547;
|
||||
constexpr int kBtnLibrarianSwapProtos = 5548;
|
||||
// LIBRARIAN menu pulldown keycodes (positionally matched to menu_3 / menu_val_3)
|
||||
constexpr int kBtnRebuildSprayTools = 0x143; // 323 — "Rebuild Weapons" (rebuilds spray tools)
|
||||
constexpr int kBtnRebuildProtoList = KEY_F10; // 324 — "Rebuild Proto List"
|
||||
constexpr int kBtnDestroyProtoList = 0x185; // 389 — "Rebuild ALL"
|
||||
constexpr int kBtnBuildAllTypeBinary = 6123; // 0x17EB — "Rebuild Binary"
|
||||
constexpr int kBtnLibrarianArtToProtos = KEY_QUESTION; // 63 — "Art => New Protos"
|
||||
constexpr int kBtnLibrarianSwapProtos = KEY_BRACE_RIGHT; // 125 — "Swap Prototypes"
|
||||
|
||||
// Direct-key bindings restored from the original mapper switch.
|
||||
constexpr int kBtnAutomap = KEY_TAB; // 9 — Automap (uses existing automapShow)
|
||||
constexpr int kBtnBookmarkChoose = 7777; // UI — Bookmark choose dialog (existing bookmarkChoose)
|
||||
constexpr int kBtnBuildAllTypeBinary = 6123; // UI — Build all type binary (proto_build_all_type_binary)
|
||||
|
||||
constexpr int kArtMaxDirect = 0x4B0;
|
||||
|
||||
@@ -734,8 +734,8 @@ void MapperInit()
|
||||
|
||||
menu_val_3[0] = kBtnRebuildSprayTools;
|
||||
menu_val_3[1] = kBtnRebuildProtoList;
|
||||
menu_val_3[2] = kBtnLibrarianRebuildAll;
|
||||
menu_val_3[3] = kBtnLibrarianRebuildBinary;
|
||||
menu_val_3[2] = kBtnDestroyProtoList;
|
||||
menu_val_3[3] = kBtnBuildAllTypeBinary;
|
||||
menu_val_3[4] = KEY_ESCAPE;
|
||||
menu_val_3[5] = kBtnLibrarianArtToProtos;
|
||||
menu_val_3[6] = kBtnLibrarianSwapProtos;
|
||||
@@ -776,6 +776,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];
|
||||
@@ -788,6 +803,8 @@ static void initMenuBar(const int screenWidth)
|
||||
_win_register_menu_pulldown(menu_bar, 80, "SCRIPTS", kBtnMenuHeaderScripts, 8, menu_names[2], foregroundColor, backgroundColor);
|
||||
_win_register_menu_pulldown(menu_bar, 130, "SETTINGS", kBtnMenuHeaderSettings, 3, menu_names[4], foregroundColor, backgroundColor);
|
||||
if (can_modify_protos) {
|
||||
// Count is 7 (vs the original's 6): the original hid the trailing "Swap
|
||||
// Prototypes" entry, but CE wires it up (arms swap mode), so it is shown.
|
||||
_win_register_menu_pulldown(menu_bar, 180, "LIBRARIAN", kBtnMenuHeaderLibrarian, 7, menu_names[3], foregroundColor, backgroundColor);
|
||||
}
|
||||
}
|
||||
@@ -1011,6 +1028,7 @@ int mapper_edit_init(int argc, char** argv)
|
||||
target_init();
|
||||
mouseShowCursor();
|
||||
mapperValidateDevPath();
|
||||
mapperMountDevTempPath();
|
||||
mapEdgeSetupInit();
|
||||
mapEdgeSetMapperMode(true);
|
||||
|
||||
@@ -1457,6 +1475,29 @@ void edit_mapper()
|
||||
|
||||
if (map_entered) continue;
|
||||
|
||||
// Swap mode (armed by "Swap Prototypes"): swap the clicked proto with
|
||||
// the active one, then clear the mode and toolbar selection.
|
||||
if (mapper_copy_proto == 1) {
|
||||
mapper_copy_proto = 0;
|
||||
if (!settings.mapper.use_art_not_protos && tool_active != -1) {
|
||||
int pid1 = toolbar_proto(currentType, scrollOffset + tool_active);
|
||||
if (pid1 != -1) {
|
||||
int pid2 = toolbar_proto(currentType, scrollOffset + (keyCode - rightBase));
|
||||
if (map_proto_swap_proto(pid1, pid2) == -1) {
|
||||
mapperShowTimedMsg("Error Swapping protos!");
|
||||
}
|
||||
tool_active = -1;
|
||||
selectedPid = -1;
|
||||
draw_mode = false;
|
||||
mapper_destroy_highlight_obj(&hl_obj1, nullptr);
|
||||
_screen_obj = nullptr;
|
||||
gameMouseResetBouncingCursorFid();
|
||||
update_art(currentType, scrollOffset);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!settings.mapper.use_art_not_protos) {
|
||||
int slotIndex = keyCode - rightBase;
|
||||
int pid = toolbar_proto(currentType, scrollOffset + slotIndex);
|
||||
@@ -2144,7 +2185,12 @@ void edit_mapper()
|
||||
if (map_entered) break;
|
||||
if (!can_modify_protos) break;
|
||||
if (mapperYesNoDialog("Do you REALLY want to rebuild spray tools?")) {
|
||||
rebuild_spray_tools();
|
||||
mapperShowTimedMsg("Please wait.");
|
||||
if (rebuild_spray_tools() == -1) {
|
||||
debugPrint("\nError: Rebuilding spray tools!");
|
||||
mapperShowTimedMsg("Error rebuilding spray tools!");
|
||||
}
|
||||
mapperShowTimedMsg("Done.");
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -2174,37 +2220,25 @@ void edit_mapper()
|
||||
}
|
||||
break;
|
||||
|
||||
// --- Librarian: Rebuild ALL ---
|
||||
case kBtnLibrarianRebuildAll:
|
||||
if (map_entered) break;
|
||||
if (!can_modify_protos) break;
|
||||
if (mapperYesNoDialog("Do you REALLY want to rebuild ALL?")) {
|
||||
_proto_remove_all();
|
||||
proto_build_all_texts();
|
||||
}
|
||||
break;
|
||||
|
||||
// --- Librarian: Rebuild Binary ---
|
||||
case kBtnLibrarianRebuildBinary:
|
||||
if (map_entered) break;
|
||||
if (!can_modify_protos) break;
|
||||
if (mapperYesNoDialog("Do you REALLY want to rebuild Binary?")) {
|
||||
rebuild_binary();
|
||||
}
|
||||
break;
|
||||
|
||||
// --- Librarian: Art => New Protos ---
|
||||
// Confirmed no-op in the original mapper: keycode 63 falls through to the
|
||||
// default (do-nothing) case and there is no backing implementation in the
|
||||
// original C/ASM. The menu item is kept for parity, but the handler is
|
||||
// disabled until/unless its intended behavior is recovered.
|
||||
case kBtnLibrarianArtToProtos:
|
||||
if (map_entered) break;
|
||||
if (!can_modify_protos) break;
|
||||
art_to_protos();
|
||||
// if (map_entered) break;
|
||||
// if (!can_modify_protos) break;
|
||||
// art_to_protos();
|
||||
break;
|
||||
|
||||
// --- Librarian: Swap Prototypes ---
|
||||
case kBtnLibrarianSwapProtos:
|
||||
if (map_entered) break;
|
||||
if (!can_modify_protos) break;
|
||||
swap_protos();
|
||||
// Original kc125 handler was a no-op (the mode flag was never set, leaving
|
||||
// map_proto_swap_proto unreachable). Wire the intended mode here.
|
||||
mapper_copy_proto = 1;
|
||||
mapperShowTimedMsg("Click a proto to swap with the active one.");
|
||||
break;
|
||||
|
||||
// --- Highlight object by proto ---
|
||||
@@ -2288,7 +2322,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 +2396,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 +2750,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 +2794,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);
|
||||
|
||||
|
||||
+2970
-126
File diff suppressed because it is too large
Load Diff
@@ -17,10 +17,10 @@ const char* proto_wall_light_str(int flags);
|
||||
int proto_pick_ai_packet(int* value);
|
||||
int proto_build_all_type(int type);
|
||||
int proto_build_all_type_binary(int type);
|
||||
void rebuild_spray_tools();
|
||||
void rebuild_binary();
|
||||
void art_to_protos();
|
||||
void swap_protos();
|
||||
// Confirmed no-op in the original mapper (keycode 63 falls through to default);
|
||||
// kept commented out, see mp_proto.cc.
|
||||
// void art_to_protos();
|
||||
int map_proto_swap_proto(int pid1, int pid2);
|
||||
int protoEdit(int protoId);
|
||||
int protoChooseMultiPids(int pidType, protoChooseFidCallback fidFunc, protoChooseAddCallback addFunc);
|
||||
// protoInstEdit moved to mp_instance.h
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,22 @@
|
||||
#ifndef FALLOUT_MAPPER_MP_SPRAY_H_
|
||||
#define FALLOUT_MAPPER_MP_SPRAY_H_
|
||||
|
||||
namespace fallout {
|
||||
|
||||
// Authoring path was disabled in the original mapper (the function just fails).
|
||||
void create_spray_tool();
|
||||
|
||||
// Pick a tile pattern and mouse-paint it onto the square tile grid.
|
||||
void copy_spray_tile();
|
||||
|
||||
// Rebuild all binary pattern (.spr) files from their text sources under the
|
||||
// mapper temp root. Returns -1 on failure. Dev-only: requires the text sources.
|
||||
int rebuild_spray_tools();
|
||||
|
||||
// Write a single floor/roof tile at an explicit square tile index (no refresh).
|
||||
// Returns true if the tile data actually changed.
|
||||
bool place_tile_at(int fid, int tileIndex);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* FALLOUT_MAPPER_MP_SPRAY_H_ */
|
||||
+159
-14
@@ -1,17 +1,48 @@
|
||||
#include "mapper/mp_targt.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "art.h"
|
||||
#include "color.h"
|
||||
#include "game.h"
|
||||
#include "map.h"
|
||||
#include "mapper/mp_proto.h"
|
||||
#include "memory.h"
|
||||
#include "platform_compat.h"
|
||||
#include "proto.h"
|
||||
#include "settings.h"
|
||||
#include "window_manager_private.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
// Target field-type names (text format), indexed by TargetSubNode::field_2C.
|
||||
static const char* const target_types[] = {
|
||||
"t_hex",
|
||||
"t_hex_offset",
|
||||
"rotation",
|
||||
"elevation",
|
||||
"t_object",
|
||||
"t_item",
|
||||
"t_scenery",
|
||||
"t_global_var",
|
||||
"t_local_var",
|
||||
"t_animation",
|
||||
"number",
|
||||
"string",
|
||||
"script",
|
||||
"yes-no",
|
||||
};
|
||||
|
||||
// Target placement names (text format), indexed by TargetSubNode::field_30.
|
||||
static const char* const target_placements[] = {
|
||||
"proto_inst_struct",
|
||||
"object_inst_struct",
|
||||
"global_var",
|
||||
"local_var",
|
||||
"scr_local_var",
|
||||
};
|
||||
|
||||
#define TARGET_DAT "target.dat"
|
||||
|
||||
typedef struct TargetNode {
|
||||
@@ -25,15 +56,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 +84,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, "\\");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,6 +269,122 @@ int target_load(int pid, TargetSubNode** subnode_ptr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Splits a "key: value" line in place: trims the newline, null-terminates the key at the
|
||||
// first ':', and returns the value with leading spaces skipped (or nullptr if no ':').
|
||||
static char* target_text_split(char* line)
|
||||
{
|
||||
char* nl = strchr(line, '\n');
|
||||
if (nl != NULL) {
|
||||
*nl = '\0';
|
||||
}
|
||||
|
||||
char* colon = strchr(line, ':');
|
||||
if (colon == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*colon = '\0';
|
||||
char* value = colon + 1;
|
||||
while (*value == ' ') {
|
||||
value++;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// Case-insensitive lookup of str in list[count]; returns index or -1.
|
||||
static int target_strlist_index(const char* str, const char* const* list, int count)
|
||||
{
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (compat_stricmp(str, list[i]) == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// target_load_text
|
||||
int target_load_text(int pid)
|
||||
{
|
||||
char path[COMPAT_MAX_PATH];
|
||||
target_make_path(path, pid);
|
||||
|
||||
size_t len = strlen(path);
|
||||
path[len] = '\\';
|
||||
_proto_list_str(pid, path + len + 1);
|
||||
|
||||
char* extension = strchr(path + len + 1, '.');
|
||||
if (extension != NULL) {
|
||||
strcpy(extension + 1, "tar");
|
||||
} else {
|
||||
strcat(path, ".tar");
|
||||
}
|
||||
|
||||
FILE* stream = fopen(path, "rt");
|
||||
if (stream == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
TargetSubNode* subnode;
|
||||
if (target_find_free_subnode(&subnode) == -1) {
|
||||
fclose(stream);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char line[120];
|
||||
while (fgets(line, sizeof(line), stream) != NULL) {
|
||||
char* value = target_text_split(line);
|
||||
if (value == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const char* key = line;
|
||||
if (strcmp(key, "pid") == 0) {
|
||||
subnode->pid = pid;
|
||||
} else if (strcmp(key, "tid") == 0) {
|
||||
sscanf(value, "%d", &subnode->tid);
|
||||
} else if (strcmp(key, "desc") == 0) {
|
||||
strcpy(reinterpret_cast<char*>(&subnode->field_8), value);
|
||||
} else if (strcmp(key, "next") == 0) {
|
||||
int hasNext = 0;
|
||||
sscanf(value, "%d", &hasNext);
|
||||
subnode->next = hasNext != 0 ? reinterpret_cast<TargetSubNode*>(1) : NULL;
|
||||
} else if (strcmp(key, "type") == 0) {
|
||||
int index = target_strlist_index(value, target_types, sizeof(target_types) / sizeof(target_types[0]));
|
||||
if (index != -1) {
|
||||
subnode->field_2C = index;
|
||||
}
|
||||
} else if (strcmp(key, "placement") == 0) {
|
||||
int index = target_strlist_index(value, target_placements, sizeof(target_placements) / sizeof(target_placements[0]));
|
||||
if (index != -1) {
|
||||
subnode->field_30 = index;
|
||||
}
|
||||
} else if (strcmp(key, "pmid") == 0) {
|
||||
sscanf(value, "%d", &subnode->field_34);
|
||||
} else if (strcmp(key, "flags") == 0) {
|
||||
sscanf(value, "%d", &subnode->field_38);
|
||||
} else if (strcmp(key, "where") == 0) {
|
||||
sscanf(value, "%d", &subnode->field_3C);
|
||||
} else if (strcmp(key, "v0") == 0) {
|
||||
sscanf(value, "%d", &subnode->field_44);
|
||||
} else if (strcmp(key, "------") == 0) {
|
||||
if (subnode->next != NULL) {
|
||||
subnode->next = (TargetSubNode*)internal_malloc(sizeof(TargetSubNode));
|
||||
if (subnode->next == NULL) {
|
||||
break;
|
||||
}
|
||||
subnode = subnode->next;
|
||||
}
|
||||
} else {
|
||||
char msg[80];
|
||||
snprintf(msg, sizeof(msg), "Load text as target error:\n\t=>%s", value);
|
||||
_win_msg(msg, 100, 100, _colorTable[31744] | 0x10000);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(stream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x49B9C0
|
||||
int target_find_free_subnode(TargetSubNode** subnode_ptr)
|
||||
{
|
||||
|
||||
@@ -55,6 +55,7 @@ int target_header_save();
|
||||
int target_header_load();
|
||||
int target_save(int pid);
|
||||
int target_load(int pid, TargetSubNode** subnode_ptr);
|
||||
int target_load_text(int pid);
|
||||
int target_find_free_subnode(TargetSubNode** subnode_ptr);
|
||||
int target_new(int pid, int* tid_ptr);
|
||||
int target_remove(int pid);
|
||||
|
||||
@@ -10,16 +10,16 @@
|
||||
|
||||
namespace fallout {
|
||||
|
||||
// 0x49DAC4
|
||||
// proto_build_all_texts
|
||||
int proto_build_all_texts()
|
||||
{
|
||||
for (int type = OBJ_TYPE_ITEM; type <= OBJ_TYPE_MISC; type++) {
|
||||
if (inputGetInput() == KEY_ESCAPE) {
|
||||
win_timed_msg("BUILD all Protos has been aborted!", _colorTable[32747] | 0x10000);
|
||||
_win_msg("BUILD all Protos has been aborted!", 150, 150, _colorTable[992] | 0x10000);
|
||||
return 0;
|
||||
}
|
||||
if (proto_build_all_type(type) == -1) {
|
||||
win_timed_msg("Build Text Error: Type Failed Build!", _colorTable[32747] | 0x10000);
|
||||
win_timed_msg("Build Text Error: Type Failed Build!", _colorTable[32767] | 0x10000);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user