oakdex-battle 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,109 @@
1
+ module Oakdex
2
+ class Battle
3
+ # Calculates Pokemon Stats
4
+ class PokemonStat
5
+ STAGE_MULTIPLIERS = {
6
+ -6 => Rational(2, 8),
7
+ -5 => Rational(2, 7),
8
+ -4 => Rational(2, 6),
9
+ -3 => Rational(2, 5),
10
+ -2 => Rational(2, 4),
11
+ -1 => Rational(2, 3),
12
+ 0 => Rational(2, 2),
13
+ 1 => Rational(3, 2),
14
+ 2 => Rational(4, 2),
15
+ 3 => Rational(5, 2),
16
+ 4 => Rational(6, 2),
17
+ 5 => Rational(7, 2),
18
+ 6 => Rational(8, 2)
19
+ }
20
+
21
+ STAGE_MULTIPLIERS_CRITICAL_HIT = {
22
+ 0 => Rational(1, 24),
23
+ 1 => Rational(1, 8),
24
+ 2 => Rational(1, 2),
25
+ 3 => Rational(1, 1)
26
+ }
27
+
28
+ STAGE_MULTIPLIERS_ACC_EVA = {
29
+ -6 => Rational(3, 9),
30
+ -5 => Rational(3, 8),
31
+ -4 => Rational(3, 7),
32
+ -3 => Rational(3, 6),
33
+ -2 => Rational(3, 5),
34
+ -1 => Rational(3, 4),
35
+ 0 => Rational(3, 3),
36
+ 1 => Rational(4, 3),
37
+ 2 => Rational(5, 3),
38
+ 3 => Rational(6, 3),
39
+ 4 => Rational(7, 3),
40
+ 5 => Rational(8, 3),
41
+ 6 => Rational(9, 3)
42
+ }
43
+
44
+ class << self
45
+ def initial_stat(stat, options = {})
46
+ first_part = initial_stat_first_part(stat, options)
47
+ (
48
+ if stat == :hp
49
+ first_part + options[:level] + 10
50
+ elsif stat.to_s == options[:nature].increased_stat
51
+ (first_part + 5) * 1.1
52
+ elsif stat.to_s == options[:nature].decreased_stat
53
+ (first_part + 5) * 0.9
54
+ else
55
+ first_part + 5
56
+ end
57
+ ).to_i
58
+ end
59
+
60
+ def exp_by_level(leveling_rate, level)
61
+ case leveling_rate
62
+ when 'Fast' then ((4.0 * level**3) / 5).to_i
63
+ when 'Slow' then ((5.0 * level**3) / 4).to_i
64
+ when 'Medium Slow' then medium_slow_exp(level)
65
+ when 'Fluctuating' then fluctuating_exp(level)
66
+ else level**3
67
+ end
68
+ end
69
+
70
+ def level_by_exp(leveling_rate, exp)
71
+ level = 2
72
+ level += 1 while exp_by_level(leveling_rate, level) <= exp
73
+ level - 1
74
+ end
75
+
76
+ private
77
+
78
+ def medium_slow_exp(level)
79
+ (
80
+ ((6.0 / 5) * level**3) - 15 * level**2 + (100 * level) - 140
81
+ ).to_i
82
+ end
83
+
84
+ def fluctuating_exp(level)
85
+ (
86
+ if level <= 15
87
+ level**3 * ((((level + 1) / 3.0) + 24) / 50)
88
+ elsif level <= 36
89
+ level**3 * ((level + 14) / 50.0)
90
+ else
91
+ level**3 * (((level / 2.0) + 32) / 50)
92
+ end
93
+ ).to_i
94
+ end
95
+
96
+ def initial_stat_first_part(stat, options = {})
97
+ (
98
+ (
99
+ 2.0 *
100
+ options[:base_stats][stat.to_s] +
101
+ options[:iv][stat] +
102
+ (options[:ev][stat] / 4)
103
+ ) * options[:level]
104
+ ) / 100
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,76 @@
1
+ require 'forwardable'
2
+
3
+ module Oakdex
4
+ class Battle
5
+ # Represents a side in an active battle, has n trainers
6
+ class Side
7
+ extend Forwardable
8
+
9
+ def_delegators :@battle, :add_to_log
10
+
11
+ attr_reader :trainers, :battle
12
+
13
+ def initialize(battle, trainers)
14
+ @battle = battle
15
+ @trainers = trainers
16
+ end
17
+
18
+ def next_position
19
+ left_position.first
20
+ end
21
+
22
+ def send_to_battle
23
+ @trainers.map do |trainer|
24
+ pokemon_per_trainer.times do |i|
25
+ break unless trainer.team[i]
26
+ trainer.send_to_battle(trainer.team[i], self)
27
+ end
28
+ end
29
+ end
30
+
31
+ def remove_fainted
32
+ @trainers.each(&:remove_fainted)
33
+ end
34
+
35
+ def trainer_on_side?(trainer)
36
+ @trainers.include?(trainer)
37
+ end
38
+
39
+ def pokemon_in_battle?(position)
40
+ in_battle_pokemon.any? do |ibp|
41
+ ibp.position == position
42
+ end
43
+ end
44
+
45
+ def pokemon_left?
46
+ !in_battle_pokemon.empty?
47
+ end
48
+
49
+ def in_battle_pokemon
50
+ @trainers.map(&:in_battle_pokemon).flatten(1)
51
+ end
52
+
53
+ def fainted?
54
+ @trainers.all?(&:fainted?)
55
+ end
56
+
57
+ private
58
+
59
+ def pokemon_per_trainer
60
+ (battle.pokemon_per_side / trainers.size)
61
+ end
62
+
63
+ def left_position
64
+ all_position - taken_positions
65
+ end
66
+
67
+ def taken_positions
68
+ in_battle_pokemon.map(&:position).sort
69
+ end
70
+
71
+ def all_position
72
+ battle.pokemon_per_side.times.to_a
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,16 @@
1
+ require 'oakdex/battle/status_conditions/base'
2
+ require 'oakdex/battle/status_conditions/non_volatile'
3
+ require 'oakdex/battle/status_conditions/poison'
4
+ require 'oakdex/battle/status_conditions/burn'
5
+ require 'oakdex/battle/status_conditions/freeze'
6
+ require 'oakdex/battle/status_conditions/paralysis'
7
+ require 'oakdex/battle/status_conditions/badly_poisoned'
8
+ require 'oakdex/battle/status_conditions/sleep'
9
+
10
+ module Oakdex
11
+ class Battle
12
+ # Status conditions that belong to a pokemon
13
+ module StatusConditions
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,36 @@
1
+ module Oakdex
2
+ class Battle
3
+ module StatusConditions
4
+ # Represents BadlyPoisoned status condition
5
+ class BadlyPoisoned < NonVolatile
6
+ def initialize(pokemon)
7
+ super
8
+ @turn_count = 0
9
+ end
10
+
11
+ def after_turn(turn)
12
+ return if pokemon.current_hp.zero?
13
+ turn.battle.add_to_log('damage_by_badly_poisoned',
14
+ pokemon.trainer.name,
15
+ pokemon.name, hp_by_turn)
16
+ pokemon.change_hp_by(hp_by_turn)
17
+ @turn_count += 1
18
+ end
19
+
20
+ def after_switched_out(_battle)
21
+ @turn_count = 0
22
+ end
23
+
24
+ private
25
+
26
+ def hp_by_turn
27
+ [-(pokemon.hp * percent).to_i, -1].min
28
+ end
29
+
30
+ def percent
31
+ ([@turn_count.to_f, 15].min + 1) / 16.0
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,36 @@
1
+ module Oakdex
2
+ class Battle
3
+ module StatusConditions
4
+ # Represents Abstract Class Base
5
+ class Base
6
+ attr_reader :pokemon
7
+
8
+ def initialize(pokemon)
9
+ @pokemon = pokemon
10
+ end
11
+
12
+ def before_turn(turn); end
13
+
14
+ def after_turn(turn); end
15
+
16
+ def after_fainted(battle); end
17
+
18
+ def after_switched_out(battle); end
19
+
20
+ def after_received_damage(move_execution); end
21
+
22
+ def stat_modifier(_stat)
23
+ 1.0
24
+ end
25
+
26
+ def damage_modifier(_move_execution)
27
+ 1.0
28
+ end
29
+
30
+ def prevents_move?(_move_execution)
31
+ false
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,26 @@
1
+ module Oakdex
2
+ class Battle
3
+ module StatusConditions
4
+ # Represents Burn status condition
5
+ class Burn < NonVolatile
6
+ def after_turn(turn)
7
+ return if pokemon.current_hp.zero?
8
+ turn.battle.add_to_log('damage_by_burn',
9
+ pokemon.trainer.name,
10
+ pokemon.name, hp_by_turn)
11
+ pokemon.change_hp_by(hp_by_turn)
12
+ end
13
+
14
+ def damage_modifier(move_execution)
15
+ move_execution.move.category == 'physical' ? 0.5 : super
16
+ end
17
+
18
+ private
19
+
20
+ def hp_by_turn
21
+ [-(pokemon.hp / 16).to_i, -1].min
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,36 @@
1
+ module Oakdex
2
+ class Battle
3
+ module StatusConditions
4
+ # Represents Freeze status condition
5
+ class Freeze < NonVolatile
6
+ def prevents_move?(move_execution)
7
+ move_execution
8
+ .battle
9
+ .add_to_log('frozen',
10
+ move_execution.pokemon.trainer.name,
11
+ move_execution.pokemon.name)
12
+ true
13
+ end
14
+
15
+ def after_received_damage(move_execution)
16
+ return unless move_execution.move.type == 'fire'
17
+ defrost(move_execution.battle)
18
+ end
19
+
20
+ def before_turn(turn)
21
+ return unless rand(1..100) <= 20
22
+ defrost(turn.battle)
23
+ end
24
+
25
+ private
26
+
27
+ def defrost(battle)
28
+ pokemon.remove_status_condition(self)
29
+ battle.add_to_log('defrosts',
30
+ pokemon.trainer.name,
31
+ pokemon.name)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,12 @@
1
+ module Oakdex
2
+ class Battle
3
+ module StatusConditions
4
+ # Represents Abstract Class Base NonVolatile
5
+ class NonVolatile < Base
6
+ def after_fainted(_battle)
7
+ pokemon.remove_status_condition(self)
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,26 @@
1
+ module Oakdex
2
+ class Battle
3
+ module StatusConditions
4
+ # Represents Paralysis status condition
5
+ class Paralysis < NonVolatile
6
+ def stat_modifier(stat)
7
+ return 0.5 if stat == :speed
8
+ super
9
+ end
10
+
11
+ def prevents_move?(move_execution)
12
+ if rand(1..100) <= 25
13
+ move_execution
14
+ .battle
15
+ .add_to_log('paralysed',
16
+ move_execution.pokemon.trainer.name,
17
+ move_execution.pokemon.name)
18
+ true
19
+ else
20
+ false
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,22 @@
1
+ module Oakdex
2
+ class Battle
3
+ module StatusConditions
4
+ # Represents Poison status condition
5
+ class Poison < NonVolatile
6
+ def after_turn(turn)
7
+ return if pokemon.current_hp.zero?
8
+ turn.battle.add_to_log('damage_by_poison',
9
+ pokemon.trainer.name,
10
+ pokemon.name, hp_by_turn)
11
+ pokemon.change_hp_by(hp_by_turn)
12
+ end
13
+
14
+ private
15
+
16
+ def hp_by_turn
17
+ [-(pokemon.hp / 8).to_i, -1].min
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,37 @@
1
+ module Oakdex
2
+ class Battle
3
+ module StatusConditions
4
+ # Represents Sleep status condition
5
+ class Sleep < NonVolatile
6
+ def initialize(pokemon)
7
+ super
8
+ @turn_count = 0
9
+ @max_turn_count = rand(1..3)
10
+ end
11
+
12
+ def after_turn(turn)
13
+ wake_up(turn.battle) if @turn_count >= @max_turn_count
14
+ @turn_count += 1
15
+ end
16
+
17
+ def prevents_move?(move_execution)
18
+ move_execution
19
+ .battle
20
+ .add_to_log('sleeping',
21
+ pokemon.trainer.name,
22
+ pokemon.name)
23
+ true
24
+ end
25
+
26
+ private
27
+
28
+ def wake_up(battle)
29
+ pokemon.remove_status_condition(self)
30
+ battle.add_to_log('wake_up',
31
+ pokemon.trainer.name,
32
+ pokemon.name)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end