Merge branch 'main' into convert-file-case
This commit is contained in:
commit
041e999e7c
|
@ -31,6 +31,18 @@ jobs:
|
||||||
- name: cppcheck
|
- name: cppcheck
|
||||||
run: cppcheck --std=c++17 src/
|
run: cppcheck --std=c++17 src/
|
||||||
|
|
||||||
|
code-format:
|
||||||
|
name: Code format check
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: clang-format
|
||||||
|
run: find src -type f -exec clang-format --dry-run --Werror {} \;
|
||||||
|
|
||||||
android:
|
android:
|
||||||
name: Android
|
name: Android
|
||||||
|
|
||||||
|
@ -78,7 +90,7 @@ jobs:
|
||||||
ios:
|
ios:
|
||||||
name: iOS
|
name: iOS
|
||||||
|
|
||||||
runs-on: macos-11
|
runs-on: macos-12
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Clone
|
- name: Clone
|
||||||
|
@ -88,30 +100,31 @@ jobs:
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: build
|
path: build
|
||||||
key: ios-cmake-v1
|
key: ios-cmake-v2
|
||||||
|
|
||||||
- name: Configure
|
- name: Configure
|
||||||
run: |
|
run: |
|
||||||
cmake \
|
cmake \
|
||||||
-B build \
|
-B build \
|
||||||
-D CMAKE_BUILD_TYPE=RelWithDebInfo \
|
|
||||||
-D CMAKE_TOOLCHAIN_FILE=cmake/toolchain/ios.toolchain.cmake \
|
-D CMAKE_TOOLCHAIN_FILE=cmake/toolchain/ios.toolchain.cmake \
|
||||||
-D ENABLE_BITCODE=0 \
|
-D ENABLE_BITCODE=0 \
|
||||||
-D PLATFORM=OS64 \
|
-D PLATFORM=OS64 \
|
||||||
|
-G Xcode \
|
||||||
|
-D CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY='' \
|
||||||
# EOL
|
# EOL
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
cmake \
|
cmake \
|
||||||
--build build \
|
--build build \
|
||||||
|
--config RelWithDebInfo \
|
||||||
-j $(sysctl -n hw.physicalcpu) \
|
-j $(sysctl -n hw.physicalcpu) \
|
||||||
--target package \
|
|
||||||
# EOL
|
# EOL
|
||||||
|
|
||||||
# TODO: Should be a part of packaging.
|
- name: Pack
|
||||||
- name: Prepare for uploading
|
|
||||||
run: |
|
run: |
|
||||||
cp build/fallout2-ce.zip build/fallout2-ce.ipa
|
cd build
|
||||||
|
cpack -C RelWithDebInfo
|
||||||
|
|
||||||
- name: Upload
|
- name: Upload
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
|
|
|
@ -303,21 +303,30 @@ if (WIN32)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
target_sources(${EXECUTABLE_NAME} PUBLIC "os/macos/fallout2-ce.icns")
|
|
||||||
set_source_files_properties("os/macos/fallout2-ce.icns" PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
|
|
||||||
|
|
||||||
if(IOS)
|
if(IOS)
|
||||||
target_sources(${EXECUTABLE_NAME} PUBLIC "os/ios/LaunchScreen.storyboard")
|
set(RESOURCES
|
||||||
set_source_files_properties("os/ios/LaunchScreen.storyboard" PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
|
"os/ios/AppIcon.xcassets"
|
||||||
set_target_properties(${EXECUTABLE_NAME} PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_SOURCE_DIR}/os/ios/Info.plist")
|
"os/ios/LaunchScreen.storyboard"
|
||||||
set_target_properties(${EXECUTABLE_NAME} PROPERTIES XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "1,2")
|
)
|
||||||
|
|
||||||
|
target_sources(${EXECUTABLE_NAME} PUBLIC ${RESOURCES})
|
||||||
|
set_source_files_properties(${RESOURCES} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
|
||||||
|
|
||||||
|
set_target_properties(${EXECUTABLE_NAME} PROPERTIES
|
||||||
|
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_SOURCE_DIR}/os/ios/Info.plist"
|
||||||
|
XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME "AppIcon"
|
||||||
|
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "com.alexbatalov.fallout2-ce"
|
||||||
|
XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "1,2"
|
||||||
|
)
|
||||||
else()
|
else()
|
||||||
set_target_properties(${EXECUTABLE_NAME} PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_SOURCE_DIR}/os/macos/Info.plist")
|
set_target_properties(${EXECUTABLE_NAME} PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_SOURCE_DIR}/os/macos/Info.plist")
|
||||||
|
target_sources(${EXECUTABLE_NAME} PUBLIC "os/macos/fallout2-ce.icns")
|
||||||
|
set_source_files_properties("os/macos/fallout2-ce.icns" PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
|
||||||
|
set(MACOSX_BUNDLE_ICON_FILE "fallout2-ce.icns")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(MACOSX_BUNDLE_GUI_IDENTIFIER "com.alexbatalov.fallout2-ce")
|
set(MACOSX_BUNDLE_GUI_IDENTIFIER "com.alexbatalov.fallout2-ce")
|
||||||
set(MACOSX_BUNDLE_BUNDLE_NAME "${EXECUTABLE_NAME}")
|
set(MACOSX_BUNDLE_BUNDLE_NAME "${EXECUTABLE_NAME}")
|
||||||
set(MACOSX_BUNDLE_ICON_FILE "fallout2-ce.icns")
|
|
||||||
set(MACOSX_BUNDLE_DISPLAY_NAME "Fallout 2")
|
set(MACOSX_BUNDLE_DISPLAY_NAME "Fallout 2")
|
||||||
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "1.2.0")
|
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "1.2.0")
|
||||||
set(MACOSX_BUNDLE_BUNDLE_VERSION "1.2.0")
|
set(MACOSX_BUNDLE_BUNDLE_VERSION "1.2.0")
|
||||||
|
@ -348,6 +357,7 @@ if(APPLE)
|
||||||
set(CPACK_GENERATOR "ZIP")
|
set(CPACK_GENERATOR "ZIP")
|
||||||
set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY OFF)
|
set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY OFF)
|
||||||
set(CPACK_PACKAGE_FILE_NAME "fallout2-ce")
|
set(CPACK_PACKAGE_FILE_NAME "fallout2-ce")
|
||||||
|
set(CPACK_ARCHIVE_FILE_EXTENSION "ipa")
|
||||||
else()
|
else()
|
||||||
install(TARGETS ${EXECUTABLE_NAME} DESTINATION .)
|
install(TARGETS ${EXECUTABLE_NAME} DESTINATION .)
|
||||||
install(CODE "
|
install(CODE "
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 1009 KiB |
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "AppIcon.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,8 +8,6 @@
|
||||||
<string>${MACOSX_BUNDLE_DISPLAY_NAME}</string>
|
<string>${MACOSX_BUNDLE_DISPLAY_NAME}</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
|
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
|
||||||
<key>CFBundleIconFile</key>
|
|
||||||
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
|
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
|
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
@ -22,8 +20,6 @@
|
||||||
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
|
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
|
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
|
||||||
<key>LSApplicationCategoryType</key>
|
|
||||||
<string>public.app-category.role-playing-games</string>
|
|
||||||
<key>LSMinimumSystemVersion</key>
|
<key>LSMinimumSystemVersion</key>
|
||||||
<string>11.0</string>
|
<string>11.0</string>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
|
@ -32,11 +28,6 @@
|
||||||
<string>True</string>
|
<string>True</string>
|
||||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>UIDeviceFamily</key>
|
|
||||||
<array>
|
|
||||||
<integer>1</integer>
|
|
||||||
<integer>2</integer>
|
|
||||||
</array>
|
|
||||||
<key>UIFileSharingEnabled</key>
|
<key>UIFileSharingEnabled</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>UILaunchStoryboardName</key>
|
<key>UILaunchStoryboardName</key>
|
||||||
|
|
|
@ -92,7 +92,7 @@ typedef enum AnimationType {
|
||||||
LAST_SF_DEATH_ANIM = ANIM_FALL_FRONT_BLOOD_SF,
|
LAST_SF_DEATH_ANIM = ANIM_FALL_FRONT_BLOOD_SF,
|
||||||
} AnimationType;
|
} AnimationType;
|
||||||
|
|
||||||
#define FID_ANIM_TYPE(value) ((value) & 0xFF0000) >> 16
|
#define FID_ANIM_TYPE(value) ((value)&0xFF0000) >> 16
|
||||||
|
|
||||||
// Signature of animation callback accepting 2 parameters.
|
// Signature of animation callback accepting 2 parameters.
|
||||||
typedef int(AnimationCallback)(void* a1, void* a2);
|
typedef int(AnimationCallback)(void* a1, void* a2);
|
||||||
|
|
|
@ -168,7 +168,7 @@ static bool _combat_call_display = false;
|
||||||
// Accuracy modifiers for hit locations.
|
// Accuracy modifiers for hit locations.
|
||||||
//
|
//
|
||||||
// 0x510954
|
// 0x510954
|
||||||
static const int _hit_location_penalty[HIT_LOCATION_COUNT] = {
|
static int hit_location_penalty_default[HIT_LOCATION_COUNT] = {
|
||||||
-40,
|
-40,
|
||||||
-30,
|
-30,
|
||||||
-30,
|
-30,
|
||||||
|
@ -180,6 +180,8 @@ static const int _hit_location_penalty[HIT_LOCATION_COUNT] = {
|
||||||
0,
|
0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int hit_location_penalty[HIT_LOCATION_COUNT];
|
||||||
|
|
||||||
// Critical hit tables for every kill type.
|
// Critical hit tables for every kill type.
|
||||||
//
|
//
|
||||||
// 0x510978
|
// 0x510978
|
||||||
|
@ -2029,6 +2031,7 @@ int combatInit()
|
||||||
burstModInit();
|
burstModInit();
|
||||||
unarmedInit();
|
unarmedInit();
|
||||||
damageModInit();
|
damageModInit();
|
||||||
|
combat_reset_hit_location_penalty();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2058,6 +2061,7 @@ void combatReset()
|
||||||
|
|
||||||
// SFALL
|
// SFALL
|
||||||
criticalsReset();
|
criticalsReset();
|
||||||
|
combat_reset_hit_location_penalty();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0x420E14
|
// 0x420E14
|
||||||
|
@ -3831,7 +3835,7 @@ static int attackCompute(Attack* attack)
|
||||||
roll = _compute_spray(attack, accuracy, &ammoQuantity, &v26, anim);
|
roll = _compute_spray(attack, accuracy, &ammoQuantity, &v26, anim);
|
||||||
} else {
|
} else {
|
||||||
int chance = critterGetStat(attack->attacker, STAT_CRITICAL_CHANCE);
|
int chance = critterGetStat(attack->attacker, STAT_CRITICAL_CHANCE);
|
||||||
roll = randomRoll(accuracy, chance - _hit_location_penalty[attack->defenderHitLocation], NULL);
|
roll = randomRoll(accuracy, chance - hit_location_penalty[attack->defenderHitLocation], NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (roll == ROLL_FAILURE) {
|
if (roll == ROLL_FAILURE) {
|
||||||
|
@ -4417,9 +4421,9 @@ static int attackDetermineToHit(Object* attacker, int tile, Object* defender, in
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isRangedWeapon) {
|
if (isRangedWeapon) {
|
||||||
accuracy += _hit_location_penalty[hitLocation];
|
accuracy += hit_location_penalty[hitLocation];
|
||||||
} else {
|
} else {
|
||||||
accuracy += _hit_location_penalty[hitLocation] / 2;
|
accuracy += hit_location_penalty[hitLocation] / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defender != NULL && (defender->flags & OBJECT_MULTIHEX) != 0) {
|
if (defender != NULL && (defender->flags & OBJECT_MULTIHEX) != 0) {
|
||||||
|
@ -6798,4 +6802,27 @@ static void damageModCalculateYaam(DamageCalculationContext* context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int combat_get_hit_location_penalty(int hit_location)
|
||||||
|
{
|
||||||
|
if (hit_location >= 0 && hit_location < HIT_LOCATION_COUNT) {
|
||||||
|
return hit_location_penalty[hit_location];
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void combat_set_hit_location_penalty(int hit_location, int penalty)
|
||||||
|
{
|
||||||
|
if (hit_location >= 0 && hit_location < HIT_LOCATION_COUNT) {
|
||||||
|
hit_location_penalty[hit_location] = penalty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void combat_reset_hit_location_penalty()
|
||||||
|
{
|
||||||
|
for (int hit_location = 0; hit_location < HIT_LOCATION_COUNT; hit_location++) {
|
||||||
|
hit_location_penalty[hit_location] = hit_location_penalty_default[hit_location];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace fallout
|
} // namespace fallout
|
||||||
|
|
|
@ -71,6 +71,9 @@ int unarmedGetKickHitMode(bool isSecondary);
|
||||||
bool unarmedIsPenetrating(int hitMode);
|
bool unarmedIsPenetrating(int hitMode);
|
||||||
bool damageModGetBonusHthDamageFix();
|
bool damageModGetBonusHthDamageFix();
|
||||||
bool damageModGetDisplayBonusDamage();
|
bool damageModGetDisplayBonusDamage();
|
||||||
|
int combat_get_hit_location_penalty(int hit_location);
|
||||||
|
void combat_set_hit_location_penalty(int hit_location, int penalty);
|
||||||
|
void combat_reset_hit_location_penalty();
|
||||||
|
|
||||||
static inline bool isInCombat()
|
static inline bool isInCombat()
|
||||||
{
|
{
|
||||||
|
|
|
@ -996,8 +996,8 @@ bool _critter_is_prone(Object* critter)
|
||||||
int anim = FID_ANIM_TYPE(critter->fid);
|
int anim = FID_ANIM_TYPE(critter->fid);
|
||||||
|
|
||||||
return (critter->data.critter.combat.results & (DAM_KNOCKED_OUT | DAM_KNOCKED_DOWN)) != 0
|
return (critter->data.critter.combat.results & (DAM_KNOCKED_OUT | DAM_KNOCKED_DOWN)) != 0
|
||||||
|| (anim >= FIRST_KNOCKDOWN_AND_DEATH_ANIM && anim <= LAST_KNOCKDOWN_AND_DEATH_ANIM)
|
|| (anim >= FIRST_KNOCKDOWN_AND_DEATH_ANIM && anim <= LAST_KNOCKDOWN_AND_DEATH_ANIM)
|
||||||
|| (anim >= FIRST_SF_DEATH_ANIM && anim <= LAST_SF_DEATH_ANIM);
|
|| (anim >= FIRST_SF_DEATH_ANIM && anim <= LAST_SF_DEATH_ANIM);
|
||||||
}
|
}
|
||||||
|
|
||||||
// critter_body_type
|
// critter_body_type
|
||||||
|
|
24
src/input.cc
24
src/input.cc
|
@ -1026,24 +1026,24 @@ static void buildNormalizedQwertyKeys()
|
||||||
keys[SDL_SCANCODE_F13] = -1;
|
keys[SDL_SCANCODE_F13] = -1;
|
||||||
keys[SDL_SCANCODE_F14] = -1;
|
keys[SDL_SCANCODE_F14] = -1;
|
||||||
keys[SDL_SCANCODE_F15] = -1;
|
keys[SDL_SCANCODE_F15] = -1;
|
||||||
//keys[DIK_KANA] = -1;
|
// keys[DIK_KANA] = -1;
|
||||||
//keys[DIK_CONVERT] = -1;
|
// keys[DIK_CONVERT] = -1;
|
||||||
//keys[DIK_NOCONVERT] = -1;
|
// keys[DIK_NOCONVERT] = -1;
|
||||||
//keys[DIK_YEN] = -1;
|
// keys[DIK_YEN] = -1;
|
||||||
keys[SDL_SCANCODE_KP_EQUALS] = -1;
|
keys[SDL_SCANCODE_KP_EQUALS] = -1;
|
||||||
//keys[DIK_PREVTRACK] = -1;
|
// keys[DIK_PREVTRACK] = -1;
|
||||||
//keys[DIK_AT] = -1;
|
// keys[DIK_AT] = -1;
|
||||||
//keys[DIK_COLON] = -1;
|
// keys[DIK_COLON] = -1;
|
||||||
//keys[DIK_UNDERLINE] = -1;
|
// keys[DIK_UNDERLINE] = -1;
|
||||||
//keys[DIK_KANJI] = -1;
|
// keys[DIK_KANJI] = -1;
|
||||||
keys[SDL_SCANCODE_STOP] = -1;
|
keys[SDL_SCANCODE_STOP] = -1;
|
||||||
//keys[DIK_AX] = -1;
|
// keys[DIK_AX] = -1;
|
||||||
//keys[DIK_UNLABELED] = -1;
|
// keys[DIK_UNLABELED] = -1;
|
||||||
keys[SDL_SCANCODE_KP_ENTER] = SDL_SCANCODE_KP_ENTER;
|
keys[SDL_SCANCODE_KP_ENTER] = SDL_SCANCODE_KP_ENTER;
|
||||||
keys[SDL_SCANCODE_RCTRL] = SDL_SCANCODE_RCTRL;
|
keys[SDL_SCANCODE_RCTRL] = SDL_SCANCODE_RCTRL;
|
||||||
keys[SDL_SCANCODE_KP_COMMA] = -1;
|
keys[SDL_SCANCODE_KP_COMMA] = -1;
|
||||||
keys[SDL_SCANCODE_KP_DIVIDE] = SDL_SCANCODE_KP_DIVIDE;
|
keys[SDL_SCANCODE_KP_DIVIDE] = SDL_SCANCODE_KP_DIVIDE;
|
||||||
//keys[DIK_SYSRQ] = 84;
|
// keys[DIK_SYSRQ] = 84;
|
||||||
keys[SDL_SCANCODE_RALT] = SDL_SCANCODE_RALT;
|
keys[SDL_SCANCODE_RALT] = SDL_SCANCODE_RALT;
|
||||||
keys[SDL_SCANCODE_HOME] = SDL_SCANCODE_HOME;
|
keys[SDL_SCANCODE_HOME] = SDL_SCANCODE_HOME;
|
||||||
keys[SDL_SCANCODE_UP] = SDL_SCANCODE_UP;
|
keys[SDL_SCANCODE_UP] = SDL_SCANCODE_UP;
|
||||||
|
|
|
@ -2616,4 +2616,37 @@ static void sidePanelsDraw(const char* path, int win, bool isLeading)
|
||||||
internal_free(image);
|
internal_free(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: Follows Sfall implementation of `GetCurrentAttackMode`. It slightly
|
||||||
|
// differs from `interfaceGetCurrentHitMode` (can return one of `reload` hit
|
||||||
|
// modes, the default is `punch`).
|
||||||
|
//
|
||||||
|
// 0x45EF6C
|
||||||
|
bool interface_get_current_attack_mode(int* hit_mode)
|
||||||
|
{
|
||||||
|
if (gInterfaceBarWindow == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (gInterfaceItemStates[gInterfaceCurrentHand].action) {
|
||||||
|
case INTERFACE_ITEM_ACTION_PRIMARY_AIMING:
|
||||||
|
case INTERFACE_ITEM_ACTION_PRIMARY:
|
||||||
|
*hit_mode = gInterfaceItemStates[gInterfaceCurrentHand].primaryHitMode;
|
||||||
|
break;
|
||||||
|
case INTERFACE_ITEM_ACTION_SECONDARY_AIMING:
|
||||||
|
case INTERFACE_ITEM_ACTION_SECONDARY:
|
||||||
|
*hit_mode = gInterfaceItemStates[gInterfaceCurrentHand].secondaryHitMode;
|
||||||
|
break;
|
||||||
|
case INTERFACE_ITEM_ACTION_RELOAD:
|
||||||
|
*hit_mode = gInterfaceCurrentHand == HAND_LEFT
|
||||||
|
? HIT_MODE_LEFT_WEAPON_RELOAD
|
||||||
|
: HIT_MODE_RIGHT_WEAPON_RELOAD;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
*hit_mode = HIT_MODE_PUNCH;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace fallout
|
} // namespace fallout
|
||||||
|
|
|
@ -69,6 +69,7 @@ void interfaceBarEndButtonsRenderRedLights();
|
||||||
int indicatorBarRefresh();
|
int indicatorBarRefresh();
|
||||||
bool indicatorBarShow();
|
bool indicatorBarShow();
|
||||||
bool indicatorBarHide();
|
bool indicatorBarHide();
|
||||||
|
bool interface_get_current_attack_mode(int* hit_mode);
|
||||||
|
|
||||||
unsigned char* customInterfaceBarGetBackgroundImageData();
|
unsigned char* customInterfaceBarGetBackgroundImageData();
|
||||||
|
|
||||||
|
|
|
@ -3268,4 +3268,29 @@ bool ProgramValue::isEmpty()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Matches Sfall implementation.
|
||||||
|
bool ProgramValue::isInt()
|
||||||
|
{
|
||||||
|
return opcode == VALUE_TYPE_INT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Matches Sfall implementation.
|
||||||
|
bool ProgramValue::isFloat()
|
||||||
|
{
|
||||||
|
return opcode == VALUE_TYPE_FLOAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Matches Sfall implementation.
|
||||||
|
float ProgramValue::asFloat()
|
||||||
|
{
|
||||||
|
switch (opcode) {
|
||||||
|
case VALUE_TYPE_INT:
|
||||||
|
return static_cast<float>(integerValue);
|
||||||
|
case VALUE_TYPE_FLOAT:
|
||||||
|
return floatValue;
|
||||||
|
default:
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace fallout
|
} // namespace fallout
|
||||||
|
|
|
@ -149,6 +149,9 @@ typedef struct ProgramValue {
|
||||||
};
|
};
|
||||||
|
|
||||||
bool isEmpty();
|
bool isEmpty();
|
||||||
|
bool isInt();
|
||||||
|
bool isFloat();
|
||||||
|
float asFloat();
|
||||||
} ProgramValue;
|
} ProgramValue;
|
||||||
|
|
||||||
typedef std::vector<ProgramValue> ProgramStack;
|
typedef std::vector<ProgramValue> ProgramStack;
|
||||||
|
|
|
@ -2987,7 +2987,7 @@ static void opGetMessageString(Program* program)
|
||||||
int messageListIndex = programStackPopInteger(program);
|
int messageListIndex = programStackPopInteger(program);
|
||||||
|
|
||||||
char* string;
|
char* string;
|
||||||
if (messageIndex >= 1) {
|
if (messageIndex >= 0) {
|
||||||
string = _scr_get_msg_str_speech(messageListIndex, messageIndex, 1);
|
string = _scr_get_msg_str_speech(messageListIndex, messageIndex, 1);
|
||||||
if (string == NULL) {
|
if (string == NULL) {
|
||||||
debugPrint("\nError: No message file EXISTS!: index %d, line %d", messageListIndex, messageIndex);
|
debugPrint("\nError: No message file EXISTS!: index %d, line %d", messageListIndex, messageIndex);
|
||||||
|
|
40
src/kb.cc
40
src/kb.cc
|
@ -1400,11 +1400,11 @@ static void keyboardBuildFrenchConfiguration()
|
||||||
gLogicalKeyEntries[SDL_SCANCODE_BACKSLASH].rmenu = -1;
|
gLogicalKeyEntries[SDL_SCANCODE_BACKSLASH].rmenu = -1;
|
||||||
gLogicalKeyEntries[SDL_SCANCODE_BACKSLASH].ctrl = -1;
|
gLogicalKeyEntries[SDL_SCANCODE_BACKSLASH].ctrl = -1;
|
||||||
|
|
||||||
//gLogicalKeyEntries[DIK_OEM_102].unmodified = KEY_LESS;
|
// gLogicalKeyEntries[DIK_OEM_102].unmodified = KEY_LESS;
|
||||||
//gLogicalKeyEntries[DIK_OEM_102].shift = KEY_GREATER;
|
// gLogicalKeyEntries[DIK_OEM_102].shift = KEY_GREATER;
|
||||||
//gLogicalKeyEntries[DIK_OEM_102].lmenu = -1;
|
// gLogicalKeyEntries[DIK_OEM_102].lmenu = -1;
|
||||||
//gLogicalKeyEntries[DIK_OEM_102].rmenu = -1;
|
// gLogicalKeyEntries[DIK_OEM_102].rmenu = -1;
|
||||||
//gLogicalKeyEntries[DIK_OEM_102].ctrl = -1;
|
// gLogicalKeyEntries[DIK_OEM_102].ctrl = -1;
|
||||||
|
|
||||||
switch (gKeyboardLayout) {
|
switch (gKeyboardLayout) {
|
||||||
case KEYBOARD_LAYOUT_QWERTY:
|
case KEYBOARD_LAYOUT_QWERTY:
|
||||||
|
@ -1583,11 +1583,11 @@ static void keyboardBuildGermanConfiguration()
|
||||||
gLogicalKeyEntries[SDL_SCANCODE_BACKSLASH].rmenu = -1;
|
gLogicalKeyEntries[SDL_SCANCODE_BACKSLASH].rmenu = -1;
|
||||||
gLogicalKeyEntries[SDL_SCANCODE_BACKSLASH].ctrl = -1;
|
gLogicalKeyEntries[SDL_SCANCODE_BACKSLASH].ctrl = -1;
|
||||||
|
|
||||||
//gLogicalKeyEntries[DIK_OEM_102].unmodified = KEY_LESS;
|
// gLogicalKeyEntries[DIK_OEM_102].unmodified = KEY_LESS;
|
||||||
//gLogicalKeyEntries[DIK_OEM_102].shift = KEY_GREATER;
|
// gLogicalKeyEntries[DIK_OEM_102].shift = KEY_GREATER;
|
||||||
//gLogicalKeyEntries[DIK_OEM_102].lmenu = -1;
|
// gLogicalKeyEntries[DIK_OEM_102].lmenu = -1;
|
||||||
//gLogicalKeyEntries[DIK_OEM_102].rmenu = KEY_166;
|
// gLogicalKeyEntries[DIK_OEM_102].rmenu = KEY_166;
|
||||||
//gLogicalKeyEntries[DIK_OEM_102].ctrl = -1;
|
// gLogicalKeyEntries[DIK_OEM_102].ctrl = -1;
|
||||||
|
|
||||||
switch (gKeyboardLayout) {
|
switch (gKeyboardLayout) {
|
||||||
case KEYBOARD_LAYOUT_FRENCH:
|
case KEYBOARD_LAYOUT_FRENCH:
|
||||||
|
@ -1684,11 +1684,11 @@ static void keyboardBuildItalianConfiguration()
|
||||||
gLogicalKeyEntries[SDL_SCANCODE_GRAVE].rmenu = -1;
|
gLogicalKeyEntries[SDL_SCANCODE_GRAVE].rmenu = -1;
|
||||||
gLogicalKeyEntries[SDL_SCANCODE_GRAVE].ctrl = -1;
|
gLogicalKeyEntries[SDL_SCANCODE_GRAVE].ctrl = -1;
|
||||||
|
|
||||||
//gLogicalKeyEntries[DIK_OEM_102].unmodified = KEY_LESS;
|
// gLogicalKeyEntries[DIK_OEM_102].unmodified = KEY_LESS;
|
||||||
//gLogicalKeyEntries[DIK_OEM_102].shift = KEY_GREATER;
|
// gLogicalKeyEntries[DIK_OEM_102].shift = KEY_GREATER;
|
||||||
//gLogicalKeyEntries[DIK_OEM_102].lmenu = -1;
|
// gLogicalKeyEntries[DIK_OEM_102].lmenu = -1;
|
||||||
//gLogicalKeyEntries[DIK_OEM_102].rmenu = -1;
|
// gLogicalKeyEntries[DIK_OEM_102].rmenu = -1;
|
||||||
//gLogicalKeyEntries[DIK_OEM_102].ctrl = -1;
|
// gLogicalKeyEntries[DIK_OEM_102].ctrl = -1;
|
||||||
|
|
||||||
gLogicalKeyEntries[SDL_SCANCODE_1].unmodified = KEY_1;
|
gLogicalKeyEntries[SDL_SCANCODE_1].unmodified = KEY_1;
|
||||||
gLogicalKeyEntries[SDL_SCANCODE_1].shift = KEY_EXCLAMATION;
|
gLogicalKeyEntries[SDL_SCANCODE_1].shift = KEY_EXCLAMATION;
|
||||||
|
@ -1896,11 +1896,11 @@ static void keyboardBuildSpanishConfiguration()
|
||||||
gLogicalKeyEntries[SDL_SCANCODE_RIGHTBRACKET].rmenu = KEY_BRACKET_RIGHT;
|
gLogicalKeyEntries[SDL_SCANCODE_RIGHTBRACKET].rmenu = KEY_BRACKET_RIGHT;
|
||||||
gLogicalKeyEntries[SDL_SCANCODE_RIGHTBRACKET].ctrl = -1;
|
gLogicalKeyEntries[SDL_SCANCODE_RIGHTBRACKET].ctrl = -1;
|
||||||
|
|
||||||
//gLogicalKeyEntries[DIK_OEM_102].unmodified = KEY_LESS;
|
// gLogicalKeyEntries[DIK_OEM_102].unmodified = KEY_LESS;
|
||||||
//gLogicalKeyEntries[DIK_OEM_102].shift = KEY_GREATER;
|
// gLogicalKeyEntries[DIK_OEM_102].shift = KEY_GREATER;
|
||||||
//gLogicalKeyEntries[DIK_OEM_102].lmenu = -1;
|
// gLogicalKeyEntries[DIK_OEM_102].lmenu = -1;
|
||||||
//gLogicalKeyEntries[DIK_OEM_102].rmenu = -1;
|
// gLogicalKeyEntries[DIK_OEM_102].rmenu = -1;
|
||||||
//gLogicalKeyEntries[DIK_OEM_102].ctrl = -1;
|
// gLogicalKeyEntries[DIK_OEM_102].ctrl = -1;
|
||||||
|
|
||||||
gLogicalKeyEntries[SDL_SCANCODE_SEMICOLON].unmodified = KEY_241;
|
gLogicalKeyEntries[SDL_SCANCODE_SEMICOLON].unmodified = KEY_241;
|
||||||
gLogicalKeyEntries[SDL_SCANCODE_SEMICOLON].shift = KEY_209;
|
gLogicalKeyEntries[SDL_SCANCODE_SEMICOLON].shift = KEY_209;
|
||||||
|
|
17
src/mouse.cc
17
src/mouse.cc
|
@ -54,7 +54,7 @@ static unsigned char* _mouse_fptr = NULL;
|
||||||
static double gMouseSensitivity = 1.0;
|
static double gMouseSensitivity = 1.0;
|
||||||
|
|
||||||
// 0x51E2AC
|
// 0x51E2AC
|
||||||
static int gMouseButtonsState = 0;
|
static int last_buttons = 0;
|
||||||
|
|
||||||
// 0x6AC790
|
// 0x6AC790
|
||||||
static bool gCursorIsHidden;
|
static bool gCursorIsHidden;
|
||||||
|
@ -415,7 +415,7 @@ void _mouse_info()
|
||||||
}
|
}
|
||||||
x = 0;
|
x = 0;
|
||||||
y = 0;
|
y = 0;
|
||||||
buttons = gMouseButtonsState;
|
buttons = last_buttons;
|
||||||
}
|
}
|
||||||
|
|
||||||
_mouse_simulate_input(x, y, buttons);
|
_mouse_simulate_input(x, y, buttons);
|
||||||
|
@ -447,7 +447,7 @@ void _mouse_simulate_input(int delta_x, int delta_y, int buttons)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (delta_x || delta_y || buttons != gMouseButtonsState) {
|
if (delta_x || delta_y || buttons != last_buttons) {
|
||||||
if (gVcrState == 0) {
|
if (gVcrState == 0) {
|
||||||
if (_vcr_buffer_index == VCR_BUFFER_CAPACITY - 1) {
|
if (_vcr_buffer_index == VCR_BUFFER_CAPACITY - 1) {
|
||||||
vcrDump();
|
vcrDump();
|
||||||
|
@ -464,13 +464,13 @@ void _mouse_simulate_input(int delta_x, int delta_y, int buttons)
|
||||||
_vcr_buffer_index++;
|
_vcr_buffer_index++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (gMouseButtonsState == 0) {
|
if (last_buttons == 0) {
|
||||||
if (!_mouse_idling) {
|
if (!_mouse_idling) {
|
||||||
_mouse_idle_start_time = getTicks();
|
_mouse_idle_start_time = getTicks();
|
||||||
_mouse_idling = 1;
|
_mouse_idling = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
gMouseButtonsState = 0;
|
last_buttons = 0;
|
||||||
_raw_buttons = 0;
|
_raw_buttons = 0;
|
||||||
gMouseEvent = 0;
|
gMouseEvent = 0;
|
||||||
|
|
||||||
|
@ -479,7 +479,7 @@ void _mouse_simulate_input(int delta_x, int delta_y, int buttons)
|
||||||
}
|
}
|
||||||
|
|
||||||
_mouse_idling = 0;
|
_mouse_idling = 0;
|
||||||
gMouseButtonsState = buttons;
|
last_buttons = buttons;
|
||||||
previousEvent = gMouseEvent;
|
previousEvent = gMouseEvent;
|
||||||
gMouseEvent = 0;
|
gMouseEvent = 0;
|
||||||
|
|
||||||
|
@ -703,4 +703,9 @@ void convertMouseWheelToArrowKey(int* keyCodePtr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int mouse_get_last_buttons()
|
||||||
|
{
|
||||||
|
return last_buttons;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace fallout
|
} // namespace fallout
|
||||||
|
|
|
@ -52,6 +52,7 @@ void mouseGetPositionInWindow(int win, int* x, int* y);
|
||||||
bool mouseHitTestInWindow(int win, int left, int top, int right, int bottom);
|
bool mouseHitTestInWindow(int win, int left, int top, int right, int bottom);
|
||||||
void mouseGetWheel(int* x, int* y);
|
void mouseGetWheel(int* x, int* y);
|
||||||
void convertMouseWheelToArrowKey(int* keyCodePtr);
|
void convertMouseWheelToArrowKey(int* keyCodePtr);
|
||||||
|
int mouse_get_last_buttons();
|
||||||
|
|
||||||
} // namespace fallout
|
} // namespace fallout
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ enum {
|
||||||
OBJ_TYPE_COUNT,
|
OBJ_TYPE_COUNT,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define FID_TYPE(value) ((value) & 0xF000000) >> 24
|
#define FID_TYPE(value) ((value)&0xF000000) >> 24
|
||||||
#define PID_TYPE(value) (value) >> 24
|
#define PID_TYPE(value) (value) >> 24
|
||||||
#define SID_TYPE(value) (value) >> 24
|
#define SID_TYPE(value) (value) >> 24
|
||||||
|
|
||||||
|
|
12
src/proto.cc
12
src/proto.cc
|
@ -249,6 +249,12 @@ int _proto_list_str(int pid, char* proto_path)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 0x49E984
|
||||||
|
size_t proto_size(int type)
|
||||||
|
{
|
||||||
|
return type >= 0 && type < OBJ_TYPE_COUNT ? _proto_sizes[type] : 0;
|
||||||
|
}
|
||||||
|
|
||||||
// 0x49E99C
|
// 0x49E99C
|
||||||
bool _proto_action_can_use(int pid)
|
bool _proto_action_can_use(int pid)
|
||||||
{
|
{
|
||||||
|
@ -1704,12 +1710,10 @@ static int _proto_load_pid(int pid, Proto** protoPtr)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// allocate memory for proto of given type and adds it to proto cache
|
// 0x4A1D98
|
||||||
static int _proto_find_free_subnode(int type, Proto** protoPtr)
|
static int _proto_find_free_subnode(int type, Proto** protoPtr)
|
||||||
{
|
{
|
||||||
size_t size = (type >= 0 && type < 11) ? _proto_sizes[type] : 0;
|
Proto* proto = (Proto*)internal_malloc(proto_size(type));
|
||||||
|
|
||||||
Proto* proto = (Proto*)internal_malloc(size);
|
|
||||||
*protoPtr = proto;
|
*protoPtr = proto;
|
||||||
if (proto == NULL) {
|
if (proto == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -104,6 +104,7 @@ extern char* _proto_none_str;
|
||||||
|
|
||||||
void _proto_make_path(char* path, int pid);
|
void _proto_make_path(char* path, int pid);
|
||||||
int _proto_list_str(int pid, char* proto_path);
|
int _proto_list_str(int pid, char* proto_path);
|
||||||
|
size_t proto_size(int type);
|
||||||
bool _proto_action_can_use(int pid);
|
bool _proto_action_can_use(int pid);
|
||||||
bool _proto_action_can_use_on(int pid);
|
bool _proto_action_can_use_on(int pid);
|
||||||
bool _proto_action_can_talk_to(int pid);
|
bool _proto_action_can_talk_to(int pid);
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "proto.h"
|
#include "proto.h"
|
||||||
#include "proto_instance.h"
|
#include "proto_instance.h"
|
||||||
#include "queue.h"
|
#include "queue.h"
|
||||||
|
#include "sfall_config.h"
|
||||||
#include "stat.h"
|
#include "stat.h"
|
||||||
#include "svga.h"
|
#include "svga.h"
|
||||||
#include "tile.h"
|
#include "tile.h"
|
||||||
|
@ -265,6 +266,15 @@ static bool _set;
|
||||||
// 0x667750
|
// 0x667750
|
||||||
static char _tempStr1[20];
|
static char _tempStr1[20];
|
||||||
|
|
||||||
|
static int gStartYear;
|
||||||
|
static int gStartMonth;
|
||||||
|
static int gStartDay;
|
||||||
|
|
||||||
|
static int gMovieTimerArtimer1;
|
||||||
|
static int gMovieTimerArtimer2;
|
||||||
|
static int gMovieTimerArtimer3;
|
||||||
|
static int gMovieTimerArtimer4;
|
||||||
|
|
||||||
// TODO: Make unsigned.
|
// TODO: Make unsigned.
|
||||||
//
|
//
|
||||||
// Returns game time in ticks (1/10 second).
|
// Returns game time in ticks (1/10 second).
|
||||||
|
@ -278,9 +288,9 @@ int gameTimeGetTime()
|
||||||
// 0x4A3338
|
// 0x4A3338
|
||||||
void gameTimeGetDate(int* monthPtr, int* dayPtr, int* yearPtr)
|
void gameTimeGetDate(int* monthPtr, int* dayPtr, int* yearPtr)
|
||||||
{
|
{
|
||||||
int year = (gGameTime / GAME_TIME_TICKS_PER_DAY + 24) / 365 + 2241;
|
int year = (gGameTime / GAME_TIME_TICKS_PER_DAY + gStartDay) / 365 + gStartYear;
|
||||||
int month = 6;
|
int month = gStartMonth;
|
||||||
int day = (gGameTime / GAME_TIME_TICKS_PER_DAY + 24) % 365;
|
int day = (gGameTime / GAME_TIME_TICKS_PER_DAY + gStartDay) % 365;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
int daysInMonth = gGameTimeDaysPerMonth[month];
|
int daysInMonth = gGameTimeDaysPerMonth[month];
|
||||||
|
@ -439,7 +449,7 @@ int _scriptsCheckGameEvents(int* moviePtr, int window)
|
||||||
movieFlags = GAME_MOVIE_FADE_IN | GAME_MOVIE_STOP_MUSIC;
|
movieFlags = GAME_MOVIE_FADE_IN | GAME_MOVIE_STOP_MUSIC;
|
||||||
endgame = true;
|
endgame = true;
|
||||||
} else {
|
} else {
|
||||||
if (day >= 360 || gameGetGlobalVar(GVAR_FALLOUT_2) >= 3) {
|
if (day >= gMovieTimerArtimer4 || gameGetGlobalVar(GVAR_FALLOUT_2) >= 3) {
|
||||||
movie = MOVIE_ARTIMER4;
|
movie = MOVIE_ARTIMER4;
|
||||||
if (!gameMovieIsSeen(MOVIE_ARTIMER4)) {
|
if (!gameMovieIsSeen(MOVIE_ARTIMER4)) {
|
||||||
adjustRep = true;
|
adjustRep = true;
|
||||||
|
@ -447,13 +457,13 @@ int _scriptsCheckGameEvents(int* moviePtr, int window)
|
||||||
wmAreaSetVisibleState(CITY_DESTROYED_ARROYO, 1, 1);
|
wmAreaSetVisibleState(CITY_DESTROYED_ARROYO, 1, 1);
|
||||||
wmAreaMarkVisitedState(CITY_DESTROYED_ARROYO, 2);
|
wmAreaMarkVisitedState(CITY_DESTROYED_ARROYO, 2);
|
||||||
}
|
}
|
||||||
} else if (day >= 270 && gameGetGlobalVar(GVAR_FALLOUT_2) != 3) {
|
} else if (day >= gMovieTimerArtimer3 && gameGetGlobalVar(GVAR_FALLOUT_2) != 3) {
|
||||||
adjustRep = true;
|
adjustRep = true;
|
||||||
movie = MOVIE_ARTIMER3;
|
movie = MOVIE_ARTIMER3;
|
||||||
} else if (day >= 180 && gameGetGlobalVar(GVAR_FALLOUT_2) != 3) {
|
} else if (day >= gMovieTimerArtimer2 && gameGetGlobalVar(GVAR_FALLOUT_2) != 3) {
|
||||||
adjustRep = true;
|
adjustRep = true;
|
||||||
movie = MOVIE_ARTIMER2;
|
movie = MOVIE_ARTIMER2;
|
||||||
} else if (day >= 90 && gameGetGlobalVar(GVAR_FALLOUT_2) != 3) {
|
} else if (day >= gMovieTimerArtimer1 && gameGetGlobalVar(GVAR_FALLOUT_2) != 3) {
|
||||||
adjustRep = true;
|
adjustRep = true;
|
||||||
movie = MOVIE_ARTIMER1;
|
movie = MOVIE_ARTIMER1;
|
||||||
}
|
}
|
||||||
|
@ -1522,6 +1532,15 @@ int scriptsInit()
|
||||||
|
|
||||||
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_SCRIPT, &gScrMessageList);
|
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_SCRIPT, &gScrMessageList);
|
||||||
|
|
||||||
|
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_START_YEAR, &gStartYear);
|
||||||
|
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_START_MONTH, &gStartMonth);
|
||||||
|
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_START_DAY, &gStartDay);
|
||||||
|
|
||||||
|
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MOVIE_TIMER_ARTIMER1, &gMovieTimerArtimer1);
|
||||||
|
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MOVIE_TIMER_ARTIMER2, &gMovieTimerArtimer2);
|
||||||
|
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MOVIE_TIMER_ARTIMER3, &gMovieTimerArtimer3);
|
||||||
|
configGetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MOVIE_TIMER_ARTIMER4, &gMovieTimerArtimer4);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,9 @@ bool sfallConfigInit(int argc, char** argv)
|
||||||
configSetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_DUDE_NATIVE_LOOK_JUMPSUIT_FEMALE_KEY, "");
|
configSetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_DUDE_NATIVE_LOOK_JUMPSUIT_FEMALE_KEY, "");
|
||||||
configSetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_DUDE_NATIVE_LOOK_TRIBAL_MALE_KEY, "");
|
configSetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_DUDE_NATIVE_LOOK_TRIBAL_MALE_KEY, "");
|
||||||
configSetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_DUDE_NATIVE_LOOK_TRIBAL_FEMALE_KEY, "");
|
configSetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_DUDE_NATIVE_LOOK_TRIBAL_FEMALE_KEY, "");
|
||||||
|
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_START_YEAR, 2241);
|
||||||
|
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_START_MONTH, 6);
|
||||||
|
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_START_DAY, 24);
|
||||||
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MAIN_MENU_BIG_FONT_COLOR_KEY, 0);
|
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MAIN_MENU_BIG_FONT_COLOR_KEY, 0);
|
||||||
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MAIN_MENU_CREDITS_OFFSET_X_KEY, 0);
|
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MAIN_MENU_CREDITS_OFFSET_X_KEY, 0);
|
||||||
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MAIN_MENU_CREDITS_OFFSET_Y_KEY, 0);
|
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MAIN_MENU_CREDITS_OFFSET_Y_KEY, 0);
|
||||||
|
@ -50,6 +53,10 @@ bool sfallConfigInit(int argc, char** argv)
|
||||||
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_BURST_MOD_TARGET_MULTIPLIER_KEY, SFALL_CONFIG_BURST_MOD_DEFAULT_TARGET_MULTIPLIER);
|
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_BURST_MOD_TARGET_MULTIPLIER_KEY, SFALL_CONFIG_BURST_MOD_DEFAULT_TARGET_MULTIPLIER);
|
||||||
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_BURST_MOD_TARGET_DIVISOR_KEY, SFALL_CONFIG_BURST_MOD_DEFAULT_TARGET_DIVISOR);
|
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_BURST_MOD_TARGET_DIVISOR_KEY, SFALL_CONFIG_BURST_MOD_DEFAULT_TARGET_DIVISOR);
|
||||||
configSetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_EXTRA_MESSAGE_LISTS_KEY, "");
|
configSetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_EXTRA_MESSAGE_LISTS_KEY, "");
|
||||||
|
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MOVIE_TIMER_ARTIMER1, 90);
|
||||||
|
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MOVIE_TIMER_ARTIMER2, 180);
|
||||||
|
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MOVIE_TIMER_ARTIMER3, 270);
|
||||||
|
configSetInt(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_MOVIE_TIMER_ARTIMER4, 360);
|
||||||
|
|
||||||
char path[COMPAT_MAX_PATH];
|
char path[COMPAT_MAX_PATH];
|
||||||
char* executable = argv[0];
|
char* executable = argv[0];
|
||||||
|
|
|
@ -13,6 +13,9 @@ namespace fallout {
|
||||||
#define SFALL_CONFIG_DUDE_NATIVE_LOOK_JUMPSUIT_FEMALE_KEY "FemaleDefaultModel"
|
#define SFALL_CONFIG_DUDE_NATIVE_LOOK_JUMPSUIT_FEMALE_KEY "FemaleDefaultModel"
|
||||||
#define SFALL_CONFIG_DUDE_NATIVE_LOOK_TRIBAL_MALE_KEY "MaleStartModel"
|
#define SFALL_CONFIG_DUDE_NATIVE_LOOK_TRIBAL_MALE_KEY "MaleStartModel"
|
||||||
#define SFALL_CONFIG_DUDE_NATIVE_LOOK_TRIBAL_FEMALE_KEY "FemaleStartModel"
|
#define SFALL_CONFIG_DUDE_NATIVE_LOOK_TRIBAL_FEMALE_KEY "FemaleStartModel"
|
||||||
|
#define SFALL_CONFIG_START_YEAR "StartYear"
|
||||||
|
#define SFALL_CONFIG_START_MONTH "StartMonth"
|
||||||
|
#define SFALL_CONFIG_START_DAY "StartDay"
|
||||||
#define SFALL_CONFIG_MAIN_MENU_BIG_FONT_COLOR_KEY "MainMenuBigFontColour"
|
#define SFALL_CONFIG_MAIN_MENU_BIG_FONT_COLOR_KEY "MainMenuBigFontColour"
|
||||||
#define SFALL_CONFIG_MAIN_MENU_CREDITS_OFFSET_X_KEY "MainMenuCreditsOffsetX"
|
#define SFALL_CONFIG_MAIN_MENU_CREDITS_OFFSET_X_KEY "MainMenuCreditsOffsetX"
|
||||||
#define SFALL_CONFIG_MAIN_MENU_CREDITS_OFFSET_Y_KEY "MainMenuCreditsOffsetY"
|
#define SFALL_CONFIG_MAIN_MENU_CREDITS_OFFSET_Y_KEY "MainMenuCreditsOffsetY"
|
||||||
|
@ -42,6 +45,10 @@ namespace fallout {
|
||||||
#define SFALL_CONFIG_PLASTIC_EXPLOSIVE_MIN_DAMAGE_KEY "PlasticExplosive_DmgMin"
|
#define SFALL_CONFIG_PLASTIC_EXPLOSIVE_MIN_DAMAGE_KEY "PlasticExplosive_DmgMin"
|
||||||
#define SFALL_CONFIG_PLASTIC_EXPLOSIVE_MAX_DAMAGE_KEY "PlasticExplosive_DmgMax"
|
#define SFALL_CONFIG_PLASTIC_EXPLOSIVE_MAX_DAMAGE_KEY "PlasticExplosive_DmgMax"
|
||||||
#define SFALL_CONFIG_EXPLOSION_EMITS_LIGHT_KEY "ExplosionsEmitLight"
|
#define SFALL_CONFIG_EXPLOSION_EMITS_LIGHT_KEY "ExplosionsEmitLight"
|
||||||
|
#define SFALL_CONFIG_MOVIE_TIMER_ARTIMER1 "MovieTimer_artimer1"
|
||||||
|
#define SFALL_CONFIG_MOVIE_TIMER_ARTIMER2 "MovieTimer_artimer2"
|
||||||
|
#define SFALL_CONFIG_MOVIE_TIMER_ARTIMER3 "MovieTimer_artimer3"
|
||||||
|
#define SFALL_CONFIG_MOVIE_TIMER_ARTIMER4 "MovieTimer_artimer4"
|
||||||
#define SFALL_CONFIG_CITY_REPUTATION_LIST_KEY "CityRepsList"
|
#define SFALL_CONFIG_CITY_REPUTATION_LIST_KEY "CityRepsList"
|
||||||
#define SFALL_CONFIG_UNARMED_FILE_KEY "UnarmedFile"
|
#define SFALL_CONFIG_UNARMED_FILE_KEY "UnarmedFile"
|
||||||
#define SFALL_CONFIG_DAMAGE_MOD_FORMULA_KEY "DamageFormula"
|
#define SFALL_CONFIG_DAMAGE_MOD_FORMULA_KEY "DamageFormula"
|
||||||
|
|
|
@ -1,19 +1,25 @@
|
||||||
#include "sfall_opcodes.h"
|
#include "sfall_opcodes.h"
|
||||||
|
|
||||||
|
#include "animation.h"
|
||||||
#include "art.h"
|
#include "art.h"
|
||||||
#include "combat.h"
|
#include "combat.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "game.h"
|
#include "game.h"
|
||||||
|
#include "input.h"
|
||||||
#include "interface.h"
|
#include "interface.h"
|
||||||
#include "interpreter.h"
|
#include "interpreter.h"
|
||||||
#include "item.h"
|
#include "item.h"
|
||||||
#include "message.h"
|
#include "message.h"
|
||||||
#include "mouse.h"
|
#include "mouse.h"
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
|
#include "proto.h"
|
||||||
|
#include "scripts.h"
|
||||||
#include "sfall_global_vars.h"
|
#include "sfall_global_vars.h"
|
||||||
#include "sfall_lists.h"
|
#include "sfall_lists.h"
|
||||||
#include "stat.h"
|
#include "stat.h"
|
||||||
#include "svga.h"
|
#include "svga.h"
|
||||||
|
#include "tile.h"
|
||||||
|
#include "worldmap.h"
|
||||||
|
|
||||||
namespace fallout {
|
namespace fallout {
|
||||||
|
|
||||||
|
@ -39,6 +45,17 @@ static void opReadByte(Program* program)
|
||||||
programStackPushInteger(program, value);
|
programStackPushInteger(program, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set_pc_base_stat
|
||||||
|
static void op_set_pc_base_stat(Program* program)
|
||||||
|
{
|
||||||
|
// CE: Implementation is different. Sfall changes value directly on the
|
||||||
|
// dude's proto, without calling |critterSetBaseStat|. This function has
|
||||||
|
// important call to update derived stats, which is not present in Sfall.
|
||||||
|
int value = programStackPopInteger(program);
|
||||||
|
int stat = programStackPopInteger(program);
|
||||||
|
critterSetBaseStat(gDude, stat, value);
|
||||||
|
}
|
||||||
|
|
||||||
// set_pc_extra_stat
|
// set_pc_extra_stat
|
||||||
static void opSetPcBonusStat(Program* program)
|
static void opSetPcBonusStat(Program* program)
|
||||||
{
|
{
|
||||||
|
@ -50,6 +67,16 @@ static void opSetPcBonusStat(Program* program)
|
||||||
critterSetBonusStat(gDude, stat, value);
|
critterSetBonusStat(gDude, stat, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get_pc_base_stat
|
||||||
|
static void op_get_pc_base_stat(Program* program)
|
||||||
|
{
|
||||||
|
// CE: Implementation is different. Sfall obtains value directly from
|
||||||
|
// dude's proto. This can have unforeseen consequences when dealing with
|
||||||
|
// current stats.
|
||||||
|
int stat = programStackPopInteger(program);
|
||||||
|
programStackPushInteger(program, critterGetBaseStat(gDude, stat));
|
||||||
|
}
|
||||||
|
|
||||||
// get_pc_extra_stat
|
// get_pc_extra_stat
|
||||||
static void opGetPcBonusStat(Program* program)
|
static void opGetPcBonusStat(Program* program)
|
||||||
{
|
{
|
||||||
|
@ -58,6 +85,28 @@ static void opGetPcBonusStat(Program* program)
|
||||||
programStackPushInteger(program, value);
|
programStackPushInteger(program, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get_year
|
||||||
|
static void op_get_year(Program* program)
|
||||||
|
{
|
||||||
|
int year;
|
||||||
|
gameTimeGetDate(nullptr, nullptr, &year);
|
||||||
|
programStackPushInteger(program, year);
|
||||||
|
}
|
||||||
|
|
||||||
|
// in_world_map
|
||||||
|
static void op_in_world_map(Program* program)
|
||||||
|
{
|
||||||
|
programStackPushInteger(program, GameMode::isInGameMode(GameMode::kWorldmap) ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set_world_map_pos
|
||||||
|
static void op_set_world_map_pos(Program* program)
|
||||||
|
{
|
||||||
|
int y = programStackPopInteger(program);
|
||||||
|
int x = programStackPopInteger(program);
|
||||||
|
wmSetPartyWorldPos(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
// active_hand
|
// active_hand
|
||||||
static void opGetCurrentHand(Program* program)
|
static void opGetCurrentHand(Program* program)
|
||||||
{
|
{
|
||||||
|
@ -100,6 +149,103 @@ static void opGetGameMode(Program* program)
|
||||||
programStackPushInteger(program, GameMode::getCurrentGameMode());
|
programStackPushInteger(program, GameMode::getCurrentGameMode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get_uptime
|
||||||
|
static void op_get_uptime(Program* program)
|
||||||
|
{
|
||||||
|
programStackPushInteger(program, getTicks());
|
||||||
|
}
|
||||||
|
|
||||||
|
// set_car_current_town
|
||||||
|
static void op_set_car_current_town(Program* program)
|
||||||
|
{
|
||||||
|
int area = programStackPopInteger(program);
|
||||||
|
wmCarSetCurrentArea(area);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get_bodypart_hit_modifier
|
||||||
|
static void op_get_bodypart_hit_modifier(Program* program)
|
||||||
|
{
|
||||||
|
int hit_location = programStackPopInteger(program);
|
||||||
|
programStackPushInteger(program, combat_get_hit_location_penalty(hit_location));
|
||||||
|
}
|
||||||
|
|
||||||
|
// set_bodypart_hit_modifier
|
||||||
|
static void op_set_bodypart_hit_modifier(Program* program)
|
||||||
|
{
|
||||||
|
int penalty = programStackPopInteger(program);
|
||||||
|
int hit_location = programStackPopInteger(program);
|
||||||
|
combat_set_hit_location_penalty(hit_location, penalty);
|
||||||
|
}
|
||||||
|
|
||||||
|
// sqrt
|
||||||
|
static void op_sqrt(Program* program)
|
||||||
|
{
|
||||||
|
ProgramValue programValue = programStackPopValue(program);
|
||||||
|
programStackPushFloat(program, sqrtf(programValue.asFloat()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// abs
|
||||||
|
static void op_abs(Program* program)
|
||||||
|
{
|
||||||
|
ProgramValue programValue = programStackPopValue(program);
|
||||||
|
|
||||||
|
if (programValue.isInt()) {
|
||||||
|
programStackPushInteger(program, abs(programValue.integerValue));
|
||||||
|
} else {
|
||||||
|
programStackPushFloat(program, abs(programValue.asFloat()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get_proto_data
|
||||||
|
static void op_get_proto_data(Program* program)
|
||||||
|
{
|
||||||
|
size_t offset = static_cast<size_t>(programStackPopInteger(program));
|
||||||
|
int pid = programStackPopInteger(program);
|
||||||
|
|
||||||
|
Proto* proto;
|
||||||
|
if (protoGetProto(pid, &proto) != 0) {
|
||||||
|
debugPrint("op_get_proto_data: bad proto %d", pid);
|
||||||
|
programStackPushInteger(program, -1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CE: Make sure the requested offset is within memory bounds and is
|
||||||
|
// properly aligned.
|
||||||
|
if (offset + sizeof(int) > proto_size(PID_TYPE(pid)) || offset % sizeof(int) != 0) {
|
||||||
|
debugPrint("op_get_proto_data: bad offset %d", offset);
|
||||||
|
programStackPushInteger(program, -1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int value = *reinterpret_cast<int*>(reinterpret_cast<unsigned char*>(proto) + offset);
|
||||||
|
programStackPushInteger(program, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set_proto_data
|
||||||
|
static void op_set_proto_data(Program* program)
|
||||||
|
{
|
||||||
|
int value = programStackPopInteger(program);
|
||||||
|
size_t offset = static_cast<size_t>(programStackPopInteger(program));
|
||||||
|
int pid = programStackPopInteger(program);
|
||||||
|
|
||||||
|
Proto* proto;
|
||||||
|
if (protoGetProto(pid, &proto) != 0) {
|
||||||
|
debugPrint("op_set_proto_data: bad proto %d", pid);
|
||||||
|
programStackPushInteger(program, -1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CE: Make sure the requested offset is within memory bounds and is
|
||||||
|
// properly aligned.
|
||||||
|
if (offset + sizeof(int) > proto_size(PID_TYPE(pid)) || offset % sizeof(int) != 0) {
|
||||||
|
debugPrint("op_set_proto_data: bad offset %d", offset);
|
||||||
|
programStackPushInteger(program, -1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
*reinterpret_cast<int*>(reinterpret_cast<unsigned char*>(proto) + offset) = value;
|
||||||
|
}
|
||||||
|
|
||||||
// list_begin
|
// list_begin
|
||||||
static void opListBegin(Program* program)
|
static void opListBegin(Program* program)
|
||||||
{
|
{
|
||||||
|
@ -251,6 +397,14 @@ static void opGetMouseY(Program* program)
|
||||||
programStackPushInteger(program, y);
|
programStackPushInteger(program, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get_mouse_buttons
|
||||||
|
static void op_get_mouse_buttons(Program* program)
|
||||||
|
{
|
||||||
|
// CE: Implementation is slightly different - it does not handle middle
|
||||||
|
// mouse button.
|
||||||
|
programStackPushInteger(program, mouse_get_last_buttons());
|
||||||
|
}
|
||||||
|
|
||||||
// get_screen_width
|
// get_screen_width
|
||||||
static void opGetScreenWidth(Program* program)
|
static void opGetScreenWidth(Program* program)
|
||||||
{
|
{
|
||||||
|
@ -263,6 +417,17 @@ static void opGetScreenHeight(Program* program)
|
||||||
programStackPushInteger(program, screenGetHeight());
|
programStackPushInteger(program, screenGetHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get_attack_type
|
||||||
|
static void op_get_attack_type(Program* program)
|
||||||
|
{
|
||||||
|
int hit_mode;
|
||||||
|
if (interface_get_current_attack_mode(&hit_mode)) {
|
||||||
|
programStackPushInteger(program, hit_mode);
|
||||||
|
} else {
|
||||||
|
programStackPushInteger(program, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// atoi
|
// atoi
|
||||||
static void opParseInt(Program* program)
|
static void opParseInt(Program* program)
|
||||||
{
|
{
|
||||||
|
@ -270,6 +435,24 @@ static void opParseInt(Program* program)
|
||||||
programStackPushInteger(program, static_cast<int>(strtol(string, nullptr, 0)));
|
programStackPushInteger(program, static_cast<int>(strtol(string, nullptr, 0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// atof
|
||||||
|
static void op_atof(Program* program)
|
||||||
|
{
|
||||||
|
const char* string = programStackPopString(program);
|
||||||
|
programStackPushFloat(program, static_cast<float>(atof(string)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// tile_under_cursor
|
||||||
|
static void op_tile_under_cursor(Program* program)
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
mouseGetPosition(&x, &y);
|
||||||
|
|
||||||
|
int tile = tileFromScreenXY(x, y, gElevation);
|
||||||
|
programStackPushInteger(program, tile);
|
||||||
|
}
|
||||||
|
|
||||||
// strlen
|
// strlen
|
||||||
static void opGetStringLength(Program* program)
|
static void opGetStringLength(Program* program)
|
||||||
{
|
{
|
||||||
|
@ -277,6 +460,22 @@ static void opGetStringLength(Program* program)
|
||||||
programStackPushInteger(program, static_cast<int>(strlen(string)));
|
programStackPushInteger(program, static_cast<int>(strlen(string)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pow (^)
|
||||||
|
static void op_power(Program* program)
|
||||||
|
{
|
||||||
|
ProgramValue expValue = programStackPopValue(program);
|
||||||
|
ProgramValue baseValue = programStackPopValue(program);
|
||||||
|
|
||||||
|
// CE: Implementation is slightly different, check.
|
||||||
|
float result = powf(baseValue.asFloat(), expValue.asFloat());
|
||||||
|
|
||||||
|
if (baseValue.isInt() && expValue.isInt()) {
|
||||||
|
programStackPushInteger(program, static_cast<int>(result));
|
||||||
|
} else {
|
||||||
|
programStackPushFloat(program, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// message_str_game
|
// message_str_game
|
||||||
static void opGetMessage(Program* program)
|
static void opGetMessage(Program* program)
|
||||||
{
|
{
|
||||||
|
@ -298,6 +497,61 @@ static void opRound(Program* program)
|
||||||
programStackPushInteger(program, integerValue);
|
programStackPushInteger(program, integerValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum BlockType {
|
||||||
|
BLOCKING_TYPE_BLOCK,
|
||||||
|
BLOCKING_TYPE_SHOOT,
|
||||||
|
BLOCKING_TYPE_AI,
|
||||||
|
BLOCKING_TYPE_SIGHT,
|
||||||
|
BLOCKING_TYPE_SCROLL,
|
||||||
|
};
|
||||||
|
|
||||||
|
PathBuilderCallback* get_blocking_func(int type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case BLOCKING_TYPE_SHOOT:
|
||||||
|
return _obj_shoot_blocking_at;
|
||||||
|
case BLOCKING_TYPE_AI:
|
||||||
|
return _obj_ai_blocking_at;
|
||||||
|
case BLOCKING_TYPE_SIGHT:
|
||||||
|
return _obj_sight_blocking_at;
|
||||||
|
default:
|
||||||
|
return _obj_blocking_at;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// obj_blocking_line
|
||||||
|
static void op_make_straight_path(Program* program)
|
||||||
|
{
|
||||||
|
int type = programStackPopInteger(program);
|
||||||
|
int dest = programStackPopInteger(program);
|
||||||
|
Object* object = static_cast<Object*>(programStackPopPointer(program));
|
||||||
|
|
||||||
|
int flags = type == BLOCKING_TYPE_SHOOT ? 32 : 0;
|
||||||
|
|
||||||
|
Object* obstacle = nullptr;
|
||||||
|
_make_straight_path_func(object, object->tile, dest, nullptr, &obstacle, flags, get_blocking_func(type));
|
||||||
|
programStackPushPointer(program, obstacle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// obj_blocking_tile
|
||||||
|
static void op_obj_blocking_at(Program* program)
|
||||||
|
{
|
||||||
|
int type = programStackPopInteger(program);
|
||||||
|
int elevation = programStackPopInteger(program);
|
||||||
|
int tile = programStackPopInteger(program);
|
||||||
|
|
||||||
|
PathBuilderCallback* func = get_blocking_func(type);
|
||||||
|
Object* obstacle = func(NULL, tile, elevation);
|
||||||
|
if (obstacle != NULL) {
|
||||||
|
if (type == BLOCKING_TYPE_SHOOT) {
|
||||||
|
if ((obstacle->flags & OBJECT_SHOOT_THRU) != 0) {
|
||||||
|
obstacle = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
programStackPushPointer(program, obstacle);
|
||||||
|
}
|
||||||
|
|
||||||
// art_exists
|
// art_exists
|
||||||
static void opArtExists(Program* program)
|
static void opArtExists(Program* program)
|
||||||
{
|
{
|
||||||
|
@ -305,15 +559,50 @@ static void opArtExists(Program* program)
|
||||||
programStackPushInteger(program, artExists(fid));
|
programStackPushInteger(program, artExists(fid));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// div (/)
|
||||||
|
static void op_div(Program* program)
|
||||||
|
{
|
||||||
|
ProgramValue divisorValue = programStackPopValue(program);
|
||||||
|
ProgramValue dividendValue = programStackPopValue(program);
|
||||||
|
|
||||||
|
if (divisorValue.integerValue == 0) {
|
||||||
|
debugPrint("Division by zero");
|
||||||
|
|
||||||
|
// TODO: Looks like execution is not halted in Sfall's div, check.
|
||||||
|
programStackPushInteger(program, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dividendValue.isFloat() || divisorValue.isFloat()) {
|
||||||
|
programStackPushFloat(program, dividendValue.asFloat() / divisorValue.asFloat());
|
||||||
|
} else {
|
||||||
|
// Unsigned divison.
|
||||||
|
programStackPushInteger(program, static_cast<unsigned int>(dividendValue.integerValue) / static_cast<unsigned int>(divisorValue.integerValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void sfallOpcodesInit()
|
void sfallOpcodesInit()
|
||||||
{
|
{
|
||||||
interpreterRegisterOpcode(0x8156, opReadByte);
|
interpreterRegisterOpcode(0x8156, opReadByte);
|
||||||
|
interpreterRegisterOpcode(0x815A, op_set_pc_base_stat);
|
||||||
interpreterRegisterOpcode(0x815B, opSetPcBonusStat);
|
interpreterRegisterOpcode(0x815B, opSetPcBonusStat);
|
||||||
|
interpreterRegisterOpcode(0x815C, op_get_pc_base_stat);
|
||||||
interpreterRegisterOpcode(0x815D, opGetPcBonusStat);
|
interpreterRegisterOpcode(0x815D, opGetPcBonusStat);
|
||||||
|
interpreterRegisterOpcode(0x8163, op_get_year);
|
||||||
|
interpreterRegisterOpcode(0x8170, op_in_world_map);
|
||||||
|
interpreterRegisterOpcode(0x8172, op_set_world_map_pos);
|
||||||
interpreterRegisterOpcode(0x8193, opGetCurrentHand);
|
interpreterRegisterOpcode(0x8193, opGetCurrentHand);
|
||||||
interpreterRegisterOpcode(0x819D, opSetGlobalVar);
|
interpreterRegisterOpcode(0x819D, opSetGlobalVar);
|
||||||
interpreterRegisterOpcode(0x819E, opGetGlobalInt);
|
interpreterRegisterOpcode(0x819E, opGetGlobalInt);
|
||||||
interpreterRegisterOpcode(0x81AF, opGetGameMode);
|
interpreterRegisterOpcode(0x81AF, opGetGameMode);
|
||||||
|
interpreterRegisterOpcode(0x81B3, op_get_uptime);
|
||||||
|
interpreterRegisterOpcode(0x81B6, op_set_car_current_town);
|
||||||
|
interpreterRegisterOpcode(0x81DF, op_get_bodypart_hit_modifier);
|
||||||
|
interpreterRegisterOpcode(0x81E0, op_set_bodypart_hit_modifier);
|
||||||
|
interpreterRegisterOpcode(0x81EC, op_sqrt);
|
||||||
|
interpreterRegisterOpcode(0x81ED, op_abs);
|
||||||
|
interpreterRegisterOpcode(0x8204, op_get_proto_data);
|
||||||
|
interpreterRegisterOpcode(0x8205, op_set_proto_data);
|
||||||
interpreterRegisterOpcode(0x820D, opListBegin);
|
interpreterRegisterOpcode(0x820D, opListBegin);
|
||||||
interpreterRegisterOpcode(0x820E, opListNext);
|
interpreterRegisterOpcode(0x820E, opListNext);
|
||||||
interpreterRegisterOpcode(0x820F, opListEnd);
|
interpreterRegisterOpcode(0x820F, opListEnd);
|
||||||
|
@ -326,13 +615,21 @@ void sfallOpcodesInit()
|
||||||
interpreterRegisterOpcode(0x821A, opSetWeaponAmmoCount);
|
interpreterRegisterOpcode(0x821A, opSetWeaponAmmoCount);
|
||||||
interpreterRegisterOpcode(0x821C, opGetMouseX);
|
interpreterRegisterOpcode(0x821C, opGetMouseX);
|
||||||
interpreterRegisterOpcode(0x821D, opGetMouseY);
|
interpreterRegisterOpcode(0x821D, opGetMouseY);
|
||||||
|
interpreterRegisterOpcode(0x821E, op_get_mouse_buttons);
|
||||||
interpreterRegisterOpcode(0x8220, opGetScreenWidth);
|
interpreterRegisterOpcode(0x8220, opGetScreenWidth);
|
||||||
interpreterRegisterOpcode(0x8221, opGetScreenHeight);
|
interpreterRegisterOpcode(0x8221, opGetScreenHeight);
|
||||||
|
interpreterRegisterOpcode(0x8228, op_get_attack_type);
|
||||||
interpreterRegisterOpcode(0x8237, opParseInt);
|
interpreterRegisterOpcode(0x8237, opParseInt);
|
||||||
|
interpreterRegisterOpcode(0x8238, op_atof);
|
||||||
|
interpreterRegisterOpcode(0x824B, op_tile_under_cursor);
|
||||||
interpreterRegisterOpcode(0x824F, opGetStringLength);
|
interpreterRegisterOpcode(0x824F, opGetStringLength);
|
||||||
|
interpreterRegisterOpcode(0x8263, op_power);
|
||||||
interpreterRegisterOpcode(0x826B, opGetMessage);
|
interpreterRegisterOpcode(0x826B, opGetMessage);
|
||||||
interpreterRegisterOpcode(0x8267, opRound);
|
interpreterRegisterOpcode(0x8267, opRound);
|
||||||
|
interpreterRegisterOpcode(0x826E, op_make_straight_path);
|
||||||
|
interpreterRegisterOpcode(0x826F, op_obj_blocking_at);
|
||||||
interpreterRegisterOpcode(0x8274, opArtExists);
|
interpreterRegisterOpcode(0x8274, opArtExists);
|
||||||
|
interpreterRegisterOpcode(0x827F, op_div);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sfallOpcodesExit()
|
void sfallOpcodesExit()
|
||||||
|
|
85
src/tile.cc
85
src/tile.cc
|
@ -5,6 +5,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
#include "art.h"
|
#include "art.h"
|
||||||
#include "color.h"
|
#include "color.h"
|
||||||
|
@ -49,11 +50,16 @@ typedef struct UpsideDownTriangle {
|
||||||
int field_8;
|
int field_8;
|
||||||
} UpsideDownTriangle;
|
} UpsideDownTriangle;
|
||||||
|
|
||||||
|
struct roof_fill_task {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
};
|
||||||
|
|
||||||
static void tileSetBorder(int windowWidth, int windowHeight, int hexGridWidth, int hexGridHeight);
|
static void tileSetBorder(int windowWidth, int windowHeight, int hexGridWidth, int hexGridHeight);
|
||||||
static void tileRefreshMapper(Rect* rect, int elevation);
|
static void tileRefreshMapper(Rect* rect, int elevation);
|
||||||
static void tileRefreshGame(Rect* rect, int elevation);
|
static void tileRefreshGame(Rect* rect, int elevation);
|
||||||
static void roof_fill_on(int x, int y, int elevation);
|
static void roof_fill_push_task_if_in_bounds(std::stack<roof_fill_task>& tasks_stack, int x, int y);
|
||||||
static void roof_fill_off(int x, int y, int elevation);
|
static void roof_fill_off_process_task(std::stack<roof_fill_task>& tasks_stack, int elevation, bool on);
|
||||||
static void tileRenderRoof(int fid, int x, int y, Rect* rect, int light);
|
static void tileRenderRoof(int fid, int x, int y, Rect* rect, int light);
|
||||||
static void _draw_grid(int tile, int elevation, Rect* rect);
|
static void _draw_grid(int tile, int elevation, Rect* rect);
|
||||||
static void tileRenderFloor(int fid, int x, int y, Rect* rect);
|
static void tileRenderFloor(int fid, int x, int y, Rect* rect);
|
||||||
|
@ -1258,27 +1264,39 @@ void tileRenderRoofsInRect(Rect* rect, int elevation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0x4B22D0
|
static void roof_fill_push_task_if_in_bounds(std::stack<roof_fill_task>& tasks_stack, int x, int y)
|
||||||
static void roof_fill_on(int x, int y, int elevation)
|
|
||||||
{
|
{
|
||||||
if (x >= 0 && x < gSquareGridWidth && y >= 0 && y < gSquareGridHeight) {
|
if (x >= 0 && x < gSquareGridWidth && y >= 0 && y < gSquareGridHeight) {
|
||||||
int squareTileIndex = gSquareGridWidth * y + x;
|
tasks_stack.push(roof_fill_task { x, y });
|
||||||
int squareTile = gTileSquares[elevation]->field_0[squareTileIndex];
|
};
|
||||||
int roof = (squareTile >> 16) & 0xFFFF;
|
};
|
||||||
|
|
||||||
int id = roof & 0xFFF;
|
static void roof_fill_off_process_task(std::stack<roof_fill_task>& tasks_stack, int elevation, bool on)
|
||||||
if (buildFid(OBJ_TYPE_TILE, id, 0, 0, 0) != buildFid(OBJ_TYPE_TILE, 1, 0, 0, 0)) {
|
{
|
||||||
int flag = (roof & 0xF000) >> 12;
|
auto [x, y] = tasks_stack.top();
|
||||||
if ((flag & 0x01) != 0) {
|
tasks_stack.pop();
|
||||||
|
|
||||||
|
int squareTileIndex = gSquareGridWidth * y + x;
|
||||||
|
int squareTile = gTileSquares[elevation]->field_0[squareTileIndex];
|
||||||
|
int roof = (squareTile >> 16) & 0xFFFF;
|
||||||
|
|
||||||
|
int id = roof & 0xFFF;
|
||||||
|
if (buildFid(OBJ_TYPE_TILE, id, 0, 0, 0) != buildFid(OBJ_TYPE_TILE, 1, 0, 0, 0)) {
|
||||||
|
int flag = (roof & 0xF000) >> 12;
|
||||||
|
|
||||||
|
if (on ? ((flag & 0x01) != 0) : ((flag & 0x03) == 0)) {
|
||||||
|
if (on) {
|
||||||
flag &= ~0x01;
|
flag &= ~0x01;
|
||||||
|
} else {
|
||||||
gTileSquares[elevation]->field_0[squareTileIndex] = (squareTile & 0xFFFF) | (((flag << 12) | id) << 16);
|
flag |= 0x01;
|
||||||
|
|
||||||
roof_fill_on(x - 1, y, elevation);
|
|
||||||
roof_fill_on(x + 1, y, elevation);
|
|
||||||
roof_fill_on(x, y - 1, elevation);
|
|
||||||
roof_fill_on(x, y + 1, elevation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gTileSquares[elevation]->field_0[squareTileIndex] = (squareTile & 0xFFFF) | (((flag << 12) | id) << 16);
|
||||||
|
|
||||||
|
roof_fill_push_task_if_in_bounds(tasks_stack, x - 1, y);
|
||||||
|
roof_fill_push_task_if_in_bounds(tasks_stack, x + 1, y);
|
||||||
|
roof_fill_push_task_if_in_bounds(tasks_stack, x, y - 1);
|
||||||
|
roof_fill_push_task_if_in_bounds(tasks_stack, x, y + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1286,35 +1304,12 @@ static void roof_fill_on(int x, int y, int elevation)
|
||||||
// 0x4B23D4
|
// 0x4B23D4
|
||||||
void tile_fill_roof(int x, int y, int elevation, bool on)
|
void tile_fill_roof(int x, int y, int elevation, bool on)
|
||||||
{
|
{
|
||||||
if (on) {
|
std::stack<roof_fill_task> tasks_stack;
|
||||||
roof_fill_on(x, y, elevation);
|
|
||||||
} else {
|
|
||||||
roof_fill_off(x, y, elevation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 0x4B23DC
|
roof_fill_push_task_if_in_bounds(tasks_stack, x, y);
|
||||||
static void roof_fill_off(int x, int y, int elevation)
|
|
||||||
{
|
|
||||||
if (x >= 0 && x < gSquareGridWidth && y >= 0 && y < gSquareGridHeight) {
|
|
||||||
int squareTileIndex = gSquareGridWidth * y + x;
|
|
||||||
int squareTile = gTileSquares[elevation]->field_0[squareTileIndex];
|
|
||||||
int roof = (squareTile >> 16) & 0xFFFF;
|
|
||||||
|
|
||||||
int id = roof & 0xFFF;
|
while (!tasks_stack.empty()) {
|
||||||
if (buildFid(OBJ_TYPE_TILE, id, 0, 0, 0) != buildFid(OBJ_TYPE_TILE, 1, 0, 0, 0)) {
|
roof_fill_off_process_task(tasks_stack, elevation, on);
|
||||||
int flag = (roof & 0xF000) >> 12;
|
|
||||||
if ((flag & 0x03) == 0) {
|
|
||||||
flag |= 0x01;
|
|
||||||
|
|
||||||
gTileSquares[elevation]->field_0[squareTileIndex] = (squareTile & 0xFFFF) | (((flag << 12) | id) << 16);
|
|
||||||
|
|
||||||
roof_fill_off(x - 1, y, elevation);
|
|
||||||
roof_fill_off(x + 1, y, elevation);
|
|
||||||
roof_fill_off(x, y - 1, elevation);
|
|
||||||
roof_fill_off(x, y + 1, elevation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6592,4 +6592,15 @@ void wmBlinkRndEncounterIcon(bool special)
|
||||||
wmGenData.encounterIconIsVisible = false;
|
wmGenData.encounterIconIsVisible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void wmSetPartyWorldPos(int x, int y)
|
||||||
|
{
|
||||||
|
wmGenData.worldPosX = x;
|
||||||
|
wmGenData.worldPosY = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wmCarSetCurrentArea(int area)
|
||||||
|
{
|
||||||
|
wmGenData.currentCarAreaId = area;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace fallout
|
} // namespace fallout
|
||||||
|
|
|
@ -277,6 +277,9 @@ int wmSetMapMusic(int mapIdx, const char* name);
|
||||||
int wmMatchAreaContainingMapIdx(int mapIdx, int* areaIdxPtr);
|
int wmMatchAreaContainingMapIdx(int mapIdx, int* areaIdxPtr);
|
||||||
int wmTeleportToArea(int areaIdx);
|
int wmTeleportToArea(int areaIdx);
|
||||||
|
|
||||||
|
void wmSetPartyWorldPos(int x, int y);
|
||||||
|
void wmCarSetCurrentArea(int area);
|
||||||
|
|
||||||
} // namespace fallout
|
} // namespace fallout
|
||||||
|
|
||||||
#endif /* WORLD_MAP_H */
|
#endif /* WORLD_MAP_H */
|
||||||
|
|
Loading…
Reference in New Issue