Compare commits

..
Author SHA1 Message Date
cambragol f3403c07f7 Merge branch 'main' into stretching-for-800x500-widescreen-mode 2025-06-22 20:33:24 +09:00
cambragol 8c44106688 Merge branch 'main' into stretching-for-800x500-widescreen-mode 2025-06-21 12:02:50 +09:00
cambragol 5248e138f6 removed Scale_2x
Removed scale_2x function, as it no longer worked nor was needed.
Fixed backing up of gPreseverAspect in guserAspectPreference - used to restore users aspect preference, when returning from the main game screen - that window overrides users aspect preferences.
2025-06-16 14:34:32 +09:00
cambragol 0076894414 First pass on widescreen mode
Adds stretching for full and aspect ratio, set from f2_res (for now)
Allows different content to be stretched/displayed uniformly (to mix 640 and 800 content smoothly)
Adds resizeContent which lets renderPresent know how big(wide) the content being stretched is. A bool also reads/restores users aspect ratio setting (because main game area forces aspect ratio)
Adds small tweak to endgame.cc that smooths the transition after slideshow to the credits movie (just keeps the screen black)
2025-06-15 17:50:06 +09:00
81 changed files with 569 additions and 10575 deletions
+6 -47
View File
@@ -14,16 +14,6 @@ jobs:
runs-on: ubuntu-latest
permissions: write-all
steps:
- name: start deployment
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository
uses: bobheadxi/deployments@v1
id: deployment
with:
ref: ${{ github.event.pull_request.head.sha }}
step: start
debug: true
env: preview-${{ github.event.pull_request.number }}
- name: Clone
uses: actions/checkout@v4
@@ -86,10 +76,6 @@ jobs:
SITE_BASE: ${{ steps.set-path.outputs.SITE_BASE }}
F2_GAME_VERSION: Game=${{github.event.pull_request.head.sha || github.sha }}
- name: Place hash file
if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository)
run: echo "$GITHUB_SHA" > fallout2-ce-ems/dist/site_hash.txt
- name: Install rsync (required for the next step)
if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository)
run: |
@@ -105,37 +91,10 @@ jobs:
clean: false
single-commit: true
- name: Check that site is deployed
if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository)
run: |
URL="$SITE_ORIGIN""$SITE_BASE""site_hash.txt"
echo "Expecting $GITHUB_SHA from $URL"
for i in `seq 1 80`; do
got="$(curl -fsSL --max-time 10 "$URL" | tr -d '\r\n' || true)"
if [ "$got" = "$GITHUB_SHA" ]; then
echo "âś… Match on attempt $i: ${got}"
exit 0
fi
echo "Received $got, waiting"
sleep 5
done
exit 1
env:
SITE_ORIGIN: https://${{ github.repository_owner }}.github.io
SITE_BASE: ${{ steps.set-path.outputs.SITE_BASE }}
- name: Update deployment status
- name: Comment preview URL on PR
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository
uses: bobheadxi/deployments@v1
with:
step: finish
status: success
debug: true
env: ${{ steps.deployment.outputs.env }}
deployment_id: ${{ steps.deployment.outputs.deployment_id }}
ref: ${{ github.event.pull_request.head.sha }}
env_url: https://${{ github.repository_owner }}.github.io/fallout2-ce/PR-${{ github.event.pull_request.number }}/
run: |
gh pr comment ${{ github.event.pull_request.number }} \
--body "🚀 WebAssembly PR Preview for ${{github.event.pull_request.head.sha || github.sha }} is available at: https://${{ github.repository_owner }}.github.io/fallout2-ce/PR-${{ github.event.pull_request.number }}/"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+5 -5
View File
@@ -87,7 +87,7 @@ jobs:
uses: actions/cache@v4
with:
path: os/android/app/.cxx
key: android-cmake-v101
key: android-cmake-v100
- name: Setup signing config
if: env.KEYSTORE_FILE_BASE64 != '' && env.KEYSTORE_PROPERTIES_FILE_BASE64 != ''
@@ -128,7 +128,7 @@ jobs:
uses: actions/cache@v4
with:
path: out
key: ios-cmake-v101
key: ios-cmake-v100
- name: Configure
run: |
@@ -183,7 +183,7 @@ jobs:
uses: actions/cache@v4
with:
path: out
key: linux-${{ matrix.arch }}-cmake-v101
key: linux-${{ matrix.arch }}-cmake-v100
- name: Configure
run: |
@@ -288,7 +288,7 @@ jobs:
uses: actions/cache@v4
with:
path: out
key: macos-cmake-v101
key: macos-cmake-v100
- name: Configure
run: |
@@ -337,7 +337,7 @@ jobs:
uses: actions/cache@v4
with:
path: out
key: windows-${{ matrix.arch }}-cmake-v101
key: windows-${{ matrix.arch }}-cmake-v100
- name: Configure
shell: cmd
+1 -10
View File
@@ -12,7 +12,6 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: write
deployments: write
steps:
- name: Checkout gh-pages branch
uses: actions/checkout@v4
@@ -44,12 +43,4 @@ jobs:
else
git commit --amend -m "đźš® Remove preview for closed PR #${{ github.event.pull_request.number }}"
git push --force
fi
- name: mark environment as deactivated
uses: bobheadxi/deployments@v1
with:
step: deactivate-env
env: preview-${{ github.event.pull_request.number }}
desc: Environment was pruned
debug: true
fi
-5
View File
@@ -288,16 +288,11 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
"src/sfall_opcodes.h"
"src/sfall_arrays.cc"
"src/sfall_arrays.h"
"src/sfall_callbacks.cc"
"src/sfall_callbacks.h"
"src/touch.cc"
"src/touch.h"
"src/scan_unimplemented.cc"
"third_party/lodepng/lodepng.cpp"
)
target_include_directories(${EXECUTABLE_NAME} PUBLIC "third_party/lodepng")
if(IOS)
target_sources(${EXECUTABLE_NAME} PUBLIC
"src/platform/ios/paths.h"
+1 -12
View File
@@ -44,7 +44,7 @@ $ sudo apt install libsdl2-2.0-0
- Alternatively you can use Fallout 2 from Macplay/The Omni Group as a base - you need to extract game assets from the original bundle. Mount CD/DMG, right click `Fallout 2` -> `Show Package Contents`, navigate to `Contents/Resources`. Copy `GameData` folder somewhere, for example `/Applications/Fallout2`.
- Or if you're a Terminal user and have Homebrew installed you can extract the needed files from the GoG installer. **Note**: You must use "Offline backup game installer", not the main game installer.
- Or if you're a Terminal user and have Homebrew installed you can extract the needed files from the GoG installer:
```console
$ brew install innoextract
@@ -126,17 +126,6 @@ IFACE_BAR_SIDES_ORI=0
;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
[STATIC_SCREENS]
;if SPLASH_SCRN_SIZE=0 - Splash screen shows at original size if it fits, otherwise scales down while preserving aspect ratio.
;if SPLASH_SCRN_SIZE=1 - Splash screen scales to fit the screen while preserving aspect ratio.
;if SPLASH_SCRN_SIZE=2 - Splash screen stretches to fill the entire screen.
SPLASH_SCRN_SIZE=0
[MAPS]
;if IGNORE_MAP_EDGES=0 - Hi-Res map scroll edges are enabled.
;if IGNORE_MAP_EDGES=1 - Hi-Res map scroll edges are ignored.
IGNORE_MAP_EDGES=0
```
Recommendations:
-33
View File
@@ -1,33 +0,0 @@
#include "test_utils.h"
#include "sfall.h"
procedure start begin
display_msg("Testing iface_tag functions...");
// assumes no iface tags active in the save game
// SNEAK
show_iface_tag(0);
call assertTrue("show_iface_tag(SNEAK)", is_iface_tag_active(0));
hide_iface_tag(0);
call assertFalse("hide_iface_tag(SNEAK)", is_iface_tag_active(0));
// LEVEL
show_iface_tag(3);
call assertTrue("show_iface_tag(LEVEL)", is_iface_tag_active(3));
hide_iface_tag(3);
call assertFalse("hide_iface_tag(LEVEL)", is_iface_tag_active(3));
// ADDICTED
show_iface_tag(4);
call assertTrue("show_iface_tag(ADDICTED)", is_iface_tag_active(4));
hide_iface_tag(4);
call assertFalse("hide_iface_tag(ADDICTED)", is_iface_tag_active(4));
// POISONED
call assertFalse("hide_iface_tag(POISONED)", is_iface_tag_active(1));
// RADIATED
call assertFalse("hide_iface_tag(RADIATED)", is_iface_tag_active(2));
call report_test_results("iface_tag");
end
-14
View File
@@ -1,14 +0,0 @@
#include "sfall.h"
// this is the basic message_box function used by RPU and Et Tu
#define message_box_warning(text) message_box4(text, 0x01, 134, 145)
procedure start begin
// I don't see a practice way to auto test message_box, so this is just a way to do manual testing
variable ret = message_box1("Basic Dialog\nwith multiple lines\nand such.");
display_msg("chose: " + ret);
message_box2("Basic Dialog\nwith default flags.", -1); // -1 means use default flags
message_box2("Basic Dialog\nsmall.", 0x02);
message_box_warning("Missing config values\n(just testing).");
end
-30
View File
@@ -1,30 +0,0 @@
#include "test_utils.h"
#include "sfall.h"
procedure start begin
display_msg("Testing metarule_exist functions...");
call assertEquals("string_format", metarule_exist("string_format"), 1);
call assertEquals("metarule_exist", metarule_exist("metarule_exist"), 1);
// This will fail on sFall
call assertEquals("opcode_exists", metarule_exist("opcode_exists"), 1);
if metarule_exist("opcode_exists") then begin // And example if how to use it
#define opcode_exists(opcode) sfall_func1("opcode_exists", opcode)
#define OP_GET_UPTIME 0x81B3
#define OP_NOOP 0x8000
#define OP_WRITE_INT 0x81D1
call assertEquals("opcode_exists OP_GET_UPTIME", opcode_exists(OP_GET_UPTIME), 1);
call assertEquals("opcode_exists OP_NOOP", opcode_exists(OP_NOOP), 1);
// Probably will never be implemented on fallout2-ce
call assertEquals("opcode_exists OP_WRITE_INT", opcode_exists(OP_WRITE_INT), 0);
call assertEquals("opcode_exists 0xFFFF", opcode_exists(0xFFFF), 0);
end else begin
display_msg("Opcode exists metarule is not available, skipping tests.");
end
call report_test_results("metarule_exist");
end
-11
View File
@@ -18,17 +18,6 @@ procedure assertTrue(variable desc, variable a) begin
end
end
procedure assertFalse(variable desc, variable a) begin
test_suite_assertions++;
if (a) then begin
display_msg("Assertion failed \""+desc+"\": is not false");
test_suite_errors ++;
end else if (test_suite_verbose) then begin
display_msg("Assert \""+desc+"\" ok");
end
end
procedure assertEquals(variable desc, variable a, variable b) begin
test_suite_assertions++;
+18 -5
View File
@@ -1032,7 +1032,9 @@ int _action_climb_ladder(Object* critter, Object* ladder)
reg_anim_begin(animationRequestOptions);
int tile = tileGetTileInDirection(ladder->tile, ROTATION_SE, 1);
if (actionPoints != -1 || objectWithinWalkDistance(critter, ladder)) {
int walkDistance = 5;
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_USE_WALK_DISTANCE, &walkDistance);
if (actionPoints != -1 || objectGetDistanceBetween(critter, ladder) < walkDistance) {
animationRegisterMoveToTile(critter, tile, ladder->elevation, actionPoints, 0);
} else {
animationRegisterRunToTile(critter, tile, ladder->elevation, actionPoints, 0);
@@ -1099,7 +1101,9 @@ int _action_use_an_item_on_object(Object* user, Object* targetObj, Object* item)
reg_anim_begin(animationRequestOptions);
if (actionPoints != -1 || objectWithinWalkDistance(user, targetObj)) {
int walkDistance = 5;
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_USE_WALK_DISTANCE, &walkDistance);
if (actionPoints != -1 || objectGetDistanceBetween(user, targetObj) < walkDistance) {
animationRegisterMoveToObject(user, targetObj, actionPoints, 0);
} else {
animationRegisterRunToObject(user, targetObj, -1, 0);
@@ -1169,12 +1173,15 @@ int actionPickUp(Object* critter, Object* item)
}
}
int walkDistance = 5;
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_USE_WALK_DISTANCE, &walkDistance);
if (isInCombat()) {
reg_anim_begin(ANIMATION_REQUEST_RESERVED);
animationRegisterMoveToObject(critter, item, critter->data.critter.combat.ap, 0);
} else {
reg_anim_begin(critter == gDude ? ANIMATION_REQUEST_RESERVED : ANIMATION_REQUEST_UNRESERVED);
if (!objectWithinWalkDistance(critter, item)) {
if (objectGetDistanceBetween(critter, item) >= walkDistance) {
animationRegisterRunToObject(critter, item, -1, 0);
} else {
animationRegisterMoveToObject(critter, item, -1, 0);
@@ -1274,13 +1281,16 @@ int _action_loot_container(Object* critter, Object* container)
}
}
int walkDistance = 5;
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_USE_WALK_DISTANCE, &walkDistance);
if (isInCombat()) {
reg_anim_begin(ANIMATION_REQUEST_RESERVED);
animationRegisterMoveToObject(critter, container, critter->data.critter.combat.ap, 0);
} else {
reg_anim_begin(critter == gDude ? ANIMATION_REQUEST_RESERVED : ANIMATION_REQUEST_UNRESERVED);
if (objectWithinWalkDistance(critter, container)) {
if (objectGetDistanceBetween(critter, container) < walkDistance) {
animationRegisterMoveToObject(critter, container, -1, 0);
} else {
animationRegisterRunToObject(critter, container, -1, 0);
@@ -1478,13 +1488,16 @@ int actionUseSkill(Object* user, Object* target, int skill)
}
}
int walkDistance = 5;
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_USE_WALK_DISTANCE, &walkDistance);
if (isInCombat()) {
reg_anim_begin(ANIMATION_REQUEST_RESERVED);
animationRegisterMoveToObject(performer, target, performer->data.critter.combat.ap, 0);
} else {
reg_anim_begin(user == gDude ? ANIMATION_REQUEST_RESERVED : ANIMATION_REQUEST_UNRESERVED);
if (target != gDude) {
if (!objectWithinWalkDistance(performer, target)) {
if (objectGetDistanceBetween(performer, target) >= walkDistance) {
animationRegisterRunToObject(performer, target, -1, 0);
} else {
animationRegisterMoveToObject(performer, target, -1, 0);
+4 -6
View File
@@ -1713,18 +1713,16 @@ static bool canUseDoor(Object* critter, Object* door)
}
// 0x415EE8
int _make_path(Object* object, int from, int to, unsigned char* rotations, int requireEmptyDest)
int _make_path(Object* object, int from, int to, unsigned char* rotations, int a5)
{
return pathfinderFindPath(object, from, to, rotations, requireEmptyDest, _obj_blocking_at);
return pathfinderFindPath(object, from, to, rotations, a5, _obj_blocking_at);
}
// TODO: move pathfinding into another unit
// If requireEmptyDest == 1, will not return a path if the destination tile is blocked (according to `callback`).
// Returns path length, or 0 if no path is available.
// 0x415EFC
int pathfinderFindPath(Object* object, int from, int to, unsigned char* rotations, int requireEmptyDest, PathBuilderCallback* callback)
int pathfinderFindPath(Object* object, int from, int to, unsigned char* rotations, int a5, PathBuilderCallback* callback)
{
if (requireEmptyDest) {
if (a5) {
if (callback(object, to, object->elevation) != nullptr) {
return 0;
}
+2 -2
View File
@@ -143,8 +143,8 @@ int animationRegisterToggleOutline(Object* object, bool outline, int delay);
int animationRegisterPlaySoundEffect(Object* owner, const char* soundEffectName, int delay);
int animationRegisterAnimateForever(Object* owner, int anim, int delay);
int animationRegisterPing(int flags, int delay);
int _make_path(Object* object, int from, int to, unsigned char* rotations, int requireEmptyDest);
int pathfinderFindPath(Object* object, int from, int to, unsigned char* rotations, int requireEmptyDest, PathBuilderCallback* callback);
int _make_path(Object* object, int from, int to, unsigned char* a4, int a5);
int pathfinderFindPath(Object* object, int from, int to, unsigned char* rotations, int a5, PathBuilderCallback* callback);
int _make_straight_path(Object* object, int from, int to, StraightPathNode* straightPathNodeList, Object** obstaclePtr, int a6);
int _make_straight_path_func(Object* object, int from, int to, StraightPathNode* straightPathNodeList, Object** obstaclePtr, int a6, PathBuilderCallback* callback);
void _object_animate();
+1 -14
View File
@@ -1,6 +1,5 @@
#include "art.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -620,7 +619,7 @@ char* artBuildFilePath(int fid)
v2 = fid;
v10 = FID_ROTATION(fid);
v10 = (fid & 0x70000000) >> 28;
v1 = artAliasFid(fid);
if (v1 != -1) {
@@ -703,13 +702,8 @@ static int artReadList(const char* path, char** artListPtr, int* artListSizePtr)
artList[12] = '\0';
artList += 13;
count--;
}
// Sanity check. There was a bug with uncompressed database file seek
assert(count == 0);
fileClose(stream);
return 0;
@@ -1012,13 +1006,6 @@ static void artCacheFreeImpl(void* ptr)
internal_free(ptr);
}
/* FID Structure:
3 bits for rotation
4 bits for object type
8 bits for animation type
4 bits for weapon code
12 bits for frame ID
*/
static int buildFidInternal(unsigned short frmId, unsigned char weaponCode, unsigned char animType, unsigned char objectType, unsigned char rotation)
{
return ((rotation << 28) & 0x70000000) | (objectType << 24) | ((animType << 16) & 0xFF0000) | ((weaponCode << 12) & 0xF000) | (frmId & 0xFFF);
+1 -2
View File
@@ -324,8 +324,7 @@ void automapShow(bool isInGame, bool isUsingScanner)
int automapWindowX = (screenGetWidth() - AUTOMAP_WINDOW_WIDTH) / 2;
int automapWindowY = (screenGetHeight() - AUTOMAP_WINDOW_HEIGHT) / 2;
// adding WINDOW_TRANSPARENT and WINDOW_DRAGGABLE_BY_BACKGROUND for testing temporarily
int window = windowCreate(automapWindowX, automapWindowY, AUTOMAP_WINDOW_WIDTH, AUTOMAP_WINDOW_HEIGHT, color, WINDOW_MODAL | WINDOW_MOVE_ON_TOP | WINDOW_TRANSPARENT | WINDOW_DRAGGABLE_BY_BACKGROUND);
int window = windowCreate(automapWindowX, automapWindowY, AUTOMAP_WINDOW_WIDTH, AUTOMAP_WINDOW_HEIGHT, color, WINDOW_MODAL | WINDOW_MOVE_ON_TOP);
int scannerBtn = buttonCreate(window,
111,
+8 -12
View File
@@ -36,7 +36,6 @@
#include "random.h"
#include "scripts.h"
#include "settings.h"
#include "sfall_callbacks.h"
#include "sfall_config.h"
#include "sfall_global_scripts.h"
#include "skill.h"
@@ -2621,7 +2620,7 @@ static void _combat_begin(Object* attacker)
100,
FID_ANIM_TYPE(v1->fid),
(v1->fid & 0xF000) >> 12,
FID_ROTATION(v1->fid));
(v1->fid & 0x70000000) >> 28);
reg_anim_clear(v1);
reg_anim_begin(ANIMATION_REQUEST_RESERVED);
@@ -2633,7 +2632,6 @@ static void _combat_begin(Object* attacker)
_process_bk();
}
}
sfallOnCombatStart();
}
}
@@ -2790,7 +2788,7 @@ static void _combat_over()
99,
FID_ANIM_TYPE(critter->fid),
(critter->fid & 0xF000) >> 12,
FID_ROTATION(critter->fid));
(critter->fid & 0x70000000) >> 28);
reg_anim_clear(critter);
reg_anim_begin(ANIMATION_REQUEST_RESERVED);
animationRegisterAnimate(critter, ANIM_UP_STAIRS_RIGHT, -1);
@@ -2843,8 +2841,6 @@ static void _combat_over()
queueRemoveEventsByType(gDude, EVENT_TYPE_KNOCKOUT);
knockoutEventProcess(gDude, nullptr);
}
sfallOnCombatEnd();
}
// 0x422194
@@ -3494,7 +3490,7 @@ void attackInit(Attack* attack, Object* attacker, Object* defender, int hitMode,
int _combat_attack(Object* attacker, Object* defender, int hitMode, int hitLocation)
{
if (attacker != gDude && hitMode == HIT_MODE_PUNCH && randomBetween(1, 4) == 1) {
int fid = buildFid(OBJ_TYPE_CRITTER, attacker->fid & 0xFFF, ANIM_KICK_LEG, (attacker->fid & 0xF000) >> 12, FID_ROTATION(attacker->fid));
int fid = buildFid(OBJ_TYPE_CRITTER, attacker->fid & 0xFFF, ANIM_KICK_LEG, (attacker->fid & 0xF000) >> 12, (attacker->fid & 0x70000000) >> 28);
if (artExists(fid)) {
hitMode = HIT_MODE_KICK;
}
@@ -3845,14 +3841,14 @@ static int attackCompute(Attack* attack)
}
int attackType = weaponGetAttackTypeForHitMode(attack->weapon, attack->hitMode);
int roundsHitMainTarget = 1;
int ammoQuantity = 1;
int damageMultiplier = 2;
int roundsSpent = 1;
int v26 = 1;
int roll;
if (anim == ANIM_FIRE_BURST || anim == ANIM_FIRE_CONTINUOUS) {
roll = _compute_spray(attack, accuracy, &roundsHitMainTarget, &roundsSpent, anim);
roll = _compute_spray(attack, accuracy, &ammoQuantity, &v26, anim);
} else {
int chance = critterGetStat(attack->attacker, STAT_CRITICAL_CHANCE);
roll = randomRoll(accuracy, chance - hit_location_penalty[attack->defenderHitLocation], nullptr);
@@ -3890,7 +3886,7 @@ static int attackCompute(Attack* attack)
}
if (attackType == ATTACK_TYPE_RANGED) {
attack->ammoQuantity = roundsSpent;
attack->ammoQuantity = v26;
if (roll == ROLL_SUCCESS && attack->attacker == gDude) {
if (perkGetRank(gDude, PERK_SNIPER) != 0) {
@@ -3928,7 +3924,7 @@ static int attackCompute(Attack* attack)
case ROLL_SUCCESS:
attack->attackerFlags |= DAM_HIT;
attackComputeEnhancedKnockout(attack);
attackComputeDamage(attack, roundsHitMainTarget, damageMultiplier);
attackComputeDamage(attack, ammoQuantity, damageMultiplier);
break;
case ROLL_FAILURE:
if (attackType == ATTACK_TYPE_RANGED || attackType == ATTACK_TYPE_THROW) {
+17 -19
View File
@@ -792,15 +792,15 @@ char* killTypeGetDescription(int killType)
}
}
// 0x42D9F4 _critter_heal_hours heals critters based on the number of elapsed hours
int _critter_heal_hours(Object* critter, int hours)
// 0x42D9F4
int _critter_heal_hours(Object* critter, int a2)
{
if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) {
return -1;
}
if (critter->data.critter.hp < critterGetStat(critter, STAT_MAXIMUM_HIT_POINTS)) {
critterAdjustHitPoints(critter, 14 * (hours / 3));
critterAdjustHitPoints(critter, 14 * (a2 / 3));
}
critter->data.critter.combat.maneuver &= ~CRITTER_MANUEVER_FLEEING;
@@ -815,7 +815,7 @@ static int _critterClearObjDrugs(Object* obj, void* data)
}
// 0x42DA64
void critterKill(Object* critter, int anim, bool refreshRect)
void critterKill(Object* critter, int anim, bool a3)
{
if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) {
return;
@@ -904,7 +904,7 @@ void critterKill(Object* critter, int anim, bool refreshRect)
itemDestroyAllHidden(critter);
if (refreshRect) {
if (a3) {
tileWindowRefreshRect(&updatedRect, elevation);
}
@@ -1282,23 +1282,21 @@ int _critter_wake_clear(Object* obj, void* data)
}
// 0x42E4C0
// note: this is sometimes called with (attacker, defender) and sometimes with (defender, attacker).
// `hitMe` may be nullptr
int _critter_set_who_hit_me(Object* critter, Object* hitMe)
int _critter_set_who_hit_me(Object* a1, Object* a2)
{
if (critter == nullptr) {
if (a1 == nullptr) {
return -1;
}
if (hitMe != nullptr && FID_TYPE(hitMe->fid) != OBJ_TYPE_CRITTER) {
if (a2 != nullptr && FID_TYPE(a2->fid) != OBJ_TYPE_CRITTER) {
return -1;
}
if (PID_TYPE(critter->pid) == OBJ_TYPE_CRITTER) {
if (hitMe == nullptr || critter->data.critter.combat.team != hitMe->data.critter.combat.team || (statRoll(critter, STAT_INTELLIGENCE, -1, nullptr) < 2 && (!objectIsPartyMember(critter) || !objectIsPartyMember(hitMe)))) {
critter->data.critter.combat.whoHitMe = hitMe;
if (hitMe == gDude) {
reactionSetValue(critter, -3);
if (PID_TYPE(a1->pid) == OBJ_TYPE_CRITTER) {
if (a2 == nullptr || a1->data.critter.combat.team != a2->data.critter.combat.team || (statRoll(a1, STAT_INTELLIGENCE, -1, nullptr) < 2 && (!objectIsPartyMember(a1) || !objectIsPartyMember(a2)))) {
a1->data.critter.combat.whoHitMe = a2;
if (a2 == gDude) {
reactionSetValue(a1, -3);
}
}
}
@@ -1348,7 +1346,7 @@ bool _critter_can_obj_dude_rest()
}
// 0x42E62C
int critterGetMovementPointCostAdjustedForCrippledLegs(Object* critter, int distance)
int critterGetMovementPointCostAdjustedForCrippledLegs(Object* critter, int actionPoints)
{
if (PID_TYPE(critter->pid) != OBJ_TYPE_CRITTER) {
return 0;
@@ -1356,11 +1354,11 @@ int critterGetMovementPointCostAdjustedForCrippledLegs(Object* critter, int dist
int flags = critter->data.critter.combat.results;
if ((flags & DAM_CRIP_LEG_LEFT) != 0 && (flags & DAM_CRIP_LEG_RIGHT) != 0) {
return 8 * distance;
return 8 * actionPoints;
} else if ((flags & DAM_CRIP_LEG_ANY) != 0) {
return 4 * distance;
return 4 * actionPoints;
} else {
return distance;
return actionPoints;
}
}
+5 -5
View File
@@ -43,8 +43,8 @@ int killsSave(File* stream);
int critterGetKillType(Object* critter);
char* killTypeGetName(int killType);
char* killTypeGetDescription(int killType);
int _critter_heal_hours(Object* obj, int hours);
void critterKill(Object* critter, int anim, bool refreshRect);
int _critter_heal_hours(Object* obj, int a2);
void critterKill(Object* critter, int anim, bool a3);
int critterGetExp(Object* critter);
bool critterIsActive(Object* critter);
bool critterIsDead(Object* critter);
@@ -64,11 +64,11 @@ int _critter_sneak_clear(Object* obj, void* data);
bool dudeIsSneaking();
int knockoutEventProcess(Object* obj, void* data);
int _critter_wake_clear(Object* obj, void* data);
int _critter_set_who_hit_me(Object* critter, Object* hitMe);
int _critter_set_who_hit_me(Object* a1, Object* a2);
bool _critter_can_obj_dude_rest();
int critterGetMovementPointCostAdjustedForCrippledLegs(Object* critter, int distance);
int critterGetMovementPointCostAdjustedForCrippledLegs(Object* critter, int a2);
bool critterIsEncumbered(Object* critter);
bool critterIsFleeing(Object* critter);
bool critterIsFleeing(Object* a1);
bool _critter_flag_check(int pid, int flag);
void critter_flag_set(int pid, int flag);
void critter_flag_unset(int pid, int flag);
+3 -11
View File
@@ -621,20 +621,12 @@ int fileNameListInit(const char* pattern, char*** fileNameListPtr, int a3, int a
int fileNamesLength = xlist->fileNamesLength;
for (int index = 0; index < fileNamesLength - 1; index++) {
if (compat_stricmp(xlist->fileNames[index], xlist->fileNames[index + 1]) == 0) {
// If the current item is equal to the next one, then remove it.
// Example 1:
// fileNamesLength = 6
// 0 1 2 3 4 5
// [a, b, c1, c2, d, e]
// duplicate found at index=2
// move items 3,4,5 to 2,3,4 and move duplicate to the end
// [a, b, c2, d, e, c1]
char* temp = xlist->fileNames[index];
memmove(&(xlist->fileNames[index]), &(xlist->fileNames[index + 1]), sizeof(*xlist->fileNames) * (xlist->fileNamesLength - index - 1));
char* temp = xlist->fileNames[index + 1];
memmove(&(xlist->fileNames[index + 1]), &(xlist->fileNames[index + 2]), sizeof(*xlist->fileNames) * (xlist->fileNamesLength - index - 1));
xlist->fileNames[xlist->fileNamesLength - 1] = temp;
fileNamesLength--;
index--; // Repeat the same index if there are more duplicates.
index--;
}
}
+9 -10
View File
@@ -154,11 +154,10 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i
MessageListItem messageListItem;
int savedFont = fontGetCurrent();
bool initializedButtons = false;
bool v86 = false;
bool hasTwoButtons = false;
if (a8 != nullptr) {
// TODO: a8 seems to be a way to customize "NO", but is unused.
hasTwoButtons = true;
}
@@ -170,7 +169,7 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i
if ((flags & DIALOG_BOX_YES_NO) != 0) {
hasTwoButtons = true;
flags |= DIALOG_BOX_LARGE;
flags &= ~DIALOG_BOX_NO_BUTTONS;
flags &= ~DIALOG_BOX_0x20;
}
int maximumLineWidth = 0;
@@ -228,7 +227,7 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i
FrmImage buttonNormalFrmImage;
FrmImage buttonPressedFrmImage;
if ((flags & DIALOG_BOX_NO_BUTTONS) == 0) {
if ((flags & DIALOG_BOX_0x20) == 0) {
int doneBoxFid = buildFid(OBJ_TYPE_INTERFACE, 209, 0, 0, 0);
if (!doneBoxFrmImage.lock(doneBoxFid)) {
fontSetCurrent(savedFont);
@@ -305,13 +304,13 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i
buttonSetCallbacks(btn, _gsound_red_butt_press, _gsound_red_butt_release);
}
initializedButtons = true;
v86 = true;
}
if (hasTwoButtons && dialogType == DIALOG_TYPE_LARGE) {
if (initializedButtons) {
if (v86) {
if ((flags & DIALOG_BOX_YES_NO) != 0) {
a8 = getmsg(&messageList, &messageListItem, 102); // 102 - NO
a8 = getmsg(&messageList, &messageListItem, 102);
}
fontSetCurrent(103);
@@ -411,7 +410,7 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i
buttonSetCallbacks(btn, _gsound_red_butt_press, _gsound_red_butt_release);
}
initializedButtons = true;
v86 = true;
}
}
@@ -538,7 +537,7 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i
} else if (keyCode == KEY_ESCAPE || keyCode == 501) {
rc = 0;
} else {
if ((flags & DIALOG_BOX_YES_NO) != 0) {
if ((flags & 0x10) != 0) {
if (keyCode == KEY_UPPERCASE_Y || keyCode == KEY_LOWERCASE_Y) {
rc = 1;
} else if (keyCode == KEY_UPPERCASE_N || keyCode == KEY_LOWERCASE_N) {
@@ -558,7 +557,7 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i
windowDestroy(win);
fontSetCurrent(savedFont);
if (initializedButtons) {
if (v86) {
messageListFree(&messageList);
}
+5 -5
View File
@@ -4,12 +4,12 @@
namespace fallout {
typedef enum DialogBoxOptions {
DIALOG_BOX_LARGE = 0x01, // sfall calls this NORMAL
DIALOG_BOX_MEDIUM = 0x02, // sfall: SMALL
DIALOG_BOX_NO_HORIZONTAL_CENTERING = 0x04, // sfall: ALIGN_LEFT
DIALOG_BOX_NO_VERTICAL_CENTERING = 0x08, // sfall: ALIGN_TOP
DIALOG_BOX_LARGE = 0x01,
DIALOG_BOX_MEDIUM = 0x02,
DIALOG_BOX_NO_HORIZONTAL_CENTERING = 0x04,
DIALOG_BOX_NO_VERTICAL_CENTERING = 0x08,
DIALOG_BOX_YES_NO = 0x10,
DIALOG_BOX_NO_BUTTONS = 0x20, // sfall: CLEAN
DIALOG_BOX_0x20 = 0x20,
} DialogBoxOptions;
int showDialogBox(const char* title, const char** body, int bodyLength, int x, int y, int titleColor, const char* a8, int bodyColor, int flags);

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