Skip to content

Commit

Permalink
Merge 402f125 into 9289242
Browse files Browse the repository at this point in the history
  • Loading branch information
nitishr committed Mar 18, 2019
2 parents 9289242 + 402f125 commit d7f8a84
Show file tree
Hide file tree
Showing 17 changed files with 271 additions and 408 deletions.
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
source 'https://rubygems.org'
gemspec

gem 'guard-rspec', require: false

# Test coverage.
gem 'coveralls', require: false

Expand Down
42 changes: 42 additions & 0 deletions Guardfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# A sample Guardfile
# More info at https://github.com/guard/guard#readme

## Uncomment and set this to only include directories you want to watch
# directories %w(app lib config test spec features) \
# .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")}

## Note: if you are using the `directories` clause above and you are not
## watching the project directory ('.'), then you will want to move
## the Guardfile to a watched dir and symlink it back, e.g.
#
# $ mkdir config
# $ mv Guardfile config/
# $ ln -s config/Guardfile .
#
# and, you'll have to watch "config/Guardfile" instead of "Guardfile"

# Note: The cmd option is now required due to the increasing number of ways
# rspec may be run, below are examples of the most common uses.
# * bundler: 'bundle exec rspec'
# * bundler binstubs: 'bin/rspec'
# * spring: 'bin/rspec' (This will use spring if running and you have
# installed the spring binstubs per the docs)
# * zeus: 'zeus rspec' (requires the server to be started separately)
# * 'just' rspec: 'rspec'

guard :rspec, cmd: "bundle exec rspec" do
require "guard/rspec/dsl"
dsl = Guard::RSpec::Dsl.new(self)

# Feel free to open issues for suggestions and improvements

# RSpec files
rspec = dsl.rspec
watch(rspec.spec_helper) { rspec.spec_dir }
watch(rspec.spec_support) { rspec.spec_dir }
watch(rspec.spec_files)

# Ruby files
ruby = dsl.ruby
dsl.watch_spec_files_for(ruby.lib_files)
end
2 changes: 1 addition & 1 deletion goby.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]

spec.add_development_dependency "bundler", "~> 1.16"
spec.add_development_dependency "bundler"
spec.add_development_dependency "rake", "~> 10.0"
spec.add_development_dependency "rspec", "~> 3.5"
end
36 changes: 8 additions & 28 deletions lib/goby/battle/attack.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
require 'goby'

module Goby

# Simple physical attack.
class Attack < BattleCommand

# @param [String] name the name.
# @param [Integer] strength the strength.
# @param [Integer] success_rate the chance of success.
def initialize(name: "Attack", strength: 1, success_rate: 100)
def initialize(name: 'Attack', strength: 1, success_rate: 100)
super(name: name)
@strength = strength
@success_rate = success_rate
Expand All @@ -20,49 +18,31 @@ def initialize(name: "Attack", strength: 1, success_rate: 100)
# @param [Entity] enemy the one on whom the attack is used.
# @return [Integer] the amount of damage to inflict on the enemy.
def calculate_damage(user, enemy)

# RANDOMIZE ATTACK
inflict = Random.rand(0.05..0.15).round(2)
multiplier = 1

if enemy.stats[:defense] > user.stats[:attack]
multiplier = 1 - ((enemy.stats[:defense] * 0.1) - (user.stats[:attack] * inflict))

# Prevent a negative multiplier.
multiplier = 0 if multiplier.negative?

else
multiplier = 1 + ((user.stats[:attack] * inflict) - (enemy.stats[:defense] * 0.1))
end

return (@strength * multiplier).round(0)
attack = user.stats[:attack] * Random.rand(0.05..0.15).round(2)
defense = enemy.stats[:defense] * 0.1
multiplier = [1 + (attack - defense), 0].max
(@strength * multiplier).round(0)
end

# Inflicts damage on the enemy and prints output.
#
# @param [Entity] user the one who is using the attack.
# @param [Entity] enemy the one on whom the attack is used.
def run(user, enemy)
if (Random.rand(100) < @success_rate)

if Random.rand(100) < @success_rate
# Damage the enemy.
original_enemy_hp = enemy.stats[:hp]
damage = calculate_damage(user, enemy)
old_hp = enemy.stats[:hp]
enemy.set_stats(hp: old_hp - damage)
enemy.set_stats(hp: original_enemy_hp - calculate_damage(user, enemy))

type("#{user.name} uses #{@name}!\n\n")
type("#{enemy.name} takes #{original_enemy_hp - enemy.stats[:hp]} damage!\n")
type("#{enemy.name}'s HP: #{original_enemy_hp} -> #{enemy.stats[:hp]}\n\n")

else
type("#{user.name} tries to use #{@name}, but it fails.\n\n")
end

end

attr_accessor :strength, :success_rate

end

end
end
57 changes: 15 additions & 42 deletions lib/goby/battle/battle.rb
Original file line number Diff line number Diff line change
@@ -1,70 +1,43 @@
require 'goby'

module Goby

# Representation of a fight between two Fighters.
class Battle

# @param [Entity] entity_a the first entity in the battle
# @param [Entity] entity_b the second entity in the battle
def initialize(entity_a, entity_b)
@entity_a = entity_a
@entity_b = entity_b
@pair = [entity_a, entity_b]
end

# Determine the winner of the battle
#
# @return [Entity] the winner of the battle
def determine_winner
type("#{entity_a.name} enters a battle with #{entity_b.name}!\n\n")
until someone_dead?
#Determine order of attacks
attackers = determine_order
type("#{@entity_a.name} enters a battle with #{@entity_b.name}!\n\n")
until @pair.any?(&:dead?)
# Determine order of attacks
total_agility = @pair.sum { |entity| entity.stats[:agility] }
attackers = Random.rand(0..total_agility - 1) < @entity_a.stats[:agility] ? @pair : @pair.reverse

# Both choose an attack.
attacks = attackers.map { |attacker| attacker.choose_attack }
attacks = attackers.zip(attackers.reverse).map do |attacker, enemy|
[attacker.choose_attack, attacker, enemy]
end

2.times do |i|
attacks.each do |attack, attacker, enemy|
# The attacker runs its attack on the other attacker.
attacks[i].run(attackers[i], attackers[(i + 1) % 2])
attack.run(attacker, enemy)

if (attackers[i].escaped)
attackers[i].escaped = false
if attacker.escaped
attacker.escaped = false
return
end

break if someone_dead?
return @pair.detect { |entity| !entity.dead? } if @pair.any?(&:dead?)
end
end

#If @entity_a is dead return @entity_b, otherwise return @entity_a
entity_a.stats[:hp] <=0 ? entity_b : entity_a
end

private

# Determine the order of attack based on the entitys' agilities
#
# @return [Array] the entities in the order of attack
def determine_order
sum = entity_a.stats[:agility] + entity_b.stats[:agility]
random_number = Random.rand(0..sum - 1)

if random_number < entity_a.stats[:agility]
[entity_a, entity_b]
else
[entity_b, entity_a]
end
end

# Check if either entity is is dead
#
# @return [Boolean] whether an entity is dead or not
def someone_dead?
entity_a.stats[:hp] <= 0 || entity_b.stats[:hp] <= 0
end

attr_reader :entity_a, :entity_b
end

end
end
12 changes: 4 additions & 8 deletions lib/goby/battle/battle_command.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
module Goby

# Commands that are used in the battle system. At each turn,
# an Entity specifies which BattleCommand to use.
class BattleCommand

# Text for when the battle command does nothing.
NO_ACTION = "Nothing happens.\n\n"
NO_ACTION = "Nothing happens.\n\n".freeze

# @param [String] name the name.
def initialize(name: "BattleCommand")
def initialize(name: 'BattleCommand')
@name = name
end

Expand Down Expand Up @@ -38,11 +36,9 @@ def to_s
# @param [BattleCommand] rhs the command on the right.
# @return [Boolean] true iff the commands are considered equal.
def ==(rhs)
@name.casecmp(rhs.name).zero?
@name.casecmp?(rhs.name)
end

attr_accessor :name

end

end
end
25 changes: 6 additions & 19 deletions lib/goby/battle/escape.rb
Original file line number Diff line number Diff line change
@@ -1,38 +1,25 @@
require 'goby'

module Goby

# Allows an Entity to try to escape from the opponent.
class Escape < BattleCommand

# Text for successful escape.
SUCCESS = "Successful escape!\n\n"
SUCCESS = "Successful escape!\n\n".freeze
# Text for failed escape.
FAILURE = "Unable to escape!\n\n"
FAILURE = "Unable to escape!\n\n".freeze

# Initializes the Escape command.
def initialize
super(name: "Escape")
super(name: 'Escape')
end

# Samples a probability to determine if the user will escape from battle.
#
# @param [Entity] user the one who is trying to escape.
# @param [Entity] enemy the one from whom the user wants to escape.
def run(user, enemy)

# Higher probability of escape when the enemy has low agility.
if (user.sample_agilities(enemy))
user.escaped = true
type(SUCCESS)
return
end

# Should already be false.
user.escaped = false
type(FAILURE)
user.escape_from(enemy)
type(user.escaped ? SUCCESS : FAILURE)
end

end

end
end
19 changes: 5 additions & 14 deletions lib/goby/battle/use.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
require 'goby'

module Goby

# Allows an Entity to use an Item in battle.
class Use < BattleCommand

# Initializes the Use command.
def initialize
super(name: "Use")
super(name: 'Use')
end

# Returns true iff the user's inventory is empty.
Expand All @@ -16,10 +14,8 @@ def initialize
# @return [Boolean] status of the user's inventory.
def fails?(user)
empty = user.inventory.empty?
if empty
print "#{user.name}'s inventory is empty!\n\n"
end
return empty
print "#{user.name}'s inventory is empty!\n\n" if empty
empty
end

# Uses the specified Item on the specified Entity.
Expand All @@ -28,12 +24,7 @@ def fails?(user)
# @param [Entity] user the one who is using the command.
# @param [Entity] enemy the one on whom the command is used.
def run(user, enemy)
# Determine the item and on whom to use the item.
pair = user.choose_item_and_on_whom(enemy)
return if (!pair)
user.use_item(pair.first, pair.second)
user.choose_and_use_item_on(enemy)
end

end

end
end

0 comments on commit d7f8a84

Please sign in to comment.