diff --git a/src/audio.cc b/src/audio.cc index ee71201..77000c6 100644 --- a/src/audio.cc +++ b/src/audio.cc @@ -58,7 +58,7 @@ static int audioSoundDecoderReadHandler(void* data, void* buffer, unsigned int s // AudioOpen // 0x41A2EC -int audioOpen(const char* fname, int flags) +int audioOpen(const char* fname, int* channels, int* sampleRate) { char path[80]; snprintf(path, sizeof(path), "%s", fname); @@ -70,28 +70,7 @@ int audioOpen(const char* fname, int flags) compression = 0; } - char mode[4]; - memset(mode, 0, 4); - - // NOTE: Original implementation is slightly different, it uses separate - // variable to track index where to set 't' and 'b'. - char* pm = mode; - if (flags & 1) { - *pm++ = 'w'; - } else if (flags & 2) { - *pm++ = 'w'; - *pm++ = '+'; - } else { - *pm++ = 'r'; - } - - if (flags & 0x100) { - *pm++ = 't'; - } else if (flags & 0x200) { - *pm++ = 'b'; - } - - File* stream = fileOpen(path, mode); + File* stream = fileOpen(path, "rb"); if (stream == NULL) { debugPrint("AudioOpen: Couldn't open %s for read\n", path); return -1; @@ -121,6 +100,9 @@ int audioOpen(const char* fname, int flags) audioFile->flags |= AUDIO_COMPRESSED; audioFile->soundDecoder = soundDecoderInit(audioSoundDecoderReadHandler, audioFile->stream, &(audioFile->channels), &(audioFile->sampleRate), &(audioFile->fileSize)); audioFile->fileSize *= 2; + + *channels = audioFile->channels; + *sampleRate = audioFile->sampleRate; } else { audioFile->fileSize = fileGetSize(stream); } diff --git a/src/audio.h b/src/audio.h index 2b96ac9..752b914 100644 --- a/src/audio.h +++ b/src/audio.h @@ -5,7 +5,7 @@ namespace fallout { typedef bool(AudioQueryCompressedFunc)(char* filePath); -int audioOpen(const char* fname, int mode); +int audioOpen(const char* fname, int* channels, int* sampleRate); int audioClose(int handle); int audioRead(int handle, void* buffer, unsigned int size); long audioSeek(int handle, long offset, int origin); diff --git a/src/audio_file.cc b/src/audio_file.cc index d1dce84..8333c5a 100644 --- a/src/audio_file.cc +++ b/src/audio_file.cc @@ -57,7 +57,7 @@ static int audioFileSoundDecoderReadHandler(void* data, void* buffer, unsigned i } // 0x41A88C -int audioFileOpen(const char* fname, int flags) +int audioFileOpen(const char* fname, int* channels, int* sampleRate) { char path[COMPAT_MAX_PATH]; strcpy(path, fname); @@ -69,28 +69,7 @@ int audioFileOpen(const char* fname, int flags) compression = 0; } - char mode[4]; - memset(mode, '\0', 4); - - // NOTE: Original implementation is slightly different, it uses separate - // variable to track index where to set 't' and 'b'. - char* pm = mode; - if (flags & 0x01) { - *pm++ = 'w'; - } else if (flags & 0x02) { - *pm++ = 'w'; - *pm++ = '+'; - } else { - *pm++ = 'r'; - } - - if (flags & 0x0100) { - *pm++ = 't'; - } else if (flags & 0x0200) { - *pm++ = 'b'; - } - - FILE* stream = compat_fopen(path, mode); + FILE* stream = compat_fopen(path, "rb"); if (stream == NULL) { return -1; } @@ -119,6 +98,9 @@ int audioFileOpen(const char* fname, int flags) audioFile->flags |= AUDIO_FILE_COMPRESSED; audioFile->soundDecoder = soundDecoderInit(audioFileSoundDecoderReadHandler, audioFile->stream, &(audioFile->channels), &(audioFile->sampleRate), &(audioFile->fileSize)); audioFile->fileSize *= 2; + + *channels = audioFile->channels; + *sampleRate = audioFile->sampleRate; } else { audioFile->fileSize = getFileSize(stream); } diff --git a/src/audio_file.h b/src/audio_file.h index f00734b..a43bdc7 100644 --- a/src/audio_file.h +++ b/src/audio_file.h @@ -5,7 +5,7 @@ namespace fallout { typedef bool(AudioFileQueryCompressedFunc)(char* filePath); -int audioFileOpen(const char* fname, int flags); +int audioFileOpen(const char* fname, int* channels, int* sampleRate); int audioFileClose(int handle); int audioFileRead(int handle, void* buf, unsigned int size); long audioFileSeek(int handle, long offset, int origin); diff --git a/src/combat.cc b/src/combat.cc index f7aafaf..cde7b7d 100644 --- a/src/combat.cc +++ b/src/combat.cc @@ -168,7 +168,7 @@ static bool _combat_call_display = false; // Accuracy modifiers for hit locations. // // 0x510954 -static const int _hit_location_penalty[HIT_LOCATION_COUNT] = { +static int hit_location_penalty_default[HIT_LOCATION_COUNT] = { -40, -30, -30, @@ -180,6 +180,8 @@ static const int _hit_location_penalty[HIT_LOCATION_COUNT] = { 0, }; +static int hit_location_penalty[HIT_LOCATION_COUNT]; + // Critical hit tables for every kill type. // // 0x510978 @@ -2029,6 +2031,7 @@ int combatInit() burstModInit(); unarmedInit(); damageModInit(); + combat_reset_hit_location_penalty(); return 0; } @@ -2058,6 +2061,7 @@ void combatReset() // SFALL criticalsReset(); + combat_reset_hit_location_penalty(); } // 0x420E14 @@ -3831,7 +3835,7 @@ static int attackCompute(Attack* attack) roll = _compute_spray(attack, accuracy, &ammoQuantity, &v26, anim); } else { int chance = critterGetStat(attack->attacker, STAT_CRITICAL_CHANCE); - roll = randomRoll(accuracy, chance - _hit_location_penalty[attack->defenderHitLocation], NULL); + roll = randomRoll(accuracy, chance - hit_location_penalty[attack->defenderHitLocation], NULL); } if (roll == ROLL_FAILURE) { @@ -4417,9 +4421,9 @@ static int attackDetermineToHit(Object* attacker, int tile, Object* defender, in } if (isRangedWeapon) { - accuracy += _hit_location_penalty[hitLocation]; + accuracy += hit_location_penalty[hitLocation]; } else { - accuracy += _hit_location_penalty[hitLocation] / 2; + accuracy += hit_location_penalty[hitLocation] / 2; } if (defender != NULL && (defender->flags & OBJECT_MULTIHEX) != 0) { @@ -6798,4 +6802,27 @@ static void damageModCalculateYaam(DamageCalculationContext* context) } } +int combat_get_hit_location_penalty(int hit_location) +{ + if (hit_location >= 0 && hit_location < HIT_LOCATION_COUNT) { + return hit_location_penalty[hit_location]; + } else { + return 0; + } +} + +void combat_set_hit_location_penalty(int hit_location, int penalty) +{ + if (hit_location >= 0 && hit_location < HIT_LOCATION_COUNT) { + hit_location_penalty[hit_location] = penalty; + } +} + +void combat_reset_hit_location_penalty() +{ + for (int hit_location = 0; hit_location < HIT_LOCATION_COUNT; hit_location++) { + hit_location_penalty[hit_location] = hit_location_penalty_default[hit_location]; + } +} + } // namespace fallout diff --git a/src/combat.h b/src/combat.h index 5775eae..4dc0430 100644 --- a/src/combat.h +++ b/src/combat.h @@ -71,6 +71,9 @@ int unarmedGetKickHitMode(bool isSecondary); bool unarmedIsPenetrating(int hitMode); bool damageModGetBonusHthDamageFix(); bool damageModGetDisplayBonusDamage(); +int combat_get_hit_location_penalty(int hit_location); +void combat_set_hit_location_penalty(int hit_location, int penalty); +void combat_reset_hit_location_penalty(); static inline bool isInCombat() { diff --git a/src/config.cc b/src/config.cc index 9143e55..966b0d4 100644 --- a/src/config.cc +++ b/src/config.cc @@ -289,7 +289,7 @@ bool configRead(Config* config, const char* filePath, bool isDb) } else { FILE* stream = compat_fopen(filePath, "rt"); if (stream != NULL) { - while (fgets(string, sizeof(string), stream) != NULL) { + while (compat_fgets(string, sizeof(string), stream) != NULL) { configParseLine(config, string); } diff --git a/src/dictionary.cc b/src/dictionary.cc index af873e9..31acacb 100644 --- a/src/dictionary.cc +++ b/src/dictionary.cc @@ -447,7 +447,7 @@ int dictionaryLoad(FILE* stream, Dictionary* dictionary, int a3) return -1; } - if (fgets(entry->key, keyLength + 1, stream) == NULL) { + if (compat_fgets(entry->key, keyLength + 1, stream) == NULL) { return -1; } diff --git a/src/game_sound.cc b/src/game_sound.cc index e7a838c..b1033ed 100644 --- a/src/game_sound.cc +++ b/src/game_sound.cc @@ -157,7 +157,7 @@ static int _gsound_speech_volume_get_set(int volume); static void speechPause(); static void speechResume(); static void _gsound_bkg_proc(); -static int gameSoundFileOpen(const char* fname, int access); +static int gameSoundFileOpen(const char* fname, int* channels, int* sampleRate); static long _gsound_write_(); static long gameSoundFileTellNotImplemented(int handle); static int gameSoundFileWrite(int handle, const void* buf, unsigned int size); @@ -1548,12 +1548,8 @@ void _gsound_bkg_proc() } // 0x451A08 -int gameSoundFileOpen(const char* fname, int flags) +int gameSoundFileOpen(const char* fname, int* channels, int* sampleRate) { - if ((flags & 2) != 0) { - return -1; - } - File* stream = fileOpen(fname, "rb"); if (stream == NULL) { return -1; diff --git a/src/interface.cc b/src/interface.cc index 3204faa..1415892 100644 --- a/src/interface.cc +++ b/src/interface.cc @@ -2616,4 +2616,37 @@ static void sidePanelsDraw(const char* path, int win, bool isLeading) internal_free(image); } +// NOTE: Follows Sfall implementation of `GetCurrentAttackMode`. It slightly +// differs from `interfaceGetCurrentHitMode` (can return one of `reload` hit +// modes, the default is `punch`). +// +// 0x45EF6C +bool interface_get_current_attack_mode(int* hit_mode) +{ + if (gInterfaceBarWindow == -1) { + return false; + } + + switch (gInterfaceItemStates[gInterfaceCurrentHand].action) { + case INTERFACE_ITEM_ACTION_PRIMARY_AIMING: + case INTERFACE_ITEM_ACTION_PRIMARY: + *hit_mode = gInterfaceItemStates[gInterfaceCurrentHand].primaryHitMode; + break; + case INTERFACE_ITEM_ACTION_SECONDARY_AIMING: + case INTERFACE_ITEM_ACTION_SECONDARY: + *hit_mode = gInterfaceItemStates[gInterfaceCurrentHand].secondaryHitMode; + break; + case INTERFACE_ITEM_ACTION_RELOAD: + *hit_mode = gInterfaceCurrentHand == HAND_LEFT + ? HIT_MODE_LEFT_WEAPON_RELOAD + : HIT_MODE_RIGHT_WEAPON_RELOAD; + break; + default: + *hit_mode = HIT_MODE_PUNCH; + break; + } + + return true; +} + } // namespace fallout diff --git a/src/interface.h b/src/interface.h index 07772df..acec2df 100644 --- a/src/interface.h +++ b/src/interface.h @@ -69,6 +69,7 @@ void interfaceBarEndButtonsRenderRedLights(); int indicatorBarRefresh(); bool indicatorBarShow(); bool indicatorBarHide(); +bool interface_get_current_attack_mode(int* hit_mode); unsigned char* customInterfaceBarGetBackgroundImageData(); diff --git a/src/interpreter.cc b/src/interpreter.cc index 8729fd5..23793ac 100644 --- a/src/interpreter.cc +++ b/src/interpreter.cc @@ -3268,4 +3268,29 @@ bool ProgramValue::isEmpty() return true; } +// Matches Sfall implementation. +bool ProgramValue::isInt() +{ + return opcode == VALUE_TYPE_INT; +} + +// Matches Sfall implementation. +bool ProgramValue::isFloat() +{ + return opcode == VALUE_TYPE_FLOAT; +} + +// Matches Sfall implementation. +float ProgramValue::asFloat() +{ + switch (opcode) { + case VALUE_TYPE_INT: + return static_cast(integerValue); + case VALUE_TYPE_FLOAT: + return floatValue; + default: + return 0.0; + } +} + } // namespace fallout diff --git a/src/interpreter.h b/src/interpreter.h index 91d27bb..f84347f 100644 --- a/src/interpreter.h +++ b/src/interpreter.h @@ -149,6 +149,9 @@ typedef struct ProgramValue { }; bool isEmpty(); + bool isInt(); + bool isFloat(); + float asFloat(); } ProgramValue; typedef std::vector ProgramStack; diff --git a/src/interpreter_extra.cc b/src/interpreter_extra.cc index 1cce7b4..12f3222 100644 --- a/src/interpreter_extra.cc +++ b/src/interpreter_extra.cc @@ -2987,7 +2987,7 @@ static void opGetMessageString(Program* program) int messageListIndex = programStackPopInteger(program); char* string; - if (messageIndex >= 1) { + if (messageIndex >= 0) { string = _scr_get_msg_str_speech(messageListIndex, messageIndex, 1); if (string == NULL) { debugPrint("\nError: No message file EXISTS!: index %d, line %d", messageListIndex, messageIndex); diff --git a/src/mouse.cc b/src/mouse.cc index 09e4334..6e8a8bb 100644 --- a/src/mouse.cc +++ b/src/mouse.cc @@ -54,7 +54,7 @@ static unsigned char* _mouse_fptr = NULL; static double gMouseSensitivity = 1.0; // 0x51E2AC -static int gMouseButtonsState = 0; +static int last_buttons = 0; // 0x6AC790 static bool gCursorIsHidden; @@ -415,7 +415,7 @@ void _mouse_info() } x = 0; y = 0; - buttons = gMouseButtonsState; + buttons = last_buttons; } _mouse_simulate_input(x, y, buttons); @@ -447,7 +447,7 @@ void _mouse_simulate_input(int delta_x, int delta_y, int buttons) return; } - if (delta_x || delta_y || buttons != gMouseButtonsState) { + if (delta_x || delta_y || buttons != last_buttons) { if (gVcrState == 0) { if (_vcr_buffer_index == VCR_BUFFER_CAPACITY - 1) { vcrDump(); @@ -464,13 +464,13 @@ void _mouse_simulate_input(int delta_x, int delta_y, int buttons) _vcr_buffer_index++; } } else { - if (gMouseButtonsState == 0) { + if (last_buttons == 0) { if (!_mouse_idling) { _mouse_idle_start_time = getTicks(); _mouse_idling = 1; } - gMouseButtonsState = 0; + last_buttons = 0; _raw_buttons = 0; gMouseEvent = 0; @@ -479,7 +479,7 @@ void _mouse_simulate_input(int delta_x, int delta_y, int buttons) } _mouse_idling = 0; - gMouseButtonsState = buttons; + last_buttons = buttons; previousEvent = gMouseEvent; gMouseEvent = 0; @@ -703,4 +703,9 @@ void convertMouseWheelToArrowKey(int* keyCodePtr) } } +int mouse_get_last_buttons() +{ + return last_buttons; +} + } // namespace fallout diff --git a/src/mouse.h b/src/mouse.h index 6b091c5..667250f 100644 --- a/src/mouse.h +++ b/src/mouse.h @@ -52,6 +52,7 @@ void mouseGetPositionInWindow(int win, int* x, int* y); bool mouseHitTestInWindow(int win, int left, int top, int right, int bottom); void mouseGetWheel(int* x, int* y); void convertMouseWheelToArrowKey(int* keyCodePtr); +int mouse_get_last_buttons(); } // namespace fallout diff --git a/src/platform_compat.cc b/src/platform_compat.cc index 5297592..b629fb6 100644 --- a/src/platform_compat.cc +++ b/src/platform_compat.cc @@ -239,6 +239,36 @@ gzFile compat_gzopen(const char* path, const char* mode) return gzopen(nativePath, mode); } +char* compat_fgets(char* buffer, int maxCount, FILE* stream) +{ + buffer = fgets(buffer, maxCount, stream); + + if (buffer != NULL) { + size_t len = strlen(buffer); + if (len >= 2 && buffer[len - 1] == '\n' && buffer[len - 2] == '\r') { + buffer[len - 2] = '\n'; + buffer[len - 1] = '\0'; + } + } + + return buffer; +} + +char* compat_gzgets(gzFile stream, char* buffer, int maxCount) +{ + buffer = gzgets(stream, buffer, maxCount); + + if (buffer != NULL) { + size_t len = strlen(buffer); + if (len >= 2 && buffer[len - 1] == '\n' && buffer[len - 2] == '\r') { + buffer[len - 2] = '\n'; + buffer[len - 1] = '\0'; + } + } + + return buffer; +} + int compat_remove(const char* path) { char nativePath[COMPAT_MAX_PATH]; diff --git a/src/platform_compat.h b/src/platform_compat.h index be88974..9fb7574 100644 --- a/src/platform_compat.h +++ b/src/platform_compat.h @@ -35,6 +35,8 @@ int compat_mkdir(const char* path); unsigned int compat_timeGetTime(); FILE* compat_fopen(const char* path, const char* mode); gzFile compat_gzopen(const char* path, const char* mode); +char* compat_fgets(char* buffer, int maxCount, FILE* stream); +char* compat_gzgets(gzFile stream, char* buffer, int maxCount); int compat_remove(const char* path); int compat_rename(const char* oldFileName, const char* newFileName); void compat_windows_path_to_native(char* path); diff --git a/src/proto.cc b/src/proto.cc index 86d767b..efb05b0 100644 --- a/src/proto.cc +++ b/src/proto.cc @@ -249,6 +249,12 @@ int _proto_list_str(int pid, char* proto_path) return 0; } +// 0x49E984 +size_t proto_size(int type) +{ + return type >= 0 && type < OBJ_TYPE_COUNT ? _proto_sizes[type] : 0; +} + // 0x49E99C bool _proto_action_can_use(int pid) { @@ -1704,12 +1710,10 @@ static int _proto_load_pid(int pid, Proto** protoPtr) return 0; } -// allocate memory for proto of given type and adds it to proto cache +// 0x4A1D98 static int _proto_find_free_subnode(int type, Proto** protoPtr) { - size_t size = (type >= 0 && type < 11) ? _proto_sizes[type] : 0; - - Proto* proto = (Proto*)internal_malloc(size); + Proto* proto = (Proto*)internal_malloc(proto_size(type)); *protoPtr = proto; if (proto == NULL) { return -1; diff --git a/src/proto.h b/src/proto.h index c7f481d..d6f13e6 100644 --- a/src/proto.h +++ b/src/proto.h @@ -104,6 +104,7 @@ extern char* _proto_none_str; void _proto_make_path(char* path, int pid); int _proto_list_str(int pid, char* proto_path); +size_t proto_size(int type); bool _proto_action_can_use(int pid); bool _proto_action_can_use_on(int pid); bool _proto_action_can_talk_to(int pid); diff --git a/src/scripts.cc b/src/scripts.cc index 3ac7e4b..7a35d39 100644 --- a/src/scripts.cc +++ b/src/scripts.cc @@ -29,6 +29,7 @@ #include "proto.h" #include "proto_instance.h" #include "queue.h" +#include "sfall_config.h" #include "stat.h" #include "svga.h" #include "tile.h" @@ -265,6 +266,15 @@ static bool _set; // 0x667750 static char _tempStr1[20]; +static int gStartYear; +static int gStartMonth; +static int gStartDay; + +static int gMovieTimerArtimer1; +static int gMovieTimerArtimer2; +static int gMovieTimerArtimer3; +static int gMovieTimerArtimer4; + // TODO: Make unsigned. // // Returns game time in ticks (1/10 second). @@ -278,9 +288,9 @@ int gameTimeGetTime() // 0x4A3338 void gameTimeGetDate(int* monthPtr, int* dayPtr, int* yearPtr) { - int year = (gGameTime / GAME_TIME_TICKS_PER_DAY + 24) / 365 + 2241; - int month = 6; - int day = (gGameTime / GAME_TIME_TICKS_PER_DAY + 24) % 365; + int year = (gGameTime / GAME_TIME_TICKS_PER_DAY + gStartDay) / 365 + gStartYear; + int month = gStartMonth; + int day = (gGameTime / GAME_TIME_TICKS_PER_DAY + gStartDay) % 365; while (1) { int daysInMonth = gGameTimeDaysPerMonth[month]; @@ -439,7 +449,7 @@ int _scriptsCheckGameEvents(int* moviePtr, int window) movieFlags = GAME_MOVIE_FADE_IN | GAME_MOVIE_STOP_MUSIC; endgame = true; } else { - if (day >= 360 || gameGetGlobalVar(GVAR_FALLOUT_2) >= 3) { + if (day >= gMovieTimerArtimer4 || gameGetGlobalVar(GVAR_FALLOUT_2) >= 3) { movie = MOVIE_ARTIMER4; if (!gameMovieIsSeen(MOVIE_ARTIMER4)) { adjustRep = true; @@ -447,13 +457,13 @@ int _scriptsCheckGameEvents(int* moviePtr, int window) wmAreaSetVisibleState(CITY_DESTROYED_ARROYO, 1, 1); wmAreaMarkVisitedState(CITY_DESTROYED_ARROYO, 2); } - } else if (day >= 270 && gameGetGlobalVar(GVAR_FALLOUT_2) != 3) { + } else if (day >= gMovieTimerArtimer3 && gameGetGlobalVar(GVAR_FALLOUT_2) != 3) { adjustRep = true; movie = MOVIE_ARTIMER3; - } else if (day >= 180 && gameGetGlobalVar(GVAR_FALLOUT_2) != 3) { + } else if (day >= gMovieTimerArtimer2 && gameGetGlobalVar(GVAR_FALLOUT_2) != 3) { adjustRep = true; movie = MOVIE_ARTIMER2; - } else if (day >= 90 && gameGetGlobalVar(GVAR_FALLOUT_2) != 3) { + } else if (day >= gMovieTimerArtimer1 && gameGetGlobalVar(GVAR_FALLOUT_2) != 3) { adjustRep = true; movie = MOVIE_ARTIMER1; } @@ -1522,6 +1532,15 @@ int scriptsInit() messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_SCRIPT, &gScrMessageList); + configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_START_YEAR, &gStartYear); + configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_START_MONTH, &gStartMonth); + configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_START_DAY, &gStartDay); + + configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MOVIE_TIMER_ARTIMER1, &gMovieTimerArtimer1); + configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MOVIE_TIMER_ARTIMER2, &gMovieTimerArtimer2); + configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MOVIE_TIMER_ARTIMER3, &gMovieTimerArtimer3); + configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MOVIE_TIMER_ARTIMER4, &gMovieTimerArtimer4); + return 0; } diff --git a/src/sfall_config.cc b/src/sfall_config.cc index c3c8f7e..c0f4b6c 100644 --- a/src/sfall_config.cc +++ b/src/sfall_config.cc @@ -27,6 +27,9 @@ bool sfallConfigInit(int argc, char** argv) 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_START_YEAR, 2241); + configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_START_MONTH, 6); + configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_START_DAY, 24); 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_CREDITS_OFFSET_X_KEY, 0); configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MAIN_MENU_CREDITS_OFFSET_Y_KEY, 0); @@ -50,6 +53,10 @@ bool sfallConfigInit(int argc, char** argv) configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_BURST_MOD_TARGET_MULTIPLIER_KEY, SFALL_CONFIG_BURST_MOD_DEFAULT_TARGET_MULTIPLIER); configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_BURST_MOD_TARGET_DIVISOR_KEY, SFALL_CONFIG_BURST_MOD_DEFAULT_TARGET_DIVISOR); configSetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_EXTRA_MESSAGE_LISTS_KEY, ""); + configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MOVIE_TIMER_ARTIMER1, 90); + configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MOVIE_TIMER_ARTIMER2, 180); + configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MOVIE_TIMER_ARTIMER3, 270); + configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MOVIE_TIMER_ARTIMER4, 360); char path[COMPAT_MAX_PATH]; char* executable = argv[0]; diff --git a/src/sfall_config.h b/src/sfall_config.h index 26d85cc..86aa7a7 100644 --- a/src/sfall_config.h +++ b/src/sfall_config.h @@ -13,6 +13,9 @@ namespace fallout { #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_START_YEAR "StartYear" +#define SFALL_CONFIG_START_MONTH "StartMonth" +#define SFALL_CONFIG_START_DAY "StartDay" #define SFALL_CONFIG_MAIN_MENU_BIG_FONT_COLOR_KEY "MainMenuBigFontColour" #define SFALL_CONFIG_MAIN_MENU_CREDITS_OFFSET_X_KEY "MainMenuCreditsOffsetX" #define SFALL_CONFIG_MAIN_MENU_CREDITS_OFFSET_Y_KEY "MainMenuCreditsOffsetY" @@ -42,6 +45,10 @@ namespace fallout { #define SFALL_CONFIG_PLASTIC_EXPLOSIVE_MIN_DAMAGE_KEY "PlasticExplosive_DmgMin" #define SFALL_CONFIG_PLASTIC_EXPLOSIVE_MAX_DAMAGE_KEY "PlasticExplosive_DmgMax" #define SFALL_CONFIG_EXPLOSION_EMITS_LIGHT_KEY "ExplosionsEmitLight" +#define SFALL_CONFIG_MOVIE_TIMER_ARTIMER1 "MovieTimer_artimer1" +#define SFALL_CONFIG_MOVIE_TIMER_ARTIMER2 "MovieTimer_artimer2" +#define SFALL_CONFIG_MOVIE_TIMER_ARTIMER3 "MovieTimer_artimer3" +#define SFALL_CONFIG_MOVIE_TIMER_ARTIMER4 "MovieTimer_artimer4" #define SFALL_CONFIG_CITY_REPUTATION_LIST_KEY "CityRepsList" #define SFALL_CONFIG_UNARMED_FILE_KEY "UnarmedFile" #define SFALL_CONFIG_DAMAGE_MOD_FORMULA_KEY "DamageFormula" diff --git a/src/sfall_opcodes.cc b/src/sfall_opcodes.cc index d746f93..103d29f 100644 --- a/src/sfall_opcodes.cc +++ b/src/sfall_opcodes.cc @@ -1,19 +1,25 @@ #include "sfall_opcodes.h" +#include "animation.h" #include "art.h" #include "combat.h" #include "debug.h" #include "game.h" +#include "input.h" #include "interface.h" #include "interpreter.h" #include "item.h" #include "message.h" #include "mouse.h" #include "object.h" +#include "proto.h" +#include "scripts.h" #include "sfall_global_vars.h" #include "sfall_lists.h" #include "stat.h" #include "svga.h" +#include "tile.h" +#include "worldmap.h" namespace fallout { @@ -39,6 +45,17 @@ static void opReadByte(Program* program) programStackPushInteger(program, value); } +// set_pc_base_stat +static void op_set_pc_base_stat(Program* program) +{ + // CE: Implementation is different. Sfall changes value directly on the + // dude's proto, without calling |critterSetBaseStat|. This function has + // important call to update derived stats, which is not present in Sfall. + int value = programStackPopInteger(program); + int stat = programStackPopInteger(program); + critterSetBaseStat(gDude, stat, value); +} + // set_pc_extra_stat static void opSetPcBonusStat(Program* program) { @@ -50,6 +67,16 @@ static void opSetPcBonusStat(Program* program) critterSetBonusStat(gDude, stat, value); } +// get_pc_base_stat +static void op_get_pc_base_stat(Program* program) +{ + // CE: Implementation is different. Sfall obtains value directly from + // dude's proto. This can have unforeseen consequences when dealing with + // current stats. + int stat = programStackPopInteger(program); + programStackPushInteger(program, critterGetBaseStat(gDude, stat)); +} + // get_pc_extra_stat static void opGetPcBonusStat(Program* program) { @@ -58,6 +85,28 @@ static void opGetPcBonusStat(Program* program) programStackPushInteger(program, value); } +// get_year +static void op_get_year(Program* program) +{ + int year; + gameTimeGetDate(nullptr, nullptr, &year); + programStackPushInteger(program, year); +} + +// in_world_map +static void op_in_world_map(Program* program) +{ + programStackPushInteger(program, GameMode::isInGameMode(GameMode::kWorldmap) ? 1 : 0); +} + +// set_world_map_pos +static void op_set_world_map_pos(Program* program) +{ + int y = programStackPopInteger(program); + int x = programStackPopInteger(program); + wmSetPartyWorldPos(x, y); +} + // active_hand static void opGetCurrentHand(Program* program) { @@ -100,6 +149,103 @@ static void opGetGameMode(Program* program) programStackPushInteger(program, GameMode::getCurrentGameMode()); } +// get_uptime +static void op_get_uptime(Program* program) +{ + programStackPushInteger(program, getTicks()); +} + +// set_car_current_town +static void op_set_car_current_town(Program* program) +{ + int area = programStackPopInteger(program); + wmCarSetCurrentArea(area); +} + +// get_bodypart_hit_modifier +static void op_get_bodypart_hit_modifier(Program* program) +{ + int hit_location = programStackPopInteger(program); + programStackPushInteger(program, combat_get_hit_location_penalty(hit_location)); +} + +// set_bodypart_hit_modifier +static void op_set_bodypart_hit_modifier(Program* program) +{ + int penalty = programStackPopInteger(program); + int hit_location = programStackPopInteger(program); + combat_set_hit_location_penalty(hit_location, penalty); +} + +// sqrt +static void op_sqrt(Program* program) +{ + ProgramValue programValue = programStackPopValue(program); + programStackPushFloat(program, sqrtf(programValue.asFloat())); +} + +// abs +static void op_abs(Program* program) +{ + ProgramValue programValue = programStackPopValue(program); + + if (programValue.isInt()) { + programStackPushInteger(program, abs(programValue.integerValue)); + } else { + programStackPushFloat(program, abs(programValue.asFloat())); + } +} + +// get_proto_data +static void op_get_proto_data(Program* program) +{ + size_t offset = static_cast(programStackPopInteger(program)); + int pid = programStackPopInteger(program); + + Proto* proto; + if (protoGetProto(pid, &proto) != 0) { + debugPrint("op_get_proto_data: bad proto %d", pid); + programStackPushInteger(program, -1); + return; + } + + // CE: Make sure the requested offset is within memory bounds and is + // properly aligned. + if (offset + sizeof(int) > proto_size(PID_TYPE(pid)) || offset % sizeof(int) != 0) { + debugPrint("op_get_proto_data: bad offset %d", offset); + programStackPushInteger(program, -1); + return; + } + + int value = *reinterpret_cast(reinterpret_cast(proto) + offset); + programStackPushInteger(program, value); +} + +// set_proto_data +static void op_set_proto_data(Program* program) +{ + int value = programStackPopInteger(program); + size_t offset = static_cast(programStackPopInteger(program)); + int pid = programStackPopInteger(program); + + Proto* proto; + if (protoGetProto(pid, &proto) != 0) { + debugPrint("op_set_proto_data: bad proto %d", pid); + programStackPushInteger(program, -1); + return; + } + + // CE: Make sure the requested offset is within memory bounds and is + // properly aligned. + if (offset + sizeof(int) > proto_size(PID_TYPE(pid)) || offset % sizeof(int) != 0) { + debugPrint("op_set_proto_data: bad offset %d", offset); + programStackPushInteger(program, -1); + return; + } + + *reinterpret_cast(reinterpret_cast(proto) + offset) = value; +} + // list_begin static void opListBegin(Program* program) { @@ -251,6 +397,14 @@ static void opGetMouseY(Program* program) programStackPushInteger(program, y); } +// get_mouse_buttons +static void op_get_mouse_buttons(Program* program) +{ + // CE: Implementation is slightly different - it does not handle middle + // mouse button. + programStackPushInteger(program, mouse_get_last_buttons()); +} + // get_screen_width static void opGetScreenWidth(Program* program) { @@ -263,6 +417,17 @@ static void opGetScreenHeight(Program* program) programStackPushInteger(program, screenGetHeight()); } +// get_attack_type +static void op_get_attack_type(Program* program) +{ + int hit_mode; + if (interface_get_current_attack_mode(&hit_mode)) { + programStackPushInteger(program, hit_mode); + } else { + programStackPushInteger(program, -1); + } +} + // atoi static void opParseInt(Program* program) { @@ -270,6 +435,24 @@ static void opParseInt(Program* program) programStackPushInteger(program, static_cast(strtol(string, nullptr, 0))); } +// atof +static void op_atof(Program* program) +{ + const char* string = programStackPopString(program); + programStackPushFloat(program, static_cast(atof(string))); +} + +// tile_under_cursor +static void op_tile_under_cursor(Program* program) +{ + int x; + int y; + mouseGetPosition(&x, &y); + + int tile = tileFromScreenXY(x, y, gElevation); + programStackPushInteger(program, tile); +} + // strlen static void opGetStringLength(Program* program) { @@ -277,6 +460,22 @@ static void opGetStringLength(Program* program) programStackPushInteger(program, static_cast(strlen(string))); } +// pow (^) +static void op_power(Program* program) +{ + ProgramValue expValue = programStackPopValue(program); + ProgramValue baseValue = programStackPopValue(program); + + // CE: Implementation is slightly different, check. + float result = powf(baseValue.asFloat(), expValue.asFloat()); + + if (baseValue.isInt() && expValue.isInt()) { + programStackPushInteger(program, static_cast(result)); + } else { + programStackPushFloat(program, result); + } +} + // message_str_game static void opGetMessage(Program* program) { @@ -298,6 +497,61 @@ static void opRound(Program* program) programStackPushInteger(program, integerValue); } +enum BlockType { + BLOCKING_TYPE_BLOCK, + BLOCKING_TYPE_SHOOT, + BLOCKING_TYPE_AI, + BLOCKING_TYPE_SIGHT, + BLOCKING_TYPE_SCROLL, +}; + +PathBuilderCallback* get_blocking_func(int type) +{ + switch (type) { + case BLOCKING_TYPE_SHOOT: + return _obj_shoot_blocking_at; + case BLOCKING_TYPE_AI: + return _obj_ai_blocking_at; + case BLOCKING_TYPE_SIGHT: + return _obj_sight_blocking_at; + default: + return _obj_blocking_at; + } +} + +// obj_blocking_line +static void op_make_straight_path(Program* program) +{ + int type = programStackPopInteger(program); + int dest = programStackPopInteger(program); + Object* object = static_cast(programStackPopPointer(program)); + + int flags = type == BLOCKING_TYPE_SHOOT ? 32 : 0; + + Object* obstacle = nullptr; + _make_straight_path_func(object, object->tile, dest, nullptr, &obstacle, flags, get_blocking_func(type)); + programStackPushPointer(program, obstacle); +} + +// obj_blocking_tile +static void op_obj_blocking_at(Program* program) +{ + int type = programStackPopInteger(program); + int elevation = programStackPopInteger(program); + int tile = programStackPopInteger(program); + + PathBuilderCallback* func = get_blocking_func(type); + Object* obstacle = func(NULL, tile, elevation); + if (obstacle != NULL) { + if (type == BLOCKING_TYPE_SHOOT) { + if ((obstacle->flags & OBJECT_SHOOT_THRU) != 0) { + obstacle = nullptr; + } + } + } + programStackPushPointer(program, obstacle); +} + // art_exists static void opArtExists(Program* program) { @@ -305,15 +559,50 @@ static void opArtExists(Program* program) programStackPushInteger(program, artExists(fid)); } +// div (/) +static void op_div(Program* program) +{ + ProgramValue divisorValue = programStackPopValue(program); + ProgramValue dividendValue = programStackPopValue(program); + + if (divisorValue.integerValue == 0) { + debugPrint("Division by zero"); + + // TODO: Looks like execution is not halted in Sfall's div, check. + programStackPushInteger(program, 0); + return; + } + + if (dividendValue.isFloat() || divisorValue.isFloat()) { + programStackPushFloat(program, dividendValue.asFloat() / divisorValue.asFloat()); + } else { + // Unsigned divison. + programStackPushInteger(program, static_cast(dividendValue.integerValue) / static_cast(divisorValue.integerValue)); + } +} + void sfallOpcodesInit() { interpreterRegisterOpcode(0x8156, opReadByte); + interpreterRegisterOpcode(0x815A, op_set_pc_base_stat); interpreterRegisterOpcode(0x815B, opSetPcBonusStat); + interpreterRegisterOpcode(0x815C, op_get_pc_base_stat); interpreterRegisterOpcode(0x815D, opGetPcBonusStat); + interpreterRegisterOpcode(0x8163, op_get_year); + interpreterRegisterOpcode(0x8170, op_in_world_map); + interpreterRegisterOpcode(0x8172, op_set_world_map_pos); interpreterRegisterOpcode(0x8193, opGetCurrentHand); interpreterRegisterOpcode(0x819D, opSetGlobalVar); interpreterRegisterOpcode(0x819E, opGetGlobalInt); interpreterRegisterOpcode(0x81AF, opGetGameMode); + interpreterRegisterOpcode(0x81B3, op_get_uptime); + interpreterRegisterOpcode(0x81B6, op_set_car_current_town); + interpreterRegisterOpcode(0x81DF, op_get_bodypart_hit_modifier); + interpreterRegisterOpcode(0x81E0, op_set_bodypart_hit_modifier); + interpreterRegisterOpcode(0x81EC, op_sqrt); + interpreterRegisterOpcode(0x81ED, op_abs); + interpreterRegisterOpcode(0x8204, op_get_proto_data); + interpreterRegisterOpcode(0x8205, op_set_proto_data); interpreterRegisterOpcode(0x820D, opListBegin); interpreterRegisterOpcode(0x820E, opListNext); interpreterRegisterOpcode(0x820F, opListEnd); @@ -326,13 +615,21 @@ void sfallOpcodesInit() interpreterRegisterOpcode(0x821A, opSetWeaponAmmoCount); interpreterRegisterOpcode(0x821C, opGetMouseX); interpreterRegisterOpcode(0x821D, opGetMouseY); + interpreterRegisterOpcode(0x821E, op_get_mouse_buttons); interpreterRegisterOpcode(0x8220, opGetScreenWidth); interpreterRegisterOpcode(0x8221, opGetScreenHeight); + interpreterRegisterOpcode(0x8228, op_get_attack_type); interpreterRegisterOpcode(0x8237, opParseInt); + interpreterRegisterOpcode(0x8238, op_atof); + interpreterRegisterOpcode(0x824B, op_tile_under_cursor); interpreterRegisterOpcode(0x824F, opGetStringLength); + interpreterRegisterOpcode(0x8263, op_power); interpreterRegisterOpcode(0x826B, opGetMessage); interpreterRegisterOpcode(0x8267, opRound); + interpreterRegisterOpcode(0x826E, op_make_straight_path); + interpreterRegisterOpcode(0x826F, op_obj_blocking_at); interpreterRegisterOpcode(0x8274, opArtExists); + interpreterRegisterOpcode(0x827F, op_div); } void sfallOpcodesExit() diff --git a/src/sound.cc b/src/sound.cc index 353b605..0576358 100644 --- a/src/sound.cc +++ b/src/sound.cc @@ -1,5 +1,6 @@ #include "sound.h" +#include #include #include #include @@ -8,7 +9,6 @@ #ifdef _WIN32 #include #else -#include #include #endif @@ -49,7 +49,7 @@ static long soundFileSize(int fileHandle); static long soundTellData(int fileHandle); static int soundWriteData(int fileHandle, const void* buf, unsigned int size); static int soundReadData(int fileHandle, void* buf, unsigned int size); -static int soundOpenData(const char* filePath, int flags); +static int soundOpenData(const char* filePath, int* channels, int* sampleRate); static long soundSeekData(int fileHandle, long offset, int origin); static int soundCloseData(int fileHandle); static char* soundFileManglerDefaultImpl(char* fname); @@ -223,8 +223,16 @@ static int soundReadData(int fileHandle, void* buf, unsigned int size) } // 0x4AC768 -static int soundOpenData(const char* filePath, int flags) +static int soundOpenData(const char* filePath, int* channels, int* sampleRate) { + int flags; + +#ifdef _WIN32 + flags = _O_RDONLY | _O_BINARY; +#else + flags = O_RDONLY; +#endif + return open(filePath, flags); } @@ -608,7 +616,7 @@ int soundLoad(Sound* sound, char* filePath) return gSoundLastError; } - sound->io.fd = sound->io.open(gSoundFileNameMangler(filePath), 0x0200); + sound->io.fd = sound->io.open(gSoundFileNameMangler(filePath), &(sound->channels), &(sound->rate)); if (sound->io.fd == -1) { gSoundLastError = SOUND_FILE_NOT_FOUND; return gSoundLastError; diff --git a/src/sound.h b/src/sound.h index ab81e63..427b5f8 100644 --- a/src/sound.h +++ b/src/sound.h @@ -46,7 +46,7 @@ typedef enum SoundError { SOUND_ERR_COUNT, } SoundError; -typedef int SoundOpenProc(const char* filePath, int flags); +typedef int SoundOpenProc(const char* filePath, int* channels, int* sampleRate); typedef int SoundCloseProc(int fileHandle); typedef int SoundReadProc(int fileHandle, void* buf, unsigned int size); typedef int SoundWriteProc(int fileHandle, const void* buf, unsigned int size); diff --git a/src/sound_decoder.cc b/src/sound_decoder.cc index 3b2c33a..83b020a 100644 --- a/src/sound_decoder.cc +++ b/src/sound_decoder.cc @@ -34,13 +34,15 @@ static int ReadBand_Fmt24(SoundDecoder* soundDecoder, int offset, int bits); static int ReadBand_Fmt26(SoundDecoder* soundDecoder, int offset, int bits); static int ReadBand_Fmt27(SoundDecoder* soundDecoder, int offset, int bits); static int ReadBand_Fmt29(SoundDecoder* soundDecoder, int offset, int bits); -static int ReadBands(SoundDecoder* ptr); +static bool ReadBands(SoundDecoder* soundDecoder); static void untransform_subband0(unsigned char* a1, unsigned char* a2, int a3, int a4); static void untransform_subband(unsigned char* a1, unsigned char* a2, int a3, int a4); static void untransform_all(SoundDecoder* soundDecoder); +static bool soundDecoderFill(SoundDecoder* soundDecoder); static inline void soundDecoderRequireBits(SoundDecoder* soundDecoder, int bits); static inline void soundDecoderDropBits(SoundDecoder* soundDecoder, int bits); +static int ReadBand_Fmt31(SoundDecoder* soundDecoder, int offset, int bits); // 0x51E328 static int gSoundDecodersCount = 0; @@ -78,7 +80,7 @@ static ReadBandFunc _ReadBand_tbl[32] = { ReadBand_Fail, ReadBand_Fmt29, ReadBand_Fail, - ReadBand_Fail, + ReadBand_Fmt31, }; // 0x6AD960 @@ -751,7 +753,7 @@ static int ReadBand_Fmt29(SoundDecoder* soundDecoder, int offset, int bits) } // 0x4D493C -static int ReadBands(SoundDecoder* soundDecoder) +static bool ReadBands(SoundDecoder* soundDecoder) { int v9; int v15; @@ -797,10 +799,10 @@ static int ReadBands(SoundDecoder* soundDecoder) fn = _ReadBand_tbl[bits]; if (!fn(soundDecoder, index, bits)) { - return 0; + return false; } } - return 1; + return true; } // 0x4D4ADC @@ -1043,53 +1045,67 @@ static void untransform_all(SoundDecoder* soundDecoder) } } +// NOTE: Inlined. +// +// 0x4D4F58 +static bool soundDecoderFill(SoundDecoder* soundDecoder) +{ + // CE: Implementation is slightly different. `ReadBands` now handles new + // Fmt31 used in some Russian localizations. The appropriate handler acts as + // both decoder and transformer, so there is no need to untransform bands + // once again. This approach assumes band 31 is never used by standard acms + // and mods. + if (ReadBands(soundDecoder)) { + untransform_all(soundDecoder); + } + + soundDecoder->file_cnt -= soundDecoder->total_samples; + soundDecoder->samp_ptr = soundDecoder->samples; + soundDecoder->samp_cnt = soundDecoder->total_samples; + + if (soundDecoder->file_cnt < 0) { + soundDecoder->samp_cnt += soundDecoder->file_cnt; + soundDecoder->file_cnt = 0; + } + + return true; +} + // 0x4D4FA0 size_t soundDecoderDecode(SoundDecoder* soundDecoder, void* buffer, size_t size) { unsigned char* dest; - unsigned char* v5; - int v6; - int v4; + unsigned char* samp_ptr; + int samp_cnt; dest = (unsigned char*)buffer; - v4 = 0; - v5 = soundDecoder->samp_ptr; - v6 = soundDecoder->samp_cnt; + samp_ptr = soundDecoder->samp_ptr; + samp_cnt = soundDecoder->samp_cnt; size_t bytesRead; for (bytesRead = 0; bytesRead < size; bytesRead += 2) { - if (!v6) { - if (!soundDecoder->file_cnt) { + if (samp_cnt == 0) { + if (soundDecoder->file_cnt == 0) { break; } - if (!ReadBands(soundDecoder)) { + // NOTE: Uninline. + if (!soundDecoderFill(soundDecoder)) { break; } - untransform_all(soundDecoder); - - soundDecoder->file_cnt -= soundDecoder->total_samples; - soundDecoder->samp_ptr = soundDecoder->samples; - soundDecoder->samp_cnt = soundDecoder->total_samples; - - if (soundDecoder->file_cnt < 0) { - soundDecoder->samp_cnt += soundDecoder->file_cnt; - soundDecoder->file_cnt = 0; - } - - v5 = soundDecoder->samp_ptr; - v6 = soundDecoder->samp_cnt; + samp_ptr = soundDecoder->samp_ptr; + samp_cnt = soundDecoder->samp_cnt; } - int v13 = *(int*)v5; - v5 += 4; - *(unsigned short*)(dest + bytesRead) = (v13 >> soundDecoder->levels) & 0xFFFF; - v6--; + int sample = *(int*)samp_ptr; + samp_ptr += 4; + *(unsigned short*)(dest + bytesRead) = (sample >> soundDecoder->levels) & 0xFFFF; + samp_cnt--; } - soundDecoder->samp_ptr = v5; - soundDecoder->samp_cnt = v6; + soundDecoder->samp_ptr = samp_ptr; + soundDecoder->samp_cnt = samp_cnt; return bytesRead; } @@ -1259,4 +1275,22 @@ static inline void soundDecoderDropBits(SoundDecoder* soundDecoder, int bits) soundDecoder->bits -= bits; } +static int ReadBand_Fmt31(SoundDecoder* soundDecoder, int offset, int bits) +{ + int* samples = (int*)soundDecoder->samples; + + int remaining_samples = soundDecoder->total_samples; + while (remaining_samples != 0) { + soundDecoderRequireBits(soundDecoder, 16); + int value = soundDecoder->hold & 0xFFFF; + soundDecoderDropBits(soundDecoder, 16); + + *samples++ = (value << 16) >> (16 - soundDecoder->levels); + + remaining_samples--; + } + + return 0; +} + } // namespace fallout diff --git a/src/sound_effects_cache.cc b/src/sound_effects_cache.cc index 26aead6..30f91ae 100644 --- a/src/sound_effects_cache.cc +++ b/src/sound_effects_cache.cc @@ -154,7 +154,7 @@ void soundEffectsCacheFlush() // sfxc_cached_open // 0x4A915C -int soundEffectsCacheFileOpen(const char* fname, int mode) +int soundEffectsCacheFileOpen(const char* fname, int* channels, int* sampleRate) { if (_sfxc_files_open >= SOUND_EFFECTS_MAX_COUNT) { return -1; diff --git a/src/sound_effects_cache.h b/src/sound_effects_cache.h index e6e0972..579c856 100644 --- a/src/sound_effects_cache.h +++ b/src/sound_effects_cache.h @@ -11,7 +11,7 @@ int soundEffectsCacheInit(int cache_size, const char* effectsPath); void soundEffectsCacheExit(); int soundEffectsCacheInitialized(); void soundEffectsCacheFlush(); -int soundEffectsCacheFileOpen(const char* fname, int mode); +int soundEffectsCacheFileOpen(const char* fname, int* channels, int* sampleRate); int soundEffectsCacheFileClose(int handle); int soundEffectsCacheFileRead(int handle, void* buf, unsigned int size); int soundEffectsCacheFileWrite(int handle, const void* buf, unsigned int size); diff --git a/src/tile.cc b/src/tile.cc index a7e98aa..af68a39 100644 --- a/src/tile.cc +++ b/src/tile.cc @@ -5,6 +5,7 @@ #include #include +#include #include "art.h" #include "color.h" @@ -49,11 +50,16 @@ typedef struct UpsideDownTriangle { int field_8; } UpsideDownTriangle; +struct roof_fill_task { + int x; + int y; +}; + static void tileSetBorder(int windowWidth, int windowHeight, int hexGridWidth, int hexGridHeight); static void tileRefreshMapper(Rect* rect, int elevation); static void tileRefreshGame(Rect* rect, int elevation); -static void roof_fill_on(int x, int y, int elevation); -static void roof_fill_off(int x, int y, int elevation); +static void roof_fill_push_task_if_in_bounds(std::stack& tasks_stack, int x, int y); +static void roof_fill_off_process_task(std::stack& tasks_stack, int elevation, bool on); static void tileRenderRoof(int fid, int x, int y, Rect* rect, int light); static void _draw_grid(int tile, int elevation, Rect* rect); static void tileRenderFloor(int fid, int x, int y, Rect* rect); @@ -1258,27 +1264,39 @@ void tileRenderRoofsInRect(Rect* rect, int elevation) } } -// 0x4B22D0 -static void roof_fill_on(int x, int y, int elevation) +static void roof_fill_push_task_if_in_bounds(std::stack& tasks_stack, int x, int y) { if (x >= 0 && x < gSquareGridWidth && y >= 0 && y < gSquareGridHeight) { - int squareTileIndex = gSquareGridWidth * y + x; - int squareTile = gTileSquares[elevation]->field_0[squareTileIndex]; - int roof = (squareTile >> 16) & 0xFFFF; + tasks_stack.push(roof_fill_task { x, y }); + }; +}; - int id = roof & 0xFFF; - if (buildFid(OBJ_TYPE_TILE, id, 0, 0, 0) != buildFid(OBJ_TYPE_TILE, 1, 0, 0, 0)) { - int flag = (roof & 0xF000) >> 12; - if ((flag & 0x01) != 0) { +static void roof_fill_off_process_task(std::stack& tasks_stack, int elevation, bool on) +{ + auto [x, y] = tasks_stack.top(); + tasks_stack.pop(); + + int squareTileIndex = gSquareGridWidth * y + x; + int squareTile = gTileSquares[elevation]->field_0[squareTileIndex]; + int roof = (squareTile >> 16) & 0xFFFF; + + int id = roof & 0xFFF; + if (buildFid(OBJ_TYPE_TILE, id, 0, 0, 0) != buildFid(OBJ_TYPE_TILE, 1, 0, 0, 0)) { + int flag = (roof & 0xF000) >> 12; + + if (on ? ((flag & 0x01) != 0) : ((flag & 0x03) == 0)) { + if (on) { flag &= ~0x01; - - gTileSquares[elevation]->field_0[squareTileIndex] = (squareTile & 0xFFFF) | (((flag << 12) | id) << 16); - - roof_fill_on(x - 1, y, elevation); - roof_fill_on(x + 1, y, elevation); - roof_fill_on(x, y - 1, elevation); - roof_fill_on(x, y + 1, elevation); + } else { + flag |= 0x01; } + + gTileSquares[elevation]->field_0[squareTileIndex] = (squareTile & 0xFFFF) | (((flag << 12) | id) << 16); + + roof_fill_push_task_if_in_bounds(tasks_stack, x - 1, y); + roof_fill_push_task_if_in_bounds(tasks_stack, x + 1, y); + roof_fill_push_task_if_in_bounds(tasks_stack, x, y - 1); + roof_fill_push_task_if_in_bounds(tasks_stack, x, y + 1); } } } @@ -1286,35 +1304,12 @@ static void roof_fill_on(int x, int y, int elevation) // 0x4B23D4 void tile_fill_roof(int x, int y, int elevation, bool on) { - if (on) { - roof_fill_on(x, y, elevation); - } else { - roof_fill_off(x, y, elevation); - } -} + std::stack tasks_stack; -// 0x4B23DC -static void roof_fill_off(int x, int y, int elevation) -{ - if (x >= 0 && x < gSquareGridWidth && y >= 0 && y < gSquareGridHeight) { - int squareTileIndex = gSquareGridWidth * y + x; - int squareTile = gTileSquares[elevation]->field_0[squareTileIndex]; - int roof = (squareTile >> 16) & 0xFFFF; + roof_fill_push_task_if_in_bounds(tasks_stack, x, y); - int id = roof & 0xFFF; - if (buildFid(OBJ_TYPE_TILE, id, 0, 0, 0) != buildFid(OBJ_TYPE_TILE, 1, 0, 0, 0)) { - int flag = (roof & 0xF000) >> 12; - if ((flag & 0x03) == 0) { - flag |= 0x01; - - gTileSquares[elevation]->field_0[squareTileIndex] = (squareTile & 0xFFFF) | (((flag << 12) | id) << 16); - - roof_fill_off(x - 1, y, elevation); - roof_fill_off(x + 1, y, elevation); - roof_fill_off(x, y - 1, elevation); - roof_fill_off(x, y + 1, elevation); - } - } + while (!tasks_stack.empty()) { + roof_fill_off_process_task(tasks_stack, elevation, on); } } diff --git a/src/window_manager.cc b/src/window_manager.cc index 101186a..e0f170a 100644 --- a/src/window_manager.cc +++ b/src/window_manager.cc @@ -25,8 +25,8 @@ namespace fallout { #define MAX_WINDOW_COUNT (50) -// The maximum number of radio groups. -#define RADIO_GROUP_LIST_CAPACITY (64) +// The maximum number of button groups. +#define BUTTON_GROUP_LIST_CAPACITY (64) static void windowFree(int win); static void _win_buffering(bool a1); @@ -39,13 +39,13 @@ static int paletteOpenFileImpl(const char* path, int flags); static int paletteReadFileImpl(int fd, void* buf, size_t count); static int paletteCloseFileImpl(int fd); static Button* buttonCreateInternal(int win, int x, int y, int width, int height, int mouseEnterEventCode, int mouseExitEventCode, int mouseDownEventCode, int mouseUpEventCode, int flags, unsigned char* up, unsigned char* dn, unsigned char* hover); -static int _GNW_check_buttons(Window* window, int* out_a2); +static int _GNW_check_buttons(Window* window, int* keyCodePtr); static bool _button_under_mouse(Button* button, Rect* rect); static void buttonFree(Button* ptr); static int button_new_id(); -static int _win_group_check_buttons(int a1, int* a2, int a3, void (*a4)(int)); +static int _win_group_check_buttons(int buttonCount, int* btns, int maxChecked, RadioButtonCallback* func); static int _button_check_group(Button* button); -static void _button_draw(Button* button, Window* window, unsigned char* data, int a4, Rect* a5, int a6); +static void _button_draw(Button* button, Window* window, unsigned char* data, bool draw, Rect* bound, bool sound); static void _GNW_button_refresh(Window* window, Rect* rect); // 0x50FA30 @@ -112,7 +112,7 @@ static int _doing_refresh_all; static void* _GNW_texture; // 0x6ADF40 -static RadioGroup gRadioGroups[RADIO_GROUP_LIST_CAPACITY]; +static ButtonGroup gButtonGroups[BUTTON_GROUP_LIST_CAPACITY]; // 0x4D5C30 int windowManagerInit(VideoSystemInitProc* videoSystemInitProc, VideoSystemExitProc* videoSystemExitProc, int a3) @@ -504,15 +504,12 @@ void windowDrawBorder(int win) } // 0x4D684C -void windowDrawText(int win, const char* str, int a3, int x, int y, int a6) +void windowDrawText(int win, const char* str, int width, int x, int y, int color) { - int v7; - int v14; unsigned char* buf; - int v27; + int textColor; Window* window = windowGetWindow(win); - v7 = a3; if (!gWindowSystemInitialized) { return; @@ -522,52 +519,51 @@ void windowDrawText(int win, const char* str, int a3, int x, int y, int a6) return; } - if (a3 == 0) { - if (a6 & 0x040000) { - v7 = fontGetMonospacedStringWidth(str); + if (width == 0) { + if (color & 0x040000) { + width = fontGetMonospacedStringWidth(str); } else { - v7 = fontGetStringWidth(str); + width = fontGetStringWidth(str); } } - if (v7 + x > window->width) { - if (!(a6 & 0x04000000)) { + if (width + x > window->width) { + if (!(color & 0x04000000)) { return; } - v7 = window->width - x; + width = window->width - x; } buf = window->buffer + x + y * window->width; - v14 = fontGetLineHeight(); - if (v14 + y > window->height) { + if (fontGetLineHeight() + y > window->height) { return; } - if (!(a6 & 0x02000000)) { + if (!(color & 0x02000000)) { if (window->color == 256 && _GNW_texture != NULL) { - _buf_texture(buf, v7, fontGetLineHeight(), window->width, _GNW_texture, window->tx + x, window->ty + y); + _buf_texture(buf, width, fontGetLineHeight(), window->width, _GNW_texture, window->tx + x, window->ty + y); } else { - bufferFill(buf, v7, fontGetLineHeight(), window->width, window->color); + bufferFill(buf, width, fontGetLineHeight(), window->width, window->color); } } - if (a6 & 0xFF00) { - int t = (a6 & 0xFF00) >> 8; - v27 = (a6 & ~0xFFFF) | _colorTable[_GNW_wcolor[t]]; + if (color & 0xFF00) { + int t = (color & 0xFF00) >> 8; + textColor = (color & ~0xFFFF) | _colorTable[_GNW_wcolor[t]]; } else { - v27 = a6; + textColor = color; } - fontDrawText(buf, str, v7, window->width, v27); + fontDrawText(buf, str, width, window->width, textColor); - if (a6 & 0x01000000) { + if (color & 0x01000000) { // TODO: Check. Rect rect; rect.left = window->rect.left + x; rect.top = window->rect.top + y; - rect.right = rect.left + v7; + rect.right = rect.left + width; rect.bottom = rect.top + fontGetLineHeight(); _GNW_win_refresh(window, &rect, NULL); } @@ -628,7 +624,7 @@ void windowDrawRect(int win, int left, int top, int right, int bottom, int color } // 0x4D6CC8 -void windowFill(int win, int x, int y, int width, int height, int a6) +void windowFill(int win, int x, int y, int width, int height, int color) { Window* window = windowGetWindow(win); @@ -640,19 +636,19 @@ void windowFill(int win, int x, int y, int width, int height, int a6) return; } - if (a6 == 256) { + if (color == 256) { if (_GNW_texture != NULL) { _buf_texture(window->buffer + window->width * y + x, width, height, window->width, _GNW_texture, x + window->tx, y + window->ty); } else { - a6 = _colorTable[_GNW_wcolor[0]] & 0xFF; + color = _colorTable[_GNW_wcolor[0]] & 0xFF; } - } else if ((a6 & 0xFF00) != 0) { - int v1 = (a6 & 0xFF00) >> 8; - a6 = (a6 & ~0xFFFF) | _colorTable[_GNW_wcolor[v1]]; + } else if ((color & 0xFF00) != 0) { + int v1 = (color & 0xFF00) >> 8; + color = (color & ~0xFFFF) | _colorTable[_GNW_wcolor[v1]]; } - if (a6 < 256) { - bufferFill(window->buffer + window->width * y + x, width, height, window->width, a6); + if (color < 256) { + bufferFill(window->buffer + window->width * y + x, width, height, window->width, color); } } @@ -1367,12 +1363,12 @@ int buttonCreate(int win, int x, int y, int width, int height, int mouseEnterEve return -1; } - Button* button = buttonCreateInternal(win, x, y, width, height, mouseEnterEventCode, mouseExitEventCode, mouseDownEventCode, mouseUpEventCode, flags | BUTTON_FLAG_0x010000, up, dn, hover); + Button* button = buttonCreateInternal(win, x, y, width, height, mouseEnterEventCode, mouseExitEventCode, mouseDownEventCode, mouseUpEventCode, flags | BUTTON_FLAG_GRAPHIC, up, dn, hover); if (button == NULL) { return -1; } - _button_draw(button, window, button->normalImage, 0, NULL, 0); + _button_draw(button, window, button->normalImage, false, NULL, false); return button->id; } @@ -1469,7 +1465,7 @@ int _win_register_text_button(int win, int x, int y, int mouseEnterEventCode, in return -1; } - _button_draw(button, window, button->normalImage, 0, NULL, 0); + _button_draw(button, window, button->normalImage, false, NULL, false); return button->id; } @@ -1494,7 +1490,7 @@ int _win_register_button_disable(int btn, unsigned char* up, unsigned char* down } // 0x4D86A8 -int _win_register_button_image(int btn, unsigned char* up, unsigned char* down, unsigned char* hover, int a5) +int _win_register_button_image(int btn, unsigned char* up, unsigned char* down, unsigned char* hover, bool draw) { if (!gWindowSystemInitialized) { return -1; @@ -1510,7 +1506,7 @@ int _win_register_button_image(int btn, unsigned char* up, unsigned char* down, return -1; } - if (!(button->flags & BUTTON_FLAG_0x010000)) { + if (!(button->flags & BUTTON_FLAG_GRAPHIC)) { return -1; } @@ -1527,7 +1523,7 @@ int _win_register_button_image(int btn, unsigned char* up, unsigned char* down, button->pressedImage = down; button->hoverImage = hover; - _button_draw(button, window, button->currentImage, a5, NULL, 0); + _button_draw(button, window, button->currentImage, draw, NULL, false); return 0; } @@ -1590,7 +1586,7 @@ int buttonSetRightMouseCallbacks(int btn, int rightMouseDownEventCode, int right // These callbacks can be triggered several times during tracking if mouse leaves button's rectangle without releasing mouse buttons. // // 0x4D87F8 -int buttonSetCallbacks(int btn, ButtonCallback* onPressed, ButtonCallback* onUnpressed) +int buttonSetCallbacks(int btn, ButtonCallback* pressSoundFunc, ButtonCallback* releaseSoundFunc) { if (!gWindowSystemInitialized) { return -1; @@ -1601,8 +1597,8 @@ int buttonSetCallbacks(int btn, ButtonCallback* onPressed, ButtonCallback* onUnp return -1; } - button->onPressed = onPressed; - button->onUnpressed = onUnpressed; + button->pressSoundFunc = pressSoundFunc; + button->releaseSoundFunc = releaseSoundFunc; return 0; } @@ -1676,9 +1672,9 @@ Button* buttonCreateInternal(int win, int x, int y, int width, int height, int m button->leftMouseUpProc = NULL; button->rightMouseDownProc = NULL; button->rightMouseUpProc = NULL; - button->onPressed = NULL; - button->onUnpressed = NULL; - button->radioGroup = NULL; + button->pressSoundFunc = NULL; + button->releaseSoundFunc = NULL; + button->buttonGroup = NULL; button->prev = NULL; button->next = window->buttonListHead; @@ -1702,7 +1698,7 @@ bool _win_button_down(int btn) return false; } - if ((button->flags & BUTTON_FLAG_0x01) != 0 && (button->flags & BUTTON_FLAG_0x020000) != 0) { + if ((button->flags & BUTTON_FLAG_0x01) != 0 && (button->flags & BUTTON_FLAG_CHECKED) != 0) { return true; } @@ -1751,10 +1747,10 @@ int _GNW_check_buttons(Window* window, int* keyCodePtr) *keyCodePtr = prevHoveredButton->mouseExitEventCode; } - if ((prevHoveredButton->flags & BUTTON_FLAG_0x01) && (prevHoveredButton->flags & BUTTON_FLAG_0x020000)) { - _button_draw(prevHoveredButton, window, prevHoveredButton->pressedImage, 1, NULL, 1); + if ((prevHoveredButton->flags & BUTTON_FLAG_0x01) && (prevHoveredButton->flags & BUTTON_FLAG_CHECKED)) { + _button_draw(prevHoveredButton, window, prevHoveredButton->pressedImage, true, NULL, true); } else { - _button_draw(prevHoveredButton, window, prevHoveredButton->normalImage, 1, NULL, 1); + _button_draw(prevHoveredButton, window, prevHoveredButton->normalImage, true, NULL, true); } window->hoveredButton = NULL; @@ -1778,10 +1774,10 @@ int _GNW_check_buttons(Window* window, int* keyCodePtr) *keyCodePtr = prevClickedButton->mouseEnterEventCode; } - if ((prevClickedButton->flags & BUTTON_FLAG_0x01) && (prevClickedButton->flags & BUTTON_FLAG_0x020000)) { - _button_draw(prevClickedButton, window, prevClickedButton->pressedImage, 1, NULL, 1); + if ((prevClickedButton->flags & BUTTON_FLAG_0x01) && (prevClickedButton->flags & BUTTON_FLAG_CHECKED)) { + _button_draw(prevClickedButton, window, prevClickedButton->pressedImage, true, NULL, true); } else { - _button_draw(prevClickedButton, window, prevClickedButton->normalImage, 1, NULL, 1); + _button_draw(prevClickedButton, window, prevClickedButton->normalImage, true, NULL, true); } window->hoveredButton = prevClickedButton; @@ -1812,10 +1808,10 @@ int _GNW_check_buttons(Window* window, int* keyCodePtr) *keyCodePtr = v28->mouseExitEventCode; } - if ((v28->flags & BUTTON_FLAG_0x01) && (v28->flags & BUTTON_FLAG_0x020000)) { - _button_draw(v28, v26, v28->pressedImage, 1, NULL, 1); + if ((v28->flags & BUTTON_FLAG_0x01) && (v28->flags & BUTTON_FLAG_CHECKED)) { + _button_draw(v28, v26, v28->pressedImage, true, NULL, true); } else { - _button_draw(v28, v26, v28->normalImage, 1, NULL, 1); + _button_draw(v28, v26, v28->normalImage, true, NULL, true); } v26->clickedButton = NULL; @@ -1857,10 +1853,10 @@ int _GNW_check_buttons(Window* window, int* keyCodePtr) if ((button->flags & BUTTON_FLAG_0x01) != 0) { if ((button->flags & BUTTON_FLAG_0x02) != 0) { - if ((button->flags & BUTTON_FLAG_0x020000) != 0) { + if ((button->flags & BUTTON_FLAG_CHECKED) != 0) { if (!(button->flags & BUTTON_FLAG_0x04)) { - if (button->radioGroup != NULL) { - button->radioGroup->field_4--; + if (button->buttonGroup != NULL) { + button->buttonGroup->currChecked--; } if ((mouseEvent & MOUSE_EVENT_LEFT_BUTTON_DOWN) != 0) { @@ -1871,7 +1867,7 @@ int _GNW_check_buttons(Window* window, int* keyCodePtr) cb = button->rightMouseUpProc; } - button->flags &= ~BUTTON_FLAG_0x020000; + button->flags &= ~BUTTON_FLAG_CHECKED; } } else { if (_button_check_group(button) == -1) { @@ -1887,7 +1883,7 @@ int _GNW_check_buttons(Window* window, int* keyCodePtr) cb = button->rightMouseDownProc; } - button->flags |= BUTTON_FLAG_0x020000; + button->flags |= BUTTON_FLAG_CHECKED; } } } else { @@ -1905,7 +1901,7 @@ int _GNW_check_buttons(Window* window, int* keyCodePtr) } } - _button_draw(button, window, button->pressedImage, 1, NULL, 1); + _button_draw(button, window, button->pressedImage, true, NULL, true); break; } @@ -1916,10 +1912,10 @@ int _GNW_check_buttons(Window* window, int* keyCodePtr) if (v49->flags & BUTTON_FLAG_0x01) { if (!(v49->flags & BUTTON_FLAG_0x02)) { - if (v49->flags & BUTTON_FLAG_0x020000) { + if (v49->flags & BUTTON_FLAG_CHECKED) { if (!(v49->flags & BUTTON_FLAG_0x04)) { - if (v49->radioGroup != NULL) { - v49->radioGroup->field_4--; + if (v49->buttonGroup != NULL) { + v49->buttonGroup->currChecked--; } if ((mouseEvent & MOUSE_EVENT_LEFT_BUTTON_UP) != 0) { @@ -1930,12 +1926,12 @@ int _GNW_check_buttons(Window* window, int* keyCodePtr) cb = button->rightMouseUpProc; } - button->flags &= ~BUTTON_FLAG_0x020000; + button->flags &= ~BUTTON_FLAG_CHECKED; } } else { if (_button_check_group(v49) == -1) { button = NULL; - _button_draw(v49, window, v49->normalImage, 1, NULL, 1); + _button_draw(v49, window, v49->normalImage, true, NULL, true); break; } @@ -1947,13 +1943,13 @@ int _GNW_check_buttons(Window* window, int* keyCodePtr) cb = v49->rightMouseDownProc; } - v49->flags |= BUTTON_FLAG_0x020000; + v49->flags |= BUTTON_FLAG_CHECKED; } } } else { - if (v49->flags & BUTTON_FLAG_0x020000) { - if (v49->radioGroup != NULL) { - v49->radioGroup->field_4--; + if (v49->flags & BUTTON_FLAG_CHECKED) { + if (v49->buttonGroup != NULL) { + v49->buttonGroup->currChecked--; } } @@ -1967,9 +1963,9 @@ int _GNW_check_buttons(Window* window, int* keyCodePtr) } if (button->hoverImage != NULL) { - _button_draw(button, window, button->hoverImage, 1, NULL, 1); + _button_draw(button, window, button->hoverImage, true, NULL, true); } else { - _button_draw(button, window, button->normalImage, 1, NULL, 1); + _button_draw(button, window, button->normalImage, true, NULL, true); } break; } @@ -1982,7 +1978,7 @@ int _GNW_check_buttons(Window* window, int* keyCodePtr) cb = button->mouseEnterProc; } - _button_draw(button, window, button->hoverImage, 1, NULL, 1); + _button_draw(button, window, button->hoverImage, true, NULL, true); } break; } @@ -1995,7 +1991,7 @@ int _GNW_check_buttons(Window* window, int* keyCodePtr) && (mouseEvent & MOUSE_EVENT_ANY_BUTTON_DOWN) != 0 && (mouseEvent & MOUSE_EVENT_ANY_BUTTON_REPEAT) == 0) { _win_drag(window->id); - _button_draw(button, window, button->normalImage, 1, NULL, 1); + _button_draw(button, window, button->normalImage, true, NULL, true); } } else if ((window->flags & WINDOW_FLAG_0x80) != 0) { v25 |= mouseEvent << 8; @@ -2023,13 +2019,13 @@ int _GNW_check_buttons(Window* window, int* keyCodePtr) *keyCodePtr = prevHoveredButton->mouseExitEventCode; unsigned char* data; - if ((prevHoveredButton->flags & BUTTON_FLAG_0x01) && (prevHoveredButton->flags & BUTTON_FLAG_0x020000)) { + if ((prevHoveredButton->flags & BUTTON_FLAG_0x01) && (prevHoveredButton->flags & BUTTON_FLAG_CHECKED)) { data = prevHoveredButton->pressedImage; } else { data = prevHoveredButton->normalImage; } - _button_draw(prevHoveredButton, window, data, 1, NULL, 1); + _button_draw(prevHoveredButton, window, data, true, NULL, true); window->hoveredButton = NULL; } @@ -2142,7 +2138,7 @@ int buttonDestroy(int btn) // 0x4D9374 void buttonFree(Button* button) { - if ((button->flags & BUTTON_FLAG_0x010000) == 0) { + if ((button->flags & BUTTON_FLAG_GRAPHIC) == 0) { if (button->normalImage != NULL) { internal_free(button->normalImage); } @@ -2168,15 +2164,15 @@ void buttonFree(Button* button) } } - RadioGroup* radioGroup = button->radioGroup; - if (radioGroup != NULL) { - for (int index = 0; index < radioGroup->buttonsLength; index++) { - if (button == radioGroup->buttons[index]) { - for (; index < radioGroup->buttonsLength - 1; index++) { - radioGroup->buttons[index] = radioGroup->buttons[index + 1]; + ButtonGroup* buttonGroup = button->buttonGroup; + if (buttonGroup != NULL) { + for (int index = 0; index < buttonGroup->buttonsLength; index++) { + if (button == buttonGroup->buttons[index]) { + for (; index < buttonGroup->buttonsLength - 1; index++) { + buttonGroup->buttons[index] = buttonGroup->buttons[index + 1]; } - radioGroup->buttonsLength--; + buttonGroup->buttonsLength--; break; } @@ -2216,7 +2212,7 @@ int buttonEnable(int btn) if ((button->flags & BUTTON_FLAG_DISABLED) != 0) { button->flags &= ~BUTTON_FLAG_DISABLED; - _button_draw(button, window, button->currentImage, 1, NULL, 0); + _button_draw(button, window, button->currentImage, true, NULL, false); } return 0; @@ -2238,7 +2234,7 @@ int buttonDisable(int btn) if ((button->flags & BUTTON_FLAG_DISABLED) == 0) { button->flags |= BUTTON_FLAG_DISABLED; - _button_draw(button, window, button->currentImage, 1, NULL, 0); + _button_draw(button, window, button->currentImage, true, NULL, false); if (button == window->hoveredButton) { if (window->hoveredButton->mouseExitEventCode != -1) { @@ -2252,7 +2248,7 @@ int buttonDisable(int btn) } // 0x4D9554 -int _win_set_button_rest_state(int btn, bool a2, int a3) +int _win_set_button_rest_state(int btn, bool checked, int flags) { if (!gWindowSystemInitialized) { return -1; @@ -2267,30 +2263,30 @@ int _win_set_button_rest_state(int btn, bool a2, int a3) if ((button->flags & BUTTON_FLAG_0x01) != 0) { int keyCode = -1; - if ((button->flags & BUTTON_FLAG_0x020000) != 0) { - if (!a2) { - button->flags &= ~BUTTON_FLAG_0x020000; + if ((button->flags & BUTTON_FLAG_CHECKED) != 0) { + if (!checked) { + button->flags &= ~BUTTON_FLAG_CHECKED; - if ((a3 & 0x02) == 0) { - _button_draw(button, window, button->normalImage, 1, NULL, 0); + if ((flags & 0x02) == 0) { + _button_draw(button, window, button->normalImage, true, NULL, false); } - if (button->radioGroup != NULL) { - button->radioGroup->field_4--; + if (button->buttonGroup != NULL) { + button->buttonGroup->currChecked--; } keyCode = button->leftMouseUpEventCode; } } else { - if (a2) { - button->flags |= BUTTON_FLAG_0x020000; + if (checked) { + button->flags |= BUTTON_FLAG_CHECKED; - if ((a3 & 0x02) == 0) { - _button_draw(button, window, button->pressedImage, 1, NULL, 0); + if ((flags & 0x02) == 0) { + _button_draw(button, window, button->pressedImage, true, NULL, false); } - if (button->radioGroup != NULL) { - button->radioGroup->field_4++; + if (button->buttonGroup != NULL) { + button->buttonGroup->currChecked++; } keyCode = button->lefMouseDownEventCode; @@ -2298,7 +2294,7 @@ int _win_set_button_rest_state(int btn, bool a2, int a3) } if (keyCode != -1) { - if ((a3 & 0x01) != 0) { + if ((flags & 0x01) != 0) { enqueueInputEvent(keyCode); } } @@ -2308,20 +2304,20 @@ int _win_set_button_rest_state(int btn, bool a2, int a3) } // 0x4D962C -int _win_group_check_buttons(int buttonCount, int* btns, int a3, void (*a4)(int)) +int _win_group_check_buttons(int buttonCount, int* btns, int maxChecked, RadioButtonCallback* func) { if (!gWindowSystemInitialized) { return -1; } - if (buttonCount >= RADIO_GROUP_BUTTON_LIST_CAPACITY) { + if (buttonCount >= BUTTON_GROUP_BUTTON_LIST_CAPACITY) { return -1; } - for (int groupIndex = 0; groupIndex < RADIO_GROUP_LIST_CAPACITY; groupIndex++) { - RadioGroup* radioGroup = &(gRadioGroups[groupIndex]); - if (radioGroup->buttonsLength == 0) { - radioGroup->field_4 = 0; + for (int groupIndex = 0; groupIndex < BUTTON_GROUP_LIST_CAPACITY; groupIndex++) { + ButtonGroup* buttonGroup = &(gButtonGroups[groupIndex]); + if (buttonGroup->buttonsLength == 0) { + buttonGroup->currChecked = 0; for (int buttonIndex = 0; buttonIndex < buttonCount; buttonIndex++) { Button* button = buttonGetButton(btns[buttonIndex], NULL); @@ -2329,18 +2325,18 @@ int _win_group_check_buttons(int buttonCount, int* btns, int a3, void (*a4)(int) return -1; } - radioGroup->buttons[buttonIndex] = button; + buttonGroup->buttons[buttonIndex] = button; - button->radioGroup = radioGroup; + button->buttonGroup = buttonGroup; - if ((button->flags & BUTTON_FLAG_0x020000) != 0) { - radioGroup->field_4++; + if ((button->flags & BUTTON_FLAG_CHECKED) != 0) { + buttonGroup->currChecked++; } } - radioGroup->buttonsLength = buttonCount; - radioGroup->field_0 = a3; - radioGroup->field_8 = a4; + buttonGroup->buttonsLength = buttonCount; + buttonGroup->maxChecked = maxChecked; + buttonGroup->func = func; return 0; } } @@ -2360,11 +2356,11 @@ int _win_group_radio_buttons(int count, int* btns) } Button* button = buttonGetButton(btns[0], NULL); - RadioGroup* radioGroup = button->radioGroup; + ButtonGroup* buttonGroup = button->buttonGroup; - for (int index = 0; index < radioGroup->buttonsLength; index++) { - Button* v1 = radioGroup->buttons[index]; - v1->flags |= BUTTON_FLAG_0x040000; + for (int index = 0; index < buttonGroup->buttonsLength; index++) { + Button* v1 = buttonGroup->buttons[index]; + v1->flags |= BUTTON_FLAG_RADIO; } return 0; @@ -2373,20 +2369,20 @@ int _win_group_radio_buttons(int count, int* btns) // 0x4D9744 int _button_check_group(Button* button) { - if (button->radioGroup == NULL) { + if (button->buttonGroup == NULL) { return 0; } - if ((button->flags & BUTTON_FLAG_0x040000) != 0) { - if (button->radioGroup->field_4 > 0) { - for (int index = 0; index < button->radioGroup->buttonsLength; index++) { - Button* v1 = button->radioGroup->buttons[index]; - if ((v1->flags & BUTTON_FLAG_0x020000) != 0) { - v1->flags &= ~BUTTON_FLAG_0x020000; + if ((button->flags & BUTTON_FLAG_RADIO) != 0) { + if (button->buttonGroup->currChecked > 0) { + for (int index = 0; index < button->buttonGroup->buttonsLength; index++) { + Button* v1 = button->buttonGroup->buttons[index]; + if ((v1->flags & BUTTON_FLAG_CHECKED) != 0) { + v1->flags &= ~BUTTON_FLAG_CHECKED; Window* window; buttonGetButton(v1->id, &window); - _button_draw(v1, window, v1->normalImage, 1, NULL, 1); + _button_draw(v1, window, v1->normalImage, true, NULL, true); if (v1->leftMouseUpProc != NULL) { v1->leftMouseUpProc(v1->id, v1->leftMouseUpEventCode); @@ -2395,30 +2391,30 @@ int _button_check_group(Button* button) } } - if ((button->flags & BUTTON_FLAG_0x020000) == 0) { - button->radioGroup->field_4++; + if ((button->flags & BUTTON_FLAG_CHECKED) == 0) { + button->buttonGroup->currChecked++; } return 0; } - if (button->radioGroup->field_4 < button->radioGroup->field_0) { - if ((button->flags & BUTTON_FLAG_0x020000) == 0) { - button->radioGroup->field_4++; + if (button->buttonGroup->currChecked < button->buttonGroup->maxChecked) { + if ((button->flags & BUTTON_FLAG_CHECKED) == 0) { + button->buttonGroup->currChecked++; } return 0; } - if (button->radioGroup->field_8 != NULL) { - button->radioGroup->field_8(button->id); + if (button->buttonGroup->func != NULL) { + button->buttonGroup->func(button->id); } return -1; } // 0x4D9808 -void _button_draw(Button* button, Window* window, unsigned char* data, int a4, Rect* a5, int a6) +void _button_draw(Button* button, Window* window, unsigned char* data, bool draw, Rect* bound, bool sound) { unsigned char* previousImage = NULL; if (data != NULL) { @@ -2427,8 +2423,8 @@ void _button_draw(Button* button, Window* window, unsigned char* data, int a4, R rectOffset(&v2, window->rect.left, window->rect.top); Rect v3; - if (a5 != NULL) { - if (rectIntersection(&v2, a5, &v2) == -1) { + if (bound != NULL) { + if (rectIntersection(&v2, bound, &v2) == -1) { return; } @@ -2438,7 +2434,7 @@ void _button_draw(Button* button, Window* window, unsigned char* data, int a4, R rectCopy(&v3, &(button->rect)); } - if (data == button->normalImage && (button->flags & BUTTON_FLAG_0x020000)) { + if (data == button->normalImage && (button->flags & BUTTON_FLAG_CHECKED)) { data = button->pressedImage; } @@ -2461,7 +2457,7 @@ void _button_draw(Button* button, Window* window, unsigned char* data, int a4, R } if (data) { - if (a4 == 0) { + if (!draw) { int width = button->rect.right - button->rect.left + 1; if ((button->flags & BUTTON_FLAG_TRANSPARENT) != 0) { blitBufferToBufferTrans( @@ -2485,18 +2481,18 @@ void _button_draw(Button* button, Window* window, unsigned char* data, int a4, R previousImage = button->currentImage; button->currentImage = data; - if (a4 != 0) { + if (draw) { _GNW_win_refresh(window, &v2, 0); } } } - if (a6) { + if (sound) { if (previousImage != data) { - if (data == button->pressedImage && button->onPressed != NULL) { - button->onPressed(button->id, button->lefMouseDownEventCode); - } else if (data == button->normalImage && button->onUnpressed != NULL) { - button->onUnpressed(button->id, button->leftMouseUpEventCode); + if (data == button->pressedImage && button->pressSoundFunc != NULL) { + button->pressSoundFunc(button->id, button->lefMouseDownEventCode); + } else if (data == button->normalImage && button->releaseSoundFunc != NULL) { + button->releaseSoundFunc(button->id, button->leftMouseUpEventCode); } } } @@ -2513,7 +2509,7 @@ void _GNW_button_refresh(Window* window, Rect* rect) } while (button != NULL) { - _button_draw(button, window, button->currentImage, 0, rect, 0); + _button_draw(button, window, button->currentImage, false, rect, false); button = button->prev; } } @@ -2531,7 +2527,7 @@ int _win_button_press_and_release(int btn) return -1; } - _button_draw(button, window, button->pressedImage, 1, NULL, 1); + _button_draw(button, window, button->pressedImage, true, NULL, true); if (button->leftMouseDownProc != NULL) { button->leftMouseDownProc(btn, button->lefMouseDownEventCode); @@ -2545,7 +2541,7 @@ int _win_button_press_and_release(int btn) } } - _button_draw(button, window, button->normalImage, 1, NULL, 1); + _button_draw(button, window, button->normalImage, true, NULL, true); if (button->leftMouseUpProc != NULL) { button->leftMouseUpProc(btn, button->leftMouseUpEventCode); diff --git a/src/window_manager.h b/src/window_manager.h index 2275b4d..265aa7e 100644 --- a/src/window_manager.h +++ b/src/window_manager.h @@ -8,7 +8,7 @@ namespace fallout { // The maximum number of buttons in one radio group. -#define RADIO_GROUP_BUTTON_LIST_CAPACITY (64) +#define BUTTON_GROUP_BUTTON_LIST_CAPACITY (64) typedef enum WindowManagerErr { WINDOW_MANAGER_OK = 0, @@ -55,9 +55,9 @@ typedef enum ButtonFlags { BUTTON_FLAG_0x10 = 0x10, BUTTON_FLAG_TRANSPARENT = 0x20, BUTTON_FLAG_0x40 = 0x40, - BUTTON_FLAG_0x010000 = 0x010000, - BUTTON_FLAG_0x020000 = 0x020000, - BUTTON_FLAG_0x040000 = 0x040000, + BUTTON_FLAG_GRAPHIC = 0x010000, + BUTTON_FLAG_CHECKED = 0x020000, + BUTTON_FLAG_RADIO = 0x040000, BUTTON_FLAG_RIGHT_MOUSE_BUTTON_CONFIGURED = 0x080000, } ButtonFlags; @@ -66,8 +66,8 @@ typedef struct MenuPulldown { int keyCode; int itemsLength; char** items; - int field_1C; - int field_20; + int foregroundColor; + int backgroundColor; } MenuPulldown; typedef struct MenuBar { @@ -75,14 +75,14 @@ typedef struct MenuBar { Rect rect; int pulldownsLength; MenuPulldown pulldowns[15]; - int borderColor; + int foregroundColor; int backgroundColor; } MenuBar; typedef void WindowBlitProc(unsigned char* src, int width, int height, int srcPitch, unsigned char* dest, int destPitch); typedef struct Button Button; -typedef struct RadioGroup RadioGroup; +typedef struct ButtonGroup ButtonGroup; typedef struct Window { int id; @@ -102,6 +102,7 @@ typedef struct Window { } Window; typedef void ButtonCallback(int btn, int keyCode); +typedef void RadioButtonCallback(int btn); typedef struct Button { int id; @@ -127,20 +128,20 @@ typedef struct Button { ButtonCallback* leftMouseUpProc; ButtonCallback* rightMouseDownProc; ButtonCallback* rightMouseUpProc; - ButtonCallback* onPressed; - ButtonCallback* onUnpressed; - RadioGroup* radioGroup; + ButtonCallback* pressSoundFunc; + ButtonCallback* releaseSoundFunc; + ButtonGroup* buttonGroup; Button* prev; Button* next; } Button; -typedef struct RadioGroup { - int field_0; - int field_4; - void (*field_8)(int); +typedef struct ButtonGroup { + int maxChecked; + int currChecked; + RadioButtonCallback* func; int buttonsLength; - Button* buttons[RADIO_GROUP_BUTTON_LIST_CAPACITY]; -} RadioGroup; + Button* buttons[BUTTON_GROUP_BUTTON_LIST_CAPACITY]; +} ButtonGroup; typedef int(VideoSystemInitProc)(); typedef void(VideoSystemExitProc)(); @@ -157,7 +158,7 @@ void windowDrawText(int win, const char* str, int a3, int x, int y, int a6); void _win_text(int win, char** fileNameList, int fileNameListLength, int maxWidth, int x, int y, int flags); void windowDrawLine(int win, int left, int top, int right, int bottom, int color); void windowDrawRect(int win, int left, int top, int right, int bottom, int color); -void windowFill(int win, int x, int y, int width, int height, int a6); +void windowFill(int win, int x, int y, int width, int height, int color); void windowShow(int win); void windowHide(int win); void windowRefresh(int win); @@ -178,10 +179,10 @@ bool showMesageBox(const char* str); int buttonCreate(int win, int x, int y, int width, int height, int mouseEnterEventCode, int mouseExitEventCode, int mouseDownEventCode, int mouseUpEventCode, unsigned char* up, unsigned char* dn, unsigned char* hover, int flags); int _win_register_text_button(int win, int x, int y, int mouseEnterEventCode, int mouseExitEventCode, int mouseDownEventCode, int mouseUpEventCode, const char* title, int flags); int _win_register_button_disable(int btn, unsigned char* up, unsigned char* down, unsigned char* hover); -int _win_register_button_image(int btn, unsigned char* up, unsigned char* down, unsigned char* hover, int a5); +int _win_register_button_image(int btn, unsigned char* up, unsigned char* down, unsigned char* hover, bool draw); int buttonSetMouseCallbacks(int btn, ButtonCallback* mouseEnterProc, ButtonCallback* mouseExitProc, ButtonCallback* mouseDownProc, ButtonCallback* mouseUpProc); int buttonSetRightMouseCallbacks(int btn, int rightMouseDownEventCode, int rightMouseUpEventCode, ButtonCallback* rightMouseDownProc, ButtonCallback* rightMouseUpProc); -int buttonSetCallbacks(int btn, ButtonCallback* onPressed, ButtonCallback* onUnpressed); +int buttonSetCallbacks(int btn, ButtonCallback* pressSoundFunc, ButtonCallback* releaseSoundFunc); int buttonSetMask(int btn, unsigned char* mask); bool _win_button_down(int btn); int buttonGetWindowId(int btn); @@ -189,8 +190,8 @@ int _win_last_button_winID(); int buttonDestroy(int btn); int buttonEnable(int btn); int buttonDisable(int btn); -int _win_set_button_rest_state(int btn, bool a2, int a3); -int _win_group_radio_buttons(int a1, int* a2); +int _win_set_button_rest_state(int btn, bool checked, int flags); +int _win_group_radio_buttons(int buttonCount, int* btns); int _win_button_press_and_release(int btn); } // namespace fallout diff --git a/src/window_manager_private.cc b/src/window_manager_private.cc index 88fe9d2..af94de7 100644 --- a/src/window_manager_private.cc +++ b/src/window_manager_private.cc @@ -79,13 +79,13 @@ static int _currx; char gProgramWindowTitle[256]; // 0x4DA6C0 -int _win_list_select(const char* title, char** fileList, int fileListLength, ListSelectionHandler* callback, int x, int y, int a7) +int _win_list_select(const char* title, char** fileList, int fileListLength, ListSelectionHandler* callback, int x, int y, int color) { - return _win_list_select_at(title, fileList, fileListLength, callback, x, y, a7, 0); + return _win_list_select_at(title, fileList, fileListLength, callback, x, y, color, 0); } // 0x4DA70C -int _win_list_select_at(const char* title, char** items, int itemsLength, ListSelectionHandler* callback, int x, int y, int a7, int a8) +int _win_list_select_at(const char* title, char** items, int itemsLength, ListSelectionHandler* callback, int x, int y, int color, int start) { if (!gWindowSystemInitialized) { return -1; @@ -170,8 +170,8 @@ int _win_list_select_at(const char* title, char** items, int itemsLength, ListSe windowWidth, _colorTable[_GNW_wcolor[0]]); - int scrollOffset = a8; - if (a8 < 0 || a8 >= itemsLength) { + int scrollOffset = start; + if (start < 0 || start >= itemsLength) { scrollOffset = 0; } @@ -189,14 +189,13 @@ int _win_list_select_at(const char* title, char** items, int itemsLength, ListSe selectedItemIndex = 0; } - char** itemsTO = items + a8; _win_text(win, - items + a8, + items + start, itemsLength < listViewCapacity ? itemsLength : listViewCapacity, listViewWidth, listViewX, listViewY, - a7 | 0x2000000); + color | 0x2000000); _lighten_buf(listViewBuffer + windowWidth * selectedItemIndex * fontGetLineHeight(), listViewWidth, @@ -452,7 +451,7 @@ int _win_list_select_at(const char* title, char** items, int itemsLength, ListSe listViewWidth, listViewX, listViewY, - a7 | 0x2000000); + color | 0x2000000); _lighten_buf(listViewBuffer + windowWidth * selectedItemIndex * fontGetLineHeight(), listViewWidth, @@ -500,19 +499,19 @@ int _win_list_select_at(const char* title, char** items, int itemsLength, ListSe windowWidth, _colorTable[_GNW_wcolor[0]]); - int color; - if ((a7 & 0xFF00) != 0) { - int colorIndex = (a7 & 0xFF) - 1; - color = (a7 & ~0xFFFF) | _colorTable[_GNW_wcolor[colorIndex]]; + int textColor; + if ((color & 0xFF00) != 0) { + int colorIndex = (color & 0xFF) - 1; + textColor = (color & ~0xFFFF) | _colorTable[_GNW_wcolor[colorIndex]]; } else { - color = a7; + textColor = color; } fontDrawText(listViewBuffer + windowWidth * previousSelectedItemIndex * fontGetLineHeight(), items[scrollOffset + previousSelectedItemIndex], windowWidth, windowWidth, - color); + textColor); _GNW_win_refresh(window, &itemRect, NULL); } @@ -619,7 +618,7 @@ int _win_get_str(char* dest, int length, const char* title, int x, int y) } // 0x4DBA98 -int _win_msg(const char* string, int x, int y, int flags) +int _win_msg(const char* string, int x, int y, int color) { if (!gWindowSystemInitialized) { return -1; @@ -644,16 +643,16 @@ int _win_msg(const char* string, int x, int y, int flags) Window* window = windowGetWindow(win); unsigned char* windowBuffer = window->buffer; - int color; - if ((flags & 0xFF00) != 0) { - int index = (flags & 0xFF) - 1; - color = _colorTable[_GNW_wcolor[index]]; - color |= flags & ~0xFFFF; + int textColor; + if ((color & 0xFF00) != 0) { + int index = (color & 0xFF) - 1; + textColor = _colorTable[_GNW_wcolor[index]]; + textColor |= color & ~0xFFFF; } else { - color = flags; + textColor = color; } - fontDrawText(windowBuffer + windowWidth * 8 + 16, string, windowWidth, windowWidth, color); + fontDrawText(windowBuffer + windowWidth * 8 + 16, string, windowWidth, windowWidth, textColor); _win_register_text_button(win, windowWidth / 2 - 32, @@ -679,23 +678,23 @@ int _win_msg(const char* string, int x, int y, int flags) } // 0x4DBBC4 -int _win_pull_down(char** items, int itemsLength, int x, int y, int a5) +int _win_pull_down(char** items, int itemsLength, int x, int y, int color) { if (!gWindowSystemInitialized) { return -1; } Rect rect; - int win = _create_pull_down(items, itemsLength, x, y, a5, _colorTable[_GNW_wcolor[0]], &rect); + int win = _create_pull_down(items, itemsLength, x, y, color, _colorTable[_GNW_wcolor[0]], &rect); if (win == -1) { return -1; } - return sub_4DBD04(win, &rect, items, itemsLength, a5, _colorTable[_GNW_wcolor[0]], NULL, -1); + return process_pull_down(win, &rect, items, itemsLength, color, _colorTable[_GNW_wcolor[0]], NULL, -1); } // 0x4DBC34 -int _create_pull_down(char** stringList, int stringListLength, int x, int y, int a5, int a6, Rect* rect) +int _create_pull_down(char** stringList, int stringListLength, int x, int y, int foregroundColor, int backgroundColor, Rect* rect) { int windowHeight = stringListLength * fontGetLineHeight() + 16; int windowWidth = _win_width_needed(stringList, stringListLength) + 4; @@ -703,14 +702,14 @@ int _create_pull_down(char** stringList, int stringListLength, int x, int y, int return -1; } - int win = windowCreate(x, y, windowWidth, windowHeight, a6, WINDOW_MODAL | WINDOW_MOVE_ON_TOP); + int win = windowCreate(x, y, windowWidth, windowHeight, backgroundColor, WINDOW_MODAL | WINDOW_MOVE_ON_TOP); if (win == -1) { return -1; } - _win_text(win, stringList, stringListLength, windowWidth - 4, 2, 8, a5); + _win_text(win, stringList, stringListLength, windowWidth - 4, 2, 8, foregroundColor); windowDrawRect(win, 0, 0, windowWidth - 1, windowHeight - 1, _colorTable[0]); - windowDrawRect(win, 1, 1, windowWidth - 2, windowHeight - 2, a5); + windowDrawRect(win, 1, 1, windowWidth - 2, windowHeight - 2, foregroundColor); windowRefresh(win); windowGetRect(win, rect); @@ -841,7 +840,7 @@ void _win_debug_delete(int btn, int keyCode) } // 0x4DC674 -int _win_register_menu_bar(int win, int x, int y, int width, int height, int borderColor, int backgroundColor) +int _win_register_menu_bar(int win, int x, int y, int width, int height, int foregroundColor, int backgroundColor) { Window* window = windowGetWindow(win); @@ -878,17 +877,17 @@ int _win_register_menu_bar(int win, int x, int y, int width, int height, int bor menuBar->rect.right = right - 1; menuBar->rect.bottom = bottom - 1; menuBar->pulldownsLength = 0; - menuBar->borderColor = borderColor; + menuBar->foregroundColor = foregroundColor; menuBar->backgroundColor = backgroundColor; windowFill(win, x, y, width, height, backgroundColor); - windowDrawRect(win, x, y, right - 1, bottom - 1, borderColor); + windowDrawRect(win, x, y, right - 1, bottom - 1, foregroundColor); return 0; } // 0x4DC768 -int _win_register_menu_pulldown(int win, int x, char* title, int keyCode, int itemsLength, char** items, int a7, int a8) +int _win_register_menu_pulldown(int win, int x, char* title, int keyCode, int itemsLength, char** items, int foregroundColor, int backgroundColor) { Window* window = windowGetWindow(win); @@ -928,7 +927,7 @@ int _win_register_menu_pulldown(int win, int x, char* title, int keyCode, int it return -1; } - windowDrawText(win, title, 0, titleX, titleY, window->menuBar->borderColor | 0x2000000); + windowDrawText(win, title, 0, titleX, titleY, window->menuBar->foregroundColor | 0x2000000); MenuPulldown* pulldown = &(window->menuBar->pulldowns[window->menuBar->pulldownsLength]); pulldown->rect.left = titleX; @@ -938,8 +937,8 @@ int _win_register_menu_pulldown(int win, int x, char* title, int keyCode, int it pulldown->keyCode = keyCode; pulldown->itemsLength = itemsLength; pulldown->items = items; - pulldown->field_1C = a7; - pulldown->field_20 = a8; + pulldown->foregroundColor = foregroundColor; + pulldown->backgroundColor = backgroundColor; window->menuBar->pulldownsLength++; @@ -1120,7 +1119,7 @@ int _win_input_str(int win, char* dest, int maxLength, int x, int y, int textCol } // 0x4DBD04 -int sub_4DBD04(int win, Rect* rect, char** items, int itemsLength, int a5, int a6, MenuBar* menuBar, int pulldownIndex) +int process_pull_down(int win, Rect* rect, char** items, int itemsLength, int foregroundColor, int backgroundColor, MenuBar* menuBar, int pulldownIndex) { // TODO: Incomplete. return -1; @@ -1143,15 +1142,15 @@ int _GNW_process_menu(MenuBar* menuBar, int pulldownIndex) pulldown->itemsLength, pulldown->rect.left, menuBar->rect.bottom + 1, - pulldown->field_1C, - pulldown->field_20, + pulldown->foregroundColor, + pulldown->backgroundColor, &rect); if (win == -1) { _curr_menu = NULL; return -1; } - keyCode = sub_4DBD04(win, &rect, pulldown->items, pulldown->itemsLength, pulldown->field_1C, pulldown->field_20, menuBar, pulldownIndex); + keyCode = process_pull_down(win, &rect, pulldown->items, pulldown->itemsLength, pulldown->foregroundColor, pulldown->backgroundColor, menuBar, pulldownIndex); if (keyCode < -1) { pulldownIndex = -2 - keyCode; } @@ -1168,20 +1167,20 @@ int _GNW_process_menu(MenuBar* menuBar, int pulldownIndex) return keyCode; } -// Calculates max length of string needed to represent a1 or a2. +// Calculates max length of string needed to represent `value` or `value2`. // // 0x4DD03C -size_t _calc_max_field_chars_wcursor(int a1, int a2) +size_t _calc_max_field_chars_wcursor(int value1, int value2) { char* str = (char*)internal_malloc(17); if (str == NULL) { return -1; } - snprintf(str, 17, "%d", a1); + snprintf(str, 17, "%d", value1); size_t len1 = strlen(str); - snprintf(str, 17, "%d", a2); + snprintf(str, 17, "%d", value2); size_t len2 = strlen(str); internal_free(str); @@ -1272,7 +1271,7 @@ void _tm_kill_msg() } // 0x4DD744 -void _tm_kill_out_of_order(int a1) +void _tm_kill_out_of_order(int queueIndex) { int v7; int v6; @@ -1281,16 +1280,16 @@ void _tm_kill_out_of_order(int a1) return; } - if (!_tm_index_active(a1)) { + if (!_tm_index_active(queueIndex)) { return; } - windowDestroy(_tm_queue[a1].field_4); + windowDestroy(_tm_queue[queueIndex].field_4); - _tm_location[_tm_queue[a1].field_8].field_0 = 0; + _tm_location[_tm_queue[queueIndex].field_8].field_0 = 0; - if (a1 != _tm_kill) { - v6 = a1; + if (queueIndex != _tm_kill) { + v6 = queueIndex; do { v7 = v6 - 1; if (v7 < 0) { @@ -1317,35 +1316,35 @@ void _tm_kill_out_of_order(int a1) void _tm_click_response(int btn) { int win; - int v3; + int queueIndex; if (_tm_kill == -1) { return; } win = buttonGetWindowId(btn); - v3 = _tm_kill; - while (win != _tm_queue[v3].field_4) { - v3++; - if (v3 == 5) { - v3 = 0; + queueIndex = _tm_kill; + while (win != _tm_queue[queueIndex].field_4) { + queueIndex++; + if (queueIndex == 5) { + queueIndex = 0; } - if (v3 == _tm_kill || !_tm_index_active(v3)) + if (queueIndex == _tm_kill || !_tm_index_active(queueIndex)) return; } - _tm_kill_out_of_order(v3); + _tm_kill_out_of_order(queueIndex); } // 0x4DD870 -int _tm_index_active(int a1) +int _tm_index_active(int queueIndex) { if (_tm_kill != _tm_add) { if (_tm_kill >= _tm_add) { - if (a1 >= _tm_add && a1 < _tm_kill) + if (queueIndex >= _tm_add && queueIndex < _tm_kill) return 0; - } else if (a1 < _tm_kill || a1 >= _tm_add) { + } else if (queueIndex < _tm_kill || queueIndex >= _tm_add) { return 0; } } diff --git a/src/window_manager_private.h b/src/window_manager_private.h index abbc4e8..449a2ed 100644 --- a/src/window_manager_private.h +++ b/src/window_manager_private.h @@ -13,30 +13,30 @@ typedef void(ListSelectionHandler)(char** items, int index); extern char gProgramWindowTitle[256]; -int _win_list_select(const char* title, char** fileList, int fileListLength, ListSelectionHandler* callback, int x, int y, int a7); -int _win_list_select_at(const char* title, char** items, int itemsLength, ListSelectionHandler* callback, int x, int y, int a7, int a8); +int _win_list_select(const char* title, char** fileList, int fileListLength, ListSelectionHandler* callback, int x, int y, int color); +int _win_list_select_at(const char* title, char** items, int itemsLength, ListSelectionHandler* callback, int x, int y, int color, int start); int _win_get_str(char* dest, int length, const char* title, int x, int y); -int _win_msg(const char* string, int x, int y, int flags); -int _win_pull_down(char** items, int itemsLength, int x, int y, int a5); -int _create_pull_down(char** stringList, int stringListLength, int x, int y, int a5, int a6, Rect* rect); +int _win_msg(const char* string, int x, int y, int color); +int _win_pull_down(char** items, int itemsLength, int x, int y, int color); +int _create_pull_down(char** stringList, int stringListLength, int x, int y, int foregroundColor, int backgroundColor, Rect* rect); int _win_debug(char* string); void _win_debug_delete(int btn, int keyCode); -int _win_register_menu_bar(int win, int x, int y, int width, int height, int borderColor, int backgroundColor); -int _win_register_menu_pulldown(int win, int x, char* title, int keyCode, int itemsLength, char** items, int a7, int a8); +int _win_register_menu_bar(int win, int x, int y, int width, int height, int foregroundColor, int backgroundColor); +int _win_register_menu_pulldown(int win, int x, char* title, int keyCode, int itemsLength, char** items, int foregroundColor, int backgroundColor); void _win_delete_menu_bar(int win); int _find_first_letter(int ch, char** stringList, int stringListLength); int _win_width_needed(char** fileNameList, int fileNameListLength); int _win_input_str(int win, char* dest, int maxLength, int x, int y, int textColor, int backgroundColor); -int sub_4DBD04(int win, Rect* rect, char** items, int itemsLength, int a5, int a6, MenuBar* menuBar, int pulldownIndex); +int process_pull_down(int win, Rect* rect, char** items, int itemsLength, int a5, int a6, MenuBar* menuBar, int pulldownIndex); int _GNW_process_menu(MenuBar* menuBar, int pulldownIndex); -size_t _calc_max_field_chars_wcursor(int a1, int a2); +size_t _calc_max_field_chars_wcursor(int value1, int value2); void _GNW_intr_init(); void _GNW_intr_exit(); void _tm_watch_msgs(); void _tm_kill_msg(); -void _tm_kill_out_of_order(int a1); +void _tm_kill_out_of_order(int queueIndex); void _tm_click_response(int btn); -int _tm_index_active(int a1); +int _tm_index_active(int queueIndex); } // namespace fallout diff --git a/src/worldmap.cc b/src/worldmap.cc index a02914f..9b6ff3d 100644 --- a/src/worldmap.cc +++ b/src/worldmap.cc @@ -6592,4 +6592,15 @@ void wmBlinkRndEncounterIcon(bool special) wmGenData.encounterIconIsVisible = false; } +void wmSetPartyWorldPos(int x, int y) +{ + wmGenData.worldPosX = x; + wmGenData.worldPosY = y; +} + +void wmCarSetCurrentArea(int area) +{ + wmGenData.currentCarAreaId = area; +} + } // namespace fallout diff --git a/src/worldmap.h b/src/worldmap.h index 1180d70..901b0a6 100644 --- a/src/worldmap.h +++ b/src/worldmap.h @@ -277,6 +277,9 @@ int wmSetMapMusic(int mapIdx, const char* name); int wmMatchAreaContainingMapIdx(int mapIdx, int* areaIdxPtr); int wmTeleportToArea(int areaIdx); +void wmSetPartyWorldPos(int x, int y); +void wmCarSetCurrentArea(int area); + } // namespace fallout #endif /* WORLD_MAP_H */ diff --git a/src/xfile.cc b/src/xfile.cc index f2ce72c..60bcea2 100644 --- a/src/xfile.cc +++ b/src/xfile.cc @@ -234,10 +234,10 @@ char* xfileReadString(char* string, int size, XFile* stream) result = dfileReadString(string, size, stream->dfile); break; case XFILE_TYPE_GZFILE: - result = gzgets(stream->gzfile, string, size); + result = compat_gzgets(stream->gzfile, string, size); break; default: - result = fgets(string, size, stream->file); + result = compat_fgets(string, size, stream->file); break; }