Merge branch 'main' into code-readability-2
This commit is contained in:
commit
f39518cd09
|
@ -253,6 +253,8 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
|
|||
target_sources(${EXECUTABLE_NAME} PUBLIC
|
||||
"src/audio_engine.cc"
|
||||
"src/audio_engine.h"
|
||||
"src/delay.cc"
|
||||
"src/delay.h"
|
||||
"src/fps_limiter.cc"
|
||||
"src/fps_limiter.h"
|
||||
"src/platform_compat.cc"
|
||||
|
@ -275,6 +277,8 @@ target_sources(${EXECUTABLE_NAME} PUBLIC
|
|||
"src/sfall_kb_helpers.h"
|
||||
"src/sfall_lists.cc"
|
||||
"src/sfall_lists.h"
|
||||
"src/sfall_metarules.cc"
|
||||
"src/sfall_metarules.h"
|
||||
"src/sfall_opcodes.cc"
|
||||
"src/sfall_opcodes.h"
|
||||
"src/sfall_arrays.cc"
|
||||
|
@ -360,7 +364,7 @@ add_subdirectory("third_party/fpattern")
|
|||
target_link_libraries(${EXECUTABLE_NAME} ${FPATTERN_LIBRARY})
|
||||
target_include_directories(${EXECUTABLE_NAME} PRIVATE ${FPATTERN_INCLUDE_DIR})
|
||||
|
||||
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
if((NOT ${CMAKE_SYSTEM_NAME} MATCHES "Linux") AND (NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") AND (NOT ${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD"))
|
||||
add_subdirectory("third_party/zlib")
|
||||
add_subdirectory("third_party/sdl2")
|
||||
else()
|
||||
|
|
|
@ -48,6 +48,9 @@ typedef enum ScienceRepairTargetType {
|
|||
// 0x5106D0
|
||||
static bool _action_in_explode = false;
|
||||
|
||||
// 0x5106D4
|
||||
int rotation;
|
||||
|
||||
// 0x5106E0
|
||||
static const int gNormalDeathAnimations[DAMAGE_TYPE_COUNT] = {
|
||||
ANIM_DANCING_AUTOFIRE,
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
namespace fallout {
|
||||
|
||||
extern int rotation;
|
||||
|
||||
int _action_attack(Attack* attack);
|
||||
int _action_use_an_item_on_object(Object* a1, Object* a2, Object* a3);
|
||||
int _action_use_an_object(Object* a1, Object* a2);
|
||||
|
|
|
@ -438,6 +438,14 @@ void artRender(int fid, unsigned char* dest, int width, int height, int pitch)
|
|||
artUnlock(handle);
|
||||
}
|
||||
|
||||
// mapper2.exe: 0x40A03C
|
||||
int art_list_str(int fid, char* name)
|
||||
{
|
||||
// TODO: Incomplete.
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 0x419160
|
||||
Art* artLock(int fid, CacheEntry** handlePtr)
|
||||
{
|
||||
|
|
|
@ -123,6 +123,7 @@ char* artGetObjectTypeName(int objectType);
|
|||
int artIsObjectTypeHidden(int objectType);
|
||||
int artGetFidgetCount(int headFid);
|
||||
void artRender(int fid, unsigned char* dest, int width, int height, int pitch);
|
||||
int art_list_str(int fid, char* name);
|
||||
Art* artLock(int fid, CacheEntry** cache_entry);
|
||||
unsigned char* artLockFrameData(int fid, int frame, int direction, CacheEntry** out_cache_entry);
|
||||
unsigned char* artLockFrameDataReturningSize(int fid, CacheEntry** out_cache_entry, int* widthPtr, int* heightPtr);
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "db.h"
|
||||
#include "dbox.h"
|
||||
#include "debug.h"
|
||||
#include "delay.h"
|
||||
#include "draw.h"
|
||||
#include "game.h"
|
||||
#include "game_mouse.h"
|
||||
|
@ -1991,7 +1992,7 @@ static int _get_input_str(int win, int cancelKeyCode, char* text, int maxLength,
|
|||
|
||||
windowRefresh(win);
|
||||
|
||||
while (getTicksSince(_frame_time) < 1000 / 24) { }
|
||||
delay_ms(1000 / 24 - (getTicks() - _frame_time));
|
||||
|
||||
renderPresent();
|
||||
sharedFpsLimiter.throttle();
|
||||
|
@ -2281,8 +2282,7 @@ static void characterEditorDrawBigNumber(int x, int y, int flags, int value, int
|
|||
windowWidth);
|
||||
windowRefreshRect(windowHandle, &rect);
|
||||
renderPresent();
|
||||
while (getTicksSince(_frame_time) < BIG_NUM_ANIMATION_DELAY)
|
||||
;
|
||||
delay_ms(BIG_NUM_ANIMATION_DELAY - (getTicks() - _frame_time));
|
||||
}
|
||||
|
||||
blitBufferToBuffer(numbersGraphicBufferPtr + BIG_NUM_WIDTH * ones,
|
||||
|
@ -2304,8 +2304,7 @@ static void characterEditorDrawBigNumber(int x, int y, int flags, int value, int
|
|||
windowWidth);
|
||||
windowRefreshRect(windowHandle, &rect);
|
||||
renderPresent();
|
||||
while (getTicksSince(_frame_time) < BIG_NUM_ANIMATION_DELAY)
|
||||
;
|
||||
delay_ms(BIG_NUM_ANIMATION_DELAY - (getTicks() - _frame_time));
|
||||
}
|
||||
|
||||
blitBufferToBuffer(numbersGraphicBufferPtr + BIG_NUM_WIDTH * tens,
|
||||
|
@ -3530,11 +3529,9 @@ static int characterEditorEditAge()
|
|||
}
|
||||
|
||||
if (v33 > dbl_50170B) {
|
||||
while (getTicksSince(_frame_time) < 1000 / _repFtime)
|
||||
;
|
||||
delay_ms(1000 / _repFtime - (getTicks() - _frame_time));
|
||||
} else {
|
||||
while (getTicksSince(_frame_time) < 1000 / 24)
|
||||
;
|
||||
delay_ms(1000 / 24 - (getTicks() - _frame_time));
|
||||
}
|
||||
|
||||
keyCode = inputGetInput();
|
||||
|
@ -3548,8 +3545,7 @@ static int characterEditorEditAge()
|
|||
} else {
|
||||
windowRefresh(win);
|
||||
|
||||
while (getTicksSince(_frame_time) < 1000 / 24)
|
||||
;
|
||||
delay_ms(1000 / 24 - (getTicks() - _frame_time));
|
||||
}
|
||||
|
||||
renderPresent();
|
||||
|
@ -3699,8 +3695,7 @@ static void characterEditorEditGender()
|
|||
|
||||
windowRefresh(win);
|
||||
|
||||
while (getTicksSince(_frame_time) < 41)
|
||||
;
|
||||
delay_ms(41 - (getTicks() - _frame_time));
|
||||
|
||||
renderPresent();
|
||||
sharedFpsLimiter.throttle();
|
||||
|
@ -3778,12 +3773,9 @@ static void characterEditorAdjustPrimaryStat(int eventCode)
|
|||
}
|
||||
|
||||
if (v11 >= 19.2) {
|
||||
unsigned int delay = 1000 / _repFtime;
|
||||
while (getTicksSince(_frame_time) < delay) {
|
||||
}
|
||||
delay_ms(1000 / _repFtime - (getTicks() - _frame_time));
|
||||
} else {
|
||||
while (getTicksSince(_frame_time) < 1000 / 24) {
|
||||
}
|
||||
delay_ms(1000 / 24 - (getTicks() - _frame_time));
|
||||
}
|
||||
|
||||
renderPresent();
|
||||
|
@ -5279,11 +5271,9 @@ static void characterEditorHandleAdjustSkillButtonPressed(int keyCode)
|
|||
if (!isUsingKeyboard) {
|
||||
unspentSp = pcGetStat(PC_STAT_UNSPENT_SKILL_POINTS);
|
||||
if (repeatDelay >= dbl_5018F0) {
|
||||
while (getTicksSince(_frame_time) < 1000 / _repFtime) {
|
||||
}
|
||||
delay_ms(1000 / _repFtime - (getTicks() - _frame_time));
|
||||
} else {
|
||||
while (getTicksSince(_frame_time) < 1000 / 24) {
|
||||
}
|
||||
delay_ms(1000 / 24 - (getTicks() - _frame_time));
|
||||
}
|
||||
|
||||
int keyCode = inputGetInput();
|
||||
|
@ -6141,11 +6131,9 @@ static int perkDialogHandleInput(int count, void (*refreshProc)())
|
|||
}
|
||||
|
||||
if (v19 < dbl_5019BE) {
|
||||
while (getTicksSince(_frame_time) < 1000 / 24) {
|
||||
}
|
||||
delay_ms(1000 / 24 - (getTicks() - _frame_time));
|
||||
} else {
|
||||
while (getTicksSince(_frame_time) < 1000 / _repFtime) {
|
||||
}
|
||||
delay_ms(1000 / _repFtime - (getTicks() - _frame_time));
|
||||
}
|
||||
|
||||
renderPresent();
|
||||
|
@ -6188,11 +6176,9 @@ static int perkDialogHandleInput(int count, void (*refreshProc)())
|
|||
}
|
||||
|
||||
if (v19 < dbl_5019BE) {
|
||||
while (getTicksSince(_frame_time) < 1000 / 24) {
|
||||
}
|
||||
delay_ms(1000 / 24 - (getTicks() - _frame_time));
|
||||
} else {
|
||||
while (getTicksSince(_frame_time) < 1000 / _repFtime) {
|
||||
}
|
||||
delay_ms(1000 / _repFtime - (getTicks() - _frame_time));
|
||||
}
|
||||
|
||||
renderPresent();
|
||||
|
@ -6224,11 +6210,9 @@ static int perkDialogHandleInput(int count, void (*refreshProc)())
|
|||
}
|
||||
|
||||
if (v19 < dbl_5019BE) {
|
||||
while (getTicksSince(_frame_time) < 1000 / 24) {
|
||||
}
|
||||
delay_ms(1000 / 24 - (getTicks() - _frame_time));
|
||||
} else {
|
||||
while (getTicksSince(_frame_time) < 1000 / _repFtime) {
|
||||
}
|
||||
delay_ms(1000 / _repFtime - (getTicks() - _frame_time));
|
||||
}
|
||||
|
||||
renderPresent();
|
||||
|
|
|
@ -6835,4 +6835,9 @@ void combat_reset_hit_location_penalty()
|
|||
}
|
||||
}
|
||||
|
||||
Attack* combat_get_data()
|
||||
{
|
||||
return &_main_ctd;
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
|
|
@ -74,6 +74,7 @@ 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();
|
||||
Attack* combat_get_data();
|
||||
|
||||
static inline bool isInCombat()
|
||||
{
|
||||
|
|
|
@ -1464,7 +1464,7 @@ static int aiFindAttackers(Object* critter, Object** whoHitMePtr, Object** whoHi
|
|||
*whoHitFriendPtr = NULL;
|
||||
}
|
||||
|
||||
if (*whoHitByFriendPtr != NULL) {
|
||||
if (whoHitByFriendPtr != NULL) {
|
||||
*whoHitByFriendPtr = NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "cycle.h"
|
||||
#include "db.h"
|
||||
#include "debug.h"
|
||||
#include "delay.h"
|
||||
#include "draw.h"
|
||||
#include "game_mouse.h"
|
||||
#include "input.h"
|
||||
|
@ -172,8 +173,7 @@ void creditsOpen(const char* filePath, int backgroundFid, bool useReversedStyle)
|
|||
windowBuffer,
|
||||
windowWidth);
|
||||
|
||||
while (getTicksSince(tick) < CREDITS_WINDOW_SCROLLING_DELAY) {
|
||||
}
|
||||
delay_ms(CREDITS_WINDOW_SCROLLING_DELAY - (getTicks() - tick));
|
||||
|
||||
tick = getTicks();
|
||||
|
||||
|
@ -215,8 +215,7 @@ void creditsOpen(const char* filePath, int backgroundFid, bool useReversedStyle)
|
|||
windowBuffer,
|
||||
windowWidth);
|
||||
|
||||
while (getTicksSince(tick) < CREDITS_WINDOW_SCROLLING_DELAY) {
|
||||
}
|
||||
delay_ms(CREDITS_WINDOW_SCROLLING_DELAY - (getTicks() - tick));
|
||||
|
||||
tick = getTicks();
|
||||
|
||||
|
|
14
src/dbox.cc
14
src/dbox.cc
|
@ -9,6 +9,7 @@
|
|||
#include "character_editor.h"
|
||||
#include "color.h"
|
||||
#include "debug.h"
|
||||
#include "delay.h"
|
||||
#include "draw.h"
|
||||
#include "game.h"
|
||||
#include "game_sound.h"
|
||||
|
@ -885,8 +886,8 @@ int showLoadFileDialog(char* title, char** fileList, char* dest, int fileListLen
|
|||
}
|
||||
|
||||
unsigned int delay = (scrollCounter > 14.4) ? 1000 / scrollDelay : 1000 / 24;
|
||||
while (getTicksSince(scrollTick) < delay) {
|
||||
}
|
||||
|
||||
delay_ms(delay - (getTicks() - scrollTick));
|
||||
|
||||
if (_game_user_wants_to_quit != 0) {
|
||||
rc = 1;
|
||||
|
@ -909,8 +910,7 @@ int showLoadFileDialog(char* title, char** fileList, char* dest, int fileListLen
|
|||
doubleClickSelectedFileIndex = -2;
|
||||
}
|
||||
|
||||
while (getTicksSince(tick) < (1000 / 24)) {
|
||||
}
|
||||
delay_ms(1000 / 24 - (getTicks() - tick));
|
||||
}
|
||||
|
||||
if (_game_user_wants_to_quit) {
|
||||
|
@ -1335,8 +1335,7 @@ int showSaveFileDialog(char* title, char** fileList, char* dest, int fileListLen
|
|||
// FIXME: Missing windowRefresh makes blinking useless.
|
||||
|
||||
unsigned int delay = (scrollCounter > 14.4) ? 1000 / scrollDelay : 1000 / 24;
|
||||
while (getTicksSince(scrollTick) < delay) {
|
||||
}
|
||||
delay_ms(delay - (getTicks() - scrollTick));
|
||||
|
||||
if (_game_user_wants_to_quit != 0) {
|
||||
rc = 1;
|
||||
|
@ -1369,8 +1368,7 @@ int showSaveFileDialog(char* title, char** fileList, char* dest, int fileListLen
|
|||
doubleClickSelectedFileIndex = -2;
|
||||
}
|
||||
|
||||
while (getTicksSince(tick) < (1000 / 24)) {
|
||||
}
|
||||
delay_ms(1000 / 24 - (getTicks() - tick));
|
||||
}
|
||||
|
||||
if (_game_user_wants_to_quit != 0) {
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
#include "delay.h"
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
void delay_ms(int ms)
|
||||
{
|
||||
if (ms <= 0) {
|
||||
return;
|
||||
}
|
||||
SDL_Delay(ms);
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef DELAY_H
|
||||
#define DELAY_H
|
||||
|
||||
void delay_ms(int ms);
|
||||
|
||||
#endif
|
|
@ -8,6 +8,7 @@
|
|||
#include "art.h"
|
||||
#include "cycle.h"
|
||||
#include "debug.h"
|
||||
#include "delay.h"
|
||||
#include "draw.h"
|
||||
#include "game_mouse.h"
|
||||
#include "game_sound.h"
|
||||
|
@ -453,8 +454,7 @@ int elevatorSelectLevel(int elevator, int* mapPtr, int* elevationPtr, int* tileP
|
|||
|
||||
windowRefresh(gElevatorWindow);
|
||||
|
||||
while (getTicksSince(tick) < delay) {
|
||||
}
|
||||
delay_ms(delay - (getTicks() - tick));
|
||||
|
||||
renderPresent();
|
||||
sharedFpsLimiter.throttle();
|
||||
|
|
10
src/game.cc
10
src/game.cc
|
@ -1363,8 +1363,16 @@ static int gameDbInit()
|
|||
return -1;
|
||||
}
|
||||
|
||||
// SFALL: custom patch file name.
|
||||
char* patch_filename = nullptr;
|
||||
if (configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_PATCH_FILE, &patch_filename)) {
|
||||
if (patch_filename == nullptr || *patch_file_name == '\0') {
|
||||
patch_filename = "patch%03d.dat";
|
||||
}
|
||||
}
|
||||
|
||||
for (patch_index = 0; patch_index < 1000; patch_index++) {
|
||||
snprintf(filename, sizeof(filename), "patch%03d.dat", patch_index);
|
||||
snprintf(filename, sizeof(filename), patch_filename, patch_index);
|
||||
|
||||
if (compat_access(filename, 0) == 0) {
|
||||
dbOpen(filename, 0, NULL, 1);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "game_config.h"
|
||||
#include "sfall_config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
@ -120,6 +121,14 @@ bool gameConfigInit(bool isMapper, int argc, char** argv)
|
|||
configSetInt(&gGameConfig, GAME_CONFIG_MAPPER_KEY, GAME_CONFIG_SORT_SCRIPT_LIST_KEY, 0);
|
||||
}
|
||||
|
||||
// SFALL: custom config file name.
|
||||
char* configFileName = nullptr;
|
||||
if (configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_CONFIG_FILE, &configFileName)) {
|
||||
if (configFileName == nullptr || *configFileName == '\0') {
|
||||
configFileName = DEFAULT_GAME_CONFIG_FILE_NAME;
|
||||
}
|
||||
}
|
||||
|
||||
// Make `fallout2.cfg` file path.
|
||||
char* executable = argv[0];
|
||||
char* ch = strrchr(executable, '\\');
|
||||
|
@ -136,14 +145,14 @@ bool gameConfigInit(bool isMapper, int argc, char** argv)
|
|||
sizeof(gGameConfigFilePath),
|
||||
"%s\\%s",
|
||||
executable,
|
||||
GAME_CONFIG_FILE_NAME);
|
||||
configFileName);
|
||||
}
|
||||
*ch = '\\';
|
||||
} else {
|
||||
if (isMapper) {
|
||||
strcpy(gGameConfigFilePath, MAPPER_CONFIG_FILE_NAME);
|
||||
} else {
|
||||
strcpy(gGameConfigFilePath, GAME_CONFIG_FILE_NAME);
|
||||
strcpy(gGameConfigFilePath, configFileName);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
namespace fallout {
|
||||
|
||||
#define GAME_CONFIG_FILE_NAME "fallout2.cfg"
|
||||
#define DEFAULT_GAME_CONFIG_FILE_NAME "fallout2.cfg"
|
||||
#define MAPPER_CONFIG_FILE_NAME "mapper2.cfg"
|
||||
|
||||
#define GAME_CONFIG_SYSTEM_KEY "system"
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "critter.h"
|
||||
#include "cycle.h"
|
||||
#include "debug.h"
|
||||
#include "delay.h"
|
||||
#include "dialog.h"
|
||||
#include "display_monitor.h"
|
||||
#include "draw.h"
|
||||
|
@ -2936,7 +2937,6 @@ void _gdialog_scroll_subwin(int win, int a2, unsigned char* a3, unsigned char* a
|
|||
int v7;
|
||||
unsigned char* v9;
|
||||
Rect rect;
|
||||
unsigned int tick;
|
||||
|
||||
v7 = a6;
|
||||
v9 = a4;
|
||||
|
@ -2971,9 +2971,7 @@ void _gdialog_scroll_subwin(int win, int a2, unsigned char* a3, unsigned char* a
|
|||
v7 += 10;
|
||||
v9 -= 10 * (GAME_DIALOG_WINDOW_WIDTH);
|
||||
|
||||
tick = getTicks();
|
||||
while (getTicksSince(tick) < 33) {
|
||||
}
|
||||
delay_ms(33);
|
||||
|
||||
renderPresent();
|
||||
sharedFpsLimiter.throttle();
|
||||
|
@ -3011,9 +3009,7 @@ void _gdialog_scroll_subwin(int win, int a2, unsigned char* a3, unsigned char* a
|
|||
|
||||
rect.top += 10;
|
||||
|
||||
tick = getTicks();
|
||||
while (getTicksSince(tick) < 33) {
|
||||
}
|
||||
delay_ms(33);
|
||||
|
||||
renderPresent();
|
||||
sharedFpsLimiter.throttle();
|
||||
|
|
|
@ -2464,4 +2464,9 @@ void gameMouseRefreshImmediately()
|
|||
renderPresent();
|
||||
}
|
||||
|
||||
Object* gmouse_get_outlined_object()
|
||||
{
|
||||
return gGameMouseHighlightedItem;
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
|
|
@ -103,6 +103,7 @@ void gameMouseLoadItemHighlight();
|
|||
void _gmouse_remove_item_outline(Object* object);
|
||||
|
||||
void gameMouseRefreshImmediately();
|
||||
Object* gmouse_get_outlined_object();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
|
|
15
src/input.cc
15
src/input.cc
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "audio_engine.h"
|
||||
#include "color.h"
|
||||
#include "delay.h"
|
||||
#include "dinput.h"
|
||||
#include "draw.h"
|
||||
#include "kb.h"
|
||||
|
@ -199,6 +200,13 @@ int inputGetInput()
|
|||
return -1;
|
||||
}
|
||||
|
||||
// 0x4C8BC8
|
||||
void get_input_position(int* x, int* y)
|
||||
{
|
||||
*x = _input_mx;
|
||||
*y = _input_my;
|
||||
}
|
||||
|
||||
// 0x4C8BDC
|
||||
void _process_bk()
|
||||
{
|
||||
|
@ -634,12 +642,7 @@ void inputPauseForTocks(unsigned int delay)
|
|||
// 0x4C93B8
|
||||
void inputBlockForTocks(unsigned int ms)
|
||||
{
|
||||
unsigned int start = SDL_GetTicks();
|
||||
unsigned int diff;
|
||||
do {
|
||||
// NOTE: Uninline
|
||||
diff = getTicksSince(start);
|
||||
} while (diff < ms);
|
||||
delay_ms(ms);
|
||||
}
|
||||
|
||||
// 0x4C93E0
|
||||
|
|
|
@ -13,6 +13,7 @@ typedef int(ScreenshotHandler)(int width, int height, unsigned char* buffer, uns
|
|||
int inputInit(int a1);
|
||||
void inputExit();
|
||||
int inputGetInput();
|
||||
void get_input_position(int* x, int* y);
|
||||
void _process_bk();
|
||||
void enqueueInputEvent(int a1);
|
||||
void inputEventQueueReset();
|
||||
|
|
|
@ -1131,7 +1131,12 @@ static void opConditionalOperatorLessThanEquals(Program* program)
|
|||
case VALUE_TYPE_PTR:
|
||||
switch (value[0].opcode) {
|
||||
case VALUE_TYPE_INT:
|
||||
if (value[0].integerValue > 0) {
|
||||
result = (uintptr_t)value[1].pointerValue <= (uintptr_t)value[0].integerValue;
|
||||
} else {
|
||||
// (ptr <= int{0 or negative}) means (ptr == nullptr)
|
||||
result = nullptr == value[1].pointerValue;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(false && "Should be unreachable");
|
||||
|
@ -1385,7 +1390,12 @@ static void opConditionalOperatorGreaterThan(Program* program)
|
|||
case VALUE_TYPE_PTR:
|
||||
switch (value[0].opcode) {
|
||||
case VALUE_TYPE_INT:
|
||||
if (value[0].integerValue > 0) {
|
||||
result = (uintptr_t)value[1].pointerValue > (uintptr_t)value[0].integerValue;
|
||||
} else {
|
||||
// (ptr > int{0 or negative}) means (ptr != nullptr)
|
||||
result = nullptr != value[1].pointerValue;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(false && "Should be unreachable");
|
||||
|
|
|
@ -1580,12 +1580,22 @@ static void opPickup(Program* program)
|
|||
return;
|
||||
}
|
||||
|
||||
if (script->target == NULL) {
|
||||
Object* self = script->target;
|
||||
|
||||
// SFALL: Override `self` via `op_set_self`.
|
||||
// CE: Implementation is different. Sfall integrates via `scriptGetSid` by
|
||||
// returning fake script with overridden `self` (and `target` in this case).
|
||||
if (script->overriddenSelf != nullptr) {
|
||||
self = script->overriddenSelf;
|
||||
script->overriddenSelf = nullptr;
|
||||
}
|
||||
|
||||
if (self == NULL) {
|
||||
scriptPredefinedError(program, "pickup_obj", SCRIPT_ERROR_OBJECT_IS_NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
actionPickUp(script->target, object);
|
||||
actionPickUp(self, object);
|
||||
}
|
||||
|
||||
// drop_obj
|
||||
|
@ -4548,6 +4558,15 @@ static void opUseObjectOnObject(Program* program)
|
|||
}
|
||||
|
||||
Object* self = scriptGetSelf(program);
|
||||
|
||||
// SFALL: Override `self` via `op_set_self`.
|
||||
// CE: Implementation is different. Sfall integrates via `scriptGetSid` by
|
||||
// returning fake script with overridden `self`.
|
||||
if (script->overriddenSelf != nullptr) {
|
||||
self = script->overriddenSelf;
|
||||
script->overriddenSelf = nullptr;
|
||||
}
|
||||
|
||||
if (PID_TYPE(self->pid) == OBJ_TYPE_CRITTER) {
|
||||
_action_use_an_item_on_object(self, target, item);
|
||||
} else {
|
||||
|
|
|
@ -5975,4 +5975,9 @@ int _inven_set_timer(Object* a1)
|
|||
return seconds;
|
||||
}
|
||||
|
||||
Object* inven_get_current_target_obj()
|
||||
{
|
||||
return _target_stack[_target_curr_stack];
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
|
|
@ -27,6 +27,7 @@ int inventoryOpenLooting(Object* looter, Object* target);
|
|||
int inventoryOpenStealing(Object* thief, Object* target);
|
||||
void inventoryOpenTrade(int win, Object* barterer, Object* playerTable, Object* bartererTable, int barterMod);
|
||||
int _inven_set_timer(Object* a1);
|
||||
Object* inven_get_current_target_obj();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "db.h"
|
||||
#include "dbox.h"
|
||||
#include "debug.h"
|
||||
#include "delay.h"
|
||||
#include "display_monitor.h"
|
||||
#include "draw.h"
|
||||
#include "file_utils.h"
|
||||
|
@ -672,9 +673,9 @@ int lsgSaveGame(int mode)
|
|||
}
|
||||
|
||||
if (scrollCounter > 14.4) {
|
||||
while (getTicksSince(start) < 1000 / scrollVelocity) { }
|
||||
delay_ms(1000 / scrollVelocity - (getTicks() - start));
|
||||
} else {
|
||||
while (getTicksSince(start) < 1000 / 24) { }
|
||||
delay_ms(1000 / 24 - (getTicks() - start));
|
||||
}
|
||||
|
||||
keyCode = inputGetInput();
|
||||
|
@ -718,8 +719,7 @@ int lsgSaveGame(int mode)
|
|||
doubleClickSlot = -1;
|
||||
}
|
||||
|
||||
while (getTicksSince(tick) < 1000 / 24) {
|
||||
}
|
||||
delay_ms(1000 / 24 - (getTicks() - tick));
|
||||
}
|
||||
|
||||
if (rc == 1) {
|
||||
|
@ -1175,9 +1175,9 @@ int lsgLoadGame(int mode)
|
|||
}
|
||||
|
||||
if (scrollCounter > 14.4) {
|
||||
while (getTicksSince(start) < 1000 / scrollVelocity) { }
|
||||
delay_ms(1000 / scrollVelocity - (getTicks() - start));
|
||||
} else {
|
||||
while (getTicksSince(start) < 1000 / 24) { }
|
||||
delay_ms(1000 / 24 - (getTicks() - start));
|
||||
}
|
||||
|
||||
keyCode = inputGetInput();
|
||||
|
@ -1227,7 +1227,7 @@ int lsgLoadGame(int mode)
|
|||
doubleClickSlot = -1;
|
||||
}
|
||||
|
||||
while (getTicksSince(time) < 1000 / 24) { }
|
||||
delay_ms(1000 / 24 - (getTicks() - time));
|
||||
}
|
||||
|
||||
if (rc == 1) {
|
||||
|
@ -2387,8 +2387,7 @@ static int _get_input_str2(int win, int doneKeyCode, int cancelKeyCode, char* de
|
|||
windowRefresh(win);
|
||||
}
|
||||
|
||||
while (getTicksSince(tick) < 1000 / 24) {
|
||||
}
|
||||
delay_ms(1000 / 24 - (getTicks() - tick));
|
||||
|
||||
renderPresent();
|
||||
sharedFpsLimiter.throttle();
|
||||
|
|
|
@ -1,7 +1,23 @@
|
|||
#include "mapper/map_func.h"
|
||||
|
||||
#include "actions.h"
|
||||
#include "color.h"
|
||||
#include "game_mouse.h"
|
||||
#include "input.h"
|
||||
#include "map.h"
|
||||
#include "memory.h"
|
||||
#include "mouse.h"
|
||||
#include "proto.h"
|
||||
#include "svga.h"
|
||||
#include "tile.h"
|
||||
#include "window_manager.h"
|
||||
#include "window_manager_private.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
// 0x5595CC
|
||||
static bool block_obj_view_on = false;
|
||||
|
||||
// 0x4825B0
|
||||
void setup_map_dirs()
|
||||
{
|
||||
|
@ -14,4 +30,151 @@ void copy_proto_lists()
|
|||
// TODO: Incomplete.
|
||||
}
|
||||
|
||||
// 0x482708
|
||||
void place_entrance_hex()
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
int tile;
|
||||
|
||||
while (inputGetInput() != -2) {
|
||||
}
|
||||
|
||||
if ((mouseGetEvent() & MOUSE_EVENT_LEFT_BUTTON_DOWN) != 0) {
|
||||
if (_mouse_click_in(0, 0, _scr_size.right - _scr_size.left, _scr_size.bottom - _scr_size.top - 100)) {
|
||||
mouseGetPosition(&x, &y);
|
||||
|
||||
tile = tileFromScreenXY(x, y, gElevation);
|
||||
if (tile != -1) {
|
||||
if (tileSetCenter(tile, TILE_SET_CENTER_FLAG_IGNORE_SCROLL_RESTRICTIONS) == 0) {
|
||||
mapSetEnteringLocation(tile, gElevation, rotation);
|
||||
} else {
|
||||
win_timed_msg("ERROR: Entrance out of range!", _colorTable[31744]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4841C4
|
||||
void pick_region(Rect* rect)
|
||||
{
|
||||
Rect temp;
|
||||
int x;
|
||||
int y;
|
||||
|
||||
gameMouseSetCursor(MOUSE_CURSOR_PLUS);
|
||||
gameMouseObjectsHide();
|
||||
|
||||
while (1) {
|
||||
if (inputGetInput() == -2
|
||||
&& (mouseGetEvent() & MOUSE_EVENT_LEFT_BUTTON_DOWN) != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
get_input_position(&x, &y);
|
||||
temp.left = x;
|
||||
temp.top = y;
|
||||
temp.right = x;
|
||||
temp.bottom = y;
|
||||
|
||||
while ((mouseGetEvent() & MOUSE_EVENT_LEFT_BUTTON_UP) == 0) {
|
||||
inputGetInput();
|
||||
|
||||
get_input_position(&x, &y);
|
||||
|
||||
if (x != temp.right || y != temp.bottom) {
|
||||
erase_rect(rect);
|
||||
sort_rect(rect, &temp);
|
||||
draw_rect(rect, _colorTable[32747]);
|
||||
}
|
||||
}
|
||||
|
||||
erase_rect(rect);
|
||||
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
|
||||
gameMouseObjectsShow();
|
||||
}
|
||||
|
||||
// 0x484294
|
||||
void sort_rect(Rect* a, Rect* b)
|
||||
{
|
||||
if (b->right > b->left) {
|
||||
a->left = b->left;
|
||||
a->right = b->right;
|
||||
} else {
|
||||
a->left = b->right;
|
||||
a->right = b->left;
|
||||
}
|
||||
|
||||
if (b->bottom > b->top) {
|
||||
a->top = b->top;
|
||||
a->bottom = b->bottom;
|
||||
} else {
|
||||
a->top = b->bottom;
|
||||
a->bottom = b->top;
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4842D4
|
||||
void draw_rect(Rect* rect, unsigned char color)
|
||||
{
|
||||
int width = rect->right - rect->left;
|
||||
int height = rect->bottom - rect->top;
|
||||
int max_dimension;
|
||||
|
||||
if (height < width) {
|
||||
max_dimension = width;
|
||||
} else {
|
||||
max_dimension = height;
|
||||
}
|
||||
|
||||
unsigned char* buffer = (unsigned char*)internal_malloc(max_dimension);
|
||||
if (buffer != NULL) {
|
||||
memset(buffer, color, max_dimension);
|
||||
_scr_blit(buffer, width, 1, 0, 0, width, 1, rect->left, rect->top);
|
||||
_scr_blit(buffer, 1, height, 0, 0, 1, height, rect->left, rect->top);
|
||||
_scr_blit(buffer, width, 1, 0, 0, width, 1, rect->left, rect->bottom);
|
||||
_scr_blit(buffer, 1, height, 0, 0, 1, height, rect->right, rect->top);
|
||||
internal_free(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
// 0x4843A0
|
||||
void erase_rect(Rect* rect)
|
||||
{
|
||||
Rect r = *rect;
|
||||
|
||||
r.bottom = rect->top;
|
||||
windowRefreshAll(&r);
|
||||
|
||||
r.bottom = rect->bottom;
|
||||
r.left = rect->right;
|
||||
windowRefreshAll(&r);
|
||||
|
||||
r.left = rect->left;
|
||||
r.top = rect->bottom;
|
||||
windowRefreshAll(&r);
|
||||
|
||||
r.top = rect->top;
|
||||
r.right = rect->left;
|
||||
windowRefreshAll(&r);
|
||||
}
|
||||
|
||||
// 0x484400
|
||||
int toolbar_proto(int type, int id)
|
||||
{
|
||||
if (id < proto_max_id(type)) {
|
||||
return (type << 24) | id;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// 0x485D44
|
||||
bool map_toggle_block_obj_viewing_on()
|
||||
{
|
||||
return block_obj_view_on;
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
|
|
@ -1,10 +1,19 @@
|
|||
#ifndef FALLOUT_MAPPER_MAP_FUNC_H_
|
||||
#define FALLOUT_MAPPER_MAP_FUNC_H_
|
||||
|
||||
#include "geometry.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
void setup_map_dirs();
|
||||
void copy_proto_lists();
|
||||
void place_entrance_hex();
|
||||
void pick_region(Rect* rect);
|
||||
void sort_rect(Rect* a, Rect* b);
|
||||
void draw_rect(Rect* rect, unsigned char color);
|
||||
void erase_rect(Rect* rect);
|
||||
int toolbar_proto(int type, int id);
|
||||
bool map_toggle_block_obj_viewing_on();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <ctype.h>
|
||||
|
||||
#include "actions.h"
|
||||
#include "animation.h"
|
||||
#include "art.h"
|
||||
#include "color.h"
|
||||
|
@ -46,7 +47,12 @@ static void edit_mapper();
|
|||
static void mapper_load_toolbar(int a1, int a2);
|
||||
static void redraw_toolname();
|
||||
static void clear_toolname();
|
||||
static void update_toolname(int* pid, int type, int id);
|
||||
static void update_high_obj_name(Object* obj);
|
||||
static void mapper_destroy_highlight_obj(Object** a1, Object** a2);
|
||||
static void mapper_refresh_rotation();
|
||||
static void update_art(int a1, int a2);
|
||||
static void handle_new_map(int* a1, int* a2);
|
||||
static int mapper_mark_exit_grid();
|
||||
static void mapper_mark_all_exit_grids();
|
||||
|
||||
|
@ -100,6 +106,26 @@ static char kSwapPrototypse[] = " Swap Prototypes ";
|
|||
|
||||
static char kTmpMapName[] = "TMP$MAP#.MAP";
|
||||
|
||||
// 0x559618
|
||||
int rotate_arrows_x_offs[] = {
|
||||
31,
|
||||
38,
|
||||
31,
|
||||
11,
|
||||
3,
|
||||
11,
|
||||
};
|
||||
|
||||
// 0x559630
|
||||
int rotate_arrows_y_offs[] = {
|
||||
7,
|
||||
23,
|
||||
37,
|
||||
37,
|
||||
23,
|
||||
7,
|
||||
};
|
||||
|
||||
// 0x559648
|
||||
char* menu_0[] = {
|
||||
kNew,
|
||||
|
@ -180,6 +206,9 @@ int art_scale_width = 49;
|
|||
// 0x559888
|
||||
int art_scale_height = 48;
|
||||
|
||||
// 0x5598A0
|
||||
static bool map_entered = false;
|
||||
|
||||
// 0x5598A4
|
||||
static char* tmp_map_name = kTmpMapName;
|
||||
|
||||
|
@ -201,6 +230,9 @@ int menu_val_2[8];
|
|||
// 0x6EAA80
|
||||
unsigned char e_num[4][19 * 26];
|
||||
|
||||
// 0x6EBD28
|
||||
unsigned char rotate_arrows[2][6][10 * 10];
|
||||
|
||||
// 0x6EC408
|
||||
int menu_val_1[21];
|
||||
|
||||
|
@ -1045,6 +1077,36 @@ int mapper_edit_init(int argc, char** argv)
|
|||
|
||||
// ARROWS
|
||||
for (index = 0; index < ROTATION_COUNT; index++) {
|
||||
int x = rotate_arrows_x_offs[index] + 285;
|
||||
int y = rotate_arrows_y_offs[index] + 25;
|
||||
unsigned char v1 = lbm_buf[27 * (_scr_size.right + 1) + 287];
|
||||
int k;
|
||||
|
||||
blitBufferToBuffer(lbm_buf + y * rectGetWidth(&_scr_size) + x,
|
||||
10,
|
||||
10,
|
||||
rectGetWidth(&_scr_size),
|
||||
rotate_arrows[1][index],
|
||||
10);
|
||||
|
||||
for (k = 0; k < 100; k++) {
|
||||
if (rotate_arrows[1][index][k] == v1) {
|
||||
rotate_arrows[1][index][k] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
blitBufferToBuffer(lbm_buf + y * rectGetWidth(&_scr_size) + x - 52,
|
||||
10,
|
||||
10,
|
||||
rectGetWidth(&_scr_size),
|
||||
rotate_arrows[0][index],
|
||||
10);
|
||||
|
||||
for (k = 0; k < 100; k++) {
|
||||
if (rotate_arrows[1][index][k] == v1) {
|
||||
rotate_arrows[1][index][k] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// COPY
|
||||
|
@ -1408,6 +1470,85 @@ void clear_toolname()
|
|||
redraw_toolname();
|
||||
}
|
||||
|
||||
// 0x48B328
|
||||
void update_toolname(int* pid, int type, int id)
|
||||
{
|
||||
Proto* proto;
|
||||
|
||||
*pid = toolbar_proto(type, id);
|
||||
|
||||
if (protoGetProto(*pid, &proto) == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
windowDrawText(tool_win,
|
||||
protoGetName(proto->pid),
|
||||
120,
|
||||
_scr_size.right - _scr_size.left - 149,
|
||||
60,
|
||||
260);
|
||||
|
||||
switch (PID_TYPE(proto->pid)) {
|
||||
case OBJ_TYPE_ITEM:
|
||||
windowDrawText(tool_win,
|
||||
gItemTypeNames[proto->item.type],
|
||||
120,
|
||||
_scr_size.right - _scr_size.left - 149,
|
||||
70,
|
||||
260);
|
||||
break;
|
||||
case OBJ_TYPE_CRITTER:
|
||||
windowDrawText(tool_win,
|
||||
"",
|
||||
120,
|
||||
_scr_size.right - _scr_size.left - 149,
|
||||
70,
|
||||
260);
|
||||
break;
|
||||
case OBJ_TYPE_WALL:
|
||||
windowDrawText(tool_win,
|
||||
proto_wall_light_str(proto->wall.flags),
|
||||
120,
|
||||
_scr_size.right - _scr_size.left - 149,
|
||||
70,
|
||||
260);
|
||||
break;
|
||||
case OBJ_TYPE_TILE:
|
||||
windowDrawText(tool_win,
|
||||
"",
|
||||
120,
|
||||
_scr_size.right - _scr_size.left - 149,
|
||||
70,
|
||||
260);
|
||||
break;
|
||||
case OBJ_TYPE_MISC:
|
||||
windowDrawText(tool_win,
|
||||
"",
|
||||
120,
|
||||
_scr_size.right - _scr_size.left - 149,
|
||||
70,
|
||||
260);
|
||||
break;
|
||||
default:
|
||||
windowDrawText(tool_win,
|
||||
"",
|
||||
120,
|
||||
_scr_size.right - _scr_size.left - 149,
|
||||
70,
|
||||
260);
|
||||
break;
|
||||
}
|
||||
|
||||
windowDrawText(tool_win,
|
||||
"",
|
||||
120,
|
||||
_scr_size.right - _scr_size.left - 149,
|
||||
80,
|
||||
260);
|
||||
|
||||
redraw_toolname();
|
||||
}
|
||||
|
||||
// 0x48B5BC
|
||||
void update_high_obj_name(Object* obj)
|
||||
{
|
||||
|
@ -1421,6 +1562,113 @@ void update_high_obj_name(Object* obj)
|
|||
}
|
||||
}
|
||||
|
||||
// 0x48B680
|
||||
void mapper_destroy_highlight_obj(Object** a1, Object** a2)
|
||||
{
|
||||
Rect rect;
|
||||
int elevation;
|
||||
|
||||
if (a2 != NULL && *a2 != NULL) {
|
||||
elevation = (*a2)->elevation;
|
||||
reg_anim_clear(*a2);
|
||||
objectDestroy(*a2, &rect);
|
||||
tileWindowRefreshRect(&rect, elevation);
|
||||
*a2 = NULL;
|
||||
}
|
||||
|
||||
if (a1 != NULL && *a1 != NULL) {
|
||||
elevation = (*a1)->elevation;
|
||||
objectDestroy(*a1, &rect);
|
||||
tileWindowRefreshRect(&rect, elevation);
|
||||
*a1 = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// 0x48B6EC
|
||||
void mapper_refresh_rotation()
|
||||
{
|
||||
Rect rect;
|
||||
char string[2];
|
||||
int index;
|
||||
|
||||
rect.left = 270;
|
||||
rect.top = 431 - (_scr_size.bottom - 99);
|
||||
rect.right = 317;
|
||||
rect.bottom = rect.top + 47;
|
||||
|
||||
sprintf(string, "%d", rotation);
|
||||
|
||||
if (tool != NULL) {
|
||||
windowFill(tool_win,
|
||||
290,
|
||||
452 - (_scr_size.bottom - 99),
|
||||
10,
|
||||
12,
|
||||
tool[(452 - (_scr_size.bottom - 99)) * (_scr_size.right + 1) + 289]);
|
||||
windowDrawText(tool_win,
|
||||
string,
|
||||
10,
|
||||
292,
|
||||
452 - (_scr_size.bottom - 99),
|
||||
0x2010104);
|
||||
|
||||
for (index = 0; index < 6; index++) {
|
||||
int x = rotate_arrows_x_offs[index] + 269;
|
||||
int y = rotate_arrows_y_offs[index] + (430 - (_scr_size.bottom - 99));
|
||||
|
||||
blitBufferToBufferTrans(rotate_arrows[index == rotation][index],
|
||||
10,
|
||||
10,
|
||||
10,
|
||||
tool + y * (_scr_size.right + 1) + x,
|
||||
_scr_size.right + 1);
|
||||
}
|
||||
|
||||
windowRefreshRect(tool_win, &rect);
|
||||
} else {
|
||||
debugPrint("Error: mapper_refresh_rotation: tool buffer invalid!");
|
||||
}
|
||||
}
|
||||
|
||||
// 0x48B850
|
||||
void update_art(int a1, int a2)
|
||||
{
|
||||
// TODO: Incomplete.
|
||||
}
|
||||
|
||||
// 0x48C524
|
||||
void handle_new_map(int* a1, int* a2)
|
||||
{
|
||||
Rect rect;
|
||||
|
||||
rect.left = 30;
|
||||
rect.top = 62;
|
||||
rect.right = 50;
|
||||
rect.bottom = 88;
|
||||
blitBufferToBuffer(e_num[gElevation],
|
||||
19,
|
||||
26,
|
||||
19,
|
||||
tool + rect.top * rectGetWidth(&_scr_size) + rect.left,
|
||||
rectGetWidth(&_scr_size));
|
||||
windowRefreshRect(tool_win, &rect);
|
||||
|
||||
if (*a1 < 0 || *a1 > 6) {
|
||||
*a1 = 4;
|
||||
}
|
||||
|
||||
*a2 = 0;
|
||||
update_art(*a1, *a2);
|
||||
|
||||
print_toolbar_name(OBJ_TYPE_TILE);
|
||||
|
||||
map_entered = false;
|
||||
|
||||
if (tileRoofIsVisible()) {
|
||||
tile_toggle_roof(true);
|
||||
}
|
||||
}
|
||||
|
||||
// 0x48C604
|
||||
int mapper_inven_unwield(Object* obj, int right_hand)
|
||||
{
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
#include "art.h"
|
||||
#include "color.h"
|
||||
#include "combat_ai.h"
|
||||
#include "critter.h"
|
||||
|
@ -22,6 +23,9 @@ namespace fallout {
|
|||
#define NO 1
|
||||
|
||||
static int proto_choose_container_flags(Proto* proto);
|
||||
static int proto_subdata_setup_int_button(const char* title, int key, int value, int min_value, int max_value, int* y, int a7);
|
||||
static int proto_subdata_setup_fid_button(const char* title, int key, int fid, int* y, int a5);
|
||||
static int proto_subdata_setup_pid_button(const char* title, int key, int pid, int* y, int a5);
|
||||
static void proto_critter_flags_redraw(int win, int pid);
|
||||
static int proto_critter_flags_modify(int pid);
|
||||
static int mp_pick_kill_type();
|
||||
|
@ -29,6 +33,12 @@ static int mp_pick_kill_type();
|
|||
static char kYes[] = "YES";
|
||||
static char kNo[] = "NO";
|
||||
|
||||
// 0x53DAFC
|
||||
static char default_proto_builder_name[36] = "EVERTS SCOTTY";
|
||||
|
||||
// 0x559924
|
||||
char* proto_builder_name = default_proto_builder_name;
|
||||
|
||||
// 0x559B94
|
||||
static const char* wall_light_strs[] = {
|
||||
"North/South",
|
||||
|
@ -51,6 +61,9 @@ int edit_window_color = 1;
|
|||
// 0x559C60
|
||||
bool can_modify_protos = false;
|
||||
|
||||
// 0x559C68
|
||||
static int subwin = -1;
|
||||
|
||||
// 0x559C6C
|
||||
static int critFlagList[CRITTER_FLAG_COUNT] = {
|
||||
CRITTER_NO_STEAL,
|
||||
|
@ -215,6 +228,162 @@ int proto_choose_container_flags(Proto* proto)
|
|||
return 0;
|
||||
}
|
||||
|
||||
// 0x492A3C
|
||||
int proto_subdata_setup_int_button(const char* title, int key, int value, int min_value, int max_value, int* y, int a7)
|
||||
{
|
||||
char text[36];
|
||||
int button_x;
|
||||
int value_offset_x;
|
||||
|
||||
button_x = 10;
|
||||
value_offset_x = 90;
|
||||
|
||||
if (a7 == 9) {
|
||||
*y -= 189;
|
||||
}
|
||||
|
||||
if (a7 > 8) {
|
||||
button_x = 165;
|
||||
value_offset_x -= 16;
|
||||
}
|
||||
|
||||
_win_register_text_button(subwin,
|
||||
button_x,
|
||||
*y,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
key,
|
||||
title,
|
||||
0);
|
||||
|
||||
if (value >= min_value && value < max_value) {
|
||||
sprintf(text, "%d", value);
|
||||
windowDrawText(subwin,
|
||||
text,
|
||||
38,
|
||||
button_x + value_offset_x,
|
||||
*y + 4,
|
||||
_colorTable[32747] | 0x10000);
|
||||
} else {
|
||||
windowDrawText(subwin,
|
||||
"<ERROR>",
|
||||
38,
|
||||
button_x + value_offset_x,
|
||||
*y + 4,
|
||||
_colorTable[31744] | 0x10000);
|
||||
}
|
||||
|
||||
*y += 21;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x492B28
|
||||
int proto_subdata_setup_fid_button(const char* title, int key, int fid, int* y, int a5)
|
||||
{
|
||||
char text[36];
|
||||
char* pch;
|
||||
int button_x;
|
||||
int value_offset_x;
|
||||
|
||||
button_x = 10;
|
||||
value_offset_x = 90;
|
||||
|
||||
if (a5 == 9) {
|
||||
*y -= 189;
|
||||
}
|
||||
|
||||
if (a5 > 8) {
|
||||
button_x = 165;
|
||||
value_offset_x -= 16;
|
||||
}
|
||||
|
||||
_win_register_text_button(subwin,
|
||||
button_x,
|
||||
*y,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
key,
|
||||
title,
|
||||
0);
|
||||
|
||||
if (art_list_str(fid, text) != -1) {
|
||||
pch = strchr(text, '.');
|
||||
if (pch != NULL) {
|
||||
*pch = '\0';
|
||||
}
|
||||
|
||||
windowDrawText(subwin,
|
||||
text,
|
||||
80,
|
||||
button_x + value_offset_x,
|
||||
*y + 4,
|
||||
_colorTable[32747] | 0x10000);
|
||||
} else {
|
||||
windowDrawText(subwin,
|
||||
"None",
|
||||
80,
|
||||
button_x + value_offset_x,
|
||||
*y + 4,
|
||||
_colorTable[992] | 0x10000);
|
||||
}
|
||||
|
||||
*y += 21;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x492C20
|
||||
int proto_subdata_setup_pid_button(const char* title, int key, int pid, int* y, int a5)
|
||||
{
|
||||
int button_x;
|
||||
int value_offset_x;
|
||||
|
||||
button_x = 10;
|
||||
value_offset_x = 90;
|
||||
|
||||
if (a5 == 9) {
|
||||
*y -= 189;
|
||||
}
|
||||
|
||||
if (a5 > 8) {
|
||||
button_x = 165;
|
||||
value_offset_x = 74;
|
||||
}
|
||||
|
||||
_win_register_text_button(subwin,
|
||||
button_x,
|
||||
*y,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
key,
|
||||
title,
|
||||
0);
|
||||
|
||||
if (pid != -1) {
|
||||
windowDrawText(subwin,
|
||||
protoGetName(pid),
|
||||
49,
|
||||
button_x + value_offset_x,
|
||||
*y + 4,
|
||||
_colorTable[32747] | 0x10000);
|
||||
} else {
|
||||
windowDrawText(subwin,
|
||||
"None",
|
||||
49,
|
||||
button_x + value_offset_x,
|
||||
*y + 4,
|
||||
_colorTable[992] | 0x10000);
|
||||
}
|
||||
|
||||
*y += 21;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x495438
|
||||
const char* proto_wall_light_str(int flags)
|
||||
{
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
namespace fallout {
|
||||
|
||||
extern char* proto_builder_name;
|
||||
extern bool can_modify_protos;
|
||||
|
||||
void init_mapper_protos();
|
||||
|
|
|
@ -5,14 +5,32 @@
|
|||
#include "art.h"
|
||||
#include "game.h"
|
||||
#include "map.h"
|
||||
#include "mapper/mp_proto.h"
|
||||
#include "memory.h"
|
||||
#include "proto.h"
|
||||
#include "window_manager_private.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
#define TARGET_DAT "target.dat"
|
||||
|
||||
typedef struct TargetNode {
|
||||
TargetSubNode subnode;
|
||||
struct TargetNode* next;
|
||||
} TargetNode;
|
||||
|
||||
typedef struct TargetList {
|
||||
TargetNode* tail;
|
||||
int count;
|
||||
int next_tid;
|
||||
} TargetList;
|
||||
|
||||
// 0x53F354
|
||||
static char default_target_path_base[] = "\\fallout2\\dev\\proto\\";
|
||||
|
||||
// 0x559CC4
|
||||
static TargetList targetlist = { NULL, 0, 0 };
|
||||
|
||||
// 0x559CD0
|
||||
static char* target_path_base = default_target_path_base;
|
||||
|
||||
|
@ -22,7 +40,17 @@ static bool tgt_overriden = false;
|
|||
// 0x49B2F0
|
||||
void target_override_protection()
|
||||
{
|
||||
// TODO: Incomplete.
|
||||
char* name;
|
||||
|
||||
tgt_overriden = true;
|
||||
|
||||
name = getenv("MAIL_NAME");
|
||||
if (name != NULL) {
|
||||
// NOTE: Unsafe, backing buffer is 32 byte max.
|
||||
strcpy(proto_builder_name, strupr(name));
|
||||
} else {
|
||||
strcpy(proto_builder_name, "UNKNOWN");
|
||||
}
|
||||
}
|
||||
|
||||
// 0x49B2F0
|
||||
|
@ -49,7 +77,8 @@ void target_make_path(char* path, int pid)
|
|||
// 0x49B424
|
||||
int target_init()
|
||||
{
|
||||
// TODO: Incomplete.
|
||||
target_remove_all();
|
||||
target_header_load();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -57,11 +86,359 @@ int target_init()
|
|||
// 0x49B434
|
||||
int target_exit()
|
||||
{
|
||||
// TODO: Incomplete.
|
||||
if (can_modify_protos) {
|
||||
target_header_save();
|
||||
target_remove_all();
|
||||
} else {
|
||||
target_remove_all();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x49B454
|
||||
int target_header_save()
|
||||
{
|
||||
char path[COMPAT_MAX_PATH];
|
||||
FILE* stream;
|
||||
|
||||
target_make_path(path, -1);
|
||||
strcat(path, TARGET_DAT);
|
||||
|
||||
stream = fopen(path, "wb");
|
||||
if (stream == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fwrite(&targetlist, sizeof(targetlist), 1, stream) != 1) {
|
||||
// FIXME: Leaking `stream`.
|
||||
return -1;
|
||||
}
|
||||
|
||||
fclose(stream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x49B4E8
|
||||
int target_header_load()
|
||||
{
|
||||
char path[COMPAT_MAX_PATH];
|
||||
FILE* stream;
|
||||
|
||||
target_make_path(path, -1);
|
||||
strcat(path, TARGET_DAT);
|
||||
|
||||
stream = fopen(path, "rb");
|
||||
if (stream == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fread(&targetlist, sizeof(targetlist), 1, stream) != 1) {
|
||||
// FIXME: Leaking `stream`.
|
||||
return -1;
|
||||
}
|
||||
|
||||
targetlist.tail = NULL;
|
||||
targetlist.count = 0;
|
||||
|
||||
fclose(stream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x49B58C
|
||||
int target_save(int pid)
|
||||
{
|
||||
char path[COMPAT_MAX_PATH];
|
||||
size_t len;
|
||||
char* extension;
|
||||
FILE* stream;
|
||||
TargetSubNode* subnode;
|
||||
|
||||
if (target_ptr(pid, &subnode) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
target_make_path(path, pid);
|
||||
|
||||
len = strlen(path);
|
||||
path[len] = '\\';
|
||||
_proto_list_str(pid, path + len + 1);
|
||||
|
||||
extension = strchr(path + len + 1, '.');
|
||||
if (extension != NULL) {
|
||||
strcpy(extension + 1, "tgt");
|
||||
} else {
|
||||
strcat(path, ".tgt");
|
||||
}
|
||||
|
||||
stream = fopen(path, "wb");
|
||||
if (stream == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (subnode != NULL) {
|
||||
fwrite(subnode, sizeof(TargetSubNode), 1, stream);
|
||||
subnode = subnode->next;
|
||||
}
|
||||
|
||||
fclose(stream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x49B6BC
|
||||
int target_load(int pid, TargetSubNode** subnode_ptr)
|
||||
{
|
||||
char path[COMPAT_MAX_PATH];
|
||||
size_t len;
|
||||
char* extension;
|
||||
FILE* stream;
|
||||
TargetSubNode* subnode;
|
||||
|
||||
target_make_path(path, pid);
|
||||
|
||||
len = strlen(path);
|
||||
path[len] = '\\';
|
||||
_proto_list_str(pid, path + len + 1);
|
||||
|
||||
extension = strchr(path + len + 1, '.');
|
||||
if (extension != NULL) {
|
||||
strcpy(extension + 1, "tgt");
|
||||
} else {
|
||||
strcat(path, ".tgt");
|
||||
}
|
||||
|
||||
stream = fopen(path, "rb");
|
||||
if (stream == NULL) {
|
||||
*subnode_ptr = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (target_find_free_subnode(&subnode) == -1) {
|
||||
*subnode_ptr = NULL;
|
||||
// FIXME: Leaks `stream`.
|
||||
return -1;
|
||||
}
|
||||
|
||||
fread(subnode, sizeof(TargetSubNode), 1, stream);
|
||||
|
||||
*subnode_ptr = subnode;
|
||||
|
||||
while (subnode->next != NULL) {
|
||||
subnode->next = (TargetSubNode*)internal_malloc(sizeof(TargetSubNode));
|
||||
if (subnode->next == NULL) {
|
||||
// FIXME: Leaks `stream`.
|
||||
return -1;
|
||||
}
|
||||
|
||||
subnode = subnode->next;
|
||||
fread(subnode, sizeof(TargetSubNode), 1, stream);
|
||||
}
|
||||
|
||||
fclose(stream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x49B9C0
|
||||
int target_find_free_subnode(TargetSubNode** subnode_ptr)
|
||||
{
|
||||
TargetNode* node = (TargetNode*)internal_malloc(sizeof(TargetNode));
|
||||
if (node == NULL) {
|
||||
*subnode_ptr = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*subnode_ptr = &(node->subnode);
|
||||
|
||||
node->subnode.pid = -1;
|
||||
node->subnode.next = NULL;
|
||||
node->next = targetlist.tail;
|
||||
|
||||
targetlist.tail = node;
|
||||
targetlist.count++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x49BA10
|
||||
int target_new(int pid, int* tid_ptr)
|
||||
{
|
||||
TargetSubNode* subnode;
|
||||
TargetSubNode* new_subnode;
|
||||
|
||||
if (target_ptr(pid, &subnode) == -1) {
|
||||
if (target_find_free_subnode(&subnode) == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
new_subnode = (TargetSubNode*)internal_malloc(sizeof(TargetSubNode));
|
||||
if (new_subnode == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
new_subnode->next = NULL;
|
||||
|
||||
while (subnode->next != NULL) {
|
||||
subnode = subnode->next;
|
||||
}
|
||||
|
||||
subnode->next = new_subnode;
|
||||
|
||||
new_subnode->pid = pid;
|
||||
new_subnode->tid = targetlist.next_tid;
|
||||
|
||||
*tid_ptr = targetlist.next_tid;
|
||||
|
||||
targetlist.count++;
|
||||
targetlist.next_tid++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x49BBD4
|
||||
int target_remove(int pid)
|
||||
{
|
||||
TargetNode* node;
|
||||
TargetSubNode* subnode;
|
||||
TargetSubNode* subnode_next;
|
||||
|
||||
node = targetlist.tail;
|
||||
while (node != NULL) {
|
||||
if (node->subnode.pid == pid) {
|
||||
break;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
if (node == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
subnode = node->subnode.next;
|
||||
|
||||
if (node == targetlist.tail) {
|
||||
targetlist.tail = targetlist.tail->next;
|
||||
}
|
||||
|
||||
internal_free(node);
|
||||
|
||||
while (subnode != NULL) {
|
||||
subnode_next = subnode->next;
|
||||
internal_free(subnode);
|
||||
subnode = subnode_next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x49BC3C
|
||||
int target_remove_tid(int pid, int tid)
|
||||
{
|
||||
TargetNode* node;
|
||||
TargetSubNode* subnode;
|
||||
TargetSubNode* subnode_next;
|
||||
|
||||
node = targetlist.tail;
|
||||
while (node != NULL) {
|
||||
if (node->subnode.pid == pid) {
|
||||
break;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
if (node == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (node->subnode.tid == tid) {
|
||||
subnode_next = node->subnode.next;
|
||||
if (subnode_next != NULL) {
|
||||
memcpy(&(node->subnode), subnode_next, sizeof(TargetSubNode));
|
||||
internal_free(subnode_next);
|
||||
} else {
|
||||
target_remove(pid);
|
||||
}
|
||||
|
||||
// FIXME: Should probably return 0 here.
|
||||
} else {
|
||||
subnode = &(node->subnode);
|
||||
while (subnode != NULL) {
|
||||
subnode_next = subnode->next;
|
||||
if (subnode_next->tid == tid) {
|
||||
subnode->next = subnode_next->next;
|
||||
internal_free(subnode_next);
|
||||
return 0;
|
||||
}
|
||||
|
||||
subnode = subnode_next;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 0x49BCBC
|
||||
int target_remove_all()
|
||||
{
|
||||
TargetNode* node;
|
||||
TargetNode* node_next;
|
||||
TargetSubNode* subnode;
|
||||
TargetSubNode* subnode_next;
|
||||
|
||||
node = targetlist.tail;
|
||||
targetlist.tail = NULL;
|
||||
|
||||
while (node != NULL) {
|
||||
node_next = node->next;
|
||||
|
||||
subnode = node->subnode.next;
|
||||
while (subnode != NULL) {
|
||||
subnode_next = subnode->next;
|
||||
internal_free(subnode);
|
||||
subnode = subnode_next;
|
||||
}
|
||||
|
||||
internal_free(node);
|
||||
node = node_next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x49BD00
|
||||
int target_ptr(int pid, TargetSubNode** subnode_ptr)
|
||||
{
|
||||
TargetNode* node = targetlist.tail;
|
||||
while (node != NULL) {
|
||||
if (node->subnode.pid == pid) {
|
||||
*subnode_ptr = &(node->subnode);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return target_load(pid, subnode_ptr);
|
||||
}
|
||||
|
||||
// 0x49BD38
|
||||
int target_tid_ptr(int pid, int tid, TargetSubNode** subnode_ptr)
|
||||
{
|
||||
TargetSubNode* subnode;
|
||||
if (target_ptr(pid, &subnode) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (subnode != NULL) {
|
||||
if (subnode->tid == tid) {
|
||||
*subnode_ptr = subnode;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 0x49BD98
|
||||
int pick_rot()
|
||||
{
|
||||
|
|
|
@ -3,11 +3,65 @@
|
|||
|
||||
namespace fallout {
|
||||
|
||||
typedef struct TargetSubNode {
|
||||
int pid;
|
||||
int tid;
|
||||
int field_8;
|
||||
int field_C;
|
||||
int field_10;
|
||||
int field_14;
|
||||
int field_18;
|
||||
int field_1C;
|
||||
int field_20;
|
||||
int field_24;
|
||||
struct TargetSubNode* next;
|
||||
int field_2C;
|
||||
int field_30;
|
||||
int field_34;
|
||||
int field_38;
|
||||
int field_3C;
|
||||
int field_40;
|
||||
int field_44;
|
||||
int field_48;
|
||||
int field_4C;
|
||||
int field_50;
|
||||
int field_54;
|
||||
int field_58;
|
||||
int field_5C;
|
||||
int field_60;
|
||||
int field_64;
|
||||
int field_68;
|
||||
int field_6C;
|
||||
int field_70;
|
||||
int field_74;
|
||||
int field_78;
|
||||
int field_7C;
|
||||
int field_80;
|
||||
int field_84;
|
||||
int field_88;
|
||||
int field_8C;
|
||||
int field_90;
|
||||
int field_94;
|
||||
int field_98;
|
||||
int field_9C;
|
||||
} TargetSubNode;
|
||||
|
||||
void target_override_protection();
|
||||
bool target_overriden();
|
||||
void target_make_path(char* path, int pid);
|
||||
int target_init();
|
||||
int target_exit();
|
||||
int target_header_save();
|
||||
int target_header_load();
|
||||
int target_save(int pid);
|
||||
int target_load(int pid, TargetSubNode** subnode_ptr);
|
||||
int target_find_free_subnode(TargetSubNode** subnode_ptr);
|
||||
int target_new(int pid, int* tid_ptr);
|
||||
int target_remove(int pid);
|
||||
int target_remove_tid(int pid, int tid);
|
||||
int target_remove_all();
|
||||
int target_ptr(int pid, TargetSubNode** subnode_ptr);
|
||||
int target_tid_ptr(int pid, int tid, TargetSubNode** subnode_ptr);
|
||||
int pick_rot();
|
||||
int target_pick_global_var(int* value_ptr);
|
||||
int target_pick_map_var(int* value_ptr);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "audio_engine.h"
|
||||
#include "delay.h"
|
||||
#include "platform_compat.h"
|
||||
|
||||
namespace fallout {
|
||||
|
@ -794,6 +795,8 @@ static int _syncWait()
|
|||
if (_sync_active) {
|
||||
if (((_sync_time + 1000 * compat_timeGetTime()) & 0x80000000) != 0) {
|
||||
result = 1;
|
||||
|
||||
delay_ms(-(_sync_time + 1000 * compat_timeGetTime()) / 1000 - 3);
|
||||
while (((_sync_time + 1000 * compat_timeGetTime()) & 0x80000000) != 0)
|
||||
;
|
||||
}
|
||||
|
@ -1148,6 +1151,7 @@ static int _MVE_sndConfigure(int a1, int a2, int a3, int a4, int a5, int a6)
|
|||
}
|
||||
|
||||
// 0x4F56C0
|
||||
// Looks like this function is not used
|
||||
static void _MVE_syncSync()
|
||||
{
|
||||
if (_sync_active) {
|
||||
|
@ -1294,6 +1298,10 @@ static void _MVE_sndSync()
|
|||
break;
|
||||
}
|
||||
v0 = true;
|
||||
|
||||
#ifdef EMSCRIPTEN
|
||||
delay_ms(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (dword_6B3660 != dword_6B3AE4) {
|
||||
|
@ -1318,6 +1326,10 @@ static int _syncWaitLevel(int a1)
|
|||
v2 = _sync_time + a1;
|
||||
do {
|
||||
result = v2 + 1000 * compat_timeGetTime();
|
||||
if (result < 0) {
|
||||
delay_ms(-result / 1000 - 3);
|
||||
}
|
||||
result = v2 + 1000 * compat_timeGetTime();
|
||||
} while (result < 0);
|
||||
|
||||
_sync_time += _sync_wait_quanta;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "cycle.h"
|
||||
#include "dbox.h"
|
||||
#include "debug.h"
|
||||
#include "delay.h"
|
||||
#include "draw.h"
|
||||
#include "game.h"
|
||||
#include "game_mouse.h"
|
||||
|
@ -2001,8 +2002,7 @@ static bool pipboyRest(int hours, int minutes, int duration)
|
|||
pipboyDrawDate();
|
||||
windowRefresh(gPipboyWindow);
|
||||
|
||||
while (getTicksSince(start) < 50) {
|
||||
}
|
||||
delay_ms(50 - (getTicks() - start));
|
||||
}
|
||||
|
||||
renderPresent();
|
||||
|
@ -2072,8 +2072,7 @@ static bool pipboyRest(int hours, int minutes, int duration)
|
|||
pipboyDrawHitPoints();
|
||||
windowRefresh(gPipboyWindow);
|
||||
|
||||
while (getTicksSince(start) < 50) {
|
||||
}
|
||||
delay_ms(50 - (getTicks() - start));
|
||||
}
|
||||
|
||||
renderPresent();
|
||||
|
@ -2366,8 +2365,7 @@ static int pipboyRenderScreensaver()
|
|||
v31 -= 1;
|
||||
} else {
|
||||
windowRefreshRect(gPipboyWindow, &gPipboyWindowContentRect);
|
||||
while (getTicksSince(time) < 50) {
|
||||
}
|
||||
delay_ms(50 - (getTicks() - time));
|
||||
}
|
||||
|
||||
renderPresent();
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "combat.h"
|
||||
#include "combat_ai.h"
|
||||
#include "debug.h"
|
||||
#include "delay.h"
|
||||
#include "draw.h"
|
||||
#include "game.h"
|
||||
#include "game_mouse.h"
|
||||
|
@ -1570,8 +1571,7 @@ static void _DoThing(int eventCode)
|
|||
blitBufferToBufferTrans(_preferencesFrmImages[PREFERENCES_WINDOW_FRM_KNOB_ON].getData(), 21, 12, 21, gPreferencesWindowBuffer + PREFERENCES_WINDOW_WIDTH * meta->knobY + v31, PREFERENCES_WINDOW_WIDTH);
|
||||
windowRefresh(gPreferencesWindow);
|
||||
|
||||
while (getTicksSince(tick) < 35)
|
||||
;
|
||||
delay_ms(35 - (getTicks() - tick));
|
||||
|
||||
renderPresent();
|
||||
sharedFpsLimiter.throttle();
|
||||
|
|
|
@ -39,7 +39,6 @@ static int _proto_find_free_subnode(int type, Proto** out_ptr);
|
|||
static void _proto_remove_some_list(int type);
|
||||
static void _proto_remove_list(int type);
|
||||
static int _proto_new_id(int type);
|
||||
static int _proto_max_id(int type);
|
||||
|
||||
// 0x50CF3C
|
||||
static char _aProto_0[] = "proto\\";
|
||||
|
@ -168,7 +167,7 @@ char* _proto_none_str;
|
|||
static char* gBodyTypeNames[BODY_TYPE_COUNT];
|
||||
|
||||
// 0x664834
|
||||
static char* gItemTypeNames[ITEM_TYPE_COUNT];
|
||||
char* gItemTypeNames[ITEM_TYPE_COUNT];
|
||||
|
||||
// 0x66484C
|
||||
static char* gDamageTypeNames[DAMAGE_TYPE_COUNT];
|
||||
|
@ -2170,7 +2169,7 @@ static int _proto_new_id(int type)
|
|||
}
|
||||
|
||||
// 0x4A2214
|
||||
static int _proto_max_id(int type)
|
||||
int proto_max_id(int type)
|
||||
{
|
||||
return _protoLists[type].max_entries_num;
|
||||
}
|
||||
|
|
|
@ -101,6 +101,7 @@ extern char _cd_path_base[COMPAT_MAX_PATH];
|
|||
|
||||
extern MessageList gProtoMessageList;
|
||||
extern char* _proto_none_str;
|
||||
extern char* gItemTypeNames[ITEM_TYPE_COUNT];
|
||||
|
||||
void proto_make_path(char* path, int pid);
|
||||
int _proto_list_str(int pid, char* proto_path);
|
||||
|
@ -137,6 +138,7 @@ int proto_new(int* pid, int type);
|
|||
void _proto_remove_all();
|
||||
int protoGetProto(int pid, Proto** protoPtr);
|
||||
int _ResetPlayer();
|
||||
int proto_max_id(int type);
|
||||
|
||||
static bool isExitGridPid(int pid)
|
||||
{
|
||||
|
|
|
@ -1998,6 +1998,8 @@ static int scriptRead(Script* scr, File* stream)
|
|||
scr->localVarsCount = 0;
|
||||
}
|
||||
|
||||
scr->overriddenSelf = nullptr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2214,6 +2216,8 @@ int scriptAdd(int* sidPtr, int scriptType)
|
|||
scr->procs[index] = SCRIPT_PROC_NO_PROC;
|
||||
}
|
||||
|
||||
scr->overriddenSelf = nullptr;
|
||||
|
||||
scriptListExtent->length++;
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -143,6 +143,8 @@ typedef struct Script {
|
|||
int field_D4;
|
||||
int field_D8;
|
||||
int field_DC;
|
||||
|
||||
Object* overriddenSelf;
|
||||
} Script;
|
||||
|
||||
extern const char* gScriptProcNames[SCRIPT_PROC_COUNT];
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "interpreter.h"
|
||||
#include "sfall_lists.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
|
@ -647,6 +648,25 @@ ProgramValue ScanArray(ArrayId arrayId, const ProgramValue& val, Program* progra
|
|||
return arr->ScanArray(val, program);
|
||||
}
|
||||
|
||||
ArrayId ListAsArray(int type)
|
||||
{
|
||||
std::vector<Object*> objects;
|
||||
sfall_lists_fill(type, objects);
|
||||
|
||||
int count = static_cast<int>(objects.size());
|
||||
ArrayId arrayId = CreateTempArray(count, 0);
|
||||
auto arr = get_array_by_id(arrayId);
|
||||
|
||||
// A little bit ugly and likely inefficient.
|
||||
for (int index = 0; index < count; index++) {
|
||||
arr->SetArray(ProgramValue { index },
|
||||
ArrayElement { ProgramValue { objects[index] }, nullptr },
|
||||
false);
|
||||
}
|
||||
|
||||
return arrayId;
|
||||
}
|
||||
|
||||
ArrayId StringSplit(const char* str, const char* split)
|
||||
{
|
||||
size_t splitLen = strlen(split);
|
||||
|
|
|
@ -26,6 +26,7 @@ void ResizeArray(ArrayId arrayId, int newLen);
|
|||
void DeleteAllTempArrays();
|
||||
int StackArray(const ProgramValue& key, const ProgramValue& val, Program* program);
|
||||
ProgramValue ScanArray(ArrayId arrayId, const ProgramValue& val, Program* program);
|
||||
ArrayId ListAsArray(int type);
|
||||
|
||||
ArrayId StringSplit(const char* str, const char* split);
|
||||
|
||||
|
|
|
@ -58,6 +58,9 @@ bool sfallConfigInit(int argc, char** argv)
|
|||
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MOVIE_TIMER_ARTIMER3, 270);
|
||||
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MOVIE_TIMER_ARTIMER4, 360);
|
||||
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_AUTO_QUICK_SAVE, 0);
|
||||
configSetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_VERSION_STRING, "");
|
||||
configSetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_CONFIG_FILE, "");
|
||||
configSetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_PATCH_FILE, "");
|
||||
|
||||
configSetString(&gSfallConfig, SFALL_CONFIG_SCRIPTS_KEY, SFALL_CONFIG_INI_CONFIG_FOLDER, "");
|
||||
configSetString(&gSfallConfig, SFALL_CONFIG_SCRIPTS_KEY, SFALL_CONFIG_GLOBAL_SCRIPT_PATHS, "");
|
||||
|
|
|
@ -72,6 +72,9 @@ namespace fallout {
|
|||
#define SFALL_CONFIG_INI_CONFIG_FOLDER "IniConfigFolder"
|
||||
#define SFALL_CONFIG_GLOBAL_SCRIPT_PATHS "GlobalScriptPaths"
|
||||
#define SFALL_CONFIG_AUTO_QUICK_SAVE "AutoQuickSave"
|
||||
#define SFALL_CONFIG_VERSION_STRING "VersionString"
|
||||
#define SFALL_CONFIG_CONFIG_FILE "ConfigFile"
|
||||
#define SFALL_CONFIG_PATCH_FILE "PatchFile"
|
||||
|
||||
#define SFALL_CONFIG_BURST_MOD_DEFAULT_CENTER_MULTIPLIER 1
|
||||
#define SFALL_CONFIG_BURST_MOD_DEFAULT_CENTER_DIVISOR 3
|
||||
|
|
|
@ -145,4 +145,53 @@ bool sfall_ini_get_string(const char* triplet, char* value, size_t size)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool sfall_ini_set_int(const char* triplet, int value)
|
||||
{
|
||||
char stringValue[20];
|
||||
compat_itoa(value, stringValue, 10);
|
||||
|
||||
return sfall_ini_set_string(triplet, stringValue);
|
||||
}
|
||||
|
||||
bool sfall_ini_set_string(const char* triplet, const char* value)
|
||||
{
|
||||
char fileName[kFileNameMaxSize];
|
||||
char section[kSectionMaxSize];
|
||||
|
||||
const char* key = parse_ini_triplet(triplet, fileName, section);
|
||||
if (key == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Config config;
|
||||
if (!configInit(&config)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char path[COMPAT_MAX_PATH];
|
||||
bool loaded = false;
|
||||
|
||||
if (basePath[0] != '\0' && !is_system_file_name(fileName)) {
|
||||
// Attempt to load requested file in base directory.
|
||||
snprintf(path, sizeof(path), "%s\\%s", basePath, fileName);
|
||||
loaded = configRead(&config, path, false);
|
||||
}
|
||||
|
||||
if (!loaded) {
|
||||
// There was no base path set, requested file is a system config, or
|
||||
// non-system config file was not found the base path - attempt to load
|
||||
// from current working directory.
|
||||
strcpy(path, fileName);
|
||||
loaded = configRead(&config, path, false);
|
||||
}
|
||||
|
||||
configSetString(&config, section, key, value);
|
||||
|
||||
bool saved = configWrite(&config, path, false);
|
||||
|
||||
configFree(&config);
|
||||
|
||||
return saved;
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
|
|
@ -14,6 +14,12 @@ bool sfall_ini_get_int(const char* triplet, int* value);
|
|||
/// Reads string key identified by "fileName|section|key" triplet into `value`.
|
||||
bool sfall_ini_get_string(const char* triplet, char* value, size_t size);
|
||||
|
||||
/// Writes integer key identified by "fileName|section|key" triplet.
|
||||
bool sfall_ini_set_int(const char* triplet, int value);
|
||||
|
||||
/// Writes string key identified by "fileName|section|key" triplet.
|
||||
bool sfall_ini_set_string(const char* triplet, const char* value);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* FALLOUT_SFALL_INI_H_ */
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#include "sfall_lists.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "object.h"
|
||||
#include "scripts.h"
|
||||
|
@ -66,46 +65,7 @@ int sfallListsCreate(int listType)
|
|||
int listId = _state->nextListId++;
|
||||
List& list = _state->lists[listId];
|
||||
|
||||
if (listType == LIST_TILES) {
|
||||
// For unknown reason this list type is not implemented in Sfall.
|
||||
} else if (listType == LIST_SPATIAL) {
|
||||
for (int elevation = 0; elevation < ELEVATION_COUNT; elevation++) {
|
||||
Script* script = scriptGetFirstSpatialScript(elevation);
|
||||
while (script != nullptr) {
|
||||
Object* obj = script->owner;
|
||||
if (obj == nullptr) {
|
||||
obj = scriptGetSelf(script->program);
|
||||
}
|
||||
list.objects.push_back(obj);
|
||||
script = scriptGetNextSpatialScript();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// CE: Implementation is slightly different. Sfall manually loops thru
|
||||
// elevations (3) and hexes (40000) and use |objectFindFirstAtLocation|
|
||||
// (originally |obj_find_first_at_tile|) to obtain next object. This
|
||||
// functionality is already implemented in |objectFindFirst| and
|
||||
// |objectFindNext|.
|
||||
//
|
||||
// As a small optimization |LIST_ALL| is handled separately since there
|
||||
// is no need to check object type.
|
||||
if (listType == LIST_ALL) {
|
||||
Object* obj = objectFindFirst();
|
||||
while (obj != nullptr) {
|
||||
list.objects.push_back(obj);
|
||||
obj = objectFindNext();
|
||||
}
|
||||
} else {
|
||||
Object* obj = objectFindFirst();
|
||||
while (obj != nullptr) {
|
||||
int objectType = PID_TYPE(obj->pid);
|
||||
if (objectType < kObjectTypeToListTypeSize && kObjectTypeToListType[objectType] == listType) {
|
||||
list.objects.push_back(obj);
|
||||
}
|
||||
obj = objectFindNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
sfall_lists_fill(listType, list.objects);
|
||||
|
||||
return listId;
|
||||
}
|
||||
|
@ -131,4 +91,54 @@ void sfallListsDestroy(int listId)
|
|||
}
|
||||
}
|
||||
|
||||
void sfall_lists_fill(int type, std::vector<Object*>& objects)
|
||||
{
|
||||
if (type == LIST_TILES) {
|
||||
// For unknown reason this list type is not implemented in Sfall.
|
||||
return;
|
||||
}
|
||||
|
||||
objects.reserve(100);
|
||||
|
||||
if (type == LIST_SPATIAL) {
|
||||
for (int elevation = 0; elevation < ELEVATION_COUNT; elevation++) {
|
||||
Script* script = scriptGetFirstSpatialScript(elevation);
|
||||
while (script != nullptr) {
|
||||
Object* obj = script->owner;
|
||||
if (obj == nullptr) {
|
||||
obj = scriptGetSelf(script->program);
|
||||
}
|
||||
objects.push_back(obj);
|
||||
script = scriptGetNextSpatialScript();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// CE: Implementation is slightly different. Sfall manually loops thru
|
||||
// elevations (3) and hexes (40000) and use |objectFindFirstAtLocation|
|
||||
// (originally |obj_find_first_at_tile|) to obtain next object. This
|
||||
// functionality is already implemented in |objectFindFirst| and
|
||||
// |objectFindNext|.
|
||||
//
|
||||
// As a small optimization |LIST_ALL| is handled separately since there
|
||||
// is no need to check object type.
|
||||
if (type == LIST_ALL) {
|
||||
Object* obj = objectFindFirst();
|
||||
while (obj != nullptr) {
|
||||
objects.push_back(obj);
|
||||
obj = objectFindNext();
|
||||
}
|
||||
} else {
|
||||
Object* obj = objectFindFirst();
|
||||
while (obj != nullptr) {
|
||||
int objectType = PID_TYPE(obj->pid);
|
||||
if (objectType < kObjectTypeToListTypeSize
|
||||
&& kObjectTypeToListType[objectType] == type) {
|
||||
objects.push_back(obj);
|
||||
}
|
||||
obj = objectFindNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef FALLOUT_SFALL_LISTS_H_
|
||||
#define FALLOUT_SFALL_LISTS_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "obj_types.h"
|
||||
|
||||
namespace fallout {
|
||||
|
@ -22,6 +24,7 @@ void sfallListsExit();
|
|||
int sfallListsCreate(int listType);
|
||||
Object* sfallListsGetNext(int listId);
|
||||
void sfallListsDestroy(int listId);
|
||||
void sfall_lists_fill(int type, std::vector<Object*>& objects);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
|
|
|
@ -0,0 +1,291 @@
|
|||
#include "sfall_metarules.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "combat.h"
|
||||
#include "debug.h"
|
||||
#include "game.h"
|
||||
#include "game_dialog.h"
|
||||
#include "game_mouse.h"
|
||||
#include "interface.h"
|
||||
#include "inventory.h"
|
||||
#include "object.h"
|
||||
#include "sfall_ini.h"
|
||||
#include "text_font.h"
|
||||
#include "tile.h"
|
||||
#include "window.h"
|
||||
#include "worldmap.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
typedef void(MetaruleHandler)(Program* program, int args);
|
||||
|
||||
// Simplified cousin of `SfallMetarule` from Sfall.
|
||||
typedef struct MetaruleInfo {
|
||||
const char* name;
|
||||
MetaruleHandler* handler;
|
||||
int minArgs;
|
||||
int maxArgs;
|
||||
} MetaruleInfo;
|
||||
|
||||
static void mf_car_gas_amount(Program* program, int args);
|
||||
static void mf_combat_data(Program* program, int args);
|
||||
static void mf_critter_inven_obj2(Program* program, int args);
|
||||
static void mf_dialog_obj(Program* program, int args);
|
||||
static void mf_get_cursor_mode(Program* program, int args);
|
||||
static void mf_get_flags(Program* program, int args);
|
||||
static void mf_get_object_data(Program* program, int args);
|
||||
static void mf_get_text_width(Program* program, int args);
|
||||
static void mf_intface_redraw(Program* program, int args);
|
||||
static void mf_loot_obj(Program* program, int args);
|
||||
static void mf_metarule_exist(Program* program, int args);
|
||||
static void mf_outlined_object(Program* program, int args);
|
||||
static void mf_set_cursor_mode(Program* program, int args);
|
||||
static void mf_set_flags(Program* program, int args);
|
||||
static void mf_set_ini_setting(Program* program, int args);
|
||||
static void mf_set_outline(Program* program, int args);
|
||||
static void mf_show_window(Program* program, int args);
|
||||
static void mf_tile_refresh_display(Program* program, int args);
|
||||
|
||||
constexpr MetaruleInfo kMetarules[] = {
|
||||
{ "car_gas_amount", mf_car_gas_amount, 0, 0 },
|
||||
{ "combat_data", mf_combat_data, 0, 0 },
|
||||
{ "critter_inven_obj2", mf_critter_inven_obj2, 2, 2 },
|
||||
{ "dialog_obj", mf_dialog_obj, 0, 0 },
|
||||
{ "get_cursor_mode", mf_get_cursor_mode, 0, 0 },
|
||||
{ "get_flags", mf_get_flags, 1, 1 },
|
||||
{ "get_object_data", mf_get_object_data, 2, 2 },
|
||||
{ "get_text_width", mf_get_text_width, 1, 1 },
|
||||
{ "intface_redraw", mf_intface_redraw, 0, 1 },
|
||||
{ "loot_obj", mf_loot_obj, 0, 0 },
|
||||
{ "metarule_exist", mf_metarule_exist, 1, 1 },
|
||||
{ "outlined_object", mf_outlined_object, 0, 0 },
|
||||
{ "set_cursor_mode", mf_set_cursor_mode, 1, 1 },
|
||||
{ "set_flags", mf_set_flags, 2, 2 },
|
||||
{ "set_ini_setting", mf_set_ini_setting, 2, 2 },
|
||||
{ "set_outline", mf_set_outline, 2, 2 },
|
||||
{ "show_window", mf_show_window, 0, 1 },
|
||||
{ "tile_refresh_display", mf_tile_refresh_display, 0, 0 },
|
||||
};
|
||||
|
||||
constexpr int kMetarulesMax = sizeof(kMetarules) / sizeof(kMetarules[0]);
|
||||
|
||||
void mf_car_gas_amount(Program* program, int args)
|
||||
{
|
||||
programStackPushInteger(program, wmCarGasAmount());
|
||||
}
|
||||
|
||||
void mf_combat_data(Program* program, int args)
|
||||
{
|
||||
if (isInCombat()) {
|
||||
programStackPushPointer(program, combat_get_data());
|
||||
} else {
|
||||
programStackPushPointer(program, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void mf_critter_inven_obj2(Program* program, int args)
|
||||
{
|
||||
int slot = programStackPopInteger(program);
|
||||
Object* obj = static_cast<Object*>(programStackPopPointer(program));
|
||||
|
||||
switch (slot) {
|
||||
case 0:
|
||||
programStackPushPointer(program, critterGetArmor(obj));
|
||||
break;
|
||||
case 1:
|
||||
programStackPushPointer(program, critterGetItem2(obj));
|
||||
break;
|
||||
case 2:
|
||||
programStackPushPointer(program, critterGetItem1(obj));
|
||||
break;
|
||||
case -2:
|
||||
programStackPushInteger(program, obj->data.inventory.length);
|
||||
break;
|
||||
default:
|
||||
programFatalError("mf_critter_inven_obj2: invalid type");
|
||||
}
|
||||
}
|
||||
|
||||
void mf_dialog_obj(Program* program, int args)
|
||||
{
|
||||
if (GameMode::isInGameMode(GameMode::kDialog)) {
|
||||
programStackPushPointer(program, gGameDialogSpeaker);
|
||||
} else {
|
||||
programStackPushPointer(program, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void mf_get_cursor_mode(Program* program, int args)
|
||||
{
|
||||
programStackPushInteger(program, gameMouseGetMode());
|
||||
}
|
||||
|
||||
void mf_get_flags(Program* program, int args)
|
||||
{
|
||||
Object* object = static_cast<Object*>(programStackPopPointer(program));
|
||||
programStackPushInteger(program, object->flags);
|
||||
}
|
||||
|
||||
void mf_get_object_data(Program* program, int args)
|
||||
{
|
||||
size_t offset = static_cast<size_t>(programStackPopInteger(program));
|
||||
void* ptr = programStackPopPointer(program);
|
||||
|
||||
if (offset % 4 != 0) {
|
||||
programFatalError("mf_get_object_data: bad offset %d", offset);
|
||||
}
|
||||
|
||||
int value = *reinterpret_cast<int*>(reinterpret_cast<unsigned char*>(ptr) + offset);
|
||||
programStackPushInteger(program, value);
|
||||
}
|
||||
|
||||
void mf_get_text_width(Program* program, int args)
|
||||
{
|
||||
const char* string = programStackPopString(program);
|
||||
programStackPushInteger(program, fontGetStringWidth(string));
|
||||
}
|
||||
|
||||
void mf_intface_redraw(Program* program, int args)
|
||||
{
|
||||
if (args == 0) {
|
||||
interfaceBarRefresh();
|
||||
} else {
|
||||
// TODO: Incomplete.
|
||||
programFatalError("mf_intface_redraw: not implemented");
|
||||
}
|
||||
|
||||
programStackPushInteger(program, -1);
|
||||
}
|
||||
|
||||
void mf_loot_obj(Program* program, int args)
|
||||
{
|
||||
if (GameMode::isInGameMode(GameMode::kInventory)) {
|
||||
programStackPushPointer(program, inven_get_current_target_obj());
|
||||
} else {
|
||||
programStackPushPointer(program, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void mf_metarule_exist(Program* program, int args)
|
||||
{
|
||||
const char* metarule = programStackPopString(program);
|
||||
|
||||
for (int index = 0; index < kMetarulesMax; index++) {
|
||||
if (strcmp(kMetarules[index].name, metarule) == 0) {
|
||||
programStackPushInteger(program, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
programStackPushInteger(program, 0);
|
||||
}
|
||||
|
||||
void mf_outlined_object(Program* program, int args)
|
||||
{
|
||||
programStackPushPointer(program, gmouse_get_outlined_object());
|
||||
}
|
||||
|
||||
void mf_set_cursor_mode(Program* program, int args)
|
||||
{
|
||||
int mode = programStackPopInteger(program);
|
||||
gameMouseSetMode(mode);
|
||||
programStackPushInteger(program, -1);
|
||||
}
|
||||
|
||||
void mf_set_flags(Program* program, int args)
|
||||
{
|
||||
int flags = programStackPopInteger(program);
|
||||
Object* object = static_cast<Object*>(programStackPopPointer(program));
|
||||
|
||||
object->flags = flags;
|
||||
|
||||
programStackPushInteger(program, -1);
|
||||
}
|
||||
|
||||
void mf_set_ini_setting(Program* program, int args)
|
||||
{
|
||||
ProgramValue value = programStackPopValue(program);
|
||||
const char* triplet = programStackPopString(program);
|
||||
|
||||
if (value.isString()) {
|
||||
const char* stringValue = programGetString(program, value.opcode, value.integerValue);
|
||||
if (!sfall_ini_set_string(triplet, stringValue)) {
|
||||
debugPrint("set_ini_setting: unable to write '%s' to '%s'",
|
||||
stringValue,
|
||||
triplet);
|
||||
}
|
||||
} else {
|
||||
int integerValue = value.asInt();
|
||||
if (!sfall_ini_set_int(triplet, integerValue)) {
|
||||
debugPrint("set_ini_setting: unable to write '%d' to '%s'",
|
||||
integerValue,
|
||||
triplet);
|
||||
}
|
||||
}
|
||||
|
||||
programStackPushInteger(program, -1);
|
||||
}
|
||||
|
||||
void mf_set_outline(Program* program, int args)
|
||||
{
|
||||
int outline = programStackPopInteger(program);
|
||||
Object* object = static_cast<Object*>(programStackPopPointer(program));
|
||||
object->outline = outline;
|
||||
programStackPushInteger(program, -1);
|
||||
}
|
||||
|
||||
void mf_show_window(Program* program, int args)
|
||||
{
|
||||
if (args == 0) {
|
||||
_windowShow();
|
||||
} else if (args == 1) {
|
||||
const char* windowName = programStackPopString(program);
|
||||
if (!_windowShowNamed(windowName)) {
|
||||
debugPrint("show_window: window '%s' is not found", windowName);
|
||||
}
|
||||
}
|
||||
|
||||
programStackPushInteger(program, -1);
|
||||
}
|
||||
|
||||
void mf_tile_refresh_display(Program* program, int args)
|
||||
{
|
||||
tileWindowRefresh();
|
||||
programStackPushInteger(program, -1);
|
||||
}
|
||||
|
||||
void sfall_metarule(Program* program, int args)
|
||||
{
|
||||
static ProgramValue values[6];
|
||||
|
||||
for (int index = 0; index < args; index++) {
|
||||
values[index] = programStackPopValue(program);
|
||||
}
|
||||
|
||||
const char* metarule = programStackPopString(program);
|
||||
|
||||
for (int index = 0; index < args; index++) {
|
||||
programStackPushValue(program, values[index]);
|
||||
}
|
||||
|
||||
int metaruleIndex = -1;
|
||||
for (int index = 0; index < kMetarulesMax; index++) {
|
||||
if (strcmp(kMetarules[index].name, metarule) == 0) {
|
||||
metaruleIndex = index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (metaruleIndex == -1) {
|
||||
programFatalError("op_sfall_func: '%s' is not implemented", metarule);
|
||||
}
|
||||
|
||||
if (args < kMetarules[metaruleIndex].minArgs || args > kMetarules[metaruleIndex].maxArgs) {
|
||||
programFatalError("op_sfall_func: '%s': invalid number of args", metarule);
|
||||
}
|
||||
|
||||
kMetarules[metaruleIndex].handler(program, args);
|
||||
}
|
||||
|
||||
} // namespace fallout
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef FALLOUT_SFALL_METARULES_H_
|
||||
#define FALLOUT_SFALL_METARULES_H_
|
||||
|
||||
#include "interpreter.h"
|
||||
|
||||
namespace fallout {
|
||||
|
||||
void sfall_metarule(Program* program, int args);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* FALLOUT_SFALL_METARULES_H_ */
|
|
@ -26,6 +26,7 @@
|
|||
#include "sfall_ini.h"
|
||||
#include "sfall_kb_helpers.h"
|
||||
#include "sfall_lists.h"
|
||||
#include "sfall_metarules.h"
|
||||
#include "stat.h"
|
||||
#include "svga.h"
|
||||
#include "tile.h"
|
||||
|
@ -33,6 +34,18 @@
|
|||
|
||||
namespace fallout {
|
||||
|
||||
typedef enum ExplosionMetarule {
|
||||
EXPL_FORCE_EXPLOSION_PATTERN = 1,
|
||||
EXPL_FORCE_EXPLOSION_ART = 2,
|
||||
EXPL_FORCE_EXPLOSION_RADIUS = 3,
|
||||
EXPL_FORCE_EXPLOSION_DMGTYPE = 4,
|
||||
EXPL_STATIC_EXPLOSION_RADIUS = 5,
|
||||
EXPL_GET_EXPLOSION_DAMAGE = 6,
|
||||
EXPL_SET_DYNAMITE_EXPLOSION_DAMAGE = 7,
|
||||
EXPL_SET_PLASTIC_EXPLOSION_DAMAGE = 8,
|
||||
EXPL_SET_EXPLOSION_MAX_TARGET = 9,
|
||||
} ExplosionMetarule;
|
||||
|
||||
static constexpr int kVersionMajor = 4;
|
||||
static constexpr int kVersionMinor = 3;
|
||||
static constexpr int kVersionPatch = 4;
|
||||
|
@ -138,6 +151,13 @@ static void op_in_world_map(Program* program)
|
|||
programStackPushInteger(program, GameMode::isInGameMode(GameMode::kWorldmap) ? 1 : 0);
|
||||
}
|
||||
|
||||
// force_encounter
|
||||
static void op_force_encounter(Program* program)
|
||||
{
|
||||
int map = programStackPopInteger(program);
|
||||
wmForceEncounter(map, 0);
|
||||
}
|
||||
|
||||
// set_world_map_pos
|
||||
static void op_set_world_map_pos(Program* program)
|
||||
{
|
||||
|
@ -268,6 +288,13 @@ static void op_abs(Program* program)
|
|||
}
|
||||
}
|
||||
|
||||
// get_script
|
||||
static void op_get_script(Program* program)
|
||||
{
|
||||
Object* obj = static_cast<Object*>(programStackPopPointer(program));
|
||||
programStackPushInteger(program, obj->field_80 + 1);
|
||||
}
|
||||
|
||||
// get_proto_data
|
||||
static void op_get_proto_data(Program* program)
|
||||
{
|
||||
|
@ -318,6 +345,19 @@ static void op_set_proto_data(Program* program)
|
|||
*reinterpret_cast<int*>(reinterpret_cast<unsigned char*>(proto) + offset) = value;
|
||||
}
|
||||
|
||||
// set_self
|
||||
static void op_set_self(Program* program)
|
||||
{
|
||||
Object* obj = static_cast<Object*>(programStackPopPointer(program));
|
||||
|
||||
int sid = scriptGetSid(program);
|
||||
|
||||
Script* scr;
|
||||
if (scriptGetScript(sid, &scr) == 0) {
|
||||
scr->overriddenSelf = obj;
|
||||
}
|
||||
}
|
||||
|
||||
// list_begin
|
||||
static void opListBegin(Program* program)
|
||||
{
|
||||
|
@ -541,6 +581,22 @@ static void op_get_attack_type(Program* program)
|
|||
}
|
||||
}
|
||||
|
||||
// force_encounter_with_flags
|
||||
static void op_force_encounter_with_flags(Program* program)
|
||||
{
|
||||
unsigned int flags = programStackPopInteger(program);
|
||||
int map = programStackPopInteger(program);
|
||||
wmForceEncounter(map, flags);
|
||||
}
|
||||
|
||||
// list_as_array
|
||||
static void op_list_as_array(Program* program)
|
||||
{
|
||||
int type = programStackPopInteger(program);
|
||||
int arrayId = ListAsArray(type);
|
||||
programStackPushInteger(program, arrayId);
|
||||
}
|
||||
|
||||
// atoi
|
||||
static void opParseInt(Program* program)
|
||||
{
|
||||
|
@ -620,6 +676,64 @@ static void opGetStringLength(Program* program)
|
|||
programStackPushInteger(program, static_cast<int>(strlen(string)));
|
||||
}
|
||||
|
||||
// metarule2_explosions
|
||||
static void op_explosions_metarule(Program* program)
|
||||
{
|
||||
int param2 = programStackPopInteger(program);
|
||||
int param1 = programStackPopInteger(program);
|
||||
int metarule = programStackPopInteger(program);
|
||||
|
||||
switch (metarule) {
|
||||
case EXPL_FORCE_EXPLOSION_PATTERN:
|
||||
if (param1 != 0) {
|
||||
explosionSetPattern(2, 4);
|
||||
} else {
|
||||
explosionSetPattern(0, 6);
|
||||
}
|
||||
programStackPushInteger(program, 0);
|
||||
break;
|
||||
case EXPL_FORCE_EXPLOSION_ART:
|
||||
explosionSetFrm(param1);
|
||||
programStackPushInteger(program, 0);
|
||||
break;
|
||||
case EXPL_FORCE_EXPLOSION_RADIUS:
|
||||
explosionSetRadius(param1);
|
||||
programStackPushInteger(program, 0);
|
||||
break;
|
||||
case EXPL_FORCE_EXPLOSION_DMGTYPE:
|
||||
explosionSetDamageType(param1);
|
||||
programStackPushInteger(program, 0);
|
||||
break;
|
||||
case EXPL_STATIC_EXPLOSION_RADIUS:
|
||||
weaponSetGrenadeExplosionRadius(param1);
|
||||
weaponSetRocketExplosionRadius(param2);
|
||||
programStackPushInteger(program, 0);
|
||||
break;
|
||||
case EXPL_GET_EXPLOSION_DAMAGE:
|
||||
if (1) {
|
||||
int minDamage;
|
||||
int maxDamage;
|
||||
explosiveGetDamage(param1, &minDamage, &maxDamage);
|
||||
|
||||
ArrayId arrayId = CreateTempArray(2, 0);
|
||||
SetArray(arrayId, ProgramValue { 0 }, ProgramValue { minDamage }, false, program);
|
||||
SetArray(arrayId, ProgramValue { 1 }, ProgramValue { maxDamage }, false, program);
|
||||
|
||||
programStackPushInteger(program, arrayId);
|
||||
}
|
||||
break;
|
||||
case EXPL_SET_DYNAMITE_EXPLOSION_DAMAGE:
|
||||
explosiveSetDamage(PROTO_ID_DYNAMITE_I, param1, param2);
|
||||
break;
|
||||
case EXPL_SET_PLASTIC_EXPLOSION_DAMAGE:
|
||||
explosiveSetDamage(PROTO_ID_PLASTIC_EXPLOSIVES_I, param1, param2);
|
||||
break;
|
||||
case EXPL_SET_EXPLOSION_MAX_TARGET:
|
||||
explosionSetMaxTargets(param1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// pow (^)
|
||||
static void op_power(Program* program)
|
||||
{
|
||||
|
@ -859,6 +973,48 @@ static void opArtExists(Program* program)
|
|||
programStackPushInteger(program, artExists(fid));
|
||||
}
|
||||
|
||||
// sfall_func0
|
||||
static void op_sfall_func0(Program* program)
|
||||
{
|
||||
sfall_metarule(program, 0);
|
||||
}
|
||||
|
||||
// sfall_func1
|
||||
static void op_sfall_func1(Program* program)
|
||||
{
|
||||
sfall_metarule(program, 1);
|
||||
}
|
||||
|
||||
// sfall_func2
|
||||
static void op_sfall_func2(Program* program)
|
||||
{
|
||||
sfall_metarule(program, 2);
|
||||
}
|
||||
|
||||
// sfall_func3
|
||||
static void op_sfall_func3(Program* program)
|
||||
{
|
||||
sfall_metarule(program, 3);
|
||||
}
|
||||
|
||||
// sfall_func4
|
||||
static void op_sfall_func4(Program* program)
|
||||
{
|
||||
sfall_metarule(program, 4);
|
||||
}
|
||||
|
||||
// sfall_func5
|
||||
static void op_sfall_func5(Program* program)
|
||||
{
|
||||
sfall_metarule(program, 5);
|
||||
}
|
||||
|
||||
// sfall_func6
|
||||
static void op_sfall_func6(Program* program)
|
||||
{
|
||||
sfall_metarule(program, 6);
|
||||
}
|
||||
|
||||
// div (/)
|
||||
static void op_div(Program* program)
|
||||
{
|
||||
|
@ -894,6 +1050,7 @@ void sfallOpcodesInit()
|
|||
interpreterRegisterOpcode(0x816A, op_set_global_script_repeat);
|
||||
interpreterRegisterOpcode(0x816C, op_key_pressed);
|
||||
interpreterRegisterOpcode(0x8170, op_in_world_map);
|
||||
interpreterRegisterOpcode(0x8171, op_force_encounter);
|
||||
interpreterRegisterOpcode(0x8172, op_set_world_map_pos);
|
||||
interpreterRegisterOpcode(0x8193, opGetCurrentHand);
|
||||
interpreterRegisterOpcode(0x819B, op_set_global_script_type);
|
||||
|
@ -908,8 +1065,10 @@ void sfallOpcodesInit()
|
|||
interpreterRegisterOpcode(0x81EB, op_get_ini_string);
|
||||
interpreterRegisterOpcode(0x81EC, op_sqrt);
|
||||
interpreterRegisterOpcode(0x81ED, op_abs);
|
||||
interpreterRegisterOpcode(0x81F5, op_get_script);
|
||||
interpreterRegisterOpcode(0x8204, op_get_proto_data);
|
||||
interpreterRegisterOpcode(0x8205, op_set_proto_data);
|
||||
interpreterRegisterOpcode(0x8206, op_set_self);
|
||||
interpreterRegisterOpcode(0x820D, opListBegin);
|
||||
interpreterRegisterOpcode(0x820E, opListNext);
|
||||
interpreterRegisterOpcode(0x820F, opListEnd);
|
||||
|
@ -927,6 +1086,7 @@ void sfallOpcodesInit()
|
|||
interpreterRegisterOpcode(0x8221, opGetScreenHeight);
|
||||
interpreterRegisterOpcode(0x8224, op_create_message_window);
|
||||
interpreterRegisterOpcode(0x8228, op_get_attack_type);
|
||||
interpreterRegisterOpcode(0x8229, op_force_encounter_with_flags);
|
||||
interpreterRegisterOpcode(0x822D, opCreateArray);
|
||||
interpreterRegisterOpcode(0x822E, opSetArray);
|
||||
interpreterRegisterOpcode(0x822F, opGetArray);
|
||||
|
@ -936,6 +1096,7 @@ void sfallOpcodesInit()
|
|||
interpreterRegisterOpcode(0x8233, opTempArray);
|
||||
interpreterRegisterOpcode(0x8234, opFixArray);
|
||||
interpreterRegisterOpcode(0x8235, opStringSplit);
|
||||
interpreterRegisterOpcode(0x8236, op_list_as_array);
|
||||
interpreterRegisterOpcode(0x8237, opParseInt);
|
||||
interpreterRegisterOpcode(0x8238, op_atof);
|
||||
interpreterRegisterOpcode(0x8239, opScanArray);
|
||||
|
@ -945,6 +1106,7 @@ void sfallOpcodesInit()
|
|||
interpreterRegisterOpcode(0x8253, opTypeOf);
|
||||
interpreterRegisterOpcode(0x8256, opGetArrayKey);
|
||||
interpreterRegisterOpcode(0x8257, opStackArray);
|
||||
interpreterRegisterOpcode(0x8261, op_explosions_metarule);
|
||||
interpreterRegisterOpcode(0x8263, op_power);
|
||||
interpreterRegisterOpcode(0x8267, opRound);
|
||||
interpreterRegisterOpcode(0x826B, opGetMessage);
|
||||
|
@ -952,6 +1114,13 @@ void sfallOpcodesInit()
|
|||
interpreterRegisterOpcode(0x826F, op_obj_blocking_at);
|
||||
interpreterRegisterOpcode(0x8271, opPartyMemberList);
|
||||
interpreterRegisterOpcode(0x8274, opArtExists);
|
||||
interpreterRegisterOpcode(0x8276, op_sfall_func0);
|
||||
interpreterRegisterOpcode(0x8277, op_sfall_func1);
|
||||
interpreterRegisterOpcode(0x8278, op_sfall_func2);
|
||||
interpreterRegisterOpcode(0x8279, op_sfall_func3);
|
||||
interpreterRegisterOpcode(0x827A, op_sfall_func4);
|
||||
interpreterRegisterOpcode(0x827B, op_sfall_func5);
|
||||
interpreterRegisterOpcode(0x827C, op_sfall_func6);
|
||||
interpreterRegisterOpcode(0x827F, op_div);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "delay.h"
|
||||
#include "input.h"
|
||||
#include "kb.h"
|
||||
#include "memory.h"
|
||||
|
@ -228,8 +229,7 @@ int vcrUpdate()
|
|||
* (vcrEntry->time - stru_6AD940.time)
|
||||
/ (vcrEntry->counter - stru_6AD940.counter);
|
||||
|
||||
while (getTicksSince(_vcr_start_time) < delay) {
|
||||
}
|
||||
delay_ms(delay - (getTicks() - _vcr_start_time));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "version.h"
|
||||
#include "sfall_config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
@ -7,7 +8,14 @@ namespace fallout {
|
|||
// 0x4B4580
|
||||
void versionGetVersion(char* dest, size_t size)
|
||||
{
|
||||
snprintf(dest, size, "FALLOUT II %d.%02d", VERSION_MAJOR, VERSION_MINOR);
|
||||
// SFALL: custom version string.
|
||||
char* versionString = nullptr;
|
||||
if (configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_VERSION_STRING, &versionString)) {
|
||||
if (*versionString == '\0') {
|
||||
versionString = nullptr;
|
||||
}
|
||||
}
|
||||
snprintf(dest, size, (versionString != nullptr ? versionString : "FALLOUT II %d.%02d"), VERSION_MAJOR, VERSION_MINOR);
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
|
|
@ -70,6 +70,8 @@ typedef struct ManagedWindow {
|
|||
|
||||
typedef int (*INITVIDEOFN)();
|
||||
|
||||
static void redrawButton(ManagedButton* managedButton);
|
||||
|
||||
// 0x51DCAC
|
||||
static int _holdTime = 250;
|
||||
|
||||
|
@ -663,6 +665,38 @@ void _setButtonGFX(int width, int height, unsigned char* normal, unsigned char*
|
|||
}
|
||||
}
|
||||
|
||||
// 0x4B75F4
|
||||
static void redrawButton(ManagedButton* managedButton)
|
||||
{
|
||||
_win_register_button_image(managedButton->btn, managedButton->normal, managedButton->pressed, managedButton->hover, false);
|
||||
}
|
||||
|
||||
// 0x4B7610
|
||||
bool _windowHide()
|
||||
{
|
||||
ManagedWindow* managedWindow = &(gManagedWindows[gCurrentManagedWindowIndex]);
|
||||
if (managedWindow->window == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
windowHide(managedWindow->window);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x4B7648
|
||||
bool _windowShow()
|
||||
{
|
||||
ManagedWindow* managedWindow = &(gManagedWindows[gCurrentManagedWindowIndex]);
|
||||
if (managedWindow->window == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
windowShow(managedWindow->window);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 0x4B7734
|
||||
int _windowWidth()
|
||||
{
|
||||
|
@ -1714,7 +1748,8 @@ bool _windowAddButtonGfx(const char* buttonName, char* pressedFileName, char* no
|
|||
buttonSetMask(managedButton->btn, managedButton->normal);
|
||||
}
|
||||
|
||||
_win_register_button_image(managedButton->btn, managedButton->normal, managedButton->pressed, managedButton->hover, 0);
|
||||
// NOTE: Uninline.
|
||||
redrawButton(managedButton);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1952,7 +1987,8 @@ bool _windowAddButtonTextWithOffsets(const char* buttonName, const char* text, i
|
|||
buttonSetMask(managedButton->btn, managedButton->normal);
|
||||
}
|
||||
|
||||
_win_register_button_image(managedButton->btn, managedButton->normal, managedButton->pressed, managedButton->hover, 0);
|
||||
// NOTE: Uninline.
|
||||
redrawButton(managedButton);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -2646,4 +2682,19 @@ void _fillBuf3x3(unsigned char* src, int srcWidth, int srcHeight, unsigned char*
|
|||
destWidth);
|
||||
}
|
||||
|
||||
bool _windowShowNamed(const char* windowName)
|
||||
{
|
||||
for (int index = 0; index < MANAGED_WINDOW_COUNT; index++) {
|
||||
ManagedWindow* managedWindow = &(gManagedWindows[index]);
|
||||
if (managedWindow->window != -1) {
|
||||
if (compat_stricmp(managedWindow->name, windowName) == 0) {
|
||||
windowShow(managedWindow->window);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
|
|
@ -63,6 +63,8 @@ void _doRightButtonPress(int btn, int keyCode);
|
|||
void sub_4B704C(int btn, int mouseEvent);
|
||||
void _doRightButtonRelease(int btn, int keyCode);
|
||||
void _setButtonGFX(int width, int height, unsigned char* normal, unsigned char* pressed, unsigned char* a5);
|
||||
bool _windowHide();
|
||||
bool _windowShow();
|
||||
int _windowWidth();
|
||||
int _windowHeight();
|
||||
bool _windowDraw();
|
||||
|
@ -127,6 +129,8 @@ void _drawScaledBuf(unsigned char* dest, int destWidth, int destHeight, unsigned
|
|||
void _alphaBltBuf(unsigned char* src, int srcWidth, int srcHeight, int srcPitch, unsigned char* alphaWindowBuffer, unsigned char* alphaBuffer, unsigned char* dest, int destPitch);
|
||||
void _fillBuf3x3(unsigned char* src, int srcWidth, int srcHeight, unsigned char* dest, int destWidth, int destHeight);
|
||||
|
||||
bool _windowShowNamed(const char* name);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
#endif /* WINDOW_H */
|
||||
|
|
|
@ -817,6 +817,8 @@ static double gGameTimeIncRemainder = 0.0;
|
|||
static FrmImage _backgroundFrmImage;
|
||||
static FrmImage _townFrmImage;
|
||||
static bool wmFaded = false;
|
||||
static int wmForceEncounterMapId = -1;
|
||||
static unsigned int wmForceEncounterFlags = 0;
|
||||
|
||||
static inline bool cityIsValid(int city)
|
||||
{
|
||||
|
@ -929,6 +931,9 @@ static int wmGenDataInit()
|
|||
wmGenData.tabsScrollingDelta = 0;
|
||||
wmGenData.viewportMaxX = 0;
|
||||
|
||||
wmForceEncounterMapId = -1;
|
||||
wmForceEncounterFlags = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -979,6 +984,9 @@ static int wmGenDataReset()
|
|||
|
||||
wmMarkSubTileRadiusVisited(wmGenData.worldPosX, wmGenData.worldPosY);
|
||||
|
||||
wmForceEncounterMapId = -1;
|
||||
wmForceEncounterFlags = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -3347,6 +3355,33 @@ static int wmRndEncounterOccurred()
|
|||
}
|
||||
}
|
||||
|
||||
// SFALL: Handle forced encounter.
|
||||
// CE: In Sfall a check for forced encounter is inserted instead of check
|
||||
// for Horrigan encounter (above). This implemenation gives Horrigan
|
||||
// encounter a priority.
|
||||
if (wmForceEncounterMapId != -1) {
|
||||
if ((wmForceEncounterFlags & ENCOUNTER_FLAG_NO_CAR) != 0) {
|
||||
if (wmGenData.isInCar) {
|
||||
wmMatchAreaContainingMapIdx(wmForceEncounterMapId, &(wmGenData.currentCarAreaId));
|
||||
}
|
||||
}
|
||||
|
||||
// For unknown reason fadeout and blinking icon are mutually exclusive.
|
||||
if ((wmForceEncounterFlags & ENCOUNTER_FLAG_FADEOUT) != 0) {
|
||||
wmFadeOut();
|
||||
} else if ((wmForceEncounterFlags & ENCOUNTER_FLAG_NO_ICON) == 0) {
|
||||
bool special = (wmForceEncounterFlags & ENCOUNTER_FLAG_ICON_SP) != 0;
|
||||
wmBlinkRndEncounterIcon(special);
|
||||
}
|
||||
|
||||
mapLoadById(wmForceEncounterMapId);
|
||||
|
||||
wmForceEncounterMapId = -1;
|
||||
wmForceEncounterFlags = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// NOTE: Uninline.
|
||||
wmPartyFindCurSubTile();
|
||||
|
||||
|
@ -6608,4 +6643,21 @@ void wmCarSetCurrentArea(int area)
|
|||
wmGenData.currentCarAreaId = area;
|
||||
}
|
||||
|
||||
void wmForceEncounter(int map, unsigned int flags)
|
||||
{
|
||||
if ((wmForceEncounterFlags & (1 << 31)) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
wmForceEncounterMapId = map;
|
||||
wmForceEncounterFlags = flags;
|
||||
|
||||
// I don't quite understand the reason why locking needs one more flag.
|
||||
if ((wmForceEncounterFlags & ENCOUNTER_FLAG_LOCK) != 0) {
|
||||
wmForceEncounterFlags |= (1 << 31);
|
||||
} else {
|
||||
wmForceEncounterFlags &= ~(1 << 31);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
|
|
@ -229,6 +229,12 @@ typedef enum Map {
|
|||
MAP_IN_GAME_MOVIE1 = 149,
|
||||
} Map;
|
||||
|
||||
#define ENCOUNTER_FLAG_NO_CAR 0x1
|
||||
#define ENCOUNTER_FLAG_LOCK 0x2
|
||||
#define ENCOUNTER_FLAG_NO_ICON 0x4
|
||||
#define ENCOUNTER_FLAG_ICON_SP 0x8
|
||||
#define ENCOUNTER_FLAG_FADEOUT 0x10
|
||||
|
||||
extern unsigned char* circleBlendTable;
|
||||
|
||||
int wmWorldMap_init();
|
||||
|
@ -279,6 +285,7 @@ int wmTeleportToArea(int areaIdx);
|
|||
|
||||
void wmSetPartyWorldPos(int x, int y);
|
||||
void wmCarSetCurrentArea(int area);
|
||||
void wmForceEncounter(int map, unsigned int flags);
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ include(FetchContent)
|
|||
|
||||
FetchContent_Declare(zlib
|
||||
GIT_REPOSITORY "https://github.com/madler/zlib"
|
||||
GIT_TAG "v1.2.11"
|
||||
GIT_TAG "v1.3"
|
||||
)
|
||||
|
||||
FetchContent_GetProperties(zlib)
|
||||
|
|
Loading…
Reference in New Issue