| 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}. | 


