Class: Gemwarrior::Battle

Inherits:
Object
  • Object
show all
Defined in:
lib/gemwarrior/battle.rb

Constant Summary collapse

ERROR_ATTACK_OPTION_INVALID =

CONSTANTS

'That will not do anything against the monster.'
BEAST_MODE_ATTACK_LO =
100
BEAST_MODE_ATTACK_HI =
200
ATTEMPT_SUCCESS_LO_DEFAULT =
0
ATTEMPT_SUCCESS_HI_DEFAULT =
100
MISS_CAP_DEFAULT =
20
LV4_ROCK_SLIDE_MOD_LO =
6
LV5_MOD_LO =
7
LV5_MOD_HI =
14
ESCAPE_TEXT =
'** POOF **'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ Battle

Returns a new instance of Battle.



25
26
27
28
29
30
# File 'lib/gemwarrior/battle.rb', line 25

def initialize(options)
  self.world                = options.fetch(:world)
  self.player               = options.fetch(:player)
  self.monster              = options.fetch(:monster)
  self.player_is_defending  = false
end

Instance Attribute Details

#monsterObject

Returns the value of attribute monster.



20
21
22
# File 'lib/gemwarrior/battle.rb', line 20

def monster
  @monster
end

#playerObject

Returns the value of attribute player.



20
21
22
# File 'lib/gemwarrior/battle.rb', line 20

def player
  @player
end

#player_is_defendingObject

Returns the value of attribute player_is_defending.



20
21
22
# File 'lib/gemwarrior/battle.rb', line 20

def player_is_defending
  @player_is_defending
end

#worldObject

Returns the value of attribute world.



20
21
22
# File 'lib/gemwarrior/battle.rb', line 20

def world
  @world
end

Instance Method Details

#start(is_arena = false, is_ambush = false) ⇒ Object



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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
# File 'lib/gemwarrior/battle.rb', line 32

def start(is_arena = false, is_ambush = false)
  # begin battle!
  Audio.play_synth(:battle_start)
  print_battle_header unless is_arena

  # print opponent announcement, depending on reason for battle
  if is_arena
    print '  Your opponent is now...'
    Animation.run(phrase: "#{monster.name.upcase}", speed: :slow, oneline: true)
    print "!\n"
  elsif is_ambush
    puts "  You are ambushed by #{monster.name}!".colorize(:yellow)
  else
    puts "  You decide to attack #{monster.name}!"
  end

  puts "  #{monster.name} cries out: \"#{monster.battlecry}\""

  # first strike! (unless arena or emerald)
  # shifty woman time, if emerald
  if monster.name.eql?('emerald')
    if world.shifty_to_jewel && !world.shifty_has_jeweled
      puts
      puts '  Suddenly, the Shifty Woman appears out of nowhere, and stands between you and Emerald!'
      STDIN.getc
      print '  '
      Person.new.speak('Hey, friend. Now it is time to finally get my revenge on ol\' Emer!')
      STDIN.getc
      puts '  She brandishes a now-sharpened-to-a-fine-point-and-glowing version of the Sand Jewel you gave to her and plunges it deep into Emerald\'s side, causing him to scream in agony.'
      puts
      print '  '
      Person.new.speak('THAT was for murdering my parents!')
      STDIN.getc
      puts '  She uses the hand not gripping the shiny blade to conjure up a small bolt of lightning, which she then flings directly at Emerald\'s chest.'
      puts
      print '  '
      Person.new.speak('And THAT was for stealing the ShinyThing(tm)!')
      STDIN.getc
      puts '  Emerald growls mightily, looking quite put off at the turn of events.'
      STDIN.getc
      puts '  He is not without strength, however, and pulls the weapon from his body with one hand while conjuring a fireball with his other, sending it right back at the Shifty Woman. Her glee at delivering a seemingly crushing blow is thwarted as she crumples to the floor.'
      STDIN.getc
      puts '  Both combatants are breathing heavily and groaning through their injuries. The Shifty Woman looks pretty hurt, and begins eyeing an exit from this mess.'
      STDIN.getc
      print '  '
      Person.new.speak('I may not have been able to finish you off, but my friend here will succeed where I and the land of Jool have failed. Goodbye and good luck!')
       puts '  The Shifty Woman regains her compsure just enough to limp off to a back door, disappearing.'
      STDIN.getc

      if GameOptions.data['debug_mode']
        puts
        puts '  Emerald Stats Before Altercation'
        puts "  HP   : #{monster.hp_cur}"
        puts "  DEF  : #{monster.defense}"
        puts "  A_LO : #{monster.atk_lo}"
        puts "  A_HI : #{monster.atk_hi}"
      end

      monster.hp_cur -= (monster.hp_cur * 0.3).floor
      monster.defense -= (monster.defense * 0.25).floor
      monster.atk_lo -= (monster.atk_lo * 0.2).floor
      monster.atk_hi -= (monster.atk_hi * 0.2).floor

      if GameOptions.data['debug_mode']
        puts
        puts '  Emerald Stats After Altercation'
        puts "  HP   : #{monster.hp_cur}"
        puts "  DEF  : #{monster.defense}"
        puts "  A_LO : #{monster.atk_lo}"
        puts "  A_HI : #{monster.atk_hi}"
        puts
      end

      puts '  Emerald has been wounded, but he is not done with this world yet. You approach him, wits about you, ready for battle.'
      world.shifty_has_jeweled = true
    end
  elsif monster_strikes_first?(is_arena, is_ambush)
    puts "  #{monster.name} strikes first!".colorize(:yellow)
    monster_attacks_player
  end
  
  # LV6:STONE_FACE modifier (chance to auto-win)
  # Doesn't work against bosses, nor if battle is an event or in the arena
  if player.special_abilities.include?(:stone_face) && !monster.is_boss && !is_ambush && !is_arena
    level_diff = (player.level - monster.level) * 4
    chance_range = 0..(30 + level_diff)
    roll = rand(0..100)

    if GameOptions.data['debug_mode']
      puts
      puts "  (MOD) LV6: Stone Face"
      puts "  SUCCESS_RANGE: #{chance_range}"
      puts "  SUCCESS_ROLL : #{roll}"
    end

    if chance_range.include?(roll)
      puts "  You use your STONE FACE to tell the #{monster.name} you mean business, and #{monster.name} just gives up!".colorize(:green)
      return monster_death
    end
  end

  # main battle loop
  loop do
    skip_next_monster_attack = false

    # 1. check for death to end battle
    if monster_dead?
      result = monster_death
      return result
    elsif player_dead?
      player_death
      return 'death'
    end

    # 2. print general info and display options prompt
    print_near_death_info
    print_combatants_health_info
    print_battle_options_prompt

    # 3. get player action
    self.player_is_defending = false
    player_action = STDIN.gets.chomp.downcase

    # 4. parse player action
    case player_action
    when 'fight', 'f', 'attack', 'a'
      can_attack = true

      # gun exception
      if player.has_weapon_equipped?
        if player.inventory.weapon.name.eql?('gun')
          if player.inventory.contains_item?('bullet')
            player.inventory.remove_item('bullet')
          else
            puts '  Your gun is out of bullets! Running is your best option now.'.colorize(:red)
            can_attack = false
          end
        end
      end

      if can_attack
        puts "  You attack #{monster.name}#{player.cur_weapon_name}!"
        dmg = calculate_damage(player, monster)
        if dmg > 0
          Audio.play_synth(:battle_player_attack)

          take_damage(monster, dmg)
          if monster_dead?
            result = monster_death
            return result
          end
        else
          Audio.play_synth(:battle_player_miss)

          puts '  You do no damage!'.colorize(:yellow)
        end
      end
    when 'defend', 'd'
      puts '  You dig in and defend this round.'
      self.player_is_defending = true
    when 'item', 'i'
      if player.inventory.is_empty?
        puts '  You have no items!'
        next
      elsif player.inventory.contains_battle_item?
        puts '  Which item do you want to use?'
        puts
        b_items = player.inventory.list_battle_items
        count = 0
        b_items.each do |bi|
          puts "  (#{count + 1}) #{bi.name}"
          count += 1
        end
        puts '  (x) exit'

        loop do
          print_battle_prompt
          answer = gets.chomp.downcase

          case answer
          when 'x', 'q'
            skip_next_monster_attack = true
            break
          else
            begin
              item = b_items[answer.to_i - 1]
              if item
                result = item.use(world)
                player.hp_cur += result[:data]
                player.inventory.remove_item(item.name) if item.consumable
                break
              end
            rescue
              puts '  That is not a valid item choice.'
              puts
              next
            end
          end
        end
      else
        puts '  You have no battle items!'
      end
    when 'look', 'l'
      print "  #{monster.name}".colorize(:white)
      print " (#{monster.hp_cur}/#{monster.hp_max} HP): #{monster.description}\n"
      puts "  It has some distinguishing features, too: face is #{monster.face.colorize(:yellow)}, hands are #{monster.hands.colorize(:yellow)}, and mood, currently, is #{monster.mood.colorize(:yellow)}."
      if GameOptions.data['debug_mode']
        puts '  If defeated, will receive:'
        puts "  >> XP   : #{monster.xp}"
        puts "  >> ROX  : #{monster.rox}"
        puts "  >> ITEMS: #{monster.inventory.contents}"
        next
      end
    when 'pass', 'p'
      puts '  You decide to pass your turn for some reason. Brave!'
    when 'run', 'r'
      if player_escape?(is_arena)
        monster.hp_cur = monster.hp_max
        puts "  You successfully elude #{monster.name}!".colorize(:green)
        print_escape_text
        print_battle_line
        return
      else
        puts '  You were not able to run away! :-('.colorize(:yellow)
      end
    else
      puts "  #{ERROR_ATTACK_OPTION_INVALID}"
      next
    end

    # 5. parse monster action
    monster_attacks_player unless skip_next_monster_attack
  end
end