mirror of
https://github.com/fallout2-ce/fallout2-ce.git
synced 2026-07-27 16:47:11 -07:00
Compare commits
32
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e574882f3 | ||
|
|
5995592664 | ||
|
|
982c5fcb42 | ||
|
|
9cd309b263 | ||
|
|
de7f12f3ca | ||
|
|
7a2edd5677 | ||
|
|
66b68f84dc | ||
|
|
fef49692e1 | ||
|
|
6c3c0d34c2 | ||
|
|
42e016e4f9 | ||
|
|
66542dc28a | ||
|
|
5270cf0d55 | ||
|
|
e598d06c4a | ||
|
|
66f7137f74 | ||
|
|
cf59439352 | ||
|
|
02ee5cba5d | ||
|
|
218fd20700 | ||
|
|
7e18a6980a | ||
|
|
66c0218741 | ||
|
|
8fc789d6f9 | ||
|
|
ddc5be3b6d | ||
|
|
833b6d8213 | ||
|
|
3163319290 | ||
|
|
252d2ef263 | ||
|
|
ef09142375 | ||
|
|
a4ba0240f1 | ||
|
|
2e8a65593e | ||
|
|
f35d1efab2 | ||
|
|
42a6a16f73 | ||
|
|
85389ef2f3 | ||
|
|
5e93479192 | ||
|
|
afeec298bf |
@@ -0,0 +1,31 @@
|
||||
### 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.
|
||||
|
||||
--->
|
||||
|
||||
+3
-1
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
cmake_minimum_required(VERSION 3.18)
|
||||
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
|
||||
|
||||
@@ -305,12 +305,14 @@ 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
@@ -33,7 +33,7 @@
|
||||
"cacheVariables": {
|
||||
"CMAKE_GENERATOR_TOOLSET": "v141_xp",
|
||||
"CMAKE_C_FLAGS": "/D_WIN32_WINNT=0x0501",
|
||||
"CMAKE_CXX_FLAGS": "/D_WIN32_WINNT=0x0501",
|
||||
"CMAKE_CXX_FLAGS": "/D_WIN32_WINNT=0x0501 /D_STATIC_CPPLIB",
|
||||
"CMAKE_MSVC_RUNTIME_LIBRARY": "MultiThreaded$<$<CONFIG:Debug>:Debug>"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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.
|
||||
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.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
There is also [Fallout Community Edition](https://github.com/alexbatalov/fallout1-ce).
|
||||
There is also [Fallout Community Edition](https://github.com/alexbatalov/fallout1-ce) (not affiliated with this fork).
|
||||
|
||||
## 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/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.
|
||||
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.
|
||||
|
||||
### Windows
|
||||
|
||||
@@ -102,7 +102,11 @@ The second configuration file is `f2_res.ini`. Use it to change game window size
|
||||
[MAIN]
|
||||
SCR_WIDTH=1280
|
||||
SCR_HEIGHT=720
|
||||
WINDOWED=1
|
||||
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)
|
||||
```
|
||||
|
||||
Recommendations:
|
||||
@@ -112,7 +116,10 @@ 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.
|
||||
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
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
+11
-2
@@ -21,6 +21,7 @@
|
||||
#include "queue.h"
|
||||
#include "random.h"
|
||||
#include "settings.h"
|
||||
#include "sfall_config.h"
|
||||
#include "sound_effects_cache.h"
|
||||
#include "stat.h"
|
||||
#include "svga.h"
|
||||
@@ -745,9 +746,17 @@ int backgroundSoundLoad(const char* fileName, int a2, int a3, int a4)
|
||||
}
|
||||
|
||||
// 0x450A08
|
||||
int _gsound_background_play_level_music(const char* a1, int a2)
|
||||
int _gsound_background_play_level_music(const char* fileName, int a2)
|
||||
{
|
||||
return backgroundSoundLoad(a1, a2, 14, 16);
|
||||
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);
|
||||
}
|
||||
|
||||
// 0x450AB4
|
||||
|
||||
+30
-25
@@ -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 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 _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 drugGetAddictionGvarByPid(int drugPid);
|
||||
static void dudeSetAddiction(int drugPid);
|
||||
static void dudeClearAddiction(int drugPid);
|
||||
@@ -1550,6 +1550,9 @@ 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)) {
|
||||
@@ -1568,26 +1571,26 @@ int weaponReload(Object* weapon, Object* ammo)
|
||||
}
|
||||
|
||||
// NOTE: Uninline.
|
||||
int v10 = ammoGetQuantity(ammo);
|
||||
int quantity = ammoGetQuantity(ammo);
|
||||
|
||||
int v11 = v10;
|
||||
int left = quantity;
|
||||
if (ammoQuantity < ammoCapacity) {
|
||||
int v12;
|
||||
if (ammoQuantity + v10 > ammoCapacity) {
|
||||
v11 = v10 - (ammoCapacity - ammoQuantity);
|
||||
v12 = ammoCapacity;
|
||||
int newQuantity;
|
||||
if (ammoQuantity + quantity > ammoCapacity) {
|
||||
left = quantity - (ammoCapacity - ammoQuantity);
|
||||
newQuantity = ammoCapacity;
|
||||
} else {
|
||||
v11 = 0;
|
||||
v12 = ammoQuantity + v10;
|
||||
left = 0;
|
||||
newQuantity = ammoQuantity + quantity;
|
||||
}
|
||||
|
||||
weapon->data.item.weapon.ammoTypePid = ammo->pid;
|
||||
|
||||
ammoSetQuantity(ammo, v11);
|
||||
ammoSetQuantity(weapon, v12);
|
||||
ammoSetQuantity(ammo, left);
|
||||
ammoSetQuantity(weapon, newQuantity);
|
||||
}
|
||||
|
||||
return v11;
|
||||
return left;
|
||||
}
|
||||
|
||||
// 0x478A1C
|
||||
@@ -2914,14 +2917,14 @@ int drugEffectEventWrite(File* stream, void* data)
|
||||
}
|
||||
|
||||
// 0x47A290
|
||||
static int _insert_withdrawal(Object* obj, int a2, int duration, int perk, int pid)
|
||||
static int _insert_withdrawal(Object* obj, int active, int duration, int perk, int pid)
|
||||
{
|
||||
WithdrawalEvent* withdrawalEvent = (WithdrawalEvent*)internal_malloc(sizeof(*withdrawalEvent));
|
||||
if (withdrawalEvent == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
withdrawalEvent->field_0 = a2;
|
||||
withdrawalEvent->active = active;
|
||||
withdrawalEvent->pid = pid;
|
||||
withdrawalEvent->perk = perk;
|
||||
|
||||
@@ -2942,7 +2945,7 @@ int _item_wd_clear(Object* obj, void* data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!withdrawalEvent->field_0) {
|
||||
if (!withdrawalEvent->active) {
|
||||
performWithdrawalEnd(obj, withdrawalEvent->perk);
|
||||
}
|
||||
|
||||
@@ -2950,11 +2953,11 @@ int _item_wd_clear(Object* obj, void* data)
|
||||
}
|
||||
|
||||
// 0x47A324
|
||||
static int _item_wd_clear_all(Object* a1, void* data)
|
||||
static int _item_wd_clear_all(Object* obj, void* data)
|
||||
{
|
||||
WithdrawalEvent* withdrawalEvent = (WithdrawalEvent*)data;
|
||||
|
||||
if (a1 != _wd_obj) {
|
||||
if (obj != _wd_obj) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2962,11 +2965,12 @@ static int _item_wd_clear_all(Object* a1, void* data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!withdrawalEvent->field_0) {
|
||||
if (!withdrawalEvent->active) {
|
||||
performWithdrawalEnd(_wd_obj, withdrawalEvent->perk);
|
||||
}
|
||||
|
||||
_insert_withdrawal(a1, 1, _wd_onset, withdrawalEvent->perk, withdrawalEvent->pid);
|
||||
// schedule start of withdrawal
|
||||
_insert_withdrawal(obj, 1, _wd_onset, withdrawalEvent->perk, withdrawalEvent->pid);
|
||||
|
||||
_wd_obj = nullptr;
|
||||
|
||||
@@ -2978,7 +2982,7 @@ int withdrawalEventProcess(Object* obj, void* data)
|
||||
{
|
||||
WithdrawalEvent* withdrawalEvent = (WithdrawalEvent*)data;
|
||||
|
||||
if (withdrawalEvent->field_0) {
|
||||
if (withdrawalEvent->active) {
|
||||
performWithdrawalStart(obj, withdrawalEvent->perk, withdrawalEvent->pid);
|
||||
} else {
|
||||
if (withdrawalEvent->perk == PERK_JET_ADDICTION) {
|
||||
@@ -3009,7 +3013,7 @@ int withdrawalEventRead(File* stream, void** dataPtr)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fileReadInt32(stream, &(withdrawalEvent->field_0)) == -1) goto err;
|
||||
if (fileReadInt32(stream, &(withdrawalEvent->active)) == -1) goto err;
|
||||
if (fileReadInt32(stream, &(withdrawalEvent->pid)) == -1) goto err;
|
||||
if (fileReadInt32(stream, &(withdrawalEvent->perk)) == -1) goto err;
|
||||
|
||||
@@ -3027,7 +3031,7 @@ int withdrawalEventWrite(File* stream, void* data)
|
||||
{
|
||||
WithdrawalEvent* withdrawalEvent = (WithdrawalEvent*)data;
|
||||
|
||||
if (fileWriteInt32(stream, withdrawalEvent->field_0) == -1) return -1;
|
||||
if (fileWriteInt32(stream, withdrawalEvent->active) == -1) return -1;
|
||||
if (fileWriteInt32(stream, withdrawalEvent->pid) == -1) return -1;
|
||||
if (fileWriteInt32(stream, withdrawalEvent->perk) == -1) return -1;
|
||||
|
||||
@@ -3064,6 +3068,7 @@ static void performWithdrawalStart(Object* obj, int perk, int pid)
|
||||
}
|
||||
}
|
||||
|
||||
// schedule end of withdrawal
|
||||
_insert_withdrawal(obj, 0, duration, perk, pid);
|
||||
}
|
||||
|
||||
|
||||
+7
-7
@@ -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* a2);
|
||||
int itemGetQuantity(Object* obj, Object* item);
|
||||
int itemIsQueued(Object* obj);
|
||||
Object* itemReplace(Object* a1, Object* a2, int a3);
|
||||
Object* itemReplace(Object* owner, Object* itemToReplace, int flags);
|
||||
bool itemIsHidden(Object* obj);
|
||||
int weaponGetAttackTypeForHitMode(Object* a1, int a2);
|
||||
int weaponGetSkillForHitMode(Object* a1, int a2);
|
||||
int weaponGetSkillValue(Object* a1, int a2);
|
||||
int weaponGetAttackTypeForHitMode(Object* weapon, int hitMode);
|
||||
int weaponGetSkillForHitMode(Object* weapon, int hitMode);
|
||||
int weaponGetSkillValue(Object* critter, int hitMode);
|
||||
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* a2);
|
||||
int _item_wd_clear(Object* obj, void* data);
|
||||
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 a2);
|
||||
int itemSetMoney(Object* obj, int amount);
|
||||
|
||||
bool booksGetInfo(int bookPid, int* messageIdPtr, int* skillPtr);
|
||||
bool explosionEmitsLight();
|
||||
|
||||
+4
-4
@@ -2303,8 +2303,8 @@ static void _ShowSlotList(int windowType)
|
||||
int inactiveColor = _colorTable[8804];
|
||||
|
||||
{
|
||||
MessageListItem messageListItemBack = {201 , 0, nullptr, nullptr};
|
||||
if (!messageListGetItem(&gPipboyMessageList, &messageListItemBack)){
|
||||
MessageListItem messageListItemBack = { 201, 0, nullptr, nullptr };
|
||||
if (!messageListGetItem(&gPipboyMessageList, &messageListItemBack)) {
|
||||
debugPrint("Error: Couldn't find LoadSave Message!");
|
||||
messageListItemBack.text = "BACK";
|
||||
}
|
||||
@@ -2316,8 +2316,8 @@ static void _ShowSlotList(int windowType)
|
||||
_currentSlotPage > 0 ? activeColor : inactiveColor);
|
||||
}
|
||||
{
|
||||
MessageListItem messageListItemMore = {200 , 0, nullptr, nullptr};
|
||||
if (!messageListGetItem(&gPipboyMessageList, &messageListItemMore)){
|
||||
MessageListItem messageListItemMore = { 200, 0, nullptr, nullptr };
|
||||
if (!messageListGetItem(&gPipboyMessageList, &messageListItemMore)) {
|
||||
debugPrint("Error: Couldn't find LoadSave Message!");
|
||||
messageListItemMore.text = "MORE";
|
||||
}
|
||||
|
||||
+11
-2
@@ -36,6 +36,7 @@
|
||||
#include "random.h"
|
||||
#include "scripts.h"
|
||||
#include "settings.h"
|
||||
#include "sfall_config.h"
|
||||
#include "svga.h"
|
||||
#include "text_object.h"
|
||||
#include "tile.h"
|
||||
@@ -819,7 +820,11 @@ int mapLoadById(int map)
|
||||
static int mapLoad(File* stream)
|
||||
{
|
||||
_map_save_in_game(true);
|
||||
backgroundSoundLoad("wind2", 12, 13, 16);
|
||||
int gaplessMusic = 0;
|
||||
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_GAPLESS_MUSIC, &gaplessMusic);
|
||||
if (!gaplessMusic) {
|
||||
backgroundSoundLoad("wind2", 12, 13, 16);
|
||||
}
|
||||
isoDisable();
|
||||
_partyMemberPrepLoad();
|
||||
_gmouse_disable_scrolling();
|
||||
@@ -1248,12 +1253,16 @@ int mapHandleTransition()
|
||||
if (gMapTransition.map == -1) {
|
||||
if (!isInCombat()) {
|
||||
animationStop();
|
||||
wmTownMap();
|
||||
// SFALL: Remove text floaters when moving to the world map
|
||||
textObjectsReset();
|
||||
wmTownMap(); // nb this is a world map transition
|
||||
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));
|
||||
}
|
||||
|
||||
+653
-429
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -31,7 +31,7 @@ typedef struct DrugEffectEvent {
|
||||
} DrugEffectEvent;
|
||||
|
||||
typedef struct WithdrawalEvent {
|
||||
int field_0;
|
||||
int active; // 0 == end withdrawal, 1 == start withdrawal
|
||||
int pid;
|
||||
int perk;
|
||||
} WithdrawalEvent;
|
||||
|
||||
@@ -68,6 +68,7 @@ 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];
|
||||
|
||||
@@ -80,6 +80,7 @@ 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
|
||||
|
||||
+58
-18
@@ -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);
|
||||
static int wmInterfaceDrawCircleOverlay(CityInfo* cityInfo, CitySizeDescription* citySizeInfo, unsigned char* buffer, int x, int y, int destPitch);
|
||||
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,17 +5221,50 @@ static int wmInterfaceRefresh()
|
||||
}
|
||||
|
||||
// Render cities.
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
@@ -5384,39 +5417,46 @@ 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)
|
||||
static int wmInterfaceDrawCircleOverlay(
|
||||
CityInfo* city,
|
||||
CitySizeDescription* citySizeDescription,
|
||||
unsigned char* dest,
|
||||
int x,
|
||||
int y,
|
||||
int destPitch)
|
||||
{
|
||||
_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,
|
||||
WM_WINDOW_WIDTH,
|
||||
destPitch,
|
||||
0x10000,
|
||||
circleBlendTable,
|
||||
_commonGrayTable);
|
||||
|
||||
// CE: Slightly increase whitespace between cirle and city name.
|
||||
int nameY = y + citySizeDescription->frmImage.getHeight() + 3;
|
||||
int maxY = 464 - fontGetLineHeight();
|
||||
int maxY = (464) + 200 - fontGetLineHeight(); // 200 for the PADDING
|
||||
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 + WM_WINDOW_WIDTH * nameY + x + citySizeDescription->frmImage.getWidth() / 2 - width / 2,
|
||||
fontDrawText(
|
||||
dest + destPitch * nameY + x + citySizeDescription->frmImage.getWidth() / 2 - width / 2,
|
||||
name,
|
||||
width,
|
||||
WM_WINDOW_WIDTH,
|
||||
destPitch,
|
||||
_colorTable[992] | FONT_SHADOW);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user