oakdex-battle 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +103 -0
- data/lib/oakdex.rb +3 -0
- data/lib/oakdex/battle.rb +111 -0
- data/lib/oakdex/battle/action.rb +115 -0
- data/lib/oakdex/battle/damage.rb +99 -0
- data/lib/oakdex/battle/in_battle_pokemon.rb +159 -0
- data/lib/oakdex/battle/move.rb +27 -0
- data/lib/oakdex/battle/move_execution.rb +148 -0
- data/lib/oakdex/battle/pokemon.rb +168 -0
- data/lib/oakdex/battle/pokemon_factory.rb +118 -0
- data/lib/oakdex/battle/pokemon_stat.rb +109 -0
- data/lib/oakdex/battle/side.rb +76 -0
- data/lib/oakdex/battle/status_conditions.rb +16 -0
- data/lib/oakdex/battle/status_conditions/badly_poisoned.rb +36 -0
- data/lib/oakdex/battle/status_conditions/base.rb +36 -0
- data/lib/oakdex/battle/status_conditions/burn.rb +26 -0
- data/lib/oakdex/battle/status_conditions/freeze.rb +36 -0
- data/lib/oakdex/battle/status_conditions/non_volatile.rb +12 -0
- data/lib/oakdex/battle/status_conditions/paralysis.rb +26 -0
- data/lib/oakdex/battle/status_conditions/poison.rb +22 -0
- data/lib/oakdex/battle/status_conditions/sleep.rb +37 -0
- data/lib/oakdex/battle/trainer.rb +50 -0
- data/lib/oakdex/battle/turn.rb +70 -0
- data/lib/oakdex/battle/valid_action_service.rb +89 -0
- data/lib/oakdex/battle/version.rb +5 -0
- metadata +82 -0
@@ -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,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
|