summaryrefslogtreecommitdiff |
diff options
Diffstat (limited to 'src/query')
-rw-r--r-- | src/query/character_turn.erl | 200 | ||||
-rw-r--r-- | src/query/character_turn/handle_character_attacking_2.erl | 59 | ||||
-rw-r--r-- | src/query/character_turn/handle_character_instance_attacking_2.erl | 358 |
3 files changed, 469 insertions, 148 deletions
diff --git a/src/query/character_turn.erl b/src/query/character_turn.erl index d71c64a..19b6cff 100644 --- a/src/query/character_turn.erl +++ b/src/query/character_turn.erl @@ -12,9 +12,9 @@ player_id, session_token, battlemap_instance_id, - character_instance_id, + character_instance_ix, path, - target_id + target_ix } ). @@ -23,8 +23,17 @@ query_state, { battlemap_instance, - character_instance, - rolls + character_instance + } +). + +-record +( + query_result, + { + is_new_turn, + updated_character_instance_ixs, + updated_battlemap_instance } ). @@ -38,16 +47,16 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% parse_input (Req) -> JSONReqMap = jiffy:decode(Req, [return_maps]), - CharacterInstanceID = binary_to_integer(maps:get(<<"cid">>, JSONReqMap)), - TargetID = binary_to_integer(maps:get(<<"tid">>, JSONReqMap)), + CharacterInstanceIX = binary_to_integer(maps:get(<<"cix">>, JSONReqMap)), + TargetIX = binary_to_integer(maps:get(<<"tix">>, JSONReqMap)), #input { player_id = maps:get(<<"pid">>, JSONReqMap), session_token = maps:get(<<"stk">>, JSONReqMap), battlemap_instance_id = maps:get(<<"bmp">>, JSONReqMap), - character_instance_id = CharacterInstanceID, + character_instance_ix = CharacterInstanceIX, path = maps:get(<<"p">>, JSONReqMap), - target_id = TargetID + target_ix = TargetIX }. fetch_data (Input) -> @@ -61,17 +70,16 @@ fetch_data (Input) -> CharacterInstance = array:get ( - Input#input.character_instance_id, + Input#input.character_instance_ix, battlemap_instance:get_character_instances(BattlemapInstance) ), #query_state { battlemap_instance = BattlemapInstance, - character_instance = CharacterInstance, - rolls = [] + character_instance = CharacterInstance }. -assert_character_can_be_played (QueryState, Input) -> +assert_character_instance_can_be_played (QueryState, Input) -> %%% Var BattlemapInstance = QueryState#query_state.battlemap_instance, PlayerID = Input#input.player_id, @@ -80,20 +88,20 @@ assert_character_can_be_played (QueryState, Input) -> PlayerID = arrays:get ( - player_turn:get_player_id + player_turn:get_player_ix ( battlemap_instance:get_player_turn(BattlemapInstance) ), - battlemap_instance:get_players(BattlemapInstance) + battlemap_instance:get_player_ids(BattlemapInstance) ), PlayerID = - character:get_owner + character:get_owner_id ( character_instance:get_character(ControlledCharacterInstance) ), - true = character_instance:is_active(ControlledCharacterInstance). + true = character_instance:get_is_active(ControlledCharacterInstance). -handle_character_moving (QueryState, Input) -> +handle_character_instance_moving (QueryState, Input) -> BattlemapInstance = QueryState#query_state.battlemap_instance, ControlledCharacterInstance = QueryState#query_state.character_instance, ControlledCharacter = @@ -130,10 +138,12 @@ handle_character_moving (QueryState, Input) -> ) }. -handle_character_switching_weapons (QueryState) -> +handle_character_instance_switching_weapons (QueryState) -> ControlledCharacterInstance = QueryState#query_state.character_instance, ControlledCharacter = character_instance:get_character(ControlledCharacterInstance), + {PrimaryWeapon, SecondaryWeapon} = + character:get_weapons(ControlledCharacter), QueryState#query_state { character_instance = @@ -141,20 +151,17 @@ handle_character_switching_weapons (QueryState) -> ( character:set_weapons ( - weapon_set:switch - ( - character:get_weapons(ControlledCharacter) - ), + {SecondaryWeapon, PrimaryWeapon}, ControlledCharacter ), ControlledCharacterInstance ) }. --include("character_turn/handle_character_attacking_2.erl"). +-include("character_turn/handle_character_instance_attacking_2.erl"). get_type_of_turn (Input) -> - case {Input#input.path, Input#input.target_id} of + case {Input#input.path, Input#input.target_ix} of {[], -1} -> [nothing, nothing]; {[], _} -> [nothing, attack]; {[<<"S">>], -1} -> [switch, nothing]; @@ -174,131 +181,137 @@ finalize_character_instance (QueryState, Input) -> QueryState#query_state { battlemap_instance = - battlemap_instance:set_characters + battlemap_instance:set_character_instances ( array:set ( - Input#input.character_instance_id, + Input#input.character_instance_ix, FinalizedCharacterInstance, - battlemap_instance:get_characters(BattlemapInstance) + battlemap_instance:get_character_instances(BattlemapInstance) ), BattlemapInstance ), character_instance = FinalizedCharacterInstance }. -unnamed_function (IDs, CharacterInstances, _Owner, -1) -> - {IDs, CharacterInstances}; -unnamed_function (IDs, CharacterInstances, Owner, I) -> - CharacterInstance = array:get(I, CharacterInstances), +activate_relevant_character_instances (IXs, CharacterInstances, _Owner, -1) -> + {IXs, CharacterInstances}; +activate_relevant_character_instances (IXs, CharacterInstances, Owner, IX) -> + CharacterInstance = array:get(IX, CharacterInstances), Character = character_instance:get_character(CharacterInstance), - case character:get_owner(Character) of + case character:get_owner_id(Character) of OwnerID when (OwnerID == Owner) -> - unnamed_function + activate_relevant_character_instances ( - [I|IDs], + [IX|IXs], array:set ( - I, + IX, character_instance:set_is_active(true, CharacterInstance), CharacterInstances ), Owner, - (I - 1) + (IX - 1) ); _ -> - unnamed_function + activate_relevant_character_instances ( - IDs, + IXs, CharacterInstances, Owner, - (I - 1) + (IX - 1) ) end. start_next_players_turn (QueryState, Input) -> BattlemapInstance = QueryState#query_state.battlemap_instance, - Players = battlemap_instance:get_players(BattlemapInstance), + PlayerIDs = battlemap_instance:get_player_ids(BattlemapInstance), PlayerTurn = battlemap_instance:get_player_turn(BattlemapInstance), - CurrentPlayerID = player_turn:get_player_id(PlayerTurn), + CurrentPlayerIX = player_turn:get_player_ix(PlayerTurn), CurrentTurnNumber = player_turn:get_number(PlayerTurn), CharacterInstances = battlemap_instance:get_character_instances(BattlemapInstance), - NextPlayer = ((CurrentPlayerID + 1) rem (array:size(Players))), + NextPlayerIX = ((CurrentPlayerIX + 1) rem (array:size(PlayerIDs))), NextPlayerTurn = player_turn:new ( - case NextPlayer of + case NextPlayerIX of 0 -> (CurrentTurnNumber + 1); _ -> CurrentTurnNumber end, - NextPlayer + NextPlayerIX ), - {ActivatedCharacterInstancesID, UpdatedCharacterInstances} = - unnamed_function + {ActivatedCharacterInstanceIXs, UpdatedCharacterInstances} = + activate_relevant_character_instances ( [], CharacterInstances, - array:get(NextPlayer, Players), + array:get(NextPlayerIX, PlayerIDs), array:size(CharacterInstances) ), - { - ActivatedCharacterInstancesID, - QueryState#query_state - { - battlemap_instance = - battlemap_instance:set_character_instances - ( - UpdatedCharacterInstances, - battlemap_instance:set_player_turn - ( - NextPlayerTurn, - BattlemapInstance - ) - ) - } - }. + UpdatedBattlemapInstance = + battlemap_instance:set_character_instances + ( + UpdatedCharacterInstances, + battlemap_instance:set_player_turn + ( + NextPlayerTurn, + BattlemapInstance + ) + ), + {ActivatedCharacterInstanceIXs, UpdatedBattlemapInstance}. finalize_character_turn (QueryState, Input) -> BattlemapInstance = QueryState#query_state.battlemap_instance, - Players = battlemap_instance:get_players(BattlemapInstance), + CharacterInstances = + battlemap_instance:get_character_instances(BattlemapInstance), - CharacterInstanceRemains = + AnActiveCharacterInstanceRemains = array:foldl ( - fun (_I, CharacterInstance, Prev) -> + fun (_IX, CharacterInstance, Prev) -> (Prev or character_instance:get_is_active(CharacterInstance)) end, - Players + CharacterInstances ), - case CharacterInstanceRemains of - true -> {false, {[], QueryState}}; - false -> {true, start_next_players_turn(QueryState, Input)} + case AnActiveCharacterInstanceRemains of + true -> + #query_result + { + is_new_turn = false, + updated_character_instance_ixs = [], + updated_battlemap_instance = BattlemapInstance + }; + false -> + {UpdatedCharacterInstanceIXs, UpdatedBattlemapInstance} = + start_next_players_turn(QueryState, Input), + #query_result + { + is_new_turn = true, + updated_character_instance_ixs = UpdatedCharacterInstanceIXs, + updated_battlemap_instance = UpdatedBattlemapInstance + } end. -play (QueryState, [], Input) -> - finalize_character_turn - ( - finalize_character_instance(QueryState, Input), - Input - ); +play (QueryState, [], _Input) -> + QueryState; play (QueryState, [nothing|Next], Input) -> play(QueryState, Next, Input); play (QueryState, [move|Next], Input) -> play ( - handle_character_moving(QueryState, Input), + handle_character_instance_moving(QueryState, Input), Next, Input ); play (QueryState, [switch|Next], Input) -> play ( - handle_character_switching_weapons(QueryState), + handle_character_instance_switching_weapons(QueryState), Next, Input ); @@ -306,32 +319,41 @@ play (QueryState, [switch|Next], Input) -> play (QueryState, [attack|Next], Input) -> play ( - handle_character_attacking(QueryState, Input), + handle_character_instance_attacking(QueryState, Input), Next, Input ). -send_to_database (QueryState, TurnType, Input) -> +send_to_database (QueryResult, TurnType, Input) -> unimplemented. -update_cache (QueryState, TurnType, Input) -> +update_cache (QueryResult, TurnType, Input) -> unimplemented. -generate_reply (QueryState, TurnType, Input) -> +generate_reply (QueryResult, TurnType, Input) -> jiffy:encode([[<<"ok">>]]). handle (Req) -> Input = parse_input(Req), security:assert_identity(Req#input.player_id, Req#input.session_token), + security:lock_queries(Req#input.player_id), QueryState = fetch_data(Input), - assert_character_can_be_played(Input, QueryState), + assert_character_instance_can_be_played(Input, QueryState), TurnType = get_type_of_turn(Input), - {IsNewTurn, {UpdatedCharacterInstancesID, PostPlayQueryState}} = - play(QueryState, TurnType, Input), - send_to_database(PostPlayQueryState, TurnType, Input), - update_cache(PostPlayQueryState, TurnType, Input), - generate_reply(PostPlayQueryState, TurnType, Input). - + QueryResult = + finalize_character_turn + ( + finalize_character_instance + ( + play(QueryState, TurnType, Input), + Input + ), + Input + ), + send_to_database(QueryResult, TurnType, Input), + update_cache(QueryResult, TurnType, Input), + security:unlock_queries(Req#input.player_id), + generate_reply(QueryResult, TurnType, Input). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/src/query/character_turn/handle_character_attacking_2.erl b/src/query/character_turn/handle_character_attacking_2.erl deleted file mode 100644 index 3fd2687..0000000 --- a/src/query/character_turn/handle_character_attacking_2.erl +++ /dev/null @@ -1,59 +0,0 @@ -roll_hits (AttackerStatistics, DefenderStatistics) -> - MissChance = - max - ( - 0, - ( - statistics:get_dodges(DefenderStatistics) - - - statistics:get_accuracy(AttackerStatistics) - ) - ), - case roll:percentage() of - X when (X < MissChance) -> misses; - X when (X < (MissChance * 2)) -> grazes; - _ -> hits - end. - -roll_damage (AttackerStatistics, _DefenderStatistics) -> - {MinimumDamage, MaximumDamage} = statistics:get_damages(AttackerStatistics), - MaximumRoll = max(1, MaximumDamage - MinimumDamage), - MinimumDamage + (rand:uniform(MaximumRoll) - 1). - -handle_character_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_id, - battlemap_instance:get_characters(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), - {DefendingWeaponRange, _} = weapon:get_ranges(DefendingWeapon), - - true = (RequiredRange =< AttackingWeaponRange), - - {Rolls, HealthMod} = - handle_attack - ( - ControlledCharacterStatistics, - TargettedCharacterStatistics - ). diff --git a/src/query/character_turn/handle_character_instance_attacking_2.erl b/src/query/character_turn/handle_character_instance_attacking_2.erl new file mode 100644 index 0000000..be2ac99 --- /dev/null +++ b/src/query/character_turn/handle_character_instance_attacking_2.erl @@ -0,0 +1,358 @@ +roll_hits (AttackerStatistics, DefenderStatistics) -> + MissChance = + max + ( + 0, + ( + statistics:get_dodges(DefenderStatistics) + - + statistics:get_accuracy(AttackerStatistics) + ) + ), + case roll:percentage() of + X when (X =< MissChance) -> misses; + X when (X =< (MissChance * 2)) -> grazes; + _ -> hits + end. + +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. + +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, + Critical, + Damage + } + end. + +handle_parry (AttackerStatistics, DefenderStatistics) -> + ParryChance = statistics:get_parries(DefenderStatistics), + case roll:percentage() of + X when (X =< ParryChance) -> + [{parry, handle_attack(DefenderStatistics, AttackerStatistics)}]; + _ -> + [] + end. + +handle_attacks ([], _AttackerStatistics, _DefenderStatistics, Results) -> + Results; +handle_attacks +( + [nothing|Next], + AttackerStatistics, + DefenderStatistics, + Results +) -> + handle_attacks + ( + Next, + AttackerStatistics, + DefenderStatistics, + Results + ); +handle_attacks +( + [first|Next], + AttackerStatistics, + DefenderStatistics, + Results +) -> + handle_attacks + ( + Next, + AttackerStatistics, + DefenderStatistics, + [ + { + first, + handle_attack(AttackerStatistics, DefenderStatistics) + } + | + Results + ] + ); +handle_attacks +( + [second|Next], + AttackerStatistics, + DefenderStatistics, + Results +) -> + handle_attacks + ( + Next, + AttackerStatistics, + DefenderStatistics, + [ + { + second, + handle_attack(AttackerStatistics, DefenderStatistics) + } + | + Results + ] + ); +handle_attacks +( + [parry|Next], + AttackerStatistics, + DefenderStatistics, + Results +) -> + handle_attacks + ( + Next, + AttackerStatistics, + DefenderStatistics, + ( + handle_parry(AttackerStatistics, DefenderStatistics) + ++ + Results + ) + ); +handle_attacks +( + [counter|Next], + AttackerStatistics, + DefenderStatistics, + Results +) -> + handle_attacks + ( + Next, + AttackerStatistics, + DefenderStatistics, + [ + { + counter, + handle_attack(DefenderStatistics, AttackerStatistics) + } + | + Results + ] + ). + +apply_attacks_to_healths ([], AttackerHealth, DefenderHealth, ValidEffects) -> + {ValidEffects, AttackerHealth, DefenderHealth}; +apply_attacks_to_healths +( + [{first, Effect}|Next], + AttackerHealth, + DefenderHealth, + ValidEffects +) -> + {_Hit, _Critical, Damage} = Effect, + case (AttackerHealth > 0) of + true -> + apply_attacks_to_healths + ( + Next, + AttackerHealth, + max(0, (DefenderHealth - Damage)), + [{first, Effect}|ValidEffects] + ); + false -> + ValidEffects + end; +apply_attacks_to_healths +( + [{second, Effect}|Next], + AttackerHealth, + DefenderHealth, + ValidEffects +) -> + {_Hit, _Critical, Damage} = Effect, + case (AttackerHealth > 0) of + true -> + apply_attacks_to_healths + ( + Next, + AttackerHealth, + max(0, (DefenderHealth - Damage)), + [{second, Effect}|ValidEffects] + ); + false -> + ValidEffects + end; +apply_attacks_to_healths +( + [{counter, Effect}|Next], + AttackerHealth, + DefenderHealth, + ValidEffects +) -> + {_Hit, _Critical, Damage} = Effect, + case (DefenderHealth > 0) of + true -> + apply_attacks_to_healths + ( + Next, + max(0, (AttackerHealth - Damage)), + DefenderHealth, + [{counter, Effect}|ValidEffects] + ); + false -> + ValidEffects + end; +apply_attacks_to_healths +( + [{parry, Effect}|Next], + AttackerHealth, + DefenderHealth, + ValidEffects +) -> + {_Hit, _Critical, Damage} = Effect, + case (DefenderHealth > 0) of + true -> + apply_attacks_to_healths + ( + Next, + max(0, (AttackerHealth - Damage)), + DefenderHealth, + [{parry, Effect}|ValidEffects] + ); + false -> + ValidEffects + end. + +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 + ( + TargettedCharacterInstance, + RemainingDefenderHealth + ) + ) + ), + character_instance = + character_instance:set_current_health + ( + ControlledCharacterInstance, + RemainingAttackerHealth + ) + }. + +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, counter, parry, first]; + {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 + ( + QueryState, + RemainingAttackerHealth, + RemainingDefenderHealth, + Input + ) + }. |