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-426] Add Dungeon Mode #614

Merged
merged 14 commits into from
May 20, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
43 changes: 38 additions & 5 deletions apps/champions/lib/champions/battle.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,33 @@ defmodule Champions.Battle do

alias Champions.Battle.Simulator
alias GameBackend.Campaigns
alias GameBackend.Campaigns.SuperCampaignProgress
alias GameBackend.Campaigns.{Campaign, Level, SuperCampaign, SuperCampaignProgress}
alias GameBackend.Units
alias GameBackend.Users
alias GameBackend.Users.DungeonSettlementLevel
alias GameBackend.Users.User

@default_max_units 6

@doc """
Plays a level for a user, which means fighting its units with their selected ones.
Returns `:win` or `:loss` accordingly, and updates the user's progress if they win..
"""
def fight_level(user_id, level_id) do
with start_time <- :os.system_time(:millisecond),
{:user_exists, true} <- {:user_exists, Users.exists?(user_id)},
{:user_exists, {:ok, user}} <- {:user_exists, Users.get_user(user_id)},
{:level, {:ok, level}} <- {:level, Campaigns.get_level(level_id)},
{:super_campaign_progress, {:ok, %SuperCampaignProgress{level_id: current_level_id}}} <-
{:super_campaign_progress, Campaigns.get_super_campaign_progress(user_id, level.campaign.super_campaign_id)},
{:level_valid, true} <- {:level_valid, current_level_id == level_id} do
units = Units.get_selected_units(user_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
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
Expand All @@ -43,10 +54,32 @@ defmodule Champions.Battle do

response
else
{:user_exists, false} -> {:error, :user_not_found}
{: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}
end
end

defp level_valid?(
%Level{
id: id,
campaign: %Campaign{super_campaign: %SuperCampaign{name: "Dungeon"}},
level_number: level_number
},
current_level_id,
%User{dungeon_settlement_level: %DungeonSettlementLevel{max_dungeon: max_dungeon}}
) do
id == current_level_id && level_number <= max_dungeon
end

defp level_valid?(%Level{id: id}, current_level_id, _) do
id == current_level_id
end

# TODO: implement buffs [#CHoM-428]
defp apply_buffs(units, _user_id) do
units
end
end
24 changes: 20 additions & 4 deletions apps/game_backend/lib/game_backend/campaigns.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ defmodule GameBackend.Campaigns do
campaigns =
Repo.all(
from(c in Campaign,
preload: [levels: ^level_preload_query()],
preload: [:super_campaign, levels: ^level_preload_query()],
order_by: [asc: c.campaign_number]
)
)
Expand All @@ -26,7 +26,9 @@ defmodule GameBackend.Campaigns do
Get a campaign by id.
"""
def get_campaign(campaign_id) do
case Repo.one(from(c in Campaign, where: c.id == ^campaign_id, preload: [levels: ^level_preload_query()])) do
case Repo.one(
from(c in Campaign, where: c.id == ^campaign_id, preload: [:super_campaign, levels: ^level_preload_query()])
) do
nil -> {:error, :not_found}
campaign -> {:ok, Map.put(campaign, :levels, Enum.sort_by(campaign.levels, & &1.level_number))}
end
Expand Down Expand Up @@ -84,8 +86,8 @@ defmodule GameBackend.Campaigns do
level =
Repo.get(Level, level_id)
|> Repo.preload([
:campaign,
:currency_rewards,
campaign: :super_campaign,
units: [
:items,
character: [basic_skill: [mechanics: :apply_effects_to], ultimate_skill: [mechanics: :apply_effects_to]]
Expand All @@ -99,7 +101,21 @@ defmodule GameBackend.Campaigns do
Get all of a User's SuperCampaignProgresses.
"""
def get_user_super_campaign_progresses(user_id),
do: Repo.all(from(cp in SuperCampaignProgress, where: cp.user_id == ^user_id, preload: [:level]))
do: Repo.all(from(cp in SuperCampaignProgress, where: cp.user_id == ^user_id, preload: [:level, :super_campaign]))

@doc """
Get a super campaign by id.
"""
def get_super_campaign(super_campaign_id) do
Repo.get(SuperCampaign, super_campaign_id)
end

@doc """
Get a super campaign by name and game_id.
"""
def get_super_campaign_by_name_and_game(name, game_id) do
Repo.get_by(SuperCampaign, name: name, game_id: game_id)
end

@doc """
Get a campaign progress by user id and campaign id.
Expand Down
6 changes: 4 additions & 2 deletions apps/game_backend/lib/game_backend/campaigns/level.ex
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ defmodule GameBackend.Campaigns.Level do
field(:level_number, :integer)
field(:experience_reward, :integer)

belongs_to(:campaign, Campaign)
field(:max_units, :integer)
has_many(:units, Unit, foreign_key: :campaign_level_id)

belongs_to(:campaign, Campaign)
has_many(:currency_rewards, CurrencyReward)
has_many(:item_rewards, ItemReward)
has_many(:unit_rewards, UnitReward)
Expand All @@ -29,7 +31,7 @@ defmodule GameBackend.Campaigns.Level do
@doc false
def changeset(level, attrs \\ %{}) do
level
|> cast(attrs, [:game_id, :level_number, :campaign_id, :experience_reward])
|> cast(attrs, [:game_id, :level_number, :campaign_id, :experience_reward, :max_units])
|> cast_assoc(:units)
|> cast_assoc(:currency_rewards)
|> cast_assoc(:item_rewards)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
defmodule GameBackend.Repo.Migrations.AddDungeonFieldsToLevel do
use Ecto.Migration

def change do
alter(table(:levels)) do
add(:max_units, :integer)
end
end
end
17 changes: 14 additions & 3 deletions apps/gateway/lib/gateway/champions_socket_handler.ex
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ defmodule Gateway.ChampionsSocketHandler do
prepare_response({:error, reason}, nil)

{:ok, campaigns} ->
prepare_response(%{campaigns: campaigns}, :campaigns)
prepare_response(%{campaigns: Enum.map(campaigns, &prepare_campaign/1)}, :campaigns)
end
end

Expand All @@ -116,7 +116,9 @@ defmodule Gateway.ChampionsSocketHandler do
prepare_response({:error, reason}, nil)

{:ok, campaign} ->
prepare_response(campaign, :campaign)
campaign
|> prepare_campaign()
|> prepare_response(:campaign)
end
end

Expand Down Expand Up @@ -216,7 +218,7 @@ defmodule Gateway.ChampionsSocketHandler do
level_id: super_campaign_progress.level_id,
user_id: super_campaign_progress.user_id,
campaign_id: super_campaign_progress.level.campaign_id,
super_campaign_id: super_campaign_progress.super_campaign_id
super_campaign_name: super_campaign_progress.super_campaign.name
}
end)

Expand Down Expand Up @@ -244,6 +246,15 @@ defmodule Gateway.ChampionsSocketHandler do
defp handle(unknown_request),
do: Logger.warning("[Gateway.ChampionsSocketHandler] Received unknown request #{unknown_request}")

defp prepare_campaign(campaign) do
%{
id: campaign.id,
super_campaign_name: campaign.super_campaign.name,
campaign_number: campaign.campaign_number,
levels: campaign.levels
}
end

defp prepare_step(step) do
update_in(step, [:actions], fn actions ->
Enum.map(actions, &prepare_action/1)
Expand Down
4 changes: 2 additions & 2 deletions apps/gateway/lib/gateway/serialization/gateway.pb.ex
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ defmodule Gateway.Serialization.SuperCampaignProgress do
field(:user_id, 1, type: :string, json_name: "userId")
field(:campaign_id, 2, type: :string, json_name: "campaignId")
field(:level_id, 3, type: :string, json_name: "levelId")
field(:super_campaign_id, 4, type: :string, json_name: "superCampaignId")
field(:super_campaign_name, 4, type: :string, json_name: "superCampaignName")
end

defmodule Gateway.Serialization.AfkRewardRate do
Expand Down Expand Up @@ -616,7 +616,7 @@ defmodule Gateway.Serialization.Campaign do
use Protobuf, syntax: :proto3, protoc_gen_elixir_version: "0.12.0"

field(:id, 1, type: :string)
field(:super_campaign_id, 2, type: :string, json_name: "superCampaignId")
field(:super_campaign_name, 2, type: :string, json_name: "superCampaignName")
field(:campaign_number, 3, type: :uint32, json_name: "campaignNumber")
field(:levels, 4, repeated: true, type: Gateway.Serialization.Level)
end
Expand Down
37 changes: 29 additions & 8 deletions apps/gateway/test/champions_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -328,8 +328,15 @@ defmodule Gateway.Test.Champions do
# Register user
{:ok, user} = Users.register("battle_user")

# Get user's first SuperCampaignProgress
[super_campaign_progress | _] = user.super_campaign_progresses
# Get user's Main Campaign progress
main_super_campaign =
GameBackend.Campaigns.get_super_campaign_by_name_and_game(
"Main Campaign",
Utils.get_game_id(:champions_of_mirra)
)

{:ok, super_campaign_progress} =
GameBackend.Campaigns.get_super_campaign_progress(user.id, main_super_campaign.id)

# Get the SuperCampaignProgress' Level
level_id = super_campaign_progress.level_id
Expand Down Expand Up @@ -357,8 +364,15 @@ defmodule Gateway.Test.Champions do
GameBackend.Units.update_unit(unit, %{level: 9999})
end)

# Get user's first SuperCampaignProgress
[super_campaign_progress | _] = user.super_campaign_progresses
# Get user's progress in the main SuperCampaign
main_super_campaign =
GameBackend.Campaigns.get_super_campaign_by_name_and_game(
"Main Campaign",
Utils.get_game_id(:champions_of_mirra)
)

{:ok, super_campaign_progress} =
GameBackend.Campaigns.get_super_campaign_progress(user.id, main_super_campaign.id)

# Get the SuperCampaignProgress' Level
level_id = super_campaign_progress.level_id
Expand All @@ -376,7 +390,8 @@ defmodule Gateway.Test.Champions do

{:ok, advanced_user} = Users.get_user(user.id)

[advanced_super_campaign_progress | _] = advanced_user.super_campaign_progresses
{:ok, advanced_super_campaign_progress} =
GameBackend.Campaigns.get_super_campaign_progress(user.id, main_super_campaign.id)

assert user.id == advanced_user.id
assert advanced_super_campaign_progress.level_id != level_id
Expand All @@ -389,10 +404,16 @@ defmodule Gateway.Test.Champions do
# Register user
{:ok, user} = Users.register("invalid_battle_user")

# Get user's first SuperCampaignProgress
[super_campaign_progress | _] = user.super_campaign_progresses
# Get user's Main Campaign progress
main_super_campaign =
GameBackend.Campaigns.get_super_campaign_by_name_and_game(
"Main Campaign",
Utils.get_game_id(:champions_of_mirra)
)

{:ok, super_campaign_progress} =
GameBackend.Campaigns.get_super_campaign_progress(user.id, main_super_campaign.id)

# Get the level of the SuperCampaignProgress
next_level_id = super_campaign_progress.level_id

# Get a Level that is not the next one in the SuperCampaignProgress
Expand Down
4 changes: 2 additions & 2 deletions apps/serialization/gateway.proto
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ syntax = "proto3";
string user_id = 1;
string campaign_id = 2;
string level_id = 3;
string super_campaign_id = 4;
string super_campaign_name = 4;
}

message AfkRewardRate {
Expand Down Expand Up @@ -286,7 +286,7 @@ syntax = "proto3";

message Campaign {
string id = 1;
string super_campaign_id = 2;
string super_campaign_name = 2;
uint32 campaign_number = 3;
repeated Level levels = 4;
}
Expand Down
Loading
Loading