summaryrefslogtreecommitdiff |
diff options
-rw-r--r-- | src/battle/mechanic/action/btl_action_attack.erl | 265 | ||||
-rw-r--r-- | src/battle/struct/btl_condition.erl | 106 | ||||
-rw-r--r-- | src/shared/struct/shr_condition.erl | 3 |
3 files changed, 176 insertions, 198 deletions
diff --git a/src/battle/mechanic/action/btl_action_attack.erl b/src/battle/mechanic/action/btl_action_attack.erl index 863ddb4..219c3cd 100644 --- a/src/battle/mechanic/action/btl_action_attack.erl +++ b/src/battle/mechanic/action/btl_action_attack.erl @@ -20,87 +20,123 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -spec apply_conditions ( - shr_condition:trigger(), - ParameterType, + shr_condition:context(A, B), + btl_character:type(), btl_character_turn_update:type() ) - -> {ParameterType, btl_character_turn_update:type()}. + -> {shr_condition:context(A, B), btl_character_turn_update:type()}. apply_conditions ( - TriggerName, - S0Parameter, + Context = {Trigger, _ReadOnlyContext, _VolatileContext}, Actor, S0Update ) -> - { - {TriggerName, S1Parameter}, - S1Update - } = + {LastContext, S1Update} = btl_condition:recursive_apply ( - btl_character:get_conditions_on(TriggerName, Actor), - {TriggerName, S0Parameter}, + btl_character:get_conditions_on(Trigger, Actor), + Context, S0Update ), - {S1Parameter, S1Update}. --spec roll_precision_modifier + {LastContext, S1Update}. + +-spec roll_for_precision ( - shr_attributes:type(), - shr_attributes:type(), + btl_character:type(), + integer(), + btl_character:type(), integer() ) - -> {float(), integer(), integer()}. -roll_precision_modifier (Attributes, TargetAttributes, TargetLuck) -> - TargetDodges = shr_attributes:get_dodge_chance(TargetAttributes), - Accuracy = shr_attributes:get_accuracy(Attributes), - MissChance = max(0, (TargetDodges - Accuracy)), + -> {btl_attack:precision(), integer(), integer()}. +roll_for_precision (Actor, ActorLuck, Target, TargetLuck) -> + TargetDodgeChance = + shr_attributes:get_dodge_chance + ( + shr_character:get_attributes + ( + btl_character:get_base_character(Target) + ) + ), + ActorAccuracy = + shr_attributes:get_accuracy + ( + shr_character:get_attributes + ( + btl_character:get_base_character(Actor) + ) + ), + + MissChance = max(0, (TargetDodgeChance - ActorAccuracy)), {Roll, _IsSuccess, PositiveModifier, NegativeModifier} = shr_roll:percentage_with_luck(MissChance, TargetLuck), { - case Roll of - X when (X =< MissChance) -> 0.0; - X when (X =< (MissChance * 2)) -> 0.5; - _ -> 1.0 - end, - PositiveModifier, - NegativeModifier + ( + if + (Roll =< MissChance) -> misses; + (Roll =< (MissChance * 2)) -> grazes; + true -> hits + end + ), + (ActorLuck + NegativeModifier), % Negative effects are for Actor. + (TargetLuck + PositiveModifier) % Positive effects are for Target. }. --spec roll_critical_modifier +-spec roll_for_critical_hit ( - shr_attributes:type(), + btl_character:type(), + integer(), + btl_character:type(), integer() ) - -> {float(), integer(), integer()}. -roll_critical_modifier (Attributes, Luck) -> - CriticalHitChance = shr_attributes:get_critical_hit_chance(Attributes), + -> {boolean(), integer(), integer()}. +roll_for_critical_hit (Actor, ActorLuck, _Target, TargetLuck) -> + ActorCriticalHitChance = + shr_attributes:get_critical_hit_chance + ( + shr_character:get_attributes + ( + btl_character:get_base_character(Actor) + ) + ), + {_Roll, IsSuccess, PositiveModifier, NegativeModifier} = - shr_roll:percentage_with_luck(CriticalHitChance, Luck), + shr_roll:percentage_with_luck(ActorCriticalHitChance, ActorLuck), { - case IsSuccess of - true -> 2.0; % [TODO][FUTURE]: variable critical multiplier? - false -> 1.0 - end, - PositiveModifier, - NegativeModifier + IsSuccess, + (ActorLuck + PositiveModifier), % Positive effects are for Actor + (TargetLuck + NegativeModifier) % Negative effects are for Target }. --spec roll_parry +-spec roll_for_parry ( - shr_attributes:type(), + btl_character:type(), + integer(), + btl_character:type(), integer() ) -> {boolean(), integer(), integer()}. -roll_parry (DefenderAttributes, DefenderLuck) -> - DefenderParryChance = shr_attributes:get_parry_chance(DefenderAttributes), +roll_for_parry (_Actor, ActorLuck, Target, TargetLuck) -> + TargetParryChance = + shr_attributes:get_critical_hit_chance + ( + shr_character:get_attributes + ( + btl_character:get_base_character(Target) + ) + ), + {_Roll, IsSuccess, PositiveModifier, NegativeModifier} = - shr_roll:percentage_with_luck(DefenderParryChance, DefenderLuck), + shr_roll:percentage_with_luck(TargetParryChance, TargetLuck), - {IsSuccess, PositiveModifier, NegativeModifier}. + { + IsSuccess, + (ActorLuck + NegativeModifier), % Negative effects are for Actor + (TargetLuck + PositiveModifier) % Positive effects are for Target + }. -spec get_character_abilities ( @@ -619,50 +655,51 @@ apply_luck_decay (Luck) -> ( shr_condition:trigger(), shr_condition:trigger(), - {btl_action:type(), OtherData}, + btl_action:type(), + {any(), VolatileContext}, btl_character_turn_update:type() ) - -> {{btl_action:type(), OtherData}, btl_character_turn_update:type()}. + -> {VolatileContext, btl_character_turn_update:type()}. apply_mirror_conditions ( OwnTriggerName, OtherTriggerName, - {S0Action, S0Data}, + Action, + {ReadOnlyContext, S0VolatileContext}, S0Update ) -> - CharacterIX = btl_action:get_actor_index(S0Action), + CharacterIX = btl_action:get_actor_index(Action), 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), - {{S1Action, S1Data}, S2Update} = + {{_TriggerName, _ReadOnlyContext, S1VolatileContext}, S2Update} = apply_conditions ( - OwnTriggerName, - {S0Action, S0Data}, + {OwnTriggerName, ReadOnlyContext, S0VolatileContext}, Character, S1Update ), - TargetCharacterIX = btl_action:get_target_index(S1Action), + TargetCharacterIX = btl_action:get_target_index(Action), S2Battle = btl_character_turn_update:get_battle(S2Update), + {TargetCharacter, S3Battle} = btl_battle:get_resolved_character(TargetCharacterIX, S2Battle), S3Update = btl_character_turn_update:set_battle(S3Battle, S2Update), - {{S2Action, S2Data}, S4Update} = + {{_TriggerName, _ReadOnlyContext, S2VolatileContext}, S4Update} = apply_conditions ( - OtherTriggerName, - {S1Action, S1Data}, + {OtherTriggerName, ReadOnlyContext, S1VolatileContext}, TargetCharacter, S3Update ), - {{S2Action, S2Data}, S4Update}. + {S2VolatileContext, S4Update}. -spec handle_start_of_attack ( @@ -671,70 +708,92 @@ apply_mirror_conditions btl_character_turn_update:type() ) -> - { - list(btl_attack:category()), - btl_action:type(), - btl_character_turn_update:type() - }. -handle_start_of_attack (S0AttackSequence, S0Action, S0Update) -> - S1Update = add_targeting_event(S0Action, S0Update), + {list(btl_attack:category()), btl_character_turn_update:type() }. +handle_start_of_attack (S0AttackSequence, Action, S0Update) -> + S1Update = add_targeting_event(Action, S0Update), - {{S1Action, S1AttackSequence}, S2Update} = + {S1AttackSequence, S2Update} = apply_mirror_conditions ( ?CONDITION_TRIGGER_START_OF_OWN_ATTACK, ?CONDITION_TRIGGER_START_OF_OTHER_ATTACK, - {S0Action, S0AttackSequence}, + Action, + {Action, S0AttackSequence}, S1Update ), - {S1AttackSequence, S1Action, S2Update}. + {S1AttackSequence, S2Update}. -spec handle_end_of_attack ( btl_action:type(), btl_character_turn_update:type() ) - -> {btl_action:type(), btl_character_turn_update:type()}. -handle_end_of_attack (S0Action, S0Update) -> - {{S1Action, _PlaceHolder}, S1Update} = + -> btl_character_turn_update:type(). +handle_end_of_attack (Action, S0Update) -> + {_None, S1Update} = apply_mirror_conditions ( ?CONDITION_TRIGGER_END_OF_OWN_ATTACK, ?CONDITION_TRIGGER_END_OF_OTHER_ATTACK, - {S0Action, ok}, + Action, + {Action, none}, S0Update ), - {S1Action, S1Update}. + S1Update. --spec handle_first_hit +-spec handle_hit ( + btl_attack:category(), list(btl_attack:category()), btl_action:type(), btl_character_turn_update:type() ) - -> - { - list(btl_attack:category()), - btl_action:type(), - btl_character_turn_update:type() - }. -handle_first_hit (S0Sequence, S0Action, S0Update) -> - {BaseActor, BaseTarget, S1Update} = get_actors(S0Action, S0Update), - {{_S1Action, {ModdedActor, ModdedTarget}}, S2Update} = + -> {list(btl_attack:category()), btl_character_turn_update:type()}. +handle_hit (AttackCategory, S0Sequence, Action, S0Update) -> + {BaseActor, S0ActorLuck, BaseTarget, S0TargetLuck, S1Update} = + get_actors_and_lucks(AttackCategory, S0Action, S0Update), + + {{S0ModdedActor, S0ModdedTarget, S1Sequence}, S2Update} = apply_mirror_conditions ( - ?CONDITION_TRIGGER_INITIAL_DATA_FOR_OWN_HIT, - ?CONDITION_TRIGGER_INITIAL_DATA_FOR_OTHER_HIT, - {S0Action, {BaseActor, BaseTarget}}, + ?CONDITION_TRIGGER_ACTORS_DEFINITION_FOR_OWN_HIT, + ?CONDITION_TRIGGER_ACTORS_DEFINITION_FOR_OTHER_HIT, + Action, + {{Action, AttackCategory}, {BaseActor, BaseTarget, S0Sequence}}, S1Update ), - case can_perform(ModdedActor, ModdedTarget) of - false -> {S0Sequence, S0Action, S2Update}; + case can_perform_attack(S0ModdedActor, S0ModdedTarget) of + false -> {S1Sequence, S2Update}; true -> - {HitData, S1Update} = get_hit_data(S0Action, S0Update), + {S0IsParry, S1ActorLuck, S1TargetLuck} = + roll_for_parry + ( + S0ModdedActor, + S0ActorLuck, + S0ModdedTarget, + S0TargetLuck + ), + { + {S1IsParry, S1ModdedActor, S1ModdedTarget, S2Sequence}, + S3Update + } = + apply_mirror_conditions + ( + ?CONDITION_TRIGGER_ACTORS_DEFINITION_FOR_OTHER_PARRY, + ?CONDITION_TRIGGER_ACTORS_DEFINITION_FOR_OWN_PARRY, + Action, + { + {Action, AttackCategory}, + {S0IsParry, S0ModdedActor, S0ModdedTarget, S1Sequence} + }, + S2Update + ), + + % TODO + {S2Sequence, S3Update} end. -spec handle_attack_sequence @@ -743,21 +802,13 @@ handle_first_hit (S0Sequence, S0Action, S0Update) -> btl_action:type(), btl_character_turn_update:type() ) - -> {btl_action:type(), btl_character_turn_update:type()}. + -> btl_character_turn_update:type(). handle_attack_sequence ([], Action, Update) -> {Action, Update}; -handle_attack_sequence ([first|S0NextElements], S0Action, S0Update) -> - {S1NextElements, S1Action, S1Update} = - handle_first_hit(S0NextElements, S0Action, S0Update), - handle_attack_sequence(S1NextElements, S1Action, S1Update); -handle_attack_sequence ([second|S0NextElements], S0Action, S0Update) -> - {S1NextElements, S1Action, S1Update} = - handle_second_hit(S0NextElements, S0Action, S0Update), - handle_attack_sequence(S1NextElements, S1Action, S1Update); -handle_attack_sequence ([counter|S0NextElements], S0Action, S0Update) -> - {S1NextElements, S1Action, S1Update} = - handle_counter_hit(S0NextElements, S0Action, S0Update), - handle_attack_sequence(S1NextElements, S1Action, S1Update). +handle_attack_sequence ([AttackCategory|S0NextElements], Action, S0Update) -> + {S1NextElements, S1Update} = + handle_hit(AttackCategory, S0NextElements, Action, S0Update), + handle_attack_sequence(S1NextElements, Action, S1Update). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -768,16 +819,14 @@ handle_attack_sequence ([counter|S0NextElements], S0Action, S0Update) -> btl_character_turn_update:type() ) -> btl_character_turn_update:type(). -handle (S0Action, S0Update) -> +handle (Action, S0Update) -> S0Sequence = [first, counter, second], - {S1Sequence, S1Action, S1Update} = - handle_start_of_attack(S0Sequence, S0Action, S0Update), - - {S2Action, S2Update} = - handle_attack_sequence(S1Sequence, S1Action, S1Update), + {S1Sequence, S1Update} = + handle_start_of_attack(S0Sequence, Action, S0Update), - {_S3Action, S3Update} = handle_end_of_attack(S2Action, S2Update), + S2Update = handle_attack_sequence(S1Sequence, Action, S1Update), + S3Update = handle_end_of_attack(S2Action, S2Update), S3Update. diff --git a/src/battle/struct/btl_condition.erl b/src/battle/struct/btl_condition.erl index 2954c13..24ef084 100644 --- a/src/battle/struct/btl_condition.erl +++ b/src/battle/struct/btl_condition.erl @@ -5,78 +5,6 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -include("tacticians/conditions.hrl"). --type trigger() :: - ( - { - ( - ?CONDITION_TRIGGER_START_OF_PLAYER_TURN - | ?CONDITION_TRIGGER_END_OF_PLAYER_TURN - ), - non_neg_integer() - } - - | - { - ( - ?CONDITION_TRIGGER_START_OF_CHARACTER_TURN - | ?CONDITION_TRIGGER_END_OF_CHARACTER_TURN - | ?CONDITION_WEAPON_SWITCH - | ?CONDITION_TRIGGER_SKILL_USE - | ?CONDITION_TRIGGER_DEATH - ), - non_neg_integer() - } - - | - { - ( - ?CONDITION_TRIGGER_START_OF_OWN_ATTACK - | ?CONDITION_TRIGGER_END_OF_OWN_ATTACK - | ?CONDITION_TRIGGER_START_OF_OWN_HIT - | ?CONDITION_TRIGGER_END_OF_OWN_HIT - | ?CONDITION_TRIGGER_OWN_DODGE - | ?CONDITION_TRIGGER_OWN_CRITICAL - | ?CONDITION_TRIGGER_OWN_DOUBLE_HIT - | ?CONDITION_TRIGGER_OWN_DAMAGE - | ?CONDITION_TRIGGER_START_OF_TARGET_ATTACK - | ?CONDITION_TRIGGER_END_OF_TARGET_ATTACK - | ?CONDITION_TRIGGER_START_OF_TARGET_HIT - | ?CONDITION_TRIGGER_END_OF_TARGET_HIT - | ?CONDITION_TRIGGER_TARGET_DODGE - | ?CONDITION_TRIGGER_TARGET_CRITICAL - | ?CONDITION_TRIGGER_TARGET_DOUBLE_HIT - | ?CONDITION_TRIGGER_TARGET_DAMAGE - ), - { - non_neg_integer(), - btl_character:type(), - non_neg_integer(), - btl_character:type() - } - } - - | - { - ( - ?CONDITION_TRIGGER_START_OF_MOVEMENT - | ?CONDITION_TRIGGER_END_OF_MOVEMENT - ), - { - non_neg_integer(), - list(shr_direction:type()) - } - } - - | - { - ( - ?CONDITION_TRIGGER_START_OF_BATTLE - | ?CONDITION_TRIGGER_END_OF_BATTLE - ), - none - } - ). - -type update_action() :: (none, remove, {update, ataxic:basic()}). -record @@ -93,7 +21,7 @@ -opaque type() :: #btl_cond{}. --export_type([type/0, trigger/0, update_action/0]). +-export_type([type/0, update_action/0]). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -303,50 +231,50 @@ get_parameters_field () -> #btl_cond.parameters. -spec apply ( type(), - trigger(), + shr_condition:context(), btl_character_turn_update:type() ) - -> {trigger(), btl_character_turn_update:type()}. -apply (S0Condition, S0Trigger, S0Update) -> + -> {shr_condition:context(), btl_character_turn_update:type()}. +apply (S0Condition, S0Context, S0Update) -> Module = shr_condition_selector:get_module(get_category(S0Condition)), - {S1Condition, UpdateAction, S1Trigger, S1Update} = - erlang:apply(Module, apply, [S0Trigger, S0Condition, S0Update]), + {S1Condition, UpdateAction, S1Context, S1Update} = + erlang:apply(Module, apply, [S0Context, S0Condition, S0Update]), case UpdateAction of - none -> {S1Trigger, S1Update}; + none -> {S1Context, S1Update}; remove -> % TODO - {S1Trigger, S1Update}; + {S1Context, S1Update}; {update, ConditionUpdate} -> % TODO - {S1Trigger, S1Update} + {S1Context, S1Update} end. -spec recursive_apply ( list(type()), - trigger(), + shr_condition:context(), btl_character_turn_update:type() ) - -> {trigger(), btl_character_turn_update:type()}. -recursive_apply (Conditions, S0Trigger, S0Update) -> - [LastTrigger, LastUpdate] = + -> {shr_condition:context(), btl_character_turn_update:type()}. +recursive_apply (Conditions, S0Context, S0Update) -> + [LastContext, LastUpdate] = lists:foldl ( fun (Condition, Parameters) -> - {NextTrigger, NextUpdate} = + {NextContext, NextUpdate} = erlang:apply(btl_condition, apply, [Condition|Parameters]), - [NextTrigger, NextUpdate] + [NextContext, NextUpdate] end, - [S0Trigger, S0Update], + [S0Context, S0Update], Conditions ), - {LastTrigger, LastUpdate}. + {LastContext, LastUpdate}. -spec encode (type()) -> {list({binary(), any()})}. encode (Condition) -> {[]} % TODO. diff --git a/src/shared/struct/shr_condition.erl b/src/shared/struct/shr_condition.erl index 6d75167..13c3426 100644 --- a/src/shared/struct/shr_condition.erl +++ b/src/shared/struct/shr_condition.erl @@ -5,6 +5,7 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -type id() :: ataxia_id:type(). -type trigger() :: atom(). +-type context(ReadOnly, Volatile) :: {trigger(), ReadOnly, Volatile}. -record ( @@ -20,7 +21,7 @@ -opaque type() :: #condition{}. --export_type([id/0, type/0, trigger/0]). +-export_type([id/0, type/0, trigger/0, context/2]). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |