summaryrefslogtreecommitdiff |
diff options
author | nsensfel <SpamShield0@noot-noot.org> | 2019-06-05 11:24:52 +0200 |
---|---|---|
committer | nsensfel <SpamShield0@noot-noot.org> | 2019-06-05 11:24:52 +0200 |
commit | 1afb69a11b0e291c7bfd6c24bdd8e55742e61889 (patch) | |
tree | 21c09b15ddcc3272bbb8fa8d41676ffa56ca3130 /src/battle/mechanic | |
parent | 1aec9784102855c4bf2e5d2ad9a945166aed2051 (diff) |
[Broken] Changing how actions are handled...
Diffstat (limited to 'src/battle/mechanic')
-rw-r--r-- | src/battle/mechanic/btl_attack.erl | 554 | ||||
-rw-r--r-- | src/battle/mechanic/btl_turn_actions_management.erl | 50 |
2 files changed, 593 insertions, 11 deletions
diff --git a/src/battle/mechanic/btl_attack.erl b/src/battle/mechanic/btl_attack.erl new file mode 100644 index 0000000..cbc1baa --- /dev/null +++ b/src/battle/mechanic/btl_attack.erl @@ -0,0 +1,554 @@ +-module(btl_attack). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export +( + [ + ] +). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec roll_precision + ( + shr_statistics:type(), + shr_statistics:type(), + integer() + ) + -> {precision(), integer(), integer()}. +roll_precision +( + AttackerStatistics, + DefenderStatistics, + DefenderLuck +) -> + DefenderDodges = shr_statistics:get_dodges(DefenderStatistics), + AttackerAccuracy = shr_statistics:get_accuracy(AttackerStatistics), + MissChance = max(0, (DefenderDodges - AttackerAccuracy)), + + {Roll, _IsSuccess, PositiveModifier, NegativeModifier} = + shr_roll:percentage_with_luck(MissChance, DefenderLuck), + + { + case Roll of + X when (X =< MissChance) -> misses; + X when (X =< (MissChance * 2)) -> grazes; + _ -> hits + end, + PositiveModifier, + NegativeModifier + }. + +-spec roll_critical_hit + ( + shr_statistics:type(), + integer() + ) + -> {boolean(), integer(), integer()}. +roll_critical_hit (AttackerStatistics, AttackerLuck) -> + CriticalHitChance = shr_statistics:get_critical_hits(AttackerStatistics), + {_Roll, IsSuccess, PositiveModifier, NegativeModifier} = + shr_roll:percentage_with_luck(CriticalHitChance, AttackerLuck), + + {IsSuccess, PositiveModifier, NegativeModifier}. + +-spec roll_parry + ( + shr_statistics:type(), + integer() + ) + -> {boolean(), integer(), integer()}. +roll_parry (DefenderStatistics, DefenderLuck) -> + DefenderParryChance = shr_statistics:get_parries(DefenderStatistics), + {_Roll, IsSuccess, PositiveModifier, NegativeModifier} = + shr_roll:percentage_with_luck(DefenderParryChance, DefenderLuck), + + {IsSuccess, PositiveModifier, NegativeModifier}. + +-spec get_damage + ( + precision(), + boolean(), + float(), + shr_omnimods:type(), + shr_omnimods:type() + ) + -> non_neg_integer(). +get_damage +( + Precision, + IsCritical, + StartingDamageMultiplier, + AttackerOmnimods, + DefenderOmnimods +) -> + ActualDamageMultiplier = + ( + StartingDamageMultiplier + * + ( + case Precision of + misses -> 0; + grazes -> 0.5; + hits -> 1 + end + ) + * + ( + case IsCritical of + true -> 2; + _ -> 1 + end + ) + ), + + ActualDamage = + shr_omnimods:get_attack_damage + ( + ActualDamageMultiplier, + AttackerOmnimods, + DefenderOmnimods + ), + + ActualDamage. + +-spec effect_of_attack + ( + order(), + shr_character:type(), + shr_character:type(), + boolean(), + integer(), + integer() + ) + -> type(). +effect_of_attack +( + Order, + Attacker, + Defender, + CanParry, + AttackerLuck, + DefenderLuck +) -> + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %%%% Roll parry to see if the roles have to be swapped. %%%%%%%%%%%%%%%%%%%%% + + DefenderStats = shr_character:get_statistics(Defender), + {ParryIsSuccessful, ParryPositiveLuckMod, ParryNegativeLuckMod} = + case CanParry of + true -> roll_parry(DefenderStats, DefenderLuck); + false -> {false, 0, 0} + end, + + { + ActualAttacker, + ActualDefender, + ActualAttackerLuck, + ActualDefenderLuck + } = + case ParryIsSuccessful of + true -> {Defender, Attacker, DefenderLuck, AttackerLuck}; + false -> {Attacker, Defender, AttackerLuck, DefenderLuck} + end, + + ActualAttackerStats = shr_character:get_statistics(ActualAttacker), + ActualAttackerOmnimods = shr_character:get_omnimods(ActualAttacker), + ActualDefenderStats = shr_character:get_statistics(ActualDefender), + ActualDefenderOmnimods = shr_character:get_omnimods(ActualDefender), + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + {Precision, PrecisionPositiveLuckMod, PrecisionNegativeLuckMod} = + roll_precision + ( + ActualAttackerStats, + ActualDefenderStats, + ActualDefenderLuck + ), + + + {IsCritical, CriticalPositiveLuckMod, CriticalNegativeLuckMod} = + roll_critical_hit(ActualAttackerStats, ActualAttackerLuck), + + ActualAttackerDamageModifier = + shr_statistics:get_damage_modifier(ActualAttackerStats), + + Damage = + get_damage + ( + Precision, + IsCritical, + ActualAttackerDamageModifier, + ActualAttackerOmnimods, + ActualDefenderOmnimods + ), + + {FinalAttackerLuckMod, FinalDefenderLuckMod} = + case {ParryIsSuccessful, Precision} of + {true, misses} -> + { + ( + % Attacker wasn't the one parrying + ParryNegativeLuckMod + % Attacker was the one evading + + PrecisionPositiveLuckMod + % miss -> no critical hit luck modifier + ), + ( + % Defender was the one parrying + ParryPositiveLuckMod + % Defender wasn't the one evading + + PrecisionNegativeLuckMod + % miss -> no critical hit luck modifier + ) + }; + + {true, _} -> + { + ( + % Attacker wasn't the one parrying + ParryNegativeLuckMod + % Attacker was the one evading + + PrecisionPositiveLuckMod + % Attacker wasn't the one doing a critical + + CriticalNegativeLuckMod + ), + ( + % Defender was the one parrying + ParryPositiveLuckMod + % Defender wasn't the one evading + + PrecisionNegativeLuckMod + % Defender was the one doing a critical + + CriticalPositiveLuckMod + ) + }; + + {false, misses} -> + { + ( + % Attacker wasn't the one parrying + ParryNegativeLuckMod + % Defender was the one evading + + PrecisionNegativeLuckMod + % miss -> no critical hit luck modifier + ), + ( + % Defender was the one parrying + ParryPositiveLuckMod + % Defender was the one evading + + PrecisionPositiveLuckMod + % miss -> no critical hit luck modifier + ) + }; + + {false, _} -> + { + ( + % Attacker wasn't the one parrying + ParryNegativeLuckMod + % Attacker wasn't the one evading + + PrecisionNegativeLuckMod + % Attacker was the one doing a critical + + CriticalPositiveLuckMod + ), + ( + % Defender was the one parrying + ParryPositiveLuckMod + % Defender was the one evading + + PrecisionPositiveLuckMod + % Defender wasn't the one doing a critical + + CriticalNegativeLuckMod + ) + } + end, + + #attack + { + order = Order, + precision = Precision, + is_critical = IsCritical, + is_parry = ParryIsSuccessful, + damage = Damage, + attacker_luck_mod = FinalAttackerLuckMod, + defender_luck_mod = FinalDefenderLuckMod + }. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec get_description_of + ( + step(), + shr_character:type(), + shr_character:type(), + integer(), + integer() + ) + -> maybe_type(). +get_description_of +( + {first, CanParry}, + Attacker, + Defender, + AttackerLuck, + DefenderLuck +) -> + effect_of_attack + ( + first, + Attacker, + Defender, + CanParry, + AttackerLuck, + DefenderLuck + ); +get_description_of +( + {second, CanParry}, + Attacker, + Defender, + AttackerLuck, + DefenderLuck +) -> + AttackerStats = shr_character:get_statistics(Attacker), + AttackerDoubleAttackChance = + shr_statistics:get_double_hits(AttackerStats), + {_Roll, IsSuccessful, PositiveModifier, NegativeModifier} = + shr_roll:percentage_with_luck(AttackerDoubleAttackChance, AttackerLuck), + + NewAttackerLuck = (AttackerLuck + PositiveModifier), + NewDefenderLuck = (DefenderLuck + NegativeModifier), + + case IsSuccessful of + true -> + Result = + effect_of_attack + ( + second, + Attacker, + Defender, + CanParry, + NewAttackerLuck, + NewDefenderLuck + ), + + Result#attack + { + attacker_luck_mod = + (Result#attack.attacker_luck_mod + PositiveModifier), + defender_luck_mod = + (Result#attack.defender_luck_mod + NegativeModifier) + }; + + _ -> {nothing, PositiveModifier, NegativeModifier} + end; +get_description_of +( + {counter, CanParry}, + Attacker, + Defender, + AttackerLuck, + DefenderLuck +) -> + effect_of_attack + ( + counter, + Defender, + Attacker, + CanParry, + DefenderLuck, + AttackerLuck + ). + +-spec apply_to_healths_and_lucks + ( + maybe_type(), + non_neg_integer(), + integer(), + non_neg_integer(), + integer() + ) + -> + { + maybe_type(), + non_neg_integer(), + integer(), + non_neg_integer(), + integer() + }. +apply_to_healths_and_lucks +( + _Attack, + AttackerHealth, + AttackerLuck, + DefenderHealth, + DefenderLuck +) +when +( + (AttackerHealth =< 0) + or (DefenderHealth =< 0) +) -> + { + {nothing, 0, 0}, + AttackerHealth, + AttackerLuck, + DefenderHealth, + DefenderLuck + }; +apply_to_healths_and_lucks +( + {nothing, AttackerLuckMod, DefenderLuckMod}, + AttackerHealth, + AttackerLuck, + DefenderHealth, + DefenderLuck +) -> + { + {nothing, AttackerLuckMod, DefenderLuckMod}, + AttackerHealth, + (AttackerLuck + AttackerLuckMod), + DefenderHealth, + (DefenderLuck + DefenderLuckMod) + }; +apply_to_healths_and_lucks +( + Attack, + AttackerHealth, + AttackerLuck, + DefenderHealth, + DefenderLuck +) +when +( + ( + (not Attack#attack.is_parry) + and ((Attack#attack.order == first) or (Attack#attack.order == second)) + ) + or + ( + Attack#attack.is_parry + and (Attack#attack.order == counter) + ) +) -> + Damage = Attack#attack.damage, + + { + Attack, + AttackerHealth, + (AttackerLuck + Attack#attack.attacker_luck_mod), + (DefenderHealth - Damage), + (DefenderLuck + Attack#attack.defender_luck_mod) + }; +apply_to_healths_and_lucks +( + Attack, + AttackerHealth, + AttackerLuck, + DefenderHealth, + DefenderLuck +) +when +( + ( + (not Attack#attack.is_parry) + and (Attack#attack.order == counter) + ) + or + ( + Attack#attack.is_parry + and ((Attack#attack.order == first) or (Attack#attack.order == second)) + ) +) -> + Damage = Attack#attack.damage, + + { + Attack, + (AttackerHealth - Damage), + (AttackerLuck + Attack#attack.attacker_luck_mod), + DefenderHealth, + (DefenderLuck + Attack#attack.defender_luck_mod) + }. + +-spec get_sequence + ( + non_neg_integer(), + shr_weapon:type(), + shr_weapon:type() + ) + -> list(step()). +get_sequence (AttackRange, AttackerWeapon, DefenderWeapon) -> + AttackerDefenseRange = shr_weapon:get_minimum_range(AttackerWeapon), + AttackerAttackRange = shr_weapon:get_maximum_range(AttackerWeapon), + DefenderDefenseRange = shr_weapon:get_minimum_range(DefenderWeapon), + DefenderAttackRange = shr_weapon:get_maximum_range(DefenderWeapon), + + AttackerCanAttack = (AttackRange =< AttackerAttackRange), + AttackerCanDefend = + (AttackerCanAttack and (AttackRange > AttackerDefenseRange)), + + true = (AttackerCanAttack == true), + + DefenderCanAttack = (AttackRange =< DefenderAttackRange), + DefenderCanDefend = + (DefenderCanAttack and (AttackRange > DefenderDefenseRange)), + + First = {first, DefenderCanDefend}, + Second = {second, DefenderCanDefend}, + Counter = {counter, AttackerCanDefend}, + + case DefenderCanDefend of + true -> [First, Counter, Second]; + _ -> [First, Second] + end. + +-spec standard + ( + non_neg_integer(), + btl_character:type(), + btl_player:type(), + btl_character:type() + btl_player:type() + ) + -> + { + % Attack Descriptions, + % Updated Attacker + % Attacker Ataxia Update + % Updated Defender + % Defender Ataxia Update + } + +-spec attack_of_opportunity + ( + btl_character:type(), + btl_player:type(), + btl_character:type() + btl_player:type(), + ) + -> + { + % Attack Descriptions, + % Updated Attacker + % Attacker Ataxia Update + % Updated Attacking Player + % Attacking Player Ataxia Update + % Updated Defender + % Defender Ataxia Update + % Updated Defending Player + % Attacking Player Ataxia Update + } + +attack_of_opportunity () -> + [ + {first, false}, + {second, false} + ]. diff --git a/src/battle/mechanic/btl_turn_actions_management.erl b/src/battle/mechanic/btl_turn_actions_management.erl index eefe812..0981ab4 100644 --- a/src/battle/mechanic/btl_turn_actions_management.erl +++ b/src/battle/mechanic/btl_turn_actions_management.erl @@ -37,15 +37,6 @@ deactivate_character (Update) -> S1Update. --spec main_character_is_alive - ( - btl_character_turn_update:type() - ) - -> {boolean(), btl_character_turn_update:type()}. -main_character_is_alive (Update) -> - {S0Update, MainCharacter} = btl_character_turn_update:get_character(Update), - {btl_character:get_is_alive(MainCharacter), S0Update}. - -spec handle_actions ( list(btl_action:type()), @@ -54,8 +45,45 @@ main_character_is_alive (Update) -> -> btl_character_turn_update:type(). handle_actions ([], Update) -> Update; handle_actions ([BattleAction|FutureBattleActions], Update) -> - {MainCharacterIsAlive, S0Update} = main_character_is_alive(Update), - + case btl_action:get_actor_index(BattleAction) of + -1 -> handle_actions(FutureBattleActions, S0Update); + CharacterIX -> + S0Battle = btl_character_turn_update:get_battle(S0Update), + {Character, S1Battle} = + btl_battle:get_resolved_character(CharacterIX, S0Battle), + + S1Update = btl_character_turn_update:set_battle(S1Battle, S0Update), + + case btl_character:is_alive(Character) of + false -> handle_actions(FutureBattleActions, S1Update); + true -> + ActionResult = + case btl_action:get_category(BattleAction) of + move -> + btl_event_move:handle + ( + BattleAction, + Character, + S1Update + ); + + attack -> + case + btl_event_attack:handle + ( + BattleAction, + Character, + S1Update + ); + + attack_of_opportunity -> + btl_event_attack_of_opportunity:handle + ( + BattleAction, + Character, + S1Update + ); + end. ActionResult = case {MainCharacterIsAlive, btl_action:get_category(BattleAction)} of {false, _} -> {ok, S0Update}; |