summaryrefslogtreecommitdiff
path: root/app/models
diff options
context:
space:
mode:
authorDavid Gay <david@davidgay.org>2021-06-16 20:49:59 -0400
committerGitHub <noreply@github.com>2021-06-16 20:49:59 -0400
commit6dfaa7453591910e1373d92d8a09ddf384ebe834 (patch)
treeccec71ec425808ea82a3bfbcd36490f1cdcb666d /app/models
parent007896b0057b8aecbf74dddd269b57efe3f6e0e6 (diff)
parent0d6a82102061ff58b7ba34b09c4be9687c21ab2a (diff)
Merge pull request #16 from dtgay/0.1.11
0.1.11
Diffstat (limited to 'app/models')
-rw-r--r--app/models/character.rb74
-rw-r--r--app/models/character_skill.rb16
-rw-r--r--app/models/concerns/has_costs_and_requirements.rb8
-rw-r--r--app/models/item.rb7
-rw-r--r--app/models/item_infix.rb21
-rw-r--r--app/models/monster_kill.rb22
6 files changed, 140 insertions, 8 deletions
diff --git a/app/models/character.rb b/app/models/character.rb
index d386002..b7649c3 100644
--- a/app/models/character.rb
+++ b/app/models/character.rb
@@ -9,10 +9,12 @@ class Character < ApplicationRecord
has_many :character_items
has_many :learned_activities
has_many :items, through: :character_items
+ has_many :item_infixes
has_many :character_skills
has_many :conditions, through: :states
has_many :states
has_many :chat_messages
+ has_many :monster_kills
has_many :bazaar_orders
validates :name, presence: true
# TODO: Make defaults better. This has to allow nil so the `attribute` default works, and I don't like that.
@@ -115,6 +117,30 @@ class Character < ApplicationRecord
end
end
+ def do_skill_based_equipment_break_checks(skill)
+ skill = Skill.find_by_gid(skill) if skill.is_a? String
+ broken_items = []
+ # TODO: HACK: Should check other stats besides speed stat in the future.
+ # TODO: HACK: May not want a chance to break if speed is _reduced_. Though no equipment does this yet.
+ equipment.all.select { |eq| eq.effects.select { |ef| ef[:gid] == "#{skill.gid}_speed" }.any? }.each do |equipment|
+ if equipment.break_check
+ broken_items.push(equipment.item)
+ end
+ end
+ broken_items
+ end
+
+ def do_skill_based_item_infix_break_checks(skill)
+ skill = Skill.find_by_gid(skill) if skill.is_a? String
+ broken_items = []
+ item_infixes.where(skill: skill).each do |ii|
+ if ii.break_check
+ broken_items.push(ii.item)
+ end
+ end
+ broken_items
+ end
+
def do_equipment_break_checks(exclude_slots: [])
broken_items = []
equipment.where.not(slot: exclude_slots).each do |equipment|
@@ -136,6 +162,10 @@ class Character < ApplicationRecord
self.equipment.find_by(item: item)
end
+ def equipment_with_tag(tag)
+ self.equipment.all.find { |e| e.item.has_tag?(tag) }
+ end
+
def open_slots_for(item)
full_slots = self.equipment.map { |e| e.slot }
item.equip_slots.reject { |slot| full_slots.include?(slot) }
@@ -182,6 +212,30 @@ class Character < ApplicationRecord
end
end
+ def max_infixes(skill)
+ skill = Skill.find_by_gid(skill) if skill.is_a? String
+ 1 + (skill_level(skill) / 20).floor
+ end
+
+ def available_infixes(skill)
+ skill = Skill.find_by_gid(skill) if skill.is_a? String
+ max_infixes(skill) - item_infixes.where(skill: skill).count
+ end
+
+ def infix(item, skill)
+ Character.transaction do
+ shift_item(item, -1)
+ item_infixes.create(item: item, skill: skill)
+ end
+ end
+
+ def remove_infix(item_infix)
+ Character.transaction do
+ shift_item(item_infix.item, 1)
+ item_infix.destroy
+ end
+ end
+
def add_skill_xp(skill, amount)
skill = Skill.find_by_gid(skill) if skill.is_a? String
Character.transaction do
@@ -247,7 +301,14 @@ class Character < ApplicationRecord
activity.whatnot[:requirements]&.each do |requirement|
case requirement[:type]
when "equipment"
- return false unless self.equipment_with_gid(requirement[:gid])
+ if requirement[:tag]
+ return false unless self.equipment_with_tag(requirement[:tag])
+ else
+ return false unless self.equipment_with_gid(requirement[:gid])
+ end
+ when "stat"
+ # TODO: HACK: This won't work with built-in stats! Need to change this to work with power and whatnot.
+ return false unless self.total_stat_change(requirement[:gid]) >= requirement[:value]
when "skill"
return false unless self.skill_level(requirement[:gid]) >= requirement[:level]
when "hearth_amenity"
@@ -306,17 +367,26 @@ class Character < ApplicationRecord
hearth_amenity_effects = self.hearth.built_hearth_amenities.filter_map { |a| a.effects if a.effects }
equipment_effects = self.equipment.filter_map { |a| a.effects if a.effects }
state_effects = self.states.filter_map { |a| a.effects if a.effects && !a.expired? }
- (hearth_amenity_effects + equipment_effects + state_effects).flatten
+ item_infix_effects = self.item_infixes.filter_map { |a| a.effects if a.effects }
+ (hearth_amenity_effects + equipment_effects + state_effects + item_infix_effects).flatten
end
def total_stat_change(gid)
effects.filter_map { |e| e[:modifier] if e[:type] == "stat_change" && e[:gid] == gid }.sum
end
+ def total_enemy_stat_change(gid)
+ effects.filter_map { |e| e[:modifier] if e[:type] == "enemy_stat_change" && e[:gid] == gid }.sum
+ end
+
def damage_ranges
effects.filter_map { |e| { gid: e[:gid], min: e[:min], max: e[:max] } if e[:type] == "damage" }
end
+ def dots
+ effects.filter_map { |e| { gid: e[:gid], min: e[:min], max: e[:max], message: e[:message] } if e[:type] == "dot" }
+ end
+
def planting_spots
[total_stat_change("planting_spots"), 0].max
end
diff --git a/app/models/character_skill.rb b/app/models/character_skill.rb
index 368cc28..406cade 100644
--- a/app/models/character_skill.rb
+++ b/app/models/character_skill.rb
@@ -39,6 +39,10 @@ class CharacterSkill < ApplicationRecord
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
@@ -46,7 +50,7 @@ class CharacterSkill < ApplicationRecord
end
def total_xp_for_next_level
- xp_required_for_level(level + 1)
+ CharacterSkill.xp_required_for_level(level + 1)
end
def xp_to_next_level
@@ -57,11 +61,13 @@ class CharacterSkill < ApplicationRecord
CharacterSkill.top_xp_for(self.skill, limit: nil).map(&:character).map(&:id).index(self.character.id) + 1
end
- private
- def xp_required_for_level(level)
- level <= 120 ? XP_TOTALS_PER_LEVEL[level - 1] : nil
- 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}!",
diff --git a/app/models/concerns/has_costs_and_requirements.rb b/app/models/concerns/has_costs_and_requirements.rb
index 34ff0f3..9c4abf8 100644
--- a/app/models/concerns/has_costs_and_requirements.rb
+++ b/app/models/concerns/has_costs_and_requirements.rb
@@ -19,8 +19,14 @@ module HasCostsAndRequirements
case req[:type]
when "skill"
requirements.push "level #{req[:level]} #{Skill.find_by_gid(req[:gid]).name}"
+ when "stat"
+ requirements.push "#{req[:value]} #{req[:gid]}"
when "equipment"
- requirements.push "equipped #{Item.find_by_gid(req[:gid]).name}"
+ if req[:tag]
+ requirements.push "equipped #{req[:tag]}"
+ else
+ requirements.push "equipped #{Item.find_by_gid(req[:gid]).name}"
+ end
when "hearth_amenity"
requirements.push "level #{req[:level]} #{HearthAmenity.find_by_gid(req[:gid]).name}"
else
diff --git a/app/models/item.rb b/app/models/item.rb
index 8b80788..0e25b2f 100644
--- a/app/models/item.rb
+++ b/app/models/item.rb
@@ -13,6 +13,13 @@ class Item < ApplicationRecord
self.whatnot && self.whatnot[:use_effects]&.any?
end
+ def infixable?(skill = nil)
+ skill = Skill.find_by_gid(skill) if skill.is_a? String
+ return false unless self.whatnot && self.whatnot[:infix_skills]&.any?
+ return true unless skill
+ self.whatnot[:infix_skills].select { |data| data[:gid] == skill.gid }.any?
+ end
+
def equip_slots
return [] unless self.equipment?
self.whatnot[:equip_slots].map { |data| data.to_sym }
diff --git a/app/models/item_infix.rb b/app/models/item_infix.rb
new file mode 100644
index 0000000..b59ccdb
--- /dev/null
+++ b/app/models/item_infix.rb
@@ -0,0 +1,21 @@
+class ItemInfix < ApplicationRecord
+ belongs_to :character
+ belongs_to :item
+ belongs_to :skill
+
+ before_create :check_max_infixes
+
+ def effects
+ self.item.whatnot[:infix_effects]
+ end
+
+ def break_check
+ rand > 0.998 ? destroy : false
+ end
+
+ private
+ def check_max_infixes
+ current_infixes = character.item_infixes.where(skill: skill)
+ raise :abort if current_infixes.count >= character.max_infixes(skill)
+ end
+end
diff --git a/app/models/monster_kill.rb b/app/models/monster_kill.rb
new file mode 100644
index 0000000..24519b1
--- /dev/null
+++ b/app/models/monster_kill.rb
@@ -0,0 +1,22 @@
+class MonsterKill < ApplicationRecord
+ belongs_to :monster
+ belongs_to :character
+
+ validates :quantity, numericality: { greater_than_or_equal_to: 0, only_integer: true }
+ scope :ordered_by_monster_name, -> { includes(:monster).order("monsters.name") }
+
+ after_save :award_titles
+
+ private
+ def award_titles
+ character.award_title("spiteful") if quantity >= 1000
+ character.award_title("hateful") if quantity >= 10_000
+ character.award_title("vicious") if quantity >= 100_000
+
+ all_kills_quantity = character.monster_kills.sum(:quantity)
+ character.award_title("slayer") if all_kills_quantity >= 1_000
+ character.award_title("butcher") if all_kills_quantity >= 10_000
+ character.award_title("slaughterer") if all_kills_quantity >= 100_000
+ character.award_title("massacrer") if all_kills_quantity >= 1_000_000
+ end
+end