Skip to content

Commit

Permalink
[GH-431] Add currency cost to levels (#617)
Browse files Browse the repository at this point in the history
* Add currency cost to level relation

* Add currency costs to proto message

* substract currencies in battle

* Use a multi to run the battle and substract the currencies

* Add :can_afford false clause to with statement

* Remove unused alias

* Improve naming for the level field

* Regen protos

* Improve the way of creating level currency_rewards in seeds

* Improve new field naming

---------

Co-authored-by: lotuuu <[email protected]>
  • Loading branch information
ncontinanza and lotuuu authored May 21, 2024
1 parent f444a4e commit c78cff2
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 32 deletions.
42 changes: 28 additions & 14 deletions apps/champions/lib/champions/battle.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ defmodule Champions.Battle do

require Logger

alias Ecto.Multi
alias GameBackend.Users.Currencies
alias Champions.Battle.Simulator
alias GameBackend.Campaigns
alias GameBackend.Campaigns.{Campaign, Level, SuperCampaign, SuperCampaignProgress}
alias GameBackend.Repo
alias GameBackend.Units
alias GameBackend.Users
alias GameBackend.Users.DungeonSettlementLevel
Expand All @@ -27,38 +30,49 @@ defmodule Champions.Battle do
{:super_campaign_progress, Campaigns.get_super_campaign_progress(user_id, level.campaign.super_campaign_id)},
{:level_valid, true} <- {:level_valid, level_valid?(level, current_level_id, user)},
units <- Units.get_selected_units(user_id),
{:max_units_met, true} <- {:max_units_met, Enum.count(units) <= (level.max_units || @default_max_units)} do
{:max_units_met, true} <- {:max_units_met, Enum.count(units) <= (level.max_units || @default_max_units)},
{:can_afford, true} <- {:can_afford, Currencies.can_afford(user_id, level.attempt_cost)} do
units =
if level.campaign.super_campaign.name == "Dungeon" do
apply_buffs(units, user_id)
else
units
end

response =
case Simulator.run_battle(units, level.units) do
%{result: "team_1"} = result ->
# TODO: add rewards to response [CHoM-191]
case Champions.Campaigns.advance_level(user_id, level.campaign.super_campaign_id) do
{:ok, _changes} -> result
_error -> {:error, :failed_to_advance}
end

result ->
result
end
{:ok, response} =
Multi.new()
|> Multi.run(:substract_currencies, fn _repo, _changes ->
Currencies.substract_currencies(user_id, level.attempt_cost)
end)
|> Multi.run(:run_battle, fn _repo, _changes -> run_battle(user_id, level, units) end)
|> Repo.transaction()

end_time = :os.system_time(:millisecond)

Logger.info("Battle took #{end_time - start_time} miliseconds")

response
{:ok, response.run_battle}
else
{:user_exists, _} -> {:error, :user_not_found}
{:level, {:error, :not_found}} -> {:error, :level_not_found}
{:super_campaign_progress, {:error, :not_found}} -> {:error, :super_campaign_progress_not_found}
{:level_valid, false} -> {:error, :level_invalid}
{:max_units_met, false} -> {:error, :max_units_exceeded}
{:can_afford, false} -> {:error, :cant_afford}
end
end

defp run_battle(user_id, level, units) do
case Simulator.run_battle(units, level.units) do
%{result: "team_1"} = result ->
# TODO: add rewards to response [CHoM-191]
case Champions.Campaigns.advance_level(user_id, level.campaign.super_campaign_id) do
{:ok, _changes} -> {:ok, result}
_error -> {:error, :failed_to_advance}
end

result ->
{:ok, result}
end
end

Expand Down
3 changes: 3 additions & 0 deletions apps/game_backend/lib/game_backend/campaigns/level.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ defmodule GameBackend.Campaigns.Level do
use GameBackend.Schema
import Ecto.Changeset

alias GameBackend.Users.Currencies.CurrencyCost
alias GameBackend.Campaigns.Rewards.CurrencyReward
alias GameBackend.Campaigns.Rewards.UnitReward
alias GameBackend.Campaigns.Rewards.ItemReward
Expand All @@ -25,6 +26,7 @@ defmodule GameBackend.Campaigns.Level do
has_many(:item_rewards, ItemReward)
has_many(:unit_rewards, UnitReward)

embeds_many(:attempt_cost, CurrencyCost)
timestamps()
end

Expand All @@ -36,6 +38,7 @@ defmodule GameBackend.Campaigns.Level do
|> cast_assoc(:currency_rewards)
|> cast_assoc(:item_rewards)
|> cast_assoc(:unit_rewards)
|> cast_embed(:attempt_cost)
|> validate_required([:game_id, :level_number, :campaign_id])
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
defmodule GameBackend.Repo.Migrations.AddCurrencyCostToLevels do
use Ecto.Migration

def change do
alter table(:levels) do
add(:attempt_cost, {:array, :map})
end
end
end
2 changes: 1 addition & 1 deletion apps/gateway/lib/gateway/champions_socket_handler.ex
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ defmodule Gateway.ChampionsSocketHandler do
{:error, reason} ->
prepare_response({:error, reason}, nil)

battle_result ->
{:ok, battle_result} ->
battle_result
|> update_in([:steps], fn steps ->
Enum.map(steps, &prepare_step/1)
Expand Down
6 changes: 6 additions & 0 deletions apps/gateway/lib/gateway/serialization/gateway.pb.ex
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,12 @@ defmodule Gateway.Serialization.Level do
)

field(:experience_reward, 6, type: :uint32, json_name: "experienceReward")

field(:attempt_cost, 7,
repeated: true,
type: Gateway.Serialization.CurrencyCost,
json_name: "attemptCost"
)
end

defmodule Gateway.Serialization.CurrencyReward do
Expand Down
3 changes: 2 additions & 1 deletion apps/serialization/gateway.proto
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,8 @@ syntax = "proto3";
uint32 level_number = 3;
repeated Unit units = 4;
repeated CurrencyReward currency_rewards = 5;
uint32 experience_reward = 6;
uint32 experience_reward = 6;
repeated CurrencyCost attempt_cost = 7;
}

message CurrencyReward {
Expand Down
29 changes: 13 additions & 16 deletions priv/repo/seeds.exs
Original file line number Diff line number Diff line change
Expand Up @@ -199,11 +199,11 @@ levels =
end)
end)

{_, levels_without_units} =
{_, levels_without_embeds} =
Repo.insert_all(Level, levels, returning: [:id, :level_number, :campaign_id])

units =
Enum.flat_map(Enum.with_index(levels_without_units, 0), fn {level, level_index} ->
Enum.flat_map(Enum.with_index(levels_without_embeds, 0), fn {level, level_index} ->
campaign_number = Repo.get!(Campaign, level.campaign_id).campaign_number
campaign_rules = Enum.at(rules, campaign_number - 1)

Expand Down Expand Up @@ -247,27 +247,24 @@ Repo.insert_all(Unit, units, on_conflict: :nothing)
# Add the rewards of each level.
# The calculation of the `amount` field is done following the specification found in https://docs.google.com/spreadsheets/d/177mvJS75LecaAEpyYotQEcrmhGJWI424UnkE2JHLmyY
currency_rewards =
Enum.map(levels_without_units, fn level ->
%{
level_id: level.id,
amount: 10 * (20 + level.level_number),
currency_id: gold_currency.id,
inserted_at: NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second),
updated_at: NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
}
end)

currency_rewards =
currency_rewards ++
Enum.map(levels_without_units, fn level ->
Enum.flat_map(levels_without_embeds, fn level ->
[
%{
level_id: level.id,
amount: 10 * (20 + level.level_number),
currency_id: gold_currency.id,
inserted_at: NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second),
updated_at: NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
},
%{
level_id: level.id,
amount: (10 * (15 + level.level_number - 1) * 1.025) |> round(),
currency_id: hero_souls_currency.id,
inserted_at: NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second),
updated_at: NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
}
end)
]
end)

Repo.insert_all(CurrencyReward, currency_rewards, on_conflict: :nothing)

Expand Down

0 comments on commit c78cff2

Please sign in to comment.