state_machines-mermaid 0.1.0
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/LICENSE.txt +21 -0
- data/README.md +177 -0
- data/lib/state_machines/mermaid/renderer.rb +192 -0
- data/lib/state_machines/mermaid/version.rb +7 -0
- data/lib/state_machines-mermaid.rb +9 -0
- data/test/mermaid_renderer_test.rb +208 -0
- data/test/support/models/battle.rb +190 -0
- data/test/support/models/character.rb +183 -0
- data/test/support/models/commander.rb +23 -0
- data/test/support/models/dragon.rb +237 -0
- data/test/support/models/mage.rb +261 -0
- data/test/support/models/regiment.rb +244 -0
- data/test/support/models/troll.rb +167 -0
- data/test/test_helper.rb +17 -0
- metadata +162 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Epic battle scenario with multiple interacting state machines
|
|
4
|
+
class Battle
|
|
5
|
+
attr_accessor :weather, :terrain, :advantage, :participants, :phase_start_time, :left_flank_secure,
|
|
6
|
+
:right_flank_secure
|
|
7
|
+
|
|
8
|
+
def initialize
|
|
9
|
+
@participants = {
|
|
10
|
+
dragons: [],
|
|
11
|
+
mages: [],
|
|
12
|
+
regiments: [],
|
|
13
|
+
heroes: []
|
|
14
|
+
}
|
|
15
|
+
@advantage = 50
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
state_machine :phase, initial: :preparation do
|
|
19
|
+
state :preparation do
|
|
20
|
+
def allow_reinforcements?
|
|
21
|
+
true
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
state :deployment do
|
|
26
|
+
def can_reposition?
|
|
27
|
+
true
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
state :skirmish do
|
|
32
|
+
def casualties_multiplier
|
|
33
|
+
0.5
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
state :main_battle do
|
|
38
|
+
def casualties_multiplier
|
|
39
|
+
2.0
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
state :climax do
|
|
44
|
+
def heroic_actions_enabled?
|
|
45
|
+
true
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
state :aftermath do
|
|
50
|
+
def battle_ended?
|
|
51
|
+
true
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
event :begin_deployment do
|
|
56
|
+
transition preparation: :deployment, if: :all_forces_ready?
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
event :commence_battle do
|
|
60
|
+
transition deployment: :skirmish
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
after_transition on: :commence_battle, to: :skirmish do |battle|
|
|
64
|
+
battle.phase_start_time = Time.now
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
event :escalate do
|
|
68
|
+
transition skirmish: :main_battle, if: -> { phase_duration > 300 || heavy_casualties? }
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
event :reach_climax do
|
|
72
|
+
transition main_battle: :climax, if: :decisive_moment?
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
event :conclude do
|
|
76
|
+
transition %i[skirmish main_battle climax] => :aftermath
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
after_transition any => any do |battle, transition|
|
|
80
|
+
battle.log_phase_change(transition)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Weather conditions affecting battle
|
|
85
|
+
state_machine :weather, initial: :clear do
|
|
86
|
+
state :clear do
|
|
87
|
+
def visibility
|
|
88
|
+
1000
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
state :fog do
|
|
93
|
+
def visibility
|
|
94
|
+
100
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def ranged_penalty
|
|
98
|
+
0.5
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
state :rain do
|
|
103
|
+
def movement_penalty
|
|
104
|
+
0.8
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def fire_magic_penalty
|
|
108
|
+
0.6
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
state :storm do
|
|
113
|
+
def movement_penalty
|
|
114
|
+
0.5
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def flying_impossible?
|
|
118
|
+
true
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
event :weather_change do
|
|
123
|
+
transition clear: %i[fog rain], if: :weather_front_approaching?
|
|
124
|
+
transition fog: %i[clear rain]
|
|
125
|
+
transition rain: %i[storm clear]
|
|
126
|
+
transition storm: :rain
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Battlefield control
|
|
131
|
+
state_machine :battlefield_control, initial: :contested do
|
|
132
|
+
state :contested
|
|
133
|
+
state :advantage_left
|
|
134
|
+
state :advantage_right
|
|
135
|
+
state :center_breakthrough
|
|
136
|
+
state :encirclement
|
|
137
|
+
|
|
138
|
+
event :gain_left do
|
|
139
|
+
transition contested: :advantage_left
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
event :gain_right do
|
|
143
|
+
transition contested: :advantage_right
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
event :breakthrough do
|
|
147
|
+
transition %i[advantage_left advantage_right] => :center_breakthrough
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
event :encircle do
|
|
151
|
+
transition %i[advantage_left advantage_right] => :encirclement, if: :flanks_secured?
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def all_forces_ready?
|
|
156
|
+
participants.values.all? { |forces| forces.any?(&:ready?) }
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def phase_duration
|
|
160
|
+
phase_start_time ? Time.now - phase_start_time : 0
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def heavy_casualties?
|
|
164
|
+
total_casualties > initial_forces * 0.2
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def decisive_moment?
|
|
168
|
+
advantage > 75 || advantage < 25
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def log_phase_change(transition)
|
|
172
|
+
puts "Battle phase changed from #{transition.from} to #{transition.to}"
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def weather_front_approaching?
|
|
176
|
+
rand(100) < 30
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def flanks_secured?
|
|
180
|
+
@left_flank_secure && @right_flank_secure
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def total_casualties
|
|
184
|
+
participants[:regiments].sum(&:casualties)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def initial_forces
|
|
188
|
+
@initial_forces ||= participants[:regiments].sum(&:soldiers)
|
|
189
|
+
end
|
|
190
|
+
end
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Base character class with complex state machine
|
|
4
|
+
class Character
|
|
5
|
+
attr_accessor :health, :mana, :stamina, :experience, :level, :gold, :inventory
|
|
6
|
+
|
|
7
|
+
def initialize
|
|
8
|
+
@health = 100
|
|
9
|
+
@mana = 100
|
|
10
|
+
@stamina = 100
|
|
11
|
+
@experience = 0
|
|
12
|
+
@level = 1
|
|
13
|
+
@gold = 0
|
|
14
|
+
@inventory = []
|
|
15
|
+
super
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
state_machine :status, initial: :idle do
|
|
19
|
+
# Basic states
|
|
20
|
+
state :idle do
|
|
21
|
+
def currently_resting?
|
|
22
|
+
true
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
state :combat do
|
|
27
|
+
def in_danger?
|
|
28
|
+
true
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
state :casting do
|
|
33
|
+
def actively_casting?
|
|
34
|
+
true
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
state :resting do
|
|
39
|
+
def regenerating?
|
|
40
|
+
true
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
state :stunned do
|
|
45
|
+
def incapacitated?
|
|
46
|
+
true
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
state :dead do
|
|
51
|
+
def game_over?
|
|
52
|
+
true
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Complex transitions with conditions
|
|
57
|
+
event :engage do
|
|
58
|
+
transition idle: :combat, if: :can_fight?
|
|
59
|
+
transition resting: :combat, if: :interrupt_rest?
|
|
60
|
+
transition casting: :combat, unless: :spell_locked?
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
event :cast_spell do
|
|
64
|
+
transition %i[idle combat] => :casting, if: :has_mana?
|
|
65
|
+
transition casting: same, if: :channeling_spell?
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
event :rest do
|
|
69
|
+
transition %i[idle combat] => :resting, unless: :in_danger?
|
|
70
|
+
transition stunned: :resting, if: :recovered?
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
event :stun do
|
|
74
|
+
transition %i[idle combat casting] => :stunned
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
event :recover do
|
|
78
|
+
transition stunned: :idle, if: :stun_expired?
|
|
79
|
+
transition resting: :idle, if: :fully_rested?
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
event :die do
|
|
83
|
+
transition all - :dead => :dead
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
event :resurrect do
|
|
87
|
+
transition dead: :idle, if: :can_resurrect?
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Complex callbacks
|
|
91
|
+
before_transition on: :cast_spell do |char, transition|
|
|
92
|
+
char.mana -= calculate_mana_cost(transition)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
after_transition to: :resting, &:start_regeneration
|
|
96
|
+
|
|
97
|
+
after_transition from: :casting, to: :idle, &:apply_spell_effects
|
|
98
|
+
|
|
99
|
+
around_transition on: :die do |char, _transition, block|
|
|
100
|
+
char.drop_items
|
|
101
|
+
block.call
|
|
102
|
+
char.notify_party
|
|
103
|
+
char.create_tombstone
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Guards would go here if using ActiveModel/ActiveRecord
|
|
107
|
+
# For plain Ruby objects, we handle validation in the condition methods
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Helper methods for conditions
|
|
111
|
+
def can_fight?
|
|
112
|
+
health.positive? && stamina > 10 && !incapacitated?
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def has_mana?
|
|
116
|
+
mana >= 10
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def channeling_spell?
|
|
120
|
+
@channeling_time&.positive?
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def spell_locked?
|
|
124
|
+
@spell_lock_time && @spell_lock_time > Time.now
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def in_danger?
|
|
128
|
+
false # Override in combat scenarios
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def interrupt_rest?
|
|
132
|
+
true
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def recovered?
|
|
136
|
+
@stun_duration && @stun_duration <= 0
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def stun_expired?
|
|
140
|
+
recovered?
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def fully_rested?
|
|
144
|
+
health == 100 && mana == 100
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def can_resurrect?
|
|
148
|
+
level > 10 || has_resurrection_item?
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def has_resurrection_item?
|
|
152
|
+
inventory.any? { |item| item.type == :resurrection }
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def incapacitated?
|
|
156
|
+
false
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def calculate_mana_cost(_transition)
|
|
160
|
+
10 # Base cost, can be overridden
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def start_regeneration
|
|
164
|
+
@regenerating = true
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def apply_spell_effects
|
|
168
|
+
# Apply any lingering spell effects
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def drop_items
|
|
172
|
+
@dropped_items = inventory.dup
|
|
173
|
+
inventory.clear
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def notify_party
|
|
177
|
+
# Notify party members
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def create_tombstone
|
|
181
|
+
# Create memorial
|
|
182
|
+
end
|
|
183
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'character'
|
|
4
|
+
|
|
5
|
+
# Commander class for regiment
|
|
6
|
+
class Commander < Character
|
|
7
|
+
attr_accessor :leadership, :tactics, :inspiring
|
|
8
|
+
|
|
9
|
+
def initialize
|
|
10
|
+
super
|
|
11
|
+
@leadership = 75
|
|
12
|
+
@tactics = 80
|
|
13
|
+
@inspiring = true
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def alive?
|
|
17
|
+
health.positive?
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def with_regiment?
|
|
21
|
+
!status?(:absent)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'character'
|
|
4
|
+
|
|
5
|
+
# Dragon with multiple parallel state machines
|
|
6
|
+
class Dragon < Character
|
|
7
|
+
attr_accessor :rage, :treasure_hoard, :territory, :wingspan, :fire_breath_cooldown, :age, :last_meal_time, :injuries,
|
|
8
|
+
:current_target, :dive_distance, :devastation_score
|
|
9
|
+
|
|
10
|
+
def initialize
|
|
11
|
+
super
|
|
12
|
+
@rage = 0
|
|
13
|
+
@treasure_hoard = 1000
|
|
14
|
+
@territory = 100
|
|
15
|
+
@wingspan = 50
|
|
16
|
+
@fire_breath_cooldown = 0
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Mood state machine with states
|
|
20
|
+
state_machine :mood, initial: :sleeping, namespace: 'dragon' do
|
|
21
|
+
state :sleeping do
|
|
22
|
+
def snoring?
|
|
23
|
+
true
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def alert_level
|
|
27
|
+
:minimal
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Sub-states would be separate state machines in state_machines gem
|
|
32
|
+
state :light_sleep
|
|
33
|
+
state :deep_sleep
|
|
34
|
+
state :hibernating
|
|
35
|
+
|
|
36
|
+
state :hunting do
|
|
37
|
+
def alert_level
|
|
38
|
+
:high
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def speed_bonus
|
|
42
|
+
1.5
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
state :stalking
|
|
47
|
+
state :pursuing
|
|
48
|
+
state :feeding
|
|
49
|
+
|
|
50
|
+
state :hoarding do
|
|
51
|
+
def greed_multiplier
|
|
52
|
+
2.0
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def treasure_sense_range
|
|
56
|
+
1000
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
state :rampaging do
|
|
61
|
+
def damage_multiplier
|
|
62
|
+
3.0
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def fear_aura_range
|
|
66
|
+
500
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Complex event transitions
|
|
71
|
+
event :wake_up do
|
|
72
|
+
transition sleeping: :hunting, if: :hungry?
|
|
73
|
+
transition sleeping: :hoarding, if: :treasure_nearby?
|
|
74
|
+
transition light_sleep: :hunting
|
|
75
|
+
transition deep_sleep: :light_sleep
|
|
76
|
+
transition hibernating: :deep_sleep, if: :winter_ended?
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
event :find_treasure do
|
|
80
|
+
transition hunting: :hoarding
|
|
81
|
+
transition hoarding: same # Keep hoarding more
|
|
82
|
+
transition rampaging: :hoarding, if: -> { rage < 50 }
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
event :enrage do
|
|
86
|
+
transition any - :rampaging => :rampaging, if: -> { rage > 75 }
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
event :exhaust do
|
|
90
|
+
transition rampaging: :sleeping, if: -> { stamina <= 0 }
|
|
91
|
+
transition %i[hunting hoarding] => :sleeping, if: :tired?
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Callbacks with conditions
|
|
95
|
+
before_transition any => :rampaging do |dragon|
|
|
96
|
+
dragon.rage = 100
|
|
97
|
+
dragon.fire_breath_cooldown = 0
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
after_transition to: :hoarding, &:count_treasure
|
|
101
|
+
|
|
102
|
+
around_transition from: :rampaging do |dragon, _transition, block|
|
|
103
|
+
villages_before = dragon.nearby_villages.count
|
|
104
|
+
block.call
|
|
105
|
+
villages_after = dragon.nearby_villages.count
|
|
106
|
+
dragon.devastation_score += (villages_before - villages_after)
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Flight state machine
|
|
111
|
+
state_machine :flight, initial: :grounded do
|
|
112
|
+
state :grounded do
|
|
113
|
+
def can_dodge?
|
|
114
|
+
false
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
state :hovering do
|
|
119
|
+
def stability
|
|
120
|
+
0.8
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
state :soaring do
|
|
125
|
+
def speed
|
|
126
|
+
200
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
state :diving do
|
|
131
|
+
def attack_bonus
|
|
132
|
+
5.0
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
event :take_off do
|
|
137
|
+
transition grounded: :hovering, if: -> { stamina > 50 && !wing_injured? }
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
event :ascend do
|
|
141
|
+
transition hovering: :soaring, if: :weather_permits?
|
|
142
|
+
transition diving: :soaring
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
event :dive_attack do
|
|
146
|
+
transition %i[hovering soaring] => :diving, if: :target_spotted?
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
event :crash_land do
|
|
150
|
+
transition %i[hovering soaring diving] => :grounded
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
after_transition on: :crash_land, to: :grounded do |dragon|
|
|
154
|
+
dragon.take_damage(20)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
event :land do
|
|
158
|
+
transition %i[hovering soaring] => :grounded
|
|
159
|
+
transition diving: :grounded, if: :dive_completed?
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Age progression state machine
|
|
164
|
+
state_machine :age_category, initial: :wyrmling do
|
|
165
|
+
state :wyrmling
|
|
166
|
+
state :young
|
|
167
|
+
state :adult
|
|
168
|
+
state :ancient
|
|
169
|
+
state :great_wyrm
|
|
170
|
+
|
|
171
|
+
event :age do
|
|
172
|
+
transition wyrmling: :young, if: -> { age >= 50 }
|
|
173
|
+
transition young: :adult, if: -> { age >= 200 }
|
|
174
|
+
transition adult: :ancient, if: -> { age >= 800 }
|
|
175
|
+
transition ancient: :great_wyrm, if: -> { age >= 1200 }
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# Dragon-specific methods
|
|
180
|
+
def hungry?
|
|
181
|
+
@last_meal_time && (Time.now - @last_meal_time) > 86_400
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def treasure_nearby?
|
|
185
|
+
sense_treasure_within(100)
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def winter_ended?
|
|
189
|
+
Time.now.month.between?(3, 10)
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def tired?
|
|
193
|
+
stamina < 30
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def count_treasure
|
|
197
|
+
@treasure_hoard = calculate_hoard_value
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def wing_injured?
|
|
201
|
+
@injuries&.include?(:wing)
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def weather_permits?
|
|
205
|
+
!stormy? && visibility > 100
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def target_spotted?
|
|
209
|
+
@current_target != nil
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def dive_completed?
|
|
213
|
+
@dive_distance && @dive_distance <= 0
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def take_damage(amount)
|
|
217
|
+
self.health -= amount
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
attr_reader :nearby_villages
|
|
221
|
+
|
|
222
|
+
def sense_treasure_within(_range)
|
|
223
|
+
false # Implement treasure detection
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def calculate_hoard_value
|
|
227
|
+
treasure_hoard * greed_multiplier
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def stormy?
|
|
231
|
+
false
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def visibility
|
|
235
|
+
1000
|
|
236
|
+
end
|
|
237
|
+
end
|