Compare commits

..
93 changed files with 1530 additions and 13210 deletions
+6 -113
View File
@@ -25,9 +25,6 @@ if(MSVC)
endif()
option(FALLOUT_VENDORED "Use vendored third-party libraries" ON)
option(FALLOUT_AUDIO_OGG "Enable OGG decoding with stb_vorbis when available" ON)
set(FALLOUT_STB_VORBIS_DIR "" CACHE PATH "Directory containing stb_vorbis.c")
if(ANDROID)
add_library(${EXECUTABLE_NAME} SHARED)
@@ -38,9 +35,7 @@ endif()
# Git Info
include("cmake/gitver.cmake")
# Shared engine sources — used by both game and mapper targets.
# Excludes main.cc/main.h (game-only entry logic).
set(FALLOUT_ENGINE_SOURCES
target_sources(${EXECUTABLE_NAME} PUBLIC
"src/actions.cc"
"src/actions.h"
"src/animation.cc"
@@ -156,11 +151,15 @@ set(FALLOUT_ENGINE_SOURCES
"src/lips.h"
"src/loadsave.cc"
"src/loadsave.h"
"src/main.cc"
"src/main.h"
"src/mainmenu.cc"
"src/mainmenu.h"
"src/map_defs.h"
"src/map.cc"
"src/map.h"
"src/map_edge.cc"
"src/map_edge.h"
"src/memory_defs.h"
"src/memory_manager.cc"
"src/memory_manager.h"
@@ -183,8 +182,6 @@ set(FALLOUT_ENGINE_SOURCES
"src/obj_types.h"
"src/object.cc"
"src/object.h"
"src/ogg_decoder.cc"
"src/ogg_decoder.h"
"src/opcode_context.cc"
"src/opcode_context.h"
"src/options.cc"
@@ -268,7 +265,7 @@ set(FALLOUT_ENGINE_SOURCES
"src/xfile.h"
)
set(FALLOUT_PLATFORM_SOURCES
target_sources(${EXECUTABLE_NAME} PUBLIC
"src/audio_engine.cc"
"src/audio_engine.h"
"src/delay.cc"
@@ -302,8 +299,6 @@ set(FALLOUT_PLATFORM_SOURCES
"src/sfall_opcodes.cc"
"src/sfall_opcodes.h"
"src/sfall_script_hooks.cc"
"src/script_sound.cc"
"src/script_sound.h"
"src/sfall_arrays.cc"
"src/sfall_arrays.h"
"src/sfall_animation.cc"
@@ -316,43 +311,8 @@ set(FALLOUT_PLATFORM_SOURCES
"third_party/lodepng/lodepng.cpp"
)
target_sources(${EXECUTABLE_NAME} PUBLIC
${FALLOUT_ENGINE_SOURCES}
"src/main.cc"
"src/main.h"
)
target_sources(${EXECUTABLE_NAME} PUBLIC ${FALLOUT_PLATFORM_SOURCES})
target_include_directories(${EXECUTABLE_NAME} PUBLIC "third_party/lodepng")
set(FALLOUT_HAVE_STB_VORBIS OFF)
if(FALLOUT_AUDIO_OGG)
if(EXISTS "${CMAKE_SOURCE_DIR}/third_party/stb_vorbis/stb_vorbis.c")
set(_fallout_stb_vorbis_dir "${CMAKE_SOURCE_DIR}/third_party/stb_vorbis")
else()
set(_fallout_stb_vorbis_dir "${FALLOUT_STB_VORBIS_DIR}")
if(NOT _fallout_stb_vorbis_dir)
find_path(_fallout_stb_vorbis_dir
NAMES "stb_vorbis.c"
DOC "Directory containing stb_vorbis.c")
endif()
endif()
if(_fallout_stb_vorbis_dir AND EXISTS "${_fallout_stb_vorbis_dir}/stb_vorbis.c")
set(FALLOUT_HAVE_STB_VORBIS ON)
target_include_directories(${EXECUTABLE_NAME} PRIVATE "${_fallout_stb_vorbis_dir}")
else()
message(STATUS "OGG support disabled: stb_vorbis.c not found")
endif()
endif()
if(FALLOUT_HAVE_STB_VORBIS)
target_compile_definitions(${EXECUTABLE_NAME} PRIVATE HAVE_STB_VORBIS=1)
else()
target_compile_definitions(${EXECUTABLE_NAME} PRIVATE HAVE_STB_VORBIS=0)
endif()
if(IOS)
target_sources(${EXECUTABLE_NAME} PUBLIC
"src/platform/ios/paths.h"
@@ -569,73 +529,6 @@ if((NOT ANDROID) AND (NOT IOS) AND (NOT CMAKE_SYSTEM_NAME MATCHES "Emscripten"))
endif()
endif()
if((NOT ANDROID) AND (NOT IOS) AND (NOT CMAKE_SYSTEM_NAME MATCHES "Emscripten"))
if(WIN32)
add_executable(mapper-ce WIN32)
else()
add_executable(mapper-ce)
endif()
target_sources(mapper-ce PUBLIC
${FALLOUT_ENGINE_SOURCES}
${FALLOUT_PLATFORM_SOURCES}
"src/mapper/map_func.cc"
"src/mapper/map_func.h"
"src/mapper/mapper.cc"
"src/mapper/mapper.h"
"src/mapper/mp_instance.cc"
"src/mapper/mp_instance.h"
"src/mapper/mp_proto.cc"
"src/mapper/mp_proto.h"
"src/mapper/mp_scrpt.cc"
"src/mapper/mp_scrpt.h"
"src/mapper/mp_targt.cc"
"src/mapper/mp_targt.h"
"src/mapper/mp_text.cc"
"src/mapper/mp_text.h"
)
target_compile_definitions(mapper-ce PUBLIC FALLOUT_MAPPER)
if(WIN32)
target_compile_definitions(mapper-ce PUBLIC
_CRT_SECURE_NO_WARNINGS
_CRT_NONSTDC_NO_WARNINGS
NOMINMAX
WIN32_LEAN_AND_MEAN
_STATIC_CPPLIB
)
target_link_libraries(mapper-ce
winmm
debug libcpmtd
optimized libcpmt
)
target_sources(mapper-ce PUBLIC
"os/windows/fallout2-ce.rc"
)
endif()
if(APPLE)
target_link_libraries(mapper-ce "-framework CoreFoundation")
set_target_properties(mapper-ce PROPERTIES
XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED "NO"
XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "NO"
)
endif()
target_include_directories(mapper-ce PUBLIC "third_party/lodepng")
target_include_directories(mapper-ce PRIVATE "src")
target_include_directories(mapper-ce PRIVATE ${ZLIB_INCLUDE_DIRS})
target_include_directories(mapper-ce PRIVATE ${SDL2_INCLUDE_DIRS})
target_link_libraries(mapper-ce
fpattern::fpattern
fpattern_windows::fpattern_windows
${ZLIB_LIBRARIES}
${SDL2_LIBRARIES}
)
endif()
if(APPLE)
if(IOS)
install(TARGETS ${EXECUTABLE_NAME} DESTINATION "Payload")
+4 -4
View File
@@ -43,7 +43,7 @@ See [`https://sfall-team.github.io/sfall/`](https://sfall-team.github.io/sfall/)
| Combat / Knockback | set_weapon_knockback<br>set_target_knockback<br>set_attacker_knockback<br>remove_weapon_knockback<br>remove_target_knockback<br>remove_attacker_knockback | not implemented | - |
| Maps and encounters | in_world_map<br>force_encounter<br>force_encounter_with_flags<br>set_map_time_multi<br>get/set_map_enter_position<br>exec_map_update_scripts<br>get/set_terrain_name<br>set_town_title<br>get/set_can_rest_on_map<br>set_rest_heal_time<br>set_rest_mode<br>set_worldmap_heal_time | implemented: in_world_map, force_encounter, force_encounter_with_flags, set_map_time_multi | - |
| Maps and encounters / Worldmap | get_world_map_x/y_pos<br>set_world_map_pos | âś… | - |
| Audio | play_sfall_sound<br>stop_sfall_sound | âś… | `play_sfall_sound` currently supports `.acm`, `.wav`, `.ogg` formats, and can load from `.dat` archives. `.mp3` is not yet supported. |
| Audio | eax_available<br>set_eax_environment<br>play_sfall_sound<br>stop_sfall_sound | not implemented | *eax* opcodes will not be implemented |
| Combat / Weapons and ammo | get/set_weapon_ammo_pid<br>get/set_weapon_ammo_count | âś… | - |
| Sfall / Version | sfall_ver_major<br>sfall_ver_minor<br>sfall_ver_build | âś… | CE currently reports `4.3.4` |
| Utility / Math | log, exponent, round, sqrt, abs, sin, cos, tan, arctan, ceil, ^, floor2, div | âś… | - |
@@ -101,8 +101,8 @@ See [`https://sfall-team.github.io/sfall/`](https://sfall-team.github.io/sfall/)
| Steal | `HOOK_STEAL` | đźš« | Et tu |
| WithinPerception | `HOOK_WITHINPERCEPTION` | âś… | - |
| InventoryMove | `HOOK_INVENTORYMOVE` | âś… | - |
| InvenWield | `HOOK_INVENWIELD` | âś… | - |
| AdjustFID | `HOOK_ADJUSTFID` | âś… | Second hook arg currently matches the first because CE has no internal FID modifiers like Hero Appearance. |
| InvenWield | `HOOK_INVENWIELD` | đźš« | - |
| AdjustFID | `HOOK_ADJUSTFID` | đźš« | - |
| CombatTurn | `HOOK_COMBATTURN` | âś… | - |
| StdProcedure | `HOOK_STDPROCEDURE` | âś… | - |
| StdProcedureEnd | `HOOK_STDPROCEDURE_END` | âś… | - |
@@ -124,5 +124,5 @@ See [`https://sfall-team.github.io/sfall/`](https://sfall-team.github.io/sfall/)
| AdjustRads | `HOOK_ADJUSTRADS` | đźš« | (maybe) |
| RollCheck | `HOOK_ROLLCHECK` | đźš« | - |
| BestWeapon | `HOOK_BESTWEAPON` | đźš« | - |
| CanUseWeapon | `HOOK_CANUSEWEAPON` | âś… | - |
| CanUseWeapon | `HOOK_CANUSEWEAPON` | đźš« | - |
| BuildSfxWeapon | `HOOK_BUILDSFXWEAPON` | đźš« | - |
-6
View File
@@ -22,10 +22,6 @@ save_text_maps=0
show_pid_numbers=0
sort_script_list=0
use_art_not_protos=0
; Allows to load a certain map right away after loading the mapper.
map=denbus2
; Allows to disable grid item picker and use a simpler list-based picker.
use_grid_item_picker=1
[preferences]
brightness=1.000000
@@ -124,5 +120,3 @@ inventory_columns=2
auto_open_doors=0
; Overrides distance at which walk animation is used when using an object.
use_walk_distance=5
; Allow switching to companions' inventories in loot screens (and barter, in the future)
party_loot_and_barter=1
+3 -3
View File
@@ -4,7 +4,7 @@
#define ARRAY_MAX_STRING (1024)
#define ARRAY_MAX_STRING (255)
#define ARRAY_MAX_SIZE (100000)
procedure array_test_suite begin
@@ -82,8 +82,8 @@ procedure array_test_suite begin
call assertEquals("string_split", get_array(string_split("this+is+good", "+"), 2), "good");
call assertEquals("string_split 2", len_array(string_split("advice", "")), 6);
s := "";
for (i := 0; i < ARRAY_MAX_STRING+1; i+=100) begin
s += "Verbosity.Verbosity.Verbosity.Verbosity.Verbosity.Verbosity.Verbosity.Verbosity.Verbosity.Verbosity.";
for (i := 0; i < ARRAY_MAX_STRING+30; i+=10) begin
s += "Verbosity.";
end
arr[0] := s;
call assertEquals("array max string", strlen(arr[0]), ARRAY_MAX_STRING-1);
-78
View File
@@ -1,78 +0,0 @@
#include "sfall.h"
#include "dik.h"
variable loop_sound_id := 0;
variable quiet_loop_sound_id := 0;
variable music_sound_id := 0;
procedure stop_if_active(variable sound_id, variable label) begin
if (sound_id != 0) then begin
stop_sfall_sound(sound_id);
display_msg(label + " stopped");
end else begin
display_msg(label + " is not active");
end
end
procedure keypress_handler begin
variable pressed := get_sfall_arg_at(0);
variable key := get_sfall_arg_at(1);
variable ignored;
if (not pressed) then return;
if (key == DIK_K) then begin
display_msg("play_sfall_sound mode 0 one-shot: sound\\sfx\\pistol.ACM");
ignored := play_sfall_sound("sound\\sfx\\pistol.ACM", 0);
end else if (key == DIK_N) then begin
if (loop_sound_id != 0) then begin
display_msg(string_format1("loop already active id=%d", loop_sound_id));
return;
end
loop_sound_id := play_sfall_sound("sound\\music\\20CAR.ACM", 1);
display_msg(string_format1("mode 1 loop id=%d", loop_sound_id));
end else if (key == DIK_M) then begin
call stop_if_active(loop_sound_id, "mode 1 loop");
loop_sound_id := 0;
end else if (key == DIK_C) then begin
if (quiet_loop_sound_id != 0) then begin
display_msg(string_format1("quiet loop already active id=%d", quiet_loop_sound_id));
return;
end
quiet_loop_sound_id := play_sfall_sound("sound\\music\\20CAR.ACM", 0x30000001);
display_msg(string_format1("quiet mode 1 loop id=%d", quiet_loop_sound_id));
end else if (key == DIK_X) then begin
call stop_if_active(quiet_loop_sound_id, "quiet mode 1 loop");
quiet_loop_sound_id := 0;
end else if (key == DIK_G) then begin
if (music_sound_id != 0) then begin
display_msg(string_format1("mode 2 music replacement already active id=%d", music_sound_id));
return;
end
music_sound_id := play_sfall_sound("sound\\music\\20CAR.ACM", 2);
display_msg(string_format1("mode 2 music replacement id=%d", music_sound_id));
end else if (key == DIK_H) then begin
call stop_if_active(music_sound_id, "mode 2 music replacement");
music_sound_id := 0;
end else if (key == DIK_V) then begin
display_msg("play_sfall_sound mode 3 speech-volume one-shot: sound\\sfx\\pistol.ACM");
ignored := play_sfall_sound("sound\\sfx\\pistol.ACM", 3);
end else if (key == DIK_B) then begin
display_msg("play_sfall_sound mode 0 one-shot wav: smw_1-up.wav"); // needs a wav file in the game dir
ignored := play_sfall_sound("smw_1-up.wav", 0);
end
end
procedure start begin
if (not game_loaded) then return;
display_msg("sfall_sound manual test ready");
display_msg("One-shots use master.dat SFX and loose-file wav; loops/replacement use music");
display_msg("K one-shot ACM mode0, B one-shot WAV mode0, N start loop mode1, M stop loop");
display_msg("C start quiet loop mode1, X stop quiet loop");
display_msg("G start mode2 music replacement, H stop mode2 replacement, V mode3 one-shot");
register_hook_proc(HOOK_KEYPRESS, keypress_handler);
end
+1 -89
View File
@@ -355,14 +355,6 @@ int artIsObjectTypeHidden(int objectType)
return objectType >= OBJ_TYPE_ITEM && objectType < OBJ_TYPE_COUNT ? gArtListDescriptions[objectType].flags & 1 : 0;
}
// 0x409DF0
void artToggleObjectTypeHidden(int objectType)
{
if (objectType >= 0 && objectType < OBJ_TYPE_COUNT) {
gArtListDescriptions[objectType].flags ^= 1;
}
}
// 0x418F7C
int artGetFidgetCount(int headFid)
{
@@ -447,87 +439,7 @@ void artRender(int fid, unsigned char* dest, int width, int height, int pitch)
// mapper2.exe: 0x40A03C
int art_list_str(int fid, char* name)
{
if (fid == -1 || name == nullptr) {
return -1;
}
int objectType = (fid & 0xF000000) >> 24;
int index = fid & 0xFFF;
const char* typeName = artGetObjectTypeName(objectType);
if (typeName == nullptr) {
return -1;
}
char path[260];
snprintf(path, sizeof(path), "%s%s%s\\%s.lst", _cd_path_base, "art\\", typeName, typeName);
File* stream = fileOpen(path, "rt");
if (stream == nullptr) {
return -1;
}
char buffer[260];
int line = 0;
bool found = false;
while (fileReadString(buffer, sizeof(buffer), stream) != nullptr) {
if (line == index) {
char* p = buffer;
while (*p) {
if (*p == ' ' || *p == '\n') {
*p = '\0';
break;
}
p++;
}
char* dst = name;
const char* src = buffer;
do {
*dst++ = *src++;
*dst++ = *src++;
} while (dst[-2] != '\0' || dst[-1] != '\0');
found = true;
break;
}
line++;
}
fileClose(stream);
return found ? 0 : -1;
}
// art_list_index
int artListIndex(int objectType, const char* name)
{
if (objectType < 0 || objectType >= OBJ_TYPE_COUNT) return -1;
if (gArtListDescriptions[objectType].fileNames == nullptr) return -1;
char upperName[13] = { 0 };
strncpy(upperName, name, 12);
upperName[12] = '\0';
compat_strupr(upperName);
int length = gArtListDescriptions[objectType].fileNamesLength;
const char* fileNames = gArtListDescriptions[objectType].fileNames;
for (int index = 0; index < length; index++) {
const char* entry = fileNames + index * 13;
char upperEntry[13];
strncpy(upperEntry, entry, 12);
upperEntry[12] = '\0';
compat_strupr(upperEntry);
char* p = upperEntry;
while (*p && ((*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9') || *p == '_'))
p++;
*p = '\0';
if (strcmp(upperEntry, upperName) == 0) {
return index;
}
}
// TODO: Incomplete.
return -1;
}
-2
View File
@@ -122,7 +122,6 @@ void artReset();
void artExit();
char* artGetObjectTypeName(int objectType);
int artIsObjectTypeHidden(int objectType);
void artToggleObjectTypeHidden(int objectType);
int artGetFidgetCount(int headFid);
void artRender(int fid, unsigned char* dest, int width, int height, int pitch);
int art_list_str(int fid, char* name);
@@ -151,7 +150,6 @@ int _art_alias_num(int index);
int artCritterFidShouldRun(int fid);
int artAliasFid(int fid);
int buildFid(int objectType, int frmId, int animType, int weaponCode, int rotation);
int artListIndex(int objectType, const char* name);
Art* artLoad(const char* path);
int artRead(const char* path, unsigned char* data);
int artWrite(const char* path, unsigned char* data);
+11 -211
View File
@@ -4,13 +4,9 @@
#include <stdio.h>
#include <string.h>
#include <SDL.h>
#include "db.h"
#include "debug.h"
#include "memory_manager.h"
#include "ogg_decoder.h"
#include "platform_compat.h"
#include "sound.h"
#include "sound_decoder.h"
@@ -19,33 +15,20 @@ namespace fallout {
typedef enum AudioFlags {
AUDIO_IN_USE = 0x01,
AUDIO_COMPRESSED = 0x02,
// CE: Decoded formats like WAV/OGG are fully loaded into memory up front.
AUDIO_MEMORY = 0x04,
} AudioFileFlags;
typedef struct Audio {
int flags;
File* stream;
SoundDecoder* soundDecoder;
unsigned char* data;
int fileSize;
int sampleRate;
int channels;
int bitsPerSample;
int position;
} Audio;
typedef enum AudioOpenMode {
AUDIO_OPEN_MODE_RAW = 0,
AUDIO_OPEN_MODE_COMPRESSED = 1, // ACM
AUDIO_OPEN_MODE_WAV = 2,
AUDIO_OPEN_MODE_OGG = 3,
} AudioOpenMode;
static bool defaultCompressionFunc(char* filePath);
static int audioSoundDecoderReadHandler(void* data, void* buf, unsigned int size);
static bool audioIsWavePath(const char* filePath);
static bool audioDecodeWave(File* stream, AudioFileInfo* info, unsigned char** dataPtr, int* sizePtr);
// 0x5108BC
static AudioQueryCompressedFunc* queryCompressedFunc = defaultCompressionFunc;
@@ -73,128 +56,18 @@ static int audioSoundDecoderReadHandler(void* data, void* buffer, unsigned int s
return fileRead(buffer, 1, size, reinterpret_cast<File*>(data));
}
static bool audioIsWavePath(const char* filePath)
{
const char* dot = strrchr(filePath, '.');
return dot != nullptr && compat_stricmp(dot + 1, "wav") == 0;
}
static bool audioDecodeWave(File* stream, AudioFileInfo* info, unsigned char** dataPtr, int* sizePtr)
{
bool success = false;
unsigned char* fileData = nullptr;
Uint8* loadedData = nullptr;
Uint8* convertedData = nullptr;
SDL_RWops* rw = nullptr;
SDL_AudioSpec spec = {};
Uint32 loadedLength = 0;
int channels = 0;
SDL_AudioCVT cvt;
memset(&cvt, 0, sizeof(cvt));
int convertedLength = 0;
bool convertedDataNeedsFree = false;
bool loadedDataNeedsFree = false;
int fileSize = fileGetSize(stream);
if (fileSize <= 0) {
return false;
}
fileData = reinterpret_cast<unsigned char*>(internal_malloc_safe(fileSize, __FILE__, __LINE__));
if (fileRead(fileData, 1, fileSize, stream) != fileSize) {
goto done;
}
rw = SDL_RWFromConstMem(fileData, fileSize);
if (rw == nullptr) {
goto done;
}
if (SDL_LoadWAV_RW(rw, 1, &spec, &loadedData, &loadedLength) == nullptr) {
rw = nullptr;
goto done;
}
rw = nullptr;
loadedDataNeedsFree = true;
channels = spec.channels == 1 ? 1 : 2;
if (SDL_BuildAudioCVT(&cvt, spec.format, spec.channels, spec.freq, AUDIO_S16SYS, channels, spec.freq) < 0) {
goto done;
}
convertedLength = static_cast<int>(loadedLength);
if (cvt.needed != 0) {
cvt.len = static_cast<int>(loadedLength);
cvt.buf = reinterpret_cast<Uint8*>(SDL_malloc(cvt.len * cvt.len_mult));
if (cvt.buf == nullptr) {
goto done;
}
memcpy(cvt.buf, loadedData, loadedLength);
if (SDL_ConvertAudio(&cvt) != 0) {
SDL_free(cvt.buf);
goto done;
}
convertedData = cvt.buf;
convertedLength = cvt.len_cvt;
convertedDataNeedsFree = true;
} else {
convertedData = loadedData;
}
if (info != nullptr) {
info->channels = channels;
info->sampleRate = spec.freq;
info->bitsPerSample = 16;
}
if (dataPtr != nullptr && sizePtr != nullptr) {
*dataPtr = reinterpret_cast<unsigned char*>(internal_malloc_safe(convertedLength, __FILE__, __LINE__));
memcpy(*dataPtr, convertedData, convertedLength);
*sizePtr = convertedLength;
}
success = true;
done:
if (rw != nullptr) {
SDL_RWclose(rw);
}
if (convertedData != nullptr) {
if (convertedDataNeedsFree) {
SDL_free(convertedData);
}
}
if (loadedDataNeedsFree && loadedData != nullptr) {
SDL_FreeWAV(loadedData);
}
if (fileData != nullptr) {
internal_free_safe(fileData, __FILE__, __LINE__);
}
return success;
}
// AudioOpen
// 0x41A2EC
int audioOpen(const char* fname, AudioFileInfo* info, bool* isMemoryBackedPtr)
int audioOpen(const char* fname, int* sampleRate)
{
char path[COMPAT_MAX_PATH];
char path[80];
snprintf(path, sizeof(path), "%s", fname);
AudioOpenMode openMode;
if (audioIsWavePath(path)) {
openMode = AUDIO_OPEN_MODE_WAV;
} else if (oggDecoderIsFilePath(path)) {
openMode = AUDIO_OPEN_MODE_OGG;
} else if (queryCompressedFunc(path)) {
openMode = AUDIO_OPEN_MODE_COMPRESSED;
int compression;
if (queryCompressedFunc(path)) {
compression = 2;
} else {
openMode = AUDIO_OPEN_MODE_RAW;
compression = 0;
}
File* stream = fileOpen(path, "rb");
@@ -220,64 +93,17 @@ int audioOpen(const char* fname, AudioFileInfo* info, bool* isMemoryBackedPtr)
}
Audio* audioFile = &(gAudioList[index]);
memset(audioFile, 0, sizeof(*audioFile));
audioFile->flags = AUDIO_IN_USE;
audioFile->stream = stream;
if (openMode == AUDIO_OPEN_MODE_WAV || openMode == AUDIO_OPEN_MODE_OGG) {
AudioFileInfo decodedInfo = {};
audioFile->flags |= AUDIO_MEMORY;
bool decoded = false;
if (openMode == AUDIO_OPEN_MODE_WAV) {
decoded = audioDecodeWave(stream, &decodedInfo, &(audioFile->data), &(audioFile->fileSize));
} else {
AudioFileInfo audioFileInfo = {};
decoded = oggDecoderDecode(stream, &audioFileInfo, &(audioFile->data), &(audioFile->fileSize));
decodedInfo.sampleRate = audioFileInfo.sampleRate;
decodedInfo.channels = audioFileInfo.channels;
decodedInfo.bitsPerSample = audioFileInfo.bitsPerSample;
}
if (!decoded) {
fileClose(stream);
memset(audioFile, 0, sizeof(*audioFile));
debugPrint("AudioOpen: Couldn't decode %s\n", path);
return -1;
}
fileClose(stream);
audioFile->stream = nullptr;
audioFile->sampleRate = decodedInfo.sampleRate;
audioFile->channels = decodedInfo.channels;
audioFile->bitsPerSample = decodedInfo.bitsPerSample;
if (info != nullptr) {
*info = decodedInfo;
}
if (isMemoryBackedPtr != nullptr) {
*isMemoryBackedPtr = true;
}
} else if (openMode == AUDIO_OPEN_MODE_COMPRESSED) {
if (compression == 2) {
audioFile->flags |= AUDIO_COMPRESSED;
audioFile->soundDecoder = soundDecoderInit(audioSoundDecoderReadHandler, audioFile->stream, &(audioFile->channels), &(audioFile->sampleRate), &(audioFile->fileSize));
audioFile->fileSize *= 2;
audioFile->bitsPerSample = 16;
if (info != nullptr) {
info->sampleRate = audioFile->sampleRate;
info->bitsPerSample = audioFile->bitsPerSample;
}
if (isMemoryBackedPtr != nullptr) {
*isMemoryBackedPtr = false;
}
*sampleRate = audioFile->sampleRate;
} else {
audioFile->fileSize = fileGetSize(stream);
audioFile->bitsPerSample = 8;
if (info != nullptr) {
info->bitsPerSample = audioFile->bitsPerSample;
}
if (isMemoryBackedPtr != nullptr) {
*isMemoryBackedPtr = false;
}
}
audioFile->position = 0;
@@ -289,13 +115,7 @@ int audioOpen(const char* fname, AudioFileInfo* info, bool* isMemoryBackedPtr)
int audioClose(int handle)
{
Audio* audioFile = &(gAudioList[handle - 1]);
if ((audioFile->flags & AUDIO_MEMORY) != 0) {
if (audioFile->data != nullptr) {
internal_free_safe(audioFile->data, __FILE__, __LINE__);
}
} else if (audioFile->stream != nullptr) {
fileClose(audioFile->stream);
}
fileClose(audioFile->stream);
if ((audioFile->flags & AUDIO_COMPRESSED) != 0) {
soundDecoderFree(audioFile->soundDecoder);
@@ -312,16 +132,7 @@ int audioRead(int handle, void* buffer, unsigned int size)
Audio* audioFile = &(gAudioList[handle - 1]);
int bytesRead;
if ((audioFile->flags & AUDIO_MEMORY) != 0) {
bytesRead = audioFile->fileSize - audioFile->position;
if (bytesRead > static_cast<int>(size)) {
bytesRead = size;
}
if (bytesRead > 0) {
memcpy(buffer, audioFile->data + audioFile->position, bytesRead);
}
} else if ((audioFile->flags & AUDIO_COMPRESSED) != 0) {
if ((audioFile->flags & AUDIO_COMPRESSED) != 0) {
bytesRead = soundDecoderDecode(audioFile->soundDecoder, buffer, size);
} else {
bytesRead = fileRead(buffer, 1, size, audioFile->stream);
@@ -355,18 +166,7 @@ long audioSeek(int handle, long offset, int origin)
assert(false && "Should be unreachable");
}
if ((audioFile->flags & AUDIO_MEMORY) != 0) {
if (pos < 0) {
pos = 0;
}
if (pos > audioFile->fileSize) {
pos = audioFile->fileSize;
}
audioFile->position = pos;
return audioFile->position;
} else if ((audioFile->flags & AUDIO_COMPRESSED) != 0) {
if ((audioFile->flags & AUDIO_COMPRESSED) != 0) {
if (pos < audioFile->position) {
soundDecoderFree(audioFile->soundDecoder);
fileSeek(audioFile->stream, 0, SEEK_SET);
+1 -3
View File
@@ -1,13 +1,11 @@
#ifndef AUDIO_H
#define AUDIO_H
#include "sound.h"
namespace fallout {
typedef bool(AudioQueryCompressedFunc)(char* filePath);
int audioOpen(const char* fname, AudioFileInfo* info, bool* isMemoryBackedPtr);
int audioOpen(const char* fname, int* sampleRate);
int audioClose(int handle);
int audioRead(int handle, void* buffer, unsigned int size);
long audioSeek(int handle, long offset, int origin);
+3 -14
View File
@@ -57,7 +57,7 @@ static int audioFileSoundDecoderReadHandler(void* data, void* buffer, unsigned i
}
// 0x41A88C
int audioFileOpen(const char* fname, AudioFileInfo* info, bool* isMemoryBackedPtr)
int audioFileOpen(const char* fname, int* sampleRate)
{
char path[COMPAT_MAX_PATH];
strcpy(path, fname);
@@ -98,21 +98,10 @@ int audioFileOpen(const char* fname, AudioFileInfo* info, bool* isMemoryBackedPt
audioFile->flags |= AUDIO_FILE_COMPRESSED;
audioFile->soundDecoder = soundDecoderInit(audioFileSoundDecoderReadHandler, audioFile->stream, &(audioFile->channels), &(audioFile->sampleRate), &(audioFile->fileSize));
audioFile->fileSize *= 2;
if (info != nullptr) {
info->sampleRate = audioFile->sampleRate;
info->bitsPerSample = 16;
}
if (isMemoryBackedPtr != nullptr) {
*isMemoryBackedPtr = false;
}
*sampleRate = audioFile->sampleRate;
} else {
audioFile->fileSize = getFileSize(stream);
if (info != nullptr) {
info->bitsPerSample = 8;
}
if (isMemoryBackedPtr != nullptr) {
*isMemoryBackedPtr = false;
}
}
audioFile->position = 0;
+1 -3
View File
@@ -1,13 +1,11 @@
#ifndef AUDIO_FILE_H
#define AUDIO_FILE_H
#include "sound.h"
namespace fallout {
typedef bool(AudioFileQueryCompressedFunc)(char* filePath);
int audioFileOpen(const char* fname, AudioFileInfo* info, bool* isMemoryBackedPtr);
int audioFileOpen(const char* fname, int* sampleRate);
int audioFileClose(int handle);
int audioFileRead(int handle, void* buf, unsigned int size);
long audioFileSeek(int handle, long offset, int origin);
+14 -24
View File
@@ -1972,41 +1972,31 @@ static Object* _ai_best_weapon(Object* attacker, Object* weapon1, Object* weapon
// 0x4298EC
static bool _ai_can_use_weapon(Object* critter, Object* weapon, int hitMode)
{
bool result = true;
int damageFlags = critter->data.critter.combat.results;
if ((damageFlags & DAM_CRIP_ARM_LEFT) != 0 && (damageFlags & DAM_CRIP_ARM_RIGHT) != 0) {
result = false;
return false;
}
if (result && (damageFlags & DAM_CRIP_ARM_ANY) != 0 && weaponIsTwoHanded(weapon)) {
result = false;
if ((damageFlags & DAM_CRIP_ARM_ANY) != 0 && weaponIsTwoHanded(weapon)) {
return false;
}
if (result) {
int rotation = critter->rotation + 1;
int animationCode = weaponGetAnimationCode(weapon);
int weaponAnimationCode = weaponGetAnimationForHitMode(weapon, hitMode);
int fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, weaponAnimationCode, animationCode, rotation);
if (!artExists(fid)) {
result = false;
}
int rotation = critter->rotation + 1;
int animationCode = weaponGetAnimationCode(weapon);
int weaponAnimationCode = weaponGetAnimationForHitMode(weapon, hitMode);
int fid = buildFid(OBJ_TYPE_CRITTER, critter->fid & 0xFFF, weaponAnimationCode, animationCode, rotation);
if (!artExists(fid)) {
return false;
}
int skill = weaponGetSkillForHitMode(weapon, hitMode);
AiPacket* ai = aiGetPacket(critter);
if (result) {
int skill = weaponGetSkillForHitMode(weapon, hitMode);
if (skillGetValue(critter, skill) < ai->min_to_hit) {
result = false;
}
if (skillGetValue(critter, skill) < ai->min_to_hit) {
return false;
}
if (result) {
int attackType = weaponGetAttackTypeForHitMode(weapon, HIT_MODE_RIGHT_WEAPON_PRIMARY);
result = _caiHasWeapPrefType(ai, attackType) != 0;
}
return scriptHooks_CanUseWeapon(result, critter, weapon, hitMode);
int attackType = weaponGetAttackTypeForHitMode(weapon, HIT_MODE_RIGHT_WEAPON_PRIMARY);
return _caiHasWeapPrefType(ai, attackType) != 0;
}
// 0x4299A0
-48
View File
@@ -29,82 +29,34 @@ long fileTell(File* stream);
void fileRewind(File* stream);
int fileEof(File* stream);
int fileReadUInt8(File* stream, unsigned char* valuePtr);
// Reads a 16-bit big-endian integer from stream and stores it in host byte order.
int fileReadInt16(File* stream, short* valuePtr);
// Reads a 16-bit big-endian unsigned integer from stream and stores it in host byte order.
int fileReadUInt16(File* stream, unsigned short* valuePtr);
// Reads a 32-bit big-endian integer from stream and stores it in host byte order.
int fileReadInt32(File* stream, int* valuePtr);
// Reads a 32-bit big-endian unsigned integer from stream and stores it in host byte order.
int fileReadUInt32(File* stream, unsigned int* valuePtr);
// Reads a 32-bit big-endian integer from stream and stores it in host byte order (alias).
int _db_freadInt(File* stream, int* valuePtr);
// Reads a 32-bit big-endian floating-point value from stream and stores it in host byte order.
int fileReadFloat(File* stream, float* valuePtr);
// Reads a 32-bit big-endian integer from stream and stores the boolean equivalent in host byte order.
int fileReadBool(File* stream, bool* valuePtr);
int fileWriteUInt8(File* stream, unsigned char value);
// Writes a 16-bit integer to stream in big-endian byte order.
int fileWriteInt16(File* stream, short value);
// Writes a 16-bit unsigned integer to stream in big-endian byte order.
int fileWriteUInt16(File* stream, unsigned short value);
// Writes a 32-bit integer to stream in big-endian byte order.
int fileWriteInt32(File* stream, int value);
// Writes a 32-bit integer to stream in big-endian byte order (alias).
int _db_fwriteLong(File* stream, int value);
// Writes a 32-bit unsigned integer to stream in big-endian byte order.
int fileWriteUInt32(File* stream, unsigned int value);
// Writes a 32-bit floating-point value to stream in big-endian byte order.
int fileWriteFloat(File* stream, float value);
// Writes a boolean value to stream as a 32-bit big-endian integer (1 or 0).
int fileWriteBool(File* stream, bool value);
int fileReadUInt8List(File* stream, unsigned char* arr, int count);
int fileReadFixedLengthString(File* stream, char* string, int length);
// Reads a list of 16-bit big-endian integers from stream into arr (in host byte order).
int fileReadInt16List(File* stream, short* arr, int count);
// Reads a list of 16-bit big-endian unsigned integers from stream into arr (in host byte order).
int fileReadUInt16List(File* stream, unsigned short* arr, int count);
// Reads a list of 32-bit big-endian integers from stream into arr (in host byte order).
int fileReadInt32List(File* stream, int* arr, int count);
// Reads a list of 32-bit big-endian integers from stream into arr (in host byte order, alias).
int _db_freadIntCount(File* stream, int* arr, int count);
// Reads a list of 32-bit big-endian unsigned integers from stream into arr (in host byte order).
int fileReadUInt32List(File* stream, unsigned int* arr, int count);
int fileWriteUInt8List(File* stream, unsigned char* arr, int count);
int fileWriteFixedLengthString(File* stream, char* string, int length);
// Writes a list of 16-bit integers to stream in big-endian byte order.
int fileWriteInt16List(File* stream, short* arr, int count);
// Writes a list of 16-bit unsigned integers to stream in big-endian byte order.
int fileWriteUInt16List(File* stream, unsigned short* arr, int count);
// Writes a list of 32-bit integers to stream in big-endian byte order.
int fileWriteInt32List(File* stream, int* arr, int count);
// Writes a list of 32-bit integers to stream in big-endian byte order (alias).
int _db_fwriteLongCount(File* stream, int* arr, int count);
// Writes a list of 32-bit unsigned integers to stream in big-endian byte order.
int fileWriteUInt32List(File* stream, unsigned int* arr, int count);
int fileNameListInit(const char* pattern, char*** fileNames);
void fileNameListFree(char*** fileNames, int unused);
+16 -51
View File
@@ -1,11 +1,11 @@
#include "debug.h"
#include <SDL.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <SDL.h>
#include "memory.h"
#include "platform_compat.h"
@@ -15,18 +15,11 @@ namespace fallout {
static int _debug_puts(char* string);
static void _debug_clear();
static int _debug_mono(const char* string);
static int _debug_log(const char* string);
static int _debug_screen(const char* string);
static int _debug_mono(char* string);
static int _debug_log(char* string);
static int _debug_screen(char* string);
static void _debug_putc(int ch);
static void _debug_scroll();
static void debugFlushBuffer();
// Messages logged before any debug proc is registered are held here and
// flushed when the first proc is registered.
static std::string debugBuffer;
static constexpr size_t kDebugBufferMaxSize = 64 * 1024;
static bool debugBufferDisabled = false;
// 0x51DEF8
static FILE* _fd = nullptr;
@@ -42,12 +35,6 @@ static DebugPrintProc* gDebugPrintProc = nullptr;
void debugModeInit(const char* debugMode)
{
debugBufferDisabled = true;
if (debugMode == nullptr) {
return;
}
// CE: Handle debug mode (exactly as seen in `mapper2.exe`).
if (compat_stricmp(debugMode, "environment") == 0) {
_debug_register_env();
@@ -60,10 +47,6 @@ void debugModeInit(const char* debugMode)
} else if (compat_stricmp(debugMode, "gnw") == 0) {
_debug_register_func(_win_debug);
}
if (gDebugPrintProc == nullptr) {
debugBuffer.clear();
}
}
// 0x4C6CD0
@@ -83,7 +66,6 @@ void _debug_register_mono()
gDebugPrintProc = _debug_mono;
_debug_clear();
debugFlushBuffer();
}
}
@@ -97,7 +79,6 @@ void _debug_register_log(const char* fileName, const char* mode)
_fd = compat_fopen(fileName, mode);
gDebugPrintProc = _debug_log;
debugFlushBuffer();
}
}
@@ -111,7 +92,6 @@ void _debug_register_screen()
}
gDebugPrintProc = _debug_screen;
debugFlushBuffer();
}
}
@@ -157,7 +137,6 @@ void _debug_register_func(DebugPrintProc* proc)
}
gDebugPrintProc = proc;
debugFlushBuffer();
}
}
@@ -167,39 +146,25 @@ int debugPrint(const char* format, ...)
va_list args;
va_start(args, format);
char string[260];
int len = vsnprintf(string, sizeof(string), format, args);
if (len < 0) {
string[0] = '\0';
}
va_end(args);
int rc;
if (gDebugPrintProc != nullptr) {
char string[260];
vsnprintf(string, sizeof(string), format, args);
rc = gDebugPrintProc(string);
} else {
if (!debugBufferDisabled && debugBuffer.size() + strlen(string) <= kDebugBufferMaxSize) {
debugBuffer += string;
}
#ifndef NDEBUG
SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, format, args);
#endif
rc = -1;
}
#ifndef NDEBUG
SDL_Log("%s", string);
#endif
va_end(args);
return rc;
}
static void debugFlushBuffer()
{
if (debugBuffer.empty() || gDebugPrintProc == nullptr) {
return;
}
gDebugPrintProc(debugBuffer.c_str());
debugBuffer.clear();
}
// 0x4C6F94
static int _debug_puts(char* string)
{
@@ -238,7 +203,7 @@ static void _debug_clear()
}
// 0x4C7004
static int _debug_mono(const char* string)
static int _debug_mono(char* string)
{
if (gDebugPrintProc == _debug_mono) {
while (*string != '\0') {
@@ -250,7 +215,7 @@ static int _debug_mono(const char* string)
}
// 0x4C7028
static int _debug_log(const char* string)
static int _debug_log(char* string)
{
if (gDebugPrintProc == _debug_log) {
if (_fd == nullptr) {
@@ -270,7 +235,7 @@ static int _debug_log(const char* string)
}
// 0x4C7068
static int _debug_screen(const char* string)
static int _debug_screen(char* string)
{
if (gDebugPrintProc == _debug_screen) {
printf("%s", string);
+1 -1
View File
@@ -3,7 +3,7 @@
namespace fallout {
typedef int(DebugPrintProc)(const char* string);
typedef int(DebugPrintProc)(char* string);
void debugModeInit(const char* debugMode);
void _GNW_debug_init();
+1 -1
View File
@@ -14,7 +14,7 @@
namespace fallout {
// The size of decompression buffer for reading compressed [DFile]s.
#define DFILE_DECOMPRESSION_BUFFER_SIZE (0x1000)
#define DFILE_DECOMPRESSION_BUFFER_SIZE (0x400)
// Specifies that [DFile] has unget character.
//
+2 -3
View File
@@ -86,6 +86,7 @@ namespace fallout {
#define SPLASH_HEIGHT (480)
#define SPLASH_COUNT (10)
static int gameLoadGlobalVars();
static int gameTakeScreenshot(int width, int height, unsigned char* buffer, unsigned char* palette);
static void gameFreeGlobalVars();
static bool tryLoadBaseCEModAtPath(const char* path, bool* found, bool* openFailed);
@@ -151,8 +152,6 @@ int gameInitWithOptions(const char* windowTitle, bool isMapper, int font, int fl
settingsInit(isMapper, argc, argv);
debugModeInit(settings.debug.mode.c_str());
gIsMapper = isMapper;
if (gameDbInit() == -1) {
@@ -1015,7 +1014,7 @@ int gameSetGlobalVar(int var, int value)
// game_load_info
// 0x443CC8
int gameLoadGlobalVars()
static int gameLoadGlobalVars()
{
if (globalVarsRead("data\\vault13.gam", "GAME_GLOBAL_VARS:", &gGameGlobalVarsLength, &gGameGlobalVars) != 0) {
return -1;
-1
View File
@@ -47,7 +47,6 @@ int gameRequestState(int newGameState);
void gameUpdateState();
int showQuitConfirmationDialog();
int gameLoadGlobalVars();
int gameShowDeathDialog(const char* message);
void gameHandleSkilldexResult(int rc);
void* gameGetGlobalPointer(int var);
+5
View File
@@ -119,6 +119,11 @@ bool gameConfigInit(bool isMapper, int argc, char** argv)
configRead(&gGameConfig, gGameConfigFilePath, false);
// Init debug mode ASAP to catch early debug messages.
char* debugMode;
configGetString(&gGameConfig, GAME_CONFIG_DEBUG_KEY, GAME_CONFIG_MODE_KEY, &debugMode);
debugModeInit(debugMode);
debugPrint("Game config loaded from %s.\n", gGameConfigFilePath);
if (!isMapper && gameConfigMigrateFromF2Res(gGameConfigFilePath, &gGameConfig)) {
+2 -23
View File
@@ -313,6 +313,7 @@ Object* gGameMouseHexCursor;
// 0x596C74
static Object* gGameMousePointedObject;
static int _gmouse_get_click_to_scroll();
static void _gmouse_3d_enable_modes();
static int gameMouseSetBouncingCursorFid(int fid);
static int gameMouseRenderAccuracy(const char* string, int color);
@@ -454,15 +455,6 @@ int _gmouse_get_click_to_scroll()
return _gmouse_click_to_scroll;
}
// gmouse_set_click_to_scroll
void _gmouse_set_click_to_scroll(int value)
{
if (value != _gmouse_click_to_scroll) {
_gmouse_click_to_scroll = value;
_gmouse_clicked_on_edge = false;
}
}
// 0x44B54C
int _gmouse_is_scrolling()
{
@@ -2287,7 +2279,7 @@ int _gmouse_3d_move_to(int x, int y, int elevation, Rect* rect)
int fid = gGameMouseBouncingCursor->fid;
if (FID_TYPE(fid) == OBJ_TYPE_TILE) {
int squareTile = squareTileFromScreenXY(x, y, elevation);
if (squareTile != -1) {
if (squareTile == -1) {
tile = HEX_GRID_WIDTH * (2 * (squareTile / SQUARE_GRID_WIDTH) + 1) + 2 * (squareTile % SQUARE_GRID_WIDTH) + 1;
x1 = -8;
y1 = 13;
@@ -2391,19 +2383,6 @@ int gameMouseHandleScrolling(int x, int y, int cursor)
flags |= SCROLLABLE_S;
}
// Click-to-scroll mode (mapper Alt-Z): only scroll while the left button is held at an
// edge. Track this in _gmouse_clicked_on_edge so callers can react (e.g. suppress the
// regular 3D cursor update while an edge-click scroll is active).
// TODO: reconcile with other site where _gmouse_clicked_on_edge is set to true
if (_gmouse_click_to_scroll) {
bool atEdge = flags != 0;
bool leftHeld = (mouseGetEvent() & MOUSE_EVENT_LEFT_BUTTON_REPEAT) != 0;
_gmouse_clicked_on_edge = atEdge && leftHeld;
if (!_gmouse_clicked_on_edge) {
return -1;
}
}
int dx = 0;
int dy = 0;

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