summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornsensfel <SpamShield0@noot-noot.org>2019-01-28 19:03:19 +0100
committernsensfel <SpamShield0@noot-noot.org>2019-01-28 19:03:19 +0100
commitdc988b5aa72204954b2034615d644c703b35d294 (patch)
tree8605e35192f542b960270f9ee35b879584fda8a8
parent04212005d8f4e078548738256add0f6c12138946 (diff)
Adding the luck mechanic...
-rw-r--r--src/battle/mechanic/turn_action/btl_turn_actions_attack.erl47
-rw-r--r--src/battle/struct/btl_attack.erl225
-rw-r--r--src/battle/struct/btl_player.erl15
-rw-r--r--src/shared/shr_roll.erl77
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}.