Skip to content
This repository has been archived by the owner on Aug 26, 2024. It is now read-only.

Opponent character changes damage taken #28

Merged
merged 2 commits into from
Apr 3, 2018
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
8 changes: 6 additions & 2 deletions lib/data/damage_type.ex
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,20 @@ defmodule Data.DamageType do
field(:key, :string)
field(:stat_modifier, Stats.Type)
field(:boost_ratio, :integer, default: 20)
field(:reverse_stat, Stats.Type)
field(:reverse_boost, :integer, default: 20)

timestamps()
end

def changeset(struct, params) do
struct
|> cast(params, [:key, :stat_modifier, :boost_ratio])
|> validate_required([:key, :stat_modifier, :boost_ratio])
|> cast(params, [:key, :stat_modifier, :boost_ratio, :reverse_stat, :reverse_boost])
|> validate_required([:key, :stat_modifier, :boost_ratio, :reverse_stat, :reverse_boost])
|> validate_inclusion(:stat_modifier, Stats.basic_fields())
|> validate_number(:boost_ratio, greater_than_or_equal_to: 0, less_than_or_equal_to: 100)
|> validate_inclusion(:reverse_stat, Stats.basic_fields())
|> validate_number(:reverse_boost, greater_than_or_equal_to: 0, less_than_or_equal_to: 100)
|> unique_constraint(:key)
end
end
8 changes: 8 additions & 0 deletions lib/game/character.ex
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ defmodule Game.Character do
GenServer.cast({:via, Via, who(target)}, {:apply_effects, effects, from, description})
end

@doc """
Reply to the sending character what effects were applied
"""
@spec effects_applied(Character.t(), [Effect.t()], Character.t()) :: :ok
def effects_applied(from, effects, target) do
GenServer.cast({:via, Via, who(from)}, {:effects_applied, effects, target})
end

@doc """
Get character information about the character
"""
Expand Down
4 changes: 2 additions & 2 deletions lib/game/command/skills.ex
Original file line number Diff line number Diff line change
Expand Up @@ -194,15 +194,15 @@ defmodule Game.Command.Skills do
Format.skill_usee(skill, user: {:user, user})
)

socket |> @socket.echo(Format.skill_user(skill, effects, target))
socket |> @socket.echo(Format.skill_user(skill, target))

state =
state
|> set_timeout(skill)
|> Map.put(:save, save)
|> track_stat_usage(effects)

{:update, state}
{:skip, :prompt, state}

{:error, _} ->
socket |> @socket.echo(~s(You don't have enough skill points to use "#{skill.command}"))
Expand Down
2 changes: 1 addition & 1 deletion lib/game/command/use.ex
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ defmodule Game.Command.Use do
)

description = Format.user_item(item, target: {:user, user}, user: {:user, user})
socket |> @socket.echo([description | Format.effects(effects)] |> Enum.join("\n"))
socket |> @socket.echo([description | Format.effects(effects, {:user, user})] |> Enum.join("\n"))

spend_item(state, instance)
end
Expand Down
8 changes: 7 additions & 1 deletion lib/game/damage_types.ex
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,13 @@ defmodule Game.DamageTypes do
end

defp create_default_damage_type(key) do
changeset = %DamageType{} |> DamageType.changeset(%{key: key, stat_modifier: "strength"})
changeset =
%DamageType{}
|> DamageType.changeset(%{
key: key,
stat_modifier: "strength",
reverse_stat: "strength",
})

case changeset |> Repo.insert() do
{:ok, damage_type} ->
Expand Down
54 changes: 46 additions & 8 deletions lib/game/effect.ex
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,53 @@ defmodule Game.Effect do
end

@doc """
Apply effects to stats.
Adjust effects before applying them to a character
"""
@spec adjust_effects([Effect.t()], Stats.t()) :: [Effect.t()]
def adjust_effects(effects, stats) do
effects |> Enum.map(&adjust_effect(&1, stats))
end

@doc """
Adjust a single effect
"""
@spec adjust_effect(Effect.t(), Stats.t()) :: Effect.t()
def adjust_effect(effect, stats)

def adjust_effect(effect = %{kind: "damage"}, stats) do
case DamageTypes.get(effect.type) do
{:ok, damage_type} ->
stat = Map.get(stats, damage_type.reverse_stat)
random_swing = Enum.random(@random_damage)
modifier = 1 + stat / damage_type.reverse_boost + random_swing / 100
modified_amount = round(Float.ceil(effect.amount / modifier))

effect |> Map.put(:amount, modified_amount)

_ ->
effect
end
end

def adjust_effect(effect = %{kind: "damage/over-time"}, stats) do
case DamageTypes.get(effect.type) do
{:ok, damage_type} ->
stat = Map.get(stats, damage_type.reverse_stat)
random_swing = Enum.random(@random_damage)
modifier = 1 + stat / damage_type.reverse_boost + random_swing / 100
modified_amount = round(Float.ceil(effect.amount / modifier))

effect |> Map.put(:amount, modified_amount)

_ ->
effect
end
end

iex> effects = [%{kind: "damage", type: "slashing", amount: 10}]
iex> Game.Effect.apply(effects, %{health_points: 25})
%{health_points: 15}
def adjust_effect(effect, _stats), do: effect

@doc """
Apply effects to stats.
"""
@spec apply([Effect.t()], Stats.t()) :: Stats.t()
def apply(effects, stats) do
Expand All @@ -133,10 +175,6 @@ defmodule Game.Effect do

@doc """
Apply an effect to stats

iex> effect = %{kind: "damage", type: "slashing", amount: 10}
iex> Game.Effect.apply_effect(effect, %{health_points: 25})
%{health_points: 15}
"""
@spec apply_effect(Effect.t(), Stats.t()) :: Stats.t()
def apply_effect(effect, stats)
Expand Down
34 changes: 15 additions & 19 deletions lib/game/format.ex
Original file line number Diff line number Diff line change
Expand Up @@ -689,21 +689,17 @@ defmodule Game.Format do
@doc """
Format a skill, from perspective of the user

iex> Game.Format.skill_user(%{user_text: "Slash away"}, [], {:npc, %{name: "Bandit"}})
iex> Game.Format.skill_user(%{user_text: "Slash away"}, {:npc, %{name: "Bandit"}})
"Slash away"

iex> effects = [%{kind: "damage", type: :slashing, amount: 10}]
iex> Game.Format.skill_user(%{user_text: "You slash away at [target]"}, effects, {:npc, %{name: "Bandit"}})
"You slash away at {npc}Bandit{/npc}\\n10 slashing damage is dealt."
iex> Game.Format.skill_user(%{user_text: "You slash away at [target]"}, {:npc, %{name: "Bandit"}})
"You slash away at {npc}Bandit{/npc}"
"""
def skill_user(skill, effects, target)
def skill_user(skill, target)

def skill_user(%{user_text: user_text}, skill_effects, target) do
user_text =
user_text
|> template(%{target: target_name(target)})

[user_text | effects(skill_effects)] |> Enum.join("\n")
def skill_user(%{user_text: user_text}, target) do
user_text
|> template(%{target: target_name(target)})
end

@doc """
Expand Down Expand Up @@ -835,27 +831,27 @@ defmodule Game.Format do
@doc """
Format effects for display.
"""
def effects([]), do: []
def effects([], _target), do: []

def effects([effect | remaining]) do
def effects([effect | remaining], target) do
case effect do
%{kind: "damage"} ->
["#{effect.amount} #{effect.type} damage is dealt." | effects(remaining)]
["#{effect.amount} #{effect.type} damage is dealt to #{name(target)}." | effects(remaining, target)]

%{kind: "damage/over-time"} ->
["#{effect.amount} #{effect.type} damage is dealt." | effects(remaining)]
["#{effect.amount} #{effect.type} damage is dealt to #{name(target)}." | effects(remaining, target)]

%{kind: "recover", type: "health"} ->
["#{effect.amount} damage is healed." | effects(remaining)]
["#{effect.amount} damage is healed to #{name(target)}." | effects(remaining, target)]

%{kind: "recover", type: "skill"} ->
["#{effect.amount} skill points are recovered." | effects(remaining)]
["#{effect.amount} skill points are recovered." | effects(remaining, target)]

%{kind: "recover", type: "move"} ->
["#{effect.amount} move points are recovered." | effects(remaining)]
["#{effect.amount} move points are recovered." | effects(remaining, target)]

_ ->
effects(remaining)
effects(remaining, target)
end
end

Expand Down
4 changes: 4 additions & 0 deletions lib/game/npc.ex
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,10 @@ defmodule Game.NPC do
{:noreply, state}
end

def handle_cast({:effects_applied, _effects, _target}, state) do
{:noreply, state}
end

def handle_cast(:terminate, state = %{room_id: room_id, npc: npc}) do
room_id |> @room.leave({:npc, npc})
{:stop, :normal, state}
Expand Down
6 changes: 5 additions & 1 deletion lib/game/npc/actions.ex
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,12 @@ defmodule Game.NPC.Actions do
"""
@spec apply_effects(State.t(), [Effect.t()], tuple()) :: State.t()
def apply_effects(state = %{npc: npc}, effects, from) do
effects = effects |> Effect.adjust_effects(npc.stats)
continuous_effects = effects |> Effect.continuous_effects(from)
stats = effects |> Effect.apply(npc.stats)
from |> Character.effects_applied(effects, {:npc, npc})
state = stats |> maybe_died(state, from)

npc = %{npc | stats: stats}
state = %{state | npc: npc}

Expand Down Expand Up @@ -164,7 +167,8 @@ defmodule Game.NPC.Actions do
"""
@spec apply_continuous_effect(State.t(), {Character.t(), Effect.t()}) :: State.t()
def apply_continuous_effect(state = %{npc: npc}, {from, effect}) do
stats = [effect] |> Effect.apply(npc.stats)
effects = [effect] |> Effect.adjust_effects(npc.stats)
stats = effects |> Effect.apply(npc.stats)
state = stats |> maybe_died(state, from)
npc = %{npc | stats: stats}
state = %{state | npc: npc}
Expand Down
11 changes: 9 additions & 2 deletions lib/game/session/character.ex
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,15 @@ defmodule Game.Session.Character do
state
end

@doc """
Callback for after a player sent effects to another character
"""
def effects_applied(state, effects, target) do
state.socket |> @socket.echo(Format.effects(effects, target))
state |> Session.Process.prompt()
state
end

@doc """
Callback for being notified of events
"""
Expand All @@ -53,8 +62,6 @@ defmodule Game.Session.Character do
|> apply_experience(character)
|> track_quest_progress(character)

state |> Session.Process.prompt()

case Character.who(character) == Character.who(state.target) do
true ->
state
Expand Down
10 changes: 7 additions & 3 deletions lib/game/session/effects.ex
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ defmodule Game.Session.Effects do
def apply(effects, from, description, state) do
%{user: user, save: save} = state

effects = effects |> Effect.adjust_effects(save.stats)
continuous_effects = effects |> Effect.continuous_effects(from)
stats = effects |> Effect.apply(save.stats)

Expand All @@ -35,6 +36,7 @@ defmodule Game.Session.Effects do
state = %{state | user: user, save: save}

user |> echo_effects(from, description, effects)
from |> Character.effects_applied(effects, {:user, user})
user |> maybe_died(state, from)

Enum.each(continuous_effects, fn {_from, effect} ->
Expand Down Expand Up @@ -98,7 +100,7 @@ defmodule Game.Session.Effects do
:ok

_ ->
description = [description | Format.effects(effects)]
description = [description | Format.effects(effects, {:user, user})]
echo(self(), description |> Enum.join("\n"))
end
end
Expand All @@ -121,13 +123,15 @@ defmodule Game.Session.Effects do
def apply_continuous_effect(state, {from, effect}) do
%{socket: socket, user: user, save: save} = state

stats = [effect] |> Effect.apply(save.stats)
effects = [effect] |> Effect.adjust_effects(save.stats)
stats = effects |> Effect.apply(save.stats)

save = Map.put(save, :stats, stats)
user = Map.put(user, :save, save)
save.room_id |> update_character(user)
state = %{state | user: user, save: save}

socket |> @socket.echo([effect] |> Format.effects() |> Enum.join("\n"))
socket |> @socket.echo(effects |> Format.effects({:user, user}) |> Enum.join("\n"))

user |> maybe_died(state, from)
state |> Process.prompt()
Expand Down
4 changes: 4 additions & 0 deletions lib/game/session/process.ex
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,10 @@ defmodule Game.Session.Process do
{:noreply, SessionCharacter.apply_effects(state, effects, from, description)}
end

def handle_cast({:effects_applied, effects, target}, state = %{state: "active"}) do
{:noreply, SessionCharacter.effects_applied(state, effects, target)}
end

def handle_cast({:notify, event}, state) do
{:noreply, SessionCharacter.notify(state, event)}
end
Expand Down
14 changes: 14 additions & 0 deletions lib/web/templates/admin/damage_type/_form.html.eex
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,20 @@
<%= error_tag f, :boost_ratio %>
<span class="help-block"><%= Help.get("damage_type.boost_ratio") %></span>
</div>

<div class="form-group">
<%= label f, :reverse_stat %>
<%= select f, :reverse_stat, Stats.basic_fields(), prompt: "Select a stat", class: "form-control" %>
<%= error_tag f, :reverse_stat %>
<span class="help-block"><%= Help.get("damage_type.stat_modifier") %></span>
</div>

<div class="form-group">
<%= label f, :reverse_boost %>
<%= number_input f, :reverse_boost, class: "form-control", min: 0, max: 100 %>
<%= error_tag f, :reverse_boost %>
<span class="help-block"><%= Help.get("damage_type.boost_ratio") %></span>
</div>
</div>

<div class="box-footer">
Expand Down
4 changes: 4 additions & 0 deletions lib/web/templates/admin/damage_type/index.html.eex
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
<th>Stat Modifier</th>
<th>Boost Ratio</th>
<th>Actions</th>
<th>Reverse Stat Modifier</th>
<th>Reverse Boost Ratio</th>
</tr>
</thead>
<tbody>
Expand All @@ -38,6 +40,8 @@
<td><%= damage_type.key %></td>
<td><%= damage_type.stat_modifier %></td>
<td><%= damage_type.boost_ratio %></td>
<td><%= damage_type.reverse_stat %></td>
<td><%= damage_type.reverse_boost %></td>
<td>
<%= link("Edit", to: damage_type_path(@conn, :edit, damage_type.id), class: "btn btn-default btn-xs") %>
</td>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
defmodule Data.Repo.Migrations.AddReverseStatsToDamageTypes do
use Ecto.Migration

def up do
alter table(:damage_types) do
add :reverse_stat, :string
add :reverse_boost, :integer
end

execute "update damage_types set reverse_stat = 'strength', reverse_boost = 20;"

alter table(:damage_types) do
modify :reverse_stat, :string, null: false
modify :reverse_boost, :integer, null: false
end
end

def down do
alter table(:damage_types) do
remove :reverse_stat
remove :reverse_boost
end
end
end
Loading