summaryrefslogtreecommitdiff |
diff options
author | nsensfel <SpamShield0@noot-noot.org> | 2019-01-28 19:03:19 +0100 |
---|---|---|
committer | nsensfel <SpamShield0@noot-noot.org> | 2019-01-28 19:03:19 +0100 |
commit | dc988b5aa72204954b2034615d644c703b35d294 (patch) | |
tree | 8605e35192f542b960270f9ee35b879584fda8a8 | |
parent | 04212005d8f4e078548738256add0f6c12138946 (diff) |
Adding the luck mechanic...
-rw-r--r-- | src/battle/mechanic/turn_action/btl_turn_actions_attack.erl | 47 | ||||
-rw-r--r-- | src/battle/struct/btl_attack.erl | 225 | ||||
-rw-r--r-- | src/battle/struct/btl_player.erl | 15 | ||||
-rw-r--r-- | src/shared/shr_roll.erl | 77 |
4 files changed, 312 insertions, 52 deletions
diff --git a/src/battle/mechanic/turn_action/btl_turn_actions_attack.erl b/src/battle/mechanic/turn_action/btl_turn_actions_attack.erl index 52dd3fb..a414588 100644 --- a/src/battle/mechanic/turn_action/btl_turn_actions_attack.erl +++ b/src/battle/mechanic/turn_action/btl_turn_actions_attack.erl @@ -22,17 +22,29 @@ non_neg_integer(), btl_character_current_data:type(), non_neg_integer(), - list(btl_attack:step()) + list(btl_attack:step()), + integer(), + integer() ) - -> {list(btl_attack:type()), non_neg_integer(), non_neg_integer()}. + -> + { + list(btl_attack:type()), + non_neg_integer(), + non_neg_integer(), + integer(), + integer() + }. handle_attack_sequence ( CharacterCurrentData, CharacterCurrentHealth, TargetCurrentData, TargetCurrentHealth, - AttackSequence + AttackSequence, + AttackerLuck, + DefenderLuck ) -> + % TODO lists:foldl over AttackSequence to take luck into account. AttackPlannedEffects = lists:map ( @@ -41,7 +53,9 @@ handle_attack_sequence ( AttackStep, CharacterCurrentData, - TargetCurrentData + TargetCurrentData, + AttackerLuck, + DefenderLuck ) end, AttackSequence @@ -119,26 +133,47 @@ handle (BattleAction, Update) -> CharacterIX = btl_character_turn_data:get_character_ix(Data), CharacterCurrentData = btl_character_turn_data:get_character_current_data(Data), + AttackingPlayer = + btl_battle:get_player(btl_character:get_player_ix(Character), Battle), + AttackingPlayerLuck = btl_player:get_luck(AttackingPlayer), + Map = btl_battle:get_map(Battle), TargetIX = btl_battle_action:get_target_ix(BattleAction), TargetCharacter = btl_battle:get_character(TargetIX, Battle), TargetCurrentData = btl_character_current_data:new(TargetCharacter, Map), + DefendingPlayer = + btl_battle:get_player + ( + btl_character:get_player_ix(TargetCharacter), + Battle + ), + DefendingPlayerLuck = btl_player:get_luck(DefendingPlayer), true = btl_character:get_is_alive(TargetCharacter), AttackSequence = get_attack_sequence(Character, TargetCharacter), - {AttackEffects, RemainingAttackerHealth, RemainingDefenderHealth} = + { + AttackEffects, + RemainingAttackerHealth, + RemainingDefenderHealth, + _NewAttackerLuck, + _NewDefenderLuck + } = handle_attack_sequence ( CharacterCurrentData, btl_character:get_current_health(Character), TargetCurrentData, btl_character:get_current_health(TargetCharacter), - AttackSequence + AttackSequence, + AttackingPlayerLuck, + DefendingPlayerLuck ), + % TODO: update lucks... + UpdatedCharacter = btl_character:set_current_health(RemainingAttackerHealth, Character), diff --git a/src/battle/struct/btl_attack.erl b/src/battle/struct/btl_attack.erl index 080dae4..6286e41 100644 --- a/src/battle/struct/btl_attack.erl +++ b/src/battle/struct/btl_attack.erl @@ -30,7 +30,7 @@ ( [ get_sequence/3, - get_description_of/3, + get_description_of/5, apply_to_healths/3 ] ). @@ -48,28 +48,73 @@ -spec roll_precision ( shr_statistics:type(), - shr_statistics:type() + shr_statistics:type(), + integer(), + integer() ) - -> precision(). -roll_precision (AttackerStatistics, DefenderStatistics) -> + -> {precision(), integer(), integer()}. +roll_precision +( + AttackerStatistics, + DefenderStatistics, + AttackerLuck, + DefenderLuck +) -> DefenderDodges = shr_statistics:get_dodges(DefenderStatistics), AttackerAccuracy = shr_statistics:get_accuracy(AttackerStatistics), MissChance = max(0, (DefenderDodges - AttackerAccuracy)), - case shr_roll:percentage() of - X when (X =< MissChance) -> misses; - X when (X =< (MissChance * 2)) -> grazes; - _ -> hits - end. --spec roll_critical_hit (shr_statistics:type()) -> boolean(). -roll_critical_hit (AttackerStatistics) -> + {Roll, _IsSuccess, NewDefenderLuck, NewAttackerLuck} = + shr_roll:conflict_with_luck + ( + MissChance, + DefenderLuck, + AttackerLuck + ), + + { + case Roll of + X when (X =< MissChance) -> misses; + X when (X =< (MissChance * 2)) -> grazes; + _ -> hits + end, + NewAttackerLuck, + NewDefenderLuck + }. + +-spec roll_critical_hit + ( + shr_statistics:type(), + integer() + ) + -> {boolean(), integer()}. +roll_critical_hit (AttackerStatistics, AttackerLuck) -> CriticalHitChance = shr_statistics:get_critical_hits(AttackerStatistics), - (shr_roll:percentage() =< CriticalHitChance). + {_Roll, IsSuccess, NewLuck} = + shr_roll:percentage_with_luck + ( + CriticalHitChance, + AttackerLuck + ), + + {IsSuccess, NewLuck}. --spec roll_parry (shr_statistics:type()) -> boolean(). -roll_parry (DefenderStatistics) -> +-spec roll_parry + ( + shr_statistics:type(), + integer() + ) + -> {boolean(), integer()}. +roll_parry (DefenderStatistics, DefenderLuck) -> DefenderParryChance = shr_statistics:get_parries(DefenderStatistics), - (shr_roll:percentage() =< DefenderParryChance). + {_Roll, IsSuccess, NewLuck} = + shr_roll:percentage_with_luck + ( + DefenderParryChance, + DefenderLuck + ), + + {IsSuccess, NewLuck}. -spec get_damage ( @@ -111,18 +156,37 @@ get_damage (Precision, IsCritical, AtkModifier, ActualAtkOmni, ActualDefOmni) -> order(), btl_character_current_data:type(), btl_character_current_data:type(), - boolean() + boolean(), + integer(), + integer() ) - -> type(). -effect_of_attack (Order, AtkCurrData, DefCurrData, CanParry) -> + -> {type(), integer(), integer()}. +effect_of_attack +( + Order, + AtkCurrData, + DefCurrData, + CanParry, + AttackerLuck, + DefenderLuck +) -> DefStats = btl_character_current_data:get_statistics(DefCurrData), - ParryIsSuccessful = (CanParry and roll_parry(DefStats)), + {ParryIsSuccessful, S0DefLuck} = + case CanParry of + true -> roll_parry(DefStats, DefenderLuck); + false -> {false, DefenderLuck} + end, - {ActualAtkData, ActualDefData} = + { + ActualAtkData, + ActualDefData, + ActualAtkLuck, + ActualDefLuck + } = case ParryIsSuccessful of - true -> {DefCurrData, AtkCurrData}; - false -> {AtkCurrData, DefCurrData} + true -> {DefCurrData, AtkCurrData, S0DefLuck, AttackerLuck}; + false -> {AtkCurrData, DefCurrData, AttackerLuck, S0DefLuck} end, ActualAtkStats = btl_character_current_data:get_statistics(ActualAtkData), @@ -130,8 +194,18 @@ effect_of_attack (Order, AtkCurrData, DefCurrData, CanParry) -> ActualDefStats = btl_character_current_data:get_statistics(ActualDefData), ActualDefOmni = btl_character_current_data:get_omnimods(ActualDefData), - Precision = roll_precision(ActualAtkStats, ActualDefStats), - IsCritical = roll_critical_hit(ActualAtkStats), + {Precision, S0ActualAtkLuck, S0ActualDefLuck} = + roll_precision + ( + ActualAtkStats, + ActualDefStats, + ActualAtkLuck, + ActualDefLuck + ), + + {IsCritical, S1ActualAtkLuck} = + roll_critical_hit(ActualAtkStats, S0ActualAtkLuck), + AtkDamageModifier = shr_statistics:get_damage_modifier(ActualAtkStats), Damage = get_damage @@ -143,13 +217,23 @@ effect_of_attack (Order, AtkCurrData, DefCurrData, CanParry) -> ActualDefOmni ), - #attack + {FinalAttackerLuck, FinalDefenderLuck} = + case ParryIsSuccessful of + true -> {S0ActualDefLuck, S1ActualAtkLuck}; + false -> {S1ActualAtkLuck, S0ActualDefLuck} + end, + { - order = Order, - precision = Precision, - is_critical = IsCritical, - is_parry = ParryIsSuccessful, - damage = Damage + #attack + { + order = Order, + precision = Precision, + is_critical = IsCritical, + is_parry = ParryIsSuccessful, + damage = Damage + }, + FinalAttackerLuck, + FinalDefenderLuck }. -spec encode_order (order()) -> binary(). @@ -170,25 +254,76 @@ encode_precision (misses) -> <<"m">>. ( step(), btl_character_current_data:type(), - btl_character_current_data:type() + btl_character_current_data:type(), + integer(), + integer() ) - -> maybe_type(). -get_description_of ({first, CanParry}, AtkCurrData, DefCurrData) -> - effect_of_attack(first, AtkCurrData, DefCurrData, CanParry); -get_description_of ({second, CanParry}, AtkCurrData, DefCurrData) -> + -> {maybe_type(), integer(), integer()}. +get_description_of +( + {first, CanParry}, + AtkCurrData, + DefCurrData, + AtkLuck, + DefLuck +) -> + effect_of_attack + ( + first, + AtkCurrData, + DefCurrData, + CanParry, + AtkLuck, + DefLuck + ); +get_description_of +( + {second, CanParry}, + AtkCurrData, + DefCurrData, + AtkLuck, + DefLuck +) -> AtkStats = btl_character_current_data:get_statistics(AtkCurrData), - AttackerDoubleAttackChange = + AttackerDoubleAttackChance = shr_statistics:get_double_hits(AtkStats), - - case shr_roll:percentage() of - X when (X =< AttackerDoubleAttackChange) -> - effect_of_attack(second, AtkCurrData, DefCurrData, CanParry); - - _ -> - nothing + {_Roll, IsSuccessful, NewAtkLuck} = + shr_roll:percentage_with_luck(AttackerDoubleAttackChance, AtkLuck), + + case IsSuccessful of + true -> + effect_of_attack + ( + second, + AtkCurrData, + DefCurrData, + CanParry, + NewAtkLuck, + DefLuck + ); + + _ -> {nothing, NewAtkLuck, DefLuck} end; -get_description_of ({counter, CanParry}, AtkCurrData, DefCurrData) -> - effect_of_attack(counter, DefCurrData, AtkCurrData, CanParry). +get_description_of +( + {counter, CanParry}, + AtkCurrData, + DefCurrData, + AtkLuck, + DefLuck +) -> + {Effect, NewDefLuck, NewAtkLuck} = + effect_of_attack + ( + counter, + DefCurrData, + AtkCurrData, + CanParry, + DefLuck, + AtkLuck + ), + {Effect, NewAtkLuck, NewDefLuck}. + -spec apply_to_healths ( diff --git a/src/battle/struct/btl_player.erl b/src/battle/struct/btl_player.erl index d5c0de7..054666d 100644 --- a/src/battle/struct/btl_player.erl +++ b/src/battle/struct/btl_player.erl @@ -13,6 +13,7 @@ character_ix :: non_neg_integer(), timeline :: list(any()), is_active :: boolean(), + luck :: integer(), summary_ix :: non_neg_integer(), summary_category :: shr_battle_summary:category() } @@ -29,6 +30,7 @@ [ get_id/1, get_index/1, + get_luck/1, get_summary_index/1, get_summary_category/1, get_character_index/1, @@ -37,10 +39,13 @@ get_is_active/1, set_is_active/2, + set_luck/2, + add_to_timeline/2, reset_timeline/1, get_timeline_field/0, + get_luck_field/0, get_is_active_field/0 ] ). @@ -65,6 +70,9 @@ get_id (Player) -> Player#player.id. -spec get_index (type()) -> non_neg_integer(). get_index (Player) -> Player#player.ix. +-spec get_luck (type()) -> integer(). +get_luck (Player) -> Player#player.luck. + -spec get_summary_index (type()) -> non_neg_integer(). get_summary_index (Player) -> Player#player.summary_ix. @@ -83,6 +91,9 @@ get_is_active (Player) -> Player#player.is_active. -spec set_is_active (boolean(), type()) -> type(). set_is_active (Val, Player) -> Player#player{ is_active = Val }. +-spec set_luck (integer(), type()) -> type(). +set_luck (Val, Player) -> Player#player{ luck = Val }. + -spec add_to_timeline (list(any()), type()) -> type(). add_to_timeline (NewEvents, Player) -> OldTimeline = Player#player.timeline, @@ -111,6 +122,7 @@ new (IX, CharacterIX, ID, SummaryIX, SummaryCategory) -> id = ID, is_active = true, timeline = [], + luck = 0, summary_ix = SummaryIX, summary_category = SummaryCategory }. @@ -118,5 +130,8 @@ new (IX, CharacterIX, ID, SummaryIX, SummaryCategory) -> -spec get_timeline_field () -> non_neg_integer(). get_timeline_field () -> #player.timeline. +-spec get_luck_field () -> non_neg_integer(). +get_luck_field () -> #player.luck. + -spec get_is_active_field () -> non_neg_integer(). get_is_active_field () -> #player.is_active. diff --git a/src/shared/shr_roll.erl b/src/shared/shr_roll.erl index 8e688c7..7c9e1c5 100644 --- a/src/shared/shr_roll.erl +++ b/src/shared/shr_roll.erl @@ -11,7 +11,9 @@ ( [ percentage/0, - between/2 + between/2, + percentage_with_luck/2, + conflict_with_luck/3 ] ). @@ -30,3 +32,76 @@ between (Min, Max) -> -spec percentage () -> 0..100. percentage () -> between(0, 100). + +-spec percentage_with_luck + ( + non_neg_integer(), + integer() + ) + -> {0..100, boolean(), integer()}. +percentage_with_luck (Target, Luck) -> + BaseRoll = percentage(), + ModedRoll = max(0, min((BaseRoll - Luck), 100)), + IsSuccess = (ModedRoll =< Target), + + NewLuck = + case {IsSuccess, (Target > 50)} of + {true, true} -> + % Succeeded, was likely to succeed. + % Only pay what was used. + MissingPoints = max(0, (BaseRoll - Target)), + (Luck - MissingPoints); + + {true, false} -> + % Succeeded, was unlikely to succeed. + % Pay a lot! + MissingPoints = (55 - Target), + (Luck - MissingPoints); + + {false, true} -> + % Failure due to bad roll. + % Was likely to succeed, you get a lot! + OwedPoints = (Target - 45), + (Luck + OwedPoints); + + _ -> Luck + end, + + {ModedRoll, IsSuccess, NewLuck}. + +-spec conflict_with_luck + ( + non_neg_integer(), + integer(), + integer() + ) + -> {0..100, boolean(), integer(), integer()}. +conflict_with_luck (Target, LuckA, LuckB) -> + BaseRoll = percentage(), + ModedRoll = max(0, min((BaseRoll - (LuckA - LuckB)), 100)), + IsSuccess = (ModedRoll =< Target), + + {NewLuckA, NewLuckB} = + case {IsSuccess, (Target > 50)} of + {true, true} -> + % Succeeded, was likely to succeed. + % Only pay what was used. + MissingPoints = max(0, (BaseRoll - Target)), + {(LuckA - MissingPoints), LuckB}; + + {true, false} -> + % Succeeded, was unlikely to succeed. + % Pay a lot! + MissingPoints = (55 - Target), + {(LuckA - MissingPoints), (LuckB + MissingPoints)}; + + {false, true} -> + % Failure due to bad roll. + % Was likely to succeed, you get a lot! + OwedPoints = (Target - 45), + {(LuckA + OwedPoints), (LuckB - OwedPoints)}; + + _ -> {LuckA, LuckB} + end, + + {ModedRoll, IsSuccess, NewLuckA, NewLuckB}. |