Merge branch 'main' into mingw-fixes

This commit is contained in:
k3tamina 2022-06-14 20:53:44 +02:00 committed by GitHub
commit 39efadcb6b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
56 changed files with 3530 additions and 2101 deletions

1
.gitattributes vendored
View File

@ -1,6 +1,7 @@
# Force LF
*.c text eol=lf
*.cc text eol=lf
*.cmake text eol=lf
*.h text eol=lf
*.md text eol=lf
*.json text eol=lf

View File

@ -4,15 +4,17 @@ on:
push:
paths:
- '.github/workflows/Build.yml'
- 'src/**.c'
- 'src/**.cc'
- 'src/**.h'
- '**/CMakeLists.txt'
- '**/*.cmake'
pull_request:
paths:
- '.github/workflows/Build.yml'
- 'src/**.c'
- 'src/**.cc'
- 'src/**.h'
- '**/CMakeLists.txt'
- '**/*.cmake'
defaults:
run:
@ -20,23 +22,195 @@ defaults:
jobs:
Build:
runs-on: windows-latest
StaticAnalysis:
name: Static analysis
runs-on: ubuntu-latest
steps:
- name: Install
run: |
:
echo ::group::apt update
sudo apt update 2>&1
echo ::endgroup::
sudo apt install cppcheck
- name: Clone
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: cppcheck
run: cppcheck --std=c++17 src/
Build:
name: ${{ matrix.cfg.name }} x${{ matrix.cfg.arch }}
runs-on: ${{ matrix.cfg.os }}
needs: [StaticAnalysis]
strategy:
fail-fast: false
matrix:
cfg:
#
# name .......... overrides job name in GitHub UI
# os ............ defines system image; passed to job.<id>.runs-on
# cc ............ defines C compiler; passed to CMake configuration step (as `CC` environment variable)
# cxx ........... defines C++ compiler; passed to CMake configuration step (as `CXX` environment variable)
# ver ........... defines optional suffix to package name when installing compiler with apt, and whenever compiler version is important for build process
# cc: gcc, cxx: g++, ver: null --becomes--> sudo apt install gcc g++
# cc: gcc, cxx: g++, ver: 10 --becomes--> sudo apt install gcc-10 g++-10
# arch .......... defines if building 32bit or 64bit application; used in multiple places to prepare build environment
# also used as job name suffix (" x32" or " x64")
# generator ..... passed to CMake configuration step (as `-G` switch)
# can-fail ...... defines if job status should be set to success even if compilation fails
# applies *only* to compilation step; errors in any other steps (installation, preparing build directory, etc.) still mark job as failed
# artifact ...... path to compiled application; use "NO" if given job run should not generate any artifacts (case sensitive)
# artifact-os ... defines artifact name suffix
#
- { name: Linux GCC, os: ubuntu-20.04, cc: gcc, cxx: g++, ver: null, arch: 32, generator: "Unix Makefiles", can-fail: false, artifact: Build/fallout2-ce, artifact-os: linux }
# { name: Linux GCC, os: ubuntu-22.04, cc: gcc, cxx: g++, ver: null, arch: 64, generator: "Unix Makefiles", can-fail: true, artifact: Build/fallout2-ce, artifact-os: linux }
- { name: Linux GCC 10, os: ubuntu-22.04, cc: gcc, cxx: g++, ver: 10, arch: 32, generator: "Unix Makefiles", can-fail: false, artifact: NO, artifact-os: linux }
# { name: Linux GCC 10, os: ubuntu-22.04, cc: gcc, cxx: g++, ver: 10, arch: 64, generator: "Unix Makefiles", can-fail: true, artifact: NO, artifact-os: linux }
# { name: MacOS 11 CLang, os: macOS-11, cc: clang, cxx: clang++, ver: null, arch: 64, generator: "Unix Makefiles", can-fail: true, artifact: NO, artifact-os: mac }
# { name: MacOS 12 CLang, os: macOS-12, cc: clang, cxx: clang++, ver: null, arch: 64, generator: "Unix Makefiles", can-fail: true, artifact: NO, artifact-os: mac }
- { name: Windows VS2019, os: windows-2019, cc: cl, cxx: cl, ver: null, arch: 32, generator: "Visual Studio 16 2019", can-fail: false, artifact: NO, artifact-os: windows }
# { name: Windows VS2019, os: windows-2019, cc: cl, cxx: cl, ver: null, arch: 64, generator: "Visual Studio 16 2019", can-fail: true, artifact: NO, artifact-os: windows }
- { name: Windows VS2022, os: windows-2022, cc: cl, cxx, cl, ver: null, arch: 32, generator: "Visual Studio 17 2022", can-fail: false, artifact: Build/Release/fallout2-ce.exe, artifact-os: windows }
# { name: Windows VS2022, os: windows-2022, cc: cl, cxx, cl, ver: null, arch: 64, generator: "Visual Studio 17 2022", can-fail: true, artifact: Build/Release/fallout2-ce.exe, artifact-os: windows }
steps:
- name: Configure
run: |
: Here be dragons :
#set -x
arch=${{ matrix.cfg.arch }}
ver="${{ matrix.cfg.ver }}"
cc="${{ matrix.cfg.cc }}"
cxx="${{ matrix.cfg.cxx }}"
# Variables exported for other steps:
#
# GHA_PM .................. packages manager executable (might include `sudo`); if not exported, `Install` step is skipped
# GHA_PM_COMPILER ......... compiler package(s), including version (if set in matrix)
# GHA_PM_COMPILER_EXTRA ... extra compiler packages
# GHA_PM_LIBS ............. required libraries packages
# GHA_CC .................. C compiler executable, including version (if set in matrix)
# GHA_CXX ................. C++ compiler executable, including version (if set in matrix)
# GHA_PLATFORM ............ CMake -A ... switch, for configure step
# GHA_TOOLCHAIN ........... CMake -DCMAKE_TOOLCHAIN_FILE=... switch, for configure step
# Compiler executables names
[[ "$ver" != "" ]] && verCMAKE="-$ver"
echo GHA_CC="$cc$verCMAKE" >> $GITHUB_ENV
echo GHA_CXX="$cxx$verCMAKE" >> $GITHUB_ENV
if [[ $arch -ne 32 ]] && [[ $arch -ne 64 ]]; then
echo "[ERROR] matrix.cfg.arch must be set to 32 or 64"
exit 1
elif [[ "$ver" != "" ]] && ! [[ "$ver" =~ [0-9]+ ]]; then
echo "[ERROR] matrix.cfg.ver must be null or number"
exit 1
elif [[ $RUNNER_OS == "Linux" ]]; then
[[ "$ver" != "" ]] && verPM="-$ver"
echo GHA_PM="sudo apt" >> $GITHUB_ENV
apt="amd64"
if [[ "$cc" == "clang" ]] && [[ "$cxx" == "clang++" ]]; then
echo GHA_PM_COMPILER="$cc$verPM" >> $GITHUB_ENV
else
echo GHA_PM_COMPILER="$cc$verPM $cxx$verPM" >> $GITHUB_ENV
fi
# Handle building 32bit executable on 64bit host
if [[ $arch -eq 32 ]]; then
apt="i386"
sudo dpkg --add-architecture $apt
# Extra packages
echo GHA_PM_COMPILER_EXTRA="gcc${verPM}-multilib g++${verPM}-multilib" >> $GITHUB_ENV
# Toolchain file; without proper 32@64 toolchain setup CMake can't find OpenGL libraries
echo GHA_TOOLCHAIN="-DCMAKE_TOOLCHAIN_FILE=cmake/toolchain/Linux32.cmake" >> $GITHUB_ENV
fi
echo GHA_PM_LIBS="libsdl2-dev:$apt zlib1g-dev:$apt" >> $GITHUB_ENV
elif [[ $RUNNER_OS == "macOS" ]]; then
[[ "$ver" != "" ]] && verPM="@$ver"
echo GHA_PM="brew" >> $GITHUB_ENV
if [[ "$cc" == "gcc" ]] && [[ "$cxx" == "g++" ]]; then
echo GHA_PM_COMPILER="$cc$verPM" >> $GITHUB_ENV
elif [[ "$cc" == "clang" ]] && [[ "$cxx" == "clang++" ]]; then
echo GHA_PM_COMPILER="llvm$verPM" >> $GITHUB_ENV
fi
echo GHA_PM_LIBS="sdl2" >> $GITHUB_ENV
elif [[ $RUNNER_OS == "Windows" ]]; then
# VisualStudio; '-A' switch is used to compile 32bit targets on 64bit hosts
if [[ "${{ matrix.cfg.generator }}" =~ ^Visual ]]; then
if [[ $arch -eq 32 ]]; then
echo GHA_PLATFORM="-A Win32" >> $GITHUB_ENV
else
echo GHA_PLATFORM="-A x64" >> $GITHUB_ENV
fi
fi
fi
- name: Install
if: env.GHA_PM != ''
run: |
:
#set -x
echo ::group::Update package manager
$GHA_PM update 2>&1
echo ::endgroup::
if [[ ${{ matrix.cfg.arch }} -eq 32 ]] && ([[ "$ImageOS" == "ubuntu20" ]] || [[ "${{ matrix.cfg.os }}" == "ubuntu-20.04" ]]); then
echo ::group::Fix Ubuntu 20
$GHA_PM install --allow-downgrades libpcre2-8-0=10.34-7
echo ::endgroup::
fi
if [[ "$GHA_PM_COMPILER" != "" ]] || [[ "$GHA_PM_COMPILER_EXTRA" ]]; then
echo ::group::Compiler
$GHA_PM install $GHA_PM_COMPILER $GHA_PM_COMPILER_EXTRA
echo ::endgroup::
fi
if [[ "$GHA_PM_LIBS" != "" ]]; then
echo ::group::Libraries
$GHA_PM install $GHA_PM_LIBS
echo :endgroup::
fi
- name: Clone
uses: actions/checkout@v3
# Using ${{ env.NAME }} here (instead of usual $NAME) to make full command line clearly displayed, without need to check step environment first
- name: Prepare
run: cmake -B Build -A Win32
run: cmake -B Build -G "${{ matrix.cfg.generator }}" ${{ env.GHA_PLATFORM }} ${{ env.GHA_TOOLCHAIN }} 2>&1
env:
CC: ${{ env.GHA_CC }}
CXX: ${{ env.GHA_CXX }}
- name: Release build
run: cmake --build Build --config Release
- name: Build
run: cmake --build Build --config Release && echo BUILD_OK=1 >> $GITHUB_ENV
continue-on-error: ${{ matrix.cfg.can-fail }}
- name: Artifact
- name: Artifact prepare
if: matrix.cfg.artifact != 'NO' && env.BUILD_OK == 1
run: |
:
echo BUILD_OK=0 >> $GITHUB_ENV
dir="${{ matrix.cfg.artifact-os }}/x${{ matrix.cfg.arch }}"
mkdir -p "$dir"
cp "${{ matrix.cfg.artifact }}" "$dir"
echo BUILD_OK=1 >> $GITHUB_ENV
- name: Artifact upload
if: matrix.cfg.artifact != 'NO' && env.BUILD_OK == 1
uses: actions/upload-artifact@v3
with:
name: fallout2-ce
path: |
Build/*/fallout2-ce.exe
name: fallout2-ce-${{ matrix.cfg.artifact-os }}
path: "${{ matrix.cfg.artifact-os }}/x${{ matrix.cfg.arch }}"
retention-days: 7

View File

@ -247,6 +247,11 @@ if(WIN32)
_CRT_SECURE_NO_WARNINGS
_CRT_NONSTDC_NO_WARNINGS
)
else()
target_compile_definitions(${EXECUTABLE_NAME} PRIVATE
$<$<CONFIG:Debug>:_DEBUG>
$<$<CONFIG:RelWithDebInfo>:_DEBUG>
)
endif()
if(WIN32)
@ -259,7 +264,7 @@ add_subdirectory("third_party/fpattern")
target_link_libraries(${EXECUTABLE_NAME} ${FPATTERN_LIBRARY})
target_include_directories(${EXECUTABLE_NAME} PRIVATE ${FPATTERN_INCLUDE_DIR})
if(NOT APPLE)
if(NOT APPLE AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Linux")
add_subdirectory("third_party/zlib")
add_subdirectory("third_party/sdl2")
else()

View File

@ -0,0 +1,4 @@
set( CMAKE_SYSTEM_NAME "Linux" )
set( CMAKE_SYSTEM_PROCESSOR "i386" )
set( CMAKE_C_FLAGS "-m32" )
set( CMAKE_CXX_FLAGS "-m32" )

View File

@ -40,8 +40,8 @@ int _action_in_explode = 0;
const int gNormalDeathAnimations[DAMAGE_TYPE_COUNT] = {
ANIM_DANCING_AUTOFIRE,
ANIM_SLICED_IN_HALF,
ANIM_CHUNKS_OF_FLESH,
ANIM_CHUNKS_OF_FLESH,
ANIM_CHARRED_BODY,
ANIM_CHARRED_BODY,
ANIM_ELECTRIFY,
ANIM_FALL_BACK,
ANIM_BIG_HOLE,
@ -1454,7 +1454,7 @@ int _pick_fall(Object* obj, int anim)
}
}
} else if (anim == ANIM_FALL_BACK) {
rotation = (obj->rotation + 3) % 6u;
rotation = (obj->rotation + 3) % ROTATION_COUNT;
for (i = 1; i < 3; i++) {
tile_num = tileGetTileInDirection(obj->tile, rotation, i);
if (_obj_blocking_at(obj, tile_num, obj->elevation) != NULL) {
@ -1725,7 +1725,7 @@ int _compute_explosion_damage(int min, int max, Object* a3, int* a4)
}
if (a4 != NULL) {
if ((a3->flags & OBJECT_FLAG_0x800) == 0) {
if ((a3->flags & OBJECT_MULTIHEX) == 0) {
*a4 = v7 / 10;
}
}
@ -1892,7 +1892,7 @@ int _compute_dmg_damage(int min, int max, Object* obj, int* a4, int damageType)
}
if (a4 != NULL) {
if ((obj->flags & OBJECT_FLAG_0x800) == 0 && damageType != DAMAGE_TYPE_ELECTRICAL) {
if ((obj->flags & OBJECT_MULTIHEX) == 0 && damageType != DAMAGE_TYPE_ELECTRICAL) {
*a4 = v10 / 10;
}
}

View File

@ -1682,7 +1682,7 @@ int _make_straight_path_func(Object* a1, int from, int to, STRUCT_530014_28* a4,
if (a5 != NULL) {
Object* v11 = a7(a1, from, a1->elevation);
if (v11 != NULL) {
if (v11 != *a5 && (a6 != 32 || (v11->flags & OBJECT_FLAG_0x80000000) == 0)) {
if (v11 != *a5 && (a6 != 32 || (v11->flags & OBJECT_SHOOT_THRU) == 0)) {
*a5 = v11;
return 0;
}
@ -1726,7 +1726,7 @@ int _make_straight_path_func(Object* a1, int from, int to, STRUCT_530014_28* a4,
int tileY = fromY;
int pathNodeIndex = 0;
int v50 = from;
int prevTile = from;
int v22 = 0;
int tile;
@ -1770,17 +1770,17 @@ int _make_straight_path_func(Object* a1, int from, int to, STRUCT_530014_28* a4,
tileY += stepY;
middle += v48;
if (tile != v50) {
if (tile != prevTile) {
if (a5 != NULL) {
Object* obj = a7(a1, tile, a1->elevation);
if (obj != NULL) {
if (obj != *a5 && (a6 != 32 || (obj->flags & OBJECT_FLAG_0x80000000) == 0)) {
if (obj != *a5 && (a6 != 32 || (obj->flags & OBJECT_SHOOT_THRU) == 0)) {
*a5 = obj;
break;
}
}
}
v50 = tile;
prevTile = tile;
}
}
} else {
@ -1823,16 +1823,17 @@ int _make_straight_path_func(Object* a1, int from, int to, STRUCT_530014_28* a4,
tileX += stepX;
middle += v47;
if (tile != v50) {
if (tile != prevTile) {
if (a5 != NULL) {
Object* obj = a7(a1, tile, a1->elevation);
if (obj != NULL) {
if (obj != *a5 && (a6 != 32 || (obj->flags & OBJECT_FLAG_0x80000000) == 0)) {
if (obj != *a5 && (a6 != 32 || (obj->flags & OBJECT_SHOOT_THRU) == 0)) {
*a5 = obj;
break;
}
}
}
prevTile = tile;
}
}
}
@ -1863,38 +1864,35 @@ int _make_straight_path_func(Object* a1, int from, int to, STRUCT_530014_28* a4,
}
// 0x4167F8
int animateMoveObjectToObject(Object* a1, Object* a2, int a3, int anim, int animationSequenceIndex)
int animateMoveObjectToObject(Object* from, Object* to, int a3, int anim, int animationSequenceIndex)
{
int v10;
int v13;
STRUCT_530014* ptr;
bool hidden = (to->flags & OBJECT_HIDDEN);
to->flags |= OBJECT_HIDDEN;
int hidden = (a2->flags & OBJECT_HIDDEN);
a2->flags |= OBJECT_HIDDEN;
int moveSadIndex = _anim_move(from, to->tile, to->elevation, -1, anim, 0, animationSequenceIndex);
v10 = _anim_move(a1, a2->tile, a2->elevation, -1, anim, 0, animationSequenceIndex);
if (hidden == 0) {
a2->flags &= ~OBJECT_HIDDEN;
if (!hidden) {
to->flags &= ~OBJECT_HIDDEN;
}
if (v10 == -1) {
if (moveSadIndex == -1) {
return -1;
}
ptr = &(_sad[v10]);
v13 = (((a1->flags & OBJECT_FLAG_0x800) != 0) + 1); // TODO: What the hell is this?
ptr->field_1C -= v13;
STRUCT_530014* ptr = &(_sad[moveSadIndex]);
// NOTE: Original code is somewhat different. Due to some kind of
// optimization this value is either 1 or 2, which is later used in
// subsequent calculations and rotations array lookup.
bool isMultihex = (from->flags & OBJECT_MULTIHEX);
ptr->field_1C -= (isMultihex ? 2 : 1);
if (ptr->field_1C <= 0) {
ptr->field_20 = -1000;
_anim_set_continue(animationSequenceIndex, 0);
}
if (v13) {
ptr->field_24 = tileGetTileInDirection(a2->tile, ptr->field_24 + v13 + ptr->field_1C + 3, 1);
}
ptr->field_24 = tileGetTileInDirection(to->tile, ptr->rotations[isMultihex ? ptr->field_1C + 1 : ptr->field_1C], 1);
if (v13 == 2) {
if (isMultihex) {
ptr->field_24 = tileGetTileInDirection(ptr->field_24, ptr->rotations[ptr->field_1C], 1);
}

View File

@ -257,15 +257,15 @@ int _idist(int a1, int a2, int a3, int a4);
int _tile_idistance(int tile1, int tile2);
int _make_straight_path(Object* a1, int from, int to, STRUCT_530014_28* pathNodes, Object** a5, int a6);
int _make_straight_path_func(Object* a1, int from, int to, STRUCT_530014_28* a4, Object** a5, int a6, Object* (*a7)(Object*, int, int));
int animateMoveObjectToObject(Object* a1, Object* a2, int a3, int a4, int a5);
int animateMoveObjectToTile(Object* obj, int tile_num, int elev, int a4, int a5, int a6);
int _anim_move(Object* obj, int tile, int elev, int a3, int a4, int a5, int animationSequenceIndex);
int _anim_move_straight_to_tile(Object* obj, int a2, int a3, int fid, int a5, int a6);
int _anim_move_on_stairs(Object* obj, int a2, int a3, int fid, int a5);
int _check_for_falling(Object* obj, int a2, int a3);
int animateMoveObjectToObject(Object* from, Object* to, int a3, int anim, int animationSequenceIndex);
int animateMoveObjectToTile(Object* obj, int tile_num, int elev, int a4, int anim, int animationSequenceIndex);
int _anim_move(Object* obj, int tile, int elev, int a3, int anim, int a5, int animationSequenceIndex);
int _anim_move_straight_to_tile(Object* obj, int tile, int elevation, int anim, int animationSequenceIndex, int flags);
int _anim_move_on_stairs(Object* obj, int tile, int elevation, int anim, int animationSequenceIndex);
int _check_for_falling(Object* obj, int anim, int a3);
void _object_move(int index);
void _object_straight_move(int a1);
int _anim_animate(Object* obj, int a2, int a3, int a4);
void _object_straight_move(int index);
int _anim_animate(Object* obj, int anim, int animationSequenceIndex, int flags);
void _object_animate();
void _object_anim_compact();
int _check_move(int* a1);
@ -274,8 +274,8 @@ int _dude_run(int a1);
void _dude_fidget();
void _dude_stand(Object* obj, int rotation, int fid);
void _dude_standup(Object* a1);
int actionRotate(Object* obj, int a2, int a3);
int _anim_change_fid(Object* obj, int a2, int fid);
int actionRotate(Object* obj, int delta, int animationSequenceIndex);
int _anim_change_fid(Object* obj, int animationSequenceIndex, int fid);
void _anim_stop();
int _check_gravity(int tile, int elevation);
unsigned int _compute_tpf(Object* object, int fid);

View File

@ -7,11 +7,24 @@
#include "memory.h"
#include "object.h"
#include "proto.h"
#include "sfall_config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 0x5002D8
char gDefaultJumpsuitMaleFileName[] = "hmjmps";
// 0x05002E0
char gDefaultJumpsuitFemaleFileName[] = "hfjmps";
// 0x5002E8
char gDefaultTribalMaleFileName[] = "hmwarr";
// 0x5002F0
char gDefaultTribalFemaleFileName[] = "hfprim";
// 0x510738
ArtListDescription gArtListDescriptions[OBJ_TYPE_COUNT] = {
{ 0, "items", 0, 0, 0 },
@ -153,18 +166,43 @@ int artInit()
return -1;
}
// SFALL: Modify player model settings.
char* jumpsuitMaleFileName = NULL;
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_DUDE_NATIVE_LOOK_JUMPSUIT_MALE_KEY, &jumpsuitMaleFileName);
if (jumpsuitMaleFileName == NULL || jumpsuitMaleFileName[0] == '\0') {
jumpsuitMaleFileName = gDefaultJumpsuitMaleFileName;
}
char* jumpsuitFemaleFileName = NULL;
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_DUDE_NATIVE_LOOK_JUMPSUIT_FEMALE_KEY, &jumpsuitFemaleFileName);
if (jumpsuitFemaleFileName == NULL || jumpsuitFemaleFileName[0] == '\0') {
jumpsuitFemaleFileName = gDefaultJumpsuitFemaleFileName;
}
char* tribalMaleFileName = NULL;
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_DUDE_NATIVE_LOOK_TRIBAL_MALE_KEY, &tribalMaleFileName);
if (tribalMaleFileName == NULL || tribalMaleFileName[0] == '\0') {
tribalMaleFileName = gDefaultTribalMaleFileName;
}
char *tribalFemaleFileName = NULL;
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_DUDE_NATIVE_LOOK_TRIBAL_FEMALE_KEY, &tribalFemaleFileName);
if (tribalFemaleFileName == NULL || tribalFemaleFileName[0] == '\0') {
tribalFemaleFileName = gDefaultTribalFemaleFileName;
}
ptr = gArtListDescriptions[1].fileNames;
for (i = 0; i < gArtListDescriptions[1].fileNamesLength; i++) {
if (compat_stricmp(ptr, "hmjmps") == 0) {
if (compat_stricmp(ptr, jumpsuitMaleFileName) == 0) {
_art_vault_person_nums[DUDE_NATIVE_LOOK_JUMPSUIT][GENDER_MALE] = i;
} else if (compat_stricmp(ptr, "hfjmps") == 0) {
} else if (compat_stricmp(ptr, jumpsuitFemaleFileName) == 0) {
_art_vault_person_nums[DUDE_NATIVE_LOOK_JUMPSUIT][GENDER_FEMALE] = i;
}
if (compat_stricmp(ptr, "hmwarr") == 0) {
if (compat_stricmp(ptr, tribalMaleFileName) == 0) {
_art_vault_person_nums[DUDE_NATIVE_LOOK_TRIBAL][GENDER_MALE] = i;
_art_vault_guy_num = i;
} else if (compat_stricmp(ptr, "hfprim") == 0) {
} else if (compat_stricmp(ptr, tribalFemaleFileName) == 0) {
_art_vault_person_nums[DUDE_NATIVE_LOOK_TRIBAL][GENDER_FEMALE] = i;
}

View File

@ -124,6 +124,11 @@ typedef enum DudeNativeLook {
DUDE_NATIVE_LOOK_COUNT,
} DudeNativeLook;
extern char gDefaultJumpsuitMaleFileName[];
extern char gDefaultJumpsuitFemaleFileName[];
extern char gDefaultTribalMaleFileName[];
extern char gDefaultTribalFemaleFileName[];
extern ArtListDescription gArtListDescriptions[OBJ_TYPE_COUNT];
extern bool gArtLanguageInitialized;
extern const char* _head1;

View File

@ -458,7 +458,7 @@ void automapRenderInMapWindow(int window, int elevation, unsigned char* backgrou
&& (object->data.critter.combat.results & DAM_DEAD) == 0) {
objectColor = _colorTable[31744];
} else {
if ((object->flags & OBJECT_FLAG_0x40000000) == 0) {
if ((object->flags & OBJECT_SEEN) == 0) {
continue;
}
@ -1011,7 +1011,7 @@ void _decode_map_data(int elevation)
Object* object = objectFindFirstAtElevation(elevation);
while (object != NULL) {
if (object->tile != -1 && (object->flags & OBJECT_FLAG_0x40000000) != 0) {
if (object->tile != -1 && (object->flags & OBJECT_SEEN) != 0) {
int contentType;
int objectType = (object->fid & 0xF000000) >> 24;

View File

@ -5,7 +5,7 @@
#include "sound.h"
#include <limits.h>
#include <stdlib.h> // qsort
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

File diff suppressed because it is too large Load Diff

View File

@ -126,10 +126,12 @@ typedef struct TownReputationEntry {
int city;
} TownReputationEntry;
typedef struct STRUCT_56FCB0 {
int field_0;
char* field_4;
} STRUCT_56FCB0;
typedef struct PerkDialogOption {
// Depending on the current mode this value is the id of either
// perk, trait (handling Mutate perk), or skill (handling Tag perk).
int value;
char* name;
} PerkDialogOption;
// TODO: Field order is probably wrong.
typedef struct KillInfo {
@ -138,11 +140,11 @@ typedef struct KillInfo {
int kills;
} KillInfo;
extern int _grph_id[50];
extern const unsigned char _copyflag[EDITOR_GRAPHIC_COUNT];
extern const int word_431D3A[EDITOR_DERIVED_STAT_COUNT];
extern const int _StatYpos[7];
extern const int word_431D6C[EDITOR_DERIVED_STAT_COUNT];
extern int gCharacterEditorFrmIds[50];
extern const unsigned char gCharacterEditorFrmShouldCopy[EDITOR_GRAPHIC_COUNT];
extern const int gCharacterEditorDerivedStatFrmIds[EDITOR_DERIVED_STAT_COUNT];
extern const int gCharacterEditorPrimaryStatY[7];
extern const int gCharacterEditorDerivedStatsMap[EDITOR_DERIVED_STAT_COUNT];
extern char byte_431D93[64];
extern const int dword_431DD4[7];
@ -151,10 +153,10 @@ extern const double dbl_501713;
extern const double dbl_5018F0;
extern const double dbl_5019BE;
extern bool _bk_enable_0;
extern int _skill_cursor;
extern int _slider_y;
extern int characterEditorRemainingCharacterPoints;
extern bool gCharacterEditorIsoWasEnabled;
extern int gCharacterEditorCurrentSkill;
extern int gCharacterEditorSkillValueAdjustmentSliderY;
extern int gCharacterEditorRemainingCharacterPoints;
extern KarmaEntry* gKarmaEntries;
extern int gKarmaEntriesLength;
extern GenericReputationEntry* gGenericReputationEntries;
@ -162,148 +164,148 @@ extern int gGenericReputationEntriesLength;
extern const TownReputationEntry gTownReputationEntries[TOWN_REPUTATION_COUNT];
extern const int gAddictionReputationVars[ADDICTION_REPUTATION_COUNT];
extern const int gAddictionReputationFrmIds[ADDICTION_REPUTATION_COUNT];
extern int _folder_up_button;
extern int _folder_down_button;
extern int gCharacterEditorFolderViewScrollUpBtn;
extern int gCharacterEditorFolderViewScrollDownBtn;
extern char _folder_card_string[256];
extern int _skillsav[SKILL_COUNT];
extern MessageList editorMessageList;
extern STRUCT_56FCB0 _name_sort_list[DIALOG_PICKER_NUM_OPTIONS];
extern int _trait_bids[TRAIT_COUNT];
extern MessageListItem editorMessageListItem;
extern char _old_str1[48];
extern char _old_str2[48];
extern int _tag_bids[SKILL_COUNT];
extern char _name_save[32];
extern Size _GInfo[EDITOR_GRAPHIC_COUNT];
extern CacheEntry* _grph_key[EDITOR_GRAPHIC_COUNT];
extern unsigned char* _grphcpy[EDITOR_GRAPHIC_COUNT];
extern unsigned char* _grphbmp[EDITOR_GRAPHIC_COUNT];
extern int _folder_max_lines;
extern int _folder_line;
extern int _folder_card_fid;
extern int _folder_top_line;
extern char* _folder_card_title;
extern char* _folder_card_title2;
extern int _folder_yoffset;
extern int _folder_karma_top_line;
extern int _folder_highlight_line;
extern char* _folder_card_desc;
extern int _folder_ypos;
extern int _folder_kills_top_line;
extern int _folder_perk_top_line;
extern unsigned char* gEditorPerkBackgroundBuffer;
extern int gEditorPerkWindow;
extern int _SliderPlusID;
extern int _SliderNegID;
extern int _stat_bids_minus[7];
extern unsigned char* characterEditorWindowBuf;
extern int characterEditorWindowHandle;
extern int _stat_bids_plus[7];
extern unsigned char* gEditorPerkWindowBuffer;
extern CritterProtoData _dude_data;
extern unsigned char* characterEditorWindowBackgroundBuf;
extern int _cline;
extern int _oldsline;
extern int _upsent_points_back;
extern int _last_level;
extern int characterEditorWindowOldFont;
extern int _kills_count;
extern CacheEntry* _bck_key;
extern int _hp_back;
extern int _mouse_ypos;
extern int _mouse_xpos;
extern char gCharacterEditorFolderCardString[256];
extern int gCharacterEditorSkillsBackup[SKILL_COUNT];
extern MessageList gCharacterEditorMessageList;
extern PerkDialogOption gPerkDialogOptionList[DIALOG_PICKER_NUM_OPTIONS];
extern int gCharacterEditorOptionalTraitBtns[TRAIT_COUNT];
extern MessageListItem gCharacterEditorMessageListItem;
extern char gCharacterEditorCardTitle[48];
extern char gPerkDialogCardTitle[48];
extern int gCharacterEditorTagSkillBtns[SKILL_COUNT];
extern char gCharacterEditorNameBackup[32];
extern Size gCharacterEditorFrmSize[EDITOR_GRAPHIC_COUNT];
extern CacheEntry* gCharacterEditorFrmHandle[EDITOR_GRAPHIC_COUNT];
extern unsigned char* gCharacterEditorFrmCopy[EDITOR_GRAPHIC_COUNT];
extern unsigned char* gCharacterEditorFrmData[EDITOR_GRAPHIC_COUNT];
extern int gCharacterEditorFolderViewMaxLines;
extern int gCharacterEditorFolderViewCurrentLine;
extern int gCharacterEditorFolderCardFrmId;
extern int gCharacterEditorFolderViewTopLine;
extern char* gCharacterEditorFolderCardTitle;
extern char* gCharacterEditorFolderCardSubtitle;
extern int gCharacterEditorFolderViewOffsetY;
extern int gCharacterEditorKarmaFolderTopLine;
extern int gCharacterEditorFolderViewHighlightedLine;
extern char* gCharacterEditorFolderCardDescription;
extern int gCharacterEditorFolderViewNextY;
extern int gCharacterEditorKillsFolderTopLine;
extern int gCharacterEditorPerkFolderTopLine;
extern unsigned char* gPerkDialogBackgroundBuffer;
extern int gPerkDialogWindow;
extern int gCharacterEditorSliderPlusBtn;
extern int gCharacterEditorSliderMinusBtn;
extern int gCharacterEditorPrimaryStatMinusBtns[7];
extern unsigned char* gCharacterEditorWindowBuffer;
extern int gCharacterEditorWindow;
extern int gCharacterEditorPrimaryStatPlusBtns[7];
extern unsigned char* gPerkDialogWindowBuffer;
extern CritterProtoData gCharacterEditorDudeDataBackup;
extern unsigned char* gCharacterEditorWindowBackgroundBuffer;
extern int gPerkDialogCurrentLine;
extern int gPerkDialogPreviousCurrentLine;
extern int gCharacterEditorUnspentSkillPointsBackup;
extern int gCharacterEditorLastLevel;
extern int gCharacterEditorOldFont;
extern int gCharacterEditorKillsCount;
extern CacheEntry* gCharacterEditorWindowBackgroundHandle;
extern int gCharacterEditorHitPointsBackup;
extern int gCharacterEditorMouseY;
extern int gCharacterEditorMouseX;
extern int characterEditorSelectedItem;
extern int characterEditorWindowSelectedFolder;
extern int _frstc_draw1;
extern int _crow;
extern int _frstc_draw2;
extern int _perk_back[PERK_COUNT];
extern bool gCharacterEditorCardDrawn;
extern int gPerkDialogTopLine;
extern bool gPerkDialogCardDrawn;
extern int gCharacterEditorPerksBackup[PERK_COUNT];
extern unsigned int _repFtime;
extern unsigned int _frame_time;
extern int _old_tags;
extern int _last_level_back;
extern int gCharacterEditorOldTaggedSkillCount;
extern int gCharacterEditorLastLevelBackup;
extern bool gCharacterEditorIsCreationMode;
extern int _tag_skill_back[NUM_TAGGED_SKILLS];
extern int _card_old_fid2;
extern int _card_old_fid1;
extern int _trait_back[3];
extern int _trait_count;
extern int _optrt_count;
extern int _temp_trait[3];
extern int _tagskill_count;
extern int _temp_tag_skill[NUM_TAGGED_SKILLS];
extern char _free_perk_back;
extern unsigned char _free_perk;
extern unsigned char _first_skill_list;
extern int gCharacterEditorTaggedSkillsBackup[NUM_TAGGED_SKILLS];
extern int gPerkDialogCardFrmId;
extern int gCharacterEditorCardFrmId;
extern int gCharacterEditorOptionalTraitsBackup[3];
extern int gCharacterEditorTempTraitCount;
extern int gPerkDialogOptionCount;
extern int gCharacterEditorTempTraits[3];
extern int gCharacterEditorTaggedSkillCount;
extern int gCharacterEditorTempTaggedSkills[NUM_TAGGED_SKILLS];
extern char gCharacterEditorHasFreePerkBackup;
extern unsigned char gCharacterEditorHasFreePerk;
extern unsigned char gCharacterEditorIsSkillsFirstDraw;
int _editor_design(bool isCreationMode);
int characterEditorShow(bool isCreationMode);
int characterEditorWindowInit();
void characterEditorWindowFree();
void _CharEditInit();
void characterEditorInit();
int _get_input_str(int win, int cancelKeyCode, char* text, int maxLength, int x, int y, int textColor, int backgroundColor, int flags);
bool _isdoschar(int ch);
char* _strmfe(char* dest, const char* name, const char* ext);
void editorRenderFolders();
void editorRenderPerks();
int _kills_list_comp(const KillInfo* a, const KillInfo* b);
int editorRenderKills();
void characterEditorRenderBigNumber(int x, int y, int flags, int value, int previousValue, int windowHandle);
void editorRenderPcStats();
void editorRenderPrimaryStat(int stat, bool animate, int previousValue);
void editorRenderGender();
void editorRenderAge();
void editorRenderName();
void editorRenderSecondaryStats();
void editorRenderSkills(int a1);
void editorRenderDetails();
void characterEditorDrawFolders();
void characterEditorDrawPerksFolder();
int characterEditorKillsCompare(const void* a1, const void* a2);
int characterEditorDrawKillsFolder();
void characterEditorDrawBigNumber(int x, int y, int flags, int value, int previousValue, int windowHandle);
void characterEditorDrawPcStats();
void characterEditorDrawPrimaryStat(int stat, bool animate, int previousValue);
void characterEditorDrawGender();
void characterEditorDrawAge();
void characterEditorDrawName();
void characterEditorDrawDerivedStats();
void characterEditorDrawSkills(int a1);
void characterEditorDrawCard();
int characterEditorEditName();
void _PrintName(unsigned char* buf, int a2);
int characterEditorRunEditAgeDialog();
void _PrintName(unsigned char* buf, int pitch);
int characterEditorEditAge();
void characterEditorEditGender();
void characterEditorHandleIncDecPrimaryStat(int eventCode);
int _OptionWindow();
void characterEditorAdjustPrimaryStat(int eventCode);
int characterEditorShowOptions();
bool characterFileExists(const char* fname);
int characterPrintToFile(const char* fileName);
char* _AddSpaces(char* string, int length);
char* _AddDots(char* string, int length);
void _ResetScreen();
void _RegInfoAreas();
void _SavePlayer();
void _RestorePlayer();
void characterEditorResetScreen();
void characterEditorRegisterInfoAreas();
void characterEditorSavePlayer();
void characterEditorRestorePlayer();
char* _itostndn(int value, char* dest);
int _DrawCard(int graphicId, const char* name, const char* attributes, char* description);
void _FldrButton();
void _InfoButton(int eventCode);
void editorAdjustSkill(int a1);
int characterEditorDrawCardWithOptions(int graphicId, const char* name, const char* attributes, char* description);
void characterEditorHandleFolderButtonPressed();
void characterEditorHandleInfoButtonPressed(int eventCode);
void characterEditorHandleAdjustSkillButtonPressed(int a1);
void characterEditorToggleTaggedSkill(int skill);
void characterEditorWindowRenderTraits();
void characterEditorDrawOptionalTraits();
void characterEditorToggleOptionalTrait(int trait);
void editorRenderKarma();
int _editor_save(File* stream);
int _editor_load(File* stream);
void _editor_reset();
int _UpdateLevel();
void _RedrwDPrks();
int editorSelectPerk();
int _InputPDLoop(int count, void (*refreshProc)());
int _ListDPerks();
void _RedrwDMPrk();
bool editorHandleMutate();
void _RedrwDMTagSkl();
bool editorHandleTag();
void _ListNewTagSkills();
int _ListMyTraits(int a1);
int _name_sort_comp(const void* a1, const void* a2);
int _DrawCard2(int frmId, const char* name, const char* rank, char* description);
void characterEditorDrawKarmaFolder();
int characterEditorSave(File* stream);
int characterEditorLoad(File* stream);
void characterEditorReset();
int characterEditorUpdateLevel();
void perkDialogRefreshPerks();
int perkDialogShow();
int perkDialogHandleInput(int count, void (*refreshProc)());
int perkDialogDrawPerks();
void perkDialogRefreshTraits();
bool perkDialogHandleMutatePerk();
void perkDialogRefreshSkills();
bool perkDialogHandleTagPerk();
void perkDialogDrawSkills();
int perkDialogDrawTraits(int a1);
int perkDialogOptionCompare(const void* a1, const void* a2);
int perkDialogDrawCard(int frmId, const char* name, const char* rank, char* description);
void _pop_perks();
int _is_supper_bonus();
int _folder_init();
void _folder_scroll(int direction);
void _folder_clear();
int _folder_print_seperator(const char* string);
bool _folder_print_line(const char* string);
bool editorDrawKillsEntry(const char* name, int kills);
int characterEditorFolderViewInit();
void characterEditorFolderViewScroll(int direction);
void characterEditorFolderViewClear();
int characterEditorFolderViewDrawHeading(const char* string);
bool characterEditorFolderViewDrawString(const char* string);
bool characterEditorFolderViewDrawKillsEntry(const char* name, int kills);
int karmaInit();
void karmaFree();
int karmaEntryCompare(const void* a1, const void* a2);
@ -311,4 +313,8 @@ int genericReputationInit();
void genericReputationFree();
int genericReputationCompare(const void* a1, const void* a2);
void customKarmaFolderInit();
void customKarmaFolderFree();
int customKarmaFolderGetFrmId();
#endif /* CHARACTER_EDITOR_H */

View File

@ -179,7 +179,7 @@ int characterSelectorOpen()
case KEY_UPPERCASE_C:
case KEY_LOWERCASE_C:
_ResetPlayer();
if (_editor_design(1) == 0) {
if (characterEditorShow(1) == 0) {
rc = 2;
done = true;
}
@ -187,7 +187,7 @@ int characterSelectorOpen()
break;
case KEY_UPPERCASE_M:
case KEY_LOWERCASE_M:
if (!_editor_design(1)) {
if (!characterEditorShow(1)) {
rc = 2;
done = true;
}

View File

@ -354,7 +354,7 @@ void _setMixTableColor(int a1)
}
// 0x4C78E4
bool colorPaletteLoad(char* path)
bool colorPaletteLoad(const char* path)
{
if (gColorFileNameMangler != NULL) {
path = gColorFileNameMangler(path);

View File

@ -5,7 +5,7 @@
#include <stdlib.h>
typedef char*(ColorFileNameManger)(char*);
typedef const char*(ColorFileNameManger)(const char*);
typedef void(ColorTransitionCallback)();
typedef int(ColorPaletteFileOpenProc)(const char* path, int mode);
@ -54,7 +54,7 @@ void _setSystemPaletteEntries(unsigned char* a1, int a2, int a3);
void _setIntensityTableColor(int a1);
void _setIntensityTables();
void _setMixTableColor(int a1);
bool colorPaletteLoad(char* path);
bool colorPaletteLoad(const char* path);
char* _colorError();
void _buildBlendTable(unsigned char* ptr, unsigned char ch);
void _rebuildColorBlendTables();

View File

@ -2542,7 +2542,7 @@ void _combat_update_critter_outline_for_los(Object* critter, bool a2)
} else {
int v7 = objectGetDistanceBetween(gDude, critter);
int v8 = critterGetStat(gDude, STAT_PERCEPTION) * 5;
if ((critter->flags & OBJECT_FLAG_0x20000) != 0) {
if ((critter->flags & OBJECT_TRANS_GLASS) != 0) {
v8 /= 2;
}
@ -3382,7 +3382,7 @@ bool _check_ranged_miss(Attack* attack)
while (curr != to) {
_make_straight_path_func(attack->attacker, curr, to, NULL, &critter, 32, _obj_shoot_blocking_at);
if (critter != NULL) {
if ((critter->flags & OBJECT_FLAG_0x80000000) == 0) {
if ((critter->flags & OBJECT_SHOOT_THRU) == 0) {
if ((critter->fid & 0xF000000) >> 24 != OBJ_TYPE_CRITTER) {
roll = ROLL_SUCCESS;
break;
@ -3412,7 +3412,7 @@ bool _check_ranged_miss(Attack* attack)
attack->defenderHitLocation = HIT_LOCATION_TORSO;
if (roll < ROLL_SUCCESS || critter == NULL || (critter->flags & OBJECT_FLAG_0x80000000) == 0) {
if (roll < ROLL_SUCCESS || critter == NULL || (critter->flags & OBJECT_SHOOT_THRU) == 0) {
return false;
}
@ -3747,7 +3747,7 @@ int attackCompute(Attack* attack)
v25 = _obj_blocking_at(NULL, attack->tile, attack->defender->elevation);
}
if (v25 != NULL && (v25->flags & OBJECT_FLAG_0x80000000) == 0) {
if (v25 != NULL && (v25->flags & OBJECT_SHOOT_THRU) == 0) {
attack->attackerFlags |= DAM_HIT;
attack->defender = v25;
attackComputeDamage(attack, 1, 2);
@ -3834,7 +3834,7 @@ void _compute_explosion_on_extras(Attack* attack, int a2, int a3, int a4)
if (v11 != NULL
&& (v11->fid & 0xF000000) >> 24 == OBJ_TYPE_CRITTER
&& (v11->data.critter.combat.results & DAM_DEAD) == 0
&& (v11->flags & OBJECT_FLAG_0x80000000) == 0
&& (v11->flags & OBJECT_SHOOT_THRU) == 0
&& !_combat_is_shot_blocked(v11, v11->tile, tile, NULL, NULL)) {
if (v11 == attack->attacker) {
attack->attackerFlags &= ~DAM_HIT;
@ -4224,7 +4224,7 @@ int attackDetermineToHit(Object* attacker, int tile, Object* defender, int hitLo
accuracy += _hit_location_penalty[hitLocation] / 2;
}
if (defender != NULL && (defender->flags & OBJECT_FLAG_0x800) != 0) {
if (defender != NULL && (defender->flags & OBJECT_MULTIHEX) != 0) {
accuracy += 15;
}
@ -4406,7 +4406,7 @@ void attackComputeDamage(Attack* attack, int ammoQuantity, int a3)
}
if (knockbackDistancePtr != NULL
&& (critter->flags & OBJECT_FLAG_0x800) == 0
&& (critter->flags & OBJECT_MULTIHEX) == 0
&& (damageType == DAMAGE_TYPE_EXPLOSION || attack->weapon == NULL || weaponGetAttackTypeForHitMode(attack->weapon, attack->hitMode) == ATTACK_TYPE_MELEE)
&& (critter->pid >> 24) == OBJ_TYPE_CRITTER
&& _critter_flag_check(critter->pid, 0x4000) == 0) {
@ -5686,7 +5686,7 @@ bool _combat_is_shot_blocked(Object* a1, int from, int to, Object* a4, int* a5)
if ((obstacle->data.critter.combat.results & (DAM_DEAD | DAM_KNOCKED_DOWN | DAM_KNOCKED_OUT)) == 0) {
*a5 += 1;
if ((obstacle->flags & OBJECT_FLAG_0x800) != 0) {
if ((obstacle->flags & OBJECT_MULTIHEX) != 0) {
*a5 += 1;
}
}
@ -5694,7 +5694,7 @@ bool _combat_is_shot_blocked(Object* a1, int from, int to, Object* a4, int* a5)
}
}
if ((obstacle->flags & OBJECT_FLAG_0x800) != 0) {
if ((obstacle->flags & OBJECT_MULTIHEX) != 0) {
int rotation = tileGetRotationTo(current, to);
current = tileGetTileInDirection(current, rotation, 1);
} else {

View File

@ -2143,13 +2143,13 @@ int _ai_move_steps_closer(Object* a1, Object* a2, int actionPoints, int a4)
}
if (actionPoints >= critterGetStat(a1, STAT_MAXIMUM_ACTION_POINTS) / 2 && artCritterFidShouldRun(a1->fid)) {
if ((a2->flags & OBJECT_FLAG_0x800) != 0) {
if ((a2->flags & OBJECT_MULTIHEX) != 0) {
reg_anim_obj_run_to_obj(a1, a2, actionPoints, 0);
} else {
reg_anim_obj_run_to_tile(a1, tile, a1->elevation, actionPoints, 0);
}
} else {
if ((a2->flags & OBJECT_FLAG_0x800) != 0) {
if ((a2->flags & OBJECT_MULTIHEX) != 0) {
reg_anim_obj_move_to_obj(a1, a2, actionPoints, 0);
} else {
reg_anim_obj_move_to_tile(a1, tile, a1->elevation, actionPoints, 0);
@ -3198,7 +3198,7 @@ bool objectCanHearObject(Object* a1, Object* a2)
int sneak = skillGetValue(a2, SKILL_SNEAK);
if (_can_see(a1, a2)) {
int v8 = perception * 5;
if ((a2->flags & OBJECT_FLAG_0x20000) != 0) {
if ((a2->flags & OBJECT_TRANS_GLASS) != 0) {
v8 /= 2;
}

View File

@ -5,6 +5,8 @@
#include "platform_compat.h"
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -178,8 +180,8 @@ bool configSetString(Config* config, const char* sectionKey, const char* key, co
return true;
}
// 0x42C05C
bool configGetInt(Config* config, const char* sectionKey, const char* key, int* valuePtr)
// 0x42C05C customized: atoi() replaced with strtol()
bool configGetInt(Config* config, const char* sectionKey, const char* key, int* valuePtr, unsigned char base /* = 0 */ )
{
if (valuePtr == NULL) {
return false;
@ -190,7 +192,13 @@ bool configGetInt(Config* config, const char* sectionKey, const char* key, int*
return false;
}
*valuePtr = atoi(stringValue);
char* end;
errno = 0;
long l = strtol(stringValue, &end, base); // see https://stackoverflow.com/a/6154614
if (((errno == ERANGE && 1 == LONG_MAX) || l > INT_MAX) || ((errno == ERANGE && l == LONG_MIN) || l < INT_MIN) || (*stringValue == '\0' || *end != '\0'))
return false;
*valuePtr = l;
return true;
}

View File

@ -27,7 +27,7 @@ void configFree(Config* config);
bool configParseCommandLineArguments(Config* config, int argc, char** argv);
bool configGetString(Config* config, const char* sectionKey, const char* key, char** valuePtr);
bool configSetString(Config* config, const char* sectionKey, const char* key, const char* value);
bool configGetInt(Config* config, const char* sectionKey, const char* key, int* valuePtr);
bool configGetInt(Config* config, const char* sectionKey, const char* key, int* valuePtr, unsigned char base = 0);
bool configGetIntList(Config* config, const char* section, const char* key, int* arr, int count);
bool configSetInt(Config* config, const char* sectionKey, const char* key, int value);
bool configRead(Config* config, const char* filePath, bool isDb);

View File

@ -15,7 +15,9 @@
#include <limits.h>
#include <string.h>
#include <SDL.h>
#if _WIN32
#include <SDL_syswm.h>
#endif
// NOT USED.
void (*_idle_func)() = NULL;
@ -4276,9 +4278,11 @@ void _kb_init_lock_status()
gModifierKeysState |= MODIFIER_KEY_STATE_NUM_LOCK;
}
#if SDL_VERSION_ATLEAST(2, 0, 18)
if ((SDL_GetModState() & KMOD_SCROLL) != 0) {
gModifierKeysState |= MODIFIER_KEY_STATE_SCROLL_LOCK;
}
#endif
}
// Get pointer to pending key event from the queue but do not consume it.

View File

@ -976,7 +976,7 @@ int gcdLoad(const char* path)
return -1;
}
if (fileReadInt32(stream, &characterEditorRemainingCharacterPoints) == -1) {
if (fileReadInt32(stream, &gCharacterEditorRemainingCharacterPoints) == -1) {
fileClose(stream);
return -1;
}
@ -1048,7 +1048,7 @@ int gcdSave(const char* path)
return -1;
}
if (fileWriteInt32(stream, characterEditorRemainingCharacterPoints) == -1) {
if (fileWriteInt32(stream, gCharacterEditorRemainingCharacterPoints) == -1) {
fileClose(stream);
return -1;
}

View File

@ -650,7 +650,12 @@ int fileNameListInit(const char* pattern, char*** fileNameListPtr, int a3, int a
}
if (!v2) {
sprintf(xlist->fileNames[index], "%s%s", fileName, extension);
// NOTE: Quick and dirty fix to buffer overflow. See RE to
// understand the problem.
char path[COMPAT_MAX_PATH];
sprintf(path, "%s%s", fileName, extension);
free(xlist->fileNames[length]);
xlist->fileNames[length] = strdup(path);
length++;
}
}

View File

@ -1,6 +1,7 @@
#include "dbox.h"
#include "art.h"
#include "character_editor.h"
#include "color.h"
#include "core.h"
#include "debug.h"
@ -18,6 +19,45 @@
#include <algorithm>
#define FILE_DIALOG_LINE_COUNT 12
#define FILE_DIALOG_DOUBLE_CLICK_DELAY 32
#define LOAD_FILE_DIALOG_DONE_BUTTON_X 58
#define LOAD_FILE_DIALOG_DONE_BUTTON_Y 187
#define LOAD_FILE_DIALOG_DONE_LABEL_X 79
#define LOAD_FILE_DIALOG_DONE_LABEL_Y 187
#define LOAD_FILE_DIALOG_CANCEL_BUTTON_X 163
#define LOAD_FILE_DIALOG_CANCEL_BUTTON_Y 187
#define LOAD_FILE_DIALOG_CANCEL_LABEL_X 182
#define LOAD_FILE_DIALOG_CANCEL_LABEL_Y 187
#define SAVE_FILE_DIALOG_DONE_BUTTON_X 58
#define SAVE_FILE_DIALOG_DONE_BUTTON_Y 214
#define SAVE_FILE_DIALOG_DONE_LABEL_X 79
#define SAVE_FILE_DIALOG_DONE_LABEL_Y 213
#define SAVE_FILE_DIALOG_CANCEL_BUTTON_X 163
#define SAVE_FILE_DIALOG_CANCEL_BUTTON_Y 214
#define SAVE_FILE_DIALOG_CANCEL_LABEL_X 182
#define SAVE_FILE_DIALOG_CANCEL_LABEL_Y 213
#define FILE_DIALOG_TITLE_X 49
#define FILE_DIALOG_TITLE_Y 16
#define FILE_DIALOG_SCROLL_BUTTON_X 36
#define FILE_DIALOG_SCROLL_BUTTON_Y 44
#define FILE_DIALOG_FILE_LIST_X 55
#define FILE_DIALOG_FILE_LIST_Y 49
#define FILE_DIALOG_FILE_LIST_WIDTH 190
#define FILE_DIALOG_FILE_LIST_HEIGHT 124
// 0x5108C8
const int gDialogBoxBackgroundFrmIds[DIALOG_TYPE_COUNT] = {
218, // MEDIALOG.FRM - Medium generic dialog box
@ -55,7 +95,7 @@ const int _dblines[DIALOG_TYPE_COUNT] = {
};
// 0x510900
int _flgids[7] = {
int gLoadFileDialogFrmIds[FILE_DIALOG_FRM_COUNT] = {
224, // loadbox.frm - character editor
8, // lilredup.frm - little red button up
9, // lilreddn.frm - little red button down
@ -66,7 +106,7 @@ int _flgids[7] = {
};
// 0x51091C
int _flgids2[7] = {
int gSaveFileDialogFrmIds[FILE_DIALOG_FRM_COUNT] = {
225, // savebox.frm - character editor
8, // lilredup.frm - little red button up
9, // lilreddn.frm - little red button down
@ -451,17 +491,32 @@ int showDialogBox(const char* title, const char** body, int bodyLength, int x, i
return rc;
}
// 0x41EA78
int _save_file_dialog(char* a1, char** fileList, char* fileName, int fileListLength, int x, int y, int flags)
// 0x41DE90
int showLoadFileDialog(char *title, char** fileList, char* dest, int fileListLength, int x, int y, int flags)
{
int oldFont = fontGetCurrent();
unsigned char* frmBuffers[7];
CacheEntry* frmHandles[7];
Size frmSizes[7];
bool isScrollable = false;
if (fileListLength > FILE_DIALOG_LINE_COUNT) {
isScrollable = true;
}
for (int index = 0; index < 7; index++) {
int fid = buildFid(6, _flgids2[index], 0, 0, 0);
int selectedFileIndex = 0;
int pageOffset = 0;
int maxPageOffset = fileListLength - (FILE_DIALOG_LINE_COUNT + 1);
if (maxPageOffset < 0) {
maxPageOffset = fileListLength - 1;
if (maxPageOffset < 0) {
maxPageOffset = 0;
}
}
unsigned char* frmBuffers[FILE_DIALOG_FRM_COUNT];
CacheEntry* frmHandles[FILE_DIALOG_FRM_COUNT];
Size frmSizes[FILE_DIALOG_FRM_COUNT];
for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) {
int fid = buildFid(6, gLoadFileDialogFrmIds[index], 0, 0, 0);
frmBuffers[index] = artLockFrameDataReturningSize(fid, &(frmHandles[index]), &(frmSizes[index].width), &(frmSizes[index].height));
if (frmBuffers[index] == NULL) {
while (--index >= 0) {
@ -471,16 +526,23 @@ int _save_file_dialog(char* a1, char** fileList, char* fileName, int fileListLen
}
}
int win = windowCreate(x, y, frmSizes[0].width, frmSizes[0].height, 256, WINDOW_FLAG_0x10 | WINDOW_FLAG_0x04);
int backgroundWidth = frmSizes[FILE_DIALOG_FRM_BACKGROUND].width;
int backgroundHeight = frmSizes[FILE_DIALOG_FRM_BACKGROUND].height;
// Maintain original position in original resolution, otherwise center it.
if (screenGetWidth() != 640) x = (screenGetWidth() - backgroundWidth) / 2;
if (screenGetHeight() != 480) y = (screenGetHeight() - backgroundHeight) / 2;
int win = windowCreate(x, y, backgroundWidth, backgroundHeight, 256, WINDOW_FLAG_0x10 | WINDOW_FLAG_0x04);
if (win == -1) {
for (int index = 0; index < 7; index++) {
for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) {
artUnlock(frmHandles[index]);
}
return -1;
}
unsigned char* windowBuffer = windowGetBuffer(win);
memcpy(windowBuffer, frmBuffers[0], frmSizes[0].width * frmSizes[0].height);
memcpy(windowBuffer, frmBuffers[FILE_DIALOG_FRM_BACKGROUND], backgroundWidth * backgroundHeight);
MessageList messageList;
MessageListItem messageListItem;
@ -488,7 +550,7 @@ int _save_file_dialog(char* a1, char** fileList, char* fileName, int fileListLen
if (!messageListInit(&messageList)) {
windowDestroy(win);
for (int index = 0; index < 7; index++) {
for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) {
artUnlock(frmHandles[index]);
}
@ -501,7 +563,7 @@ int _save_file_dialog(char* a1, char** fileList, char* fileName, int fileListLen
if (!messageListLoad(&messageList, path)) {
windowDestroy(win);
for (int index = 0; index < 7; index++) {
for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) {
artUnlock(frmHandles[index]);
}
@ -512,23 +574,23 @@ int _save_file_dialog(char* a1, char** fileList, char* fileName, int fileListLen
// DONE
const char* done = getmsg(&messageList, &messageListItem, 100);
fontDrawText(windowBuffer + frmSizes[0].width * 213 + 79, done, frmSizes[0].width, frmSizes[0].width, _colorTable[18979]);
fontDrawText(windowBuffer + LOAD_FILE_DIALOG_DONE_LABEL_Y * backgroundWidth + LOAD_FILE_DIALOG_DONE_LABEL_X, done, backgroundWidth, backgroundWidth, _colorTable[18979]);
// CANCEL
const char* cancel = getmsg(&messageList, &messageListItem, 103);
fontDrawText(windowBuffer + frmSizes[0].width * 213 + 182, cancel, frmSizes[0].width, frmSizes[0].width, _colorTable[18979]);
fontDrawText(windowBuffer + LOAD_FILE_DIALOG_CANCEL_LABEL_Y * backgroundWidth + LOAD_FILE_DIALOG_CANCEL_LABEL_X, cancel, backgroundWidth, backgroundWidth, _colorTable[18979]);
int doneBtn = buttonCreate(win,
58,
214,
frmSizes[2].width,
frmSizes[2].height,
LOAD_FILE_DIALOG_DONE_BUTTON_X,
LOAD_FILE_DIALOG_DONE_BUTTON_Y,
frmSizes[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].width,
frmSizes[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].height,
-1,
-1,
-1,
500,
frmBuffers[1],
frmBuffers[2],
frmBuffers[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_NORMAL],
frmBuffers[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED],
NULL,
BUTTON_FLAG_TRANSPARENT);
if (doneBtn != -1) {
@ -536,16 +598,16 @@ int _save_file_dialog(char* a1, char** fileList, char* fileName, int fileListLen
}
int cancelBtn = buttonCreate(win,
163,
214,
frmSizes[2].width,
frmSizes[2].height,
LOAD_FILE_DIALOG_CANCEL_BUTTON_X,
LOAD_FILE_DIALOG_CANCEL_BUTTON_Y,
frmSizes[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].width,
frmSizes[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].height,
-1,
-1,
-1,
501,
frmBuffers[1],
frmBuffers[2],
frmBuffers[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_NORMAL],
frmBuffers[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED],
NULL,
BUTTON_FLAG_TRANSPARENT);
if (cancelBtn != -1) {
@ -553,16 +615,16 @@ int _save_file_dialog(char* a1, char** fileList, char* fileName, int fileListLen
}
int scrollUpBtn = buttonCreate(win,
36,
44,
frmSizes[6].width,
frmSizes[6].height,
FILE_DIALOG_SCROLL_BUTTON_X,
FILE_DIALOG_SCROLL_BUTTON_Y,
frmSizes[FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED].width,
frmSizes[FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED].height,
-1,
505,
506,
505,
frmBuffers[5],
frmBuffers[6],
frmBuffers[FILE_DIALOG_FRM_SCROLL_UP_ARROW_NORMAL],
frmBuffers[FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED],
NULL,
BUTTON_FLAG_TRANSPARENT);
if (scrollUpBtn != -1) {
@ -570,16 +632,16 @@ int _save_file_dialog(char* a1, char** fileList, char* fileName, int fileListLen
}
int scrollDownButton = buttonCreate(win,
36,
44 + frmSizes[6].height,
frmSizes[4].width,
frmSizes[4].height,
FILE_DIALOG_SCROLL_BUTTON_X,
FILE_DIALOG_SCROLL_BUTTON_Y + frmSizes[FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED].height,
frmSizes[FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_PRESSED].width,
frmSizes[FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_PRESSED].height,
-1,
503,
504,
503,
frmBuffers[3],
frmBuffers[4],
frmBuffers[FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_NORMAL],
frmBuffers[FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_PRESSED],
NULL,
BUTTON_FLAG_TRANSPARENT);
if (scrollUpBtn != -1) {
@ -588,10 +650,10 @@ int _save_file_dialog(char* a1, char** fileList, char* fileName, int fileListLen
buttonCreate(
win,
55,
49,
190,
124,
FILE_DIALOG_FILE_LIST_X,
FILE_DIALOG_FILE_LIST_Y,
FILE_DIALOG_FILE_LIST_WIDTH,
FILE_DIALOG_FILE_LIST_HEIGHT,
-1,
-1,
-1,
@ -601,25 +663,714 @@ int _save_file_dialog(char* a1, char** fileList, char* fileName, int fileListLen
NULL,
0);
if (a1 != NULL) {
fontDrawText(windowBuffer + frmSizes[0].width * 16 + 49, a1, frmSizes[0].width, frmSizes[0].width, _colorTable[18979]);
if (title != NULL) {
fontDrawText(windowBuffer + backgroundWidth * FILE_DIALOG_TITLE_Y + FILE_DIALOG_TITLE_X, title, backgroundWidth, backgroundWidth, _colorTable[18979]);
}
fontSetCurrent(101);
fileDialogRenderFileList(windowBuffer, fileList, pageOffset, fileListLength, selectedFileIndex, backgroundWidth);
windowRefresh(win);
int doubleClickSelectedFileIndex = -2;
int doubleClickTimer = FILE_DIALOG_DOUBLE_CLICK_DELAY;
int rc = -1;
while (rc == -1) {
unsigned int tick = _get_time();
int keyCode = _get_input();
int scrollDirection = FILE_DIALOG_SCROLL_DIRECTION_NONE;
int scrollCounter = 0;
bool isScrolling = false;
if (keyCode == 500) {
if (fileListLength != 0) {
strncpy(dest, fileList[selectedFileIndex + pageOffset], 16);
rc = 0;
} else {
rc = 1;
}
} else if (keyCode == 501 || keyCode == KEY_ESCAPE) {
rc = 1;
} else if (keyCode == 502 && fileListLength != 0) {
int mouseX;
int mouseY;
mouseGetPosition(&mouseX, &mouseY);
int selectedLine = (mouseY - y - FILE_DIALOG_FILE_LIST_Y) / fontGetLineHeight();
if (selectedLine - 1 < 0) {
selectedLine = 0;
}
if (isScrollable || selectedLine < fileListLength) {
if (selectedLine >= FILE_DIALOG_LINE_COUNT) {
selectedLine = FILE_DIALOG_LINE_COUNT - 1;
}
} else {
selectedLine = fileListLength - 1;
}
selectedFileIndex = selectedLine;
if (selectedFileIndex == doubleClickSelectedFileIndex) {
soundPlayFile("ib1p1xx1");
strncpy(dest, fileList[selectedFileIndex + pageOffset], 16);
rc = 0;
}
doubleClickSelectedFileIndex = selectedFileIndex;
fileDialogRenderFileList(windowBuffer, fileList, pageOffset, fileListLength, selectedFileIndex, backgroundWidth);
} else if (keyCode == 506) {
scrollDirection = FILE_DIALOG_SCROLL_DIRECTION_UP;
} else if (keyCode == 504) {
scrollDirection = FILE_DIALOG_SCROLL_DIRECTION_DOWN;
} else {
switch (keyCode) {
case KEY_ARROW_UP:
pageOffset--;
if (pageOffset < 0) {
selectedFileIndex--;
if (selectedFileIndex < 0) {
selectedFileIndex = 0;
}
pageOffset = 0;
}
fileDialogRenderFileList(windowBuffer, fileList, pageOffset, fileListLength, selectedFileIndex, backgroundWidth);
doubleClickSelectedFileIndex = -2;
break;
case KEY_ARROW_DOWN:
if (isScrollable) {
pageOffset++;
// FIXME: Should be >= maxPageOffset (as in save dialog).
// Otherwise out of bounds index is considered selected.
if (pageOffset > maxPageOffset) {
selectedFileIndex++;
// FIXME: Should be >= FILE_DIALOG_LINE_COUNT (as in
// save dialog). Otherwise out of bounds index is
// considered selected.
if (selectedFileIndex > FILE_DIALOG_LINE_COUNT) {
selectedFileIndex = FILE_DIALOG_LINE_COUNT - 1;
}
pageOffset = maxPageOffset;
}
} else {
selectedFileIndex++;
if (selectedFileIndex > maxPageOffset) {
selectedFileIndex = maxPageOffset;
}
}
fileDialogRenderFileList(windowBuffer, fileList, pageOffset, fileListLength, selectedFileIndex, backgroundWidth);
doubleClickSelectedFileIndex = -2;
break;
case KEY_HOME:
selectedFileIndex = 0;
pageOffset = 0;
fileDialogRenderFileList(windowBuffer, fileList, pageOffset, fileListLength, selectedFileIndex, backgroundWidth);
doubleClickSelectedFileIndex = -2;
break;
case KEY_END:
if (isScrollable) {
selectedFileIndex = FILE_DIALOG_LINE_COUNT - 1;
pageOffset = maxPageOffset;
} else {
selectedFileIndex = maxPageOffset;
pageOffset = 0;
}
fileDialogRenderFileList(windowBuffer, fileList, pageOffset, fileListLength, selectedFileIndex, backgroundWidth);
doubleClickSelectedFileIndex = -2;
break;
}
}
if (scrollDirection != FILE_DIALOG_SCROLL_DIRECTION_NONE) {
unsigned int scrollDelay = 4;
doubleClickSelectedFileIndex = -2;
while (1) {
unsigned int scrollTick = _get_time();
scrollCounter += 1;
if ((!isScrolling && scrollCounter == 1) || (isScrolling && scrollCounter > 14.4)) {
isScrolling = true;
if (scrollCounter > 14.4) {
scrollDelay += 1;
if (scrollDelay > 24) {
scrollDelay = 24;
}
}
if (scrollDirection == FILE_DIALOG_SCROLL_DIRECTION_UP) {
pageOffset--;
if (pageOffset < 0) {
selectedFileIndex--;
if (selectedFileIndex < 0) {
selectedFileIndex = 0;
}
pageOffset = 0;
}
} else {
if (isScrollable) {
pageOffset++;
if (pageOffset > maxPageOffset) {
selectedFileIndex++;
if (selectedFileIndex >= FILE_DIALOG_LINE_COUNT) {
selectedFileIndex = FILE_DIALOG_LINE_COUNT - 1;
}
pageOffset = maxPageOffset;
}
} else {
selectedFileIndex++;
if (selectedFileIndex > maxPageOffset) {
selectedFileIndex = maxPageOffset;
}
}
}
fileDialogRenderFileList(windowBuffer, fileList, pageOffset, fileListLength, selectedFileIndex, backgroundWidth);
windowRefresh(win);
}
unsigned int delay = (scrollCounter > 14.4) ? 1000 / scrollDelay : 1000 / 24;
while (getTicksSince(scrollTick) < delay) {
}
if (_game_user_wants_to_quit != 0) {
rc = 1;
break;
}
int keyCode = _get_input();
if (keyCode == 505 || keyCode == 503) {
break;
}
}
} else {
windowRefresh(win);
doubleClickTimer--;
if (doubleClickTimer == 0) {
doubleClickTimer = FILE_DIALOG_DOUBLE_CLICK_DELAY;
doubleClickSelectedFileIndex = -2;
}
while (getTicksSince(tick) < (1000 / 24)) {
}
}
if (_game_user_wants_to_quit) {
rc = 1;
}
}
windowDestroy(win);
for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) {
artUnlock(frmHandles[index]);
}
messageListFree(&messageList);
fontSetCurrent(oldFont);
return rc;
}
// 0x41EA78
int showSaveFileDialog(char* title, char** fileList, char* dest, int fileListLength, int x, int y, int flags)
{
int oldFont = fontGetCurrent();
bool isScrollable = false;
if (fileListLength > FILE_DIALOG_LINE_COUNT) {
isScrollable = true;
}
int selectedFileIndex = 0;
int pageOffset = 0;
int maxPageOffset = fileListLength - (FILE_DIALOG_LINE_COUNT + 1);
if (maxPageOffset < 0) {
maxPageOffset = fileListLength - 1;
if (maxPageOffset < 0) {
maxPageOffset = 0;
}
}
unsigned char* frmBuffers[FILE_DIALOG_FRM_COUNT];
CacheEntry* frmHandles[FILE_DIALOG_FRM_COUNT];
Size frmSizes[FILE_DIALOG_FRM_COUNT];
for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) {
int fid = buildFid(6, gSaveFileDialogFrmIds[index], 0, 0, 0);
frmBuffers[index] = artLockFrameDataReturningSize(fid, &(frmHandles[index]), &(frmSizes[index].width), &(frmSizes[index].height));
if (frmBuffers[index] == NULL) {
while (--index >= 0) {
artUnlock(frmHandles[index]);
}
return -1;
}
}
int backgroundWidth = frmSizes[FILE_DIALOG_FRM_BACKGROUND].width;
int backgroundHeight = frmSizes[FILE_DIALOG_FRM_BACKGROUND].height;
// Maintain original position in original resolution, otherwise center it.
if (screenGetWidth() != 640) x = (screenGetWidth() - backgroundWidth) / 2;
if (screenGetHeight() != 480) y = (screenGetHeight() - backgroundHeight) / 2;
int win = windowCreate(x, y, backgroundWidth, backgroundHeight, 256, WINDOW_FLAG_0x10 | WINDOW_FLAG_0x04);
if (win == -1) {
for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) {
artUnlock(frmHandles[index]);
}
return -1;
}
unsigned char* windowBuffer = windowGetBuffer(win);
memcpy(windowBuffer, frmBuffers[FILE_DIALOG_FRM_BACKGROUND], backgroundWidth * backgroundHeight);
MessageList messageList;
MessageListItem messageListItem;
if (!messageListInit(&messageList)) {
windowDestroy(win);
for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) {
artUnlock(frmHandles[index]);
}
return -1;
}
char path[COMPAT_MAX_PATH];
sprintf(path, "%s%s", asc_5186C8, "DBOX.MSG");
if (!messageListLoad(&messageList, path)) {
windowDestroy(win);
for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) {
artUnlock(frmHandles[index]);
}
return -1;
}
fontSetCurrent(103);
// DONE
const char* done = getmsg(&messageList, &messageListItem, 100);
fontDrawText(windowBuffer + backgroundWidth * SAVE_FILE_DIALOG_DONE_LABEL_Y + SAVE_FILE_DIALOG_DONE_LABEL_X, done, backgroundWidth, backgroundWidth, _colorTable[18979]);
// CANCEL
const char* cancel = getmsg(&messageList, &messageListItem, 103);
fontDrawText(windowBuffer + backgroundWidth * SAVE_FILE_DIALOG_CANCEL_LABEL_Y + SAVE_FILE_DIALOG_CANCEL_LABEL_X, cancel, backgroundWidth, backgroundWidth, _colorTable[18979]);
int doneBtn = buttonCreate(win,
SAVE_FILE_DIALOG_DONE_BUTTON_X,
SAVE_FILE_DIALOG_DONE_BUTTON_Y,
frmSizes[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].width,
frmSizes[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].height,
-1,
-1,
-1,
500,
frmBuffers[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_NORMAL],
frmBuffers[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED],
NULL,
BUTTON_FLAG_TRANSPARENT);
if (doneBtn != -1) {
buttonSetCallbacks(doneBtn, _gsound_red_butt_press, _gsound_red_butt_release);
}
int cancelBtn = buttonCreate(win,
SAVE_FILE_DIALOG_CANCEL_BUTTON_X,
SAVE_FILE_DIALOG_CANCEL_BUTTON_Y,
frmSizes[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].width,
frmSizes[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED].height,
-1,
-1,
-1,
501,
frmBuffers[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_NORMAL],
frmBuffers[FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED],
NULL,
BUTTON_FLAG_TRANSPARENT);
if (cancelBtn != -1) {
buttonSetCallbacks(cancelBtn, _gsound_red_butt_press, _gsound_red_butt_release);
}
int scrollUpBtn = buttonCreate(win,
FILE_DIALOG_SCROLL_BUTTON_X,
FILE_DIALOG_SCROLL_BUTTON_Y,
frmSizes[FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED].width,
frmSizes[FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED].height,
-1,
505,
506,
505,
frmBuffers[FILE_DIALOG_FRM_SCROLL_UP_ARROW_NORMAL],
frmBuffers[FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED],
NULL,
BUTTON_FLAG_TRANSPARENT);
if (scrollUpBtn != -1) {
buttonSetCallbacks(cancelBtn, _gsound_red_butt_press, _gsound_red_butt_release);
}
int scrollDownButton = buttonCreate(win,
FILE_DIALOG_SCROLL_BUTTON_X,
FILE_DIALOG_SCROLL_BUTTON_Y + frmSizes[FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED].height,
frmSizes[FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_PRESSED].width,
frmSizes[FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_PRESSED].height,
-1,
503,
504,
503,
frmBuffers[FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_NORMAL],
frmBuffers[FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_PRESSED],
NULL,
BUTTON_FLAG_TRANSPARENT);
if (scrollUpBtn != -1) {
buttonSetCallbacks(cancelBtn, _gsound_red_butt_press, _gsound_red_butt_release);
}
buttonCreate(
win,
FILE_DIALOG_FILE_LIST_X,
FILE_DIALOG_FILE_LIST_Y,
FILE_DIALOG_FILE_LIST_WIDTH,
FILE_DIALOG_FILE_LIST_HEIGHT,
-1,
-1,
-1,
502,
NULL,
NULL,
NULL,
0);
if (title != NULL) {
fontDrawText(windowBuffer + backgroundWidth * FILE_DIALOG_TITLE_Y + FILE_DIALOG_TITLE_X, title, backgroundWidth, backgroundWidth, _colorTable[18979]);
}
fontSetCurrent(101);
int cursorHeight = fontGetLineHeight();
int cursorWidth = fontGetStringWidth("_") - 4;
fileDialogRenderFileList(windowBuffer, fileList, pageOffset, fileListLength, selectedFileIndex, backgroundWidth);
int fileNameLength = 0;
char* pch = dest;
while (*pch != '\0' && *pch != '.') {
fileNameLength++;
if (fileNameLength >= 12) {
break;
}
}
dest[fileNameLength] = '\0';
char fileNameCopy[32];
strncpy(fileNameCopy, dest, 32);
int fileNameCopyLength = strlen(fileNameCopy);
fileNameCopy[fileNameCopyLength + 1] = '\0';
fileNameCopy[fileNameCopyLength] = ' ';
unsigned char* fileNameBufferPtr = windowBuffer + backgroundWidth * 190 + 57;
bufferFill(fileNameBufferPtr, fontGetStringWidth(fileNameCopy), cursorHeight, backgroundWidth, 100);
fontDrawText(fileNameBufferPtr, fileNameCopy, backgroundWidth, backgroundWidth, _colorTable[992]);
windowRefresh(win);
int blinkingCounter = 3;
bool blink = false;
int doubleClickSelectedFileIndex = -2;
int doubleClickTimer = FILE_DIALOG_DOUBLE_CLICK_DELAY;
int rc = -1;
while (rc == -1) {
unsigned int tick = _get_time();
int keyCode = _get_input();
int scrollDirection = FILE_DIALOG_SCROLL_DIRECTION_NONE;
int scrollCounter = 0;
bool isScrolling = false;
if (keyCode == 500) {
rc = 0;
} else if (keyCode == KEY_RETURN) {
soundPlayFile("ib1p1xx1");
rc = 0;
} else if (keyCode == 501 || keyCode == KEY_ESCAPE) {
rc = 1;
} else if ((keyCode == KEY_DELETE || keyCode == KEY_BACKSPACE) && fileNameCopyLength > 0) {
bufferFill(fileNameBufferPtr, fontGetStringWidth(fileNameCopy), cursorHeight, backgroundWidth, 100);
fileNameCopy[fileNameCopyLength - 1] = ' ';
fileNameCopy[fileNameCopyLength] = '\0';
fontDrawText(fileNameBufferPtr, fileNameCopy, backgroundWidth, backgroundWidth, _colorTable[992]);
fileNameCopyLength--;
windowRefresh(win);
} else if (keyCode < KEY_FIRST_INPUT_CHARACTER || keyCode > KEY_LAST_INPUT_CHARACTER || fileNameCopyLength >= 8) {
if (keyCode == 502 && fileListLength != 0) {
int mouseX;
int mouseY;
mouseGetPosition(&mouseX, &mouseY);
int selectedLine = (mouseY - y - FILE_DIALOG_FILE_LIST_Y) / fontGetLineHeight();
if (selectedLine - 1 < 0) {
selectedLine = 0;
}
if (isScrollable || selectedLine < fileListLength) {
if (selectedLine >= FILE_DIALOG_LINE_COUNT) {
selectedLine = FILE_DIALOG_LINE_COUNT - 1;
}
} else {
selectedLine = fileListLength - 1;
}
selectedFileIndex = selectedLine;
if (selectedFileIndex == doubleClickSelectedFileIndex) {
soundPlayFile("ib1p1xx1");
strncpy(dest, fileList[selectedFileIndex + pageOffset], 16);
int index;
for (index = 0; index < 12; index++) {
if (dest[index] == '.' || dest[index] == '\0') {
break;
}
}
dest[index] = '\0';
rc = 2;
} else {
doubleClickSelectedFileIndex = selectedFileIndex;
bufferFill(fileNameBufferPtr, fontGetStringWidth(fileNameCopy), cursorHeight, backgroundWidth, 100);
strncpy(fileNameCopy, fileList[selectedFileIndex + pageOffset], 16);
int index;
for (index = 0; index < 12; index++) {
if (fileNameCopy[index] == '.' || fileNameCopy[index] == '\0') {
break;
}
}
fileNameCopy[index] = '\0';
fileNameCopyLength = strlen(fileNameCopy);
fileNameCopy[fileNameCopyLength] = ' ';
fileNameCopy[fileNameCopyLength + 1] = '\0';
fontDrawText(fileNameBufferPtr, fileNameCopy, backgroundWidth, backgroundWidth, _colorTable[992]);
fileDialogRenderFileList(windowBuffer, fileList, pageOffset, fileListLength, selectedFileIndex, backgroundWidth);
}
} else if (keyCode == 506) {
scrollDirection = FILE_DIALOG_SCROLL_DIRECTION_UP;
} else if (keyCode == 504) {
scrollDirection = FILE_DIALOG_SCROLL_DIRECTION_DOWN;
} else {
switch (keyCode) {
case KEY_ARROW_UP:
pageOffset--;
if (pageOffset < 0) {
selectedFileIndex--;
if (selectedFileIndex < 0) {
selectedFileIndex = 0;
}
pageOffset = 0;
}
fileDialogRenderFileList(windowBuffer, fileList, pageOffset, fileListLength, selectedFileIndex, backgroundWidth);
doubleClickSelectedFileIndex = -2;
break;
case KEY_ARROW_DOWN:
if (isScrollable) {
pageOffset++;
if (pageOffset >= maxPageOffset) {
selectedFileIndex++;
if (selectedFileIndex >= FILE_DIALOG_LINE_COUNT) {
selectedFileIndex = FILE_DIALOG_LINE_COUNT - 1;
}
pageOffset = maxPageOffset;
}
} else {
selectedFileIndex++;
if (selectedFileIndex > maxPageOffset) {
selectedFileIndex = maxPageOffset;
}
}
fileDialogRenderFileList(windowBuffer, fileList, pageOffset, fileListLength, selectedFileIndex, backgroundWidth);
doubleClickSelectedFileIndex = -2;
break;
case KEY_HOME:
selectedFileIndex = 0;
pageOffset = 0;
fileDialogRenderFileList(windowBuffer, fileList, pageOffset, fileListLength, selectedFileIndex, backgroundWidth);
doubleClickSelectedFileIndex = -2;
break;
case KEY_END:
if (isScrollable) {
selectedFileIndex = 11;
pageOffset = maxPageOffset;
} else {
selectedFileIndex = maxPageOffset;
pageOffset = 0;
}
fileDialogRenderFileList(windowBuffer, fileList, pageOffset, fileListLength, selectedFileIndex, backgroundWidth);
doubleClickSelectedFileIndex = -2;
break;
}
}
} else if (_isdoschar(keyCode)) {
bufferFill(fileNameBufferPtr, fontGetStringWidth(fileNameCopy), cursorHeight, backgroundWidth, 100);
fileNameCopy[fileNameCopyLength] = keyCode & 0xFF;
fileNameCopy[fileNameCopyLength + 1] = ' ';
fileNameCopy[fileNameCopyLength + 2] = '\0';
fontDrawText(fileNameBufferPtr, fileNameCopy, backgroundWidth, backgroundWidth, _colorTable[992]);
fileNameCopyLength++;
windowRefresh(win);
}
if (scrollDirection != FILE_DIALOG_SCROLL_DIRECTION_NONE) {
unsigned int scrollDelay = 4;
doubleClickSelectedFileIndex = -2;
while (1) {
unsigned int scrollTick = _get_time();
scrollCounter += 1;
if ((!isScrolling && scrollCounter == 1) || (isScrolling && scrollCounter > 14.4)) {
isScrolling = true;
if (scrollCounter > 14.4) {
scrollDelay += 1;
if (scrollDelay > 24) {
scrollDelay = 24;
}
}
if (scrollDirection == FILE_DIALOG_SCROLL_DIRECTION_UP) {
pageOffset--;
if (pageOffset < 0) {
selectedFileIndex--;
if (selectedFileIndex < 0) {
selectedFileIndex = 0;
}
pageOffset = 0;
}
} else {
if (isScrollable) {
pageOffset++;
if (pageOffset > maxPageOffset) {
selectedFileIndex++;
if (selectedFileIndex >= FILE_DIALOG_LINE_COUNT) {
selectedFileIndex = FILE_DIALOG_LINE_COUNT - 1;
}
pageOffset = maxPageOffset;
}
} else {
selectedFileIndex++;
if (selectedFileIndex > maxPageOffset) {
selectedFileIndex = maxPageOffset;
}
}
}
fileDialogRenderFileList(windowBuffer, fileList, pageOffset, fileListLength, selectedFileIndex, backgroundWidth);
windowRefresh(win);
}
// NOTE: Original code is slightly different. For unknown reason
// entire blinking stuff is placed into two different branches,
// which only differs by amount of delay. Probably result of
// using large blinking macro as there are no traces of inlined
// function.
blinkingCounter -= 1;
if (blinkingCounter == 0) {
blinkingCounter = 3;
int color = blink ? 100 : _colorTable[992];
blink = !blink;
bufferFill(fileNameBufferPtr + fontGetStringWidth(fileNameCopy) - cursorWidth, cursorWidth, cursorHeight - 2, backgroundWidth, color);
}
// FIXME: Missing windowRefresh makes blinking useless.
unsigned int delay = (scrollCounter > 14.4) ? 1000 / scrollDelay : 1000 / 24;
while (getTicksSince(scrollTick) < delay) {
}
if (_game_user_wants_to_quit != 0) {
rc = 1;
break;
}
int key = _get_input();
if (key == 505 || key == 503) {
break;
}
}
} else {
blinkingCounter -= 1;
if (blinkingCounter == 0) {
blinkingCounter = 3;
int color = blink ? 100 : _colorTable[992];
blink = !blink;
bufferFill(fileNameBufferPtr + fontGetStringWidth(fileNameCopy) - cursorWidth, cursorWidth, cursorHeight - 2, backgroundWidth, color);
}
windowRefresh(win);
doubleClickTimer--;
if (doubleClickTimer == 0) {
doubleClickTimer = FILE_DIALOG_DOUBLE_CLICK_DELAY;
doubleClickSelectedFileIndex = -2;
}
while (getTicksSince(tick) < (1000 / 24)) {
}
}
if (_game_user_wants_to_quit != 0) {
rc = 1;
}
}
if (rc == 0) {
if (fileNameCopyLength != 0) {
fileNameCopy[fileNameCopyLength] = '\0';
strcpy(dest, fileNameCopy);
} else {
rc = 1;
}
} else {
if (rc == 2) {
rc = 0;
}
}
windowDestroy(win);
for (int index = 0; index < FILE_DIALOG_FRM_COUNT; index++) {
artUnlock(frmHandles[index]);
}
messageListFree(&messageList);
fontSetCurrent(oldFont);
return rc;
}
// 0x41FBDC
void _PrntFlist(unsigned char* buffer, char** fileList, int pageOffset, int fileListLength, int selectedIndex, int pitch)
void fileDialogRenderFileList(unsigned char* buffer, char** fileList, int pageOffset, int fileListLength, int selectedIndex, int pitch)
{
int lineHeight = fontGetLineHeight();
int y = 49;
bufferFill(buffer + y * pitch + 55, 190, 124, pitch, 100);
int y = FILE_DIALOG_FILE_LIST_Y;
bufferFill(buffer + y * pitch + FILE_DIALOG_FILE_LIST_X, FILE_DIALOG_FILE_LIST_WIDTH, FILE_DIALOG_FILE_LIST_HEIGHT, pitch, 100);
if (fileListLength != 0) {
if (fileListLength - pageOffset > 12) {
fileListLength = 12;
if (fileListLength - pageOffset > FILE_DIALOG_LINE_COUNT) {
fileListLength = FILE_DIALOG_LINE_COUNT;
}
for (int index = 0; index < fileListLength; index++) {
int color = index == selectedIndex ? _colorTable[32747] : _colorTable[992];
fontDrawText(buffer + y * index + 55, fileList[index], pitch, pitch, color);
fontDrawText(buffer + pitch * y + FILE_DIALOG_FILE_LIST_X, fileList[pageOffset + index], pitch, pitch, color);
y += lineHeight;
}
}

View File

@ -16,17 +16,35 @@ typedef enum DialogType {
DIALOG_TYPE_COUNT,
} DialogType;
typedef enum FileDialogFrm {
FILE_DIALOG_FRM_BACKGROUND,
FILE_DIALOG_FRM_LITTLE_RED_BUTTON_NORMAL,
FILE_DIALOG_FRM_LITTLE_RED_BUTTON_PRESSED,
FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_NORMAL,
FILE_DIALOG_FRM_SCROLL_DOWN_ARROW_PRESSED,
FILE_DIALOG_FRM_SCROLL_UP_ARROW_NORMAL,
FILE_DIALOG_FRM_SCROLL_UP_ARROW_PRESSED,
FILE_DIALOG_FRM_COUNT,
} FileDialogFrm;
typedef enum FileDialogScrollDirection {
FILE_DIALOG_SCROLL_DIRECTION_NONE,
FILE_DIALOG_SCROLL_DIRECTION_UP,
FILE_DIALOG_SCROLL_DIRECTION_DOWN,
} FileDialogScrollDirection;
extern const int gDialogBoxBackgroundFrmIds[DIALOG_TYPE_COUNT];
extern const int _ytable[DIALOG_TYPE_COUNT];
extern const int _xtable[DIALOG_TYPE_COUNT];
extern const int _doneY[DIALOG_TYPE_COUNT];
extern const int _doneX[DIALOG_TYPE_COUNT];
extern const int _dblines[DIALOG_TYPE_COUNT];
extern int _flgids[7];
extern int _flgids2[7];
extern int gLoadFileDialogFrmIds[FILE_DIALOG_FRM_COUNT];
extern int gSaveFileDialogFrmIds[FILE_DIALOG_FRM_COUNT];
int showDialogBox(const char* title, const char** body, int bodyLength, int x, int y, int titleColor, const char* a8, int bodyColor, int flags);
int _save_file_dialog(char* a1, char** fileList, char* fileName, int fileListLength, int x, int y, int flags);
void _PrntFlist(unsigned char* buffer, char** fileList, int pageOffset, int fileListLength, int selectedIndex, int pitch);
int showLoadFileDialog(char* title, char** fileList, char* dest, int fileListLength, int x, int y, int flags);
int showSaveFileDialog(char* title, char** fileList, char* dest, int fileListLength, int x, int y, int flags);
void fileDialogRenderFileList(unsigned char* buffer, char** fileList, int pageOffset, int fileListLength, int selectedIndex, int pitch);
#endif /* DBOX_H */

View File

@ -142,7 +142,7 @@ int debugPrint(const char* format, ...)
#ifdef _WIN32
OutputDebugStringA(string);
#else
printf(string);
printf("%s", string);
#endif
#endif
rc = -1;

View File

@ -493,7 +493,12 @@ int endgameEndingSlideshowWindowInit()
int windowEndgameEndingX = (screenGetWidth() - ENDGAME_ENDING_WINDOW_WIDTH) / 2;
int windowEndgameEndingY = (screenGetHeight() - ENDGAME_ENDING_WINDOW_HEIGHT) / 2;
gEndgameEndingSlideshowWindow = windowCreate(windowEndgameEndingX, windowEndgameEndingY, ENDGAME_ENDING_WINDOW_WIDTH, ENDGAME_ENDING_WINDOW_HEIGHT, _colorTable[0], 4);
gEndgameEndingSlideshowWindow = windowCreate(windowEndgameEndingX,
windowEndgameEndingY,
ENDGAME_ENDING_WINDOW_WIDTH,
ENDGAME_ENDING_WINDOW_HEIGHT,
_colorTable[0],
WINDOW_FLAG_0x04);
if (gEndgameEndingSlideshowWindow == -1) {
return -1;
}

View File

@ -155,7 +155,11 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int a4
}
}
if (!gIsMapper) {
// SFALL: Allow to skip splash screen
int skipOpeningMovies = 0;
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_SKIP_OPENING_MOVIES_KEY, &skipOpeningMovies);
if (!gIsMapper && skipOpeningMovies < 2) {
showSplash();
}
@ -263,7 +267,7 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int a4
debugPrint(">wmWorldMap_init\t");
_CharEditInit();
characterEditorInit();
debugPrint(">CharEditInit\t");
pipboyInit();
@ -363,7 +367,7 @@ void gameReset()
scriptsReset();
worldmapReset();
partyMembersReset();
_CharEditInit();
characterEditorInit();
pipboyReset();
_ResetLoadSave();
gameDialogReset();
@ -512,7 +516,7 @@ int gameHandleKey(int eventCode, bool isInCombatMode)
if (interfaceBarEnabled()) {
soundPlayFile("ib1p1xx1");
bool isoWasEnabled = isoDisable();
_editor_design(false);
characterEditorShow(false);
if (isoWasEnabled) {
isoEnable();
}
@ -887,6 +891,24 @@ int gameSetGlobalVar(int var, int value)
return -1;
}
// SFALL: Display karma changes.
if (var == GVAR_PLAYER_REPUTATION) {
bool shouldDisplayKarmaChanges = false;
configGetBool(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_DISPLAY_KARMA_CHANGES_KEY, &shouldDisplayKarmaChanges);
if (shouldDisplayKarmaChanges) {
int diff = value - gGameGlobalVars[var];
if (diff != 0) {
char formattedMessage[80];
if (diff > 0) {
sprintf(formattedMessage, "You gained %d karma.", diff);
} else {
sprintf(formattedMessage, "You lost %d karma.", -diff);
}
displayMonitorAddMessage(formattedMessage);
}
}
}
gGameGlobalVars[var] = value;
return 0;

View File

@ -571,7 +571,7 @@ void gameDialogEnter(Object* a1, int a2)
return;
}
if ((a1->pid >> 24) != OBJ_TYPE_ITEM && (a1->pid >> 24) != OBJ_TYPE_CRITTER) {
if ((a1->pid >> 24) != OBJ_TYPE_ITEM && (a1->sid >> 24) != SCRIPT_TYPE_SPATIAL) {
MessageListItem messageListItem;
int rc = _action_can_talk_to(gDude, a1);
@ -1142,7 +1142,12 @@ int gameDialogReviewWindowInit(int* win)
int reviewWindowX = (screenGetWidth() - GAME_DIALOG_REVIEW_WINDOW_WIDTH) / 2;
int reviewWindowY = (screenGetHeight() - GAME_DIALOG_REVIEW_WINDOW_HEIGHT) / 2;
*win = windowCreate(reviewWindowX, reviewWindowY, GAME_DIALOG_REVIEW_WINDOW_WIDTH, GAME_DIALOG_REVIEW_WINDOW_HEIGHT, 256, WINDOW_FLAG_0x10 | WINDOW_FLAG_0x04);
*win = windowCreate(reviewWindowX,
reviewWindowY,
GAME_DIALOG_REVIEW_WINDOW_WIDTH,
GAME_DIALOG_REVIEW_WINDOW_HEIGHT,
256,
WINDOW_FLAG_0x10 | WINDOW_FLAG_0x04);
if (*win == -1) {
return -1;
}
@ -1548,7 +1553,12 @@ int _gdProcessInit()
int replyWindowX = (screenGetWidth() - GAME_DIALOG_WINDOW_WIDTH) / 2 + GAME_DIALOG_REPLY_WINDOW_X;
int replyWindowY = (screenGetHeight() - GAME_DIALOG_WINDOW_HEIGHT) / 2 + GAME_DIALOG_REPLY_WINDOW_Y;
gGameDialogReplyWindow = windowCreate(replyWindowX, replyWindowY, GAME_DIALOG_REPLY_WINDOW_WIDTH, GAME_DIALOG_REPLY_WINDOW_HEIGHT, 256, WINDOW_FLAG_0x04);
gGameDialogReplyWindow = windowCreate(replyWindowX,
replyWindowY,
GAME_DIALOG_REPLY_WINDOW_WIDTH,
GAME_DIALOG_REPLY_WINDOW_HEIGHT,
256,
WINDOW_FLAG_0x04);
if (gGameDialogReplyWindow == -1) {
goto err;
}
@ -2174,7 +2184,12 @@ int _gdCreateHeadWindow()
int backgroundWindowX = (screenGetWidth() - GAME_DIALOG_WINDOW_WIDTH) / 2;
int backgroundWindowY = (screenGetHeight() - GAME_DIALOG_WINDOW_HEIGHT) / 2;
gGameDialogBackgroundWindow = windowCreate(backgroundWindowX, backgroundWindowY, windowWidth, GAME_DIALOG_WINDOW_HEIGHT, 256, WINDOW_FLAG_0x02);
gGameDialogBackgroundWindow = windowCreate(backgroundWindowX,
backgroundWindowY,
windowWidth,
GAME_DIALOG_WINDOW_HEIGHT,
256,
WINDOW_FLAG_0x02);
gameDialogWindowRenderBackground();
unsigned char* buf = windowGetBuffer(gGameDialogBackgroundWindow);
@ -2594,6 +2609,9 @@ void gameDialogTicker()
if (_gd_optionsWin != -1) {
windowUnhide(_gd_optionsWin);
// SFALL: Fix for the player's money not being displayed in the
// dialog window after leaving the barter/combat control interface.
gameDialogRenderCaps();
}
break;
@ -2980,7 +2998,12 @@ int _gdialog_barter_create_win()
int barterWindowX = (screenGetWidth() - GAME_DIALOG_WINDOW_WIDTH) / 2;
int barterWindowY = (screenGetHeight() - GAME_DIALOG_WINDOW_HEIGHT) / 2 + GAME_DIALOG_WINDOW_HEIGHT - _dialogue_subwin_len;
gGameDialogWindow = windowCreate(barterWindowX, barterWindowY, GAME_DIALOG_WINDOW_WIDTH, _dialogue_subwin_len, 256, WINDOW_FLAG_0x02);
gGameDialogWindow = windowCreate(barterWindowX,
barterWindowY,
GAME_DIALOG_WINDOW_WIDTH,
_dialogue_subwin_len,
256,
WINDOW_FLAG_0x02);
if (gGameDialogWindow == -1) {
artUnlock(backgroundHandle);
return -1;
@ -3133,7 +3156,12 @@ int partyMemberControlWindowInit()
_dialogue_subwin_len = artGetHeight(backgroundFrm, 0, 0);
int controlWindowX = (screenGetWidth() - GAME_DIALOG_WINDOW_WIDTH) / 2;
int controlWindowY = (screenGetHeight() - GAME_DIALOG_WINDOW_HEIGHT) / 2 + GAME_DIALOG_WINDOW_HEIGHT - _dialogue_subwin_len;
gGameDialogWindow = windowCreate(controlWindowX, controlWindowY, GAME_DIALOG_WINDOW_WIDTH, _dialogue_subwin_len, 256, WINDOW_FLAG_0x02);
gGameDialogWindow = windowCreate(controlWindowX,
controlWindowY,
GAME_DIALOG_WINDOW_WIDTH,
_dialogue_subwin_len,
256,
WINDOW_FLAG_0x02);
if (gGameDialogWindow == -1) {
partyMemberControlWindowFree();
return -1;
@ -3567,7 +3595,12 @@ int partyMemberCustomizationWindowInit()
int customizationWindowX = (screenGetWidth() - GAME_DIALOG_WINDOW_WIDTH) / 2;
int customizationWindowY = (screenGetHeight() - GAME_DIALOG_WINDOW_HEIGHT) / 2 + GAME_DIALOG_WINDOW_HEIGHT - _dialogue_subwin_len;
gGameDialogWindow = windowCreate(customizationWindowX, customizationWindowY, GAME_DIALOG_WINDOW_WIDTH, _dialogue_subwin_len, 256, WINDOW_FLAG_0x02);
gGameDialogWindow = windowCreate(customizationWindowX,
customizationWindowY,
GAME_DIALOG_WINDOW_WIDTH,
_dialogue_subwin_len,
256,
WINDOW_FLAG_0x02);
if (gGameDialogWindow == -1) {
partyMemberCustomizationWindowFree();
return -1;
@ -4102,7 +4135,7 @@ int _gdialog_window_create()
int dialogSubwindowX = (screenGetWidth() - GAME_DIALOG_WINDOW_WIDTH) / 2;
int dialogSubwindowY = (screenGetHeight() - GAME_DIALOG_WINDOW_HEIGHT) / 2 + GAME_DIALOG_WINDOW_HEIGHT - _dialogue_subwin_len;
gGameDialogWindow = windowCreate(dialogSubwindowX, dialogSubwindowY, screenWidth, _dialogue_subwin_len, 256, 2);
gGameDialogWindow = windowCreate(dialogSubwindowX, dialogSubwindowY, screenWidth, _dialogue_subwin_len, 256, WINDOW_FLAG_0x02);
if (gGameDialogWindow != -1) {
unsigned char* v10 = windowGetBuffer(gGameDialogWindow);
@ -4369,11 +4402,19 @@ void gameDialogRenderTalkingHead(Art* headFrm, int frame)
}
unsigned char* src = windowGetBuffer(gIsoWindow);
// Usually rendering functions use `screenGetWidth`/`screenGetHeight` to
// determine rendering position. However in this case `windowGetHeight`
// is a must because isometric window's height can either include
// interface bar or not. Offset is updated accordingly (332 -> 232, the
// missing 100 is interface bar height, which is already accounted for
// when we're using `windowGetHeight`). `windowGetWidth` is used for
// consistency.
blitBufferToBuffer(
src + ((GAME_DIALOG_WINDOW_WIDTH - 332) / 2) * (GAME_DIALOG_WINDOW_WIDTH) + (GAME_DIALOG_WINDOW_WIDTH - 388) / 2,
src + ((windowGetHeight(gIsoWindow) - 232) / 2) * windowGetWidth(gIsoWindow) + (windowGetWidth(gIsoWindow) - 388) / 2,
388,
200,
screenGetWidth(),
windowGetWidth(gIsoWindow),
gGameDialogDisplayBuffer,
GAME_DIALOG_WINDOW_WIDTH);
}

View File

@ -1927,16 +1927,16 @@ int gameMouseObjectsInit()
return -1;
}
gGameMouseBouncingCursor->flags |= OBJECT_FLAG_0x20000000;
gGameMouseBouncingCursor->flags |= OBJECT_LIGHT_THRU;
gGameMouseBouncingCursor->flags |= OBJECT_TEMPORARY;
gGameMouseBouncingCursor->flags |= OBJECT_FLAG_0x400;
gGameMouseBouncingCursor->flags |= OBJECT_FLAG_0x80000000;
gGameMouseBouncingCursor->flags |= OBJECT_SHOOT_THRU;
gGameMouseBouncingCursor->flags |= OBJECT_NO_BLOCK;
gGameMouseHexCursor->flags |= OBJECT_FLAG_0x400;
gGameMouseHexCursor->flags |= OBJECT_TEMPORARY;
gGameMouseHexCursor->flags |= OBJECT_FLAG_0x20000000;
gGameMouseHexCursor->flags |= OBJECT_FLAG_0x80000000;
gGameMouseHexCursor->flags |= OBJECT_LIGHT_THRU;
gGameMouseHexCursor->flags |= OBJECT_SHOOT_THRU;
gGameMouseHexCursor->flags |= OBJECT_NO_BLOCK;
_obj_toggle_flat(gGameMouseHexCursor, NULL);

View File

@ -46,7 +46,7 @@ const char* gMovieFileNames[MOVIE_COUNT] = {
};
// 0x518DE4
char* gMoviePaletteFilePaths[MOVIE_COUNT] = {
const char* gMoviePaletteFilePaths[MOVIE_COUNT] = {
NULL,
"art\\cuts\\introsub.pal",
"art\\cuts\\eldersub.pal",
@ -209,7 +209,7 @@ int gameMoviePlay(int movie, int flags)
int oldTextColor;
int oldFont;
if (subtitlesEnabled) {
char* subtitlesPaletteFilePath;
const char* subtitlesPaletteFilePath;
if (gMoviePaletteFilePaths[movie] != NULL) {
subtitlesPaletteFilePath = gMoviePaletteFilePaths[movie];
} else {

View File

@ -35,7 +35,7 @@ typedef enum GameMovie {
extern const float flt_50352A;
extern const char* gMovieFileNames[MOVIE_COUNT];
extern char* gMoviePaletteFilePaths[MOVIE_COUNT];
extern const char* gMoviePaletteFilePaths[MOVIE_COUNT];
extern bool gGameMovieIsPlaying;
extern bool gGameMovieFaded;

View File

@ -41,6 +41,14 @@
#include <algorithm>
#define INVENTORY_WINDOW_X 80
#define INVENTORY_WINDOW_Y 0
#define INVENTORY_TRADE_WINDOW_X 80
#define INVENTORY_TRADE_WINDOW_Y 290
#define INVENTORY_TRADE_WINDOW_WIDTH 480
#define INVENTORY_TRADE_WINDOW_HEIGHT 180
#define INVENTORY_LARGE_SLOT_WIDTH 90
#define INVENTORY_LARGE_SLOT_HEIGHT 61
@ -550,10 +558,10 @@ bool _setup_inventory(int inventoryWindowType)
// Maintain original position in original resolution, otherwise center it.
int inventoryWindowX = screenGetWidth() != 640
? (screenGetWidth() - windowDescription->width) / 2
: 80;
: INVENTORY_WINDOW_X;
int inventoryWindowY = screenGetHeight() != 480
? (screenGetHeight() - windowDescription->height) / 2
: 0;
: INVENTORY_WINDOW_Y;
gInventoryWindow = windowCreate(inventoryWindowX,
inventoryWindowY,
windowDescription->width,
@ -582,15 +590,15 @@ bool _setup_inventory(int inventoryWindowType)
gInventorySlotsCount = 3;
// Trade inventory window is a part of game dialog, which is 640x480.
int tradeWindowX = (screenGetWidth() - 640) / 2 + 80;
int tradeWindowY = (screenGetHeight() - 480) / 2 + 290;
gInventoryWindow = windowCreate(tradeWindowX, tradeWindowY, 480, 180, 257, 0);
gInventoryWindowMaxX = tradeWindowX + 480;
gInventoryWindowMaxY = tradeWindowY + 180;
int tradeWindowX = (screenGetWidth() - 640) / 2 + INVENTORY_TRADE_WINDOW_X;
int tradeWindowY = (screenGetHeight() - 480) / 2 + INVENTORY_TRADE_WINDOW_Y;
gInventoryWindow = windowCreate(tradeWindowX, tradeWindowY, INVENTORY_TRADE_WINDOW_WIDTH, INVENTORY_TRADE_WINDOW_HEIGHT, 257, 0);
gInventoryWindowMaxX = tradeWindowX + INVENTORY_TRADE_WINDOW_WIDTH;
gInventoryWindowMaxY = tradeWindowY + INVENTORY_TRADE_WINDOW_HEIGHT;
unsigned char* dest = windowGetBuffer(gInventoryWindow);
unsigned char* src = windowGetBuffer(_barter_back_win);
blitBufferToBuffer(src + 80, 480, 180, 640, dest, 480);
blitBufferToBuffer(src + INVENTORY_TRADE_WINDOW_X, INVENTORY_TRADE_WINDOW_WIDTH, INVENTORY_TRADE_WINDOW_HEIGHT, 640, dest, INVENTORY_TRADE_WINDOW_WIDTH);
gInventoryPrintItemDescriptionHandler = gameDialogRenderSupplementaryMessage;
}
@ -606,7 +614,7 @@ bool _setup_inventory(int inventoryWindowType)
}
int eventCode = 2005;
int y = INVENTORY_SLOT_HEIGHT * 5 + INVENTORY_SLOT_HEIGHT;
int y = INVENTORY_SLOT_HEIGHT * 5 + INVENTORY_LOOT_LEFT_SCROLLER_Y;
// Create invisible buttons representing container's inventory item
// slots. For unknown reason it loops backwards and it's size is
@ -2987,7 +2995,7 @@ void inventoryWindowOpenContextMenu(int keyCode, int inventoryWindowType)
int x;
int y;
mouseGetPositionInWindow(gInventoryWindow, &x, &y);
mouseGetPosition(&x, &y);
int actionMenuItemsLength;
const int* actionMenuItems;
@ -3035,9 +3043,15 @@ void inventoryWindowOpenContextMenu(int keyCode, int inventoryWindowType)
}
const InventoryWindowDescription* windowDescription = &(gInventoryWindowDescriptions[inventoryWindowType]);
Rect windowRect;
windowGetRect(gInventoryWindow, &windowRect);
int inventoryWindowX = windowRect.left;
int inventoryWindowY = windowRect.top;
gameMouseRenderActionMenuItems(x, y, actionMenuItems, actionMenuItemsLength,
windowDescription->width + windowDescription->x,
windowDescription->height + windowDescription->y);
windowDescription->width + inventoryWindowX,
windowDescription->height + inventoryWindowY);
InventoryCursorData* cursorData = &(gInventoryCursorData[INVENTORY_WINDOW_CURSOR_MENU]);
@ -3046,8 +3060,8 @@ void inventoryWindowOpenContextMenu(int keyCode, int inventoryWindowType)
artGetRotationOffsets(cursorData->frm, 0, &offsetX, &offsetY);
Rect rect;
rect.left = x - windowDescription->x - cursorData->width / 2 + offsetX;
rect.top = y - windowDescription->y - cursorData->height + 1 + offsetY;
rect.left = x - inventoryWindowX - cursorData->width / 2 + offsetX;
rect.top = y - inventoryWindowY - cursorData->height + 1 + offsetY;
rect.right = rect.left + cursorData->width - 1;
rect.bottom = rect.top + cursorData->height - 1;
@ -3082,7 +3096,7 @@ void inventoryWindowOpenContextMenu(int keyCode, int inventoryWindowType)
int x;
int y;
mouseGetPositionInWindow(gInventoryWindow, &x, &y);
mouseGetPosition(&x, &y);
if (y - previousMouseY > 10 || previousMouseY - y > 10) {
if (y >= previousMouseY || menuItemIndex <= 0) {
if (previousMouseY < y && menuItemIndex < actionMenuItemsLength - 1) {
@ -4476,6 +4490,7 @@ void _container_enter(int keyCode, int inventoryWindowType)
_stack[_curr_stack] = item;
_stack_offset[_curr_stack] = 0;
_inven_dude = _stack[_curr_stack];
_pud = &(item->data.inventory);
_adjust_fid();

View File

@ -576,11 +576,11 @@ bool _item_identical(Object* a1, Object* a2)
return false;
}
if ((a1->flags & (OBJECT_EQUIPPED | OBJECT_FLAG_0x2000)) != 0) {
if ((a1->flags & (OBJECT_EQUIPPED | OBJECT_USED)) != 0) {
return false;
}
if ((a2->flags & (OBJECT_EQUIPPED | OBJECT_FLAG_0x2000)) != 0) {
if ((a2->flags & (OBJECT_EQUIPPED | OBJECT_USED)) != 0) {
return false;
}
@ -989,14 +989,14 @@ int _item_queued(Object* obj)
return false;
}
if ((obj->flags & OBJECT_FLAG_0x2000) != 0) {
if ((obj->flags & OBJECT_USED) != 0) {
return true;
}
Inventory* inventory = &(obj->data.inventory);
for (int index = 0; index < inventory->length; index++) {
InventoryItem* inventoryItem = &(inventory->items[index]);
if ((inventoryItem->item->flags & OBJECT_FLAG_0x2000) != 0) {
if ((inventoryItem->item->flags & OBJECT_USED) != 0) {
return true;
}
@ -2402,11 +2402,11 @@ int _item_m_turn_off_from_queue(Object* obj, void* data)
// 0x479960
int stealthBoyTurnOn(Object* object)
{
if ((object->flags & OBJECT_FLAG_0x20000) != 0) {
if ((object->flags & OBJECT_TRANS_GLASS) != 0) {
return -1;
}
object->flags |= OBJECT_FLAG_0x20000;
object->flags |= OBJECT_TRANS_GLASS;
Rect rect;
objectGetRect(object, &rect);
@ -2428,11 +2428,11 @@ int stealthBoyTurnOff(Object* critter, Object* item)
return -1;
}
if ((critter->flags & OBJECT_FLAG_0x20000) == 0) {
if ((critter->flags & OBJECT_TRANS_GLASS) == 0) {
return -1;
}
critter->flags &= ~OBJECT_FLAG_0x20000;
critter->flags &= ~OBJECT_TRANS_GLASS;
Rect rect;
objectGetRect(critter, &rect);

View File

@ -177,44 +177,46 @@ int lipsStart()
}
// 0x47AD98
int lipsReadV1(LipsData* a1, File* stream)
int lipsReadV1(LipsData* lipsData, File* stream)
{
int field_C;
int sound;
int field_14;
int field_18;
int field_30;
int phonemes;
int markers;
if (fileReadInt32(stream, &(a1->version)) == -1) return -1;
if (fileReadInt32(stream, &(a1->field_4)) == -1) return -1;
if (fileReadInt32(stream, &(a1->flags)) == -1) return -1;
if (fileReadInt32(stream, &(field_C)) == -1) return -1;
if (fileReadInt32(stream, &(a1->field_10)) == -1) return -1;
if (fileReadInt32(stream, &(lipsData->version)) == -1) return -1;
if (fileReadInt32(stream, &(lipsData->field_4)) == -1) return -1;
if (fileReadInt32(stream, &(lipsData->flags)) == -1) return -1;
if (fileReadInt32(stream, &(sound)) == -1) return -1;
if (fileReadInt32(stream, &(lipsData->field_10)) == -1) return -1;
if (fileReadInt32(stream, &(field_14)) == -1) return -1;
if (fileReadInt32(stream, &(field_18)) == -1) return -1;
if (fileReadInt32(stream, &(a1->field_1C)) == -1) return -1;
if (fileReadInt32(stream, &(a1->field_20)) == -1) return -1;
if (fileReadInt32(stream, &(a1->field_24)) == -1) return -1;
if (fileReadInt32(stream, &(a1->field_28)) == -1) return -1;
if (fileReadInt32(stream, &(a1->field_2C)) == -1) return -1;
if (fileReadInt32(stream, &(field_30)) == -1) return -1;
if (fileReadInt32(stream, &(a1->field_34)) == -1) return -1;
if (fileReadInt32(stream, &(a1->field_38)) == -1) return -1;
if (fileReadInt32(stream, &(a1->field_3C)) == -1) return -1;
if (fileReadInt32(stream, &(a1->field_40)) == -1) return -1;
if (fileReadInt32(stream, &(a1->field_44)) == -1) return -1;
if (fileReadInt32(stream, &(a1->field_48)) == -1) return -1;
if (fileReadInt32(stream, &(a1->field_4C)) == -1) return -1;
if (fileReadFixedLengthString(stream, a1->field_50, 8) == -1) return -1;
if (fileReadFixedLengthString(stream, a1->field_58, 4) == -1) return -1;
if (fileReadFixedLengthString(stream, a1->field_5C, 4) == -1) return -1;
if (fileReadFixedLengthString(stream, a1->field_60, 4) == -1) return -1;
if (fileReadFixedLengthString(stream, a1->field_64, 260) == -1) return -1;
if (fileReadInt32(stream, &(phonemes)) == -1) return -1;
if (fileReadInt32(stream, &(lipsData->field_1C)) == -1) return -1;
if (fileReadInt32(stream, &(lipsData->field_20)) == -1) return -1;
if (fileReadInt32(stream, &(lipsData->field_24)) == -1) return -1;
if (fileReadInt32(stream, &(lipsData->field_28)) == -1) return -1;
if (fileReadInt32(stream, &(lipsData->field_2C)) == -1) return -1;
if (fileReadInt32(stream, &(markers)) == -1) return -1;
if (fileReadInt32(stream, &(lipsData->field_34)) == -1) return -1;
if (fileReadInt32(stream, &(lipsData->field_38)) == -1) return -1;
if (fileReadInt32(stream, &(lipsData->field_3C)) == -1) return -1;
if (fileReadInt32(stream, &(lipsData->field_40)) == -1) return -1;
if (fileReadInt32(stream, &(lipsData->field_44)) == -1) return -1;
if (fileReadInt32(stream, &(lipsData->field_48)) == -1) return -1;
if (fileReadInt32(stream, &(lipsData->field_4C)) == -1) return -1;
if (fileReadFixedLengthString(stream, lipsData->field_50, 8) == -1) return -1;
if (fileReadFixedLengthString(stream, lipsData->field_58, 4) == -1) return -1;
if (fileReadFixedLengthString(stream, lipsData->field_5C, 4) == -1) return -1;
if (fileReadFixedLengthString(stream, lipsData->field_60, 4) == -1) return -1;
if (fileReadFixedLengthString(stream, lipsData->field_64, 260) == -1) return -1;
// TODO: What for?
a1->sound = (Sound*)field_C;
a1->field_14 = (void*)field_14;
a1->phonemes = (unsigned char*)field_18;
a1->markers = (SpeechMarker*)field_30;
// NOTE: Original code is different. For unknown reason it assigns values
// from file (integers) and treat them as pointers, which is obviously wrong
// is in this case.
lipsData->sound = NULL;
lipsData->field_14 = NULL;
lipsData->phonemes = NULL;
lipsData->markers = NULL;
return 0;
}

View File

@ -111,7 +111,7 @@ SaveGameHandler* _master_save_list[LOAD_SAVE_HANDLER_COUNT] = {
traitsSave,
automapSave,
preferencesSave,
_editor_save,
characterEditorSave,
worldmapSave,
pipboySave,
gameMoviesSave,
@ -142,7 +142,7 @@ LoadGameHandler* _master_load_list[LOAD_SAVE_HANDLER_COUNT] = {
traitsLoad,
automapLoad,
preferencesLoad,
_editor_load,
characterEditorLoad,
worldmapLoad,
pipboyLoad,
gameMoviesLoad,
@ -626,9 +626,10 @@ int _QuickSnapShot()
}
// For preview take 640x380 area in the center of isometric window.
unsigned char* isoWindowBuffer = windowGetBuffer(gIsoWindow)
+ (screenGetWidth() - ORIGINAL_ISO_WINDOW_WIDTH) / 2 * (screenGetHeight() - ORIGINAL_ISO_WINDOW_HEIGHT) / 2
+ (screenGetWidth() - ORIGINAL_ISO_WINDOW_WIDTH) / 2;
Window* window = windowGetWindow(gIsoWindow);
unsigned char* isoWindowBuffer = window->buffer
+ window->width * (window->height - ORIGINAL_ISO_WINDOW_HEIGHT) / 2
+ (window->width - ORIGINAL_ISO_WINDOW_WIDTH) / 2;
blitBufferToBufferStretch(isoWindowBuffer,
ORIGINAL_ISO_WINDOW_WIDTH,
ORIGINAL_ISO_WINDOW_HEIGHT,
@ -1107,9 +1108,10 @@ int lsgWindowInit(int windowType)
}
// For preview take 640x380 area in the center of isometric window.
unsigned char* isoWindowBuffer = windowGetBuffer(gIsoWindow)
+ (screenGetWidth() - ORIGINAL_ISO_WINDOW_WIDTH) / 2 * (screenGetHeight() - ORIGINAL_ISO_WINDOW_HEIGHT) / 2
+ (screenGetWidth() - ORIGINAL_ISO_WINDOW_WIDTH) / 2;
Window* window = windowGetWindow(gIsoWindow);
unsigned char* isoWindowBuffer = window->buffer
+ window->width * (window->height - ORIGINAL_ISO_WINDOW_HEIGHT) / 2
+ (window->width - ORIGINAL_ISO_WINDOW_WIDTH) / 2;
blitBufferToBufferStretch(isoWindowBuffer,
ORIGINAL_ISO_WINDOW_WIDTH,
ORIGINAL_ISO_WINDOW_HEIGHT,

View File

@ -132,9 +132,14 @@ int falloutMain(int argc, char** argv)
return 1;
}
// SFALL: Allow to skip intro movies
int skipOpeningMovies;
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_SKIP_OPENING_MOVIES_KEY, &skipOpeningMovies);
if(skipOpeningMovies < 1) {
gameMoviePlay(MOVIE_IPLOGO, GAME_MOVIE_FADE_IN);
gameMoviePlay(MOVIE_INTRO, 0);
gameMoviePlay(MOVIE_CREDITS, 0);
}
FpsLimiter fpsLimiter;
@ -194,7 +199,7 @@ int falloutMain(int argc, char** argv)
mainMenuWindowHide(true);
mainMenuWindowFree();
_game_user_wants_to_quit = 0;
gDude->flags &= ~OBJECT_FLAG_0x08;
gDude->flags &= ~OBJECT_FLAT;
_main_show_death_scene = 0;
objectShow(gDude, NULL);
mouseHideCursor();
@ -296,7 +301,7 @@ int _main_load_new(char* mapFileName)
{
_game_user_wants_to_quit = 0;
_main_show_death_scene = 0;
gDude->flags &= ~OBJECT_FLAG_0x08;
gDude->flags &= ~OBJECT_FLAT;
objectShow(gDude, NULL);
mouseHideCursor();
@ -639,17 +644,31 @@ int mainMenuWindowInit()
int oldFont = fontGetCurrent();
fontSetCurrent(100);
// SFALL: Allow to change font color/flags of copyright/version text
// It's the last byte ('3C' by default) that picks the colour used. The first byte supplies additional flags for this option
// 0x010000 - change the color for version string only
// 0x020000 - underline text (only for the version string)
// 0x040000 - monospace font (only for the version string)
int fontSettings = _colorTable[21091], fontSettingsSFall = 0;
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MAIN_MENU_FONT_COLOR_KEY, &fontSettingsSFall);
if (fontSettingsSFall && !(fontSettingsSFall & 0x010000))
fontSettings = fontSettingsSFall & 0xFF;
// Copyright.
msg.num = 20;
if (messageListGetItem(&gMiscMessageList, &msg)) {
windowDrawText(gMainMenuWindow, msg.text, 0, 15, 460, _colorTable[21091] | 0x6000000);
windowDrawText(gMainMenuWindow, msg.text, 0, 15, 460, fontSettings | 0x06000000);
}
// SFALL: Make sure font settings are applied when using 0x010000 flag
if (fontSettingsSFall)
fontSettings = fontSettingsSFall;
// Version.
char version[VERSION_MAX];
versionGetVersion(version);
len = fontGetStringWidth(version);
windowDrawText(gMainMenuWindow, version, 0, 615 - len, 460, _colorTable[21091] | 0x6000000);
windowDrawText(gMainMenuWindow, version, 0, 615 - len, 460, fontSettings | 0x06000000);
// menuup.frm
fid = buildFid(6, 299, 0, 0, 0);
@ -683,11 +702,18 @@ int mainMenuWindowInit()
fontSetCurrent(104);
// SFALL: Allow to change font color of buttons
fontSettings = _colorTable[21091];
fontSettingsSFall = 0;
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MAIN_MENU_BIG_FONT_COLOR_KEY, &fontSettingsSFall);
if (fontSettingsSFall)
fontSettings = fontSettingsSFall & 0xFF;
for (int index = 0; index < MAIN_MENU_BUTTON_COUNT; index++) {
msg.num = 9 + index;
if (messageListGetItem(&gMiscMessageList, &msg)) {
len = fontGetStringWidth(msg.text);
fontDrawText(gMainMenuWindowBuffer + 640 * (42 * index - index + 20) + 126 - (len / 2), msg.text, 640 - (126 - (len / 2)) - 1, 640, _colorTable[21091]);
fontDrawText(gMainMenuWindowBuffer + 640 * (42 * index - index + 20) + 126 - (len / 2), msg.text, 640 - (126 - (len / 2)) - 1, 640, fontSettings);
}
}

View File

@ -903,7 +903,7 @@ int mapLoad(File* stream)
Object* object;
int fid = buildFid(5, 12, 0, 0, 0);
objectCreateWithFidPid(&object, fid, -1);
object->flags |= (OBJECT_FLAG_0x20000000 | OBJECT_TEMPORARY | OBJECT_HIDDEN);
object->flags |= (OBJECT_LIGHT_THRU | OBJECT_TEMPORARY | OBJECT_HIDDEN);
objectSetLocation(object, 1, 0, NULL);
object->sid = gMapSid;
scriptSetFixedParam(gMapSid, (gMapHeader.flags & 1) == 0);

View File

@ -22,10 +22,10 @@ int gMemoryBlocksCurrentCount = 0;
int gMemoryBlockMaximumCount = 0;
// 0x51DEE4
int gMemoryBlocksCurrentSize = 0;
size_t gMemoryBlocksCurrentSize = 0;
// 0x51DEE8
int gMemoryBlocksMaximumSize = 0;
size_t gMemoryBlocksMaximumSize = 0;
// 0x4C5A80
char* internal_strdup(const char* string)

View File

@ -29,8 +29,8 @@ extern ReallocProc* gReallocProc;
extern FreeProc* gFreeProc;
extern int gMemoryBlocksCurrentCount;
extern int gMemoryBlockMaximumCount;
extern int gMemoryBlocksCurrentSize;
extern int gMemoryBlocksMaximumSize;
extern size_t gMemoryBlocksCurrentSize;
extern size_t gMemoryBlocksMaximumSize;
char* internal_strdup(const char* string);
void* internal_malloc(size_t size);

View File

@ -9,23 +9,7 @@
// 0x4E08A0
bool mmxIsSupported()
{
int v1;
// TODO: There are other ways to determine MMX using FLAGS register.
#if defined (_MSC_VER)
__asm
{
mov eax, 1
cpuid
and edx, 0x800000
mov v1, edx
}
#else
v1 = 0;
#endif
return v1 != 0;
return SDL_HasMMX() == SDL_TRUE;
}
// 0x4E0DB0

View File

@ -39,31 +39,31 @@ typedef enum OutlineType {
typedef enum ObjectFlags {
OBJECT_HIDDEN = 0x01,
OBJECT_TEMPORARY = 0x04,
OBJECT_FLAG_0x08 = 0x08,
OBJECT_FLAT = 0x08,
OBJECT_NO_BLOCK = 0x10,
OBJECT_LIGHTING = 0x20,
OBJECT_FLAG_0x400 = 0x400,
OBJECT_FLAG_0x800 = 0x800,
OBJECT_FLAG_0x1000 = 0x1000,
OBJECT_FLAG_0x2000 = 0x2000,
OBJECT_FLAG_0x4000 = 0x4000,
OBJECT_FLAG_0x8000 = 0x8000,
OBJECT_FLAG_0x10000 = 0x10000,
OBJECT_FLAG_0x20000 = 0x20000,
OBJECT_FLAG_0x40000 = 0x40000,
OBJECT_FLAG_0x80000 = 0x80000,
OBJECT_FLAG_0x400 = 0x400, // ???
OBJECT_MULTIHEX = 0x800,
OBJECT_NO_HIGHLIGHT = 0x1000,
OBJECT_USED = 0x2000, // set if there was/is any event for the object
OBJECT_TRANS_RED = 0x4000,
OBJECT_TRANS_NONE = 0x8000,
OBJECT_TRANS_WALL = 0x10000,
OBJECT_TRANS_GLASS = 0x20000,
OBJECT_TRANS_STEAM = 0x40000,
OBJECT_TRANS_ENERGY = 0x80000,
OBJECT_IN_LEFT_HAND = 0x1000000,
OBJECT_IN_RIGHT_HAND = 0x2000000,
OBJECT_WORN = 0x4000000,
OBJECT_FLAG_0x10000000 = 0x10000000,
OBJECT_FLAG_0x20000000 = 0x20000000,
OBJECT_FLAG_0x40000000 = 0x40000000,
OBJECT_FLAG_0x80000000 = 0x80000000,
OBJECT_WALL_TRANS_END = 0x10000000,
OBJECT_LIGHT_THRU = 0x20000000,
OBJECT_SEEN = 0x40000000,
OBJECT_SHOOT_THRU = 0x80000000,
OBJECT_IN_ANY_HAND = OBJECT_IN_LEFT_HAND | OBJECT_IN_RIGHT_HAND,
OBJECT_EQUIPPED = OBJECT_IN_ANY_HAND | OBJECT_WORN,
OBJECT_FLAG_0xFC000 = OBJECT_FLAG_0x80000 | OBJECT_FLAG_0x40000 | OBJECT_FLAG_0x20000 | OBJECT_FLAG_0x10000 | OBJECT_FLAG_0x8000 | OBJECT_FLAG_0x4000,
OBJECT_OPEN_DOOR = OBJECT_FLAG_0x80000000 | OBJECT_FLAG_0x20000000 | OBJECT_NO_BLOCK,
OBJECT_FLAG_0xFC000 = OBJECT_TRANS_ENERGY | OBJECT_TRANS_STEAM | OBJECT_TRANS_GLASS | OBJECT_TRANS_WALL | OBJECT_TRANS_NONE | OBJECT_TRANS_RED,
OBJECT_OPEN_DOOR = OBJECT_SHOOT_THRU | OBJECT_LIGHT_THRU | OBJECT_NO_BLOCK,
} ObjectFlags;
#define OUTLINE_TYPE_MASK 0xFFFFFF

View File

@ -30,13 +30,13 @@
bool gObjectsInitialized = false;
// 0x5195FC
int _updateHexWidth = 0;
int gObjectsUpdateAreaHexWidth = 0;
// 0x519600
int _updateHexHeight = 0;
int gObjectsUpdateAreaHexHeight = 0;
// 0x519604
int _updateHexArea = 0;
int gObjectsUpdateAreaHexSize = 0;
// 0x519608
int* _orderTable[2] = {
@ -204,16 +204,7 @@ Rect gObjectsWindowRect;
Object* _outlinedObjects[100];
// 0x639D90
int _updateAreaPixelBounds;
// 0x639D94
int dword_639D94;
// 0x639D98
int dword_639D98;
// 0x639D9C
int dword_639D9C;
Rect gObjectsUpdateAreaPixelBounds;
// Contains objects that are bounded to tiles.
//
@ -264,14 +255,14 @@ int objectsInit(unsigned char* buf, int width, int height, int pitch)
int eggFid;
memset(_obj_seen, 0, 5001);
dword_639D98 = width + 320;
_updateAreaPixelBounds = -320;
dword_639D9C = height + 240;
dword_639D94 = -240;
gObjectsUpdateAreaPixelBounds.right = width + 320;
gObjectsUpdateAreaPixelBounds.left = -320;
gObjectsUpdateAreaPixelBounds.bottom = height + 240;
gObjectsUpdateAreaPixelBounds.top = -240;
_updateHexWidth = (dword_639D98 + 320 + 1) / 32 + 1;
_updateHexHeight = (dword_639D9C + 240 + 1) / 12 + 1;
_updateHexArea = _updateHexWidth * _updateHexHeight;
gObjectsUpdateAreaHexWidth = (gObjectsUpdateAreaPixelBounds.right + 320 + 1) / 32 + 1;
gObjectsUpdateAreaHexHeight = (gObjectsUpdateAreaPixelBounds.bottom + 240 + 1) / 12 + 1;
gObjectsUpdateAreaHexSize = gObjectsUpdateAreaHexWidth * gObjectsUpdateAreaHexHeight;
memset(gObjectListHeadByTile, 0, sizeof(gObjectListHeadByTile));
@ -298,7 +289,7 @@ int objectsInit(unsigned char* buf, int width, int height, int pitch)
_obj_light_table_init();
_obj_blend_table_init();
_centerToUpperLeft = tileFromScreenXY(_updateAreaPixelBounds, dword_639D94, 0) - gCenterTile;
_centerToUpperLeft = tileFromScreenXY(gObjectsUpdateAreaPixelBounds.left, gObjectsUpdateAreaPixelBounds.top, 0) - gCenterTile;
gObjectsWindowWidth = width;
gObjectsWindowHeight = height;
gObjectsWindowBuffer = buf;
@ -317,7 +308,7 @@ int objectsInit(unsigned char* buf, int width, int height, int pitch)
gDude->flags |= OBJECT_FLAG_0x400;
gDude->flags |= OBJECT_TEMPORARY;
gDude->flags |= OBJECT_HIDDEN;
gDude->flags |= OBJECT_FLAG_0x20000000;
gDude->flags |= OBJECT_LIGHT_THRU;
objectSetLight(gDude, 4, 0x10000, NULL);
if (partyMemberAdd(gDude) == -1) {
@ -330,7 +321,7 @@ int objectsInit(unsigned char* buf, int width, int height, int pitch)
gEgg->flags |= OBJECT_FLAG_0x400;
gEgg->flags |= OBJECT_TEMPORARY;
gEgg->flags |= OBJECT_HIDDEN;
gEgg->flags |= OBJECT_FLAG_0x20000000;
gEgg->flags |= OBJECT_LIGHT_THRU;
gObjectsInitialized = true;
@ -767,35 +758,59 @@ void _obj_render_pre_roof(Rect* rect, int elevation)
return;
}
int lightLevel = lightGetLightLevel();
int v5 = updatedRect.left - 320;
int v4 = updatedRect.top - 240;
int v17 = updatedRect.right + 320;
int v18 = updatedRect.bottom + 240;
int v19 = tileFromScreenXY(v5, v4, elevation);
int v20 = (v17 - v5 + 1) / 32;
int v23 = (v18 - v4 + 1) / 12;
int ambientLight = lightGetLightLevel();
int minX = updatedRect.left - 320;
int minY = updatedRect.top - 240;
int maxX = updatedRect.right + 320;
int maxY = updatedRect.bottom + 240;
int topLeftTile = tileFromScreenXY(minX, minY, elevation);
int updateAreaHexWidth = (maxX - minX + 1) / 32;
int updateAreaHexHeight = (maxY - minY + 1) / 12;
int odd = gCenterTile & 1;
int* v7 = _orderTable[odd];
int* v8 = _offsetTable[odd];
// On some maps (which were designed too close to edges) HRP brings a new
// problem - extended update rect (+/- 320/240 stuff above) may end up
// outside of the map edge. In this case `topLeftTile` will be -1 which
// affect all subsequent calculations. In order to fix that attempt to
// find closest valid tile.
while (!hexGridTileIsValid(topLeftTile)) {
minX += 32;
minY += 12;
topLeftTile = tileFromScreenXY(minX, minY, elevation);
}
// Do the same for the for bottom-right part of the extended update rect.
int bottomRightTile = tileFromScreenXY(maxX, maxY, elevation);
while (!hexGridTileIsValid(bottomRightTile)) {
maxX -= 32;
maxY -= 12;
bottomRightTile = tileFromScreenXY(maxX, maxY, elevation);
}
updateAreaHexWidth = (maxX - minX + 1) / 32;
updateAreaHexHeight = (maxY - minY + 1) / 12;
int parity = gCenterTile & 1;
int* orders = _orderTable[parity];
int* offsets = _offsetTable[parity];
_outlineCount = 0;
int v34 = 0;
for (int i = 0; i < _updateHexArea; i++) {
int v9 = *v7++;
if (v23 > _offsetDivTable[v9] && v20 > _offsetModTable[v9]) {
int v2;
int renderCount = 0;
for (int i = 0; i < gObjectsUpdateAreaHexSize; i++) {
int offsetIndex = *orders++;
if (updateAreaHexHeight > _offsetDivTable[offsetIndex] && updateAreaHexWidth > _offsetModTable[offsetIndex]) {
int light;
ObjectListNode* objectListNode = gObjectListHeadByTile[v19 + v8[v9]];
ObjectListNode* objectListNode = hexGridTileIsValid(topLeftTile + offsets[offsetIndex])
? gObjectListHeadByTile[topLeftTile + offsets[offsetIndex]]
: NULL;
if (objectListNode != NULL) {
// NOTE: calls _light_get_tile two times, probably result of min/max macro
int q = _light_get_tile(elevation, objectListNode->obj->tile);
if (q >= lightLevel) {
v2 = q;
int tileLight = _light_get_tile(elevation, objectListNode->obj->tile);
if (tileLight >= ambientLight) {
light = tileLight;
} else {
v2 = lightLevel;
light = ambientLight;
}
}
@ -805,12 +820,12 @@ void _obj_render_pre_roof(Rect* rect, int elevation)
}
if (elevation == objectListNode->obj->elevation) {
if ((objectListNode->obj->flags & OBJECT_FLAG_0x08) == 0) {
if ((objectListNode->obj->flags & OBJECT_FLAT) == 0) {
break;
}
if ((objectListNode->obj->flags & OBJECT_HIDDEN) == 0) {
_obj_render_object(objectListNode->obj, &updatedRect, v2);
_obj_render_object(objectListNode->obj, &updatedRect, light);
if ((objectListNode->obj->outline & OUTLINE_TYPE_MASK) != 0) {
if ((objectListNode->obj->outline & OUTLINE_DISABLED) == 0 && _outlineCount < 100) {
@ -824,20 +839,22 @@ void _obj_render_pre_roof(Rect* rect, int elevation)
}
if (objectListNode != NULL) {
_renderTable[v34++] = objectListNode;
_renderTable[renderCount++] = objectListNode;
}
}
}
for (int i = 0; i < v34; i++) {
int v2;
for (int i = 0; i < renderCount; i++) {
int light;
ObjectListNode* objectListNode = _renderTable[i];
if (objectListNode != NULL) {
v2 = lightLevel;
int w = _light_get_tile(elevation, objectListNode->obj->tile);
if (w > v2) {
v2 = w;
// NOTE: calls _light_get_tile two times, probably result of min/max macro
int tileLight = _light_get_tile(elevation, objectListNode->obj->tile);
if (tileLight >= ambientLight) {
light = tileLight;
} else {
light = ambientLight;
}
}
@ -849,7 +866,7 @@ void _obj_render_pre_roof(Rect* rect, int elevation)
if (elevation == objectListNode->obj->elevation) {
if ((objectListNode->obj->flags & OBJECT_HIDDEN) == 0) {
_obj_render_object(object, &updatedRect, v2);
_obj_render_object(object, &updatedRect, light);
if ((objectListNode->obj->outline & OUTLINE_TYPE_MASK) != 0) {
if ((objectListNode->obj->outline & OUTLINE_DISABLED) == 0 && _outlineCount < 100) {
@ -943,39 +960,39 @@ int objectCreateWithFidPid(Object** objectPtr, int fid, int pid)
}
if ((proto->flags & 0x800) != 0) {
objectListNode->obj->flags |= OBJECT_FLAG_0x800;
objectListNode->obj->flags |= OBJECT_MULTIHEX;
}
if ((proto->flags & 0x8000) != 0) {
objectListNode->obj->flags |= OBJECT_FLAG_0x8000;
objectListNode->obj->flags |= OBJECT_TRANS_NONE;
} else {
if ((proto->flags & 0x10000) != 0) {
objectListNode->obj->flags |= OBJECT_FLAG_0x10000;
objectListNode->obj->flags |= OBJECT_TRANS_WALL;
} else if ((proto->flags & 0x20000) != 0) {
objectListNode->obj->flags |= OBJECT_FLAG_0x20000;
objectListNode->obj->flags |= OBJECT_TRANS_GLASS;
} else if ((proto->flags & 0x40000) != 0) {
objectListNode->obj->flags |= OBJECT_FLAG_0x40000;
objectListNode->obj->flags |= OBJECT_TRANS_STEAM;
} else if ((proto->flags & 0x80000) != 0) {
objectListNode->obj->flags |= OBJECT_FLAG_0x80000;
objectListNode->obj->flags |= OBJECT_TRANS_ENERGY;
} else if ((proto->flags & 0x4000) != 0) {
objectListNode->obj->flags |= OBJECT_FLAG_0x4000;
objectListNode->obj->flags |= OBJECT_TRANS_RED;
}
}
if ((proto->flags & 0x20000000) != 0) {
objectListNode->obj->flags |= OBJECT_FLAG_0x20000000;
objectListNode->obj->flags |= OBJECT_LIGHT_THRU;
}
if ((proto->flags & 0x80000000) != 0) {
objectListNode->obj->flags |= OBJECT_FLAG_0x80000000;
objectListNode->obj->flags |= OBJECT_SHOOT_THRU;
}
if ((proto->flags & 0x10000000) != 0) {
objectListNode->obj->flags |= OBJECT_FLAG_0x10000000;
objectListNode->obj->flags |= OBJECT_WALL_TRANS_END;
}
if ((proto->flags & 0x1000) != 0) {
objectListNode->obj->flags |= OBJECT_FLAG_0x1000;
objectListNode->obj->flags |= OBJECT_NO_HIGHLIGHT;
}
_obj_new_sid(objectListNode->obj, &(objectListNode->obj->sid));
@ -1041,7 +1058,7 @@ int _obj_copy(Object** a1, Object* a2)
return -1;
}
objectListNode->obj->flags &= ~OBJECT_FLAG_0x2000;
objectListNode->obj->flags &= ~OBJECT_USED;
Inventory* newInventory = &(objectListNode->obj->data.inventory);
newInventory->length = 0;
@ -1948,7 +1965,7 @@ int _obj_toggle_flat(Object* object, Rect* rect)
}
}
object->flags ^= OBJECT_FLAG_0x08;
object->flags ^= OBJECT_FLAT;
_obj_insert(node);
objectGetRect(object, &v1);
@ -1965,7 +1982,7 @@ int _obj_toggle_flat(Object* object, Rect* rect)
}
}
object->flags ^= OBJECT_FLAG_0x08;
object->flags ^= OBJECT_FLAT;
_obj_insert(node);
}
@ -2419,7 +2436,7 @@ Object* _obj_blocking_at(Object* a1, int tile, int elev)
objectListNode = gObjectListHeadByTile[neighboor];
while (objectListNode != NULL) {
v7 = objectListNode->obj;
if ((v7->flags & OBJECT_FLAG_0x800) != 0) {
if ((v7->flags & OBJECT_MULTIHEX) != 0) {
if (v7->elevation == elev) {
if ((v7->flags & OBJECT_HIDDEN) == 0 && (v7->flags & OBJECT_NO_BLOCK) == 0 && v7 != a1) {
type = (v7->fid & 0xF000000) >> 24;
@ -2451,7 +2468,7 @@ Object* _obj_shoot_blocking_at(Object* obj, int tile, int elev)
Object* candidate = objectListItem->obj;
if (candidate->elevation == elev) {
unsigned int flags = candidate->flags;
if ((flags & OBJECT_HIDDEN) == 0 && ((flags & OBJECT_NO_BLOCK) == 0 || (flags & OBJECT_FLAG_0x80000000) == 0) && candidate != obj) {
if ((flags & OBJECT_HIDDEN) == 0 && ((flags & OBJECT_NO_BLOCK) == 0 || (flags & OBJECT_SHOOT_THRU) == 0) && candidate != obj) {
int type = (candidate->fid & 0xF000000) >> 24;
// SFALL: Fix to prevent corpses from blocking line of fire.
if ((type == OBJ_TYPE_CRITTER && !critterIsDead(candidate))
@ -2474,7 +2491,7 @@ Object* _obj_shoot_blocking_at(Object* obj, int tile, int elev)
while (objectListItem != NULL) {
Object* candidate = objectListItem->obj;
unsigned int flags = candidate->flags;
if ((flags & OBJECT_FLAG_0x800) != 0) {
if ((flags & OBJECT_MULTIHEX) != 0) {
if (candidate->elevation == elev) {
if ((flags & OBJECT_HIDDEN) == 0 && (flags & OBJECT_NO_BLOCK) == 0 && candidate != obj) {
int type = (candidate->fid & 0xF000000) >> 24;
@ -2533,7 +2550,7 @@ Object* _obj_ai_blocking_at(Object* a1, int tile, int elevation)
objectListNode = gObjectListHeadByTile[candidate];
while (objectListNode != NULL) {
Object* object = objectListNode->obj;
if ((object->flags & OBJECT_FLAG_0x800) != 0) {
if ((object->flags & OBJECT_MULTIHEX) != 0) {
if (object->elevation == elevation) {
if ((object->flags & OBJECT_HIDDEN) == 0
&& (object->flags & OBJECT_NO_BLOCK) == 0
@ -2590,7 +2607,7 @@ Object* _obj_sight_blocking_at(Object* a1, int tile, int elevation)
Object* object = objectListNode->obj;
if (object->elevation == elevation
&& (object->flags & OBJECT_HIDDEN) == 0
&& (object->flags & OBJECT_FLAG_0x20000000) == 0
&& (object->flags & OBJECT_LIGHT_THRU) == 0
&& object != a1) {
int objectType = (object->fid & 0xF000000) >> 24;
if (objectType == OBJ_TYPE_SCENERY || objectType == OBJ_TYPE_WALL) {
@ -2612,11 +2629,11 @@ int objectGetDistanceBetween(Object* object1, Object* object2)
int distance = tileDistanceBetween(object1->tile, object2->tile);
if ((object1->flags & OBJECT_FLAG_0x800) != 0) {
if ((object1->flags & OBJECT_MULTIHEX) != 0) {
distance -= 1;
}
if ((object2->flags & OBJECT_FLAG_0x800) != 0) {
if ((object2->flags & OBJECT_MULTIHEX) != 0) {
distance -= 1;
}
@ -2636,11 +2653,11 @@ int objectGetDistanceBetweenTiles(Object* object1, int tile1, Object* object2, i
int distance = tileDistanceBetween(tile1, tile2);
if ((object1->flags & OBJECT_FLAG_0x800) != 0) {
if ((object1->flags & OBJECT_MULTIHEX) != 0) {
distance -= 1;
}
if ((object2->flags & OBJECT_FLAG_0x800) != 0) {
if ((object2->flags & OBJECT_MULTIHEX) != 0) {
distance -= 1;
}
@ -2869,7 +2886,7 @@ int objectSetOutline(Object* obj, int outlineType, Rect* rect)
return -1;
}
if ((obj->flags & OBJECT_FLAG_0x1000) != 0) {
if ((obj->flags & OBJECT_NO_HIGHLIGHT) != 0) {
return -1;
}
@ -2951,7 +2968,7 @@ int _obj_intersects_with(Object* object, int x, int y)
flags |= 0x01;
if ((object->flags & OBJECT_FLAG_0xFC000) != 0) {
if ((object->flags & OBJECT_FLAG_0x8000) == 0) {
if ((object->flags & OBJECT_TRANS_NONE) == 0) {
flags &= ~0x03;
flags |= 0x02;
}
@ -2999,14 +3016,14 @@ int _obj_create_intersect_list(int x, int y, int elevation, int objectType, Obje
int v5 = tileFromScreenXY(x - 320, y - 240, elevation);
*entriesPtr = NULL;
if (_updateHexArea <= 0) {
if (gObjectsUpdateAreaHexSize <= 0) {
return 0;
}
int count = 0;
int parity = gCenterTile & 1;
for (int index = 0; index < _updateHexArea; index++) {
for (int index = 0; index < gObjectsUpdateAreaHexSize; index++) {
int v7 = _orderTable[parity][index];
if (_offsetDivTable[v7] < 30 && _offsetModTable[v7] < 20) {
ObjectListNode* objectListNode = gObjectListHeadByTile[_offsetTable[parity][v7] + v5];
@ -3100,7 +3117,7 @@ void _obj_process_seen()
if (v5 < 40000) {
for (obj_entry = gObjectListHeadByTile[v5]; obj_entry != NULL; obj_entry = obj_entry->next) {
if (obj_entry->obj->elevation == gDude->elevation) {
obj_entry->obj->flags |= OBJECT_FLAG_0x40000000;
obj_entry->obj->flags |= OBJECT_SEEN;
}
}
}
@ -3238,46 +3255,46 @@ int _obj_offset_table_init()
return -1;
}
_offsetTable[0] = (int*)internal_malloc(sizeof(int) * _updateHexArea);
_offsetTable[0] = (int*)internal_malloc(sizeof(int) * gObjectsUpdateAreaHexSize);
if (_offsetTable[0] == NULL) {
goto err;
}
_offsetTable[1] = (int*)internal_malloc(sizeof(int) * _updateHexArea);
_offsetTable[1] = (int*)internal_malloc(sizeof(int) * gObjectsUpdateAreaHexSize);
if (_offsetTable[1] == NULL) {
goto err;
}
for (int i = 0; i < 2; i++) {
int tile = tileFromScreenXY(_updateAreaPixelBounds, dword_639D94, 0);
if (tile != -1) {
int* v5 = _offsetTable[gCenterTile & 1];
int v20;
int v19;
tileToScreenXY(tile, &v20, &v19, 0);
for (int parity = 0; parity < 2; parity++) {
int originTile = tileFromScreenXY(gObjectsUpdateAreaPixelBounds.left, gObjectsUpdateAreaPixelBounds.top, 0);
if (originTile != -1) {
int* offsets = _offsetTable[gCenterTile & 1];
int originTileX;
int originTileY;
tileToScreenXY(originTile, &originTileX, &originTileY, 0);
int v23 = 16;
v20 += 16;
v19 += 8;
if (v20 > _updateAreaPixelBounds) {
v23 = -v23;
int parityShift = 16;
originTileX += 16;
originTileY += 8;
if (originTileX > gObjectsUpdateAreaPixelBounds.left) {
parityShift = -parityShift;
}
int v6 = v20;
for (int j = 0; j < _updateHexHeight; j++) {
for (int m = 0; m < _updateHexWidth; m++) {
int t = tileFromScreenXY(v6, v19, 0);
if (t == -1) {
int tileX = originTileX;
for (int y = 0; y < gObjectsUpdateAreaHexHeight; y++) {
for (int x = 0; x < gObjectsUpdateAreaHexWidth; x++) {
int tile = tileFromScreenXY(tileX, originTileY, 0);
if (tile == -1) {
goto err;
}
v6 += 32;
*v5++ = t - tile;
tileX += 32;
*offsets++ = tile - originTile;
}
v6 = v23 + v20;
v19 += 12;
v23 = -v23;
tileX = parityShift + originTileX;
originTileY += 12;
parityShift = -parityShift;
}
}
@ -3286,22 +3303,22 @@ int _obj_offset_table_init()
}
}
_offsetDivTable = (int*)internal_malloc(sizeof(int) * _updateHexArea);
_offsetDivTable = (int*)internal_malloc(sizeof(int) * gObjectsUpdateAreaHexSize);
if (_offsetDivTable == NULL) {
goto err;
}
for (i = 0; i < _updateHexArea; i++) {
_offsetDivTable[i] = i / _updateHexWidth;
for (i = 0; i < gObjectsUpdateAreaHexSize; i++) {
_offsetDivTable[i] = i / gObjectsUpdateAreaHexWidth;
}
_offsetModTable = (int*)internal_malloc(sizeof(int) * _updateHexArea);
_offsetModTable = (int*)internal_malloc(sizeof(int) * gObjectsUpdateAreaHexSize);
if (_offsetModTable == NULL) {
goto err;
}
for (i = 0; i < _updateHexArea; i++) {
_offsetModTable[i] = i % _updateHexWidth;
for (i = 0; i < gObjectsUpdateAreaHexSize; i++) {
_offsetModTable[i] = i % gObjectsUpdateAreaHexWidth;
}
return 0;
@ -3343,23 +3360,23 @@ int _obj_order_table_init()
return -1;
}
_orderTable[0] = (int*)internal_malloc(sizeof(int) * _updateHexArea);
_orderTable[0] = (int*)internal_malloc(sizeof(int) * gObjectsUpdateAreaHexSize);
if (_orderTable[0] == NULL) {
goto err;
}
_orderTable[1] = (int*)internal_malloc(sizeof(int) * _updateHexArea);
_orderTable[1] = (int*)internal_malloc(sizeof(int) * gObjectsUpdateAreaHexSize);
if (_orderTable[1] == NULL) {
goto err;
}
for (int index = 0; index < _updateHexArea; index++) {
for (int index = 0; index < gObjectsUpdateAreaHexSize; index++) {
_orderTable[0][index] = index;
_orderTable[1][index] = index;
}
qsort(_orderTable[0], _updateHexArea, sizeof(int), _obj_order_comp_func_even);
qsort(_orderTable[1], _updateHexArea, sizeof(int), _obj_order_comp_func_odd);
qsort(_orderTable[0], gObjectsUpdateAreaHexSize, sizeof(int), _obj_order_comp_func_even);
qsort(_orderTable[1], gObjectsUpdateAreaHexSize, sizeof(int), _obj_order_comp_func_odd);
return 0;
@ -3410,12 +3427,12 @@ int _obj_render_table_init()
return -1;
}
_renderTable = (ObjectListNode**)internal_malloc(sizeof(*_renderTable) * _updateHexArea);
_renderTable = (ObjectListNode**)internal_malloc(sizeof(*_renderTable) * gObjectsUpdateAreaHexSize);
if (_renderTable == NULL) {
return -1;
}
for (int index = 0; index < _updateHexArea; index++) {
for (int index = 0; index < gObjectsUpdateAreaHexSize; index++) {
_renderTable[index] = NULL;
}
@ -3438,11 +3455,11 @@ void _obj_light_table_init()
{
for (int s = 0; s < 2; s++) {
int v4 = gCenterTile + s;
for (int i = 0; i < 6; i++) {
for (int i = 0; i < ROTATION_COUNT; i++) {
int v15 = 8;
int* p = _light_offsets[v4 & 1][i];
for (int j = 0; j < 8; j++) {
int tile = tileGetTileInDirection(v4, (i + 1) % 6, j);
int tile = tileGetTileInDirection(v4, (i + 1) % ROTATION_COUNT, j);
for (int m = 0; m < v15; m++) {
*p++ = tileGetTileInDirection(tile, i, m + 1) - v4;
@ -3856,11 +3873,11 @@ void _obj_insert(ObjectListNode* objectListNode)
}
if (obj->elevation == objectListNode->obj->elevation) {
if ((obj->flags & OBJECT_FLAG_0x08) == 0 && (objectListNode->obj->flags & OBJECT_FLAG_0x08) != 0) {
if ((obj->flags & OBJECT_FLAT) == 0 && (objectListNode->obj->flags & OBJECT_FLAT) != 0) {
break;
}
if ((obj->flags & OBJECT_FLAG_0x08) == (objectListNode->obj->flags & OBJECT_FLAG_0x08)) {
if ((obj->flags & OBJECT_FLAT) == (objectListNode->obj->flags & OBJECT_FLAT)) {
bool v11 = false;
CacheEntry* a2;
Art* v12 = artLock(obj->fid, &a2);
@ -4553,10 +4570,10 @@ int _obj_adjust_light(Object* obj, int a2, Rect* rect)
objectGetRect(objectListNode->obj, &v29);
rectUnion(&objectRect, &v29, &objectRect);
v14 = (objectListNode->obj->flags & OBJECT_FLAG_0x20000000) == 0;
v14 = (objectListNode->obj->flags & OBJECT_LIGHT_THRU) == 0;
if ((objectListNode->obj->fid & 0xF000000) >> 24 == OBJ_TYPE_WALL) {
if ((objectListNode->obj->flags & OBJECT_FLAG_0x08) == 0) {
if ((objectListNode->obj->flags & OBJECT_FLAT) == 0) {
Proto* proto;
protoGetProto(objectListNode->obj->pid, &proto);
if ((proto->wall.extendedFlags & 0x8000000) != 0 || (proto->wall.extendedFlags & 0x40000000) != 0) {
@ -4964,7 +4981,7 @@ void _obj_render_object(Object* object, Rect* rect, int light)
v17 = tileIsInFrontOf(object->tile, gDude->tile);
if (!v17
|| !tileIsToRightOf(object->tile, gDude->tile)
|| (object->flags & OBJECT_FLAG_0x10000000) == 0) {
|| (object->flags & OBJECT_WALL_TRANS_END) == 0) {
// nothing
} else {
v17 = false;
@ -4980,7 +4997,7 @@ void _obj_render_object(Object* object, Rect* rect, int light)
v17 = tileIsToRightOf(gDude->tile, object->tile);
if (v17
&& tileIsInFrontOf(gDude->tile, object->tile)
&& (object->flags & OBJECT_FLAG_0x10000000) != 0) {
&& (object->flags & OBJECT_WALL_TRANS_END) != 0) {
v17 = 0;
}
}
@ -5071,19 +5088,19 @@ void _obj_render_object(Object* object, Rect* rect, int light)
}
switch (object->flags & OBJECT_FLAG_0xFC000) {
case OBJECT_FLAG_0x4000:
case OBJECT_TRANS_RED:
_dark_translucent_trans_buf_to_buf(src, objectWidth, objectHeight, frameWidth, gObjectsWindowBuffer, objectRect.left, objectRect.top, gObjectsWindowPitch, light, _redBlendTable, _commonGrayTable);
break;
case OBJECT_FLAG_0x10000:
case OBJECT_TRANS_WALL:
_dark_translucent_trans_buf_to_buf(src, objectWidth, objectHeight, frameWidth, gObjectsWindowBuffer, objectRect.left, objectRect.top, gObjectsWindowPitch, 0x10000, _wallBlendTable, _commonGrayTable);
break;
case OBJECT_FLAG_0x20000:
case OBJECT_TRANS_GLASS:
_dark_translucent_trans_buf_to_buf(src, objectWidth, objectHeight, frameWidth, gObjectsWindowBuffer, objectRect.left, objectRect.top, gObjectsWindowPitch, light, _glassBlendTable, _glassGrayTable);
break;
case OBJECT_FLAG_0x40000:
case OBJECT_TRANS_STEAM:
_dark_translucent_trans_buf_to_buf(src, objectWidth, objectHeight, frameWidth, gObjectsWindowBuffer, objectRect.left, objectRect.top, gObjectsWindowPitch, light, _steamBlendTable, _commonGrayTable);
break;
case OBJECT_FLAG_0x80000:
case OBJECT_TRANS_ENERGY:
_dark_translucent_trans_buf_to_buf(src, objectWidth, objectHeight, frameWidth, gObjectsWindowBuffer, objectRect.left, objectRect.top, gObjectsWindowPitch, light, _energyBlendTable, _commonGrayTable);
break;
default:

View File

@ -13,9 +13,9 @@ typedef struct ObjectWithFlags {
} ObjectWithFlags;
extern bool gObjectsInitialized;
extern int _updateHexWidth;
extern int _updateHexHeight;
extern int _updateHexArea;
extern int gObjectsUpdateAreaHexWidth;
extern int gObjectsUpdateAreaHexHeight;
extern int gObjectsUpdateAreaHexSize;
extern int* _orderTable[2];
extern int* _offsetTable[2];
extern int* _offsetModTable;
@ -49,10 +49,7 @@ extern int _light_blocked[6][36];
extern int _light_offsets[2][6][36];
extern Rect gObjectsWindowRect;
extern Object* _outlinedObjects[100];
extern int _updateAreaPixelBounds;
extern int dword_639D94;
extern int dword_639D98;
extern int dword_639D9C;
extern Rect gObjectsUpdateAreaPixelBounds;
extern ObjectListNode* gObjectListHeadByTile[HEX_GRID_SIZE];
extern unsigned char _glassGrayTable[256];
extern unsigned char _commonGrayTable[256];

View File

@ -21,7 +21,7 @@
#ifdef _WIN32
#include <timeapi.h>
#else
#include <sys/time.h>
#include <chrono>
#endif
int compat_stricmp(const char* string1, const char* string2)
@ -145,8 +145,8 @@ unsigned int compat_timeGetTime()
#ifdef _WIN32
return timeGetTime();
#else
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_usec / 1000;
static auto start = std::chrono::steady_clock::now();
auto now = std::chrono::steady_clock::now();
return static_cast<unsigned int>(std::chrono::duration_cast<std::chrono::milliseconds>(now - start).count());
#endif
}

View File

@ -777,7 +777,7 @@ int _proto_dude_init(const char* path)
_proto_dude_update_gender();
_inven_reset_dude();
if ((gDude->flags & OBJECT_FLAG_0x08) != 0) {
if ((gDude->flags & OBJECT_FLAT) != 0) {
_obj_toggle_flat(gDude, NULL);
}
@ -1854,7 +1854,7 @@ int _ResetPlayer()
pcStatsReset();
protoCritterDataResetStats(&(proto->critter.data));
critterReset();
_editor_reset();
characterEditorReset();
protoCritterDataResetSkills(&(proto->critter.data));
skillsReset();
perksReset();

View File

@ -796,7 +796,7 @@ int _obj_use_flare(Object* critter_obj, Object* flare)
return -1;
}
if ((flare->flags & OBJECT_FLAG_0x2000) != 0) {
if ((flare->flags & OBJECT_USED) != 0) {
if (critter_obj == gDude) {
// The flare is already lit.
messageListItem.num = 588;
@ -854,7 +854,7 @@ int _obj_use_explosive(Object* explosive)
return -1;
}
if ((explosive->flags & OBJECT_FLAG_0x2000) != 0) {
if ((explosive->flags & OBJECT_USED) != 0) {
// The timer is already ticking.
messageListItem.num = 590;
if (messageListGetItem(&gProtoMessageList, &messageListItem)) {
@ -2198,7 +2198,7 @@ int _objPMAttemptPlacement(Object* obj, int tile, int elevation)
for (int v4 = 1; v4 <= 100; v4++) {
// TODO: Check.
v7++;
v9 = tileGetTileInDirection(v9, v7 % 6, 1);
v9 = tileGetTileInDirection(v9, v7 % ROTATION_COUNT, 1);
if (_wmEvalTileNumForPlacement(v9) != 0) {
break;
}

View File

@ -232,7 +232,7 @@ int queueAddEvent(int delay, Object* obj, void* data, int eventType)
newQueueListNode->data = data;
if (obj != NULL) {
obj->flags |= OBJECT_FLAG_0x2000;
obj->flags |= OBJECT_USED;
}
QueueListNode** v3 = &gQueueListHead;

View File

@ -1723,7 +1723,8 @@ int scriptWrite(Script* scr, File* stream)
if (fileWriteInt32(stream, scr->flags) == -1) return -1;
if (fileWriteInt32(stream, scr->field_14) == -1) return -1;
if (fileWriteInt32(stream, (int)scr->program) == -1) return -1; // FIXME: writing pointer to file
// NOTE: Original code writes `scr->program` pointer which is meaningless.
if (fileWriteInt32(stream, 0) == -1) return -1;
if (fileWriteInt32(stream, scr->field_1C) == -1) return -1;
if (fileWriteInt32(stream, scr->localVarsOffset) == -1) return -1;
if (fileWriteInt32(stream, scr->localVarsCount) == -1) return -1;
@ -1753,8 +1754,8 @@ int scriptListExtentWrite(ScriptListExtent* a1, File* stream)
return -1;
}
if (fileWriteInt32(stream, (int)a1->next) != 0) {
// FIXME: writing pointer to file
// NOTE: Original code writes `a1->next` pointer which is meaningless.
if (fileWriteInt32(stream, 0) != 0) {
return -1;
}
@ -1778,18 +1779,16 @@ int scriptSaveAll(File* stream)
for (int index = 0; index < scriptExtent->length; index++) {
Script* script = &(scriptExtent->scripts[index]);
lastScriptExtent = scriptList->tail;
if ((script->flags & SCRIPT_FLAG_0x08) != 0) {
scriptCount--;
lastScriptExtent = scriptList->tail;
int backwardsIndex = lastScriptExtent->length - 1;
while (lastScriptExtent != scriptExtent || backwardsIndex > index) {
if (lastScriptExtent == scriptExtent) {
if (backwardsIndex >= index) {
if (lastScriptExtent == scriptExtent && backwardsIndex <= index) {
break;
}
}
while (lastScriptExtent != scriptExtent || backwardsIndex > index) {
Script* backwardsScript = &(lastScriptExtent->scripts[backwardsIndex]);
if ((backwardsScript->flags & SCRIPT_FLAG_0x08) == 0) {
break;
@ -2427,7 +2426,7 @@ bool scriptsExecSpatialProc(Object* object, int tile, int elevation)
return false;
}
if ((object->flags & OBJECT_HIDDEN) != 0 || (object->flags & OBJECT_FLAG_0x08) != 0) {
if ((object->flags & OBJECT_HIDDEN) != 0 || (object->flags & OBJECT_FLAT) != 0) {
return false;
}
@ -2685,7 +2684,7 @@ int scriptGetLocalVar(int sid, int variable, int* value)
}
Script* script;
if (scriptGetScript(sid, &script) == 1) {
if (scriptGetScript(sid, &script) == -1) {
*value = -1;
return -1;
}

View File

@ -21,7 +21,15 @@ bool sfallConfigInit(int argc, char** argv)
}
// Initialize defaults.
configSetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_DUDE_NATIVE_LOOK_JUMPSUIT_MALE_KEY, "");
configSetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_DUDE_NATIVE_LOOK_JUMPSUIT_FEMALE_KEY, "");
configSetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_DUDE_NATIVE_LOOK_TRIBAL_MALE_KEY, "");
configSetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_DUDE_NATIVE_LOOK_TRIBAL_FEMALE_KEY, "");
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MAIN_MENU_BIG_FONT_COLOR_KEY, 0);
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MAIN_MENU_FONT_COLOR_KEY, 0);
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_SKIP_OPENING_MOVIES_KEY, 0);
configSetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_STARTING_MAP_KEY, "");
configSetBool(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_DISPLAY_KARMA_CHANGES_KEY, false);
char path[COMPAT_MAX_PATH];
char* executable = argv[0];

View File

@ -7,7 +7,17 @@
#define SFALL_CONFIG_MISC_KEY "Misc"
#define SFALL_CONFIG_DUDE_NATIVE_LOOK_JUMPSUIT_MALE_KEY "MaleDefaultModel"
#define SFALL_CONFIG_DUDE_NATIVE_LOOK_JUMPSUIT_FEMALE_KEY "FemaleDefaultModel"
#define SFALL_CONFIG_DUDE_NATIVE_LOOK_TRIBAL_MALE_KEY "MaleStartModel"
#define SFALL_CONFIG_DUDE_NATIVE_LOOK_TRIBAL_FEMALE_KEY "FemaleStartModel"
#define SFALL_CONFIG_MAIN_MENU_BIG_FONT_COLOR_KEY "MainMenuBigFontColour"
#define SFALL_CONFIG_MAIN_MENU_FONT_COLOR_KEY "MainMenuFontColour"
#define SFALL_CONFIG_SKIP_OPENING_MOVIES_KEY "SkipOpeningMovies"
#define SFALL_CONFIG_STARTING_MAP_KEY "StartingMap"
#define SFALL_CONFIG_KARMA_FRMS_KEY "KarmaFRMs"
#define SFALL_CONFIG_KARMA_POINTS_KEY "KarmaPoints"
#define SFALL_CONFIG_DISPLAY_KARMA_CHANGES_KEY "DisplayKarmaChanges"
extern bool gSfallConfigInitialized;
extern Config gSfallConfig;

View File

@ -323,6 +323,7 @@ int critterGetStat(Object* critter, int stat)
}
break;
case STAT_DAMAGE_RESISTANCE:
case STAT_DAMAGE_RESISTANCE_EXPLOSION:
if (perkGetRank(critter, PERK_DERMAL_IMPACT_ARMOR)) {
value += 5;
} else if (perkGetRank(critter, PERK_DERMAL_IMPACT_ASSAULT_ENHANCEMENT)) {

View File

@ -125,9 +125,18 @@ int textFontLoad(int font)
goto out;
}
if (fileRead(textFontDescriptor, sizeof(TextFontDescriptor), 1, stream) != 1) {
goto out;
}
// NOTE: Original code reads entire descriptor in one go. This does not work
// in x64 because of the two pointers.
if (fileRead(&(textFontDescriptor->glyphCount), 4, 1, stream) != 1) goto out;
if (fileRead(&(textFontDescriptor->lineHeight), 4, 1, stream) != 1) goto out;
if (fileRead(&(textFontDescriptor->letterSpacing), 4, 1, stream) != 1) goto out;
int glyphsPtr;
if (fileRead(&glyphsPtr, 4, 1, stream) != 1) goto out;
int dataPtr;
if (fileRead(&dataPtr, 4, 1, stream) != 1) goto out;
textFontDescriptor->glyphs = (TextFontGlyph*)internal_malloc(textFontDescriptor->glyphCount * sizeof(TextFontGlyph));
if (textFontDescriptor->glyphs == NULL) {

View File

@ -387,9 +387,23 @@ int tileInit(TileData** a1, int squareGridWidth, int squareGridHeight, int hexGr
bufferDrawLine(_tile_grid_blocked, 32, v25, v20, v22, v20, _colorTable[31744]);
}
// In order to calculate scroll borders correctly we need to pretend we're
// at original resolution. Since border is calculated only once at start,
// there is not need to change it all the time.
gTileWindowWidth = ORIGINAL_ISO_WINDOW_WIDTH;
gTileWindowHeight = ORIGINAL_ISO_WINDOW_HEIGHT;
tileSetCenter(hexGridWidth * (hexGridHeight / 2) + hexGridWidth / 2, 2);
tileSetBorder(windowWidth, windowHeight, hexGridWidth, hexGridHeight);
// Restore actual window size and set center one more time to calculate
// correct screen offsets, which are required for subsequent object update
// area calculations.
gTileWindowWidth = windowWidth;
gTileWindowHeight = windowHeight;
tileSetCenter(hexGridWidth * (hexGridHeight / 2) + hexGridWidth / 2, 2);
char* executable;
configGetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_EXECUTABLE_KEY, &executable);
if (compat_stricmp(executable, "mapper") == 0) {

View File

@ -265,6 +265,8 @@ void windowManagerExit(void)
textFontsExit();
_colorsClose();
SDL_DestroyWindow(gSdlWindow);
gWindowSystemInitialized = false;
#ifdef _WIN32

View File

@ -617,7 +617,7 @@ bool xlistEnumerate(const char* pattern, XListEnumerationHandler* handler, XList
}
} while (fileFindNext(&directoryFileFindData));
}
return findFindClose(&directoryFileFindData);
findFindClose(&directoryFileFindData);
}
xbase = xbase->next;
}