Improve some combat functions readability

This commit is contained in:
Alexander Batalov 2022-09-23 14:01:39 +03:00
parent cb9c72d1db
commit 3168c2ec09
3 changed files with 79 additions and 81 deletions

View File

@ -85,7 +85,7 @@ typedef struct DamageCalculationContext {
int combatDifficultyDamageModifier; int combatDifficultyDamageModifier;
} DamageCalculationContext; } DamageCalculationContext;
static bool _combat_safety_invalidate_weapon_func(Object* critter, Object* weapon, int hitMode, Object* a4, int* a5, Object* a6); static bool _combat_safety_invalidate_weapon_func(Object* attacker, Object* weapon, int 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);
@ -103,8 +103,8 @@ static void _combat_set_move_all();
static int _combat_turn(Object* a1, bool a2); static int _combat_turn(Object* a1, bool a2);
static bool _combat_should_end(); static bool _combat_should_end();
static bool _check_ranged_miss(Attack* attack); static bool _check_ranged_miss(Attack* attack);
static int _shoot_along_path(Attack* attack, int a2, int a3, int anim); static int _shoot_along_path(Attack* attack, int endTile, int rounds, int anim);
static int _compute_spray(Attack* attack, int accuracy, int* a3, int* a4, int anim); static int _compute_spray(Attack* attack, int accuracy, int* roundsHitMainTargetPtr, int* roundsSpentPtr, int anim);
static int attackComputeEnhancedKnockout(Attack* attack); static int attackComputeEnhancedKnockout(Attack* attack);
static int attackCompute(Attack* attack); static int attackCompute(Attack* attack);
static int attackComputeCriticalHit(Attack* a1); static int attackComputeCriticalHit(Attack* a1);
@ -2247,39 +2247,39 @@ int combatSave(File* stream)
} }
// 0x4213E8 // 0x4213E8
bool _combat_safety_invalidate_weapon(Object* a1, Object* a2, int hitMode, Object* a4, int* a5) bool _combat_safety_invalidate_weapon(Object* attacker, Object* weapon, int hitMode, Object* defender, int* safeDistancePtr)
{ {
return _combat_safety_invalidate_weapon_func(a1, a2, hitMode, a4, a5, NULL); return _combat_safety_invalidate_weapon_func(attacker, weapon, hitMode, defender, safeDistancePtr, NULL);
} }
// 0x4213FC // 0x4213FC
static bool _combat_safety_invalidate_weapon_func(Object* critter, Object* weapon, int hitMode, Object* a4, int* a5, Object* a6) static bool _combat_safety_invalidate_weapon_func(Object* attacker, Object* weapon, int hitMode, Object* defender, int* safeDistancePtr, Object* attackerFriend)
{ {
if (a5 != NULL) { if (safeDistancePtr != NULL) {
*a5 = 0; *safeDistancePtr = 0;
} }
if (critter->pid == PROTO_ID_0x10001E0) { if (attacker->pid == PROTO_ID_0x10001E0) {
return false; return false;
} }
int intelligence = critterGetStat(critter, STAT_INTELLIGENCE); int intelligence = critterGetStat(attacker, STAT_INTELLIGENCE);
int team = critter->data.critter.combat.team; int team = attacker->data.critter.combat.team;
int v41 = weaponGetDamageRadius(weapon, hitMode); int damageRadius = weaponGetDamageRadius(weapon, hitMode);
int maxDamage; int maxDamage;
weaponGetDamageMinMax(weapon, NULL, &maxDamage); weaponGetDamageMinMax(weapon, NULL, &maxDamage);
int damageType = weaponGetDamageType(critter, weapon); int damageType = weaponGetDamageType(attacker, weapon);
if (v41 > 0) { if (damageRadius > 0) {
if (intelligence < 5) { if (intelligence < 5) {
v41 -= 5 - intelligence; damageRadius -= 5 - intelligence;
if (v41 < 0) { if (damageRadius < 0) {
v41 = 0; damageRadius = 0;
} }
} }
if (a6 != NULL) { if (attackerFriend != NULL) {
if (objectGetDistanceBetween(a4, a6) < v41) { if (objectGetDistanceBetween(defender, attackerFriend) < damageRadius) {
debugPrint("Friendly was in the way!"); debugPrint("Friendly was in the way!");
return true; return true;
} }
@ -2288,11 +2288,11 @@ static bool _combat_safety_invalidate_weapon_func(Object* critter, Object* weapo
for (int index = 0; index < _list_total; index++) { for (int index = 0; index < _list_total; index++) {
Object* candidate = _combat_list[index]; Object* candidate = _combat_list[index];
if (candidate->data.critter.combat.team == team if (candidate->data.critter.combat.team == team
&& candidate != critter && candidate != attacker
&& candidate != a4 && candidate != defender
&& !critterIsDead(candidate)) { && !critterIsDead(candidate)) {
int v14 = objectGetDistanceBetween(a4, candidate); int v14 = objectGetDistanceBetween(defender, candidate);
if (v14 < v41 && candidate != candidate->data.critter.combat.whoHitMe) { if (v14 < damageRadius && candidate != candidate->data.critter.combat.whoHitMe) {
int damageThreshold = critterGetStat(candidate, STAT_DAMAGE_THRESHOLD + damageType); int damageThreshold = critterGetStat(candidate, STAT_DAMAGE_THRESHOLD + damageType);
int damageResistance = critterGetStat(candidate, STAT_DAMAGE_RESISTANCE + damageType); int damageResistance = critterGetStat(candidate, STAT_DAMAGE_RESISTANCE + damageType);
if (damageResistance * (maxDamage - damageThreshold) / 100 > 0) { if (damageResistance * (maxDamage - damageThreshold) / 100 > 0) {
@ -2302,11 +2302,9 @@ static bool _combat_safety_invalidate_weapon_func(Object* critter, Object* weapo
} }
} }
int v17 = objectGetDistanceBetween(a4, critter); if (objectGetDistanceBetween(defender, attacker) <= damageRadius) {
if (v17 <= v41) { if (safeDistancePtr != NULL) {
if (a5 != NULL) { *safeDistancePtr = damageRadius - objectGetDistanceBetween(defender, attacker) + 1;
int v18 = objectGetDistanceBetween(a4, critter);
*a5 = v41 - v18 + 1;
return false; return false;
} }
@ -2316,22 +2314,22 @@ static bool _combat_safety_invalidate_weapon_func(Object* critter, Object* weapo
return false; return false;
} }
int v19 = weaponGetAnimationForHitMode(weapon, hitMode); int anim = weaponGetAnimationForHitMode(weapon, hitMode);
if (v19 != ANIM_FIRE_BURST && v19 != ANIM_FIRE_CONTINUOUS) { if (anim != ANIM_FIRE_BURST && anim != ANIM_FIRE_CONTINUOUS) {
return false; return false;
} }
Attack attack; Attack attack;
attackInit(&attack, critter, a4, hitMode, HIT_LOCATION_TORSO); attackInit(&attack, attacker, defender, hitMode, HIT_LOCATION_TORSO);
int accuracy = attackDetermineToHit(critter, critter->tile, a4, HIT_LOCATION_TORSO, hitMode, true); int accuracy = attackDetermineToHit(attacker, attacker->tile, defender, HIT_LOCATION_TORSO, hitMode, true);
int v33; int roundsHitMainTarget;
int a4a; int roundsSpent;
_compute_spray(&attack, accuracy, &v33, &a4a, v19); _compute_spray(&attack, accuracy, &roundsHitMainTarget, &roundsSpent, anim);
if (a6 != NULL) { if (attackerFriend != NULL) {
for (int index = 0; index < attack.extrasLength; index++) { for (int index = 0; index < attack.extrasLength; index++) {
if (attack.extras[index] == a6) { if (attack.extras[index] == attackerFriend) {
debugPrint("Friendly was in the way!"); debugPrint("Friendly was in the way!");
return true; return true;
} }
@ -2341,8 +2339,8 @@ static bool _combat_safety_invalidate_weapon_func(Object* critter, Object* weapo
for (int index = 0; index < attack.extrasLength; index++) { for (int index = 0; index < attack.extrasLength; index++) {
Object* candidate = attack.extras[index]; Object* candidate = attack.extras[index];
if (candidate->data.critter.combat.team == team if (candidate->data.critter.combat.team == team
&& candidate != critter && candidate != attacker
&& candidate != a4 && candidate != defender
&& !critterIsDead(candidate) && !critterIsDead(candidate)
&& candidate != candidate->data.critter.combat.whoHitMe) { && candidate != candidate->data.critter.combat.whoHitMe) {
int damageThreshold = critterGetStat(candidate, STAT_DAMAGE_THRESHOLD + damageType); int damageThreshold = critterGetStat(candidate, STAT_DAMAGE_THRESHOLD + damageType);
@ -2357,9 +2355,9 @@ static bool _combat_safety_invalidate_weapon_func(Object* critter, Object* weapo
} }
// 0x4217BC // 0x4217BC
bool _combatTestIncidentalHit(Object* a1, Object* a2, Object* a3, Object* a4) bool _combatTestIncidentalHit(Object* attacker, Object* defender, Object* attackerFriend, Object* weapon)
{ {
return _combat_safety_invalidate_weapon_func(a1, a4, HIT_MODE_RIGHT_WEAPON_PRIMARY, a2, NULL, a3); return _combat_safety_invalidate_weapon_func(attacker, weapon, HIT_MODE_RIGHT_WEAPON_PRIMARY, defender, NULL, attackerFriend);
} }
// 0x4217D4 // 0x4217D4
@ -3604,39 +3602,39 @@ static bool _check_ranged_miss(Attack* attack)
} }
// 0x423284 // 0x423284
static int _shoot_along_path(Attack* attack, int a2, int a3, int anim) static int _shoot_along_path(Attack* attack, int endTile, int rounds, int anim)
{ {
int v5 = a3; int remainingRounds = rounds;
int v17 = 0; int roundsHitMainTarget = 0;
int v7 = attack->attacker->tile; int currentTile = attack->attacker->tile;
Object* critter = attack->attacker; Object* critter = attack->attacker;
while (critter != NULL) { while (critter != NULL) {
if ((v5 <= 0 && anim != ANIM_FIRE_CONTINUOUS) || v7 == a2 || attack->extrasLength >= 6) { if ((remainingRounds <= 0 && anim != ANIM_FIRE_CONTINUOUS) || currentTile == endTile || attack->extrasLength >= 6) {
break; break;
} }
_make_straight_path_func(attack->attacker, v7, a2, NULL, &critter, 32, _obj_shoot_blocking_at); _make_straight_path_func(attack->attacker, currentTile, endTile, NULL, &critter, 32, _obj_shoot_blocking_at);
if (critter != NULL) { if (critter != NULL) {
if (FID_TYPE(critter->fid) != OBJ_TYPE_CRITTER) { if (FID_TYPE(critter->fid) != OBJ_TYPE_CRITTER) {
break; break;
} }
int v8 = attackDetermineToHit(attack->attacker, attack->attacker->tile, critter, HIT_LOCATION_TORSO, attack->hitMode, true); int accuracy = attackDetermineToHit(attack->attacker, attack->attacker->tile, critter, HIT_LOCATION_TORSO, attack->hitMode, true);
if (anim == ANIM_FIRE_CONTINUOUS) { if (anim == ANIM_FIRE_CONTINUOUS) {
v5 = 1; remainingRounds = 1;
} }
int a2a = 0; int roundsHit = 0;
while (randomBetween(1, 100) <= v8 && v5 > 0) { while (randomBetween(1, 100) <= accuracy && remainingRounds > 0) {
v5 -= 1; remainingRounds -= 1;
a2a += 1; roundsHit += 1;
} }
if (a2a != 0) { if (roundsHit != 0) {
if (critter == attack->defender) { if (critter == attack->defender) {
v17 += a2a; roundsHitMainTarget += roundsHit;
} else { } else {
int index; int index;
for (index = 0; index < attack->extrasLength; index += 1) { for (index = 0; index < attack->extrasLength; index += 1) {
@ -3649,7 +3647,7 @@ static int _shoot_along_path(Attack* attack, int a2, int a3, int anim)
attack->extras[index] = critter; attack->extras[index] = critter;
attackInit(&_shoot_ctd, attack->attacker, critter, attack->hitMode, HIT_LOCATION_TORSO); attackInit(&_shoot_ctd, attack->attacker, critter, attack->hitMode, HIT_LOCATION_TORSO);
_shoot_ctd.attackerFlags |= DAM_HIT; _shoot_ctd.attackerFlags |= DAM_HIT;
attackComputeDamage(&_shoot_ctd, a2a, 2); attackComputeDamage(&_shoot_ctd, roundsHit, 2);
if (index == attack->extrasLength) { if (index == attack->extrasLength) {
attack->extrasDamage[index] = _shoot_ctd.defenderDamage; attack->extrasDamage[index] = _shoot_ctd.defenderDamage;
@ -3666,21 +3664,21 @@ static int _shoot_along_path(Attack* attack, int a2, int a3, int anim)
} }
} }
v7 = critter->tile; currentTile = critter->tile;
} }
} }
if (anim == ANIM_FIRE_CONTINUOUS) { if (anim == ANIM_FIRE_CONTINUOUS) {
v17 = 0; roundsHitMainTarget = 0;
} }
return v17; return roundsHitMainTarget;
} }
// 0x423488 // 0x423488
static int _compute_spray(Attack* attack, int accuracy, int* a3, int* a4, int anim) static int _compute_spray(Attack* attack, int accuracy, int* roundsHitMainTargetPtr, int* roundsSpentPtr, int anim)
{ {
*a3 = 0; *roundsHitMainTargetPtr = 0;
int ammoQuantity = ammoGetQuantity(attack->weapon); int ammoQuantity = ammoGetQuantity(attack->weapon);
int burstRounds = weaponGetBurstRounds(attack->weapon); int burstRounds = weaponGetBurstRounds(attack->weapon);
@ -3688,7 +3686,7 @@ static int _compute_spray(Attack* attack, int accuracy, int* a3, int* a4, int an
ammoQuantity = burstRounds; ammoQuantity = burstRounds;
} }
*a4 = ammoQuantity; *roundsSpentPtr = ammoQuantity;
int criticalChance = critterGetStat(attack->attacker, STAT_CRITICAL_CHANCE); int criticalChance = critterGetStat(attack->attacker, STAT_CRITICAL_CHANCE);
int roll = randomRoll(accuracy, criticalChance, NULL); int roll = randomRoll(accuracy, criticalChance, NULL);
@ -3732,17 +3730,17 @@ static int _compute_spray(Attack* attack, int accuracy, int* a3, int* a4, int an
for (int index = 0; index < mainTargetRounds; index += 1) { for (int index = 0; index < mainTargetRounds; index += 1) {
if (randomRoll(accuracy, 0, NULL) >= ROLL_SUCCESS) { if (randomRoll(accuracy, 0, NULL) >= ROLL_SUCCESS) {
*a3 += 1; *roundsHitMainTargetPtr += 1;
} }
} }
if (*a3 == 0 && _check_ranged_miss(attack)) { if (*roundsHitMainTargetPtr == 0 && _check_ranged_miss(attack)) {
*a3 = 1; *roundsHitMainTargetPtr = 1;
} }
int range = weaponGetRange(attack->attacker, attack->hitMode); int range = weaponGetRange(attack->attacker, attack->hitMode);
int mainTargetEndTile = _tile_num_beyond(attack->attacker->tile, attack->defender->tile, range); int mainTargetEndTile = _tile_num_beyond(attack->attacker->tile, attack->defender->tile, range);
*a3 += _shoot_along_path(attack, mainTargetEndTile, centerRounds - *a3, anim); *roundsHitMainTargetPtr += _shoot_along_path(attack, mainTargetEndTile, centerRounds - *roundsHitMainTargetPtr, anim);
int centerTile; int centerTile;
if (objectGetDistanceBetween(attack->attacker, attack->defender) <= 3) { if (objectGetDistanceBetween(attack->attacker, attack->defender) <= 3) {
@ -3755,14 +3753,14 @@ static int _compute_spray(Attack* attack, int accuracy, int* a3, int* a4, int an
int leftTile = tileGetTileInDirection(centerTile, (rotation + 1) % ROTATION_COUNT, 1); int leftTile = tileGetTileInDirection(centerTile, (rotation + 1) % ROTATION_COUNT, 1);
int leftEndTile = _tile_num_beyond(attack->attacker->tile, leftTile, range); int leftEndTile = _tile_num_beyond(attack->attacker->tile, leftTile, range);
*a3 += _shoot_along_path(attack, leftEndTile, leftRounds, anim); *roundsHitMainTargetPtr += _shoot_along_path(attack, leftEndTile, leftRounds, anim);
int rightTile = tileGetTileInDirection(centerTile, (rotation + 5) % ROTATION_COUNT, 1); int rightTile = tileGetTileInDirection(centerTile, (rotation + 5) % ROTATION_COUNT, 1);
int rightEndTile = _tile_num_beyond(attack->attacker->tile, rightTile, range); int rightEndTile = _tile_num_beyond(attack->attacker->tile, rightTile, range);
*a3 += _shoot_along_path(attack, rightEndTile, rightRounds, anim); *roundsHitMainTargetPtr += _shoot_along_path(attack, rightEndTile, rightRounds, anim);
if (roll != ROLL_FAILURE || (*a3 <= 0 && attack->extrasLength <= 0)) { if (roll != ROLL_FAILURE || (*roundsHitMainTargetPtr <= 0 && attack->extrasLength <= 0)) {
if (roll >= ROLL_SUCCESS && *a3 == 0 && attack->extrasLength == 0) { if (roll >= ROLL_SUCCESS && *roundsHitMainTargetPtr == 0 && attack->extrasLength == 0) {
roll = ROLL_FAILURE; roll = ROLL_FAILURE;
} }
} else { } else {

View File

@ -17,8 +17,8 @@ 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* a1, Object* a2, int hitMode, Object* a4, int* a5); bool _combat_safety_invalidate_weapon(Object* attacker, Object* weapon, int hitMode, Object* defender, int* safeDistancePtr);
bool _combatTestIncidentalHit(Object* a1, Object* a2, Object* a3, Object* a4); 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);
Object* aiInfoGetFriendlyDead(Object* obj); Object* aiInfoGetFriendlyDead(Object* obj);

View File

@ -120,7 +120,7 @@ static int _ai_move_steps_closer(Object* a1, Object* a2, int actionPoints, int a
static int _ai_move_closer(Object* a1, Object* a2, int a3); static int _ai_move_closer(Object* a1, Object* a2, int a3);
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* a1, Object* a2, Object* a3, 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, int* hitMode, Object** weapon, Object* a4);
static int _ai_called_shot(Object* a1, Object* a2, int a3); static int _ai_called_shot(Object* a1, Object* a2, int a3);
static int _ai_attack(Object* a1, Object* a2, int a3); static int _ai_attack(Object* a1, Object* a2, int a3);
@ -2421,27 +2421,27 @@ static int _cai_retargetTileFromFriendlyFireSubFunc(AiRetargetData* aiRetargetDa
} }
// 0x42A518 // 0x42A518
static bool _cai_attackWouldIntersect(Object* a1, Object* a2, Object* a3, 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; int hitMode = HIT_MODE_RIGHT_WEAPON_PRIMARY;
bool aiming = false; bool aiming = false;
if (a1 == gDude) { if (attacker == gDude) {
interfaceGetCurrentHitMode(&hitMode, &aiming); interfaceGetCurrentHitMode(&hitMode, &aiming);
} }
Object* v8 = critterGetWeaponForHitMode(a1, hitMode); Object* weapon = critterGetWeaponForHitMode(attacker, hitMode);
if (v8 == NULL) { if (weapon == NULL) {
return false; return false;
} }
if (weaponGetRange(a1, hitMode) < 1) { if (weaponGetRange(attacker, hitMode) < 1) {
return false; return false;
} }
Object* object = NULL; Object* object = NULL;
_make_straight_path_func(a1, a1->tile, a2->tile, NULL, &object, 32, _obj_shoot_blocking_at); _make_straight_path_func(attacker, attacker->tile, defender->tile, NULL, &object, 32, _obj_shoot_blocking_at);
if (object != a3) { if (object != attackerFriend) {
if (!_combatTestIncidentalHit(a1, a2, a3, v8)) { if (!_combatTestIncidentalHit(attacker, defender, attackerFriend, weapon)) {
return false; return false;
} }
} }