mirror of
https://github.com/fallout2-ce/fallout2-ce.git
synced 2026-07-27 16:47:11 -07:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1c6fa29292 |
@@ -42,11 +42,6 @@ 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` |
|
||||
|
||||
## Opcodes / Metarules
|
||||
@@ -57,7 +52,7 @@ See [`https://sfall-team.github.io/sfall/`](https://sfall-team.github.io/sfall/)
|
||||
| --- | --- | --- | --- |
|
||||
| Direct memory access| read_byte,short,int,string<br>write_byte,short,int,string<br>call_offset_vX | đźš« | Not possible. Open an issue if you need functionality not covered by other opcodes. |
|
||||
| Stats | get/set_pc_base_stat<br>get/set_pc_extra_stat<br>get/set_critter_base_stat<br>get/set_critter_extra_stat | âś… | CE uses engine stat helpers here instead of sfall's direct proto-field behavior, so derived-stat update behavior can differ. |
|
||||
| Stats / Alter min/max | get/set_stat_min/max<br>set_pc_stat_min/max<br>set_npc_stat_min/max | âś… | - |
|
||||
| Stats / Alter min/max | get/set_stat_min/max<br>set_pc_stat_min/max<br>set_npc_stat_min/max | not implemented | - |
|
||||
| Skills | get/set_critter_skill_points<br>get/set_available_skill_points<br>set_skill_max<br>set_critter_skill_mod<br>set_base_skill_mod<br>mod_skill_points_per_level | not implemented | - |
|
||||
| Graphics | graphics_funcs_available<br>force_graphics_refresh<br>get_screen_width<br>get_screen_height<br>set_palette | implemented: only get_screen_width, get_screen_height | - |
|
||||
| Shaders | load_shader<br>free_shader<br>activate_shader<br>deactivate_shader<br>set/get_shader_* | đźš« | likely will not implement direct compatibility
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,80 +0,0 @@
|
||||
#include "define_lite.h"
|
||||
#include "sfall.h"
|
||||
#include "test_utils.h"
|
||||
|
||||
procedure start begin
|
||||
variable original_extra;
|
||||
variable original_value;
|
||||
variable original_pc_max;
|
||||
variable original_pc_min;
|
||||
variable original_npc_max;
|
||||
variable original_npc_min;
|
||||
variable original_npc_luck_max;
|
||||
variable test_npc;
|
||||
variable test_npc_extra;
|
||||
variable test_npc_luck;
|
||||
|
||||
if (not game_loaded) then return;
|
||||
|
||||
display_msg("Testing stat min/max...");
|
||||
test_suite_errors := 0;
|
||||
|
||||
original_extra := get_pc_extra_stat(STAT_rad_resist);
|
||||
original_value := get_critter_stat(dude_obj, STAT_rad_resist);
|
||||
original_pc_max := get_pc_stat_max(STAT_rad_resist);
|
||||
original_pc_min := get_pc_stat_min(STAT_rad_resist);
|
||||
original_npc_max := get_npc_stat_max(STAT_rad_resist);
|
||||
original_npc_min := get_npc_stat_min(STAT_rad_resist);
|
||||
|
||||
set_stat_max(STAT_rad_resist, 101);
|
||||
call assertEquals("set_stat_max changes PC bound", get_pc_stat_max(STAT_rad_resist), 101);
|
||||
call assertEquals("set_stat_max changes NPC bound", get_npc_stat_max(STAT_rad_resist), 101);
|
||||
|
||||
set_stat_min(STAT_rad_resist, -10);
|
||||
call assertEquals("set_stat_min changes PC bound", get_pc_stat_min(STAT_rad_resist), -10);
|
||||
call assertEquals("set_stat_min changes NPC bound", get_npc_stat_min(STAT_rad_resist), -10);
|
||||
|
||||
set_pc_extra_stat(STAT_rad_resist, 200);
|
||||
set_pc_stat_max(STAT_rad_resist, 100);
|
||||
call assertEquals("PC maximum changed independently", get_pc_stat_max(STAT_rad_resist), 100);
|
||||
call assertEquals("NPC maximum unchanged by PC setter", get_npc_stat_max(STAT_rad_resist), 101);
|
||||
call assertEquals("radiation resistance capped at 100", get_critter_stat(dude_obj, STAT_rad_resist), 100);
|
||||
|
||||
set_pc_extra_stat(STAT_rad_resist, -200);
|
||||
set_pc_stat_min(STAT_rad_resist, -5);
|
||||
call assertEquals("PC minimum changed independently", get_pc_stat_min(STAT_rad_resist), -5);
|
||||
call assertEquals("NPC minimum unchanged by PC setter", get_npc_stat_min(STAT_rad_resist), -10);
|
||||
call assertEquals("radiation resistance clamped to PC minimum", get_critter_stat(dude_obj, STAT_rad_resist), -5);
|
||||
|
||||
set_npc_stat_max(STAT_rad_resist, 99);
|
||||
call assertEquals("NPC maximum changed independently", get_npc_stat_max(STAT_rad_resist), 99);
|
||||
call assertEquals("PC maximum unchanged by NPC setter", get_pc_stat_max(STAT_rad_resist), 100);
|
||||
|
||||
set_npc_stat_min(STAT_rad_resist, -4);
|
||||
call assertEquals("NPC minimum changed independently", get_npc_stat_min(STAT_rad_resist), -4);
|
||||
call assertEquals("PC minimum unchanged by NPC setter", get_pc_stat_min(STAT_rad_resist), -5);
|
||||
|
||||
test_npc := create_object_sid(0x01000001, 0, 0, -1);
|
||||
test_npc_extra := get_critter_extra_stat(test_npc, STAT_rad_resist);
|
||||
set_critter_extra_stat(test_npc, STAT_rad_resist, 200);
|
||||
call assertEquals("NPC radiation resistance uses NPC maximum", get_critter_stat(test_npc, STAT_rad_resist), 99);
|
||||
set_critter_extra_stat(test_npc, STAT_rad_resist, test_npc_extra);
|
||||
|
||||
test_npc_luck := get_critter_base_stat(test_npc, STAT_lu);
|
||||
original_npc_luck_max := get_npc_stat_max(STAT_lu);
|
||||
set_npc_stat_max(STAT_lu, test_npc_luck - 1);
|
||||
set_critter_base_stat(test_npc, STAT_lu, test_npc_luck + 1);
|
||||
call assertEquals("NPC base stat rejects value above configured maximum", get_critter_base_stat(test_npc, STAT_lu), test_npc_luck);
|
||||
set_npc_stat_max(STAT_lu, original_npc_luck_max);
|
||||
destroy_object(test_npc);
|
||||
|
||||
set_pc_stat_max(STAT_rad_resist, original_pc_max);
|
||||
set_pc_stat_min(STAT_rad_resist, original_pc_min);
|
||||
set_npc_stat_max(STAT_rad_resist, original_npc_max);
|
||||
set_npc_stat_min(STAT_rad_resist, original_npc_min);
|
||||
set_pc_extra_stat(STAT_rad_resist, original_extra);
|
||||
call assertEquals("original radiation resistance restored", get_critter_stat(dude_obj, STAT_rad_resist), original_value);
|
||||
|
||||
call report_test_results("stat min/max");
|
||||
signal_close_game;
|
||||
end
|
||||
+1
-3
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -16,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;
|
||||
@@ -29,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 },
|
||||
@@ -110,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
|
||||
@@ -175,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" },
|
||||
@@ -305,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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -41,7 +41,6 @@ int gameDialogBarter(int modifier);
|
||||
void gameDialogEndBarter();
|
||||
bool gameDialogIsBarterWindowExpanded();
|
||||
int gameDialogGetWindow();
|
||||
int gameDialogGetBackgroundWindow();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
|
||||
+12
-65
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
+34
-20
@@ -38,7 +38,6 @@
|
||||
#include "sfall_opcodes.h"
|
||||
#include "sfall_script_hooks.h"
|
||||
#include "skilldex.h"
|
||||
#include "stat.h"
|
||||
#include "text_font.h"
|
||||
#include "tile.h"
|
||||
#include "window.h"
|
||||
@@ -780,8 +779,6 @@ static void mf_get_object_ai_data(OpcodeContext& ctx);
|
||||
static void mf_get_object_data(OpcodeContext& ctx);
|
||||
static void mf_get_outline(OpcodeContext& ctx);
|
||||
static void mf_get_sfall_arg_at(OpcodeContext& ctx);
|
||||
static void mf_get_stat_max(OpcodeContext& ctx);
|
||||
static void mf_get_stat_min(OpcodeContext& ctx);
|
||||
static void mf_get_terrain_name(OpcodeContext& ctx);
|
||||
static void mf_get_text_width(OpcodeContext& ctx);
|
||||
static void mf_get_window_attribute(OpcodeContext& ctx);
|
||||
@@ -861,8 +858,8 @@ const MetaruleInfo kMetarules[] = {
|
||||
{ "get_object_data", mf_get_object_data, 2, 2, 0, { ARG_OBJECT, ARG_INT } },
|
||||
{ "get_outline", mf_get_outline, 1, 1, 0, { ARG_OBJECT } },
|
||||
{ "get_sfall_arg_at", mf_get_sfall_arg_at, 1, 1, 0, { ARG_INT } },
|
||||
{ "get_stat_max", mf_get_stat_max, 1, 2, 0, { ARG_INT, ARG_INT } },
|
||||
{ "get_stat_min", mf_get_stat_min, 1, 2, 0, { ARG_INT, ARG_INT } },
|
||||
// {"get_stat_max", mf_get_stat_max, 1, 2, 0, {ARG_INT, ARG_INT}},
|
||||
// {"get_stat_min", mf_get_stat_min, 1, 2, 0, {ARG_INT, ARG_INT}},
|
||||
// {"get_string_pointer", mf_get_string_pointer, 1, 1, 0, {ARG_STRING}}, // note: deprecated; do not implement
|
||||
{ "get_terrain_name", mf_get_terrain_name, 0, 2, -1, { ARG_INT, ARG_INT } },
|
||||
{ "get_text_width", mf_get_text_width, 1, 1, 0, { ARG_STRING } },
|
||||
@@ -961,7 +958,7 @@ static InterfaceWindowLookupResult getInterfaceWindowByType(int winType, int& wi
|
||||
window = inventoryGetWindow();
|
||||
break;
|
||||
case 1:
|
||||
window = gameDialogGetBackgroundWindow();
|
||||
window = gameDialogGetWindow();
|
||||
break;
|
||||
case 2:
|
||||
window = pipboyGetWindow();
|
||||
@@ -992,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) {
|
||||
@@ -1219,18 +1245,6 @@ void mf_get_sfall_arg_at(OpcodeContext& ctx)
|
||||
ctx.setReturn(result);
|
||||
}
|
||||
|
||||
void mf_get_stat_max(OpcodeContext& ctx)
|
||||
{
|
||||
const bool npc = ctx.numArgs() > 1 && ctx.arg(1).asInt() != 0;
|
||||
ctx.setReturn(statGetConfiguredMaximum(ctx.arg(0).asInt(), npc));
|
||||
}
|
||||
|
||||
void mf_get_stat_min(OpcodeContext& ctx)
|
||||
{
|
||||
const bool npc = ctx.numArgs() > 1 && ctx.arg(1).asInt() != 0;
|
||||
ctx.setReturn(statGetConfiguredMinimum(ctx.arg(0).asInt(), npc));
|
||||
}
|
||||
|
||||
void mf_get_object_ai_data(OpcodeContext& ctx)
|
||||
{
|
||||
Object* object = ctx.arg(0).asObject();
|
||||
@@ -1856,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -160,50 +160,6 @@ static void op_set_critter_extra_stat(Program* program)
|
||||
critterSetBonusStat(obj, stat, value);
|
||||
}
|
||||
|
||||
static void op_set_stat_max(Program* program)
|
||||
{
|
||||
int maximum = programStackPopInteger(program);
|
||||
int stat = programStackPopInteger(program);
|
||||
statSetPcMaximum(stat, maximum);
|
||||
statSetNpcMaximum(stat, maximum);
|
||||
}
|
||||
|
||||
static void op_set_stat_min(Program* program)
|
||||
{
|
||||
int minimum = programStackPopInteger(program);
|
||||
int stat = programStackPopInteger(program);
|
||||
statSetPcMinimum(stat, minimum);
|
||||
statSetNpcMinimum(stat, minimum);
|
||||
}
|
||||
|
||||
static void op_set_pc_stat_max(Program* program)
|
||||
{
|
||||
int maximum = programStackPopInteger(program);
|
||||
int stat = programStackPopInteger(program);
|
||||
statSetPcMaximum(stat, maximum);
|
||||
}
|
||||
|
||||
static void op_set_pc_stat_min(Program* program)
|
||||
{
|
||||
int minimum = programStackPopInteger(program);
|
||||
int stat = programStackPopInteger(program);
|
||||
statSetPcMinimum(stat, minimum);
|
||||
}
|
||||
|
||||
static void op_set_npc_stat_max(Program* program)
|
||||
{
|
||||
int maximum = programStackPopInteger(program);
|
||||
int stat = programStackPopInteger(program);
|
||||
statSetNpcMaximum(stat, maximum);
|
||||
}
|
||||
|
||||
static void op_set_npc_stat_min(Program* program)
|
||||
{
|
||||
int minimum = programStackPopInteger(program);
|
||||
int stat = programStackPopInteger(program);
|
||||
statSetNpcMinimum(stat, minimum);
|
||||
}
|
||||
|
||||
// get_pc_base_stat
|
||||
static void op_get_pc_base_stat(Program* program)
|
||||
{
|
||||
@@ -1940,17 +1896,11 @@ void sfallOpcodesInit()
|
||||
// 0x8246 - void mod_skill_points_per_level(int value)
|
||||
|
||||
// 0x81b4 - void set_stat_max(int stat, int value)
|
||||
interpreterRegisterOpcode(0x81B4, op_set_stat_max);
|
||||
// 0x81b5 - void set_stat_min(int stat, int value)
|
||||
interpreterRegisterOpcode(0x81B5, op_set_stat_min);
|
||||
// 0x81b7 - void set_pc_stat_max(int stat, int value)
|
||||
interpreterRegisterOpcode(0x81B7, op_set_pc_stat_max);
|
||||
// 0x81b8 - void set_pc_stat_min(int stat, int value)
|
||||
interpreterRegisterOpcode(0x81B8, op_set_pc_stat_min);
|
||||
// 0x81b9 - void set_npc_stat_max(int stat, int value)
|
||||
interpreterRegisterOpcode(0x81B9, op_set_npc_stat_max);
|
||||
// 0x81ba - void set_npc_stat_min(int stat, int value)
|
||||
interpreterRegisterOpcode(0x81BA, op_set_npc_stat_min);
|
||||
|
||||
// 0x816b - int input_funcs_available() // deprecated; do not implement
|
||||
// 0x816c - int key_pressed(int dxScancode)
|
||||
|
||||
+3
-89
@@ -98,25 +98,14 @@ static char* gStatValueDescriptions[PRIMARY_STAT_RANGE];
|
||||
// 0x6681AC curr_pc_stat
|
||||
static int gPcStatValues[PC_STAT_COUNT];
|
||||
|
||||
static int pcStatMaximums[SAVEABLE_STAT_COUNT];
|
||||
static int pcStatMinimums[SAVEABLE_STAT_COUNT];
|
||||
static int npcStatMaximums[SAVEABLE_STAT_COUNT];
|
||||
static int npcStatMinimums[SAVEABLE_STAT_COUNT];
|
||||
|
||||
static int unspentApBonus = 4;
|
||||
static int unspentApPerkBonus = 4;
|
||||
|
||||
static void statResetBounds();
|
||||
static int statGetMaximum(Object* critter, int stat);
|
||||
static int statGetMinimum(Object* critter, int stat);
|
||||
|
||||
// 0x4AED70
|
||||
int statsInit()
|
||||
{
|
||||
MessageListItem messageListItem;
|
||||
|
||||
statResetBounds();
|
||||
|
||||
// NOTE: Uninline.
|
||||
pcStatsReset();
|
||||
|
||||
@@ -155,7 +144,6 @@ int statsReset()
|
||||
{
|
||||
// NOTE: Uninline.
|
||||
pcStatsReset();
|
||||
statResetBounds();
|
||||
statResetUnspentApBonuses();
|
||||
|
||||
return 0;
|
||||
@@ -220,72 +208,6 @@ int statGetUnspentApPerkBonus()
|
||||
return unspentApPerkBonus;
|
||||
}
|
||||
|
||||
static void statResetBounds()
|
||||
{
|
||||
for (int stat = 0; stat < SAVEABLE_STAT_COUNT; stat++) {
|
||||
pcStatMaximums[stat] = gStatDescriptions[stat].maximumValue;
|
||||
pcStatMinimums[stat] = gStatDescriptions[stat].minimumValue;
|
||||
npcStatMaximums[stat] = gStatDescriptions[stat].maximumValue;
|
||||
npcStatMinimums[stat] = gStatDescriptions[stat].minimumValue;
|
||||
}
|
||||
}
|
||||
|
||||
static int statGetMaximum(Object* critter, int stat)
|
||||
{
|
||||
return critter == gDude ? pcStatMaximums[stat] : npcStatMaximums[stat];
|
||||
}
|
||||
|
||||
static int statGetMinimum(Object* critter, int stat)
|
||||
{
|
||||
return critter == gDude ? pcStatMinimums[stat] : npcStatMinimums[stat];
|
||||
}
|
||||
|
||||
int statGetConfiguredMaximum(int stat, bool npc)
|
||||
{
|
||||
if (stat >= 0 && stat < SAVEABLE_STAT_COUNT) {
|
||||
return npc ? npcStatMaximums[stat] : pcStatMaximums[stat];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int statGetConfiguredMinimum(int stat, bool npc)
|
||||
{
|
||||
if (stat >= 0 && stat < SAVEABLE_STAT_COUNT) {
|
||||
return npc ? npcStatMinimums[stat] : pcStatMinimums[stat];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void statSetPcMaximum(int stat, int maximum)
|
||||
{
|
||||
if (stat >= 0 && stat < SAVEABLE_STAT_COUNT) {
|
||||
pcStatMaximums[stat] = maximum;
|
||||
}
|
||||
}
|
||||
|
||||
void statSetPcMinimum(int stat, int minimum)
|
||||
{
|
||||
if (stat >= 0 && stat < SAVEABLE_STAT_COUNT) {
|
||||
pcStatMinimums[stat] = minimum;
|
||||
}
|
||||
}
|
||||
|
||||
void statSetNpcMaximum(int stat, int maximum)
|
||||
{
|
||||
if (stat >= 0 && stat < SAVEABLE_STAT_COUNT) {
|
||||
npcStatMaximums[stat] = maximum;
|
||||
}
|
||||
}
|
||||
|
||||
void statSetNpcMinimum(int stat, int minimum)
|
||||
{
|
||||
if (stat >= 0 && stat < SAVEABLE_STAT_COUNT) {
|
||||
npcStatMinimums[stat] = minimum;
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4AEF48
|
||||
int critterGetStat(Object* critter, int stat)
|
||||
{
|
||||
@@ -475,15 +397,7 @@ int critterGetStat(Object* critter, int stat)
|
||||
}
|
||||
}
|
||||
|
||||
int minimum = statGetMinimum(critter, stat);
|
||||
if (value < minimum) {
|
||||
value = minimum;
|
||||
} else {
|
||||
int maximum = statGetMaximum(critter, stat);
|
||||
if (value > maximum) {
|
||||
value = maximum;
|
||||
}
|
||||
}
|
||||
value = std::clamp(value, gStatDescriptions[stat].minimumValue, gStatDescriptions[stat].maximumValue);
|
||||
} else {
|
||||
switch (stat) {
|
||||
case STAT_CURRENT_HIT_POINTS:
|
||||
@@ -571,11 +485,11 @@ int critterSetBaseStat(Object* critter, int stat, int value)
|
||||
value -= traitGetStatModifier(stat);
|
||||
}
|
||||
|
||||
if (value < statGetMinimum(critter, stat)) {
|
||||
if (value < gStatDescriptions[stat].minimumValue) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (value > statGetMaximum(critter, stat)) {
|
||||
if (value > gStatDescriptions[stat].maximumValue) {
|
||||
return -3;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user