Compare commits

..
18 changed files with 522 additions and 854 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>"
}
},
+6 -13
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
@@ -102,11 +102,7 @@ The second configuration file is `f2_res.ini`. Use it to change game window size
[MAIN]
SCR_WIDTH=1280
SCR_HEIGHT=720
WINDOWED=1 ; 0 = fullscreen
SCALE_2X=1 ; 0 = original scale, 1 = 2x
[IFACE]
IFACE_BAR_MODE, IFACE_BAR_SIDE_ART, IFACE_BAR_SIDES_ORI, IFACE_BAR_WIDTH supported (require assets in appropriate places)
WINDOWED=1
```
Recommendations:
@@ -116,10 +112,7 @@ Recommendations:
In time this stuff will receive in-game interface, right now you have to do it manually.
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. For high res configs, the following is recommended:
```[Main]
HiResMode=1
```
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
+4
View File
@@ -172,6 +172,9 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int a4
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) {
@@ -185,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);
+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
+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
+1 -1
View File
@@ -31,7 +31,7 @@ typedef struct DrugEffectEvent {
} DrugEffectEvent;
typedef struct WithdrawalEvent {
int active; // 0 == end withdrawal, 1 == start withdrawal
int field_0;
int pid;
int perk;
} WithdrawalEvent;
-1
View File
@@ -68,7 +68,6 @@ bool sfallConfigInit(int argc, char** argv)
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_PIPBOY_AVAILABLE_AT_GAMESTART, 0);
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_USE_WALK_DISTANCE, 5);
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_AUTO_OPEN_DOORS, 0);
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_GAPLESS_MUSIC, 0);
char path[COMPAT_MAX_PATH];
char* executable = argv[0];
-1
View File
@@ -80,7 +80,6 @@ namespace fallout {
#define SFALL_CONFIG_PIPBOY_AVAILABLE_AT_GAMESTART "PipBoyAvailableAtGameStart"
#define SFALL_CONFIG_USE_WALK_DISTANCE "UseWalkDistance"
#define SFALL_CONFIG_AUTO_OPEN_DOORS "AutoOpenDoors"
#define SFALL_CONFIG_GAPLESS_MUSIC "GaplessMusic"
#define SFALL_CONFIG_BURST_MOD_DEFAULT_CENTER_MULTIPLIER 1
#define SFALL_CONFIG_BURST_MOD_DEFAULT_CENTER_DIVISOR 3
+18 -58
View File
@@ -534,7 +534,7 @@ static int wmTileGrabArt(int tileIdx);
static int wmInterfaceRefresh();
static void wmInterfaceRefreshDate(bool shouldRefreshWindow);
static int wmMatchWorldPosToArea(int x, int y, int* areaIdxPtr);
static int wmInterfaceDrawCircleOverlay(CityInfo* cityInfo, CitySizeDescription* citySizeInfo, unsigned char* buffer, int x, int y, int destPitch);
static int wmInterfaceDrawCircleOverlay(CityInfo* cityInfo, CitySizeDescription* citySizeInfo, unsigned char* buffer, int x, int y);
static void wmInterfaceDrawSubTileRectFogged(unsigned char* dest, int width, int height, int pitch);
static int wmInterfaceDrawSubTileList(TileInfo* tileInfo, int column, int row, int x, int y, int a6);
static int wmDrawCursorStopped();
@@ -5221,50 +5221,17 @@ static int wmInterfaceRefresh()
}
// Render cities.
constexpr int PADDING = 100;
int viewportWidth = 472;
int viewportHeight = 465;
int bufferWidth = viewportWidth + PADDING * 2;
int bufferHeight = viewportHeight + PADDING * 2;
unsigned char* paddedBuf = (unsigned char*)malloc(bufferWidth * bufferHeight);
if (paddedBuf != nullptr) {
// Copy current wmBkWinBuf into center of paddedBuf
memset(paddedBuf, 0, bufferWidth * bufferHeight); // Clear padding
for (int y = 0; y < viewportHeight; y++) {
memcpy(
paddedBuf + bufferWidth * (y + PADDING) + PADDING,
wmBkWinBuf + y * WM_WINDOW_WIDTH,
viewportWidth);
}
// Draw cities onto a padded buffer
for (int index = 0; index < wmMaxAreaNum; index++) {
CityInfo* cityInfo = &wmAreaInfoList[index];
if (cityInfo->state != CITY_STATE_UNKNOWN) {
CitySizeDescription* citySizeDescription = &wmSphereData[cityInfo->size];
int cityX = cityInfo->x - wmWorldOffsetX + PADDING;
int cityY = cityInfo->y - wmWorldOffsetY + PADDING;
if (cityX >= 0 && cityX <= bufferWidth - citySizeDescription->frmImage.getWidth() &&
cityY >= 0 && cityY <= bufferHeight - citySizeDescription->frmImage.getHeight()) {
wmInterfaceDrawCircleOverlay(cityInfo, citySizeDescription, paddedBuf, cityX, cityY, bufferWidth);
}
for (int index = 0; index < wmMaxAreaNum; index++) {
CityInfo* cityInfo = &(wmAreaInfoList[index]);
if (cityInfo->state != CITY_STATE_UNKNOWN) {
CitySizeDescription* citySizeDescription = &(wmSphereData[cityInfo->size]);
int cityX = cityInfo->x - wmWorldOffsetX;
int cityY = cityInfo->y - wmWorldOffsetY;
if (cityX >= 0 && cityX <= 472 - citySizeDescription->frmImage.getWidth()
&& cityY >= 0 && cityY <= 465 - citySizeDescription->frmImage.getHeight()) {
wmInterfaceDrawCircleOverlay(cityInfo, citySizeDescription, wmBkWinBuf, cityX, cityY);
}
}
// Copy center portion back to wmBkWinBuf
for (int y = 0; y < viewportHeight; y++) {
memcpy(
wmBkWinBuf + y * WM_WINDOW_WIDTH,
paddedBuf + bufferWidth * (y + PADDING) + PADDING,
viewportWidth);
}
free(paddedBuf);
}
// Hide unknown subtiles, dim unvisited.
@@ -5417,46 +5384,39 @@ static int wmMatchWorldPosToArea(int x, int y, int* areaIdxPtr)
return 0;
}
// Function augmented to add destPitch to align city icons properly
// 0x4C3FA8
static int wmInterfaceDrawCircleOverlay(
CityInfo* city,
CitySizeDescription* citySizeDescription,
unsigned char* dest,
int x,
int y,
int destPitch)
static int wmInterfaceDrawCircleOverlay(CityInfo* city, CitySizeDescription* citySizeDescription, unsigned char* dest, int x, int y)
{
_dark_translucent_trans_buf_to_buf(
citySizeDescription->frmImage.getData(),
_dark_translucent_trans_buf_to_buf(citySizeDescription->frmImage.getData(),
citySizeDescription->frmImage.getWidth(),
citySizeDescription->frmImage.getHeight(),
citySizeDescription->frmImage.getWidth(),
dest,
x,
y,
destPitch,
WM_WINDOW_WIDTH,
0x10000,
circleBlendTable,
_commonGrayTable);
// CE: Slightly increase whitespace between cirle and city name.
int nameY = y + citySizeDescription->frmImage.getHeight() + 3;
int maxY = (464) + 200 - fontGetLineHeight(); // 200 for the PADDING
int maxY = 464 - fontGetLineHeight();
if (nameY < maxY) {
MessageListItem messageListItem;
char name[40];
if (wmAreaIsKnown(city->areaId)) {
// NOTE: Uninline.
wmGetAreaName(city, name);
} else {
strncpy(name, getmsg(&wmMsgFile, &messageListItem, 1004), 40);
}
int width = fontGetStringWidth(name);
fontDrawText(
dest + destPitch * nameY + x + citySizeDescription->frmImage.getWidth() / 2 - width / 2,
fontDrawText(dest + WM_WINDOW_WIDTH * nameY + x + citySizeDescription->frmImage.getWidth() / 2 - width / 2,
name,
width,
destPitch,
WM_WINDOW_WIDTH,
_colorTable[992] | FONT_SHADOW);
}
+2 -2
View File
@@ -1,8 +1,8 @@
include(FetchContent)
FetchContent_Declare(fpattern
GIT_REPOSITORY "https://github.com/alexbatalov/fpattern"
GIT_TAG 8523173ec252c3b796fcdfca0fcc6329642fbbe3 # v1.9
GIT_REPOSITORY "https://github.com/fallout2-ce/fpattern"
GIT_TAG 35005aec7dd94584a7563fb75bc0597b2259058d # v1.9
GIT_SHALLOW TRUE
GIT_PROGRESS TRUE
EXCLUDE_FROM_ALL