aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornsensfel <SpamShield0@noot-noot.org>2018-02-28 17:46:41 +0100
committernsensfel <SpamShield0@noot-noot.org>2018-02-28 17:46:41 +0100
commit1b59bdfc0d923a1ebfcebf4d6efceb2f2f4579a4 (patch)
treed000a796fd61b27d8031cbdf691f1be73fdb5cb0
parent5235345620c0d4a6669ccc6badc387902ea8c92a (diff)
downloadtacticians-server-1b59bdfc0d923a1ebfcebf4d6efceb2f2f4579a4.zip
tacticians-server-1b59bdfc0d923a1ebfcebf4d6efceb2f2f4579a4.tar.bz2
Moved the mess from 'character_turn' into 'attack'.
-rw-r--r--src/battlemap/attack.erl279
-rw-r--r--src/query/character_turn.erl146
-rw-r--r--src/query/character_turn/handle_character_instance_attacking_2.erl383
-rw-r--r--src/struct/weapon.erl4
4 files changed, 428 insertions, 384 deletions
diff --git a/src/battlemap/attack.erl b/src/battlemap/attack.erl
new file mode 100644
index 0000000..7384f78
--- /dev/null
+++ b/src/battlemap/attack.erl
@@ -0,0 +1,279 @@
+-module(attack).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% TODO: find better names for those types.
+-type hits() :: ('misses' | 'grazes' | 'hits').
+-type critical() :: ('critical' | 'basic').
+-type attack_order() :: 'first' | 'second' | 'counter'.
+-type attack_order_with_parry() :: {attack_order(), boolean()}.
+-type attack_category() ::
+ (
+ attack_order()
+ | {attack_order(), 'parry'}
+ ).
+-type attack_effect() :: {hits(), critical(), non_neg_integer()}.
+-type attack_desc() ::
+ (
+ {attack_category(), attack_effect()}
+ | 'nothing'
+ ).
+
+-export_type
+(
+ [
+ hits/0,
+ critical/0,
+ attack_category/0,
+ attack_effect/0,
+ attack_desc/0
+ ]
+).
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-export
+(
+ [
+ get_sequence/3,
+ get_description_of/3,
+ apply_to_healths/3
+ ]
+).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-spec roll_hits
+ (
+ statistics:struct(),
+ statistics:struct()
+ )
+ -> hits().
+roll_hits (AttackerStatistics, DefenderStatistics) ->
+ DefenderDodges = statistics:get_dodges(DefenderStatistics),
+ AttackerAccuracy = statistics:get_accuracy(AttackerStatistics),
+ MissChance = max(0, (DefenderDodges - AttackerAccuracy)),
+ case roll:percentage() of
+ X when (X =< MissChance) -> misses;
+ X when (X =< (MissChance * 2)) -> grazes;
+ _ -> hits
+ end.
+
+-spec roll_damage
+ (
+ statistics:struct(),
+ statistics:struct()
+ )
+ -> {critical(), non_neg_integer()}.
+roll_damage (AttackerStatistics, _DefenderStatistics) ->
+ {MinimumDamage, MaximumDamage} = statistics:get_damages(AttackerStatistics),
+ MaximumRoll = max(1, MaximumDamage - MinimumDamage),
+ BaseDamage = MinimumDamage + (rand:uniform(MaximumRoll) - 1),
+ CriticalHitChance = statistics:get_critical_hits(AttackerStatistics),
+ case roll:percentage() of
+ X when (X =< CriticalHitChance) -> {critical, (BaseDamage * 2)};
+ _ -> {basic, BaseDamage}
+ end.
+
+-spec effect_of_attack
+ (
+ statistics:struct(),
+ statistics:struct()
+ )
+ -> attack_effect().
+effect_of_attack (AttackerStatistics, DefenderStatistics) ->
+ Hits = roll_hits(AttackerStatistics, DefenderStatistics),
+ {Critical, Damage} = roll_damage(AttackerStatistics, DefenderStatistics),
+ case Hits of
+ misses -> {Hits, Critical, 0};
+ grazes -> {Hits, Critical, trunc(Damage / 2)};
+ hits -> {Hits, Critical, Damage}
+ end.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-spec get_description_of
+ (
+ attack_order_with_parry(),
+ statistics:struct(),
+ statistics:struct()
+ )
+ -> attack_desc().
+get_description_of
+(
+ {first, DefenderCanParry},
+ AttackerStatistics,
+ DefenderStatistics
+) ->
+ DefenderParryChance = statistics:get_parries(DefenderStatistics),
+ ParryRoll =
+ case DefenderCanParry of
+ true -> roll:percentage();
+ _ -> 101
+ end,
+ if
+ (ParryRoll =< DefenderParryChance) ->
+ {
+ {first, parry},
+ effect_of_attack(DefenderStatistics, AttackerStatistics)
+ };
+
+ true ->
+ {first, effect_of_attack(AttackerStatistics, DefenderStatistics)}
+ end;
+get_description_of
+(
+ {second, DefenderCanParry},
+ AttackerStatistics,
+ DefenderStatistics
+) ->
+ DefenderParryChance = statistics:get_parries(DefenderStatistics),
+ ParryRoll =
+ case DefenderCanParry of
+ true -> roll:percentage();
+ _ -> 101
+ end,
+ AttackerDoubleAttackChange = statistics:get_double_hits(AttackerStatistics),
+ DoubleAttackRoll = roll:percentage(),
+ if
+ (DoubleAttackRoll > AttackerDoubleAttackChange) ->
+ nothing;
+
+ (ParryRoll =< DefenderParryChance) ->
+ {
+ {second, parry},
+ effect_of_attack(DefenderStatistics, AttackerStatistics)
+ };
+
+ true ->
+ {second, effect_of_attack(AttackerStatistics, DefenderStatistics)}
+ end;
+get_description_of
+(
+ {counter, AttackerCanParry},
+ AttackerStatistics,
+ DefenderStatistics
+) ->
+ AttackerParryChance = statistics:get_parries(AttackerStatistics),
+ ParryRoll =
+ case AttackerCanParry of
+ true -> roll:percentage();
+ _ -> 101
+ end,
+ if
+ (ParryRoll =< AttackerParryChance) ->
+ {
+ {counter, parry},
+ effect_of_attack(AttackerStatistics, DefenderStatistics)
+ };
+
+ true ->
+ {counter, effect_of_attack(DefenderStatistics, AttackerStatistics)}
+ end.
+
+-spec apply_to_healths
+ (
+ attack_desc(),
+ non_neg_integer(),
+ non_neg_integer()
+ )
+ -> {attack_desc(), non_neg_integer(), non_neg_integer()}.
+apply_to_healths
+(
+ nothing,
+ AttackerHealth,
+ DefenderHealth
+) ->
+ {nothing, AttackerHealth, DefenderHealth};
+apply_to_healths
+(
+ {Attack, Effect},
+ AttackerHealth,
+ DefenderHealth
+)
+when
+(
+ (Attack == first)
+ or (Attack == second)
+ or (Attack == {counter, parry})
+) ->
+ {_Hits, _Critical, Damage} = Effect,
+ case AttackerHealth of
+ 0 ->
+ {nothing, AttackerHealth, DefenderHealth};
+
+ _ ->
+ {
+ {Attack, Effect},
+ AttackerHealth,
+ max(0, (DefenderHealth - Damage))
+ }
+ end;
+apply_to_healths
+(
+ {Attack, Effect},
+ AttackerHealth,
+ DefenderHealth
+)
+when
+(
+ (Attack == {first, parry})
+ or (Attack == {second, parry})
+ or (Attack == counter)
+) ->
+ {_Hits, _Critical, Damage} = Effect,
+ case DefenderHealth of
+ 0 ->
+ {nothing, AttackerHealth, DefenderHealth};
+
+ _ ->
+ {
+ {Attack, Effect},
+ max(0, (AttackerHealth - Damage)),
+ DefenderHealth
+ }
+ end.
+
+-spec get_sequence
+ (
+ non_neg_integer(),
+ weapon:struct(),
+ weapon:struct()
+ )
+ -> list(attack_order_with_parry()).
+get_sequence (AttackRange, AttackerWeapon, DefenderWeapon) ->
+ {AttackerDefenseRange, AttackerAttackRange} =
+ weapon:get_ranges(AttackerWeapon),
+ {DefenderDefenseRange, DefenderAttackRange} =
+ weapon:get_ranges(DefenderWeapon),
+
+ AttackerCanAttack = (AttackRange =< AttackerAttackRange),
+ AttackerCanDefend =
+ (AttackerCanAttack and (AttackRange > AttackerDefenseRange)),
+ AttackerCanParry =
+ (AttackerCanDefend and weapon:can_parry(AttackerWeapon)),
+
+ DefenderCanAttack = (AttackRange =< DefenderAttackRange),
+ DefenderCanDefend =
+ (DefenderCanAttack and (AttackRange > DefenderDefenseRange)),
+ DefenderCanParry =
+ (DefenderCanDefend and weapon:can_parry(DefenderWeapon)),
+
+ First = {first, DefenderCanParry},
+ Second = {second, DefenderCanParry},
+ Counter = {counter, AttackerCanParry},
+
+ if
+ (not AttackerCanAttack) ->
+ [];
+
+ (not DefenderCanDefend) ->
+ [First, Second];
+
+ true ->
+ [First, Counter, Second]
+ end.
diff --git a/src/query/character_turn.erl b/src/query/character_turn.erl
index c920745..b24e038 100644
--- a/src/query/character_turn.erl
+++ b/src/query/character_turn.erl
@@ -233,7 +233,151 @@ handle_character_instance_switching_weapons (QueryState, Input) ->
UpdatedQueryState
}.
--include("character_turn/handle_character_instance_attacking_2.erl").
+-spec set_new_healths_in_query_state
+ (
+ non_neg_integer(),
+ non_neg_integer(),
+ query_state(),
+ input()
+ )
+ -> query_state().
+set_new_healths_in_query_state
+(
+ RemainingAttackerHealth,
+ RemainingDefenderHealth,
+ QueryState,
+ Input
+) ->
+ BattlemapInstance = QueryState#query_state.battlemap_instance,
+ ControlledCharacterInstance = QueryState#query_state.character_instance,
+ CharacterInstances =
+ battlemap_instance:get_character_instances(BattlemapInstance),
+ TargettedCharacterInstanceIX = Input#input.target_ix,
+ TargettedCharacterInstance =
+ array:get
+ (
+ TargettedCharacterInstanceIX,
+ CharacterInstances
+ ),
+
+ QueryState#query_state
+ {
+ battlemap_instance =
+ battlemap_instance:set_character_instances
+ (
+ array:set
+ (
+ TargettedCharacterInstanceIX,
+ character_instance:set_current_health
+ (
+ RemainingDefenderHealth,
+ TargettedCharacterInstance
+ ),
+ CharacterInstances
+ ),
+ BattlemapInstance
+ ),
+ character_instance =
+ character_instance:set_current_health
+ (
+ RemainingAttackerHealth,
+ ControlledCharacterInstance
+ )
+ }.
+
+-spec handle_character_instance_attacking
+ (
+ query_state(),
+ input()
+ )
+ -> {list(attack:attack_desc()), query_state()}.
+handle_character_instance_attacking (QueryState, Input) ->
+ BattlemapInstance = QueryState#query_state.battlemap_instance,
+ ControlledCharacterInstance = QueryState#query_state.character_instance,
+ ControlledCharacter =
+ character_instance:get_character(ControlledCharacterInstance),
+ ControlledCharacterStatistics =
+ character:get_statistics(ControlledCharacter),
+ TargettedCharacterInstance =
+ array:get
+ (
+ Input#input.target_ix,
+ battlemap_instance:get_character_instances(BattlemapInstance)
+ ),
+ TargettedCharacter =
+ character_instance:get_character(TargettedCharacterInstance),
+ TargettedCharacterStatistics = character:get_statistics(TargettedCharacter),
+ RequiredRange =
+ movement:steps_between
+ (
+ character_instance:get_location(ControlledCharacterInstance),
+ character_instance:get_location(TargettedCharacterInstance)
+ ),
+ {AttackingWeaponID, _} = character:get_weapon_ids(ControlledCharacter),
+ AttackingWeapon = weapon:from_id(AttackingWeaponID),
+ {DefendingWeaponID, _} = character:get_weapon_ids(TargettedCharacter),
+ DefendingWeapon = weapon:from_id(DefendingWeaponID),
+ BaseAttackerHealth =
+ character_instance:get_current_health(ControlledCharacterInstance),
+ BaseDefenderHealth =
+ character_instance:get_current_health(TargettedCharacterInstance),
+
+ AttackSequence =
+ attack:get_sequence(RequiredRange, AttackingWeapon, DefendingWeapon),
+
+ AttackEffects =
+ lists:map
+ (
+ fun (AttackOrder) ->
+ attack:get_description_of
+ (
+ AttackOrder,
+ ControlledCharacterStatistics,
+ TargettedCharacterStatistics
+ )
+ end,
+ AttackSequence
+ ),
+
+ {AttackSummary, RemainingAttackerHealth, RemainingDefenderHealth} =
+ lists:foldl
+ (
+ fun
+ (
+ AttackEffect,
+ {
+ CurrentAttackEffects,
+ CurrentAttackerHealth,
+ CurrentDefenderHealth
+ }
+ ) ->
+ {AttackTrueEffect, NewAttackerHealth, NewDefenderHealth} =
+ attack:apply_to_healths
+ (
+ AttackEffect,
+ CurrentAttackerHealth,
+ CurrentDefenderHealth
+ ),
+ {
+ [AttackTrueEffect|CurrentAttackEffects],
+ NewAttackerHealth,
+ NewDefenderHealth
+ }
+ end,
+ {[], BaseAttackerHealth, BaseDefenderHealth},
+ AttackEffects
+ ),
+
+ {
+ AttackSummary,
+ set_new_healths_in_query_state
+ (
+ RemainingAttackerHealth,
+ RemainingDefenderHealth,
+ QueryState,
+ Input
+ )
+ }.
-spec get_type_of_turn (input()) -> list(atom()).
get_type_of_turn (Input) ->
diff --git a/src/query/character_turn/handle_character_instance_attacking_2.erl b/src/query/character_turn/handle_character_instance_attacking_2.erl
deleted file mode 100644
index 6995c4c..0000000
--- a/src/query/character_turn/handle_character_instance_attacking_2.erl
+++ /dev/null
@@ -1,383 +0,0 @@
-% TODO: put all of that into separate modules. It's kind of a mess here.
--type hits() :: ('misses' | 'grazes' | 'hits').
--type critical() :: ('critical' | 'basic').
--type attack_category() ::
- (
- 'first'
- | 'second'
- | 'counter'
- | {'first', 'parry'}
- | {'second', 'parry'}
- ).
--type attack_effect() :: {hits(), critical(), non_neg_integer()}.
--type attack_desc() :: {attack_category(), attack_effect()}.
-
--spec roll_hits
- (
- statistics:struct(),
- statistics:struct()
- )
- -> hits().
-roll_hits (AttackerStatistics, DefenderStatistics) ->
- DefenderDodges = statistics:get_dodges(DefenderStatistics),
- AttackerAccuracy = statistics:get_accuracy(AttackerStatistics),
- MissChance = max(0, (DefenderDodges - AttackerAccuracy)),
- case roll:percentage() of
- X when (X =< MissChance) -> misses;
- X when (X =< (MissChance * 2)) -> grazes;
- _ -> hits
- end.
-
--spec roll_damage
- (
- statistics:struct(),
- statistics:struct()
- )
- -> {critical(), non_neg_integer()}.
-roll_damage (AttackerStatistics, _DefenderStatistics) ->
- {MinimumDamage, MaximumDamage} = statistics:get_damages(AttackerStatistics),
- MaximumRoll = max(1, MaximumDamage - MinimumDamage),
- BaseDamage = MinimumDamage + (rand:uniform(MaximumRoll) - 1),
- CriticalHitChance = statistics:get_critical_hits(AttackerStatistics),
- case roll:percentage() of
- X when (X =< CriticalHitChance) -> {critical, (BaseDamage * 2)};
- _ -> {basic, BaseDamage}
- end.
-
--spec handle_attack
- (
- statistics:struct(),
- statistics:struct()
- )
- -> {hits(), critical(), non_neg_integer()}.
-handle_attack (AttackerStatistics, DefenderStatistics) ->
- Hits = roll_hits(AttackerStatistics, DefenderStatistics),
- {Critical, Damage} = roll_damage(AttackerStatistics, DefenderStatistics),
- case Hits of
- misses -> {Hits, Critical, 0};
- grazes -> {Hits, Critical, trunc(Damage / 2)};
- hits -> {Hits, Critical, Damage}
- end.
-
--spec handle_attacks
- (
- list(attack_category()),
- statistics:struct(),
- statistics:struct(),
- list(attack_desc())
- )
- -> list(attack_desc()).
-handle_attacks ([], _AttackerStatistics, _DefenderStatistics, Results) ->
- Results;
-handle_attacks
-(
- [first|Next],
- AttackerStatistics,
- DefenderStatistics,
- Results
-) ->
- AttackResult = handle_attack(AttackerStatistics, DefenderStatistics),
- handle_attacks
- (
- Next,
- AttackerStatistics,
- DefenderStatistics,
- [{first, AttackResult} | Results]
- );
-handle_attacks
-(
- [second|Next],
- AttackerStatistics,
- DefenderStatistics,
- Results
-) ->
- SecondHitChance = statistics:get_double_hits(AttackerStatistics),
- UpdatedResults =
- case roll:percentage() of
- X when (X =< SecondHitChance) ->
- [
- {second, handle_attack(AttackerStatistics, DefenderStatistics)}
- |
- Results
- ];
-
- _ ->
- Results
- end,
- handle_attacks(Next, AttackerStatistics, DefenderStatistics, UpdatedResults);
-handle_attacks
-(
- [{first, parry}|Next],
- AttackerStatistics,
- DefenderStatistics,
- Results
-) ->
- ParryChance = statistics:get_parries(DefenderStatistics),
- AttackResult =
- case roll:percentage() of
- X when (X =< ParryChance) ->
- {
- {first, parry},
- handle_attack(DefenderStatistics, AttackerStatistics)
- };
-
- _ ->
- {first, handle_attack(AttackerStatistics, DefenderStatistics)}
- end,
- handle_attacks
- (
- Next,
- AttackerStatistics,
- DefenderStatistics,
- [AttackResult|Results]
- );
-handle_attacks
-(
- [{second, parry}|Next],
- AttackerStatistics,
- DefenderStatistics,
- Results
-) ->
- SecondHitChance = statistics:get_double_hits(AttackerStatistics),
- ParryChance = statistics:get_parries(DefenderStatistics),
- AttackResult =
- case roll:percentage() of
- X when (X =< SecondHitChance) ->
- case roll:percentage() of
- Y when (Y =< ParryChance) ->
- {
- {second, parry},
- handle_attack(DefenderStatistics, AttackerStatistics)
- };
-
- _ ->
- {
- second,
- handle_attack(AttackerStatistics, DefenderStatistics)
- }
- end;
-
- _ -> nothing
- end,
- handle_attacks
- (
- Next,
- AttackerStatistics,
- DefenderStatistics,
- case AttackResult of
- nothing -> Results;
- _ -> [AttackResult|Results]
- end
- );
-handle_attacks
-(
- [counter|Next],
- AttackerStatistics,
- DefenderStatistics,
- Results
-) ->
- handle_attacks
- (
- Next,
- AttackerStatistics,
- DefenderStatistics,
- [
- {counter, handle_attack(DefenderStatistics, AttackerStatistics)}
- |
- Results
- ]
- ).
-
--spec apply_attacks_to_healths
- (
- list(attack_desc()),
- non_neg_integer(),
- non_neg_integer(),
- list(attack_desc())
- )
- -> {list(attack_desc()), non_neg_integer(), non_neg_integer()}.
-apply_attacks_to_healths ([], AttackerHealth, DefenderHealth, ValidEffects) ->
- {ValidEffects, AttackerHealth, DefenderHealth};
-apply_attacks_to_healths
-(
- [{Action, Effect}|Next],
- AttackerHealth,
- DefenderHealth,
- ValidEffects
-)
-when ((Action == first) or (Action == second)) ->
- {_Hit, _Critical, Damage} = Effect,
- case (AttackerHealth > 0) of
- true ->
- apply_attacks_to_healths
- (
- Next,
- AttackerHealth,
- max(0, (DefenderHealth - Damage)),
- [{Action, Effect}|ValidEffects]
- );
-
- false ->
- {ValidEffects, AttackerHealth, DefenderHealth}
- end;
-apply_attacks_to_healths
-(
- [{Action, Effect}|Next],
- AttackerHealth,
- DefenderHealth,
- ValidEffects
-)
-when
-(
- (Action == counter)
- or (Action == {first, parry})
- or (Action == {second, parry})
-) ->
- {_Hit, _Critical, Damage} = Effect,
- case (DefenderHealth > 0) of
- true ->
- apply_attacks_to_healths
- (
- Next,
- max(0, (AttackerHealth - Damage)),
- DefenderHealth,
- [{Action, Effect}|ValidEffects]
- );
-
- false ->
- {ValidEffects, AttackerHealth, DefenderHealth}
- end.
-
--spec set_new_healths_in_query_state
- (
- non_neg_integer(),
- non_neg_integer(),
- query_state(),
- input()
- )
- -> query_state().
-set_new_healths_in_query_state
-(
- RemainingAttackerHealth,
- RemainingDefenderHealth,
- QueryState,
- Input
-) ->
- BattlemapInstance = QueryState#query_state.battlemap_instance,
- ControlledCharacterInstance = QueryState#query_state.character_instance,
- CharacterInstances =
- battlemap_instance:get_character_instances(BattlemapInstance),
- TargettedCharacterInstanceIX = Input#input.target_ix,
- TargettedCharacterInstance =
- array:get
- (
- TargettedCharacterInstanceIX,
- CharacterInstances
- ),
-
- QueryState#query_state
- {
- battlemap_instance =
- battlemap_instance:set_character_instances
- (
- array:set
- (
- TargettedCharacterInstanceIX,
- character_instance:set_current_health
- (
- RemainingDefenderHealth,
- TargettedCharacterInstance
- ),
- CharacterInstances
- ),
- BattlemapInstance
- ),
- character_instance =
- character_instance:set_current_health
- (
- RemainingAttackerHealth,
- ControlledCharacterInstance
- )
- }.
-
--spec handle_character_instance_attacking
- (
- query_state(),
- input()
- )
- -> {list(attack_desc()), query_state()}.
-handle_character_instance_attacking (QueryState, Input) ->
- BattlemapInstance = QueryState#query_state.battlemap_instance,
- ControlledCharacterInstance = QueryState#query_state.character_instance,
- ControlledCharacter =
- character_instance:get_character(ControlledCharacterInstance),
- ControlledCharacterStatistics =
- character:get_statistics(ControlledCharacter),
- TargettedCharacterInstance =
- array:get
- (
- Input#input.target_ix,
- battlemap_instance:get_character_instances(BattlemapInstance)
- ),
- TargettedCharacter =
- character_instance:get_character(TargettedCharacterInstance),
- TargettedCharacterStatistics = character:get_statistics(TargettedCharacter),
- RequiredRange =
- movement:steps_between
- (
- character_instance:get_location(ControlledCharacterInstance),
- character_instance:get_location(TargettedCharacterInstance)
- ),
- {AttackingWeaponID, _} = character:get_weapon_ids(ControlledCharacter),
- AttackingWeapon = weapon:from_id(AttackingWeaponID),
- {_, AttackingWeaponRange} = weapon:get_ranges(AttackingWeapon),
- {DefendingWeaponID, _} = character:get_weapon_ids(TargettedCharacter),
- DefendingWeapon = weapon:from_id(DefendingWeaponID),
- {DefendingWeaponDefRange, DefendingWeaponAtkRange} =
- weapon:get_ranges(DefendingWeapon),
-
- true = (RequiredRange =< AttackingWeaponRange),
-
- CanDefend =
- (
- (RequiredRange > DefendingWeaponDefRange)
- and
- (RequiredRange =< DefendingWeaponAtkRange)
- ),
- CanParry = (weapon:get_range_type(DefendingWeapon) == melee),
- Actions =
- case {CanDefend, CanParry} of
- {true, true} ->
- [{second, parry}, counter, {first, parry}];
- {true, false} ->
- [second, counter, first];
- {false, _} ->
- [second, first]
- end,
- Effects =
- handle_attacks
- (
- Actions,
- ControlledCharacterStatistics,
- TargettedCharacterStatistics,
- []
- ),
- {RemainingEffects, RemainingAttackerHealth, RemainingDefenderHealth} =
- apply_attacks_to_healths
- (
- Effects,
- character_instance:get_current_health(ControlledCharacterInstance),
- character_instance:get_current_health(TargettedCharacterInstance),
- []
- ),
-
- {
- RemainingEffects,
- set_new_healths_in_query_state
- (
- RemainingAttackerHealth,
- RemainingDefenderHealth,
- QueryState,
- Input
- )
- }.
diff --git a/src/struct/weapon.erl b/src/struct/weapon.erl
index d96886c..80cb925 100644
--- a/src/struct/weapon.erl
+++ b/src/struct/weapon.erl
@@ -55,6 +55,7 @@
[
random_id/0,
from_id/1,
+ can_parry/1,
apply_to_attributes/2
]
).
@@ -102,6 +103,9 @@ get_ranges (Wp) ->
get_damages (Wp) ->
damages_of_type(Wp#weapon.range_type, Wp#weapon.damage_mod).
+-spec can_parry (struct()) -> boolean().
+can_parry (Wp) -> (Wp#weapon.range_type == melee).
+
-spec from_id (id()) -> struct().
from_id (0) ->
#weapon{