diff options
Diffstat (limited to 'app/controllers')
-rw-r--r-- | app/controllers/application_controller.rb | 4 | ||||
-rw-r--r-- | app/controllers/game_controller.rb | 80 |
2 files changed, 84 insertions, 0 deletions
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index efd8427..81e07da 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -10,4 +10,8 @@ class ApplicationController < ActionController::Base def redirect_if_no_active_character redirect_to new_character_path unless current_char end + + def roll(sides) + rand(sides) + 1 + end end diff --git a/app/controllers/game_controller.rb b/app/controllers/game_controller.rb index 58644a7..c63fbc5 100644 --- a/app/controllers/game_controller.rb +++ b/app/controllers/game_controller.rb @@ -13,6 +13,23 @@ class GameController < ApplicationController activity.whatnot[:results].each do |result| type = result[:type] case type + when "monster" + next if rand > (result[:chance] || 1) + table_roll = rand + result[:table].sort_by { |t| -t[:score] }.each do |table_entry| + score = table_entry[:score] + result[:table_scaling]&.each do |scale_entry| + case scale_entry[:type] + when "skill" + score = score**(1 + (scale_entry[:scale_value] * current_char.skill_level(scale_entry[:gid]))) + end + end + if table_roll >= score + activity = Activity.find_by_gid(table_entry[:gid]) + monster = Monster.find_by_gid(table_entry[:gid]) + resolve_combat_with(monster) + end + end when "item" next if rand > (result[:chance] || 1) @@ -83,4 +100,67 @@ class GameController < ApplicationController current_char.shift_item(item, quantity) @results.push({ type: "item", item: item, quantity: quantity, xp: xp_awards }) end + + def resolve_combat_with(mon) + char = current_char + char_hp = current_char.max_hp + mon_hp = mon.max_hp + combat_message = ->(msg) { @results.push({ type: "message", body: "[#{char_hp}/#{char.max_hp}] #{msg}" }) } + combat_message.call("You encountered a #{mon.name}.") + char_initiative = roll(10) + char.speed + mon_initative = roll(10) + mon.speed + if char_initiative > mon_initative + turn_order = [char, mon] + elsif mon_initative > char_initiative + turn_order = [mon, char] + else + turn_order = [char, mon].shuffle + end + turn_order.cycle do |actor| + case actor + when char + accuracy_roll = roll(20) + char.accuracy + evasion_roll = roll(20) + mon.evasion + if accuracy_roll >= evasion_roll + dealt_damage = roll(4) + char.power # TODO: Replace d4 with weapon damage + if accuracy_roll >= (evasion_roll + 10) + combat_message.call("You landed a critical hit!") + dealt_damage = dealt_damage * 2 + end + blocked_damage = (accuracy_roll >= (roll(20) + mon.block)) ? 0 : mon.block_value + resolved_damage = dealt_damage - blocked_damage + mon_hp -= resolved_damage + combat_message.call("You hit for #{resolved_damage} (#{dealt_damage} - #{blocked_damage} blocked)") + elsif evasion_roll > accuracy_roll + combat_message.call("The #{mon.name} evaded your attack.") + end + when mon + combat_message.call("Monsters don't get turns yet.") + else + raise "Invalid combatant (class is #{actor.class})" + end + if char_hp < 1 || mon_hp < 1 + if char_hp < 1 + combat_message.call("You were defeated! You retreat, wounded.") + char.increment(:wounds) + else + combat_message.call("You defeated the #{mon.name}.") + mon.whatnot[:awards]&.each do |award_data| + case award_data[:type] + when "xp" + skill = Skill.find_by_gid(award_data[:skill]) + amount = award_data[:base] + char.add_skill_xp(skill, amount) + combat_message.call("You gained #{amount} #{skill.name} XP.") + else + raise "Invalid award type string (#{award_data[:type]})" + end + end + end + break + else + combat_message.call("-" * 20) + end + end + end end |