summaryrefslogtreecommitdiff
path: root/app/models/character_skill.rb
blob: 406caded74caff508908de223ecf55c4354d3b57 (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
class CharacterSkill < ApplicationRecord
  belongs_to :character
  belongs_to :skill
  validates :skill_id, uniqueness: { scope: :character_id }
  validates :xp, numericality: { greater_than_or_equal_to: 0, only_integer: true }

  before_update :send_chat_message_if_leveled_up, :award_titles

  scope :ordered_by_skill_name, -> { includes(:skill).order("skills.name") }

  XP_TOTALS_PER_LEVEL = [
    0, 117, 436, 959, 1685, 2615, 3749, 5088, 6634, 8387, 10347, 12517, 14897,
    17489, 20296, 23318, 26559, 30022, 33709, 37624, 41773, 46158, 50788,
    55667, 60804, 66207, 71886, 77853, 84122, 90706, 97626, 104899, 112551,
    120608, 129101, 138067, 147545, 157584, 168239, 179572, 191657, 204576,
    218427, 233319, 249382, 266761, 285626, 306173, 328626, 353243, 380324,
    410211, 443300, 480046, 520974, 566687, 617881, 675357, 740038, 812987,
    895428, 988769, 1094635, 1214895, 1351701, 1507535, 1685252, 1888141,
    2119991, 2385164, 2688687, 3036344, 3434803, 3891738, 4415991, 5017743,
    5708720, 6502428, 7414420, 8462610, 9667629, 11053238, 12646801, 14479834,
    16588636, 19015009, 21807100, 25020357, 28718640, 32975498, 37875637,
    43516611, 50010775, 57487528, 66095898, 76007520, 87420069, 100561203,
    115693120, 133117791, 153182996, 176289273, 202897924, 233540227,
    268828058, 309466113, 356265990, 410162408, 472231880, 543714231,
    626037362, 720845790, 830033503, 955781810, 1100602922, 1267390153,
    1459475733, 1680697391, 1935475040, 2228899094
  ].freeze

  def self.top_xp_for(skill, limit: 10)
    skill = Skill.find_by_gid(skill) if skill.is_a? String
    where(skill: skill).order(xp: :desc, updated_at: :asc).limit(limit)
  end

  def self.level_for_xp(xp)
    XP_TOTALS_PER_LEVEL.each_with_index do |total, index|
      if total > xp
        return index
      end
    end
  end

  def self.xp_required_for_level(level)
    level <= 120 ? XP_TOTALS_PER_LEVEL[level - 1] : nil
  end

  def level
    XP_TOTALS_PER_LEVEL.each_with_index do |total, index|
      return index if total > self.xp
    end
  end

  def total_xp_for_next_level
    CharacterSkill.xp_required_for_level(level + 1)
  end

  def xp_to_next_level
    total_xp_for_next_level - self.xp
  end

  def rank
    CharacterSkill.top_xp_for(self.skill, limit: nil).map(&:character).map(&:id).index(self.character.id) + 1
  end

  def percentage_of_skill_level_completed
    xp_gained_this_level = xp - CharacterSkill.xp_required_for_level(level)
    total_xp_gain_neeeded_for_entire_level = total_xp_for_next_level - CharacterSkill.xp_required_for_level(level)
    (xp_gained_this_level.to_f / total_xp_gain_neeeded_for_entire_level) * 100
  end

  private
    def send_chat_message_if_leveled_up
      if CharacterSkill.level_for_xp(self.xp_was) < CharacterSkill.level_for_xp(self.xp)
        chat_message = ChatMessage.new(body: "reached #{self.skill.name} level #{self.level}!",
                                       target: self.character,
                                       chat_room: ChatRoom.find_by_gid("achievement"))
        if chat_message.save
          ChatRoomChannel.broadcast_chat_message(chat_message)
        end
      end
    end

    def award_titles
      new_level = CharacterSkill.level_for_xp(xp)
      if CharacterSkill.level_for_xp(self.xp_was) < new_level
        if character.character_skills.where.not(id: self.id).to_a.sum(&:level) + new_level >= 100
          character.award_title("aspirant")
        end
      end
    end
end