Compare commits

..
Author SHA1 Message Date
Mike Klaas 1c6fa29292 WIP MAIN_MENU_PANEL_OFFSET_X/Y 2026-07-24 23:34:02 -07:00
19 changed files with 166 additions and 277 deletions
-9
View File
@@ -42,16 +42,7 @@ The following settings were moved into [`<DAT>/config/game.cfg`](files/ce.dat/co
| ddraw.ini section | ddraw.ini key | game.cfg section | game.cfg key |
| --- | --- | --- | --- |
| `Misc` | `StartingMap` | `start` | `map` |
| `Misc` | `StartXPos` | `start` | `worldmap_x` |
| `Misc` | `StartYPos` | `start` | `worldmap_y` |
| `Misc` | `ViewXPos` | `start` | `worldmap_view_x` |
| `Misc` | `ViewYPos` | `start` | `worldmap_view_y` |
| `Misc` | `StartGDialogFix` | `dialog` | `start_gdialog_fix` |
| `Misc` | `WorldMapFPSPatch` + `WorldMapDelay2` | `worldmap` | `travel_delay` |
Unlike sfall, `travel_delay` throttles only world-map travel simulation. Input,
rendering, and world-map scripts continue at the normal frame rate.
## Opcodes / Metarules
+3 -8
View File
@@ -11,12 +11,6 @@ month=6
day=24
; To start a new game somewhere other than artemple.map, set this to the map file name.
map=
; Starting worldmap marker position. -1 uses the starting map's world area.
worldmap_x=-1
worldmap_y=-1
; Starting worldmap viewport position. -1 uses the default upper-left view.
worldmap_view_x=-1
worldmap_view_y=-1
; Starting (tribal) and default (jumpsuit) player models. Can also be changed in-game via script.
model_male=hmwarr
model_male_default=hmjmps
@@ -61,6 +55,9 @@ big_font_color=0
; Pixel offset for main menu buttons.
offset_x=0
offset_y=0
; Pixel offset for the high resolution main menu button panel.
main_menu_panel_offset_x=16
main_menu_panel_offset_y=15
; Pixel offset for the copyright text line.
credits_offset_x=0
credits_offset_y=0
@@ -118,8 +115,6 @@ repair=293
[worldmap]
; Set to 1 to prevent using number keys to enter unvisited areas on a town map.
town_map_hotkeys_fix=1
; Milliseconds between world map travel updates (1-150). Set to 0 to update every rendered frame.
travel_delay=0
; Set to 1 to show travel markers on the world map, or 2 to show only when sneaking.
trail_markers=0
; Set to 1 to skip the encounter with Frank Horrigan.
-10
View File
@@ -165,16 +165,6 @@ main_menu_scale_mode=1
; Set to 1 to show a Help option in the in-game options menu which opens the F1 help screen.
in_game_menu_help=1
; Weight/size indicator for PC, critters and containers
; Set to 0 for vanilla behavior (no weight indicator)
; Set to 1 to show a simple weight indicator; works with all inventory_columns values
; Set to 2 to show a detailed weight indicator; works with inventory_columns > 1 only
loot_weight_indicator=1
; Set to 0 to show container indicator at all times
; Set to XX to show container indicator when size reaches XX%
; Set to 100 to show container indicator when full
loot_container_size_indicator_threshold=50
[qol]
; Automatically open doors that are unlocked and has no script attached.
+1 -3
View File
@@ -1789,13 +1789,11 @@ void FrmImage::resetInternal()
bool FrmImage::setFrame(const Art* art, int frame, int direction)
{
unsigned char* data = artGetFrameData(art, frame, direction, &_width, &_height, nullptr, nullptr);
unsigned char* data = artGetFrameData(art, frame, direction, &_width, &_height, &_xOffset, &_yOffset);
if (data == nullptr) {
return false;
}
_xOffset = art->xOffsets[direction];
_yOffset = art->yOffsets[direction];
_data = data;
return true;
}
+3 -2
View File
@@ -15,8 +15,9 @@ void contentConfigInit()
return;
}
// Try to migrate some settings from sfall.
// Try to migrate some settings from legacy config files.
contentConfigTryMigrateFromSfall(kConfigPatchPath);
contentConfigTryMigrateFromF2Res(kConfigPatchPath);
if (!configInit(&gContentConfig)) {
return;
@@ -35,4 +36,4 @@ void contentConfigExit()
configFree(&gContentConfig);
}
} // namespace fallout
} // namespace fallout
+100 -16
View File
@@ -1,6 +1,5 @@
#include "game_config_migration.h"
#include <algorithm>
#include <assert.h>
#include <stdio.h>
#include <string.h>
@@ -17,6 +16,8 @@ namespace fallout {
namespace {
#define F2_RES_CONFIG_FILE_NAME "f2_res.ini"
#define F2_RES_MAIN_MENU_BUTTON_X 30
#define F2_RES_MAIN_MENU_BUTTON_Y 19
struct F2ResMigrationEntry {
const char* legacySection;
@@ -30,6 +31,7 @@ namespace {
static bool gameConfigMigrateMainMenuScaleModeKey(Config* legacyConfig, Config* gameConfig);
static bool gameConfigMigrateStringKey(Config* legacyConfig, Config* gameConfig, const F2ResMigrationEntry& entry);
static bool gameConfigMigrateScaleKey(Config* legacyConfig, Config* gameConfig);
static bool contentConfigMigrateF2ResMainMenuPanelOffsetKey(Config* legacyConfig, Config* contentConfig, const char* legacyKey, const char* targetKey, int baseValue, int defaultValue);
static constexpr F2ResMigrationEntry kF2ResMigrationEntries[] = {
{ "MAIN", "SCR_WIDTH", GAME_CONFIG_SCREEN_KEY, GAME_CONFIG_RESOLUTION_X_KEY },
@@ -111,6 +113,27 @@ namespace {
return configSetInt(gameConfig, GAME_CONFIG_SCREEN_KEY, GAME_CONFIG_SCALE_KEY, value + 1);
}
static bool contentConfigMigrateF2ResMainMenuPanelOffsetKey(Config* legacyConfig, Config* contentConfig, const char* legacyKey, const char* targetKey, int baseValue, int defaultValue)
{
assert(legacyConfig != nullptr && contentConfig != nullptr);
if (gameConfigHasKey(contentConfig, CONTENT_CONFIG_MAIN_MENU_SECTION, targetKey)) {
return false;
}
int value;
if (!configGetInt(legacyConfig, "MAINMENU", legacyKey, &value)) {
return false;
}
value += baseValue;
if (value == defaultValue) {
return false;
}
return configSetInt(contentConfig, CONTENT_CONFIG_MAIN_MENU_SECTION, targetKey, value);
}
} // namespace
// Migrate settings F2_RES.INI to fallout2.cfg
@@ -176,10 +199,6 @@ namespace {
constexpr SfallMigrationEntry kSfallMigrationEntries[] = {
// [start]
{ kSfallMisc, "StartingMap", CONTENT_CONFIG_START_SECTION, "map", "" },
{ kSfallMisc, "StartXPos", CONTENT_CONFIG_START_SECTION, "worldmap_x", "-1" },
{ kSfallMisc, "StartYPos", CONTENT_CONFIG_START_SECTION, "worldmap_y", "-1" },
{ kSfallMisc, "ViewXPos", CONTENT_CONFIG_START_SECTION, "worldmap_view_x", "-1" },
{ kSfallMisc, "ViewYPos", CONTENT_CONFIG_START_SECTION, "worldmap_view_y", "-1" },
{ kSfallMisc, "MaleStartModel", CONTENT_CONFIG_START_SECTION, "model_male", "hmwarr" },
{ kSfallMisc, "MaleDefaultModel", CONTENT_CONFIG_START_SECTION, "model_male_default", "hmjmps" },
{ kSfallMisc, "FemaleStartModel", CONTENT_CONFIG_START_SECTION, "model_female", "hfprim" },
@@ -263,17 +282,6 @@ static bool contentConfigMigrateFromSfall(Config* sfallConfig, const char* conte
}
bool migrated = false;
bool worldMapFpsPatch;
if (configGetBool(sfallConfig, kSfallMisc, "WorldMapFPSPatch", &worldMapFpsPatch)
&& worldMapFpsPatch) {
int travelDelay = 66;
configGetInt(sfallConfig, kSfallMisc, "WorldMapDelay2", &travelDelay);
travelDelay = std::clamp(travelDelay, 1, 150);
configSetInt(&migratedConfig, CONTENT_CONFIG_WORLDMAP_SECTION, "travel_delay", travelDelay);
migrated = true;
}
// Migrate start year/month/day only when explicitly set (not the sfall -1 sentinel).
auto migrateStartInt = [&](const char* sfallKey, const char* targetKey, int defaultValue) {
int value;
@@ -317,6 +325,82 @@ static bool contentConfigMigrateFromSfall(Config* sfallConfig, const char* conte
return migrated;
}
static bool contentConfigEnsureDirectory(const char* contentConfigFilePath)
{
char drive[COMPAT_MAX_DRIVE];
char dirPart[COMPAT_MAX_DIR];
char pathWithoutFile[COMPAT_MAX_PATH];
compat_splitpath(contentConfigFilePath, drive, dirPart, nullptr, nullptr);
compat_makepath(pathWithoutFile, drive, dirPart, nullptr, nullptr);
return compat_mkdir_recursive(pathWithoutFile) == 0;
}
static bool contentConfigMigrateFromF2Res(Config* legacyConfig, const char* contentConfigFilePath)
{
assert(legacyConfig != nullptr && contentConfigFilePath != nullptr);
Config migratedConfig;
if (!configInit(&migratedConfig)) {
return false;
}
configRead(&migratedConfig, contentConfigFilePath, false);
bool migrated = false;
if (contentConfigMigrateF2ResMainMenuPanelOffsetKey(legacyConfig, &migratedConfig, "MENU_BG_OFFSET_X", "main_menu_panel_offset_x", F2_RES_MAIN_MENU_BUTTON_X, 16)) {
migrated = true;
}
if (contentConfigMigrateF2ResMainMenuPanelOffsetKey(legacyConfig, &migratedConfig, "MENU_BG_OFFSET_Y", "main_menu_panel_offset_y", F2_RES_MAIN_MENU_BUTTON_Y, 15)) {
migrated = true;
}
if (migrated) {
if (contentConfigEnsureDirectory(contentConfigFilePath)) {
if (!configWriteEx(&migratedConfig, contentConfigFilePath, CONFIG_RETAIN_ALL)) {
debugPrint("Failed to write migrated settings to %s!\n", contentConfigFilePath);
}
} else {
debugPrint("Failed to create directory for migrated settings at %s!\n", contentConfigFilePath);
}
}
configFree(&migratedConfig);
return migrated;
}
void contentConfigTryMigrateFromF2Res(const char* contentConfigPath)
{
const auto& masterPatches = settings.system.master_patches_path;
if (masterPatches.empty()) {
debugPrint("Failed to migrate from f2_res.ini: no master_patches is set.\n");
return;
}
if (!compat_is_dir(masterPatches.c_str())) {
return;
}
char f2ResFilePath[COMPAT_MAX_PATH];
char drive[COMPAT_MAX_DRIVE];
char dir[COMPAT_MAX_DIR];
compat_splitpath(gGameConfigFilePath, drive, dir, nullptr, nullptr);
compat_makepath(f2ResFilePath, drive, dir, F2_RES_CONFIG_FILE_NAME, nullptr);
Config legacyConfig;
if (!configInit(&legacyConfig)) {
return;
}
if (configRead(&legacyConfig, f2ResFilePath, false)) {
char contentCfgPath[COMPAT_MAX_PATH];
snprintf(contentCfgPath, sizeof(contentCfgPath), "%s\\%s", masterPatches.c_str(), contentConfigPath);
if (contentConfigMigrateFromF2Res(&legacyConfig, contentCfgPath)) {
debugPrint("Migrated settings from f2_res.ini to game.cfg.\n");
}
}
configFree(&legacyConfig);
}
void contentConfigTryMigrateFromSfall(const char* contentConfigPath)
{
if (!gSfallConfig.isInitialized() || gSfallConfig.entriesLength == 0) {
+1
View File
@@ -6,6 +6,7 @@
namespace fallout {
bool gameConfigMigrateFromF2Res(const char* gameConfigFilePath, Config* gameConfig);
void contentConfigTryMigrateFromF2Res(const char* contentConfigPath);
void contentConfigTryMigrateFromSfall(const char* contentConfigPath);
} // namespace fallout
-5
View File
@@ -3500,11 +3500,6 @@ int gameDialogGetWindow()
return windowGetWindow(gGameDialogWindow) != nullptr ? gGameDialogWindow : -1;
}
int gameDialogGetBackgroundWindow()
{
return windowGetWindow(gGameDialogBackgroundWindow) != nullptr ? gGameDialogBackgroundWindow : -1;
}
// 0x448660 gdialog_barter_cleanup_tables
void gameDialogBarterCleanupTables()
{
-1
View File
@@ -41,7 +41,6 @@ int gameDialogBarter(int modifier);
void gameDialogEndBarter();
bool gameDialogIsBarterWindowExpanded();
int gameDialogGetWindow();
int gameDialogGetBackgroundWindow();
} // namespace fallout
+12 -65
View File
@@ -5,7 +5,6 @@
#include <string.h>
#include <algorithm>
#include <cmath>
#include <string>
#include <utility>
@@ -926,31 +925,7 @@ static bool inventoryLootMouseHitTestScroller(bool targetInventory)
static void inventoryLootRenderPaneWeight(unsigned char* windowBuffer, int pitch, bool targetPane, Object* object, int extraWeight)
{
int loot_weight_indicator = settings.ui.loot_weight_indicator;
bool showLabel = inventoryLootLayout.columns > 1;
bool showDetailed = loot_weight_indicator == 2 && showLabel;
bool showSimple = loot_weight_indicator == 1 || (loot_weight_indicator == 2 && !showLabel);
if (!showDetailed && !showSimple) {
return;
}
int containerSizeThreshold = settings.ui.loot_container_size_indicator_threshold;
// Wt.
MessageListItem messageListItem;
messageListItem.num = 30;
if (showLabel) {
if (!messageListGetItem(&gInventoryMessageList, &messageListItem)) {
showSimple = true;
showDetailed = false;
showLabel = false;
}
}
char formattedText[30];
char formattedText[20];
formattedText[0] = '\0';
int oldFont = fontGetCurrent();
@@ -967,54 +942,26 @@ static void inventoryLootRenderPaneWeight(unsigned char* windowBuffer, int pitch
pitch);
}
int color = COLOR_WHITE;
int inventoryWeight = objectGetInventoryWeight(object);
int color = COLOR_GREEN;
if (PID_TYPE(object->pid) == OBJ_TYPE_CRITTER) {
int currentWeight = inventoryWeight + extraWeight;
int currentWeight = objectGetInventoryWeight(object) + extraWeight;
int maxWeight = critterGetStat(object, STAT_CARRY_WEIGHT);
int weightPercentage = maxWeight < 1 ? 0 : (int)std::ceil(currentWeight * 100 / (float)maxWeight);
if (showSimple) {
if (showLabel) {
snprintf(formattedText, sizeof(formattedText), "%s %d/%d", messageListItem.text, currentWeight, maxWeight);
} else {
snprintf(formattedText, sizeof(formattedText), "%d/%d", currentWeight, maxWeight);
}
} else if (showDetailed) {
snprintf(formattedText, sizeof(formattedText), "%s %d/%d (%d%%)", messageListItem.text, currentWeight, maxWeight, weightPercentage);
}
snprintf(formattedText, sizeof(formattedText), "%d/%d", currentWeight, maxWeight);
if (currentWeight > maxWeight) {
color = COLOR_RED;
}
} else if (targetPane && PID_TYPE(object->pid) == OBJ_TYPE_ITEM && itemGetType(object) == ITEM_TYPE_CONTAINER) {
int currentSize = containerGetTotalSize(object);
int maxSize = containerGetMaxSize(object);
int sizePercentage = maxSize < 1 ? 0 : (int)std::ceil(currentSize * 100 / (float)maxSize);
if (sizePercentage < containerSizeThreshold) {
fontSetCurrent(oldFont);
return;
}
if (showSimple) {
snprintf(formattedText, sizeof(formattedText), "%d%%", sizePercentage);
} else if (showDetailed) {
snprintf(formattedText, sizeof(formattedText), "%s %d (%d%%)", messageListItem.text, inventoryWeight, sizePercentage);
}
snprintf(formattedText, sizeof(formattedText), "%d/%d", currentSize, maxSize);
} else {
if (showLabel) {
snprintf(formattedText, sizeof(formattedText), "%s %d", messageListItem.text, inventoryWeight);
} else {
snprintf(formattedText, sizeof(formattedText), "%d", inventoryWeight);
}
int inventoryWeight = objectGetInventoryWeight(object);
snprintf(formattedText, sizeof(formattedText), "%d", inventoryWeight);
}
if (strlen(formattedText) > 0) {
int x = targetPane ? inventoryLootLayout.rightScrollerX : inventoryLootLayout.leftScrollerX;
int y = (targetPane ? inventoryLootLayout.rightScrollerY : inventoryLootLayout.leftScrollerY) + inventoryLootLayout.scrollerHeight + 2;
inventoryDrawCenteredText(windowBuffer, pitch, inventoryLootLayout.scrollerWidth, x, y, formattedText, color);
}
int x = targetPane ? inventoryLootLayout.rightScrollerX : inventoryLootLayout.leftScrollerX;
int y = (targetPane ? inventoryLootLayout.rightScrollerY : inventoryLootLayout.leftScrollerY) + inventoryLootLayout.scrollerHeight + 2;
inventoryDrawCenteredText(windowBuffer, pitch, inventoryLootLayout.scrollerWidth, x, y, formattedText, color);
fontSetCurrent(oldFont);
}
@@ -4149,10 +4096,10 @@ static void displayLootPanePartyName(unsigned char* windowBuffer, int windowPitc
int oldFont = fontGetCurrent();
fontSetCurrent(101);
int nameY = rect.bottom - fontGetLineHeight();
int nameY = rect.bottom - fontGetLineHeight() - 2;
fontSetCurrent(oldFont);
inventoryDrawCenteredText(windowBuffer, windowPitch, INVENTORY_BODY_VIEW_WIDTH, rect.left, nameY, name, COLOR_WHITE);
inventoryDrawCenteredText(windowBuffer, windowPitch, INVENTORY_BODY_VIEW_WIDTH, rect.left, nameY, name, COLOR_GREEN);
}
// Displays item description.
-13
View File
@@ -331,19 +331,6 @@ static int _main_load_new(char* mapFileName)
gameMouseSetCursor(MOUSE_CURSOR_NONE);
mouseShowCursor();
mapLoadByName(mapFileName);
// SFALL: Fix the starting position of the player's marker on the world map
// when starting a new game with a custom starting map.
int areaIdx;
if (wmMatchAreaContainingMapIdx(gMapHeader.index, &areaIdx) == 0) {
if (wmStartWorldPosIsConfigured()) {
wmSetPartyCurArea(areaIdx);
wmClearPartyWalking();
} else {
wmTeleportToArea(areaIdx);
}
}
wmMapMusicStart();
paletteFadeTo(gPaletteWhite);
windowDestroy(win);
+6 -1
View File
@@ -305,8 +305,13 @@ static void mainMenuDrawPanel(const MainMenuLayout& layout, const MainMenuOffset
return;
}
int panelOffsetX = MAIN_MENU_PANEL_OFFSET_X;
int panelOffsetY = MAIN_MENU_PANEL_OFFSET_Y;
configGetInt(&gContentConfig, CONTENT_CONFIG_MAIN_MENU_SECTION, "main_menu_panel_offset_x", &panelOffsetX, MAIN_MENU_PANEL_OFFSET_X);
configGetInt(&gContentConfig, CONTENT_CONFIG_MAIN_MENU_SECTION, "main_menu_panel_offset_y", &panelOffsetY, MAIN_MENU_PANEL_OFFSET_Y);
Size panelSize = mainMenuTransformSize(layout, mainMenuButtonPanelFrmImage.getWidth(), mainMenuButtonPanelFrmImage.getHeight());
Point panelOrigin = mainMenuTransformPoint(layout, MAIN_MENU_PANEL_OFFSET_X, MAIN_MENU_PANEL_OFFSET_Y);
Point panelOrigin = mainMenuTransformPoint(layout, panelOffsetX, panelOffsetY);
blitBuffer2DScaledTrans(mainMenuButtonPanelFrmImage.getBuffer(),
Buffer2D(gMainMenuWindowBuffer, layout.screenWidth, layout.screenHeight),
+1 -1
View File
@@ -978,7 +978,7 @@ static int mapLoad(File* stream)
}
lightSetAmbientIntensity(LIGHT_INTENSITY_MAX, false);
objectSetLocation(gDude, gEnteringTile, gElevation, nullptr);
objectSetLocation(gDude, gCenterTile, gElevation, nullptr);
objectSetRotation(gDude, gEnteringRotation, nullptr);
gMapHeader.index = wmMapMatchNameToIdx(gMapHeader.name);
+2 -3
View File
@@ -501,14 +501,13 @@ int pipboyOpen(int intent)
return 0;
}
ScopedGameMode gm(GameMode::kPipboy);
intent = pipboyWindowInit(intent);
if (intent == -1) {
return -1;
}
ScopedGameMode gm(GameMode::kPipboy);
windowRefresh(gPipboyWindow);
touch_set_touchscreen_mode(true);
mouseGetPositionInWindow(gPipboyWindow, &gPipboyPreviousMouseX, &gPipboyPreviousMouseY);
-2
View File
@@ -172,8 +172,6 @@ void initSettingsRegistry(bool isMapper)
SETTING(extend_ap_bar);
SETTING(expand_barter_window);
SETTING_P(inventory_columns, clamp(1, 2));
SETTING_P(loot_weight_indicator, clamp(0, 2));
SETTING_P(loot_container_size_indicator_threshold, clamp(0, 100));
#undef SECT
#define SECT preferences
-10
View File
@@ -95,16 +95,6 @@ struct UISettings {
bool enable_high_resolution_stencil = true;
// Maximum number of columns in inventory and loot windows
int inventory_columns = 1;
// 0 - No indicator, vanilla
// 1 - Simple indicator
// 2 - Detailed indicator, works with inventory_columns > 1 only
int loot_weight_indicator = 1;
// 0 - Container indicator is always visible
// XX - Container indicator is visible when size reaches XX percent
// 100 - Container indicator is visible when fully loaded
int loot_container_size_indicator_threshold = 50;
};
// These are settings handled by preferences UI and saved in save games.
+32 -3
View File
@@ -958,7 +958,7 @@ static InterfaceWindowLookupResult getInterfaceWindowByType(int winType, int& wi
window = inventoryGetWindow();
break;
case 1:
window = gameDialogGetBackgroundWindow();
window = gameDialogGetWindow();
break;
case 2:
window = pipboyGetWindow();
@@ -989,6 +989,35 @@ static InterfaceWindowLookupResult getInterfaceWindowByType(int winType, int& wi
return window != -1 ? InterfaceWindowLookupResult::Found : InterfaceWindowLookupResult::Missing;
}
static int getCurrentInterfaceWindow()
{
int window = -1;
if (GameMode::isInGameMode(GameMode::kInventory)
|| GameMode::isInGameMode(GameMode::kUseOn)
|| GameMode::isInGameMode(GameMode::kLoot)
|| GameMode::isInGameMode(GameMode::kBarter)) {
window = inventoryGetWindow();
} else if (GameMode::isInGameMode(GameMode::kDialog)) {
window = gameDialogGetWindow();
} else if (GameMode::isInGameMode(GameMode::kPipboy)) {
window = pipboyGetWindow();
} else if (GameMode::isInGameMode(GameMode::kWorldmap)) {
window = worldmapGetWindow();
} else if (GameMode::isInGameMode(GameMode::kEditor)) {
window = characterEditorGetWindow();
} else if (GameMode::isInGameMode(GameMode::kSkilldex)) {
window = skilldexGetWindow();
} else if (GameMode::isInGameMode(GameMode::kOptions)) {
window = optionsGetWindow();
} else if (GameMode::isInGameMode(GameMode::kAutomap)) {
window = automapGetWindow();
} else if (windowGetWindow(gInterfaceBarWindow) != nullptr) {
window = gInterfaceBarWindow;
}
return window;
}
static bool clampWindowFillRect(int windowWidth, int windowHeight, int& x, int& y, int& width, int& height)
{
if (x < 0) {
@@ -1841,10 +1870,10 @@ void mf_set_window_flag(OpcodeContext& ctx)
int windowId = ctx.arg(0).asInt();
if (windowId <= 0) {
windowId = inventoryGetWindow();
windowId = getCurrentInterfaceWindow();
}
if (windowId == -1 || windowGetWindow(windowId) == nullptr) {
if (windowId == -1) {
return;
}
+5 -122
View File
@@ -480,10 +480,6 @@ static std::vector<std::pair<int, std::string>> wmTerrainNameOverrides;
static void wmSetFlags(int* flagsPtr, int flag, int value);
static int wmGenDataInit();
static int wmGenDataReset();
static void wmGenDataSetStartWorldPos();
static bool wmGetStartWorldMapConfigValue(const char* key, int* valuePtr);
static void wmGenDataClampWorldPosToBounds();
static void wmSetStartWorldView();
static int wmWorldMapSaveTempData();
static int wmWorldMapLoadTempData();
static int wmConfigInit();
@@ -541,7 +537,6 @@ static bool wmGameTimeIncrement(int ticksToAdd);
static int wmGrabTileWalkMask(int tileIdx);
static bool wmWorldPosInvalid(int x, int y);
static void wmPartyInitWalking(int x, int y);
static bool wmTravelTickDue(unsigned int now);
static void wmPartyWalkingStep();
static void wmInterfaceScrollTabsStart(int delta);
static void wmInterfaceScrollTabsStop();
@@ -944,8 +939,6 @@ static FrmImage _townFrmImage;
static bool wmFaded = false;
static int wmForceEncounterMapId = -1;
static unsigned int wmForceEncounterFlags = 0;
static int worldmapTravelDelay;
static unsigned int wmLastTravelTick;
static int worldmapTrailMarkers;
static inline bool cityIsValid(int city)
@@ -986,11 +979,8 @@ int wmWorldMap_init()
return -1;
}
wmGenDataClampWorldPosToBounds();
wmGenData.viewportMaxX = WM_TILE_WIDTH * wmNumHorizontalTiles - WM_VIEW_WIDTH;
wmGenData.viewportMaxY = WM_TILE_HEIGHT * (wmMaxTileNum / wmNumHorizontalTiles) - WM_VIEW_HEIGHT;
wmSetStartWorldView();
circleBlendTable = _getColorBlendTable(COLOR_GREEN);
wmMarkSubTileRadiusVisited(wmGenData.worldPosX, wmGenData.worldPosY);
@@ -998,8 +988,6 @@ int wmWorldMap_init()
// SFALL
configGetBool(&gContentConfig, CONTENT_CONFIG_WORLDMAP_SECTION, "town_map_hotkeys_fix", &gTownMapHotkeysFix, true);
configGetInt(&gContentConfig, CONTENT_CONFIG_WORLDMAP_SECTION, "travel_delay", &worldmapTravelDelay, 0);
worldmapTravelDelay = std::clamp(worldmapTravelDelay, 0, 150);
configGetInt(&gContentConfig, CONTENT_CONFIG_WORLDMAP_SECTION, "trail_markers", &worldmapTrailMarkers, 0);
// CE: City size fids should be initialized during startup. They are used
@@ -1021,7 +1009,8 @@ static int wmGenDataInit()
{
gDidMeetFrankHorrigan = false;
wmGenData.currentAreaId = -1;
wmGenDataSetStartWorldPos();
wmGenData.worldPosX = 173;
wmGenData.worldPosY = 122;
wmGenData.currentSubtile = nullptr;
wmGenData.dword_672E18 = 0;
wmGenData.isWalking = false;
@@ -1087,8 +1076,8 @@ static int wmGenDataReset()
wmGenData.encounterIconIsVisible = false;
mousePressed = false;
wmGenData.currentAreaId = -1;
wmGenDataSetStartWorldPos();
wmGenDataClampWorldPosToBounds();
wmGenData.worldPosX = 173;
wmGenData.worldPosY = 122;
wmGenData.walkDestinationX = -1;
wmGenData.walkDestinationY = -1;
wmGenData.encounterMapId = -1;
@@ -1124,70 +1113,6 @@ static int wmGenDataReset()
return 0;
}
static void wmGenDataSetStartWorldPos()
{
wmGenData.worldPosX = 173;
wmGenData.worldPosY = 122;
int value;
if (wmGetStartWorldMapConfigValue("worldmap_x", &value)) {
wmGenData.worldPosX = value;
}
if (wmGetStartWorldMapConfigValue("worldmap_y", &value)) {
wmGenData.worldPosY = value;
}
}
static bool wmGetStartWorldMapConfigValue(const char* key, int* valuePtr)
{
assert(key != nullptr);
assert(valuePtr != nullptr);
int value;
if (!configGetInt(&gContentConfig, CONTENT_CONFIG_START_SECTION, key, &value)) {
return false;
}
if (value == -1) {
return false;
}
*valuePtr = std::max(value, 0);
return true;
}
static void wmGenDataClampWorldPosToBounds()
{
if (wmNumHorizontalTiles <= 0 || wmMaxTileNum <= 0) {
return;
}
int worldMaxX = WM_TILE_WIDTH * wmNumHorizontalTiles;
int worldMaxY = WM_TILE_HEIGHT * (wmMaxTileNum / wmNumHorizontalTiles);
if (worldMaxX <= 0 || worldMaxY <= 0) {
return;
}
wmGenData.worldPosX = std::clamp(wmGenData.worldPosX, 0, worldMaxX - 1);
wmGenData.worldPosY = std::clamp(wmGenData.worldPosY, 0, worldMaxY - 1);
}
static void wmSetStartWorldView()
{
wmWorldOffsetX = 0;
wmWorldOffsetY = 0;
int value;
if (wmGetStartWorldMapConfigValue("worldmap_view_x", &value)) {
wmWorldOffsetX = std::clamp(value, 0, std::max(wmGenData.viewportMaxX, 0));
}
if (wmGetStartWorldMapConfigValue("worldmap_view_y", &value)) {
wmWorldOffsetY = std::clamp(value, 0, std::max(wmGenData.viewportMaxY, 0));
}
}
// 0x4BCE00 wmWorldMap_exit
void wmWorldMap_exit()
{
@@ -1252,7 +1177,6 @@ int wmWorldMap_reset()
gGameTimeIncRemainder = 0.0;
wmWorldMapLoadTempData();
wmSetStartWorldView();
wmMarkAllSubTiles(0);
return wmGenDataReset();
@@ -3211,7 +3135,6 @@ static int wmWorldMapFunc(int a1)
unsigned int partyHealTime = 0;
int map = -1;
int rc = 0;
wmLastTravelTick = getTicks();
while (true) {
sharedFpsLimiter.mark();
@@ -3243,7 +3166,7 @@ static int wmWorldMapFunc(int a1)
int mouseEvent = mouseGetEvent();
if (wmGenData.isWalking && wmTravelTickDue(now)) {
if (wmGenData.isWalking) {
wmPartyWalkingStep();
if (wmGenData.isInCar) {
@@ -4552,7 +4475,6 @@ static void wmPartyInitWalking(int x, int y)
wmGenData.walkDestinationY = y;
wmGenData.currentAreaId = -1;
wmGenData.isWalking = true;
wmLastTravelTick = getTicks();
int dx = abs(x - wmGenData.worldPosX);
int dy = abs(y - wmGenData.worldPosY);
@@ -4592,25 +4514,6 @@ static void wmPartyInitWalking(int x, int y)
}
}
static bool wmTravelTickDue(unsigned int now)
{
if (worldmapTravelDelay == 0) {
return true;
}
if (getTicksBetween(now, wmLastTravelTick) < worldmapTravelDelay) {
return false;
}
wmLastTravelTick += worldmapTravelDelay;
if (getTicksBetween(now, wmLastTravelTick) >= worldmapTravelDelay) {
// Drop accumulated ticks after a stall instead of advancing in bursts.
wmLastTravelTick = now;
}
return true;
}
// 0x4C1F90 wmPartyWalkingStep
static void wmPartyWalkingStep()
{
@@ -6267,14 +6170,6 @@ int wmGetPartyCurArea(int* areaIdxPtr)
return -1;
}
bool wmStartWorldPosIsConfigured()
{
int x;
int y;
return wmGetStartWorldMapConfigValue("worldmap_x", &x)
|| wmGetStartWorldMapConfigValue("worldmap_y", &y);
}
// 0x4C47D8 wmMarkAllSubTiles
static void wmMarkAllSubTiles(int state)
{
@@ -7192,18 +7087,6 @@ void wmSetPartyWorldPos(int x, int y)
wmGenData.worldPosY = y;
}
void wmSetPartyCurArea(int areaIdx)
{
wmGenData.currentAreaId = cityIsValid(areaIdx) ? areaIdx : -1;
}
void wmClearPartyWalking()
{
wmGenData.walkDestinationX = 0;
wmGenData.walkDestinationY = 0;
wmGenData.isWalking = false;
}
void wmCarSetCurrentArea(int area)
{
wmGenData.currentCarAreaId = area;
-3
View File
@@ -285,9 +285,6 @@ int wmMatchAreaContainingMapIdx(int mapIdx, int* areaIdxPtr);
int wmTeleportToArea(int areaIdx);
// CE
bool wmStartWorldPosIsConfigured();
void wmSetPartyCurArea(int areaIdx);
void wmClearPartyWalking();
void wmSetPartyWorldPos(int x, int y);
void wmCarSetCurrentArea(int area);
void wmForceEncounter(int map, unsigned int flags);