Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GH-852] Configurator: Migrate effects config #856

Merged
merged 20 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 43 additions & 18 deletions apps/arena/lib/arena/configuration.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,9 @@ defmodule Arena.Configuration do
end

def get_game_config() do
{:ok, config_json} =
Application.app_dir(:arena, "priv/config.json")
|> File.read()

config = Jason.decode!(config_json, [{:keys, :atoms}])
client_config = get_client_config()

config
|> Map.merge(get_current_game_configuration())
get_current_game_configuration()
|> Map.put(:client_config, client_config)
end

Expand Down Expand Up @@ -69,21 +63,32 @@ defmodule Arena.Configuration do
end)
end

defp parse_items_config(items) do
Enum.map(items, fn item ->
%{
item
| effect: parse_effect(item.effect),
radius: maybe_to_float(item.radius),
mechanics: parse_mechanics_config(item.mechanics)
}
end)
end

defp parse_skill_config(%{cooldown_mechanism: "stamina", stamina_cost: cost} = skill_config) when cost >= 0 do
skill_config = parse_combo_config(skill_config)
mechanics = parse_mechanics_config(skill_config.mechanics)
%{skill_config | mechanics: mechanics}
%{skill_config | mechanics: mechanics, effect_to_apply: parse_effect(skill_config.effect_to_apply)}
end

defp parse_skill_config(%{cooldown_mechanism: "time", cooldown_ms: cooldown} = skill_config) when cooldown >= 0 do
skill_config = parse_combo_config(skill_config)
mechanics = parse_mechanics_config(skill_config.mechanics)
%{skill_config | mechanics: mechanics}
%{skill_config | mechanics: mechanics, effect_to_apply: parse_effect(skill_config.effect_to_apply)}
end

defp parse_skill_config(%{cooldown_mechanism: "mana", mana_cost: cost} = skill_config) when cost >= 0 do
mechanics = parse_mechanics_config(skill_config.mechanics)
%{skill_config | mechanics: mechanics}
%{skill_config | mechanics: mechanics, effect_to_apply: parse_effect(skill_config.effect_to_apply)}
end

defp parse_skill_config(skill_config) do
Expand Down Expand Up @@ -156,7 +161,9 @@ defmodule Arena.Configuration do
speed: maybe_to_float(mechanic.speed),
on_arrival_mechanic: parse_mechanic_config(mechanic.on_arrival_mechanic),
on_explode_mechanics: parse_mechanics_config(mechanic.on_explode_mechanics),
parent_mechanic: parse_mechanic_config(mechanic.parent_mechanic)
parent_mechanic: parse_mechanic_config(mechanic.parent_mechanic),
effect: parse_effect(mechanic.effect),
on_collide_effects: parse_on_collide_effects(mechanic.on_collide_effects)
}
end

Expand Down Expand Up @@ -210,13 +217,31 @@ defmodule Arena.Configuration do
%{mechanics | polygon_hit: %{polygon_hit | vertices: Enum.map(polygon_hit.vertices, &parse_position/1)}}
end

defp parse_items_config(items) do
Enum.map(items, fn item ->
%{
item
| radius: maybe_to_float(item.radius),
mechanics: parse_mechanics_config(item.mechanics)
}
defp parse_on_collide_effects(nil) do
nil
end

defp parse_on_collide_effects(on_collide_effects) do
%{
on_collide_effects
| effect: parse_effect(on_collide_effects.effect)
}
end

defp parse_effect(nil) do
nil
end

defp parse_effect(effect) do
Map.update!(effect, :effect_mechanics, fn effect_mechanics ->
Enum.map(effect_mechanics, fn effect_mechanic ->
%{
effect_mechanic
| modifier: maybe_to_float(effect_mechanic.modifier),
force: maybe_to_float(effect_mechanic.force),
stat_multiplier: maybe_to_float(effect_mechanic.stat_multiplier)
}
end)
end)
end

Expand Down
6 changes: 3 additions & 3 deletions apps/arena/lib/arena/entities.ex
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ defmodule Arena.Entities do
remove_on_collision: config_params.remove_on_collision,
on_explode_mechanics: Map.get(config_params, :on_explode_mechanics),
pull_immunity: true,
on_collide_effects: Map.get(config_params, :on_collide_effects)
on_collide_effect: Map.get(config_params, :on_collide_effects)
},
collides_with: []
}
Expand Down Expand Up @@ -177,7 +177,7 @@ defmodule Arena.Entities do
},
is_moving: false,
aditional_info: %{
effects_to_apply: pool_params.effects_to_apply,
effect_to_apply: pool_params.effect,
owner_id: pool_params.owner_id,
effects: [],
stat_multiplier: 0,
Expand Down Expand Up @@ -205,7 +205,7 @@ defmodule Arena.Entities do
is_moving: false,
aditional_info: %{
name: config.name,
effects: config.effects,
effect: config.effect,
mechanics: config.mechanics,
pull_immunity: true
}
Expand Down
83 changes: 48 additions & 35 deletions apps/arena/lib/arena/game/effect.ex
Original file line number Diff line number Diff line change
Expand Up @@ -82,68 +82,53 @@ defmodule Arena.Game.Effect do
end)
end

defp apply_stat_modifier(player, {:damage_change, damage_change}) do
defp apply_stat_modifier(player, %{name: "damage_change"} = damage_change) do
update_in(player, [:aditional_info, :bonus_damage], fn bonus_damage -> bonus_damage + damage_change.modifier end)
end

defp apply_stat_modifier(player, {:defense_change, defense_change}) do
defp apply_stat_modifier(player, %{name: "defense_change"} = defense_change) do
update_in(player, [:aditional_info, :bonus_defense], fn bonus_defense ->
min(1.0, bonus_defense + defense_change.modifier)
end)
end

defp apply_stat_modifier(player, {:reduce_stamina_interval, reduce_stamina_interval}) do
defp apply_stat_modifier(player, %{name: "reduce_stamina_interval"} = reduce_stamina_interval) do
stamina_speedup_by =
(player.aditional_info.stamina_interval * reduce_stamina_interval.decrease_by)
(player.aditional_info.stamina_interval * reduce_stamina_interval.modifier)
|> round()

new_stamina_interval = player.aditional_info.stamina_interval - stamina_speedup_by

put_in(player, [:aditional_info, :stamina_interval], new_stamina_interval)
end

defp apply_stat_modifier(player, {:reduce_cooldowns_duration, reduce_cooldowns_duration}) do
put_in(player, [:aditional_info, :cooldown_multiplier], reduce_cooldowns_duration.multiplier)
defp apply_stat_modifier(player, %{name: "reduce_cooldowns_duration"} = reduce_cooldowns_duration) do
put_in(player, [:aditional_info, :cooldown_multiplier], reduce_cooldowns_duration.modifier)
end

defp apply_stat_modifier(player, {:speed_boost, speed_boost}) do
defp apply_stat_modifier(player, %{name: "speed_boost"} = speed_boost) do
case player.aditional_info.forced_movement do
true -> player
false -> %{player | speed: player.speed * (1 + speed_boost.modifier)}
end
end

defp apply_stat_modifier(player, {:modify_radius, modify_radius}) do
defp apply_stat_modifier(player, %{name: "modify_radius"} = modify_radius) do
%{player | radius: player.radius * (1 + modify_radius.modifier)}
end

defp apply_stat_modifier(player, {:damage_immunity, _damage_immunity}) do
defp apply_stat_modifier(player, %{name: "damage_immunity"} = _damage_immunity) do
put_in(player, [:aditional_info, :damage_immunity], true)
end

defp apply_stat_modifier(player, {:pull_immunity, _damage_immunity}) do
defp apply_stat_modifier(player, %{name: "pull_immunity"} = _damage_immunity) do
put_in(player, [:aditional_info, :pull_immunity], true)
end

defp apply_stat_modifier(player, _) do
player
end

@doc """
This function finds an updates the given attributes of an effect in a player list of effects
"""
def put_in_effect(player, effect, keys, value) do
update_in(player, [:aditional_info, :effects], fn effects ->
Enum.map(effects, fn current_effect ->
if current_effect.id == effect.id do
put_in(current_effect, keys, value)
else
current_effect
end
end)
end)
end

@doc """
Receives the game state.
Gets the desired entities to apply effects to.
Expand All @@ -168,24 +153,52 @@ defmodule Arena.Game.Effect do
defp apply_effect_mechanic(entity, effect, game_state) do
now = System.monotonic_time(:millisecond)

Enum.reduce(effect.effect_mechanics, entity, fn {mechanic_name, mechanic_params} = mechanic, entity ->
Enum.reduce(effect.effect_mechanics, entity, fn mechanic, entity ->
execute_multiple_times? =
mechanic_params.execute_multiple_times or is_nil(Map.get(mechanic_params, :last_application_time))
mechanic.execute_multiple_times or is_nil(Map.get(mechanic, :last_application_time))

enough_time_passed? =
is_nil(Map.get(mechanic_params, :last_application_time)) or
now - Map.get(mechanic_params, :last_application_time) >= mechanic_params.effect_delay_ms
is_nil(Map.get(mechanic, :last_application_time)) or
now - Map.get(mechanic, :last_application_time) >= mechanic.effect_delay_ms

if execute_multiple_times? and enough_time_passed? do
do_effect_mechanics(game_state, entity, effect, mechanic)
|> put_in_effect(effect, [:effect_mechanics, mechanic_name, :last_application_time], now)
|> update_effect_mechanic_last_application_time(effect, mechanic, now)
else
entity
end
end)
end

defp do_effect_mechanics(game_state, entity, effect, {:pull, pull_params}) do
@doc """
This function finds an updates the given attributes of an effect in a player list of effects
"""
def update_effect_mechanic_last_application_time(player, effect, mechanic, now) do
update_in(player, [:aditional_info, :effects], fn effects ->
Enum.map(effects, fn current_effect ->
if current_effect.id == effect.id do
update_effect_mechanic_value_in_effect(effect, mechanic, :last_application_time, now)
else
current_effect
end
end)
end)
end

defp update_effect_mechanic_value_in_effect(effect, mechanic, key, value) do
effect
|> update_in([:effect_mechanics], fn effect_mechanics ->
Enum.map(effect_mechanics, fn effect_mechanic ->
if effect_mechanic.name == mechanic.name do
Map.put(effect_mechanic, key, value)
else
effect_mechanic
end
end)
end)
end

defp do_effect_mechanics(game_state, entity, effect, %{name: "pull"} = pull_params) do
case Map.get(game_state.pools, effect.owner_id) do
nil ->
entity
Expand Down Expand Up @@ -215,7 +228,7 @@ defmodule Arena.Game.Effect do
end
end

defp do_effect_mechanics(game_state, entity, effect, {:damage, damage_params}) do
defp do_effect_mechanics(game_state, entity, effect, %{name: "damage"} = damage_params) do
# TODO not all effects may come from pools entities, maybe we should update this when we implement other skills that
# applies this effect
Map.get(game_state.pools, effect.owner_id)
Expand All @@ -233,7 +246,7 @@ defmodule Arena.Game.Effect do
end
end

defp do_effect_mechanics(game_state, entity, _effect, {:buff_pool, buff_attributes}) do
defp do_effect_mechanics(game_state, entity, _effect, %{name: "buff_pool"} = buff_attributes) do
Map.get(game_state.pools, entity.id)
|> case do
nil ->
Expand All @@ -253,11 +266,11 @@ defmodule Arena.Game.Effect do
end
end

defp do_effect_mechanics(_game_state, entity, _effect, {:refresh_stamina, _refresh_stamina}) do
defp do_effect_mechanics(_game_state, entity, _effect, %{name: "refresh_stamina"} = _refresh_stamina) do
Entities.refresh_stamina(entity)
end

defp do_effect_mechanics(_game_state, entity, _effect, {:refresh_cooldowns, _refresh_cooldowns}) do
defp do_effect_mechanics(_game_state, entity, _effect, %{name: "refresh_cooldowns"} = _refresh_cooldowns) do
Entities.refresh_cooldowns(entity)
end

Expand Down
32 changes: 15 additions & 17 deletions apps/arena/lib/arena/game/player.ex
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ defmodule Arena.Game.Player do

Process.send_after(
self(),
{:delayed_effect_application, player.id, Map.get(skill, :effects_to_apply), skill.execution_duration_ms},
{:delayed_effect_application, player.id, Map.get(skill, :effect_to_apply), skill.execution_duration_ms},
skill.activation_delay_ms
)

Expand Down Expand Up @@ -361,19 +361,15 @@ defmodule Arena.Game.Player do
player.aditional_info.inventory != nil
end

def use_item(player, game_state, game_config) do
def use_item(player, game_state) do
case player.aditional_info.inventory do
nil ->
game_state

item ->
game_state =
Enum.reduce(item.effects, game_state, fn effect_name, game_state_acc ->
effect = Enum.find(game_config.effects, fn %{name: name} -> name == effect_name end)

Effect.put_effect_to_entity(game_state_acc, player, player.id, effect)
|> maybe_update_player_item_effects_expires_at(player, effect)
end)
Effect.put_effect_to_entity(game_state, player, player.id, item.effect)
|> maybe_update_player_item_effects_expires_at(player, item.effect)
|> put_in([:players, player.id, :aditional_info, :inventory], nil)

Item.do_mechanics(game_state, player, item.mechanics)
Expand All @@ -383,7 +379,7 @@ defmodule Arena.Game.Player do
def invisible?(player) do
get_in(player, [:aditional_info, :effects])
|> Enum.any?(fn effect ->
Enum.any?(effect.effect_mechanics, fn {mechanic, _} -> mechanic == :invisible end)
Enum.any?(effect.effect_mechanics, fn mechanic -> mechanic.name == "invisible" end)
end)
end

Expand Down Expand Up @@ -594,16 +590,18 @@ defmodule Arena.Game.Player do
duration_ms: skill.execution_duration_ms,
remove_on_action: false,
one_time_application: true,
effect_mechanics: %{
damage_immunity: %{
execute_multiple_times: false,
effect_delay_ms: 0
effect_mechanics: [
%{
name: "damage_immunity",
effect_delay_ms: 0,
execute_multiple_times: false
},
pull_immunity: %{
execute_multiple_times: false,
effect_delay_ms: 0
%{
name: "pull_immunity",
effect_delay_ms: 0,
execute_multiple_times: false
}
}
]
}

player = Map.get(game_state.players, player_id)
Expand Down
10 changes: 2 additions & 8 deletions apps/arena/lib/arena/game/skill.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ defmodule Arena.Game.Skill do
@moduledoc """
Module for handling skills
"""
alias Arena.GameUpdater
alias Arena.Game.Effect
alias Arena.{Entities, Utils}
alias Arena.Game.{Player, Crate}
Expand Down Expand Up @@ -322,13 +321,8 @@ defmodule Arena.Game.Skill do
deal_damage_to_game_entities(game_state, entity_player_owner, polygon_damage_area, polygon_hit.damage)
end

def handle_skill_effects(game_state, player, effects, execution_duration_ms, game_config) do
effects_to_apply =
GameUpdater.get_effects_from_config(effects, game_config)

Enum.reduce(effects_to_apply, game_state, fn effect, game_state ->
Effect.put_effect_to_entity(game_state, player, player.id, execution_duration_ms, effect)
end)
def handle_skill_effects(game_state, player, effect, execution_duration_ms) do
Effect.put_effect_to_entity(game_state, player, player.id, execution_duration_ms, effect)
end

defp calculate_angle_directions(amount, angle_between, base_direction) do
Expand Down
Loading
Loading