class MonsterSpawnCombat < ApplicationRecord belongs_to :monster_spawn belongs_to :character validates :hp_lost, numericality: { greater_than_or_equal_to: 0, only_integer: true } after_create :check_hp private def check_hp return if monster_spawn.alive? monster = monster_spawn.monster message_body_parts = {} # TODO: HACK (should allow multiple xp awards, eventually) involved_character_ids = MonsterSpawnCombat.where(monster_spawn: monster_spawn).pluck(:character_id).uniq involved_characters = Character.where(id: involved_character_ids) monster.whatnot[:awards]&.each do |data| case data[:type] when "xp" involved_characters.each do |character| total_xp = data[:base] * MonsterSpawnCombat.where(monster_spawn: monster_spawn, character: character).count character.add_skill_xp(data[:gid], total_xp) message_body_parts[character.id] ||= [] message_body_parts[character.id].push("You got #{total_xp} #{Skill.find_by_gid(data[:gid]).name} XP") end when "item" next if rand > (data[:chance] || 1) if data[:table] table_roll = rand data[:table].sort_by { |t| -t[:score] }.each do |table_entry| min_quantity = table_entry[:min_quantity] || table_entry[:quantity] || 1 max_quantity = table_entry[:max_quantity] || table_entry[:quantity] || 1 quantity = rand(min_quantity..max_quantity) score = table_entry[:score] if table_roll >= score item = Item.find_by_gid(data[:gid]) character_quantities = {} quantity.times do id = involved_characters.sample.id character_quantities[id] ||= 0 character_quantities[id] += 1 end character_quantities.each do |character_id, character_quantity| Character.find(character_id).shift_item(item, character_quantity) message_body_parts[character_id] ||= [] message_body_parts[character_id].push("You got #{character_quantity} #{item.name}") end end end else min_quantity = data[:min_quantity] || data[:quantity] || 1 max_quantity = data[:max_quantity] || data[:quantity] || 1 quantity = rand(min_quantity..max_quantity) item = Item.find_by_gid(data[:gid]) character_quantities = {} quantity.times do id = involved_characters.sample.id character_quantities[id] ||= 0 character_quantities[id] += 1 end character_quantities.each do |character_id, character_quantity| Character.find(character_id).shift_item(item, character_quantity) message_body_parts[character_id] ||= [] message_body_parts[character_id].push("You got #{character_quantity} #{item.name}") end end else raise "Invalid monster spawn reward gid string" end end # TODO: HACK for title for now character_damage = {} involved_characters.each do |character| character_damage[character] = MonsterSpawnCombat.where(monster_spawn: monster_spawn, character: character).sum(:hp_lost) end title_recipient = character_damage.max_by { |_, v| v }[0] if title_recipient.award_title("sentinel") message_body_parts[title_recipient.id].push("You earned the Sentinel title!") end message_body_parts.each do |character_id, body_parts| if body_parts.any? Message.create(recipient_id: character_id, subject: "#{monster.name} slain", body: body_parts.join(", ")) end end chat_message = ChatMessage.new(body: "The #{monster.name} in #{monster_spawn.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