empi 0.24 → 0.25
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/empi.rb +5 -2
- data/lib/lib/game_states/build_state.rb +2 -2
- data/lib/lib/game_states/play_state.rb +19 -5
- data/lib/lib/game_states/quit_state.rb +1 -1
- data/lib/lib/game_states/set_state.rb +75 -0
- data/lib/lib/game_states/welcome_state.rb +39 -18
- data/lib/lib/game_states/win_state.rb +61 -0
- data/lib/lib/units/town.rb +1 -1
- data/lib/lib/units/unit.rb +16 -15
- data/lib/lib/units/{unitFunction.rb → unit_function.rb} +5 -5
- data/lib/lib/user_interface/cursor.rb +94 -32
- data/lib/lib/user_interface/infopane.rb +1 -1
- data/lib/lib/user_interface/map.rb +56 -24
- data/lib/lib/user_interface/tile.rb +7 -3
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: abe9081612cf59f547e94e98d5ee4373fab6ded9298bfb20366bc3d67725c0cc
|
4
|
+
data.tar.gz: 7f7683c7a94d512965feed1617fc3cb700851e5444862a28069b8c2ddb76cecc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: feac436c82e490b978bac742c546816879fa7c32ef3e14410023078d83b1e8d5366d3ffa7ef051442cf84d5cef728f8c7ee2f2577ddce84c7f3ef16c2661def1
|
7
|
+
data.tar.gz: 73ade95b93a6b84b509ecb88ea545aaa80babbd007586bc4d5db52dee03a79eec15c9fd18f7a4422db265398921e1ab33701bd2c2230f9a7592fdc64cae64277
|
data/lib/empi.rb
CHANGED
@@ -19,7 +19,11 @@ class GameWindow < Gosu::Window
|
|
19
19
|
height = (MAPY + 2) * TILESIZE, \
|
20
20
|
fullscreen = false)
|
21
21
|
super
|
22
|
-
|
22
|
+
|
23
|
+
# Set version name
|
24
|
+
version = '0.25'
|
25
|
+
self.caption = "Empi: Ruby Edition #{version}"
|
26
|
+
WelcomeState.instance.version = version
|
23
27
|
|
24
28
|
# Activate first state
|
25
29
|
$window = self
|
@@ -46,7 +50,6 @@ class GameWindow < Gosu::Window
|
|
46
50
|
|
47
51
|
# Draw according to current state
|
48
52
|
def draw
|
49
|
-
|
50
53
|
@button = BUTTON_PROCESSED # draw just once after each button release
|
51
54
|
unless $window.state.nil?
|
52
55
|
@state.draw
|
@@ -6,7 +6,7 @@ require_relative './play_state'
|
|
6
6
|
require_relative './../units/army'
|
7
7
|
require_relative './../units/ship'
|
8
8
|
|
9
|
-
# Game state of
|
9
|
+
# Game state of selection of the build project
|
10
10
|
class BuildState < GameState
|
11
11
|
include Singleton
|
12
12
|
|
@@ -20,7 +20,7 @@ class BuildState < GameState
|
|
20
20
|
#def before_end
|
21
21
|
#end
|
22
22
|
|
23
|
-
# Process given button
|
23
|
+
# Process given button
|
24
24
|
def update(button)
|
25
25
|
newly_selected = nil
|
26
26
|
|
@@ -2,12 +2,12 @@ require 'singleton'
|
|
2
2
|
|
3
3
|
require_relative './game_state'
|
4
4
|
require_relative './welcome_state'
|
5
|
+
require_relative './win_state'
|
5
6
|
|
6
7
|
require_relative './../user_interface/cursor'
|
7
8
|
require_relative './../user_interface/infopane'
|
8
9
|
require_relative './../user_interface/map'
|
9
10
|
|
10
|
-
|
11
11
|
XTEXT = 5
|
12
12
|
YTEXT = 5
|
13
13
|
ZTILE = 0
|
@@ -32,6 +32,7 @@ class PlayState < GameState
|
|
32
32
|
# Load new scenario or resume game
|
33
33
|
def after_start
|
34
34
|
if @desired_new_map
|
35
|
+
WinState.instance.unset_victory!
|
35
36
|
load_new_map!
|
36
37
|
help # show help after each loading of a new map
|
37
38
|
@desired_new_map = nil
|
@@ -65,7 +66,11 @@ class PlayState < GameState
|
|
65
66
|
def update(button)
|
66
67
|
case(button)
|
67
68
|
when Gosu::KbEscape then
|
68
|
-
|
69
|
+
unless WinState.instance.faction
|
70
|
+
GameState.switch!(WelcomeState.instance)
|
71
|
+
else
|
72
|
+
GameState.switch!(WinState.instance)
|
73
|
+
end
|
69
74
|
when Gosu::KbPeriod then
|
70
75
|
next_faction_turn!
|
71
76
|
when Gosu::KbH then
|
@@ -120,6 +125,14 @@ class PlayState < GameState
|
|
120
125
|
}
|
121
126
|
all_faction_units.each { |uu| uu.reset_moves!}
|
122
127
|
|
128
|
+
# Win check: current faction has lost all units
|
129
|
+
if !WinState.instance.faction and all_faction_units.empty?
|
130
|
+
WinState.instance.set_victory!(
|
131
|
+
3 - @infopane.faction, # TODO more factions?
|
132
|
+
'Annihilation', @infopane.turn, @infopane.score
|
133
|
+
)
|
134
|
+
end
|
135
|
+
|
123
136
|
# Lock the cursor to the first waiting unit
|
124
137
|
@cursor.reset!
|
125
138
|
end
|
@@ -127,9 +140,10 @@ class PlayState < GameState
|
|
127
140
|
# Printout the controls
|
128
141
|
def help
|
129
142
|
puts "-----------\n" \
|
130
|
-
"
|
131
|
-
"
|
132
|
-
"
|
143
|
+
"H: help, Esc: menu, Enter: info, " \
|
144
|
+
".: end your turn, J: switch freeroam\n" \
|
145
|
+
"QWEADZXC or arrow keys: movement, K: previous unit, L: next unit\n" \
|
146
|
+
"functions: S sentry, B build, N none\n" \
|
133
147
|
"-----------\n"
|
134
148
|
end
|
135
149
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
require_relative './game_state'
|
4
|
+
require_relative './welcome_state'
|
5
|
+
|
6
|
+
# Game state of settings screen
|
7
|
+
class SetState < GameState
|
8
|
+
include Singleton
|
9
|
+
|
10
|
+
# TODO move out?
|
11
|
+
attr_reader :settings
|
12
|
+
|
13
|
+
# What to do just after state gets activated
|
14
|
+
#def after_start
|
15
|
+
#end
|
16
|
+
|
17
|
+
# What to do just before state gets deactivated
|
18
|
+
#def before_end
|
19
|
+
#end
|
20
|
+
|
21
|
+
def initialize
|
22
|
+
super
|
23
|
+
@settings = { # TODO move out?
|
24
|
+
'axis_top' => true,
|
25
|
+
'axis_bottom' => false,
|
26
|
+
'axis_left' => true,
|
27
|
+
'axis_right' => false
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
# Process given button
|
32
|
+
def update(button)
|
33
|
+
case(button)
|
34
|
+
when Gosu::Kb1, Gosu::Kb2, Gosu::Kb3, Gosu::Kb4 then
|
35
|
+
change_setting!(button)
|
36
|
+
when Gosu::KbEscape then
|
37
|
+
GameState.switch!(WelcomeState.instance)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def draw
|
42
|
+
header_text = '
|
43
|
+
/-- /// /-/ -/-
|
44
|
+
/-- ||| /-/ |
|
45
|
+
/-- ||| | -/-'
|
46
|
+
options_text = "
|
47
|
+
1 – show top axis: #{@settings['axis_top']}
|
48
|
+
2 – show bottom axis: #{@settings['axis_bottom']}
|
49
|
+
3 – show left axis: #{@settings['axis_left']}
|
50
|
+
4 – show right axis: #{@settings['axis_right']}\n
|
51
|
+
Esc – return to menu"
|
52
|
+
warning_text = '
|
53
|
+
Warning: settings are not saved
|
54
|
+
when Empi is closed'
|
55
|
+
|
56
|
+
menu = Gosu::Image.from_text(
|
57
|
+
header_text + "\n\n\n\n\n" + options_text + "\n\n\n" + warning_text, 20)
|
58
|
+
|
59
|
+
menu.draw((3*TILESIZE) + XTEXT, (2*TILESIZE) + YTEXT, ZTEXT)
|
60
|
+
end
|
61
|
+
|
62
|
+
def change_setting!(button)
|
63
|
+
changed_setting = {
|
64
|
+
Gosu::Kb1 => 'axis_top',
|
65
|
+
Gosu::Kb2 => 'axis_bottom',
|
66
|
+
Gosu::Kb3 => 'axis_left',
|
67
|
+
Gosu::Kb4 => 'axis_right'
|
68
|
+
}[button]
|
69
|
+
|
70
|
+
old_value = @settings[changed_setting]
|
71
|
+
@settings[changed_setting] = !@settings[changed_setting] # TODO other than boolean types?
|
72
|
+
puts "setting #{changed_setting} changed from #{old_value} " \
|
73
|
+
"to #{@settings[changed_setting]}"
|
74
|
+
end
|
75
|
+
end
|
@@ -3,11 +3,15 @@ require 'singleton'
|
|
3
3
|
require_relative './game_state'
|
4
4
|
require_relative './play_state'
|
5
5
|
require_relative './quit_state'
|
6
|
+
require_relative './set_state'
|
7
|
+
require_relative './win_state'
|
6
8
|
|
7
|
-
# Game state of
|
9
|
+
# Game state of main menu
|
8
10
|
class WelcomeState < GameState
|
9
11
|
include Singleton
|
10
12
|
|
13
|
+
attr_accessor :version
|
14
|
+
|
11
15
|
# What to do just after state gets activated
|
12
16
|
#def after_start
|
13
17
|
#end
|
@@ -16,14 +20,17 @@ class WelcomeState < GameState
|
|
16
20
|
#def before_end
|
17
21
|
#end
|
18
22
|
|
19
|
-
# Process given button
|
23
|
+
# Process given button
|
20
24
|
def update(button)
|
21
25
|
case(button)
|
22
|
-
when Gosu::Kb0, Gosu::KbQ then
|
23
|
-
GameState.switch!(QuitState.instance)
|
24
26
|
when Gosu::KbEscape then
|
27
|
+
# If there is active map go either to it or to its win screen
|
25
28
|
if PlayState.instance.map
|
26
|
-
|
29
|
+
unless WinState.instance.faction
|
30
|
+
GameState.switch!(PlayState.instance)
|
31
|
+
else
|
32
|
+
GameState.switch!(WinState.instance)
|
33
|
+
end
|
27
34
|
end
|
28
35
|
when Gosu::Kb1, Gosu::Kb2, Gosu::Kb3 then
|
29
36
|
PlayState.instance.desired_new_map = {
|
@@ -32,6 +39,10 @@ class WelcomeState < GameState
|
|
32
39
|
Gosu::Kb3 => 'm03'
|
33
40
|
}[button]
|
34
41
|
GameState.switch!(PlayState.instance)
|
42
|
+
when Gosu::Kb9, Gosu::KbS then
|
43
|
+
GameState.switch!(SetState.instance)
|
44
|
+
when Gosu::Kb0, Gosu::KbQ then
|
45
|
+
GameState.switch!(QuitState.instance)
|
35
46
|
end
|
36
47
|
end
|
37
48
|
|
@@ -41,24 +52,34 @@ class WelcomeState < GameState
|
|
41
52
|
/-- ||| /-/ |
|
42
53
|
/-- ||| | -/-'
|
43
54
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
55
|
+
# Is there active map? Is it won?
|
56
|
+
if PlayState.instance.map
|
57
|
+
unless WinState.instance.faction
|
58
|
+
resume_text = "
|
59
|
+
Esc – resume"
|
60
|
+
else
|
61
|
+
resume_text = "
|
62
|
+
Esc – return to victory screen"
|
63
|
+
end
|
48
64
|
else
|
49
|
-
|
50
|
-
options_text = ""
|
65
|
+
resume_text = "\n"
|
51
66
|
end
|
52
67
|
|
53
|
-
options_text
|
54
|
-
1 –
|
55
|
-
2 –
|
56
|
-
3 –
|
57
|
-
|
68
|
+
options_text = "
|
69
|
+
1 – start new: Map 01
|
70
|
+
2 – start new: Map 02
|
71
|
+
3 – start new: Map 03\n
|
72
|
+
9, S – settings
|
73
|
+
0, Q – quit"
|
58
74
|
|
59
|
-
|
60
|
-
|
75
|
+
version_text = "
|
76
|
+
version #{self.version}"
|
61
77
|
|
78
|
+
menu = Gosu::Image.from_text(
|
79
|
+
header_text + "\n\n\n" +
|
80
|
+
resume_text + "\n" +
|
81
|
+
options_text + "\n\n\n\n\n\n\n\n" +
|
82
|
+
version_text, 20)
|
62
83
|
menu.draw((3*TILESIZE) + XTEXT, (2*TILESIZE) + YTEXT, ZTEXT)
|
63
84
|
end
|
64
85
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
require_relative './game_state'
|
4
|
+
require_relative './play_state'
|
5
|
+
require_relative './welcome_state'
|
6
|
+
|
7
|
+
# Game state of summary of won game
|
8
|
+
class WinState < GameState
|
9
|
+
include Singleton
|
10
|
+
|
11
|
+
attr_reader :faction
|
12
|
+
|
13
|
+
# What to do just after state gets activated
|
14
|
+
#def after_start
|
15
|
+
#end
|
16
|
+
|
17
|
+
# What to do just before state gets deactivated
|
18
|
+
#def before_end
|
19
|
+
#end
|
20
|
+
|
21
|
+
# Process given button
|
22
|
+
def update(button)
|
23
|
+
case(button)
|
24
|
+
when Gosu::KbEscape then
|
25
|
+
GameState.switch!(WelcomeState.instance)
|
26
|
+
when Gosu::KbReturn then
|
27
|
+
GameState.switch!(PlayState.instance)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def draw
|
32
|
+
winner_text = "VICTORY FOR FACTION #{@faction}"
|
33
|
+
summary_text = "Summary:
|
34
|
+
victory type: #{@type}
|
35
|
+
won on turn: #{@turn}
|
36
|
+
ending score: #{@score}"
|
37
|
+
options_text = 'Do you want to continue playing?
|
38
|
+
Enter – resume
|
39
|
+
Esc – return to menu'
|
40
|
+
|
41
|
+
win_summary = Gosu::Image.from_text(
|
42
|
+
winner_text + "\n\n\n" + summary_text + "\n\n" + options_text, 20)
|
43
|
+
win_summary.draw((2*TILESIZE) + XTEXT, (2*TILESIZE) + YTEXT, ZTEXT)
|
44
|
+
end
|
45
|
+
|
46
|
+
def set_victory!(faction, type, turn, score)
|
47
|
+
@faction = faction
|
48
|
+
@type = type
|
49
|
+
@turn = turn
|
50
|
+
@score = score.clone # separate object is neeeded
|
51
|
+
|
52
|
+
GameState.switch!(WinState.instance)
|
53
|
+
end
|
54
|
+
|
55
|
+
def unset_victory!()
|
56
|
+
@faction = nil
|
57
|
+
@type = nil
|
58
|
+
@turn = nil
|
59
|
+
@score = nil
|
60
|
+
end
|
61
|
+
end
|
data/lib/lib/units/town.rb
CHANGED
@@ -76,7 +76,7 @@ class Town < Unit
|
|
76
76
|
# Set desired project
|
77
77
|
def set_project!(desired_project)
|
78
78
|
unless price_list.key?(desired_project)
|
79
|
-
abort("
|
79
|
+
abort("Town.set_project!(): Unknown project (#{desired_project})")
|
80
80
|
end
|
81
81
|
@parts_needed = price_list[desired_project]
|
82
82
|
|
data/lib/lib/units/unit.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require_relative './
|
1
|
+
require_relative './unit_function'
|
2
2
|
|
3
3
|
# Both capturable and movable game pieces
|
4
4
|
class Unit
|
@@ -35,8 +35,8 @@ class Unit
|
|
35
35
|
|
36
36
|
# Process engagement targeted at this unit
|
37
37
|
def engage!(by_whom)
|
38
|
-
if by_whom == @faction
|
39
|
-
abort("
|
38
|
+
if by_whom.faction == @faction
|
39
|
+
abort("Unit.engage!(): Engaging unit is of the same faction as this one (#{@faction})")
|
40
40
|
end
|
41
41
|
|
42
42
|
# Can it be captured and is it without defenders?
|
@@ -46,7 +46,7 @@ class Unit
|
|
46
46
|
else # then capture it if you can
|
47
47
|
if by_whom.can_capture?
|
48
48
|
puts PROMPT + by_whom.to_s + ' is capturing ' + to_s
|
49
|
-
capture!(by_whom
|
49
|
+
capture!(by_whom)
|
50
50
|
else
|
51
51
|
puts PROMPT + by_whom.to_s + ' can\'t capture other units'
|
52
52
|
end
|
@@ -65,16 +65,16 @@ class Unit
|
|
65
65
|
# Process capture targeted at this unit
|
66
66
|
def capture!(by_whom)
|
67
67
|
unless can_be_captured?
|
68
|
-
abort("
|
68
|
+
abort("Unit.capture!(): This unit can\'t be captured")
|
69
69
|
end
|
70
70
|
|
71
|
-
if by_whom == @faction
|
72
|
-
abort("
|
71
|
+
if by_whom.faction == @faction
|
72
|
+
abort("Unit.capture!(): This unit already belongs to faction #{@faction}")
|
73
73
|
end
|
74
74
|
|
75
75
|
# Add <value> to the capturing faction
|
76
|
-
@infopane.add_score(by_whom - 1, self.class.value)
|
77
|
-
@faction = by_whom
|
76
|
+
@infopane.add_score(by_whom.faction - 1, self.class.value)
|
77
|
+
@faction = by_whom.faction
|
78
78
|
end
|
79
79
|
|
80
80
|
# Add <value> to the other faction and remove links to given unit
|
@@ -98,7 +98,7 @@ class Unit
|
|
98
98
|
def check_movement(old_x, old_y)
|
99
99
|
if @x != old_x || @y != old_y # only if it moved
|
100
100
|
if @moves_left <= 0
|
101
|
-
abort("
|
101
|
+
abort("Unit.check_movement(): Moving unit does not have enough move points (#{@moves_left} moves)")
|
102
102
|
end
|
103
103
|
|
104
104
|
oldcoords_unit = @map.get_unit(old_x, old_y)
|
@@ -121,17 +121,18 @@ class Unit
|
|
121
121
|
# Get to new coordinates
|
122
122
|
if !newcoords_unit
|
123
123
|
@map.set_unit(@x, @y, self)
|
124
|
-
@cargo.each { |uu|
|
125
|
-
uu.x = @x
|
126
|
-
uu.y = @y
|
127
|
-
}
|
128
|
-
|
129
124
|
else # if you are going to be transported
|
130
125
|
newcoords_unit.cargo.insert(-1, self) # -1 = to the end
|
131
126
|
puts PROMPT + to_s + ' got loaded into '+ newcoords_unit.to_s
|
132
127
|
@moves_left = 1 unless newcoords_unit.can_build? # use all your left moves unless you are getting loaded into a town
|
133
128
|
end
|
134
129
|
|
130
|
+
# Update position of your cargo
|
131
|
+
@cargo.each { |uu|
|
132
|
+
uu.x = @x
|
133
|
+
uu.y = @y
|
134
|
+
}
|
135
|
+
|
135
136
|
else # if there already is somebody that can't transport you (enemy or full friend)
|
136
137
|
# Stay on your original tile
|
137
138
|
@x = old_x
|
@@ -13,7 +13,7 @@ class UnitFunction
|
|
13
13
|
"no function"
|
14
14
|
when FUNCBUILD
|
15
15
|
unless @unit.project
|
16
|
-
abort("
|
16
|
+
abort("UnitFunction.info(): No project set (" + @unit.to_s + ")")
|
17
17
|
end
|
18
18
|
"building #{@unit.project.name} (#{@unit.build_info})"
|
19
19
|
when FUNCSENTRY
|
@@ -26,7 +26,7 @@ class UnitFunction
|
|
26
26
|
# Build given unit
|
27
27
|
when FUNCBUILD
|
28
28
|
unless @unit.project
|
29
|
-
abort("
|
29
|
+
abort("UnitFunction.func!(): No project set (" + @unit.to_s + ")")
|
30
30
|
end
|
31
31
|
|
32
32
|
@unit.parts_built += 1
|
@@ -39,9 +39,9 @@ class UnitFunction
|
|
39
39
|
@unit.project.new(@unit.x, @unit.y, @unit.faction, map, infopane)
|
40
40
|
end
|
41
41
|
|
42
|
-
# Wake when enemies are nearby
|
42
|
+
# Wake when enemies are nearby (checking just map units is enough)
|
43
43
|
when FUNCSENTRY
|
44
|
-
units_around = map.all_units.select { |uu|
|
44
|
+
units_around = map.all_units(0,0).select { |uu|
|
45
45
|
(uu.x - @unit.x).abs <= 1 &&
|
46
46
|
(uu.y - @unit.y).abs <= 1 &&
|
47
47
|
uu.faction != @unit.faction
|
@@ -55,7 +55,7 @@ class UnitFunction
|
|
55
55
|
end
|
56
56
|
|
57
57
|
unless ret
|
58
|
-
abort("
|
58
|
+
abort("UnitFunction.func!(): Functionable unit didn't function (" + @unit.to_s + ")")
|
59
59
|
end
|
60
60
|
|
61
61
|
ret
|
@@ -15,7 +15,7 @@ class Cursor
|
|
15
15
|
|
16
16
|
# Give to Infopane link to yourself (for freeroam marker)
|
17
17
|
if !@infopane
|
18
|
-
abort("Cursor.initialize
|
18
|
+
abort("Cursor.initialize(): Infopane is not set")
|
19
19
|
end
|
20
20
|
@infopane.cursor = self
|
21
21
|
end
|
@@ -53,6 +53,10 @@ class Cursor
|
|
53
53
|
# The rest
|
54
54
|
when Gosu::KbJ, Gosu::KB_NUMPAD_0 then
|
55
55
|
switch_freeroam!
|
56
|
+
when Gosu::KbK, Gosu::KB_NUMPAD_MINUS then
|
57
|
+
select_other_unit!(false)
|
58
|
+
when Gosu::KbL, Gosu::KB_NUMPAD_PLUS then
|
59
|
+
select_other_unit!(true)
|
56
60
|
when Gosu::KbReturn, Gosu::KB_NUMPAD_5 then
|
57
61
|
info
|
58
62
|
end
|
@@ -65,11 +69,11 @@ class Cursor
|
|
65
69
|
@image.draw(@x * TILESIZE, (@y + 1) * TILESIZE, ZCURSOR)
|
66
70
|
end
|
67
71
|
|
68
|
-
# Move to coordinates of unit the cursor is locked to
|
72
|
+
# Move to coordinates of map unit the cursor is locked to
|
69
73
|
def warp_to_locked!()
|
70
|
-
@x = @
|
71
|
-
@y = @
|
72
|
-
@
|
74
|
+
@x = @locked_unit.x
|
75
|
+
@y = @locked_unit.y
|
76
|
+
@selected_unit = @locked_unit
|
73
77
|
end
|
74
78
|
|
75
79
|
# Move by given change of coordinates
|
@@ -77,39 +81,39 @@ class Cursor
|
|
77
81
|
if freeroam
|
78
82
|
@x += xx
|
79
83
|
@y += yy
|
80
|
-
@
|
84
|
+
@selected_unit = @map.get_unit(@x, @y)
|
81
85
|
# TODO show some basic tile info in infopane
|
82
86
|
else
|
83
87
|
check_unit
|
84
88
|
|
85
89
|
# Move the unit first
|
86
|
-
@
|
87
|
-
@
|
88
|
-
@
|
90
|
+
@locked_unit.x += xx
|
91
|
+
@locked_unit.y += yy
|
92
|
+
@locked_unit.check_movement(@x, @y) # cursor coordinates work like old_x, old_y
|
89
93
|
|
90
94
|
# Is the unit still alive?
|
91
|
-
if @
|
95
|
+
if @locked_unit.armour_left > 0
|
92
96
|
warp_to_locked! # whether it moved or not
|
93
97
|
else
|
94
98
|
# It got destroyed so clear last links then so that (object of)
|
95
99
|
# given unit can be truly destroyed
|
96
|
-
@
|
97
|
-
@
|
100
|
+
@selected_unit = nil
|
101
|
+
@locked_unit = nil
|
98
102
|
end
|
99
103
|
end
|
100
104
|
end
|
101
105
|
|
102
|
-
# Tries to set function <func> to
|
106
|
+
# Tries to set function <func> to selected unit
|
103
107
|
def set_function_to_unit(func)
|
104
108
|
check_unit
|
105
109
|
|
106
|
-
if @
|
107
|
-
@
|
110
|
+
if @selected_unit
|
111
|
+
@selected_unit.set_function!(func, @infopane.faction)
|
108
112
|
|
109
113
|
# Update infopane with the new (possibly changed) state
|
110
114
|
# (visible only in freeroam mode as in locked one the infopane is
|
111
115
|
# overwritten as cursor either jumps away or switches to freeroam mode)
|
112
|
-
@infopane.text = @
|
116
|
+
@infopane.text = @selected_unit.info
|
113
117
|
else
|
114
118
|
puts "no unit to set that function to (at #{@x}-#{@y})"
|
115
119
|
end
|
@@ -119,19 +123,19 @@ class Cursor
|
|
119
123
|
def reset!
|
120
124
|
@freeroam = true
|
121
125
|
switch_freeroam!
|
122
|
-
@
|
123
|
-
@
|
126
|
+
@selected_unit = nil
|
127
|
+
@locked_unit = nil
|
124
128
|
to_next_unit!
|
125
129
|
end
|
126
130
|
|
127
131
|
# Find next unit which is still waiting for commands and lock to it
|
128
|
-
# (
|
132
|
+
# (selected -> last locked to -> next waiting) or switch (back) to freeroaming
|
129
133
|
def to_next_unit!
|
130
|
-
if @
|
134
|
+
if @selected_unit and @selected_unit.is_waiting_for_commands?
|
131
135
|
# Lock to such unit (though it may have already been locked)
|
132
|
-
@
|
136
|
+
@locked_unit = @selected_unit
|
133
137
|
else
|
134
|
-
unless @
|
138
|
+
unless @locked_unit and @locked_unit.is_waiting_for_commands?
|
135
139
|
waiting = @map.all_units.select { |uu| uu.is_waiting_for_commands? }
|
136
140
|
|
137
141
|
# Are there still some units of active faction waiting for commands?
|
@@ -141,7 +145,8 @@ class Cursor
|
|
141
145
|
return
|
142
146
|
end
|
143
147
|
|
144
|
-
|
148
|
+
# Pick the first waiting unit (leftmost of topmosts)
|
149
|
+
@locked_unit = waiting[0]
|
145
150
|
end
|
146
151
|
end
|
147
152
|
|
@@ -149,11 +154,68 @@ class Cursor
|
|
149
154
|
info unless @info_stopped # due to switching out of the play game state
|
150
155
|
end
|
151
156
|
|
152
|
-
#
|
153
|
-
|
157
|
+
# Skip or cycle units, depending on cursor mode
|
158
|
+
def select_other_unit!(search_forward)
|
159
|
+
unless @freeroam
|
160
|
+
skip_to_other_unit!(search_forward)
|
161
|
+
else
|
162
|
+
cycle_to_other_unit!(search_forward)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
# Skip from selected unit waiting for commands to the next/previous waiting one
|
167
|
+
def skip_to_other_unit!(search_forward = true)
|
168
|
+
if @freeroam
|
169
|
+
abort("Cursor.skip_to_other_unit!(): " \
|
170
|
+
"skipping to #{ search_forward ? 'next' : 'previous'} " \
|
171
|
+
"unit works only in locked mode, not in freeroam one")
|
172
|
+
end
|
173
|
+
|
174
|
+
waiting = @map.all_units.select { |uu| uu.is_waiting_for_commands? }
|
175
|
+
|
176
|
+
# Pick the previous/next waiting unit, relative to the current one
|
177
|
+
# (picking the previous of the first results in index -1 which is the last
|
178
|
+
# so there it is fine but taking the next of the last would go out of range)
|
179
|
+
current_index = waiting.index(@selected_unit)
|
180
|
+
other_index = search_forward ? current_index + 1 : current_index - 1
|
181
|
+
other_index = 0 if other_index >= waiting.size # == would be enough
|
182
|
+
|
183
|
+
@locked_unit = waiting[other_index]
|
184
|
+
warp_to_locked! # so that to_next_unit!() doesn't stay at @selected_unit
|
185
|
+
end
|
186
|
+
|
187
|
+
# Cycle from selected unit to the next/previous local one
|
188
|
+
def cycle_to_other_unit!(search_forward = true)
|
189
|
+
unless @freeroam
|
190
|
+
abort("Cursor.cycle_to_other_unit!():" \
|
191
|
+
"cycling to #{ search_forward ? 'next' : 'previous'} " \
|
192
|
+
"unit works only in freeroam mode, not in locked one")
|
193
|
+
end
|
194
|
+
|
195
|
+
unless @selected_unit
|
196
|
+
@infopane.text = ''
|
197
|
+
puts "no units to cycle through (at #{@x}-#{@y})"
|
198
|
+
return
|
199
|
+
end
|
200
|
+
|
201
|
+
local_pile = @map.all_units_from_tile(@x, @y)
|
202
|
+
|
203
|
+
# Pick the previous/next local unit, relative to the current one
|
204
|
+
# (picking the previous of the first results in index -1 which is the last
|
205
|
+
# so there it is fine but taking the next of the last would go out of range)
|
206
|
+
current_index = local_pile.index(@selected_unit)
|
207
|
+
other_index = search_forward ? current_index + 1 : current_index - 1
|
208
|
+
other_index = 0 if other_index >= local_pile.size # == would be enough
|
209
|
+
|
210
|
+
@selected_unit = local_pile[other_index]
|
211
|
+
info
|
212
|
+
end
|
213
|
+
|
214
|
+
# When cursor is in locked mode there needs to be unit it is locked to
|
215
|
+
# When cursor is in freeroam mode the locked unit should be kept
|
154
216
|
def check_unit
|
155
|
-
if !@freeroam and !@
|
156
|
-
abort("
|
217
|
+
if !@freeroam and !@locked_unit
|
218
|
+
abort("Cursor.check_unit(): Cursor is in locked mode " \
|
157
219
|
"but there is no unit it is locked to (at #{@x}-#{@y})")
|
158
220
|
end
|
159
221
|
end
|
@@ -175,12 +237,12 @@ class Cursor
|
|
175
237
|
def info
|
176
238
|
check_unit
|
177
239
|
|
178
|
-
if @
|
179
|
-
@infopane.text = @
|
180
|
-
puts @
|
240
|
+
if @selected_unit
|
241
|
+
@infopane.text = @selected_unit.info
|
242
|
+
puts @selected_unit.info
|
181
243
|
|
182
|
-
if @
|
183
|
-
@
|
244
|
+
if @selected_unit.is_transporting?
|
245
|
+
@selected_unit.cargo.each { |uu| puts '- cargo: ' + uu.info }
|
184
246
|
end
|
185
247
|
else
|
186
248
|
@infopane.text = ''
|
@@ -4,6 +4,8 @@ require_relative './../units/army'
|
|
4
4
|
require_relative './../units/ship'
|
5
5
|
require_relative './../units/town'
|
6
6
|
|
7
|
+
MAX_CARGO_LEVEL = 10
|
8
|
+
|
7
9
|
class Map
|
8
10
|
attr_accessor :name, :mapx, :mapy, :infopane
|
9
11
|
|
@@ -73,13 +75,13 @@ class Map
|
|
73
75
|
coords_y = coords[1].to_i
|
74
76
|
if (coords_x < 0 || coords_x >= @mapx ||
|
75
77
|
coords_y < 0 || coords_y >= @mapy)
|
76
|
-
abort("
|
78
|
+
abort("Map.load_unit!(): Unit out of map borders (#{coords_x}-#{coords_y})")
|
77
79
|
end
|
78
80
|
|
79
81
|
# Check faction
|
80
82
|
fac = unit[1].to_i
|
81
83
|
if(fac < 0 || fac > FACTIONS)
|
82
|
-
abort("
|
84
|
+
abort("Map.load_unit!(): Bad faction id (#{fac})")
|
83
85
|
end
|
84
86
|
|
85
87
|
# Create unit
|
@@ -87,7 +89,7 @@ class Map
|
|
87
89
|
if @known_unit_types.include?(unit_type)
|
88
90
|
@known_unit_types[unit_type].new(coords_x, coords_y, fac, self, @infopane)
|
89
91
|
else
|
90
|
-
abort("
|
92
|
+
abort("Map.load_unit!(): Unknown unit type symbol (#{unit_type})")
|
91
93
|
end
|
92
94
|
end
|
93
95
|
|
@@ -105,7 +107,7 @@ class Map
|
|
105
107
|
def all_tiles
|
106
108
|
ret = []
|
107
109
|
ii = 0
|
108
|
-
0.upto(
|
110
|
+
0.upto(MAPY) { |rr|
|
109
111
|
0.upto(MAPX) { |cc|
|
110
112
|
ret[ii] = @tiles[rr][cc]
|
111
113
|
ii += 1
|
@@ -124,34 +126,64 @@ class Map
|
|
124
126
|
@tiles[rr][cc].unit = uu
|
125
127
|
end
|
126
128
|
|
127
|
-
# Return
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
# Return only units directly on map
|
133
|
-
def all_map_units
|
129
|
+
# Return all units with cargo level in given range
|
130
|
+
# CL0 = map units, CL1 = units in map units, CL2 = units in CL1 units...
|
131
|
+
# all_units() -> all units, all_units(0, 0) -> only map units
|
132
|
+
def all_units(min_cargo_level = 0, max_cargo_level = MAX_CARGO_LEVEL)
|
134
133
|
ret = []
|
135
|
-
|
136
|
-
|
134
|
+
|
135
|
+
unless min_cargo_level.between?(0, MAX_CARGO_LEVEL) and
|
136
|
+
max_cargo_level.between?(0, MAX_CARGO_LEVEL)
|
137
|
+
abort("Map.all_units(): Desired cargo levels need to be " \
|
138
|
+
"from 0 to #{MAX_CARGO_LEVEL}")
|
139
|
+
end
|
140
|
+
unless min_cargo_level <= max_cargo_level
|
141
|
+
abort("Map.all_units(): Min cargo level (#{min_cargo_level}) is higher " \
|
142
|
+
"than max cargo level (#{max_cargo_level})")
|
143
|
+
end
|
144
|
+
|
145
|
+
0.upto(MAPY) { |rr|
|
137
146
|
0.upto(MAPX) { |cc|
|
138
|
-
|
139
|
-
ret[ii] = get_unit(cc, rr)
|
140
|
-
ii += 1
|
141
|
-
end
|
147
|
+
ret += all_units_from_tile(cc, rr)
|
142
148
|
}
|
143
149
|
}
|
150
|
+
|
144
151
|
ret
|
145
152
|
end
|
146
153
|
|
147
|
-
# Return
|
148
|
-
def
|
154
|
+
# Return all units from given tile with cargo level in given range
|
155
|
+
def all_units_from_tile(cc, rr,
|
156
|
+
min_cargo_level = 0,
|
157
|
+
max_cargo_level = MAX_CARGO_LEVEL)
|
149
158
|
ret = []
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
159
|
+
|
160
|
+
uu = get_unit(cc, rr)
|
161
|
+
if uu
|
162
|
+
ret += add_unit_to_list(uu, 0, min_cargo_level, max_cargo_level)
|
163
|
+
end
|
164
|
+
|
165
|
+
ret
|
166
|
+
end
|
167
|
+
|
168
|
+
# Recursively add units to the list
|
169
|
+
def add_unit_to_list(unit, cargo_level = 0,
|
170
|
+
min_cargo_level = 0,
|
171
|
+
max_cargo_level = MAX_CARGO_LEVEL)
|
172
|
+
ret = []
|
173
|
+
|
174
|
+
# This unit
|
175
|
+
if cargo_level >= min_cargo_level
|
176
|
+
ret.append(unit)
|
177
|
+
end
|
178
|
+
|
179
|
+
# Transported units
|
180
|
+
cargo_level += 1
|
181
|
+
if cargo_level <= max_cargo_level
|
182
|
+
unit.cargo.each { |uu|
|
183
|
+
ret += add_unit_to_list(uu, cargo_level, min_cargo_level, max_cargo_level)
|
184
|
+
}
|
185
|
+
end
|
186
|
+
|
155
187
|
ret
|
156
188
|
end
|
157
189
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require_relative './../game_states/set_state'
|
2
|
+
|
1
3
|
TILE_SEA = 0
|
2
4
|
TILE_GROUND = 1
|
3
5
|
|
@@ -22,7 +24,7 @@ class Tile
|
|
22
24
|
@terrain = TILE_GROUND
|
23
25
|
@image = Gosu::Image.new(dir_path + '/../../media/ground.png')
|
24
26
|
else
|
25
|
-
abort("
|
27
|
+
abort("Tile.initialize(): Unknown terrain symbol (#{loaded_symbol})")
|
26
28
|
end
|
27
29
|
end
|
28
30
|
|
@@ -36,8 +38,10 @@ class Tile
|
|
36
38
|
end
|
37
39
|
|
38
40
|
# 3) axes
|
39
|
-
draw_axis_tick(@x, @y, 0) # TODO 0 -> viewport.y
|
40
|
-
draw_axis_tick(@
|
41
|
+
draw_axis_tick(@x, @y, 0) if SetState.instance.settings['axis_top'] # TODO 0 -> viewport.y
|
42
|
+
draw_axis_tick(@x, @y, MAPY) if SetState.instance.settings['axis_bottom']
|
43
|
+
draw_axis_tick(@y, @x, 0) if SetState.instance.settings['axis_left'] # TODO 0 -> viewport.x
|
44
|
+
draw_axis_tick(@y, @x, MAPX) if SetState.instance.settings['axis_right']
|
41
45
|
end
|
42
46
|
|
43
47
|
# Draw one tick of axis for appropriate tiles
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: empi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.25'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Detros
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-09-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: gosu
|
@@ -52,12 +52,14 @@ files:
|
|
52
52
|
- lib/lib/game_states/game_state.rb
|
53
53
|
- lib/lib/game_states/play_state.rb
|
54
54
|
- lib/lib/game_states/quit_state.rb
|
55
|
+
- lib/lib/game_states/set_state.rb
|
55
56
|
- lib/lib/game_states/welcome_state.rb
|
57
|
+
- lib/lib/game_states/win_state.rb
|
56
58
|
- lib/lib/units/army.rb
|
57
59
|
- lib/lib/units/ship.rb
|
58
60
|
- lib/lib/units/town.rb
|
59
61
|
- lib/lib/units/unit.rb
|
60
|
-
- lib/lib/units/
|
62
|
+
- lib/lib/units/unit_function.rb
|
61
63
|
- lib/lib/user_interface/cursor.rb
|
62
64
|
- lib/lib/user_interface/infopane.rb
|
63
65
|
- lib/lib/user_interface/map.rb
|