diff options
Diffstat (limited to 'app')
-rw-r--r-- | app/errors/monster_spawn_error.rb | 2 | ||||
-rw-r--r-- | app/lib/activity_processor.rb | 57 | ||||
-rw-r--r-- | app/models/location.rb | 1 | ||||
-rw-r--r-- | app/models/monster_spawn.rb | 35 | ||||
-rw-r--r-- | app/models/monster_spawn_combat.rb | 6 | ||||
-rw-r--r-- | app/views/application/_results.html.erb | 3 | ||||
-rw-r--r-- | app/views/locations/show.html.erb | 10 |
7 files changed, 103 insertions, 11 deletions
diff --git a/app/errors/monster_spawn_error.rb b/app/errors/monster_spawn_error.rb new file mode 100644 index 0000000..5a6a667 --- /dev/null +++ b/app/errors/monster_spawn_error.rb @@ -0,0 +1,2 @@ +class MonsterSpawnError < StandardError +end diff --git a/app/lib/activity_processor.rb b/app/lib/activity_processor.rb index c0eaab1..11f0db0 100644 --- a/app/lib/activity_processor.rb +++ b/app/lib/activity_processor.rb @@ -39,6 +39,18 @@ class ActivityProcessor when "xp" puts "Result: #{result}" handle_xp_result(result) + when "monster_spawn" + raise TooManyWoundsError unless @character.can_fight? + next if rand > (result[:chance] || 1) + + @results.push({ type: "br" }) + + monster_spawn = MonsterSpawn.where(location: Location.find_by_gid(result[:location])).select(&:alive?).first + raise MonsterSpawnError unless monster_spawn + + @results.push({ type: type, monster_spawn: monster_spawn }) + resolve_combat_with(monster_spawn) + break when "monster" raise TooManyWoundsError unless @character.can_fight? next if rand > (result[:chance] || 1) @@ -129,6 +141,10 @@ class ActivityProcessor @character.stop_activity @results.replace([{ type: "error", message: "You can't fight in your condition. You'll have to heal a wound." }]) + rescue MonsterSpawnError + @character.stop_activity + @results.replace([{ type: "error", + message: "There are no living leviathans here." }]) end private @@ -193,9 +209,16 @@ class ActivityProcessor end def resolve_combat_with(mon) + + monster_spawn = nil + if mon.is_a? MonsterSpawn + monster_spawn = mon + mon = monster_spawn.monster + end + char = @character char_hp = @character.max_hp - mon_hp = mon.max_hp + mon_hp = monster_spawn.present? ? monster_spawn.remaining_hp : mon.max_hp combat_message = ->(msg) { @results.push({ type: "message", body: "[#{char_hp}/#{char.max_hp}] #{msg}" }) } char_initiative = roll(20) + char.speed mon_initative = roll(20) + mon.speed @@ -244,6 +267,13 @@ class ActivityProcessor combat_message.call("#{target.name} evaded #{actor.name}'s attack.") end if char_hp < 1 || mon_hp < 1 + if monster_spawn + hp_lost = monster_spawn.remaining_hp - mon_hp + if hp_lost > 0 + monster_spawn.monster_spawn_combats.create(monster_spawn: monster_spawn, character: char, + hp_lost: monster_spawn.remaining_hp - mon_hp) + end + end if char_hp < 1 @results.push({ type: "message", body: "You were defeated! You retreat, wounded." }) char.wounds += 1 @@ -256,16 +286,21 @@ class ActivityProcessor end else @results.push({ type: "message", body: "You slew the #{mon.name}." }) - mon.whatnot[:awards]&.each do |award_data| - case award_data[:type] - when "title" - handle_title_result(award_data) - when "xp" - handle_xp_result(award_data) - when "item" - handle_item_result(award_data) - else - raise "Invalid award type string (#{award_data[:type]})" + if monster_spawn + char.stop_activity + return + else + mon.whatnot[:awards]&.each do |award_data| + case award_data[:type] + when "title" + handle_title_result(award_data) + when "xp" + handle_xp_result(award_data) + when "item" + handle_item_result(award_data) + else + raise "Invalid award type string (#{award_data[:type]})" + end end end end diff --git a/app/models/location.rb b/app/models/location.rb index b7c5bf5..e008270 100644 --- a/app/models/location.rb +++ b/app/models/location.rb @@ -2,5 +2,6 @@ class Location < ApplicationRecord include HasWhatnot has_many :activities + has_many :monster_spawns validates :gid, :name, presence: true end diff --git a/app/models/monster_spawn.rb b/app/models/monster_spawn.rb new file mode 100644 index 0000000..d34e390 --- /dev/null +++ b/app/models/monster_spawn.rb @@ -0,0 +1,35 @@ +class MonsterSpawn < ApplicationRecord + belongs_to :monster + belongs_to :location + has_many :monster_spawn_combats + + after_update :check_hp + after_create :send_chat_message + + def alive? + self.remaining_hp > 0 + end + + def remaining_hp + self.monster.max_hp - MonsterSpawnCombat.where(monster_spawn: self).sum(:hp_lost) + end + + private + def send_chat_message + chat_message = ChatMessage.new(body: "A leviathan has appeared in #{location.name}!", + chat_room: ChatRoom.find_by_gid("news")) + if chat_message.save + ChatRoomChannel.broadcast_chat_message(chat_message) + end + end + + def check_hp + if alive? + chat_message = ChatMessage.new(body: "The #{monster.name} in #{location.name} has been slain!", + chat_room: ChatRoom.find_by_gid("news")) + if chat_message.save + ChatRoomChannel.broadcast_chat_message(chat_message) + end + end + end +end diff --git a/app/models/monster_spawn_combat.rb b/app/models/monster_spawn_combat.rb new file mode 100644 index 0000000..50a565b --- /dev/null +++ b/app/models/monster_spawn_combat.rb @@ -0,0 +1,6 @@ +class MonsterSpawnCombat < ApplicationRecord + belongs_to :monster_spawn + belongs_to :character + + validates :hp_lost, numericality: { greater_than_or_equal_to: 0, only_integer: true } +end diff --git a/app/views/application/_results.html.erb b/app/views/application/_results.html.erb index 31fb93e..ec62991 100644 --- a/app/views/application/_results.html.erb +++ b/app/views/application/_results.html.erb @@ -17,6 +17,9 @@ <% when "monster" %> <p>You encountered a <%= result[:monster].name %>.</p> <p class="text-xs italic"><%= result[:monster].description %></p> + <% when "monster_spawn" %> + <p>You found the <%= result[:monster_spawn].monster.name %>!</p> + <p class="text-xs italic"><%= result[:monster_spawn].monster.description %></p> <% when "xp" %> <p class="text-xs">You gained <%= result[:xp] %> <%= result[:skill].name %> XP.</p> <% when "title" %> diff --git a/app/views/locations/show.html.erb b/app/views/locations/show.html.erb index ff7b2a8..fcc668a 100644 --- a/app/views/locations/show.html.erb +++ b/app/views/locations/show.html.erb @@ -3,6 +3,16 @@ <p class="italic"><%= @location.description %></p> </div> +<% @location.monster_spawns.select(&:alive?).each do |ms| %> + <p class="text-yellow-400">A <%= ms.monster.name %> is ravaging this location! (<%= ms.remaining_hp %> HP)</p> + <%# TODO: HACK %> + <% activity = Activity.find_by_gid("beastslay_leviathan_floret_region") %> + <%= form_with url: start_activity_path(activity) do |f| %> + <%= f.hidden_field :id, value: activity.id %> + <%= f.submit "Hunt" %> + <% end %> +<% end %> + <% @location.activities.order(:name).each do |activity| %> <div class="my-4"> <h2 class="text-xl"><%= link_to activity.name, activity_path(activity) %></h2> |