mirror of
https://github.com/fallout2-ce/fallout2-ce.git
synced 2026-07-27 16:47:11 -07:00
Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e3b1d8cd42 | ||
|
|
34096e0bcc | ||
|
|
2c0796839f | ||
|
|
8e60a2fba2 | ||
|
|
ca89abad6c | ||
|
|
21a98bebb1 | ||
|
|
283107bebe |
@@ -55,9 +55,6 @@ 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
|
||||
|
||||
@@ -165,6 +165,16 @@ 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.
|
||||
|
||||
+3
-1
@@ -1789,11 +1789,13 @@ void FrmImage::resetInternal()
|
||||
|
||||
bool FrmImage::setFrame(const Art* art, int frame, int direction)
|
||||
{
|
||||
unsigned char* data = artGetFrameData(art, frame, direction, &_width, &_height, &_xOffset, &_yOffset);
|
||||
unsigned char* data = artGetFrameData(art, frame, direction, &_width, &_height, nullptr, nullptr);
|
||||
if (data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_xOffset = art->xOffsets[direction];
|
||||
_yOffset = art->yOffsets[direction];
|
||||
_data = data;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -15,9 +15,8 @@ void contentConfigInit()
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to migrate some settings from legacy config files.
|
||||
// Try to migrate some settings from sfall.
|
||||
contentConfigTryMigrateFromSfall(kConfigPatchPath);
|
||||
contentConfigTryMigrateFromF2Res(kConfigPatchPath);
|
||||
|
||||
if (!configInit(&gContentConfig)) {
|
||||
return;
|
||||
@@ -36,4 +35,4 @@ void contentConfigExit()
|
||||
configFree(&gContentConfig);
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
} // namespace fallout
|
||||
@@ -16,8 +16,6 @@ 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;
|
||||
@@ -31,7 +29,6 @@ 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 },
|
||||
@@ -113,27 +110,6 @@ 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
|
||||
@@ -325,82 +301,6 @@ 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) {
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
namespace fallout {
|
||||
|
||||
bool gameConfigMigrateFromF2Res(const char* gameConfigFilePath, Config* gameConfig);
|
||||
void contentConfigTryMigrateFromF2Res(const char* contentConfigPath);
|
||||
void contentConfigTryMigrateFromSfall(const char* contentConfigPath);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -3500,6 +3500,11 @@ int gameDialogGetWindow()
|
||||
return windowGetWindow(gGameDialogWindow) != nullptr ? gGameDialogWindow : -1;
|
||||
}
|
||||
|
||||
int gameDialogGetBackgroundWindow()
|
||||
{
|
||||
return windowGetWindow(gGameDialogBackgroundWindow) != nullptr ? gGameDialogBackgroundWindow : -1;
|
||||
}
|
||||
|
||||
// 0x448660 gdialog_barter_cleanup_tables
|
||||
void gameDialogBarterCleanupTables()
|
||||
{
|
||||
|
||||
@@ -41,6 +41,7 @@ int gameDialogBarter(int modifier);
|
||||
void gameDialogEndBarter();
|
||||
bool gameDialogIsBarterWindowExpanded();
|
||||
int gameDialogGetWindow();
|
||||
int gameDialogGetBackgroundWindow();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
|
||||
+65
-12
@@ -5,6 +5,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
@@ -925,7 +926,31 @@ static bool inventoryLootMouseHitTestScroller(bool targetInventory)
|
||||
|
||||
static void inventoryLootRenderPaneWeight(unsigned char* windowBuffer, int pitch, bool targetPane, Object* object, int extraWeight)
|
||||
{
|
||||
char formattedText[20];
|
||||
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];
|
||||
formattedText[0] = '\0';
|
||||
|
||||
int oldFont = fontGetCurrent();
|
||||
@@ -942,26 +967,54 @@ static void inventoryLootRenderPaneWeight(unsigned char* windowBuffer, int pitch
|
||||
pitch);
|
||||
}
|
||||
|
||||
int color = COLOR_GREEN;
|
||||
int color = COLOR_WHITE;
|
||||
int inventoryWeight = objectGetInventoryWeight(object);
|
||||
if (PID_TYPE(object->pid) == OBJ_TYPE_CRITTER) {
|
||||
int currentWeight = objectGetInventoryWeight(object) + extraWeight;
|
||||
int currentWeight = inventoryWeight + extraWeight;
|
||||
int maxWeight = critterGetStat(object, STAT_CARRY_WEIGHT);
|
||||
snprintf(formattedText, sizeof(formattedText), "%d/%d", currentWeight, maxWeight);
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
snprintf(formattedText, sizeof(formattedText), "%d/%d", currentSize, maxSize);
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
int inventoryWeight = objectGetInventoryWeight(object);
|
||||
snprintf(formattedText, sizeof(formattedText), "%d", inventoryWeight);
|
||||
if (showLabel) {
|
||||
snprintf(formattedText, sizeof(formattedText), "%s %d", messageListItem.text, inventoryWeight);
|
||||
} else {
|
||||
snprintf(formattedText, sizeof(formattedText), "%d", inventoryWeight);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
fontSetCurrent(oldFont);
|
||||
}
|
||||
@@ -4096,10 +4149,10 @@ static void displayLootPanePartyName(unsigned char* windowBuffer, int windowPitc
|
||||
|
||||
int oldFont = fontGetCurrent();
|
||||
fontSetCurrent(101);
|
||||
int nameY = rect.bottom - fontGetLineHeight() - 2;
|
||||
int nameY = rect.bottom - fontGetLineHeight();
|
||||
fontSetCurrent(oldFont);
|
||||
|
||||
inventoryDrawCenteredText(windowBuffer, windowPitch, INVENTORY_BODY_VIEW_WIDTH, rect.left, nameY, name, COLOR_GREEN);
|
||||
inventoryDrawCenteredText(windowBuffer, windowPitch, INVENTORY_BODY_VIEW_WIDTH, rect.left, nameY, name, COLOR_WHITE);
|
||||
}
|
||||
|
||||
// Displays item description.
|
||||
|
||||
+1
-6
@@ -305,13 +305,8 @@ 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, panelOffsetX, panelOffsetY);
|
||||
Point panelOrigin = mainMenuTransformPoint(layout, MAIN_MENU_PANEL_OFFSET_X, MAIN_MENU_PANEL_OFFSET_Y);
|
||||
|
||||
blitBuffer2DScaledTrans(mainMenuButtonPanelFrmImage.getBuffer(),
|
||||
Buffer2D(gMainMenuWindowBuffer, layout.screenWidth, layout.screenHeight),
|
||||
|
||||
+1
-1
@@ -978,7 +978,7 @@ static int mapLoad(File* stream)
|
||||
}
|
||||
|
||||
lightSetAmbientIntensity(LIGHT_INTENSITY_MAX, false);
|
||||
objectSetLocation(gDude, gCenterTile, gElevation, nullptr);
|
||||
objectSetLocation(gDude, gEnteringTile, gElevation, nullptr);
|
||||
objectSetRotation(gDude, gEnteringRotation, nullptr);
|
||||
gMapHeader.index = wmMapMatchNameToIdx(gMapHeader.name);
|
||||
|
||||
|
||||
+3
-2
@@ -501,13 +501,14 @@ 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);
|
||||
|
||||
@@ -172,6 +172,8 @@ 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
|
||||
|
||||
@@ -95,6 +95,16 @@ 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.
|
||||
|
||||
+3
-32
@@ -958,7 +958,7 @@ static InterfaceWindowLookupResult getInterfaceWindowByType(int winType, int& wi
|
||||
window = inventoryGetWindow();
|
||||
break;
|
||||
case 1:
|
||||
window = gameDialogGetWindow();
|
||||
window = gameDialogGetBackgroundWindow();
|
||||
break;
|
||||
case 2:
|
||||
window = pipboyGetWindow();
|
||||
@@ -989,35 +989,6 @@ 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) {
|
||||
@@ -1870,10 +1841,10 @@ void mf_set_window_flag(OpcodeContext& ctx)
|
||||
|
||||
int windowId = ctx.arg(0).asInt();
|
||||
if (windowId <= 0) {
|
||||
windowId = getCurrentInterfaceWindow();
|
||||
windowId = inventoryGetWindow();
|
||||
}
|
||||
|
||||
if (windowId == -1) {
|
||||
if (windowId == -1 || windowGetWindow(windowId) == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+90
-57
@@ -761,12 +761,26 @@ static const int wmRndCursorFids[WORLD_MAP_ENCOUNTER_FRM_COUNT] = {
|
||||
};
|
||||
|
||||
#define MAX_TRAIL_LENGTH 1000
|
||||
#define TRAIL_MARKER_STYLE_COUNT 4
|
||||
|
||||
typedef struct TrailMarkerStyle {
|
||||
int length;
|
||||
int spacing;
|
||||
} TrailMarkerStyle;
|
||||
|
||||
typedef struct {
|
||||
int x;
|
||||
int y;
|
||||
} TrailDot;
|
||||
|
||||
typedef struct TrailMarkerState {
|
||||
bool hasPattern;
|
||||
int dotCount;
|
||||
TrailDot dots[MAX_TRAIL_LENGTH];
|
||||
int remainingDots;
|
||||
int remainingSpacing;
|
||||
} TrailMarkerState;
|
||||
|
||||
// 0x51DE94 wmLabelList
|
||||
static int* wmLabelList = nullptr;
|
||||
|
||||
@@ -940,6 +954,60 @@ static bool wmFaded = false;
|
||||
static int wmForceEncounterMapId = -1;
|
||||
static unsigned int wmForceEncounterFlags = 0;
|
||||
static int worldmapTrailMarkers;
|
||||
static TrailMarkerState trailMarkerState = {};
|
||||
|
||||
static const unsigned char worldmapTrailMarkerColor = 134;
|
||||
static const TrailMarkerStyle worldmapTrailMarkerStyles[TRAIL_MARKER_STYLE_COUNT] = {
|
||||
{ 1, 2 },
|
||||
{ 2, 1 },
|
||||
{ 1, 3 },
|
||||
{ 1, 2 },
|
||||
};
|
||||
|
||||
static void wmAddTrailDot(TrailDot* trailDots, int* trailDotCount, int x, int y)
|
||||
{
|
||||
if (*trailDotCount < MAX_TRAIL_LENGTH) {
|
||||
trailDots[(*trailDotCount)++] = { x, y };
|
||||
} else {
|
||||
memmove(trailDots, trailDots + 1, sizeof(TrailDot) * (MAX_TRAIL_LENGTH - 1));
|
||||
trailDots[MAX_TRAIL_LENGTH - 1] = { x, y };
|
||||
}
|
||||
}
|
||||
|
||||
static void wmAddTrailMarker(int terrainId, int x, int y)
|
||||
{
|
||||
int styleIndex = std::clamp(terrainId, 0, TRAIL_MARKER_STYLE_COUNT - 1);
|
||||
const TrailMarkerStyle* style = &(worldmapTrailMarkerStyles[styleIndex]);
|
||||
|
||||
if (!trailMarkerState.hasPattern) {
|
||||
trailMarkerState.hasPattern = true;
|
||||
trailMarkerState.remainingDots = style->length;
|
||||
trailMarkerState.remainingSpacing = style->spacing;
|
||||
} else {
|
||||
trailMarkerState.remainingDots = std::min(trailMarkerState.remainingDots, style->length);
|
||||
trailMarkerState.remainingSpacing = std::min(trailMarkerState.remainingSpacing, style->spacing);
|
||||
}
|
||||
|
||||
if (trailMarkerState.remainingDots <= 0 && trailMarkerState.remainingSpacing > 0) {
|
||||
trailMarkerState.remainingSpacing--;
|
||||
if (trailMarkerState.remainingSpacing == 0) {
|
||||
trailMarkerState.remainingDots = style->length;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
trailMarkerState.remainingDots--;
|
||||
trailMarkerState.remainingSpacing = style->spacing;
|
||||
wmAddTrailDot(trailMarkerState.dots, &(trailMarkerState.dotCount), x, y);
|
||||
}
|
||||
|
||||
static void wmResetTrailMarkers()
|
||||
{
|
||||
trailMarkerState.hasPattern = false;
|
||||
trailMarkerState.dotCount = 0;
|
||||
trailMarkerState.remainingDots = 0;
|
||||
trailMarkerState.remainingSpacing = 0;
|
||||
}
|
||||
|
||||
static inline bool cityIsValid(int city)
|
||||
{
|
||||
@@ -1055,6 +1123,7 @@ static int wmGenDataInit()
|
||||
wmForceEncounterMapId = -1;
|
||||
wmForceEncounterFlags = 0;
|
||||
wmTerrainNameOverrides.clear();
|
||||
wmResetTrailMarkers();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1109,6 +1178,7 @@ static int wmGenDataReset()
|
||||
wmForceEncounterMapId = -1;
|
||||
wmForceEncounterFlags = 0;
|
||||
wmTerrainNameOverrides.clear();
|
||||
wmResetTrailMarkers();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1268,6 +1338,8 @@ int wmWorldMap_save(File* stream)
|
||||
// 0x4BD28C wmWorldMap_load
|
||||
int wmWorldMap_load(File* stream)
|
||||
{
|
||||
wmResetTrailMarkers();
|
||||
|
||||
if (fileReadBool(stream, &gDidMeetFrankHorrigan) == -1) return -1;
|
||||
if (fileReadInt32(stream, &(wmGenData.currentAreaId)) == -1) return -1;
|
||||
if (fileReadInt32(stream, &(wmGenData.worldPosX)) == -1) return -1;
|
||||
@@ -3119,6 +3191,8 @@ static int wmWorldMapFunc(int a1)
|
||||
{
|
||||
ScopedGameMode gm(GameMode::kWorldmap);
|
||||
|
||||
wmResetTrailMarkers();
|
||||
|
||||
wmFadeOut();
|
||||
|
||||
if (wmInterfaceInit() == -1) {
|
||||
@@ -4579,6 +4653,12 @@ static void wmPartyWalkingStep()
|
||||
false);
|
||||
}
|
||||
|
||||
if (worldmapTrailMarkers) {
|
||||
SubtileInfo* markerSubtile;
|
||||
wmFindCurSubTileFromPos(wmGenData.worldPosX, wmGenData.worldPosY, &markerSubtile);
|
||||
wmAddTrailMarker(markerSubtile->terrain, wmGenData.worldPosX, wmGenData.worldPosY);
|
||||
}
|
||||
|
||||
wmGenData.walkDistance -= 1;
|
||||
if (wmGenData.walkDistance == 0) {
|
||||
wmGenData.walkDestinationY = 0;
|
||||
@@ -5905,70 +5985,23 @@ static int wmDrawCursorStopped()
|
||||
// Dotted Trail logic
|
||||
|
||||
if (worldmapTrailMarkers) {
|
||||
static bool wasWalking = false;
|
||||
static uint32_t lastTrailDropTick = 0;
|
||||
const int baseCooldown = 25; // base time between potential dot drops
|
||||
static int trailDotCount = 0;
|
||||
static TrailDot trailDots[MAX_TRAIL_LENGTH];
|
||||
static int patternCounter = 0;
|
||||
|
||||
// Clear the trail when player stops - needs to be done when reloading map too
|
||||
if (wasWalking && !isWalkingNow) {
|
||||
trailDotCount = 0;
|
||||
}
|
||||
wasWalking = isWalkingNow;
|
||||
|
||||
if (isWalkingNow) {
|
||||
uint32_t now = getTicks();
|
||||
if (now - lastTrailDropTick >= baseCooldown) {
|
||||
lastTrailDropTick = now;
|
||||
patternCounter++;
|
||||
|
||||
// Figure out current terrain difficulty
|
||||
wmPartyFindCurSubTile();
|
||||
int difficulty = 1;
|
||||
if (wmGenData.currentSubtile) {
|
||||
Terrain* t = &wmTerrainTypeList[wmGenData.currentSubtile->terrain];
|
||||
difficulty = t->difficulty;
|
||||
if (difficulty < 1) difficulty = 1;
|
||||
}
|
||||
|
||||
// Decide whether to drop on this step, based on terrain (difficulty)
|
||||
bool shouldDrop;
|
||||
if (difficulty >= 4) {
|
||||
shouldDrop = (patternCounter % 4) != 0; // Drop 3 out of every 4 steps --- used?
|
||||
} else if (difficulty == 3) {
|
||||
shouldDrop = (patternCounter % 3) != 0; // Drop 2 out of every 3
|
||||
} else if (difficulty == 2) {
|
||||
shouldDrop = (patternCounter % 2) == 0; // Drop every other step
|
||||
} else {
|
||||
shouldDrop = (patternCounter % 3) == 0; // Drop only once every 3 steps
|
||||
}
|
||||
|
||||
if (shouldDrop) {
|
||||
int cx = wmGenData.worldPosX;
|
||||
int cy = wmGenData.worldPosY;
|
||||
if (trailDotCount < MAX_TRAIL_LENGTH) {
|
||||
trailDots[trailDotCount++] = { cx, cy };
|
||||
} else {
|
||||
// shift left, add more dots
|
||||
memmove(trailDots, trailDots + 1, sizeof(TrailDot) * (MAX_TRAIL_LENGTH - 1));
|
||||
trailDots[MAX_TRAIL_LENGTH - 1] = { cx, cy };
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isWalkingNow) {
|
||||
wmResetTrailMarkers();
|
||||
}
|
||||
|
||||
// Render the trail dots
|
||||
for (int i = 0; i < trailDotCount; i++) {
|
||||
int x = trailDots[i].x;
|
||||
int y = trailDots[i].y;
|
||||
for (int i = 0; i < trailMarkerState.dotCount; i++) {
|
||||
int x = trailMarkerState.dots[i].x;
|
||||
int y = trailMarkerState.dots[i].y;
|
||||
if (x >= wmWorldOffsetX && x < wmWorldOffsetX + WM_VIEW_WIDTH
|
||||
&& y >= wmWorldOffsetY && y < wmWorldOffsetY + WM_VIEW_HEIGHT) {
|
||||
int screenY = WM_VIEW_Y - wmWorldOffsetY + y;
|
||||
int screenX = WM_VIEW_X - wmWorldOffsetX + x;
|
||||
unsigned char* dst = wmBkWinBuf
|
||||
+ WM_WINDOW_WIDTH * (WM_VIEW_Y - wmWorldOffsetY + y)
|
||||
+ (WM_VIEW_X - wmWorldOffsetX + x);
|
||||
*dst = 136; // bright-red palette index? - not matching perfectly, what palette is being used?
|
||||
+ WM_WINDOW_WIDTH * screenY
|
||||
+ screenX;
|
||||
*dst = worldmapTrailMarkerColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user