empi 0.24 → 0.25

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 63caec222a8c3c293532aabadbebc30a9acb2f8a664b4327ba95dae6e5222955
4
- data.tar.gz: '09b1c7b2f163e042ee4e9ecb17547b585c5d8b80480c099f8a253a2c917449e2'
3
+ metadata.gz: abe9081612cf59f547e94e98d5ee4373fab6ded9298bfb20366bc3d67725c0cc
4
+ data.tar.gz: 7f7683c7a94d512965feed1617fc3cb700851e5444862a28069b8c2ddb76cecc
5
5
  SHA512:
6
- metadata.gz: 1662dd058a2e1d8d5e4a8f4cdf48cb7f3b8a45bcc2500c11dd458af7c0d0aff5c9718ce79d5378f47ef6d9d0b9650a1a0a8604b791368371515f68390264e02e
7
- data.tar.gz: abcac90abcfa4d0c72561ddac4c8a074e558d906f82530a7ac7d554f8784d769998b778ed8e5cb3f71c2217f807d6ddcf505217f589a1bfdf2f887c1b3577a0b
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
- self.caption = 'Empi: Ruby Edition 0.24'
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 closing the game window
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 to cursor
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
- GameState.switch!(WelcomeState.instance)
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
- "h: help, Esc: menu, Enter: info, j: switch freeroam\n" \
131
- "QWEADZXC or arrow keys: movement, .: end your turn\n" \
132
- "functions: s sentry, b build, n none\n" \
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
@@ -15,7 +15,7 @@ class QuitState < GameState
15
15
  #def before_end
16
16
  #end
17
17
 
18
- # Process given button to cursor
18
+ # Process given button
19
19
  def update(button)
20
20
  case(button)
21
21
  when Gosu::KbY then
@@ -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 closing the game window
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 to cursor
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
- GameState.switch!(PlayState.instance)
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
- if PlayState.instance.map # some map is loaded
45
- space_text = "\n\n\n"
46
- options_text = "
47
- Esc Resume"
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
- space_text = "\n\n\n\n"
50
- options_text = ""
65
+ resume_text = "\n"
51
66
  end
52
67
 
53
- options_text += "
54
- 1 – Start New: Map 01
55
- 2 – Start New: Map 02
56
- 3 – Start New: Map 03\n
57
- 0, QQuit"
68
+ options_text = "
69
+ 1 – start new: Map 01
70
+ 2 – start new: Map 02
71
+ 3 – start new: Map 03\n
72
+ 9, Ssettings
73
+ 0, Q – quit"
58
74
 
59
- menu = Gosu::Image.from_text(
60
- header_text + space_text + options_text, 20)
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
@@ -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("town.set_project!(): Unknown project (#{desired_project})")
79
+ abort("Town.set_project!(): Unknown project (#{desired_project})")
80
80
  end
81
81
  @parts_needed = price_list[desired_project]
82
82
 
@@ -1,4 +1,4 @@
1
- require_relative './unitFunction'
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("unit.engage!(): Engaging unit is of the same faction as this one (#{@faction})")
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.faction)
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("unit.capture!(): This unit can\'t be captured")
68
+ abort("Unit.capture!(): This unit can\'t be captured")
69
69
  end
70
70
 
71
- if by_whom == @faction
72
- abort("unit.capture!(): This unit already belongs to faction #{@faction}")
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("unit.check_movement(): Moving unit does not have enough move points (#{@moves_left} moves)")
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("unitFunction.info(): No project set (" + @unit.to_s + ")")
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("unitFunction.func!(): No project set (" + @unit.to_s + ")")
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("unitFunction.func!(): Functionable unit didn't function (" + @unit.to_s + ")")
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!(): Infopane is not set")
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 = @locked_to.x
71
- @y = @locked_to.y
72
- @local_unit = @locked_to
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
- @local_unit = @map.get_unit(@x, @y)
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
- @locked_to.x += xx
87
- @locked_to.y += yy
88
- @locked_to.check_movement(@x, @y) # cursor coordinates work like old_x, old_y
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 @locked_to.armour_left > 0
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
- @local_unit = nil
97
- @locked_to = nil
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 local unit
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 @local_unit
107
- @local_unit.set_function!(func, @infopane.faction)
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 = @local_unit.info
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
- @local_unit = nil
123
- @locked_to = nil
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
- # (local -> last locked to -> next waiting) or switch (back) to freeroaming
132
+ # (selected -> last locked to -> next waiting) or switch (back) to freeroaming
129
133
  def to_next_unit!
130
- if @local_unit and @local_unit.is_waiting_for_commands?
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
- @locked_to = @local_unit
136
+ @locked_unit = @selected_unit
133
137
  else
134
- unless @locked_to and @locked_to.is_waiting_for_commands?
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
- @locked_to = waiting[0] # newly selected one
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
- # When cursor is in locked mode there needs to be a local unit it is locked to
153
- # When cursor is in freeroam mode the local unit should still be loaded
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 !@local_unit
156
- abort("cursor.set_function_to_unit(): Cursor is in locked mode " \
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 @local_unit
179
- @infopane.text = @local_unit.info
180
- puts @local_unit.info
240
+ if @selected_unit
241
+ @infopane.text = @selected_unit.info
242
+ puts @selected_unit.info
181
243
 
182
- if @local_unit.is_transporting?
183
- @local_unit.cargo.each { |uu| puts '- cargo: ' + uu.info }
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 = ''
@@ -2,7 +2,7 @@ LINE_HEIGHT = 20
2
2
 
3
3
  # Score, turn and event texts
4
4
  class Infopane
5
- attr_reader :faction
5
+ attr_reader :faction, :turn, :score
6
6
  attr_writer :cursor, :text
7
7
 
8
8
  def initialize
@@ -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("map.load_unit!(): Unit out of map borders (#{coords_x}-#{coords_y})")
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("map.load_unit!(): Bad faction id (#{fac})")
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("map.load_unit!(): Unknown unit type symbol (#{unit_type})")
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(MAPX) { |rr|
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 both map units and transported units
128
- def all_units
129
- all_map_units + all_transported_units
130
- end
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
- ii = 0
136
- 0.upto(MAPX) { |rr|
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
- if get_unit(cc, rr)
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 only units transported by other units
148
- def all_transported_units
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
- all_map_units.each { |uu|
151
- if uu.is_transporting?
152
- ret += uu.cargo
153
- end
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("tile.initialize(): Unknown terrain symbol (#{loaded_symbol})")
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(@y, @x, 0) # TODO 0 -> viewport.x
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.24'
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: 2020-10-22 00:00:00.000000000 Z
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/unitFunction.rb
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