summaryrefslogtreecommitdiff
path: root/app/models/monster_spawn_combat.rb
blob: f15f339eb0daa9bb0462ebb74bdeb174b3cd1306 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
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