summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/errors/monster_spawn_error.rb2
-rw-r--r--app/lib/activity_processor.rb57
-rw-r--r--app/models/location.rb1
-rw-r--r--app/models/monster_spawn.rb35
-rw-r--r--app/models/monster_spawn_combat.rb6
-rw-r--r--app/views/application/_results.html.erb3
-rw-r--r--app/views/locations/show.html.erb10
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>