Compare commits

..
26 changed files with 643 additions and 1443 deletions
-31
View File
@@ -1,31 +0,0 @@
### Description
<!--- Clearly describe the changes introduced by this PR. What was fixed, added, or updated? --->
### Reproduction Steps and Savefile (if available)
<!--- Provide detailed steps to reproduce the issue. Include a savefile if applicable, preferrably for Sonora --->
### Screenshots
<!--- If the PR includes visual changes, add screenshots here. --->
<!---
**Important Notes**
- *Preview builds are not available for pull requests from forked repositories.* To enable preview builds, submit the PR from a branch within this repository.
- *Formatting issues? You have two options:*
1. **Fix formatting automatically** using the following Docker command: *(If you're using Windows, remove `--user $(id -u):$(id -g)`)*
```bash
docker run --rm \
-v $(pwd):/app --workdir /app \
--user $(id -u):$(id -g) silkeh/clang:18 \
bash -c 'find src -type f -name \*.cc -o -name \*.h | xargs clang-format -i'
```
2. **Skip formatting check** by adding the `skip-formatting` label to this PR.
--->
+7 -1
View File
@@ -30,7 +30,13 @@ jobs:
git config --global --add safe.directory "*"
mkdir -p build
cd build
emcmake cmake ../ -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchain/Emscripten.cmake -DCMAKE_BUILD_TYPE=Release && emmake make VERBOSE=1 -j 4
if [[ "$GITHUB_EVENT_NAME" == "pull_request" ]]; then
export BUILD_TYPE=Debug
else
export BUILD_TYPE=Release
fi
emcmake cmake ../ -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchain/Emscripten.cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE}
emmake make VERBOSE=1 -j 4
cd ..
- name: Add node
+1 -3
View File
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.18)
cmake_minimum_required(VERSION 3.13)
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
@@ -305,14 +305,12 @@ if(WIN32)
_CRT_NONSTDC_NO_WARNINGS
NOMINMAX
WIN32_LEAN_AND_MEAN
_STATIC_CPPLIB
)
endif()
if(WIN32)
target_link_libraries(${EXECUTABLE_NAME}
winmm
libcpmt
)
endif()
+1 -1
View File
@@ -33,7 +33,7 @@
"cacheVariables": {
"CMAKE_GENERATOR_TOOLSET": "v141_xp",
"CMAKE_C_FLAGS": "/D_WIN32_WINNT=0x0501",
"CMAKE_CXX_FLAGS": "/D_WIN32_WINNT=0x0501 /D_STATIC_CPPLIB",
"CMAKE_CXX_FLAGS": "/D_WIN32_WINNT=0x0501",
"CMAKE_MSVC_RUNTIME_LIBRARY": "MultiThreaded$<$<CONFIG:Debug>:Debug>"
}
},
+9 -36
View File
@@ -1,14 +1,14 @@
# Fallout 2 Community Edition
Fallout 2 Community Edition is a fully working re-implementation of Fallout 2, with the same original gameplay, engine bugfixes, and some quality of life improvements, that works (mostly) hassle-free on multiple platforms. This is a fork of the original project, which isn't getting regular updates.
Fallout 2 Community Edition is a fully working re-implementation of Fallout 2, with the same original gameplay, engine bugfixes, and some quality of life improvements, that works (mostly) hassle-free on multiple platforms.
Popular Fallout 2 total conversion mods are partially supported. Original versions of Nevada and Sonora (that do not rely on extended features provided by Sfall) work. [Fallout 2 Restoration Project](https://github.com/BGforgeNet/Fallout2_Restoration_Project), [Fallout Et Tu](https://github.com/rotators/Fo1in2) and [Olympus 2207](https://olympus2207.com) are not yet supported. Other mods (particularly Resurrection and Yesterday) are not tested.
Popular Fallout 2 total conversion mods are partially supported. Original versions of Nevada and Sonora (that do not rely on extended features provided by Sfall) likely work, although there is no complete walkthrough confirmation yet. [Fallout 2 Restoration Project](https://github.com/BGforgeNet/Fallout2_Restoration_Project), [Fallout Et Tu](https://github.com/rotators/Fo1in2) and [Olympus 2207](https://olympus2207.com) are not yet supported. Other mods (particularly Resurrection and Yesterday) are not tested.
There is also [Fallout Community Edition](https://github.com/alexbatalov/fallout1-ce) (not affiliated with this fork).
There is also [Fallout Community Edition](https://github.com/alexbatalov/fallout1-ce).
## Installation
You must own the game to play. Purchase your copy on [GOG](https://www.gog.com/game/fallout_2), [Epic Games](https://store.epicgames.com/p/fallout-2) or [Steam](https://store.steampowered.com/app/38410). Download latest [release](https://github.com/fallout2-ce/fallout2-ce/releases) or build from source.
You must own the game to play. Purchase your copy on [GOG](https://www.gog.com/game/fallout_2), [Epic Games](https://store.epicgames.com/p/fallout-2) or [Steam](https://store.steampowered.com/app/38410). Download latest [release](https://github.com/alexbatalov/fallout2-ce/releases) or build from source. You can also check latest [debug](https://github.com/alexbatalov/fallout2-ce/actions) build intended for testers.
### Windows
@@ -96,36 +96,13 @@ The main configuration file is `fallout2.cfg`. There are several important setti
The `sound` folder (with `music` folder inside) might be located either in `data` folder, or be in the Fallout folder. Update `music_path1` setting to match your hierarchy, usually it's `data/sound/music/` or `sound/music/`. Make sure it matches your path exactly (so it might be `SOUND/MUSIC/` if you've installed Fallout from CD). Music files themselves (with `ACM` extension) should be all uppercased, regardless of `sound` and `music` folders.
The second configuration file is `f2_res.ini`. Use it to change game window size, enable/disable fullscreen mode and configure IFACE settings (the control bar at the bottom of the game screen).
The second configuration file is `f2_res.ini`. Use it to change game window size and enable/disable fullscreen mode.
```ini
[MAIN]
SCR_WIDTH=1280
SCR_HEIGHT=720
WINDOWED=1 ; 0 = fullscreen
SCALE_2X=1 ; 0 = original scale, 1 = 2x - requires increasing the minimum resolution from 640x480 to 1280x960.
[IFACE]
; if IFACE_BAR_MODE=0 - the bottom of the map view window sits at the top of the IFACE Bar.
; if IFACE_BAR_MODE=1 - the bottom of the map view window extends to the base of the screen and is overlapped by the IFACE Bar.
IFACE_BAR_MODE=0
;if IFACE_BAR_SIDE_ART=0 - Black, No Iface-bar side art used.
;if IFACE_BAR_SIDE_ART=1 - Metal (grey) look Iface-bar side art used.
;if IFACE_BAR_SIDE_ART=2 - Leather look Iface-bar side art used.
;if IFACE_BAR_SIDE_ART=3-6 - Alternative Metal look Iface-bar side art used.
;if IFACE_BAR_SIDE_ART=7 - Alternative Leather look Iface-bar side art used.
;if IFACE_BAR_SIDE_ART=8 - Metal (brown) look Iface-bar side art used.
IFACE_BAR_SIDE_ART=2
;if IFACE_BAR_SIDES_ORI=0 - Iface-bar side graphics extend from the Iface-Bar to the Screen edges.
;if IFACE_BAR_SIDES_ORI=1 - Iface-bar side graphics extend from the Screen edges to the Iface-Bar.
IFACE_BAR_SIDES_ORI=0
;This will increase the width of the interface bar expanding the area used to display text.
;if IFACE_BAR_WIDTH=640 - Interface bar will remain at it's original width.
;if IFACE_BAR_WIDTH=800 - Interface bar will use 800pix wide asset from f2_res.dat.
IFACE_BAR_WIDTH=640
WINDOWED=1
```
Recommendations:
@@ -133,19 +110,15 @@ Recommendations:
- **Tablets**: Set these values to logical resolution of your device, for example iPad Pro 11 is 1668x2388 (pixels), but it's logical resolution is 834x1194 (points).
- **Mobile phones**: Set height to 480, calculate width according to your device screen (aspect) ratio, for example Samsung S21 is 20:9 device, so the width should be 480 * 20 / 9 = 1067.
In time this stuff will receive in-game interface, right now you have to do it manually. For a sample f2_res.ini configuration file, containing all currently working settings use this link: [f2_res.ini](https://raw.githubusercontent.com/fallout2-ce/fallout2-ce/refs/heads/mainmenu/files/f2_res.ini)
In time this stuff will receive in-game interface, right now you have to do it manually.
*Note*: use of the IFACE_BAR settings requires the f2_res.dat file, which contains graphical assets. Various versions are available, but one compatible with the above f2_res.ini be found here: [f2_res.dat](https://github.com/fallout2-ce/fallout2-ce/raw/refs/heads/mainmenu/files/f2_res.dat)
The third configuration file is `ddraw.ini` (part of Sfall). There are dozens of options that adjust or override engine behaviour and gameplay mechanics. This file is intended for modders and advanced users.
For a sample ddraw.ini configuration file, containing all currently working settings use this link: [ddraw.ini](https://raw.githubusercontent.com/fallout2-ce/fallout2-ce/refs/heads/main/files/ddraw.ini)
The third configuration file is `ddraw.ini` (part of Sfall). There are dozens of options that adjust or override engine behaviour and gameplay mechanics. This file is intended for modders and advanced users. Currently only a small subset of these settings are actually implemented.
## Contributing
Integrating Sfall goodies is the top priority. Quality of life updates are OK too. Please no large scale refactorings at this time as we need to reconcile changes from Reference Edition, which will make this process slow and error-prone. In any case open up an issue with your suggestion or to notify other people that something is being worked on.
### Integrating Sfall
### Intergrating Sfall
There are literally hundreds if not thousands of fixes and features in sfall. I guess not all of them are needed in Community Edition, but for the sake of compatibility with big mods out there, let's integrate them all.
-207
View File
@@ -1,207 +0,0 @@
;sfall configuration settings for Fallout 2 CE
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[Main]
;Set to one to hide areas outside map bounds when using higher than 640x480 resolution, and to zero to disable
;HiResMode=1
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[Misc]
;Uncomment these lines to change the timers of how many days after the game starts Hakunin dream sequences will occur
;MovieTimer_artimer1=5000
;MovieTimer_artimer2=5000
;MovieTimer_artimer3=5000
;MovieTimer_artimer4=5000
;To start a new game somewhere other than artemple.map, uncomment the next line and set it to the map you want to load
;StartingMap=V13ent.map
;To change the 'FALLOUT II v1.02d' version string on the main menu, uncomment the next line
;You can use up to 2 %d's in this if you want to include Fallout's version number somewhere
;VersionString=FALLOUT II v1.02d
;To use a config file other than fallout2.cfg, uncomment the next line and add the name of your new file
;ConfigFile=
;To use a patch file other than patch000.dat, uncomment the next line and add your new file name
;If you want to load multiple patch files (up to 1000) at once, you can include a %d in the file name (sprintf syntax)
;PatchFile=patch%03d.dat
;Set to 1 to allow using the caret character '^' in dialog msg files to specify alternative text in dialogue based on the player's gender
;The text must be enclosed in angle brackets (example: <MaleText^FemaleText>)
;DialogGenderWords=0
;To change the default and starting player models, uncomment the next four lines.
;The default models can also be changed in-game via script
;MaleStartModel=hmjmps
;MaleDefaultModel=hmjmps
;FemaleStartModel=hfjmps
;FemaleDefaultModel=hfjmps
;To change the starting year, month or day, uncomment the next 3 lines
;Both StartMonth and StartDay are 0-indexed (i.e. 0 is January or the first day of a month)
;StartYear=2241
;StartMonth=01
;StartDay=01
;Set to 1 if you want the pipboy to be available at the start of the game
;Set to 2 to make the pipboy available by only skipping the vault suit movie check
;PipBoyAvailableAtGameStart=1
;Choose the damage formula used to calculate combat damage.
;Don't set this to anything other than 0 unless another mod you're using explicitly tells you to!
;0 - Fallout default
;1 - Glovz's Damage Fix
;2 - Glovz's Damage Fix with Damage Multiplier tweak
;5 - Haenlomal's Yet Another Ammo Mod
;DamageFormula=0
;Prevents you from using 0 to escape from dialogue at any time.
;DialogueFix=1
;Prevents you from using number keys to enter unvisited areas on a town map
TownMapHotkeysFix=1
;Set to 1 to use a CriticalOverrides.ini file to override the default critical table
;Set to 2 to use the default critical with bug fixes (doesn't require an ini)
;Set to 3 to use a new format CriticalOverrides.ini file, with preadded bug fixes
;If the ExtraKillTypes option is enabled, this should be set to 3, with containing entries for any new types
;Must be non-zero to use the edit/get/reset_critical script functions
;OverrideCriticalTable=2
;Set to 1 to get notification of karma changes in the notification window
DisplayKarmaChanges=0
;Set to 1 to skip the 3 opening movies
;Set to 2 to also skip the splash screen
SkipOpeningMovies=0
;Change the Skilldex cursor FRM numbers
;Default is 293 for all skills
Lockpick=293
Steal=293
Traps=293
FirstAid=293
Doctor=293
Science=293
Repair=293
;Uncomment these lines to control the premade characters offered when starting a new game
;Multiple options should be separated by commas, and there must be the same number of entries in both lines
;Each name in PremadePaths is limited to 11 characters
;PremadePaths=combat,diplomat,stealth
;PremadeFIDs=201,203,202
;Use this line to modify the list of cities and their associated global variables used for city reputations
;Syntax is 'city id:global id', with each city/global pair separated by a comma.
;CityRepsList=0:5001,2:5003,3:5004,4:5005,5:5006,6:5007,7:5008,8:5009,10:5011,11:5012,60:1640
;Set this to a valid path to save a copy of the console contents
;ConsoleOutputPath=console.txt
;Set to 1 to add additional pages of save slots !!! can be implemented !!!
;ExtraSaveSlots=1
;To use more than one save slot for quick saving (F6 key) without picking a slot beforehand, set the next two lines
;Quick save will cyclically overwrite saves from the first slot on the specified page to the last slot on the n-th page
;AutoQuickSave sets how many pages you want to use for quick saving (valid range: 1..10)
;Set to 0 to disable
AutoQuickSave=0
;These lines allow you to control the karma FRMs displayed on the character screen
;Number of KarmaPoints should be 1 less than number of KarmaFRMs
;KarmaFRMs=47,48,49
;KarmaPoints=-100,100
;Set to 1 to allow science and repair to be used on the player, or 2 for all critters. (Rather than only brahmin/robots)
ScienceOnCritters=0
;Set to 1 to fix the bug that caused bonus HtH damage to not be applied correctly.
BonusHtHDamageFix=1
;Set to 1 to display additional points of damage from Bonus HtH/Ranged Damage perks in the inventory
;DisplayBonusDamage=1
;Set to 1 to remove the limits that stop the game from rolling critical successes/failures in the first few days of game time
RemoveCriticalTimelimits=0
;Change the colour of the font used on the main menu for the Fallout/sfall version string and copyright text
;It's the last byte ('3C' by default) that picks the colour used. The first byte supplies additional flags for this option
;1 - change the colour for the version string only
;2 - underline text for the version string
;4 - use monospace font for the version string
;MainMenuFontColour=0x000055
;Change the colour of the font used on the main menu for the button text
;MainMenuBigFontColour=0x3C
;Uncomment the next four lines to move the main menu buttons and credit text (the 'Copyright(c)' line on the main menu)
;MainMenuOffsetX=392
;MainMenuOffsetY=26
;MainMenuCreditsOffsetX=0
;MainMenuCreditsOffsetY=0
;These options modify the bullet distribution of burst attacks
;All the bullets are divided into three groups: center, left, and right
;These groups will then travel along three parallel tracks, trying to hit targets on the way
;CenterMult/Div set the ratio of how many bullets go to the center group, and the remaining are divided equally to the left and right sides
;TargetMult/Div set the ratio of how many bullets in the center group will attack the primary target directly
;Multiplier values are capped at divisor values
;ComputeSpray_CenterMult=1
;ComputeSpray_CenterDiv=3
;ComputeSpray_TargetMult=1
;ComputeSpray_TargetDiv=2
;Set to 1 to make explosions and projectiles emit light
;ExplosionsEmitLight=1
;Uncomment these lines to change explosives damage. DmgMax can be set to 9999 at max, and DmgMin is capped at DmgMax
;Dynamite_DmgMax=50
;Dynamite_DmgMin=30
;PlasticExplosive_DmgMax=80
;PlasticExplosive_DmgMin=40
;To add additional game msg files, uncomment the next line and set a comma delimited list of filenames without .msg extension
;By default, the files will have consecutive numbers assigned beginning with 0
;You can use the syntax 'filename:number' to manually assign numbers to specific msg files, with each pair separated by a comma
;If a file after the specified pair does not have a number assigned, it will have the next consecutive number from the last pair
;You need to use the message_str_game script function to get messages from the files
;ExtraGameMsgFileList=
;Set to 1 to display numbered dialogue options
NumbersInDialogue=0
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
; Configuration ini files
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
;To change the path and filename of the critical table file, uncomment the next line
;OverrideCriticalFile=config\CriticalOverrides.ini
;To add additional books to the game, uncomment the next line and point to a file containing book information
;See the Books.ini in the modders pack for an example file
;BooksFile=sfall\Books.ini
;Point to an ini file containing elevator data
;ElevatorsFile=config\Elevators.ini
;Allows you to change the requirements and effects of unarmed attacks
;See the Unarmed.ini in the modders pack for an example file
;UnarmedFile=sfall\Unarmed.ini
;To change some engine parameters for the game mechanics, uncomment the next line
;TweaksFile=sfall\Tweaks.ini
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[Scripts]
;Comma-separated list of masked paths to load global scripts from
;Only use single backslash \ as the directory separator
;Paths outside of scripts folder are supported
;GlobalScriptPaths=scripts\gl_*.int,scripts\sfall\gl*.int
;Uncomment the option to specify an additional directory for ini files used by scripts
;The game will search for ini files first relative to this directory and then relative to the root directory if not found
;The path length is limited to 61 characters
;IniConfigFolder=mods\iniConfigs
BIN
View File
Binary file not shown.
-50
View File
@@ -1,50 +0,0 @@
;hi-res configuration settings for Fallout 2 CE
;##################################################################################################################
[MAIN]
; Set SCALE_2X=1 to scale the game x2.
; Note: This will increase the minimum resolution to from 640x480 to 1280x960.
SCALE_2X=1
; Set the Fullscreen resolution here.
SCR_WIDTH=640
SCR_HEIGHT=480
; Set WINDOWED=1 to enable windowed mode.
WINDOWED=1
;##################################################################################################################
[IFACE]
; if IFACE_BAR_MODE=0 - the bottom of the map view window sits at the top of the IFACE Bar.
; if IFACE_BAR_MODE=1 - the bottom of the map view window extends to the base of the screen and is overlapped by the IFACE Bar.
IFACE_BAR_MODE=0
;if IFACE_BAR_SIDE_ART=0 - Black, No Iface-bar side art used.
;if IFACE_BAR_SIDE_ART=1 - Metal (grey) look Iface-bar side art used.
;if IFACE_BAR_SIDE_ART=2 - Leather look Iface-bar side art used.
;if IFACE_BAR_SIDE_ART=3-6 - Alternative Metal look Iface-bar side art used.
;if IFACE_BAR_SIDE_ART=7 - Alternative Leather look Iface-bar side art used.
;if IFACE_BAR_SIDE_ART=8 - Metal (brown) look Iface-bar side art used.
IFACE_BAR_SIDE_ART=2
;if IFACE_BAR_SIDES_ORI=0 - Iface-bar side graphics extend from the Iface-Bar to the Screen edges.
;if IFACE_BAR_SIDES_ORI=1 - Iface-bar side graphics extend from the Screen edges to the Iface-Bar.
IFACE_BAR_SIDES_ORI=0
;This will increase the width of the interface bar expanding the area used to display text.
;if IFACE_BAR_WIDTH=640 - Interface bar will remain at it's original width.
;if IFACE_BAR_WIDTH=800 - Interface bar will use 800pix wide asset from f2_res.dat. Note
IFACE_BAR_WIDTH=640
;##################################################################################################################
[STATIC_SCREENS]
; if set to 0 - background image will display at its original size.
; if set to 1 - background image will stretch to fit the screen while maintaining its aspect ratio.
; if set to 2 - background image will stretch to fill the screen.
SPLASH_SCRN_SIZE=2
-51
View File
@@ -1,8 +1,6 @@
#include "draw.h"
#include <cstring>
#include <string.h>
#include <vector>
#include "color.h"
#include "svga.h"
@@ -341,53 +339,4 @@ void transSrcCopy(unsigned char* dest, int destPitch, unsigned char* src, int sr
}
}
void blitBufferToBufferStretchAndFixEdges(
unsigned char* src, int srcW, int srcH, int srcPitch,
unsigned char* dst, int dstW, int dstH, int dstPitch,
int numStates)
{
// Temp buffer for over-stretched result (per state)
const int stretchW = dstW + 1;
const int stretchH = dstH + 1;
const int stretchPitch = stretchW;
std::vector<unsigned char> tempBuffer(stretchW * stretchH * numStates);
// Stretch all states to slightly larger temp buffer
blitBufferToBufferStretch(
src, srcW, srcH * numStates, srcPitch,
tempBuffer.data(), stretchW, stretchH * numStates, stretchPitch);
// Now copy only the top-left dstW x dstH portion per state into the final buffer
for (int state = 0; state < numStates; ++state) {
unsigned char* tempFrame = tempBuffer.data() + stretchW * stretchH * state;
unsigned char* finalFrame = dst + dstW * dstH * state;
for (int y = 0; y < dstH; ++y) {
memcpy(
finalFrame + y * dstW,
tempFrame + y * stretchPitch,
dstW);
}
}
}
void calculateScaledSize(int srcWidth, int srcHeight, int targetWidth, int targetHeight, int mode, int& outWidth, int& outHeight)
{
if (mode == 2) {
// Fullscreen stretch
outWidth = targetWidth;
outHeight = targetHeight;
} else {
// Maintain aspect ratio
if (targetHeight * srcWidth >= targetWidth * srcHeight) {
outWidth = targetWidth;
outHeight = (targetWidth * srcHeight) / srcWidth;
} else {
outWidth = (targetHeight * srcWidth) / srcHeight;
outHeight = targetHeight;
}
}
}
} // namespace fallout
-5
View File
@@ -17,11 +17,6 @@ void _swap_color_buf(unsigned char* buf, int width, int height, int pitch, int c
void bufferOutline(unsigned char* buf, int width, int height, int pitch, int a5);
void srcCopy(unsigned char* dest, int destPitch, unsigned char* src, int srcPitch, int width, int height);
void transSrcCopy(unsigned char* dest, int destPitch, unsigned char* src, int srcPitch, int width, int height);
void blitBufferToBufferStretchAndFixEdges(
unsigned char* src, int srcW, int srcH, int srcPitch,
unsigned char* dst, int dstW, int dstH, int dstPitch,
int numStates = 1);
void calculateScaledSize(int srcWidth, int srcHeight, int targetWidth, int targetHeight, int mode, int& outWidth, int& outHeight);
} // namespace fallout
+103 -180
View File
@@ -168,18 +168,13 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int a4
int skipOpeningMovies = 0;
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_SKIP_OPENING_MOVIES_KEY, &skipOpeningMovies);
// load preferences before Splash screen to get proper brightness
if (_init_options_menu() != 0) {
debugPrint("Failed on init_options_menu\n");
return -1;
}
debugPrint(">init_options_menu\n");
if (!gIsMapper && skipOpeningMovies < 2) {
showSplash();
}
#if (defined(__EMSCRIPTEN__) && !defined(NDEBUG))
debugPrint("This is a web build with debug mode so print to the console\n");
#else
// CE: Handle debug mode (exactly as seen in `mapper2.exe`).
const char* debugMode = settings.debug.mode.c_str();
if (compat_stricmp(debugMode, "environment") == 0) {
@@ -193,6 +188,7 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int a4
} else if (compat_stricmp(debugMode, "gnw") == 0) {
_debug_register_func(_win_debug);
}
#endif
interfaceFontsInit();
fontManagerAdd(&gModernFontManager);
@@ -349,7 +345,7 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int a4
debugPrint(">scr_disable\t");
if (_init_options_menu() != 0) {
if (_init_options_menu() != 0) {
debugPrint("Failed on init_options_menu\n");
return -1;
}
@@ -1201,139 +1197,71 @@ static void gameFreeGlobalVars()
// 0x443F74
static void showHelp()
{
ScopedGameMode gm(GameMode::kHelp); // Switch to Help game mode.
ScopedGameMode gm(GameMode::kHelp);
bool isoWasEnabled = isoDisable();
gameMouseObjectsHide();
gameMouseSetCursor(MOUSE_CURSOR_NONE);
bool colorCycleWasEnabled = colorCycleEnabled();
colorCycleDisable();
// load the optional stretch setting from f2_res.ini
int helpScreenStretchMode = 0;
int stretchGameMode = 0;
Config config;
if (configInit(&config)) {
if (configRead(&config, "f2_res.ini", false)) {
configGetInt(&config, "STATIC_SCREENS", "HELP_SCRN_SIZE", &helpScreenStretchMode);
// CE: Help screen uses separate color palette which is incompatible with
// colors in other windows. Setup overlay to hide everything.
int overlay = windowCreate(0, 0, screenGetWidth(), screenGetHeight(), 0, WINDOW_HIDDEN | WINDOW_MOVE_ON_TOP);
if (configGetInt(&config, "STATIC_SCREENS", "STRETCH_GAME", &stretchGameMode)) {
helpScreenStretchMode = stretchGameMode; // always override if key exists
}
}
configFree(&config);
}
int screenWidth = screenGetWidth();
int screenHeight = screenGetHeight();
// Create an invisible fullscreen overlay window to cover everything.
int overlay = windowCreate(0, 0, screenWidth, screenHeight, 0, WINDOW_HIDDEN | WINDOW_MOVE_ON_TOP);
FrmImage helpFrmImage;
int helpFid = buildFid(OBJ_TYPE_INTERFACE, 297, 0, 0, 0); // Load Help screen graphic (FID 297).
if (!helpFrmImage.lock(helpFid)) {
if (colorCycleWasEnabled)
colorCycleEnable();
gameMouseObjectsShow();
if (isoWasEnabled)
isoEnable();
return;
}
unsigned char* helpData = helpFrmImage.getData();
int helpWidth = HELP_SCREEN_WIDTH;
int helpHeight = HELP_SCREEN_HEIGHT;
unsigned char* bufferToBlit = helpData;
int blitWidth = helpWidth;
int blitHeight = helpHeight;
// Check if stretching is needed (based on config or screen too small).
if (helpScreenStretchMode != 0 || screenWidth < helpWidth || screenHeight < helpHeight) {
int scaledWidth, scaledHeight;
calculateScaledSize(
helpWidth,
helpHeight,
screenWidth,
screenHeight,
helpScreenStretchMode,
scaledWidth,
scaledHeight);
// Allocate memory for the scaled image.
unsigned char* scaled = reinterpret_cast<unsigned char*>(internal_malloc((scaledWidth + 1) * (scaledHeight + 1)));
if (scaled != nullptr) {
// Stretch and fix the original help image into the new buffer.
blitBufferToBufferStretchAndFixEdges(
helpData, helpWidth, helpHeight, helpWidth, // Source buffer and dimensions
scaled, scaledWidth, scaledHeight, scaledWidth, // Destination buffer and dimensions
1 // numStates = 1 for a single image
);
bufferToBlit = scaled;
blitWidth = scaledWidth;
blitHeight = scaledHeight;
}
}
// Center the window on the screen.
int x = (screenWidth - blitWidth) / 2;
int y = (screenHeight - blitHeight) / 2;
// Create window for the help screen.
int win = windowCreate(x, y, blitWidth, blitHeight, 0, WINDOW_HIDDEN | WINDOW_MOVE_ON_TOP);
int helpWindowX = (screenGetWidth() - HELP_SCREEN_WIDTH) / 2;
int helpWindowY = (screenGetHeight() - HELP_SCREEN_HEIGHT) / 2;
int win = windowCreate(helpWindowX, helpWindowY, HELP_SCREEN_WIDTH, HELP_SCREEN_HEIGHT, 0, WINDOW_HIDDEN | WINDOW_MOVE_ON_TOP);
if (win != -1) {
unsigned char* windowBuffer = windowGetBuffer(win);
if (windowBuffer != nullptr) {
// Clear palette to black before displaying.
paletteSetEntries(gPaletteBlack);
FrmImage backgroundFrmImage;
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 297, 0, 0, 0);
if (backgroundFrmImage.lock(backgroundFid)) {
paletteSetEntries(gPaletteBlack);
blitBufferToBuffer(backgroundFrmImage.getData(), HELP_SCREEN_WIDTH, HELP_SCREEN_HEIGHT, HELP_SCREEN_WIDTH, windowBuffer, HELP_SCREEN_WIDTH);
// Copy the help image into the window.
blitBufferToBuffer(bufferToBlit, blitWidth, blitHeight, blitWidth, windowBuffer, blitWidth);
colorPaletteLoad("art\\intrface\\helpscrn.pal");
paletteSetEntries(_cmap);
// Load the help screen's specific palette.
colorPaletteLoad("art\\intrface\\helpscrn.pal");
paletteSetEntries(_cmap);
// CE: Fill overlay with darkest color in the palette. It might
// not be completely black, but at least it's uniform.
bufferFill(windowGetBuffer(overlay),
screenGetWidth(),
screenGetHeight(),
screenGetWidth(),
intensityColorTable[_colorTable[0]][0]);
// Fill the overlay with the darkest palette color to hide everything behind.
bufferFill(windowGetBuffer(overlay), screenWidth, screenHeight, screenWidth, intensityColorTable[_colorTable[0]][0]);
windowShow(overlay);
windowShow(win);
windowShow(overlay);
windowShow(win);
while (inputGetInput() == -1 && _game_user_wants_to_quit == 0) {
sharedFpsLimiter.mark();
renderPresent();
sharedFpsLimiter.throttle();
}
while (inputGetInput() == -1 && _game_user_wants_to_quit == 0) {
sharedFpsLimiter.mark();
renderPresent();
sharedFpsLimiter.throttle();
while (mouseGetEvent() != 0) {
sharedFpsLimiter.mark();
inputGetInput();
renderPresent();
sharedFpsLimiter.throttle();
}
paletteSetEntries(gPaletteBlack);
}
while (mouseGetEvent() != 0) {
sharedFpsLimiter.mark();
inputGetInput();
renderPresent();
sharedFpsLimiter.throttle();
}
// Fade back to black.
paletteSetEntries(gPaletteBlack);
}
// Cleanup
windowDestroy(overlay);
windowDestroy(win);
colorPaletteLoad("color.pal");
paletteSetEntries(_cmap);
}
// Free temporary scaled buffer if it was allocated.
if (bufferToBlit != helpData) {
internal_free(bufferToBlit);
}
// Restore previous state.
if (colorCycleWasEnabled) {
colorCycleEnable();
}
@@ -1447,7 +1375,7 @@ static int gameDbInit()
char* path_file_name_template = nullptr;
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_PATCH_FILE, &path_file_name_template);
if (path_file_name_template == nullptr || *path_file_name_template == '\0') {
path_file_name_template = "patch%03d.dat";
path_file_name_template = (char*)"patch%03d.dat";
}
for (patch_index = 0; patch_index < 1000; patch_index++) {
@@ -1470,9 +1398,8 @@ static int gameDbInit()
// 0x444384
static void showSplash()
{
int splashIndex = settings.system.splash;
int splash = settings.system.splash;
// path to local splash folder
char path[64];
const char* language = settings.system.language.c_str();
if (compat_stricmp(language, ENGLISH) != 0) {
@@ -1481,19 +1408,19 @@ static void showSplash()
snprintf(path, sizeof(path), "art\\splash\\");
}
// open a splash file, cycle through SPLASH_COUNT entries
File* stream = nullptr;
for (int attempt = 0; attempt < SPLASH_COUNT; attempt++) {
File* stream;
for (int index = 0; index < SPLASH_COUNT; index++) {
char filePath[64];
snprintf(filePath, sizeof(filePath), "%ssplash%d.rix", path, splashIndex);
snprintf(filePath, sizeof(filePath), "%ssplash%d.rix", path, splash);
stream = fileOpen(filePath, "rb");
if (stream != nullptr) {
break;
}
splashIndex++;
if (splashIndex >= SPLASH_COUNT) {
splashIndex = 0;
splash++;
if (splash >= SPLASH_COUNT) {
splash = 0;
}
}
@@ -1501,109 +1428,105 @@ static void showSplash()
return;
}
// Allocate memory for the palette
unsigned char* palette = reinterpret_cast<unsigned char*>(internal_malloc(768));
if (palette == nullptr) {
fileClose(stream);
return;
}
// Verify RIX image version (needed?)
int version;
fileReadInt32(stream, &version);
if (version != 'RIX3') {
fileClose(stream);
internal_free(palette);
return;
}
// Read image dimensions
short splashWidth, splashHeight;
fileRead(&splashWidth, sizeof(splashWidth), 1, stream);
fileRead(&splashHeight, sizeof(splashHeight), 1, stream);
short width;
fileRead(&width, sizeof(width), 1, stream);
// Allocate memory for the image pixel data
unsigned char* splashData = reinterpret_cast<unsigned char*>(internal_malloc(splashWidth * splashHeight));
if (splashData == nullptr) {
short height;
fileRead(&height, sizeof(height), 1, stream);
unsigned char* data = reinterpret_cast<unsigned char*>(internal_malloc(width * height));
if (data == nullptr) {
internal_free(palette);
fileClose(stream);
return;
}
// Load palette and image data
paletteSetEntries(gPaletteBlack);
fileSeek(stream, 10, SEEK_SET);
fileRead(palette, 1, 768, stream);
fileRead(splashData, 1, splashWidth * splashHeight, stream);
fileRead(data, 1, width * height, stream);
fileClose(stream);
int splashScreenStretchMode = 0;
int stretchGameMode = 0;
// Fix of wrong Palette, without it this makes background bright
// Basically just swapping first and last colors, this problem presented ONLY in F2, F1 has right palette in every splash
memcpy(palette + (255 * 3), palette, 3);
memset(palette, 0, 3);
for (int i = 0; i < width * height; i++) {
if (data[i] == 0) {
data[i] = 255;
} else if (data[i] == 255) {
data[i] = 0;
}
}
int size = 0;
// TODO: Move to settings.
Config config;
if (configInit(&config)) {
if (configRead(&config, "f2_res.ini", false)) {
configGetInt(&config, "STATIC_SCREENS", "SPLASH_SCRN_SIZE", &splashScreenStretchMode);
if (configGetInt(&config, "STATIC_SCREENS", "STRETCH_GAME", &stretchGameMode)) {
splashScreenStretchMode = stretchGameMode; // always override if key exists
}
configGetInt(&config, "STATIC_SCREENS", "SPLASH_SCRN_SIZE", &size);
}
configFree(&config);
}
int screenWidth = screenGetWidth();
int screenHeight = screenGetHeight();
// Stretch image if required or if it doesn't fit the screen
if (splashScreenStretchMode != 0 || screenWidth < splashWidth || screenHeight < splashHeight) {
int scaledWidth, scaledHeight;
if (size != 0 || screenWidth < width || screenHeight < height) {
int scaledWidth;
int scaledHeight;
calculateScaledSize(
splashWidth,
splashHeight,
screenWidth,
screenHeight,
splashScreenStretchMode,
scaledWidth,
scaledHeight);
if (size == 2) {
scaledWidth = screenWidth;
scaledHeight = screenHeight;
} else {
if (screenHeight * width >= screenWidth * height) {
scaledWidth = screenWidth;
scaledHeight = screenWidth * height / width;
} else {
scaledWidth = screenHeight * width / height;
scaledHeight = screenHeight;
}
}
unsigned char* scaled = reinterpret_cast<unsigned char*>(internal_malloc((scaledWidth) * (scaledHeight)));
unsigned char* scaled = reinterpret_cast<unsigned char*>(internal_malloc(scaledWidth * scaledHeight));
if (scaled != nullptr) {
// Stretch the splash screen and fix edge artifacts
blitBufferToBufferStretchAndFixEdges(
splashData,
splashWidth,
splashHeight,
splashWidth,
scaled,
scaledWidth,
scaledHeight,
scaledWidth,
1 // numStates = 1 for a single splash image
);
int x = (screenWidth > scaledWidth) ? (screenWidth - scaledWidth) / 2 : 0;
int y = (screenHeight > scaledHeight) ? (screenHeight - scaledHeight) / 2 : 0;
blitBufferToBufferStretch(data, width, height, width, scaled, scaledWidth, scaledHeight, scaledWidth);
int x = screenWidth > scaledWidth ? (screenWidth - scaledWidth) / 2 : 0;
int y = screenHeight > scaledHeight ? (screenHeight - scaledHeight) / 2 : 0;
_scr_blit(scaled, scaledWidth, scaledHeight, 0, 0, scaledWidth, scaledHeight, x, y);
paletteFadeTo(palette);
internal_free(scaled);
}
} else {
// Center image without scaling
int x = (screenWidth - splashWidth) / 2;
int y = (screenHeight - splashHeight) / 2;
_scr_blit(splashData, splashWidth, splashHeight, 0, 0, splashWidth, splashHeight, x, y);
int x = (screenWidth - width) / 2;
int y = (screenHeight - height) / 2;
_scr_blit(data, width, height, 0, 0, width, height, x, y);
paletteFadeTo(palette);
}
// Clean up
internal_free(splashData);
internal_free(data);
internal_free(palette);
// Save index for next splash image
settings.system.splash = splashIndex + 1;
settings.system.splash = splash + 1;
}
int gameShowDeathDialog(const char* message)
+8 -46
View File
@@ -548,8 +548,6 @@ static FrmImage _redButtonNormalFrmImage;
static FrmImage _redButtonPressedFrmImage;
static FrmImage _lowerHighlightFrmImage;
static FrmImage _upperHighlightFrmImage;
static FrmImage _littleRedButtonNormalFrmImage;
static FrmImage _littleRedButtonPressedFrmImage;
static int _gdialogReset();
static void gameDialogEndLips();
@@ -625,9 +623,7 @@ static void gameDialogHighlightsInit();
static void gameDialogHighlightsExit();
static void gameDialogRedButtonsInit();
static void gameDialogLittleRedButtonsInit();
static void gameDialogRedButtonsExit();
static void gameDialogLittleRedButtonsExit();
static bool gGameDialogFix;
static bool gNumberOptions;
@@ -918,7 +914,6 @@ int _gdialogInitFromScript(int headFid, int reaction)
// CE: Fix Barter button.
gameDialogRedButtonsInit();
gameDialogLittleRedButtonsInit();
_gdCreateHeadWindow();
tickersAdd(gameDialogTicker);
@@ -971,7 +966,6 @@ int _gdialogExitFromScript()
// CE: Fix Barter button.
gameDialogRedButtonsExit();
gameDialogLittleRedButtonsExit();
fontSetCurrent(_oldFont);
@@ -3413,7 +3407,7 @@ int partyMemberControlWindowInit()
partyMemberControlWindowFree();
return -1;
}
buttonSetCallbacks(_gdialog_buttons[2], _gsound_med_butt_press, _gsound_med_butt_release);
buttonSetCallbacks(_gdialog_buttons[1], _gsound_med_butt_press, _gsound_med_butt_release);
// USE BEST ARMOR
_gdialog_buttons[3] = buttonCreate(gGameDialogWindow, 235, 46, 14, 14, -1, -1, -1, KEY_LOWERCASE_A, _redButtonNormalFrmImage.getData(), _redButtonPressedFrmImage.getData(), nullptr, BUTTON_FLAG_TRANSPARENT);
@@ -3421,7 +3415,7 @@ int partyMemberControlWindowInit()
partyMemberControlWindowFree();
return -1;
}
buttonSetCallbacks(_gdialog_buttons[3], _gsound_med_butt_press, _gsound_med_butt_release);
buttonSetCallbacks(_gdialog_buttons[2], _gsound_med_butt_press, _gsound_med_butt_release);
_control_buttons_start = 4;
@@ -3890,7 +3884,7 @@ int partyMemberCustomizationWindowInit()
return -1;
}
buttonSetCallbacks(_gdialog_buttons[optionButton], _gsound_med_butt_press, _gsound_med_butt_release);
buttonSetCallbacks(_gdialog_buttons[index], _gsound_med_butt_press, _gsound_med_butt_release);
}
_custom_current_selected[PARTY_MEMBER_CUSTOMIZATION_OPTION_AREA_ATTACK_MODE] = aiGetAreaAttackMode(gGameDialogSpeaker);
@@ -4125,25 +4119,18 @@ int _gdCustomSelect(int a1)
backgroundFrmImage.unlock();
int btn1 = buttonCreate(win, 70, 164, _littleRedButtonNormalFrmImage.getWidth(), _littleRedButtonNormalFrmImage.getHeight(), -1, -1, -1, 500, _littleRedButtonNormalFrmImage.getData(), _littleRedButtonPressedFrmImage.getData(), nullptr, BUTTON_FLAG_TRANSPARENT);
int btn1 = buttonCreate(win, 70, 164, 14, 14, -1, -1, -1, KEY_RETURN, _redButtonNormalFrmImage.getData(), _redButtonPressedFrmImage.getData(), nullptr, BUTTON_FLAG_TRANSPARENT);
if (btn1 == -1) {
windowDestroy(win);
return -1;
}
if (btn1 != -1) {
buttonSetCallbacks(btn1, _gsound_red_butt_press, _gsound_red_butt_release);
}
int btn2 = buttonCreate(win, 176, 163, _littleRedButtonNormalFrmImage.getWidth(), _littleRedButtonNormalFrmImage.getHeight(), -1, -1, -1, KEY_ESCAPE, _littleRedButtonNormalFrmImage.getData(), _littleRedButtonPressedFrmImage.getData(), nullptr, BUTTON_FLAG_TRANSPARENT);
int btn2 = buttonCreate(win, 176, 163, 14, 14, -1, -1, -1, KEY_ESCAPE, _redButtonNormalFrmImage.getData(), _redButtonPressedFrmImage.getData(), nullptr, BUTTON_FLAG_TRANSPARENT);
if (btn2 == -1) {
windowDestroy(win);
return -1;
}
if (btn2 != -1) {
buttonSetCallbacks(btn2, _gsound_red_butt_press, _gsound_red_butt_release);
}
fontSetCurrent(103);
MessageListItem messageListItem;
@@ -4182,13 +4169,10 @@ int _gdCustomSelect(int a1)
break;
}
if (keyCode == KEY_RETURN || keyCode == 500) {
if (keyCode == KEY_RETURN) {
STRUCT_5189E4* ptr = &(_custom_settings[a1][value]);
_custom_current_selected[a1] = value;
_gdCustomUpdateSetting(a1, ptr->value);
if (keyCode != 500){
soundPlayFile("ib1p1xx1");
}
done = true;
} else if (keyCode == KEY_ESCAPE) {
done = true;
@@ -4362,9 +4346,6 @@ int _gdialog_window_create()
// TODO: Not sure about offsets.
blitBufferToBuffer(bgWindowBuf + screenWidth * (GAME_DIALOG_WINDOW_HEIGHT - _dialogue_subwin_len), screenWidth, _dialogue_subwin_len, screenWidth, windowBuf, screenWidth);
// BARTER/TRADE - button moved here to set above background window
_gdialog_buttons[0] = buttonCreate(gGameDialogWindow, 593, 41, 14, 14, -1, -1, -1, -1, _redButtonNormalFrmImage.getData(), _redButtonPressedFrmImage.getData(), nullptr, BUTTON_FLAG_TRANSPARENT);
if (_dialogue_just_started) {
windowRefresh(gGameDialogBackgroundWindow);
_gdialog_scroll_subwin(gGameDialogWindow, true, backgroundFrmData, windowBuf, nullptr, _dialogue_subwin_len, true);
@@ -4373,6 +4354,8 @@ int _gdialog_window_create()
_gdialog_scroll_subwin(gGameDialogWindow, true, backgroundFrmData, windowBuf, nullptr, _dialogue_subwin_len, false);
}
// BARTER/TRADE
_gdialog_buttons[0] = buttonCreate(gGameDialogWindow, 593, 41, 14, 14, -1, -1, -1, -1, _redButtonNormalFrmImage.getData(), _redButtonPressedFrmImage.getData(), nullptr, BUTTON_FLAG_TRANSPARENT);
if (_gdialog_buttons[0] != -1) {
buttonSetMouseCallbacks(_gdialog_buttons[0], nullptr, nullptr, nullptr, gameDialogBarterButtonUpMouseUp);
buttonSetCallbacks(_gdialog_buttons[0], _gsound_med_butt_press, _gsound_med_butt_release);
@@ -4741,27 +4724,6 @@ static void gameDialogRedButtonsInit()
}
}
static void gameDialogLittleRedButtonsInit()
{
// di_rdbt2.frm - dialog red button up
int normalFid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0);
if (!_littleRedButtonNormalFrmImage.lock(normalFid)) {
gameDialogLittleRedButtonsExit();
}
// di_rdbt1.frm - dialog red button down
int pressedFid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0);
if (!_littleRedButtonPressedFrmImage.lock(pressedFid)) {
gameDialogLittleRedButtonsExit();
}
}
static void gameDialogLittleRedButtonsExit()
{
_littleRedButtonNormalFrmImage.unlock();
_littleRedButtonPressedFrmImage.unlock();
}
static void gameDialogRedButtonsExit()
{
_redButtonNormalFrmImage.unlock();
+2 -11
View File
@@ -21,7 +21,6 @@
#include "queue.h"
#include "random.h"
#include "settings.h"
#include "sfall_config.h"
#include "sound_effects_cache.h"
#include "stat.h"
#include "svga.h"
@@ -746,17 +745,9 @@ int backgroundSoundLoad(const char* fileName, int a2, int a3, int a4)
}
// 0x450A08
int _gsound_background_play_level_music(const char* fileName, int a2)
int _gsound_background_play_level_music(const char* a1, int a2)
{
int gaplessMusic = 0;
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_GAPLESS_MUSIC, &gaplessMusic);
if (gaplessMusic) {
if (!strcmp(fileName, gBackgroundSoundFileName)) {
return 0;
}
}
return backgroundSoundLoad(fileName, a2, 14, 16);
return backgroundSoundLoad(a1, a2, 14, 16);
}
// 0x450AB4
+26 -82
View File
@@ -553,15 +553,6 @@ static int inventoryMessageListFree()
return 0;
}
// Helper function to flip the button buffer horizontally
void flipBufferHorizontally(unsigned char* src, int width, int height, int pitch) {
for (int y = 0; y < height; y++) {
for (int x = 0; x < width / 2; x++) {
std::swap(src[y * pitch + x], src[y * pitch + (width - 1 - x)]);
}
}
}
// 0x46E7B0
void inventoryOpen()
{
@@ -1018,105 +1009,60 @@ static bool _setup_inventory(int inventoryWindowType)
int fid;
int btn;
fid = buildFid(OBJ_TYPE_INTERFACE, 299, 0, 0, 0);
fid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0);
_inventoryFrmImages[0].lock(fid);
fid = buildFid(OBJ_TYPE_INTERFACE, 300, 0, 0, 0);
fid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0);
_inventoryFrmImages[1].lock(fid);
// Inventory, Use On, and Loot screens have incorrect buttons
// Game currently doesn't have the correct button resource
// We are going to scale and flip the menu buttons as a temporary solution
// Base button dimensions
int buttonBaseWidth = 26;
int buttonBaseHeight = 26;
int buttonWidth = 21;
int buttonHeight = 21;
unsigned char* scaledNormal = reinterpret_cast<unsigned char*>(SDL_malloc(21 * 21));
unsigned char* scaledPressed = reinterpret_cast<unsigned char*>(SDL_malloc(21 * 21));
if (!scaledNormal || !scaledPressed) {
return -1;
}
// Create flipped copies (to align highlights to top right light source)
unsigned char* flippedNormal = reinterpret_cast<unsigned char*>(SDL_malloc(buttonBaseWidth * buttonBaseHeight));
unsigned char* flippedPressed = reinterpret_cast<unsigned char*>(SDL_malloc(buttonBaseWidth * buttonBaseHeight));
if (!flippedNormal || !flippedPressed) {
return -1;
}
// Copy and flip the original images
memcpy(flippedNormal, _inventoryFrmImages[0].getData(), buttonBaseWidth * buttonBaseHeight);
memcpy(flippedPressed, _inventoryFrmImages[1].getData(), buttonBaseWidth * buttonBaseHeight);
// Flip them with the helper
flipBufferHorizontally(flippedNormal, buttonBaseWidth, buttonBaseHeight, buttonBaseWidth);
flipBufferHorizontally(flippedPressed, buttonBaseWidth, buttonBaseHeight, buttonBaseWidth);
// Use the flipped buffers as source and scale them
blitBufferToBufferStretchAndFixEdges(
flippedNormal, buttonBaseWidth, buttonBaseHeight, buttonBaseWidth,
scaledNormal, buttonWidth, buttonHeight, buttonWidth);
blitBufferToBufferStretchAndFixEdges(
flippedPressed, buttonBaseWidth, buttonBaseHeight, buttonBaseWidth,
scaledPressed, buttonWidth, buttonHeight, buttonWidth);
// Free the temp buffers
SDL_free(flippedNormal);
SDL_free(flippedPressed);
if (_inventoryFrmImages[0].isLocked() && _inventoryFrmImages[1].isLocked()) {
btn = -1;
switch (inventoryWindowType) {
case INVENTORY_WINDOW_TYPE_NORMAL:
// Done button
btn = buttonCreate(gInventoryWindow,
434,
325,
21,
21,
437,
329,
15,
16,
-1,
-1,
-1,
KEY_ESCAPE,
scaledNormal, // scaled and flipped button
scaledPressed, // scaled and flipped button
_inventoryFrmImages[0].getData(),
_inventoryFrmImages[1].getData(),
nullptr,
BUTTON_FLAG_TRANSPARENT);
break;
case INVENTORY_WINDOW_TYPE_USE_ITEM_ON:
// Cancel button
btn = buttonCreate(gInventoryWindow,
230,
325,
21,
21,
233,
328,
15,
16,
-1,
-1,
-1,
KEY_ESCAPE,
scaledNormal, // scaled and flipped button
scaledPressed, // scaled and flipped button
_inventoryFrmImages[0].getData(),
_inventoryFrmImages[1].getData(),
nullptr,
BUTTON_FLAG_TRANSPARENT);
break;
case INVENTORY_WINDOW_TYPE_LOOT:
// Done button
btn = buttonCreate(gInventoryWindow,
473,
327,
21,
21,
476,
331,
15,
16,
-1,
-1,
-1,
KEY_ESCAPE,
scaledNormal, // scaled and flipped button
scaledPressed, // scaled and flipped button
_inventoryFrmImages[0].getData(),
_inventoryFrmImages[1].getData(),
nullptr,
BUTTON_FLAG_TRANSPARENT);
break;
@@ -5692,17 +5638,15 @@ static int inventoryQuantitySelect(int inventoryWindowType, Object* item, int ma
return -1;
}
if (keyCode == KEY_RETURN || keyCode == 500) {
if (keyCode == KEY_RETURN) {
if (value >= min && value <= max) {
if (inventoryWindowType != INVENTORY_WINDOW_TYPE_SET_TIMER || value % 10 == 0) {
if (keyCode != 500) {
soundPlayFile("ib1p1xx1");
}
soundPlayFile("ib1p1xx1");
break;
}
} else {
soundPlayFile("iisxxxx1");
}
break;
soundPlayFile("iisxxxx1");
} else if (keyCode == 5000) {
isTyping = false;
value = max;
@@ -5963,7 +5907,7 @@ static int inventoryQuantityWindowInit(int inventoryWindowType, Object* item)
-1,
-1,
-1,
500,
KEY_RETURN,
_moveFrmImages[4].getData(),
_moveFrmImages[5].getData(),
nullptr,
+25 -30
View File
@@ -50,10 +50,10 @@ static int stealthBoyTurnOff(Object* critter, Object* item);
static int _insert_drug_effect(Object* critter, Object* item, int duration, int* stats, int* mods);
static void _perform_drug_effect(Object* critter, int* stats, int* mods, bool isImmediate);
static bool _drug_effect_allowed(Object* critter, int pid);
static int _insert_withdrawal(Object* obj, int active, int duration, int perk, int pid);
static int _item_wd_clear_all(Object* obj, void* data);
static void performWithdrawalStart(Object* obj, int perk, int pid);
static void performWithdrawalEnd(Object* obj, int perk);
static int _insert_withdrawal(Object* obj, int a2, int a3, int a4, int a5);
static int _item_wd_clear_all(Object* a1, void* data);
static void performWithdrawalStart(Object* obj, int perk, int a3);
static void performWithdrawalEnd(Object* obj, int a2);
static int drugGetAddictionGvarByPid(int drugPid);
static void dudeSetAddiction(int drugPid);
static void dudeClearAddiction(int drugPid);
@@ -1550,9 +1550,6 @@ bool weaponCanBeReloadedWith(Object* weapon, Object* ammo)
}
// 0x478918
// weaponReload adds ammo to the weapon and removes it from the given ammo stack
// return -1 if ammo is incompatible with weapon; otherwise returns the number of
// rounds left in the ammo stack
int weaponReload(Object* weapon, Object* ammo)
{
if (!weaponCanBeReloadedWith(weapon, ammo)) {
@@ -1571,26 +1568,26 @@ int weaponReload(Object* weapon, Object* ammo)
}
// NOTE: Uninline.
int quantity = ammoGetQuantity(ammo);
int v10 = ammoGetQuantity(ammo);
int left = quantity;
int v11 = v10;
if (ammoQuantity < ammoCapacity) {
int newQuantity;
if (ammoQuantity + quantity > ammoCapacity) {
left = quantity - (ammoCapacity - ammoQuantity);
newQuantity = ammoCapacity;
int v12;
if (ammoQuantity + v10 > ammoCapacity) {
v11 = v10 - (ammoCapacity - ammoQuantity);
v12 = ammoCapacity;
} else {
left = 0;
newQuantity = ammoQuantity + quantity;
v11 = 0;
v12 = ammoQuantity + v10;
}
weapon->data.item.weapon.ammoTypePid = ammo->pid;
ammoSetQuantity(ammo, left);
ammoSetQuantity(weapon, newQuantity);
ammoSetQuantity(ammo, v11);
ammoSetQuantity(weapon, v12);
}
return left;
return v11;
}
// 0x478A1C
@@ -2917,14 +2914,14 @@ int drugEffectEventWrite(File* stream, void* data)
}
// 0x47A290
static int _insert_withdrawal(Object* obj, int active, int duration, int perk, int pid)
static int _insert_withdrawal(Object* obj, int a2, int duration, int perk, int pid)
{
WithdrawalEvent* withdrawalEvent = (WithdrawalEvent*)internal_malloc(sizeof(*withdrawalEvent));
if (withdrawalEvent == nullptr) {
return -1;
}
withdrawalEvent->active = active;
withdrawalEvent->field_0 = a2;
withdrawalEvent->pid = pid;
withdrawalEvent->perk = perk;
@@ -2945,7 +2942,7 @@ int _item_wd_clear(Object* obj, void* data)
return 0;
}
if (!withdrawalEvent->active) {
if (!withdrawalEvent->field_0) {
performWithdrawalEnd(obj, withdrawalEvent->perk);
}
@@ -2953,11 +2950,11 @@ int _item_wd_clear(Object* obj, void* data)
}
// 0x47A324
static int _item_wd_clear_all(Object* obj, void* data)
static int _item_wd_clear_all(Object* a1, void* data)
{
WithdrawalEvent* withdrawalEvent = (WithdrawalEvent*)data;
if (obj != _wd_obj) {
if (a1 != _wd_obj) {
return 0;
}
@@ -2965,12 +2962,11 @@ static int _item_wd_clear_all(Object* obj, void* data)
return 0;
}
if (!withdrawalEvent->active) {
if (!withdrawalEvent->field_0) {
performWithdrawalEnd(_wd_obj, withdrawalEvent->perk);
}
// schedule start of withdrawal
_insert_withdrawal(obj, 1, _wd_onset, withdrawalEvent->perk, withdrawalEvent->pid);
_insert_withdrawal(a1, 1, _wd_onset, withdrawalEvent->perk, withdrawalEvent->pid);
_wd_obj = nullptr;
@@ -2982,7 +2978,7 @@ int withdrawalEventProcess(Object* obj, void* data)
{
WithdrawalEvent* withdrawalEvent = (WithdrawalEvent*)data;
if (withdrawalEvent->active) {
if (withdrawalEvent->field_0) {
performWithdrawalStart(obj, withdrawalEvent->perk, withdrawalEvent->pid);
} else {
if (withdrawalEvent->perk == PERK_JET_ADDICTION) {
@@ -3013,7 +3009,7 @@ int withdrawalEventRead(File* stream, void** dataPtr)
return -1;
}
if (fileReadInt32(stream, &(withdrawalEvent->active)) == -1) goto err;
if (fileReadInt32(stream, &(withdrawalEvent->field_0)) == -1) goto err;
if (fileReadInt32(stream, &(withdrawalEvent->pid)) == -1) goto err;
if (fileReadInt32(stream, &(withdrawalEvent->perk)) == -1) goto err;
@@ -3031,7 +3027,7 @@ int withdrawalEventWrite(File* stream, void* data)
{
WithdrawalEvent* withdrawalEvent = (WithdrawalEvent*)data;
if (fileWriteInt32(stream, withdrawalEvent->active) == -1) return -1;
if (fileWriteInt32(stream, withdrawalEvent->field_0) == -1) return -1;
if (fileWriteInt32(stream, withdrawalEvent->pid) == -1) return -1;
if (fileWriteInt32(stream, withdrawalEvent->perk) == -1) return -1;
@@ -3068,7 +3064,6 @@ static void performWithdrawalStart(Object* obj, int perk, int pid)
}
}
// schedule end of withdrawal
_insert_withdrawal(obj, 0, duration, perk, pid);
}
+7 -7
View File
@@ -49,13 +49,13 @@ bool dudeIsWeaponDisabled(Object* weapon);
int itemGetInventoryFid(Object* obj);
Object* critterGetWeaponForHitMode(Object* critter, int hitMode);
int itemGetActionPointCost(Object* obj, int hitMode, bool aiming);
int itemGetQuantity(Object* obj, Object* item);
int itemGetQuantity(Object* obj, Object* a2);
int itemIsQueued(Object* obj);
Object* itemReplace(Object* owner, Object* itemToReplace, int flags);
Object* itemReplace(Object* a1, Object* a2, int a3);
bool itemIsHidden(Object* obj);
int weaponGetAttackTypeForHitMode(Object* weapon, int hitMode);
int weaponGetSkillForHitMode(Object* weapon, int hitMode);
int weaponGetSkillValue(Object* critter, int hitMode);
int weaponGetAttackTypeForHitMode(Object* a1, int a2);
int weaponGetSkillForHitMode(Object* a1, int a2);
int weaponGetSkillValue(Object* a1, int a2);
int weaponGetDamageMinMax(Object* weapon, int* minDamagePtr, int* maxDamagePtr);
int weaponGetDamage(Object* critter, int hitMode);
int weaponGetDamageType(Object* critter, Object* weapon);
@@ -123,14 +123,14 @@ int _item_d_clear(Object* obj, void* data);
int drugEffectEventProcess(Object* obj, void* data);
int drugEffectEventRead(File* stream, void** dataPtr);
int drugEffectEventWrite(File* stream, void* data);
int _item_wd_clear(Object* obj, void* data);
int _item_wd_clear(Object* obj, void* a2);
int withdrawalEventProcess(Object* obj, void* data);
int withdrawalEventRead(File* stream, void** dataPtr);
int withdrawalEventWrite(File* stream, void* data);
int itemGetTotalCaps(Object* obj);
int itemCapsAdjust(Object* obj, int amount);
int itemGetMoney(Object* obj);
int itemSetMoney(Object* obj, int amount);
int itemSetMoney(Object* obj, int a2);
bool booksGetInfo(int bookPid, int* messageIdPtr, int* skillPtr);
bool explosionEmitsLight();
+8 -18
View File
@@ -359,6 +359,8 @@ void _InitLoadSave()
if (quickSaveSlots > 0 && quickSaveSlots <= saveLoadTotalSlots) {
autoQuickSaveSlots = true;
}
pipboyMessageListInit();
}
// 0x47B85C
@@ -459,8 +461,6 @@ int lsgSaveGame(int mode)
return -1;
}
pipboyMessageListInit();
if (_GetSlotList() == -1) {
windowRefresh(gLoadSaveWindow);
@@ -941,8 +941,6 @@ int lsgSaveGame(int mode)
lsgWindowFree(LOAD_SAVE_WINDOW_TYPE_SAVE_GAME);
pipboyMessageListFree();
tileWindowRefresh();
if (mode == LOAD_SAVE_MODE_QUICK) {
@@ -1085,8 +1083,6 @@ int lsgLoadGame(int mode)
return -1;
}
pipboyMessageListInit();
if (_GetSlotList() == -1) {
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
windowRefresh(gLoadSaveWindow);
@@ -1476,8 +1472,6 @@ int lsgLoadGame(int mode)
? LOAD_SAVE_WINDOW_TYPE_LOAD_GAME_FROM_MAIN_MENU
: LOAD_SAVE_WINDOW_TYPE_LOAD_GAME);
pipboyMessageListFree();
if (mode == LOAD_SAVE_MODE_QUICK) {
if (rc == 1) {
_quick_done = true;
@@ -2303,11 +2297,9 @@ static void _ShowSlotList(int windowType)
int inactiveColor = _colorTable[8804];
{
MessageListItem messageListItemBack = { 201, 0, nullptr, nullptr };
if (!messageListGetItem(&gPipboyMessageList, &messageListItemBack)) {
debugPrint("Error: Couldn't find LoadSave Message!");
messageListItemBack.text = "BACK";
}
MessageListItem messageListItemBack;
messageListItemBack.num = 201; // Back
messageListGetItem(&gPipboyMessageList, &messageListItemBack);
fontDrawText(
gLoadSaveWindowBuffer + LS_WINDOW_WIDTH * (y + 0) + 95,
messageListItemBack.text,
@@ -2316,11 +2308,9 @@ static void _ShowSlotList(int windowType)
_currentSlotPage > 0 ? activeColor : inactiveColor);
}
{
MessageListItem messageListItemMore = { 200, 0, nullptr, nullptr };
if (!messageListGetItem(&gPipboyMessageList, &messageListItemMore)) {
debugPrint("Error: Couldn't find LoadSave Message!");
messageListItemMore.text = "MORE";
}
MessageListItem messageListItemMore;
messageListItemMore.num = 200; // More
messageListGetItem(&gPipboyMessageList, &messageListItemMore);
fontDrawText(gLoadSaveWindowBuffer + LS_WINDOW_WIDTH * (y + 0) + 210,
messageListItemMore.text,
LS_WINDOW_WIDTH,
+2 -11
View File
@@ -36,7 +36,6 @@
#include "random.h"
#include "scripts.h"
#include "settings.h"
#include "sfall_config.h"
#include "svga.h"
#include "text_object.h"
#include "tile.h"
@@ -820,11 +819,7 @@ int mapLoadById(int map)
static int mapLoad(File* stream)
{
_map_save_in_game(true);
int gaplessMusic = 0;
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_GAPLESS_MUSIC, &gaplessMusic);
if (!gaplessMusic) {
backgroundSoundLoad("wind2", 12, 13, 16);
}
backgroundSoundLoad("wind2", 12, 13, 16);
isoDisable();
_partyMemberPrepLoad();
_gmouse_disable_scrolling();
@@ -1253,16 +1248,12 @@ int mapHandleTransition()
if (gMapTransition.map == -1) {
if (!isInCombat()) {
animationStop();
// SFALL: Remove text floaters when moving to the world map
textObjectsReset();
wmTownMap(); // nb this is a world map transition
wmTownMap();
memset(&gMapTransition, 0, sizeof(gMapTransition));
}
} else if (gMapTransition.map == -2) {
if (!isInCombat()) {
animationStop();
// SFALL: Remove text floaters when moving to the world map
textObjectsReset();
wmWorldMap();
memset(&gMapTransition, 0, sizeof(gMapTransition));
}
+438 -664
View File
File diff suppressed because it is too large Load Diff
-1
View File
@@ -19,7 +19,6 @@ int pipboyLoad(File* stream);
extern MessageList gPipboyMessageList;
int pipboyMessageListInit();
void pipboyMessageListFree();
} // namespace fallout

Some files were not shown because too many files have changed in this diff Show More