mirror of
https://github.com/fallout2-ce/fallout2-ce.git
synced 2026-07-27 16:47:11 -07:00
Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1c6fa29292 | ||
|
|
dd21129464 | ||
|
|
7604061e1c | ||
|
|
f832d78949 | ||
|
|
57b784b8a0 | ||
|
|
d5fd197dd9 | ||
|
|
6375604af8 | ||
|
|
c02c5efcf6 |
@@ -142,7 +142,7 @@ jobs:
|
|||||||
ios:
|
ios:
|
||||||
name: iOS
|
name: iOS
|
||||||
|
|
||||||
runs-on: macos-15
|
runs-on: macos-14
|
||||||
needs: [ce-dat]
|
needs: [ce-dat]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -328,7 +328,7 @@ jobs:
|
|||||||
macos:
|
macos:
|
||||||
name: macOS
|
name: macOS
|
||||||
|
|
||||||
runs-on: macos-15
|
runs-on: macos-14
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Clone
|
- name: Clone
|
||||||
|
|||||||
+2
-2
@@ -6,10 +6,10 @@ set(EXECUTABLE_NAME fallout2-ce)
|
|||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
if(IOS)
|
if(IOS)
|
||||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "13" CACHE STRING "")
|
set(CMAKE_OSX_DEPLOYMENT_TARGET "12" CACHE STRING "")
|
||||||
set(CMAKE_OSX_ARCHITECTURES "arm64" CACHE STRING "")
|
set(CMAKE_OSX_ARCHITECTURES "arm64" CACHE STRING "")
|
||||||
else()
|
else()
|
||||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "")
|
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.13" CACHE STRING "")
|
||||||
set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64" CACHE STRING "")
|
set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64" CACHE STRING "")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ See [`https://sfall-team.github.io/sfall/`](https://sfall-team.github.io/sfall/)
|
|||||||
| Perks and traits | set_perk_image<br>set_perk_*<br>set_pyromaniac_mod<br>apply_heaveho_fix<br>set_swiftlearner_mod<br>has/set_fake_perk<br>has/set_fake_trait<br>set_selectable_perk<br>set_perkbox_title<br>show/hide_real_perks<br>perk_add_mode<br>clear_selectable_perks<br>add/remove_trait<br>seq_perk_freq | not implemented | - |
|
| Perks and traits | set_perk_image<br>set_perk_*<br>set_pyromaniac_mod<br>apply_heaveho_fix<br>set_swiftlearner_mod<br>has/set_fake_perk<br>has/set_fake_trait<br>set_selectable_perk<br>set_perkbox_title<br>show/hide_real_perks<br>perk_add_mode<br>clear_selectable_perks<br>add/remove_trait<br>seq_perk_freq | not implemented | - |
|
||||||
| Virtual file system | fs_create<br>fs_copy<br>fs_find<br>fs_read/write_*<br>fs_delete<br>fs_size<br>fs_pos<br>fs_seek<br>fs_resize | đźš« | Open an issue if you have a use case for these |
|
| Virtual file system | fs_create<br>fs_copy<br>fs_find<br>fs_read/write_*<br>fs_delete<br>fs_size<br>fs_pos<br>fs_seek<br>fs_resize | đźš« | Open an issue if you have a use case for these |
|
||||||
| Combat / Knockback | set_weapon_knockback<br>set_target_knockback<br>set_attacker_knockback<br>remove_weapon_knockback<br>remove_target_knockback<br>remove_attacker_knockback | not implemented | - |
|
| Combat / Knockback | set_weapon_knockback<br>set_target_knockback<br>set_attacker_knockback<br>remove_weapon_knockback<br>remove_target_knockback<br>remove_attacker_knockback | not implemented | - |
|
||||||
| Maps and encounters | in_world_map<br>force_encounter{_with_flags}<br>set_map_time_multi<br>get/set_map_enter_position<br>exec_map_update_scripts<br>get/set_terrain_name<br>set_town_title<br>get/set_can_rest_on_map<br>set_rest_heal_time<br>set_rest_mode<br>set_worldmap_heal_time | implemented: in_world_map, force_encounter, force_encounter_with_flags, set_map_time_multi | - |
|
| Maps and encounters | in_world_map<br>force_encounter{_with_flags}<br>set_map_time_multi<br>get/set_map_enter_position<br>exec_map_update_scripts<br>get/set_terrain_name<br>set_town_title<br>get/set_can_rest_on_map<br>set_rest_heal_time<br>set_rest_mode<br>set_worldmap_heal_time | implemented: in_world_map, force_encounter, force_encounter_with_flags, set_map_time_multi, get_terrain_name, set_terrain_name | - |
|
||||||
| Maps and encounters / Worldmap | get_world_map_x/y_pos<br>set_world_map_pos | âś… | - |
|
| Maps and encounters / Worldmap | get_world_map_x/y_pos<br>set_world_map_pos | âś… | - |
|
||||||
| Audio | play_sfall_sound<br>stop_sfall_sound | âś… | `play_sfall_sound` currently supports `.acm`, `.wav`, `.ogg` formats, and can load from `.dat` archives. `.mp3` is not yet supported. |
|
| Audio | play_sfall_sound<br>stop_sfall_sound | âś… | `play_sfall_sound` currently supports `.acm`, `.wav`, `.ogg` formats, and can load from `.dat` archives. `.mp3` is not yet supported. |
|
||||||
| Combat / Weapons and ammo | get/set_weapon_ammo_pid<br>get/set_weapon_ammo_count | âś… | - |
|
| Combat / Weapons and ammo | get/set_weapon_ammo_pid<br>get/set_weapon_ammo_count | âś… | - |
|
||||||
|
|||||||
@@ -55,6 +55,9 @@ big_font_color=0
|
|||||||
; Pixel offset for main menu buttons.
|
; Pixel offset for main menu buttons.
|
||||||
offset_x=0
|
offset_x=0
|
||||||
offset_y=0
|
offset_y=0
|
||||||
|
; Pixel offset for the high resolution main menu button panel.
|
||||||
|
main_menu_panel_offset_x=16
|
||||||
|
main_menu_panel_offset_y=15
|
||||||
; Pixel offset for the copyright text line.
|
; Pixel offset for the copyright text line.
|
||||||
credits_offset_x=0
|
credits_offset_x=0
|
||||||
credits_offset_y=0
|
credits_offset_y=0
|
||||||
|
|||||||
@@ -89,7 +89,6 @@ def assertSdlJavaBindingsMatch = { String variantName ->
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdk 32
|
compileSdk 32
|
||||||
ndkVersion "27.3.13750724"
|
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId 'com.alexbatalov.fallout2ce'
|
applicationId 'com.alexbatalov.fallout2ce'
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#include "test_utils.h"
|
||||||
|
#include "sfall.h"
|
||||||
|
|
||||||
|
procedure start begin
|
||||||
|
variable defaultName;
|
||||||
|
|
||||||
|
display_msg("Testing terrain name metarules...");
|
||||||
|
|
||||||
|
call assertEquals("get metarule exists", metarule_exist("get_terrain_name"), 1);
|
||||||
|
call assertEquals("set metarule exists", metarule_exist("set_terrain_name"), 1);
|
||||||
|
|
||||||
|
defaultName := get_terrain_name(0, 0);
|
||||||
|
call assertNotEquals("default terrain name is not error", defaultName, "Error");
|
||||||
|
call assertNotEquals("default terrain name is not empty", defaultName, "");
|
||||||
|
|
||||||
|
set_terrain_name(0, 0, "CE Terrain Override");
|
||||||
|
call assertEquals("terrain override is returned", get_terrain_name(0, 0), "CE Terrain Override");
|
||||||
|
|
||||||
|
set_terrain_name(0, 0, "CE Terrain Override 2");
|
||||||
|
call assertEquals("latest terrain override wins", get_terrain_name(0, 0), "CE Terrain Override 2");
|
||||||
|
call assertEquals("one argument get returns error", sfall_func1("get_terrain_name", 0), -1);
|
||||||
|
call assertEquals("invalid get returns error", get_terrain_name(-1, 0), "Error");
|
||||||
|
call assertNotEquals("current terrain name is available", get_current_terrain_name, "Error");
|
||||||
|
|
||||||
|
call report_test_results("terrain_name");
|
||||||
|
signal_close_game;
|
||||||
|
end
|
||||||
+1
-1
@@ -3019,7 +3019,7 @@ int _check_move(int* actionPointsPtr)
|
|||||||
if (isInCombat()) {
|
if (isInCombat()) {
|
||||||
if (*actionPointsPtr != -1) {
|
if (*actionPointsPtr != -1) {
|
||||||
if (gPressedPhysicalKeys[SDL_SCANCODE_RCTRL] || gPressedPhysicalKeys[SDL_SCANCODE_LCTRL]) {
|
if (gPressedPhysicalKeys[SDL_SCANCODE_RCTRL] || gPressedPhysicalKeys[SDL_SCANCODE_LCTRL]) {
|
||||||
int hitMode;
|
HitMode hitMode;
|
||||||
bool aiming;
|
bool aiming;
|
||||||
interfaceGetCurrentHitMode(&hitMode, &aiming);
|
interfaceGetCurrentHitMode(&hitMode, &aiming);
|
||||||
|
|
||||||
|
|||||||
+66
-63
@@ -93,7 +93,7 @@ typedef struct DamageCalculationContext {
|
|||||||
int difficultyDamagePercent;
|
int difficultyDamagePercent;
|
||||||
} DamageCalculationContext;
|
} DamageCalculationContext;
|
||||||
|
|
||||||
static bool _combat_safety_invalidate_weapon_func(Object* attacker, Object* weapon, int hitMode, Object* defender, int* safeDistancePtr, Object* attackerFriend);
|
static bool _combat_safety_invalidate_weapon_func(Object* attacker, Object* weapon, HitMode hitMode, Object* defender, int* safeDistancePtr, Object* attackerFriend);
|
||||||
static void _combatInitAIInfoList();
|
static void _combatInitAIInfoList();
|
||||||
static int aiInfoCopy(int srcIndex, int destIndex);
|
static int aiInfoCopy(int srcIndex, int destIndex);
|
||||||
static int _combatAIInfoSetLastMove(Object* object, int move);
|
static int _combatAIInfoSetLastMove(Object* object, int move);
|
||||||
@@ -122,7 +122,7 @@ static int attackComputeCriticalHit(Attack* a1);
|
|||||||
static int _attackFindInvalidFlags(Object* a1, Object* a2);
|
static int _attackFindInvalidFlags(Object* a1, Object* a2);
|
||||||
static int attackComputeCriticalFailure(Attack* attack);
|
static int attackComputeCriticalFailure(Attack* attack);
|
||||||
static void _do_random_cripple(int* flagsPtr);
|
static void _do_random_cripple(int* flagsPtr);
|
||||||
static int attackDetermineToHit(Object* attacker, int tile, Object* defender, int hitLocation, int hitMode, bool useDistance);
|
static int attackDetermineToHit(Object* attacker, int tile, Object* defender, HitLocation hitLocation, HitMode hitMode, bool useDistance);
|
||||||
static void attackComputeDamage(Attack* attack, int numRounds, int baseDamageMult);
|
static void attackComputeDamage(Attack* attack, int numRounds, int baseDamageMult);
|
||||||
static void _check_for_death(Object* a1, int a2, int* a3);
|
static void _check_for_death(Object* a1, int a2, int* a3);
|
||||||
static void _set_new_results(Object* a1, int a2);
|
static void _set_new_results(Object* a1, int a2);
|
||||||
@@ -131,11 +131,11 @@ static void combatCopyDamageAmountDescription(char* dest, size_t size, Object* c
|
|||||||
static void combatAddDamageFlagsDescription(char* a1, int flags, Object* a3);
|
static void combatAddDamageFlagsDescription(char* a1, int flags, Object* a3);
|
||||||
static void _combat_standup(Object* a1);
|
static void _combat_standup(Object* a1);
|
||||||
static void _print_tohit(unsigned char* dest, int dest_pitch, int a3);
|
static void _print_tohit(unsigned char* dest, int dest_pitch, int a3);
|
||||||
static char* hitLocationGetName(Object* critter, int hitLocation);
|
static char* hitLocationGetName(Object* critter, HitLocation hitLocation);
|
||||||
static void _draw_loc_off(int a1, int a2);
|
static void _draw_loc_off(int a1, int a2);
|
||||||
static void _draw_loc_on_(int a1, int a2);
|
static void _draw_loc_on_(int a1, int a2);
|
||||||
static void _draw_loc_(int eventCode, int color);
|
static void _draw_loc_(int eventCode, int color);
|
||||||
static int calledShotSelectHitLocation(Object* critter, int* hitLocation, int hitMode);
|
static int calledShotSelectHitLocation(Object* critter, HitLocation* hitLocation, HitMode hitMode);
|
||||||
|
|
||||||
static void criticalsInit();
|
static void criticalsInit();
|
||||||
static void criticalsReset();
|
static void criticalsReset();
|
||||||
@@ -145,7 +145,7 @@ static int burstModComputeRounds(int totalRounds, int* centerRoundsPtr, int* lef
|
|||||||
static void unarmedInit();
|
static void unarmedInit();
|
||||||
static void unarmedInitVanilla();
|
static void unarmedInitVanilla();
|
||||||
static void unarmedInitCustom();
|
static void unarmedInitCustom();
|
||||||
static int unarmedGetHitModeInRange(int firstHitMode, int lastHitMode, bool isSecondary);
|
static HitMode unarmedGetHitModeInRange(HitMode firstHitMode, HitMode lastHitMode, bool isSecondary);
|
||||||
static void damageModInit();
|
static void damageModInit();
|
||||||
static void damageModCalculateGlovz(DamageCalculationContext* context);
|
static void damageModCalculateGlovz(DamageCalculationContext* context);
|
||||||
static int damageModGlovzDivRound(int dividend, int divisor);
|
static int damageModGlovzDivRound(int dividend, int divisor);
|
||||||
@@ -163,7 +163,7 @@ int _combatNumTurns = 0;
|
|||||||
static int combatTurnHookResult = 0;
|
static int combatTurnHookResult = 0;
|
||||||
|
|
||||||
// 0x510944 combat_state
|
// 0x510944 combat_state
|
||||||
unsigned int gCombatState = COMBAT_STATE_PLAYER_TURN;
|
CombatState gCombatState = COMBAT_STATE_PLAYER_TURN;
|
||||||
|
|
||||||
// 0x510948 aiInfoList
|
// 0x510948 aiInfoList
|
||||||
static CombatAiInfo* _aiInfoList = nullptr;
|
static CombatAiInfo* _aiInfoList = nullptr;
|
||||||
@@ -1899,7 +1899,7 @@ static const int _call_ty[4] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 0x51803C hit_loc_left
|
// 0x51803C hit_loc_left
|
||||||
static const int _hit_loc_left[4] = {
|
static const HitLocation _hit_loc_left[4] = {
|
||||||
HIT_LOCATION_HEAD,
|
HIT_LOCATION_HEAD,
|
||||||
HIT_LOCATION_EYES,
|
HIT_LOCATION_EYES,
|
||||||
HIT_LOCATION_RIGHT_ARM,
|
HIT_LOCATION_RIGHT_ARM,
|
||||||
@@ -1907,7 +1907,7 @@ static const int _hit_loc_left[4] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 0x51804C hit_loc_right
|
// 0x51804C hit_loc_right
|
||||||
static const int _hit_loc_right[4] = {
|
static const HitLocation _hit_loc_right[4] = {
|
||||||
HIT_LOCATION_TORSO,
|
HIT_LOCATION_TORSO,
|
||||||
HIT_LOCATION_GROIN,
|
HIT_LOCATION_GROIN,
|
||||||
HIT_LOCATION_LEFT_ARM,
|
HIT_LOCATION_LEFT_ARM,
|
||||||
@@ -2103,7 +2103,7 @@ int _find_cid(int a1, int cid, Object** critterList, int critterListLength)
|
|||||||
// 0x420E4C
|
// 0x420E4C
|
||||||
int combatLoad(File* stream)
|
int combatLoad(File* stream)
|
||||||
{
|
{
|
||||||
if (fileReadUInt32(stream, &gCombatState) == -1) return -1;
|
if (fileReadUInt32(stream, reinterpret_cast<unsigned int*>(&gCombatState)) == -1) return -1;
|
||||||
|
|
||||||
if (!isInCombat()) {
|
if (!isInCombat()) {
|
||||||
Object* obj = objectFindFirst();
|
Object* obj = objectFindFirst();
|
||||||
@@ -2297,13 +2297,13 @@ int combatSave(File* stream)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 0x4213E8
|
// 0x4213E8
|
||||||
bool _combat_safety_invalidate_weapon(Object* attacker, Object* weapon, int hitMode, Object* defender, int* safeDistancePtr)
|
bool _combat_safety_invalidate_weapon(Object* attacker, Object* weapon, HitMode hitMode, Object* defender, int* safeDistancePtr)
|
||||||
{
|
{
|
||||||
return _combat_safety_invalidate_weapon_func(attacker, weapon, hitMode, defender, safeDistancePtr, nullptr);
|
return _combat_safety_invalidate_weapon_func(attacker, weapon, hitMode, defender, safeDistancePtr, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0x4213FC
|
// 0x4213FC
|
||||||
static bool _combat_safety_invalidate_weapon_func(Object* attacker, Object* weapon, int hitMode, Object* defender, int* safeDistancePtr, Object* attackerFriend)
|
static bool _combat_safety_invalidate_weapon_func(Object* attacker, Object* weapon, HitMode hitMode, Object* defender, int* safeDistancePtr, Object* attackerFriend)
|
||||||
{
|
{
|
||||||
if (safeDistancePtr != nullptr) {
|
if (safeDistancePtr != nullptr) {
|
||||||
*safeDistancePtr = 0;
|
*safeDistancePtr = 0;
|
||||||
@@ -2680,7 +2680,7 @@ static void _combat_begin_extra(Object* attacker)
|
|||||||
_combat_update_critter_outline_for_los(_combat_list[index], 0);
|
_combat_update_critter_outline_for_los(_combat_list[index], 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
attackInit(&_main_ctd, attacker, nullptr, 4, 3);
|
attackInit(&_main_ctd, attacker, nullptr, HIT_MODE_PUNCH, HIT_LOCATION_TORSO);
|
||||||
|
|
||||||
_combat_turn_obj = attacker;
|
_combat_turn_obj = attacker;
|
||||||
|
|
||||||
@@ -2874,7 +2874,7 @@ static void _combat_over()
|
|||||||
void _combat_over_from_load()
|
void _combat_over_from_load()
|
||||||
{
|
{
|
||||||
_combat_over();
|
_combat_over();
|
||||||
gCombatState = 0;
|
gCombatState = COMBAT_STATE_OUT_COMBAT;
|
||||||
_combat_end_due_to_load = 1;
|
_combat_end_due_to_load = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3468,7 +3468,7 @@ void _combat(CombatStartData* csd)
|
|||||||
if (csd == nullptr
|
if (csd == nullptr
|
||||||
|| (csd->attacker == nullptr || csd->attacker->elevation == gElevation)
|
|| (csd->attacker == nullptr || csd->attacker->elevation == gElevation)
|
||||||
|| (csd->defender == nullptr || csd->defender->elevation == gElevation)) {
|
|| (csd->defender == nullptr || csd->defender->elevation == gElevation)) {
|
||||||
bool wasInCombat = (gCombatState & COMBAT_STATE_IN_COMBAT) != 0;
|
bool wasInCombat = isInCombat();
|
||||||
|
|
||||||
_combat_begin(nullptr);
|
_combat_begin(nullptr);
|
||||||
|
|
||||||
@@ -3566,7 +3566,7 @@ void _combat(CombatStartData* csd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 0x422EC4
|
// 0x422EC4
|
||||||
void attackInit(Attack* attack, Object* attacker, Object* defender, int hitMode, int hitLocation)
|
void attackInit(Attack* attack, Object* attacker, Object* defender, HitMode hitMode, HitLocation hitLocation)
|
||||||
{
|
{
|
||||||
attack->attacker = attacker;
|
attack->attacker = attacker;
|
||||||
attack->hitMode = hitMode;
|
attack->hitMode = hitMode;
|
||||||
@@ -3587,7 +3587,7 @@ void attackInit(Attack* attack, Object* attacker, Object* defender, int hitMode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 0x422F3C
|
// 0x422F3C
|
||||||
int _combat_attack(Object* attacker, Object* defender, int hitMode, int hitLocation)
|
int _combat_attack(Object* attacker, Object* defender, HitMode hitMode, HitLocation hitLocation)
|
||||||
{
|
{
|
||||||
if (attacker != gDude && hitMode == HIT_MODE_PUNCH && randomBetween(1, 4) == 1) {
|
if (attacker != gDude && hitMode == HIT_MODE_PUNCH && randomBetween(1, 4) == 1) {
|
||||||
int fid = buildFid(OBJ_TYPE_CRITTER, attacker->fid & 0xFFF, ANIM_KICK_LEG, (attacker->fid & 0xF000) >> 12, FID_ROTATION(attacker->fid));
|
int fid = buildFid(OBJ_TYPE_CRITTER, attacker->fid & 0xFFF, ANIM_KICK_LEG, (attacker->fid & 0xF000) >> 12, FID_ROTATION(attacker->fid));
|
||||||
@@ -4415,26 +4415,26 @@ static void _do_random_cripple(int* flagsPtr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 0x42436C
|
// 0x42436C
|
||||||
int _determine_to_hit(Object* attacker, Object* defender, int hitLocation, int hitMode)
|
int _determine_to_hit(Object* attacker, Object* defender, HitLocation hitLocation, HitMode hitMode)
|
||||||
{
|
{
|
||||||
return attackDetermineToHit(attacker, attacker->tile, defender, hitLocation, hitMode, true);
|
return attackDetermineToHit(attacker, attacker->tile, defender, hitLocation, hitMode, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0x424380
|
// 0x424380
|
||||||
int _determine_to_hit_no_range(Object* attacker, Object* defender, int hitLocation, int hitMode, unsigned char* a5)
|
int _determine_to_hit_no_range(Object* attacker, Object* defender, HitLocation hitLocation, HitMode hitMode, unsigned char* a5)
|
||||||
{
|
{
|
||||||
return attackDetermineToHit(attacker, attacker->tile, defender, hitLocation, hitMode, false);
|
return attackDetermineToHit(attacker, attacker->tile, defender, hitLocation, hitMode, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0x424394
|
// 0x424394
|
||||||
int _determine_to_hit_from_tile(Object* attacker, int tile, Object* defender, int hitLocation, int hitMode)
|
int _determine_to_hit_from_tile(Object* attacker, int tile, Object* defender, HitLocation hitLocation, HitMode hitMode)
|
||||||
{
|
{
|
||||||
return attackDetermineToHit(attacker, tile, defender, hitLocation, hitMode, true);
|
return attackDetermineToHit(attacker, tile, defender, hitLocation, hitMode, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// determine_to_hit
|
// determine_to_hit
|
||||||
// 0x4243A8
|
// 0x4243A8
|
||||||
static int attackDetermineToHit(Object* attacker, int tile, Object* defender, int hitLocation, int hitMode, bool useDistance)
|
static int attackDetermineToHit(Object* attacker, int tile, Object* defender, HitLocation hitLocation, HitMode hitMode, bool useDistance)
|
||||||
{
|
{
|
||||||
Object* weapon = critterGetWeaponForHitMode(attacker, hitMode);
|
Object* weapon = critterGetWeaponForHitMode(attacker, hitMode);
|
||||||
|
|
||||||
@@ -4689,15 +4689,18 @@ static void attackComputeDamage(Attack* attack, int numRounds, int baseDamageMul
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SFALL: Damage mod.
|
// SFALL: Damage mod.
|
||||||
DamageCalculationContext context;
|
DamageCalculationContext context = {};
|
||||||
context.attack = attack;
|
context.attack = attack;
|
||||||
context.damagePtr = damagePtr;
|
context.damagePtr = damagePtr;
|
||||||
|
context.ammoQuantity = numRounds;
|
||||||
context.damageResistance = damageResistance;
|
context.damageResistance = damageResistance;
|
||||||
context.damageThreshold = damageThreshold;
|
context.damageThreshold = damageThreshold;
|
||||||
context.damageBonus = damageBonus;
|
context.damageBonus = damageBonus;
|
||||||
context.baseDamageMult = baseDamageMult;
|
context.baseDamageMult = baseDamageMult;
|
||||||
context.difficultyDamagePercent = difficultyDamagePercent;
|
context.difficultyDamagePercent = difficultyDamagePercent;
|
||||||
|
|
||||||
|
// SFALL: HOOK_SUBCOMBATDAMAGE would fit here when no built-in damage
|
||||||
|
// formula is selected. In sfall, DamageFormula 1/2/5 bypasses that hook.
|
||||||
if (gDamageCalculationType == DAMAGE_CALCULATION_TYPE_GLOVZ || gDamageCalculationType == DAMAGE_CALCULATION_TYPE_GLOVZ_WITH_DAMAGE_MULTIPLIER_TWEAK) {
|
if (gDamageCalculationType == DAMAGE_CALCULATION_TYPE_GLOVZ || gDamageCalculationType == DAMAGE_CALCULATION_TYPE_GLOVZ_WITH_DAMAGE_MULTIPLIER_TWEAK) {
|
||||||
damageModCalculateGlovz(&context);
|
damageModCalculateGlovz(&context);
|
||||||
} else if (gDamageCalculationType == DAMAGE_CALCULATION_TYPE_YAAM) {
|
} else if (gDamageCalculationType == DAMAGE_CALCULATION_TYPE_YAAM) {
|
||||||
@@ -5553,7 +5556,7 @@ static void _print_tohit(unsigned char* dest, int destPitch, int accuracy)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 0x42612C
|
// 0x42612C
|
||||||
static char* hitLocationGetName(Object* critter, int hitLocation)
|
static char* hitLocationGetName(Object* critter, HitLocation hitLocation)
|
||||||
{
|
{
|
||||||
MessageListItem messageListItem;
|
MessageListItem messageListItem;
|
||||||
messageListItem.num = 1000 + 10 * _art_alias_num(critter->fid & 0xFFF) + hitLocation;
|
messageListItem.num = 1000 + 10 * _art_alias_num(critter->fid & 0xFFF) + hitLocation;
|
||||||
@@ -5592,7 +5595,7 @@ static void _draw_loc_(int eventCode, int color)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 0x426218
|
// 0x426218
|
||||||
static int calledShotSelectHitLocation(Object* critter, int* hitLocation, int hitMode)
|
static int calledShotSelectHitLocation(Object* critter, HitLocation* hitLocation, HitMode hitMode)
|
||||||
{
|
{
|
||||||
*hitLocation = HIT_LOCATION_TORSO;
|
*hitLocation = HIT_LOCATION_TORSO;
|
||||||
|
|
||||||
@@ -5760,7 +5763,7 @@ static int calledShotSelectHitLocation(Object* critter, int* hitLocation, int hi
|
|||||||
|
|
||||||
// check for possibility of performing attacking
|
// check for possibility of performing attacking
|
||||||
// 0x426614
|
// 0x426614
|
||||||
int _combat_check_bad_shot(Object* attacker, Object* defender, int hitMode, bool aiming)
|
CombatBadShot _combat_check_bad_shot(Object* attacker, Object* defender, HitMode hitMode, bool aiming)
|
||||||
{
|
{
|
||||||
int range = 1;
|
int range = 1;
|
||||||
int tile = -1;
|
int tile = -1;
|
||||||
@@ -5816,7 +5819,7 @@ int _combat_check_bad_shot(Object* attacker, Object* defender, int hitMode, bool
|
|||||||
// 0x426744
|
// 0x426744
|
||||||
bool _combat_to_hit(Object* target, int* accuracy)
|
bool _combat_to_hit(Object* target, int* accuracy)
|
||||||
{
|
{
|
||||||
int hitMode;
|
HitMode hitMode;
|
||||||
bool aiming;
|
bool aiming;
|
||||||
if (interfaceGetCurrentHitMode(&hitMode, &aiming) == -1) {
|
if (interfaceGetCurrentHitMode(&hitMode, &aiming) == -1) {
|
||||||
return false;
|
return false;
|
||||||
@@ -5842,7 +5845,7 @@ void _combat_attack_this(Object* target)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hitMode;
|
HitMode hitMode;
|
||||||
bool aiming;
|
bool aiming;
|
||||||
if (interfaceGetCurrentHitMode(&hitMode, &aiming) == -1) {
|
if (interfaceGetCurrentHitMode(&hitMode, &aiming) == -1) {
|
||||||
return;
|
return;
|
||||||
@@ -5853,7 +5856,7 @@ void _combat_attack_this(Object* target)
|
|||||||
char formattedText[80];
|
char formattedText[80];
|
||||||
const char* sfx;
|
const char* sfx;
|
||||||
|
|
||||||
int rc = _combat_check_bad_shot(gDude, target, hitMode, aiming);
|
CombatBadShot rc = _combat_check_bad_shot(gDude, target, hitMode, aiming);
|
||||||
switch (rc) {
|
switch (rc) {
|
||||||
case COMBAT_BAD_SHOT_NO_AMMO:
|
case COMBAT_BAD_SHOT_NO_AMMO:
|
||||||
item = critterGetWeaponForHitMode(gDude, hitMode);
|
item = critterGetWeaponForHitMode(gDude, hitMode);
|
||||||
@@ -5925,7 +5928,7 @@ void _combat_attack_this(Object* target)
|
|||||||
debugPrint("Bad called shot value %d\n", aiming);
|
debugPrint("Bad called shot value %d\n", aiming);
|
||||||
}
|
}
|
||||||
|
|
||||||
int hitLocation;
|
HitLocation hitLocation;
|
||||||
if (calledShotSelectHitLocation(target, &hitLocation, hitMode) != -1) {
|
if (calledShotSelectHitLocation(target, &hitLocation, hitMode) != -1) {
|
||||||
_combat_attack(gDude, target, hitMode, hitLocation);
|
_combat_attack(gDude, target, hitMode, hitLocation);
|
||||||
}
|
}
|
||||||
@@ -5976,7 +5979,7 @@ void _combat_outline_off()
|
|||||||
int v5;
|
int v5;
|
||||||
Object** v9;
|
Object** v9;
|
||||||
|
|
||||||
if ((gCombatState & COMBAT_STATE_IN_COMBAT) != 0) {
|
if (isInCombat()) {
|
||||||
for (i = 0; i < _list_total; i++) {
|
for (i = 0; i < _list_total; i++) {
|
||||||
objectDisableOutline(_combat_list[i], nullptr);
|
objectDisableOutline(_combat_list[i], nullptr);
|
||||||
}
|
}
|
||||||
@@ -6303,13 +6306,13 @@ static void criticalsInit()
|
|||||||
|
|
||||||
// Read original kill types (19) plus one for the player.
|
// Read original kill types (19) plus one for the player.
|
||||||
for (int killType = 0; killType < KILL_TYPE_COUNT + 1; killType++) {
|
for (int killType = 0; killType < KILL_TYPE_COUNT + 1; killType++) {
|
||||||
for (int hitLocation = 0; hitLocation < HIT_LOCATION_COUNT; hitLocation++) {
|
for (HitLocation hitLocation = HIT_LOCATION_HEAD; hitLocation < HIT_LOCATION_COUNT; hitLocation++) {
|
||||||
for (int effect = 0; effect < CRTICIAL_EFFECT_COUNT; effect++) {
|
for (int effect = 0; effect < CRTICIAL_EFFECT_COUNT; effect++) {
|
||||||
snprintf(sectionKey, sizeof(sectionKey), "c_%02d_%d_%d", killType, hitLocation, effect);
|
snprintf(sectionKey, sizeof(sectionKey), "c_%02d_%d_%d", killType, hitLocation, effect);
|
||||||
|
|
||||||
// Update player kill type if needed.
|
// Update player kill type if needed.
|
||||||
int newKillType = killType == KILL_TYPE_COUNT ? SFALL_KILL_TYPE_COUNT : killType;
|
int newKillType = killType == KILL_TYPE_COUNT ? SFALL_KILL_TYPE_COUNT : killType;
|
||||||
for (int dataMember = 0; dataMember < CRIT_DATA_MEMBER_COUNT; dataMember++) {
|
for (CriticalHitDataMember dataMember = CRIT_DATA_MEMBER_DAMAGE_MULTIPLIER; dataMember < CRIT_DATA_MEMBER_COUNT; dataMember++) {
|
||||||
int value = criticalsGetValue(newKillType, hitLocation, effect, dataMember);
|
int value = criticalsGetValue(newKillType, hitLocation, effect, dataMember);
|
||||||
if (configGetInt(&criticalsConfig, sectionKey, gCritDataMemberKeys[dataMember], &value)) {
|
if (configGetInt(&criticalsConfig, sectionKey, gCritDataMemberKeys[dataMember], &value)) {
|
||||||
criticalsSetValue(newKillType, hitLocation, effect, dataMember, value);
|
criticalsSetValue(newKillType, hitLocation, effect, dataMember, value);
|
||||||
@@ -6333,7 +6336,7 @@ static void criticalsInit()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int hitLocation = 0; hitLocation < HIT_LOCATION_COUNT; hitLocation++) {
|
for (HitLocation hitLocation = HIT_LOCATION_HEAD; hitLocation < HIT_LOCATION_COUNT; hitLocation++) {
|
||||||
if (enabled < 2) {
|
if (enabled < 2) {
|
||||||
bool hitLocationChanged = false;
|
bool hitLocationChanged = false;
|
||||||
|
|
||||||
@@ -6348,7 +6351,7 @@ static void criticalsInit()
|
|||||||
snprintf(hitLocationSectionKey, sizeof(hitLocationSectionKey), "c_%02d_%d", killType, hitLocation);
|
snprintf(hitLocationSectionKey, sizeof(hitLocationSectionKey), "c_%02d_%d", killType, hitLocation);
|
||||||
|
|
||||||
for (int effect = 0; effect < CRTICIAL_EFFECT_COUNT; effect++) {
|
for (int effect = 0; effect < CRTICIAL_EFFECT_COUNT; effect++) {
|
||||||
for (int dataMember = 0; dataMember < CRIT_DATA_MEMBER_COUNT; dataMember++) {
|
for (CriticalHitDataMember dataMember = CRIT_DATA_MEMBER_DAMAGE_MULTIPLIER; dataMember < CRIT_DATA_MEMBER_COUNT; dataMember++) {
|
||||||
int value = criticalsGetValue(killType, hitLocation, effect, dataMember);
|
int value = criticalsGetValue(killType, hitLocation, effect, dataMember);
|
||||||
snprintf(key, sizeof(key), "e%d_%s", effect, gCritDataMemberKeys[dataMember]);
|
snprintf(key, sizeof(key), "e%d_%s", effect, gCritDataMemberKeys[dataMember]);
|
||||||
if (configGetInt(&criticalsConfig, hitLocationSectionKey, key, &value)) {
|
if (configGetInt(&criticalsConfig, hitLocationSectionKey, key, &value)) {
|
||||||
@@ -6380,7 +6383,7 @@ static void criticalsExit()
|
|||||||
criticalsReset();
|
criticalsReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
int criticalsGetValue(int killType, int hitLocation, int effect, int dataMember)
|
int criticalsGetValue(int killType, HitLocation hitLocation, int effect, CriticalHitDataMember dataMember)
|
||||||
{
|
{
|
||||||
if (killType == SFALL_KILL_TYPE_COUNT) {
|
if (killType == SFALL_KILL_TYPE_COUNT) {
|
||||||
return gPlayerCriticalHitTable[hitLocation][effect].values[dataMember];
|
return gPlayerCriticalHitTable[hitLocation][effect].values[dataMember];
|
||||||
@@ -6389,7 +6392,7 @@ int criticalsGetValue(int killType, int hitLocation, int effect, int dataMember)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void criticalsSetValue(int killType, int hitLocation, int effect, int dataMember, int value)
|
void criticalsSetValue(int killType, HitLocation hitLocation, int effect, CriticalHitDataMember dataMember, int value)
|
||||||
{
|
{
|
||||||
if (killType == SFALL_KILL_TYPE_COUNT) {
|
if (killType == SFALL_KILL_TYPE_COUNT) {
|
||||||
gPlayerCriticalHitTable[hitLocation][effect].values[dataMember] = value;
|
gPlayerCriticalHitTable[hitLocation][effect].values[dataMember] = value;
|
||||||
@@ -6398,7 +6401,7 @@ void criticalsSetValue(int killType, int hitLocation, int effect, int dataMember
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void criticalsResetValue(int killType, int hitLocation, int effect, int dataMember)
|
void criticalsResetValue(int killType, HitLocation hitLocation, int effect, CriticalHitDataMember dataMember)
|
||||||
{
|
{
|
||||||
if (killType == SFALL_KILL_TYPE_COUNT) {
|
if (killType == SFALL_KILL_TYPE_COUNT) {
|
||||||
gPlayerCriticalHitTable[hitLocation][effect].values[dataMember] = gBasePlayerCriticalHitTable[hitLocation][effect].values[dataMember];
|
gPlayerCriticalHitTable[hitLocation][effect].values[dataMember] = gBasePlayerCriticalHitTable[hitLocation][effect].values[dataMember];
|
||||||
@@ -6649,7 +6652,7 @@ static void unarmedInitCustom()
|
|||||||
char section[4];
|
char section[4];
|
||||||
char statKey[6];
|
char statKey[6];
|
||||||
|
|
||||||
for (int hitMode = 0; hitMode < HIT_MODE_COUNT; hitMode++) {
|
for (HitMode hitMode = HIT_MODE_LEFT_WEAPON_PRIMARY; hitMode < HIT_MODE_COUNT; hitMode++) {
|
||||||
if (!isUnarmedHitMode(hitMode)) {
|
if (!isUnarmedHitMode(hitMode)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -6678,7 +6681,7 @@ static void unarmedInitCustom()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int unarmedGetDamage(int hitMode, int* minDamagePtr, int* maxDamagePtr)
|
int unarmedGetDamage(HitMode hitMode, int* minDamagePtr, int* maxDamagePtr)
|
||||||
{
|
{
|
||||||
UnarmedHitDescription* hitDescription = &(gUnarmedHitDescriptions[hitMode]);
|
UnarmedHitDescription* hitDescription = &(gUnarmedHitDescriptions[hitMode]);
|
||||||
*minDamagePtr = hitDescription->minDamage;
|
*minDamagePtr = hitDescription->minDamage;
|
||||||
@@ -6686,45 +6689,45 @@ int unarmedGetDamage(int hitMode, int* minDamagePtr, int* maxDamagePtr)
|
|||||||
return hitDescription->bonusDamage;
|
return hitDescription->bonusDamage;
|
||||||
}
|
}
|
||||||
|
|
||||||
int unarmedGetBonusCriticalChance(int hitMode)
|
int unarmedGetBonusCriticalChance(HitMode hitMode)
|
||||||
{
|
{
|
||||||
UnarmedHitDescription* hitDescription = &(gUnarmedHitDescriptions[hitMode]);
|
UnarmedHitDescription* hitDescription = &(gUnarmedHitDescriptions[hitMode]);
|
||||||
return hitDescription->bonusCriticalChance;
|
return hitDescription->bonusCriticalChance;
|
||||||
}
|
}
|
||||||
|
|
||||||
int unarmedGetActionPointCost(int hitMode)
|
int unarmedGetActionPointCost(HitMode hitMode)
|
||||||
{
|
{
|
||||||
UnarmedHitDescription* hitDescription = &(gUnarmedHitDescriptions[hitMode]);
|
UnarmedHitDescription* hitDescription = &(gUnarmedHitDescriptions[hitMode]);
|
||||||
return hitDescription->actionPointCost;
|
return hitDescription->actionPointCost;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool unarmedIsPenetrating(int hitMode)
|
bool unarmedIsPenetrating(HitMode hitMode)
|
||||||
{
|
{
|
||||||
UnarmedHitDescription* hitDescription = &(gUnarmedHitDescriptions[hitMode]);
|
UnarmedHitDescription* hitDescription = &(gUnarmedHitDescriptions[hitMode]);
|
||||||
return hitDescription->isPenetrate;
|
return hitDescription->isPenetrate;
|
||||||
}
|
}
|
||||||
|
|
||||||
int unarmedGetPunchHitMode(bool isSecondary)
|
HitMode unarmedGetPunchHitMode(bool isSecondary)
|
||||||
{
|
{
|
||||||
int hitMode = unarmedGetHitModeInRange(FIRST_ADVANCED_PUNCH_HIT_MODE, LAST_ADVANCED_PUNCH_HIT_MODE, isSecondary);
|
HitMode hitMode = unarmedGetHitModeInRange(FIRST_ADVANCED_PUNCH_HIT_MODE, LAST_ADVANCED_PUNCH_HIT_MODE, isSecondary);
|
||||||
if (hitMode == -1) {
|
if (hitMode == HIT_MODE_INVALID) {
|
||||||
hitMode = HIT_MODE_PUNCH;
|
hitMode = HIT_MODE_PUNCH;
|
||||||
}
|
}
|
||||||
return hitMode;
|
return hitMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
int unarmedGetKickHitMode(bool isSecondary)
|
HitMode unarmedGetKickHitMode(bool isSecondary)
|
||||||
{
|
{
|
||||||
int hitMode = unarmedGetHitModeInRange(FIRST_ADVANCED_KICK_HIT_MODE, LAST_ADVANCED_KICK_HIT_MODE, isSecondary);
|
HitMode hitMode = unarmedGetHitModeInRange(FIRST_ADVANCED_KICK_HIT_MODE, LAST_ADVANCED_KICK_HIT_MODE, isSecondary);
|
||||||
if (hitMode == -1) {
|
if (hitMode == HIT_MODE_INVALID) {
|
||||||
hitMode = HIT_MODE_KICK;
|
hitMode = HIT_MODE_KICK;
|
||||||
}
|
}
|
||||||
return hitMode;
|
return hitMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int unarmedGetHitModeInRange(int firstHitMode, int lastHitMode, bool isSecondary)
|
static HitMode unarmedGetHitModeInRange(HitMode firstHitMode, HitMode lastHitMode, bool isSecondary)
|
||||||
{
|
{
|
||||||
int hitMode = -1;
|
HitMode hitMode = HIT_MODE_INVALID;
|
||||||
|
|
||||||
int unarmed = skillGetValue(gDude, SKILL_UNARMED);
|
int unarmed = skillGetValue(gDude, SKILL_UNARMED);
|
||||||
int level = pcGetStat(PC_STAT_LEVEL);
|
int level = pcGetStat(PC_STAT_LEVEL);
|
||||||
@@ -6733,7 +6736,7 @@ static int unarmedGetHitModeInRange(int firstHitMode, int lastHitMode, bool isSe
|
|||||||
stats[stat] = critterGetStat(gDude, stat);
|
stats[stat] = critterGetStat(gDude, stat);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int candidateHitMode = firstHitMode; candidateHitMode <= lastHitMode; candidateHitMode++) {
|
for (HitMode candidateHitMode = firstHitMode; candidateHitMode <= lastHitMode; candidateHitMode++) {
|
||||||
UnarmedHitDescription* hitDescription = &(gUnarmedHitDescriptions[candidateHitMode]);
|
UnarmedHitDescription* hitDescription = &(gUnarmedHitDescriptions[candidateHitMode]);
|
||||||
if (isSecondary != hitDescription->isSecondary) {
|
if (isSecondary != hitDescription->isSecondary) {
|
||||||
continue;
|
continue;
|
||||||
@@ -6859,7 +6862,7 @@ static void damageModCalculateGlovz(DamageCalculationContext* context)
|
|||||||
if (gDamageCalculationType == DAMAGE_CALCULATION_TYPE_GLOVZ_WITH_DAMAGE_MULTIPLIER_TWEAK) {
|
if (gDamageCalculationType == DAMAGE_CALCULATION_TYPE_GLOVZ_WITH_DAMAGE_MULTIPLIER_TWEAK) {
|
||||||
damage += damageModGlovzDivRound(damage * context->baseDamageMult * 25, 100);
|
damage += damageModGlovzDivRound(damage * context->baseDamageMult * 25, 100);
|
||||||
} else {
|
} else {
|
||||||
damage += damage * context->baseDamageMult / 2;
|
damage = damage * context->baseDamageMult / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (damage > 0) {
|
if (damage > 0) {
|
||||||
@@ -6932,34 +6935,34 @@ static void damageModCalculateYaam(DamageCalculationContext* context)
|
|||||||
damage *= context->difficultyDamagePercent;
|
damage *= context->difficultyDamagePercent;
|
||||||
damage /= 100;
|
damage /= 100;
|
||||||
|
|
||||||
damage -= damage * damageResistance / 100;
|
damage -= damage * calculatedDamageResistance / 100;
|
||||||
|
|
||||||
if (damage > 0) {
|
if (damage > 0) {
|
||||||
context->damagePtr += damage;
|
*context->damagePtr += damage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int combat_get_hit_location_penalty(int hit_location)
|
int combat_get_hit_location_penalty(HitLocation hitLocation)
|
||||||
{
|
{
|
||||||
if (hit_location >= 0 && hit_location < HIT_LOCATION_COUNT) {
|
if (hitLocationIsValid(hitLocation)) {
|
||||||
return hit_location_penalty[hit_location];
|
return hit_location_penalty[hitLocation];
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void combat_set_hit_location_penalty(int hit_location, int penalty)
|
void combat_set_hit_location_penalty(HitLocation hitLocation, int penalty)
|
||||||
{
|
{
|
||||||
if (hit_location >= 0 && hit_location < HIT_LOCATION_COUNT) {
|
if (hitLocationIsValid(hitLocation)) {
|
||||||
hit_location_penalty[hit_location] = penalty;
|
hit_location_penalty[hitLocation] = penalty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void combat_reset_hit_location_penalty()
|
void combat_reset_hit_location_penalty()
|
||||||
{
|
{
|
||||||
for (int hit_location = 0; hit_location < HIT_LOCATION_COUNT; hit_location++) {
|
for (HitLocation hitLocation = HIT_LOCATION_HEAD; hitLocation < HIT_LOCATION_COUNT; hitLocation++) {
|
||||||
hit_location_penalty[hit_location] = hit_location_penalty_default[hit_location];
|
hit_location_penalty[hitLocation] = hit_location_penalty_default[hitLocation];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+21
-21
@@ -9,7 +9,7 @@
|
|||||||
namespace fallout {
|
namespace fallout {
|
||||||
|
|
||||||
extern int _combatNumTurns;
|
extern int _combatNumTurns;
|
||||||
extern unsigned int gCombatState;
|
extern CombatState gCombatState;
|
||||||
|
|
||||||
extern int _combat_free_move;
|
extern int _combat_free_move;
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ void combatExit();
|
|||||||
int _find_cid(int a1, int a2, Object** a3, int a4);
|
int _find_cid(int a1, int a2, Object** a3, int a4);
|
||||||
int combatLoad(File* stream);
|
int combatLoad(File* stream);
|
||||||
int combatSave(File* stream);
|
int combatSave(File* stream);
|
||||||
bool _combat_safety_invalidate_weapon(Object* attacker, Object* weapon, int hitMode, Object* defender, int* safeDistancePtr);
|
bool _combat_safety_invalidate_weapon(Object* attacker, Object* weapon, HitMode hitMode, Object* defender, int* safeDistancePtr);
|
||||||
bool _combatTestIncidentalHit(Object* attacker, Object* defender, Object* attackerFriend, Object* weapon);
|
bool _combatTestIncidentalHit(Object* attacker, Object* defender, Object* attackerFriend, Object* weapon);
|
||||||
Object* _combat_whose_turn();
|
Object* _combat_whose_turn();
|
||||||
void _combat_data_init(Object* obj);
|
void _combat_data_init(Object* obj);
|
||||||
@@ -34,19 +34,19 @@ void _combat_over_from_load();
|
|||||||
void _combat_give_exps(int exp_points);
|
void _combat_give_exps(int exp_points);
|
||||||
void _combat_turn_run();
|
void _combat_turn_run();
|
||||||
void _combat(CombatStartData* csd);
|
void _combat(CombatStartData* csd);
|
||||||
void attackInit(Attack* attack, Object* attacker, Object* defender, int hitMode, int hitLocation);
|
void attackInit(Attack* attack, Object* attacker, Object* defender, HitMode hitMode, HitLocation hitLocation);
|
||||||
int _combat_attack(Object* attacker, Object* defender, int hitMode, int hitLocation);
|
int _combat_attack(Object* attacker, Object* defender, HitMode hitMode, HitLocation hitLocation);
|
||||||
int _combat_bullet_start(const Object* attacker, const Object* target);
|
int _combat_bullet_start(const Object* attacker, const Object* target);
|
||||||
void _compute_explosion_on_extras(Attack* attack, bool isFromAttacker, bool isGrenade, bool noDamage);
|
void _compute_explosion_on_extras(Attack* attack, bool isFromAttacker, bool isGrenade, bool noDamage);
|
||||||
int _determine_to_hit(Object* a1, Object* a2, int hitLocation, int hitMode);
|
int _determine_to_hit(Object* a1, Object* a2, HitLocation hitLocation, HitMode hitMode);
|
||||||
int _determine_to_hit_no_range(Object* attacker, Object* defender, int hitLocation, int hitMode, unsigned char* a5);
|
int _determine_to_hit_no_range(Object* attacker, Object* defender, HitLocation hitLocation, HitMode hitMode, unsigned char* a5);
|
||||||
int _determine_to_hit_from_tile(Object* attacker, int tile, Object* defender, int hitLocation, int hitMode);
|
int _determine_to_hit_from_tile(Object* attacker, int tile, Object* defender, HitLocation hitLocation, HitMode hitMode);
|
||||||
void attackComputeDeathFlags(Attack* attack);
|
void attackComputeDeathFlags(Attack* attack);
|
||||||
void _apply_damage(Attack* attack, bool animated);
|
void _apply_damage(Attack* attack, bool animated);
|
||||||
void _combat_display(Attack* attack);
|
void _combat_display(Attack* attack);
|
||||||
void _combat_anim_begin();
|
void _combat_anim_begin();
|
||||||
void _combat_anim_finished();
|
void _combat_anim_finished();
|
||||||
int _combat_check_bad_shot(Object* attacker, Object* defender, int hitMode, bool aiming);
|
CombatBadShot _combat_check_bad_shot(Object* attacker, Object* defender, HitMode hitMode, bool aiming);
|
||||||
bool _combat_to_hit(Object* target, int* accuracy);
|
bool _combat_to_hit(Object* target, int* accuracy);
|
||||||
void _combat_attack_this(Object* target);
|
void _combat_attack_this(Object* target);
|
||||||
void _combat_outline_on();
|
void _combat_outline_on();
|
||||||
@@ -59,21 +59,21 @@ void _combat_delete_critter(Object* obj);
|
|||||||
void _combatKillCritterOutsideCombat(Object* critter_obj, char* msg);
|
void _combatKillCritterOutsideCombat(Object* critter_obj, char* msg);
|
||||||
|
|
||||||
int combatGetTargetHighlight();
|
int combatGetTargetHighlight();
|
||||||
int criticalsGetValue(int killType, int hitLocation, int effect, int dataMember);
|
int criticalsGetValue(int killType, HitLocation hitLocation, int effect, CriticalHitDataMember dataMember);
|
||||||
void criticalsSetValue(int killType, int hitLocation, int effect, int dataMember, int value);
|
void criticalsSetValue(int killType, HitLocation hitLocation, int effect, CriticalHitDataMember dataMember, int value);
|
||||||
void criticalsResetValue(int killType, int hitLocation, int effect, int dataMember);
|
void criticalsResetValue(int killType, HitLocation hitLocation, int effect, CriticalHitDataMember dataMember);
|
||||||
bool criticalsNoTimeLimits();
|
bool criticalsNoTimeLimits();
|
||||||
int unarmedGetDamage(int hitMode, int* minDamagePtr, int* maxDamagePtr);
|
int unarmedGetDamage(HitMode hitMode, int* minDamagePtr, int* maxDamagePtr);
|
||||||
int unarmedGetBonusCriticalChance(int hitMode);
|
int unarmedGetBonusCriticalChance(HitMode hitMode);
|
||||||
int unarmedGetActionPointCost(int hitMode);
|
int unarmedGetActionPointCost(HitMode hitMode);
|
||||||
bool unarmedIsPenetrating(int hitMode);
|
bool unarmedIsPenetrating(HitMode hitMode);
|
||||||
int unarmedGetPunchHitMode(bool isSecondary);
|
HitMode unarmedGetPunchHitMode(bool isSecondary);
|
||||||
int unarmedGetKickHitMode(bool isSecondary);
|
HitMode unarmedGetKickHitMode(bool isSecondary);
|
||||||
bool unarmedIsPenetrating(int hitMode);
|
bool unarmedIsPenetrating(HitMode hitMode);
|
||||||
bool damageModGetBonusHthDamageFix();
|
bool damageModGetBonusHthDamageFix();
|
||||||
bool damageModGetDisplayBonusDamage();
|
bool damageModGetDisplayBonusDamage();
|
||||||
int combat_get_hit_location_penalty(int hit_location);
|
int combat_get_hit_location_penalty(HitLocation hitLocation);
|
||||||
void combat_set_hit_location_penalty(int hit_location, int penalty);
|
void combat_set_hit_location_penalty(HitLocation hitLocation, int penalty);
|
||||||
void combat_reset_hit_location_penalty();
|
void combat_reset_hit_location_penalty();
|
||||||
Attack* combat_get_data();
|
Attack* combat_get_data();
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ static inline bool isInCombat()
|
|||||||
return (gCombatState & COMBAT_STATE_IN_COMBAT) != 0;
|
return (gCombatState & COMBAT_STATE_IN_COMBAT) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool isUnarmedHitMode(int hitMode)
|
static inline bool isUnarmedHitMode(HitMode hitMode)
|
||||||
{
|
{
|
||||||
return hitMode == HIT_MODE_PUNCH
|
return hitMode == HIT_MODE_PUNCH
|
||||||
|| hitMode == HIT_MODE_KICK
|
|| hitMode == HIT_MODE_KICK
|
||||||
|
|||||||
+21
-24
@@ -93,19 +93,19 @@ static Object* _ai_danger_source(Object* a1);
|
|||||||
static bool aiHaveAmmo(Object* critter, Object* weapon, Object** ammoPtr);
|
static bool aiHaveAmmo(Object* critter, Object* weapon, Object** ammoPtr);
|
||||||
static bool _caiHasWeapPrefType(AiPacket* ai, int attackType);
|
static bool _caiHasWeapPrefType(AiPacket* ai, int attackType);
|
||||||
static Object* _ai_best_weapon(Object* a1, Object* a2, Object* a3, Object* a4);
|
static Object* _ai_best_weapon(Object* a1, Object* a2, Object* a3, Object* a4);
|
||||||
static bool _ai_can_use_weapon(Object* critter, Object* weapon, int hitMode);
|
static bool _ai_can_use_weapon(Object* critter, Object* weapon, HitMode hitMode);
|
||||||
static bool aiCanUseItem(Object* obj, Object* a2);
|
static bool aiCanUseItem(Object* obj, Object* a2);
|
||||||
static Object* _ai_search_environ(Object* critter, int itemType);
|
static Object* _ai_search_environ(Object* critter, int itemType);
|
||||||
static Object* _ai_retrieve_object(Object* critter, Object* item);
|
static Object* _ai_retrieve_object(Object* critter, Object* item);
|
||||||
static int _ai_pick_hit_mode(Object* attacker, Object* weapon, Object* defender);
|
static HitMode _ai_pick_hit_mode(Object* attacker, Object* weapon, Object* defender);
|
||||||
static int _ai_move_steps_closer(Object* a1, Object* a2, int actionPoints, bool taunt);
|
static int _ai_move_steps_closer(Object* a1, Object* a2, int actionPoints, bool taunt);
|
||||||
static int _ai_move_closer(Object* a1, Object* a2, bool taunt);
|
static int _ai_move_closer(Object* a1, Object* a2, bool taunt);
|
||||||
static int _cai_retargetTileFromFriendlyFire(Object* source, Object* target, int* tilePtr);
|
static int _cai_retargetTileFromFriendlyFire(Object* source, Object* target, int* tilePtr);
|
||||||
static int _cai_retargetTileFromFriendlyFireSubFunc(AiRetargetData* aiRetargetData, int tile);
|
static int _cai_retargetTileFromFriendlyFireSubFunc(AiRetargetData* aiRetargetData, int tile);
|
||||||
static bool _cai_attackWouldIntersect(Object* attacker, Object* defender, Object* attackerFriend, int tile, int* distance);
|
static bool _cai_attackWouldIntersect(Object* attacker, Object* defender, Object* attackerFriend, int tile, int* distance);
|
||||||
static int _ai_switch_weapons(Object* a1, int* hitMode, Object** weapon, Object* a4);
|
static int _ai_switch_weapons(Object* a1, HitMode* hitMode, Object** weapon, Object* a4);
|
||||||
static int _ai_called_shot(Object* attacker, Object* defender, int hitMode);
|
static HitLocation _ai_called_shot(Object* attacker, Object* defender, HitMode hitMode);
|
||||||
static int _ai_attack(Object* attacker, Object* defender, int hitMode);
|
static int _ai_attack(Object* attacker, Object* defender, HitMode hitMode);
|
||||||
static int _ai_try_attack(Object* a1, Object* a2);
|
static int _ai_try_attack(Object* a1, Object* a2);
|
||||||
static int _cai_get_min_hp(AiPacket* ai);
|
static int _cai_get_min_hp(AiPacket* ai);
|
||||||
static int _ai_print_msg(Object* critter, int type);
|
static int _ai_print_msg(Object* critter, int type);
|
||||||
@@ -1619,7 +1619,7 @@ static Object* _ai_danger_source(Object* a1)
|
|||||||
// Check if we can attack it. No ammo and out of
|
// Check if we can attack it. No ammo and out of
|
||||||
// range are ok results, since we can reload weapon
|
// range are ok results, since we can reload weapon
|
||||||
// move closer if necessary.
|
// move closer if necessary.
|
||||||
int badShot = _combat_check_bad_shot(a1, critter, HIT_MODE_RIGHT_WEAPON_PRIMARY, false);
|
CombatBadShot badShot = _combat_check_bad_shot(a1, critter, HIT_MODE_RIGHT_WEAPON_PRIMARY, false);
|
||||||
if (badShot != COMBAT_BAD_SHOT_OK
|
if (badShot != COMBAT_BAD_SHOT_OK
|
||||||
&& badShot != COMBAT_BAD_SHOT_NO_AMMO
|
&& badShot != COMBAT_BAD_SHOT_NO_AMMO
|
||||||
&& badShot != COMBAT_BAD_SHOT_OUT_OF_RANGE) {
|
&& badShot != COMBAT_BAD_SHOT_OUT_OF_RANGE) {
|
||||||
@@ -1975,7 +1975,7 @@ static Object* _ai_best_weapon(Object* attacker, Object* weapon1, Object* weapon
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 0x4298EC
|
// 0x4298EC
|
||||||
static bool _ai_can_use_weapon(Object* critter, Object* weapon, int hitMode)
|
static bool _ai_can_use_weapon(Object* critter, Object* weapon, HitMode hitMode)
|
||||||
{
|
{
|
||||||
bool result = critterCanUseWeapon(critter, weapon, hitMode);
|
bool result = critterCanUseWeapon(critter, weapon, hitMode);
|
||||||
|
|
||||||
@@ -2260,7 +2260,7 @@ static Object* _ai_retrieve_object(Object* critter, Object* item)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 0x429DB4
|
// 0x429DB4
|
||||||
static int _ai_pick_hit_mode(Object* attacker, Object* weapon, Object* defender)
|
static HitMode _ai_pick_hit_mode(Object* attacker, Object* weapon, Object* defender)
|
||||||
{
|
{
|
||||||
if (weapon == nullptr) {
|
if (weapon == nullptr) {
|
||||||
return HIT_MODE_PUNCH;
|
return HIT_MODE_PUNCH;
|
||||||
@@ -2302,19 +2302,19 @@ static int _ai_pick_hit_mode(Object* attacker, Object* weapon, Object* defender)
|
|||||||
break;
|
break;
|
||||||
case AREA_ATTACK_MODE_BE_SURE:
|
case AREA_ATTACK_MODE_BE_SURE:
|
||||||
if (_determine_to_hit(attacker, defender, HIT_LOCATION_TORSO, HIT_MODE_RIGHT_WEAPON_SECONDARY) >= 85
|
if (_determine_to_hit(attacker, defender, HIT_LOCATION_TORSO, HIT_MODE_RIGHT_WEAPON_SECONDARY) >= 85
|
||||||
&& !_combat_safety_invalidate_weapon(attacker, weapon, 3, defender, nullptr)) {
|
&& !_combat_safety_invalidate_weapon(attacker, weapon, HIT_MODE_RIGHT_WEAPON_SECONDARY, defender, nullptr)) {
|
||||||
useSecondaryMode = true;
|
useSecondaryMode = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AREA_ATTACK_MODE_BE_CAREFUL:
|
case AREA_ATTACK_MODE_BE_CAREFUL:
|
||||||
if (_determine_to_hit(attacker, defender, HIT_LOCATION_TORSO, HIT_MODE_RIGHT_WEAPON_SECONDARY) >= 50
|
if (_determine_to_hit(attacker, defender, HIT_LOCATION_TORSO, HIT_MODE_RIGHT_WEAPON_SECONDARY) >= 50
|
||||||
&& !_combat_safety_invalidate_weapon(attacker, weapon, 3, defender, nullptr)) {
|
&& !_combat_safety_invalidate_weapon(attacker, weapon, HIT_MODE_RIGHT_WEAPON_SECONDARY, defender, nullptr)) {
|
||||||
useSecondaryMode = true;
|
useSecondaryMode = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AREA_ATTACK_MODE_BE_ABSOLUTELY_SURE:
|
case AREA_ATTACK_MODE_BE_ABSOLUTELY_SURE:
|
||||||
if (_determine_to_hit(attacker, defender, HIT_LOCATION_TORSO, HIT_MODE_RIGHT_WEAPON_SECONDARY) >= 95
|
if (_determine_to_hit(attacker, defender, HIT_LOCATION_TORSO, HIT_MODE_RIGHT_WEAPON_SECONDARY) >= 95
|
||||||
&& !_combat_safety_invalidate_weapon(attacker, weapon, 3, defender, nullptr)) {
|
&& !_combat_safety_invalidate_weapon(attacker, weapon, HIT_MODE_RIGHT_WEAPON_SECONDARY, defender, nullptr)) {
|
||||||
useSecondaryMode = true;
|
useSecondaryMode = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -2574,7 +2574,7 @@ static int _cai_retargetTileFromFriendlyFireSubFunc(AiRetargetData* aiRetargetDa
|
|||||||
// 0x42A518
|
// 0x42A518
|
||||||
static bool _cai_attackWouldIntersect(Object* attacker, Object* defender, Object* attackerFriend, int tile, int* distance)
|
static bool _cai_attackWouldIntersect(Object* attacker, Object* defender, Object* attackerFriend, int tile, int* distance)
|
||||||
{
|
{
|
||||||
int hitMode = HIT_MODE_RIGHT_WEAPON_PRIMARY;
|
HitMode hitMode = HIT_MODE_RIGHT_WEAPON_PRIMARY;
|
||||||
bool aiming = false;
|
bool aiming = false;
|
||||||
if (attacker == gDude) {
|
if (attacker == gDude) {
|
||||||
interfaceGetCurrentHitMode(&hitMode, &aiming);
|
interfaceGetCurrentHitMode(&hitMode, &aiming);
|
||||||
@@ -2601,7 +2601,7 @@ static bool _cai_attackWouldIntersect(Object* attacker, Object* defender, Object
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 0x42A5B8
|
// 0x42A5B8
|
||||||
static int _ai_switch_weapons(Object* attacker, int* hitMode, Object** weapon, Object* defender)
|
static int _ai_switch_weapons(Object* attacker, HitMode* hitMode, Object** weapon, Object* defender)
|
||||||
{
|
{
|
||||||
*weapon = nullptr;
|
*weapon = nullptr;
|
||||||
*hitMode = HIT_MODE_PUNCH;
|
*hitMode = HIT_MODE_PUNCH;
|
||||||
@@ -2639,9 +2639,9 @@ static int _ai_switch_weapons(Object* attacker, int* hitMode, Object** weapon, O
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 0x42A670
|
// 0x42A670
|
||||||
static int _ai_called_shot(Object* attacker, Object* defender, int hitMode)
|
static HitLocation _ai_called_shot(Object* attacker, Object* defender, HitMode hitMode)
|
||||||
{
|
{
|
||||||
int hitLocation = HIT_LOCATION_TORSO;
|
HitLocation hitLocation = HIT_LOCATION_TORSO;
|
||||||
|
|
||||||
if (weaponGetActionPointCost(attacker, hitMode, true) <= attacker->data.critter.combat.ap) {
|
if (weaponGetActionPointCost(attacker, hitMode, true) <= attacker->data.critter.combat.ap) {
|
||||||
if (critterCanAim(attacker, hitMode)) {
|
if (critterCanAim(attacker, hitMode)) {
|
||||||
@@ -2661,8 +2661,8 @@ static int _ai_called_shot(Object* attacker, Object* defender, int hitMode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (critterGetStat(attacker, STAT_INTELLIGENCE) >= intelligenceRequired) {
|
if (critterGetStat(attacker, STAT_INTELLIGENCE) >= intelligenceRequired) {
|
||||||
hitLocation = randomBetween(0, HIT_LOCATION_SPECIFIC_COUNT);
|
hitLocation = static_cast<HitLocation>(randomBetween(HIT_LOCATION_HEAD, HIT_LOCATION_SPECIFIC_COUNT));
|
||||||
int chanceToHit = _determine_to_hit(attacker, defender, hitMode, hitLocation);
|
int chanceToHit = _determine_to_hit(attacker, defender, hitLocation, hitMode);
|
||||||
if (chanceToHit < ai->min_to_hit) {
|
if (chanceToHit < ai->min_to_hit) {
|
||||||
hitLocation = HIT_LOCATION_TORSO;
|
hitLocation = HIT_LOCATION_TORSO;
|
||||||
}
|
}
|
||||||
@@ -2675,7 +2675,7 @@ static int _ai_called_shot(Object* attacker, Object* defender, int hitMode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 0x42A748
|
// 0x42A748
|
||||||
static int _ai_attack(Object* attacker, Object* defender, int hitMode)
|
static int _ai_attack(Object* attacker, Object* defender, HitMode hitMode)
|
||||||
{
|
{
|
||||||
if (attacker->data.critter.combat.maneuver & CRITTER_MANUEVER_FLEEING) {
|
if (attacker->data.critter.combat.maneuver & CRITTER_MANUEVER_FLEEING) {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -2686,7 +2686,7 @@ static int _ai_attack(Object* attacker, Object* defender, int hitMode)
|
|||||||
reg_anim_end();
|
reg_anim_end();
|
||||||
_combat_turn_run();
|
_combat_turn_run();
|
||||||
|
|
||||||
int hitLocation = _ai_called_shot(attacker, defender, hitMode);
|
HitLocation hitLocation = _ai_called_shot(attacker, defender, hitMode);
|
||||||
if (_combat_attack(attacker, defender, hitMode, hitLocation)) {
|
if (_combat_attack(attacker, defender, hitMode, hitLocation)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -2709,7 +2709,7 @@ static int _ai_try_attack(Object* attacker, Object* defender)
|
|||||||
weapon = nullptr;
|
weapon = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hitMode = _ai_pick_hit_mode(attacker, weapon, defender);
|
HitMode hitMode = _ai_pick_hit_mode(attacker, weapon, defender);
|
||||||
int minToHit = aiGetPacket(attacker)->min_to_hit;
|
int minToHit = aiGetPacket(attacker)->min_to_hit;
|
||||||
|
|
||||||
int actionPoints = attacker->data.critter.combat.ap;
|
int actionPoints = attacker->data.critter.combat.ap;
|
||||||
@@ -2736,7 +2736,7 @@ static int _ai_try_attack(Object* attacker, Object* defender)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
int reason = _combat_check_bad_shot(attacker, defender, hitMode, false);
|
CombatBadShot reason = _combat_check_bad_shot(attacker, defender, hitMode, false);
|
||||||
if (reason == COMBAT_BAD_SHOT_NO_AMMO) {
|
if (reason == COMBAT_BAD_SHOT_NO_AMMO) {
|
||||||
// If the secondary attack (for example, burst fire) does not have enough ammo,
|
// If the secondary attack (for example, burst fire) does not have enough ammo,
|
||||||
// try the primary attack, which may have a lower ammo cost.
|
// try the primary attack, which may have a lower ammo cost.
|
||||||
@@ -2821,9 +2821,6 @@ static int _ai_try_attack(Object* attacker, Object* defender)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (reason == COMBAT_BAD_SHOT_NOT_ENOUGH_AP || reason == COMBAT_BAD_SHOT_ARM_CRIPPLED || reason == COMBAT_BAD_SHOT_BOTH_ARMS_CRIPPLED) {
|
} else if (reason == COMBAT_BAD_SHOT_NOT_ENOUGH_AP || reason == COMBAT_BAD_SHOT_ARM_CRIPPLED || reason == COMBAT_BAD_SHOT_BOTH_ARMS_CRIPPLED) {
|
||||||
// 3 - not enough action points
|
|
||||||
// 6 - crippled one arm for two-handed weapon
|
|
||||||
// 7 - both hands crippled
|
|
||||||
if (_ai_switch_weapons(attacker, &hitMode, &weapon, defender) == -1) {
|
if (_ai_switch_weapons(attacker, &hitMode, &weapon, defender) == -1) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
+93
-32
@@ -12,13 +12,38 @@
|
|||||||
|
|
||||||
namespace fallout {
|
namespace fallout {
|
||||||
|
|
||||||
typedef enum CombatState {
|
enum CombatState : unsigned int {
|
||||||
|
COMBAT_STATE_OUT_COMBAT = 0x00,
|
||||||
COMBAT_STATE_IN_COMBAT = 0x01,
|
COMBAT_STATE_IN_COMBAT = 0x01,
|
||||||
COMBAT_STATE_PLAYER_TURN = 0x02,
|
COMBAT_STATE_PLAYER_TURN = 0x02,
|
||||||
COMBAT_STATE_EXIT_REQUESTED = 0x08,
|
COMBAT_STATE_EXIT_REQUESTED = 0x08,
|
||||||
} CombatState;
|
};
|
||||||
|
|
||||||
typedef enum HitMode {
|
inline fallout::CombatState& operator&=(fallout::CombatState& lhs, unsigned int rhs)
|
||||||
|
{
|
||||||
|
lhs = static_cast<fallout::CombatState>(static_cast<unsigned int>(lhs) & rhs);
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline constexpr CombatState operator~(CombatState rhs)
|
||||||
|
{
|
||||||
|
return static_cast<CombatState>(~static_cast<unsigned int>(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline CombatState& operator&=(CombatState& lhs, CombatState rhs)
|
||||||
|
{
|
||||||
|
lhs = static_cast<CombatState>(static_cast<unsigned int>(lhs) & static_cast<unsigned int>(rhs));
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline CombatState& operator|=(CombatState& lhs, CombatState rhs)
|
||||||
|
{
|
||||||
|
lhs = static_cast<CombatState>(static_cast<unsigned int>(lhs) | static_cast<unsigned int>(rhs));
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum HitMode : int {
|
||||||
|
HIT_MODE_INVALID = -1,
|
||||||
HIT_MODE_LEFT_WEAPON_PRIMARY = 0,
|
HIT_MODE_LEFT_WEAPON_PRIMARY = 0,
|
||||||
HIT_MODE_LEFT_WEAPON_SECONDARY = 1,
|
HIT_MODE_LEFT_WEAPON_SECONDARY = 1,
|
||||||
HIT_MODE_RIGHT_WEAPON_PRIMARY = 2,
|
HIT_MODE_RIGHT_WEAPON_PRIMARY = 2,
|
||||||
@@ -70,21 +95,45 @@ typedef enum HitMode {
|
|||||||
LAST_ADVANCED_KICK_HIT_MODE = HIT_MODE_PIERCING_KICK,
|
LAST_ADVANCED_KICK_HIT_MODE = HIT_MODE_PIERCING_KICK,
|
||||||
FIRST_ADVANCED_UNARMED_HIT_MODE = FIRST_ADVANCED_PUNCH_HIT_MODE,
|
FIRST_ADVANCED_UNARMED_HIT_MODE = FIRST_ADVANCED_PUNCH_HIT_MODE,
|
||||||
LAST_ADVANCED_UNARMED_HIT_MODE = LAST_ADVANCED_KICK_HIT_MODE,
|
LAST_ADVANCED_UNARMED_HIT_MODE = LAST_ADVANCED_KICK_HIT_MODE,
|
||||||
} HitMode;
|
};
|
||||||
|
|
||||||
typedef enum HitLocation {
|
inline static bool hitModeIsValid(int hitMode)
|
||||||
HIT_LOCATION_HEAD,
|
{
|
||||||
HIT_LOCATION_LEFT_ARM,
|
return hitMode >= HIT_MODE_LEFT_WEAPON_PRIMARY && hitMode < HIT_MODE_COUNT;
|
||||||
HIT_LOCATION_RIGHT_ARM,
|
}
|
||||||
HIT_LOCATION_TORSO,
|
|
||||||
HIT_LOCATION_RIGHT_LEG,
|
inline HitMode operator++(HitMode& e, int)
|
||||||
HIT_LOCATION_LEFT_LEG,
|
{
|
||||||
HIT_LOCATION_EYES,
|
HitMode result = e;
|
||||||
HIT_LOCATION_GROIN,
|
e = static_cast<HitMode>(static_cast<int>(e) + 1);
|
||||||
HIT_LOCATION_UNCALLED,
|
return result;
|
||||||
HIT_LOCATION_COUNT,
|
}
|
||||||
|
|
||||||
|
enum HitLocation : int {
|
||||||
|
HIT_LOCATION_HEAD = 0,
|
||||||
|
HIT_LOCATION_LEFT_ARM = 1,
|
||||||
|
HIT_LOCATION_RIGHT_ARM = 2,
|
||||||
|
HIT_LOCATION_TORSO = 3,
|
||||||
|
HIT_LOCATION_RIGHT_LEG = 4,
|
||||||
|
HIT_LOCATION_LEFT_LEG = 5,
|
||||||
|
HIT_LOCATION_EYES = 6,
|
||||||
|
HIT_LOCATION_GROIN = 7,
|
||||||
|
HIT_LOCATION_UNCALLED = 8,
|
||||||
|
HIT_LOCATION_COUNT = 9,
|
||||||
HIT_LOCATION_SPECIFIC_COUNT = HIT_LOCATION_COUNT - 1,
|
HIT_LOCATION_SPECIFIC_COUNT = HIT_LOCATION_COUNT - 1,
|
||||||
} HitLocation;
|
};
|
||||||
|
|
||||||
|
inline static bool hitLocationIsValid(int hitLocation)
|
||||||
|
{
|
||||||
|
return hitLocation >= HIT_LOCATION_HEAD && hitLocation < HIT_LOCATION_COUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline HitLocation operator++(HitLocation& e, int)
|
||||||
|
{
|
||||||
|
HitLocation result = e;
|
||||||
|
e = static_cast<HitLocation>(static_cast<int>(e) + 1);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct CombatStartData {
|
typedef struct CombatStartData {
|
||||||
Object* attacker;
|
Object* attacker;
|
||||||
@@ -101,16 +150,16 @@ typedef struct CombatStartData {
|
|||||||
|
|
||||||
typedef struct Attack {
|
typedef struct Attack {
|
||||||
Object* attacker;
|
Object* attacker;
|
||||||
int hitMode;
|
HitMode hitMode;
|
||||||
Object* weapon;
|
Object* weapon;
|
||||||
int attackHitLocation; // UNUSED?
|
HitLocation attackHitLocation; // UNUSED?
|
||||||
int attackerDamage;
|
int attackerDamage;
|
||||||
int attackerFlags;
|
int attackerFlags;
|
||||||
int ammoQuantity;
|
int ammoQuantity;
|
||||||
int criticalMessageId;
|
int criticalMessageId;
|
||||||
Object* defender;
|
Object* defender;
|
||||||
int tile;
|
int tile;
|
||||||
int defenderHitLocation;
|
HitLocation defenderHitLocation;
|
||||||
int defenderDamage;
|
int defenderDamage;
|
||||||
int defenderFlags;
|
int defenderFlags;
|
||||||
int defenderKnockback;
|
int defenderKnockback;
|
||||||
@@ -123,16 +172,28 @@ typedef struct Attack {
|
|||||||
int extrasKnockback[EXPLOSION_TARGET_COUNT];
|
int extrasKnockback[EXPLOSION_TARGET_COUNT];
|
||||||
} Attack;
|
} Attack;
|
||||||
|
|
||||||
typedef enum CriticalHitDescriptionDataMember {
|
enum CriticalHitDataMember : int {
|
||||||
CRIT_DATA_MEMBER_DAMAGE_MULTIPLIER,
|
CRIT_DATA_MEMBER_DAMAGE_MULTIPLIER = 0,
|
||||||
CRIT_DATA_MEMBER_FLAGS,
|
CRIT_DATA_MEMBER_FLAGS = 1,
|
||||||
CRIT_DATA_MEMBER_MASSIVE_CRITICAL_STAT,
|
CRIT_DATA_MEMBER_MASSIVE_CRITICAL_STAT = 2,
|
||||||
CRIT_DATA_MEMBER_MASSIVE_CRITICAL_STAT_MODIFIER,
|
CRIT_DATA_MEMBER_MASSIVE_CRITICAL_STAT_MODIFIER = 3,
|
||||||
CRIT_DATA_MEMBER_MASSIVE_CRITICAL_FLAGS,
|
CRIT_DATA_MEMBER_MASSIVE_CRITICAL_FLAGS = 4,
|
||||||
CRIT_DATA_MEMBER_MESSAGE_ID,
|
CRIT_DATA_MEMBER_MESSAGE_ID = 5,
|
||||||
CRIT_DATA_MEMBER_MASSIVE_CRITICAL_MESSAGE_ID,
|
CRIT_DATA_MEMBER_MASSIVE_CRITICAL_MESSAGE_ID = 6,
|
||||||
CRIT_DATA_MEMBER_COUNT,
|
CRIT_DATA_MEMBER_COUNT = 7,
|
||||||
} CriticalHitDescriptionDataMember;
|
};
|
||||||
|
|
||||||
|
inline static bool criticalHitDataMemberIsValid(int criticalHitDataMember)
|
||||||
|
{
|
||||||
|
return criticalHitDataMember >= CRIT_DATA_MEMBER_DAMAGE_MULTIPLIER && criticalHitDataMember < CRIT_DATA_MEMBER_COUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline CriticalHitDataMember operator++(CriticalHitDataMember& e, int)
|
||||||
|
{
|
||||||
|
CriticalHitDataMember result = e;
|
||||||
|
e = static_cast<CriticalHitDataMember>(static_cast<int>(e) + 1);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Provides metadata about critical hit effect.
|
// Provides metadata about critical hit effect.
|
||||||
typedef union CriticalHitDescription {
|
typedef union CriticalHitDescription {
|
||||||
@@ -160,7 +221,7 @@ typedef union CriticalHitDescription {
|
|||||||
int values[CRIT_DATA_MEMBER_COUNT];
|
int values[CRIT_DATA_MEMBER_COUNT];
|
||||||
} CriticalHitDescription;
|
} CriticalHitDescription;
|
||||||
|
|
||||||
typedef enum CombatBadShot {
|
enum CombatBadShot : int {
|
||||||
COMBAT_BAD_SHOT_OK = 0,
|
COMBAT_BAD_SHOT_OK = 0,
|
||||||
COMBAT_BAD_SHOT_NO_AMMO = 1,
|
COMBAT_BAD_SHOT_NO_AMMO = 1,
|
||||||
COMBAT_BAD_SHOT_OUT_OF_RANGE = 2,
|
COMBAT_BAD_SHOT_OUT_OF_RANGE = 2,
|
||||||
@@ -168,8 +229,8 @@ typedef enum CombatBadShot {
|
|||||||
COMBAT_BAD_SHOT_ALREADY_DEAD = 4,
|
COMBAT_BAD_SHOT_ALREADY_DEAD = 4,
|
||||||
COMBAT_BAD_SHOT_AIM_BLOCKED = 5,
|
COMBAT_BAD_SHOT_AIM_BLOCKED = 5,
|
||||||
COMBAT_BAD_SHOT_ARM_CRIPPLED = 6,
|
COMBAT_BAD_SHOT_ARM_CRIPPLED = 6,
|
||||||
COMBAT_BAD_SHOT_BOTH_ARMS_CRIPPLED = 7,
|
COMBAT_BAD_SHOT_BOTH_ARMS_CRIPPLED = 7
|
||||||
} CombatBadShot;
|
};
|
||||||
|
|
||||||
} // namespace fallout
|
} // namespace fallout
|
||||||
|
|
||||||
|
|||||||
+32
-15
@@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
namespace fallout {
|
namespace fallout {
|
||||||
|
|
||||||
#define CONFIG_FILE_MAX_LINE_LENGTH (1024)
|
#define CONFIG_FILE_MAX_LINE_LENGTH (2048)
|
||||||
|
|
||||||
// The initial number of sections (or key-value) pairs in the config.
|
// The initial number of sections (or key-value) pairs in the config.
|
||||||
#define CONFIG_INITIAL_CAPACITY (10)
|
#define CONFIG_INITIAL_CAPACITY (10)
|
||||||
@@ -32,9 +32,10 @@ struct CaseInsensitiveLess {
|
|||||||
typedef std::set<std::string, CaseInsensitiveLess> StringSet;
|
typedef std::set<std::string, CaseInsensitiveLess> StringSet;
|
||||||
|
|
||||||
static bool configParseLine(Config* config, char* string);
|
static bool configParseLine(Config* config, char* string);
|
||||||
static bool configParseKeyValue(char* string, char* key, char* value);
|
static bool configParseKeyValue(char* string, std::string& key, std::string& value);
|
||||||
static bool configEnsureSectionExists(Config* config, const char* sectionKey);
|
static bool configEnsureSectionExists(Config* config, const char* sectionKey);
|
||||||
static bool configTrimString(char* string);
|
static bool configTrimString(char* string);
|
||||||
|
static std::string configGetTrimmedString(const char* string);
|
||||||
|
|
||||||
static bool configWriteDb(Config* config, const char* filePath);
|
static bool configWriteDb(Config* config, const char* filePath);
|
||||||
static bool configWriteStandard(Config* config, const char* filePath);
|
static bool configWriteStandard(Config* config, const char* filePath);
|
||||||
@@ -120,10 +121,10 @@ bool configParseCommandLineArguments(Config* config, int argc, char** argv)
|
|||||||
|
|
||||||
*pch = '\0';
|
*pch = '\0';
|
||||||
|
|
||||||
char key[260];
|
std::string key;
|
||||||
char value[260];
|
std::string value;
|
||||||
if (configParseKeyValue(pch + 1, key, value)) {
|
if (configParseKeyValue(pch + 1, key, value)) {
|
||||||
if (!configSetString(config, sectionKey, key, value)) {
|
if (!configSetString(config, sectionKey, key.c_str(), value.c_str())) {
|
||||||
*pch = ']';
|
*pch = ']';
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -683,13 +684,13 @@ static bool configParseLine(Config* config, char* string)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char key[260];
|
std::string key;
|
||||||
char value[260];
|
std::string value;
|
||||||
if (!configParseKeyValue(string, key, value)) {
|
if (!configParseKeyValue(string, key, value)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return configSetString(config, gConfigLastSectionKey, key, value);
|
return configSetString(config, gConfigLastSectionKey, key.c_str(), value.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Splits "key=value" pair from [string] and copy appropriate parts into [key]
|
// Splits "key=value" pair from [string] and copy appropriate parts into [key]
|
||||||
@@ -698,9 +699,9 @@ static bool configParseLine(Config* config, char* string)
|
|||||||
// Both key and value are trimmed.
|
// Both key and value are trimmed.
|
||||||
//
|
//
|
||||||
// 0x42C594
|
// 0x42C594
|
||||||
static bool configParseKeyValue(char* string, char* key, char* value)
|
static bool configParseKeyValue(char* string, std::string& key, std::string& value)
|
||||||
{
|
{
|
||||||
if (string == nullptr || key == nullptr || value == nullptr) {
|
if (string == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -712,14 +713,11 @@ static bool configParseKeyValue(char* string, char* key, char* value)
|
|||||||
|
|
||||||
*pch = '\0';
|
*pch = '\0';
|
||||||
|
|
||||||
strcpy(key, string);
|
key = configGetTrimmedString(string);
|
||||||
strcpy(value, pch + 1);
|
value = configGetTrimmedString(pch + 1);
|
||||||
|
|
||||||
*pch = '=';
|
*pch = '=';
|
||||||
|
|
||||||
configTrimString(key);
|
|
||||||
configTrimString(value);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -791,6 +789,25 @@ static bool configTrimString(char* string)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::string configGetTrimmedString(const char* string)
|
||||||
|
{
|
||||||
|
if (string == nullptr) {
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* start = string;
|
||||||
|
while (isspace(static_cast<unsigned char>(*start))) {
|
||||||
|
start++;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* end = start + strlen(start);
|
||||||
|
while (end > start && isspace(static_cast<unsigned char>(*(end - 1)))) {
|
||||||
|
end--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string(start, end);
|
||||||
|
}
|
||||||
|
|
||||||
// 0x42C718
|
// 0x42C718
|
||||||
bool configGetDouble(Config* config, const char* sectionKey, const char* key, double* valuePtr)
|
bool configGetDouble(Config* config, const char* sectionKey, const char* key, double* valuePtr)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,8 +15,9 @@ void contentConfigInit()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to migrate some settings from sfall.
|
// Try to migrate some settings from legacy config files.
|
||||||
contentConfigTryMigrateFromSfall(kConfigPatchPath);
|
contentConfigTryMigrateFromSfall(kConfigPatchPath);
|
||||||
|
contentConfigTryMigrateFromF2Res(kConfigPatchPath);
|
||||||
|
|
||||||
if (!configInit(&gContentConfig)) {
|
if (!configInit(&gContentConfig)) {
|
||||||
return;
|
return;
|
||||||
@@ -35,4 +36,4 @@ void contentConfigExit()
|
|||||||
configFree(&gContentConfig);
|
configFree(&gContentConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace fallout
|
} // namespace fallout
|
||||||
|
|||||||
+1
-1
@@ -1024,7 +1024,7 @@ int critterGetBodyType(Object* critter)
|
|||||||
return proto->critter.data.bodyType;
|
return proto->critter.data.bodyType;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool critterCanUseWeapon(Object* critter, Object* weapon, int hitMode)
|
bool critterCanUseWeapon(Object* critter, Object* weapon, HitMode hitMode)
|
||||||
{
|
{
|
||||||
if (critter == nullptr || weapon == nullptr || itemGetType(weapon) != ITEM_TYPE_WEAPON) {
|
if (critter == nullptr || weapon == nullptr || itemGetType(weapon) != ITEM_TYPE_WEAPON) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
+2
-1
@@ -1,6 +1,7 @@
|
|||||||
#ifndef CRITTER_H
|
#ifndef CRITTER_H
|
||||||
#define CRITTER_H
|
#define CRITTER_H
|
||||||
|
|
||||||
|
#include "combat_defs.h"
|
||||||
#include "db.h"
|
#include "db.h"
|
||||||
#include "obj_types.h"
|
#include "obj_types.h"
|
||||||
#include "proto_types.h"
|
#include "proto_types.h"
|
||||||
@@ -56,7 +57,7 @@ bool critterIsProne(Object* critter);
|
|||||||
int critterGetBodyType(Object* critter);
|
int critterGetBodyType(Object* critter);
|
||||||
// Checks physical/art capability only. Callers that expose weapon usability
|
// Checks physical/art capability only. Callers that expose weapon usability
|
||||||
// decisions must still call scriptHooks_CanUseWeapon with the final result.
|
// decisions must still call scriptHooks_CanUseWeapon with the final result.
|
||||||
bool critterCanUseWeapon(Object* critter, Object* weapon, int hitMode);
|
bool critterCanUseWeapon(Object* critter, Object* weapon, HitMode hitMode);
|
||||||
int critterBuildGorisFid(Object* critter, int frmId);
|
int critterBuildGorisFid(Object* critter, int frmId);
|
||||||
int gcdLoad(const char* path);
|
int gcdLoad(const char* path);
|
||||||
int protoCritterDataRead(File* stream, CritterProtoData* critterData);
|
int protoCritterDataRead(File* stream, CritterProtoData* critterData);
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ namespace fallout {
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
#define F2_RES_CONFIG_FILE_NAME "f2_res.ini"
|
#define F2_RES_CONFIG_FILE_NAME "f2_res.ini"
|
||||||
|
#define F2_RES_MAIN_MENU_BUTTON_X 30
|
||||||
|
#define F2_RES_MAIN_MENU_BUTTON_Y 19
|
||||||
|
|
||||||
struct F2ResMigrationEntry {
|
struct F2ResMigrationEntry {
|
||||||
const char* legacySection;
|
const char* legacySection;
|
||||||
@@ -29,6 +31,7 @@ namespace {
|
|||||||
static bool gameConfigMigrateMainMenuScaleModeKey(Config* legacyConfig, Config* gameConfig);
|
static bool gameConfigMigrateMainMenuScaleModeKey(Config* legacyConfig, Config* gameConfig);
|
||||||
static bool gameConfigMigrateStringKey(Config* legacyConfig, Config* gameConfig, const F2ResMigrationEntry& entry);
|
static bool gameConfigMigrateStringKey(Config* legacyConfig, Config* gameConfig, const F2ResMigrationEntry& entry);
|
||||||
static bool gameConfigMigrateScaleKey(Config* legacyConfig, Config* gameConfig);
|
static bool gameConfigMigrateScaleKey(Config* legacyConfig, Config* gameConfig);
|
||||||
|
static bool contentConfigMigrateF2ResMainMenuPanelOffsetKey(Config* legacyConfig, Config* contentConfig, const char* legacyKey, const char* targetKey, int baseValue, int defaultValue);
|
||||||
|
|
||||||
static constexpr F2ResMigrationEntry kF2ResMigrationEntries[] = {
|
static constexpr F2ResMigrationEntry kF2ResMigrationEntries[] = {
|
||||||
{ "MAIN", "SCR_WIDTH", GAME_CONFIG_SCREEN_KEY, GAME_CONFIG_RESOLUTION_X_KEY },
|
{ "MAIN", "SCR_WIDTH", GAME_CONFIG_SCREEN_KEY, GAME_CONFIG_RESOLUTION_X_KEY },
|
||||||
@@ -110,6 +113,27 @@ namespace {
|
|||||||
|
|
||||||
return configSetInt(gameConfig, GAME_CONFIG_SCREEN_KEY, GAME_CONFIG_SCALE_KEY, value + 1);
|
return configSetInt(gameConfig, GAME_CONFIG_SCREEN_KEY, GAME_CONFIG_SCALE_KEY, value + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool contentConfigMigrateF2ResMainMenuPanelOffsetKey(Config* legacyConfig, Config* contentConfig, const char* legacyKey, const char* targetKey, int baseValue, int defaultValue)
|
||||||
|
{
|
||||||
|
assert(legacyConfig != nullptr && contentConfig != nullptr);
|
||||||
|
|
||||||
|
if (gameConfigHasKey(contentConfig, CONTENT_CONFIG_MAIN_MENU_SECTION, targetKey)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int value;
|
||||||
|
if (!configGetInt(legacyConfig, "MAINMENU", legacyKey, &value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
value += baseValue;
|
||||||
|
if (value == defaultValue) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return configSetInt(contentConfig, CONTENT_CONFIG_MAIN_MENU_SECTION, targetKey, value);
|
||||||
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
// Migrate settings F2_RES.INI to fallout2.cfg
|
// Migrate settings F2_RES.INI to fallout2.cfg
|
||||||
@@ -301,6 +325,82 @@ static bool contentConfigMigrateFromSfall(Config* sfallConfig, const char* conte
|
|||||||
return migrated;
|
return migrated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool contentConfigEnsureDirectory(const char* contentConfigFilePath)
|
||||||
|
{
|
||||||
|
char drive[COMPAT_MAX_DRIVE];
|
||||||
|
char dirPart[COMPAT_MAX_DIR];
|
||||||
|
char pathWithoutFile[COMPAT_MAX_PATH];
|
||||||
|
compat_splitpath(contentConfigFilePath, drive, dirPart, nullptr, nullptr);
|
||||||
|
compat_makepath(pathWithoutFile, drive, dirPart, nullptr, nullptr);
|
||||||
|
return compat_mkdir_recursive(pathWithoutFile) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool contentConfigMigrateFromF2Res(Config* legacyConfig, const char* contentConfigFilePath)
|
||||||
|
{
|
||||||
|
assert(legacyConfig != nullptr && contentConfigFilePath != nullptr);
|
||||||
|
|
||||||
|
Config migratedConfig;
|
||||||
|
if (!configInit(&migratedConfig)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
configRead(&migratedConfig, contentConfigFilePath, false);
|
||||||
|
|
||||||
|
bool migrated = false;
|
||||||
|
if (contentConfigMigrateF2ResMainMenuPanelOffsetKey(legacyConfig, &migratedConfig, "MENU_BG_OFFSET_X", "main_menu_panel_offset_x", F2_RES_MAIN_MENU_BUTTON_X, 16)) {
|
||||||
|
migrated = true;
|
||||||
|
}
|
||||||
|
if (contentConfigMigrateF2ResMainMenuPanelOffsetKey(legacyConfig, &migratedConfig, "MENU_BG_OFFSET_Y", "main_menu_panel_offset_y", F2_RES_MAIN_MENU_BUTTON_Y, 15)) {
|
||||||
|
migrated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (migrated) {
|
||||||
|
if (contentConfigEnsureDirectory(contentConfigFilePath)) {
|
||||||
|
if (!configWriteEx(&migratedConfig, contentConfigFilePath, CONFIG_RETAIN_ALL)) {
|
||||||
|
debugPrint("Failed to write migrated settings to %s!\n", contentConfigFilePath);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
debugPrint("Failed to create directory for migrated settings at %s!\n", contentConfigFilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
configFree(&migratedConfig);
|
||||||
|
return migrated;
|
||||||
|
}
|
||||||
|
|
||||||
|
void contentConfigTryMigrateFromF2Res(const char* contentConfigPath)
|
||||||
|
{
|
||||||
|
const auto& masterPatches = settings.system.master_patches_path;
|
||||||
|
if (masterPatches.empty()) {
|
||||||
|
debugPrint("Failed to migrate from f2_res.ini: no master_patches is set.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!compat_is_dir(masterPatches.c_str())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char f2ResFilePath[COMPAT_MAX_PATH];
|
||||||
|
char drive[COMPAT_MAX_DRIVE];
|
||||||
|
char dir[COMPAT_MAX_DIR];
|
||||||
|
compat_splitpath(gGameConfigFilePath, drive, dir, nullptr, nullptr);
|
||||||
|
compat_makepath(f2ResFilePath, drive, dir, F2_RES_CONFIG_FILE_NAME, nullptr);
|
||||||
|
|
||||||
|
Config legacyConfig;
|
||||||
|
if (!configInit(&legacyConfig)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configRead(&legacyConfig, f2ResFilePath, false)) {
|
||||||
|
char contentCfgPath[COMPAT_MAX_PATH];
|
||||||
|
snprintf(contentCfgPath, sizeof(contentCfgPath), "%s\\%s", masterPatches.c_str(), contentConfigPath);
|
||||||
|
if (contentConfigMigrateFromF2Res(&legacyConfig, contentCfgPath)) {
|
||||||
|
debugPrint("Migrated settings from f2_res.ini to game.cfg.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
configFree(&legacyConfig);
|
||||||
|
}
|
||||||
|
|
||||||
void contentConfigTryMigrateFromSfall(const char* contentConfigPath)
|
void contentConfigTryMigrateFromSfall(const char* contentConfigPath)
|
||||||
{
|
{
|
||||||
if (!gSfallConfig.isInitialized() || gSfallConfig.entriesLength == 0) {
|
if (!gSfallConfig.isInitialized() || gSfallConfig.entriesLength == 0) {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
namespace fallout {
|
namespace fallout {
|
||||||
|
|
||||||
bool gameConfigMigrateFromF2Res(const char* gameConfigFilePath, Config* gameConfig);
|
bool gameConfigMigrateFromF2Res(const char* gameConfigFilePath, Config* gameConfig);
|
||||||
|
void contentConfigTryMigrateFromF2Res(const char* contentConfigPath);
|
||||||
void contentConfigTryMigrateFromSfall(const char* contentConfigPath);
|
void contentConfigTryMigrateFromSfall(const char* contentConfigPath);
|
||||||
|
|
||||||
} // namespace fallout
|
} // namespace fallout
|
||||||
|
|||||||
+1
-1
@@ -1062,7 +1062,7 @@ void _gmouse_handle_event(int mouseX, int mouseY, int mouseState)
|
|||||||
Object* weapon;
|
Object* weapon;
|
||||||
if (interfaceGetActiveItem(&weapon) != -1) {
|
if (interfaceGetActiveItem(&weapon) != -1) {
|
||||||
if (isInCombat()) {
|
if (isInCombat()) {
|
||||||
int hitMode = interfaceGetCurrentHand()
|
HitMode hitMode = interfaceGetCurrentHand()
|
||||||
? HIT_MODE_RIGHT_WEAPON_PRIMARY
|
? HIT_MODE_RIGHT_WEAPON_PRIMARY
|
||||||
: HIT_MODE_LEFT_WEAPON_PRIMARY;
|
: HIT_MODE_LEFT_WEAPON_PRIMARY;
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1366,7 +1366,7 @@ char* gameSoundBuildInterfaceName(const char* a1)
|
|||||||
|
|
||||||
// sfx_build_weapon_name
|
// sfx_build_weapon_name
|
||||||
// 0x451760
|
// 0x451760
|
||||||
char* sfxBuildWeaponName(int effectType, Object* weapon, int hitMode, Object* target)
|
char* sfxBuildWeaponName(int effectType, Object* weapon, HitMode hitMode, Object* target)
|
||||||
{
|
{
|
||||||
int soundVariant;
|
int soundVariant;
|
||||||
char weaponSoundCode;
|
char weaponSoundCode;
|
||||||
|
|||||||
+2
-1
@@ -1,6 +1,7 @@
|
|||||||
#ifndef GAME_SOUND_H
|
#ifndef GAME_SOUND_H
|
||||||
#define GAME_SOUND_H
|
#define GAME_SOUND_H
|
||||||
|
|
||||||
|
#include "combat_defs.h"
|
||||||
#include "obj_types.h"
|
#include "obj_types.h"
|
||||||
#include "sound.h"
|
#include "sound.h"
|
||||||
|
|
||||||
@@ -102,7 +103,7 @@ int _gsound_compute_relative_volume(Object* obj);
|
|||||||
char* sfxBuildCharName(Object* object, int anim, int weaponAnimationCode);
|
char* sfxBuildCharName(Object* object, int anim, int weaponAnimationCode);
|
||||||
char* gameSoundBuildAmbientSoundEffectName(const char* name);
|
char* gameSoundBuildAmbientSoundEffectName(const char* name);
|
||||||
char* gameSoundBuildInterfaceName(const char* name);
|
char* gameSoundBuildInterfaceName(const char* name);
|
||||||
char* sfxBuildWeaponName(int effectType, Object* weapon, int hitMode, Object* target);
|
char* sfxBuildWeaponName(int effectType, Object* weapon, HitMode hitMode, Object* target);
|
||||||
char* sfxBuildSceneryName(int actionType, int action, const char* name);
|
char* sfxBuildSceneryName(int actionType, int action, const char* name);
|
||||||
char* sfxBuildOpenName(Object* object, int action);
|
char* sfxBuildOpenName(Object* object, int action);
|
||||||
void _gsound_red_butt_press(int btn, int keyCode);
|
void _gsound_red_butt_press(int btn, int keyCode);
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user